2021-06-17 16:22:14

by viktor.barna

[permalink] [raw]
Subject: [RFC v1 000/256] wireless: cl8k driver for Celeno IEEE 802.11ax devices

From: Viktor Barna <[email protected]>

Celeno Communications publishes to the opensource new wireless driver
for an own 802.11 chipset family - 80xx. The main chip supports multiple
simultaneous bands functioning (2.4G/5.2G or 5.2G/6G) over PCIe 3.0
dual-lane interface. Basically, the chip is dual-band concurrent up to
8x8 in total, and up to 6x6 per band, including 802.11ax 160MHz support
and functioning of AP/STA/MESH modes. The driver architecture is strong
SoftMAC.

The current patchset is considered to be published in form of RFC
(Request for Comments). If there are any suggestions/propositions - we
will be glad to fix them and eventually share the driver with the
community in form of an official patch (including the firmware
binaries).

The RFC is divided into separate patches on a per-file basis to simplify
the review process.

Signed-off-by: Aviad Brikman <[email protected]>
Signed-off-by: Eliav Farber <[email protected]>
Signed-off-by: Oleksandr Savchenko <[email protected]>
Signed-off-by: Shay Bar <[email protected]>
Signed-off-by: Viktor Barna <[email protected]>

Viktor Barna (256):
celeno: add Kconfig
celeno: add Makefile
cl8k: add Kconfig
cl8k: add Makefile
cl8k: add afe.c
cl8k: add afe.h
cl8k: add agc_params.c
cl8k: add agc_params.h
cl8k: add ampdu.c
cl8k: add ampdu.h
cl8k: add ate.c
cl8k: add ate.h
cl8k: add band.c
cl8k: add band.h
cl8k: add bf.c
cl8k: add bf.h
cl8k: add bus/pci/ipc.c
cl8k: add bus/pci/ipc.h
cl8k: add bus/pci/irq.c
cl8k: add bus/pci/irq.h
cl8k: add bus/pci/msg_pci.c
cl8k: add bus/pci/msg_pci.h
cl8k: add bus/pci/pci.c
cl8k: add bus/pci/rx_pci.c
cl8k: add bus/pci/rx_pci.h
cl8k: add bus/pci/tx_pci.c
cl8k: add bus/pci/tx_pci.h
cl8k: add calib.c
cl8k: add calib.h
cl8k: add cap.c
cl8k: add cap.h
cl8k: add cca.c
cl8k: add cca.h
cl8k: add cecli.c
cl8k: add cecli.h
cl8k: add chandef.c
cl8k: add chandef.h
cl8k: add channel.c
cl8k: add channel.h
cl8k: add chan_info.c
cl8k: add chan_info.h
cl8k: add chip.c
cl8k: add chip.h
cl8k: add chip_config.c
cl8k: add chip_config.h
cl8k: add config.c
cl8k: add config.h
cl8k: add coredump.c
cl8k: add coredump.h
cl8k: add data_rates.c
cl8k: add data_rates.h
cl8k: add dbgfile.c
cl8k: add dbgfile.h
cl8k: add debug.h
cl8k: add debugfs.c
cl8k: add debugfs.h
cl8k: add debugfs_defs.h
cl8k: add def.h
cl8k: add dfs/dfs.c
cl8k: add dfs/dfs.h
cl8k: add dfs/dfs_db.h
cl8k: add dfs/radar.c
cl8k: add dfs/radar.h
cl8k: add drv_ops.h
cl8k: add dsp.c
cl8k: add dsp.h
cl8k: add e2p.c
cl8k: add e2p.h
cl8k: add edca.c
cl8k: add edca.h
cl8k: add ela.c
cl8k: add ela.h
cl8k: add enhanced_tim.c
cl8k: add enhanced_tim.h
cl8k: add env_det.c
cl8k: add env_det.h
cl8k: add ext/dyn_bcast_rate.c
cl8k: add ext/dyn_bcast_rate.h
cl8k: add ext/dyn_mcast_rate.c
cl8k: add ext/dyn_mcast_rate.h
cl8k: add ext/vlan_dscp.c
cl8k: add ext/vlan_dscp.h
cl8k: add fem.c
cl8k: add fem.h
cl8k: add fem_common.h
cl8k: add fw/fw_dbg.c
cl8k: add fw/fw_dbg.h
cl8k: add fw/fw_file.c
cl8k: add fw/fw_file.h
cl8k: add fw/fw_msg.c
cl8k: add fw/fw_msg.h
cl8k: add fw/msg_cfm.c
cl8k: add fw/msg_cfm.h
cl8k: add fw/msg_rx.c
cl8k: add fw/msg_rx.h
cl8k: add fw/msg_tx.c
cl8k: add fw/msg_tx.h
cl8k: add hw.c
cl8k: add hw.h
cl8k: add hw_assert.c
cl8k: add hw_assert.h
cl8k: add ipc_shared.h
cl8k: add key.c
cl8k: add key.h
cl8k: add mac80211.c
cl8k: add mac80211.h
cl8k: add mac_addr.c
cl8k: add mac_addr.h
cl8k: add main.c
cl8k: add main.h
cl8k: add maintenance.c
cl8k: add maintenance.h
cl8k: add mib.c
cl8k: add mib.h
cl8k: add motion_sense.c
cl8k: add motion_sense.h
cl8k: add netlink.c
cl8k: add netlink.h
cl8k: add noise.c
cl8k: add noise.h
cl8k: add omi.c
cl8k: add omi.h
cl8k: add ops.c
cl8k: add ops.h
cl8k: add phy/phy.c
cl8k: add phy/phy.h
cl8k: add phy/phy_athos_lut.c
cl8k: add phy/phy_athos_lut.h
cl8k: add phy/phy_common_lut.c
cl8k: add phy/phy_common_lut.h
cl8k: add phy/phy_olympus_lut.c
cl8k: add phy/phy_olympus_lut.h
cl8k: add power.c
cl8k: add power.h
cl8k: add power_cli.c
cl8k: add power_cli.h
cl8k: add power_table.c
cl8k: add power_table.h
cl8k: add prot_mode.c
cl8k: add prot_mode.h
cl8k: add radio.c
cl8k: add radio.h
cl8k: add rate_ctrl.c
cl8k: add rate_ctrl.h
cl8k: add recovery.c
cl8k: add recovery.h
cl8k: add reg/ceva.h
cl8k: add reg/reg_access.h
cl8k: add reg/reg_cli.c
cl8k: add reg/reg_cli.h
cl8k: add reg/reg_cmu.h
cl8k: add reg/reg_fem.h
cl8k: add reg/reg_io_ctrl.h
cl8k: add reg/reg_ipc.h
cl8k: add reg/reg_lcu_common.h
cl8k: add reg/reg_lcu_phy.h
cl8k: add reg/reg_macdsp_api.h
cl8k: add reg/reg_macsys_gcu.h
cl8k: add reg/reg_mac_hw.h
cl8k: add reg/reg_mac_hw_mu.h
cl8k: add reg/reg_modem_gcu.h
cl8k: add reg/reg_otp_pvt.h
cl8k: add reg/reg_ricu.h
cl8k: add reg/reg_riu.h
cl8k: add reg/reg_riu_rc.h
cl8k: add rf_boot.c
cl8k: add rf_boot.h
cl8k: add rsrc_mgmt.c
cl8k: add rsrc_mgmt.h
cl8k: add rssi.c
cl8k: add rssi.h
cl8k: add rx/rx.c
cl8k: add rx/rx.h
cl8k: add rx/rx_amsdu.c
cl8k: add rx/rx_amsdu.h
cl8k: add rx/rx_filter.c
cl8k: add rx/rx_filter.h
cl8k: add rx/rx_reorder.c
cl8k: add rx/rx_reorder.h
cl8k: add sounding.c
cl8k: add sounding.h
cl8k: add sta.c
cl8k: add sta.h
cl8k: add stats.c
cl8k: add stats.h
cl8k: add tcv_config.c
cl8k: add tcv_config.h
cl8k: add temperature.c
cl8k: add temperature.h
cl8k: add trace.c
cl8k: add trace.h
cl8k: add traffic.c
cl8k: add traffic.h
cl8k: add twt.c
cl8k: add twt.h
cl8k: add twt_cli.c
cl8k: add twt_cli.h
cl8k: add twt_frame.c
cl8k: add twt_frame.h
cl8k: add tx/agg_cfm.c
cl8k: add tx/agg_cfm.h
cl8k: add tx/agg_tx_report.c
cl8k: add tx/agg_tx_report.h
cl8k: add tx/baw.c
cl8k: add tx/baw.h
cl8k: add tx/bcmc_cfm.c
cl8k: add tx/bcmc_cfm.h
cl8k: add tx/single_cfm.c
cl8k: add tx/single_cfm.h
cl8k: add tx/sw_txhdr.c
cl8k: add tx/sw_txhdr.h
cl8k: add tx/tx.c
cl8k: add tx/tx.h
cl8k: add tx/tx_amsdu.c
cl8k: add tx/tx_amsdu.h
cl8k: add tx/tx_inject.c
cl8k: add tx/tx_inject.h
cl8k: add tx/tx_queue.c
cl8k: add tx/tx_queue.h
cl8k: add utils/file.c
cl8k: add utils/file.h
cl8k: add utils/ip.c
cl8k: add utils/ip.h
cl8k: add utils/math.h
cl8k: add utils/string.c
cl8k: add utils/string.h
cl8k: add utils/timer.c
cl8k: add utils/timer.h
cl8k: add utils/utils.c
cl8k: add utils/utils.h
cl8k: add vendor_cmd.c
cl8k: add vendor_cmd.h
cl8k: add version.c
cl8k: add version.h
cl8k: add vif.c
cl8k: add vif.h
cl8k: add vns.c
cl8k: add vns.h
cl8k: add wrs/wrs.c
cl8k: add wrs/wrs.h
cl8k: add wrs/wrs_ap.c
cl8k: add wrs/wrs_ap.h
cl8k: add wrs/wrs_api.c
cl8k: add wrs/wrs_api.h
cl8k: add wrs/wrs_cli.c
cl8k: add wrs/wrs_cli.h
cl8k: add wrs/wrs_db.h
cl8k: add wrs/wrs_rssi.c
cl8k: add wrs/wrs_rssi.h
cl8k: add wrs/wrs_sta.c
cl8k: add wrs/wrs_sta.h
cl8k: add wrs/wrs_stats.c
cl8k: add wrs/wrs_stats.h
cl8k: add wrs/wrs_tables.c
cl8k: add wrs/wrs_tables.h
wireless: add Celeno vendor

drivers/net/wireless/Kconfig | 1 +
drivers/net/wireless/Makefile | 1 +
drivers/net/wireless/celeno/Kconfig | 17 +
drivers/net/wireless/celeno/Makefile | 2 +
drivers/net/wireless/celeno/cl8k/Kconfig | 16 +
drivers/net/wireless/celeno/cl8k/Makefile | 149 +
drivers/net/wireless/celeno/cl8k/afe.c | 737 +++++
drivers/net/wireless/celeno/cl8k/afe.h | 20 +
drivers/net/wireless/celeno/cl8k/agc_params.c | 683 +++++
drivers/net/wireless/celeno/cl8k/agc_params.h | 151 +
drivers/net/wireless/celeno/cl8k/ampdu.c | 344 +++
drivers/net/wireless/celeno/cl8k/ampdu.h | 45 +
drivers/net/wireless/celeno/cl8k/ate.c | 841 ++++++
drivers/net/wireless/celeno/cl8k/ate.h | 90 +
drivers/net/wireless/celeno/cl8k/band.c | 60 +
drivers/net/wireless/celeno/cl8k/band.h | 40 +
drivers/net/wireless/celeno/cl8k/bf.c | 556 ++++
drivers/net/wireless/celeno/cl8k/bf.h | 32 +
.../net/wireless/celeno/cl8k/bus/pci/ipc.c | 1278 ++++++++
.../net/wireless/celeno/cl8k/bus/pci/ipc.h | 135 +
.../net/wireless/celeno/cl8k/bus/pci/irq.c | 331 ++
.../net/wireless/celeno/cl8k/bus/pci/irq.h | 15 +
.../wireless/celeno/cl8k/bus/pci/msg_pci.c | 101 +
.../wireless/celeno/cl8k/bus/pci/msg_pci.h | 12 +
.../net/wireless/celeno/cl8k/bus/pci/pci.c | 210 ++
.../net/wireless/celeno/cl8k/bus/pci/rx_pci.c | 219 ++
.../net/wireless/celeno/cl8k/bus/pci/rx_pci.h | 14 +
.../net/wireless/celeno/cl8k/bus/pci/tx_pci.c | 434 +++
.../net/wireless/celeno/cl8k/bus/pci/tx_pci.h | 14 +
drivers/net/wireless/celeno/cl8k/calib.c | 1682 +++++++++++
drivers/net/wireless/celeno/cl8k/calib.h | 237 ++
drivers/net/wireless/celeno/cl8k/cap.c | 928 ++++++
drivers/net/wireless/celeno/cl8k/cap.h | 21 +
drivers/net/wireless/celeno/cl8k/cca.c | 518 ++++
drivers/net/wireless/celeno/cl8k/cca.h | 30 +
drivers/net/wireless/celeno/cl8k/cecli.c | 354 +++
drivers/net/wireless/celeno/cl8k/cecli.h | 112 +
drivers/net/wireless/celeno/cl8k/chan_info.c | 852 ++++++
drivers/net/wireless/celeno/cl8k/chan_info.h | 32 +
drivers/net/wireless/celeno/cl8k/chandef.c | 152 +
drivers/net/wireless/celeno/cl8k/chandef.h | 14 +
drivers/net/wireless/celeno/cl8k/channel.c | 373 +++
drivers/net/wireless/celeno/cl8k/channel.h | 187 ++
drivers/net/wireless/celeno/cl8k/chip.c | 241 ++
drivers/net/wireless/celeno/cl8k/chip.h | 143 +
.../net/wireless/celeno/cl8k/chip_config.c | 290 ++
.../net/wireless/celeno/cl8k/chip_config.h | 58 +
drivers/net/wireless/celeno/cl8k/config.c | 121 +
drivers/net/wireless/celeno/cl8k/config.h | 392 +++
drivers/net/wireless/celeno/cl8k/coredump.c | 190 ++
drivers/net/wireless/celeno/cl8k/coredump.h | 76 +
drivers/net/wireless/celeno/cl8k/data_rates.c | 1019 +++++++
drivers/net/wireless/celeno/cl8k/data_rates.h | 30 +
drivers/net/wireless/celeno/cl8k/dbgfile.c | 438 +++
drivers/net/wireless/celeno/cl8k/dbgfile.h | 23 +
drivers/net/wireless/celeno/cl8k/debug.h | 121 +
drivers/net/wireless/celeno/cl8k/debugfs.c | 957 ++++++
drivers/net/wireless/celeno/cl8k/debugfs.h | 28 +
.../net/wireless/celeno/cl8k/debugfs_defs.h | 36 +
drivers/net/wireless/celeno/cl8k/def.h | 269 ++
drivers/net/wireless/celeno/cl8k/dfs/dfs.c | 977 ++++++
drivers/net/wireless/celeno/cl8k/dfs/dfs.h | 26 +
drivers/net/wireless/celeno/cl8k/dfs/dfs_db.h | 107 +
drivers/net/wireless/celeno/cl8k/dfs/radar.c | 116 +
drivers/net/wireless/celeno/cl8k/dfs/radar.h | 55 +
drivers/net/wireless/celeno/cl8k/drv_ops.h | 28 +
drivers/net/wireless/celeno/cl8k/dsp.c | 611 ++++
drivers/net/wireless/celeno/cl8k/dsp.h | 27 +
drivers/net/wireless/celeno/cl8k/e2p.c | 664 ++++
drivers/net/wireless/celeno/cl8k/e2p.h | 166 +
drivers/net/wireless/celeno/cl8k/edca.c | 265 ++
drivers/net/wireless/celeno/cl8k/edca.h | 47 +
drivers/net/wireless/celeno/cl8k/ela.c | 227 ++
drivers/net/wireless/celeno/cl8k/ela.h | 38 +
.../net/wireless/celeno/cl8k/enhanced_tim.c | 216 ++
.../net/wireless/celeno/cl8k/enhanced_tim.h | 24 +
drivers/net/wireless/celeno/cl8k/env_det.c | 32 +
drivers/net/wireless/celeno/cl8k/env_det.h | 36 +
.../wireless/celeno/cl8k/ext/dyn_bcast_rate.c | 182 ++
.../wireless/celeno/cl8k/ext/dyn_bcast_rate.h | 18 +
.../wireless/celeno/cl8k/ext/dyn_mcast_rate.c | 125 +
.../wireless/celeno/cl8k/ext/dyn_mcast_rate.h | 14 +
.../net/wireless/celeno/cl8k/ext/vlan_dscp.c | 658 ++++
.../net/wireless/celeno/cl8k/ext/vlan_dscp.h | 37 +
drivers/net/wireless/celeno/cl8k/fem.c | 1271 ++++++++
drivers/net/wireless/celeno/cl8k/fem.h | 32 +
drivers/net/wireless/celeno/cl8k/fem_common.h | 79 +
drivers/net/wireless/celeno/cl8k/fw/fw_dbg.c | 2686 +++++++++++++++++
drivers/net/wireless/celeno/cl8k/fw/fw_dbg.h | 30 +
drivers/net/wireless/celeno/cl8k/fw/fw_file.c | 485 +++
drivers/net/wireless/celeno/cl8k/fw/fw_file.h | 13 +
drivers/net/wireless/celeno/cl8k/fw/fw_msg.c | 135 +
drivers/net/wireless/celeno/cl8k/fw/fw_msg.h | 1656 ++++++++++
drivers/net/wireless/celeno/cl8k/fw/msg_cfm.c | 316 ++
drivers/net/wireless/celeno/cl8k/fw/msg_cfm.h | 35 +
drivers/net/wireless/celeno/cl8k/fw/msg_rx.c | 349 +++
drivers/net/wireless/celeno/cl8k/fw/msg_rx.h | 10 +
drivers/net/wireless/celeno/cl8k/fw/msg_tx.c | 1800 +++++++++++
drivers/net/wireless/celeno/cl8k/fw/msg_tx.h | 141 +
drivers/net/wireless/celeno/cl8k/hw.c | 166 +
drivers/net/wireless/celeno/cl8k/hw.h | 797 +++++
drivers/net/wireless/celeno/cl8k/hw_assert.c | 129 +
drivers/net/wireless/celeno/cl8k/hw_assert.h | 13 +
drivers/net/wireless/celeno/cl8k/ipc_shared.h | 1445 +++++++++
drivers/net/wireless/celeno/cl8k/key.c | 197 ++
drivers/net/wireless/celeno/cl8k/key.h | 19 +
drivers/net/wireless/celeno/cl8k/mac80211.c | 17 +
drivers/net/wireless/celeno/cl8k/mac80211.h | 310 ++
drivers/net/wireless/celeno/cl8k/mac_addr.c | 331 ++
drivers/net/wireless/celeno/cl8k/mac_addr.h | 67 +
drivers/net/wireless/celeno/cl8k/main.c | 584 ++++
drivers/net/wireless/celeno/cl8k/main.h | 16 +
.../net/wireless/celeno/cl8k/maintenance.c | 80 +
.../net/wireless/celeno/cl8k/maintenance.h | 17 +
drivers/net/wireless/celeno/cl8k/mib.c | 437 +++
drivers/net/wireless/celeno/cl8k/mib.h | 286 ++
.../net/wireless/celeno/cl8k/motion_sense.c | 458 +++
.../net/wireless/celeno/cl8k/motion_sense.h | 47 +
drivers/net/wireless/celeno/cl8k/netlink.c | 41 +
drivers/net/wireless/celeno/cl8k/netlink.h | 28 +
drivers/net/wireless/celeno/cl8k/noise.c | 499 +++
drivers/net/wireless/celeno/cl8k/noise.h | 15 +
drivers/net/wireless/celeno/cl8k/omi.c | 214 ++
drivers/net/wireless/celeno/cl8k/omi.h | 31 +
drivers/net/wireless/celeno/cl8k/ops.c | 889 ++++++
drivers/net/wireless/celeno/cl8k/ops.h | 59 +
drivers/net/wireless/celeno/cl8k/phy/phy.c | 272 ++
drivers/net/wireless/celeno/cl8k/phy/phy.h | 17 +
.../wireless/celeno/cl8k/phy/phy_athos_lut.c | 2069 +++++++++++++
.../wireless/celeno/cl8k/phy/phy_athos_lut.h | 1049 +++++++
.../wireless/celeno/cl8k/phy/phy_common_lut.c | 143 +
.../wireless/celeno/cl8k/phy/phy_common_lut.h | 21 +
.../celeno/cl8k/phy/phy_olympus_lut.c | 2189 ++++++++++++++
.../celeno/cl8k/phy/phy_olympus_lut.h | 777 +++++
drivers/net/wireless/celeno/cl8k/power.c | 946 ++++++
drivers/net/wireless/celeno/cl8k/power.h | 37 +
drivers/net/wireless/celeno/cl8k/power_cli.c | 878 ++++++
drivers/net/wireless/celeno/cl8k/power_cli.h | 12 +
.../net/wireless/celeno/cl8k/power_table.c | 218 ++
.../net/wireless/celeno/cl8k/power_table.h | 25 +
drivers/net/wireless/celeno/cl8k/prot_mode.c | 53 +
drivers/net/wireless/celeno/cl8k/prot_mode.h | 30 +
drivers/net/wireless/celeno/cl8k/radio.c | 171 ++
drivers/net/wireless/celeno/cl8k/radio.h | 24 +
drivers/net/wireless/celeno/cl8k/rate_ctrl.c | 276 ++
drivers/net/wireless/celeno/cl8k/rate_ctrl.h | 106 +
drivers/net/wireless/celeno/cl8k/recovery.c | 264 ++
drivers/net/wireless/celeno/cl8k/recovery.h | 27 +
drivers/net/wireless/celeno/cl8k/reg/ceva.h | 44 +
.../net/wireless/celeno/cl8k/reg/reg_access.h | 197 ++
.../net/wireless/celeno/cl8k/reg/reg_cli.c | 277 ++
.../net/wireless/celeno/cl8k/reg/reg_cli.h | 11 +
.../net/wireless/celeno/cl8k/reg/reg_cmu.h | 379 +++
.../net/wireless/celeno/cl8k/reg/reg_fem.h | 102 +
.../wireless/celeno/cl8k/reg/reg_io_ctrl.h | 1223 ++++++++
.../net/wireless/celeno/cl8k/reg/reg_ipc.h | 157 +
.../wireless/celeno/cl8k/reg/reg_lcu_common.h | 32 +
.../wireless/celeno/cl8k/reg/reg_lcu_phy.h | 92 +
.../net/wireless/celeno/cl8k/reg/reg_mac_hw.h | 490 +++
.../wireless/celeno/cl8k/reg/reg_mac_hw_mu.h | 33 +
.../wireless/celeno/cl8k/reg/reg_macdsp_api.h | 66 +
.../wireless/celeno/cl8k/reg/reg_macsys_gcu.h | 94 +
.../wireless/celeno/cl8k/reg/reg_modem_gcu.h | 628 ++++
.../wireless/celeno/cl8k/reg/reg_otp_pvt.h | 219 ++
.../net/wireless/celeno/cl8k/reg/reg_ricu.h | 1326 ++++++++
.../net/wireless/celeno/cl8k/reg/reg_riu.h | 902 ++++++
.../net/wireless/celeno/cl8k/reg/reg_riu_rc.h | 115 +
drivers/net/wireless/celeno/cl8k/rf_boot.c | 354 +++
drivers/net/wireless/celeno/cl8k/rf_boot.h | 12 +
drivers/net/wireless/celeno/cl8k/rsrc_mgmt.c | 279 ++
drivers/net/wireless/celeno/cl8k/rsrc_mgmt.h | 29 +
drivers/net/wireless/celeno/cl8k/rssi.c | 320 ++
drivers/net/wireless/celeno/cl8k/rssi.h | 28 +
drivers/net/wireless/celeno/cl8k/rx/rx.c | 1108 +++++++
drivers/net/wireless/celeno/cl8k/rx/rx.h | 173 ++
.../net/wireless/celeno/cl8k/rx/rx_amsdu.c | 257 ++
.../net/wireless/celeno/cl8k/rx/rx_amsdu.h | 20 +
.../net/wireless/celeno/cl8k/rx/rx_filter.c | 88 +
.../net/wireless/celeno/cl8k/rx/rx_filter.h | 91 +
.../net/wireless/celeno/cl8k/rx/rx_reorder.c | 335 ++
.../net/wireless/celeno/cl8k/rx/rx_reorder.h | 14 +
drivers/net/wireless/celeno/cl8k/sounding.c | 1432 +++++++++
drivers/net/wireless/celeno/cl8k/sounding.h | 148 +
drivers/net/wireless/celeno/cl8k/sta.c | 536 ++++
drivers/net/wireless/celeno/cl8k/sta.h | 241 ++
drivers/net/wireless/celeno/cl8k/stats.c | 1402 +++++++++
drivers/net/wireless/celeno/cl8k/stats.h | 27 +
drivers/net/wireless/celeno/cl8k/tcv_config.c | 1463 +++++++++
drivers/net/wireless/celeno/cl8k/tcv_config.h | 333 ++
.../net/wireless/celeno/cl8k/temperature.c | 858 ++++++
.../net/wireless/celeno/cl8k/temperature.h | 74 +
drivers/net/wireless/celeno/cl8k/trace.c | 9 +
drivers/net/wireless/celeno/cl8k/trace.h | 203 ++
drivers/net/wireless/celeno/cl8k/traffic.c | 315 ++
drivers/net/wireless/celeno/cl8k/traffic.h | 57 +
drivers/net/wireless/celeno/cl8k/twt.c | 455 +++
drivers/net/wireless/celeno/cl8k/twt.h | 58 +
drivers/net/wireless/celeno/cl8k/twt_cli.c | 359 +++
drivers/net/wireless/celeno/cl8k/twt_cli.h | 11 +
drivers/net/wireless/celeno/cl8k/twt_frame.c | 385 +++
drivers/net/wireless/celeno/cl8k/twt_frame.h | 39 +
drivers/net/wireless/celeno/cl8k/tx/agg_cfm.c | 219 ++
drivers/net/wireless/celeno/cl8k/tx/agg_cfm.h | 21 +
.../wireless/celeno/cl8k/tx/agg_tx_report.c | 196 ++
.../wireless/celeno/cl8k/tx/agg_tx_report.h | 92 +
drivers/net/wireless/celeno/cl8k/tx/baw.c | 74 +
drivers/net/wireless/celeno/cl8k/tx/baw.h | 26 +
.../net/wireless/celeno/cl8k/tx/bcmc_cfm.c | 64 +
.../net/wireless/celeno/cl8k/tx/bcmc_cfm.h | 14 +
.../net/wireless/celeno/cl8k/tx/single_cfm.c | 214 ++
.../net/wireless/celeno/cl8k/tx/single_cfm.h | 18 +
.../net/wireless/celeno/cl8k/tx/sw_txhdr.c | 40 +
.../net/wireless/celeno/cl8k/tx/sw_txhdr.h | 45 +
drivers/net/wireless/celeno/cl8k/tx/tx.c | 1325 ++++++++
drivers/net/wireless/celeno/cl8k/tx/tx.h | 109 +
.../net/wireless/celeno/cl8k/tx/tx_amsdu.c | 483 +++
.../net/wireless/celeno/cl8k/tx/tx_amsdu.h | 43 +
.../net/wireless/celeno/cl8k/tx/tx_inject.c | 364 +++
.../net/wireless/celeno/cl8k/tx/tx_inject.h | 39 +
.../net/wireless/celeno/cl8k/tx/tx_queue.c | 1620 ++++++++++
.../net/wireless/celeno/cl8k/tx/tx_queue.h | 48 +
drivers/net/wireless/celeno/cl8k/utils/file.c | 52 +
drivers/net/wireless/celeno/cl8k/utils/file.h | 18 +
drivers/net/wireless/celeno/cl8k/utils/ip.c | 140 +
drivers/net/wireless/celeno/cl8k/utils/ip.h | 51 +
drivers/net/wireless/celeno/cl8k/utils/math.h | 18 +
.../net/wireless/celeno/cl8k/utils/string.c | 235 ++
.../net/wireless/celeno/cl8k/utils/string.h | 25 +
.../net/wireless/celeno/cl8k/utils/timer.c | 72 +
.../net/wireless/celeno/cl8k/utils/timer.h | 30 +
.../net/wireless/celeno/cl8k/utils/utils.c | 388 +++
.../net/wireless/celeno/cl8k/utils/utils.h | 104 +
drivers/net/wireless/celeno/cl8k/vendor_cmd.c | 377 +++
drivers/net/wireless/celeno/cl8k/vendor_cmd.h | 116 +
drivers/net/wireless/celeno/cl8k/version.c | 129 +
drivers/net/wireless/celeno/cl8k/version.h | 14 +
drivers/net/wireless/celeno/cl8k/vif.c | 143 +
drivers/net/wireless/celeno/cl8k/vif.h | 44 +
drivers/net/wireless/celeno/cl8k/vns.c | 505 ++++
drivers/net/wireless/celeno/cl8k/vns.h | 36 +
drivers/net/wireless/celeno/cl8k/wrs/wrs.c | 1159 +++++++
drivers/net/wireless/celeno/cl8k/wrs/wrs.h | 45 +
drivers/net/wireless/celeno/cl8k/wrs/wrs_ap.c | 99 +
drivers/net/wireless/celeno/cl8k/wrs/wrs_ap.h | 13 +
.../net/wireless/celeno/cl8k/wrs/wrs_api.c | 212 ++
.../net/wireless/celeno/cl8k/wrs/wrs_api.h | 30 +
.../net/wireless/celeno/cl8k/wrs/wrs_cli.c | 852 ++++++
.../net/wireless/celeno/cl8k/wrs/wrs_cli.h | 12 +
drivers/net/wireless/celeno/cl8k/wrs/wrs_db.h | 386 +++
.../net/wireless/celeno/cl8k/wrs/wrs_rssi.c | 444 +++
.../net/wireless/celeno/cl8k/wrs/wrs_rssi.h | 22 +
.../net/wireless/celeno/cl8k/wrs/wrs_sta.c | 360 +++
.../net/wireless/celeno/cl8k/wrs/wrs_sta.h | 20 +
.../net/wireless/celeno/cl8k/wrs/wrs_stats.c | 242 ++
.../net/wireless/celeno/cl8k/wrs/wrs_stats.h | 24 +
.../net/wireless/celeno/cl8k/wrs/wrs_tables.c | 774 +++++
.../net/wireless/celeno/cl8k/wrs/wrs_tables.h | 76 +
257 files changed, 77223 insertions(+)
create mode 100644 drivers/net/wireless/celeno/Kconfig
create mode 100644 drivers/net/wireless/celeno/Makefile
create mode 100644 drivers/net/wireless/celeno/cl8k/Kconfig
create mode 100644 drivers/net/wireless/celeno/cl8k/Makefile
create mode 100644 drivers/net/wireless/celeno/cl8k/afe.c
create mode 100644 drivers/net/wireless/celeno/cl8k/afe.h
create mode 100644 drivers/net/wireless/celeno/cl8k/agc_params.c
create mode 100644 drivers/net/wireless/celeno/cl8k/agc_params.h
create mode 100644 drivers/net/wireless/celeno/cl8k/ampdu.c
create mode 100644 drivers/net/wireless/celeno/cl8k/ampdu.h
create mode 100644 drivers/net/wireless/celeno/cl8k/ate.c
create mode 100644 drivers/net/wireless/celeno/cl8k/ate.h
create mode 100644 drivers/net/wireless/celeno/cl8k/band.c
create mode 100644 drivers/net/wireless/celeno/cl8k/band.h
create mode 100644 drivers/net/wireless/celeno/cl8k/bf.c
create mode 100644 drivers/net/wireless/celeno/cl8k/bf.h
create mode 100644 drivers/net/wireless/celeno/cl8k/bus/pci/ipc.c
create mode 100644 drivers/net/wireless/celeno/cl8k/bus/pci/ipc.h
create mode 100644 drivers/net/wireless/celeno/cl8k/bus/pci/irq.c
create mode 100644 drivers/net/wireless/celeno/cl8k/bus/pci/irq.h
create mode 100644 drivers/net/wireless/celeno/cl8k/bus/pci/msg_pci.c
create mode 100644 drivers/net/wireless/celeno/cl8k/bus/pci/msg_pci.h
create mode 100644 drivers/net/wireless/celeno/cl8k/bus/pci/pci.c
create mode 100644 drivers/net/wireless/celeno/cl8k/bus/pci/rx_pci.c
create mode 100644 drivers/net/wireless/celeno/cl8k/bus/pci/rx_pci.h
create mode 100644 drivers/net/wireless/celeno/cl8k/bus/pci/tx_pci.c
create mode 100644 drivers/net/wireless/celeno/cl8k/bus/pci/tx_pci.h
create mode 100644 drivers/net/wireless/celeno/cl8k/calib.c
create mode 100644 drivers/net/wireless/celeno/cl8k/calib.h
create mode 100644 drivers/net/wireless/celeno/cl8k/cap.c
create mode 100644 drivers/net/wireless/celeno/cl8k/cap.h
create mode 100644 drivers/net/wireless/celeno/cl8k/cca.c
create mode 100644 drivers/net/wireless/celeno/cl8k/cca.h
create mode 100644 drivers/net/wireless/celeno/cl8k/cecli.c
create mode 100644 drivers/net/wireless/celeno/cl8k/cecli.h
create mode 100644 drivers/net/wireless/celeno/cl8k/chan_info.c
create mode 100644 drivers/net/wireless/celeno/cl8k/chan_info.h
create mode 100644 drivers/net/wireless/celeno/cl8k/chandef.c
create mode 100644 drivers/net/wireless/celeno/cl8k/chandef.h
create mode 100644 drivers/net/wireless/celeno/cl8k/channel.c
create mode 100644 drivers/net/wireless/celeno/cl8k/channel.h
create mode 100644 drivers/net/wireless/celeno/cl8k/chip.c
create mode 100644 drivers/net/wireless/celeno/cl8k/chip.h
create mode 100644 drivers/net/wireless/celeno/cl8k/chip_config.c
create mode 100644 drivers/net/wireless/celeno/cl8k/chip_config.h
create mode 100644 drivers/net/wireless/celeno/cl8k/config.c
create mode 100644 drivers/net/wireless/celeno/cl8k/config.h
create mode 100644 drivers/net/wireless/celeno/cl8k/coredump.c
create mode 100644 drivers/net/wireless/celeno/cl8k/coredump.h
create mode 100644 drivers/net/wireless/celeno/cl8k/data_rates.c
create mode 100644 drivers/net/wireless/celeno/cl8k/data_rates.h
create mode 100644 drivers/net/wireless/celeno/cl8k/dbgfile.c
create mode 100644 drivers/net/wireless/celeno/cl8k/dbgfile.h
create mode 100644 drivers/net/wireless/celeno/cl8k/debug.h
create mode 100644 drivers/net/wireless/celeno/cl8k/debugfs.c
create mode 100644 drivers/net/wireless/celeno/cl8k/debugfs.h
create mode 100644 drivers/net/wireless/celeno/cl8k/debugfs_defs.h
create mode 100644 drivers/net/wireless/celeno/cl8k/def.h
create mode 100644 drivers/net/wireless/celeno/cl8k/dfs/dfs.c
create mode 100644 drivers/net/wireless/celeno/cl8k/dfs/dfs.h
create mode 100644 drivers/net/wireless/celeno/cl8k/dfs/dfs_db.h
create mode 100644 drivers/net/wireless/celeno/cl8k/dfs/radar.c
create mode 100644 drivers/net/wireless/celeno/cl8k/dfs/radar.h
create mode 100644 drivers/net/wireless/celeno/cl8k/drv_ops.h
create mode 100644 drivers/net/wireless/celeno/cl8k/dsp.c
create mode 100644 drivers/net/wireless/celeno/cl8k/dsp.h
create mode 100644 drivers/net/wireless/celeno/cl8k/e2p.c
create mode 100644 drivers/net/wireless/celeno/cl8k/e2p.h
create mode 100644 drivers/net/wireless/celeno/cl8k/edca.c
create mode 100644 drivers/net/wireless/celeno/cl8k/edca.h
create mode 100644 drivers/net/wireless/celeno/cl8k/ela.c
create mode 100644 drivers/net/wireless/celeno/cl8k/ela.h
create mode 100644 drivers/net/wireless/celeno/cl8k/enhanced_tim.c
create mode 100644 drivers/net/wireless/celeno/cl8k/enhanced_tim.h
create mode 100644 drivers/net/wireless/celeno/cl8k/env_det.c
create mode 100644 drivers/net/wireless/celeno/cl8k/env_det.h
create mode 100644 drivers/net/wireless/celeno/cl8k/ext/dyn_bcast_rate.c
create mode 100644 drivers/net/wireless/celeno/cl8k/ext/dyn_bcast_rate.h
create mode 100644 drivers/net/wireless/celeno/cl8k/ext/dyn_mcast_rate.c
create mode 100644 drivers/net/wireless/celeno/cl8k/ext/dyn_mcast_rate.h
create mode 100644 drivers/net/wireless/celeno/cl8k/ext/vlan_dscp.c
create mode 100644 drivers/net/wireless/celeno/cl8k/ext/vlan_dscp.h
create mode 100644 drivers/net/wireless/celeno/cl8k/fem.c
create mode 100644 drivers/net/wireless/celeno/cl8k/fem.h
create mode 100644 drivers/net/wireless/celeno/cl8k/fem_common.h
create mode 100644 drivers/net/wireless/celeno/cl8k/fw/fw_dbg.c
create mode 100644 drivers/net/wireless/celeno/cl8k/fw/fw_dbg.h
create mode 100644 drivers/net/wireless/celeno/cl8k/fw/fw_file.c
create mode 100644 drivers/net/wireless/celeno/cl8k/fw/fw_file.h
create mode 100644 drivers/net/wireless/celeno/cl8k/fw/fw_msg.c
create mode 100644 drivers/net/wireless/celeno/cl8k/fw/fw_msg.h
create mode 100644 drivers/net/wireless/celeno/cl8k/fw/msg_cfm.c
create mode 100644 drivers/net/wireless/celeno/cl8k/fw/msg_cfm.h
create mode 100644 drivers/net/wireless/celeno/cl8k/fw/msg_rx.c
create mode 100644 drivers/net/wireless/celeno/cl8k/fw/msg_rx.h
create mode 100644 drivers/net/wireless/celeno/cl8k/fw/msg_tx.c
create mode 100644 drivers/net/wireless/celeno/cl8k/fw/msg_tx.h
create mode 100644 drivers/net/wireless/celeno/cl8k/hw.c
create mode 100644 drivers/net/wireless/celeno/cl8k/hw.h
create mode 100644 drivers/net/wireless/celeno/cl8k/hw_assert.c
create mode 100644 drivers/net/wireless/celeno/cl8k/hw_assert.h
create mode 100644 drivers/net/wireless/celeno/cl8k/ipc_shared.h
create mode 100644 drivers/net/wireless/celeno/cl8k/key.c
create mode 100644 drivers/net/wireless/celeno/cl8k/key.h
create mode 100644 drivers/net/wireless/celeno/cl8k/mac80211.c
create mode 100644 drivers/net/wireless/celeno/cl8k/mac80211.h
create mode 100644 drivers/net/wireless/celeno/cl8k/mac_addr.c
create mode 100644 drivers/net/wireless/celeno/cl8k/mac_addr.h
create mode 100644 drivers/net/wireless/celeno/cl8k/main.c
create mode 100644 drivers/net/wireless/celeno/cl8k/main.h
create mode 100644 drivers/net/wireless/celeno/cl8k/maintenance.c
create mode 100644 drivers/net/wireless/celeno/cl8k/maintenance.h
create mode 100644 drivers/net/wireless/celeno/cl8k/mib.c
create mode 100644 drivers/net/wireless/celeno/cl8k/mib.h
create mode 100644 drivers/net/wireless/celeno/cl8k/motion_sense.c
create mode 100644 drivers/net/wireless/celeno/cl8k/motion_sense.h
create mode 100644 drivers/net/wireless/celeno/cl8k/netlink.c
create mode 100644 drivers/net/wireless/celeno/cl8k/netlink.h
create mode 100644 drivers/net/wireless/celeno/cl8k/noise.c
create mode 100644 drivers/net/wireless/celeno/cl8k/noise.h
create mode 100644 drivers/net/wireless/celeno/cl8k/omi.c
create mode 100644 drivers/net/wireless/celeno/cl8k/omi.h
create mode 100644 drivers/net/wireless/celeno/cl8k/ops.c
create mode 100644 drivers/net/wireless/celeno/cl8k/ops.h
create mode 100644 drivers/net/wireless/celeno/cl8k/phy/phy.c
create mode 100644 drivers/net/wireless/celeno/cl8k/phy/phy.h
create mode 100644 drivers/net/wireless/celeno/cl8k/phy/phy_athos_lut.c
create mode 100644 drivers/net/wireless/celeno/cl8k/phy/phy_athos_lut.h
create mode 100644 drivers/net/wireless/celeno/cl8k/phy/phy_common_lut.c
create mode 100644 drivers/net/wireless/celeno/cl8k/phy/phy_common_lut.h
create mode 100644 drivers/net/wireless/celeno/cl8k/phy/phy_olympus_lut.c
create mode 100644 drivers/net/wireless/celeno/cl8k/phy/phy_olympus_lut.h
create mode 100644 drivers/net/wireless/celeno/cl8k/power.c
create mode 100644 drivers/net/wireless/celeno/cl8k/power.h
create mode 100644 drivers/net/wireless/celeno/cl8k/power_cli.c
create mode 100644 drivers/net/wireless/celeno/cl8k/power_cli.h
create mode 100644 drivers/net/wireless/celeno/cl8k/power_table.c
create mode 100644 drivers/net/wireless/celeno/cl8k/power_table.h
create mode 100644 drivers/net/wireless/celeno/cl8k/prot_mode.c
create mode 100644 drivers/net/wireless/celeno/cl8k/prot_mode.h
create mode 100644 drivers/net/wireless/celeno/cl8k/radio.c
create mode 100644 drivers/net/wireless/celeno/cl8k/radio.h
create mode 100644 drivers/net/wireless/celeno/cl8k/rate_ctrl.c
create mode 100644 drivers/net/wireless/celeno/cl8k/rate_ctrl.h
create mode 100644 drivers/net/wireless/celeno/cl8k/recovery.c
create mode 100644 drivers/net/wireless/celeno/cl8k/recovery.h
create mode 100644 drivers/net/wireless/celeno/cl8k/reg/ceva.h
create mode 100644 drivers/net/wireless/celeno/cl8k/reg/reg_access.h
create mode 100644 drivers/net/wireless/celeno/cl8k/reg/reg_cli.c
create mode 100644 drivers/net/wireless/celeno/cl8k/reg/reg_cli.h
create mode 100644 drivers/net/wireless/celeno/cl8k/reg/reg_cmu.h
create mode 100644 drivers/net/wireless/celeno/cl8k/reg/reg_fem.h
create mode 100644 drivers/net/wireless/celeno/cl8k/reg/reg_io_ctrl.h
create mode 100644 drivers/net/wireless/celeno/cl8k/reg/reg_ipc.h
create mode 100644 drivers/net/wireless/celeno/cl8k/reg/reg_lcu_common.h
create mode 100644 drivers/net/wireless/celeno/cl8k/reg/reg_lcu_phy.h
create mode 100644 drivers/net/wireless/celeno/cl8k/reg/reg_mac_hw.h
create mode 100644 drivers/net/wireless/celeno/cl8k/reg/reg_mac_hw_mu.h
create mode 100644 drivers/net/wireless/celeno/cl8k/reg/reg_macdsp_api.h
create mode 100644 drivers/net/wireless/celeno/cl8k/reg/reg_macsys_gcu.h
create mode 100644 drivers/net/wireless/celeno/cl8k/reg/reg_modem_gcu.h
create mode 100644 drivers/net/wireless/celeno/cl8k/reg/reg_otp_pvt.h
create mode 100644 drivers/net/wireless/celeno/cl8k/reg/reg_ricu.h
create mode 100644 drivers/net/wireless/celeno/cl8k/reg/reg_riu.h
create mode 100644 drivers/net/wireless/celeno/cl8k/reg/reg_riu_rc.h
create mode 100644 drivers/net/wireless/celeno/cl8k/rf_boot.c
create mode 100644 drivers/net/wireless/celeno/cl8k/rf_boot.h
create mode 100644 drivers/net/wireless/celeno/cl8k/rsrc_mgmt.c
create mode 100644 drivers/net/wireless/celeno/cl8k/rsrc_mgmt.h
create mode 100644 drivers/net/wireless/celeno/cl8k/rssi.c
create mode 100644 drivers/net/wireless/celeno/cl8k/rssi.h
create mode 100644 drivers/net/wireless/celeno/cl8k/rx/rx.c
create mode 100644 drivers/net/wireless/celeno/cl8k/rx/rx.h
create mode 100644 drivers/net/wireless/celeno/cl8k/rx/rx_amsdu.c
create mode 100644 drivers/net/wireless/celeno/cl8k/rx/rx_amsdu.h
create mode 100644 drivers/net/wireless/celeno/cl8k/rx/rx_filter.c
create mode 100644 drivers/net/wireless/celeno/cl8k/rx/rx_filter.h
create mode 100644 drivers/net/wireless/celeno/cl8k/rx/rx_reorder.c
create mode 100644 drivers/net/wireless/celeno/cl8k/rx/rx_reorder.h
create mode 100644 drivers/net/wireless/celeno/cl8k/sounding.c
create mode 100644 drivers/net/wireless/celeno/cl8k/sounding.h
create mode 100644 drivers/net/wireless/celeno/cl8k/sta.c
create mode 100644 drivers/net/wireless/celeno/cl8k/sta.h
create mode 100644 drivers/net/wireless/celeno/cl8k/stats.c
create mode 100644 drivers/net/wireless/celeno/cl8k/stats.h
create mode 100644 drivers/net/wireless/celeno/cl8k/tcv_config.c
create mode 100644 drivers/net/wireless/celeno/cl8k/tcv_config.h
create mode 100644 drivers/net/wireless/celeno/cl8k/temperature.c
create mode 100644 drivers/net/wireless/celeno/cl8k/temperature.h
create mode 100644 drivers/net/wireless/celeno/cl8k/trace.c
create mode 100644 drivers/net/wireless/celeno/cl8k/trace.h
create mode 100644 drivers/net/wireless/celeno/cl8k/traffic.c
create mode 100644 drivers/net/wireless/celeno/cl8k/traffic.h
create mode 100644 drivers/net/wireless/celeno/cl8k/twt.c
create mode 100644 drivers/net/wireless/celeno/cl8k/twt.h
create mode 100644 drivers/net/wireless/celeno/cl8k/twt_cli.c
create mode 100644 drivers/net/wireless/celeno/cl8k/twt_cli.h
create mode 100644 drivers/net/wireless/celeno/cl8k/twt_frame.c
create mode 100644 drivers/net/wireless/celeno/cl8k/twt_frame.h
create mode 100644 drivers/net/wireless/celeno/cl8k/tx/agg_cfm.c
create mode 100644 drivers/net/wireless/celeno/cl8k/tx/agg_cfm.h
create mode 100644 drivers/net/wireless/celeno/cl8k/tx/agg_tx_report.c
create mode 100644 drivers/net/wireless/celeno/cl8k/tx/agg_tx_report.h
create mode 100644 drivers/net/wireless/celeno/cl8k/tx/baw.c
create mode 100644 drivers/net/wireless/celeno/cl8k/tx/baw.h
create mode 100644 drivers/net/wireless/celeno/cl8k/tx/bcmc_cfm.c
create mode 100644 drivers/net/wireless/celeno/cl8k/tx/bcmc_cfm.h
create mode 100644 drivers/net/wireless/celeno/cl8k/tx/single_cfm.c
create mode 100644 drivers/net/wireless/celeno/cl8k/tx/single_cfm.h
create mode 100644 drivers/net/wireless/celeno/cl8k/tx/sw_txhdr.c
create mode 100644 drivers/net/wireless/celeno/cl8k/tx/sw_txhdr.h
create mode 100644 drivers/net/wireless/celeno/cl8k/tx/tx.c
create mode 100644 drivers/net/wireless/celeno/cl8k/tx/tx.h
create mode 100644 drivers/net/wireless/celeno/cl8k/tx/tx_amsdu.c
create mode 100644 drivers/net/wireless/celeno/cl8k/tx/tx_amsdu.h
create mode 100644 drivers/net/wireless/celeno/cl8k/tx/tx_inject.c
create mode 100644 drivers/net/wireless/celeno/cl8k/tx/tx_inject.h
create mode 100644 drivers/net/wireless/celeno/cl8k/tx/tx_queue.c
create mode 100644 drivers/net/wireless/celeno/cl8k/tx/tx_queue.h
create mode 100644 drivers/net/wireless/celeno/cl8k/utils/file.c
create mode 100644 drivers/net/wireless/celeno/cl8k/utils/file.h
create mode 100644 drivers/net/wireless/celeno/cl8k/utils/ip.c
create mode 100644 drivers/net/wireless/celeno/cl8k/utils/ip.h
create mode 100644 drivers/net/wireless/celeno/cl8k/utils/math.h
create mode 100644 drivers/net/wireless/celeno/cl8k/utils/string.c
create mode 100644 drivers/net/wireless/celeno/cl8k/utils/string.h
create mode 100644 drivers/net/wireless/celeno/cl8k/utils/timer.c
create mode 100644 drivers/net/wireless/celeno/cl8k/utils/timer.h
create mode 100644 drivers/net/wireless/celeno/cl8k/utils/utils.c
create mode 100644 drivers/net/wireless/celeno/cl8k/utils/utils.h
create mode 100644 drivers/net/wireless/celeno/cl8k/vendor_cmd.c
create mode 100644 drivers/net/wireless/celeno/cl8k/vendor_cmd.h
create mode 100644 drivers/net/wireless/celeno/cl8k/version.c
create mode 100644 drivers/net/wireless/celeno/cl8k/version.h
create mode 100644 drivers/net/wireless/celeno/cl8k/vif.c
create mode 100644 drivers/net/wireless/celeno/cl8k/vif.h
create mode 100644 drivers/net/wireless/celeno/cl8k/vns.c
create mode 100644 drivers/net/wireless/celeno/cl8k/vns.h
create mode 100644 drivers/net/wireless/celeno/cl8k/wrs/wrs.c
create mode 100644 drivers/net/wireless/celeno/cl8k/wrs/wrs.h
create mode 100644 drivers/net/wireless/celeno/cl8k/wrs/wrs_ap.c
create mode 100644 drivers/net/wireless/celeno/cl8k/wrs/wrs_ap.h
create mode 100644 drivers/net/wireless/celeno/cl8k/wrs/wrs_api.c
create mode 100644 drivers/net/wireless/celeno/cl8k/wrs/wrs_api.h
create mode 100644 drivers/net/wireless/celeno/cl8k/wrs/wrs_cli.c
create mode 100644 drivers/net/wireless/celeno/cl8k/wrs/wrs_cli.h
create mode 100644 drivers/net/wireless/celeno/cl8k/wrs/wrs_db.h
create mode 100644 drivers/net/wireless/celeno/cl8k/wrs/wrs_rssi.c
create mode 100644 drivers/net/wireless/celeno/cl8k/wrs/wrs_rssi.h
create mode 100644 drivers/net/wireless/celeno/cl8k/wrs/wrs_sta.c
create mode 100644 drivers/net/wireless/celeno/cl8k/wrs/wrs_sta.h
create mode 100644 drivers/net/wireless/celeno/cl8k/wrs/wrs_stats.c
create mode 100644 drivers/net/wireless/celeno/cl8k/wrs/wrs_stats.h
create mode 100644 drivers/net/wireless/celeno/cl8k/wrs/wrs_tables.c
create mode 100644 drivers/net/wireless/celeno/cl8k/wrs/wrs_tables.h

--
2.30.0

________________________________
The information transmitted is intended only for the person or entity to which it is addressed and may contain confidential and/or privileged material. Any retransmission, dissemination, copying or other use of, or taking of any action in reliance upon this information is prohibited. If you received this in error, please contact the sender and delete the material from any computer. Nothing contained herein shall be deemed as a representation, warranty or a commitment by Celeno. No warranties are expressed or implied, including, but not limited to, any implied warranties of non-infringement, merchantability and fitness for a particular purpose.
________________________________


2021-06-17 16:22:45

by viktor.barna

[permalink] [raw]
Subject: [RFC v1 009/256] cl8k: add ampdu.c

From: Viktor Barna <[email protected]>

(Part of the split. Please, take a look at the cover letter for more
details).

Signed-off-by: Viktor Barna <[email protected]>
---
drivers/net/wireless/celeno/cl8k/ampdu.c | 344 +++++++++++++++++++++++
1 file changed, 344 insertions(+)
create mode 100644 drivers/net/wireless/celeno/cl8k/ampdu.c

diff --git a/drivers/net/wireless/celeno/cl8k/ampdu.c b/drivers/net/wireless/celeno/cl8k/ampdu.c
new file mode 100644
index 000000000000..7116995b5059
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/ampdu.c
@@ -0,0 +1,344 @@
+// SPDX-License-Identifier: MIT
+/* Copyright(c) 2019-2021, Celeno Communications Ltd. */
+
+#include "ampdu.h"
+#include "hw.h"
+#include "fw/msg_tx.h"
+#include "tx/tx_queue.h"
+#include "tx/agg_cfm.h"
+#include "recovery.h"
+#include "tx/tx_inject.h"
+#include "tx/baw.h"
+#include "utils/math.h"
+#include "band.h"
+#include "rx/rx_reorder.h"
+#ifdef CONFIG_CL_PCIE
+#include "bus/pci/ipc.h"
+#endif
+
+int cl_ampdu_rx_start(struct cl_hw *cl_hw,
+ struct cl_sta *cl_sta,
+ u16 tid,
+ u16 ssn,
+ u16 buf_size)
+{
+ /* @IEEE80211_AMPDU_RX_START: start RX aggregation */
+ if (!cl_hw->conf->ci_agg_rx)
+ return -EOPNOTSUPP;
+
+ cl_dbg_trace(cl_hw, "sta_idx [%u] tid [%u]\n", cl_sta->sta_idx, tid);
+
+ buf_size = min(buf_size, cl_hw->conf->ce_max_agg_size_rx);
+
+ if (cl_hw->conf->ci_fast_rx_en)
+ cl_rx_reorder_init(cl_hw, cl_sta, tid, buf_size);
+
+ cl_msg_tx_ba_add(cl_hw, BA_AGMT_RX, cl_sta->sta_idx, tid, buf_size, ssn);
+
+ return 0;
+}
+
+void cl_ampdu_rx_stop(struct cl_hw *cl_hw,
+ struct cl_sta *cl_sta,
+ u16 tid)
+{
+ /* @IEEE80211_AMPDU_RX_STOP: stop RX aggregation */
+ cl_dbg_trace(cl_hw, "sta_idx [%u] tid [%u]\n", cl_sta->sta_idx, tid);
+
+ if (cl_hw->conf->ci_fast_rx_en)
+ cl_rx_reorder_close(cl_sta, tid);
+}
+
+int cl_ampdu_tx_start(struct cl_hw *cl_hw,
+ struct ieee80211_vif *vif,
+ struct cl_sta *cl_sta,
+ u16 tid,
+ u16 ssn)
+{
+ /* @IEEE80211_AMPDU_TX_START: start TX aggregation */
+ struct mm_available_ba_txq_cfm *cfm = NULL;
+ int ret = 0;
+
+ if (!ieee80211_hw_check(cl_hw->hw, AMPDU_AGGREGATION) || !cl_hw->conf->ci_agg_tx)
+ return -EOPNOTSUPP;
+
+ if (!cl_txq_is_agg_available(cl_hw)) {
+ cl_dbg_warn(cl_hw, "No free aggregation queue for sta_idx [%u] tid [%u]\n",
+ cl_sta->sta_idx, tid);
+ return -1;
+ }
+
+ ret = cl_msg_tx_available_ba_txq(cl_hw, cl_sta->sta_idx, tid);
+ if (ret)
+ return ret;
+
+ /* Read FW confirm message */
+ cfm = (struct mm_available_ba_txq_cfm *)(cl_hw->msg_cfm_params[MM_AVAILABLE_BA_TXQ_CFM]);
+ if (!cfm)
+ return -ENOMSG;
+
+ /* Check if status is valid */
+ if (cfm->status != BA_TXQUEUE_INVALID && cfm->status != BA_TXQUEUE_VALID) {
+ cl_dbg_verbose(cl_hw, "Status Error (%u)\n", cfm->status);
+ cl_msg_tx_free_cfm_params(cl_hw, MM_AVAILABLE_BA_TXQ_CFM);
+ return -EIO;
+ }
+
+ if (cfm->status == BA_TXQUEUE_INVALID) {
+ cl_dbg_warn(cl_hw, "BA_TXQUEUE_INVALID - sta_idx [%u] tid [%u]\n",
+ cfm->sta_idx, cfm->tid);
+ cl_msg_tx_free_cfm_params(cl_hw, MM_AVAILABLE_BA_TXQ_CFM);
+ return -1;
+ }
+
+ cl_msg_tx_free_cfm_params(cl_hw, MM_AVAILABLE_BA_TXQ_CFM);
+ cl_txq_agg_request_add(cl_hw, cl_sta->sta_idx, tid);
+ cl_baw_start(&cl_sta->baws[tid], ssn);
+
+ /* Mandatory callback once setup preparations are done at lower level */
+ ieee80211_start_tx_ba_cb_irqsafe(vif, cl_sta->addr, tid);
+
+ return 0;
+}
+
+int cl_ampdu_tx_operational(struct cl_hw *cl_hw,
+ struct cl_sta *cl_sta,
+ u16 tid,
+ u16 buf_size,
+ bool amsdu_supported)
+{
+ /* @IEEE80211_AMPDU_TX_OPERATIONAL: TX aggregation has become operational */
+ struct mm_ba_add_cfm *cfm = NULL;
+ struct cl_baw *baw = &cl_sta->baws[tid];
+ u16 ssn = baw->ssn;
+ int ret = 0;
+
+ buf_size = min(buf_size, cl_hw->conf->ce_max_agg_size_tx);
+
+ /* Send MM_BA_ADD_TX_REQ message to firmware */
+ ret = cl_msg_tx_ba_add(cl_hw, BA_AGMT_TX, cl_sta->sta_idx, tid, buf_size, ssn);
+ if (ret)
+ return ret;
+
+ /* Handle message confirmation */
+ cfm = (struct mm_ba_add_cfm *)(cl_hw->msg_cfm_params[MM_BA_ADD_TX_CFM]);
+ if (!cfm)
+ return -ENOMSG;
+
+ if (cfm->status != BA_AGMT_ESTABLISHED) {
+ cl_dbg_verbose(cl_hw, "Status Error (%u)\n", cfm->status);
+ cl_msg_tx_free_cfm_params(cl_hw, MM_BA_ADD_TX_CFM);
+ cl_txq_agg_request_del(cl_hw, cl_sta->sta_idx, tid);
+ return -EIO;
+ }
+
+ cl_baw_operational(cl_hw, baw, cfm->agg_idx, amsdu_supported);
+ cl_agg_cfm_set_ssn(cl_hw, ssn, cfm->agg_idx);
+#ifdef CONFIG_CL_PCIE
+ cl_hw->ipc_env->ring_indices_elem->indices->new_ssn_idx[cfm->agg_idx] = cpu_to_le16(ssn);
+#endif
+
+ if (amsdu_supported)
+ cl_tx_amsdu_set_max_len(cl_hw, cl_sta, tid);
+ else
+ cl_dbg_trace(cl_hw, "AMSDU not supported - sta_idx=%u\n", cl_sta->sta_idx);
+
+ cl_txq_agg_alloc(cl_hw, cl_sta, cfm, buf_size);
+ cl_msg_tx_free_cfm_params(cl_hw, MM_BA_ADD_TX_CFM);
+
+ return 0;
+}
+
+void _cl_ampdu_tx_stop(struct cl_hw *cl_hw,
+ struct cl_tx_queue *tx_queue,
+ struct cl_sta *cl_sta,
+ u8 tid)
+{
+ struct mm_ba_del_cfm *cfm = NULL;
+ u8 fw_agg_idx = tx_queue->index;
+
+ if (cl_recovery_in_progress(cl_hw))
+ goto out;
+
+ /*
+ * TX stop flow:
+ * 1) Flush TX queues - done in cl_ampdu_tx_stop()
+ * 2) Poll confirmation queue and clear enhanced TIM
+ * 3) Send MM_STA_DEL_REQ message to firmware
+ * 4) Poll again confirmation and flush confirmation queue
+ * 5) Reset write index
+ */
+ cl_agg_cfm_poll_empty(cl_hw, fw_agg_idx, false);
+
+ /* Send MM_BA_DEL_REQ message to firmware */
+ if (cl_msg_tx_ba_del(cl_hw, cl_sta->sta_idx, tid))
+ goto out;
+
+ cfm = (struct mm_ba_del_cfm *)(cl_hw->msg_cfm_params[MM_BA_DEL_CFM]);
+ if (!cfm) {
+ cl_dbg_err(cl_hw, "Unable to fetch CFM\n");
+ goto out;
+ }
+
+ /* Check confirmation status */
+ if (cfm->status != BA_AGMT_DELETED && cfm->status != BA_AGMT_DOES_NOT_EXIST)
+ cl_dbg_verbose(cl_hw, "Status Error (%u)\n", cfm->status);
+
+ cl_msg_tx_free_cfm_params(cl_hw, MM_BA_DEL_CFM);
+
+out:
+ cl_agg_cfm_poll_empty(cl_hw, fw_agg_idx, true);
+ cl_txq_agg_free(cl_hw, tx_queue, cl_sta, tid);
+
+#ifdef CONFIG_CL_PCIE
+ /* Reset the synchronization counters between the fw and the IPC layer */
+ cl_hw->ipc_env->ring_indices_elem->indices->txdesc_write_idx.agg[fw_agg_idx] = 0;
+#endif
+}
+
+int cl_ampdu_tx_stop(struct cl_hw *cl_hw,
+ struct ieee80211_vif *vif,
+ enum ieee80211_ampdu_mlme_action action,
+ struct cl_sta *cl_sta,
+ u16 tid)
+{
+ /*
+ * @IEEE80211_AMPDU_TX_STOP_CONT: stop TX aggregation but continue transmitting
+ * queued packets, now unaggregated. After all packets are transmitted the
+ * driver has to call ieee80211_stop_tx_ba_cb_irqsafe().
+ * @IEEE80211_AMPDU_TX_STOP_FLUSH: stop TX aggregation and flush all packets,
+ * called when the station is removed. There's no need or reason to call
+ * ieee80211_stop_tx_ba_cb_irqsafe() in this case as mac80211 assumes the
+ * session is gone and removes the station.
+ * @IEEE80211_AMPDU_TX_STOP_FLUSH_CONT: called when TX aggregation is stopped
+ * but the driver hasn't called ieee80211_stop_tx_ba_cb_irqsafe() yet and
+ * now the connection is dropped and the station will be removed. Drivers
+ * should clean up and drop remaining packets when this is called.
+ */
+
+ /* !!! Comment in agg-tx.c, ___ieee80211_stop_tx_ba_session(): !!!
+ * !!! HW shall not deny going back to legacy !!!
+ * !!! Therefore cl_ampdu_tx_stop() always returns 0 !!!
+ */
+
+ struct cl_tx_queue *tx_queue = cl_sta->agg_tx_queues[tid];
+ struct cl_baw *baw = &cl_sta->baws[tid];
+
+ spin_lock_bh(&cl_hw->tx_lock_agg);
+
+ cl_baw_stop(baw);
+ cl_txq_agg_request_del(cl_hw, cl_sta->sta_idx, tid);
+
+ /* Check if BA session exist */
+ if (!tx_queue) {
+ spin_unlock_bh(&cl_hw->tx_lock_agg);
+
+ if (!cl_recovery_in_progress(cl_hw))
+ cl_dbg_warn(cl_hw, "Queue doesn't exist - sta_idx [%u] tid [%u]\n",
+ cl_sta->sta_idx, tid);
+
+ goto out;
+ }
+
+ if (action == IEEE80211_AMPDU_TX_STOP_CONT) {
+ /*
+ * The order of flow here is very important here to avoid reorder problem!
+ * 1) Take single lock to block single traffic
+ * 2) Stop agg traffic.
+ * 3) Transfer agg-to-single and push all skbs from agg queue to single queue.
+ * 4) Transfer BA window pending queue to single queue.
+ * 5) Release single lock
+ */
+ spin_lock_bh(&cl_hw->tx_lock_single);
+ cl_txq_agg_stop(cl_sta, tid);
+ cl_txq_transfer_agg_to_single(cl_hw, tx_queue);
+ cl_baw_pending_to_single(cl_hw, cl_sta, baw);
+ spin_unlock_bh(&cl_hw->tx_lock_single);
+ } else {
+ cl_txq_agg_stop(cl_sta, tid);
+ cl_txq_flush(cl_hw, tx_queue);
+ cl_baw_pending_purge(baw);
+ }
+
+ cl_tx_amsdu_anchor_reset(&cl_sta->amsdu_anchor[tid]);
+
+ spin_unlock_bh(&cl_hw->tx_lock_agg);
+
+ _cl_ampdu_tx_stop(cl_hw, tx_queue, cl_sta, tid);
+
+out:
+ /* Mandatory callback once we've made our own tear down ops */
+ if (action != IEEE80211_AMPDU_TX_STOP_FLUSH)
+ ieee80211_stop_tx_ba_cb_irqsafe(vif, cl_sta->addr, tid);
+
+ return 0;
+}
+
+#define HE_MAC_CAP3_MAX_AMPDU_LEN_EXP_OFFSET 3
+#define HE_EXP_MAX 22 /* 2 ^ 22 = 4194304 < 6500631 */
+
+static void _cl_ampdu_size_exp(struct ieee80211_sta *sta,
+ u8 *ampdu_exp_he,
+ u8 *ampdu_exp_vht,
+ u8 *ampdu_exp_ht)
+{
+ struct ieee80211_sta_he_cap *he_cap = &sta->he_cap;
+ u8 mac_cap_info3 = he_cap->he_cap_elem.mac_cap_info[3];
+ u8 he_exp;
+
+ if (sta->ht_cap.ht_supported)
+ *ampdu_exp_ht = IEEE80211_HT_MAX_AMPDU_FACTOR + sta->ht_cap.ampdu_factor;
+
+ if (sta->vht_cap.vht_supported) {
+ u32 vht_exp = (sta->vht_cap.cap &
+ IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MASK) >>
+ IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_SHIFT;
+
+ *ampdu_exp_vht = IEEE80211_HT_MAX_AMPDU_FACTOR + vht_exp;
+ }
+
+ he_exp = (mac_cap_info3 & IEEE80211_HE_MAC_CAP3_MAX_AMPDU_LEN_EXP_MASK) >>
+ HE_MAC_CAP3_MAX_AMPDU_LEN_EXP_OFFSET;
+
+ if (sta->vht_cap.vht_supported) {
+ if (he_exp)
+ *ampdu_exp_he = min(IEEE80211_HE_VHT_MAX_AMPDU_FACTOR + he_exp, HE_EXP_MAX);
+ else
+ *ampdu_exp_he = *ampdu_exp_vht;
+ } else if (sta->ht_cap.ht_supported) {
+ if (he_exp)
+ *ampdu_exp_he = IEEE80211_HE_HT_MAX_AMPDU_FACTOR + he_exp;
+ else
+ *ampdu_exp_he = *ampdu_exp_ht;
+ }
+}
+
+static void _cl_ampdu_size_exp_6g(struct ieee80211_sta *sta, u8 *ampdu_exp_he)
+{
+ u8 mac_cap_info3 = sta->he_cap.he_cap_elem.mac_cap_info[3];
+ u8 he_exp_ext = (mac_cap_info3 & IEEE80211_HE_MAC_CAP3_MAX_AMPDU_LEN_EXP_MASK) >>
+ HE_MAC_CAP3_MAX_AMPDU_LEN_EXP_OFFSET;
+
+ if (he_exp_ext) {
+ *ampdu_exp_he = min(IEEE80211_HE_VHT_MAX_AMPDU_FACTOR + he_exp_ext, HE_EXP_MAX);
+ } else {
+ struct ieee80211_he_6ghz_capa *he_6g_cap = &sta->he_6ghz_capa;
+ u8 he_exp_6ghz = (he_6g_cap->capa & HE_6GHZ_CAP_MAX_AMPDU_LEN_EXP_MASK) >>
+ HE_6GHZ_CAP_MAX_AMPDU_LEN_EXP_OFFSET;
+
+ *ampdu_exp_he = min(HE_6GHZ_CAP_MAX_AMPDU_LEN_FACTOR + he_exp_6ghz, HE_EXP_MAX);
+ }
+}
+
+void cl_ampdu_size_exp(struct cl_hw *cl_hw, struct ieee80211_sta *sta,
+ u8 *ampdu_exp_he, u8 *ampdu_exp_vht, u8 *ampdu_exp_ht)
+{
+ if (cl_band_is_6g(cl_hw))
+ _cl_ampdu_size_exp_6g(sta, ampdu_exp_he);
+ else
+ _cl_ampdu_size_exp(sta, ampdu_exp_he, ampdu_exp_vht, ampdu_exp_ht);
+
+ cl_dbg_info(cl_hw, "ampdu_size_exp: he = %u, vht = %u, ht = %u\n",
+ *ampdu_exp_he, *ampdu_exp_vht, *ampdu_exp_ht);
+}
+
--
2.30.0

________________________________
The information transmitted is intended only for the person or entity to which it is addressed and may contain confidential and/or privileged material. Any retransmission, dissemination, copying or other use of, or taking of any action in reliance upon this information is prohibited. If you received this in error, please contact the sender and delete the material from any computer. Nothing contained herein shall be deemed as a representation, warranty or a commitment by Celeno. No warranties are expressed or implied, including, but not limited to, any implied warranties of non-infringement, merchantability and fitness for a particular purpose.
________________________________

2021-06-17 16:23:07

by viktor.barna

[permalink] [raw]
Subject: [RFC v1 015/256] cl8k: add bf.c

From: Viktor Barna <[email protected]>

(Part of the split. Please, take a look at the cover letter for more
details).

Signed-off-by: Viktor Barna <[email protected]>
---
drivers/net/wireless/celeno/cl8k/bf.c | 556 ++++++++++++++++++++++++++
1 file changed, 556 insertions(+)
create mode 100644 drivers/net/wireless/celeno/cl8k/bf.c

diff --git a/drivers/net/wireless/celeno/cl8k/bf.c b/drivers/net/wireless/celeno/cl8k/bf.c
new file mode 100644
index 000000000000..1b4521080aa5
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/bf.c
@@ -0,0 +1,556 @@
+// SPDX-License-Identifier: MIT
+/* Copyright(c) 2019-2021, Celeno Communications Ltd. */
+
+#include "bf.h"
+#include "sounding.h"
+#include "fw/msg_tx.h"
+#include "traffic.h"
+#include "sta.h"
+#include "utils/math.h"
+#include "utils/utils.h"
+
+#define CL_BF_SOUNDING_INTERVAL_MAX 0x3ff
+#define CL_BF_MIN_SOUNDING_NR 3
+
+#define bf_pr(cl_hw, level, ...) \
+ do { \
+ if ((level) <= (cl_hw)->bf_db.dbg_level) \
+ pr_debug(__VA_ARGS__); \
+ } while (0)
+
+#define bf_pr_verbose(cl_hw, ...) bf_pr((cl_hw), DBG_LVL_VERBOSE, ##__VA_ARGS__)
+#define bf_pr_err(cl_hw, ...) bf_pr((cl_hw), DBG_LVL_ERROR, ##__VA_ARGS__)
+#define bf_pr_warn(cl_hw, ...) bf_pr((cl_hw), DBG_LVL_WARNING, ##__VA_ARGS__)
+#define bf_pr_trace(cl_hw, ...) bf_pr((cl_hw), DBG_LVL_TRACE, ##__VA_ARGS__)
+#define bf_pr_info(cl_hw, ...) bf_pr((cl_hw), DBG_LVL_INFO, ##__VA_ARGS__)
+
+static void cl_bf_cli_fw_control_stats(struct cl_hw *cl_hw, u32 action)
+{
+ if (action == 0)
+ cl_msg_tx_dbg_print_stats(cl_hw, DBG_PRINT_RESET, 0, 0, 0, 0);
+ else if (action == 1)
+ cl_msg_tx_dbg_print_stats(cl_hw, DBG_PRINT_BF_CTRL_ACTIVE, 0, 0, 0, 0);
+ else if (action == 2)
+ cl_msg_tx_dbg_print_stats(cl_hw, DBG_PRINT_BF_CTRL_PASSIVE, 0, 0, 0, 0);
+ else
+ bf_pr_verbose(cl_hw, "Invalid input [%u]\n", action);
+}
+
+static bool cl_bf_is_beamformee_capable_he(struct ieee80211_sta *sta, bool mu_cap)
+{
+ u8 phy_cap_info4 = sta->he_cap.he_cap_elem.phy_cap_info[4];
+
+ if (mu_cap)
+ return (phy_cap_info4 & IEEE80211_HE_PHY_CAP4_MU_BEAMFORMER) ? true : false;
+ else
+ return (phy_cap_info4 & IEEE80211_HE_PHY_CAP4_SU_BEAMFORMEE) ? true : false;
+}
+
+static bool cl_bf_is_beamformee_capable_vht(struct ieee80211_sta *sta, bool mu_cap)
+{
+ u32 vht_cap = sta->vht_cap.cap;
+
+ if (mu_cap)
+ return (vht_cap & IEEE80211_VHT_CAP_MU_BEAMFORMEE_CAPABLE) ? true : false;
+ else
+ return (vht_cap & IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE) ? true : false;
+}
+
+static bool cl_bf_is_beamformee_capable(struct cl_sta *cl_sta, bool mu_cap)
+{
+ struct ieee80211_sta *sta = &cl_sta->stainfo->sta;
+
+ if (sta->he_cap.has_he)
+ return cl_bf_is_beamformee_capable_he(sta, mu_cap);
+
+ if (sta->vht_cap.vht_supported)
+ return cl_bf_is_beamformee_capable_vht(sta, mu_cap);
+
+ return false;
+}
+
+static int cl_bf_cli_config_print(struct cl_hw *cl_hw)
+{
+ bool is_enabled = cl_bf_is_enabled(cl_hw);
+ struct cl_tcv_conf *conf = cl_hw->conf;
+ char *buf = NULL;
+ ssize_t buf_size;
+ int err = 0;
+ int len = 0;
+
+ cl_snprintf(&buf, &len, &buf_size,
+ "Beamforming Configuration\n"
+ "------------------------------\n");
+
+ cl_snprintf(&buf, &len, &buf_size,
+ "Is enabled: %s\n",
+ is_enabled ? "True" : "False");
+
+ cl_snprintf(&buf, &len, &buf_size,
+ "Force: %s\n",
+ cl_hw->bf_db.force ? "True" : "False");
+
+ cl_snprintf(&buf, &len, &buf_size,
+ "Debug level: %d\n",
+ cl_hw->bf_db.dbg_level);
+
+ cl_snprintf(&buf, &len, &buf_size,
+ "Max nss supported: %u\n",
+ conf->ci_bf_max_nss);
+
+ err = cl_vendor_reply(cl_hw, buf, len);
+ kfree(buf);
+
+ return err;
+}
+
+static void cl_bf_cli_debug_set(struct cl_hw *cl_hw, u32 dbg_level)
+{
+ if (dbg_level < DBG_LVL_MAX) {
+ cl_hw->bf_db.dbg_level = dbg_level;
+ pr_debug("[BF] Debug level [%d]\n", dbg_level);
+ }
+}
+
+void cl_bf_enable(struct cl_hw *cl_hw, bool enable)
+{
+ struct cl_tcv_conf *conf = cl_hw->conf;
+
+ if (conf->ce_bf_en == enable)
+ return;
+
+ conf->ce_bf_en = enable;
+ pr_debug("[BF] %s\n", enable ? "Enable" : "Disable");
+
+ cl_sta_loop_bh(cl_hw, cl_bf_sounding_decision);
+}
+
+static void cl_bf_cli_force_set(struct cl_hw *cl_hw, bool force)
+{
+ if (cl_hw->bf_db.force == force)
+ return;
+
+ cl_hw->bf_db.force = force;
+ pr_debug("[BF] Force: %s\n", force ? "True" : "False");
+
+ cl_sta_loop_bh(cl_hw, cl_bf_sounding_decision);
+}
+
+static int cl_bf_cli_sta_info_print(struct cl_hw *cl_hw)
+{
+ struct cl_sta *cl_sta = NULL;
+ char *buf = NULL;
+ ssize_t buf_size;
+ int len = 0;
+ int err = 0;
+
+ /* Go over all stations - use bottom-half lock */
+ read_lock_bh(&cl_hw->cl_sta_db.lock);
+
+ list_for_each_entry(cl_sta, &cl_hw->cl_sta_db.head, list) {
+ struct cl_bf_sta_db *bf_db = &cl_sta->bf_db;
+ u8 nss = cl_sta->wrs_sta.su_params.tx_params.nss;
+ bool is_on = cl_bf_is_on(cl_hw, cl_sta, nss);
+ bool su_beamformee_capable =
+ cl_bf_is_beamformee_capable(cl_sta, false);
+ bool mu_beamformee_capable =
+ cl_bf_is_beamformee_capable(cl_sta, true);
+
+ cl_snprintf(&buf, &len, &buf_size,
+ "\nStation [%u]\n", cl_sta->sta_idx);
+ cl_snprintf(&buf, &len, &buf_size,
+ "-------------------------------\n");
+ cl_snprintf(&buf, &len, &buf_size,
+ "SU beamformee capable: %s\n",
+ su_beamformee_capable ? "True" : "False");
+ cl_snprintf(&buf, &len, &buf_size,
+ "MU beamformee capable: %s\n",
+ mu_beamformee_capable ? "True" : "False");
+ cl_snprintf(&buf, &len, &buf_size,
+ "Beamformee STS: %u\n",
+ bf_db->beamformee_sts);
+ cl_snprintf(&buf, &len, &buf_size,
+ "Beamformee NSS: %u\n", bf_db->nc);
+ cl_snprintf(&buf, &len, &buf_size,
+ "Traffic active: %s\n",
+ bf_db->traffic_active ? "True" : "False");
+ cl_snprintf(&buf, &len, &buf_size,
+ "Sound start: %s\n",
+ bf_db->sounding_start ? "True" : "False");
+ cl_snprintf(&buf, &len, &buf_size,
+ "Sounding indications: %u\n",
+ bf_db->sounding_indications);
+ cl_snprintf(&buf, &len, &buf_size,
+ "Indication_timeout: %s\n",
+ bf_db->indication_timeout ? "True" : "False");
+ cl_snprintf(&buf, &len, &buf_size,
+ "Is on: %s\n",
+ is_on ? "True" : "False");
+ }
+
+ read_unlock_bh(&cl_hw->cl_sta_db.lock);
+
+ err = cl_vendor_reply(cl_hw, buf, len);
+ kfree(buf);
+
+ return err;
+}
+
+static int cl_bf_cli_help(struct cl_hw *cl_hw)
+{
+ char *ret_buf = kzalloc(PAGE_SIZE, GFP_KERNEL);
+ int err = 0;
+
+ if (!ret_buf)
+ return -ENOMEM;
+
+ snprintf(ret_buf, PAGE_SIZE,
+ "bf usage\n"
+ "-a: Firmware BF control stats [0-Reset,1-PrintActive,2-PrintPassive]\n"
+ "-c: Print BF configuration\n"
+ "-d: Set debug level [0-OFF,1-ERROR,2-WARN,3-TRACE,4-INFO]\n"
+ "-e: Disable or Enable BF [0/1]\n"
+ "-f: Force BF [0-Disable,1-Enable]\n"
+ "-s: Print BF station info\n");
+
+ err = cl_vendor_reply(cl_hw, ret_buf, strlen(ret_buf));
+ kfree(ret_buf);
+
+ return err;
+}
+
+static void cl_bf_timer_callback(unsigned long data)
+{
+ /*
+ * If timer expired it means that we started sounding but didn't get any
+ * indication for (10 * sounding_interval).
+ * So we disable sounding for this station (even when in starts again traffic).
+ */
+ struct cl_sta *cl_sta = (struct cl_sta *)data;
+
+ if (cl_sta) {
+ struct cl_hw *cl_hw = cl_sta->cl_vif->cl_hw;
+
+ bf_pr_trace(cl_hw, "[BF] Failed to get reply (%u)\n", cl_sta->sta_idx);
+ cl_sta->bf_db.indication_timeout = true;
+ cl_bf_sounding_decision(cl_hw, cl_sta);
+ }
+}
+
+void cl_bf_sounding_start(struct cl_hw *cl_hw, enum sounding_type type, struct cl_sta **cl_sta_arr,
+ u8 sta_num, struct cl_sounding_info *recovery_elem)
+{
+#define STA_INDICES_STR_SIZE 64
+
+ /* Send request to start sounding */
+ u8 i, bw = CHNL_BW_MAX;
+ char sta_indices_str[STA_INDICES_STR_SIZE] = {0};
+ u8 str_len = 0;
+
+ for (i = 0; i < sta_num; i++) {
+ struct cl_sta *cl_sta = cl_sta_arr[i];
+ struct cl_bf_sta_db *bf_db = &cl_sta->bf_db;
+
+ bw = cl_sta->wrs_sta.assoc_bw;
+ bf_db->synced = false;
+ bf_db->sounding_start = true;
+ bf_db->sounding_indications = 0;
+
+ str_len += snprintf(sta_indices_str, STA_INDICES_STR_SIZE - str_len, "%u%s",
+ cl_sta->sta_idx, (i == sta_num - 1 ? ", " : ""));
+
+ }
+
+ bf_pr_trace(cl_hw, "[BF] Start sounding: Sta = %s\n", sta_indices_str);
+ cl_sounding_send_request(cl_hw, cl_sta_arr, sta_num, SOUNDING_ENABLE, type, bw, 0,
+ recovery_elem);
+
+#undef STA_INDICES_STR_SIZE
+}
+
+void cl_bf_reset_sounding_info(struct cl_sta *cl_sta)
+{
+ struct cl_bf_sta_db *bf_db = &cl_sta->bf_db;
+
+ bf_db->synced = false;
+ bf_db->sounding_start = false;
+ bf_db->sounding_indications = 0;
+}
+
+void cl_bf_sounding_stop(struct cl_hw *cl_hw, struct cl_sta *cl_sta)
+{
+ struct cl_bf_sta_db *bf_db = &cl_sta->bf_db;
+
+ if (bf_db->sounding_start) {
+ /* Send request to stop sounding */
+ cl_bf_reset_sounding_info(cl_sta);
+ bf_pr_trace(cl_hw, "[BF] Sta = %u, Stop sounding\n", cl_sta->sta_idx);
+ cl_sounding_send_request(cl_hw, &cl_sta, 1, SOUNDING_DISABLE, SOUNDING_TYPE_HE_SU,
+ 0, 0, NULL);
+ bf_pr_trace(cl_hw, "[BF] Sta: %u, Beamforming disabled\n", cl_sta->sta_idx);
+ }
+}
+
+void cl_bf_sounding_decision(struct cl_hw *cl_hw, struct cl_sta *cl_sta)
+{
+ struct cl_bf_sta_db *bf_db = &cl_sta->bf_db;
+
+ if (cl_bf_is_enabled(cl_hw) &&
+ cl_bf_is_beamformee_capable(cl_sta, false) &&
+ !bf_db->indication_timeout &&
+ ((bf_db->beamformee_sts + 1) >= CL_BF_MIN_SOUNDING_NR) &&
+ (bf_db->traffic_active || cl_hw->bf_db.force)) {
+ if (!bf_db->sounding_start) {
+ if (cl_sta->su_sid == INVALID_SID)
+ cl_bf_sounding_start(cl_hw, SOUNDING_TYPE_HE_SU, &cl_sta, 1, NULL);
+ else
+ bf_pr_verbose(cl_hw, "[%s]: STA %u already belongs to sid %u\n",
+ __func__, cl_sta->sta_idx, cl_sta->su_sid);
+ }
+ } else {
+ cl_timer_disable(&bf_db->timer);
+ cl_bf_sounding_stop(cl_hw, cl_sta);
+ }
+}
+
+static u8 cl_bf_get_sts_he(struct ieee80211_sta *sta)
+{
+ u8 *phy_cap_info = sta->he_cap.he_cap_elem.phy_cap_info;
+
+ if (phy_cap_info[0] & IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_160MHZ_IN_5G ||
+ phy_cap_info[0] & IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_80PLUS80_MHZ_IN_5G)
+ return u8_get_bits(phy_cap_info[4],
+ IEEE80211_HE_PHY_CAP4_BEAMFORMEE_MAX_STS_ABOVE_80MHZ_MASK);
+ else
+ return u8_get_bits(phy_cap_info[4],
+ IEEE80211_HE_PHY_CAP4_BEAMFORMEE_MAX_STS_UNDER_80MHZ_MASK);
+}
+
+static u8 cl_bf_get_sts_vht(struct ieee80211_sta *sta)
+{
+ struct ieee80211_sta_vht_cap *vht_cap = &sta->vht_cap;
+
+ return u32_get_bits(vht_cap->cap, IEEE80211_VHT_CAP_BEAMFORMEE_STS_MASK);
+}
+
+static u8 cl_bf_get_sts(struct ieee80211_sta *sta)
+{
+ if (sta->he_cap.has_he)
+ return cl_bf_get_sts_he(sta);
+
+ return cl_bf_get_sts_vht(sta);
+}
+
+void cl_bf_update_rate(struct cl_hw *cl_hw, struct cl_sta *cl_sta)
+{
+ struct cl_bf_sta_db *bf_db = &cl_sta->bf_db;
+
+ /* Old & new BF state for main rate */
+ bool bf_on_old = bf_db->is_on;
+ bool bf_on_new = cl_bf_is_on(cl_hw, cl_sta, bf_db->num_ss);
+
+ /* Old & new BF state for fallback rate */
+ bool bf_on_old_fbk = bf_db->is_on_fallback;
+ bool bf_on_new_fbk = cl_bf_is_on(cl_hw, cl_sta, bf_db->num_ss_fallback);
+
+ if (bf_on_old != bf_on_new || bf_on_old_fbk != bf_on_new_fbk) {
+ /* BF state for main rate or fallback rate changed */
+
+ /* Save the new state */
+ bf_db->is_on = bf_on_new;
+ bf_db->is_on_fallback = bf_on_new_fbk;
+
+ /* Update the firmware */
+ if (cl_msg_tx_set_tx_bf(cl_hw, cl_sta->sta_idx, bf_on_new, bf_on_new_fbk))
+ pr_err("%s: failed to set TX-BF\n", __func__);
+ }
+}
+
+void cl_bf_sta_add(struct cl_hw *cl_hw, struct cl_sta *cl_sta, struct ieee80211_sta *sta)
+{
+ /* Beamformee capabilities */
+ bool su_beamformee_capable = cl_bf_is_beamformee_capable(cl_sta, false);
+ bool mu_beamformee_capable = cl_bf_is_beamformee_capable(cl_sta, true);
+ struct cl_bf_sta_db *bf_db = &cl_sta->bf_db;
+
+ WARN_ON_ONCE(sta->rx_nss == 0);
+ bf_db->beamformee_sts = cl_bf_get_sts(sta);
+ bf_db->nc = min_t(u8, sta->rx_nss, WRS_SS_MAX) - 1;
+ cl_sta->su_sid = INVALID_SID;
+
+ bf_pr_trace(cl_hw,
+ "[BF] sta_idx: %u, su_beamformee_capable: %u, mu_beamformee_capable: %u, "
+ "beamformee_sts: %u, nc = %u\n",
+ cl_sta->sta_idx, su_beamformee_capable, mu_beamformee_capable,
+ bf_db->beamformee_sts, bf_db->nc);
+
+ if (bf_db->beamformee_sts == 0)
+ bf_db->beamformee_sts = 3;
+
+ /*
+ * Init the BF timer
+ * Period is set to 0. It will be updated before enabling it.
+ */
+ cl_timer_init(&bf_db->timer, cl_bf_timer_callback, (unsigned long)cl_sta, 0, false);
+}
+
+void cl_bf_sta_remove(struct cl_hw *cl_hw, struct cl_sta *cl_sta)
+{
+ struct cl_bf_sta_db *bf_db = &cl_sta->bf_db;
+
+ /* Disable timer before removing the station */
+ cl_timer_disable_sync(&bf_db->timer);
+
+ /*
+ * Remove the sounding sequence associated with the STA and possibly start another sequence
+ * for other stations that participate in the same sounding sequence with the STA
+ */
+ if (cl_sta->su_sid != INVALID_SID) {
+ bf_db->sounding_remove_required = true;
+ cl_sounding_stop_by_sid(cl_hw, cl_sta->su_sid, true);
+ }
+}
+
+void cl_bf_sta_active(struct cl_hw *cl_hw, struct cl_sta *cl_sta, bool active)
+{
+ struct cl_bf_sta_db *bf_db = &cl_sta->bf_db;
+
+ if (bf_db->traffic_active != active) {
+ bf_pr_trace(cl_hw, "[BF] Sta: %u, Active: %s\n",
+ cl_sta->sta_idx, active ? "True" : " False");
+
+ bf_db->traffic_active = active;
+ cl_bf_sounding_decision(cl_hw, cl_sta);
+ }
+}
+
+void cl_bf_reset_sounding_ind(struct cl_hw *cl_hw, struct cl_sta *cl_sta)
+{
+ cl_sta->bf_db.sounding_indications = 0;
+}
+
+bool cl_bf_is_enabled(struct cl_hw *cl_hw)
+{
+ return cl_hw->conf->ce_bf_en;
+}
+
+int cl_bf_cli(struct cl_hw *cl_hw, struct cli_params *cli_params)
+{
+ u32 expected_params = 0;
+ bool fw_ctrl_stats = false;
+ bool config_print = false;
+ bool debug_set = false;
+ bool enable_set = false;
+ bool force_set = false;
+ bool sta_info_print = false;
+
+ switch (cli_params->option) {
+ case 'a':
+ fw_ctrl_stats = true;
+ expected_params = 1;
+ break;
+ case 'c':
+ config_print = true;
+ expected_params = 0;
+ break;
+ case 'd':
+ debug_set = true;
+ expected_params = 1;
+ break;
+ case 'e':
+ enable_set = true;
+ expected_params = 1;
+ break;
+ case 'f':
+ force_set = true;
+ expected_params = 1;
+ break;
+ case 's':
+ sta_info_print = true;
+ expected_params = 0;
+ break;
+ case '?':
+ return cl_bf_cli_help(cl_hw);
+ default:
+ cl_dbg_err(cl_hw, "Illegal option (%c) - try '?' for help\n", cli_params->option);
+ goto out_err;
+ }
+
+ if (expected_params != cli_params->num_params) {
+ cl_dbg_err(cl_hw, "Wrong number of arguments (expected %u) (actual %u)\n",
+ expected_params, cli_params->num_params);
+ goto out_err;
+ }
+
+ if (fw_ctrl_stats)
+ cl_bf_cli_fw_control_stats(cl_hw, cli_params->params[0]);
+ else if (config_print)
+ return cl_bf_cli_config_print(cl_hw);
+ else if (debug_set)
+ cl_bf_cli_debug_set(cl_hw, cli_params->params[0]);
+ else if (enable_set)
+ cl_bf_enable(cl_hw, !!cli_params->params[0]);
+ else if (force_set)
+ cl_bf_cli_force_set(cl_hw, !!cli_params->params[0]);
+ else if (sta_info_print)
+ return cl_bf_cli_sta_info_print(cl_hw);
+
+ return 0;
+out_err:
+ return -EIO;
+}
+
+bool cl_bf_is_on(struct cl_hw *cl_hw, struct cl_sta *cl_sta, u8 nss)
+{
+ struct cl_bf_sta_db *bf_db = &cl_sta->bf_db;
+
+ return (cl_bf_is_enabled(cl_hw) &&
+ bf_db->sounding_start &&
+ bf_db->sounding_indications &&
+ (nss <= min(cl_hw->conf->ci_bf_max_nss, bf_db->nc)));
+}
+
+void cl_bf_sounding_req_success(struct cl_hw *cl_hw, struct cl_sounding_info *new_elem)
+{
+ /*
+ * Start a timer to check that we are receiving indications from the station.
+ * The period of the timer is set to 10 times the sounding-interval.
+ */
+ u8 i;
+ struct cl_sta *cl_sta;
+ struct cl_bf_sta_db *bf_db;
+ unsigned long period = CL_SOUNDING_FACTOR * cl_sounding_get_interval(cl_hw);
+
+ for (i = 0; i < new_elem->sta_num; i++) {
+ cl_sta = new_elem->su_cl_sta_arr[i];
+ bf_db = &cl_sta->bf_db;
+
+ if (cl_sta) {
+ cl_sta->bf_db.sounding_start = true;
+ cl_sta->su_sid = new_elem->sounding_id;
+
+ /* Don't enable BF timer in case of force mode */
+ if (!cl_hw->bf_db.force) {
+ cl_timer_period_set(&bf_db->timer, period);
+ cl_timer_enable(&bf_db->timer);
+ }
+ }
+ }
+}
+
+void cl_bf_sounding_req_failure(struct cl_hw *cl_hw, struct cl_sounding_info *new_elem)
+{
+ u8 i;
+ struct cl_sta *cl_sta;
+ struct cl_bf_sta_db *bf_db;
+
+ for (i = 0; i < new_elem->sta_num; i++) {
+ cl_sta = new_elem->su_cl_sta_arr[i];
+
+ if (cl_sta) {
+ bf_db = &cl_sta->bf_db;
+ bf_db->sounding_start = false;
+ bf_db->sounding_indications = 0;
+ }
+ }
+}
--
2.30.0

________________________________
The information transmitted is intended only for the person or entity to which it is addressed and may contain confidential and/or privileged material. Any retransmission, dissemination, copying or other use of, or taking of any action in reliance upon this information is prohibited. If you received this in error, please contact the sender and delete the material from any computer. Nothing contained herein shall be deemed as a representation, warranty or a commitment by Celeno. No warranties are expressed or implied, including, but not limited to, any implied warranties of non-infringement, merchantability and fitness for a particular purpose.
________________________________

2021-06-17 16:23:10

by viktor.barna

[permalink] [raw]
Subject: [RFC v1 014/256] cl8k: add band.h

From: Viktor Barna <[email protected]>

(Part of the split. Please, take a look at the cover letter for more
details).

Signed-off-by: Viktor Barna <[email protected]>
---
drivers/net/wireless/celeno/cl8k/band.h | 40 +++++++++++++++++++++++++
1 file changed, 40 insertions(+)
create mode 100644 drivers/net/wireless/celeno/cl8k/band.h

diff --git a/drivers/net/wireless/celeno/cl8k/band.h b/drivers/net/wireless/celeno/cl8k/band.h
new file mode 100644
index 000000000000..9642432bed0f
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/band.h
@@ -0,0 +1,40 @@
+/* SPDX-License-Identifier: MIT */
+/* Copyright(c) 2019-2021, Celeno Communications Ltd. */
+
+#ifndef CL_BAND_H
+#define CL_BAND_H
+
+#include "hw.h"
+
+enum c_fw_band {
+ FW_BAND_2GHZ,
+ FW_BAND_5GHZ,
+ FW_BAND_6GHZ,
+
+ FW_BAND_MAX,
+};
+
+#define BAND_6G 6
+#define BAND_5G 5
+#define BAND_24G 24
+
+#define BAND_TO_STR(band) \
+ ((band) == 6 ? "6G" : \
+ ((band) == 5 ? "5G" : "24G"))
+
+#define BAND_IS_5G_6G(cl_hw) \
+ (cl_band_is_5g(cl_hw) || cl_band_is_6g(cl_hw))
+
+bool cl_band_is_6g(struct cl_hw *cl_hw);
+bool cl_band_is_6g_freq(u16 freq);
+
+bool cl_band_is_5g(struct cl_hw *cl_hw);
+bool cl_band_is_5g_freq(u16 freq);
+
+bool cl_band_is_24g(struct cl_hw *cl_hw);
+bool cl_band_is_24g_freq(u16 freq);
+
+u8 cl_band_to_fw_idx(struct cl_hw *cl_hw);
+u8 cl_band_from_fw_idx(u32 phy_band);
+
+#endif /* CL_BAND_H */
--
2.30.0

________________________________
The information transmitted is intended only for the person or entity to which it is addressed and may contain confidential and/or privileged material. Any retransmission, dissemination, copying or other use of, or taking of any action in reliance upon this information is prohibited. If you received this in error, please contact the sender and delete the material from any computer. Nothing contained herein shall be deemed as a representation, warranty or a commitment by Celeno. No warranties are expressed or implied, including, but not limited to, any implied warranties of non-infringement, merchantability and fitness for a particular purpose.
________________________________

2021-06-17 16:23:11

by viktor.barna

[permalink] [raw]
Subject: [RFC v1 029/256] cl8k: add calib.h

From: Viktor Barna <[email protected]>

(Part of the split. Please, take a look at the cover letter for more
details).

Signed-off-by: Viktor Barna <[email protected]>
---
drivers/net/wireless/celeno/cl8k/calib.h | 237 +++++++++++++++++++++++
1 file changed, 237 insertions(+)
create mode 100644 drivers/net/wireless/celeno/cl8k/calib.h

diff --git a/drivers/net/wireless/celeno/cl8k/calib.h b/drivers/net/wireless/celeno/cl8k/calib.h
new file mode 100644
index 000000000000..3282b8fc4efd
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/calib.h
@@ -0,0 +1,237 @@
+/* SPDX-License-Identifier: MIT */
+/* Copyright(c) 2019-2021, Celeno Communications Ltd. */
+
+#ifndef CL_CALIB_H
+#define CL_CALIB_H
+
+#include <net/cfg80211.h>
+
+#include "def.h"
+#include "vendor_cmd.h"
+
+#define UNCALIBRATED_POWER 15
+#define UNCALIBRATED_POWER_OFFSET 0
+#define UNCALIBRATED_TEMPERATURE 35
+
+#define DCOC_LNA_GAIN_NUM 8
+#define MAX_SX 2
+#define IQ_NUM_TONES_REQ 8
+#define IQ_NUM_TONES_CFM (2 * IQ_NUM_TONES_REQ)
+#define SINGLETONS_MAX_NUM 1
+#define LOOPS_MAX_NUM (2 + SINGLETONS_MAX_NUM) /* 1: pre,2-11:singletone,12:post */
+#define SX_FREQ_OFFSET_Q2 5
+
+/* Calibration constants */
+#define CALIB_RX_GAIN_DEFAULT 0x83
+#define CALIB_TX_GAIN_DEFAULT 0x75
+#define GAIN_SLEEVE_TRSHLD_DEFAULT 2
+#define CALIB_NCO_AMP_DEFAULT -10
+#define CALIB_NCO_FREQ_DEFAULT 16 /* 5M/312.5K */
+#define LO_P_THRESH 1000000
+#define N_SAMPLES_EXP_LOLC 13
+#define N_SAMPLES_EXP_IQC 13
+#define N_BIT_FIR_SCALE 11
+#define N_BIT_AMP_SCALE 10
+#define N_BIT_PHASE_SCALE 10
+#define GP_RAD_TRSHLD_DEFAULT 1144 /* Represents 1 degree in Q(16,16): 1*(pi/180) */
+#define GA_LIN_UPPER_TRSHLD_DEFAULT 66295 /* Represents 0.1 db in Q(16,16): 10^( 0.1/20)*2^16 */
+#define GA_LIN_LOWER_TRSHLD_DEFAULT 64786 /* Represents -0.1 db in Q(16,16): 10^(-0.1/20)*2^16 */
+#define COMP_FILTER_LEN_DEFAULT 9
+#define SINGLETONS_NUM_DEFAULT 10 /* Set to SINGLETONS_MAX_NUM for now*/
+#define RAMPUP_TIME 50
+#define LO_COARSE_STEP 20
+#define LO_FINE_STEP 1
+
+#define DCOC_MAX_VGA 0x14
+#define CALIB_RX_GAIN_UPPER_LIMIT 0x0
+#define CALIB_RX_GAIN_LOWER_LIMIT 0x14
+#define DCOC_MAX_VGA_ATHOS 0x1E
+#define CALIB_RX_GAIN_DEFAULT_ATHOS 0x8D
+#define CALIB_RX_GAIN_UPPER_LIMIT_ATHOS 0x0A
+#define CALIB_RX_GAIN_LOWER_LIMIT_ATHOS 0x14
+
+#define SET_PHY_DATA_FLAGS_NONE 0x0
+#define SET_PHY_DATA_FLAGS_DCOC 0x1 /* Set DCOC calibration data.*/
+#define SET_PHY_DATA_FLAGS_IQ_TX 0x2 /* Set IQ Tx calibration data.*/
+#define SET_PHY_DATA_FLAGS_IQ_RX 0x4 /* Set IQ Rx calibration data.*/
+#define SET_PHY_DATA_FLAGS_IQ_TX_LOLC 0x8 /* Set IQ Tx LOLC calibration data.*/
+#define SET_PHY_DATA_FLAGS_ALL ( \
+ SET_PHY_DATA_FLAGS_DCOC | \
+ SET_PHY_DATA_FLAGS_IQ_TX | \
+ SET_PHY_DATA_FLAGS_IQ_RX | \
+ SET_PHY_DATA_FLAGS_IQ_TX_LOLC)
+
+enum calib_cfm_id_type {
+ CALIB_CFM_DCOC,
+ CALIB_CFM_IQ,
+ CALIB_CFM_MAX
+};
+
+enum calib_channel_idx_24g {
+ CALIB_CHAN_24G_1,
+ CALIB_CHAN_24G_6,
+ CALIB_CHAN_24G_11,
+ CALIB_CHAN_24G_MAX,
+};
+
+enum calib_channel_idx_5g {
+ CALIB_CHAN_5G_36,
+ CALIB_CHAN_5G_52,
+ CALIB_CHAN_5G_100,
+ CALIB_CHAN_5G_116,
+ CALIB_CHAN_5G_132,
+ CALIB_CHAN_5G_149,
+ CALIB_CHAN_5G_MAX
+};
+
+enum calib_channel_idx_6g {
+ CALIB_CHAN_6G_1,
+ CALIB_CHAN_6G_17,
+ CALIB_CHAN_6G_33,
+ CALIB_CHAN_6G_49,
+ CALIB_CHAN_6G_65,
+ CALIB_CHAN_6G_81,
+ CALIB_CHAN_6G_97,
+ CALIB_CHAN_6G_113,
+ CALIB_CHAN_6G_129,
+ CALIB_CHAN_6G_145,
+ CALIB_CHAN_6G_161,
+ CALIB_CHAN_6G_177,
+ CALIB_CHAN_6G_193,
+ CALIB_CHAN_6G_209,
+ CALIB_CHAN_6G_225,
+ CALIB_CHAN_6G_MAX,
+};
+
+/* MAX(CALIB_CHAN_24G_MAX, CALIB_CHAN_5G_MAX, CALIB_CHAN_6G_MAX) */
+#define CALIB_CHAN_MAX CALIB_CHAN_6G_MAX
+
+struct cl_dcoc_calib {
+ s8 i;
+ s8 q;
+};
+
+struct cl_dcoc_report {
+ __le16 i_dc;
+ __le16 i_iterations;
+ __le16 q_dc;
+ __le16 q_iterations;
+};
+
+struct cl_iq_report {
+ u8 status;
+ s8 ir_db[LOOPS_MAX_NUM][IQ_NUM_TONES_CFM];
+ s8 ir_db_avg_post;
+};
+
+struct cl_iq_calib {
+ __le32 coef0;
+ __le32 coef1;
+ __le32 coef2;
+ __le32 gain;
+};
+
+struct cl_calib_errors {
+ u16 dcoc;
+ u16 lolc;
+ u16 iq_tx;
+ u16 iq_rx;
+};
+
+struct cl_calib_db {
+ struct cl_dcoc_calib
+ dcoc[TCV_MAX][CALIB_CHAN_MAX][CHNL_BW_MAX][MAX_SX][MAX_ANTENNAS][DCOC_LNA_GAIN_NUM];
+ u32 iq_tx_lolc[TCV_MAX][CALIB_CHAN_MAX][CHNL_BW_MAX][MAX_SX][MAX_ANTENNAS];
+ struct cl_iq_calib iq_tx[TCV_MAX][CALIB_CHAN_MAX][CHNL_BW_MAX][MAX_SX][MAX_ANTENNAS];
+ struct cl_iq_calib iq_rx[TCV_MAX][CALIB_CHAN_MAX][CHNL_BW_MAX][MAX_SX][MAX_ANTENNAS];
+ struct cl_calib_errors errors[TCV_MAX];
+ bool scan_complete;
+};
+
+
+struct cl_lolc_report {
+ u8 status;
+ u8 n_iter;
+ __le16 lolc_qual;
+};
+
+struct cl_gain_report {
+ u8 status;
+ u8 rx_gain;
+ u8 tx_gain;
+ u8 gain_quality;
+ __le16 final_p2p;
+ __le16 initial_p2p;
+};
+
+struct cl_iq_dcoc_info {
+ struct cl_dcoc_calib dcoc[DCOC_LNA_GAIN_NUM][MAX_ANTENNAS];
+ struct cl_iq_calib iq_tx[MAX_ANTENNAS];
+ __le32 iq_tx_lolc[MAX_ANTENNAS];
+ struct cl_iq_calib iq_rx[MAX_ANTENNAS];
+};
+
+struct cl_iq_dcoc_report {
+ struct cl_dcoc_report dcoc[DCOC_LNA_GAIN_NUM][MAX_ANTENNAS];
+ struct cl_gain_report gain_tx[MAX_ANTENNAS];
+ struct cl_gain_report gain_rx[MAX_ANTENNAS];
+ struct cl_lolc_report lolc_report[MAX_ANTENNAS];
+ struct cl_iq_report iq_tx[MAX_ANTENNAS];
+ struct cl_iq_report iq_rx[MAX_ANTENNAS];
+};
+
+struct calib_cfm {
+ u8 status;
+ __le16 raw_bits_data_0;
+ __le16 raw_bits_data_1;
+};
+
+struct cl_iq_dcoc_data {
+ struct cl_iq_dcoc_info iq_dcoc_db;
+ struct cl_iq_dcoc_report report;
+ struct calib_cfm dcoc_iq_cfm[CALIB_CFM_MAX];
+};
+
+struct cl_iq_dcoc_data_info {
+ struct cl_iq_dcoc_data *iq_dcoc_data;
+ u32 dma_addr;
+};
+
+struct cl_calib_restore {
+ u8 bw;
+ u32 primary;
+ u32 center;
+ u8 channel;
+};
+
+struct cl_hw;
+struct cl_calib_work {
+ struct work_struct ws;
+ struct cl_hw *cl_hw;
+};
+
+int cl_calib_get(struct wiphy *wiphy, struct wireless_dev *wdev,
+ const void *data, int data_len);
+int cl_calib_set(struct wiphy *wiphy, struct wireless_dev *wdev,
+ const void *data, int data_len);
+
+void cl_calib_power_read(struct cl_hw *cl_hw);
+void cl_calib_power_offset_fill(struct cl_hw *cl_hw, u8 channel,
+ u8 bw, u8 offset[MAX_ANTENNAS]);
+
+int cl_calib_pivot_channels_set(struct cl_hw *cl_hw, const void *chan_list, u32 size);
+int cl_calib_pivot_channels_reset(struct cl_hw *cl_hw);
+
+int cl_calib_start(struct cl_hw *cl_hw);
+void cl_calib_fill_phy_data(struct cl_hw *cl_hw, struct cl_iq_dcoc_info *iq_dcoc_db, u8 flags);
+int cl_calib_tables_alloc(struct cl_hw *cl_hw);
+void cl_calib_tables_free(struct cl_hw *cl_hw);
+bool cl_calib_is_needed(struct cl_hw *cl_hw, u8 channel, u8 bw);
+int cl_calib_set_channel(struct cl_hw *cl_hw, u8 channel, u8 bw, u32 primary, u32 center);
+void cl_calib_start_work(struct cl_hw *cl_hw);
+int cl_calib_handle_cfm(struct cl_hw *cl_hw, u8 mode);
+int cl_calib_validate_ants(struct cl_hw *cl_hw);
+void cl_calib_iq_get_tone_vector(u8 bw, u16 *tone_vector);
+int cl_calib_cli(struct cl_hw *cl_hw, struct cli_params *cli_params);
+
+#endif /* CL_CALIB_H */
--
2.30.0

________________________________
The information transmitted is intended only for the person or entity to which it is addressed and may contain confidential and/or privileged material. Any retransmission, dissemination, copying or other use of, or taking of any action in reliance upon this information is prohibited. If you received this in error, please contact the sender and delete the material from any computer. Nothing contained herein shall be deemed as a representation, warranty or a commitment by Celeno. No warranties are expressed or implied, including, but not limited to, any implied warranties of non-infringement, merchantability and fitness for a particular purpose.
________________________________

2021-06-17 16:23:11

by viktor.barna

[permalink] [raw]
Subject: [RFC v1 025/256] cl8k: add bus/pci/rx_pci.h

From: Viktor Barna <[email protected]>

(Part of the split. Please, take a look at the cover letter for more
details).

Signed-off-by: Viktor Barna <[email protected]>
---
drivers/net/wireless/celeno/cl8k/bus/pci/rx_pci.h | 14 ++++++++++++++
1 file changed, 14 insertions(+)
create mode 100644 drivers/net/wireless/celeno/cl8k/bus/pci/rx_pci.h

diff --git a/drivers/net/wireless/celeno/cl8k/bus/pci/rx_pci.h b/drivers/net/wireless/celeno/cl8k/bus/pci/rx_pci.h
new file mode 100644
index 000000000000..71dceddffb84
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/bus/pci/rx_pci.h
@@ -0,0 +1,14 @@
+/* SPDX-License-Identifier: MIT */
+/* Copyright(c) 2019-2021, Celeno Communications Ltd. */
+
+#ifndef CL_RX_PCI_H
+#define CL_RX_PCI_H
+
+#include "hw.h"
+
+void cl_rx_pci_init(struct cl_hw *cl_hw);
+void cl_rx_pci_deinit(struct cl_hw *cl_hw);
+void cl_rx_pci_desc_handler(struct cl_hw *cl_hw);
+void cl_rx_pci_desc_tasklet(unsigned long data);
+
+#endif /* CL_RX_PCI_H */
--
2.30.0

________________________________
The information transmitted is intended only for the person or entity to which it is addressed and may contain confidential and/or privileged material. Any retransmission, dissemination, copying or other use of, or taking of any action in reliance upon this information is prohibited. If you received this in error, please contact the sender and delete the material from any computer. Nothing contained herein shall be deemed as a representation, warranty or a commitment by Celeno. No warranties are expressed or implied, including, but not limited to, any implied warranties of non-infringement, merchantability and fitness for a particular purpose.
________________________________

2021-06-17 16:23:13

by viktor.barna

[permalink] [raw]
Subject: [RFC v1 026/256] cl8k: add bus/pci/tx_pci.c

From: Viktor Barna <[email protected]>

(Part of the split. Please, take a look at the cover letter for more
details).

Signed-off-by: Viktor Barna <[email protected]>
---
.../net/wireless/celeno/cl8k/bus/pci/tx_pci.c | 434 ++++++++++++++++++
1 file changed, 434 insertions(+)
create mode 100644 drivers/net/wireless/celeno/cl8k/bus/pci/tx_pci.c

diff --git a/drivers/net/wireless/celeno/cl8k/bus/pci/tx_pci.c b/drivers/net/wireless/celeno/cl8k/bus/pci/tx_pci.c
new file mode 100644
index 000000000000..4aeaa6a74777
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/bus/pci/tx_pci.c
@@ -0,0 +1,434 @@
+// SPDX-License-Identifier: MIT
+/* Copyright(c) 2019-2021, Celeno Communications Ltd. */
+
+#include <net/mac80211.h>
+#include "bus/pci/tx_pci.h"
+#include "bus/pci/ipc.h"
+#include "ipc_shared.h"
+#include "chip.h"
+#include "tx/tx.h"
+#include "sta.h"
+#include "enhanced_tim.h"
+#include "tx/bcmc_cfm.h"
+#include "tx/single_cfm.h"
+#include "tx/agg_cfm.h"
+#include "tx/tx_queue.h"
+#include "tx/agg_tx_report.h"
+#include "tx/sw_txhdr.h"
+#include "tx/tx_inject.h"
+#include "bus/pci/irq.h"
+#ifdef TRACE_SUPPORT
+#include "trace.h"
+#endif
+
+static void cl_tx_ipc_txdesc_populate(struct cl_hw *cl_hw, struct txdesc *txdesc,
+ u8 queue_type, u32 ipc_queue_idx)
+{
+ /*
+ * 1) Request allocation of txdesc associated with queue type and index from the ipc layer.
+ * 2) Populate ipc-txdesc with the received txdesc.
+ * 3) Increase write index - (must be last action since FW fetch WR idx first).
+ */
+ u32 *write_idx_ptr = NULL;
+ struct txdesc *ipc_txdesc = NULL;
+ struct cl_ipc_ring_indices *indices = cl_hw->ipc_env->ring_indices_elem->indices;
+ struct cl_ipc_txdesc_write_idx *txdesc_write_idx =
+ (struct cl_ipc_txdesc_write_idx *)&indices->txdesc_write_idx;
+ u32 write_idx = 0;
+ u32 masked_write_idx = 0;
+
+ switch (queue_type) {
+ case QUEUE_TYPE_AGG:
+ ipc_txdesc = cl_hw->ipc_env->tx_queues.ipc_txdesc_agg[ipc_queue_idx];
+ write_idx = le32_to_cpu(txdesc_write_idx->agg[ipc_queue_idx]);
+ write_idx_ptr = &txdesc_write_idx->agg[ipc_queue_idx];
+ masked_write_idx = write_idx & (cl_hw->max_agg_tx_q_size - 1);
+ break;
+ case QUEUE_TYPE_SINGLE:
+ ipc_txdesc = cl_hw->ipc_env->tx_queues.ipc_txdesc_single[ipc_queue_idx];
+ write_idx = le32_to_cpu(txdesc_write_idx->single[ipc_queue_idx]);
+ write_idx_ptr = &txdesc_write_idx->single[ipc_queue_idx];
+ masked_write_idx = write_idx & (IPC_TXDESC_CNT_SINGLE - 1);
+ break;
+ case QUEUE_TYPE_BCMC:
+ ipc_txdesc = cl_hw->ipc_env->tx_queues.ipc_txdesc_bcmc;
+ write_idx = le32_to_cpu(txdesc_write_idx->bcmc);
+ write_idx_ptr = &txdesc_write_idx->bcmc;
+ masked_write_idx = write_idx & (IPC_TXDESC_CNT_BCMC - 1);
+ break;
+ default:
+ cl_dbg_verbose(cl_hw, "undefined queue type %u\n", queue_type);
+ WARN_ON(true);
+ }
+
+ ipc_txdesc += masked_write_idx;
+
+ memcpy(ipc_txdesc, txdesc, sizeof(struct txdesc));
+
+ /*
+ * Update write pointer only after new txdesc copy is done since FW
+ * fetch WR pointer first, if not, FW might read and old txdesc since
+ * WR index indicate txdesc is valid.
+ */
+ *write_idx_ptr = cpu_to_le32(write_idx + 1);
+}
+
+static int cl_tx_pci_agg_cfm_handler(struct cl_hw *cl_hw)
+{
+ struct cl_agg_cfm_queue *cfm_queue = NULL;
+ struct cl_tx_queue *tx_queue = NULL;
+ struct cl_ipc_ring_indices *indices = cl_hw->ipc_env->ring_indices_elem->indices;
+ int total_cfm_handled = 0;
+ int free_space_add = 0;
+ u16 new_ssn = 0;
+ u16 prev_ssn = 0;
+ u8 used_cntr = 0;
+ u8 ba_queue_idx = 0;
+
+ for (ba_queue_idx = 0; ba_queue_idx < IPC_MAX_BA_SESSIONS; ba_queue_idx++) {
+
+ spin_lock(&cl_hw->tx_lock_cfm_agg);
+
+ cfm_queue = &cl_hw->agg_cfm_queues[ba_queue_idx];
+ if (list_empty(&cfm_queue->head)) {
+ spin_unlock(&cl_hw->tx_lock_cfm_agg);
+ continue;
+ }
+
+ tx_queue = cfm_queue->tx_queue;
+ free_space_add = 0;
+ prev_ssn = cfm_queue->ssn;
+ new_ssn = le16_to_cpu(indices->new_ssn_idx[ba_queue_idx]);
+
+ /*
+ * Continue to free skb's until:
+ * 1. list is empty.
+ * 2. agg ssn is equal to new ssn received from ssn.
+ */
+ while (!list_empty(&cfm_queue->head) && (cfm_queue->ssn != new_ssn)) {
+ cl_agg_cfm_free_head_skb(cl_hw, cfm_queue, ba_queue_idx);
+ free_space_add++;
+ cfm_queue->ssn = ((cfm_queue->ssn + 1) & 0xFFF);
+ }
+
+ /* Sanity check. test if all skb's marked to be free. */
+ if (unlikely(cfm_queue->ssn != new_ssn))
+ cl_dbg_err(cl_hw,
+ "ssn diff - queue idx=%u, new ssn=%u, prev ssn=%u, cfm ssn=%u\n",
+ ba_queue_idx, new_ssn, prev_ssn, cfm_queue->ssn);
+
+ spin_unlock(&cl_hw->tx_lock_cfm_agg);
+
+ if (free_space_add > 0) {
+ spin_lock(&cl_hw->tx_lock_agg);
+
+ if (tx_queue) {
+ tx_queue->fw_free_space += free_space_add;
+ tx_queue->total_fw_cfm += free_space_add;
+
+ /*
+ * If FW used all packets that driver pushed to him,
+ * clear the enhanced TIM bit.
+ */
+ if (cl_txq_is_fw_empty(tx_queue))
+ cl_enhanced_tim_clear_tx_agg(cl_hw,
+ ba_queue_idx,
+ tx_queue->hw_index,
+ tx_queue->cl_sta,
+ tx_queue->tid);
+ }
+
+ spin_unlock(&cl_hw->tx_lock_agg);
+
+ total_cfm_handled += free_space_add;
+ }
+
+ /* Optimization - avoid running the for loop IPC_MAX_BA_SESSIONS times */
+ used_cntr++;
+ if (used_cntr == cl_hw->used_agg_queues)
+ break;
+ }
+
+ return total_cfm_handled;
+}
+
+void cl_tx_pci_agg_cfm_tasklet(unsigned long data)
+{
+ struct cl_hw *cl_hw = (struct cl_hw *)data;
+ int cfm_handled;
+
+#ifdef TRACE_SUPPORT
+ trace_cl_trace_tx_agg_cfm_tasklet_start(cl_hw->idx);
+#endif
+
+ cfm_handled = cl_tx_pci_agg_cfm_handler(cl_hw);
+
+ if (!test_bit(CL_DEV_STOP_HW, &cl_hw->drv_flags))
+ cl_irq_enable(cl_hw, cl_hw->ipc_e2a_irq.txdesc_ind);
+
+#ifdef TRACE_SUPPORT
+ trace_cl_trace_tx_agg_cfm_tasklet_end(cl_hw->idx, cfm_handled);
+#endif
+}
+
+static void cl_tx_pci_single_cfm_handler(struct cl_hw *cl_hw, u32 cfm_status,
+ u32 dma_addr, u32 single_queue_idx)
+{
+ struct sk_buff *skb = NULL;
+ struct ieee80211_tx_info *tx_info = NULL;
+ struct cl_hw_tx_status *status = (struct cl_hw_tx_status *)&cfm_status;
+ struct cl_sw_txhdr *sw_txhdr = NULL;
+ struct cl_tx_queue *tx_queue = NULL;
+ struct cl_sta *cl_sta = NULL;
+ unsigned long flags = 0;
+ u8 hw_queue;
+ bool is_bcn;
+
+ if (status->is_bcmc) {
+ spin_lock_irqsave(&cl_hw->tx_lock_bcmc, flags);
+ sw_txhdr = cl_bcmc_cfm_find(cl_hw, dma_addr, status->keep_skb);
+ tx_queue = &cl_hw->tx_queues.bcmc;
+ } else {
+ spin_lock_bh(&cl_hw->tx_lock_single);
+ sw_txhdr = cl_single_cfm_find(cl_hw, single_queue_idx, dma_addr);
+ tx_queue = &cl_hw->tx_queues.single[single_queue_idx];
+ }
+
+ if (!sw_txhdr) {
+ cl_dbg_err(cl_hw, "Failed to find single cfm [single_queue_idx %u] status 0x%x\n",
+ single_queue_idx, cfm_status);
+ goto out;
+ }
+
+ skb = sw_txhdr->skb;
+ tx_info = IEEE80211_SKB_CB(skb);
+ hw_queue = sw_txhdr->hw_queue;
+ is_bcn = sw_txhdr->is_bcn;
+
+ /*
+ * Used for beacon frames only !!
+ * if skb was already confirmed we do not need to inc FwFreeSpace counter
+ */
+ if (likely(!status->freespace_inc_skip)) {
+ tx_queue->total_fw_cfm++;
+ tx_queue->fw_free_space++;
+
+ /* Clear the TIM element if assoicated IPC queue is empty */
+ if (!is_bcn && cl_txq_is_fw_empty(tx_queue)) {
+ bool no_ps_buffer =
+ (tx_info->flags & IEEE80211_TX_CTL_NO_PS_BUFFER) ? true : false;
+
+ cl_sta_lock(cl_hw);
+ cl_sta = cl_sta_get(cl_hw, sw_txhdr->sta_idx);
+ cl_enhanced_tim_clear_tx_single(cl_hw, single_queue_idx, hw_queue,
+ no_ps_buffer, cl_sta, sw_txhdr->tid);
+ cl_sta_unlock(cl_hw);
+ }
+ } else if (!is_bcn) {
+ cl_dbg_verbose(cl_hw, "should no be here - is_bcn=%d hw_queue=%d\n",
+ is_bcn, hw_queue);
+ }
+
+ /*
+ * Used for beacon frames only !!
+ * if this flag is set, it means FW still need this beacon skb, therefore
+ * we do not free this skb.
+ */
+ if (unlikely(status->keep_skb)) {
+ if (!is_bcn)
+ cl_dbg_verbose(cl_hw, "should not be here - is_bcn=%d hw_queue=%d\n",
+ is_bcn, hw_queue);
+ goto out;
+ }
+
+ dma_unmap_single(cl_hw->chip->dev, dma_addr, sw_txhdr->map_len, DMA_TO_DEVICE);
+
+ /*
+ * If queue is not empty call cl_txq_sched() to
+ * transfer packets from the queue to firmware
+ */
+ if (!list_empty(&tx_queue->hdrs))
+ cl_txq_sched(cl_hw, tx_queue);
+
+ /* Cl_tx_inject_cfm() must be called inside the lock */
+ if (cl_tx_ctrl_is_inject(tx_info)) {
+ cl_sta_lock(cl_hw);
+ cl_sta = cl_sta_get(cl_hw, sw_txhdr->sta_idx);
+ if (cl_sta)
+ cl_agg_tx_report_simulate_for_single(cl_hw, cl_sta, status);
+ cl_sta_unlock(cl_hw);
+
+ cl_tx_inject_cfm(cl_hw);
+ dev_kfree_skb_any(skb);
+ cl_sw_txhdr_free(cl_hw, sw_txhdr);
+ goto out;
+ }
+
+ if (status->is_bcmc)
+ spin_unlock_irqrestore(&cl_hw->tx_lock_bcmc, flags);
+ else
+ spin_unlock_bh(&cl_hw->tx_lock_single);
+
+ if (is_bcn) {
+ struct ieee80211_vif *vif = sw_txhdr->cl_vif->vif;
+
+ if (vif) {
+ if (vif->csa_active &&
+ ieee80211_beacon_cntdwn_is_complete(vif))
+ ieee80211_csa_finish(vif);
+ }
+
+ consume_skb(skb);
+ cl_sw_txhdr_free(cl_hw, sw_txhdr);
+ return;
+ }
+
+ if (status->frm_successful && !(tx_info->flags & IEEE80211_TX_CTL_NO_ACK))
+ tx_info->flags |= IEEE80211_TX_STAT_ACK;
+
+ cl_sta_lock(cl_hw);
+ cl_sta = cl_sta_get(cl_hw, sw_txhdr->sta_idx);
+
+ if (cl_sta) {
+ if (tx_queue->type != QUEUE_TYPE_BCMC &&
+ ieee80211_is_data(sw_txhdr->fc) &&
+ !cl_tx_ctrl_is_eapol(tx_info))
+ cl_agg_tx_report_simulate_for_single(cl_hw, cl_sta, status);
+
+ cl_tx_check_start_ba_session(cl_hw, cl_sta->stainfo, skb);
+ }
+
+ cl_sta_unlock(cl_hw);
+
+ if (tx_info->ack_frame_id)
+ ieee80211_tx_status(cl_hw->hw, skb);
+ else
+ consume_skb(skb);
+
+ cl_sw_txhdr_free(cl_hw, sw_txhdr);
+ return;
+
+out:
+ if (status->is_bcmc)
+ spin_unlock_irqrestore(&cl_hw->tx_lock_bcmc, flags);
+ else
+ spin_unlock_bh(&cl_hw->tx_lock_single);
+}
+
+void cl_tx_pci_single_cfm_tasklet(unsigned long data)
+{
+ struct cl_hw *cl_hw = (struct cl_hw *)data;
+ struct cl_ipc_host_env *ipc_env = cl_hw->ipc_env;
+ struct cl_ipc_cfm_msg *msg = NULL;
+
+#ifdef TRACE_SUPPORT
+ trace_cl_trace_tx_pci_single_cfm_tasklet_start(cl_hw->idx, ipc_env->cfm_used_idx);
+#endif
+
+ msg = (struct cl_ipc_cfm_msg *)(ipc_env->cfm_virt_base_addr) +
+ (ipc_env->cfm_used_idx % IPC_CFM_CNT);
+
+ while (msg && msg->dma_addr) {
+ u32 cfm_used_idx = ipc_env->cfm_used_idx++;
+
+ cl_tx_pci_single_cfm_handler(cl_hw,
+ le32_to_cpu(msg->status),
+ le32_to_cpu(msg->dma_addr),
+ le32_to_cpu(msg->single_queue_idx));
+ msg->dma_addr = 0;
+ ipc_env->shared->cfm_read_pointer = cpu_to_le32(cfm_used_idx);
+ msg = (struct cl_ipc_cfm_msg *)(ipc_env->cfm_virt_base_addr) +
+ (ipc_env->cfm_used_idx % IPC_CFM_CNT);
+ }
+
+ /* Enable the Tx CFM interrupt bit */
+ if (!test_bit(CL_DEV_STOP_HW, &cl_hw->drv_flags))
+ cl_irq_enable(cl_hw, cl_hw->ipc_e2a_irq.txcfm);
+
+#ifdef TRACE_SUPPORT
+ trace_cl_trace_tx_pci_single_cfm_tasklet_end(cl_hw->idx, ipc_env->cfm_used_idx);
+#endif
+}
+
+void cl_tx_pci_pkt_fw_send(struct cl_hw *cl_hw, struct cl_sw_txhdr *sw_txhdr,
+ struct cl_tx_queue *tx_queue)
+{
+ struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(sw_txhdr->skb);
+ struct txdesc *txdesc = &sw_txhdr->txdesc;
+ struct tx_host_info *host_info = &txdesc->host_info;
+ struct cl_sta *cl_sta = sw_txhdr->cl_sta;
+ struct cl_vif *cl_vif = sw_txhdr->cl_vif;
+ u8 hw_queue = sw_txhdr->hw_queue;
+ u16 a2e_trigger_bit_pos;
+ u8 tid = sw_txhdr->tid;
+ u8 queue_type = tx_queue->type;
+ bool no_ps_buffer = !!(tx_info->flags & IEEE80211_TX_CTL_NO_PS_BUFFER);
+ u16 ipc_queue_idx = tx_queue->index;
+ bool is_mgmt = ieee80211_is_mgmt(sw_txhdr->fc);
+ u8 *cpu_addr = (u8 *)sw_txhdr->skb->data -
+ ((host_info->host_padding & 1) * 2);
+ dma_addr_t dma_addr = dma_map_single(cl_hw->chip->dev, cpu_addr,
+ sw_txhdr->map_len, DMA_TO_DEVICE);
+
+ if (WARN_ON(dma_mapping_error(cl_hw->chip->dev, dma_addr))) {
+ tx_queue->dump_dma_map_fail++;
+
+ if (queue_type == QUEUE_TYPE_SINGLE) {
+ if (!is_mgmt)
+ cl_vif->sequence_number = DEC_SN(cl_vif->sequence_number);
+
+ cl_tx_single_free_skb(cl_hw, sw_txhdr->skb);
+ } else {
+ if (queue_type == QUEUE_TYPE_AGG) {
+ struct cl_baw *baw = &cl_sta->baws[tid];
+
+ baw->tid_seq = DEC_SN(baw->tid_seq);
+ }
+
+ dev_kfree_skb_any(sw_txhdr->skb);
+ }
+
+ cl_sw_txhdr_free(cl_hw, sw_txhdr);
+ return;
+ }
+
+ txdesc->umacdesc.packet_addr[0] = cpu_to_le32(dma_addr);
+
+ cl_tx_ipc_txdesc_populate(cl_hw, txdesc, queue_type, ipc_queue_idx);
+
+ /* make sure memory is written before push to HW */
+ wmb();
+
+ /*
+ * 1) Notify firmware on new buffered traffic by updating the enhanced tim.
+ * 2) Push sw_txhdr to confirmation list
+ */
+ if (queue_type == QUEUE_TYPE_AGG) {
+ a2e_trigger_bit_pos = IPC_IRQ_A2E_TXDESC_AGG_MAP(hw_queue);
+ cl_agg_cfm_add(cl_hw, sw_txhdr, ipc_queue_idx);
+ cl_enhanced_tim_set_tx_agg(cl_hw, ipc_queue_idx, hw_queue,
+ no_ps_buffer, cl_sta, tid);
+ } else if (queue_type == QUEUE_TYPE_SINGLE) {
+ a2e_trigger_bit_pos = IPC_IRQ_A2E_TXDESC_SINGLE_MAP(hw_queue);
+ cl_single_cfm_add(cl_hw, sw_txhdr, ipc_queue_idx);
+ cl_enhanced_tim_set_tx_single(cl_hw, ipc_queue_idx, hw_queue,
+ no_ps_buffer, cl_sta, tid);
+ } else {
+ a2e_trigger_bit_pos = IPC_IRQ_A2E_TXDESC_SINGLE_MAP(hw_queue);
+ cl_bcmc_cfm_add(cl_hw, sw_txhdr);
+ }
+
+ /* Tx_queue counters */
+ tx_queue->fw_free_space--;
+ tx_queue->total_fw_push_desc++;
+ tx_queue->total_fw_push_skb += host_info->packet_cnt;
+
+#ifdef TRACE_SUPPORT
+ trace_cl_trace_tx_push(cl_hw->idx, sw_txhdr->skb, host_info->packet_cnt,
+ txdesc->e2w_txhdr_param.seq_ctrl, tid);
+#endif
+
+ /* Trigger interrupt to firmware so that it will know that a new descriptor is ready */
+ cl_hw->ipc_host2xmac_trigger_set(cl_hw->chip, BIT(a2e_trigger_bit_pos));
+}
+
--
2.30.0

________________________________
The information transmitted is intended only for the person or entity to which it is addressed and may contain confidential and/or privileged material. Any retransmission, dissemination, copying or other use of, or taking of any action in reliance upon this information is prohibited. If you received this in error, please contact the sender and delete the material from any computer. Nothing contained herein shall be deemed as a representation, warranty or a commitment by Celeno. No warranties are expressed or implied, including, but not limited to, any implied warranties of non-infringement, merchantability and fitness for a particular purpose.
________________________________

2021-06-17 16:23:14

by viktor.barna

[permalink] [raw]
Subject: [RFC v1 028/256] cl8k: add calib.c

From: Viktor Barna <[email protected]>

(Part of the split. Please, take a look at the cover letter for more
details).

Signed-off-by: Viktor Barna <[email protected]>
---
drivers/net/wireless/celeno/cl8k/calib.c | 1682 ++++++++++++++++++++++
1 file changed, 1682 insertions(+)
create mode 100644 drivers/net/wireless/celeno/cl8k/calib.c

diff --git a/drivers/net/wireless/celeno/cl8k/calib.c b/drivers/net/wireless/celeno/cl8k/calib.c
new file mode 100644
index 000000000000..8861964e3aff
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/calib.c
@@ -0,0 +1,1682 @@
+// SPDX-License-Identifier: MIT
+/* Copyright(c) 2019-2021, Celeno Communications Ltd. */
+
+#include <linux/string.h>
+#include <linux/bitops.h>
+#include <linux/workqueue.h>
+#include <linux/delay.h>
+#include <linux/fs.h>
+#include <linux/buffer_head.h>
+
+#include "calib.h"
+#include "temperature.h"
+#include "utils/utils.h"
+#include "chip.h"
+#include "chandef.h"
+#include "fw/msg_cfm.h"
+#include "fw/msg_tx.h"
+#include "band.h"
+#include "e2p.h"
+#include "channel.h"
+#include "power.h"
+#include "afe.h"
+#include "radio.h"
+
+/*
+ * CL80x0: TCV0 - 5g, TCV1 - 24g
+ * ==============================================
+ * 50 48 46 44 42 40 38 36 --> Start 5g
+ * 100 64 62 60 58 56 54 52
+ * 116 114 112 110 108 106 104 102
+ * 134 132 128 126 124 122 120 118
+ * 153 151 149 144 142 140 138 136
+ * 3 2 1 165 161 159 157 155 --> Start 24g
+ * 11 10 9 8 7 6 5 4
+ * 14 13 12
+ */
+
+/*
+ * CL80x6: TCV0 - 6g, TCV1 - 5g
+ * ==============================================
+ * 25 21 17 13 9 5 2 1 --> Start 6g
+ * 57 53 49 45 41 37 33 29
+ * 89 85 81 77 73 69 65 61
+ * 121 117 113 109 105 101 97 93
+ * 153 147 143 139 135 131 127 123
+ * 185 181 177 173 169 165 161 157
+ * 217 213 209 205 201 197 193 189
+ * 42 40 38 36 233 229 225 221 --> Start 5g
+ * 58 56 54 52 50 48 46 44
+ * 108 106 104 102 100 64 62 60
+ * 124 122 120 118 116 114 112 110
+ * 142 140 138 136 134 132 128 126
+ * 161 159 157 155 153 151 149 144
+ * 165
+ */
+
+#define BITMAP_80X0_START_TCV0 0
+#define BITMAP_80X0_MAX_TCV0 NUM_CHANNELS_5G
+
+#define BITMAP_80X0_START_TCV1 NUM_CHANNELS_5G
+#define BITMAP_80X0_MAX_TCV1 (NUM_CHANNELS_5G + NUM_CHANNELS_24G)
+
+#define BITMAP_80X6_START_TCV0 0
+#define BITMAP_80X6_MAX_TCV0 NUM_CHANNELS_6G
+
+#define BITMAP_80X6_START_TCV1 NUM_CHANNELS_6G
+#define BITMAP_80X6_MAX_TCV1 (NUM_CHANNELS_6G + NUM_CHANNELS_5G)
+
+#define INVALID_ADDR 0xffff
+
+#define S12_S_BIT (0x00000800)
+#define U12_BIT_MASK (0x00000FFF)
+#define CAST_S12_TO_S32(i) ((~(i) & S12_S_BIT) ? (i) : ((i) | ~U12_BIT_MASK))
+
+static const u8 calib_channels_24g[CALIB_CHAN_24G_MAX] = {
+ 1, 6, 11
+};
+
+static const u8 calib_channels_5g[CALIB_CHAN_5G_MAX] = {
+ 36, 52, 100, 116, 132, 149
+};
+
+static const u8 calib_channels_6g[CALIB_CHAN_6G_MAX] = {
+ 1, 17, 33, 49, 65, 81, 97, 113, 129, 145, 161, 177, 193, 209, 225
+};
+
+static u8 tone_vector_arr[CHNL_BW_MAX][IQ_NUM_TONES_REQ] = {
+ {6, 10, 14, 18, 22, 24, 26, 27},
+ {10, 18, 26, 34, 41, 48, 53, 58},
+ {18, 34, 50, 66, 82, 98, 110, 122},
+ {18, 34, 66, 98, 130, 164, 224, 250}
+};
+
+static u8 get_bitmap_start_tcv1(struct cl_chip *chip)
+{
+ if (cl_chip_is_6g(chip))
+ return BITMAP_80X6_START_TCV1;
+ else
+ return BITMAP_80X0_START_TCV1;
+}
+
+static void get_bitmap_boundaries(struct cl_chip *chip, u8 tcv_idx, u8 *start, u8 *max)
+{
+ if (cl_chip_is_6g(chip)) {
+ if (tcv_idx == TCV0) {
+ *start = BITMAP_80X6_START_TCV0;
+ *max = BITMAP_80X6_MAX_TCV0;
+ } else {
+ *start = BITMAP_80X6_START_TCV1;
+ *max = BITMAP_80X6_MAX_TCV1;
+ }
+ } else {
+ if (tcv_idx == TCV0) {
+ *start = BITMAP_80X0_START_TCV0;
+ *max = BITMAP_80X0_MAX_TCV0;
+ } else {
+ *start = BITMAP_80X0_START_TCV1;
+ *max = BITMAP_80X0_MAX_TCV1;
+ }
+ }
+}
+
+static u8 idx_to_arr_offset(u8 idx)
+{
+ /* Divide by 8 for array index */
+ return idx >> 3;
+}
+
+static u8 idx_to_bit_offset(u8 idx)
+{
+ /* Reminder is for bit index (assummed array of u8) */
+ return idx & 0x07;
+}
+
+static const u8 bits_cnt_table256[] = {
+ 0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4,
+ 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
+ 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
+ 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
+ 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
+ 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
+ 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
+ 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
+ 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
+ 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
+ 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
+ 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
+ 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
+ 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
+ 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
+ 4, 5, 5, 6, 5, 6, 6, 7, 5, 6, 6, 7, 6, 7, 7, 8
+};
+
+static u8 count_bits(const u8 *bitmap)
+{
+ /*
+ * Count bits in a given u8 array ASSUMED ARRAY SIZE IS BIT_MAP_SIZE
+ * bitmap - pointer to u8 array (bitmap)
+ */
+ u8 i = 0, cnt = 0;
+
+ for (i = 0; i < BIT_MAP_SIZE; i++)
+ cnt += bits_cnt_table256[bitmap[i]];
+
+ return cnt;
+}
+
+static bool is_vector_unset(const u8 *bitmap)
+{
+ /* Check bitmap is unset i.e. all values are CURR_BMP_UNSET */
+ u8 empty_bitmap[BIT_MAP_SIZE] = {0};
+
+ return !memcmp(bitmap, empty_bitmap, BIT_MAP_SIZE);
+}
+
+static bool bitmap_test_bit_idx(const u8 *bitmap, u8 idx)
+{
+ /* Check bit at a given index is set i.e. 1 */
+ u8 arr_idx = idx_to_arr_offset(idx), bit_idx = idx_to_bit_offset(idx);
+
+ if (arr_idx >= BIT_MAP_SIZE)
+ return false;
+
+ /* Convert non-zero to true and zero to false */
+ return !!(bitmap[arr_idx] & BIT(bit_idx));
+}
+
+static void bitmap_shift(u8 *bitmap, u8 shft)
+{
+ /* Shifts an array of byte of size len by shft number of bits to the left */
+ u8 bitmap_tmp[BIT_MAP_SIZE] = {0};
+ u8 msb_shifts = shft % 8;
+ u8 lsb_shifts = 8 - msb_shifts;
+ u8 byte_shift = shft / 8;
+ u8 last_byte = BIT_MAP_SIZE - byte_shift - 1;
+ u8 msb_idx;
+ u8 i;
+
+ memcpy(bitmap_tmp, bitmap, BIT_MAP_SIZE);
+ memset(bitmap, 0, BIT_MAP_SIZE);
+
+ for (i = 0; i < BIT_MAP_SIZE; i++) {
+ if (i <= last_byte) {
+ msb_idx = i + byte_shift;
+ bitmap[i] = bitmap_tmp[msb_idx] >> msb_shifts;
+ if (i != last_byte)
+ bitmap[i] |= bitmap_tmp[msb_idx + 1] << lsb_shifts;
+ }
+ }
+}
+
+static bool bitmap_set_bit_idx(struct cl_hw *cl_hw, u8 *bitmap, u8 idx)
+{
+ /* Set bit at a given index */
+ u8 arr_idx = idx_to_arr_offset(idx), bit_idx = idx_to_bit_offset(idx);
+
+ if (arr_idx >= BIT_MAP_SIZE) {
+ cl_dbg_err(cl_hw, "invalid arr_idx (%u)\n", arr_idx);
+ return false;
+ }
+
+ bitmap[arr_idx] |= BIT(bit_idx);
+ return true;
+}
+
+static bool bitmap_clear_bit_idx(struct cl_hw *cl_hw, u8 *bitmap, u8 idx)
+{
+ /* Clear bit at a given index */
+ u8 arr_idx = idx_to_arr_offset(idx), bit_idx = idx_to_bit_offset(idx);
+
+ if (arr_idx >= BIT_MAP_SIZE) {
+ cl_dbg_err(cl_hw, "invalid arr_idx (%u)\n", arr_idx);
+ return false;
+ }
+
+ bitmap[arr_idx] &= ~BIT(bit_idx);
+ return true;
+}
+
+static u16 bitmap_look_lsb_up(struct cl_hw *cl_hw, u8 *bitmap, u16 idx)
+{
+ /* Find closest ON(1) bit with index haigher than idx inside bitmap */
+ u16 curr_idx = idx;
+ u8 curr = 0;
+
+ while (++curr_idx < cl_channel_num(cl_hw)) {
+ curr = bitmap[idx_to_arr_offset(curr_idx)];
+ if (curr & (1ULL << idx_to_bit_offset(curr_idx)))
+ return curr_idx;
+ }
+
+ /* No matching bit found - return original index */
+ return idx;
+}
+
+static u16 bitmap_look_msb_down(struct cl_hw *cl_hw, u8 *bitmap, u16 idx)
+{
+ /* Find closest ON(1) bit with index lower than idx inside bitmap */
+ u16 curr_idx = idx;
+ u8 curr = 0;
+
+ if (idx >= cl_channel_num(cl_hw)) {
+ cl_dbg_err(cl_hw, "Invalid channel index [%u]\n", idx);
+ return idx;
+ }
+
+ while (curr_idx-- != 0) {
+ curr = bitmap[idx_to_arr_offset(curr_idx)];
+ if (curr & (1ULL << idx_to_bit_offset(curr_idx)))
+ return curr_idx;
+ }
+
+ /* No matching bit found - return original index */
+ return idx;
+}
+
+static u8 address_offset_tcv1(struct cl_hw *cl_hw)
+{
+ /* Calculate eeprom calibration data offset for tcv1 */
+ struct cl_chip *chip = cl_hw->chip;
+ u8 i, cnt = 0;
+ u8 bitmap[BIT_MAP_SIZE] = {0};
+
+ if (cl_e2p_read(chip, bitmap, BIT_MAP_SIZE, ADDR_CALIB_CHAN_BMP))
+ return 0;
+
+ for (i = 0; i < get_bitmap_start_tcv1(chip); i++)
+ cnt += bitmap_test_bit_idx(bitmap, i);
+
+ return cnt;
+}
+
+static int point_idx_to_address(struct cl_hw *cl_hw, u8 *bitmap, struct point *pt)
+{
+ /* Calculate eeprom address for a given idx and phy (initiated point) */
+ u8 i, cnt = 0;
+
+ pt->addr = INVALID_ADDR;
+
+ if (!bitmap_test_bit_idx(bitmap, pt->idx))
+ return 0;
+
+ if (pt->phy >= MAX_ANTENNAS) {
+ cl_dbg_err(cl_hw, "Invalid phy number %u", pt->phy);
+ return -EINVAL;
+ }
+
+ for (i = 0; i < pt->idx; i++)
+ cnt += bitmap_test_bit_idx(bitmap, i);
+
+ if (cl_hw_is_tcv1(cl_hw))
+ cnt += address_offset_tcv1(cl_hw);
+
+ pt->addr = ADDR_CALIB_PHY +
+ sizeof(struct eeprom_phy_calib) * (cnt * MAX_ANTENNAS + pt->phy);
+
+ return 0;
+}
+
+static bool linear_equation_signed(struct cl_hw *cl_hw, const u16 x, s8 *y,
+ const u16 x0, const s8 y0, const u16 x1, const s8 y1)
+{
+ /* Calculate y given to points (x0,y0) and (x1,y1) and x */
+ s32 numerator = (x - x0) * (y1 - y0);
+ s32 denominator = x1 - x0;
+
+ if (unlikely(!denominator)) {
+ cl_dbg_err(cl_hw, "zero denominator\n");
+ return false;
+ }
+
+ *y = (s8)(y0 + DIV_ROUND_CLOSEST(numerator, denominator));
+
+ return true;
+}
+
+static bool calculate_calib(struct cl_hw *cl_hw, u8 *bitmap,
+ struct point *p0, struct point *p1, struct point *p2)
+{
+ /* Main interpolation/extrapolation function */
+ bool calc_succsess = false;
+ u16 freq0, freq1, freq2;
+
+ if (unlikely(is_vector_unset(bitmap)))
+ return false;
+
+ p1->idx = bitmap_look_lsb_up(cl_hw, bitmap, p0->idx);
+ p2->idx = bitmap_look_msb_down(cl_hw, bitmap, p0->idx);
+
+ /* Invalid case */
+ if (p1->idx == p0->idx && p2->idx == p0->idx) {
+ cl_dbg_err(cl_hw, "Invalid index %u or bad bit map\n", p0->idx);
+ return false;
+ }
+
+ /* Extrapolation case */
+ if (p1->idx == p0->idx)
+ p1->idx = bitmap_look_msb_down(cl_hw, bitmap, p2->idx);
+ if (p2->idx == p0->idx)
+ p2->idx = bitmap_look_lsb_up(cl_hw, bitmap, p1->idx);
+
+ /* Address from index */
+ if (point_idx_to_address(cl_hw, bitmap, p1) || p1->addr == INVALID_ADDR) {
+ cl_dbg_err(cl_hw, "Point calculation failed\n");
+ return false;
+ }
+
+ if (point_idx_to_address(cl_hw, bitmap, p2) || p2->addr == INVALID_ADDR) {
+ cl_dbg_err(cl_hw, "Point calculation failed\n");
+ return false;
+ }
+
+ /* Read from eeprom */
+ if (cl_e2p_read(cl_hw->chip, (u8 *)&p1->calib, sizeof(struct eeprom_phy_calib), p1->addr))
+ return false;
+
+ /* No interpolation required */
+ if (p1->addr == p2->addr) {
+ p0->calib = p1->calib;
+ return true;
+ }
+
+ /* Interpolation or extrapolation is required - read from eeprom */
+ if (cl_e2p_read(cl_hw->chip, (u8 *)&p2->calib, sizeof(struct eeprom_phy_calib), p2->addr))
+ return false;
+
+ freq0 = cl_channel_idx_to_freq(cl_hw, p0->idx);
+ freq1 = cl_channel_idx_to_freq(cl_hw, p1->idx);
+ freq2 = cl_channel_idx_to_freq(cl_hw, p2->idx);
+
+ /* Interpolate/extrapolate target power */
+ calc_succsess = linear_equation_signed(cl_hw,
+ freq0, &p0->calib.pow,
+ freq1, p1->calib.pow,
+ freq2, p2->calib.pow);
+
+ /* Interpolate/extrapolate power offset */
+ calc_succsess = calc_succsess && linear_equation_signed(cl_hw,
+ freq0, &p0->calib.offset,
+ freq1, p1->calib.offset,
+ freq2, p2->calib.offset);
+
+ /* Interpolate/extrapolate calibration temperature */
+ calc_succsess = calc_succsess && linear_equation_signed(cl_hw,
+ freq0, &p0->calib.tmp,
+ freq1, p1->calib.tmp,
+ freq2, p2->calib.tmp);
+
+ if (unlikely(!calc_succsess)) {
+ cl_dbg_err(cl_hw,
+ "Calc failed: freq0 %u idx0 %u, freq1 %u idx1 %u, freq2 %u idx2 %u\n",
+ freq0, p0->idx, freq1, p1->idx, freq2, p2->idx);
+ return false;
+ }
+
+ return true;
+}
+
+static int read_validate_vector_bitmap(struct cl_hw *cl_hw, u8 *bitmap)
+{
+ struct cl_chip *chip = cl_hw->chip;
+
+ if (cl_e2p_read(chip, bitmap, BIT_MAP_SIZE, ADDR_CALIB_CHAN_BMP))
+ return -1;
+
+ /* Test if e2p was read succsefull since it is not ALL EMPTY */
+ if (is_vector_unset(bitmap)) {
+ cl_dbg_err(cl_hw, "Vector not ready\n");
+ return -EPERM;
+ }
+
+ if (cl_hw_is_tcv1(cl_hw)) {
+ u8 bitmap_start = get_bitmap_start_tcv1(chip);
+
+ bitmap_shift(bitmap, bitmap_start);
+ }
+
+ return 0;
+}
+
+static int e2p_prepare(struct cl_hw *cl_hw, struct point *data, u8 *bitmap)
+{
+ int ret = read_validate_vector_bitmap(cl_hw, bitmap);
+
+ if (ret) {
+ cl_dbg_err(cl_hw, "read_validate_vector_bitmap failed\n");
+ return ret;
+ }
+
+ data->idx = cl_channel_to_index(cl_hw, data->chan);
+
+ return point_idx_to_address(cl_hw, bitmap, data);
+}
+
+static int read_or_interpolate_point(struct cl_hw *cl_hw, u8 *bitmap, struct point *p0)
+{
+ struct point p1 = {.phy = p0->phy};
+ struct point p2 = {.phy = p0->phy};
+ struct point tmp_pt = *p0;
+
+ /* Invalid address = no physical address was allocated to this channel */
+ if (tmp_pt.addr != INVALID_ADDR) {
+ if (cl_e2p_read(cl_hw->chip, (u8 *)&tmp_pt.calib,
+ sizeof(struct eeprom_phy_calib), tmp_pt.addr))
+ return -1;
+ } else {
+ /* Interpolate */
+ if (!calculate_calib(cl_hw, bitmap, &tmp_pt, &p1, &p2)) {
+ cl_dbg_err(cl_hw, "Interpolation Error\n");
+ return -EFAULT;
+ }
+ }
+
+ if (tmp_pt.calib.pow == 0 && tmp_pt.calib.offset == 0 && tmp_pt.calib.tmp == 0) {
+ u16 freq = cl_channel_idx_to_freq(cl_hw, tmp_pt.idx);
+
+ cl_dbg_err(cl_hw, "Verify calibration point: addr %x, idx %u, freq %u, phy %u\n",
+ tmp_pt.addr, tmp_pt.idx, freq, tmp_pt.phy);
+ /* *Uninitiated eeprom value */
+ return -EINVAL;
+ }
+
+ /* Now p0 will contain "Valid" calculations of calib" */
+ p0->calib = tmp_pt.calib;
+ return 0;
+}
+
+int cl_calib_get(struct wiphy *wiphy, struct wireless_dev *wdev,
+ const void *data, int data_len)
+{
+ /* Kernel space callback for handling E2P_GET_CALIB vendor subcmd */
+ int ret;
+ struct point *p0;
+ u8 e2p_bitmap[BIT_MAP_SIZE] = {0};
+ struct cl_hw *cl_hw = WIPHY_TO_CL_HW(wiphy);
+
+ if (!data) {
+ cl_dbg_err(cl_hw, "data is null\n");
+ return -1;
+ }
+
+ p0 = (struct point *)data;
+
+ ret = e2p_prepare(cl_hw, p0, e2p_bitmap);
+ if (ret) {
+ cl_dbg_err(cl_hw, "Unable prepare e2p\n");
+ return ret;
+ }
+
+ ret = read_or_interpolate_point(cl_hw, e2p_bitmap, p0);
+ if (ret) {
+ cl_dbg_trace(cl_hw, "read_or_interpolate_point error\n");
+ return ret;
+ }
+
+ return cl_vendor_reply(cl_hw, &p0->calib, sizeof(p0->calib));
+}
+
+int cl_calib_set(struct wiphy *wiphy, struct wireless_dev *wdev,
+ const void *data, int data_len)
+{
+ /* Kernel space callback for handling E2P_SET_CALIB vendor subcmd */
+ struct cl_hw *cl_hw = WIPHY_TO_CL_HW(wiphy);
+ struct point pt;
+ int ret;
+ u8 e2p_bitmap[BIT_MAP_SIZE] = {0};
+ u8 ch_idx = 0;
+
+ if (!data) {
+ cl_dbg_err(cl_hw, "data is null\n");
+ return -1;
+ }
+
+ pt = *(struct point *)data;
+
+ ret = e2p_prepare(cl_hw, &pt, e2p_bitmap);
+ if (ret) {
+ cl_dbg_err(cl_hw, "Unable prepare e2p\n");
+ return ret;
+ }
+
+ if (pt.addr == INVALID_ADDR) {
+ cl_dbg_err(cl_hw, "Invalid address - permission denied\n");
+ return -EPERM;
+ }
+
+ if (pt.calib.pow < POWER_MIN_DB || pt.calib.pow > POWER_MAX_DB) {
+ cl_dbg_err(cl_hw, "Invalid power (%d). Valid range (%d - %d)\n",
+ pt.calib.pow, POWER_MIN_DB, POWER_MAX_DB);
+ return -1;
+ }
+
+ if (pt.calib.offset < POWER_OFFSET_MIN_Q2 || pt.calib.offset > POWER_OFFSET_MAX_Q2) {
+ cl_dbg_err(cl_hw, "Invalid power offset (%d). Valid range (%d - %d)\n",
+ pt.calib.offset, POWER_OFFSET_MIN_Q2, POWER_OFFSET_MAX_Q2);
+ return -1;
+ }
+
+ if (!bitmap_test_bit_idx(e2p_bitmap, pt.idx)) {
+ cl_dbg_err(cl_hw, "No permition to write to this channel %u\n", pt.idx);
+ return -EACCES;
+ }
+
+ /*
+ * Temperature is an optional argument for "e2p set calib" command.
+ * If value is 0x7f then temperature argument was not set, and it
+ * should be set by the driver.
+ */
+ if (pt.calib.tmp == S8_MAX)
+ pt.calib.tmp = cl_temperature_read(cl_hw, TEMP_MODE_INTERNAL);
+
+ if (cl_e2p_write(cl_hw->chip, (u8 *)&pt.calib, sizeof(struct eeprom_phy_calib), pt.addr))
+ return -1;
+
+ ch_idx = cl_channel_to_index(cl_hw, pt.chan);
+
+ if (ch_idx < MAX_CHANNELS && pt.phy < MAX_ANTENNAS) {
+ cl_hw->tx_pow_info[ch_idx][pt.phy].power = pt.calib.pow;
+ cl_hw->tx_pow_info[ch_idx][pt.phy].offset = pt.calib.offset;
+ cl_hw->tx_pow_info[ch_idx][pt.phy].temperature = pt.calib.tmp;
+ cl_hw->set_calib = true;
+ }
+
+ return 0;
+}
+
+static void cl_calib_power_reset(struct cl_hw *cl_hw)
+{
+ u8 ch_idx;
+ u16 phy;
+ static const struct cl_tx_power_info default_info = {
+ .power = UNCALIBRATED_POWER,
+ .offset = UNCALIBRATED_POWER_OFFSET,
+ .temperature = UNCALIBRATED_TEMPERATURE
+ };
+
+ /* Initiate tx_pow_info struct to default values */
+ for (ch_idx = 0; ch_idx < cl_channel_num(cl_hw); ch_idx++)
+ for (phy = 0; phy < MAX_ANTENNAS; phy++)
+ cl_hw->tx_pow_info[ch_idx][phy] = default_info;
+}
+
+#define PHY0_OFFSET_FIX_Q2 -8 /* -2db */
+#define PHY3_OFFSET_FIX_Q2 14 /* +3.5db */
+
+void cl_calib_power_read(struct cl_hw *cl_hw)
+{
+ struct cl_chip *chip = cl_hw->chip;
+ int ret;
+ u8 bitmap[BIT_MAP_SIZE] = {0};
+ struct point curr_point = {0};
+ u8 *phy = &curr_point.phy;
+ u8 *ch_idx = &curr_point.idx;
+
+ /* Initiate tx_pow_info struct to default values */
+ cl_calib_power_reset(cl_hw);
+
+ /* Vector not initiated set table to default values */
+ if (unlikely(read_validate_vector_bitmap(cl_hw, bitmap))) {
+ cl_dbg_trace(cl_hw, "initiate to default values\n");
+ return;
+ }
+
+ /* Perform only on calibrated boards - read_validate_vector_bitmap succeeded (0) */
+ for (*ch_idx = 0; *ch_idx < cl_channel_num(cl_hw); (*ch_idx)++)
+ for (*phy = 0; *phy < cl_hw->num_antennas; (*phy)++) {
+ ret = point_idx_to_address(cl_hw, bitmap, &curr_point);
+
+ if (ret) {
+ /* *don't overwrite default values */
+ cl_dbg_err(cl_hw, "point idx to address failed\n");
+ continue;
+ }
+
+ ret = read_or_interpolate_point(cl_hw, bitmap, &curr_point);
+ /* Unable to calculate new value ==> DON'T overwrite default values */
+ if (unlikely(ret))
+ continue;
+
+ /*
+ * Work around:
+ * Add 3.5dB offset to PHY3 if EEPROM version is 0.
+ * Decrease 2dB offset to all PHYs if EEPROM version is 1.
+ */
+ if (!cl_chip_is_6g(chip)) {
+ u8 eeprom_version = chip->eeprom_cache->general.version;
+
+ if (cl_band_is_5g(cl_hw) && eeprom_version == 0 && *phy == 3)
+ curr_point.calib.offset += PHY3_OFFSET_FIX_Q2;
+ else if (cl_band_is_24g(cl_hw) && eeprom_version == 1)
+ curr_point.calib.offset += PHY0_OFFSET_FIX_Q2;
+ }
+
+ cl_hw->tx_pow_info[*ch_idx][*phy].power = curr_point.calib.pow;
+ cl_hw->tx_pow_info[*ch_idx][*phy].offset = curr_point.calib.offset;
+ cl_hw->tx_pow_info[*ch_idx][*phy].temperature = curr_point.calib.tmp;
+ }
+
+ cl_dbg_trace(cl_hw, "Created tx_pow_info\n");
+}
+
+void cl_calib_power_offset_fill(struct cl_hw *cl_hw, u8 channel,
+ u8 bw, u8 offset[MAX_ANTENNAS])
+{
+ u8 i;
+ u8 chan_idx = cl_channel_to_index(cl_hw, channel);
+ s8 signed_offset;
+ struct cl_ate_db *ate_db = &cl_hw->ate_db;
+
+ if (chan_idx == INVALID_CHAN_IDX)
+ return;
+
+ /* In ATE mode, use values of 'ATE power_offset' if it was set */
+ if (ate_db->active && ate_db->tx_power_offset[0] != S8_MAX) {
+ for (i = 0; i < MAX_ANTENNAS; i++) {
+ s8 pow_offset = ate_db->tx_power_offset[i];
+
+ signed_offset = cl_power_offset_check_margin(cl_hw, bw, i, pow_offset);
+ offset[i] = cl_convert_signed_to_reg_value(signed_offset);
+ }
+
+ return;
+ }
+
+ for (i = 0; i < MAX_ANTENNAS; i++) {
+ s8 pow_offset = cl_hw->tx_pow_info[chan_idx][i].offset;
+
+ signed_offset = cl_power_offset_check_margin(cl_hw, bw, i, pow_offset);
+ offset[i] = cl_convert_signed_to_reg_value(signed_offset);
+ }
+}
+
+static void pivot_channels_reset(struct cl_hw *cl_hw, u8 *bitmap)
+{
+ u8 i, start = 0, max = 0;
+
+ get_bitmap_boundaries(cl_hw->chip, cl_hw->tcv_idx, &start, &max);
+
+ for (i = start; i < max; i++)
+ bitmap_clear_bit_idx(cl_hw, bitmap, i);
+}
+
+static u8 count_num_pivots(struct cl_chip *chip, const u8 *bitmap, u8 tcv_idx)
+{
+ u8 i = 0, cnt = 0, start = 0, max = 0;
+
+ get_bitmap_boundaries(chip, tcv_idx, &start, &max);
+
+ for (i = start; i < max; i++)
+ if (bitmap_test_bit_idx(bitmap, i))
+ cnt++;
+
+ return cnt;
+}
+
+int cl_calib_pivot_channels_set(struct cl_hw *cl_hw, const void *chan_list, u32 size)
+{
+ struct cl_chip *chip = cl_hw->chip;
+ u8 bitmap[BIT_MAP_SIZE] = {0};
+ u8 num_pivots = 0;
+ u8 idx = 0;
+
+ if (cl_e2p_read(chip, bitmap, BIT_MAP_SIZE, ADDR_CALIB_CHAN_BMP))
+ return -1;
+
+ num_pivots = count_num_pivots(chip, bitmap, cl_hw->tcv_idx);
+
+ if (num_pivots > 0) {
+ cl_dbg_err(cl_hw, "Vector already set\n");
+ return -EACCES;
+ }
+
+ while (size--) {
+ idx = cl_channel_to_index(cl_hw, ((u32 *)chan_list)[size]);
+
+ if (idx == INVALID_CHAN_IDX) {
+ cl_dbg_err(cl_hw, "Bad channel index %u", idx);
+ return -EINVAL;
+ }
+
+ if (cl_hw_is_tcv1(cl_hw))
+ idx += get_bitmap_start_tcv1(chip);
+
+ if (!bitmap_set_bit_idx(cl_hw, bitmap, idx)) {
+ cl_dbg_err(cl_hw, "Bad channel index %u", idx);
+ return -EINVAL;
+ }
+ }
+
+ if (count_bits(bitmap) > NUM_OF_PIVOTS) {
+ cl_dbg_err(cl_hw, "Too much pivot channels chosen\n");
+ return -EINVAL;
+ }
+
+ if (cl_e2p_write(chip, bitmap, BIT_MAP_SIZE, ADDR_CALIB_CHAN_BMP))
+ return -1;
+
+ /*
+ * Pivots of tcv0 are located before the pivots of tcv1.
+ * If calibration of tcv1 was done before calibration of tcv0, we must move the
+ * calibration data of tcv1 so that there is room for the tcv0 calibration data.
+ */
+ if (cl_hw_is_tcv0(cl_hw)) {
+ u8 num_pivots_tcv0 = count_num_pivots(chip, bitmap, TCV0);
+ u8 num_pivots_tcv1 = count_num_pivots(chip, bitmap, TCV1);
+
+ if (num_pivots_tcv1 > 0) {
+ struct eeprom_phy_calib phy_calib[NUM_PIVOT_PHYS] = { {0} };
+
+ if (cl_e2p_read(chip, (u8 *)phy_calib, SIZE_CALIB_PHY, ADDR_CALIB_PHY))
+ return -1;
+
+ memmove(&phy_calib[num_pivots_tcv0 * MAX_ANTENNAS],
+ &phy_calib[0],
+ num_pivots_tcv1 * MAX_ANTENNAS * sizeof(struct eeprom_phy_calib));
+ memset(&phy_calib[0],
+ 0,
+ num_pivots_tcv0 * MAX_ANTENNAS * sizeof(struct eeprom_phy_calib));
+
+ if (cl_e2p_write(chip, (u8 *)phy_calib, SIZE_CALIB_PHY, ADDR_CALIB_PHY))
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+int cl_calib_pivot_channels_reset(struct cl_hw *cl_hw)
+{
+ /* Both eeprom and efuse are being set to 0 for reset */
+ struct cl_chip *chip = cl_hw->chip;
+ u8 bitmap[BIT_MAP_SIZE] = {0};
+ struct eeprom_phy_calib phy_calib[NUM_PIVOT_PHYS] = { {0} };
+ u8 num_pivots_tcv0 = 0;
+ u8 num_pivots_tcv1 = 0;
+
+ if (sizeof(phy_calib) != SIZE_CALIB_PHY) {
+ cl_dbg_err(cl_hw, "sizeof(phy_calib) != SIZE_CALIB_PHY\n");
+ return -1;
+ }
+
+ /* Read current bitmap and calibration data */
+ if (cl_e2p_read(chip, (u8 *)bitmap, BIT_MAP_SIZE, ADDR_CALIB_CHAN_BMP))
+ return -1;
+ if (cl_e2p_read(chip, (u8 *)phy_calib, SIZE_CALIB_PHY, ADDR_CALIB_PHY))
+ return -1;
+
+ /* Find number of pivots for each band */
+ num_pivots_tcv0 = count_num_pivots(chip, bitmap, TCV0);
+ num_pivots_tcv1 = count_num_pivots(chip, bitmap, TCV1);
+
+ /* Reset bitmap of this band */
+ pivot_channels_reset(cl_hw, bitmap);
+
+ /* Reset calibration data of this band */
+ if (cl_hw_is_tcv0(cl_hw)) {
+ if (num_pivots_tcv1 > 0) {
+ /* For tcv0 shift calibration data of tcv1 to the beginning */
+ memcpy(&phy_calib[0], &phy_calib[num_pivots_tcv0 * MAX_ANTENNAS],
+ num_pivots_tcv1 * MAX_ANTENNAS * sizeof(struct eeprom_phy_calib));
+ memset(&phy_calib[num_pivots_tcv1 * MAX_ANTENNAS], 0,
+ num_pivots_tcv0 * MAX_ANTENNAS * sizeof(struct eeprom_phy_calib));
+ } else {
+ memset(&phy_calib[0], 0,
+ num_pivots_tcv0 * MAX_ANTENNAS * sizeof(struct eeprom_phy_calib));
+ }
+ } else {
+ memset(&phy_calib[num_pivots_tcv0 * MAX_ANTENNAS],
+ 0, num_pivots_tcv1 * MAX_ANTENNAS * sizeof(struct eeprom_phy_calib));
+ }
+
+ /* Write back modified bitmap and calibration data */
+ if (cl_e2p_write(chip, (u8 *)bitmap, BIT_MAP_SIZE, ADDR_CALIB_CHAN_BMP))
+ return -1;
+ if (cl_e2p_write(chip, (u8 *)phy_calib, SIZE_CALIB_PHY, ADDR_CALIB_PHY))
+ return -1;
+
+ /* Reset host calibration data */
+ cl_calib_power_reset(cl_hw);
+
+ return 0;
+}
+
+static void cl_calib_init_cfm(struct cl_iq_dcoc_data *iq_dcoc_data)
+{
+ int i;
+
+ for (i = 0; i < CALIB_CFM_MAX; i++)
+ iq_dcoc_data->dcoc_iq_cfm[i].status = CALIB_FAIL;
+}
+
+static void cl_calib_save_channel(struct cl_hw *cl_hw, struct cl_calib_restore *calib_restore)
+{
+ calib_restore->bw = cl_hw->bw;
+ calib_restore->primary = cl_hw->primary_freq;
+ calib_restore->center = cl_hw->center_freq;
+ calib_restore->channel = ieee80211_frequency_to_channel(cl_hw->primary_freq);
+}
+
+static int cl_calib_set_idle(struct cl_hw *cl_hw, bool idle)
+{
+ struct cl_chip *chip = cl_hw->chip;
+ struct cl_hw *cl_hw_tcv0 = chip->cl_hw_tcv0;
+ struct cl_hw *cl_hw_tcv1 = chip->cl_hw_tcv1;
+ u8 is_prod = chip->conf->ce_production_mode;
+ bool tcv0_en = (cl_radio_is_on(cl_hw_tcv0) || (is_prod && cl_hw_tcv0->ate_db.active));
+ bool tcv1_en = (cl_radio_is_on(cl_hw_tcv1) || (is_prod && cl_hw_tcv1->ate_db.active));
+
+ if (!idle) {
+ if (tcv1_en)
+ cl_msg_tx_set_idle(cl_hw_tcv1, MAC_ACTIVE);
+
+ if (tcv0_en)
+ cl_msg_tx_set_idle(cl_hw_tcv0, MAC_ACTIVE);
+
+ return 0;
+ }
+
+ if (tcv1_en)
+ cl_msg_tx_idle_async(cl_hw_tcv1);
+
+ if (tcv0_en)
+ cl_msg_tx_set_idle(cl_hw_tcv0, MAC_IDLE_SYNC);
+
+ if (wait_event_timeout(cl_hw->wait_queue, !cl_hw->idle_async_set,
+ CL_MSG_CFM_TIMEOUT_JIFFIES))
+ return 0;
+
+ cl_dbg_err(cl_hw, "Timeout occurred - MM_IDLE_ASYNC_IND\n");
+
+ return -ETIMEDOUT;
+}
+
+static int _cl_calib_set_channel(struct cl_hw *cl_hw, u32 channel, u32 bw)
+{
+ u32 primary = 0;
+ u32 center = 0;
+ enum nl80211_chan_width width = NL80211_CHAN_WIDTH_20;
+
+ if (cl_chandef_calc(cl_hw, channel, bw, &width, &primary, &center)) {
+ cl_dbg_err(cl_hw, "cl_chandef_calc failed\n");
+ return -EINVAL;
+ }
+
+ cl_dbg_verbose(cl_hw, "Calibrate channel %u bw %u\n", channel, BW_TO_MHZ(bw));
+
+ return _cl_msg_tx_set_channel(cl_hw, channel, bw, primary, center, SET_CHANNEL_MODE_CALIB);
+}
+
+static void cl_calib_channels_6g(struct cl_hw *cl_hw)
+{
+ int i;
+
+ /* Calibrate channels: 1, 33, 65, 97, 129, 161, 193, 225 */
+ for (i = 0; i < CALIB_CHAN_6G_MAX; i += 2)
+ _cl_calib_set_channel(cl_hw, calib_channels_6g[i], CHNL_BW_160);
+
+ for (i = 0; i < CALIB_CHAN_6G_MAX; i++) {
+ _cl_calib_set_channel(cl_hw, calib_channels_6g[i], CHNL_BW_80);
+ _cl_calib_set_channel(cl_hw, calib_channels_6g[i], CHNL_BW_20);
+ }
+}
+
+static void cl_calib_channels_5g(struct cl_hw *cl_hw)
+{
+ int i;
+
+ _cl_calib_set_channel(cl_hw, 36, CHNL_BW_160);
+ _cl_calib_set_channel(cl_hw, 100, CHNL_BW_160);
+
+ for (i = 0; i < CALIB_CHAN_5G_MAX; i++) {
+ _cl_calib_set_channel(cl_hw, calib_channels_5g[i], CHNL_BW_80);
+ _cl_calib_set_channel(cl_hw, calib_channels_5g[i], CHNL_BW_20);
+ }
+}
+
+static void cl_calib_channels_24g(struct cl_hw *cl_hw)
+{
+ int i;
+
+ for (i = 0; i < CALIB_CHAN_24G_MAX; i++) {
+ _cl_calib_set_channel(cl_hw, calib_channels_24g[i], CHNL_BW_40);
+ _cl_calib_set_channel(cl_hw, calib_channels_24g[i], CHNL_BW_20);
+ }
+}
+
+static void cl_calib_scan_all_channels(struct cl_hw *cl_hw)
+{
+ if (cl_band_is_6g(cl_hw))
+ cl_calib_channels_6g(cl_hw);
+ else if (cl_band_is_5g(cl_hw))
+ cl_calib_channels_5g(cl_hw);
+ else
+ cl_calib_channels_24g(cl_hw);
+}
+
+static void cl_calib_restore_channel(struct cl_hw *cl_hw, struct cl_calib_restore *calib_restore)
+{
+ u8 bw = calib_restore->bw;
+ u32 primary = calib_restore->primary;
+ u32 center = calib_restore->center;
+ u8 channel = calib_restore->channel;
+
+ cl_msg_tx_set_channel(cl_hw, channel, bw, primary, center);
+}
+
+static void cl_calib_print_errors(struct cl_hw *cl_hw)
+{
+ struct cl_calib_errors *errors = &cl_hw->chip->calib_db.errors[cl_hw->tcv_idx];
+
+ if (!errors->dcoc && !errors->lolc && !errors->iq_rx && !errors->iq_tx)
+ return;
+
+ pr_warn("Calibration errors: DCOC %u, LOLC %u, IQ RX %u, IQ TX %u\n",
+ errors->dcoc, errors->lolc, errors->iq_rx, errors->iq_tx);
+}
+
+static u8 cl_calib_channel_to_idx(struct cl_hw *cl_hw, u8 channel)
+{
+ u8 i = 0;
+
+ if (cl_band_is_6g(cl_hw)) {
+ for (i = 0; i < CALIB_CHAN_6G_MAX; i++)
+ if (calib_channels_6g[i] == channel)
+ return i;
+ } else if (cl_band_is_5g(cl_hw)) {
+ for (i = 0; i < CALIB_CHAN_5G_MAX; i++)
+ if (calib_channels_5g[i] == channel)
+ return i;
+ } else {
+ for (i = 0; i < CALIB_CHAN_24G_MAX; i++)
+ if (calib_channels_24g[i] == channel)
+ return i;
+ }
+
+ return 0;
+}
+
+static void cl_calib_check_err_dcoc(struct cl_hw *cl_hw, s16 calib_temperature,
+ int channel, u8 bw)
+{
+ struct cl_chip *chip = cl_hw->chip;
+ int lna, ant;
+ struct cl_dcoc_report *dcoc_calib_report_dma;
+ u8 dcoc_threshold = chip->conf->ci_dcoc_mv_thr[bw];
+ s16 i, q;
+
+ for (lna = 0; lna < DCOC_LNA_GAIN_NUM; lna++) {
+ ant_for_each(ant) {
+ dcoc_calib_report_dma =
+ &cl_hw->iq_dcoc_data_info.iq_dcoc_data->report.dcoc[lna][ant];
+ i = (s16)le16_to_cpu(dcoc_calib_report_dma->i_dc);
+ q = (s16)le16_to_cpu(dcoc_calib_report_dma->q_dc);
+
+ if (abs(i) > dcoc_threshold) {
+ chip->calib_db.errors[cl_hw->tcv_idx].dcoc++;
+ cl_dbg_info(cl_hw,
+ "DCOC Error: lna = %u, ant = %u, "
+ "i (|%d|) > threshold (%d)\n",
+ lna, ant, i, dcoc_threshold);
+ } else {
+ cl_dbg_info(cl_hw,
+ "DCOC Valid: lna = %u, ant = %u, "
+ "i (|%d|) < threshold (%d)\n",
+ lna, ant, i, dcoc_threshold);
+ }
+
+ if (abs(q) > dcoc_threshold) {
+ chip->calib_db.errors[cl_hw->tcv_idx].dcoc++;
+ cl_dbg_info(cl_hw,
+ "DCOC Error: lna = %u, ant = %u, "
+ "q (|%d|) > threshold (%d)\n",
+ lna, ant, q, dcoc_threshold);
+ } else {
+ cl_dbg_info(cl_hw,
+ "DCOC Valid: lna = %u, ant = %u, "
+ "q (|%d|) < threshold (%d)\n",
+ lna, ant, q, dcoc_threshold);
+ }
+ }
+ }
+}
+
+static void cl_calib_check_err_iq_lolc(struct cl_hw *cl_hw, s16 calib_temperature,
+ int channel, u8 bw, u8 plan_bitmap)
+{
+ struct cl_chip *chip = cl_hw->chip;
+ struct cl_iq_dcoc_report *report = &cl_hw->iq_dcoc_data_info.iq_dcoc_data->report;
+ int ant;
+ struct cl_lolc_report lolc_report_dma;
+ s16 lolc_threshold = chip->conf->ci_lolc_db_thr;
+ s32 lolc_qual = 0;
+
+ ant_for_each(ant) {
+ if ((plan_bitmap & (1 << ant)) == 0)
+ continue;
+
+ lolc_report_dma = report->lolc_report[ant];
+ lolc_qual = (s16)le16_to_cpu(lolc_report_dma.lolc_qual) >> 8;
+
+ if (lolc_qual > lolc_threshold) {
+ chip->calib_db.errors[cl_hw->tcv_idx].lolc++;
+
+ cl_dbg_info(cl_hw,
+ "LOLC Error: ant = %u, n_iter = %u, "
+ "quality (%d) > threshold (%d)\n",
+ ant, lolc_report_dma.n_iter, lolc_qual, lolc_threshold);
+ } else {
+ cl_dbg_info(cl_hw,
+ "LOLC Valid: ant = %u, n_iter = %u, "
+ "quality (%d) < threshold (%d)\n",
+ ant, lolc_report_dma.n_iter, lolc_qual, lolc_threshold);
+ }
+ }
+}
+
+static void cl_calib_check_err_iq(struct cl_hw *cl_hw, s16 calib_temperature,
+ u8 ch, u8 bw, u8 plan_bitmap)
+{
+ struct cl_chip *chip = cl_hw->chip;
+ u8 tcv_idx = cl_hw->tcv_idx;
+ u8 ant = 0;
+ struct cl_iq_report iq_report_dma;
+ s8 iq_threshold = cl_hw->chip->conf->ci_iq_db_thr;
+
+ ant_for_each(ant) {
+ if ((plan_bitmap & (1 << ant)) == 0)
+ continue;
+
+ iq_report_dma = cl_hw->iq_dcoc_data_info.iq_dcoc_data->report.iq_tx[ant];
+
+ if (iq_report_dma.ir_db_avg_post > iq_threshold) {
+ chip->calib_db.errors[tcv_idx].iq_tx++;
+ cl_dbg_info(cl_hw, "IQ TX Error: ant = %u, ir (%d) > threshold (%d)\n",
+ ant, iq_report_dma.ir_db_avg_post, iq_threshold);
+ } else {
+ cl_dbg_info(cl_hw, "IQ TX Valid: ant = %u, ir (%d) < threshold (%d)\n",
+ ant, iq_report_dma.ir_db_avg_post, iq_threshold);
+ }
+
+ iq_report_dma = cl_hw->iq_dcoc_data_info.iq_dcoc_data->report.iq_rx[ant];
+
+ if (iq_report_dma.ir_db_avg_post > iq_threshold) {
+ chip->calib_db.errors[tcv_idx].iq_rx++;
+ cl_dbg_info(cl_hw, "IQ RX Error: ant = %u, ir (%d) > threshold (%d)\n",
+ ant, iq_report_dma.ir_db_avg_post, iq_threshold);
+ } else {
+ cl_dbg_info(cl_hw, "IQ RX Valid: ant = %u, ir (%d) < threshold (%d)\n",
+ ant, iq_report_dma.ir_db_avg_post, iq_threshold);
+ }
+ }
+}
+
+static u8 cl_calib_center_freq_to_idx(struct cl_hw *cl_hw, u32 center_freq)
+{
+ u8 i = 0;
+ u8 center_channel = ieee80211_frequency_to_channel(center_freq);
+
+ if (cl_band_is_6g(cl_hw)) {
+ for (i = 1; i < CALIB_CHAN_6G_MAX; i++)
+ if (calib_channels_6g[i] > center_channel)
+ return (i - 1);
+
+ return (CALIB_CHAN_6G_MAX - 1);
+ }
+
+ if (cl_band_is_5g(cl_hw)) {
+ for (i = 1; i < CALIB_CHAN_5G_MAX; i++)
+ if (calib_channels_5g[i] > center_channel)
+ return (i - 1);
+
+ return (CALIB_CHAN_5G_MAX - 1);
+ }
+
+ for (i = 0; i < CALIB_CHAN_24G_MAX; i++)
+ if (abs(calib_channels_24g[i] - center_channel) < 3)
+ return i;
+
+ return (CALIB_CHAN_24G_MAX - 1);
+}
+
+static void cl_calib_fill_data_dcoc(struct cl_hw *cl_hw, struct cl_iq_dcoc_info *iq_dcoc_db)
+{
+ struct cl_chip *chip = cl_hw->chip;
+ u8 lna = 0, ant = 0;
+ u8 channel_idx = cl_calib_center_freq_to_idx(cl_hw, cl_hw->center_freq);
+ u8 bw = cl_hw->bw;
+ u8 tcv_idx = cl_hw->tcv_idx;
+ u8 sx = tcv_idx;
+
+ for (lna = 0; lna < DCOC_LNA_GAIN_NUM; lna++)
+ ant_for_each(ant)
+ iq_dcoc_db->dcoc[lna][ant] =
+ chip->calib_db.dcoc[tcv_idx][channel_idx][bw][sx][ant][lna];
+}
+
+static void cl_calib_fill_data_iq(struct cl_hw *cl_hw, struct cl_iq_calib *iq_data,
+ struct cl_iq_calib *iq_chip_data)
+{
+ u8 ant = 0;
+
+ ant_for_each(ant) {
+ iq_data[ant].coef0 = cpu_to_le32(iq_chip_data[ant].coef0);
+ iq_data[ant].coef1 = cpu_to_le32(iq_chip_data[ant].coef1);
+ iq_data[ant].coef2 = cpu_to_le32(iq_chip_data[ant].coef2);
+ iq_data[ant].gain = cpu_to_le32(iq_chip_data[ant].gain);
+ }
+}
+
+static void cl_calib_fill_data_iq_lolc(struct cl_hw *cl_hw, __le32 *iq_lolc)
+{
+ struct cl_calib_db *calib_db = &cl_hw->chip->calib_db;
+ u8 ant = 0;
+ u8 chan_idx = cl_calib_center_freq_to_idx(cl_hw, cl_hw->center_freq);
+ u8 bw = cl_hw->bw;
+ u8 tcv_idx = cl_hw->tcv_idx;
+ u8 sx = tcv_idx;
+
+ ant_for_each(ant)
+ iq_lolc[ant] = cpu_to_le32(calib_db->iq_tx_lolc[tcv_idx][chan_idx][bw][sx][ant]);
+}
+
+static void cl_calib_handle_cfm_dcoc(struct cl_hw *cl_hw)
+{
+ struct cl_chip *chip = cl_hw->chip;
+ struct cl_dcoc_calib *dcoc_calib;
+ struct cl_dcoc_calib *dcoc_calib_dma;
+ struct calib_cfm *dcoc_iq_cfm =
+ &cl_hw->iq_dcoc_data_info.iq_dcoc_data->dcoc_iq_cfm[CALIB_CFM_DCOC];
+ int lna, ant;
+ u16 raw_bits = (le16_to_cpu(dcoc_iq_cfm->raw_bits_data_0) +
+ le16_to_cpu(dcoc_iq_cfm->raw_bits_data_1)) / 2;
+ s16 calib_temperature = cl_temperature_calib_calc(cl_hw, raw_bits);
+ u8 tcv_idx = cl_hw->tcv_idx;
+ u8 sx = tcv_idx;
+ u8 channel = cl_hw->channel;
+ u8 bw = cl_hw->bw;
+ u8 channel_idx = cl_calib_channel_to_idx(cl_hw, channel);
+
+ for (lna = 0; lna < DCOC_LNA_GAIN_NUM; lna++) {
+ ant_for_each(ant) {
+ dcoc_calib = &chip->calib_db.dcoc[tcv_idx][channel_idx][bw][sx][ant][lna];
+ dcoc_calib_dma =
+ &cl_hw->iq_dcoc_data_info.iq_dcoc_data->iq_dcoc_db.dcoc[lna][ant];
+ dcoc_calib->i = dcoc_calib_dma->i;
+ dcoc_calib->q = dcoc_calib_dma->q;
+ }
+ }
+
+ cl_calib_check_err_dcoc(cl_hw, calib_temperature, channel, bw);
+
+ /*
+ * Set the default status to FAIL, to ensure FW is actually changing the value,
+ * if the calibration succeeded.
+ */
+ cl_hw->iq_dcoc_data_info.iq_dcoc_data->dcoc_iq_cfm[CALIB_CFM_DCOC].status = CALIB_FAIL;
+}
+
+static void cl_calib_handle_cfm_iq(struct cl_hw *cl_hw, u8 plan_bitmap)
+{
+ struct calib_cfm *dcoc_iq_cfm =
+ &cl_hw->iq_dcoc_data_info.iq_dcoc_data->dcoc_iq_cfm[CALIB_CFM_IQ];
+ u16 raw_bits_data_0 = le16_to_cpu(dcoc_iq_cfm->raw_bits_data_0);
+ u16 raw_bits_data_1 = le16_to_cpu(dcoc_iq_cfm->raw_bits_data_1);
+ u16 raw_bits = (raw_bits_data_0 + raw_bits_data_1) / 2;
+ s16 calib_temperature = cl_temperature_calib_calc(cl_hw, raw_bits);
+ u8 channel = cl_hw->channel;
+ u8 bw = cl_hw->bw;
+ int ant;
+ u8 tcv_idx = cl_hw->tcv_idx;
+ u8 sx = tcv_idx;
+ u8 channel_idx = cl_calib_channel_to_idx(cl_hw, channel);
+
+ ant_for_each(ant) {
+ if ((plan_bitmap & (1 << ant)) == 0)
+ continue;
+
+ cl_hw->chip->calib_db.iq_tx[tcv_idx][channel_idx][bw][sx][ant] =
+ cl_hw->iq_dcoc_data_info.iq_dcoc_data->iq_dcoc_db.iq_tx[ant];
+
+ cl_hw->chip->calib_db.iq_rx[tcv_idx][channel_idx][bw][sx][ant] =
+ cl_hw->iq_dcoc_data_info.iq_dcoc_data->iq_dcoc_db.iq_rx[ant];
+ }
+
+ cl_calib_check_err_iq(cl_hw, calib_temperature, channel, bw, plan_bitmap);
+
+ /*
+ * Set the default status to FAIL, to ensure FW is actually changing the value,
+ * if the calibration succeeded.
+ */
+ dcoc_iq_cfm->status = CALIB_FAIL;
+}
+
+static void cl_calib_handle_cfm_iq_lolc(struct cl_hw *cl_hw, u8 plan_bitmap)
+{
+ struct calib_cfm *dcoc_iq_cfm =
+ &cl_hw->iq_dcoc_data_info.iq_dcoc_data->dcoc_iq_cfm[CALIB_CFM_IQ];
+ u16 raw_bits = (le16_to_cpu(dcoc_iq_cfm->raw_bits_data_0) +
+ le16_to_cpu(dcoc_iq_cfm->raw_bits_data_1)) / 2;
+ s16 calib_temperature = cl_temperature_calib_calc(cl_hw, raw_bits);
+ u8 channel = cl_hw->channel;
+ u8 channel_idx = cl_calib_channel_to_idx(cl_hw, channel);
+ u8 bw = cl_hw->bw;
+ u8 sx = cl_hw->tcv_idx;
+ int ant;
+
+ ant_for_each(ant) {
+ if ((plan_bitmap & (1 << ant)) == 0)
+ continue;
+
+ cl_hw->chip->calib_db.iq_tx_lolc[cl_hw->tcv_idx][channel_idx][bw][sx][ant] =
+ cl_hw->iq_dcoc_data_info.iq_dcoc_data->iq_dcoc_db.iq_tx_lolc[ant];
+ }
+
+ cl_calib_check_err_iq_lolc(cl_hw, calib_temperature, channel, bw, plan_bitmap);
+
+ /*
+ * Set the default status to FAIL, to ensure FW is actually changing the value,
+ * if the calibration succeeded.
+ */
+ dcoc_iq_cfm->status = CALIB_FAIL;
+}
+
+static void cl_calib_set_channel_start_work(struct work_struct *ws)
+{
+ struct cl_calib_work *calib_work = container_of(ws, struct cl_calib_work, ws);
+ struct cl_hw *cl_hw = calib_work->cl_hw;
+ struct cl_hw *cl_hw_other = cl_hw_other_tcv(cl_hw);
+ struct cl_chip *chip = cl_hw->chip;
+
+ cl_calib_start(cl_hw);
+
+ if (cl_chip_is_both_enabled(chip))
+ cl_calib_start(cl_hw_other);
+
+ chip->calib_db.scan_complete = true;
+}
+
+int cl_calib_start(struct cl_hw *cl_hw)
+{
+ u8 channel = cl_hw->conf->ha_channel;
+ u8 bw = cl_hw->conf->ce_channel_bandwidth;
+ enum nl80211_chan_width width = NL80211_CHAN_WIDTH_20;
+ u32 primary = 0;
+ u32 center = 0;
+
+ if (cl_chandef_calc(cl_hw, channel, bw, &width, &primary, &center))
+ return -EINVAL;
+
+ return cl_calib_set_channel(cl_hw, channel, bw, primary, center);
+}
+
+void cl_calib_fill_phy_data(struct cl_hw *cl_hw, struct cl_iq_dcoc_info *iq_dcoc_db, u8 flags)
+{
+ struct cl_chip *chip = cl_hw->chip;
+ u8 channel_idx = cl_calib_center_freq_to_idx(cl_hw, cl_hw->center_freq);
+ u8 bw = cl_hw->bw;
+ u8 tcv_idx = cl_hw->tcv_idx;
+
+ if (flags & SET_PHY_DATA_FLAGS_DCOC)
+ cl_calib_fill_data_dcoc(cl_hw, iq_dcoc_db);
+
+ if (flags & SET_PHY_DATA_FLAGS_IQ_TX_LOLC)
+ cl_calib_fill_data_iq_lolc(cl_hw, iq_dcoc_db->iq_tx_lolc);
+
+ if (flags & SET_PHY_DATA_FLAGS_IQ_TX)
+ cl_calib_fill_data_iq(cl_hw, iq_dcoc_db->iq_tx,
+ chip->calib_db.iq_tx[tcv_idx][channel_idx][bw][tcv_idx]);
+
+ if (flags & SET_PHY_DATA_FLAGS_IQ_RX)
+ cl_calib_fill_data_iq(cl_hw, iq_dcoc_db->iq_rx,
+ chip->calib_db.iq_rx[tcv_idx][channel_idx][bw][tcv_idx]);
+}
+
+int cl_calib_tables_alloc(struct cl_hw *cl_hw)
+{
+ struct cl_iq_dcoc_data *buf = NULL;
+ u32 len = sizeof(struct cl_iq_dcoc_data);
+ dma_addr_t phys_dma_addr;
+
+ buf = dma_alloc_coherent(cl_hw->chip->dev, len, &phys_dma_addr, GFP_KERNEL);
+
+ if (!buf)
+ return -1;
+
+ cl_hw->iq_dcoc_data_info.iq_dcoc_data = buf;
+ cl_hw->iq_dcoc_data_info.dma_addr = cpu_to_le32(phys_dma_addr);
+
+ cl_calib_init_cfm(cl_hw->iq_dcoc_data_info.iq_dcoc_data);
+
+ return 0;
+}
+
+void cl_calib_tables_free(struct cl_hw *cl_hw)
+{
+ struct cl_iq_dcoc_data_info *iq_dcoc_data_info = &cl_hw->iq_dcoc_data_info;
+ u32 len = sizeof(struct cl_iq_dcoc_data);
+ dma_addr_t phys_dma_addr = le32_to_cpu(iq_dcoc_data_info->dma_addr);
+
+ if (!iq_dcoc_data_info->iq_dcoc_data)
+ return;
+
+ dma_free_coherent(cl_hw->chip->dev, len, (void *)iq_dcoc_data_info->iq_dcoc_data,
+ phys_dma_addr);
+ iq_dcoc_data_info->iq_dcoc_data = NULL;
+}
+
+bool cl_calib_is_needed(struct cl_hw *cl_hw, u8 channel, u8 bw)
+{
+ u8 channel_idx;
+ u8 tcv_idx = cl_hw->tcv_idx;
+ u8 ant;
+ u32 primary = 0;
+ u32 center_freq = 0;
+ enum nl80211_chan_width width = NL80211_CHAN_WIDTH_20;
+
+ if (cl_chandef_calc(cl_hw, channel, bw, &width, &primary, &center_freq)) {
+ cl_dbg_err(cl_hw, "cl_chandef_calc failed\n");
+ return false;
+ }
+
+ channel_idx = cl_calib_center_freq_to_idx(cl_hw, center_freq);
+
+ /* Check if we already calibrated */
+ ant_for_each(ant) {
+ if (cl_hw->chip->calib_db.iq_tx_lolc[tcv_idx][channel_idx][bw][tcv_idx][ant])
+ return false;
+ }
+
+ return true;
+}
+
+int cl_calib_set_channel(struct cl_hw *cl_hw, u8 channel, u8 bw, u32 primary, u32 center)
+{
+ struct cl_chip *chip = cl_hw->chip;
+ struct cl_hw *cl_hw_other = cl_hw_other_tcv(cl_hw);
+ struct cl_calib_restore calib_restore;
+ int ret = 0;
+ u8 fem_mode = cl_hw->fem_system_mode;
+ bool save_ch_other = !!cl_hw_other->primary_freq;
+
+ if (save_ch_other)
+ cl_calib_save_channel(cl_hw_other, &calib_restore);
+
+ ret = cl_calib_set_idle(cl_hw, true);
+ if (ret)
+ return ret;
+
+ cl_fem_set_system_mode(cl_hw, FEM_MODE_LNA_BYPASS_ONLY, U8_MAX);
+ cl_afe_cfg_calib(chip);
+
+ if (chip->conf->ce_calib_scan_en && !chip->calib_db.scan_complete && cl_hw->calib_ready)
+ cl_calib_scan_all_channels(cl_hw);
+ else
+ _cl_calib_set_channel(cl_hw, channel, bw);
+
+ cl_fem_set_system_mode(cl_hw, fem_mode, U8_MAX);
+ cl_afe_cfg_restore(chip);
+
+ _cl_msg_tx_set_channel(cl_hw, channel, bw, primary, center, SET_CHANNEL_MODE_OPERETIONAL);
+
+ if (save_ch_other)
+ cl_calib_restore_channel(cl_hw_other, &calib_restore);
+
+ cl_calib_set_idle(cl_hw, false);
+
+ return ret;
+}
+
+void cl_calib_start_work(struct cl_hw *cl_hw)
+{
+ struct cl_calib_work *calib_work = kzalloc(sizeof(*calib_work), GFP_ATOMIC);
+
+ if (!calib_work)
+ return;
+
+ calib_work->cl_hw = cl_hw;
+ INIT_WORK(&calib_work->ws, cl_calib_set_channel_start_work);
+ queue_work(cl_hw->drv_workqueue, &calib_work->ws);
+}
+
+int cl_calib_handle_cfm(struct cl_hw *cl_hw, u8 mode)
+{
+ struct cl_iq_dcoc_data *iq_dcoc_data = cl_hw->iq_dcoc_data_info.iq_dcoc_data;
+ struct cl_calib_errors *errors = &cl_hw->chip->calib_db.errors[cl_hw->tcv_idx];
+
+ /*
+ * In case any of the requested calibrations failed - no need to copy
+ * the other Calibration data, and fail the whole calibration process.
+ */
+ if ((mode & SET_CHANNEL_MODE_CALIB_DCOC &&
+ iq_dcoc_data->dcoc_iq_cfm[CALIB_CFM_DCOC].status != CALIB_SUCCESS) ||
+ (mode & SET_CHANNEL_MODE_CALIB_IQ &&
+ iq_dcoc_data->dcoc_iq_cfm[CALIB_CFM_IQ].status != CALIB_SUCCESS)) {
+ cl_dbg_err(cl_hw, "Calibration failed! mode = %u, DCOC_CFM_STATUS = %u, "
+ "IQ_CFM_STATUS = %u\n",
+ mode,
+ iq_dcoc_data->dcoc_iq_cfm[CALIB_CFM_DCOC].status,
+ iq_dcoc_data->dcoc_iq_cfm[CALIB_CFM_IQ].status);
+ /* Set status to CALIB_FAIL to ensure that FW is writing the values. */
+ iq_dcoc_data->dcoc_iq_cfm[CALIB_CFM_DCOC].status = CALIB_FAIL;
+ iq_dcoc_data->dcoc_iq_cfm[CALIB_CFM_IQ].status = CALIB_FAIL;
+ return -1;
+ }
+
+ if (mode & SET_CHANNEL_MODE_CALIB_DCOC)
+ cl_calib_handle_cfm_dcoc(cl_hw);
+
+ if (mode & SET_CHANNEL_MODE_CALIB_IQ)
+ cl_calib_handle_cfm_iq(cl_hw, cl_hw->mask_num_antennas);
+
+ if (mode & SET_CHANNEL_MODE_CALIB_LOLC)
+ cl_calib_handle_cfm_iq_lolc(cl_hw, cl_hw->mask_num_antennas);
+
+ /* Print calibration errors counters */
+ cl_calib_print_errors(cl_hw);
+
+ memset(errors, 0, sizeof(*errors));
+
+ return 0;
+}
+
+int cl_calib_validate_ants(struct cl_hw *cl_hw)
+{
+ struct cl_tcv_conf *conf = cl_hw->conf;
+ u8 ant = 0;
+ int ret = 0;
+
+ for (ant = 0; ant < cl_hw->num_antennas; ant++) {
+ if (conf->ci_calib_ant_tx[ant] < cl_hw->first_ant ||
+ conf->ci_calib_ant_tx[ant] > cl_hw->last_ant) {
+ CL_DBG_ERROR(cl_hw,
+ "TX: Antenna [%u] value is out of boundaries [%u].\n"
+ "Minimum value allowed is: %u\n"
+ "Maximum value allowed is: %u\n",
+ ant, conf->ci_calib_ant_tx[ant], cl_hw->first_ant,
+ cl_hw->last_ant);
+ ret = -1;
+ }
+
+ if (conf->ci_calib_ant_rx[ant] < cl_hw->first_ant ||
+ conf->ci_calib_ant_rx[ant] > cl_hw->last_ant) {
+ CL_DBG_ERROR(cl_hw,
+ "RX: Antenna [%u] value is out of boundaries [%u]."
+ "Minimum value allowed is: %u\n"
+ "Maximum value allowed is: %u\n",
+ ant, conf->ci_calib_ant_tx[ant], cl_hw->first_ant,
+ cl_hw->last_ant);
+ ret = -1;
+ }
+ }
+
+ return ret;
+}
+
+void cl_calib_iq_get_tone_vector(u8 bw, u16 *tone_vector)
+{
+ u8 tone = 0;
+
+ for (tone = 0; tone < IQ_NUM_TONES_REQ; tone++)
+ tone_vector[tone] = cpu_to_le16((u16)tone_vector_arr[bw][tone]);
+}
+
+static int cl_calib_print_dcoc(struct cl_hw *cl_hw)
+{
+ struct cl_calib_db *calib_db = &cl_hw->chip->calib_db;
+ struct cl_dcoc_calib *dcoc_calib;
+ u8 lna = 0;
+ u8 ant = 0;
+ u8 channel_idx = cl_calib_center_freq_to_idx(cl_hw, cl_hw->center_freq);
+ u8 tcv_idx = cl_hw->tcv_idx;
+ u8 sx = tcv_idx;
+ u8 bw = cl_hw->bw;
+ char *buf = kzalloc(PAGE_SIZE, GFP_KERNEL);
+ int err = 0;
+ int len = 0;
+
+ if (!buf)
+ return -ENOMEM;
+
+ len += snprintf(buf + len, PAGE_SIZE - len,
+ "DCOC:\n"
+ "LNA GAIN ANTENNA I Q\n"
+ "----------------------------\n");
+
+ for (lna = 0; lna < DCOC_LNA_GAIN_NUM; lna++) {
+ ant_for_each(ant) {
+ dcoc_calib =
+ &calib_db->dcoc[tcv_idx][channel_idx][bw][sx][ant][lna];
+
+ len += snprintf(buf + len, PAGE_SIZE - len,
+ "%-11u%-10u%-5d%-5d\n", lna,
+ ant, dcoc_calib->i, dcoc_calib->q);
+ }
+ }
+
+ err = cl_vendor_reply(cl_hw, buf, strlen(buf));
+ kfree(buf);
+
+ return err;
+}
+
+static int cl_calib_print_lolc(struct cl_hw *cl_hw)
+{
+ struct cl_calib_db *calib_db = &cl_hw->chip->calib_db;
+ u32 lolc_calib;
+ u8 ant = 0;
+ u8 channel_idx = cl_calib_center_freq_to_idx(cl_hw, cl_hw->center_freq);
+ u8 tcv_idx = cl_hw->tcv_idx;
+ u8 sx = tcv_idx;
+ u8 bw = cl_hw->bw;
+ char *buf = kzalloc(PAGE_SIZE, GFP_KERNEL);
+ int err = 0;
+ int len = 0;
+
+ if (!buf)
+ return -ENOMEM;
+
+ len += snprintf(buf + len, PAGE_SIZE - len,
+ "LOLC:\n"
+ "ANTENNA I Q\n"
+ "---------------------\n");
+
+ ant_for_each(ant) {
+ lolc_calib = calib_db->iq_tx_lolc[tcv_idx][channel_idx][bw][sx][ant];
+
+ len += snprintf(buf + len, PAGE_SIZE - len,
+ "%-10u%-6d%-6d\n",
+ ant, CAST_S12_TO_S32(lolc_calib & U12_BIT_MASK),
+ CAST_S12_TO_S32((lolc_calib >> 2) & U12_BIT_MASK));
+ }
+
+ err = cl_vendor_reply(cl_hw, buf, strlen(buf));
+ kfree(buf);
+
+ return err;
+}
+
+static int cl_calib_print_iq(struct cl_hw *cl_hw)
+{
+ struct cl_calib_db *calib_db = &cl_hw->chip->calib_db;
+ struct cl_iq_calib *iq;
+ u8 ant = 0;
+ u8 channel_idx = cl_calib_center_freq_to_idx(cl_hw, cl_hw->center_freq);
+ u8 tcv_idx = cl_hw->tcv_idx;
+ u8 sx = tcv_idx;
+ u8 bw = cl_hw->bw;
+ char *buf = kzalloc(PAGE_SIZE, GFP_KERNEL);
+ int err = 0;
+ int len = 0;
+
+ if (!buf)
+ return -ENOMEM;
+
+ len += snprintf(buf + len, PAGE_SIZE - len,
+ "IQ TX:\n"
+ "ANTENNA COEF0 COEF1 COEF2 GAIN\n"
+ "---------------------------------------------------\n");
+
+ ant_for_each(ant) {
+ iq = &calib_db->iq_tx[tcv_idx][channel_idx][bw][sx][ant];
+
+ len += snprintf(buf + len, PAGE_SIZE - len,
+ "%-7u 0x%08x 0x%08x 0x%08x 0x%08x\n",
+ ant, iq->coef0, iq->coef1, iq->coef2, iq->gain);
+ }
+
+ len += snprintf(buf + len, PAGE_SIZE - len,
+ "IQ RX:\n"
+ "ANTENNA COEF0 COEF1 COEF2 GAIN\n"
+ "---------------------------------------------------\n");
+
+ ant_for_each(ant) {
+ iq = &calib_db->iq_rx[tcv_idx][channel_idx][bw][sx][ant];
+
+ len += snprintf(buf + len, PAGE_SIZE - len,
+ "%-7u 0x%08x 0x%08x 0x%08x 0x%08x\n",
+ ant, iq->coef0, iq->coef1, iq->coef2, iq->gain);
+ }
+ err = cl_vendor_reply(cl_hw, buf, strlen(buf));
+ kfree(buf);
+
+ return err;
+}
+
+static int cl_calib_common_cli_help(struct cl_hw *cl_hw)
+{
+ char *buf = kzalloc(PAGE_SIZE, GFP_KERNEL);
+ int err = 0;
+
+ if (!buf)
+ return -ENOMEM;
+
+ snprintf(buf, PAGE_SIZE,
+ "calib usage:\n"
+ "-d : Print DCOC coefficients\n"
+ "-i : Print IQ coefficients\n"
+ "-l : Print LOLC coefficients\n");
+
+ err = cl_vendor_reply(cl_hw, buf, strlen(buf));
+ kfree(buf);
+
+ return err;
+}
+
+int cl_calib_cli(struct cl_hw *cl_hw, struct cli_params *cli_params)
+{
+ switch (cli_params->option) {
+ case 'd':
+ return cl_calib_print_dcoc(cl_hw);
+ case 'i':
+ return cl_calib_print_iq(cl_hw);
+ case 'l':
+ return cl_calib_print_lolc(cl_hw);
+ case '?':
+ return cl_calib_common_cli_help(cl_hw);
+ default:
+ cl_dbg_err(cl_hw, "Illegal option (%c) - try '?' for help\n",
+ cli_params->option);
+ return 0;
+ }
+}
--
2.30.0

________________________________
The information transmitted is intended only for the person or entity to which it is addressed and may contain confidential and/or privileged material. Any retransmission, dissemination, copying or other use of, or taking of any action in reliance upon this information is prohibited. If you received this in error, please contact the sender and delete the material from any computer. Nothing contained herein shall be deemed as a representation, warranty or a commitment by Celeno. No warranties are expressed or implied, including, but not limited to, any implied warranties of non-infringement, merchantability and fitness for a particular purpose.
________________________________

2021-06-17 16:23:23

by viktor.barna

[permalink] [raw]
Subject: [RFC v1 011/256] cl8k: add ate.c

From: Viktor Barna <[email protected]>

(Part of the split. Please, take a look at the cover letter for more
details).

Signed-off-by: Viktor Barna <[email protected]>
---
drivers/net/wireless/celeno/cl8k/ate.c | 841 +++++++++++++++++++++++++
1 file changed, 841 insertions(+)
create mode 100644 drivers/net/wireless/celeno/cl8k/ate.c

diff --git a/drivers/net/wireless/celeno/cl8k/ate.c b/drivers/net/wireless/celeno/cl8k/ate.c
new file mode 100644
index 000000000000..95e4e73cd9c0
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/ate.c
@@ -0,0 +1,841 @@
+// SPDX-License-Identifier: MIT
+/* Copyright(c) 2019-2021, Celeno Communications Ltd. */
+
+#include "ate.h"
+#include "tx/tx_inject.h"
+#include "calib.h"
+#include "rate_ctrl.h"
+#include "fw/msg_tx.h"
+#include "mib.h"
+#include "edca.h"
+#include "reg/reg_mac_hw.h"
+#include "reg/reg_macdsp_api.h"
+#include "reg/reg_riu.h"
+#include "tx/tx_queue.h"
+#include "utils/utils.h"
+#include "band.h"
+#include "fem.h"
+#include "chandef.h"
+#include "mac_addr.h"
+#include "power.h"
+#include "e2p.h"
+
+#define DIFF(_diff, _new, _old, _member)\
+ ((_diff)._member = (_new)._member - (_old)._member)
+
+/* Max freq delta is 100MHz in Q2 */
+#define MAX_FREQ_DELTA (100 << 2)
+
+static void set_fixed_rate(struct cl_hw *cl_hw)
+{
+ struct cl_ate_db *ate_db = &cl_hw->ate_db;
+ union cl_rate_ctrl_info_he rate_ctrl_he = {.word = 0};
+ u8 ltf = 0;
+
+ if (ate_db->mode == WRS_MODE_HE) {
+ rate_ctrl_he.field.spatial_conf = RATE_CNTRL_HE_SPATIAL_CONF_DEF;
+
+ if (ate_db->ltf == LTF_MAX)
+ ltf = cl_map_gi_to_ltf(WRS_MODE_HE, ate_db->gi);
+ else
+ ltf = ate_db->ltf;
+ }
+
+ cl_hw->entry_fixed_rate = true;
+
+ cl_rate_ctrl_set_fixed(cl_hw, rate_ctrl_he.word, ate_db->mode, ate_db->mcs,
+ ate_db->nss, ate_db->bw, ate_db->gi, ltf);
+}
+
+static inline void read_stat(struct cl_hw *cl_hw, struct ate_stats *stats)
+{
+ stats->tx_bw20 = cl_mib_cntr_read(cl_hw, MIB_DOT11_20MHZ_FRAME_TRANSMITTED_COUNT);
+ stats->tx_bw40 = cl_mib_cntr_read(cl_hw, MIB_DOT11_40MHZ_FRAME_TRANSMITTED_COUNT);
+ stats->tx_bw80 = cl_mib_cntr_read(cl_hw, MIB_DOT11_80MHZ_FRAME_TRANSMITTED_COUNT);
+ stats->tx_bw160 = cl_mib_cntr_read(cl_hw, MIB_DOT11_160MHZ_FRAME_TRANSMITTED_COUNT);
+ stats->rx_bw20 = cl_mib_cntr_read(cl_hw, MIB_DOT11_20MHZ_FRAME_RECEIVED_COUNT);
+ stats->rx_bw40 = cl_mib_cntr_read(cl_hw, MIB_DOT11_40MHZ_FRAME_RECEIVED_COUNT);
+ stats->rx_bw80 = cl_mib_cntr_read(cl_hw, MIB_DOT11_80MHZ_FRAME_RECEIVED_COUNT);
+ stats->rx_bw160 = cl_mib_cntr_read(cl_hw, MIB_DOT11_160MHZ_FRAME_RECEIVED_COUNT);
+ stats->fcs_err = cl_mib_cntr_read(cl_hw, MIB_DOT11_FCS_ERROR_COUNT);
+ stats->phy_err = cl_mib_cntr_read(cl_hw, MIB_DOT11_RX_PHY_ERROR_COUNT);
+ stats->delimiter_err = cl_mib_cntr_read(cl_hw, MIB_DOT11_AMPDU_DELIMITER_CRC_ERROR_COUNT);
+}
+
+static bool is_valid_rate_he(struct cl_hw *cl_hw, u8 bw, u8 nss, u8 mcs, u8 gi)
+{
+ u8 ltf = cl_hw->ate_db.ltf;
+
+ /* BW */
+ if (!cl_hw->conf->ce_txldpc_en) {
+ if (bw > CHNL_BW_20) {
+ u8 bw_mhz = BW_TO_MHZ(bw);
+
+ cl_dbg_err(cl_hw, "Invalid bw [%u] - must be 20 when tx ldpc disabled\n",
+ bw_mhz);
+ return false;
+ }
+ }
+
+ /* NSS */
+ if (nss >= cl_hw->conf->ce_tx_nss) {
+ cl_dbg_err(cl_hw, "Invalid nss [%u] - must be < %u\n",
+ nss, cl_hw->conf->ce_tx_nss);
+ return false;
+ }
+
+ /* MCS */
+ if (cl_hw->conf->ce_txldpc_en) {
+ if (mcs >= WRS_MCS_MAX_HE) {
+ cl_dbg_err(cl_hw, "Invalid mcs [%u] - must be 0 - 11\n", mcs);
+ return false;
+ }
+ } else {
+ if (mcs >= WRS_MCS_10) {
+ cl_dbg_err(cl_hw, "Invalid mcs [%u] - must be 0-9 when tx ldpc disabled\n",
+ mcs);
+ return false;
+ }
+ }
+
+ /* GI */
+ if (gi >= WRS_GI_MAX_HE) {
+ cl_dbg_err(cl_hw, "Invalid gi [%u] - must be 0(0.8u)/1(1.6u)/2(3.2u)\n", gi);
+ return false;
+ }
+
+ /* LTF */
+ if (ltf > LTF_MAX) {
+ cl_dbg_err(cl_hw, "Invalid ltf [%u] - must be 0(X1)/1(X2)/2(X4)\n", ltf);
+ return -EINVAL;
+ } else if (ltf < LTF_MAX) {
+ /*
+ * Supported GI/LTF combinations:
+ * GI = 3.2: LTF_X4
+ * GI = 1.6: LTF_X2
+ * GI = 0.8: LTF_X1, LTF_X2, LTF_X4
+ */
+ if (gi == WRS_GI_LONG) {
+ if (ltf != LTF_X4) {
+ cl_dbg_err(cl_hw, "ltf must be 2 (=X4) for gi=0\n");
+ return false;
+ }
+ } else if (gi == WRS_GI_SHORT) {
+ if (ltf != LTF_X2) {
+ cl_dbg_err(cl_hw, "ltf must be 1 (=X2) for gi=1\n");
+ return false;
+ }
+ }
+ }
+
+ return true;
+}
+
+static bool is_valid_rate_vht(struct cl_hw *cl_hw, u8 bw, u8 nss, u8 mcs, u8 gi)
+{
+ /* BW */
+ if (bw == CHNL_BW_160 && nss >= WRS_SS_3) {
+ cl_dbg_err(cl_hw, "bw 160 is invalid in 3/4 nss\n");
+ return false;
+ }
+
+ /* NSS */
+ if (nss >= cl_hw->conf->ce_tx_nss) {
+ cl_dbg_err(cl_hw, "Invalid nss [%u] - must be < %u\n",
+ nss, cl_hw->conf->ce_tx_nss);
+ return false;
+ }
+
+ /* MCS */
+ if (mcs >= WRS_MCS_MAX_VHT) {
+ cl_dbg_err(cl_hw, "Invalid mcs [%u] - must be 0-9\n", mcs);
+ return false;
+ }
+
+ /* GI */
+ if (gi >= WRS_GI_MAX_VHT) {
+ cl_dbg_err(cl_hw, "Invalid gi [%u] - must be 0(0.8u)/1(0.4u)\n", gi);
+ return false;
+ }
+
+ /* Make sure it is not an invalid VHT rate */
+ if (bw == CHNL_BW_20 && mcs == WRS_MCS_9)
+ if (nss == WRS_SS_1 || nss == WRS_SS_2 || nss == WRS_SS_4) {
+ cl_dbg_err(cl_hw, "nss 1/2/4 are invalid in bw 20, mcs 9\n");
+ return false;
+ }
+
+ if (bw == CHNL_BW_80 && mcs == WRS_MCS_6 && nss == WRS_SS_3) {
+ cl_dbg_err(cl_hw, "bw 80, mcs 6, nss 3 is invalid\n");
+ return false;
+ }
+
+ return true;
+}
+
+static bool is_valid_rate_ht(struct cl_hw *cl_hw, u8 bw, u8 nss, u8 mcs, u8 gi)
+{
+ /* BW */
+ if (bw > CHNL_BW_40) {
+ u8 bw_mhz = BW_TO_MHZ(bw);
+
+ cl_dbg_err(cl_hw, "Invalid bw [%u] - must be 20/40\n", bw_mhz);
+ return false;
+ }
+
+ /* NSS */
+ if (nss >= cl_hw->conf->ce_tx_nss) {
+ cl_dbg_err(cl_hw, "Invalid nss [%u] - must be < %u\n",
+ nss, cl_hw->conf->ce_tx_nss);
+ return false;
+ }
+
+ /* MCS */
+ if (mcs >= WRS_MCS_MAX_HT) {
+ cl_dbg_err(cl_hw, "Invalid mcs [%u] - must be 0 - 7\n", mcs);
+ return false;
+ }
+
+ /* GI */
+ if (gi >= WRS_GI_MAX_HT) {
+ cl_dbg_err(cl_hw, "Invalid gi [%u] - must be 0(0.8u)/1(0.4u)\n", gi);
+ return false;
+ }
+
+ return true;
+}
+
+static bool is_valid_rate_ofdm(struct cl_hw *cl_hw, u8 bw, u8 nss, u8 mcs, u8 gi)
+{
+ /*
+ * BW
+ * There is no need to check if bw is valid.
+ * It was already done in is_valid_bw_mhz().
+ * For ofdm we allow bw to be > 20, for FORMAT_NON_HT_DUP.
+ */
+
+ /* NSS */
+ if (nss != 0) {
+ cl_dbg_err(cl_hw, "Invalid nss [%u] - must be 0\n", nss);
+ return false;
+ }
+
+ /* MCS */
+ if (mcs >= WRS_MCS_MAX_OFDM) {
+ cl_dbg_err(cl_hw, "Invalid mcs [%u] - must be 0 - 7\n", mcs);
+ return false;
+ }
+
+ /* GI */
+ if (gi != 0) {
+ cl_dbg_err(cl_hw, "Invalid gi [%u] - nust be 0\n", gi);
+ return false;
+ }
+
+ return true;
+}
+
+static bool is_valid_rate_cck(struct cl_hw *cl_hw, u8 bw, u8 nss, u8 mcs, u8 gi)
+{
+ /* BW */
+ if (bw > CHNL_BW_20) {
+ u8 bw_mhz = BW_TO_MHZ(bw);
+
+ cl_dbg_err(cl_hw, "Invalid bw [%u] - must be 20\n", bw_mhz);
+ return false;
+ }
+
+ /* NSS */
+ if (nss != 0) {
+ cl_dbg_err(cl_hw, "Invalid nss [%u] - must be 0\n", nss);
+ return false;
+ }
+
+ /* MCS */
+ if (mcs >= WRS_MCS_MAX_CCK) {
+ cl_dbg_err(cl_hw, "Invalid mcs [%u] - must be 0 - 3\n", mcs);
+ return false;
+ }
+
+ /* GI */
+ if (gi != 0) {
+ cl_dbg_err(cl_hw, "Invalid gi [%u] - nust be 0\n", gi);
+ return false;
+ }
+
+ return true;
+}
+
+static bool is_valid_rate(struct cl_hw *cl_hw)
+{
+ u8 mode = cl_hw->ate_db.mode;
+ u8 bw = cl_hw->ate_db.bw;
+ u8 nss = cl_hw->ate_db.nss;
+ u8 mcs = cl_hw->ate_db.mcs;
+ u8 gi = cl_hw->ate_db.gi;
+
+ switch (mode) {
+ case WRS_MODE_HE:
+ return is_valid_rate_he(cl_hw, bw, nss, mcs, gi);
+ case WRS_MODE_VHT:
+ return is_valid_rate_vht(cl_hw, bw, nss, mcs, gi);
+ case WRS_MODE_HT:
+ return is_valid_rate_ht(cl_hw, bw, nss, mcs, gi);
+ case WRS_MODE_OFDM:
+ return is_valid_rate_ofdm(cl_hw, bw, nss, mcs, gi);
+ case WRS_MODE_CCK:
+ return is_valid_rate_cck(cl_hw, bw, nss, mcs, gi);
+ default:
+ cl_dbg_err(cl_hw,
+ "Invalid mode [%u] - must be: 0(cck)/1(ofdm)/2(ht)/3(vht)/4(he)\n",
+ mode);
+ break;
+ }
+
+ return false;
+}
+
+static bool is_valid_bw(struct cl_hw *cl_hw)
+{
+ if (cl_hw->bw < cl_hw->ate_db.bw) {
+ cl_dbg_err(cl_hw, "TX bw [%u] can't be greater than channel bw [%u]\n",
+ BW_TO_MHZ(cl_hw->ate_db.bw), BW_TO_MHZ(cl_hw->bw));
+ return false;
+ }
+
+ return true;
+}
+
+static bool is_valid_bw_mhz(struct cl_hw *cl_hw, u8 bw_mhz)
+{
+ if (BAND_IS_5G_6G(cl_hw)) {
+ if (bw_mhz != BW_TO_MHZ(CHNL_BW_20) &&
+ bw_mhz != BW_TO_MHZ(CHNL_BW_40) &&
+ bw_mhz != BW_TO_MHZ(CHNL_BW_80) &&
+ bw_mhz != BW_TO_MHZ(CHNL_BW_160)) {
+ cl_dbg_err(cl_hw,
+ "Invalid bw [%u] - must be 20/40/80/160\n", bw_mhz);
+ return false;
+ }
+ } else {
+ if (bw_mhz != BW_TO_MHZ(CHNL_BW_20) &&
+ bw_mhz != BW_TO_MHZ(CHNL_BW_40)) {
+ cl_dbg_err(cl_hw, "Invalid bw [%u] - must be 20/40\n", bw_mhz);
+ return false;
+ }
+ }
+
+ return true;
+}
+
+int cl_ate_reset(struct wiphy *wiphy, struct wireless_dev *wdev,
+ const void *data, int data_len)
+{
+ struct cl_hw *cl_hw = WIPHY_TO_CL_HW(wiphy);
+
+ if (cl_tx_inject_is_running(cl_hw)) {
+ tasklet_kill(&cl_hw->tx_inject.tasklet);
+ cl_ate_stop(wiphy, NULL, NULL, 0);
+ }
+
+ /* Reset rate parameters */
+ cl_hw->ate_db.mode = 0;
+ cl_hw->ate_db.bw = 0;
+ cl_hw->ate_db.nss = 0;
+ cl_hw->ate_db.mcs = 0;
+ cl_hw->ate_db.gi = 0;
+ cl_hw->ate_db.ltf = LTF_MAX;
+
+ cl_hw->entry_fixed_rate = false;
+
+ /* Reset TX power */
+ cl_hw->ate_db.tx_power = S8_MAX;
+ memset(cl_hw->ate_db.tx_power_offset, S8_MAX, MAX_ANTENNAS);
+
+ cl_tx_inject_reset(cl_hw);
+
+ /* Go to ACTIVE state */
+ if (cl_hw->chip->conf->ce_production_mode)
+ cl_msg_tx_set_idle(cl_hw, MAC_ACTIVE);
+
+ if (cl_hw->ate_db.ant_mask) {
+ u8 default_ant_mask = ANT_MASK(cl_hw->num_antennas);
+
+ cl_msg_tx_set_ant_bitmap(cl_hw, default_ant_mask);
+ cl_hw->ate_db.ant_mask = 0;
+ }
+
+ cl_hw->ate_db.active = true;
+
+ /*
+ * Rearm last_tbtt_irq so that error message will
+ * not be printed in cl_irq_status_tbtt()
+ */
+ cl_hw->last_tbtt_irq = jiffies;
+
+ cl_dbg_trace(cl_hw, "\n");
+
+ return 0;
+}
+
+int cl_ate_mode(struct wiphy *wiphy, struct wireless_dev *wdev,
+ const void *data, int data_len)
+{
+ struct cl_hw *cl_hw = WIPHY_TO_CL_HW(wiphy);
+
+ cl_hw->ate_db.mode = *(u8 *)data;
+
+ cl_dbg_trace(cl_hw, "mode = %u\n", cl_hw->ate_db.mode);
+
+ return 0;
+}
+
+int cl_ate_bw(struct wiphy *wiphy, struct wireless_dev *wdev,
+ const void *data, int data_len)
+{
+ struct cl_hw *cl_hw = WIPHY_TO_CL_HW(wiphy);
+ u8 bw_mhz = *(u8 *)data;
+
+ if (!is_valid_bw_mhz(cl_hw, bw_mhz))
+ return -EINVAL;
+
+ cl_hw->ate_db.bw = MHZ_TO_BW(bw_mhz);
+
+ cl_dbg_trace(cl_hw, "bw = %u\n", bw_mhz);
+
+ return 0;
+}
+
+int cl_ate_mcs(struct wiphy *wiphy, struct wireless_dev *wdev,
+ const void *data, int data_len)
+{
+ struct cl_hw *cl_hw = WIPHY_TO_CL_HW(wiphy);
+
+ cl_hw->ate_db.mcs = *(u8 *)data;
+
+ cl_dbg_trace(cl_hw, "mcs = %u\n", cl_hw->ate_db.mcs);
+
+ return 0;
+}
+
+int cl_ate_nss(struct wiphy *wiphy, struct wireless_dev *wdev,
+ const void *data, int data_len)
+{
+ struct cl_hw *cl_hw = WIPHY_TO_CL_HW(wiphy);
+
+ cl_hw->ate_db.nss = *(u8 *)data;
+
+ cl_dbg_trace(cl_hw, "nss = %u\n", cl_hw->ate_db.nss);
+
+ return 0;
+}
+
+int cl_ate_gi(struct wiphy *wiphy, struct wireless_dev *wdev,
+ const void *data, int data_len)
+{
+ struct cl_hw *cl_hw = WIPHY_TO_CL_HW(wiphy);
+
+ cl_hw->ate_db.gi = *(u8 *)data;
+ cl_dbg_trace(cl_hw, "gi = %u\n", cl_hw->ate_db.gi);
+
+ return 0;
+}
+
+int cl_ate_ltf(struct wiphy *wiphy, struct wireless_dev *wdev,
+ const void *data, int data_len)
+{
+ struct cl_hw *cl_hw = WIPHY_TO_CL_HW(wiphy);
+
+ cl_hw->ate_db.ltf = *(u8 *)data;
+
+ cl_dbg_trace(cl_hw, "ltf = %u\n", cl_hw->ate_db.ltf);
+
+ return 0;
+}
+
+int cl_ate_ldpc(struct wiphy *wiphy, struct wireless_dev *wdev,
+ const void *data, int data_len)
+{
+ struct cl_hw *cl_hw = WIPHY_TO_CL_HW(wiphy);
+
+ cl_hw->conf->ce_txldpc_en = (bool)(*(u8 *)data);
+
+ cl_dbg_trace(cl_hw, "ldpc = %u\n", cl_hw->conf->ce_txldpc_en);
+
+ return 0;
+}
+
+int cl_ate_channel(struct wiphy *wiphy, struct wireless_dev *wdev,
+ const void *data, int data_len)
+{
+ struct cl_hw *cl_hw = WIPHY_TO_CL_HW(wiphy);
+ u32 channel = ((u32 *)data)[0];
+ u32 bw_mhz = ((u32 *)data)[1];
+ u32 bw = 0;
+ u32 primary = 0;
+ u32 center = 0;
+ enum nl80211_chan_width width = NL80211_CHAN_WIDTH_20;
+
+ if (!is_valid_bw_mhz(cl_hw, bw_mhz))
+ return -EINVAL;
+
+ if (cl_band_is_6g(cl_hw) && channel == 2 &&
+ bw_mhz != BW_TO_MHZ(CHNL_BW_20)) {
+ cl_dbg_err(cl_hw, "Only 20Mhz is allowed for channel 2\n");
+ return -EINVAL;
+ }
+
+ bw = MHZ_TO_BW(bw_mhz);
+
+ if (cl_chandef_calc(cl_hw, channel, bw, &width, &primary, &center)) {
+ cl_dbg_err(cl_hw, "cl_chandef_calc failed\n");
+ return -EINVAL;
+ }
+
+ if (cl_hw->set_calib) {
+ cl_hw->set_calib = false;
+ cl_calib_power_read(cl_hw);
+ }
+
+ cl_msg_tx_set_channel(cl_hw, channel, bw, primary, center);
+
+ return 0;
+}
+
+int cl_ate_ant(struct wiphy *wiphy, struct wireless_dev *wdev,
+ const void *data, int data_len)
+{
+ struct cl_hw *cl_hw = WIPHY_TO_CL_HW(wiphy);
+ u8 ant = *(u8 *)data;
+ u8 mask;
+
+ if (ant >= MAX_ANTENNAS) {
+ cl_dbg_err(cl_hw, "Invalid antenna value [%u]", ant);
+ return -EINVAL;
+ }
+
+ mask = (1 << ant);
+
+ if (mask != cl_hw->ate_db.ant_mask) {
+ cl_hw->ate_db.ant_mask = mask;
+ cl_msg_tx_set_ant_bitmap(cl_hw, mask);
+ }
+
+ cl_dbg_trace(cl_hw, "ant = %u, mask = 0x%x\n", ant, mask);
+
+ return 0;
+}
+
+#define FULL_ANT_MASK ((1 << MAX_ANTENNAS) - 1)
+
+int cl_ate_multi_ant(struct wiphy *wiphy, struct wireless_dev *wdev,
+ const void *data, int data_len)
+{
+ struct cl_hw *cl_hw = WIPHY_TO_CL_HW(wiphy);
+ u8 mask = *(u8 *)data;
+
+ if (mask == 0 || mask > FULL_ANT_MASK) {
+ cl_dbg_err(cl_hw, "Invalid antenna bitmap [0x%x]", mask);
+ return -EINVAL;
+ }
+
+ if (mask != cl_hw->ate_db.ant_mask) {
+ cl_hw->ate_db.ant_mask = mask;
+ cl_msg_tx_set_ant_bitmap(cl_hw, mask);
+ }
+
+ cl_dbg_trace(cl_hw, "mask = 0x%x\n", mask);
+
+ return 0;
+}
+
+int cl_ate_packet_len(struct wiphy *wiphy, struct wireless_dev *wdev,
+ const void *data, int data_len)
+{
+ struct cl_hw *cl_hw = WIPHY_TO_CL_HW(wiphy);
+ u32 packet_len = *(u32 *)data;
+
+ cl_dbg_trace(cl_hw, "packet_len = %u\n", packet_len);
+
+ return cl_tx_inject_set_length(cl_hw, packet_len);
+}
+
+int cl_ate_vector(struct wiphy *wiphy, struct wireless_dev *wdev,
+ const void *data, int data_len)
+{
+ struct cl_hw *cl_hw = WIPHY_TO_CL_HW(wiphy);
+ u32 size = data_len / sizeof(u32);
+ int ret = 0;
+
+ cl_dbg_trace(cl_hw, "\n");
+
+ ret = cl_calib_pivot_channels_set(cl_hw, data, size);
+
+ /* Write EEPROM version when starting calibration process */
+ if (!ret)
+ return cl_e2p_write_version(cl_hw->chip);
+
+ return ret;
+}
+
+int cl_ate_vector_reset(struct wiphy *wiphy, struct wireless_dev *wdev,
+ const void *data, int data_len)
+{
+ struct cl_hw *cl_hw = WIPHY_TO_CL_HW(wiphy);
+
+ cl_dbg_trace(cl_hw, "\n");
+
+ return cl_calib_pivot_channels_reset(cl_hw);
+}
+
+#define FREQ_OFST_MAX 959
+
+int cl_ate_freq_offset(struct wiphy *wiphy, struct wireless_dev *wdev,
+ const void *data, int data_len)
+{
+ struct cl_hw *cl_hw = WIPHY_TO_CL_HW(wiphy);
+ u16 freq_offset = *(u16 *)data;
+
+ if (freq_offset > FREQ_OFST_MAX) {
+ cl_dbg_err(cl_hw, "Invalid freq offset 0x%04x\n", freq_offset);
+ return -1;
+ }
+
+ cl_dbg_trace(cl_hw, "Freq offset 0x%04x\n", freq_offset);
+
+ return cl_msg_tx_set_freq_offset(cl_hw, freq_offset);
+}
+
+int cl_ate_stat(struct wiphy *wiphy, struct wireless_dev *wdev,
+ const void *data, int data_len)
+{
+ struct cl_hw *cl_hw = WIPHY_TO_CL_HW(wiphy);
+ struct ate_stats new_stats;
+ struct ate_stats ret_stats;
+
+ read_stat(cl_hw, &new_stats);
+
+ DIFF(ret_stats, new_stats, cl_hw->ate_db.stats, tx_bw20);
+ DIFF(ret_stats, new_stats, cl_hw->ate_db.stats, tx_bw40);
+ DIFF(ret_stats, new_stats, cl_hw->ate_db.stats, tx_bw80);
+ DIFF(ret_stats, new_stats, cl_hw->ate_db.stats, tx_bw160);
+ DIFF(ret_stats, new_stats, cl_hw->ate_db.stats, rx_bw20);
+ DIFF(ret_stats, new_stats, cl_hw->ate_db.stats, rx_bw40);
+ DIFF(ret_stats, new_stats, cl_hw->ate_db.stats, rx_bw80);
+ DIFF(ret_stats, new_stats, cl_hw->ate_db.stats, rx_bw160);
+ DIFF(ret_stats, new_stats, cl_hw->ate_db.stats, fcs_err);
+ DIFF(ret_stats, new_stats, cl_hw->ate_db.stats, phy_err);
+ DIFF(ret_stats, new_stats, cl_hw->ate_db.stats, delimiter_err);
+
+ /* Present rx seccess of the defined bw */
+ switch (cl_hw->ate_db.bw) {
+ case CHNL_BW_20:
+ ret_stats.rx_success = ret_stats.rx_bw20;
+ break;
+ case CHNL_BW_40:
+ ret_stats.rx_success = ret_stats.rx_bw40;
+ break;
+ case CHNL_BW_80:
+ ret_stats.rx_success = ret_stats.rx_bw80;
+ break;
+ case CHNL_BW_160:
+ ret_stats.rx_success = ret_stats.rx_bw160;
+ break;
+ default:
+ /* Should not get here */
+ return -EINVAL;
+ }
+
+ /* Read rssi */
+ macdsp_api_inbdpow_20_unpack(cl_hw, &ret_stats.rssi3, &ret_stats.rssi2,
+ &ret_stats.rssi1, &ret_stats.rssi0);
+ ret_stats.rssi4 = S8_MIN;
+ ret_stats.rssi5 = S8_MIN;
+
+ cl_dbg_trace(cl_hw, "\n");
+
+ return cl_vendor_reply(cl_hw, &ret_stats, sizeof(struct ate_stats));
+}
+
+int cl_ate_stat_reset(struct wiphy *wiphy, struct wireless_dev *wdev,
+ const void *data, int data_len)
+{
+ struct cl_hw *cl_hw = WIPHY_TO_CL_HW(wiphy);
+
+ read_stat(cl_hw, &cl_hw->ate_db.stats);
+
+ cl_dbg_trace(cl_hw, "\n");
+
+ return 0;
+}
+
+int cl_ate_power(struct wiphy *wiphy, struct wireless_dev *wdev,
+ const void *data, int data_len)
+{
+ struct cl_hw *cl_hw = WIPHY_TO_CL_HW(wiphy);
+ s8 tx_power = *(s8 *)data;
+ s8 tx_power_q1 = 0;
+
+ if (tx_power < POWER_MIN_DB || tx_power > POWER_MAX_DB) {
+ cl_dbg_err(cl_hw, "Invalid power (%d). Must be between %d and %d\n",
+ tx_power, POWER_MIN_DB, POWER_MAX_DB);
+ return 0;
+ }
+
+ cl_hw->ate_db.tx_power = tx_power;
+ tx_power_q1 = tx_power << 1;
+
+ cl_dbg_trace(cl_hw, "ate_power = %u\n", tx_power);
+
+ memset(&cl_hw->phy_data_info.data->pwr_tables,
+ tx_power_q1, sizeof(struct cl_pwr_tables));
+
+ cl_msg_tx_refresh_power(cl_hw);
+
+ return 0;
+}
+
+int cl_ate_power_offset(struct wiphy *wiphy, struct wireless_dev *wdev,
+ const void *data, int data_len)
+{
+ struct cl_hw *cl_hw = WIPHY_TO_CL_HW(wiphy);
+ s8 *pwr_offset = cl_hw->ate_db.tx_power_offset;
+ int i;
+
+ for (i = 0; i < MAX_ANTENNAS; i++) {
+ pwr_offset[i] = ((s8 *)data)[i];
+
+ if (pwr_offset[i] < POWER_OFFSET_MIN_Q2 ||
+ pwr_offset[i] > POWER_OFFSET_MAX_Q2) {
+ cl_dbg_err(cl_hw, "Invalid power offset (%d). Valid range (%d - %d)\n",
+ pwr_offset[i], POWER_OFFSET_MIN_Q2, POWER_OFFSET_MAX_Q2);
+ memset(pwr_offset, S8_MAX, MAX_ANTENNAS);
+ return -1;
+ }
+ }
+
+ cl_dbg_trace(cl_hw, "power_offset = %d,%d,%d,%d,%d,%d\n",
+ pwr_offset[0], pwr_offset[1], pwr_offset[2],
+ pwr_offset[3], pwr_offset[4], pwr_offset[5]);
+
+ return cl_msg_tx_set_ant_pwr_offset(cl_hw, pwr_offset);
+}
+
+int cl_ate_tx_start(struct wiphy *wiphy, struct wireless_dev *wdev,
+ const void *data, int data_len)
+{
+ struct cl_hw *cl_hw = WIPHY_TO_CL_HW(wiphy);
+ u32 tx_cnt = *(u32 *)data;
+
+ if (!cl_hw->ate_db.active) {
+ cl_dbg_err(cl_hw, "Must call 'ATE reset' first.\n");
+ return -EPERM;
+ }
+
+ if (tx_cnt == 0) {
+ cl_tx_inject_stop_traffic(cl_hw);
+ return 0;
+ }
+
+ if (cl_tx_inject_is_running(cl_hw)) {
+ cl_dbg_err(cl_hw, "TX already running.\n");
+ return -EPERM;
+ }
+
+ if (!is_valid_rate(cl_hw) || !is_valid_bw(cl_hw))
+ return -EPERM;
+
+ set_fixed_rate(cl_hw);
+ cl_tx_inject_start(cl_hw, tx_cnt);
+
+ cl_dbg_trace(cl_hw, "\n");
+
+ return 0;
+}
+
+int cl_ate_tx_continuous(struct wiphy *wiphy, struct wireless_dev *wdev,
+ const void *data, int data_len)
+{
+ struct cl_hw *cl_hw = WIPHY_TO_CL_HW(wiphy);
+
+ if (!cl_hw->ate_db.active) {
+ cl_dbg_err(cl_hw, "Must call 'ATE reset' first.\n");
+ return -EPERM;
+ }
+
+ if (cl_tx_inject_is_running(cl_hw)) {
+ cl_dbg_err(cl_hw, "TX already running.\n");
+ return -EPERM;
+ }
+
+ if (!is_valid_rate(cl_hw) || !is_valid_bw(cl_hw))
+ return -EPERM;
+
+ set_fixed_rate(cl_hw);
+ cl_tx_inject_start_continuous(cl_hw);
+
+ cl_dbg_trace(cl_hw, "\n");
+
+ return 0;
+}
+
+int cl_ate_stop(struct wiphy *wiphy, struct wireless_dev *wdev,
+ const void *data, int data_len)
+{
+ struct cl_hw *cl_hw = WIPHY_TO_CL_HW(wiphy);
+
+ cl_tx_inject_stop(cl_hw);
+
+ /* Go back to IDLE state */
+ if (cl_hw->chip->conf->ce_production_mode)
+ cl_msg_tx_set_idle(cl_hw, MAC_IDLE_SYNC);
+
+ cl_hw->ate_db.active = false;
+
+ cl_dbg_trace(cl_hw, "\n");
+
+ return 0;
+}
+
+int cl_ate_help(struct wiphy *wiphy, struct wireless_dev *wdev,
+ const void *data, int data_len)
+{
+ struct cl_hw *cl_hw = WIPHY_TO_CL_HW(wiphy);
+ char *ret_buf = kzalloc(PAGE_SIZE, GFP_KERNEL);
+ int err = 0;
+
+ if (!ret_buf)
+ return -ENOMEM;
+
+ snprintf(ret_buf, PAGE_SIZE,
+ "usage:\n"
+ "reset - Reset ATE configuration\n"
+ "mode <0=CCK,1=OFDM,2=HT,3=VHT,4=HE> - Set mode\n"
+ "bw <20/40/80/160> - Set TX bandwidth parameter\n"
+ "mcs <CCK=0-3, OFDM/HT=0-7, VHT=0-9, HE=0-11> - set mcs parameter\n"
+ "nss <0-3> - set nss parameter\n"
+ "gi <CCK/OFDM=0, HT/VHT=0-1, HE=0-2> - set gi\n"
+ "ltf <HE-LTF: 0=LTF_X1,1=LTF_X2,2=LTF_X4> - set ltf\n"
+ "ldpc <0=Disable, 1=Enable> - set ldpc parameter\n"
+ "channel <ch number> <ch bw [20/40/80/160]> <Frequency delta"
+ " from center Frequency (optional)> - change channel\n"
+ "ant <Antenna index 0-5> - Enable single antenna\n"
+ "multi_ant <Ant bitmap> - Enable multiple antennas\n"
+ "packet_len <packet length (16-4096)> - Set length of packets to inject\n"
+ "vector <Channel vector separated by space> - Set"
+ " vector of channels to calibrate\n"
+ "freq_offset <0-959> - Set frequency offset\n"
+ "stat <reset (optional)> - Display/Reset statistics\n"
+ "power <-10dB - 30dB> - Set tx power\n"
+ "power_offset <offset_ant1 ... offset_ant6> - Power"
+ " offset per anthenna [range +/-64][units=0.25dB]\n"
+ "tx_start <Num of packets> - Start TX packets\n"
+ "tx_continuous - Start transmitting infinite packets\n"
+ "stop - Stop transmission\n");
+
+ err = cl_vendor_reply(cl_hw, ret_buf, strlen(ret_buf));
+ kfree(ret_buf);
+
+ return err;
+}
+
--
2.30.0

________________________________
The information transmitted is intended only for the person or entity to which it is addressed and may contain confidential and/or privileged material. Any retransmission, dissemination, copying or other use of, or taking of any action in reliance upon this information is prohibited. If you received this in error, please contact the sender and delete the material from any computer. Nothing contained herein shall be deemed as a representation, warranty or a commitment by Celeno. No warranties are expressed or implied, including, but not limited to, any implied warranties of non-infringement, merchantability and fitness for a particular purpose.
________________________________

2021-06-17 16:23:24

by viktor.barna

[permalink] [raw]
Subject: [RFC v1 031/256] cl8k: add cap.h

From: Viktor Barna <[email protected]>

(Part of the split. Please, take a look at the cover letter for more
details).

Signed-off-by: Viktor Barna <[email protected]>
---
drivers/net/wireless/celeno/cl8k/cap.h | 21 +++++++++++++++++++++
1 file changed, 21 insertions(+)
create mode 100644 drivers/net/wireless/celeno/cl8k/cap.h

diff --git a/drivers/net/wireless/celeno/cl8k/cap.h b/drivers/net/wireless/celeno/cl8k/cap.h
new file mode 100644
index 000000000000..5bbbccf3daaa
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/cap.h
@@ -0,0 +1,21 @@
+/* SPDX-License-Identifier: MIT */
+/* Copyright(c) 2019-2021, Celeno Communications Ltd. */
+
+#ifndef CL_CAP_H
+#define CL_CAP_H
+
+#include "hw.h"
+
+/**
+ * Capabilities indication to the cfg80211/mac80211 layer
+ */
+
+#define PPE_0US 0
+#define PPE_8US 1
+#define PPE_16US 2
+
+void cl_cap_dyn_params(struct cl_hw *cl_hw);
+void cl_cap_ppe_duration(struct cl_hw *cl_hw, struct ieee80211_sta *sta,
+ u8 pe_dur[CHNL_BW_MAX][WRS_MCS_MAX_HE]);
+
+#endif /* CL_CAP_H */
--
2.30.0

________________________________
The information transmitted is intended only for the person or entity to which it is addressed and may contain confidential and/or privileged material. Any retransmission, dissemination, copying or other use of, or taking of any action in reliance upon this information is prohibited. If you received this in error, please contact the sender and delete the material from any computer. Nothing contained herein shall be deemed as a representation, warranty or a commitment by Celeno. No warranties are expressed or implied, including, but not limited to, any implied warranties of non-infringement, merchantability and fitness for a particular purpose.
________________________________

2021-06-17 16:23:28

by viktor.barna

[permalink] [raw]
Subject: [RFC v1 030/256] cl8k: add cap.c

From: Viktor Barna <[email protected]o.com>

(Part of the split. Please, take a look at the cover letter for more
details).

Signed-off-by: Viktor Barna <[email protected]>
---
drivers/net/wireless/celeno/cl8k/cap.c | 928 +++++++++++++++++++++++++
1 file changed, 928 insertions(+)
create mode 100644 drivers/net/wireless/celeno/cl8k/cap.c

diff --git a/drivers/net/wireless/celeno/cl8k/cap.c b/drivers/net/wireless/celeno/cl8k/cap.c
new file mode 100644
index 000000000000..bfd884706aa7
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/cap.c
@@ -0,0 +1,928 @@
+// SPDX-License-Identifier: MIT
+/* Copyright(c) 2019-2021, Celeno Communications Ltd. */
+
+#include "cap.h"
+#include "utils/utils.h"
+#include "debug.h"
+#include "band.h"
+#include "chan_info.h"
+#include "tx/tx.h"
+#include "sta.h"
+#include "rx/rx_amsdu.h"
+
+#define CL_HT_CAPABILITIES \
+{ \
+ .ht_supported = true, \
+ .cap = IEEE80211_HT_CAP_DSSSCCK40 | IEEE80211_HT_CAP_MAX_AMSDU, \
+ .ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K, \
+ .ampdu_density = IEEE80211_HT_MPDU_DENSITY_1, \
+ .mcs = { \
+ .rx_mask = { 0xff, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, \
+ .rx_highest = cpu_to_le16(65), \
+ .tx_params = IEEE80211_HT_MCS_TX_DEFINED, \
+ }, \
+}
+
+#define CL_VHT_CAPABILITIES \
+{ \
+ .vht_supported = false, \
+ .cap = \
+ IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE | \
+ IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE | \
+ IEEE80211_VHT_CAP_MU_BEAMFORMER_CAPABLE | \
+ IEEE80211_VHT_CAP_MU_BEAMFORMEE_CAPABLE | \
+ (3 << IEEE80211_VHT_CAP_SOUNDING_DIMENSIONS_SHIFT) | \
+ (3 << IEEE80211_VHT_CAP_BEAMFORMEE_STS_SHIFT), \
+ .vht_mcs = { \
+ .rx_mcs_map = cpu_to_le16( \
+ IEEE80211_VHT_MCS_SUPPORT_0_7 << 0 | \
+ IEEE80211_VHT_MCS_NOT_SUPPORTED << 2 | \
+ IEEE80211_VHT_MCS_NOT_SUPPORTED << 4 | \
+ IEEE80211_VHT_MCS_NOT_SUPPORTED << 6 | \
+ IEEE80211_VHT_MCS_NOT_SUPPORTED << 8 | \
+ IEEE80211_VHT_MCS_NOT_SUPPORTED << 10 | \
+ IEEE80211_VHT_MCS_NOT_SUPPORTED << 12 | \
+ IEEE80211_VHT_MCS_NOT_SUPPORTED << 14), \
+ .tx_mcs_map = cpu_to_le16( \
+ IEEE80211_VHT_MCS_SUPPORT_0_7 << 0 | \
+ IEEE80211_VHT_MCS_NOT_SUPPORTED << 2 | \
+ IEEE80211_VHT_MCS_NOT_SUPPORTED << 4 | \
+ IEEE80211_VHT_MCS_NOT_SUPPORTED << 6 | \
+ IEEE80211_VHT_MCS_NOT_SUPPORTED << 8 | \
+ IEEE80211_VHT_MCS_NOT_SUPPORTED << 10 | \
+ IEEE80211_VHT_MCS_NOT_SUPPORTED << 12 | \
+ IEEE80211_VHT_MCS_NOT_SUPPORTED << 14), \
+ } \
+}
+
+#define CL_HE_CAP_ELEM_STATION \
+{ \
+ .mac_cap_info[0] = IEEE80211_HE_MAC_CAP0_HTC_HE, \
+ .mac_cap_info[1] = 0, \
+ .mac_cap_info[2] = 0, \
+ .mac_cap_info[3] = IEEE80211_HE_MAC_CAP3_MAX_AMPDU_LEN_EXP_EXT_2, \
+ .mac_cap_info[4] = IEEE80211_HE_MAC_CAP4_BQR, \
+ .mac_cap_info[5] = IEEE80211_HE_MAC_CAP5_HT_VHT_TRIG_FRAME_RX, \
+ .phy_cap_info[0] = IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_RU_MAPPING_IN_2G, \
+ .phy_cap_info[1] = IEEE80211_HE_PHY_CAP1_DEVICE_CLASS_A, \
+ .phy_cap_info[2] = 0, \
+ .phy_cap_info[3] = 0, \
+ .phy_cap_info[4] = 0, \
+ .phy_cap_info[5] = 0, \
+ .phy_cap_info[6] = 0, \
+ .phy_cap_info[7] = 0, \
+ .phy_cap_info[8] = IEEE80211_HE_PHY_CAP8_20MHZ_IN_40MHZ_HE_PPDU_IN_2G, \
+ .phy_cap_info[9] = IEEE80211_HE_PHY_CAP9_NOMIMAL_PKT_PADDING_16US, \
+ .phy_cap_info[10] = 0, \
+}
+
+#define CL_HE_CAP_ELEM_AP \
+{ \
+ .mac_cap_info[0] = IEEE80211_HE_MAC_CAP0_HTC_HE, \
+ .mac_cap_info[1] = 0, \
+ .mac_cap_info[2] = 0, \
+ .mac_cap_info[3] = IEEE80211_HE_MAC_CAP3_MAX_AMPDU_LEN_EXP_EXT_2, \
+ .mac_cap_info[4] = IEEE80211_HE_MAC_CAP4_BQR, \
+ .mac_cap_info[5] = 0, \
+ .phy_cap_info[0] = 0, \
+ .phy_cap_info[1] = IEEE80211_HE_PHY_CAP1_DEVICE_CLASS_A, \
+ .phy_cap_info[2] = 0, \
+ .phy_cap_info[3] = 0, \
+ .phy_cap_info[4] = 0, \
+ .phy_cap_info[5] = 0, \
+ .phy_cap_info[6] = 0, \
+ .phy_cap_info[7] = 0, \
+ .phy_cap_info[8] = 0, \
+ .phy_cap_info[9] = IEEE80211_HE_PHY_CAP9_NOMIMAL_PKT_PADDING_16US, \
+ .phy_cap_info[10] = 0, \
+}
+
+#define CL_HE_CAP_ELEM_MESH_POINT \
+{ \
+ .mac_cap_info[0] = IEEE80211_HE_MAC_CAP0_HTC_HE, \
+ .mac_cap_info[1] = 0, \
+ .mac_cap_info[2] = 0, \
+ .mac_cap_info[3] = IEEE80211_HE_MAC_CAP3_MAX_AMPDU_LEN_EXP_EXT_2, \
+ .mac_cap_info[4] = IEEE80211_HE_MAC_CAP4_BQR, \
+ .mac_cap_info[5] = 0, \
+ .phy_cap_info[0] = 0, \
+ .phy_cap_info[1] = IEEE80211_HE_PHY_CAP1_DEVICE_CLASS_A, \
+ .phy_cap_info[2] = 0, \
+ .phy_cap_info[3] = 0, \
+ .phy_cap_info[4] = 0, \
+ .phy_cap_info[5] = 0, \
+ .phy_cap_info[6] = 0, \
+ .phy_cap_info[7] = 0, \
+ .phy_cap_info[8] = 0, \
+ .phy_cap_info[9] = IEEE80211_HE_PHY_CAP9_NOMIMAL_PKT_PADDING_16US, \
+ .phy_cap_info[10] = 0, \
+}
+
+#define CL_HE_MCS_NSS_SUPP \
+{ \
+ .rx_mcs_80 = cpu_to_le16(0xff00), \
+ .tx_mcs_80 = cpu_to_le16(0xff00), \
+ .rx_mcs_160 = cpu_to_le16(0xff00), \
+ .tx_mcs_160 = cpu_to_le16(0xff00), \
+ .rx_mcs_80p80 = cpu_to_le16(0xffff), \
+ .tx_mcs_80p80 = cpu_to_le16(0xffff), \
+}
+
+#define RATE(_bitrate, _hw_rate, _flags) { \
+ .bitrate = (_bitrate), \
+ .flags = (_flags), \
+ .hw_value = (_hw_rate), \
+}
+
+#define CHAN(_freq, _idx) { \
+ .center_freq = (_freq), \
+ .hw_value = (_idx), \
+ .max_power = 18, \
+}
+
+#define CHANF(_freq, _idx, _flags) { \
+ .center_freq = (_freq), \
+ .hw_value = (_idx), \
+ .flags = (_flags), \
+ .max_power = 18, \
+}
+
+static struct ieee80211_sband_iftype_data cl_he_data[] = {
+ {
+ .types_mask = BIT(NL80211_IFTYPE_STATION),
+ .he_cap = {
+ .has_he = true,
+ .he_cap_elem = CL_HE_CAP_ELEM_STATION,
+ .he_mcs_nss_supp = CL_HE_MCS_NSS_SUPP,
+ },
+ },
+ {
+ .types_mask = BIT(NL80211_IFTYPE_AP),
+ .he_cap = {
+ .has_he = true,
+ .he_cap_elem = CL_HE_CAP_ELEM_AP,
+ .he_mcs_nss_supp = CL_HE_MCS_NSS_SUPP,
+ },
+ },
+ {
+ .types_mask = BIT(NL80211_IFTYPE_MESH_POINT),
+ .he_cap = {
+ .has_he = true,
+ .he_cap_elem = CL_HE_CAP_ELEM_MESH_POINT,
+ .he_mcs_nss_supp = CL_HE_MCS_NSS_SUPP,
+ },
+ },
+};
+
+static struct ieee80211_rate cl_ratetable[] = {
+ RATE(10, 0x00, 0),
+ RATE(20, 0x01, IEEE80211_RATE_SHORT_PREAMBLE),
+ RATE(55, 0x02, IEEE80211_RATE_SHORT_PREAMBLE),
+ RATE(110, 0x03, IEEE80211_RATE_SHORT_PREAMBLE),
+ RATE(60, 0x04, 0),
+ RATE(90, 0x05, 0),
+ RATE(120, 0x06, 0),
+ RATE(180, 0x07, 0),
+ RATE(240, 0x08, 0),
+ RATE(360, 0x09, 0),
+ RATE(480, 0x0A, 0),
+ RATE(540, 0x0B, 0),
+};
+
+/* The channels indexes here are not used anymore */
+static struct ieee80211_channel cl_2ghz_channels[] = {
+ CHAN(2412, 0),
+ CHAN(2417, 1),
+ CHAN(2422, 2),
+ CHAN(2427, 3),
+ CHAN(2432, 4),
+ CHAN(2437, 5),
+ CHAN(2442, 6),
+ CHAN(2447, 7),
+ CHAN(2452, 8),
+ CHAN(2457, 9),
+ CHAN(2462, 10),
+ CHAN(2467, 11),
+ CHAN(2472, 12),
+ CHAN(2484, 13),
+};
+
+static struct ieee80211_channel cl_5ghz_channels[] = {
+ CHAN(5180, 0), /* 36 - 20MHz */
+ CHAN(5200, 1), /* 40 - 20MHz */
+ CHAN(5220, 2), /* 44 - 20MHz */
+ CHAN(5240, 3), /* 48 - 20MHz */
+
+ CHANF(5260, 4, IEEE80211_CHAN_RADAR), /* 52 - 20MHz */
+ CHANF(5280, 5, IEEE80211_CHAN_RADAR), /* 56 - 20MHz */
+ CHANF(5300, 6, IEEE80211_CHAN_RADAR), /* 60 - 20MHz */
+ CHANF(5320, 7, IEEE80211_CHAN_RADAR), /* 64 - 20MHz */
+ CHANF(5500, 8, IEEE80211_CHAN_RADAR), /* 100 - 20MHz */
+ CHANF(5520, 9, IEEE80211_CHAN_RADAR), /* 104 - 20MHz */
+ CHANF(5540, 10, IEEE80211_CHAN_RADAR), /* 108 - 20MHz */
+ CHANF(5560, 11, IEEE80211_CHAN_RADAR), /* 112 - 20MHz */
+ CHANF(5580, 12, IEEE80211_CHAN_RADAR), /* 116 - 20MHz */
+ CHANF(5600, 13, IEEE80211_CHAN_RADAR), /* 120 - 20MHz */
+ CHANF(5620, 14, IEEE80211_CHAN_RADAR), /* 124 - 20MHz */
+ CHANF(5640, 15, IEEE80211_CHAN_RADAR), /* 128 - 20MHz */
+ CHANF(5660, 16, IEEE80211_CHAN_RADAR), /* 132 - 20MHz */
+ CHANF(5680, 17, IEEE80211_CHAN_RADAR), /* 136 - 20MHz */
+ CHANF(5700, 18, IEEE80211_CHAN_RADAR), /* 140 - 20MHz */
+
+ CHAN(5720, 19), /* 144 - 20MHz */
+ CHAN(5745, 20), /* 149 - 20MHz */
+ CHAN(5765, 21), /* 153 - 20MHz */
+ CHAN(5785, 22), /* 157 - 20MHz */
+ CHAN(5805, 23), /* 161 - 20MHz */
+ CHAN(5825, 24), /* 165 - 20MHz */
+};
+
+static struct ieee80211_channel cl_6ghz_channels[] = {
+ CHAN(5955, 1), /* 1 - 20MHz */
+ CHAN(5935, 2), /* 2 - 20MHz */
+ CHAN(5975, 5), /* 5 - 20MHz */
+ CHAN(5995, 9), /* 9 - 20MHz */
+ CHAN(6015, 13), /* 13 - 20MHz */
+ CHAN(6035, 17), /* 17 - 20MHz */
+ CHAN(6055, 21), /* 21 - 20MHz */
+ CHAN(6075, 25), /* 25 - 20MHz */
+ CHAN(6095, 29), /* 29 - 20MHz */
+ CHAN(6115, 33), /* 33 - 20MHz */
+ CHAN(6135, 37), /* 37 - 20MHz */
+ CHAN(6155, 41), /* 41 - 20MHz */
+ CHAN(6175, 45), /* 45 - 20MHz */
+ CHAN(6195, 49), /* 49 - 20MHz */
+ CHAN(6215, 53), /* 53 - 20MHz */
+ CHAN(6235, 57), /* 57 - 20MHz */
+ CHAN(6255, 61), /* 61 - 20MHz */
+ CHAN(6275, 65), /* 65 - 20MHz */
+ CHAN(6295, 69), /* 69 - 20MHz */
+ CHAN(6315, 73), /* 73 - 20MHz */
+ CHAN(6335, 77), /* 77 - 20MHz */
+ CHAN(6355, 81), /* 81 - 20MHz */
+ CHAN(6375, 85), /* 85 - 20MHz */
+ CHAN(6395, 89), /* 89 - 20MHz */
+ CHAN(6415, 93), /* 93 - 20MHz */
+ CHAN(6435, 97), /* 97 - 20MHz */
+ CHAN(6455, 101), /* 101 - 20MHz */
+ CHAN(6475, 105), /* 105 - 20MHz */
+ CHAN(6495, 109), /* 109 - 20MHz */
+ CHAN(6515, 113), /* 113 - 20MHz */
+ CHAN(6535, 117), /* 117 - 20MHz */
+ CHAN(6555, 121), /* 121 - 20MHz */
+ CHAN(6575, 125), /* 125 - 20MHz */
+ CHAN(6595, 129), /* 129 - 20MHz */
+ CHAN(6615, 133), /* 133 - 20MHz */
+ CHAN(6635, 137), /* 137 - 20MHz */
+ CHAN(6655, 141), /* 141 - 20MHz */
+ CHAN(6675, 145), /* 145 - 20MHz */
+ CHAN(6695, 149), /* 149 - 20MHz */
+ CHAN(6715, 153), /* 153 - 20MHz */
+ CHAN(6735, 157), /* 157 - 20MHz */
+ CHAN(6755, 161), /* 161 - 20MHz */
+ CHAN(6775, 165), /* 165 - 20MHz */
+ CHAN(6795, 169), /* 169 - 20MHz */
+ CHAN(6815, 173), /* 173 - 20MHz */
+ CHAN(6835, 177), /* 177 - 20MHz */
+ CHAN(6855, 181), /* 181 - 20MHz */
+ CHAN(6875, 188), /* 185 - 20MHz */
+ CHAN(6895, 189), /* 189 - 20MHz */
+ CHAN(6915, 193), /* 193 - 20MHz */
+ CHAN(6935, 197), /* 197 - 20MHz */
+ CHAN(6955, 201), /* 201 - 20MHz */
+ CHAN(6975, 205), /* 205 - 20MHz */
+ CHAN(6995, 209), /* 209 - 20MHz */
+ CHAN(7015, 213), /* 213 - 20MHz */
+ CHAN(7035, 217), /* 217 - 20MHz */
+ CHAN(7055, 221), /* 221 - 20MHz */
+ CHAN(7075, 225), /* 225 - 20MHz */
+ CHAN(7095, 229), /* 229 - 20MHz */
+ CHAN(7115, 233), /* 233 - 20MHz */
+};
+
+static struct ieee80211_supported_band cl_band_2ghz = {
+ .channels = cl_2ghz_channels,
+ .n_channels = ARRAY_SIZE(cl_2ghz_channels),
+ .bitrates = cl_ratetable,
+ .n_bitrates = ARRAY_SIZE(cl_ratetable),
+ .ht_cap = CL_HT_CAPABILITIES,
+ .vht_cap = CL_VHT_CAPABILITIES,
+};
+
+static struct ieee80211_supported_band cl_band_5ghz = {
+ .channels = cl_5ghz_channels,
+ .n_channels = ARRAY_SIZE(cl_5ghz_channels),
+ .bitrates = &cl_ratetable[4],
+ .n_bitrates = ARRAY_SIZE(cl_ratetable) - 4,
+ .ht_cap = CL_HT_CAPABILITIES,
+ .vht_cap = CL_VHT_CAPABILITIES,
+};
+
+static struct ieee80211_supported_band cl_band_6ghz = {
+ .channels = cl_6ghz_channels,
+ .n_channels = ARRAY_SIZE(cl_6ghz_channels),
+ .bitrates = &cl_ratetable[4],
+ .n_bitrates = ARRAY_SIZE(cl_ratetable) - 4,
+};
+
+static const struct ieee80211_iface_limit cl_limits[] = {
+ {
+ .max = MAX_BSS_NUM,
+ .types = BIT(NL80211_IFTYPE_AP) |
+ BIT(NL80211_IFTYPE_STATION) |
+ BIT(NL80211_IFTYPE_MESH_POINT),
+ },
+};
+
+static const u8 cl_if_types_ext_capa_ap[] = {
+ [0] = WLAN_EXT_CAPA1_EXT_CHANNEL_SWITCHING,
+ [7] = WLAN_EXT_CAPA8_OPMODE_NOTIF,
+ [10] = WLAN_EXT_CAPA11_COMPLETE_LIST_OF_NONTXBSSID_PROFILES,
+};
+
+static const struct wiphy_iftype_ext_capab cl_iftypes_ext_capa[] = {
+ {
+ .iftype = NL80211_IFTYPE_AP,
+ .extended_capabilities = cl_if_types_ext_capa_ap,
+ .extended_capabilities_mask = cl_if_types_ext_capa_ap,
+ .extended_capabilities_len = sizeof(cl_if_types_ext_capa_ap),
+ },
+};
+
+static const struct ieee80211_iface_combination cl_combinations[] = {
+ {
+ .limits = cl_limits,
+ .n_limits = ARRAY_SIZE(cl_limits),
+ .num_different_channels = 1,
+ .max_interfaces = MAX_BSS_NUM,
+ .beacon_int_min_gcd = 100,
+ .radar_detect_widths = BIT(NL80211_CHAN_WIDTH_20) |
+ BIT(NL80211_CHAN_WIDTH_40) |
+ BIT(NL80211_CHAN_WIDTH_80) |
+ BIT(NL80211_CHAN_WIDTH_160),
+ }
+};
+
+static u8 he_mcs_supp_tx(struct cl_hw *cl_hw, u8 nss)
+{
+ u8 mcs = cl_hw->conf->ce_he_mcs_nss_supp_tx[nss];
+
+ switch (mcs) {
+ case WRS_MCS_7:
+ return IEEE80211_HE_MCS_SUPPORT_0_7;
+ case WRS_MCS_9:
+ return IEEE80211_HE_MCS_SUPPORT_0_9;
+ case WRS_MCS_11:
+ return IEEE80211_HE_MCS_SUPPORT_0_11;
+ }
+
+ cl_dbg_err(cl_hw, "Invalid mcs %u for nss %u. Must be 7, 9 or 11!\n", mcs, nss);
+ return IEEE80211_HE_MCS_NOT_SUPPORTED;
+}
+
+static u8 he_mcs_supp_rx(struct cl_hw *cl_hw, u8 nss)
+{
+ u8 mcs = cl_hw->conf->ce_he_mcs_nss_supp_rx[nss];
+
+ switch (mcs) {
+ case WRS_MCS_7:
+ return IEEE80211_HE_MCS_SUPPORT_0_7;
+ case WRS_MCS_9:
+ return IEEE80211_HE_MCS_SUPPORT_0_9;
+ case WRS_MCS_11:
+ return IEEE80211_HE_MCS_SUPPORT_0_11;
+ }
+
+ cl_dbg_err(cl_hw, "Invalid mcs %u for nss %u. Must be 7, 9 or 11!\n", mcs, nss);
+ return IEEE80211_HE_MCS_NOT_SUPPORTED;
+}
+
+static u8 vht_mcs_supp_tx(struct cl_hw *cl_hw, u8 nss)
+{
+ u8 mcs = cl_hw->conf->ce_vht_mcs_nss_supp_tx[nss];
+
+ switch (mcs) {
+ case WRS_MCS_7:
+ return IEEE80211_VHT_MCS_SUPPORT_0_7;
+ case WRS_MCS_8:
+ return IEEE80211_VHT_MCS_SUPPORT_0_8;
+ case WRS_MCS_9:
+ return IEEE80211_VHT_MCS_SUPPORT_0_9;
+ }
+
+ cl_dbg_err(cl_hw, "Invalid mcs %u for nss %u. Must be 7-9!\n", mcs, nss);
+ return IEEE80211_VHT_MCS_NOT_SUPPORTED;
+}
+
+static u8 vht_mcs_supp_rx(struct cl_hw *cl_hw, u8 nss)
+{
+ u8 mcs = cl_hw->conf->ce_vht_mcs_nss_supp_rx[nss];
+
+ switch (mcs) {
+ case WRS_MCS_7:
+ return IEEE80211_VHT_MCS_SUPPORT_0_7;
+ case WRS_MCS_8:
+ return IEEE80211_VHT_MCS_SUPPORT_0_8;
+ case WRS_MCS_9:
+ return IEEE80211_VHT_MCS_SUPPORT_0_9;
+ }
+
+ cl_dbg_err(cl_hw, "Invalid mcs %u for nss %u. Must be 7-9!\n", mcs, nss);
+ return IEEE80211_VHT_MCS_NOT_SUPPORTED;
+}
+
+static void cl_set_he_6ghz_capab(struct cl_hw *cl_hw)
+{
+ struct ieee80211_he_6ghz_capa *he_6ghz_cap0 = &cl_hw->iftype_data[0].he_6ghz_capa;
+ struct ieee80211_he_6ghz_capa *he_6ghz_cap1 = &cl_hw->iftype_data[1].he_6ghz_capa;
+ struct ieee80211_he_6ghz_capa *he_6ghz_cap2 = &cl_hw->iftype_data[2].he_6ghz_capa;
+
+ he_6ghz_cap0->capa = cpu_to_le16(IEEE80211_HT_MPDU_DENSITY_1);
+ he_6ghz_cap0->capa |=
+ cpu_to_le16(cl_hw->conf->ha_max_mpdu_len << HE_6GHZ_CAP_MAX_MPDU_LEN_OFFSET);
+ he_6ghz_cap0->capa |=
+ cpu_to_le16(IEEE80211_VHT_MAX_AMPDU_1024K << HE_6GHZ_CAP_MAX_AMPDU_LEN_EXP_OFFSET);
+
+ he_6ghz_cap1->capa = he_6ghz_cap0->capa;
+ he_6ghz_cap2->capa = he_6ghz_cap0->capa;
+}
+
+static void _cl_set_he_capab(struct cl_hw *cl_hw, u8 idx)
+{
+ struct ieee80211_sta_he_cap *he_cap = &cl_hw->iftype_data[idx].he_cap;
+ struct ieee80211_he_mcs_nss_supp *he_mcs_nss_supp = &he_cap->he_mcs_nss_supp;
+ struct ieee80211_he_cap_elem *he_cap_elem = &he_cap->he_cap_elem;
+ u8 rx_nss = cl_hw->conf->ce_rx_nss;
+ u8 tx_nss = cl_hw->conf->ce_tx_nss;
+ int i = 0;
+
+ if (BAND_IS_5G_6G(cl_hw)) {
+ he_cap_elem->phy_cap_info[0] |=
+ IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_160MHZ_IN_5G;
+
+ for (i = 0; i < rx_nss; i++)
+ he_mcs_nss_supp->rx_mcs_160 |=
+ cpu_to_le16(he_mcs_supp_rx(cl_hw, i) << (i * 2));
+
+ for (i = 0; i < tx_nss; i++)
+ he_mcs_nss_supp->tx_mcs_160 |=
+ cpu_to_le16(he_mcs_supp_tx(cl_hw, i) << (i * 2));
+
+ he_cap_elem->phy_cap_info[0] |=
+ IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_40MHZ_80MHZ_IN_5G;
+
+ for (i = 0; i < rx_nss; i++)
+ he_mcs_nss_supp->rx_mcs_80 |=
+ cpu_to_le16(he_mcs_supp_rx(cl_hw, i) << (i * 2));
+
+ for (i = 0; i < tx_nss; i++)
+ he_mcs_nss_supp->tx_mcs_80 |=
+ cpu_to_le16(he_mcs_supp_tx(cl_hw, i) << (i * 2));
+ } else {
+ he_cap_elem->phy_cap_info[0] |=
+ IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_40MHZ_IN_2G;
+
+ for (i = 0; i < rx_nss; i++)
+ he_mcs_nss_supp->rx_mcs_80 |=
+ cpu_to_le16(he_mcs_supp_rx(cl_hw, i) << (i * 2));
+
+ for (i = 0; i < tx_nss; i++)
+ he_mcs_nss_supp->tx_mcs_80 |=
+ cpu_to_le16(he_mcs_supp_tx(cl_hw, i) << (i * 2));
+ }
+
+ for (i = rx_nss; i < 8; i++) {
+ he_mcs_nss_supp->rx_mcs_80 |=
+ cpu_to_le16(IEEE80211_HE_MCS_NOT_SUPPORTED << (i * 2));
+ he_mcs_nss_supp->rx_mcs_160 |=
+ cpu_to_le16(IEEE80211_HE_MCS_NOT_SUPPORTED << (i * 2));
+ }
+
+ for (i = tx_nss; i < 8; i++) {
+ he_mcs_nss_supp->tx_mcs_80 |=
+ cpu_to_le16(IEEE80211_HE_MCS_NOT_SUPPORTED << (i * 2));
+ he_mcs_nss_supp->tx_mcs_160 |=
+ cpu_to_le16(IEEE80211_HE_MCS_NOT_SUPPORTED << (i * 2));
+ }
+
+ if (cl_hw->conf->ce_he_rxldpc_en)
+ he_cap_elem->phy_cap_info[1] |=
+ IEEE80211_HE_PHY_CAP1_LDPC_CODING_IN_PAYLOAD;
+
+ if (cl_hw->conf->ci_rx_he_mu_ppdu)
+ he_cap_elem->phy_cap_info[3] |=
+ IEEE80211_HE_PHY_CAP3_RX_PARTIAL_BW_SU_IN_20MHZ_MU;
+
+ he_cap_elem->phy_cap_info[3] |=
+ IEEE80211_HE_PHY_CAP3_SU_BEAMFORMER;
+ he_cap_elem->phy_cap_info[5] |=
+ IEEE80211_HE_PHY_CAP5_BEAMFORMEE_NUM_SND_DIM_UNDER_80MHZ_4;
+}
+
+static void cl_set_he_capab(struct cl_hw *cl_hw)
+{
+ struct ieee80211_sta_he_cap *he_cap0 = &cl_hw->iftype_data[0].he_cap;
+ struct ieee80211_sta_he_cap *he_cap1 = &cl_hw->iftype_data[1].he_cap;
+ struct ieee80211_he_cap_elem *he_cap_elem0 = &he_cap0->he_cap_elem;
+ struct ieee80211_he_cap_elem *he_cap_elem1 = &he_cap1->he_cap_elem;
+
+ struct cl_tcv_conf *conf = cl_hw->conf;
+ u8 tf_mac_pad_dur = conf->ci_tf_mac_pad_dur;
+
+ memcpy(&cl_hw->iftype_data, cl_he_data, sizeof(cl_hw->iftype_data));
+
+ /* TWT support */
+ if (conf->ce_twt_en) {
+ /* STA mode */
+ he_cap_elem0->mac_cap_info[0] |= IEEE80211_HE_MAC_CAP0_TWT_REQ;
+ /* AP mode */
+ he_cap_elem1->mac_cap_info[0] |= IEEE80211_HE_MAC_CAP0_TWT_RES;
+ }
+
+ /* OMI support */
+ if (conf->ce_omi_en) {
+ /* STA mode */
+ he_cap_elem0->mac_cap_info[3] |= IEEE80211_HE_MAC_CAP3_OMI_CONTROL;
+ /* AP mode */
+ he_cap_elem1->mac_cap_info[3] |= IEEE80211_HE_MAC_CAP3_OMI_CONTROL;
+ he_cap_elem1->mac_cap_info[5] |= IEEE80211_HE_MAC_CAP5_OM_CTRL_UL_MU_DATA_DIS_RX;
+ }
+
+ if (tf_mac_pad_dur == 1)
+ he_cap_elem0->mac_cap_info[1] |= IEEE80211_HE_MAC_CAP1_TF_MAC_PAD_DUR_8US;
+ else if (tf_mac_pad_dur == 2)
+ he_cap_elem0->mac_cap_info[1] |= IEEE80211_HE_MAC_CAP1_TF_MAC_PAD_DUR_16US;
+
+ _cl_set_he_capab(cl_hw, 0);
+ _cl_set_he_capab(cl_hw, 1);
+ _cl_set_he_capab(cl_hw, 2);
+
+ if (cl_band_is_6g(cl_hw))
+ cl_set_he_6ghz_capab(cl_hw);
+
+ cl_hw->sband.n_iftype_data = ARRAY_SIZE(cl_he_data);
+ cl_hw->sband.iftype_data = cl_hw->iftype_data;
+}
+
+void cl_cap_dyn_params(struct cl_hw *cl_hw)
+{
+ struct ieee80211_hw *hw = cl_hw->hw;
+ struct wiphy *wiphy = hw->wiphy;
+ struct cl_tcv_conf *conf = cl_hw->conf;
+ u8 rx_nss = conf->ce_rx_nss;
+ u8 tx_nss = conf->ce_tx_nss;
+ u8 guard_interval = conf->ha_short_guard_interval;
+ u8 i;
+ u8 bw = cl_hw->conf->ce_channel_bandwidth;
+ struct ieee80211_supported_band *sband = &cl_hw->sband;
+ struct ieee80211_sta_ht_cap *sband_ht_cap = &sband->ht_cap;
+ struct ieee80211_sta_vht_cap *sband_vht_cap = &sband->vht_cap;
+
+ if (cl_band_is_6g(cl_hw)) {
+ memcpy(sband, &cl_band_6ghz, sizeof(struct ieee80211_supported_band));
+ } else if (cl_band_is_5g(cl_hw)) {
+ memcpy(sband, &cl_band_5ghz, sizeof(struct ieee80211_supported_band));
+ if (!conf->ci_ieee80211h) {
+ int i;
+
+ for (i = 0; i < sband->n_channels; i++)
+ sband->channels[i].flags &= ~IEEE80211_CHAN_RADAR;
+ }
+ } else {
+ memcpy(sband, &cl_band_2ghz, sizeof(struct ieee80211_supported_band));
+
+ if (!conf->ci_vht_cap_24g)
+ memset(&sband->vht_cap, 0, sizeof(struct ieee80211_sta_vht_cap));
+ }
+
+ /* 6GHz doesn't support HT/VHT */
+ if (!cl_band_is_6g(cl_hw)) {
+ if (bw > CHNL_BW_20)
+ sband_ht_cap->cap |= IEEE80211_HT_CAP_SUP_WIDTH_20_40;
+
+ /* Guard_interval */
+ if (guard_interval) {
+ sband_ht_cap->cap |= IEEE80211_HT_CAP_SGI_20;
+
+ if (bw >= CHNL_BW_40)
+ sband_ht_cap->cap |= IEEE80211_HT_CAP_SGI_40;
+
+ if (bw >= CHNL_BW_80)
+ sband_vht_cap->cap |= IEEE80211_VHT_CAP_SHORT_GI_80;
+
+ if (bw == CHNL_BW_160)
+ sband_vht_cap->cap |= IEEE80211_VHT_CAP_SHORT_GI_160;
+ }
+ }
+
+ /* Amsdu */
+ cl_rx_amsdu_hw_en(hw, conf->ce_rxamsdu_en);
+ cl_hw->txamsdu_en = conf->ce_txamsdu_en;
+
+ /* Hw flags */
+ ieee80211_hw_set(hw, HOST_BROADCAST_PS_BUFFERING);
+ ieee80211_hw_set(hw, SIGNAL_DBM);
+ ieee80211_hw_set(hw, REPORTS_TX_ACK_STATUS);
+ ieee80211_hw_set(hw, QUEUE_CONTROL);
+ ieee80211_hw_set(hw, WANT_MONITOR_VIF);
+ ieee80211_hw_set(hw, SPECTRUM_MGMT);
+ ieee80211_hw_set(hw, SUPPORTS_HT_CCK_RATES);
+ ieee80211_hw_set(hw, HAS_RATE_CONTROL);
+ ieee80211_hw_set(hw, SUPPORT_FAST_XMIT);
+ ieee80211_hw_set(hw, NO_AUTO_VIF);
+
+ wiphy->features |= NL80211_FEATURE_AP_MODE_CHAN_WIDTH_CHANGE;
+
+ /* Turn on "20/40 Coex Mgmt Support" bit (24g only) */
+ if (cl_band_is_24g(cl_hw)) {
+ struct ieee80211_local *local = hw_to_local(hw);
+
+ if (conf->ce_coex_en)
+ local->ext_capa[0] |= WLAN_EXT_CAPA1_2040_BSS_COEX_MGMT_ENABLED;
+ else
+ wiphy->features &= ~NL80211_FEATURE_AP_MODE_CHAN_WIDTH_CHANGE;
+ }
+
+ if (conf->ci_fast_rx_en) {
+ ieee80211_hw_set(hw, SUPPORTS_REORDERING_BUFFER);
+ ieee80211_hw_set(hw, AP_LINK_PS);
+ }
+
+ /*
+ * To disable the dynamic PS we say to the stack that we support it in
+ * HW. This will force mac80211 rely on us to handle this.
+ */
+ ieee80211_hw_set(hw, SUPPORTS_DYNAMIC_PS);
+
+ if (conf->ci_agg_tx)
+ ieee80211_hw_set(hw, AMPDU_AGGREGATION);
+
+ if (conf->ci_ieee80211w)
+ ieee80211_hw_set(hw, MFP_CAPABLE);
+
+ wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
+ BIT(NL80211_IFTYPE_AP) |
+ BIT(NL80211_IFTYPE_MESH_POINT);
+
+ wiphy->flags |= WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL |
+ WIPHY_FLAG_HAS_CHANNEL_SWITCH;
+
+ if (conf->ce_uapsd_en)
+ wiphy->flags |= WIPHY_FLAG_AP_UAPSD;
+
+ wiphy->iface_combinations = cl_combinations;
+ wiphy->n_iface_combinations = ARRAY_SIZE(cl_combinations);
+
+ hw->max_rates = IEEE80211_TX_MAX_RATES;
+ hw->max_report_rates = IEEE80211_TX_MAX_RATES;
+ hw->max_rate_tries = 1;
+
+ hw->max_tx_aggregation_subframes = conf->ce_max_agg_size_tx;
+ hw->max_rx_aggregation_subframes = conf->ce_max_agg_size_rx;
+
+ hw->vif_data_size = sizeof(struct cl_vif);
+ hw->sta_data_size = sizeof(struct cl_sta);
+
+ hw->extra_tx_headroom = 0;
+ hw->queues = IEEE80211_MAX_QUEUES;
+ hw->offchannel_tx_hw_queue = CL_HWQ_VO;
+
+ if (!cl_band_is_6g(cl_hw)) {
+ if (conf->ce_ht_rxldpc_en)
+ sband_ht_cap->cap |= IEEE80211_HT_CAP_LDPC_CODING;
+
+ sband_ht_cap->cap |= IEEE80211_HT_CAP_MAX_AMSDU;
+ sband_vht_cap->cap |= cl_hw->conf->ha_max_mpdu_len;
+ }
+
+ if (cl_band_is_5g(cl_hw) || (cl_band_is_24g(cl_hw) && conf->ci_vht_cap_24g)) {
+ if (bw == CHNL_BW_160)
+ sband_vht_cap->cap |= IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160MHZ;
+
+ sband_vht_cap->cap |= (conf->ha_vht_max_ampdu_len_exp <<
+ IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_SHIFT);
+
+ if (conf->ce_vht_rxldpc_en)
+ sband_vht_cap->cap |= IEEE80211_VHT_CAP_RXLDPC;
+
+ sband_vht_cap->vht_mcs.rx_mcs_map = cpu_to_le16(0);
+ sband_vht_cap->vht_mcs.tx_mcs_map = cpu_to_le16(0);
+
+ for (i = 0; i < rx_nss; i++)
+ sband_vht_cap->vht_mcs.rx_mcs_map |=
+ cpu_to_le16(vht_mcs_supp_rx(cl_hw, i) << (i * 2));
+
+ for (; i < 8; i++)
+ sband_vht_cap->vht_mcs.rx_mcs_map |=
+ cpu_to_le16(IEEE80211_VHT_MCS_NOT_SUPPORTED << (i * 2));
+
+ for (i = 0; i < tx_nss; i++)
+ sband_vht_cap->vht_mcs.tx_mcs_map |=
+ cpu_to_le16(vht_mcs_supp_tx(cl_hw, i) << (i * 2));
+
+ for (; i < 8; i++)
+ sband_vht_cap->vht_mcs.tx_mcs_map |=
+ cpu_to_le16(IEEE80211_VHT_MCS_NOT_SUPPORTED << (i * 2));
+
+ sband_vht_cap->vht_mcs.rx_highest = cpu_to_le16(390 * rx_nss);
+ sband_vht_cap->vht_mcs.tx_highest = cpu_to_le16(390 * tx_nss);
+ sband_vht_cap->vht_supported = true;
+ }
+
+ /* 6GHz band supports HE only */
+ if (!cl_band_is_6g(cl_hw)) {
+ for (i = 0; i < rx_nss; i++)
+ sband_ht_cap->mcs.rx_mask[i] = U8_MAX;
+
+ if (bw == CHNL_BW_20)
+ sband_ht_cap->mcs.rx_highest = guard_interval ?
+ cpu_to_le16(72 * rx_nss) : cpu_to_le16(65 * rx_nss);
+ else
+ sband_ht_cap->mcs.rx_highest = guard_interval ?
+ cpu_to_le16(150 * rx_nss) : cpu_to_le16(135 * rx_nss);
+ }
+
+ if (cl_hw->conf->ce_wireless_mode > WIRELESS_MODE_HT_VHT)
+ cl_set_he_capab(cl_hw);
+
+ /* Get channels and power limitations information from ChannelInfo file */
+ cl_chan_info_init(cl_hw);
+
+ if (cl_band_is_6g(cl_hw)) {
+ wiphy->bands[NL80211_BAND_2GHZ] = NULL;
+ wiphy->bands[NL80211_BAND_5GHZ] = NULL;
+ wiphy->bands[NL80211_BAND_6GHZ] = sband;
+ } else if (cl_band_is_5g(cl_hw)) {
+ wiphy->bands[NL80211_BAND_2GHZ] = NULL;
+ wiphy->bands[NL80211_BAND_5GHZ] = sband;
+ wiphy->bands[NL80211_BAND_6GHZ] = NULL;
+ } else {
+ wiphy->bands[NL80211_BAND_2GHZ] = sband;
+ wiphy->bands[NL80211_BAND_5GHZ] = NULL;
+ wiphy->bands[NL80211_BAND_6GHZ] = NULL;
+ }
+
+ wiphy->regulatory_flags |= REGULATORY_WIPHY_SELF_MANAGED;
+}
+
+enum he_pkt_ext_constellations {
+ HE_PKT_EXT_BPSK = 0,
+ HE_PKT_EXT_QPSK,
+ HE_PKT_EXT_16QAM,
+ HE_PKT_EXT_64QAM,
+ HE_PKT_EXT_256QAM,
+ HE_PKT_EXT_1024QAM,
+ HE_PKT_EXT_RESERVED,
+ HE_PKT_EXT_NONE,
+};
+
+static u8 mcs_to_constellation[WRS_MCS_MAX_HE] = {
+ HE_PKT_EXT_BPSK,
+ HE_PKT_EXT_QPSK,
+ HE_PKT_EXT_QPSK,
+ HE_PKT_EXT_16QAM,
+ HE_PKT_EXT_16QAM,
+ HE_PKT_EXT_64QAM,
+ HE_PKT_EXT_64QAM,
+ HE_PKT_EXT_64QAM,
+ HE_PKT_EXT_256QAM,
+ HE_PKT_EXT_256QAM,
+ HE_PKT_EXT_1024QAM,
+ HE_PKT_EXT_1024QAM
+};
+
+#define QAM_THR_1 0
+#define QAM_THR_2 1
+#define QAM_THR_MAX 2
+
+static u8 get_ppe_val(u8 *ppe, u8 ppe_pos_bit)
+{
+ u8 byte_num = ppe_pos_bit / 8;
+ u8 bit_num = ppe_pos_bit % 8;
+ u8 residue_bits;
+ u8 res;
+
+ if (bit_num <= 5)
+ return (ppe[byte_num] >> bit_num) &
+ (BIT(IEEE80211_PPE_THRES_INFO_PPET_SIZE) - 1);
+
+ /*
+ * If bit_num > 5, we have to combine bits with next byte.
+ * Calculate how many bits we need to take from current byte (called
+ * here "residue_bits"), and add them to bits from next byte.
+ */
+ residue_bits = 8 - bit_num;
+
+ res = (ppe[byte_num + 1] &
+ (BIT(IEEE80211_PPE_THRES_INFO_PPET_SIZE - residue_bits) - 1)) <<
+ residue_bits;
+ res += (ppe[byte_num] >> bit_num) & (BIT(residue_bits) - 1);
+
+ return res;
+}
+
+static void set_fixed_ppe_val(u8 pe_dur[CHNL_BW_MAX][WRS_MCS_MAX_HE], u8 dur)
+{
+ u8 val = ((dur << 6) | (dur << 4) | (dur << 2) | dur);
+
+ memset(pe_dur, val, CHNL_BW_MAX * WRS_MCS_MAX_HE);
+}
+
+void cl_cap_ppe_duration(struct cl_hw *cl_hw, struct ieee80211_sta *sta,
+ u8 pe_dur[CHNL_BW_MAX][WRS_MCS_MAX_HE])
+{
+ /* Force NVRAM parameter */
+ if (cl_hw->conf->ci_pe_duration <= PPE_16US) {
+ set_fixed_ppe_val(pe_dur, cl_hw->conf->ci_pe_duration);
+ return;
+ }
+
+ /*
+ * If STA sets the PPE Threshold Present subfield to 0,
+ * the value should be set according to the Nominal Packet Padding subfield
+ */
+ if ((sta->he_cap.he_cap_elem.phy_cap_info[6] &
+ IEEE80211_HE_PHY_CAP6_PPE_THRESHOLD_PRESENT) == 0) {
+ switch (sta->he_cap.he_cap_elem.phy_cap_info[9] &
+ IEEE80211_HE_PHY_CAP9_NOMIMAL_PKT_PADDING_MASK) {
+ case IEEE80211_HE_PHY_CAP9_NOMIMAL_PKT_PADDING_0US:
+ set_fixed_ppe_val(pe_dur, PPE_0US);
+ break;
+ case IEEE80211_HE_PHY_CAP9_NOMIMAL_PKT_PADDING_8US:
+ set_fixed_ppe_val(pe_dur, PPE_8US);
+ break;
+ case IEEE80211_HE_PHY_CAP9_NOMIMAL_PKT_PADDING_16US:
+ default:
+ set_fixed_ppe_val(pe_dur, PPE_16US);
+ break;
+ }
+
+ return;
+ }
+
+ /*
+ * struct iwl_he_pkt_ext - QAM thresholds
+ * The required PPE is set via HE Capabilities IE, per Nss x BW x MCS
+ * The IE is organized in the following way:
+ * Support for Nss x BW (or RU) matrix:
+ * (0=SISO, 1=MIMO2) x (0-20MHz, 1-40MHz, 2-80MHz, 3-160MHz)
+ * Each entry contains 2 QAM thresholds for 8us and 16us:
+ * 0=BPSK, 1=QPSK, 2=16QAM, 3=64QAM, 4=256QAM, 5=1024QAM, 6=RES, 7=NONE
+ * i.e. QAM_th1 < QAM_th2 such if TX uses QAM_tx:
+ * QAM_tx < QAM_th1 --> PPE=0us
+ * QAM_th1 <= QAM_tx < QAM_th2 --> PPE=8us
+ * QAM_th2 <= QAM_tx --> PPE=16us
+ * @pkt_ext_qam_th: QAM thresholds
+ * For each Nss/Bw define 2 QAM thrsholds (0..5)
+ * For rates below the low_th, no need for PPE
+ * For rates between low_th and high_th, need 8us PPE
+ * For rates equal or higher then the high_th, need 16us PPE
+ * Nss (0-siso, 1-mimo2) x BW (0-20MHz, 1-40MHz, 2-80MHz, 3-160MHz) x
+ * (0-low_th, 1-high_th)
+ */
+ u8 pkt_ext_qam_th[WRS_SS_MAX][CHNL_BW_MAX][QAM_THR_MAX];
+
+ /* If PPE Thresholds exist, parse them into a FW-familiar format. */
+ u8 nss = (sta->he_cap.ppe_thres[0] & IEEE80211_PPE_THRES_NSS_MASK) + 1;
+ u8 ru_index_bitmap = u32_get_bits(sta->he_cap.ppe_thres[0],
+ IEEE80211_PPE_THRES_RU_INDEX_BITMASK_MASK);
+ u8 *ppe = &sta->he_cap.ppe_thres[0];
+ u8 ppe_pos_bit = 7; /* Starting after PPE header */
+ u8 bw, ss, mcs, constellation;
+
+ if (nss > WRS_SS_MAX)
+ nss = WRS_SS_MAX;
+
+ for (ss = 0; ss < nss; ss++) {
+ u8 ru_index_tmp = ru_index_bitmap << 1;
+
+ for (bw = 0; bw <= cl_hw->bw; bw++) {
+ ru_index_tmp >>= 1;
+ if (!(ru_index_tmp & 1))
+ continue;
+
+ pkt_ext_qam_th[ss][bw][QAM_THR_2] = get_ppe_val(ppe, ppe_pos_bit);
+ ppe_pos_bit += IEEE80211_PPE_THRES_INFO_PPET_SIZE;
+ pkt_ext_qam_th[ss][bw][QAM_THR_1] = get_ppe_val(ppe, ppe_pos_bit);
+ ppe_pos_bit += IEEE80211_PPE_THRES_INFO_PPET_SIZE;
+ }
+ }
+
+ /* Reset PE duration before filling it */
+ memset(pe_dur, 0, CHNL_BW_MAX * WRS_MCS_MAX_HE);
+
+ for (ss = 0; ss < nss; ss++) {
+ for (bw = 0; bw <= cl_hw->bw; bw++) {
+ for (mcs = 0; mcs < WRS_MCS_MAX_HE; mcs++) {
+ constellation = mcs_to_constellation[mcs];
+
+ if (constellation < pkt_ext_qam_th[ss][bw][QAM_THR_1])
+ pe_dur[bw][mcs] |= (PPE_0US << (ss * 2));
+ else if (constellation < pkt_ext_qam_th[ss][bw][QAM_THR_2])
+ pe_dur[bw][mcs] |= (PPE_8US << (ss * 2));
+ else
+ pe_dur[bw][mcs] |= (PPE_16US << (ss * 2));
+ }
+ }
+ }
+}
--
2.30.0

________________________________
The information transmitted is intended only for the person or entity to which it is addressed and may contain confidential and/or privileged material. Any retransmission, dissemination, copying or other use of, or taking of any action in reliance upon this information is prohibited. If you received this in error, please contact the sender and delete the material from any computer. Nothing contained herein shall be deemed as a representation, warranty or a commitment by Celeno. No warranties are expressed or implied, including, but not limited to, any implied warranties of non-infringement, merchantability and fitness for a particular purpose.
________________________________

2021-06-17 16:23:31

by viktor.barna

[permalink] [raw]
Subject: [RFC v1 034/256] cl8k: add cecli.c

From: Viktor Barna <[email protected]>

(Part of the split. Please, take a look at the cover letter for more
details).

Signed-off-by: Viktor Barna <[email protected]>
---
drivers/net/wireless/celeno/cl8k/cecli.c | 354 +++++++++++++++++++++++
1 file changed, 354 insertions(+)
create mode 100644 drivers/net/wireless/celeno/cl8k/cecli.c

diff --git a/drivers/net/wireless/celeno/cl8k/cecli.c b/drivers/net/wireless/celeno/cl8k/cecli.c
new file mode 100644
index 000000000000..abe5d4a06f48
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/cecli.c
@@ -0,0 +1,354 @@
+// SPDX-License-Identifier: MIT
+/* Copyright(c) 2019-2021, Celeno Communications Ltd. */
+
+#include "hw.h"
+#include "vif.h"
+#include "cecli.h"
+#include "vendor_cmd.h"
+#include "wrs/wrs_api.h"
+#include "chip.h"
+#include "fw/msg_tx.h"
+#include "channel.h"
+#include "calib.h"
+#include "tx/tx_queue.h"
+#include "tx/tx.h"
+#include "stats.h"
+#include "power_cli.h"
+#include "bf.h"
+#include "edca.h"
+#include "traffic.h"
+#include "reg/reg_cli.h"
+#include "radio.h"
+#include "temperature.h"
+#include "rx/rx_filter.h"
+#include "dfs/dfs.h"
+#include "utils/math.h"
+#include "cecli.h"
+#include "utils/utils.h"
+#include "fw/fw_dbg.h"
+#include "ext/vlan_dscp.h"
+#include "vns.h"
+#include "motion_sense.h"
+#include "version.h"
+#include "enhanced_tim.h"
+#include "rssi.h"
+#include "cca.h"
+#include "noise.h"
+#include "twt_cli.h"
+#include "omi.h"
+#include "config.h"
+
+int cl_cecli_agc_params(struct wiphy *wiphy, struct wireless_dev *wdev,
+ const void *data, int data_len)
+{
+ struct cl_hw *cl_hw = WIPHY_TO_CL_HW(wiphy);
+ struct cli_params *cli_params = (struct cli_params *)data;
+
+ return cl_agc_params_cli(cl_hw, cli_params);
+}
+
+int cl_cecli_bf(struct wiphy *wiphy, struct wireless_dev *wdev,
+ const void *data, int data_len)
+{
+ struct cli_params *cli_params = (struct cli_params *)data;
+ struct cl_hw *cl_hw = WIPHY_TO_CL_HW(wiphy);
+
+ return cl_bf_cli(cl_hw, cli_params);
+}
+
+int cl_cecli_calib(struct wiphy *wiphy, struct wireless_dev *wdev,
+ const void *data, int data_len)
+{
+ struct cl_hw *cl_hw = WIPHY_TO_CL_HW(wiphy);
+ struct cli_params *cli_params = (struct cli_params *)data;
+
+ return cl_calib_cli(cl_hw, cli_params);
+}
+
+int cl_cecli_cca(struct wiphy *wiphy, struct wireless_dev *wdev,
+ const void *data, int data_len)
+{
+ struct cl_hw *cl_hw = WIPHY_TO_CL_HW(wiphy);
+ struct cli_params *cli_params = (struct cli_params *)data;
+
+ return cl_cca_cli(cl_hw, cli_params);
+}
+
+int cl_cecli_chip(struct wiphy *wiphy, struct wireless_dev *wdev,
+ const void *data, int data_len)
+{
+ struct cl_hw *cl_hw = WIPHY_TO_CL_HW(wiphy);
+
+ if (data) {
+ char *str = (char *)data;
+
+ return cl_chip_config_set(cl_hw->chip, str, strlen(str) + 1);
+ }
+
+ return -1;
+}
+
+int cl_cecli_config(struct wiphy *wiphy, struct wireless_dev *wdev,
+ const void *data, int data_len)
+{
+ struct cli_params *cli_params = (struct cli_params *)data;
+ struct cl_hw *cl_hw = WIPHY_TO_CL_HW(wiphy);
+
+ return cl_config_cli(cl_hw, cli_params);
+}
+
+int cl_cecli_debug(struct wiphy *wiphy, struct wireless_dev *wdev,
+ const void *data, int data_len)
+{
+ struct cl_hw *cl_hw = WIPHY_TO_CL_HW(wiphy);
+
+ cl_hw->conf->ce_debug_level = *(s8 *)data;
+ cl_hw->chip->conf->ce_debug_level = *(s8 *)data;
+
+ return 0;
+}
+
+int cl_cecli_dfs(struct wiphy *wiphy, struct wireless_dev *wdev,
+ const void *data, int data_len)
+{
+ struct cl_hw *cl_hw = WIPHY_TO_CL_HW(wiphy);
+ u16 ret_buf_len = PAGE_SIZE;
+ char *ret_buf = kzalloc(ret_buf_len, GFP_KERNEL);
+
+ if (ret_buf) {
+ struct cli_params *cli_params = (struct cli_params *)data;
+
+ if (cl_dfs_cli(cl_hw, cli_params, ret_buf, &ret_buf_len))
+ cl_vendor_reply(cl_hw, ret_buf, (int)ret_buf_len);
+
+ kfree(ret_buf);
+ } else {
+ return -ENOMEM;
+ }
+
+ return 0;
+}
+
+int cl_cecli_edca(struct wiphy *wiphy, struct wireless_dev *wdev,
+ const void *data, int data_len)
+{
+ struct cl_hw *cl_hw = WIPHY_TO_CL_HW(wiphy);
+ struct cli_params *cli_params = (struct cli_params *)data;
+
+ return cl_edca_cli(cl_hw, cli_params);
+}
+
+int cl_cecli_fw(struct wiphy *wiphy, struct wireless_dev *wdev,
+ const void *data, int data_len)
+{
+ struct cli_params *cli_params = (struct cli_params *)data;
+ struct cl_hw *cl_hw = WIPHY_TO_CL_HW(wiphy);
+
+ return cl_fw_dbg_cli(cl_hw, cli_params);
+}
+
+int cl_cecli_motion(struct wiphy *wiphy, struct wireless_dev *wdev,
+ const void *data, int data_len)
+{
+ struct cli_params *cli_params = (struct cli_params *)data;
+ struct cl_hw *cl_hw = WIPHY_TO_CL_HW(wiphy);
+
+ return cl_motion_sense_cli(cl_hw, cli_params);
+}
+
+int cl_cecli_noise(struct wiphy *wiphy, struct wireless_dev *wdev,
+ const void *data, int data_len)
+{
+ struct cl_hw *cl_hw = WIPHY_TO_CL_HW(wiphy);
+ struct cli_params *cli_params = (struct cli_params *)data;
+
+ return cl_noise_cli(cl_hw, cli_params);
+}
+
+int cl_cecli_omi(struct wiphy *wiphy, struct wireless_dev *wdev,
+ const void *data, int data_len)
+{
+ struct cli_params *cli_params = (struct cli_params *)data;
+ struct cl_hw *cl_hw = WIPHY_TO_CL_HW(wiphy);
+
+ return cl_omi_cli(cl_hw, cli_params);
+}
+
+int cl_cecli_power(struct wiphy *wiphy, struct wireless_dev *wdev,
+ const void *data, int data_len)
+{
+ struct cl_hw *cl_hw = WIPHY_TO_CL_HW(wiphy);
+ struct cli_params *cli_params = (struct cli_params *)data;
+
+ return cl_power_cli(cl_hw, cli_params);
+}
+
+int cl_cecli_qos(struct wiphy *wiphy, struct wireless_dev *wdev,
+ const void *data, int data_len)
+{
+ struct cl_hw *cl_hw = WIPHY_TO_CL_HW(wiphy);
+ struct cl_vif *cl_vif = NETDEV_TO_CL_VIF(wdev->netdev);
+
+ return data ? cl_vlan_dscp_cli(cl_hw, cl_vif, (char *)data) : -1;
+}
+
+int cl_cecli_radio(struct wiphy *wiphy, struct wireless_dev *wdev,
+ const void *data, int data_len)
+{
+ struct cl_hw *cl_hw = WIPHY_TO_CL_HW(wiphy);
+ bool radio_on = *(bool *)data;
+
+ return cl_radio_cli(cl_hw, radio_on);
+}
+
+int cl_cecli_reg(struct wiphy *wiphy, struct wireless_dev *wdev,
+ const void *data, int data_len)
+{
+ struct cli_params *cli_params = (struct cli_params *)data;
+ struct cl_hw *cl_hw = WIPHY_TO_CL_HW(wiphy);
+
+ return cl_reg_cli(cl_hw, cli_params);
+}
+
+int cl_cecli_sounding(struct wiphy *wiphy, struct wireless_dev *wdev,
+ const void *data, int data_len)
+{
+ struct cli_params *cli_params = (struct cli_params *)data;
+ struct cl_hw *cl_hw = WIPHY_TO_CL_HW(wiphy);
+
+ return cl_sounding_cli(cl_hw, cli_params);
+}
+
+int cl_cecli_stats(struct wiphy *wiphy, struct wireless_dev *wdev,
+ const void *data, int data_len)
+{
+ struct cl_hw *cl_hw = WIPHY_TO_CL_HW(wiphy);
+ struct cl_vif *cl_vif = NETDEV_TO_CL_VIF(wdev->netdev);
+ struct cli_params *cli_params = (struct cli_params *)data;
+
+ return cl_stats_cli(cl_hw, cl_vif, cli_params);
+}
+
+int cl_cecli_tcv(struct wiphy *wiphy, struct wireless_dev *wdev,
+ const void *data, int data_len)
+{
+ struct cl_hw *cl_hw = WIPHY_TO_CL_HW(wiphy);
+
+ if (data) {
+ char *str = (char *)data;
+
+ return cl_tcv_config_set(cl_hw, str, strlen(str) + 1);
+ }
+
+ return -1;
+}
+
+int cl_cecli_temp(struct wiphy *wiphy, struct wireless_dev *wdev,
+ const void *data, int data_len)
+{
+ struct cl_hw *cl_hw = WIPHY_TO_CL_HW(wiphy);
+ struct cli_params *cli_params = (struct cli_params *)data;
+
+ cl_temperature_cli(cl_hw, cli_params);
+ return 0;
+}
+
+int cl_cecli_traffic(struct wiphy *wiphy, struct wireless_dev *wdev,
+ const void *data, int data_len)
+{
+ struct cli_params *cli_params = (struct cli_params *)data;
+ struct cl_hw *cl_hw = WIPHY_TO_CL_HW(wiphy);
+
+ return cl_traffic_cli(cl_hw, cli_params);
+}
+
+int cl_cecli_twt(struct wiphy *wiphy, struct wireless_dev *wdev,
+ const void *data, int data_len)
+{
+ struct cli_params *cli_params = (struct cli_params *)data;
+ struct cl_hw *cl_hw = WIPHY_TO_CL_HW(wiphy);
+
+ return cl_twt_cli(cl_hw, cli_params);
+}
+
+int cl_cecli_txq(struct wiphy *wiphy, struct wireless_dev *wdev,
+ const void *data, int data_len)
+{
+ struct cli_params *cli_params = (struct cli_params *)data;
+ struct cl_hw *cl_hw = WIPHY_TO_CL_HW(wiphy);
+
+ return cl_txq_cli(cl_hw, cli_params);
+}
+
+int cl_cecli_version(struct wiphy *wiphy, struct wireless_dev *wdev,
+ const void *data, int data_len)
+{
+ struct cl_hw *cl_hw = WIPHY_TO_CL_HW(wiphy);
+
+ cl_version_cli(cl_hw);
+ return 0;
+}
+
+int cl_cecli_vns(struct wiphy *wiphy, struct wireless_dev *wdev,
+ const void *data, int data_len)
+{
+ struct cli_params *cli_params = (struct cli_params *)data;
+ struct cl_hw *cl_hw = WIPHY_TO_CL_HW(wiphy);
+
+ return cl_vns_cli(cl_hw, cli_params);
+}
+
+int cl_cecli_wrs(struct wiphy *wiphy, struct wireless_dev *wdev,
+ const void *data, int data_len)
+{
+ struct cli_params *cli_params = (struct cli_params *)data;
+ struct cl_vif *cl_vif = NETDEV_TO_CL_VIF(wdev->netdev);
+ struct cl_hw *cl_hw = WIPHY_TO_CL_HW(wiphy);
+
+ return cl_wrs_api_cli(cl_hw, cl_vif, cli_params);
+}
+
+int cl_cecli_help(struct wiphy *wiphy, struct wireless_dev *wdev,
+ const void *data, int data_len)
+{
+ struct cl_hw *cl_hw = WIPHY_TO_CL_HW(wiphy);
+ char *ret_buf = kzalloc(PAGE_SIZE, GFP_KERNEL);
+ int err = 0;
+
+ if (!ret_buf)
+ return -ENOMEM;
+
+ snprintf(ret_buf, PAGE_SIZE,
+ "usage:\n"
+ "agc_params - AGC params\n"
+ "bf - Beem Forming\n"
+ "cca - CCA related\n"
+ "chip - Set nvram per chip\n"
+ "config - Debug configuration\n"
+ "debug - Set Debug level\n"
+ "dfs - Dynamic Frequency Selection\n"
+ "edca - Enhanced Distributed Channel Access\n"
+ "fw - Firmware related\n"
+ "motion - Motion feature\n"
+ "noise - Noise related\n"
+ "omi - OM infrastructure\n"
+ "power - Power related\n"
+ "qos - Quality Of Service\n"
+ "radio - Set radio on/off\n"
+ "reg - Register related\n"
+ "sounding - Sounding related\n"
+ "stats - Statistics related\n"
+ "tcv - Set nvram per tcv\n"
+ "temp - Temperature related\n"
+ "traffic - Traffic related\n"
+ "twt - Target Wake Time\n"
+ "txq - TX queue\n"
+ "version - Read Version\n"
+ "vns - Very Near Station\n"
+ "wrs - Weighted Rate Selection\n");
+
+ err = cl_vendor_reply(cl_hw, ret_buf, strlen(ret_buf));
+ kfree(ret_buf);
+
+ return err;
+}
--
2.30.0

________________________________
The information transmitted is intended only for the person or entity to which it is addressed and may contain confidential and/or privileged material. Any retransmission, dissemination, copying or other use of, or taking of any action in reliance upon this information is prohibited. If you received this in error, please contact the sender and delete the material from any computer. Nothing contained herein shall be deemed as a representation, warranty or a commitment by Celeno. No warranties are expressed or implied, including, but not limited to, any implied warranties of non-infringement, merchantability and fitness for a particular purpose.
________________________________

2021-06-17 16:23:31

by viktor.barna

[permalink] [raw]
Subject: [RFC v1 016/256] cl8k: add bf.h

From: Viktor Barna <[email protected]>

(Part of the split. Please, take a look at the cover letter for more
details).

Signed-off-by: Viktor Barna <[email protected]>
---
drivers/net/wireless/celeno/cl8k/bf.h | 32 +++++++++++++++++++++++++++
1 file changed, 32 insertions(+)
create mode 100644 drivers/net/wireless/celeno/cl8k/bf.h

diff --git a/drivers/net/wireless/celeno/cl8k/bf.h b/drivers/net/wireless/celeno/cl8k/bf.h
new file mode 100644
index 000000000000..eb7f0000b2c6
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/bf.h
@@ -0,0 +1,32 @@
+/* SPDX-License-Identifier: MIT */
+/* Copyright(c) 2019-2021, Celeno Communications Ltd. */
+
+#ifndef CL_BF_H
+#define CL_BF_H
+
+#include "fw/fw_msg.h"
+#include "debug.h"
+#include "hw.h"
+#include "sta.h"
+
+/**
+ * BF (=BeamForming, 802.11)
+ */
+
+void cl_bf_update_rate(struct cl_hw *cl_hw, struct cl_sta *cl_sta);
+void cl_bf_sta_add(struct cl_hw *cl_hw, struct cl_sta *cl_sta, struct ieee80211_sta *sta);
+void cl_bf_sta_remove(struct cl_hw *cl_hw, struct cl_sta *cl_sta);
+void cl_bf_sta_active(struct cl_hw *cl_hw, struct cl_sta *cl_sta, bool active);
+void cl_bf_reset_sounding_ind(struct cl_hw *cl_hw, struct cl_sta *cl_sta);
+bool cl_bf_is_enabled(struct cl_hw *cl_hw);
+int cl_bf_cli(struct cl_hw *cl_hw, struct cli_params *cli_params);
+bool cl_bf_is_on(struct cl_hw *cl_hw, struct cl_sta *cl_sta, u8 nss);
+void cl_bf_enable(struct cl_hw *cl_hw, bool enable);
+void cl_bf_sounding_start(struct cl_hw *cl_hw, enum sounding_type type, struct cl_sta **cl_sta_arr,
+ u8 sta_num, struct cl_sounding_info *recovery_elem);
+void cl_bf_sounding_stop(struct cl_hw *cl_hw, struct cl_sta *cl_sta);
+void cl_bf_sounding_decision(struct cl_hw *cl_hw, struct cl_sta *cl_sta);
+void cl_bf_sounding_req_success(struct cl_hw *cl_hw, struct cl_sounding_info *new_elem);
+void cl_bf_sounding_req_failure(struct cl_hw *cl_hw, struct cl_sounding_info *new_elem);
+
+#endif /* CL_BF_H */
--
2.30.0

________________________________
The information transmitted is intended only for the person or entity to which it is addressed and may contain confidential and/or privileged material. Any retransmission, dissemination, copying or other use of, or taking of any action in reliance upon this information is prohibited. If you received this in error, please contact the sender and delete the material from any computer. Nothing contained herein shall be deemed as a representation, warranty or a commitment by Celeno. No warranties are expressed or implied, including, but not limited to, any implied warranties of non-infringement, merchantability and fitness for a particular purpose.
________________________________

2021-06-17 16:23:36

by viktor.barna

[permalink] [raw]
Subject: [RFC v1 032/256] cl8k: add cca.c

From: Viktor Barna <[email protected]>

(Part of the split. Please, take a look at the cover letter for more
details).

Signed-off-by: Viktor Barna <[email protected]>
---
drivers/net/wireless/celeno/cl8k/cca.c | 518 +++++++++++++++++++++++++
1 file changed, 518 insertions(+)
create mode 100644 drivers/net/wireless/celeno/cl8k/cca.c

diff --git a/drivers/net/wireless/celeno/cl8k/cca.c b/drivers/net/wireless/celeno/cl8k/cca.c
new file mode 100644
index 000000000000..70f1d54b771b
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/cca.c
@@ -0,0 +1,518 @@
+// SPDX-License-Identifier: MIT
+/* Copyright(c) 2019-2021, Celeno Communications Ltd. */
+
+#include "cca.h"
+#include "reg/reg_mac_hw.h"
+#include "reg/reg_riu.h"
+#include "band.h"
+#include "hw.h"
+
+#define TO_PERCENT(val, interval) (100 * (val) / (interval))
+#define SET_CCA_OPT(en, a, b) ((en) ? ((a) |= (b)) : ((a) &= ~(b)))
+#define MDM_AFTER_L_SIG 0x3F0
+#define MDM_BEFORE_L_SIG 0x3F8
+#define SAMPLE_RES 5
+
+static void cl_cca_print_cs(struct cl_hw *cl_hw, unsigned long time)
+{
+ u8 cca_cs = TO_PERCENT(riu_cca_cnt_cs_get(cl_hw), time);
+
+ pr_debug("cca_cs = %u%%\n", cca_cs);
+}
+
+static void cl_cca_print_mdm_state(struct cl_hw *cl_hw, unsigned long time)
+{
+ u32 cca_mdm_state_p = TO_PERCENT(riu_cca_cnt_modem_state_p_get(cl_hw), time);
+ u32 cca_mdm_state_20s = TO_PERCENT(riu_cca_cnt_modem_state_20_s_get(cl_hw), time);
+ u32 cca_mdm_state_40s = TO_PERCENT(riu_cca_cnt_modem_state_40_s_get(cl_hw), time);
+ u32 cca_mdm_state_80s = TO_PERCENT(riu_cca_cnt_modem_state_80_s_get(cl_hw), time);
+
+ pr_debug("cca_mdm_state: primary = %u%%, sec20 = %u%%, sec40 = %u%%, sec80 = %u%%\n",
+ cca_mdm_state_p, cca_mdm_state_20s, cca_mdm_state_40s, cca_mdm_state_80s);
+}
+
+static void cl_cca_print_mp(struct cl_hw *cl_hw, unsigned long time)
+{
+ u32 cca_mp_20p = TO_PERCENT(riu_cca_cnt_gi_20_p_get(cl_hw), time);
+ u32 cca_mp_20s = TO_PERCENT(riu_cca_cnt_gi_20_s_get(cl_hw), time);
+ u32 cca_mp_40s = TO_PERCENT(riu_cca_cnt_gi_40_s_get(cl_hw), time);
+ u32 cca_mp_80s = TO_PERCENT(riu_cca_cnt_gi_80_s_get(cl_hw), time);
+
+ pr_debug("cca_mp: primary = %u%%, sec20 = %u%%, sec40 = %u, sec80 = %u%%\n",
+ cca_mp_20p, cca_mp_20s, cca_mp_40s, cca_mp_80s);
+}
+
+static void cl_cca_print_energy(struct cl_hw *cl_hw, unsigned long time)
+{
+ u32 cca_energy_thr_p = TO_PERCENT(riu_cca_cnt_energy_thr_p_get(cl_hw), time);
+ u32 cca_energy_thr_20s = TO_PERCENT(riu_cca_cnt_energy_thr_20_s_get(cl_hw), time);
+ u32 cca_energy_thr_40s = TO_PERCENT(riu_cca_cnt_energy_thr_40_s_get(cl_hw), time);
+ u32 cca_energy_thr_80s = TO_PERCENT(riu_cca_cnt_energy_thr_80_s_get(cl_hw), time);
+
+ pr_debug("cca_energy_thr: primary = %u%%, sec20 = %u%%, sec40 = (%u%%), sec80 = %u%%\n",
+ cca_energy_thr_p, cca_energy_thr_20s, cca_energy_thr_40s, cca_energy_thr_80s);
+}
+
+static void cl_cca_print_energy_band(struct cl_hw *cl_hw, unsigned long time)
+{
+ u32 cca_energy_20_band0 = TO_PERCENT(riu_cca_cnt_energy_thr_20_band_0_get(cl_hw), time);
+ u32 cca_energy_20_band1 = TO_PERCENT(riu_cca_cnt_energy_thr_20_band_1_get(cl_hw), time);
+ u32 cca_energy_20_band2 = TO_PERCENT(riu_cca_cnt_energy_thr_20_band_2_get(cl_hw), time);
+ u32 cca_energy_20_band3 = TO_PERCENT(riu_cca_cnt_energy_thr_20_band_3_get(cl_hw), time);
+ u32 cca_energy_20_band4 = TO_PERCENT(riu_cca_cnt_energy_thr_20_band_4_get(cl_hw), time);
+ u32 cca_energy_20_band5 = TO_PERCENT(riu_cca_cnt_energy_thr_20_band_5_get(cl_hw), time);
+ u32 cca_energy_20_band6 = TO_PERCENT(riu_cca_cnt_energy_thr_20_band_6_get(cl_hw), time);
+ u32 cca_energy_20_band7 = TO_PERCENT(riu_cca_cnt_energy_thr_20_band_7_get(cl_hw), time);
+
+ pr_debug("cca_energy_20: band0 = %u%%, band1 = %u%%, band2 = %u%%, band3 = %u%%, "
+ "band4 = %u%%, band5 = %u%%, band6 = %u%%, band7 = %u%%\n",
+ cca_energy_20_band0, cca_energy_20_band1, cca_energy_20_band2,
+ cca_energy_20_band3, cca_energy_20_band4, cca_energy_20_band5,
+ cca_energy_20_band6, cca_energy_20_band7);
+}
+
+static void cl_cca_update_counters(u16 *hist, u32 counter)
+{
+ if (counter == 0)
+ hist[0]++;
+ else if (counter > 100)
+ hist[CCA_MAX_SAMPLE - 1]++;
+ else
+ hist[((counter - 1) / SAMPLE_RES) + 1]++;
+}
+
+static void cl_cca_print_utility(struct cl_hw *cl_hw, unsigned long time)
+{
+ struct cl_cca_db *cca_db = &cl_hw->cca_db;
+ struct cl_edca_hist_db *hist_db = &cca_db->edca_hist;
+ u32 cca_cs = riu_cca_cnt_cs_get(cl_hw);
+ u32 edca_busy = mac_hw_edca_cca_busy_get(cl_hw);
+ u32 cca_mdm_state_p = riu_cca_cnt_modem_state_p_get(cl_hw);
+ u32 tx_mine = mac_hw_tx_mine_busy_get(cl_hw);
+ u32 rx_mine = mac_hw_rx_mine_busy_get(cl_hw);
+ u32 sample_cnt = hist_db->sample_cnt;
+ u32 edca_busy_diff = edca_busy - cca_db->edca_busy;
+ u32 tx_mine_diff = tx_mine - cca_db->tx_mine;
+ u32 rx_mine_diff = rx_mine - cca_db->rx_mine;
+
+ /* Cca utility formulas */
+ u32 air_util = cca_cs + tx_mine_diff;
+ u32 wifi_air_util = cca_mdm_state_p + tx_mine_diff;
+ u32 not_mine_rx_wifi = cca_mdm_state_p - rx_mine_diff;
+ u32 mine_util = tx_mine_diff + rx_mine_diff;
+ u32 non_wifi_util = edca_busy_diff - cca_mdm_state_p;
+ u32 not_mine_util = edca_busy_diff - rx_mine_diff;
+ u32 not_mine_time = time - mine_util;
+
+ u32 air_util_percent = TO_PERCENT(air_util, time);
+ u32 wifi_air_util_percent = TO_PERCENT(wifi_air_util, time);
+ u32 not_mine_rx_wifi_percent = TO_PERCENT(not_mine_rx_wifi, time);
+ u32 mine_util_percent = TO_PERCENT(mine_util, time);
+ u32 non_wifi_util_percent = TO_PERCENT(non_wifi_util, time);
+ u32 not_mine_util_percent = TO_PERCENT(not_mine_util, time);
+ u32 not_mine_busy_util_percent =
+ (not_mine_time > 0) ? TO_PERCENT(not_mine_util, not_mine_time) : 0;
+
+ cca_db->edca_busy = edca_busy;
+ cca_db->tx_mine = tx_mine;
+ cca_db->rx_mine = rx_mine;
+
+ if (sample_cnt > 0) {
+ cl_cca_update_counters(hist_db->air_util, air_util_percent);
+ cl_cca_update_counters(hist_db->wifi_air_util, wifi_air_util_percent);
+ cl_cca_update_counters(hist_db->not_mine_rx_wifi, not_mine_rx_wifi_percent);
+ cl_cca_update_counters(hist_db->mine, mine_util_percent);
+ cl_cca_update_counters(hist_db->non_wifi_util, non_wifi_util_percent);
+ cl_cca_update_counters(hist_db->not_mine, not_mine_util_percent);
+ cl_cca_update_counters(hist_db->not_mine_busy, not_mine_busy_util_percent);
+
+ hist_db->sample_cnt--;
+
+ /* Stop sampling */
+ if (hist_db->sample_cnt == 0) {
+ SET_CCA_OPT(0, cca_db->cca_opt, CCA_OPT_REC_HIST);
+ pr_debug("Record is done\n");
+ }
+ }
+
+ if (cca_db->cca_opt & CCA_OPT_UTIL)
+ pr_debug("air_util = %u%%, wifi_air_util = %u%%, not_mine_rx_wifi = %u%%, "
+ "mine_util = %u%%, non_wifi_util = %u%%, not_mine_util = %u%%, "
+ "not_mine_busy_util = %u%%\n",
+ air_util_percent, wifi_air_util_percent, not_mine_rx_wifi,
+ mine_util_percent, non_wifi_util_percent, not_mine_util_percent,
+ not_mine_busy_util_percent);
+}
+
+static void cl_cca_print_tx_rx_mine(struct cl_hw *cl_hw, unsigned long time)
+{
+ struct cl_cca_db *cca_db = &cl_hw->cca_db;
+
+ u32 tx_mine = mac_hw_tx_mine_busy_get(cl_hw);
+ u32 rx_mine = mac_hw_rx_mine_busy_get(cl_hw);
+
+ u32 diff_tx_mine = tx_mine - cca_db->print_tx_mine;
+ u32 diff_rx_mine = rx_mine - cca_db->print_rx_mine;
+
+ cca_db->print_tx_mine = tx_mine;
+ cca_db->print_rx_mine = rx_mine;
+
+ pr_debug("tx_mine = %u (%lu%%), rx_mine = %u (%lu%%)\n",
+ diff_tx_mine,
+ TO_PERCENT(diff_tx_mine, time),
+ diff_rx_mine,
+ TO_PERCENT(diff_rx_mine, time));
+}
+
+static void cl_cca_edca(struct cl_hw *cl_hw, unsigned long time)
+{
+ struct cl_cca_db *cca_db = &cl_hw->cca_db;
+ bool is_24g = cl_band_is_24g(cl_hw);
+ bool sec80 = !is_24g;
+
+ u32 new_edca_busy = mac_hw_edca_cca_busy_get(cl_hw);
+ u32 new_edca_busy_sec20 = mac_hw_add_cca_busy_sec_20_get(cl_hw);
+ u32 new_edca_busy_sec40 = is_24g ? 0 : mac_hw_add_cca_busy_sec_40_get(cl_hw);
+ u32 new_edca_busy_sec80 = sec80 ? mac_hw_add_cca_busy_sec_80_get(cl_hw) : 0;
+
+ u32 diff_edca_busy = new_edca_busy - cca_db->edca_busy;
+ u32 diff_edca_busy_sec20 = new_edca_busy_sec20 - cca_db->edca_busy_sec20;
+ u32 diff_edca_busy_sec40 = new_edca_busy_sec40 - cca_db->edca_busy_sec40;
+ u32 diff_edca_busy_sec80 = new_edca_busy_sec80 - cca_db->edca_busy_sec80;
+
+ u32 percent_edca_busy = TO_PERCENT(diff_edca_busy, time);
+ u32 percent_edca_busy_sec20 = TO_PERCENT(diff_edca_busy_sec20, time);
+ u32 percent_edca_busy_sec40 = TO_PERCENT(diff_edca_busy_sec40, time);
+ u32 percent_edca_busy_sec80 = TO_PERCENT(diff_edca_busy_sec80, time);
+
+ cca_db->edca_busy = new_edca_busy;
+ cca_db->edca_busy_sec20 = new_edca_busy_sec20;
+ cca_db->edca_busy_sec40 = new_edca_busy_sec40;
+ cca_db->edca_busy_sec80 = new_edca_busy_sec80;
+
+ pr_debug("edca_busy: primary = %u (%u%%), sec20 = %u (%u%%), "
+ "sec40 = %u (%u%%), sec80 = %u (%u%%)\n",
+ diff_edca_busy, percent_edca_busy,
+ diff_edca_busy_sec20, percent_edca_busy_sec20,
+ diff_edca_busy_sec40, percent_edca_busy_sec40,
+ diff_edca_busy_sec80, percent_edca_busy_sec80);
+}
+
+static void cl_cca_print_edca_nav(struct cl_hw *cl_hw, unsigned long time)
+{
+ struct cl_cca_db *cca_db = &cl_hw->cca_db;
+
+ u32 new_cca_busy_nav = mac_hw_edca_nav_busy_get(cl_hw);
+ u32 new_cca_intra_bss_nav = mac_hw_intra_bss_nav_busy_get(cl_hw);
+ u32 new_cca_inter_bss_nav = mac_hw_inter_bss_nav_busy_get(cl_hw);
+
+ u32 diff_cca_busy_nav = new_cca_busy_nav - cca_db->cca_busy_nav;
+ u32 diff_cca_intra_bss_nav = new_cca_intra_bss_nav - cca_db->cca_intra_bss_nav;
+ u32 diff_cca_inter_bss_nav = new_cca_inter_bss_nav - cca_db->cca_inter_bss_nav;
+
+ u32 percent_cca_busy_nav = TO_PERCENT(diff_cca_busy_nav, time);
+ u32 percent_cca_intra_bss_nav = TO_PERCENT(diff_cca_intra_bss_nav, time);
+ u32 percent_cca_inter_bss_nav = TO_PERCENT(diff_cca_inter_bss_nav, time);
+
+ cca_db->cca_busy_nav = new_cca_busy_nav;
+ cca_db->cca_intra_bss_nav = new_cca_intra_bss_nav;
+ cca_db->cca_inter_bss_nav = new_cca_inter_bss_nav;
+
+ pr_debug("cca_busy_nav = %u%%, cca_intra_bass_nav = %u%%, cca_inter_bass_nav = %u%%\n",
+ percent_cca_busy_nav, percent_cca_intra_bss_nav, percent_cca_inter_bss_nav);
+}
+
+static int cl_cca_cli_help(struct cl_hw *cl_hw)
+{
+ char *buf = kzalloc(PAGE_SIZE, GFP_KERNEL);
+ int err = 0;
+
+ if (!buf)
+ return -ENOMEM;
+
+ snprintf(buf, PAGE_SIZE,
+ "cca usage:\n"
+ "-a : Print TX mine and RX mine [0-dis, 1-en]\n"
+ "-b : Print energy detect registers per20 [0-dis, 1-en]\n"
+ "-c : Print EDCA registers [0-dis, 1-en]\n"
+ "-d : Enable/Disable CCA statistics - [0-dis, 0xff-en all]\n"
+ "-e : Print energy detect registers [0-dis, 1-en]\n"
+ "-g : Print mid-packet registers [0-dis, 1-en]\n"
+ "-h : Print histogram [0-reset, 1-print]\n"
+ "-i : Print NAV busy registers [0-dis, 1-en]\n"
+ "-m : Print modem-state registers [0-dis, 1-en]\n"
+ "-n : Set modem-state registers [0-before L-SIG, 1-after L-SIG]\n"
+ "-r : Record histogram [samples #]\n"
+ "-s : Print carrier-sense register [0-dis, 1-en]\n"
+ "-u : Print CCA utility [0-dis, 1-en]\n");
+
+ err = cl_vendor_reply(cl_hw, buf, strlen(buf));
+ kfree(buf);
+
+ return err;
+}
+
+static bool cl_cca_is_hist_empty(struct cl_edca_hist_db *hist_db, u8 cnt)
+{
+ if (!hist_db->air_util[cnt] &&
+ !hist_db->mine[cnt] &&
+ !hist_db->non_wifi_util[cnt] &&
+ !hist_db->not_mine[cnt] &&
+ !hist_db->not_mine_busy[cnt] &&
+ !hist_db->not_mine_rx_wifi[cnt] &&
+ !hist_db->wifi_air_util[cnt])
+ return true;
+
+ return false;
+}
+
+static void cl_cca_print_histogram(struct cl_hw *cl_hw)
+{
+ struct cl_edca_hist_db *hist_db = &cl_hw->cca_db.edca_hist;
+ u8 i = 0;
+ u8 range = 1;
+
+ pr_debug("|---------------------------------------------------------------|\n");
+ pr_debug("|Samples|AirUtil|WifiAir|NonWifi|Mine |NotMine|NotMine|NotMine|\n");
+ pr_debug("| | |Util |Util | | |Busy |RxWifi |\n");
+ pr_debug("|-------+-------+-------+-------+-------+-------+-------+-------|\n");
+
+ for (i = 0; i < CCA_MAX_SAMPLE; i++) {
+ if (cl_cca_is_hist_empty(hist_db, i))
+ continue;
+
+ if (i > 1)
+ range = ((i - 1) * SAMPLE_RES) + 1;
+
+ if (i != 0)
+ pr_debug("|%3u-%-3u| %5u | %5u | %5u | %5u | %5u | %5u | %5u |\n",
+ range, range + SAMPLE_RES - 1, hist_db->air_util[i],
+ hist_db->wifi_air_util[i], hist_db->non_wifi_util[i],
+ hist_db->mine[i], hist_db->not_mine[i],
+ hist_db->not_mine_busy[i], hist_db->not_mine_rx_wifi[i]);
+ else
+ pr_debug("|0 | %5u | %5u | %5u | %5u | %5u | %5u | %5u |\n",
+ hist_db->air_util[i], hist_db->wifi_air_util[i],
+ hist_db->non_wifi_util[i], hist_db->mine[i],
+ hist_db->not_mine[i], hist_db->not_mine_busy[i],
+ hist_db->not_mine_rx_wifi[i]);
+ }
+
+ pr_debug("|---------------------------------------------------------------|\n");
+}
+
+static void cl_cca_opt_update(struct cl_hw *cl_hw, u32 cca_opt_prev)
+{
+ struct cl_cca_db *cca_db = &cl_hw->cca_db;
+ u32 cca_opt_new = cca_db->cca_opt;
+
+ if (cca_opt_prev == 0 && cca_opt_new != 0) {
+ cca_db->time = jiffies_to_usecs(jiffies);
+ riu_rwnxagccca_1_cca_cnt_clear_setf(cl_hw, 0);
+ }
+
+ if (((cca_opt_prev & CCA_OPT_TX_RX_MINE) != CCA_OPT_TX_RX_MINE) &&
+ (cca_opt_new & CCA_OPT_TX_RX_MINE)) {
+ cca_db->print_tx_mine = mac_hw_tx_mine_busy_get(cl_hw);
+ cca_db->print_rx_mine = mac_hw_rx_mine_busy_get(cl_hw);
+ }
+
+ if (((cca_opt_prev & CCA_OPT_UTIL) != CCA_OPT_UTIL) &&
+ (cca_opt_new & CCA_OPT_UTIL)) {
+ cca_db->tx_mine = mac_hw_tx_mine_busy_get(cl_hw);
+ cca_db->rx_mine = mac_hw_rx_mine_busy_get(cl_hw);
+ cca_db->edca_busy = mac_hw_edca_cca_busy_get(cl_hw);
+ }
+}
+
+int cl_cca_cli(struct cl_hw *cl_hw, struct cli_params *cli_params)
+{
+ struct cl_cca_db *cca_db = &cl_hw->cca_db;
+ u32 cca_opt_prev = cca_db->cca_opt;
+ u32 expected_params = -1;
+ u32 param = (u32)cli_params->params[0];
+ bool print_tx_rx_mine = false;
+ bool print_energy_band = false;
+ bool print_edca = false;
+ bool print_all = false;
+ bool print_energy = false;
+ bool print_mp = false;
+ bool print_histogram = false;
+ bool print_nav_edca = false;
+ bool print_mdm = false;
+ bool set_mdm = false;
+ bool record_histogram = false;
+ bool print_cs = false;
+ bool print_util = false;
+
+ switch (cli_params->option) {
+ case 'a':
+ print_tx_rx_mine = true;
+ expected_params = 1;
+ break;
+ case 'b':
+ print_energy_band = true;
+ expected_params = 1;
+ break;
+ case 'c':
+ print_edca = true;
+ expected_params = 1;
+ break;
+ case 'd':
+ print_all = true;
+ expected_params = 1;
+ break;
+ case 'e':
+ print_energy = true;
+ expected_params = 1;
+ break;
+ case 'g':
+ print_mp = true;
+ expected_params = 1;
+ break;
+ case 'h':
+ print_histogram = true;
+ expected_params = 1;
+ break;
+ case 'i':
+ print_nav_edca = true;
+ expected_params = 1;
+ break;
+ case 'm':
+ print_mdm = true;
+ expected_params = 1;
+ break;
+ case 'n':
+ set_mdm = true;
+ expected_params = 1;
+ break;
+ case 'r':
+ record_histogram = true;
+ expected_params = 1;
+ break;
+ case 's':
+ print_cs = true;
+ expected_params = 1;
+ break;
+ case 'u':
+ print_util = true;
+ expected_params = 1;
+ break;
+ case '?':
+ return cl_cca_cli_help(cl_hw);
+ default:
+ cl_dbg_err(cl_hw, "Illegal option (%c) - try '?' for help\n", cli_params->option);
+ goto out_err;
+ }
+
+ if (expected_params != cli_params->num_params) {
+ cl_dbg_err(cl_hw, "Wrong number of arguments (expected %u) (actual %u)\n",
+ expected_params, cli_params->num_params);
+ goto out_err;
+ }
+
+ if (print_tx_rx_mine)
+ SET_CCA_OPT(param, cca_db->cca_opt, CCA_OPT_TX_RX_MINE);
+
+ if (print_energy_band)
+ SET_CCA_OPT(param, cca_db->cca_opt, CCA_OPT_CNT_ENERGY_BAND);
+
+ if (print_all)
+ cca_db->cca_opt = param;
+
+ if (print_edca)
+ SET_CCA_OPT(param, cca_db->cca_opt, CCA_OPT_EDCA);
+
+ if (print_energy)
+ SET_CCA_OPT(param, cca_db->cca_opt, CCA_OPT_CNT_ENERGY);
+
+ if (print_mp)
+ SET_CCA_OPT(param, cca_db->cca_opt, CCA_OPT_CNT_MP);
+
+ if (print_histogram) {
+ if (param)
+ cl_cca_print_histogram(cl_hw);
+ else
+ memset(&cca_db->edca_hist, 0, sizeof(struct cl_edca_hist_db));
+
+ return 0;
+ }
+
+ if (print_nav_edca)
+ SET_CCA_OPT(param, cca_db->cca_opt, CCA_OPT_EDCA_NAV);
+
+ if (print_mdm)
+ SET_CCA_OPT(param, cca_db->cca_opt, CCA_OPT_CNT_MDM_STATE);
+
+ if (set_mdm) {
+ u16 psel = param ? MDM_AFTER_L_SIG : MDM_BEFORE_L_SIG;
+
+ pr_debug("Modem state register set to : %s L-SIG detection!\n",
+ param ? "after" : "before");
+ riu_rwnxagcccastate_0_rxstatecca_20_psel_setf(cl_hw, psel);
+
+ return 0;
+ }
+
+ if (record_histogram) {
+ pr_debug("%s recording samples\n", param ? "Start" : "Stop");
+ cca_db->edca_hist.sample_cnt = param;
+ SET_CCA_OPT(!!param, cca_db->cca_opt, CCA_OPT_REC_HIST);
+ }
+
+ if (print_cs)
+ SET_CCA_OPT(param, cca_db->cca_opt, CCA_OPT_CNT_CS);
+
+ if (print_util)
+ SET_CCA_OPT(param, cca_db->cca_opt, CCA_OPT_UTIL);
+
+ cl_cca_opt_update(cl_hw, cca_opt_prev);
+ return 0;
+
+out_err:
+ return -EIO;
+}
+
+void cl_cca_maintenance(struct cl_hw *cl_hw)
+{
+ struct cl_cca_db *cca_db = &cl_hw->cca_db;
+ unsigned long time = jiffies_to_usecs(jiffies);
+ unsigned long diff_time = time - cca_db->time;
+ u32 cca_opt = cca_db->cca_opt;
+
+ cca_db->time = time;
+
+ if (!diff_time || !cca_opt)
+ return;
+
+ if (cca_opt & CCA_OPT_CNT_CS)
+ cl_cca_print_cs(cl_hw, diff_time);
+
+ if (cca_opt & CCA_OPT_CNT_MDM_STATE)
+ cl_cca_print_mdm_state(cl_hw, diff_time);
+
+ if (cca_opt & CCA_OPT_CNT_MP)
+ cl_cca_print_mp(cl_hw, diff_time);
+
+ if (cca_opt & CCA_OPT_CNT_ENERGY)
+ cl_cca_print_energy(cl_hw, diff_time);
+
+ if (cca_opt & CCA_OPT_CNT_ENERGY_BAND)
+ cl_cca_print_energy_band(cl_hw, diff_time);
+
+ if (cca_opt & (CCA_OPT_UTIL | CCA_OPT_REC_HIST))
+ cl_cca_print_utility(cl_hw, diff_time);
+
+ if (cca_opt & CCA_OPT_TX_RX_MINE)
+ cl_cca_print_tx_rx_mine(cl_hw, diff_time);
+
+ if (cca_opt & CCA_OPT_EDCA)
+ cl_cca_edca(cl_hw, diff_time);
+
+ if (cca_opt & CCA_OPT_EDCA_NAV)
+ cl_cca_print_edca_nav(cl_hw, diff_time);
+
+ /* Rest CCA counters */
+ riu_rwnxagccca_1_cca_cnt_clear_setf(cl_hw, 0);
+}
+
--
2.30.0

________________________________
The information transmitted is intended only for the person or entity to which it is addressed and may contain confidential and/or privileged material. Any retransmission, dissemination, copying or other use of, or taking of any action in reliance upon this information is prohibited. If you received this in error, please contact the sender and delete the material from any computer. Nothing contained herein shall be deemed as a representation, warranty or a commitment by Celeno. No warranties are expressed or implied, including, but not limited to, any implied warranties of non-infringement, merchantability and fitness for a particular purpose.
________________________________

2021-06-17 16:23:36

by viktor.barna

[permalink] [raw]
Subject: [RFC v1 018/256] cl8k: add bus/pci/ipc.h

From: Viktor Barna <[email protected]>

(Part of the split. Please, take a look at the cover letter for more
details).

Signed-off-by: Viktor Barna <[email protected]>
---
.../net/wireless/celeno/cl8k/bus/pci/ipc.h | 135 ++++++++++++++++++
1 file changed, 135 insertions(+)
create mode 100644 drivers/net/wireless/celeno/cl8k/bus/pci/ipc.h

diff --git a/drivers/net/wireless/celeno/cl8k/bus/pci/ipc.h b/drivers/net/wireless/celeno/cl8k/bus/pci/ipc.h
new file mode 100644
index 000000000000..81cdae55f467
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/bus/pci/ipc.h
@@ -0,0 +1,135 @@
+/* SPDX-License-Identifier: MIT */
+/* Copyright(c) 2019-2021, Celeno Communications Ltd. */
+
+#ifndef CL_IPC_H
+#define CL_IPC_H
+
+#include "ipc_shared.h"
+#include "hw.h"
+
+/* Struct used to store information about host buffers (DMA Address and local pointer) */
+struct cl_ipc_hostbuf {
+ ptrdiff_t hostid; /* Ptr to hostbuf client (ipc_host client) structure */
+ dma_addr_t dma_addr; /* Ptr to real hostbuf dma address */
+};
+
+/*
+ * Index in txdesc - updated by host on every push, used by firmware side
+ * Keep this structure aligned to 4-byte
+ */
+struct cl_ipc_txdesc_write_idx {
+ u32 agg[IPC_MAX_BA_SESSIONS];
+ u32 single[MAX_SINGLE_QUEUES];
+ u32 bcmc;
+};
+
+struct cl_ipc_ring_indices {
+ /* Last copy of ipc txdesc write desc right after DMA push operation */
+ volatile struct cl_ipc_txdesc_write_idx txdesc_write_idx;
+ /*
+ * new start sn - equal to last acknowledged sequence number + 1.
+ * Updated by firmware and used by host.
+ */
+ volatile u16 new_ssn_idx[IPC_MAX_BA_SESSIONS];
+ volatile u8 dtim_count[MAX_BSS_NUM];
+ /* Index in rxdesc array, updated by firmware on every payload push, used by host */
+ volatile u32 rxdesc_write_idx[CL_RX_BUF_MAX];
+ /* Index in rxdesc array, updated by host on rxdesc copy completion, used by firmware */
+ volatile u32 rxdesc_read_idx[CL_RX_BUF_MAX];
+ /* BSR data counters */
+ volatile u32 bsr_data_ctrs[TID_MAX];
+};
+
+/* Structure used to store Shared Txring indices */
+struct cl_ipc_ring_indices_elem {
+ struct cl_ipc_ring_indices *indices;
+ dma_addr_t dma_addr;
+};
+
+struct cl_ipc_host_rxbuf {
+ /* Array of drv desc which holds the skb and additional data */
+ ptrdiff_t **ipc_host_rxdesc_ptr;
+ /* Address of payload for embedded push operation (part of rxdesc data) */
+ u32 *dma_payload_addr;
+ /* Dma pointer to array of DMA payload addresses */
+ __le32 dma_payload_base_addr;
+};
+
+/*
+ * struct tx_queues_dma_addr - ipc layer queues addresses casted to DMA addresses
+ *
+ * The ipc layer points to array of txdesc, there are:
+ * 'IPC_MAX_BA_SESSIONS' arrays for aggregation queues
+ * 'MAX_SINGLE_QUEUES' arrayes for singletons queues
+ * '1' arrays for broadcast/unicast queue
+ *
+ * Each one of this arrays should be copied compeletly to the FW, therefore we should
+ * cast all of the arrays to dma addresses.
+ */
+struct tx_queues_dma_addr {
+ u32 agg[IPC_MAX_BA_SESSIONS];
+ u32 single[MAX_SINGLE_QUEUES];
+ u32 bcmc;
+};
+
+/* struct cl_ipc_tx_queues - ipc layer tx queues */
+struct cl_ipc_tx_queues {
+ struct txdesc *ipc_txdesc_agg[IPC_MAX_BA_SESSIONS];
+ struct txdesc *ipc_txdesc_single[MAX_SINGLE_QUEUES];
+ struct txdesc *ipc_txdesc_bcmc;
+ /* Mapping of the TXQ's addresses to DMA addresses */
+ struct tx_queues_dma_addr *queues_dma_addr;
+ /* DMA address of tx_queues_dma_addr */
+ u32 dma_addr;
+};
+
+struct cl_ipc_host_env {
+ /* Pointer to the shared environment */
+ struct cl_ipc_shared_env *shared;
+ /* TX ring indices (RD, WR idx & new_ssn) */
+ struct cl_ipc_ring_indices_elem *ring_indices_elem;
+ /* RX buffers (rxdesc & dma_addr) */
+ ptrdiff_t *ipc_host_rxdesc_rxm[IPC_RXBUF_CNT_RXM];
+ ptrdiff_t *ipc_host_rxdesc_fw[IPC_RXBUF_CNT_FW];
+ struct cl_ipc_host_rxbuf rx_hostbuf_array[CL_RX_BUF_MAX];
+ /* Host last read idx */
+ u32 host_rxdesc_read_idx[CL_RX_BUF_MAX];
+ /* Fields for Radar events handling */
+ struct cl_ipc_hostbuf radar_hostbuf_array[IPC_RADAR_BUF_CNT];
+ u8 radar_host_idx;
+ /* Fields for Emb->App MSGs handling */
+ struct cl_ipc_hostbuf e2a_msg_hostbuf_array[IPC_E2A_MSG_BUF_CNT];
+ u8 e2a_msg_host_idx;
+ /* Fields for Debug MSGs handling */
+ struct cl_ipc_hostbuf dbg_hostbuf_array[IPC_DBG_BUF_CNT];
+ u8 dbg_host_idx;
+ /* IPC queues */
+ struct cl_ipc_tx_queues tx_queues;
+ struct cl_ipc_enhanced_tim enhanced_tim;
+ /* Fields for single confirmation handling */
+ u8 *cfm_virt_base_addr;
+ dma_addr_t cfm_dma_base_addr;
+ /* Index used that points to the first used CFM */
+ u32 cfm_used_idx;
+ /* Tasklets */
+ struct tasklet_struct rxdesc_tasklet;
+ struct tasklet_struct tx_single_cfm_tasklet;
+ struct tasklet_struct tx_agg_cfm_tasklet;
+ struct tasklet_struct msg_tasklet;
+ struct tasklet_struct dbg_tasklet;
+};
+
+int cl_ipc_init(struct cl_hw *cl_hw);
+void cl_ipc_recovery(struct cl_hw *cl_hw);
+void cl_ipc_reset(struct cl_hw *cl_hw);
+void cl_ipc_deinit(struct cl_hw *cl_hw);
+void cl_ipc_stop(struct cl_hw *cl_hw);
+int cl_ipc_rx_elem_alloc(struct cl_hw *cl_hw, struct cl_rx_elem *rx_elem, u32 size);
+void cl_ipc_msgbuf_push(struct cl_ipc_host_env *ipc_env, ptrdiff_t hostid, dma_addr_t hostbuf);
+void cl_ipc_rxbuf_push(struct cl_ipc_host_env *ipc_env, struct cl_rx_elem *rx_elem,
+ u32 rxdesc_read_idx, u32 host_read_idx, enum rx_buf_type type);
+void cl_ipc_radarbuf_push(struct cl_ipc_host_env *ipc_env, ptrdiff_t hostid, dma_addr_t hostbuf);
+void cl_ipc_dbgbuf_push(struct cl_ipc_host_env *ipc_env, ptrdiff_t hostid, dma_addr_t hostbuf);
+void cl_ipc_dbginfobuf_push(struct cl_ipc_host_env *ipc_env, dma_addr_t infobuf);
+
+#endif /* CL_IPC_H */
--
2.30.0

________________________________
The information transmitted is intended only for the person or entity to which it is addressed and may contain confidential and/or privileged material. Any retransmission, dissemination, copying or other use of, or taking of any action in reliance upon this information is prohibited. If you received this in error, please contact the sender and delete the material from any computer. Nothing contained herein shall be deemed as a representation, warranty or a commitment by Celeno. No warranties are expressed or implied, including, but not limited to, any implied warranties of non-infringement, merchantability and fitness for a particular purpose.
________________________________

2021-06-17 16:23:53

by viktor.barna

[permalink] [raw]
Subject: [RFC v1 038/256] cl8k: add channel.c

From: Viktor Barna <[email protected]>

(Part of the split. Please, take a look at the cover letter for more
details).

Signed-off-by: Viktor Barna <[email protected]>
---
drivers/net/wireless/celeno/cl8k/channel.c | 373 +++++++++++++++++++++
1 file changed, 373 insertions(+)
create mode 100644 drivers/net/wireless/celeno/cl8k/channel.c

diff --git a/drivers/net/wireless/celeno/cl8k/channel.c b/drivers/net/wireless/celeno/cl8k/channel.c
new file mode 100644
index 000000000000..78346f04e332
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/channel.c
@@ -0,0 +1,373 @@
+// SPDX-License-Identifier: MIT
+/* Copyright(c) 2019-2021, Celeno Communications Ltd. */
+
+#include "channel.h"
+#include "band.h"
+#include "vif.h"
+#include "dfs/dfs.h"
+#include "chandef.h"
+#include "netlink.h"
+
+#define CASE_CHAN2IDX_6G(_chan) { case _chan: return (b6g_ch ## _chan); }
+#define CASE_CHAN2IDX_5G(_chan) { case _chan: return (b5g_ch ## _chan); }
+#define CASE_CHAN2IDX_2G(_chan) { case _chan: return (b24g_ch ## _chan); }
+
+#define CASE_IDX2FREQ_6G(_chan) { case (b6g_ch ## _chan): return FREQ6G(_chan); }
+#define CASE_IDX2FREQ_5G(_chan) { case (b5g_ch ## _chan): return FREQ5G(_chan); }
+#define CASE_IDX2FREQ_2G(_chan) { case (b24g_ch ## _chan): return FREQ2G(_chan); }
+
+#define INVALID_FREQ 0xffff
+
+static u8 cl_channel_to_index_6g(struct cl_hw *cl_hw, u32 channel)
+{
+ switch (channel) {
+ CASE_CHAN2IDX_6G(1);
+ CASE_CHAN2IDX_6G(2);
+ CASE_CHAN2IDX_6G(5);
+ CASE_CHAN2IDX_6G(9);
+ CASE_CHAN2IDX_6G(13);
+ CASE_CHAN2IDX_6G(17);
+ CASE_CHAN2IDX_6G(21);
+ CASE_CHAN2IDX_6G(25);
+ CASE_CHAN2IDX_6G(29);
+ CASE_CHAN2IDX_6G(33);
+ CASE_CHAN2IDX_6G(37);
+ CASE_CHAN2IDX_6G(41);
+ CASE_CHAN2IDX_6G(45);
+ CASE_CHAN2IDX_6G(49);
+ CASE_CHAN2IDX_6G(53);
+ CASE_CHAN2IDX_6G(57);
+ CASE_CHAN2IDX_6G(61);
+ CASE_CHAN2IDX_6G(65);
+ CASE_CHAN2IDX_6G(69);
+ CASE_CHAN2IDX_6G(73);
+ CASE_CHAN2IDX_6G(77);
+ CASE_CHAN2IDX_6G(81);
+ CASE_CHAN2IDX_6G(85);
+ CASE_CHAN2IDX_6G(89);
+ CASE_CHAN2IDX_6G(93);
+ CASE_CHAN2IDX_6G(97);
+ CASE_CHAN2IDX_6G(101);
+ CASE_CHAN2IDX_6G(105);
+ CASE_CHAN2IDX_6G(109);
+ CASE_CHAN2IDX_6G(113);
+ CASE_CHAN2IDX_6G(117);
+ CASE_CHAN2IDX_6G(121);
+ CASE_CHAN2IDX_6G(125);
+ CASE_CHAN2IDX_6G(129);
+ CASE_CHAN2IDX_6G(133);
+ CASE_CHAN2IDX_6G(137);
+ CASE_CHAN2IDX_6G(141);
+ CASE_CHAN2IDX_6G(145);
+ CASE_CHAN2IDX_6G(149);
+ CASE_CHAN2IDX_6G(153);
+ CASE_CHAN2IDX_6G(157);
+ CASE_CHAN2IDX_6G(161);
+ CASE_CHAN2IDX_6G(165);
+ CASE_CHAN2IDX_6G(169);
+ CASE_CHAN2IDX_6G(173);
+ CASE_CHAN2IDX_6G(177);
+ CASE_CHAN2IDX_6G(181);
+ CASE_CHAN2IDX_6G(185);
+ CASE_CHAN2IDX_6G(189);
+ CASE_CHAN2IDX_6G(193);
+ CASE_CHAN2IDX_6G(197);
+ CASE_CHAN2IDX_6G(201);
+ CASE_CHAN2IDX_6G(205);
+ CASE_CHAN2IDX_6G(209);
+ CASE_CHAN2IDX_6G(213);
+ CASE_CHAN2IDX_6G(217);
+ CASE_CHAN2IDX_6G(221);
+ CASE_CHAN2IDX_6G(225);
+ CASE_CHAN2IDX_6G(229);
+ CASE_CHAN2IDX_6G(233);
+ };
+
+ return INVALID_CHAN_IDX;
+}
+
+static u8 cl_channel_to_index_5g(struct cl_hw *cl_hw, u32 channel)
+{
+ switch (channel) {
+ CASE_CHAN2IDX_5G(36);
+ CASE_CHAN2IDX_5G(38);
+ CASE_CHAN2IDX_5G(40);
+ CASE_CHAN2IDX_5G(42);
+ CASE_CHAN2IDX_5G(44);
+ CASE_CHAN2IDX_5G(46);
+ CASE_CHAN2IDX_5G(48);
+ CASE_CHAN2IDX_5G(50);
+ CASE_CHAN2IDX_5G(52);
+ CASE_CHAN2IDX_5G(54);
+ CASE_CHAN2IDX_5G(56);
+ CASE_CHAN2IDX_5G(58);
+ CASE_CHAN2IDX_5G(60);
+ CASE_CHAN2IDX_5G(62);
+ CASE_CHAN2IDX_5G(64);
+ CASE_CHAN2IDX_5G(100);
+ CASE_CHAN2IDX_5G(102);
+ CASE_CHAN2IDX_5G(104);
+ CASE_CHAN2IDX_5G(106);
+ CASE_CHAN2IDX_5G(108);
+ CASE_CHAN2IDX_5G(110);
+ CASE_CHAN2IDX_5G(112);
+ CASE_CHAN2IDX_5G(114);
+ CASE_CHAN2IDX_5G(116);
+ CASE_CHAN2IDX_5G(118);
+ CASE_CHAN2IDX_5G(120);
+ CASE_CHAN2IDX_5G(122);
+ CASE_CHAN2IDX_5G(124);
+ CASE_CHAN2IDX_5G(126);
+ CASE_CHAN2IDX_5G(128);
+ /* 130 - invalid */
+ CASE_CHAN2IDX_5G(132);
+ CASE_CHAN2IDX_5G(134);
+ CASE_CHAN2IDX_5G(136);
+ CASE_CHAN2IDX_5G(138);
+ CASE_CHAN2IDX_5G(140);
+ CASE_CHAN2IDX_5G(142);
+ CASE_CHAN2IDX_5G(144);
+ CASE_CHAN2IDX_5G(149);
+ CASE_CHAN2IDX_5G(151);
+ CASE_CHAN2IDX_5G(153);
+ CASE_CHAN2IDX_5G(155);
+ CASE_CHAN2IDX_5G(157);
+ CASE_CHAN2IDX_5G(159);
+ CASE_CHAN2IDX_5G(161);
+ /* 163 - invalid */
+ CASE_CHAN2IDX_5G(165);
+ };
+
+ return INVALID_CHAN_IDX;
+}
+
+static u8 cl_channel_to_index_24g(struct cl_hw *cl_hw, u32 channel)
+{
+ switch (channel) {
+ CASE_CHAN2IDX_2G(1);
+ CASE_CHAN2IDX_2G(2);
+ CASE_CHAN2IDX_2G(3);
+ CASE_CHAN2IDX_2G(4);
+ CASE_CHAN2IDX_2G(5);
+ CASE_CHAN2IDX_2G(6);
+ CASE_CHAN2IDX_2G(7);
+ CASE_CHAN2IDX_2G(8);
+ CASE_CHAN2IDX_2G(9);
+ CASE_CHAN2IDX_2G(10);
+ CASE_CHAN2IDX_2G(11);
+ CASE_CHAN2IDX_2G(12);
+ CASE_CHAN2IDX_2G(13);
+ CASE_CHAN2IDX_2G(14);
+ };
+
+ return INVALID_CHAN_IDX;
+}
+
+u8 cl_channel_to_index(struct cl_hw *cl_hw, u32 channel)
+{
+ /* Calculate index for a given channel */
+ if (cl_band_is_6g(cl_hw))
+ return cl_channel_to_index_6g(cl_hw, channel);
+ else if (cl_band_is_5g(cl_hw))
+ return cl_channel_to_index_5g(cl_hw, channel);
+ else
+ return cl_channel_to_index_24g(cl_hw, channel);
+}
+
+static u16 cl_channel_idx_to_freq_6g(struct cl_hw *cl_hw, u8 index)
+{
+ switch (index) {
+ CASE_IDX2FREQ_6G(1);
+ CASE_IDX2FREQ_6G(2);
+ CASE_IDX2FREQ_6G(5);
+ CASE_IDX2FREQ_6G(9);
+ CASE_IDX2FREQ_6G(13);
+ CASE_IDX2FREQ_6G(17);
+ CASE_IDX2FREQ_6G(21);
+ CASE_IDX2FREQ_6G(25);
+ CASE_IDX2FREQ_6G(29);
+ CASE_IDX2FREQ_6G(33);
+ CASE_IDX2FREQ_6G(37);
+ CASE_IDX2FREQ_6G(41);
+ CASE_IDX2FREQ_6G(45);
+ CASE_IDX2FREQ_6G(49);
+ CASE_IDX2FREQ_6G(53);
+ CASE_IDX2FREQ_6G(57);
+ CASE_IDX2FREQ_6G(61);
+ CASE_IDX2FREQ_6G(65);
+ CASE_IDX2FREQ_6G(69);
+ CASE_IDX2FREQ_6G(73);
+ CASE_IDX2FREQ_6G(77);
+ CASE_IDX2FREQ_6G(81);
+ CASE_IDX2FREQ_6G(85);
+ CASE_IDX2FREQ_6G(89);
+ CASE_IDX2FREQ_6G(93);
+ CASE_IDX2FREQ_6G(97);
+ CASE_IDX2FREQ_6G(101);
+ CASE_IDX2FREQ_6G(105);
+ CASE_IDX2FREQ_6G(109);
+ CASE_IDX2FREQ_6G(113);
+ CASE_IDX2FREQ_6G(117);
+ CASE_IDX2FREQ_6G(121);
+ CASE_IDX2FREQ_6G(125);
+ CASE_IDX2FREQ_6G(129);
+ CASE_IDX2FREQ_6G(133);
+ CASE_IDX2FREQ_6G(137);
+ CASE_IDX2FREQ_6G(141);
+ CASE_IDX2FREQ_6G(145);
+ CASE_IDX2FREQ_6G(149);
+ CASE_IDX2FREQ_6G(153);
+ CASE_IDX2FREQ_6G(157);
+ CASE_IDX2FREQ_6G(161);
+ CASE_IDX2FREQ_6G(165);
+ CASE_IDX2FREQ_6G(169);
+ CASE_IDX2FREQ_6G(173);
+ CASE_IDX2FREQ_6G(177);
+ CASE_IDX2FREQ_6G(181);
+ CASE_IDX2FREQ_6G(185);
+ CASE_IDX2FREQ_6G(189);
+ CASE_IDX2FREQ_6G(193);
+ CASE_IDX2FREQ_6G(197);
+ CASE_IDX2FREQ_6G(201);
+ CASE_IDX2FREQ_6G(205);
+ CASE_IDX2FREQ_6G(209);
+ CASE_IDX2FREQ_6G(213);
+ CASE_IDX2FREQ_6G(217);
+ CASE_IDX2FREQ_6G(221);
+ CASE_IDX2FREQ_6G(225);
+ CASE_IDX2FREQ_6G(229);
+ CASE_IDX2FREQ_6G(233);
+ };
+
+ return INVALID_FREQ;
+}
+
+static u16 cl_channel_idx_to_freq_5g(struct cl_hw *cl_hw, u8 index)
+{
+ switch (index) {
+ CASE_IDX2FREQ_5G(36);
+ CASE_IDX2FREQ_5G(38);
+ CASE_IDX2FREQ_5G(40);
+ CASE_IDX2FREQ_5G(42);
+ CASE_IDX2FREQ_5G(44);
+ CASE_IDX2FREQ_5G(46);
+ CASE_IDX2FREQ_5G(48);
+ CASE_IDX2FREQ_5G(50);
+ CASE_IDX2FREQ_5G(52);
+ CASE_IDX2FREQ_5G(54);
+ CASE_IDX2FREQ_5G(56);
+ CASE_IDX2FREQ_5G(58);
+ CASE_IDX2FREQ_5G(60);
+ CASE_IDX2FREQ_5G(62);
+ CASE_IDX2FREQ_5G(64);
+ CASE_IDX2FREQ_5G(100);
+ CASE_IDX2FREQ_5G(102);
+ CASE_IDX2FREQ_5G(104);
+ CASE_IDX2FREQ_5G(106);
+ CASE_IDX2FREQ_5G(108);
+ CASE_IDX2FREQ_5G(110);
+ CASE_IDX2FREQ_5G(112);
+ CASE_IDX2FREQ_5G(114);
+ CASE_IDX2FREQ_5G(116);
+ CASE_IDX2FREQ_5G(118);
+ CASE_IDX2FREQ_5G(120);
+ CASE_IDX2FREQ_5G(122);
+ CASE_IDX2FREQ_5G(124);
+ CASE_IDX2FREQ_5G(126);
+ CASE_IDX2FREQ_5G(128);
+ CASE_IDX2FREQ_5G(132);
+ CASE_IDX2FREQ_5G(134);
+ CASE_IDX2FREQ_5G(136);
+ CASE_IDX2FREQ_5G(138);
+ CASE_IDX2FREQ_5G(140);
+ CASE_IDX2FREQ_5G(142);
+ CASE_IDX2FREQ_5G(144);
+ CASE_IDX2FREQ_5G(149);
+ CASE_IDX2FREQ_5G(151);
+ CASE_IDX2FREQ_5G(153);
+ CASE_IDX2FREQ_5G(155);
+ CASE_IDX2FREQ_5G(157);
+ CASE_IDX2FREQ_5G(159);
+ CASE_IDX2FREQ_5G(161);
+ CASE_IDX2FREQ_5G(165);
+ };
+
+ return INVALID_FREQ;
+}
+
+static u16 cl_channel_idx_to_freq_24g(struct cl_hw *cl_hw, u8 index)
+{
+ switch (index) {
+ CASE_IDX2FREQ_2G(1);
+ CASE_IDX2FREQ_2G(2);
+ CASE_IDX2FREQ_2G(3);
+ CASE_IDX2FREQ_2G(4);
+ CASE_IDX2FREQ_2G(5);
+ CASE_IDX2FREQ_2G(6);
+ CASE_IDX2FREQ_2G(7);
+ CASE_IDX2FREQ_2G(8);
+ CASE_IDX2FREQ_2G(9);
+ CASE_IDX2FREQ_2G(10);
+ CASE_IDX2FREQ_2G(11);
+ CASE_IDX2FREQ_2G(12);
+ CASE_IDX2FREQ_2G(13);
+ CASE_IDX2FREQ_2G(14);
+ };
+
+ return INVALID_FREQ;
+}
+
+u16 cl_channel_idx_to_freq(struct cl_hw *cl_hw, u8 index)
+{
+ /* Calculate frequency of a given idnex */
+ if (cl_band_is_6g(cl_hw))
+ return cl_channel_idx_to_freq_6g(cl_hw, index);
+ else if (cl_band_is_5g(cl_hw))
+ return cl_channel_idx_to_freq_5g(cl_hw, index);
+ else
+ return cl_channel_idx_to_freq_24g(cl_hw, index);
+}
+
+bool cl_channel_is_valid(struct cl_hw *cl_hw, u8 channel)
+{
+ if (cl_band_is_24g(cl_hw)) {
+ return (channel > 0 && channel <= 14);
+ } else if (cl_band_is_5g(cl_hw)) {
+ if (channel >= 36 && channel <= 64)
+ return ((channel & 0x1) == 0x0);
+
+ if (channel >= 100 && channel <= 144)
+ return ((channel & 0x1) == 0x0);
+
+ if (channel >= 149 && channel <= 161)
+ return ((channel & 0x1) == 0x1);
+
+ if (channel == 165)
+ return true;
+ } else {
+ if (channel == 2)
+ return true;
+
+ if (channel >= 1 && channel <= 233)
+ if ((channel & 0x3) == 0x1)
+ return true;
+ }
+
+ return false;
+}
+
+u32 cl_channel_num(struct cl_hw *cl_hw)
+{
+ if (cl_hw->conf->ci_band_num == 6)
+ return NUM_CHANNELS_6G;
+
+ if (cl_hw->conf->ci_band_num == 5)
+ return NUM_CHANNELS_5G;
+
+ return NUM_CHANNELS_24G;
+}
+
+bool __must_check cl_channel_is_scan_active(struct cl_hw *cl_hw)
+{
+ return false;
+}
--
2.30.0

________________________________
The information transmitted is intended only for the person or entity to which it is addressed and may contain confidential and/or privileged material. Any retransmission, dissemination, copying or other use of, or taking of any action in reliance upon this information is prohibited. If you received this in error, please contact the sender and delete the material from any computer. Nothing contained herein shall be deemed as a representation, warranty or a commitment by Celeno. No warranties are expressed or implied, including, but not limited to, any implied warranties of non-infringement, merchantability and fitness for a particular purpose.
________________________________

2021-06-17 16:23:55

by viktor.barna

[permalink] [raw]
Subject: [RFC v1 035/256] cl8k: add cecli.h

From: Viktor Barna <[email protected]>

(Part of the split. Please, take a look at the cover letter for more
details).

Signed-off-by: Viktor Barna <[email protected]>
---
drivers/net/wireless/celeno/cl8k/cecli.h | 112 +++++++++++++++++++++++
1 file changed, 112 insertions(+)
create mode 100644 drivers/net/wireless/celeno/cl8k/cecli.h

diff --git a/drivers/net/wireless/celeno/cl8k/cecli.h b/drivers/net/wireless/celeno/cl8k/cecli.h
new file mode 100644
index 000000000000..3260ca56e563
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/cecli.h
@@ -0,0 +1,112 @@
+/* SPDX-License-Identifier: MIT */
+/* Copyright(c) 2019-2021, Celeno Communications Ltd. */
+
+#ifndef CL_CECLI_H
+#define CL_CECLI_H
+
+#include <net/cfg80211.h>
+#include <net/mac80211.h>
+#include <linux/version.h>
+
+/**
+ * DOC: Cecli - command line interface wrapper
+ *
+ * Allows to control the driver behavior and inspect statistics, utilizes
+ * vendor specific commands and events from the nl80211 layer.
+ */
+
+int cl_cecli_acs(struct wiphy *wiphy, struct wireless_dev *wdev,
+ const void *data, int data_len);
+int cl_cecli_agc_params(struct wiphy *wiphy, struct wireless_dev *wdev,
+ const void *data, int data_len);
+int cl_cecli_bf(struct wiphy *wiphy, struct wireless_dev *wdev,
+ const void *data, int data_len);
+int cl_cecli_bss_color(struct wiphy *wiphy, struct wireless_dev *wdev,
+ const void *data, int data_len);
+int cl_cecli_calib(struct wiphy *wiphy, struct wireless_dev *wdev,
+ const void *data, int data_len);
+int cl_cecli_cca(struct wiphy *wiphy, struct wireless_dev *wdev,
+ const void *data, int data_len);
+int cl_cecli_chip(struct wiphy *wiphy, struct wireless_dev *wdev,
+ const void *data, int data_len);
+int cl_cecli_config(struct wiphy *wiphy, struct wireless_dev *wdev,
+ const void *data, int data_len);
+int cl_cecli_debug(struct wiphy *wiphy, struct wireless_dev *wdev,
+ const void *data, int data_len);
+int cl_cecli_dfs(struct wiphy *wiphy, struct wireless_dev *wdev,
+ const void *data, int data_len);
+int cl_cecli_edca(struct wiphy *wiphy, struct wireless_dev *wdev,
+ const void *data, int data_len);
+int cl_cecli_fw(struct wiphy *wiphy, struct wireless_dev *wdev,
+ const void *data, int data_len);
+int cl_cecli_motion(struct wiphy *wiphy, struct wireless_dev *wdev,
+ const void *data, int data_len);
+int cl_cecli_noise(struct wiphy *wiphy, struct wireless_dev *wdev,
+ const void *data, int data_len);
+int cl_cecli_omi(struct wiphy *wiphy, struct wireless_dev *wdev,
+ const void *data, int data_len);
+int cl_cecli_power(struct wiphy *wiphy, struct wireless_dev *wdev,
+ const void *data, int data_len);
+int cl_cecli_qos(struct wiphy *wiphy, struct wireless_dev *wdev,
+ const void *data, int data_len);
+int cl_cecli_radio(struct wiphy *wiphy, struct wireless_dev *wdev,
+ const void *data, int data_len);
+int cl_cecli_reg(struct wiphy *wiphy, struct wireless_dev *wdev,
+ const void *data, int data_len);
+int cl_cecli_sounding(struct wiphy *wiphy, struct wireless_dev *wdev,
+ const void *data, int data_len);
+int cl_cecli_stats(struct wiphy *wiphy, struct wireless_dev *wdev,
+ const void *data, int data_len);
+int cl_cecli_tcv(struct wiphy *wiphy, struct wireless_dev *wdev,
+ const void *data, int data_len);
+int cl_cecli_temp(struct wiphy *wiphy, struct wireless_dev *wdev,
+ const void *data, int data_len);
+int cl_cecli_traffic(struct wiphy *wiphy, struct wireless_dev *wdev,
+ const void *data, int data_len);
+int cl_cecli_twt(struct wiphy *wiphy, struct wireless_dev *wdev,
+ const void *data, int data_len);
+int cl_cecli_txq(struct wiphy *wiphy, struct wireless_dev *wdev,
+ const void *data, int data_len);
+int cl_cecli_version(struct wiphy *wiphy, struct wireless_dev *wdev,
+ const void *data, int data_len);
+int cl_cecli_vns(struct wiphy *wiphy, struct wireless_dev *wdev,
+ const void *data, int data_len);
+int cl_cecli_wrs(struct wiphy *wiphy, struct wireless_dev *wdev,
+ const void *data, int data_len);
+int cl_cecli_help(struct wiphy *wiphy, struct wireless_dev *wdev,
+ const void *data, int data_len);
+
+enum cl_cecli_cmd {
+ CL_CECLI_AGC_PARAMS,
+ CL_CECLI_BF,
+ CL_CECLI_CALIB,
+ CL_CECLI_CCA,
+ CL_CECLI_CHIP,
+ CL_CECLI_CONFIG,
+ CL_CECLI_DEBUG,
+ CL_CECLI_DFS,
+ CL_CECLI_EDCA,
+ CL_CECLI_FW,
+ CL_CECLI_MORE_DATA,
+ CL_CECLI_MOTION,
+ CL_CECLI_NOISE,
+ CL_CECLI_OMI,
+ CL_CECLI_POWER,
+ CL_CECLI_QOS,
+ CL_CECLI_RADIO,
+ CL_CECLI_REG,
+ CL_CECLI_SOUNDING,
+ CL_CECLI_STATS,
+ CL_CECLI_TCV,
+ CL_CECLI_TEMP,
+ CL_CECLI_TRAFFIC,
+ CL_CECLI_TWT,
+ CL_CECLI_TXQ,
+ CL_CECLI_VERSION,
+ CL_CECLI_VNS,
+ CL_CECLI_WRS,
+
+ CL_CECLI_MAX
+};
+
+#endif /* CL_CECLI_H */
--
2.30.0

________________________________
The information transmitted is intended only for the person or entity to which it is addressed and may contain confidential and/or privileged material. Any retransmission, dissemination, copying or other use of, or taking of any action in reliance upon this information is prohibited. If you received this in error, please contact the sender and delete the material from any computer. Nothing contained herein shall be deemed as a representation, warranty or a commitment by Celeno. No warranties are expressed or implied, including, but not limited to, any implied warranties of non-infringement, merchantability and fitness for a particular purpose.
________________________________

2021-06-17 16:24:10

by viktor.barna

[permalink] [raw]
Subject: [RFC v1 039/256] cl8k: add channel.h

From: Viktor Barna <[email protected]>

(Part of the split. Please, take a look at the cover letter for more
details).

Signed-off-by: Viktor Barna <[email protected]>
---
drivers/net/wireless/celeno/cl8k/channel.h | 187 +++++++++++++++++++++
1 file changed, 187 insertions(+)
create mode 100644 drivers/net/wireless/celeno/cl8k/channel.h

diff --git a/drivers/net/wireless/celeno/cl8k/channel.h b/drivers/net/wireless/celeno/cl8k/channel.h
new file mode 100644
index 000000000000..c31cb4f69f2a
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/channel.h
@@ -0,0 +1,187 @@
+/* SPDX-License-Identifier: MIT */
+/* Copyright(c) 2019-2021, Celeno Communications Ltd. */
+
+#ifndef CL_CHANNEL_H
+#define CL_CHANNEL_H
+
+#include <linux/types.h>
+#include <linux/errno.h>
+
+enum chan_idx_6g {
+ b6g_ch1,
+ b6g_ch2,
+ b6g_ch5,
+ b6g_ch9,
+ b6g_ch13,
+ b6g_ch17,
+ b6g_ch21,
+ b6g_ch25,
+ b6g_ch29,
+ b6g_ch33,
+ b6g_ch37,
+ b6g_ch41,
+ b6g_ch45,
+ b6g_ch49,
+ b6g_ch53,
+ b6g_ch57,
+ b6g_ch61,
+ b6g_ch65,
+ b6g_ch69,
+ b6g_ch73,
+ b6g_ch77,
+ b6g_ch81,
+ b6g_ch85,
+ b6g_ch89,
+ b6g_ch93,
+ b6g_ch97,
+ b6g_ch101,
+ b6g_ch105,
+ b6g_ch109,
+ b6g_ch113,
+ b6g_ch117,
+ b6g_ch121,
+ b6g_ch125,
+ b6g_ch129,
+ b6g_ch133,
+ b6g_ch137,
+ b6g_ch141,
+ b6g_ch145,
+ b6g_ch149,
+ b6g_ch153,
+ b6g_ch157,
+ b6g_ch161,
+ b6g_ch165,
+ b6g_ch169,
+ b6g_ch173,
+ b6g_ch177,
+ b6g_ch181,
+ b6g_ch185,
+ b6g_ch189,
+ b6g_ch193,
+ b6g_ch197,
+ b6g_ch201,
+ b6g_ch205,
+ b6g_ch209,
+ b6g_ch213,
+ b6g_ch217,
+ b6g_ch221,
+ b6g_ch225,
+ b6g_ch229,
+ b6g_ch233,
+
+ NUM_CHANNELS_6G
+};
+
+enum chan_idx_5g {
+ b5g_ch36,
+ b5g_ch38,
+ b5g_ch40,
+ b5g_ch42,
+ b5g_ch44,
+ b5g_ch46,
+ b5g_ch48,
+ b5g_ch50,
+ b5g_ch52,
+ b5g_ch54,
+ b5g_ch56,
+ b5g_ch58,
+ b5g_ch60,
+ b5g_ch62,
+ b5g_ch64,
+ b5g_ch100,
+ b5g_ch102,
+ b5g_ch104,
+ b5g_ch106,
+ b5g_ch108,
+ b5g_ch110,
+ b5g_ch112,
+ b5g_ch114,
+ b5g_ch116,
+ b5g_ch118,
+ b5g_ch120,
+ b5g_ch122,
+ b5g_ch124,
+ b5g_ch126,
+ b5g_ch128,
+ b5g_ch132,
+ b5g_ch134,
+ b5g_ch136,
+ b5g_ch138,
+ b5g_ch140,
+ b5g_ch142,
+ b5g_ch144,
+ b5g_ch149,
+ b5g_ch151,
+ b5g_ch153,
+ b5g_ch155,
+ b5g_ch157,
+ b5g_ch159,
+ b5g_ch161,
+ b5g_ch165,
+
+ NUM_CHANNELS_5G
+};
+
+enum chan_idx_24g {
+ b24g_ch1,
+ b24g_ch2,
+ b24g_ch3,
+ b24g_ch4,
+ b24g_ch5,
+ b24g_ch6,
+ b24g_ch7,
+ b24g_ch8,
+ b24g_ch9,
+ b24g_ch10,
+ b24g_ch11,
+ b24g_ch12,
+ b24g_ch13,
+ b24g_ch14,
+
+ NUM_CHANNELS_24G
+};
+
+enum cl_ch_status {
+ CH_STATUS_SUCCESS,
+ CH_STATUS_ALREADY_ON_CHANNEL,
+ CH_STATUS_INVALID_PARAM = -EINVAL,
+
+ CH_STATUS_MAX
+};
+
+/* 6g band has the largest list */
+#define MAX_CHANNELS NUM_CHANNELS_6G
+
+#define START_CHAN_IDX_6G 1
+
+/* 1 ==> 5955 */
+#define FREQ6G(_chan) ((_chan) == 2 ? 5935 : 5950 + 5 * (_chan))
+/* 36 ==> 5180 */
+#define FREQ5G(_chan) (5000 + 5 * (_chan))
+/* 1 ==> 2412 */
+#define FREQ2G(_chan) ((_chan) == 14 ? 2484 : 2407 + (_chan) * 5)
+
+/* 6G channels - UNII-5 */
+#define START_CHAN_IDX_UNII5 1
+#define END_CHAN_IDX_UNII5 85
+/* 6G channels - UNII-6 */
+#define START_CHAN_IDX_UNII6 89
+#define END_CHAN_IDX_UNII6 109
+/* 6G channels - UNII-7 */
+#define START_CHAN_IDX_UNII7 113
+#define END_CHAN_IDX_UNII7 165
+/* 6G channels - UNII-8 */
+#define START_CHAN_IDX_UNII8 169
+#define END_CHAN_IDX_UNII8 233
+
+#define INVALID_CHAN_IDX 0xff
+
+struct cl_hw;
+
+u8 cl_channel_to_index(struct cl_hw *cl_hw, u32 channel);
+u16 cl_channel_idx_to_freq(struct cl_hw *cl_hw, u8 index);
+bool cl_channel_is_valid(struct cl_hw *cl_hw, u8 channel);
+u32 cl_channel_num(struct cl_hw *cl_hw);
+bool __must_check cl_channel_is_scan_active(struct cl_hw *cl_hw);
+
+#endif /* CL_CHANNEL_H */
--
2.30.0

________________________________
The information transmitted is intended only for the person or entity to which it is addressed and may contain confidential and/or privileged material. Any retransmission, dissemination, copying or other use of, or taking of any action in reliance upon this information is prohibited. If you received this in error, please contact the sender and delete the material from any computer. Nothing contained herein shall be deemed as a representation, warranty or a commitment by Celeno. No warranties are expressed or implied, including, but not limited to, any implied warranties of non-infringement, merchantability and fitness for a particular purpose.
________________________________

2021-06-17 16:24:12

by viktor.barna

[permalink] [raw]
Subject: [RFC v1 036/256] cl8k: add chandef.c

From: Viktor Barna <[email protected]>

(Part of the split. Please, take a look at the cover letter for more
details).

Signed-off-by: Viktor Barna <[email protected]>
---
drivers/net/wireless/celeno/cl8k/chandef.c | 152 +++++++++++++++++++++
1 file changed, 152 insertions(+)
create mode 100644 drivers/net/wireless/celeno/cl8k/chandef.c

diff --git a/drivers/net/wireless/celeno/cl8k/chandef.c b/drivers/net/wireless/celeno/cl8k/chandef.c
new file mode 100644
index 000000000000..61e127386b32
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/chandef.c
@@ -0,0 +1,152 @@
+// SPDX-License-Identifier: MIT
+/* Copyright(c) 2019-2021, Celeno Communications Ltd. */
+
+#include "chandef.h"
+#include "band.h"
+#include "utils/utils.h"
+#include "chip.h"
+
+static int cl_chandef_calc_6g(struct cl_hw *cl_hw, u16 freq, u32 bw, u32 offset,
+ u32 *primary, u32 *center)
+{
+ u32 bw_mhz = BW_TO_MHZ(bw);
+ u32 min_freq = 0;
+
+ if (freq == FREQ6G(2)) {
+ min_freq = FREQ6G(2);
+ } else if (freq >= FREQ6G(1) && freq <= FREQ6G(233)) {
+ min_freq = FREQ6G(1);
+ } else {
+ cl_dbg_err(cl_hw, "Invalid frequecy - %u\n", freq);
+ return -EINVAL;
+ }
+
+ *primary = freq - (freq - min_freq) % 20;
+ *center = *primary - (*primary - min_freq) % bw_mhz + offset;
+
+ return 0;
+}
+
+static int cl_chandef_calc_5g(struct cl_hw *cl_hw, u16 freq, u32 bw, u32 offset,
+ u32 *primary, u32 *center)
+{
+ u32 bw_mhz = BW_TO_MHZ(bw);
+ u32 min_freq = 0;
+
+ if ((freq >= FREQ5G(36) && freq <= FREQ5G(64)) ||
+ (freq >= FREQ5G(100) && freq <= FREQ5G(144))) {
+ min_freq = FREQ5G(36);
+ } else if (freq >= FREQ5G(149) && freq <= FREQ5G(165)) {
+ min_freq = FREQ5G(149);
+ } else {
+ cl_dbg_err(cl_hw, "Invalid frequecy - %u\n", freq);
+ return -EINVAL;
+ }
+
+ *primary = freq - (freq - min_freq) % 20;
+ *center = *primary - (*primary - min_freq) % bw_mhz + offset;
+
+ return 0;
+}
+
+static int cl_chandef_calc_24g(struct cl_hw *cl_hw, u16 freq, u32 bw, u32 offset,
+ u32 *primary, u32 *center)
+{
+ u32 min_freq = 0;
+
+ if (freq < FREQ2G(1) || freq > FREQ2G(14)) {
+ cl_dbg_err(cl_hw, "Invalid frequecy - %u\n", freq);
+ return -EINVAL;
+ }
+
+ min_freq = freq < FREQ2G(14) ? FREQ2G(1) : FREQ2G(14);
+ *primary = freq - (freq - min_freq) % 5;
+
+ if (bw == CHNL_BW_20) {
+ *center = *primary;
+ } else {
+ if (freq <= FREQ2G(4)) {
+ /* Above extension channel */
+ *center = *primary + offset;
+ } else if (freq >= FREQ2G(10)) {
+ /* Below extension channel */
+ *center = *primary - offset;
+ } else {
+ /* Channels 5-9 must be below if channel 13 is not supported */
+ if (!cl_chan_info_get(cl_hw, 13, CHNL_BW_20) &&
+ /* For Calibration, when using 2.4GHz channels on TCV0 to set SX0. */
+ !cl_chan_info_get(cl_hw->chip->cl_hw_tcv1, 13, CHNL_BW_20)) {
+ *center = *primary - offset;
+ } else {
+ /* Set below/above according to NVRAM configuration */
+ if (cl_hw->conf->ce_extension_channel == -1)
+ *center = *primary - offset;
+ else
+ *center = *primary + offset;
+ }
+ }
+ }
+
+ return 0;
+}
+
+int cl_chandef_calc(struct cl_hw *cl_hw, u32 channel, u32 bw,
+ enum nl80211_chan_width *width, u32 *primary, u32 *center)
+{
+ u16 freq = ieee80211_channel_to_frequency(channel, cl_hw->nl_band);
+ u32 offset = 0;
+ int ret = 0;
+
+ switch (bw) {
+ case CHNL_BW_20:
+ offset = 0;
+ if (channel == 14)
+ *width = NL80211_CHAN_WIDTH_20_NOHT;
+ else
+ *width = NL80211_CHAN_WIDTH_20;
+ break;
+ case CHNL_BW_40:
+ offset = 10;
+ *width = NL80211_CHAN_WIDTH_40;
+ break;
+ case CHNL_BW_80:
+ if (cl_band_is_24g(cl_hw)) {
+ cl_dbg_err(cl_hw, "Invalid bandwidth - %u\n", bw);
+ return -EINVAL;
+ }
+ offset = 30;
+ *width = NL80211_CHAN_WIDTH_80;
+ break;
+ case CHNL_BW_160:
+ if (cl_band_is_24g(cl_hw)) {
+ cl_dbg_err(cl_hw, "Invalid bandwidth - %u\n", bw);
+ return -EINVAL;
+ }
+ offset = 70;
+ *width = NL80211_CHAN_WIDTH_160;
+ break;
+ default:
+ cl_dbg_err(cl_hw, "Invalid bandwidth - %u\n", bw);
+ return -EINVAL;
+ }
+
+ if (cl_band_is_6g(cl_hw))
+ ret = cl_chandef_calc_6g(cl_hw, freq, bw, offset, primary, center);
+ else if (cl_band_is_5g(cl_hw))
+ ret = cl_chandef_calc_5g(cl_hw, freq, bw, offset, primary, center);
+ else
+ ret = cl_chandef_calc_24g(cl_hw, freq, bw, offset, primary, center);
+
+ cl_dbg_trace(cl_hw, "primary=%u center=%u\n", *primary, *center);
+
+ return ret;
+}
+
+int cl_chandef_get_default(struct cl_hw *cl_hw, enum nl80211_chan_width *width,
+ u32 *primary, u32 *center)
+{
+ u32 bw = cl_hw->conf->ce_channel_bandwidth;
+ u32 channel = cl_hw->conf->ha_channel;
+
+ return cl_chandef_calc(cl_hw, channel, bw, width, primary, center);
+}
--
2.30.0

________________________________
The information transmitted is intended only for the person or entity to which it is addressed and may contain confidential and/or privileged material. Any retransmission, dissemination, copying or other use of, or taking of any action in reliance upon this information is prohibited. If you received this in error, please contact the sender and delete the material from any computer. Nothing contained herein shall be deemed as a representation, warranty or a commitment by Celeno. No warranties are expressed or implied, including, but not limited to, any implied warranties of non-infringement, merchantability and fitness for a particular purpose.
________________________________

2021-06-17 16:24:12

by viktor.barna

[permalink] [raw]
Subject: [RFC v1 019/256] cl8k: add bus/pci/irq.c

From: Viktor Barna <[email protected]>

(Part of the split. Please, take a look at the cover letter for more
details).

Signed-off-by: Viktor Barna <[email protected]>
---
.../net/wireless/celeno/cl8k/bus/pci/irq.c | 331 ++++++++++++++++++
1 file changed, 331 insertions(+)
create mode 100644 drivers/net/wireless/celeno/cl8k/bus/pci/irq.c

diff --git a/drivers/net/wireless/celeno/cl8k/bus/pci/irq.c b/drivers/net/wireless/celeno/cl8k/bus/pci/irq.c
new file mode 100644
index 000000000000..8ef5d2dba9ac
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/bus/pci/irq.c
@@ -0,0 +1,331 @@
+// SPDX-License-Identifier: MIT
+/* Copyright(c) 2019-2021, Celeno Communications Ltd. */
+
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include "reg/reg_access.h"
+#include "reg/reg_ipc.h"
+#include "bus/pci/ipc.h"
+#include "fw/msg_rx.h"
+#include "bus/pci/irq.h"
+#include "chip.h"
+#include "hw.h"
+#include "tx/tx.h"
+#include "dfs/radar.h"
+#include "recovery.h"
+#include "radio.h"
+#include "bus/pci/rx_pci.h"
+
+static void cl_irq_status_rxdesc(struct cl_hw *cl_hw, struct cl_ipc_host_env *ipc_env)
+{
+ /* Handle the reception of a Rx Descriptor */
+
+ /*
+ * Disable the RX interrupt until rxelement/skb handled
+ * this would avoid redundant context switch + redundant tasklet scheduling
+ */
+ cl_irq_disable(cl_hw, cl_hw->ipc_e2a_irq.rxdesc);
+
+ /* Acknowledge the interrupt BEFORE handling the packet */
+ ipc_xmac_2_host_ack_set(cl_hw->chip, cl_hw->ipc_e2a_irq.rxdesc);
+
+ /*
+ * If more than 50% of buffer are populated handle them in the interrupt,
+ * otherwise schedule a tasklet to handle the buffers.
+ */
+ if (cl_rx_process_in_irq(cl_hw))
+ cl_rx_pci_desc_handler(cl_hw);
+ else
+ tasklet_schedule(&ipc_env->rxdesc_tasklet);
+}
+
+static void cl_irq_status_txcfm(struct cl_hw *cl_hw, struct cl_ipc_host_env *ipc_env)
+{
+ /*
+ * Disable the TXCFM interrupt bit - will be enabled
+ * at the end of cl_tx_pci_single_cfm_tasklet()
+ */
+ cl_irq_disable(cl_hw, cl_hw->ipc_e2a_irq.txcfm);
+
+ /* Acknowledge the TXCFM interrupt */
+ ipc_xmac_2_host_ack_set(cl_hw->chip, cl_hw->ipc_e2a_irq.txcfm);
+
+ /* Schedule tasklet to handle the TXCFM */
+ tasklet_schedule(&ipc_env->tx_single_cfm_tasklet);
+}
+
+static void cl_irq_status_tbtt(struct cl_hw *cl_hw)
+{
+ unsigned long tbtt_diff_msec = jiffies_to_msecs(jiffies - cl_hw->last_tbtt_irq);
+
+ /* Acknowledge the interrupt BEFORE handling the request */
+ ipc_xmac_2_host_ack_set(cl_hw->chip, cl_hw->ipc_e2a_irq.tbtt);
+
+ cl_hw->last_tbtt_irq = jiffies;
+ cl_hw->tbtt_cnt++;
+
+ /*
+ * Send beacon only if radio is on, there is at least one AP interface
+ * up, we aren't in the middle of recovery, and user didn't disable them.
+ */
+ if (cl_radio_is_off(cl_hw) ||
+ cl_hw->vif_db.num_iface_bcn == 0 ||
+ cl_recovery_in_progress(cl_hw) ||
+ cl_hw->tx_disable_flags ||
+ !test_bit(CL_DEV_STARTED, &cl_hw->drv_flags) ||
+ test_bit(CL_DEV_FW_ERROR, &cl_hw->drv_flags))
+ return;
+
+ if (cl_hw->iface_conf == CL_IFCONF_MESH_ONLY ||
+ (cl_hw->mesh_tbtt_div > 1 &&
+ ((cl_hw->tbtt_cnt % cl_hw->mesh_tbtt_div) == 0))) {
+ tasklet_hi_schedule(&cl_hw->tx_mesh_bcn_task);
+ } else {
+ /*
+ * More than 2 times the beacon interval passed between beacons - WARNING
+ * More than 3 times the beacon interval passed between beacons - ERROR
+ */
+ if (tbtt_diff_msec > (cl_hw->conf->ha_beacon_int * 3))
+ cl_dbg_err(cl_hw, "last_tbtt_irq=%lu, curr_time=%lu, diff=%lu\n",
+ cl_hw->last_tbtt_irq, jiffies, tbtt_diff_msec);
+ else if (tbtt_diff_msec > (cl_hw->conf->ha_beacon_int * 2))
+ cl_dbg_warn(cl_hw, "last_tbtt_irq=%lu, curr_time=%lu, diff=%lu\n",
+ cl_hw->last_tbtt_irq, jiffies, tbtt_diff_msec);
+ }
+
+ cl_tx_bcns(cl_hw);
+}
+
+static void cl_irq_status_msg(struct cl_hw *cl_hw, struct cl_ipc_host_env *ipc_env)
+{
+ /* Acknowledge the interrupt BEFORE handling the request */
+ ipc_xmac_2_host_ack_set(cl_hw->chip, cl_hw->ipc_e2a_irq.msg);
+
+ /* Schedule tasklet to handle the messages */
+ tasklet_schedule(&ipc_env->msg_tasklet);
+}
+
+static u8 cl_radar_handler(struct cl_hw *cl_hw, ptrdiff_t hostid)
+{
+ struct cl_radar_elem *radar_elem = (struct cl_radar_elem *)hostid;
+ u8 ret = 0;
+ struct cl_radar_pulse_array *pulses;
+
+ /* Retrieve the radar pulses structure */
+ pulses = (struct cl_radar_pulse_array *)radar_elem->radarbuf_ptr;
+
+ /* Look for pulse count meaning that this hostbuf contains RADAR pulses */
+ if (pulses->cnt == 0) {
+ ret = -1;
+ goto radar_no_push;
+ }
+
+ /* Push pulse information to queue and schedule a tasklet to handle it */
+ cl_radar_push(cl_hw, radar_elem);
+
+ /* Reset the radar element and re-use it */
+ pulses->cnt = 0;
+
+ /* Make sure memory is written before push to HW */
+ wmb();
+
+ /* Push back the buffer to the firmware */
+ cl_ipc_radarbuf_push(cl_hw->ipc_env, (ptrdiff_t)radar_elem, radar_elem->dma_addr);
+
+radar_no_push:
+ return ret;
+}
+
+static void cl_irq_status_radar(struct cl_hw *cl_hw, struct cl_ipc_host_env *ipc_env)
+{
+ /*
+ * Firmware has triggered an IT saying that a radar event has been sent to upper layer.
+ * Then we first need to check the validity of the current msg buf, and the validity
+ * of the next buffers too, because it is likely that several buffers have been
+ * filled within the time needed for this irq handling
+ */
+
+ /* Disable the RADAR interrupt bit - will be enabled at the end of cl_radar_tasklet() */
+ cl_irq_disable(cl_hw, cl_hw->ipc_e2a_irq.radar);
+
+ /* Acknowledge the RADAR interrupt */
+ ipc_xmac_2_host_ack_set(cl_hw->chip, cl_hw->ipc_e2a_irq.radar);
+
+ /* Push all new radar pulses to queue */
+ while (cl_radar_handler(cl_hw,
+ ipc_env->radar_hostbuf_array[ipc_env->radar_host_idx].hostid) == 0)
+ ;
+
+ /* Schedule tasklet to handle the radar pulses */
+ cl_radar_tasklet_schedule(cl_hw);
+}
+
+static void cl_irq_status_dbg(struct cl_hw *cl_hw, struct cl_ipc_host_env *ipc_env)
+{
+ /* Disable the DBG interrupt bit - will be enabled at the end of cl_dbgfile_tasklet() */
+ cl_irq_disable(cl_hw, cl_hw->ipc_e2a_irq.dbg);
+
+ /* Acknowledge the DBG interrupt */
+ ipc_xmac_2_host_ack_set(cl_hw->chip, cl_hw->ipc_e2a_irq.dbg);
+
+ /* Schedule tasklet to handle the debug */
+ tasklet_schedule(&ipc_env->dbg_tasklet);
+}
+
+static void cl_irq_status_txdesc_ind(struct cl_hw *cl_hw, struct cl_ipc_host_env *ipc_env)
+{
+ /*
+ * Disable the TXDESC_IND interrupt bit -
+ * will be enabled at the end of cl_tx_pci_agg_cfm_tasklet()
+ */
+ cl_irq_disable(cl_hw, cl_hw->ipc_e2a_irq.txdesc_ind);
+
+ /* Acknowledge the TXDESC_IND interrupt */
+ ipc_xmac_2_host_ack_set(cl_hw->chip, cl_hw->ipc_e2a_irq.txdesc_ind);
+
+ tasklet_schedule(&ipc_env->tx_agg_cfm_tasklet);
+ tasklet_schedule(&cl_hw->tx_task);
+}
+
+static void cl_irq_status_sync(struct cl_hw *cl_hw, struct cl_ipc_host_env *ipc_env)
+{
+ /* Acknowledge the interrupt BEFORE handling the request */
+ ipc_xmac_2_host_ack_set(cl_hw->chip, cl_hw->ipc_e2a_irq.sync);
+
+ set_bit(CL_DEV_FW_SYNC, &cl_hw->drv_flags);
+ wake_up_interruptible(&cl_hw->fw_sync_wq);
+}
+
+void cl_irq_status(struct cl_hw *cl_hw, u32 status)
+{
+ /* Handle all IPC interrupts on the host side */
+ struct cl_ipc_host_env *ipc_env = cl_hw->ipc_env;
+
+ if (status & cl_hw->ipc_e2a_irq.rxdesc)
+ cl_irq_status_rxdesc(cl_hw, ipc_env);
+
+ if (status & cl_hw->ipc_e2a_irq.txcfm)
+ cl_irq_status_txcfm(cl_hw, ipc_env);
+
+ if (status & cl_hw->ipc_e2a_irq.tbtt)
+ cl_irq_status_tbtt(cl_hw);
+
+ if (status & cl_hw->ipc_e2a_irq.msg)
+ cl_irq_status_msg(cl_hw, ipc_env);
+
+ if (status & cl_hw->ipc_e2a_irq.radar)
+ cl_irq_status_radar(cl_hw, ipc_env);
+
+ if (status & cl_hw->ipc_e2a_irq.dbg)
+ cl_irq_status_dbg(cl_hw, ipc_env);
+
+ if (status & cl_hw->ipc_e2a_irq.txdesc_ind)
+ cl_irq_status_txdesc_ind(cl_hw, ipc_env);
+
+ if (status & cl_hw->ipc_e2a_irq.sync)
+ cl_irq_status_sync(cl_hw, ipc_env);
+}
+
+#ifdef CONFIG_CL_PCIE
+static void cl_irq_handler(struct cl_chip *chip)
+{
+ /* Interrupt handler */
+ u32 status, statuses = 0;
+ unsigned long now = jiffies;
+ struct cl_irq_stats *irq_stats = &chip->irq_stats;
+
+ while ((status = ipc_xmac_2_host_status_get(chip))) {
+ statuses |= status;
+
+ if (status & IPC_IRQ_L2H_ALL)
+ cl_irq_status(chip->cl_hw_tcv0, status);
+
+ if (status & IPC_IRQ_S2H_ALL)
+ cl_irq_status(chip->cl_hw_tcv1, status);
+ }
+
+ if (statuses & (IPC_IRQ_L2H_RXDESC | IPC_IRQ_S2H_RXDESC))
+ irq_stats->last_rx = now;
+
+ if (statuses & (IPC_IRQ_L2H_TXCFM | IPC_IRQ_S2H_TXCFM))
+ irq_stats->last_tx = now;
+
+ irq_stats->last_isr = now;
+ irq_stats->last_isr_statuses = statuses;
+}
+
+static irqreturn_t cl_irq_request_handler(int irq, void *dev_id)
+{
+ struct cl_chip *chip = (struct cl_chip *)dev_id;
+
+ cl_irq_handler(chip);
+
+ return IRQ_HANDLED;
+}
+
+#ifdef CONFIG_SMP
+static void cl_irq_set_affinity(struct cl_chip *chip, struct pci_dev *pci_dev)
+{
+ s32 irq_smp_affinity = chip->conf->ce_irq_smp_affinity;
+
+ if (irq_smp_affinity != -1) {
+ struct irq_data *data = irq_get_irq_data(pci_dev->irq);
+
+ if (data) {
+ static struct cpumask mask;
+
+ cpumask_clear(&mask);
+ cpumask_set_cpu(irq_smp_affinity, &mask);
+
+ if (data->chip->irq_set_affinity) {
+ data->chip->irq_set_affinity(data, &mask, false);
+ pr_debug("irq=%d, affinity=%d\n", pci_dev->irq, irq_smp_affinity);
+ }
+ }
+ }
+}
+#endif
+
+int cl_irq_request(struct cl_chip *chip)
+{
+ /*
+ * Allocate host irq line.
+ * Enable PCIe device interrupts
+ */
+ int ret;
+ /* Request exclusive PCI interrupt in firmware test mode */
+ struct pci_dev *pci_dev = chip->pci_dev;
+
+ ret = request_irq(pci_dev->irq, cl_irq_request_handler, IRQF_SHARED, "cl", chip);
+
+ if (ret) {
+ pr_err("ERROR: could not assign interrupt %d, err=%d\n", pci_dev->irq, ret);
+ return ret;
+ }
+
+#ifdef CONFIG_SMP
+ cl_irq_set_affinity(chip, pci_dev);
+#endif
+
+ return ret;
+}
+
+void cl_irq_free(struct cl_chip *chip)
+{
+ struct pci_dev *pci_dev = chip->pci_dev;
+ /* Disable PCI device interrupt and release irq line */
+ free_irq(pci_dev->irq, chip);
+}
+#endif /* CONFIG_CL_PCIE */
+
+void cl_irq_enable(struct cl_hw *cl_hw, u32 value)
+{
+ /* Enable IPC interrupts */
+ ipc_xmac_2_host_enable_set_set(cl_hw->chip, value);
+}
+
+void cl_irq_disable(struct cl_hw *cl_hw, u32 value)
+{
+ /* Disable IPC interrupts */
+ ipc_xmac_2_host_enable_clear_set(cl_hw->chip, value);
+}
--
2.30.0

________________________________
The information transmitted is intended only for the person or entity to which it is addressed and may contain confidential and/or privileged material. Any retransmission, dissemination, copying or other use of, or taking of any action in reliance upon this information is prohibited. If you received this in error, please contact the sender and delete the material from any computer. Nothing contained herein shall be deemed as a representation, warranty or a commitment by Celeno. No warranties are expressed or implied, including, but not limited to, any implied warranties of non-infringement, merchantability and fitness for a particular purpose.
________________________________

2021-06-17 16:24:16

by viktor.barna

[permalink] [raw]
Subject: [RFC v1 037/256] cl8k: add chandef.h

From: Viktor Barna <[email protected]>

(Part of the split. Please, take a look at the cover letter for more
details).

Signed-off-by: Viktor Barna <[email protected]>
---
drivers/net/wireless/celeno/cl8k/chandef.h | 14 ++++++++++++++
1 file changed, 14 insertions(+)
create mode 100644 drivers/net/wireless/celeno/cl8k/chandef.h

diff --git a/drivers/net/wireless/celeno/cl8k/chandef.h b/drivers/net/wireless/celeno/cl8k/chandef.h
new file mode 100644
index 000000000000..414e5c76f09f
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/chandef.h
@@ -0,0 +1,14 @@
+/* SPDX-License-Identifier: MIT */
+/* Copyright(c) 2019-2021, Celeno Communications Ltd. */
+
+#ifndef CL_CHANDEF_H
+#define CL_CHANDEF_H
+
+#include "hw.h"
+
+int cl_chandef_calc(struct cl_hw *cl_hw, u32 channel, u32 bw,
+ enum nl80211_chan_width *width, u32 *primary, u32 *center);
+int cl_chandef_get_default(struct cl_hw *cl_hw, enum nl80211_chan_width *width,
+ u32 *primary, u32 *center);
+
+#endif /* CL_CHANDEF_H */
--
2.30.0

________________________________
The information transmitted is intended only for the person or entity to which it is addressed and may contain confidential and/or privileged material. Any retransmission, dissemination, copying or other use of, or taking of any action in reliance upon this information is prohibited. If you received this in error, please contact the sender and delete the material from any computer. Nothing contained herein shall be deemed as a representation, warranty or a commitment by Celeno. No warranties are expressed or implied, including, but not limited to, any implied warranties of non-infringement, merchantability and fitness for a particular purpose.
________________________________

2021-06-17 16:24:21

by viktor.barna

[permalink] [raw]
Subject: [RFC v1 020/256] cl8k: add bus/pci/irq.h

From: Viktor Barna <[email protected]>

(Part of the split. Please, take a look at the cover letter for more
details).

Signed-off-by: Viktor Barna <[email protected]>
---
drivers/net/wireless/celeno/cl8k/bus/pci/irq.h | 15 +++++++++++++++
1 file changed, 15 insertions(+)
create mode 100644 drivers/net/wireless/celeno/cl8k/bus/pci/irq.h

diff --git a/drivers/net/wireless/celeno/cl8k/bus/pci/irq.h b/drivers/net/wireless/celeno/cl8k/bus/pci/irq.h
new file mode 100644
index 000000000000..10fe4588c1bb
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/bus/pci/irq.h
@@ -0,0 +1,15 @@
+/* SPDX-License-Identifier: MIT */
+/* Copyright(c) 2019-2021, Celeno Communications Ltd. */
+
+#ifndef CL_IRQ_H
+#define CL_IRQ_H
+
+#ifdef CONFIG_CL_PCIE
+int cl_irq_request(struct cl_chip *chip);
+void cl_irq_free(struct cl_chip *chip);
+#endif
+void cl_irq_status(struct cl_hw *cl_hw, u32 status);
+void cl_irq_enable(struct cl_hw *cl_hw, u32 value);
+void cl_irq_disable(struct cl_hw *cl_hw, u32 value);
+
+#endif /* CL_IRQ_H */
--
2.30.0

________________________________
The information transmitted is intended only for the person or entity to which it is addressed and may contain confidential and/or privileged material. Any retransmission, dissemination, copying or other use of, or taking of any action in reliance upon this information is prohibited. If you received this in error, please contact the sender and delete the material from any computer. Nothing contained herein shall be deemed as a representation, warranty or a commitment by Celeno. No warranties are expressed or implied, including, but not limited to, any implied warranties of non-infringement, merchantability and fitness for a particular purpose.
________________________________

2021-06-17 16:24:21

by viktor.barna

[permalink] [raw]
Subject: [RFC v1 046/256] cl8k: add config.c

From: Viktor Barna <[email protected]>

(Part of the split. Please, take a look at the cover letter for more
details).

Signed-off-by: Viktor Barna <[email protected]>
---
drivers/net/wireless/celeno/cl8k/config.c | 121 ++++++++++++++++++++++
1 file changed, 121 insertions(+)
create mode 100644 drivers/net/wireless/celeno/cl8k/config.c

diff --git a/drivers/net/wireless/celeno/cl8k/config.c b/drivers/net/wireless/celeno/cl8k/config.c
new file mode 100644
index 000000000000..8dbe72adfd3d
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/config.c
@@ -0,0 +1,121 @@
+// SPDX-License-Identifier: MIT
+/* Copyright(c) 2019-2021, Celeno Communications Ltd. */
+
+#include "chip_config.h"
+#include "fw/msg_tx.h"
+
+static char *non_driver_conf_params[] = {
+ "ws_",
+ "ha_",
+ "uuid1",
+ "ce_pci_id",
+ "ce_rst_gpio",
+ "ce_iface_eth",
+ "ce_iface_vlan",
+ "ce_iface_ip",
+ "ci_sim_chip_num",
+ "ci_lcu_dump_folder",
+ "ci_server_addr",
+ "ci_server_user",
+ NULL
+};
+
+bool cl_config_is_non_driver_param(char *name)
+{
+ int i = 0;
+
+ for (i = 0; non_driver_conf_params[i]; i++)
+ if (!strncmp(name, non_driver_conf_params[i], strlen(non_driver_conf_params[i])))
+ return true;
+
+ return false;
+}
+
+static int cl_config_cli_help(struct cl_hw *cl_hw)
+{
+ char *buf = kzalloc(PAGE_SIZE, GFP_KERNEL);
+ int err = 0;
+
+ if (!buf)
+ return -ENOMEM;
+
+ snprintf(buf, PAGE_SIZE,
+ "config usage:\n"
+ "-c : Print chip configuration\n"
+ "-n : Set NDP TX parameters [chain mask][bw][format][num_ltf]\n"
+ "-t : Print tcv configuration\n");
+
+ err = cl_vendor_reply(cl_hw, buf, strlen(buf));
+ kfree(buf);
+
+ return err;
+}
+
+int cl_config_cli(struct cl_hw *cl_hw, struct cli_params *cli_params)
+{
+ bool print_chip = false;
+ bool set_ndp_tx_ctrl = false;
+ bool print_tcv = false;
+ int expected_params = -1;
+
+ switch (cli_params->option) {
+ case 'c':
+ print_chip = true;
+ expected_params = 0;
+ break;
+ case 'n':
+ set_ndp_tx_ctrl = true;
+ expected_params = 4;
+ break;
+ case 't':
+ print_tcv = true;
+ expected_params = 0;
+ break;
+ case '?':
+ return cl_config_cli_help(cl_hw);
+ default:
+ cl_dbg_err(cl_hw, "Illegal option (%c) - try '?' for help\n", cli_params->option);
+ goto out_err;
+ }
+
+ if (expected_params != cli_params->num_params) {
+ cl_dbg_err(cl_hw, "Wrong number of arguments (expected %u) (actual %u)\n",
+ expected_params, cli_params->num_params);
+ goto out_err;
+ }
+
+ if (print_chip) {
+ cl_chip_config_print(cl_hw->chip);
+ return 0;
+ }
+
+ if (set_ndp_tx_ctrl) {
+ u8 chain_mask = (u8)cli_params->params[0];
+ u8 bw = (u8)cli_params->params[1];
+ u8 format = (u8)cli_params->params[2];
+ u8 num_ltf = (u8)cli_params->params[3];
+
+ if (IS_VALID_TX_CHAINS(chain_mask) &&
+ bw < CHNL_BW_MAX &&
+ format < FORMATMOD_MAX &&
+ num_ltf < LTF_MAX) {
+ cl_hw->conf->ci_ndp_tx_chain_mask = chain_mask;
+ cl_hw->conf->ci_ndp_tx_bw = bw;
+ cl_hw->conf->ci_ndp_tx_format = format;
+ cl_hw->conf->ci_ndp_tx_num_ltf = num_ltf;
+ cl_msg_tx_ndp_tx_control(cl_hw, chain_mask, bw, format, num_ltf);
+ } else {
+ pr_err("Invalid parametets [chain_mask %x][bw %u][format %u][num_ltf %u]\n",
+ chain_mask, bw, format, num_ltf);
+ }
+ return 0;
+ }
+
+ if (print_tcv) {
+ cl_tcv_config_print(cl_hw);
+ return 0;
+ }
+
+out_err:
+ return -EIO;
+}
--
2.30.0

________________________________
The information transmitted is intended only for the person or entity to which it is addressed and may contain confidential and/or privileged material. Any retransmission, dissemination, copying or other use of, or taking of any action in reliance upon this information is prohibited. If you received this in error, please contact the sender and delete the material from any computer. Nothing contained herein shall be deemed as a representation, warranty or a commitment by Celeno. No warranties are expressed or implied, including, but not limited to, any implied warranties of non-infringement, merchantability and fitness for a particular purpose.
________________________________

2021-06-17 16:24:23

by viktor.barna

[permalink] [raw]
Subject: [RFC v1 040/256] cl8k: add chan_info.c

From: Viktor Barna <[email protected]>

(Part of the split. Please, take a look at the cover letter for more
details).

Signed-off-by: Viktor Barna <[email protected]>
---
drivers/net/wireless/celeno/cl8k/chan_info.c | 852 +++++++++++++++++++
1 file changed, 852 insertions(+)
create mode 100644 drivers/net/wireless/celeno/cl8k/chan_info.c

diff --git a/drivers/net/wireless/celeno/cl8k/chan_info.c b/drivers/net/wireless/celeno/cl8k/chan_info.c
new file mode 100644
index 000000000000..95b09128c166
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/chan_info.c
@@ -0,0 +1,852 @@
+// SPDX-License-Identifier: MIT
+/* Copyright(c) 2019-2021, Celeno Communications Ltd. */
+
+#include "chan_info.h"
+#include "utils/utils.h"
+#include "chip.h"
+#include "utils/math.h"
+#include "band.h"
+#include "utils/string.h"
+#include "channel.h"
+#include "utils/file.h"
+
+struct ieee80211_regdomain cl_regdom_24g = {
+ .n_reg_rules = 2,
+ .alpha2 = "99",
+ .reg_rules = {
+ REG_RULE(2412 - 10, 2472 + 10, 40, 6, 20, 0),
+ REG_RULE(2484 - 10, 2484 + 10, 20, 6, 20, 0),
+ }
+};
+
+struct ieee80211_regdomain cl_regdom_5g = {
+ .n_reg_rules = 1,
+ .alpha2 = "99",
+ .reg_rules = {
+ REG_RULE(5150 - 10, 5850 + 10, 80, 6, 30, 0),
+ }
+};
+
+struct ieee80211_regdomain cl_regdom_6g = {
+ .n_reg_rules = 1,
+ .alpha2 = "99",
+ .reg_rules = {
+ REG_RULE(5935 - 10, 7115 + 10, 80, 6, 30, 0),
+ }
+};
+
+static inline s32 convert_str_int_q2(s8 *str)
+{
+ s32 x, y;
+
+ if (!str)
+ return 0;
+ if (sscanf(str, "%d.%2d", &x, &y) != 2)
+ return 0;
+ if (!strstr(str, "."))
+ return x * 4;
+ if (y < 10 && (*(strstr(str, ".") + 1) != '0'))
+ y *= 10;
+ return (x * 100 + y) * 4 / 100;
+}
+
+static int cl_parse_reg_domain(struct cl_hw *cl_hw, char **str)
+{
+ /* Check if current line contains "FCC" or "ETSI" */
+ char *token = strsep(str, "\n");
+
+ if (!token)
+ goto err;
+
+ if (strstr(token, "FCC")) {
+ cl_hw->channel_info.standard = CL_STANDARD_FCC;
+ cl_dbg_info(cl_hw, "Standard = FCC\n");
+ return 0;
+ }
+
+ if (strstr(token, "ETSI")) {
+ cl_hw->channel_info.standard = CL_STANDARD_ETSI;
+ cl_dbg_info(cl_hw, "Standard = ETSI\n");
+ return 0;
+ }
+
+err:
+ cl_dbg_err(cl_hw, "Illegal regulatory domain\n");
+ cl_hw->channel_info.standard = CL_STANDARD_NONE;
+ return -1;
+}
+
+#define MAX_CC_STR 4
+#define MAX_BW_STR 8
+
+static bool cl_parse_channel_info_txt(struct cl_hw *cl_hw)
+{
+ /*
+ * Example of country information in channel_info.txt:
+ *
+ * [EU (European Union)ETSI]
+ * 2.4GHz/20MHz: 2412(1,20) 2417(2,20) 2422(3,20) 2427(4,20) 2432(5,20) 2437(6,20)
+ * 2442(7,20) 2447(8,20) 2452(9,20) 2457(10,20) 2462(11,20) 2467(12,20)
+ * 2472(13,20)
+ * 2.4GHz/40MHz: 2422(1,20) 2427(2,20) 2432(3,20) 2437(4,20) 2442(5,20) 2447(6,20)
+ * 2452(7,20) 2457(8,20) 2462(9,20) 2467(10,20) 2472(11,20)
+ * 5.2GHz/20MHz: 5180(36,23) 5200(40,23) 5220(44,23) 5240(48,23) 5260(52,23) 5280(56,23)
+ * 5300(60,23) 5320(64,23) 5500(100,30) 5520(104,30) 5540(108,30)
+ * 5560(112,30)5580(116,30) 5600(120,30) 5620(124,30) 5640(128,30)
+ * 5660(132,30) 5680(136,30) 5700(140,30)
+ * 5.2GHz/40MHz: 5180(36,23) 5200(40,23) 5220(44,23) 5240(48,23) 5260(52,23) 5280(56,23)
+ * 5300(60,23) 5310(64,23) 5510(100,30) 5510(104,30) 5550(108,30)
+ * 5550(112,30) 5590(116,30) 5590(120,30) 5630(124,30) 5630(128,30)
+ * 5670(132,30) 5670(136,30)
+ * 5.2GHz/80MHz: 5180(36,23) 5200(40,23) 5220(44,23) 5240(48,23) 5260(52,23) 5280(56,23)
+ * 5300(60,23) 5310(64,23) 5510(100,30) 5510(104,30) 5550(108,30)
+ * 5550(112,30) 5590(116,30) 5590(120,30) 5630(124,30) 5630(128,30)
+ * 5.2GHz/160MHz: 5180(36,23) 5200(40,23) 5220(44,23) 5240(48,23) 5260(52,23) 5280(56,23)
+ * 5300(60,23) 5310(64,23) 5510(100,30) 5510(104,30) 5550(108,30)
+ * 5550(112,30) 5590(116,30) 5590(120,30) 5630(124,30) 5630(128,30)
+ */
+
+ struct cl_channel_info *channel_info = &cl_hw->channel_info;
+ char *buf = NULL, *ptr = NULL;
+ char cc_str[MAX_CC_STR] = {0};
+ char bw_str[MAX_BW_STR] = {0};
+ size_t size;
+ u8 bw, bw_mhz, bw_max, max_power, channel, i;
+
+ /* Read channel_info.txt into buf */
+ size = cl_file_open_and_read(cl_hw->chip, "channel_info.txt", &buf);
+
+ if (!buf)
+ return false;
+
+ /* Jump to the correct country in the file */
+ snprintf(cc_str, sizeof(cc_str), "[%s", cl_hw->chip->conf->ce_country_code);
+ ptr = strstr(buf, cc_str);
+ if (!ptr)
+ goto out;
+
+ if (cl_parse_reg_domain(cl_hw, &ptr))
+ goto out;
+
+ /* Jump to the relevant band */
+ if (cl_band_is_24g(cl_hw)) {
+ bw_max = CHNL_BW_40;
+ ptr = strstr(ptr, "2.4GHz");
+ } else if (cl_band_is_5g(cl_hw)) {
+ ptr = strstr(ptr, "5.2GHz");
+ bw_max = CHNL_BW_160;
+ } else {
+ ptr = strstr(ptr, "6GHz");
+ bw_max = CHNL_BW_160;
+ }
+
+ for (bw = 0; bw <= bw_max; bw++) {
+ if (!ptr)
+ goto out;
+
+ i = 0;
+
+ /* Jump to relevant bandwidth */
+ bw_mhz = BW_TO_MHZ(bw);
+ snprintf(bw_str, sizeof(bw_str), "%uMHz:", bw_mhz);
+ ptr = strstr(ptr, bw_str);
+
+ /* Iterate until end of line and parse (channel, max_power) */
+ while (ptr && (ptr + 1) && (*(ptr + 1) != '\n')) {
+ ptr = strstr(ptr, "(");
+ if (!ptr)
+ goto out;
+
+ if (sscanf(ptr, "(%hhu,%hhu)", &channel, &max_power) != 2)
+ goto out;
+
+ if (!cl_channel_is_valid(cl_hw, channel) ||
+ i == cl_channel_num(cl_hw))
+ goto out;
+
+ channel_info->channels[bw][i].channel = channel;
+ channel_info->channels[bw][i].max_power_q2 = max_power << 2;
+ channel_info->channels[bw][i].country_max_power_q2 = max_power << 2;
+
+ i++;
+ ptr = strstr(ptr, ")");
+ }
+ }
+
+ kfree(buf);
+ return true;
+
+out:
+ kfree(buf);
+ return false;
+}
+
+static bool cl_is_parsing_success(struct cl_hw *cl_hw)
+{
+ /* Check that there is at least one channel in any bw */
+ u8 bw;
+ u8 max_bw = BAND_IS_5G_6G(cl_hw) ? CHNL_BW_160 : CHNL_BW_40;
+
+ for (bw = 0; bw <= max_bw; bw++)
+ if (!cl_hw->channel_info.channels[bw][0].channel)
+ return false;
+
+ return true;
+}
+
+static void cl_chan_info_set_max_bw_6g(struct cl_hw *cl_hw)
+{
+ u8 i, bw, bw_cnt, channel, channel_gap;
+ struct cl_chan_info *chan_info;
+
+ for (bw = 0; bw < CHNL_BW_MAX; bw++) {
+ chan_info = cl_hw->channel_info.channels[bw];
+ bw_cnt = 0;
+
+ for (i = 0; i < NUM_CHANNELS_6G; i++) {
+ channel = chan_info[i].channel;
+
+ if (channel == 0)
+ break;
+
+ channel_gap = channel - START_CHAN_IDX_6G;
+
+ /*
+ * Verify that we don't combine together channels
+ * from different 80MHz sections
+ */
+ if ((channel_gap % CL_160MHZ_CH_GAP) == 0)
+ bw_cnt = 0;
+
+ if (i > 0)
+ bw_cnt++;
+
+ /* Verify that we don't make illegal 80MHz combination */
+ if ((channel_gap % CL_80MHZ_CH_GAP == 0) && bw_cnt == 3)
+ bw_cnt = 0;
+
+ /* Verify that we don't make illegal 40MHz combination */
+ if ((channel_gap % CL_40MHZ_CH_GAP == 0) && bw_cnt == 1)
+ bw_cnt = 0;
+
+ if ((((bw_cnt + 1) % CL_160MHZ_HOP) == 0) && bw == CHNL_BW_160) {
+ chan_info[i].max_bw = CHNL_BW_160;
+ chan_info[i - 1].max_bw = CHNL_BW_160;
+ chan_info[i - 2].max_bw = CHNL_BW_160;
+ chan_info[i - 3].max_bw = CHNL_BW_160;
+ chan_info[i - 4].max_bw = CHNL_BW_160;
+ chan_info[i - 5].max_bw = CHNL_BW_160;
+ chan_info[i - 6].max_bw = CHNL_BW_160;
+ chan_info[i - 7].max_bw = CHNL_BW_160;
+ } else if ((((bw_cnt + 1) % CL_80MHZ_HOP) == 0) && (bw == CHNL_BW_80)) {
+ chan_info[i].max_bw = CHNL_BW_80;
+ chan_info[i - 1].max_bw = CHNL_BW_80;
+ chan_info[i - 2].max_bw = CHNL_BW_80;
+ chan_info[i - 3].max_bw = CHNL_BW_80;
+ } else if ((((bw_cnt + 1) % CL_40MHZ_HOP) == 0) && (bw >= CHNL_BW_40)) {
+ chan_info[i].max_bw = CHNL_BW_40;
+ chan_info[i - 1].max_bw = CHNL_BW_40;
+ } else {
+ chan_info[i].max_bw = CHNL_BW_20;
+ }
+ }
+ }
+}
+
+static void cl_chan_info_set_max_bw_5g(struct cl_hw *cl_hw)
+{
+ u8 i, bw, bw_cnt, channel, channel_gap;
+ struct cl_chan_info *chan_info;
+
+ for (bw = 0; bw < CHNL_BW_MAX; bw++) {
+ chan_info = cl_hw->channel_info.channels[bw];
+ bw_cnt = 0;
+
+ for (i = 0; i < NUM_CHANNELS_5G; i++) {
+ channel = chan_info[i].channel;
+
+ if (channel == 0)
+ break;
+
+ if (channel < 149)
+ channel_gap = channel - 36;
+ else
+ channel_gap = channel - 149;
+
+ /*
+ * Verify that we don't combine together channels from
+ * different 80MHz sections
+ * (i.e. 36-48 can be combined into 80MHz channels, unlike 40-52)
+ */
+ if ((channel_gap % CL_160MHZ_CH_GAP) == 0)
+ bw_cnt = 0;
+
+ /* Check if 20MHz channels can be combined into 40MHz or 80MHz channels */
+ if (i > 0) {
+ /*
+ * Verify that we don't combine together unsecutive channels
+ * (like 36 and 44 when 40 is missing)
+ */
+ if ((chan_info[i].channel - chan_info[i - 1].channel) >
+ CL_20MHZ_CH_GAP)
+ bw_cnt = 0;
+ else
+ bw_cnt++;
+ }
+
+ /* Verify that we don't make illegal 80MHz combination (like 44-56) */
+ if ((channel_gap % CL_80MHZ_CH_GAP == 0) && bw_cnt == 3)
+ bw_cnt = 0;
+
+ /* Verify that we don't make illegal 40MHz combination (like 40-44) */
+ if ((channel_gap % CL_40MHZ_CH_GAP == 0) && bw_cnt == 1)
+ bw_cnt = 0;
+
+ if ((((bw_cnt + 1) % CL_160MHZ_HOP) == 0) && bw == CHNL_BW_160) {
+ chan_info[i].max_bw = CHNL_BW_160;
+ chan_info[i - 1].max_bw = CHNL_BW_160;
+ chan_info[i - 2].max_bw = CHNL_BW_160;
+ chan_info[i - 3].max_bw = CHNL_BW_160;
+ chan_info[i - 4].max_bw = CHNL_BW_160;
+ chan_info[i - 5].max_bw = CHNL_BW_160;
+ chan_info[i - 6].max_bw = CHNL_BW_160;
+ chan_info[i - 7].max_bw = CHNL_BW_160;
+ } else if ((((bw_cnt + 1) % CL_80MHZ_HOP) == 0) && bw == CHNL_BW_80) {
+ chan_info[i].max_bw = CHNL_BW_80;
+ chan_info[i - 1].max_bw = CHNL_BW_80;
+ chan_info[i - 2].max_bw = CHNL_BW_80;
+ chan_info[i - 3].max_bw = CHNL_BW_80;
+ } else if ((((bw_cnt + 1) % CL_40MHZ_HOP) == 0) && bw >= CHNL_BW_40) {
+ chan_info[i].max_bw = CHNL_BW_40;
+ chan_info[i - 1].max_bw = CHNL_BW_40;
+ } else {
+ chan_info[i].max_bw = CHNL_BW_20;
+ }
+ }
+ }
+}
+
+static void cl_chan_info_set_max_bw_24g(struct cl_hw *cl_hw)
+{
+ u8 i, bw, channel;
+ struct cl_chan_info *chan_info;
+
+ for (bw = 0; bw < CHNL_BW_80; bw++) {
+ chan_info = cl_hw->channel_info.channels[bw];
+
+ for (i = 0; i < NUM_CHANNELS_24G; i++) {
+ channel = chan_info[i].channel;
+
+ if (channel == 0)
+ break;
+
+ if (channel < 14)
+ chan_info[i].max_bw = CHNL_BW_40;
+ else
+ chan_info[i].max_bw = CHNL_BW_20;
+ }
+ }
+}
+
+static void cl_chan_info_set_max_bw(struct cl_hw *cl_hw)
+{
+ if (cl_band_is_6g(cl_hw))
+ cl_chan_info_set_max_bw_6g(cl_hw);
+ else if (cl_band_is_5g(cl_hw))
+ cl_chan_info_set_max_bw_5g(cl_hw);
+ else
+ cl_chan_info_set_max_bw_24g(cl_hw);
+}
+
+static void cl_chan_info_dbg(struct cl_hw *cl_hw)
+{
+ struct cl_chan_info *chan_info;
+ u32 max_power_integer, max_power_fraction;
+ u8 i, j;
+
+ for (i = 0; i < CHNL_BW_MAX; i++) {
+ cl_dbg_info(cl_hw, "Bandwidth = %uMHz\n", BW_TO_MHZ(i));
+ for (j = 0; j < cl_channel_num(cl_hw); j++) {
+ chan_info = &cl_hw->channel_info.channels[i][j];
+
+ if (chan_info->channel == 0)
+ continue;
+
+ max_power_integer = (chan_info->max_power_q2 / 4);
+ max_power_fraction =
+ (100 * (chan_info->max_power_q2 - 4 * max_power_integer) / 4);
+
+ cl_dbg_info(cl_hw, "Channel = %u, max EIRP = %3u.%02u, bw = %uMHz\n",
+ chan_info->channel, max_power_integer,
+ max_power_fraction, BW_TO_MHZ(chan_info->max_bw));
+ }
+ }
+}
+
+/* Band 6G - default power */
+#define UNII_5_POW_Q2 (27 << 2)
+#define UNII_6_POW_Q2 (27 << 2)
+#define UNII_7_POW_Q2 (27 << 2)
+#define UNII_8_POW_Q2 (27 << 2)
+
+/* Band 5G - default power */
+#define UNII_1_POW_Q2 (22 << 2)
+#define UNII_2_POW_Q2 (27 << 2)
+#define UNII_2_EXT_POW_Q2 (27 << 2)
+#define UNII_3_POW_Q2 (27 << 2)
+
+/* Band 2.4G - default power */
+#define BAND_24G_POW_Q2 (36 << 2)
+
+static void cl_fill_channel_info(struct cl_hw *cl_hw, u8 bw, u8 ch_idx, u8 channel,
+ u8 country_max_power_q2, u8 max_power_q2)
+{
+ struct cl_channel_info *channel_info = &cl_hw->channel_info;
+
+ channel_info->channels[bw][ch_idx].channel = channel;
+ channel_info->channels[bw][ch_idx].country_max_power_q2 = country_max_power_q2;
+ channel_info->channels[bw][ch_idx].max_power_q2 = max_power_q2;
+}
+
+static void cl_set_default_channel_info_6g(struct cl_hw *cl_hw)
+{
+ u8 i, j, k;
+
+ for (i = 0; i < CHNL_BW_MAX; i++) {
+ k = 0;
+
+ /* Ch2 is a special case */
+ cl_fill_channel_info(cl_hw, i, k, 2, UNII_5_POW_Q2, UNII_5_POW_Q2);
+ k++;
+
+ for (j = START_CHAN_IDX_UNII5; j <= END_CHAN_IDX_UNII5; j += 4) {
+ cl_fill_channel_info(cl_hw, i, k, j, UNII_5_POW_Q2, UNII_5_POW_Q2);
+ k++;
+ }
+
+ for (j = START_CHAN_IDX_UNII6; j <= END_CHAN_IDX_UNII6; j += 4) {
+ cl_fill_channel_info(cl_hw, i, k, j, UNII_6_POW_Q2, UNII_6_POW_Q2);
+ k++;
+ }
+
+ for (j = START_CHAN_IDX_UNII7; j <= END_CHAN_IDX_UNII7; j += 4) {
+ cl_fill_channel_info(cl_hw, i, k, j, UNII_7_POW_Q2, UNII_7_POW_Q2);
+ k++;
+ }
+
+ for (j = START_CHAN_IDX_UNII8; j <= END_CHAN_IDX_UNII8; j += 4) {
+ /* Channel 233 is valid only in 20MHz */
+ if (i != CHNL_BW_20 && j == END_CHAN_IDX_UNII8)
+ break;
+
+ cl_fill_channel_info(cl_hw, i, k, j, UNII_8_POW_Q2, UNII_8_POW_Q2);
+ k++;
+ }
+ }
+}
+
+static void cl_set_default_channel_info_5g(struct cl_hw *cl_hw)
+{
+ u8 i, j, k;
+
+ for (i = 0; i < CHNL_BW_MAX; i++) {
+ k = 0;
+
+ for (j = 36; j <= 48; j += 4) {
+ cl_fill_channel_info(cl_hw, i, k, j, UNII_1_POW_Q2, UNII_1_POW_Q2);
+ k++;
+ }
+
+ for (j = 52; j <= 64; j += 4) {
+ cl_fill_channel_info(cl_hw, i, k, j, UNII_2_POW_Q2, UNII_2_POW_Q2);
+ k++;
+ }
+
+ for (j = 100; j <= 144; j += 4) {
+ /* 160MHz is supported only in channel 36 - 64 and 100 - 128 */
+ if (i == CHNL_BW_160 && j == 132)
+ return;
+
+ cl_fill_channel_info(cl_hw, i, k, j, UNII_2_EXT_POW_Q2, UNII_2_EXT_POW_Q2);
+ k++;
+ }
+
+ for (j = 149; j <= 165; j += 4) {
+ /* Channel 165 is valid only in 20MHz */
+ if (i != CHNL_BW_20 && j == 165)
+ break;
+
+ cl_fill_channel_info(cl_hw, i, k, j, UNII_3_POW_Q2, UNII_3_POW_Q2);
+ k++;
+ }
+ }
+}
+
+static void cl_set_default_channel_info_24g(struct cl_hw *cl_hw)
+{
+ u8 i, j;
+
+ for (i = 0; i <= CHNL_BW_40; i++)
+ for (j = 0; j < 13; j++)
+ cl_fill_channel_info(cl_hw, i, j, j + 1, BAND_24G_POW_Q2, BAND_24G_POW_Q2);
+}
+
+static void cl_set_default_channel_info(struct cl_hw *cl_hw)
+{
+ struct cl_channel_info *channel_info = &cl_hw->channel_info;
+
+ memset(channel_info->channels, 0, sizeof(channel_info->channels));
+
+ channel_info->standard = CL_STANDARD_FCC;
+
+ if (cl_band_is_6g(cl_hw))
+ cl_set_default_channel_info_6g(cl_hw);
+ else if (cl_band_is_5g(cl_hw))
+ cl_set_default_channel_info_5g(cl_hw);
+ else
+ cl_set_default_channel_info_24g(cl_hw);
+}
+
+static u8 cl_regulatory_domain_max_power(struct cl_hw *cl_hw, int idx)
+{
+ u8 bw = 0;
+ u8 max_power = 0;
+ struct cl_channel_info *chan_info = &cl_hw->channel_info;
+
+ for (bw = CHNL_BW_20; bw < CHNL_BW_MAX; bw++) {
+ u8 power = chan_info->channels[bw][idx].country_max_power_q2;
+
+ if (max_power < power)
+ max_power = power;
+ }
+
+ /* Translate from country_power (.25dBm) to max_power (1dBm) */
+ return (max_power >> 2);
+}
+
+static int cl_regulatory_domain_update_rule(struct cl_hw *cl_hw, int freq, int power)
+{
+ struct ieee80211_regdomain *rd = cl_hw->channel_info.rd;
+ struct ieee80211_reg_rule *reg_rule = &rd->reg_rules[rd->n_reg_rules - 1];
+ struct ieee80211_power_rule *power_rule = &reg_rule->power_rule;
+
+ reg_rule->freq_range.end_freq_khz = MHZ_TO_KHZ(freq + 10);
+ if (power_rule->max_eirp < DBM_TO_MBM(power))
+ power_rule->max_eirp = DBM_TO_MBM(power);
+
+ return (reg_rule->freq_range.end_freq_khz -
+ reg_rule->freq_range.start_freq_khz);
+}
+
+static void cl_regulatory_domain_add_rule(struct cl_hw *cl_hw, int freq, int max_power, u8 bw)
+{
+ struct ieee80211_regdomain *rd = cl_hw->channel_info.rd;
+ struct ieee80211_reg_rule *reg_rule = &rd->reg_rules[rd->n_reg_rules];
+ struct ieee80211_freq_range *freq_range = &reg_rule->freq_range;
+ struct ieee80211_power_rule *power_rule = &reg_rule->power_rule;
+
+ freq_range->start_freq_khz = MHZ_TO_KHZ(freq - 10);
+ freq_range->end_freq_khz = MHZ_TO_KHZ(freq + 10);
+ freq_range->max_bandwidth_khz = BW_TO_KHZ(bw);
+
+ power_rule->max_eirp = DBM_TO_MBM(max_power);
+ power_rule->max_antenna_gain = DBI_TO_MBI(3);
+
+ rd->n_reg_rules++;
+}
+
+static void cl_regulatory_domain_set(struct cl_hw *cl_hw)
+{
+ int j = 0;
+ int diff = 0;
+ int power = 0, prev_power = 0;
+ u8 bw = 0, prev_bw = 0;
+ int freq = 0, prev_freq = 0;
+ u8 chan = 0;
+ struct ieee80211_regdomain *rd = cl_hw->channel_info.rd;
+
+ memcpy(rd->alpha2, cl_hw->chip->conf->ce_country_code, 2);
+
+ if (cl_hw->channel_info.standard == CL_STANDARD_FCC)
+ rd->dfs_region = NL80211_DFS_FCC;
+ else if (cl_hw->channel_info.standard == CL_STANDARD_ETSI)
+ rd->dfs_region = NL80211_DFS_ETSI;
+ else
+ rd->dfs_region = NL80211_DFS_UNSET;
+
+ for (j = 0; j < cl_channel_num(cl_hw); j++) {
+ chan = cl_hw->channel_info.channels[CHNL_BW_20][j].channel;
+ if (!chan)
+ continue;
+ power = cl_regulatory_domain_max_power(cl_hw, j);
+ bw = cl_chan_info_get_max_bw(cl_hw, chan);
+ freq = ieee80211_channel_to_frequency(chan, cl_hw->nl_band);
+ if (freq - prev_freq > 20 ||
+ (prev_power != power && diff >= BW_TO_KHZ(bw)) ||
+ prev_bw != bw) {
+ cl_regulatory_domain_add_rule(cl_hw, freq, power, bw);
+ diff = 0;
+ } else {
+ diff = cl_regulatory_domain_update_rule(cl_hw, freq, power);
+ }
+
+ prev_freq = freq;
+ prev_power = power;
+ prev_bw = bw;
+ }
+}
+
+/*
+ * cl_hardware_power_table_update: Applies individual regulatory table entry
+ * Inputs: cl_hw - pointer to cl_hw
+ * bw_mhz - current bandwidth in MHz
+ * chan_start - match channels greater or equal to chan_start
+ * chan_end - match channels less than chan_end
+ * reg_pwr - ensure channel_info.channels[bw][ch_idx].max_power does not exceed this
+ * Output: updated channel_info.channels[bw][ch_idx].max_power
+ * and channel_info.channels[bw][ch_idx].max_total_power
+ * on all channels that match specified range
+ */
+static void cl_hardware_power_table_update(struct cl_hw *cl_hw, u8 bw_mhz,
+ u8 chan_start, u8 chan_end, u8 pwr_q2)
+{
+ struct cl_chan_info *chan_info = NULL;
+ u8 bw = 0;
+ u8 ch_idx = 0;
+ bool ch_found = false;
+ bool is_24g = cl_band_is_24g(cl_hw);
+
+ if (bw_mhz == 20 || bw_mhz == 40 || (!is_24g && (bw_mhz == 80 || bw_mhz == 160))) {
+ bw = MHZ_TO_BW(bw_mhz);
+ } else {
+ cl_dbg_err(cl_hw, "Invalid bw %u\n", bw_mhz);
+ return;
+ }
+
+ /* Iterate through all cl_channels[bw][ch_idx] - to find all matches */
+ for (ch_idx = 0; ch_idx < cl_channel_num(cl_hw); ch_idx++) {
+ chan_info = &cl_hw->channel_info.channels[bw][ch_idx];
+
+ if (chan_start <= chan_info->channel && chan_info->channel < chan_end) {
+ ch_found = true;
+
+ /*
+ * Max-Power =
+ * minimum between hardware_power_table and country code definition
+ */
+ chan_info->max_power_q2 = min(pwr_q2, chan_info->max_power_q2);
+ chan_info->hardware_max_power_q2 = pwr_q2;
+ }
+ }
+
+ if (!ch_found)
+ cl_dbg_info(cl_hw, "Skipping invalid channel range: %u - %u\n",
+ chan_start, chan_end);
+}
+
+/*
+ * cl_hardware_power_table_parse():
+ * Iterate through hardware power table entries and apply each one.
+ * Expected format:
+ * bw1(chan1=reg_pwr1;chan2=reg_pwr2;...)#bw2(chan3=reg_pwr3;chan4=reg_pwr4;...) ...
+ * Example:
+ * 20(36=22.0;40=22.75;149=21.75)#40(36=22.5;40=23.0;149=21.75)#80(36=21.75;40=21.5;149=22.25)
+ */
+static void cl_hardware_power_table_parse(struct cl_hw *cl_hw)
+{
+ s8 *table_str = NULL;
+ s8 *channel_str = NULL;
+ s8 *bw_set = NULL;
+ s8 *out_tok = NULL;
+ s8 *saveptr1 = NULL;
+ s8 *saveptr2 = NULL;
+ s8 in_reg_pwr[16] = {0};
+ u8 bw_mhz = 0;
+ u8 chan_start = 0;
+ u8 chan_end = 0;
+ u8 curr_pwr_q2 = 0;
+ u8 next_pwr_q2 = 0;
+
+ if (strlen(cl_hw->conf->ce_hardware_power_table) == 0)
+ return; /* Not configured */
+
+ table_str = kzalloc(CL_MAX_STR_BUFFER_SIZE / 2, GFP_KERNEL);
+ if (!table_str)
+ return;
+
+ channel_str = kzalloc(CL_MAX_STR_BUFFER_SIZE / 2, GFP_KERNEL);
+ if (!channel_str) {
+ kfree(table_str);
+ cl_dbg_err(cl_hw, "Failed to allocate channel_str\n");
+ return;
+ }
+
+ strncpy(table_str,
+ cl_hw->conf->ce_hardware_power_table,
+ (CL_MAX_STR_BUFFER_SIZE / 2) - 1);
+
+ /* Iterate through all bandwidth sets included in table_str */
+ bw_set = cl_strtok_r(table_str, "#", &saveptr1);
+ while (bw_set) {
+ if (sscanf(bw_set, "%hhu(%s)", &bw_mhz, channel_str) != 2) {
+ bw_set = cl_strtok_r(NULL, "#", &saveptr1);
+ continue;
+ }
+
+ /* Iterate through each channel in this bandwidth set */
+ chan_start = 0;
+ chan_end = 0;
+ curr_pwr_q2 = 0;
+ next_pwr_q2 = 0;
+ out_tok = cl_strtok_r(channel_str, ";", &saveptr2);
+
+ while (out_tok) {
+ if (sscanf(out_tok, "%hhu=%s", &chan_end, in_reg_pwr) == 2) {
+ next_pwr_q2 = convert_str_int_q2(in_reg_pwr);
+
+ /* Apply regulatory table rule. Skip initial case */
+ if (curr_pwr_q2 != 0 && chan_start != 0)
+ cl_hardware_power_table_update(cl_hw, bw_mhz, chan_start,
+ chan_end, curr_pwr_q2);
+
+ /* Prepare next iteration */
+ chan_start = chan_end;
+ curr_pwr_q2 = next_pwr_q2;
+ }
+ out_tok = cl_strtok_r(NULL, ";", &saveptr2);
+ }
+
+ /* Handle last channel case */
+ if (next_pwr_q2 != 0 && chan_start != 0) {
+ u8 chan_end;
+
+ if (cl_band_is_6g(cl_hw))
+ chan_end = 234;
+ else if (cl_band_is_5g(cl_hw))
+ chan_end = 166;
+ else
+ chan_end = 15;
+
+ cl_hardware_power_table_update(cl_hw, bw_mhz, chan_start,
+ chan_end, curr_pwr_q2);
+ }
+
+ bw_set = cl_strtok_r(NULL, "#", &saveptr1);
+ }
+
+ kfree(table_str);
+ kfree(channel_str);
+}
+
+void cl_chan_info_init(struct cl_hw *cl_hw)
+{
+ struct cl_channel_info *channel_info = &cl_hw->channel_info;
+
+ channel_info->use_channel_info = !cl_hw->chip->conf->ce_production_mode;
+
+ if (channel_info->use_channel_info) {
+ cl_hw->channel_info.rd = kzalloc(sizeof(*cl_hw->channel_info.rd) +
+ NL80211_MAX_SUPP_REG_RULES *
+ sizeof(struct ieee80211_reg_rule),
+ GFP_KERNEL);
+
+ if (!cl_hw->channel_info.rd) {
+ cl_dbg_err(cl_hw, "memory allocation failed!\n");
+ return;
+ }
+
+ if (!cl_parse_channel_info_txt(cl_hw) || !cl_is_parsing_success(cl_hw)) {
+ CL_DBG_WARNING(cl_hw, "Error parsing channel_info.txt. Using default!\n");
+ cl_set_default_channel_info(cl_hw);
+ }
+
+ cl_chan_info_set_max_bw(cl_hw);
+ cl_chan_info_dbg(cl_hw);
+ cl_regulatory_domain_set(cl_hw);
+ } else {
+ cl_set_default_channel_info(cl_hw);
+
+ if (cl_band_is_6g(cl_hw))
+ cl_hw->channel_info.rd = &cl_regdom_6g;
+ else if (cl_band_is_5g(cl_hw))
+ cl_hw->channel_info.rd = &cl_regdom_5g;
+ else
+ cl_hw->channel_info.rd = &cl_regdom_24g;
+ }
+
+ cl_hardware_power_table_parse(cl_hw);
+}
+
+void cl_chan_info_deinit(struct cl_hw *cl_hw)
+{
+ if (cl_hw->channel_info.rd &&
+ cl_hw->channel_info.use_channel_info)
+ kfree(cl_hw->channel_info.rd);
+}
+
+struct cl_chan_info *cl_chan_info_get(struct cl_hw *cl_hw, u8 channel, u8 bw)
+{
+ int i = 0;
+ struct cl_chan_info *chan_info;
+
+ for (i = 0; i < cl_channel_num(cl_hw); i++) {
+ chan_info = &cl_hw->channel_info.channels[bw][i];
+
+ if (chan_info->channel == channel)
+ return chan_info;
+ }
+
+ return NULL;
+}
+
+u8 cl_chan_info_get_max_bw(struct cl_hw *cl_hw, u8 channel)
+{
+ s8 bw = 0;
+
+ for (bw = CHNL_BW_160; bw > CHNL_BW_20; bw--)
+ if (cl_chan_info_get(cl_hw, channel, bw))
+ return (u8)bw;
+
+ return CHNL_BW_20;
+}
+
+s16 cl_chan_info_get_eirp_limit_q8(struct cl_hw *cl_hw, u8 bw)
+{
+ /* Eirp_limit = min(country_limit, hw_limit) */
+ struct cl_chan_info *chan_info = cl_chan_info_get(cl_hw, cl_hw->channel, bw);
+
+ return chan_info ? (chan_info->max_power_q2 << 6) : CL_DEFAULT_CHANNEL_POWER_Q8;
+}
+
+s16 cl_chan_info_get_country_limit_q8(struct cl_hw *cl_hw, u8 channel, u8 bw)
+{
+ struct cl_chan_info *chan_info = cl_chan_info_get(cl_hw, channel, bw);
+
+ return chan_info ? (chan_info->country_max_power_q2 << 6) : CL_DEFAULT_CHANNEL_POWER_Q8;
+}
+
+s16 cl_chan_info_get_hardware_limit_q8(struct cl_hw *cl_hw, u8 channel, u8 bw)
+{
+ struct cl_chan_info *chan_info = cl_chan_info_get(cl_hw, channel, bw);
+
+ return chan_info ? (chan_info->hardware_max_power_q2 << 6) : CL_DEFAULT_CHANNEL_POWER_Q8;
+}
+
+u8 cl_chan_info_get_max_power(struct cl_hw *cl_hw, u8 channel)
+{
+ struct cl_chan_info *chan_info;
+ u8 bw = 0;
+ u8 max_power_q2 = 0;
+
+ for (bw = 0; bw < ARRAY_SIZE(cl_hw->channel_info.channels); bw++) {
+ chan_info = cl_chan_info_get(cl_hw, channel, bw);
+
+ if (!chan_info)
+ continue;
+
+ if (chan_info->max_power_q2 > max_power_q2)
+ max_power_q2 = chan_info->max_power_q2;
+ }
+
+ return max_power_q2 >> 2;
+}
--
2.30.0

________________________________
The information transmitted is intended only for the person or entity to which it is addressed and may contain confidential and/or privileged material. Any retransmission, dissemination, copying or other use of, or taking of any action in reliance upon this information is prohibited. If you received this in error, please contact the sender and delete the material from any computer. Nothing contained herein shall be deemed as a representation, warranty or a commitment by Celeno. No warranties are expressed or implied, including, but not limited to, any implied warranties of non-infringement, merchantability and fitness for a particular purpose.
________________________________

2021-06-17 16:24:32

by viktor.barna

[permalink] [raw]
Subject: [RFC v1 041/256] cl8k: add chan_info.h

From: Viktor Barna <[email protected]>

(Part of the split. Please, take a look at the cover letter for more
details).

Signed-off-by: Viktor Barna <[email protected]>
---
drivers/net/wireless/celeno/cl8k/chan_info.h | 32 ++++++++++++++++++++
1 file changed, 32 insertions(+)
create mode 100644 drivers/net/wireless/celeno/cl8k/chan_info.h

diff --git a/drivers/net/wireless/celeno/cl8k/chan_info.h b/drivers/net/wireless/celeno/cl8k/chan_info.h
new file mode 100644
index 000000000000..d2eb1c3828c8
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/chan_info.h
@@ -0,0 +1,32 @@
+/* SPDX-License-Identifier: MIT */
+/* Copyright(c) 2019-2021, Celeno Communications Ltd. */
+
+#ifndef CL_CHAN_INFO_H
+#define CL_CHAN_INFO_H
+
+#include "fw/fw_msg.h"
+#include <linux/rtnetlink.h>
+#include <net/cfg80211.h>
+
+#define CL_MAX_STR_BUFFER_SIZE 1024
+
+#define CL_DEFAULT_CHANNEL_POWER_Q8 (30 << 8)
+
+#define CL_20MHZ_CH_GAP 4
+#define CL_40MHZ_CH_GAP 8
+#define CL_80MHZ_CH_GAP 16
+#define CL_160MHZ_CH_GAP 32
+#define CL_40MHZ_HOP 2
+#define CL_80MHZ_HOP 4
+#define CL_160MHZ_HOP 8
+
+void cl_chan_info_init(struct cl_hw *cl_hw);
+void cl_chan_info_deinit(struct cl_hw *cl_hw);
+struct cl_chan_info *cl_chan_info_get(struct cl_hw *cl_hw, u8 channel, u8 bw);
+u8 cl_chan_info_get_max_bw(struct cl_hw *cl_hw, u8 channel);
+s16 cl_chan_info_get_eirp_limit_q8(struct cl_hw *cl_hw, u8 bw);
+s16 cl_chan_info_get_country_limit_q8(struct cl_hw *cl_hw, u8 channel, u8 bw);
+s16 cl_chan_info_get_hardware_limit_q8(struct cl_hw *cl_hw, u8 channel, u8 bw);
+u8 cl_chan_info_get_max_power(struct cl_hw *cl_hw, u8 channel);
+
+#endif /* CL_CHAN_INFO_H */
--
2.30.0

________________________________
The information transmitted is intended only for the person or entity to which it is addressed and may contain confidential and/or privileged material. Any retransmission, dissemination, copying or other use of, or taking of any action in reliance upon this information is prohibited. If you received this in error, please contact the sender and delete the material from any computer. Nothing contained herein shall be deemed as a representation, warranty or a commitment by Celeno. No warranties are expressed or implied, including, but not limited to, any implied warranties of non-infringement, merchantability and fitness for a particular purpose.
________________________________

2021-06-17 16:24:39

by viktor.barna

[permalink] [raw]
Subject: [RFC v1 021/256] cl8k: add bus/pci/msg_pci.c

From: Viktor Barna <[email protected]>

(Part of the split. Please, take a look at the cover letter for more
details).

Signed-off-by: Viktor Barna <[email protected]>
---
.../wireless/celeno/cl8k/bus/pci/msg_pci.c | 101 ++++++++++++++++++
1 file changed, 101 insertions(+)
create mode 100644 drivers/net/wireless/celeno/cl8k/bus/pci/msg_pci.c

diff --git a/drivers/net/wireless/celeno/cl8k/bus/pci/msg_pci.c b/drivers/net/wireless/celeno/cl8k/bus/pci/msg_pci.c
new file mode 100644
index 000000000000..4ddc060940c1
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/bus/pci/msg_pci.c
@@ -0,0 +1,101 @@
+// SPDX-License-Identifier: MIT
+/* Copyright(c) 2019-2021, Celeno Communications Ltd. */
+
+#include "chip.h"
+#include "hw.h"
+#include "bus/pci/ipc.h"
+#include "fw/fw_msg.h"
+#include "fw/msg_cfm.h"
+#ifdef TRACE_SUPPORT
+#include "trace.h"
+#endif
+
+static void cl_msg_pci_fw_push(struct cl_hw *cl_hw, void *msg_buf, u16 len)
+{
+ /* Send a message to the embedded side */
+ int i;
+ u32 *src;
+ u32 *dst;
+ struct cl_ipc_host_env *ipc_env = cl_hw->ipc_env;
+
+ /* Copy the message into the IPC MSG buffer */
+ src = (u32 *)msg_buf;
+ dst = (u32 *)&ipc_env->shared->a2e_msg_buf;
+
+ /*
+ * Move the destination pointer forward by one word
+ * (due to the format of the firmware kernel messages)
+ */
+ dst++;
+
+ /* Align length of message to 4 */
+ len = ALIGN(len, sizeof(u32));
+
+ /* Copy the message in the IPC queue */
+ for (i = 0; i < len; i += sizeof(u32))
+ *dst++ = cpu_to_le32(*src++);
+
+ /* Trigger the irq to send the message to EMB */
+ cl_hw->ipc_host2xmac_trigger_set(cl_hw->chip, IPC_IRQ_A2E_MSG);
+}
+
+int cl_msg_pci_msg_fw_send(struct cl_hw *cl_hw, const void *msg_params,
+ bool background)
+{
+ struct fw_msg *msg = container_of((void *)msg_params, struct fw_msg, param);
+ u16 req_id = msg->msg_id;
+ u16 cfm_bit = cl_msg_cfm_set_bit(req_id);
+ int length = sizeof(struct fw_msg) + msg->param_len;
+ int error = 0;
+
+ if (!cl_hw->fw_active) {
+ cl_dbg_verbose(cl_hw, "Bypass %s (firmware not loaded)\n", MSG_ID_STR(req_id));
+ /* Free the message */
+ kfree(msg);
+ return -EBUSY;
+ }
+
+ if (test_bit(CL_DEV_FW_ERROR, &cl_hw->drv_flags)) {
+ cl_dbg_verbose(cl_hw, "Bypass %s (CL_DEV_FW_ERROR is set)\n", MSG_ID_STR(req_id));
+ /* Free the message */
+ kfree(msg);
+ return -EBUSY;
+ }
+
+ if (!test_bit(CL_DEV_STARTED, &cl_hw->drv_flags) &&
+ msg->msg_id != MM_RESET_REQ &&
+ msg->msg_id != MM_START_REQ) {
+ cl_dbg_verbose(cl_hw, "Bypass %s (CL_DEV_STARTED not set)\n", MSG_ID_STR(req_id));
+ /* Free the message */
+ kfree(msg);
+ return -EBUSY;
+ }
+
+ /* Lock msg tx of the correct msg buffer. */
+ error = mutex_lock_interruptible(&cl_hw->msg_tx_mutex);
+ if (error != 0) {
+ cl_dbg_verbose(cl_hw, "Bypass %s (mutex error %d)\n", MSG_ID_STR(req_id), error);
+ /* Free the message */
+ kfree(msg);
+ return error;
+ }
+
+ cl_hw->msg_background = background;
+
+ CFM_SET_BIT(cfm_bit, &cl_hw->cfm_flags);
+
+ cl_dbg_trace(cl_hw, "%s\n", MSG_ID_STR(req_id));
+
+ /* Push the message in the IPC */
+ cl_msg_pci_fw_push(cl_hw, msg, length);
+
+ /* Free the message */
+ kfree(msg);
+
+#ifdef TRACE_SUPPORT
+ trace_cl_trace_cl_msg_fw_send(cl_hw->idx, (int)req_id);
+#endif
+
+ return cl_msg_cfm_wait(cl_hw, cfm_bit, req_id);
+}
+
--
2.30.0

________________________________
The information transmitted is intended only for the person or entity to which it is addressed and may contain confidential and/or privileged material. Any retransmission, dissemination, copying or other use of, or taking of any action in reliance upon this information is prohibited. If you received this in error, please contact the sender and delete the material from any computer. Nothing contained herein shall be deemed as a representation, warranty or a commitment by Celeno. No warranties are expressed or implied, including, but not limited to, any implied warranties of non-infringement, merchantability and fitness for a particular purpose.
________________________________

2021-06-17 16:24:41

by viktor.barna

[permalink] [raw]
Subject: [RFC v1 022/256] cl8k: add bus/pci/msg_pci.h

From: Viktor Barna <[email protected]>

(Part of the split. Please, take a look at the cover letter for more
details).

Signed-off-by: Viktor Barna <[email protected]>
---
drivers/net/wireless/celeno/cl8k/bus/pci/msg_pci.h | 12 ++++++++++++
1 file changed, 12 insertions(+)
create mode 100644 drivers/net/wireless/celeno/cl8k/bus/pci/msg_pci.h

diff --git a/drivers/net/wireless/celeno/cl8k/bus/pci/msg_pci.h b/drivers/net/wireless/celeno/cl8k/bus/pci/msg_pci.h
new file mode 100644
index 000000000000..6ad2050dc57c
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/bus/pci/msg_pci.h
@@ -0,0 +1,12 @@
+/* SPDX-License-Identifier: MIT */
+/* Copyright(c) 2019-2021, Celeno Communications Ltd. */
+
+#ifndef CL_MSG_PCI_H
+#define CL_MSG_PCI_H
+
+#include "hw.h"
+
+int cl_msg_pci_msg_fw_send(struct cl_hw *cl_hw, const void *msg_params,
+ bool background);
+
+#endif /* CL_MSG_PCI_H */
--
2.30.0

________________________________
The information transmitted is intended only for the person or entity to which it is addressed and may contain confidential and/or privileged material. Any retransmission, dissemination, copying or other use of, or taking of any action in reliance upon this information is prohibited. If you received this in error, please contact the sender and delete the material from any computer. Nothing contained herein shall be deemed as a representation, warranty or a commitment by Celeno. No warranties are expressed or implied, including, but not limited to, any implied warranties of non-infringement, merchantability and fitness for a particular purpose.
________________________________

2021-06-17 16:24:46

by viktor.barna

[permalink] [raw]
Subject: [RFC v1 023/256] cl8k: add bus/pci/pci.c

From: Viktor Barna <[email protected]>

(Part of the split. Please, take a look at the cover letter for more
details).

Signed-off-by: Viktor Barna <[email protected]>
---
.../net/wireless/celeno/cl8k/bus/pci/pci.c | 210 ++++++++++++++++++
1 file changed, 210 insertions(+)
create mode 100644 drivers/net/wireless/celeno/cl8k/bus/pci/pci.c

diff --git a/drivers/net/wireless/celeno/cl8k/bus/pci/pci.c b/drivers/net/wireless/celeno/cl8k/bus/pci/pci.c
new file mode 100644
index 000000000000..a9c2eebaeb1f
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/bus/pci/pci.c
@@ -0,0 +1,210 @@
+// SPDX-License-Identifier: MIT
+/* Copyright(c) 2019-2021, Celeno Communications Ltd. */
+
+#include "chip.h"
+#include "hw.h"
+#include "bus/pci/msg_pci.h"
+#include "bus/pci/tx_pci.h"
+#include "bus/pci/rx_pci.h"
+#include "reg/reg_macsys_gcu.h"
+#include "main.h"
+#include "ela.h"
+#include "debug.h"
+
+struct cl_pci_db {
+ u8 device_cntr;
+ struct pci_dev *dev[CHIP_MAX];
+};
+
+static struct cl_pci_db pci_db;
+
+void cl_pci_get_celeno_device(void)
+{
+ /*
+ * Search the PCI for all Celeno devices.
+ * If there are two devices sort them in ascending order.
+ */
+ struct pci_dev *dev = NULL;
+
+ while ((dev = pci_get_device(CL_VENDOR_ID, PCI_ANY_ID, dev))) {
+ pci_db.dev[pci_db.device_cntr] = dev;
+ pci_db.device_cntr++;
+
+ if (pci_db.device_cntr == CHIP_MAX) {
+ if (pci_db.dev[CHIP0]->device > pci_db.dev[CHIP1]->device)
+ swap(pci_db.dev[CHIP0], pci_db.dev[CHIP1]);
+
+ break;
+ }
+ }
+}
+
+static u8 cl_pci_chip_idx(struct pci_dev *pci_dev)
+{
+ if (pci_db.device_cntr == 0)
+ cl_pci_get_celeno_device();
+
+ if (pci_db.device_cntr == 1)
+ return CHIP0;
+
+ return (pci_db.dev[CHIP0] == pci_dev) ? CHIP0 : CHIP1;
+}
+
+static const struct cl_driver_ops drv_ops = {
+ .msg_fw_send = cl_msg_pci_msg_fw_send,
+ .pkt_fw_send = cl_tx_pci_pkt_fw_send,
+};
+
+static int cl_pci_probe(struct pci_dev *pci_dev,
+ const struct pci_device_id *pci_id)
+{
+ u16 pci_cmd;
+ int ret;
+ u8 chip_idx = cl_pci_chip_idx(pci_dev);
+ u8 step_id;
+ struct cl_chip *chip = cl_chip_alloc(chip_idx);
+
+ if (!chip) {
+ pr_err("Chip [%u] alloc failed\n", chip_idx);
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ ret = cl_chip_config_read(chip);
+ if (ret) {
+ cl_chip_dealloc(chip);
+ return 0;
+ }
+
+ chip->pci_dev = pci_dev;
+ chip->dev = &pci_dev->dev;
+ chip->bus_type = CL_BUS_TYPE_PCI;
+
+ pci_set_drvdata(pci_dev, chip);
+
+ /* Hotplug fixups */
+ pci_read_config_word(pci_dev, PCI_COMMAND, &pci_cmd);
+ pci_cmd |= PCI_COMMAND_PARITY | PCI_COMMAND_SERR;
+ pci_write_config_word(pci_dev, PCI_COMMAND, pci_cmd);
+ pci_write_config_byte(pci_dev, PCI_CACHE_LINE_SIZE, L1_CACHE_BYTES >> 2);
+
+ ret = pci_enable_device(pci_dev);
+ if (ret) {
+ cl_dbg_chip_err(chip, "pci_enable_device failed\n");
+ goto out;
+ }
+
+ if (!dma_set_mask_and_coherent(&pci_dev->dev, DMA_BIT_MASK(32))) {
+ cl_dbg_chip_verbose(chip, "Using 32bit DMA\n");
+ } else {
+ cl_dbg_chip_verbose(chip, "No suitable DMA available\n");
+ goto out_disable_device;
+ }
+
+ pci_set_master(pci_dev);
+
+ ret = pci_request_regions(pci_dev, chip->pci_drv.name);
+ if (ret) {
+ cl_dbg_chip_verbose(chip, "pci_request_regions failed\n");
+ goto out_disable_device;
+ }
+
+ chip->pci_bar0_virt_addr = pci_ioremap_bar(pci_dev, 0);
+ if (!chip->pci_bar0_virt_addr) {
+ cl_dbg_chip_verbose(chip, "pci_ioremap_bar 0 failed\n");
+ ret = -ENOMEM;
+ goto out_release_regions;
+ }
+
+#ifdef CONFIG_PCI_MSI
+ if (chip->conf->ci_pci_msi_enable) {
+ ret = pci_enable_msi(pci_dev);
+ if (ret)
+ cl_dbg_chip_err(chip, "pci_enable_msi failed (%d)\n", ret);
+ }
+#endif
+
+ step_id = macsys_gcu_chip_version_step_id_getf(chip);
+ if (step_id != 0xB) {
+ cl_dbg_chip_err(chip, "Invalid Step ID: 0x%X\n", step_id);
+ ret = -EOPNOTSUPP;
+ goto out_release_regions;
+ }
+
+ ret = cl_chip_init(chip);
+ if (ret)
+ goto out_chip_deinit;
+
+ ret = cl_main_init(chip, &drv_ops);
+ if (ret)
+ goto out_chip_deinit;
+
+ if (cl_ela_init(chip))
+ cl_dbg_chip_err(chip, "Non-critical: cl_ela_init failed\n");
+
+ return 0;
+
+out_chip_deinit:
+ cl_chip_deinit(chip);
+#ifdef CONFIG_PCI_MSI
+ if (chip->conf->ci_pci_msi_enable)
+ pci_disable_msi(pci_dev);
+#endif
+ iounmap(chip->pci_bar0_virt_addr);
+out_release_regions:
+ pci_release_regions(pci_dev);
+out_disable_device:
+ pci_disable_device(pci_dev);
+out:
+
+ return ret;
+}
+
+static void cl_pci_remove(struct pci_dev *pci_dev)
+{
+ struct cl_chip *chip = pci_get_drvdata(pci_dev);
+
+ if (!chip) {
+ pr_err("%s: failed to find chip\n", __func__);
+ return;
+ }
+
+ cl_ela_deinit(chip);
+
+ cl_main_deinit(chip);
+
+ cl_chip_deinit(chip);
+
+#ifdef CONFIG_PCI_MSI
+ if (chip->conf->ci_pci_msi_enable) {
+ pci_disable_msi(pci_dev);
+ pr_debug("pci_disable_msi\n");
+ }
+#endif
+
+ iounmap(chip->pci_bar0_virt_addr);
+ cl_chip_dealloc(chip);
+ pci_release_regions(pci_dev);
+ pci_disable_device(pci_dev);
+}
+
+static const struct pci_device_id cl_pci_id_table[] = {
+ { PCI_DEVICE(CL_VENDOR_ID, 0x8000) },
+ { PCI_DEVICE(CL_VENDOR_ID, 0x8001) },
+ { PCI_DEVICE(CL_VENDOR_ID, 0x8040) },
+ { PCI_DEVICE(CL_VENDOR_ID, 0x8060) },
+ { PCI_DEVICE(CL_VENDOR_ID, 0x8080) },
+ { PCI_DEVICE(CL_VENDOR_ID, 0x8046) },
+ { PCI_DEVICE(CL_VENDOR_ID, 0x8066) },
+ { PCI_DEVICE(CL_VENDOR_ID, 0x8086) },
+ { },
+};
+
+static struct pci_driver cl_pci_driver = {
+ .name = "cl_pci",
+ .id_table = cl_pci_id_table,
+ .probe = cl_pci_probe,
+ .remove = cl_pci_remove,
+};
+
+module_pci_driver(cl_pci_driver);
--
2.30.0

________________________________
The information transmitted is intended only for the person or entity to which it is addressed and may contain confidential and/or privileged material. Any retransmission, dissemination, copying or other use of, or taking of any action in reliance upon this information is prohibited. If you received this in error, please contact the sender and delete the material from any computer. Nothing contained herein shall be deemed as a representation, warranty or a commitment by Celeno. No warranties are expressed or implied, including, but not limited to, any implied warranties of non-infringement, merchantability and fitness for a particular purpose.
________________________________

2021-06-17 16:24:51

by viktor.barna

[permalink] [raw]
Subject: [RFC v1 048/256] cl8k: add coredump.c

From: Viktor Barna <[email protected]>

(Part of the split. Please, take a look at the cover letter for more
details).

Signed-off-by: Viktor Barna <[email protected]>
---
drivers/net/wireless/celeno/cl8k/coredump.c | 190 ++++++++++++++++++++
1 file changed, 190 insertions(+)
create mode 100644 drivers/net/wireless/celeno/cl8k/coredump.c

diff --git a/drivers/net/wireless/celeno/cl8k/coredump.c b/drivers/net/wireless/celeno/cl8k/coredump.c
new file mode 100644
index 000000000000..bf0313715f6f
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/coredump.c
@@ -0,0 +1,190 @@
+// SPDX-License-Identifier: MIT
+/* Copyright(c) 2019-2021, Celeno Communications Ltd. */
+
+#include "coredump.h"
+#include "recovery.h"
+#include "mib.h"
+#include "ela.h"
+#ifdef CONFIG_CL_PCIE
+#include "bus/pci/ipc.h"
+#endif
+#include "chip.h"
+#include "config.h"
+
+#include "fw/fw_dbg.h"
+
+#include <linux/devcoredump.h>
+
+static int cl_coredump_generate(struct cl_hw *cl_hw)
+{
+ struct cl_coredump *dump;
+
+ dump = cl_fw_dbg_prepare_coredump(cl_hw);
+ if (!dump)
+ return -ENODATA;
+
+ dev_coredumpv(cl_hw->chip->dev, dump, le32_to_cpu(dump->len),
+ GFP_KERNEL);
+
+ return 0;
+}
+
+static void cl_coredump_done(struct cl_hw *cl_hw)
+{
+ /*
+ * Print MIB counters only if watchdog is disabled,
+ * otherwise the dump of prints effects the recovery
+ */
+ if (cl_hw->conf->ce_fw_watchdog_mode == FW_WD_DISABLE)
+ cl_mib_cntrs_dump(cl_hw);
+
+ if (!test_bit(CL_DEV_STARTED, &cl_hw->drv_flags))
+ return;
+
+ /*
+ * Assuming firmware cannot request next dump before we release the host buffer
+ * so no need to sync the following against error_ind()
+ */
+ cl_hw->debugfs.trace_prst = false;
+#ifdef CONFIG_CL_PCIE
+ cl_ipc_dbginfobuf_push(cl_hw->ipc_env, cl_hw->dbginfo.dma_addr);
+#endif
+ if (cl_hw->dbginfo.buf->u.dump.general_data.error_type == DBG_ERROR_FATAL ||
+ cl_hw->assert_info.restart_needed) {
+ cl_dbg_err(cl_hw, "Starting recovery due to unrecoverable assert\n");
+ cl_recovery_start(cl_hw, RECOVERY_UNRECOVERABLE_ASSERT);
+ }
+}
+
+static void cl_coredump_work(struct work_struct *ws)
+{
+ struct cl_debugfs *debugfs = container_of(ws, struct cl_debugfs, coredump_work);
+ struct cl_hw *cl_hw = container_of(debugfs, struct cl_hw, debugfs);
+ unsigned long flags;
+
+ debugfs->coredump_call_tstamp = jiffies;
+
+ cl_coredump_generate(cl_hw);
+ if (cl_ela_is_on(cl_hw->chip)) {
+ cl_ela_lcu_reset(cl_hw->chip);
+ cl_ela_lcu_apply_config(cl_hw->chip);
+ }
+
+ spin_lock_irqsave(&debugfs->coredump_lock, flags);
+ if (!debugfs->unregistering)
+ cl_coredump_done(cl_hw);
+ debugfs->coredump_scheduled = false;
+ spin_unlock_irqrestore(&debugfs->coredump_lock, flags);
+}
+
+int cl_coredump_trigger(struct cl_hw *cl_hw)
+{
+ struct cl_debugfs *debugfs = &cl_hw->debugfs;
+ unsigned long flags;
+ unsigned long curr_time = jiffies;
+ unsigned int diff_time = jiffies_to_msecs(curr_time - debugfs->coredump_call_tstamp);
+
+ if (diff_time < cl_hw->conf->ci_coredump_diff_time_ms) {
+#ifdef CONFIG_CL_PCIE
+ cl_ipc_dbginfobuf_push(cl_hw->ipc_env, cl_hw->dbginfo.dma_addr);
+#endif
+ cl_dbg_verbose(cl_hw,
+ "Skip coredump - time from previous call=%u m-sec\n",
+ diff_time);
+ return -1;
+ }
+
+ spin_lock_irqsave(&debugfs->coredump_lock, flags);
+ if (debugfs->coredump_scheduled) {
+ spin_unlock_irqrestore(&debugfs->coredump_lock, flags);
+ cl_dbg_verbose(cl_hw, ": Already scheduled\n");
+ return -EBUSY;
+ }
+
+ if (debugfs->unregistering) {
+ spin_unlock_irqrestore(&debugfs->coredump_lock, flags);
+ cl_dbg_verbose(cl_hw, ": unregistering\n");
+ return -ENOENT;
+ }
+
+ debugfs->coredump_scheduled = true;
+ debugfs->trace_prst = true;
+ ktime_get_real_ts64(&cl_hw->dbginfo.trigger_tstamp);
+
+ schedule_work(&debugfs->coredump_work);
+ spin_unlock_irqrestore(&debugfs->coredump_lock, flags);
+
+ return 0;
+}
+
+bool cl_coredump_recovery(struct cl_hw *cl_hw, int reason)
+{
+ struct cl_debugfs *debugfs = &cl_hw->debugfs;
+ unsigned long flags;
+ bool need_restart = false;
+
+ spin_lock_irqsave(&debugfs->coredump_lock, flags);
+
+ if (!debugfs->coredump_scheduled) {
+ cl_dbg_trace(cl_hw,
+ "Starting recovery due to reason:%d\n",
+ reason);
+ cl_recovery_start(cl_hw, reason);
+ } else {
+ need_restart = true;
+ }
+
+ spin_unlock_irqrestore(&debugfs->coredump_lock, flags);
+
+ return need_restart;
+}
+
+bool cl_coredump_is_scheduled(struct cl_hw *cl_hw)
+{
+ struct cl_debugfs *debugfs = &cl_hw->debugfs;
+
+ return debugfs->coredump_scheduled;
+}
+
+void cl_coredump_reset_trace(struct cl_hw *cl_hw)
+{
+ struct cl_debugfs *debugfs = &cl_hw->debugfs;
+
+ debugfs->trace_prst = false;
+}
+
+void cl_coredump_init(struct cl_hw *cl_hw, struct dentry *dir_drv)
+{
+ struct cl_debugfs *debugfs = &cl_hw->debugfs;
+
+ debugfs->dir = dir_drv;
+ debugfs->unregistering = false;
+ debugfs->trace_prst = false;
+ debugfs->coredump_scheduled = false;
+
+ INIT_WORK(&debugfs->coredump_work, cl_coredump_work);
+
+ spin_lock_init(&debugfs->coredump_lock);
+
+ /*
+ * Initialize coredump_call_tstamp to current time minus
+ * (ci_coredump_diff_time_ms + 1), so that if assert happens immediately
+ * coredump will be called.
+ */
+ debugfs->coredump_call_tstamp = jiffies -
+ msecs_to_jiffies(cl_hw->conf->ci_coredump_diff_time_ms + 1);
+}
+
+void cl_coredump_close(struct cl_hw *cl_hw)
+{
+ struct cl_debugfs *debugfs = &cl_hw->debugfs;
+
+ flush_work(&debugfs->coredump_work);
+
+ if (!debugfs->dir)
+ return;
+
+ debugfs->unregistering = true;
+ debugfs_remove_recursive(debugfs->dir);
+ debugfs->dir = NULL;
+}
--
2.30.0

________________________________
The information transmitted is intended only for the person or entity to which it is addressed and may contain confidential and/or privileged material. Any retransmission, dissemination, copying or other use of, or taking of any action in reliance upon this information is prohibited. If you received this in error, please contact the sender and delete the material from any computer. Nothing contained herein shall be deemed as a representation, warranty or a commitment by Celeno. No warranties are expressed or implied, including, but not limited to, any implied warranties of non-infringement, merchantability and fitness for a particular purpose.
________________________________

2021-06-17 16:24:51

by viktor.barna

[permalink] [raw]
Subject: [RFC v1 043/256] cl8k: add chip.h

From: Viktor Barna <[email protected]>

(Part of the split. Please, take a look at the cover letter for more
details).

Signed-off-by: Viktor Barna <[email protected]>
---
drivers/net/wireless/celeno/cl8k/chip.h | 143 ++++++++++++++++++++++++
1 file changed, 143 insertions(+)
create mode 100644 drivers/net/wireless/celeno/cl8k/chip.h

diff --git a/drivers/net/wireless/celeno/cl8k/chip.h b/drivers/net/wireless/celeno/cl8k/chip.h
new file mode 100644
index 000000000000..c7548ca92e59
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/chip.h
@@ -0,0 +1,143 @@
+/* SPDX-License-Identifier: MIT */
+/* Copyright(c) 2019-2021, Celeno Communications Ltd. */
+
+#ifndef CL_CHIP_H
+#define CL_CHIP_H
+
+#include <linux/types.h>
+#include <linux/spinlock.h>
+#ifdef CONFIG_CL_PCIE
+#include <linux/pci.h>
+#endif
+#include "calib.h"
+#include "temperature.h"
+#include "bus/pci/ipc.h"
+#include "chip_config.h"
+
+/**
+ * DOC: Chip basics
+ *
+ * Each physical device of ours is a separate chip, that is being described by
+ * %cl_chip structure. Each chip may be several (%TCV_MAX) transceivers (bands),
+ * which are operating simultaneously and are described via own %ieee80211_hw
+ * unit (it refers to the private driver via specific pointer, described by
+ * %cl_hw). Totally, 3 types of bands are supported - 2.4G/5.2G/6G. Driver
+ * supports multiple chips (up to %CHIP_MAX). Since the driver can control up
+ * to %TCV_TOTAL entities, it is important to pass it's pointer to each
+ * function, that operates somehow with specific band/transceiver.
+ *
+ * Chip instance is being created during bus probing procedure and is being
+ * destroyed during bus removal procedure.
+ *
+ * Physically, 80xx chips family may have different amount of antennas (4/6/8),
+ * each of which may not be hardly bounded to the specific band (both bands are
+ * sharing them and may change antenna combinations in specific circumstances).
+ *
+ * Each band (transceiver) has own FW, that is being loaded by
+ * request_firmware() call during chip structure initialization procedure. At
+ * lower layer each band is associated with own HW die by LMAC and SMAC names
+ * (e.g: 5.2G and 2.4G). Celeno is using XMAC naming when we are referring to any
+ * of LMAC/SMAC components.
+ */
+
+enum cl_bus_type {
+ CL_BUS_TYPE_PCI,
+};
+
+struct cl_irq_stats {
+ unsigned long last_rx;
+ unsigned long last_tx;
+ unsigned long last_isr;
+ u32 last_isr_statuses;
+ u32 count_irq;
+ u32 ipc_success;
+};
+
+struct cl_fem_params {
+ u8 wiring_id;
+ u16 lut[FEM_TYPE_MAX];
+ u16 lut_registers[TCV_MAX][FEM_LUT_AMOUNT_PER_MAC];
+ u16 lut_off_register[TCV_MAX];
+ u16 lut_off_register_list[FEM_TYPE_MAX];
+};
+
+struct cl_afe_reg {
+ u32 ctrl36_phy0;
+ u32 ctrl36_phy1;
+ u32 ctrl37_phy0;
+ u32 ctrl37_phy1;
+};
+
+struct cl_ring_indices {
+ struct cl_ipc_ring_indices *params;
+ dma_addr_t dma_addr;
+ struct dma_pool *pool;
+};
+
+struct cl_xmem {
+ u32 total_used;
+ u32 size;
+};
+
+struct cl_ela_db {
+ char *raw_lcu_config;
+ struct list_head cmd_head;
+ struct {
+ u32 adaptations_cnt;
+ u32 applications_cnt;
+ } stats;
+ int error_state;
+};
+
+struct cl_chip {
+ u8 idx;
+ enum cl_bus_type bus_type;
+ bool temperature_configured;
+ u8 max_antennas;
+#ifdef CONFIG_CL_PCIE
+ struct pci_driver pci_drv;
+ struct pci_dev *pci_dev;
+#endif
+ void __iomem *pci_bar0_virt_addr;
+ struct cl_irq_stats irq_stats;
+ struct cl_temperature temperature;
+ struct cl_chip_conf *conf;
+ struct device *dev;
+ struct cl_hw *cl_hw_lut[TCV_MAX];
+ struct cl_hw *cl_hw_tcv0;
+ struct cl_hw *cl_hw_tcv1;
+ spinlock_t isr_lock;
+ spinlock_t spi_lock;
+ rwlock_t cl_hw_lock;
+ bool fw_first_tcv;
+ struct cl_fem_params fem;
+ struct eeprom *eeprom_cache;
+ int (*eeprom_read_block)(struct cl_chip *chip, u16 addr, u16 num_of_byte, u8 *data);
+ int (*eeprom_write_block)(struct cl_chip *chip, u16 addr, u16 num_of_byte, u8 *data);
+ struct cl_afe_reg orig_afe_reg;
+ u8 agc_table_entry;
+ u8 lna_bypass_mode_set;
+ struct cl_calib_db calib_db;
+ struct cl_ela_db ela_db;
+ struct cl_ring_indices ring_indices;
+ u8 reg_dbg;
+ struct cl_xmem xmem_db;
+};
+
+struct cl_chip *cl_chip_alloc(u8 idx);
+void cl_chip_dealloc(struct cl_chip *chip);
+int cl_chip_init(struct cl_chip *chip);
+void cl_chip_deinit(struct cl_chip *chip);
+bool cl_chip_is_enabled(struct cl_chip *chip);
+bool cl_chip_is_both_enabled(struct cl_chip *chip);
+bool cl_chip_is_tcv_enabled(struct cl_chip *chip, u8 tcv_idx);
+bool cl_chip_is_tcv0_enabled(struct cl_chip *chip);
+bool cl_chip_is_tcv1_enabled(struct cl_chip *chip);
+void cl_chip_set_hw(struct cl_chip *chip, struct cl_hw *cl_hw);
+void cl_chip_unset_hw(struct cl_chip *chip, struct cl_hw *cl_hw);
+bool cl_chip_is_8ant(struct cl_chip *chip);
+bool cl_chip_is_6ant(struct cl_chip *chip);
+bool cl_chip_is_4ant(struct cl_chip *chip);
+bool cl_chip_is_6g(struct cl_chip *chip);
+
+#endif /* CL_CHIP_H */
--
2.30.0

________________________________
The information transmitted is intended only for the person or entity to which it is addressed and may contain confidential and/or privileged material. Any retransmission, dissemination, copying or other use of, or taking of any action in reliance upon this information is prohibited. If you received this in error, please contact the sender and delete the material from any computer. Nothing contained herein shall be deemed as a representation, warranty or a commitment by Celeno. No warranties are expressed or implied, including, but not limited to, any implied warranties of non-infringement, merchantability and fitness for a particular purpose.
________________________________

2021-06-17 16:24:55

by viktor.barna

[permalink] [raw]
Subject: [RFC v1 047/256] cl8k: add config.h

From: Viktor Barna <[email protected]>

(Part of the split. Please, take a look at the cover letter for more
details).

Signed-off-by: Viktor Barna <[email protected]>
---
drivers/net/wireless/celeno/cl8k/config.h | 392 ++++++++++++++++++++++
1 file changed, 392 insertions(+)
create mode 100644 drivers/net/wireless/celeno/cl8k/config.h

diff --git a/drivers/net/wireless/celeno/cl8k/config.h b/drivers/net/wireless/celeno/cl8k/config.h
new file mode 100644
index 000000000000..7809b72b0f86
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/config.h
@@ -0,0 +1,392 @@
+/* SPDX-License-Identifier: MIT */
+/* Copyright(c) 2019-2021, Celeno Communications Ltd. */
+
+#ifndef CL_CONFIG_H
+#define CL_CONFIG_H
+
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include "vendor_cmd.h"
+
+#define MAX_PARAM_NAME_LENGTH 64
+
+#define PRINT_UNSIGNED_ARR(param, old_val, size, new_val) \
+do { \
+ u8 i; \
+ char buf[STR_LEN_256B]; \
+ int len = 0; \
+ len += snprintf(buf, sizeof(buf), "%s: old value ", #param); \
+ for (i = 0; i < (size) - 1; i++) \
+ len += snprintf(buf + len, sizeof(buf) - len, \
+ "%u,", old_val[i]); \
+ len += snprintf(buf + len, sizeof(buf) - len, \
+ "%u --> new value %s\n", old_val[(size) - 1], new_val); \
+ pr_debug("%s", buf); \
+} while (0)
+
+#define PRINT_SIGNED_ARR(param, old_val, size, new_val) \
+do { \
+ u8 i; \
+ char buf[STR_LEN_256B]; \
+ int len = 0; \
+ len += snprintf(buf, sizeof(buf), "%s: old value ", #param); \
+ for (i = 0; i < (size) - 1; i++) \
+ len += snprintf(buf + len, sizeof(buf) - len, \
+ "%d,", old_val[i]); \
+ len += snprintf(buf + len, sizeof(buf) - len, \
+ "%d --> new value %s\n", old_val[(size) - 1], new_val); \
+ pr_debug("%s", buf); \
+} while (0)
+
+#define READ_BOOL(param) \
+do { \
+ if (!strcmp(name, #param)) { \
+ bool new_val = false; \
+ if (kstrtobool(value, &new_val) != 0) { \
+ pr_err("%s: invalid value [%s]\n", #param, value); \
+ return -1; \
+ } \
+ if (conf->param != new_val) { \
+ pr_debug("%s: old value %u -> new value %u\n", \
+ #param, conf->param, new_val); \
+ conf->param = new_val; \
+ } \
+ return 0; \
+ } \
+} while (0)
+
+#define READ_U8(param) \
+do { \
+ if (!strcmp(name, #param)) { \
+ u8 new_val = 0; \
+ if (kstrtou8(value, 0, &new_val) != 0) { \
+ pr_err("%s: invalid value [%s]\n", #param, value); \
+ return -1; \
+ } \
+ if (conf->param != new_val) { \
+ pr_debug("%s: old value %u -> new value %u\n", \
+ #param, conf->param, new_val); \
+ conf->param = new_val; \
+ } \
+ return 0; \
+ } \
+} while (0)
+
+#define READ_U16(param) \
+do { \
+ if (!strcmp(name, #param)) { \
+ u16 new_val = 0; \
+ if (kstrtou16(value, 0, &new_val) != 0) { \
+ pr_err("%s: invalid value [%s]\n", #param, value); \
+ return -1; \
+ } \
+ if (conf->param != new_val) { \
+ pr_debug("%s: old value %u -> new value %u\n", \
+ #param, conf->param, new_val); \
+ conf->param = new_val; \
+ } \
+ return 0; \
+ } \
+} while (0)
+
+#define READ_U32(param) \
+do { \
+ if (!strcmp(name, #param)) { \
+ u32 new_val = 0; \
+ if (kstrtou32(value, 0, &new_val) != 0) { \
+ pr_err("%s: invalid value [%s]\n", #param, value); \
+ return -1; \
+ } \
+ if (conf->param != new_val) { \
+ pr_debug("%s: old value %u -> new value %u\n", \
+ #param, conf->param, new_val); \
+ conf->param = new_val; \
+ } \
+ return 0; \
+ } \
+} while (0)
+
+#define READ_S8(param) \
+do { \
+ if (!strcmp(name, #param)) { \
+ s8 new_val = 0; \
+ if (kstrtos8(value, 0, &new_val) != 0) { \
+ pr_err("%s: invalid value [%s]\n", #param, value); \
+ return -1; \
+ } \
+ if (conf->param != new_val) { \
+ pr_debug("%s: old value %d -> new value %d\n", \
+ #param, conf->param, new_val); \
+ conf->param = new_val; \
+ } \
+ return 0; \
+ } \
+} while (0)
+
+#define READ_S16(param) \
+do { \
+ if (!strcmp(name, #param)) { \
+ s16 new_val = 0; \
+ if (kstrtos16(value, 0, &new_val) != 0) { \
+ pr_err("%s: invalid value [%s]\n", #param, value); \
+ return -1; \
+ } \
+ if (conf->param != new_val) { \
+ pr_debug("%s: old value %d -> new value %d\n", \
+ #param, conf->param, new_val); \
+ conf->param = new_val; \
+ } \
+ return 0; \
+ } \
+} while (0)
+
+#define READ_S32(param) \
+do { \
+ if (!strcmp(name, #param)) { \
+ s32 new_val = 0; \
+ if (kstrtos32(value, 0, &new_val) != 0) { \
+ pr_err("%s: invalid value [%s]\n", #param, value); \
+ return -1; \
+ } \
+ if (conf->param != new_val) { \
+ pr_debug("%s: old value %d -> new value %d\n", \
+ #param, conf->param, new_val); \
+ conf->param = new_val; \
+ } \
+ return 0; \
+ } \
+} while (0)
+
+#define READ_BOOL_ARR(param, size) \
+do { \
+ if (!strcmp(name, #param)) { \
+ int ret = 0; \
+ bool old_val[size] = {false}; \
+ memcpy(old_val, conf->param, sizeof(old_val)); \
+ ret = cl_strtobool_vector(value, conf->param, size, ","); \
+ if (ret == 0) { \
+ if (memcmp(old_val, conf->param, sizeof(old_val))) \
+ PRINT_UNSIGNED_ARR(param, old_val, size, value); \
+ } else if (ret == -E2BIG) { \
+ pr_err("%s: value [%s] too big [%zu]\n", #param, value, strlen(value)); \
+ } else if (ret == -EIO) { \
+ pr_err("%s: delimiter ',' not found\n", #param); \
+ } else if (ret == -EINVAL) { \
+ pr_err("%s: invalid argument [%s]\n", #param, value); \
+ } else if (ret == -1) { \
+ pr_err("%s: value [%s] doesn't have %u elements\n", #param, value, size); \
+ } \
+ return ret; \
+ } \
+} while (0)
+
+#define READ_U8_ARR(param, size) \
+do { \
+ if (!strcmp(name, #param)) { \
+ int ret = 0; \
+ u8 old_val[size] = {0}; \
+ memcpy(old_val, conf->param, sizeof(old_val)); \
+ ret = cl_strtou8_vector(value, conf->param, size, ","); \
+ if (ret == 0) { \
+ if (memcmp(old_val, conf->param, sizeof(old_val))) \
+ PRINT_UNSIGNED_ARR(param, old_val, size, value); \
+ } else if (ret == -E2BIG) { \
+ pr_err("%s: value [%s] too big [%zu]\n", #param, value, strlen(value)); \
+ } else if (ret == -EIO) { \
+ pr_err("%s: delimiter ',' not found\n", #param); \
+ } else if (ret == -EINVAL) { \
+ pr_err("%s: invalid argument [%s]\n", #param, value); \
+ } else if (ret == -1) { \
+ pr_err("%s: value [%s] doesn't have %u elements\n", #param, value, size); \
+ } \
+ return ret; \
+ } \
+} while (0)
+
+#define READ_U16_ARR(param, size) \
+do { \
+ if (!strcmp(name, #param)) { \
+ int ret = 0; \
+ u16 old_val[size] = {0}; \
+ memcpy(old_val, conf->param, sizeof(old_val)); \
+ ret = cl_strtou16_vector(value, conf->param, size, ","); \
+ if (ret == 0) { \
+ if (memcmp(old_val, conf->param, sizeof(old_val))) \
+ PRINT_UNSIGNED_ARR(param, old_val, size, value); \
+ } else if (ret == -E2BIG) { \
+ pr_err("%s: value [%s] too big [%zu]\n", #param, value, strlen(value)); \
+ } else if (ret == -EIO) { \
+ pr_err("%s: delimiter ',' not found\n", #param); \
+ } else if (ret == -EINVAL) { \
+ pr_err("%s: invalid argument [%s]\n", #param, value); \
+ } else if (ret == -1) { \
+ pr_err("%s: value [%s] doesn't have %u elements\n", #param, value, size); \
+ } \
+ return ret; \
+ } \
+} while (0)
+
+#define READ_U32_ARR(param, size) \
+do { \
+ if (!strcmp(name, #param)) { \
+ int ret = 0; \
+ u32 old_val[size] = {0}; \
+ memcpy(old_val, conf->param, sizeof(old_val)); \
+ ret = cl_strtou32_vector(value, conf->param, size, ","); \
+ if (ret == 0) { \
+ if (memcmp(old_val, conf->param, sizeof(old_val))) \
+ PRINT_UNSIGNED_ARR(param, old_val, size, value); \
+ } else if (ret == -E2BIG) { \
+ pr_err("%s: value [%s] too big [%zu]\n", #param, value, strlen(value)); \
+ } else if (ret == -EIO) { \
+ pr_err("%s: delimiter ',' not found\n", #param); \
+ } else if (ret == -EINVAL) { \
+ pr_err("%s: invalid argument [%s]\n", #param, value); \
+ } else if (ret == -1) { \
+ pr_err("%s: value [%s] doesn't have %u elements\n", #param, value, size); \
+ } \
+ return ret; \
+ } \
+} while (0)
+
+#define READ_S8_ARR(param, size) \
+do { \
+ if (!strcmp(name, #param)) { \
+ int ret = 0; \
+ s8 old_val[size] = {0}; \
+ memcpy(old_val, conf->param, sizeof(old_val)); \
+ ret = cl_strtos8_vector(value, conf->param, size, ","); \
+ if (ret == 0) { \
+ if (memcmp(old_val, conf->param, sizeof(old_val))) \
+ PRINT_SIGNED_ARR(param, old_val, size, value); \
+ } else if (ret == -E2BIG) { \
+ pr_err("%s: value [%s] too big [%zu]\n", #param, value, strlen(value)); \
+ } else if (ret == -EIO) { \
+ pr_err("%s: delimiter ',' not found\n", #param); \
+ } else if (ret == -EINVAL) { \
+ pr_err("%s: invalid argument [%s]\n", #param, value); \
+ } else if (ret == -1) { \
+ pr_err("%s: value [%s] doesn't have %u elements\n", #param, value, size); \
+ } \
+ return ret; \
+ } \
+} while (0)
+
+#define READ_S16_ARR(param, size) \
+do { \
+ if (!strcmp(name, #param)) { \
+ int ret = 0; \
+ s16 old_val[size] = {0}; \
+ memcpy(old_val, conf->param, sizeof(old_val)); \
+ ret = cl_strtos16_vector(value, conf->param, size, ","); \
+ if (ret == 0) { \
+ if (memcmp(old_val, conf->param, sizeof(old_val))) \
+ PRINT_SIGNED_ARR(param, old_val, size, value); \
+ } else if (ret == -E2BIG) { \
+ pr_err("%s: value [%s] too big [%zu]\n", #param, value, strlen(value)); \
+ } else if (ret == -EIO) { \
+ pr_err("%s: delimiter ',' not found\n", #param); \
+ } else if (ret == -EINVAL) { \
+ pr_err("%s: invalid argument [%s]\n", #param, value); \
+ } else if (ret == -1) { \
+ pr_err("%s: value [%s] doesn't have %u elements\n", #param, value, size); \
+ } \
+ return ret; \
+ } \
+} while (0)
+
+#define READ_S32_ARR(param, size) \
+do { \
+ if (!strcmp(name, #param)) { \
+ int ret = 0; \
+ s32 old_val[size] = {0}; \
+ memcpy(old_val, conf->param, sizeof(old_val)); \
+ ret = cl_strtos32_vector(value, conf->param, size, ","); \
+ if (ret == 0) { \
+ if (memcmp(old_val, conf->param, sizeof(old_val))) \
+ PRINT_SIGNED_ARR(param, old_val, size, value); \
+ } else if (ret == -E2BIG) { \
+ pr_err("%s: value [%s] too big [%zu]\n", #param, value, strlen(value)); \
+ } else if (ret == -EIO) { \
+ pr_err("%s: delimiter ',' not found\n", #param); \
+ } else if (ret == -EINVAL) { \
+ pr_err("%s: invalid argument [%s]\n", #param, value); \
+ } else if (ret == -1) { \
+ pr_err("%s: value [%s] doesn't have %u elements\n", #param, value, size); \
+ } \
+ return ret; \
+ } \
+} while (0)
+
+#define READ_STR(param) \
+do { \
+ if (!strcmp(name, #param)) { \
+ if (strcmp(value, conf->param)) { \
+ pr_debug("%s: old value %s -> new value %s\n", \
+ #param, conf->param, value); \
+ strncpy(conf->param, value, sizeof(conf->param) - 1); \
+ } \
+ return 0; \
+ } \
+} while (0)
+
+#define READ_MAC(param) \
+do { \
+ if (!strcmp(name, #param)) { \
+ u8 old_val[ETH_ALEN] = {0}; \
+ memcpy(old_val, conf->param, ETH_ALEN); \
+ if (cl_strtou8_hex_vector(value, conf->param, ETH_ALEN, ":")) \
+ return -1; \
+ if (memcmp(old_val, conf->param, sizeof(old_val))) \
+ pr_debug("%s: old value %pM -> new value %pM\n", \
+ #param, old_val, conf->param); \
+ return 0; \
+ } \
+} while (0)
+
+#define print_signed(var) \
+ pr_debug("%s = %d\n", #var, conf->var)
+
+#define print_unsigned(var) \
+ pr_debug("%s = %u\n", #var, conf->var)
+
+#define print_bool(var) \
+ pr_debug("%s = %s\n", #var, conf->var ? "true" : "false")
+
+#define print_str(var) \
+ pr_debug("%s = %s\n", #var, conf->var)
+
+#define print_mac(var) \
+ pr_debug("%s = %pM\n", #var, conf->var)
+
+#define print_hex(var) \
+ pr_debug("%s = 0x%x\n", #var, conf->var)
+
+#define print_signed_arr(var, size) \
+ { \
+ int i, len; \
+ char str[256] = {0}; \
+ len = snprintf(str, sizeof(str), "%s = ", #var); \
+ for (i = 0; i < (size); i++) \
+ len += snprintf(str + len, sizeof(str) - len, \
+ "%d%s", conf->var[i], (i < ((size) - 1)) ? "," : ""); \
+ pr_debug("%s\n", str); \
+ }
+
+#define print_unsigned_arr(var, size) \
+ { \
+ int i, len; \
+ char str[256] = {0}; \
+ len = snprintf(str, sizeof(str), "%s = ", #var); \
+ for (i = 0; i < (size); i++) \
+ len += snprintf(str + len, sizeof(str) - len, \
+ "%u%s", conf->var[i], (i < ((size) - 1)) ? "," : ""); \
+ pr_debug("%s\n", str); \
+ }
+
+struct cl_hw;
+
+bool cl_config_is_non_driver_param(char *name);
+int cl_config_cli(struct cl_hw *cl_hw, struct cli_params *cli_params);
+
+#endif /* CL_CONFIG_H */
--
2.30.0

________________________________
The information transmitted is intended only for the person or entity to which it is addressed and may contain confidential and/or privileged material. Any retransmission, dissemination, copying or other use of, or taking of any action in reliance upon this information is prohibited. If you received this in error, please contact the sender and delete the material from any computer. Nothing contained herein shall be deemed as a representation, warranty or a commitment by Celeno. No warranties are expressed or implied, including, but not limited to, any implied warranties of non-infringement, merchantability and fitness for a particular purpose.
________________________________

2021-06-17 16:24:58

by viktor.barna

[permalink] [raw]
Subject: [RFC v1 042/256] cl8k: add chip.c

From: Viktor Barna <[email protected]>

(Part of the split. Please, take a look at the cover letter for more
details).

Signed-off-by: Viktor Barna <[email protected]>
---
drivers/net/wireless/celeno/cl8k/chip.c | 241 ++++++++++++++++++++++++
1 file changed, 241 insertions(+)
create mode 100644 drivers/net/wireless/celeno/cl8k/chip.c

diff --git a/drivers/net/wireless/celeno/cl8k/chip.c b/drivers/net/wireless/celeno/cl8k/chip.c
new file mode 100644
index 000000000000..5876b1da1857
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/chip.c
@@ -0,0 +1,241 @@
+// SPDX-License-Identifier: MIT
+/* Copyright(c) 2019-2021, Celeno Communications Ltd. */
+
+#include <linux/dmapool.h>
+#include "chip.h"
+#include "chip_config.h"
+#include "utils/utils.h"
+#include "reg/reg_access.h"
+#include "reg/reg_ipc.h"
+#include "temperature.h"
+#include "fem.h"
+#include "e2p.h"
+#include "ela.h"
+#include "utils/string.h"
+#include "main.h"
+#include "netlink.h"
+#include "data_rates.h"
+#ifdef CONFIG_CL_PCIE
+#include "bus/pci/irq.h"
+#endif
+
+#define CL_ALIGN_BOUND_64KB BIT(16)
+
+static void cl_chip_set_max_antennas(struct cl_chip *chip)
+{
+ switch (chip->pci_dev->device) {
+ case 0x8040:
+ case 0x8046:
+ chip->max_antennas = MAX_ANTENNAS_CL804X;
+ break;
+ case 0x8060:
+ case 0x8066:
+ chip->max_antennas = MAX_ANTENNAS_CL806X;
+ break;
+ case 0x8080:
+ case 0x8086:
+ default:
+ chip->max_antennas = MAX_ANTENNAS_CL808X;
+ break;
+ }
+
+ cl_dbg_chip_trace(chip, "max_antennas = %u\n", chip->max_antennas);
+}
+
+static int cl_chip_print_serial_number(struct cl_chip *chip)
+{
+ u8 serial_number[SIZE_GEN_SERIAL_NUMBER + 1] = {0};
+
+ if (cl_e2p_read(chip, (u8 *)&serial_number, SIZE_GEN_SERIAL_NUMBER, ADDR_GEN_SERIAL_NUMBER))
+ return -1;
+
+ if (strlen(serial_number) == 0)
+ CL_DBG_WARNING_CHIP(chip, "Serial-number in not set in EEPROM\n");
+ else
+ cl_dbg_chip_verbose(chip, "Serial-number = %s\n", serial_number);
+
+ return 0;
+}
+
+static int cl_chip_ring_indices_init(struct cl_chip *chip)
+{
+ struct cl_ring_indices *ring_indices = &chip->ring_indices;
+
+ ring_indices->pool = dma_pool_create("cl_ring_indices_pool", chip->dev,
+ (sizeof(struct cl_ipc_ring_indices) * TCV_MAX),
+ CL_ALIGN_BOUND_64KB, CL_ALIGN_BOUND_64KB);
+
+ if (!ring_indices->pool) {
+ cl_dbg_chip_err(chip, "ring_indices pool create failed !!!\n");
+ return -ENOMEM;
+ }
+
+ ring_indices->params = dma_pool_alloc(ring_indices->pool, GFP_KERNEL,
+ &ring_indices->dma_addr);
+ if (!ring_indices->params)
+ return -ENOMEM;
+
+ return 0;
+}
+
+static void cl_chip_ring_indices_deinit(struct cl_chip *chip)
+{
+ if (chip->ring_indices.params) {
+ dma_pool_free(chip->ring_indices.pool,
+ chip->ring_indices.params,
+ chip->ring_indices.dma_addr);
+ chip->ring_indices.params = NULL;
+ }
+
+ dma_pool_destroy(chip->ring_indices.pool);
+ chip->ring_indices.pool = NULL;
+}
+
+struct cl_chip *cl_chip_alloc(u8 idx)
+{
+ struct cl_chip *chip = kzalloc(sizeof(*chip), GFP_KERNEL);
+
+ if (!chip)
+ return NULL;
+
+ chip->idx = idx;
+ return chip;
+}
+
+void cl_chip_dealloc(struct cl_chip *chip)
+{
+ cl_chip_config_dealloc(chip);
+ kfree(chip);
+}
+
+int cl_chip_init(struct cl_chip *chip)
+{
+ int ret = 0;
+
+ chip->agc_table_entry = U8_MAX;
+
+ spin_lock_init(&chip->isr_lock);
+ spin_lock_init(&chip->spi_lock);
+
+ rwlock_init(&chip->cl_hw_lock);
+
+ cl_chip_set_max_antennas(chip);
+
+#ifdef CONFIG_CL_PCIE
+ ret = cl_irq_request(chip);
+ if (ret)
+ return ret;
+#endif
+ ipc_host_global_int_en_set(chip, 1);
+
+ cl_temperature_init(chip);
+
+ ret = cl_e2p_init(chip);
+ if (ret) {
+ cl_dbg_chip_err(chip, "cl_e2p_init failed %d\n", ret);
+ return ret;
+ }
+
+ ret = cl_fem_init(chip);
+ if (ret)
+ return ret;
+
+ ret = cl_chip_ring_indices_init(chip);
+ if (ret)
+ return ret;
+
+ cl_chip_print_serial_number(chip);
+
+ cl_wrs_tables_global_build();
+ cl_data_rates_inverse_build();
+
+ return ret;
+}
+
+void cl_chip_deinit(struct cl_chip *chip)
+{
+ cl_chip_ring_indices_deinit(chip);
+ cl_temperature_close(chip);
+ cl_e2p_close(chip);
+ ipc_host_global_int_en_set(chip, 0);
+
+#ifdef CONFIG_CL_PCIE
+ cl_irq_free(chip);
+#endif
+}
+
+bool cl_chip_is_enabled(struct cl_chip *chip)
+{
+ return cl_chip_is_tcv0_enabled(chip) || cl_chip_is_tcv1_enabled(chip);
+}
+
+bool cl_chip_is_both_enabled(struct cl_chip *chip)
+{
+ return cl_chip_is_tcv0_enabled(chip) && cl_chip_is_tcv1_enabled(chip);
+}
+
+bool cl_chip_is_tcv_enabled(struct cl_chip *chip, u8 tcv_idx)
+{
+ return chip->conf->ce_tcv_enabled[tcv_idx];
+}
+
+bool cl_chip_is_tcv0_enabled(struct cl_chip *chip)
+{
+ return chip->conf->ce_tcv_enabled[TCV0];
+}
+
+bool cl_chip_is_tcv1_enabled(struct cl_chip *chip)
+{
+ return chip->conf->ce_tcv_enabled[TCV1];
+}
+
+void cl_chip_set_hw(struct cl_chip *chip, struct cl_hw *cl_hw)
+{
+ if (cl_hw_is_tcv0(cl_hw))
+ chip->cl_hw_tcv0 = cl_hw;
+ else
+ chip->cl_hw_tcv1 = cl_hw;
+}
+
+void cl_chip_unset_hw(struct cl_chip *chip, struct cl_hw *cl_hw)
+{
+ if (cl_hw_is_tcv0(cl_hw))
+ chip->cl_hw_tcv0 = NULL;
+ else
+ chip->cl_hw_tcv1 = NULL;
+}
+
+bool cl_chip_is_8ant(struct cl_chip *chip)
+{
+ return chip->max_antennas == MAX_ANTENNAS_CL808X;
+}
+
+bool cl_chip_is_6ant(struct cl_chip *chip)
+{
+ return chip->max_antennas == MAX_ANTENNAS_CL806X;
+}
+
+bool cl_chip_is_4ant(struct cl_chip *chip)
+{
+ return chip->max_antennas == MAX_ANTENNAS_CL804X;
+}
+
+static u16 cl_chip_get_device_id(struct cl_chip *chip)
+{
+ u16 device_id = chip->pci_dev->device;
+
+ /* If device-id is default, set it accoridng to phy-dev. */
+ if (device_id == 0x8000 || device_id == 0x8001)
+ device_id = IS_PHY_ATHOS(chip) ? 0x8086 : 0x8080;
+
+ return device_id;
+}
+
+bool cl_chip_is_6g(struct cl_chip *chip)
+{
+ u16 device_id = cl_chip_get_device_id(chip);
+ u8 band = device_id & 0xf;
+
+ return (band == 6);
+}
+
--
2.30.0

________________________________
The information transmitted is intended only for the person or entity to which it is addressed and may contain confidential and/or privileged material. Any retransmission, dissemination, copying or other use of, or taking of any action in reliance upon this information is prohibited. If you received this in error, please contact the sender and delete the material from any computer. Nothing contained herein shall be deemed as a representation, warranty or a commitment by Celeno. No warranties are expressed or implied, including, but not limited to, any implied warranties of non-infringement, merchantability and fitness for a particular purpose.
________________________________

2021-06-17 16:24:59

by viktor.barna

[permalink] [raw]
Subject: [RFC v1 024/256] cl8k: add bus/pci/rx_pci.c

From: Viktor Barna <[email protected]>

(Part of the split. Please, take a look at the cover letter for more
details).

Signed-off-by: Viktor Barna <[email protected]>
---
.../net/wireless/celeno/cl8k/bus/pci/rx_pci.c | 219 ++++++++++++++++++
1 file changed, 219 insertions(+)
create mode 100644 drivers/net/wireless/celeno/cl8k/bus/pci/rx_pci.c

diff --git a/drivers/net/wireless/celeno/cl8k/bus/pci/rx_pci.c b/drivers/net/wireless/celeno/cl8k/bus/pci/rx_pci.c
new file mode 100644
index 000000000000..1f0724dcc692
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/bus/pci/rx_pci.c
@@ -0,0 +1,219 @@
+// SPDX-License-Identifier: MIT
+/* Copyright(c) 2019-2021, Celeno Communications Ltd. */
+
+#include "bus/pci/rx_pci.h"
+#include "bus/pci/ipc.h"
+#include "rx/rx.h"
+#include "ipc_shared.h"
+#include "def.h"
+#include "bus/pci/irq.h"
+#include "chip.h"
+#ifdef TRACE_SUPPORT
+#include "trace.h"
+#endif
+
+static DEFINE_PER_CPU(struct tasklet_struct, rx_remote_tasklet_drv[TCV_TOTAL]);
+
+static void cl_rx_pci_stats_rxm(struct cl_hw *cl_hw, u16 bucket_idx)
+{
+ if (bucket_idx < IPC_RXBUF_NUM_BUCKETS_RXM)
+ cl_hw->rx_info.pkt_handle_bucket_rxm[bucket_idx]++;
+ else
+ cl_hw->rx_info.pkt_handle_bucket_rxm[IPC_RXBUF_NUM_BUCKETS_RXM - 1]++;
+}
+
+static void cl_rx_pci_stats_fw(struct cl_hw *cl_hw, u16 bucket_idx)
+{
+ if (bucket_idx < IPC_RXBUF_NUM_BUCKETS_FW)
+ cl_hw->rx_info.pkt_handle_bucket_fw[bucket_idx]++;
+ else
+ cl_hw->rx_info.pkt_handle_bucket_fw[IPC_RXBUF_NUM_BUCKETS_FW - 1]++;
+}
+
+static void cl_rx_pci_stats(struct cl_hw *cl_hw, u16 pkt_cnt, enum rx_buf_type type)
+{
+ /* Collect stats - fill the bucket stats */
+ if (pkt_cnt) {
+ u16 bucket_idx = pkt_cnt >> IPC_RXBUF_BUCKET_POW_SIZE;
+
+ if (type == CL_RX_BUF_RXM)
+ cl_rx_pci_stats_rxm(cl_hw, bucket_idx);
+ else
+ cl_rx_pci_stats_fw(cl_hw, bucket_idx);
+ }
+}
+
+static int _cl_rx_pci_start(struct cl_hw *cl_hw, u32 rxdesc_read_idx, u32 host_read_idx,
+ enum rx_buf_type type)
+{
+ struct cl_ipc_host_env *ipc_env = cl_hw->ipc_env;
+ struct cl_ipc_host_rxbuf *rx_hostbuf = &ipc_env->rx_hostbuf_array[type];
+ struct cl_rx_elem *rxelem =
+ (struct cl_rx_elem *)rx_hostbuf->ipc_host_rxdesc_ptr[host_read_idx];
+ struct sk_buff *skb;
+ int ret = 0;
+ dma_addr_t dma_addr;
+ u32 size = cl_hw->conf->ci_ipc_rxbuf_size[type];
+
+ cl_hw->rx_info.rx_desc[type]++;
+
+ /* Copy the current skb buffer & dma_addr. */
+ skb = rxelem->skb;
+ dma_addr = rxelem->dma_addr;
+
+ /* Try to populate the rxelem with new skb */
+ if (cl_ipc_rx_elem_alloc(cl_hw, rxelem, size)) {
+ cl_hw->rx_info.elem_alloc_fail++;
+ /* Restore skb and dma_addr value */
+ rxelem->skb = skb;
+ rxelem->dma_addr = dma_addr;
+ ret = -ENOMEM;
+ goto handle_done;
+ }
+
+ /* Release dma virtual memory early */
+ dma_unmap_single(cl_hw->chip->dev, dma_addr, size, DMA_FROM_DEVICE);
+
+ if (!skb) {
+ cl_hw->rx_info.skb_null++;
+ cl_dbg_verbose(cl_hw, "skb is NULL\n");
+ goto handle_done;
+ }
+
+ cl_ipc_rxbuf_push(ipc_env, rxelem, rxdesc_read_idx, host_read_idx, type);
+
+ cl_rx_push_queue(cl_hw, skb);
+
+handle_done:
+ return ret;
+}
+
+static void cl_rx_pci_start(struct cl_hw *cl_hw, enum rx_buf_type type, u16 rx_buf_cnt)
+{
+ struct cl_ipc_host_env *ipc_env = cl_hw->ipc_env;
+ struct cl_ipc_ring_indices *indices = ipc_env->ring_indices_elem->indices;
+ u16 buf_cnt_mask = rx_buf_cnt - 1;
+ u16 pkt_cnt = 0;
+ u32 rxdesc_read_idx = le32_to_cpu(indices->rxdesc_read_idx[type]);
+ u32 host_read_idx = 0;
+ u32 rxdesc_write_idx = le32_to_cpu(indices->rxdesc_write_idx[type]);
+ u32 host_write_idx = 0;
+
+ /*
+ * Firmware has triggered an interrupt saying that a reception has occurred.
+ * Iterate over all valid rxdesc pushed by embedded.
+ * The read index is incremented once the callback function finishes meaning
+ * a new allocated skb pushed the rxbuff.
+ * The write index is incremented in direct write by the embedded layer,
+ * indicating that allocated skb was populated with packet data.
+ */
+
+ do {
+ host_write_idx = rxdesc_write_idx;
+
+ while (ipc_env->host_rxdesc_read_idx[type] != host_write_idx) {
+ host_read_idx = rxdesc_read_idx & buf_cnt_mask;
+
+ if (_cl_rx_pci_start(cl_hw, rxdesc_read_idx, host_read_idx, type) == 0) {
+ /* Local application follower of embedded read idx */
+ ipc_env->host_rxdesc_read_idx[type]++;
+ rxdesc_read_idx++;
+ pkt_cnt++;
+ } else {
+ /*
+ * Replacing old skb with new allocated skb failed
+ * (should not happen). Postpone the handle of the
+ * old skb until this function is reschduled again.
+ */
+ if (!test_bit(CL_DEV_STOP_HW, &cl_hw->drv_flags))
+ tasklet_schedule(&ipc_env->rxdesc_tasklet);
+ goto out;
+ }
+ }
+
+ /* Check if firmware pushed new descriptors */
+ rxdesc_write_idx = le32_to_cpu(indices->rxdesc_write_idx[type]);
+ } while (host_write_idx != rxdesc_write_idx);
+
+out:
+ cl_rx_pci_stats(cl_hw, pkt_cnt, type);
+}
+
+static void cl_rx_pci_remote_tasklet_handler(unsigned long data)
+{
+ struct cl_hw *cl_hw = (struct cl_hw *)data;
+
+ cl_rx_remote_cpu_info(cl_hw);
+ cl_rx_pci_desc_handler(cl_hw);
+}
+
+static void cl_rx_pci_remote_cpu_sched(struct cl_hw *cl_hw)
+{
+ int cpu = cl_hw->conf->ci_rx_remote_cpu_drv;
+ struct tasklet_struct *t = &per_cpu(rx_remote_tasklet_drv[cl_hw->idx], cpu);
+
+ if (!test_bit(TASKLET_STATE_SCHED, &t->state))
+ smp_call_function_single(cpu, cl_rx_remote_tasklet_sched, t, 0);
+}
+
+void cl_rx_pci_init(struct cl_hw *cl_hw)
+{
+ s8 cpu = cl_hw->conf->ci_rx_remote_cpu_drv;
+
+ if (cpu >= 0)
+ tasklet_init(&per_cpu(rx_remote_tasklet_drv[cl_hw->idx], cpu),
+ cl_rx_pci_remote_tasklet_handler,
+ (unsigned long)cl_hw);
+}
+
+void cl_rx_pci_deinit(struct cl_hw *cl_hw)
+{
+ s8 cpu = cl_hw->conf->ci_rx_remote_cpu_drv;
+
+ if (cpu >= 0)
+ tasklet_kill(&per_cpu(rx_remote_tasklet_drv[cl_hw->idx], cpu));
+}
+
+void cl_rx_pci_desc_handler(struct cl_hw *cl_hw)
+{
+#ifdef TRACE_SUPPORT
+ struct cl_ipc_host_env *ipc_env = cl_hw->ipc_env;
+
+ trace_cl_trace_rx_desc_tasklet_start(cl_hw->idx,
+ ipc_env->host_rxdesc_read_idx[CL_RX_BUF_RXM],
+ ipc_env->host_rxdesc_read_idx[CL_RX_BUF_FW]);
+#endif
+
+ /* Handle all RXM rx elements */
+ cl_rx_pci_start(cl_hw, CL_RX_BUF_RXM, IPC_RXBUF_CNT_RXM);
+ /* Handle all FW rx elements */
+ cl_rx_pci_start(cl_hw, CL_RX_BUF_FW, IPC_RXBUF_CNT_FW);
+
+ /* Initiate interrupt to embbeded when all rx elements were handled */
+ if (!test_bit(CL_DEV_HW_RESTART, &cl_hw->drv_flags))
+ cl_hw->ipc_host2xmac_trigger_set(cl_hw->chip, IPC_IRQ_A2E_RXBUF_BACK);
+
+ /*
+ * Finished handle all valid rx elements, restore the RX interrupt
+ * to enable handling new populated rx elements
+ */
+ if (!test_bit(CL_DEV_STOP_HW, &cl_hw->drv_flags))
+ cl_irq_enable(cl_hw, cl_hw->ipc_e2a_irq.rxdesc);
+
+#ifdef TRACE_SUPPORT
+ trace_cl_trace_rx_desc_tasklet_end(cl_hw->idx,
+ ipc_env->host_rxdesc_read_idx[CL_RX_BUF_RXM],
+ ipc_env->host_rxdesc_read_idx[CL_RX_BUF_FW]);
+#endif
+}
+
+void cl_rx_pci_desc_tasklet(unsigned long data)
+{
+ struct cl_hw *cl_hw = (struct cl_hw *)data;
+
+ if (cl_hw->conf->ci_rx_remote_cpu_drv == -1)
+ cl_rx_pci_desc_handler(cl_hw);
+ else
+ cl_rx_pci_remote_cpu_sched(cl_hw);
+}
+
--
2.30.0

________________________________
The information transmitted is intended only for the person or entity to which it is addressed and may contain confidential and/or privileged material. Any retransmission, dissemination, copying or other use of, or taking of any action in reliance upon this information is prohibited. If you received this in error, please contact the sender and delete the material from any computer. Nothing contained herein shall be deemed as a representation, warranty or a commitment by Celeno. No warranties are expressed or implied, including, but not limited to, any implied warranties of non-infringement, merchantability and fitness for a particular purpose.
________________________________

2021-06-17 16:25:01

by viktor.barna

[permalink] [raw]
Subject: [RFC v1 045/256] cl8k: add chip_config.h

From: Viktor Barna <[email protected]>

(Part of the split. Please, take a look at the cover letter for more
details).

Signed-off-by: Viktor Barna <[email protected]>
---
.../net/wireless/celeno/cl8k/chip_config.h | 58 +++++++++++++++++++
1 file changed, 58 insertions(+)
create mode 100644 drivers/net/wireless/celeno/cl8k/chip_config.h

diff --git a/drivers/net/wireless/celeno/cl8k/chip_config.h b/drivers/net/wireless/celeno/cl8k/chip_config.h
new file mode 100644
index 000000000000..2cfa20522e0d
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/chip_config.h
@@ -0,0 +1,58 @@
+/* SPDX-License-Identifier: MIT */
+/* Copyright(c) 2019-2021, Celeno Communications Ltd. */
+
+#ifndef CL_CHIP_CONFIG_H
+#define CL_CHIP_CONFIG_H
+
+#include "def.h"
+#include "utils/string.h"
+#include <linux/types.h>
+#include <linux/if_ether.h>
+
+#define CC_MAX_LEN 3 /* 2 characters + null */
+#define FW_MAX_NAME 32
+
+struct cl_chip_conf {
+ bool ce_tcv_enabled[TCV_MAX];
+ s8 ce_lmac[FW_MAX_NAME];
+ s8 ce_smac[FW_MAX_NAME];
+ s8 ce_umac[FW_MAX_NAME];
+ s32 ce_irq_smp_affinity;
+ u8 ce_eeprom_mode;
+ bool ce_production_mode;
+ bool ci_pci_msi_enable;
+ u8 ci_dma_lli_max_chan[TCV_MAX];
+ s8 ce_country_code[CC_MAX_LEN];
+ s8 ce_ela_mode[STR_LEN_64B];
+ u8 ci_phy_dev;
+ s8 ce_debug_level;
+ u8 ce_host_pci_gen_ver;
+ bool ce_temp_comp_en;
+ u8 ce_temp_protect_en;
+ s8 ce_temp_protect_delta;
+ s16 ce_temp_protect_th_max;
+ s16 ce_temp_protect_th_min;
+ u16 ce_temp_protect_tx_period_ms;
+ s16 ce_temp_protect_radio_off_th;
+ u8 ce_phys_mac_addr[ETH_ALEN];
+ bool ce_lam_enable;
+ u8 ce_first_mask_bit;
+ bool ci_no_capture_noise_sleep;
+ u8 ci_dcoc_mv_thr[CHNL_BW_MAX];
+ s8 ci_lolc_db_thr;
+ s8 ci_iq_db_thr;
+ bool ci_rx_resched_tasklet;
+ u32 ci_rx_skb_max;
+ bool ce_calib_scan_en;
+
+ /* New NVRAM parameters must be added to cl_chip_config_print() */
+};
+
+struct cl_chip;
+
+int cl_chip_config_read(struct cl_chip *chip);
+int cl_chip_config_set(struct cl_chip *chip, char *buf, loff_t size);
+void cl_chip_config_dealloc(struct cl_chip *chip);
+void cl_chip_config_print(struct cl_chip *chip);
+
+#endif /* CL_CHIP_CONFIG_H */
--
2.30.0

________________________________
The information transmitted is intended only for the person or entity to which it is addressed and may contain confidential and/or privileged material. Any retransmission, dissemination, copying or other use of, or taking of any action in reliance upon this information is prohibited. If you received this in error, please contact the sender and delete the material from any computer. Nothing contained herein shall be deemed as a representation, warranty or a commitment by Celeno. No warranties are expressed or implied, including, but not limited to, any implied warranties of non-infringement, merchantability and fitness for a particular purpose.
________________________________

2021-06-17 16:25:02

by viktor.barna

[permalink] [raw]
Subject: [RFC v1 056/256] cl8k: add debugfs.h

From: Viktor Barna <[email protected]>

(Part of the split. Please, take a look at the cover letter for more
details).

Signed-off-by: Viktor Barna <[email protected]>
---
drivers/net/wireless/celeno/cl8k/debugfs.h | 28 ++++++++++++++++++++++
1 file changed, 28 insertions(+)
create mode 100644 drivers/net/wireless/celeno/cl8k/debugfs.h

diff --git a/drivers/net/wireless/celeno/cl8k/debugfs.h b/drivers/net/wireless/celeno/cl8k/debugfs.h
new file mode 100644
index 000000000000..1684c6aea1a9
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/debugfs.h
@@ -0,0 +1,28 @@
+/* SPDX-License-Identifier: MIT */
+/* Copyright(c) 2019-2021, Celeno Communications Ltd. */
+
+#ifndef CL_DEBUGFS_H
+#define CL_DEBUGFS_H
+
+#include "debugfs_defs.h"
+#include "hw.h"
+
+#ifdef CONFIG_CL_DEBUGFS
+
+int cl_dbgfs_register(struct cl_hw *cl_hw, const char *name);
+void cl_dbgfs_unregister(struct cl_hw *cl_hw);
+
+#else
+
+static inline int cl_dbgfs_register(struct cl_hw *cl_hw, const char *name)
+{
+ return 0;
+}
+
+static inline void cl_dbgfs_unregister(struct cl_hw *cl_hw)
+{
+}
+
+#endif /* CONFIG_CL_DEBUGFS */
+
+#endif /* CL_DEBUGFS_H */
--
2.30.0

________________________________
The information transmitted is intended only for the person or entity to which it is addressed and may contain confidential and/or privileged material. Any retransmission, dissemination, copying or other use of, or taking of any action in reliance upon this information is prohibited. If you received this in error, please contact the sender and delete the material from any computer. Nothing contained herein shall be deemed as a representation, warranty or a commitment by Celeno. No warranties are expressed or implied, including, but not limited to, any implied warranties of non-infringement, merchantability and fitness for a particular purpose.
________________________________

2021-06-17 16:25:04

by viktor.barna

[permalink] [raw]
Subject: [RFC v1 049/256] cl8k: add coredump.h

From: Viktor Barna <[email protected]>

(Part of the split. Please, take a look at the cover letter for more
details).

Signed-off-by: Viktor Barna <[email protected]>
---
drivers/net/wireless/celeno/cl8k/coredump.h | 76 +++++++++++++++++++++
1 file changed, 76 insertions(+)
create mode 100644 drivers/net/wireless/celeno/cl8k/coredump.h

diff --git a/drivers/net/wireless/celeno/cl8k/coredump.h b/drivers/net/wireless/celeno/cl8k/coredump.h
new file mode 100644
index 000000000000..d24f97b8f5de
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/coredump.h
@@ -0,0 +1,76 @@
+/* SPDX-License-Identifier: MIT */
+/* Copyright(c) 2019-2021, Celeno Communications Ltd. */
+
+#ifndef CL_COREDUMP_H
+#define CL_COREDUMP_H
+
+#include "hw.h"
+
+#define CL_COREDUMP_V1 1
+#define CL_COREDUMP_MAGIC_LEN 16
+
+struct cl_coredump {
+ char magic[CL_COREDUMP_MAGIC_LEN];
+ __le32 len;
+
+ /* 28 bits of self sizes + 4 bits of CL_COREDUMP_V* indicators */
+ __le32 self_version;
+
+ /* timings */
+ __le64 trig_tv_sec;
+ __le64 trig_tv_nsec;
+
+ /* dump info */
+ __le32 dump_mask;
+
+ u8 reserved[256];
+
+ /* Consists of multiple NLEV elements */
+ u8 data[];
+} __packed;
+
+/* NLEV - Name-Length-Error-Value element */
+struct cl_nlev {
+ char n[CL_COREDUMP_MAGIC_LEN];
+ __le32 l;
+ __le32 e;
+ u8 v[];
+} __packed;
+
+#ifdef CONFIG_CL_DEBUGFS
+
+int cl_coredump_trigger(struct cl_hw *cl_hw);
+bool cl_coredump_recovery(struct cl_hw *cl_hw, int reason);
+bool cl_coredump_is_scheduled(struct cl_hw *cl_hw);
+void cl_coredump_reset_trace(struct cl_hw *cl_hw);
+void cl_coredump_init(struct cl_hw *cl_hw, struct dentry *dir_drv);
+void cl_coredump_close(struct cl_hw *cl_hw);
+
+#else
+
+static inline int cl_coredump_trigger(struct cl_hw *cl_hw)
+{
+ return 0;
+}
+
+static inline bool cl_coredump_recovery(struct cl_hw *cl_hw, int reason)
+{
+ return false;
+}
+
+static inline bool cl_coredump_is_scheduled(struct cl_hw *cl_hw)
+{
+ return false;
+}
+
+static inline void cl_coredump_reset_trace(struct cl_hw *cl_hw)
+{}
+
+static inline void cl_coredump_init(struct cl_hw *cl_hw, struct dentry *dir_drv)
+{}
+
+static inline void cl_coredump_close(struct cl_hw *cl_hw)
+{}
+#endif /* CONFIG_CL_DEBUGFS */
+
+#endif /* CL_COREDUMP_H */
--
2.30.0

________________________________
The information transmitted is intended only for the person or entity to which it is addressed and may contain confidential and/or privileged material. Any retransmission, dissemination, copying or other use of, or taking of any action in reliance upon this information is prohibited. If you received this in error, please contact the sender and delete the material from any computer. Nothing contained herein shall be deemed as a representation, warranty or a commitment by Celeno. No warranties are expressed or implied, including, but not limited to, any implied warranties of non-infringement, merchantability and fitness for a particular purpose.
________________________________

2021-06-17 16:25:04

by viktor.barna

[permalink] [raw]
Subject: [RFC v1 027/256] cl8k: add bus/pci/tx_pci.h

From: Viktor Barna <[email protected]>

(Part of the split. Please, take a look at the cover letter for more
details).

Signed-off-by: Viktor Barna <[email protected]>
---
drivers/net/wireless/celeno/cl8k/bus/pci/tx_pci.h | 14 ++++++++++++++
1 file changed, 14 insertions(+)
create mode 100644 drivers/net/wireless/celeno/cl8k/bus/pci/tx_pci.h

diff --git a/drivers/net/wireless/celeno/cl8k/bus/pci/tx_pci.h b/drivers/net/wireless/celeno/cl8k/bus/pci/tx_pci.h
new file mode 100644
index 000000000000..8e07ee1965f1
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/bus/pci/tx_pci.h
@@ -0,0 +1,14 @@
+/* SPDX-License-Identifier: MIT */
+/* Copyright(c) 2019-2021, Celeno Communications Ltd. */
+
+#ifndef CL_TX_PCI_H
+#define CL_TX_PCI_H
+
+#include "hw.h"
+
+void cl_tx_pci_single_cfm_tasklet(unsigned long data);
+void cl_tx_pci_agg_cfm_tasklet(unsigned long data);
+void cl_tx_pci_pkt_fw_send(struct cl_hw *cl_hw, struct cl_sw_txhdr *sw_txhdr,
+ struct cl_tx_queue *tx_queue);
+
+#endif /* CL_TX_PCI_H */
--
2.30.0

________________________________
The information transmitted is intended only for the person or entity to which it is addressed and may contain confidential and/or privileged material. Any retransmission, dissemination, copying or other use of, or taking of any action in reliance upon this information is prohibited. If you received this in error, please contact the sender and delete the material from any computer. Nothing contained herein shall be deemed as a representation, warranty or a commitment by Celeno. No warranties are expressed or implied, including, but not limited to, any implied warranties of non-infringement, merchantability and fitness for a particular purpose.
________________________________

2021-06-17 16:25:08

by viktor.barna

[permalink] [raw]
Subject: [RFC v1 055/256] cl8k: add debugfs.c

From: Viktor Barna <[email protected]>

(Part of the split. Please, take a look at the cover letter for more
details).

Signed-off-by: Viktor Barna <[email protected]>
---
drivers/net/wireless/celeno/cl8k/debugfs.c | 957 +++++++++++++++++++++
1 file changed, 957 insertions(+)
create mode 100644 drivers/net/wireless/celeno/cl8k/debugfs.c

diff --git a/drivers/net/wireless/celeno/cl8k/debugfs.c b/drivers/net/wireless/celeno/cl8k/debugfs.c
new file mode 100644
index 000000000000..79854dfd85ea
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/debugfs.c
@@ -0,0 +1,957 @@
+// SPDX-License-Identifier: MIT
+/* Copyright(c) 2019-2021, Celeno Communications Ltd. */
+
+#include <linux/version.h>
+#include <linux/kernel.h>
+#include <linux/kmod.h>
+#include <linux/debugfs.h>
+#include <linux/string.h>
+#include <linux/list.h>
+
+#include "debugfs.h"
+#include "chip.h"
+#include "fw/msg_tx.h"
+#include "fw/msg_cfm.h"
+#include "tx/tx.h"
+#include "rate_ctrl.h"
+#include "utils/utils.h"
+#include "coredump.h"
+#include "fw/fw_dbg.h"
+#include "dbgfile.h"
+
+#define DEBUGFS_ADD_FILE(name, parent, mode) \
+do { \
+ if (!debugfs_create_file(#name, mode, parent, cl_hw, &cl_dbgfs_##name##_ops)) \
+ goto err; \
+} while (0)
+
+/* File operation */
+#define DEBUGFS_READ_FUNC(name) \
+ static ssize_t cl_dbgfs_##name##_read(struct file *file, \
+ char __user *user_buf, \
+ size_t count, loff_t *ppos)
+
+#define DEBUGFS_WRITE_FUNC(name) \
+ static ssize_t cl_dbgfs_##name##_write(struct file *file, \
+ const char __user *user_buf, \
+ size_t count, loff_t *ppos)
+
+#define DEBUGFS_READ_FILE_OPS(name) \
+ DEBUGFS_READ_FUNC(name); \
+ static const struct file_operations cl_dbgfs_##name##_ops = { \
+ .read = cl_dbgfs_##name##_read, \
+ .open = simple_open, \
+ .llseek = generic_file_llseek, \
+ }
+
+#define DEBUGFS_WRITE_FILE_OPS(name) \
+ DEBUGFS_WRITE_FUNC(name); \
+ static const struct file_operations cl_dbgfs_##name##_ops = { \
+ .write = cl_dbgfs_##name##_write, \
+ .open = simple_open, \
+ .llseek = generic_file_llseek, \
+ }
+
+#define DEBUGFS_READ_WRITE_FILE_OPS(name) \
+ DEBUGFS_READ_FUNC(name); \
+ DEBUGFS_WRITE_FUNC(name); \
+ static const struct file_operations cl_dbgfs_##name##_ops = { \
+ .write = cl_dbgfs_##name##_write, \
+ .read = cl_dbgfs_##name##_read, \
+ .open = simple_open, \
+ .llseek = generic_file_llseek, \
+ }
+
+static ssize_t cl_dbgfs_set_debug_write(struct file *file,
+ const char __user *user_buf,
+ size_t count,
+ loff_t *ppos)
+{
+ struct cl_hw *cl_hw = file->private_data;
+ struct cl_tcv_conf *conf = cl_hw->conf;
+ char buf[32];
+ char *usage_str = "Usage:\n"
+ "echo [mod_filter] > set_debug\n";
+ unsigned long long mod_filter;
+ int ret;
+ int eobuf = min_t(size_t, sizeof(buf) - 1, count);
+
+ buf[eobuf] = '\0';
+ if (copy_from_user(&buf, user_buf, eobuf))
+ return -EFAULT;
+
+ ret = kstrtoull(buf, 0, &mod_filter);
+ if (ret) {
+ cl_dbg_verbose(cl_hw, "%s", usage_str);
+ return ret;
+ }
+
+ cl_dbg_verbose(cl_hw, "Send to FW: dbg_module=0x%x, dbg_severity=%u, mod_filter=0x%x\n",
+ conf->ci_fw_dbg_module, conf->ci_fw_dbg_severity, (u32)mod_filter);
+
+ ret = cl_msg_tx_dbg_set_ce_mod_filter(cl_hw, conf->ci_fw_dbg_module);
+ if (ret)
+ return ret;
+
+ ret = cl_msg_tx_dbg_set_sev_filter(cl_hw, conf->ci_fw_dbg_severity);
+ if (ret)
+ return ret;
+
+ ret = cl_msg_tx_dbg_set_mod_filter(cl_hw, mod_filter);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+DEBUGFS_WRITE_FILE_OPS(set_debug);
+
+static ssize_t cl_dbgfs_tx_trace_debug_flag_write(struct file *file,
+ const char __user *user_buf,
+ size_t count,
+ loff_t *ppos)
+{
+ struct cl_hw *cl_hw = file->private_data;
+ char buf[32];
+ int ret;
+ unsigned long long result;
+ u8 read_write_cmd;
+ char *sptr, *token;
+ char *usage_str = "Usage: echo [w\\r] [value] > tx_trace_debug_flag\n";
+ int eobuf = min_t(size_t, sizeof(buf) - 1, count);
+
+ buf[eobuf] = '\0';
+ if (copy_from_user(&buf, user_buf, eobuf)) {
+ cl_dbg_err(cl_hw, "illegal input\n %s", usage_str);
+ return -EFAULT;
+ }
+ sptr = buf;
+ token = strsep(&sptr, " ");
+ if (!token) {
+ cl_dbg_err(cl_hw, "illegal input\n %s", usage_str);
+ return -EINVAL;
+ }
+
+ if (!strncasecmp(token, "w", strlen("w"))) {
+ read_write_cmd = 1;
+ ret = kstrtoull(sptr, 0, &result);
+ if (ret) {
+ cl_dbg_err(cl_hw, "illegal input\n %s", usage_str);
+ return ret;
+ }
+ cl_dbg_trace(cl_hw, "(write value=0x%x)\n", (u32)result);
+ } else if (!strncasecmp(token, "r", strlen("r"))) {
+ read_write_cmd = 0;
+ result = 0;
+ cl_dbg_trace(cl_hw, "(read)\n");
+ } else {
+ cl_dbg_err(cl_hw, "illegal input\n %s", usage_str);
+ return -EFAULT;
+ }
+
+ ret = cl_msg_tx_dbg_tx_trace_debug_flag(cl_hw, (u32)result, (u8)read_write_cmd);
+
+ return count;
+}
+
+DEBUGFS_WRITE_FILE_OPS(tx_trace_debug_flag);
+
+static ssize_t cl_dbgfs_test_mode_write(struct file *file,
+ const char __user *user_buf,
+ size_t count,
+ loff_t *ppos)
+{
+ struct cl_hw *cl_hw = file->private_data;
+ char buf[32];
+ int ret;
+ unsigned long long params[TEST_MODE_PARAM_MAX + 1] = {0};
+ u32 test_params[TEST_MODE_PARAM_MAX + 1] = {0};
+ char *usage_str = "Usage:\n"
+ "debugfsh <chip> <tcv> test_mode <command> <params> <params> ..\n";
+ char *token, *sptr;
+ int eobuf = min_t(size_t, sizeof(buf) - 1, count);
+ int i = 0;
+
+ buf[eobuf] = '\0';
+ if (copy_from_user(&buf, user_buf, eobuf)) {
+ cl_dbg_err(cl_hw, "string %s count %zu eobuf %d\n", buf, count, eobuf);
+ return -EFAULT;
+ }
+ sptr = buf;
+ token = strsep(&sptr, " ");
+
+ for (i = 0; i < TEST_MODE_PARAM_MAX + 1; i++) {
+ if (token) {
+ ret = kstrtoull(token, 0, &params[i]);
+ if (ret) {
+ cl_dbg_trace(cl_hw, "Token %s illegal convert %s\n",
+ token, usage_str);
+ return ret;
+ }
+ test_params[i] = (u32)params[i];
+ cl_dbg_trace(cl_hw, "param[%d]=%llu\n", i, params[i]);
+ } else {
+ break;
+ }
+ token = strsep(&sptr, " ");
+ }
+
+ ret = cl_msg_tx_dbg_test_mode(cl_hw, test_params);
+
+ return count;
+}
+
+DEBUGFS_WRITE_FILE_OPS(test_mode);
+
+static ssize_t cl_dbgfs_fixed_rate_write(struct file *file,
+ const char __user *user_buf,
+ size_t count,
+ loff_t *ppos)
+{
+ struct cl_hw *cl_hw = file->private_data;
+ char buf[32];
+ int ret;
+ unsigned long long mcs = 0, bw = 0, gi = 0, format = 0, ltf_field = 0,
+ pre_type_or_stbc = 0, sta_idx = 0xff;
+ char *sptr, *token1, *token2, *token3, *token4, *token5, *token6, *token7;
+ char *usage_str = "Usage:\n"
+ "echo [mcs] [bw] [gi] [format] [ltf_field] [pre_type_or_stbc(opt)] "
+ "[sta_idx(opt)] > fixed_rate\n";
+ u8 op_mode = RATE_OP_MODE_FIXED;
+ int eobuf = min_t(size_t, sizeof(buf) - 1, count);
+ union cl_rate_ctrl_info rate_ctrl;
+ union cl_rate_ctrl_info_he rate_ctrl_he;
+
+ buf[eobuf] = '\0';
+ if (copy_from_user(&buf, user_buf, eobuf)) {
+ cl_dbg_err(cl_hw, "illegal input\n %s", usage_str);
+ return -EFAULT;
+ }
+
+ sptr = buf;
+
+ /* Token1 - mcs */
+ token1 = strsep(&sptr, " ");
+ if (!token1) {
+ cl_dbg_err(cl_hw, "token1 illegal %s\n", usage_str);
+ return -EINVAL;
+ }
+
+ ret = kstrtoull(token1, 0, &mcs);
+ if (ret) {
+ cl_dbg_err(cl_hw, "token1 %s illegal convert %s\n", token1, usage_str);
+ return ret;
+ }
+
+ /* Token2 - bw */
+ token2 = strsep(&sptr, " ");
+ if (!token2) {
+ cl_dbg_err(cl_hw, "token2 illegal %s\n", usage_str);
+ return -EINVAL;
+ }
+
+ ret = kstrtoull(token2, 0, &bw);
+ if (ret) {
+ cl_dbg_err(cl_hw, "token2 %s illegal convert %s\n", token2, usage_str);
+ return ret;
+ }
+
+ /* Token3 - gi */
+ token3 = strsep(&sptr, " ");
+ if (!token3) {
+ cl_dbg_err(cl_hw, "token3 illegal %s\n", usage_str);
+ return -EINVAL;
+ }
+
+ ret = kstrtoull(token3, 0, &gi);
+ if (ret) {
+ cl_dbg_err(cl_hw, "token3 %s illegal convert %s\n", token3, usage_str);
+ return ret;
+ }
+
+ /* Token4 - format */
+ token4 = strsep(&sptr, " ");
+ if (!token4) {
+ cl_dbg_err(cl_hw, "token4 illegal %s\n", usage_str);
+ return -EINVAL;
+ }
+
+ ret = kstrtoull(token4, 0, &format);
+ if (ret) {
+ cl_dbg_err(cl_hw, "token4 %s illegal convert %s\n", token4, usage_str);
+ return ret;
+ }
+
+ /* Token5 - ltf_field */
+ token5 = strsep(&sptr, " ");
+ if (!token5) {
+ cl_dbg_err(cl_hw, "token5 illegal %s\n", usage_str);
+ return -EINVAL;
+ }
+
+ ret = kstrtoull(token5, 0, &ltf_field);
+ if (ret) {
+ cl_dbg_err(cl_hw, "token5 %s illegal convert %s\n", token5, usage_str);
+ return ret;
+ }
+
+ /* Token6 - pre_type_or_stbc (optional) */
+ token6 = strsep(&sptr, " ");
+ if (token6) {
+ ret = kstrtoull(token6, 0, &pre_type_or_stbc);
+ if (ret) {
+ cl_dbg_err(cl_hw, "token6 %s illegal convert %s\n", token6, usage_str);
+ return ret;
+ }
+ }
+
+ /* Token7 - sta_idx (optional) */
+ token7 = strsep(&sptr, " ");
+ if (token7) {
+ ret = kstrtoull(token7, 0, &sta_idx);
+ if (ret) {
+ cl_dbg_err(cl_hw, "token7 %s illegal convert %s\n", token7, usage_str);
+ return ret;
+ }
+ }
+
+ /* Sanity tests */
+ if (sta_idx != STA_IDX_INVALID && !cl_sta_is_assoc(cl_hw, sta_idx)) {
+ cl_dbg_err(cl_hw, "Invalid station index [%llu]\n", sta_idx);
+ return -EINVAL;
+ }
+
+ if (format > FORMATMOD_HE_SU) {
+ cl_dbg_err(cl_hw, "Invalid format [%llu]\n", format);
+ return -EINVAL;
+ }
+
+ if (format < FORMATMOD_HE_SU)
+ ltf_field = 0;
+
+ /* Build rate_ctrl and rate_ctrl_he */
+ if (mcs == 0xff || bw == 0xff || gi == 0xff || format == 0xff) {
+ cl_hw->entry_fixed_rate = false;
+ cl_dbg_trace(cl_hw, "Fixed rate turned off\n");
+ } else {
+ rate_ctrl.word = 0;
+ rate_ctrl.field.mcs_index = mcs;
+ rate_ctrl.field.bw = bw;
+ rate_ctrl.field.gi = gi;
+ rate_ctrl.field.format_mod = format;
+
+ if (rate_ctrl.field.format_mod != FORMATMOD_NON_HT)
+ rate_ctrl.field.pre_type_or_stbc = pre_type_or_stbc;
+
+ /* rate_ctrl_he is relevant only for HE format mode. */
+ if (format > FORMATMOD_VHT)
+ rate_ctrl_he.field.spatial_conf = RATE_CNTRL_HE_SPATIAL_CONF_DEF;
+ else
+ rate_ctrl_he.word = 0;
+
+ cl_dbg_trace(cl_hw, "mcs=%llu bw=%llu gi=%llu format=%llu --> rate_ctrl 0x%x\n",
+ mcs, bw, gi, format, rate_ctrl.word);
+
+ /* Set entry_fixed_rate to true only if there is no specific station */
+ cl_hw->entry_fixed_rate = (sta_idx == 0xff);
+
+ if (!cl_rate_ctrl_set_dbgfs(cl_hw, sta_idx, rate_ctrl.word, rate_ctrl_he.word,
+ op_mode, bw, ltf_field))
+ return -EFAULT;
+ }
+
+ return count;
+}
+
+DEBUGFS_WRITE_FILE_OPS(fixed_rate);
+
+static ssize_t cl_dbgfs_mactrace_read(struct file *file,
+ char __user *user_buf,
+ size_t count,
+ loff_t *ppos)
+{
+ struct cl_hw *cl_hw = file->private_data;
+ ssize_t read;
+
+ mutex_lock(&cl_hw->dbginfo.mutex);
+ if (cl_hw->debugfs.trace_prst) {
+ read = simple_read_from_buffer(user_buf, count, ppos,
+ &cl_hw->dbginfo.buf->u.dump.la_mem[0],
+ ARRAY_SIZE(cl_hw->dbginfo.buf->u.dump.la_mem[0]));
+ } else {
+ pr_debug("No dump!\n");
+ read = 0;
+ }
+ mutex_unlock(&cl_hw->dbginfo.mutex);
+
+ return read;
+}
+
+static ssize_t cl_dbgfs_mactrace_write(struct file *file,
+ const char __user *user_buf,
+ size_t count,
+ loff_t *ppos)
+{
+ /* Write "1" to diags/mactrace triggers dump, type 0 (recoverable). */
+ struct cl_hw *cl_hw = file->private_data;
+ char buf[32];
+ unsigned long v;
+ int eobuf = min_t(size_t, sizeof(buf) - 1, count);
+
+ if (cl_hw->debugfs.unregistering)
+ return -EFAULT;
+
+ if (copy_from_user(&buf, user_buf, eobuf))
+ return -EFAULT;
+
+ buf[eobuf] = '\0';
+ if (kstrtoul(buf, 0, &v) || v != 1) {
+ pr_debug("Usage: echo 1 > mactrace : trigger firmware dump\n");
+ return -EFAULT;
+ }
+
+ mutex_lock(&cl_hw->dbginfo.mutex);
+ if (cl_hw->debugfs.trace_prst) {
+ pr_debug("Dump already waiting\n");
+ mutex_unlock(&cl_hw->dbginfo.mutex);
+ return -EFAULT;
+ }
+
+ scnprintf(buf, sizeof(buf), "Force trigger\n");
+ cl_msg_tx_dbg_trigger(cl_hw, buf);
+ mutex_unlock(&cl_hw->dbginfo.mutex);
+
+ return count;
+}
+
+DEBUGFS_READ_WRITE_FILE_OPS(mactrace);
+
+static ssize_t cl_dbgfs_phytrace_read(struct file *file,
+ char __user *user_buf,
+ size_t count,
+ loff_t *ppos)
+{
+#if LA_CNT < 2
+ return -EFAULT; /* La_mem[1] does not exist */
+#else
+ struct cl_hw *cl_hw = file->private_data;
+ ssize_t read;
+
+ mutex_lock(&cl_hw->dbginfo.mutex);
+ if (!cl_hw->debugfs.trace_prst) {
+ mutex_unlock(&cl_hw->dbginfo.mutex);
+ return 0;
+ }
+
+ read = simple_read_from_buffer(user_buf, count, ppos,
+ &cl_hw->dbginfo.buf->u.dump.la_mem[1],
+ ARRAY_SIZE(cl_hw->dbginfo.buf->u.dump.la_mem[1]));
+ mutex_unlock(&cl_hw->dbginfo.mutex);
+ return read;
+#endif
+}
+
+DEBUGFS_READ_FILE_OPS(phytrace);
+
+static ssize_t cl_dbgfs_macdiags_read(struct file *file,
+ char __user *user_buf,
+ size_t count,
+ loff_t *ppos)
+{
+ struct cl_hw *cl_hw = file->private_data;
+ ssize_t read;
+
+ mutex_lock(&cl_hw->dbginfo.mutex);
+ if (!cl_hw->debugfs.trace_prst) {
+ mutex_unlock(&cl_hw->dbginfo.mutex);
+ return 0;
+ }
+
+ read = simple_read_from_buffer(user_buf, count, ppos,
+ cl_hw->dbginfo.buf->u.dump.general_data.diags_mac,
+ DBG_DIAGS_MAC_MAX * 2); // FIXME: Why * 2?? BUG?
+ mutex_unlock(&cl_hw->dbginfo.mutex);
+
+ return read;
+}
+
+DEBUGFS_READ_FILE_OPS(macdiags);
+
+static ssize_t cl_dbgfs_hwdiags_read(struct file *file,
+ char __user *user_buf,
+ size_t count,
+ loff_t *ppos)
+{
+ struct cl_hw *cl_hw = file->private_data;
+ char buf[16];
+ int ret;
+
+ mutex_lock(&cl_hw->dbginfo.mutex);
+ if (!cl_hw->debugfs.trace_prst) {
+ mutex_unlock(&cl_hw->dbginfo.mutex);
+ return 0;
+ }
+
+ ret = scnprintf(buf, min_t(size_t, sizeof(buf) - 1, count),
+ "%08X\n", cl_hw->dbginfo.buf->u.dump.general_data.hw_diag);
+
+ mutex_unlock(&cl_hw->dbginfo.mutex);
+ return simple_read_from_buffer(user_buf, count, ppos, buf, ret);
+}
+
+DEBUGFS_READ_FILE_OPS(hwdiags);
+
+static ssize_t cl_dbgfs_swdiags_read(struct file *file,
+ char __user *user_buf,
+ size_t count,
+ loff_t *ppos)
+{
+ struct cl_hw *cl_hw = file->private_data;
+ ssize_t read;
+
+ mutex_lock(&cl_hw->dbginfo.mutex);
+ if (!cl_hw->debugfs.trace_prst) {
+ mutex_unlock(&cl_hw->dbginfo.mutex);
+ return 0;
+ }
+
+ read = simple_read_from_buffer(user_buf, count, ppos,
+ &cl_hw->dbginfo.buf->u.dump.general_data.sw_diag,
+ cl_hw->dbginfo.buf->u.dump.general_data.sw_diag_len);
+
+ mutex_unlock(&cl_hw->dbginfo.mutex);
+ return read;
+}
+
+DEBUGFS_READ_FILE_OPS(swdiags);
+
+static ssize_t cl_dbgfs_lamacconf_read(struct file *file,
+ char __user *user_buf,
+ size_t count,
+ loff_t *ppos)
+{
+ struct cl_hw *cl_hw = file->private_data;
+ ssize_t read;
+
+ mutex_lock(&cl_hw->dbginfo.mutex);
+ if (!cl_hw->debugfs.trace_prst) {
+ mutex_unlock(&cl_hw->dbginfo.mutex);
+ return 0;
+ }
+
+ read = simple_read_from_buffer(user_buf, count, ppos,
+ &cl_hw->dbginfo.buf->u.dump.general_data.la_conf[0],
+ sizeof(struct la_conf_tag));
+
+ mutex_unlock(&cl_hw->dbginfo.mutex);
+ return read;
+}
+
+DEBUGFS_READ_FILE_OPS(lamacconf);
+
+static ssize_t cl_dbgfs_laphyconf_read(struct file *file,
+ char __user *user_buf,
+ size_t count,
+ loff_t *ppos)
+{
+ struct cl_hw *cl_hw = file->private_data;
+ ssize_t read;
+
+ mutex_lock(&cl_hw->dbginfo.mutex);
+ if (!cl_hw->debugfs.trace_prst) {
+ mutex_unlock(&cl_hw->dbginfo.mutex);
+ return 0;
+ }
+
+ read = simple_read_from_buffer(user_buf, count, ppos,
+ &cl_hw->dbginfo.buf->u.dump.general_data.la_conf[1],
+ sizeof(struct la_conf_tag));
+
+ mutex_unlock(&cl_hw->dbginfo.mutex);
+ return read;
+}
+
+DEBUGFS_READ_FILE_OPS(laphyconf);
+
+static ssize_t cl_dbgfs_chaninfo_read(struct file *file,
+ char __user *user_buf,
+ size_t count,
+ loff_t *ppos)
+{
+ struct cl_hw *cl_hw = file->private_data;
+ struct phy_channel_info *chan_info = &cl_hw->dbginfo.buf->u.dump.general_data.chan_info;
+ char buf[4 * 32];
+ int ret;
+
+ mutex_lock(&cl_hw->dbginfo.mutex);
+ if (!cl_hw->debugfs.trace_prst) {
+ mutex_unlock(&cl_hw->dbginfo.mutex);
+ return 0;
+ }
+
+ ret = scnprintf(buf, min_t(size_t, sizeof(buf) - 1, count),
+ "type: %u\n"
+ "prim20_freq: %u MHz\n"
+ "center1_freq: %u MHz\n"
+ "center2_freq: %u MHz\n",
+ (chan_info->info1 >> 8) & 0xFF,
+ (chan_info->info1 >> 16) & 0xFFFF,
+ (chan_info->info2 >> 0) & 0xFFFF,
+ (chan_info->info2 >> 16) & 0xFFFF);
+
+ mutex_unlock(&cl_hw->dbginfo.mutex);
+ return simple_read_from_buffer(user_buf, count, ppos, buf, ret);
+}
+
+DEBUGFS_READ_FILE_OPS(chaninfo);
+
+#define MAX_BUF_SIZE 512
+
+static ssize_t cl_dbgfs_error_read(struct file *file,
+ char __user *user_buf,
+ size_t count,
+ loff_t *ppos)
+{
+ struct cl_hw *cl_hw = file->private_data;
+ struct dbg_print_ind *ind =
+ &cl_hw->dbginfo.buf->u.dump.fw_dump.common_info.error_info;
+ ssize_t read;
+
+ mutex_lock(&cl_hw->dbginfo.mutex);
+ if (!cl_hw->debugfs.trace_prst) {
+ mutex_unlock(&cl_hw->dbginfo.mutex);
+ return 0;
+ }
+
+ /* If an assert message, search for assert string */
+ if (ind->file_id && ind->line) {
+ u16 file_id = le16_to_cpu(ind->file_id);
+ u16 line = le16_to_cpu(ind->line);
+ const char *assert_string = cl_dbgfile_get_msg_txt(&cl_hw->dbg_data, file_id, line);
+
+ /* If string not found. use FW error string. */
+ if (!assert_string)
+ assert_string = cl_hw->dbginfo.buf->u.dump.general_data.error;
+
+ read = simple_read_from_buffer(user_buf, count, ppos, assert_string,
+ strnlen(assert_string, MAX_BUF_SIZE));
+ } else {
+ char *error = cl_hw->dbginfo.buf->u.dump.general_data.error;
+
+ read = simple_read_from_buffer(user_buf, count, ppos, error,
+ strnlen(error, DBG_ERROR_TRACE_SIZE));
+ }
+
+ mutex_unlock(&cl_hw->dbginfo.mutex);
+ return read;
+}
+
+DEBUGFS_READ_FILE_OPS(error);
+
+static ssize_t cl_dbgfs_mpifmask_write(struct file *file,
+ const char __user *user_buf,
+ size_t count,
+ loff_t *ppos)
+{
+ struct cl_hw *cl_hw = file->private_data;
+ char buf[32];
+ int ret;
+ int eobuf = min_t(size_t, sizeof(buf) - 1, count);
+ unsigned long long result;
+
+ buf[eobuf] = '\0';
+ if (copy_from_user(&buf, user_buf, eobuf))
+ return -EFAULT;
+
+ ret = kstrtoull(buf, 0, &result);
+ if (ret)
+ return ret;
+
+ cl_dbg_trace(cl_hw, "Set LA mpif mask = 0x%08x\n", (u32)result);
+
+ cl_msg_tx_dbg_set_la_mpif_mask(cl_hw, result);
+
+ return count;
+}
+
+DEBUGFS_WRITE_FILE_OPS(mpifmask);
+
+static ssize_t cl_dbgfs_trigpoint_write(struct file *file,
+ const char __user *user_buf,
+ size_t count,
+ loff_t *ppos)
+{
+ struct cl_hw *cl_hw = file->private_data;
+ char buf[32];
+ int ret;
+ int eobuf = min_t(size_t, sizeof(buf) - 1, count);
+ unsigned long long result;
+
+ buf[eobuf] = '\0';
+ if (copy_from_user(&buf, user_buf, eobuf))
+ return -EFAULT;
+
+ ret = kstrtoull(buf, 0, &result);
+ if (ret)
+ return ret;
+
+ cl_dbg_trace(cl_hw, "Set LA trigger point = 0x%x\n", (u32)result);
+
+ cl_msg_tx_dbg_set_la_trig_point(cl_hw, result);
+
+ return count;
+}
+
+DEBUGFS_WRITE_FILE_OPS(trigpoint);
+
+enum {
+ CL_LA_MPIF_DEBUG_MODE_GEN, /* Generic MPIF sampling mask */
+ CL_LA_MPIF_DEBUG_MODE_TX, /* Tx oriented MPIF sampling mask */
+ CL_LA_MPIF_DEBUG_MODE_RX, /* Rx oriented MPIF sampling mask */
+
+ CL_LA_MPIF_DEBUG_MODE_NUM
+};
+
+const char *ce_la_mpif_debug_mode_str[CL_LA_MPIF_DEBUG_MODE_NUM] = {
+ [CL_LA_MPIF_DEBUG_MODE_GEN] = "LA_MPIF_DEBUG_MODE_GEN",
+ [CL_LA_MPIF_DEBUG_MODE_TX] = "LA_MPIF_DEBUG_MODE_TX",
+ [CL_LA_MPIF_DEBUG_MODE_RX] = "LA_MPIF_DEBUG_MODE_RX"
+};
+
+static ssize_t cl_dbgfs_mpif_debug_mode_write(struct file *file,
+ const char __user *user_buf,
+ size_t count,
+ loff_t *ppos)
+{
+ struct cl_hw *cl_hw = file->private_data;
+ char buf[32];
+ int ret;
+ int eobuf = min_t(size_t, sizeof(buf) - 1, count);
+ unsigned long long result;
+ u8 mode;
+
+ buf[eobuf] = '\0';
+ if (copy_from_user(&buf, user_buf, eobuf))
+ return -EFAULT;
+
+ ret = kstrtoull(buf, 0, &result);
+ if (ret)
+ return ret;
+
+ mode = (u8)result;
+ if (mode >= CL_LA_MPIF_DEBUG_MODE_NUM)
+ return -EINVAL;
+
+ cl_dbg_trace(cl_hw, "Set LA MPIF mode = %u (%s)\n", mode, ce_la_mpif_debug_mode_str[mode]);
+
+ cl_msg_tx_dbg_set_la_mpif_debug_mode(cl_hw, result);
+
+ return count;
+}
+
+DEBUGFS_WRITE_FILE_OPS(mpif_debug_mode);
+
+char *la_trig_oper_str[LA_TRIG_OPER_MAX] = {
+ [LA_TRIG_OPER_EQ] = "eq",
+ [LA_TRIG_OPER_NOT_EQ] = "neq",
+ [LA_TRIG_OPER_GT] = "gt",
+ [LA_TRIG_OPER_GT_EQ] = "gte",
+ [LA_TRIG_OPER_LT] = "lt",
+ [LA_TRIG_OPER_LT_EQ] = "lte"
+};
+
+static ssize_t cl_dbgfs_trig_rule_write(struct file *file,
+ const char __user *user_buf,
+ size_t count,
+ loff_t *ppos)
+{
+ struct cl_hw *cl_hw = file->private_data;
+ char buf[100];
+ int ret = 0;
+ int eobuf = min_t(size_t, sizeof(buf) - 1, count);
+ char *sptr = NULL, *token = NULL;
+ unsigned long val;
+ u32 address = 0, value = 0, mask = 0, duration = 0;
+ u8 idx = 0, oper = 0;
+ bool enable = false;
+ char *usage_str = "Usage:\n"
+ "echo <rule-idx> <enable {1|0}> <address> <oper {eq|neq|gt|gte|lt|lte}>"
+ " <value> <mask> [duration] > trig_rule\n";
+
+ buf[eobuf] = '\0';
+ if (copy_from_user(&buf, user_buf, eobuf))
+ return -EFAULT;
+
+ sptr = buf;
+
+ token = strsep(&sptr, " ");
+ if (!token) {
+ pr_err("Illegal token.\n%s", usage_str);
+ return -EINVAL;
+ }
+
+ ret = kstrtoul(token, 0, &val);
+ if (ret) {
+ pr_err("<rule-idx> illegal value (%s)\n%s", token, usage_str);
+ return -EINVAL;
+ }
+
+ idx = (u8)val;
+
+ token = strsep(&sptr, " ");
+ if (!token) {
+ pr_err("Illegal token.\n%s", usage_str);
+ return -EINVAL;
+ }
+
+ ret = kstrtoul(token, 0, &val);
+ if (ret) {
+ pr_err("<enable> illegal value (%s)\n%s", token, usage_str);
+ return -EINVAL;
+ }
+
+ enable = (bool)val;
+
+ if (enable) {
+ /* Address token */
+ token = strsep(&sptr, " ");
+ if (!token) {
+ pr_err("Illegal token.\n%s", usage_str);
+ return -EINVAL;
+ }
+
+ ret = kstrtoul(token, 0, &val);
+ if (ret) {
+ pr_err("<address> illegal value (%s)\n%s", token, usage_str);
+ return -EINVAL;
+ }
+
+ address = val;
+
+ /* Comparison Operator token */
+ token = strsep(&sptr, " ");
+ if (!token) {
+ pr_err("Illegal token.\n%s", usage_str);
+ return -EINVAL;
+ }
+
+ for (oper = LA_TRIG_OPER_EQ; oper < LA_TRIG_OPER_MAX; ++oper)
+ if (!strcmp(token, la_trig_oper_str[oper]))
+ break;
+
+ if (oper == LA_TRIG_OPER_MAX) {
+ pr_err("<oper> illegal value (%s)\n%s", token, usage_str);
+ return -EINVAL;
+ }
+
+ /* Value token */
+ token = strsep(&sptr, " ");
+ if (!token) {
+ pr_err("Illegal token.\n%s", usage_str);
+ return -EINVAL;
+ }
+
+ ret = kstrtoul(token, 0, &val);
+ if (ret) {
+ pr_err("<value> illegal value (%s)\n%s", token, usage_str);
+ return -EINVAL;
+ }
+
+ value = val;
+
+ /* Mask token */
+ token = strsep(&sptr, " ");
+ if (!token) {
+ pr_err("Illegal token.\n%s", usage_str);
+ return -EINVAL;
+ }
+
+ ret = kstrtoul(token, 0, &val);
+ if (ret) {
+ pr_err("<mask> illegal value (%s)\n%s", token, usage_str);
+ return -EINVAL;
+ }
+
+ mask = val;
+
+ /* Duration token (optional) */
+ token = strsep(&sptr, " ");
+ if (token) {
+ ret = kstrtoul(token, 0, &val);
+ if (ret) {
+ pr_err("<duration> illegal value (%s)\n%s", token, usage_str);
+ return -EINVAL;
+ }
+
+ duration = val;
+ }
+ }
+
+ if (enable)
+ pr_debug("Set trigger rule: idx=%u, addr=0x%08x, oper=%s, value=0x%08x, "
+ "mask=0x%08x, duration=%u\n",
+ idx, address, la_trig_oper_str[oper], value, mask, duration);
+ else
+ pr_debug("Disable trigger rule: idx=%u\n", idx);
+
+ if (cl_msg_tx_dbg_set_la_trig_rule(cl_hw, idx, enable, address, oper,
+ value, mask, duration))
+ return -EFAULT;
+
+ return count;
+}
+
+DEBUGFS_WRITE_FILE_OPS(trig_rule);
+
+int cl_dbgfs_register(struct cl_hw *cl_hw, const char *name)
+{
+ struct dentry *phyd = cl_hw->hw->wiphy->debugfsdir;
+ struct dentry *dir_drv, *dir_diags, *dir_cl;
+
+ cl_dbg_trace(cl_hw, "/sys/kernel/debug/%s/%s/%s.\n",
+ phyd->d_parent->d_name.name, phyd->d_name.name, name);
+
+ dir_drv = debugfs_create_dir(name, phyd);
+ if (!dir_drv)
+ return -ENOMEM;
+
+ dir_diags = debugfs_create_dir("diags", dir_drv);
+ if (!dir_diags)
+ goto err;
+
+ dir_cl = debugfs_create_dir("cl8k", dir_drv);
+ if (!dir_cl) {
+ cl_dbg_err(cl_hw, "%s\n", name);
+ goto err;
+ }
+
+ cl_coredump_init(cl_hw, dir_drv);
+
+ DEBUGFS_ADD_FILE(mactrace, dir_diags, 0400);
+ DEBUGFS_ADD_FILE(phytrace, dir_diags, 0400);
+ DEBUGFS_ADD_FILE(macdiags, dir_diags, 0400);
+ DEBUGFS_ADD_FILE(hwdiags, dir_diags, 0400);
+ DEBUGFS_ADD_FILE(swdiags, dir_diags, 0400);
+ DEBUGFS_ADD_FILE(error, dir_diags, 0400);
+ DEBUGFS_ADD_FILE(lamacconf, dir_diags, 0400);
+ DEBUGFS_ADD_FILE(laphyconf, dir_diags, 0400);
+ DEBUGFS_ADD_FILE(chaninfo, dir_diags, 0400);
+ DEBUGFS_ADD_FILE(trigpoint, dir_diags, 0200);
+ DEBUGFS_ADD_FILE(mpifmask, dir_diags, 0200);
+ DEBUGFS_ADD_FILE(mpif_debug_mode, dir_diags, 0200);
+ DEBUGFS_ADD_FILE(set_debug, dir_cl, 0200);
+ DEBUGFS_ADD_FILE(test_mode, dir_cl, 0200);
+ DEBUGFS_ADD_FILE(fixed_rate, dir_cl, 0200);
+ DEBUGFS_ADD_FILE(tx_trace_debug_flag, dir_cl, 0200);
+ DEBUGFS_ADD_FILE(trig_rule, dir_cl, 0200);
+ return 0;
+
+err:
+ cl_dbgfs_unregister(cl_hw);
+ return -ENOMEM;
+}
+
+void cl_dbgfs_unregister(struct cl_hw *cl_hw)
+{
+ cl_coredump_close(cl_hw);
+}
--
2.30.0

________________________________
The information transmitted is intended only for the person or entity to which it is addressed and may contain confidential and/or privileged material. Any retransmission, dissemination, copying or other use of, or taking of any action in reliance upon this information is prohibited. If you received this in error, please contact the sender and delete the material from any computer. Nothing contained herein shall be deemed as a representation, warranty or a commitment by Celeno. No warranties are expressed or implied, including, but not limited to, any implied warranties of non-infringement, merchantability and fitness for a particular purpose.
________________________________

2021-06-17 16:25:16

by viktor.barna

[permalink] [raw]
Subject: [RFC v1 033/256] cl8k: add cca.h

From: Viktor Barna <[email protected]>

(Part of the split. Please, take a look at the cover letter for more
details).

Signed-off-by: Viktor Barna <[email protected]>
---
drivers/net/wireless/celeno/cl8k/cca.h | 30 ++++++++++++++++++++++++++
1 file changed, 30 insertions(+)
create mode 100644 drivers/net/wireless/celeno/cl8k/cca.h

diff --git a/drivers/net/wireless/celeno/cl8k/cca.h b/drivers/net/wireless/celeno/cl8k/cca.h
new file mode 100644
index 000000000000..ceb2c4251d9a
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/cca.h
@@ -0,0 +1,30 @@
+/* SPDX-License-Identifier: MIT */
+/* Copyright(c) 2019-2021, Celeno Communications Ltd. */
+
+#ifndef CL_CCA_H
+#define CL_CCA_H
+
+/**
+ * CCA (=Clear Channel Assessment)
+ */
+
+struct cl_hw;
+struct cli_params;
+
+enum cl_cca_opt {
+ CCA_OPT_CNT_CS = 0x1,
+ CCA_OPT_CNT_MDM_STATE = 0x2,
+ CCA_OPT_CNT_MP = 0x4,
+ CCA_OPT_CNT_ENERGY = 0x8,
+ CCA_OPT_CNT_ENERGY_BAND = 0x10,
+ CCA_OPT_UTIL = 0x20,
+ CCA_OPT_TX_RX_MINE = 0x40,
+ CCA_OPT_EDCA = 0x80,
+ CCA_OPT_EDCA_NAV = 0x100,
+ CCA_OPT_REC_HIST = 0x200
+};
+
+void cl_cca_maintenance(struct cl_hw *cl_hw);
+int cl_cca_cli(struct cl_hw *cl_hw, struct cli_params *cli_params);
+
+#endif /* CL_CCA_H */
--
2.30.0

________________________________
The information transmitted is intended only for the person or entity to which it is addressed and may contain confidential and/or privileged material. Any retransmission, dissemination, copying or other use of, or taking of any action in reliance upon this information is prohibited. If you received this in error, please contact the sender and delete the material from any computer. Nothing contained herein shall be deemed as a representation, warranty or a commitment by Celeno. No warranties are expressed or implied, including, but not limited to, any implied warranties of non-infringement, merchantability and fitness for a particular purpose.
________________________________

2021-06-17 16:25:24

by viktor.barna

[permalink] [raw]
Subject: [RFC v1 054/256] cl8k: add debug.h

From: Viktor Barna <[email protected]>

(Part of the split. Please, take a look at the cover letter for more
details).

Signed-off-by: Viktor Barna <[email protected]>
---
drivers/net/wireless/celeno/cl8k/debug.h | 121 +++++++++++++++++++++++
1 file changed, 121 insertions(+)
create mode 100644 drivers/net/wireless/celeno/cl8k/debug.h

diff --git a/drivers/net/wireless/celeno/cl8k/debug.h b/drivers/net/wireless/celeno/cl8k/debug.h
new file mode 100644
index 000000000000..f51591755051
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/debug.h
@@ -0,0 +1,121 @@
+/* SPDX-License-Identifier: MIT */
+/* Copyright(c) 2019-2021, Celeno Communications Ltd. */
+
+#ifndef CL_DEBUG_H
+#define CL_DEBUG_H
+
+#include <linux/string.h>
+
+enum cl_dbg_level {
+ DBG_LVL_VERBOSE,
+ DBG_LVL_ERROR,
+ DBG_LVL_WARNING,
+ DBG_LVL_TRACE,
+ DBG_LVL_INFO,
+
+ DBG_LVL_MAX,
+};
+
+#define CL_DBG(cl_hw, lvl, fmt, ...) \
+do { \
+ if ((lvl) <= (cl_hw)->conf->ce_debug_level) \
+ pr_debug("[tcv%u][%s][%d] " fmt, (cl_hw)->idx, __func__, __LINE__, ##__VA_ARGS__); \
+} while (0)
+
+#define CL_DBG_CHIP(chip, lvl, fmt, ...) \
+do { \
+ if ((lvl) <= (chip)->conf->ce_debug_level) \
+ pr_debug("[chip%u][%s][%d] " fmt, (chip)->idx, __func__, __LINE__, ##__VA_ARGS__); \
+} while (0)
+
+#define cl_dbg_verbose(cl_hw, ...) CL_DBG((cl_hw), DBG_LVL_VERBOSE, ##__VA_ARGS__)
+#define cl_dbg_err(cl_hw, ...) CL_DBG((cl_hw), DBG_LVL_ERROR, ##__VA_ARGS__)
+#define cl_dbg_warn(cl_hw, ...) CL_DBG((cl_hw), DBG_LVL_WARNING, ##__VA_ARGS__)
+#define cl_dbg_trace(cl_hw, ...) CL_DBG((cl_hw), DBG_LVL_TRACE, ##__VA_ARGS__)
+#define cl_dbg_info(cl_hw, ...) CL_DBG((cl_hw), DBG_LVL_INFO, ##__VA_ARGS__)
+
+#define cl_dbg_chip_verbose(chip, ...) CL_DBG_CHIP((chip), DBG_LVL_VERBOSE, ##__VA_ARGS__)
+#define cl_dbg_chip_err(chip, ...) CL_DBG_CHIP((chip), DBG_LVL_ERROR, ##__VA_ARGS__)
+#define cl_dbg_chip_warn(chip, ...) CL_DBG_CHIP((chip), DBG_LVL_WARNING, ##__VA_ARGS__)
+#define cl_dbg_chip_trace(chip, ...) CL_DBG_CHIP((chip), DBG_LVL_TRACE, ##__VA_ARGS__)
+#define cl_dbg_chip_info(chip, ...) CL_DBG_CHIP((chip), DBG_LVL_INFO, ##__VA_ARGS__)
+
+static inline char *basename(const char *filename)
+{
+ char *p = strrchr(filename, '/');
+
+ return p ? p + 1 : (char *)filename;
+}
+
+#define TXT_ERROR \
+ do { \
+ pr_debug("\n"); \
+ pr_debug("####### ##### ##### ##### #####\n"); \
+ pr_debug("# # # # # # # # #\n"); \
+ pr_debug("# # # # # # # # #\n"); \
+ pr_debug("####### ##### ##### # # #####\n"); \
+ pr_debug("# # # # # # # # #\n"); \
+ pr_debug("# # # # # # # # #\n"); \
+ pr_debug("####### # # # # ##### # #\n"); \
+ } while (0)
+
+#define TXT_WARNING \
+ do { \
+ pr_debug("\n"); \
+ pr_debug("# # ##### ##### # # ### # # #####\n"); \
+ pr_debug("# # # # # # ## # # ## # # #\n"); \
+ pr_debug("# # # # # # # # # # # # # #\n"); \
+ pr_debug("# # # ####### ##### # # # # # # # # ###\n"); \
+ pr_debug("# # # # # # # # # # # # # # # # #\n"); \
+ pr_debug("# # # # # # # # # ## # # ## # #\n"); \
+ pr_debug(" # # # # # # # # ### # # #####\n"); \
+ } while (0)
+
+#define INFO_CL_HW(cl_hw, ...) \
+ do { \
+ pr_debug("\n"); \
+ pr_debug("CHIP: %u\n", (cl_hw)->chip->idx); \
+ pr_debug("TCV: %u\n", (cl_hw)->idx); \
+ pr_debug("FILE: %s\n", basename(__FILE__)); \
+ pr_debug("FUNCTION: %s\n", __func__); \
+ pr_debug("LINE: %u\n", __LINE__); \
+ pr_debug("DESCRIPTION: " __VA_ARGS__); \
+ pr_debug("\n"); \
+ } while (0)
+
+#define INFO_CHIP(chip, ...) \
+ do { \
+ pr_debug("\n"); \
+ pr_debug("CHIP: %u\n", (chip)->idx); \
+ pr_debug("FILE: %s\n", basename(__FILE__)); \
+ pr_debug("FUNCTION: %s\n", __func__); \
+ pr_debug("LINE: %u\n", __LINE__); \
+ pr_debug("DESCRIPTION: " __VA_ARGS__); \
+ pr_debug("\n"); \
+ } while (0)
+
+#define CL_DBG_ERROR(cl_hw, ...) \
+ do { \
+ TXT_ERROR; \
+ INFO_CL_HW(cl_hw, __VA_ARGS__); \
+ } while (0)
+
+#define CL_DBG_ERROR_CHIP(chip, ...) \
+ do { \
+ TXT_ERROR; \
+ INFO_CHIP(chip, __VA_ARGS__); \
+ } while (0)
+
+#define CL_DBG_WARNING(cl_hw, ...) \
+ do { \
+ TXT_WARNING; \
+ INFO_CL_HW(cl_hw, __VA_ARGS__); \
+ } while (0)
+
+#define CL_DBG_WARNING_CHIP(chip, ...) \
+ do { \
+ TXT_WARNING; \
+ INFO_CHIP(chip, __VA_ARGS__); \
+ } while (0)
+
+#endif /* CL_DEBUG_H */
--
2.30.0

________________________________
The information transmitted is intended only for the person or entity to which it is addressed and may contain confidential and/or privileged material. Any retransmission, dissemination, copying or other use of, or taking of any action in reliance upon this information is prohibited. If you received this in error, please contact the sender and delete the material from any computer. Nothing contained herein shall be deemed as a representation, warranty or a commitment by Celeno. No warranties are expressed or implied, including, but not limited to, any implied warranties of non-infringement, merchantability and fitness for a particular purpose.
________________________________

2021-06-17 16:25:27

by viktor.barna

[permalink] [raw]
Subject: [RFC v1 053/256] cl8k: add dbgfile.h

From: Viktor Barna <[email protected]>

(Part of the split. Please, take a look at the cover letter for more
details).

Signed-off-by: Viktor Barna <[email protected]>
---
drivers/net/wireless/celeno/cl8k/dbgfile.h | 23 ++++++++++++++++++++++
1 file changed, 23 insertions(+)
create mode 100644 drivers/net/wireless/celeno/cl8k/dbgfile.h

diff --git a/drivers/net/wireless/celeno/cl8k/dbgfile.h b/drivers/net/wireless/celeno/cl8k/dbgfile.h
new file mode 100644
index 000000000000..d089fdbbc3ae
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/dbgfile.h
@@ -0,0 +1,23 @@
+/* SPDX-License-Identifier: MIT */
+/* Copyright(c) 2019-2021, Celeno Communications Ltd. */
+
+#ifndef CL_DBGFILE_H
+#define CL_DBGFILE_H
+
+#include "hw.h"
+
+#define DBG_FILE_MAX_ASSERT_LEN 256
+#define DBG_FILE_MAX_PRINT_LEN 350
+
+void cl_dbgfile_parse(struct cl_hw *cl_hw, void *edata, u32 esize);
+const char *cl_dbgfile_get_msg_txt(struct cl_dbg_data *dbg_data, int fileid, int line);
+void cl_dbgfile_release_mem(struct cl_dbg_data *dbg_data,
+ struct cl_str_offload_env *str_offload_env);
+void cl_dbgfile_print_fw_str(struct cl_hw *cl_hw, u8 *str, int max_size);
+int cl_dbgfile_store_offload_data(struct cl_chip *chip, struct cl_hw *cl_hw,
+ void *data1, u32 size1, u32 base1,
+ void *data2, u32 size2, u32 base2,
+ void *data3, u32 size3, u32 base3);
+const char *cl_dbgfile_get_msg_txt(struct cl_dbg_data *dbg_data, int file_id, int line);
+
+#endif /* CL_DBGFILE_H */
--
2.30.0

________________________________
The information transmitted is intended only for the person or entity to which it is addressed and may contain confidential and/or privileged material. Any retransmission, dissemination, copying or other use of, or taking of any action in reliance upon this information is prohibited. If you received this in error, please contact the sender and delete the material from any computer. Nothing contained herein shall be deemed as a representation, warranty or a commitment by Celeno. No warranties are expressed or implied, including, but not limited to, any implied warranties of non-infringement, merchantability and fitness for a particular purpose.
________________________________

2021-06-17 16:25:33

by viktor.barna

[permalink] [raw]
Subject: [RFC v1 076/256] cl8k: add env_det.h

From: Viktor Barna <[email protected]>

(Part of the split. Please, take a look at the cover letter for more
details).

Signed-off-by: Viktor Barna <[email protected]>
---
drivers/net/wireless/celeno/cl8k/env_det.h | 36 ++++++++++++++++++++++
1 file changed, 36 insertions(+)
create mode 100644 drivers/net/wireless/celeno/cl8k/env_det.h

diff --git a/drivers/net/wireless/celeno/cl8k/env_det.h b/drivers/net/wireless/celeno/cl8k/env_det.h
new file mode 100644
index 000000000000..b00940b94825
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/env_det.h
@@ -0,0 +1,36 @@
+/* SPDX-License-Identifier: MIT */
+/* Copyright(c) 2019-2021, Celeno Communications Ltd. */
+
+#ifndef CL_ENV_DET_H
+#define CL_ENV_DET_H
+
+#include "vendor_cmd.h"
+
+#define MAX_CCA_CLEAN_DEF 20000
+#define MAX_CCA_AVERAGE_DEF 300000
+#define MAX_CCA_NOISY_DEF 850000
+#define MIN_CCA_CLEAN_DEF 20000
+#define MIN_CCA_AVERAGE_DEF 100000
+#define MIN_CCA_NOISY_DEF 400000
+
+enum cl_env_type {
+ CL_ENV_TYPE_CLEAN,
+ CL_ENV_TYPE_AVERAGE,
+ CL_ENV_TYPE_NOISY,
+ CL_ENV_TYPE_VERY_NOISY,
+
+ CL_ENV_TYPE_MAX
+};
+
+struct cl_env_db {
+ enum cl_env_type type;
+};
+
+void cl_env_det_set_type(struct cl_hw *cl_hw, enum cl_env_type type);
+
+bool cl_env_det_is_clean(struct cl_hw *cl_hw);
+bool cl_env_det_is_average(struct cl_hw *cl_hw);
+bool cl_env_det_is_noisy(struct cl_hw *cl_hw);
+bool cl_env_det_is_very_noisy(struct cl_hw *cl_hw);
+
+#endif /* CL_ENV_DET_H */
--
2.30.0

________________________________
The information transmitted is intended only for the person or entity to which it is addressed and may contain confidential and/or privileged material. Any retransmission, dissemination, copying or other use of, or taking of any action in reliance upon this information is prohibited. If you received this in error, please contact the sender and delete the material from any computer. Nothing contained herein shall be deemed as a representation, warranty or a commitment by Celeno. No warranties are expressed or implied, including, but not limited to, any implied warranties of non-infringement, merchantability and fitness for a particular purpose.
________________________________

2021-06-17 16:25:33

by viktor.barna

[permalink] [raw]
Subject: [RFC v1 061/256] cl8k: add dfs/dfs_db.h

From: Viktor Barna <[email protected]>

(Part of the split. Please, take a look at the cover letter for more
details).

Signed-off-by: Viktor Barna <[email protected]>
---
drivers/net/wireless/celeno/cl8k/dfs/dfs_db.h | 107 ++++++++++++++++++
1 file changed, 107 insertions(+)
create mode 100644 drivers/net/wireless/celeno/cl8k/dfs/dfs_db.h

diff --git a/drivers/net/wireless/celeno/cl8k/dfs/dfs_db.h b/drivers/net/wireless/celeno/cl8k/dfs/dfs_db.h
new file mode 100644
index 000000000000..43bb07cef00a
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/dfs/dfs_db.h
@@ -0,0 +1,107 @@
+/* SPDX-License-Identifier: MIT */
+/* Copyright(c) 2019-2021, Celeno Communications Ltd. */
+
+#ifndef CL_DFS_DB_H
+#define CL_DFS_DB_H
+
+#include "dfs/radar.h"
+#include "utils/timer.h"
+
+#define CL_DFS_MAX_TBL_LINE 11 /* Radar Table Max Line */
+#define CL_DFS_MAX_PULSE 4 /* Max Pulses per Interrupt */
+#define CL_DFS_PULSE_BUF_SIZE 64 /* Radar Pulse buffer size */
+#define CL_DFS_PULSE_BUF_MASK 0x03F /* Radar Pulse buffer cyclic mask */
+#define CL_DFS_PULSE_WINDOW 100 /* Radar Pulse search window [ms] */
+#define CL_DFS_MIN_PULSE_TRIG 1 /* Minimum Pulse trigger num */
+#define CL_DFS_MAX_20MHZ_CH 25 /* Maximum 20MHz channels */
+#define CL_DFS_MIN_CH 52 /* Min DFS channel */
+#define CL_DFS_MAX_CH 144 /* Max DFS channel */
+#define CL_DFS_MIN_WEATHER_CH 120 /* Min DFS weather channel */
+#define CL_DFS_MAX_WEATHER_CH 128 /* Max DFS weather channel */
+#define CL_DFS_CAC_TIME 60 /* DFS CAC Time */
+#define CL_DFS_WEATHER_CAC_TIME 600 /* DFS weather channel CAC Time */
+#define CL_DFS_VALIDATION_TIME 1800 /* Validation time */
+#define CL_DFS_CE_CSA_CNT 10 /* According to CE regulation must leave within 1 sec */
+#define CL_DFS_LONG_MIN_WIDTH 20 /* Min Long Pulse Width */
+#define CL_DFS_LONG_FALSE_WIDTH 10 /* Low width signals indicates of false detections */
+#define CL_DFS_LONG_FALSE_IND 6 /* False indication while searching for long sequence */
+#define CL_DFS_FCC_CSA_CNT 2 /* According to FCC regulation must leave within 200ms */
+#define CL_DFS_SAFE_WIDTH 10 /* False detection not expected for high width signals */
+#define CL_DFS_BUF_SIZE 128 /* Max buffer size for loading channels DBs from NVRAM */
+#define CL_DFS_STAGGERED_CHEC_LEN 4 /* Staggered check length */
+#define CL_DFS_ONE_MINUTE 60 /* One minute [s] */
+#define CL_DFS_ONE_MINUTE_MS 60000 /* One minute [ms] */
+#define CL_DFS_ONE_SEC_MS 1000 /* One Second in [ms] */
+#define CL_DFS_THREE_SEC_MS 3000 /* Three Second in [ms] */
+#define CL_DFS_FIVE_SEC_MS 5000 /* Five Second in [ms] */
+#define CL_DFS_TEN_SEC_MS 10000 /* Twn Seconds in [ms] */
+#define CL_DFS_MIN_IDLE 10 /* Minimum consecutive idle decisions to start OCC */
+#define CL_DFS_CONCEAL_CNT 10 /* Maximum concealed pulses search */
+#define CL_DFS_FILTER_DELAY 100 /* Delay the decision by 100ms */
+#define CL_DFS_FILTER_PRI_MARGIN 10 /* PRI search margin */
+#define CL_DFS_LTP_PPB_MARGIN 2 /* Low TP PPB margin */
+#define CL_DFS_MAX_STAGGERED 3 /* Max Staggered patterns */
+
+enum cl_radar_waveform {
+ RADAR_WAVEFORM_SHORT,
+ RADAR_WAVEFORM_LONG,
+ RADAR_WAVEFORM_STAGGERED,
+ RADAR_WAVEFORM_SEVERE
+};
+
+struct cl_radar_type {
+ u8 id;
+ s32 min_width;
+ s32 max_width;
+ s32 tol_width;
+ s32 min_pri;
+ s32 max_pri;
+ s32 tol_pri;
+ s32 tol_freq;
+ u8 min_burst;
+ u8 ppb;
+ u8 trig_count;
+ enum cl_radar_waveform waveform;
+};
+
+struct cl_dfs_pulse {
+ s32 freq : 8; /* Radar Frequency offset [units of 4MHz] */
+ u32 fom : 8; /* Figure of Merit */
+ u32 width : 8; /* Pulse Width [units of 2 micro sec] */
+ u32 occ : 1; /* OCC indication for Primary/Secondary channel */
+ u32 res1 : 7; /* Reserve */
+ u32 pri : 16; /* Pulse Repetition Frequency */
+ u32 res2 : 16;
+ unsigned long time; /* Pulse Receive Time */
+};
+
+struct cl_dfs_db {
+ bool en;
+
+ struct {
+ bool started;
+ bool requested;
+ } cac;
+
+ enum cl_dbg_level dbg_lvl;
+ enum cl_reg_standard dfs_standard;
+ struct cl_radar_type *radar_type;
+ u8 csa_cnt;
+
+ u8 min_pulse_eeq;
+ u8 buf_idx;
+ u8 radar_type_cnt;
+ u16 search_window;
+ u16 last_pri;
+ u16 max_interrupt_diff;
+ u32 pulse_cnt;
+ u32 severe_env_pulse_cnt;
+ struct cl_dfs_pulse dfs_pulse[CL_DFS_PULSE_BUF_SIZE];
+ struct cl_dfs_pulse pulse_buffer[CL_DFS_PULSE_BUF_SIZE];
+ u8 long_pulse_count;
+ u32 last_long_pulse_ts;
+ u8 short_pulse_count;
+ u8 long_pri_match_count;
+};
+
+#endif /* CL_DFS_DB_H */
--
2.30.0

________________________________
The information transmitted is intended only for the person or entity to which it is addressed and may contain confidential and/or privileged material. Any retransmission, dissemination, copying or other use of, or taking of any action in reliance upon this information is prohibited. If you received this in error, please contact the sender and delete the material from any computer. Nothing contained herein shall be deemed as a representation, warranty or a commitment by Celeno. No warranties are expressed or implied, including, but not limited to, any implied warranties of non-infringement, merchantability and fitness for a particular purpose.
________________________________

2021-06-17 16:25:32

by viktor.barna

[permalink] [raw]
Subject: [RFC v1 050/256] cl8k: add data_rates.c

From: Viktor Barna <[email protected]>

(Part of the split. Please, take a look at the cover letter for more
details).

Signed-off-by: Viktor Barna <[email protected]>
---
drivers/net/wireless/celeno/cl8k/data_rates.c | 1019 +++++++++++++++++
1 file changed, 1019 insertions(+)
create mode 100644 drivers/net/wireless/celeno/cl8k/data_rates.c

diff --git a/drivers/net/wireless/celeno/cl8k/data_rates.c b/drivers/net/wireless/celeno/cl8k/data_rates.c
new file mode 100644
index 000000000000..64c02b9385c1
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/data_rates.c
@@ -0,0 +1,1019 @@
+// SPDX-License-Identifier: MIT
+/* Copyright(c) 2019-2021, Celeno Communications Ltd. */
+
+#include "data_rates.h"
+
+/*
+ * This table of rates was taken from IEEE 802.11ax Draft v3.3, 28.5. Parameters
+ * for HE-HE_MCSs. The units are 1/10 Mbs. Note that we don't support DCM, so it is
+ * not taken into account in this table.
+ */
+const u16 data_rate_he_x10[CHNL_BW_MAX][WRS_SS_MAX][WRS_MCS_MAX_HE][WRS_GI_MAX_HE] = {
+ [CHNL_BW_20][WRS_SS_1][WRS_MCS_0][WRS_GI_LONG] = 73,
+ [CHNL_BW_20][WRS_SS_1][WRS_MCS_0][WRS_GI_SHORT] = 81,
+ [CHNL_BW_20][WRS_SS_1][WRS_MCS_0][WRS_GI_VSHORT] = 86,
+ [CHNL_BW_20][WRS_SS_1][WRS_MCS_1][WRS_GI_LONG] = 146,
+ [CHNL_BW_20][WRS_SS_1][WRS_MCS_1][WRS_GI_SHORT] = 163,
+ [CHNL_BW_20][WRS_SS_1][WRS_MCS_1][WRS_GI_VSHORT] = 172,
+ [CHNL_BW_20][WRS_SS_1][WRS_MCS_2][WRS_GI_LONG] = 219,
+ [CHNL_BW_20][WRS_SS_1][WRS_MCS_2][WRS_GI_SHORT] = 244,
+ [CHNL_BW_20][WRS_SS_1][WRS_MCS_2][WRS_GI_VSHORT] = 258,
+ [CHNL_BW_20][WRS_SS_1][WRS_MCS_3][WRS_GI_LONG] = 293,
+ [CHNL_BW_20][WRS_SS_1][WRS_MCS_3][WRS_GI_SHORT] = 325,
+ [CHNL_BW_20][WRS_SS_1][WRS_MCS_3][WRS_GI_VSHORT] = 344,
+ [CHNL_BW_20][WRS_SS_1][WRS_MCS_4][WRS_GI_LONG] = 439,
+ [CHNL_BW_20][WRS_SS_1][WRS_MCS_4][WRS_GI_SHORT] = 488,
+ [CHNL_BW_20][WRS_SS_1][WRS_MCS_4][WRS_GI_VSHORT] = 516,
+ [CHNL_BW_20][WRS_SS_1][WRS_MCS_5][WRS_GI_LONG] = 585,
+ [CHNL_BW_20][WRS_SS_1][WRS_MCS_5][WRS_GI_SHORT] = 650,
+ [CHNL_BW_20][WRS_SS_1][WRS_MCS_5][WRS_GI_VSHORT] = 688,
+ [CHNL_BW_20][WRS_SS_1][WRS_MCS_6][WRS_GI_LONG] = 658,
+ [CHNL_BW_20][WRS_SS_1][WRS_MCS_6][WRS_GI_SHORT] = 731,
+ [CHNL_BW_20][WRS_SS_1][WRS_MCS_6][WRS_GI_VSHORT] = 774,
+ [CHNL_BW_20][WRS_SS_1][WRS_MCS_7][WRS_GI_LONG] = 731,
+ [CHNL_BW_20][WRS_SS_1][WRS_MCS_7][WRS_GI_SHORT] = 813,
+ [CHNL_BW_20][WRS_SS_1][WRS_MCS_7][WRS_GI_VSHORT] = 860,
+ [CHNL_BW_20][WRS_SS_1][WRS_MCS_8][WRS_GI_LONG] = 878,
+ [CHNL_BW_20][WRS_SS_1][WRS_MCS_8][WRS_GI_SHORT] = 975,
+ [CHNL_BW_20][WRS_SS_1][WRS_MCS_8][WRS_GI_VSHORT] = 1032,
+ [CHNL_BW_20][WRS_SS_1][WRS_MCS_9][WRS_GI_LONG] = 975,
+ [CHNL_BW_20][WRS_SS_1][WRS_MCS_9][WRS_GI_SHORT] = 1083,
+ [CHNL_BW_20][WRS_SS_1][WRS_MCS_9][WRS_GI_VSHORT] = 1147,
+ [CHNL_BW_20][WRS_SS_1][WRS_MCS_10][WRS_GI_LONG] = 1097,
+ [CHNL_BW_20][WRS_SS_1][WRS_MCS_10][WRS_GI_SHORT] = 1219,
+ [CHNL_BW_20][WRS_SS_1][WRS_MCS_10][WRS_GI_VSHORT] = 1290,
+ [CHNL_BW_20][WRS_SS_1][WRS_MCS_11][WRS_GI_LONG] = 1219,
+ [CHNL_BW_20][WRS_SS_1][WRS_MCS_11][WRS_GI_SHORT] = 1354,
+ [CHNL_BW_20][WRS_SS_1][WRS_MCS_11][WRS_GI_VSHORT] = 1434,
+ [CHNL_BW_20][WRS_SS_2][WRS_MCS_0][WRS_GI_LONG] = 146,
+ [CHNL_BW_20][WRS_SS_2][WRS_MCS_0][WRS_GI_SHORT] = 163,
+ [CHNL_BW_20][WRS_SS_2][WRS_MCS_0][WRS_GI_VSHORT] = 172,
+ [CHNL_BW_20][WRS_SS_2][WRS_MCS_1][WRS_GI_LONG] = 293,
+ [CHNL_BW_20][WRS_SS_2][WRS_MCS_1][WRS_GI_SHORT] = 325,
+ [CHNL_BW_20][WRS_SS_2][WRS_MCS_1][WRS_GI_VSHORT] = 344,
+ [CHNL_BW_20][WRS_SS_2][WRS_MCS_2][WRS_GI_LONG] = 439,
+ [CHNL_BW_20][WRS_SS_2][WRS_MCS_2][WRS_GI_SHORT] = 488,
+ [CHNL_BW_20][WRS_SS_2][WRS_MCS_2][WRS_GI_VSHORT] = 516,
+ [CHNL_BW_20][WRS_SS_2][WRS_MCS_3][WRS_GI_LONG] = 585,
+ [CHNL_BW_20][WRS_SS_2][WRS_MCS_3][WRS_GI_SHORT] = 650,
+ [CHNL_BW_20][WRS_SS_2][WRS_MCS_3][WRS_GI_VSHORT] = 688,
+ [CHNL_BW_20][WRS_SS_2][WRS_MCS_4][WRS_GI_LONG] = 878,
+ [CHNL_BW_20][WRS_SS_2][WRS_MCS_4][WRS_GI_SHORT] = 975,
+ [CHNL_BW_20][WRS_SS_2][WRS_MCS_4][WRS_GI_VSHORT] = 1032,
+ [CHNL_BW_20][WRS_SS_2][WRS_MCS_5][WRS_GI_LONG] = 1170,
+ [CHNL_BW_20][WRS_SS_2][WRS_MCS_5][WRS_GI_SHORT] = 1300,
+ [CHNL_BW_20][WRS_SS_2][WRS_MCS_5][WRS_GI_VSHORT] = 1376,
+ [CHNL_BW_20][WRS_SS_2][WRS_MCS_6][WRS_GI_LONG] = 1316,
+ [CHNL_BW_20][WRS_SS_2][WRS_MCS_6][WRS_GI_SHORT] = 1463,
+ [CHNL_BW_20][WRS_SS_2][WRS_MCS_6][WRS_GI_VSHORT] = 1549,
+ [CHNL_BW_20][WRS_SS_2][WRS_MCS_7][WRS_GI_LONG] = 1463,
+ [CHNL_BW_20][WRS_SS_2][WRS_MCS_7][WRS_GI_SHORT] = 1625,
+ [CHNL_BW_20][WRS_SS_2][WRS_MCS_7][WRS_GI_VSHORT] = 1721,
+ [CHNL_BW_20][WRS_SS_2][WRS_MCS_8][WRS_GI_LONG] = 1755,
+ [CHNL_BW_20][WRS_SS_2][WRS_MCS_8][WRS_GI_SHORT] = 1950,
+ [CHNL_BW_20][WRS_SS_2][WRS_MCS_8][WRS_GI_VSHORT] = 2065,
+ [CHNL_BW_20][WRS_SS_2][WRS_MCS_9][WRS_GI_LONG] = 1950,
+ [CHNL_BW_20][WRS_SS_2][WRS_MCS_9][WRS_GI_SHORT] = 2167,
+ [CHNL_BW_20][WRS_SS_2][WRS_MCS_9][WRS_GI_VSHORT] = 2294,
+ [CHNL_BW_20][WRS_SS_2][WRS_MCS_10][WRS_GI_LONG] = 2194,
+ [CHNL_BW_20][WRS_SS_2][WRS_MCS_10][WRS_GI_SHORT] = 2438,
+ [CHNL_BW_20][WRS_SS_2][WRS_MCS_10][WRS_GI_VSHORT] = 2581,
+ [CHNL_BW_20][WRS_SS_2][WRS_MCS_11][WRS_GI_LONG] = 2438,
+ [CHNL_BW_20][WRS_SS_2][WRS_MCS_11][WRS_GI_SHORT] = 2708,
+ [CHNL_BW_20][WRS_SS_2][WRS_MCS_11][WRS_GI_VSHORT] = 2868,
+ [CHNL_BW_20][WRS_SS_3][WRS_MCS_0][WRS_GI_LONG] = 219,
+ [CHNL_BW_20][WRS_SS_3][WRS_MCS_0][WRS_GI_SHORT] = 244,
+ [CHNL_BW_20][WRS_SS_3][WRS_MCS_0][WRS_GI_VSHORT] = 258,
+ [CHNL_BW_20][WRS_SS_3][WRS_MCS_1][WRS_GI_LONG] = 439,
+ [CHNL_BW_20][WRS_SS_3][WRS_MCS_1][WRS_GI_SHORT] = 488,
+ [CHNL_BW_20][WRS_SS_3][WRS_MCS_1][WRS_GI_VSHORT] = 516,
+ [CHNL_BW_20][WRS_SS_3][WRS_MCS_2][WRS_GI_LONG] = 658,
+ [CHNL_BW_20][WRS_SS_3][WRS_MCS_2][WRS_GI_SHORT] = 731,
+ [CHNL_BW_20][WRS_SS_3][WRS_MCS_2][WRS_GI_VSHORT] = 774,
+ [CHNL_BW_20][WRS_SS_3][WRS_MCS_3][WRS_GI_LONG] = 878,
+ [CHNL_BW_20][WRS_SS_3][WRS_MCS_3][WRS_GI_SHORT] = 975,
+ [CHNL_BW_20][WRS_SS_3][WRS_MCS_3][WRS_GI_VSHORT] = 1032,
+ [CHNL_BW_20][WRS_SS_3][WRS_MCS_4][WRS_GI_LONG] = 1316,
+ [CHNL_BW_20][WRS_SS_3][WRS_MCS_4][WRS_GI_SHORT] = 1463,
+ [CHNL_BW_20][WRS_SS_3][WRS_MCS_4][WRS_GI_VSHORT] = 1549,
+ [CHNL_BW_20][WRS_SS_3][WRS_MCS_5][WRS_GI_LONG] = 1755,
+ [CHNL_BW_20][WRS_SS_3][WRS_MCS_5][WRS_GI_SHORT] = 1950,
+ [CHNL_BW_20][WRS_SS_3][WRS_MCS_5][WRS_GI_VSHORT] = 2065,
+ [CHNL_BW_20][WRS_SS_3][WRS_MCS_6][WRS_GI_LONG] = 1974,
+ [CHNL_BW_20][WRS_SS_3][WRS_MCS_6][WRS_GI_SHORT] = 2194,
+ [CHNL_BW_20][WRS_SS_3][WRS_MCS_6][WRS_GI_VSHORT] = 2323,
+ [CHNL_BW_20][WRS_SS_3][WRS_MCS_7][WRS_GI_LONG] = 2194,
+ [CHNL_BW_20][WRS_SS_3][WRS_MCS_7][WRS_GI_SHORT] = 2438,
+ [CHNL_BW_20][WRS_SS_3][WRS_MCS_7][WRS_GI_VSHORT] = 2581,
+ [CHNL_BW_20][WRS_SS_3][WRS_MCS_8][WRS_GI_LONG] = 2633,
+ [CHNL_BW_20][WRS_SS_3][WRS_MCS_8][WRS_GI_SHORT] = 2925,
+ [CHNL_BW_20][WRS_SS_3][WRS_MCS_8][WRS_GI_VSHORT] = 3097,
+ [CHNL_BW_20][WRS_SS_3][WRS_MCS_9][WRS_GI_LONG] = 2925,
+ [CHNL_BW_20][WRS_SS_3][WRS_MCS_9][WRS_GI_SHORT] = 3250,
+ [CHNL_BW_20][WRS_SS_3][WRS_MCS_9][WRS_GI_VSHORT] = 3441,
+ [CHNL_BW_20][WRS_SS_3][WRS_MCS_10][WRS_GI_LONG] = 3291,
+ [CHNL_BW_20][WRS_SS_3][WRS_MCS_10][WRS_GI_SHORT] = 3656,
+ [CHNL_BW_20][WRS_SS_3][WRS_MCS_10][WRS_GI_VSHORT] = 3871,
+ [CHNL_BW_20][WRS_SS_3][WRS_MCS_11][WRS_GI_LONG] = 3656,
+ [CHNL_BW_20][WRS_SS_3][WRS_MCS_11][WRS_GI_SHORT] = 4063,
+ [CHNL_BW_20][WRS_SS_3][WRS_MCS_11][WRS_GI_VSHORT] = 4301,
+ [CHNL_BW_20][WRS_SS_4][WRS_MCS_0][WRS_GI_LONG] = 293,
+ [CHNL_BW_20][WRS_SS_4][WRS_MCS_0][WRS_GI_SHORT] = 325,
+ [CHNL_BW_20][WRS_SS_4][WRS_MCS_0][WRS_GI_VSHORT] = 344,
+ [CHNL_BW_20][WRS_SS_4][WRS_MCS_1][WRS_GI_LONG] = 585,
+ [CHNL_BW_20][WRS_SS_4][WRS_MCS_1][WRS_GI_SHORT] = 650,
+ [CHNL_BW_20][WRS_SS_4][WRS_MCS_1][WRS_GI_VSHORT] = 688,
+ [CHNL_BW_20][WRS_SS_4][WRS_MCS_2][WRS_GI_LONG] = 878,
+ [CHNL_BW_20][WRS_SS_4][WRS_MCS_2][WRS_GI_SHORT] = 975,
+ [CHNL_BW_20][WRS_SS_4][WRS_MCS_2][WRS_GI_VSHORT] = 1032,
+ [CHNL_BW_20][WRS_SS_4][WRS_MCS_3][WRS_GI_LONG] = 1170,
+ [CHNL_BW_20][WRS_SS_4][WRS_MCS_3][WRS_GI_SHORT] = 1300,
+ [CHNL_BW_20][WRS_SS_4][WRS_MCS_3][WRS_GI_VSHORT] = 1376,
+ [CHNL_BW_20][WRS_SS_4][WRS_MCS_4][WRS_GI_LONG] = 1755,
+ [CHNL_BW_20][WRS_SS_4][WRS_MCS_4][WRS_GI_SHORT] = 1950,
+ [CHNL_BW_20][WRS_SS_4][WRS_MCS_4][WRS_GI_VSHORT] = 2065,
+ [CHNL_BW_20][WRS_SS_4][WRS_MCS_5][WRS_GI_LONG] = 2340,
+ [CHNL_BW_20][WRS_SS_4][WRS_MCS_5][WRS_GI_SHORT] = 2600,
+ [CHNL_BW_20][WRS_SS_4][WRS_MCS_5][WRS_GI_VSHORT] = 2753,
+ [CHNL_BW_20][WRS_SS_4][WRS_MCS_6][WRS_GI_LONG] = 2633,
+ [CHNL_BW_20][WRS_SS_4][WRS_MCS_6][WRS_GI_SHORT] = 2925,
+ [CHNL_BW_20][WRS_SS_4][WRS_MCS_6][WRS_GI_VSHORT] = 3097,
+ [CHNL_BW_20][WRS_SS_4][WRS_MCS_7][WRS_GI_LONG] = 2925,
+ [CHNL_BW_20][WRS_SS_4][WRS_MCS_7][WRS_GI_SHORT] = 3250,
+ [CHNL_BW_20][WRS_SS_4][WRS_MCS_7][WRS_GI_VSHORT] = 3441,
+ [CHNL_BW_20][WRS_SS_4][WRS_MCS_8][WRS_GI_LONG] = 3510,
+ [CHNL_BW_20][WRS_SS_4][WRS_MCS_8][WRS_GI_SHORT] = 3900,
+ [CHNL_BW_20][WRS_SS_4][WRS_MCS_8][WRS_GI_VSHORT] = 4129,
+ [CHNL_BW_20][WRS_SS_4][WRS_MCS_9][WRS_GI_LONG] = 3900,
+ [CHNL_BW_20][WRS_SS_4][WRS_MCS_9][WRS_GI_SHORT] = 4333,
+ [CHNL_BW_20][WRS_SS_4][WRS_MCS_9][WRS_GI_VSHORT] = 4588,
+ [CHNL_BW_20][WRS_SS_4][WRS_MCS_10][WRS_GI_LONG] = 4388,
+ [CHNL_BW_20][WRS_SS_4][WRS_MCS_10][WRS_GI_SHORT] = 4875,
+ [CHNL_BW_20][WRS_SS_4][WRS_MCS_10][WRS_GI_VSHORT] = 5162,
+ [CHNL_BW_20][WRS_SS_4][WRS_MCS_11][WRS_GI_LONG] = 4875,
+ [CHNL_BW_20][WRS_SS_4][WRS_MCS_11][WRS_GI_SHORT] = 5417,
+ [CHNL_BW_20][WRS_SS_4][WRS_MCS_11][WRS_GI_VSHORT] = 5735,
+ [CHNL_BW_40][WRS_SS_1][WRS_MCS_0][WRS_GI_LONG] = 146,
+ [CHNL_BW_40][WRS_SS_1][WRS_MCS_0][WRS_GI_SHORT] = 163,
+ [CHNL_BW_40][WRS_SS_1][WRS_MCS_0][WRS_GI_VSHORT] = 172,
+ [CHNL_BW_40][WRS_SS_1][WRS_MCS_1][WRS_GI_LONG] = 293,
+ [CHNL_BW_40][WRS_SS_1][WRS_MCS_1][WRS_GI_SHORT] = 325,
+ [CHNL_BW_40][WRS_SS_1][WRS_MCS_1][WRS_GI_VSHORT] = 344,
+ [CHNL_BW_40][WRS_SS_1][WRS_MCS_2][WRS_GI_LONG] = 439,
+ [CHNL_BW_40][WRS_SS_1][WRS_MCS_2][WRS_GI_SHORT] = 488,
+ [CHNL_BW_40][WRS_SS_1][WRS_MCS_2][WRS_GI_VSHORT] = 516,
+ [CHNL_BW_40][WRS_SS_1][WRS_MCS_3][WRS_GI_LONG] = 585,
+ [CHNL_BW_40][WRS_SS_1][WRS_MCS_3][WRS_GI_SHORT] = 650,
+ [CHNL_BW_40][WRS_SS_1][WRS_MCS_3][WRS_GI_VSHORT] = 688,
+ [CHNL_BW_40][WRS_SS_1][WRS_MCS_4][WRS_GI_LONG] = 878,
+ [CHNL_BW_40][WRS_SS_1][WRS_MCS_4][WRS_GI_SHORT] = 975,
+ [CHNL_BW_40][WRS_SS_1][WRS_MCS_4][WRS_GI_VSHORT] = 1032,
+ [CHNL_BW_40][WRS_SS_1][WRS_MCS_5][WRS_GI_LONG] = 1170,
+ [CHNL_BW_40][WRS_SS_1][WRS_MCS_5][WRS_GI_SHORT] = 1300,
+ [CHNL_BW_40][WRS_SS_1][WRS_MCS_5][WRS_GI_VSHORT] = 1376,
+ [CHNL_BW_40][WRS_SS_1][WRS_MCS_6][WRS_GI_LONG] = 1316,
+ [CHNL_BW_40][WRS_SS_1][WRS_MCS_6][WRS_GI_SHORT] = 1463,
+ [CHNL_BW_40][WRS_SS_1][WRS_MCS_6][WRS_GI_VSHORT] = 1549,
+ [CHNL_BW_40][WRS_SS_1][WRS_MCS_7][WRS_GI_LONG] = 1463,
+ [CHNL_BW_40][WRS_SS_1][WRS_MCS_7][WRS_GI_SHORT] = 1625,
+ [CHNL_BW_40][WRS_SS_1][WRS_MCS_7][WRS_GI_VSHORT] = 1721,
+ [CHNL_BW_40][WRS_SS_1][WRS_MCS_8][WRS_GI_LONG] = 1755,
+ [CHNL_BW_40][WRS_SS_1][WRS_MCS_8][WRS_GI_SHORT] = 1950,
+ [CHNL_BW_40][WRS_SS_1][WRS_MCS_8][WRS_GI_VSHORT] = 2065,
+ [CHNL_BW_40][WRS_SS_1][WRS_MCS_9][WRS_GI_LONG] = 1950,
+ [CHNL_BW_40][WRS_SS_1][WRS_MCS_9][WRS_GI_SHORT] = 2167,
+ [CHNL_BW_40][WRS_SS_1][WRS_MCS_9][WRS_GI_VSHORT] = 2294,
+ [CHNL_BW_40][WRS_SS_1][WRS_MCS_10][WRS_GI_LONG] = 2194,
+ [CHNL_BW_40][WRS_SS_1][WRS_MCS_10][WRS_GI_SHORT] = 2438,
+ [CHNL_BW_40][WRS_SS_1][WRS_MCS_10][WRS_GI_VSHORT] = 2581,
+ [CHNL_BW_40][WRS_SS_1][WRS_MCS_11][WRS_GI_LONG] = 2438,
+ [CHNL_BW_40][WRS_SS_1][WRS_MCS_11][WRS_GI_SHORT] = 2708,
+ [CHNL_BW_40][WRS_SS_1][WRS_MCS_11][WRS_GI_VSHORT] = 2868,
+ [CHNL_BW_40][WRS_SS_2][WRS_MCS_0][WRS_GI_LONG] = 293,
+ [CHNL_BW_40][WRS_SS_2][WRS_MCS_0][WRS_GI_SHORT] = 325,
+ [CHNL_BW_40][WRS_SS_2][WRS_MCS_0][WRS_GI_VSHORT] = 344,
+ [CHNL_BW_40][WRS_SS_2][WRS_MCS_1][WRS_GI_LONG] = 585,
+ [CHNL_BW_40][WRS_SS_2][WRS_MCS_1][WRS_GI_SHORT] = 650,
+ [CHNL_BW_40][WRS_SS_2][WRS_MCS_1][WRS_GI_VSHORT] = 688,
+ [CHNL_BW_40][WRS_SS_2][WRS_MCS_2][WRS_GI_LONG] = 878,
+ [CHNL_BW_40][WRS_SS_2][WRS_MCS_2][WRS_GI_SHORT] = 975,
+ [CHNL_BW_40][WRS_SS_2][WRS_MCS_2][WRS_GI_VSHORT] = 1032,
+ [CHNL_BW_40][WRS_SS_2][WRS_MCS_3][WRS_GI_LONG] = 1170,
+ [CHNL_BW_40][WRS_SS_2][WRS_MCS_3][WRS_GI_SHORT] = 1300,
+ [CHNL_BW_40][WRS_SS_2][WRS_MCS_3][WRS_GI_VSHORT] = 1376,
+ [CHNL_BW_40][WRS_SS_2][WRS_MCS_4][WRS_GI_LONG] = 1755,
+ [CHNL_BW_40][WRS_SS_2][WRS_MCS_4][WRS_GI_SHORT] = 1950,
+ [CHNL_BW_40][WRS_SS_2][WRS_MCS_4][WRS_GI_VSHORT] = 2065,
+ [CHNL_BW_40][WRS_SS_2][WRS_MCS_5][WRS_GI_LONG] = 2340,
+ [CHNL_BW_40][WRS_SS_2][WRS_MCS_5][WRS_GI_SHORT] = 2600,
+ [CHNL_BW_40][WRS_SS_2][WRS_MCS_5][WRS_GI_VSHORT] = 2753,
+ [CHNL_BW_40][WRS_SS_2][WRS_MCS_6][WRS_GI_LONG] = 2633,
+ [CHNL_BW_40][WRS_SS_2][WRS_MCS_6][WRS_GI_SHORT] = 2925,
+ [CHNL_BW_40][WRS_SS_2][WRS_MCS_6][WRS_GI_VSHORT] = 3097,
+ [CHNL_BW_40][WRS_SS_2][WRS_MCS_7][WRS_GI_LONG] = 2925,
+ [CHNL_BW_40][WRS_SS_2][WRS_MCS_7][WRS_GI_SHORT] = 3250,
+ [CHNL_BW_40][WRS_SS_2][WRS_MCS_7][WRS_GI_VSHORT] = 3441,
+ [CHNL_BW_40][WRS_SS_2][WRS_MCS_8][WRS_GI_LONG] = 3510,
+ [CHNL_BW_40][WRS_SS_2][WRS_MCS_8][WRS_GI_SHORT] = 3900,
+ [CHNL_BW_40][WRS_SS_2][WRS_MCS_8][WRS_GI_VSHORT] = 4129,
+ [CHNL_BW_40][WRS_SS_2][WRS_MCS_9][WRS_GI_LONG] = 3900,
+ [CHNL_BW_40][WRS_SS_2][WRS_MCS_9][WRS_GI_SHORT] = 4333,
+ [CHNL_BW_40][WRS_SS_2][WRS_MCS_9][WRS_GI_VSHORT] = 4588,
+ [CHNL_BW_40][WRS_SS_2][WRS_MCS_10][WRS_GI_LONG] = 4388,
+ [CHNL_BW_40][WRS_SS_2][WRS_MCS_10][WRS_GI_SHORT] = 4875,
+ [CHNL_BW_40][WRS_SS_2][WRS_MCS_10][WRS_GI_VSHORT] = 5162,
+ [CHNL_BW_40][WRS_SS_2][WRS_MCS_11][WRS_GI_LONG] = 4875,
+ [CHNL_BW_40][WRS_SS_2][WRS_MCS_11][WRS_GI_SHORT] = 5417,
+ [CHNL_BW_40][WRS_SS_2][WRS_MCS_11][WRS_GI_VSHORT] = 5735,
+ [CHNL_BW_40][WRS_SS_3][WRS_MCS_0][WRS_GI_LONG] = 439,
+ [CHNL_BW_40][WRS_SS_3][WRS_MCS_0][WRS_GI_SHORT] = 488,
+ [CHNL_BW_40][WRS_SS_3][WRS_MCS_0][WRS_GI_VSHORT] = 516,
+ [CHNL_BW_40][WRS_SS_3][WRS_MCS_1][WRS_GI_LONG] = 878,
+ [CHNL_BW_40][WRS_SS_3][WRS_MCS_1][WRS_GI_SHORT] = 975,
+ [CHNL_BW_40][WRS_SS_3][WRS_MCS_1][WRS_GI_VSHORT] = 1032,
+ [CHNL_BW_40][WRS_SS_3][WRS_MCS_2][WRS_GI_LONG] = 1316,
+ [CHNL_BW_40][WRS_SS_3][WRS_MCS_2][WRS_GI_SHORT] = 1463,
+ [CHNL_BW_40][WRS_SS_3][WRS_MCS_2][WRS_GI_VSHORT] = 1549,
+ [CHNL_BW_40][WRS_SS_3][WRS_MCS_3][WRS_GI_LONG] = 1755,
+ [CHNL_BW_40][WRS_SS_3][WRS_MCS_3][WRS_GI_SHORT] = 1950,
+ [CHNL_BW_40][WRS_SS_3][WRS_MCS_3][WRS_GI_VSHORT] = 2065,
+ [CHNL_BW_40][WRS_SS_3][WRS_MCS_4][WRS_GI_LONG] = 2633,
+ [CHNL_BW_40][WRS_SS_3][WRS_MCS_4][WRS_GI_SHORT] = 2925,
+ [CHNL_BW_40][WRS_SS_3][WRS_MCS_4][WRS_GI_VSHORT] = 3097,
+ [CHNL_BW_40][WRS_SS_3][WRS_MCS_5][WRS_GI_LONG] = 3510,
+ [CHNL_BW_40][WRS_SS_3][WRS_MCS_5][WRS_GI_SHORT] = 3900,
+ [CHNL_BW_40][WRS_SS_3][WRS_MCS_5][WRS_GI_VSHORT] = 4129,
+ [CHNL_BW_40][WRS_SS_3][WRS_MCS_6][WRS_GI_LONG] = 3949,
+ [CHNL_BW_40][WRS_SS_3][WRS_MCS_6][WRS_GI_SHORT] = 4388,
+ [CHNL_BW_40][WRS_SS_3][WRS_MCS_6][WRS_GI_VSHORT] = 4646,
+ [CHNL_BW_40][WRS_SS_3][WRS_MCS_7][WRS_GI_LONG] = 4388,
+ [CHNL_BW_40][WRS_SS_3][WRS_MCS_7][WRS_GI_SHORT] = 4875,
+ [CHNL_BW_40][WRS_SS_3][WRS_MCS_7][WRS_GI_VSHORT] = 5162,
+ [CHNL_BW_40][WRS_SS_3][WRS_MCS_8][WRS_GI_LONG] = 5265,
+ [CHNL_BW_40][WRS_SS_3][WRS_MCS_8][WRS_GI_SHORT] = 5850,
+ [CHNL_BW_40][WRS_SS_3][WRS_MCS_8][WRS_GI_VSHORT] = 6194,
+ [CHNL_BW_40][WRS_SS_3][WRS_MCS_9][WRS_GI_LONG] = 5850,
+ [CHNL_BW_40][WRS_SS_3][WRS_MCS_9][WRS_GI_SHORT] = 6500,
+ [CHNL_BW_40][WRS_SS_3][WRS_MCS_9][WRS_GI_VSHORT] = 6882,
+ [CHNL_BW_40][WRS_SS_3][WRS_MCS_10][WRS_GI_LONG] = 6581,
+ [CHNL_BW_40][WRS_SS_3][WRS_MCS_10][WRS_GI_SHORT] = 7313,
+ [CHNL_BW_40][WRS_SS_3][WRS_MCS_10][WRS_GI_VSHORT] = 7743,
+ [CHNL_BW_40][WRS_SS_3][WRS_MCS_11][WRS_GI_LONG] = 7313,
+ [CHNL_BW_40][WRS_SS_3][WRS_MCS_11][WRS_GI_SHORT] = 8125,
+ [CHNL_BW_40][WRS_SS_3][WRS_MCS_11][WRS_GI_VSHORT] = 8603,
+ [CHNL_BW_40][WRS_SS_4][WRS_MCS_0][WRS_GI_LONG] = 585,
+ [CHNL_BW_40][WRS_SS_4][WRS_MCS_0][WRS_GI_SHORT] = 650,
+ [CHNL_BW_40][WRS_SS_4][WRS_MCS_0][WRS_GI_VSHORT] = 688,
+ [CHNL_BW_40][WRS_SS_4][WRS_MCS_1][WRS_GI_LONG] = 1170,
+ [CHNL_BW_40][WRS_SS_4][WRS_MCS_1][WRS_GI_SHORT] = 1300,
+ [CHNL_BW_40][WRS_SS_4][WRS_MCS_1][WRS_GI_VSHORT] = 1376,
+ [CHNL_BW_40][WRS_SS_4][WRS_MCS_2][WRS_GI_LONG] = 1755,
+ [CHNL_BW_40][WRS_SS_4][WRS_MCS_2][WRS_GI_SHORT] = 1950,
+ [CHNL_BW_40][WRS_SS_4][WRS_MCS_2][WRS_GI_VSHORT] = 2065,
+ [CHNL_BW_40][WRS_SS_4][WRS_MCS_3][WRS_GI_LONG] = 2340,
+ [CHNL_BW_40][WRS_SS_4][WRS_MCS_3][WRS_GI_SHORT] = 2600,
+ [CHNL_BW_40][WRS_SS_4][WRS_MCS_3][WRS_GI_VSHORT] = 2753,
+ [CHNL_BW_40][WRS_SS_4][WRS_MCS_4][WRS_GI_LONG] = 3510,
+ [CHNL_BW_40][WRS_SS_4][WRS_MCS_4][WRS_GI_SHORT] = 3900,
+ [CHNL_BW_40][WRS_SS_4][WRS_MCS_4][WRS_GI_VSHORT] = 4129,
+ [CHNL_BW_40][WRS_SS_4][WRS_MCS_5][WRS_GI_LONG] = 4680,
+ [CHNL_BW_40][WRS_SS_4][WRS_MCS_5][WRS_GI_SHORT] = 5200,
+ [CHNL_BW_40][WRS_SS_4][WRS_MCS_5][WRS_GI_VSHORT] = 5506,
+ [CHNL_BW_40][WRS_SS_4][WRS_MCS_6][WRS_GI_LONG] = 5265,
+ [CHNL_BW_40][WRS_SS_4][WRS_MCS_6][WRS_GI_SHORT] = 5850,
+ [CHNL_BW_40][WRS_SS_4][WRS_MCS_6][WRS_GI_VSHORT] = 6194,
+ [CHNL_BW_40][WRS_SS_4][WRS_MCS_7][WRS_GI_LONG] = 5850,
+ [CHNL_BW_40][WRS_SS_4][WRS_MCS_7][WRS_GI_SHORT] = 6500,
+ [CHNL_BW_40][WRS_SS_4][WRS_MCS_7][WRS_GI_VSHORT] = 6882,
+ [CHNL_BW_40][WRS_SS_4][WRS_MCS_8][WRS_GI_LONG] = 7020,
+ [CHNL_BW_40][WRS_SS_4][WRS_MCS_8][WRS_GI_SHORT] = 7800,
+ [CHNL_BW_40][WRS_SS_4][WRS_MCS_8][WRS_GI_VSHORT] = 8259,
+ [CHNL_BW_40][WRS_SS_4][WRS_MCS_9][WRS_GI_LONG] = 7800,
+ [CHNL_BW_40][WRS_SS_4][WRS_MCS_9][WRS_GI_SHORT] = 8667,
+ [CHNL_BW_40][WRS_SS_4][WRS_MCS_9][WRS_GI_VSHORT] = 9176,
+ [CHNL_BW_40][WRS_SS_4][WRS_MCS_10][WRS_GI_LONG] = 8775,
+ [CHNL_BW_40][WRS_SS_4][WRS_MCS_10][WRS_GI_SHORT] = 9750,
+ [CHNL_BW_40][WRS_SS_4][WRS_MCS_10][WRS_GI_VSHORT] = 10324,
+ [CHNL_BW_40][WRS_SS_4][WRS_MCS_11][WRS_GI_LONG] = 9750,
+ [CHNL_BW_40][WRS_SS_4][WRS_MCS_11][WRS_GI_SHORT] = 10833,
+ [CHNL_BW_40][WRS_SS_4][WRS_MCS_11][WRS_GI_VSHORT] = 11471,
+ [CHNL_BW_80][WRS_SS_1][WRS_MCS_0][WRS_GI_LONG] = 306,
+ [CHNL_BW_80][WRS_SS_1][WRS_MCS_0][WRS_GI_SHORT] = 340,
+ [CHNL_BW_80][WRS_SS_1][WRS_MCS_0][WRS_GI_VSHORT] = 360,
+ [CHNL_BW_80][WRS_SS_1][WRS_MCS_1][WRS_GI_LONG] = 613,
+ [CHNL_BW_80][WRS_SS_1][WRS_MCS_1][WRS_GI_SHORT] = 681,
+ [CHNL_BW_80][WRS_SS_1][WRS_MCS_1][WRS_GI_VSHORT] = 721,
+ [CHNL_BW_80][WRS_SS_1][WRS_MCS_2][WRS_GI_LONG] = 919,
+ [CHNL_BW_80][WRS_SS_1][WRS_MCS_2][WRS_GI_SHORT] = 1021,
+ [CHNL_BW_80][WRS_SS_1][WRS_MCS_2][WRS_GI_VSHORT] = 1081,
+ [CHNL_BW_80][WRS_SS_1][WRS_MCS_3][WRS_GI_LONG] = 1225,
+ [CHNL_BW_80][WRS_SS_1][WRS_MCS_3][WRS_GI_SHORT] = 1361,
+ [CHNL_BW_80][WRS_SS_1][WRS_MCS_3][WRS_GI_VSHORT] = 1441,
+ [CHNL_BW_80][WRS_SS_1][WRS_MCS_4][WRS_GI_LONG] = 1838,
+ [CHNL_BW_80][WRS_SS_1][WRS_MCS_4][WRS_GI_SHORT] = 2042,
+ [CHNL_BW_80][WRS_SS_1][WRS_MCS_4][WRS_GI_VSHORT] = 2162,
+ [CHNL_BW_80][WRS_SS_1][WRS_MCS_5][WRS_GI_LONG] = 2450,
+ [CHNL_BW_80][WRS_SS_1][WRS_MCS_5][WRS_GI_SHORT] = 2722,
+ [CHNL_BW_80][WRS_SS_1][WRS_MCS_5][WRS_GI_VSHORT] = 2882,
+ [CHNL_BW_80][WRS_SS_1][WRS_MCS_6][WRS_GI_LONG] = 2756,
+ [CHNL_BW_80][WRS_SS_1][WRS_MCS_6][WRS_GI_SHORT] = 3063,
+ [CHNL_BW_80][WRS_SS_1][WRS_MCS_6][WRS_GI_VSHORT] = 3243,
+ [CHNL_BW_80][WRS_SS_1][WRS_MCS_7][WRS_GI_LONG] = 3063,
+ [CHNL_BW_80][WRS_SS_1][WRS_MCS_7][WRS_GI_SHORT] = 3403,
+ [CHNL_BW_80][WRS_SS_1][WRS_MCS_7][WRS_GI_VSHORT] = 3603,
+ [CHNL_BW_80][WRS_SS_1][WRS_MCS_8][WRS_GI_LONG] = 3675,
+ [CHNL_BW_80][WRS_SS_1][WRS_MCS_8][WRS_GI_SHORT] = 4083,
+ [CHNL_BW_80][WRS_SS_1][WRS_MCS_8][WRS_GI_VSHORT] = 4324,
+ [CHNL_BW_80][WRS_SS_1][WRS_MCS_9][WRS_GI_LONG] = 4083,
+ [CHNL_BW_80][WRS_SS_1][WRS_MCS_9][WRS_GI_SHORT] = 4537,
+ [CHNL_BW_80][WRS_SS_1][WRS_MCS_9][WRS_GI_VSHORT] = 4804,
+ [CHNL_BW_80][WRS_SS_1][WRS_MCS_10][WRS_GI_LONG] = 4594,
+ [CHNL_BW_80][WRS_SS_1][WRS_MCS_10][WRS_GI_SHORT] = 5104,
+ [CHNL_BW_80][WRS_SS_1][WRS_MCS_10][WRS_GI_VSHORT] = 5404,
+ [CHNL_BW_80][WRS_SS_1][WRS_MCS_11][WRS_GI_LONG] = 5104,
+ [CHNL_BW_80][WRS_SS_1][WRS_MCS_11][WRS_GI_SHORT] = 5671,
+ [CHNL_BW_80][WRS_SS_1][WRS_MCS_11][WRS_GI_VSHORT] = 6004,
+ [CHNL_BW_80][WRS_SS_2][WRS_MCS_0][WRS_GI_LONG] = 613,
+ [CHNL_BW_80][WRS_SS_2][WRS_MCS_0][WRS_GI_SHORT] = 681,
+ [CHNL_BW_80][WRS_SS_2][WRS_MCS_0][WRS_GI_VSHORT] = 721,
+ [CHNL_BW_80][WRS_SS_2][WRS_MCS_1][WRS_GI_LONG] = 1225,
+ [CHNL_BW_80][WRS_SS_2][WRS_MCS_1][WRS_GI_SHORT] = 1361,
+ [CHNL_BW_80][WRS_SS_2][WRS_MCS_1][WRS_GI_VSHORT] = 1441,
+ [CHNL_BW_80][WRS_SS_2][WRS_MCS_2][WRS_GI_LONG] = 1838,
+ [CHNL_BW_80][WRS_SS_2][WRS_MCS_2][WRS_GI_SHORT] = 2042,
+ [CHNL_BW_80][WRS_SS_2][WRS_MCS_2][WRS_GI_VSHORT] = 2162,
+ [CHNL_BW_80][WRS_SS_2][WRS_MCS_3][WRS_GI_LONG] = 2450,
+ [CHNL_BW_80][WRS_SS_2][WRS_MCS_3][WRS_GI_SHORT] = 2722,
+ [CHNL_BW_80][WRS_SS_2][WRS_MCS_3][WRS_GI_VSHORT] = 2882,
+ [CHNL_BW_80][WRS_SS_2][WRS_MCS_4][WRS_GI_LONG] = 3675,
+ [CHNL_BW_80][WRS_SS_2][WRS_MCS_4][WRS_GI_SHORT] = 4083,
+ [CHNL_BW_80][WRS_SS_2][WRS_MCS_4][WRS_GI_VSHORT] = 4324,
+ [CHNL_BW_80][WRS_SS_2][WRS_MCS_5][WRS_GI_LONG] = 4900,
+ [CHNL_BW_80][WRS_SS_2][WRS_MCS_5][WRS_GI_SHORT] = 5444,
+ [CHNL_BW_80][WRS_SS_2][WRS_MCS_5][WRS_GI_VSHORT] = 5765,
+ [CHNL_BW_80][WRS_SS_2][WRS_MCS_6][WRS_GI_LONG] = 5513,
+ [CHNL_BW_80][WRS_SS_2][WRS_MCS_6][WRS_GI_SHORT] = 6125,
+ [CHNL_BW_80][WRS_SS_2][WRS_MCS_6][WRS_GI_VSHORT] = 6485,
+ [CHNL_BW_80][WRS_SS_2][WRS_MCS_7][WRS_GI_LONG] = 6125,
+ [CHNL_BW_80][WRS_SS_2][WRS_MCS_7][WRS_GI_SHORT] = 6806,
+ [CHNL_BW_80][WRS_SS_2][WRS_MCS_7][WRS_GI_VSHORT] = 7206,
+ [CHNL_BW_80][WRS_SS_2][WRS_MCS_8][WRS_GI_LONG] = 7350,
+ [CHNL_BW_80][WRS_SS_2][WRS_MCS_8][WRS_GI_SHORT] = 8167,
+ [CHNL_BW_80][WRS_SS_2][WRS_MCS_8][WRS_GI_VSHORT] = 8647,
+ [CHNL_BW_80][WRS_SS_2][WRS_MCS_9][WRS_GI_LONG] = 8166,
+ [CHNL_BW_80][WRS_SS_2][WRS_MCS_9][WRS_GI_SHORT] = 9074,
+ [CHNL_BW_80][WRS_SS_2][WRS_MCS_9][WRS_GI_VSHORT] = 9607,
+ [CHNL_BW_80][WRS_SS_2][WRS_MCS_10][WRS_GI_LONG] = 9188,
+ [CHNL_BW_80][WRS_SS_2][WRS_MCS_10][WRS_GI_SHORT] = 10208,
+ [CHNL_BW_80][WRS_SS_2][WRS_MCS_10][WRS_GI_VSHORT] = 10809,
+ [CHNL_BW_80][WRS_SS_2][WRS_MCS_11][WRS_GI_LONG] = 10208,
+ [CHNL_BW_80][WRS_SS_2][WRS_MCS_11][WRS_GI_SHORT] = 11343,
+ [CHNL_BW_80][WRS_SS_2][WRS_MCS_11][WRS_GI_VSHORT] = 12010,
+ [CHNL_BW_80][WRS_SS_3][WRS_MCS_0][WRS_GI_LONG] = 919,
+ [CHNL_BW_80][WRS_SS_3][WRS_MCS_0][WRS_GI_SHORT] = 1021,
+ [CHNL_BW_80][WRS_SS_3][WRS_MCS_0][WRS_GI_VSHORT] = 1081,
+ [CHNL_BW_80][WRS_SS_3][WRS_MCS_1][WRS_GI_LONG] = 1838,
+ [CHNL_BW_80][WRS_SS_3][WRS_MCS_1][WRS_GI_SHORT] = 2042,
+ [CHNL_BW_80][WRS_SS_3][WRS_MCS_1][WRS_GI_VSHORT] = 2162,
+ [CHNL_BW_80][WRS_SS_3][WRS_MCS_2][WRS_GI_LONG] = 2756,
+ [CHNL_BW_80][WRS_SS_3][WRS_MCS_2][WRS_GI_SHORT] = 3063,
+ [CHNL_BW_80][WRS_SS_3][WRS_MCS_2][WRS_GI_VSHORT] = 3243,
+ [CHNL_BW_80][WRS_SS_3][WRS_MCS_3][WRS_GI_LONG] = 3675,
+ [CHNL_BW_80][WRS_SS_3][WRS_MCS_3][WRS_GI_SHORT] = 4083,
+ [CHNL_BW_80][WRS_SS_3][WRS_MCS_3][WRS_GI_VSHORT] = 4324,
+ [CHNL_BW_80][WRS_SS_3][WRS_MCS_4][WRS_GI_LONG] = 5513,
+ [CHNL_BW_80][WRS_SS_3][WRS_MCS_4][WRS_GI_SHORT] = 6125,
+ [CHNL_BW_80][WRS_SS_3][WRS_MCS_4][WRS_GI_VSHORT] = 6485,
+ [CHNL_BW_80][WRS_SS_3][WRS_MCS_5][WRS_GI_LONG] = 7350,
+ [CHNL_BW_80][WRS_SS_3][WRS_MCS_5][WRS_GI_SHORT] = 8167,
+ [CHNL_BW_80][WRS_SS_3][WRS_MCS_5][WRS_GI_VSHORT] = 8647,
+ [CHNL_BW_80][WRS_SS_3][WRS_MCS_6][WRS_GI_LONG] = 8269,
+ [CHNL_BW_80][WRS_SS_3][WRS_MCS_6][WRS_GI_SHORT] = 9188,
+ [CHNL_BW_80][WRS_SS_3][WRS_MCS_6][WRS_GI_VSHORT] = 9728,
+ [CHNL_BW_80][WRS_SS_3][WRS_MCS_7][WRS_GI_LONG] = 9188,
+ [CHNL_BW_80][WRS_SS_3][WRS_MCS_7][WRS_GI_SHORT] = 10208,
+ [CHNL_BW_80][WRS_SS_3][WRS_MCS_7][WRS_GI_VSHORT] = 10809,
+ [CHNL_BW_80][WRS_SS_3][WRS_MCS_8][WRS_GI_LONG] = 11025,
+ [CHNL_BW_80][WRS_SS_3][WRS_MCS_8][WRS_GI_SHORT] = 12250,
+ [CHNL_BW_80][WRS_SS_3][WRS_MCS_8][WRS_GI_VSHORT] = 12971,
+ [CHNL_BW_80][WRS_SS_3][WRS_MCS_9][WRS_GI_LONG] = 12250,
+ [CHNL_BW_80][WRS_SS_3][WRS_MCS_9][WRS_GI_SHORT] = 13611,
+ [CHNL_BW_80][WRS_SS_3][WRS_MCS_9][WRS_GI_VSHORT] = 14412,
+ [CHNL_BW_80][WRS_SS_3][WRS_MCS_10][WRS_GI_LONG] = 13781,
+ [CHNL_BW_80][WRS_SS_3][WRS_MCS_10][WRS_GI_SHORT] = 15313,
+ [CHNL_BW_80][WRS_SS_3][WRS_MCS_10][WRS_GI_VSHORT] = 16213,
+ [CHNL_BW_80][WRS_SS_3][WRS_MCS_11][WRS_GI_LONG] = 15313,
+ [CHNL_BW_80][WRS_SS_3][WRS_MCS_11][WRS_GI_SHORT] = 17014,
+ [CHNL_BW_80][WRS_SS_3][WRS_MCS_11][WRS_GI_VSHORT] = 18015,
+ [CHNL_BW_80][WRS_SS_4][WRS_MCS_0][WRS_GI_LONG] = 1225,
+ [CHNL_BW_80][WRS_SS_4][WRS_MCS_0][WRS_GI_SHORT] = 1361,
+ [CHNL_BW_80][WRS_SS_4][WRS_MCS_0][WRS_GI_VSHORT] = 1441,
+ [CHNL_BW_80][WRS_SS_4][WRS_MCS_1][WRS_GI_LONG] = 2450,
+ [CHNL_BW_80][WRS_SS_4][WRS_MCS_1][WRS_GI_SHORT] = 2722,
+ [CHNL_BW_80][WRS_SS_4][WRS_MCS_1][WRS_GI_VSHORT] = 2882,
+ [CHNL_BW_80][WRS_SS_4][WRS_MCS_2][WRS_GI_LONG] = 3675,
+ [CHNL_BW_80][WRS_SS_4][WRS_MCS_2][WRS_GI_SHORT] = 4083,
+ [CHNL_BW_80][WRS_SS_4][WRS_MCS_2][WRS_GI_VSHORT] = 4324,
+ [CHNL_BW_80][WRS_SS_4][WRS_MCS_3][WRS_GI_LONG] = 4900,
+ [CHNL_BW_80][WRS_SS_4][WRS_MCS_3][WRS_GI_SHORT] = 5444,
+ [CHNL_BW_80][WRS_SS_4][WRS_MCS_3][WRS_GI_VSHORT] = 5765,
+ [CHNL_BW_80][WRS_SS_4][WRS_MCS_4][WRS_GI_LONG] = 7350,
+ [CHNL_BW_80][WRS_SS_4][WRS_MCS_4][WRS_GI_SHORT] = 8167,
+ [CHNL_BW_80][WRS_SS_4][WRS_MCS_4][WRS_GI_VSHORT] = 8647,
+ [CHNL_BW_80][WRS_SS_4][WRS_MCS_5][WRS_GI_LONG] = 9800,
+ [CHNL_BW_80][WRS_SS_4][WRS_MCS_5][WRS_GI_SHORT] = 10889,
+ [CHNL_BW_80][WRS_SS_4][WRS_MCS_5][WRS_GI_VSHORT] = 11529,
+ [CHNL_BW_80][WRS_SS_4][WRS_MCS_6][WRS_GI_LONG] = 11025,
+ [CHNL_BW_80][WRS_SS_4][WRS_MCS_6][WRS_GI_SHORT] = 12250,
+ [CHNL_BW_80][WRS_SS_4][WRS_MCS_6][WRS_GI_VSHORT] = 12971,
+ [CHNL_BW_80][WRS_SS_4][WRS_MCS_7][WRS_GI_LONG] = 12250,
+ [CHNL_BW_80][WRS_SS_4][WRS_MCS_7][WRS_GI_SHORT] = 13611,
+ [CHNL_BW_80][WRS_SS_4][WRS_MCS_7][WRS_GI_VSHORT] = 14412,
+ [CHNL_BW_80][WRS_SS_4][WRS_MCS_8][WRS_GI_LONG] = 14700,
+ [CHNL_BW_80][WRS_SS_4][WRS_MCS_8][WRS_GI_SHORT] = 16333,
+ [CHNL_BW_80][WRS_SS_4][WRS_MCS_8][WRS_GI_VSHORT] = 17294,
+ [CHNL_BW_80][WRS_SS_4][WRS_MCS_9][WRS_GI_LONG] = 16333,
+ [CHNL_BW_80][WRS_SS_4][WRS_MCS_9][WRS_GI_SHORT] = 18148,
+ [CHNL_BW_80][WRS_SS_4][WRS_MCS_9][WRS_GI_VSHORT] = 19215,
+ [CHNL_BW_80][WRS_SS_4][WRS_MCS_10][WRS_GI_LONG] = 18375,
+ [CHNL_BW_80][WRS_SS_4][WRS_MCS_10][WRS_GI_SHORT] = 20417,
+ [CHNL_BW_80][WRS_SS_4][WRS_MCS_10][WRS_GI_VSHORT] = 21618,
+ [CHNL_BW_80][WRS_SS_4][WRS_MCS_11][WRS_GI_LONG] = 20416,
+ [CHNL_BW_80][WRS_SS_4][WRS_MCS_11][WRS_GI_SHORT] = 22685,
+ [CHNL_BW_80][WRS_SS_4][WRS_MCS_11][WRS_GI_VSHORT] = 24019,
+ [CHNL_BW_160][WRS_SS_1][WRS_MCS_0][WRS_GI_LONG] = 613,
+ [CHNL_BW_160][WRS_SS_1][WRS_MCS_0][WRS_GI_SHORT] = 681,
+ [CHNL_BW_160][WRS_SS_1][WRS_MCS_0][WRS_GI_VSHORT] = 721,
+ [CHNL_BW_160][WRS_SS_1][WRS_MCS_1][WRS_GI_LONG] = 1225,
+ [CHNL_BW_160][WRS_SS_1][WRS_MCS_1][WRS_GI_SHORT] = 1361,
+ [CHNL_BW_160][WRS_SS_1][WRS_MCS_1][WRS_GI_VSHORT] = 1441,
+ [CHNL_BW_160][WRS_SS_1][WRS_MCS_2][WRS_GI_LONG] = 1838,
+ [CHNL_BW_160][WRS_SS_1][WRS_MCS_2][WRS_GI_SHORT] = 2042,
+ [CHNL_BW_160][WRS_SS_1][WRS_MCS_2][WRS_GI_VSHORT] = 2162,
+ [CHNL_BW_160][WRS_SS_1][WRS_MCS_3][WRS_GI_LONG] = 2450,
+ [CHNL_BW_160][WRS_SS_1][WRS_MCS_3][WRS_GI_SHORT] = 2722,
+ [CHNL_BW_160][WRS_SS_1][WRS_MCS_3][WRS_GI_VSHORT] = 2882,
+ [CHNL_BW_160][WRS_SS_1][WRS_MCS_4][WRS_GI_LONG] = 3675,
+ [CHNL_BW_160][WRS_SS_1][WRS_MCS_4][WRS_GI_SHORT] = 4083,
+ [CHNL_BW_160][WRS_SS_1][WRS_MCS_4][WRS_GI_VSHORT] = 4324,
+ [CHNL_BW_160][WRS_SS_1][WRS_MCS_5][WRS_GI_LONG] = 4900,
+ [CHNL_BW_160][WRS_SS_1][WRS_MCS_5][WRS_GI_SHORT] = 5444,
+ [CHNL_BW_160][WRS_SS_1][WRS_MCS_5][WRS_GI_VSHORT] = 5765,
+ [CHNL_BW_160][WRS_SS_1][WRS_MCS_6][WRS_GI_LONG] = 5513,
+ [CHNL_BW_160][WRS_SS_1][WRS_MCS_6][WRS_GI_SHORT] = 6125,
+ [CHNL_BW_160][WRS_SS_1][WRS_MCS_6][WRS_GI_VSHORT] = 6485,
+ [CHNL_BW_160][WRS_SS_1][WRS_MCS_7][WRS_GI_LONG] = 6125,
+ [CHNL_BW_160][WRS_SS_1][WRS_MCS_7][WRS_GI_SHORT] = 6806,
+ [CHNL_BW_160][WRS_SS_1][WRS_MCS_7][WRS_GI_VSHORT] = 7206,
+ [CHNL_BW_160][WRS_SS_1][WRS_MCS_8][WRS_GI_LONG] = 7350,
+ [CHNL_BW_160][WRS_SS_1][WRS_MCS_8][WRS_GI_SHORT] = 8167,
+ [CHNL_BW_160][WRS_SS_1][WRS_MCS_8][WRS_GI_VSHORT] = 8647,
+ [CHNL_BW_160][WRS_SS_1][WRS_MCS_9][WRS_GI_LONG] = 8166,
+ [CHNL_BW_160][WRS_SS_1][WRS_MCS_9][WRS_GI_SHORT] = 9074,
+ [CHNL_BW_160][WRS_SS_1][WRS_MCS_9][WRS_GI_VSHORT] = 9607,
+ [CHNL_BW_160][WRS_SS_1][WRS_MCS_10][WRS_GI_LONG] = 9188,
+ [CHNL_BW_160][WRS_SS_1][WRS_MCS_10][WRS_GI_SHORT] = 10208,
+ [CHNL_BW_160][WRS_SS_1][WRS_MCS_10][WRS_GI_VSHORT] = 10809,
+ [CHNL_BW_160][WRS_SS_1][WRS_MCS_11][WRS_GI_LONG] = 10208,
+ [CHNL_BW_160][WRS_SS_1][WRS_MCS_11][WRS_GI_SHORT] = 11342,
+ [CHNL_BW_160][WRS_SS_1][WRS_MCS_11][WRS_GI_VSHORT] = 12010,
+ [CHNL_BW_160][WRS_SS_2][WRS_MCS_0][WRS_GI_LONG] = 1225,
+ [CHNL_BW_160][WRS_SS_2][WRS_MCS_0][WRS_GI_SHORT] = 1361,
+ [CHNL_BW_160][WRS_SS_2][WRS_MCS_0][WRS_GI_VSHORT] = 1441,
+ [CHNL_BW_160][WRS_SS_2][WRS_MCS_1][WRS_GI_LONG] = 2450,
+ [CHNL_BW_160][WRS_SS_2][WRS_MCS_1][WRS_GI_SHORT] = 2722,
+ [CHNL_BW_160][WRS_SS_2][WRS_MCS_1][WRS_GI_VSHORT] = 2882,
+ [CHNL_BW_160][WRS_SS_2][WRS_MCS_2][WRS_GI_LONG] = 3675,
+ [CHNL_BW_160][WRS_SS_2][WRS_MCS_2][WRS_GI_SHORT] = 4083,
+ [CHNL_BW_160][WRS_SS_2][WRS_MCS_2][WRS_GI_VSHORT] = 4324,
+ [CHNL_BW_160][WRS_SS_2][WRS_MCS_3][WRS_GI_LONG] = 4900,
+ [CHNL_BW_160][WRS_SS_2][WRS_MCS_3][WRS_GI_SHORT] = 5444,
+ [CHNL_BW_160][WRS_SS_2][WRS_MCS_3][WRS_GI_VSHORT] = 5765,
+ [CHNL_BW_160][WRS_SS_2][WRS_MCS_4][WRS_GI_LONG] = 7350,
+ [CHNL_BW_160][WRS_SS_2][WRS_MCS_4][WRS_GI_SHORT] = 8167,
+ [CHNL_BW_160][WRS_SS_2][WRS_MCS_4][WRS_GI_VSHORT] = 8647,
+ [CHNL_BW_160][WRS_SS_2][WRS_MCS_5][WRS_GI_LONG] = 9800,
+ [CHNL_BW_160][WRS_SS_2][WRS_MCS_5][WRS_GI_SHORT] = 10889,
+ [CHNL_BW_160][WRS_SS_2][WRS_MCS_5][WRS_GI_VSHORT] = 11529,
+ [CHNL_BW_160][WRS_SS_2][WRS_MCS_6][WRS_GI_LONG] = 11025,
+ [CHNL_BW_160][WRS_SS_2][WRS_MCS_6][WRS_GI_SHORT] = 12250,
+ [CHNL_BW_160][WRS_SS_2][WRS_MCS_6][WRS_GI_VSHORT] = 12971,
+ [CHNL_BW_160][WRS_SS_2][WRS_MCS_7][WRS_GI_LONG] = 12250,
+ [CHNL_BW_160][WRS_SS_2][WRS_MCS_7][WRS_GI_SHORT] = 13611,
+ [CHNL_BW_160][WRS_SS_2][WRS_MCS_7][WRS_GI_VSHORT] = 14412,
+ [CHNL_BW_160][WRS_SS_2][WRS_MCS_8][WRS_GI_LONG] = 14700,
+ [CHNL_BW_160][WRS_SS_2][WRS_MCS_8][WRS_GI_SHORT] = 16333,
+ [CHNL_BW_160][WRS_SS_2][WRS_MCS_8][WRS_GI_VSHORT] = 17294,
+ [CHNL_BW_160][WRS_SS_2][WRS_MCS_9][WRS_GI_LONG] = 16333,
+ [CHNL_BW_160][WRS_SS_2][WRS_MCS_9][WRS_GI_SHORT] = 18148,
+ [CHNL_BW_160][WRS_SS_2][WRS_MCS_9][WRS_GI_VSHORT] = 19215,
+ [CHNL_BW_160][WRS_SS_2][WRS_MCS_10][WRS_GI_LONG] = 18375,
+ [CHNL_BW_160][WRS_SS_2][WRS_MCS_10][WRS_GI_SHORT] = 20417,
+ [CHNL_BW_160][WRS_SS_2][WRS_MCS_10][WRS_GI_VSHORT] = 21618,
+ [CHNL_BW_160][WRS_SS_2][WRS_MCS_11][WRS_GI_LONG] = 20416,
+ [CHNL_BW_160][WRS_SS_2][WRS_MCS_11][WRS_GI_SHORT] = 22685,
+ [CHNL_BW_160][WRS_SS_2][WRS_MCS_11][WRS_GI_VSHORT] = 24019,
+ [CHNL_BW_160][WRS_SS_3][WRS_MCS_0][WRS_GI_LONG] = 1838,
+ [CHNL_BW_160][WRS_SS_3][WRS_MCS_0][WRS_GI_SHORT] = 2042,
+ [CHNL_BW_160][WRS_SS_3][WRS_MCS_0][WRS_GI_VSHORT] = 2162,
+ [CHNL_BW_160][WRS_SS_3][WRS_MCS_1][WRS_GI_LONG] = 3675,
+ [CHNL_BW_160][WRS_SS_3][WRS_MCS_1][WRS_GI_SHORT] = 4083,
+ [CHNL_BW_160][WRS_SS_3][WRS_MCS_1][WRS_GI_VSHORT] = 4324,
+ [CHNL_BW_160][WRS_SS_3][WRS_MCS_2][WRS_GI_LONG] = 5513,
+ [CHNL_BW_160][WRS_SS_3][WRS_MCS_2][WRS_GI_SHORT] = 6125,
+ [CHNL_BW_160][WRS_SS_3][WRS_MCS_2][WRS_GI_VSHORT] = 6485,
+ [CHNL_BW_160][WRS_SS_3][WRS_MCS_3][WRS_GI_LONG] = 7350,
+ [CHNL_BW_160][WRS_SS_3][WRS_MCS_3][WRS_GI_SHORT] = 8167,
+ [CHNL_BW_160][WRS_SS_3][WRS_MCS_3][WRS_GI_VSHORT] = 8647,
+ [CHNL_BW_160][WRS_SS_3][WRS_MCS_4][WRS_GI_LONG] = 11025,
+ [CHNL_BW_160][WRS_SS_3][WRS_MCS_4][WRS_GI_SHORT] = 12250,
+ [CHNL_BW_160][WRS_SS_3][WRS_MCS_4][WRS_GI_VSHORT] = 12971,
+ [CHNL_BW_160][WRS_SS_3][WRS_MCS_5][WRS_GI_LONG] = 14700,
+ [CHNL_BW_160][WRS_SS_3][WRS_MCS_5][WRS_GI_SHORT] = 16333,
+ [CHNL_BW_160][WRS_SS_3][WRS_MCS_5][WRS_GI_VSHORT] = 17294,
+ [CHNL_BW_160][WRS_SS_3][WRS_MCS_6][WRS_GI_LONG] = 16538,
+ [CHNL_BW_160][WRS_SS_3][WRS_MCS_6][WRS_GI_SHORT] = 18375,
+ [CHNL_BW_160][WRS_SS_3][WRS_MCS_6][WRS_GI_VSHORT] = 19456,
+ [CHNL_BW_160][WRS_SS_3][WRS_MCS_7][WRS_GI_LONG] = 18375,
+ [CHNL_BW_160][WRS_SS_3][WRS_MCS_7][WRS_GI_SHORT] = 20417,
+ [CHNL_BW_160][WRS_SS_3][WRS_MCS_7][WRS_GI_VSHORT] = 21618,
+ [CHNL_BW_160][WRS_SS_3][WRS_MCS_8][WRS_GI_LONG] = 22050,
+ [CHNL_BW_160][WRS_SS_3][WRS_MCS_8][WRS_GI_SHORT] = 24500,
+ [CHNL_BW_160][WRS_SS_3][WRS_MCS_8][WRS_GI_VSHORT] = 25941,
+ [CHNL_BW_160][WRS_SS_3][WRS_MCS_9][WRS_GI_LONG] = 24500,
+ [CHNL_BW_160][WRS_SS_3][WRS_MCS_9][WRS_GI_SHORT] = 27222,
+ [CHNL_BW_160][WRS_SS_3][WRS_MCS_9][WRS_GI_VSHORT] = 28824,
+ [CHNL_BW_160][WRS_SS_3][WRS_MCS_10][WRS_GI_LONG] = 27563,
+ [CHNL_BW_160][WRS_SS_3][WRS_MCS_10][WRS_GI_SHORT] = 30625,
+ [CHNL_BW_160][WRS_SS_3][WRS_MCS_10][WRS_GI_VSHORT] = 32426,
+ [CHNL_BW_160][WRS_SS_3][WRS_MCS_11][WRS_GI_LONG] = 30625,
+ [CHNL_BW_160][WRS_SS_3][WRS_MCS_11][WRS_GI_SHORT] = 34028,
+ [CHNL_BW_160][WRS_SS_3][WRS_MCS_11][WRS_GI_VSHORT] = 36029,
+ [CHNL_BW_160][WRS_SS_4][WRS_MCS_0][WRS_GI_LONG] = 2450,
+ [CHNL_BW_160][WRS_SS_4][WRS_MCS_0][WRS_GI_SHORT] = 2722,
+ [CHNL_BW_160][WRS_SS_4][WRS_MCS_0][WRS_GI_VSHORT] = 2882,
+ [CHNL_BW_160][WRS_SS_4][WRS_MCS_1][WRS_GI_LONG] = 4900,
+ [CHNL_BW_160][WRS_SS_4][WRS_MCS_1][WRS_GI_SHORT] = 5444,
+ [CHNL_BW_160][WRS_SS_4][WRS_MCS_1][WRS_GI_VSHORT] = 5765,
+ [CHNL_BW_160][WRS_SS_4][WRS_MCS_2][WRS_GI_LONG] = 7350,
+ [CHNL_BW_160][WRS_SS_4][WRS_MCS_2][WRS_GI_SHORT] = 8167,
+ [CHNL_BW_160][WRS_SS_4][WRS_MCS_2][WRS_GI_VSHORT] = 8647,
+ [CHNL_BW_160][WRS_SS_4][WRS_MCS_3][WRS_GI_LONG] = 9800,
+ [CHNL_BW_160][WRS_SS_4][WRS_MCS_3][WRS_GI_SHORT] = 10889,
+ [CHNL_BW_160][WRS_SS_4][WRS_MCS_3][WRS_GI_VSHORT] = 11529,
+ [CHNL_BW_160][WRS_SS_4][WRS_MCS_4][WRS_GI_LONG] = 14700,
+ [CHNL_BW_160][WRS_SS_4][WRS_MCS_4][WRS_GI_SHORT] = 16333,
+ [CHNL_BW_160][WRS_SS_4][WRS_MCS_4][WRS_GI_VSHORT] = 17294,
+ [CHNL_BW_160][WRS_SS_4][WRS_MCS_5][WRS_GI_LONG] = 19600,
+ [CHNL_BW_160][WRS_SS_4][WRS_MCS_5][WRS_GI_SHORT] = 21778,
+ [CHNL_BW_160][WRS_SS_4][WRS_MCS_5][WRS_GI_VSHORT] = 23059,
+ [CHNL_BW_160][WRS_SS_4][WRS_MCS_6][WRS_GI_LONG] = 22050,
+ [CHNL_BW_160][WRS_SS_4][WRS_MCS_6][WRS_GI_SHORT] = 24500,
+ [CHNL_BW_160][WRS_SS_4][WRS_MCS_6][WRS_GI_VSHORT] = 25941,
+ [CHNL_BW_160][WRS_SS_4][WRS_MCS_7][WRS_GI_LONG] = 24500,
+ [CHNL_BW_160][WRS_SS_4][WRS_MCS_7][WRS_GI_SHORT] = 27222,
+ [CHNL_BW_160][WRS_SS_4][WRS_MCS_7][WRS_GI_VSHORT] = 28824,
+ [CHNL_BW_160][WRS_SS_4][WRS_MCS_8][WRS_GI_LONG] = 29400,
+ [CHNL_BW_160][WRS_SS_4][WRS_MCS_8][WRS_GI_SHORT] = 32667,
+ [CHNL_BW_160][WRS_SS_4][WRS_MCS_8][WRS_GI_VSHORT] = 34588,
+ [CHNL_BW_160][WRS_SS_4][WRS_MCS_9][WRS_GI_LONG] = 32666,
+ [CHNL_BW_160][WRS_SS_4][WRS_MCS_9][WRS_GI_SHORT] = 36296,
+ [CHNL_BW_160][WRS_SS_4][WRS_MCS_9][WRS_GI_VSHORT] = 38431,
+ [CHNL_BW_160][WRS_SS_4][WRS_MCS_10][WRS_GI_LONG] = 36750,
+ [CHNL_BW_160][WRS_SS_4][WRS_MCS_10][WRS_GI_SHORT] = 40833,
+ [CHNL_BW_160][WRS_SS_4][WRS_MCS_10][WRS_GI_VSHORT] = 43235,
+ [CHNL_BW_160][WRS_SS_4][WRS_MCS_11][WRS_GI_LONG] = 40833,
+ [CHNL_BW_160][WRS_SS_4][WRS_MCS_11][WRS_GI_SHORT] = 45370,
+ [CHNL_BW_160][WRS_SS_4][WRS_MCS_11][WRS_GI_VSHORT] = 48039,
+};
+
+/*
+ * This table of rates was taken from IEEE Std 802.11TM-2016, 21.5 Parameters
+ * for VHT-MCSs. The units are 1/10 Mbs. Invalid combinations are with 0's. Note
+ * that HT data rates are a subset of VHT data rates, so we can use a single
+ * table for both.
+ */
+const u16 data_rate_ht_vht_x10[CHNL_BW_MAX][WRS_SS_MAX][WRS_MCS_MAX_VHT][WRS_GI_MAX_VHT] = {
+ [CHNL_BW_20][WRS_SS_1][WRS_MCS_0][WRS_GI_LONG] = 65,
+ [CHNL_BW_20][WRS_SS_1][WRS_MCS_0][WRS_GI_SHORT] = 72,
+ [CHNL_BW_20][WRS_SS_1][WRS_MCS_1][WRS_GI_LONG] = 130,
+ [CHNL_BW_20][WRS_SS_1][WRS_MCS_1][WRS_GI_SHORT] = 144,
+ [CHNL_BW_20][WRS_SS_1][WRS_MCS_2][WRS_GI_LONG] = 195,
+ [CHNL_BW_20][WRS_SS_1][WRS_MCS_2][WRS_GI_SHORT] = 217,
+ [CHNL_BW_20][WRS_SS_1][WRS_MCS_3][WRS_GI_LONG] = 260,
+ [CHNL_BW_20][WRS_SS_1][WRS_MCS_3][WRS_GI_SHORT] = 289,
+ [CHNL_BW_20][WRS_SS_1][WRS_MCS_4][WRS_GI_LONG] = 390,
+ [CHNL_BW_20][WRS_SS_1][WRS_MCS_4][WRS_GI_SHORT] = 433,
+ [CHNL_BW_20][WRS_SS_1][WRS_MCS_5][WRS_GI_LONG] = 520,
+ [CHNL_BW_20][WRS_SS_1][WRS_MCS_5][WRS_GI_SHORT] = 578,
+ [CHNL_BW_20][WRS_SS_1][WRS_MCS_6][WRS_GI_LONG] = 585,
+ [CHNL_BW_20][WRS_SS_1][WRS_MCS_6][WRS_GI_SHORT] = 650,
+ [CHNL_BW_20][WRS_SS_1][WRS_MCS_7][WRS_GI_LONG] = 650,
+ [CHNL_BW_20][WRS_SS_1][WRS_MCS_7][WRS_GI_SHORT] = 722,
+ [CHNL_BW_20][WRS_SS_1][WRS_MCS_8][WRS_GI_LONG] = 780,
+ [CHNL_BW_20][WRS_SS_1][WRS_MCS_8][WRS_GI_SHORT] = 867,
+ [CHNL_BW_20][WRS_SS_1][WRS_MCS_9][WRS_GI_LONG] = 0,
+ [CHNL_BW_20][WRS_SS_1][WRS_MCS_9][WRS_GI_SHORT] = 0,
+ [CHNL_BW_20][WRS_SS_2][WRS_MCS_0][WRS_GI_LONG] = 130,
+ [CHNL_BW_20][WRS_SS_2][WRS_MCS_0][WRS_GI_SHORT] = 144,
+ [CHNL_BW_20][WRS_SS_2][WRS_MCS_1][WRS_GI_LONG] = 260,
+ [CHNL_BW_20][WRS_SS_2][WRS_MCS_1][WRS_GI_SHORT] = 289,
+ [CHNL_BW_20][WRS_SS_2][WRS_MCS_2][WRS_GI_LONG] = 390,
+ [CHNL_BW_20][WRS_SS_2][WRS_MCS_2][WRS_GI_SHORT] = 433,
+ [CHNL_BW_20][WRS_SS_2][WRS_MCS_3][WRS_GI_LONG] = 520,
+ [CHNL_BW_20][WRS_SS_2][WRS_MCS_3][WRS_GI_SHORT] = 578,
+ [CHNL_BW_20][WRS_SS_2][WRS_MCS_4][WRS_GI_LONG] = 780,
+ [CHNL_BW_20][WRS_SS_2][WRS_MCS_4][WRS_GI_SHORT] = 867,
+ [CHNL_BW_20][WRS_SS_2][WRS_MCS_5][WRS_GI_LONG] = 1040,
+ [CHNL_BW_20][WRS_SS_2][WRS_MCS_5][WRS_GI_SHORT] = 1156,
+ [CHNL_BW_20][WRS_SS_2][WRS_MCS_6][WRS_GI_LONG] = 1170,
+ [CHNL_BW_20][WRS_SS_2][WRS_MCS_6][WRS_GI_SHORT] = 1303,
+ [CHNL_BW_20][WRS_SS_2][WRS_MCS_7][WRS_GI_LONG] = 1300,
+ [CHNL_BW_20][WRS_SS_2][WRS_MCS_7][WRS_GI_SHORT] = 1444,
+ [CHNL_BW_20][WRS_SS_2][WRS_MCS_8][WRS_GI_LONG] = 1560,
+ [CHNL_BW_20][WRS_SS_2][WRS_MCS_8][WRS_GI_SHORT] = 1733,
+ [CHNL_BW_20][WRS_SS_2][WRS_MCS_9][WRS_GI_LONG] = 0,
+ [CHNL_BW_20][WRS_SS_2][WRS_MCS_9][WRS_GI_SHORT] = 0,
+ [CHNL_BW_20][WRS_SS_3][WRS_MCS_0][WRS_GI_LONG] = 195,
+ [CHNL_BW_20][WRS_SS_3][WRS_MCS_0][WRS_GI_SHORT] = 217,
+ [CHNL_BW_20][WRS_SS_3][WRS_MCS_1][WRS_GI_LONG] = 390,
+ [CHNL_BW_20][WRS_SS_3][WRS_MCS_1][WRS_GI_SHORT] = 433,
+ [CHNL_BW_20][WRS_SS_3][WRS_MCS_2][WRS_GI_LONG] = 585,
+ [CHNL_BW_20][WRS_SS_3][WRS_MCS_2][WRS_GI_SHORT] = 650,
+ [CHNL_BW_20][WRS_SS_3][WRS_MCS_3][WRS_GI_LONG] = 780,
+ [CHNL_BW_20][WRS_SS_3][WRS_MCS_3][WRS_GI_SHORT] = 867,
+ [CHNL_BW_20][WRS_SS_3][WRS_MCS_4][WRS_GI_LONG] = 1170,
+ [CHNL_BW_20][WRS_SS_3][WRS_MCS_4][WRS_GI_SHORT] = 1300,
+ [CHNL_BW_20][WRS_SS_3][WRS_MCS_5][WRS_GI_LONG] = 1560,
+ [CHNL_BW_20][WRS_SS_3][WRS_MCS_5][WRS_GI_SHORT] = 1733,
+ [CHNL_BW_20][WRS_SS_3][WRS_MCS_6][WRS_GI_LONG] = 1755,
+ [CHNL_BW_20][WRS_SS_3][WRS_MCS_6][WRS_GI_SHORT] = 1950,
+ [CHNL_BW_20][WRS_SS_3][WRS_MCS_7][WRS_GI_LONG] = 1950,
+ [CHNL_BW_20][WRS_SS_3][WRS_MCS_7][WRS_GI_SHORT] = 2167,
+ [CHNL_BW_20][WRS_SS_3][WRS_MCS_8][WRS_GI_LONG] = 2340,
+ [CHNL_BW_20][WRS_SS_3][WRS_MCS_8][WRS_GI_SHORT] = 2600,
+ [CHNL_BW_20][WRS_SS_3][WRS_MCS_9][WRS_GI_LONG] = 2600,
+ [CHNL_BW_20][WRS_SS_3][WRS_MCS_9][WRS_GI_SHORT] = 2889,
+ [CHNL_BW_20][WRS_SS_4][WRS_MCS_0][WRS_GI_LONG] = 260,
+ [CHNL_BW_20][WRS_SS_4][WRS_MCS_0][WRS_GI_SHORT] = 288,
+ [CHNL_BW_20][WRS_SS_4][WRS_MCS_1][WRS_GI_LONG] = 520,
+ [CHNL_BW_20][WRS_SS_4][WRS_MCS_1][WRS_GI_SHORT] = 576,
+ [CHNL_BW_20][WRS_SS_4][WRS_MCS_2][WRS_GI_LONG] = 780,
+ [CHNL_BW_20][WRS_SS_4][WRS_MCS_2][WRS_GI_SHORT] = 868,
+ [CHNL_BW_20][WRS_SS_4][WRS_MCS_3][WRS_GI_LONG] = 1040,
+ [CHNL_BW_20][WRS_SS_4][WRS_MCS_3][WRS_GI_SHORT] = 1156,
+ [CHNL_BW_20][WRS_SS_4][WRS_MCS_4][WRS_GI_LONG] = 1560,
+ [CHNL_BW_20][WRS_SS_4][WRS_MCS_4][WRS_GI_SHORT] = 1732,
+ [CHNL_BW_20][WRS_SS_4][WRS_MCS_5][WRS_GI_LONG] = 2080,
+ [CHNL_BW_20][WRS_SS_4][WRS_MCS_5][WRS_GI_SHORT] = 2312,
+ [CHNL_BW_20][WRS_SS_4][WRS_MCS_6][WRS_GI_LONG] = 2340,
+ [CHNL_BW_20][WRS_SS_4][WRS_MCS_6][WRS_GI_SHORT] = 2600,
+ [CHNL_BW_20][WRS_SS_4][WRS_MCS_7][WRS_GI_LONG] = 2600,
+ [CHNL_BW_20][WRS_SS_4][WRS_MCS_7][WRS_GI_SHORT] = 2888,
+ [CHNL_BW_20][WRS_SS_4][WRS_MCS_8][WRS_GI_LONG] = 3120,
+ [CHNL_BW_20][WRS_SS_4][WRS_MCS_8][WRS_GI_SHORT] = 3468,
+ [CHNL_BW_20][WRS_SS_4][WRS_MCS_9][WRS_GI_LONG] = 0,
+ [CHNL_BW_20][WRS_SS_4][WRS_MCS_9][WRS_GI_SHORT] = 0,
+ [CHNL_BW_40][WRS_SS_1][WRS_MCS_0][WRS_GI_LONG] = 135,
+ [CHNL_BW_40][WRS_SS_1][WRS_MCS_0][WRS_GI_SHORT] = 150,
+ [CHNL_BW_40][WRS_SS_1][WRS_MCS_1][WRS_GI_LONG] = 270,
+ [CHNL_BW_40][WRS_SS_1][WRS_MCS_1][WRS_GI_SHORT] = 300,
+ [CHNL_BW_40][WRS_SS_1][WRS_MCS_2][WRS_GI_LONG] = 405,
+ [CHNL_BW_40][WRS_SS_1][WRS_MCS_2][WRS_GI_SHORT] = 450,
+ [CHNL_BW_40][WRS_SS_1][WRS_MCS_3][WRS_GI_LONG] = 540,
+ [CHNL_BW_40][WRS_SS_1][WRS_MCS_3][WRS_GI_SHORT] = 600,
+ [CHNL_BW_40][WRS_SS_1][WRS_MCS_4][WRS_GI_LONG] = 810,
+ [CHNL_BW_40][WRS_SS_1][WRS_MCS_4][WRS_GI_SHORT] = 900,
+ [CHNL_BW_40][WRS_SS_1][WRS_MCS_5][WRS_GI_LONG] = 1080,
+ [CHNL_BW_40][WRS_SS_1][WRS_MCS_5][WRS_GI_SHORT] = 1200,
+ [CHNL_BW_40][WRS_SS_1][WRS_MCS_6][WRS_GI_LONG] = 1215,
+ [CHNL_BW_40][WRS_SS_1][WRS_MCS_6][WRS_GI_SHORT] = 1350,
+ [CHNL_BW_40][WRS_SS_1][WRS_MCS_7][WRS_GI_LONG] = 1350,
+ [CHNL_BW_40][WRS_SS_1][WRS_MCS_7][WRS_GI_SHORT] = 1500,
+ [CHNL_BW_40][WRS_SS_1][WRS_MCS_8][WRS_GI_LONG] = 1620,
+ [CHNL_BW_40][WRS_SS_1][WRS_MCS_8][WRS_GI_SHORT] = 1800,
+ [CHNL_BW_40][WRS_SS_1][WRS_MCS_9][WRS_GI_LONG] = 1800,
+ [CHNL_BW_40][WRS_SS_1][WRS_MCS_9][WRS_GI_SHORT] = 2000,
+ [CHNL_BW_40][WRS_SS_2][WRS_MCS_0][WRS_GI_LONG] = 270,
+ [CHNL_BW_40][WRS_SS_2][WRS_MCS_0][WRS_GI_SHORT] = 300,
+ [CHNL_BW_40][WRS_SS_2][WRS_MCS_1][WRS_GI_LONG] = 540,
+ [CHNL_BW_40][WRS_SS_2][WRS_MCS_1][WRS_GI_SHORT] = 600,
+ [CHNL_BW_40][WRS_SS_2][WRS_MCS_2][WRS_GI_LONG] = 810,
+ [CHNL_BW_40][WRS_SS_2][WRS_MCS_2][WRS_GI_SHORT] = 900,
+ [CHNL_BW_40][WRS_SS_2][WRS_MCS_3][WRS_GI_LONG] = 1080,
+ [CHNL_BW_40][WRS_SS_2][WRS_MCS_3][WRS_GI_SHORT] = 1200,
+ [CHNL_BW_40][WRS_SS_2][WRS_MCS_4][WRS_GI_LONG] = 1620,
+ [CHNL_BW_40][WRS_SS_2][WRS_MCS_4][WRS_GI_SHORT] = 1800,
+ [CHNL_BW_40][WRS_SS_2][WRS_MCS_5][WRS_GI_LONG] = 2160,
+ [CHNL_BW_40][WRS_SS_2][WRS_MCS_5][WRS_GI_SHORT] = 2400,
+ [CHNL_BW_40][WRS_SS_2][WRS_MCS_6][WRS_GI_LONG] = 2430,
+ [CHNL_BW_40][WRS_SS_2][WRS_MCS_6][WRS_GI_SHORT] = 2700,
+ [CHNL_BW_40][WRS_SS_2][WRS_MCS_7][WRS_GI_LONG] = 2700,
+ [CHNL_BW_40][WRS_SS_2][WRS_MCS_7][WRS_GI_SHORT] = 3000,
+ [CHNL_BW_40][WRS_SS_2][WRS_MCS_8][WRS_GI_LONG] = 3240,
+ [CHNL_BW_40][WRS_SS_2][WRS_MCS_8][WRS_GI_SHORT] = 3600,
+ [CHNL_BW_40][WRS_SS_2][WRS_MCS_9][WRS_GI_LONG] = 3600,
+ [CHNL_BW_40][WRS_SS_2][WRS_MCS_9][WRS_GI_SHORT] = 4000,
+ [CHNL_BW_40][WRS_SS_3][WRS_MCS_0][WRS_GI_LONG] = 405,
+ [CHNL_BW_40][WRS_SS_3][WRS_MCS_0][WRS_GI_SHORT] = 450,
+ [CHNL_BW_40][WRS_SS_3][WRS_MCS_1][WRS_GI_LONG] = 810,
+ [CHNL_BW_40][WRS_SS_3][WRS_MCS_1][WRS_GI_SHORT] = 900,
+ [CHNL_BW_40][WRS_SS_3][WRS_MCS_2][WRS_GI_LONG] = 1215,
+ [CHNL_BW_40][WRS_SS_3][WRS_MCS_2][WRS_GI_SHORT] = 1350,
+ [CHNL_BW_40][WRS_SS_3][WRS_MCS_3][WRS_GI_LONG] = 1620,
+ [CHNL_BW_40][WRS_SS_3][WRS_MCS_3][WRS_GI_SHORT] = 1800,
+ [CHNL_BW_40][WRS_SS_3][WRS_MCS_4][WRS_GI_LONG] = 2430,
+ [CHNL_BW_40][WRS_SS_3][WRS_MCS_4][WRS_GI_SHORT] = 2700,
+ [CHNL_BW_40][WRS_SS_3][WRS_MCS_5][WRS_GI_LONG] = 3240,
+ [CHNL_BW_40][WRS_SS_3][WRS_MCS_5][WRS_GI_SHORT] = 3600,
+ [CHNL_BW_40][WRS_SS_3][WRS_MCS_6][WRS_GI_LONG] = 3645,
+ [CHNL_BW_40][WRS_SS_3][WRS_MCS_6][WRS_GI_SHORT] = 4050,
+ [CHNL_BW_40][WRS_SS_3][WRS_MCS_7][WRS_GI_LONG] = 4050,
+ [CHNL_BW_40][WRS_SS_3][WRS_MCS_7][WRS_GI_SHORT] = 4500,
+ [CHNL_BW_40][WRS_SS_3][WRS_MCS_8][WRS_GI_LONG] = 4860,
+ [CHNL_BW_40][WRS_SS_3][WRS_MCS_8][WRS_GI_SHORT] = 5400,
+ [CHNL_BW_40][WRS_SS_3][WRS_MCS_9][WRS_GI_LONG] = 5400,
+ [CHNL_BW_40][WRS_SS_3][WRS_MCS_9][WRS_GI_SHORT] = 6000,
+ [CHNL_BW_40][WRS_SS_4][WRS_MCS_0][WRS_GI_LONG] = 540,
+ [CHNL_BW_40][WRS_SS_4][WRS_MCS_0][WRS_GI_SHORT] = 600,
+ [CHNL_BW_40][WRS_SS_4][WRS_MCS_1][WRS_GI_LONG] = 1080,
+ [CHNL_BW_40][WRS_SS_4][WRS_MCS_1][WRS_GI_SHORT] = 1200,
+ [CHNL_BW_40][WRS_SS_4][WRS_MCS_2][WRS_GI_LONG] = 1620,
+ [CHNL_BW_40][WRS_SS_4][WRS_MCS_2][WRS_GI_SHORT] = 1800,
+ [CHNL_BW_40][WRS_SS_4][WRS_MCS_3][WRS_GI_LONG] = 2160,
+ [CHNL_BW_40][WRS_SS_4][WRS_MCS_3][WRS_GI_SHORT] = 2400,
+ [CHNL_BW_40][WRS_SS_4][WRS_MCS_4][WRS_GI_LONG] = 3240,
+ [CHNL_BW_40][WRS_SS_4][WRS_MCS_4][WRS_GI_SHORT] = 3600,
+ [CHNL_BW_40][WRS_SS_4][WRS_MCS_5][WRS_GI_LONG] = 4320,
+ [CHNL_BW_40][WRS_SS_4][WRS_MCS_5][WRS_GI_SHORT] = 4800,
+ [CHNL_BW_40][WRS_SS_4][WRS_MCS_6][WRS_GI_LONG] = 4860,
+ [CHNL_BW_40][WRS_SS_4][WRS_MCS_6][WRS_GI_SHORT] = 5400,
+ [CHNL_BW_40][WRS_SS_4][WRS_MCS_7][WRS_GI_LONG] = 5400,
+ [CHNL_BW_40][WRS_SS_4][WRS_MCS_7][WRS_GI_SHORT] = 6000,
+ [CHNL_BW_40][WRS_SS_4][WRS_MCS_8][WRS_GI_LONG] = 6480,
+ [CHNL_BW_40][WRS_SS_4][WRS_MCS_8][WRS_GI_SHORT] = 7200,
+ [CHNL_BW_40][WRS_SS_4][WRS_MCS_9][WRS_GI_LONG] = 7200,
+ [CHNL_BW_40][WRS_SS_4][WRS_MCS_9][WRS_GI_SHORT] = 8000,
+ [CHNL_BW_80][WRS_SS_1][WRS_MCS_0][WRS_GI_LONG] = 293,
+ [CHNL_BW_80][WRS_SS_1][WRS_MCS_0][WRS_GI_SHORT] = 325,
+ [CHNL_BW_80][WRS_SS_1][WRS_MCS_1][WRS_GI_LONG] = 585,
+ [CHNL_BW_80][WRS_SS_1][WRS_MCS_1][WRS_GI_SHORT] = 650,
+ [CHNL_BW_80][WRS_SS_1][WRS_MCS_2][WRS_GI_LONG] = 878,
+ [CHNL_BW_80][WRS_SS_1][WRS_MCS_2][WRS_GI_SHORT] = 975,
+ [CHNL_BW_80][WRS_SS_1][WRS_MCS_3][WRS_GI_LONG] = 1170,
+ [CHNL_BW_80][WRS_SS_1][WRS_MCS_3][WRS_GI_SHORT] = 1300,
+ [CHNL_BW_80][WRS_SS_1][WRS_MCS_4][WRS_GI_LONG] = 1755,
+ [CHNL_BW_80][WRS_SS_1][WRS_MCS_4][WRS_GI_SHORT] = 1950,
+ [CHNL_BW_80][WRS_SS_1][WRS_MCS_5][WRS_GI_LONG] = 2340,
+ [CHNL_BW_80][WRS_SS_1][WRS_MCS_5][WRS_GI_SHORT] = 2600,
+ [CHNL_BW_80][WRS_SS_1][WRS_MCS_6][WRS_GI_LONG] = 2633,
+ [CHNL_BW_80][WRS_SS_1][WRS_MCS_6][WRS_GI_SHORT] = 2925,
+ [CHNL_BW_80][WRS_SS_1][WRS_MCS_7][WRS_GI_LONG] = 2925,
+ [CHNL_BW_80][WRS_SS_1][WRS_MCS_7][WRS_GI_SHORT] = 3250,
+ [CHNL_BW_80][WRS_SS_1][WRS_MCS_8][WRS_GI_LONG] = 3510,
+ [CHNL_BW_80][WRS_SS_1][WRS_MCS_8][WRS_GI_SHORT] = 3900,
+ [CHNL_BW_80][WRS_SS_1][WRS_MCS_9][WRS_GI_LONG] = 3900,
+ [CHNL_BW_80][WRS_SS_1][WRS_MCS_9][WRS_GI_SHORT] = 4333,
+ [CHNL_BW_80][WRS_SS_2][WRS_MCS_0][WRS_GI_LONG] = 585,
+ [CHNL_BW_80][WRS_SS_2][WRS_MCS_0][WRS_GI_SHORT] = 650,
+ [CHNL_BW_80][WRS_SS_2][WRS_MCS_1][WRS_GI_LONG] = 1170,
+ [CHNL_BW_80][WRS_SS_2][WRS_MCS_1][WRS_GI_SHORT] = 1300,
+ [CHNL_BW_80][WRS_SS_2][WRS_MCS_2][WRS_GI_LONG] = 1755,
+ [CHNL_BW_80][WRS_SS_2][WRS_MCS_2][WRS_GI_SHORT] = 1950,
+ [CHNL_BW_80][WRS_SS_2][WRS_MCS_3][WRS_GI_LONG] = 2340,
+ [CHNL_BW_80][WRS_SS_2][WRS_MCS_3][WRS_GI_SHORT] = 2600,
+ [CHNL_BW_80][WRS_SS_2][WRS_MCS_4][WRS_GI_LONG] = 3510,
+ [CHNL_BW_80][WRS_SS_2][WRS_MCS_4][WRS_GI_SHORT] = 3900,
+ [CHNL_BW_80][WRS_SS_2][WRS_MCS_5][WRS_GI_LONG] = 4680,
+ [CHNL_BW_80][WRS_SS_2][WRS_MCS_5][WRS_GI_SHORT] = 5200,
+ [CHNL_BW_80][WRS_SS_2][WRS_MCS_6][WRS_GI_LONG] = 5265,
+ [CHNL_BW_80][WRS_SS_2][WRS_MCS_6][WRS_GI_SHORT] = 5850,
+ [CHNL_BW_80][WRS_SS_2][WRS_MCS_7][WRS_GI_LONG] = 5850,
+ [CHNL_BW_80][WRS_SS_2][WRS_MCS_7][WRS_GI_SHORT] = 6500,
+ [CHNL_BW_80][WRS_SS_2][WRS_MCS_8][WRS_GI_LONG] = 7020,
+ [CHNL_BW_80][WRS_SS_2][WRS_MCS_8][WRS_GI_SHORT] = 7800,
+ [CHNL_BW_80][WRS_SS_2][WRS_MCS_9][WRS_GI_LONG] = 7800,
+ [CHNL_BW_80][WRS_SS_2][WRS_MCS_9][WRS_GI_SHORT] = 8667,
+ [CHNL_BW_80][WRS_SS_3][WRS_MCS_0][WRS_GI_LONG] = 878,
+ [CHNL_BW_80][WRS_SS_3][WRS_MCS_0][WRS_GI_SHORT] = 975,
+ [CHNL_BW_80][WRS_SS_3][WRS_MCS_1][WRS_GI_LONG] = 1755,
+ [CHNL_BW_80][WRS_SS_3][WRS_MCS_1][WRS_GI_SHORT] = 1950,
+ [CHNL_BW_80][WRS_SS_3][WRS_MCS_2][WRS_GI_LONG] = 2633,
+ [CHNL_BW_80][WRS_SS_3][WRS_MCS_2][WRS_GI_SHORT] = 2925,
+ [CHNL_BW_80][WRS_SS_3][WRS_MCS_3][WRS_GI_LONG] = 3510,
+ [CHNL_BW_80][WRS_SS_3][WRS_MCS_3][WRS_GI_SHORT] = 3900,
+ [CHNL_BW_80][WRS_SS_3][WRS_MCS_4][WRS_GI_LONG] = 5265,
+ [CHNL_BW_80][WRS_SS_3][WRS_MCS_4][WRS_GI_SHORT] = 5850,
+ [CHNL_BW_80][WRS_SS_3][WRS_MCS_5][WRS_GI_LONG] = 7020,
+ [CHNL_BW_80][WRS_SS_3][WRS_MCS_5][WRS_GI_SHORT] = 7800,
+ [CHNL_BW_80][WRS_SS_3][WRS_MCS_6][WRS_GI_LONG] = 0,
+ [CHNL_BW_80][WRS_SS_3][WRS_MCS_6][WRS_GI_SHORT] = 0,
+ [CHNL_BW_80][WRS_SS_3][WRS_MCS_7][WRS_GI_LONG] = 8775,
+ [CHNL_BW_80][WRS_SS_3][WRS_MCS_7][WRS_GI_SHORT] = 9750,
+ [CHNL_BW_80][WRS_SS_3][WRS_MCS_8][WRS_GI_LONG] = 10530,
+ [CHNL_BW_80][WRS_SS_3][WRS_MCS_8][WRS_GI_SHORT] = 11700,
+ [CHNL_BW_80][WRS_SS_3][WRS_MCS_9][WRS_GI_LONG] = 11700,
+ [CHNL_BW_80][WRS_SS_3][WRS_MCS_9][WRS_GI_SHORT] = 13000,
+ [CHNL_BW_80][WRS_SS_4][WRS_MCS_0][WRS_GI_LONG] = 1172,
+ [CHNL_BW_80][WRS_SS_4][WRS_MCS_0][WRS_GI_SHORT] = 1300,
+ [CHNL_BW_80][WRS_SS_4][WRS_MCS_1][WRS_GI_LONG] = 2340,
+ [CHNL_BW_80][WRS_SS_4][WRS_MCS_1][WRS_GI_SHORT] = 2600,
+ [CHNL_BW_80][WRS_SS_4][WRS_MCS_2][WRS_GI_LONG] = 3512,
+ [CHNL_BW_80][WRS_SS_4][WRS_MCS_2][WRS_GI_SHORT] = 3900,
+ [CHNL_BW_80][WRS_SS_4][WRS_MCS_3][WRS_GI_LONG] = 4680,
+ [CHNL_BW_80][WRS_SS_4][WRS_MCS_3][WRS_GI_SHORT] = 5200,
+ [CHNL_BW_80][WRS_SS_4][WRS_MCS_4][WRS_GI_LONG] = 7020,
+ [CHNL_BW_80][WRS_SS_4][WRS_MCS_4][WRS_GI_SHORT] = 7800,
+ [CHNL_BW_80][WRS_SS_4][WRS_MCS_5][WRS_GI_LONG] = 9360,
+ [CHNL_BW_80][WRS_SS_4][WRS_MCS_5][WRS_GI_SHORT] = 10400,
+ [CHNL_BW_80][WRS_SS_4][WRS_MCS_6][WRS_GI_LONG] = 10532,
+ [CHNL_BW_80][WRS_SS_4][WRS_MCS_6][WRS_GI_SHORT] = 11700,
+ [CHNL_BW_80][WRS_SS_4][WRS_MCS_7][WRS_GI_LONG] = 11700,
+ [CHNL_BW_80][WRS_SS_4][WRS_MCS_7][WRS_GI_SHORT] = 13000,
+ [CHNL_BW_80][WRS_SS_4][WRS_MCS_8][WRS_GI_LONG] = 14040,
+ [CHNL_BW_80][WRS_SS_4][WRS_MCS_8][WRS_GI_SHORT] = 15600,
+ [CHNL_BW_80][WRS_SS_4][WRS_MCS_9][WRS_GI_LONG] = 15600,
+ [CHNL_BW_80][WRS_SS_4][WRS_MCS_9][WRS_GI_SHORT] = 17332,
+ [CHNL_BW_160][WRS_SS_1][WRS_MCS_0][WRS_GI_LONG] = 585,
+ [CHNL_BW_160][WRS_SS_1][WRS_MCS_0][WRS_GI_SHORT] = 650,
+ [CHNL_BW_160][WRS_SS_1][WRS_MCS_1][WRS_GI_LONG] = 1170,
+ [CHNL_BW_160][WRS_SS_1][WRS_MCS_1][WRS_GI_SHORT] = 1300,
+ [CHNL_BW_160][WRS_SS_1][WRS_MCS_2][WRS_GI_LONG] = 1755,
+ [CHNL_BW_160][WRS_SS_1][WRS_MCS_2][WRS_GI_SHORT] = 1950,
+ [CHNL_BW_160][WRS_SS_1][WRS_MCS_3][WRS_GI_LONG] = 2340,
+ [CHNL_BW_160][WRS_SS_1][WRS_MCS_3][WRS_GI_SHORT] = 2600,
+ [CHNL_BW_160][WRS_SS_1][WRS_MCS_4][WRS_GI_LONG] = 3510,
+ [CHNL_BW_160][WRS_SS_1][WRS_MCS_4][WRS_GI_SHORT] = 3900,
+ [CHNL_BW_160][WRS_SS_1][WRS_MCS_5][WRS_GI_LONG] = 4680,
+ [CHNL_BW_160][WRS_SS_1][WRS_MCS_5][WRS_GI_SHORT] = 5200,
+ [CHNL_BW_160][WRS_SS_1][WRS_MCS_6][WRS_GI_LONG] = 5265,
+ [CHNL_BW_160][WRS_SS_1][WRS_MCS_6][WRS_GI_SHORT] = 5850,
+ [CHNL_BW_160][WRS_SS_1][WRS_MCS_7][WRS_GI_LONG] = 5850,
+ [CHNL_BW_160][WRS_SS_1][WRS_MCS_7][WRS_GI_SHORT] = 6500,
+ [CHNL_BW_160][WRS_SS_1][WRS_MCS_8][WRS_GI_LONG] = 7020,
+ [CHNL_BW_160][WRS_SS_1][WRS_MCS_8][WRS_GI_SHORT] = 7800,
+ [CHNL_BW_160][WRS_SS_1][WRS_MCS_9][WRS_GI_LONG] = 7800,
+ [CHNL_BW_160][WRS_SS_1][WRS_MCS_9][WRS_GI_SHORT] = 8667,
+ [CHNL_BW_160][WRS_SS_2][WRS_MCS_0][WRS_GI_LONG] = 1170,
+ [CHNL_BW_160][WRS_SS_2][WRS_MCS_0][WRS_GI_SHORT] = 1300,
+ [CHNL_BW_160][WRS_SS_2][WRS_MCS_1][WRS_GI_LONG] = 2340,
+ [CHNL_BW_160][WRS_SS_2][WRS_MCS_1][WRS_GI_SHORT] = 2600,
+ [CHNL_BW_160][WRS_SS_2][WRS_MCS_2][WRS_GI_LONG] = 3510,
+ [CHNL_BW_160][WRS_SS_2][WRS_MCS_2][WRS_GI_SHORT] = 3900,
+ [CHNL_BW_160][WRS_SS_2][WRS_MCS_3][WRS_GI_LONG] = 4680,
+ [CHNL_BW_160][WRS_SS_2][WRS_MCS_3][WRS_GI_SHORT] = 5200,
+ [CHNL_BW_160][WRS_SS_2][WRS_MCS_4][WRS_GI_LONG] = 7020,
+ [CHNL_BW_160][WRS_SS_2][WRS_MCS_4][WRS_GI_SHORT] = 7800,
+ [CHNL_BW_160][WRS_SS_2][WRS_MCS_5][WRS_GI_LONG] = 9360,
+ [CHNL_BW_160][WRS_SS_2][WRS_MCS_5][WRS_GI_SHORT] = 10400,
+ [CHNL_BW_160][WRS_SS_2][WRS_MCS_6][WRS_GI_LONG] = 10530,
+ [CHNL_BW_160][WRS_SS_2][WRS_MCS_6][WRS_GI_SHORT] = 11700,
+ [CHNL_BW_160][WRS_SS_2][WRS_MCS_7][WRS_GI_LONG] = 11700,
+ [CHNL_BW_160][WRS_SS_2][WRS_MCS_7][WRS_GI_SHORT] = 13000,
+ [CHNL_BW_160][WRS_SS_2][WRS_MCS_8][WRS_GI_LONG] = 14040,
+ [CHNL_BW_160][WRS_SS_2][WRS_MCS_8][WRS_GI_SHORT] = 15600,
+ [CHNL_BW_160][WRS_SS_2][WRS_MCS_9][WRS_GI_LONG] = 15600,
+ [CHNL_BW_160][WRS_SS_2][WRS_MCS_9][WRS_GI_SHORT] = 17333,
+ [CHNL_BW_160][WRS_SS_3][WRS_MCS_0][WRS_GI_LONG] = 1755,
+ [CHNL_BW_160][WRS_SS_3][WRS_MCS_0][WRS_GI_SHORT] = 1950,
+ [CHNL_BW_160][WRS_SS_3][WRS_MCS_1][WRS_GI_LONG] = 3510,
+ [CHNL_BW_160][WRS_SS_3][WRS_MCS_1][WRS_GI_SHORT] = 3900,
+ [CHNL_BW_160][WRS_SS_3][WRS_MCS_2][WRS_GI_LONG] = 5265,
+ [CHNL_BW_160][WRS_SS_3][WRS_MCS_2][WRS_GI_SHORT] = 5850,
+ [CHNL_BW_160][WRS_SS_3][WRS_MCS_3][WRS_GI_LONG] = 7020,
+ [CHNL_BW_160][WRS_SS_3][WRS_MCS_3][WRS_GI_SHORT] = 7800,
+ [CHNL_BW_160][WRS_SS_3][WRS_MCS_4][WRS_GI_LONG] = 10530,
+ [CHNL_BW_160][WRS_SS_3][WRS_MCS_4][WRS_GI_SHORT] = 11700,
+ [CHNL_BW_160][WRS_SS_3][WRS_MCS_5][WRS_GI_LONG] = 14040,
+ [CHNL_BW_160][WRS_SS_3][WRS_MCS_5][WRS_GI_SHORT] = 15600,
+ [CHNL_BW_160][WRS_SS_3][WRS_MCS_6][WRS_GI_LONG] = 15795,
+ [CHNL_BW_160][WRS_SS_3][WRS_MCS_6][WRS_GI_SHORT] = 17550,
+ [CHNL_BW_160][WRS_SS_3][WRS_MCS_7][WRS_GI_LONG] = 17550,
+ [CHNL_BW_160][WRS_SS_3][WRS_MCS_7][WRS_GI_SHORT] = 19500,
+ [CHNL_BW_160][WRS_SS_3][WRS_MCS_8][WRS_GI_LONG] = 21060,
+ [CHNL_BW_160][WRS_SS_3][WRS_MCS_8][WRS_GI_SHORT] = 23400,
+ [CHNL_BW_160][WRS_SS_3][WRS_MCS_9][WRS_GI_LONG] = 0,
+ [CHNL_BW_160][WRS_SS_3][WRS_MCS_9][WRS_GI_SHORT] = 0,
+ [CHNL_BW_160][WRS_SS_4][WRS_MCS_0][WRS_GI_LONG] = 2340,
+ [CHNL_BW_160][WRS_SS_4][WRS_MCS_0][WRS_GI_SHORT] = 2600,
+ [CHNL_BW_160][WRS_SS_4][WRS_MCS_1][WRS_GI_LONG] = 4680,
+ [CHNL_BW_160][WRS_SS_4][WRS_MCS_1][WRS_GI_SHORT] = 5200,
+ [CHNL_BW_160][WRS_SS_4][WRS_MCS_2][WRS_GI_LONG] = 7020,
+ [CHNL_BW_160][WRS_SS_4][WRS_MCS_2][WRS_GI_SHORT] = 7800,
+ [CHNL_BW_160][WRS_SS_4][WRS_MCS_3][WRS_GI_LONG] = 9360,
+ [CHNL_BW_160][WRS_SS_4][WRS_MCS_3][WRS_GI_SHORT] = 10400,
+ [CHNL_BW_160][WRS_SS_4][WRS_MCS_4][WRS_GI_LONG] = 10400,
+ [CHNL_BW_160][WRS_SS_4][WRS_MCS_4][WRS_GI_SHORT] = 15600,
+ [CHNL_BW_160][WRS_SS_4][WRS_MCS_5][WRS_GI_LONG] = 18720,
+ [CHNL_BW_160][WRS_SS_4][WRS_MCS_5][WRS_GI_SHORT] = 20800,
+ [CHNL_BW_160][WRS_SS_4][WRS_MCS_6][WRS_GI_LONG] = 21060,
+ [CHNL_BW_160][WRS_SS_4][WRS_MCS_6][WRS_GI_SHORT] = 23400,
+ [CHNL_BW_160][WRS_SS_4][WRS_MCS_7][WRS_GI_LONG] = 23400,
+ [CHNL_BW_160][WRS_SS_4][WRS_MCS_7][WRS_GI_SHORT] = 26000,
+ [CHNL_BW_160][WRS_SS_4][WRS_MCS_8][WRS_GI_LONG] = 28080,
+ [CHNL_BW_160][WRS_SS_4][WRS_MCS_8][WRS_GI_SHORT] = 31200,
+ [CHNL_BW_160][WRS_SS_4][WRS_MCS_9][WRS_GI_LONG] = 31200,
+ [CHNL_BW_160][WRS_SS_4][WRS_MCS_9][WRS_GI_SHORT] = 34667,
+};
+
+/* OFDM Data Rates - (multiplied by 10) */
+const u16 data_rate_ofdm_x10[] = {
+ 60,
+ 90,
+ 120,
+ 180,
+ 240,
+ 360,
+ 480,
+ 540,
+};
+
+/* CCK Data Rates - (multiplied by 10) */
+const u16 data_rate_cck_x10[] = {
+ 10,
+ 20,
+ 55,
+ 110,
+};
+
+struct cl_inverse_data_rate inverse_data_rate;
+
+static u16 cl_data_rates_inverse_he(u8 bw, u8 nss, u8 mcs, u8 gi)
+{
+ return (80 << DATA_RATE_INVERSE_Q) / data_rate_he_x10[bw][nss][mcs][gi];
+}
+
+static u16 cl_data_rates_inverse_vht(u8 bw, u8 nss, u8 mcs, u8 gi)
+{
+ u16 data_rate = data_rate_ht_vht_x10[bw][nss][mcs][gi];
+
+ if (data_rate)
+ return (80 << DATA_RATE_INVERSE_Q) / data_rate;
+
+ return 0;
+}
+
+static u16 cl_data_rates_inverse_ofdm(u8 mcs)
+{
+ return (80 << DATA_RATE_INVERSE_Q) / data_rate_ofdm_x10[mcs];
+}
+
+static u16 cl_data_rates_inverse_cck(u8 mcs)
+{
+ return (80 << DATA_RATE_INVERSE_Q) / data_rate_cck_x10[mcs];
+}
+
+void cl_data_rates_inverse_build(void)
+{
+ /*
+ * The calculation is: round((2^15[Q] * 8[bits] * 10)/rate[Mbps]) - unit (us * 2^15)
+ * multiply by 10 because data rates in the above tables are also multiplied by 10
+ */
+ u8 bw, nss, mcs, gi;
+
+ for (bw = 0; bw < CHNL_BW_MAX; bw++)
+ for (nss = 0; nss < WRS_SS_MAX; nss++) {
+ /* HE */
+ for (mcs = 0; mcs < WRS_MCS_MAX_HE; mcs++)
+ for (gi = 0; gi < WRS_GI_MAX_HE; gi++)
+ inverse_data_rate.he[bw][nss][mcs][gi] =
+ cl_data_rates_inverse_he(bw, nss, mcs, gi);
+
+ /* VHT */
+ for (mcs = 0; mcs < WRS_MCS_MAX_VHT; mcs++)
+ for (gi = 0; gi < WRS_GI_MAX_VHT; gi++)
+ inverse_data_rate.ht_vht[bw][nss][mcs][gi] =
+ cl_data_rates_inverse_vht(bw, nss, mcs, gi);
+ }
+
+ /* OFDM */
+ for (mcs = 0; mcs < WRS_MCS_MAX_OFDM; mcs++)
+ inverse_data_rate.ofdm[mcs] = cl_data_rates_inverse_ofdm(mcs);
+
+ /* CCK */
+ for (mcs = 0; mcs < WRS_MCS_MAX_CCK; mcs++)
+ inverse_data_rate.cck[mcs] = cl_data_rates_inverse_cck(mcs);
+}
+
+u16 cl_data_rates_get(u8 mode, u8 bw, u8 nss, u8 mcs, u8 gi)
+{
+ return cl_data_rates_get_x10(mode, bw, nss, mcs, gi) / 10;
+}
+
+u16 cl_data_rates_get_x10(u8 mode, u8 bw, u8 nss, u8 mcs, u8 gi)
+{
+ switch (mode) {
+ case WRS_MODE_HE:
+ return data_rate_he_x10[bw][nss][mcs][gi];
+ case WRS_MODE_VHT:
+ case WRS_MODE_HT:
+ return data_rate_ht_vht_x10[bw][nss][mcs][gi];
+ case WRS_MODE_OFDM:
+ return data_rate_ofdm_x10[mcs];
+ case WRS_MODE_CCK:
+ return data_rate_cck_x10[mcs];
+ default:
+ return 0;
+ }
+}
+
--
2.30.0

________________________________
The information transmitted is intended only for the person or entity to which it is addressed and may contain confidential and/or privileged material. Any retransmission, dissemination, copying or other use of, or taking of any action in reliance upon this information is prohibited. If you received this in error, please contact the sender and delete the material from any computer. Nothing contained herein shall be deemed as a representation, warranty or a commitment by Celeno. No warranties are expressed or implied, including, but not limited to, any implied warranties of non-infringement, merchantability and fitness for a particular purpose.
________________________________

2021-06-17 16:25:44

by viktor.barna

[permalink] [raw]
Subject: [RFC v1 060/256] cl8k: add dfs/dfs.h

From: Viktor Barna <[email protected]>

(Part of the split. Please, take a look at the cover letter for more
details).

Signed-off-by: Viktor Barna <[email protected]>
---
drivers/net/wireless/celeno/cl8k/dfs/dfs.h | 26 ++++++++++++++++++++++
1 file changed, 26 insertions(+)
create mode 100644 drivers/net/wireless/celeno/cl8k/dfs/dfs.h

diff --git a/drivers/net/wireless/celeno/cl8k/dfs/dfs.h b/drivers/net/wireless/celeno/cl8k/dfs/dfs.h
new file mode 100644
index 000000000000..7630861a5351
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/dfs/dfs.h
@@ -0,0 +1,26 @@
+/* SPDX-License-Identifier: MIT */
+/* Copyright(c) 2019-2021, Celeno Communications Ltd. */
+
+#ifndef CL_DFS_H
+#define CL_DFS_H
+
+#include "hw.h"
+#include "dfs/radar.h"
+
+bool cl_dfs_pulse_process(struct cl_hw *cl_hw, struct cl_radar_pulse *pulse, u8 pulse_cnt,
+ unsigned long time);
+bool __must_check cl_dfs_is_en(struct cl_hw *cl_hw);
+bool __must_check cl_dfs_is_in_cac(struct cl_hw *cl_hw);
+bool __must_check cl_dfs_requested_cac(struct cl_hw *cl_hw);
+bool __must_check cl_dfs_radar_listening(struct cl_hw *cl_hw);
+void cl_dfs_init(struct cl_hw *cl_hw);
+void cl_dfs_close(struct cl_hw *cl_hw);
+void cl_dfs_recovery(struct cl_hw *cl_hw);
+void cl_dfs_force_cac_start(struct cl_hw *cl_hw);
+void cl_dfs_force_cac_end(struct cl_hw *cl_hw);
+void cl_dfs_radar_listen_start(struct cl_hw *cl_hw);
+void cl_dfs_radar_listen_end(struct cl_hw *cl_hw);
+void cl_dfs_request_cac(struct cl_hw *cl_hw, bool should_do);
+int cl_dfs_cli(struct cl_hw *cl_hw, struct cli_params *cli_params, u8 *ret_buf, u16 *ret_buf_len);
+
+#endif /* CL_DFS_H */
--
2.30.0

________________________________
The information transmitted is intended only for the person or entity to which it is addressed and may contain confidential and/or privileged material. Any retransmission, dissemination, copying or other use of, or taking of any action in reliance upon this information is prohibited. If you received this in error, please contact the sender and delete the material from any computer. Nothing contained herein shall be deemed as a representation, warranty or a commitment by Celeno. No warranties are expressed or implied, including, but not limited to, any implied warranties of non-infringement, merchantability and fitness for a particular purpose.
________________________________

2021-06-17 16:25:48

by viktor.barna

[permalink] [raw]
Subject: [RFC v1 063/256] cl8k: add dfs/radar.h

From: Viktor Barna <[email protected]>

(Part of the split. Please, take a look at the cover letter for more
details).

Signed-off-by: Viktor Barna <[email protected]>
---
drivers/net/wireless/celeno/cl8k/dfs/radar.h | 55 ++++++++++++++++++++
1 file changed, 55 insertions(+)
create mode 100644 drivers/net/wireless/celeno/cl8k/dfs/radar.h

diff --git a/drivers/net/wireless/celeno/cl8k/dfs/radar.h b/drivers/net/wireless/celeno/cl8k/dfs/radar.h
new file mode 100644
index 000000000000..bed037cce624
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/dfs/radar.h
@@ -0,0 +1,55 @@
+/* SPDX-License-Identifier: MIT */
+/* Copyright(c) 2019-2021, Celeno Communications Ltd. */
+
+#ifndef CL_RADAR_H
+#define CL_RADAR_H
+
+ #include <linux/types.h>
+
+/* Number of pulses in a radar event structure */
+#define RADAR_PULSE_MAX 4
+
+/*
+ * Structure used to store information regarding
+ * E2A radar events in the driver
+ */
+struct cl_radar_elem {
+ struct cl_radar_pulse_array *radarbuf_ptr;
+ dma_addr_t dma_addr;
+};
+
+/* Bit mapping inside a radar pulse element */
+struct cl_radar_pulse {
+ u64 freq : 8;
+ u64 fom : 8;
+ u64 len : 8; /* Pulse length timer */
+ u64 measure_cnt : 2; /* Measure count */
+ u64 rsv1 : 6; /* Reserve1 */
+ u64 rep : 16; /* PRI */
+ u64 rsv2 : 16; /* Reserve2 */
+};
+
+/* Definition of an array of radar pulses */
+struct cl_radar_pulse_array {
+ /* Buffer containing the radar pulses */
+ u64 pulse[RADAR_PULSE_MAX];
+ /* Number of valid pulses in the buffer */
+ u32 cnt;
+};
+
+struct cl_radar_queue_elem {
+ struct list_head list;
+ struct cl_hw *cl_hw;
+ struct cl_radar_elem radar_elem;
+ unsigned long time;
+};
+
+struct cl_hw;
+
+void cl_radar_init(struct cl_hw *cl_hw);
+void cl_radar_push(struct cl_hw *cl_hw, struct cl_radar_elem *radar_elem);
+void cl_radar_tasklet_schedule(struct cl_hw *cl_hw);
+void cl_radar_flush(struct cl_hw *cl_hw);
+void cl_radar_close(struct cl_hw *cl_hw);
+
+#endif /* CL_RADAR_H */
--
2.30.0

________________________________
The information transmitted is intended only for the person or entity to which it is addressed and may contain confidential and/or privileged material. Any retransmission, dissemination, copying or other use of, or taking of any action in reliance upon this information is prohibited. If you received this in error, please contact the sender and delete the material from any computer. Nothing contained herein shall be deemed as a representation, warranty or a commitment by Celeno. No warranties are expressed or implied, including, but not limited to, any implied warranties of non-infringement, merchantability and fitness for a particular purpose.
________________________________

2021-06-17 16:25:54

by viktor.barna

[permalink] [raw]
Subject: [RFC v1 062/256] cl8k: add dfs/radar.c

From: Viktor Barna <[email protected]>

(Part of the split. Please, take a look at the cover letter for more
details).

Signed-off-by: Viktor Barna <[email protected]>
---
drivers/net/wireless/celeno/cl8k/dfs/radar.c | 116 +++++++++++++++++++
1 file changed, 116 insertions(+)
create mode 100644 drivers/net/wireless/celeno/cl8k/dfs/radar.c

diff --git a/drivers/net/wireless/celeno/cl8k/dfs/radar.c b/drivers/net/wireless/celeno/cl8k/dfs/radar.c
new file mode 100644
index 000000000000..3f763e274102
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/dfs/radar.c
@@ -0,0 +1,116 @@
+// SPDX-License-Identifier: MIT
+/* Copyright(c) 2019-2021, Celeno Communications Ltd. */
+
+#include "dfs/radar.h"
+#include "dfs/dfs.h"
+#ifdef CONFIG_CL_PCIE
+#include "bus/pci/irq.h"
+#include "ipc_shared.h"
+#endif
+
+static void cl_radar_handler(struct cl_hw *cl_hw, struct cl_radar_elem *radar_elem,
+ unsigned long time)
+{
+ /* Retrieve the radar pulses structure */
+ struct cl_radar_pulse_array *pulses = radar_elem->radarbuf_ptr;
+
+ cl_dfs_pulse_process(cl_hw, (struct cl_radar_pulse *)pulses->pulse,
+ pulses->cnt, time);
+}
+
+static void cl_radar_tasklet(unsigned long data)
+{
+ struct cl_hw *cl_hw = (struct cl_hw *)data;
+ struct cl_radar_queue_elem *radar_elem = NULL;
+ unsigned long flags = 0;
+
+ while (!list_empty(&cl_hw->radar_queue.head)) {
+ spin_lock_irqsave(&cl_hw->radar_queue.lock, flags);
+ radar_elem = list_first_entry(&cl_hw->radar_queue.head,
+ struct cl_radar_queue_elem, list);
+ list_del(&radar_elem->list);
+ spin_unlock_irqrestore(&cl_hw->radar_queue.lock, flags);
+
+ cl_radar_handler(radar_elem->cl_hw, &radar_elem->radar_elem,
+ radar_elem->time);
+
+ kfree(radar_elem->radar_elem.radarbuf_ptr);
+ kfree(radar_elem);
+ }
+
+#ifdef CONFIG_CL_PCIE
+ if (!test_bit(CL_DEV_STOP_HW, &cl_hw->drv_flags))
+ cl_irq_enable(cl_hw, cl_hw->ipc_e2a_irq.radar);
+#endif
+}
+
+void cl_radar_init(struct cl_hw *cl_hw)
+{
+ INIT_LIST_HEAD(&cl_hw->radar_queue.head);
+
+ tasklet_init(&cl_hw->radar_tasklet, cl_radar_tasklet, (unsigned long)cl_hw);
+
+ spin_lock_init(&cl_hw->radar_queue.lock);
+}
+
+void cl_radar_push(struct cl_hw *cl_hw, struct cl_radar_elem *radar_elem)
+{
+ struct cl_radar_queue_elem *new_queue_elem = NULL;
+ u32 i;
+
+ new_queue_elem = kzalloc(sizeof(*new_queue_elem), GFP_ATOMIC);
+
+ if (new_queue_elem) {
+ new_queue_elem->radar_elem.radarbuf_ptr =
+ kzalloc(sizeof(*new_queue_elem->radar_elem.radarbuf_ptr), GFP_ATOMIC);
+
+ if (new_queue_elem->radar_elem.radarbuf_ptr) {
+ new_queue_elem->radar_elem.dma_addr = radar_elem->dma_addr;
+ new_queue_elem->radar_elem.radarbuf_ptr->cnt =
+ le32_to_cpu(radar_elem->radarbuf_ptr->cnt);
+
+ /* Copy into local list */
+ for (i = 0; i < ARRAY_SIZE(radar_elem->radarbuf_ptr->pulse); i++)
+ new_queue_elem->radar_elem.radarbuf_ptr->pulse[i] =
+ le64_to_cpu(radar_elem->radarbuf_ptr->pulse[i]);
+
+ new_queue_elem->time = jiffies_to_msecs(jiffies);
+ new_queue_elem->cl_hw = cl_hw;
+
+ spin_lock(&cl_hw->radar_queue.lock);
+ list_add_tail(&new_queue_elem->list, &cl_hw->radar_queue.head);
+ spin_unlock(&cl_hw->radar_queue.lock);
+ } else {
+ kfree(new_queue_elem);
+ }
+ }
+}
+
+void cl_radar_tasklet_schedule(struct cl_hw *cl_hw)
+{
+ tasklet_schedule(&cl_hw->radar_tasklet);
+}
+
+void cl_radar_flush(struct cl_hw *cl_hw)
+{
+ struct cl_radar_queue_elem *radar_elem = NULL;
+ unsigned long flags = 0;
+
+ spin_lock_irqsave(&cl_hw->radar_queue.lock, flags);
+
+ while (!list_empty(&cl_hw->radar_queue.head)) {
+ radar_elem = list_first_entry(&cl_hw->radar_queue.head,
+ struct cl_radar_queue_elem, list);
+ list_del(&radar_elem->list);
+ kfree(radar_elem->radar_elem.radarbuf_ptr);
+ kfree(radar_elem);
+ }
+
+ spin_unlock_irqrestore(&cl_hw->radar_queue.lock, flags);
+}
+
+void cl_radar_close(struct cl_hw *cl_hw)
+{
+ cl_radar_flush(cl_hw);
+ tasklet_kill(&cl_hw->radar_tasklet);
+}
--
2.30.0

________________________________
The information transmitted is intended only for the person or entity to which it is addressed and may contain confidential and/or privileged material. Any retransmission, dissemination, copying or other use of, or taking of any action in reliance upon this information is prohibited. If you received this in error, please contact the sender and delete the material from any computer. Nothing contained herein shall be deemed as a representation, warranty or a commitment by Celeno. No warranties are expressed or implied, including, but not limited to, any implied warranties of non-infringement, merchantability and fitness for a particular purpose.
________________________________

2021-06-17 16:26:01

by viktor.barna

[permalink] [raw]
Subject: [RFC v1 078/256] cl8k: add ext/dyn_bcast_rate.h

From: Viktor Barna <[email protected]>

(Part of the split. Please, take a look at the cover letter for more
details).

Signed-off-by: Viktor Barna <[email protected]>
---
.../wireless/celeno/cl8k/ext/dyn_bcast_rate.h | 18 ++++++++++++++++++
1 file changed, 18 insertions(+)
create mode 100644 drivers/net/wireless/celeno/cl8k/ext/dyn_bcast_rate.h

diff --git a/drivers/net/wireless/celeno/cl8k/ext/dyn_bcast_rate.h b/drivers/net/wireless/celeno/cl8k/ext/dyn_bcast_rate.h
new file mode 100644
index 000000000000..d5d828d85fc7
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/ext/dyn_bcast_rate.h
@@ -0,0 +1,18 @@
+/* SPDX-License-Identifier: MIT */
+/* Copyright(c) 2019-2021, Celeno Communications Ltd. */
+
+#ifndef CL_DYN_BCAST_RATE_H
+#define CL_DYN_BCAST_RATE_H
+
+#include "hw.h"
+
+void cl_dyn_bcast_rate_init(struct cl_hw *cl_hw);
+void cl_dyn_bcast_rate_set(struct cl_hw *cl_hw, u8 bcast_mcs);
+u16 cl_dyn_bcast_rate_get(struct cl_hw *cl_hw);
+void cl_dyn_bcast_rate_recovery(struct cl_hw *cl_hw);
+void cl_dyn_bcast_rate_change(struct cl_hw *cl_hw, struct cl_sta *cl_sta_change,
+ u8 old_mcs, u8 new_mcs);
+void cl_dyn_bcast_rate_update_upon_assoc(struct cl_hw *cl_hw, u8 mcs, u8 num_sta);
+void cl_dyn_bcast_rate_update_upon_disassoc(struct cl_hw *cl_hw, u8 mcs, u8 num_sta);
+
+#endif /* CL_DYN_BCAST_RATE_H */
--
2.30.0

________________________________
The information transmitted is intended only for the person or entity to which it is addressed and may contain confidential and/or privileged material. Any retransmission, dissemination, copying or other use of, or taking of any action in reliance upon this information is prohibited. If you received this in error, please contact the sender and delete the material from any computer. Nothing contained herein shall be deemed as a representation, warranty or a commitment by Celeno. No warranties are expressed or implied, including, but not limited to, any implied warranties of non-infringement, merchantability and fitness for a particular purpose.
________________________________

2021-06-17 16:26:04

by viktor.barna

[permalink] [raw]
Subject: [RFC v1 077/256] cl8k: add ext/dyn_bcast_rate.c

From: Viktor Barna <[email protected]>

(Part of the split. Please, take a look at the cover letter for more
details).

Signed-off-by: Viktor Barna <[email protected]>
---
.../wireless/celeno/cl8k/ext/dyn_bcast_rate.c | 182 ++++++++++++++++++
1 file changed, 182 insertions(+)
create mode 100644 drivers/net/wireless/celeno/cl8k/ext/dyn_bcast_rate.c

diff --git a/drivers/net/wireless/celeno/cl8k/ext/dyn_bcast_rate.c b/drivers/net/wireless/celeno/cl8k/ext/dyn_bcast_rate.c
new file mode 100644
index 000000000000..434ed433b90f
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/ext/dyn_bcast_rate.c
@@ -0,0 +1,182 @@
+// SPDX-License-Identifier: MIT
+/* Copyright(c) 2019-2021, Celeno Communications Ltd. */
+
+#include "ext/dyn_bcast_rate.h"
+#include "band.h"
+#include "sta.h"
+#include "rate_ctrl.h"
+#include "fw/msg_tx.h"
+#include "utils/utils.h"
+#include "data_rates.h"
+
+/*
+ * MIN_MCS | BCAST_MCS
+ * -------------------
+ * 0 - 1 | 0
+ * 2 - 3 | 1
+ * 4 - 5 | 2
+ * 6 - 7 | 3
+ * 8 - 9 | 4
+ * 10 - 11 | 5
+ */
+
+static u8 conv_min_mcs_to_bcast_mcs[WRS_MCS_MAX] = {
+ 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5
+};
+
+static void cl_dyn_bcast_rate_update(struct cl_hw *cl_hw, u8 min_mcs)
+{
+ struct cl_dyn_bcast_rate *dyn_bcast_rate = &cl_hw->dyn_bcast_rate;
+ u8 bcast_mcs = conv_min_mcs_to_bcast_mcs[min_mcs];
+
+ dyn_bcast_rate->sta_min_mcs = min_mcs;
+
+ if (bcast_mcs != dyn_bcast_rate->bcast_mcs)
+ cl_dyn_bcast_rate_set(cl_hw, bcast_mcs);
+}
+
+void cl_dyn_bcast_rate_init(struct cl_hw *cl_hw)
+{
+ struct cl_dyn_bcast_rate *dyn_bcast_rate = &cl_hw->dyn_bcast_rate;
+
+ dyn_bcast_rate->sta_min_mcs = 0;
+ dyn_bcast_rate->bcast_mcs = conv_min_mcs_to_bcast_mcs[0];
+
+ if (cl_band_is_6g(cl_hw)) {
+ dyn_bcast_rate->wrs_mode = WRS_MODE_HE;
+ dyn_bcast_rate->ltf = LTF_X4;
+ } else if (cl_band_is_24g(cl_hw) && cl_hw_mode_is_b_or_bg(cl_hw)) {
+ dyn_bcast_rate->wrs_mode = WRS_MODE_CCK;
+ dyn_bcast_rate->ltf = 0;
+ } else {
+ dyn_bcast_rate->wrs_mode = WRS_MODE_OFDM;
+ dyn_bcast_rate->ltf = 0;
+ }
+}
+
+void cl_dyn_bcast_rate_set(struct cl_hw *cl_hw, u8 bcast_mcs)
+{
+ struct cl_dyn_bcast_rate *dyn_bcast_rate = &cl_hw->dyn_bcast_rate;
+ u8 wrs_mode = dyn_bcast_rate->wrs_mode;
+ u8 ltf = dyn_bcast_rate->ltf;
+ u32 rate_ctrl;
+
+ cl_hw->dyn_bcast_rate.bcast_mcs = bcast_mcs;
+
+ rate_ctrl = cl_rate_ctrl_generate(cl_hw, NULL, wrs_mode, 0, 0, bcast_mcs,
+ 0, false);
+ cl_msg_tx_update_rate_dl(cl_hw, U8_MAX, rate_ctrl, 0, 0,
+ RATE_OP_MODE_BCAST, ltf, 0, 0);
+
+ cl_dbg_info(cl_hw, "Broadcast MCS set to %u\n", bcast_mcs);
+}
+
+u16 cl_dyn_bcast_rate_get(struct cl_hw *cl_hw)
+{
+ struct cl_dyn_bcast_rate *dyn_bcast_rate = &cl_hw->dyn_bcast_rate;
+
+ return cl_data_rates_get(dyn_bcast_rate->wrs_mode, 0, 0, dyn_bcast_rate->bcast_mcs, 0);
+}
+
+void cl_dyn_bcast_rate_recovery(struct cl_hw *cl_hw)
+{
+ cl_dyn_bcast_rate_set(cl_hw, cl_hw->dyn_bcast_rate.bcast_mcs);
+}
+
+void cl_dyn_bcast_rate_change(struct cl_hw *cl_hw, struct cl_sta *cl_sta_change,
+ u8 old_mcs, u8 new_mcs)
+{
+ struct cl_dyn_bcast_rate *dyn_bcast_rate = &cl_hw->dyn_bcast_rate;
+ struct cl_sta *cl_sta = NULL;
+ u8 min_mcs = WRS_MCS_MAX - 1;
+ u8 sta_mcs = 0;
+
+ if (!cl_hw->conf->ce_dyn_bcast_rate_en)
+ return;
+
+ if (!cl_sta_change->add_complete)
+ return;
+
+ /* Single station */
+ if (cl_sta_num_bh(cl_hw) == 1) {
+ cl_dyn_bcast_rate_update(cl_hw, new_mcs);
+ return;
+ }
+
+ /*
+ * If this station did not have the minimum mcs,
+ * and the new rate is now below the minimum mcs there is nothing to do
+ */
+ if (old_mcs > dyn_bcast_rate->sta_min_mcs &&
+ new_mcs > dyn_bcast_rate->sta_min_mcs)
+ return;
+
+ /* Multi station - find new minimum MCS of all stations */
+ cl_sta_lock_bh(cl_hw);
+
+ list_for_each_entry(cl_sta, &cl_hw->cl_sta_db.head, list) {
+ sta_mcs = (cl_sta->sta_idx == cl_sta_change->sta_idx) ?
+ new_mcs : cl_sta->wrs_sta.su_params.tx_params.mcs;
+
+ if (sta_mcs < min_mcs) {
+ min_mcs = sta_mcs;
+
+ if (min_mcs == 0)
+ break;
+ }
+ }
+
+ cl_sta_unlock_bh(cl_hw);
+
+ cl_dyn_bcast_rate_update(cl_hw, min_mcs);
+}
+
+void cl_dyn_bcast_rate_update_upon_assoc(struct cl_hw *cl_hw, u8 mcs, u8 num_sta)
+{
+ struct cl_dyn_bcast_rate *dyn_bcast_rate = &cl_hw->dyn_bcast_rate;
+
+ if (!cl_hw->conf->ce_dyn_bcast_rate_en)
+ return;
+
+ if (num_sta == 1 || mcs < dyn_bcast_rate->sta_min_mcs)
+ cl_dyn_bcast_rate_update(cl_hw, mcs);
+}
+
+void cl_dyn_bcast_rate_update_upon_disassoc(struct cl_hw *cl_hw, u8 mcs, u8 num_sta)
+{
+ struct cl_dyn_bcast_rate *dyn_bcast_rate = &cl_hw->dyn_bcast_rate;
+ struct cl_sta *cl_sta = NULL;
+ u8 min_mcs = WRS_MCS_MAX - 1;
+
+ if (!cl_hw->conf->ce_dyn_bcast_rate_en)
+ return;
+
+ /* When the last station disconnects - set bcast back to 0 */
+ if (num_sta == 0) {
+ cl_dyn_bcast_rate_update(cl_hw, 0);
+ return;
+ }
+
+ /* If this station did not have the minimum rate there is nothing to do */
+ if (mcs > dyn_bcast_rate->sta_min_mcs)
+ return;
+
+ /*
+ * Find new minimum MCS of all station (the disassociating
+ * station is not in list at this stage)
+ */
+ cl_sta_lock_bh(cl_hw);
+
+ list_for_each_entry(cl_sta, &cl_hw->cl_sta_db.head, list) {
+ if (cl_sta->wrs_sta.su_params.tx_params.mcs < min_mcs) {
+ min_mcs = cl_sta->wrs_sta.su_params.tx_params.mcs;
+
+ if (min_mcs == 0)
+ break;
+ }
+ }
+
+ cl_sta_unlock_bh(cl_hw);
+
+ cl_dyn_bcast_rate_update(cl_hw, min_mcs);
+}
--
2.30.0

________________________________
The information transmitted is intended only for the person or entity to which it is addressed and may contain confidential and/or privileged material. Any retransmission, dissemination, copying or other use of, or taking of any action in reliance upon this information is prohibited. If you received this in error, please contact the sender and delete the material from any computer. Nothing contained herein shall be deemed as a representation, warranty or a commitment by Celeno. No warranties are expressed or implied, including, but not limited to, any implied warranties of non-infringement, merchantability and fitness for a particular purpose.
________________________________

2021-06-17 16:26:04

by viktor.barna

[permalink] [raw]
Subject: [RFC v1 064/256] cl8k: add drv_ops.h

From: Viktor Barna <[email protected]>

(Part of the split. Please, take a look at the cover letter for more
details).

Signed-off-by: Viktor Barna <[email protected]>
---
drivers/net/wireless/celeno/cl8k/drv_ops.h | 28 ++++++++++++++++++++++
1 file changed, 28 insertions(+)
create mode 100644 drivers/net/wireless/celeno/cl8k/drv_ops.h

diff --git a/drivers/net/wireless/celeno/cl8k/drv_ops.h b/drivers/net/wireless/celeno/cl8k/drv_ops.h
new file mode 100644
index 000000000000..3e8f56d9d6f6
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/drv_ops.h
@@ -0,0 +1,28 @@
+/* SPDX-License-Identifier: MIT */
+/* Copyright(c) 2019-2021, Celeno Communications Ltd. */
+
+#ifndef CL_DRV_OPS_H
+#define CL_DRV_OPS_H
+
+#include "hw.h"
+#include "tx/sw_txhdr.h"
+
+static inline int cl_drv_ops_msg_fw_send(struct cl_hw *cl_hw,
+ const void *msg_params,
+ bool background)
+{
+ if (cl_hw->drv_ops->msg_fw_send)
+ return cl_hw->drv_ops->msg_fw_send(cl_hw, msg_params,
+ background);
+ return 0;
+}
+
+static inline void cl_drv_ops_pkt_fw_send(struct cl_hw *cl_hw,
+ struct cl_sw_txhdr *sw_txhdr,
+ struct cl_tx_queue *tx_queue)
+{
+ if (cl_hw->drv_ops->pkt_fw_send)
+ cl_hw->drv_ops->pkt_fw_send(cl_hw, sw_txhdr, tx_queue);
+}
+
+#endif /* CL_DRV_OPS_H */
--
2.30.0

________________________________
The information transmitted is intended only for the person or entity to which it is addressed and may contain confidential and/or privileged material. Any retransmission, dissemination, copying or other use of, or taking of any action in reliance upon this information is prohibited. If you received this in error, please contact the sender and delete the material from any computer. Nothing contained herein shall be deemed as a representation, warranty or a commitment by Celeno. No warranties are expressed or implied, including, but not limited to, any implied warranties of non-infringement, merchantability and fitness for a particular purpose.
________________________________

2021-06-17 16:26:12

by viktor.barna

[permalink] [raw]
Subject: [RFC v1 080/256] cl8k: add ext/dyn_mcast_rate.h

From: Viktor Barna <[email protected]>

(Part of the split. Please, take a look at the cover letter for more
details).

Signed-off-by: Viktor Barna <[email protected]>
---
.../net/wireless/celeno/cl8k/ext/dyn_mcast_rate.h | 14 ++++++++++++++
1 file changed, 14 insertions(+)
create mode 100644 drivers/net/wireless/celeno/cl8k/ext/dyn_mcast_rate.h

diff --git a/drivers/net/wireless/celeno/cl8k/ext/dyn_mcast_rate.h b/drivers/net/wireless/celeno/cl8k/ext/dyn_mcast_rate.h
new file mode 100644
index 000000000000..dac8c816c5a4
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/ext/dyn_mcast_rate.h
@@ -0,0 +1,14 @@
+/* SPDX-License-Identifier: MIT */
+/* Copyright(c) 2019-2021, Celeno Communications Ltd. */
+
+#ifndef CL_DYN_MCAST_RATE_H
+#define CL_DYN_MCAST_RATE_H
+
+void cl_dyn_mcast_rate_init(struct cl_hw *cl_hw);
+void cl_dyn_mcast_rate_set(struct cl_hw *cl_hw);
+u16 cl_dyn_mcast_rate_get(struct cl_hw *cl_hw);
+void cl_dyn_mcast_rate_recovery(struct cl_hw *cl_hw);
+void cl_dyn_mcast_rate_update_upon_assoc(struct cl_hw *cl_hw, u8 wrs_mode, u8 num_sta);
+void cl_dyn_mcast_rate_update_upon_disassoc(struct cl_hw *cl_hw, u8 wrs_mode, u8 num_sta);
+
+#endif /* CL_DYN_MCAST_RATE_H */
--
2.30.0

________________________________
The information transmitted is intended only for the person or entity to which it is addressed and may contain confidential and/or privileged material. Any retransmission, dissemination, copying or other use of, or taking of any action in reliance upon this information is prohibited. If you received this in error, please contact the sender and delete the material from any computer. Nothing contained herein shall be deemed as a representation, warranty or a commitment by Celeno. No warranties are expressed or implied, including, but not limited to, any implied warranties of non-infringement, merchantability and fitness for a particular purpose.
________________________________

2021-06-17 16:26:15

by viktor.barna

[permalink] [raw]
Subject: [RFC v1 057/256] cl8k: add debugfs_defs.h

From: Viktor Barna <[email protected]>

(Part of the split. Please, take a look at the cover letter for more
details).

Signed-off-by: Viktor Barna <[email protected]>
---
.../net/wireless/celeno/cl8k/debugfs_defs.h | 36 +++++++++++++++++++
1 file changed, 36 insertions(+)
create mode 100644 drivers/net/wireless/celeno/cl8k/debugfs_defs.h

diff --git a/drivers/net/wireless/celeno/cl8k/debugfs_defs.h b/drivers/net/wireless/celeno/cl8k/debugfs_defs.h
new file mode 100644
index 000000000000..d6b8d0db7bb8
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/debugfs_defs.h
@@ -0,0 +1,36 @@
+/* SPDX-License-Identifier: MIT */
+/* Copyright(c) 2019-2021, Celeno Communications Ltd. */
+
+#ifndef CL_DEBUGFS_DEFS_H
+#define CL_DEBUGFS_DEFS_H
+
+/* Min HW assert before testing asserts time-stamp */
+#define CL_MIN_ASSERT_CNT 10
+
+/* Define max time between hw asserts in msec */
+#define CL_HW_ASSERT_TIME_MAX 5000
+
+#ifdef CONFIG_CL_DEBUGFS
+
+#include <linux/workqueue.h>
+#include <linux/interrupt.h>
+
+struct cl_debugfs {
+ unsigned long long rateidx;
+ struct dentry *dir;
+ bool trace_prst;
+ struct work_struct coredump_work;
+ bool coredump_scheduled;
+ spinlock_t coredump_lock;
+ unsigned long coredump_call_tstamp;
+ bool unregistering;
+};
+
+#else
+
+struct cl_debugfs {
+};
+
+#endif /* CONFIG_CL_DEBUGFS */
+
+#endif /* CL_DEBUGFS_DEFS_H */
--
2.30.0

________________________________
The information transmitted is intended only for the person or entity to which it is addressed and may contain confidential and/or privileged material. Any retransmission, dissemination, copying or other use of, or taking of any action in reliance upon this information is prohibited. If you received this in error, please contact the sender and delete the material from any computer. Nothing contained herein shall be deemed as a representation, warranty or a commitment by Celeno. No warranties are expressed or implied, including, but not limited to, any implied warranties of non-infringement, merchantability and fitness for a particular purpose.
________________________________

2021-06-17 16:26:17

by viktor.barna

[permalink] [raw]
Subject: [RFC v1 058/256] cl8k: add def.h

From: Viktor Barna <[email protected]>

(Part of the split. Please, take a look at the cover letter for more
details).

Signed-off-by: Viktor Barna <[email protected]>
---
drivers/net/wireless/celeno/cl8k/def.h | 269 +++++++++++++++++++++++++
1 file changed, 269 insertions(+)
create mode 100644 drivers/net/wireless/celeno/cl8k/def.h

diff --git a/drivers/net/wireless/celeno/cl8k/def.h b/drivers/net/wireless/celeno/cl8k/def.h
new file mode 100644
index 000000000000..b57f611dfac2
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/def.h
@@ -0,0 +1,269 @@
+/* SPDX-License-Identifier: MIT */
+/* Copyright(c) 2019-2021, Celeno Communications Ltd. */
+
+#ifndef CL_DEF_H
+#define CL_DEF_H
+
+#include <stddef.h>
+#include <linux/types.h>
+
+#define ASSERT_ERR(condition) \
+ do { \
+ if (unlikely(!(condition))) \
+ cl_dbg_err(cl_hw, ":ASSERT_ERR(" #condition ")\n"); \
+ } while (0)
+
+#define ASSERT_ERR_CHIP(condition) \
+ do { \
+ if (unlikely(!(condition))) \
+ cl_dbg_chip_err(chip, ":ASSERT_ERR(" #condition ")\n"); \
+ } while (0)
+
+#define CL_TIME_DIFF(a, b) ((a) - (b))
+
+#define msecs_round(ms) jiffies_to_msecs(msecs_to_jiffies(ms))
+
+/* Each chip supports two TCVs */
+#define TCV0 0
+#define TCV1 1
+#define TCV_MAX 2
+
+#define CHIP0 0
+#define CHIP1 1
+#define CHIP_MAX 2
+
+#define TCV_TOTAL (CHIP_MAX * TCV_MAX)
+
+#define CL_VENDOR_ID 0x1d69
+
+#define CPU_MAX_NUM 8
+
+/* We support 128 stations and last station is assigned for high priority */
+#define CL_MAX_NUM_STA 128
+#define FW_MAX_NUM_STA (CL_MAX_NUM_STA + 1)
+
+#define MAX_SINGLE_QUEUES (AC_MAX * FW_MAX_NUM_STA)
+#define HIGH_PRIORITY_QUEUE (MAX_SINGLE_QUEUES - 1)
+
+/* Must be aligned to NX_VIRT_DEV_MAX definition in rwnx_config.h */
+#define MAX_BSS_NUM 8
+
+#define MAX_TX_SW_AMSDU_PACKET 15
+
+#define RX_MAX_MSDU_IN_AMSDU 128
+
+#define CL_PATH_MAX 200
+#define CL_FILENAME_MAX 100
+
+/* MAX/MIN number of antennas supported */
+#define MIN_ANTENNAS 1
+#define MAX_ANTENNAS 6
+#define MAX_ANTENNAS_OFDM_HT_VHT 4
+#define MAX_ANTENNAS_CCK 4
+#define MAX_ANTENNAS_CHIP 8
+
+#define MAX_ANTENNAS_CL808X 8
+#define MAX_ANTENNAS_CL806X 6
+#define MAX_ANTENNAS_CL804X 4
+
+#define ANT_MASK(ant) (BIT(ant) - 1)
+
+/* 6GHz defines */
+#define HE_6GHZ_CAP_MIN_MPDU_START_OFFSET 0
+#define HE_6GHZ_CAP_MAX_AMPDU_LEN_EXP_OFFSET 3
+#define HE_6GHZ_CAP_MAX_MPDU_LEN_OFFSET 6
+#define HE_6GHZ_CAP_MAX_AMPDU_LEN_FACTOR 13
+#define HE_6GHZ_CAP_MAX_AMPDU_LEN_EXP_MASK 0x38
+
+#define MHZ_TO_BW(mhz) ilog2((mhz) / 20)
+#define BW_TO_MHZ(bw) ((1 << (bw)) * 20)
+#define BW_TO_KHZ(bw) ((1 << (bw)) * 20000)
+
+#define CIPHER_SUITE_LIST_OFFSET 11
+#define CIPHER_SUITE_LIST_SIZE 4
+
+/* Cipher suite selectors */
+#define CL_CIPHER_SUITE_USE_NONE 0
+#define CL_CIPHER_SUITE_WEP40 1
+#define CL_CIPHER_SUITE_TKIP 2
+#define CL_CIPHER_SUITE_CCMP 4
+#define CL_CIPHER_SUITE_WEP104 5
+#define CL_CIPHER_SUITE_AES_CMAC 6
+#define CL_CIPHER_SUITE_GCMP 8
+#define CL_CIPHER_SUITE_GCMP_256 9
+#define CL_CIPHER_SUITE_CCMP_256 10
+#define CL_CIPHER_SUITE_BIP_GMAC_128 11
+#define CL_CIPHER_SUITE_BIP_GMAC_256 12
+#define CL_CIPHER_SUITE_BIP_CMAC_256 13
+#define CL_CIPHER_SUITE_USE_GROUP 14
+
+#define CIPHER_SUITE_MASK() (BIT(CL_CIPHER_SUITE_WEP40) | \
+ BIT(CL_CIPHER_SUITE_WEP40) | \
+ BIT(CL_CIPHER_SUITE_TKIP) | \
+ BIT(CL_CIPHER_SUITE_CCMP) | \
+ BIT(CL_CIPHER_SUITE_WEP104) | \
+ BIT(CL_CIPHER_SUITE_AES_CMAC) | \
+ BIT(CL_CIPHER_SUITE_GCMP) | \
+ BIT(CL_CIPHER_SUITE_GCMP_256) | \
+ BIT(CL_CIPHER_SUITE_CCMP_256) | \
+ BIT(CL_CIPHER_SUITE_BIP_GMAC_128) | \
+ BIT(CL_CIPHER_SUITE_BIP_GMAC_256) | \
+ BIT(CL_CIPHER_SUITE_BIP_CMAC_256) | \
+ BIT(CL_CIPHER_SUITE_USE_GROUP))
+
+#define IS_VALID_ENCRYPT_TYPE(encrypt_type) ((encrypt_type) & CIPHER_SUITE_MASK())
+
+#define CL_CIPHER_SUITE_MIXED_TKIP_CCMP (BIT(CL_CIPHER_SUITE_TKIP) | \
+ BIT(CL_CIPHER_SUITE_CCMP))
+
+/* AKM suite selectors */
+#define CL_AKM_SUITE_OPEN 0
+#define CL_AKM_SUITE_8021X 1
+#define CL_AKM_SUITE_PSK 2
+#define CL_AKM_SUITE_FT_8021X 3
+#define CL_AKM_SUITE_FT_PSK 4
+#define CL_AKM_SUITE_8021X_SHA256 5
+#define CL_AKM_SUITE_PSK_SHA256 6
+#define CL_AKM_SUITE_TDLS 7
+#define CL_AKM_SUITE_SAE 8
+#define CL_AKM_SUITE_FT_OVER_SAE 9
+#define CL_AKM_SUITE_8021X_SUITE_B 11
+#define CL_AKM_SUITE_8021X_SUITE_B_192 12
+#define CL_AKM_SUITE_FILS_SHA256 14
+#define CL_AKM_SUITE_FILS_SHA384 15
+#define CL_AKM_SUITE_FT_FILS_SHA256 16
+#define CL_AKM_SUITE_FT_FILS_SHA384 17
+
+#define CL_HWQ_BK 0
+#define CL_HWQ_BE 1
+#define CL_HWQ_VI 2
+#define CL_HWQ_VO 3
+#define CL_HWQ_BCN 4
+
+/* Traffic ID enumeration */
+enum {
+ TID_0,
+ TID_1,
+ TID_2,
+ TID_3,
+ TID_4,
+ TID_5,
+ TID_6,
+ TID_7,
+ TID_MAX
+};
+
+/* Access Category enumeration */
+enum {
+ AC_BK = 0,
+ AC_BE,
+ AC_VI,
+ AC_VO,
+ AC_MAX
+};
+
+enum cl_dev_flag {
+ CL_DEV_HW_RESTART,
+ CL_DEV_SW_RESTART,
+ CL_DEV_STOP_HW,
+ CL_DEV_STARTED,
+ CL_DEV_RADAR_LISTEN,
+ CL_DEV_INIT,
+ CL_DEV_FW_SYNC,
+ CL_DEV_FW_ERROR,
+ CL_DEV_REPEATER,
+ CL_DEV_MESH_AP,
+};
+
+enum cl_hw_mode {
+ HW_MODE_A,
+ HW_MODE_B,
+ HW_MODE_G,
+ HW_MODE_BG,
+
+ HW_MODE_MAX,
+};
+
+enum cl_channel_bw {
+ CHNL_BW_20,
+ CHNL_BW_40,
+ CHNL_BW_80,
+ CHNL_BW_160,
+
+ CHNL_BW_MAX,
+};
+
+#define MU_UL_MAX 4
+
+#define CHNL_BW_MAX_HE CHNL_BW_MAX
+#define CHNL_BW_MAX_VHT CHNL_BW_MAX
+#define CHNL_BW_MAX_HT CHNL_BW_80
+#define CHNL_BW_MAX_OFDM CHNL_BW_40
+#define CHNL_BW_MAX_CCK CHNL_BW_40
+
+#define CHNL_BW_2_5 4
+#define CHNL_BW_5 5
+#define CHNL_BW_10 6
+
+#define CHNL_BW_MAX_OFDMA 7
+
+enum cl_reg_standard {
+ CL_STANDARD_NONE,
+ CL_STANDARD_FCC,
+ CL_STANDARD_ETSI,
+};
+
+enum cl_wireless_mode {
+ WIRELESS_MODE_LEGACY,
+ WIRELESS_MODE_HT,
+ WIRELESS_MODE_HT_VHT,
+ WIRELESS_MODE_HT_VHT_HE,
+ WIRELESS_MODE_HE
+};
+
+enum cl_ndp_tx_chains {
+ NDP_TX_PHY0 = 0x1,
+ NDP_TX_PHY1 = 0x2,
+ NDP_TX_PHY01 = 0x3,
+};
+
+#define IS_VALID_TX_CHAINS(mask) \
+ (((mask) == NDP_TX_PHY0) || \
+ ((mask) == NDP_TX_PHY1) || \
+ ((mask) == NDP_TX_PHY01))
+
+#define Q2_TO_FREQ(x) ((x) >> 2)
+#define Q2_TO_FREQ_FRAC(x) (((x) & 0x3) * 25)
+#define FREQ_TO_Q2(freq) ((freq) << 2)
+
+/* Values of the firmware FORMATMOD fields */
+enum format_mode {
+ FORMATMOD_NON_HT = 0,
+ FORMATMOD_NON_HT_DUP_OFDM = 1,
+ FORMATMOD_HT_MF = 2,
+ FORMATMOD_HT_GF = 3,
+ FORMATMOD_VHT = 4,
+ FORMATMOD_HE_SU = 5,
+ FORMATMOD_HE_MU = 6,
+ FORMATMOD_HE_EXT = 7,
+ FORMATMOD_HE_TRIG = 8,
+ FORMATMOD_MAX = 9
+};
+
+/* PHY device options */
+enum {
+ PHY_DEV_OLYMPUS, /* Olympus - 5g + 24g */
+ PHY_DEV_ATHOS, /* Athos - 6g + 5g */
+ PHY_DEV_MAX,
+};
+
+#define IS_PHY_OLYMPUS(chip) ((chip)->conf->ci_phy_dev == PHY_DEV_OLYMPUS)
+#define IS_PHY_ATHOS(chip) ((chip)->conf->ci_phy_dev == PHY_DEV_ATHOS)
+
+#define ant_for_each(_ant) for (_ant = cl_hw->first_ant; _ant <= cl_hw->last_ant; _ant++)
+
+#define CL_MU_MAX_STA_PER_GROUP 8
+#define CL_MU_OFDMA_MAX_STA_PER_GRP 8
+#define CL_MU_MIMO_MAX_STA_PER_GRP 4
+
+#endif /* CL_DEF_H */
--
2.30.0

________________________________
The information transmitted is intended only for the person or entity to which it is addressed and may contain confidential and/or privileged material. Any retransmission, dissemination, copying or other use of, or taking of any action in reliance upon this information is prohibited. If you received this in error, please contact the sender and delete the material from any computer. Nothing contained herein shall be deemed as a representation, warranty or a commitment by Celeno. No warranties are expressed or implied, including, but not limited to, any implied warranties of non-infringement, merchantability and fitness for a particular purpose.
________________________________

2021-06-17 16:26:17

by viktor.barna

[permalink] [raw]
Subject: [RFC v1 090/256] cl8k: add fw/fw_msg.c

From: Viktor Barna <[email protected]>

(Part of the split. Please, take a look at the cover letter for more
details).

Signed-off-by: Viktor Barna <[email protected]>
---
drivers/net/wireless/celeno/cl8k/fw/fw_msg.c | 135 +++++++++++++++++++
1 file changed, 135 insertions(+)
create mode 100644 drivers/net/wireless/celeno/cl8k/fw/fw_msg.c

diff --git a/drivers/net/wireless/celeno/cl8k/fw/fw_msg.c b/drivers/net/wireless/celeno/cl8k/fw/fw_msg.c
new file mode 100644
index 000000000000..ea59bf57fa97
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/fw/fw_msg.c
@@ -0,0 +1,135 @@
+// SPDX-License-Identifier: MIT
+/* Copyright(c) 2019-2021, Celeno Communications Ltd. */
+
+#include "fw/fw_msg.h"
+
+/* Should be used for REQ and CFM only */
+const char *const msg2str[MSG_TOTAL_REQ_CFM] = {
+ /* MM messages */
+ [MM_RESET_REQ] = "MM_RESET_REQ",
+ [MM_RESET_CFM] = "MM_RESET_CFM",
+ [MM_START_REQ] = "MM_START_REQ",
+ [MM_START_CFM] = "MM_START_CFM",
+ [MM_VERSION_REQ] = "MM_VERSION_REQ",
+ [MM_VERSION_CFM] = "MM_VERSION_CFM",
+ [MM_ADD_IF_REQ] = "MM_ADD_IF_REQ",
+ [MM_ADD_IF_CFM] = "MM_ADD_IF_CFM",
+ [MM_REMOVE_IF_REQ] = "MM_REMOVE_IF_REQ",
+ [MM_REMOVE_IF_CFM] = "MM_REMOVE_IF_CFM",
+ [MM_STA_ADD_REQ] = "MM_STA_ADD_REQ",
+ [MM_STA_ADD_CFM] = "MM_STA_ADD_CFM",
+ [MM_STA_DEL_REQ] = "MM_STA_DEL_REQ",
+ [MM_STA_DEL_CFM] = "MM_STA_DEL_CFM",
+ [MM_SET_FILTER_REQ] = "MM_SET_FILTER_REQ",
+ [MM_SET_FILTER_CFM] = "MM_SET_FILTER_CFM",
+ [MM_SET_CHANNEL_REQ] = "MM_SET_CHANNEL_REQ",
+ [MM_SET_CHANNEL_CFM] = "MM_SET_CHANNEL_CFM",
+ [MM_SET_DTIM_REQ] = "MM_SET_DTIM_REQ",
+ [MM_SET_DTIM_CFM] = "MM_SET_DTIM_CFM",
+ [MM_SET_BEACON_INT_REQ] = "MM_SET_BEACON_INT_REQ",
+ [MM_SET_BEACON_INT_CFM] = "MM_SET_BEACON_INT_CFM",
+ [MM_SET_BASIC_RATES_REQ] = "MM_SET_BASIC_RATES_REQ",
+ [MM_SET_BASIC_RATES_CFM] = "MM_SET_BASIC_RATES_CFM",
+ [MM_SET_BSSID_REQ] = "MM_SET_BSSID_REQ",
+ [MM_SET_BSSID_CFM] = "MM_SET_BSSID_CFM",
+ [MM_SET_EDCA_REQ] = "MM_SET_EDCA_REQ",
+ [MM_SET_EDCA_CFM] = "MM_SET_EDCA_CFM",
+ [MM_SET_ASSOCIATED_REQ] = "MM_SET_ASSOCIATED_REQ",
+ [MM_SET_ASSOCIATED_CFM] = "MM_SET_ASSOCIATED_CFM",
+ [MM_SET_SLOTTIME_REQ] = "MM_SET_SLOTTIME_REQ",
+ [MM_SET_SLOTTIME_CFM] = "MM_SET_SLOTTIME_CFM",
+ [MM_SET_IDLE_REQ] = "MM_SET_IDLE_REQ",
+ [MM_SET_IDLE_CFM] = "MM_SET_IDLE_CFM",
+ [MM_KEY_ADD_REQ] = "MM_KEY_ADD_REQ",
+ [MM_KEY_ADD_CFM] = "MM_KEY_ADD_CFM",
+ [MM_KEY_DEL_REQ] = "MM_KEY_DEL_REQ",
+ [MM_KEY_DEL_CFM] = "MM_KEY_DEL_CFM",
+ [MM_BA_ADD_TX_REQ] = "MM_BA_ADD_TX_REQ",
+ [MM_BA_ADD_TX_CFM] = "MM_BA_ADD_TX_CFM",
+ [MM_BA_ADD_RX_REQ] = "MM_BA_ADD_RX_REQ",
+ [MM_BA_ADD_RX_CFM] = "MM_BA_ADD_RX_CFM",
+ [MM_BA_DEL_REQ] = "MM_BA_DEL_REQ",
+ [MM_BA_DEL_CFM] = "MM_BA_DEL_CFM",
+ [MM_PHY_RESET_REQ] = "MM_PHY_RESET_REQ",
+ [MM_PHY_RESET_CFM] = "MM_PHY_RESET_CFM",
+ [MM_AVAILABLE_BA_TXQ_REQ] = "MM_AVAILABLE_BA_TXQ_REQ",
+ [MM_AVAILABLE_BA_TXQ_CFM] = "MM_AVAILABLE_BA_TXQ_CFM",
+ [MM_UPDATE_RATE_DL_REQ] = "MM_UPDATE_RATE_DL_REQ",
+ [MM_UPDATE_RATE_DL_CFM] = "MM_UPDATE_RATE_DL_CFM",
+ [MM_SET_VNS_REQ] = "MM_SET_VNS_REQ",
+ [MM_SET_VNS_CFM] = "MM_SET_VNS_CFM",
+ [MM_SET_TX_BF_REQ] = "MM_SET_TX_BF_REQ",
+ [MM_SET_TX_BF_CFM] = "MM_SET_TX_BF_CFM",
+ [MM_SOUNDING_REQ] = "MM_SOUNDING_REQ",
+ [MM_SOUNDING_CFM] = "MM_SOUNDING_CFM",
+ [MM_SOUNDING_PAIRING_REQ] = "MM_SOUNDING_PAIRING_REQ",
+ [MM_SOUNDING_PAIRING_CFM] = "MM_SOUNDING_PAIRING_CFM",
+ [MM_SOUNDING_INTERVAL_REQ] = "MM_SOUNDING_INTERVAL_REQ",
+ [MM_SOUNDING_INTERVAL_CFM] = "MM_SOUNDING_INTERVAL_CFM",
+ [MM_SOUNDING_STA_SWITCH_REQ] = "MM_SOUNDING_STA_SWITCH_REQ",
+ [MM_SOUNDING_STA_SWITCH_CFM] = "MM_SOUNDING_STA_SWITCH_CFM",
+ [MM_CONFIG_CCA_REQ] = "MM_CONFIG_CCA_REQ",
+ [MM_CONFIG_CCA_CFM] = "MM_CONFIG_CCA_CFM",
+ [MM_SET_DFS_REQ] = "MM_SET_DFS_REQ",
+ [MM_SET_DFS_CFM] = "MM_SET_DFS_CFM",
+ [MM_SET_ANT_BITMAP_REQ] = "MM_SET_ANT_BITMAP_REQ",
+ [MM_SET_ANT_BITMAP_CFM] = "MM_SET_ANT_BITMAP_CFM",
+ [MM_NDP_TX_CONTROL_REQ] = "MM_NDP_TX_CONTROL_REQ",
+ [MM_NDP_TX_CONTROL_CFM] = "MM_NDP_TX_CONTROL_CFM",
+ [MM_REG_WRITE_REQ] = "MM_REG_WRITE_REQ",
+ [MM_REG_WRITE_CFM] = "MM_REG_WRITE_CFM",
+ [MM_PROT_MODE_REQ] = "MM_PROT_MODE_REQ",
+ [MM_PROT_MODE_CFM] = "MM_PROT_MODE_CFM",
+ [MM_GOTO_POWER_REDUCTION_REQ] = "MM_GOTO_POWER_REDUCTION_REQ",
+ [MM_GOTO_POWER_REDUCTION_CFM] = "MM_GOTO_POWER_REDUCTION_CFM",
+ [MM_BACKUP_BCN_EN_REQ] = "MM_BACKUP_BCN_EN_REQ",
+ [MM_BACKUP_BCN_EN_CFM] = "MM_BACKUP_BCN_EN_CFM",
+ [MM_START_PERIODIC_TX_TIME_REQ] = "MM_START_PERIODIC_TX_TIME_REQ",
+ [MM_START_PERIODIC_TX_TIME_CFM] = "MM_START_PERIODIC_TX_TIME_CFM",
+ [MM_ANAMON_READ_REQ] = "MM_ANAMON_READ_REQ",
+ [MM_ANAMON_READ_CFM] = "MM_ANAMON_READ_CFM",
+ [MM_REFRESH_PWR_REQ] = "MM_REFRESH_PWR_REQ",
+ [MM_REFRESH_PWR_CFM] = "MM_REFRESH_PWR_CFM",
+ [MM_SET_ANT_PWR_OFFSET_REQ] = "MM_SET_ANT_PWR_OFFSET_REQ",
+ [MM_SET_ANT_PWR_OFFSET_CFM] = "MM_SET_ANT_PWR_OFFSET_CFM",
+ [MM_SET_RATE_FALLBACK_REQ] = "MM_SET_RATE_FALLBACK_REQ",
+ [MM_SET_RATE_FALLBACK_CFM] = "MM_SET_RATE_FALLBACK_CFM",
+ [MM_TWT_SETUP_REQ] = "MM_TWT_SETUP_REQ",
+ [MM_TWT_SETUP_CFM] = "MM_TWT_SETUP_CFM",
+ [MM_TWT_TEARDOWN_REQ] = "MM_TWT_TEARDOWN_REQ",
+ [MM_TWT_TEARDOWN_CFM] = "MM_TWT_TEARDOWN_CFM",
+ [MM_RSRC_MGMT_REQ] = "MM_RSRC_MGMT_REQ",
+ [MM_RSRC_MGMT_CFM] = "MM_RSRC_MGMT_CFM",
+ [MM_SET_FREQ_OFFSET_REQ] = "MM_SET_FREQ_OFFSET_REQ",
+ [MM_SET_FREQ_OFFSET_CFM] = "MM_SET_FREQ_OFFSET_CFM",
+
+ /* DBG messages */
+ [DBG_STR_SHIFT(DBG_SET_MOD_FILTER_REQ)] = "DBG_SET_MOD_FILTER_REQ",
+ [DBG_STR_SHIFT(DBG_SET_MOD_FILTER_CFM)] = "DBG_SET_MOD_FILTER_CFM",
+ [DBG_STR_SHIFT(DBG_CE_SET_MOD_FILTER_REQ)] = "DBG_CE_SET_MOD_FILTER_REQ",
+ [DBG_STR_SHIFT(DBG_CE_SET_MOD_FILTER_CFM)] = "DBG_CE_SET_MOD_FILTER_CFM",
+ [DBG_STR_SHIFT(DBG_SET_SEV_FILTER_REQ)] = "DBG_SET_SEV_FILTER_REQ",
+ [DBG_STR_SHIFT(DBG_SET_SEV_FILTER_CFM)] = "DBG_SET_SEV_FILTER_CFM",
+ [DBG_STR_SHIFT(DBG_BEAMFORMING_TX_REQ)] = "DBG_BEAMFORMING_TX_REQ",
+ [DBG_STR_SHIFT(DBG_BEAMFORMING_TX_CFM)] = "DBG_BEAMFORMING_TX_CFM",
+ [DBG_STR_SHIFT(DBG_GET_E2W_STATS_REQ)] = "DBG_GET_E2W_STATS_REQ",
+ [DBG_STR_SHIFT(DBG_GET_E2W_STATS_CFM)] = "DBG_GET_E2W_STATS_CFM",
+ [DBG_STR_SHIFT(DBG_SET_LA_MPIF_MASK_REQ)] = "DBG_SET_LA_MPIF_MASK_REQ",
+ [DBG_STR_SHIFT(DBG_SET_LA_MPIF_MASK_CFM)] = "DBG_SET_LA_MPIF_MASK_CFM",
+ [DBG_STR_SHIFT(DBG_SET_LA_TRIG_POINT_REQ)] = "DBG_SET_LA_TRIG_POINT_REQ",
+ [DBG_STR_SHIFT(DBG_SET_LA_TRIG_POINT_CFM)] = "DBG_SET_LA_TRIG_POINT_CFM",
+ [DBG_STR_SHIFT(DBG_SET_LA_MPIF_DEBUG_MODE_REQ)] = "DBG_SET_LA_MPIF_DEBUG_MODE_REQ",
+ [DBG_STR_SHIFT(DBG_SET_LA_MPIF_DEBUG_MODE_CFM)] = "DBG_SET_LA_MPIF_DEBUG_MODE_CFM",
+ [DBG_STR_SHIFT(DBG_SET_LA_TRIG_RULE_REQ)] = "DBG_SET_LA_TRIG_RULE_REQ",
+ [DBG_STR_SHIFT(DBG_SET_LA_TRIG_RULE_CFM)] = "DBG_SET_LA_TRIG_RULE_CFM",
+ [DBG_STR_SHIFT(DBG_TX_TRACE_DEBUG_FLAG_REQ)] = "DBG_TX_TRACE_DEBUG_FLAG_REQ",
+ [DBG_STR_SHIFT(DBG_TX_TRACE_DEBUG_FLAG_CFM)] = "DBG_TX_TRACE_DEBUG_FLAG_CFM",
+ [DBG_STR_SHIFT(DBG_PRINT_STATS_REQ)] = "DBG_PRINT_STATS_REQ",
+ [DBG_STR_SHIFT(DBG_PRINT_STATS_CFM)] = "DBG_PRINT_STATS_CFM",
+ [DBG_STR_SHIFT(DBG_TRIGGER_REQ)] = "DBG_TRIGGER_REQ",
+ [DBG_STR_SHIFT(DBG_TRIGGER_CFM)] = "DBG_TRIGGER_CFM",
+ [DBG_STR_SHIFT(DBG_TEST_MODE_REQ)] = "DBG_TEST_MODE_REQ",
+ [DBG_STR_SHIFT(DBG_TEST_MODE_CFM)] = "DBG_TEST_MODE_CFM",
+ [DBG_STR_SHIFT(DBG_SOUNDING_CMD_REQ)] = "DBG_SOUNDING_CMD_REQ",
+ [DBG_STR_SHIFT(DBG_SOUNDING_CMD_CFM)] = "DBG_SOUNDING_CMD_CFM",
+};
--
2.30.0

________________________________
The information transmitted is intended only for the person or entity to which it is addressed and may contain confidential and/or privileged material. Any retransmission, dissemination, copying or other use of, or taking of any action in reliance upon this information is prohibited. If you received this in error, please contact the sender and delete the material from any computer. Nothing contained herein shall be deemed as a representation, warranty or a commitment by Celeno. No warranties are expressed or implied, including, but not limited to, any implied warranties of non-infringement, merchantability and fitness for a particular purpose.
________________________________

2021-06-17 16:26:22

by viktor.barna

[permalink] [raw]
Subject: [RFC v1 105/256] cl8k: add mac80211.c

From: Viktor Barna <[email protected]>

(Part of the split. Please, take a look at the cover letter for more
details).

Signed-off-by: Viktor Barna <[email protected]>
---
drivers/net/wireless/celeno/cl8k/mac80211.c | 17 +++++++++++++++++
1 file changed, 17 insertions(+)
create mode 100644 drivers/net/wireless/celeno/cl8k/mac80211.c

diff --git a/drivers/net/wireless/celeno/cl8k/mac80211.c b/drivers/net/wireless/celeno/cl8k/mac80211.c
new file mode 100644
index 000000000000..4ba6dd1e6eec
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/mac80211.c
@@ -0,0 +1,17 @@
+// SPDX-License-Identifier: MIT
+/* Copyright(c) 2019-2021, Celeno Communications Ltd. */
+
+#include "mac80211.h"
+#include <net/mac80211.h>
+
+/* Copied from kernel/bp/net/mac80211/wme.c */
+const int ieee802_1d_to_ac[8] = {
+ IEEE80211_AC_BE,
+ IEEE80211_AC_BK,
+ IEEE80211_AC_BK,
+ IEEE80211_AC_BE,
+ IEEE80211_AC_VI,
+ IEEE80211_AC_VI,
+ IEEE80211_AC_VO,
+ IEEE80211_AC_VO
+};
--
2.30.0

________________________________
The information transmitted is intended only for the person or entity to which it is addressed and may contain confidential and/or privileged material. Any retransmission, dissemination, copying or other use of, or taking of any action in reliance upon this information is prohibited. If you received this in error, please contact the sender and delete the material from any computer. Nothing contained herein shall be deemed as a representation, warranty or a commitment by Celeno. No warranties are expressed or implied, including, but not limited to, any implied warranties of non-infringement, merchantability and fitness for a particular purpose.
________________________________

2021-06-17 16:26:22

by viktor.barna

[permalink] [raw]
Subject: [RFC v1 066/256] cl8k: add dsp.h

From: Viktor Barna <[email protected]>

(Part of the split. Please, take a look at the cover letter for more
details).

Signed-off-by: Viktor Barna <[email protected]>
---
drivers/net/wireless/celeno/cl8k/dsp.h | 27 ++++++++++++++++++++++++++
1 file changed, 27 insertions(+)
create mode 100644 drivers/net/wireless/celeno/cl8k/dsp.h

diff --git a/drivers/net/wireless/celeno/cl8k/dsp.h b/drivers/net/wireless/celeno/cl8k/dsp.h
new file mode 100644
index 000000000000..f9802c479e47
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/dsp.h
@@ -0,0 +1,27 @@
+/* SPDX-License-Identifier: MIT */
+/* Copyright(c) 2019-2021, Celeno Communications Ltd. */
+
+#ifndef CL_DSP_H
+#define CL_DSP_H
+
+#include "chip.h"
+
+/*
+ * cl_dsp_load_regular - Load DSP firmware for both TCV's.
+ *
+ * @chip - chip pointer.
+ *
+ * Return value: 0 upon success, negative errno code upon failure.
+ */
+int cl_dsp_load_regular(struct cl_chip *chip);
+
+/*
+ * cl_dsp_load_recovery - Load only DSP data for single TCV.
+ *
+ * @chip - chip pointer.
+ *
+ * Return value: 0 upon success, negative errno code upon failure.
+ */
+int cl_dsp_load_recovery(struct cl_hw *cl_hw);
+
+#endif /* CL_DSP_LOAD_H */
--
2.30.0

________________________________
The information transmitted is intended only for the person or entity to which it is addressed and may contain confidential and/or privileged material. Any retransmission, dissemination, copying or other use of, or taking of any action in reliance upon this information is prohibited. If you received this in error, please contact the sender and delete the material from any computer. Nothing contained herein shall be deemed as a representation, warranty or a commitment by Celeno. No warranties are expressed or implied, including, but not limited to, any implied warranties of non-infringement, merchantability and fitness for a particular purpose.
________________________________

2021-06-17 16:26:27

by viktor.barna

[permalink] [raw]
Subject: [RFC v1 106/256] cl8k: add mac80211.h

From: Viktor Barna <[email protected]>

(Part of the split. Please, take a look at the cover letter for more
details).

Signed-off-by: Viktor Barna <[email protected]>
---
drivers/net/wireless/celeno/cl8k/mac80211.h | 310 ++++++++++++++++++++
1 file changed, 310 insertions(+)
create mode 100644 drivers/net/wireless/celeno/cl8k/mac80211.h

diff --git a/drivers/net/wireless/celeno/cl8k/mac80211.h b/drivers/net/wireless/celeno/cl8k/mac80211.h
new file mode 100644
index 000000000000..57bd08d5a730
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/mac80211.h
@@ -0,0 +1,310 @@
+/* SPDX-License-Identifier: MIT */
+/* Copyright(c) 2019-2021, Celeno Communications Ltd. */
+
+#ifndef CL_MAC80211_H
+#define CL_MAC80211_H
+
+#include <linux/types.h>
+#include <linux/if_ether.h>
+
+extern const int ieee802_1d_to_ac[8];
+
+#define IEEE80211_CTRL_A_CTRL_MASK 0x3
+
+#define IEEE80211_CTRL_A_CTRL_ID_OM 0x1
+#define IEEE80211_CTRL_A_CTRL_ID_UPH 0x4
+
+#define IEEE80211_CTRL_UPH_OFFSET 6
+
+static inline bool ieee80211_has_a_ctrl(u32 val)
+{
+ return ((val & IEEE80211_CTRL_A_CTRL_MASK) == IEEE80211_CTRL_A_CTRL_MASK);
+}
+
+struct ieee80211_a_control {
+ union {
+ struct {
+ u32 b0 : 1,
+ b1 : 1,
+ control_id : 4,
+ control_info : 26;
+ } __packed fields;
+ u32 value;
+ } u;
+} __packed;
+
+struct ieee80211_uph_ctrl {
+ union {
+ struct {
+ u8 pwr_headroom : 5,
+ min_pwr : 1,
+ reserved : 2;
+ } __packed fields;
+ u8 value;
+ } u;
+} __packed;
+
+/* HTC header might includes HT/VHT/HE variant */
+/* This struct implements only HE variant type */
+struct ieee80211_qos_htc_hdr {
+ __le16 frame_control;
+ __le16 duration_id;
+ u8 addr1[ETH_ALEN];
+ u8 addr2[ETH_ALEN];
+ u8 addr3[ETH_ALEN];
+ __le16 seq_ctrl;
+ __le16 qos_ctrl;
+ struct ieee80211_a_control a_ctrl;
+} __packed __aligned(2);
+
+/* WLAN_EID_BSS_COEX_2040 = 72 */
+/* 802.11n 7.3.2.61 */
+struct ieee80211_bss_coex_20_40_ie {
+ u8 element_id;
+ u8 len;
+ u8 info_req : 1;
+ /* Inter-BSS set 1 when prohibits a receiving BSS from operating as a 20/40 Mhz BSS */
+ u8 intolerant40 : 1;
+ /* Intra-BSS set 1 when prohibits a receiving AP from operating its BSS as a 20/40MHz BSS */
+ u8 bss20_width_req : 1;
+ u8 obss_scan_exemp_req : 1;
+ u8 obss_scan_exemp_grant : 1;
+ u8 rsv : 3;
+} __packed;
+
+/* WLAN_EID_BSS_INTOLERANT_CHL_REPORT = 73 */
+/*802.11n 7.3.2.59 */
+struct ieee80211_bss_intolerant_chl_report_ie {
+ u8 element_id;
+ u8 len;
+ u8 regulatory_class;
+ u8 ch_list[0];
+} __packed;
+
+enum ieee80211_twt_setup_command {
+ IEEE80211_TWT_SETUP_COMMAND_REQUEST = 0,
+ IEEE80211_TWT_SETUP_COMMAND_SUGGEST = 1,
+ IEEE80211_TWT_SETUP_COMMAND_DEMAND = 2,
+ IEEE80211_TWT_SETUP_COMMAND_GROUPING = 3,
+ IEEE80211_TWT_SETUP_COMMAND_ACCEPT = 4,
+ IEEE80211_TWT_SETUP_COMMAND_ALTERNATE = 5,
+ IEEE80211_TWT_SETUP_COMMAND_DICTATE = 6,
+ IEEE80211_TWT_SETUP_COMMAND_REJECT = 7
+};
+
+union ieee80211_twt_control_field {
+ struct {
+ u8 ndp_paging_indicator:1,
+ responder_pm_mode:1,
+ negotiation_type:2,
+ twt_info_frame_disabled:1,
+ wake_duration_unit:1, /* 0 - 256us, 1 - 1024us */
+ reserved:2;
+ } __packed fields;
+ u8 value;
+} __packed;
+
+struct ieee80211_twt_individual_elem {
+ union ieee80211_twt_control_field control;
+ union {
+ struct {
+ u16 request :1,
+ setup_cmd :3,
+ trigger :1,
+ implicit :1,
+ flow_type :1,
+ flow_id :3,
+ wake_interval_exponent:5,
+ protection :1;
+ } __packed fields;
+ u16 value;
+ } req_type;
+ u64 target_wake_time;
+ u8 min_wake_duration;
+ u16 wake_interval_mantissa;
+ u8 channel;
+} __packed;
+
+struct ieee80211_twt_broadcast_elem {
+ union ieee80211_twt_control_field control;
+ union {
+ struct {
+ u16 request :1,
+ setup_cmd :3,
+ trigger :1,
+ last_broadcast_param_set:1,
+ flow_type :1,
+ recommendation :3,
+ wake_interval_exponent :5,
+ reserved :1;
+ } __packed fields;
+ u16 value;
+ } req_type;
+ u16 target_wake_time;
+ u8 min_wake_duration;
+ u16 wake_interval_mantissa;
+ union {
+ struct {
+ u16 reserved :3,
+ id :5,
+ persistence:8;
+ } __packed fields;
+ u16 value;
+ } broadcast_twt_info;
+} __packed;
+
+/* Union options that are not included in 'struct ieee80211_mgmt' */
+struct cl_ieee80211_mgmt {
+ __le16 frame_control;
+ __le16 duration;
+ u8 da[ETH_ALEN];
+ u8 sa[ETH_ALEN];
+ u8 bssid[ETH_ALEN];
+ __le16 seq_ctrl;
+ union {
+ struct {
+ __le16 auth_alg;
+ __le16 auth_transaction;
+ __le16 status_code;
+ /* Possibly followed by Challenge text */
+ u8 variable[0];
+ } __packed auth;
+ struct {
+ __le16 reason_code;
+ } __packed deauth;
+ struct {
+ __le16 capab_info;
+ __le16 listen_interval;
+ /* Followed by SSID and Supported rates */
+ u8 variable[0];
+ } __packed assoc_req;
+ struct {
+ __le16 capab_info;
+ __le16 status_code;
+ __le16 aid;
+ /* Followed by Supported rates */
+ u8 variable[0];
+ } __packed assoc_resp, reassoc_resp;
+ struct {
+ __le16 capab_info;
+ __le16 listen_interval;
+ u8 current_ap[ETH_ALEN];
+ /* Followed by SSID and Supported rates */
+ u8 variable[0];
+ } __packed reassoc_req;
+ struct {
+ __le16 reason_code;
+ } __packed disassoc;
+ struct {
+ __le64 timestamp;
+ __le16 beacon_int;
+ __le16 capab_info;
+ /*
+ * Followed by some of SSID, Supported rates,
+ * FH Params, DS Params, CF Params, IBSS Params, TIM
+ */
+ u8 variable[0];
+ } __packed beacon;
+ struct {
+ /* Only variable items: SSID, Supported rates */
+ u8 variable[0];
+ } __packed probe_req;
+ struct {
+ __le64 timestamp;
+ __le16 beacon_int;
+ __le16 capab_info;
+ /*
+ * Followed by some of SSID, Supported rates,
+ * FH Params, DS Params, CF Params, IBSS Params
+ */
+ u8 variable[0];
+ } __packed probe_resp;
+ struct {
+ u8 category;
+ union {
+ struct {
+ u8 action_code;
+ struct ieee80211_bss_coex_20_40_ie bss_coex_20_40_ie;
+ /*
+ * This IE May appear zero or more times,
+ * that situation wasn't handled here.
+ */
+ struct ieee80211_bss_intolerant_chl_report_ie
+ bss_intolerant_chl_report_ie;
+ } __packed coex_2040_mgmt;
+ struct {
+ u8 action_code;
+ u8 dialog_token;
+ u8 twt_elem_id;
+ u8 twt_elem_length;
+ struct ieee80211_twt_individual_elem twt_elem;
+ } __packed twt_individual_setup;
+ struct {
+ u8 action_code;
+ u8 dialog_token;
+ u8 twt_elem_id;
+ u8 twt_elem_length;
+ struct ieee80211_twt_broadcast_elem twt_elem;
+ } __packed twt_broadcast_setup;
+ struct {
+ u8 action_code;
+ /*
+ * reserved bits can be combined with flow_id to
+ * form broadcast TWT id of 5 bits in case that
+ * negotiation_type = 3
+ */
+ u8 flow_id :3,
+ reserved:2,
+ negotiation_type:2,
+ teardown_all_twt:1;
+ } __packed twt_individual_teardown;
+ struct {
+ u8 action_code;
+ u8 flow_id:3,
+ response_requested:1,
+ next_twt_request:1,
+ next_twt_subfield_size:2,
+ all_twt:1;
+ u8 next_twt[64];
+ } __packed twt_information;
+ } u;
+ } __packed action;
+ } u;
+} __packed __aligned(2);
+
+/*
+ * Information Element IDs
+ * Should be part of 'enum ieee80211_eid'
+ */
+#define WLAN_EID_TWT 216
+
+/*
+ * Action category code
+ * Should be part of 'enum ieee80211_category'
+ */
+#define WLAN_CATEGORY_UNPROTECTED_S1G 22
+#define WLAN_CATEGORY_S1G 23
+
+enum ieee80211_unprotected_s1g_actioncode {
+ WLAN_UNPROT_S1G_ACTION_AID_SWITCH_REQUEST = 0,
+ WLAN_UNPROT_S1G_ACTION_AID_SWITCH_RESPONSE = 1,
+ WLAN_UNPROT_S1G_ACTION_SYNC_CONTROL = 2,
+ WLAN_UNPROT_S1G_ACTION_STA_INFO_ANNOUNCEMENT = 3,
+ WLAN_UNPROT_S1G_ACTION_EDCA_PARAMETER_SET = 4,
+ WLAN_UNPROT_S1G_ACTION_EL_OPERATION = 5,
+ WLAN_UNPROT_S1G_ACTION_TWT_SETUP = 6,
+ WLAN_UNPROT_S1G_ACTION_TWT_TEARDOWN = 7,
+ WLAN_UNPROT_S1G_ACTION_SECTORIZED_GROUP_ID_LIST = 8,
+ WLAN_UNPROT_S1G_ACTION_SECTOR_ID_FEEDBACK = 9,
+ WLAN_UNPROT_S1G_ACTION_RESERVED = 10,
+ WLAN_UNPROT_S1G_ACTION_TWT_INFORMATION = 11,
+};
+
+/*
+ * Extended Channel Switching capability to be set in the 1st byte of
+ * the @WLAN_EID_EXT_CAPABILITY information element
+ */
+#define WLAN_EXT_CAPA1_2040_BSS_COEX_MGMT_ENABLED BIT(0)
+#define WLAN_EXT_CAPA11_COMPLETE_LIST_OF_NONTXBSSID_PROFILES BIT(0)
+
+#endif /* CL_MAC80211_H */
--
2.30.0

________________________________
The information transmitted is intended only for the person or entity to which it is addressed and may contain confidential and/or privileged material. Any retransmission, dissemination, copying or other use of, or taking of any action in reliance upon this information is prohibited. If you received this in error, please contact the sender and delete the material from any computer. Nothing contained herein shall be deemed as a representation, warranty or a commitment by Celeno. No warranties are expressed or implied, including, but not limited to, any implied warranties of non-infringement, merchantability and fitness for a particular purpose.
________________________________

2021-06-17 16:26:29

by viktor.barna

[permalink] [raw]
Subject: [RFC v1 065/256] cl8k: add dsp.c

From: Viktor Barna <[email protected]>

(Part of the split. Please, take a look at the cover letter for more
details).

Signed-off-by: Viktor Barna <[email protected]>
---
drivers/net/wireless/celeno/cl8k/dsp.c | 611 +++++++++++++++++++++++++
1 file changed, 611 insertions(+)
create mode 100644 drivers/net/wireless/celeno/cl8k/dsp.c

diff --git a/drivers/net/wireless/celeno/cl8k/dsp.c b/drivers/net/wireless/celeno/cl8k/dsp.c
new file mode 100644
index 000000000000..cf9646cd1ed4
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/dsp.c
@@ -0,0 +1,611 @@
+// SPDX-License-Identifier: MIT
+/* Copyright(c) 2019-2021, Celeno Communications Ltd. */
+
+#include "reg/reg_modem_gcu.h"
+#include "reg/reg_macdsp_api.h"
+#include "reg/reg_cmu.h"
+#include "reg/reg_access.h"
+#include "reg/ceva.h"
+#include "dsp.h"
+#include "hw.h"
+#include <linux/firmware.h>
+
+#define BUSY_WAIT_LIMIT 10000
+
+static int dsp_busy_wait(struct cl_hw *cl_hw, u32 control_reg)
+{
+ int i;
+
+ for (i = 0; i < BUSY_WAIT_LIMIT; i++) {
+ /* Poll Bit29 to verify DMA transfer has ended. */
+ if ((cl_reg_read(cl_hw, control_reg) & 0x20000000) == 0)
+ return 0;
+
+ cpu_relax();
+ }
+
+ return -EIO;
+}
+
+static void cl_dsp_boot(struct cl_hw *cl_hw)
+{
+ struct cl_chip *chip = cl_hw->chip;
+
+ if (cl_hw_is_tcv0(cl_hw)) {
+ /* Disable ceva_free_clk */
+ cmu_phy_0_clk_en_ceva_0_clk_en_setf(chip, 0);
+ /* Assert Ceva reset */
+ cmu_phy_0_rst_ceva_0_global_rst_n_setf(chip, 0);
+ } else {
+ /* Disable ceva_free_clk */
+ cmu_phy_1_clk_en_ceva_1_clk_en_setf(chip, 0);
+ /* Assert Ceva reset */
+ cmu_phy_1_rst_ceva_1_global_rst_n_setf(chip, 0);
+ }
+
+ /* Set Ceva boot=1 */
+ modem_gcu_ceva_ctrl_boot_setf(cl_hw, 1);
+ /* Set Ceva vector */
+ modem_gcu_ceva_vec_set(cl_hw, 0);
+
+ if (cl_hw_is_tcv0(cl_hw)) {
+ /* Enable ceva_clk */
+ cmu_phy_0_clk_en_ceva_0_clk_en_setf(chip, 1);
+ /* Disabel ceva_clk */
+ cmu_phy_0_clk_en_ceva_0_clk_en_setf(chip, 0);
+ /* De-Assert Ceva reset - Reset Release */
+ cmu_phy_0_rst_ceva_0_global_rst_n_setf(chip, 1);
+ /* Enable ceva_clk */
+ cmu_phy_0_clk_en_ceva_0_clk_en_setf(chip, 1);
+ } else {
+ /* Enable ceva_clk */
+ cmu_phy_1_clk_en_ceva_1_clk_en_setf(chip, 1);
+ /* Disabel ceva_clk */
+ cmu_phy_1_clk_en_ceva_1_clk_en_setf(chip, 0);
+ /* De-Assert Ceva reset - Reset Release */
+ cmu_phy_1_rst_ceva_1_global_rst_n_setf(chip, 1);
+ /* Enable ceva_clk */
+ cmu_phy_1_clk_en_ceva_1_clk_en_setf(chip, 1);
+ }
+
+ /* Release Ceva external_wait */
+ modem_gcu_ceva_ctrl_external_wait_setf(cl_hw, 0);
+ /* Set Ceva boot=0 */
+ modem_gcu_ceva_ctrl_boot_setf(cl_hw, 0);
+}
+
+static void config_dma_for_code_copy(struct cl_hw *cl_hw, u32 page)
+{
+ /* Configure Program DMA to copy FW code from Shared PMEM to internal PMEM. */
+
+ /* External address to read from. */
+ cl_reg_write(cl_hw, CEVA_CPM_PDEA_REG, CEVA_SHARED_PMEM_BASE_ADDR_INTERNAL);
+ /* Internal address to write to. */
+ cl_reg_write(cl_hw, CEVA_CPM_PDIA_REG, CEVA_SHARED_PMEM_SIZE * page);
+ /* Page size */
+ cl_reg_write(cl_hw, CEVA_CPM_PDTC_REG, CEVA_SHARED_PMEM_SIZE);
+}
+
+static void config_dma_for_external_data_copy(struct cl_hw *cl_hw)
+{
+ /* Configure Program DMA to copy FW code from Shared XMEM to internal XMEM. */
+
+ /* External address to read from. */
+ cl_reg_write(cl_hw, CEVA_CPM_DDEA_REG, CEVA_SHARED_XMEM_BASE_ADDR_INTERNAL);
+ /* Internal address to write to. */
+ cl_reg_write(cl_hw, CEVA_CPM_DDIA_REG, 0);
+ /* Page size + DMA direction is write */
+ cl_reg_write(cl_hw, CEVA_CPM_DDTC_REG,
+ CEVA_SHARED_XMEM_SIZE | CEVA_CPM_DDTC_WRITE_COMMAND);
+}
+
+static int cl_dsp_hex_load(struct cl_hw *cl_hw, const u8 *buf,
+ off_t offset, size_t size, size_t buf_size)
+{
+ u8 single_buf[4] = {0};
+ u32 bin_data = 0;
+ u8 next_byte;
+ u8 byte_num = 0;
+ int ret = 0;
+ ssize_t oft = 0;
+ size_t real_size = min(size * 3, buf_size);
+ /*
+ * CEVA_SHARED_PMEM_BASE_ADDR_FROM_HOST is global and we don't
+ * want to add TCV reg offset.
+ */
+ bool chip_reg = (offset == CEVA_SHARED_PMEM_BASE_ADDR_FROM_HOST);
+
+ if (buf_size % 3) {
+ cl_dbg_err(cl_hw, "DSP size %zu must be divided by 3 !!!\n",
+ buf_size);
+ return -EINVAL;
+ }
+
+ while (oft < real_size) {
+ memcpy(single_buf, buf + oft, 3);
+ /* Each line contains 2 hex digits + a line feed, i.e. 3 bytes */
+ ret = kstrtou8(single_buf, 16, &next_byte);
+ if (ret < 0) {
+ cl_dbg_err(cl_hw,
+ "ret = %d, oft = %zu,"
+ "single_buf = 0x%x 0x%x 0x%x 0x%x\n",
+ ret, oft, single_buf[0], single_buf[1],
+ single_buf[2], single_buf[3]);
+ return ret;
+ }
+
+ /* Little-endian order. */
+ bin_data += next_byte << (8 * byte_num);
+ byte_num = (byte_num + 1) % 4;
+
+ /* Read 4 lines from the file, and then write. */
+ if (byte_num == 0) {
+ if (chip_reg)
+ cl_reg_write_chip(cl_hw->chip, offset, bin_data);
+ else
+ cl_reg_write_direct(cl_hw, offset, bin_data);
+ offset += 4;
+ bin_data = 0;
+ }
+
+ memset(&single_buf, 0, sizeof(single_buf));
+ oft += 3;
+ }
+
+ return 0;
+}
+
+static int load_dsp_code(struct cl_hw *cl_hw)
+{
+ struct cl_chip *chip = cl_hw->chip;
+ u32 real_size;
+ u32 page;
+ const struct firmware *fw;
+ size_t size = 0;
+ u8 *buf = NULL;
+ char path_name[CL_PATH_MAX] = {0};
+ int ret;
+
+ snprintf(path_name, sizeof(path_name), "cl8k/%s",
+ cl_hw->conf->ce_dsp_code);
+
+ cl_dbg_verbose(cl_hw, "from %s\n", cl_hw->conf->ce_dsp_code);
+
+ ret = request_firmware(&fw, path_name, chip->dev);
+
+ if (ret) {
+ cl_dbg_err(cl_hw, "Failed to get %s, with error: %x!\n",
+ path_name, ret);
+ goto out;
+ }
+
+ size = fw->size;
+ buf = (u8 *)fw->data;
+
+ for (page = 0; page < CEVA_MAX_PAGES; page++) {
+ /* Copy DSP code (one page each time) */
+ ret = cl_dsp_hex_load(cl_hw, buf,
+ CEVA_SHARED_PMEM_BASE_ADDR_FROM_HOST,
+ CEVA_SHARED_PMEM_SIZE, size);
+ if (ret != 0) {
+ cl_dbg_err(cl_hw, "Failed to load pmem page 0x%x!\n", page);
+ break;
+ }
+
+ config_dma_for_code_copy(cl_hw, page);
+ ret = dsp_busy_wait(cl_hw, CEVA_CPM_PDTC_REG);
+
+ if (ret) {
+ cl_dbg_err(cl_hw, "dsp_busy_wait failed!\n");
+ goto out;
+ }
+
+ real_size = min_t(u32, CEVA_SHARED_PMEM_SIZE * 3, size);
+ buf += real_size;
+ size -= real_size;
+ }
+
+out:
+ release_firmware(fw);
+
+ return ret;
+}
+
+static int load_dsp_data(struct cl_hw *cl_hw)
+{
+ struct cl_chip *chip = cl_hw->chip;
+ const struct firmware *fw;
+ size_t size = 0;
+ char path_name[CL_PATH_MAX] = {0};
+ int ret;
+
+ snprintf(path_name, sizeof(path_name), "cl8k/%s",
+ cl_hw->conf->ce_dsp_data);
+
+ cl_dbg_verbose(cl_hw, "from %s\n", cl_hw->conf->ce_dsp_data);
+
+ ret = request_firmware(&fw, path_name, chip->dev);
+ if (ret) {
+ cl_dbg_err(cl_hw, "Failed to get %s, with error: %x!\n",
+ path_name, ret);
+ goto out;
+ }
+
+ size = fw->size;
+
+ ret = cl_dsp_hex_load(cl_hw, fw->data, REG_MACDSP_API_BASE_ADDR,
+ CEVA_DSP_DATA_SIZE, size);
+ if (ret) {
+ cl_dbg_err(cl_hw, "Failed to load HEX file\n");
+ goto out;
+ }
+out:
+ release_firmware(fw);
+
+ return ret;
+}
+
+static int load_dsp_external_data(struct cl_hw *cl_hw)
+{
+ /*
+ * Shared XMEM is not accessible by host.
+ * Copy the XMEM section to DRAM first and then use CEVA internal DMA to copy to
+ * SHARED XMEM.
+ */
+ struct cl_chip *chip = cl_hw->chip;
+ const struct firmware *fw;
+ size_t size = 0;
+ char path_name[CL_PATH_MAX] = {0};
+ int ret;
+
+ snprintf(path_name, sizeof(path_name), "cl8k/%s",
+ cl_hw->conf->ce_dsp_external_data);
+
+ cl_dbg_verbose(cl_hw, "from %s\n", cl_hw->conf->ce_dsp_external_data);
+
+ ret = request_firmware(&fw, path_name, chip->dev);
+ if (ret) {
+ cl_dbg_err(cl_hw, "Failed to get %s, with error: %x!\n",
+ path_name, ret);
+ goto out;
+ }
+
+ size = fw->size;
+
+ ret = cl_dsp_hex_load(cl_hw, fw->data, REG_MACDSP_API_BASE_ADDR,
+ CEVA_DSP_EXT_DATA_SIZE, size);
+
+ if (ret) {
+ cl_dbg_err(cl_hw, "Failed to load HEX file\n");
+ goto out;
+ }
+
+ config_dma_for_external_data_copy(cl_hw);
+ ret = dsp_busy_wait(cl_hw, CEVA_CPM_DDTC_REG);
+
+ if (ret) {
+ cl_dbg_err(cl_hw, "dsp_busy_wait failed!\n");
+ goto out;
+ }
+
+out:
+ release_firmware(fw);
+
+ return ret;
+}
+
+static bool cl_dsp_is_universal_file(struct cl_chip *chip)
+{
+ return (cl_chip_is_tcv0_enabled(chip) &&
+ cl_chip_is_tcv1_enabled(chip) &&
+ !strcmp(chip->cl_hw_tcv0->conf->ce_dsp_code,
+ chip->cl_hw_tcv1->conf->ce_dsp_code));
+}
+
+static int load_dsp_code_dual(struct cl_chip *chip, const char *filename)
+{
+ struct cl_hw *cl_hw_tcv0 = chip->cl_hw_tcv0;
+ struct cl_hw *cl_hw_tcv1 = chip->cl_hw_tcv1;
+ u32 real_size;
+ u32 page;
+ const struct firmware *fw;
+ size_t size = 0;
+ u8 *buf = NULL;
+ char path_name[CL_PATH_MAX] = {0};
+ int ret;
+
+ snprintf(path_name, sizeof(path_name), "cl8k/%s", filename);
+ cl_dbg_chip_verbose(chip, "from %s\n", filename);
+ ret = request_firmware(&fw, path_name, chip->dev);
+
+ if (ret) {
+ cl_dbg_chip_err(chip, "Failed to get %s, with error: %x!\n",
+ path_name, ret);
+ goto out;
+ }
+
+ size = fw->size;
+ buf = (u8 *)fw->data;
+
+ for (page = 0; page < CEVA_MAX_PAGES; page++) {
+ /* Copy DSP code (one page each time) */
+ ret = cl_dsp_hex_load(chip->cl_hw_tcv0, buf,
+ CEVA_SHARED_PMEM_BASE_ADDR_FROM_HOST,
+ CEVA_SHARED_PMEM_SIZE, size);
+ if (ret) {
+ cl_dbg_chip_err(chip, "Failed to load pmem page 0x%x!\n", page);
+ break;
+ }
+
+ config_dma_for_code_copy(cl_hw_tcv0, page);
+ ret = dsp_busy_wait(cl_hw_tcv0, CEVA_CPM_PDTC_REG);
+
+ if (ret) {
+ cl_dbg_err(cl_hw_tcv0, "dsp_busy_wait failed\n");
+ goto out;
+ }
+
+ config_dma_for_code_copy(cl_hw_tcv1, page);
+ ret = dsp_busy_wait(cl_hw_tcv1, CEVA_CPM_PDTC_REG);
+
+ if (ret) {
+ cl_dbg_err(cl_hw_tcv1, "dsp_busy_wait failed\n");
+ goto out;
+ }
+
+ real_size = min_t(u32, CEVA_SHARED_PMEM_SIZE * 3, size);
+ buf += real_size;
+ size -= real_size;
+ }
+
+out:
+ release_firmware(fw);
+
+ return ret;
+}
+
+static int load_dsp_external_data_dual(struct cl_chip *chip, const char *filename)
+{
+ /*
+ * Shared XMEM is not accessible by host.
+ * Copy the XMEM section to DRAM first and then use CEVA internal DMA to copy to
+ * SHARED XMEM.
+ */
+ struct cl_hw *cl_hw_tcv0 = chip->cl_hw_tcv0;
+ struct cl_hw *cl_hw_tcv1 = chip->cl_hw_tcv1;
+ const struct firmware *fw;
+ size_t size = 0;
+ char path_name[CL_PATH_MAX] = {0};
+ int ret;
+
+ snprintf(path_name, sizeof(path_name), "cl8k/%s", filename);
+ cl_dbg_chip_verbose(chip, "from %s\n", filename);
+ ret = request_firmware(&fw, path_name, chip->dev);
+
+ if (ret) {
+ cl_dbg_chip_err(chip, "Failed to get %s, with error: %x!\n",
+ path_name, ret);
+ goto out;
+ }
+
+ size = fw->size;
+
+ /* TCV0 */
+ ret = cl_dsp_hex_load(cl_hw_tcv0, fw->data, REG_MACDSP_API_BASE_ADDR,
+ CEVA_DSP_EXT_DATA_SIZE, size);
+
+ if (ret) {
+ cl_dbg_err(cl_hw_tcv0, "Failed to load HEX file\n");
+ goto out;
+ }
+
+ config_dma_for_external_data_copy(cl_hw_tcv0);
+ ret = dsp_busy_wait(cl_hw_tcv0, CEVA_CPM_DDTC_REG);
+
+ if (ret) {
+ cl_dbg_err(cl_hw_tcv0, "dsp_busy_wait failed!\n");
+ goto out;
+ }
+
+ /* TCV1 */
+ ret = cl_dsp_hex_load(cl_hw_tcv1, fw->data, REG_MACDSP_API_BASE_ADDR,
+ CEVA_DSP_EXT_DATA_SIZE, size);
+
+ if (ret) {
+ cl_dbg_err(cl_hw_tcv1, "Failed to load HEX file\n");
+ goto out;
+ }
+
+ config_dma_for_external_data_copy(cl_hw_tcv1);
+ ret = dsp_busy_wait(cl_hw_tcv1, CEVA_CPM_DDTC_REG);
+
+ if (ret) {
+ cl_dbg_err(cl_hw_tcv1, "dsp_busy_wait failed!\n");
+ goto out;
+ }
+
+out:
+ release_firmware(fw);
+
+ return ret;
+}
+
+static int load_dsp_data_dual(struct cl_chip *chip, const char *filename)
+{
+ struct cl_hw *cl_hw_tcv0 = chip->cl_hw_tcv0;
+ struct cl_hw *cl_hw_tcv1 = chip->cl_hw_tcv1;
+ const struct firmware *fw;
+ size_t size = 0;
+ char path_name[CL_PATH_MAX] = {0};
+ int ret;
+
+ snprintf(path_name, sizeof(path_name), "cl8k/%s", filename);
+ cl_dbg_chip_verbose(chip, "from %s\n", filename);
+ ret = request_firmware(&fw, path_name, chip->dev);
+
+ if (ret) {
+ cl_dbg_chip_err(chip, "Failed to get %s, with error: %x!\n",
+ path_name, ret);
+ goto out;
+ }
+
+ size = fw->size;
+
+ ret = cl_dsp_hex_load(cl_hw_tcv0, fw->data,
+ REG_MACDSP_API_BASE_ADDR,
+ CEVA_DSP_DATA_SIZE, size);
+
+ if (ret != 0) {
+ cl_dbg_err(cl_hw_tcv0, "Failed to load HEX file\n");
+ goto out;
+ }
+
+ ret = cl_dsp_hex_load(cl_hw_tcv1, fw->data,
+ REG_MACDSP_API_BASE_ADDR,
+ CEVA_DSP_DATA_SIZE, size);
+
+ if (ret != 0) {
+ cl_dbg_err(cl_hw_tcv1, "Failed to load HEX file\n");
+ goto out;
+ }
+
+out:
+ release_firmware(fw);
+
+ return ret;
+}
+
+static void print_ceva_core_info(struct cl_hw *cl_hw)
+{
+ cl_dbg_trace(cl_hw, "CEVA_CORE_VERSION_ADDR=0x%X.\n",
+ cl_reg_read(cl_hw, CEVA_CORE_VERSION_ADDR));
+ cl_dbg_trace(cl_hw, "CEVA_CORE_ID_ADDR=0x%X.\n",
+ cl_reg_read(cl_hw, CEVA_CORE_ID_ADDR));
+}
+
+static int cl_dsp_load_dual(struct cl_chip *chip)
+{
+ int ret = 0;
+ struct cl_hw *cl_hw_tcv0 = chip->cl_hw_tcv0;
+ struct cl_hw *cl_hw_tcv1 = chip->cl_hw_tcv1;
+ struct cl_tcv_conf *tcv0_conf = cl_hw_tcv0->conf;
+
+ modem_gcu_ceva_ctrl_external_wait_setf(cl_hw_tcv0, 0x1);
+ modem_gcu_ceva_ctrl_external_wait_setf(cl_hw_tcv1, 0x1);
+
+ print_ceva_core_info(cl_hw_tcv0);
+ print_ceva_core_info(cl_hw_tcv1);
+
+ ret = load_dsp_code_dual(chip, tcv0_conf->ce_dsp_code);
+ if (ret != 0) {
+ cl_dbg_chip_err(chip,
+ "Failed to load DSP code. Error code %d.\n",
+ ret);
+ return ret;
+ }
+
+ ret = load_dsp_external_data_dual(chip, tcv0_conf->ce_dsp_external_data);
+ if (ret != 0) {
+ cl_dbg_chip_err(chip,
+ "Failed to load DSP external data. Error code %d.\n",
+ ret);
+ return ret;
+ }
+
+ ret = load_dsp_data_dual(chip, tcv0_conf->ce_dsp_data);
+ if (ret != 0) {
+ cl_dbg_chip_err(chip,
+ "Failed to load DSP data. Error code %d.\n",
+ ret);
+ return ret;
+ }
+
+ macdsp_api_config_space_set(cl_hw_tcv0, 0);
+ /* Release DSP wait. */
+ cl_dsp_boot(cl_hw_tcv0);
+
+ macdsp_api_config_space_set(cl_hw_tcv1, 0);
+ /* Release DSP wait. */
+ cl_dsp_boot(cl_hw_tcv1);
+
+ return ret;
+}
+
+static int _cl_dsp_load(struct cl_hw *cl_hw)
+{
+ int ret = 0;
+
+ modem_gcu_ceva_ctrl_external_wait_setf(cl_hw, 0x1);
+ print_ceva_core_info(cl_hw);
+
+ ret = load_dsp_code(cl_hw);
+ if (ret) {
+ cl_dbg_err(cl_hw, "Failed to load DSP code %d\n", ret);
+ return ret;
+ }
+
+ ret = load_dsp_external_data(cl_hw);
+ if (ret) {
+ cl_dbg_err(cl_hw, "Failed to load DSP external data %d\n", ret);
+ return ret;
+ }
+
+ ret = load_dsp_data(cl_hw);
+ if (ret) {
+ cl_dbg_err(cl_hw, "Failed to load DSP data %d\n", ret);
+ return ret;
+ }
+
+ macdsp_api_config_space_set(cl_hw, 0);
+ /* Release DSP wait */
+ cl_dsp_boot(cl_hw);
+
+ return ret;
+}
+
+int cl_dsp_load_regular(struct cl_chip *chip)
+{
+ int ret = 0;
+
+ if (cl_dsp_is_universal_file(chip))
+ return cl_dsp_load_dual(chip);
+
+ if (cl_chip_is_tcv0_enabled(chip)) {
+ ret = _cl_dsp_load(chip->cl_hw_tcv0);
+ if (ret)
+ return ret;
+ }
+
+ if (cl_chip_is_tcv1_enabled(chip)) {
+ ret = _cl_dsp_load(chip->cl_hw_tcv1);
+ if (ret)
+ return ret;
+ }
+
+ return ret;
+}
+
+int cl_dsp_load_recovery(struct cl_hw *cl_hw)
+{
+ int ret = 0;
+
+ modem_gcu_ceva_ctrl_external_wait_setf(cl_hw, 0x1);
+
+ ret = load_dsp_external_data(cl_hw);
+ if (ret) {
+ cl_dbg_err(cl_hw, "Failed to load DSP external data %d\n", ret);
+ return ret;
+ }
+
+ ret = load_dsp_data(cl_hw);
+ if (ret) {
+ cl_dbg_err(cl_hw, "Failed to load DSP data %d\n", ret);
+ return ret;
+ }
+
+ macdsp_api_config_space_set(cl_hw, 0);
+ /* Release DSP wait. */
+ cl_dsp_boot(cl_hw);
+
+ return ret;
+}
--
2.30.0

________________________________
The information transmitted is intended only for the person or entity to which it is addressed and may contain confidential and/or privileged material. Any retransmission, dissemination, copying or other use of, or taking of any action in reliance upon this information is prohibited. If you received this in error, please contact the sender and delete the material from any computer. Nothing contained herein shall be deemed as a representation, warranty or a commitment by Celeno. No warranties are expressed or implied, including, but not limited to, any implied warranties of non-infringement, merchantability and fitness for a particular purpose.
________________________________

2021-06-17 16:26:29

by viktor.barna

[permalink] [raw]
Subject: [RFC v1 059/256] cl8k: add dfs/dfs.c

From: Viktor Barna <[email protected]>

(Part of the split. Please, take a look at the cover letter for more
details).

Signed-off-by: Viktor Barna <[email protected]>
---
drivers/net/wireless/celeno/cl8k/dfs/dfs.c | 977 +++++++++++++++++++++
1 file changed, 977 insertions(+)
create mode 100644 drivers/net/wireless/celeno/cl8k/dfs/dfs.c

diff --git a/drivers/net/wireless/celeno/cl8k/dfs/dfs.c b/drivers/net/wireless/celeno/cl8k/dfs/dfs.c
new file mode 100644
index 000000000000..b2717a8be26a
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/dfs/dfs.c
@@ -0,0 +1,977 @@
+// SPDX-License-Identifier: MIT
+/* Copyright(c) 2019-2021, Celeno Communications Ltd. */
+
+#include "dfs/dfs.h"
+#include "dfs/dfs_db.h"
+#include "dfs/radar.h"
+#include "chip.h"
+#include "channel.h"
+#include "chan_info.h"
+#include "env_det.h"
+#include "debug.h"
+#include "utils/timer.h"
+#include "tx/tx.h"
+#include "temperature.h"
+#include "utils/math.h"
+#include "calib.h"
+#include "traffic.h"
+#include "utils/utils.h"
+#include "reg/reg_riu.h"
+#include "reg/reg_mac_hw.h"
+#include "band.h"
+#include "chandef.h"
+#include "utils/string.h"
+#include "utils/file.h"
+#include "config.h"
+
+#define dfs_pr(cl_hw, level, ...) \
+ do { \
+ if ((level) <= (cl_hw)->dfs_db.dbg_lvl) \
+ pr_debug(__VA_ARGS__); \
+ } while (0)
+
+#define dfs_pr_verbose(cl_hw, ...) dfs_pr((cl_hw), DBG_LVL_VERBOSE, ##__VA_ARGS__)
+#define dfs_pr_err(cl_hw, ...) dfs_pr((cl_hw), DBG_LVL_ERROR, ##__VA_ARGS__)
+#define dfs_pr_warn(cl_hw, ...) dfs_pr((cl_hw), DBG_LVL_WARNING, ##__VA_ARGS__)
+#define dfs_pr_trace(cl_hw, ...) dfs_pr((cl_hw), DBG_LVL_TRACE, ##__VA_ARGS__)
+#define dfs_pr_info(cl_hw, ...) dfs_pr((cl_hw), DBG_LVL_INFO, ##__VA_ARGS__)
+
+#define COUNTRY_CODE_LEN 2
+
+/*
+ * ID Min Max Tol Min Max Tol Tol MIN PPB Trig Type
+ * Width Width Width PRI PRI PRI FREQ Burst Count
+ */
+
+/* ETSI Radar Types v1.8.2 */
+static struct cl_radar_type radar_type_etsi[] = {
+
+ {0, 1, 1, 1, 1428, 1428, 1, 1, 1, 18, 10, RADAR_WAVEFORM_SHORT},
+ {1, 1, 5, 1, 1000, 5000, 1, 1, 1, 10, 5, RADAR_WAVEFORM_SHORT},
+ {2, 1, 15, 1, 625, 5000, 1, 1, 1, 15, 8, RADAR_WAVEFORM_SHORT},
+ {3, 1, 15, 1, 250, 435, 1, 1, 1, 25, 10, RADAR_WAVEFORM_SHORT},
+ {4, 10, 30, 1, 250, 500, 1, 1, 1, 20, 10, RADAR_WAVEFORM_SHORT},
+ {5, 1, 5, 1, 2500, 3334, 1, 1, 2, 10, 5, RADAR_WAVEFORM_STAGGERED},
+ {6, 1, 5, 1, 833, 2500, 1, 1, 2, 15, 8, RADAR_WAVEFORM_STAGGERED},
+};
+
+/* FCC Radar Types 8/14 */
+static struct cl_radar_type radar_type_fcc[] = {
+ {0, 1, 1, 0, 1428, 1428, 1, 1, 1, 18, 10, RADAR_WAVEFORM_SHORT},
+ {1, 1, 5, 3, 518, 3066, 3, 1, 1, 18, 10, RADAR_WAVEFORM_SHORT},
+ {2, 1, 5, 3, 150, 230, 3, 1, 1, 23, 10, RADAR_WAVEFORM_SHORT},
+ {3, 3, 10, 3, 200, 500, 3, 1, 1, 16, 6, RADAR_WAVEFORM_SHORT},
+ {4, 6, 20, 3, 200, 500, 3, 1, 1, 12, 6, RADAR_WAVEFORM_SHORT},
+ {5, 50, 100, 50, 1000, 2000, 1, 1, 2, 10, 5, RADAR_WAVEFORM_LONG},
+ {6, 1, 1, 0, 333, 333, 1, 1, 2, 30, 10, RADAR_WAVEFORM_LONG},
+};
+
+static void cl_dfs_fw_en(struct cl_hw *cl_hw, u8 dfs_en)
+{
+ struct cl_dfs_db *dfs_db = &cl_hw->dfs_db;
+ struct cl_tcv_conf *conf = cl_hw->conf;
+
+ cl_msg_tx_set_dfs(cl_hw, dfs_en, dfs_db->dfs_standard,
+ conf->ci_dfs_initial_gain, conf->ci_dfs_agc_cd_th);
+}
+
+static int cl_dfs_print_tbl(struct cl_hw *cl_hw)
+{
+ int i;
+ struct cl_dfs_db *dfs_db = &cl_hw->dfs_db;
+ char *buf = NULL;
+ ssize_t buf_size;
+ int err = 0;
+ int len = 0;
+
+ cl_snprintf(&buf, &len, &buf_size,
+ "-------------------------------------------------------------------------"
+ "---------------\n"
+ "| | Min | Max | Tol | Min | Max | Tol | Tol | Min | |"
+ " Trig | |\n"
+ "| ID | Width | Width | Width | PRI | PRI | PRI | FREQ | Burst | PPB |"
+ " Count | Type |\n"
+ "-------------------------------------------------------------------------"
+ "---------------\n");
+
+ for (i = 0; i < dfs_db->radar_type_cnt; i++) {
+ cl_snprintf(&buf, &len, &buf_size,
+ "| %2u | %5d | %5d | %5d | %5d | %5d | %3d | %4d | %5u |"
+ " %3u | %5u | %4d |\n",
+ dfs_db->radar_type[i].id,
+ dfs_db->radar_type[i].min_width,
+ dfs_db->radar_type[i].max_width,
+ dfs_db->radar_type[i].tol_width,
+ dfs_db->radar_type[i].min_pri,
+ dfs_db->radar_type[i].max_pri,
+ dfs_db->radar_type[i].tol_pri,
+ dfs_db->radar_type[i].tol_freq,
+ dfs_db->radar_type[i].min_burst,
+ dfs_db->radar_type[i].ppb,
+ dfs_db->radar_type[i].trig_count,
+ dfs_db->radar_type[i].waveform);
+ cl_snprintf(&buf, &len, &buf_size,
+ "-----------------------------------------------------------------"
+ "-----------------------\n");
+ }
+
+ err = cl_vendor_reply(cl_hw, buf, len);
+ kfree(buf);
+
+ return err;
+}
+
+static bool cl_dfs_create_detection_buffer(struct cl_hw *cl_hw, struct cl_dfs_db *dfs_db,
+ struct cl_dfs_pulse *pulse_buffer, u8 *samples_cnt,
+ unsigned long time)
+{
+ u8 i;
+ u8 pulse_idx;
+ /* Init First index to last */
+ u8 first_pulse_idx = (dfs_db->buf_idx - 1 + CL_DFS_PULSE_BUF_SIZE) & CL_DFS_PULSE_BUF_MASK;
+
+ /* Find Start Pulse indexes */
+ for (i = 0; i < CL_DFS_PULSE_BUF_SIZE; i++) {
+ pulse_idx = (i + dfs_db->buf_idx) & CL_DFS_PULSE_BUF_MASK;
+
+ if ((time - dfs_db->dfs_pulse[pulse_idx].time) < dfs_db->search_window) {
+ first_pulse_idx = pulse_idx;
+ break;
+ }
+ }
+
+ dfs_pr_info(cl_hw, "DFS: First pulse idx = %u, Last pulse idx = %u\n",
+ first_pulse_idx, dfs_db->buf_idx - 1);
+
+ if (dfs_db->buf_idx - 1 >= first_pulse_idx)
+ if ((dfs_db->buf_idx - first_pulse_idx - 1) < (dfs_db->min_pulse_eeq - 1)) {
+ /* Return if buffer don't hold enough valid samples */
+ dfs_pr_warn(cl_hw, "DFS: Not enough pulses in buffer\n");
+
+ return false;
+ }
+
+ /* Copy the processed samples to local Buf to avoid index castings */
+ for (i = 0; pulse_idx != ((dfs_db->buf_idx - 1 + CL_DFS_PULSE_BUF_SIZE)
+ & CL_DFS_PULSE_BUF_MASK); i++) {
+ pulse_idx = (i + first_pulse_idx) & CL_DFS_PULSE_BUF_MASK;
+ memcpy(&pulse_buffer[i], &dfs_db->dfs_pulse[pulse_idx], sizeof(pulse_buffer[i]));
+ }
+ *samples_cnt = i + 1;
+
+ return true;
+}
+
+static void cl_dfs_add_pulses_to_global_buffer(struct cl_hw *cl_hw, struct cl_dfs_db *dfs_db,
+ struct cl_radar_pulse *pulse, u8 pulse_cnt,
+ unsigned long time)
+{
+ int i;
+
+ for (i = 0; i < pulse_cnt; i++)
+ dfs_pr_info(cl_hw, "Pulse=%d, Width=%u, PRI=%u, FREQ=%d, Time=%lu, FOM=%x\n",
+ i, pulse[i].len, pulse[i].rep, pulse[i].freq, time, pulse[i].fom);
+
+ /* Maintain cyclic pulse buffer */
+ for (i = 0; i < pulse_cnt; i++) {
+ dfs_db->dfs_pulse[dfs_db->buf_idx].freq = pulse[i].freq;
+ dfs_db->dfs_pulse[dfs_db->buf_idx].width = pulse[i].len;
+ dfs_db->dfs_pulse[dfs_db->buf_idx].pri = pulse[i].rep;
+ dfs_db->dfs_pulse[dfs_db->buf_idx].occ = 0; /* occ temp disabled. */
+ dfs_db->dfs_pulse[dfs_db->buf_idx].time = time;
+
+ dfs_db->buf_idx++;
+ dfs_db->buf_idx &= CL_DFS_PULSE_BUF_MASK;
+ }
+}
+
+static bool cl_dfs_buf_maintain(struct cl_hw *cl_hw, struct cl_radar_pulse *pulse,
+ struct cl_dfs_pulse *pulse_buffer, u8 pulse_cnt,
+ unsigned long time, u8 *samples_cnt, struct cl_dfs_db *dfs_db)
+{
+ int i;
+
+ cl_dfs_add_pulses_to_global_buffer(cl_hw, dfs_db, pulse, pulse_cnt, time);
+ if (!cl_dfs_create_detection_buffer(cl_hw, dfs_db, pulse_buffer, samples_cnt, time))
+ return false;
+
+ for (i = 0; i < *samples_cnt; i++)
+ dfs_pr_info(cl_hw, "DFS: pulse[%d]: width=%u, pri=%u, freq=%d\n",
+ i, pulse_buffer[i].width, pulse_buffer[i].pri, pulse_buffer[i].freq);
+
+ return true;
+}
+
+static inline bool cl_dfs_pulse_match(s32 pulse_val, s32 spec_min_val,
+ s32 spec_max_val, s32 spec_tol)
+{
+ return ((pulse_val >= (spec_min_val - spec_tol)) &&
+ (pulse_val <= (spec_max_val + spec_tol)));
+}
+
+static u8 cl_dfs_is_stag_pulse(struct cl_hw *cl_hw, struct cl_dfs_db *dfs_db,
+ struct cl_dfs_pulse *pulse)
+{
+ int i;
+ struct cl_radar_type *radar_type;
+
+ for (i = 0; i < dfs_db->radar_type_cnt; i++) {
+ radar_type = &dfs_db->radar_type[i];
+
+ if (radar_type->waveform != RADAR_WAVEFORM_STAGGERED)
+ continue;
+
+ if (cl_dfs_pulse_match((s32)pulse->width, radar_type->min_width,
+ radar_type->max_width, radar_type->tol_width) &&
+ cl_dfs_pulse_match((s32)pulse->pri, radar_type->min_pri,
+ radar_type->max_pri, radar_type->tol_pri)) {
+ /* Search for the second burst */
+ if (abs(pulse[0].pri - pulse[2].pri) <= dfs_db->radar_type[i].tol_pri &&
+ abs(pulse[1].pri - pulse[3].pri) <= radar_type->tol_pri &&
+ abs(pulse[0].pri - pulse[1].pri) > radar_type->tol_pri &&
+ abs(pulse[2].pri - pulse[3].pri) > radar_type->tol_pri) {
+ dfs_pr_info(cl_hw, "DFS: Found match type %d\n", i);
+ return (i + 1);
+ } else if (abs(pulse[0].pri - pulse[3].pri) <= radar_type->tol_pri &&
+ abs(pulse[1].pri - pulse[4].pri) <= radar_type->tol_pri &&
+ abs(pulse[0].pri - pulse[1].pri) > radar_type->tol_pri &&
+ abs(pulse[3].pri - pulse[4].pri) > radar_type->tol_pri) {
+ dfs_pr_info(cl_hw, "DFS: Found match radar %d\n", i);
+ return (i + 1);
+ }
+ }
+ }
+
+ return 0;
+}
+
+static u8 cl_dfs_is_non_stag_pulse(struct cl_hw *cl_hw, struct cl_dfs_db *dfs_db,
+ struct cl_dfs_pulse *pulse)
+{
+ int i;
+ struct cl_radar_type *radar_type;
+
+ for (i = 0; i < dfs_db->radar_type_cnt; i++) {
+ radar_type = &dfs_db->radar_type[i];
+
+ if (radar_type->waveform == RADAR_WAVEFORM_STAGGERED)
+ continue;
+
+ if (cl_dfs_pulse_match((s32)pulse->width, radar_type->min_width,
+ radar_type->max_width, radar_type->tol_width) &&
+ cl_dfs_pulse_match((s32)pulse->pri, radar_type->min_pri,
+ radar_type->max_pri, radar_type->tol_pri)) {
+ dfs_pr_info(cl_hw, "DFS: Found match type %d\n", i);
+ return (i + 1);
+ }
+ }
+
+ dfs_pr_warn(cl_hw, "DFS: Match not found\n");
+
+ return 0;
+}
+
+static u8 cl_dfs_get_pulse_type(struct cl_hw *cl_hw, struct cl_dfs_pulse *pulse,
+ bool stag_candidate)
+{
+ struct cl_dfs_db *dfs_db = &cl_hw->dfs_db;
+
+ if (stag_candidate) {
+ u8 pulse_type = cl_dfs_is_stag_pulse(cl_hw, dfs_db, pulse);
+
+ if (pulse_type)
+ return pulse_type;
+ }
+
+ return cl_dfs_is_non_stag_pulse(cl_hw, dfs_db, pulse);
+}
+
+static bool cl_dfs_compare_cand(struct cl_hw *cl_hw, struct cl_dfs_db *dfs_db, u8 pulse_type,
+ struct cl_dfs_pulse radar_cand, u8 *match, int idx,
+ u8 *occ_ch_cand)
+{
+ int i;
+
+ if (!(abs(dfs_db->pulse_buffer[idx].width - radar_cand.width) <=
+ dfs_db->radar_type[pulse_type].tol_width))
+ goto end;
+
+ if (!(abs(dfs_db->pulse_buffer[idx].freq - radar_cand.freq) <=
+ dfs_db->radar_type[pulse_type].tol_freq))
+ goto end;
+
+ for (i = 1; i < CL_DFS_CONCEAL_CNT; i++)
+ if (abs(dfs_db->pulse_buffer[idx].pri - i * radar_cand.pri) <=
+ dfs_db->radar_type[pulse_type].tol_pri)
+ break;
+
+ if (i == CL_DFS_CONCEAL_CNT)
+ goto end;
+
+ (*match)++;
+ (*occ_ch_cand) += dfs_db->pulse_buffer[i].occ;
+
+end:
+ dfs_pr_info(cl_hw, "DFS: compared pulse - width=%u, pri=%u, freq=%u match: %u "
+ "trig cnt: %u\n",
+ dfs_db->pulse_buffer[idx].width, dfs_db->pulse_buffer[idx].pri,
+ dfs_db->pulse_buffer[idx].freq, *match,
+ dfs_db->radar_type[pulse_type].trig_count);
+
+ if (*match < dfs_db->radar_type[pulse_type].trig_count)
+ return false;
+
+ return true;
+}
+
+static bool cl_dfs_check_cand(struct cl_hw *cl_hw, struct cl_dfs_db *dfs_db, u8 pulse_type,
+ struct cl_dfs_pulse radar_cand, u8 samples_cnt)
+{
+ u8 occ_ch_cand = 0;
+ u8 match = 0;
+ int i;
+
+ dfs_pr_info(cl_hw, "DFS: candidate pulse - width=%u, pri=%u, freq=%u\n",
+ radar_cand.width, radar_cand.pri, radar_cand.freq);
+
+ for (i = 0; i < samples_cnt; i++) {
+ if (!cl_dfs_compare_cand(cl_hw, dfs_db, pulse_type, radar_cand, &match, i,
+ &occ_ch_cand))
+ continue;
+
+ dfs_pr_verbose(cl_hw, "DFS: Radar detected - type %u\n", pulse_type);
+ return true;
+ }
+
+ return false;
+}
+
+static bool cl_dfs_short_pulse_search(struct cl_hw *cl_hw, struct cl_radar_pulse *pulse,
+ u8 pulse_cnt, unsigned long time, struct cl_dfs_db *dfs_db)
+{
+ int i;
+ bool stag_candidate;
+ u8 samples_cnt = 0;
+ u8 pulse_type;
+
+ /* Return if not enough pulses in the buffer */
+ if (!cl_dfs_buf_maintain(cl_hw, pulse, dfs_db->pulse_buffer, pulse_cnt, time,
+ &samples_cnt, dfs_db))
+ return false;
+
+ for (i = 0; i < samples_cnt; i++) {
+ struct cl_dfs_pulse radar_cand;
+
+ stag_candidate = false;
+
+ /* Make sure there is enough samples to staggered check */
+ if (dfs_db->dfs_standard == CL_STANDARD_ETSI &&
+ (samples_cnt - i) > CL_DFS_STAGGERED_CHEC_LEN)
+ stag_candidate = true;
+
+ pulse_type = cl_dfs_get_pulse_type(cl_hw, &dfs_db->pulse_buffer[i], stag_candidate);
+
+ if (!pulse_type)
+ continue;
+
+ radar_cand.width = dfs_db->pulse_buffer[i].width;
+ radar_cand.pri = dfs_db->pulse_buffer[i].pri;
+ radar_cand.freq = dfs_db->pulse_buffer[i].freq;
+
+ if (cl_dfs_check_cand(cl_hw, dfs_db, pulse_type - 1, radar_cand, samples_cnt))
+ return true;
+ }
+
+ return false;
+}
+
+static bool cl_dfs_long_pulse_search(struct cl_hw *cl_hw, struct cl_radar_pulse *pulse,
+ u8 pulse_cnt, unsigned long time)
+{
+ u32 prev_pulse_time_diff;
+ struct cl_dfs_db *dfs_db = &cl_hw->dfs_db;
+ struct cl_tcv_conf *conf = cl_hw->conf;
+ int i;
+
+ for (i = 0; i < pulse_cnt; i++) {
+ if (pulse[i].len > CL_DFS_LONG_MIN_WIDTH) {
+ prev_pulse_time_diff = time - dfs_db->last_long_pulse_ts;
+
+ if (pulse[i].rep >= dfs_db->radar_type[5].min_pri &&
+ pulse[i].rep <= dfs_db->radar_type[5].max_pri)
+ dfs_db->long_pri_match_count += 1;
+
+ dfs_pr_info(cl_hw, "DFS: Long pulse search: width = %u, delta_time = %u\n",
+ pulse[i].len, prev_pulse_time_diff);
+
+ if (dfs_db->long_pulse_count == 0 ||
+ (prev_pulse_time_diff >= conf->ci_dfs_long_pulse_min &&
+ prev_pulse_time_diff <= conf->ci_dfs_long_pulse_max)) {
+ dfs_db->long_pulse_count += 1;
+ } else if (prev_pulse_time_diff > min(dfs_db->max_interrupt_diff,
+ conf->ci_dfs_long_pulse_min)) {
+ dfs_db->long_pulse_count = 0;
+ dfs_db->short_pulse_count = 0;
+ dfs_db->long_pri_match_count = 0;
+ }
+ dfs_db->last_long_pulse_ts = time;
+ } else if (pulse[i].len < CL_DFS_LONG_FALSE_WIDTH) {
+ dfs_db->short_pulse_count++;
+
+ if (dfs_db->short_pulse_count > CL_DFS_LONG_FALSE_IND) {
+ dfs_db->long_pulse_count = 0;
+ dfs_db->short_pulse_count = 0;
+ dfs_db->long_pri_match_count = 0;
+
+ dfs_pr_warn(cl_hw, "DFS: Restart long sequence search\n");
+ }
+ }
+ }
+
+ if (dfs_db->long_pulse_count >= dfs_db->radar_type[5].trig_count &&
+ dfs_db->long_pri_match_count >= (dfs_db->radar_type[5].trig_count - 1)) {
+ dfs_db->short_pulse_count = 0;
+ dfs_db->long_pulse_count = 0;
+ dfs_db->long_pri_match_count = 0;
+ return true;
+ } else {
+ return false;
+ }
+}
+
+static bool cl_dfs_post_detection(struct cl_hw *cl_hw)
+{
+ struct cl_dfs_db *dfs_db = &cl_hw->dfs_db;
+ struct cl_tcv_conf *conf = cl_hw->conf;
+
+ /* Make sure firmware sets the DFS registers */
+ cl_radar_flush(cl_hw);
+ cl_msg_tx_set_dfs(cl_hw, false, dfs_db->dfs_standard,
+ conf->ci_dfs_initial_gain, conf->ci_dfs_agc_cd_th);
+
+ ieee80211_radar_detected(cl_hw->hw);
+
+ return true;
+}
+
+bool cl_dfs_pulse_process(struct cl_hw *cl_hw, struct cl_radar_pulse *pulse, u8 pulse_cnt,
+ unsigned long time)
+{
+ struct cl_dfs_db *dfs_db = &cl_hw->dfs_db;
+
+ dfs_db->pulse_cnt += pulse_cnt;
+
+ if (dfs_db->dfs_standard == CL_STANDARD_FCC &&
+ cl_dfs_long_pulse_search(cl_hw, pulse, pulse_cnt, time)) {
+ dfs_pr_verbose(cl_hw, "DFS: Radar detected - long\n");
+ return cl_dfs_post_detection(cl_hw);
+ } else if (cl_dfs_short_pulse_search(cl_hw, pulse, pulse_cnt, time, dfs_db)) {
+ dfs_pr_verbose(cl_hw, "DFS: Radar detected - short\n");
+ return cl_dfs_post_detection(cl_hw);
+ }
+
+ return false;
+}
+
+static void cl_dfs_set_min_pulse(struct cl_hw *cl_hw)
+{
+ int i;
+ struct cl_dfs_db *dfs_db = &cl_hw->dfs_db;
+
+ dfs_db->min_pulse_eeq = U8_MAX;
+
+ for (i = 0; i < dfs_db->radar_type_cnt; i++) {
+ if (dfs_db->radar_type[i].trig_count < dfs_db->min_pulse_eeq)
+ dfs_db->min_pulse_eeq = dfs_db->radar_type[i].trig_count;
+ }
+ dfs_db->min_pulse_eeq = max(dfs_db->min_pulse_eeq, (u8)CL_DFS_MIN_PULSE_TRIG);
+}
+
+static void cl_dfs_set_region(struct cl_hw *cl_hw, enum cl_reg_standard std)
+{
+ struct cl_dfs_db *dfs_db = &cl_hw->dfs_db;
+
+ dfs_db->dfs_standard = std;
+
+ if (dfs_db->dfs_standard == CL_STANDARD_FCC) {
+ dfs_db->csa_cnt = CL_DFS_FCC_CSA_CNT;
+ dfs_db->radar_type = radar_type_fcc;
+ dfs_db->radar_type_cnt = sizeof(radar_type_fcc) / sizeof(struct cl_radar_type);
+ } else {
+ dfs_db->csa_cnt = CL_DFS_CE_CSA_CNT;
+ dfs_db->radar_type = radar_type_etsi;
+ dfs_db->radar_type_cnt = sizeof(radar_type_etsi) / sizeof(struct cl_radar_type);
+ }
+}
+
+static void cl_dfs_start_cac(struct cl_dfs_db *db)
+{
+ db->cac.started = true;
+}
+
+static void cl_dfs_end_cac(struct cl_dfs_db *db)
+{
+ db->cac.started = false;
+}
+
+void cl_dfs_radar_listen_start(struct cl_hw *cl_hw)
+{
+ set_bit(CL_DEV_RADAR_LISTEN, &cl_hw->drv_flags);
+
+ cl_dfs_fw_en(cl_hw, true);
+
+ dfs_pr_verbose(cl_hw, "DFS: Started radar listening\n");
+}
+
+void cl_dfs_radar_listen_end(struct cl_hw *cl_hw)
+{
+ clear_bit(CL_DEV_RADAR_LISTEN, &cl_hw->drv_flags);
+
+ cl_dfs_fw_en(cl_hw, false);
+
+ dfs_pr_verbose(cl_hw, "DFS: Ended radar listening\n");
+}
+
+void cl_dfs_force_cac_start(struct cl_hw *cl_hw)
+{
+ bool is_listening = test_bit(CL_DEV_RADAR_LISTEN, &cl_hw->drv_flags);
+
+ cl_dfs_start_cac(&cl_hw->dfs_db);
+
+ /* Reset request state upon completion */
+ cl_dfs_request_cac(cl_hw, false);
+
+ /* Disable all the TX flow - be silent */
+ cl_tx_en(cl_hw, CL_TX_EN_DFS, false);
+
+ /* If for some reason we are still not listening radar, do it */
+ if (unlikely(!is_listening && cl_hw->hw->conf.radar_enabled))
+ cl_dfs_radar_listen_start(cl_hw);
+
+ dfs_pr_verbose(cl_hw, "DFS: CAC started\n");
+}
+
+void cl_dfs_force_cac_end(struct cl_hw *cl_hw)
+{
+ bool is_listening = test_bit(CL_DEV_RADAR_LISTEN, &cl_hw->drv_flags);
+
+ /* Enable all the TX flow */
+ cl_tx_en(cl_hw, CL_TX_EN_DFS, true);
+
+ /*
+ * If for some reason we are still listening and mac80211 does not
+ * require to listen radar - disable it
+ */
+ if (unlikely(is_listening && !cl_hw->hw->conf.radar_enabled))
+ cl_dfs_radar_listen_end(cl_hw);
+
+ cl_dfs_end_cac(&cl_hw->dfs_db);
+
+ dfs_pr_verbose(cl_hw, "DFS: CAC ended\n");
+}
+
+static u16 cl_dfs_get_remain_cac_time(struct cl_hw *cl_hw)
+{
+ struct cl_vif *cl_vif = cl_vif_get_first_ap(cl_hw);
+ struct wireless_dev *wdev = cl_vif ? ieee80211_vif_to_wdev(cl_vif->vif) : NULL;
+
+ if (wdev && wdev->cac_started)
+ return (jiffies_to_msecs(jiffies - wdev->cac_start_time) / 1000U);
+
+ return 0;
+}
+
+bool __must_check cl_dfs_is_en(struct cl_hw *cl_hw)
+{
+ return cl_hw->dfs_db.en;
+}
+
+bool __must_check cl_dfs_is_in_cac(struct cl_hw *cl_hw)
+{
+ return cl_hw->dfs_db.cac.started;
+}
+
+bool __must_check cl_dfs_radar_listening(struct cl_hw *cl_hw)
+{
+ return test_bit(CL_DEV_RADAR_LISTEN, &cl_hw->drv_flags);
+}
+
+bool __must_check cl_dfs_requested_cac(struct cl_hw *cl_hw)
+{
+ return cl_hw->dfs_db.cac.requested;
+}
+
+void cl_dfs_request_cac(struct cl_hw *cl_hw, bool should_do)
+{
+ cl_hw->dfs_db.cac.requested = should_do;
+}
+
+static void cl_dfs_edit_tbl(struct cl_hw *cl_hw, u8 row, u8 line, s16 val)
+{
+ struct cl_dfs_db *dfs_db = &cl_hw->dfs_db;
+
+ if (row > dfs_db->radar_type_cnt) {
+ dfs_pr_err(cl_hw, "Invalid row number (%u) [0 - %u]\n", line,
+ dfs_db->radar_type_cnt - 1);
+ return;
+ }
+
+ if (line == 0 || line > CL_DFS_MAX_TBL_LINE) {
+ dfs_pr_err(cl_hw, "Invalid line number (%u) [1 - %u]\n", line,
+ CL_DFS_MAX_TBL_LINE - 1);
+ return;
+ }
+
+ if (line == 1)
+ dfs_db->radar_type[row].min_width = (s32)val;
+ else if (line == 2)
+ dfs_db->radar_type[row].max_width = (s32)val;
+ else if (line == 3)
+ dfs_db->radar_type[row].tol_width = (s32)val;
+ else if (line == 4)
+ dfs_db->radar_type[row].min_pri = (s32)val;
+ else if (line == 5)
+ dfs_db->radar_type[row].max_pri = (s32)val;
+ else if (line == 6)
+ dfs_db->radar_type[row].tol_pri = (s32)val;
+ else if (line == 7)
+ dfs_db->radar_type[row].tol_freq = (s32)val;
+ else if (line == 8)
+ dfs_db->radar_type[row].min_burst = (u8)val;
+ else if (line == 9)
+ dfs_db->radar_type[row].ppb = (u8)val;
+ else if (line == 10)
+ dfs_db->radar_type[row].trig_count = (u8)val;
+ else if (line == 11)
+ dfs_db->radar_type[row].waveform = (enum cl_radar_waveform)val;
+
+ /* Verify if min_pulse_eeq was changed */
+ cl_dfs_set_min_pulse(cl_hw);
+}
+
+static void cl_dfs_tbl_overwrite_set(struct cl_hw *cl_hw)
+{
+ s8 *tok = NULL, *saveptr = NULL;
+ u8 param1 = 0;
+ u8 param2 = 0;
+ s16 param3 = 0;
+ char str[64];
+
+ if (strlen(cl_hw->conf->ce_dfs_tbl_overwrite) == 0)
+ return;
+
+ snprintf(str, sizeof(str), cl_hw->conf->ce_dfs_tbl_overwrite);
+
+ tok = cl_strtok_r(str, ",", &saveptr);
+ while (tok) {
+ if (sscanf(tok, "%hhd,%hhd,%hd", &param1, &param2, &param3) == 3)
+ cl_dfs_edit_tbl(cl_hw, param1, param2, param3);
+ tok = cl_strtok_r(NULL, ",", &saveptr);
+ }
+}
+
+void cl_dfs_close(struct cl_hw *cl_hw)
+{
+ if (!cl_band_is_5g(cl_hw))
+ return;
+
+ cl_hw->dfs_db.en = false;
+}
+
+void cl_dfs_init(struct cl_hw *cl_hw)
+{
+ struct cl_dfs_db *dfs_db = &cl_hw->dfs_db;
+ struct cl_tcv_conf *conf = cl_hw->conf;
+
+ if (!cl_band_is_5g(cl_hw))
+ return;
+
+ dfs_db->en = conf->ci_ieee80211h;
+
+ /*
+ * Setting min window size to avoid the case where the second interrupt
+ * within the burst is setting the counter to 0. the max is between jiffies
+ * unit and max PRI in ms.
+ */
+ dfs_db->max_interrupt_diff = max(1000 / HZ, 2);
+ dfs_db->search_window = CL_DFS_PULSE_WINDOW;
+
+ cl_dfs_set_region(cl_hw, cl_hw->channel_info.standard);
+ cl_dfs_set_min_pulse(cl_hw);
+ cl_dfs_tbl_overwrite_set(cl_hw);
+}
+
+void cl_dfs_recovery(struct cl_hw *cl_hw)
+{
+ /* Re-enable DFS after recovery */
+ if (cl_dfs_is_in_cac(cl_hw)) {
+ cl_dfs_fw_en(cl_hw, true);
+
+ /* If recovery happened during CAC make sure to disable beacon backup */
+ cl_tx_en(cl_hw, CL_TX_EN_DFS, false);
+ }
+}
+
+static int cl_dfs_print_pulse_buffer(struct cl_hw *cl_hw, bool clear_buf)
+{
+ int i;
+ struct cl_dfs_db *dfs_db = &cl_hw->dfs_db;
+ char *buf = NULL;
+ ssize_t buf_size;
+ int err = 0;
+ int len = 0;
+
+ cl_snprintf(&buf, &len, &buf_size,
+ "DFS Pulse Count = %u\n", dfs_db->pulse_cnt);
+
+ for (i = 0; i < ARRAY_SIZE(dfs_db->dfs_pulse); i++) {
+ cl_snprintf(&buf, &len, &buf_size,
+ "Pulse Buffer: i=%d, Width=%u, PRI=%u, FREQ=%d, OCC=%u, Time=%lu\n",
+ i, dfs_db->dfs_pulse[i].width,
+ dfs_db->dfs_pulse[i].pri,
+ dfs_db->dfs_pulse[i].freq,
+ dfs_db->dfs_pulse[i].occ,
+ dfs_db->dfs_pulse[i].time);
+ }
+
+ if (clear_buf) {
+ dfs_db->pulse_cnt = 0;
+ memset(dfs_db->dfs_pulse, 0, sizeof(dfs_db->dfs_pulse));
+ }
+
+ err = cl_vendor_reply(cl_hw, buf, len);
+ kfree(buf);
+
+ return err;
+}
+
+static void cl_dfs_cli_force_detection(struct cl_hw *cl_hw, struct cl_dfs_db *dfs_db)
+{
+ dfs_pr_verbose(cl_hw, "DFS: Force Radar Detection\n");
+ cl_dfs_post_detection(cl_hw);
+}
+
+static void cl_dfs_cli_set_cac(struct cl_hw *cl_hw, bool start)
+{
+ if (start)
+ cl_dfs_force_cac_start(cl_hw);
+ else
+ cl_dfs_force_cac_end(cl_hw);
+}
+
+static int cl_dfs_cli_help(struct cl_hw *cl_hw)
+{
+ char *buf = kzalloc(PAGE_SIZE, GFP_KERNEL);
+ int err = 0;
+
+ if (!buf)
+ return -ENOMEM;
+
+ snprintf(buf, PAGE_SIZE,
+ "dfs usage:\n"
+ "-b : Print pulse buffer [(0)Read / (1)Read and clear]\n"
+ "-c : Stop/Start CAC[(0)Stop / (1)Start]\n"
+ "-d : DFS debug mode[0: Verbose 1: Error, 2: Warning, 3: Trace, 4: Info]\n"
+ "-e : Enable/Disable DFS [(0)Disable DFS / (1)Enable DFS]\n"
+ "-f : Force radar detection\n"
+ "-i : Set initial gain\n"
+ "-j : Set agc cd threshold\n"
+ "-k : return remaining cac time (in seconds)\n"
+ "-m : Set Min/Max Windows for Long radar types\n"
+ "-p : Print radar tables [0:Detection Table, 1:Channel info]\n"
+ "-q : Print jumpable channel list\n"
+ "-s : Simulate radar detection table "
+ "[width][pri][freq][time]\n"
+ "-t : Edit radar detection table [row][line][value]\n"
+ "-w : Set search window size\n");
+
+ err = cl_vendor_reply(cl_hw, buf, strlen(buf));
+ kfree(buf);
+
+ return err;
+}
+
+int cl_dfs_cli(struct cl_hw *cl_hw, struct cli_params *cli_params, u8 *ret_buf, u16 *ret_buf_len)
+{
+ s32 *params = cli_params->params;
+ u32 expected_params = 0;
+ struct cl_dfs_db *dfs_db = &cl_hw->dfs_db;
+ struct cl_tcv_conf *conf = cl_hw->conf;
+ bool print_buf = false;
+ bool dbg_lvl = false;
+ bool en = false;
+ bool force = false;
+ bool print_tbl = false;
+ bool return_remain_cac_time = false;
+ bool radar_sim = false;
+ bool edit_tbl = false;
+ bool win_set = false;
+ bool cac = false;
+ bool long_prms = false;
+ bool init_gain = false;
+ bool agc_cd_hh = false;
+
+ switch (cli_params->option) {
+ case 'b':
+ print_buf = true;
+ expected_params = 1;
+ break;
+ case 'c':
+ cac = true;
+ expected_params = 1;
+ break;
+ case 'd':
+ dbg_lvl = true;
+ expected_params = 1;
+ break;
+ case 'e':
+ en = true;
+ expected_params = 1;
+ break;
+ case 'f':
+ force = true;
+ expected_params = 0;
+ break;
+ case 'i':
+ init_gain = true;
+ expected_params = 1;
+ break;
+ case 'j':
+ agc_cd_hh = true;
+ expected_params = 1;
+ break;
+ case 'k':
+ return_remain_cac_time = true;
+ expected_params = 0;
+ break;
+ case 'm':
+ long_prms = true;
+ expected_params = 2;
+ break;
+ case 'p':
+ print_tbl = true;
+ expected_params = 1;
+ break;
+ case 's':
+ radar_sim = true;
+ expected_params = 4;
+ break;
+ case 't':
+ edit_tbl = true;
+ expected_params = 3;
+ break;
+ case 'w':
+ win_set = true;
+ expected_params = 1;
+ break;
+ case '?':
+ return cl_dfs_cli_help(cl_hw);
+ default:
+ cl_dbg_err(cl_hw, "Illegal option (%c) - try '?' for help\n", cli_params->option);
+ goto out_err;
+ }
+
+ if (expected_params != cli_params->num_params) {
+ cl_dbg_err(cl_hw, "Wrong number of arguments (expected %u) (actual %u)\n",
+ expected_params, cli_params->num_params);
+ goto out_err;
+ }
+
+ if (cac) {
+ bool start = (bool)params[0];
+
+ cl_dfs_cli_set_cac(cl_hw, start);
+ return 0;
+ }
+
+ if (print_buf)
+ return cl_dfs_print_pulse_buffer(cl_hw, (bool)params[0]);
+
+ if (dbg_lvl) {
+ s32 dbg_lvl = params[0];
+
+ if (dbg_lvl > 0 && dbg_lvl < DBG_LVL_MAX) {
+ dfs_db->dbg_lvl = dbg_lvl;
+ dfs_pr_verbose(cl_hw, "Debug level = %d\n", dbg_lvl);
+ } else {
+ dfs_pr_err(cl_hw, "Invalid debug level (%d)\n", dbg_lvl);
+ }
+
+ return 0;
+ }
+
+ if (en) {
+ dfs_db->en = (bool)(params[0]);
+ dfs_pr_verbose(cl_hw, "DFS = %s\n", dfs_db->en ? "Enabled" : "Disabled");
+ cl_dfs_fw_en(cl_hw, dfs_db->en);
+ return 0;
+ }
+
+ if (force) {
+ cl_dfs_cli_force_detection(cl_hw, dfs_db);
+ return 0;
+ }
+
+ if (print_tbl) {
+ u8 table = (u8)params[0];
+
+ if (table == 0)
+ return cl_dfs_print_tbl(cl_hw);
+ return 0;
+ }
+
+ if (return_remain_cac_time) {
+ u16 cac_time = cl_dfs_get_remain_cac_time(cl_hw);
+
+ snprintf(ret_buf, PAGE_SIZE, "%u", cac_time);
+ *ret_buf_len = strlen(ret_buf);
+ return 1;
+ }
+
+ if (radar_sim) {
+ struct cl_radar_pulse pulse[CL_DFS_MAX_PULSE];
+ unsigned long time;
+
+ pulse[0].len = (u32)params[0];
+ pulse[0].rep = (u32)params[1];
+ pulse[0].freq = (s32)params[2];
+ time = (unsigned long)params[3];
+ cl_dfs_pulse_process(cl_hw, pulse, 1, time);
+ return 0;
+ }
+
+ if (edit_tbl) {
+ cl_dfs_edit_tbl(cl_hw, (u8)params[0], (u8)params[1], (s16)params[2]);
+ return 0;
+ }
+
+ if (win_set) {
+ dfs_db->search_window = (u16)params[0];
+ dfs_pr_verbose(cl_hw, "Search window size = %u\n", dfs_db->search_window);
+ return 0;
+ }
+
+ if (long_prms) {
+ conf->ci_dfs_long_pulse_min = (u16)params[0];
+ conf->ci_dfs_long_pulse_max = (u16)params[1];
+ dfs_pr_verbose(cl_hw, "Long pulse min = %u\n", conf->ci_dfs_long_pulse_min);
+ dfs_pr_verbose(cl_hw, "Long pulse max = %u\n", conf->ci_dfs_long_pulse_max);
+ return 0;
+ }
+
+ if (init_gain) {
+ conf->ci_dfs_initial_gain = (u8)params[0];
+ dfs_pr_verbose(cl_hw, "Initial gain = %u\n", conf->ci_dfs_initial_gain);
+ return 0;
+ }
+
+ if (agc_cd_hh) {
+ conf->ci_dfs_agc_cd_th = (u8)params[0];
+ dfs_pr_verbose(cl_hw, "AGC CD threshold = %u\n", conf->ci_dfs_agc_cd_th);
+ return 0;
+ }
+
+out_err:
+ return -EIO;
+}
+
--
2.30.0

________________________________
The information transmitted is intended only for the person or entity to which it is addressed and may contain confidential and/or privileged material. Any retransmission, dissemination, copying or other use of, or taking of any action in reliance upon this information is prohibited. If you received this in error, please contact the sender and delete the material from any computer. Nothing contained herein shall be deemed as a representation, warranty or a commitment by Celeno. No warranties are expressed or implied, including, but not limited to, any implied warranties of non-infringement, merchantability and fitness for a particular purpose.
________________________________

2021-06-17 16:26:34

by viktor.barna

[permalink] [raw]
Subject: [RFC v1 082/256] cl8k: add ext/vlan_dscp.h

From: Viktor Barna <[email protected]>

(Part of the split. Please, take a look at the cover letter for more
details).

Signed-off-by: Viktor Barna <[email protected]>
---
.../net/wireless/celeno/cl8k/ext/vlan_dscp.h | 37 +++++++++++++++++++
1 file changed, 37 insertions(+)
create mode 100644 drivers/net/wireless/celeno/cl8k/ext/vlan_dscp.h

diff --git a/drivers/net/wireless/celeno/cl8k/ext/vlan_dscp.h b/drivers/net/wireless/celeno/cl8k/ext/vlan_dscp.h
new file mode 100644
index 000000000000..d483aad2e724
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/ext/vlan_dscp.h
@@ -0,0 +1,37 @@
+/* SPDX-License-Identifier: MIT */
+/* Copyright(c) 2019-2021, Celeno Communications Ltd. */
+
+#ifndef CL_VLAN_DSCP_H
+#define CL_VLAN_DSCP_H
+
+#include <linux/ip.h>
+
+/* Length of packet field */
+#define LENGTH_VLAN_HDR 4
+
+/* Some VLAN parameters */
+#define ETH_VLAN 0x8100
+#define VID_MASK 0x0FFF
+#define PBIT_OFFSET 13
+
+/* Version field value of IP header */
+#define IP_V_IPV4 0x40
+#define IP_V_IPV6 0x60
+
+#define CL_UP_BY_L3 3
+#define CL_UP_BY_L2 2
+
+struct cl_hw;
+struct cl_vif;
+
+void cl_vlan_dscp_init(struct cl_hw *cl_hw);
+bool cl_vlan_dscp_is_enabled(struct cl_hw *cl_hw,
+ struct cl_vif *cl_vif);
+u8 cl_vlan_dscp_check_ether_type(struct cl_hw *cl_hw,
+ struct sk_buff *skb,
+ u8 ap_idx);
+int cl_vlan_dscp_cli(struct cl_hw *cl_hw,
+ struct cl_vif *cl_vif,
+ char *data);
+
+#endif /* CL_VLAN_DSCP_H */
--
2.30.0

________________________________
The information transmitted is intended only for the person or entity to which it is addressed and may contain confidential and/or privileged material. Any retransmission, dissemination, copying or other use of, or taking of any action in reliance upon this information is prohibited. If you received this in error, please contact the sender and delete the material from any computer. Nothing contained herein shall be deemed as a representation, warranty or a commitment by Celeno. No warranties are expressed or implied, including, but not limited to, any implied warranties of non-infringement, merchantability and fitness for a particular purpose.
________________________________

2021-06-17 16:26:33

by viktor.barna

[permalink] [raw]
Subject: [RFC v1 092/256] cl8k: add fw/msg_cfm.c

From: Viktor Barna <[email protected]>

(Part of the split. Please, take a look at the cover letter for more
details).

Signed-off-by: Viktor Barna <[email protected]>
---
drivers/net/wireless/celeno/cl8k/fw/msg_cfm.c | 316 ++++++++++++++++++
1 file changed, 316 insertions(+)
create mode 100644 drivers/net/wireless/celeno/cl8k/fw/msg_cfm.c

diff --git a/drivers/net/wireless/celeno/cl8k/fw/msg_cfm.c b/drivers/net/wireless/celeno/cl8k/fw/msg_cfm.c
new file mode 100644
index 000000000000..a63751d0804e
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/fw/msg_cfm.c
@@ -0,0 +1,316 @@
+// SPDX-License-Identifier: MIT
+/* Copyright(c) 2019-2021, Celeno Communications Ltd. */
+
+#include "fw/msg_cfm.h"
+#include "fw/msg_rx.h"
+#include "recovery.h"
+#include "reg/reg_ipc.h"
+#include "chip.h"
+#include "hw_assert.h"
+#include "config.h"
+#include "coredump.h"
+
+static void cl_check_exception(struct cl_hw *cl_hw)
+{
+ /* Check if Tensilica exception occurred */
+ int i;
+ struct cl_ipc_exception_struct *data =
+ (struct cl_ipc_exception_struct *)cl_hw->ipc_env->shared;
+
+ if (data->pattern != IPC_EXCEPTION_PATTERN)
+ return;
+
+ cl_dbg_err(cl_hw, "######################### firmware tensilica exception:\n");
+ cl_dbg_err(cl_hw, "................................. type: ");
+
+ switch (data->type) {
+ case 0:
+ cl_dbg_err(cl_hw, "EXCEPTION_ILLEGALINSTRUCTION\n");
+ break;
+ case 2:
+ cl_dbg_err(cl_hw, "EXCEPTION_INSTRUCTIONFETCHERROR\n");
+ break;
+ case 3:
+ cl_dbg_err(cl_hw, "EXCEPTION_LOADSTOREERROR\n");
+ break;
+ case 6:
+ cl_dbg_err(cl_hw, "EXCEPTION_INTEGERDIVIDEBYZERO\n");
+ break;
+ case 7:
+ cl_dbg_err(cl_hw, "EXCEPTION_SPECULATION\n");
+ break;
+ case 8:
+ cl_dbg_err(cl_hw, "EXCEPTION_PRIVILEGED\n");
+ break;
+ case 9:
+ cl_dbg_err(cl_hw, "EXCEPTION_UNALIGNED\n");
+ break;
+ case 16:
+ cl_dbg_err(cl_hw, "EXCEPTION_INSTTLBMISS\n");
+ break;
+ case 17:
+ cl_dbg_err(cl_hw, "EXCEPTION_INSTTLBMULTIHIT\n");
+ break;
+ case 18:
+ cl_dbg_err(cl_hw, "EXCEPTION_INSTFETCHPRIVILEGE\n");
+ break;
+ case 20:
+ cl_dbg_err(cl_hw, "EXCEPTION_INSTFETCHPROHIBITED\n");
+ break;
+ case 24:
+ cl_dbg_err(cl_hw, "EXCEPTION_LOADSTORETLBMISS\n");
+ break;
+ case 25:
+ cl_dbg_err(cl_hw, "EXCEPTION_LOADSTORETLBMULTIHIT\n");
+ break;
+ case 26:
+ cl_dbg_err(cl_hw, "EXCEPTION_LOADSTOREPRIVILEGE\n");
+ break;
+ case 28:
+ cl_dbg_err(cl_hw, "EXCEPTION_LOADPROHIBITED\n");
+ break;
+ default:
+ cl_dbg_err(cl_hw, "unknown\n");
+ break;
+ }
+
+ cl_dbg_err(cl_hw, "................................. EPC: %08X\n", data->epc);
+ cl_dbg_err(cl_hw, "................................. EXCSAVE: %08X\n", data->excsave);
+ cl_dbg_err(cl_hw, "..........................BACKTRACE-PC.........................\n");
+
+ for (i = 0; i < IPC_BACKTRACT_DEPTH; i++)
+ cl_dbg_err(cl_hw, "PC#%d: 0x%08X\n", i, data->backtrace.pc[i]);
+}
+
+static u16 cl_msg_cfm_clear_bit(u16 cfm)
+{
+ if (cfm < MM_REQ_CFM_MAX)
+ return ((cfm - 1) >> 1);
+
+ return ((cfm - 1 - FIRST_MSG(TASK_DBG) + MM_REQ_CFM_MAX) >> 1);
+}
+
+u16 cl_msg_cfm_set_bit(u16 req)
+{
+ if (req < MM_REQ_CFM_MAX)
+ return (req >> 1);
+
+ return ((req - FIRST_MSG(TASK_DBG) + MM_REQ_CFM_MAX) >> 1);
+}
+
+int cl_msg_cfm_wait(struct cl_hw *cl_hw, u16 bit, u16 req_id)
+{
+ /*
+ * Start a timeout to stop on the main waiting queue,
+ * and then check the result.
+ */
+ struct cl_chip *chip = cl_hw->chip;
+ int timeout = 0, error = 0;
+ int max_timeout = 0;
+
+ if (!cl_hw->msg_calib_timeout)
+ max_timeout = CL_MSG_CFM_TIMEOUT_JIFFIES;
+ else
+ max_timeout = CL_MSG_CFM_TIMEOUT_CALIB_JIFFIES;
+
+ /* Wait for confirmation message */
+ timeout = wait_event_timeout(cl_hw->wait_queue,
+ !CFM_TEST_BIT(bit, &cl_hw->cfm_flags),
+ max_timeout);
+
+ if (timeout == 0) {
+ /*
+ * Timeout occurred!
+ * Make sure that confirmation wasn't received after the timeout.
+ */
+ if (CFM_TEST_BIT(bit, &cl_hw->cfm_flags)) {
+ cl_dbg_verbose(cl_hw, "[WARN] Timeout occurred - %s\n",
+ MSG_ID_STR(req_id));
+ error = -ETIMEDOUT;
+ }
+ }
+
+ if (error) {
+ struct cl_irq_stats *irq_stats = &chip->irq_stats;
+ unsigned long now = jiffies, flags;
+ u32 status, raw_status;
+
+ /*
+ * The interrupt was not handled in time, lets try to handle it safely.
+ * The spin lock protects us from the following race scenarios:
+ * 1) atomic read of the IPC status register,
+ * 2) execution on the msg handler twice from different context.
+ * 3) disable context switch from the same core.
+ */
+ spin_lock_irqsave(&chip->isr_lock, flags);
+
+ status = ipc_xmac_2_host_status_get(chip);
+ raw_status = ipc_xmac_2_host_raw_status_get(chip);
+
+ cl_dbg_verbose(cl_hw,
+ "[INFO] status=0x%x, raw_status=0x%x, last_isr_statuses=0x%x, "
+ "last_rx=%ums, last_tx=%ums, last_isr=%ums\n",
+ status,
+ raw_status,
+ irq_stats->last_isr_statuses,
+ jiffies_to_msecs(now - irq_stats->last_rx),
+ jiffies_to_msecs(now - irq_stats->last_tx),
+ jiffies_to_msecs(now - irq_stats->last_isr));
+
+ if (status & cl_hw->ipc_e2a_irq.msg) {
+ /*
+ * WORKAROUND #1: In some cases the kernel is losing sync with the
+ * interrupt handler and the reason is still unknown.
+ * It seems that disabling master interrupt for a couple of cycles and
+ * then re-enabling it restores the sync with the cl interrupt handler.
+ */
+ ipc_host_global_int_en_set(chip, 0);
+
+ /* Acknowledge the MSG interrupt */
+ ipc_xmac_2_host_ack_set(cl_hw->chip, cl_hw->ipc_e2a_irq.msg);
+
+ /*
+ * Unlock before calling cl_msg_rx_tasklet() because
+ * spin_unlock_irqrestore() disables interrupts, but in
+ * cl_msg_rx_tasklet() there might be several places that
+ * use spin_unlock_bh() which enables soft-irqs.
+ */
+ spin_unlock_irqrestore(&chip->isr_lock, flags);
+
+ /*
+ * Call the tasklet handler (it also gives the CPU that
+ * is mapped to the cl_interrupt few cycle to recover)
+ */
+ cl_msg_rx_tasklet((unsigned long)cl_hw);
+
+ /* Re-enable master interrupts */
+ ipc_host_global_int_en_set(chip, 1);
+ } else {
+ /*
+ * WORKAROUND #2: Try to call the handler unconditioanly.
+ * Maybe we cleared the "cl_hw->ipc_e2a_irq.msg" without handling it.
+ */
+
+ /*
+ * Unlock before calling cl_msg_rx_tasklet() because
+ * spin_unlock_irqrestore() disables interrupts, but in
+ * cl_msg_rx_tasklet() there might be several places
+ * that use spin_unlock_bh() which enables soft-irqs.
+ */
+ spin_unlock_irqrestore(&chip->isr_lock, flags);
+
+ /* Call the tasklet handler */
+ cl_msg_rx_tasklet((unsigned long)cl_hw);
+ }
+
+ /* Did the workarounds work? */
+ if (CFM_TEST_BIT(bit, &cl_hw->cfm_flags)) {
+ cl_dbg_verbose(cl_hw, "[ERR] Failed to recover from timeout\n");
+ } else {
+ cl_dbg_verbose(cl_hw, "[INFO] Managed to recover from timeout\n");
+ error = 0;
+ goto exit;
+ }
+
+ /* Failed handling the message */
+ CFM_CLEAR_BIT(bit, &cl_hw->cfm_flags);
+
+ cl_check_exception(cl_hw);
+
+ cl_hw_assert_check(cl_hw);
+
+ if (!strcmp(chip->conf->ce_ela_mode, "XTDEBUG") ||
+ !strcmp(chip->conf->ce_ela_mode, "XTDEBUG_STD")) {
+ /*
+ * TODO: Special debug hack: collect debug info & skip restart
+ * "wait4cfm" string is expected by debug functionality
+ */
+ goto exit;
+ }
+
+ if (!test_bit(CL_DEV_HW_RESTART, &cl_hw->drv_flags) &&
+ !test_bit(CL_DEV_SW_RESTART, &cl_hw->drv_flags) &&
+ test_bit(CL_DEV_STARTED, &cl_hw->drv_flags) &&
+ !cl_hw->is_stop_context) {
+ /* Unlock msg mutex before restarting */
+ mutex_unlock(&cl_hw->msg_tx_mutex);
+
+ if (cl_coredump_is_scheduled(cl_hw))
+ set_bit(CL_DEV_FW_ERROR, &cl_hw->drv_flags);
+ else
+ cl_recovery_start(cl_hw, RECOVERY_WAIT4CFM);
+
+ return error;
+ }
+ }
+
+exit:
+ /* Unlock msg mutex */
+ mutex_unlock(&cl_hw->msg_tx_mutex);
+
+ return error;
+}
+
+static void cl_msg_cfm_assign_params(struct cl_hw *cl_hw, struct cl_ipc_e2a_msg *msg)
+{
+ u32 *param;
+ u16 msg_id = le16_to_cpu(msg->id);
+ u16 msg_len = le16_to_cpu(msg->param_len);
+
+ /* A message sent in background is not allowed to assign confirmation parameters */
+ if (cl_hw->msg_background) {
+ cl_dbg_verbose(cl_hw,
+ "Background message can't assign confirmation parameters (%s)\n",
+ MSG_ID_STR(msg_id));
+ return;
+ }
+
+ if (msg->param_len) {
+ param = kzalloc(msg_len, GFP_ATOMIC);
+ if (param) {
+ memcpy(param, msg->param, msg_len);
+ if (cl_hw->msg_cfm_params[msg_id])
+ cl_dbg_err(cl_hw, "msg_cfm_params is not NULL for %s\n",
+ MSG_ID_STR(msg_id));
+ cl_hw->msg_cfm_params[msg_id] = param;
+ } else {
+ cl_dbg_err(cl_hw, "param allocation failed\n");
+ }
+ } else {
+ u16 dummy_dest_id = le16_to_cpu(msg->dummy_dest_id);
+ u16 dummy_src_id = le16_to_cpu(msg->dummy_src_id);
+
+ cl_dbg_err(cl_hw, "msg->param_len is 0 [%u,%u,%u]\n",
+ msg_id, dummy_dest_id, dummy_src_id);
+ }
+}
+
+void cl_msg_cfm_assign_and_clear(struct cl_hw *cl_hw, struct cl_ipc_e2a_msg *msg)
+{
+ u16 bit = cl_msg_cfm_clear_bit(msg->id);
+
+ if (CFM_TEST_BIT(bit, &cl_hw->cfm_flags)) {
+ cl_msg_cfm_assign_params(cl_hw, msg);
+ CFM_CLEAR_BIT(bit, &cl_hw->cfm_flags);
+ } else {
+ cl_dbg_verbose(cl_hw, "Msg ID not set in cfm_flags (%s)\n", MSG_ID_STR(msg->id));
+ }
+}
+
+void cl_msg_cfm_clear(struct cl_hw *cl_hw, struct cl_ipc_e2a_msg *msg)
+{
+ u16 bit = cl_msg_cfm_clear_bit(msg->id);
+
+ if (!CFM_TEST_AND_CLEAR_BIT(bit, &cl_hw->cfm_flags))
+ cl_dbg_verbose(cl_hw, "Msg ID not set in cfm_flags (%s)\n", MSG_ID_STR(msg->id));
+}
+
+void cl_msg_cfm_simulate_timeout(struct cl_hw *cl_hw)
+{
+ u16 bit = cl_msg_cfm_set_bit(DBG_SET_MOD_FILTER_REQ);
+
+ mutex_lock(&cl_hw->msg_tx_mutex);
+ CFM_SET_BIT(bit, &cl_hw->cfm_flags);
+ cl_msg_cfm_wait(cl_hw, bit, DBG_STR_SHIFT(DBG_SET_MOD_FILTER_REQ));
+}
+
--
2.30.0

________________________________
The information transmitted is intended only for the person or entity to which it is addressed and may contain confidential and/or privileged material. Any retransmission, dissemination, copying or other use of, or taking of any action in reliance upon this information is prohibited. If you received this in error, please contact the sender and delete the material from any computer. Nothing contained herein shall be deemed as a representation, warranty or a commitment by Celeno. No warranties are expressed or implied, including, but not limited to, any implied warranties of non-infringement, merchantability and fitness for a particular purpose.
________________________________

2021-06-17 16:26:39

by viktor.barna

[permalink] [raw]
Subject: [RFC v1 094/256] cl8k: add fw/msg_rx.c

From: Viktor Barna <[email protected]>

(Part of the split. Please, take a look at the cover letter for more
details).

Signed-off-by: Viktor Barna <[email protected]>
---
drivers/net/wireless/celeno/cl8k/fw/msg_rx.c | 349 +++++++++++++++++++
1 file changed, 349 insertions(+)
create mode 100644 drivers/net/wireless/celeno/cl8k/fw/msg_rx.c

diff --git a/drivers/net/wireless/celeno/cl8k/fw/msg_rx.c b/drivers/net/wireless/celeno/cl8k/fw/msg_rx.c
new file mode 100644
index 000000000000..be8a6b13392b
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/fw/msg_rx.c
@@ -0,0 +1,349 @@
+// SPDX-License-Identifier: MIT
+/* Copyright(c) 2019-2021, Celeno Communications Ltd. */
+
+#include "tx/tx.h"
+#include "sounding.h"
+#include "fw/msg_rx.h"
+#include "fw/msg_tx.h"
+#include "fw/msg_cfm.h"
+#include "stats.h"
+#include "rssi.h"
+#include "fw/fw_dbg.h"
+#include "utils/utils.h"
+#include "hw_assert.h"
+#include "rate_ctrl.h"
+#include "bus/pci/ipc.h"
+#include "rsrc_mgmt.h"
+#ifdef TRACE_SUPPORT
+#include "trace.h"
+#endif
+
+static inline void rx_mm_start_cfm(struct cl_hw *cl_hw, struct cl_ipc_e2a_msg *msg)
+{
+ cl_msg_cfm_clear(cl_hw, msg);
+
+ /* Send indication to the embedded that a new rxbuffer element are ready */
+ cl_hw->ipc_host2xmac_trigger_set(cl_hw->chip, IPC_IRQ_A2E_RXBUF_BACK);
+}
+
+static inline void rx_mm_ba_add_cfm(struct cl_hw *cl_hw, struct cl_ipc_e2a_msg *msg)
+{
+ if (le16_to_cpu(msg->id) == MM_BA_ADD_TX_CFM)
+ cl_msg_cfm_assign_and_clear(cl_hw, msg);
+ else
+ cl_msg_cfm_clear(cl_hw, msg);
+}
+
+static inline void rx_mm_rsrc_mgmt_cfm(struct cl_hw *cl_hw, struct cl_ipc_e2a_msg *msg)
+{
+ struct mm_rsrc_mgmt_cfm *cfm = (struct mm_rsrc_mgmt_cfm *)msg->param;
+
+ cl_rsrc_mgmt_process_cfm(cl_hw, cfm);
+ cl_msg_cfm_clear(cl_hw, msg);
+}
+
+static inline void rx_mm_agg_tx_report_ind(struct cl_hw *cl_hw, struct cl_ipc_e2a_msg *msg)
+{
+ struct cl_agg_tx_report *agg_report = (struct cl_agg_tx_report *)msg->param;
+ struct cl_sta *cl_sta;
+ union cl_rate_ctrl_info rate_ctrl_info;
+
+ /*
+ * Take care of endianness and update gi and format_mod fields of rate
+ * ctrl info in agg_report for the sake of any function that needs to
+ * use them
+ */
+ agg_report->rate_cntrl_info = le32_to_cpu(agg_report->rate_cntrl_info);
+ agg_report->rate_cntrl_info_he = le32_to_cpu(agg_report->rate_cntrl_info_he);
+
+ rate_ctrl_info.word = agg_report->rate_cntrl_info;
+
+ cl_rate_ctrl_convert(&rate_ctrl_info);
+ agg_report->rate_cntrl_info = rate_ctrl_info.word;
+
+ cl_sta_lock(cl_hw);
+ cl_sta = cl_sta_get(cl_hw, agg_report->sta_idx);
+
+ if (cl_sta) {
+ /* TX stats */
+ cl_agg_tx_report_handler(cl_hw, cl_sta, (void *)agg_report);
+ cl_stats_update_tx_agg(cl_hw, cl_sta, agg_report);
+
+ /* RSSI stats */
+ if (!agg_report->ba_not_received)
+ cl_rssi_block_ack_handler(cl_hw, cl_sta, agg_report);
+
+ /*
+ * TODO: Do we need to notify upper layer at agg_report->success?
+ * Ageout may need to reset ageout counter if at least one
+ * frame was success.
+ * May be needed when sending UDP downlink because BA's are not
+ * forwarded to driver.
+ */
+ }
+
+ cl_sta_unlock(cl_hw);
+}
+
+static inline void rx_mm_sounding_ind(struct cl_hw *cl_hw, struct cl_ipc_e2a_msg *msg)
+{
+ struct mm_sounding_ind *ind = (struct mm_sounding_ind *)msg->param;
+
+ cl_sounding_indication(cl_hw, ind);
+}
+
+static inline void rx_mm_fw_error_ind(struct cl_hw *cl_hw, struct cl_ipc_e2a_msg *msg)
+{
+ struct mm_fw_error_ind *ind = (struct mm_fw_error_ind *)msg->param;
+
+ switch (ind->error_type) {
+ case MM_FW_ERROR_TYPE_MU_OFDMA_SLOW_SECONDARY:
+ break;
+ case MM_FW_ERROR_TYPE_MAX:
+ default:
+ cl_dbg_err(cl_hw, "Invalid fw error type %u\n", ind->error_type);
+ break;
+ }
+}
+
+static inline void rx_mm_idle_async_ind(struct cl_hw *cl_hw, struct cl_ipc_e2a_msg *msg)
+{
+ cl_hw->idle_async_set = false;
+
+ cl_dbg_trace(cl_hw, "Clear MM_IDLE_ASYNC_IND\n");
+}
+
+static inline void rx_mm_rsrc_mgmt_ind(struct cl_hw *cl_hw, struct cl_ipc_e2a_msg *msg)
+{
+ cl_rsrc_mgmt_process_ind(cl_hw, (struct mm_rsrc_mgmt_ind *)msg->param);
+}
+
+static inline void rx_dbg_print_ind(struct cl_hw *cl_hw, struct cl_ipc_e2a_msg *msg)
+{
+ cl_hw_assert_print(cl_hw, msg);
+}
+
+static inline void rx_dbg_info_ind(struct cl_hw *cl_hw, struct cl_ipc_e2a_msg *msg)
+{
+ cl_fw_dbg_handler(cl_hw);
+}
+
+static void (*mm_hdlrs[])(struct cl_hw *cl_hw, struct cl_ipc_e2a_msg *msg) = {
+ [MM_RESET_CFM] = cl_msg_cfm_clear,
+ [MM_START_CFM] = rx_mm_start_cfm,
+ [MM_VERSION_CFM] = cl_msg_cfm_assign_and_clear,
+ [MM_ADD_IF_CFM] = cl_msg_cfm_assign_and_clear,
+ [MM_REMOVE_IF_CFM] = cl_msg_cfm_clear,
+ [MM_STA_ADD_CFM] = cl_msg_cfm_assign_and_clear,
+ [MM_STA_DEL_CFM] = cl_msg_cfm_clear,
+ [MM_SET_FILTER_CFM] = cl_msg_cfm_clear,
+ [MM_SET_CHANNEL_CFM] = cl_msg_cfm_clear,
+ [MM_SET_DTIM_CFM] = cl_msg_cfm_clear,
+ [MM_SET_BEACON_INT_CFM] = cl_msg_cfm_clear,
+ [MM_SET_BASIC_RATES_CFM] = cl_msg_cfm_clear,
+ [MM_SET_BSSID_CFM] = cl_msg_cfm_clear,
+ [MM_SET_EDCA_CFM] = cl_msg_cfm_clear,
+ [MM_SET_ASSOCIATED_CFM] = cl_msg_cfm_clear,
+ [MM_SET_SLOTTIME_CFM] = cl_msg_cfm_clear,
+ [MM_SET_IDLE_CFM] = cl_msg_cfm_clear,
+ [MM_KEY_ADD_CFM] = cl_msg_cfm_assign_and_clear,
+ [MM_KEY_DEL_CFM] = cl_msg_cfm_clear,
+ [MM_BA_ADD_TX_CFM] = rx_mm_ba_add_cfm,
+ [MM_BA_ADD_RX_CFM] = rx_mm_ba_add_cfm,
+ [MM_BA_DEL_CFM] = cl_msg_cfm_assign_and_clear,
+ [MM_AVAILABLE_BA_TXQ_CFM] = cl_msg_cfm_assign_and_clear,
+ [MM_UPDATE_RATE_DL_CFM] = cl_msg_cfm_clear,
+ [MM_SET_VNS_CFM] = cl_msg_cfm_clear,
+ [MM_SET_TX_BF_CFM] = cl_msg_cfm_clear,
+ [MM_PHY_RESET_CFM] = cl_msg_cfm_clear,
+ [MM_CONFIG_CCA_CFM] = cl_msg_cfm_clear,
+ [MM_SET_DFS_CFM] = cl_msg_cfm_clear,
+ [MM_SET_ANT_BITMAP_CFM] = cl_msg_cfm_clear,
+ [MM_NDP_TX_CONTROL_CFM] = cl_msg_cfm_clear,
+ [MM_REG_WRITE_CFM] = cl_msg_cfm_clear,
+ [MM_PROT_MODE_CFM] = cl_msg_cfm_clear,
+ [MM_GOTO_POWER_REDUCTION_CFM] = cl_msg_cfm_clear,
+ [MM_SOUNDING_CFM] = cl_msg_cfm_assign_and_clear,
+ [MM_SOUNDING_PAIRING_CFM] = cl_msg_cfm_clear,
+ [MM_SOUNDING_INTERVAL_CFM] = cl_msg_cfm_assign_and_clear,
+ [MM_SOUNDING_STA_SWITCH_CFM] = cl_msg_cfm_assign_and_clear,
+ [MM_BACKUP_BCN_EN_CFM] = cl_msg_cfm_clear,
+ [MM_START_PERIODIC_TX_TIME_CFM] = cl_msg_cfm_clear,
+ [MM_ANAMON_READ_CFM] = cl_msg_cfm_assign_and_clear,
+ [MM_REFRESH_PWR_CFM] = cl_msg_cfm_clear,
+ [MM_SET_ANT_PWR_OFFSET_CFM] = cl_msg_cfm_clear,
+ [MM_SET_RATE_FALLBACK_CFM] = cl_msg_cfm_clear,
+ [MM_TWT_SETUP_CFM] = cl_msg_cfm_clear,
+ [MM_TWT_TEARDOWN_CFM] = cl_msg_cfm_clear,
+ [MM_RSRC_MGMT_CFM] = rx_mm_rsrc_mgmt_cfm,
+ [MM_SET_FREQ_OFFSET_CFM] = cl_msg_cfm_clear,
+ [MM_AGG_TX_REPORT_IND] = rx_mm_agg_tx_report_ind,
+ [MM_SOUNDING_IND] = rx_mm_sounding_ind,
+ [MM_FW_ERROR_IND] = rx_mm_fw_error_ind,
+ [MM_IDLE_ASYNC_IND] = rx_mm_idle_async_ind,
+ [MM_RSRC_MGMT_IND] = rx_mm_rsrc_mgmt_ind,
+ [MM_MAX] = NULL,
+};
+
+#define DBG_MSG_SHIFT(id) ((id) - FIRST_MSG(TASK_DBG))
+
+static void (*dbg_hdlrs[])(struct cl_hw *cl_hw, struct cl_ipc_e2a_msg *msg) = {
+ [DBG_MSG_SHIFT(DBG_SET_MOD_FILTER_CFM)] = cl_msg_cfm_clear,
+ [DBG_MSG_SHIFT(DBG_SET_SEV_FILTER_CFM)] = cl_msg_cfm_clear,
+ [DBG_MSG_SHIFT(DBG_CE_SET_MOD_FILTER_CFM)] = cl_msg_cfm_clear,
+ [DBG_MSG_SHIFT(DBG_BEAMFORMING_TX_CFM)] = cl_msg_cfm_clear,
+ [DBG_MSG_SHIFT(DBG_GET_E2W_STATS_CFM)] = cl_msg_cfm_assign_and_clear,
+ [DBG_MSG_SHIFT(DBG_SET_LA_MPIF_MASK_CFM)] = cl_msg_cfm_clear,
+ [DBG_MSG_SHIFT(DBG_SET_LA_TRIG_POINT_CFM)] = cl_msg_cfm_clear,
+ [DBG_MSG_SHIFT(DBG_SET_LA_MPIF_DEBUG_MODE_CFM)] = cl_msg_cfm_clear,
+ [DBG_MSG_SHIFT(DBG_SET_LA_TRIG_RULE_CFM)] = cl_msg_cfm_clear,
+ [DBG_MSG_SHIFT(DBG_TX_TRACE_DEBUG_FLAG_CFM)] = cl_msg_cfm_clear,
+ [DBG_MSG_SHIFT(DBG_PRINT_STATS_CFM)] = cl_msg_cfm_clear,
+ [DBG_MSG_SHIFT(DBG_TRIGGER_CFM)] = cl_msg_cfm_clear,
+ [DBG_MSG_SHIFT(DBG_TEST_MODE_CFM)] = cl_msg_cfm_clear,
+ [DBG_MSG_SHIFT(DBG_SOUNDING_CMD_CFM)] = cl_msg_cfm_clear,
+ [DBG_MSG_SHIFT(DBG_PRINT_IND)] = rx_dbg_print_ind,
+ [DBG_MSG_SHIFT(DBG_INFO_IND)] = rx_dbg_info_ind,
+ [DBG_MSG_SHIFT(DBG_MAX)] = NULL,
+};
+
+static bool is_dbg_msg(u16 msg_id)
+{
+ return (msg_id >= FIRST_MSG(TASK_DBG) && msg_id < DBG_MAX);
+}
+
+static void cl_msg_rx_run_mm(struct cl_hw *cl_hw, struct cl_ipc_e2a_msg *msg, u16 msg_id)
+{
+ if (msg_id < MM_REQ_CFM_MAX)
+ cl_dbg_trace(cl_hw, "%s\n", msg2str[msg_id]);
+
+ mm_hdlrs[msg_id](cl_hw, msg);
+}
+
+static int cl_msg_rx_run_dbg(struct cl_hw *cl_hw, struct cl_ipc_e2a_msg *msg, u16 msg_id)
+{
+ u16 dbg_id = DBG_MSG_SHIFT(msg_id);
+
+ if (dbg_hdlrs[dbg_id]) {
+ if (msg_id < DBG_REQ_CFM_MAX) {
+ u16 str_id = DBG_STR_SHIFT(msg_id);
+
+ cl_dbg_trace(cl_hw, "%s\n", msg2str[str_id]);
+ }
+
+ dbg_hdlrs[dbg_id](cl_hw, msg);
+ return 0;
+ }
+
+ return -1;
+}
+
+static int cl_msg_rx_run(struct cl_hw *cl_hw, struct cl_ipc_e2a_msg *msg)
+{
+ u16 msg_id = le16_to_cpu(msg->id);
+
+ if (msg_id < MM_MAX && mm_hdlrs[msg_id]) {
+ cl_msg_rx_run_mm(cl_hw, msg, msg_id);
+ return 0;
+ }
+
+ if (is_dbg_msg(msg_id))
+ return cl_msg_rx_run_dbg(cl_hw, msg, msg_id);
+
+ return -1;
+}
+
+static bool is_cfm_msg(u16 msg_id)
+{
+ /* A confirmation must be an odd id */
+ if ((msg_id & 0x1) == 0)
+ return false;
+
+ return ((msg_id < MM_FIRST_IND) || is_dbg_msg(msg_id));
+}
+
+static int cl_msg_rx_handler(struct cl_hw *cl_hw, struct cl_ipc_e2a_msg *msg)
+{
+ int ret = 0;
+ u16 msg_id = le16_to_cpu(msg->id);
+
+#ifdef TRACE_SUPPORT
+ trace_cl_trace_msg_rx_handler_start(cl_hw->idx, msg_id,
+ le32_to_cpu(msg->pattern), cl_hw->cfm_flags);
+#endif
+ /* Relay further actions to the msg parser */
+ ret = cl_msg_rx_run(cl_hw, msg);
+
+ if (ret) {
+ cl_dbg_err(cl_hw, "Unexpected msg (%u)\n", msg_id);
+ } else {
+ /* Wake up the queue in case the msg is a confirmation */
+ if (is_cfm_msg(msg_id))
+ wake_up(&cl_hw->wait_queue);
+ }
+
+#ifdef TRACE_SUPPORT
+ trace_cl_trace_msg_rx_handler_end(cl_hw->idx, cl_hw->cfm_flags);
+#endif
+
+ return ret;
+}
+
+void cl_msg_rx_tasklet(unsigned long data)
+{
+ struct cl_hw *cl_hw = (struct cl_hw *)data;
+ struct cl_ipc_host_env *ipc_env = cl_hw->ipc_env;
+ struct cl_e2a_msg_elem *msg_elem = NULL;
+ struct cl_ipc_e2a_msg *msg = NULL;
+ int msg_handled = 0;
+ u8 idx;
+
+#ifdef TRACE_SUPPORT
+ trace_cl_trace_msg_rx_tasklet_start(cl_hw->idx);
+#endif
+
+ while (1) {
+ idx = ipc_env->e2a_msg_host_idx;
+ msg_elem = (struct cl_e2a_msg_elem *)(ipc_env->e2a_msg_hostbuf_array[idx].hostid);
+ msg = msg_elem->msgbuf_ptr;
+
+ /* Look for pattern which means that this hostbuf has been used for a MSG */
+ if (le32_to_cpu(msg->pattern) != IPC_E2A_MSG_VALID_PATTERN)
+ break;
+
+ cl_msg_rx_handler(cl_hw, msg);
+ msg_handled++;
+
+ /* Reset the msg element and re-use it */
+ msg->pattern = 0;
+
+ /* Make sure memory is written before push to HW */
+ wmb();
+
+ /* Push back the buffer */
+ cl_ipc_msgbuf_push(ipc_env, (ptrdiff_t)msg_elem, msg_elem->dma_addr);
+ }
+
+#ifdef TRACE_SUPPORT
+ trace_cl_trace_msg_rx_tasklet_end(cl_hw->idx, msg_handled);
+#endif
+}
+
+void cl_msg_rx_flush_all(struct cl_hw *cl_hw)
+{
+ int i = 0;
+
+ for (i = FIRST_MSG(TASK_MM); i < MM_MAX; i++) {
+ if (cl_hw->msg_cfm_params[i]) {
+ cl_dbg_verbose(cl_hw, "free MM msg_cfm_params %d\n", i);
+ cl_msg_tx_free_cfm_params(cl_hw, i);
+ }
+ }
+
+ for (i = FIRST_MSG(TASK_DBG); i < DBG_MAX; i++) {
+ if (cl_hw->msg_cfm_params[i]) {
+ cl_dbg_verbose(cl_hw, "free DBG msg_cfm_params %d\n", i);
+ cl_msg_tx_free_cfm_params(cl_hw, i);
+ }
+ }
+}
--
2.30.0

________________________________
The information transmitted is intended only for the person or entity to which it is addressed and may contain confidential and/or privileged material. Any retransmission, dissemination, copying or other use of, or taking of any action in reliance upon this information is prohibited. If you received this in error, please contact the sender and delete the material from any computer. Nothing contained herein shall be deemed as a representation, warranty or a commitment by Celeno. No warranties are expressed or implied, including, but not limited to, any implied warranties of non-infringement, merchantability and fitness for a particular purpose.
________________________________

2021-06-17 16:26:42

by viktor.barna

[permalink] [raw]
Subject: [RFC v1 068/256] cl8k: add e2p.h

From: Viktor Barna <[email protected]>

(Part of the split. Please, take a look at the cover letter for more
details).

Signed-off-by: Viktor Barna <[email protected]>
---
drivers/net/wireless/celeno/cl8k/e2p.h | 166 +++++++++++++++++++++++++
1 file changed, 166 insertions(+)
create mode 100644 drivers/net/wireless/celeno/cl8k/e2p.h

diff --git a/drivers/net/wireless/celeno/cl8k/e2p.h b/drivers/net/wireless/celeno/cl8k/e2p.h
new file mode 100644
index 000000000000..74ec66dfe277
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/e2p.h
@@ -0,0 +1,166 @@
+/* SPDX-License-Identifier: MIT */
+/* Copyright(c) 2019-2021, Celeno Communications Ltd. */
+
+#ifndef CL_E2P_H
+#define CL_E2P_H
+
+#include <linux/types.h>
+#include <net/cfg80211.h>
+
+
+#include "def.h"
+#include "fem_common.h"
+
+/**
+ * EEPROM abstraction layer
+ */
+
+#define SERIAL_NUMBER_SIZE 32
+
+enum eeprom_flavor {
+ EEPROM_FLAVOR_CL80X0,
+ EEPROM_FLAVOR_CL80X6,
+};
+
+struct eeprom_hw {
+ u8 reserved[96];
+} __packed;
+
+struct eeprom_general {
+ u8 version;
+ u8 flavor;
+ u8 mac_address[6];
+ u8 temp_diff; /* Default value TEMP_DIFF_INVALID = 0x7F */
+ u8 serial_number[SERIAL_NUMBER_SIZE];
+ u8 pwr_table_id[2];
+ u8 reserved[53];
+} __attribute__((__packed__));
+
+struct eeprom_fem {
+ u8 wiring_id;
+ u16 fem_lut[FEM_TYPE_MAX];
+ u32 platform_id;
+ u8 reserved[19];
+} __packed;
+
+struct eeprom_phy_calib {
+ s8 pow;
+ s8 offset;
+ s8 tmp;
+} __packed;
+
+#define BIT_MAP_SIZE 20
+#define NUM_OF_PIVOTS 20
+#define NUM_PIVOT_PHYS (MAX_ANTENNAS * NUM_OF_PIVOTS)
+
+struct eeprom_calib {
+ u16 freq_offset;
+ u8 chan_bmp[BIT_MAP_SIZE];
+ struct eeprom_phy_calib phy_calib[NUM_PIVOT_PHYS];
+} __packed;
+
+struct eeprom {
+ struct eeprom_hw hw;
+ struct eeprom_general general;
+ struct eeprom_fem fem;
+ struct eeprom_calib calib;
+} __packed;
+
+enum {
+ ADDR_HW = offsetof(struct eeprom, hw),
+ ADDR_HW_RESERVED = ADDR_HW + offsetof(struct eeprom_hw, reserved),
+
+ ADDR_GEN = offsetof(struct eeprom, general),
+ ADDR_GEN_VERSION = ADDR_GEN + offsetof(struct eeprom_general, version),
+ ADDR_GEN_FLAVOR = ADDR_GEN + offsetof(struct eeprom_general, flavor),
+ ADDR_GEN_MAC_ADDR = ADDR_GEN + offsetof(struct eeprom_general, mac_address),
+ ADDR_GEN_TEMP_DIFF = ADDR_GEN + offsetof(struct eeprom_general, temp_diff),
+ ADDR_GEN_SERIAL_NUMBER = ADDR_GEN + offsetof(struct eeprom_general, serial_number),
+ ADDR_GEN_PWR_TABLE_ID = ADDR_GEN + offsetof(struct eeprom_general, pwr_table_id),
+ ADDR_GEN_RESERVED = ADDR_GEN + offsetof(struct eeprom_general, reserved),
+
+ ADDR_FEM = offsetof(struct eeprom, fem),
+ ADDR_FEM_WIRING_ID = ADDR_FEM + offsetof(struct eeprom_fem, wiring_id),
+ ADDR_FEM_LUT = ADDR_FEM + offsetof(struct eeprom_fem, fem_lut),
+ ADDR_FEM_PLATFORM_ID = ADDR_FEM + offsetof(struct eeprom_fem, platform_id),
+ ADDR_FEM_RESERVED = ADDR_FEM + offsetof(struct eeprom_fem, reserved),
+
+ ADDR_CALIB = offsetof(struct eeprom, calib),
+ ADDR_CALIB_FREQ_OFFSET = ADDR_CALIB + offsetof(struct eeprom_calib, freq_offset),
+ ADDR_CALIB_CHAN_BMP = ADDR_CALIB + offsetof(struct eeprom_calib, chan_bmp),
+ ADDR_CALIB_PHY = ADDR_CALIB + offsetof(struct eeprom_calib, phy_calib),
+
+ SIZE_HW = sizeof(struct eeprom_hw),
+ SIZE_HW_RESERVED = ADDR_GEN - ADDR_HW_RESERVED,
+
+ SIZE_GEN = sizeof(struct eeprom_general),
+ SIZE_GEN_VERSION = ADDR_GEN_FLAVOR - ADDR_GEN_VERSION,
+ SIZE_GEN_FLAVOR = ADDR_GEN_MAC_ADDR - ADDR_GEN_FLAVOR,
+ SIZE_GEN_MAC_ADDR = ADDR_GEN_TEMP_DIFF - ADDR_GEN_MAC_ADDR,
+ SIZE_GEN_TEMP_DIFF = ADDR_GEN_SERIAL_NUMBER - ADDR_GEN_TEMP_DIFF,
+ SIZE_GEN_SERIAL_NUMBER = ADDR_GEN_PWR_TABLE_ID - ADDR_GEN_SERIAL_NUMBER,
+ SIZE_GEN_PWR_TABLE_ID = ADDR_GEN_RESERVED - ADDR_GEN_PWR_TABLE_ID,
+ SIZE_GEN_RESERVED = ADDR_FEM - ADDR_GEN_RESERVED,
+
+ SIZE_FEM = sizeof(struct eeprom_fem),
+ SIZE_FEM_WIRING_ID = ADDR_FEM_LUT - ADDR_FEM_WIRING_ID,
+ SIZE_FEM_LUT = ADDR_FEM_PLATFORM_ID - ADDR_FEM_LUT,
+ SIZE_FEM_PLATFORM_ID = ADDR_FEM_RESERVED - ADDR_FEM_PLATFORM_ID,
+
+ SIZE_CALIB = sizeof(struct eeprom_calib),
+ SIZE_CALIB_FREQ_OFFSET = ADDR_CALIB_CHAN_BMP - ADDR_CALIB_FREQ_OFFSET,
+ SIZE_CALIB_CHAN_BMP = ADDR_CALIB_PHY - ADDR_CALIB_CHAN_BMP,
+ SIZE_CALIB_PHY = sizeof(struct eeprom_phy_calib) * NUM_PIVOT_PHYS,
+
+ EEPROM_NUM_BYTES = sizeof(struct eeprom),
+ EEPROM_LAST_BYTE = EEPROM_NUM_BYTES - 1,
+};
+
+struct cl_e2p_get_reply {
+ u8 e2p_mode;
+ u8 e2p_data[];
+};
+
+struct cl_chip;
+
+int cl_e2p_init(struct cl_chip *chip);
+void cl_e2p_close(struct cl_chip *chip);
+int cl_e2p_write(struct cl_chip *chip, u8 *data, u16 size, u16 addr);
+int cl_e2p_read(struct cl_chip *chip, u8 *data, u16 size, u16 addr);
+int cl_e2p_write_version(struct cl_chip *chip);
+int cl_e2p_get_addr(struct wiphy *wiphy, struct wireless_dev *wdev,
+ void *data, int data_len);
+int cl_e2p_set_addr(struct wiphy *wiphy, struct wireless_dev *wdev,
+ const void *data, int data_len);
+int cl_e2p_set_wiring_id(struct wiphy *wiphy, struct wireless_dev *wdev,
+ const void *data, int data_len);
+int cl_e2p_help(struct wiphy *wiphy, struct wireless_dev *wdev,
+ void *data, int data_len);
+
+enum cl_e2p_cmd {
+ CL_E2P_GET_ADDR,
+ CL_E2P_GET_MAC,
+ CL_E2P_GET_SERIAL_NUMBER,
+ CL_E2P_GET_PWR_TABLE_ID,
+ CL_E2P_GET_FREQ_OFFSET,
+ CL_E2P_GET_WIRING_ID,
+ CL_E2P_GET_FEM_LUT,
+ CL_E2P_GET_PLATFORM_ID,
+ CL_E2P_GET_CALIB,
+ CL_E2P_GET_HEXDUMP,
+ CL_E2P_GET_TABLE,
+
+ CL_E2P_SET_ADDR,
+ CL_E2P_SET_MAC,
+ CL_E2P_SET_SERIAL_NUMBER,
+ CL_E2P_SET_PWR_TABLE_ID,
+ CL_E2P_SET_FREQ_OFFSET,
+ CL_E2P_SET_WIRING_ID,
+ CL_E2P_SET_FEM_LUT,
+ CL_E2P_SET_PLATFORM_ID,
+ CL_E2P_SET_CALIB,
+
+ CL_E2P_MAX
+};
+
+#endif /* CL_E2P_H */
--
2.30.0

________________________________
The information transmitted is intended only for the person or entity to which it is addressed and may contain confidential and/or privileged material. Any retransmission, dissemination, copying or other use of, or taking of any action in reliance upon this information is prohibited. If you received this in error, please contact the sender and delete the material from any computer. Nothing contained herein shall be deemed as a representation, warranty or a commitment by Celeno. No warranties are expressed or implied, including, but not limited to, any implied warranties of non-infringement, merchantability and fitness for a particular purpose.
________________________________

2021-06-17 16:26:42

by viktor.barna

[permalink] [raw]
Subject: [RFC v1 107/256] cl8k: add mac_addr.c

From: Viktor Barna <[email protected]>

(Part of the split. Please, take a look at the cover letter for more
details).

Signed-off-by: Viktor Barna <[email protected]>
---
drivers/net/wireless/celeno/cl8k/mac_addr.c | 331 ++++++++++++++++++++
1 file changed, 331 insertions(+)
create mode 100644 drivers/net/wireless/celeno/cl8k/mac_addr.c

diff --git a/drivers/net/wireless/celeno/cl8k/mac_addr.c b/drivers/net/wireless/celeno/cl8k/mac_addr.c
new file mode 100644
index 000000000000..eeb3ce294111
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/mac_addr.c
@@ -0,0 +1,331 @@
+// SPDX-License-Identifier: MIT
+/* Copyright(c) 2019-2021, Celeno Communications Ltd. */
+
+#include "mac_addr.h"
+#include "utils/utils.h"
+#include "chip.h"
+
+static int set_mask_addr_without_zeroing_bits(struct cl_hw *cl_hw, u64 mac64, u8 bss_num,
+ u8 first_mask_bit, u8 *mask_addr)
+{
+ u64 mask = mac64;
+ s8 idx = 0;
+
+ mask >>= first_mask_bit;
+ mask += (bss_num - 1);
+
+ /*
+ * After the following line the mask will contain the changed
+ * bits between the first BSS MAC and the last BSS MAC
+ */
+ mask ^= (mac64 >> first_mask_bit);
+
+ /* Find leftmost set bit */
+ for (idx = 47 - first_mask_bit; (idx >= 0) && (!(mask & (1ULL << idx))); idx--)
+ ;
+
+ if (idx < 0) {
+ cl_dbg_err(cl_hw, "Invalid mask (mac=0x%02llx, first_mask_bit=%u, bss_num=%u)\n",
+ mac64, first_mask_bit, bss_num);
+ mask = 0;
+ eth_zero_addr(mask_addr);
+
+ return -1;
+ }
+
+ mask = (1ULL << idx);
+ mask |= (mask - 1);
+ mask <<= first_mask_bit;
+
+ for (idx = 0; idx < ETH_ALEN; idx++) {
+ u8 shift = (8 * (ETH_ALEN - 1 - idx));
+
+ mask_addr[idx] = (mask & ((u64)0xff << shift)) >> shift;
+ }
+
+ return 0;
+}
+
+static int mask_mac_by_bss_num(struct cl_hw *cl_hw, u8 *mac_addr, u8 *mask_addr,
+ bool use_lam, bool random_mac)
+{
+ u8 bss_num = cl_hw->conf->ce_bss_num;
+ u8 first_mask_bit = cl_hw->chip->conf->ce_first_mask_bit;
+ u8 i;
+ /* Determine the bits necessary to cover the number of BSSIDs. */
+ u8 num_bits_to_mask[MAX_BSS_NUM * 2 + 1] = {
+ 0, 0, 1, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4
+ };
+ u8 mask_size = 0;
+ u8 byte_num = ETH_ALEN - 1 - (first_mask_bit / 8);
+ u8 bit_in_byte = first_mask_bit % 8; /* Referring to the index of the bit */
+
+ if ((first_mask_bit + num_bits_to_mask[bss_num]) > (ETH_ALEN * 8)) {
+ pr_err("Invalid combination of first_mask_bit + bss_num. "
+ "must be lower than 48 bit in total\n");
+ return -1;
+ }
+
+ if (cl_hw_is_tcv0(cl_hw)) {
+ mask_size = num_bits_to_mask[bss_num - 1];
+ } else {
+ u64 mac64 = ether_addr_to_u64(mac_addr);
+ u8 tcv0_bss_num = cl_hw->chip->cl_hw_tcv0->conf->ce_bss_num;
+ u8 bit_mask = (1 << num_bits_to_mask[bss_num + tcv0_bss_num - 1]) - 1;
+
+ /*
+ * If we need to zero bits due to lack of room for the MAC addresses
+ * of all BSSs of TCV1, then the mask is the number of zeroed bits
+ */
+ if (((u64)bit_mask - ((mac64 >> first_mask_bit) & (u64)bit_mask) + 1) < bss_num) {
+ mask_size = num_bits_to_mask[bss_num + tcv0_bss_num - 1];
+ } else {
+ /*
+ * Otherwise the mask is the different bits between the
+ * addresses of the first and the last BSSs
+ */
+ set_mask_addr_without_zeroing_bits(cl_hw, mac64, bss_num,
+ first_mask_bit, mask_addr);
+ return 0;
+ }
+ }
+
+ /* Build mac and mask addr */
+ for (i = 0; i < mask_size; i++) {
+ /*
+ * Build mask - Convert to "1" the relevant bits in the mask
+ * addr in order to support the desired number of BSSIDs
+ */
+ mask_addr[byte_num] |= (0x01 << bit_in_byte);
+
+ /*
+ * Build mac -convert to "0" the relevant bits in the mac addr
+ * in order to support the desired number of BSSIDs
+ */
+ if (random_mac && !use_lam)
+ mac_addr[byte_num] &= ~(0x01 << bit_in_byte);
+
+ bit_in_byte++;
+
+ /* Support cases where the mask bits are not at the same byte. */
+ if (bit_in_byte == 8) {
+ byte_num--;
+ bit_in_byte = 0;
+ }
+ }
+
+ if (use_lam) {
+ /* Mask LAM bit (Locally Administered Mac) */
+ if (cl_hw_is_tcv0(cl_hw))
+ mask_addr[0] |= 0x02;
+ } else {
+ /*
+ * When not using LAM we do not zero the MAC address of the second BSS,
+ * so the mask (the modified bits between the first and last BSS) depends
+ * on initial MAC
+ */
+ u64 mac64 = ether_addr_to_u64(mac_addr);
+
+ set_mask_addr_without_zeroing_bits(cl_hw, mac64, bss_num,
+ first_mask_bit, mask_addr);
+ }
+
+ return 0;
+}
+
+#define MAC_FILTER_BITS 4
+#define MAC_FILTER_MASK ((1 << MAC_FILTER_BITS) - 1)
+
+static bool is_valid_mac_addr(u64 mac64, u8 first_mask_bit, u8 bss_num)
+{
+ u8 mac_bits = (mac64 >> first_mask_bit) & MAC_FILTER_MASK;
+ u8 mac_diff = 0;
+ u8 i;
+
+ for (i = 0; i < bss_num; i++) {
+ mac_diff |= mac_bits;
+ mac_bits++;
+ }
+
+ return hweight8(mac_diff) <= MAC_FILTER_BITS;
+}
+
+static int cl_mac_addr_set_addresses(struct cl_hw *cl_hw, bool use_lam,
+ u8 *mask_addr)
+{
+ u8 first_mask_bit = cl_hw->chip->conf->ce_first_mask_bit;
+ int i = 0;
+ u8 bss_num = cl_hw->conf->ce_bss_num;
+ u64 mac64 = ether_addr_to_u64(cl_hw->hw->wiphy->perm_addr);
+ u64 mask64 = 0;
+ u8 new_addr[ETH_ALEN] = {0};
+
+ if (!use_lam && !is_valid_mac_addr(mac64, first_mask_bit, bss_num)) {
+ cl_dbg_err(cl_hw,
+ "perm_addr %pM is invalid for bss_num %d without LAM\n",
+ cl_hw->hw->wiphy->perm_addr, bss_num);
+ return -1;
+ }
+
+ cl_mac_addr_copy(cl_hw->addresses[i].addr,
+ cl_hw->hw->wiphy->perm_addr);
+ for (i = 1; i < bss_num; i++) {
+ u8 *prev_addr = cl_hw->addresses[i - 1].addr;
+
+ if (use_lam) {
+ mac64 = ether_addr_to_u64(prev_addr);
+ mask64 = ether_addr_to_u64(mask_addr);
+ if (cl_hw_is_tcv0(cl_hw)) {
+ if (i == 1)
+ mac64 &= ~mask64;
+ else
+ mac64 += 1 << first_mask_bit;
+ u64_to_ether_addr(mac64, new_addr);
+ new_addr[0] |= 0x02;
+ } else {
+ if ((mac64 & mask64) == mask64)
+ mac64 &= ~mask64;
+ else
+ mac64 += 1 << first_mask_bit;
+ u64_to_ether_addr(mac64, new_addr);
+ }
+ cl_mac_addr_copy(cl_hw->addresses[i].addr, new_addr);
+ } else {
+ mac64 = ether_addr_to_u64(prev_addr);
+ mac64 += 1 << first_mask_bit;
+ u64_to_ether_addr(mac64, cl_hw->addresses[i].addr);
+ }
+ }
+ cl_hw->n_addresses = bss_num;
+
+ return 0;
+}
+
+int cl_mac_addr_set_tcv0(struct cl_hw *cl_hw, u8 *dflt_mac, u8 *dflt_mask, bool *random_mac)
+{
+ struct cl_chip *chip = cl_hw->chip;
+
+ if (!cl_mac_addr_is_zero(chip->conf->ce_phys_mac_addr)) {
+ /* Read MAC from NVRAM file */
+ cl_mac_addr_copy(dflt_mac, chip->conf->ce_phys_mac_addr);
+ cl_dbg_verbose(cl_hw, "Read MAC address from NVRAM [%pM]\n", dflt_mac);
+ } else {
+ /* Read MAC from EEPROM */
+ if (chip->eeprom_read_block(chip, ADDR_GEN_MAC_ADDR,
+ ETH_ALEN, dflt_mac) != ETH_ALEN) {
+ CL_DBG_ERROR(cl_hw, "Error reading MAC address from EEPROM\n");
+ return -1;
+ }
+
+ cl_dbg_verbose(cl_hw, "Read MAC address from EEPROM [%pM]\n", dflt_mac);
+ }
+
+ /* Test if the new mac address is 00:00:00:00:00:00 or ff:ff:ff:ff:ff:ff */
+ if (cl_mac_addr_is_zero(dflt_mac) || cl_mac_addr_is_broadcast(dflt_mac)) {
+ /* Set celeno oui */
+ dflt_mac[0] = 0x00;
+ dflt_mac[1] = 0x1c;
+ dflt_mac[2] = 0x51;
+ get_random_bytes(&dflt_mac[3], 3);
+ cl_dbg_verbose(cl_hw, "Random MAC address [%pM]\n", dflt_mac);
+ *random_mac = true;
+ }
+
+ return 0;
+}
+
+void cl_mac_addr_set_tcv1(struct cl_hw *cl_hw, u8 *dflt_mac, u8 *dflt_mask)
+{
+ struct cl_chip *chip = cl_hw->chip;
+ struct cl_hw *cl_hw_tcv0 = chip->cl_hw_tcv0;
+ u8 tcv0_bss_num = cl_hw_tcv0->conf->ce_bss_num;
+ u8 first_mask_bit = chip->conf->ce_first_mask_bit;
+ u64 mac64;
+ u8 idx;
+ u8 bss_num = cl_hw->conf->ce_bss_num;
+ u8 bit_mask[MAX_BSS_NUM + 1] = {0x0, 0x0, 0x1, 0x3, 0x3, 0x7, 0x7, 0x7, 0x7};
+
+ mac64 = ether_addr_to_u64(cl_hw_tcv0->hw->wiphy->perm_addr);
+
+ if (chip->conf->ce_lam_enable) {
+ /* Find the first address of TCV1 */
+ if (tcv0_bss_num == 1) {
+ /*
+ * For tcv0 bss num = 1, we have to zero the necessary bits
+ * since it hasn't been done in TCV0
+ */
+ mac64 &= ~((u64)bit_mask[bss_num] << first_mask_bit);
+ } else {
+ u8 total_bss_to_mask = bss_num + tcv0_bss_num - 1;
+
+ mac64 &= ~((u64)bit_mask[tcv0_bss_num - 1] << first_mask_bit);
+ /*
+ * Get the first MAC address of TCV1 by incrementing the MAC
+ * address of the last BSS of TCV0.
+ * After the instruction below mac64 will hold the MAC of TCV0's
+ * last BSS.
+ */
+ mac64 += ((u64)(tcv0_bss_num - 2) << first_mask_bit);
+ /*
+ * If there is no more room for another address in TCV0's mask
+ * address then we have to zero bits else increment the last
+ * address of TCV0
+ */
+ if (((mac64 >> first_mask_bit) & (u64)bit_mask[total_bss_to_mask]) ==
+ (u64)bit_mask[total_bss_to_mask])
+ mac64 &= ~((u64)bit_mask[total_bss_to_mask] << first_mask_bit);
+ else
+ mac64 += (1ULL << first_mask_bit);
+ }
+
+ /* Enable LAM bit */
+ mac64 += (0x2ULL << 40);
+ } else {
+ mac64 += ((u64)tcv0_bss_num << first_mask_bit);
+ }
+
+ for (idx = 0; idx < ETH_ALEN; idx++) {
+ u8 shift = (8 * (ETH_ALEN - 1 - idx));
+
+ dflt_mac[idx] = (mac64 & ((u64)0xFF << shift)) >> shift;
+ }
+}
+
+int cl_mac_addr_set(struct cl_hw *cl_hw)
+{
+ bool random_mac = false;
+ u8 dflt_mac[ETH_ALEN] = {0, 28, 81, 81, 81, 81};
+ u8 dflt_mask[ETH_ALEN] = {0};
+ bool use_lam = cl_hw->chip->conf->ce_lam_enable;
+ struct wiphy *wiphy = cl_hw->hw->wiphy;
+
+ if (cl_hw_is_tcv0(cl_hw)) {
+ if (cl_mac_addr_set_tcv0(cl_hw, dflt_mac, dflt_mask, &random_mac))
+ return -1;
+ } else {
+ cl_mac_addr_set_tcv1(cl_hw, dflt_mac, dflt_mask);
+ }
+
+ /* For single BSS mask should be 0 */
+ if (cl_hw->conf->ce_bss_num > 1)
+ if (mask_mac_by_bss_num(cl_hw, dflt_mac, dflt_mask, use_lam, random_mac))
+ return -1;
+
+ /* Permanent address MAC (the MAC of the first BSS) */
+ SET_IEEE80211_PERM_ADDR(cl_hw->hw, dflt_mac);
+
+ /*
+ * MAX_BSS_NUM must be power of 2
+ * mac80211 doesn't handle non-contiguous masks
+ */
+ if (!WARN_ON(MAX_BSS_NUM & (MAX_BSS_NUM - 1)))
+ cl_mac_addr_array_to_nxmac(dflt_mask, &cl_hw->mask_low, &cl_hw->mask_hi);
+
+ if (cl_mac_addr_set_addresses(cl_hw, use_lam, dflt_mask))
+ return -1;
+
+ wiphy->addresses = cl_hw->addresses;
+ wiphy->n_addresses = cl_hw->n_addresses;
+
+ return 0;
+}
--
2.30.0

________________________________
The information transmitted is intended only for the person or entity to which it is addressed and may contain confidential and/or privileged material. Any retransmission, dissemination, copying or other use of, or taking of any action in reliance upon this information is prohibited. If you received this in error, please contact the sender and delete the material from any computer. Nothing contained herein shall be deemed as a representation, warranty or a commitment by Celeno. No warranties are expressed or implied, including, but not limited to, any implied warranties of non-infringement, merchantability and fitness for a particular purpose.
________________________________

2021-06-17 16:26:42

by viktor.barna

[permalink] [raw]
Subject: [RFC v1 109/256] cl8k: add main.c

From: Viktor Barna <[email protected]>

(Part of the split. Please, take a look at the cover letter for more
details).

Signed-off-by: Viktor Barna <[email protected]>
---
drivers/net/wireless/celeno/cl8k/main.c | 584 ++++++++++++++++++++++++
1 file changed, 584 insertions(+)
create mode 100644 drivers/net/wireless/celeno/cl8k/main.c

diff --git a/drivers/net/wireless/celeno/cl8k/main.c b/drivers/net/wireless/celeno/cl8k/main.c
new file mode 100644
index 000000000000..0b37ae8a03e1
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/main.c
@@ -0,0 +1,584 @@
+// SPDX-License-Identifier: MIT
+/* Copyright(c) 2019-2021, Celeno Communications Ltd. */
+
+#include "chip.h"
+#include "main.h"
+#include "ops.h"
+#include "dfs/radar.h"
+#include "fw/msg_tx.h"
+#include "tx/tx.h"
+#include "reg/reg_access.h"
+#include "stats.h"
+#include "debugfs.h"
+#include "vendor_cmd.h"
+#include "chan_info.h"
+#include "tx/agg_cfm.h"
+#include "tx/single_cfm.h"
+#include "tx/bcmc_cfm.h"
+#include "tx/tx_queue.h"
+#include "rssi.h"
+#include "maintenance.h"
+#include "vns.h"
+#include "traffic.h"
+#include "ext/vlan_dscp.h"
+#include "sounding.h"
+#include "recovery.h"
+#include "rate_ctrl.h"
+#include "ext/dyn_mcast_rate.h"
+#include "ext/dyn_bcast_rate.h"
+#include "tx/tx_amsdu.h"
+#include "prot_mode.h"
+#include "utils/utils.h"
+#include "band.h"
+#include "phy/phy.h"
+#include "rf_boot.h"
+#include "dsp.h"
+#include "calib.h"
+#include "reg/reg_macsys_gcu.h"
+#include "dfs/dfs.h"
+#include "tx/sw_txhdr.h"
+#include "tx/tx_inject.h"
+#include "fem.h"
+#include "fw/fw_file.h"
+#include "cap.h"
+#include "tcv_config.h"
+#include "mac_addr.h"
+#include "hw_assert.h"
+#include "power_table.h"
+#include "noise.h"
+#include "twt.h"
+#include "fw/fw_dbg.h"
+#include "wrs/wrs_api.h"
+#ifdef CONFIG_CL_PCIE
+#include "fw/msg_rx.h"
+#include "bus/pci/irq.h"
+#include "reg/reg_ipc.h"
+#include "bus/pci/ipc.h"
+#endif
+
+MODULE_DESCRIPTION("Celeno 11ax driver for Linux");
+MODULE_VERSION("8.1.x");
+MODULE_AUTHOR("Copyright(c) 2021 Celeno Communications Ltd");
+MODULE_LICENSE("MIT");
+
+#define MAX_MU_CNT_LMAC 8
+#define MAX_MU_CNT_SMAC 8
+
+static struct ieee80211_ops cl_ops = {
+ .tx = cl_ops_tx,
+ .start = cl_ops_start,
+ .stop = cl_ops_stop,
+ .add_interface = cl_ops_add_interface,
+ .remove_interface = cl_ops_remove_interface,
+ .config = cl_ops_config,
+ .bss_info_changed = cl_ops_bss_info_changed,
+ .start_ap = cl_ops_start_ap,
+ .stop_ap = cl_ops_stop_ap,
+ .prepare_multicast = cl_ops_prepare_multicast,
+ .configure_filter = cl_ops_configure_filter,
+ .set_key = cl_ops_set_key,
+ .sw_scan_start = cl_ops_sw_scan_start,
+ .sta_state = cl_ops_sta_state,
+ .sta_notify = cl_ops_sta_notify,
+ .conf_tx = cl_ops_conf_tx,
+ .sta_rc_update = cl_ops_sta_rc_update,
+ .ampdu_action = cl_ops_ampdu_action,
+ .post_channel_switch = cl_ops_post_channel_switch,
+ .flush = cl_ops_flush,
+ .tx_frames_pending = cl_ops_tx_frames_pending,
+ .reconfig_complete = cl_ops_reconfig_complete,
+ .get_txpower = cl_ops_get_txpower,
+ .set_rts_threshold = cl_ops_set_rts_threshold,
+ .event_callback = cl_ops_event_callback,
+ .set_tim = cl_ops_set_tim,
+};
+
+static void cl_drv_workqueue_create(struct cl_hw *cl_hw)
+{
+ if (!cl_hw->drv_workqueue)
+ cl_hw->drv_workqueue = create_singlethread_workqueue("drv_workqueue");
+}
+
+static void cl_drv_workqueue_destroy(struct cl_hw *cl_hw)
+{
+ if (cl_hw->drv_workqueue) {
+ destroy_workqueue(cl_hw->drv_workqueue);
+ cl_hw->drv_workqueue = NULL;
+ }
+}
+
+static int cl_main_alloc(struct cl_hw *cl_hw)
+{
+ int ret = 0;
+
+ ret = cl_phy_data_alloc(cl_hw);
+ if (ret)
+ return ret;
+
+ ret = cl_calib_tables_alloc(cl_hw);
+ if (ret)
+ return ret;
+
+ ret = cl_power_table_alloc(cl_hw);
+ if (ret)
+ return ret;
+
+ return ret;
+}
+
+static void cl_main_free(struct cl_hw *cl_hw)
+{
+ cl_phy_data_free(cl_hw);
+ cl_calib_tables_free(cl_hw);
+ cl_power_table_free(cl_hw);
+}
+
+static void cl_free_hw(struct cl_hw *cl_hw)
+{
+ struct ieee80211_hw *hw = cl_hw->hw;
+
+ cl_tcv_config_free(cl_hw);
+
+ if (hw->wiphy->registered)
+ ieee80211_unregister_hw(hw);
+
+ cl_chip_unset_hw(cl_hw->chip, cl_hw);
+ ieee80211_free_hw(hw);
+}
+
+static void cl_free_chip(struct cl_chip *chip)
+{
+ cl_free_hw(chip->cl_hw_tcv0);
+ cl_free_hw(chip->cl_hw_tcv1);
+}
+
+static int cl_prepare_hw(struct cl_chip *chip, u8 tcv_idx,
+ const struct cl_driver_ops *drv_ops)
+{
+ struct cl_hw *cl_hw = NULL;
+ struct ieee80211_hw *hw;
+ int ret = 0;
+
+ hw = ieee80211_alloc_hw(sizeof(struct cl_hw), &cl_ops);
+ if (!hw) {
+ cl_dbg_chip_err(chip, ": ieee80211_alloc_hw failed\n");
+ return -ENOMEM;
+ }
+
+ cl_hw_init(chip, hw->priv, tcv_idx);
+
+ cl_hw = hw->priv;
+ cl_hw->hw = hw;
+ cl_hw->tcv_idx = tcv_idx;
+ cl_hw->chip = chip;
+
+ /*
+ * chip0, tcv0 --> 0
+ * chip0, tcv1 --> 1
+ * chip1, tcv0 --> 2
+ * chip1, tcv1 --> 3
+ */
+ cl_hw->idx = chip->idx * CHIP_MAX + tcv_idx;
+
+ cl_hw->drv_ops = drv_ops;
+
+ if (cl_hw_is_tcv0(cl_hw))
+ cl_hw->max_mu_cnt = MAX_MU_CNT_LMAC;
+ else
+ cl_hw->max_mu_cnt = MAX_MU_CNT_SMAC;
+
+ SET_IEEE80211_DEV(hw, chip->dev);
+
+ ret = cl_tcv_config_alloc(cl_hw);
+ if (ret)
+ goto out_free_hw;
+
+ ret = cl_hw_set_antennas(cl_hw);
+ if (ret)
+ goto out_free_hw;
+
+ ret = cl_tcv_config_read(cl_hw);
+ if (ret)
+ goto out_free_hw;
+
+ cl_chip_set_hw(chip, cl_hw);
+
+ ret = cl_mac_addr_set(cl_hw);
+ if (ret) {
+ cl_dbg_err(cl_hw, "cl_mac_addr_set failed\n");
+ goto out_free_hw;
+ }
+
+ if (cl_band_is_6g(cl_hw))
+ cl_hw->nl_band = NL80211_BAND_6GHZ;
+ else if (cl_band_is_5g(cl_hw))
+ cl_hw->nl_band = NL80211_BAND_5GHZ;
+ else
+ cl_hw->nl_band = NL80211_BAND_2GHZ;
+
+ cl_cap_dyn_params(cl_hw);
+ cl_vendor_cmds_init(hw->wiphy);
+
+ /*
+ * ieee80211_register_hw() will take care of calling wiphy_register() and
+ * also ieee80211_if_add() (because IFTYPE_STATION is supported)
+ * which will internally call register_netdev()
+ */
+ ret = ieee80211_register_hw(hw);
+ if (ret) {
+ cl_dbg_err(cl_hw, "ieee80211_register_hw failed\n");
+ goto out_free_hw;
+ }
+
+ if (hw->wiphy->regulatory_flags & REGULATORY_WIPHY_SELF_MANAGED) {
+ ret = regulatory_set_wiphy_regd(hw->wiphy, cl_hw->channel_info.rd);
+ if (ret)
+ cl_dbg_err(cl_hw, "regulatory failed\n");
+ }
+
+ cl_dbg_verbose(cl_hw, "cl_hw created\n");
+
+ return 0;
+
+out_free_hw:
+ cl_free_hw(cl_hw);
+
+ return ret;
+}
+
+void cl_main_off(struct cl_hw *cl_hw)
+{
+#ifdef CONFIG_CL_PCIE
+ cl_irq_disable(cl_hw, cl_hw->ipc_e2a_irq.all);
+ cl_ipc_stop(cl_hw);
+#endif
+
+ if (!test_bit(CL_DEV_INIT, &cl_hw->drv_flags)) {
+ cl_tx_off(cl_hw);
+ cl_rx_off(cl_hw);
+#ifdef CONFIG_CL_PCIE
+ cl_msg_rx_flush_all(cl_hw);
+#endif
+ }
+
+ cl_fw_file_cleanup(cl_hw);
+}
+
+static void _cl_main_deinit(struct cl_hw *cl_hw)
+{
+ /* First bring down all interfaces */
+ cl_vif_bring_all_interfaces_down(cl_hw);
+
+ cl_hw->is_stop_context = true;
+
+ cl_drv_workqueue_destroy(cl_hw);
+
+ cl_noise_close(cl_hw);
+ cl_maintenance_close(cl_hw);
+ cl_vns_close(cl_hw);
+ cl_rssi_assoc_exit(cl_hw);
+ cl_radar_close(cl_hw);
+ cl_sounding_close(cl_hw);
+ cl_chan_info_deinit(cl_hw);
+ cl_wrs_api_close(cl_hw);
+ cl_dfs_close(cl_hw);
+ cl_twt_close(cl_hw);
+ cl_tx_inject_close(cl_hw);
+ cl_dbgfs_unregister(cl_hw);
+ cl_main_off(cl_hw);
+ /* These 2 must be called after cl_tx_off() (which is called from cl_main_off) */
+ cl_tx_amsdu_txhdr_deinit(cl_hw);
+ cl_sw_txhdr_deinit(cl_hw);
+ cl_stats_deinit(cl_hw);
+ cl_main_free(cl_hw);
+ cl_fw_file_release(cl_hw);
+ cl_vendor_timer_close(cl_hw);
+#ifdef CONFIG_CL_PCIE
+ cl_ipc_deinit(cl_hw);
+#endif
+ cl_hw_deinit(cl_hw, cl_hw->tcv_idx);
+}
+
+void cl_main_deinit(struct cl_chip *chip)
+{
+ struct cl_hw *cl_hw_tcv0 = chip->cl_hw_tcv0;
+ struct cl_hw *cl_hw_tcv1 = chip->cl_hw_tcv1;
+
+ if (cl_chip_is_tcv1_enabled(chip) && cl_hw_tcv1)
+ _cl_main_deinit(cl_hw_tcv1);
+
+ if (cl_chip_is_tcv0_enabled(chip) && cl_hw_tcv0)
+ _cl_main_deinit(cl_hw_tcv0);
+
+ if (cl_hw_tcv1) {
+ cl_phy_off(cl_hw_tcv1);
+ cl_free_hw(cl_hw_tcv1);
+ }
+
+ if (cl_hw_tcv0) {
+ cl_phy_off(cl_hw_tcv0);
+ cl_free_hw(cl_hw_tcv0);
+ }
+}
+
+struct cl_controller_reg all_controller_reg = {
+ .breset = XMAC_BRESET,
+ .debug_enable = XMAC_DEBUG_ENABLE,
+ .dreset = XMAC_DRESET,
+ .ocd_halt_on_reset = XMAC_OCD_HALT_ON_RESET,
+ .run_stall = XMAC_RUN_STALL
+};
+
+void cl_main_reset(struct cl_chip *chip, struct cl_controller_reg *controller_reg)
+{
+ /* Release TRST & BReset to enable JTAG connection to FPGA A */
+ u32 regval;
+
+ /* 1. return to reset value */
+ regval = macsys_gcu_xt_control_get(chip);
+ regval |= controller_reg->ocd_halt_on_reset;
+ regval &= ~(controller_reg->dreset | controller_reg->run_stall | controller_reg->breset);
+ macsys_gcu_xt_control_set(chip, regval);
+
+ regval = macsys_gcu_xt_control_get(chip);
+ regval |= controller_reg->dreset;
+ macsys_gcu_xt_control_set(chip, regval);
+
+ /* 2. stall xtensa & release ocd */
+ regval = macsys_gcu_xt_control_get(chip);
+ regval |= controller_reg->run_stall;
+ regval &= ~controller_reg->ocd_halt_on_reset;
+ macsys_gcu_xt_control_set(chip, regval);
+
+ /* 3. breset release & debug enable */
+ regval = macsys_gcu_xt_control_get(chip);
+ regval |= (controller_reg->debug_enable | controller_reg->breset);
+ macsys_gcu_xt_control_set(chip, regval);
+
+ msleep(100);
+}
+
+int cl_main_on(struct cl_hw *cl_hw)
+{
+ struct cl_chip *chip = cl_hw->chip;
+ int ret;
+ u32 regval;
+
+ cl_hw->fw_active = false;
+
+ cl_txq_init(cl_hw);
+
+ cl_hw_assert_info_init(cl_hw);
+
+ if (cl_recovery_in_progress(cl_hw))
+ cl_main_reset(chip, &cl_hw->controller_reg);
+
+ ret = cl_fw_file_load(cl_hw);
+ if (ret) {
+ cl_dbg_err(cl_hw, "cl_fw_file_load failed %d\n", ret);
+ return ret;
+ }
+
+ /* Clear CL_DEV_FW_ERROR after firmware loaded */
+ clear_bit(CL_DEV_FW_ERROR, &cl_hw->drv_flags);
+
+#ifdef CONFIG_CL_PCIE
+ if (cl_recovery_in_progress(cl_hw))
+ cl_ipc_recovery(cl_hw);
+#endif
+
+ regval = macsys_gcu_xt_control_get(chip);
+
+ /* Set fw to run */
+ if (cl_hw->fw_active)
+ regval &= ~cl_hw->controller_reg.run_stall;
+
+#ifdef CONFIG_CL_PCIE
+ /* Ack all possibly pending IRQs */
+ ipc_xmac_2_host_ack_set(chip, cl_hw->ipc_e2a_irq.all);
+#endif
+
+ macsys_gcu_xt_control_set(chip, regval);
+
+#ifdef CONFIG_CL_PCIE
+ cl_irq_enable(cl_hw, cl_hw->ipc_e2a_irq.all);
+#endif
+
+ /*
+ * cl_irq_status_sync will set CL_DEV_FW_SYNC when fw raises IPC_IRQ_E2A_SYNC
+ * (indicate its ready to accept interrupts)
+ */
+ ret = wait_event_interruptible_timeout(cl_hw->fw_sync_wq,
+ test_and_clear_bit(CL_DEV_FW_SYNC,
+ &cl_hw->drv_flags),
+ msecs_to_jiffies(5000));
+
+ if (ret == 0) {
+ pr_err("[%s]: FW synchronization timeout.\n", __func__);
+ cl_hw_assert_check(cl_hw);
+ ret = -ETIMEDOUT;
+ goto out_free_cached_fw;
+ } else if (ret == -ERESTARTSYS) {
+ goto out_free_cached_fw;
+ }
+
+ return 0;
+
+out_free_cached_fw:
+ cl_fw_file_release(cl_hw);
+ return ret;
+}
+
+static int __cl_main_init(struct cl_hw *cl_hw)
+{
+ int ret = 0;
+
+ set_bit(CL_DEV_INIT, &cl_hw->drv_flags);
+
+ /* By default, set FEM mode to operational mode. */
+ cl_hw->fem_system_mode = FEM_MODE_OPERETIONAL;
+
+ cl_vif_init(cl_hw);
+
+ cl_drv_workqueue_create(cl_hw);
+
+ init_waitqueue_head(&cl_hw->wait_queue);
+ init_waitqueue_head(&cl_hw->fw_sync_wq);
+ init_waitqueue_head(&cl_hw->radio_wait_queue);
+
+ mutex_init(&cl_hw->dbginfo.mutex);
+ mutex_init(&cl_hw->msg_tx_mutex);
+ mutex_init(&cl_hw->set_channel_mutex);
+
+ spin_lock_init(&cl_hw->tx_lock_agg);
+ spin_lock_init(&cl_hw->tx_lock_cfm_agg);
+ spin_lock_init(&cl_hw->tx_lock_single);
+ spin_lock_init(&cl_hw->tx_lock_bcmc);
+
+#ifdef CONFIG_CL_PCIE
+ ret = cl_ipc_init(cl_hw);
+ if (ret) {
+ cl_dbg_err(cl_hw, "cl_ipc_init failed %d\n", ret);
+ return ret;
+ }
+#endif
+ ret = cl_main_on(cl_hw);
+ if (ret) {
+ cl_dbg_err(cl_hw, "cl_main_on failed %d\n", ret);
+#ifdef CONFIG_CL_PCIE
+ cl_ipc_deinit(cl_hw);
+#endif
+ return ret;
+ }
+
+ ret = cl_main_alloc(cl_hw);
+ if (ret)
+ goto out_free;
+
+ /* Reset firmware */
+ ret = cl_msg_tx_reset(cl_hw);
+ if (ret)
+ goto out_free;
+
+ cl_calib_power_read(cl_hw);
+ cl_dbgfs_register(cl_hw, "cl");
+ cl_sta_init(cl_hw);
+ cl_sw_txhdr_init(cl_hw);
+ cl_tx_amsdu_txhdr_init(cl_hw);
+ cl_tx_init(cl_hw);
+ cl_rx_init(cl_hw);
+ cl_prot_mode_init(cl_hw);
+ cl_radar_init(cl_hw);
+ cl_sounding_init(cl_hw);
+ cl_vlan_dscp_init(cl_hw);
+ cl_traffic_init(cl_hw);
+ cl_rsrc_mgmt_init(cl_hw);
+ cl_vns_init(cl_hw);
+ cl_maintenance_init(cl_hw);
+ cl_rssi_assoc_init(cl_hw);
+ cl_agg_cfm_init(cl_hw);
+ cl_single_cfm_init(cl_hw);
+ cl_bcmc_cfm_init(cl_hw);
+ cl_dyn_mcast_rate_init(cl_hw);
+ cl_dyn_bcast_rate_init(cl_hw);
+ cl_wrs_api_init(cl_hw);
+ cl_dfs_init(cl_hw);
+ cl_tx_inject_init(cl_hw);
+ cl_noise_init(cl_hw);
+ cl_twt_init(cl_hw);
+ cl_fw_dbg_trigger_based_init(cl_hw);
+ cl_stats_init(cl_hw);
+ cl_vendor_timer_init(cl_hw);
+
+ return 0;
+
+out_free:
+ cl_main_free(cl_hw);
+
+ return ret;
+}
+
+static int _cl_main_init(struct cl_chip *chip, struct cl_hw *cl_hw)
+{
+ int ret = 0;
+
+ if (cl_chip_is_tcv_enabled(chip, cl_hw->tcv_idx)) {
+ ret = __cl_main_init(cl_hw);
+ if (ret) {
+ cl_dbg_chip_err(chip, "TCV%u failed (%d)\n", cl_hw->tcv_idx, ret);
+ return ret;
+ }
+ } else {
+ ieee80211_unregister_hw(cl_hw->hw);
+ }
+
+ return ret;
+}
+
+int cl_main_init(struct cl_chip *chip, const struct cl_driver_ops *drv_ops)
+{
+ int ret = 0;
+
+ /* All cores needs to be reset first (once per chip) */
+ cl_main_reset(chip, &all_controller_reg);
+
+ ret = cl_prepare_hw(chip, TCV0, drv_ops);
+ if (ret) {
+ cl_dbg_chip_err(chip, "cl_prepare_hw for TCV0 failed %d\n", ret);
+ return ret;
+ }
+
+ ret = cl_prepare_hw(chip, TCV1, drv_ops);
+ if (ret) {
+ cl_dbg_chip_err(chip, "cl_prepare_hw for TCV1 failed %d\n", ret);
+ cl_free_hw(chip->cl_hw_tcv0);
+ return ret;
+ }
+
+ ret = cl_rf_boot(chip);
+ if (ret) {
+ cl_dbg_chip_err(chip, "cl_rf_boot failed %d\n", ret);
+ return ret;
+ }
+
+ ret = cl_dsp_load_regular(chip);
+ if (ret) {
+ cl_dbg_chip_err(chip, "cl_dsp_load_regular failed %d\n", ret);
+ return ret;
+ }
+
+ ret = _cl_main_init(chip, chip->cl_hw_tcv0);
+ if (ret) {
+ cl_free_chip(chip);
+ return ret;
+ }
+
+ ret = _cl_main_init(chip, chip->cl_hw_tcv1);
+ if (ret) {
+ _cl_main_deinit(chip->cl_hw_tcv0);
+ cl_free_chip(chip);
+ return ret;
+ }
+
+ return ret;
+}
--
2.30.0

________________________________
The information transmitted is intended only for the person or entity to which it is addressed and may contain confidential and/or privileged material. Any retransmission, dissemination, copying or other use of, or taking of any action in reliance upon this information is prohibited. If you received this in error, please contact the sender and delete the material from any computer. Nothing contained herein shall be deemed as a representation, warranty or a commitment by Celeno. No warranties are expressed or implied, including, but not limited to, any implied warranties of non-infringement, merchantability and fitness for a particular purpose.
________________________________

2021-06-17 16:26:44

by viktor.barna

[permalink] [raw]
Subject: [RFC v1 075/256] cl8k: add env_det.c

From: Viktor Barna <[email protected]>

(Part of the split. Please, take a look at the cover letter for more
details).

Signed-off-by: Viktor Barna <[email protected]>
---
drivers/net/wireless/celeno/cl8k/env_det.c | 32 ++++++++++++++++++++++
1 file changed, 32 insertions(+)
create mode 100644 drivers/net/wireless/celeno/cl8k/env_det.c

diff --git a/drivers/net/wireless/celeno/cl8k/env_det.c b/drivers/net/wireless/celeno/cl8k/env_det.c
new file mode 100644
index 000000000000..fcd2de02018b
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/env_det.c
@@ -0,0 +1,32 @@
+// SPDX-License-Identifier: MIT
+/* Copyright(c) 2019-2021, Celeno Communications Ltd. */
+
+#include "env_det.h"
+#include "hw.h"
+
+void cl_env_det_set_type(struct cl_hw *cl_hw, enum cl_env_type type)
+{
+ cl_dbg_info(cl_hw, "Changing env state from:%u to %u\n",
+ cl_hw->env_db.type, type);
+ cl_hw->env_db.type = type;
+}
+
+bool cl_env_det_is_clean(struct cl_hw *cl_hw)
+{
+ return cl_hw->env_db.type == CL_ENV_TYPE_CLEAN;
+}
+
+bool cl_env_det_is_average(struct cl_hw *cl_hw)
+{
+ return cl_hw->env_db.type == CL_ENV_TYPE_AVERAGE;
+}
+
+bool cl_env_det_is_noisy(struct cl_hw *cl_hw)
+{
+ return cl_hw->env_db.type == CL_ENV_TYPE_NOISY;
+}
+
+bool cl_env_det_is_very_noisy(struct cl_hw *cl_hw)
+{
+ return cl_hw->env_db.type == CL_ENV_TYPE_VERY_NOISY;
+}
--
2.30.0

________________________________
The information transmitted is intended only for the person or entity to which it is addressed and may contain confidential and/or privileged material. Any retransmission, dissemination, copying or other use of, or taking of any action in reliance upon this information is prohibited. If you received this in error, please contact the sender and delete the material from any computer. Nothing contained herein shall be deemed as a representation, warranty or a commitment by Celeno. No warranties are expressed or implied, including, but not limited to, any implied warranties of non-infringement, merchantability and fitness for a particular purpose.
________________________________

2021-06-17 16:26:48

by viktor.barna

[permalink] [raw]
Subject: [RFC v1 044/256] cl8k: add chip_config.c

From: Viktor Barna <[email protected]>

(Part of the split. Please, take a look at the cover letter for more
details).

Signed-off-by: Viktor Barna <[email protected]>
---
.../net/wireless/celeno/cl8k/chip_config.c | 290 ++++++++++++++++++
1 file changed, 290 insertions(+)
create mode 100644 drivers/net/wireless/celeno/cl8k/chip_config.c

diff --git a/drivers/net/wireless/celeno/cl8k/chip_config.c b/drivers/net/wireless/celeno/cl8k/chip_config.c
new file mode 100644
index 000000000000..c6d60ff685d5
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/chip_config.c
@@ -0,0 +1,290 @@
+// SPDX-License-Identifier: MIT
+/* Copyright(c) 2019-2021, Celeno Communications Ltd. */
+
+#include "chip_config.h"
+#include "chip.h"
+#include "utils/file.h"
+#include "config.h"
+
+#define MAX_FIRST_MASK_BIT ((ETH_ALEN * 8) - 1)
+
+static struct cl_chip_conf chip_conf = {
+ .ce_tcv_enabled = {
+ [TCV0] = false,
+ [TCV1] = false
+ },
+ .ce_lmac = "lmacfw.bin",
+ .ce_smac = "smacfw.bin",
+ .ce_umac = "no_load",
+ .ce_irq_smp_affinity = -1,
+ .ce_eeprom_mode = E2P_MODE_BIN,
+ .ce_production_mode = false,
+ .ci_pci_msi_enable = true,
+ .ci_dma_lli_max_chan = {
+ [TCV0] = 6,
+ [TCV1] = 3
+ },
+ .ce_country_code = "EU",
+ .ce_ela_mode = "default",
+ .ci_phy_dev = PHY_DEV_OLYMPUS,
+ .ce_debug_level = DBG_LVL_ERROR,
+ .ce_host_pci_gen_ver = 3,
+ .ce_temp_comp_en = false,
+ .ce_temp_protect_en = TEMP_PROTECT_OFF,
+ .ce_temp_protect_delta = 0,
+ .ce_temp_protect_th_max = 110,
+ .ce_temp_protect_th_min = 100,
+ .ce_temp_protect_tx_period_ms = 50,
+ .ce_temp_protect_radio_off_th = 115,
+ .ce_phys_mac_addr = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+ .ce_lam_enable = true,
+ .ce_first_mask_bit = 0,
+ .ci_no_capture_noise_sleep = true,
+ .ci_dcoc_mv_thr = {
+ [CHNL_BW_20] = 150,
+ [CHNL_BW_40] = 100,
+ [CHNL_BW_80] = 100,
+ [CHNL_BW_160] = 100
+ },
+ .ci_lolc_db_thr = -40,
+ .ci_iq_db_thr = -46,
+ .ci_rx_resched_tasklet = false,
+ .ci_rx_skb_max = 10000,
+ .ce_calib_scan_en = false,
+};
+
+static int update_config(struct cl_chip *chip, char *name, char *value)
+{
+ struct cl_chip_conf *conf = chip->conf;
+
+ READ_BOOL_ARR(ce_tcv_enabled, TCV_MAX);
+ READ_STR(ce_lmac);
+ READ_STR(ce_smac);
+ READ_STR(ce_umac);
+ READ_S32(ce_irq_smp_affinity);
+ READ_U8(ce_eeprom_mode);
+ READ_BOOL(ce_production_mode);
+ READ_BOOL(ci_pci_msi_enable);
+ READ_U8_ARR(ci_dma_lli_max_chan, TCV_MAX);
+ READ_STR(ce_country_code);
+ READ_STR(ce_ela_mode);
+ READ_U8(ci_phy_dev);
+ READ_S8(ce_debug_level);
+ READ_U8(ce_host_pci_gen_ver);
+ READ_BOOL(ce_temp_comp_en);
+ READ_U8(ce_temp_protect_en);
+ READ_S8(ce_temp_protect_delta);
+ READ_S16(ce_temp_protect_th_max);
+ READ_S16(ce_temp_protect_th_min);
+ READ_U16(ce_temp_protect_tx_period_ms);
+ READ_S16(ce_temp_protect_radio_off_th);
+ READ_MAC(ce_phys_mac_addr);
+ READ_BOOL(ce_lam_enable);
+ READ_U8(ce_first_mask_bit);
+ READ_BOOL(ci_no_capture_noise_sleep);
+ READ_U8_ARR(ci_dcoc_mv_thr, CHNL_BW_MAX);
+ READ_S8(ci_lolc_db_thr);
+ READ_S8(ci_iq_db_thr);
+ READ_BOOL(ci_rx_resched_tasklet);
+ READ_U32(ci_rx_skb_max);
+ READ_BOOL(ce_calib_scan_en);
+
+ if (!cl_config_is_non_driver_param(name)) {
+ CL_DBG_ERROR_CHIP(chip, "No matching conf for nvram parameter %s\n", name);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int post_configuration(struct cl_chip *chip)
+{
+ struct cl_chip_conf *conf = chip->conf;
+
+ if (!conf->