All of lore.kernel.org
 help / color / mirror / Atom feed
* [RFC v1 000/256] wireless: cl8k driver for Celeno IEEE 802.11ax devices
@ 2021-06-17 15:58 viktor.barna
  2021-06-17 15:58 ` [RFC v1 001/256] celeno: add Kconfig viktor.barna
                   ` (257 more replies)
  0 siblings, 258 replies; 262+ messages in thread
From: viktor.barna @ 2021-06-17 15:58 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Oleksandr Savchenko, Shay Bar, Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

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 <aviad.brikman@celeno.com>
Signed-off-by: Eliav Farber <eliav.farber@gmail.com>
Signed-off-by: Oleksandr Savchenko <oleksandr.savchenko@celeno.com>
Signed-off-by: Shay Bar <shay.bar@celeno.com>
Signed-off-by: Viktor Barna <viktor.barna@celeno.com>

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.
________________________________


^ permalink raw reply	[flat|nested] 262+ messages in thread

* [RFC v1 001/256] celeno: add Kconfig
  2021-06-17 15:58 [RFC v1 000/256] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
@ 2021-06-17 15:58 ` viktor.barna
  2021-06-17 15:58 ` [RFC v1 002/256] celeno: add Makefile viktor.barna
                   ` (256 subsequent siblings)
  257 siblings, 0 replies; 262+ messages in thread
From: viktor.barna @ 2021-06-17 15:58 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Oleksandr Savchenko, Shay Bar, Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

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

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 drivers/net/wireless/celeno/Kconfig | 17 +++++++++++++++++
 1 file changed, 17 insertions(+)
 create mode 100644 drivers/net/wireless/celeno/Kconfig

diff --git a/drivers/net/wireless/celeno/Kconfig b/drivers/net/wireless/celeno/Kconfig
new file mode 100644
index 000000000000..4779c1ba1644
--- /dev/null
+++ b/drivers/net/wireless/celeno/Kconfig
@@ -0,0 +1,17 @@
+# SPDX-License-Identifier: MIT
+config WLAN_VENDOR_CELENO
+       bool "Celeno devices"
+       default y
+       help
+         If you have a wireless card belonging to this class, say Y.
+
+         Note that the answer to this question doesn't directly affect the
+         kernel: saying N will just cause the configurator to skip all the
+         questions about these cards. If you say Y, you will be asked for
+         your specific card in the following questions.
+
+if WLAN_VENDOR_CELENO
+
+source "drivers/net/wireless/celeno/cl8k/Kconfig"
+
+endif # WLAN_VENDOR_CELENO
--
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.
________________________________


^ permalink raw reply related	[flat|nested] 262+ messages in thread

* [RFC v1 002/256] celeno: add Makefile
  2021-06-17 15:58 [RFC v1 000/256] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
  2021-06-17 15:58 ` [RFC v1 001/256] celeno: add Kconfig viktor.barna
@ 2021-06-17 15:58 ` viktor.barna
  2021-06-17 15:58 ` [RFC v1 003/256] cl8k: add Kconfig viktor.barna
                   ` (255 subsequent siblings)
  257 siblings, 0 replies; 262+ messages in thread
From: viktor.barna @ 2021-06-17 15:58 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Oleksandr Savchenko, Shay Bar, Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

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

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 drivers/net/wireless/celeno/Makefile | 2 ++
 1 file changed, 2 insertions(+)
 create mode 100644 drivers/net/wireless/celeno/Makefile

diff --git a/drivers/net/wireless/celeno/Makefile b/drivers/net/wireless/celeno/Makefile
new file mode 100644
index 000000000000..b1724b81d10c
--- /dev/null
+++ b/drivers/net/wireless/celeno/Makefile
@@ -0,0 +1,2 @@
+# SPDX-License-Identifier: MIT
+obj-$(CONFIG_CL8K) += cl8k/
--
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.
________________________________


^ permalink raw reply related	[flat|nested] 262+ messages in thread

* [RFC v1 003/256] cl8k: add Kconfig
  2021-06-17 15:58 [RFC v1 000/256] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
  2021-06-17 15:58 ` [RFC v1 001/256] celeno: add Kconfig viktor.barna
  2021-06-17 15:58 ` [RFC v1 002/256] celeno: add Makefile viktor.barna
@ 2021-06-17 15:58 ` viktor.barna
  2021-06-17 15:58 ` [RFC v1 004/256] cl8k: add Makefile viktor.barna
                   ` (254 subsequent siblings)
  257 siblings, 0 replies; 262+ messages in thread
From: viktor.barna @ 2021-06-17 15:58 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Oleksandr Savchenko, Shay Bar, Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

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

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 drivers/net/wireless/celeno/cl8k/Kconfig | 16 ++++++++++++++++
 1 file changed, 16 insertions(+)
 create mode 100644 drivers/net/wireless/celeno/cl8k/Kconfig

diff --git a/drivers/net/wireless/celeno/cl8k/Kconfig b/drivers/net/wireless/celeno/cl8k/Kconfig
new file mode 100644
index 000000000000..452c647320de
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/Kconfig
@@ -0,0 +1,16 @@
+# SPDX-License-Identifier: MIT
+config CL8K
+       tristate "Celeno CL8K WLAN support"
+       depends on m
+       depends on MAC80211
+       select WANT_DEV_COREDUMP
+       help
+         This option enables support for Celeno CL8K WLAN.
+         Select M (recommended), if you have a wireless module.
+
+config CL8K_PCI
+       bool "PCI devices support"
+       depends on CL8K
+       default y
+       help
+         Say Y if you revision with PCIe-based interface.
--
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.
________________________________


^ permalink raw reply related	[flat|nested] 262+ messages in thread

* [RFC v1 004/256] cl8k: add Makefile
  2021-06-17 15:58 [RFC v1 000/256] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (2 preceding siblings ...)
  2021-06-17 15:58 ` [RFC v1 003/256] cl8k: add Kconfig viktor.barna
@ 2021-06-17 15:58 ` viktor.barna
  2021-06-17 15:58 ` [RFC v1 005/256] cl8k: add afe.c viktor.barna
                   ` (253 subsequent siblings)
  257 siblings, 0 replies; 262+ messages in thread
From: viktor.barna @ 2021-06-17 15:58 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Oleksandr Savchenko, Shay Bar, Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

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

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 drivers/net/wireless/celeno/cl8k/Makefile | 149 ++++++++++++++++++++++
 1 file changed, 149 insertions(+)
 create mode 100644 drivers/net/wireless/celeno/cl8k/Makefile

diff --git a/drivers/net/wireless/celeno/cl8k/Makefile b/drivers/net/wireless/celeno/cl8k/Makefile
new file mode 100644
index 000000000000..188da2ea2dfd
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/Makefile
@@ -0,0 +1,149 @@
+# SPDX-License-Identifier: MIT
+obj-$(CONFIG_CL8K) += cl8k.o
+
+# Stop these C90 warnings. We use C99.
+ccflags-y += -Wno-declaration-after-statement -g -Werror
+
+IFACE_PREFIX=wlan
+
+ccflags-y += -D__CHECK_ENDIAN__ -DDEBUG -DCL_IFACE_PREFIX=\"$(IFACE_PREFIX)\"
+cl-objs += \
+       wrs/wrs.o \
+       wrs/wrs_api.o \
+       wrs/wrs_cli.o \
+       wrs/wrs_tables.o \
+       wrs/wrs_rssi.o \
+       wrs/wrs_sta.o \
+       wrs/wrs_ap.o \
+       wrs/wrs_stats.o \
+       phy/phy_common_lut.o\
+       phy/phy_olympus_lut.o\
+       phy/phy_athos_lut.o\
+       reg/reg_cli.o \
+       key.o \
+       sta.o \
+       hw.o \
+       chip.o \
+       fw/msg_tx.o \
+       fw/fw_msg.o \
+       utils/utils.o \
+       channel.o \
+       utils/string.o \
+       rx/rx.o \
+       rx/rx_amsdu.o \
+       tx/tx.o \
+       tx/tx_amsdu.o \
+       vendor_cmd.o \
+       main.o \
+       mac_addr.o \
+       ops.o \
+       ampdu.o \
+       dfs/dfs.o \
+       tx/tx_inject.o \
+       enhanced_tim.o \
+       e2p.o \
+       chan_info.o \
+       edca.o \
+       calib.o \
+       utils/timer.o \
+       tx/agg_cfm.o \
+       tx/single_cfm.o \
+       tx/bcmc_cfm.o \
+       tx/tx_queue.o \
+       stats.o \
+       cca.o \
+       noise.o \
+       tx/baw.o \
+       power.o \
+       power_cli.o \
+       power_table.o \
+       motion_sense.o \
+       dfs/radar.o \
+       bf.o \
+       sounding.o \
+       dbgfile.o \
+       temperature.o \
+       recovery.o \
+       phy/phy.o \
+       prot_mode.o \
+       rate_ctrl.o \
+       radio.o \
+       config.o \
+       tcv_config.o \
+       chip_config.o \
+       rsrc_mgmt.o \
+       traffic.o \
+       rssi.o \
+       fw/fw_file.o \
+       utils/file.o \
+       rx/rx_filter.o \
+       vns.o \
+       env_det.o \
+       maintenance.o \
+       ela.o \
+       fw/fw_dbg.o \
+       ext/dyn_mcast_rate.o \
+       ext/dyn_bcast_rate.o \
+       vif.o \
+       mib.o \
+       band.o \
+       tx/agg_tx_report.o \
+       hw_assert.o \
+       dsp.o \
+       rf_boot.o \
+       ate.o \
+       afe.o \
+       tx/sw_txhdr.o \
+       fem.o \
+       chandef.o \
+       version.o \
+       cap.o \
+       agc_params.o \
+       utils/ip.o \
+       ext/vlan_dscp.o \
+       netlink.o \
+       twt_frame.o \
+       twt.o \
+       twt_cli.o \
+       cecli.o \
+       mac80211.o \
+       omi.o \
+       data_rates.o \
+       rx/rx_reorder.o
+
+ccflags-y += -I$(src) -I$(srctree)/net/wireless -I$(srctree)/net/mac80211/
+
+ifdef CONFIG_DEBUG_FS
+       CONFIG_CL_DEBUGFS=y
+endif
+
+ifdef CONFIG_CL_DEBUGFS
+       ccflags-y += -DCONFIG_CL_DEBUGFS
+       cl-objs += coredump.o
+       cl-objs += debugfs.o
+endif
+
+ifeq ($(CONFIG_CL8K_TRACE),y)
+# Without this flag, the trace.h will be searched for in include/trace/events,
+# which is not what we desire.
+       CFLAGS_trace.o := -I$(src) -Wno-unused-variable -Wno-uninitialized
+       cl-objs += trace.o
+       ccflags-y += -DTRACE_SUPPORT
+endif
+
+ifeq ($(CONFIG_CL8K_PCI),y)
+ccflags-y += -DCONFIG_CL_PCIE
+cl-objs += \
+       bus/pci/pci.o \
+       bus/pci/rx_pci.o \
+       bus/pci/tx_pci.o \
+       bus/pci/msg_pci.o \
+       fw/msg_cfm.o \
+       fw/msg_rx.o \
+       bus/pci/ipc.o \
+       bus/pci/irq.o
+endif
+
+ifneq ($(CONFIG_CL8K),)
+cl8k-y += $(cl-objs)
+endif
--
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.
________________________________


^ permalink raw reply related	[flat|nested] 262+ messages in thread

* [RFC v1 005/256] cl8k: add afe.c
  2021-06-17 15:58 [RFC v1 000/256] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (3 preceding siblings ...)
  2021-06-17 15:58 ` [RFC v1 004/256] cl8k: add Makefile viktor.barna
@ 2021-06-17 15:58 ` viktor.barna
  2021-06-17 15:58 ` [RFC v1 006/256] cl8k: add afe.h viktor.barna
                   ` (252 subsequent siblings)
  257 siblings, 0 replies; 262+ messages in thread
From: viktor.barna @ 2021-06-17 15:58 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Oleksandr Savchenko, Shay Bar, Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

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

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 drivers/net/wireless/celeno/cl8k/afe.c | 737 +++++++++++++++++++++++++
 1 file changed, 737 insertions(+)
 create mode 100644 drivers/net/wireless/celeno/cl8k/afe.c

diff --git a/drivers/net/wireless/celeno/cl8k/afe.c b/drivers/net/wireless/celeno/cl8k/afe.c
new file mode 100644
index 000000000000..ce846396ac0f
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/afe.c
@@ -0,0 +1,737 @@
+// SPDX-License-Identifier: MIT
+/* Copyright(c) 2019-2021, Celeno Communications Ltd. */
+
+#include "afe.h"
+#include "reg/reg_ricu.h"
+#include "reg/reg_io_ctrl.h"
+#include "fem.h"
+
+/*
+ * The configuration below supports:
+ * CL8080: 4 + 4 (chains 0-3 @ TCV0 and chains 0-3 @ TCV1)
+ * CL8060: 4 + 2 (chains 0-3 @ TCV0 and chains 2-3 @ TCV1)
+ * CL8064: 4 + 2 (chains 0-3 @ TCV0 and chains 2-3 @ TCV1)
+ * CL8040: 2 + 2 (chains 0-1 @ TCV0 and chains 2-3 @ TCV1)
+ * CL8046: 4 + 0 (chains 0-3 @ TCV0)
+ */
+
+#define RICU_AFE_CTL_9_EN_DAC_REF_CL808X \
+       (RICU_AFE_CTL_9_EN_DAC_REF_0_BIT | \
+        RICU_AFE_CTL_9_EN_DAC_REF_1_BIT | \
+        RICU_AFE_CTL_9_EN_DAC_REF_2_BIT | \
+        RICU_AFE_CTL_9_EN_DAC_REF_3_BIT | \
+        RICU_AFE_CTL_9_EN_DAC_REF_4_BIT | \
+        RICU_AFE_CTL_9_EN_DAC_REF_5_BIT | \
+        RICU_AFE_CTL_9_EN_DAC_REF_6_BIT | \
+        RICU_AFE_CTL_9_EN_DAC_REF_7_BIT)
+
+#define RICU_AFE_CTL_9_EN_DAC_REF_CL806X \
+       (RICU_AFE_CTL_9_EN_DAC_REF_0_BIT | \
+        RICU_AFE_CTL_9_EN_DAC_REF_1_BIT | \
+        RICU_AFE_CTL_9_EN_DAC_REF_2_BIT | \
+        RICU_AFE_CTL_9_EN_DAC_REF_3_BIT | \
+        RICU_AFE_CTL_9_EN_DAC_REF_4_BIT | \
+        RICU_AFE_CTL_9_EN_DAC_REF_5_BIT)
+
+#define RICU_AFE_CTL_9_EN_DAC_REF_CL8046 \
+       (RICU_AFE_CTL_9_EN_DAC_REF_0_BIT | \
+        RICU_AFE_CTL_9_EN_DAC_REF_1_BIT | \
+        RICU_AFE_CTL_9_EN_DAC_REF_2_BIT | \
+        RICU_AFE_CTL_9_EN_DAC_REF_3_BIT)
+
+#define RICU_AFE_CTL_9_EN_DAC_REF_CL8040 \
+       (RICU_AFE_CTL_9_EN_DAC_REF_0_BIT | \
+        RICU_AFE_CTL_9_EN_DAC_REF_1_BIT | \
+        RICU_AFE_CTL_9_EN_DAC_REF_4_BIT | \
+        RICU_AFE_CTL_9_EN_DAC_REF_5_BIT)
+
+#define RICU_AFE_CTL_8_EN_BGR_CL808X \
+       (RICU_AFE_CTL_8_EN_BGR_0_BIT | \
+        RICU_AFE_CTL_8_EN_BGR_1_BIT | \
+        RICU_AFE_CTL_8_EN_BGR_2_BIT | \
+        RICU_AFE_CTL_8_EN_BGR_3_BIT | \
+        RICU_AFE_CTL_8_EN_BGR_4_BIT | \
+        RICU_AFE_CTL_8_EN_BGR_5_BIT | \
+        RICU_AFE_CTL_8_EN_BGR_6_BIT | \
+        RICU_AFE_CTL_8_EN_BGR_7_BIT)
+
+#define RICU_AFE_CTL_8_EN_BGR_CL806X \
+       (RICU_AFE_CTL_8_EN_BGR_0_BIT | \
+        RICU_AFE_CTL_8_EN_BGR_1_BIT | \
+        RICU_AFE_CTL_8_EN_BGR_2_BIT | \
+        RICU_AFE_CTL_8_EN_BGR_3_BIT | \
+        RICU_AFE_CTL_8_EN_BGR_4_BIT | \
+        RICU_AFE_CTL_8_EN_BGR_5_BIT)
+
+#define RICU_AFE_CTL_8_EN_BGR_CL8046 \
+       (RICU_AFE_CTL_8_EN_BGR_0_BIT | \
+        RICU_AFE_CTL_8_EN_BGR_1_BIT | \
+        RICU_AFE_CTL_8_EN_BGR_2_BIT | \
+        RICU_AFE_CTL_8_EN_BGR_3_BIT)
+
+#define RICU_AFE_CTL_8_EN_BGR_CL8040 \
+       (RICU_AFE_CTL_8_EN_BGR_0_BIT | \
+        RICU_AFE_CTL_8_EN_BGR_1_BIT | \
+        RICU_AFE_CTL_8_EN_BGR_4_BIT | \
+        RICU_AFE_CTL_8_EN_BGR_5_BIT)
+
+#define RICU_AFE_CTL_8_EN_REF_CL808X \
+       (RICU_AFE_CTL_8_EN_REF_0_BIT | \
+        RICU_AFE_CTL_8_EN_REF_1_BIT | \
+        RICU_AFE_CTL_8_EN_REF_2_BIT | \
+        RICU_AFE_CTL_8_EN_REF_3_BIT | \
+        RICU_AFE_CTL_8_EN_REF_4_BIT | \
+        RICU_AFE_CTL_8_EN_REF_5_BIT | \
+        RICU_AFE_CTL_8_EN_REF_6_BIT | \
+        RICU_AFE_CTL_8_EN_REF_7_BIT)
+
+#define RICU_AFE_CTL_8_EN_REF_CL806X \
+       (RICU_AFE_CTL_8_EN_REF_0_BIT | \
+        RICU_AFE_CTL_8_EN_REF_1_BIT | \
+        RICU_AFE_CTL_8_EN_REF_2_BIT | \
+        RICU_AFE_CTL_8_EN_REF_3_BIT | \
+        RICU_AFE_CTL_8_EN_REF_4_BIT | \
+        RICU_AFE_CTL_8_EN_REF_5_BIT)
+
+#define RICU_AFE_CTL_8_EN_REF_CL8046 \
+       (RICU_AFE_CTL_8_EN_REF_0_BIT | \
+        RICU_AFE_CTL_8_EN_REF_1_BIT | \
+        RICU_AFE_CTL_8_EN_REF_2_BIT | \
+        RICU_AFE_CTL_8_EN_REF_3_BIT)
+
+#define RICU_AFE_CTL_8_EN_REF_CL8040 \
+       (RICU_AFE_CTL_8_EN_REF_0_BIT | \
+        RICU_AFE_CTL_8_EN_REF_1_BIT | \
+        RICU_AFE_CTL_8_EN_REF_4_BIT | \
+        RICU_AFE_CTL_8_EN_REF_5_BIT)
+
+#define RICU_AFE_CTRL_37_PHY_0_DAC_CL808X \
+       (RICU_AFE_CTRL_37_PHY_0_EN_DAC_0_BIT | \
+        RICU_AFE_CTRL_37_PHY_0_EN_DAC_1_BIT | \
+        RICU_AFE_CTRL_37_PHY_0_EN_DAC_2_BIT | \
+        RICU_AFE_CTRL_37_PHY_0_EN_DAC_3_BIT | \
+        RICU_AFE_CTRL_37_PHY_0_EN_DAC_4_BIT | \
+        RICU_AFE_CTRL_37_PHY_0_EN_DAC_5_BIT)
+
+#define RICU_AFE_CTRL_37_PHY_0_DAC_CL806X \
+       (RICU_AFE_CTRL_37_PHY_0_EN_DAC_0_BIT | \
+        RICU_AFE_CTRL_37_PHY_0_EN_DAC_1_BIT | \
+        RICU_AFE_CTRL_37_PHY_0_EN_DAC_2_BIT | \
+        RICU_AFE_CTRL_37_PHY_0_EN_DAC_3_BIT)
+
+#define RICU_AFE_CTRL_37_PHY_0_DAC_CL8046 \
+       (RICU_AFE_CTRL_37_PHY_0_EN_DAC_0_BIT | \
+        RICU_AFE_CTRL_37_PHY_0_EN_DAC_1_BIT | \
+        RICU_AFE_CTRL_37_PHY_0_EN_DAC_2_BIT | \
+        RICU_AFE_CTRL_37_PHY_0_EN_DAC_3_BIT)
+
+#define RICU_AFE_CTRL_37_PHY_0_DAC_CL8040 \
+       (RICU_AFE_CTRL_37_PHY_0_EN_DAC_0_BIT | \
+        RICU_AFE_CTRL_37_PHY_0_EN_DAC_1_BIT)
+
+#define RICU_AFE_CTRL_37_PHY_1_DAC_CL808X \
+       (RICU_AFE_CTRL_37_PHY_1_EN_DAC_0_BIT | \
+        RICU_AFE_CTRL_37_PHY_1_EN_DAC_1_BIT | \
+        RICU_AFE_CTRL_37_PHY_1_EN_DAC_2_BIT | \
+        RICU_AFE_CTRL_37_PHY_1_EN_DAC_3_BIT | \
+        RICU_AFE_CTRL_37_PHY_1_EN_DAC_4_BIT | \
+        RICU_AFE_CTRL_37_PHY_1_EN_DAC_5_BIT)
+
+#define RICU_AFE_CTRL_37_PHY_1_DAC_CL806X \
+       (RICU_AFE_CTRL_37_PHY_1_EN_DAC_2_BIT | \
+        RICU_AFE_CTRL_37_PHY_1_EN_DAC_3_BIT)
+
+#define RICU_AFE_CTRL_37_PHY_1_DAC_CL804X \
+       (RICU_AFE_CTRL_37_PHY_1_EN_DAC_2_BIT | \
+        RICU_AFE_CTRL_37_PHY_1_EN_DAC_3_BIT)
+
+static void cl_afe_enable(struct cl_chip *chip)
+{
+       u32 regval;
+
+       /* Enable PLL LDO */
+       ricu_afe_ctl_1_en_pll_ldo_setf(chip, 1);
+
+       /* Enable DAC BGR & reference */
+       regval = ricu_afe_ctl_9_get(chip);
+       if (cl_chip_is_8ant(chip))
+               regval |= RICU_AFE_CTL_9_EN_DAC_REF_CL808X;
+       else if (cl_chip_is_6ant(chip))
+               regval |= RICU_AFE_CTL_9_EN_DAC_REF_CL806X;
+       else if (cl_chip_is_6g(chip))
+               regval |= RICU_AFE_CTL_9_EN_DAC_REF_CL8046;
+       else
+               regval |= RICU_AFE_CTL_9_EN_DAC_REF_CL8040;
+       ricu_afe_ctl_9_set(chip, regval);
+
+       /* Enable ADC BGR & Reference */
+       regval = ricu_afe_ctl_8_get(chip);
+       if (cl_chip_is_8ant(chip)) {
+               regval |= RICU_AFE_CTL_8_EN_BGR_CL808X;
+               regval |= RICU_AFE_CTL_8_EN_REF_CL808X;
+       } else if (cl_chip_is_6ant(chip)) {
+               regval |= RICU_AFE_CTL_8_EN_BGR_CL806X;
+               regval |= RICU_AFE_CTL_8_EN_REF_CL806X;
+       } else if (cl_chip_is_6g(chip)) {
+               regval |= RICU_AFE_CTL_8_EN_BGR_CL8046;
+               regval |= RICU_AFE_CTL_8_EN_REF_CL8046;
+       } else {
+               regval |= RICU_AFE_CTL_8_EN_BGR_CL8040;
+               regval |= RICU_AFE_CTL_8_EN_REF_CL8040;
+       }
+       ricu_afe_ctl_8_set(chip, regval);
+
+       /* Enable Embedded LDO */
+       regval = ricu_afe_ctrl_36_phy_0_get(chip);
+       regval |= (RICU_AFE_CTRL_36_PHY_0_ADC_ALWAYS_EN_LD_IR_BIT |
+                  RICU_AFE_CTRL_36_PHY_0_ADC_ALWAYS_EN_LD_AVDQ_BIT |
+                  RICU_AFE_CTRL_36_PHY_0_ADC_ALWAYS_EN_LD_AVDI_BIT);
+       ricu_afe_ctrl_36_phy_0_set(chip, regval);
+
+       regval = ricu_afe_ctrl_36_phy_1_get(chip);
+       regval |= (RICU_AFE_CTRL_36_PHY_1_ADC_ALWAYS_EN_LD_IR_BIT |
+                  RICU_AFE_CTRL_36_PHY_1_ADC_ALWAYS_EN_LD_AVDQ_BIT |
+                  RICU_AFE_CTRL_36_PHY_1_ADC_ALWAYS_EN_LD_AVDI_BIT);
+       ricu_afe_ctrl_36_phy_1_set(chip, regval);
+
+       /* Wait 2 us PLL LDO settling time */
+       udelay(2);
+
+       /* Enable the LC oscillator of the LCPLL */
+       ricu_afe_ctl_2_lock_con_rev_lc_setf(chip, 1);
+       /* Enable the LC PBIAS of the LCPLL */
+       ricu_afe_ctl_0_pbias_ctrl_en_lc_setf(chip, 1);
+
+       /* Wait 1 us */
+       udelay(1);
+
+       /* Power up control for LCPLL */
+       ricu_afe_ctl_1_resetb_lc_setf(chip, 1);
+
+       /* Wait 1 us */
+       udelay(1);
+
+       /* Enable DAC & ADC cores */
+       if (cl_chip_is_8ant(chip))
+               ricu_afe_ctrl_37_phy_0_set(chip, RICU_AFE_CTRL_37_PHY_0_DAC_CL808X);
+       else if (cl_chip_is_6ant(chip))
+               ricu_afe_ctrl_37_phy_0_set(chip, RICU_AFE_CTRL_37_PHY_0_DAC_CL806X);
+       else if (cl_chip_is_6g(chip))
+               ricu_afe_ctrl_37_phy_0_set(chip, RICU_AFE_CTRL_37_PHY_0_DAC_CL8046);
+       else
+               ricu_afe_ctrl_37_phy_0_set(chip, RICU_AFE_CTRL_37_PHY_0_DAC_CL8040);
+
+       if (cl_chip_is_8ant(chip))
+               ricu_afe_ctrl_37_phy_1_set(chip, RICU_AFE_CTRL_37_PHY_1_DAC_CL808X);
+       else if (cl_chip_is_6ant(chip))
+               ricu_afe_ctrl_37_phy_1_set(chip, RICU_AFE_CTRL_37_PHY_1_DAC_CL806X);
+       else
+               ricu_afe_ctrl_37_phy_1_set(chip, RICU_AFE_CTRL_37_PHY_1_DAC_CL804X);
+
+       /* Enable DAC & ADC cores */
+       regval = ricu_afe_ctrl_36_phy_0_get(chip);
+       regval |= (RICU_AFE_CTRL_36_PHY_0_ADC_ALWAYS_EN_ADCQ_BIT |
+                  RICU_AFE_CTRL_36_PHY_0_ADC_ALWAYS_EN_ADCI_BIT);
+       ricu_afe_ctrl_36_phy_0_set(chip, regval);
+
+       regval = ricu_afe_ctrl_36_phy_1_get(chip);
+       regval |= (RICU_AFE_CTRL_36_PHY_1_ADC_ALWAYS_EN_ADCQ_BIT |
+                  RICU_AFE_CTRL_36_PHY_1_ADC_ALWAYS_EN_ADCI_BIT);
+       ricu_afe_ctrl_36_phy_1_set(chip, regval);
+
+       /* Wait 2us */
+       udelay(2);
+
+       /* Enable Main & 2nd CDB clock generators */
+       ricu_afe_ctl_0_cdb_clk_resetb_setf(chip, 1);
+}
+
+static void cl_afe_disable(struct cl_chip *chip)
+{
+       u32 regval;
+
+       /* Power down control for LCPLL */
+       ricu_afe_ctl_1_resetb_lc_setf(chip, 0);
+       /* Disable PLL LDO */
+       ricu_afe_ctl_1_en_pll_ldo_setf(chip, 0);
+       /* Disable the LC oscillator of the LCPLL */
+       ricu_afe_ctl_2_lock_con_rev_lc_setf(chip, 0);
+       /* Disable the LC PBIAS of the LCPLL */
+       ricu_afe_ctl_0_pbias_ctrl_en_lc_setf(chip, 0);
+
+       /* Disable DAC BGR & reference */
+       regval = ricu_afe_ctl_9_get(chip);
+       if (cl_chip_is_8ant(chip))
+               regval &= ~RICU_AFE_CTL_9_EN_DAC_REF_CL808X;
+       else if (cl_chip_is_6ant(chip))
+               regval &= ~RICU_AFE_CTL_9_EN_DAC_REF_CL806X;
+       else if (cl_chip_is_6g(chip))
+               regval &= ~RICU_AFE_CTL_9_EN_DAC_REF_CL8046;
+       else
+               regval &= ~RICU_AFE_CTL_9_EN_DAC_REF_CL8040;
+       ricu_afe_ctl_9_set(chip, regval);
+
+       /* Disable ADC BGR & Reference */
+       regval = ricu_afe_ctl_8_get(chip);
+       if (cl_chip_is_8ant(chip)) {
+               regval &= ~RICU_AFE_CTL_8_EN_BGR_CL808X;
+               regval &= ~RICU_AFE_CTL_8_EN_REF_CL808X;
+       } else if (cl_chip_is_6ant(chip)) {
+               regval &= ~RICU_AFE_CTL_8_EN_BGR_CL806X;
+               regval &= ~RICU_AFE_CTL_8_EN_REF_CL806X;
+       } else if (cl_chip_is_6g(chip)) {
+               regval &= ~RICU_AFE_CTL_8_EN_BGR_CL8046;
+               regval &= ~RICU_AFE_CTL_8_EN_REF_CL8046;
+       } else {
+               regval &= ~RICU_AFE_CTL_8_EN_BGR_CL8040;
+               regval &= ~RICU_AFE_CTL_8_EN_REF_CL8040;
+       }
+       ricu_afe_ctl_8_set(chip, regval);
+
+       /* Disable Embedded LDO */
+       regval = ricu_afe_ctrl_36_phy_0_get(chip);
+       regval &= ~(RICU_AFE_CTRL_36_PHY_0_ADC_ALWAYS_EN_LD_IR_BIT |
+                   RICU_AFE_CTRL_36_PHY_0_ADC_ALWAYS_EN_LD_AVDQ_BIT |
+                   RICU_AFE_CTRL_36_PHY_0_ADC_ALWAYS_EN_LD_AVDI_BIT);
+       ricu_afe_ctrl_36_phy_0_set(chip, regval);
+
+       regval = ricu_afe_ctrl_36_phy_1_get(chip);
+       regval &= ~(RICU_AFE_CTRL_36_PHY_1_ADC_ALWAYS_EN_LD_IR_BIT |
+                   RICU_AFE_CTRL_36_PHY_1_ADC_ALWAYS_EN_LD_AVDQ_BIT |
+                   RICU_AFE_CTRL_36_PHY_1_ADC_ALWAYS_EN_LD_AVDI_BIT);
+       ricu_afe_ctrl_36_phy_1_set(chip, regval);
+
+       /* Disable DAC & ADC cores */
+       ricu_afe_ctrl_37_phy_0_set(chip, 0);
+       ricu_afe_ctrl_37_phy_1_set(chip, 0);
+
+       /* Disable DAC & ADC cores */
+       regval = ricu_afe_ctrl_36_phy_0_get(chip);
+       regval &= ~(RICU_AFE_CTRL_36_PHY_0_ADC_ALWAYS_EN_ADCQ_BIT |
+                   RICU_AFE_CTRL_36_PHY_0_ADC_ALWAYS_EN_ADCI_BIT);
+       ricu_afe_ctrl_36_phy_0_set(chip, regval);
+
+       regval = ricu_afe_ctrl_36_phy_1_get(chip);
+       regval &= ~(RICU_AFE_CTRL_36_PHY_1_ADC_ALWAYS_EN_ADCQ_BIT |
+                   RICU_AFE_CTRL_36_PHY_1_ADC_ALWAYS_EN_ADCI_BIT);
+       ricu_afe_ctrl_36_phy_1_set(chip, regval);
+
+       /* Disable Main & 2nd CDB clock generators */
+       ricu_afe_ctl_0_cdb_clk_resetb_setf(chip, 0);
+}
+
+static void cl_io_ctrl_config(struct cl_chip *chip)
+{
+       io_ctrl_fastwr_0_set(chip, 0x2338);
+       io_ctrl_fastwr_1_set(chip, 0x2338);
+       io_ctrl_fastwr_2_set(chip, 0x2338);
+       io_ctrl_fastwr_3_set(chip, 0x2338);
+       io_ctrl_fastwr_4_set(chip, 0x2338);
+       io_ctrl_fastwr_5_set(chip, 0x2338);
+       io_ctrl_fastwr_6_set(chip, 0x2338);
+       io_ctrl_fastwr_7_set(chip, 0x2338);
+       io_ctrl_fwr_en_1_set(chip, 0x338);
+       io_ctrl_spiclk_set(chip, 0x308);
+}
+
+static int cl_adc_sampling_cfg_tcv0(struct cl_chip *chip, u16 adc_sampling_clk)
+{
+       switch (adc_sampling_clk) {
+       case 40:
+               ricu_afe_ctrl_43_freq_sel_setf(chip, 0x0);
+               /* Configure ADC sampling for primary chains */
+               ricu_afe_ctl_25_pack(chip, 0x1, 0x3D, 0x3D);
+               ricu_afe_ctl_26_pack(chip, 0x1, 0x3D, 0x3D);
+               ricu_afe_ctl_27_pack(chip, 0x1, 0x3D, 0x3D);
+               ricu_afe_ctl_33_pack(chip, 0x1, 0x3D, 0x3D);
+               break;
+       case 80:
+               ricu_afe_ctrl_43_freq_sel_setf(chip, 0x1);
+               /* Configure ADC sampling for primary chains */
+               ricu_afe_ctl_25_pack(chip, 0x1, 0x3D, 0x3D);
+               ricu_afe_ctl_26_pack(chip, 0x1, 0x3D, 0x3D);
+               ricu_afe_ctl_27_pack(chip, 0x1, 0x3D, 0x3D);
+               ricu_afe_ctl_33_pack(chip, 0x1, 0x3D, 0x3D);
+               break;
+       case 160:
+               ricu_afe_ctrl_43_freq_sel_setf(chip, 0x2);
+               /* Configure ADC sampling for primary chains */
+               ricu_afe_ctl_25_pack(chip, 0x0, 0x7, 0x7);
+               ricu_afe_ctl_26_pack(chip, 0x0, 0x7, 0x7);
+               ricu_afe_ctl_27_pack(chip, 0x0, 0x7, 0x7);
+               ricu_afe_ctl_33_pack(chip, 0x0, 0x7, 0x7);
+               break;
+       case 320:
+               ricu_afe_ctrl_43_freq_sel_setf(chip, 0x3);
+               /* Configure ADC sampling for primary chains */
+               ricu_afe_ctl_25_pack(chip, 0x0, 0x7, 0x7);
+               ricu_afe_ctl_26_pack(chip, 0x0, 0x7, 0x7);
+               ricu_afe_ctl_27_pack(chip, 0x0, 0x7, 0x7);
+               ricu_afe_ctl_33_pack(chip, 0x0, 0x7, 0x7);
+               break;
+       default:
+               CL_DBG_ERROR_CHIP(chip, "Invalid adc_sampling_clk %u\n", adc_sampling_clk);
+               return -1;
+       }
+
+       return 0;
+}
+
+static int cl_adc_sampling_cfg_tcv1(struct cl_chip *chip, u32 adc_sampling_clk)
+{
+       switch (adc_sampling_clk) {
+       case 40:
+               ricu_afe_ctrl_44_cdb_freq_sel_setf(chip, 0x0);
+               /* Configure ADC sampling for secondary chains */
+               ricu_afe_ctrl_39_pack(chip, 0x1, 0x3D, 0x3D);
+               ricu_afe_ctrl_40_pack(chip, 0x1, 0x3D, 0x3D);
+               ricu_afe_ctrl_41_pack(chip, 0x1, 0x3D, 0x3D);
+               ricu_afe_ctrl_42_pack(chip, 0x1, 0x3D, 0x3D);
+               break;
+       case 80:
+               ricu_afe_ctrl_44_cdb_freq_sel_setf(chip, 0x1);
+               /* Configure ADC sampling for secondary chains */
+               ricu_afe_ctrl_39_pack(chip, 0x1, 0x3D, 0x3D);
+               ricu_afe_ctrl_40_pack(chip, 0x1, 0x3D, 0x3D);
+               ricu_afe_ctrl_41_pack(chip, 0x1, 0x3D, 0x3D);
+               ricu_afe_ctrl_42_pack(chip, 0x1, 0x3D, 0x3D);
+               break;
+       case 160:
+               ricu_afe_ctrl_44_cdb_freq_sel_setf(chip, 0x2);
+               /* Configure ADC sampling for secondary chains */
+               ricu_afe_ctrl_39_pack(chip, 0x0, 0x7, 0x7);
+               ricu_afe_ctrl_40_pack(chip, 0x0, 0x7, 0x7);
+               ricu_afe_ctrl_41_pack(chip, 0x0, 0x7, 0x7);
+               ricu_afe_ctrl_42_pack(chip, 0x0, 0x7, 0x7);
+               break;
+       case 320:
+               ricu_afe_ctrl_44_cdb_freq_sel_setf(chip, 0x3);
+               /* Configure ADC sampling for secondary chains */
+               ricu_afe_ctrl_39_pack(chip, 0x0, 0x7, 0x7);
+               ricu_afe_ctrl_40_pack(chip, 0x0, 0x7, 0x7);
+               ricu_afe_ctrl_41_pack(chip, 0x0, 0x7, 0x7);
+               ricu_afe_ctrl_42_pack(chip, 0x0, 0x7, 0x7);
+               break;
+       default:
+               CL_DBG_ERROR_CHIP(chip, "Invalid adc_sampling_clk %u\n", adc_sampling_clk);
+               return -1;
+       }
+
+       return 0;
+}
+
+static int cl_afe_adc_and_dac_cfg(struct cl_chip *chip)
+{
+       struct cl_hw *cl_hw_tcv0 = chip->cl_hw_tcv0;
+       struct cl_hw *cl_hw_tcv1 = chip->cl_hw_tcv1;
+       u16 bw_tcv0 = cl_hw_tcv0->conf->ce_channel_bandwidth;
+       u16 bw_tcv1 = cl_hw_tcv1->conf->ce_channel_bandwidth;
+       u16 riu_sampling_clk_tcv0 = cl_hw_tcv0->conf->ci_hr_factor[bw_tcv0] * BW_TO_MHZ(bw_tcv0);
+       u16 riu_sampling_clk_tcv1 = cl_hw_tcv1->conf->ci_hr_factor[bw_tcv1] * BW_TO_MHZ(bw_tcv1);
+       u16 adc_sampling_clk_tcv0 = 2 * riu_sampling_clk_tcv0;
+       u16 adc_sampling_clk_tcv1 = 2 * riu_sampling_clk_tcv1;
+       u8 sb_rd_delay_tcv0 = ((riu_sampling_clk_tcv0 == 80) ||
+                              (riu_sampling_clk_tcv0 == 160)) ? 4 : 2;
+       u8 sb_rd_delay_tcv1 = ((riu_sampling_clk_tcv1 == 80) ||
+                              (riu_sampling_clk_tcv1 == 160)) ? 4 : 2;
+       u32 regval;
+
+       /*
+        * For ADC sampling CLK=40MHz set to 0
+        * For ADC sampling CLK=80MHz set to 1
+        * For ADC sampling CLK=160MHz set to 2
+        * For ADC sampling CLK=320MHz set to 3
+        *
+        * The sampling clock depends on the channel_bandwidth (20/40/80/160MHz)
+        * and hr_factor (1,2,4,8):
+        * ADC Sampling (MHz) = 2 * hr_factor * channel_bandwidth
+        *
+        * Select the external forced clock for ADC0..7:
+        * For ADC sampling CLK=40MHz/80MHz set to 1
+        * For ADC sampling CLK=160MHz/320MHz set to 0
+        * In our default case: rosel0-3 = 0x0; rosel4-7 = 0x1
+        *
+        * Internal clock frequency of ADCI0..7 I (when its ROSEL is low):
+        * For ADC sampling CLK=40MHz/80MHz set to 7'b011_1101
+        * For ADC sampling CLK=160MHz/320MHz set to 7'b000_0111
+        * In our default case: roctrli0-3 = 0x7; roctrli4-7 = 0x3D
+        *
+        * Internal clock frequency of ADCQ0..7 I (when its ROSEL is low):
+        * For ADC sampling CLK=40MHz/80MHz set to 7'b011_1101
+        * For ADC sampling CLK=160MHz/320MHz set to 7'b000_0111
+        * In our default case: roctrlq0-3 = 0x7; roctrlq4-7 = 0x3D
+        */
+
+       if (cl_adc_sampling_cfg_tcv0(chip, adc_sampling_clk_tcv0))
+               return -1;
+       if (cl_adc_sampling_cfg_tcv1(chip, adc_sampling_clk_tcv1))
+               return -1;
+
+       /* AFE_CTL_0 - AUX ADC for debug + for second band */
+       regval = ricu_afe_ctl_0_get(chip);
+       if (cl_chip_is_4ant(chip) && cl_chip_is_6g(chip))
+               regval |= (RICU_AFE_CTL_0_EN_GPADC_CLK_BIT |
+                          RICU_AFE_CTL_0_EN_GPADC_BIT);
+       else
+               regval |= (RICU_AFE_CTL_0_EN_CDB_DAC_CLK_BIT |
+                          RICU_AFE_CTL_0_EN_CDB_ADC_CLK_BIT |
+                          RICU_AFE_CTL_0_EN_CDB_GEN_BIT |
+                          RICU_AFE_CTL_0_EN_GPADC_CLK_BIT |
+                          RICU_AFE_CTL_0_EN_GPADC_BIT);
+       ricu_afe_ctl_0_set(chip, regval);
+
+       ricu_afe_ctl_3_cml_sel_setf(chip, 7);
+
+       /* VC_LD_AVDI0..7 = 0x1 */
+       ricu_afe_ctl_23_set(chip, 0x55555555);
+       /* VC_LD_AVDQ0..7 = 0x1 */
+       ricu_afe_ctl_24_set(chip, 0x55555555);
+       /* EN_BGR0..7 = 0x1, CH_CML_SEL0..7 = 0x1, EN_EXT_LOAD0..7 = 0x0, EN_REF0..7 = 0x1 */
+       ricu_afe_ctl_8_set(chip, 0xff00ffff);
+       /* VC_CML0..7_I = 0x0 */
+       ricu_afe_ctl_29_set(chip, 0x0);
+       /* VC_CML0..7_Q = 0x0 */
+       ricu_afe_ctl_30_set(chip, 0x0);
+       /* IC_REFSSF0..7 = 0x3, EOC_CTRL0..7 = 0x2 */
+       ricu_afe_ctl_12_set(chip, 0xaaaaffff);
+
+       /*
+        * Set channels to Transceiver0 (phy0) or Transceiver1 (phy1):
+        * 6'b11_0000 (Transceiver1 @CH7~6, Transceiver0 @CH5~0)
+        * 6'b11_1000 (Transceiver1 @CH7~5, Transceiver0 @CH4~0)
+        * 6'b11_1100 (Transceiver1 @CH7~4, Transceiver0 @CH3~0)
+        * 6'b11_1110 (Transceiver1 @CH7~3, Transceiver0 @CH3~0)
+        * 6'b11_1111 (Transceiver1 @CH7~2, Transceiver0 @CH2~0)
+        * In our default case: mainsel72 = 0x3C
+        */
+       ricu_afe_ctl_5_main_sel_7_2_setf(chip, 0x3C);
+
+       /*
+        * Set 1 - b0 to MINV0/1/2/3/4/5/6/7 (DAC)
+        * Set 1 - b1 to TWOS0/1/2/3/4/5/6/7 (ADC)
+        */
+       ricu_afe_ctl_10_set(chip, 0x00FF0000);
+
+       /* Set VC_REF0/1/2/../7 */
+       ricu_afe_ctl_17_set(chip, 0x77777777);
+
+       /* Set COMP_CTRL0/1/2/.../7[3:0] to 4'b1010 for normal mode */
+       ricu_afe_ctl_19_set(chip, 0xAAAAAAAA);
+
+       /*
+        * Disable DAC & ADC cores (To save power.
+        * Assuming RIU HW will control it due to HW_MODE_ADC/DAC)
+        */
+       ricu_afe_ctrl_37_phy_0_set(chip, 0);
+       ricu_afe_ctrl_37_phy_1_set(chip, 0);
+
+       regval = ricu_afe_ctrl_36_phy_0_get(chip);
+       regval &= ~(RICU_AFE_CTRL_36_PHY_0_ADC_ALWAYS_EN_ADCQ_BIT |
+                   RICU_AFE_CTRL_36_PHY_0_ADC_ALWAYS_EN_ADCI_BIT);
+       ricu_afe_ctrl_36_phy_0_set(chip, regval);
+
+       regval = ricu_afe_ctrl_36_phy_1_get(chip);
+       regval &= ~(RICU_AFE_CTRL_36_PHY_1_ADC_ALWAYS_EN_ADCQ_BIT |
+                   RICU_AFE_CTRL_36_PHY_1_ADC_ALWAYS_EN_ADCI_BIT);
+       ricu_afe_ctrl_36_phy_1_set(chip, regval);
+
+       /* Sync buffer read delay, ignore fifo indication */
+       ricu_afe_ctrl_34_phy_0_adc_sb_rd_delay_setf(chip, sb_rd_delay_tcv0);
+       ricu_afe_ctrl_34_phy_0_adc_sb_ignore_fifo_indication_setf(chip, 1);
+
+       ricu_afe_ctrl_34_phy_1_adc_sb_rd_delay_setf(chip, sb_rd_delay_tcv1);
+       ricu_afe_ctrl_34_phy_1_adc_sb_ignore_fifo_indication_setf(chip, 1);
+
+       /* DAC - ignore fifo indication = true */
+       ricu_afe_ctrl_35_phy_0_dac_sb_rd_delay_setf(chip, 1);
+       ricu_afe_ctrl_35_phy_0_dac_sb_ignore_fifo_indication_setf(chip, 1);
+
+       ricu_afe_ctrl_35_phy_1_dac_sb_rd_delay_setf(chip, 1);
+       ricu_afe_ctrl_35_phy_1_dac_sb_ignore_fifo_indication_setf(chip, 1);
+
+       /* Set to HW/SW control mode */
+       ricu_afe_ctrl_36_phy_0_hw_mode_adc_setf(chip, 1);
+       ricu_afe_ctrl_36_phy_0_hw_mode_dac_setf(chip, 1);
+
+       ricu_afe_ctrl_36_phy_1_hw_mode_adc_setf(chip, 1);
+       ricu_afe_ctrl_36_phy_1_hw_mode_dac_setf(chip, 1);
+
+       return 0;
+}
+
+static int cl_afe_set_cdb_mode(struct cl_chip *chip)
+{
+       /* Configure number of RF chains per PHY */
+       struct cl_hw *cl_hw_tcv0 = chip->cl_hw_tcv0;
+       struct cl_hw *cl_hw_tcv1 = chip->cl_hw_tcv1;
+       u8 ant_tcv0 = cl_hw_tcv0->num_antennas;
+       u8 ant_tcv1 = cl_hw_tcv1 ? cl_hw_tcv1->num_antennas : (chip->max_antennas - ant_tcv0);
+       u8 ant_total = ant_tcv0 + ant_tcv1;
+
+       if (!cl_chip_is_8ant(chip)) {
+               ricu_static_conf_0_cdb_mode_maj_setf(chip, 0x4);
+               return 0;
+       }
+
+       if (ant_total < MAX_ANTENNAS_CHIP) {
+               if (ant_tcv0 <= 4 && ant_tcv1 <= 4) {
+                       ant_tcv0 = 4;
+                       ant_tcv1 = 4;
+               } else {
+                       ant_tcv0 += min(cl_hw_tcv0->max_antennas - cl_hw_tcv0->num_antennas,
+                                       chip->max_antennas - ant_total);
+
+                       if (cl_hw_tcv1) {
+                               ant_total = ant_tcv0 + ant_tcv1;
+                               ant_tcv1 += min(cl_hw_tcv1->max_antennas - cl_hw_tcv1->num_antennas,
+                                               chip->max_antennas - ant_total);
+                       } else {
+                               ant_tcv1 = MAX_ANTENNAS_CHIP - ant_tcv0;
+                       }
+               }
+       }
+
+       if (ant_tcv0 == 6 && ant_tcv1 == 2) {
+               ricu_static_conf_0_cdb_mode_maj_setf(chip, 0x2);
+       } else if (ant_tcv0 == 5 && ant_tcv1 == 3) {
+               ricu_static_conf_0_cdb_mode_maj_setf(chip, 0x3);
+       } else if (ant_tcv0 == 4 && ant_tcv1 == 4) {
+               ricu_static_conf_0_cdb_mode_maj_setf(chip, 0x4);
+       } else if (ant_tcv0 == 3 && ant_tcv1 == 5) {
+               ricu_static_conf_0_cdb_mode_maj_setf(chip, 0x5);
+       } else if (ant_tcv0 == 2 && ant_tcv1 == 6) {
+               ricu_static_conf_0_cdb_mode_maj_setf(chip, 0x6);
+       } else {
+               CL_DBG_ERROR_CHIP(chip, "Invalid antenna configuration (tcv0 %u) (tcv1 %u)\n",
+                                 ant_tcv0, ant_tcv1);
+               return -1;
+       }
+
+       return 0;
+}
+
+static int cl_afe_phy_type_and_rf_chains(struct cl_chip *chip)
+{
+       ricu_spi_clk_ctrl_set(chip, 0x1c); /* SPI clock bitmap */
+       ricu_static_conf_0_btc_sel_setf(chip, 0); /* Clear BTC select */
+
+       if (cl_afe_set_cdb_mode(chip))
+               return -1;
+
+       if (cl_chip_is_8ant(chip))
+               ricu_afe_adc_ch_alloc_afe_adc_ch_alloc_setf(chip, U8_MAX);
+       else if (cl_chip_is_6ant(chip))
+               ricu_afe_adc_ch_alloc_afe_adc_ch_alloc_setf(chip, 0x3f);
+       else if (cl_chip_is_6g(chip))
+               ricu_afe_adc_ch_alloc_afe_adc_ch_alloc_setf(chip, 0x0f);
+       else
+               ricu_afe_adc_ch_alloc_afe_adc_ch_alloc_setf(chip, 0x33);
+
+       /* Reset RFIC */
+       ricu_static_conf_0_rf_rst_n_req_setf(chip, 0x1);
+
+       return 0;
+}
+
+int cl_afe_cfg(struct cl_chip *chip)
+{
+       /* 1. Define PHY Type & RF Chains per band */
+       if (cl_afe_phy_type_and_rf_chains(chip))
+               return -1;
+
+       /* 2. AFE Disable */
+       cl_afe_disable(chip);
+
+       /* Wait 2us for AFE LDO settling time */
+       udelay(2);
+
+       /* 3. AFE Enable */
+       cl_afe_enable(chip);
+
+       /* 4. ADC & DAC Configuration */
+       cl_afe_adc_and_dac_cfg(chip);
+
+       cl_io_ctrl_config(chip);
+
+       /* 5. FEM Configuration */
+       cl_fem_update_conf_params(chip);
+
+       return 0;
+}
+
+void cl_afe_cfg_calib(struct cl_chip *chip)
+{
+       struct cl_afe_reg *orig_afe_reg = &chip->orig_afe_reg;
+       u32 reg_phy0, reg_phy1;
+
+       orig_afe_reg->ctrl36_phy0 = ricu_afe_ctrl_36_phy_0_get(chip);
+       orig_afe_reg->ctrl36_phy1 = ricu_afe_ctrl_36_phy_1_get(chip);
+       orig_afe_reg->ctrl37_phy0 = ricu_afe_ctrl_37_phy_0_get(chip);
+       orig_afe_reg->ctrl37_phy1 = ricu_afe_ctrl_37_phy_1_get(chip);
+
+       reg_phy0 = orig_afe_reg->ctrl36_phy0;
+       reg_phy0 |= (RICU_AFE_CTRL_36_PHY_0_ADC_ALWAYS_EN_ADCQ_BIT |
+                    RICU_AFE_CTRL_36_PHY_0_ADC_ALWAYS_EN_ADCI_BIT |
+                    RICU_AFE_CTRL_36_PHY_0_ADC_ALWAYS_EN_LD_IR_BIT |
+                    RICU_AFE_CTRL_36_PHY_0_ADC_ALWAYS_EN_LD_AVDQ_BIT |
+                    RICU_AFE_CTRL_36_PHY_0_ADC_ALWAYS_EN_LD_AVDI_BIT); /* Enable ADC cores */
+       reg_phy0 &= ~(RICU_AFE_CTRL_36_PHY_0_HW_MODE_ADC_BIT |
+                     RICU_AFE_CTRL_36_PHY_0_HW_MODE_DAC_BIT); /* Set to SW control mode */
+       ricu_afe_ctrl_36_phy_0_set(chip, reg_phy0);
+
+       cl_dbg_chip_trace(chip, "Setting: RICU_AFE_CTRL_36_PHY_0 = 0x%x\n", reg_phy0);
+
+       reg_phy1 = orig_afe_reg->ctrl36_phy1;
+       reg_phy1 |= (RICU_AFE_CTRL_36_PHY_1_ADC_ALWAYS_EN_ADCQ_BIT |
+                    RICU_AFE_CTRL_36_PHY_1_ADC_ALWAYS_EN_ADCI_BIT |
+                    RICU_AFE_CTRL_36_PHY_1_ADC_ALWAYS_EN_LD_IR_BIT |
+                    RICU_AFE_CTRL_36_PHY_1_ADC_ALWAYS_EN_LD_AVDQ_BIT |
+                    RICU_AFE_CTRL_36_PHY_1_ADC_ALWAYS_EN_LD_AVDI_BIT);
+       reg_phy1 &= ~(RICU_AFE_CTRL_36_PHY_1_HW_MODE_ADC_BIT |
+                     RICU_AFE_CTRL_36_PHY_1_HW_MODE_DAC_BIT); /* Set to SW control mode */
+       ricu_afe_ctrl_36_phy_1_set(chip, reg_phy1);
+
+       cl_dbg_chip_trace(chip, "Setting: RICU_AFE_CTRL_36_PHY_1 = 0x%x\n", reg_phy1);
+
+       /* Enable DAC cores */
+       if (cl_chip_is_8ant(chip)) {
+               reg_phy0 = RICU_AFE_CTRL_37_PHY_0_DAC_CL808X;
+               reg_phy1 = RICU_AFE_CTRL_37_PHY_1_DAC_CL808X;
+       } else if (cl_chip_is_6ant(chip)) {
+               reg_phy0 = RICU_AFE_CTRL_37_PHY_0_DAC_CL806X;
+               reg_phy1 = RICU_AFE_CTRL_37_PHY_1_DAC_CL806X;
+       } else if (cl_chip_is_6g(chip)) {
+               reg_phy0 = RICU_AFE_CTRL_37_PHY_0_DAC_CL8046;
+               reg_phy1 = RICU_AFE_CTRL_37_PHY_1_DAC_CL804X;
+       } else {
+               reg_phy0 = RICU_AFE_CTRL_37_PHY_0_DAC_CL8040;
+               reg_phy1 = RICU_AFE_CTRL_37_PHY_1_DAC_CL804X;
+       }
+
+       ricu_afe_ctrl_37_phy_0_set(chip, reg_phy0);
+       cl_dbg_chip_trace(chip, "Setting: RICU_AFE_CTRL_37_PHY_0 = 0x%x\n", reg_phy0);
+
+       ricu_afe_ctrl_37_phy_1_set(chip, reg_phy1);
+       cl_dbg_chip_trace(chip, "Setting: RICU_AFE_CTRL_37_PHY_1 = 0x%x\n", reg_phy1);
+}
+
+void cl_afe_cfg_restore(struct cl_chip *chip)
+{
+       struct cl_afe_reg *orig_afe_reg = &chip->orig_afe_reg;
+
+       ricu_afe_ctrl_36_phy_0_set(chip, orig_afe_reg->ctrl36_phy0);
+       cl_dbg_chip_trace(chip, "Restoring: RICU_AFE_CTRL_36_PHY_0 = 0x%x\n",
+                         orig_afe_reg->ctrl36_phy0);
+
+       ricu_afe_ctrl_36_phy_1_set(chip, orig_afe_reg->ctrl36_phy1);
+       cl_dbg_chip_trace(chip, "Restoring: RICU_AFE_CTRL_36_PHY_1 = 0x%x\n",
+                         orig_afe_reg->ctrl36_phy1);
+
+       ricu_afe_ctrl_37_phy_0_set(chip, orig_afe_reg->ctrl37_phy0);
+       cl_dbg_chip_trace(chip, "Restoring: RICU_AFE_CTRL_37_PHY_0 = 0x%x\n",
+                         orig_afe_reg->ctrl37_phy0);
+
+       ricu_afe_ctrl_37_phy_1_set(chip, orig_afe_reg->ctrl37_phy1);
+       cl_dbg_chip_trace(chip, "Restoring: RICU_AFE_CTRL_37_PHY_1 = 0x%x\n",
+                         orig_afe_reg->ctrl37_phy1);
+}
--
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.
________________________________


^ permalink raw reply related	[flat|nested] 262+ messages in thread

* [RFC v1 006/256] cl8k: add afe.h
  2021-06-17 15:58 [RFC v1 000/256] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (4 preceding siblings ...)
  2021-06-17 15:58 ` [RFC v1 005/256] cl8k: add afe.c viktor.barna
@ 2021-06-17 15:58 ` viktor.barna
  2021-06-17 15:58 ` [RFC v1 007/256] cl8k: add agc_params.c viktor.barna
                   ` (251 subsequent siblings)
  257 siblings, 0 replies; 262+ messages in thread
From: viktor.barna @ 2021-06-17 15:58 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Oleksandr Savchenko, Shay Bar, Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

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

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 drivers/net/wireless/celeno/cl8k/afe.h | 20 ++++++++++++++++++++
 1 file changed, 20 insertions(+)
 create mode 100644 drivers/net/wireless/celeno/cl8k/afe.h

diff --git a/drivers/net/wireless/celeno/cl8k/afe.h b/drivers/net/wireless/celeno/cl8k/afe.h
new file mode 100644
index 000000000000..3cf713a57ea5
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/afe.h
@@ -0,0 +1,20 @@
+/* SPDX-License-Identifier: MIT */
+/* Copyright(c) 2019-2021, Celeno Communications Ltd. */
+
+#ifndef CL_AFE_H
+#define CL_AFE_H
+
+#include "chip.h"
+
+/**
+ * DOC: AFE (=Analog Front End)
+ *
+ * Configuration layer for the HW component, most of the defined operations
+ * happen  when we start the driver.
+ */
+
+int cl_afe_cfg(struct cl_chip *chip);
+void cl_afe_cfg_calib(struct cl_chip *chip);
+void cl_afe_cfg_restore(struct cl_chip *chip);
+
+#endif /* CL_AFE_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.
________________________________


^ permalink raw reply related	[flat|nested] 262+ messages in thread

* [RFC v1 007/256] cl8k: add agc_params.c
  2021-06-17 15:58 [RFC v1 000/256] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (5 preceding siblings ...)
  2021-06-17 15:58 ` [RFC v1 006/256] cl8k: add afe.h viktor.barna
@ 2021-06-17 15:58 ` viktor.barna
  2021-06-17 15:58 ` [RFC v1 008/256] cl8k: add agc_params.h viktor.barna
                   ` (250 subsequent siblings)
  257 siblings, 0 replies; 262+ messages in thread
From: viktor.barna @ 2021-06-17 15:58 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Oleksandr Savchenko, Shay Bar, Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

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

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 drivers/net/wireless/celeno/cl8k/agc_params.c | 683 ++++++++++++++++++
 1 file changed, 683 insertions(+)
 create mode 100644 drivers/net/wireless/celeno/cl8k/agc_params.c

diff --git a/drivers/net/wireless/celeno/cl8k/agc_params.c b/drivers/net/wireless/celeno/cl8k/agc_params.c
new file mode 100644
index 000000000000..3512defb6f18
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/agc_params.c
@@ -0,0 +1,683 @@
+// SPDX-License-Identifier: MIT
+/* Copyright(c) 2019-2021, Celeno Communications Ltd. */
+
+#include "agc_params.h"
+#include "chip.h"
+#include "hw.h"
+#include "e2p.h"
+#include "utils/utils.h"
+
+struct cl_agc_profile agc_profile_2_1_6 = {
+       .id                 = AGC_PROFILE(2, 1, 6),
+       .fsm_preset_p2      = { .val = 0x00004701, .mask = 0xffffffff }, /* 0x244 */
+       .lna_thr_set0_ref2  = { .val = 0x2E292624, .mask = 0xffffffff }, /* 0x25C */
+       .lna_thr_set0_ref3  = { .val = 0x00393933, .mask = 0xffffffff }, /* 0x260 */
+       .lna_thr_set1_ref2  = { .val = 0x2E292624, .mask = 0xffffffff }, /* 0x264 */
+       .lna_thr_set1_ref3  = { .val = 0x5D393933, .mask = 0xffffffff }, /* 0x268 */
+       .lna_thr_set2_ref2  = { .val = 0x2E292624, .mask = 0xffffffff }, /* 0x26C */
+       .lna_thr_set2_ref3  = { .val = 0x5D393933, .mask = 0xffffffff }, /* 0x270 */
+       .lna_gain_set0_ref2 = { .val = 0x2926231F, .mask = 0xffffffff }, /* 0x274 */
+       .lna_gain_set0_ref3 = { .val = 0x3838322E, .mask = 0xffffffff }, /* 0x278 */
+       .lna_nf_set0_ref2   = { .val = 0x04080C0F, .mask = 0xffffffff }, /* 0x27C */
+       .lna_nf_set0_ref3   = { .val = 0x03030303, .mask = 0xffffffff }, /* 0x280 */
+       .lna_icp1_set0_ref2 = { .val = 0x66696C6C, .mask = 0xffffffff }, /* 0x284 */
+       .lna_icp1_set0_ref3 = { .val = 0x625F6264, .mask = 0xffffffff }, /* 0x288 */
+       .fsm_preset_p10     = { .val = 0x00001E21, .mask = 0xffffffff }, /* 0x2A8 */
+       .fsm_preset_p11     = { .val = 0x00001E21, .mask = 0xffffffff }, /* 0x2AC */
+       .fsm_preset_p12     = { .val = 0x00ECEA07, .mask = 0xffffffff }, /* 0x2B0 */
+       .ant_loss           = { .val = 0x00000000, .mask = 0xffffffff }, /* 0x300 */
+       .gain_range         = { .val = 0x47076407, .mask = 0xffffffff }, /* 0x304 */
+       .vga_ref0           = { .val = 0x0001021E, .mask = 0xffffffff }, /* 0x308 */
+       .lna_gain_set0_ref0 = { .val = 0x15120F0B, .mask = 0xffffffff }, /* 0x30C */
+       .lna_gain_set0_ref1 = { .val = 0x24241E1A, .mask = 0xffffffff }, /* 0x310 */
+       .lna_thr_set0_ref0  = { .val = 0x1A16130F, .mask = 0xffffffff }, /* 0x314 */
+       .lna_thr_set0_ref1  = { .val = 0x2424241F, .mask = 0xffffffff }, /* 0x318 */
+       .lna_thr_set1_ref0  = { .val = 0x1A16130F, .mask = 0xffffffff }, /* 0x31C */
+       .lna_thr_set1_ref1  = { .val = 0x2424241F, .mask = 0xffffffff }, /* 0x320 */
+       .lna_thr_set2_ref0  = { .val = 0x1A16130F, .mask = 0xffffffff }, /* 0x324 */
+       .lna_thr_set2_ref1  = { .val = 0x2424241F, .mask = 0xffffffff }, /* 0x328 */
+       .lna_nf_set0_ref0   = { .val = 0x141A2023, .mask = 0xffffffff }, /* 0x32C */
+       .lna_nf_set0_ref1   = { .val = 0x000D0E10, .mask = 0xffffffff }, /* 0x330 */
+       .lna_icp1_set0_ref0 = { .val = 0x7A7D0000, .mask = 0xffffffff }, /* 0x334 */
+       .lna_icp1_set0_ref1 = { .val = 0x00737678, .mask = 0xffffffff }, /* 0x338 */
+       .saturation         = { .val = 0x08393536, .mask = 0xffffffff }, /* 0x364 */
+       .ramp               = { .val = 0x05200710, .mask = 0xffffffff }, /* 0x36C */
+       .dsp0               = { .val = 0x00000000, .mask = 0x000000ff }, /* 0x394 */
+       .dsp1               = { .val = 0x00000000, .mask = 0x000000ff }, /* 0x398 */
+       .dsp2               = { .val = 0x00000000, .mask = 0xffffffff }, /* 0x39A */
+       .dsp3               = { .val = 0x0B730000, .mask = 0xffff0000 }, /* 0x3A0 */
+       .lna_gain_set1_ref0 = { .val = 0x15120F0B, .mask = 0xffffffff }, /* 0x590 */
+       .lna_gain_set1_ref1 = { .val = 0x24241E1A, .mask = 0xffffffff }, /* 0x594 */
+       .lna_gain_set1_ref2 = { .val = 0x2926231F, .mask = 0xffffffff }, /* 0x598 */
+       .lna_gain_set1_ref3 = { .val = 0x3838322E, .mask = 0xffffffff }, /* 0x59C */
+       .lna_nf_set1_ref0   = { .val = 0x141A2023, .mask = 0xffffffff }, /* 0x5A0 */
+       .lna_nf_set1_ref1   = { .val = 0x000D0E10, .mask = 0xffffffff }, /* 0x5A4 */
+       .lna_nf_set1_ref2   = { .val = 0x04080C0F, .mask = 0xffffffff }, /* 0x5A8 */
+       .lna_nf_set1_ref3   = { .val = 0x03030303, .mask = 0xffffffff }, /* 0x5AC */
+       .lna_icp1_set1_ref0 = { .val = 0x7A7D0000, .mask = 0xffffffff }, /* 0x5B0 */
+       .lna_icp1_set1_ref1 = { .val = 0x00737678, .mask = 0xffffffff }, /* 0x5B4 */
+       .lna_icp1_set1_ref2 = { .val = 0x66696C6C, .mask = 0xffffffff }, /* 0x5B8 */
+       .lna_icp1_set1_ref3 = { .val = 0x625F6264, .mask = 0xffffffff }, /* 0x5BC */
+};
+
+struct cl_agc_profile agc_profile_5_1_7 = {
+       .id                 = AGC_PROFILE(5, 1, 7),
+       .fsm_preset_p2      = { .val = 0x00004701, .mask = 0xffffffff }, /* 0x244 */
+       .lna_thr_set0_ref2  = { .val = 0x2E28231F, .mask = 0xffffffff }, /* 0x25C */
+       .lna_thr_set0_ref3  = { .val = 0x00353532, .mask = 0xffffffff }, /* 0x260 */
+       .lna_thr_set1_ref2  = { .val = 0x2E28231F, .mask = 0xffffffff }, /* 0x264 */
+       .lna_thr_set1_ref3  = { .val = 0x5B353532, .mask = 0xffffffff }, /* 0x268 */
+       .lna_thr_set2_ref2  = { .val = 0x2E28231F, .mask = 0xffffffff }, /* 0x26C */
+       .lna_thr_set2_ref3  = { .val = 0x5B353532, .mask = 0xffffffff }, /* 0x270 */
+       .lna_gain_set0_ref2 = { .val = 0x27231E19, .mask = 0xffffffff }, /* 0x274 */
+       .lna_gain_set0_ref3 = { .val = 0x3535312C, .mask = 0xffffffff }, /* 0x278 */
+       .lna_nf_set0_ref2   = { .val = 0x0406090D, .mask = 0xffffffff }, /* 0x27C */
+       .lna_nf_set0_ref3   = { .val = 0x02030303, .mask = 0xffffffff }, /* 0x280 */
+       .lna_icp1_set0_ref2 = { .val = 0x5D666A6F, .mask = 0xffffffff }, /* 0x284 */
+       .lna_icp1_set0_ref3 = { .val = 0x5757575B, .mask = 0xffffffff }, /* 0x288 */
+       .fsm_preset_p10     = { .val = 0x00001E21, .mask = 0xffffffff }, /* 0x2A8 */
+       .fsm_preset_p11     = { .val = 0x00001E21, .mask = 0xffffffff }, /* 0x2AC */
+       .fsm_preset_p12     = { .val = 0x00ECEA07, .mask = 0xffffffff }, /* 0x2B0 */
+       .ant_loss           = { .val = 0x00000000, .mask = 0xffffffff }, /* 0x300 */
+       .gain_range         = { .val = 0x47026402, .mask = 0xffffffff }, /* 0x304 */
+       .vga_ref0           = { .val = 0x0001021E, .mask = 0xffffffff }, /* 0x308 */
+       .lna_gain_set0_ref0 = { .val = 0x120E0904, .mask = 0xffffffff }, /* 0x30C */
+       .lna_gain_set0_ref1 = { .val = 0x20201C17, .mask = 0xffffffff }, /* 0x310 */
+       .lna_thr_set0_ref0  = { .val = 0x17120E09, .mask = 0xffffffff }, /* 0x314 */
+       .lna_thr_set0_ref1  = { .val = 0x1F1F1F1C, .mask = 0xffffffff }, /* 0x318 */
+       .lna_thr_set1_ref0  = { .val = 0x17120E09, .mask = 0xffffffff }, /* 0x31C */
+       .lna_thr_set1_ref1  = { .val = 0x1F1F1F1C, .mask = 0xffffffff }, /* 0x320 */
+       .lna_thr_set2_ref0  = { .val = 0x17120E09, .mask = 0xffffffff }, /* 0x324 */
+       .lna_thr_set2_ref1  = { .val = 0x1F1F1F1C, .mask = 0xffffffff }, /* 0x328 */
+       .lna_nf_set0_ref0   = { .val = 0x12171C20, .mask = 0xffffffff }, /* 0x32C */
+       .lna_nf_set0_ref1   = { .val = 0x0A0B0B0F, .mask = 0xffffffff }, /* 0x330 */
+       .lna_icp1_set0_ref0 = { .val = 0x6F727476, .mask = 0xffffffff }, /* 0x334 */
+       .lna_icp1_set0_ref1 = { .val = 0x6268686D, .mask = 0xffffffff }, /* 0x338 */
+       .saturation         = { .val = 0x08393536, .mask = 0xffffffff }, /* 0x364 */
+       .ramp               = { .val = 0x05200710, .mask = 0xffffffff }, /* 0x36C */
+       .dsp0               = { .val = 0x00000000, .mask = 0x000000ff }, /* 0x394 */
+       .dsp1               = { .val = 0x00000000, .mask = 0x000000ff }, /* 0x398 */
+       .dsp2               = { .val = 0x00000000, .mask = 0xffffffff }, /* 0x39A */
+       .dsp3               = { .val = 0x0B730000, .mask = 0xffff0000 }, /* 0x3A0 */
+       .lna_gain_set1_ref0 = { .val = 0x120E0904, .mask = 0xffffffff }, /* 0x590 */
+       .lna_gain_set1_ref1 = { .val = 0x20201C17, .mask = 0xffffffff }, /* 0x594 */
+       .lna_gain_set1_ref2 = { .val = 0x27231E19, .mask = 0xffffffff }, /* 0x598 */
+       .lna_gain_set1_ref3 = { .val = 0x3535312C, .mask = 0xffffffff }, /* 0x59C */
+       .lna_nf_set1_ref0   = { .val = 0x12171C20, .mask = 0xffffffff }, /* 0x5A0 */
+       .lna_nf_set1_ref1   = { .val = 0x0A0B0B0F, .mask = 0xffffffff }, /* 0x5A4 */
+       .lna_nf_set1_ref2   = { .val = 0x0406090D, .mask = 0xffffffff }, /* 0x5A8 */
+       .lna_nf_set1_ref3   = { .val = 0x02030303, .mask = 0xffffffff }, /* 0x5AC */
+       .lna_icp1_set1_ref0 = { .val = 0x6F727476, .mask = 0xffffffff }, /* 0x5B0 */
+       .lna_icp1_set1_ref1 = { .val = 0x6268686D, .mask = 0xffffffff }, /* 0x5B4 */
+       .lna_icp1_set1_ref2 = { .val = 0x5D666A6F, .mask = 0xffffffff }, /* 0x5B8 */
+       .lna_icp1_set1_ref3 = { .val = 0x5757575B, .mask = 0xffffffff }, /* 0x5BC */
+};
+
+struct cl_agc_profile agc_profile_6_1_3 = {
+       .id                 = AGC_PROFILE(6, 1, 3),
+       .fsm_preset_p2      = { .val = 0x00004701, .mask = 0xffffffff }, /* 0x244 */
+       .lna_thr_set0_ref2  = { .val = 0x29241F1C, .mask = 0xffffffff }, /* 0x25C */
+       .lna_thr_set0_ref3  = { .val = 0x0033332D, .mask = 0xffffffff }, /* 0x260 */
+       .lna_thr_set1_ref2  = { .val = 0x29241F1C, .mask = 0xffffffff }, /* 0x264 */
+       .lna_thr_set1_ref3  = { .val = 0x5833332D, .mask = 0xffffffff }, /* 0x268 */
+       .lna_thr_set2_ref2  = { .val = 0x29241F1C, .mask = 0xffffffff }, /* 0x26C */
+       .lna_thr_set2_ref3  = { .val = 0x5833332D, .mask = 0xffffffff }, /* 0x270 */
+       .lna_gain_set0_ref2 = { .val = 0x1A15100C, .mask = 0xffffffff }, /* 0x274 */
+       .lna_gain_set0_ref3 = { .val = 0x2828231E, .mask = 0xffffffff }, /* 0x278 */
+       .lna_nf_set0_ref2   = { .val = 0x0406090D, .mask = 0xffffffff }, /* 0x27C */
+       .lna_nf_set0_ref3   = { .val = 0x02030303, .mask = 0xffffffff }, /* 0x280 */
+       .lna_icp1_set0_ref2 = { .val = 0x5D666A6F, .mask = 0xffffffff }, /* 0x284 */
+       .lna_icp1_set0_ref3 = { .val = 0x5757575B, .mask = 0xffffffff }, /* 0x288 */
+       .fsm_preset_p10     = { .val = 0x00001E21, .mask = 0xffffffff }, /* 0x2A8 */
+       .fsm_preset_p11     = { .val = 0x00001E21, .mask = 0xffffffff }, /* 0x2AC */
+       .fsm_preset_p12     = { .val = 0x00ECEA07, .mask = 0xffffffff }, /* 0x2B0 */
+       .ant_loss           = { .val = 0x00000000, .mask = 0xffffffff }, /* 0x300 */
+       .gain_range         = { .val = 0x47026402, .mask = 0xffffffff }, /* 0x304 */
+       .vga_ref0           = { .val = 0x0001A214, .mask = 0xffffffff }, /* 0x308 */
+       .lna_gain_set0_ref0 = { .val = 0x047F7A76, .mask = 0xffffffff }, /* 0x30C */
+       .lna_gain_set0_ref1 = { .val = 0x12120D08, .mask = 0xffffffff }, /* 0x310 */
+       .lna_thr_set0_ref0  = { .val = 0x130D0906, .mask = 0xffffffff }, /* 0x314 */
+       .lna_thr_set0_ref1  = { .val = 0x1A1A1A17, .mask = 0xffffffff }, /* 0x318 */
+       .lna_thr_set1_ref0  = { .val = 0x130D0906, .mask = 0xffffffff }, /* 0x31C */
+       .lna_thr_set1_ref1  = { .val = 0x1A1A1A17, .mask = 0xffffffff }, /* 0x320 */
+       .lna_thr_set2_ref0  = { .val = 0x130D0906, .mask = 0xffffffff }, /* 0x324 */
+       .lna_thr_set2_ref1  = { .val = 0x1A1A1A17, .mask = 0xffffffff }, /* 0x328 */
+       .lna_nf_set0_ref0   = { .val = 0x12171C20, .mask = 0xffffffff }, /* 0x32C */
+       .lna_nf_set0_ref1   = { .val = 0x0A0B0B0F, .mask = 0xffffffff }, /* 0x330 */
+       .lna_icp1_set0_ref0 = { .val = 0x6F727476, .mask = 0xffffffff }, /* 0x334 */
+       .lna_icp1_set0_ref1 = { .val = 0x6268686D, .mask = 0xffffffff }, /* 0x338 */
+       .saturation         = { .val = 0x08383435, .mask = 0xffffffff }, /* 0x364 */
+       .ramp               = { .val = 0x05200710, .mask = 0xffffffff }, /* 0x36C */
+       .dsp0               = { .val = 0x00000004, .mask = 0x000000ff }, /* 0x394 */
+       .dsp1               = { .val = 0x00000006, .mask = 0x000000ff }, /* 0x398 */
+       .dsp2               = { .val = 0x06060606, .mask = 0xffffffff }, /* 0x39A */
+       .dsp3               = { .val = 0x0B730000, .mask = 0xffff0000 }, /* 0x3A0 */
+       .lna_gain_set1_ref0 = { .val = 0x047F7A76, .mask = 0xffffffff }, /* 0x590 */
+       .lna_gain_set1_ref1 = { .val = 0x12120D08, .mask = 0xffffffff }, /* 0x594 */
+       .lna_gain_set1_ref2 = { .val = 0x1A15100C, .mask = 0xffffffff }, /* 0x598 */
+       .lna_gain_set1_ref3 = { .val = 0x2828231E, .mask = 0xffffffff }, /* 0x59C */
+       .lna_nf_set1_ref0   = { .val = 0x12171C20, .mask = 0xffffffff }, /* 0x5A0 */
+       .lna_nf_set1_ref1   = { .val = 0x0A0B0B0F, .mask = 0xffffffff }, /* 0x5A4 */
+       .lna_nf_set1_ref2   = { .val = 0x0406090D, .mask = 0xffffffff }, /* 0x5A8 */
+       .lna_nf_set1_ref3   = { .val = 0x02030303, .mask = 0xffffffff }, /* 0x5AC */
+       .lna_icp1_set1_ref0 = { .val = 0x6F727476, .mask = 0xffffffff }, /* 0x5B0 */
+       .lna_icp1_set1_ref1 = { .val = 0x6268686D, .mask = 0xffffffff }, /* 0x5B4 */
+       .lna_icp1_set1_ref2 = { .val = 0x5D666A6F, .mask = 0xffffffff }, /* 0x5B8 */
+       .lna_icp1_set1_ref3 = { .val = 0x5757575B, .mask = 0xffffffff }, /* 0x5BC */
+};
+
+#define PLATFORM_DESCRIPTION_LENGTH 100
+
+struct cl_agc_table {
+       u32 platform_id;
+       u8 platform_description[PLATFORM_DESCRIPTION_LENGTH];
+       struct cl_agc_profile *agc_profile[TCV_MAX];
+       struct cl_agc_profile *agc_profile_elastic[TCV_MAX];
+       struct cl_agc_profile *agc_profile_sensing;
+};
+
+struct cl_agc_table agc_table[] = {
+       {
+               .platform_id = AGC_PLATFORM(CL_CUSTOMER_CELENO, CL_BOARD_EVB, 0),
+               .platform_description = "Celeno, EVB, 5G 6x6 + 2.4G 6x6",
+               .agc_profile[TCV0] = &agc_profile_5_1_7,
+               .agc_profile[TCV1] = &agc_profile_2_1_6,
+               .agc_profile_elastic[TCV0] = NULL,
+               .agc_profile_elastic[TCV1] = NULL,
+               .agc_profile_sensing = NULL,
+       },
+       {
+               .platform_id = AGC_PLATFORM(CL_CUSTOMER_CELENO, CL_BOARD_MERLIN, 0),
+               .platform_description = "Celeno, Merlin, 5G 4x4 + 2.4G 4x4",
+               .agc_profile[TCV0] = &agc_profile_5_1_7,
+               .agc_profile[TCV1] = &agc_profile_2_1_6,
+               .agc_profile_elastic[TCV0] = NULL,
+               .agc_profile_elastic[TCV1] = NULL,
+               .agc_profile_sensing = NULL,
+       },
+       {
+               .platform_id = AGC_PLATFORM(CL_CUSTOMER_CELENO, CL_BOARD_EVB_6G, 0),
+               .platform_description = "Celeno, EVB, 6G 4x4 + 6G 4x4",
+               .agc_profile[TCV0] = &agc_profile_6_1_3,
+               .agc_profile[TCV1] = &agc_profile_6_1_3,
+               .agc_profile_elastic[TCV0] = NULL,
+               .agc_profile_elastic[TCV1] = NULL,
+               .agc_profile_sensing = NULL,
+       },
+       {
+               .platform_id = AGC_PLATFORM(CL_CUSTOMER_CELENO, CL_BOARD_ALBATROSS, 0),
+               .platform_description =
+                       "Celeno, Albatross, 6G 4x4 WiFi + 6G 2x2 sensing + 5G 2x2 sensing",
+               .agc_profile[TCV0] = &agc_profile_6_1_3,
+               .agc_profile[TCV1] = NULL,
+               .agc_profile_elastic[TCV0] = NULL,
+               .agc_profile_elastic[TCV1] = NULL,
+               .agc_profile_sensing = &agc_profile_6_1_3,
+       },
+       {
+               .platform_id = AGC_PLATFORM(CL_CUSTOMER_CELENO, CL_BOARD_ALBATROSS_2, 0),
+               .platform_description =
+                       "Celeno, Albatross 2, 6G 4x4 WiFi + 6G 2x2 sensing + 5G 2x2 sensing",
+               .agc_profile[TCV0] = &agc_profile_6_1_3,
+               .agc_profile[TCV1] = NULL,
+               .agc_profile_elastic[TCV0] = NULL,
+               .agc_profile_elastic[TCV1] = NULL,
+               .agc_profile_sensing = &agc_profile_6_1_3,
+       },
+       {
+               .platform_id = AGC_PLATFORM(CL_CUSTOMER_CELENO, CL_BOARD_CHAMELEON, 0),
+               .platform_description = "Celeno, Chameleon, 5G 4x4 WiFi + 5G 4x4 sensing",
+               .agc_profile[TCV0] = &agc_profile_5_1_7,
+               .agc_profile[TCV1] = NULL,
+               .agc_profile_elastic[TCV0] = NULL,
+               .agc_profile_elastic[TCV1] = NULL,
+               .agc_profile_sensing = &agc_profile_5_1_7,
+       },
+};
+
+int cl_agc_params_read_platform_id(struct cl_chip *chip)
+{
+       u8 i;
+       u32 platform_id = 0;
+
+       if (cl_e2p_read(chip, (u8 *)&platform_id, SIZE_FEM_PLATFORM_ID, ADDR_FEM_PLATFORM_ID))
+               return -1;
+
+       cl_dbg_chip_verbose(chip,
+                           "platform_id: 0x%08x, "
+                           "customer_id: 0x%04x, board_id: 0x%02x, chip_id: 0x%x\n",
+                           platform_id,
+                           AGC_PLATFORM_CUSTOMER(platform_id),
+                           AGC_PLATFORM_BOARD(platform_id),
+                           AGC_PLATFORM_CHIP(platform_id));
+
+       for (i = 0; i < ARRAY_SIZE(agc_table); i++) {
+               if (platform_id != agc_table[i].platform_id)
+                       continue;
+
+               cl_dbg_chip_verbose(chip, "%s\n", agc_table[i].platform_description);
+               chip->agc_table_entry = i;
+               return 0;
+       }
+
+       CL_DBG_ERROR_CHIP(chip, "Invalid platform_id 0x%08x\n", platform_id);
+
+       if (!chip->conf->ce_production_mode)
+               return -1;
+
+       return 0;
+}
+
+#ifdef __BIG_ENDIAN_BITFIELD
+static void agc_profile_to_le32(struct cl_agc_profile *profile)
+{
+       u32 i;
+       u32 size = sizeof(struct cl_agc_profile);
+       u32 *ptr = (u32 *)profile;
+
+       /* Make sure that size divides by 4 */
+       WARN_ON((size & 0x3) != 0);
+
+       for (i = 0; i < size / 4; i++)
+               ptr[i] = cpu_to_le32(ptr[i]);
+}
+#endif
+
+int cl_agc_params_fill(struct cl_hw *cl_hw, struct cl_agc_params *agc_params)
+{
+       u8 tcv_idx = cl_hw->tcv_idx;
+       u8 agc_table_entry = cl_hw->chip->agc_table_entry;
+       struct cl_agc_table *table;
+
+       memset(agc_params, 0, sizeof(struct cl_agc_params));
+
+       if (agc_table_entry == U8_MAX)
+               return 0;
+
+       table = &agc_table[agc_table_entry];
+
+       if (!table->agc_profile_elastic[tcv_idx] || cl_hw->num_antennas <= 2) {
+               u8 ant_shift = cl_hw_ant_shift(cl_hw);
+
+               if (table->agc_profile[tcv_idx]) {
+                       memcpy(&agc_params->profile1,
+                              table->agc_profile[tcv_idx],
+                              sizeof(struct cl_agc_profile));
+               } else if (tcv_idx == TCV1 && table->agc_profile_sensing) {
+                       memcpy(&agc_params->profile1,
+                              table->agc_profile_sensing,
+                              sizeof(struct cl_agc_profile));
+               } else {
+                       CL_DBG_ERROR(cl_hw, "Invalid tcv/sensing profile");
+                       return -1;
+               }
+
+               agc_params->num_profiles = 1;
+               agc_params->ant_mask1 = ANT_MASK(cl_hw->num_antennas) << ant_shift;
+               agc_params->ant_mask2 = 0;
+
+#ifdef __BIG_ENDIAN_BITFIELD
+               agc_profile_to_le32(&agc_params->profile1);
+#endif
+       } else {
+               if (table->agc_profile[tcv_idx]) {
+                       memcpy(&agc_params->profile1,
+                              table->agc_profile[tcv_idx],
+                              sizeof(struct cl_agc_profile));
+               } else {
+                       CL_DBG_ERROR(cl_hw, "Invalid tcv profile");
+                       return -1;
+               }
+
+               if (table->agc_profile_elastic[tcv_idx]) {
+                       memcpy(&agc_params->profile2,
+                              table->agc_profile_elastic[tcv_idx],
+                              sizeof(struct cl_agc_profile));
+               } else {
+                       CL_DBG_ERROR(cl_hw, "Invalid elastic profile");
+                       return -1;
+               }
+
+               agc_params->num_profiles = 2;
+               agc_params->ant_mask1 = ANT_MASK(2);
+               agc_params->ant_mask2 = ANT_MASK(cl_hw->num_antennas - 2) << 2;
+
+#ifdef __BIG_ENDIAN_BITFIELD
+               agc_profile_to_le32(&agc_params->profile1);
+               agc_profile_to_le32(&agc_params->profile2);
+#endif
+       }
+
+       return 0;
+}
+
+static void _cl_agc_params_dump(struct cl_hw *cl_hw, char **buf, int *len,
+                               ssize_t *buf_size, struct cl_agc_profile *agc_table)
+{
+       cl_snprintf(buf, len, buf_size,
+                   "|------------------------------------------------------|\n"
+                   "| Addr  | Name               | Mask       | Value      |\n"
+                   "|-------+--------------------+------------+------------|\n");
+
+       cl_snprintf(buf, len, buf_size,
+                   "| 0x244 | fsm_preset_p2      | 0x%08x | 0x%08x |\n",
+                   agc_table->fsm_preset_p2.mask, agc_table->fsm_preset_p2.val);
+       cl_snprintf(buf, len, buf_size,
+                   "| 0x25C | lna_thr_set0_ref2  | 0x%08x | 0x%08x |\n",
+                   agc_table->lna_thr_set0_ref2.mask, agc_table->lna_thr_set0_ref2.val);
+       cl_snprintf(buf, len, buf_size,
+                   "| 0x260 | lna_thr_set0_ref3  | 0x%08x | 0x%08x |\n",
+                   agc_table->lna_thr_set0_ref3.mask, agc_table->lna_thr_set0_ref3.val);
+       cl_snprintf(buf, len, buf_size,
+                   "| 0x264 | lna_thr_set1_ref2  | 0x%08x | 0x%08x |\n",
+                   agc_table->lna_thr_set1_ref2.mask, agc_table->lna_thr_set1_ref2.val);
+       cl_snprintf(buf, len, buf_size,
+                   "| 0x268 | lna_thr_set1_ref3  | 0x%08x | 0x%08x |\n",
+                   agc_table->lna_thr_set1_ref3.mask, agc_table->lna_thr_set1_ref3.val);
+       cl_snprintf(buf, len, buf_size,
+                   "| 0x26C | lna_thr_set2_ref2  | 0x%08x | 0x%08x |\n",
+                   agc_table->lna_thr_set2_ref2.mask, agc_table->lna_thr_set2_ref2.val);
+       cl_snprintf(buf, len, buf_size,
+                   "| 0x270 | lna_thr_set2_ref3  | 0x%08x | 0x%08x |\n",
+                   agc_table->lna_thr_set2_ref3.mask, agc_table->lna_thr_set2_ref3.val);
+       cl_snprintf(buf, len, buf_size,
+                   "| 0x274 | lna_gain_set0_ref2 | 0x%08x | 0x%08x |\n",
+                   agc_table->lna_gain_set0_ref2.mask, agc_table->lna_gain_set0_ref2.val);
+       cl_snprintf(buf, len, buf_size,
+                   "| 0x278 | lna_gain_set0_ref3 | 0x%08x | 0x%08x |\n",
+                   agc_table->lna_gain_set0_ref3.mask, agc_table->lna_gain_set0_ref3.val);
+       cl_snprintf(buf, len, buf_size,
+                   "| 0x27C | lna_nf_set0_ref2   | 0x%08x | 0x%08x |\n",
+                   agc_table->lna_nf_set0_ref2.mask, agc_table->lna_nf_set0_ref2.val);
+       cl_snprintf(buf, len, buf_size,
+                   "| 0x280 | lna_nf_set0_ref3   | 0x%08x | 0x%08x |\n",
+                   agc_table->lna_nf_set0_ref3.mask, agc_table->lna_nf_set0_ref3.val);
+       cl_snprintf(buf, len, buf_size,
+                   "| 0x284 | lna_icp1_set0_ref2 | 0x%08x | 0x%08x |\n",
+                   agc_table->lna_icp1_set0_ref2.mask, agc_table->lna_icp1_set0_ref2.val);
+       cl_snprintf(buf, len, buf_size,
+                   "| 0x288 | lna_icp1_set0_ref3 | 0x%08x | 0x%08x |\n",
+                   agc_table->lna_icp1_set0_ref3.mask, agc_table->lna_icp1_set0_ref3.val);
+       cl_snprintf(buf, len, buf_size,
+                   "| 0x2A8 | fsm_preset_p10     | 0x%08x | 0x%08x |\n",
+                   agc_table->fsm_preset_p10.mask, agc_table->fsm_preset_p10.val);
+       cl_snprintf(buf, len, buf_size,
+                   "| 0x2AC | fsm_preset_p11     | 0x%08x | 0x%08x |\n",
+                   agc_table->fsm_preset_p11.mask, agc_table->fsm_preset_p11.val);
+       cl_snprintf(buf, len, buf_size,
+                   "| 0x2B0 | fsm_preset_p12     | 0x%08x | 0x%08x |\n",
+                   agc_table->fsm_preset_p12.mask, agc_table->fsm_preset_p12.val);
+       cl_snprintf(buf, len, buf_size,
+                   "| 0x300 | ant_loss           | 0x%08x | 0x%08x |\n",
+                   agc_table->ant_loss.mask, agc_table->ant_loss.val);
+       cl_snprintf(buf, len, buf_size,
+                   "| 0x304 | gain_range         | 0x%08x | 0x%08x |\n",
+                   agc_table->gain_range.mask, agc_table->gain_range.val);
+       cl_snprintf(buf, len, buf_size,
+                   "| 0x308 | vga_ref0           | 0x%08x | 0x%08x |\n",
+                   agc_table->vga_ref0.mask, agc_table->vga_ref0.val);
+       cl_snprintf(buf, len, buf_size,
+                   "| 0x30C | lna_gain_set0_ref0 | 0x%08x | 0x%08x |\n",
+                   agc_table->lna_gain_set0_ref0.mask, agc_table->lna_gain_set0_ref0.val);
+       cl_snprintf(buf, len, buf_size,
+                   "| 0x310 | lna_gain_set0_ref1 | 0x%08x | 0x%08x |\n",
+                   agc_table->lna_gain_set0_ref1.mask, agc_table->lna_gain_set0_ref1.val);
+       cl_snprintf(buf, len, buf_size,
+                   "| 0x314 | lna_thr_set0_ref0  | 0x%08x | 0x%08x |\n",
+                   agc_table->lna_thr_set0_ref0.mask, agc_table->lna_thr_set0_ref0.val);
+       cl_snprintf(buf, len, buf_size,
+                   "| 0x318 | lna_thr_set0_ref1  | 0x%08x | 0x%08x |\n",
+                   agc_table->lna_thr_set0_ref1.mask, agc_table->lna_thr_set0_ref1.val);
+       cl_snprintf(buf, len, buf_size,
+                   "| 0x31C | lna_thr_set1_ref0  | 0x%08x | 0x%08x |\n",
+                   agc_table->lna_thr_set1_ref0.mask, agc_table->lna_thr_set1_ref0.val);
+       cl_snprintf(buf, len, buf_size,
+                   "| 0x320 | lna_thr_set1_ref1  | 0x%08x | 0x%08x |\n",
+                   agc_table->lna_thr_set1_ref1.mask, agc_table->lna_thr_set1_ref1.val);
+       cl_snprintf(buf, len, buf_size,
+                   "| 0x324 | lna_thr_set2_ref0  | 0x%08x | 0x%08x |\n",
+                   agc_table->lna_thr_set2_ref0.mask, agc_table->lna_thr_set2_ref0.val);
+       cl_snprintf(buf, len, buf_size,
+                   "| 0x328 | lna_thr_set2_ref1  | 0x%08x | 0x%08x |\n",
+                   agc_table->lna_thr_set2_ref1.mask, agc_table->lna_thr_set2_ref1.val);
+       cl_snprintf(buf, len, buf_size,
+                   "| 0x32C | lna_nf_set0_ref0   | 0x%08x | 0x%08x |\n",
+                   agc_table->lna_nf_set0_ref0.mask, agc_table->lna_nf_set0_ref0.val);
+       cl_snprintf(buf, len, buf_size,
+                   "| 0x330 | lna_nf_set0_ref1   | 0x%08x | 0x%08x |\n",
+                   agc_table->lna_nf_set0_ref1.mask, agc_table->lna_nf_set0_ref1.val);
+       cl_snprintf(buf, len, buf_size,
+                   "| 0x334 | lna_icp1_set0_ref0 | 0x%08x | 0x%08x |\n",
+                   agc_table->lna_icp1_set0_ref0.mask, agc_table->lna_icp1_set0_ref0.val);
+       cl_snprintf(buf, len, buf_size,
+                   "| 0x338 | lna_icp1_set0_ref1 | 0x%08x | 0x%08x |\n",
+                   agc_table->lna_icp1_set0_ref1.mask, agc_table->lna_icp1_set0_ref1.val);
+       cl_snprintf(buf, len, buf_size,
+                   "| 0x364 | saturation          | 0x%08x | 0x%08x |\n",
+                   agc_table->saturation.mask, agc_table->saturation.val);
+       cl_snprintf(buf, len, buf_size,
+                   "| 0x36C | ramp               | 0x%08x | 0x%08x |\n",
+                   agc_table->ramp.mask, agc_table->ramp.val);
+       cl_snprintf(buf, len, buf_size,
+                   "| 0x394 | dsp0               | 0x%08x | 0x%08x |\n",
+                   agc_table->dsp0.mask, agc_table->dsp0.val);
+       cl_snprintf(buf, len, buf_size,
+                   "| 0x398 | dsp1               | 0x%08x | 0x%08x |\n",
+                   agc_table->dsp1.mask, agc_table->dsp1.val);
+       cl_snprintf(buf, len, buf_size,
+                   "| 0x39C | dsp2               | 0x%08x | 0x%08x |\n",
+                   agc_table->dsp2.mask, agc_table->dsp2.val);
+       cl_snprintf(buf, len, buf_size,
+                   "| 0x3A0 | dsp3               | 0x%08x | 0x%08x |\n",
+                   agc_table->dsp3.mask, agc_table->dsp3.val);
+       cl_snprintf(buf, len, buf_size,
+                   "| 0x590 | lna_gain_set1_ref0 | 0x%08x | 0x%08x |\n",
+                   agc_table->lna_gain_set1_ref0.mask,
+                   agc_table->lna_gain_set1_ref0.val);
+       cl_snprintf(buf, len, buf_size,
+                   "| 0x594 | lna_gain_set1_ref1 | 0x%08x | 0x%08x |\n",
+                   agc_table->lna_gain_set1_ref1.mask,
+                   agc_table->lna_gain_set1_ref1.val);
+       cl_snprintf(buf, len, buf_size,
+                   "| 0x598 | lna_gain_set1_ref2 | 0x%08x | 0x%08x |\n",
+                   agc_table->lna_gain_set1_ref2.mask,
+                   agc_table->lna_gain_set1_ref2.val);
+       cl_snprintf(buf, len, buf_size,
+                   "| 0x59C | lna_gain_set1_ref3 | 0x%08x | 0x%08x |\n",
+                   agc_table->lna_gain_set1_ref3.mask,
+                   agc_table->lna_gain_set1_ref3.val);
+       cl_snprintf(buf, len, buf_size,
+                   "| 0x5A0 | lna_nf_set1_ref0   | 0x%08x | 0x%08x |\n",
+                   agc_table->lna_nf_set1_ref0.mask,
+                   agc_table->lna_nf_set1_ref0.val);
+       cl_snprintf(buf, len, buf_size,
+                   "| 0x5A4 | lna_nf_set1_ref1   | 0x%08x | 0x%08x |\n",
+                   agc_table->lna_nf_set1_ref1.mask,
+                   agc_table->lna_nf_set1_ref1.val);
+       cl_snprintf(buf, len, buf_size,
+                   "| 0x5A8 | lna_nf_set1_ref2   | 0x%08x | 0x%08x |\n",
+                   agc_table->lna_nf_set1_ref2.mask,
+                   agc_table->lna_nf_set1_ref2.val);
+       cl_snprintf(buf, len, buf_size,
+                   "| 0x5AC | lna_nf_set1_ref3   | 0x%08x | 0x%08x |\n",
+                   agc_table->lna_nf_set1_ref3.mask,
+                   agc_table->lna_nf_set1_ref3.val);
+       cl_snprintf(buf, len, buf_size,
+                   "| 0x5B0 | lna_icp1_set1_ref0 | 0x%08x | 0x%08x |\n",
+                   agc_table->lna_icp1_set1_ref0.mask,
+                   agc_table->lna_icp1_set1_ref0.val);
+       cl_snprintf(buf, len, buf_size,
+                   "| 0x5B4 | lna_icp1_set1_ref1 | 0x%08x | 0x%08x |\n",
+                   agc_table->lna_icp1_set1_ref1.mask,
+                   agc_table->lna_icp1_set1_ref1.val);
+       cl_snprintf(buf, len, buf_size,
+                   "| 0x5B8 | lna_icp1_set1_ref2 | 0x%08x | 0x%08x |\n",
+                   agc_table->lna_icp1_set1_ref2.mask,
+                   agc_table->lna_icp1_set1_ref2.val);
+       cl_snprintf(buf, len, buf_size,
+                   "| 0x5BC | lna_icp1_set1_ref3 | 0x%08x | 0x%08x |\n",
+                   agc_table->lna_icp1_set1_ref3.mask,
+                   agc_table->lna_icp1_set1_ref3.val);
+
+       cl_snprintf(buf, len, buf_size,
+                   "|------------------------------------------------------|\n");
+}
+
+static int cl_agc_params_dump(struct cl_hw *cl_hw)
+{
+       struct cl_agc_params *agc_params =
+                                       &cl_hw->phy_data_info.data->agc_params;
+       char *buf = NULL;
+       ssize_t buf_size;
+       int err = 0;
+       int len = 0;
+
+       if (agc_params->profile1.id) {
+               cl_snprintf(&buf, &len, &buf_size, "AGC Params [%ug]\n", cl_hw->conf->ci_band_num);
+               _cl_agc_params_dump(cl_hw, &buf, &len, &buf_size, &agc_params->profile1);
+       }
+
+       if (agc_params->profile2.id) {
+               cl_snprintf(&buf, &len, &buf_size, "AGC Params [%ug elastic]",
+                           cl_hw->conf->ci_band_num);
+               _cl_agc_params_dump(cl_hw, &buf, &len, &buf_size, &agc_params->profile2);
+       }
+
+       err = cl_vendor_reply(cl_hw, buf, len);
+       kfree(buf);
+
+       return err;
+}
+
+static int cl_agc_params_print_table(struct cl_hw *cl_hw)
+{
+       struct cl_agc_table *table;
+       u32 platform_id;
+       u8 i;
+       char *buf = NULL;
+       ssize_t buf_size;
+       int err = 0;
+       int len = 0;
+
+       for (i = 0; i < ARRAY_SIZE(agc_table); i++) {
+               table = &agc_table[i];
+               platform_id = table->platform_id;
+
+               cl_snprintf(&buf, &len, &buf_size,
+                           "------------------------------------------------------\n");
+               cl_snprintf(&buf, &len, &buf_size, "Table #%u\n", i);
+               cl_snprintf(&buf, &len, &buf_size,
+                           "------------------------------------------------------\n");
+               cl_snprintf(&buf, &len, &buf_size, "Platform ID: 0x%08x\n", platform_id);
+               cl_snprintf(&buf, &len, &buf_size, "  - Customer = 0x%04x\n",
+                           AGC_PLATFORM_CUSTOMER(platform_id));
+               cl_snprintf(&buf, &len, &buf_size, "  - Board = 0x%02x\n",
+                           AGC_PLATFORM_BOARD(platform_id));
+               cl_snprintf(&buf, &len, &buf_size, "  - Chip = 0x%x\n",
+                           AGC_PLATFORM_CHIP(platform_id));
+               cl_snprintf(&buf, &len, &buf_size, "Description:\n");
+               cl_snprintf(&buf, &len, &buf_size, "  - %s\n", table->platform_description);
+               cl_snprintf(&buf, &len, &buf_size, "AGC Profile:\n");
+
+               cl_agc_params_print_profile(&buf, &len, &buf_size, table->agc_profile[TCV0],
+                                           "  - TCV0 =");
+               cl_agc_params_print_profile(&buf, &len, &buf_size,
+                                           table->agc_profile[TCV1], "  - TCV1 =");
+               cl_agc_params_print_profile(&buf, &len, &buf_size,
+                                           table->agc_profile_elastic[TCV0],
+                                           "  - Elastic TCV0 =");
+               cl_agc_params_print_profile(&buf, &len, &buf_size,
+                                           table->agc_profile_elastic[TCV1],
+                                           "  - Elastic TCV1 =");
+               cl_agc_params_print_profile(&buf, &len, &buf_size,
+                                           table->agc_profile_sensing, "  - Sensing =");
+       }
+
+       err = cl_vendor_reply(cl_hw, buf, len);
+       kfree(buf);
+
+       return err;
+}
+
+void cl_agc_params_print_profile(char **buf, int *len, ssize_t *buf_size,
+                                struct cl_agc_profile *profile,
+                                const char *str)
+{
+       u32 id;
+       u8 band, branch, version;
+
+       if (!profile)
+               return;
+
+       id = profile->id;
+
+       if (id == 0)
+               return;
+
+       band = AGC_PROFILE_BAND(id);
+       branch = AGC_PROFILE_BRANCH(id);
+       version = AGC_PROFILE_VERSION(id);
+
+       if (*buf)
+               cl_snprintf(buf, len, buf_size, "%s %u.%u.%u\n", str, band, branch, version);
+       else
+               pr_debug("%s %u.%u.%u\n", str, band, branch, version);
+}
+
+static int cl_agc_params_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,
+                "agc_params usage:\n"
+                "-d : Dump AGC parameters\n"
+                "-t : Print AGC table\n");
+
+       err = cl_vendor_reply(cl_hw, buf, strlen(buf));
+       kfree(buf);
+
+       return err;
+}
+
+int cl_agc_params_cli(struct cl_hw *cl_hw, struct cli_params *cli_params)
+{
+       bool dump_params = false;
+       bool print_table = false;
+       u32 expected_params = -1;
+
+       switch (cli_params->option) {
+       case 'd':
+               dump_params = true;
+               expected_params = 0;
+               break;
+       case 't':
+               print_table = true;
+               expected_params = 0;
+               break;
+       case '?':
+               return cl_agc_params_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 (dump_params)
+               return cl_agc_params_dump(cl_hw);
+
+       if (print_table)
+               return cl_agc_params_print_table(cl_hw);
+
+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.
________________________________


^ permalink raw reply related	[flat|nested] 262+ messages in thread

* [RFC v1 008/256] cl8k: add agc_params.h
  2021-06-17 15:58 [RFC v1 000/256] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (6 preceding siblings ...)
  2021-06-17 15:58 ` [RFC v1 007/256] cl8k: add agc_params.c viktor.barna
@ 2021-06-17 15:58 ` viktor.barna
  2021-06-17 15:58 ` [RFC v1 009/256] cl8k: add ampdu.c viktor.barna
                   ` (249 subsequent siblings)
  257 siblings, 0 replies; 262+ messages in thread
From: viktor.barna @ 2021-06-17 15:58 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Oleksandr Savchenko, Shay Bar, Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

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

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 drivers/net/wireless/celeno/cl8k/agc_params.h | 151 ++++++++++++++++++
 1 file changed, 151 insertions(+)
 create mode 100644 drivers/net/wireless/celeno/cl8k/agc_params.h

diff --git a/drivers/net/wireless/celeno/cl8k/agc_params.h b/drivers/net/wireless/celeno/cl8k/agc_params.h
new file mode 100644
index 000000000000..e0f5816d6e07
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/agc_params.h
@@ -0,0 +1,151 @@
+/* SPDX-License-Identifier: MIT */
+/* Copyright(c) 2019-2021, Celeno Communications Ltd. */
+
+#ifndef CL_AGC_PARAMS_H
+#define CL_AGC_PARAMS_H
+
+#include <linux/types.h>
+#include <linux/bitfield.h>
+#include "def.h"
+#include "vendor_cmd.h"
+
+/**
+ * AGC (=Automatic Gain Control)
+ */
+
+/* AGC PROFILE */
+#define AGC_PROFILE_BAND_OFFSET     28
+#define AGC_PROFILE_BAND_MASK       0xf0000000
+#define AGC_PROFILE_BRANCH_OFFSET   20
+#define AGC_PROFILE_BRANCH_MASK     0x0ff00000
+#define AGC_PROFILE_VERSION_OFFSET  12
+#define AGC_PROFILE_VERSION_MASK    0x000ff000
+#define AGC_PROFILE_RESERVED_OFFSET 0
+#define AGC_PROFILE_RESERVED_MASK   0x00000fff
+
+#define AGC_PROFILE(band, branch, version) \
+       (((band) << AGC_PROFILE_BAND_OFFSET) | \
+        ((branch) << AGC_PROFILE_BRANCH_OFFSET) | \
+        ((version) << AGC_PROFILE_VERSION_OFFSET))
+
+#define AGC_PROFILE_BAND(profile) \
+       u32_get_bits(profile, AGC_PROFILE_BAND_MASK)
+#define AGC_PROFILE_BRANCH(profile) \
+       u32_get_bits(profile, AGC_PROFILE_BRANCH_MASK)
+#define AGC_PROFILE_VERSION(profile) \
+       u32_get_bits(profile, AGC_PROFILE_VERSION_MASK)
+
+/* AGC PLATFORM */
+#define AGC_PLATFORM_CUSTOMER_OFFSET 16
+#define AGC_PLATFORM_CUSTOMER_MASK   0xffff0000
+#define AGC_PLATFORM_BOARD_OFFSET    8
+#define AGC_PLATFORM_BOARD_MASK      0x0000ff00
+#define AGC_PLATFORM_CHIP_OFFSET     4
+#define AGC_PLATFORM_CHIP_MASK       0x000000f0
+#define AGC_PLATFORM_RESERVED_OFFSET 0
+#define AGC_PLATFORM_RESERVED_MASK   0x0000000f
+
+#define AGC_PLATFORM(customer, board, chip) \
+       (((customer) << AGC_PLATFORM_CUSTOMER_OFFSET) | \
+        ((board) << AGC_PLATFORM_BOARD_OFFSET) | \
+        ((chip) << AGC_PLATFORM_CHIP_OFFSET))
+
+#define AGC_PLATFORM_CUSTOMER(platform) \
+       u32_get_bits(platform, AGC_PLATFORM_CUSTOMER_MASK)
+#define AGC_PLATFORM_BOARD(platform) \
+       u32_get_bits(platform, AGC_PLATFORM_BOARD_MASK)
+#define AGC_PLATFORM_CHIP(platform) \
+       u32_get_bits(platform, AGC_PLATFORM_CHIP_MASK)
+
+enum cl_customer_list {
+       CL_CUSTOMER_CELENO = 0,
+};
+
+enum cl_board_list {
+       /* Board list for Celeno customer */
+       CL_BOARD_EVB = 0,
+       /* Values from 1 to 5 are reserved */
+       CL_BOARD_MERLIN = 6,
+       CL_BOARD_EVB_6G = 7,
+       CL_BOARD_ALBATROSS = 8,
+       CL_BOARD_ALBATROSS_2 = 9,
+       CL_BOARD_CHAMELEON = 10,
+};
+
+struct cl_agc_reg {
+       u32 val;
+       u32 mask;
+};
+
+struct cl_agc_profile {
+       u32 id;
+       struct cl_agc_reg fsm_preset_p2;      /* 0x244 */
+       struct cl_agc_reg lna_thr_set0_ref2;  /* 0x25C */
+       struct cl_agc_reg lna_thr_set0_ref3;  /* 0x260 */
+       struct cl_agc_reg lna_thr_set1_ref2;  /* 0x264 */
+       struct cl_agc_reg lna_thr_set1_ref3;  /* 0x268 */
+       struct cl_agc_reg lna_thr_set2_ref2;  /* 0x26C */
+       struct cl_agc_reg lna_thr_set2_ref3;  /* 0x270 */
+       struct cl_agc_reg lna_gain_set0_ref2; /* 0x274 */
+       struct cl_agc_reg lna_gain_set0_ref3; /* 0x278 */
+       struct cl_agc_reg lna_nf_set0_ref2;   /* 0x27C */
+       struct cl_agc_reg lna_nf_set0_ref3;   /* 0x280 */
+       struct cl_agc_reg lna_icp1_set0_ref2; /* 0x284 */
+       struct cl_agc_reg lna_icp1_set0_ref3; /* 0x288 */
+       struct cl_agc_reg fsm_preset_p10;     /* 0x2A8 */
+       struct cl_agc_reg fsm_preset_p11;     /* 0x2AC */
+       struct cl_agc_reg fsm_preset_p12;     /* 0x2B0 */
+       struct cl_agc_reg ant_loss;           /* 0x300 */
+       struct cl_agc_reg gain_range;         /* 0x304 */
+       struct cl_agc_reg vga_ref0;           /* 0x308 */
+       struct cl_agc_reg lna_gain_set0_ref0; /* 0x30C */
+       struct cl_agc_reg lna_gain_set0_ref1; /* 0x310 */
+       struct cl_agc_reg lna_thr_set0_ref0;  /* 0x314 */
+       struct cl_agc_reg lna_thr_set0_ref1;  /* 0x318 */
+       struct cl_agc_reg lna_thr_set1_ref0;  /* 0x31C */
+       struct cl_agc_reg lna_thr_set1_ref1;  /* 0x320 */
+       struct cl_agc_reg lna_thr_set2_ref0;  /* 0x324 */
+       struct cl_agc_reg lna_thr_set2_ref1;  /* 0x328 */
+       struct cl_agc_reg lna_nf_set0_ref0;   /* 0x32C */
+       struct cl_agc_reg lna_nf_set0_ref1;   /* 0x330 */
+       struct cl_agc_reg lna_icp1_set0_ref0; /* 0x334 */
+       struct cl_agc_reg lna_icp1_set0_ref1; /* 0x338 */
+       struct cl_agc_reg saturation;         /* 0x364 */
+       struct cl_agc_reg ramp;               /* 0x36C */
+       struct cl_agc_reg dsp0;               /* 0x394 */
+       struct cl_agc_reg dsp1;               /* 0x398 */
+       struct cl_agc_reg dsp2;               /* 0x39C */
+       struct cl_agc_reg dsp3;               /* 0x3A0 */
+       struct cl_agc_reg lna_gain_set1_ref0; /* 0x590 */
+       struct cl_agc_reg lna_gain_set1_ref1; /* 0x594 */
+       struct cl_agc_reg lna_gain_set1_ref2; /* 0x598 */
+       struct cl_agc_reg lna_gain_set1_ref3; /* 0x59c */
+       struct cl_agc_reg lna_nf_set1_ref0;   /* 0x5A0 */
+       struct cl_agc_reg lna_nf_set1_ref1;   /* 0x5A4 */
+       struct cl_agc_reg lna_nf_set1_ref2;   /* 0x5A8 */
+       struct cl_agc_reg lna_nf_set1_ref3 ;  /* 0x5AC */
+       struct cl_agc_reg lna_icp1_set1_ref0; /* 0x5B0 */
+       struct cl_agc_reg lna_icp1_set1_ref1; /* 0x5B4 */
+       struct cl_agc_reg lna_icp1_set1_ref2; /* 0x5B8 */
+       struct cl_agc_reg lna_icp1_set1_ref3 ;/* 0x5BC */
+};
+
+struct cl_agc_params {
+       u8 num_profiles;
+       u8 ant_mask1;
+       u8 ant_mask2;
+       struct cl_agc_profile profile1;
+       struct cl_agc_profile profile2;
+};
+
+struct cl_chip;
+struct cl_hw;
+
+int cl_agc_params_read_platform_id(struct cl_chip *chip);
+int cl_agc_params_fill(struct cl_hw *cl_hw, struct cl_agc_params *agc_params);
+void cl_agc_params_print_profile(char **buf, int *len, ssize_t *buf_size,
+                                struct cl_agc_profile *profile,
+                                const char *str);
+int cl_agc_params_cli(struct cl_hw *cl_hw, struct cli_params *cli_params);
+
+#endif /* CL_AGC_PARAMS_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.
________________________________


^ permalink raw reply related	[flat|nested] 262+ messages in thread

* [RFC v1 009/256] cl8k: add ampdu.c
  2021-06-17 15:58 [RFC v1 000/256] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (7 preceding siblings ...)
  2021-06-17 15:58 ` [RFC v1 008/256] cl8k: add agc_params.h viktor.barna
@ 2021-06-17 15:58 ` viktor.barna
  2021-06-17 15:58 ` [RFC v1 010/256] cl8k: add ampdu.h viktor.barna
                   ` (248 subsequent siblings)
  257 siblings, 0 replies; 262+ messages in thread
From: viktor.barna @ 2021-06-17 15:58 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Oleksandr Savchenko, Shay Bar, Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

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

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 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.
________________________________


^ permalink raw reply related	[flat|nested] 262+ messages in thread

* [RFC v1 010/256] cl8k: add ampdu.h
  2021-06-17 15:58 [RFC v1 000/256] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (8 preceding siblings ...)
  2021-06-17 15:58 ` [RFC v1 009/256] cl8k: add ampdu.c viktor.barna
@ 2021-06-17 15:58 ` viktor.barna
  2021-06-17 15:58 ` [RFC v1 011/256] cl8k: add ate.c viktor.barna
                   ` (247 subsequent siblings)
  257 siblings, 0 replies; 262+ messages in thread
From: viktor.barna @ 2021-06-17 15:58 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Oleksandr Savchenko, Shay Bar, Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

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

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 drivers/net/wireless/celeno/cl8k/ampdu.h | 45 ++++++++++++++++++++++++
 1 file changed, 45 insertions(+)
 create mode 100644 drivers/net/wireless/celeno/cl8k/ampdu.h

diff --git a/drivers/net/wireless/celeno/cl8k/ampdu.h b/drivers/net/wireless/celeno/cl8k/ampdu.h
new file mode 100644
index 000000000000..8b1cdd35dbbb
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/ampdu.h
@@ -0,0 +1,45 @@
+/* SPDX-License-Identifier: MIT */
+/* Copyright(c) 2019-2021, Celeno Communications Ltd. */
+
+#ifndef CL_AMPDU_H
+#define CL_AMPDU_H
+
+#include "sta.h"
+
+int cl_ampdu_rx_start(struct cl_hw *cl_hw,
+                     struct cl_sta *cl_sta,
+                     u16 tid,
+                     u16 ssn,
+                     u16 buf_size);
+
+void cl_ampdu_rx_stop(struct cl_hw *cl_hw,
+                     struct cl_sta *cl_sta,
+                     u16 tid);
+
+int cl_ampdu_tx_start(struct cl_hw *cl_hw,
+                     struct ieee80211_vif *vif,
+                     struct cl_sta *cl_sta,
+                     u16 tid,
+                     u16 ssn);
+
+int cl_ampdu_tx_operational(struct cl_hw *hw,
+                           struct cl_sta *cl_sta,
+                           u16 tid,
+                           u16 buf_size,
+                           bool amsdu_supported);
+
+void _cl_ampdu_tx_stop(struct cl_hw *cl_hw,
+                      struct cl_tx_queue *tx_queue,
+                      struct cl_sta *cl_sta,
+                      u8 tid);
+
+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);
+
+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);
+
+#endif /* CL_AMPDU_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.
________________________________


^ permalink raw reply related	[flat|nested] 262+ messages in thread

* [RFC v1 011/256] cl8k: add ate.c
  2021-06-17 15:58 [RFC v1 000/256] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (9 preceding siblings ...)
  2021-06-17 15:58 ` [RFC v1 010/256] cl8k: add ampdu.h viktor.barna
@ 2021-06-17 15:58 ` viktor.barna
  2021-06-17 15:58 ` [RFC v1 012/256] cl8k: add ate.h viktor.barna
                   ` (246 subsequent siblings)
  257 siblings, 0 replies; 262+ messages in thread
From: viktor.barna @ 2021-06-17 15:58 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Oleksandr Savchenko, Shay Bar, Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

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

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 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.
________________________________


^ permalink raw reply related	[flat|nested] 262+ messages in thread

* [RFC v1 012/256] cl8k: add ate.h
  2021-06-17 15:58 [RFC v1 000/256] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (10 preceding siblings ...)
  2021-06-17 15:58 ` [RFC v1 011/256] cl8k: add ate.c viktor.barna
@ 2021-06-17 15:58 ` viktor.barna
  2021-06-17 15:58 ` [RFC v1 013/256] cl8k: add band.c viktor.barna
                   ` (245 subsequent siblings)
  257 siblings, 0 replies; 262+ messages in thread
From: viktor.barna @ 2021-06-17 15:58 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Oleksandr Savchenko, Shay Bar, Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

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

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 drivers/net/wireless/celeno/cl8k/ate.h | 90 ++++++++++++++++++++++++++
 1 file changed, 90 insertions(+)
 create mode 100644 drivers/net/wireless/celeno/cl8k/ate.h

diff --git a/drivers/net/wireless/celeno/cl8k/ate.h b/drivers/net/wireless/celeno/cl8k/ate.h
new file mode 100644
index 000000000000..ae9ea58b1a01
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/ate.h
@@ -0,0 +1,90 @@
+/* SPDX-License-Identifier: MIT */
+/* Copyright(c) 2019-2021, Celeno Communications Ltd. */
+
+#ifndef CL_ATE_H
+#define CL_ATE_H
+
+#include "hw.h"
+
+/**
+ * DOC: ATE (=Automatic Test Equipment)
+ *
+ * Routines, that may be helpful in pre/post production stages to verify
+ * validity of the chip behavior.
+ */
+
+int cl_ate_reset(struct wiphy *wiphy, struct wireless_dev *wdev,
+                const void *data, int data_len);
+int cl_ate_mode(struct wiphy *wiphy, struct wireless_dev *wdev,
+               const void *data, int data_len);
+int cl_ate_bw(struct wiphy *wiphy, struct wireless_dev *wdev,
+             const void *data, int data_len);
+int cl_ate_mcs(struct wiphy *wiphy, struct wireless_dev *wdev,
+              const void *data, int data_len);
+int cl_ate_nss(struct wiphy *wiphy, struct wireless_dev *wdev,
+              const void *data, int data_len);
+int cl_ate_gi(struct wiphy *wiphy, struct wireless_dev *wdev,
+             const void *data, int data_len);
+int cl_ate_ltf(struct wiphy *wiphy, struct wireless_dev *wdev,
+              const void *data, int data_len);
+int cl_ate_ldpc(struct wiphy *wiphy, struct wireless_dev *wdev,
+               const void *data, int data_len);
+int cl_ate_channel(struct wiphy *wiphy, struct wireless_dev *wdev,
+                  const void *data, int data_len);
+int cl_ate_ant(struct wiphy *wiphy, struct wireless_dev *wdev,
+              const void *data, int data_len);
+int cl_ate_multi_ant(struct wiphy *wiphy, struct wireless_dev *wdev,
+                    const void *data, int data_len);
+int cl_ate_packet_len(struct wiphy *wiphy, struct wireless_dev *wdev,
+                     const void *data, int data_len);
+int cl_ate_vector(struct wiphy *wiphy, struct wireless_dev *wdev,
+                 const void *data, int data_len);
+int cl_ate_vector_reset(struct wiphy *wiphy, struct wireless_dev *wdev,
+                       const void *data, int data_len);
+int cl_ate_freq_offset(struct wiphy *wiphy, struct wireless_dev *wdev,
+                      const void *data, int data_len);
+int cl_ate_stat(struct wiphy *wiphy, struct wireless_dev *wdev,
+               const void *data, int data_len);
+int cl_ate_stat_reset(struct wiphy *wiphy, struct wireless_dev *wdev,
+                     const void *data, int data_len);
+int cl_ate_power(struct wiphy *wiphy, struct wireless_dev *wdev,
+                const void *data, int data_len);
+int cl_ate_power_offset(struct wiphy *wiphy, struct wireless_dev *wdev,
+                       const void *data, int data_len);
+int cl_ate_tx_start(struct wiphy *wiphy, struct wireless_dev *wdev,
+                   const void *data, int data_len);
+int cl_ate_tx_continuous(struct wiphy *wiphy, struct wireless_dev *wdev,
+                        const void *data, int data_len);
+int cl_ate_stop(struct wiphy *wiphy, struct wireless_dev *wdev,
+               const void *data, int data_len);
+int cl_ate_help(struct wiphy *wiphy, struct wireless_dev *wdev,
+               const void *data, int data_len);
+
+enum cl_ate_cmd {
+       CL_ATE_RESET,
+       CL_ATE_MODE,
+       CL_ATE_BW,
+       CL_ATE_MCS,
+       CL_ATE_NSS,
+       CL_ATE_GI,
+       CL_ATE_LTF,
+       CL_ATE_LDPC,
+       CL_ATE_CHANNEL,
+       CL_ATE_ANT,
+       CL_ATE_MULTI_ANT,
+       CL_ATE_PACKET_LEN,
+       CL_ATE_VECTOR_RESET,
+       CL_ATE_VECTOR,
+       CL_ATE_FREQ_OFFSET,
+       CL_ATE_STAT_RESET,
+       CL_ATE_STAT,
+       CL_ATE_POWER,
+       CL_ATE_POWER_OFFSET,
+       CL_ATE_TX_START,
+       CL_ATE_TX_CONTINUOUS,
+       CL_ATE_STOP,
+
+       CL_ATE_MAX
+};
+
+#endif /* CL_ATE_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.
________________________________


^ permalink raw reply related	[flat|nested] 262+ messages in thread

* [RFC v1 013/256] cl8k: add band.c
  2021-06-17 15:58 [RFC v1 000/256] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (11 preceding siblings ...)
  2021-06-17 15:58 ` [RFC v1 012/256] cl8k: add ate.h viktor.barna
@ 2021-06-17 15:58 ` viktor.barna
  2021-06-17 15:58 ` [RFC v1 014/256] cl8k: add band.h viktor.barna
                   ` (244 subsequent siblings)
  257 siblings, 0 replies; 262+ messages in thread
From: viktor.barna @ 2021-06-17 15:58 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Oleksandr Savchenko, Shay Bar, Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

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

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 drivers/net/wireless/celeno/cl8k/band.c | 60 +++++++++++++++++++++++++
 1 file changed, 60 insertions(+)
 create mode 100644 drivers/net/wireless/celeno/cl8k/band.c

diff --git a/drivers/net/wireless/celeno/cl8k/band.c b/drivers/net/wireless/celeno/cl8k/band.c
new file mode 100644
index 000000000000..6fc688613a51
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/band.c
@@ -0,0 +1,60 @@
+// SPDX-License-Identifier: MIT
+/* Copyright(c) 2019-2021, Celeno Communications Ltd. */
+
+#include "band.h"
+
+bool cl_band_is_6g(struct cl_hw *cl_hw)
+{
+       return (cl_hw->conf->ci_band_num == 6);
+}
+
+bool cl_band_is_6g_freq(u16 freq)
+{
+       return (freq > 5935) ? true : false;
+}
+
+bool cl_band_is_5g(struct cl_hw *cl_hw)
+{
+       return (cl_hw->conf->ci_band_num == 5);
+}
+
+bool cl_band_is_5g_freq(u16 freq)
+{
+       return (freq > 5000 && freq <= 5835) ? true : false;
+}
+
+bool cl_band_is_24g(struct cl_hw *cl_hw)
+{
+       return (cl_hw->conf->ci_band_num == 24);
+}
+
+bool cl_band_is_24g_freq(u16 freq)
+{
+       return (freq < 5000) ? true : false;
+}
+
+u8 cl_band_to_fw_idx(struct cl_hw *cl_hw)
+{
+       if (cl_hw->nl_band == NL80211_BAND_6GHZ)
+               return FW_BAND_6GHZ;
+
+       if (cl_hw->nl_band == NL80211_BAND_5GHZ)
+               return FW_BAND_5GHZ;
+
+       return FW_BAND_2GHZ;
+}
+
+static u8 fw_to_nl_band[FW_BAND_MAX] = {
+       [FW_BAND_6GHZ] = NL80211_BAND_6GHZ,
+       [FW_BAND_5GHZ] = NL80211_BAND_5GHZ,
+       [FW_BAND_2GHZ] = NL80211_BAND_2GHZ,
+};
+
+u8 cl_band_from_fw_idx(u32 phy_band)
+{
+       if (phy_band < FW_BAND_MAX)
+               return fw_to_nl_band[phy_band];
+
+       return FW_BAND_MAX;
+}
+
--
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.
________________________________


^ permalink raw reply related	[flat|nested] 262+ messages in thread

* [RFC v1 014/256] cl8k: add band.h
  2021-06-17 15:58 [RFC v1 000/256] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (12 preceding siblings ...)
  2021-06-17 15:58 ` [RFC v1 013/256] cl8k: add band.c viktor.barna
@ 2021-06-17 15:58 ` viktor.barna
  2021-06-17 15:58 ` [RFC v1 015/256] cl8k: add bf.c viktor.barna
                   ` (243 subsequent siblings)
  257 siblings, 0 replies; 262+ messages in thread
From: viktor.barna @ 2021-06-17 15:58 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Oleksandr Savchenko, Shay Bar, Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

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

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 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.
________________________________


^ permalink raw reply related	[flat|nested] 262+ messages in thread

* [RFC v1 015/256] cl8k: add bf.c
  2021-06-17 15:58 [RFC v1 000/256] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (13 preceding siblings ...)
  2021-06-17 15:58 ` [RFC v1 014/256] cl8k: add band.h viktor.barna
@ 2021-06-17 15:58 ` viktor.barna
  2021-06-17 15:58 ` [RFC v1 016/256] cl8k: add bf.h viktor.barna
                   ` (242 subsequent siblings)
  257 siblings, 0 replies; 262+ messages in thread
From: viktor.barna @ 2021-06-17 15:58 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Oleksandr Savchenko, Shay Bar, Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

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

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 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.
________________________________


^ permalink raw reply related	[flat|nested] 262+ messages in thread

* [RFC v1 016/256] cl8k: add bf.h
  2021-06-17 15:58 [RFC v1 000/256] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (14 preceding siblings ...)
  2021-06-17 15:58 ` [RFC v1 015/256] cl8k: add bf.c viktor.barna
@ 2021-06-17 15:58 ` viktor.barna
  2021-06-17 15:58 ` [RFC v1 017/256] cl8k: add bus/pci/ipc.c viktor.barna
                   ` (241 subsequent siblings)
  257 siblings, 0 replies; 262+ messages in thread
From: viktor.barna @ 2021-06-17 15:58 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Oleksandr Savchenko, Shay Bar, Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

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

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 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.
________________________________


^ permalink raw reply related	[flat|nested] 262+ messages in thread

* [RFC v1 017/256] cl8k: add bus/pci/ipc.c
  2021-06-17 15:58 [RFC v1 000/256] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (15 preceding siblings ...)
  2021-06-17 15:58 ` [RFC v1 016/256] cl8k: add bf.h viktor.barna
@ 2021-06-17 15:58 ` viktor.barna
  2021-06-17 15:58 ` [RFC v1 018/256] cl8k: add bus/pci/ipc.h viktor.barna
                   ` (240 subsequent siblings)
  257 siblings, 0 replies; 262+ messages in thread
From: viktor.barna @ 2021-06-17 15:58 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Oleksandr Savchenko, Shay Bar, Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

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

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 .../net/wireless/celeno/cl8k/bus/pci/ipc.c    | 1278 +++++++++++++++++
 1 file changed, 1278 insertions(+)
 create mode 100644 drivers/net/wireless/celeno/cl8k/bus/pci/ipc.c

diff --git a/drivers/net/wireless/celeno/cl8k/bus/pci/ipc.c b/drivers/net/wireless/celeno/cl8k/bus/pci/ipc.c
new file mode 100644
index 000000000000..c7ba5eb09be0
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/bus/pci/ipc.c
@@ -0,0 +1,1278 @@
+// SPDX-License-Identifier: MIT
+/* Copyright(c) 2019-2021, Celeno Communications Ltd. */
+
+#include <linux/dma-mapping.h>
+#include <linux/dmapool.h>
+
+#include "bus/pci/ipc.h"
+#include "rx/rx.h"
+#include "bus/pci/rx_pci.h"
+#include "tx/tx.h"
+#include "bus/pci/tx_pci.h"
+#include "bus/pci/irq.h"
+#include "fw/fw_dbg.h"
+#include "reg/reg_access.h"
+#include "reg/reg_ipc.h"
+#include "enhanced_tim.h"
+#include "fw/msg_rx.h"
+#include "dbgfile.h"
+#ifdef TRACE_SUPPORT
+#include "trace.h"
+#endif
+
+#define DMA_CFM_QUEUE_SIZE 1024
+#define DMA_CFM_TOTAL_SIZE (8 * sizeof(struct cl_ipc_cfm_msg) * DMA_CFM_QUEUE_SIZE)
+
+static void ipc_env_free(struct cl_hw *cl_hw)
+{
+       kfree(cl_hw->ipc_env);
+       cl_hw->ipc_env = NULL;
+}
+
+static void ring_indices_dealloc(struct cl_hw *cl_hw)
+{
+       struct cl_ipc_host_env *ipc_env = cl_hw->ipc_env;
+
+       if (!ipc_env->ring_indices_elem)
+               return;
+
+       memset(ipc_env->ring_indices_elem->indices, 0, sizeof(struct cl_ipc_ring_indices));
+       ipc_env->ring_indices_elem->indices = NULL;
+       kfree(ipc_env->ring_indices_elem);
+       ipc_env->ring_indices_elem = NULL;
+}
+
+static void _txdesc_dealloc(struct cl_hw *cl_hw,
+                           struct txdesc *txdesc,
+                           __le32 dma_addr,
+                           u32 desc_num)
+{
+       dma_addr_t phys_dma_addr = le32_to_cpu(dma_addr);
+       u32 size = (desc_num * sizeof(struct txdesc));
+
+       if (size < PAGE_SIZE)
+               dma_pool_free(cl_hw->txdesc_pool, txdesc, phys_dma_addr);
+       else
+               dma_free_coherent(cl_hw->chip->dev, size, txdesc, phys_dma_addr);
+}
+
+static void txdesc_dealloc(struct cl_hw *cl_hw)
+{
+       struct cl_ipc_tx_queues *tx_queues = &cl_hw->ipc_env->tx_queues;
+       struct tx_queues_dma_addr *queues_dma_addr = tx_queues->queues_dma_addr;
+       u32 i;
+
+       if (queues_dma_addr->bcmc) {
+               _txdesc_dealloc(cl_hw, tx_queues->ipc_txdesc_bcmc, queues_dma_addr->bcmc,
+                               IPC_TXDESC_CNT_BCMC);
+               queues_dma_addr->bcmc = 0;
+       }
+
+       for (i = 0; i < MAX_SINGLE_QUEUES; i++)
+               if (queues_dma_addr->single[i]) {
+                       _txdesc_dealloc(cl_hw, tx_queues->ipc_txdesc_single[i],
+                                       queues_dma_addr->single[i], IPC_TXDESC_CNT_SINGLE);
+                       queues_dma_addr->single[i] = 0;
+               }
+
+       for (i = 0; i < IPC_MAX_BA_SESSIONS; i++)
+               if (queues_dma_addr->agg[i]) {
+                       _txdesc_dealloc(cl_hw, tx_queues->ipc_txdesc_agg[i],
+                                       queues_dma_addr->agg[i], cl_hw->max_agg_tx_q_size);
+                       queues_dma_addr->agg[i] = 0;
+               }
+
+       dma_pool_destroy(cl_hw->txdesc_pool);
+       cl_hw->txdesc_pool = NULL;
+}
+
+static void tx_queues_dealloc(struct cl_hw *cl_hw)
+{
+       u32 len = sizeof(struct tx_queues_dma_addr);
+       dma_addr_t phys_dma_addr = cl_hw->ipc_env->tx_queues.dma_addr;
+
+       if (!cl_hw->ipc_env->tx_queues.queues_dma_addr)
+               return;
+
+       dma_free_coherent(cl_hw->chip->dev, len,
+                         (void *)cl_hw->ipc_env->tx_queues.queues_dma_addr,
+                         phys_dma_addr);
+       cl_hw->ipc_env->tx_queues.queues_dma_addr = NULL;
+}
+
+static void rx_dealloc_skb(struct cl_hw *cl_hw, struct cl_rx_elem *rx_elem,
+                          u16 len)
+{
+       dma_unmap_single(cl_hw->chip->dev, rx_elem->dma_addr, len,
+                        DMA_FROM_DEVICE);
+       kfree_skb(rx_elem->skb);
+       rx_elem->skb = NULL;
+}
+
+static void _rx_dealloc_buff(struct cl_hw *cl_hw,
+                            u32 *rxbuf,
+                            __le32 dma_addr,
+                            u32 desc_num)
+{
+       dma_addr_t phys_dma_addr = le32_to_cpu(dma_addr);
+       u32 size = (desc_num * sizeof(u32));
+
+       dma_free_coherent(cl_hw->chip->dev, size, rxbuf, phys_dma_addr);
+}
+
+static void rx_dealloc_buff(struct cl_hw *cl_hw)
+{
+       struct cl_ipc_host_env *ipc_env = cl_hw->ipc_env;
+       struct cl_ipc_host_rxbuf *rxbuf_rxm = &ipc_env->rx_hostbuf_array[CL_RX_BUF_RXM];
+       struct cl_ipc_host_rxbuf *rxbuf_fw = &ipc_env->rx_hostbuf_array[CL_RX_BUF_FW];
+
+       if (rxbuf_rxm->dma_payload_base_addr)
+               _rx_dealloc_buff(cl_hw,
+                                rxbuf_rxm->dma_payload_addr,
+                                rxbuf_rxm->dma_payload_base_addr,
+                                IPC_RXBUF_CNT_RXM);
+
+       if (rxbuf_fw->dma_payload_base_addr)
+               _rx_dealloc_buff(cl_hw,
+                                rxbuf_fw->dma_payload_addr,
+                                rxbuf_fw->dma_payload_base_addr,
+                                IPC_RXBUF_CNT_FW);
+}
+
+static void rx_dealloc(struct cl_hw *cl_hw)
+{
+       struct cl_rx_elem *rx_elem = cl_hw->rx_elems;
+       u16 rxbuf_size_rxm = cl_hw->conf->ci_ipc_rxbuf_size[CL_RX_BUF_RXM];
+       u16 rxbuf_size_fw = cl_hw->conf->ci_ipc_rxbuf_size[CL_RX_BUF_FW];
+       int i;
+
+       if (!cl_hw->rx_elems)
+               return;
+
+       for (i = 0; i < IPC_RXBUF_CNT_RXM; i++, rx_elem++)
+               if (rx_elem->skb && !rx_elem->passed)
+                       rx_dealloc_skb(cl_hw, rx_elem, rxbuf_size_rxm);
+
+       for (i = 0; i < IPC_RXBUF_CNT_FW; i++, rx_elem++)
+               if (rx_elem->skb && !rx_elem->passed)
+                       rx_dealloc_skb(cl_hw, rx_elem, rxbuf_size_fw);
+
+       kfree(cl_hw->rx_elems);
+       cl_hw->rx_elems = NULL;
+
+       rx_dealloc_buff(cl_hw);
+}
+
+static void msg_dealloc(struct cl_hw *cl_hw)
+{
+       struct cl_e2a_msg_elem *msg_elem;
+       int i;
+
+       if (!cl_hw->e2a_msg_elems || !cl_hw->e2a_msg_pool)
+               return;
+
+       for (i = 0, msg_elem = cl_hw->e2a_msg_elems;
+            i < IPC_E2A_MSG_BUF_CNT; i++, msg_elem++) {
+               if (msg_elem->msgbuf_ptr) {
+                       dma_pool_free(cl_hw->e2a_msg_pool, msg_elem->msgbuf_ptr,
+                                     msg_elem->dma_addr);
+                       msg_elem->msgbuf_ptr = NULL;
+               }
+       }
+
+       dma_pool_destroy(cl_hw->e2a_msg_pool);
+       cl_hw->e2a_msg_pool = NULL;
+
+       kfree(cl_hw->e2a_msg_elems);
+       cl_hw->e2a_msg_elems = NULL;
+}
+
+static void radar_dealloc(struct cl_hw *cl_hw)
+{
+       struct cl_radar_elem *radar_elem;
+       int i;
+
+       if (!cl_hw->radar_pool || !cl_hw->radar_elems)
+               return;
+
+       for (i = 0, radar_elem = cl_hw->radar_elems;
+            i < IPC_RADAR_BUF_CNT; i++, radar_elem++) {
+               if (radar_elem->radarbuf_ptr) {
+                       dma_pool_free(cl_hw->radar_pool, radar_elem->radarbuf_ptr,
+                                     radar_elem->dma_addr);
+                       radar_elem->radarbuf_ptr = NULL;
+               }
+       }
+
+       dma_pool_destroy(cl_hw->radar_pool);
+       cl_hw->radar_pool = NULL;
+
+       kfree(cl_hw->radar_elems);
+       cl_hw->radar_elems = NULL;
+}
+
+static void dbg_dealloc(struct cl_hw *cl_hw)
+{
+       struct cl_dbg_elem *dbg_elem;
+       int i;
+
+       if (!cl_hw->dbg_pool || !cl_hw->dbg_elems)
+               return;
+
+       for (i = 0, dbg_elem = cl_hw->dbg_elems;
+            i < IPC_DBG_BUF_CNT; i++, dbg_elem++) {
+               if (dbg_elem->dbgbuf_ptr) {
+                       dma_pool_free(cl_hw->dbg_pool, dbg_elem->dbgbuf_ptr,
+                                     dbg_elem->dma_addr);
+                       dbg_elem->dbgbuf_ptr = NULL;
+               }
+       }
+
+       dma_pool_destroy(cl_hw->dbg_pool);
+       cl_hw->dbg_pool = NULL;
+
+       kfree(cl_hw->dbg_elems);
+       cl_hw->dbg_elems = NULL;
+}
+
+static void cfm_dealloc(struct cl_hw *cl_hw)
+{
+       struct cl_ipc_host_env *ipc_env = cl_hw->ipc_env;
+
+       dma_free_coherent(cl_hw->chip->dev,
+                         DMA_CFM_TOTAL_SIZE,
+                         ipc_env->cfm_virt_base_addr,
+                         ipc_env->cfm_dma_base_addr);
+
+       ipc_env->cfm_dma_base_addr = 0;
+       ipc_env->cfm_virt_base_addr = NULL;
+}
+
+static void dbg_info_dealloc(struct cl_hw *cl_hw)
+{
+       if (!cl_hw->dbginfo.buf)
+               return;
+
+       dma_free_coherent(cl_hw->chip->dev,
+                         cl_hw->dbginfo.bufsz,
+                         cl_hw->dbginfo.buf,
+                         cl_hw->dbginfo.dma_addr);
+
+       cl_hw->dbginfo.buf = NULL;
+}
+
+static void ipc_elems_dealloc(struct cl_hw *cl_hw)
+{
+       ring_indices_dealloc(cl_hw);
+       txdesc_dealloc(cl_hw);
+       tx_queues_dealloc(cl_hw);
+       rx_dealloc(cl_hw);
+       msg_dealloc(cl_hw);
+       radar_dealloc(cl_hw);
+       dbg_dealloc(cl_hw);
+       cfm_dealloc(cl_hw);
+       dbg_info_dealloc(cl_hw);
+}
+
+static int ring_indices_alloc(struct cl_hw *cl_hw)
+{
+       struct cl_chip *chip = cl_hw->chip;
+       struct cl_ipc_host_env *ipc_env = cl_hw->ipc_env;
+
+       ipc_env->ring_indices_elem = kzalloc(sizeof(*ipc_env->ring_indices_elem), GFP_KERNEL);
+
+       if (!ipc_env->ring_indices_elem)
+               return -ENOMEM;
+
+       if (cl_hw_is_tcv0(cl_hw)) {
+               ipc_env->ring_indices_elem->indices = chip->ring_indices.params;
+               ipc_env->ring_indices_elem->dma_addr = chip->ring_indices.dma_addr;
+       } else {
+               ipc_env->ring_indices_elem->indices = chip->ring_indices.params + 1;
+               ipc_env->ring_indices_elem->dma_addr =
+                       (u32)chip->ring_indices.dma_addr + sizeof(struct cl_ipc_ring_indices);
+       }
+
+       memset(ipc_env->ring_indices_elem->indices, 0, sizeof(struct cl_ipc_ring_indices));
+
+       return 0;
+}
+
+static int tx_queues_alloc(struct cl_hw *cl_hw)
+{
+       struct tx_queues_dma_addr *buf = NULL;
+       u32 size = sizeof(struct tx_queues_dma_addr);
+       dma_addr_t phys_dma_addr;
+
+       buf = dma_alloc_coherent(cl_hw->chip->dev, size, &phys_dma_addr, GFP_KERNEL);
+
+       if (!buf)
+               return -ENOMEM;
+
+       cl_hw->ipc_env->tx_queues.queues_dma_addr = buf;
+       cl_hw->ipc_env->tx_queues.dma_addr = phys_dma_addr;
+
+       return 0;
+}
+
+static int __txdesc_alloc(struct cl_hw *cl_hw,
+                         struct txdesc **txdesc,
+                         u32 *dma_addr,
+                         u32 desc_num)
+{
+       dma_addr_t phys_dma_addr;
+       u32 size = (desc_num * sizeof(struct txdesc));
+
+       if (size < PAGE_SIZE) {
+               *txdesc = dma_pool_alloc(cl_hw->txdesc_pool, GFP_KERNEL, &phys_dma_addr);
+
+               if (!(*txdesc)) {
+                       cl_dbg_err(cl_hw, "dma_pool_alloc failed size=%d\n", size);
+                       return -ENOMEM;
+               }
+       } else {
+               *txdesc = dma_alloc_coherent(cl_hw->chip->dev, size, &phys_dma_addr, GFP_KERNEL);
+
+               if (!(*txdesc)) {
+                       cl_dbg_err(cl_hw, "dma_alloc_coherent failed size=%d\n", size);
+                       return -ENOMEM;
+               }
+       }
+
+       *dma_addr = cpu_to_le32(phys_dma_addr);
+       memset(*txdesc, 0, size);
+
+       return 0;
+}
+
+static int _txdesc_alloc(struct cl_hw *cl_hw)
+{
+       /*
+        * Allocate ipc txdesc for each queue, map the base
+        * address to the DMA and set the queues size
+        */
+       struct cl_ipc_tx_queues *tx_queues = &cl_hw->ipc_env->tx_queues;
+       struct tx_queues_dma_addr *queues_dma_addr = tx_queues->queues_dma_addr;
+       u32 i;
+       int ret = 0;
+
+       cl_hw->max_agg_tx_q_size = LMAC_TXDESC_AGG_Q_SIZE_MAX;
+
+       ret = __txdesc_alloc(cl_hw, &tx_queues->ipc_txdesc_bcmc,
+                            &queues_dma_addr->bcmc, IPC_TXDESC_CNT_BCMC);
+       if (ret)
+               return ret;
+
+       for (i = 0; i < MAX_SINGLE_QUEUES; i++) {
+               ret = __txdesc_alloc(cl_hw, &tx_queues->ipc_txdesc_single[i],
+                                    &queues_dma_addr->single[i], IPC_TXDESC_CNT_SINGLE);
+               if (ret)
+                       return ret;
+       }
+
+       for (i = 0; i < IPC_MAX_BA_SESSIONS; i++) {
+               ret = __txdesc_alloc(cl_hw, &tx_queues->ipc_txdesc_agg[i],
+                                    &queues_dma_addr->agg[i], cl_hw->max_agg_tx_q_size);
+               if (ret)
+                       return ret;
+       }
+
+       return 0;
+}
+
+static int txdesc_alloc(struct cl_hw *cl_hw)
+{
+       u32 pool_size = IPC_TXDESC_CNT_SINGLE * sizeof(struct txdesc);
+
+       cl_hw->txdesc_pool = dma_pool_create("cl_txdesc_pool", cl_hw->chip->dev, pool_size,
+                                            cache_line_size(), 0);
+
+       if (!cl_hw->txdesc_pool) {
+               cl_dbg_verbose(cl_hw, "dma_pool_create failed !!!\n");
+               return -ENOMEM;
+       }
+
+       return _txdesc_alloc(cl_hw);
+}
+
+static int rx_skb_alloc(struct cl_hw *cl_hw)
+{
+       /*
+        * This function allocates Rx elements for DMA
+        * transfers and pushes the DMA address to FW.
+        */
+       struct cl_rx_elem *rx_elem = cl_hw->rx_elems;
+       struct cl_ipc_host_env *ipc_env = cl_hw->ipc_env;
+       int i = 0;
+       u16 rxbuf_size_rxm = cl_hw->conf->ci_ipc_rxbuf_size[CL_RX_BUF_RXM];
+       u16 rxbuf_size_fw = cl_hw->conf->ci_ipc_rxbuf_size[CL_RX_BUF_FW];
+
+       /* Allocate and push RXM buffers */
+       for (i = 0; i < IPC_RXBUF_CNT_RXM; rx_elem++, i++) {
+               if (cl_ipc_rx_elem_alloc(cl_hw, rx_elem, rxbuf_size_rxm)) {
+                       cl_dbg_verbose(cl_hw, "RXM rx_elem allocation failed !!!\n");
+                       return -ENOMEM;
+               }
+               cl_ipc_rxbuf_push(ipc_env, rx_elem, i, i, CL_RX_BUF_RXM);
+       }
+
+       /* Allocate and push FW buffers */
+       for (i = 0; i < IPC_RXBUF_CNT_FW; rx_elem++, i++) {
+               if (cl_ipc_rx_elem_alloc(cl_hw, rx_elem, rxbuf_size_fw)) {
+                       cl_dbg_verbose(cl_hw, "FW rx_elem allocation failed !!!\n");
+                       return -ENOMEM;
+               }
+               cl_ipc_rxbuf_push(ipc_env, rx_elem, i, i, CL_RX_BUF_FW);
+       }
+
+       return 0;
+}
+
+static int _rx_buf_alloc(struct cl_hw *cl_hw, u32 **rxbuf, u32 *dma_addr, u32 desc_num)
+{
+       dma_addr_t phys_dma_addr;
+       u32 size = (desc_num * sizeof(u32));
+
+       *rxbuf = dma_alloc_coherent(cl_hw->chip->dev,
+                                   size,
+                                   &phys_dma_addr,
+                                   GFP_KERNEL);
+
+       if (!(*rxbuf))
+               return -ENOMEM;
+
+       *dma_addr = cpu_to_le32(phys_dma_addr);
+       memset(*rxbuf, 0, size);
+
+       return 0;
+}
+
+static int rx_buf_alloc(struct cl_hw *cl_hw)
+{
+       struct cl_ipc_host_env *ipc_env = cl_hw->ipc_env;
+       struct cl_ipc_host_rxbuf *rxbuf_rxm = &ipc_env->rx_hostbuf_array[CL_RX_BUF_RXM];
+       struct cl_ipc_host_rxbuf *rxbuf_fw = &ipc_env->rx_hostbuf_array[CL_RX_BUF_FW];
+       int ret = 0;
+
+       rxbuf_rxm->ipc_host_rxdesc_ptr = ipc_env->ipc_host_rxdesc_rxm;
+       rxbuf_fw->ipc_host_rxdesc_ptr = ipc_env->ipc_host_rxdesc_fw;
+
+       /* Allocate RXM RX write/read indexes */
+       ret = _rx_buf_alloc(cl_hw,
+                           (u32 **)&rxbuf_rxm->dma_payload_addr,
+                           &rxbuf_rxm->dma_payload_base_addr,
+                           IPC_RXBUF_CNT_RXM);
+       if (ret)
+               return ret;
+
+       /* Allocate FW RX write/read indexes */
+       ret = _rx_buf_alloc(cl_hw,
+                           (u32 **)&rxbuf_fw->dma_payload_addr,
+                           &rxbuf_fw->dma_payload_base_addr,
+                           IPC_RXBUF_CNT_FW);
+       if (ret)
+               return ret;
+
+       return 0;
+}
+
+static int rx_alloc(struct cl_hw *cl_hw)
+{
+       u32 total_rx_elems = IPC_RXBUF_CNT_RXM + IPC_RXBUF_CNT_FW;
+       u32 alloc_size = total_rx_elems * sizeof(struct cl_rx_elem);
+       int ret = rx_buf_alloc(cl_hw);
+
+       if (ret)
+               return ret;
+
+       cl_hw->rx_elems = kzalloc(alloc_size, GFP_KERNEL);
+
+       if (!cl_hw->rx_elems)
+               return -ENOMEM;
+
+       return rx_skb_alloc(cl_hw);
+}
+
+static int _msg_alloc(struct cl_hw *cl_hw, struct cl_e2a_msg_elem *msg_elem)
+{
+       dma_addr_t dma_addr;
+       struct cl_ipc_e2a_msg *msg;
+
+       /* Initialize the message pattern to NULL */
+       msg = dma_pool_alloc(cl_hw->e2a_msg_pool, GFP_KERNEL, &dma_addr);
+       if (!msg)
+               return -ENOMEM;
+
+       msg->pattern = 0;
+
+       /* Save the msg pointer (for deallocation) and the dma_addr */
+       msg_elem->msgbuf_ptr = msg;
+       msg_elem->dma_addr = dma_addr;
+
+       return 0;
+}
+
+static int msg_alloc(struct cl_hw *cl_hw)
+{
+       struct cl_ipc_host_env *ipc_env = cl_hw->ipc_env;
+       struct cl_e2a_msg_elem *msg_elem;
+       u32 alloc_size = IPC_E2A_MSG_BUF_CNT * sizeof(struct cl_e2a_msg_elem);
+       u32 i;
+
+       cl_hw->e2a_msg_elems = kzalloc(alloc_size, GFP_KERNEL);
+
+       if (!cl_hw->e2a_msg_elems)
+               return -ENOMEM;
+
+       cl_hw->e2a_msg_pool = dma_pool_create("dma_pool_msg",
+                                             cl_hw->chip->dev,
+                                             sizeof(struct cl_ipc_e2a_msg),
+                                             cache_line_size(),
+                                             0);
+
+       if (!cl_hw->e2a_msg_pool) {
+               cl_dbg_verbose(cl_hw, "dma_pool_create failed !!!\n");
+               return -ENOMEM;
+       }
+
+       /* Initialize the msg buffers in the global IPC array. */
+       for (i = 0, msg_elem = cl_hw->e2a_msg_elems;
+            i < IPC_E2A_MSG_BUF_CNT; msg_elem++, i++) {
+               if (_msg_alloc(cl_hw, msg_elem)) {
+                       cl_dbg_verbose(cl_hw, "msg allocation failed !!!\n");
+                       return -ENOMEM;
+               }
+
+               cl_ipc_msgbuf_push(ipc_env, (ptrdiff_t)msg_elem, msg_elem->dma_addr);
+       }
+
+       return 0;
+}
+
+static int _radar_alloc(struct cl_hw *cl_hw, struct cl_radar_elem *radar_elem)
+{
+       dma_addr_t dma_addr;
+       struct cl_radar_pulse_array *radar;
+
+       /* Initialize the message pattern to NULL */
+       radar = dma_pool_alloc(cl_hw->radar_pool, GFP_KERNEL, &dma_addr);
+       if (!radar)
+               return -ENOMEM;
+
+       radar->cnt = 0;
+
+       /* Save the msg pointer (for deallocation) and the dma_addr */
+       radar_elem->radarbuf_ptr = radar;
+       radar_elem->dma_addr = dma_addr;
+
+       return 0;
+}
+
+static int radar_alloc(struct cl_hw *cl_hw)
+{
+       struct cl_ipc_host_env *ipc_env = cl_hw->ipc_env;
+       struct cl_radar_elem *radar_elem;
+       u32 alloc_size = IPC_RADAR_BUF_CNT * sizeof(struct cl_radar_elem);
+       u32 i;
+
+       cl_hw->radar_elems = kzalloc(alloc_size, GFP_KERNEL);
+
+       if (!cl_hw->radar_elems)
+               return -ENOMEM;
+
+       cl_hw->radar_pool = dma_pool_create("dma_pool_radar",
+                                           cl_hw->chip->dev,
+                                           sizeof(struct cl_radar_pulse_array),
+                                           cache_line_size(),
+                                           0);
+
+       if (!cl_hw->radar_pool) {
+               cl_dbg_verbose(cl_hw, "dma_pool_create failed !!!\n");
+               return -ENOMEM;
+       }
+
+       /* Initialize the radar buffers in the global IPC array. */
+       for (i = 0, radar_elem = cl_hw->radar_elems;
+            i < IPC_RADAR_BUF_CNT; radar_elem++, i++) {
+               if (_radar_alloc(cl_hw, radar_elem)) {
+                       cl_dbg_verbose(cl_hw, "radar allocation failed !!!\n");
+                       return -ENOMEM;
+               }
+
+               cl_ipc_radarbuf_push(ipc_env, (ptrdiff_t)radar_elem, radar_elem->dma_addr);
+       }
+
+       return 0;
+}
+
+static int _dbg_alloc(struct cl_hw *cl_hw, struct cl_dbg_elem *dbg_elem)
+{
+       dma_addr_t dma_addr;
+       struct cl_ipc_dbg_msg *dbg_msg;
+
+       dbg_msg = dma_pool_alloc(cl_hw->dbg_pool, GFP_KERNEL, &dma_addr);
+       if (!dbg_msg)
+               return -ENOMEM;
+
+       dbg_msg->pattern = 0;
+
+       /* Save the Debug msg pointer (for deallocation) and the dma_addr */
+       dbg_elem->dbgbuf_ptr = dbg_msg;
+       dbg_elem->dma_addr = dma_addr;
+
+       return 0;
+}
+
+static int dbg_alloc(struct cl_hw *cl_hw)
+{
+       struct cl_ipc_host_env *ipc_env = cl_hw->ipc_env;
+       struct cl_dbg_elem *dbg_elem;
+       u32 alloc_size = IPC_DBG_BUF_CNT * sizeof(struct cl_dbg_elem);
+       u32 i;
+
+       cl_hw->dbg_elems = kzalloc(alloc_size, GFP_KERNEL);
+
+       if (!cl_hw->dbg_elems)
+               return -ENOMEM;
+
+       cl_hw->dbg_pool = dma_pool_create("dma_pool_dbg",
+                                         cl_hw->chip->dev,
+                                         sizeof(struct cl_ipc_dbg_msg),
+                                         cache_line_size(),
+                                         0);
+
+       if (!cl_hw->dbg_pool) {
+               cl_dbg_verbose(cl_hw, "dma_pool_create failed !!!\n");
+               return -ENOMEM;
+       }
+
+       /* Initialize the dbg buffers in the global IPC array. */
+       for (i = 0, dbg_elem = cl_hw->dbg_elems;
+            i < IPC_DBG_BUF_CNT; dbg_elem++, i++) {
+               if (_dbg_alloc(cl_hw, dbg_elem)) {
+                       cl_dbg_verbose(cl_hw, "dbgelem allocation failed !!!\n");
+                       return -ENOMEM;
+               }
+
+               cl_ipc_dbgbuf_push(ipc_env, (ptrdiff_t)dbg_elem, dbg_elem->dma_addr);
+       }
+
+       return 0;
+}
+
+static int cfm_alloc(struct cl_hw *cl_hw)
+{
+       dma_addr_t dma_addr;
+       u8 *host_virt_addr;
+       struct cl_ipc_host_env *ipc_env = cl_hw->ipc_env;
+
+       host_virt_addr = dma_alloc_coherent(cl_hw->chip->dev,
+                                           DMA_CFM_TOTAL_SIZE,
+                                           &dma_addr,
+                                           GFP_KERNEL);
+
+       if (!host_virt_addr)
+               return -ENOMEM;
+
+       memset(host_virt_addr, 0, DMA_CFM_TOTAL_SIZE);
+       ipc_env->cfm_dma_base_addr = dma_addr;
+       ipc_env->cfm_virt_base_addr = host_virt_addr;
+
+       memset(ipc_env->cfm_virt_base_addr, 0, IPC_CFM_SIZE);
+
+       return 0;
+}
+
+static int _dbg_info_alloc(struct cl_hw *cl_hw)
+{
+       dma_addr_t dma_addr;
+       u32 len = sizeof(struct dbg_info);
+       struct dbg_info *buf = dma_alloc_coherent(cl_hw->chip->dev, len, &dma_addr, GFP_KERNEL);
+
+       if (!buf) {
+               cl_dbg_verbose(cl_hw, "buffer alloc of size %u failed\n", len);
+               return -ENOMEM;
+       }
+
+       memset(buf, 0, sizeof(struct dbg_info));
+       buf->u.type = DBG_INFO_UNSET;
+
+       cl_hw->dbginfo.buf = buf;
+       cl_hw->dbginfo.dma_addr = dma_addr;
+       cl_hw->dbginfo.bufsz = len;
+
+       return 0;
+}
+
+static int dbg_info_alloc(struct cl_hw *cl_hw)
+{
+       /* Initialize the debug information buffer */
+       if (_dbg_info_alloc(cl_hw)) {
+               cl_dbg_verbose(cl_hw, "dbginfo allocation failed !!!\n");
+               return -ENOMEM;
+       }
+
+       cl_ipc_dbginfobuf_push(cl_hw->ipc_env, cl_hw->dbginfo.dma_addr);
+
+       return 0;
+}
+
+static int ipc_elems_alloc(struct cl_hw *cl_hw)
+{
+       /* Allocate all the elements required for communications with firmware */
+       if (ring_indices_alloc(cl_hw))
+               goto out_err;
+
+       if (tx_queues_alloc(cl_hw))
+               goto out_err;
+
+       if (txdesc_alloc(cl_hw))
+               goto out_err;
+
+       if (rx_alloc(cl_hw))
+               goto out_err;
+
+       if (msg_alloc(cl_hw))
+               goto out_err;
+
+       if (radar_alloc(cl_hw))
+               goto out_err;
+
+       if (dbg_alloc(cl_hw))
+               goto out_err;
+
+       if (cfm_alloc(cl_hw))
+               goto out_err;
+
+       if (dbg_info_alloc(cl_hw))
+               goto out_err;
+
+       return 0;
+
+out_err:
+       ipc_elems_dealloc(cl_hw);
+       return -ENOMEM;
+}
+
+static u8 cl_ipc_dbgfile_handler(struct cl_hw *cl_hw, ptrdiff_t hostid)
+{
+       struct cl_dbg_elem *dbg_elem = (struct cl_dbg_elem *)hostid;
+       struct cl_ipc_dbg_msg *dbg_msg;
+       u8 ret = 0;
+
+       /* Retrieve the message structure */
+       dbg_msg = (struct cl_ipc_dbg_msg *)dbg_elem->dbgbuf_ptr;
+
+       if (!dbg_msg) {
+               ret = -1;
+               cl_dbg_err(cl_hw, "dbgbuf_ptr is NULL!!!!\n");
+               goto dbg_push;
+       }
+
+       /* Look for pattern which means that this hostbuf has been used for a MSG */
+       if (le32_to_cpu(dbg_msg->pattern) != IPC_DBG_VALID_PATTERN) {
+               ret = -1;
+               goto dbg_no_push;
+       }
+
+       /* Reset the msg element and re-use it */
+       dbg_msg->pattern = 0;
+
+       /* Display the firmware string */
+       cl_dbgfile_print_fw_str(cl_hw, dbg_msg->string, IPC_DBG_PARAM_SIZE);
+
+dbg_push:
+       /* make sure memory is written before push to HW */
+       wmb();
+
+       /* Push back the buffer to the firmware */
+       cl_ipc_dbgbuf_push(cl_hw->ipc_env, (ptrdiff_t)dbg_elem, dbg_elem->dma_addr);
+
+dbg_no_push:
+       return ret;
+}
+
+static void cl_ipc_dbgfile_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_hostbuf *dbg_array = ipc_env->dbg_hostbuf_array;
+       int dbg_handled = 0;
+
+#ifdef TRACE_SUPPORT
+       trace_cl_trace_dbgfile_tasklet_start(cl_hw->idx);
+#endif
+
+       while (!cl_ipc_dbgfile_handler(cl_hw, dbg_array[ipc_env->dbg_host_idx].hostid))
+               dbg_handled++;
+
+#ifdef TRACE_SUPPORT
+       trace_cl_trace_dbgfile_tasklet_end(cl_hw->idx, dbg_handled);
+#endif
+
+       /* Enable the DBG interrupt */
+       if (!test_bit(CL_DEV_STOP_HW, &cl_hw->drv_flags))
+               cl_irq_enable(cl_hw, cl_hw->ipc_e2a_irq.dbg);
+}
+
+static void ipc_tasklet_init(struct cl_hw *cl_hw)
+{
+       struct cl_ipc_host_env *ipc_env = cl_hw->ipc_env;
+
+       tasklet_init(&ipc_env->rxdesc_tasklet,
+                    cl_rx_pci_desc_tasklet,
+                    (unsigned long)cl_hw);
+       tasklet_init(&ipc_env->tx_single_cfm_tasklet,
+                    cl_tx_pci_single_cfm_tasklet,
+                    (unsigned long)cl_hw);
+       tasklet_init(&ipc_env->tx_agg_cfm_tasklet,
+                    cl_tx_pci_agg_cfm_tasklet,
+                    (unsigned long)cl_hw);
+       tasklet_init(&ipc_env->msg_tasklet,
+                    cl_msg_rx_tasklet,
+                    (unsigned long)cl_hw);
+       tasklet_init(&ipc_env->dbg_tasklet,
+                    cl_ipc_dbgfile_tasklet,
+                    (unsigned long)cl_hw);
+}
+
+static int ipc_env_init(struct cl_hw *cl_hw)
+{
+       u32 *dst;
+       u32 i;
+
+       BUILD_BUG_ON_NOT_POWER_OF_2(IPC_RXBUF_CNT_RXM);
+       BUILD_BUG_ON_NOT_POWER_OF_2(IPC_RXBUF_CNT_FW);
+
+       /* Allocate the IPC environment */
+       cl_hw->ipc_env = kzalloc(sizeof(*cl_hw->ipc_env), GFP_KERNEL);
+       if (!cl_hw->ipc_env)
+               return -ENOMEM;
+
+       dst = (u32 *)(cl_hw->ipc_env);
+
+       /*
+        * Reset the IPC Host environment.
+        * Perform the reset word per word because memset() does
+        * not correctly reset all (due to misaligned accesses)
+        */
+       for (i = 0; i < sizeof(*cl_hw->ipc_env); i += sizeof(u32))
+               *dst++ = 0;
+
+       return 0;
+}
+
+static bool is_la_enabled(struct cl_chip *chip)
+{
+       s8 *ela_mode = chip->conf->ce_ela_mode;
+
+       return (!strcmp(ela_mode, "default") ||
+               !strncmp(ela_mode, "lcu_mac", 7) ||
+               !strncmp(ela_mode, "lcu_phy", 7));
+}
+
+static void ipc_shared_env_init(struct cl_hw *cl_hw)
+{
+       struct cl_chip *chip = cl_hw->chip;
+       struct cl_ipc_host_env *ipc_env = cl_hw->ipc_env;
+       struct cl_ipc_shared_env *shared_env =
+               (struct cl_ipc_shared_env *)(chip->pci_bar0_virt_addr + SHARED_RAM_START_ADDR);
+       u32 *dst, i;
+
+       /* The shared environment of TCV1 is located after the shared environment of TCV0. */
+       if (cl_hw_is_tcv1(cl_hw))
+               shared_env++;
+
+       dst = (u32 *)(shared_env);
+
+       /* Reset the shared environment */
+       for (i = 0; i < sizeof(struct cl_ipc_shared_env); i += sizeof(u32))
+               *dst++ = 0;
+
+       shared_env->la_enable = is_la_enabled(chip);
+       shared_env->max_retry = cl_hw->chip->conf->ce_production_mode ?
+               0 : cpu_to_le16(cl_hw->conf->ce_max_retry);
+       shared_env->lft_limit_ms = cpu_to_le16(CL_TX_LIFETIME_MS);
+       shared_env->phy_dev = cpu_to_le16(chip->conf->ci_phy_dev);
+
+       /* Initialize the shared environment pointer */
+       ipc_env->shared = shared_env;
+}
+
+static void ipc_e2a_irq_init(struct cl_hw *cl_hw)
+{
+       struct cl_ipc_e2a_irq *ipc_e2a_irq = &cl_hw->ipc_e2a_irq;
+
+       if (cl_hw_is_tcv0(cl_hw)) {
+               ipc_e2a_irq->dbg = IPC_IRQ_L2H_DBG;
+               ipc_e2a_irq->msg = IPC_IRQ_L2H_MSG;
+               ipc_e2a_irq->rxdesc = IPC_IRQ_L2H_RXDESC;
+               ipc_e2a_irq->txcfm = IPC_IRQ_L2H_TXCFM;
+               ipc_e2a_irq->radar = IPC_IRQ_L2H_RADAR;
+               ipc_e2a_irq->txdesc_ind = IPC_IRQ_L2H_TXDESC_IND;
+               ipc_e2a_irq->tbtt = IPC_IRQ_L2H_TBTT;
+               ipc_e2a_irq->sync = IPC_IRQ_L2H_SYNC;
+               ipc_e2a_irq->all = IPC_IRQ_L2H_ALL;
+       } else {
+               ipc_e2a_irq->dbg = IPC_IRQ_S2H_DBG;
+               ipc_e2a_irq->msg = IPC_IRQ_S2H_MSG;
+               ipc_e2a_irq->rxdesc = IPC_IRQ_S2H_RXDESC;
+               ipc_e2a_irq->txcfm = IPC_IRQ_S2H_TXCFM;
+               ipc_e2a_irq->radar = IPC_IRQ_S2H_RADAR;
+               ipc_e2a_irq->txdesc_ind = IPC_IRQ_S2H_TXDESC_IND;
+               ipc_e2a_irq->tbtt = IPC_IRQ_S2H_TBTT;
+               ipc_e2a_irq->sync = IPC_IRQ_S2H_SYNC;
+               ipc_e2a_irq->all = IPC_IRQ_S2H_ALL;
+       }
+}
+
+int cl_ipc_init(struct cl_hw *cl_hw)
+{
+       /*
+        * This function initializes IPC interface by registering callbacks, setting
+        * shared memory area and calling IPC Init function.
+        * This function should be called only once during driver's lifetime.
+        */
+       int ret = ipc_env_init(cl_hw);
+
+       if (ret)
+               return ret;
+
+       ipc_e2a_irq_init(cl_hw);
+       if (cl_hw_is_tcv0(cl_hw))
+               cl_hw->ipc_host2xmac_trigger_set = ipc_host_2_lmac_trigger_set;
+       else
+               cl_hw->ipc_host2xmac_trigger_set = ipc_host_2_smac_trigger_set;
+
+       ipc_shared_env_init(cl_hw);
+
+       ret = ipc_elems_alloc(cl_hw);
+       if (ret) {
+               ipc_env_free(cl_hw);
+               return ret;
+       }
+
+       ipc_tasklet_init(cl_hw);
+
+       return ret;
+}
+
+static void ring_indices_reset(struct cl_hw *cl_hw)
+{
+       struct cl_ipc_host_env *ipc_env = cl_hw->ipc_env;
+
+       memset(ipc_env->ring_indices_elem->indices, 0,
+              sizeof(*ipc_env->ring_indices_elem->indices));
+
+       /* Reset host desc read idx follower */
+       ipc_env->host_rxdesc_read_idx[CL_RX_BUF_RXM] = 0;
+       ipc_env->host_rxdesc_read_idx[CL_RX_BUF_FW] = 0;
+}
+
+static void _txdesc_reset(struct txdesc **txdesc, u32 desc_num)
+{
+       u32 size = (desc_num * sizeof(struct txdesc));
+
+       memset(*txdesc, 0, size);
+}
+
+static void txdesc_reset(struct cl_hw *cl_hw)
+{
+       struct cl_ipc_tx_queues *tx_queues = &cl_hw->ipc_env->tx_queues;
+       u32 i;
+
+       _txdesc_reset(&tx_queues->ipc_txdesc_bcmc, IPC_TXDESC_CNT_BCMC);
+
+       for (i = 0; i < MAX_SINGLE_QUEUES; i++)
+               _txdesc_reset(&tx_queues->ipc_txdesc_single[i], IPC_TXDESC_CNT_SINGLE);
+
+       for (i = 0; i < IPC_MAX_BA_SESSIONS; i++)
+               _txdesc_reset(&tx_queues->ipc_txdesc_agg[i], cl_hw->max_agg_tx_q_size);
+}
+
+static void rx_skb_reset(struct cl_hw *cl_hw)
+{
+       /*
+        * This function allocates Rx elements for DMA
+        * transfers and pushes the DMA address to FW.
+        */
+       struct cl_ipc_host_env *ipc_env = cl_hw->ipc_env;
+       struct cl_rx_elem *rx_elem = cl_hw->rx_elems;
+       int i = 0;
+
+       /* Push RXM buffers */
+       for (i = 0; i < IPC_RXBUF_CNT_RXM; rx_elem++, i++)
+               cl_ipc_rxbuf_push(ipc_env, rx_elem, i, i, CL_RX_BUF_RXM);
+
+       /* Push FW buffers */
+       for (i = 0; i < IPC_RXBUF_CNT_FW; rx_elem++, i++)
+               cl_ipc_rxbuf_push(ipc_env, rx_elem, i, i, CL_RX_BUF_FW);
+}
+
+static void _rx_buf_reset(u32 **rxbuf, u32 desc_num)
+{
+       u32 size = (desc_num * sizeof(u32));
+
+       memset(*rxbuf, 0, size);
+}
+
+static void rx_buf_reset(struct cl_hw *cl_hw)
+{
+       struct cl_ipc_host_env *ipc_env = cl_hw->ipc_env;
+       struct cl_ipc_host_rxbuf *rxbuf_rxm = &ipc_env->rx_hostbuf_array[CL_RX_BUF_RXM];
+       struct cl_ipc_host_rxbuf *rxbuf_fw = &ipc_env->rx_hostbuf_array[CL_RX_BUF_FW];
+
+       /* Reset RXM RX buffer */
+       _rx_buf_reset((u32 **)&rxbuf_rxm->dma_payload_addr,
+                     IPC_RXBUF_CNT_RXM);
+
+       /* Reset FW RX buffer */
+       _rx_buf_reset((u32 **)&rxbuf_fw->dma_payload_addr,
+                     IPC_RXBUF_CNT_FW);
+}
+
+static void rx_reset(struct cl_hw *cl_hw)
+{
+       rx_buf_reset(cl_hw);
+       rx_skb_reset(cl_hw);
+}
+
+static void msg_reset(struct cl_hw *cl_hw)
+{
+       struct cl_ipc_host_env *ipc_env = cl_hw->ipc_env;
+       struct cl_e2a_msg_elem *msg_elem;
+       u32 i;
+
+       ipc_env->e2a_msg_host_idx = 0;
+
+       /* Initialize the msg buffers in the global IPC array. */
+       for (i = 0, msg_elem = cl_hw->e2a_msg_elems;
+            i < IPC_E2A_MSG_BUF_CNT; msg_elem++, i++) {
+               msg_elem->msgbuf_ptr->pattern = 0;
+               cl_ipc_msgbuf_push(ipc_env, (ptrdiff_t)msg_elem, msg_elem->dma_addr);
+       }
+}
+
+static void radar_reset(struct cl_hw *cl_hw)
+{
+       struct cl_ipc_host_env *ipc_env = cl_hw->ipc_env;
+       struct cl_radar_elem *radar_elem;
+       u32 i;
+
+       ipc_env->radar_host_idx = 0;
+
+       /* Initialize the radar buffers in the global IPC array. */
+       for (i = 0, radar_elem = cl_hw->radar_elems;
+            i < IPC_RADAR_BUF_CNT; radar_elem++, i++) {
+               radar_elem->radarbuf_ptr->cnt = 0;
+               cl_ipc_radarbuf_push(ipc_env, (ptrdiff_t)radar_elem, radar_elem->dma_addr);
+       }
+}
+
+static void dbg_reset(struct cl_hw *cl_hw)
+{
+       struct cl_ipc_host_env *ipc_env = cl_hw->ipc_env;
+       struct cl_dbg_elem *dbg_elem;
+       u32 i;
+
+       ipc_env->dbg_host_idx = 0;
+
+       /* Initialize the dbg buffers in the global IPC array. */
+       for (i = 0, dbg_elem = cl_hw->dbg_elems;
+            i < IPC_DBG_BUF_CNT; dbg_elem++, i++) {
+               dbg_elem->dbgbuf_ptr->pattern = 0;
+               cl_ipc_dbgbuf_push(ipc_env, (ptrdiff_t)dbg_elem, dbg_elem->dma_addr);
+       }
+}
+
+static void cfm_reset(struct cl_hw *cl_hw)
+{
+       struct cl_ipc_host_env *ipc_env = cl_hw->ipc_env;
+
+       ipc_env->cfm_used_idx = 0;
+       memset(ipc_env->cfm_virt_base_addr, 0, IPC_CFM_SIZE);
+}
+
+static void dbg_info_reset(struct cl_hw *cl_hw)
+{
+       struct dbg_info *buf = cl_hw->dbginfo.buf;
+
+       memset(buf, 0, sizeof(struct dbg_info));
+       buf->u.type = DBG_INFO_UNSET;
+
+       cl_ipc_dbginfobuf_push(cl_hw->ipc_env, cl_hw->dbginfo.dma_addr);
+}
+
+static void ipc_elems_reset(struct cl_hw *cl_hw)
+{
+       ring_indices_reset(cl_hw);
+       txdesc_reset(cl_hw);
+       rx_reset(cl_hw);
+       msg_reset(cl_hw);
+       radar_reset(cl_hw);
+       dbg_reset(cl_hw);
+       cfm_reset(cl_hw);
+       dbg_info_reset(cl_hw);
+       cl_enhanced_tim_reset(cl_hw);
+}
+
+void cl_ipc_recovery(struct cl_hw *cl_hw)
+{
+       ipc_shared_env_init(cl_hw);
+       ipc_elems_reset(cl_hw);
+}
+
+void cl_ipc_reset(struct cl_hw *cl_hw)
+{
+       cl_hw->ipc_env->shared->cfm_read_pointer = 0;
+       cl_hw->ipc_env->cfm_used_idx = 0;
+}
+
+void cl_ipc_deinit(struct cl_hw *cl_hw)
+{
+       ipc_elems_dealloc(cl_hw);
+       ipc_env_free(cl_hw);
+}
+
+void cl_ipc_stop(struct cl_hw *cl_hw)
+{
+       struct cl_ipc_host_env *ipc_env = cl_hw->ipc_env;
+
+       tasklet_kill(&ipc_env->rxdesc_tasklet);
+       tasklet_kill(&ipc_env->tx_single_cfm_tasklet);
+       tasklet_kill(&ipc_env->tx_agg_cfm_tasklet);
+       tasklet_kill(&ipc_env->msg_tasklet);
+       tasklet_kill(&ipc_env->dbg_tasklet);
+}
+
+int cl_ipc_rx_elem_alloc(struct cl_hw *cl_hw, struct cl_rx_elem *rx_elem, u32 size)
+{
+       struct sk_buff *skb;
+       dma_addr_t dma_addr;
+       struct hw_rxhdr *rxhdr;
+
+       rx_elem->passed = 0;
+
+       skb = dev_alloc_skb(size);
+
+       if (unlikely(!skb)) {
+               cl_dbg_verbose(cl_hw, "skb alloc failed (size %u)\n", size);
+               rx_elem->dma_addr = (dma_addr_t)0;
+               return -ENOMEM;
+       }
+
+       /* Reserve room for RX vector */
+       skb_reserve(skb, IPC_RXBUF_EXTRA_HEADROOM);
+
+       rxhdr = (struct hw_rxhdr *)skb->data;
+       rxhdr->pattern = 0;
+
+       dma_addr = dma_map_single(cl_hw->chip->dev, skb->data, size, DMA_FROM_DEVICE);
+
+       if (unlikely(dma_mapping_error(cl_hw->chip->dev, dma_addr))) {
+               cl_dbg_verbose(cl_hw, "dma_mapping_error\n");
+               kfree_skb(skb);
+               return -1;
+       }
+
+       rx_elem->skb = skb;
+       rx_elem->dma_addr = dma_addr;
+
+       cl_rx_skb_alloc_handler(skb);
+
+       return 0;
+}
+
+void cl_ipc_msgbuf_push(struct cl_ipc_host_env *ipc_env, ptrdiff_t hostid, dma_addr_t hostbuf)
+{
+       /*
+        * Push a pre-allocated buffer descriptor for MSGs
+        * This function is only called at Init time since the MSGs will be handled directly
+        * and buffer can be re-used as soon as the message is handled, no need to re-allocate
+        * new buffers in the meantime.
+        */
+       struct cl_ipc_shared_env *shared_env = ipc_env->shared;
+       u8 e2a_msg_host_idx = ipc_env->e2a_msg_host_idx;
+
+       /* Save the hostid and the hostbuf in global array */
+       ipc_env->e2a_msg_hostbuf_array[e2a_msg_host_idx].hostid = hostid;
+       ipc_env->e2a_msg_hostbuf_array[e2a_msg_host_idx].dma_addr = hostbuf;
+
+       /* Copy the hostbuf (DMA address) in the ipc shared memory */
+       shared_env->e2a_msg_hostbuf_addr[e2a_msg_host_idx] = cpu_to_le32(hostbuf);
+
+       /* Increment the array index */
+       ipc_env->e2a_msg_host_idx = (e2a_msg_host_idx + 1) % IPC_E2A_MSG_BUF_CNT;
+}
+
+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)
+{
+       /*
+        * Push a pre-allocated buffer descriptor for Rx packet.
+        * This function is called to supply the firmware with new empty buffer.
+        */
+       struct cl_ipc_ring_indices *indices = ipc_env->ring_indices_elem->indices;
+       struct cl_ipc_host_rxbuf *host_rxbuf = &ipc_env->rx_hostbuf_array[type];
+
+       /* Save the hostid and the hostbuf in global array */
+       host_rxbuf->ipc_host_rxdesc_ptr[host_read_idx] = (ptrdiff_t *)rx_elem;
+       host_rxbuf->dma_payload_addr[host_read_idx] = rx_elem->dma_addr;
+
+       /* Update rxbuff metadata */
+       indices->rxdesc_read_idx[type] = cpu_to_le32(rxdesc_read_idx + 1);
+}
+
+void cl_ipc_radarbuf_push(struct cl_ipc_host_env *ipc_env, ptrdiff_t hostid, dma_addr_t hostbuf)
+{
+       /*
+        * Push a pre-allocated radar event buffer descriptor.
+        * This function should be called by the host IRQ handler to supply the embedded
+        * side with new empty buffer.
+        */
+       struct cl_ipc_shared_env *shared_env = ipc_env->shared;
+       u8 radar_host_idx = ipc_env->radar_host_idx;
+
+       /* Save the hostid and the hostbuf in global array */
+       ipc_env->radar_hostbuf_array[radar_host_idx].hostid = hostid;
+       ipc_env->radar_hostbuf_array[radar_host_idx].dma_addr = hostbuf;
+
+       /* Copy the hostbuf (DMA address) in the ipc shared memory */
+       shared_env->radarbuf_hostbuf[radar_host_idx] = cpu_to_le32(hostbuf);
+
+       /* Increment the array index */
+       ipc_env->radar_host_idx = (radar_host_idx + 1) % IPC_RADAR_BUF_CNT;
+}
+
+void cl_ipc_dbgbuf_push(struct cl_ipc_host_env *ipc_env, ptrdiff_t hostid, dma_addr_t hostbuf)
+{
+       /*
+        * Push a pre-allocated buffer descriptor for Debug messages.
+        * This function is only called at Init time since the Debug messages will be
+        * handled directly and buffer can be re-used as soon as the message is handled,
+        * no need to re-allocate new buffers in the meantime.
+        */
+       struct cl_ipc_shared_env *shared_env = ipc_env->shared;
+       u8 dbg_host_idx = ipc_env->dbg_host_idx;
+
+       /* Save the hostid and the hostbuf in global array */
+       ipc_env->dbg_hostbuf_array[dbg_host_idx].hostid = hostid;
+       ipc_env->dbg_hostbuf_array[dbg_host_idx].dma_addr = hostbuf;
+
+       /* Copy the hostbuf (DMA address) in the ipc shared memory */
+       shared_env->dbg_hostbuf_addr[dbg_host_idx] = cpu_to_le32(hostbuf);
+
+       /* Increment the array index */
+       ipc_env->dbg_host_idx = (dbg_host_idx + 1) % IPC_DBG_BUF_CNT;
+}
+
+void cl_ipc_dbginfobuf_push(struct cl_ipc_host_env *ipc_env, dma_addr_t infobuf)
+{
+       /*Push the pre-allocated logic analyzer and debug information buffer */
+       struct cl_ipc_shared_env *shared_env = ipc_env->shared;
+
+       /* Copy the hostbuf (DMA address) in the ipc shared memory */
+       shared_env->dbginfo_addr = cpu_to_le32(infobuf);
+       /* Copy the hostbuf size in the ipc shared memory */
+       shared_env->dbginfo_size = cpu_to_le32(DBG_DUMP_BUFFER_SIZE);
+}
--
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.
________________________________


^ permalink raw reply related	[flat|nested] 262+ messages in thread

* [RFC v1 018/256] cl8k: add bus/pci/ipc.h
  2021-06-17 15:58 [RFC v1 000/256] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (16 preceding siblings ...)
  2021-06-17 15:58 ` [RFC v1 017/256] cl8k: add bus/pci/ipc.c viktor.barna
@ 2021-06-17 15:58 ` viktor.barna
  2021-06-17 15:58 ` [RFC v1 019/256] cl8k: add bus/pci/irq.c viktor.barna
                   ` (239 subsequent siblings)
  257 siblings, 0 replies; 262+ messages in thread
From: viktor.barna @ 2021-06-17 15:58 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Oleksandr Savchenko, Shay Bar, Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

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

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 .../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.
________________________________


^ permalink raw reply related	[flat|nested] 262+ messages in thread

* [RFC v1 019/256] cl8k: add bus/pci/irq.c
  2021-06-17 15:58 [RFC v1 000/256] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (17 preceding siblings ...)
  2021-06-17 15:58 ` [RFC v1 018/256] cl8k: add bus/pci/ipc.h viktor.barna
@ 2021-06-17 15:58 ` viktor.barna
  2021-06-17 15:58 ` [RFC v1 020/256] cl8k: add bus/pci/irq.h viktor.barna
                   ` (238 subsequent siblings)
  257 siblings, 0 replies; 262+ messages in thread
From: viktor.barna @ 2021-06-17 15:58 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Oleksandr Savchenko, Shay Bar, Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

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

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 .../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.
________________________________


^ permalink raw reply related	[flat|nested] 262+ messages in thread

* [RFC v1 020/256] cl8k: add bus/pci/irq.h
  2021-06-17 15:58 [RFC v1 000/256] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (18 preceding siblings ...)
  2021-06-17 15:58 ` [RFC v1 019/256] cl8k: add bus/pci/irq.c viktor.barna
@ 2021-06-17 15:58 ` viktor.barna
  2021-06-17 15:58 ` [RFC v1 021/256] cl8k: add bus/pci/msg_pci.c viktor.barna
                   ` (237 subsequent siblings)
  257 siblings, 0 replies; 262+ messages in thread
From: viktor.barna @ 2021-06-17 15:58 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Oleksandr Savchenko, Shay Bar, Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

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

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 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.
________________________________


^ permalink raw reply related	[flat|nested] 262+ messages in thread

* [RFC v1 021/256] cl8k: add bus/pci/msg_pci.c
  2021-06-17 15:58 [RFC v1 000/256] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (19 preceding siblings ...)
  2021-06-17 15:58 ` [RFC v1 020/256] cl8k: add bus/pci/irq.h viktor.barna
@ 2021-06-17 15:58 ` viktor.barna
  2021-06-17 15:58 ` [RFC v1 022/256] cl8k: add bus/pci/msg_pci.h viktor.barna
                   ` (236 subsequent siblings)
  257 siblings, 0 replies; 262+ messages in thread
From: viktor.barna @ 2021-06-17 15:58 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Oleksandr Savchenko, Shay Bar, Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

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

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 .../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.
________________________________


^ permalink raw reply related	[flat|nested] 262+ messages in thread

* [RFC v1 022/256] cl8k: add bus/pci/msg_pci.h
  2021-06-17 15:58 [RFC v1 000/256] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (20 preceding siblings ...)
  2021-06-17 15:58 ` [RFC v1 021/256] cl8k: add bus/pci/msg_pci.c viktor.barna
@ 2021-06-17 15:58 ` viktor.barna
  2021-06-17 15:58 ` [RFC v1 023/256] cl8k: add bus/pci/pci.c viktor.barna
                   ` (235 subsequent siblings)
  257 siblings, 0 replies; 262+ messages in thread
From: viktor.barna @ 2021-06-17 15:58 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Oleksandr Savchenko, Shay Bar, Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

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

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 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.
________________________________


^ permalink raw reply related	[flat|nested] 262+ messages in thread

* [RFC v1 023/256] cl8k: add bus/pci/pci.c
  2021-06-17 15:58 [RFC v1 000/256] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (21 preceding siblings ...)
  2021-06-17 15:58 ` [RFC v1 022/256] cl8k: add bus/pci/msg_pci.h viktor.barna
@ 2021-06-17 15:58 ` viktor.barna
  2021-06-17 15:58 ` [RFC v1 024/256] cl8k: add bus/pci/rx_pci.c viktor.barna
                   ` (234 subsequent siblings)
  257 siblings, 0 replies; 262+ messages in thread
From: viktor.barna @ 2021-06-17 15:58 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Oleksandr Savchenko, Shay Bar, Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

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

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 .../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.
________________________________


^ permalink raw reply related	[flat|nested] 262+ messages in thread

* [RFC v1 024/256] cl8k: add bus/pci/rx_pci.c
  2021-06-17 15:58 [RFC v1 000/256] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (22 preceding siblings ...)
  2021-06-17 15:58 ` [RFC v1 023/256] cl8k: add bus/pci/pci.c viktor.barna
@ 2021-06-17 15:58 ` viktor.barna
  2021-06-17 15:58 ` [RFC v1 025/256] cl8k: add bus/pci/rx_pci.h viktor.barna
                   ` (233 subsequent siblings)
  257 siblings, 0 replies; 262+ messages in thread
From: viktor.barna @ 2021-06-17 15:58 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Oleksandr Savchenko, Shay Bar, Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

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

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 .../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.
________________________________


^ permalink raw reply related	[flat|nested] 262+ messages in thread

* [RFC v1 025/256] cl8k: add bus/pci/rx_pci.h
  2021-06-17 15:58 [RFC v1 000/256] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (23 preceding siblings ...)
  2021-06-17 15:58 ` [RFC v1 024/256] cl8k: add bus/pci/rx_pci.c viktor.barna
@ 2021-06-17 15:58 ` viktor.barna
  2021-06-17 15:58 ` [RFC v1 026/256] cl8k: add bus/pci/tx_pci.c viktor.barna
                   ` (232 subsequent siblings)
  257 siblings, 0 replies; 262+ messages in thread
From: viktor.barna @ 2021-06-17 15:58 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Oleksandr Savchenko, Shay Bar, Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

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

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 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.
________________________________


^ permalink raw reply related	[flat|nested] 262+ messages in thread

* [RFC v1 026/256] cl8k: add bus/pci/tx_pci.c
  2021-06-17 15:58 [RFC v1 000/256] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (24 preceding siblings ...)
  2021-06-17 15:58 ` [RFC v1 025/256] cl8k: add bus/pci/rx_pci.h viktor.barna
@ 2021-06-17 15:58 ` viktor.barna
  2021-06-17 15:58 ` [RFC v1 027/256] cl8k: add bus/pci/tx_pci.h viktor.barna
                   ` (231 subsequent siblings)
  257 siblings, 0 replies; 262+ messages in thread
From: viktor.barna @ 2021-06-17 15:58 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Oleksandr Savchenko, Shay Bar, Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

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

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 .../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.
________________________________


^ permalink raw reply related	[flat|nested] 262+ messages in thread

* [RFC v1 027/256] cl8k: add bus/pci/tx_pci.h
  2021-06-17 15:58 [RFC v1 000/256] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (25 preceding siblings ...)
  2021-06-17 15:58 ` [RFC v1 026/256] cl8k: add bus/pci/tx_pci.c viktor.barna
@ 2021-06-17 15:58 ` viktor.barna
  2021-06-17 15:58 ` [RFC v1 028/256] cl8k: add calib.c viktor.barna
                   ` (230 subsequent siblings)
  257 siblings, 0 replies; 262+ messages in thread
From: viktor.barna @ 2021-06-17 15:58 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Oleksandr Savchenko, Shay Bar, Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

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

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 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.
________________________________


^ permalink raw reply related	[flat|nested] 262+ messages in thread

* [RFC v1 028/256] cl8k: add calib.c
  2021-06-17 15:58 [RFC v1 000/256] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (26 preceding siblings ...)
  2021-06-17 15:58 ` [RFC v1 027/256] cl8k: add bus/pci/tx_pci.h viktor.barna
@ 2021-06-17 15:58 ` viktor.barna
  2021-06-17 15:58 ` [RFC v1 029/256] cl8k: add calib.h viktor.barna
                   ` (229 subsequent siblings)
  257 siblings, 0 replies; 262+ messages in thread
From: viktor.barna @ 2021-06-17 15:58 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Oleksandr Savchenko, Shay Bar, Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

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

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 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.
________________________________


^ permalink raw reply related	[flat|nested] 262+ messages in thread

* [RFC v1 029/256] cl8k: add calib.h
  2021-06-17 15:58 [RFC v1 000/256] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (27 preceding siblings ...)
  2021-06-17 15:58 ` [RFC v1 028/256] cl8k: add calib.c viktor.barna
@ 2021-06-17 15:58 ` viktor.barna
  2021-06-17 15:58 ` [RFC v1 030/256] cl8k: add cap.c viktor.barna
                   ` (228 subsequent siblings)
  257 siblings, 0 replies; 262+ messages in thread
From: viktor.barna @ 2021-06-17 15:58 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Oleksandr Savchenko, Shay Bar, Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

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

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 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.
________________________________


^ permalink raw reply related	[flat|nested] 262+ messages in thread

* [RFC v1 030/256] cl8k: add cap.c
  2021-06-17 15:58 [RFC v1 000/256] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (28 preceding siblings ...)
  2021-06-17 15:58 ` [RFC v1 029/256] cl8k: add calib.h viktor.barna
@ 2021-06-17 15:58 ` viktor.barna
  2021-06-17 15:58 ` [RFC v1 031/256] cl8k: add cap.h viktor.barna
                   ` (227 subsequent siblings)
  257 siblings, 0 replies; 262+ messages in thread
From: viktor.barna @ 2021-06-17 15:58 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Oleksandr Savchenko, Shay Bar, Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

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

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 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.
________________________________


^ permalink raw reply related	[flat|nested] 262+ messages in thread

* [RFC v1 031/256] cl8k: add cap.h
  2021-06-17 15:58 [RFC v1 000/256] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (29 preceding siblings ...)
  2021-06-17 15:58 ` [RFC v1 030/256] cl8k: add cap.c viktor.barna
@ 2021-06-17 15:58 ` viktor.barna
  2021-06-17 15:58 ` [RFC v1 032/256] cl8k: add cca.c viktor.barna
                   ` (226 subsequent siblings)
  257 siblings, 0 replies; 262+ messages in thread
From: viktor.barna @ 2021-06-17 15:58 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Oleksandr Savchenko, Shay Bar, Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

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

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 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.
________________________________


^ permalink raw reply related	[flat|nested] 262+ messages in thread

* [RFC v1 032/256] cl8k: add cca.c
  2021-06-17 15:58 [RFC v1 000/256] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (30 preceding siblings ...)
  2021-06-17 15:58 ` [RFC v1 031/256] cl8k: add cap.h viktor.barna
@ 2021-06-17 15:58 ` viktor.barna
  2021-06-17 15:58 ` [RFC v1 033/256] cl8k: add cca.h viktor.barna
                   ` (225 subsequent siblings)
  257 siblings, 0 replies; 262+ messages in thread
From: viktor.barna @ 2021-06-17 15:58 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Oleksandr Savchenko, Shay Bar, Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

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

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 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.
________________________________


^ permalink raw reply related	[flat|nested] 262+ messages in thread

* [RFC v1 033/256] cl8k: add cca.h
  2021-06-17 15:58 [RFC v1 000/256] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (31 preceding siblings ...)
  2021-06-17 15:58 ` [RFC v1 032/256] cl8k: add cca.c viktor.barna
@ 2021-06-17 15:58 ` viktor.barna
  2021-06-17 15:58 ` [RFC v1 034/256] cl8k: add cecli.c viktor.barna
                   ` (224 subsequent siblings)
  257 siblings, 0 replies; 262+ messages in thread
From: viktor.barna @ 2021-06-17 15:58 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Oleksandr Savchenko, Shay Bar, Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

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

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 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.
________________________________


^ permalink raw reply related	[flat|nested] 262+ messages in thread

* [RFC v1 034/256] cl8k: add cecli.c
  2021-06-17 15:58 [RFC v1 000/256] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (32 preceding siblings ...)
  2021-06-17 15:58 ` [RFC v1 033/256] cl8k: add cca.h viktor.barna
@ 2021-06-17 15:58 ` viktor.barna
  2021-06-17 15:58 ` [RFC v1 035/256] cl8k: add cecli.h viktor.barna
                   ` (223 subsequent siblings)
  257 siblings, 0 replies; 262+ messages in thread
From: viktor.barna @ 2021-06-17 15:58 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Oleksandr Savchenko, Shay Bar, Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

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

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 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.
________________________________


^ permalink raw reply related	[flat|nested] 262+ messages in thread

* [RFC v1 035/256] cl8k: add cecli.h
  2021-06-17 15:58 [RFC v1 000/256] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (33 preceding siblings ...)
  2021-06-17 15:58 ` [RFC v1 034/256] cl8k: add cecli.c viktor.barna
@ 2021-06-17 15:58 ` viktor.barna
  2021-06-17 15:58 ` [RFC v1 036/256] cl8k: add chandef.c viktor.barna
                   ` (222 subsequent siblings)
  257 siblings, 0 replies; 262+ messages in thread
From: viktor.barna @ 2021-06-17 15:58 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Oleksandr Savchenko, Shay Bar, Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

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

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 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.
________________________________


^ permalink raw reply related	[flat|nested] 262+ messages in thread

* [RFC v1 036/256] cl8k: add chandef.c
  2021-06-17 15:58 [RFC v1 000/256] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (34 preceding siblings ...)
  2021-06-17 15:58 ` [RFC v1 035/256] cl8k: add cecli.h viktor.barna
@ 2021-06-17 15:58 ` viktor.barna
  2021-06-17 15:58 ` [RFC v1 037/256] cl8k: add chandef.h viktor.barna
                   ` (221 subsequent siblings)
  257 siblings, 0 replies; 262+ messages in thread
From: viktor.barna @ 2021-06-17 15:58 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Oleksandr Savchenko, Shay Bar, Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

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

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 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.
________________________________


^ permalink raw reply related	[flat|nested] 262+ messages in thread

* [RFC v1 037/256] cl8k: add chandef.h
  2021-06-17 15:58 [RFC v1 000/256] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (35 preceding siblings ...)
  2021-06-17 15:58 ` [RFC v1 036/256] cl8k: add chandef.c viktor.barna
@ 2021-06-17 15:58 ` viktor.barna
  2021-06-17 15:58 ` [RFC v1 038/256] cl8k: add channel.c viktor.barna
                   ` (220 subsequent siblings)
  257 siblings, 0 replies; 262+ messages in thread
From: viktor.barna @ 2021-06-17 15:58 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Oleksandr Savchenko, Shay Bar, Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

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

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 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.
________________________________


^ permalink raw reply related	[flat|nested] 262+ messages in thread

* [RFC v1 038/256] cl8k: add channel.c
  2021-06-17 15:58 [RFC v1 000/256] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (36 preceding siblings ...)
  2021-06-17 15:58 ` [RFC v1 037/256] cl8k: add chandef.h viktor.barna
@ 2021-06-17 15:58 ` viktor.barna
  2021-06-17 15:58 ` [RFC v1 039/256] cl8k: add channel.h viktor.barna
                   ` (219 subsequent siblings)
  257 siblings, 0 replies; 262+ messages in thread
From: viktor.barna @ 2021-06-17 15:58 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Oleksandr Savchenko, Shay Bar, Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

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

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 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.
________________________________


^ permalink raw reply related	[flat|nested] 262+ messages in thread

* [RFC v1 039/256] cl8k: add channel.h
  2021-06-17 15:58 [RFC v1 000/256] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (37 preceding siblings ...)
  2021-06-17 15:58 ` [RFC v1 038/256] cl8k: add channel.c viktor.barna
@ 2021-06-17 15:58 ` viktor.barna
  2021-06-17 15:58 ` [RFC v1 040/256] cl8k: add chan_info.c viktor.barna
                   ` (218 subsequent siblings)
  257 siblings, 0 replies; 262+ messages in thread
From: viktor.barna @ 2021-06-17 15:58 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Oleksandr Savchenko, Shay Bar, Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

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

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 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.
________________________________


^ permalink raw reply related	[flat|nested] 262+ messages in thread

* [RFC v1 040/256] cl8k: add chan_info.c
  2021-06-17 15:58 [RFC v1 000/256] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (38 preceding siblings ...)
  2021-06-17 15:58 ` [RFC v1 039/256] cl8k: add channel.h viktor.barna
@ 2021-06-17 15:58 ` viktor.barna
  2021-06-17 15:58 ` [RFC v1 041/256] cl8k: add chan_info.h viktor.barna
                   ` (217 subsequent siblings)
  257 siblings, 0 replies; 262+ messages in thread
From: viktor.barna @ 2021-06-17 15:58 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Oleksandr Savchenko, Shay Bar, Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

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

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 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.
________________________________


^ permalink raw reply related	[flat|nested] 262+ messages in thread

* [RFC v1 041/256] cl8k: add chan_info.h
  2021-06-17 15:58 [RFC v1 000/256] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (39 preceding siblings ...)
  2021-06-17 15:58 ` [RFC v1 040/256] cl8k: add chan_info.c viktor.barna
@ 2021-06-17 15:58 ` viktor.barna
  2021-06-17 15:58 ` [RFC v1 042/256] cl8k: add chip.c viktor.barna
                   ` (216 subsequent siblings)
  257 siblings, 0 replies; 262+ messages in thread
From: viktor.barna @ 2021-06-17 15:58 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Oleksandr Savchenko, Shay Bar, Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

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

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 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.
________________________________


^ permalink raw reply related	[flat|nested] 262+ messages in thread

* [RFC v1 042/256] cl8k: add chip.c
  2021-06-17 15:58 [RFC v1 000/256] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (40 preceding siblings ...)
  2021-06-17 15:58 ` [RFC v1 041/256] cl8k: add chan_info.h viktor.barna
@ 2021-06-17 15:58 ` viktor.barna
  2021-06-17 15:58 ` [RFC v1 043/256] cl8k: add chip.h viktor.barna
                   ` (215 subsequent siblings)
  257 siblings, 0 replies; 262+ messages in thread
From: viktor.barna @ 2021-06-17 15:58 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Oleksandr Savchenko, Shay Bar, Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

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

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 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.
________________________________


^ permalink raw reply related	[flat|nested] 262+ messages in thread

* [RFC v1 043/256] cl8k: add chip.h
  2021-06-17 15:58 [RFC v1 000/256] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (41 preceding siblings ...)
  2021-06-17 15:58 ` [RFC v1 042/256] cl8k: add chip.c viktor.barna
@ 2021-06-17 15:58 ` viktor.barna
  2021-06-17 15:58 ` [RFC v1 044/256] cl8k: add chip_config.c viktor.barna
                   ` (214 subsequent siblings)
  257 siblings, 0 replies; 262+ messages in thread
From: viktor.barna @ 2021-06-17 15:58 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Oleksandr Savchenko, Shay Bar, Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

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

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 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.
________________________________


^ permalink raw reply related	[flat|nested] 262+ messages in thread

* [RFC v1 044/256] cl8k: add chip_config.c
  2021-06-17 15:58 [RFC v1 000/256] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (42 preceding siblings ...)
  2021-06-17 15:58 ` [RFC v1 043/256] cl8k: add chip.h viktor.barna
@ 2021-06-17 15:58 ` viktor.barna
  2021-06-17 15:58 ` [RFC v1 045/256] cl8k: add chip_config.h viktor.barna
                   ` (213 subsequent siblings)
  257 siblings, 0 replies; 262+ messages in thread
From: viktor.barna @ 2021-06-17 15:58 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Oleksandr Savchenko, Shay Bar, Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

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

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 .../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->ce_tcv_enabled[TCV0] && conf->ce_tcv_enabled[TCV1]) {
+               CL_DBG_ERROR_CHIP(chip,
+                                 "TCV1 can't be enabled without enabling TCV0\n");
+               return -EINVAL;
+       }
+
+       if (conf->ce_eeprom_mode >= E2P_MODE_MAX) {
+               CL_DBG_ERROR_CHIP(chip,
+                                 "Invalid ce_eeprom_mode [%u]. Must be 0 (file) or 1 (eeprom)\n",
+                                 conf->ce_eeprom_mode);
+               return -EINVAL;
+       }
+
+       if (conf->ce_first_mask_bit > MAX_FIRST_MASK_BIT) {
+               CL_DBG_ERROR_CHIP(chip, "Invalid ce_first_mask_bit (%u). Must be <= %u\n",
+                                 conf->ce_first_mask_bit, MAX_FIRST_MASK_BIT);
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static int set_all_params_from_buf(struct cl_chip *chip, char *buf, loff_t size)
+{
+       char *line = buf;
+       char name[MAX_PARAM_NAME_LENGTH];
+       char value[STR_LEN_256B];
+       char *begin;
+       char *end;
+       int ret = 0;
+       int name_length = 0;
+       int value_length = 0;
+
+       while (line && strlen(line) && (line != (buf + size))) {
+               if ((*line == '#') || (*line == '\n')) {
+                       /* Skip comment or blank line */
+                       line = strstr(line, "\n") + 1;
+               } else if (*line) {
+                       begin = line;
+                       end = strstr(begin, "=");
+
+                       if (!end) {
+                               ret = -EBADMSG;
+                               goto exit;
+                       }
+
+                       end++;
+                       name_length = end - begin;
+                       value_length = strstr(end, "\n") - end + 1;
+
+                       if (name_length >= MAX_PARAM_NAME_LENGTH) {
+                               cl_dbg_chip_err(chip, "Name too long (%u)\n", name_length);
+                               ret = -EBADMSG;
+                               goto exit;
+                       }
+                       if (value_length >= STR_LEN_256B) {
+                               cl_dbg_chip_err(chip, "Value too long (%u)\n", value_length);
+                               ret = -EBADMSG;
+                               goto exit;
+                       }
+
+                       snprintf(name, name_length, "%s", begin);
+                       snprintf(value, value_length, "%s", end);
+
+                       ret = update_config(chip, name, value);
+                       if (ret)
+                               goto exit;
+
+                       line = strstr(line, "\n") + 1;
+               }
+       }
+
+exit:
+
+       return ret;
+}
+
+int cl_chip_config_read(struct cl_chip *chip)
+{
+       char *buf = NULL;
+       loff_t size = 0;
+       int ret = 0;
+       char filename[CL_FILENAME_MAX] = {0};
+
+       /* Allocate cl_chip_conf */
+       chip->conf = kzalloc(sizeof(*chip->conf), GFP_KERNEL);
+       if (!chip->conf)
+               return -ENOMEM;
+
+       /* Copy default parameters */
+       memcpy(chip->conf, &chip_conf, sizeof(*chip->conf));
+
+       snprintf(filename, sizeof(filename), "cl_chip%u.dat", chip->idx);
+       pr_debug("%s: %s\n", __func__, filename);
+       size = cl_file_open_and_read(chip, filename, &buf);
+
+       if (!buf) {
+               pr_err("read %s failed !!!\n", filename);
+               return -ENODATA;
+       }
+
+       ret = set_all_params_from_buf(chip, buf, size);
+       if (ret) {
+               kfree(buf);
+               return ret;
+       }
+
+       kfree(buf);
+
+       if (!cl_chip_is_enabled(chip)) {
+               cl_dbg_chip_verbose(chip, "Disabled\n");
+               return -EOPNOTSUPP;
+       }
+
+       ret = post_configuration(chip);
+
+       return ret;
+}
+
+int cl_chip_config_set(struct cl_chip *chip, char *buf, loff_t size)
+{
+       loff_t new_size = size + 1;
+       char *new_buf = kzalloc(new_size, GFP_KERNEL);
+       int ret;
+
+       if (!new_buf)
+               return -ENOMEM;
+
+       /* Add '\n' at the end of the string, before the NULL */
+       memcpy(new_buf, buf, size);
+       new_buf[size - 1] = '\n';
+
+       ret = set_all_params_from_buf(chip, new_buf, new_size);
+       if (ret == 0)
+               ret = post_configuration(chip);
+
+       kfree(new_buf);
+
+       return ret;
+}
+
+void cl_chip_config_dealloc(struct cl_chip *chip)
+{
+       kfree(chip->conf);
+}
+
+void cl_chip_config_print(struct cl_chip *chip)
+{
+       struct cl_chip_conf *conf = chip->conf;
+
+       pr_debug("=======================\n");
+       pr_debug("  Chip%u configuration\n", chip->idx);
+       pr_debug("=======================\n");
+
+       print_unsigned_arr(ce_tcv_enabled, TCV_MAX);
+       print_str(ce_lmac);
+       print_str(ce_smac);
+       print_str(ce_umac);
+       print_signed(ce_irq_smp_affinity);
+       print_unsigned(ce_eeprom_mode);
+       print_bool(ce_production_mode);
+       print_bool(ci_pci_msi_enable);
+       print_unsigned_arr(ci_dma_lli_max_chan, TCV_MAX);
+       print_str(ce_country_code);
+       print_str(ce_ela_mode);
+       print_unsigned(ci_phy_dev);
+       print_signed(ce_debug_level);
+       print_unsigned(ce_host_pci_gen_ver);
+       print_bool(ce_temp_comp_en);
+       print_unsigned(ce_temp_protect_en);
+       print_signed(ce_temp_protect_delta);
+       print_signed(ce_temp_protect_th_max);
+       print_signed(ce_temp_protect_th_min);
+       print_unsigned(ce_temp_protect_tx_period_ms);
+       print_signed(ce_temp_protect_radio_off_th);
+       print_mac(ce_phys_mac_addr);
+       print_bool(ce_lam_enable);
+       print_unsigned(ce_first_mask_bit);
+       print_bool(ci_no_capture_noise_sleep);
+       print_unsigned_arr(ci_dcoc_mv_thr, CHNL_BW_MAX);
+       print_signed(ci_lolc_db_thr);
+       print_signed(ci_iq_db_thr);
+       print_bool(ci_rx_resched_tasklet);
+       print_unsigned(ci_rx_skb_max);
+       print_bool(ce_calib_scan_en);
+}
+
--
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.
________________________________


^ permalink raw reply related	[flat|nested] 262+ messages in thread

* [RFC v1 045/256] cl8k: add chip_config.h
  2021-06-17 15:58 [RFC v1 000/256] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (43 preceding siblings ...)
  2021-06-17 15:58 ` [RFC v1 044/256] cl8k: add chip_config.c viktor.barna
@ 2021-06-17 15:58 ` viktor.barna
  2021-06-17 15:58 ` [RFC v1 046/256] cl8k: add config.c viktor.barna
                   ` (212 subsequent siblings)
  257 siblings, 0 replies; 262+ messages in thread
From: viktor.barna @ 2021-06-17 15:58 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Oleksandr Savchenko, Shay Bar, Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

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

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 .../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.
________________________________


^ permalink raw reply related	[flat|nested] 262+ messages in thread

* [RFC v1 046/256] cl8k: add config.c
  2021-06-17 15:58 [RFC v1 000/256] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (44 preceding siblings ...)
  2021-06-17 15:58 ` [RFC v1 045/256] cl8k: add chip_config.h viktor.barna
@ 2021-06-17 15:58 ` viktor.barna
  2021-06-17 15:58 ` [RFC v1 047/256] cl8k: add config.h viktor.barna
                   ` (211 subsequent siblings)
  257 siblings, 0 replies; 262+ messages in thread
From: viktor.barna @ 2021-06-17 15:58 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Oleksandr Savchenko, Shay Bar, Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

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

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 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.
________________________________


^ permalink raw reply related	[flat|nested] 262+ messages in thread

* [RFC v1 047/256] cl8k: add config.h
  2021-06-17 15:58 [RFC v1 000/256] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (45 preceding siblings ...)
  2021-06-17 15:58 ` [RFC v1 046/256] cl8k: add config.c viktor.barna
@ 2021-06-17 15:58 ` viktor.barna
  2021-06-17 15:58 ` [RFC v1 048/256] cl8k: add coredump.c viktor.barna
                   ` (210 subsequent siblings)
  257 siblings, 0 replies; 262+ messages in thread
From: viktor.barna @ 2021-06-17 15:58 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Oleksandr Savchenko, Shay Bar, Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

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

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 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.
________________________________


^ permalink raw reply related	[flat|nested] 262+ messages in thread

* [RFC v1 048/256] cl8k: add coredump.c
  2021-06-17 15:58 [RFC v1 000/256] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (46 preceding siblings ...)
  2021-06-17 15:58 ` [RFC v1 047/256] cl8k: add config.h viktor.barna
@ 2021-06-17 15:58 ` viktor.barna
  2021-06-17 15:58 ` [RFC v1 049/256] cl8k: add coredump.h viktor.barna
                   ` (209 subsequent siblings)
  257 siblings, 0 replies; 262+ messages in thread
From: viktor.barna @ 2021-06-17 15:58 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Oleksandr Savchenko, Shay Bar, Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

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

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 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.
________________________________


^ permalink raw reply related	[flat|nested] 262+ messages in thread

* [RFC v1 049/256] cl8k: add coredump.h
  2021-06-17 15:58 [RFC v1 000/256] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (47 preceding siblings ...)
  2021-06-17 15:58 ` [RFC v1 048/256] cl8k: add coredump.c viktor.barna
@ 2021-06-17 15:58 ` viktor.barna
  2021-06-17 15:58 ` [RFC v1 050/256] cl8k: add data_rates.c viktor.barna
                   ` (208 subsequent siblings)
  257 siblings, 0 replies; 262+ messages in thread
From: viktor.barna @ 2021-06-17 15:58 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Oleksandr Savchenko, Shay Bar, Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

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

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 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.
________________________________


^ permalink raw reply related	[flat|nested] 262+ messages in thread

* [RFC v1 050/256] cl8k: add data_rates.c
  2021-06-17 15:58 [RFC v1 000/256] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (48 preceding siblings ...)
  2021-06-17 15:58 ` [RFC v1 049/256] cl8k: add coredump.h viktor.barna
@ 2021-06-17 15:58 ` viktor.barna
  2021-06-17 15:58 ` [RFC v1 051/256] cl8k: add data_rates.h viktor.barna
                   ` (207 subsequent siblings)
  257 siblings, 0 replies; 262+ messages in thread
From: viktor.barna @ 2021-06-17 15:58 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Oleksandr Savchenko, Shay Bar, Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

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

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 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.
________________________________


^ permalink raw reply related	[flat|nested] 262+ messages in thread

* [RFC v1 051/256] cl8k: add data_rates.h
  2021-06-17 15:58 [RFC v1 000/256] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (49 preceding siblings ...)
  2021-06-17 15:58 ` [RFC v1 050/256] cl8k: add data_rates.c viktor.barna
@ 2021-06-17 15:58 ` viktor.barna
  2021-06-17 15:58 ` [RFC v1 052/256] cl8k: add dbgfile.c viktor.barna
                   ` (206 subsequent siblings)
  257 siblings, 0 replies; 262+ messages in thread
From: viktor.barna @ 2021-06-17 15:58 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Oleksandr Savchenko, Shay Bar, Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

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

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 drivers/net/wireless/celeno/cl8k/data_rates.h | 30 +++++++++++++++++++
 1 file changed, 30 insertions(+)
 create mode 100644 drivers/net/wireless/celeno/cl8k/data_rates.h

diff --git a/drivers/net/wireless/celeno/cl8k/data_rates.h b/drivers/net/wireless/celeno/cl8k/data_rates.h
new file mode 100644
index 000000000000..ddb027402c19
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/data_rates.h
@@ -0,0 +1,30 @@
+/* SPDX-License-Identifier: MIT */
+/* Copyright(c) 2019-2021, Celeno Communications Ltd. */
+
+#ifndef CL_DATA_RATES_H
+#define CL_DATA_RATES_H
+
+#include "wrs/wrs_db.h"
+#include "def.h"
+
+#define DATA_RATE_INVERSE_Q 15
+
+struct cl_inverse_data_rate {
+       u16 he[CHNL_BW_MAX][WRS_SS_MAX][WRS_MCS_MAX_HE][WRS_GI_MAX_HE];
+       u16 ht_vht[CHNL_BW_MAX][WRS_SS_MAX][WRS_MCS_MAX_VHT][WRS_GI_MAX_VHT];
+       u16 ofdm[WRS_MCS_MAX_OFDM];
+       u16 cck[WRS_MCS_MAX_CCK];
+};
+
+extern struct cl_inverse_data_rate inverse_data_rate;
+
+extern const u16 data_rate_he_x10[CHNL_BW_MAX][WRS_SS_MAX][WRS_MCS_MAX_HE][WRS_GI_MAX_HE];
+extern const u16 data_rate_ht_vht_x10[CHNL_BW_MAX][WRS_SS_MAX][WRS_MCS_MAX_VHT][WRS_GI_MAX_VHT];
+extern const u16 data_rate_ofdm_x10[];
+extern const u16 data_rate_cck_x10[];
+
+void cl_data_rates_inverse_build(void);
+u16 cl_data_rates_get(u8 mode, u8 bw, u8 nss, u8 mcs, u8 gi);
+u16 cl_data_rates_get_x10(u8 mode, u8 bw, u8 nss, u8 mcs, u8 gi);
+
+#endif /* CL_DATA_RATES_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.
________________________________


^ permalink raw reply related	[flat|nested] 262+ messages in thread

* [RFC v1 052/256] cl8k: add dbgfile.c
  2021-06-17 15:58 [RFC v1 000/256] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (50 preceding siblings ...)
  2021-06-17 15:58 ` [RFC v1 051/256] cl8k: add data_rates.h viktor.barna
@ 2021-06-17 15:58 ` viktor.barna
  2021-06-17 15:59 ` [RFC v1 053/256] cl8k: add dbgfile.h viktor.barna
                   ` (205 subsequent siblings)
  257 siblings, 0 replies; 262+ messages in thread
From: viktor.barna @ 2021-06-17 15:58 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Oleksandr Savchenko, Shay Bar, Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

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

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 drivers/net/wireless/celeno/cl8k/dbgfile.c | 438 +++++++++++++++++++++
 1 file changed, 438 insertions(+)
 create mode 100644 drivers/net/wireless/celeno/cl8k/dbgfile.c

diff --git a/drivers/net/wireless/celeno/cl8k/dbgfile.c b/drivers/net/wireless/celeno/cl8k/dbgfile.c
new file mode 100644
index 000000000000..1e8aebbe91f4
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/dbgfile.c
@@ -0,0 +1,438 @@
+// SPDX-License-Identifier: MIT
+/* Copyright(c) 2019-2021, Celeno Communications Ltd. */
+
+#include <linux/ctype.h>
+#include "dbgfile.h"
+#include "reg/reg_access.h"
+#include "utils/utils.h"
+#include "dbgfile.h"
+
+const char *cl_dbgfile_get_msg_txt(struct cl_dbg_data *dbg_data, int file_id, int line)
+{
+       /* Get the message text from the .dbg file by fileid & line number */
+       int remaining_bytes = dbg_data->size;
+       const char *str = dbg_data->str;
+       char id_str[32];
+       int idstr_len;
+
+       if (!str || 0 == remaining_bytes)
+               return NULL;
+
+       idstr_len = snprintf(id_str, sizeof(id_str), "%hu:%hu:", file_id, line);
+
+       /* Skip hash */
+       while (*str++ != '\n')
+               ;
+
+       remaining_bytes -= (str - (char *)dbg_data->str);
+
+       while (remaining_bytes > 0) {
+               if (strncmp(id_str, str, idstr_len) == 0) {
+                       str += idstr_len;
+                       while (*str == ' ')
+                               ++str;
+                       return (const char *)str;
+               }
+
+               str += strnlen(str, 512) + 1;
+               remaining_bytes = dbg_data->size - (str - (char *)dbg_data->str);
+       }
+
+       /* No match found */
+       pr_err("error: file_id=%d line=%d not found in debug print file\n", file_id, line);
+       return NULL;
+}
+
+void cl_dbgfile_parse(struct cl_hw *cl_hw, void *edata, u32 esize)
+{
+       /* Parse & store the firmware debug file */
+       struct cl_dbg_data *dbg_data = &cl_hw->dbg_data;
+
+       dbg_data->size = esize;
+       dbg_data->str = edata;
+}
+
+void cl_dbgfile_release_mem(struct cl_dbg_data *dbg_data,
+                           struct cl_str_offload_env *str_offload_env)
+{
+       dbg_data->str = NULL;
+
+       str_offload_env->enabled = false;
+       str_offload_env->block1 = NULL;
+       str_offload_env->block2 = NULL;
+}
+
+/*
+ * Store debug print offload data
+ * - part 1: offloaded block that does not exist on target
+ * - part 2: resident block that remains on target [optional]
+ */
+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)
+{
+       u32 u = size1;
+       struct cl_str_offload_env *str_offload_env = &cl_hw->str_offload_env;
+
+       if (u > 200000)
+               goto err_too_big;
+
+       /* TODO we modify offload data! if caller checks integrity, make a copy? */
+       str_offload_env->block1 = data1;
+       str_offload_env->size1 = size1;
+       str_offload_env->base1 = base1;
+
+       str_offload_env->block2 = data2;
+       str_offload_env->size2 = size2;
+       str_offload_env->base2 = base2;
+
+       str_offload_env->block3 = data3;
+       str_offload_env->size3 = size3;
+       str_offload_env->base3 = base3;
+
+       str_offload_env->enabled = true;
+
+       cl_dbg_info(cl_hw, "%cmac%u: FW prints offload memory use = %uK\n",
+                   cl_hw->fw_prefix, chip->idx, (size1 + size2 + 1023) / 1024);
+
+       return 0;
+
+err_too_big:
+       pr_err("%s: size too big: %u\n", __func__, u);
+       return 1;
+}
+
+static void do_print_n(struct cl_hw *cl_hw, const char *str, int n)
+{
+       /* Print formatted string with "band" prefix */
+       if (n < 0 || n > 256) {
+               cl_dbg_err(cl_hw, "%cmac%u: *** FW PRINT - BAD SIZE: %d\n",
+                          cl_hw->fw_prefix, cl_hw->chip->idx, n);
+               return;
+       }
+
+       cl_dbg_verbose(cl_hw, "%cmac%u: %.*s\n", cl_hw->fw_prefix, cl_hw->chip->idx, n, str);
+}
+
+static void do_hex_dump_bytes(struct cl_hw *cl_hw, u32 addr, void *data, u32 count)
+{
+       cl_dbg_verbose(cl_hw, "%cmac%u: hex dump:\n", cl_hw->fw_prefix, cl_hw->chip->idx);
+       cl_hex_dump(NULL, data, count, addr, true);
+}
+
+#define MAGIC_PRINT_OFFLOAD   0xFA  /* 1st (low) byte of signature */
+/* 2-nd signature byte */
+#define MAGIC_PRINT_OFF_XDUMP 0xD0  /* Hex dump, by bytes */
+#define MAGIC_PRINT_OFF_LIT   0x01  /* Literal/preformatted string */
+#define MAGIC_PRINT_OFF_PRINT 0x02  /* Print with 'virtual' format string */
+
+#define MAX_PRINT_OFF_PARAMS  20
+
+static int offload_print(struct cl_str_offload_env *str_offload_env, char *fmt, const char *params)
+{
+       static char buf[1024] = {0};
+       const char *cur_prm = params;
+       char tmp;
+       char *fmt_end = fmt;
+       size_t size = sizeof(int);
+       int len = 0;
+
+       union v {
+               u32 val32;
+               u64 val64;
+               ptrdiff_t str;
+       } v;
+
+       while ((fmt_end = strchr(fmt_end, '%'))) {
+               fmt_end++;
+
+               /* Skip '%%'. */
+               if (*fmt_end == '%') {
+                       fmt_end++;
+                       continue;
+               }
+
+               /* Skip flags. */
+               while (strchr("-+ 0#", *fmt_end))
+                       fmt_end++;
+
+               /* Skip width. */
+               while (isdigit(*fmt_end))
+                       fmt_end++;
+
+               /* Skip precision. */
+               if (*fmt_end == '.') {
+                       while (*fmt_end == '-' || *fmt_end == '+')
+                               fmt_end++;
+
+                       while (isdigit(*fmt_end))
+                               fmt_end++;
+               }
+
+               /* Get size. */
+               if (*fmt_end == 'z') {
+                       /* Remove 'z' from %zu, %zd, %zx and %zX,
+                        * because sizeof(size_t) == 4 in the firmware.
+                        * 'z' can only appear in front of 'd', 'u', 'x' or 'X'.
+                        */
+                       if (!strchr("duxX", *(fmt_end + 1)))
+                               return -1;
+
+                       fmt_end++;
+                       size = 4;
+               } else if (*fmt_end == 'l') {
+                       fmt_end++;
+
+                       if (*fmt_end == 'l') {
+                               fmt_end++;
+                               size = sizeof(long long);
+                       } else {
+                               size = sizeof(long);
+                       }
+
+                       if (*fmt_end == 'p') /* %p can't get 'l' or 'll' modifiers. */
+                               return -1;
+               } else {
+                       size = 4;
+               }
+
+               /* Get parameter. */
+               switch (*fmt_end) {
+               case 'p': /* Replace %p with %x, because the firmware's pointers are 32 bit wide */
+                       *fmt_end = 'x';
+                       fallthrough;
+               case 'd':
+               case 'u':
+               case 'x':
+               case 'X':
+                       if (size == 4)
+                               v.val32 = __le32_to_cpu(*(__le32 *)cur_prm);
+                       else
+                               v.val64 = __le64_to_cpu(*(__le64 *)cur_prm);
+                       cur_prm += size;
+                       break;
+               case 's':
+                       v.str = __le32_to_cpu(*(__le32 *)cur_prm);
+                       cur_prm += 4;
+                       size = sizeof(ptrdiff_t);
+
+                       if (v.str >= str_offload_env->base3 &&
+                           v.str < str_offload_env->base3 + str_offload_env->size3) {
+                               v.str -= str_offload_env->base3;
+                               v.str += (ptrdiff_t)str_offload_env->block3;
+                       } else if (v.str >= str_offload_env->base2 &&
+                                  v.str < str_offload_env->base2 + str_offload_env->size2) {
+                               v.str -= str_offload_env->base2;
+                               v.str += (ptrdiff_t)str_offload_env->block2;
+                       } else
+                               return -1;
+
+                       break;
+               default:
+                       return -1;
+               }
+
+               /* Print into buffer. */
+               fmt_end++;
+               tmp = *fmt_end; /* Truncate the format to the current point and then restore. */
+               *fmt_end = 0;
+               len += snprintf(buf + len, sizeof(buf) - len, fmt, size == 4 ? v.val32 : v.val64);
+               *fmt_end = tmp;
+               fmt = fmt_end;
+       }
+
+       snprintf(buf + len, sizeof(buf) - len, "%s", fmt);
+
+       pr_debug("%s", buf);
+
+       return 0;
+}
+
+struct pr_off_desc {
+       u8 file_id;
+       u8 flag;
+       __le16 line_num;
+       char fmt[];
+};
+
+char *strreplace(char *s, char old, char new)
+{
+       for (; *s; ++s)
+               if (*s == old)
+                       *s = new;
+       return s;
+}
+
+static int do_dprint(struct cl_hw *cl_hw, u32 fmtaddr, u32 nparams, u32 *params)
+{
+       /*
+        * fmtaddr - virtual address of format descriptor in firmware,
+        *           must be in the offloaded segment
+        * nparams - size of parameters array in u32; min=0, max=MAX_PRINT_OFF_PARAMS
+        * params  - array of parameters[nparams]
+        */
+       struct cl_str_offload_env *str_offload_env = &cl_hw->str_offload_env;
+       struct pr_off_desc *pfmt = NULL;
+
+       if (!str_offload_env->enabled)
+               return -1;
+
+       if (fmtaddr & 0x3)
+               cl_dbg_warn(cl_hw, "FW PRINT - format not aligned on 4? %8.8X\n", fmtaddr);
+
+       if (fmtaddr > str_offload_env->base1 &&
+           fmtaddr < (str_offload_env->base1 + str_offload_env->size1)) {
+               pfmt = (void *)((fmtaddr - str_offload_env->base1) + str_offload_env->block1);
+       } else {
+               cl_dbg_err(cl_hw, "FW PRINT - format not in allowed area %8.8X\n", fmtaddr);
+               return -1;
+       }
+
+       /*
+        * Current string sent by firmware is #mac@ where # is '253' and @ is '254'
+        * Replace '253' with 'l' or 's' according to the fw_prefix.
+        * Replace '254' with '0' or '1' according to chip index.
+        */
+       strreplace(pfmt->fmt, (char)253, cl_hw->fw_prefix);
+       strreplace(pfmt->fmt, (char)254, (cl_hw->chip->idx == CHIP0) ? '0' : '1');
+
+       if (offload_print(str_offload_env, pfmt->fmt, (char *)params) == -1) {
+               cl_dbg_err(cl_hw, "FW PRINT - ERROR in format! (file %u:%u)\n",
+                          pfmt->file_id, pfmt->line_num);
+               /* $$$ dbg dump the struct */
+               cl_hex_dump(NULL, (void *)pfmt, 48, fmtaddr, true);
+               return -1;
+       }
+
+       return 0;
+}
+
+static int do_offload(struct cl_hw *cl_hw, u8 *data, int bytes_remaining)
+{
+       u8 magic2 = data[1];
+       u32 nb = data[2] + (data[3] << 8); /* Following size in bytes */
+       /* DATA IS UNALIGNED! REVISE if alignment required or BIG ENDIAN! */
+       __le32 *dp = (__le32 *)data;
+       int bytes_consumed = 4; /* 1 + 1 + 2 */
+
+       /* Data: [0] u8 magic1, u8 magic2, u16 following size in bytes */
+       if (bytes_remaining < 8) {
+               cl_dbg_err(cl_hw, "*** FW PRINT - OFFLOAD PACKET TOO SHORT: %d\n",
+                          bytes_remaining);
+               return bytes_remaining;
+       }
+
+       if (bytes_remaining < (nb + bytes_consumed)) {
+               cl_dbg_err(cl_hw, "*** FW PRINT - OFFLOAD PACKET %u > remainder %d??\n",
+                          nb, bytes_remaining);
+               return bytes_remaining;
+       }
+
+       switch (magic2) {
+       case MAGIC_PRINT_OFF_PRINT: {
+               /*
+                * [1] u32 format descriptor ptr
+                * [2] u32[] parameters
+                */
+               u32 fmtp = dp[1];
+               u32 np = (nb - 4) / 4; /* Number of printf parameters */
+
+               if (nb < 4 || nb & 3)  {
+                       cl_dbg_err(cl_hw, "*** FW PRINT - bad pkt size: %u\n", nb);
+                       goto err;
+               }
+
+               do_dprint(cl_hw, fmtp, np, &dp[2]);
+
+               bytes_consumed += nb; /* Already padded to 4 bytes */
+               }
+               break;
+
+       case MAGIC_PRINT_OFF_LIT: {
+               /* [1] Remaining bytes: literal string */
+               do_print_n(cl_hw, (char *)&dp[1], nb);
+               bytes_consumed += ((nb + 3) / 4) * 4; /* Padding to 4 bytes */
+               }
+               break;
+
+       case MAGIC_PRINT_OFF_XDUMP:
+               /* [1] bytes[nb] */
+               if (nb >= 1)
+                       do_hex_dump_bytes(cl_hw, 0, &dp[1], nb);
+
+               bytes_consumed += ((nb + 3) / 4) * 4; /* Padding to 4 bytes */
+               break;
+
+       default:
+               cl_dbg_err(cl_hw, "*** FW PRINT - BAD TYPE: %4.4X\n", magic2);
+               goto err;
+       }
+
+       return bytes_consumed;
+
+err:
+       return bytes_remaining; /* Skip all */
+}
+
+void cl_dbgfile_print_fw_str(struct cl_hw *cl_hw, u8 *str, int max_size)
+{
+       /* Handler for firmware debug prints */
+       int bytes_remaining = max_size;
+       int i;
+       u8 delim = 0;
+
+       while (bytes_remaining > 0) {
+               /* Scan for normal print data: */
+               for (i = 0; i < bytes_remaining; i++) {
+                       if (str[i] < ' ' || str[i] >= 0x7F) {
+                               if (str[i] == '\t')
+                                       continue;
+                               delim = str[i];
+                               break;
+                       }
+               }
+
+               if (i > 0) {
+                       if (delim == '\n') {
+                               bytes_remaining -= i + 1;
+                               do_print_n(cl_hw, str, i);
+                               str += i + 1;
+                               continue;
+                       }
+
+                       if (delim != MAGIC_PRINT_OFFLOAD) {
+                               do_print_n(cl_hw, str, i);
+                               bytes_remaining -= i;
+                               return; /* Better stop parsing this */
+                       }
+                       /* Found offload packet but previous string not terminated: */
+                       do_print_n(cl_hw, str, i);
+                       cl_dbg_err(cl_hw, "*** FW PRINT - NO LINE END2\n");
+                       bytes_remaining -= i;
+                       str += i;
+                       continue;
+               }
+
+               /* Delimiter at offset 0 */
+               switch (delim) {
+               case '\n':
+                       do_print_n(cl_hw, " ", 1); /* Print empty line */
+                       str++;
+                       bytes_remaining--;
+                       continue;
+               case 0:
+                       return;
+               case MAGIC_PRINT_OFFLOAD:
+                       i = do_offload(cl_hw, str, bytes_remaining);
+                       bytes_remaining -= i;
+                       str += i;
+                       break;
+               default:
+                       cl_dbg_err(cl_hw, "*** FW PRINT - BAD BYTE=%2.2X ! rem=%d\n",
+                                  delim, bytes_remaining);
+                       return; /* Better stop parsing this */
+               }
+       }
+}
+
--
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.
________________________________


^ permalink raw reply related	[flat|nested] 262+ messages in thread

* [RFC v1 053/256] cl8k: add dbgfile.h
  2021-06-17 15:58 [RFC v1 000/256] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (51 preceding siblings ...)
  2021-06-17 15:58 ` [RFC v1 052/256] cl8k: add dbgfile.c viktor.barna
@ 2021-06-17 15:59 ` viktor.barna
  2021-06-17 15:59 ` [RFC v1 054/256] cl8k: add debug.h viktor.barna
                   ` (204 subsequent siblings)
  257 siblings, 0 replies; 262+ messages in thread
From: viktor.barna @ 2021-06-17 15:59 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Oleksandr Savchenko, Shay Bar, Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

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

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 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.
________________________________


^ permalink raw reply related	[flat|nested] 262+ messages in thread

* [RFC v1 054/256] cl8k: add debug.h
  2021-06-17 15:58 [RFC v1 000/256] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (52 preceding siblings ...)
  2021-06-17 15:59 ` [RFC v1 053/256] cl8k: add dbgfile.h viktor.barna
@ 2021-06-17 15:59 ` viktor.barna
  2021-06-17 15:59 ` [RFC v1 055/256] cl8k: add debugfs.c viktor.barna
                   ` (203 subsequent siblings)
  257 siblings, 0 replies; 262+ messages in thread
From: viktor.barna @ 2021-06-17 15:59 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Oleksandr Savchenko, Shay Bar, Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

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

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 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.
________________________________


^ permalink raw reply related	[flat|nested] 262+ messages in thread

* [RFC v1 055/256] cl8k: add debugfs.c
  2021-06-17 15:58 [RFC v1 000/256] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (53 preceding siblings ...)
  2021-06-17 15:59 ` [RFC v1 054/256] cl8k: add debug.h viktor.barna
@ 2021-06-17 15:59 ` viktor.barna
  2021-06-17 15:59 ` [RFC v1 056/256] cl8k: add debugfs.h viktor.barna
                   ` (202 subsequent siblings)
  257 siblings, 0 replies; 262+ messages in thread
From: viktor.barna @ 2021-06-17 15:59 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Oleksandr Savchenko, Shay Bar, Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

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

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 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.
________________________________


^ permalink raw reply related	[flat|nested] 262+ messages in thread

* [RFC v1 056/256] cl8k: add debugfs.h
  2021-06-17 15:58 [RFC v1 000/256] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (54 preceding siblings ...)
  2021-06-17 15:59 ` [RFC v1 055/256] cl8k: add debugfs.c viktor.barna
@ 2021-06-17 15:59 ` viktor.barna
  2021-06-17 15:59 ` [RFC v1 057/256] cl8k: add debugfs_defs.h viktor.barna
                   ` (201 subsequent siblings)
  257 siblings, 0 replies; 262+ messages in thread
From: viktor.barna @ 2021-06-17 15:59 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Oleksandr Savchenko, Shay Bar, Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

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

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 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.
________________________________


^ permalink raw reply related	[flat|nested] 262+ messages in thread

* [RFC v1 057/256] cl8k: add debugfs_defs.h
  2021-06-17 15:58 [RFC v1 000/256] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (55 preceding siblings ...)
  2021-06-17 15:59 ` [RFC v1 056/256] cl8k: add debugfs.h viktor.barna
@ 2021-06-17 15:59 ` viktor.barna
  2021-06-17 15:59 ` [RFC v1 058/256] cl8k: add def.h viktor.barna
                   ` (200 subsequent siblings)
  257 siblings, 0 replies; 262+ messages in thread
From: viktor.barna @ 2021-06-17 15:59 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Oleksandr Savchenko, Shay Bar, Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

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

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 .../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.
________________________________


^ permalink raw reply related	[flat|nested] 262+ messages in thread

* [RFC v1 058/256] cl8k: add def.h
  2021-06-17 15:58 [RFC v1 000/256] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (56 preceding siblings ...)
  2021-06-17 15:59 ` [RFC v1 057/256] cl8k: add debugfs_defs.h viktor.barna
@ 2021-06-17 15:59 ` viktor.barna
  2021-06-17 15:59 ` [RFC v1 059/256] cl8k: add dfs/dfs.c viktor.barna
                   ` (199 subsequent siblings)
  257 siblings, 0 replies; 262+ messages in thread
From: viktor.barna @ 2021-06-17 15:59 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Oleksandr Savchenko, Shay Bar, Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

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

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 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.
________________________________


^ permalink raw reply related	[flat|nested] 262+ messages in thread

* [RFC v1 059/256] cl8k: add dfs/dfs.c
  2021-06-17 15:58 [RFC v1 000/256] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (57 preceding siblings ...)
  2021-06-17 15:59 ` [RFC v1 058/256] cl8k: add def.h viktor.barna
@ 2021-06-17 15:59 ` viktor.barna
  2021-06-17 15:59 ` [RFC v1 060/256] cl8k: add dfs/dfs.h viktor.barna
                   ` (198 subsequent siblings)
  257 siblings, 0 replies; 262+ messages in thread
From: viktor.barna @ 2021-06-17 15:59 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Oleksandr Savchenko, Shay Bar, Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

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

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 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.
________________________________


^ permalink raw reply related	[flat|nested] 262+ messages in thread

* [RFC v1 060/256] cl8k: add dfs/dfs.h
  2021-06-17 15:58 [RFC v1 000/256] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (58 preceding siblings ...)
  2021-06-17 15:59 ` [RFC v1 059/256] cl8k: add dfs/dfs.c viktor.barna
@ 2021-06-17 15:59 ` viktor.barna
  2021-06-17 15:59 ` [RFC v1 061/256] cl8k: add dfs/dfs_db.h viktor.barna
                   ` (197 subsequent siblings)
  257 siblings, 0 replies; 262+ messages in thread
From: viktor.barna @ 2021-06-17 15:59 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Oleksandr Savchenko, Shay Bar, Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

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

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 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.
________________________________


^ permalink raw reply related	[flat|nested] 262+ messages in thread

* [RFC v1 061/256] cl8k: add dfs/dfs_db.h
  2021-06-17 15:58 [RFC v1 000/256] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (59 preceding siblings ...)
  2021-06-17 15:59 ` [RFC v1 060/256] cl8k: add dfs/dfs.h viktor.barna
@ 2021-06-17 15:59 ` viktor.barna
  2021-06-17 15:59 ` [RFC v1 062/256] cl8k: add dfs/radar.c viktor.barna
                   ` (196 subsequent siblings)
  257 siblings, 0 replies; 262+ messages in thread
From: viktor.barna @ 2021-06-17 15:59 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Oleksandr Savchenko, Shay Bar, Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

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

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 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.
________________________________


^ permalink raw reply related	[flat|nested] 262+ messages in thread

* [RFC v1 062/256] cl8k: add dfs/radar.c
  2021-06-17 15:58 [RFC v1 000/256] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (60 preceding siblings ...)
  2021-06-17 15:59 ` [RFC v1 061/256] cl8k: add dfs/dfs_db.h viktor.barna
@ 2021-06-17 15:59 ` viktor.barna
  2021-06-17 15:59 ` [RFC v1 063/256] cl8k: add dfs/radar.h viktor.barna
                   ` (195 subsequent siblings)
  257 siblings, 0 replies; 262+ messages in thread
From: viktor.barna @ 2021-06-17 15:59 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Oleksandr Savchenko, Shay Bar, Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

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

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 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.
________________________________


^ permalink raw reply related	[flat|nested] 262+ messages in thread

* [RFC v1 063/256] cl8k: add dfs/radar.h
  2021-06-17 15:58 [RFC v1 000/256] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (61 preceding siblings ...)
  2021-06-17 15:59 ` [RFC v1 062/256] cl8k: add dfs/radar.c viktor.barna
@ 2021-06-17 15:59 ` viktor.barna
  2021-06-17 15:59 ` [RFC v1 064/256] cl8k: add drv_ops.h viktor.barna
                   ` (194 subsequent siblings)
  257 siblings, 0 replies; 262+ messages in thread
From: viktor.barna @ 2021-06-17 15:59 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Oleksandr Savchenko, Shay Bar, Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

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

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 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.
________________________________


^ permalink raw reply related	[flat|nested] 262+ messages in thread

* [RFC v1 064/256] cl8k: add drv_ops.h
  2021-06-17 15:58 [RFC v1 000/256] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (62 preceding siblings ...)
  2021-06-17 15:59 ` [RFC v1 063/256] cl8k: add dfs/radar.h viktor.barna
@ 2021-06-17 15:59 ` viktor.barna
  2021-06-17 15:59 ` [RFC v1 065/256] cl8k: add dsp.c viktor.barna
                   ` (193 subsequent siblings)
  257 siblings, 0 replies; 262+ messages in thread
From: viktor.barna @ 2021-06-17 15:59 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Oleksandr Savchenko, Shay Bar, Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

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

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 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.
________________________________


^ permalink raw reply related	[flat|nested] 262+ messages in thread

* [RFC v1 065/256] cl8k: add dsp.c
  2021-06-17 15:58 [RFC v1 000/256] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (63 preceding siblings ...)
  2021-06-17 15:59 ` [RFC v1 064/256] cl8k: add drv_ops.h viktor.barna
@ 2021-06-17 15:59 ` viktor.barna
  2021-06-17 15:59 ` [RFC v1 066/256] cl8k: add dsp.h viktor.barna
                   ` (192 subsequent siblings)
  257 siblings, 0 replies; 262+ messages in thread
From: viktor.barna @ 2021-06-17 15:59 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Oleksandr Savchenko, Shay Bar, Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

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

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 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.
________________________________


^ permalink raw reply related	[flat|nested] 262+ messages in thread

* [RFC v1 066/256] cl8k: add dsp.h
  2021-06-17 15:58 [RFC v1 000/256] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (64 preceding siblings ...)
  2021-06-17 15:59 ` [RFC v1 065/256] cl8k: add dsp.c viktor.barna
@ 2021-06-17 15:59 ` viktor.barna
  2021-06-17 15:59 ` [RFC v1 067/256] cl8k: add e2p.c viktor.barna
                   ` (191 subsequent siblings)
  257 siblings, 0 replies; 262+ messages in thread
From: viktor.barna @ 2021-06-17 15:59 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Oleksandr Savchenko, Shay Bar, Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

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

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 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.
________________________________


^ permalink raw reply related	[flat|nested] 262+ messages in thread

* [RFC v1 067/256] cl8k: add e2p.c
  2021-06-17 15:58 [RFC v1 000/256] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (65 preceding siblings ...)
  2021-06-17 15:59 ` [RFC v1 066/256] cl8k: add dsp.h viktor.barna
@ 2021-06-17 15:59 ` viktor.barna
  2021-06-17 15:59 ` [RFC v1 068/256] cl8k: add e2p.h viktor.barna
                   ` (190 subsequent siblings)
  257 siblings, 0 replies; 262+ messages in thread
From: viktor.barna @ 2021-06-17 15:59 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Oleksandr Savchenko, Shay Bar, Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

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

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 drivers/net/wireless/celeno/cl8k/e2p.c | 664 +++++++++++++++++++++++++
 1 file changed, 664 insertions(+)
 create mode 100644 drivers/net/wireless/celeno/cl8k/e2p.c

diff --git a/drivers/net/wireless/celeno/cl8k/e2p.c b/drivers/net/wireless/celeno/cl8k/e2p.c
new file mode 100644
index 000000000000..0e51d88b042a
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/e2p.c
@@ -0,0 +1,664 @@
+// SPDX-License-Identifier: MIT
+/* Copyright(c) 2019-2021, Celeno Communications Ltd. */
+
+#include <linux/delay.h>
+#include <linux/kernel.h>
+#include "utils/utils.h"
+#include "utils/file.h"
+#include "chip.h"
+#include "e2p.h"
+#include "reg/reg_access.h"
+#include "config.h"
+
+#define EEPROM_VERSION 2
+
+/* EEPROM Parameters - Suitable for ATMEL AT24C16BN */
+#define E2P_SIZE       0x800               /* 2KB = 16Kbit */
+#define E2P_PAGE_SIZE  0x10                /* 16 Bytes */
+#define E2P_PAGE_MASK  (E2P_PAGE_SIZE - 1) /* 0xF */
+#define E2P_PAGE_SHIFT 0x4
+
+#define PAGE_NUM(addr) ((addr) >> E2P_PAGE_SHIFT)
+#define PAGE_OFF(addr) ((addr) & E2P_PAGE_MASK)
+
+enum bit_num {
+       BIT0,
+       BIT1,
+       BIT2,
+       BIT3,
+       BIT4,
+       BIT5,
+       BIT6,
+       BIT7,
+       BIT8,
+       BIT9,
+       BIT10,
+       BIT11,
+       BIT12,
+       BIT13,
+       BIT14,
+       BIT15,
+       BIT16,
+       BIT17,
+       BIT18,
+       BIT19,
+       BIT20,
+       BIT21,
+       BIT22,
+       BIT23,
+       BIT24,
+       BIT25,
+       BIT26,
+       BIT27,
+       BIT28,
+       BIT29,
+       BIT30,
+       BIT31
+};
+
+/*
+ * MACSYS_I2C:: PRERLO (0x0) - Clock Prescale register lo-byte
+ * Width: 8, Access: RW, Reset: 0xff.
+ */
+#define I2C_PRERLO (I2C_REG_BASE_ADDR + 0x0)
+
+/*
+ * MACSYS_I2C:: PRERHI (0x4) - Clock Prescale register lo-byte
+ * Width: 8, Access: RW, Reset: 0xff.
+ */
+#define I2C_PRERHI (I2C_REG_BASE_ADDR + 0x4)
+
+/*
+ * MACSYS_I2C:: CTR (0x8) - Control Register
+ * Width: 8, Access: RW, Reset: 0x00.
+ */
+#define I2C_CTR (I2C_REG_BASE_ADDR + 0x8)
+
+#define EN (BIT7) /* ‘1’ the core is enabled. */
+
+/*
+ * MACSYS_I2C:: TXR_RXR (0xC) - Transmit Register - Data
+ * Width: 8, Access: W, Reset: 0x00.
+ */
+#define I2C_TXD (I2C_REG_BASE_ADDR + 0xC)
+
+/* 7:0 TXD */
+#define TXD (BIT0) /* Next byte to transmit via I2C */
+
+#define TXD_MASK (0xFF << TXD)
+
+/*
+ * MACSYS_I2C:: TXR_RXR (0xC) - Transmit Register - Address
+ * Width: 8, Access: W, Reset: 0x00.
+ */
+#define I2C_TXADDR (I2C_REG_BASE_ADDR + 0xC)
+
+/*
+ * 7:1 TXADDR
+ * 0 RDWR
+ */
+#define TXADDR (BIT1) /* I2C Slave Address */
+#define RDWR   (BIT0) /* ‘1’ = reading from slave. ‘0’ = writing to slave. */
+
+#define TXADDR_MASK (0x7F << TXADDR)
+
+/*
+ * MACSYS_I2C:: TXR_RXR (0xC) - Receive Register
+ * Width: 8, Access: R, Reset: 0x00.
+ */
+#define I2C_RXD (I2C_REG_BASE_ADDR + 0xC)
+
+/* 7:0 RXD */
+#define RXD (BIT0) /* Last byte received via I2C. */
+#define RXD_MASK (0xFF << RXD)
+
+/*
+ * MACSYS_I2C:: CR_SR (0x10) - Command Register
+ * Width: 8, Access: WC, Reset: 0x00.
+ */
+#define I2C_CR (I2C_REG_BASE_ADDR + 0x10)
+
+/*
+ * 7 STA
+ * 6 STO
+ * 5 RD
+ * 4 WR
+ * 3 ACK
+ * 2:1 RES
+ * 0 IACK
+ */
+#define STA  (BIT7) /* Generate (repeated) start condition. */
+#define STO  (BIT6) /* Generate stop condition. */
+#define RD   (BIT5) /* Read from slave. */
+#define WR   (BIT4) /* Write to slave. */
+#define ACK  (BIT3) /* When a receiver, sent ACK (ACK = ‘0’) or NACK (NACK = ‘1’). */
+#define IACK (BIT0) /* Interrupt acknowledge, When set, clears a pending interrupt. */
+
+/*
+ * MACSYS_I2C:: CR_SR (0x10) - Status Register
+ * Width: 8, Access: R, Reset: 0x00.
+ */
+#define I2C_SR (I2C_REG_BASE_ADDR + 0x10)
+
+/*
+ * 7 RX_ACK - Received acknowledge from slave - ‘1’ = No acknowledge received.
+ * 6 BUSY - I2C bus busy - ‘1’ after START signal detected. ‘0’ after STOP signal detected.
+ * 5 AL - Arbitration lost - This bit is set when the core lost arbitration.
+ * 4:2 RES
+ * 1 TIP - Transfer in progress. ‘1’ when transferring data. ‘0’ when transfer complete.
+ * 0 IF - Set when interrupt is pending, cause a processor interrupt if the IEN bit is set.
+ */
+#define RX_ACK (BIT7)
+#define BUSY   (BIT6)
+#define AL     (BIT5)
+#define TIP    (BIT1)
+#define IF     (BIT0)
+
+#define I2C_EEPROM_ADDR(page) (0xA0 | (((page) >> 3) & 0xE)) /* [1-0-1-0-P2-P1-P0-0] */
+
+/* E2P_MAX_POLLS should not exceed 12 iterations (attemts) */
+#define E2P_MAX_POLLS 10
+#define E2P_INITIAL_DELAY 32
+
+static int i2c_poll_xfer_acked(struct cl_chip *chip)
+{
+       u32 val = cl_reg_read_chip(chip, I2C_SR);
+       int cnt = E2P_MAX_POLLS;
+       unsigned long delay = E2P_INITIAL_DELAY;
+
+       while ((val & BIT(TIP)) && cnt--) {
+               udelay(delay);
+               val = cl_reg_read_chip(chip, I2C_SR);
+               delay <<= 1;
+       }
+       ++cnt;
+
+       while ((val & BIT(RX_ACK)) && cnt--) {
+               udelay(delay);
+               val = cl_reg_read_chip(chip, I2C_SR);
+               delay <<= 1;
+       }
+
+       if (cnt >= 0)
+               return 0;
+
+       cl_dbg_chip_err(chip, "ACK FAILED\n");
+       cl_dbg_chip_trace(chip, "I2C_POLL_XFER_ACKED: val=%Xh, cnt=%d.\n", val, cnt);
+
+       return -1;
+}
+
+static int i2c_poll_xfer_no_acked(struct cl_chip *chip)
+{
+       u32 val = cl_reg_read_chip(chip, I2C_SR);
+       int cnt = E2P_MAX_POLLS;
+       unsigned long delay = E2P_INITIAL_DELAY;
+
+       while ((val & BIT(TIP)) && cnt--) {
+               udelay(delay);
+               val = cl_reg_read_chip(chip, I2C_SR);
+               delay <<= 1;
+       }
+
+       ++cnt;
+
+       while (!(val & BIT(RX_ACK)) && cnt--) {
+               udelay(delay);
+               val = cl_reg_read_chip(chip, I2C_SR);
+               delay <<= 1;
+       }
+
+       if (cnt >= 0)
+               return 0;
+
+       cl_dbg_chip_err(chip, "NO ACK FAILED\n");
+       cl_dbg_chip_trace(chip, "I2C_POLL_XFER_NO_ACKED: val=%Xh, cnt=%d.\n", val, cnt);
+
+       return -1;
+}
+
+static void i2c_write_start(struct cl_chip *chip, u16 page)
+{
+       u32 addr = I2C_EEPROM_ADDR(page) & TXADDR_MASK;
+
+       cl_reg_write_chip(chip, I2C_TXADDR, addr);
+       cl_reg_write_chip(chip, I2C_CR, BIT(STA) | BIT(WR));
+}
+
+static void i2c_write(struct cl_chip *chip, u8 data)
+{
+       cl_reg_write_chip(chip, I2C_TXD, data & TXD_MASK);
+       cl_reg_write_chip(chip, I2C_CR, BIT(WR));
+}
+
+static void i2c_write_stop(struct cl_chip *chip, u8 data)
+{
+       cl_reg_write_chip(chip, I2C_TXD, data & TXD_MASK);
+       cl_reg_write_chip(chip, I2C_CR, BIT(STO) | BIT(WR));
+}
+
+static void i2c_read_start(struct cl_chip *chip, u16 page)
+{
+       u32 addr = (I2C_EEPROM_ADDR(page) & TXADDR_MASK) | BIT(RDWR);
+
+       cl_reg_write_chip(chip, I2C_TXADDR, addr);
+       cl_reg_write_chip(chip, I2C_CR, BIT(STA) | BIT(WR));
+}
+
+static int i2c_read_stop(struct cl_chip *chip, u8 *data)
+{
+       cl_reg_write_chip(chip, I2C_CR, BIT(STO) | BIT(RD) | BIT(ACK));
+       if (i2c_poll_xfer_no_acked(chip) == -1)
+               return -1;
+       *data = cl_reg_read_chip(chip, I2C_RXD) & RXD_MASK;
+       return 0;
+}
+
+static void e2p_reg_set_bit(struct cl_chip *chip, u32 reg, u32 bit)
+{
+       u32 regval = cl_reg_read_chip(chip, reg);
+
+       regval |= bit;
+       cl_reg_write_chip(chip, reg, regval);
+}
+
+static void e2p_reg_clear_bit(struct cl_chip *chip, u32 reg, u32 bit)
+{
+       u32 regval = cl_reg_read_chip(chip, reg);
+
+       regval &= ~bit;
+       cl_reg_write_chip(chip, reg, regval);
+}
+
+static void e2p_enable(struct cl_chip *chip)
+{
+       /* Disable I2C Core */
+       e2p_reg_clear_bit(chip, I2C_CTR, BIT(EN));
+
+       /*
+        * Set Pre-Scaler LO
+        * pclk = 240MHz, desired SCL = 400KHz.
+        * Prescale = [240e6 / (5*400e3) ] – 1 = 120 -1 = 119 = 77h
+        */
+       cl_reg_write_chip(chip, I2C_PRERLO, 0x77);
+
+       /* Set Pre-Scaler HI */
+       cl_reg_write_chip(chip, I2C_PRERHI, 0x0);
+
+       /* Enable I2C Core */
+       e2p_reg_set_bit(chip, I2C_CTR, BIT(EN));
+}
+
+static int e2p_read_byte(struct cl_chip *chip, u16 addr, u8 *pbyte)
+{
+       if (addr > E2P_SIZE) {
+               cl_dbg_chip_err(chip, "Wrong addr or len\n");
+               return -1;
+       }
+
+       /* Clock in the address to read from. */
+       i2c_write_start(chip, PAGE_NUM(addr));
+       if (i2c_poll_xfer_acked(chip) == -1)
+               return -1;
+
+       /* Addr 8 lsbits are 4 bits page lsbits or`ed with 4 bits page offset */
+       i2c_write(chip, addr);
+       if (i2c_poll_xfer_acked(chip) == -1)
+               return -1;
+
+       /* Read single byte */
+       i2c_read_start(chip, PAGE_NUM(addr));
+       if (i2c_poll_xfer_acked(chip) == -1)
+               return -1;
+
+       return i2c_read_stop(chip, pbyte);
+}
+
+static int e2p_write_page(struct cl_chip *chip, u16 addr, u8 *val, u16 num_of_bytes)
+{
+       /* This is a write page (up to 16 bytes) operation indicating the offset to write to. */
+       int i;
+
+       if (num_of_bytes > E2P_PAGE_SIZE)
+               return -1;
+
+       /* Clock in the address to write to. */
+       i2c_write_start(chip, PAGE_NUM(addr));
+       if (i2c_poll_xfer_acked(chip) == -1)
+               return -1;
+
+       /* Addr 8 lsbits are 4 bits page lsbits or`ed with 4 bits page offset */
+       i2c_write(chip, addr);
+       if (i2c_poll_xfer_acked(chip) == -1)
+               return -1;
+
+       /* Clock in the data to write. */
+       for (i = 0; i < (num_of_bytes - 1); i++, val++) {
+               i2c_write(chip, *val);
+               if (i2c_poll_xfer_acked(chip) == -1)
+                       return -1;
+       }
+
+       /* Clock in the last data byte to write */
+       i2c_write_stop(chip, *val);
+       if (i2c_poll_xfer_acked(chip) == -1)
+               return -1;
+
+       /* Make sure to wait before moving to another page */
+       mdelay(4);
+
+       return 0;
+}
+
+static int e2p_write_block(struct cl_chip *chip, u16 addr, u16 num_of_bytes, u8 *val)
+{
+       u16 bytes_on_curr_page = 0, bytes_left_to_write = num_of_bytes;
+
+       do {
+               bytes_on_curr_page = E2P_PAGE_SIZE - PAGE_OFF(addr);
+               bytes_on_curr_page = min(bytes_left_to_write, bytes_on_curr_page);
+               bytes_left_to_write -= bytes_on_curr_page;
+
+               if (e2p_write_page(chip, addr, val, bytes_on_curr_page) == -1) {
+                       cl_dbg_chip_err(chip, "Error writing page %u offset %u\n",
+                                       PAGE_NUM(addr), PAGE_OFF(addr));
+                       /* Written less bytes than num_of_bytes */
+                       return 0;
+               }
+
+               addr += bytes_on_curr_page;
+               val += bytes_on_curr_page;
+       } while (bytes_left_to_write);
+
+       return num_of_bytes - bytes_left_to_write;
+}
+
+static int e2p_load_dev(struct cl_chip *chip)
+{
+       u8 *cache = (u8 *)chip->eeprom_cache;
+       u16 i;
+
+       for (i = 0; i < EEPROM_NUM_BYTES; i++)
+               if (e2p_read_byte(chip, i, &cache[i]) == -1)
+                       return -1;
+
+       return 0;
+}
+
+static int e2p_dev_read_block(struct cl_chip *chip, u16 addr, u16 num_of_bytes, u8 *val)
+{
+       void *read_block = NULL;
+
+       if (!val)
+               return -EFAULT;
+
+       if (addr + num_of_bytes > EEPROM_NUM_BYTES)
+               return -ENXIO;
+
+       read_block = (u8 *)chip->eeprom_cache + addr;
+       memcpy(val, read_block, num_of_bytes);
+
+       return num_of_bytes;
+}
+
+static int e2p_dev_write_block(struct cl_chip *chip, u16 addr, u16 num_of_bytes, u8 *val)
+{
+       int bytes_written = -EIO;
+       void *write_block = NULL;
+
+       if (!val)
+               return -EFAULT;
+
+       if (addr + num_of_bytes > EEPROM_NUM_BYTES)
+               return -ENXIO;
+
+       bytes_written = e2p_write_block(chip, addr, num_of_bytes, val);
+       write_block = (u8 *)chip->eeprom_cache + addr;
+       memcpy(write_block, val, num_of_bytes);
+
+       return bytes_written;
+}
+
+static int e2p_load_bin(struct cl_chip *chip)
+{
+       char filename[CL_FILENAME_MAX];
+       size_t size = 0;
+
+       if (cl_chip_is_6g(chip))
+               snprintf(filename, sizeof(filename),
+                        "eeprom/eeprom%u_cl80x6.bin", chip->idx);
+       else
+               snprintf(filename, sizeof(filename),
+                        "eeprom/eeprom%u_cl80x0.bin", chip->idx);
+
+       size = cl_file_open_and_read(chip, filename,
+                                    (char **)&chip->eeprom_cache);
+
+       if (size != EEPROM_NUM_BYTES) {
+               cl_dbg_chip_err(chip,
+                               "Invalid EEPROM size - %s (actual %zu) (expected %d)\n",
+                               filename, size, EEPROM_NUM_BYTES);
+               return -1;
+       }
+
+       return 0;
+}
+
+static int e2p_bin_write_block(struct cl_chip *chip, u16 addr, u16 num_of_bytes, u8 *val)
+{
+       return -EOPNOTSUPP;
+}
+
+static int e2p_bin_read_block(struct cl_chip *chip, u16 addr, u16 num_of_bytes, u8 *val)
+{
+       u8 *base;
+       u16 *offset_addr;
+
+       if (!val)
+               return -EFAULT;
+
+       if (addr + num_of_bytes > EEPROM_NUM_BYTES)
+               return -ENXIO;
+
+       base = (u8 *)chip->eeprom_cache;
+       offset_addr = (u16 *)(base + addr);
+       memmove(val, offset_addr, num_of_bytes);
+
+       return num_of_bytes;
+}
+
+static int cl_e2p_init_bin(struct cl_chip *chip)
+{
+       if (e2p_load_bin(chip))
+               return -1;
+
+       chip->eeprom_read_block = e2p_bin_read_block;
+       chip->eeprom_write_block = e2p_bin_write_block;
+
+       return 0;
+}
+
+static int cl_e2p_init_dev(struct cl_chip *chip)
+{
+       chip->eeprom_cache = kzalloc(EEPROM_NUM_BYTES, GFP_KERNEL);
+
+       if (!chip->eeprom_cache)
+               return -1;
+
+       e2p_enable(chip);
+
+       if (e2p_load_dev(chip))
+               return -1;
+
+       chip->eeprom_read_block = e2p_dev_read_block;
+       chip->eeprom_write_block = e2p_dev_write_block;
+
+       return 0;
+}
+
+int cl_e2p_init(struct cl_chip *chip)
+{
+       u8 mode = chip->conf->ce_eeprom_mode;
+
+       if (mode == E2P_MODE_BIN)
+               return cl_e2p_init_bin(chip);
+       else if (mode == E2P_MODE_EEPROM)
+               return cl_e2p_init_dev(chip);
+
+       return -1;
+}
+
+void cl_e2p_close(struct cl_chip *chip)
+{
+       kfree(chip->eeprom_cache);
+}
+
+int cl_e2p_write(struct cl_chip *chip, u8 *data, u16 size, u16 addr)
+{
+       if (size != chip->eeprom_write_block(chip, addr, size, data)) {
+               cl_dbg_chip_err(chip, "Error writing eeprom addr 0x%x\n", addr);
+               return -1;
+       }
+
+       return 0;
+}
+
+int cl_e2p_read(struct cl_chip *chip, u8 *data, u16 size, u16 addr)
+{
+       if (size != chip->eeprom_read_block(chip, addr, size, data)) {
+               cl_dbg_chip_err(chip, "Error reading eeprom addr 0x%x\n", addr);
+               return -1;
+       }
+
+       return 0;
+}
+
+int cl_e2p_write_version(struct cl_chip *chip)
+{
+       u8 version = EEPROM_VERSION;
+
+       if (chip->eeprom_cache->general.version != version)
+               return cl_e2p_write(chip, &version,
+                                   SIZE_GEN_VERSION, ADDR_GEN_VERSION);
+
+       return 0;
+}
+
+int cl_e2p_get_addr(struct wiphy *wiphy, struct wireless_dev *wdev,
+                   void *data, int data_len)
+{
+       struct cl_hw *cl_hw = WIPHY_TO_CL_HW(wiphy);
+       u16 addr = *(u16 *)data;
+       u16 len = *((u16 *)data + 1);
+       int reply_len;
+       struct cl_e2p_get_reply *reply = NULL;
+       struct cl_chip *chip = cl_hw->chip;
+       int ret = 0;
+       u32 end = EEPROM_NUM_BYTES;
+       u8 mode = chip->conf->ce_eeprom_mode;
+
+       reply_len = sizeof(struct cl_e2p_get_reply) + len;
+       reply = kzalloc(reply_len, GFP_KERNEL);
+
+       if (!reply)
+               return -ENOMEM;
+
+       reply->e2p_mode = mode;
+
+       cl_dbg_trace(cl_hw, "addr %u len %u\n", addr, len);
+
+       if (end < (addr + len)) {
+               cl_dbg_err(cl_hw,
+                          "size check failed: last addr = 0x%x, eeprom memory end"
+                          " = 0x%x, eeprom_mode = %u\n", (addr + len),
+                          end, mode);
+               ret = -EINVAL;
+               goto e2p_fail;
+       }
+
+       if (len != chip->eeprom_read_block(chip, addr, len, reply->e2p_data)) {
+               cl_dbg_err(cl_hw, "Error reading eeprom addr 0x%x: len %u\n",
+                          addr, len);
+               ret = -EXDEV;
+               goto e2p_fail;
+       }
+
+       ret = cl_vendor_reply(cl_hw, (void *)reply, reply_len);
+
+e2p_fail:
+       kfree(reply);
+
+       return ret;
+}
+
+int cl_e2p_set_addr(struct wiphy *wiphy, struct wireless_dev *wdev,
+                   const void *data, int data_len)
+{
+       struct cl_hw *cl_hw = WIPHY_TO_CL_HW(wiphy);
+       u16 addr = *(u16 *)data;
+       u16 len = *((u16 *)data + 1);
+       u8 *e2p_data = (u8 *)((u16 *)data + 2);
+       u32 end = EEPROM_NUM_BYTES;
+
+       cl_dbg_trace(cl_hw, "addr %u len %u\n", addr, len);
+
+       if (end < (addr + len)) {
+               cl_dbg_err(cl_hw, "Invalid E2P addr 0x%x, valid are: 0 - %u\n",
+                          addr, end);
+               return -EINVAL;
+       }
+
+       return cl_e2p_write(cl_hw->chip, e2p_data, len, addr);
+}
+
+int cl_e2p_set_wiring_id(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_chip *chip = cl_hw->chip;
+       u8 wiring_id = *(u8 *)data;
+
+       return cl_fem_set_wiring_id(chip, wiring_id);
+}
+
+int cl_e2p_help(struct wiphy *wiphy, struct wireless_dev *wdev,
+               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"
+                "get addr <address> - Read value from specified addr\n"
+                "get mac - Read MAC address\n"
+                "get serial_number - Read serial number\n"
+                "get pwr_table_id - Read power table IDs\n"
+                "get freq_offset - Read frequency offset\n"
+                "get wiring_id - Read wiring ID\n"
+                "get fem_lut- Read FEM look up table\n"
+                "get platform_id - Read platform ID\n"
+                "get calib <ant> <ch> - Read calibrated offset for a given antenna and channel\n"
+                "get hexdump - Read entire eeprom\n"
+                "get table - Read entire eeprom and print in format of table\n"
+                "set addr <address> <value> - Write value to specified address\n"
+                "set mac <macaddr> - Write MAC addr\n"
+                "set serial_number <32 characters> - Write serial number\n"
+                "set pwr_table_id <id tcv0> <id tcv1> - Write power table IDs\n"
+                "set wiring_id <0 - 255> - Write wiring-ID\n"
+                "set fem_lut <type_num> <lut_lna_bypass> <lut_tx> <lut_rx> <lut_off> -"
+                " Write FEM look up table\n"
+                "set platform_id <val> - Write platform-id to eeprom\n"
+                "set freq_offset <0 - 959> - Write frequency offset to eeprom\n"
+                "set calib <antenna> <channel> <power> <offset> <temperature (optional)> -"
+                " Write calibrated power and power offset for a given antenna and channel\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.
________________________________


^ permalink raw reply related	[flat|nested] 262+ messages in thread

* [RFC v1 068/256] cl8k: add e2p.h
  2021-06-17 15:58 [RFC v1 000/256] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (66 preceding siblings ...)
  2021-06-17 15:59 ` [RFC v1 067/256] cl8k: add e2p.c viktor.barna
@ 2021-06-17 15:59 ` viktor.barna
  2021-06-17 15:59 ` [RFC v1 069/256] cl8k: add edca.c viktor.barna
                   ` (189 subsequent siblings)
  257 siblings, 0 replies; 262+ messages in thread
From: viktor.barna @ 2021-06-17 15:59 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Oleksandr Savchenko, Shay Bar, Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

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

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 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.
________________________________


^ permalink raw reply related	[flat|nested] 262+ messages in thread

* [RFC v1 069/256] cl8k: add edca.c
  2021-06-17 15:58 [RFC v1 000/256] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (67 preceding siblings ...)
  2021-06-17 15:59 ` [RFC v1 068/256] cl8k: add e2p.h viktor.barna
@ 2021-06-17 15:59 ` viktor.barna
  2021-06-17 15:59 ` [RFC v1 070/256] cl8k: add edca.h viktor.barna
                   ` (188 subsequent siblings)
  257 siblings, 0 replies; 262+ messages in thread
From: viktor.barna @ 2021-06-17 15:59 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Oleksandr Savchenko, Shay Bar, Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

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

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 drivers/net/wireless/celeno/cl8k/edca.c | 265 ++++++++++++++++++++++++
 1 file changed, 265 insertions(+)
 create mode 100644 drivers/net/wireless/celeno/cl8k/edca.c

diff --git a/drivers/net/wireless/celeno/cl8k/edca.c b/drivers/net/wireless/celeno/cl8k/edca.c
new file mode 100644
index 000000000000..d17a7bd674c5
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/edca.c
@@ -0,0 +1,265 @@
+// SPDX-License-Identifier: MIT
+/* Copyright(c) 2019-2021, Celeno Communications Ltd. */
+
+#include "edca.h"
+#include "sta.h"
+#include "vendor_cmd.h"
+#include "fw/msg_tx.h"
+#include "utils/utils.h"
+
+static u8 conv_to_fw_ac[EDCA_AC_MAX] = {
+       [EDCA_AC_BE] = AC_BE,
+       [EDCA_AC_BK] = AC_BK,
+       [EDCA_AC_VI] = AC_VI,
+       [EDCA_AC_VO] = AC_VO
+};
+
+static const char *edca_ac_str[EDCA_AC_MAX] = {
+       [EDCA_AC_BE] = "BE",
+       [EDCA_AC_BK] = "BK",
+       [EDCA_AC_VI] = "VI",
+       [EDCA_AC_VO] = "VO"
+};
+
+static int cl_edca_print(struct cl_hw *cl_hw)
+{
+       u8 ac = 0;
+       struct edca_params *params;
+       char *buf = NULL;
+       ssize_t buf_size;
+       int err = 0;
+       int len = 0;
+
+       cl_snprintf(&buf, &len, &buf_size,
+                   "---------------------------------------\n"
+                   "| ac | aifsn | cw_min | cw_max | txop |\n"
+                   "|----+-------+--------+--------+------|\n");
+
+       for (ac = 0; ac < AC_MAX; ac++) {
+               params = &cl_hw->edca_db.hw_params[ac];
+               cl_snprintf(&buf, &len, &buf_size,
+                           "| %s | %5u | %6u | %6u | %4u |\n",
+                           edca_ac_str[ac], params->aifsn, params->cw_min,
+                           params->cw_max, params->txop);
+       }
+
+       cl_snprintf(&buf, &len, &buf_size,
+                   "---------------------------------------\n\n");
+
+       err = cl_vendor_reply(cl_hw, buf, len);
+       kfree(buf);
+
+       return err;
+}
+
+static void cl_edca_set_conf(struct cl_hw *cl_hw, u8 ac)
+{
+       struct edca_params params = {
+               .aifsn = cl_hw->conf->ce_wmm_aifsn[ac],
+               .cw_min = cl_hw->conf->ce_wmm_cwmin[ac],
+               .cw_max = cl_hw->conf->ce_wmm_cwmax[ac],
+               .txop = cl_hw->conf->ce_wmm_txop[ac]
+       };
+
+       cl_edca_set(cl_hw, ac, &params, NULL);
+}
+
+static void cl_edca_ac_set(struct cl_hw *cl_hw, u8 ac, u8 aifsn, u8 cw_min, u8 cw_max, u16 txop)
+{
+       pr_debug("ac = %u, aifsn = %u, cw_min = %u, cw_max = %u, txop = %u\n",
+                ac, aifsn, cw_min, cw_max, txop);
+
+       cl_hw->conf->ce_wmm_aifsn[ac] = aifsn;
+       cl_hw->conf->ce_wmm_cwmin[ac] = cw_min;
+       cl_hw->conf->ce_wmm_cwmax[ac] = cw_max;
+       cl_hw->conf->ce_wmm_txop[ac] = txop;
+
+       cl_edca_set_conf(cl_hw, ac);
+}
+
+static void cl_edca_aifsn_set(struct cl_hw *cl_hw, s32 aifsn[AC_MAX])
+{
+       u8 ac = 0;
+
+       pr_debug("Set aifsn: BE = %d, BK = %d, VI = %d, VO = %d\n",
+                aifsn[0], aifsn[1], aifsn[2], aifsn[3]);
+
+       for (ac = 0; ac < AC_MAX; ac++) {
+               cl_hw->conf->ce_wmm_aifsn[ac] = (u8)aifsn[ac];
+               cl_edca_set_conf(cl_hw, ac);
+       }
+}
+
+static void cl_edca_cwmin_set(struct cl_hw *cl_hw, s32 cw_min[AC_MAX])
+{
+       u8 ac = 0;
+
+       pr_debug("Set cw_min: BE = %d, BK = %d, VI = %d, VO = %d\n",
+                cw_min[0], cw_min[1], cw_min[2], cw_min[3]);
+
+       for (ac = 0; ac < AC_MAX; ac++) {
+               cl_hw->conf->ce_wmm_cwmin[ac] = (u8)cw_min[ac];
+               cl_edca_set_conf(cl_hw, ac);
+       }
+}
+
+static void cl_edca_cwmax_set(struct cl_hw *cl_hw, s32 cw_max[AC_MAX])
+{
+       u8 ac = 0;
+
+       pr_debug("Set cw_max: BE = %d, BK = %d, VI = %d, VO = %d\n",
+                cw_max[0], cw_max[1], cw_max[2], cw_max[3]);
+
+       for (ac = 0; ac < AC_MAX; ac++) {
+               cl_hw->conf->ce_wmm_cwmax[ac] = (u8)cw_max[ac];
+               cl_edca_set_conf(cl_hw, ac);
+       }
+}
+
+static void cl_edca_txop_set(struct cl_hw *cl_hw, s32 txop[AC_MAX])
+{
+       u8 ac = 0;
+
+       pr_debug("Set txop: BE = %d, BK = %d, VI = %d, VO = %d\n",
+                txop[0], txop[1], txop[2], txop[3]);
+
+       for (ac = 0; ac < AC_MAX; ac++) {
+               cl_hw->conf->ce_wmm_txop[ac] = (u16)txop[ac];
+               cl_edca_set_conf(cl_hw, ac);
+       }
+}
+
+static int cl_edca_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,
+                "edca usage:\n"
+                "-a : Print current configuration\n"
+                "-b : Set per AC [0-BE,1-BK,2-VI,3-VO].[aifsn].[cw_min]."
+                       "[cw_max].[txop]\n"
+                "-c : Set aifsn [BE].[BK].[VI].[VO]\n"
+                "-d : Set cw_min [BE].[BK].[VI].[VO]\n"
+                "-e : Set cw_max [BE].[BK].[VI].[VO]\n"
+                "-f : Set txop  [BE].[BK].[VI].[VO]\n");
+
+       err = cl_vendor_reply(cl_hw, buf, strlen(buf));
+       kfree(buf);
+
+       return err;
+}
+
+void cl_edca_hw_conf(struct cl_hw *cl_hw)
+{
+       u8 ac = 0;
+       struct cl_tcv_conf *conf = cl_hw->conf;
+
+       for (ac = 0; ac < AC_MAX; ac++) {
+               struct edca_params params = {
+                       .aifsn = conf->ce_wmm_aifsn[ac],
+                       .cw_min = conf->ce_wmm_cwmin[ac],
+                       .cw_max = conf->ce_wmm_cwmax[ac],
+                       .txop = conf->ce_wmm_txop[ac]
+               };
+
+               cl_edca_set(cl_hw, ac, &params, NULL);
+       }
+}
+
+void cl_edca_set(struct cl_hw *cl_hw, u8 ac, struct edca_params *params,
+                struct ieee80211_he_mu_edca_param_ac_rec *mu_edca)
+{
+       u32 edca_reg_val = 0;
+
+       if (ac >= AC_MAX) {
+               pr_err("%s: Invalid AC index\n", __func__);
+               return;
+       }
+
+       edca_reg_val  = (u32)(params->aifsn);
+       edca_reg_val |= (u32)(params->cw_min << 4);
+       edca_reg_val |= (u32)(params->cw_max << 8);
+       edca_reg_val |= (u32)(params->txop << 12);
+
+       memcpy(&cl_hw->edca_db.hw_params[ac], params, sizeof(struct edca_params));
+
+       cl_msg_tx_set_edca(cl_hw, conv_to_fw_ac[ac], edca_reg_val, mu_edca);
+
+       cl_dbg_trace(cl_hw, "EDCA-%s: aifsn=%u, cw_min=%u, cw_max=%u, txop=%u\n",
+                    edca_ac_str[ac], params->aifsn, params->cw_min, params->cw_max, params->txop);
+}
+
+void cl_edca_restore_conf(struct cl_hw *cl_hw, u8 ac)
+{
+       cl_edca_set_conf(cl_hw, ac);
+}
+
+void cl_edca_recovery(struct cl_hw *cl_hw)
+{
+       u8 ac;
+
+       for (ac = 0; ac < AC_MAX; ac++)
+               cl_edca_set(cl_hw, ac, &cl_hw->edca_db.hw_params[ac], NULL);
+}
+
+int cl_edca_cli(struct cl_hw *cl_hw, struct cli_params *cli_params)
+{
+       u8 ac, aifsn, cw_min, cw_max;
+       u16 txop;
+
+       switch (cli_params->option) {
+       case 'a':
+               return cl_edca_print(cl_hw);
+       case 'b':
+               if (cli_params->num_params != 5)
+                       goto err_num_of_arg;
+
+               ac = (u8)cli_params->params[0];
+               aifsn = (u8)cli_params->params[1];
+               cw_min = (u8)cli_params->params[2];
+               cw_max = (u8)cli_params->params[3];
+               txop = (u16)cli_params->params[4];
+
+               cl_edca_ac_set(cl_hw, ac, aifsn, cw_min, cw_max, txop);
+               break;
+       case 'c':
+               if (cli_params->num_params != AC_MAX)
+                       goto err_num_of_arg;
+
+               cl_edca_aifsn_set(cl_hw, cli_params->params);
+               break;
+       case 'd':
+               if (cli_params->num_params != AC_MAX)
+                       goto err_num_of_arg;
+
+               cl_edca_cwmin_set(cl_hw, cli_params->params);
+               break;
+       case 'e':
+               if (cli_params->num_params != AC_MAX)
+                       goto err_num_of_arg;
+
+               cl_edca_cwmax_set(cl_hw, cli_params->params);
+               break;
+       case 'f':
+               if (cli_params->num_params != AC_MAX)
+                       goto err_num_of_arg;
+
+               cl_edca_txop_set(cl_hw, cli_params->params);
+               break;
+       case '?':
+               return cl_edca_cli_help(cl_hw);
+       default:
+               cl_dbg_err(cl_hw, "Illegal option (%c) - try '?' for help\n", cli_params->option);
+               break;
+       }
+
+       return 0;
+
+err_num_of_arg:
+       pr_err("wrong number of arguments\n");
+       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.
________________________________


^ permalink raw reply related	[flat|nested] 262+ messages in thread

* [RFC v1 070/256] cl8k: add edca.h
  2021-06-17 15:58 [RFC v1 000/256] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (68 preceding siblings ...)
  2021-06-17 15:59 ` [RFC v1 069/256] cl8k: add edca.c viktor.barna
@ 2021-06-17 15:59 ` viktor.barna
  2021-06-17 15:59 ` [RFC v1 071/256] cl8k: add ela.c viktor.barna
                   ` (187 subsequent siblings)
  257 siblings, 0 replies; 262+ messages in thread
From: viktor.barna @ 2021-06-17 15:59 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Oleksandr Savchenko, Shay Bar, Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

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

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 drivers/net/wireless/celeno/cl8k/edca.h | 47 +++++++++++++++++++++++++
 1 file changed, 47 insertions(+)
 create mode 100644 drivers/net/wireless/celeno/cl8k/edca.h

diff --git a/drivers/net/wireless/celeno/cl8k/edca.h b/drivers/net/wireless/celeno/cl8k/edca.h
new file mode 100644
index 000000000000..d8edcf12b95c
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/edca.h
@@ -0,0 +1,47 @@
+/* SPDX-License-Identifier: MIT */
+/* Copyright(c) 2019-2021, Celeno Communications Ltd. */
+
+#ifndef CL_EDCA_H
+#define CL_EDCA_H
+
+#include "vendor_cmd.h"
+#include "def.h"
+
+enum edca_ac {
+       EDCA_AC_BE,
+       EDCA_AC_BK,
+       EDCA_AC_VI,
+       EDCA_AC_VO,
+
+       EDCA_AC_MAX
+};
+
+#define EDCA_AIFSN      0
+#define EDCA_CW_MIN     1
+#define EDCA_CW_MAX     2
+#define EDCA_TXOP       3
+#define EDCA_MAX_PARAMS 4
+
+struct edca_params {
+       u16 txop;
+       u8 cw_max;
+       u8 cw_min;
+       u8 aifsn;
+};
+
+struct cl_edca_db {
+       struct edca_params hw_params[AC_MAX];
+};
+
+struct cl_hw;
+struct cl_sta;
+struct ieee80211_he_mu_edca_param_ac_rec;
+
+void cl_edca_hw_conf(struct cl_hw *cl_hw);
+void cl_edca_set(struct cl_hw *cl_hw, u8 ac, struct edca_params *params,
+                struct ieee80211_he_mu_edca_param_ac_rec *mu_edca);
+void cl_edca_restore_conf(struct cl_hw *cl_hw, u8 ac);
+void cl_edca_recovery(struct cl_hw *cl_hw);
+int cl_edca_cli(struct cl_hw *cl_hw, struct cli_params *cli_params);
+
+#endif /* CL_EDCA_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.
________________________________


^ permalink raw reply related	[flat|nested] 262+ messages in thread

* [RFC v1 071/256] cl8k: add ela.c
  2021-06-17 15:58 [RFC v1 000/256] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (69 preceding siblings ...)
  2021-06-17 15:59 ` [RFC v1 070/256] cl8k: add edca.h viktor.barna
@ 2021-06-17 15:59 ` viktor.barna
  2021-06-17 15:59 ` [RFC v1 072/256] cl8k: add ela.h viktor.barna
                   ` (186 subsequent siblings)
  257 siblings, 0 replies; 262+ messages in thread
From: viktor.barna @ 2021-06-17 15:59 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Oleksandr Savchenko, Shay Bar, Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

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

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 drivers/net/wireless/celeno/cl8k/ela.c | 227 +++++++++++++++++++++++++
 1 file changed, 227 insertions(+)
 create mode 100644 drivers/net/wireless/celeno/cl8k/ela.c

diff --git a/drivers/net/wireless/celeno/cl8k/ela.c b/drivers/net/wireless/celeno/cl8k/ela.c
new file mode 100644
index 000000000000..49f4d2d21054
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/ela.c
@@ -0,0 +1,227 @@
+// SPDX-License-Identifier: MIT
+/* Copyright(c) 2021, Celeno Communications Ltd. */
+
+#include "ela.h"
+#include "utils/file.h"
+#include "reg/reg_access.h"
+#include "reg/reg_lcu_common.h"
+#include "reg/reg_lcu_phy.h"
+
+#define CL_ELA_MODE_DFLT_ALIAS          "default"
+#define CL_ELA_MODE_DFLT_SYMB_LINK      "lcu_default.conf"
+#define CL_ELA_MODE_DFLT_OFF            "OFF"
+#define CL_ELA_LCU_CONF_TOKENS_CNT      3 /* cmd addr1 addr2 */
+#define CL_ELA_LCU_MEM_WRITE_CMD_STR    "mem_write"
+#define CL_ELA_LCU_MEM_WRITE_CMD_SZ     sizeof(CL_ELA_LCU_MEM_WRITE_CMD_STR)
+#define CL_ELA_LCU_UNKNOWN_CMD_TYPE     0
+#define CL_ELA_LCU_MEM_WRITE_CMD_TYPE   1
+#define CL_ELA_LCU_UNKNOWN_CMD_STR      "unknown"
+
+static int __must_check get_lcu_cmd_type(char *cmd)
+{
+       if (!strncmp(CL_ELA_LCU_MEM_WRITE_CMD_STR, cmd, CL_ELA_LCU_MEM_WRITE_CMD_SZ))
+               return CL_ELA_LCU_MEM_WRITE_CMD_TYPE;
+
+       return CL_ELA_LCU_UNKNOWN_CMD_TYPE;
+}
+
+static int add_lcu_cmd(struct cl_ela_db *ed, u32 type, u32 offset, u32 value)
+{
+       struct cl_lcu_cmd *cmd = NULL;
+
+       cmd = kzalloc(sizeof(*cmd), GFP_ATOMIC);
+       if (!cmd)
+               return -ENOMEM;
+
+       cmd->type = type;
+       cmd->offset = offset;
+       cmd->value = value;
+
+       list_add_tail(&cmd->cmd_list, &ed->cmd_head);
+
+       return 0;
+}
+
+static void remove_lcu_cmd(struct cl_lcu_cmd *cmd)
+{
+       list_del(&cmd->cmd_list);
+       kfree(cmd);
+}
+
+static void reset_stats(struct cl_ela_db *db)
+{
+       memset(&db->stats, 0, sizeof(db->stats));
+}
+
+static int load_cmds_from_buf(struct cl_chip *chip, char *buf, size_t size)
+{
+       struct cl_ela_db *ed = &chip->ela_db;
+       char *line = buf;
+       char cmd[STR_LEN_256B];
+       u32 type = CL_ELA_LCU_UNKNOWN_CMD_TYPE;
+       u32 offset = 0;
+       u32 value = 0;
+       int tokens_cnt = 0;
+       int ret = 0;
+
+       while (line && strlen(line) && (line != (buf + size))) {
+               if ((*line == '#') || (*line == '\n')) {
+                       /* Skip comment or blank line */
+                       line = strstr(line, "\n") + 1;
+               } else if (*line) {
+                       tokens_cnt = sscanf(line, "%s %x %x\n", cmd, &offset, &value);
+                       cl_dbg_chip_trace(chip,
+                                         "tokens(%d):cmd(%s), offset(0x%X), value(0x%X)\n",
+                                         tokens_cnt, cmd, offset, value);
+
+                       type = get_lcu_cmd_type(cmd);
+                       if (type == CL_ELA_LCU_UNKNOWN_CMD_TYPE) {
+                               cl_dbg_chip_trace(chip, "Detected extra token, skipping\n");
+                               goto newline;
+                       }
+                       if (tokens_cnt != CL_ELA_LCU_CONF_TOKENS_CNT) {
+                               cl_dbg_chip_err(chip,
+                                               "Tokens count is wrong! (%d != %d)\n",
+                                               CL_ELA_LCU_CONF_TOKENS_CNT,
+                                               tokens_cnt);
+                               ret = -EBADMSG;
+                               goto exit;
+                       }
+
+                       ret = add_lcu_cmd(ed, type, offset, value);
+                       if (ret)
+                               goto exit;
+
+newline:
+                       line = strstr(line, "\n") + 1;
+               }
+       }
+
+exit:
+       ed->stats.adaptations_cnt++;
+       return ret;
+}
+
+void cl_ela_lcu_reset(struct cl_chip *chip)
+{
+       lcu_common_sw_rst_set(chip, 0x1);
+       lcu_phy_lcu_sw_rst_set(chip->cl_hw_tcv0, 0x1);
+       lcu_phy_lcu_sw_rst_set(chip->cl_hw_tcv1, 0x1);
+}
+
+void cl_ela_lcu_apply_config(struct cl_chip *chip)
+{
+       struct cl_ela_db *ed = &chip->ela_db;
+       struct cl_lcu_cmd *cmd = NULL;
+
+       if (!cl_ela_lcu_is_valid_config(chip)) {
+               cl_dbg_chip_err(chip, "Active ELA LCU config is not valid\n");
+               return;
+       }
+
+       list_for_each_entry(cmd, &ed->cmd_head, cmd_list) {
+               cl_dbg_chip_info(chip, "Writing cmd (0x%X, 0x%X)\n",
+                                cmd->offset, cmd->value);
+               cl_reg_write_chip(chip, cmd->offset, cmd->value);
+       }
+       ed->stats.applications_cnt++;
+}
+
+bool cl_ela_is_on(struct cl_chip *chip)
+{
+       return !!strncmp(CL_ELA_MODE_DFLT_OFF, chip->conf->ce_ela_mode,
+                        sizeof(chip->conf->ce_ela_mode));
+}
+
+bool cl_ela_is_default(struct cl_chip *chip)
+{
+       return !strncmp(CL_ELA_MODE_DFLT_ALIAS, chip->conf->ce_ela_mode,
+                       sizeof(chip->conf->ce_ela_mode));
+}
+
+bool cl_ela_lcu_is_valid_config(struct cl_chip *chip)
+{
+       struct cl_ela_db *ed = &chip->ela_db;
+
+       return ed->error_state == 0;
+}
+
+char *cl_ela_lcu_cmd_str(u32 type)
+{
+       if (type == CL_ELA_LCU_MEM_WRITE_CMD_TYPE)
+               return CL_ELA_LCU_MEM_WRITE_CMD_STR;
+
+       return CL_ELA_LCU_UNKNOWN_CMD_STR;
+}
+
+char *cl_ela_lcu_config_name(struct cl_chip *chip)
+{
+       if (!cl_ela_is_on(chip))
+               return CL_ELA_MODE_DFLT_OFF;
+
+       if (cl_ela_is_default(chip))
+               return CL_ELA_MODE_DFLT_SYMB_LINK;
+
+       return chip->conf->ce_ela_mode;
+}
+
+int cl_ela_lcu_config_read(struct cl_chip *chip)
+{
+       struct cl_ela_db *ed = &chip->ela_db;
+       char filename[CL_FILENAME_MAX] = {0};
+       size_t size = 0;
+       int ret = 0;
+
+       if (!cl_ela_is_on(chip)) {
+               ret = -EOPNOTSUPP;
+               goto exit;
+       }
+
+       reset_stats(ed);
+
+       snprintf(filename, sizeof(filename), "%s", cl_ela_lcu_config_name(chip));
+       size = cl_file_open_and_read(chip, filename, &ed->raw_lcu_config);
+       if (!ed->raw_lcu_config) {
+               ret = -ENODATA;
+               goto exit;
+       }
+
+       ret = load_cmds_from_buf(chip, ed->raw_lcu_config, size);
+exit:
+       ed->error_state = ret;
+       return ret;
+}
+
+int cl_ela_init(struct cl_chip *chip)
+{
+       struct cl_ela_db *ed = &chip->ela_db;
+       int ret = 0;
+
+       if (!cl_ela_is_on(chip))
+               return 0;
+
+       INIT_LIST_HEAD(&ed->cmd_head);
+
+       ret = cl_ela_lcu_config_read(chip);
+       if (ret == 0) {
+               cl_ela_lcu_reset(chip);
+               cl_ela_lcu_apply_config(chip);
+       }
+
+       return ret;
+}
+
+void cl_ela_deinit(struct cl_chip *chip)
+{
+       struct cl_ela_db *ed = &chip->ela_db;
+       struct cl_lcu_cmd *cmd = NULL, *cmd_tmp = NULL;
+
+       if (!cl_ela_is_on(chip))
+               return;
+
+       kfree(ed->raw_lcu_config);
+       ed->raw_lcu_config = NULL;
+
+       list_for_each_entry_safe(cmd, cmd_tmp, &ed->cmd_head, cmd_list)
+               remove_lcu_cmd(cmd);
+}
--
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.
________________________________


^ permalink raw reply related	[flat|nested] 262+ messages in thread

* [RFC v1 072/256] cl8k: add ela.h
  2021-06-17 15:58 [RFC v1 000/256] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (70 preceding siblings ...)
  2021-06-17 15:59 ` [RFC v1 071/256] cl8k: add ela.c viktor.barna
@ 2021-06-17 15:59 ` viktor.barna
  2021-06-17 15:59 ` [RFC v1 073/256] cl8k: add enhanced_tim.c viktor.barna
                   ` (185 subsequent siblings)
  257 siblings, 0 replies; 262+ messages in thread
From: viktor.barna @ 2021-06-17 15:59 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Oleksandr Savchenko, Shay Bar, Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

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

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 drivers/net/wireless/celeno/cl8k/ela.h | 38 ++++++++++++++++++++++++++
 1 file changed, 38 insertions(+)
 create mode 100644 drivers/net/wireless/celeno/cl8k/ela.h

diff --git a/drivers/net/wireless/celeno/cl8k/ela.h b/drivers/net/wireless/celeno/cl8k/ela.h
new file mode 100644
index 000000000000..dc2e67d06798
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/ela.h
@@ -0,0 +1,38 @@
+/* SPDX-License-Identifier: MIT */
+/* Copyright(c) 2019-2021, Celeno Communications Ltd. */
+
+#ifndef CL_ELA_H
+#define CL_ELA_H
+
+#include "chip.h"
+
+/**
+ * DOC: ELA (=Embedded Logic Analyzer)
+ *
+ * Chip contains built-in ELA with LCU (=Logic Capture Unit), that allows to
+ * collect profiling info. Collected data is aggregated via set of %cl_nlev
+ * elements, and saved inside special dump buffer (described by %cl_coredump)
+ * and fed to the userspace via DEV_COREDUMP subsystem.
+ *
+ * This layer is mandatory since it allows to set properly initial and
+ * post-recovery configuration.
+ */
+
+struct cl_lcu_cmd {
+       u32 type;
+       u32 offset;
+       u32 value;
+       struct list_head cmd_list;
+};
+
+void cl_ela_lcu_reset(struct cl_chip *chip);
+void cl_ela_lcu_apply_config(struct cl_chip *chip);
+bool cl_ela_is_on(struct cl_chip *chip);
+bool cl_ela_is_default(struct cl_chip *chip);
+bool cl_ela_lcu_is_valid_config(struct cl_chip *chip);
+char *cl_ela_lcu_cmd_str(u32 type);
+char *cl_ela_lcu_config_name(struct cl_chip *chip);
+int cl_ela_lcu_config_read(struct cl_chip *chip);
+int cl_ela_init(struct cl_chip *chip);
+void cl_ela_deinit(struct cl_chip *chip);
+#endif /* CL_ELA_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.
________________________________


^ permalink raw reply related	[flat|nested] 262+ messages in thread

* [RFC v1 073/256] cl8k: add enhanced_tim.c
  2021-06-17 15:58 [RFC v1 000/256] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (71 preceding siblings ...)
  2021-06-17 15:59 ` [RFC v1 072/256] cl8k: add ela.h viktor.barna
@ 2021-06-17 15:59 ` viktor.barna
  2021-06-17 15:59 ` [RFC v1 074/256] cl8k: add enhanced_tim.h viktor.barna
                   ` (184 subsequent siblings)
  257 siblings, 0 replies; 262+ messages in thread
From: viktor.barna @ 2021-06-17 15:59 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Oleksandr Savchenko, Shay Bar, Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

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

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 .../net/wireless/celeno/cl8k/enhanced_tim.c   | 216 ++++++++++++++++++
 1 file changed, 216 insertions(+)
 create mode 100644 drivers/net/wireless/celeno/cl8k/enhanced_tim.c

diff --git a/drivers/net/wireless/celeno/cl8k/enhanced_tim.c b/drivers/net/wireless/celeno/cl8k/enhanced_tim.c
new file mode 100644
index 000000000000..da2a0cf547fc
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/enhanced_tim.c
@@ -0,0 +1,216 @@
+// SPDX-License-Identifier: MIT
+/* Copyright(c) 2019-2021, Celeno Communications Ltd. */
+
+#include "enhanced_tim.h"
+#include "bus/pci/ipc.h"
+#include "utils/utils.h"
+
+/*
+ * The kernel's test_and_set_bit() gets unsigned long * as an argument, but we actually
+ * pass a pointer to u32, what cause to alignment fault in 64bit platforms.
+ * This function gets a pointer to u32 to prevent this alignment fault.
+ * Notice that the kernel's function sets the bit as an atomic operation,
+ * and our function doesn't. Vut it's not an issue since we set the bit from one context only.
+ */
+static int cl_test_and_set_bit(unsigned long nr, u32 *addr)
+{
+       u32 *new_addr, mask, old;
+
+       new_addr = ((u32 *)addr) + (nr >> 5);
+       mask = 1 << (nr & 31);
+       old = *new_addr & mask;
+       *new_addr |= mask;
+
+       return (old != 0);
+}
+
+static int CFM_TEST_AND_CLEAR_BIT(unsigned long nr, u32 *addr)
+{
+       u32 *new_addr, mask, old;
+
+       new_addr = ((u32 *)addr) + (nr >> 5);
+       mask = 1 << (nr & 31);
+       old = *new_addr & mask;
+       *new_addr &= ~mask;
+
+       return (old != 0);
+}
+
+void cl_enhanced_tim_reset(struct cl_hw *cl_hw)
+{
+       /*
+        * There is no need to reset cl_hw->ipc_env->shared->enhanced_tim.
+        * It is done as part of ipc_shared_env_init()
+        */
+       memset(&cl_hw->ipc_env->enhanced_tim, 0, sizeof(struct cl_ipc_enhanced_tim));
+}
+
+/*
+ * NOTE: the UMAC DRAM starts with the enhanced TIM elements stractures.
+ * This is hard coded in the FW, this memory allocation should be changed in
+ * the driver module .ELF file.
+ */
+
+void cl_enhanced_tim_clear_tx_agg(struct cl_hw *cl_hw, u32 ipc_queue_idx,
+                                 u8 ac, struct cl_sta *cl_sta, u8 tid)
+{
+       /* Pointer to HOST enhanced TIM */
+       u32 *source = cl_hw->ipc_env->enhanced_tim.tx_rx_agg[ac];
+       u32 ipc_queue_idx_common = IPC_TX_QUEUE_IDX_TO_COMMON_QUEUE_IDX(ipc_queue_idx);
+       /*
+        * Does the UMAC enhanced TIM need update?
+        * If the TIM element is set then clear it and update the UMAC TIM element
+        */
+       if (CFM_TEST_AND_CLEAR_BIT(ipc_queue_idx_common, source)) {
+               /* Pointer to UMAC enhanced TIM */
+               u32 *target = (u32 *)cl_hw->ipc_env->shared->enhanced_tim.tx_rx_agg[ac];
+               /* Offset to UMAC encahned TIM array position */
+               u32 agg_offset = ipc_queue_idx_common / (BITS_PER_BYTE * sizeof(u32));
+
+               /* Update tim element */
+               if (cl_sta && test_sta_flag(cl_sta->stainfo, WLAN_STA_PS_STA))
+                       ieee80211_sta_set_buffered(&cl_sta->stainfo->sta, tid,
+                                                  false);
+
+               target[agg_offset] = cpu_to_le32(source[agg_offset]);
+       }
+}
+
+void cl_enhanced_tim_clear_tx_single(struct cl_hw *cl_hw, u32 ipc_queue_idx, u8 ac,
+                                    bool no_ps_buffer, struct cl_sta *cl_sta, u8 tid)
+{
+       /* Pointer to HOST enhanced TIM */
+       u32 *source = cl_hw->ipc_env->enhanced_tim.tx_single[ac];
+       /* Staton index: 0 - 128 (do not use cl_sta->sta_idx which is 0 -127) */
+       u32 sta_idx = ipc_queue_idx % FW_MAX_NUM_STA;
+
+       /*
+        * Does the UMAC enhanced TIM need update?
+        * If the TIM element is set then clear it and update the UMAC TIM element
+        */
+       if (CFM_TEST_AND_CLEAR_BIT(sta_idx, source)) {
+               /* Pointer to UMAC enhanced TIM for singles or aggregation */
+               u32 *target = (u32 *)cl_hw->ipc_env->shared->enhanced_tim.tx_single[ac];
+               /* Offset to UMAC encahned TIM array position */
+               u32 sta_offset = sta_idx / (BITS_PER_BYTE * sizeof(u32));
+
+               /* Update tim element */
+               if (!no_ps_buffer && cl_sta &&
+                   test_sta_flag(cl_sta->stainfo, WLAN_STA_PS_STA))
+                       ieee80211_sta_set_buffered(&cl_sta->stainfo->sta, tid,
+                                                  false);
+
+               target[sta_offset] = cpu_to_le32(source[sta_offset]);
+       }
+}
+
+void cl_enhanced_tim_set_tx_agg(struct cl_hw *cl_hw, u32 ipc_queue_idx, u8 ac,
+                               bool no_ps_buffer, struct cl_sta *cl_sta, u8 tid)
+{
+       /* Pointer to HOST enhanced TIM */
+       u32 *source = cl_hw->ipc_env->enhanced_tim.tx_rx_agg[ac];
+       u32 ipc_queue_idx_common = IPC_TX_QUEUE_IDX_TO_COMMON_QUEUE_IDX(ipc_queue_idx);
+       /*
+        * Does the UMAC enhanced TIM need update?
+        * If the TIM element is cleared then set it and update the UMAC TIM element
+        */
+       if (!cl_test_and_set_bit(ipc_queue_idx_common, source)) {
+               /* Pointer to UMAC enhanced TIM */
+               u32 *target = (u32 *)cl_hw->ipc_env->shared->enhanced_tim.tx_rx_agg[ac];
+               /* Offset to UMAC encahned TIM array position */
+               u32 agg_offset = ipc_queue_idx_common / (BITS_PER_BYTE * sizeof(u32));
+
+               /* Update tim element */
+               if (!no_ps_buffer && cl_sta &&
+                   test_sta_flag(cl_sta->stainfo, WLAN_STA_PS_STA))
+                       ieee80211_sta_set_buffered(&cl_sta->stainfo->sta, tid,
+                                                  true);
+
+               target[agg_offset] = cpu_to_le32(source[agg_offset]);
+       }
+}
+
+void cl_enhanced_tim_set_tx_single(struct cl_hw *cl_hw, u32 ipc_queue_idx, u8 ac,
+                                  bool no_ps_buffer, struct cl_sta *cl_sta, u8 tid)
+{
+       /* Pointer to HOST enhanced TIM */
+       u32 *source = cl_hw->ipc_env->enhanced_tim.tx_single[ac];
+       /* Staton index: 0 - 128 (do not use cl_sta->sta_idx which is 0 -127) */
+       u32 sta_idx = ipc_queue_idx % FW_MAX_NUM_STA;
+
+       /*
+        * Does the UMAC enhanced TIM need update?
+        * If the TIM element is cleared then set it and update the UMAC TIM element
+        */
+       if (!cl_test_and_set_bit(sta_idx, source)) {
+               /* Pointer to UMAC enhanced TIM */
+               u32 *target = (u32 *)cl_hw->ipc_env->shared->enhanced_tim.tx_single[ac];
+               /* Offset to UMAC encahned TIM array position */
+               u32 sta_offset = sta_idx / (BITS_PER_BYTE * sizeof(u32));
+
+               /* Update tim element */
+               if (!no_ps_buffer && cl_sta &&
+                   test_sta_flag(cl_sta->stainfo, WLAN_STA_PS_STA))
+                       ieee80211_sta_set_buffered(&cl_sta->stainfo->sta, tid,
+                                                  true);
+
+               target[sta_offset] = cpu_to_le32(source[sta_offset]);
+       }
+}
+
+void cl_enhanced_tim_clear_rx(struct cl_hw *cl_hw, u8 ac, u8 sta_idx)
+{
+       /* Pointer to HOST enhanced TIM */
+       u32 *source = cl_hw->ipc_env->enhanced_tim.tx_rx_agg[ac];
+       u32 ipc_queue_idx_common = IPC_RX_QUEUE_IDX_TO_COMMON_QUEUE_IDX(sta_idx);
+       /*
+        * Does the UMAC enhanced TIM need update?
+        * If the TIM element is set then clear it and update the UMAC TIM element
+        */
+       if (CFM_TEST_AND_CLEAR_BIT(ipc_queue_idx_common, source)) {
+               /* Pointer to UMAC enhanced TIM for singles or aggregation */
+               u32 *target = (u32 *)cl_hw->ipc_env->shared->enhanced_tim.tx_rx_agg[ac];
+               /* Offset to UMAC encahned TIM array position */
+               u32 sta_offset = ipc_queue_idx_common / (BITS_PER_BYTE * sizeof(u32));
+
+               target[sta_offset] = cpu_to_le32(source[sta_offset]);
+       }
+}
+
+void cl_enhanced_tim_set_rx(struct cl_hw *cl_hw, u8 ac, u8 sta_idx)
+{
+       /* Pointer to HOST enhanced TIM */
+       u32 *source = cl_hw->ipc_env->enhanced_tim.tx_rx_agg[ac];
+       u32 ipc_queue_idx_common = IPC_RX_QUEUE_IDX_TO_COMMON_QUEUE_IDX(sta_idx);
+       /*
+        * Does the UMAC enhanced TIM need update?
+        * If the TIM element is cleared then set it and update the UMAC TIM element
+        */
+       if (!cl_test_and_set_bit(ipc_queue_idx_common, source)) {
+               /* Pointer to UMAC enhanced TIM */
+               u32 *target = (u32 *)cl_hw->ipc_env->shared->enhanced_tim.tx_rx_agg[ac];
+               /* Offset to UMAC encahned TIM array position */
+               u32 sta_offset = ipc_queue_idx_common / (BITS_PER_BYTE * sizeof(u32));
+
+               target[sta_offset] = cpu_to_le32(source[sta_offset]);
+
+               cl_hw->ipc_host2xmac_trigger_set(cl_hw->chip, BIT(IPC_IRQ_A2E_RX_STA_MAP(ac)));
+       }
+}
+
+void cl_enhanced_tim_clear_rx_sta(struct cl_hw *cl_hw, u8 sta_idx)
+{
+       u8 ac;
+
+       for (ac = 0; ac < AC_MAX; ac++)
+               cl_enhanced_tim_clear_rx(cl_hw, ac, sta_idx);
+}
+
+void cl_enhanced_tim_set_rx_sta(struct cl_hw *cl_hw, u8 sta_idx)
+{
+       u8 ac;
+
+       for (ac = 0; ac < AC_MAX; ac++)
+               cl_enhanced_tim_set_rx(cl_hw, ac, sta_idx);
+}
+
--
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.
________________________________


^ permalink raw reply related	[flat|nested] 262+ messages in thread

* [RFC v1 074/256] cl8k: add enhanced_tim.h
  2021-06-17 15:58 [RFC v1 000/256] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (72 preceding siblings ...)
  2021-06-17 15:59 ` [RFC v1 073/256] cl8k: add enhanced_tim.c viktor.barna
@ 2021-06-17 15:59 ` viktor.barna
  2021-06-17 15:59 ` [RFC v1 075/256] cl8k: add env_det.c viktor.barna
                   ` (183 subsequent siblings)
  257 siblings, 0 replies; 262+ messages in thread
From: viktor.barna @ 2021-06-17 15:59 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Oleksandr Savchenko, Shay Bar, Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

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

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 .../net/wireless/celeno/cl8k/enhanced_tim.h   | 24 +++++++++++++++++++
 1 file changed, 24 insertions(+)
 create mode 100644 drivers/net/wireless/celeno/cl8k/enhanced_tim.h

diff --git a/drivers/net/wireless/celeno/cl8k/enhanced_tim.h b/drivers/net/wireless/celeno/cl8k/enhanced_tim.h
new file mode 100644
index 000000000000..0d7b05bd28fe
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/enhanced_tim.h
@@ -0,0 +1,24 @@
+/* SPDX-License-Identifier: MIT */
+/* Copyright(c) 2019-2021, Celeno Communications Ltd. */
+
+#ifndef CL_ENHANCED_TIM_H
+#define CL_ENHANCED_TIM_H
+
+#include "hw.h"
+#include "sta.h"
+
+void cl_enhanced_tim_reset(struct cl_hw *cl_hw);
+void cl_enhanced_tim_clear_tx_agg(struct cl_hw *cl_hw, u32 ipc_queue_idx,
+                                 u8 ac, struct cl_sta *cl_sta, u8 tid);
+void cl_enhanced_tim_clear_tx_single(struct cl_hw *cl_hw, u32 ipc_queue_idx, u8 ac,
+                                    bool no_ps_buffer, struct cl_sta *cl_sta, u8 tid);
+void cl_enhanced_tim_set_tx_agg(struct cl_hw *cl_hw, u32 ipc_queue_idx, u8 ac,
+                               bool no_ps_buffer, struct cl_sta *cl_sta, u8 tid);
+void cl_enhanced_tim_set_tx_single(struct cl_hw *cl_hw, u32 ipc_queue_idx, u8 ac,
+                                  bool no_ps_buffer, struct cl_sta *cl_sta, u8 tid);
+void cl_enhanced_tim_clear_rx(struct cl_hw *cl_hw, u8 ac, u8 sta_idx);
+void cl_enhanced_tim_set_rx(struct cl_hw *cl_hw, u8 ac, u8 sta_idx);
+void cl_enhanced_tim_clear_rx_sta(struct cl_hw *cl_hw, u8 sta_idx);
+void cl_enhanced_tim_set_rx_sta(struct cl_hw *cl_hw, u8 sta_idx);
+
+#endif /* CL_ENHANCED_TIM_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.
________________________________


^ permalink raw reply related	[flat|nested] 262+ messages in thread

* [RFC v1 075/256] cl8k: add env_det.c
  2021-06-17 15:58 [RFC v1 000/256] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (73 preceding siblings ...)
  2021-06-17 15:59 ` [RFC v1 074/256] cl8k: add enhanced_tim.h viktor.barna
@ 2021-06-17 15:59 ` viktor.barna
  2021-06-17 15:59 ` [RFC v1 076/256] cl8k: add env_det.h viktor.barna
                   ` (182 subsequent siblings)
  257 siblings, 0 replies; 262+ messages in thread
From: viktor.barna @ 2021-06-17 15:59 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Oleksandr Savchenko, Shay Bar, Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

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

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 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.
________________________________


^ permalink raw reply related	[flat|nested] 262+ messages in thread

* [RFC v1 076/256] cl8k: add env_det.h
  2021-06-17 15:58 [RFC v1 000/256] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (74 preceding siblings ...)
  2021-06-17 15:59 ` [RFC v1 075/256] cl8k: add env_det.c viktor.barna
@ 2021-06-17 15:59 ` viktor.barna
  2021-06-17 15:59 ` [RFC v1 077/256] cl8k: add ext/dyn_bcast_rate.c viktor.barna
                   ` (181 subsequent siblings)
  257 siblings, 0 replies; 262+ messages in thread
From: viktor.barna @ 2021-06-17 15:59 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Oleksandr Savchenko, Shay Bar, Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

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

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 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.
________________________________


^ permalink raw reply related	[flat|nested] 262+ messages in thread

* [RFC v1 077/256] cl8k: add ext/dyn_bcast_rate.c
  2021-06-17 15:58 [RFC v1 000/256] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (75 preceding siblings ...)
  2021-06-17 15:59 ` [RFC v1 076/256] cl8k: add env_det.h viktor.barna
@ 2021-06-17 15:59 ` viktor.barna
  2021-06-17 15:59 ` [RFC v1 078/256] cl8k: add ext/dyn_bcast_rate.h viktor.barna
                   ` (180 subsequent siblings)
  257 siblings, 0 replies; 262+ messages in thread
From: viktor.barna @ 2021-06-17 15:59 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Oleksandr Savchenko, Shay Bar, Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

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

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 .../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.
________________________________


^ permalink raw reply related	[flat|nested] 262+ messages in thread

* [RFC v1 078/256] cl8k: add ext/dyn_bcast_rate.h
  2021-06-17 15:58 [RFC v1 000/256] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (76 preceding siblings ...)
  2021-06-17 15:59 ` [RFC v1 077/256] cl8k: add ext/dyn_bcast_rate.c viktor.barna
@ 2021-06-17 15:59 ` viktor.barna
  2021-06-17 15:59 ` [RFC v1 079/256] cl8k: add ext/dyn_mcast_rate.c viktor.barna
                   ` (179 subsequent siblings)
  257 siblings, 0 replies; 262+ messages in thread
From: viktor.barna @ 2021-06-17 15:59 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Oleksandr Savchenko, Shay Bar, Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

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

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 .../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.
________________________________


^ permalink raw reply related	[flat|nested] 262+ messages in thread

* [RFC v1 079/256] cl8k: add ext/dyn_mcast_rate.c
  2021-06-17 15:58 [RFC v1 000/256] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (77 preceding siblings ...)
  2021-06-17 15:59 ` [RFC v1 078/256] cl8k: add ext/dyn_bcast_rate.h viktor.barna
@ 2021-06-17 15:59 ` viktor.barna
  2021-06-17 15:59 ` [RFC v1 080/256] cl8k: add ext/dyn_mcast_rate.h viktor.barna
                   ` (178 subsequent siblings)
  257 siblings, 0 replies; 262+ messages in thread
From: viktor.barna @ 2021-06-17 15:59 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Oleksandr Savchenko, Shay Bar, Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

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

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 .../wireless/celeno/cl8k/ext/dyn_mcast_rate.c | 125 ++++++++++++++++++
 1 file changed, 125 insertions(+)
 create mode 100644 drivers/net/wireless/celeno/cl8k/ext/dyn_mcast_rate.c

diff --git a/drivers/net/wireless/celeno/cl8k/ext/dyn_mcast_rate.c b/drivers/net/wireless/celeno/cl8k/ext/dyn_mcast_rate.c
new file mode 100644
index 000000000000..bbd83468bcc7
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/ext/dyn_mcast_rate.c
@@ -0,0 +1,125 @@
+// SPDX-License-Identifier: MIT
+/* Copyright(c) 2019-2021, Celeno Communications Ltd. */
+
+#include "band.h"
+#include "sta.h"
+#include "rate_ctrl.h"
+#include "data_rates.h"
+#include "utils/utils.h"
+
+static void _cl_dyn_mcast_rate_send(struct cl_hw *cl_hw, u8 wrs_mode_new)
+{
+       struct cl_dyn_mcast_rate *dyn_mcast_rate = &cl_hw->dyn_mcast_rate;
+
+       if (dyn_mcast_rate->wrs_mode_curr == wrs_mode_new)
+               return;
+
+       if (!cl_rate_ctrl_set_mcast(cl_hw, wrs_mode_new, cl_hw->conf->ce_mcast_rate))
+               return;
+
+       dyn_mcast_rate->wrs_mode_curr = wrs_mode_new;
+       cl_dbg_trace(cl_hw, "New multicast mode = %u\n", wrs_mode_new);
+}
+
+void cl_dyn_mcast_rate_init(struct cl_hw *cl_hw)
+{
+       struct cl_dyn_mcast_rate *dyn_mcast_rate = &cl_hw->dyn_mcast_rate;
+
+       if (cl_hw->conf->ci_min_he_en &&
+           cl_hw->conf->ce_wireless_mode == WIRELESS_MODE_HE)
+               dyn_mcast_rate->wrs_mode_default = WRS_MODE_HE;
+       else if (cl_band_is_24g(cl_hw) && cl_hw_mode_is_b_or_bg(cl_hw))
+               dyn_mcast_rate->wrs_mode_default = WRS_MODE_CCK;
+       else
+               dyn_mcast_rate->wrs_mode_default = WRS_MODE_OFDM;
+
+       cl_dbg_trace(cl_hw, "mode = %u, mcs = %u\n",
+                    dyn_mcast_rate->wrs_mode_default, cl_hw->conf->ce_mcast_rate);
+}
+
+void cl_dyn_mcast_rate_set(struct cl_hw *cl_hw)
+{
+       /*
+        * Set wrs_mode_curr to 0xff so that the message will be sent to
+        * firmware when this function is called from cl_ops_start()
+        */
+       struct cl_dyn_mcast_rate *dyn_mcast_rate = &cl_hw->dyn_mcast_rate;
+
+       dyn_mcast_rate->wrs_mode_curr = U8_MAX;
+
+       _cl_dyn_mcast_rate_send(cl_hw, dyn_mcast_rate->wrs_mode_default);
+}
+
+u16 cl_dyn_mcast_rate_get(struct cl_hw *cl_hw)
+{
+       struct cl_dyn_mcast_rate *dyn_mcast_rate = &cl_hw->dyn_mcast_rate;
+
+       return cl_data_rates_get(dyn_mcast_rate->wrs_mode_curr, 0, 0,
+                                cl_hw->conf->ce_mcast_rate, 0);
+}
+
+void cl_dyn_mcast_rate_recovery(struct cl_hw *cl_hw)
+{
+       /*
+        * cl_dyn_mcast_rate_recovery() is called during recovery process().
+        * Reset wrs_mode_curr so that message will be sent.
+        */
+       struct cl_dyn_mcast_rate *dyn_mcast_rate = &cl_hw->dyn_mcast_rate;
+       u8 wrs_mode_curr = dyn_mcast_rate->wrs_mode_curr;
+
+       dyn_mcast_rate->wrs_mode_curr = U8_MAX;
+
+       _cl_dyn_mcast_rate_send(cl_hw, wrs_mode_curr);
+}
+
+void cl_dyn_mcast_rate_update_upon_assoc(struct cl_hw *cl_hw, u8 wrs_mode, u8 num_sta)
+{
+       struct cl_dyn_mcast_rate *dyn_mcast_rate = &cl_hw->dyn_mcast_rate;
+
+       if (!cl_hw->conf->ce_dyn_mcast_rate_en)
+               return;
+
+       /*
+        * If the wrs_mode of the new station is lower than the current multicast
+        * wrs_mode, or if this is the first station to connect - update multicast mode
+        */
+       if (wrs_mode < dyn_mcast_rate->wrs_mode_curr || num_sta == 1)
+               _cl_dyn_mcast_rate_send(cl_hw, wrs_mode);
+}
+
+void cl_dyn_mcast_rate_update_upon_disassoc(struct cl_hw *cl_hw, u8 wrs_mode, u8 num_sta)
+{
+       struct cl_dyn_mcast_rate *dyn_mcast_rate = &cl_hw->dyn_mcast_rate;
+       struct cl_sta *cl_sta = NULL;
+       u8 wrs_mode_min = WRS_MODE_HE;
+
+       if (!cl_hw->conf->ce_dyn_mcast_rate_en)
+               return;
+
+       /* When the last station disconnects - set default mcast rate */
+       if (num_sta == 0) {
+               _cl_dyn_mcast_rate_send(cl_hw, dyn_mcast_rate->wrs_mode_default);
+               return;
+       }
+
+       /*
+        * If wrs_mode of the disassociating station is bigger
+        * than the current mode then there is nothing to update.
+        */
+       if (wrs_mode > dyn_mcast_rate->wrs_mode_curr)
+               return;
+
+       /*
+        * Find minimal wrs_mode among the connected stations (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.mode < wrs_mode_min)
+                       wrs_mode_min = cl_sta->wrs_sta.mode;
+
+       cl_sta_unlock_bh(cl_hw);
+
+       _cl_dyn_mcast_rate_send(cl_hw, wrs_mode_min);
+}
--
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.
________________________________


^ permalink raw reply related	[flat|nested] 262+ messages in thread

* [RFC v1 080/256] cl8k: add ext/dyn_mcast_rate.h
  2021-06-17 15:58 [RFC v1 000/256] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (78 preceding siblings ...)
  2021-06-17 15:59 ` [RFC v1 079/256] cl8k: add ext/dyn_mcast_rate.c viktor.barna
@ 2021-06-17 15:59 ` viktor.barna
  2021-06-17 15:59 ` [RFC v1 081/256] cl8k: add ext/vlan_dscp.c viktor.barna
                   ` (177 subsequent siblings)
  257 siblings, 0 replies; 262+ messages in thread
From: viktor.barna @ 2021-06-17 15:59 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Oleksandr Savchenko, Shay Bar, Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

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

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 .../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.
________________________________


^ permalink raw reply related	[flat|nested] 262+ messages in thread

* [RFC v1 081/256] cl8k: add ext/vlan_dscp.c
  2021-06-17 15:58 [RFC v1 000/256] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (79 preceding siblings ...)
  2021-06-17 15:59 ` [RFC v1 080/256] cl8k: add ext/dyn_mcast_rate.h viktor.barna
@ 2021-06-17 15:59 ` viktor.barna
  2021-06-17 15:59 ` [RFC v1 082/256] cl8k: add ext/vlan_dscp.h viktor.barna
                   ` (176 subsequent siblings)
  257 siblings, 0 replies; 262+ messages in thread
From: viktor.barna @ 2021-06-17 15:59 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Oleksandr Savchenko, Shay Bar, Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

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

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 .../net/wireless/celeno/cl8k/ext/vlan_dscp.c  | 658 ++++++++++++++++++
 1 file changed, 658 insertions(+)
 create mode 100644 drivers/net/wireless/celeno/cl8k/ext/vlan_dscp.c

diff --git a/drivers/net/wireless/celeno/cl8k/ext/vlan_dscp.c b/drivers/net/wireless/celeno/cl8k/ext/vlan_dscp.c
new file mode 100644
index 000000000000..9942d5599ffb
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/ext/vlan_dscp.c
@@ -0,0 +1,658 @@
+// SPDX-License-Identifier: MIT
+/* Copyright(c) 2019-2021, Celeno Communications Ltd. */
+
+#include <linux/if_vlan.h>
+#include <linux/string.h>
+
+#include "ext/vlan_dscp.h"
+#include "utils/ip.h"
+#include "vif.h"
+#include "hw.h"
+#include "utils/utils.h"
+
+#define VLAN_DSCP_DBG(...) \
+       do { \
+               if (cl_hw->vlan_dscp.debug) \
+                       pr_debug(__VA_ARGS__); \
+       } while (0)
+
+static u8 get_vlan_pbit_up(struct cl_hw *cl_hw, u8 pbit_val, u16 vlan_id_val, u8 ap_idx)
+{
+       /* Get UP from VID + priority bits */
+       u8 user_priority = 0;
+       u8 pbit_found = 0;
+       struct cl_vid_user *vid_user;
+       struct cl_vlan_dhcp_params *vlan_dhcp_params =
+               &cl_hw->vlan_dscp.vlan_dhcp_params[ap_idx];
+       int j;
+
+       for (j = 0; j < CL_USER_PRIO_VALS; j++) {
+               vid_user = &vlan_dhcp_params->vlan_pbit_to_up[pbit_val][j];
+               if (vid_user->vid == 0)
+                       break; /* End of vid list in this Pbit raw */
+
+               if (vlan_id_val == vid_user->vid) {
+                       user_priority = vid_user->user_prio;
+                       pbit_found = 1;
+                       break;
+               }
+       }
+
+       /* Use vlan_to_up mapping */
+       if (pbit_found == 0)
+               user_priority = vlan_dhcp_params->vlan_to_up[pbit_val];
+
+       VLAN_DSCP_DBG("[%s] vlan_id_val=%u, pbit_val=%u, ap_idx=%u, user_priority=%u\n",
+                     __func__, vlan_id_val, pbit_val, ap_idx, user_priority);
+
+       return user_priority;
+}
+
+static u8 get_ip_user_priority(struct cl_hw *cl_hw, u8 *src_buf, u16 protocol, u8 ap_idx)
+{
+       /* Get UP from DSCP value */
+       u8 user_priority = cl_hw->vlan_dscp.vlan_dhcp_params[ap_idx].dscp_to_up[0];
+       u8 dscp_val = 0;
+
+       if (protocol == ETH_P_IP) /* IPv4 */
+               dscp_val = (*(src_buf + 1) & 0xfc) >> 2;
+       else
+               dscp_val = (ntohs(*(u16 *)src_buf) >> 6) & 0x3f;
+
+       if (dscp_val > 63) {
+               VLAN_DSCP_DBG("[%s] bad DSCP value = %u\n", __func__, dscp_val);
+               return user_priority;
+       }
+
+       /* Look for priority in the DSCP array */
+       user_priority = cl_hw->vlan_dscp.vlan_dhcp_params[ap_idx].dscp_to_up[dscp_val];
+       if (user_priority == U8_MAX) {
+               /* Value wasn't found in the array. use regular parsing */
+               if (protocol == ETH_P_IP) /* IPv4 */
+                       user_priority = (*(src_buf + 1) & 0xe0) >> 5;
+               else /* IPv6 */
+                       user_priority = ((*src_buf) & 0x0e) >> 1;
+       }
+
+       VLAN_DSCP_DBG("[%s] dscp_val=%u, user_priority=%u, ap_idx=%u\n",
+                     __func__, dscp_val, user_priority, ap_idx);
+
+       return user_priority;
+}
+
+static int print_configuration(struct cl_hw *cl_hw, u8 ap_idx)
+{
+       /* Print all the configuration parameters for specific AP */
+       struct cl_vlan_dscp *dscp = &cl_hw->vlan_dscp;
+       struct cl_vlan_dhcp_params *param = &dscp->vlan_dhcp_params[ap_idx];
+       u8 i, j;
+       char *buf = NULL;
+       ssize_t buf_size;
+       int err = 0;
+       int len = 0;
+
+       cl_snprintf(&buf, &len, &buf_size,
+                   "=====================================\n");
+       cl_snprintf(&buf, &len, &buf_size,
+                   "AP %u\n", ap_idx);
+       cl_snprintf(&buf, &len, &buf_size,
+                   "=====================================\n");
+       cl_snprintf(&buf, &len, &buf_size,
+                   "enable = %s\n", dscp->enable[ap_idx] ? "True" : "False");
+       cl_snprintf(&buf, &len, &buf_size,
+                   "up_layer_based = %u [0-AUTO 2-VLAN 3-DSCP]\n", param->up_layer_based);
+       cl_snprintf(&buf, &len, &buf_size,
+                   "default_vlan_up = %u\n", param->default_vlan_up);
+
+       cl_snprintf(&buf, &len, &buf_size, "\ndscp_to_up:\n");
+
+       for (i = 0; i < CL_USER_DSCP_VALS; i++) {
+               cl_snprintf(&buf, &len, &buf_size,
+                           "dscp=%u up=%u", i, param->dscp_to_up[i]);
+               if ((i + 1) % 8 == 0)
+                       cl_snprintf(&buf, &len, &buf_size, "\n");
+               else
+                       cl_snprintf(&buf, &len, &buf_size, "\t");
+       }
+
+       cl_snprintf(&buf, &len, &buf_size, "\n\nvlan_to_up:\n");
+       for (i = 0; i < CL_USER_PRIO_VALS; i++)
+               cl_snprintf(&buf, &len, &buf_size,
+                           "%3u ", param->vlan_to_up[i]);
+
+       cl_snprintf(&buf, &len, &buf_size, "\n\nvlan_pbit_to_up:\n");
+       for (i = 0; i < CL_USER_PRIO_VALS; i++) {
+               cl_snprintf(&buf, &len, &buf_size, "pbit %u\t", i);
+               for (j = 0; j < CL_USER_PRIO_VALS; j++)
+                       cl_snprintf(&buf, &len, &buf_size,
+                                   "v=%u,up=%u\t",
+                                   param->vlan_pbit_to_up[i][j].vid,
+                                   param->vlan_pbit_to_up[i][j].user_prio);
+
+               cl_snprintf(&buf, &len, &buf_size, "\n");
+       }
+
+       err = cl_vendor_reply(cl_hw, buf, len);
+       kfree(buf);
+
+       return err;
+}
+
+static void read_dscp_parms_format1(struct cl_hw *cl_hw, char *buffer, u8 ap_idx)
+{
+       int i;
+       int num_of_str;
+       char *tok_ptr;
+       char *mac_ptr;
+       char *str_ptr[CL_USER_DSCP_VALS];
+       u8 dscp;
+       u8 user_prio;
+       u32 val;
+       struct cl_vlan_dhcp_params *vlan_dhcp_params =
+               &cl_hw->vlan_dscp.vlan_dhcp_params[ap_idx];
+
+       mac_ptr = strsep(&buffer, ";");
+       for (num_of_str = 0; mac_ptr && (num_of_str < ARRAY_SIZE(str_ptr)); num_of_str++) {
+               str_ptr[num_of_str] = mac_ptr;
+               mac_ptr = strsep(&buffer, ";");
+       }
+
+       for (i = 0; i < num_of_str; i++) {
+               val = U32_MAX;
+               dscp = U8_MAX;
+               user_prio = U8_MAX;
+
+               /* Get DSCP 0-63 */
+               tok_ptr = strsep(&str_ptr[i], ",");
+
+               if (!tok_ptr) {
+                       pr_err("dscp_to_up0_7dec: dscp null\n");
+                       continue;
+               }
+               if (kstrtou32(tok_ptr, 10, &val) != 0) {
+                       pr_err("dscp_to_up0_7dec: invalid dscp (%s)\n", tok_ptr);
+                       continue;
+               }
+               if (val > 63) {
+                       pr_err("dscp_to_up0_7dec: dscp exceeds 63 (%u)\n", val);
+                       continue;
+               }
+
+               dscp = (u8)val;
+
+               /* Get user priority */
+               val = U32_MAX;
+               tok_ptr = strsep(&str_ptr[i], ",");
+
+               if (!tok_ptr) {
+                       pr_err("dscp_to_up0_7dec: up null\n");
+                       continue;
+               }
+               if (kstrtou32(tok_ptr, 10, &val) != 0) {
+                       pr_err("dscp_to_up0_7dec: invalid up (%s)\n", tok_ptr);
+                       continue;
+               }
+               if (val > 7) {
+                       pr_err("dscp_to_up0_7dec: up exceeds 7 (%u)\n", val);
+                       continue;
+               }
+
+               user_prio = (u8)val;
+
+               /* At this point the 2 parameters are valid: dscp, and user_prio */
+               if (vlan_dhcp_params->dscp_to_up[dscp] == U8_MAX)
+                       /* First time initialization for this dscp */
+                       vlan_dhcp_params->dscp_to_up[dscp] = user_prio;
+               else
+                       pr_warn("dscp_to_up0_7dec[%u] is already set with user_prio %u."
+                               "Will not set it with a different user_prio %u\n",
+                               dscp, vlan_dhcp_params->dscp_to_up[dscp], user_prio);
+       }
+}
+
+static void read_dscp_parms_format2(struct cl_hw *cl_hw, char *buffer, u8 ap_idx)
+{
+       int i;
+       char *mac_ptr;
+       u8 dscp_val;
+       struct cl_vlan_dhcp_params *vlan_dhcp_params =
+               &cl_hw->vlan_dscp.vlan_dhcp_params[ap_idx];
+
+       for (i = 0, mac_ptr = strsep(&buffer, ","); mac_ptr; mac_ptr = strsep(&buffer, ","), i++) {
+               if (i > (CL_USER_PRIO_VALS - 1)) {
+                       pr_err("dscp_to_up0_7dec: DSCP exceeds %d entries!"
+                              "Remaining DSCP entries ignored\n", CL_USER_PRIO_VALS);
+                       break;
+               }
+
+               if (kstrtou8(mac_ptr, 10, &dscp_val) != 0) {
+                       pr_err("dscp_to_up0_7dec: Invalid dscp (%s)\n", mac_ptr);
+                       continue;
+               }
+
+               if (dscp_val > 63) {
+                       pr_err("dscp_to_up0_7dec: illegal dscp value %u."
+                              "Converted to %u\n", dscp_val, (dscp_val & 0x3F));
+                       dscp_val &= 0x3F;
+               }
+
+               vlan_dhcp_params->dscp_to_up[dscp_val] = i;
+       }
+
+       if (i < (CL_USER_PRIO_VALS - 1))
+               pr_warn("dscp_to_up0_7dec: only %d first DSCP entries filled in."
+                       "Remaining DSCP entries will remain unassigned\n", i + 1);
+}
+
+static void read_dscp_parms_from_buffer(struct cl_hw *cl_hw, char *buffer, u8 ap_idx)
+{
+       /*
+        * Initiate configuration per AP index by buffer by
+        * configuration parameter dscp_to_up0_7dec
+        */
+       char *pch;
+       struct cl_vlan_dhcp_params *vlan_dhcp_params =
+               &cl_hw->vlan_dscp.vlan_dhcp_params[ap_idx];
+
+       if (!buffer || (strlen(buffer) == 0))
+               return;
+
+       /* Initially fill with illegal dscp value */
+       memset(vlan_dhcp_params->dscp_to_up, U8_MAX, CL_USER_DSCP_VALS);
+
+       pch = strchr(buffer, ';');
+       if (pch)
+               /* Handle the follow format dscp_val1,up;dscp_val2,up;dscp_val3,up;... */
+               read_dscp_parms_format1(cl_hw, buffer, ap_idx);
+       else
+               /* Handle the follow format dscp_to_up_0,dscp_to_up_1,dscp_to_up_2,... */
+               read_dscp_parms_format2(cl_hw, buffer, ap_idx);
+}
+
+static void read_vlan_parms_format1(struct cl_hw *cl_hw, char *buffer, u8 ap_idx)
+{
+       int i, j, num_of_str;
+       char *mac_ptr, *tok_ptr;
+       char *str_ptr[CL_USER_PRIO_VALS * CL_USER_PRIO_VALS];
+       u8 pbit, user_prio;
+       u8 helper[CL_USER_PRIO_VALS];
+       u16 vid;
+       u32 val;
+       struct cl_vlan_dhcp_params *vlan_dhcp_params = &cl_hw->vlan_dscp.vlan_dhcp_params[ap_idx];
+
+       /*Initialize array */
+       for (i = 0; i < CL_USER_PRIO_VALS; i++) {
+               for (j = 0; j < CL_USER_PRIO_VALS; j++) {
+                       vlan_dhcp_params->vlan_pbit_to_up[i][j].vid = 0;
+                       vlan_dhcp_params->vlan_pbit_to_up[i][j].user_prio = 0;
+               }
+               helper[i] = 0;
+       }
+
+       mac_ptr = strsep(&buffer, ";");
+
+       for (num_of_str = 0; mac_ptr && (num_of_str < ARRAY_SIZE(str_ptr)); num_of_str++) {
+               str_ptr[num_of_str] = mac_ptr;
+               mac_ptr = strsep(&buffer, ";");
+       }
+
+       for (i = 0; i < num_of_str; i++) {
+               val = U32_MAX;
+               pbit = U8_MAX;
+               vid = U16_MAX;
+               user_prio = U8_MAX;
+
+               /* Get vid */
+               tok_ptr = strsep(&str_ptr[i], ",");
+               if (!tok_ptr) {
+                       pr_err("vlan_to_up0_7dec: vid null\n");
+                       continue;
+               }
+               if (kstrtou32(tok_ptr, 10, &val) != 0) {
+                       pr_err("vlan_to_up0_7dec: invalid vid (%s)\n", tok_ptr);
+                       continue;
+               }
+               if (val > 4095) {
+                       pr_err("vlan_to_up0_7dec: vid exceeds 4095 (%u)\n", val);
+                       continue;
+               }
+
+               vid = (u16)val;
+
+               /* Get p-bit */
+               val = U32_MAX;
+               tok_ptr = strsep(&str_ptr[i], ",");
+
+               if (!tok_ptr) {
+                       pr_err("vlan_to_up0_7dec: pbit null\n");
+                       continue;
+               }
+               if (kstrtou32(tok_ptr, 10, &val) != 0) {
+                       pr_err("vlan_to_up0_7dec: invalid pbit (%s)\n", tok_ptr);
+                       continue;
+               }
+               if (val > 7) {
+                       pr_err("vlan_to_up0_7dec: pbit exceeds 7 (%u)\n", val);
+                       continue;
+               }
+
+               pbit = (u8)val;
+
+               /* Get user priority */
+               val = U32_MAX;
+               tok_ptr = strsep(&str_ptr[i], ",");
+
+               if (!tok_ptr) {
+                       pr_err("vlan_to_up0_7dec: up null\n");
+                       continue;
+               }
+               if (kstrtou32(tok_ptr, 10, &val) != 0) {
+                       pr_err("vlan_to_up0_7dec: invalid up (%s)\n", tok_ptr);
+                       continue;
+               }
+               if (val > 7) {
+                       pr_err("vlan_to_up0_7dec: up exceeds 7 (%u)\n", val);
+                       continue;
+               }
+
+               user_prio = (u8)val;
+
+               /* At this point all 3 parameters are valid: p-bit, vid and user_prio */
+               if (vid != 0) {
+                       if (helper[pbit] < CL_USER_PRIO_VALS) {
+                               struct cl_vid_user *vid_user =
+                                       &vlan_dhcp_params->vlan_pbit_to_up[pbit][helper[pbit]];
+
+                               vid_user->vid = vid;
+                               vid_user->user_prio = user_prio;
+                               helper[pbit]++;
+
+                               /*
+                                * Mark the fact that vlan_pbit_to_up
+                                * array has been initialized
+                                */
+                               if (vlan_dhcp_params->vlan_pbit_to_up[0][0].user_prio == (u8)(-1))
+                                       vlan_dhcp_params->vlan_pbit_to_up[0][0].user_prio = 0;
+                       }
+               } else {
+                       vlan_dhcp_params->vlan_to_up[pbit] = user_prio;
+               }
+       }
+}
+
+static void read_vlan_parms_format2(struct cl_hw *cl_hw, char *buffer, u8 ap_idx)
+{
+       struct cl_vlan_dhcp_params *vlan_dhcp_params = &cl_hw->vlan_dscp.vlan_dhcp_params[ap_idx];
+       int i;
+       char *mac_ptr;
+       u8 user_prio;
+
+       for (i = 0, mac_ptr = strsep(&buffer, ","); mac_ptr; mac_ptr = strsep(&buffer, ","), i++) {
+               if (i > (CL_USER_PRIO_VALS - 1)) {
+                       pr_warn("vlan_to_up0_7dec: Priority bit exceeds %d entries!"
+                               "Rest of Priority bits ignored\n", CL_USER_PRIO_VALS);
+                       break;
+               }
+
+               if (kstrtou8(mac_ptr, 10, &user_prio) != 0) {
+                       pr_err("dscp_to_up0_7dec: Invalid up (%s)\n", mac_ptr);
+                       continue;
+               }
+
+               if (user_prio > 7) {
+                       pr_err("vlan_to_up0_7dec[%d]: illegal user priority %u."
+                              "Set it to %u\n", i, user_prio, (user_prio & 0x7));
+                       user_prio = (user_prio & 0x7);
+               }
+
+               vlan_dhcp_params->vlan_to_up[i] = user_prio;
+       }
+
+       if (i < (CL_USER_PRIO_VALS - 1))
+               pr_warn("vlan_to_up0_7dec: only %d first priority bits entries filled in."
+                       "Remaining priority bits will remain unassigned\n", i + 1);
+}
+
+static void read_vlan_parms_from_buffer(struct cl_hw *cl_hw, char *buffer, u8 ap_idx)
+{
+       /*
+        * Initiate configuration per AP index by buffer
+        * by configuration parameter vlan_to_up0_7dec
+        */
+       struct cl_vlan_dhcp_params *vlan_dhcp_params =
+               &cl_hw->vlan_dscp.vlan_dhcp_params[ap_idx];
+       int i;
+       char *pch;
+
+       if (!buffer || (strlen(buffer) == 0))
+               return;
+
+       /* Assume initially no change in vlan user priority */
+       for (i = 0; i < CL_USER_PRIO_VALS; i++)
+               vlan_dhcp_params->vlan_to_up[i] = i;
+
+       /* Assume initially vid_pbit NVRAM parameter is not initialized */
+       vlan_dhcp_params->vlan_pbit_to_up[0][0].user_prio = (u8)(-1);
+
+       pch = strchr(buffer, ';');
+       if (pch)
+               /* Handle format vlan_id1,pbit,up;vlan_id2,pbit,up;vlan_id3,pbit,up.. */
+               read_vlan_parms_format1(cl_hw, buffer, ap_idx);
+       else
+               /* Handle the follow format dscp_to_up_0,dscp_to_up_1,dscp_to_up_2,... */
+               read_vlan_parms_format2(cl_hw, buffer, ap_idx);
+}
+
+static void read_layer_based_parms_from_buffer(struct cl_hw *cl_hw, char *buffer, u8 ap_idx)
+{
+       if (!buffer || (strlen(buffer) == 0))
+               return;
+
+       if ((strcmp(buffer, "AUTO") == 0) || (strcmp(buffer, "0") == 0))
+               cl_hw->vlan_dscp.vlan_dhcp_params[ap_idx].up_layer_based = 0;
+       else if ((strcmp(buffer, "VLAN") == 0) || (strcmp(buffer, "2") == 0))
+               cl_hw->vlan_dscp.vlan_dhcp_params[ap_idx].up_layer_based = 2;
+       else if ((strcmp(buffer, "DSCP") == 0) || (strcmp(buffer, "3") == 0))
+               cl_hw->vlan_dscp.vlan_dhcp_params[ap_idx].up_layer_based = 3;
+       else
+               pr_err("%s: invalid input [%s]\n", __func__, buffer);
+}
+
+static void read_default_vlan_up_parms_from_buffer(struct cl_hw *cl_hw, char *buffer, u8 ap_idx)
+{
+       u8 default_vlan_up;
+
+       if (!buffer || (strlen(buffer) == 0))
+               return;
+
+       if (kstrtou8(buffer, 10, &default_vlan_up) != 0) {
+               pr_err("invalid param - %s\n", buffer);
+               return;
+       }
+
+       if (default_vlan_up < 8)
+               cl_hw->vlan_dscp.vlan_dhcp_params[ap_idx].default_vlan_up = default_vlan_up;
+}
+
+static int cl_vlan_dscp_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,
+                "qos usage:\n"
+                "-a : Set ce_dscp_to_up0_7dec0 [val]\n"
+                "-b : Set ce_vlan_to_up0_7dec0 [val]\n"
+                "-c : Set ce_up0_7_layer_based [val]\n"
+                "-d : Set ce_up0_7_default_vlan_user_prio [val]\n"
+                "-e : Enable/Disable QOS functionality [1/0]\n"
+                "-s : Show current QoS configuration\n"
+                "-v : Enable/Disable QOS debug [1/0]\n");
+
+       err = cl_vendor_reply(cl_hw, buf, strlen(buf));
+       kfree(buf);
+
+       return err;
+}
+
+void cl_vlan_dscp_init(struct cl_hw *cl_hw)
+{
+       struct cl_tcv_conf *conf = cl_hw->conf;
+       u8 ap_idx;
+
+       for (ap_idx = 0; ap_idx < MAX_BSS_NUM; ap_idx++) {
+               cl_hw->vlan_dscp.enable[ap_idx] = conf->ce_dscp_vlan_enable[ap_idx];
+               cl_hw->vlan_dscp.vlan_dhcp_params[ap_idx].up_layer_based =
+                       conf->ce_up0_7_layer_based[ap_idx];
+               cl_hw->vlan_dscp.vlan_dhcp_params[ap_idx].default_vlan_up =
+                       conf->ce_up0_7_default_vlan_user_prio[ap_idx];
+       }
+
+       /* Ce_dscp_to_up0_7decX */
+       read_dscp_parms_from_buffer(cl_hw, conf->ce_dscp_to_up0_7dec0, 0);
+       read_dscp_parms_from_buffer(cl_hw, conf->ce_dscp_to_up0_7dec1, 1);
+       read_dscp_parms_from_buffer(cl_hw, conf->ce_dscp_to_up0_7dec2, 2);
+       read_dscp_parms_from_buffer(cl_hw, conf->ce_dscp_to_up0_7dec3, 3);
+       read_dscp_parms_from_buffer(cl_hw, conf->ce_dscp_to_up0_7dec4, 4);
+       read_dscp_parms_from_buffer(cl_hw, conf->ce_dscp_to_up0_7dec5, 5);
+       read_dscp_parms_from_buffer(cl_hw, conf->ce_dscp_to_up0_7dec6, 6);
+       read_dscp_parms_from_buffer(cl_hw, conf->ce_dscp_to_up0_7dec7, 7);
+
+       /* Ce_vlan_to_up0_7decX */
+       read_vlan_parms_from_buffer(cl_hw, conf->ce_vlan_to_up0_7dec0, 0);
+       read_vlan_parms_from_buffer(cl_hw, conf->ce_vlan_to_up0_7dec1, 1);
+       read_vlan_parms_from_buffer(cl_hw, conf->ce_vlan_to_up0_7dec2, 2);
+       read_vlan_parms_from_buffer(cl_hw, conf->ce_vlan_to_up0_7dec3, 3);
+       read_vlan_parms_from_buffer(cl_hw, conf->ce_vlan_to_up0_7dec4, 4);
+       read_vlan_parms_from_buffer(cl_hw, conf->ce_vlan_to_up0_7dec5, 5);
+       read_vlan_parms_from_buffer(cl_hw, conf->ce_vlan_to_up0_7dec6, 6);
+       read_vlan_parms_from_buffer(cl_hw, conf->ce_vlan_to_up0_7dec7, 7);
+}
+
+bool cl_vlan_dscp_is_enabled(struct cl_hw *cl_hw, struct cl_vif *cl_vif)
+{
+       return cl_hw->vlan_dscp.enable[cl_vif->vif_index];
+}
+
+u8 cl_vlan_dscp_check_ether_type(struct cl_hw *cl_hw, struct sk_buff *skb, u8 ap_idx)
+{
+       /* Calculate the user priority according to the celeno logic and configuration */
+       struct cl_vlan_dhcp_params *vlan_dhcp_params = &cl_hw->vlan_dscp.vlan_dhcp_params[ap_idx];
+       u8 user_priority = 0;
+       u16 ether_type;
+       u8 *src_buf = skb->data;
+
+       /* VLAN TCI: 3-bit UP + 1-bit CFI + 12-bit VLAN ID */
+       u16 vlan_id_val = 0;
+       u8 pbit_val = 0;
+
+       /* Get Ethernet protocol field*/
+       ether_type = get_ether_type(2 * ETH_ALEN, src_buf);
+       /* Skip the Ethernet Header.*/
+       src_buf += ETH_HLEN;
+
+       /*
+        * handel LLC packets
+        * if it's a LLC packet we should move the data pointer and to
+        * get the ether type from the llc header add support to other LLC
+        */
+       if (ether_type <= 1500) {
+               /* 802.3, 802.3 LLC
+                * DestMAC(6) + SrcMAC(6) + Length(2) +
+                * DSAP(1) + SSAP(1) + Control(1) +
+                * if the DSAP = 0xAA, SSAP=0xAA, Contorl = 0x03, it has a 5-bytes SNAP header.
+                * => + SNAP (5, OriginationID(3) + etherType(2))
+                */
+               if (PKT_HAS_LLC_HDR(src_buf)) {
+                       /* Get new ether_type */
+                       ether_type = get_ether_type(LENGTH_LLC + LENGTH_SSNAP - 2, src_buf);
+                       src_buf += LENGTH_LLC + LENGTH_SSNAP; /* Skip this LLC/SNAP header */
+               }
+       }
+
+       if (ether_type == ETH_VLAN || skb->vlan_tci != 0) {
+               if (skb->vlan_tci != 0) {
+                       pbit_val = (skb->vlan_tci >> PBIT_OFFSET);
+                       vlan_id_val = skb->vlan_tci & VID_MASK;
+               } else {
+                       /* VLAN tag: 3-bit UP + 1-bit CFI + 12-bit VLAN ID */
+                       vlan_id_val = *(u16 *)src_buf;
+                       vlan_id_val = htons(vlan_id_val);
+                       vlan_id_val = vlan_id_val & VID_MASK;
+                       ether_type = get_ether_type(LENGTH_VLAN_HDR - 2, src_buf);
+                       pbit_val = (*(src_buf) & 0xe0) >> 5;
+               }
+
+               /* Only use VLAN tag */
+               if (vlan_dhcp_params->up_layer_based != CL_UP_BY_L3) {
+                       user_priority = get_vlan_pbit_up(cl_hw, pbit_val, vlan_id_val, ap_idx);
+                       goto out;
+               }
+
+               if (ether_type == ETH_VLAN)
+                       src_buf += LENGTH_VLAN_HDR; /* Skip the VLAN Header.*/
+       }
+
+       ether_type = htons(*(u16 *)(src_buf - 2));
+
+       if (vlan_dhcp_params->up_layer_based != CL_UP_BY_L2) {
+               /*
+                * GET user priority by DSCP
+                * If it is an IP packet and up_layer_based == 3 (DSCP),
+                * we will check it's DSCP parameter
+                */
+               if (ether_type == ETH_P_IP || ether_type == ETH_P_IPV6) {
+                       u8 version = (*src_buf & 0xf0);
+
+                       if ((version == IP_V_IPV6 || version == IP_V_IPV4))
+                               user_priority = get_ip_user_priority(cl_hw, src_buf,
+                                                                    ether_type, ap_idx);
+               }
+       }
+
+out:
+       VLAN_DSCP_DBG("ether_type=0x%X, vlan_tci=0x%X, pbit_val=%u, vlan_id_val=%u, priority=%u\n",
+                     ether_type, skb->vlan_tci, pbit_val, vlan_id_val, user_priority);
+
+       return user_priority;
+}
+
+int cl_vlan_dscp_cli(struct cl_hw *cl_hw, struct cl_vif *cl_vif, char *data)
+{
+       u8 ap_idx = cl_vif->vif_index;
+       char *payload_start = data + 3;
+
+       if (!(payload_start && strlen(payload_start)))
+               return cl_vlan_dscp_cli_help(cl_hw);
+
+       /*
+        * workaround: delete last 'space' symbol if it is present in the payload
+        * this is caused by Celeno iw command convention - automatically added after all payload
+        */
+       if (payload_start[strlen(payload_start) - 1] == ' ')
+               payload_start[strlen(payload_start) - 1] = '\0';
+
+       if (!strncmp(data, "-a.", 3)) {
+               read_dscp_parms_from_buffer(cl_hw, payload_start, ap_idx);
+       } else if (!strncmp(data, "-b.", 3)) {
+               read_vlan_parms_from_buffer(cl_hw, payload_start, ap_idx);
+       } else if (!strncmp(data, "-c.", 3)) {
+               read_layer_based_parms_from_buffer(cl_hw, payload_start, ap_idx);
+       } else if (!strncmp(data, "-d.", 3)) {
+               read_default_vlan_up_parms_from_buffer(cl_hw, payload_start, ap_idx);
+       } else if (!strncmp(data, "-e.", 3)) {
+               if (kstrtobool(payload_start, &cl_hw->vlan_dscp.enable[ap_idx]) != 0)
+                       pr_err("invalid data - %s\n", payload_start);
+       } else if (!strncmp(data, "-v.", 3)) {
+               if (kstrtobool(payload_start, &cl_hw->vlan_dscp.debug) != 0)
+                       pr_err("invalid data - %s\n", payload_start);
+       } else if (!strncmp(data, "-s.?", 4)) {
+               return print_configuration(cl_hw, ap_idx);
+       }
+
+       pr_err("%s(): error in parameters\n", __func__);
+       return cl_vlan_dscp_cli_help(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.
________________________________


^ permalink raw reply related	[flat|nested] 262+ messages in thread

* [RFC v1 082/256] cl8k: add ext/vlan_dscp.h
  2021-06-17 15:58 [RFC v1 000/256] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (80 preceding siblings ...)
  2021-06-17 15:59 ` [RFC v1 081/256] cl8k: add ext/vlan_dscp.c viktor.barna
@ 2021-06-17 15:59 ` viktor.barna
  2021-06-17 15:59 ` [RFC v1 083/256] cl8k: add fem.c viktor.barna
                   ` (175 subsequent siblings)
  257 siblings, 0 replies; 262+ messages in thread
From: viktor.barna @ 2021-06-17 15:59 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Oleksandr Savchenko, Shay Bar, Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

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

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 .../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.
________________________________


^ permalink raw reply related	[flat|nested] 262+ messages in thread

* [RFC v1 083/256] cl8k: add fem.c
  2021-06-17 15:58 [RFC v1 000/256] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (81 preceding siblings ...)
  2021-06-17 15:59 ` [RFC v1 082/256] cl8k: add ext/vlan_dscp.h viktor.barna
@ 2021-06-17 15:59 ` viktor.barna
  2021-06-17 15:59 ` [RFC v1 084/256] cl8k: add fem.h viktor.barna
                   ` (174 subsequent siblings)
  257 siblings, 0 replies; 262+ messages in thread
From: viktor.barna @ 2021-06-17 15:59 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Oleksandr Savchenko, Shay Bar, Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

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

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 drivers/net/wireless/celeno/cl8k/fem.c | 1271 ++++++++++++++++++++++++
 1 file changed, 1271 insertions(+)
 create mode 100644 drivers/net/wireless/celeno/cl8k/fem.c

diff --git a/drivers/net/wireless/celeno/cl8k/fem.c b/drivers/net/wireless/celeno/cl8k/fem.c
new file mode 100644
index 000000000000..4786106b63aa
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/fem.c
@@ -0,0 +1,1271 @@
+// SPDX-License-Identifier: MIT
+/* Copyright(c) 2019-2021, Celeno Communications Ltd. */
+
+#include "chip.h"
+#include "fem.h"
+#include "reg/reg_fem.h"
+#include "fem_common.h"
+#include "e2p.h"
+#include "reg/reg_ricu.h"
+#include "reg/reg_riu_rc.h"
+#include "agc_params.h"
+
+static const struct cl_fem_lna_enable_gpio lna_enable_gpio[FEM_WIRING_MAX] = {
+       [FEM_WIRING_0_TCV0_6_TCV1_6]           = { .val = 0b000000000000 },
+       [FEM_WIRING_1_TCV0_6_TCV1_6]           = { .val = 0b000000000000 },
+       [FEM_WIRING_2_TCV0_6_TCV1_6]           = { .val = 0b000000000000 },
+       [FEM_WIRING_3_TCV0_2_ELASTIC_4_TCV1_2] = { .val = 0b001100110000 },
+       [FEM_WIRING_4_TCV0_2_ELASTIC_4_TCV1_2] = { .val = 0b001100110000 },
+       [FEM_WIRING_5_TCV0_2_ELASTIC_4_TCV1_2] = { .val = 0b001100110000 },
+       [FEM_WIRING_6_TCV0_2_ELASTIC_4_TCV1_2] = { .val = 0b001100110000 },
+       [FEM_WIRING_7_TCV0_4_TCV1_4]           = { .val = 0b000000111010 },
+       [FEM_WIRING_8_TCV0_4_TCV1_4]           = { .val = 0b000000111010 },
+       [FEM_WIRING_9_TCV0_4_TCV1_4]           = { .val = 0b111100000000 },
+       [FEM_WIRING_10_TCV0_4_TCV1_4]          = { .val = 0b111100000000 },
+       [FEM_WIRING_11_TCV0_4_TCV1_4_RX_ONLY]  = { .val = 0b111100000000 },
+       [FEM_WIRING_12_TCV0_4_TCV1_4_RX_ONLY]  = { .val = 0b111100000000 },
+       [FEM_WIRING_13_SENSING_4RX_2TX]        = { .val = 0b001111110000 },
+       [FEM_WIRING_14_SENSING_4TX_2RX]        = { .val = 0b111100110000 },
+       [FEM_WIRING_15_CHAMELEON_4TX_4RX]      = { .val = 0b001100001010 },
+       [FEM_WIRING_16_TCV0_2_TCV1_2]          = { .val = 0b100110111110 },
+       [FEM_WIRING_17_TCV0_4_TCV1_0]          = { .val = 0b111111110000 },
+       [FEM_WIRING_18_TCV0_4_TCV1_4]          = { .val = 0b000000111010 },
+       [FEM_WIRING_19_TCV0_2_TCV1_2_SWAPPED]  = { .val = 0b000011111111 },
+       [FEM_WIRING_20_TCV0_4_TCV1_2]          = { .val = 0b000011111010 },
+       [FEM_WIRING_21_TCV0_4_TCV1_2]          = { .val = 0b111111000000 },
+};
+
+static const struct cl_fem_pa_enable_gpio pa_enable_gpio[FEM_WIRING_MAX] = {
+       [FEM_WIRING_0_TCV0_6_TCV1_6]           = { .val = 0b000000000000 },
+       [FEM_WIRING_1_TCV0_6_TCV1_6]           = { .val = 0b000000000000 },
+       [FEM_WIRING_2_TCV0_6_TCV1_6]           = { .val = 0b000000000000 },
+       [FEM_WIRING_3_TCV0_2_ELASTIC_4_TCV1_2] = { .val = 0b000000000000 },
+       [FEM_WIRING_4_TCV0_2_ELASTIC_4_TCV1_2] = { .val = 0b000000000000 },
+       [FEM_WIRING_5_TCV0_2_ELASTIC_4_TCV1_2] = { .val = 0b000000000000 },
+       [FEM_WIRING_6_TCV0_2_ELASTIC_4_TCV1_2] = { .val = 0b000000000000 },
+       [FEM_WIRING_7_TCV0_4_TCV1_4]           = { .val = 0b000000111010 },
+       [FEM_WIRING_8_TCV0_4_TCV1_4]           = { .val = 0b000000111010 },
+       [FEM_WIRING_9_TCV0_4_TCV1_4]           = { .val = 0b111100000000 },
+       [FEM_WIRING_10_TCV0_4_TCV1_4]          = { .val = 0b111100000000 },
+       [FEM_WIRING_11_TCV0_4_TCV1_4_RX_ONLY]  = { .val = 0b111111110000 },
+       [FEM_WIRING_12_TCV0_4_TCV1_4_RX_ONLY]  = { .val = 0b111111110000 },
+       [FEM_WIRING_13_SENSING_4RX_2TX]        = { .val = 0b001111110000 },
+       [FEM_WIRING_14_SENSING_4TX_2RX]        = { .val = 0b001111111010 },
+       [FEM_WIRING_15_CHAMELEON_4TX_4RX]      = { .val = 0b001111111010 },
+       [FEM_WIRING_16_TCV0_2_TCV1_2]          = { .val = 0b100110111110 },
+       [FEM_WIRING_17_TCV0_4_TCV1_0]          = { .val = 0b111111110000 },
+       [FEM_WIRING_18_TCV0_4_TCV1_4]          = { .val = 0b000000111010 },
+       [FEM_WIRING_19_TCV0_2_TCV1_2_SWAPPED]  = { .val = 0b000011111111 },
+       [FEM_WIRING_20_TCV0_4_TCV1_2]          = { .val = 0b000011111010 },
+       [FEM_WIRING_21_TCV0_4_TCV1_2]          = { .val = 0b111111110000 },
+};
+
+static const struct cl_fem_rx_active_gpio rx_active_gpio[FEM_WIRING_MAX] = {
+       [FEM_WIRING_0_TCV0_6_TCV1_6]           = { .val = 0b11000000 },
+       [FEM_WIRING_1_TCV0_6_TCV1_6]           = { .val = 0b11111111 },
+       [FEM_WIRING_2_TCV0_6_TCV1_6]           = { .val = 0b00000000 }, /* N/A */
+       [FEM_WIRING_3_TCV0_2_ELASTIC_4_TCV1_2] = { .val = 0b11111100 },
+       [FEM_WIRING_4_TCV0_2_ELASTIC_4_TCV1_2] = { .val = 0b11111111 },
+       [FEM_WIRING_5_TCV0_2_ELASTIC_4_TCV1_2] = { .val = 0b00000000 }, /* N/A */
+       [FEM_WIRING_6_TCV0_2_ELASTIC_4_TCV1_2] = { .val = 0b00000000 }, /* N/A */
+       [FEM_WIRING_7_TCV0_4_TCV1_4]           = { .val = 0b11110000 },
+       [FEM_WIRING_8_TCV0_4_TCV1_4]           = { .val = 0b00000000 }, /* N/A */
+       [FEM_WIRING_9_TCV0_4_TCV1_4]           = { .val = 0b11111111 },
+       [FEM_WIRING_10_TCV0_4_TCV1_4]          = { .val = 0b00000000 },
+       [FEM_WIRING_11_TCV0_4_TCV1_4_RX_ONLY]  = { .val = 0b11110000 },
+       [FEM_WIRING_12_TCV0_4_TCV1_4_RX_ONLY]  = { .val = 0b11111111 },
+       [FEM_WIRING_13_SENSING_4RX_2TX]        = { .val = 0b11000000 },
+       [FEM_WIRING_14_SENSING_4TX_2RX]        = { .val = 0b11110000 },
+       [FEM_WIRING_15_CHAMELEON_4TX_4RX]      = { .val = 0b11110000 },
+       [FEM_WIRING_16_TCV0_2_TCV1_2]          = { .val = 0b11111001 },
+       [FEM_WIRING_17_TCV0_4_TCV1_0]          = { .val = 0b11111111 },
+       [FEM_WIRING_18_TCV0_4_TCV1_4]          = { .val = 0b00000000 },
+       [FEM_WIRING_19_TCV0_2_TCV1_2_SWAPPED]  = { .val = 0b11001111 },
+       [FEM_WIRING_20_TCV0_4_TCV1_2]          = { .val = 0b11110000 },
+       [FEM_WIRING_21_TCV0_4_TCV1_2]          = { .val = 0b11111111 },
+};
+
+static const u32 ricu_fem_conf[FEM_WIRING_MAX][TCV_MAX] = {
+       [FEM_WIRING_0_TCV0_6_TCV1_6]           = { 0x00AB3021, 0x0054CD89},
+       [FEM_WIRING_1_TCV0_6_TCV1_6]           = { 0x00AB3021, 0x0054CD89},
+       [FEM_WIRING_2_TCV0_6_TCV1_6]           = { 0x00AB3021, 0x0054CD89},
+       [FEM_WIRING_3_TCV0_2_ELASTIC_4_TCV1_2] = { 0x00003021, 0x00AB0089},
+       [FEM_WIRING_4_TCV0_2_ELASTIC_4_TCV1_2] = { 0x00003021, 0x00AB0089},
+       [FEM_WIRING_5_TCV0_2_ELASTIC_4_TCV1_2] = { 0x00003021, 0x00AB0089},
+       [FEM_WIRING_6_TCV0_2_ELASTIC_4_TCV1_2] = { 0x00003021, 0x00AB0089},
+       [FEM_WIRING_7_TCV0_4_TCV1_4]           = { 0x00000001, 0x0032AB89},
+       [FEM_WIRING_8_TCV0_4_TCV1_4]           = { 0x00000001, 0x0032AB89},
+       [FEM_WIRING_9_TCV0_4_TCV1_4]           = { 0x00AB3210, 0x00000089},
+       [FEM_WIRING_10_TCV0_4_TCV1_4]          = { 0x00AB3210, 0x00000089},
+       [FEM_WIRING_11_TCV0_4_TCV1_4_RX_ONLY]  = { 0x00AB3210, 0x00000089},
+       [FEM_WIRING_12_TCV0_4_TCV1_4_RX_ONLY]  = { 0x00AB3210, 0x00000089},
+       [FEM_WIRING_13_SENSING_4RX_2TX]        = { 0x00003021, 0x00890000},
+       [FEM_WIRING_14_SENSING_4TX_2RX]        = { 0x00003021, 0x00000089},
+       [FEM_WIRING_15_CHAMELEON_4TX_4RX]      = { 0x00AB0001, 0x00320089},
+       [FEM_WIRING_16_TCV0_2_TCV1_2]          = { 0x00000001, 0x0000B00A},
+       [FEM_WIRING_17_TCV0_4_TCV1_0]          = { 0x00AB3210, 0x00000089},
+       [FEM_WIRING_18_TCV0_4_TCV1_4]          = { 0x00000001, 0x0032AB89},
+       [FEM_WIRING_19_TCV0_2_TCV1_2_SWAPPED]  = { 0x00000000, 0x00AB3289},
+       [FEM_WIRING_20_TCV0_4_TCV1_2]          = { 0x00000001, 0x0032AB00},
+       [FEM_WIRING_21_TCV0_4_TCV1_2]          = { 0x00AB3210, 0x00000089},
+};
+
+static const u8 fem_full_list[FEM_WIRING_MAX][TCV_MAX][FEM_LUT_AMOUNT_PER_MAC] = {
+       [FEM_WIRING_0_TCV0_6_TCV1_6] = {
+               {FEM_TYPE_TCV0, FEM_TYPE_TCV0, FEM_TYPE_TCV0,
+                       FEM_TYPE_TCV0, FEM_TYPE_TCV0, FEM_TYPE_TCV0},
+               {FEM_TYPE_TCV1, FEM_TYPE_TCV1, FEM_TYPE_TCV1,
+                       FEM_TYPE_TCV1, FEM_TYPE_TCV1, FEM_TYPE_TCV1},
+       },
+       [FEM_WIRING_1_TCV0_6_TCV1_6] = {
+               {FEM_TYPE_TCV0, FEM_TYPE_TCV0, FEM_TYPE_TCV0,
+                       FEM_TYPE_TCV0, FEM_TYPE_TCV0, FEM_TYPE_TCV0},
+               {FEM_TYPE_TCV1, FEM_TYPE_TCV1, FEM_TYPE_TCV1,
+                       FEM_TYPE_TCV1, FEM_TYPE_TCV1, FEM_TYPE_TCV1},
+       },
+       [FEM_WIRING_2_TCV0_6_TCV1_6] = {
+               {FEM_TYPE_TCV0, FEM_TYPE_TCV0, FEM_TYPE_TCV0,
+                       FEM_TYPE_TCV0, FEM_TYPE_TCV0, FEM_TYPE_TCV0},
+               {FEM_TYPE_TCV1, FEM_TYPE_TCV1, FEM_TYPE_TCV1,
+                       FEM_TYPE_TCV1, FEM_TYPE_TCV1, FEM_TYPE_TCV1},
+       },
+       [FEM_WIRING_3_TCV0_2_ELASTIC_4_TCV1_2] = {
+               {FEM_TYPE_TCV0, FEM_TYPE_TCV0, FEM_TYPE_ELASTIC,
+                       FEM_TYPE_ELASTIC, FEM_TYPE_ELASTIC, FEM_TYPE_ELASTIC},
+               {FEM_TYPE_TCV1, FEM_TYPE_TCV1, FEM_TYPE_ELASTIC,
+                       FEM_TYPE_ELASTIC, FEM_TYPE_ELASTIC, FEM_TYPE_ELASTIC},
+       },
+       [FEM_WIRING_4_TCV0_2_ELASTIC_4_TCV1_2] = {
+               {FEM_TYPE_TCV0, FEM_TYPE_TCV0, FEM_TYPE_ELASTIC,
+                       FEM_TYPE_ELASTIC, FEM_TYPE_ELASTIC, FEM_TYPE_ELASTIC},
+               {FEM_TYPE_TCV1, FEM_TYPE_TCV1, FEM_TYPE_ELASTIC,
+                       FEM_TYPE_ELASTIC, FEM_TYPE_ELASTIC, FEM_TYPE_ELASTIC},
+       },
+       [FEM_WIRING_5_TCV0_2_ELASTIC_4_TCV1_2] = {
+               {FEM_TYPE_TCV0, FEM_TYPE_TCV0, FEM_TYPE_ELASTIC,
+                       FEM_TYPE_ELASTIC, FEM_TYPE_ELASTIC, FEM_TYPE_ELASTIC},
+               {FEM_TYPE_TCV1, FEM_TYPE_TCV1, FEM_TYPE_ELASTIC,
+                       FEM_TYPE_ELASTIC, FEM_TYPE_ELASTIC, FEM_TYPE_ELASTIC},
+       },
+       [FEM_WIRING_6_TCV0_2_ELASTIC_4_TCV1_2] = {
+               {FEM_TYPE_TCV0, FEM_TYPE_TCV0, FEM_TYPE_ELASTIC,
+                       FEM_TYPE_ELASTIC, FEM_TYPE_ELASTIC, FEM_TYPE_ELASTIC},
+               {FEM_TYPE_TCV1, FEM_TYPE_TCV1, FEM_TYPE_ELASTIC,
+                       FEM_TYPE_ELASTIC, FEM_TYPE_ELASTIC, FEM_TYPE_ELASTIC},
+       },
+       [FEM_WIRING_7_TCV0_4_TCV1_4] = {
+               {FEM_TYPE_TCV0, FEM_TYPE_TCV0, FEM_TYPE_TCV0,
+                       FEM_TYPE_TCV0, FEM_LUT_EMPTY, FEM_LUT_EMPTY},
+               {FEM_TYPE_TCV1, FEM_TYPE_TCV1, FEM_TYPE_TCV1,
+                       FEM_TYPE_TCV1, FEM_LUT_EMPTY, FEM_LUT_EMPTY},
+       },
+       [FEM_WIRING_8_TCV0_4_TCV1_4] = {
+               {FEM_TYPE_TCV0, FEM_TYPE_TCV0, FEM_TYPE_TCV0,
+                       FEM_TYPE_TCV0, FEM_LUT_EMPTY, FEM_LUT_EMPTY},
+               {FEM_TYPE_TCV1, FEM_TYPE_TCV1, FEM_TYPE_TCV1,
+                       FEM_TYPE_TCV1, FEM_LUT_EMPTY, FEM_LUT_EMPTY},
+       },
+       [FEM_WIRING_9_TCV0_4_TCV1_4] = {
+               {FEM_TYPE_TCV0, FEM_TYPE_TCV0, FEM_TYPE_TCV0,
+                       FEM_TYPE_TCV0, FEM_LUT_EMPTY, FEM_LUT_EMPTY},
+               {FEM_TYPE_TCV1, FEM_TYPE_TCV1, FEM_TYPE_TCV1,
+                       FEM_TYPE_TCV1, FEM_LUT_EMPTY, FEM_LUT_EMPTY},
+       },
+       [FEM_WIRING_10_TCV0_4_TCV1_4] = {
+               {FEM_TYPE_TCV0, FEM_TYPE_TCV0, FEM_TYPE_TCV0,
+                       FEM_TYPE_TCV0, FEM_LUT_EMPTY, FEM_LUT_EMPTY},
+               {FEM_TYPE_TCV1, FEM_TYPE_TCV1, FEM_TYPE_TCV1,
+                       FEM_TYPE_TCV1, FEM_LUT_EMPTY, FEM_LUT_EMPTY},
+       },
+       [FEM_WIRING_11_TCV0_4_TCV1_4_RX_ONLY] = {
+               {FEM_TYPE_TCV0, FEM_TYPE_TCV0, FEM_TYPE_TCV0,
+                       FEM_TYPE_TCV0, FEM_LUT_EMPTY, FEM_LUT_EMPTY},
+               {FEM_TYPE_SENSING, FEM_TYPE_SENSING, FEM_TYPE_SENSING,
+                       FEM_TYPE_SENSING, FEM_LUT_EMPTY, FEM_LUT_EMPTY},
+       },
+       [FEM_WIRING_12_TCV0_4_TCV1_4_RX_ONLY] = {
+               {FEM_TYPE_TCV0, FEM_TYPE_TCV0, FEM_TYPE_TCV0,
+                       FEM_TYPE_TCV0, FEM_LUT_EMPTY, FEM_LUT_EMPTY},
+               {FEM_TYPE_SENSING, FEM_TYPE_SENSING, FEM_TYPE_SENSING,
+                       FEM_TYPE_SENSING, FEM_LUT_EMPTY, FEM_LUT_EMPTY},
+       },
+       [FEM_WIRING_13_SENSING_4RX_2TX] = {
+               {FEM_TYPE_SENSING, FEM_TYPE_SENSING, FEM_TYPE_SENSING,
+                       FEM_TYPE_SENSING, FEM_LUT_EMPTY, FEM_LUT_EMPTY},
+               {FEM_TYPE_TCV1, FEM_TYPE_TCV1, FEM_LUT_EMPTY,
+                       FEM_LUT_EMPTY, FEM_LUT_EMPTY, FEM_LUT_EMPTY},
+       },
+       [FEM_WIRING_14_SENSING_4TX_2RX] = {
+               {FEM_TYPE_TCV0, FEM_TYPE_TCV0, FEM_TYPE_TCV0,
+                       FEM_TYPE_TCV0, FEM_LUT_EMPTY, FEM_LUT_EMPTY},
+               {FEM_TYPE_SENSING, FEM_TYPE_SENSING, FEM_LUT_EMPTY,
+                       FEM_LUT_EMPTY, FEM_LUT_EMPTY, FEM_LUT_EMPTY},
+       },
+       [FEM_WIRING_15_CHAMELEON_4TX_4RX] = {
+               {FEM_TYPE_TCV0, FEM_TYPE_TCV0, FEM_TYPE_TCV0,
+                       FEM_TYPE_TCV0, FEM_LUT_EMPTY, FEM_LUT_EMPTY},
+               {FEM_TYPE_SENSING, FEM_TYPE_SENSING, FEM_TYPE_SENSING,
+                       FEM_TYPE_SENSING, FEM_LUT_EMPTY, FEM_LUT_EMPTY},
+       },
+       [FEM_WIRING_16_TCV0_2_TCV1_2] = {
+               {FEM_TYPE_TCV0, FEM_TYPE_TCV0, FEM_LUT_EMPTY,
+                       FEM_LUT_EMPTY, FEM_LUT_EMPTY, FEM_LUT_EMPTY},
+               {FEM_LUT_EMPTY, FEM_LUT_EMPTY, FEM_TYPE_TCV1,
+                       FEM_TYPE_TCV1, FEM_LUT_EMPTY, FEM_LUT_EMPTY},
+       },
+       [FEM_WIRING_17_TCV0_4_TCV1_0] = {
+               {FEM_TYPE_TCV0, FEM_TYPE_TCV0, FEM_TYPE_TCV0,
+                       FEM_TYPE_TCV0, FEM_LUT_EMPTY, FEM_LUT_EMPTY},
+               {FEM_LUT_EMPTY, FEM_LUT_EMPTY, FEM_LUT_EMPTY,
+                       FEM_LUT_EMPTY, FEM_LUT_EMPTY, FEM_LUT_EMPTY},
+       },
+       [FEM_WIRING_18_TCV0_4_TCV1_4] = {
+               {FEM_TYPE_TCV0, FEM_TYPE_TCV0, FEM_TYPE_TCV0,
+                       FEM_TYPE_TCV0, FEM_LUT_EMPTY, FEM_LUT_EMPTY},
+               {FEM_TYPE_TCV1, FEM_TYPE_TCV1, FEM_TYPE_TCV1,
+                       FEM_TYPE_TCV1, FEM_LUT_EMPTY, FEM_LUT_EMPTY},
+       },
+       [FEM_WIRING_19_TCV0_2_TCV1_2_SWAPPED] = {
+               {FEM_LUT_EMPTY, FEM_LUT_EMPTY, FEM_TYPE_TCV0,
+                       FEM_TYPE_TCV0, FEM_LUT_EMPTY, FEM_LUT_EMPTY},
+               {FEM_LUT_EMPTY, FEM_LUT_EMPTY, FEM_TYPE_TCV1,
+                       FEM_TYPE_TCV1, FEM_LUT_EMPTY, FEM_LUT_EMPTY},
+       },
+       [FEM_WIRING_20_TCV0_4_TCV1_2] = {
+               {FEM_TYPE_TCV0, FEM_TYPE_TCV0, FEM_TYPE_TCV0,
+                       FEM_TYPE_TCV0, FEM_LUT_EMPTY, FEM_LUT_EMPTY},
+               {FEM_LUT_EMPTY, FEM_LUT_EMPTY, FEM_TYPE_TCV1,
+                       FEM_TYPE_TCV1, FEM_LUT_EMPTY, FEM_LUT_EMPTY},
+       },
+       [FEM_WIRING_21_TCV0_4_TCV1_2] = {
+               {FEM_TYPE_TCV0, FEM_TYPE_TCV0, FEM_TYPE_TCV0,
+                       FEM_TYPE_TCV0, FEM_LUT_EMPTY, FEM_LUT_EMPTY},
+               {FEM_LUT_EMPTY, FEM_LUT_EMPTY, FEM_TYPE_SENSING,
+                       FEM_TYPE_SENSING, FEM_LUT_EMPTY, FEM_LUT_EMPTY},
+       }
+};
+
+static u16 cl_fem_reg_manual(struct cl_hw *cl_hw, u16 val, u8 ant_idx)
+{
+       u8 shift = 0;
+       u16 lut, lut0, lut1, lut2;
+
+       if (cl_hw->fem_ant != ant_idx && cl_hw->fem_ant != U8_MAX)
+               shift = 0; /* In case manual fem setting was chosen */
+       else
+               shift = cl_hw->fem_system_mode * 4;
+
+       lut = (val >> shift) & RIU_RC_RF_LNA_LUT_RFLNALUT_0_MASK;
+       lut0 = ((lut << RIU_RC_RF_LNA_LUT_RFLNALUT_0_LSB) & (u16)RIU_RC_RF_LNA_LUT_RFLNALUT_0_MASK);
+       lut1 = ((lut << RIU_RC_RF_LNA_LUT_RFLNALUT_1_LSB) & (u16)RIU_RC_RF_LNA_LUT_RFLNALUT_1_MASK);
+       lut2 = ((lut << RIU_RC_RF_LNA_LUT_RFLNALUT_2_LSB) & (u16)RIU_RC_RF_LNA_LUT_RFLNALUT_2_MASK);
+
+       return (lut0 | lut1 | lut2);
+}
+
+int cl_fem_get_registers(struct cl_hw *cl_hw, u32 fem_reg[FEM_REGISTERS_AMOUNT])
+{
+       u8 i;
+       u8 reg_idx;
+       u8 shift;
+       u8 tcv_idx = cl_hw->tcv_idx;
+       u16 reg_val;
+       struct cl_fem_params *fem = &cl_hw->chip->fem;
+
+       /* In case there's no valid wiring_id, keep the fem lut registers empty. */
+       if (fem->wiring_id >= FEM_WIRING_MAX)
+               return 0;
+
+       for (i = 0; i < MAX_ANTENNAS; i++) {
+               reg_idx = i >> 1; /* 0 - 2 */
+               shift = (i & 0x1) ? 16 : 0; /* even - 0. odd  - 16 */
+
+               if (i < cl_hw->num_antennas) {
+                       if (cl_hw->fem_system_mode == FEM_MODE_OPERETIONAL) {
+                               reg_val = fem->lut_registers[tcv_idx][i];
+                       } else {
+                               u16 fem_val = fem->lut_registers[tcv_idx][i];
+
+                               reg_val = cl_fem_reg_manual(cl_hw, fem_val, i);
+                       }
+               } else {
+                       reg_val = fem->lut_off_register[tcv_idx];
+               }
+
+               fem_reg[reg_idx] |= ((u32)reg_val << shift);
+       }
+
+       for (i = 0; i < FEM_REGISTERS_AMOUNT; i++)
+               cl_dbg_trace(cl_hw, "RC_RFLNALUT_%u: [0x%08X]\n", i, fem_reg[i]);
+
+       return 0;
+}
+
+static int cl_fem_read_lut(struct cl_chip *chip)
+{
+       int i;
+       int has_valid_fem_lut = 0;
+       struct cl_fem_params *fem = &chip->fem;
+
+       /* Read FEM LUT from eeprom */
+       if (cl_e2p_read(chip, (u8 *)&fem->lut, SIZE_FEM_LUT, ADDR_FEM_LUT))
+               return -1;
+
+       for (i = 0; i < FEM_TYPE_MAX; i++) {
+               if (fem->lut[i] == U16_MAX)
+                       continue;
+
+               /* Mark as valid if at least one the FEM LUTs has a valid value. */
+               has_valid_fem_lut = 1;
+               fem->lut_off_register_list[i] = EXTRACT_OFF_LUT(fem->lut[i]);
+               fem->lut[i] &= FEM_LUT_MASK;
+               cl_dbg_chip_trace(chip, "lut[%d] = 0x%X, lut_off_register_list[%d] = 0x%X\n",
+                                 i, fem->lut[i], i, fem->lut_off_register_list[i]);
+       }
+
+       return !has_valid_fem_lut;
+}
+
+#define FEM_LUT_OFFSET_BYPASS 0
+#define FEM_LUT_OFFSET_TX     4
+#define FEM_LUT_OFFSET_RX     8
+#define FEM_LUT_OFFSET_OFF    12
+#define FEM_LUT_VAL_MASK      0x7
+
+static int _cl_fem_check_lut_validity(struct cl_chip *chip, enum fem_type type)
+{
+       u16 fem_lut = chip->fem.lut[type];
+       u16 bypass = (fem_lut >> FEM_LUT_OFFSET_BYPASS) & FEM_LUT_VAL_MASK;
+       u16 tx = (fem_lut >> FEM_LUT_OFFSET_TX) & FEM_LUT_VAL_MASK;
+       u16 rx = (fem_lut >> FEM_LUT_OFFSET_RX) & FEM_LUT_VAL_MASK;
+       u16 off = (fem_lut >> FEM_LUT_OFFSET_OFF) & FEM_LUT_VAL_MASK;
+       int ret = 0;
+
+       if (fem_lut == U16_MAX) {
+               cl_dbg_chip_err(chip, "Wiring_id [%u] must have valid FEM LUTs for %s\n",
+                               chip->fem.wiring_id, FEM_TYPE_STR(type));
+               return -1;
+       }
+
+       // Skip uniqueness check for sensing type
+       if (type == FEM_TYPE_SENSING)
+               return 0;
+
+       // Check uniqueness of BYPASS/TX/RX/OFF
+       if (bypass == tx) {
+               cl_dbg_chip_err(chip, "Error: bypass (%u) and tx (%u) values are equal\n",
+                               bypass, tx);
+               ret = -EIO;
+       }
+
+       if (bypass == rx) {
+               cl_dbg_chip_err(chip, "Error: bypass (%u) and rx (%u) values are equal\n",
+                               bypass, rx);
+               ret = -EIO;
+       }
+
+       if (tx == rx) {
+               cl_dbg_chip_err(chip, "Error: tx (%u) and rx (%u) values are equal\n",
+                               tx, rx);
+               ret = -EIO;
+       }
+
+       if (tx == off) {
+               cl_dbg_chip_err(chip, "Error: tx (%u) and off (%u) values are equal\n",
+                               tx, off);
+               ret = -EIO;
+       }
+
+       if (rx == off) {
+               cl_dbg_chip_err(chip, "Error: rx (%u) and off (%u) values are equal\n",
+                               rx, off);
+               ret = -EIO;
+       }
+
+       return ret;
+}
+
+static int cl_fem_check_lut_validity(struct cl_chip *chip, u8 wiring_id)
+{
+       if (cl_fem_read_lut(chip)) {
+               cl_dbg_chip_err(chip, "None of the FEM LUTs is valid. Aborting.\n");
+               return -1;
+       }
+
+       switch (wiring_id) {
+       case FEM_WIRING_0_TCV0_6_TCV1_6:
+       case FEM_WIRING_1_TCV0_6_TCV1_6:
+       /* case FEM_WIRING_2_TCV0_6_TCV1_6: */
+       case FEM_WIRING_7_TCV0_4_TCV1_4:
+       /* case FEM_WIRING_8_TCV0_4_TCV1_4: */
+       case FEM_WIRING_9_TCV0_4_TCV1_4:
+       case FEM_WIRING_10_TCV0_4_TCV1_4:
+       case FEM_WIRING_16_TCV0_2_TCV1_2:
+       case FEM_WIRING_18_TCV0_4_TCV1_4:
+       case FEM_WIRING_19_TCV0_2_TCV1_2_SWAPPED:
+       case FEM_WIRING_20_TCV0_4_TCV1_2:
+               if (_cl_fem_check_lut_validity(chip, FEM_TYPE_TCV0) ||
+                   _cl_fem_check_lut_validity(chip, FEM_TYPE_TCV1))
+                       return -1;
+               break;
+
+       case FEM_WIRING_17_TCV0_4_TCV1_0:
+               if (_cl_fem_check_lut_validity(chip, FEM_TYPE_TCV0))
+                       return -1;
+               break;
+
+       case FEM_WIRING_3_TCV0_2_ELASTIC_4_TCV1_2:
+       case FEM_WIRING_4_TCV0_2_ELASTIC_4_TCV1_2:
+       /* case FEM_WIRING_5_TCV0_2_ELASTIC_4_TCV1_2: */
+       /* case FEM_WIRING_6_TCV0_2_ELASTIC_4_TCV1_2: */
+               if (_cl_fem_check_lut_validity(chip, FEM_TYPE_TCV0) ||
+                   _cl_fem_check_lut_validity(chip, FEM_TYPE_TCV1) ||
+                   _cl_fem_check_lut_validity(chip, FEM_TYPE_ELASTIC))
+                       return -1;
+               break;
+
+       case FEM_WIRING_11_TCV0_4_TCV1_4_RX_ONLY:
+       case FEM_WIRING_12_TCV0_4_TCV1_4_RX_ONLY:
+       case FEM_WIRING_14_SENSING_4TX_2RX:
+       case FEM_WIRING_15_CHAMELEON_4TX_4RX:
+       case FEM_WIRING_21_TCV0_4_TCV1_2:
+               if (_cl_fem_check_lut_validity(chip, FEM_TYPE_TCV0) ||
+                   _cl_fem_check_lut_validity(chip, FEM_TYPE_SENSING))
+                       return -1;
+               break;
+
+       case FEM_WIRING_13_SENSING_4RX_2TX:
+               if (_cl_fem_check_lut_validity(chip, FEM_TYPE_TCV1) ||
+                   _cl_fem_check_lut_validity(chip, FEM_TYPE_SENSING))
+                       return -1;
+               break;
+
+       case FEM_WIRING_2_TCV0_6_TCV1_6:
+       case FEM_WIRING_5_TCV0_2_ELASTIC_4_TCV1_2:
+       case FEM_WIRING_6_TCV0_2_ELASTIC_4_TCV1_2:
+       case FEM_WIRING_8_TCV0_4_TCV1_4:
+               cl_dbg_chip_err(chip, "wiring_id %u is not supported\n", wiring_id);
+               return -1;
+
+       default:
+               cl_dbg_chip_err(chip, "Wiring_id [%u] is not valid [0..%u]\n",
+                               wiring_id, FEM_WIRING_MAX - 1);
+               return -1;
+       }
+
+       return 0;
+}
+
+static int cl_fem_validate_wiring_id(struct cl_chip *chip, u8 wiring_id)
+{
+       switch (wiring_id) {
+       case FEM_WIRING_0_TCV0_6_TCV1_6:
+       case FEM_WIRING_1_TCV0_6_TCV1_6:
+       case FEM_WIRING_2_TCV0_6_TCV1_6:
+       case FEM_WIRING_3_TCV0_2_ELASTIC_4_TCV1_2:
+       case FEM_WIRING_4_TCV0_2_ELASTIC_4_TCV1_2:
+       case FEM_WIRING_5_TCV0_2_ELASTIC_4_TCV1_2:
+       case FEM_WIRING_6_TCV0_2_ELASTIC_4_TCV1_2:
+       case FEM_WIRING_7_TCV0_4_TCV1_4:
+       case FEM_WIRING_8_TCV0_4_TCV1_4:
+       case FEM_WIRING_9_TCV0_4_TCV1_4:
+       case FEM_WIRING_10_TCV0_4_TCV1_4:
+       case FEM_WIRING_11_TCV0_4_TCV1_4_RX_ONLY:
+       case FEM_WIRING_12_TCV0_4_TCV1_4_RX_ONLY:
+       case FEM_WIRING_13_SENSING_4RX_2TX:
+       case FEM_WIRING_14_SENSING_4TX_2RX:
+       case FEM_WIRING_15_CHAMELEON_4TX_4RX:
+       case FEM_WIRING_18_TCV0_4_TCV1_4:
+       case FEM_WIRING_19_TCV0_2_TCV1_2_SWAPPED:
+               return cl_chip_is_8ant(chip) ? 0 : -1;
+       case FEM_WIRING_20_TCV0_4_TCV1_2:
+       case FEM_WIRING_21_TCV0_4_TCV1_2:
+               return cl_chip_is_6ant(chip) ? 0 : -1;
+       case FEM_WIRING_16_TCV0_2_TCV1_2:
+       case FEM_WIRING_17_TCV0_4_TCV1_0:
+               return cl_chip_is_4ant(chip) ? 0 : -1;
+       default:
+               cl_dbg_chip_err(chip, "wiring_id %u is not valid. [0..%u] are valid values\n",
+                               wiring_id, (FEM_WIRING_MAX - 1));
+               return -1;
+       }
+
+       return -1;
+}
+
+int cl_fem_read_wiring_id(struct cl_chip *chip)
+{
+       struct cl_fem_params *fem = &chip->fem;
+
+       /* In case there's a valid wiring id in chip, no need to re-read it from EEPROM */
+       if (fem->wiring_id < FEM_WIRING_MAX)
+               return 0;
+
+       /* Read wiring_id from eeprom */
+       if (cl_e2p_read(chip, &fem->wiring_id, SIZE_FEM_WIRING_ID, ADDR_FEM_WIRING_ID))
+               return -1;
+
+       return cl_fem_validate_wiring_id(chip, fem->wiring_id);
+}
+
+static void cl_fem_set_registers(struct cl_chip *chip)
+{
+       struct cl_fem_params *fem = &chip->fem;
+       int i;
+       u8 wiring_id = fem->wiring_id;
+
+       for (i = 0; i < FEM_LUT_AMOUNT_PER_MAC; i++) {
+               fem->lut_registers[TCV0][i] = fem->lut[fem_full_list[wiring_id][TCV0][i]];
+               fem->lut_registers[TCV1][i] = fem->lut[fem_full_list[wiring_id][TCV1][i]];
+       }
+}
+
+static int cl_fem_set_lut_off(struct cl_chip *chip)
+{
+       struct cl_fem_params *fem = &chip->fem;
+
+       switch (fem->wiring_id) {
+       case FEM_WIRING_0_TCV0_6_TCV1_6:
+       case FEM_WIRING_1_TCV0_6_TCV1_6:
+       case FEM_WIRING_2_TCV0_6_TCV1_6:
+       case FEM_WIRING_7_TCV0_4_TCV1_4:
+       case FEM_WIRING_8_TCV0_4_TCV1_4:
+       case FEM_WIRING_9_TCV0_4_TCV1_4:
+       case FEM_WIRING_10_TCV0_4_TCV1_4:
+       case FEM_WIRING_11_TCV0_4_TCV1_4_RX_ONLY:
+       case FEM_WIRING_12_TCV0_4_TCV1_4_RX_ONLY:
+       case FEM_WIRING_13_SENSING_4RX_2TX:
+       case FEM_WIRING_14_SENSING_4TX_2RX:
+       case FEM_WIRING_15_CHAMELEON_4TX_4RX:
+       case FEM_WIRING_16_TCV0_2_TCV1_2:
+       case FEM_WIRING_18_TCV0_4_TCV1_4:
+       case FEM_WIRING_19_TCV0_2_TCV1_2_SWAPPED:
+       case FEM_WIRING_20_TCV0_4_TCV1_2:
+       case FEM_WIRING_21_TCV0_4_TCV1_2:
+               fem->lut_off_register[TCV0] = fem->lut_off_register_list[FEM_TYPE_TCV0];
+               fem->lut_off_register[TCV1] = fem->lut_off_register_list[FEM_TYPE_TCV1];
+               break;
+
+       case FEM_WIRING_17_TCV0_4_TCV1_0:
+               fem->lut_off_register[TCV0] = fem->lut_off_register_list[FEM_TYPE_TCV0];
+               break;
+
+       case FEM_WIRING_3_TCV0_2_ELASTIC_4_TCV1_2:
+       case FEM_WIRING_4_TCV0_2_ELASTIC_4_TCV1_2:
+       case FEM_WIRING_5_TCV0_2_ELASTIC_4_TCV1_2:
+       case FEM_WIRING_6_TCV0_2_ELASTIC_4_TCV1_2:
+               fem->lut_off_register[TCV0] = fem->lut_off_register_list[FEM_TYPE_ELASTIC];
+               fem->lut_off_register[TCV1] = fem->lut_off_register_list[FEM_TYPE_ELASTIC];
+               break;
+
+       default:
+               cl_dbg_chip_err(chip, "Unsupported wiring id [%u]\n", fem->wiring_id);
+               return -1;
+       }
+
+       cl_dbg_chip_trace(chip, "wiring_id = %u, lut_off_register = [%u %u]\n",
+                         fem->wiring_id,
+                         fem->lut_off_register[TCV0],
+                         fem->lut_off_register[TCV1]);
+       return 0;
+}
+
+int cl_fem_init(struct cl_chip *chip)
+{
+       int ret = 0;
+       struct cl_fem_params *fem = &chip->fem;
+
+       fem->wiring_id = FEM_WIRING_DEFAULT;
+
+       ret = cl_fem_read_wiring_id(chip);
+
+       if (ret) {
+               CL_DBG_ERROR_CHIP(chip, "Invalid wiring_id = %u. Aborting.\n", fem->wiring_id);
+
+               if (!chip->conf->ce_production_mode)
+                       return ret;
+       }
+
+       if (cl_fem_read_lut(chip)) {
+               CL_DBG_ERROR_CHIP(chip, "None of the FEM_LUT registers is valid. Aborting.\n");
+
+               if (!chip->conf->ce_production_mode)
+                       return -1;
+       }
+
+       if (cl_fem_check_lut_validity(chip, fem->wiring_id) &&
+           !chip->conf->ce_production_mode)
+               return -1;
+
+       if (cl_fem_set_lut_off(chip) &&
+           !chip->conf->ce_production_mode)
+               return -1;
+
+       cl_dbg_chip_verbose(chip, "wiring_id = %u\n", fem->wiring_id);
+       cl_fem_set_registers(chip);
+
+       ret = cl_agc_params_read_platform_id(chip);
+       if (ret)
+               return ret;
+
+       return 0;
+}
+
+static void cl_fem_get_conf_params(struct cl_chip *chip,
+                                  u32 *ricu_fem_conf_0,
+                                  u32 *ricu_fem_conf_1)
+{
+       u8 wiring_id = chip->fem.wiring_id;
+
+       *ricu_fem_conf_0 = ricu_fem_conf[wiring_id][0];
+       *ricu_fem_conf_1 = ricu_fem_conf[wiring_id][1];
+
+       cl_dbg_chip_verbose(chip, "ricu_fem_conf_0 = 0x%08X, ricu_fem_conf_1 = 0x%08X\n",
+                           *ricu_fem_conf_0, *ricu_fem_conf_1);
+}
+
+static u8 get_num_antennas_tcv0(struct cl_chip *chip)
+{
+       if (chip->cl_hw_tcv0)
+               return chip->cl_hw_tcv0->num_antennas;
+       else
+               return chip->max_antennas - chip->cl_hw_tcv1->num_antennas;
+}
+
+static void update_formation_1_band_select(struct cl_chip *chip)
+{
+       u8 num_antennas_tcv0 = get_num_antennas_tcv0(chip);
+
+       if (num_antennas_tcv0 == 2) {
+               io_ctrl_pa_enable_4_set(chip, PA_ENABLE_GPIO_OUT_CFG(0));
+               io_ctrl_pa_enable_5_set(chip, PA_ENABLE_GPIO_OUT_CFG(0));
+               io_ctrl_pa_enable_8_set(chip, PA_ENABLE_GPIO_OUT_CFG(0));
+               io_ctrl_pa_enable_9_set(chip, PA_ENABLE_GPIO_OUT_CFG(0));
+       } else if (num_antennas_tcv0 == 3) {
+               io_ctrl_pa_enable_4_set(chip, PA_ENABLE_GPIO_OUT_CFG(0));
+               io_ctrl_pa_enable_5_set(chip, PA_ENABLE_GPIO_OUT_CFG(0));
+               io_ctrl_pa_enable_8_set(chip, PA_ENABLE_GPIO_OUT_CFG(1));
+               io_ctrl_pa_enable_9_set(chip, PA_ENABLE_GPIO_OUT_CFG(0));
+       } else if (num_antennas_tcv0 == 4) {
+               io_ctrl_pa_enable_4_set(chip, PA_ENABLE_GPIO_OUT_CFG(0));
+               io_ctrl_pa_enable_5_set(chip, PA_ENABLE_GPIO_OUT_CFG(0));
+               io_ctrl_pa_enable_8_set(chip, PA_ENABLE_GPIO_OUT_CFG(1));
+               io_ctrl_pa_enable_9_set(chip, PA_ENABLE_GPIO_OUT_CFG(1));
+       } else if (num_antennas_tcv0 == 5) {
+               io_ctrl_pa_enable_4_set(chip, PA_ENABLE_GPIO_OUT_CFG(1));
+               io_ctrl_pa_enable_5_set(chip, PA_ENABLE_GPIO_OUT_CFG(0));
+               io_ctrl_pa_enable_8_set(chip, PA_ENABLE_GPIO_OUT_CFG(1));
+               io_ctrl_pa_enable_9_set(chip, PA_ENABLE_GPIO_OUT_CFG(1));
+       } else if (num_antennas_tcv0 == 6) {
+               io_ctrl_pa_enable_4_set(chip, PA_ENABLE_GPIO_OUT_CFG(1));
+               io_ctrl_pa_enable_5_set(chip, PA_ENABLE_GPIO_OUT_CFG(1));
+               io_ctrl_pa_enable_8_set(chip, PA_ENABLE_GPIO_OUT_CFG(1));
+               io_ctrl_pa_enable_9_set(chip, PA_ENABLE_GPIO_OUT_CFG(1));
+       }
+}
+
+static void set_lna_bypass_gpio(struct cl_chip *chip)
+{
+       struct cl_fem_params *fem = &chip->fem;
+       u8 lna_bypass_val_tcv0 = fem->lut[FEM_TYPE_TCV0] & RIU_RC_RF_LNA_LUT_RFLNALUT_0_MASK;
+       u8 lna_bypass_val_tcv1 = fem->lut[FEM_TYPE_TCV1] & RIU_RC_RF_LNA_LUT_RFLNALUT_0_MASK;
+       u8 lna_bypass_val_elastic = fem->lut[FEM_TYPE_ELASTIC] & RIU_RC_RF_LNA_LUT_RFLNALUT_0_MASK;
+       u8 lna_bypass_val_sensing = fem->lut[FEM_TYPE_SENSING] & RIU_RC_RF_LNA_LUT_RFLNALUT_0_MASK;
+       u8 pa_enable_bit_tcv0 = GET_BIT(lna_bypass_val_tcv0, PA_ENABLE_POS);
+       u8 pa_enable_bit_tcv1 = GET_BIT(lna_bypass_val_tcv1, PA_ENABLE_POS);
+       u8 pa_enable_bit_elastic = GET_BIT(lna_bypass_val_elastic, PA_ENABLE_POS);
+       u8 pa_enable_bit_sensing = GET_BIT(lna_bypass_val_sensing, PA_ENABLE_POS);
+       u8 lna_enable_bit_tcv0 = GET_BIT(lna_bypass_val_tcv0, LNA_ENABLE_POS);
+       u8 lna_enable_bit_tcv1 = GET_BIT(lna_bypass_val_tcv1, LNA_ENABLE_POS);
+       u8 lna_enable_bit_elastic = GET_BIT(lna_bypass_val_elastic, LNA_ENABLE_POS);
+       u8 lna_enable_bit_sensing = GET_BIT(lna_bypass_val_sensing, LNA_ENABLE_POS);
+       u8 rx_active_bit_tcv0 = GET_BIT(lna_bypass_val_tcv0, RX_ACTIVE_POS);
+       u8 rx_active_bit_tcv1 = GET_BIT(lna_bypass_val_tcv1, RX_ACTIVE_POS);
+       u8 rx_active_bit_sensing = GET_BIT(lna_bypass_val_sensing, RX_ACTIVE_POS);
+       u32 pa_enable_cfg_tcv0 = PA_ENABLE_GPIO_OUT_CFG(pa_enable_bit_tcv0);
+       u32 pa_enable_cfg_tcv1 = PA_ENABLE_GPIO_OUT_CFG(pa_enable_bit_tcv1);
+       u32 pa_enable_cfg_elastic = PA_ENABLE_GPIO_OUT_CFG(pa_enable_bit_elastic);
+       u32 pa_enable_cfg_sensing = PA_ENABLE_GPIO_OUT_CFG(pa_enable_bit_sensing);
+       u32 lna_enable_cfg_tcv0 = LNA_ENABLE_GPIO_OUT_CFG(lna_enable_bit_tcv0);
+       u32 lna_enable_cfg_tcv1 = LNA_ENABLE_GPIO_OUT_CFG(lna_enable_bit_tcv1);
+       u32 lna_enable_cfg_elastic = LNA_ENABLE_GPIO_OUT_CFG(lna_enable_bit_elastic);
+       u32 lna_enable_cfg_sensing = LNA_ENABLE_GPIO_OUT_CFG(lna_enable_bit_sensing);
+       u32 rx_active_cfg_tcv0 = RX_ACTIVE_GPIO_OUT_CFG(rx_active_bit_tcv0);
+       u32 rx_active_cfg_tcv1 = RX_ACTIVE_GPIO_OUT_CFG(rx_active_bit_tcv1);
+       u32 rx_active_cfg_sensing = RX_ACTIVE_GPIO_OUT_CFG(rx_active_bit_sensing);
+
+       switch (fem->wiring_id) {
+       case FEM_WIRING_0_TCV0_6_TCV1_6:
+               io_ctrl_lna_enable_0_set(chip, lna_enable_cfg_tcv0);
+               io_ctrl_lna_enable_1_set(chip, lna_enable_cfg_tcv0);
+               io_ctrl_lna_enable_2_set(chip, lna_enable_cfg_tcv0);
+               io_ctrl_lna_enable_3_set(chip, lna_enable_cfg_tcv0);
+               io_ctrl_lna_enable_4_set(chip, lna_enable_cfg_tcv1);
+               io_ctrl_lna_enable_5_set(chip, lna_enable_cfg_tcv1);
+               io_ctrl_lna_enable_6_set(chip, lna_enable_cfg_tcv1);
+               io_ctrl_lna_enable_7_set(chip, lna_enable_cfg_tcv1);
+               io_ctrl_lna_enable_8_set(chip, lna_enable_cfg_tcv1);
+               io_ctrl_lna_enable_9_set(chip, lna_enable_cfg_tcv1);
+               io_ctrl_lna_enable_10_set(chip, lna_enable_cfg_tcv0);
+               io_ctrl_lna_enable_11_set(chip, lna_enable_cfg_tcv0);
+
+               io_ctrl_pa_enable_0_set(chip, pa_enable_cfg_tcv0);
+               io_ctrl_pa_enable_1_set(chip, pa_enable_cfg_tcv0);
+               io_ctrl_pa_enable_2_set(chip, pa_enable_cfg_tcv0);
+               io_ctrl_pa_enable_3_set(chip, pa_enable_cfg_tcv0);
+               io_ctrl_pa_enable_4_set(chip, pa_enable_cfg_tcv1);
+               io_ctrl_pa_enable_5_set(chip, pa_enable_cfg_tcv1);
+               io_ctrl_pa_enable_6_set(chip, pa_enable_cfg_tcv1);
+               io_ctrl_pa_enable_7_set(chip, pa_enable_cfg_tcv1);
+               io_ctrl_pa_enable_8_set(chip, pa_enable_cfg_tcv1);
+               io_ctrl_pa_enable_9_set(chip, pa_enable_cfg_tcv1);
+               io_ctrl_pa_enable_10_set(chip, pa_enable_cfg_tcv0);
+               io_ctrl_pa_enable_11_set(chip, pa_enable_cfg_tcv0);
+
+               io_ctrl_rx_active_0_set(chip, rx_active_cfg_tcv0);
+               io_ctrl_rx_active_1_set(chip, rx_active_cfg_tcv0);
+               io_ctrl_rx_active_2_set(chip, rx_active_cfg_tcv0);
+               io_ctrl_rx_active_3_set(chip, rx_active_cfg_tcv0);
+               io_ctrl_rx_active_4_set(chip, rx_active_cfg_tcv0);
+               io_ctrl_rx_active_5_set(chip, rx_active_cfg_tcv0);
+               break;
+       case FEM_WIRING_1_TCV0_6_TCV1_6:
+               io_ctrl_lna_enable_0_set(chip, lna_enable_cfg_tcv0);
+               io_ctrl_lna_enable_1_set(chip, lna_enable_cfg_tcv0);
+               io_ctrl_lna_enable_2_set(chip, lna_enable_cfg_tcv0);
+               io_ctrl_lna_enable_3_set(chip, lna_enable_cfg_tcv0);
+               io_ctrl_lna_enable_4_set(chip, lna_enable_cfg_tcv1);
+               io_ctrl_lna_enable_5_set(chip, lna_enable_cfg_tcv1);
+               io_ctrl_lna_enable_6_set(chip, lna_enable_cfg_tcv1);
+               io_ctrl_lna_enable_7_set(chip, lna_enable_cfg_tcv1);
+               io_ctrl_lna_enable_8_set(chip, lna_enable_cfg_tcv1);
+               io_ctrl_lna_enable_9_set(chip, lna_enable_cfg_tcv1);
+               io_ctrl_lna_enable_10_set(chip, lna_enable_cfg_tcv0);
+               io_ctrl_lna_enable_11_set(chip, lna_enable_cfg_tcv0);
+
+               io_ctrl_pa_enable_0_set(chip, pa_enable_cfg_tcv0);
+               io_ctrl_pa_enable_1_set(chip, pa_enable_cfg_tcv0);
+               io_ctrl_pa_enable_2_set(chip, pa_enable_cfg_tcv0);
+               io_ctrl_pa_enable_3_set(chip, pa_enable_cfg_tcv0);
+               io_ctrl_pa_enable_4_set(chip, pa_enable_cfg_tcv1);
+               io_ctrl_pa_enable_5_set(chip, pa_enable_cfg_tcv1);
+               io_ctrl_pa_enable_6_set(chip, pa_enable_cfg_tcv1);
+               io_ctrl_pa_enable_7_set(chip, pa_enable_cfg_tcv1);
+               io_ctrl_pa_enable_8_set(chip, pa_enable_cfg_tcv1);
+               io_ctrl_pa_enable_9_set(chip, pa_enable_cfg_tcv1);
+               io_ctrl_pa_enable_10_set(chip, pa_enable_cfg_tcv0);
+               io_ctrl_pa_enable_11_set(chip, pa_enable_cfg_tcv0);
+               break;
+       case FEM_WIRING_2_TCV0_6_TCV1_6:
+               /* TBD */
+               break;
+       case FEM_WIRING_3_TCV0_2_ELASTIC_4_TCV1_2:
+               io_ctrl_lna_enable_0_set(chip, lna_enable_cfg_tcv0);
+               io_ctrl_lna_enable_1_set(chip, lna_enable_cfg_elastic);
+               io_ctrl_lna_enable_2_set(chip, lna_enable_cfg_tcv0);
+               io_ctrl_lna_enable_3_set(chip, lna_enable_cfg_elastic);
+               io_ctrl_lna_enable_6_set(chip, lna_enable_cfg_tcv1);
+               io_ctrl_lna_enable_7_set(chip, lna_enable_cfg_tcv1);
+               io_ctrl_lna_enable_10_set(chip, lna_enable_cfg_elastic);
+               io_ctrl_lna_enable_11_set(chip, lna_enable_cfg_elastic);
+
+               io_ctrl_pa_enable_0_set(chip, pa_enable_cfg_tcv0);
+               io_ctrl_pa_enable_1_set(chip, pa_enable_cfg_elastic);
+               io_ctrl_pa_enable_2_set(chip, pa_enable_cfg_tcv0);
+               io_ctrl_pa_enable_3_set(chip, pa_enable_cfg_elastic);
+               io_ctrl_pa_enable_6_set(chip, pa_enable_cfg_tcv1);
+               io_ctrl_pa_enable_7_set(chip, pa_enable_cfg_tcv1);
+               io_ctrl_pa_enable_10_set(chip, pa_enable_cfg_elastic);
+               io_ctrl_pa_enable_11_set(chip, pa_enable_cfg_elastic);
+
+               io_ctrl_rx_active_0_set(chip, rx_active_cfg_tcv0);
+               io_ctrl_rx_active_1_set(chip, rx_active_cfg_tcv0);
+               break;
+       case FEM_WIRING_4_TCV0_2_ELASTIC_4_TCV1_2:
+               io_ctrl_lna_enable_0_set(chip, lna_enable_cfg_tcv0);
+               io_ctrl_lna_enable_1_set(chip, lna_enable_cfg_elastic);
+               io_ctrl_lna_enable_2_set(chip, lna_enable_cfg_tcv0);
+               io_ctrl_lna_enable_3_set(chip, lna_enable_cfg_elastic);
+               io_ctrl_lna_enable_6_set(chip, lna_enable_cfg_tcv1);
+               io_ctrl_lna_enable_7_set(chip, lna_enable_cfg_tcv1);
+               io_ctrl_lna_enable_10_set(chip, lna_enable_cfg_elastic);
+               io_ctrl_lna_enable_11_set(chip, lna_enable_cfg_elastic);
+
+               io_ctrl_pa_enable_0_set(chip, pa_enable_cfg_tcv0);
+               io_ctrl_pa_enable_1_set(chip, pa_enable_cfg_elastic);
+               io_ctrl_pa_enable_2_set(chip, pa_enable_cfg_tcv0);
+               io_ctrl_pa_enable_3_set(chip, pa_enable_cfg_elastic);
+               io_ctrl_pa_enable_6_set(chip, pa_enable_cfg_tcv1);
+               io_ctrl_pa_enable_7_set(chip, pa_enable_cfg_tcv1);
+               io_ctrl_pa_enable_10_set(chip, pa_enable_cfg_elastic);
+               io_ctrl_pa_enable_11_set(chip, pa_enable_cfg_elastic);
+               break;
+       case FEM_WIRING_5_TCV0_2_ELASTIC_4_TCV1_2:
+               io_ctrl_lna_enable_0_set(chip, lna_enable_cfg_tcv0);
+               io_ctrl_lna_enable_1_set(chip, lna_enable_cfg_elastic);
+               io_ctrl_lna_enable_2_set(chip, lna_enable_cfg_tcv0);
+               io_ctrl_lna_enable_3_set(chip, lna_enable_cfg_elastic);
+               io_ctrl_lna_enable_6_set(chip, lna_enable_cfg_tcv1);
+               io_ctrl_lna_enable_7_set(chip, lna_enable_cfg_tcv1);
+               io_ctrl_lna_enable_10_set(chip, lna_enable_cfg_elastic);
+               io_ctrl_lna_enable_11_set(chip, lna_enable_cfg_elastic);
+
+               io_ctrl_pa_enable_0_set(chip, pa_enable_cfg_tcv0);
+               io_ctrl_pa_enable_1_set(chip, pa_enable_cfg_elastic);
+               io_ctrl_pa_enable_2_set(chip, pa_enable_cfg_tcv0);
+               io_ctrl_pa_enable_3_set(chip, pa_enable_cfg_elastic);
+               io_ctrl_pa_enable_6_set(chip, pa_enable_cfg_tcv1);
+               io_ctrl_pa_enable_7_set(chip, pa_enable_cfg_tcv1);
+               io_ctrl_pa_enable_10_set(chip, pa_enable_cfg_elastic);
+               io_ctrl_pa_enable_11_set(chip, pa_enable_cfg_elastic);
+
+               io_ctrl_rx_active_0_set(chip, rx_active_cfg_tcv0);
+               io_ctrl_rx_active_1_set(chip, rx_active_cfg_tcv0);
+               io_ctrl_rx_active_6_set(chip, rx_active_cfg_tcv1);
+               io_ctrl_rx_active_7_set(chip, rx_active_cfg_tcv1);
+               break;
+       case FEM_WIRING_6_TCV0_2_ELASTIC_4_TCV1_2:
+               /* TBD */
+               break;
+       case FEM_WIRING_7_TCV0_4_TCV1_4:
+               io_ctrl_lna_enable_0_set(chip, lna_enable_cfg_tcv0);
+               io_ctrl_lna_enable_2_set(chip, lna_enable_cfg_tcv0);
+               io_ctrl_lna_enable_6_set(chip, lna_enable_cfg_tcv1);
+               io_ctrl_lna_enable_7_set(chip, lna_enable_cfg_tcv1);
+               io_ctrl_lna_enable_8_set(chip, lna_enable_cfg_tcv1);
+               io_ctrl_lna_enable_9_set(chip, lna_enable_cfg_tcv1);
+               io_ctrl_lna_enable_10_set(chip, lna_enable_cfg_tcv0);
+               io_ctrl_lna_enable_11_set(chip, lna_enable_cfg_tcv0);
+
+               io_ctrl_pa_enable_0_set(chip, pa_enable_cfg_tcv0);
+               io_ctrl_pa_enable_2_set(chip, pa_enable_cfg_tcv0);
+               io_ctrl_pa_enable_6_set(chip, pa_enable_cfg_tcv1);
+               io_ctrl_pa_enable_7_set(chip, pa_enable_cfg_tcv1);
+               io_ctrl_pa_enable_8_set(chip, pa_enable_cfg_tcv1);
+               io_ctrl_pa_enable_9_set(chip, pa_enable_cfg_tcv1);
+               io_ctrl_pa_enable_10_set(chip, pa_enable_cfg_tcv0);
+               io_ctrl_pa_enable_11_set(chip, pa_enable_cfg_tcv0);
+
+               io_ctrl_rx_active_0_set(chip, rx_active_cfg_tcv0);
+               io_ctrl_rx_active_1_set(chip, rx_active_cfg_tcv0);
+               io_ctrl_rx_active_2_set(chip, rx_active_cfg_tcv0);
+               io_ctrl_rx_active_3_set(chip, rx_active_cfg_tcv0);
+               break;
+       case FEM_WIRING_8_TCV0_4_TCV1_4:
+               /* TBD */
+               break;
+       case FEM_WIRING_9_TCV0_4_TCV1_4:
+               io_ctrl_lna_enable_0_set(chip, lna_enable_cfg_tcv0);
+               io_ctrl_lna_enable_1_set(chip, lna_enable_cfg_tcv0);
+               io_ctrl_lna_enable_2_set(chip, lna_enable_cfg_tcv0);
+               io_ctrl_lna_enable_3_set(chip, lna_enable_cfg_tcv0);
+               io_ctrl_lna_enable_4_set(chip, lna_enable_cfg_tcv1);
+               io_ctrl_lna_enable_5_set(chip, lna_enable_cfg_tcv1);
+               io_ctrl_lna_enable_6_set(chip, lna_enable_cfg_tcv1);
+               io_ctrl_lna_enable_7_set(chip, lna_enable_cfg_tcv1);
+
+               io_ctrl_pa_enable_0_set(chip, pa_enable_cfg_tcv0);
+               io_ctrl_pa_enable_1_set(chip, pa_enable_cfg_tcv0);
+               io_ctrl_pa_enable_2_set(chip, pa_enable_cfg_tcv0);
+               io_ctrl_pa_enable_3_set(chip, pa_enable_cfg_tcv0);
+               io_ctrl_pa_enable_4_set(chip, pa_enable_cfg_tcv1);
+               io_ctrl_pa_enable_5_set(chip, pa_enable_cfg_tcv1);
+               io_ctrl_pa_enable_6_set(chip, pa_enable_cfg_tcv1);
+               io_ctrl_pa_enable_7_set(chip, pa_enable_cfg_tcv1);
+               break;
+       case FEM_WIRING_10_TCV0_4_TCV1_4:
+               io_ctrl_lna_enable_0_set(chip, lna_enable_cfg_tcv0);
+               io_ctrl_lna_enable_1_set(chip, lna_enable_cfg_tcv0);
+               io_ctrl_lna_enable_2_set(chip, lna_enable_cfg_tcv0);
+               io_ctrl_lna_enable_3_set(chip, lna_enable_cfg_tcv0);
+               io_ctrl_lna_enable_4_set(chip, lna_enable_cfg_tcv1);
+               io_ctrl_lna_enable_5_set(chip, lna_enable_cfg_tcv1);
+               io_ctrl_lna_enable_6_set(chip, lna_enable_cfg_tcv1);
+               io_ctrl_lna_enable_7_set(chip, lna_enable_cfg_tcv1);
+
+               io_ctrl_pa_enable_0_set(chip, pa_enable_cfg_tcv0);
+               io_ctrl_pa_enable_1_set(chip, pa_enable_cfg_tcv0);
+               io_ctrl_pa_enable_2_set(chip, pa_enable_cfg_tcv0);
+               io_ctrl_pa_enable_3_set(chip, pa_enable_cfg_tcv0);
+               io_ctrl_pa_enable_4_set(chip, pa_enable_cfg_tcv1);
+               io_ctrl_pa_enable_5_set(chip, pa_enable_cfg_tcv1);
+               io_ctrl_pa_enable_6_set(chip, pa_enable_cfg_tcv1);
+               io_ctrl_pa_enable_7_set(chip, pa_enable_cfg_tcv1);
+
+               io_ctrl_rx_active_0_set(chip, rx_active_cfg_tcv0);
+               io_ctrl_rx_active_1_set(chip, rx_active_cfg_tcv0);
+               io_ctrl_rx_active_2_set(chip, rx_active_cfg_tcv0);
+               io_ctrl_rx_active_3_set(chip, rx_active_cfg_tcv0);
+               io_ctrl_rx_active_4_set(chip, rx_active_cfg_tcv1);
+               io_ctrl_rx_active_5_set(chip, rx_active_cfg_tcv1);
+               io_ctrl_rx_active_6_set(chip, rx_active_cfg_tcv1);
+               io_ctrl_rx_active_7_set(chip, rx_active_cfg_tcv1);
+               break;
+       case FEM_WIRING_11_TCV0_4_TCV1_4_RX_ONLY:
+               io_ctrl_lna_enable_0_set(chip, lna_enable_cfg_tcv0);
+               io_ctrl_lna_enable_1_set(chip, lna_enable_cfg_tcv0);
+               io_ctrl_lna_enable_2_set(chip, lna_enable_cfg_tcv0);
+               io_ctrl_lna_enable_3_set(chip, lna_enable_cfg_tcv0);
+               io_ctrl_lna_enable_4_set(chip, lna_enable_cfg_sensing);
+               io_ctrl_lna_enable_5_set(chip, lna_enable_cfg_sensing);
+               io_ctrl_lna_enable_6_set(chip, lna_enable_cfg_sensing);
+               io_ctrl_lna_enable_7_set(chip, lna_enable_cfg_sensing);
+
+               io_ctrl_pa_enable_0_set(chip, pa_enable_cfg_tcv0);
+               io_ctrl_pa_enable_1_set(chip, pa_enable_cfg_tcv0);
+               io_ctrl_pa_enable_2_set(chip, pa_enable_cfg_tcv0);
+               io_ctrl_pa_enable_3_set(chip, pa_enable_cfg_tcv0);
+
+               io_ctrl_rx_active_0_set(chip, rx_active_cfg_tcv0);
+               io_ctrl_rx_active_1_set(chip, rx_active_cfg_tcv0);
+               io_ctrl_rx_active_2_set(chip, rx_active_cfg_tcv0);
+               io_ctrl_rx_active_3_set(chip, rx_active_cfg_tcv0);
+               break;
+       case FEM_WIRING_12_TCV0_4_TCV1_4_RX_ONLY:
+               io_ctrl_lna_enable_0_set(chip, lna_enable_cfg_tcv0);
+               io_ctrl_lna_enable_1_set(chip, lna_enable_cfg_tcv0);
+               io_ctrl_lna_enable_2_set(chip, lna_enable_cfg_tcv0);
+               io_ctrl_lna_enable_3_set(chip, lna_enable_cfg_tcv0);
+               io_ctrl_lna_enable_4_set(chip, lna_enable_cfg_sensing);
+               io_ctrl_lna_enable_5_set(chip, lna_enable_cfg_sensing);
+               io_ctrl_lna_enable_6_set(chip, lna_enable_cfg_sensing);
+               io_ctrl_lna_enable_7_set(chip, lna_enable_cfg_sensing);
+
+               io_ctrl_pa_enable_0_set(chip, pa_enable_cfg_tcv0);
+               io_ctrl_pa_enable_1_set(chip, pa_enable_cfg_tcv0);
+               io_ctrl_pa_enable_2_set(chip, pa_enable_cfg_tcv0);
+               io_ctrl_pa_enable_3_set(chip, pa_enable_cfg_tcv0);
+               break;
+       case FEM_WIRING_13_SENSING_4RX_2TX:
+               io_ctrl_lna_enable_0_set(chip, lna_enable_cfg_sensing);
+               io_ctrl_lna_enable_1_set(chip, lna_enable_cfg_sensing);
+               io_ctrl_lna_enable_2_set(chip, lna_enable_cfg_sensing);
+               io_ctrl_lna_enable_3_set(chip, lna_enable_cfg_sensing);
+               io_ctrl_lna_enable_10_set(chip, lna_enable_cfg_tcv1);
+               io_ctrl_lna_enable_11_set(chip, lna_enable_cfg_tcv1);
+
+               io_ctrl_pa_enable_0_set(chip, pa_enable_cfg_sensing);
+               io_ctrl_pa_enable_1_set(chip, pa_enable_cfg_sensing);
+               io_ctrl_pa_enable_2_set(chip, pa_enable_cfg_sensing);
+               io_ctrl_pa_enable_3_set(chip, pa_enable_cfg_sensing);
+               io_ctrl_pa_enable_10_set(chip, pa_enable_cfg_tcv1);
+               io_ctrl_pa_enable_11_set(chip, pa_enable_cfg_tcv1);
+
+               io_ctrl_rx_active_0_set(chip, rx_active_cfg_sensing);
+               io_ctrl_rx_active_1_set(chip, rx_active_cfg_sensing);
+               io_ctrl_rx_active_2_set(chip, rx_active_cfg_sensing);
+               io_ctrl_rx_active_3_set(chip, rx_active_cfg_sensing);
+               io_ctrl_rx_active_4_set(chip, rx_active_cfg_tcv1);
+               io_ctrl_rx_active_5_set(chip, rx_active_cfg_tcv1);
+               break;
+       case FEM_WIRING_14_SENSING_4TX_2RX:
+               io_ctrl_lna_enable_0_set(chip, lna_enable_cfg_tcv0);
+               io_ctrl_lna_enable_1_set(chip, lna_enable_cfg_tcv0);
+               io_ctrl_lna_enable_2_set(chip, lna_enable_cfg_tcv0);
+               io_ctrl_lna_enable_3_set(chip, lna_enable_cfg_tcv0);
+               io_ctrl_lna_enable_6_set(chip, lna_enable_cfg_sensing);
+               io_ctrl_lna_enable_7_set(chip, lna_enable_cfg_sensing);
+
+               io_ctrl_pa_enable_0_set(chip, pa_enable_cfg_tcv0);
+               io_ctrl_pa_enable_1_set(chip, pa_enable_cfg_tcv0);
+               io_ctrl_pa_enable_2_set(chip, pa_enable_cfg_tcv0);
+               io_ctrl_pa_enable_3_set(chip, pa_enable_cfg_tcv0);
+
+               io_ctrl_rx_active_0_set(chip, rx_active_cfg_tcv0);
+               io_ctrl_rx_active_1_set(chip, rx_active_cfg_tcv0);
+               io_ctrl_rx_active_2_set(chip, rx_active_cfg_tcv0);
+               io_ctrl_rx_active_3_set(chip, rx_active_cfg_tcv0);
+               break;
+       case FEM_WIRING_15_CHAMELEON_4TX_4RX:
+               io_ctrl_lna_enable_0_set(chip, lna_enable_cfg_tcv0);
+               io_ctrl_lna_enable_2_set(chip, lna_enable_cfg_tcv0);
+               io_ctrl_lna_enable_4_set(chip, lna_enable_cfg_sensing);
+               io_ctrl_lna_enable_5_set(chip, lna_enable_cfg_sensing);
+               io_ctrl_lna_enable_6_set(chip, lna_enable_cfg_sensing);
+               io_ctrl_lna_enable_7_set(chip, lna_enable_cfg_sensing);
+               io_ctrl_lna_enable_10_set(chip, lna_enable_cfg_tcv0);
+               io_ctrl_lna_enable_11_set(chip, lna_enable_cfg_tcv0);
+
+               io_ctrl_pa_enable_0_set(chip, pa_enable_cfg_tcv0);
+               io_ctrl_pa_enable_2_set(chip, pa_enable_cfg_tcv0);
+               io_ctrl_pa_enable_10_set(chip, pa_enable_cfg_tcv0);
+               io_ctrl_pa_enable_11_set(chip, pa_enable_cfg_tcv0);
+
+               io_ctrl_rx_active_0_set(chip, rx_active_cfg_tcv0);
+               io_ctrl_rx_active_1_set(chip, rx_active_cfg_tcv0);
+               io_ctrl_rx_active_2_set(chip, rx_active_cfg_tcv0);
+               io_ctrl_rx_active_3_set(chip, rx_active_cfg_tcv0);
+               break;
+       case FEM_WIRING_16_TCV0_2_TCV1_2:
+               io_ctrl_lna_enable_0_set(chip, lna_enable_cfg_tcv0);
+               io_ctrl_lna_enable_6_set(chip, lna_enable_cfg_tcv1);
+               io_ctrl_lna_enable_9_set(chip, lna_enable_cfg_tcv1);
+               io_ctrl_lna_enable_10_set(chip, lna_enable_cfg_tcv0);
+
+               io_ctrl_pa_enable_0_set(chip, pa_enable_cfg_tcv0);
+               io_ctrl_pa_enable_6_set(chip, pa_enable_cfg_tcv1);
+               io_ctrl_pa_enable_9_set(chip, pa_enable_cfg_tcv1);
+               io_ctrl_pa_enable_10_set(chip, pa_enable_cfg_tcv0);
+
+               io_ctrl_rx_active_1_set(chip, rx_active_cfg_tcv0);
+               io_ctrl_rx_active_2_set(chip, rx_active_cfg_tcv0);
+               break;
+       case FEM_WIRING_17_TCV0_4_TCV1_0:
+               io_ctrl_lna_enable_0_set(chip, lna_enable_cfg_tcv0);
+               io_ctrl_lna_enable_1_set(chip, lna_enable_cfg_tcv0);
+               io_ctrl_lna_enable_2_set(chip, lna_enable_cfg_tcv0);
+               io_ctrl_lna_enable_3_set(chip, lna_enable_cfg_tcv0);
+
+               io_ctrl_pa_enable_0_set(chip, pa_enable_cfg_tcv0);
+               io_ctrl_pa_enable_1_set(chip, pa_enable_cfg_tcv0);
+               io_ctrl_pa_enable_2_set(chip, pa_enable_cfg_tcv0);
+               io_ctrl_pa_enable_3_set(chip, pa_enable_cfg_tcv0);
+               break;
+       case FEM_WIRING_18_TCV0_4_TCV1_4:
+               io_ctrl_lna_enable_0_set(chip, lna_enable_cfg_tcv0);
+               io_ctrl_lna_enable_2_set(chip, lna_enable_cfg_tcv0);
+               io_ctrl_lna_enable_6_set(chip, lna_enable_cfg_tcv1);
+               io_ctrl_lna_enable_7_set(chip, lna_enable_cfg_tcv1);
+               io_ctrl_lna_enable_8_set(chip, lna_enable_cfg_tcv1);
+               io_ctrl_lna_enable_9_set(chip, lna_enable_cfg_tcv1);
+               io_ctrl_lna_enable_10_set(chip, lna_enable_cfg_tcv0);
+               io_ctrl_lna_enable_11_set(chip, lna_enable_cfg_tcv0);
+
+               io_ctrl_pa_enable_0_set(chip, pa_enable_cfg_tcv0);
+               io_ctrl_pa_enable_2_set(chip, pa_enable_cfg_tcv0);
+               io_ctrl_pa_enable_6_set(chip, pa_enable_cfg_tcv1);
+               io_ctrl_pa_enable_7_set(chip, pa_enable_cfg_tcv1);
+               io_ctrl_pa_enable_8_set(chip, pa_enable_cfg_tcv1);
+               io_ctrl_pa_enable_9_set(chip, pa_enable_cfg_tcv1);
+               io_ctrl_pa_enable_10_set(chip, pa_enable_cfg_tcv0);
+               io_ctrl_pa_enable_11_set(chip, pa_enable_cfg_tcv0);
+
+               io_ctrl_rx_active_0_set(chip, rx_active_cfg_tcv0);
+               io_ctrl_rx_active_1_set(chip, rx_active_cfg_tcv0);
+               io_ctrl_rx_active_2_set(chip, rx_active_cfg_tcv0);
+               io_ctrl_rx_active_3_set(chip, rx_active_cfg_tcv0);
+               io_ctrl_rx_active_4_set(chip, rx_active_cfg_tcv0);
+               io_ctrl_rx_active_5_set(chip, rx_active_cfg_tcv0);
+               io_ctrl_rx_active_6_set(chip, rx_active_cfg_tcv0);
+               io_ctrl_rx_active_7_set(chip, rx_active_cfg_tcv0);
+               break;
+       case FEM_WIRING_19_TCV0_2_TCV1_2_SWAPPED:
+               io_ctrl_lna_enable_8_set(chip, lna_enable_cfg_tcv1);
+               io_ctrl_lna_enable_9_set(chip, lna_enable_cfg_tcv1);
+               io_ctrl_lna_enable_10_set(chip, lna_enable_cfg_tcv0);
+               io_ctrl_lna_enable_11_set(chip, lna_enable_cfg_tcv0);
+
+               io_ctrl_pa_enable_8_set(chip, pa_enable_cfg_tcv1);
+               io_ctrl_pa_enable_9_set(chip, pa_enable_cfg_tcv1);
+               io_ctrl_pa_enable_10_set(chip, pa_enable_cfg_tcv0);
+               io_ctrl_pa_enable_11_set(chip, pa_enable_cfg_tcv0);
+
+               io_ctrl_rx_active_4_set(chip, rx_active_cfg_tcv0);
+               io_ctrl_rx_active_5_set(chip, rx_active_cfg_tcv0);
+               break;
+       case FEM_WIRING_20_TCV0_4_TCV1_2:
+               io_ctrl_lna_enable_0_set(chip, lna_enable_cfg_tcv0);
+               io_ctrl_lna_enable_2_set(chip, lna_enable_cfg_tcv0);
+               io_ctrl_lna_enable_8_set(chip, lna_enable_cfg_tcv1);
+               io_ctrl_lna_enable_9_set(chip, lna_enable_cfg_tcv1);
+               io_ctrl_lna_enable_10_set(chip, lna_enable_cfg_tcv0);
+               io_ctrl_lna_enable_11_set(chip, lna_enable_cfg_tcv0);
+
+               io_ctrl_pa_enable_0_set(chip, pa_enable_cfg_tcv0);
+               io_ctrl_pa_enable_2_set(chip, pa_enable_cfg_tcv0);
+               io_ctrl_pa_enable_8_set(chip, pa_enable_cfg_tcv1);
+               io_ctrl_pa_enable_9_set(chip, pa_enable_cfg_tcv1);
+               io_ctrl_pa_enable_10_set(chip, pa_enable_cfg_tcv0);
+               io_ctrl_pa_enable_11_set(chip, pa_enable_cfg_tcv0);
+
+               io_ctrl_rx_active_0_set(chip, rx_active_cfg_tcv0);
+               io_ctrl_rx_active_1_set(chip, rx_active_cfg_tcv0);
+               io_ctrl_rx_active_2_set(chip, rx_active_cfg_tcv0);
+               io_ctrl_rx_active_3_set(chip, rx_active_cfg_tcv0);
+               break;
+       case FEM_WIRING_21_TCV0_4_TCV1_2:
+               io_ctrl_lna_enable_0_set(chip, lna_enable_cfg_tcv0);
+               io_ctrl_lna_enable_1_set(chip, lna_enable_cfg_tcv0);
+               io_ctrl_lna_enable_2_set(chip, lna_enable_cfg_tcv0);
+               io_ctrl_lna_enable_3_set(chip, lna_enable_cfg_tcv0);
+               io_ctrl_lna_enable_4_set(chip, lna_enable_cfg_sensing);
+               io_ctrl_lna_enable_5_set(chip, lna_enable_cfg_sensing);
+
+               io_ctrl_pa_enable_0_set(chip, pa_enable_cfg_tcv0);
+               io_ctrl_pa_enable_1_set(chip, pa_enable_cfg_tcv0);
+               io_ctrl_pa_enable_2_set(chip, pa_enable_cfg_tcv0);
+               io_ctrl_pa_enable_3_set(chip, pa_enable_cfg_tcv0);
+               break;
+       default:
+               break;
+       }
+}
+
+static void _cl_fem_conf_gpio(struct cl_chip *chip,
+                             const struct cl_fem_lna_enable_gpio *lna_enable_gpio,
+                             const struct cl_fem_pa_enable_gpio *pa_enable_gpio,
+                             const struct cl_fem_rx_active_gpio *rx_active_gpio)
+{
+       io_ctrl_lna_enable_0_set(chip, LNA_ENABLE_GPIO_VAL(lna_enable_gpio->b0));
+       io_ctrl_lna_enable_1_set(chip, LNA_ENABLE_GPIO_VAL(lna_enable_gpio->b1));
+       io_ctrl_lna_enable_2_set(chip, LNA_ENABLE_GPIO_VAL(lna_enable_gpio->b2));
+       io_ctrl_lna_enable_3_set(chip, LNA_ENABLE_GPIO_VAL(lna_enable_gpio->b3));
+       io_ctrl_lna_enable_4_set(chip, LNA_ENABLE_GPIO_VAL(lna_enable_gpio->b4));
+       io_ctrl_lna_enable_5_set(chip, LNA_ENABLE_GPIO_VAL(lna_enable_gpio->b5));
+       io_ctrl_lna_enable_6_set(chip, LNA_ENABLE_GPIO_VAL(lna_enable_gpio->b6));
+       io_ctrl_lna_enable_7_set(chip, LNA_ENABLE_GPIO_VAL(lna_enable_gpio->b7));
+       io_ctrl_lna_enable_8_set(chip, LNA_ENABLE_GPIO_VAL(lna_enable_gpio->b8));
+       io_ctrl_lna_enable_9_set(chip, LNA_ENABLE_GPIO_VAL(lna_enable_gpio->b9));
+       io_ctrl_lna_enable_10_set(chip, LNA_ENABLE_GPIO_VAL(lna_enable_gpio->b10));
+       io_ctrl_lna_enable_11_set(chip, LNA_ENABLE_GPIO_VAL(lna_enable_gpio->b11));
+
+       io_ctrl_pa_enable_0_set(chip, PA_ENABLE_GPIO_VAL(pa_enable_gpio->b0));
+       io_ctrl_pa_enable_1_set(chip, PA_ENABLE_GPIO_VAL(pa_enable_gpio->b1));
+       io_ctrl_pa_enable_2_set(chip, PA_ENABLE_GPIO_VAL(pa_enable_gpio->b2));
+       io_ctrl_pa_enable_3_set(chip, PA_ENABLE_GPIO_VAL(pa_enable_gpio->b3));
+       io_ctrl_pa_enable_4_set(chip, PA_ENABLE_GPIO_VAL(pa_enable_gpio->b4));
+       io_ctrl_pa_enable_5_set(chip, PA_ENABLE_GPIO_VAL(pa_enable_gpio->b5));
+       io_ctrl_pa_enable_6_set(chip, PA_ENABLE_GPIO_VAL(pa_enable_gpio->b6));
+       io_ctrl_pa_enable_7_set(chip, PA_ENABLE_GPIO_VAL(pa_enable_gpio->b7));
+       io_ctrl_pa_enable_8_set(chip, PA_ENABLE_GPIO_VAL(pa_enable_gpio->b8));
+       io_ctrl_pa_enable_9_set(chip, PA_ENABLE_GPIO_VAL(pa_enable_gpio->b9));
+       io_ctrl_pa_enable_10_set(chip, PA_ENABLE_GPIO_VAL(pa_enable_gpio->b10));
+       io_ctrl_pa_enable_11_set(chip, PA_ENABLE_GPIO_VAL(pa_enable_gpio->b11));
+
+       io_ctrl_rx_active_0_set(chip, RX_ACTIVE_GPIO_VAL(rx_active_gpio->b0));
+       io_ctrl_rx_active_1_set(chip, RX_ACTIVE_GPIO_VAL(rx_active_gpio->b1));
+       io_ctrl_rx_active_2_set(chip, RX_ACTIVE_GPIO_VAL(rx_active_gpio->b2));
+       io_ctrl_rx_active_3_set(chip, RX_ACTIVE_GPIO_VAL(rx_active_gpio->b3));
+       io_ctrl_rx_active_4_set(chip, RX_ACTIVE_GPIO_VAL(rx_active_gpio->b4));
+       io_ctrl_rx_active_5_set(chip, RX_ACTIVE_GPIO_VAL(rx_active_gpio->b5));
+       io_ctrl_rx_active_6_set(chip, RX_ACTIVE_GPIO_VAL(rx_active_gpio->b6));
+       io_ctrl_rx_active_7_set(chip, RX_ACTIVE_GPIO_VAL(rx_active_gpio->b7));
+}
+
+static int cl_fem_conf_gpio(struct cl_chip *chip)
+{
+       struct cl_fem_params *fem = &chip->fem;
+       u8 wiring_id = fem->wiring_id;
+
+       if (wiring_id == FEM_WIRING_2_TCV0_6_TCV1_6 ||
+           wiring_id == FEM_WIRING_5_TCV0_2_ELASTIC_4_TCV1_2 ||
+           wiring_id == FEM_WIRING_6_TCV0_2_ELASTIC_4_TCV1_2 ||
+           wiring_id == FEM_WIRING_8_TCV0_4_TCV1_4) {
+               /* Need to be approved by Menashe - so for now it's unsupported. */
+               cl_dbg_chip_err(chip, "Unsupported wiring id [%u]\n", wiring_id);
+               return -1;
+       }
+
+       _cl_fem_conf_gpio(chip,
+                         &lna_enable_gpio[wiring_id],
+                         &pa_enable_gpio[wiring_id],
+                         &rx_active_gpio[wiring_id]);
+
+       if (wiring_id == FEM_WIRING_3_TCV0_2_ELASTIC_4_TCV1_2 ||
+           wiring_id == FEM_WIRING_4_TCV0_2_ELASTIC_4_TCV1_2 ||
+           wiring_id == FEM_WIRING_5_TCV0_2_ELASTIC_4_TCV1_2 ||
+           wiring_id == FEM_WIRING_6_TCV0_2_ELASTIC_4_TCV1_2)
+               update_formation_1_band_select(chip);
+
+       return 0;
+}
+
+int cl_fem_set_system_mode(struct cl_hw *cl_hw, u8 fem_system_mode, u8 fem_ant)
+{
+       struct cl_chip *chip = cl_hw->chip;
+
+       if (fem_system_mode > FEM_MODE_MAX && fem_system_mode != FEM_MODE_OPERETIONAL)
+               return -1;
+
+       cl_dbg_trace(cl_hw, "fem_system_mode: old value = %u -> new value = %u\n",
+                    cl_hw->fem_system_mode, fem_system_mode);
+
+       if (fem_system_mode == FEM_MODE_OPERETIONAL) {
+               cl_fem_conf_gpio(chip);
+               chip->lna_bypass_mode_set = 0;
+       } else if (!chip->lna_bypass_mode_set) {
+               cl_dbg_trace(cl_hw, "fem_system_mode: Set GPIO to LNA Bypass Mode.\n");
+               set_lna_bypass_gpio(chip);
+               chip->lna_bypass_mode_set = 1;
+       }
+
+       cl_hw->fem_system_mode = fem_system_mode;
+       cl_hw->fem_ant = fem_ant;
+       return 0;
+}
+
+int cl_fem_update_conf_params(struct cl_chip *chip)
+{
+       u32 ricu_fem_conf_0, ricu_fem_conf_1 = 0;
+
+       if (cl_fem_read_lut(chip))
+               return -1;
+
+       if (cl_fem_check_lut_validity(chip, chip->fem.wiring_id))
+               return -1;
+
+       /* In case of invalid platform id, don't update FEM conf params*/
+       if (cl_fem_set_lut_off(chip))
+               return -1;
+
+       cl_fem_get_conf_params(chip, &ricu_fem_conf_0, &ricu_fem_conf_1);
+       ricu_fem_conf_0_set(chip, ricu_fem_conf_0);
+       ricu_fem_conf_1_set(chip, ricu_fem_conf_1);
+
+       if (cl_fem_conf_gpio(chip))
+               return -1;
+
+       cl_fem_set_registers(chip);
+
+       return 0;
+}
+
+static int cl_fem_write_wiring_id(struct cl_chip *chip, u8 wiring_id)
+{
+       if (wiring_id >= FEM_WIRING_MAX) {
+               cl_dbg_chip_err(chip, "wiring_id %u is not valid. [0..%u] are valid values\n",
+                               wiring_id, (FEM_WIRING_MAX - 1));
+               return -1;
+       }
+
+       if (cl_fem_check_lut_validity(chip, wiring_id))
+               return -1;
+
+       /* Write wiring ID to eeprom */
+       if (cl_e2p_write(chip, &wiring_id, SIZE_FEM_WIRING_ID, ADDR_FEM_WIRING_ID))
+               return -1;
+
+       chip->fem.wiring_id = wiring_id;
+       cl_dbg_chip_verbose(chip, "wiring_id is %u\n", chip->fem.wiring_id);
+
+       return 0;
+}
+
+static void update_set_channel_fem(struct cl_chip *chip, struct cl_hw *cl_hw)
+{
+       if (cl_hw && cl_chip_is_tcv_enabled(chip, cl_hw->tcv_idx))
+               cl_msg_tx_set_channel(cl_hw, cl_hw->channel, cl_hw->bw, cl_hw->primary_freq,
+                                     cl_hw->center_freq);
+}
+
+int cl_fem_set_wiring_id(struct cl_chip *chip, u8 wiring_id)
+{
+       int ret = cl_fem_write_wiring_id(chip, wiring_id);
+
+       if (ret)
+               return ret;
+
+       ret = cl_fem_update_conf_params(chip);
+
+       if (ret) {
+               cl_dbg_chip_err(chip, "Error occurred while updating configuration parameters.\n");
+               return ret;
+       }
+
+       update_set_channel_fem(chip, chip->cl_hw_tcv0);
+       update_set_channel_fem(chip, chip->cl_hw_tcv1);
+
+       cl_dbg_chip_trace(chip, "wiring_id = %u\n", chip->fem.wiring_id);
+
+       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.
________________________________


^ permalink raw reply related	[flat|nested] 262+ messages in thread

* [RFC v1 084/256] cl8k: add fem.h
  2021-06-17 15:58 [RFC v1 000/256] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (82 preceding siblings ...)
  2021-06-17 15:59 ` [RFC v1 083/256] cl8k: add fem.c viktor.barna
@ 2021-06-17 15:59 ` viktor.barna
  2021-06-17 15:59 ` [RFC v1 085/256] cl8k: add fem_common.h viktor.barna
                   ` (173 subsequent siblings)
  257 siblings, 0 replies; 262+ messages in thread
From: viktor.barna @ 2021-06-17 15:59 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Oleksandr Savchenko, Shay Bar, Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

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

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 drivers/net/wireless/celeno/cl8k/fem.h | 32 ++++++++++++++++++++++++++
 1 file changed, 32 insertions(+)
 create mode 100644 drivers/net/wireless/celeno/cl8k/fem.h

diff --git a/drivers/net/wireless/celeno/cl8k/fem.h b/drivers/net/wireless/celeno/cl8k/fem.h
new file mode 100644
index 000000000000..8fcef76c7a61
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/fem.h
@@ -0,0 +1,32 @@
+/* SPDX-License-Identifier: MIT */
+/* Copyright(c) 2019-2021, Celeno Communications Ltd. */
+
+#ifndef CL_FEM_H
+#define CL_FEM_H
+
+#include "fem_common.h"
+
+/**
+ * FEM (=Front End Module)
+ */
+
+enum fem_mode {
+       FEM_MODE_LNA_BYPASS_ONLY = 0,
+       FEM_MODE_TX_ONLY = 1,
+       FEM_MODE_RX_ONLY = 2,
+
+       FEM_MODE_MAX,
+       FEM_MODE_OPERETIONAL = 255
+};
+
+struct cl_chip;
+
+int cl_fem_init(struct cl_chip *chip);
+int cl_fem_read_wiring_id(struct cl_chip *chip);
+int cl_fem_set_wiring_id(struct cl_chip *chip, u8 wiring_id);
+
+int cl_fem_get_registers(struct cl_hw *cl_hw, u32 fem_data[FEM_REGISTERS_AMOUNT]);
+int cl_fem_set_system_mode(struct cl_hw *cl_hw, u8 fem_system_mode, u8 fem_ant);
+int cl_fem_update_conf_params(struct cl_chip *chip);
+
+#endif /* CL_FEM_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.
________________________________


^ permalink raw reply related	[flat|nested] 262+ messages in thread

* [RFC v1 085/256] cl8k: add fem_common.h
  2021-06-17 15:58 [RFC v1 000/256] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (83 preceding siblings ...)
  2021-06-17 15:59 ` [RFC v1 084/256] cl8k: add fem.h viktor.barna
@ 2021-06-17 15:59 ` viktor.barna
  2021-06-17 15:59 ` [RFC v1 086/256] cl8k: add fw/fw_dbg.c viktor.barna
                   ` (172 subsequent siblings)
  257 siblings, 0 replies; 262+ messages in thread
From: viktor.barna @ 2021-06-17 15:59 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Oleksandr Savchenko, Shay Bar, Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

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

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 drivers/net/wireless/celeno/cl8k/fem_common.h | 79 +++++++++++++++++++
 1 file changed, 79 insertions(+)
 create mode 100644 drivers/net/wireless/celeno/cl8k/fem_common.h

diff --git a/drivers/net/wireless/celeno/cl8k/fem_common.h b/drivers/net/wireless/celeno/cl8k/fem_common.h
new file mode 100644
index 000000000000..9c0d165fb6b8
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/fem_common.h
@@ -0,0 +1,79 @@
+/* SPDX-License-Identifier: MIT */
+/* Copyright(c) 2019-2021, Celeno Communications Ltd. */
+
+#ifndef CL_FEM_COMMON_H
+#define CL_FEM_COMMON_H
+
+#define FEM_LUTS_PER_REGISTER  2
+#define FEM_LUT_AMOUNT_PER_MAC 6
+#define FEM_REGISTERS_AMOUNT   (FEM_LUT_AMOUNT_PER_MAC / FEM_LUTS_PER_REGISTER)
+
+/* Also needed for iw (e2p.c) in utils, so needed to be separated from the other definitions. */
+enum fem_wiring_id {
+       /* TCV0 - 6 FEMs 3 wires, TCV1 - 6 FEMs 2 wires */
+       FEM_WIRING_0_TCV0_6_TCV1_6           = 0,
+       /* TCV0 - 6 FEMs 2 wires, TCV1 - 6 FEMs 2 wires */
+       FEM_WIRING_1_TCV0_6_TCV1_6           = 1,
+       /* TCV0 - 6 FEMs 2 wires, TCV1 - 6 FEMs 3 wires */
+       FEM_WIRING_2_TCV0_6_TCV1_6           = 2,
+       /* TCV0 - 2 FEMs 3 wires, Elastic - 4 FEMs 3 wires, TCV1 - 2 FEMs 2 wires */
+       FEM_WIRING_3_TCV0_2_ELASTIC_4_TCV1_2 = 3,
+       /* TCV0 - 2 FEMs 2 wires, Elastic - 4 FEMs 3 wires, TCV1 - 2 FEMs 2 wires */
+       FEM_WIRING_4_TCV0_2_ELASTIC_4_TCV1_2 = 4,
+       /* TCV0 - 2 FEMs 3 wires, Elastic - 4 FEMs 3 wires, TCV1 - 2 FEMs 3 wires */
+       FEM_WIRING_5_TCV0_2_ELASTIC_4_TCV1_2 = 5,
+       /* TCV0 - 2 FEMs 2 wires, Elastic - 4 FEMs 3 wires, TCV1 - 2 FEMs 3 wires */
+       FEM_WIRING_6_TCV0_2_ELASTIC_4_TCV1_2 = 6,
+       /* TCV0 - 4 FEMs 3 wires, TCV1 - 4 FEMs 2 wires */
+       FEM_WIRING_7_TCV0_4_TCV1_4           = 7,
+       /* TCV0 - 4 FEMs 3 wires, TCV1 - 4 FEMs 3 wires */
+       FEM_WIRING_8_TCV0_4_TCV1_4           = 8,
+       /* TCV0 - 4 FEMs 2 wires, TCV1 - 4 FEMs 2 wires */
+       FEM_WIRING_9_TCV0_4_TCV1_4           = 9,
+       /* TCV0 - 4 FEMs 3 wires, TCV1 - 4 FEMs 3 wires */
+       FEM_WIRING_10_TCV0_4_TCV1_4          = 10,
+       /* TCV0 - 4 FEMs 3 wires, TCV1 - 4 LNAs (RX only) */
+       FEM_WIRING_11_TCV0_4_TCV1_4_RX_ONLY  = 11,
+       /* TCV0 - 4 FEMs 2 wires, TCV1 - 4 LNAs (RX only) */
+       FEM_WIRING_12_TCV0_4_TCV1_4_RX_ONLY  = 12,
+       /* TCV0 - 6 FEMs 3 wires, TCV1 - 6 FEMs 2 wires (not active), 2 LNAs 1 wire (not active) */
+       FEM_WIRING_13_SENSING_4RX_2TX        = 13,
+       /* TCV0 - 6 FEMs 3 wires (4 active), TCV1 - 6 FEMs 2 wires (not active), 2 LNAs 1 wire */
+       FEM_WIRING_14_SENSING_4TX_2RX        = 14,
+       /* TCV0 - 4 FEMs 3 wires, TCV1 - 4 FEMs (RX only) */
+       FEM_WIRING_15_CHAMELEON_4TX_4RX      = 15,
+       /* TCV0 - 2 FEMs 3 wires, TCV1 - 2 FEMs 2 wires (CL8040) */
+       FEM_WIRING_16_TCV0_2_TCV1_2          = 16,
+       /* TCV0 - 4 FEMs 2 wires, TCV1 - 0 FEMs (CL8046) */
+       FEM_WIRING_17_TCV0_4_TCV1_0          = 17,
+       /* TCV0 - 4 FEMs 3 wires, TCV1 - 4 FEMs 3 wires */
+       FEM_WIRING_18_TCV0_4_TCV1_4          = 18,
+       /* TCV0 - 2 FEMs 3 wires, TCV1 - 2 FEMs 3 wires (EVB swapped) */
+       FEM_WIRING_19_TCV0_2_TCV1_2_SWAPPED  = 19,
+       /* TCV0 - 4 FEMs 3 wires, TCV1 - 2 FEMs 2 wires (CL8060 4+2) */
+       FEM_WIRING_20_TCV0_4_TCV1_2          = 20,
+       /* TCV0 - 4 FEMs 3 wires, TCV1 - 2 LNAs (RX only) (CL8066 4+2) */
+       FEM_WIRING_21_TCV0_4_TCV1_2          = 21,
+
+       FEM_WIRING_MAX,
+       FEM_WIRING_DEFAULT = 255
+};
+
+enum fem_type {
+       FEM_TYPE_TCV0    = 0,
+       FEM_TYPE_TCV1    = 1,
+       FEM_TYPE_ELASTIC = 2,
+       FEM_TYPE_SENSING = 3,
+
+       FEM_TYPE_MAX,
+};
+
+#define FEM_LUT_EMPTY 0x0
+
+#define FEM_TYPE_STR(type) \
+       ((type == FEM_TYPE_TCV0) ? "TCV0" : \
+       ((type == FEM_TYPE_TCV1) ? "TCV1" : \
+       ((type == FEM_TYPE_ELASTIC) ? "ELASTIC" : \
+       ((type == FEM_TYPE_SENSING) ? "SENSING" : "ERROR"))))
+
+#endif /* CL_FEM_COMMON_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.
________________________________


^ permalink raw reply related	[flat|nested] 262+ messages in thread

* [RFC v1 086/256] cl8k: add fw/fw_dbg.c
  2021-06-17 15:58 [RFC v1 000/256] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (84 preceding siblings ...)
  2021-06-17 15:59 ` [RFC v1 085/256] cl8k: add fem_common.h viktor.barna
@ 2021-06-17 15:59 ` viktor.barna
  2021-06-17 15:59 ` [RFC v1 087/256] cl8k: add fw/fw_dbg.h viktor.barna
                   ` (171 subsequent siblings)
  257 siblings, 0 replies; 262+ messages in thread
From: viktor.barna @ 2021-06-17 15:59 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Oleksandr Savchenko, Shay Bar, Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

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

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 drivers/net/wireless/celeno/cl8k/fw/fw_dbg.c | 2686 ++++++++++++++++++
 1 file changed, 2686 insertions(+)
 create mode 100644 drivers/net/wireless/celeno/cl8k/fw/fw_dbg.c

diff --git a/drivers/net/wireless/celeno/cl8k/fw/fw_dbg.c b/drivers/net/wireless/celeno/cl8k/fw/fw_dbg.c
new file mode 100644
index 000000000000..413f45b433c6
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/fw/fw_dbg.c
@@ -0,0 +1,2686 @@
+// SPDX-License-Identifier: MIT
+/* Copyright(c) 2019-2021, Celeno Communications Ltd. */
+#include <linux/utsname.h>
+
+#include "utils/utils.h"
+#include "fw/fw_dbg.h"
+#ifdef CONFIG_CL_PCIE
+#include "bus/pci/ipc.h"
+#endif
+#include "band.h"
+#include "chip.h"
+#include "coredump.h"
+#include "ela.h"
+#include "utils/file.h"
+#include "dbgfile.h"
+#include "rx/rx.h"
+#include "fw/msg_tx.h"
+
+/* Work struct wrapper for print statistics */
+struct cl_print_stats_work {
+       struct work_struct ws;
+       struct cl_hw *cl_hw;
+       u32 dbg_info_type;
+};
+
+#define FW_DBG_INVALID_SESSION U8_MAX
+
+#define PRINT_FW(cl_hw, fmt, ...) \
+       pr_debug("%cmac%u " fmt, (cl_hw)->fw_prefix, (cl_hw)->chip->idx, ##__VA_ARGS__)
+
+/*
+ * Display 2 digit decimal fraction.
+ * Example: x = 541, y = 19 = 28.47368
+ *   ==> 47
+ */
+#define DECIMAL_FRACTION_X2(x, y) (100 * ((x) - (y) * ((x) / (y))) / (y))
+
+static void cl_print_tx_stats(struct cl_hw *cl_hw, struct cl_txl_statistics *tx_stats)
+{
+       int i;
+       u8 per = 0;
+       u64 total_retry = 0;
+       u64 total_tx = 0;
+       u32 total_natt = 0;
+       u32 avg_backoff = 0;
+       u32 agg_size_total = 0;
+       u32 agg_size_x100 = 0;
+       u32 total_vns_off = 0;
+       u32 total_vns_on = 0;
+       bool is_agg_in_txop = false;
+       struct cl_txl_agg_statistics *agg = &tx_stats->agg;
+       struct cl_txl_htp_statistics *htp = &tx_stats->htp;
+       struct cl_txl_natt_statistics *natt = &tx_stats->natt;
+       struct cl_txl_vns_statistics *vns = &tx_stats->vns;
+       struct cl_txl_fec_statistics *fec = &tx_stats->fec;
+       struct cl_txl_backoff_params *backoff_params = &tx_stats->backoff_params;
+       struct cl_txl_rts_cts_statistics *rts_cts = &tx_stats->rts_cts;
+       struct cl_txl_underrun_statistics *underrun = &tx_stats->underrun;
+
+       const char *fw_tx_backoff_str[CL_MAX_FRM_TYPE] = {
+               [CE_BACKOFF_25]          = "<25",
+               [CE_BACKOFF_50]          = "50",
+               [CE_BACKOFF_100]         = "100",
+               [CE_BACKOFF_500]         = "500",
+               [CE_BACKOFF_1000]        = "1000",
+               [CE_BACKOFF_5000]        = "5000",
+               [CE_BACKOFF_10000]       = "10000",
+               [CE_BACKOFF_20000]       = "20000",
+               [CE_BACKOFF_20000_ABOVE] = ">20000",
+       };
+
+       /* Singles info */
+       PRINT_FW(cl_hw, "TX statistics - singles\n");
+       PRINT_FW(cl_hw, "------------------------------------------------------------------\n");
+       PRINT_FW(cl_hw, "| q |sent      |retry     |lft exp   |ret limit |ret lim ps|per %%|\n");
+       PRINT_FW(cl_hw, "|---+----------+----------+----------+----------+----------+-----|\n");
+
+       for (i = 0; i < IPC_TX_QUEUE_CNT; i++) {
+               total_retry = tx_stats->single[i].total_rtx_cnt +
+                       tx_stats->single[i].total_lifetime_expired_cnt +
+                       tx_stats->single[i].total_rtx_limit_reached;
+
+               total_tx = tx_stats->single[i].total_cnt + total_retry;
+
+               if (total_tx == 0)
+                       continue;
+
+               per = (u8)div64_u64(total_retry * 100, total_tx);
+
+               PRINT_FW(cl_hw, "|%3u|%10u|%10u|%10u|%10u|%10u|%5u|\n",
+                        i,
+                        tx_stats->single[i].total_cnt,
+                        tx_stats->single[i].total_rtx_cnt,
+                        tx_stats->single[i].total_lifetime_expired_cnt,
+                        tx_stats->single[i].total_rtx_limit_reached,
+                        tx_stats->single[i].total_rtx_limit_reached_ps,
+                        per);
+       }
+
+       PRINT_FW(cl_hw, "------------------------------------------------------------------\n");
+       PRINT_FW(cl_hw, "\n");
+
+       /* Aggregation info */
+       PRINT_FW(cl_hw, "TX statistics - aggregations - MAX [%u]\n", IPC_MAX_BA_SESSIONS);
+       PRINT_FW(cl_hw, "-----------------------------------------------------------------------------------------------------------------------------\n");
+       PRINT_FW(cl_hw, "|Q |Total    |Total    |Lifetime|Retry |BA       |BA not   |BA     |BA     |BA    |Below BA|Above BA|ACK    |PS BA not|Total|\n");
+       PRINT_FW(cl_hw, "|  |sent     |retry    |expired |Limit |received |received |Cleared|Invalid|un-exp|window  |window  |inst BA|received |Per %%|\n");
+       PRINT_FW(cl_hw, "|--+---------+---------+--------+------+---------+---------+-------+-------+------+--------+--------+-------+---------+-----|\n");
+
+       for (i = 0; i < IPC_MAX_BA_SESSIONS; i++) {
+               total_retry = tx_stats->ba[i].total_rtx_cnt +
+                       tx_stats->ba[i].total_lifetime_expired_cnt +
+                       tx_stats->ba[i].total_rtx_limit_reached;
+
+               total_tx = tx_stats->ba[i].total_cnt;
+
+               if (total_tx == 0)
+                       continue;
+
+               per = (u8)div64_u64(total_retry * 100, total_tx);
+
+               PRINT_FW(cl_hw, "|%2u|%9u|%9u|%8u|%6u|%9u|%9u|%7u|%7u|%6u|%8u|%8u|%7u|%9u|%5u|\n",
+                        i,
+                        tx_stats->ba[i].total_cnt,
+                        tx_stats->ba[i].total_rtx_cnt,
+                        tx_stats->ba[i].total_lifetime_expired_cnt,
+                        tx_stats->ba[i].total_rtx_limit_reached,
+                        tx_stats->ba[i].total_ba_received,
+                        tx_stats->ba[i].total_ba_not_received_cnt,
+                        tx_stats->ba[i].total_cleard_ba,
+                        tx_stats->ba[i].total_invalid_ba,
+                        tx_stats->ba[i].total_unexpected_ba,
+                        tx_stats->ba[i].total_packets_below_baw,
+                        tx_stats->ba[i].total_packets_above_baw,
+                        tx_stats->ba[i].total_ack_instead_ba,
+                        tx_stats->ba[i].total_ba_not_received_cnt_ps,
+                        per);
+       }
+       PRINT_FW(cl_hw, "-----------------------------------------------------------------------------------------------------------------------------\n");
+       PRINT_FW(cl_hw, "\n");
+
+       /* TID info */
+       PRINT_FW(cl_hw, "----------------\n");
+       PRINT_FW(cl_hw, "|TID|NumPackets|\n");
+       PRINT_FW(cl_hw, "|---+----------|\n");
+
+       for (i = 0; i < TID_MAX; i++) {
+               if (tx_stats->tid[i].total_tid_desc_cnt == 0)
+                       continue;
+
+               PRINT_FW(cl_hw, "|%3d|%10u|\n", i, tx_stats->tid[i].total_tid_desc_cnt);
+       }
+
+       PRINT_FW(cl_hw, "----------------\n");
+       PRINT_FW(cl_hw, "\n");
+
+       /* AC info */
+       PRINT_FW(cl_hw, "---------------------------------------------------------------------\n");
+       PRINT_FW(cl_hw, "|     AC     |    0     |    1     |    2     |    3     |    4     |\n");
+       PRINT_FW(cl_hw, "|------------+----------+----------+----------+----------+----------|\n");
+       PRINT_FW(cl_hw, "|Num switches|%10u|%10u|%10u|%10u|%10u|\n",
+                tx_stats->ac[0].total_q_switch_cnt,
+                tx_stats->ac[1].total_q_switch_cnt,
+                tx_stats->ac[2].total_q_switch_cnt,
+                tx_stats->ac[3].total_q_switch_cnt,
+                tx_stats->ac[4].total_q_switch_cnt);
+       PRINT_FW(cl_hw, "|Num txdesc  |%10u|%10u|%10u|%10u|%10u|\n",
+                tx_stats->ac[0].total_ac_desc_cnt,
+                tx_stats->ac[1].total_ac_desc_cnt,
+                tx_stats->ac[2].total_ac_desc_cnt,
+                tx_stats->ac[3].total_ac_desc_cnt,
+                tx_stats->ac[4].total_ac_desc_cnt);
+       PRINT_FW(cl_hw, "---------------------------------------------------------------------\n");
+       PRINT_FW(cl_hw, "\n");
+
+       /* Underrun info */
+       if (underrun->length_cnt || underrun->pattern_cnt) {
+               PRINT_FW(cl_hw, "======== Underrun recovery statistics =======\n");
+               PRINT_FW(cl_hw, "Length underrun %u\n",
+                        underrun->length_cnt);
+               PRINT_FW(cl_hw, "Pattern underrun %u\n",
+                        underrun->pattern_cnt);
+               PRINT_FW(cl_hw, "Total frames flushed in underrun %u\n",
+                        underrun->flushed_frames_cnt);
+               PRINT_FW(cl_hw, "\n");
+       }
+
+       /* BW drop fail info */
+       if (tx_stats->tx_obtain_bw_fail_cnt) {
+               PRINT_FW(cl_hw, "Failed to obtain BW count %u\n", tx_stats->tx_obtain_bw_fail_cnt);
+               PRINT_FW(cl_hw, "\n");
+       }
+
+       /* Backoff time info */
+       PRINT_FW(cl_hw, "Backoff Time [us]\n");
+       PRINT_FW(cl_hw, "------------------------------------------------------\n");
+       PRINT_FW(cl_hw, "|Backoff |   AC 0   |   AC 1   |   AC 2   |   AC 3   |\n");
+
+       for (i = 0; i < CE_BACKOFF_MAX; i++) {
+               if (tx_stats->backoff_stats[AC_BK].backoff_hist[i] == 0 &&
+                   tx_stats->backoff_stats[AC_BE].backoff_hist[i] == 0 &&
+                   tx_stats->backoff_stats[AC_VI].backoff_hist[i] == 0 &&
+                   tx_stats->backoff_stats[AC_VO].backoff_hist[i] == 0)
+                       continue;
+
+               PRINT_FW(cl_hw, "|--------+----------+----------+----------+----------|\n");
+               PRINT_FW(cl_hw, "| %6s |%10u|%10u|%10u|%10u|\n",
+                        fw_tx_backoff_str[i],
+                        tx_stats->backoff_stats[AC_BK].backoff_hist[i],
+                        tx_stats->backoff_stats[AC_BE].backoff_hist[i],
+                        tx_stats->backoff_stats[AC_VI].backoff_hist[i],
+                        tx_stats->backoff_stats[AC_VO].backoff_hist[i]);
+       }
+
+       PRINT_FW(cl_hw, "------------------------------------------------------\n");
+       PRINT_FW(cl_hw, "\n");
+
+       /* AMSDU Packet cnt */
+       PRINT_FW(cl_hw, "|--------------------|\n");
+       PRINT_FW(cl_hw, "|  AMSDU Packet cnt  |\n");
+       PRINT_FW(cl_hw, "|--------------------|\n");
+       for (i = 0; i < IPC_MAX_BA_SESSIONS; i++) {
+               if (agg->amsdu_stat[i].packet_cnt_2 == 0 &&
+                   agg->amsdu_stat[i].packet_cnt_3 == 0 &&
+                   agg->amsdu_stat[i].packet_cnt_4 == 0 &&
+                   agg->amsdu_stat[i].packet_cnt_5_or_more == 0)
+                       continue;
+
+               PRINT_FW(cl_hw, "# session=%u\n", i);
+               PRINT_FW(cl_hw, "packet_cnt  = 2: [%u]\n",
+                        agg->amsdu_stat[i].packet_cnt_2);
+               PRINT_FW(cl_hw, "packet_cnt  = 3: [%u]\n",
+                        agg->amsdu_stat[i].packet_cnt_3);
+               PRINT_FW(cl_hw, "packet_cnt  = 4: [%u]\n",
+                        agg->amsdu_stat[i].packet_cnt_4);
+               PRINT_FW(cl_hw, "packet_cnt >= 5: [%u]\n",
+                        agg->amsdu_stat[i].packet_cnt_5_or_more);
+               PRINT_FW(cl_hw, "\n");
+       }
+       PRINT_FW(cl_hw, "\n");
+
+       /* Agg statistics */
+       for (i = 1; i < CL_MAX_AGG_IN_TXOP; i++) {
+               if (agg->agg_in_txop_statistics[i]) {
+                       is_agg_in_txop = true;
+                       break;
+               }
+       }
+
+       if (is_agg_in_txop) {
+               /* Agg in TXOP */
+               PRINT_FW(cl_hw, "Agg in TXOP\n");
+               PRINT_FW(cl_hw, "|----------------|\n");
+               PRINT_FW(cl_hw, "| Agg |  Count   |\n");
+               PRINT_FW(cl_hw, "|-----+----------|\n");
+
+               for (i = 1; i < CL_MAX_AGG_IN_TXOP; i++) {
+                       if (!agg->agg_in_txop_statistics[i])
+                               continue;
+
+                       PRINT_FW(cl_hw, "|%5u|%10u|\n",
+                                i + 1, agg->agg_in_txop_statistics[i]);
+               }
+
+               PRINT_FW(cl_hw, "|----------------|\n");
+               PRINT_FW(cl_hw, "\n");
+
+               /* Agg close reason & Agg queue switch */
+               PRINT_FW(cl_hw, "Agg close reason:\n");
+               PRINT_FW(cl_hw, "  Not enough txdescs = %u\n",
+                        agg->agg_in_txop_close_reason[AGG_IN_TXOP_CLOSE_REASON_NO_TXDESC]);
+               PRINT_FW(cl_hw, "  TXOP expired       = %u\n",
+                        agg->agg_in_txop_close_reason[AGG_IN_TXOP_CLOSE_REASON_TXOP_EXPIRED]);
+               PRINT_FW(cl_hw, "  Delba in process   = %u\n",
+                        agg->agg_in_txop_close_reason[AGG_IN_TXOP_CLOSE_REASON_ACTIVE_DELBA]);
+               PRINT_FW(cl_hw, "Agg queue switch:\n");
+               PRINT_FW(cl_hw, "  Queue switch within TXOP               = %u\n",
+                        agg->agg_in_txop_queue_switch);
+               PRINT_FW(cl_hw, "  Queue switch abort due diff bw in TXOP = %u\n",
+                        agg->agg_in_txop_queue_switch_abort_bw);
+               PRINT_FW(cl_hw, "\n");
+       }
+
+       /* RTS-CTS statistics */
+       if (rts_cts->fw_rts_cnt ||
+           rts_cts->fw_cts_cnt ||
+           rts_cts->hw_rts_cnt ||
+           rts_cts->hw_cts_cnt) {
+               PRINT_FW(cl_hw, "RTS-CTS statistics\n");
+               PRINT_FW(cl_hw, "==================\n");
+               PRINT_FW(cl_hw, "FW RTS frame count = %u\n", rts_cts->fw_rts_cnt);
+               PRINT_FW(cl_hw, "FW CTS frame count = %u\n", rts_cts->fw_cts_cnt);
+               PRINT_FW(cl_hw, "HW RTS frame count = %u\n", rts_cts->hw_rts_cnt);
+               PRINT_FW(cl_hw, "HW CTS frame count = %u\n", rts_cts->hw_cts_cnt);
+               PRINT_FW(cl_hw, "\n");
+       }
+
+       /* Natt statistics */
+       PRINT_FW(cl_hw, "natt statistics\n");
+       PRINT_FW(cl_hw, "===============\n");
+       PRINT_FW(cl_hw, "agg size[0] = %u <singeltons>\n", agg->agg_size_statistics[0]);
+       PRINT_FW(cl_hw, "\n");
+
+       PRINT_FW(cl_hw, "-----------------------------------------------------------\n");
+       PRINT_FW(cl_hw, "|agg | num sent |percent | pass per | drop per | PER per  |\n");
+       PRINT_FW(cl_hw, "|size| per size |per size| agg size | agg size | agg size |\n");
+       PRINT_FW(cl_hw, "|----+----------+--------+----------+----------+----------|\n");
+
+       for (i = 1; i < DBG_STATS_MAX_AGG_SIZE; i++)
+               agg_size_total += agg->agg_size_statistics[i];
+
+       for (i = 1; i < DBG_STATS_MAX_AGG_SIZE; i++) {
+               if (agg->agg_size_statistics[i] == 0)
+                       continue;
+
+               total_natt = agg->packet_failed_statistics[i] + agg->packet_passed_statistics[i];
+
+               if (total_natt == 0)
+                       continue;
+
+               agg_size_x100 = 100 * agg->agg_size_statistics[i];
+
+               PRINT_FW(cl_hw, "|%4u|%10u|%5u.%02u|%10u|%10u|%10u|\n",
+                        i,
+                        agg->agg_size_statistics[i],
+                        agg_size_x100 / agg_size_total,
+                        DECIMAL_FRACTION_X2(agg_size_x100, agg_size_total),
+                        agg->packet_passed_statistics[i],
+                        agg->packet_failed_statistics[i],
+                        ((agg->packet_failed_statistics[i] * 100) / total_natt));
+       }
+       PRINT_FW(cl_hw, "-----------------------------------------------------------\n");
+       PRINT_FW(cl_hw, "Amount of all su aggregations: %u\n", agg_size_total);
+       PRINT_FW(cl_hw, "\n");
+
+       /* Natt statistics (HTP flows) */
+       PRINT_FW(cl_hw, "natt statistics HTP flows\n");
+       PRINT_FW(cl_hw, "=========================\n");
+       PRINT_FW(cl_hw, "-----------------------------------------------------------\n");
+       PRINT_FW(cl_hw, "|agg |num sent| percent  | pass per | drop per | PER per  |\n");
+       PRINT_FW(cl_hw, "|size|per size| per size | agg size | agg size | agg size |\n");
+       PRINT_FW(cl_hw, "|----+--------+----------+----------+----------+----------|\n");
+
+       agg_size_total = 0;
+       for (i = 1; i < DBG_STATS_MAX_AGG_SIZE; i++)
+               agg_size_total += agg->htp_agg_size_statistics[i];
+
+       for (i = 1; i < DBG_STATS_MAX_AGG_SIZE; i++) {
+               if (agg->htp_agg_size_statistics[i] == 0)
+                       continue;
+
+               total_natt = agg->htp_packet_failed_statistics[i] +
+                       agg->htp_packet_passed_statistics[i];
+
+               if (total_natt == 0)
+                       continue;
+
+               agg_size_x100 = 100 * agg->htp_agg_size_statistics[i];
+
+               PRINT_FW(cl_hw, "|%4u|%10u|%5u.%02u|%10u|%10u|%10u|\n",
+                        i,
+                        agg->htp_agg_size_statistics[i],
+                        agg_size_x100 / agg_size_total,
+                        DECIMAL_FRACTION_X2(agg_size_x100, agg_size_total),
+                        agg->htp_packet_passed_statistics[i],
+                        agg->htp_packet_failed_statistics[i],
+                        (agg->htp_agg_size_statistics[i] * 100 / total_natt));
+       }
+       PRINT_FW(cl_hw, "-----------------------------------------------------------\n");
+       PRINT_FW(cl_hw, "\n");
+
+       /* Chosen frame BW */
+       PRINT_FW(cl_hw, "Chosen frame BW\n");
+       for (i = 0; i < NATT_BW_MAX; i++)
+               PRINT_FW(cl_hw, "BW[%u] = %u\n", i, natt->chosen_frame_bw[i]);
+       PRINT_FW(cl_hw, "\n");
+
+       /* Natt operation mode */
+       PRINT_FW(cl_hw, "Natt operation mode\n");
+       for (i = 0; i < 8; i++)
+               if (natt->operation_mode[i] != 0)
+                       PRINT_FW(cl_hw, "[0x%x] = %u\n", i, natt->operation_mode[i]);
+       PRINT_FW(cl_hw, "\n");
+
+       /* Natt agg close reason */
+       PRINT_FW(cl_hw, "natt agg close reason\n");
+       PRINT_FW(cl_hw, "=====================\n");
+       PRINT_FW(cl_hw, "Max length exceed  %u\n", natt->agg_close_reason[NATT_REASON_MAX_LEN]);
+       PRINT_FW(cl_hw, "TXOP limit exceed  %u\n", natt->agg_close_reason[NATT_REASON_TXOP_LIMIT]);
+       PRINT_FW(cl_hw, "MPDU number exceed %u\n", natt->agg_close_reason[NATT_REASON_MPDU_NUM]);
+       PRINT_FW(cl_hw, "\n");
+
+       /* Recovery count */
+       if (tx_stats->recovery_count) {
+               PRINT_FW(cl_hw, "Recovery count\n");
+               PRINT_FW(cl_hw, "==============\n");
+               PRINT_FW(cl_hw, "Total: %u\n", tx_stats->recovery_count);
+               PRINT_FW(cl_hw, "\n");
+       }
+
+       /* Singelton backoff_params time */
+       PRINT_FW(cl_hw, "Singelton backoff_params time:\n");
+       for (i = 0; i < AC_MAX; i++) {
+               if (backoff_params->singelton_cnt[i]) {
+                       avg_backoff = backoff_params->singelton_total[i] /
+                               backoff_params->singelton_cnt[i];
+                       PRINT_FW(cl_hw, "ac%d avarage backoff_params %u\n", i, avg_backoff);
+               } else {
+                       PRINT_FW(cl_hw, "ac%d avarage backoff_params 0\n", i);
+               }
+       }
+       PRINT_FW(cl_hw, "\n");
+
+       /* Aggregation backoff_params time */
+       PRINT_FW(cl_hw, "Aggregation backoff_params time:\n");
+       for (i = 0; i < AC_VO; i++) {
+               if (backoff_params->agg_cnt[i]) {
+                       avg_backoff = backoff_params->agg_total[i] /
+                               backoff_params->agg_cnt[i];
+                       PRINT_FW(cl_hw, "ac%d avarage backoff_params %u\n", i, avg_backoff);
+               } else {
+                       PRINT_FW(cl_hw, "ac%d avarage backoff_params 0\n", i);
+               }
+       }
+       PRINT_FW(cl_hw, "\n");
+
+       /* Trigger Based traffic statistics */
+       PRINT_FW(cl_hw, "Trigger Based traffic statistics:\n");
+       for (i = 0; i < TID_MAX; i++)
+               if (htp->total_cnt[i])
+                       PRINT_FW(cl_hw, "TID%d total_cnt %u\n", i, htp->total_cnt[i]);
+       PRINT_FW(cl_hw, "\n");
+
+       if (htp->need_response || htp->tb_response_required) {
+               PRINT_FW(cl_hw, "need_response         = %u\n", htp->need_response);
+               PRINT_FW(cl_hw, "tb_response_required  = %u\n", htp->tb_response_required);
+               PRINT_FW(cl_hw, "ac_not_found          = %u\n", htp->ac_not_found);
+               PRINT_FW(cl_hw, "end_of_packet_int     = %u\n", htp->end_of_packet_int);
+               PRINT_FW(cl_hw, "tb_bw_decision        = %u\n", htp->tb_bw_decision);
+               PRINT_FW(cl_hw, "tb_ba_thd_removed     = %u\n", htp->tb_ba_thd_removed);
+               PRINT_FW(cl_hw, "tb_ac_unchain         = %u\n", htp->tb_ac_unchain);
+               PRINT_FW(cl_hw, "tb_htp_unchain        = %u\n", htp->tb_htp_unchain);
+               PRINT_FW(cl_hw, "tb_dummy_htp_tx       = %u\n", htp->tb_dummy_htp_tx);
+               PRINT_FW(cl_hw, "tb_dummy_no_tx        = %u\n", htp->tb_dummy_no_tx);
+               PRINT_FW(cl_hw, "msta_ba_received      = %u\n", htp->msta_ba_received);
+               PRINT_FW(cl_hw, "msta_ba_aid_not_found = %u\n", htp->msta_ba_aid_not_found);
+       }
+
+       total_vns_off = vns->off_cck + vns->off_ofdm + vns->off_ht_vht + vns->off_he;
+       total_vns_on = vns->on_cck + vns->on_ofdm + vns->on_ht_vht + vns->on_he;
+
+       if (total_vns_off || total_vns_on) {
+               PRINT_FW(cl_hw, "       -----------------------\n");
+               PRINT_FW(cl_hw, "       | VNS-OFF  |  VNS-ON  |\n");
+               PRINT_FW(cl_hw, "-------+----------+----------|\n");
+               PRINT_FW(cl_hw, "|CCK   |%10u|%10u|\n", vns->off_cck, vns->on_cck);
+               PRINT_FW(cl_hw, "|OFDM  |%10u|%10u|\n", vns->off_ofdm, vns->on_ofdm);
+               PRINT_FW(cl_hw, "|HT-VHT|%10u|%10u|\n", vns->off_ht_vht, vns->on_ht_vht);
+               PRINT_FW(cl_hw, "|HE    |%10u|%10u|\n", vns->off_he, vns->on_he);
+               PRINT_FW(cl_hw, "|------+----------+----------|\n");
+               PRINT_FW(cl_hw, "|TOTAL |%10u|%10u|\n", total_vns_off, total_vns_on);
+               PRINT_FW(cl_hw, "------------------------------\n");
+               PRINT_FW(cl_hw, "\n");
+       }
+
+       if (fec->ldpc || fec->bcc) {
+               PRINT_FW(cl_hw, "FEC Coding:\n");
+               PRINT_FW(cl_hw, "LDPC = %u\n", fec->ldpc);
+               PRINT_FW(cl_hw, "BCC  = %u\n", fec->bcc);
+               PRINT_FW(cl_hw, "\n");
+       }
+}
+
+static void cl_print_tx_mu_stats(struct cl_hw *cl_hw, struct cl_txl_statistics *tx_stats)
+{
+       int i;
+       struct cl_txl_agg_statistics *agg = &tx_stats->agg;
+
+       if (agg->mu_stats[CL_MU1_IDX].chain_cnt == 0) {
+               PRINT_FW(cl_hw, "~~~~~~~~~~~~~~~~~~  MU  statistics - EMPTY  ~~~~~~~~~~~~~~~~~~\n");
+               return;
+       }
+
+       PRINT_FW(cl_hw, "~~~~~~~~~~~~~~~~~~~~~~~~~  MU  statistics  ~~~~~~~~~~~~~~~~~~~~~~~~~\n");
+       PRINT_FW(cl_hw, "\n");
+
+#if (MU_MAX_STREAMS >= 4)
+       /* MU status statistics */
+       PRINT_FW(cl_hw, "--------------------------------------------------------\n");
+       PRINT_FW(cl_hw, "|            | MU1 | MU2 | MU3 | MU4 | MU5 | MU6 | MU7 |\n");
+       PRINT_FW(cl_hw, "|------------+-----+-----+-----+-----+-----+-----+-----|\n");
+       PRINT_FW(cl_hw, "|Chain count |%5u|%5u|%5u|%5u|%5u|%5u|%5u|\n",
+                agg->mu_stats[CL_MU1_IDX].chain_cnt,
+                agg->mu_stats[CL_MU2_IDX].chain_cnt,
+                agg->mu_stats[CL_MU3_IDX].chain_cnt,
+                agg->mu_stats[CL_MU4_IDX].chain_cnt,
+                agg->mu_stats[CL_MU5_IDX].chain_cnt,
+                agg->mu_stats[CL_MU6_IDX].chain_cnt,
+                agg->mu_stats[CL_MU7_IDX].chain_cnt);
+       PRINT_FW(cl_hw, "|Status count|%5u|%5u|%5u|%5u|%5u|%5u|%5u|\n",
+                agg->mu_stats[CL_MU1_IDX].status_cnt,
+                agg->mu_stats[CL_MU2_IDX].status_cnt,
+                agg->mu_stats[CL_MU3_IDX].status_cnt,
+                agg->mu_stats[CL_MU4_IDX].status_cnt,
+                agg->mu_stats[CL_MU5_IDX].status_cnt,
+                agg->mu_stats[CL_MU6_IDX].status_cnt,
+                agg->mu_stats[CL_MU7_IDX].status_cnt);
+       PRINT_FW(cl_hw, "--------------------------------------------------------\n");
+       PRINT_FW(cl_hw, "\n");
+
+       /* MU agg-size statistics */
+       PRINT_FW(cl_hw, "------------------------------------------------------------\n");
+       PRINT_FW(cl_hw, "| agg size | MU0 | MU1 | MU2 | MU3 | MU4 | MU5 | MU6 | MU7 |\n");
+       PRINT_FW(cl_hw, "|----------+-----+-----+-----+-----+-----+-----+-----+-----|\n");
+       for (i = 1; i < DBG_STATS_MAX_AGG_SIZE; i++) {
+               if (agg->mu_agg_size_statistics[CL_MU0_IDX][i] ||
+                   agg->mu_agg_size_statistics[CL_MU1_IDX][i] ||
+                   agg->mu_agg_size_statistics[CL_MU2_IDX][i] ||
+                   agg->mu_agg_size_statistics[CL_MU3_IDX][i] ||
+                   agg->mu_agg_size_statistics[CL_MU4_IDX][i] ||
+                   agg->mu_agg_size_statistics[CL_MU5_IDX][i] ||
+                   agg->mu_agg_size_statistics[CL_MU6_IDX][i] ||
+                   agg->mu_agg_size_statistics[CL_MU7_IDX][i]) {
+                       PRINT_FW(cl_hw, "|%10u|%5u|%5u|%5u|%5u|%5u|%5u|%5u|%5u|\n",
+                                i,
+                                agg->mu_agg_size_statistics[CL_MU0_IDX][i],
+                                agg->mu_agg_size_statistics[CL_MU1_IDX][i],
+                                agg->mu_agg_size_statistics[CL_MU2_IDX][i],
+                                agg->mu_agg_size_statistics[CL_MU3_IDX][i],
+                                agg->mu_agg_size_statistics[CL_MU4_IDX][i],
+                                agg->mu_agg_size_statistics[CL_MU5_IDX][i],
+                                agg->mu_agg_size_statistics[CL_MU6_IDX][i],
+                                agg->mu_agg_size_statistics[CL_MU7_IDX][i]);
+               }
+       }
+       PRINT_FW(cl_hw, "------------------------------------------------------------\n");
+       PRINT_FW(cl_hw, "\n");
+
+       /* MU BA statistics */
+       PRINT_FW(cl_hw, "--------------------------------------------------------------------\n");
+       PRINT_FW(cl_hw, "| MU BA statistics | MU0 | MU1 | MU2 | MU3 | MU4 | MU5 | MU6 | MU7 |\n");
+       PRINT_FW(cl_hw, "|------------------+-----+-----+-----+-----+-----+-----+-----+-----|\n");
+       PRINT_FW(cl_hw, "|  BA Received     |%5u|%5u|%5u|%5u|%5u|%5u|%5u|%5u|\n",
+                agg->mu_stats[CL_MU0_IDX].ba_received,
+                agg->mu_stats[CL_MU1_IDX].ba_received,
+                agg->mu_stats[CL_MU2_IDX].ba_received,
+                agg->mu_stats[CL_MU3_IDX].ba_received,
+                agg->mu_stats[CL_MU4_IDX].ba_received,
+                agg->mu_stats[CL_MU5_IDX].ba_received,
+                agg->mu_stats[CL_MU6_IDX].ba_received,
+                agg->mu_stats[CL_MU7_IDX].ba_received);
+       PRINT_FW(cl_hw, "|  --Unexpected BA |%5u|%5u|%5u|%5u|%5u|%5u|%5u|%5u|\n",
+                agg->mu_stats[CL_MU0_IDX].unexpected_ba,
+                agg->mu_stats[CL_MU1_IDX].unexpected_ba,
+                agg->mu_stats[CL_MU2_IDX].unexpected_ba,
+                agg->mu_stats[CL_MU3_IDX].unexpected_ba,
+                agg->mu_stats[CL_MU4_IDX].unexpected_ba,
+                agg->mu_stats[CL_MU5_IDX].unexpected_ba,
+                agg->mu_stats[CL_MU6_IDX].unexpected_ba,
+                agg->mu_stats[CL_MU7_IDX].unexpected_ba);
+       PRINT_FW(cl_hw, "|  --Cleared    BA |%5u|%5u|%5u|%5u|%5u|%5u|%5u|%5u|\n",
+                agg->mu_stats[CL_MU0_IDX].clear_ba,
+                agg->mu_stats[CL_MU1_IDX].clear_ba,
+                agg->mu_stats[CL_MU2_IDX].clear_ba,
+                agg->mu_stats[CL_MU3_IDX].clear_ba,
+                agg->mu_stats[CL_MU4_IDX].clear_ba,
+                agg->mu_stats[CL_MU5_IDX].clear_ba,
+                agg->mu_stats[CL_MU6_IDX].clear_ba,
+                agg->mu_stats[CL_MU7_IDX].clear_ba);
+       PRINT_FW(cl_hw, "|  --Invalid    BA |%5u|%5u|%5u|%5u|%5u|%5u|%5u|%5u|\n",
+                agg->mu_stats[CL_MU0_IDX].invalid_ba,
+                agg->mu_stats[CL_MU1_IDX].invalid_ba,
+                agg->mu_stats[CL_MU2_IDX].invalid_ba,
+                agg->mu_stats[CL_MU3_IDX].invalid_ba,
+                agg->mu_stats[CL_MU4_IDX].invalid_ba,
+                agg->mu_stats[CL_MU5_IDX].invalid_ba,
+                agg->mu_stats[CL_MU6_IDX].invalid_ba,
+                agg->mu_stats[CL_MU7_IDX].invalid_ba);
+       PRINT_FW(cl_hw, "|  --Correct    BA |%5u|%5u|%5u|%5u|%5u|%5u|%5u|%5u|\n",
+                agg->mu_stats[CL_MU0_IDX].correct_ba,
+                agg->mu_stats[CL_MU1_IDX].correct_ba,
+                agg->mu_stats[CL_MU2_IDX].correct_ba,
+                agg->mu_stats[CL_MU3_IDX].correct_ba,
+                agg->mu_stats[CL_MU4_IDX].correct_ba,
+                agg->mu_stats[CL_MU5_IDX].correct_ba,
+                agg->mu_stats[CL_MU6_IDX].correct_ba,
+                agg->mu_stats[CL_MU7_IDX].correct_ba);
+       PRINT_FW(cl_hw, "|  BA not Received |%5u|%5u|%5u|%5u|%5u|%5u|%5u|%5u|\n",
+                agg->mu_stats[CL_MU0_IDX].ba_no_received,
+                agg->mu_stats[CL_MU1_IDX].ba_no_received,
+                agg->mu_stats[CL_MU2_IDX].ba_no_received,
+                agg->mu_stats[CL_MU3_IDX].ba_no_received,
+                agg->mu_stats[CL_MU4_IDX].ba_no_received,
+                agg->mu_stats[CL_MU5_IDX].ba_no_received,
+                agg->mu_stats[CL_MU6_IDX].ba_no_received,
+                agg->mu_stats[CL_MU7_IDX].ba_no_received);
+       PRINT_FW(cl_hw, "--------------------------------------------------------------------\n");
+#elif (MU_MAX_STREAMS == 3)
+       /* MU status statistics */
+       PRINT_FW(cl_hw, "--------------------------\n");
+       PRINT_FW(cl_hw, "|            | MU1 | MU2 |\n");
+       PRINT_FW(cl_hw, "|------------+-----+-----|\n");
+       PRINT_FW(cl_hw, "|Chain count |%5u|%5u|\n",
+                agg->mu_stats[CL_MU1_IDX].chain_cnt,
+                agg->mu_stats[CL_MU2_IDX].chain_cnt);
+       PRINT_FW(cl_hw, "|Status count|%5u|%5u|\n",
+                agg->mu_stats[CL_MU1_IDX].status_cnt,
+                agg->mu_stats[CL_MU2_IDX].status_cnt);
+       PRINT_FW(cl_hw, "--------------------------\n");
+       PRINT_FW(cl_hw, "\n");
+
+       /* MU agg-size statistics */
+       PRINT_FW(cl_hw, "------------------------------\n");
+       PRINT_FW(cl_hw, "| agg size | MU0 | MU1 | MU2 |\n");
+       PRINT_FW(cl_hw, "|----------+-----+-----+-----|\n");
+       for (i = 1; i < DBG_STATS_MAX_AGG_SIZE; i++) {
+               if (agg->mu_agg_size_statistics[CL_MU0_IDX][i] ||
+                   agg->mu_agg_size_statistics[CL_MU1_IDX][i] ||
+                   agg->mu_agg_size_statistics[CL_MU2_IDX][i]) {
+                       PRINT_FW(cl_hw, "|%10u|%5u|%5u|%5u|\n",
+                                i,
+                                agg->mu_agg_size_statistics[CL_MU0_IDX][i],
+                                agg->mu_agg_size_statistics[CL_MU1_IDX][i],
+                                agg->mu_agg_size_statistics[CL_MU2_IDX][i]);
+               }
+       }
+       PRINT_FW(cl_hw, "------------------------------\n");
+       PRINT_FW(cl_hw, "\n");
+
+       /* MU BA statistics */
+       PRINT_FW(cl_hw, "--------------------------------------\n");
+       PRINT_FW(cl_hw, "| MU BA statistics | MU0 | MU1 | MU2 |\n");
+       PRINT_FW(cl_hw, "|------------------+-----+-----+-----|\n");
+       PRINT_FW(cl_hw, "|  BA Received     |%5u|%5u|%5u|\n",
+                agg->mu_stats[CL_MU0_IDX].ba_received,
+                agg->mu_stats[CL_MU1_IDX].ba_received,
+                agg->mu_stats[CL_MU2_IDX].ba_received);
+       PRINT_FW(cl_hw, "|  --Unexpected BA |%5u|%5u|%5u|\n",
+                agg->mu_stats[CL_MU0_IDX].unexpected_ba,
+                agg->mu_stats[CL_MU1_IDX].unexpected_ba,
+                agg->mu_stats[CL_MU2_IDX].unexpected_ba);
+       PRINT_FW(cl_hw, "|  --Cleared    BA |%5u|%5u|%5u|\n",
+                agg->mu_stats[CL_MU0_IDX].clear_ba,
+                agg->mu_stats[CL_MU1_IDX].clear_ba,
+                agg->mu_stats[CL_MU2_IDX].clear_ba);
+       PRINT_FW(cl_hw, "|  --Invalid    BA |%5u|%5u|%5u|\n",
+                agg->mu_stats[CL_MU0_IDX].invalid_ba,
+                agg->mu_stats[CL_MU1_IDX].invalid_ba,
+                agg->mu_stats[CL_MU2_IDX].invalid_ba);
+       PRINT_FW(cl_hw, "|  --Correct    BA |%5u|%5u|%5u|\n",
+                agg->mu_stats[CL_MU0_IDX].correct_ba,
+                agg->mu_stats[CL_MU1_IDX].correct_ba,
+                agg->mu_stats[CL_MU2_IDX].correct_ba);
+       PRINT_FW(cl_hw, "|  BA not Received |%5u|%5u|%5u|\n",
+                agg->mu_stats[CL_MU0_IDX].ba_no_received,
+                agg->mu_stats[CL_MU1_IDX].ba_no_received,
+                agg->mu_stats[CL_MU2_IDX].ba_no_received);
+       PRINT_FW(cl_hw, "--------------------------------------\n");
+#else
+       /* MU status statistics */
+       PRINT_FW(cl_hw, "--------------------\n");
+       PRINT_FW(cl_hw, "|            | MU1 |\n");
+       PRINT_FW(cl_hw, "|------------+-----|\n");
+       PRINT_FW(cl_hw, "|Chain count |%5u|\n",
+                agg->mu_stats[CL_MU1_IDX].chain_cnt);
+       PRINT_FW(cl_hw, "|Status count|%5u|\n",
+                agg->mu_stats[CL_MU1_IDX].status_cnt);
+       PRINT_FW(cl_hw, "--------------------\n");
+       PRINT_FW(cl_hw, "\n");
+
+       /* MU agg-size statistics */
+       PRINT_FW(cl_hw, "------------------------\n");
+       PRINT_FW(cl_hw, "| agg size | MU0 | MU1 |\n");
+       PRINT_FW(cl_hw, "|----------+-----+-----|\n");
+       for (i = 1; i < DBG_STATS_MAX_AGG_SIZE; i++) {
+               if (agg->mu_agg_size_statistics[CL_MU0_IDX][i] ||
+                   agg->mu_agg_size_statistics[CL_MU1_IDX][i]) {
+                       PRINT_FW(cl_hw, "|%10u|%5u|%5u|\n",
+                                i,
+                                agg->mu_agg_size_statistics[CL_MU0_IDX][i],
+                                agg->mu_agg_size_statistics[CL_MU1_IDX][i]);
+               }
+       }
+       PRINT_FW(cl_hw, "------------------------\n");
+       PRINT_FW(cl_hw, "\n");
+
+       /* MU BA statistics */
+       PRINT_FW(cl_hw, "--------------------------------\n");
+       PRINT_FW(cl_hw, "| MU BA statistics | MU0 | MU1 |\n");
+       PRINT_FW(cl_hw, "|------------------+-----+-----|\n");
+       PRINT_FW(cl_hw, "|  BA Received     |%5u|%5u|\n",
+                agg->mu_stats[CL_MU0_IDX].ba_received,
+                agg->mu_stats[CL_MU1_IDX].ba_received);
+       PRINT_FW(cl_hw, "|  --Unexpected BA |%5u|%5u|\n",
+                agg->mu_stats[CL_MU0_IDX].unexpected_ba,
+                agg->mu_stats[CL_MU1_IDX].unexpected_ba);
+       PRINT_FW(cl_hw, "|  --Cleared    BA |%5u|%5u|\n",
+                agg->mu_stats[CL_MU0_IDX].clear_ba,
+                agg->mu_stats[CL_MU1_IDX].clear_ba);
+       PRINT_FW(cl_hw, "|  --Invalid    BA |%5u|%5u|\n",
+                agg->mu_stats[CL_MU0_IDX].invalid_ba,
+                agg->mu_stats[CL_MU1_IDX].invalid_ba);
+       PRINT_FW(cl_hw, "|  --Correct    BA |%5u|%5u|\n",
+                agg->mu_stats[CL_MU0_IDX].correct_ba,
+                agg->mu_stats[CL_MU1_IDX].correct_ba);
+       PRINT_FW(cl_hw, "|  BA not Received |%5u|%5u|\n",
+                agg->mu_stats[CL_MU0_IDX].ba_no_received,
+                agg->mu_stats[CL_MU1_IDX].ba_no_received);
+       PRINT_FW(cl_hw, "--------------------------------\n");
+#endif
+}
+
+static void cl_print_bcn_stats(struct cl_hw *cl_hw, struct cl_bcn_statistics *bcn_stats)
+{
+       struct beacon_timing *bcn_timing_stats = &bcn_stats->beacon_timing;
+       struct beacon_counters *bcn_cnt_stats = &bcn_stats->beacon_counters;
+       struct bcn_backup_stats *bcn_backup_stats = &bcn_stats->bcn_backup_stats;
+       u32 avg_time_between_bcn = 0, avg_time_bcn_chain = 0;
+
+       if (bcn_cnt_stats->nof_time_intervals_between_beacons != 0)
+               avg_time_between_bcn = (bcn_timing_stats->total_bcn_time /
+                                       bcn_cnt_stats->nof_time_intervals_between_beacons);
+
+       if (bcn_cnt_stats->bcn_chain_total_cnt != 0)
+               avg_time_bcn_chain = ((bcn_timing_stats->bcn_chain_total_time) /
+                                     (bcn_cnt_stats->bcn_chain_total_cnt));
+
+       PRINT_FW(cl_hw, "----------------------------------------\n");
+       PRINT_FW(cl_hw, "Number of beacon flushed\n");
+       PRINT_FW(cl_hw, "+---------+-------------+--------------+\n");
+       PRINT_FW(cl_hw, "| pending | downloading | transmitting |\n");
+       PRINT_FW(cl_hw, "+---------+-------------+--------------+\n");
+       PRINT_FW(cl_hw, "|%-9u|%-13u|%-14u|\n",
+                bcn_cnt_stats->ce_txl_flushed_beacons[BCN_FLUSH_PENDING],
+                bcn_cnt_stats->ce_txl_flushed_beacons[BCN_FLUSH_DOWNLOADING],
+                bcn_cnt_stats->ce_txl_flushed_beacons[BCN_FLUSH_TRANSMITTING]);
+       PRINT_FW(cl_hw, "+---------+-------------+--------------+\n\n");
+
+       PRINT_FW(cl_hw, "----------------------------------------\n");
+       PRINT_FW(cl_hw, "Time between transmission of two beacons\n");
+       PRINT_FW(cl_hw, "+----------+----------+---------+----------------+\n");
+       PRINT_FW(cl_hw, "| min time | max time | bcn cnt | avg time[mSec] |\n");
+       PRINT_FW(cl_hw, "+----------+----------+---------+----------------+\n");
+       PRINT_FW(cl_hw, "|%-10u|%-10u|%-9u|%-16u|\n",
+                bcn_timing_stats->min_time_from_last_bcn,
+                bcn_timing_stats->max_time_from_last_bcn,
+                bcn_cnt_stats->total_cnt,
+                avg_time_between_bcn);
+       PRINT_FW(cl_hw, "+----------+----------+---------+----------------+\n\n");
+
+       PRINT_FW(cl_hw, "---------------------------------------------------------------\n");
+       PRINT_FW(cl_hw, "Time of beacon until chain\n");
+       PRINT_FW(cl_hw, "+----------+----------+---------------+----------+\n");
+       PRINT_FW(cl_hw, "| min time | max time | bcn chain cnt | avg time |\n");
+       PRINT_FW(cl_hw, "+----------+----------+---------------+----------+\n");
+       PRINT_FW(cl_hw, "|%-10u|%-10u|%-15u|%-10u|\n",
+                bcn_timing_stats->bcn_chain_min_time,
+                bcn_timing_stats->bcn_chain_max_time,
+                bcn_cnt_stats->bcn_chain_total_cnt,
+                avg_time_bcn_chain);
+       PRINT_FW(cl_hw, "+----------+----------+---------------+----------+\n\n");
+
+       PRINT_FW(cl_hw, "---------------------------------------------------------------------\n");
+       PRINT_FW(cl_hw, " beacon pending-chain path max time = %u\n",
+                bcn_timing_stats->bcn_pending_2_chain_max_time);
+       PRINT_FW(cl_hw, " beacon pending-chain not in time count = %u\n",
+                bcn_cnt_stats->pending2chain_not_in_threshold_cnt);
+       PRINT_FW(cl_hw, " Max time until recievd beacon from driver = %u\n",
+                bcn_timing_stats->max_bcn_time_until_get_beacon_from_driver_in_tbtt);
+       PRINT_FW(cl_hw, " Total count of beacon flushed because didn't received in time = %u\n",
+                bcn_cnt_stats->bcn_time_from_driver_not_in_threshold_cnt);
+       PRINT_FW(cl_hw, " Max num of beacon not received from driver = %u\n",
+                bcn_cnt_stats->max_bcn_not_received_from_host);
+       PRINT_FW(cl_hw, "---------------------------------------------------------------------\n");
+
+       PRINT_FW(cl_hw, "+--------------------------------------+\n");
+       PRINT_FW(cl_hw, "|        Backup beacon stats           |\n");
+       PRINT_FW(cl_hw, "+------+------+---------+--------------+\n");
+       PRINT_FW(cl_hw, "| Used |  TX  | flushed | Max in a row |\n");
+       PRINT_FW(cl_hw, "+------+------+---------+--------------+\n");
+       PRINT_FW(cl_hw, "|%6u|%6u|%9u|%14u|\n",
+                bcn_backup_stats->bcn_backup_used_cnt,
+                bcn_backup_stats->bcn_backup_tx_cnt,
+                bcn_backup_stats->bcn_backup_flushed_cnt,
+                bcn_backup_stats->bcn_backup_max_used_in_arow_cnt);
+       PRINT_FW(cl_hw, "+------+------+---------+--------------+\n");
+}
+
+static void cl_print_rate_fallback_stats(struct cl_hw *cl_hw,
+                                        struct cl_rate_drop_statistics *stats)
+{
+       PRINT_FW(cl_hw, "\n");
+       PRINT_FW(cl_hw, "---------------------------\n");
+       PRINT_FW(cl_hw, "   Fallback statistics\n");
+       PRINT_FW(cl_hw, "---------------------------\n");
+       PRINT_FW(cl_hw, "ba_per_stats          = %u\n",
+                stats->drop_reason[AGG_TX_RATE_DROP_MAX_BA_PER_REACHED]);
+       PRINT_FW(cl_hw, "ba_not_received_stats = %u\n",
+                stats->drop_reason[AGG_TX_RATE_DROP_MAX_BA_NOT_RECEIVED_REACHED]);
+       PRINT_FW(cl_hw, "max_retry_reached     = %u\n",
+                stats->drop_reason[AGG_TX_RATE_DROP_MAX_RETRY_REACHED]);
+}
+
+static void cl_print_rx_stats_precent(struct cl_hw *cl_hw, const char *str, u32 x, u32 y)
+{
+       /*
+        * Example:
+        * x = 541, y = 19
+        * Result 28.4736
+        */
+       u32 integer = x / y;
+       u32 fraction = 10000 * (x - y * (x / y)) / y;
+
+       PRINT_FW(cl_hw, "%s = %u.%04u\n", str, integer, fraction);
+}
+
+static void cl_print_rx_stats(struct cl_hw *cl_hw, struct cl_rxl_statistics *rx_stats)
+{
+       int i, mu_idx, total_rx = 0;
+       enum format_mode fm;
+
+       PRINT_FW(cl_hw, "=========================================\n");
+       PRINT_FW(cl_hw, "        Global RX stats\n");
+       PRINT_FW(cl_hw, "=========================================\n");
+       PRINT_FW(cl_hw, "host rxelem not ready      = %u\n",
+                rx_stats->host_rxelem_not_ready_cnt);
+       PRINT_FW(cl_hw, "MSDU host rxelem not ready = %u\n",
+                rx_stats->msdu_host_rxelem_not_ready_cnt);
+       PRINT_FW(cl_hw, "MSDU dma pool not ready    = %u\n",
+                rx_stats->dma_rx_pool_not_ready_cnt);
+       PRINT_FW(cl_hw, "Percent of Rx CCA busy      = %u\n",
+                rx_stats->cca_busy_percent);
+       PRINT_FW(cl_hw, "Percent of Rx mine CCA busy = %u\n",
+                rx_stats->rx_mine_busy_percent);
+       PRINT_FW(cl_hw, "Percent of Tx mine busy     = %u\n",
+                rx_stats->tx_mine_busy_percent);
+       PRINT_FW(cl_hw, "\n");
+
+       PRINT_FW(cl_hw, "=== Rx Format ==\n");
+       for (fm = 0; fm < FORMATMOD_MAX; fm++)
+               if (rx_stats->stats_rx_format[fm])
+                       PRINT_FW(cl_hw, "Rx Format[%d] = %u\n", fm, rx_stats->stats_rx_format[fm]);
+
+       PRINT_FW(cl_hw, "=== Rx Decryption errors ==\n");
+       for (i = RHD_DECR_ICVFAIL_IDX; i < RHD_DECR_IDX_MAX; i++)
+               if (rx_stats->decrypt_err[i])
+                       PRINT_FW(cl_hw, "decrypt_err[%d] = %u\n", i, rx_stats->decrypt_err[i]);
+
+       /* RX prints */
+       for (mu_idx = 0; mu_idx < MU_UL_MAX; mu_idx++) {
+               PRINT_FW(cl_hw, "============================================\n");
+               PRINT_FW(cl_hw, "=====         RX MAC HW MU [%2d]       =====\n", mu_idx);
+               PRINT_FW(cl_hw, "============================================\n");
+               total_rx = rx_stats->total_rx_packets[mu_idx] +
+                       rx_stats->fcs_error_counter[mu_idx] +
+                       rx_stats->phy_error_counter[mu_idx] +
+                       rx_stats->ampdu_incorrect_received_counter[mu_idx] +
+                       rx_stats->delimiter_error_counter[mu_idx] +
+                       rx_stats->rx_fifo_overflow_err_cnt[mu_idx];
+
+               if (total_rx == 0)
+                       continue;
+
+               for (i = 0; i < MAX_HANDLED_FRM_TYPE; i++) {
+                       if (!rx_stats->emb_ll1_handled_frame_counter[mu_idx][i])
+                               continue;
+
+                       PRINT_FW(cl_hw, "emb_handled_packet[%d] - %u\n",
+                                i, rx_stats->emb_ll1_handled_frame_counter[mu_idx][i]);
+               }
+
+               PRINT_FW(cl_hw, "Total packets dropped (pckt_len > %u) %u\n",
+                        rx_stats->max_mpdu_data_len[mu_idx],
+                        rx_stats->rx_pckt_exceed_max_len_cnt[mu_idx]);
+               PRINT_FW(cl_hw, "Number of bad formated BA frames = %u\n",
+                        rx_stats->rx_pckt_bad_ba_statinfo_cnt[mu_idx]);
+               PRINT_FW(cl_hw, "Max occupancy list2 = %u\n",
+                        rx_stats->rhd_ll2_max_cnt[mu_idx]);
+               PRINT_FW(cl_hw, "Max occupancy list1 = %u\n",
+                        rx_stats->rhd_ll1_max_cnt[mu_idx]);
+               PRINT_FW(cl_hw, "\n");
+               PRINT_FW(cl_hw, "Total Qos MPDU received    = %u\n",
+                        rx_stats->total_rx_packets[mu_idx]);
+               PRINT_FW(cl_hw, "Total Aggregation received = %u\n",
+                        rx_stats->total_agg_packets[mu_idx]);
+               PRINT_FW(cl_hw, "Number of Rx Fifo Overflow = %u\n",
+                        rx_stats->rx_fifo_overflow_err_cnt[mu_idx]);
+               PRINT_FW(cl_hw, "Number of FCS ERROR        = %u\n",
+                        rx_stats->fcs_error_counter[mu_idx]);
+               PRINT_FW(cl_hw, "Number of PHY ERROR        = %u\n",
+                        rx_stats->phy_error_counter[mu_idx]);
+               PRINT_FW(cl_hw, "Number of AMPDUS           = %u\n",
+                        rx_stats->ampdu_received_counter[mu_idx]);
+               PRINT_FW(cl_hw, "Number of Incorrect AMPDUS = %u\n",
+                        rx_stats->ampdu_incorrect_received_counter[mu_idx]);
+               PRINT_FW(cl_hw, "Number of Delimiter errors = %u\n",
+                        rx_stats->delimiter_error_counter[mu_idx]);
+
+               if (rx_stats->total_rx_packets[mu_idx]) {
+                       u32 total_rx_packets = rx_stats->total_rx_packets[mu_idx] +
+                               rx_stats->rx_fifo_overflow_err_cnt[mu_idx] +
+                               rx_stats->fcs_error_counter[mu_idx] +
+                               rx_stats->phy_error_counter[mu_idx] +
+                               rx_stats->delimiter_error_counter[mu_idx];
+
+                       cl_print_rx_stats_precent(cl_hw,
+                                                 "Rx Fifo Overflow percent  ",
+                                                 100 * rx_stats->rx_fifo_overflow_err_cnt[mu_idx],
+                                                 total_rx_packets);
+                       cl_print_rx_stats_precent(cl_hw,
+                                                 "FCS Error percent         ",
+                                                 100 * rx_stats->fcs_error_counter[mu_idx],
+                                                 total_rx_packets);
+                       cl_print_rx_stats_precent(cl_hw,
+                                                 "Phy Error percent         ",
+                                                 100 * rx_stats->phy_error_counter[mu_idx],
+                                                 total_rx_packets);
+                       cl_print_rx_stats_precent(cl_hw,
+                                                 "Delimiter Error percent   ",
+                                                 100 * rx_stats->delimiter_error_counter[mu_idx],
+                                                 total_rx_packets);
+               }
+
+               PRINT_FW(cl_hw, "Current NAV value          = %u\n", rx_stats->nav_value[mu_idx]);
+
+               PRINT_FW(cl_hw, "\n");
+               PRINT_FW(cl_hw, "Rx LL split stats: 1st LL interrupts = %u\n",
+                        rx_stats->counter_timer_trigger_ll1[mu_idx]);
+               PRINT_FW(cl_hw, "Rx LL split stats: 2nd LL interrupts = %u\n",
+                        rx_stats->counter_timer_trigger_ll2[mu_idx]);
+               PRINT_FW(cl_hw, "Number of incorrect format mode received = %u\n",
+                        rx_stats->rx_incorrect_format_mode[mu_idx]);
+
+               for (i = 0; i < RX_CLASSIFICATION_MAX; i++) {
+                       if (!rx_stats->rx_class_counter[mu_idx][i])
+                               continue;
+
+                       PRINT_FW(cl_hw, "Rx classification rules stats: Rx rule%d= %u\n",
+                                i, rx_stats->rx_class_counter[mu_idx][i]);
+               }
+
+               if (rx_stats->rx_class_int_counter[mu_idx])
+                       PRINT_FW(cl_hw, "Rx classification interrupts rules = %u\n",
+                                rx_stats->rx_class_int_counter[mu_idx]);
+
+               PRINT_FW(cl_hw, "\n");
+               PRINT_FW(cl_hw, "Rx Implicit BF statistics:      = %u\n",
+                        rx_stats->rx_imp_bf_counter[mu_idx]);
+               PRINT_FW(cl_hw, "Rx Implicit BF interrupts stats = %u\n",
+                        rx_stats->rx_imp_bf_int_counter[mu_idx]);
+               PRINT_FW(cl_hw, "RXM STATISTICS\n");
+               PRINT_FW(cl_hw, "rxm_stats_overflow      = %u\n",
+                        rx_stats->rxm_stats_overflow[mu_idx]);
+               PRINT_FW(cl_hw, "rx_incorrect_format_mode= %u\n",
+                        rx_stats->rx_incorrect_format_mode[mu_idx]);
+               PRINT_FW(cl_hw, "correct_received_mpdu   = %u\n",
+                        rx_stats->correct_received_mpdu[mu_idx]);
+               PRINT_FW(cl_hw, "incorrect_received_mpdu = %u\n",
+                        rx_stats->incorrect_received_mpdu[mu_idx]);
+               PRINT_FW(cl_hw, "discarded_mpdu          = %u\n",
+                        rx_stats->discarded_mpdu[mu_idx]);
+               PRINT_FW(cl_hw, "incorrect_delimiter     = %u\n",
+                        rx_stats->incorrect_delimiter[mu_idx]);
+               PRINT_FW(cl_hw, "rts_bar_cnt             = %u\n",
+                        rx_stats->rts_bar_cnt[mu_idx]);
+               PRINT_FW(cl_hw, "rxm_mpdu_cnt            = %u\n",
+                        rx_stats->rxm_mpdu_cnt[mu_idx]);
+
+               if (rx_stats->rxm_mpdu_cnt[mu_idx]) {
+                       PRINT_FW(cl_hw, "rxm_rule0_match        = %u\n",
+                                rx_stats->rxm_rule0_match[mu_idx]);
+                       PRINT_FW(cl_hw, "rxm_rule1_match        = %u\n",
+                                rx_stats->rxm_rule1_match[mu_idx]);
+                       PRINT_FW(cl_hw, "rxm_rule2_match        = %u\n",
+                                rx_stats->rxm_rule2_match[mu_idx]);
+                       PRINT_FW(cl_hw, "rxm_rule3_match        = %u\n",
+                                rx_stats->rxm_rule3_match[mu_idx]);
+                       PRINT_FW(cl_hw, "rxm_rule4_match        = %u\n",
+                                rx_stats->rxm_rule4_match[mu_idx]);
+                       PRINT_FW(cl_hw, "rxm_rule5_match        = %u\n",
+                                rx_stats->rxm_rule5_match[mu_idx]);
+                       PRINT_FW(cl_hw, "rxm_rule6_match        = %u\n",
+                                rx_stats->rxm_rule6_match[mu_idx]);
+                       PRINT_FW(cl_hw, "rxm_default_rule_match = %u\n",
+                                rx_stats->rxm_default_rule_match[mu_idx]);
+                       PRINT_FW(cl_hw, "RXM amsdu stat not supported. use iwcl stats instead\n");
+               }
+
+               /* RX AMSDU prints */
+               PRINT_FW(cl_hw, "\n");
+               PRINT_FW(cl_hw, "RX AMSDU STATS\n");
+
+               PRINT_FW(cl_hw, "AMSDU RX cnt  = %u\n",
+                        rx_stats->stats_tot_rx_amsdu_cnt[mu_idx]);
+
+               for (i = 0; i < ARRAY_SIZE(rx_stats->stats_rx_amsdu_cnt[mu_idx]); i++)
+                       if (rx_stats->stats_rx_amsdu_cnt[mu_idx][i])
+                               PRINT_FW(cl_hw, "A-MSDU of %d = %u\n",
+                                        i + 1, rx_stats->stats_rx_amsdu_cnt[mu_idx][i]);
+
+               PRINT_FW(cl_hw, "A-MSDU RX errors:\n");
+               for (i = 0; i < AMSDU_DEAGGREGATION_ERR_MAX; i++)
+                       if (rx_stats->stats_rx_amsdu_err[mu_idx][i])
+                               PRINT_FW(cl_hw, " err_id[%d] = %u\n",
+                                        i, rx_stats->stats_rx_amsdu_err[mu_idx][i]);
+       }
+
+       PRINT_FW(cl_hw, "Frequency offset:\n");
+       for (i = 0; i < FREQ_OFFSET_TABLE_IDX_MAX; i++)
+               if (rx_stats->frequency_offset[i])
+                       PRINT_FW(cl_hw, "frequency_offset = %u\n", rx_stats->frequency_offset[i]);
+}
+
+static void cl_print_trigger_flow_stats(struct cl_hw *cl_hw,
+                                       struct cl_trigger_flow_statistics *tf_stats)
+{
+       u16 idx;
+       struct cl_rx_trigger_based_stats *tb_stats = &cl_hw->tb_stats;
+
+       if (!tb_stats->enable) {
+               PRINT_FW(cl_hw, "WARNING: Trigger based statistics are disabled!\n");
+               return;
+       }
+
+       PRINT_FW(cl_hw, "--------------------------------\n");
+       PRINT_FW(cl_hw, "     Trigger flow statistics\n");
+       PRINT_FW(cl_hw, "--------------------------------\n");
+       PRINT_FW(cl_hw, "Sent trigger frames\n");
+       PRINT_FW(cl_hw, "---------------|---AC0---|---AC1---|---AC2---|---AC3---|\n");
+       PRINT_FW(cl_hw, "BASIC TRIGGER: |%9u|%9u|%9u|%9u|\n",
+                tf_stats->single_trigger_sent[TRIGGER_FLOW_BASIC_TRIGGER_TYPE][AC_BK],
+                tf_stats->single_trigger_sent[TRIGGER_FLOW_BASIC_TRIGGER_TYPE][AC_BE],
+                tf_stats->single_trigger_sent[TRIGGER_FLOW_BASIC_TRIGGER_TYPE][AC_VI],
+                tf_stats->single_trigger_sent[TRIGGER_FLOW_BASIC_TRIGGER_TYPE][AC_VO]);
+       PRINT_FW(cl_hw, "BSRP:          |%9u|%9u|%9u|%9u|\n",
+                tf_stats->single_trigger_sent[TRIGGER_FLOW_BSRP_TYPE][AC_BK],
+                tf_stats->single_trigger_sent[TRIGGER_FLOW_BSRP_TYPE][AC_BE],
+                tf_stats->single_trigger_sent[TRIGGER_FLOW_BSRP_TYPE][AC_VI],
+                tf_stats->single_trigger_sent[TRIGGER_FLOW_BSRP_TYPE][AC_VO]);
+       PRINT_FW(cl_hw, "BFRP:          |%9u|%9u|%9u|%9u|\n",
+                tf_stats->single_trigger_sent[TRIGGER_FLOW_BFRP_TYPE][AC_BK],
+                tf_stats->single_trigger_sent[TRIGGER_FLOW_BFRP_TYPE][AC_BE],
+                tf_stats->single_trigger_sent[TRIGGER_FLOW_BFRP_TYPE][AC_VI],
+                tf_stats->single_trigger_sent[TRIGGER_FLOW_BFRP_TYPE][AC_VO]);
+       PRINT_FW(cl_hw, "HTP FAILURE:   |%9u|%9u|%9u|%9u|\n",
+                tf_stats->htp_rx_failure[AC_BK],
+                tf_stats->htp_rx_failure[AC_BE],
+                tf_stats->htp_rx_failure[AC_VI],
+                tf_stats->htp_rx_failure[AC_VO]);
+
+       PRINT_FW(cl_hw, "--------------------------------\n");
+       PRINT_FW(cl_hw, "TRIGGER BASED MPDUs PER MAC HW\n");
+       PRINT_FW(cl_hw, "--------------------------------\n");
+       tf_stats->trigger_based_mpdu[0] = tb_stats->total;
+
+       for (idx = 1; idx < MU_UL_MAX; idx++)
+               tf_stats->trigger_based_mpdu[0] -= tf_stats->trigger_based_mpdu[idx];
+
+       for (idx = 0; idx < MU_UL_MAX; idx++)
+               PRINT_FW(cl_hw, "MAC HW %u - %10u\n", idx, tf_stats->trigger_based_mpdu[idx]);
+
+       PRINT_FW(cl_hw, "--------------------------------\n");
+       PRINT_FW(cl_hw, "TRIGGER BASED AGGREGATIONS SIZE\n");
+       PRINT_FW(cl_hw, "--------------------------------\n");
+       PRINT_FW(cl_hw, "|-SIZE-|---TB AGGS---|\n");
+
+       for (idx = 1; idx < DBG_STATS_MAX_AGG_SIZE; idx++) {
+               if (tb_stats->data[idx] == 0)
+                       continue;
+
+               PRINT_FW(cl_hw, "| %4u |%13u|\n", idx, tb_stats->data[idx]);
+       }
+
+       PRINT_FW(cl_hw, "--------------------------------\n");
+       PRINT_FW(cl_hw, "TRIGGER BASED QOS NULL AGGR SIZE\n");
+       PRINT_FW(cl_hw, "--------------------------------\n");
+       PRINT_FW(cl_hw, "|-SIZE-|---TB AGGS---|\n");
+
+       for (idx = 1; idx < TID_MAX + 1; idx++)
+               if (tb_stats->qos_null[idx] > 0)
+                       PRINT_FW(cl_hw, "| %4u |%13u|\n", idx, tb_stats->qos_null[idx]);
+
+       if (tb_stats->qos_null[TID_MAX + 1] > 0)
+               PRINT_FW(cl_hw, "|  >8  |%13u|\n", tb_stats->qos_null[TID_MAX + 1]);
+}
+
+static void cl_print_dyn_calib_stats(struct cl_hw *cl_hw,
+                                    struct cl_dyn_calib_statistics *dyn_cal_stats)
+{
+       u8 i, j;
+
+       PRINT_FW(cl_hw, "--------------------------------\n");
+       PRINT_FW(cl_hw, "Dynamic Calibration Information\n");
+       PRINT_FW(cl_hw, "--------------------------------\n\n");
+
+       PRINT_FW(cl_hw, "Default Dynamic Calibation Value = %u\n\n",
+                dyn_cal_stats->default_dyn_cal_val);
+
+       for (i = dyn_cal_stats->dyn_cal_debug_info_ix, j = 0;
+            j < DYN_CAL_DEBUG_NUM_ITER;
+            (i = ((i + 1) % 3)), j++) {
+               struct dyn_cal_debug_info_t *dyn_cal_debug_info =
+                       &dyn_cal_stats->dyn_cal_debug_info[i];
+
+               if (dyn_cal_stats->is_multi_client_mode)
+                       PRINT_FW(cl_hw,
+                                "calib_num = %u, min_val = %d, max_val = %d, min_config = %u, "
+                                "max_config = %u, curr_config = %u, new_config = %u\n",
+                                dyn_cal_debug_info->calib_num,
+                                (s32)dyn_cal_debug_info->dyn_cal_min_val,
+                                (s32)dyn_cal_debug_info->dyn_cal_max_val,
+                                dyn_cal_debug_info->min_config,
+                                dyn_cal_debug_info->max_config,
+                                dyn_cal_debug_info->curr_config,
+                                dyn_cal_debug_info->new_config);
+               else
+                       PRINT_FW(cl_hw,
+                                "calib_num = %u, iter_num = %u, config_val_prev = %u, "
+                                "measured_val = %u, new_config_val = %u\n",
+                                dyn_cal_debug_info->calib_num,
+                                dyn_cal_debug_info->iter_num,
+                                dyn_cal_debug_info->curr_config,
+                                dyn_cal_debug_info->measured_val,
+                                dyn_cal_debug_info->new_config);
+       }
+
+       if (dyn_cal_stats->mac_phy_sync_err_cnt)
+               PRINT_FW(cl_hw, "mac_phy_sync_err_cnt = %u\n\n",
+                        dyn_cal_stats->mac_phy_sync_err_cnt);
+
+       PRINT_FW(cl_hw, "\n-----------------------------------------\n\n");
+}
+
+static void cl_print_bf_stats(struct cl_hw *cl_hw, struct cl_bf_statistics *bf_stats)
+{
+       u32 idx;
+       bool should_print = false;
+       u16 *tx_bf_data_err;
+
+       for (idx = 0; idx < BF_DB_MAX; idx++)
+               if (bf_stats->print_active_free_list == bf_stats->stats_data[idx].is_active_list) {
+                       should_print = true;
+                       break;
+               }
+
+       if (!should_print)
+               return;
+
+       /* Info phase 1 */
+       PRINT_FW(cl_hw, "List of non active BFs:\n");
+       PRINT_FW(cl_hw, "============================\n");
+       PRINT_FW(cl_hw, "BF_CTRL statistics\n");
+       PRINT_FW(cl_hw, "+-----+----+----+-------+-------+----------------+-----------------+--------------+---------------+-----------------+---------------+--------------+------------+-------+\n");
+       PRINT_FW(cl_hw, "|INDEX|#NDP|#BFP|#SU BFR|#MU BFR|#BFR_BW_MISMATCH|#BFR_NSS_MISMATCH|#SOUNDING_CHBW|#TOKEN_MISMATCH|#NDP_NDPA_TX_DROP|#BFR_RX_ERR_ACK|#BFR SEGMENTED|#RESOURCE_NA|STA_IDX|\n");
+       PRINT_FW(cl_hw, "+-----+----+----+-------+-------+----------------+-----------------+--------------+---------------+-----------------+---------------+--------------+------------+-------+\n");
+
+       for (idx = 0; idx < BF_DB_MAX; idx++) {
+               if (bf_stats->print_active_free_list != bf_stats->stats_data[idx].is_active_list)
+                       continue;
+
+               PRINT_FW(cl_hw,
+                        "|%5u|%4u|%4u|%7u|%7u|%16u|%17u|%14u|%15u|%17u|%15u|%14u|%12u|%7u|\n",
+                        idx,
+                        bf_stats->stats_data[idx].dbg.ndp_cnt,
+                        bf_stats->stats_data[idx].dbg.bfp_cnt,
+                        bf_stats->stats_data[idx].dbg.su_bfr_cnt,
+                        bf_stats->stats_data[idx].dbg.mu_bfr_cnt,
+                        bf_stats->stats_data[idx].dbg.bf_invalid_cnt[BFR_RX_ERR_BW_MISMATCH],
+                        bf_stats->stats_data[idx].dbg.bf_invalid_cnt[BFR_RX_ERR_NSS_MISMATCH],
+                        bf_stats->stats_data[idx].dbg.bf_invalid_cnt[BFR_RX_ERR_SOUNDING_CHBW],
+                        bf_stats->stats_data[idx].dbg.bf_invalid_cnt[BFR_RX_ERR_TOKEN_MISMATCH],
+                        bf_stats->stats_data[idx].dbg.bf_invalid_cnt[BFR_RX_ERR_NDP_DROP],
+                        bf_stats->stats_data[idx].dbg.bf_invalid_cnt[BFR_RX_ERR_MISS_ACK],
+                        bf_stats->stats_data[idx].dbg.bf_invalid_cnt[BFR_SEGMENTED_DROP],
+                        bf_stats->stats_data[idx].dbg.bf_invalid_cnt[BFR_RX_ERR_RESOURCE_NA],
+                        bf_stats->stats_data[idx].sta_idx);
+       }
+
+       PRINT_FW(cl_hw, "+-----+----+----+-------+-------+----------------+-----------------+--------------+---------------+-----------------+---------------+--------------+------------+-------+\n");
+
+       /* Info phase 2 */
+       PRINT_FW(cl_hw, "statistic BF DATA FRAMESs:\n");
+       PRINT_FW(cl_hw, "============================\n");
+       PRINT_FW(cl_hw, "BF_CTRL statistics\n");
+       PRINT_FW(cl_hw, "+-----+-----------+------------+-------------+-----------------+----------------+-----------------+-----------+-----------+----------+------------------+-----------------+-------+\n");
+       PRINT_FW(cl_hw, "|INDEX|#ACTIVE_IDX|#PASSIVE_IDX|#ERR_BFR_MISS|#ERR_BFR_OUTDATED|#ERR_BW_MISMATCH|#ERR_NSS_MISMATCH|#BF_DATA_OK|#BUFF_IN_PS|#REL_IN_PS|#BUFF_RESOURCE_ERR|#REL_RESOURCE_ERR|STA_IDX|\n");
+       PRINT_FW(cl_hw, "+-----+-----------+------------+-------------+-----------------+----------------+-----------------+-----------+-----------+----------+------------------+-----------------+-------+\n");
+
+       for (idx = 0; idx < BF_DB_MAX; idx++) {
+               if (bf_stats->print_active_free_list != bf_stats->stats_data[idx].is_active_list)
+                       continue;
+
+               tx_bf_data_err = bf_stats->stats_data[idx].dbg.tx_bf_data_err;
+
+               PRINT_FW(cl_hw,
+                        "|%5u|%11u|%12u|%13u|%17u|%16u|%17u|%11u|%11u|%10u|%18u|%17u|%7u|\n",
+                        idx,
+                        bf_stats->stats_data[idx].active_dsp_idx,
+                        bf_stats->stats_data[idx].passive_dsp_idx,
+                        tx_bf_data_err[TX_BF_DATA_ERR_BFR_MISS],
+                        tx_bf_data_err[TX_BF_DATA_ERR_BFR_OUTDATED],
+                        tx_bf_data_err[TX_BF_DATA_ERR_MISMATCH_BW],
+                        tx_bf_data_err[TX_BF_DATA_ERR_MISMATCH_NSS],
+                        tx_bf_data_err[TX_BF_DATA_OK],
+                        tx_bf_data_err[TX_BF_DATA_BUFFERED_PS_STA],
+                        tx_bf_data_err[TX_BF_DATA_RELEASED_PS_STA],
+                        tx_bf_data_err[TX_BF_DATA_BUFFERED_RESOURCE_ERR],
+                        tx_bf_data_err[TX_BF_DATA_RELEASED_RESOURCE_ERR],
+                        bf_stats->stats_data[idx].sta_idx);
+       }
+
+       PRINT_FW(cl_hw, "+-----+-----------+------------+-------------+-----------------+----------------+-----------------+-----------+-----------+----------+------------------+-----------------+-------+\n");
+}
+
+static void cl_print_stats_handler(struct work_struct *ws)
+{
+       struct cl_print_stats_work *stats_work = container_of(ws, struct cl_print_stats_work, ws);
+       struct cl_hw *cl_hw = stats_work->cl_hw;
+       u32 dbg_info_type = stats_work->dbg_info_type;
+
+       if (dbg_info_type == DBG_INFO_TX_STATS) {
+               struct cl_txl_statistics *tx_stats =
+                       &(((struct dbg_info *)cl_hw->dbginfo.buf)->u.tx_stats);
+
+               cl_print_tx_stats(cl_hw, tx_stats);
+               cl_print_tx_mu_stats(cl_hw, tx_stats);
+       } else if (dbg_info_type == DBG_INFO_BCN_STATS) {
+               struct cl_bcn_statistics *bcn_stats =
+                       &(((struct dbg_info *)cl_hw->dbginfo.buf)->u.bcn_stats);
+
+               cl_print_bcn_stats(cl_hw, bcn_stats);
+       } else if (dbg_info_type == DBG_INFO_RX_STATS) {
+               struct cl_rxl_statistics *rx_stats =
+                       &(((struct dbg_info *)cl_hw->dbginfo.buf)->u.rx_stats);
+
+               cl_print_rx_stats(cl_hw, rx_stats);
+       } else if (dbg_info_type == DBG_INFO_DYN_CAL_STATS) {
+               struct cl_dyn_calib_statistics *dyn_cal_stats =
+                       &(((struct dbg_info *)cl_hw->dbginfo.buf)->u.dyn_calib_stats);
+
+               cl_print_dyn_calib_stats(cl_hw, dyn_cal_stats);
+       } else if (dbg_info_type == DBG_INFO_RATE_FALLBACK_STATS) {
+               struct cl_rate_drop_statistics *agg_rate_drop_stats =
+                       &(((struct dbg_info *)cl_hw->dbginfo.buf)->u.rate_drop_stats);
+
+               cl_print_rate_fallback_stats(cl_hw, agg_rate_drop_stats);
+       } else if (dbg_info_type == DBG_INFO_BF) {
+               struct cl_bf_statistics *bf_stats =
+                       &(((struct dbg_info *)cl_hw->dbginfo.buf)->u.bf_stats);
+
+               cl_print_bf_stats(cl_hw, bf_stats);
+       } else if (dbg_info_type == DBG_INFO_TRIGGER_FLOW) {
+               struct cl_trigger_flow_statistics *tf_stats =
+                       &(((struct dbg_info *)cl_hw->dbginfo.buf)->u.trigger_flow_stats);
+
+               cl_print_trigger_flow_stats(cl_hw, tf_stats);
+       }
+
+#ifdef CONFIG_CL_PCIE
+       cl_ipc_dbginfobuf_push(cl_hw->ipc_env, cl_hw->dbginfo.dma_addr);
+#endif
+       kfree(stats_work);
+}
+
+static void cl_schedule_print_stats(struct cl_hw *cl_hw, u32 dbg_info_type)
+{
+       struct cl_print_stats_work *stats_work =
+               kzalloc(sizeof(*stats_work), GFP_ATOMIC);
+
+       if (stats_work) {
+               INIT_WORK(&stats_work->ws, cl_print_stats_handler);
+               stats_work->cl_hw = cl_hw;
+               stats_work->dbg_info_type = dbg_info_type;
+
+               /* Schedule work, the work will be executed in the background */
+               queue_work(cl_hw->drv_workqueue, &stats_work->ws);
+       } else {
+               cl_dbg_err(cl_hw, "stats_work allocation failed\n");
+       }
+}
+
+void cl_fw_dbg_handler(struct cl_hw *cl_hw)
+{
+       struct dbg_info *dbg_info = NULL;
+
+       /* Function called upon DBG_INFO_IND message reception. */
+       dma_sync_single_for_device(cl_hw->chip->dev, cl_hw->dbginfo.dma_addr,
+                                  cl_hw->dbginfo.bufsz, DMA_FROM_DEVICE);
+       dbg_info = (struct dbg_info *)cl_hw->dbginfo.buf;
+
+       if (dbg_info->u.type == DBG_INFO_DUMP) {
+               cl_dbg_info(cl_hw, "type %u): dump received\n",
+                           cl_hw->dbginfo.buf->u.dump.general_data.error_type);
+               cl_coredump_trigger(cl_hw);
+       } else if (dbg_info->u.type < DBG_INFO_MAX) {
+               cl_schedule_print_stats(cl_hw, dbg_info->u.type);
+       } else {
+               cl_dbg_warn(cl_hw, "Debug info wrong type - %u\n", dbg_info->u.type);
+       }
+}
+
+static int cl_fw_dbg_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,
+                "fw usage:\n"
+                "-a : Trigger assert error (echo ASSERT_ERR > errsim)\n"
+                "-b : Trigger assert recovery (echo 1 > test_mode)\n"
+                "-d : Set trigger-based debug statistics [0-dis/1-en]\n"
+                "-m : Trigger firmware dump (echo 1 > mactrace)\n"
+                "-s : Print statistics (echo param > stat_print)\n"
+                "-t : Test mode command (cmd + 0 to 5 parameters)\n");
+
+       err = cl_vendor_reply(cl_hw, buf, strlen(buf));
+       kfree(buf);
+
+       return err;
+}
+
+int cl_fw_dbg_cli(struct cl_hw *cl_hw, struct cli_params *cli_params)
+{
+       u32 expected_params = 0;
+       bool assert_err = false;
+       bool assert_rec = false;
+       bool dbg_tb_stats = false;
+       bool mactrace = false;
+       bool stat_print = false;
+       bool test_mode = false;
+
+       switch (cli_params->option) {
+       case 'a':
+               assert_err = true;
+               expected_params = 0;
+               break;
+       case 'b':
+               assert_rec = true;
+               expected_params = 0;
+               break;
+       case 'd':
+               dbg_tb_stats = true;
+               expected_params = 1;
+               break;
+       case 'm':
+               mactrace = true;
+               expected_params = 0;
+               break;
+       case 's':
+               stat_print = true;
+               expected_params = 1;
+               break;
+       case 't':
+               test_mode = true;
+               break;
+       case '?':
+               return cl_fw_dbg_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) && !test_mode) {
+               cl_dbg_err(cl_hw, "Wrong number of arguments (expected %u) (actual %u)\n",
+                          expected_params, cli_params->num_params);
+               goto out_err;
+       }
+
+       if (assert_err) {
+               cl_msg_tx_key_del(cl_hw, 0xFF);
+               return 0;
+       }
+
+       if (assert_rec) {
+               u32 params[TEST_MODE_PARAM_MAX + 1] = {1, 0, 0, 0, 0, 0};
+
+               cl_msg_tx_dbg_test_mode(cl_hw, params);
+               return 0;
+       }
+
+       if (dbg_tb_stats) {
+               cl_hw->tb_stats.enable = (bool)cli_params->params[0];
+               pr_debug("TB statistics %s\n", cl_hw->tb_stats.enable ? "enable" : "disable");
+               return 0;
+       }
+
+       if (mactrace) {
+               cl_msg_tx_dbg_trigger(cl_hw, "Force trigger");
+               return 0;
+       }
+
+       if (stat_print) {
+               u32 bitmap = (u32)cli_params->params[0];
+
+               cl_msg_tx_dbg_print_stats(cl_hw, bitmap, 0, 0, 0, 0);
+               return 0;
+       }
+
+       if (test_mode) {
+               u32 params[TEST_MODE_PARAM_MAX + 1] = {0};
+               u8 i;
+
+               if (cli_params->num_params == 0 ||
+                   cli_params->num_params > TEST_MODE_PARAM_MAX + 1) {
+                       cl_dbg_err(cl_hw, "Test mode expects cmd + 0 to 5 parameters\n");
+                       goto out_err;
+               }
+
+               for (i = 0; i < cli_params->num_params; i++)
+                       params[i] = (u32)cli_params->params[i];
+
+               cl_msg_tx_dbg_test_mode(cl_hw, params);
+               return 0;
+       }
+
+out_err:
+       return -EIO;
+}
+
+static void cl_dbg_dump_check_params(struct cl_hw *cl_hw,
+                                    u8 *buf, int bufsz, int *pos,
+                                    struct dbg_error_trace_info_drv *dump)
+{
+       int is_mismatch = false;
+       struct dbg_meta_data *dbg_metadata = &dump->common_info.dbg_metadata;
+
+       if (dbg_metadata->lmac_req_buf_size != sizeof(struct dbg_error_trace_info_drv) ||
+           dbg_metadata->physical_queue_cnt != CL_MAX_BA_PHYSICAL_QUEUE_CNT ||
+           dbg_metadata->agg_index_max != AGG_IDX_MAX ||
+           dbg_metadata->ce_ac_max != CE_AC_MAX ||
+           dbg_metadata->mu_user_max != MU_MAX_STREAMS ||
+           dbg_metadata->txl_exch_trace_depth != DBG_TXL_FRAME_EXCH_TRACE_DEPTH ||
+           dbg_metadata->mac_hw_regs_max != HAL_MACHW_REG_NUM ||
+           dbg_metadata->phy_hw_regs_max != PHY_HW_DBG_REGS_CNT)
+               is_mismatch = true;
+
+       if (is_mismatch) {
+               *pos += scnprintf(buf + *pos, bufsz - *pos,
+                                 "\nWarning!!!!\n");
+               *pos += scnprintf(buf + *pos, bufsz - *pos,
+                                 "DBG metadata mismatch bwtween FW & DRV!!!!\n");
+       }
+
+       if (dbg_metadata->lmac_req_buf_size != (u32)(sizeof(struct dbg_error_trace_info_drv)))
+               *pos += scnprintf(buf + *pos, bufsz - *pos,
+                                 "FW buf size       %u expected %u\n",
+                                 dbg_metadata->lmac_req_buf_size,
+                                 (u32)(sizeof(struct dbg_error_trace_info_drv)));
+
+       if (dbg_metadata->physical_queue_cnt != CL_MAX_BA_PHYSICAL_QUEUE_CNT)
+               *pos += scnprintf(buf + *pos, bufsz - *pos,
+                                 "physical queue cn %u expected %u\n",
+                                 dbg_metadata->physical_queue_cnt,
+                                 CL_MAX_BA_PHYSICAL_QUEUE_CNT);
+
+       if (dbg_metadata->agg_index_max != AGG_IDX_MAX)
+               *pos += scnprintf(buf + *pos, bufsz - *pos,
+                                 "agg idx max       %u expected %u\n",
+                                 dbg_metadata->agg_index_max, AGG_IDX_MAX);
+
+       if (dbg_metadata->ce_ac_max != CE_AC_MAX)
+               *pos += scnprintf(buf + *pos, bufsz - *pos,
+                                 "ac max            %u expected %u\n",
+                                 dbg_metadata->ce_ac_max, CE_AC_MAX);
+
+       if (dbg_metadata->mu_user_max != MU_MAX_STREAMS)
+               *pos += scnprintf(buf + *pos, bufsz - *pos,
+                                 "MU MAX            %u expected %u\n",
+                                 dbg_metadata->mu_user_max, MU_MAX_STREAMS);
+
+       if (dbg_metadata->txl_exch_trace_depth != DBG_TXL_FRAME_EXCH_TRACE_DEPTH)
+               *pos += scnprintf(buf + *pos, bufsz - *pos,
+                                 "txl trace depth   %u expected %u\n",
+                                 dbg_metadata->txl_exch_trace_depth,
+                                 DBG_TXL_FRAME_EXCH_TRACE_DEPTH);
+
+       if (dbg_metadata->mac_hw_regs_max != HAL_MACHW_REG_NUM)
+               *pos += scnprintf(buf + *pos, bufsz - *pos,
+                                 "MAC HW regs cnt   %u expected %u\n",
+                                 dbg_metadata->mac_hw_regs_max,
+                                 HAL_MACHW_REG_NUM);
+
+       if (dbg_metadata->phy_hw_regs_max != PHY_HW_DBG_REGS_CNT)
+               *pos += scnprintf(buf + *pos, bufsz - *pos,
+                                 "PHY HW regs       %u expected %u\n",
+                                 dbg_metadata->phy_hw_regs_max,
+                                 PHY_HW_DBG_REGS_CNT);
+}
+
+static void cl_dbg_policy_table_print(struct cl_hw *cl_hw,
+                                     u8 *buf, int bufsz, int *pos,
+                                     struct tx_policy_tbl *policy_table_ptr,
+                                     u32 policy_table_addr)
+{
+       *pos += scnprintf(buf + *pos, bufsz - *pos,
+                         "================================================="
+                         "= Policy Table 0x%x ============================="
+                         "============================\n",
+                        policy_table_addr);
+       *pos += scnprintf(buf + *pos, bufsz - *pos,
+                         "| upatterntx         = 0x%08x| phycntrlinfo1      = 0x%08x"
+                         "| phycntrlinfo2     = 0x%08x| maccntrlinfo1      = 0x%08x|\n",
+                         policy_table_ptr->upatterntx,
+                         policy_table_ptr->phycntrlinfo1,
+                         policy_table_ptr->phycntrlinfo2,
+                         policy_table_ptr->maccntrlinfo1);
+       *pos += scnprintf(buf + *pos, bufsz - *pos,
+                         "| maccntrlinfo2      = 0x%08x| ratecntrlinfo[0]   = 0x%08x"
+                         "| ratecntrlinfo[1]  = 0x%08x| ratecntrlinfo[2]   = 0x%08x|\n",
+                         policy_table_ptr->maccntrlinfo2,
+                         policy_table_ptr->ratecntrlinfo[0],
+                         policy_table_ptr->ratecntrlinfo[1],
+                         policy_table_ptr->ratecntrlinfo[2]);
+       *pos += scnprintf(buf + *pos, bufsz - *pos,
+                         "| ratecntrlinfo[3]   = 0x%08x| phycntrlinfo3      = 0x%08x"
+                         "| phycntrlinfo4     = 0x%08x| phycntrlinfo5      = 0x%08x|\n",
+                         policy_table_ptr->ratecntrlinfo[3],
+                         policy_table_ptr->phycntrlinfo3,
+                         policy_table_ptr->phycntrlinfo4,
+                         policy_table_ptr->phycntrlinfo5);
+       *pos += scnprintf(buf + *pos, bufsz - *pos,
+                         "| stationinfo        = 0x%08x| ratecntrlinfohe[0] = 0x%08x"
+                         "| ratecntrlinfohe[1]= 0x%08x| ratecntrlinfohe[2] = 0x%08x|\n",
+                         policy_table_ptr->stationinfo,
+                         policy_table_ptr->ratecntrlinfohe[0],
+                         policy_table_ptr->ratecntrlinfohe[1],
+                         policy_table_ptr->ratecntrlinfohe[2]);
+       *pos += scnprintf(buf + *pos, bufsz - *pos,
+                         "| ratecntrlinfohe[3] = 0x%08x| maccntrlinfo3      = 0x%08x"
+                         "| triggercommoninfo = 0x%08x| trigperuserinfo[0] = 0x%08x|\n",
+                         policy_table_ptr->ratecntrlinfohe[3],
+                         policy_table_ptr->maccntrlinfo3,
+                         policy_table_ptr->triggercommoninfo,
+                         policy_table_ptr->triggerperuserinfo[0]);
+       *pos += scnprintf(buf + *pos, bufsz - *pos,
+                         "| trigperuserinfo[1] = 0x%08x| trigperuserinfo[2] = 0x%08x"
+                         "| trigperuserinfo[3]= 0x%08x| trigperuserinfo[4] = 0x%08x|\n",
+                         policy_table_ptr->triggerperuserinfo[1],
+                         policy_table_ptr->triggerperuserinfo[2],
+                         policy_table_ptr->triggerperuserinfo[3],
+                         policy_table_ptr->triggerperuserinfo[4]);
+       *pos += scnprintf(buf + *pos, bufsz - *pos,
+                         "| trigperuserinfo[5] = 0x%08x| trigperuserinfo[6] = 0x%08x"
+                         "| trigperuserinfo[7]= 0x%08x|\n",
+                         policy_table_ptr->triggerperuserinfo[5],
+                         policy_table_ptr->triggerperuserinfo[6],
+                         policy_table_ptr->triggerperuserinfo[7]);
+       *pos += scnprintf(buf + *pos, bufsz - *pos,
+                         "| triginforallocau0u3= 0x%08x| triginforallocau4u7= 0x%08x |\n",
+                         policy_table_ptr->triggerinforuallocationu0u3,
+                         policy_table_ptr->triggerinforuallocationu4u7);
+       *pos += scnprintf(buf + *pos, bufsz - *pos,
+                         "===================================================="
+                         "===================================================="
+                         "============================\n\n");
+}
+
+static void cl_dbg_thd_print(struct cl_hw *cl_hw,
+                            u8 *buf, int bufsz, int *pos,
+                            struct tx_hd *thd_ptr, u32 thd_addr)
+{
+       *pos += scnprintf(buf + *pos, bufsz - *pos,
+                         "=============================================="
+                         "=       THD 0x%x      ========================"
+                         "=======================\n",
+                         thd_addr);
+       *pos += scnprintf(buf + *pos, bufsz - *pos,
+                         "| upatterntx   = 0x%08x | nextfrmexseq_ptr = 0x%08x "
+                         "| nextmpdudesc_ptr = 0x%08x | first_pbd_ptr = 0x%08x|\n",
+                        thd_ptr->upatterntx,
+                        thd_ptr->nextfrmexseq_ptr,
+                        thd_ptr->nextmpdudesc_ptr,
+                        thd_ptr->first_pbd_ptr);
+       *pos += scnprintf(buf + *pos, bufsz - *pos,
+                         "| datastartptr = 0x%08x | dataendptr       = 0x%08x "
+                         "| frmlen           = 0x%08x | spacinginfo   = 0x%08x|\n",
+                         thd_ptr->datastartptr,
+                         thd_ptr->dataendptr,
+                         thd_ptr->frmlen,
+                         thd_ptr->spacinginfo);
+       *pos += scnprintf(buf + *pos, bufsz - *pos,
+                         "| phyctrlinfo1 = 0x%08x | policyentryaddr  = 0x%08x "
+                         "| macctrlinfo1     = 0x%08x | macctrlinfo2  = 0x%08x|\n",
+                         thd_ptr->phyctrlinfo1,
+                         thd_ptr->policyentryaddr,
+                         thd_ptr->macctrlinfo1,
+                         thd_ptr->macctrlinfo2);
+       *pos += scnprintf(buf + *pos, bufsz - *pos,
+                         "| statinfo     = 0x%08x | phyctrlinfo2     = 0x%08x |\n",
+                         thd_ptr->statinfo,
+                         thd_ptr->phyctrlinfo2);
+       *pos += scnprintf(buf + *pos, bufsz - *pos,
+                         "=============================================="
+                         "=============================================="
+                         "=============================\n\n");
+}
+
+static void cl_dbg_pbd_print(struct cl_hw *cl_hw,
+                            u8 *buf, int bufsz, int *pos,
+                            struct tx_pbd *pbd_ptr, u32 pbd_addr)
+{
+       *pos += scnprintf(buf + *pos, bufsz - *pos,
+                        "==============================================="
+                        "===      PBD 0x%x     ========================="
+                        "========================\n",
+                        pbd_addr);
+       *pos += scnprintf(buf + *pos, bufsz - *pos,
+                         "| upatterntx = 0x%08x | next = 0x%08x| datastartptr = 0x%08x"
+                         "| dataendptr = 0x%08x| bufctrlinfo = 0x%08x|\n",
+                         pbd_ptr->upatterntx,
+                         pbd_ptr->next,
+                         pbd_ptr->datastartptr,
+                         pbd_ptr->dataendptr,
+                         pbd_ptr->bufctrlinfo);
+       *pos += scnprintf(buf + *pos, bufsz - *pos,
+                         "=============================================="
+                         "=============================================="
+                         "================================\n\n");
+}
+
+static void cl_dbg_dump_txm_regs(struct cl_hw *cl_hw,
+                                u8 *buf, int bufsz, int *pos,
+                                struct dbg_error_trace_info_drv *dump)
+{
+       int stream_idx;
+       struct dbg_fw_info *fw_info = &dump->common_info.fw_info;
+
+       for (stream_idx = 0; stream_idx < ARRAY_SIZE(fw_info->txlist_info_agg); ++stream_idx) {
+               struct dbg_txm_regs *txm_regs;
+
+               if (!fw_info->txlist_info_agg[stream_idx].curr_session_idx)
+                       continue;
+
+               txm_regs = &dump->common_info.hw_info.txm_regs[stream_idx];
+               *pos += scnprintf(buf + *pos, bufsz - *pos,
+                                 "#### TXM stream %u Registers\n", stream_idx);
+               *pos += scnprintf(buf + *pos, bufsz - *pos,
+                                 "|--------------------------------------------------------------------|\n");
+               *pos += scnprintf(buf + *pos, bufsz - *pos,
+                                 "| HW state = %3u FW state = %3u SPX state = %3u free buff state = %3u|\n",
+                                 txm_regs->hw_state, txm_regs->fw_state,
+                                 txm_regs->spx_state, txm_regs->free_buf_state);
+               *pos += scnprintf(buf + *pos, bufsz - *pos,
+                                 "| MPDU cnt = %3u LLI cnt  = %3u LLI done mpdu num = %3u  reason = %3u|\n",
+                                 txm_regs->mpdu_cnt, txm_regs->lli_cnt,
+                                 txm_regs->lli_done_mpdu_num, txm_regs->lli_done_reason);
+               *pos += scnprintf(buf + *pos, bufsz - *pos,
+                                 "| active bytes   = 0x%08x prefetch bytes = 0x%08x            |\n",
+                                 txm_regs->active_bytes, txm_regs->prefetch_bytes);
+               *pos += scnprintf(buf + *pos, bufsz - *pos,
+                                 "| last THD: addr = 0x%x MPDU number = %3u underrun cnt = %3u   |\n",
+                                 txm_regs->last_thd_done_addr,
+                                 txm_regs->last_thd_done_mpdu_num, txm_regs->underrun_cnt);
+               *pos += scnprintf(buf + *pos, bufsz - *pos,
+                                "|--------------------------------------------------------------------|\n\n");
+       }
+}
+
+static void cl_dbg_dump_machw_regs(struct cl_hw *cl_hw,
+                                  u8 *buf, int bufsz, int *pos,
+                                  struct dbg_error_trace_info_drv *dump)
+{
+       u8 i = 0, mu_idx;
+       struct dbg_hw_reg_info *hw_info = &dump->common_info.hw_info;
+
+       const char *hal_machw_reg_str[HAL_MACHW_REG_NUM] = {
+               [HAL_MACHW_AGGR_STATUS]                    = "AGGR_STATUS",
+               [HAL_MACHW_DEBUG_HWSM_1]                   = "DBG_HWSM_1",
+               [HAL_MACHW_DEBUG_HWSM_2]                   = "DBG_HWSM_2",
+               [HAL_MACHW_DEBUG_HWSM_3]                   = "DBG_HWSM_3",
+               [HAL_MACHW_DMA_STATUS_1]                   = "DMA_STATUS_1",
+               [HAL_MACHW_DMA_STATUS_2]                   = "DMA_STATUS_2",
+               [HAL_MACHW_DMA_STATUS_3]                   = "DMA_STATUS_3",
+               [HAL_MACHW_DMA_STATUS_4]                   = "DMA_STATUS_4",
+               [HAL_MACHW_RX_HEADER_H_PTR]                = "RX_HEADER_HEAD_PTR",
+               [HAL_MACHW_RX_PAYLOAD_H_PTR]               = "RX_PAYLOAD_HEAD_PTR",
+               [HAL_MACHW_DEBUG_BCN_S_PTR]                = "DBG_BCN_STATUS_PTR",
+               [HAL_MACHW_DEBUG_AC0_S_PTR]                = "DBG_AC_0_STATUS_PTR",
+               [HAL_MACHW_DEBUG_AC1_S_PTR]                = "DBG_AC_1_STATUS_PTR",
+               [HAL_MACHW_DEBUG_AC2_S_PTR]                = "DBG_AC_2_STATUS_PTR",
+               [HAL_MACHW_DEBUG_AC3_S_PTR]                = "DBG_AC_3_STATUS_PTR",
+               [HAL_MACHW_DEBUG_HTP_S_PTR]                = "DBG_HTP_STATUS_PTR",
+               [HAL_MACHW_DEBUG_TX_C_PTR]                 = "DBG_TX_CURRENT_PTR",
+               [HAL_MACHW_DEBUG_RX_HDR_C_PTR]             = "DBG_RX_HDR_CURRENT_PTR",
+               [HAL_MACHW_DEBUG_RX_PAY_C_PTR]             = "DBG_RX_PAY_CURRENT_PTR",
+               [HAL_MACHW_MU0_TX_POWER_LEVEL_DELTA_1]     = "DBG_MU0_TX_PWR_LEVEL_DELTA_1",
+               [HAL_MACHW_MU0_TX_POWER_LEVEL_DELTA_2]     = "DBG_MU0_TX_PWR_LEVEL_DELTA_2",
+               [HAL_MACHW_POWER_BW_CALIB_FACTOR]          = "DBG_TX_POWER_BW_CALIB_FACTOR",
+               [HAL_MACHW_TX_POWER_ANTENNA_FACTOR_1_ADDR] = "DBG_tX_POWER_ANT_FACTOR_1",
+               [HAL_MACHW_TX_POWER_ANTENNA_FACTOR_2_ADDR] = "DBG_TX_POWER_ANT_FACTOR_2"
+       };
+
+       *pos += scnprintf(buf + *pos, bufsz - *pos, "\n##### MAC HW regs ####\n");
+
+       for (i = 0; i < ARRAY_SIZE(hw_info->mac_hw_reg); ++i)
+               *pos += scnprintf(buf + *pos, bufsz - *pos,
+                                 "%30s = 0x%08x\n",
+                                 hal_machw_reg_str[i], hw_info->mac_hw_reg[i]);
+
+       *pos += scnprintf(buf + *pos, bufsz - *pos,
+                         "#########################\n\n");
+
+       *pos += scnprintf(buf + *pos, bufsz - *pos,
+                         "############# MAC HW Secondary FSMs #############\n");
+       *pos += scnprintf(buf + *pos, bufsz - *pos,
+                         "|---------------------------------------------------------|\n");
+       *pos += scnprintf(buf + *pos, bufsz - *pos,
+                        "|MU IDX|%12s|%12s|%12s|%11s|\n",
+                         hal_machw_reg_str[HAL_MACHW_AGGR_STATUS],
+                         hal_machw_reg_str[HAL_MACHW_DEBUG_HWSM_1],
+                         hal_machw_reg_str[HAL_MACHW_DEBUG_HWSM_2],
+                         hal_machw_reg_str[HAL_MACHW_DEBUG_HWSM_3]);
+
+       *pos += scnprintf(buf + *pos, bufsz - *pos,
+                         "|---------------------------------------------------------|\n");
+
+       for (i = 0; i < ARRAY_SIZE(hw_info->mac_hw_sec_fsm); ++i) {
+               mu_idx = CL_MU1_IDX + i;
+               *pos += scnprintf(buf + *pos, bufsz - *pos,
+                                 "| MU %u | 0x%08x | 0x%08x | 0x%08x | 0x%08x|\n",
+                                 mu_idx,
+                                 hw_info->mac_hw_sec_fsm[i][HAL_MACHW_AGGR_STATUS],
+                                 hw_info->mac_hw_sec_fsm[i][HAL_MACHW_DEBUG_HWSM_1],
+                                 hw_info->mac_hw_sec_fsm[i][HAL_MACHW_DEBUG_HWSM_2],
+                                 hw_info->mac_hw_sec_fsm[i][HAL_MACHW_DEBUG_HWSM_3]);
+       }
+       *pos += scnprintf(buf + *pos, bufsz - *pos,
+                         "|---------------------------------------------------------|\n\n");
+
+       /* Write THD data if valid */
+       for (i = HAL_MACHW_DEBUG_BCN_S_PTR; i <= HAL_MACHW_DEBUG_TX_C_PTR; ++i)
+               if (hw_info->mac_hw_reg[i]) {
+                       u8 thd_idx = i - HAL_MACHW_DEBUG_BCN_S_PTR;
+
+                       cl_dbg_thd_print(cl_hw, buf, bufsz, pos,
+                                        &dump->machw_thd_info.thd[thd_idx],
+                                        hw_info->mac_hw_reg[i]);
+               }
+
+       cl_dbg_dump_txm_regs(cl_hw, buf, bufsz, pos, dump);
+}
+
+static void cl_dbg_dump_phyhw_regs(struct cl_hw *cl_hw,
+                                  u8 *buf, int bufsz, int *pos,
+                                  struct dbg_error_trace_info_drv *dump)
+{
+       int i = 0;
+       const char *phy_hw_mpu_reg_str[PHY_HW_DBG_REGS_CNT] = {
+               [MPU_COMMON_FORMAT]       = "MPU_COMMON_FORMAT",
+               [MPU_COMMON_FIELD_CTRL]   = "MPU_COMMON_FIELD_CTRL",
+               [MPU_COMMON_LEGACY_INFO]  = "MPU_COMMON_LEGACY_INFO",
+               [MPU_COMMON_COMMON_CFG_1] = "MPU_COMMON_COMMON_CFG_1",
+               [MPU_COMMON_COMMON_CFG_2] = "MPU_COMMON_COMMON_CFG_2",
+               [MPU_COMMON_COMMON_CFG_3] = "MPU_COMMON_COMMON_CFG_3",
+               [MPU_COMMON_HE_CFG_1]     = "MPU_COMMON_HE_CFG_1",
+               [MPU_COMMON_HE_CFG_2]     = "MPU_COMMON_HE_CFG_2",
+               [MPU_COMMON_INT_STAT_RAW] = "MPU_COMMON_INT_STAT_RAW",
+               [RIU_CCAGENSTAT]          = "RIU_CCAGENSTAT",
+       };
+
+       *pos += scnprintf(buf + *pos, bufsz - *pos, "##### PHY HW regs ####\n");
+
+       for (i = 0; i < ARRAY_SIZE(dump->common_info.hw_info.phy_mpu_hw_reg); ++i)
+               *pos += scnprintf(buf + *pos, bufsz - *pos, "%25s = 0x%08x\n",
+                                 phy_hw_mpu_reg_str[i],
+                                 dump->common_info.hw_info.phy_mpu_hw_reg[i]);
+
+       *pos += scnprintf(buf + *pos, bufsz - *pos, "#########################\n\n");
+}
+
+static void cl_dbg_dump_ac_info(struct cl_hw *cl_hw,
+                               u8 *buf, int bufsz, int *pos,
+                               struct dbg_error_trace_info_drv *dump)
+{
+       int i = 0;
+       struct dbg_fw_info *fw_info = &dump->common_info.fw_info;
+       const char *fw_tx_state_str[CE_TXL_TX_PATH_MAX] = {
+               [CE_TXL_TX_PATH_IDLE]                  = "PATH_IDLE",
+               [CE_TXL_TX_PATH_START]                 = "PATH_START",
+               [CE_TXL_TX_PATH_POST_START_DOWNLOAD]   = "POST_START_DOWNLOAD",
+               [CE_TXL_TX_PATH_TX_DATA_DOWNLOADING]   = "TX_DATA_DOWNLOADING",
+               [CE_TXL_TX_PATH_MU_RECOVERY]           = "MU_RECOVERY",
+               [CE_TXL_TX_PATH_LAST_DOWNLOADING]      = "LAST_DOWNLOADING",
+               [CE_TXL_TX_PATH_NEXT_SESSION_PREPARED] = "NEXT_SESSION_PREP",
+               [CE_TXL_TX_PATH_MU_NEXT_JOB_READY]     = "MU_NEXT_JOB_READY",
+       };
+
+       *pos += scnprintf(buf + *pos, bufsz - *pos,
+                         "\n#####  Per AC info  ####\n");
+       *pos += scnprintf(buf + *pos, bufsz - *pos,
+                         "|--------------------------------------------------------|\n");
+       *pos += scnprintf(buf + *pos, bufsz - *pos,
+                         "|AC|MU|session|phys queue|check_state|   TX path state   |\n");
+
+       for (i = 0; i < ARRAY_SIZE(fw_info->ac_info); ++i) {
+               u32 mu_idx = (i >= IPC_TX_QUEUE_CNT) ? (i - IPC_TX_QUEUE_CNT + 1) : 0;
+               u32 session_idx = (fw_info->ac_info[i].active_session != FW_DBG_INVALID_SESSION) ?
+                       fw_info->ac_info[i].active_session : 0;
+
+               *pos += scnprintf(buf + *pos, bufsz - *pos,
+                                 "|--+--+-------+----------+-----------+-------------------|\n");
+               *pos += scnprintf(buf + *pos, bufsz - *pos,
+                                 "|%2u|%2u|%7u|%10u|%11u|%19s|\n",
+                                 i,
+                                 mu_idx,
+                                 session_idx,
+                                 fw_info->ac_info[i].physical_queue_idx,
+                                 fw_info->ac_info[i].chk_state,
+                                 fw_tx_state_str[fw_info->ac_info[i].tx_path_state]);
+       }
+
+       *pos += scnprintf(buf + *pos, bufsz - *pos,
+                         "|--------------------------------------------------------|\n");
+}
+
+static void cl_dbg_dump_single_tx_list_info(struct cl_hw *cl_hw,
+                                           u8 *buf, int bufsz, int *pos,
+                                           struct dbg_error_trace_info_drv *dump)
+{
+       int i = 0;
+       struct dbg_fw_info *fw_info = &dump->common_info.fw_info;
+
+       *pos += scnprintf(buf + *pos, bufsz - *pos,
+                         "\n##### Singles txdesc lists info ####\n");
+       *pos += scnprintf(buf + *pos, bufsz - *pos,
+                         "|----|---------|-------------|--------------|\n");
+       *pos += scnprintf(buf + *pos, bufsz - *pos,
+                         "| AC | pending | downloading | transmitting |\n");
+       *pos += scnprintf(buf + *pos, bufsz - *pos,
+                         "|----|---------|-------------|--------------|\n");
+
+       for (i = 0; i < ARRAY_SIZE(fw_info->txlist_info_singles); ++i) {
+               *pos += scnprintf(buf + *pos, bufsz - *pos,
+                                 "|%4u|%9u|%13u|%14u|\n",
+                                 i,
+                                 fw_info->txlist_info_singles[i].pending_cnt,
+                                 fw_info->txlist_info_singles[i].download_cnt,
+                                 fw_info->txlist_info_singles[i].transmit_cnt);
+
+               *pos += scnprintf(buf + *pos, bufsz - *pos,
+                                 "|----|---------|-------------|--------------|\n");
+       }
+}
+
+static void cl_dbg_dump_agg_tx_list_info(struct cl_hw *cl_hw,
+                                        u8 *buf, int bufsz, int *pos,
+                                        struct dbg_error_trace_info_drv *dump)
+{
+       int i = 0;
+       u32 mu_idx;
+       struct dbg_fw_info *fw_info = &dump->common_info.fw_info;
+
+       *pos += scnprintf(buf + *pos, bufsz - *pos,
+                         "\n##### Agg txdesc lists info ####\n");
+       *pos += scnprintf(buf + *pos, bufsz - *pos,
+                         "|----------------------------------------------------------------|\n");
+       *pos += scnprintf(buf + *pos, bufsz - *pos,
+                         "|idx|mu|session|pending|download|transmit|wait4ba|next   |next   |\n");
+       *pos += scnprintf(buf + *pos, bufsz - *pos,
+                         "|   |  |       |       |        |        |       |session|pending|\n");
+
+       for (i = 0; i < ARRAY_SIZE(fw_info->txlist_info_agg); ++i) {
+               mu_idx = ((i >= AGG_MU1_IDX) && (i <= AGG_MU7_IDX)) ? (i - AGG_MU1_IDX + 1) : 0;
+
+               *pos += scnprintf(buf + *pos, bufsz - *pos,
+                                 "|---+--+-------+-------+--------+--------+--"
+                                 "-----+-------+-------|\n");
+               *pos += scnprintf(buf + *pos, bufsz - *pos,
+                                 "|%3u|%2u|%7u|%7u|%8u|%8u|%7u|%7u|%7u|\n",
+                                 i,
+                                 mu_idx,
+                                 fw_info->txlist_info_agg[i].curr_session_idx,
+                                 fw_info->txlist_info_agg[i].pending_cnt,
+                                 fw_info->txlist_info_agg[i].download_cnt,
+                                 fw_info->txlist_info_agg[i].transmit_cnt,
+                                 fw_info->txlist_info_agg[i].wait_for_ba_cnt,
+                                 fw_info->txlist_info_agg[i].next_session_idx,
+                                fw_info->txlist_info_agg[i].next_pending_cnt);
+       }
+
+       *pos += scnprintf(buf + *pos, bufsz - *pos,
+                         "|----------------------------------------------------------------|\n");
+}
+
+static void cl_dbg_dump_thd_chains_info(struct cl_hw *cl_hw,
+                                       u8 *buf, int bufsz, int *pos,
+                                       struct dbg_error_trace_info_drv *dump, u8 ac)
+{
+       int i = 0;
+       u32 data_offset = 0;
+       struct dbg_thd_chains_info *chain_info = &dump->thd_chains_info[ac];
+       struct dbg_thd_chains_data *chain_data = &dump->thd_chains_data[ac];
+       struct tx_hd *hd;
+       struct tx_policy_tbl *policy_tbl;
+       struct tx_pbd *pbd;
+
+       while (chain_info->type_array[i] != DBG_CHAINS_INFO_EMPTY) {
+               switch (chain_info->type_array[i]) {
+               case DBG_CHAINS_INFO_THD:
+                       hd = (struct tx_hd *)&chain_data->data[data_offset];
+                       cl_dbg_thd_print(cl_hw, buf, bufsz, pos, hd,
+                                        chain_info->elem_address[i]);
+                       data_offset += sizeof(struct tx_hd);
+                       break;
+
+               case DBG_CHAINS_INFO_PT:
+                       policy_tbl = (struct tx_policy_tbl *)&chain_data->data[data_offset];
+                       cl_dbg_policy_table_print(cl_hw, buf, bufsz, pos,
+                                                 policy_tbl,
+                                                 chain_info->elem_address[i]);
+                       data_offset += sizeof(struct tx_policy_tbl);
+                       break;
+
+               case DBG_CHAINS_INFO_PBD:
+                       pbd = (struct tx_pbd *)&chain_data->data[data_offset];
+                       cl_dbg_pbd_print(cl_hw, buf, bufsz, pos, pbd,
+                                        chain_info->elem_address[i]);
+                       data_offset += sizeof(struct tx_pbd);
+                       break;
+
+               default:
+                       return;
+               }
+
+               i++;
+               if (i >= DBG_CHAINS_INFO_ELEM_CNT)
+                       break;
+       }
+}
+
+static void cl_dbg_dump_agg_thd_info(struct cl_hw *cl_hw,
+                                    u8 *buf, int bufsz, int *pos,
+                                    struct dbg_error_trace_info_drv *dump,
+                                    u8 ac, u8 mu_idx)
+{
+       u8 agg_idx = (ac < AGG_MU1_IDX) ? ac : (mu_idx + AGG_MU1_IDX - 1);
+       u32 addr = dump->common_info.agg_thds_addr[agg_idx].rts_cts_thd_addr;
+
+       if (addr) {
+               /* RTS CTS THD print */
+               *pos += scnprintf(buf + *pos, bufsz - *pos, "\n  RTS CTS THD 0x%x\n", addr);
+               cl_dbg_thd_print(cl_hw, buf, bufsz, pos,
+                                &dump->agg_thd_info[agg_idx].rts_cts_thd, addr);
+       }
+
+       addr = dump->common_info.agg_thds_addr[agg_idx].athd_addr;
+       if (addr) {
+               /* ATHD print */
+               *pos += scnprintf(buf + *pos, bufsz - *pos, "\n  ATHD 0x%x\n", addr);
+               cl_dbg_thd_print(cl_hw, buf, bufsz, pos,
+                                &dump->agg_thd_info[agg_idx].athd, addr);
+       }
+
+       addr = dump->common_info.agg_thds_addr[agg_idx].policy_table_addr;
+       if (addr) {
+               /* Policy Table print */
+               *pos += scnprintf(buf + *pos, bufsz - *pos, "  Policy Table 0x%x\n", addr);
+               cl_dbg_policy_table_print(cl_hw, buf, bufsz, pos,
+                                         &dump->agg_thd_info[agg_idx].policy_table,
+                                         addr);
+       }
+
+       addr = dump->common_info.agg_thds_addr[agg_idx].tf_thd_addr;
+       if (addr) {
+               /* TF-THD print */
+               *pos += scnprintf(buf + *pos, bufsz - *pos, "  TF-THD 0x%x\n", addr);
+               cl_dbg_thd_print(cl_hw, buf, bufsz, pos,
+                                &dump->agg_thd_info[agg_idx].tf_thd, addr);
+       }
+
+       cl_dbg_dump_thd_chains_info(cl_hw, buf, bufsz, pos, dump, ac);
+
+       addr = dump->common_info.agg_thds_addr[agg_idx].bar_thd_addr;
+       if (addr) {
+               /* BAR THD print */
+               *pos += scnprintf(buf + *pos, bufsz - *pos, "  BAR THD 0x%x\n", addr);
+               cl_dbg_thd_print(cl_hw, buf, bufsz, pos,
+                                &dump->agg_thd_info[agg_idx].bar_thd, addr);
+       }
+}
+
+static void cl_dbg_dump_thd_info(struct cl_hw *cl_hw,
+                                u8 *buf, int bufsz, int *pos,
+                                struct dbg_error_trace_info_drv *dump,
+                                u8 ac, u8 mu_idx)
+{
+       u32 session_idx = dump->common_info.fw_info.ac_info[ac].active_session;
+
+       if (session_idx != FW_DBG_INVALID_SESSION) {
+               bool is_agg = ((mu_idx > 0) || (session_idx >= IPC_TX_QUEUE_CNT)) ? true : false;
+
+               if (is_agg)
+                       cl_dbg_dump_agg_thd_info(cl_hw, buf, bufsz, pos, dump, ac, mu_idx);
+               else
+                       cl_dbg_dump_thd_chains_info(cl_hw, buf, bufsz, pos, dump, ac);
+       }
+}
+
+static void cl_dbg_dump_tx_trace_info(struct cl_hw *cl_hw,
+                                     u8 *buf, int bufsz, int *pos,
+                                     struct dbg_error_trace_info_drv *dump)
+{
+       int i = 0;
+       const char *fw_tx_frame_type_str[CL_MAX_FRM_TYPE] = {
+               [SING_FRM_TYPE]             = "MPDU",
+               [AGG_FRM_TYPE]              = "AMPDU",
+               [AGG_NEXT_IN_TXOP_FRM_TYPE] = "TXOP",
+               [INT_FRM_TYPE]              = "INTERNAL",
+               [BCN_FRM_TYPE]              = "BCN",
+               [MU_FRM_TYPE]               = "MU_AMPDU",
+               [FRM_TYPE_BASIC_TRIGGER]    = "BASIC_TF",
+               [FRM_TYPE_MU_BAR_TRIGGER]   = "MU_BAR",
+               [BCK_BCN_TYPE]              = "BCN_BCK",
+               [QOS_NULL]                  = "QOSNULL",
+               [AGG_TB]                    = "AGG_TB",
+               [RTS_TYPE]                  = "RTS_FW",
+               [CTS_TYPE]                  = "CTS_FW",
+               [TB_SINGLE_FRM_TYPE]        = "TB_SMPDU",
+               [TF_AMPDU_TYPE]             = "TF_AMPDU"
+       };
+
+       *pos += scnprintf(buf + *pos,
+                         bufsz - *pos,
+                         "\n#### TX Trace ####\n");
+
+       for (i = 0; i < ARRAY_SIZE(dump->common_info.fw_info.txl_ac_chain_trace); ++i) {
+               u8 trace_idx = 0, table_idx = 0;
+               u32 mu_idx;
+               struct dbg_txl_ac_chain_trace *trace_ptr =
+                       &dump->common_info.fw_info.txl_ac_chain_trace[i];
+               struct cl_dbg_txl_chain_info *data;
+
+               if (trace_ptr->next_chain_index == 0)
+                       table_idx = DBG_TXL_FRAME_EXCH_TRACE_DEPTH - 1;
+               else
+                       table_idx = trace_ptr->next_chain_index - 1;
+
+               data = &trace_ptr->data[table_idx];
+
+               if (data->count == 0)
+                       continue;
+
+               mu_idx = (i >= IPC_TX_QUEUE_CNT) ? (i - IPC_TX_QUEUE_CNT + 1) : 0;
+
+               *pos += scnprintf(buf + *pos, bufsz - *pos, "\n AC %u MU idx %u:\n", i, mu_idx);
+               *pos += scnprintf(buf + *pos, bufsz - *pos,
+                                 "|========|========|==========|==========|=========="
+                                 "|======|==========|==========|=====|======="
+                                 "|======|=========|=======|==========|\n"
+                                 "|#PPDU   | Type   |First THD | Last THD | Prev THD "
+                                 "|Req BW| PTalbe   |PTalbe_HE |queue|Length "
+                                 "|#MPDU |Chosen BW|TX time| txstatus |\n"
+                                 "|========|========|==========|==========|=========="
+                                 "|======|==========|==========|=====|======="
+                                 "|======|=========|=======|==========|\n");
+
+               for (trace_idx = 0; trace_idx < DBG_TXL_FRAME_EXCH_TRACE_DEPTH; ++trace_idx) {
+                       *pos += scnprintf(buf + *pos,
+                                         bufsz - *pos,
+                                         "|%8u|%8s|0x%08x|0x%08x|0x%08x|%6u|0x%08x"
+                                         "|0x%08x|%5u|%7u|%6u|%9u|%7u|0x%08x|\n",
+                                         data->count,
+                                         fw_tx_frame_type_str[data->frm_type],
+                                         data->first_thd_ptr,
+                                         data->last_thd_ptr,
+                                         data->prev_thd_ptr,
+                                         data->reqbw,
+                                         data->rate_ctrl_info,
+                                         data->rate_ctrl_info_he,
+                                         data->ce_txq_idx,
+                                         data->length,
+                                         data->mpdu_count,
+                                         data->chbw,
+                                         data->tx_time,
+                                         data->txstatus);
+
+                       if (!table_idx)
+                               table_idx = DBG_TXL_FRAME_EXCH_TRACE_DEPTH - 1;
+                       else
+                               table_idx--;
+
+                       data = &trace_ptr->data[table_idx];
+               }
+
+               *pos += scnprintf(buf + *pos,
+                                 bufsz - *pos,
+                                 "|========|========|==========|==========|==="
+                                 "=======|======|==========|==========|=====|="
+                                 "======|======|=========|=======|==========|\n");
+
+               cl_dbg_dump_thd_info(cl_hw, buf, bufsz, pos, dump, i, mu_idx);
+       }
+}
+
+static void cl_dbg_dump_error_info(struct cl_hw *cl_hw,
+                                  u8 *buf, int bufsz, int *pos,
+                                  struct dbg_error_trace_info_drv *trace)
+{
+       struct dbg_print_ind *ind = &trace->common_info.error_info;
+       const char *assert_string;
+       u16 file_id = le16_to_cpu(ind->file_id);
+       u16 line = le16_to_cpu(ind->line);
+       u16 has_param = le16_to_cpu(ind->has_param);
+       u32 param = has_param ? le32_to_cpu(ind->param) : 0;
+
+       if (file_id && line) {
+               *pos += scnprintf(buf + *pos,
+                                bufsz - *pos,
+                                "ASSERT_TCV%u @ FILE=%hu LINE=%hu param=0x%08X\n",
+                                cl_hw->idx, file_id, line, param);
+
+               /* Get assert string */
+               assert_string = cl_dbgfile_get_msg_txt(&cl_hw->dbg_data, file_id, line);
+               if (!assert_string)
+                       assert_string = "ASSERT STRING NOT FOUND";
+
+               *pos += scnprintf(buf + *pos,
+                                 bufsz - *pos,
+                                 "%s\n", assert_string);
+       } else {
+               struct dbg_info *dbg_info = (struct dbg_info *)cl_hw->dbginfo.buf;
+
+               *pos += snprintf(buf + *pos,
+                                bufsz - *pos,
+                                "%s\n", dbg_info->u.dump.general_data.error);
+       }
+}
+
+static void cl_dbg_dump_fw_trace_info(struct cl_hw *cl_hw,
+                                     u8 *buf, int bufsz, int *pos,
+                                     struct dbg_error_trace_info_drv *dump)
+{
+       int i = 0;
+
+       *pos += scnprintf(buf + *pos,
+                         bufsz - *pos,
+                         "\n###   FW trace dump   ###\n"
+                         "------------------------------------------------------"
+                         "-----------------------------------\n"
+                         "|idx|   String        | value 1  | value 2  | value 3 "
+                         "| value 4  | value 5  | value 6  |\n"
+                         "|---+-----------------+----------+----------+---------"
+                         "-+----------+----------+----------|\n");
+
+       for (i = 0; i < ARRAY_SIZE(dump->common_info.fw_info.fw_trace); ++i) {
+               u8 dbg_idx = (dump->common_info.fw_info.fw_trace_idx + i) % DBG_FW_TRACE_SIZE;
+               struct dbg_fw_trace *trace = &dump->common_info.fw_info.fw_trace[dbg_idx];
+               char *str = trace->string_ptr ? trace->string_char : "NULL";
+
+               *pos += scnprintf(buf + *pos,
+                                 bufsz - *pos,
+                                 "|%3u|%17s|0x%08x|0x%08x|0x%08x|0x%08x|0x%08x|0x%08x|\n",
+                                 i,
+                                 str,
+                                 trace->var_1,
+                                 trace->var_2,
+                                 trace->var_3,
+                                 trace->var_4,
+                                 trace->var_5,
+                                 trace->var_6);
+       }
+
+       *pos += scnprintf(buf + *pos,
+                         bufsz - *pos,
+                         "----------------------------------------------------"
+                         "-------------------------------------\n");
+}
+
+static int cl_dbg_dump_host_descr(struct cl_hw *cl_hw,
+                                 u8 *buf, int bufsz, int *pos)
+{
+       struct new_utsname *nu = init_utsname();
+
+       *pos += scnprintf(buf + *pos, bufsz - *pos,
+                         "#### KERNEL ####\n"
+                         "release: %s\n"
+                         "version: %s\n"
+                         "machine: %s\n",
+                         nu->release,
+                         nu->version,
+                         nu->machine);
+
+       *pos += scnprintf(buf + *pos, bufsz - *pos,
+                         "#### CPUs ####\n"
+                         "num online  : %d\n"
+                         "num possible: %d\n"
+                         "num present : %d\n"
+                         "num active  : %d\n",
+                         num_online_cpus(),
+                         num_possible_cpus(),
+                         num_present_cpus(),
+                         num_active_cpus());
+
+       *pos += scnprintf(buf + *pos, bufsz - *pos,
+                         "#### ENDIANNESS ####\n"
+                         "LE (byte) : %u\n"
+                         "LE (bits) : %u\n"
+                         "BE (byte) : %u\n"
+                         "BE (bits) : %u\n",
+                         cl_are_host_bytes_le(),
+                         cl_are_host_bits_le(),
+                         cl_are_host_bytes_be(),
+                         cl_are_host_bits_be());
+       return 0;
+}
+
+static int cl_dbg_dump_chip_descr(struct cl_hw *cl_hw,
+                                 u8 *buf, int bufsz, int *pos)
+{
+       struct cl_version_db *vd = &cl_hw->version_db;
+
+       *pos += scnprintf(buf + *pos, bufsz - *pos,
+                         "#### BASE ####\n"
+                         "chip : %u\n"
+                         "TCV  : %u\n"
+                         "bus  : %u\n",
+                         cl_hw->chip->idx,
+                         cl_hw->tcv_idx,
+                         cl_hw->chip->bus_type);
+
+       *pos += scnprintf(buf + *pos, bufsz - *pos,
+                         "#### VERSIONS ####\n"
+                         "drv     : %s\n"
+                         "FW      : %s\n"
+                         "DSP     : 0x%-.8X\n"
+                         "RFIC SW : %u\n"
+                         "RFIC HW : 0x%X\n",
+                         vd->drv,
+                         vd->fw,
+                         vd->dsp,
+                         vd->rfic_sw,
+                         vd->rfic_hw);
+       /* TODO: AGC info */
+       *pos += scnprintf(buf + *pos, bufsz - *pos,
+                         "#### STATE ####\n"
+                         "recoveries : %u\n"
+                         "DRV flags  : %lu\n"
+                         "TCV-0 en   : %u\n"
+                         "TCV-1 en   : %u\n",
+                         cl_hw->fw_recovery_cntr,
+                         cl_hw->drv_flags,
+                         cl_chip_is_tcv0_enabled(cl_hw->chip),
+                         cl_chip_is_tcv1_enabled(cl_hw->chip));
+       return 0;
+}
+
+static int cl_dbg_dump_ela_descr(struct cl_hw *cl_hw,
+                                u8 *buf, int bufsz, int *pos)
+{
+       struct cl_chip *chip = cl_hw->chip;
+       struct cl_ela_db *ed = &chip->ela_db;
+       int ret = 0;
+
+       if (cl_ela_is_on(chip)) {
+               *pos += scnprintf(buf + *pos, bufsz - *pos,
+                                 "#### CONF SOURCE ####\n"
+                                 "ELA mode: %s #\n",
+                                 chip->conf->ce_ela_mode);
+               *pos += scnprintf(buf + *pos, bufsz - *pos,
+                                 "#### CONF LIFETIME ####\n"
+                                 "adaptations  : %u #\n"
+                                 "applications : %u #\n"
+                                 "error state  : %d #\n",
+                                 ed->stats.adaptations_cnt,
+                                 ed->stats.applications_cnt,
+                                 ed->error_state);
+       } else {
+               *pos += scnprintf(buf + *pos, bufsz - *pos,
+                                 "#### DISABLED ####\n");
+       }
+       return ret;
+}
+
+static int cl_dbg_dump_raw_lcu_conf(struct cl_hw *cl_hw,
+                                   u8 *buf, int bufsz, int *pos)
+{
+       struct cl_chip *chip = cl_hw->chip;
+       struct cl_ela_db *ed = &chip->ela_db;
+       int ret = 0;
+
+       if (cl_ela_is_on(chip) && ed->raw_lcu_config)
+               *pos += scnprintf(buf + *pos, bufsz - *pos, "%s", ed->raw_lcu_config);
+       else
+               ret = -ENODATA;
+       return ret;
+}
+
+static int cl_dbg_dump_adapted_lcu_conf(struct cl_hw *cl_hw,
+                                       u8 *buf, int bufsz, int *pos)
+{
+       struct cl_chip *chip = cl_hw->chip;
+       struct cl_ela_db *ed = &chip->ela_db;
+       struct cl_lcu_cmd *cmd = NULL, *cmd_tmp = NULL;
+       int ret = 0;
+
+       if (cl_ela_is_on(chip)) {
+               *pos += scnprintf(buf + *pos, bufsz - *pos,
+                                 "#### CONF SOURCE ####\n"
+                                 "# %s #\n",
+                                 cl_ela_lcu_config_name(chip));
+               *pos += scnprintf(buf + *pos, bufsz - *pos,
+                                 "#### CONF COMMANDS ####\n");
+
+               list_for_each_entry_safe(cmd, cmd_tmp, &ed->cmd_head, cmd_list)
+                       *pos += scnprintf(buf + *pos, bufsz - *pos,
+                                         "%s 0x%X 0x%X\n",
+                                         cl_ela_lcu_cmd_str(cmd->type),
+                                         cmd->offset,
+                                         cmd->value);
+       } else {
+               ret = -ENODATA;
+       }
+       return ret;
+}
+
+static int cl_dbg_dump_la_mem(struct cl_hw *cl_hw,
+                             u8 *buf, int bufsz, int *pos,
+                             int idx, struct dbg_info *dbg_info)
+{
+       size_t la_size = 0;
+
+       if (ARRAY_SIZE(dbg_info->u.dump.la_mem) < idx + 1)
+               return -EINVAL;
+
+       la_size = ARRAY_SIZE(dbg_info->u.dump.la_mem[idx]);
+       if (la_size > (bufsz - *pos))
+               return -ENOBUFS;
+
+       memcpy(buf + *pos, &dbg_info->u.dump.la_mem[idx], la_size);
+       *pos += la_size;
+
+       return 0;
+}
+
+static int cl_dbg_dump_la_conf(struct cl_hw *cl_hw,
+                              u8 *buf, int bufsz, int *pos,
+                              int idx, struct dbg_debug_info_tag *gdata)
+{
+       size_t la_size = 0;
+
+       if (ARRAY_SIZE(gdata->la_conf) < idx + 1)
+               return -EINVAL;
+
+       la_size = sizeof(gdata->la_conf[idx]);
+       if (la_size > (bufsz - *pos))
+               return -ENOBUFS;
+
+       memcpy(buf + *pos, &gdata->la_conf[idx], la_size);
+       *pos += la_size;
+
+       return 0;
+}
+
+static int cl_dbg_dump_mac_diags(struct cl_hw *cl_hw,
+                                u8 *buf, int bufsz, int *pos,
+                                struct dbg_debug_info_tag *gdata)
+{
+       size_t la_size = ARRAY_SIZE(gdata->diags_mac);
+
+       if (la_size > (bufsz - *pos))
+               return -ENOBUFS;
+
+       memcpy(buf + *pos, &gdata->diags_mac, la_size);
+       *pos += la_size;
+
+       return 0;
+}
+
+static int cl_dbg_dump_hw_diags(struct cl_hw *cl_hw,
+                               u8 *buf, int bufsz, int *pos,
+                               struct dbg_debug_info_tag *gdata)
+{
+       *pos += scnprintf(buf + *pos, bufsz - *pos, "%08X\n", gdata->hw_diag);
+
+       return 0;
+}
+
+static int cl_dbg_dump_sw_diags(struct cl_hw *cl_hw,
+                               u8 *buf, int bufsz, int *pos,
+                               struct dbg_debug_info_tag *gdata)
+{
+       size_t la_size = min_t(size_t, ARRAY_SIZE(gdata->sw_diag),
+                              gdata->sw_diag_len);
+
+       if (la_size > (bufsz - *pos))
+               return -ENOBUFS;
+
+       memcpy(buf + *pos, &gdata->sw_diag, la_size);
+       *pos += la_size;
+
+       return 0;
+}
+
+static int cl_dbg_dump_chan_info(struct cl_hw *cl_hw,
+                                u8 *buf, int bufsz, int *pos,
+                                struct dbg_debug_info_tag *gdata)
+{
+       u32 info1 = le32_to_cpu(gdata->chan_info.info1);
+       u32 info2 = le32_to_cpu(gdata->chan_info.info2);
+       u8 band = info1 & 0xFF;
+       u8 type = (info1 >> 8) & 0xFF;
+       u16 prim20 = (info1 >> 16) & 0xFFFF;
+       u16 center1 = info2 & 0xFFFF;
+
+       *pos += scnprintf(buf + *pos, bufsz - *pos,
+                         "#### FW ####\n"
+                         "band         : %u\n"
+                         "type         : %u\n"
+                         "prim20_freq  : %u.%u MHz\n"
+                         "center1_freq : %u.%u MHz\n",
+                         band,
+                         type,
+                         Q2_TO_FREQ(prim20), Q2_TO_FREQ_FRAC(prim20),
+                         Q2_TO_FREQ(center1), Q2_TO_FREQ_FRAC(center1));
+       *pos += scnprintf(buf + *pos, bufsz - *pos,
+                         "#### DRIVER ####\n"
+                         "channel      : %u\n"
+                         "bw           : %u\n"
+                         "primary_freq : %u MHz\n"
+                         "center_freq  : %u MHz\n",
+                         cl_hw->channel,
+                         cl_hw->bw,
+                         cl_hw->primary_freq,
+                         cl_hw->center_freq);
+       return 0;
+}
+
+/**
+ * pre_fill_hook - initialize record data in coredump container
+ *
+ * Each record presents some section of information. Since, at this stage we
+ * have no idea about estimated data length, we shift "pos" only for size
+ * of header information, actual number of written bytes should be calculated
+ * in the post_fill_hook.
+ *
+ * @record: (NLEV) Name-Length-Error-Values record.
+ * @d: Coredump to fill in.
+ * @name: Name to set for this specific record;
+ * @pos: Position of last filled in element in the coredump (equal prev_pos till
+ *  fill in).
+ * @prev_pos: Position of the previous filled in element in the coredump.
+ *
+ * Returns nothing.
+ */
+static void pre_fill_hook(struct cl_nlev **record, struct cl_coredump *cd,
+                         char *name, int *pos, int *prev_pos)
+{
+       size_t coredump_space = le32_to_cpu(cd->len) - sizeof(*cd);
+       size_t free_space = coredump_space - *pos;
+
+       /* Save prev postion for NLEV length calculation in "post" hook */
+       *prev_pos = *pos;
+
+       /* Check if there is enough space for NLE (w/o V) */
+       if (free_space < sizeof(**record))
+               return;
+
+       /* Set pointer of the record to proper buffer place */
+       *record = (struct cl_nlev *)(cd->data + *pos);
+
+       /* Fill type info string */
+       scnprintf(cd->data + *pos, free_space, "%s", name);
+
+       /* Adjust position as like as new NLEV was added */
+       *pos += sizeof(**record);
+}
+
+/**
+ * post_fill_hook - finalize record data in the coredump container
+ *
+ * @record: (NLEV) Name-Length-Error-Values record.
+ * @err_code: processing error indication, typical errno
+ * @pos: Position of last filled in element in the coredump.
+ * @prev_pos: Position of the previous filled in element in the coredump,
+ *  in conjunction with "pos" is used to calculated filled in data and set
+ *  it as "Length" in the NLEV header.
+ *
+ * Returns nothing.
+ */
+static void post_fill_hook(struct cl_nlev **record, int *err_code, int *pos,
+                          int *prev_pos)
+{
+       /* Finalize what we know about NLEV - size (without headers)
+        * and processing error codeA
+        */
+       (**record).l = cpu_to_le32(*pos - *prev_pos - sizeof(**record));
+       (**record).e = cpu_to_le32(*err_code);
+
+       /* Reset error code for further usage */
+       *err_code = 0;
+}
+
+struct cl_coredump *cl_fw_dbg_prepare_coredump(struct cl_hw *cl_hw)
+{
+       struct dbg_info *dbg_info = (struct dbg_info *)cl_hw->dbginfo.buf;
+       struct dbg_error_trace_info_drv *fdump = &dbg_info->u.dump.fw_dump;
+       struct dbg_debug_info_tag *gdata = &dbg_info->u.dump.general_data;
+       struct cl_coredump *cd;
+       unsigned char *buf;
+       /* TODO: Make this size dynamic */
+       size_t len = PAGE_SIZE * 100;
+       size_t data_len = len - sizeof(*cd);
+       int pos = 0;
+       int prev_pos = 0;
+       int e = 0;
+       struct cl_nlev *rec = NULL;
+
+       buf = vzalloc(len);
+       if (!buf)
+               goto out;
+
+       cd = (typeof(cd))buf;
+       cd->len = cpu_to_le32(len);
+       cd->self_version = cpu_to_le32((CL_COREDUMP_V1 << 28) +
+                                      sizeof(*cd) + sizeof(*rec));
+       /* TODO: Mask support */
+       cd->dump_mask = cpu_to_le32(0);
+       cd->trig_tv_sec = cpu_to_le64(cl_hw->dbginfo.trigger_tstamp.tv_sec);
+       cd->trig_tv_nsec = cpu_to_le64(cl_hw->dbginfo.trigger_tstamp.tv_nsec);
+       scnprintf(cd->magic, sizeof(cd->magic), "CE_CL8K_DUMP");
+
+       /* Main section with dynamic dump data filling */
+       mutex_lock(&cl_hw->dbginfo.mutex);
+
+       pre_fill_hook(&rec, cd, "chip_descr", &pos, &prev_pos);
+       e = cl_dbg_dump_chip_descr(cl_hw, cd->data, data_len, &pos);
+       post_fill_hook(&rec, &e, &pos, &prev_pos);
+
+       pre_fill_hook(&rec, cd, "host_descr", &pos, &prev_pos);
+       e = cl_dbg_dump_host_descr(cl_hw, cd->data, data_len, &pos);
+       post_fill_hook(&rec, &e, &pos, &prev_pos);
+
+       pre_fill_hook(&rec, cd, "error", &pos, &prev_pos);
+       cl_dbg_dump_error_info(cl_hw, cd->data, data_len, &pos, fdump);
+       post_fill_hook(&rec, &e, &pos, &prev_pos);
+
+       /* Embedded logic analyzer info */
+       pre_fill_hook(&rec, cd, "ela_descr", &pos, &prev_pos);
+       e = cl_dbg_dump_ela_descr(cl_hw, cd->data, data_len, &pos);
+       post_fill_hook(&rec, &e, &pos, &prev_pos);
+
+       pre_fill_hook(&rec, cd, "raw_lcu_conf", &pos, &prev_pos);
+       e = cl_dbg_dump_raw_lcu_conf(cl_hw, cd->data, data_len, &pos);
+       post_fill_hook(&rec, &e, &pos, &prev_pos);
+
+       pre_fill_hook(&rec, cd, "adapted_lcu_conf", &pos, &prev_pos);
+       e = cl_dbg_dump_adapted_lcu_conf(cl_hw, cd->data, data_len, &pos);
+       post_fill_hook(&rec, &e, &pos, &prev_pos);
+
+       /* Stringified FW state conents */
+       pre_fill_hook(&rec, cd, "fw_dump", &pos, &prev_pos);
+       cl_dbg_dump_check_params(cl_hw, cd->data, data_len, &pos, fdump);
+       cl_dbg_dump_machw_regs(cl_hw, cd->data, data_len, &pos, fdump);
+       cl_dbg_dump_phyhw_regs(cl_hw, cd->data, data_len, &pos, fdump);
+       cl_dbg_dump_ac_info(cl_hw, cd->data, data_len, &pos, fdump);
+       cl_dbg_dump_single_tx_list_info(cl_hw, cd->data, data_len, &pos, fdump);
+       cl_dbg_dump_agg_tx_list_info(cl_hw, cd->data, data_len, &pos, fdump);
+       cl_dbg_dump_tx_trace_info(cl_hw, cd->data, data_len, &pos, fdump);
+       cl_dbg_dump_fw_trace_info(cl_hw, cd->data, data_len, &pos, fdump);
+       post_fill_hook(&rec, &e, &pos, &prev_pos);
+
+       pre_fill_hook(&rec, cd, "hw_diags", &pos, &prev_pos);
+       e = cl_dbg_dump_hw_diags(cl_hw, cd->data, data_len, &pos, gdata);
+       post_fill_hook(&rec, &e, &pos, &prev_pos);
+
+       /* FW/DRV-view of channel and freqs */
+       pre_fill_hook(&rec, cd, "chan_info", &pos, &prev_pos);
+       e = cl_dbg_dump_chan_info(cl_hw, cd->data, data_len, &pos, gdata);
+       post_fill_hook(&rec, &e, &pos, &prev_pos);
+
+       /* Logic analyzer (0) memory - MAC */
+       pre_fill_hook(&rec, cd, "la_mac_trace", &pos, &prev_pos);
+       e = cl_dbg_dump_la_mem(cl_hw, cd->data, data_len, &pos, LA_MAC_IDX, dbg_info);
+       post_fill_hook(&rec, &e, &pos, &prev_pos);
+
+       /* Logic analyzer (0) conf - MAC */
+       pre_fill_hook(&rec, cd, "la_mac_conf", &pos, &prev_pos);
+       e = cl_dbg_dump_la_conf(cl_hw, cd->data, data_len, &pos, LA_MAC_IDX, gdata);
+       post_fill_hook(&rec, &e, &pos, &prev_pos);
+
+       /* Logic analyzer (1) memory - PHY */
+       pre_fill_hook(&rec, cd, "la_phy_trace", &pos, &prev_pos);
+       e = cl_dbg_dump_la_mem(cl_hw, cd->data, data_len, &pos, LA_PHY_IDX, dbg_info);
+       post_fill_hook(&rec, &e, &pos, &prev_pos);
+
+       /* Logic analyzer (1) conf - PHY */
+       pre_fill_hook(&rec, cd, "la_phy_conf", &pos, &prev_pos);
+       e = cl_dbg_dump_la_conf(cl_hw, cd->data, data_len, &pos, LA_PHY_IDX, gdata);
+       post_fill_hook(&rec, &e, &pos, &prev_pos);
+
+       /* Diagnotics port - MAC */
+       pre_fill_hook(&rec, cd, "mac_diags", &pos, &prev_pos);
+       e = cl_dbg_dump_mac_diags(cl_hw, cd->data, data_len, &pos, gdata);
+       post_fill_hook(&rec, &e, &pos, &prev_pos);
+
+       /* SW diagnostics port */
+       pre_fill_hook(&rec, cd, "sw_diags", &pos, &prev_pos);
+       e = cl_dbg_dump_sw_diags(cl_hw, cd->data, data_len, &pos, gdata);
+       post_fill_hook(&rec, &e, &pos, &prev_pos);
+
+       mutex_unlock(&cl_hw->dbginfo.mutex);
+
+       /* devcoredump will take care of memory free process */
+       return cd;
+out:
+       return NULL;
+}
+
+#define INVALID_AMPDU_CNT U8_MAX
+
+void cl_fw_dbg_trigger_based_init(struct cl_hw *cl_hw)
+{
+       memset(&cl_hw->tb_stats, 0, sizeof(cl_hw->tb_stats));
+       cl_hw->tb_stats.ampdu_cnt = INVALID_AMPDU_CNT;
+}
+
+void cl_fw_dbg_trigger_based_update(struct cl_hw *cl_hw, struct hw_rxhdr *rxhdr,
+                                   struct ieee80211_hdr *hdr)
+{
+       struct cl_rx_trigger_based_stats *tb_stats = &cl_hw->tb_stats;
+
+       if (!tb_stats->enable)
+               return;
+
+       if (tb_stats->ampdu_cnt == INVALID_AMPDU_CNT) {
+               tb_stats->ampdu_cnt = rxhdr->ampdu_cnt;
+               if (rxhdr->format_mod == FORMATMOD_HE_TRIG) {
+                       if (ieee80211_is_qos_nullfunc(hdr->frame_control))
+                               tb_stats->qos_null_per_agg += rxhdr->frm_successful_rx;
+                       else
+                               tb_stats->data_per_agg += rxhdr->frm_successful_rx;
+
+                       tb_stats->total += rxhdr->frm_successful_rx;
+               }
+       } else if (tb_stats->ampdu_cnt == rxhdr->ampdu_cnt) {
+               if (rxhdr->format_mod == FORMATMOD_HE_TRIG) {
+                       if (ieee80211_is_qos_nullfunc(hdr->frame_control))
+                               tb_stats->qos_null_per_agg += rxhdr->frm_successful_rx;
+                       else
+                               tb_stats->data_per_agg += rxhdr->frm_successful_rx;
+
+                       tb_stats->total += rxhdr->frm_successful_rx;
+               }
+       } else {
+               tb_stats->ampdu_cnt = rxhdr->ampdu_cnt;
+               if (unlikely(tb_stats->data_per_agg >= DBG_STATS_MAX_AGG_SIZE))
+                       cl_dbg_err(cl_hw, "rx trigger_based agg size %u > 256\n",
+                                  tb_stats->data_per_agg);
+               else
+                       tb_stats->data[tb_stats->data_per_agg]++;
+
+               if (unlikely(tb_stats->qos_null_per_agg > TID_MAX))
+                       tb_stats->qos_null[TID_MAX + 1]++;
+               else
+                       tb_stats->qos_null[tb_stats->qos_null_per_agg]++;
+
+               tb_stats->data_per_agg = 0;
+               tb_stats->qos_null_per_agg = 0;
+
+               if (rxhdr->format_mod == FORMATMOD_HE_TRIG) {
+                       if (ieee80211_is_qos_nullfunc(hdr->frame_control))
+                               tb_stats->qos_null_per_agg += rxhdr->frm_successful_rx;
+                       else
+                               tb_stats->data_per_agg += rxhdr->frm_successful_rx;
+
+                       tb_stats->total += rxhdr->frm_successful_rx;
+               }
+       }
+}
+
+void cl_fw_dbg_trigger_based_reset(struct cl_hw *cl_hw)
+{
+       u32 idx;
+       struct cl_rx_trigger_based_stats *tb_stats = &cl_hw->tb_stats;
+
+       tb_stats->total = 0;
+
+       for (idx = 0; idx < ARRAY_SIZE(tb_stats->data); idx++)
+               tb_stats->data[idx] = 0;
+
+       for (idx = 0; idx < ARRAY_SIZE(tb_stats->qos_null); idx++)
+               tb_stats->qos_null[idx] = 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.
________________________________


^ permalink raw reply related	[flat|nested] 262+ messages in thread

* [RFC v1 087/256] cl8k: add fw/fw_dbg.h
  2021-06-17 15:58 [RFC v1 000/256] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (85 preceding siblings ...)
  2021-06-17 15:59 ` [RFC v1 086/256] cl8k: add fw/fw_dbg.c viktor.barna
@ 2021-06-17 15:59 ` viktor.barna
  2021-06-17 15:59 ` [RFC v1 088/256] cl8k: add fw/fw_file.c viktor.barna
                   ` (170 subsequent siblings)
  257 siblings, 0 replies; 262+ messages in thread
From: viktor.barna @ 2021-06-17 15:59 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Oleksandr Savchenko, Shay Bar, Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

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

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 drivers/net/wireless/celeno/cl8k/fw/fw_dbg.h | 30 ++++++++++++++++++++
 1 file changed, 30 insertions(+)
 create mode 100644 drivers/net/wireless/celeno/cl8k/fw/fw_dbg.h

diff --git a/drivers/net/wireless/celeno/cl8k/fw/fw_dbg.h b/drivers/net/wireless/celeno/cl8k/fw/fw_dbg.h
new file mode 100644
index 000000000000..a35b63fece63
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/fw/fw_dbg.h
@@ -0,0 +1,30 @@
+/* SPDX-License-Identifier: MIT */
+/* Copyright(c) 2019-2021, Celeno Communications Ltd. */
+
+#ifndef CL_FW_DBG_H
+#define CL_FW_DBG_H
+
+#include "hw.h"
+
+enum {
+       DBG_INFO_DUMP = 1,
+       DBG_INFO_TX_STATS,
+       DBG_INFO_BCN_STATS,
+       DBG_INFO_RX_STATS,
+       DBG_INFO_DYN_CAL_STATS,
+       DBG_INFO_RATE_FALLBACK_STATS,
+       DBG_INFO_BF,
+       DBG_INFO_TRIGGER_FLOW,
+       DBG_INFO_MAX,
+       DBG_INFO_UNSET = DBG_INFO_MAX
+};
+
+void cl_fw_dbg_handler(struct cl_hw *cl_hw);
+int cl_fw_dbg_cli(struct cl_hw *cl_hw, struct cli_params *cli_params);
+void cl_fw_dbg_trigger_based_init(struct cl_hw *cl_hw);
+void cl_fw_dbg_trigger_based_update(struct cl_hw *cl_hw, struct hw_rxhdr *rxhdr,
+                                   struct ieee80211_hdr *hdr);
+void cl_fw_dbg_trigger_based_reset(struct cl_hw *cl_hw);
+struct cl_coredump *cl_fw_dbg_prepare_coredump(struct cl_hw *cl_hw);
+
+#endif /* CL_FW_DBG_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.
________________________________


^ permalink raw reply related	[flat|nested] 262+ messages in thread

* [RFC v1 088/256] cl8k: add fw/fw_file.c
  2021-06-17 15:58 [RFC v1 000/256] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (86 preceding siblings ...)
  2021-06-17 15:59 ` [RFC v1 087/256] cl8k: add fw/fw_dbg.h viktor.barna
@ 2021-06-17 15:59 ` viktor.barna
  2021-06-17 15:59 ` [RFC v1 089/256] cl8k: add fw/fw_file.h viktor.barna
                   ` (169 subsequent siblings)
  257 siblings, 0 replies; 262+ messages in thread
From: viktor.barna @ 2021-06-17 15:59 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Oleksandr Savchenko, Shay Bar, Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

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

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 drivers/net/wireless/celeno/cl8k/fw/fw_file.c | 485 ++++++++++++++++++
 1 file changed, 485 insertions(+)
 create mode 100644 drivers/net/wireless/celeno/cl8k/fw/fw_file.c

diff --git a/drivers/net/wireless/celeno/cl8k/fw/fw_file.c b/drivers/net/wireless/celeno/cl8k/fw/fw_file.c
new file mode 100644
index 000000000000..73b239ab5814
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/fw/fw_file.c
@@ -0,0 +1,485 @@
+// SPDX-License-Identifier: MIT
+/* Copyright(c) 2019-2021, Celeno Communications Ltd. */
+
+#include "fw/fw_file.h"
+#include "dbgfile.h"
+#include "reg/reg_access.h"
+#include "chip.h"
+#include <linux/firmware.h>
+
+/* Location where FW codes must be written */
+#define RAM_SMAC_FW_ADDR 0x00300000
+#define RAM_UMAC_FW_ADDR 0x00280000
+#define RAM_LMAC_FW_ADDR 0x00200000
+
+#define FW_START_MAGIC           "CEFWHDRSTART"
+#define FW_END_MAGIC             "CEFWHDREND"
+#define FW_OFFLOAD_MEM_BASE_ADDR 0x70000000 /* Defined in fw link script */
+#define FW_SECTION_SIZE_MASK     0x7FFFF    /* Mask for max. size of a section */
+#define FW_REMOTE_ROM_BASE_ADDR  0x80000000 /* Defined in fw link script */
+#define FW_REMOTE_ROM_MAX        150000
+
+/* Location (offset) where FW codes must be taken from */
+#define IRAM_START_OFFSET        0x40000
+
+/*
+ * Poor man parser of a plain zip file
+ * We use it just as a container for now. Could use cpio instead.
+ * (no compression, no 64-bit data ... no nothing)
+ * Reference: ZIP File Format Specification v.6.3.4 (2014)
+ *     http://pkware.cachefly.net/webdocs/casestudies/APPNOTE.TXT
+ * For BIG ENDIAN host: zip format is always little endian.
+ * TODO need alignment on non-intel hosts! zip format has no alignment,padding
+ * TODO check CRC?
+ */
+
+struct pkzip_local_hdr  {
+       u32 signature;
+       u16 ver2extract;
+       u16 flags;
+       u16 cmpr_meth;
+       u16 filetime;
+       u16 filedate;
+       u32 crc32;
+       u32 cmpr_size;
+       u32 orig_size;
+       u16 fname_len;
+       u16 hdr_extra_len;
+       /* Filename goes here - not 0 terminated! */
+       /* Hdr_extra_data goes here */
+       /* File data goes here; no padding, no alignment */
+} __packed;
+
+#define PKZIP_LOCAL_HDR_MAGIC   le32_to_cpu(0x04034b50)
+#define PKZIP_CENTRAL_DIR_MAGIC le32_to_cpu(0x02014b50)
+
+/*
+ * Enumerate zip data in buffer, find named item
+ * Return: 0 on success (the item found)
+ *        -ENOENT the item not found, normal end of data found
+ *        -EINVAL the data is not zip (maybe old format firmware)
+ *         else invalid data format or other error
+ */
+static int cl_enum_zipfile(const void *data, size_t size,
+                          const char *name, char **pdata, size_t *psize)
+{
+       const struct pkzip_local_hdr *phdr = data;
+       int remain_size = (int)size;
+
+       BUILD_BUG_ON(sizeof(struct pkzip_local_hdr) != 30);
+
+       while (remain_size > sizeof(struct pkzip_local_hdr)) {
+               char *pfname;
+               char *edata;
+
+               if (phdr->signature != PKZIP_LOCAL_HDR_MAGIC) {
+                       if (phdr->signature == PKZIP_CENTRAL_DIR_MAGIC)
+                               return -ENOENT; /* Normal end of zip */
+                       if ((void *)phdr == data)
+                               /* Bad signature in the first entry - not a zip at all */
+                               return -EINVAL;
+                       pr_err("ZIP - unexpected block: %8.8X\n", phdr->signature);
+                       return -1;
+               }
+
+               if (phdr->fname_len == 0 || le16_to_cpu(phdr->fname_len) > 128) {
+                       /* FIX max len */
+                       pr_err("ZIP entry name len bad: %u\n", le16_to_cpu(phdr->fname_len));
+                       return -1;
+               }
+
+               if (phdr->hdr_extra_len == 0) {
+                       pr_err("ZIP xtra hdr size=0! FIXME!\n"); /* Copy name to tmp buffer */
+                       return -1;
+               }
+
+               pfname = (char *)phdr + sizeof(struct pkzip_local_hdr);
+               /* Because fname in zip is not null term! */
+               pfname[le16_to_cpu(phdr->fname_len)] = 0;
+               edata = pfname + le16_to_cpu(phdr->fname_len) + le16_to_cpu(phdr->hdr_extra_len);
+               remain_size -= (sizeof(*phdr) + le16_to_cpu(phdr->fname_len) +
+                               le16_to_cpu(phdr->hdr_extra_len));
+
+               if (phdr->cmpr_size == 0 || le32_to_cpu(phdr->cmpr_size) > remain_size) {
+                       pr_err("ZIP entry data len bad: %u name=%s, left=%u\n",
+                              le32_to_cpu(phdr->cmpr_size), pfname, remain_size);
+                       return -1;
+               }
+
+               if (strncmp(name, pfname, le16_to_cpu(phdr->fname_len)) == 0) {
+                       if (phdr->cmpr_meth != 0 || phdr->cmpr_size != phdr->orig_size) {
+                               pr_err("ZIP entry compressed! name=%s\n", pfname);
+                               return -1;
+                       }
+
+                       *pdata = edata;
+                       *psize = (size_t)le32_to_cpu(phdr->cmpr_size);
+                       return 0;
+               }
+
+               remain_size -= le32_to_cpu(phdr->cmpr_size);
+               phdr = (const struct pkzip_local_hdr *)(edata + le32_to_cpu(phdr->cmpr_size));
+       }
+
+       return -1;
+}
+
+static int cl_fw_unpack(const void *data, size_t size,
+                       const char *name, char **pdata, size_t *psize)
+{
+       /*
+        * Get named item in firmware container
+        * Args: pdata : pointer to pointer to item data, psize : pointer to item size
+        */
+       *pdata = NULL;
+       *psize = 0;
+       return cl_enum_zipfile(data, size, name, pdata, psize);
+}
+
+static int cl_fw_load_other(struct cl_hw *cl_hw, const char *name)
+{
+       /* Handle other stuff in firmware container */
+       char *edata;
+       size_t esize;
+       struct cl_cached_fw *cached_fw = &cl_hw->cached_fw;
+       int rc = cl_fw_unpack(cached_fw->data, cached_fw->size,
+                             name, &edata, &esize);
+
+       if (rc)
+               return rc;
+
+       cl_dbgfile_parse(cl_hw, edata, esize);
+
+       return 0;
+}
+
+/*
+ * Copy the FW code and data into the proper memory inside the firmware asic.
+ * vaddr - run address
+ * paddr - load address
+ * fsize - memory section size to copy
+ * msize - memory section physical size
+ * mem_base - base address of xtensa internal memory
+ * fw_buf - buffer holding the FW binary code and data
+ */
+static void cl_fw_copy_section(struct cl_chip *chip, char *fw_buf, u32 mem_base,
+                              u32 vaddr, u32 paddr, u32 fsize, u32 msize)
+{
+       u32 *src_addr;
+       u32 dst_addr;
+       u32 i;
+
+       src_addr = (u32 *)(fw_buf + (paddr & 0x0007FFFF));
+       /* 512KB - cover all internal iram and dram and some more */
+
+       /* Check if run address is external or internal from xtensa point of view */
+       if ((vaddr & 0xFF000000) == XTENSA_PIF_BASE_ADDR)
+               dst_addr = vaddr & 0x007FFFFF; /* Must be in 8M PCIe window */
+       else
+               dst_addr = (mem_base | (vaddr & 0x0007FFFF));
+
+       for (i = 0; i < fsize; i += sizeof(*src_addr))
+               CL_BAR_REG_WRITE(chip, dst_addr + i, *src_addr++);
+}
+
+static int cl_fw_phdrs_upload(struct cl_chip *chip, struct cl_hw *cl_hw,
+                             u32 fw_addr, const void *edata, size_t esize)
+{
+       /*
+        * Load firmware image with "phdrs" header
+        * and optional non-resident (offloaded) section
+        */
+       u32 size = esize, section, section_cnt = 0;
+       char const *pbuf = edata;
+       u32 *src;
+
+       /* Verify FW image phdrs start magic */
+       if (strncmp(pbuf, FW_START_MAGIC, strlen(FW_START_MAGIC))) {
+               cl_dbg_err(cl_hw, "phdrs start magic not found, aborting...\n");
+               return -1;
+       }
+
+       cl_dbg_info(cl_hw, "phdrs start magic found !!!!!\n");
+       pbuf += (strlen(FW_START_MAGIC) + 1);
+       size -= (strlen(FW_START_MAGIC) + 1);
+
+       /* Verify FW image phdrs end magic */
+       while (size > 0) {
+               if (strncmp(pbuf, FW_END_MAGIC, strlen(FW_END_MAGIC)) == 0) {
+                       cl_dbg_info(cl_hw, "phdrs end magic found !!!!!\n");
+                       break;
+               }
+
+               pbuf += 16;
+               size -= 16;
+               section_cnt++;
+       }
+
+       /* FW image phdrs end magic not found */
+       if (size == 0 || section_cnt > 100) {
+               cl_dbg_err(cl_hw, "phdrs end magic not found, aborting...\n");
+               return -1;
+       }
+
+       /* Remember where the fw code start in firmware buffer */
+       src = (u32 *)(pbuf + (strlen(FW_END_MAGIC) + 1));
+       /* Re-assign firmware buffer ptrs to start */
+       pbuf = edata + (strlen(FW_START_MAGIC) + 1);
+       size = esize - (strlen(FW_START_MAGIC) + 1);
+
+       bool is_offload_present = false;
+       u32 off2_start = 0, off2_end = 0;
+       u32 off3_start = 0, off3_end = 0;
+
+       for (section = 0; section < section_cnt; section++) {
+               u32 *param = (u32 *)pbuf;
+
+               if (le32_to_cpu(param[0]) == FW_REMOTE_ROM_BASE_ADDR) {
+                       if (param[2] > FW_REMOTE_ROM_MAX) {
+                               cl_dbg_info(cl_hw, "%cmac%u: FW remote rom too big = %uK\n",
+                                           cl_hw->fw_prefix, chip->idx, param[2]);
+                       } else {
+                               dma_addr_t phys_dma_addr;
+                               char *pfake = (char *)src + (param[1] & FW_SECTION_SIZE_MASK);
+                               struct cl_dma_accessed *fw_rom = &cl_hw->fw_remote_rom;
+
+                               fw_rom->size = param[2];
+                               fw_rom->drv_v_addr = dma_alloc_coherent(cl_hw->chip->dev,
+                                                                       fw_rom->size,
+                                                                       &phys_dma_addr, GFP_KERNEL);
+                               if (!fw_rom->drv_v_addr) {
+                                       cl_dbg_info(cl_hw, "%cmac%u: FW remote rom dma_alloc_coherent failed = %uK\n",
+                                                   cl_hw->fw_prefix, chip->idx, fw_rom->size);
+                                       fw_rom->size = 0;
+                               } else {
+                                       fw_rom->fw_v_addr = FW_REMOTE_ROM_BASE_ADDR;
+                                       fw_rom->dma_addr = cpu_to_le32(phys_dma_addr);
+                                       memcpy(fw_rom->drv_v_addr, pfake, fw_rom->size);
+                                       cl_dbg_info(cl_hw, "%cmac%u: FW remote rom memory use = %uK\n",
+                                                   cl_hw->fw_prefix, chip->idx, fw_rom->size);
+                               }
+                       }
+                       pbuf += 16;
+                       continue;
+               }
+
+               if (le32_to_cpu(param[0]) == FW_OFFLOAD_MEM_BASE_ADDR) {
+                       is_offload_present = true;
+                       u32 *pdata = (u32 *)((char *)src + (param[1] & 0x7FFFF));
+
+                       off2_start = pdata[0];
+                       off2_end = pdata[1];
+                       off3_start = pdata[2];
+                       off3_end = pdata[3];
+                       cl_dbg_info(cl_hw, "Resident RO DATA block: start=0x%x, end=0x%x\n\n",
+                                   off2_start, off2_end);
+                       pbuf += 16;
+                       continue;
+               }
+
+               cl_fw_copy_section(chip, (char *)src, fw_addr,
+                                  le32_to_cpu(param[0]),
+                                  le32_to_cpu(param[1]),
+                                  le32_to_cpu(param[2]),
+                                  le32_to_cpu(param[3]));
+               pbuf += 16;
+       }
+
+       if (is_offload_present) {
+               /* 2nd pass to find the resident RO data block */
+               pbuf -= (16 * section_cnt);
+               char *resident_file_data = NULL;
+               char *resident_umac_file_data = NULL;
+               u32 *param;
+
+               for (section = 0; section < section_cnt; section++) {
+                       param = (u32 *)pbuf;
+                       if (param[0] <= off2_start &&
+                           (param[0] + param[3]) > off2_end) {
+                               resident_file_data =
+                                       (char *)src + (param[1] & FW_SECTION_SIZE_MASK) +
+                                       (off2_start - param[0]);
+                               cl_dbg_info(cl_hw, "resident_file_data=0x%p.\n",
+                                           resident_file_data);
+                       }
+
+                       if (param[0] <= off3_start &&
+                           (param[0] + param[3]) >= off3_end) {
+                               resident_umac_file_data =
+                                       (char *)src + (param[1] & FW_SECTION_SIZE_MASK) +
+                                       (off3_start - param[0]);
+                               cl_dbg_info(cl_hw, "resident_umac_file_data=0x%p.\n",
+                                           resident_umac_file_data);
+                       }
+
+                       if (param[0] == FW_OFFLOAD_MEM_BASE_ADDR) {
+                               char *pfake = (char *)src + (param[1] & FW_SECTION_SIZE_MASK);
+
+                               cl_dbgfile_store_offload_data(chip,
+                                                             cl_hw,
+                                                             pfake, param[2],
+                                                             FW_OFFLOAD_MEM_BASE_ADDR,
+                                                             resident_file_data,
+                                                             off2_end - off2_start,
+                                                             off2_start,
+                                                             resident_umac_file_data,
+                                                             off3_end - off3_start,
+                                                             off3_start);
+
+                               break; /* This should be last section */
+                       }
+                       pbuf += 16;
+               }
+
+               if (!resident_file_data)
+                       cl_dbg_warn(cl_hw, "FW resident data block [%#X-%#X] not found!\n",
+                                   off2_start, off2_end);
+       }
+
+       return 0;
+}
+
+static int cl_fw_upload(struct cl_chip *chip, struct cl_hw *cl_hw,
+                       u32 fw_addr, const char *data, size_t size)
+{
+       /* Is it old .bin format (used for firmware tests) */
+       if (data[IRAM_START_OFFSET] == 0x06) {
+               const u32 *src = (const u32 *)data;
+               int i;
+
+               for (i = 0; i < size; i += sizeof(*src))
+                       CL_BAR_REG_WRITE(chip, fw_addr + i, *src++);
+
+               return 0;
+       }
+
+       return cl_fw_phdrs_upload(chip, cl_hw, fw_addr, data, size);
+}
+
+static int cl_fw_load_operational(struct cl_hw *cl_hw, const char *fw_name,
+                                 const char *main_str, const char *dbg_str,
+                                 u32 ram_addr)
+{
+       int rc;
+       const struct firmware *fw;
+       char *fw_ptr;
+       size_t fw_size;
+       struct cl_chip *chip = cl_hw->chip;
+       struct cl_cached_fw *cached_fw = &cl_hw->cached_fw;
+
+       clear_bit(CL_DEV_FW_SYNC, &cl_hw->drv_flags);
+
+       if (!cached_fw->data) {
+               char path_name[CL_PATH_MAX] = {0};
+
+               snprintf(path_name, sizeof(path_name), "cl8k/%s", fw_name);
+               rc = request_firmware(&fw, path_name, chip->dev);
+
+               if (rc) {
+                       cl_dbg_err(cl_hw, "# Failed to get %s, with error: %x\n",
+                                  path_name, rc);
+                       return rc;
+               }
+               cached_fw->data = vzalloc(fw->size);
+               if (!cached_fw->data) {
+                       release_firmware(fw);
+                       return -ENOMEM;
+               }
+               memcpy(cached_fw->data, fw->data, fw->size);
+               cached_fw->size = fw->size;
+               release_firmware(fw);
+       }
+
+       rc = cl_fw_unpack(cached_fw->data, cached_fw->size,
+                         main_str, &fw_ptr, &fw_size);
+
+       if (rc == 0) {
+               rc = cl_fw_upload(chip, cl_hw, ram_addr,
+                                 fw_ptr, fw_size);
+               /* Load other stuff packed in firmware container */
+               if (rc == 0)
+                       rc = cl_fw_load_other(cl_hw, dbg_str);
+       } else if (rc != -ENOENT) {
+               /* Assume it is a single file, not a container (used for tests) */
+               rc = cl_fw_upload(chip, cl_hw, ram_addr,
+                                 cached_fw->data,
+                                 cached_fw->size);
+       }
+
+       return rc;
+}
+
+static int cl_fw_load_lmac(struct cl_hw *cl_hw)
+{
+       struct cl_chip *chip = cl_hw->chip;
+
+       if (cl_fw_load_operational(cl_hw, chip->conf->ce_lmac,
+                                  "lmacfw.main", "lmacfw.dbg",
+                                  RAM_LMAC_FW_ADDR))
+               return -1;
+
+       cl_hw->fw_active = true;
+
+       return 0;
+}
+
+static int cl_fw_load_smac(struct cl_hw *cl_hw)
+{
+       struct cl_chip *chip = cl_hw->chip;
+
+       if (cl_fw_load_operational(cl_hw, chip->conf->ce_smac,
+                                  "smacfw.main", "smacfw.dbg",
+                                  RAM_SMAC_FW_ADDR))
+               return -1;
+
+       cl_hw->fw_active = true;
+
+       return 0;
+}
+
+int cl_fw_file_load(struct cl_hw *cl_hw)
+{
+       /* For TCV0 load lmac, and for TCV1 load smac */
+       if (cl_hw_is_tcv0(cl_hw) &&
+           strcmp(cl_hw->chip->conf->ce_lmac, "no_load")) {
+               if (cl_fw_load_lmac(cl_hw))
+                       return -1;
+       } else if (cl_hw_is_tcv1(cl_hw) &&
+                  strcmp(cl_hw->chip->conf->ce_smac, "no_load")) {
+               if (cl_fw_load_smac(cl_hw))
+                       return -1;
+       }
+
+       return 0;
+}
+
+void cl_fw_file_cleanup(struct cl_hw *cl_hw)
+{
+       /* Clean up all firmware allocations in cl_hw */
+       cl_dbgfile_release_mem(&cl_hw->dbg_data, &cl_hw->str_offload_env);
+}
+
+void cl_fw_file_release(struct cl_hw *cl_hw)
+{
+       struct cl_cached_fw *cached_fw = &cl_hw->cached_fw;
+
+       if (cached_fw->data) {
+               struct cl_dma_accessed *fw_rom = &cl_hw->fw_remote_rom;
+
+               vfree(cached_fw->data);
+               cached_fw->data = NULL;
+               cached_fw->size = 0;
+
+               if (fw_rom->drv_v_addr) {
+                       dma_addr_t phys_dma_addr = le32_to_cpu(fw_rom->dma_addr);
+
+                       dma_free_coherent(cl_hw->chip->dev, fw_rom->size, fw_rom->drv_v_addr,
+                                         phys_dma_addr);
+                       fw_rom->drv_v_addr = NULL;
+                       fw_rom->size = 0;
+                       fw_rom->fw_v_addr = 0;
+                       fw_rom->dma_addr = 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.
________________________________


^ permalink raw reply related	[flat|nested] 262+ messages in thread

* [RFC v1 089/256] cl8k: add fw/fw_file.h
  2021-06-17 15:58 [RFC v1 000/256] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (87 preceding siblings ...)
  2021-06-17 15:59 ` [RFC v1 088/256] cl8k: add fw/fw_file.c viktor.barna
@ 2021-06-17 15:59 ` viktor.barna
  2021-06-17 15:59 ` [RFC v1 090/256] cl8k: add fw/fw_msg.c viktor.barna
                   ` (168 subsequent siblings)
  257 siblings, 0 replies; 262+ messages in thread
From: viktor.barna @ 2021-06-17 15:59 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Oleksandr Savchenko, Shay Bar, Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

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

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 drivers/net/wireless/celeno/cl8k/fw/fw_file.h | 13 +++++++++++++
 1 file changed, 13 insertions(+)
 create mode 100644 drivers/net/wireless/celeno/cl8k/fw/fw_file.h

diff --git a/drivers/net/wireless/celeno/cl8k/fw/fw_file.h b/drivers/net/wireless/celeno/cl8k/fw/fw_file.h
new file mode 100644
index 000000000000..a9a861a615a1
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/fw/fw_file.h
@@ -0,0 +1,13 @@
+/* SPDX-License-Identifier: MIT */
+/* Copyright(c) 2019-2021, Celeno Communications Ltd. */
+
+#ifndef CL_FW_FILE_H
+#define CL_FW_FILE_H
+
+#include "hw.h"
+
+int cl_fw_file_load(struct cl_hw *cl_hw);
+void cl_fw_file_cleanup(struct cl_hw *cl_hw);
+void cl_fw_file_release(struct cl_hw *cl_hw);
+
+#endif /* CL_FW_FILE_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.
________________________________


^ permalink raw reply related	[flat|nested] 262+ messages in thread

* [RFC v1 090/256] cl8k: add fw/fw_msg.c
  2021-06-17 15:58 [RFC v1 000/256] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (88 preceding siblings ...)
  2021-06-17 15:59 ` [RFC v1 089/256] cl8k: add fw/fw_file.h viktor.barna
@ 2021-06-17 15:59 ` viktor.barna
  2021-06-17 15:59 ` [RFC v1 091/256] cl8k: add fw/fw_msg.h viktor.barna
                   ` (167 subsequent siblings)
  257 siblings, 0 replies; 262+ messages in thread
From: viktor.barna @ 2021-06-17 15:59 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Oleksandr Savchenko, Shay Bar, Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

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

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 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.
________________________________


^ permalink raw reply related	[flat|nested] 262+ messages in thread

* [RFC v1 091/256] cl8k: add fw/fw_msg.h
  2021-06-17 15:58 [RFC v1 000/256] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (89 preceding siblings ...)
  2021-06-17 15:59 ` [RFC v1 090/256] cl8k: add fw/fw_msg.c viktor.barna
@ 2021-06-17 15:59 ` viktor.barna
  2021-06-17 15:59 ` [RFC v1 092/256] cl8k: add fw/msg_cfm.c viktor.barna
                   ` (166 subsequent siblings)
  257 siblings, 0 replies; 262+ messages in thread
From: viktor.barna @ 2021-06-17 15:59 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Oleksandr Savchenko, Shay Bar, Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

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

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 drivers/net/wireless/celeno/cl8k/fw/fw_msg.h | 1656 ++++++++++++++++++
 1 file changed, 1656 insertions(+)
 create mode 100644 drivers/net/wireless/celeno/cl8k/fw/fw_msg.h

diff --git a/drivers/net/wireless/celeno/cl8k/fw/fw_msg.h b/drivers/net/wireless/celeno/cl8k/fw/fw_msg.h
new file mode 100644
index 000000000000..fbad729724c9
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/fw/fw_msg.h
@@ -0,0 +1,1656 @@
+/* SPDX-License-Identifier: MIT */
+/* Copyright(c) 2019-2021, Celeno Communications Ltd. */
+
+#ifndef CL_FW_MSG_H
+#define CL_FW_MSG_H
+
+#include <linux/types.h>
+#include "vendor_cmd.h"
+#include "def.h"
+#include "ipc_shared.h"
+#include "wrs/wrs_db.h"
+#include "calib.h"
+#include "fem.h"
+#include "agc_params.h"
+
+#if !defined(__LITTLE_ENDIAN_BITFIELD) && !defined(__BIG_ENDIAN_BITFIELD)
+#error "Please fix <asm/byteorder.h>"
+#endif
+
+#define MSG_SHIFT       7
+#define FIRST_MSG(task) ((task) << MSG_SHIFT)
+
+/* Message structure. */
+struct fw_msg {
+       u16 msg_id;     /* Message ID. */
+       u8 dst_kern_id; /* Destination kernel ID. */
+       u8 dst_task_id; /* Destination task ID. */
+       u8 src_kern_id; /* Source kernel ID. */
+       u8 src_task_id; /* Source task ID. */
+       u16 param_len;  /* Parameter embedded struct length. */
+       u32 param[1];   /* Parameter embedded struct - must be word-aligned. */
+};
+
+enum dbg_print {
+       DBG_PRINT_RESET,
+       DBG_PRINT_HELP,
+       DBG_PRINT_TX_STATS,
+       DBG_PRINT_RX_STATS,
+       DBG_PRINT_TXDESC_LIST,
+       DBG_PRINT_AGG_DESC,
+       DBG_PRINT_TX_TRACE_DUMP,
+       DBG_PRINT_TX_RATE_CTRL,
+       DBG_PRINT_FO_CALIB,
+       DBG_PRINT_TX_RETRY,
+       DBG_PRINT_TX_BCN_FLUSH,
+       DBG_PRINT_FW_TRACE,
+       DBG_PRINT_ENHANCED_TIM,
+       DBG_PRINT_TX_DELBA_STATS,
+       DBG_PRINT_RATE_LIMITER,
+       DBG_PRINT_POWER_SAVE_STATS,
+       DBG_PRINT_BF_CTRL_ACTIVE,
+       DBG_PRINT_BF_CTRL_PASSIVE,
+       DBG_PRINT_PERIODIC_TX,
+       DBG_PRINT_MU_GRP_STATS,
+       DBG_PRINT_INT_FRAME_STATS,
+       DBG_PRINT_BMU_STATS,
+       DBG_PRINT_RX_TRACE_DUMP,
+       DBG_PRINT_RD_RW_IDX,
+       DBG_PRINT_OLYMPUS_REG_DUMP,
+       DBG_PRINT_TX_POWER_MEMORY,
+       DBG_PRINT_TX_POWER_MACHW_REGS,
+       DBG_PRINT_TX_POWER_TABLES,
+       DBG_PRINT_DBG_REGS_INFO,
+       DBG_PRINT_RICU_REGS_DUMP,
+       DBG_PRINT_RXM_STATUS,
+       DBG_PRINT_TXM_STATUS,
+       DBG_PRINT_VALID_BITMAP,
+       DBG_PRINT_TRIGGER_FLOW_INFO,
+       DBG_PRINT_LAST
+};
+
+enum {
+       TASK_MM,
+       TASK_DBG,
+       TASK_MAX,
+};
+
+/* List of messages related to the task. */
+enum mm_msg_tag {
+       /* Reset message */
+       MM_RESET_REQ = FIRST_MSG(TASK_MM),
+       MM_RESET_CFM,
+       /* Start message */
+       MM_START_REQ,
+       MM_START_CFM,
+       /* Version message */
+       MM_VERSION_REQ,
+       MM_VERSION_CFM,
+       /* Add interface message */
+       MM_ADD_IF_REQ,
+       MM_ADD_IF_CFM,
+       /* Remove interface message */
+       MM_REMOVE_IF_REQ,
+       MM_REMOVE_IF_CFM,
+       /* Station add message */
+       MM_STA_ADD_REQ,
+       MM_STA_ADD_CFM,
+       /* Station del message */
+       MM_STA_DEL_REQ,
+       MM_STA_DEL_CFM,
+       /* Set filter message */
+       MM_SET_FILTER_REQ,
+       MM_SET_FILTER_CFM,
+       /* Set channel message */
+       MM_SET_CHANNEL_REQ,
+       MM_SET_CHANNEL_CFM,
+       /* Set DTIM message */
+       MM_SET_DTIM_REQ,
+       MM_SET_DTIM_CFM,
+       /* Set beacon interval message */
+       MM_SET_BEACON_INT_REQ,
+       MM_SET_BEACON_INT_CFM,
+       /* Set basic rates message */
+       MM_SET_BASIC_RATES_REQ,
+       MM_SET_BASIC_RATES_CFM,
+       /* Set BSSID message */
+       MM_SET_BSSID_REQ,
+       MM_SET_BSSID_CFM,
+       /* Set EDCA message */
+       MM_SET_EDCA_REQ,
+       MM_SET_EDCA_CFM,
+       /* Set associated message */
+       MM_SET_ASSOCIATED_REQ,
+       MM_SET_ASSOCIATED_CFM,
+       /* Set slot time message */
+       MM_SET_SLOTTIME_REQ,
+       MM_SET_SLOTTIME_CFM,
+       /* Set idle message */
+       MM_SET_IDLE_REQ,
+       MM_SET_IDLE_CFM,
+       /* Key add message */
+       MM_KEY_ADD_REQ,
+       MM_KEY_ADD_CFM,
+       /* Key delete message */
+       MM_KEY_DEL_REQ,
+       MM_KEY_DEL_CFM,
+       /* Block ack add TX message */
+       MM_BA_ADD_TX_REQ,
+       MM_BA_ADD_TX_CFM,
+       /* Block ack add RX message */
+       MM_BA_ADD_RX_REQ,
+       MM_BA_ADD_RX_CFM,
+       /* Block ack delete message */
+       MM_BA_DEL_REQ,
+       MM_BA_DEL_CFM,
+       /* PHY reset message */
+       MM_PHY_RESET_REQ,
+       MM_PHY_RESET_CFM,
+       /* Available BA TX queue message */
+       MM_AVAILABLE_BA_TXQ_REQ,
+       MM_AVAILABLE_BA_TXQ_CFM,
+       /* Update rate DL message */
+       MM_UPDATE_RATE_DL_REQ,
+       MM_UPDATE_RATE_DL_CFM,
+       /* Set VNS message */
+       MM_SET_VNS_REQ,
+       MM_SET_VNS_CFM,
+       /* Set TX BF message */
+       MM_SET_TX_BF_REQ,
+       MM_SET_TX_BF_CFM,
+       /* Sounding message */
+       MM_SOUNDING_REQ,
+       MM_SOUNDING_CFM,
+       // Sounding pairing message
+       MM_SOUNDING_PAIRING_REQ,
+       MM_SOUNDING_PAIRING_CFM,
+       /* Sounding interval message */
+       MM_SOUNDING_INTERVAL_REQ,
+       MM_SOUNDING_INTERVAL_CFM,
+       /* Sounding station switch message */
+       MM_SOUNDING_STA_SWITCH_REQ,
+       MM_SOUNDING_STA_SWITCH_CFM,
+       /* Configure CCA message */
+       MM_CONFIG_CCA_REQ,
+       MM_CONFIG_CCA_CFM,
+       /* Set DFS message */
+       MM_SET_DFS_REQ,
+       MM_SET_DFS_CFM,
+       /* Set antenna bitmap message */
+       MM_SET_ANT_BITMAP_REQ,
+       MM_SET_ANT_BITMAP_CFM,
+       /* Set NDP TX control message */
+       MM_NDP_TX_CONTROL_REQ,
+       MM_NDP_TX_CONTROL_CFM,
+       /* Register write message */
+       MM_REG_WRITE_REQ,
+       MM_REG_WRITE_CFM,
+       /* Protection mode message */
+       MM_PROT_MODE_REQ,
+       MM_PROT_MODE_CFM,
+       /* Goto power reduction message */
+       MM_GOTO_POWER_REDUCTION_REQ,
+       MM_GOTO_POWER_REDUCTION_CFM,
+       /* Backup beacon enable message */
+       MM_BACKUP_BCN_EN_REQ,
+       MM_BACKUP_BCN_EN_CFM,
+       /* Start periodic TX time message */
+       MM_START_PERIODIC_TX_TIME_REQ,
+       MM_START_PERIODIC_TX_TIME_CFM,
+       /* Anamon read message */
+       MM_ANAMON_READ_REQ,
+       MM_ANAMON_READ_CFM,
+       /* Refresh power message */
+       MM_REFRESH_PWR_REQ,
+       MM_REFRESH_PWR_CFM,
+       /* Set antenna power offset message */
+       MM_SET_ANT_PWR_OFFSET_REQ,
+       MM_SET_ANT_PWR_OFFSET_CFM,
+       /* Set rate fallback message */
+       MM_SET_RATE_FALLBACK_REQ,
+       MM_SET_RATE_FALLBACK_CFM,
+       /* TWT setup message */
+       MM_TWT_SETUP_REQ,
+       MM_TWT_SETUP_CFM,
+       /* TWT teardown message */
+       MM_TWT_TEARDOWN_REQ,
+       MM_TWT_TEARDOWN_CFM,
+       /* FW resource management message */
+       MM_RSRC_MGMT_REQ,
+       MM_RSRC_MGMT_CFM,
+       /* Set frequency offset message */
+       MM_SET_FREQ_OFFSET_REQ,
+       MM_SET_FREQ_OFFSET_CFM,
+
+       MM_REQ_CFM_MAX,
+
+       /* ############### Firmware internal messages   ############### */
+       /* Periodic task - reset ADC / DAC modules. */
+       MM_ADC_DAC_PERIODIC_TIMER = MM_REQ_CFM_MAX,
+       /* Dynamic calibration config */
+       MM_DYNAMIC_CALIBRATION_CONFIG,
+       /* Set AGC values. */
+       MM_SET_AGC_VALS,
+       /* MU-EDCA Timer interrupt message */
+       MM_MU_EDCA_TIMER,
+       /* TWT Timer interrupt message */
+       MM_TWT_TIMER,
+
+       /* ############### Firmware indication messages   ############### */
+       /* Start of indication messages */
+       MM_FIRST_IND,
+       /* TX aggregation indication from FW */
+       MM_AGG_TX_REPORT_IND = MM_FIRST_IND,
+       /* Indication for BF sounding */
+       MM_SOUNDING_IND,
+       /* Indication of fw error */
+       MM_FW_ERROR_IND,
+       /* Async indication that MAC is in idle */
+       MM_IDLE_ASYNC_IND,
+       /* Intidcation of FW resource management decision */
+       MM_RSRC_MGMT_IND,
+
+       /* MAX number of messages */
+       MM_MAX,
+};
+
+/* Firmware resource enums types (for the API sanity) */
+enum mm_rsrc_mgmt_sanity {
+       MM_RSRC_MGMT_SANITY_FIRST,
+
+       MM_RSRC_MGMT_SANITY_SELF = MM_RSRC_MGMT_SANITY_FIRST,
+       MM_RSRC_MGMT_SANITY_SUBTYPES,
+       MM_RSRC_MGMT_SANITY_ACTION_HINTS,
+       MM_RSRC_MGMT_SANITY_CONTROL_OF,
+
+       MM_RSRC_MGMT_SANITY_MAX
+};
+
+/* Firmware resource hints types */
+enum mm_rsrc_mgmt_subtype {
+       /* DRV -> FW, REQ (with CFM) */
+       MM_RSRC_MGMT_FIRST,
+
+       MM_RSRC_MGMT_API_SANITY = MM_RSRC_MGMT_FIRST,
+       MM_RSRC_MGMT_TRAFFIC_START,
+       MM_RSRC_MGMT_TRAFFIC_STOP,
+       MM_RSRC_MGMT_RATES_UPDATE,
+       MM_RSRC_MGMT_CECLI_HINT,
+
+       /* DRV <- FW, IND */
+       MM_RSRC_MGMT_ACTION_HINT,
+       MM_RSRC_MGMT_ENV_CHANGE,
+       MM_RSRC_MGMT_STATS,
+       MM_RSRC_MGMT_CONFIG_QUERY,
+       MM_RSRC_MGMT_NOTIF_POLICY_SET,
+
+       MM_RSRC_MGMT_MAX
+};
+
+enum mm_rsrc_mgmt_action_hint {
+       MM_RSRC_MGMT_ACTION_FIRST,
+
+       MM_RSRC_MGMT_ACTION_ENABLE = MM_RSRC_MGMT_ACTION_FIRST,
+       MM_RSRC_MGMT_ACTION_DISABLE,
+       MM_RSRC_MGMT_ACTION_RESTORE_DEFAULT,
+       MM_RSRC_MGMT_ACTION_SET,
+       MM_RSRC_MGMT_ACTION_GET,
+
+       MM_RSRC_MGMT_ACTION_MAX
+};
+
+enum mm_rsrc_mgmt_control_of {
+       MM_RSRC_MGMT_OF_FIRST,
+
+       MM_RSRC_MGMT_OF_TX_AMSDU = MM_RSRC_MGMT_OF_FIRST,
+       MM_RSRC_MGMT_OF_RX_AMSDU,
+       MM_RSRC_MGMT_OF_PROT_MODE,
+       MM_RSRC_MGMT_OF_CCA,
+
+       MM_RSRC_MGMT_OF_MAX
+};
+
+struct mm_rsrc_mgmt_active_sta {
+       u8 idx;
+       struct {
+               u8 bw;
+               u8 nss;
+               u8 mcs;
+       } su_rate, max_rate;
+};
+
+struct mm_rsrc_mgmt_notif_policy {
+       bool enabled;
+       u8 level_mask;
+       u8 direction_mask;
+       struct {
+               s8 low_th;
+               s8 high_th;
+       } active_sta;
+};
+
+struct mm_rsrc_mgmt_cecli {
+       __le32 num_params;
+       __le32 mode;
+       char option;
+       u8 len;
+       __le32 params[0];
+};
+
+struct mm_rsrc_mgmt_req {
+       u8 subtype;
+       union {
+               struct {
+                       u8 enum_type;
+                       __le32 enum_max;
+                       __le32 index;
+                       u8 len;
+                       char descr[0];
+               } api_sanity;
+               struct {
+                       u8 level;
+                       u8 direction;
+                       struct {
+                               u8 cnt;
+                               struct mm_rsrc_mgmt_active_sta list[0];
+                       } active_sta;
+               } traffic_event;
+               struct {
+                       struct mm_rsrc_mgmt_active_sta sta;
+               } rate_event;
+               struct mm_rsrc_mgmt_cecli cecli_event;
+       } u;
+};
+
+struct mm_rsrc_mgmt_cfm {
+       u8 subtype;
+       s8 status;
+};
+
+struct mm_rsrc_mgmt_ind {
+       u8 subtype;
+       union {
+               struct {
+                       __le16 target;
+                       u8 action;
+                       u8 data[0];
+               } action_hint;
+               struct {
+                       u8 state;
+               } env_event;
+               struct {
+                       __le16 target;
+               } cfg_query;
+               struct {
+                       __le32 stub;
+               } stats;
+               struct {
+                       u8 subtype;
+                       struct mm_rsrc_mgmt_notif_policy settings;
+               } notif_policy_set;
+       } u;
+};
+
+/* Interface types */
+enum {
+       MM_STA,
+       MM_IBSS,
+       MM_AP,
+       MM_MONITOR,
+       MM_MESH_POINT,
+};
+
+/* BA agreement types */
+enum {
+       /* BlockAck agreement for TX */
+       BA_AGMT_TX,
+       /* BlockAck agreement for RX */
+       BA_AGMT_RX,
+};
+
+/* BA agreement related status */
+enum {
+       BA_AGMT_ESTABLISHED,
+       BA_AGMT_ALREADY_EXISTS,
+       BA_AGMT_DELETED,
+       BA_AGMT_DOES_NOT_EXIST,
+       BA_AGMT_NOT_ESTABLISHED,
+};
+
+/* MM_BA_TXQUEUE request / confirm related status */
+enum {
+       BA_TXQUEUE_INVALID,
+       BA_TXQUEUE_VALID,
+};
+
+/* MAC address structure. */
+struct mac_addr {
+       /* Array of bytes that make up the MAC address. */
+       u8 array[ETH_ALEN];
+};
+
+#define PWR_TBL_HE_BF_SIZE  (WRS_SS_MAX + 1)
+#define PWR_TBL_VHT_BF_SIZE WRS_SS_MAX
+
+/* DCOC/IQ Calibration related defines */
+#define CALIB_SUCCESS 0x00
+#define CALIB_FAIL    0x01
+
+/*
+ * Structure containing the power tables
+ * All values are in resolution of 0.5dBm
+ */
+struct cl_pwr_tables {
+       /* Regular Tx */
+       s8 ant_pwr_he[CHNL_BW_MAX][WRS_MCS_MAX_HE][PWR_TBL_HE_BF_SIZE];
+       s8 ant_pwr_ht_vht[CHNL_BW_MAX][WRS_MCS_MAX_VHT][PWR_TBL_VHT_BF_SIZE];
+       s8 ant_pwr_ofdm[WRS_MCS_MAX_OFDM];
+       s8 ant_pwr_cck[WRS_MCS_MAX_CCK];
+       /* VNS */
+       s8 ant_pwr_vns_he;
+       s8 ant_pwr_vns_ht_vht;
+       s8 ant_pwr_vns_ofdm;
+       s8 ant_pwr_vns_cck;
+       /* Auto response */
+       s8 pwr_auto_resp_he[WRS_MCS_MAX_HE];
+       s8 pwr_auto_resp_ht_vht[WRS_MCS_MAX_VHT];
+       s8 pwr_auto_resp_ofdm[WRS_MCS_MAX_OFDM];
+       s8 pwr_auto_resp_cck[WRS_MCS_MAX_CCK];
+       /* Auto response VNS */
+       s8 pwr_auto_resp_vns_he;
+       s8 pwr_auto_resp_vns_ht_vht;
+       s8 pwr_auto_resp_vns_ofdm;
+       s8 pwr_auto_resp_vns_cck;
+};
+
+struct cl_phy_data {
+       struct cl_pwr_tables pwr_tables;
+       struct cl_iq_dcoc_info iq_dcoc_db;
+       struct cl_agc_params agc_params;
+};
+
+struct reg_offset_val {
+       __le16 addr_offset;
+       __le32 val;
+};
+
+struct cl_antenna_config {
+       /* Number of antennas */
+       u8 num_tx_he;
+       u8 num_tx_ofdm_ht_vht;
+       u8 num_rx;
+       /* Mask of antennas */
+       u8 mask_tx_he;
+       u8 mask_tx_ofdm_ht_vht;
+       u8 mask_rx;
+       /* CCK mask */
+       u8 mask_tx_cck;
+       u8 mask_rx_cck;
+       /* CDB_mask 0x0 -> SX0 chain. 0x1-> SX1 chain. */
+       u8 cdb_mask;
+};
+
+struct cl_fem_config {
+       u32 reg[FEM_REGISTERS_AMOUNT];
+};
+
+struct cl_cca_config {
+       u8 ed_rise_thr_dbm;
+       u8 ed_fall_thr_dbm;
+       u8 cs_en;
+       u8 modem_en;
+       u8 main_ant;
+       u8 second_ant;
+       u8 flag0_ctrl;
+       u8 flag1_ctrl;
+       u8 flag2_ctrl;
+       u8 flag3_ctrl;
+       u8 gi_rise_thr_dbm;
+       u8 gi_fall_thr_dbm;
+       u8 gi_pow_lim_dbm;
+       u16 ed_en;
+       u8 gi_en;
+};
+
+/* Structure containing the parameters of the PHY configuration */
+struct cl_phy_cfg {
+       struct cl_cca_config cca_config;
+       struct cl_antenna_config ant_config;
+       struct cl_fem_config fem_conf;
+       u8 first_start;
+       u8 channel_bandwidth;
+       u8 band; /* 0 = 2.4g / 1 = 5g / 2 = 6g */
+       u16 freq_offset;
+       u8 rx_sensitivity[MAX_ANTENNAS];
+       u8 vns_tx_power_mode;
+       u8 vns_rssi_suto_resp_th;
+       u8 afe_config_en;
+       u8 no_capture_noise_sleep;
+       u8 ht_rxldpc_en;
+       u8 gain_update_enable;
+       u8 mcs_sig_b;
+       u8 ofdm_only;
+       u8 hr_factor;
+       u8 td_csd_en;
+       u8 pe_duration_bcast;
+       u32 tx_digital_gain;
+       u32 tx_digital_gain_cck;
+       u8 ofdm_cck_power_offset;
+       u8 phy_clk_gating_en;
+       u8 tcv1_chains_sx0;
+};
+
+enum {
+       CENX_CFG_DEBUG_PRINT,
+       CENX_CFG_INT_FRAME,
+       CENX_CFG_CE_TX_CFM,
+       CENX_CFG_LMAC_SEQNUM,
+       CENX_CFG_DBG_COUNTERS,
+       CENX_CFG_RHD_LL_SPLIT,
+       CENX_CFG_RX_HDR_SPLIT,
+       CENX_CFG_CYC_BUF,
+       CENX_CFG_DEBUG_TRACE,
+       CENX_RX_CLASSIFICATION,
+       CENX_RX_IMP_BF,
+       CENX_CSI_SUPPORT,
+       CENX_NATT_DBG,
+       CENX_GRP_MGMT_FRAME,
+       CENX_GRP_MGMT_FRAME_RX,
+       CENX_MU_GROUP,
+       CENX_CFG_MAX
+};
+
+#define IPC_TXQ_CNT  5
+
+/* MM_START_REQ parameters */
+struct cl_start_param {
+       __le32 comp_flags;
+       __le16 cfm_size;
+       __le32 cfm_dma_base_addr;
+       __le16 phy_dev;
+       __le16 fw_scale_down;
+       __le16 dbg_test_mode_max;
+       struct {
+               __le32 idle;
+               __le32 ac0;
+               __le32 ac1;
+               __le32 ac2;
+               __le32 ac3;
+               __le32 bcn;
+       } hal_timeout;
+       /*
+        * this is the pointer to the dma base address of the host struct
+        * that hold all the dma addresses of the ipc host queues
+        */
+       __le32 ipc_host_tx_queues_dma_addr;
+       /* Address of RX buffer in host RAM */
+       __le32 host_rxbuf_base_addr[CL_RX_BUF_MAX];
+       /* Address of HOST indices */
+       __le32 ipc_ring_indices_base;
+       u8 prot_log_nav_en;
+       u8 prot_mode;
+       u8 prot_rate_format;
+       u8 prot_rate_mcs;
+       u8 prot_rate_pre_type;
+       u8 bw_signaling_mode;
+       u8 mult_ampdu_in_txop_en;
+       u8 preemptive_backoff_en;
+       __le32 cca_timeout;
+       u8 short_retry_limit;
+       u8 long_retry_limit;
+       u8 assoc_auth_retry_limit;
+       __le16 bcn_tx_path_min_time;
+       u8 backup_bcn_en;
+       u8 tx_txop_cut_en;
+       u8 ps_ctrl_enabled;
+       u8 ac_with_bcns_flushed_cnt_thr;
+       __le32 txl_statistics_struct_size;
+       __le32 rxl_statistics_struct_size;
+       struct dbg_meta_data dbg_metadata;
+       u8 phy_err_prevents_phy_dump;
+       u8 tx_rx_delay;
+       u8 assert_storm_detect_thd;
+       u8 assert_time_diff_sec;
+       __le16 ipc_rxbuf_size[CL_RX_BUF_MAX];
+       __le32 ipc_rxbuf_extra_headroom;
+       u8 host_pci_gen_ver;
+       u8 dma_lli_max_chan[2];
+       u8 production_mode;
+       u8 bw_factor_q2[CHNL_BW_MAX];
+       u8 ant_factor_q2[MAX_ANTENNAS];
+       u8 min_ant_pwr_q1;
+       struct {
+               u8 auto_resp_all  : 2;
+               u8 auto_resp_msta : 2;
+               u8 rsv            : 4;
+       } default_distance;
+       __le32 phy_data_dma_addr;
+       __le32 phy_remote_rom_dma_addr;
+       __le32 iq_dcoc_calib_tables_dma_addr;
+       __le32 power_table_dma_addr;
+       __le32 tf_info_dma_addr;
+       u8 su_force_min_spacing_usec;
+       u8 mu_force_min_spacing_usec;
+       u8 force_tcv0_only;
+       u8 rx_padding;
+       u8 bar_cap_disable;
+       u8 hw_bsr;
+       u8 drop_to_lower_bw;
+       u8 dra_enable;
+       u8 mac_clk_gating_en;
+       u8 imaging_blocker;
+       u8 fec_coding;
+       u8 cs_required;
+       u8 first_tcv;
+};
+
+struct cl_tx_params {
+       __le32 rate;
+       __le32 rate_he;
+       u8 req_bw_tx;
+       u8 ant_set;
+       u8 ltf;
+};
+
+struct cl_rx_params {
+       u8 format;
+       u8 mcs;
+       u8 nss;
+};
+
+struct mm_update_rate_dl_req {
+       u8 op_mode;
+       u8 sta_idx;
+       u8 mu_is_rate_valid;
+       u8 group_id;
+       struct cl_tx_params tx_params;
+       __le32 rate_fallback;
+       u8 ltf_fallback;
+};
+
+struct mm_set_ant_pwr_offset_req {
+       /* Power offset (0.25dB resoultion) */
+       u8 pwr_offset[MAX_ANTENNAS];
+};
+
+struct mm_rate_fallback_req {
+       u8 fallback_count_su;
+       u8 fallback_count_mu;
+       u8 ba_per_thr;
+       u8 ba_not_received_thr;
+       u8 retry_count_thr;
+       u8 disable_mcs0;
+};
+
+struct mm_set_vns_req {
+       u8 sta_idx;
+       u8 is_vns;
+};
+
+struct mm_set_tx_bf_req {
+       u8 sta_idx;
+       u8 is_on;
+       u8 is_on_fallback;
+};
+
+/* Structure containing the parameters of the MM_START_REQ message */
+struct mm_start_req {
+       /* PHY configuration */
+       struct cl_phy_cfg phy_cfg;
+       /* Other start parameters */
+       struct cl_start_param param;
+};
+
+struct mm_mac_api_lut_line {
+       __le16 frequency_q2;
+       union {
+               struct {
+                       struct {
+                               u8 vcocalsel;
+                               u8 nint;
+                               __le32 nfrac;
+                               __le32 freqmeastarg;
+                       } xco_40M;
+                       struct {
+                               u8 vcocalsel;
+                               u8 nint;
+                               __le32 nfrac;
+                               __le32 freqmeastarg;
+                       } xco_60M;
+               } olympus_2_lines;
+               struct {
+                       struct {
+                               u8 vcocalsel;
+                               u8 nint;
+                               __le32 nfrac;
+                               __le32 freqmeastarg;
+                       } xco_40M;
+                       struct {
+                               u8 vcocalsel;
+                               u8 nint;
+                               __le32 nfrac;
+                               __le32 freqmeastarg;
+                       } xco_60M_s0;
+                       struct {
+                               u8 vcocalsel;
+                               u8 nint;
+                               __le32 nfrac;
+                               __le32 freqmeastarg;
+                       } xco_60M_s1;
+               } olympus_3_lines;
+       } rfic_specific;
+};
+
+struct cl_calib_other_tcv {
+       /* Parameters for calibration */
+       __le16 prim20_freq;
+       struct mm_mac_api_lut_line center1_freq_lut;
+       /* Parameter to restore previous configuration of other TCV */
+       u8 mask_tx_he;
+       u8 num_tx_he;
+       u8 band;
+};
+
+struct cl_calib_conf {
+       u8 initial_rx_gain;
+       u8 initial_tx_gain;
+       u8 rx_gain_upper_limit;
+       u8 rx_gain_lower_limit;
+       __le16 nco_freq;
+       s8 nco_amp;
+       u8 sleeve_trshld;
+       u8 n_samples_exp_lolc;
+       u8 n_samples_exp_iqc;
+       __le32 p_thresh;
+       u8 n_bit_fir_scale;
+       u8 n_bit_amp_scale;
+       u8 n_bit_phase_scale;
+       __le16 tone_vector[IQ_NUM_TONES_REQ];
+       __le32 gp_rad_trshld;
+       __le32 ga_lin_upper_trshld;
+       __le32 ga_lin_lower_trshld;
+       u8 comp_filter_len;
+       u8 singletons_num;
+       u8 tones_num;
+       __le16 rampup_time;
+       __le16 lo_coarse_step;
+       __le16 lo_fine_step;
+};
+
+struct cl_calib_param {
+       u8 mode;
+       u8 dcoc_max_vga;
+       u8 ant_tx_pairs[MAX_ANTENNAS];
+       u8 ant_rx_pairs[MAX_ANTENNAS];
+       struct cl_calib_conf conf;
+       struct cl_calib_other_tcv other_tcv;
+};
+
+/* Structure containing the parameters of the MM_SET_CHANNEL_REQ message */
+struct mm_set_channel_req {
+       /* Band (2.4GHz or 5GHz) */
+       u8 band;
+       /* Channel type: 20,40,80 or 160 MHz */
+       u8 bandwidth;
+       /* Frequency for Primary 20MHz channel (in MHz) */
+       __le16 prim20_freq;
+       /* Frequency for Center of the contiguous channel or center of Primary 80+80 */
+       struct mm_mac_api_lut_line center1_freq_lut;
+       /* Antenna configuration */
+       struct cl_antenna_config ant_config;
+       /* FEM configuration */
+       struct cl_fem_config fem_conf;
+       u8 calib_info_set;
+       /* Calibration configuration */
+       struct cl_calib_param calib_param;
+       /* Antenna power offset */
+       u8 ant_pwr_offset[MAX_ANTENNAS];
+       /*
+        * Frequency offset in MHz between current synthesizer's center channel,
+        * and the other synthesizer's channel.
+        * Needed for LOLC and IQC Calibration. Otherwise, shouldn't be used.
+        */
+       s8 sx_freq_offset_mhz;
+       /* Hr factor */
+       u8 hr_factor;
+       /* Signal extension enable (for 2.4G sifs10 mode), should be 1 for 2,4 band by default */
+       u8 signal_ext;
+};
+
+enum mm_ext_calib_command {
+       MM_EXT_CALIB_CMD_INIT_SX,
+       MM_EXT_CALIB_CMD_SET_CHANNEL,
+       MM_EXT_CALIB_CMD_INIT_AND_SET_CHANNEL,
+       MM_EXT_CALIB_CMD_MAX
+};
+
+struct mm_ext_calib_init_sx_req {
+       u8 band;
+       u8 cdb_mask;
+       u8 mask_tx_he;
+       u8 num_tx_he;
+       u8 sx_idx;
+};
+
+struct mm_ext_calib_set_channel_req {
+       u8 band;
+       u8 bandwidth;
+       __le16 prim20_freq;
+       struct mm_mac_api_lut_line center1_freq_lut;
+       u8 sx_idx;
+};
+
+struct mm_ext_calib_init_and_set_req {
+       u8 band;
+       u8 cdb_mask;
+       u8 bandwidth;
+       __le16 prim20_freq;
+       struct mm_mac_api_lut_line center1_freq_lut;
+       __le16 remote_prim20_freq;
+       struct mm_mac_api_lut_line remote_center1_freq_lut;
+};
+
+union mm_ext_calib_cmd_req {
+       struct mm_ext_calib_init_sx_req init_sx;
+       struct mm_ext_calib_set_channel_req set_channel;
+       struct mm_ext_calib_init_and_set_req init_and_set;
+};
+
+struct mm_ext_calib_req {
+       u8 cmd;
+       union mm_ext_calib_cmd_req u;
+};
+
+/* Structure containing the parameters of the MM_GOTO_POWER_REDUCTION_REQ message */
+struct mm_goto_power_reduction_req {
+       u8 goto_power_reduction_mode;
+};
+
+/* Structure containing the parameters of the MM_FREQ_UPDATE_REQ message */
+struct mm_freq_update_req {
+       u16 freq;
+};
+
+/* Structure containing the parameters of the MM_SET_DTIM_REQ message */
+struct mm_set_dtim_req {
+       u8 dtim_period;
+};
+
+/* Structure containing the parameters of the MM_SET_BEACON_INT_REQ message */
+struct mm_set_beacon_int_req {
+       __le16 beacon_int;
+       /* Index of the interface */
+       u8 inst_nbr;
+};
+
+/* Structure containing the parameters of the MM_SET_BASIC_RATES_REQ message */
+struct mm_set_basic_rates_req {
+       /* Basic rate set (as expected by bssBasicRateSet field of Rates MAC HW register) */
+       __le32 rates;
+};
+
+/* Structure containing the parameters of the MM_SET_BSSID_REQ message */
+struct mm_set_bssid_req {
+       /* BSSID to be configured in HW */
+       struct mac_addr bssid;
+       /* Index of the interface for which the parameter is configured */
+       u8 inst_nbr;
+};
+
+/* Structure containing the parameters of the MM_SET_FILTER_REQ message */
+struct mm_set_filter_req {
+       __le32 filter;
+};
+
+/* Structure containing the parameters of the MM_ADD_IF_REQ message. */
+struct mm_add_if_req {
+       u8 type;
+       struct mac_addr addr;
+       u8 inst_nbr;
+       u8 tx_strip_vlan;
+       u8 rx_push_vlan;
+       __le32 rx_push_vlan_tag;
+       __le32 rx_filter_monitor_mask;
+       __le32 mac_addr_hi_mask;
+       __le32 mac_addr_low_mask;
+       u8 start_dtim_count;
+       u8 mbssid_mode;
+};
+
+/* Structure containing the parameters of the MM_SET_EDCA_REQ message */
+struct mm_set_edca_req {
+       __le32 ac_param;
+       u8 hw_queue;
+       u8 mu_edca_aifsn;
+       u8 mu_edca_ecw_min_max;
+       u8 mu_edca_timer;
+};
+
+struct mm_config_cca_req {
+       u8 enable;
+};
+
+struct mm_set_dfs_req {
+       bool enable;
+       bool standard_fcc;
+       u8 initial_gain;
+       u8 agc_cd_th;
+};
+
+struct mm_set_ant_bitmap_req {
+       struct cl_antenna_config ant_config;
+};
+
+struct mm_ndp_tx_control_req {
+       u8 chain_mask;
+       u8 bw;
+       u8 format;
+       u8 num_ltf;
+};
+
+struct mm_reg_write_req {
+       __le32 address;
+       __le32 value;
+       __le32 mask;
+};
+
+struct mm_prot_mode_req {
+       u8 log_nav_en;
+       u8 mode;
+       u8 rate_format;
+       u8 rate_mcs;
+       u8 rate_pre_type;
+};
+
+struct mm_bw_signaling_mode_req {
+       u8 mode;
+};
+
+enum mac_idle_cmd {
+       MAC_ACTIVE = 0,
+       MAC_IDLE_SYNC,
+       MAC_IDLE_ASYNC
+};
+
+struct mm_set_idle_req {
+       u8 hw_idle;
+};
+
+/* Structure containing the parameters of the MM_SET_SLOTTIME_REQ message */
+struct mm_set_slottime_req {
+       /* Slot time expressed in us */
+       u8 slottime;
+};
+
+/* Structure containing the parameters of the MM_SET_ASSOCIATED_REQ message */
+struct mm_set_associated_req {
+       /* Association Id received from the AP */
+       __le16 aid;
+       /* Mask address high - [47:32] */
+       __le32 bssid_hi_mask;
+       /* Mask address low - [31:0] */
+       __le32 bssid_low_mask;
+};
+
+/* Structure containing the parameters of the MM_ADD_IF_CFM message. */
+struct mm_add_if_cfm {
+       /* Status of operation (different from 0 if unsuccessful) */
+       u8 status;
+};
+
+/* Structure containing the parameters of the MM_REMOVE_IF_REQ message. */
+struct mm_remove_if_req {
+       /* Interface index assigned by the firmware */
+       u8 inst_nbr;
+};
+
+/* Structure containing the parameters of the MM_VERSION_CFM message. */
+struct mm_version_cfm {
+       struct {
+               __le32 dsp;
+               __le32 rfic_sw;
+               __le32 rfic_hw;
+               __le32 agcram;
+               char fw[CL_VERSION_STR_SIZE];
+       } versions;
+       u8 rf_crystal_mhz;
+};
+
+/* Structure containing the parameters of the MM_STA_ADD_REQ message. */
+struct mm_sta_add_req {
+       /* Exponent for calculating HE Maximum A-MPDU size */
+       u8 ampdu_size_exp_he;
+       /* Exponent for calculating VHT Maximum A-MPDU size */
+       u8 ampdu_size_exp_vht;
+       /* Exponent for calculating HT Maximum A-MPDU size */
+       u8 ampdu_size_exp_ht;
+       /* MAC address of the station to be added */
+       struct mac_addr mac_addr;
+       /* A-MPDU spacing, in us */
+       u8 ampdu_min_spacing;
+       /* Interface index */
+       u8 inst_nbr;
+       /* Support ldpc Tx */
+       u8 ldpc_enabled;
+       /* MU beamformee capable */
+       u8 mu_bfee;
+       /* SU beamformee capable */
+       u8 su_bfee;
+       /* Station AID */
+       __le16 aid;
+       /* My_aid - ??? */
+       __le16 my_aid;
+       /* Index of station in case of recovery */
+       u8 recovery_sta_idx;
+       u8 max_sp;
+       u8 uapsd_queues;
+       /* TX params */
+       struct cl_tx_params tx_params;
+       /*
+        * PE duration (0 = 0us, 1 = 8us, 2 = 16us)
+        * SS0 bits 0-1, SS1 bits 2-3, SS2 bits 4-5, SS3 bits 6-7.
+        */
+       u8 pe_duration[CHNL_BW_MAX][WRS_MCS_MAX_HE];
+       u8 he_tf_mac_padding_duration;
+       u8 he_rx_ctrl_frm_to_mbss;
+       u8 he_rx_1024qam_under_ru242;
+};
+
+/* Structure containing the parameters of the MM_STA_ADD_CFM message. */
+struct mm_sta_add_cfm {
+       /* Status of the operation (different from 0 if unsuccessful) */
+       u8 status;
+       /* Index assigned by the firmware to the newly added station */
+       u8 sta_idx;
+};
+
+/* Structure containing the parameters of the MM_STA_DEL_REQ message. */
+struct mm_sta_del_req {
+       u8 sta_idx;
+};
+
+/* Structure containing the parameters of the MM_STA_DEL_CFM message. */
+struct mm_sta_del_cfm {
+       /* Status of the operation (different from 0 if unsuccessful) */
+       u8 status;
+};
+
+/* Structure containing the parameters of the SET_POWER_MODE REQ message. */
+struct mm_setpowermode_req {
+       u8 mode;
+       u8 sta_idx;
+};
+
+/* Structure containing the parameters of the SET_POWER_MODE CFM message. */
+struct mm_setpowermode_cfm {
+       u8 status;
+};
+
+/* MAC Secret Key */
+#define MAC_SEC_KEY_LEN 32  /* TKIP keys 256 bits (max length) with MIC keys */
+
+struct mac_sec_key {
+       /* Key material length */
+       u8 length;
+       /* Key material */
+       u32 array[MAC_SEC_KEY_LEN / 4];
+};
+
+enum mac_cipher_suite {
+       MAC_CIPHER_SUITE_NULL,
+       MAC_CIPHER_SUITE_WEP40,
+       MAC_CIPHER_SUITE_TKIP,
+       MAC_CIPHER_SUITE_CCMP,
+       MAC_CIPHER_SUITE_WEP104,
+       MAC_CIPHER_SUITE_GCMP,
+
+       MAC_CIPHER_SUITE_MAX
+};
+
+/* Structure containing the parameters of the MM_KEY_ADD REQ message. */
+struct mm_key_add_req {
+       /* Key index (valid only for default keys) */
+       u8 key_idx;
+       /* STA index (valid only for pairwise keys) */
+       u8 sta_idx;
+       /* Key material */
+       struct mac_sec_key key;
+       /* Cipher suite */
+       u8 cipher_suite;
+       /* Index of the interface for which the key is set (valid only for default keys) */
+       u8 inst_nbr;
+       /* A-MSDU SPP parameter */
+       u8 spp;
+};
+
+/* Structure containing the parameters of the MM_KEY_ADD_CFM message. */
+struct mm_key_add_cfm {
+       /* Status of the operation (different from 0 if unsuccessful) */
+       u8 status;
+       /* HW index of the key just added */
+       u8 hw_key_idx;
+};
+
+/* Structure containing the parameters of the MM_KEY_DEL_REQ message. */
+struct mm_key_del_req {
+       u8 hw_key_idx;
+};
+
+/* Structure containing the parameters of the MM_BA_ADD_REQ message. */
+struct mm_ba_add_req {
+       /* Type of agreement (0: TX, 1: RX) */
+       u8 type;
+       /* Index of peer station with which the agreement is made */
+       u8 sta_idx;
+       /* TID for which the agreement is made with peer station */
+       u8 tid;
+       /* Buffer size - number of MPDUs that can be held in its buffer per TID */
+       __le16 bufsz;
+       /* Start sequence number negotiated during BA setup */
+       __le16 ssn;
+};
+
+/* Structure containing the parameters of the MM_BA_ADD_CFM message. */
+struct mm_ba_add_cfm {
+       /* Index of peer station for which the agreement is being confirmed */
+       u8 sta_idx;
+       /* TID for which the agreement is being confirmed */
+       u8 tid;
+       /* Status of ba establishment */
+       u8 status;
+       /* Aggregation index */
+       u8 agg_idx;
+       /* Number of descriptors the queue of session can hold */
+       u16 desc_cnt;
+};
+
+/* Structure containing the parameters of the MM_BA_DEL_REQ message. */
+struct mm_ba_del_req {
+       /* Index of peer station for which the agreement is being deleted */
+       u8 sta_idx;
+       /* TID for which the agreement is being deleted */
+       u8 tid;
+};
+
+/* Structure containing the parameters of the MM_BA_DEL_CFM message. */
+struct mm_ba_del_cfm {
+       /* Index of peer station for which the agreement deletion is being confirmed */
+       u8 sta_idx;
+       /* TID for which the agreement deletion is being confirmed */
+       u8 tid;
+       /* Status of ba deletion */
+       u8 status;
+};
+
+/* Structure containing the parameters of the MM_AVAILABLE_BA_TXQ_REQ message. */
+struct mm_available_ba_txq_req {
+       /* Index of peer station for which the agreement deletion is being confirmed */
+       u8 sta_idx;
+       /* TID for which the agreement deletion is being confirmed */
+       u8 tid;
+};
+
+/* Structure containing the parameters of the MM_AVAILABLE_BA_TXQ_CFM message. */
+struct mm_available_ba_txq_cfm {
+       /* Index of peer station for which the agreement deletion is being confirmed */
+       u8 sta_idx;
+       /* TID for which the agreement deletion is being confirmed */
+       u8 tid;
+       /* Status if ba txqueue available */
+       u8 status;
+};
+
+/* Structure containing the parameters of the MM_CONNECTION_LOSS_IND message. */
+struct mm_connection_loss_ind {
+       /* VIF instance number */
+       u8 inst_nbr;
+};
+
+/* Structure containing the parameters of the MM_PHY_RESET_CFM */
+struct mm_phy_reset_req {
+       /* PHY device: triding/elma/sdmb2b/sim */
+       u8 phy_reset;
+};
+
+struct sounding_info_per_sta {
+       u8 sta_idx;
+#if defined(__LITTLE_ENDIAN_BITFIELD)
+       u8 nc                 : 4, /* [3:0] NC of the STA */
+          fb_type_ng_cb_size : 3, /* [6:4] */
+          rsv1               : 1; /* [7] reserved */
+#else
+       u8 rsv1               : 1, /* [7] reserved */
+          fb_type_ng_cb_size : 3, /* [6:4] */
+          nc                 : 4; /* [3:0] NC of the STA */
+#endif
+};
+
+/* Information provided by application to firmware */
+struct mm_sounding_req {
+       struct sounding_info_per_sta info_per_sta[CL_MU_MAX_STA_PER_GROUP];
+       __le32 host_address;
+#if defined(__LITTLE_ENDIAN_BITFIELD)
+               /* [2:0] sounding type (HE-SU/HE-MU/HE_CQI/VHT-SU/VHT-MU) */
+       __le32  sounding_type        : 3,
+               /* [3:6] number of stations in the sounding sequence */
+               sta_num              : 4,
+               /* [7] start/stop sounding sequence */
+               start                : 1,
+               /* [19:8] life expectancy of BFR in ms */
+               lifetime             : 12,
+               /* [31:20] sounding interval. 0 means a single sounding */
+               interval             : 12;
+               /* [1:0] requested bw for the sounding sequence (BFR/NDP) */
+       u8      req_txbw             : 2,
+               /* [5:2] NSTS in the NDP frame */
+               ndp_nsts             : 4,
+               /* [7:6] reserved bits */
+               rsv1                 : 2;
+               /* [3:0] Bitmap of STAs to create SU Q-matrix for */
+       u8      q_matrix_bitmap      : 4,
+               /* [7:4] reserved bits */
+               rsv2                 : 4;
+#else
+               /* [31:20] sounding interval. 0 means a single sounding */
+       __le32  interval             : 12,
+               /* [19:8] life expectancy of BFR in ms */
+               lifetime             : 12,
+               /* [7] start/stop sounding sequence */
+               start                : 1,
+               /* [3:6] number of stations in the sounding sequence */
+               sta_num              : 4,
+               /* [2:0] sounding type (HE-SU/HE-MU/HE_CQI/VHT-SU/VHT-MU) */
+               sounding_type        : 3;
+               /* [7:6] reserved bits */
+       u8      rsv1                 : 2,
+               /* [5:2] NSTS in the NDP frame */
+               ndp_nsts             : 4,
+               /* [1:0] requested bw for the sounding sequence (BFR/NDP) */
+               req_txbw             : 2;
+               /* [7:4] reserved bits */
+       u8      rsv2                 : 4,
+               /* [3:0] Bitmap of STAs to create SU Q-matrix for */
+               q_matrix_bitmap      : 4;
+#endif
+       /* Sounding id. Used when deleting a sounding sequence */
+       u8 sid;
+};
+
+/* Application feedback for sounding request */
+struct mm_sounding_cfm {
+       u8 param_err;
+       u8 sounding_id;
+};
+
+struct mm_sounding_pairing {
+       u8 sounding_type;
+       u8 sounding_id;
+       u8 sta_idx;
+       u8 gid;
+};
+
+struct mm_sounding_interval_req {
+       __le16 interval;     /* Sounding interval */
+       __le16 bfr_lifetime; /* Life expectancy of BFR in ms */
+       u8 sounding_type;    /* Type of sounding (VHT/HT/SU/MU) */
+       u8 sta_idx;          /* Sta idx */
+};
+
+struct mm_sounding_interval_cfm {
+       u8 param_err;
+};
+
+/* Structure containing the parameters of the MM_BACKUP_BCN_EN_REQ message */
+struct mm_set_backup_bcn_en_req {
+       /* Backup beacon disable/enable */
+       bool backup_bcn_en;
+};
+
+/* Structure containing the parameters of the MM_START_PERIODIC_TX_TIME_REQ message */
+struct mm_start_periodic_tx_time_req {
+       u16 periodic_tx_time_off;
+       u16 periodic_tx_time_on;
+};
+
+enum ANAMON_MODE {
+       ANAMON_MODE_TEMPERATURE,
+       ANAMON_MODE_CHAINS,
+       ANAMON_MODE_SX
+};
+
+/* Structure containing the parameters of the MM_ANAMON_READ_REQ message */
+struct mm_anamon_read_req {
+       u8 mode;   /* 0 - Temperature, 1 - Chains, 2 - SX */
+       u8 param1; /* For mode = 0: 0 - Internal, 1 - External ; For mode = 1/2: Page number */
+       u8 param2; /* For mode = 5 bit value corresponding to mode selection */
+};
+
+struct mm_anamon_read_cfm {
+       u8 retval;
+       __le16 raw_bits_data_0;
+       __le16 raw_bits_data_1;
+};
+
+struct mm_twt_setup_req {
+       u64 twt_start_time_tsf;
+       u64 twt_interval_us;
+       u32 min_wake_duration_us;
+       u8 sta_idx;
+       u8 twt_flow_id;
+       u8 triggered;
+       u8 announced;
+};
+
+struct mm_twt_teardown_req {
+       u8 sta_idx;
+       u8 twt_flow_id;
+};
+
+struct mm_set_freq_offset_req {
+       __le16 val;
+};
+
+/* +++++++++++++++++++++++++ Debug messages +++++++++++++++++++++++++ */
+
+/* Messages related to Debug Task */
+enum dbg_msg_tag {
+       /* Set module filter message */
+       DBG_SET_MOD_FILTER_REQ = FIRST_MSG(TASK_DBG),
+       DBG_SET_MOD_FILTER_CFM,
+       /* Set module filter message */
+       DBG_CE_SET_MOD_FILTER_REQ,
+       DBG_CE_SET_MOD_FILTER_CFM,
+       /* Set severity filter message */
+       DBG_SET_SEV_FILTER_REQ,
+       DBG_SET_SEV_FILTER_CFM,
+       /* Beamforming TX message */
+       DBG_BEAMFORMING_TX_REQ,
+       DBG_BEAMFORMING_TX_CFM,
+       /* Get ETH2WLAN statistics message */
+       DBG_GET_E2W_STATS_REQ,
+       DBG_GET_E2W_STATS_CFM,
+       /* Set LA MPIF mask message */
+       DBG_SET_LA_MPIF_MASK_REQ,
+       DBG_SET_LA_MPIF_MASK_CFM,
+       /* Set LA trigger point message */
+       DBG_SET_LA_TRIG_POINT_REQ,
+       DBG_SET_LA_TRIG_POINT_CFM,
+       /* Set LA MPIF debug mode message */
+       DBG_SET_LA_MPIF_DEBUG_MODE_REQ,
+       DBG_SET_LA_MPIF_DEBUG_MODE_CFM,
+       /* Set LA trigger rule message */
+       DBG_SET_LA_TRIG_RULE_REQ,
+       DBG_SET_LA_TRIG_RULE_CFM,
+       /* TX trace dump debug flag message */
+       DBG_TX_TRACE_DEBUG_FLAG_REQ,
+       DBG_TX_TRACE_DEBUG_FLAG_CFM,
+       /* Print statistics message */
+       DBG_PRINT_STATS_REQ,
+       DBG_PRINT_STATS_CFM,
+       /* Trigger the embedded logic analyzer message */
+       DBG_TRIGGER_REQ,
+       DBG_TRIGGER_CFM,
+       /* Test mode message */
+       DBG_TEST_MODE_REQ,
+       DBG_TEST_MODE_CFM,
+       /* Sounding command message */
+       DBG_SOUNDING_CMD_REQ,
+       DBG_SOUNDING_CMD_CFM,
+
+       DBG_REQ_CFM_MAX,
+
+       /* Print request */
+       DBG_PRINT_IND = DBG_REQ_CFM_MAX,
+       /* Information indication */
+       DBG_INFO_IND,
+       /* Max number of debug messages */
+       DBG_MAX,
+};
+
+/* Structure containing the parameters of the MM_DBG_TRIGGER_REQ message. */
+struct dbg_trigger_req {
+       /* Error trace to be reported by the firmware */
+       char error[64];
+};
+
+/* Structure containing the parameters of the DBG_SET_MOD_FILTER_REQ message. */
+struct dbg_set_mod_filter_req {
+       /* Bit field indicating for each module if the traces are enabled or not */
+       __le32 mod_filter;
+};
+
+/* Structure containing the parameters of the DBG_SEV_MOD_FILTER_REQ message. */
+struct dbg_set_sev_filter_req {
+       /* Bit field indicating the severity threshold for the traces */
+       __le32 sev_filter;
+};
+
+/* Beam forming debug sequence request */
+struct dbg_beamforming_tx_req {
+       __le32 bf_cmd;
+};
+
+/* Beamforming command parameters (debugFS interface) */
+struct dbg_fs_bf_args {
+       __le32 sta_idx     : 8;
+       __le32 antenna_set : 8;
+       __le32 is_mu       : 1; /* SU-0, MU-1 */
+       __le32 is_enable   : 1;
+       __le32 interval    : 10;
+       __le32 cmd         : 4;
+};
+
+struct dbg_frame_rate {
+       __le32 mcs          : 7;
+       __le32 bw           : 2;
+       __le32 gi           : 1;
+       __le32 pretypetxrcx : 1;
+       __le32 format       : 3;
+       __le32 reserved     : 14;
+       __le32 cmd          : 4;
+};
+
+/* Statistics print request. */
+struct dbg_print_stats_req {
+       __le32 command;
+       __le32 param[4];
+};
+
+/* Must be aligned with FW (dbg.h) */
+enum dbg_test_mode {
+       DBG_TEST_MODE_HELP = 0,
+       DBG_TEST_MODE_ASSERT_REC,
+       DBG_TEST_MODE_ERR_CORRECT_MODE,
+       DBG_TEST_MODE_PRESILICON_TESTS,
+       DBG_TEST_MODE_TRIGGER_BA_NOT_RECEIVED,
+       DBG_TEST_MODE_TRIGGER_ABOVE_BAW,
+       DBG_TEST_MODE_TRIGGER_BELOW_BAW,
+       DBG_TEST_MODE_TRIGGER_RETRY_LIMIT_REACHED,
+       DBG_TEST_MODE_DMA_DATA_PRINT,
+       DBG_TEST_MODE_SET_AGC_MEM,
+       DBG_TEST_MODE_FW_TRACE_MODE,
+       DBG_TEST_MODE_TX_POWER_DEBUG,
+       DBG_TEST_MODE_DCOC_IQ_MODE,
+       DBG_TEST_MODE_MACHW_STATE,
+       DBG_TEST_MODE_PHY_GLOBAL_RESET,
+       DBG_TEST_MODE_PHY_OLYMPUS_TXRX_MODE,
+       DBG_TEST_MODE_AFE_LOOPBACK_MODE,
+       DBG_TEST_MODE_MIN_SPACING_MODE,
+       DBG_TEST_MODE_DELAY_CHAIN,
+       DBG_TEST_MODE_ERR_DUMP_PRINT,
+       DBG_TEST_MODE_BW_SIG_PRINT,
+       DBG_TEST_MODE_RECOVER_BA_NOT_RECEIVED,
+       DBG_TEST_MODE_BAP_MODE,
+       DBG_TEST_MODE_DPHY_INJECT_RXERR,
+       DBG_TEST_MODE_RXM_RXVECTOR_PRINT,
+       DBG_TEST_MODE_STOP_CHAIN,
+       DBG_TEST_MODE_MAX_AGG_SIZE,
+       DBG_TEST_MODE_DISABLE_RECOVERY,
+       DBG_TEST_MODE_SET_NAV_DURATION,
+       DBG_TEST_MODE_SET_NAV_CLEAR,
+       DBG_TEST_MODE_DRA_GRP_LIMIT_SET,
+       DBG_TEST_MODE_DURATION_FROM_THD,
+       DBG_TEST_MODE_RIU_INT_EN,
+       DBG_TEST_MODE_MU_OF_1_USER,
+       DBG_TEST_MODE_FORCE_TRIGGER,
+       DBG_TEST_MODE_RECOVERY_DEBUG,
+       DBG_TEST_MODE_CHAIN_SUSPEND,
+       DBG_TEST_MODE_DSP_LCU_TRIG,
+       DBG_TEST_MODE_POWER_SAVE,
+       DBG_TEST_MODE_TRIGGER_RX_NOT_RECEIVED,
+       DBG_TEST_MODE_SNIFFER_MODE,
+       DBG_TEST_MODE_AGC_CAPTURE_NOISE,
+       DBG_TEST_MODE_TRIGGER_UNDERRUN,
+       DBG_TEST_MODE_TF_IN_AMPDU_EN,
+       DBG_TEST_MODE_MAX,
+};
+
+/* Number of input parameters to test mode */
+#define TEST_MODE_PARAM_MAX  5
+
+/* Statistics print request. */
+struct dbg_test_mode_req {
+       __le32 command;
+       __le32 params[TEST_MODE_PARAM_MAX];
+};
+
+#define SOUNDING_CMD_MAX_PARAMS 20
+
+/* Sounding cmd */
+struct dbg_sounding_cmd_param {
+       __le32 sounding_cmd_index;
+       __le32 param[SOUNDING_CMD_MAX_PARAMS];
+};
+
+/* ETH2WLAN statistics request DBG_GET_E2W_STATS_REQ message */
+struct dbg_e2w_stats_req {
+       /* Clear statistics after get */
+       __le32 clear;
+};
+
+/* ETH2WLAN software debug counters */
+struct dbg_e2w_counters {
+       /* Total number of module activations */
+       __le32 tx_ac_total[AC_MAX];
+       /* Number of Tx conversion errors */
+       __le32 tx_ac_convert_error[AC_MAX];
+       /* Number of incorrect THD frmlen errors */
+       __le32 tx_ac_thd_frmlen_error[AC_MAX];
+       /* Number of incorrect THD data-start or data-end pointer errors */
+       __le32 tx_ac_thd_ptr_error[AC_MAX];
+       /* Number of incorrect unique THD pattern errors */
+       __le32 tx_ac_thd_pattern_error[AC_MAX];
+       /* Number of module Tx errors */
+       __le32 tx_module_error;
+
+};
+
+/* ETH2WLAN statistics confirm DBG_GET_E2W_STATS_CFM message */
+struct dbg_e2w_stats_cfm {
+       struct dbg_e2w_counters cntrs;
+};
+
+/* Embedded LA MPIF mask set request message */
+struct dbg_set_la_mpif_mask_req {
+       __le32 mpif_mask;
+};
+
+/* Embedded LA Trigger Point set request message */
+struct dbg_set_la_trig_point_req {
+       __le32 trigger_point;
+};
+
+/* Embedded LA MPIF debug mode set request message */
+struct dbg_set_la_mpif_debug_mode_req {
+       u8 mode;
+};
+
+/* Structure containing the parameters of the DBG_TX_TRACE_DEBUG_FLAG_REQ message. */
+struct dbg_tx_trace_debug_flag_req {
+       /* Bitmap for enabling\disabling debug options */
+       __le32 bitmap;
+       /* "1" - write the bitmap to global var, "0" - read the global var */
+       u8 read_write_flag;
+};
+
+enum la_trig_oper {
+       LA_TRIG_OPER_EQ,
+       LA_TRIG_OPER_NOT_EQ,
+       LA_TRIG_OPER_GT,
+       LA_TRIG_OPER_GT_EQ,
+       LA_TRIG_OPER_LT,
+       LA_TRIG_OPER_LT_EQ,
+
+       /* Always keep this entry last */
+       LA_TRIG_OPER_MAX
+};
+
+struct dbg_set_la_trig_rule_req {
+       /* Rule index */
+       u8 rule_id;
+       /* Comparison operator */
+       u8 oper;
+       /* Rule enable/disable */
+       u8 enable;
+       /* Reserved */
+       u8 rsv;
+       /* Address to be checked */
+       u32 address;
+       /* Trigger value */
+       u32 value;
+       /* Trigger value mask (enable mask - only set bits are compared) */
+       u32 mask;
+       /* Duration in usec value must match for trigger */
+       u32 duration;
+};
+
+/* Information sent from firmware to host indicating the rx bfr variables */
+struct mm_sounding_ind {
+       /* Param that are application private, collected by host without local copy */
+#if defined(__LITTLE_ENDIAN_BITFIELD)
+       u8 sounding_type : 3,
+          status        : 1,
+          fail_reason   : 4;
+       u8 mu            : 1,
+          rsv           : 7;
+#else
+       u8 fail_reason   : 4,
+          status        : 1,
+          sounding_type : 3;
+       u8 rsv           : 7,
+          mu            : 1;
+#endif
+       u8 sid;
+       u8 sta_idx;
+       u16 v_matrix_offset[CL_MU_MAX_STA_PER_GROUP];
+};
+
+/* Possible fw errors types */
+enum mm_fw_error_type {
+       MM_FW_ERROR_TYPE_MU_OFDMA_SLOW_SECONDARY,
+       MM_FW_ERROR_TYPE_MAX
+};
+
+/* Structure containing the parameters of the MM_FW_ERROR_IND message */
+struct mm_fw_error_ind {
+       u8 group_id;
+       u8 error_type;
+       u8 sta_inidices[CL_MU_MAX_STA_PER_GROUP];
+       u8 sta_num;
+};
+
+enum mm_agg_rx_status_type {
+       MM_AGG_RX_REPORT_STAT_OK,
+       MM_AGG_RX_REPORT_STAT_COLISION_WITH_COUNTER,
+       MM_AGG_RX_REPORT_STAT_COUNTER_LOST,
+       MM_AGG_RX_REPORT_STAT_NOT_RECEIVED,
+       MM_AGG_RX_REPORT_STAT_NOT_HE
+};
+
+#define MSG_TOTAL_REQ_CFM (MM_REQ_CFM_MAX + DBG_REQ_CFM_MAX)
+#define DBG_STR_SHIFT(id) ((id) - FIRST_MSG(TASK_DBG) + MM_REQ_CFM_MAX)
+#define MSG_ID_STR(id)    (((id) < MM_REQ_CFM_MAX) ? msg2str[id] : msg2str[DBG_STR_SHIFT(id)])
+
+extern const char *const msg2str[MSG_TOTAL_REQ_CFM];
+
+#endif /* _CL_FW_MSG_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.
________________________________


^ permalink raw reply related	[flat|nested] 262+ messages in thread

* [RFC v1 092/256] cl8k: add fw/msg_cfm.c
  2021-06-17 15:58 [RFC v1 000/256] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (90 preceding siblings ...)
  2021-06-17 15:59 ` [RFC v1 091/256] cl8k: add fw/fw_msg.h viktor.barna
@ 2021-06-17 15:59 ` viktor.barna
  2021-06-17 15:59 ` [RFC v1 093/256] cl8k: add fw/msg_cfm.h viktor.barna
                   ` (165 subsequent siblings)
  257 siblings, 0 replies; 262+ messages in thread
From: viktor.barna @ 2021-06-17 15:59 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Oleksandr Savchenko, Shay Bar, Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

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

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 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.
________________________________


^ permalink raw reply related	[flat|nested] 262+ messages in thread

* [RFC v1 093/256] cl8k: add fw/msg_cfm.h
  2021-06-17 15:58 [RFC v1 000/256] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (91 preceding siblings ...)
  2021-06-17 15:59 ` [RFC v1 092/256] cl8k: add fw/msg_cfm.c viktor.barna
@ 2021-06-17 15:59 ` viktor.barna
  2021-06-17 15:59 ` [RFC v1 094/256] cl8k: add fw/msg_rx.c viktor.barna
                   ` (164 subsequent siblings)
  257 siblings, 0 replies; 262+ messages in thread
From: viktor.barna @ 2021-06-17 15:59 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Oleksandr Savchenko, Shay Bar, Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

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

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 drivers/net/wireless/celeno/cl8k/fw/msg_cfm.h | 35 +++++++++++++++++++
 1 file changed, 35 insertions(+)
 create mode 100644 drivers/net/wireless/celeno/cl8k/fw/msg_cfm.h

diff --git a/drivers/net/wireless/celeno/cl8k/fw/msg_cfm.h b/drivers/net/wireless/celeno/cl8k/fw/msg_cfm.h
new file mode 100644
index 000000000000..21c4996634ae
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/fw/msg_cfm.h
@@ -0,0 +1,35 @@
+/* SPDX-License-Identifier: MIT */
+/* Copyright(c) 2019-2021, Celeno Communications Ltd. */
+
+#ifndef CL_MSG_CFM_H
+#define CL_MSG_CFM_H
+
+#include "hw.h"
+#include "fw/fw_msg.h"
+
+/* Timeout waiting for firmware confirmation */
+#define CL_MSG_CFM_TIMEOUT_MS            400
+#define CL_MSG_CFM_TIMEOUT_JIFFIES       msecs_to_jiffies(CL_MSG_CFM_TIMEOUT_MS)
+
+#define CL_MSG_CFM_TIMEOUT_CALIB_MS      1800
+#define CL_MSG_CFM_TIMEOUT_CALIB_JIFFIES msecs_to_jiffies(CL_MSG_CFM_TIMEOUT_CALIB_MS)
+
+#define CFM_CLEAR_BIT(bit, cfm_flags) \
+       clear_bit((bit) & 0x1f, *(cfm_flags) + ((bit) >> 5))
+
+#define CFM_SET_BIT(bit, cfm_flags) \
+       set_bit((bit) & 0x1f, *(cfm_flags) + ((bit) >> 5))
+
+#define CFM_TEST_BIT(bit, cfm_flags) \
+       test_bit((bit) & 0x1f, *(cfm_flags) + ((bit) >> 5))
+
+#define CFM_TEST_AND_CLEAR_BIT(bit, cfm_flags) \
+       test_and_clear_bit((bit) & 0x1f, *(cfm_flags) + ((bit) >> 5))
+
+u16 cl_msg_cfm_set_bit(u16 req);
+int cl_msg_cfm_wait(struct cl_hw *cl_hw, u16 bit, u16 req_id);
+void cl_msg_cfm_assign_and_clear(struct cl_hw *cl_hw, struct cl_ipc_e2a_msg *msg);
+void cl_msg_cfm_clear(struct cl_hw *cl_hw, struct cl_ipc_e2a_msg *msg);
+void cl_msg_cfm_simulate_timeout(struct cl_hw *cl_hw);
+
+#endif /* CL_MSG_CFM_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.
________________________________


^ permalink raw reply related	[flat|nested] 262+ messages in thread

* [RFC v1 094/256] cl8k: add fw/msg_rx.c
  2021-06-17 15:58 [RFC v1 000/256] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (92 preceding siblings ...)
  2021-06-17 15:59 ` [RFC v1 093/256] cl8k: add fw/msg_cfm.h viktor.barna
@ 2021-06-17 15:59 ` viktor.barna
  2021-06-17 15:59 ` [RFC v1 095/256] cl8k: add fw/msg_rx.h viktor.barna
                   ` (163 subsequent siblings)
  257 siblings, 0 replies; 262+ messages in thread
From: viktor.barna @ 2021-06-17 15:59 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Oleksandr Savchenko, Shay Bar, Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

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

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 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.
________________________________


^ permalink raw reply related	[flat|nested] 262+ messages in thread

* [RFC v1 095/256] cl8k: add fw/msg_rx.h
  2021-06-17 15:58 [RFC v1 000/256] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (93 preceding siblings ...)
  2021-06-17 15:59 ` [RFC v1 094/256] cl8k: add fw/msg_rx.c viktor.barna
@ 2021-06-17 15:59 ` viktor.barna
  2021-06-17 15:59 ` [RFC v1 096/256] cl8k: add fw/msg_tx.c viktor.barna
                   ` (162 subsequent siblings)
  257 siblings, 0 replies; 262+ messages in thread
From: viktor.barna @ 2021-06-17 15:59 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Oleksandr Savchenko, Shay Bar, Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

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

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 drivers/net/wireless/celeno/cl8k/fw/msg_rx.h | 10 ++++++++++
 1 file changed, 10 insertions(+)
 create mode 100644 drivers/net/wireless/celeno/cl8k/fw/msg_rx.h

diff --git a/drivers/net/wireless/celeno/cl8k/fw/msg_rx.h b/drivers/net/wireless/celeno/cl8k/fw/msg_rx.h
new file mode 100644
index 000000000000..14d971e81db9
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/fw/msg_rx.h
@@ -0,0 +1,10 @@
+/* SPDX-License-Identifier: MIT */
+/* Copyright(c) 2019-2021, Celeno Communications Ltd. */
+
+#ifndef CL_MSG_RX_H
+#define CL_MSG_RX_H
+
+void cl_msg_rx_tasklet(unsigned long data);
+void cl_msg_rx_flush_all(struct cl_hw *cl_hw);
+
+#endif /* CL_MSG_RX_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.
________________________________


^ permalink raw reply related	[flat|nested] 262+ messages in thread

* [RFC v1 096/256] cl8k: add fw/msg_tx.c
  2021-06-17 15:58 [RFC v1 000/256] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (94 preceding siblings ...)
  2021-06-17 15:59 ` [RFC v1 095/256] cl8k: add fw/msg_rx.h viktor.barna
@ 2021-06-17 15:59 ` viktor.barna
  2021-06-17 15:59 ` [RFC v1 097/256] cl8k: add fw/msg_tx.h viktor.barna
                   ` (161 subsequent siblings)
  257 siblings, 0 replies; 262+ messages in thread
From: viktor.barna @ 2021-06-17 15:59 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Oleksandr Savchenko, Shay Bar, Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

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

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 drivers/net/wireless/celeno/cl8k/fw/msg_tx.c | 1800 ++++++++++++++++++
 1 file changed, 1800 insertions(+)
 create mode 100644 drivers/net/wireless/celeno/cl8k/fw/msg_tx.c

diff --git a/drivers/net/wireless/celeno/cl8k/fw/msg_tx.c b/drivers/net/wireless/celeno/cl8k/fw/msg_tx.c
new file mode 100644
index 000000000000..b63d5be24660
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/fw/msg_tx.c
@@ -0,0 +1,1800 @@
+// SPDX-License-Identifier: MIT
+/* Copyright(c) 2019-2021, Celeno Communications Ltd. */
+
+#include "chip.h"
+#include "tx/tx.h"
+#include "rx/rx.h"
+#include "fw/msg_tx.h"
+#include "fw/msg_cfm.h"
+#include "fw/fw_msg.h"
+#include "drv_ops.h"
+#include "temperature.h"
+#include "chan_info.h"
+#include "power.h"
+#include "env_det.h"
+#include "rx/rx_filter.h"
+#include "prot_mode.h"
+#include "rate_ctrl.h"
+#include "utils/utils.h"
+#include "calib.h"
+#include "band.h"
+#include "reg/reg_riu.h"
+#include "reg/reg_ricu.h"
+#include "calib.h"
+#include "recovery.h"
+#include "utils/math.h"
+#include "fem.h"
+#include "agc_params.h"
+#include "mac_addr.h"
+#include "cap.h"
+#include "ampdu.h"
+#include "phy/phy_common_lut.h"
+#include "channel.h"
+
+#define DRV_TASK_ID 100
+
+#define CL_DEF_ANT_BITMAP 0x55
+
+/* No scale-down on ASIC platform */
+#define CL_ASIC_FW_SCALEDOWN 1
+
+struct cl_msg_tx_work {
+       struct work_struct ws;
+
+       /* Background message info */
+       struct cl_hw *cl_hw;
+       void *msg_params;
+};
+
+void cl_msg_tx_free_cfm_params(struct cl_hw *cl_hw, u16 id)
+{
+       /* Free message and set pointer to NULL */
+       kfree(cl_hw->msg_cfm_params[id]);
+       cl_hw->msg_cfm_params[id] = NULL;
+}
+
+static inline void *cl_msg_zalloc(struct cl_hw *cl_hw, u16 msg_id, u8 dst_task_id, u16 param_len)
+{
+       struct fw_msg *msg;
+       u32 total_size = ALIGN(sizeof(struct fw_msg) + param_len, sizeof(u32));
+       u32 max_size = sizeof(u32) * IPC_A2E_MSG_BUF_SIZE;
+
+       if (total_size > max_size) {
+               cl_dbg_err(cl_hw, "total size (%u) > max size (%u)\n",
+                          total_size, max_size);
+               return NULL;
+       }
+
+       /* msg is freed out of the scope of this function */
+       msg = kzalloc(total_size, GFP_ATOMIC);
+       if (!msg)
+               return NULL;
+
+       msg->msg_id = cpu_to_le16(msg_id);
+       msg->dst_kern_id = cl_hw->fw_dst_kern_id;
+       msg->dst_task_id = dst_task_id;
+       msg->src_kern_id = KERN_HOST;
+       msg->src_task_id = DRV_TASK_ID;
+       msg->param_len = cpu_to_le16(param_len);
+
+       return msg->param;
+}
+
+static inline void cl_msg_free(const void *msg_param)
+{
+       kfree(container_of((void *)msg_param, struct fw_msg, param));
+}
+
+static void cl_send_msg_background_handler(struct work_struct *ws)
+{
+       struct cl_msg_tx_work *msg_tx_work = container_of(ws, struct cl_msg_tx_work, ws);
+
+       cl_drv_ops_msg_fw_send(msg_tx_work->cl_hw, msg_tx_work->msg_params, true);
+       kfree(msg_tx_work);
+}
+
+static int cl_send_msg_background(struct cl_hw *cl_hw,
+                                 const void *msg_params)
+{
+       /* Generate & populate the work struct wrapper for the background msg */
+       struct cl_msg_tx_work *msg_tx_work = kzalloc(sizeof(*msg_tx_work), GFP_ATOMIC);
+
+       if (msg_tx_work) {
+               INIT_WORK(&msg_tx_work->ws, cl_send_msg_background_handler);
+               msg_tx_work->cl_hw = cl_hw;
+               msg_tx_work->msg_params = (void *)msg_params;
+
+               /* Schedule work, the work will be executed in the background */
+               queue_work(cl_hw->drv_workqueue, &msg_tx_work->ws);
+
+               return 0;
+       }
+
+       cl_dbg_err(cl_hw, "msg_tx_work allocation failed\n");
+       cl_msg_free(msg_params);
+
+       return -ENODATA;
+}
+
+static int cl_send_request(struct cl_hw *cl_hw, const void *msg_params)
+{
+       int ret;
+       bool background = (preempt_count() != 0);
+
+       if (background) {
+               /*
+                * asynchronous operation mode, message would be triggered in the background
+                */
+               ret = cl_send_msg_background(cl_hw, msg_params);
+       } else {
+               /*
+                * synchronous operation mode, message would be triggered immediately
+                * feedback to caller given immediately
+                */
+               ret = cl_drv_ops_msg_fw_send(cl_hw, msg_params, false);
+       }
+
+       /*
+        * In case of synchronous mode ret success implies that the msg was successfully
+        * transmited where is asynchronous mode ret success implies that the msg was
+        * successfully pushed to background queue
+        */
+       return ret;
+}
+
+int cl_msg_tx_reset(struct cl_hw *cl_hw)
+{
+       void *void_param;
+
+       /* RESET REQ has no parameter */
+       void_param = cl_msg_zalloc(cl_hw, MM_RESET_REQ, TASK_MM, 0);
+       if (!void_param)
+               return -ENOMEM;
+
+       return cl_send_request(cl_hw, void_param);
+}
+
+static u8 copy_mask_bits(u8 mask, u8 num_bits)
+{
+       /* Copy first X bits that are set in mask to new_mask */
+       u8 i = 0, cntr = 0, new_mask = 0;
+
+       for (i = 0; i < MAX_ANTENNAS; i++) {
+               if (mask & (1 << i)) {
+                       new_mask |= (1 << i);
+
+                       cntr++;
+                       if (cntr == num_bits)
+                               break;
+               }
+       }
+
+       return new_mask;
+}
+
+static void cl_fill_ant_config(struct cl_hw *cl_hw,
+                              struct cl_antenna_config *ant_config,
+                              u8 num_antennas, u8 mask_antennas,
+                              u8 tx_mask_cck, u8 rx_mask_cck)
+{
+       struct cl_chip *chip = cl_hw->chip;
+       u8 ricu_cdb = 0;
+       u8 ant_shift = cl_hw_ant_shift(cl_hw);
+
+       ant_config->num_tx_he = num_antennas;
+       ant_config->num_rx = num_antennas;
+       ant_config->mask_tx_he = mask_antennas << ant_shift;
+       ant_config->mask_rx = mask_antennas << ant_shift;
+
+       /* Configuration for TX OFDM/HT/VHT (limited to 4 antennas) */
+       if (num_antennas <= MAX_ANTENNAS_OFDM_HT_VHT) {
+               ant_config->num_tx_ofdm_ht_vht = num_antennas;
+               ant_config->mask_tx_ofdm_ht_vht = mask_antennas << ant_shift;
+       } else {
+               ant_config->num_tx_ofdm_ht_vht = MAX_ANTENNAS_OFDM_HT_VHT;
+               ant_config->mask_tx_ofdm_ht_vht =
+                       copy_mask_bits(mask_antennas, MAX_ANTENNAS_OFDM_HT_VHT) << ant_shift;
+       }
+
+       /* Antenna configuration for CCK */
+       if (cl_band_is_24g(cl_hw)) {
+               ant_config->mask_tx_cck = tx_mask_cck << ant_shift;
+               ant_config->mask_rx_cck = rx_mask_cck << ant_shift;
+       }
+
+       ricu_cdb = ricu_static_conf_0_cdb_mode_maj_getf(chip);
+
+       /*
+        * In current implementation cdb_mode equals the num of ants for SX1
+        * cbd_mask 0x0 -> SX0 chain. 0x1-> SX1 chain.
+        */
+       ricu_cdb = MAX_ANTENNAS_CHIP - ricu_cdb;
+       ricu_cdb = ANT_MASK(ricu_cdb);
+       ricu_cdb = ~ricu_cdb;
+
+       ant_config->cdb_mask = ricu_cdb;
+}
+
+static void cl_fill_fem_config(struct cl_hw *cl_hw, struct cl_fem_config *fem_conf)
+{
+       int i;
+
+       cl_fem_get_registers(cl_hw, fem_conf->reg);
+
+       for (i = 0; i < ARRAY_SIZE(fem_conf->reg); i++)
+               fem_conf->reg[i] = cpu_to_le32(fem_conf->reg[i]);
+}
+
+static void cl_fill_calib_config(struct cl_hw *cl_hw, struct cl_calib_param *calib_param,
+                                u16 primary, u16 center, u8 mode)
+{
+       struct cl_hw *cl_hw_other = cl_hw_other_tcv(cl_hw);
+       struct cl_tcv_conf *conf = cl_hw->conf;
+       u8 ant = 0;
+       u8 calib_bitmap = cl_hw->mask_num_antennas;
+       u8 ant_shift = cl_hw_ant_shift(cl_hw);
+
+       memset(calib_param->ant_tx_pairs, U8_MAX, ARRAY_SIZE(calib_param->ant_tx_pairs));
+       memset(calib_param->ant_rx_pairs, U8_MAX, ARRAY_SIZE(calib_param->ant_rx_pairs));
+
+       ant_for_each(ant) {
+               if (calib_bitmap & (1 << ant)) {
+                       calib_param->ant_tx_pairs[ant] = conf->ci_calib_ant_tx[ant - ant_shift];
+                       if (mode & SET_CHANNEL_MODE_CALIB_IQ)
+                               calib_param->ant_rx_pairs[ant] =
+                                       conf->ci_calib_ant_rx[ant - ant_shift];
+               }
+       }
+
+       if (IS_PHY_ATHOS(cl_hw->chip)) {
+               calib_param->conf.initial_rx_gain = CALIB_RX_GAIN_DEFAULT_ATHOS;
+               calib_param->conf.rx_gain_upper_limit = CALIB_RX_GAIN_UPPER_LIMIT_ATHOS;
+               calib_param->conf.rx_gain_lower_limit = CALIB_RX_GAIN_LOWER_LIMIT_ATHOS;
+       } else {
+               calib_param->conf.initial_rx_gain = CALIB_RX_GAIN_DEFAULT;
+               calib_param->conf.rx_gain_upper_limit = CALIB_RX_GAIN_UPPER_LIMIT;
+               calib_param->conf.rx_gain_lower_limit = CALIB_RX_GAIN_LOWER_LIMIT;
+       }
+
+       calib_param->conf.initial_tx_gain = CALIB_TX_GAIN_DEFAULT;
+       calib_param->conf.nco_freq = cpu_to_le16(CALIB_NCO_FREQ_DEFAULT);
+       calib_param->conf.nco_amp = CALIB_NCO_AMP_DEFAULT;
+       calib_param->conf.sleeve_trshld = GAIN_SLEEVE_TRSHLD_DEFAULT;
+       calib_param->conf.n_samples_exp_lolc = N_SAMPLES_EXP_LOLC;
+       calib_param->conf.n_samples_exp_iqc = N_SAMPLES_EXP_IQC;
+       calib_param->conf.p_thresh = cpu_to_le32(LO_P_THRESH);
+       calib_param->conf.n_bit_fir_scale = N_BIT_FIR_SCALE;
+       calib_param->conf.n_bit_amp_scale = N_BIT_AMP_SCALE;
+       calib_param->conf.n_bit_phase_scale = N_BIT_PHASE_SCALE;
+
+       cl_calib_iq_get_tone_vector(cl_hw->bw, calib_param->conf.tone_vector);
+
+       calib_param->conf.gp_rad_trshld = cpu_to_le32(GP_RAD_TRSHLD_DEFAULT);
+       calib_param->conf.ga_lin_upper_trshld = cpu_to_le32(GA_LIN_UPPER_TRSHLD_DEFAULT);
+       calib_param->conf.ga_lin_lower_trshld = cpu_to_le32(GA_LIN_LOWER_TRSHLD_DEFAULT);
+       calib_param->conf.comp_filter_len = COMP_FILTER_LEN_DEFAULT;
+       calib_param->conf.singletons_num = SINGLETONS_NUM_DEFAULT;
+       calib_param->conf.tones_num = IQ_NUM_TONES_REQ;
+       calib_param->conf.rampup_time = cpu_to_le16(RAMPUP_TIME);
+       calib_param->conf.lo_coarse_step = cpu_to_le16(LO_COARSE_STEP);
+       calib_param->conf.lo_fine_step = cpu_to_le16(LO_FINE_STEP);
+
+       calib_param->other_tcv.prim20_freq = cpu_to_le16(primary + SX_FREQ_OFFSET_Q2);
+       cl_phy_oly_lut_update(cl_hw->nl_band,
+                             center + SX_FREQ_OFFSET_Q2,
+                             &calib_param->other_tcv.center1_freq_lut);
+
+       if (cl_chip_is_both_enabled(cl_hw->chip)) {
+               calib_param->other_tcv.mask_tx_he = cl_hw_other->mask_num_antennas;
+               calib_param->other_tcv.num_tx_he = cl_hw_other->num_antennas;
+               calib_param->other_tcv.band = cl_band_to_fw_idx(cl_hw_other);
+       } else {
+               calib_param->other_tcv.mask_tx_he = cl_hw->mask_num_antennas;
+               calib_param->other_tcv.num_tx_he = cl_hw->num_antennas;
+               calib_param->other_tcv.band = cl_band_to_fw_idx(cl_hw);
+       }
+}
+
+int cl_msg_tx_start(struct cl_hw *cl_hw)
+{
+       struct mm_start_req *req;
+       struct cl_phy_cfg *phy_cfg;
+       struct cl_start_param *param;
+       struct cl_cca_config *cca_config;
+       struct dbg_meta_data *dbg_metadata;
+       struct cl_chip *chip = cl_hw->chip;
+       struct cl_tcv_conf *tcv_conf = cl_hw->conf;
+       struct cl_chip_conf *chip_conf = chip->conf;
+       struct cl_ipc_host_env *ipc_env = cl_hw->ipc_env;
+       u8 bw = 0, ant = 0;
+
+       req = cl_msg_zalloc(cl_hw, MM_START_REQ, TASK_MM, sizeof(*req));
+       if (!req)
+               return -ENOMEM;
+
+       phy_cfg = &req->phy_cfg;
+       param = &req->param;
+       cca_config = &phy_cfg->cca_config;
+       dbg_metadata = &param->dbg_metadata;
+
+       phy_cfg->band = cl_band_to_fw_idx(cl_hw);
+       phy_cfg->channel_bandwidth = tcv_conf->ce_channel_bandwidth;
+       phy_cfg->ht_rxldpc_en = tcv_conf->ce_ht_rxldpc_en;
+       phy_cfg->freq_offset = cpu_to_le16(chip->eeprom_cache->calib.freq_offset);
+       phy_cfg->vns_tx_power_mode = chip_conf->ce_production_mode ? 0 : tcv_conf->ci_vns_pwr_mode;
+       phy_cfg->vns_rssi_suto_resp_th = tcv_conf->ci_vns_rssi_auto_resp_thr;
+       phy_cfg->afe_config_en = true;
+       phy_cfg->no_capture_noise_sleep = chip_conf->ci_no_capture_noise_sleep;
+       phy_cfg->gain_update_enable = tcv_conf->ci_gain_update_enable;
+       phy_cfg->mcs_sig_b = tcv_conf->ci_mcs_sig_b;
+       phy_cfg->ofdm_only = tcv_conf->ci_ofdm_only;
+       phy_cfg->hr_factor = tcv_conf->ci_hr_factor[phy_cfg->channel_bandwidth];
+       phy_cfg->td_csd_en = tcv_conf->ci_csd_en;
+       phy_cfg->pe_duration_bcast = tcv_conf->ci_pe_duration_bcast;
+       phy_cfg->tx_digital_gain = cpu_to_le32(tcv_conf->ci_tx_digital_gain);
+       phy_cfg->tx_digital_gain_cck = cpu_to_le32(tcv_conf->ci_tx_digital_gain_cck);
+       phy_cfg->ofdm_cck_power_offset = (u8)tcv_conf->ci_ofdm_cck_power_offset;
+       phy_cfg->phy_clk_gating_en = tcv_conf->ci_phy_clk_gating_en;
+
+       /*
+        * Set rx_sensitivity according to number of antennas.
+        * For all other antennas set 0xff which is equal to -1
+        */
+       memcpy(phy_cfg->rx_sensitivity, cl_hw->rx_sensitivity, cl_hw->num_antennas);
+       if (cl_hw->num_antennas < ARRAY_SIZE(phy_cfg->rx_sensitivity))
+               memset(&phy_cfg->rx_sensitivity[cl_hw->num_antennas], U8_MAX,
+                      MAX_ANTENNAS - cl_hw->num_antennas);
+
+       if (!cl_hw->fw_send_start) {
+               cl_hw->fw_send_start = true;
+               phy_cfg->first_start = true;
+       }
+
+       cl_fill_ant_config(cl_hw, &phy_cfg->ant_config, cl_hw->num_antennas,
+                          cl_hw->mask_num_antennas, tcv_conf->ce_cck_tx_ant_mask,
+                          tcv_conf->ce_cck_rx_ant_mask);
+       cl_fill_fem_config(cl_hw, &phy_cfg->fem_conf);
+
+       cca_config->ed_rise_thr_dbm = (u8)tcv_conf->ci_cca_ed_rise_thr_dbm;
+       cca_config->ed_fall_thr_dbm = (u8)tcv_conf->ci_cca_ed_fall_thr_dbm;
+       cca_config->cs_en = tcv_conf->ci_cca_cs_en;
+       cca_config->modem_en = tcv_conf->ci_cca_modem_en;
+       cca_config->main_ant = tcv_conf->ci_cca_main_ant;
+       cca_config->second_ant = tcv_conf->ci_cca_second_ant;
+       cca_config->flag0_ctrl = tcv_conf->ci_cca_flag0_ctrl;
+       cca_config->flag1_ctrl = tcv_conf->ci_cca_flag1_ctrl;
+       cca_config->flag2_ctrl = tcv_conf->ci_cca_flag2_ctrl;
+       cca_config->flag3_ctrl = tcv_conf->ci_cca_flag3_ctrl;
+       cca_config->gi_rise_thr_dbm = (u8)tcv_conf->ci_cca_gi_rise_thr_dbm;
+       cca_config->gi_fall_thr_dbm = (u8)tcv_conf->ci_cca_gi_fall_thr_dbm;
+       cca_config->gi_pow_lim_dbm = (u8)tcv_conf->ci_cca_gi_pow_lim_dbm;
+       cca_config->ed_en = cpu_to_le16(tcv_conf->ci_cca_ed_en);
+       cca_config->gi_en = tcv_conf->ci_cca_gi_en;
+
+       param->prot_log_nav_en = tcv_conf->ce_prot_log_nav_en;
+       param->prot_mode = cl_prot_mode_get(cl_hw);
+       param->prot_rate_format = tcv_conf->ce_prot_rate_format;
+       param->prot_rate_mcs = tcv_conf->ce_prot_rate_mcs;
+       param->prot_rate_pre_type = tcv_conf->ce_prot_rate_pre_type;
+       param->bw_signaling_mode = tcv_conf->ce_bw_signaling_mode;
+       param->cfm_size = cpu_to_le16(IPC_CFM_SIZE);
+       param->cfm_dma_base_addr = cpu_to_le32(ipc_env->cfm_dma_base_addr);
+       param->phy_dev = cpu_to_le16(chip_conf->ci_phy_dev);
+       param->fw_scale_down = cpu_to_le16(CL_ASIC_FW_SCALEDOWN);
+       param->hal_timeout.idle = cpu_to_le32(tcv_conf->ci_hal_idle_to);
+       param->hal_timeout.ac0 = cpu_to_le32(tcv_conf->ci_tx_ac0_to);
+       param->hal_timeout.ac1 = cpu_to_le32(tcv_conf->ci_tx_ac1_to);
+       param->hal_timeout.ac2 = cpu_to_le32(tcv_conf->ci_tx_ac2_to);
+       param->hal_timeout.ac3 = cpu_to_le32(tcv_conf->ci_tx_ac3_to);
+       param->hal_timeout.bcn = cpu_to_le32(tcv_conf->ci_tx_bcn_to);
+
+       /* Update rxbuff/txqueue & ring_indices that hold the array metadata */
+       param->ipc_ring_indices_base = cpu_to_le32(ipc_env->ring_indices_elem->dma_addr);
+       param->host_rxbuf_base_addr[CL_RX_BUF_RXM] =
+               ipc_env->rx_hostbuf_array[CL_RX_BUF_RXM].dma_payload_base_addr;
+       param->host_rxbuf_base_addr[CL_RX_BUF_FW] =
+               ipc_env->rx_hostbuf_array[CL_RX_BUF_FW].dma_payload_base_addr;
+
+       /*
+        * The FW needs to be aware of the DMA addresses of the
+        * TX queues so it could fetch txdesc from the host.
+        */
+       param->ipc_host_tx_queues_dma_addr = cpu_to_le32(cl_hw->ipc_env->tx_queues.dma_addr);
+
+       /*
+        * Compilation flags match check - please add here all compilation flags
+        * which should be compiled on both driver and firmware.
+        */
+       param->comp_flags = cpu_to_le32(0) | cpu_to_le32(BIT(CENX_CFG_CE_TX_CFM));
+
+       param->dbg_test_mode_max = DBG_TEST_MODE_MAX;
+
+       param->ipc_rxbuf_size[CL_RX_BUF_RXM] =
+               cpu_to_le16(tcv_conf->ci_ipc_rxbuf_size[CL_RX_BUF_RXM]);
+       param->ipc_rxbuf_size[CL_RX_BUF_FW] =
+               cpu_to_le16(tcv_conf->ci_ipc_rxbuf_size[CL_RX_BUF_FW]);
+
+       param->ipc_rxbuf_extra_headroom = cpu_to_le32(IPC_RXBUF_EXTRA_HEADROOM);
+       param->host_pci_gen_ver = chip_conf->ce_host_pci_gen_ver;
+       param->dma_lli_max_chan[0] = chip_conf->ci_dma_lli_max_chan[0];
+       param->dma_lli_max_chan[1] = chip_conf->ci_dma_lli_max_chan[1];
+       param->production_mode = chip_conf->ce_production_mode;
+       param->mult_ampdu_in_txop_en = tcv_conf->ci_mult_ampdu_in_txop_en;
+       param->cca_timeout = cpu_to_le32(tcv_conf->ci_cca_timeout);
+       param->long_retry_limit = tcv_conf->ce_long_retry_limit;
+       param->short_retry_limit = tcv_conf->ce_short_retry_limit;
+       param->assoc_auth_retry_limit = tcv_conf->ci_assoc_auth_retry_limit;
+       param->bcn_tx_path_min_time = cpu_to_le16(tcv_conf->ce_bcn_tx_path_min_time);
+       param->backup_bcn_en = tcv_conf->ci_backup_bcn_en;
+       param->tx_txop_cut_en = tcv_conf->ce_tx_txop_cut_en;
+       param->ac_with_bcns_flushed_cnt_thr = tcv_conf->ci_bcns_flushed_cnt_thr;
+       param->txl_statistics_struct_size = cpu_to_le32(sizeof(struct cl_txl_statistics));
+       param->rxl_statistics_struct_size = cpu_to_le32(sizeof(struct cl_rxl_statistics));
+       param->phy_err_prevents_phy_dump = tcv_conf->ci_phy_err_prevents_phy_dump;
+       param->tx_rx_delay = tcv_conf->ci_tx_rx_delay;
+       param->assert_storm_detect_thd = tcv_conf->ci_fw_assert_storm_detect_thd;
+       param->assert_time_diff_sec = tcv_conf->ci_fw_assert_time_diff_sec;
+       param->ps_ctrl_enabled = tcv_conf->ce_ps_ctrl_enabled;
+       param->phy_data_dma_addr = cpu_to_le32(cl_hw->phy_data_info.dma_addr);
+       param->phy_remote_rom_dma_addr = cpu_to_le32(cl_hw->fw_remote_rom.dma_addr);
+       param->iq_dcoc_calib_tables_dma_addr = cpu_to_le32(cl_hw->iq_dcoc_data_info.dma_addr);
+       param->power_table_dma_addr = cpu_to_le32(cl_hw->power_table_info.dma_addr);
+       param->tf_info_dma_addr = 0;
+       param->min_ant_pwr_q1 = cl_power_min_ant_q1(cl_hw);
+
+       for (bw = 0; bw < ARRAY_SIZE(param->bw_factor_q2); bw++) {
+               cl_hw->power_db.bw_factor_q2[bw] = cl_power_bw_factor_q2(cl_hw, bw);
+               param->bw_factor_q2[bw] =
+                       cl_convert_signed_to_reg_value(cl_hw->power_db.bw_factor_q2[bw]);
+       }
+
+       for (ant = 0; ant < ARRAY_SIZE(param->ant_factor_q2); ant++) {
+               cl_hw->power_db.ant_factor_q2[ant] = cl_power_array_gain_q2(cl_hw, ant + 1);
+               param->ant_factor_q2[ant] = cl_hw->power_db.ant_factor_q2[ant];
+       }
+
+       param->default_distance.auto_resp_all = tcv_conf->ci_distance_auto_resp_all;
+       param->default_distance.auto_resp_msta = tcv_conf->ci_distance_auto_resp_msta;
+       param->su_force_min_spacing_usec = tcv_conf->ci_su_force_min_spacing;
+       param->mu_force_min_spacing_usec = tcv_conf->ci_mu_force_min_spacing;
+       param->force_tcv0_only = false;
+       param->rx_padding = tcv_conf->ci_rx_padding_en;
+       param->bar_cap_disable = tcv_conf->ci_bar_disable;
+       param->hw_bsr = 0; /* FIXME */
+       param->drop_to_lower_bw = tcv_conf->ci_drop_to_lower_bw;
+       param->dra_enable = cl_chip_is_both_enabled(chip); /* DRA enable only in CDB mode */
+       param->mac_clk_gating_en = tcv_conf->ci_mac_clk_gating_en;
+       param->imaging_blocker = tcv_conf->ci_imaging_blocker;
+       param->fec_coding = tcv_conf->ce_he_rxldpc_en;
+       param->cs_required = tcv_conf->ci_cs_required;
+
+       if (!chip->fw_first_tcv) {
+               chip->fw_first_tcv = true;
+               param->first_tcv = true;
+       }
+
+       dbg_metadata->lmac_req_buf_size = cpu_to_le32(sizeof(struct dbg_error_trace_info_drv));
+       dbg_metadata->physical_queue_cnt = CL_MAX_BA_PHYSICAL_QUEUE_CNT;
+       dbg_metadata->agg_index_max = AGG_IDX_MAX;
+       dbg_metadata->ce_ac_max = CE_AC_MAX;
+       dbg_metadata->mu_user_max = MU_MAX_STREAMS;
+       dbg_metadata->txl_exch_trace_depth = DBG_TXL_FRAME_EXCH_TRACE_DEPTH;
+       dbg_metadata->mac_hw_regs_max = cpu_to_le16(HAL_MACHW_REG_NUM);
+       dbg_metadata->phy_hw_regs_max = cpu_to_le16(PHY_HW_DBG_REGS_CNT);
+       dbg_metadata->thd_chains_data_size = cpu_to_le16(DBG_THD_CHAINS_INFO_ARRAY_SIZE);
+       dbg_metadata->chains_info_elem_cnt = DBG_CHAINS_INFO_ELEM_CNT;
+
+       return cl_send_request(cl_hw, req);
+}
+
+int cl_msg_tx_version(struct cl_hw *cl_hw)
+{
+       void *void_param;
+
+       /* VERSION REQ has no parameter */
+       void_param = cl_msg_zalloc(cl_hw, MM_VERSION_REQ, TASK_MM, 0);
+       if (!void_param)
+               return -ENOMEM;
+
+       return cl_send_request(cl_hw, void_param);
+}
+
+int cl_msg_tx_add_if(struct cl_hw *cl_hw, struct ieee80211_vif *vif,
+                    u8 vif_index)
+{
+       struct mm_add_if_req *req;
+
+       req = cl_msg_zalloc(cl_hw, MM_ADD_IF_REQ, TASK_MM, sizeof(*req));
+       if (!req)
+               return -ENOMEM;
+
+       cl_mac_addr_copy(req->addr.array, vif->addr);
+
+       switch (vif->type) {
+       case NL80211_IFTYPE_STATION:
+       case NL80211_IFTYPE_P2P_CLIENT:
+               req->type = MM_STA;
+               break;
+
+       case NL80211_IFTYPE_ADHOC:
+               req->type = MM_IBSS;
+               break;
+
+       case NL80211_IFTYPE_AP:
+       case NL80211_IFTYPE_P2P_GO:
+               req->type = MM_AP;
+               break;
+
+       case NL80211_IFTYPE_MONITOR:
+               req->type = MM_MONITOR;
+               break;
+
+       case NL80211_IFTYPE_MESH_POINT:
+               req->type = MM_MESH_POINT;
+               break;
+
+       default:
+               req->type = MM_STA;
+               break;
+       }
+
+       req->tx_strip_vlan = 1;
+       req->mac_addr_hi_mask = cpu_to_le32(cl_hw->mask_hi);
+       req->mac_addr_low_mask = cpu_to_le32(cl_hw->mask_low);
+       req->inst_nbr = vif_index;
+
+       if (vif->type == NL80211_IFTYPE_AP) {
+               struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif);
+               struct ps_data *ps = &sdata->u.ap.ps;
+
+               req->start_dtim_count = (u8)(ps->dtim_count);
+       }
+
+       return cl_send_request(cl_hw, req);
+}
+
+int cl_msg_tx_remove_if(struct cl_hw *cl_hw, u8 vif_index)
+{
+       struct mm_remove_if_req *req;
+
+       req = cl_msg_zalloc(cl_hw, MM_REMOVE_IF_REQ, TASK_MM, sizeof(*req));
+       if (!req)
+               return -ENOMEM;
+
+       req->inst_nbr = vif_index;
+
+       return cl_send_request(cl_hw, req);
+}
+
+int cl_msg_tx_sta_add(struct cl_hw *cl_hw, struct ieee80211_sta *sta,
+                     struct cl_vif *cl_vif, u8 recovery_sta_idx,
+                     u32 rate_ctrl_info)
+{
+       struct mm_sta_add_req *req;
+       struct ieee80211_sta_ht_cap *ht_cap = &sta->ht_cap;
+       struct ieee80211_sta_vht_cap *vht_cap = &sta->vht_cap;
+       struct ieee80211_sta_he_cap *he_cap = &sta->he_cap;
+       u16 my_aid = 0;
+       u8 inst_nbr = cl_vif->vif_index;
+       bool is_6g = cl_band_is_6g(cl_hw);
+       struct cl_sta *cl_sta = IEEE80211_STA_TO_CL_STA(sta);
+
+       req = cl_msg_zalloc(cl_hw, MM_STA_ADD_REQ, TASK_MM, sizeof(*req));
+       if (!req)
+               return -ENOMEM;
+
+       cl_mac_addr_copy(req->mac_addr.array, sta->addr);
+
+       if (cl_vif->vif->type == NL80211_IFTYPE_STATION)
+               my_aid = cl_vif->vif->bss_conf.aid;
+
+       if (is_6g) {
+               u8 mac_cap_info4 = he_cap->he_cap_elem.mac_cap_info[4];
+
+               req->su_bfee = (mac_cap_info4 & IEEE80211_HE_PHY_CAP4_SU_BEAMFORMEE) ? 1 : 0;
+               req->mu_bfee = (mac_cap_info4 & IEEE80211_HE_PHY_CAP4_MU_BEAMFORMER) ? 1 : 0;
+       } else if (vht_cap->vht_supported) {
+               req->su_bfee = (vht_cap->cap & IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE) ? 1 : 0;
+               req->mu_bfee = (vht_cap->cap & IEEE80211_VHT_CAP_MU_BEAMFORMEE_CAPABLE) ? 1 : 0;
+       }
+
+       req->ampdu_min_spacing = cl_sta->ampdu_min_spacing;
+
+       if (he_cap->has_he) {
+               u8 mac_cap_info1 = he_cap->he_cap_elem.mac_cap_info[1];
+               u8 mac_cap_info3 = he_cap->he_cap_elem.mac_cap_info[3];
+
+               req->he_tf_mac_padding_duration =
+                       (mac_cap_info1 & IEEE80211_HE_MAC_CAP1_TF_MAC_PAD_DUR_MASK);
+
+               req->he_rx_ctrl_frm_to_mbss =
+                       (mac_cap_info3 & IEEE80211_HE_MAC_CAP3_RX_CTRL_FRAME_TO_MULTIBSS) ?
+                       true : false;
+
+               /* Fill PE duration table */
+               cl_cap_ppe_duration(cl_hw, sta, req->pe_duration);
+       }
+
+       cl_ampdu_size_exp(cl_hw, sta, &req->ampdu_size_exp_he,
+                         &req->ampdu_size_exp_vht, &req->ampdu_size_exp_ht);
+
+       if (cl_hw->conf->ce_txldpc_en) {
+               if (he_cap->has_he)
+                       req->ldpc_enabled = (he_cap->he_cap_elem.phy_cap_info[1] &
+                                            IEEE80211_HE_PHY_CAP1_LDPC_CODING_IN_PAYLOAD) ? 1 : 0;
+               else if (vht_cap->vht_supported)
+                       req->ldpc_enabled = (vht_cap->cap & IEEE80211_VHT_CAP_RXLDPC) ? 1 : 0;
+               else if (ht_cap->ht_supported)
+                       req->ldpc_enabled = (ht_cap->cap & IEEE80211_HT_CAP_LDPC_CODING) ? 1 : 0;
+       }
+
+       /* TODO Set the interface index from the vif structure */
+       req->inst_nbr = inst_nbr;
+
+       req->aid = cpu_to_le16(sta->aid);
+       req->my_aid = cpu_to_le16(my_aid);
+       req->recovery_sta_idx = recovery_sta_idx;
+
+       /* Station power save configuration */
+       req->uapsd_queues = sta->uapsd_queues;
+       req->max_sp = sta->max_sp;
+
+       /* Set WRS default parameters for rate control */
+       req->tx_params.rate = cpu_to_le32(rate_ctrl_info);
+
+       /* Fill TX antenna with default value */
+       req->tx_params.ant_set = CL_DEF_ANT_BITMAP;
+
+       return cl_send_request(cl_hw, req);
+}
+
+int cl_msg_tx_sta_del(struct cl_hw *cl_hw, u8 sta_idx)
+{
+       struct mm_sta_del_req *req;
+
+       req = cl_msg_zalloc(cl_hw, MM_STA_DEL_REQ, TASK_MM, sizeof(*req));
+       if (!req)
+               return -ENOMEM;
+
+       req->sta_idx = sta_idx;
+
+       return cl_send_request(cl_hw, req);
+}
+
+int cl_msg_tx_set_filter(struct cl_hw *cl_hw, u32 filter, bool force)
+{
+       struct mm_set_filter_req *req;
+       u32 rx_filter = 0;
+
+       if (cl_channel_is_scan_active(cl_hw)) {
+               cl_dbg_trace(cl_hw, "Set filter ignored due to active channel scan\n");
+               return 0;
+       }
+
+       if (force)
+               rx_filter = filter;
+       else
+               rx_filter = cl_rx_filter_update_flags(cl_hw, filter);
+
+       if (rx_filter == cl_hw->rx_filter) {
+               cl_dbg_trace(cl_hw, "Rx filter 0x%x already set - return\n", rx_filter);
+               return 0;
+       }
+
+       req = cl_msg_zalloc(cl_hw, MM_SET_FILTER_REQ, TASK_MM, sizeof(*req));
+       if (!req)
+               return -ENOMEM;
+
+       /* Now copy all the flags into the message parameter */
+       req->filter = cpu_to_le32(rx_filter);
+       cl_hw->rx_filter = rx_filter;
+
+       cl_dbg_trace(cl_hw, "new total_flags = 0x%08x\nrx filter set to  0x%08x\n",
+                    filter, rx_filter);
+
+       return cl_send_request(cl_hw, req);
+}
+
+u8 cl_mark_calib_flags(struct cl_hw *cl_hw, u8 mode)
+{
+       int lna = 0;
+       int ant = 0;
+       u8 calib_info_set = 0;
+       struct cl_iq_dcoc_info *iq_dcoc_db = &cl_hw->phy_data_info.data->iq_dcoc_db;
+
+       /* In case DCOC is going to be calibrated, no need to raise any calibration flag. */
+       if (mode & SET_CHANNEL_MODE_CALIB_DCOC)
+               return calib_info_set;
+
+       /* Check if DCOC flag should be marked */
+       for (lna = 0; lna < ARRAY_SIZE(iq_dcoc_db->dcoc); lna++) {
+               for (ant = 0; ant < cl_hw->num_antennas; ant++) {
+                       if (iq_dcoc_db->dcoc[lna][ant].i || iq_dcoc_db->dcoc[lna][ant].q) {
+                               calib_info_set |= SET_PHY_DATA_FLAGS_DCOC;
+                               break;
+                       }
+               }
+       }
+
+       /* Check if IQ Tx LOLC flag should be marked */
+       for (ant = 0; ant < cl_hw->num_antennas; ant++) {
+               if (iq_dcoc_db->iq_tx_lolc[ant]) {
+                       calib_info_set |= SET_PHY_DATA_FLAGS_IQ_TX_LOLC;
+                       break;
+               }
+       }
+
+       /* Check if IQ Tx flag should be marked */
+       for (ant = 0; ant < cl_hw->num_antennas; ant++) {
+               if (iq_dcoc_db->iq_tx[ant].coef0 || iq_dcoc_db->iq_tx[ant].coef1 ||
+                   iq_dcoc_db->iq_tx[ant].coef2 || iq_dcoc_db->iq_tx[ant].gain) {
+                       calib_info_set |= SET_PHY_DATA_FLAGS_IQ_TX;
+                       break;
+               }
+       }
+
+       /* Check if IQ Rx flag should be marked */
+       for (ant = 0; ant < cl_hw->num_antennas; ant++) {
+               if (iq_dcoc_db->iq_rx[ant].coef0 || iq_dcoc_db->iq_rx[ant].coef1 ||
+                   iq_dcoc_db->iq_rx[ant].coef2 || iq_dcoc_db->iq_rx[ant].gain) {
+                       calib_info_set |= SET_PHY_DATA_FLAGS_IQ_RX;
+                       return calib_info_set;
+               }
+       }
+       return calib_info_set;
+}
+
+static int __cl_msg_tx_set_channel(struct cl_hw *cl_hw, u32 channel, u8 bw, u16 primary,
+                                  u16 center, u8 mode)
+{
+       struct mm_set_channel_req *req;
+       int res = 0;
+       struct cl_phy_data *data = cl_hw->phy_data_info.data;
+
+       /* Fill AGC parameters - check before we start building the message */
+       if ((res = cl_agc_params_fill(cl_hw, &data->agc_params)))
+               return res;
+
+       req = cl_msg_zalloc(cl_hw, MM_SET_CHANNEL_REQ, TASK_MM, sizeof(*req));
+       if (!req)
+               return -ENOMEM;
+
+       req->band = cl_band_to_fw_idx(cl_hw);
+       req->bandwidth = bw;
+       req->prim20_freq = cpu_to_le16(primary);
+       cl_phy_oly_lut_update(cl_hw->nl_band, center, &req->center1_freq_lut);
+       req->hr_factor = cl_hw->conf->ci_hr_factor[bw];
+       req->signal_ext = cl_hw->conf->ci_signal_extension_en;
+
+       /* Set power per mcs offset after EIRP truncation */
+       cl_power_tables_update(cl_hw, &data->pwr_tables);
+
+       /* Get antenna power offset from eeprom */
+       cl_calib_power_offset_fill(cl_hw, channel, bw, req->ant_pwr_offset);
+
+       cl_calib_fill_phy_data(cl_hw, &data->iq_dcoc_db, SET_PHY_DATA_FLAGS_ALL);
+
+       if (mode == SET_CHANNEL_MODE_CALIB)
+               req->calib_info_set = SET_PHY_DATA_FLAGS_ALL;
+       else
+               req->calib_info_set = SET_PHY_DATA_FLAGS_NONE;
+
+       req->calib_param.mode = mode;
+
+       if (mode & (SET_CHANNEL_MODE_CALIB_LOLC | SET_CHANNEL_MODE_CALIB_IQ)) {
+               req->sx_freq_offset_mhz = SX_FREQ_OFFSET_Q2;
+               cl_fill_calib_config(cl_hw, &req->calib_param, primary, center, mode);
+       }
+
+       if (mode & SET_CHANNEL_MODE_CALIB_DCOC) {
+               if (IS_PHY_ATHOS(cl_hw->chip))
+                       req->calib_param.dcoc_max_vga = DCOC_MAX_VGA_ATHOS;
+               else
+                       req->calib_param.dcoc_max_vga = DCOC_MAX_VGA;
+       }
+
+       /* Antenna configuration */
+       cl_fill_ant_config(cl_hw, &req->ant_config, cl_hw->num_antennas, cl_hw->mask_num_antennas,
+                          cl_hw->conf->ce_cck_tx_ant_mask, cl_hw->conf->ce_cck_rx_ant_mask);
+       /* FEM configuration */
+       cl_fill_fem_config(cl_hw, &req->fem_conf);
+
+       res = cl_send_request(cl_hw, req);
+
+       cl_temperature_comp_update_calib(cl_hw);
+
+       cl_dbg_info(cl_hw,
+                   "band=%u, channel=%u, bw=%u, primary=%u.%u, center=%u.%u, sx_index=%u\n",
+                   cl_hw->conf->ci_band_num, channel, bw, GET_FREQ_INT(primary),
+                   GET_FREQ_FRAC(primary), GET_FREQ_INT(center), GET_FREQ_FRAC(center),
+                   cl_hw->tcv_idx);
+
+       return res;
+}
+
+int _cl_msg_tx_set_channel(struct cl_hw *cl_hw, u32 channel, u8 bw, u32 primary,
+                          u32 center, u8 mode)
+{
+       int res = 0;
+       u32 primary_q2 = FREQ_TO_Q2(primary);
+       u32 center_q2 = FREQ_TO_Q2(center);
+
+       /*
+        * Need to take mutex lock to ensure that no one touching the phy_data
+        * DMA before FW is reading all its values.
+        * The mutex is unlocked right after the iq_dcoc_data_info DMA is
+        * handled in cl_calib_handle_set_channel_cfm.
+        */
+       res = mutex_lock_interruptible(&cl_hw->set_channel_mutex);
+
+       if (res != 0) {
+               cl_dbg_verbose(cl_hw, "Error - mutex_lock_interruptible (%d)\n", res);
+               return res;
+       }
+
+       cl_hw->channel = channel;
+       cl_hw->bw = bw;
+       cl_hw->primary_freq = primary;
+       cl_hw->center_freq = center;
+
+       if (mode & SET_CHANNEL_MODE_CALIB)
+               cl_hw->msg_calib_timeout = true;
+
+       res = __cl_msg_tx_set_channel(cl_hw, channel, bw, primary_q2, center_q2, mode);
+
+       if (mode & SET_CHANNEL_MODE_CALIB) {
+               cl_hw->msg_calib_timeout = false;
+
+               if (!res)
+                       res = cl_calib_handle_cfm(cl_hw, mode);
+       }
+
+       mutex_unlock(&cl_hw->set_channel_mutex);
+
+       return res;
+}
+
+int cl_msg_tx_set_channel(struct cl_hw *cl_hw, u32 channel, u8 bw, u32 primary, u32 center)
+{
+       if (cl_calib_is_needed(cl_hw, channel, bw))
+               return cl_calib_set_channel(cl_hw, channel, bw, primary, center);
+       else
+               return _cl_msg_tx_set_channel(cl_hw, channel, bw, primary, center,
+                                             SET_CHANNEL_MODE_OPERETIONAL);
+}
+
+int cl_msg_tx_dtim(struct cl_hw *cl_hw, u8 dtim_period)
+{
+       struct mm_set_dtim_req *req;
+
+       req = cl_msg_zalloc(cl_hw, MM_SET_DTIM_REQ, TASK_MM, sizeof(*req));
+       if (!req)
+               return -ENOMEM;
+
+       req->dtim_period = dtim_period;
+
+       return cl_send_request(cl_hw, req);
+}
+
+int cl_msg_tx_set_beacon_int(struct cl_hw *cl_hw, u16 beacon_int, u8 vif_idx)
+{
+       struct mm_set_beacon_int_req *req;
+
+       req = cl_msg_zalloc(cl_hw, MM_SET_BEACON_INT_REQ, TASK_MM, sizeof(*req));
+       if (!req)
+               return -ENOMEM;
+
+       req->beacon_int = cpu_to_le16(beacon_int);
+       req->inst_nbr = vif_idx;
+
+       return cl_send_request(cl_hw, req);
+}
+
+int cl_msg_tx_set_basic_rates(struct cl_hw *cl_hw, u32 basic_rates)
+{
+       struct mm_set_basic_rates_req *req;
+
+       req = cl_msg_zalloc(cl_hw, MM_SET_BASIC_RATES_REQ, TASK_MM, sizeof(*req));
+       if (!req)
+               return -ENOMEM;
+
+       req->rates = cpu_to_le32(basic_rates);
+
+       return cl_send_request(cl_hw, req);
+}
+
+int cl_msg_tx_set_bssid(struct cl_hw *cl_hw, const u8 *bssid, u8 vif_idx)
+{
+       struct mm_set_bssid_req *req;
+
+       req = cl_msg_zalloc(cl_hw, MM_SET_BSSID_REQ, TASK_MM, sizeof(*req));
+       if (!req)
+               return -ENOMEM;
+
+       cl_mac_addr_copy(req->bssid.array, bssid);
+       req->inst_nbr = vif_idx;
+
+       return cl_send_request(cl_hw, req);
+}
+
+int cl_msg_tx_set_edca(struct cl_hw *cl_hw, u8 hw_queue, u32 param,
+                      struct ieee80211_he_mu_edca_param_ac_rec *mu_edca)
+{
+       struct mm_set_edca_req *req;
+
+       req = cl_msg_zalloc(cl_hw, MM_SET_EDCA_REQ, TASK_MM, sizeof(*req));
+       if (!req)
+               return -ENOMEM;
+
+       req->ac_param = cpu_to_le32(param);
+       req->hw_queue = hw_queue;
+
+       if (mu_edca) {
+               req->mu_edca_aifsn = mu_edca->aifsn;
+               req->mu_edca_ecw_min_max = mu_edca->ecw_min_max;
+               req->mu_edca_timer = mu_edca->mu_edca_timer;
+       }
+
+       return cl_send_request(cl_hw, req);
+}
+
+int cl_msg_tx_set_associated(struct cl_hw *cl_hw,
+                            struct ieee80211_bss_conf *bss_conf)
+{
+       struct mm_set_associated_req *req;
+
+       req = cl_msg_zalloc(cl_hw, MM_SET_ASSOCIATED_REQ, TASK_MM, sizeof(*req));
+       if (!req)
+               return -ENOMEM;
+
+       req->aid = cpu_to_le16(bss_conf->aid);
+
+       /* Multiple BSSID feature support */
+       if (bss_conf->nontransmitted && bss_conf->assoc) {
+               u8 i = 0;
+               u8 mask_addr[ETH_ALEN] = {0};
+               u32 bssid_hi_mask = 0;
+               u32 bssid_low_mask = 0;
+
+               for (i = 0; i < ARRAY_SIZE(mask_addr); i++)
+                       mask_addr[i] = (bss_conf->transmitter_bssid[i] ^
+                                       bss_conf->bssid[i]);
+               cl_mac_addr_array_to_nxmac(mask_addr, &bssid_low_mask,
+                                          &bssid_hi_mask);
+               /* Set mask to allow the transmitter BSSID Rx reception */
+               req->bssid_hi_mask = cpu_to_le32(bssid_hi_mask);
+               req->bssid_low_mask = cpu_to_le32(bssid_low_mask);
+       }
+
+       return cl_send_request(cl_hw, req);
+}
+
+int cl_msg_tx_set_slottime(struct cl_hw *cl_hw, bool use_short_slot)
+{
+       struct mm_set_slottime_req *req;
+
+       req = cl_msg_zalloc(cl_hw, MM_SET_SLOTTIME_REQ, TASK_MM, sizeof(*req));
+       if (!req)
+               return -ENOMEM;
+
+       req->slottime = use_short_slot ? 9 : 20;
+
+       return cl_send_request(cl_hw, req);
+}
+
+int cl_msg_tx_set_idle(struct cl_hw *cl_hw, u8 idle)
+{
+       struct mm_set_idle_req *req;
+
+       if (cl_fem_read_wiring_id(cl_hw->chip)) {
+               cl_dbg_err(cl_hw, "!!! Invalid wiring id [%u] !!! Aborting\n",
+                          cl_hw->chip->fem.wiring_id);
+               return -EINVAL;
+       }
+
+       /*
+        * Rearm last_tbtt_ind so that error message will
+        * not be printed in cl_irq_status_tbtt()
+        */
+       if (!idle)
+               cl_hw->last_tbtt_irq = jiffies;
+
+       req = cl_msg_zalloc(cl_hw, MM_SET_IDLE_REQ, TASK_MM, sizeof(*req));
+       if (!req)
+               return -ENOMEM;
+
+       req->hw_idle = idle;
+
+       cl_dbg_info(cl_hw, "idle = %s\n", idle ? "True" : "False");
+
+       return cl_send_request(cl_hw, req);
+}
+
+void cl_msg_tx_idle_async(struct cl_hw *cl_hw)
+{
+       cl_hw->idle_async_set = true;
+       cl_msg_tx_set_idle(cl_hw, MAC_IDLE_ASYNC);
+}
+
+int cl_msg_tx_key_add(struct cl_hw *cl_hw, struct ieee80211_vif *vif,
+                     struct ieee80211_sta *sta,
+                     struct ieee80211_key_conf *key_conf,
+                     u8 cipher_suite)
+{
+       struct mm_key_add_req *req;
+
+       req = cl_msg_zalloc(cl_hw, MM_KEY_ADD_REQ, TASK_MM, sizeof(*req));
+       if (!req)
+               return -ENOMEM;
+
+       if (sta) {
+               /* Pairwise key */
+               req->sta_idx = ((struct cl_sta *)sta->drv_priv)->sta_idx;
+       } else {
+               /* Default key */
+               req->sta_idx = 0xFF;
+               req->key_idx = (u8)(key_conf->keyidx); /* Only useful for default keys */
+       }
+
+       req->inst_nbr = ((struct cl_vif *)vif->drv_priv)->vif_index;
+       req->key.length = key_conf->keylen;
+
+       /* TODO: check if this works well in Big endian platforms */
+       memcpy(req->key.array, key_conf->key, key_conf->keylen);
+
+       req->cipher_suite = cipher_suite;
+       req->spp = cl_hw->conf->ci_spp_ksr_value;
+
+       cl_dbg_info(cl_hw, "sta_idx:%u, key_idx:%u, inst_nbr:%u, cipher:%u, key_len:%u, spp:%u\n",
+                   req->sta_idx, req->key_idx, req->inst_nbr,
+                   req->cipher_suite, req->key.length, req->spp);
+
+       return cl_send_request(cl_hw, req);
+}
+
+int cl_msg_tx_key_del(struct cl_hw *cl_hw, u8 hw_key_idx)
+{
+       struct mm_key_del_req *req;
+
+       req = cl_msg_zalloc(cl_hw, MM_KEY_DEL_REQ, TASK_MM, sizeof(*req));
+       if (!req)
+               return -ENOMEM;
+
+       req->hw_key_idx = hw_key_idx;
+
+       return cl_send_request(cl_hw, req);
+}
+
+int cl_msg_tx_ba_add(struct cl_hw *cl_hw, u8 type, u8 sta_idx,
+                    u16 tid, u16 bufsz, u16 ssn)
+{
+       struct mm_ba_add_req *req;
+       u16 msg_id = ((type == BA_AGMT_TX) ? MM_BA_ADD_TX_REQ : MM_BA_ADD_RX_REQ);
+
+       req = cl_msg_zalloc(cl_hw, msg_id, TASK_MM, sizeof(*req));
+       if (!req)
+               return -ENOMEM;
+
+       req->type = type;
+       req->sta_idx = sta_idx;
+       req->tid = (u8)tid;
+       req->bufsz = cpu_to_le16(bufsz);
+       req->ssn = cpu_to_le16(ssn);
+
+       return cl_send_request(cl_hw, req);
+}
+
+int cl_msg_tx_ba_del(struct cl_hw *cl_hw, u8 sta_idx, u16 tid)
+{
+       struct mm_ba_del_req *req;
+
+       req = cl_msg_zalloc(cl_hw, MM_BA_DEL_REQ, TASK_MM, sizeof(*req));
+       if (!req)
+               return -ENOMEM;
+
+       req->sta_idx = sta_idx;
+       req->tid = (u8)tid;
+
+       return cl_send_request(cl_hw, req);
+}
+
+int cl_msg_tx_phy_reset(struct cl_hw *cl_hw)
+{
+       struct mm_phy_reset_req *req;
+
+       req = cl_msg_zalloc(cl_hw, MM_PHY_RESET_REQ, TASK_MM, sizeof(*req));
+       if (!req)
+               return -ENOMEM;
+
+       return cl_send_request(cl_hw, req);
+}
+
+int cl_msg_tx_available_ba_txq(struct cl_hw *cl_hw, u8 sta_idx, u16 tid)
+{
+       struct mm_available_ba_txq_req *req;
+
+       req = cl_msg_zalloc(cl_hw, MM_AVAILABLE_BA_TXQ_REQ, TASK_MM, sizeof(*req));
+       if (!req)
+               return -ENOMEM;
+
+       req->sta_idx = sta_idx;
+       req->tid = (u8)tid;
+
+       return cl_send_request(cl_hw, req);
+}
+
+int cl_msg_tx_update_rate_dl(struct cl_hw *cl_hw, u8 sta_idx, u32 rate, u32 rate_fallback,
+                            u8 req_bw_tx, u8 op_mode, u8 ltf, u8 ltf_fallback, u32 rate_he)
+{
+       struct mm_update_rate_dl_req *req;
+
+       cl_dbg_info(cl_hw, "sta_idx=%u, rate=0x%x, rate_fallback=0x%x, req_bw_tx=%u, "
+                   "op_mode=%u, ltf=%u, ltf_fallback=%u, rate_he=0x%x\n",
+                   sta_idx, rate, rate_fallback, req_bw_tx, op_mode,
+                   ltf, ltf_fallback, rate_he);
+
+       req = cl_msg_zalloc(cl_hw, MM_UPDATE_RATE_DL_REQ, TASK_MM, sizeof(*req));
+       if (!req)
+               return -ENOMEM;
+
+       /* Populate tx_params */
+       req->tx_params.rate = cpu_to_le32(rate);
+       req->tx_params.rate_he = cpu_to_le32(rate_he);
+       req->tx_params.req_bw_tx = req_bw_tx;
+       req->tx_params.ant_set = CL_DEF_ANT_BITMAP;
+       req->tx_params.ltf = ltf;
+
+       req->op_mode = op_mode;
+       req->sta_idx = sta_idx;
+       req->rate_fallback = cpu_to_le32(rate_fallback);
+       req->ltf_fallback = ltf_fallback;
+
+       return cl_send_request(cl_hw, req);
+}
+
+int cl_msg_tx_set_vns(struct cl_hw *cl_hw, u8 sta_idx, u8 is_vns)
+{
+       struct mm_set_vns_req *req;
+
+       req = cl_msg_zalloc(cl_hw, MM_SET_VNS_REQ, TASK_MM, sizeof(*req));
+       if (!req)
+               return -ENOMEM;
+
+       req->sta_idx = sta_idx;
+       req->is_vns = is_vns;
+
+       return cl_send_request(cl_hw, req);
+}
+
+int cl_msg_tx_set_tx_bf(struct cl_hw *cl_hw, u8 sta_idx, u8 is_on, u8 is_on_fallback)
+{
+       struct mm_set_tx_bf_req *req;
+
+       req = cl_msg_zalloc(cl_hw, MM_SET_TX_BF_REQ, TASK_MM, sizeof(*req));
+       if (!req)
+               return -ENOMEM;
+
+       req->sta_idx = sta_idx;
+       req->is_on = is_on;
+       req->is_on_fallback = is_on_fallback;
+
+       return cl_send_request(cl_hw, req);
+}
+
+int cl_msg_tx_sounding(struct cl_hw *cl_hw,
+                      struct mm_sounding_req *sounding_req)
+{
+       struct mm_sounding_req *req;
+       u8 i;
+
+       req = cl_msg_zalloc(cl_hw, MM_SOUNDING_REQ, TASK_MM, sizeof(*req));
+       if (!req)
+               return -ENOMEM;
+
+       /* Populate mm_sounding_req */
+       memcpy(req, sounding_req, sizeof(struct mm_sounding_req));
+
+       /* In case of non-TB HE SU/CQI, nc should be set to 0 */
+       if (req->sounding_type == SOUNDING_TYPE_HE_CQI ||
+           req->sounding_type == SOUNDING_TYPE_HE_SU)
+               for (i = 0; i < req->sta_num; i++)
+                       req->info_per_sta[i].nc = 0;
+
+       return cl_send_request(cl_hw, req);
+}
+
+int cl_msg_tx_sounding_pairing(struct cl_hw *cl_hw, u8 sounding_id, u8 sounding_type,
+                              u8 gid, u8 sta_idx)
+{
+       struct mm_sounding_pairing *req;
+
+       req = cl_msg_zalloc(cl_hw, MM_SOUNDING_PAIRING_REQ, TASK_MM, sizeof(*req));
+       if (!req)
+               return -ENOMEM;
+
+       req->sounding_type = sounding_type;
+       req->sta_idx = sta_idx;
+       req->gid = gid;
+       req->sounding_id = sounding_id;
+
+       return cl_send_request(cl_hw, req);
+}
+
+int cl_msg_tx_sounding_interval(struct cl_hw *cl_hw, u16 interval, u16 lifetime,
+                               u8 sounding_type, u8 sta_idx)
+{
+       struct mm_sounding_interval_req *req;
+
+       req = cl_msg_zalloc(cl_hw, MM_SOUNDING_INTERVAL_REQ, TASK_MM, sizeof(*req));
+       if (!req)
+               return -ENOMEM;
+
+       req->interval = cpu_to_le16(interval);
+       req->bfr_lifetime = cpu_to_le16(lifetime);
+       req->sounding_type = sounding_type;
+       req->sta_idx = sta_idx;
+
+       return cl_send_request(cl_hw, req);
+}
+
+int cl_msg_tx_config_cca(struct cl_hw *cl_hw, bool enable)
+{
+       struct mm_config_cca_req *req;
+
+       req = cl_msg_zalloc(cl_hw, MM_CONFIG_CCA_REQ, TASK_MM, sizeof(*req));
+       if (!req)
+               return -ENOMEM;
+
+       req->enable = enable;
+
+       return cl_send_request(cl_hw, req);
+}
+
+int cl_msg_tx_set_dfs(struct cl_hw *cl_hw, bool enable, u8 standard,
+                     u8 initial_gain, u8 agc_cd_th)
+{
+       struct mm_set_dfs_req *req;
+
+       req = cl_msg_zalloc(cl_hw, MM_SET_DFS_REQ, TASK_MM, sizeof(*req));
+       if (!req)
+               return -ENOMEM;
+
+       req->enable = enable;
+       req->standard_fcc = (standard == CL_STANDARD_FCC) ? true : false;
+       req->initial_gain = initial_gain;
+       req->agc_cd_th = agc_cd_th;
+
+       return cl_send_request(cl_hw, req);
+}
+
+int cl_msg_tx_set_ant_bitmap(struct cl_hw *cl_hw, u8 bitmap)
+{
+       struct mm_set_ant_bitmap_req *req;
+       u8 num_antennas = hweight8(bitmap);
+       u8 bitmap_cck = 0;
+
+       req = cl_msg_zalloc(cl_hw, MM_SET_ANT_BITMAP_REQ, TASK_MM, sizeof(*req));
+       if (!req)
+               return -ENOMEM;
+
+       if (cl_band_is_24g(cl_hw)) {
+               if (num_antennas > MAX_ANTENNAS_CCK)
+                       bitmap_cck = copy_mask_bits(bitmap, MAX_ANTENNAS_CCK);
+               else
+                       bitmap_cck = bitmap;
+       }
+
+       cl_fill_ant_config(cl_hw, &req->ant_config, num_antennas, bitmap, bitmap_cck, bitmap_cck);
+
+       return cl_send_request(cl_hw, req);
+}
+
+int cl_msg_tx_ndp_tx_control(struct cl_hw *cl_hw, u8 chain_mask, u8 bw, u8 format, u8 num_ltf)
+{
+       struct mm_ndp_tx_control_req *req;
+
+       req = cl_msg_zalloc(cl_hw, MM_NDP_TX_CONTROL_REQ, TASK_MM, sizeof(*req));
+       if (!req)
+               return -ENOMEM;
+
+       req->chain_mask = chain_mask;
+       req->bw = bw;
+       req->format = format;
+       req->num_ltf = num_ltf;
+
+       return cl_send_request(cl_hw, req);
+}
+
+int cl_msg_tx_reg_write(struct cl_hw *cl_hw, u32 address, u32 value, u32 mask)
+{
+       struct mm_reg_write_req *req;
+
+       req = cl_msg_zalloc(cl_hw, MM_REG_WRITE_REQ, TASK_MM, sizeof(*req));
+       if (!req)
+               return -ENOMEM;
+
+       req->address = cpu_to_le32(address);
+       req->value = cpu_to_le32(value);
+       req->mask = cpu_to_le32(mask);
+
+       cl_dbg_info(cl_hw, "address=0x%x, value=0x%x, mask=0x%x\n", address, value, mask);
+
+       return cl_send_request(cl_hw, req);
+}
+
+int cl_msg_tx_prot_mode(struct cl_hw *cl_hw, u8 log_nav_en, u8 mode, u8 rate_format,
+                       u8 rate_mcs, u8 rate_pre_type)
+{
+       struct mm_prot_mode_req *req;
+
+       req = cl_msg_zalloc(cl_hw, MM_PROT_MODE_REQ, TASK_MM, sizeof(*req));
+       if (!req)
+               return -ENOMEM;
+
+       req->log_nav_en = log_nav_en;
+       req->mode = mode;
+       req->rate_format = rate_format;
+       req->rate_mcs = rate_mcs;
+       req->rate_pre_type = rate_pre_type;
+
+       return cl_send_request(cl_hw, req);
+}
+
+int cl_msg_tx_goto_power_reduction(struct cl_hw *cl_hw, u8 mode)
+{
+       struct mm_goto_power_reduction_req *req;
+
+       req = cl_msg_zalloc(cl_hw, MM_GOTO_POWER_REDUCTION_REQ, TASK_MM, sizeof(*req));
+       if (!req)
+               return -ENOMEM;
+
+       req->goto_power_reduction_mode = mode;
+
+       return cl_send_request(cl_hw, req);
+}
+
+int cl_msg_tx_backup_bcn_en(struct cl_hw *cl_hw, bool backup_bcn_en)
+{
+       struct mm_set_backup_bcn_en_req *req;
+
+       req = cl_msg_zalloc(cl_hw, MM_BACKUP_BCN_EN_REQ, TASK_MM, sizeof(*req));
+       if (!req)
+               return -ENOMEM;
+
+       req->backup_bcn_en = backup_bcn_en;
+
+       return cl_send_request(cl_hw, req);
+}
+
+int cl_msg_tx_start_periodic_tx_time(struct cl_hw *cl_hw, u16 periodic_tx_time_off,
+                                    u16 periodic_tx_time_on)
+{
+       struct mm_start_periodic_tx_time_req *req;
+
+       req = cl_msg_zalloc(cl_hw, MM_START_PERIODIC_TX_TIME_REQ, TASK_MM, sizeof(*req));
+       if (!req)
+               return -ENOMEM;
+
+       req->periodic_tx_time_off = cpu_to_le16(periodic_tx_time_off);
+       req->periodic_tx_time_on = cpu_to_le16(periodic_tx_time_on);
+
+       return cl_send_request(cl_hw, req);
+}
+
+int cl_msg_tx_anamon_read(struct cl_hw *cl_hw, u8 mode, u8 param1, u8 param2)
+{
+       struct mm_anamon_read_req *req;
+
+       req = cl_msg_zalloc(cl_hw, MM_ANAMON_READ_REQ, TASK_MM, sizeof(*req));
+       if (!req)
+               return -ENOMEM;
+
+       req->mode = mode;
+       req->param1 = param1;
+       req->param2 = param2;
+
+       return cl_send_request(cl_hw, req);
+}
+
+int cl_msg_tx_refresh_power(struct cl_hw *cl_hw)
+{
+       void *void_param;
+
+       /* MM_REFRESH_PWR_REQ has no parameter */
+       void_param = cl_msg_zalloc(cl_hw, MM_REFRESH_PWR_REQ, TASK_MM, 0);
+       if (!void_param)
+               return -ENOMEM;
+
+       return cl_send_request(cl_hw, void_param);
+}
+
+int cl_msg_tx_set_ant_pwr_offset(struct cl_hw *cl_hw, s8 pwr_offset[MAX_ANTENNAS])
+{
+       struct mm_set_ant_pwr_offset_req *req;
+       u8 i = 0;
+
+       req = cl_msg_zalloc(cl_hw, MM_SET_ANT_PWR_OFFSET_REQ, TASK_MM, sizeof(*req));
+       if (!req)
+               return -ENOMEM;
+
+       for (i = 0; i < ARRAY_SIZE(req->pwr_offset); i++) {
+               pwr_offset[i] = cl_power_offset_check_margin(cl_hw, cl_hw->bw, i, pwr_offset[i]);
+               req->pwr_offset[i] = cl_convert_signed_to_reg_value(pwr_offset[i]);
+       }
+
+       return cl_send_request(cl_hw, req);
+}
+
+int cl_msg_tx_set_rate_fallback(struct cl_hw *cl_hw)
+{
+       struct mm_rate_fallback_req *req;
+       u8 *fb_conf = cl_hw->conf->ci_rate_fallback;
+
+       req = cl_msg_zalloc(cl_hw, MM_SET_RATE_FALLBACK_REQ, TASK_MM, sizeof(*req));
+       if (!req)
+               return -ENOMEM;
+
+       req->fallback_count_su = fb_conf[CL_RATE_FALLBACK_COUNT_SU];
+       req->fallback_count_mu = fb_conf[CL_RATE_FALLBACK_COUNT_MU];
+       req->retry_count_thr = fb_conf[CL_RATE_FALLBACK_RETRY_COUNT_THR];
+       req->ba_per_thr = fb_conf[CL_RATE_FALLBACK_BA_PER_THR];
+       req->ba_not_received_thr = fb_conf[CL_RATE_FALLBACK_BA_NOT_RECEIVED_THR];
+       req->disable_mcs0 = fb_conf[CL_RATE_FALLBACK_DISABLE_MCS];
+
+       return cl_send_request(cl_hw, req);
+}
+
+int cl_msg_tx_twt_setup(struct cl_hw *cl_hw, struct mm_twt_setup_req *params)
+{
+       struct mm_twt_setup_req *req;
+
+       req = cl_msg_zalloc(cl_hw, MM_TWT_SETUP_REQ, TASK_MM, sizeof(*req));
+       if (!req)
+               return -ENOMEM;
+
+       req->sta_idx = params->sta_idx;
+       req->twt_flow_id = params->twt_flow_id;
+       req->announced = params->announced;
+       req->triggered = params->triggered;
+       req->min_wake_duration_us = cpu_to_le32(params->min_wake_duration_us);
+       req->twt_interval_us = cpu_to_le64(params->twt_interval_us);
+       req->twt_start_time_tsf = cpu_to_le64(params->twt_start_time_tsf);
+
+       cl_dbg_info(cl_hw,
+                   "sta_idx %u, flow_id %u, interval_us %llu, min_wake_duration_us %u,"
+                   "start_time %llu, announced %u, triggered %u\n",
+                   req->sta_idx, req->twt_flow_id, req->twt_interval_us,
+                   req->min_wake_duration_us, req->twt_start_time_tsf,
+                   req->announced, req->triggered);
+
+       return cl_send_request(cl_hw, req);
+}
+
+int cl_msg_tx_twt_teardown(struct cl_hw *cl_hw, struct mm_twt_teardown_req *params)
+{
+       struct mm_twt_teardown_req *req;
+
+       req = cl_msg_zalloc(cl_hw, MM_TWT_TEARDOWN_REQ, TASK_MM, sizeof(*req));
+       if (!req)
+               return -ENOMEM;
+
+       req->sta_idx = params->sta_idx;
+       req->twt_flow_id = params->twt_flow_id;
+
+       cl_dbg_info(cl_hw, "sta_idx %u, flow_id %u\n",
+                   req->sta_idx, req->twt_flow_id);
+
+       return cl_send_request(cl_hw, req);
+}
+
+int cl_msg_tx_rsrc_mgmt_traffic_event(struct cl_hw *cl_hw, u8 event_type,
+                                     enum cl_traffic_level level,
+                                     enum cl_traffic_direction direction,
+                                     u8 active_sta_cnt)
+{
+       struct mm_rsrc_mgmt_req *req = NULL;
+       struct cl_sta *cl_sta = NULL;
+       int curr_cnt = 0;
+       size_t size = sizeof(*req) + active_sta_cnt * sizeof(struct mm_rsrc_mgmt_active_sta);
+
+       req = cl_msg_zalloc(cl_hw, MM_RSRC_MGMT_REQ, TASK_MM, size);
+       if (!req)
+               return -ENOMEM;
+
+       req->subtype = event_type;
+       req->u.traffic_event.level = level;
+       req->u.traffic_event.direction = direction;
+
+       cl_sta_lock_bh(cl_hw);
+       list_for_each_entry(cl_sta, &cl_hw->cl_sta_db.head, list) {
+               struct cl_wrs_rate *max_rate_cap = &cl_sta->wrs_sta.max_rate_cap;
+               struct cl_wrs_tx_params *su_tx_params = &cl_sta->wrs_sta.su_params.tx_params;
+
+               if (!cl_sta->traffic_db[direction].activity_db[level].is_active)
+                       continue;
+
+               if (req->u.traffic_event.active_sta.cnt == active_sta_cnt) {
+                       WARN_ONCE(active_sta_cnt != 0,
+                                 "Synchronization failure between actual and "
+                                 "preallocated station entities!");
+                       break;
+               }
+
+               req->u.traffic_event.active_sta.list[curr_cnt] = (struct mm_rsrc_mgmt_active_sta) {
+                   .idx = cl_sta->sta_idx,
+                   .su_rate = {
+                       .bw = su_tx_params->bw,
+                       .nss = su_tx_params->nss,
+                       .mcs = su_tx_params->mcs
+                   },
+                   .max_rate = {
+                       .bw = max_rate_cap->bw,
+                       .nss = max_rate_cap->nss,
+                       .mcs = max_rate_cap->mcs
+                   },
+               };
+
+               curr_cnt++;
+       }
+       req->u.traffic_event.active_sta.cnt = curr_cnt;
+       cl_sta_unlock_bh(cl_hw);
+
+       return cl_send_request(cl_hw, req);
+}
+
+int cl_msg_tx_rsrc_mgmt_rates_event(struct cl_hw *cl_hw, u8 event_type,
+                                   struct cl_sta *cl_sta)
+{
+       struct mm_rsrc_mgmt_req *req = NULL;
+       struct cl_wrs_rate *max_rate_cap = &cl_sta->wrs_sta.max_rate_cap;
+       struct cl_wrs_tx_params *su_tx_params = &cl_sta->wrs_sta.su_params.tx_params;
+
+       req = cl_msg_zalloc(cl_hw, MM_RSRC_MGMT_REQ, TASK_MM, sizeof(*req));
+       if (!req)
+               return -ENOMEM;
+
+       req->subtype = event_type;
+       req->u.rate_event.sta = (struct mm_rsrc_mgmt_active_sta) {
+           .idx = cl_sta->sta_idx,
+           .su_rate = {
+               .bw = su_tx_params->bw,
+               .nss = su_tx_params->nss,
+               .mcs = su_tx_params->mcs
+           },
+           .max_rate = {
+               .bw = max_rate_cap->bw,
+               .nss = max_rate_cap->nss,
+               .mcs = max_rate_cap->mcs
+           },
+       };
+
+       return cl_send_request(cl_hw, req);
+}
+
+int cl_msg_tx_set_freq_offset(struct cl_hw *cl_hw, u16 val)
+{
+       struct mm_set_freq_offset_req *req;
+
+       /* Build the MM_SET_FREQ_OFFSET_REQ message */
+       req = cl_msg_zalloc(cl_hw, MM_SET_FREQ_OFFSET_REQ, TASK_MM,
+                           sizeof(struct mm_set_freq_offset_req));
+
+       if (!req)
+               return -ENOMEM;
+
+       /* Set parameters for the MM_SET_FREQ_OFFSET_REQ message */
+       req->val = cpu_to_le16(val);
+
+       /* Send the MM_SET_FREQ_OFFSET_REQ message to firmware */
+       return cl_send_request(cl_hw, req);
+}
+
+int cl_msg_tx_dbg_set_mod_filter(struct cl_hw *cl_hw, u32 filter)
+{
+       struct dbg_set_mod_filter_req *req;
+
+       req = cl_msg_zalloc(cl_hw, DBG_SET_MOD_FILTER_REQ, TASK_DBG, sizeof(*req));
+       if (!req)
+               return -ENOMEM;
+
+       req->mod_filter = cpu_to_le32(filter);
+
+       return cl_send_request(cl_hw, req);
+}
+
+int cl_msg_tx_dbg_set_ce_mod_filter(struct cl_hw *cl_hw, u32 filter)
+{
+       struct dbg_set_mod_filter_req *req;
+
+       req = cl_msg_zalloc(cl_hw, DBG_CE_SET_MOD_FILTER_REQ, TASK_DBG, sizeof(*req));
+       if (!req)
+               return -ENOMEM;
+
+       req->mod_filter = cpu_to_le32(filter);
+
+       return cl_send_request(cl_hw, req);
+}
+
+int cl_msg_tx_dbg_set_sev_filter(struct cl_hw *cl_hw, u32 filter)
+{
+       struct dbg_set_sev_filter_req *req;
+
+       req = cl_msg_zalloc(cl_hw, DBG_SET_SEV_FILTER_REQ, TASK_DBG, sizeof(*req));
+       if (!req)
+               return -ENOMEM;
+
+       req->sev_filter = cpu_to_le32(filter);
+
+       return cl_send_request(cl_hw, req);
+}
+
+int cl_msg_tx_dbg_beamforming_tx(struct cl_hw *cl_hw, u32 param32)
+{
+       struct dbg_beamforming_tx_req *req;
+
+       req = cl_msg_zalloc(cl_hw, DBG_BEAMFORMING_TX_REQ, TASK_DBG, sizeof(*req));
+       if (!req)
+               return -ENOMEM;
+
+       req->bf_cmd = cpu_to_le32(param32);
+
+       return cl_send_request(cl_hw, req);
+}
+
+int cl_msg_tx_dbg_get_e2w_stats(struct cl_hw *cl_hw, bool clear)
+{
+       struct dbg_e2w_stats_req *req;
+
+       req = cl_msg_zalloc(cl_hw, DBG_GET_E2W_STATS_REQ, TASK_DBG, sizeof(*req));
+       if (!req)
+               return -ENOMEM;
+
+       req->clear = cpu_to_le32(clear);
+
+       return cl_send_request(cl_hw, req);
+}
+
+int cl_msg_tx_dbg_set_la_mpif_mask(struct cl_hw *cl_hw, u32 mask)
+{
+       struct dbg_set_la_mpif_mask_req *req;
+
+       req = cl_msg_zalloc(cl_hw, DBG_SET_LA_MPIF_MASK_REQ, TASK_DBG, sizeof(*req));
+       if (!req)
+               return -ENOMEM;
+
+       req->mpif_mask = cpu_to_le32(mask);
+
+       return cl_send_request(cl_hw, req);
+}
+
+int cl_msg_tx_dbg_set_la_trig_point(struct cl_hw *cl_hw, u32 trigger_point)
+{
+       struct dbg_set_la_trig_point_req *req;
+
+       req = cl_msg_zalloc(cl_hw, DBG_SET_LA_TRIG_POINT_REQ, TASK_DBG, sizeof(*req));
+       if (!req)
+               return -ENOMEM;
+
+       req->trigger_point = cpu_to_le32(trigger_point);
+
+       return cl_send_request(cl_hw, req);
+}
+
+int cl_msg_tx_dbg_set_la_mpif_debug_mode(struct cl_hw *cl_hw, u8 mode)
+{
+       struct dbg_set_la_mpif_debug_mode_req *req;
+
+       req = cl_msg_zalloc(cl_hw, DBG_SET_LA_MPIF_DEBUG_MODE_REQ, TASK_DBG,
+                           sizeof(*req));
+       if (!req)
+               return -ENOMEM;
+
+       req->mode = mode;
+
+       return cl_send_request(cl_hw, req);
+}
+
+int cl_msg_tx_dbg_set_la_trig_rule(struct cl_hw *cl_hw, u8 idx, bool enable, u32 address,
+                                  u8 oper, u32 value, u32 mask, u32 duration)
+{
+       struct dbg_set_la_trig_rule_req *req;
+
+       req = cl_msg_zalloc(cl_hw, DBG_SET_LA_TRIG_RULE_REQ, TASK_DBG, sizeof(*req));
+       if (!req)
+               return -ENOMEM;
+
+       req->rule_id = idx;
+       req->oper = oper;
+       req->enable = enable;
+       req->address = cpu_to_le32(address);
+       req->value = cpu_to_le32(value);
+       req->mask = cpu_to_le32(mask);
+       req->duration = cpu_to_le32(duration);
+
+       return cl_send_request(cl_hw, req);
+}
+
+int cl_msg_tx_dbg_tx_trace_debug_flag(struct cl_hw *cl_hw, u32 bitmap, u8 w_r_cmd)
+{
+       struct dbg_tx_trace_debug_flag_req *req;
+
+       req = cl_msg_zalloc(cl_hw, DBG_TX_TRACE_DEBUG_FLAG_REQ, TASK_DBG, sizeof(*req));
+       if (!req)
+               return -ENOMEM;
+
+       req->read_write_flag = w_r_cmd;
+       req->bitmap = cpu_to_le32(bitmap);
+
+       return cl_send_request(cl_hw, req);
+}
+
+int cl_msg_tx_dbg_print_stats(struct cl_hw *cl_hw, u32 command,
+                             u32 param0, u32 param1, u32 param2, u32 param3)
+{
+       struct dbg_print_stats_req *req;
+
+       req = cl_msg_zalloc(cl_hw, DBG_PRINT_STATS_REQ, TASK_DBG, sizeof(*req));
+       if (!req)
+               return -ENOMEM;
+
+       req->command = cpu_to_le32(command);
+       req->param[0] = cpu_to_le32(param0);
+       req->param[1] = cpu_to_le32(param1);
+       req->param[2] = cpu_to_le32(param2);
+       req->param[3] = cpu_to_le32(param3);
+
+       cl_dbg_verbose(cl_hw, "param0 = 0x%x, param1 = 0x%x, param2 = 0x%x, param3 = 0x%x\n",
+                      req->param[0], req->param[1], req->param[2], req->param[3]);
+
+       return cl_send_request(cl_hw, req);
+}
+
+int cl_msg_tx_dbg_trigger(struct cl_hw *cl_hw, char *msg)
+{
+       struct dbg_trigger_req *req;
+       u8 msg_len = min(strlen(msg), sizeof(req->error) - 1);
+
+       req = cl_msg_zalloc(cl_hw, DBG_TRIGGER_REQ, TASK_DBG, sizeof(*req));
+       if (!req)
+               return -ENOMEM;
+
+       strncpy(req->error, msg, msg_len);
+
+       return cl_send_request(cl_hw, req);
+}
+
+int cl_msg_tx_dbg_test_mode(struct cl_hw *cl_hw, u32 *params)
+{
+       struct dbg_test_mode_req *req;
+       int i = 0;
+
+       req = cl_msg_zalloc(cl_hw, DBG_TEST_MODE_REQ, TASK_DBG, sizeof(*req));
+       if (!req)
+               return -ENOMEM;
+
+       req->command = cpu_to_le32(params[0]);
+
+       /* Param[0] is the command, therefore start from param[i + 1] */
+       for (i = 0; i < ARRAY_SIZE(req->params); i++)
+               req->params[i] = cpu_to_le32(params[i + 1]);
+
+       return cl_send_request(cl_hw, req);
+}
+
+int cl_msg_tx_dbg_sounding_cmd(struct cl_hw *cl_hw, struct dbg_sounding_cmd_param *params)
+{
+       struct dbg_sounding_cmd_param *req;
+       int i;
+
+       req = cl_msg_zalloc(cl_hw, DBG_SOUNDING_CMD_REQ, TASK_DBG, sizeof(*req));
+       if (!req)
+               return -ENOMEM;
+
+       memcpy(req, params, sizeof(struct dbg_sounding_cmd_param));
+       req->sounding_cmd_index = cpu_to_le32(params->sounding_cmd_index);
+
+       for (i = 0; i < ARRAY_SIZE(req->param); i++)
+               req->param[i] = cpu_to_le32(params->param[i]);
+
+       return cl_send_request(cl_hw, 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.
________________________________


^ permalink raw reply related	[flat|nested] 262+ messages in thread

* [RFC v1 097/256] cl8k: add fw/msg_tx.h
  2021-06-17 15:58 [RFC v1 000/256] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (95 preceding siblings ...)
  2021-06-17 15:59 ` [RFC v1 096/256] cl8k: add fw/msg_tx.c viktor.barna
@ 2021-06-17 15:59 ` viktor.barna
  2021-06-17 15:59 ` [RFC v1 098/256] cl8k: add hw.c viktor.barna
                   ` (160 subsequent siblings)
  257 siblings, 0 replies; 262+ messages in thread
From: viktor.barna @ 2021-06-17 15:59 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Oleksandr Savchenko, Shay Bar, Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

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

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 drivers/net/wireless/celeno/cl8k/fw/msg_tx.h | 141 +++++++++++++++++++
 1 file changed, 141 insertions(+)
 create mode 100644 drivers/net/wireless/celeno/cl8k/fw/msg_tx.h

diff --git a/drivers/net/wireless/celeno/cl8k/fw/msg_tx.h b/drivers/net/wireless/celeno/cl8k/fw/msg_tx.h
new file mode 100644
index 000000000000..c82ccc1752aa
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/fw/msg_tx.h
@@ -0,0 +1,141 @@
+/* SPDX-License-Identifier: MIT */
+/* Copyright(c) 2019-2021, Celeno Communications Ltd. */
+
+#ifndef CL_MSG_TX_H
+#define CL_MSG_TX_H
+
+#include "hw.h"
+#include "vif.h"
+
+#define FREQUENCY_INT_MASK 0xfffc
+#define FREQUENCY_FRAC_MASK 0x0003
+#define FREQUENCY_COMP_INT_MASK ~FREQUENCY_FRAC_MASK
+#define FREQUENCY_INT_SHIFT 2
+#define FREQUENCY_FRAC_RESOLUTION 25
+
+#define GET_FREQ_INT(freq) (((freq) & FREQUENCY_INT_MASK) >> FREQUENCY_INT_SHIFT)
+#define GET_FREQ_FRAC(freq) (((freq) & FREQUENCY_FRAC_MASK) * FREQUENCY_FRAC_RESOLUTION)
+#define GET_FREQ_COMP_INT(freq) ((abs(freq) & FREQUENCY_COMP_INT_MASK) >> FREQUENCY_INT_SHIFT)
+#define GET_FREQ_COMP_FRAC(freq) ((abs(freq) & FREQUENCY_FRAC_MASK) * FREQUENCY_FRAC_RESOLUTION)
+#define GET_FREQ_SIGN(freq) (((freq) > 0) ? "" : "-")
+
+enum ke_kern_tag {
+       KERN_HOST,
+       KERN_LMAC,
+       KERN_UMAC,
+       KERN_SMAC,
+
+       KERN_MAX,
+};
+
+#define SET_CHANNEL_MODE_OPERETIONAL  0x01
+#define SET_CHANNEL_MODE_CALIB_DCOC   0x02
+#define SET_CHANNEL_MODE_CALIB_IQ     0x04
+#define SET_CHANNEL_MODE_CALIB_LOLC   0x08
+#define SET_CHANNEL_MODE_CALIB        (SET_CHANNEL_MODE_CALIB_DCOC | \
+                                      SET_CHANNEL_MODE_CALIB_IQ | \
+                                      SET_CHANNEL_MODE_CALIB_LOLC)
+
+/*
+ * confirmation call back params
+ * @err: general msg transmitting error
+ * @param: pointer to lower layer feedback param (FW layer)
+ */
+struct cl_msg_cfm_cb_param {
+       int err;
+       void *param; /* Pointer to msg cfm param, the caller should be aware to that type */
+};
+
+/*
+ * call back function definition, associate with all backgrounf triggered messages
+ * if caller intersting in message done feedback it must declare function of this type!
+ */
+typedef void (*cl_msg_cfm_cb_func)(struct cl_msg_cfm_cb_param *p_cfm_cb_param, u32 token);
+
+void cl_msg_tx_free_cfm_params(struct cl_hw *cl_hw, u16 id);
+
+int cl_msg_tx_reset(struct cl_hw *cl_hw);
+int cl_msg_tx_start(struct cl_hw *cl_hw);
+int cl_msg_tx_version(struct cl_hw *cl_hw);
+int cl_msg_tx_add_if(struct cl_hw *cl_hw, struct ieee80211_vif *vif, u8 vif_index);
+int cl_msg_tx_remove_if(struct cl_hw *cl_hw, u8 vif_index);
+int cl_msg_tx_sta_add(struct cl_hw *cl_hw, struct ieee80211_sta *sta, struct cl_vif *cl_vif,
+                     u8 recovery_sta_idx, u32 rate_ctrl_info);
+int cl_msg_tx_sta_del(struct cl_hw *cl_hw, u8 sta_idx);
+int cl_msg_tx_set_filter(struct cl_hw *cl_hw, u32 filter, bool force);
+int cl_msg_tx_set_channel(struct cl_hw *cl_hw, u32 channel, u8 bw, u32 primary, u32 center);
+int _cl_msg_tx_set_channel(struct cl_hw *cl_hw, u32 channel, u8 bw, u32 primary,
+                          u32 center, u8 mode);
+int cl_msg_tx_dtim(struct cl_hw *cl_hw, u8 dtim_period);
+int cl_msg_tx_set_beacon_int(struct cl_hw *cl_hw, u16 beacon_int, u8 vif_idx);
+int cl_msg_tx_set_basic_rates(struct cl_hw *cl_hw, u32 basic_rates);
+int cl_msg_tx_set_bssid(struct cl_hw *cl_hw, const u8 *bssid, u8 vif_idx);
+int cl_msg_tx_set_edca(struct cl_hw *cl_hw, u8 hw_queue, u32 param,
+                      struct ieee80211_he_mu_edca_param_ac_rec *mu_edca);
+int cl_msg_tx_set_associated(struct cl_hw *cl_hw,
+                            struct ieee80211_bss_conf *bss_conf);
+int cl_msg_tx_set_slottime(struct cl_hw *cl_hw, bool use_short_slot);
+int cl_msg_tx_set_idle(struct cl_hw *cl_hw, u8 idle);
+void cl_msg_tx_idle_async(struct cl_hw *cl_hw);
+int cl_msg_tx_key_add(struct cl_hw *cl_hw, struct ieee80211_vif *vif, struct ieee80211_sta *sta,
+                     struct ieee80211_key_conf *key_conf, u8 cipher_suite);
+int cl_msg_tx_key_del(struct cl_hw *cl_hw, u8 hw_key_idx);
+int cl_msg_tx_ba_add(struct cl_hw *cl_hw, u8 type, u8 sta_idx, u16 tid, u16 bufsz, u16 ssn);
+int cl_msg_tx_ba_del(struct cl_hw *cl_hw, u8 sta_idx, u16 tid);
+int cl_msg_tx_phy_reset(struct cl_hw *cl_hw);
+int cl_msg_tx_available_ba_txq(struct cl_hw *cl_hw, u8 sta_idx, u16 tid);
+int cl_msg_tx_update_rate_dl(struct cl_hw *cl_hw, u8 sta_idx, u32 rate, u32 rate_fallback,
+                            u8 req_bw_tx, u8 op_mode, u8 ltf, u8 ltf_fallback, u32 rate_he);
+int cl_msg_tx_set_vns(struct cl_hw *cl_hw, u8 sta_idx, u8 is_vns);
+int cl_msg_tx_set_tx_bf(struct cl_hw *cl_hw, u8 sta_idx, u8 is_on, u8 is_on_fallback);
+int cl_msg_tx_sounding(struct cl_hw *cl_hw,
+                      struct mm_sounding_req *sounding_req);
+int cl_msg_tx_sounding_pairing(struct cl_hw *cl_hw, u8 sounding_id, u8 sounding_type,
+                              u8 gid, u8 sta_idx);
+int cl_msg_tx_sounding_interval(struct cl_hw *cl_hw, u16 interval, u16 lifetime,
+                               u8 sounding_type, u8 sta_idx);
+int cl_msg_tx_config_cca(struct cl_hw *cl_hw, bool enable);
+int cl_msg_tx_set_dfs(struct cl_hw *cl_hw, bool enable, u8 standard,
+                     u8 initial_gain, u8 agc_cd_th);
+int cl_msg_tx_set_ant_bitmap(struct cl_hw *cl_hw, u8 bitmap);
+int cl_msg_tx_ndp_tx_control(struct cl_hw *cl_hw, u8 chain_mask, u8 bw, u8 format, u8 num_ltf);
+int cl_msg_tx_reg_write(struct cl_hw *cl_hw, u32 address, u32 value, u32 mask);
+int cl_msg_tx_prot_mode(struct cl_hw *cl_hw, u8 log_nav_en, u8 mode,
+                       u8 rate_format, u8 rate_mcs, u8 rate_pre_type);
+int cl_msg_tx_goto_power_reduction(struct cl_hw *cl_hw, u8 mode);
+int cl_msg_tx_backup_bcn_en(struct cl_hw *cl_hw, bool backup_bcn_en);
+int cl_msg_tx_start_periodic_tx_time(struct cl_hw *cl_hw, u16 periodic_tx_time_off,
+                                    u16 periodic_tx_time_on);
+int cl_msg_tx_anamon_read(struct cl_hw *cl_hw, u8 mode, u8 param1, u8 param2);
+int cl_msg_tx_refresh_power(struct cl_hw *cl_hw);
+int cl_msg_tx_set_ant_pwr_offset(struct cl_hw *cl_hw, s8 pwr_offset[MAX_ANTENNAS]);
+int cl_msg_tx_set_rate_fallback(struct cl_hw *cl_hw);
+int cl_msg_tx_twt_setup(struct cl_hw *cl_hw, struct mm_twt_setup_req *params);
+int cl_msg_tx_twt_teardown(struct cl_hw *cl_hw, struct mm_twt_teardown_req *params);
+int cl_msg_tx_rsrc_mgmt_traffic_event(struct cl_hw *cl_hw, u8 event_type,
+                                     enum cl_traffic_level level,
+                                     enum cl_traffic_direction direction,
+                                     u8 active_sta_cnt);
+int cl_msg_tx_rsrc_mgmt_rates_event(struct cl_hw *cl_hw, u8 event_type,
+                                   struct cl_sta *cl_sta);
+int cl_msg_tx_set_freq_offset(struct cl_hw *cl_hw, u16 val);
+
+/* Debug messages */
+int cl_msg_tx_dbg_set_mod_filter(struct cl_hw *cl_hw, u32 filter);
+int cl_msg_tx_dbg_set_ce_mod_filter(struct cl_hw *cl_hw, u32 filter);
+int cl_msg_tx_dbg_set_sev_filter(struct cl_hw *cl_hw, u32 filter);
+int cl_msg_tx_dbg_beamforming_tx(struct cl_hw *cl_hw, u32 param32);
+int cl_msg_tx_dbg_get_e2w_stats(struct cl_hw *cl_hw, bool clear);
+int cl_msg_tx_dbg_set_la_mpif_mask(struct cl_hw *cl_hw, u32 mask);
+int cl_msg_tx_dbg_set_la_trig_point(struct cl_hw *cl_hw, u32 trigger_point);
+int cl_msg_tx_dbg_set_la_mpif_debug_mode(struct cl_hw *cl_hw, u8 mode);
+int cl_msg_tx_dbg_set_la_trig_rule(struct cl_hw *cl_hw, u8 idx, bool enable, u32 address,
+                                  u8 oper, u32 value, u32 mask, u32 duration);
+int cl_msg_tx_dbg_tx_trace_debug_flag(struct cl_hw *cl_hw, u32 bitmap, u8 w_r_cmd);
+int cl_msg_tx_dbg_print_stats(struct cl_hw *cl_hw, u32 command,
+                             u32 param0, u32 param1, u32 param2, u32 param3);
+int cl_msg_tx_dbg_trigger(struct cl_hw *cl_hw, char *msg);
+int cl_msg_tx_dbg_test_mode(struct cl_hw *cl_hw, u32 *params);
+int cl_msg_tx_dbg_sounding_cmd(struct cl_hw *cl_hw, struct dbg_sounding_cmd_param *params);
+
+#endif /* CL_MSG_TX_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.
________________________________


^ permalink raw reply related	[flat|nested] 262+ messages in thread

* [RFC v1 098/256] cl8k: add hw.c
  2021-06-17 15:58 [RFC v1 000/256] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (96 preceding siblings ...)
  2021-06-17 15:59 ` [RFC v1 097/256] cl8k: add fw/msg_tx.h viktor.barna
@ 2021-06-17 15:59 ` viktor.barna
  2021-06-17 15:59 ` [RFC v1 099/256] cl8k: add hw.h viktor.barna
                   ` (159 subsequent siblings)
  257 siblings, 0 replies; 262+ messages in thread
From: viktor.barna @ 2021-06-17 15:59 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Oleksandr Savchenko, Shay Bar, Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

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

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 drivers/net/wireless/celeno/cl8k/hw.c | 166 ++++++++++++++++++++++++++
 1 file changed, 166 insertions(+)
 create mode 100644 drivers/net/wireless/celeno/cl8k/hw.c

diff --git a/drivers/net/wireless/celeno/cl8k/hw.c b/drivers/net/wireless/celeno/cl8k/hw.c
new file mode 100644
index 000000000000..0f7e7dcc659d
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/hw.c
@@ -0,0 +1,166 @@
+// SPDX-License-Identifier: MIT
+/* Copyright(c) 2019-2021, Celeno Communications Ltd. */
+
+#include "hw.h"
+#include "rate_ctrl.h"
+#include <linux/spinlock.h>
+#include "reg/reg_access.h"
+
+static void cl_hw_init_tcv0(struct cl_hw *cl_hw)
+{
+       struct cl_controller_reg *controller_reg = &cl_hw->controller_reg;
+
+       cl_hw->fw_dst_kern_id = KERN_LMAC;
+       cl_hw->fw_prefix = 'l';
+
+       controller_reg->breset = LMAC_BRESET;
+       controller_reg->debug_enable = LMAC_DEBUG_ENABLE;
+       controller_reg->dreset = LMAC_DRESET;
+       controller_reg->ocd_halt_on_reset = LMAC_OCD_HALT_ON_RESET;
+       controller_reg->run_stall = LMAC_RUN_STALL;
+
+       cl_hw->mac_hw_regs_offset = 0;
+       cl_hw->phy_regs_offset = 0;
+}
+
+static void cl_hw_init_tcv1(struct cl_hw *cl_hw)
+{
+       struct cl_controller_reg *controller_reg = &cl_hw->controller_reg;
+
+       cl_hw->fw_dst_kern_id = KERN_SMAC;
+       cl_hw->fw_prefix = 's';
+
+       controller_reg->breset = SMAC_BRESET;
+       controller_reg->debug_enable = SMAC_DEBUG_ENABLE;
+       controller_reg->dreset = SMAC_DRESET;
+       controller_reg->ocd_halt_on_reset = SMAC_OCD_HALT_ON_RESET;
+       controller_reg->run_stall = SMAC_RUN_STALL;
+
+       cl_hw->mac_hw_regs_offset = REG_MAC_HW_SMAC_OFFSET;
+       cl_hw->phy_regs_offset = REG_PHY_SMAC_OFFSET;
+}
+
+void cl_hw_init(struct cl_chip *chip, struct cl_hw *cl_hw, u8 tcv_idx)
+{
+       write_lock(&chip->cl_hw_lock);
+       chip->cl_hw_lut[tcv_idx] = cl_hw;
+       write_unlock(&chip->cl_hw_lock);
+
+       if (tcv_idx == TCV0)
+               cl_hw_init_tcv0(cl_hw);
+       else
+               cl_hw_init_tcv1(cl_hw);
+}
+
+void cl_hw_deinit(struct cl_hw *cl_hw, u8 tcv_idx)
+{
+       struct cl_chip *chip = cl_hw->chip;
+
+       write_lock(&chip->cl_hw_lock);
+       chip->cl_hw_lut[tcv_idx] = NULL;
+       write_unlock(&chip->cl_hw_lock);
+}
+
+void cl_hw_lock(struct cl_hw *cl_hw)
+{
+       read_lock(&cl_hw->chip->cl_hw_lock);
+}
+
+void cl_hw_unlock(struct cl_hw *cl_hw)
+{
+       read_unlock(&cl_hw->chip->cl_hw_lock);
+}
+
+struct cl_hw *cl_hw_other_tcv(struct cl_hw *cl_hw)
+{
+       /* This function must be called after read lock is taken */
+       return cl_hw->chip->cl_hw_lut[1 - cl_hw->tcv_idx];
+}
+
+bool cl_hw_is_tcv0(struct cl_hw *cl_hw)
+{
+       return (cl_hw->tcv_idx == TCV0);
+}
+
+bool cl_hw_is_tcv1(struct cl_hw *cl_hw)
+{
+       return (cl_hw->tcv_idx == TCV1);
+}
+
+int cl_hw_set_antennas(struct cl_hw *cl_hw)
+{
+       struct cl_chip *chip = cl_hw->chip;
+       u8 ant_shift = cl_hw_ant_shift(cl_hw);
+
+       /* Set num_antennas and max_antennas + masks for both. */
+       switch (chip->fem.wiring_id) {
+       case FEM_WIRING_0_TCV0_6_TCV1_6:
+       case FEM_WIRING_1_TCV0_6_TCV1_6:
+       case FEM_WIRING_2_TCV0_6_TCV1_6:
+       case FEM_WIRING_3_TCV0_2_ELASTIC_4_TCV1_2:
+       case FEM_WIRING_4_TCV0_2_ELASTIC_4_TCV1_2:
+       case FEM_WIRING_5_TCV0_2_ELASTIC_4_TCV1_2:
+       case FEM_WIRING_6_TCV0_2_ELASTIC_4_TCV1_2:
+               cl_hw->max_antennas = 6;
+               break;
+       case FEM_WIRING_7_TCV0_4_TCV1_4:
+       case FEM_WIRING_8_TCV0_4_TCV1_4:
+       case FEM_WIRING_9_TCV0_4_TCV1_4:
+       case FEM_WIRING_10_TCV0_4_TCV1_4:
+       case FEM_WIRING_11_TCV0_4_TCV1_4_RX_ONLY:
+       case FEM_WIRING_12_TCV0_4_TCV1_4_RX_ONLY:
+       case FEM_WIRING_15_CHAMELEON_4TX_4RX:
+       case FEM_WIRING_18_TCV0_4_TCV1_4:
+       case FEM_WIRING_19_TCV0_2_TCV1_2_SWAPPED:
+               cl_hw->max_antennas = 4;
+               break;
+       case FEM_WIRING_13_SENSING_4RX_2TX:
+       case FEM_WIRING_14_SENSING_4TX_2RX:
+       case FEM_WIRING_20_TCV0_4_TCV1_2:
+       case FEM_WIRING_21_TCV0_4_TCV1_2:
+               cl_hw->max_antennas = cl_hw_is_tcv0(cl_hw) ? 4 : 2;
+               break;
+       case FEM_WIRING_17_TCV0_4_TCV1_0:
+               cl_hw->max_antennas = cl_hw_is_tcv0(cl_hw) ? 4 : 0;
+               break;
+       case FEM_WIRING_16_TCV0_2_TCV1_2:
+               cl_hw->max_antennas = 2;
+               break;
+       default:
+               if (chip->conf->ce_production_mode)
+                       cl_hw->max_antennas = chip->max_antennas / 2;
+               else
+                       return -1;
+               break;
+       }
+
+       cl_hw->num_antennas = cl_hw->conf->ce_num_antennas;
+       cl_hw->mask_num_antennas = ANT_MASK(cl_hw->num_antennas);
+       cl_hw->first_ant = ant_shift;
+       cl_hw->last_ant = cl_hw->num_antennas + ant_shift - 1;
+
+       cl_dbg_trace(cl_hw, "num_antennas = %u, max_antennas = %u\n",
+                    cl_hw->num_antennas, cl_hw->max_antennas);
+
+       if (cl_hw->num_antennas > cl_hw->max_antennas) {
+               CL_DBG_ERROR(cl_hw, "num_antennas (%u) > max_antennas (%u)\n",
+                            cl_hw->num_antennas, cl_hw->max_antennas);
+               return -1;
+       }
+
+       return 0;
+}
+
+u8 cl_hw_ant_shift(struct cl_hw *cl_hw)
+{
+       struct cl_chip *chip = cl_hw->chip;
+
+       /* CL808x uses chains 0 - 3 for both bands */
+       if (cl_chip_is_8ant(chip))
+               return 0;
+
+       /* CL804x uses chains 0 - 1 for TCV0 and chains 2 - 3 for TCV1 */
+       /* CL806x uses chains 0 - 3 for TCV0 and chains 2 - 3 for TCV1 */
+       return cl_hw_is_tcv0(cl_hw) ? 0 : 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.
________________________________


^ permalink raw reply related	[flat|nested] 262+ messages in thread

* [RFC v1 099/256] cl8k: add hw.h
  2021-06-17 15:58 [RFC v1 000/256] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (97 preceding siblings ...)
  2021-06-17 15:59 ` [RFC v1 098/256] cl8k: add hw.c viktor.barna
@ 2021-06-17 15:59 ` viktor.barna
  2021-06-17 15:59 ` [RFC v1 100/256] cl8k: add hw_assert.c viktor.barna
                   ` (158 subsequent siblings)
  257 siblings, 0 replies; 262+ messages in thread
From: viktor.barna @ 2021-06-17 15:59 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Oleksandr Savchenko, Shay Bar, Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

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

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 drivers/net/wireless/celeno/cl8k/hw.h | 797 ++++++++++++++++++++++++++
 1 file changed, 797 insertions(+)
 create mode 100644 drivers/net/wireless/celeno/cl8k/hw.h

diff --git a/drivers/net/wireless/celeno/cl8k/hw.h b/drivers/net/wireless/celeno/cl8k/hw.h
new file mode 100644
index 000000000000..17f8f14b9891
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/hw.h
@@ -0,0 +1,797 @@
+/* SPDX-License-Identifier: MIT */
+/* Copyright(c) 2019-2021, Celeno Communications Ltd. */
+
+#ifndef CL_HW_H
+#define CL_HW_H
+
+#include "wrs/wrs_db.h"
+#include "traffic.h"
+#include "edca.h"
+#include "env_det.h"
+#include "temperature.h"
+#include "dfs/dfs_db.h"
+#include "chan_info.h"
+#include "calib.h"
+#include "debugfs_defs.h"
+#include "ipc_shared.h"
+#include "fw/fw_msg.h"
+#include "dfs/radar.h"
+#include "rate_ctrl.h"
+#include "power_table.h"
+#include "cca.h"
+#include "def.h"
+#include "noise.h"
+#include "mac80211.h"
+#include "tcv_config.h"
+#include "sounding.h"
+#include "rsrc_mgmt.h"
+#include "channel.h"
+#include <linux/workqueue.h>
+#include <linux/module.h>
+
+/* Max flags for driver status description is defined as 32 * MAX_CFM_FLAGS */
+#define MAX_CFM_FLAGS 2
+
+enum cl_radio_stats {
+       CL_RADIO_FCS_ERROR = 0,
+       CL_RADIO_PHY_ERROR,
+       CL_RADIO_RX_FIFO_OVERFLOW,
+       CL_RADIO_ADDRESS_MISMATCH,
+       CL_RADIO_UNDEFINED_ERROR,
+       CL_RADIO_ERRORS_MAX
+};
+
+struct cl_rx_path_info {
+       u32 rx_desc[CL_RX_BUF_MAX];
+       u32 elem_alloc_fail;
+       u32 skb_null;
+       u32 pkt_drop_amsdu_corrupted;
+       u32 pkt_drop_sub_amsdu_corrupted;
+       u32 pkt_drop_amsdu_len_error;
+       u32 pkt_drop_sub_amsdu_len_error;
+       u32 pkt_drop_wrong_pattern;
+       u32 pkt_drop_not_success;
+       u32 pkt_drop_unencrypted;
+       u32 pkt_drop_decrypt_fail;
+       u32 pkt_drop_rxhdr_len_error;
+       u32 pkt_drop_sta_null;
+       u32 pkt_drop_host_limit;
+       u32 netif_rx;
+       u32 remote_cpu[CPU_MAX_NUM];
+       u32 exceed_pkt_budget;
+       u32 pkt_handle_bucket_rxm[IPC_RXBUF_NUM_BUCKETS_RXM];
+       u32 pkt_handle_bucket_fw[IPC_RXBUF_NUM_BUCKETS_FW];
+       u32 amsdu_cnt[RX_MAX_MSDU_IN_AMSDU];
+       u32 non_amsdu;
+       u32 buffer_process_irq;
+       u32 buffer_process_tasklet;
+};
+
+/* Structure used to store information regarding E2A msg buffers in the driver */
+struct cl_e2a_msg_elem {
+       struct cl_ipc_e2a_msg *msgbuf_ptr;
+       dma_addr_t dma_addr;
+};
+
+/* Structure used to store information regarding Debug msg buffers in the driver */
+struct cl_dbg_elem {
+       struct cl_ipc_dbg_msg *dbgbuf_ptr;
+       dma_addr_t dma_addr;
+};
+
+struct cl_tx_power_info {
+       s8 power;
+       s8 offset;
+       s8 temperature;
+};
+
+struct cl_rx_elem {
+       int passed;
+       struct sk_buff *skb;
+       dma_addr_t dma_addr;
+};
+
+struct cl_dbg_info {
+       struct mutex mutex;
+       struct dbg_info *buf;
+       dma_addr_t dma_addr;
+       int bufsz;
+       struct timespec64 trigger_tstamp;
+};
+
+struct cl_dbg_data {
+       char *str; /* Pointer to debug strings start address */
+       int size; /* Size of debug strings pool */
+};
+
+struct cl_phy_data_info {
+       struct cl_phy_data *data;
+       u32 dma_addr;
+};
+
+struct cl_sec_phy_chan {
+       u16 prim20_freq;
+       u16 center_freq1;
+       u16 center_freq2;
+       enum nl80211_band band;
+       u8 type;
+};
+
+struct cl_amsdu_rx_state {
+       u8 msdu_cnt;
+       u8 msdu_remaining_cnt;
+       /*
+        * MSDU padding - all MSDU pkt within A-MSDU are 4byte aligned (this
+        * value holds the alignment value)
+        * According to ieee80211 spec all MSDU share the same alignment
+        */
+       u8 msdu_dma_align;
+       u8 amsdu_error;
+       u8 encrypt_len;
+       u8 sta_idx;
+       u8 tid;
+       u32 packet_len;
+       struct hw_rxhdr *rxhdr;
+       struct sk_buff *first_skb;
+       struct sk_buff_head frames;
+};
+
+struct cl_tx_queue {
+       struct list_head sched_list;
+       struct list_head hdrs;
+       struct cl_sta *cl_sta;
+       bool sched;
+       u16 fw_free_space;
+       u16 fw_max_size;
+       u8 type;
+       u8 tid;
+       u8 hw_index;
+       u16 index;
+       u16 max_packets;
+       u16 num_packets;
+       u32 total_packets;
+       u32 total_fw_push_desc;
+       u32 total_fw_push_skb;
+       u32 total_fw_cfm;
+       u32 dump_queue_full;
+       u32 dump_dma_map_fail;
+       u32 stats_hw_amsdu_cnt[CL_AMSDU_TX_PAYLOAD_MAX];
+       u32 stats_sw_amsdu_cnt[MAX_TX_SW_AMSDU_PACKET];
+};
+
+struct cl_req_agg_db {
+       bool is_used;
+       u8 sta_idx;
+       u8 tid;
+};
+
+/*
+ * struct cl_tx_queues:
+ * This structure holds all driver TX queues,
+ * The queues buffer frames pushed by upper layer and push them to lower IPC layer.
+ */
+struct cl_tx_queues {
+       struct cl_tx_queue agg[IPC_MAX_BA_SESSIONS];
+       struct cl_tx_queue single[MAX_SINGLE_QUEUES];
+       struct cl_tx_queue bcmc;
+};
+
+struct cl_prot_mode {
+       u8 current_val;
+       u8 default_val;
+       u8 dynamic_val;
+};
+
+struct mac_entry {
+       struct cl_hw *cl_hw;
+       struct list_head list;
+       time64_t kt_sec;
+       u8 addr[ETH_ALEN];
+       u8 state;
+       bool assoc_flag;
+       unsigned long allow_time;
+       spinlock_t entry_lock;
+       struct cl_timer timer;
+       struct cl_timer allow_timer;
+       struct work_struct cross_allow_time_work;
+};
+
+struct mac_drv {
+       struct mac_entry mac;
+       u16 list_size;
+};
+
+struct cl_hw_asserts_info {
+
+       /* Timestamp (jiffies) of the last CL_MIN_ASSERT_CNT hw assert. */
+       unsigned long timestamp[CL_MIN_ASSERT_CNT];
+       /* Hw assert index. */
+       u8 index;
+       /* Indicate if hw_restart was schedule */
+       u8 restart_sched;
+       /* Indicate if hw_restart is needed due to unrecoverable assert. */
+       u8 restart_needed;
+};
+
+struct cl_ate_db {
+       bool active;
+       s8 tx_power;
+       s8 tx_power_offset[MAX_ANTENNAS];
+       u8 ant_mask;
+       u8 mode;
+       u8 bw;
+       u8 nss;
+       u8 mcs;
+       u8 gi;
+       u8 ltf;
+       struct ate_stats stats;
+};
+
+struct cl_agg_cfm_queue {
+       struct list_head head;
+       struct cl_tx_queue *tx_queue;
+       u16 ssn;
+};
+
+struct cl_single_cfm_queue {
+       struct list_head head;
+};
+
+struct cl_assoc_queue {
+       struct list_head list;
+       spinlock_t lock;
+};
+
+struct cl_agc_cd {
+       /* Configuration */
+       u32 period;
+       bool debug;
+       /* Internal parameters */
+       bool is_on;
+       bool use_hystersis;
+       u32 maintenance;
+};
+
+struct cl_dyn_mcast_rate {
+       u8 wrs_mode_default;
+       u8 wrs_mode_curr;
+};
+
+struct cl_dyn_bcast_rate {
+       u8 sta_min_mcs;
+       u8 bcast_mcs;
+       u8 wrs_mode;
+       u8 ltf;
+};
+
+struct cl_power_db {
+       u8 curr_percentage;
+       s8 curr_offset;
+       /* Used to validate margins of MAC power */
+       s8 bw_factor_q2[CHNL_BW_MAX];
+       s8 ant_factor_q2[MAX_ANTENNAS];
+};
+
+struct cl_bf_db {
+       bool force;
+       enum cl_dbg_level dbg_level;
+};
+
+struct cl_vns_rssi_entry {
+       struct list_head list_all;
+       struct list_head list_addr;
+       unsigned long timestamp;
+       s8 strongset_rssi;
+       u8 addr[ETH_ALEN];
+};
+
+#define STA_HASH_SIZE 256
+
+struct cl_vns_mgmt_db {
+       u32 num_entries;
+       struct list_head list_all;
+       struct list_head list_addr[STA_HASH_SIZE];
+};
+
+struct cl_vns_db {
+       bool enable;
+       bool dbg;
+       bool dbg_per_packet;
+       u16 interval_period;
+       spinlock_t lock;
+       struct cl_vns_mgmt_db mgmt_db;
+};
+
+/* Cl_dbgfile.c - offload data */
+struct cl_str_offload_env {
+       char *block1;
+       u32 size1;
+       u32 base1;
+       char *block2;
+       u32 size2;
+       u32 base2;
+       char *block3;
+       u32 size3;
+       u32 base3;
+       bool enabled;
+       char buf[512];
+};
+
+struct cl_dma_accessed {
+       void *drv_v_addr;
+       u32 size;
+       u32 fw_v_addr;
+       u32 dma_addr;
+};
+
+struct cl_radar_queue {
+       struct list_head head;
+       spinlock_t lock;
+};
+
+struct cl_recovery_db {
+       unsigned long last_restart;
+       u32 restart_cnt;
+
+       u32 ela_en;
+       u32 ela_sel_a;
+       u32 ela_sel_b;
+       u32 ela_sel_c;
+
+       bool in_recovery;
+};
+
+struct cl_noise_reg {
+       struct list_head list;
+       u32 np_prim20_per_ant;
+       u32 np_prim20_per_ant2;
+       u32 nasp_prim20_per_ant;
+       u32 nasp_prim20_per_ant2;
+       u32 np_sub20_per_chn;
+       u32 np_sub20_per_chn2;
+       u32 nasp_sub20_per_chn;
+       u32 nasp_sub20_per_chn2;
+       u32 np_sec20_dens_per_ant;
+       u32 nasp_sec20_dens_per_ant;
+};
+
+struct cl_noise_db {
+       struct list_head reg_list;
+       bool hist_record;
+       u8 active_ant;
+       u8 sample_cnt;
+};
+
+struct cl_chan_info {
+       u8 channel;
+       u8 max_bw;
+       /* Resolution of 0.25dB */
+       u8 max_power_q2; /* MIN(country_max_power_q2, hardware_max_power_q2) */
+       u8 country_max_power_q2;
+       u8 hardware_max_power_q2;
+};
+
+struct cl_channel_info {
+       bool use_channel_info;
+       struct cl_chan_info channels[CHNL_BW_MAX][MAX_CHANNELS];
+       enum cl_reg_standard standard;
+       struct ieee80211_regdomain *rd;
+};
+
+#define CL_STA_HASH_SIZE (CL_MAX_NUM_STA / 2)
+#define CL_STA_HASH_MASK (CL_STA_HASH_SIZE - 1)
+#define CL_STA_HASH_IDX(x) ((x) & CL_STA_HASH_MASK)
+
+struct cl_sta_db {
+       struct list_head head;
+       struct cl_sta *lut[CL_MAX_NUM_STA];
+       struct list_head hash[CL_STA_HASH_SIZE];
+       rwlock_t lock;
+       u32 num;
+};
+
+struct cl_tx_inject {
+       bool continuous;
+       bool is_running;
+       bool aggressive_edca;
+       u32 alloc_counter;
+       u32 current_counter;
+       u32 max_counter;
+       u32 packet_len;
+       struct cl_sta *cl_sta;
+       struct tasklet_struct tasklet;
+};
+
+#define CL_USER_PRIO_VALS 8
+#define CL_USER_DSCP_VALS 64
+
+struct cl_vid_user {
+       u16 vid;
+       u8 user_prio;
+};
+
+struct cl_vlan_dhcp_params {
+       /* DSCP to user priority mapping */
+       u8 dscp_to_up[CL_USER_DSCP_VALS];
+       /* VLAN to user priority mapping */
+       u8 vlan_to_up[CL_USER_PRIO_VALS];
+       /*
+        * Vid-pbit to user priority mapping
+        * First index is the pbit. Second index is a running index 0
+        */
+       struct cl_vid_user vlan_pbit_to_up[CL_USER_PRIO_VALS][CL_USER_PRIO_VALS];
+       /* 2 - "VLAN" VLAN based only, 3 - "DSCP" DSCP based only. Any other number - Automatic */
+       u8 up_layer_based;
+       u8 default_vlan_up;
+};
+
+struct cl_vlan_dscp {
+       struct cl_vlan_dhcp_params vlan_dhcp_params[MAX_BSS_NUM];
+       bool enable[MAX_BSS_NUM];
+       bool debug;
+};
+
+struct cl_controller_reg {
+       u32 breset;
+       u32 debug_enable;
+       u32 dreset;
+       u32 ocd_halt_on_reset;
+       u32 run_stall;
+};
+
+struct cl_busytime_stats {
+       u32 rx_mine_time_us;
+       u32 tx_mine_time_us;
+       u32 edca_cca_busy_us;
+};
+
+#define CCA_MAX_SAMPLE 21
+
+struct cl_edca_hist_db {
+       u16 air_util[CCA_MAX_SAMPLE];
+       u16 wifi_air_util[CCA_MAX_SAMPLE];
+       u16 not_mine_rx_wifi[CCA_MAX_SAMPLE];
+       u16 mine[CCA_MAX_SAMPLE];
+       u16 not_mine[CCA_MAX_SAMPLE];
+       u16 non_wifi_util[CCA_MAX_SAMPLE];
+       u16 not_mine_busy[CCA_MAX_SAMPLE];
+       u16 sample_cnt;
+};
+
+struct cl_cca_db {
+       struct cl_edca_hist_db edca_hist;
+       unsigned long time;
+       u32 edca_busy;
+       u32 edca_busy_sec20;
+       u32 edca_busy_sec40;
+       u32 edca_busy_sec80;
+       u32 cca_busy_nav;
+       u32 cca_intra_bss_nav;
+       u32 cca_inter_bss_nav;
+       u32 tx_mine;
+       u32 rx_mine;
+       u32 print_tx_mine;
+       u32 print_rx_mine;
+       enum cl_cca_opt cca_opt;
+};
+
+struct cl_cpu_cntr {
+       u32 tx_agg[CPU_MAX_NUM];
+       u32 tx_single[CPU_MAX_NUM];
+};
+
+struct cl_tx_drop_cntr {
+       u32 wd_restart;
+       u32 radio_off;
+       u32 in_recovery;
+       u32 short_length;
+       u32 pending_full;
+       u32 packet_limit;
+       u32 dev_flags;
+       u32 tx_disable;
+       u32 length_limit;
+       u32 txhdr_alloc_fail;
+       u32 queue_null;
+       u32 amsdu_alloc_fail;
+       u32 amsdu_dma_map_err;
+       u32 build_hdr_fail;
+       u32 key_disable;
+       u32 queue_flush;
+       u32 sta_null_in_agg;
+};
+
+struct cl_tx_forward_cntr {
+       u32 tx_start;
+       u32 drv_fast_agg;
+       u32 drv_fast_single;
+       u32 to_mac;
+       u32 from_mac_single;
+       u32 from_mac_agg;
+};
+
+struct cl_tx_transfer_cntr {
+       u32 single_to_agg;
+       u32 agg_to_single;
+};
+
+struct cl_tx_packet_cntr {
+       struct cl_tx_forward_cntr forward;
+       struct cl_tx_drop_cntr drop;
+       struct cl_tx_transfer_cntr transfer;
+};
+
+struct cl_power_truncate {
+       u8 he[CHNL_BW_MAX][WRS_MCS_MAX_HE][PWR_TBL_HE_BF_SIZE];
+       u8 ht_vht[CHNL_BW_MAX][WRS_MCS_MAX_VHT][PWR_TBL_VHT_BF_SIZE];
+       u8 ofdm[WRS_MCS_MAX_OFDM];
+       u8 cck[WRS_MCS_MAX_CCK];
+};
+
+#define CL_TWT_MAX_SESSIONS 8
+
+struct cl_twt_session_db {
+       struct cl_sta *cl_sta;
+       struct ieee80211_twt_individual_elem twt_setup;
+};
+
+struct cl_twt_db {
+       struct cl_twt_session_db cl_twt_sessions[CL_TWT_MAX_SESSIONS];
+       u8 num_sessions;
+       u8 dialog_token;
+};
+
+struct cl_vif_db {
+       struct list_head head;
+       u8 num_iface_bcn;
+};
+
+enum cl_rx_stats_flag {
+       RX_STATS_CCK = 0x01,
+       RX_STATS_OFDM = 0x02,
+       RX_STATS_HT = 0x04,
+       RX_STATS_VHT = 0x08,
+       RX_STATS_HE_SU = 0x10,
+       RX_STATS_HE_MU = 0x20,
+       RX_STATS_HE_EXT = 0x40,
+       RX_STATS_HE_TRIG = 0x80,
+};
+
+struct cl_rx_stats {
+       u32 he_trig[CHNL_BW_MAX_HE][WRS_SS_MAX][WRS_MCS_MAX_HE][WRS_GI_MAX_HE];
+       u32 he_ext[CHNL_BW_MAX_HE][WRS_SS_MAX][WRS_MCS_MAX_HE][WRS_GI_MAX_HE];
+       u32 he_mu[CHNL_BW_MAX_HE][WRS_SS_MAX][WRS_MCS_MAX_HE][WRS_GI_MAX_HE];
+       u32 he_su[CHNL_BW_MAX_HE][WRS_SS_MAX][WRS_MCS_MAX_HE][WRS_GI_MAX_HE];
+       u32 vht[CHNL_BW_MAX_VHT][WRS_SS_MAX][WRS_MCS_MAX_VHT][WRS_GI_MAX_VHT];
+       u32 ht[CHNL_BW_MAX_HT][WRS_SS_MAX][WRS_MCS_MAX_HT][WRS_GI_MAX_HT];
+       u32 ofdm[WRS_MCS_MAX_OFDM];
+       u32 cck[WRS_MCS_MAX_CCK];
+       u8 flag;
+};
+
+struct cl_fw_dbg {
+       char *buf;
+       int len;
+};
+
+struct cl_rx_trigger_based_stats {
+       bool enable;
+       u8 ampdu_cnt;
+       u16 data_per_agg;
+       u16 qos_null_per_agg;
+       u32 total;
+       u32 data[DBG_STATS_MAX_AGG_SIZE];
+       u32 qos_null[TID_MAX + 2];
+};
+
+enum cl_iface_conf {
+       CL_IFCONF_AP,
+       CL_IFCONF_STA,
+       CL_IFCONF_REPEATER,
+       CL_IFCONF_MESH_AP,
+       CL_IFCONF_MESH_ONLY,
+
+       CL_IFCONF_MAX
+};
+
+struct cl_vendor_msg {
+       u8 *buf;
+       u16 len;
+       u16 offset;
+       bool in_process;
+};
+
+struct cl_driver_ops {
+       int (*msg_fw_send)(struct cl_hw *cl_hw,
+                          const void *msg_params,
+                          bool background);
+       void (*pkt_fw_send)(struct cl_hw *cl_hw,
+                           struct cl_sw_txhdr *sw_txhdr,
+                           struct cl_tx_queue *tx_queue);
+};
+
+struct cl_version_db {
+       u32 dsp;
+       u32 rfic_sw;
+       u32 rfic_hw;
+       u32 agcram;
+       char fw[CL_VERSION_STR_SIZE];
+       char drv[CL_VERSION_STR_SIZE];
+       unsigned long last_update;
+};
+
+struct cl_cached_fw {
+       void *data;
+       size_t size;
+};
+
+struct cl_hw {
+       u8 idx; /* Global index (0-3) */
+       u8 tcv_idx; /* Transceiver index (0-1) */
+       struct cl_tcv_conf *conf;
+       struct cl_chip *chip;
+       struct ieee80211_hw *hw;
+       const struct cl_driver_ops *drv_ops;
+       struct cl_vif_db vif_db;
+       struct cl_fw_dbg fw_dbg;
+       enum cl_iface_conf iface_conf;
+       u32 num_ap_started;
+       u8 tx_power_version;
+       struct cl_vif *mc_vif;
+       u8 bw;
+       u32 channel;
+       u32 primary_freq;
+       u32 center_freq;
+       enum nl80211_band nl_band;
+       u8 num_antennas;
+       u8 mask_num_antennas;
+       u8 first_ant;
+       u8 last_ant;
+       u8 max_antennas;
+       u8 max_mu_cnt;
+       struct cl_sta_db cl_sta_db;
+       struct cl_ipc_e2a_irq ipc_e2a_irq;
+       struct cl_controller_reg controller_reg;
+       struct ieee80211_supported_band sband;
+       void (*ipc_host2xmac_trigger_set)(struct cl_chip *chip, u32 value);
+       unsigned long drv_flags;
+       unsigned long tx_disable_flags;
+       struct cl_ipc_host_env *ipc_env;
+       spinlock_t tx_lock_agg;
+       spinlock_t tx_lock_cfm_agg;
+       spinlock_t tx_lock_single;
+       spinlock_t tx_lock_bcmc;
+       struct mutex msg_tx_mutex;
+       wait_queue_head_t wait_queue; /* Synchronize driver<-->firmware message exchanges */
+       unsigned long cfm_flags[MAX_CFM_FLAGS];
+       void *msg_cfm_params[MM_MAX + DBG_MAX]; /* Array of pointers per received msg CFM */
+       bool msg_background;
+       wait_queue_head_t fw_sync_wq;
+       wait_queue_head_t radio_wait_queue;
+       struct cl_rx_elem *rx_elems;
+       struct cl_e2a_msg_elem *e2a_msg_elems;
+       struct cl_dbg_elem *dbg_elems;
+       struct cl_radar_elem *radar_elems;
+       struct dma_pool *txdesc_pool;
+       struct dma_pool *dbg_pool;
+       struct dma_pool *e2a_msg_pool;
+       struct dma_pool *radar_pool;
+       struct cl_dbg_info dbginfo;
+       struct cl_debugfs debugfs;
+       struct cl_hw_asserts_info assert_info;
+       char fw_prefix; /* Single character for fw prefix - l/u/s */
+       u8 fw_dst_kern_id; /* Firmware destination (LMAC/SMAC) */
+       bool fw_active;
+       bool fw_send_start; /* Did driver already send a start request message to firmware? */
+       struct cl_tx_inject tx_inject;
+       bool chandef_set;
+       struct cl_dbg_data dbg_data;
+       bool set_calib;
+       struct cl_tx_power_info tx_pow_info[MAX_CHANNELS][MAX_ANTENNAS];
+       struct cl_channel_info channel_info;
+       struct cl_phy_data_info phy_data_info;
+       u32 mask_hi;
+       u32 mask_low;
+       struct cl_timer maintenance_slow_timer;
+       struct cl_timer maintenance_fast_timer;
+       struct tasklet_struct tx_task;
+       struct list_head list_sched_q_agg;
+       struct list_head list_sched_q_single;
+       struct cl_ate_db ate_db;
+       struct cl_env_db env_db;
+       struct cl_req_agg_db req_agg_db[IPC_MAX_BA_SESSIONS];
+       u8 req_agg_queues;
+       u8 used_agg_queues;
+       u16 max_agg_tx_q_size;
+       bool wd_restart_drv;
+       bool is_stop_context;
+       struct workqueue_struct *drv_workqueue;
+       struct cl_amsdu_rx_state amsdu_rx_state;
+       struct cl_tx_queues tx_queues;
+       struct kmem_cache *sw_txhdr_cache;
+       struct kmem_cache *amsdu_txhdr_cache;
+       u32 radio_stats[CL_RADIO_ERRORS_MAX];
+       atomic_t tx_packet_count;
+       struct cl_rx_path_info rx_info;
+       struct cl_prot_mode prot_mode;
+       struct cl_agg_cfm_queue agg_cfm_queues[IPC_MAX_BA_SESSIONS];
+       struct cl_single_cfm_queue single_cfm_queues[MAX_SINGLE_QUEUES];
+       struct cl_single_cfm_queue bcmc_cfm_queue;
+       atomic_t radio_lock;
+       struct cl_assoc_queue assoc_queue;
+       struct cl_agc_cd agc_cd;
+       struct cl_wrs_db wrs_db;
+       struct cl_traffic_main traffic_db;
+       struct cl_rsrc_mgmt_db rsrc_mgmt_db;
+       struct cl_power_db power_db;
+       struct cl_bf_db bf_db;
+       struct cl_edca_db edca_db;
+       struct cl_vns_db vns_db;
+       struct cl_str_offload_env str_offload_env;
+       struct cl_dma_accessed fw_remote_rom;
+       struct cl_recovery_db recovery_db;
+       struct cl_radar_queue radar_queue;
+       struct tasklet_struct radar_tasklet;
+       struct cl_cached_fw cached_fw;
+       s8 rx_sensitivity[MAX_ANTENNAS];
+       struct cl_cca_db cca_db;
+       struct cl_noise_db noise_db;
+       struct cl_temp_comp_db temp_comp_db;
+       struct cl_sounding_db sounding;
+       struct cl_dyn_mcast_rate dyn_mcast_rate;
+       struct cl_dyn_bcast_rate dyn_bcast_rate;
+       struct cl_dfs_db dfs_db;
+       struct cl_version_db version_db;
+       bool entry_fixed_rate;
+       struct cl_vlan_dscp vlan_dscp;
+       unsigned long last_tbtt_irq;
+       u32 tbtt_cnt;
+       u8 mesh_tbtt_div;
+       struct tasklet_struct tx_mesh_bcn_task;
+       u32 fw_recovery_cntr;
+       u32 rx_filter;
+       ptrdiff_t mac_hw_regs_offset;
+       ptrdiff_t phy_regs_offset;
+       struct sk_buff_head tx_remote_queue;
+       struct sk_buff_head rx_remote_queue_mac;
+       struct sk_buff_head rx_skb_queue;
+       struct tasklet_struct rx_tasklet;
+       struct tasklet_struct rx_resched_tasklet;
+       u8 fem_system_mode;
+       u8 fem_ant;
+       struct cl_tx_packet_cntr tx_packet_cntr;
+       struct cl_cpu_cntr cpu_cntr;
+       struct cl_iq_dcoc_data_info iq_dcoc_data_info;
+       struct cl_power_table_info power_table_info;
+       struct ieee80211_sband_iftype_data iftype_data[3];
+       bool motion_sense_dbg;
+       struct cl_power_truncate pwr_trunc;
+       struct mutex set_channel_mutex;
+       u8 radio_status;
+       u8 rf_crystal_mhz;
+       bool calib_ready;
+       struct cl_twt_db twt_db;
+       struct mac_address addresses[MAX_BSS_NUM];
+       struct cl_rx_stats *rx_stats; /* RX statistics for production mode. */
+       spinlock_t lock_stats;
+       u16 n_addresses;
+       u8 txamsdu_en;
+       bool reg_dbg;
+       struct cl_rx_trigger_based_stats tb_stats;
+       bool idle_async_set;
+       struct cl_vendor_msg vendor_msg;
+       struct cl_timer vendor_timer;
+       bool msg_calib_timeout;
+       struct cl_calib_work *calib_work;
+};
+
+void cl_hw_init(struct cl_chip *chip, struct cl_hw *cl_hw, u8 tcv_idx);
+void cl_hw_deinit(struct cl_hw *cl_hw, u8 tcv_idx);
+void cl_hw_lock(struct cl_hw *cl_hw);
+void cl_hw_unlock(struct cl_hw *cl_hw);
+struct cl_hw *cl_hw_other_tcv(struct cl_hw *cl_hw);
+bool cl_hw_is_tcv0(struct cl_hw *cl_hw);
+bool cl_hw_is_tcv1(struct cl_hw *cl_hw);
+int cl_hw_set_antennas(struct cl_hw *cl_hw);
+u8 cl_hw_ant_shift(struct cl_hw *cl_hw);
+
+#endif /* CL_HW_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.
________________________________


^ permalink raw reply related	[flat|nested] 262+ messages in thread

* [RFC v1 100/256] cl8k: add hw_assert.c
  2021-06-17 15:58 [RFC v1 000/256] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (98 preceding siblings ...)
  2021-06-17 15:59 ` [RFC v1 099/256] cl8k: add hw.h viktor.barna
@ 2021-06-17 15:59 ` viktor.barna
  2021-06-17 15:59 ` [RFC v1 101/256] cl8k: add hw_assert.h viktor.barna
                   ` (157 subsequent siblings)
  257 siblings, 0 replies; 262+ messages in thread
From: viktor.barna @ 2021-06-17 15:59 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Oleksandr Savchenko, Shay Bar, Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

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

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 drivers/net/wireless/celeno/cl8k/hw_assert.c | 129 +++++++++++++++++++
 1 file changed, 129 insertions(+)
 create mode 100644 drivers/net/wireless/celeno/cl8k/hw_assert.c

diff --git a/drivers/net/wireless/celeno/cl8k/hw_assert.c b/drivers/net/wireless/celeno/cl8k/hw_assert.c
new file mode 100644
index 000000000000..b632d70bae44
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/hw_assert.c
@@ -0,0 +1,129 @@
+// SPDX-License-Identifier: MIT
+/* Copyright(c) 2019-2021, Celeno Communications Ltd. */
+
+#include "hw_assert.h"
+#include "recovery.h"
+#include "debug.h"
+#include "dbgfile.h"
+#include "bus/pci/ipc.h"
+#include "coredump.h"
+
+#define ASSERT_PATTERN 0xC0DEDEAD
+
+/*
+ * Function will take time stamp for each hw error indication.
+ * when time diff between each error is less than ce_hw_assert_time_max
+ * cl_hw_restart work will be scheduled
+ */
+static bool cl_hw_assert_storm_detect(struct cl_hw *cl_hw)
+{
+       struct cl_hw_asserts_info *assert_info = &cl_hw->assert_info;
+       u8 idx = assert_info->index % CL_MIN_ASSERT_CNT;
+       /* Get the oldest assert timestamp. */
+       u8 prev_idx = (assert_info->index + 1) % CL_MIN_ASSERT_CNT;
+       bool is_hw_restarted = false;
+
+       if (assert_info->restart_sched) {
+               is_hw_restarted = true;
+       } else {
+               /* Take time stamp of the assert */
+               assert_info->timestamp[idx] = jiffies;
+               assert_info->index++;
+               /* In case hw assert time diff is less than CL_HW_ASSERT_TIME_MAX, restart hw. */
+               if (assert_info->index > CL_MIN_ASSERT_CNT) {
+                       unsigned long time_diff_jiffies =
+                               assert_info->timestamp[idx] - assert_info->timestamp[prev_idx];
+                       unsigned int time_diff_msecs = jiffies_to_msecs(time_diff_jiffies);
+
+                       if (time_diff_msecs < cl_hw->conf->ce_hw_assert_time_max) {
+                               assert_info->index = 0;
+
+                               cl_dbg_err(cl_hw, "Assert storm detect (time_diff = %u)\n",
+                                          time_diff_msecs);
+                               cl_recovery_start(cl_hw, RECOVERY_ASSERT_STORM_DETECT);
+
+                               is_hw_restarted = true;
+                       }
+               }
+       }
+
+       return is_hw_restarted;
+}
+
+void cl_hw_assert_info_init(struct cl_hw *cl_hw)
+{
+       memset(&cl_hw->assert_info, 0, sizeof(cl_hw->assert_info));
+}
+
+void cl_hw_assert_print(struct cl_hw *cl_hw, struct cl_ipc_e2a_msg *msg)
+{
+       struct dbg_print_ind *ind = (struct dbg_print_ind *)msg->param;
+       const char *assert_string;
+       u32 assert_pattern;
+       u16 file_id = le16_to_cpu(ind->file_id);
+       u16 line = le16_to_cpu(ind->line);
+       u16 has_param = le16_to_cpu(ind->has_param);
+       u32 param = le32_to_cpu(ind->param);
+
+       /* If ce_hw_assert_time_max is 0, HW assert storm detection is disabled */
+       if (cl_hw->conf->ce_hw_assert_time_max)
+               if (cl_hw_assert_storm_detect(cl_hw))
+                       return;
+
+       /* Print ASSERT message with fileid, line, [parameter] */
+       if (has_param)
+               cl_dbg_err(cl_hw, "ASSERT_TCV%u @ FILE=%hu LINE=%hu param=0x%08X\n",
+                          cl_hw->idx, file_id, line, param);
+       else
+               cl_dbg_err(cl_hw, "ASSERT_TCV%u @ file=%hu line=%hu\n",
+                          cl_hw->idx, file_id, line);
+
+       assert_string = cl_dbgfile_get_msg_txt(&cl_hw->dbg_data, file_id, line);
+
+       if (!assert_string)
+               assert_string = "ASSERT STRING NOT FOUND";
+
+       /* TODO: length of single print may be limited, consider printing long msgs by pieces */
+       cl_dbg_err(cl_hw, "%.500s\n", assert_string);
+
+       assert_pattern = le32_to_cpu(cl_hw->ipc_env->shared->assert_pattern);
+
+       /* Reset ASSERT pattern if needed (in order to prevent assert prints loop) */
+       if (assert_pattern == ASSERT_PATTERN)
+               cl_hw->ipc_env->shared->assert_pattern = 0;
+
+       if (ind->err_no_dump) {
+               bool reason = RECOVERY_UNRECOVERABLE_ASSERT_NO_DUMP;
+               bool restart = cl_coredump_recovery(cl_hw, reason);
+
+               if (restart)
+                       cl_hw->assert_info.restart_needed = true;
+       } else {
+               cl_hw->assert_info.restart_needed = false;
+       }
+}
+
+void cl_hw_assert_check(struct cl_hw *cl_hw)
+{
+       struct cl_ipc_shared_env *shared_env = cl_hw->ipc_env->shared;
+       u32 assert_pattern = le32_to_cpu(shared_env->assert_pattern);
+
+       if (assert_pattern == ASSERT_PATTERN) {
+               u16 line = le16_to_cpu(shared_env->assert_line_num);
+               u16 fileid = le16_to_cpu(shared_env->assert_file_id);
+               u32 param = le32_to_cpu(shared_env->assert_param);
+               const char *assert_string = cl_dbgfile_get_msg_txt(&cl_hw->dbg_data, fileid, line);
+
+               /* Print 1st ASSERT message with fileid, line, [parameter] */
+               cl_dbg_err(cl_hw, "ASSERT_%cmac @ FILE=%hu LINE=%hu param=0x%08X\n",
+                          cl_hw->fw_prefix, fileid, line, param);
+
+               if (!assert_string)
+                       assert_string = "ASSERT STRING NOT FOUND";
+
+               cl_dbg_err(cl_hw, "%.500s\n", assert_string);
+
+               /* Reset ASSERT pattern in order to prevent assert prints loop */
+               shared_env->assert_pattern = 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.
________________________________


^ permalink raw reply related	[flat|nested] 262+ messages in thread

* [RFC v1 101/256] cl8k: add hw_assert.h
  2021-06-17 15:58 [RFC v1 000/256] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (99 preceding siblings ...)
  2021-06-17 15:59 ` [RFC v1 100/256] cl8k: add hw_assert.c viktor.barna
@ 2021-06-17 15:59 ` viktor.barna
  2021-06-17 15:59 ` [RFC v1 102/256] cl8k: add ipc_shared.h viktor.barna
                   ` (156 subsequent siblings)
  257 siblings, 0 replies; 262+ messages in thread
From: viktor.barna @ 2021-06-17 15:59 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Oleksandr Savchenko, Shay Bar, Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

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

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 drivers/net/wireless/celeno/cl8k/hw_assert.h | 13 +++++++++++++
 1 file changed, 13 insertions(+)
 create mode 100644 drivers/net/wireless/celeno/cl8k/hw_assert.h

diff --git a/drivers/net/wireless/celeno/cl8k/hw_assert.h b/drivers/net/wireless/celeno/cl8k/hw_assert.h
new file mode 100644
index 000000000000..0033c2f5025f
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/hw_assert.h
@@ -0,0 +1,13 @@
+/* SPDX-License-Identifier: MIT */
+/* Copyright(c) 2019-2021, Celeno Communications Ltd. */
+
+#ifndef CL_HW_ASSERT_H
+#define CL_HW_ASSERT_H
+
+#include "hw.h"
+
+void cl_hw_assert_info_init(struct cl_hw *cl_hw);
+void cl_hw_assert_print(struct cl_hw *cl_hw, struct cl_ipc_e2a_msg *msg);
+void cl_hw_assert_check(struct cl_hw *cl_hw);
+
+#endif /* CL_HW_ASSERT_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.
________________________________


^ permalink raw reply related	[flat|nested] 262+ messages in thread

* [RFC v1 102/256] cl8k: add ipc_shared.h
  2021-06-17 15:58 [RFC v1 000/256] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (100 preceding siblings ...)
  2021-06-17 15:59 ` [RFC v1 101/256] cl8k: add hw_assert.h viktor.barna
@ 2021-06-17 15:59 ` viktor.barna
  2021-06-17 15:59 ` [RFC v1 103/256] cl8k: add key.c viktor.barna
                   ` (155 subsequent siblings)
  257 siblings, 0 replies; 262+ messages in thread
From: viktor.barna @ 2021-06-17 15:59 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Oleksandr Savchenko, Shay Bar, Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

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

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 drivers/net/wireless/celeno/cl8k/ipc_shared.h | 1445 +++++++++++++++++
 1 file changed, 1445 insertions(+)
 create mode 100644 drivers/net/wireless/celeno/cl8k/ipc_shared.h

diff --git a/drivers/net/wireless/celeno/cl8k/ipc_shared.h b/drivers/net/wireless/celeno/cl8k/ipc_shared.h
new file mode 100644
index 000000000000..fbe3f6b17996
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/ipc_shared.h
@@ -0,0 +1,1445 @@
+/* SPDX-License-Identifier: MIT */
+/* Copyright(c) 2019-2021, Celeno Communications Ltd. */
+
+#ifndef CL_IPC_SHARED_H
+#define CL_IPC_SHARED_H
+
+#include "def.h"
+#include <net/mac80211.h>
+#include "utils/math.h"
+
+/** DOC: IPC - introduction
+ *
+ * IPC layer between the FW (XMAC -> LMAC, SMAC, UMAC) and the driver. Driver
+ * talks with lower layer via custom IPC messages and DMA. Basically, drv <->
+ * fw messages flow consists of %fw_msg, that contains info about direction,
+ * message id (which is enum field of %mm_msg_tag or %dbg_msg_tag) and payload
+ * itself.
+ *
+ * Messages may be synchronous (with the confirmation feedback) and
+ * asynchronous. The latter is typically being used as inidication of
+ * occurrence of some event.
+ *
+ * Driver              LMAC/SMAC
+ *  +                     +
+ *  |       AA_REQ        |
+ *  |-------------------->|...+ (Request)
+ *  |       AA_CFM        |   | Mandatory control messages
+ *  |<--------------------|...+ (Confirmation)
+ *  |                     |
+ *  .       BB_IND        .
+ *  |<--------------------|... Asynchronous indication
+ *
+ *  Messages are using prelocated buffers and size limit of %IPC_RXBUF_SIZE.
+ *  Each message may have verification pattern, that allows to verify the
+ *  validity of payload. Most important TX/RX flow operations are tracked and
+ *  are reflected by stats change (like &cl_rx_path_info structure).
+ */
+
+/*
+ * Number of Host buffers available for Data Rx handling (through DMA)
+ * Must correspond to FW code definition, and must be power of 2.
+ */
+#define IPC_RXBUF_CNT_RXM 2048
+#define IPC_RXBUF_CNT_FW  128
+
+/* Bucket debug */
+#define IPC_RXBUF_BUCKET_POW_SIZE 5
+#define IPC_RXBUF_BUCKET_SIZE     BIT(IPC_RXBUF_BUCKET_POW_SIZE) /* 2 ^ 5 = 32 */
+#define IPC_RXBUF_NUM_BUCKETS_RXM (IPC_RXBUF_CNT_RXM / IPC_RXBUF_BUCKET_SIZE)
+#define IPC_RXBUF_NUM_BUCKETS_FW  (IPC_RXBUF_CNT_FW / IPC_RXBUF_BUCKET_SIZE)
+
+#define MU_MAX_STREAMS     8
+#define MU_MAX_SECONDARIES (MU_MAX_STREAMS - 1)
+
+#define CL_MU0_IDX 0
+#define CL_MU1_IDX 1
+#define CL_MU2_IDX 2
+#define CL_MU3_IDX 3
+#define CL_MU4_IDX 4
+#define CL_MU5_IDX 5
+#define CL_MU6_IDX 6
+#define CL_MU7_IDX 7
+#define CL_MU_IDX_MAX CL_MU7_IDX
+
+#define IPC_TX_QUEUE_CNT 5
+
+#define IPC_MAX_BA_SESSIONS 128
+
+#if IPC_MAX_BA_SESSIONS > CL_MAX_NUM_STA
+#define IPC_MAX_TIM_TX_OR_RX_AGG_SIZE IPC_MAX_BA_SESSIONS
+#else
+#define IPC_MAX_TIM_TX_OR_RX_AGG_SIZE CL_MAX_NUM_STA
+#endif
+
+#define IPC_TIM_AGG_SIZE (IPC_MAX_TIM_TX_OR_RX_AGG_SIZE * 2)
+
+#define IPC_TX_QUEUE_IDX_TO_COMMON_QUEUE_IDX(idx) ((idx) * 2)
+
+#define IPC_RX_QUEUE_IDX_TO_COMMON_QUEUE_IDX(idx) (((idx) * 2) + 1)
+
+#define CL_MAX_BA_PHYSICAL_QUEUE_CNT (AC_MAX + MU_MAX_SECONDARIES)
+#define CE_AC_MAX (IPC_TX_QUEUE_CNT + MU_MAX_SECONDARIES)
+
+enum {
+       AGG_AC0_IDX = AC_BK,
+       AGG_AC1_IDX = AC_BE,
+       AGG_AC2_IDX = AC_VI,
+       AGG_AC3_IDX = AC_VO,
+       AGG_MU1_IDX,
+       AGG_MU2_IDX,
+       AGG_MU3_IDX,
+       AGG_MU4_IDX,
+       AGG_MU5_IDX,
+       AGG_MU6_IDX,
+       AGG_MU7_IDX,
+       AGG_IDX_MAX,
+};
+
+#define DBG_DUMP_BUFFER_SIZE (1024 * 40)
+
+#define IPC_TXDESC_CNT_SINGLE 16
+#define IPC_TXDESC_CNT_BCMC   16
+
+/* Max count of Tx MSDU in A-MSDU */
+#define CL_AMSDU_TX_PAYLOAD_MAX 4
+
+#define LMAC_TXDESC_AGG_Q_SIZE_MAX 512
+#define SMAC_TXDESC_AGG_Q_SIZE_MAX 256
+
+#define CL_MAX_AGG_IN_TXOP 20
+
+/* Keep LMAC & SMAC debug agg stats arrays size aligned */
+#define DBG_STATS_MAX_AGG_SIZE (256 + 1)
+
+/* Must be power of 2 */
+#define IPC_CFM_CNT 4096
+
+#define IPC_CFM_SIZE (IPC_CFM_CNT * sizeof(struct cl_ipc_cfm_msg))
+
+/* Number of rates in Policy table */
+#define CL_RATE_CONTROL_STEPS 4
+
+/*
+ * Stringified DRV/FW versions should be small enough to fit related ethtool
+ * descriptors size (32)
+ */
+#define CL_VERSION_STR_SIZE 32
+
+#if (IPC_CFM_CNT & (IPC_CFM_CNT - 1))
+#error "IPC_CFM_CNT Not a power of 2"
+#endif
+
+/*
+ * the calculation is conducted as follow:
+ * 1500 - max ethernet frame
+ * conversion of ETH to MSDU:
+ * 1500[eth max] - 12[hdr frame] + 14[msdu frame] + 8[llc snap] + 4[MSDU Padding] = 1514
+ * MSDU + WLAN HDR = 1514[MSDU MAX] + 36[MAX WLAN HDR] = 1550
+ * 32 bytes is being PADDED by SKB alloc for alignment.
+ * 18 byte encryption
+ * 50 bytes is save for upper layer + some internal meta data.
+ */
+#define IPC_RXBUF_SIZE           1682
+#define IPC_RXBUF_EXTRA_HEADROOM 40
+
+/* Number of available host buffers */
+#define IPC_RADAR_BUF_CNT   32
+#define IPC_E2A_MSG_BUF_CNT 128
+#define IPC_DBG_BUF_CNT     64
+
+/* Length used in MSGs structures (size in 4-byte words) */
+#define IPC_A2E_MSG_BUF_SIZE   255
+#define IPC_E2A_MSG_PARAM_SIZE 63
+
+/* Debug messages buffers size (in bytes) */
+#define IPC_DBG_PARAM_SIZE 256
+
+/* Pattern indication for validity */
+#define IPC_RX_DMA_OVER_PATTERN   0xAAAAAA00
+#define IPC_E2A_MSG_VALID_PATTERN 0xADDEDE2A
+#define IPC_DBG_VALID_PATTERN     0x000CACA0
+#define IPC_EXCEPTION_PATTERN     0xDEADDEAD
+
+#define HB_POOL_DMA_DESCS_NUM 2
+
+/* Tensilica backtrace depth */
+#define IPC_BACKTRACT_DEPTH  5
+
+/* Maximum length of the SW diag trace */
+#define DBG_SW_DIAG_MAX_LEN  1024
+
+/* Maximum length of the error trace */
+#define DBG_ERROR_TRACE_SIZE 256
+
+/* Number of MAC diagnostic port banks */
+#define DBG_DIAGS_MAC_MAX    48
+
+/* Number of PHY diagnostic port banks */
+#define DBG_DIAGS_PHY_MAX    32
+
+/* Maximum size of the RX header descriptor information in the debug dump */
+#define DBG_RHD_MEM_LEN      (5 * 1024)
+
+/* Maximum size of the RX buffer descriptor information in the debug dump */
+#define DBG_RBD_MEM_LEN      (5 * 1024)
+
+/* Maximum size of the TX header descriptor information in the debug dump */
+#define DBG_THD_MEM_LEN      (10 * 1024)
+
+/* Driver mem size used for THDs PTs & PBDs */
+#define DBG_THD_CHAINS_INFO_THD_CNT 5
+#define DBG_THD_CHAINS_INFO_PBD_CNT 9
+#define DBG_THD_CHAINS_INFO_PT_CNT  1
+#define DBG_THD_CHAINS_INFO_ARRAY_SIZE \
+       ((DBG_THD_CHAINS_INFO_THD_CNT * sizeof(struct tx_hd)) + \
+        (DBG_THD_CHAINS_INFO_PBD_CNT * sizeof(struct tx_pbd)) + \
+        (DBG_THD_CHAINS_INFO_PT_CNT * sizeof(struct tx_policy_tbl)))
+
+#define DBG_CHAINS_INFO_ELEM_CNT 10
+
+enum DBG_CHAINS_INFO_ELEMENTS {
+       DBG_CHAINS_INFO_EMPTY,
+       DBG_CHAINS_INFO_THD,
+       DBG_CHAINS_INFO_PBD,
+       DBG_CHAINS_INFO_PT,
+       DBG_CHAINS_INFO_MAX
+};
+
+/* Txl chain info - per ac */
+#define DBG_TXL_FRAME_EXCH_TRACE_DEPTH 5
+
+/* FW debug trace size */
+#define DBG_FW_TRACE_SIZE    30
+#define DBG_FW_TRACE_STR_MAX 20
+
+/* Number of embedded logic analyzers */
+#define LA_CNT               1
+
+#define LA_MAC_IDX 0
+#define LA_PHY_IDX 1
+
+/* Length of the configuration data of a logic analyzer */
+#define LA_CONF_LEN          102
+
+/* Structure containing the configuration data of a logic analyzer */
+struct la_conf_tag {
+       u32 conf[LA_CONF_LEN];
+};
+
+/* Size of a logic analyzer memory */
+#define LA_MEM_LEN (256 * 1024)
+
+/* Message structure for MSGs from Emb to App */
+struct cl_ipc_e2a_msg {
+       __le16 id;
+       __le16 dummy_dest_id;
+       __le16 dummy_src_id;
+       __le16 param_len;
+       u32 param[IPC_E2A_MSG_PARAM_SIZE];
+       __le32 pattern;
+};
+
+struct cl_ipc_msg {
+       struct list_head list;
+       struct cl_ipc_e2a_msg buf;
+};
+
+enum rx_buf_type {
+       CL_RX_BUF_RXM,
+       CL_RX_BUF_FW,
+       CL_RX_BUF_MAX
+};
+
+/*
+ * Structs & function  associated with HW & SW debug data
+ * The Debug information forwarded to host when an error occurs, and printed to stdout
+ * This data must be consistent with firmware, any new debug data should exist also in
+ * firmware side
+ */
+
+struct tx_hd {
+       u32 upatterntx;
+       u32 nextfrmexseq_ptr;
+       u32 nextmpdudesc_ptr;
+       u32 first_pbd_ptr;
+       u32 datastartptr;
+       u32 dataendptr;
+       u32 frmlen;
+       u32 spacinginfo;
+       u32 phyctrlinfo1;
+       u32 policyentryaddr;
+       u32 bar_thd_desc_ptr;
+       u32 reserved1;
+       u32 macctrlinfo1;
+       u32 macctrlinfo2;
+       u32 statinfo;
+       u32 phyctrlinfo2;
+};
+
+struct tx_policy_tbl {
+       u32 upatterntx;
+       u32 phycntrlinfo1;
+       u32 phycntrlinfo2;
+       u32 maccntrlinfo1;
+       u32 maccntrlinfo2;
+       u32 ratecntrlinfo[CL_RATE_CONTROL_STEPS];
+       u32 phycntrlinfo3;
+       u32 phycntrlinfo4;
+       u32 phycntrlinfo5;
+       u32 stationinfo;
+       u32 ratecntrlinfohe[CL_RATE_CONTROL_STEPS];
+       u32 maccntrlinfo3;
+       u32 triggercommoninfo;
+       u32 triggerinforuallocationu0u3;
+       u32 triggerinforuallocationu4u7;
+       u32 triggerperuserinfo[MU_MAX_STREAMS];
+};
+
+struct tx_pbd {
+       u32 upatterntx;
+       u32 next;
+       u32 datastartptr;
+       u32 dataendptr;
+       u32 bufctrlinfo;
+};
+
+enum cl_macfw_dbg_severity {
+       CL_MACFW_DBG_SEV_NONE,
+       CL_MACFW_DBG_SEV_ERROR,
+       CL_MACFW_DBG_SEV_WARNING,
+       CL_MACFW_DBG_SEV_INFO,
+       CL_MACFW_DBG_SEV_VERBOSE,
+
+       CL_MACFW_DBG_SEV_MAX
+};
+
+struct phy_channel_info {
+       __le32 info1;
+       __le32 info2;
+};
+
+struct dbg_debug_info_tag {
+       u32 error_type; /* (0: recoverable, 1: fatal) */
+       u32 hw_diag;
+       char error[DBG_ERROR_TRACE_SIZE];
+       u32 sw_diag_len;
+       char sw_diag[DBG_SW_DIAG_MAX_LEN];
+       struct phy_channel_info chan_info;
+       struct la_conf_tag la_conf[LA_CNT];
+       u16 diags_mac[DBG_DIAGS_MAC_MAX];
+};
+
+/*
+ * Defines, enums and structs below are used at TX statistics
+ * structure.
+ * Because of the TX statistics structure should be same at
+ * host and at firmware,the change of these parameters requires
+ * similar firmware changes
+ */
+
+struct cl_txl_ba_statistics {
+       u32 total_cnt;
+       u32 total_rtx_cnt;
+       u16 total_ba_received;
+       u16 total_ba_not_received_cnt;
+       u16 total_lifetime_expired_cnt;
+       u16 total_rtx_limit_reached;
+       u16 total_packets_below_baw;
+       u16 total_packets_above_baw;
+       u16 total_ba_not_received_cnt_ps;
+       u16 total_cleard_ba;
+       u16 total_unexpected_ba;
+       u16 total_invalid_ba;
+       u16 total_ack_instead_ba;
+};
+
+struct cl_txl_single_statistics {
+       u32 total_cnt;
+       u32 total_rtx_cnt;
+       u16 total_lifetime_expired_cnt;
+       u16 total_rtx_limit_reached;
+       u16 total_rtx_limit_reached_ps;
+};
+
+enum {
+       CE_BACKOFF_25,
+       CE_BACKOFF_50,
+       CE_BACKOFF_100,
+       CE_BACKOFF_500,
+       CE_BACKOFF_1000,
+       CE_BACKOFF_5000,
+       CE_BACKOFF_10000,
+       CE_BACKOFF_20000,
+       CE_BACKOFF_20000_ABOVE,
+       CE_BACKOFF_MAX
+};
+
+struct cl_txl_backoff_statistics {
+       u32 chain_time;
+       u32 backoff_hist[CE_BACKOFF_MAX];
+};
+
+struct cl_txl_tid_statistics {
+       u32 total_tid_desc_cnt;
+};
+
+/* Natt closed an aggregation due to one of the bellow reasons. */
+enum {
+       NATT_REASON_MAX_LEN    = 0x1,
+       NATT_REASON_TXOP_LIMIT = 0x2,
+       NATT_REASON_MPDU_NUM   = 0x4,
+       NATT_REASON_LAST_BIT   = 0x8,
+       NATT_REASON_MAX
+};
+
+/* Tx BW */
+enum {
+       NATT_BW_20,
+       NATT_BW_40,
+       NATT_BW_80,
+       NATT_BW_160,
+       NATT_BW_MAX
+};
+
+struct cl_txl_natt_statistics {
+       u32 agg_close_reason[NATT_REASON_MAX];
+       u32 chosen_frame_bw[NATT_BW_MAX];
+       u32 operation_mode[8];
+};
+
+enum {
+       AGG_IN_TXOP_CLOSE_REASON_NO_TXDESC,
+       AGG_IN_TXOP_CLOSE_REASON_TXOP_EXPIRED,
+       AGG_IN_TXOP_CLOSE_REASON_ACTIVE_DELBA,
+       AGG_IN_TXOP_CLOSE_REASON_MAX
+};
+
+struct amsdu_stat {
+       u16 packet_cnt_2;
+       u16 packet_cnt_3;
+       u16 packet_cnt_4;
+       u16 packet_cnt_5_or_more;
+};
+
+struct cl_txl_mu_statistics {
+       u16 chain_cnt;
+       u16 status_cnt;
+       u16 ba_received;
+       u16 ba_no_received;
+       u16 clear_ba;
+       u16 correct_ba;
+       u16 unexpected_ba;
+       u16 invalid_ba;
+};
+
+struct cl_txl_agg_statistics {
+       u16 agg_size_statistics[DBG_STATS_MAX_AGG_SIZE];
+       u32 packet_failed_statistics[DBG_STATS_MAX_AGG_SIZE];
+       u32 packet_passed_statistics[DBG_STATS_MAX_AGG_SIZE];
+       u16 htp_agg_size_statistics[DBG_STATS_MAX_AGG_SIZE];
+       u32 htp_packet_failed_statistics[DBG_STATS_MAX_AGG_SIZE];
+       u32 htp_packet_passed_statistics[DBG_STATS_MAX_AGG_SIZE];
+       u16 agg_in_txop_statistics[CL_MAX_AGG_IN_TXOP];
+       u16 agg_in_txop_close_reason[AGG_IN_TXOP_CLOSE_REASON_MAX];
+       u16 agg_in_txop_queue_switch;
+       u16 agg_in_txop_queue_switch_abort_bw;
+       struct amsdu_stat amsdu_stat[IPC_MAX_BA_SESSIONS];
+       u16 mu_agg_size_statistics[MU_MAX_STREAMS][DBG_STATS_MAX_AGG_SIZE];
+       struct cl_txl_mu_statistics mu_stats[MU_MAX_STREAMS];
+};
+
+struct cl_txl_ac_statistics {
+       u32 total_q_switch_cnt;
+       u32 total_ac_desc_cnt;
+};
+
+struct cl_txl_underrun_statistics {
+       u16 length_cnt;
+       u16 pattern_cnt;
+       u16 flushed_frames_cnt;
+};
+
+struct cl_txl_rts_cts_statistics {
+       u32 fw_rts_cnt;
+       u32 hw_rts_cnt;
+       u32 fw_cts_cnt;
+       u32 hw_cts_cnt;
+};
+
+struct cl_txl_backoff_params {
+       u32 singelton_total[AC_MAX];
+       u32 singelton_cnt[AC_MAX];
+       u32 agg_total[AC_MAX];
+       u32 agg_cnt[AC_MAX];
+};
+
+struct cl_txl_htp_statistics {
+       u32 total_cnt[TID_MAX];
+       u32 need_response;
+       u32 tb_response_required;
+       u32 ac_not_found;
+       u32 end_of_packet_int;
+       u32 tb_bw_decision;
+       u32 tb_ba_thd_removed;
+       u32 tb_ac_unchain;
+       u32 tb_htp_unchain;
+       u32 tb_dummy_htp_tx;
+       u32 tb_dummy_no_tx;
+       u32 msta_ba_received;
+       u32 msta_ba_aid_not_found;
+};
+
+struct cl_txl_vns_statistics {
+       u32 off_he;
+       u32 off_ht_vht;
+       u32 off_ofdm;
+       u32 off_cck;
+       u32 on_he;
+       u32 on_ht_vht;
+       u32 on_ofdm;
+       u32 on_cck;
+};
+
+struct cl_txl_fec_statistics {
+       u32 ldpc;
+       u32 bcc;
+};
+
+struct cl_txl_statistics {
+       u32 type; /* This field should be first in the struct */
+       u32 recovery_count;
+       u32 tx_obtain_bw_fail_cnt;
+       struct cl_txl_single_statistics single[IPC_TX_QUEUE_CNT];
+       struct cl_txl_ba_statistics ba[IPC_MAX_BA_SESSIONS];
+       struct cl_txl_backoff_statistics backoff_stats[AC_MAX];
+       struct cl_txl_natt_statistics natt;
+       struct cl_txl_tid_statistics tid[TID_MAX];
+       struct cl_txl_agg_statistics agg;
+       struct cl_txl_ac_statistics ac[CE_AC_MAX];
+       struct cl_txl_underrun_statistics underrun;
+       struct cl_txl_rts_cts_statistics rts_cts;
+       struct cl_txl_backoff_params backoff_params;
+       struct cl_txl_htp_statistics htp;
+       struct cl_txl_vns_statistics vns;
+       struct cl_txl_fec_statistics fec;
+};
+
+/* Flushed beacon list options */
+enum {
+       BCN_FLUSH_PENDING,
+       BCN_FLUSH_DOWNLOADING,
+       BCN_FLUSH_TRANSMITTING,
+       BCN_FLUSH_MAX,
+};
+
+struct bcn_backup_stats {
+       u32 bcn_backup_used_cnt;
+       u32 bcn_backup_tx_cnt;
+       u32 bcn_backup_flushed_cnt;
+       u32 bcn_backup_used_in_arow_cnt;
+       u32 bcn_backup_max_used_in_arow_cnt;
+};
+
+struct beacon_timing {
+       /* Time measurements between beacons */
+       u32 last_bcn_start_time;
+       u32 max_time_from_last_bcn;
+       u32 min_time_from_last_bcn;
+       u32 total_bcn_time;
+       /* Time measurements until beacon chained */
+       u32 imp_tbtt_start_time;
+       u32 bcn_chain_total_time;
+       u32 bcn_chain_max_time;
+       u32 bcn_chain_min_time;
+       /* Time measurements until received beacon from host */
+       u32 bcn_last_request_time;
+       u32 max_bcn_time_until_get_beacon_from_driver_in_tbtt;
+       u32 bcn_last_req_rec_time;
+       /* Time measurements of bcn from pending to chain */
+       u32 bcn_push_pending_start_time;
+       u32 bcn_pending_2_chain_max_time;
+};
+
+struct beacon_counters {
+       u32 bcn_time_from_driver_not_in_threshold_cnt;
+       u32 nof_time_intervals_between_beacons;
+       u32 total_cnt;
+       u32 bcn_chain_total_cnt;
+       u32 ce_txl_flushed_beacons[BCN_FLUSH_MAX];
+       u32 pending2chain_not_in_threshold_cnt;
+       u16 total_bcn_req_without_rec_from_host;
+       u16 max_bcn_not_received_from_host;
+       u32 total_beacons_received_from_host;
+};
+
+struct cl_bcn_statistics {
+       u32 type; /* This field should be first in the struct */
+       struct beacon_counters beacon_counters;
+       struct beacon_timing beacon_timing;
+       struct bcn_backup_stats bcn_backup_stats;
+};
+
+enum agg_tx_rate_drop_reason {
+       AGG_TX_RATE_DROP_MAX_BA_NOT_RECEIVED_REACHED,
+       AGG_TX_RATE_DROP_MAX_BA_PER_REACHED,
+       AGG_TX_RATE_DROP_MAX_RETRY_REACHED,
+       AGG_TX_RATE_DROP_MAX,
+};
+
+struct cl_rate_drop_statistics {
+       u32 type;
+       u32 drop_reason[AGG_TX_RATE_DROP_MAX];
+};
+
+#define BF_DB_MAX 16
+
+enum bfr_rx_err {
+       BFR_RX_ERR_BW_MISMATCH,
+       BFR_RX_ERR_NSS_MISMATCH,
+       BFR_RX_ERR_SOUNDING_CHBW,
+       BFR_RX_ERR_TOKEN_MISMATCH,
+       BFR_RX_ERR_NDP_DROP,
+       BFR_SEGMENTED_DROP,
+       BFR_RX_ERR_MISS_ACK,
+       BFR_RX_ERR_RESOURCE_NA,
+       BFR_RX_ERR_MAX
+};
+
+enum TX_BF_DATA_STAT {
+       TX_BF_DATA_OK = 0,
+       TX_BF_DATA_BUFFERED_RESOURCE_ERR,
+       TX_BF_DATA_RELEASED_RESOURCE_ERR,
+       TX_BF_DATA_BUFFERED_PS_STA,
+       TX_BF_DATA_RELEASED_PS_STA,
+       TX_BF_DATA_ERR_BFR_MISS,
+       TX_BF_DATA_ERR_BFR_OUTDATED,
+       TX_BF_DATA_ERR_MISMATCH_BW,
+       TX_BF_DATA_ERR_MISMATCH_NSS,
+       TX_BF_DATA_ERR_MAX
+};
+
+struct bf_ctrl_dbg {
+       u16 ndp_cnt;
+       u16 bfp_cnt;
+       u16 su_bfr_cnt;
+       u16 mu_bfr_cnt;
+       u16 bf_invalid_cnt[BFR_RX_ERR_MAX];
+       u16 tx_bf_data_err[TX_BF_DATA_ERR_MAX];
+};
+
+struct bf_stats_database {
+       bool is_active_list;
+       struct bf_ctrl_dbg dbg;
+       u8 sta_idx;
+       u16 active_dsp_idx;
+       u16 passive_dsp_idx;
+};
+
+struct cl_bf_statistics {
+       u32 type;
+       bool print_active_free_list;
+       struct bf_stats_database stats_data[BF_DB_MAX];
+};
+
+enum amsdu_deaggregation_err {
+       AMSDU_DEAGGREGATION_ERR_MAX_MSDU_REACH,
+       AMSDU_DEAGGREGATION_ERR_MSDU_GT_AMSDU_LEN,
+       AMSDU_DEAGGREGATION_ERR_MSDU_LEN,
+       AMSDU_ENCRYPTION_KEY_GET_ERR,
+
+       AMSDU_DEAGGREGATION_ERR_MAX
+};
+
+enum emb_ll1_handled_frm_type {
+       BA_FRM_TYPE,
+       NDPA_FRM_TYPE,
+       NDP_FRM_TYPE,
+       ACTION_NO_ACK_FRM_TYPE,
+
+       MAX_HANDLED_FRM_TYPE
+};
+
+enum rhd_decr_idx {
+       RHD_DECR_UNENC_IDX,
+       RHD_DECR_ICVFAIL_IDX,
+       RHD_DECR_CCMPFAIL_IDX,
+       RHD_DECR_AMSDUDISCARD_IDX,
+       RHD_DECR_NULLKEY_IDX,
+       RHD_DECR_IDX_MAX
+};
+
+#define RX_CLASSIFICATION_MAX 6
+#define FREQ_OFFSET_TABLE_IDX_MAX 8 /* Must be a power of 2 */
+#define RX_MAX_MSDU_IN_SINGLE_AMSDU 16
+
+struct cl_rxl_statistics {
+       u32 type; /* This field should be first in the struct */
+       u32 rx_imp_bf_counter[MU_UL_MAX];
+       u32 rx_imp_bf_int_counter[MU_UL_MAX];
+       u32 rx_class_counter[MU_UL_MAX][RX_CLASSIFICATION_MAX];
+       u32 rx_class_int_counter[MU_UL_MAX];
+       u32 counter_timer_trigger_ll1[MU_UL_MAX];
+       u32 counter_timer_trigger_ll2[MU_UL_MAX];
+       u32 total_rx_packets[MU_UL_MAX];
+       u32 total_agg_packets[MU_UL_MAX];
+       u32 rx_fifo_overflow_err_cnt[MU_UL_MAX];
+       u32 rx_dma_discard_cnt;
+       u32 host_rxelem_not_ready_cnt;
+       u32 msdu_host_rxelem_not_ready_cnt;
+       u32 dma_rx_pool_not_ready_cnt;
+       u32 rx_pckt_exceed_max_len_cnt[MU_UL_MAX];
+       u32 rx_pckt_bad_ba_statinfo_cnt[MU_UL_MAX];
+       u32 nav_value[MU_UL_MAX];
+       u16 max_mpdu_data_len[MU_UL_MAX];
+       u8 rhd_ll2_max_cnt[MU_UL_MAX]; /* Rhd first list */
+       u8 rhd_ll1_max_cnt[MU_UL_MAX]; /* Rhd second list */
+       u8 cca_busy_percent;
+       u8 rx_mine_busy_percent;
+       u8 tx_mine_busy_percent;
+       u8 sample_cnt;
+       /* Emb handled frames */
+       u32 emb_ll1_handled_frame_counter[MU_UL_MAX][MAX_HANDLED_FRM_TYPE];
+       u32 rxm_stats_overflow[MU_UL_MAX];
+       /* RX AMSDU statistics counters */
+       u32 stats_tot_rx_amsdu_cnt[MU_UL_MAX];
+       u32 stats_rx_amsdu_cnt[MU_UL_MAX][RX_MAX_MSDU_IN_SINGLE_AMSDU];
+       u32 stats_rx_amsdu_err[MU_UL_MAX][AMSDU_DEAGGREGATION_ERR_MAX];
+       u32 stats_rx_format[FORMATMOD_MAX];
+       /* RX decryption error */
+       u32 decrypt_err[RHD_DECR_IDX_MAX];
+       u32 rx_incorrect_format_mode[MU_UL_MAX];
+       u32 fcs_error_counter[MU_UL_MAX];
+       u32 phy_error_counter[MU_UL_MAX];
+       u32 ampdu_received_counter[MU_UL_MAX];
+       u32 delimiter_error_counter[MU_UL_MAX];
+       u32 ampdu_incorrect_received_counter[MU_UL_MAX];
+       u32 correct_received_mpdu[MU_UL_MAX];
+       u32 incorrect_received_mpdu[MU_UL_MAX];
+       u32 discarded_mpdu[MU_UL_MAX];
+       u32 incorrect_delimiter[MU_UL_MAX];
+       u32 rxm_mpdu_cnt[MU_UL_MAX];
+       u32 rxm_rule0_match[MU_UL_MAX];
+       u32 rxm_rule1_match[MU_UL_MAX];
+       u32 rxm_rule2_match[MU_UL_MAX];
+       u32 rxm_rule3_match[MU_UL_MAX];
+       u32 rxm_rule4_match[MU_UL_MAX];
+       u32 rxm_rule5_match[MU_UL_MAX];
+       u32 rxm_rule6_match[MU_UL_MAX];
+       u32 rxm_default_rule_match[MU_UL_MAX];
+       u32 rxm_amsdu_1[MU_UL_MAX];
+       u32 rxm_amsdu_2[MU_UL_MAX];
+       u32 rxm_amsdu_3[MU_UL_MAX];
+       u32 rxm_amsdu_4[MU_UL_MAX];
+       u32 rxm_amsdu_5_15[MU_UL_MAX];
+       u32 rxm_amsdu_16_or_more[MU_UL_MAX];
+       u32 frequency_offset[FREQ_OFFSET_TABLE_IDX_MAX];
+       u32 frequency_offset_idx;
+       u32 rts_bar_cnt[MU_UL_MAX];
+};
+
+enum trigger_flow_single_trigger_type {
+       TRIGGER_FLOW_BASIC_TRIGGER_TYPE,
+       TRIGGER_FLOW_BSRP_TYPE,
+       TRIGGER_FLOW_BFRP_TYPE,
+       TRIGGER_FLOW_MAX
+};
+
+struct cl_trigger_flow_statistics {
+       u32 type; /* This field should be first in the struct */
+       u32 single_trigger_sent[TRIGGER_FLOW_MAX][AC_MAX];
+       u32 htp_rx_failure[AC_MAX];
+       u32 trigger_based_mpdu[MU_UL_MAX];
+};
+
+#define DYN_CAL_DEBUG_NUM_ITER  3
+
+struct dyn_cal_debug_info_t {
+       u16 calib_num;
+       u8 curr_config;
+       union {
+               struct {
+                       u8 iter_num;
+                       u32 measured_val;
+               };
+               struct {
+                       u8 min_config;
+                       u32 dyn_cal_min_val;
+                       u32 dyn_cal_max_val;
+                       u8 max_config;
+               };
+       };
+
+       u8 new_config;
+};
+
+struct cl_dyn_calib_statistics {
+       u32 type; /* This field should be first in the struct */
+       u8 is_multi_client_mode;
+       u8 default_dyn_cal_val;
+       u8 dyn_cal_debug_info_ix;
+       u16 dyn_cal_process_cnt;
+       u16 mac_phy_sync_err_cnt;
+       struct dyn_cal_debug_info_t dyn_cal_debug_info[DYN_CAL_DEBUG_NUM_ITER];
+};
+
+struct ac_info_t {
+       u8 active_session;
+       u32 total_q_switch_cnt;
+       u32 total_ac_desc_cnt;
+       u8 mult_ampdu_in_txop_cnt;
+};
+
+/* End of parameters that require host changes */
+
+/* Structure containing the parameters for assert prints DBG_PRINT_IND message. */
+struct dbg_print_ind {
+       __le16 file_id;
+       __le16 line;
+       __le16 has_param;
+       u8 err_no_dump;
+       u8 reserved;
+       __le32 param;
+};
+
+enum {
+       CE_TXL_TX_PATH_IDLE,
+       CE_TXL_TX_PATH_START,
+       CE_TXL_TX_PATH_POST_START_DOWNLOAD,
+       CE_TXL_TX_PATH_TX_DATA_DOWNLOADING,
+       CE_TXL_TX_PATH_MU_RECOVERY,
+       CE_TXL_TX_PATH_LAST_DOWNLOADING,
+       CE_TXL_TX_PATH_NEXT_SESSION_PREPARED,
+       CE_TXL_TX_PATH_MU_NEXT_JOB_READY,
+       CE_TXL_TX_PATH_MAX
+};
+
+/* 4 ACs + BCN + HTP + current THD */
+#define MACHW_THD_REGS_CNT (IPC_TX_QUEUE_CNT + 2)
+
+/* Enumeration of MAC-HW registers (debug dump at recovery event) */
+enum {
+       HAL_MACHW_AGGR_STATUS,
+       HAL_MACHW_DEBUG_HWSM_1,
+       HAL_MACHW_DEBUG_HWSM_2,
+       HAL_MACHW_DEBUG_HWSM_3,
+       HAL_MACHW_DMA_STATUS_1,
+       HAL_MACHW_DMA_STATUS_2,
+       HAL_MACHW_DMA_STATUS_3,
+       HAL_MACHW_DMA_STATUS_4,
+       HAL_MACHW_RX_HEADER_H_PTR,
+       HAL_MACHW_RX_PAYLOAD_H_PTR,
+       HAL_MACHW_DEBUG_BCN_S_PTR,
+       HAL_MACHW_DEBUG_AC0_S_PTR,
+       HAL_MACHW_DEBUG_AC1_S_PTR,
+       HAL_MACHW_DEBUG_AC2_S_PTR,
+       HAL_MACHW_DEBUG_AC3_S_PTR,
+       HAL_MACHW_DEBUG_HTP_S_PTR,
+       HAL_MACHW_DEBUG_TX_C_PTR,
+       HAL_MACHW_DEBUG_RX_HDR_C_PTR,
+       HAL_MACHW_DEBUG_RX_PAY_C_PTR,
+       HAL_MACHW_MU0_TX_POWER_LEVEL_DELTA_1,
+       HAL_MACHW_MU0_TX_POWER_LEVEL_DELTA_2,
+       HAL_MACHW_POWER_BW_CALIB_FACTOR,
+       HAL_MACHW_TX_POWER_ANTENNA_FACTOR_1_ADDR,
+       HAL_MACHW_TX_POWER_ANTENNA_FACTOR_2_ADDR,
+       /* Keep this entry last */
+       HAL_MACHW_REG_NUM
+};
+
+#define HAL_MACHW_FSM_REG_NUM ((HAL_MACHW_DEBUG_HWSM_3 - HAL_MACHW_AGGR_STATUS) + 1)
+
+enum {
+       MPU_COMMON_FORMAT,
+       MPU_COMMON_FIELD_CTRL,
+       MPU_COMMON_LEGACY_INFO,
+       MPU_COMMON_COMMON_CFG_1,
+       MPU_COMMON_COMMON_CFG_2,
+       MPU_COMMON_COMMON_CFG_3,
+       MPU_COMMON_HE_CFG_1,
+       MPU_COMMON_HE_CFG_2,
+       MPU_COMMON_INT_STAT_RAW,
+       RIU_CCAGENSTAT,
+       PHY_HW_DBG_REGS_CNT
+};
+
+/* Error trace CE_AC info */
+struct dbg_ac_info {
+       u8 chk_state;
+       u8 tx_path_state;
+       u8 physical_queue_idx;
+       u16 active_session;
+       u32 last_frame_exch_ptr;
+};
+
+/* Error trace txdesc lists info */
+struct dbg_txlist_info {
+       u8 curr_session_idx;
+       u8 next_session_idx;
+       u16 pending_cnt;
+       u16 download_cnt;
+       u16 transmit_cnt;
+       u16 wait_for_ba_cnt;
+       u16 next_pending_cnt;
+};
+
+enum {
+       SING_FRM_TYPE,
+       AGG_FRM_TYPE,
+       AGG_NEXT_IN_TXOP_FRM_TYPE,
+       INT_FRM_TYPE,
+       BCN_FRM_TYPE,
+       MU_FRM_TYPE,
+       FRM_TYPE_BASIC_TRIGGER,
+       FRM_TYPE_MU_BAR_TRIGGER,
+       BCK_BCN_TYPE,
+       TB_FRT_TYPE,
+       QOS_NULL,
+       AGG_TB,
+       RTS_TYPE,
+       CTS_TYPE,
+       TB_SINGLE_FRM_TYPE,
+       TF_AMPDU_TYPE,
+       CL_MAX_FRM_TYPE,
+};
+
+/* Txl chain info */
+struct cl_dbg_txl_chain_info {
+       u32 count;
+       u32 frm_type;
+       u32 first_thd_ptr;
+       u32 last_thd_ptr;
+       u32 prev_thd_ptr;
+       u32 req_phy_flags;
+       u8 reqbw;
+       u8 ce_txq_idx;
+       u16 mpdu_count;
+       u8 chbw;
+       u32 rate_ctrl_info;
+       u32 rate_ctrl_info_he;
+       u32 txstatus;
+       u32 length;
+       u32 tx_time;
+};
+
+struct dbg_txl_ac_chain_trace {
+       struct cl_dbg_txl_chain_info data[DBG_TXL_FRAME_EXCH_TRACE_DEPTH];
+       u32 count;
+       u8 next_chain_index;
+       u8 next_done_index;
+       u8 delta;
+};
+
+struct dbg_fw_trace {
+       u32 string_ptr;
+       u32 var_1;
+       u32 var_2;
+       u32 var_3;
+       u32 var_4;
+       u32 var_5;
+       u32 var_6;
+       /*
+        * This field is used only for driver pring dump file.
+        * collect string char is done at error dump collect data function.
+        */
+       char string_char[DBG_FW_TRACE_STR_MAX];
+};
+
+/* Error trace MAC-FW info */
+struct dbg_fw_info {
+       struct dbg_ac_info ac_info[CE_AC_MAX];
+       struct dbg_txlist_info txlist_info_singles[IPC_TX_QUEUE_CNT];
+       struct dbg_txlist_info txlist_info_agg[AGG_IDX_MAX];
+       struct dbg_txl_ac_chain_trace txl_ac_chain_trace[CE_AC_MAX];
+       struct dbg_fw_trace fw_trace[DBG_FW_TRACE_SIZE];
+       u32 fw_trace_idx;
+};
+
+/* TXM regs */
+struct dbg_txm_regs {
+       u8 hw_state;
+       u8 fw_state;
+       u8 spx_state;
+       u8 free_buf_state;
+       u8 mpdu_cnt;
+       u8 lli_cnt;
+       u8 lli_done_reason;
+       u8 lli_done_mpdu_num;
+       u16 active_bytes;
+       u16 prefetch_bytes;
+       u32 last_thd_done_addr;
+       u16 last_thd_done_mpdu_num;
+       u16 underrun_cnt;
+};
+
+/* Error trace HW registers */
+struct dbg_hw_reg_info {
+       u32 mac_hw_reg[HAL_MACHW_REG_NUM];
+       u32 mac_hw_sec_fsm[CL_MU_IDX_MAX][HAL_MACHW_FSM_REG_NUM];
+       u32 phy_mpu_hw_reg[PHY_HW_DBG_REGS_CNT];
+       struct dbg_txm_regs txm_regs[AGG_IDX_MAX];
+};
+
+struct dbg_meta_data {
+       __le32 lmac_req_buf_size;
+       u8 physical_queue_cnt;
+       u8 agg_index_max;
+       u8 ce_ac_max;
+       u8 mu_user_max;
+       u8 txl_exch_trace_depth;
+       __le16 mac_hw_regs_max;
+       __le16 phy_hw_regs_max;
+       __le16 thd_chains_data_size;
+       u8 chains_info_elem_cnt;
+};
+
+struct dbg_agg_thds_addr {
+       u32 rts_cts_thd_addr;
+       u32 athd_addr;
+       u32 tf_thd_addr;
+       u32 bar_thd_addr;
+       u32 policy_table_addr;
+};
+
+struct dbg_agg_thd_info {
+       struct tx_hd rts_cts_thd;
+       struct tx_hd athd;
+       struct tx_hd tf_thd;
+       struct tx_hd bar_thd;
+       struct tx_policy_tbl policy_table;
+};
+
+struct dbg_machw_regs_thd_info {
+       struct tx_hd thd[MACHW_THD_REGS_CNT];
+};
+
+struct dbg_thd_chains_info {
+       u8 type_array[DBG_CHAINS_INFO_ELEM_CNT];
+       u32 elem_address[DBG_CHAINS_INFO_ELEM_CNT];
+};
+
+struct dbg_thd_chains_data {
+       u8 data[DBG_THD_CHAINS_INFO_ARRAY_SIZE];
+};
+
+/* Error trace debug structure. common to fw & drv */
+struct dbg_error_trace_info_common {
+       struct dbg_print_ind error_info;
+       struct dbg_meta_data dbg_metadata;
+       struct dbg_hw_reg_info hw_info;
+       struct dbg_fw_info fw_info;
+       struct dbg_agg_thds_addr agg_thds_addr[AGG_IDX_MAX];
+};
+
+/* Dbg error info driver side */
+struct dbg_error_trace_info_drv {
+       struct dbg_error_trace_info_common common_info;
+       struct dbg_agg_thd_info agg_thd_info[AGG_IDX_MAX];
+       struct dbg_machw_regs_thd_info machw_thd_info;
+       struct dbg_thd_chains_info thd_chains_info[CE_AC_MAX];
+       struct dbg_thd_chains_data thd_chains_data[CE_AC_MAX];
+};
+
+/*
+ * This is the main debug struct, the kernel allocate the needed spaces using kmalloc().
+ * the firmware holds a pointer to this struct.
+ */
+struct dbg_dump_info {
+       u32 dbg_info; /* Should be first member in the struct */
+       /* Dump data transferred to host */
+       struct dbg_debug_info_tag general_data;
+       struct dbg_error_trace_info_drv fw_dump;
+       u8 la_mem[LA_CNT][LA_MEM_LEN];
+};
+
+struct dbg_info {
+       union {
+               u32 type;
+               struct dbg_dump_info dump;
+               struct cl_txl_statistics tx_stats;
+               struct cl_bcn_statistics bcn_stats;
+               struct cl_rxl_statistics rx_stats;
+               struct cl_dyn_calib_statistics dyn_calib_stats;
+               struct cl_rate_drop_statistics rate_drop_stats;
+               struct cl_bf_statistics bf_stats;
+               struct cl_trigger_flow_statistics trigger_flow_stats;
+       } u;
+};
+
+/* Structure of a list element header */
+struct co_list_hdr {
+       __le32 next;
+};
+
+/* ETH2WLAN and NATT common parameters field (e2w_natt_param) struct definition: */
+struct cl_e2w_natt_param {
+#ifdef __LITTLE_ENDIAN_BITFIELD
+       u32 valid           : 1,  /* [0] */
+           ampdu           : 1,  /* [1] */
+           last_mpdu       : 1,  /* [2] */
+           lc_snap         : 1,  /* [3] */
+           vlan            : 1,  /* [4] */
+           amsdu           : 1,  /* [5] */
+           e2w_band_id     : 1,  /* [6] */
+           use_local_addr  : 1,  /* [7] */
+           hdr_conv_enable : 1,  /* [8] */
+           sta_index       : 7,  /* [9:15] */
+           packet_length   : 15, /* [30:16] */
+           e2w_int_enable  : 1;  /* [31] */
+#else /* __BIG_ENDIAN_BITFIELD */
+       u32 e2w_int_enable  : 1,  /* [0] */
+           packet_length   : 15, /* [15:1] */
+           sta_index       : 7,  /* [22:16] */
+           hdr_conv_enable : 1,  /* [23] */
+           use_local_addr  : 1,  /* [24] */
+           e2w_band_id     : 1,  /* [25] */
+           amsdu           : 1,  /* [26] */
+           vlan            : 1,  /* [27] */
+           llc_snap        : 1,  /* [28] */
+           last_mpdu       : 1,  /* [29] */
+           ampdu           : 1,  /* [30] */
+           valid           : 1;  /* [31] */
+#endif
+};
+
+#define CL_CCMP_GCMP_PN_SIZE 6
+
+struct cl_e2w_txhdr_param {
+       __le16 frame_ctrl;
+       __le16 seq_ctrl;
+       __le32 ht_ctrl;
+       u8 encrypt_pn[CL_CCMP_GCMP_PN_SIZE];
+       __le16 qos_ctrl;
+};
+
+/* This structure is not filled by the driver, so there is no need to support LITTLE/BIG ENDIAN */
+struct cl_natt_result {
+       u32 n_zld     : 16, /* [15:0] Number of Zero-Length Delimiters */
+           reserved  : 15, /* [30:16] */
+           natt_done : 1;  /* [31] NATT Tx Descriptor */
+};
+
+/* Bit 16 Has different usage for single (valid sta - set by host) or agg (tx done - set by HW) */
+struct cl_e2w_result {
+#ifdef __LITTLE_ENDIAN_BITFIELD
+       u32 backup_bcn                        : 1,  /* [0] */
+           dont_chain                        : 1,  /* [1] */
+           is_flush_needed                   : 1,  /* [2] */
+           is_internal                       : 1,  /* [3] */
+           which_descriptor                  : 2,  /* [5:4] */
+           is_first_in_AMPDU                 : 1,  /* [6] */
+           is_ext_buff                       : 1,  /* [7] */
+           is_txinject                       : 1,  /* [8] */
+           is_vns                            : 1,  /* [9] */
+           single_type                       : 2,  /* [11:10] */
+           tid                               : 4,  /* [15:12] */
+           single_valid_sta__agg_e2w_tx_done : 1,  /* [16] */
+           msdu_length                       : 13, /* [29:17] */
+           bcmc                              : 1,  /* [30] */
+           sw_padding                        : 1;  /* [31] */
+#else /* __BIG_ENDIAN_BITFIELD */
+       u32 sw_padding                        : 1,  /* [0] */
+           bcmc                              : 1,  /* [1] */
+           msdu_length                       : 13, /* [14:2] */
+           single_valid_sta__agg_e2w_tx_done : 1,  /* [15] */
+           tid                               : 4,  /* [19:16] */
+           single_type                       : 2,  /* [21:20] */
+           is_vns                            : 1,  /* [22] */
+           is_txinject                       : 1,  /* [23] */
+           is_ext_buff                       : 1,  /* [24] */
+           is_first_in_AMPDU                 : 1,  /* [25] */
+           which_descriptor                  : 2,  /* [27:26] */
+           is_internal                       : 1,  /* [28] */
+           is_flush_needed                   : 1,  /* [29] */
+           dont_chain                        : 1,  /* [30] */
+           backup_bcn                        : 1;  /* [31] */
+#endif
+};
+
+struct tx_host_info {
+#ifdef __LITTLE_ENDIAN_BITFIELD
+       u32 packet_cnt               : 4, /* [3:0] */
+           host_padding             : 8, /* [11:4] */
+           last_MSDU_LLI_INT_enable : 1, /* [12] */
+           is_eth_802_3             : 1, /* [13] */
+           is_protected             : 1, /* [14] */
+           vif_index                : 4, /* [18:15] */
+           rate_ctrl_entry          : 3, /* [21:19] */
+           expected_ack             : 1, /* [22] */
+           is_bcn                   : 1, /* [23] */
+           hw_key_idx               : 8; /* [31:24] */
+#else /* __BIG_ENDIAN_BITFIELD */
+       u32 hw_key_idx               : 8, /* [7:0] */
+           is_bcn                   : 1, /* [8] */
+           expected_ack             : 1, /* [9] */
+           rate_ctrl_entry          : 3, /* [12:10] */
+           vif_index                : 4, /* [16:13] */
+           is_protected             : 1, /* [17] */
+           is_eth_802_3             : 1, /* [18] */
+           last_MSDU_LLI_INT_enable : 1, /* [19] */
+           host_padding             : 8, /* [27:20] */
+           packet_cnt               : 4; /* [31:28] */
+#endif
+};
+
+struct lmacapi {
+       __le32 packet_addr[CL_AMSDU_TX_PAYLOAD_MAX];
+       __le16 packet_len[CL_AMSDU_TX_PAYLOAD_MAX];
+       __le16 push_timestamp; /* Milisec */
+};
+
+struct lmacpriv {
+       __le32 buffer;
+};
+
+struct txdesc {
+       /* Pointer to the next element in the queue */
+       struct co_list_hdr list_hdr;
+       /* E2w txhdr parameters */
+       struct cl_e2w_txhdr_param e2w_txhdr_param __aligned(4);
+       /* Celeno flags field */
+       struct tx_host_info host_info __aligned(4);
+       /* Common parameters for ETH2WLAN and NATT hardware modules */
+       struct cl_e2w_natt_param  e2w_natt_param;
+       /* ETH2WLAN status and NATT calculation results */
+       struct cl_e2w_result e2w_result;
+       /* Information provided by UMAC to LMAC */
+       struct lmacapi umacdesc;
+};
+
+/*
+ * Comes from ipc_dma.h
+ * Element in the pool of TX DMA bridge descriptors.
+ * PAY ATTENTION - Avoid Changing/adding pointers to that struct,
+ * or any shared-memory-related-structs !!!
+ * Since in 64Bit platforms (Where pointers are 64Bit) such pointers
+ * might change alignments in shared-memory-related-structs of FW and DRV.
+ */
+struct dma_desc {
+       /*
+        * Application subsystem address which is used as source address for DMA payload
+        * transfer
+        */
+       u32 src;
+       /*
+        * Points to the start of the embedded data buffer associated with this descriptor.
+        * This address acts as the destination address for the DMA payload transfer
+        */
+       u32 dest;
+       /* Complete length of the buffer in memory */
+       u16 length;
+       /* Control word for the DMA engine (e.g. for interrupt generation) */
+       u16 ctrl;
+       /* Pointer to the next element of the chained list */
+       u32 next;
+       /*
+        * When working with 64bit application the high 32bit address should be provided
+        * in the following variable (note: "PCIEW_CONF" register should be configured accordingly)
+        */
+       u32 app_hi_32bit;
+};
+
+struct dma_desc_hdr {
+       struct co_list_hdr list_hdr;
+       struct dma_desc dma_desc;
+};
+
+enum {
+       DBG_ERROR_RECOVERABLE = 0,
+       DBG_ERROR_FATAL
+};
+
+/* Message structure for CFMs from Emb to App */
+struct cl_ipc_cfm_msg {
+       __le32 status;
+       __le32 dma_addr;
+       __le32 single_queue_idx;
+};
+
+/* Message structure for Debug messages from Emb to App */
+struct cl_ipc_dbg_msg {
+       char string[IPC_DBG_PARAM_SIZE];
+       __le32 pattern;
+};
+
+/*
+ * Message structure for MSGs from App to Emb.
+ * Actually a sub-structure will be used when filling the messages.
+ */
+struct cl_ipc_a2e_msg {
+       u32 dummy_word;
+       u32 msg[IPC_A2E_MSG_BUF_SIZE];
+};
+
+/* Struct for tensilica  backtrace */
+struct cl_ipc_backtrace_struct {
+       u32 pc[IPC_BACKTRACT_DEPTH];
+};
+
+/* Struct for tensilica  exception indication */
+struct cl_ipc_exception_struct {
+       u32 pattern;
+       u32 type;
+       u32 epc;
+       u32 excsave;
+       struct cl_ipc_backtrace_struct backtrace;
+};
+
+/*
+ * Can't use BITS_TO_LONGS since in firmware sizeof(long) == 4 and in the host
+ * this might be different from compiler to compiler. We need our own macro to
+ * match the firmware definition.
+ */
+#define CL_BITS_TO_U32S(nr) DIV_ROUND_UP(nr, BITS_PER_BYTE * sizeof(u32))
+
+/*
+ * struct cl_ipc_enhanced_tim - ipc enhanced tim element
+ *
+ * This structure hold indication on the buffered traffic resembles the TIM element.
+ * This enhanced TIM holds more info on the buffered traffic, it indicate whether the
+ * traffic is associated with BA or singles and on which AC's.
+ *
+ * @tx_agg: indicate buffered tx-aggregated traffic per AC per BA session index
+ * @tx_single: indicate buffered tx-singles traffic per AC per station index
+ * @rx: indicate buffered rx traffic per AC per station index
+ */
+struct cl_ipc_enhanced_tim {
+       /*
+        * Traffic indication map
+        * our driver push packets to the IPC queues (DRIVER_LAYER -> IPC_LAYER),
+        * on each push it also notify the IPC_LAYER for which queue it pushed packets.
+        * this indication done by filling the bitmap.
+        *
+        * this is enhanced tim element because it is divided into AC and packet type
+        * (aggregatable/non aggregatable).
+        * the regular tim element which exist in the beacon is divided by AID only
+        * which is less informative.
+        *
+        * TODO: add TIM element maintenance in the FW, this can be achieved by the
+        * enhanced tim elements abstraction.
+        */
+       u32 tx_rx_agg[AC_MAX][CL_BITS_TO_U32S(IPC_TIM_AGG_SIZE)];
+       u32 tx_single[AC_MAX][CL_BITS_TO_U32S(FW_MAX_NUM_STA)];
+};
+
+struct cl_ipc_shared_env {
+       volatile struct cl_ipc_a2e_msg a2e_msg_buf;
+       /* Fields for MSGs sending from Emb to App */
+       volatile struct cl_ipc_e2a_msg e2a_msg_buf;
+       volatile struct dma_desc msg_dma_desc;
+       volatile __le32 e2a_msg_hostbuf_addr[IPC_E2A_MSG_BUF_CNT];
+       /* Fields for Debug MSGs sending from Emb to App */
+       volatile struct cl_ipc_dbg_msg dbg_buf;
+       volatile struct dma_desc dbg_dma_desc;
+       volatile __le32 dbg_hostbuf_addr[IPC_DBG_BUF_CNT];
+       volatile __le32 dbginfo_addr;
+       volatile __le32 dbginfo_size;
+       volatile __le32 pattern_addr;
+       volatile __le32 radarbuf_hostbuf[IPC_RADAR_BUF_CNT]; /* Buffers for radar events */
+       /* Used to update host general debug data */
+       volatile struct dma_desc dbg_info_dma_desc;
+       /*
+        * The following members are associated ith the process of fetching
+        * "application txdesc" from the application and copy them to the
+        * internal embedded queues.
+        *
+        * @host_address_dma: dedicated dma descriptor to fetch the addresses of
+        * "application txdesc" queues
+        * @write_dma_desc_pool: dedicated dma descriptor to fetch the "@txdesc_emb_wr_idx"
+        * index (dma for application txdesc metadata)
+        * @last_txdesc_dma_desc_pool: dedicated dma descriptor to fetch "application txdescs"
+        * (dma for application txdesc)
+        * @txdesc_emb_wr_idx: indicate the last valid "application txdesc" fetched
+        */
+       volatile struct dma_desc host_address_dma;
+       volatile struct dma_desc tx_power_tables_dma_desc;
+       volatile __le32 txdesc_emb_wr_idx[IPC_TX_QUEUE_CNT + CL_MAX_BA_PHYSICAL_QUEUE_CNT];
+       volatile __le32 host_rxbuf_rd_idx[CL_RX_BUF_MAX];                       /* For FW only */
+       volatile struct dma_desc rx_fw_hb_pool_dma_desc[HB_POOL_DMA_DESCS_NUM]; /* For FW only */
+       volatile struct dma_desc rxm_hb_pool_dma_desc[HB_POOL_DMA_DESCS_NUM];   /* For FW only */
+       volatile __le32 cfm_read_pointer; /* CFM read point. Updated by Host, Read by FW */
+       volatile __le16 phy_dev;
+       volatile u8 la_enable;
+       volatile u8 flags;
+       volatile __le16 max_retry;
+       volatile __le16 lft_limit_ms;
+       volatile __le16 bar_max_retry; /* Not used by driver */
+       volatile __le32 assert_pattern;
+       volatile __le16 assert_file_id;
+       volatile __le16 assert_line_num;
+       volatile __le32 assert_param;
+       volatile struct cl_ipc_enhanced_tim enhanced_tim;
+};
+
+/* IRQs from app to emb */
+#define IPC_IRQ_A2E_TXDESC     0xFF00
+#define IPC_IRQ_A2E_RXBUF_BACK BIT(2)
+#define IPC_IRQ_A2E_MSG        BIT(1)
+#define IPC_IRQ_A2E_RXREQ      0x78
+#define IPC_IRQ_A2E_ALL        (IPC_IRQ_A2E_TXDESC | IPC_IRQ_A2E_MSG)
+
+#define IPC_IRQ_A2E_TXDESC_FIRSTBIT 8
+#define IPC_IRQ_A2E_RXREQ_FIRSTBIT  3
+
+#define IPC_IRQ_A2E_TXDESC_AGG_MAP(ac)    (IPC_IRQ_A2E_TXDESC_FIRSTBIT + IPC_TXQ_CNT + (ac))
+#define IPC_IRQ_A2E_TXDESC_SINGLE_MAP(ac) (IPC_IRQ_A2E_TXDESC_FIRSTBIT + (ac))
+#define IPC_IRQ_A2E_RX_STA_MAP(ac)        (IPC_IRQ_A2E_RXREQ_FIRSTBIT + (ac))
+
+struct cl_ipc_e2a_irq {
+       u32 dbg;
+       u32 msg;
+       u32 rxdesc;
+       u32 txcfm;
+       u32 radar;
+       u32 txdesc_ind;
+       u32 tbtt;
+       u32 sync;
+       u32 all;
+};
+
+/*
+ * IRQs from emb to app
+ * This interrupt is used by the firmware to indicate the driver that it may proceed.
+ * The corresponding interrupt handler sets the CL_DEV_FW_SYNC flag in cl_hw->drv_flags.
+ * There is also the cl_hw->fw_sync_wq wait queue, on which we may sleep while waiting for
+ * the interrupt, if we are allowed to do so (e.g., when we are in a system call).
+ */
+#define IPC_IRQ_L2H_DBG        BIT(0)
+#define IPC_IRQ_L2H_MSG        BIT(1)
+#define IPC_IRQ_L2H_RXDESC     BIT(2)
+#define IPC_IRQ_L2H_TXCFM      0x000000F8
+#define IPC_IRQ_L2H_RADAR      BIT(8)
+#define IPC_IRQ_L2H_TXDESC_IND BIT(9)
+#define IPC_IRQ_L2H_TBTT       BIT(10)
+#define IPC_IRQ_L2H_SYNC       BIT(11)
+
+#define IPC_IRQ_L2H_ALL          \
+       (IPC_IRQ_L2H_TXCFM |     \
+       IPC_IRQ_L2H_RXDESC |     \
+       IPC_IRQ_L2H_MSG |        \
+       IPC_IRQ_L2H_DBG |        \
+       IPC_IRQ_L2H_RADAR |      \
+       IPC_IRQ_L2H_TXDESC_IND | \
+       IPC_IRQ_L2H_TBTT |       \
+       IPC_IRQ_L2H_SYNC)
+
+#define IPC_IRQ_S2H_DBG        BIT(12)
+#define IPC_IRQ_S2H_MSG        BIT(13)
+#define IPC_IRQ_S2H_RXDESC     BIT(14)
+#define IPC_IRQ_S2H_TXCFM      0x000F8000
+#define IPC_IRQ_S2H_RADAR      BIT(20)
+#define IPC_IRQ_S2H_TXDESC_IND BIT(21)
+#define IPC_IRQ_S2H_TBTT       BIT(22)
+#define IPC_IRQ_S2H_SYNC       BIT(23)
+
+#define IPC_IRQ_S2H_ALL          \
+       (IPC_IRQ_S2H_TXCFM |     \
+       IPC_IRQ_S2H_RXDESC |     \
+       IPC_IRQ_S2H_MSG |        \
+       IPC_IRQ_S2H_DBG |        \
+       IPC_IRQ_S2H_RADAR |      \
+       IPC_IRQ_S2H_TXDESC_IND | \
+       IPC_IRQ_S2H_TBTT |       \
+       IPC_IRQ_S2H_SYNC)
+
+#endif /* CL_IPC_SHARED_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.
________________________________


^ permalink raw reply related	[flat|nested] 262+ messages in thread

* [RFC v1 103/256] cl8k: add key.c
  2021-06-17 15:58 [RFC v1 000/256] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (101 preceding siblings ...)
  2021-06-17 15:59 ` [RFC v1 102/256] cl8k: add ipc_shared.h viktor.barna
@ 2021-06-17 15:59 ` viktor.barna
  2021-06-17 15:59 ` [RFC v1 104/256] cl8k: add key.h viktor.barna
                   ` (154 subsequent siblings)
  257 siblings, 0 replies; 262+ messages in thread
From: viktor.barna @ 2021-06-17 15:59 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Oleksandr Savchenko, Shay Bar, Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

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

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 drivers/net/wireless/celeno/cl8k/key.c | 197 +++++++++++++++++++++++++
 1 file changed, 197 insertions(+)
 create mode 100644 drivers/net/wireless/celeno/cl8k/key.c

diff --git a/drivers/net/wireless/celeno/cl8k/key.c b/drivers/net/wireless/celeno/cl8k/key.c
new file mode 100644
index 000000000000..276c2e76e126
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/key.c
@@ -0,0 +1,197 @@
+// SPDX-License-Identifier: MIT
+/* Copyright(c) 2019-2021, Celeno Communications Ltd. */
+
+#include "key.h"
+#include "fw/msg_tx.h"
+#include "fw/fw_msg.h"
+#include "sta.h"
+#include "tx/single_cfm.h"
+#include "tx/agg_cfm.h"
+#include "tx/tx_queue.h"
+
+static int cmd_set_key(struct cl_hw *cl_hw,
+                      struct ieee80211_vif *vif,
+                      struct ieee80211_sta *sta,
+                      struct ieee80211_key_conf *key)
+{
+       int error = 0;
+       struct mm_key_add_cfm *key_add_cfm;
+       u8 cipher_suite = 0;
+
+       /* Retrieve the cipher suite selector */
+       switch (key->cipher) {
+       case WLAN_CIPHER_SUITE_WEP40:
+               cipher_suite = MAC_CIPHER_SUITE_WEP40;
+               break;
+       case WLAN_CIPHER_SUITE_WEP104:
+               cipher_suite = MAC_CIPHER_SUITE_WEP104;
+               break;
+       case WLAN_CIPHER_SUITE_TKIP:
+               cipher_suite = MAC_CIPHER_SUITE_TKIP;
+               break;
+       case WLAN_CIPHER_SUITE_CCMP:
+               cipher_suite = MAC_CIPHER_SUITE_CCMP;
+               break;
+       case WLAN_CIPHER_SUITE_GCMP:
+       case WLAN_CIPHER_SUITE_GCMP_256:
+               cipher_suite = MAC_CIPHER_SUITE_GCMP;
+               break;
+       case WLAN_CIPHER_SUITE_AES_CMAC:
+               return -EOPNOTSUPP;
+       default:
+               return -EINVAL;
+       }
+
+       error = cl_msg_tx_key_add(cl_hw, vif, sta, key, cipher_suite);
+       if (error)
+               return error;
+
+       key_add_cfm = (struct mm_key_add_cfm *)(cl_hw->msg_cfm_params[MM_KEY_ADD_CFM]);
+       if (!key_add_cfm)
+               return -ENOMSG;
+
+       if (key_add_cfm->status != 0) {
+               cl_dbg_verbose(cl_hw, "Status Error (%u)\n", key_add_cfm->status);
+               cl_msg_tx_free_cfm_params(cl_hw, MM_KEY_ADD_CFM);
+               return -EIO;
+       }
+
+       /* Save the index retrieved from firmware */
+       key->hw_key_idx = key_add_cfm->hw_key_idx;
+
+       cl_msg_tx_free_cfm_params(cl_hw, MM_KEY_ADD_CFM);
+
+       /*
+        * Now inform mac80211 about our choices regarding header fields generation:
+        * we let mac80211 take care of all generations
+        */
+       key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
+       if (key->cipher == WLAN_CIPHER_SUITE_TKIP)
+               key->flags |= IEEE80211_KEY_FLAG_GENERATE_MMIC;
+
+       if (sta) {
+               struct cl_sta *cl_sta = (struct cl_sta *)sta->drv_priv;
+
+               cl_sta->key_conf = key;
+       } else {
+               struct cl_vif *cl_vif = (struct cl_vif *)vif->drv_priv;
+
+               cl_vif->key_conf = key;
+       }
+
+       return error;
+}
+
+static int cmd_disable_key(struct cl_hw *cl_hw,
+                          struct ieee80211_vif *vif,
+                          struct ieee80211_sta *sta,
+                          struct ieee80211_key_conf *key)
+{
+       if (sta) {
+               struct cl_sta *cl_sta = (struct cl_sta *)sta->drv_priv;
+
+               cl_sta->key_conf = NULL;
+               cl_sta->key_disable = true;
+
+               /*
+                * Make sure there aren't any packets in firmware before deleting the key,
+                * otherwise they will be transmitted without encryption.
+                */
+               cl_txq_flush_sta(cl_hw, cl_sta);
+               cl_single_cfm_poll_empty_sta(cl_hw, cl_sta->sta_idx);
+               cl_agg_cfm_poll_empty_sta(cl_hw, cl_sta);
+       } else {
+               struct cl_vif *cl_vif = (struct cl_vif *)vif->drv_priv;
+
+               cl_vif->key_conf = NULL;
+       }
+
+       return cl_msg_tx_key_del(cl_hw, key->hw_key_idx);
+}
+
+int cl_key_set(struct cl_hw *cl_hw,
+              enum set_key_cmd cmd,
+              struct ieee80211_vif *vif,
+              struct ieee80211_sta *sta,
+              struct ieee80211_key_conf *key)
+{
+       int error = 0;
+
+       switch (cmd) {
+       case SET_KEY:
+               error = cmd_set_key(cl_hw, vif, sta, key);
+               break;
+
+       case DISABLE_KEY:
+               error = cmd_disable_key(cl_hw, vif, sta, key);
+               break;
+
+       default:
+               error = -EINVAL;
+               break;
+       }
+
+       return error;
+}
+
+struct ieee80211_key_conf *cl_key_get(struct cl_sta *cl_sta)
+{
+       if (cl_sta->key_conf)
+               return cl_sta->key_conf;
+
+       if (cl_sta->cl_vif->key_conf)
+               return cl_sta->cl_vif->key_conf;
+
+       return NULL;
+}
+
+bool cl_key_is_cipher_ccmp_gcmp(struct ieee80211_key_conf *keyconf)
+{
+       u32 cipher;
+
+       if (!keyconf)
+               return false;
+
+       cipher = keyconf->cipher;
+
+       return ((cipher == WLAN_CIPHER_SUITE_CCMP) ||
+               (cipher == WLAN_CIPHER_SUITE_GCMP) ||
+               (cipher == WLAN_CIPHER_SUITE_GCMP_256));
+}
+
+void cl_key_ccmp_gcmp_pn_to_hdr(u8 *hdr, u64 pn, int key_id)
+{
+       hdr[0] = pn;
+       hdr[1] = pn >> 8;
+       hdr[2] = 0;
+       hdr[3] = 0x20 | (key_id << 6);
+       hdr[4] = pn >> 16;
+       hdr[5] = pn >> 24;
+       hdr[6] = pn >> 32;
+       hdr[7] = pn >> 40;
+}
+
+u8 cl_key_get_cipher_len(struct sk_buff *skb)
+{
+       struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
+       struct ieee80211_key_conf *key_conf = tx_info->control.hw_key;
+
+       if (key_conf) {
+               switch (key_conf->cipher) {
+               case WLAN_CIPHER_SUITE_WEP40:
+               case WLAN_CIPHER_SUITE_WEP104:
+                       return IEEE80211_WEP_IV_LEN;
+               case WLAN_CIPHER_SUITE_TKIP:
+                       return  IEEE80211_TKIP_IV_LEN;
+               case WLAN_CIPHER_SUITE_CCMP:
+                       return  IEEE80211_CCMP_HDR_LEN;
+               case WLAN_CIPHER_SUITE_CCMP_256:
+                       return  IEEE80211_CCMP_256_HDR_LEN;
+               case WLAN_CIPHER_SUITE_GCMP:
+               case WLAN_CIPHER_SUITE_GCMP_256:
+                       return  IEEE80211_GCMP_HDR_LEN;
+               }
+       }
+
+       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.
________________________________


^ permalink raw reply related	[flat|nested] 262+ messages in thread

* [RFC v1 104/256] cl8k: add key.h
  2021-06-17 15:58 [RFC v1 000/256] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (102 preceding siblings ...)
  2021-06-17 15:59 ` [RFC v1 103/256] cl8k: add key.c viktor.barna
@ 2021-06-17 15:59 ` viktor.barna
  2021-06-17 15:59 ` [RFC v1 105/256] cl8k: add mac80211.c viktor.barna
                   ` (153 subsequent siblings)
  257 siblings, 0 replies; 262+ messages in thread
From: viktor.barna @ 2021-06-17 15:59 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Oleksandr Savchenko, Shay Bar, Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

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

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 drivers/net/wireless/celeno/cl8k/key.h | 19 +++++++++++++++++++
 1 file changed, 19 insertions(+)
 create mode 100644 drivers/net/wireless/celeno/cl8k/key.h

diff --git a/drivers/net/wireless/celeno/cl8k/key.h b/drivers/net/wireless/celeno/cl8k/key.h
new file mode 100644
index 000000000000..9c9b9fe122f0
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/key.h
@@ -0,0 +1,19 @@
+/* SPDX-License-Identifier: MIT */
+/* Copyright(c) 2019-2021, Celeno Communications Ltd. */
+
+#ifndef CL_KEY_H
+#define CL_KEY_H
+
+#include "hw.h"
+
+int cl_key_set(struct cl_hw *cl_hw,
+              enum set_key_cmd cmd,
+              struct ieee80211_vif *vif,
+              struct ieee80211_sta *sta,
+              struct ieee80211_key_conf *key);
+struct ieee80211_key_conf *cl_key_get(struct cl_sta *cl_sta);
+bool cl_key_is_cipher_ccmp_gcmp(struct ieee80211_key_conf *keyconf);
+void cl_key_ccmp_gcmp_pn_to_hdr(u8 *hdr, u64 pn, int key_id);
+u8 cl_key_get_cipher_len(struct sk_buff *skb);
+
+#endif /* CL_KEY_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.
________________________________


^ permalink raw reply related	[flat|nested] 262+ messages in thread

* [RFC v1 105/256] cl8k: add mac80211.c
  2021-06-17 15:58 [RFC v1 000/256] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (103 preceding siblings ...)
  2021-06-17 15:59 ` [RFC v1 104/256] cl8k: add key.h viktor.barna
@ 2021-06-17 15:59 ` viktor.barna
  2021-06-17 15:59 ` [RFC v1 106/256] cl8k: add mac80211.h viktor.barna
                   ` (152 subsequent siblings)
  257 siblings, 0 replies; 262+ messages in thread
From: viktor.barna @ 2021-06-17 15:59 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Oleksandr Savchenko, Shay Bar, Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

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

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 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.
________________________________


^ permalink raw reply related	[flat|nested] 262+ messages in thread

* [RFC v1 106/256] cl8k: add mac80211.h
  2021-06-17 15:58 [RFC v1 000/256] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (104 preceding siblings ...)
  2021-06-17 15:59 ` [RFC v1 105/256] cl8k: add mac80211.c viktor.barna
@ 2021-06-17 15:59 ` viktor.barna
  2021-06-17 15:59 ` [RFC v1 107/256] cl8k: add mac_addr.c viktor.barna
                   ` (151 subsequent siblings)
  257 siblings, 0 replies; 262+ messages in thread
From: viktor.barna @ 2021-06-17 15:59 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Oleksandr Savchenko, Shay Bar, Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

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

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 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.
________________________________


^ permalink raw reply related	[flat|nested] 262+ messages in thread

* [RFC v1 107/256] cl8k: add mac_addr.c
  2021-06-17 15:58 [RFC v1 000/256] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (105 preceding siblings ...)
  2021-06-17 15:59 ` [RFC v1 106/256] cl8k: add mac80211.h viktor.barna
@ 2021-06-17 15:59 ` viktor.barna
  2021-06-17 15:59 ` [RFC v1 108/256] cl8k: add mac_addr.h viktor.barna
                   ` (150 subsequent siblings)
  257 siblings, 0 replies; 262+ messages in thread
From: viktor.barna @ 2021-06-17 15:59 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Oleksandr Savchenko, Shay Bar, Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

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

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 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.
________________________________


^ permalink raw reply related	[flat|nested] 262+ messages in thread

* [RFC v1 108/256] cl8k: add mac_addr.h
  2021-06-17 15:58 [RFC v1 000/256] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (106 preceding siblings ...)
  2021-06-17 15:59 ` [RFC v1 107/256] cl8k: add mac_addr.c viktor.barna
@ 2021-06-17 15:59 ` viktor.barna
  2021-06-17 15:59 ` [RFC v1 109/256] cl8k: add main.c viktor.barna
                   ` (149 subsequent siblings)
  257 siblings, 0 replies; 262+ messages in thread
From: viktor.barna @ 2021-06-17 15:59 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Oleksandr Savchenko, Shay Bar, Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

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

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 drivers/net/wireless/celeno/cl8k/mac_addr.h | 67 +++++++++++++++++++++
 1 file changed, 67 insertions(+)
 create mode 100644 drivers/net/wireless/celeno/cl8k/mac_addr.h

diff --git a/drivers/net/wireless/celeno/cl8k/mac_addr.h b/drivers/net/wireless/celeno/cl8k/mac_addr.h
new file mode 100644
index 000000000000..6cd264c32f58
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/mac_addr.h
@@ -0,0 +1,67 @@
+/* SPDX-License-Identifier: MIT */
+/* Copyright(c) 2019-2021, Celeno Communications Ltd. */
+
+#ifndef CL_MAC_ADDR_H
+#define CL_MAC_ADDR_H
+
+#include "hw.h"
+
+int cl_mac_addr_set(struct cl_hw *cl_hw);
+
+static inline void cl_mac_addr_copy(u8 *dest_addr, const u8 *src_addr)
+{
+       memcpy(dest_addr, src_addr, ETH_ALEN);
+}
+
+static inline void cl_mac_addr_move(u8 *dest_addr, const u8 *src_addr)
+{
+       memmove(dest_addr, src_addr, ETH_ALEN);
+}
+
+static inline bool cl_mac_addr_compare(const u8 *addr1, const u8 *addr2)
+{
+       return !memcmp(addr1, addr2, ETH_ALEN);
+}
+
+static inline bool cl_mac_addr_is_zero(const u8 *addr)
+{
+       const u8 addr_zero[ETH_ALEN] = {0};
+
+       return !memcmp(addr, addr_zero, ETH_ALEN);
+}
+
+static inline bool cl_mac_addr_is_broadcast(const u8 *addr)
+{
+       const u8 addr_bcast[ETH_ALEN] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
+
+       return !memcmp(addr, addr_bcast, ETH_ALEN);
+}
+
+static inline bool cl_mac_addr_parse_str(const u8 *str, u8 *addr)
+{
+       return (sscanf(str,
+                      "%02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx",
+                      &addr[0],
+                      &addr[1],
+                      &addr[2],
+                      &addr[3],
+                      &addr[4],
+                      &addr[5]) == ETH_ALEN);
+}
+
+static inline void cl_mac_addr_array_to_nxmac(u8 *array, u32 *low, u32 *high)
+{
+       /* Convert mac address (in a form of array) to a C nxmac form.
+        * Input: array - MAC address
+        * Output: low - array[0..3], high - array[4..5]
+        */
+       u8 i;
+
+       for (i = 0; i < 4; i++)
+               *low |= (u32)(((u32)array[i]) << (i * 8));
+
+       for (i = 0; i < 2; i++)
+               *high |= (u32)(((u32)array[i + 4]) << (i * 8));
+}
+
+#endif /* CL_MAC_ADDR_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.
________________________________


^ permalink raw reply related	[flat|nested] 262+ messages in thread

* [RFC v1 109/256] cl8k: add main.c
  2021-06-17 15:58 [RFC v1 000/256] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (107 preceding siblings ...)
  2021-06-17 15:59 ` [RFC v1 108/256] cl8k: add mac_addr.h viktor.barna
@ 2021-06-17 15:59 ` viktor.barna
  2021-06-17 15:59 ` [RFC v1 110/256] cl8k: add main.h viktor.barna
                   ` (148 subsequent siblings)
  257 siblings, 0 replies; 262+ messages in thread
From: viktor.barna @ 2021-06-17 15:59 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Oleksandr Savchenko, Shay Bar, Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

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

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 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.
________________________________


^ permalink raw reply related	[flat|nested] 262+ messages in thread

* [RFC v1 110/256] cl8k: add main.h
  2021-06-17 15:58 [RFC v1 000/256] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (108 preceding siblings ...)
  2021-06-17 15:59 ` [RFC v1 109/256] cl8k: add main.c viktor.barna
@ 2021-06-17 15:59 ` viktor.barna
  2021-06-17 15:59 ` [RFC v1 111/256] cl8k: add maintenance.c viktor.barna
                   ` (147 subsequent siblings)
  257 siblings, 0 replies; 262+ messages in thread
From: viktor.barna @ 2021-06-17 15:59 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Oleksandr Savchenko, Shay Bar, Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

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

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 drivers/net/wireless/celeno/cl8k/main.h | 16 ++++++++++++++++
 1 file changed, 16 insertions(+)
 create mode 100644 drivers/net/wireless/celeno/cl8k/main.h

diff --git a/drivers/net/wireless/celeno/cl8k/main.h b/drivers/net/wireless/celeno/cl8k/main.h
new file mode 100644
index 000000000000..8fab87e715f5
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/main.h
@@ -0,0 +1,16 @@
+/* SPDX-License-Identifier: MIT */
+/* Copyright(c) 2019-2021, Celeno Communications Ltd. */
+
+#ifndef CL_MAIN_H
+#define CL_MAIN_H
+
+#include "chip.h"
+#include "hw.h"
+
+int cl_main_init(struct cl_chip *chip, const struct cl_driver_ops *drv_ops);
+void cl_main_deinit(struct cl_chip *chip);
+void cl_main_reset(struct cl_chip *chip, struct cl_controller_reg *controller_reg);
+int cl_main_on(struct cl_hw *cl_hw);
+void cl_main_off(struct cl_hw *cl_hw);
+
+#endif /* CL_MAIN_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.
________________________________


^ permalink raw reply related	[flat|nested] 262+ messages in thread

* [RFC v1 111/256] cl8k: add maintenance.c
  2021-06-17 15:58 [RFC v1 000/256] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (109 preceding siblings ...)
  2021-06-17 15:59 ` [RFC v1 110/256] cl8k: add main.h viktor.barna
@ 2021-06-17 15:59 ` viktor.barna
  2021-06-17 15:59 ` [RFC v1 112/256] cl8k: add maintenance.h viktor.barna
                   ` (146 subsequent siblings)
  257 siblings, 0 replies; 262+ messages in thread
From: viktor.barna @ 2021-06-17 15:59 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Oleksandr Savchenko, Shay Bar, Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

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

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 .../net/wireless/celeno/cl8k/maintenance.c    | 80 +++++++++++++++++++
 1 file changed, 80 insertions(+)
 create mode 100644 drivers/net/wireless/celeno/cl8k/maintenance.c

diff --git a/drivers/net/wireless/celeno/cl8k/maintenance.c b/drivers/net/wireless/celeno/cl8k/maintenance.c
new file mode 100644
index 000000000000..82c1255b8872
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/maintenance.c
@@ -0,0 +1,80 @@
+// SPDX-License-Identifier: MIT
+/* Copyright(c) 2019-2021, Celeno Communications Ltd. */
+
+#include "maintenance.h"
+#include "utils/timer.h"
+#include "traffic.h"
+#include "vns.h"
+#include "reg/reg_access.h"
+#include "sounding.h"
+#include "utils/utils.h"
+#include "sta.h"
+#include "motion_sense.h"
+#include "cca.h"
+#include "noise.h"
+
+static void cl_maintenance_callback_slow(unsigned long data)
+{
+       struct cl_hw *cl_hw = (struct cl_hw *)data;
+
+       cl_cca_maintenance(cl_hw);
+       cl_noise_maintenance(cl_hw);
+
+       if (cl_hw->chip->conf->ce_production_mode)
+               return;
+
+       cl_vns_maintenance(cl_hw);
+
+       if (cl_sta_num(cl_hw) == 0)
+               return;
+
+       cl_motion_sense_maintenance(cl_hw);
+       cl_sounding_maintenance(cl_hw);
+}
+
+static void cl_maintenance_callback_fast(unsigned long data)
+{
+       struct cl_hw *cl_hw = (struct cl_hw *)data;
+
+       if (cl_sta_num(cl_hw) == 0)
+               return;
+
+       cl_traffic_maintenance(cl_hw);
+}
+
+void cl_maintenance_init(struct cl_hw *cl_hw)
+{
+       cl_timer_init(&cl_hw->maintenance_slow_timer,
+                     cl_maintenance_callback_slow,
+                     (unsigned long)cl_hw,
+                     CL_MAINTENANCE_PERIOD_SLOW_MS,
+                     true);
+
+       cl_timer_init(&cl_hw->maintenance_fast_timer,
+                     cl_maintenance_callback_fast,
+                     (unsigned long)cl_hw,
+                     CL_MAINTENANCE_PERIOD_FAST_MS,
+                     true);
+
+       cl_maintenance_start(cl_hw);
+}
+
+void cl_maintenance_close(struct cl_hw *cl_hw)
+{
+       cl_timer_disable_sync(&cl_hw->maintenance_slow_timer);
+       cl_timer_disable_sync(&cl_hw->maintenance_fast_timer);
+}
+
+void cl_maintenance_stop(struct cl_hw *cl_hw)
+{
+       cl_timer_disable(&cl_hw->maintenance_slow_timer);
+       cl_timer_disable(&cl_hw->maintenance_fast_timer);
+}
+
+void cl_maintenance_start(struct cl_hw *cl_hw)
+{
+       cl_timer_enable(&cl_hw->maintenance_slow_timer);
+
+       if (!cl_hw->chip->conf->ce_production_mode)
+               cl_timer_enable(&cl_hw->maintenance_fast_timer);
+}
--
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.
________________________________


^ permalink raw reply related	[flat|nested] 262+ messages in thread

* [RFC v1 112/256] cl8k: add maintenance.h
  2021-06-17 15:58 [RFC v1 000/256] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (110 preceding siblings ...)
  2021-06-17 15:59 ` [RFC v1 111/256] cl8k: add maintenance.c viktor.barna
@ 2021-06-17 15:59 ` viktor.barna
  2021-06-17 16:00 ` [RFC v1 113/256] cl8k: add mib.c viktor.barna
                   ` (145 subsequent siblings)
  257 siblings, 0 replies; 262+ messages in thread
From: viktor.barna @ 2021-06-17 15:59 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Oleksandr Savchenko, Shay Bar, Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

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

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 drivers/net/wireless/celeno/cl8k/maintenance.h | 17 +++++++++++++++++
 1 file changed, 17 insertions(+)
 create mode 100644 drivers/net/wireless/celeno/cl8k/maintenance.h

diff --git a/drivers/net/wireless/celeno/cl8k/maintenance.h b/drivers/net/wireless/celeno/cl8k/maintenance.h
new file mode 100644
index 000000000000..456aa4e75d4b
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/maintenance.h
@@ -0,0 +1,17 @@
+/* SPDX-License-Identifier: MIT */
+/* Copyright(c) 2019-2021, Celeno Communications Ltd. */
+
+#ifndef CL_MAINTENANCE_H
+#define CL_MAINTENANCE_H
+
+#include "hw.h"
+
+#define CL_MAINTENANCE_PERIOD_SLOW_MS   1000
+#define CL_MAINTENANCE_PERIOD_FAST_MS   100
+
+void cl_maintenance_init(struct cl_hw *cl_hw);
+void cl_maintenance_close(struct cl_hw *cl_hw);
+void cl_maintenance_stop(struct cl_hw *cl_hw);
+void cl_maintenance_start(struct cl_hw *cl_hw);
+
+#endif /* CL_MAINTENANCE_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.
________________________________


^ permalink raw reply related	[flat|nested] 262+ messages in thread

* [RFC v1 113/256] cl8k: add mib.c
  2021-06-17 15:58 [RFC v1 000/256] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (111 preceding siblings ...)
  2021-06-17 15:59 ` [RFC v1 112/256] cl8k: add maintenance.h viktor.barna
@ 2021-06-17 16:00 ` viktor.barna
  2021-06-17 16:00 ` [RFC v1 114/256] cl8k: add mib.h viktor.barna
                   ` (144 subsequent siblings)
  257 siblings, 0 replies; 262+ messages in thread
From: viktor.barna @ 2021-06-17 16:00 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Oleksandr Savchenko, Shay Bar, Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

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

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 drivers/net/wireless/celeno/cl8k/mib.c | 437 +++++++++++++++++++++++++
 1 file changed, 437 insertions(+)
 create mode 100644 drivers/net/wireless/celeno/cl8k/mib.c

diff --git a/drivers/net/wireless/celeno/cl8k/mib.c b/drivers/net/wireless/celeno/cl8k/mib.c
new file mode 100644
index 000000000000..946043dddd5d
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/mib.c
@@ -0,0 +1,437 @@
+// SPDX-License-Identifier: MIT
+/* Copyright(c) 2019-2021, Celeno Communications Ltd. */
+
+#include "mib.h"
+#include "reg/reg_access.h"
+
+#define NUM_OF_MIB_COUNTERS 254
+#define MIB_REG_OFFSET 0x800
+
+static void init_mib_counter_arr(char *mib_counter_names_arr[NUM_OF_MIB_COUNTERS])
+{
+       /*
+        * MIB element to count the number of unencrypted frames that have been
+        * discarded
+        */
+       mib_counter_names_arr[0] = "dot11_wep_excluded_count";
+
+       /* MIB element to count the receive FCS errors */
+       mib_counter_names_arr[1] = "dot11_fcs_error_count";
+       /*
+        * MIB element to count the number of PHY Errors reported during a
+        * receive transaction.
+        */
+       mib_counter_names_arr[2] = "nx_rx_phy_error_count";
+       /*
+        * MIB element to count the number of times the receive FIFO has
+        * overflowed
+        */
+       mib_counter_names_arr[3] = "nx_rx_Discard_RHD";
+       /*
+        * MIB element to count the number of times underrun has occurred on the
+        * transmit side
+        */
+       mib_counter_names_arr[4] = "nx_tx_underrun_count";
+
+       /* MIB element to count unicast transmitted MPDU */
+       mib_counter_names_arr[5] = "nx_qos_utransmitted_mpdu_count[0]";
+       mib_counter_names_arr[6] = "nx_qos_utransmitted_mpdu_count[1]";
+       mib_counter_names_arr[7] = "nx_qos_utransmitted_mpdu_count[2]";
+       mib_counter_names_arr[8] = "nx_qos_utransmitted_mpdu_count[3]";
+       mib_counter_names_arr[9] = "nx_qos_utransmitted_mpdu_count[4]";
+       mib_counter_names_arr[10] = "nx_qos_utransmitted_mpdu_count[5]";
+       mib_counter_names_arr[11] = "nx_qos_utransmitted_mpdu_count[6]";
+       mib_counter_names_arr[12] = "nx_qos_utransmitted_mpdu_count[7]";
+       /* MIB element to count group addressed transmitted MPDU */
+       mib_counter_names_arr[13] = "nx_qos_gtransmitted_mpdu_count[0]";
+       mib_counter_names_arr[14] = "nx_qos_gtransmitted_mpdu_count[1]";
+       mib_counter_names_arr[15] = "nx_qos_gtransmitted_mpdu_count[2]";
+       mib_counter_names_arr[16] = "nx_qos_gtransmitted_mpdu_count[3]";
+       mib_counter_names_arr[17] = "nx_qos_gtransmitted_mpdu_count[4]";
+       mib_counter_names_arr[18] = "nx_qos_gtransmitted_mpdu_count[5]";
+       mib_counter_names_arr[19] = "nx_qos_gtransmitted_mpdu_count[6]";
+       mib_counter_names_arr[20] = "nx_qos_gtransmitted_mpdu_count[7]";
+       /*
+        * MIB element to count the number of MSDUs or MMPDUs discarded
+        * because of retry-limit reached
+        */
+       mib_counter_names_arr[21] = "dot11_qos_failed_count[0]";
+       mib_counter_names_arr[22] = "dot11_qos_failed_count[1]";
+       mib_counter_names_arr[23] = "dot11_qos_failed_count[2]";
+       mib_counter_names_arr[24] = "dot11_qos_failed_count[3]";
+       mib_counter_names_arr[25] = "dot11_qos_failed_count[4]";
+       mib_counter_names_arr[26] = "dot11_qos_failed_count[5]";
+       mib_counter_names_arr[27] = "dot11_qos_failed_count[6]";
+       mib_counter_names_arr[28] = "dot11_qos_failed_count[7]";
+       /*
+        * MIB element to count number of unfragmented MSDU's or MMPDU's
+        * transmitted successfully after 1 or more transmission
+        */
+       mib_counter_names_arr[29] = "dot11_qos_retry_count[0]";
+       mib_counter_names_arr[30] = "dot11_qos_retry_count[1]";
+       mib_counter_names_arr[31] = "dot11_qos_retry_count[2]";
+       mib_counter_names_arr[32] = "dot11_qos_retry_count[3]";
+       mib_counter_names_arr[33] = "dot11_qos_retry_count[4]";
+       mib_counter_names_arr[34] = "dot11_qos_retry_count[5]";
+       mib_counter_names_arr[35] = "dot11_qos_retry_count[6]";
+       mib_counter_names_arr[36] = "dot11_qos_retry_count[7]";
+       /* MIB element to count number of successful RTS Frame transmission */
+       mib_counter_names_arr[37] = "dot11_qos_rts_success_count[0]";
+       mib_counter_names_arr[38] = "dot11_qos_rts_success_count[1]";
+       mib_counter_names_arr[39] = "dot11_qos_rts_success_count[2]";
+       mib_counter_names_arr[40] = "dot11_qos_rts_success_count[3]";
+       mib_counter_names_arr[41] = "dot11_qos_rts_success_count[4]";
+       mib_counter_names_arr[42] = "dot11_qos_rts_success_count[5]";
+       mib_counter_names_arr[43] = "dot11_qos_rts_success_count[6]";
+       mib_counter_names_arr[44] = "dot11_qos_rts_success_count[7]";
+       /* MIB element to count number of unsuccessful RTS Frame transmission */
+       mib_counter_names_arr[45] = "dot11_qos_rts_failure_count[0]";
+       mib_counter_names_arr[46] = "dot11_qos_rts_failure_count[1]";
+       mib_counter_names_arr[47] = "dot11_qos_rts_failure_count[2]";
+       mib_counter_names_arr[48] = "dot11_qos_rts_failure_count[3]";
+       mib_counter_names_arr[49] = "dot11_qos_rts_failure_count[4]";
+       mib_counter_names_arr[50] = "dot11_qos_rts_failure_count[5]";
+       mib_counter_names_arr[51] = "dot11_qos_rts_failure_count[6]";
+       mib_counter_names_arr[52] = "dot11_qos_rts_failure_count[7]";
+       /* MIB element to count number of MPDU's not received ACK */
+       mib_counter_names_arr[53] = "nx_qos_ack_failure_count[0]";
+       mib_counter_names_arr[54] = "nx_qos_ack_failure_count[1]";
+       mib_counter_names_arr[55] = "nx_qos_ack_failure_count[2]";
+       mib_counter_names_arr[56] = "nx_qos_ack_failure_count[3]";
+       mib_counter_names_arr[57] = "nx_qos_ack_failure_count[4]";
+       mib_counter_names_arr[58] = "nx_qos_ack_failure_count[5]";
+       mib_counter_names_arr[59] = "nx_qos_ack_failure_count[6]";
+       mib_counter_names_arr[60] = "nx_qos_ack_failure_count[7]";
+       /* MIB element to count number of unicast MPDU's received successfully */
+       mib_counter_names_arr[61] = "nx_qos_ureceived_mpdu_count[0]";
+       mib_counter_names_arr[62] = "nx_qos_ureceived_mpdu_count[1]";
+       mib_counter_names_arr[63] = "nx_qos_ureceived_mpdu_count[2]";
+       mib_counter_names_arr[64] = "nx_qos_ureceived_mpdu_count[3]";
+       mib_counter_names_arr[65] = "nx_qos_ureceived_mpdu_count[4]";
+       mib_counter_names_arr[66] = "nx_qos_ureceived_mpdu_count[5]";
+       mib_counter_names_arr[67] = "nx_qos_ureceived_mpdu_count[6]";
+       mib_counter_names_arr[68] = "nx_qos_ureceived_mpdu_count[7]";
+       /*
+        * MIB element to count number of group addressed MPDU's received
+        * successfully
+        */
+       mib_counter_names_arr[69] = "nx_qos_greceived_mpdu_count[0]";
+       mib_counter_names_arr[70] = "nx_qos_greceived_mpdu_count[1]";
+       mib_counter_names_arr[71] = "nx_qos_greceived_mpdu_count[2]";
+       mib_counter_names_arr[72] = "nx_qos_greceived_mpdu_count[3]";
+       mib_counter_names_arr[73] = "nx_qos_greceived_mpdu_count[4]";
+       mib_counter_names_arr[74] = "nx_qos_greceived_mpdu_count[5]";
+       mib_counter_names_arr[75] = "nx_qos_greceived_mpdu_count[6]";
+       mib_counter_names_arr[76] = "nx_qos_greceived_mpdu_count[7]";
+       /*
+        * MIB element to count the number of unicast MPDUs not destined to
+        * this device received successfully.
+        */
+       mib_counter_names_arr[77] = "nx_qos_ureceived_other_mpdu[0]";
+       mib_counter_names_arr[78] = "nx_qos_ureceived_other_mpdu[1]";
+       mib_counter_names_arr[79] = "nx_qos_ureceived_other_mpdu[2]";
+       mib_counter_names_arr[80] = "nx_qos_ureceived_other_mpdu[3]";
+       mib_counter_names_arr[81] = "nx_qos_ureceived_other_mpdu[4]";
+       mib_counter_names_arr[82] = "nx_qos_ureceived_other_mpdu[5]";
+       mib_counter_names_arr[83] = "nx_qos_ureceived_other_mpdu[6]";
+       mib_counter_names_arr[84] = "nx_qos_ureceived_other_mpdu[7]";
+       /*
+        * MIB element to count the number of MPDUs received with retry bit
+        * set
+        */
+       mib_counter_names_arr[85] = "dot11_qos_retries_received_count[0]";
+       mib_counter_names_arr[86] = "dot11_qos_retries_received_count[1]";
+       mib_counter_names_arr[87] = "dot11_qos_retries_received_count[2]";
+       mib_counter_names_arr[88] = "dot11_qos_retries_received_count[3]";
+       mib_counter_names_arr[89] = "dot11_qos_retries_received_count[4]";
+       mib_counter_names_arr[90] = "dot11_qos_retries_received_count[5]";
+       mib_counter_names_arr[91] = "dot11_qos_retries_received_count[6]";
+       mib_counter_names_arr[92] = "dot11_qos_retries_received_count[7]";
+       /*
+        * MIB element to count the number of unicast A-MSDUs that were
+        * transmitted successfully
+        */
+       mib_counter_names_arr[93] = "nx_utransmitted_amsdu_count[0]";
+       mib_counter_names_arr[94] = "nx_utransmitted_amsdu_count[1]";
+       mib_counter_names_arr[95] = "nx_utransmitted_amsdu_count[2]";
+       mib_counter_names_arr[96] = "nx_utransmitted_amsdu_count[3]";
+       mib_counter_names_arr[97] = "nx_utransmitted_amsdu_count[4]";
+       mib_counter_names_arr[98] = "nx_utransmitted_amsdu_count[5]";
+       mib_counter_names_arr[99] = "nx_utransmitted_amsdu_count[6]";
+       mib_counter_names_arr[100] = "nx_utransmitted_amsdu_count[7]";
+       /*
+        * MIB element to count the number of group-addressed A-MSDUs that were
+        * transmitted successfully
+        */
+       mib_counter_names_arr[101] = "nx_gtransmitted_amsdu_count[0]";
+       mib_counter_names_arr[102] = "nx_gtransmitted_amsdu_count[1]";
+       mib_counter_names_arr[103] = "nx_gtransmitted_amsdu_count[2]";
+       mib_counter_names_arr[104] = "nx_gtransmitted_amsdu_count[3]";
+       mib_counter_names_arr[105] = "nx_gtransmitted_amsdu_count[4]";
+       mib_counter_names_arr[106] = "nx_gtransmitted_amsdu_count[5]";
+       mib_counter_names_arr[107] = "nx_gtransmitted_amsdu_count[6]";
+       mib_counter_names_arr[108] = "nx_gtransmitted_amsdu_count[7]";
+       /*
+        * MIB element to count number of AMSDU's discarded because of retry
+        * limit reached
+        */
+       mib_counter_names_arr[109] = "dot11_failed_amsdu_count[0]";
+       mib_counter_names_arr[110] = "dot11_failed_amsdu_count[1]";
+       mib_counter_names_arr[111] = "dot11_failed_amsdu_count[2]";
+       mib_counter_names_arr[112] = "dot11_failed_amsdu_count[3]";
+       mib_counter_names_arr[113] = "dot11_failed_amsdu_count[4]";
+       mib_counter_names_arr[114] = "dot11_failed_amsdu_count[5]";
+       mib_counter_names_arr[115] = "dot11_failed_amsdu_count[6]";
+       mib_counter_names_arr[116] = "dot11_failed_amsdu_count[7]";
+       /*
+        * MIB element to count number of A-MSDU's transmitted successfully
+        * with retry
+        */
+       mib_counter_names_arr[117] = "dot11_retry_amsdu_count[0]";
+       mib_counter_names_arr[118] = "dot11_retry_amsdu_count[1]";
+       mib_counter_names_arr[119] = "dot11_retry_amsdu_count[2]";
+       mib_counter_names_arr[120] = "dot11_retry_amsdu_count[3]";
+       mib_counter_names_arr[121] = "dot11_retry_amsdu_count[4]";
+       mib_counter_names_arr[122] = "dot11_retry_amsdu_count[5]";
+       mib_counter_names_arr[123] = "dot11_retry_amsdu_count[6]";
+       mib_counter_names_arr[124] = "dot11_retry_amsdu_count[7]";
+       /*
+        * MIB element to count number of bytes of an A-MSDU that was
+        * transmitted successfully
+        */
+       mib_counter_names_arr[125] = "dot11_transmitted_octets_in_amsdu[0]";
+       mib_counter_names_arr[126] = "dot11_transmitted_octets_in_amsdu[1]";
+       mib_counter_names_arr[127] = "dot11_transmitted_octets_in_amsdu[2]";
+       mib_counter_names_arr[128] = "dot11_transmitted_octets_in_amsdu[3]";
+       mib_counter_names_arr[129] = "dot11_transmitted_octets_in_amsdu[4]";
+       mib_counter_names_arr[130] = "dot11_transmitted_octets_in_amsdu[5]";
+       mib_counter_names_arr[131] = "dot11_transmitted_octets_in_amsdu[6]";
+       mib_counter_names_arr[132] = "dot11_transmitted_octets_in_amsdu[7]";
+       /*
+        * MIB element to counts the number of A-MSDUs that did not receive an
+        * ACK frame successfully in response
+        */
+       mib_counter_names_arr[133] = "dot11_amsdu_ack_failure_count[0]";
+       mib_counter_names_arr[134] = "dot11_amsdu_ack_failure_count[1]";
+       mib_counter_names_arr[135] = "dot11_amsdu_ack_failure_count[2]";
+       mib_counter_names_arr[136] = "dot11_amsdu_ack_failure_count[3]";
+       mib_counter_names_arr[137] = "dot11_amsdu_ack_failure_count[4]";
+       mib_counter_names_arr[138] = "dot11_amsdu_ack_failure_count[5]";
+       mib_counter_names_arr[139] = "dot11_amsdu_ack_failure_count[6]";
+       mib_counter_names_arr[140] = "dot11_amsdu_ack_failure_count[7]";
+       /*
+        * MIB element to count number of unicast A-MSDUs received
+        * successfully
+        */
+       mib_counter_names_arr[141] = "nx_ureceived_amsdu_count[0]";
+       mib_counter_names_arr[142] = "nx_ureceived_amsdu_count[1]";
+       mib_counter_names_arr[143] = "nx_ureceived_amsdu_count[2]";
+       mib_counter_names_arr[144] = "nx_ureceived_amsdu_count[3]";
+       mib_counter_names_arr[145] = "nx_ureceived_amsdu_count[4]";
+       mib_counter_names_arr[146] = "nx_ureceived_amsdu_count[5]";
+       mib_counter_names_arr[147] = "nx_ureceived_amsdu_count[6]";
+       mib_counter_names_arr[148] = "nx_ureceived_amsdu_count[7]";
+       /*
+        * MIB element to count number of group addressed A-MSDUs received
+        * successfully
+        */
+       mib_counter_names_arr[149] = "nx_greceived_amsdu_count[0]";
+       mib_counter_names_arr[150] = "nx_greceived_amsdu_count[1]";
+       mib_counter_names_arr[151] = "nx_greceived_amsdu_count[2]";
+       mib_counter_names_arr[152] = "nx_greceived_amsdu_count[3]";
+       mib_counter_names_arr[153] = "nx_greceived_amsdu_count[4]";
+       mib_counter_names_arr[154] = "nx_greceived_amsdu_count[5]";
+       mib_counter_names_arr[155] = "nx_greceived_amsdu_count[6]";
+       mib_counter_names_arr[156] = "nx_greceived_amsdu_count[7]";
+       /*
+        * MIB element to count number of unicast A-MSDUs not destined to
+        * this device received successfully
+        */
+       mib_counter_names_arr[157] = "nx_ureceived_other_amsdu[0]";
+       mib_counter_names_arr[158] = "nx_ureceived_other_amsdu[1]";
+       mib_counter_names_arr[159] = "nx_ureceived_other_amsdu[2]";
+       mib_counter_names_arr[160] = "nx_ureceived_other_amsdu[3]";
+       mib_counter_names_arr[161] = "nx_ureceived_other_amsdu[4]";
+       mib_counter_names_arr[162] = "nx_ureceived_other_amsdu[5]";
+       mib_counter_names_arr[163] = "nx_ureceived_other_amsdu[6]";
+       mib_counter_names_arr[164] = "nx_ureceived_other_amsdu[7]";
+       /* MIB element to count number of bytes in an A-MSDU is received */
+       mib_counter_names_arr[165] = "dot11_received_octets_in_amsdu_count[0]";
+       mib_counter_names_arr[166] = "dot11_received_octets_in_amsdu_count[1]";
+       mib_counter_names_arr[167] = "dot11_received_octets_in_amsdu_count[2]";
+       mib_counter_names_arr[168] = "dot11_received_octets_in_amsdu_count[3]";
+       mib_counter_names_arr[169] = "dot11_received_octets_in_amsdu_count[4]";
+       mib_counter_names_arr[170] = "dot11_received_octets_in_amsdu_count[5]";
+       mib_counter_names_arr[171] = "dot11_received_octets_in_amsdu_count[6]";
+       mib_counter_names_arr[172] = "dot11_received_octets_in_amsdu_count[7]";
+       /* Reserved */
+       mib_counter_names_arr[173] = "reserved";
+       mib_counter_names_arr[174] = "reserved";
+       mib_counter_names_arr[175] = "reserved";
+
+       mib_counter_names_arr[176] = "dot11_beamforming_frame_count";
+       mib_counter_names_arr[177] = "beamforming_received_frame_count";
+       mib_counter_names_arr[178] = "su_bfr_transmitted_count";
+       mib_counter_names_arr[179] = "mu_bfr_transmitted_count";
+       mib_counter_names_arr[180] = "bfr_received_count";
+       mib_counter_names_arr[181] = "mu_received_frame_count";
+       mib_counter_names_arr[182] = "respSetByFW";
+       mib_counter_names_arr[183] = "respForcedByFW";
+       mib_counter_names_arr[184] = "respForcedByHW";
+       mib_counter_names_arr[185] = "respForcedByHW";
+       mib_counter_names_arr[186] = "rxUnexpectedFrameTypeInAmpdu";
+       mib_counter_names_arr[187] = "rxMultiTid";
+       mib_counter_names_arr[188] = "ksrMissQosDataInAmpdu";
+       mib_counter_names_arr[189] = "ksrMissMultiTid";
+       mib_counter_names_arr[190] = "ksrMissQosDataInAmpduHeTB";
+       mib_counter_names_arr[191] = "rxUnassociatedMgmtInHeTB";
+       mib_counter_names_arr[192] = "HtpFailedMeduimCheckCount";
+       mib_counter_names_arr[193] = "mibRxErrorVector[0]";
+       mib_counter_names_arr[194] = "mibRxErrorVector[1]";
+       mib_counter_names_arr[195] = "mibRxErrorVector[2]";
+       mib_counter_names_arr[196] = "mibRxErrorVector[3]";
+       mib_counter_names_arr[197] = "mibRxErrorVector[4]";
+       mib_counter_names_arr[198] = "mibRxErrorVector[5]";
+       mib_counter_names_arr[199] = "mibRxErrorVector[6]";
+       mib_counter_names_arr[200] = "mibRxErrorVector[7]";
+       mib_counter_names_arr[201] = "mibRxErrorVector[8]";
+       mib_counter_names_arr[202] = "mibRxErrorVector[9]";
+       mib_counter_names_arr[203] = "mibRxErrorVector[10]";
+
+       /* MIB element to count number of A-MPDUs transmitted successfully */
+       mib_counter_names_arr[204] = "dot11_transmitted_ampdu_count";
+       /* MIB element to count number of MPDUs transmitted in an A-MPDU */
+       mib_counter_names_arr[205] = "dot11_transmitted_mpdus_in_ampdu_count";
+       /* MIB element to count the number of bytes in a transmitted A-MPDU */
+       mib_counter_names_arr[206] = "dot11_transmitted_octets_in_ampdu_count";
+       /* MIB element to count number of unicast A-MPDU's received */
+       mib_counter_names_arr[207] = "wnlu_ampdu_received_count";
+       /* MIB element to count number of group addressed A-MPDU's received */
+       mib_counter_names_arr[208] = "nx_gampdu_received_count";
+       /*
+        * MIB element to count number of unicast A-MPDUs received not destined
+        * to this device
+        */
+       mib_counter_names_arr[209] = "nx_other_ampdu_received_count";
+       /* MIB element to count number of MPDUs received in an A-MPDU */
+       mib_counter_names_arr[210] = "dot11_mpdu_in_received_ampdu_count";
+       /* MIB element to count number of bytes received in an A-MPDU */
+       mib_counter_names_arr[211] = "dot11_received_octets_in_ampdu_count";
+       /* MIB element to count number of CRC errors in MPDU delimeter of and A-MPDU */
+       mib_counter_names_arr[212] = "dot11_ampdu_delimiter_crc_error_count";
+       /*
+        * MIB element to count number of implicit BAR frames that did not received
+        * BA frame successfully in response
+        */
+       mib_counter_names_arr[213] = "dot11_implicit_bar_failure_count";
+       /*
+        * MIB element to count number of explicit BAR frames that did not received
+        * BA frame successfully in response
+        */
+       mib_counter_names_arr[214] = "dot11_explicit_bar_failure_count";
+       mib_counter_names_arr[215] = "mibRxErrorVector[11]";
+       mib_counter_names_arr[216] = "mibRxErrorVector[12]";
+       mib_counter_names_arr[217] = "mibRxErrorVector[13]";
+       mib_counter_names_arr[218] = "mibRxErrorVector[14]";
+       mib_counter_names_arr[219] = "mibRxErrorVector[15]";
+       /* MIB element to count the number of frames transmitted at 20 MHz BW */
+       mib_counter_names_arr[220] = "dot11_20mhz_frame_transmitted_count";
+       /* MIB element to count the number of frames transmitted at 40 MHz BW */
+       mib_counter_names_arr[221] = "dot11_40mhz_frame_transmitted_count";
+       mib_counter_names_arr[222] = "dot11_80mhz_frame_transmitted_count";
+       mib_counter_names_arr[223] = "dot11_160mhz_frame_transmitted_count";
+       /* MIB element to count the number of frames received at 20 MHz BW */
+       mib_counter_names_arr[224] = "dot11_20mhz_frame_received_count";
+       /* MIB element to count the number of frames received at 40 MHz BW */
+       mib_counter_names_arr[225] = "dot11_40mhz_frame_received_count";
+       mib_counter_names_arr[226] = "dot11_80mhz_frame_received_count";
+       mib_counter_names_arr[227] = "dot11_160mhz_frame_received_count";
+       /* MIB element to count the number of attempts made to acquire a 40 MHz TXOP */
+       mib_counter_names_arr[228] = "nx_failed_20mhz_txop";
+       mib_counter_names_arr[229] = "nx_succsessful_20mhz_txop";
+
+       mib_counter_names_arr[230] = "nx_failed_40mhz_txop";
+       mib_counter_names_arr[231] = "nx_succsessful_40mhz_txop";
+
+       mib_counter_names_arr[232] = "nx_failed_80mhz_txop";
+       mib_counter_names_arr[233] = "nx_succsessful_80mhz_txop";
+
+       mib_counter_names_arr[234] = "nx_failed_160mhz_txop";
+       mib_counter_names_arr[235] = "nx_succsessful_160mhz_txop";
+
+       mib_counter_names_arr[236] = "dynamic_bw_drop_count";
+       mib_counter_names_arr[237] = "static_bw_failed_count";
+
+       /* Reserved */
+       mib_counter_names_arr[238] = "reserved";
+       mib_counter_names_arr[239] = "reserved";
+
+       /* MIB element to count the number of times the dual CTS fails */
+       mib_counter_names_arr[240] = "dot11_dualcts_success_count";
+       /*
+        * MIB element to count the number of times the AP does not detect a collision
+        * PIFS after transmitting a STBC CTS frame
+        */
+       mib_counter_names_arr[241] = "dot11_stbc_cts_success_count";
+       /*
+        * MIB element to count the number of times the AP detects a collision PIFS after
+        * transmitting a STBC CTS frame
+        */
+       mib_counter_names_arr[242] = "dot11_stbc_cts_failure_count";
+       /*
+        * MIB element to count the number of times the AP does not detect a collision PIFS
+        * after transmitting a non-STBC CTS frame
+        */
+       mib_counter_names_arr[243] = "dot11_non_stbc_cts_success_count";
+       /*
+        * MIB element to count the number of times the AP detects a collision PIFS after
+        * transmitting a non-STBC CTS frame
+        */
+       mib_counter_names_arr[244] = "dot11_non_stbc_cts_failure_count";
+       mib_counter_names_arr[245] = "dot11_txund_discard_fcs_count";
+       mib_counter_names_arr[246] = "dot11_rx_ampdu_incorrect_received_count";
+       mib_counter_names_arr[247] = "cl_rx_class_match_count[0]";
+       mib_counter_names_arr[248] = "cl_rx_class_match_count[1]";
+       mib_counter_names_arr[249] = "cl_rx_class_match_count[2]";
+       mib_counter_names_arr[250] = "cl_rx_class_match_count[3]";
+       mib_counter_names_arr[251] = "cl_rx_class_match_count[4]";
+       mib_counter_names_arr[252] = "cl_rx_class_match_count[5]";
+       mib_counter_names_arr[253] = "dot11_rx_mpif_overflow_count";
+}
+
+void cl_mib_cntrs_dump(struct cl_hw *cl_hw)
+{
+       static char *mib_counter_names_arr[NUM_OF_MIB_COUNTERS];
+       int i = 0;
+       u32 mib_reg_addr = 0;
+       u32 mib_reg_val = 0;
+
+       init_mib_counter_arr(mib_counter_names_arr);
+
+       pr_debug("------------------------------------------------------------\n");
+       pr_debug("Counter                                   Address  Value\n");
+       pr_debug("------------------------------------------------------------\n");
+
+       for (i = 0; i < NUM_OF_MIB_COUNTERS; i++) {
+               /* Reserved registers */
+               if (i == 173 || i == 174 || i == 175 || i == 238 || i == 239)
+                       continue;
+
+               mib_reg_addr = MIB_REG_OFFSET + (i * 4);
+               mib_reg_val = cl_mib_cntr_read(cl_hw, mib_reg_addr);
+
+               if (mib_reg_val == 0)
+                       continue;
+
+               pr_debug("%-40s  0x%X    %u\n",
+                        mib_counter_names_arr[i], mib_reg_addr, mib_reg_val);
+       }
+
+       pr_debug("------------------------------------------------------------\n");
+}
+
+u32 cl_mib_cntr_read(struct cl_hw *cl_hw, u32 addr)
+{
+       return cl_reg_read(cl_hw, REG_MAC_HW_BASE_ADDR + addr);
+}
+
--
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.
________________________________


^ permalink raw reply related	[flat|nested] 262+ messages in thread

* [RFC v1 114/256] cl8k: add mib.h
  2021-06-17 15:58 [RFC v1 000/256] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (112 preceding siblings ...)
  2021-06-17 16:00 ` [RFC v1 113/256] cl8k: add mib.c viktor.barna
@ 2021-06-17 16:00 ` viktor.barna
  2021-06-17 16:00 ` [RFC v1 115/256] cl8k: add motion_sense.c viktor.barna
                   ` (143 subsequent siblings)
  257 siblings, 0 replies; 262+ messages in thread
From: viktor.barna @ 2021-06-17 16:00 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Oleksandr Savchenko, Shay Bar, Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

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

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 drivers/net/wireless/celeno/cl8k/mib.h | 286 +++++++++++++++++++++++++
 1 file changed, 286 insertions(+)
 create mode 100644 drivers/net/wireless/celeno/cl8k/mib.h

diff --git a/drivers/net/wireless/celeno/cl8k/mib.h b/drivers/net/wireless/celeno/cl8k/mib.h
new file mode 100644
index 000000000000..7089ecf3c374
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/mib.h
@@ -0,0 +1,286 @@
+/* SPDX-License-Identifier: MIT */
+/* Copyright(c) 2019-2021, Celeno Communications Ltd. */
+
+#ifndef CL_MIB_H
+#define CL_MIB_H
+
+#include "hw.h"
+
+/**
+ * MIB (=Managaement Information Database, 802.11)
+ */
+
+/*
+ * MIB counters RW
+ */
+#define MIB_DOT11_WEP_EXCLUDED_COUNT 0x800
+#define MIB_DOT11_FCS_ERROR_COUNT 0x804
+#define MIB_DOT11_RX_PHY_ERROR_COUNT 0x808
+#define MIB_DOT11_RX_FIFO_OVERFLOW_COUNT 0x80C
+#define MIB_DOT11_TX_UNDERRUN_COUNT 0x810
+#define MIB_RW_QOS_U_TRANSMITTED_MPDU_COUNT_TID0 0x814
+#define MIB_RW_QOS_U_TRANSMITTED_MPDU_COUNT_TID1 0x818
+#define MIB_RW_QOS_U_TRANSMITTED_MPDU_COUNT_TID2 0x81C
+#define MIB_RW_QOS_U_TRANSMITTED_MPDU_COUNT_TID3 0x820
+#define MIB_RW_QOS_U_TRANSMITTED_MPDU_COUNT_TID4 0x824
+#define MIB_RW_QOS_U_TRANSMITTED_MPDU_COUNT_TID5 0x828
+#define MIB_RW_QOS_U_TRANSMITTED_MPDU_COUNT_TID6 0x82C
+#define MIB_RW_QOS_U_TRANSMITTED_MPDU_COUNT_TID7 0x830
+#define MIB_RW_QOS_G_TRANSMITTED_MPDU_COUNT_TID0 0x834
+#define MIB_RW_QOS_G_TRANSMITTED_MPDU_COUNT_TID1 0x838
+#define MIB_RW_QOS_G_TRANSMITTED_MPDU_COUNT_TID2 0x83C
+#define MIB_RW_QOS_G_TRANSMITTED_MPDU_COUNT_TID3 0x840
+#define MIB_RW_QOS_G_TRANSMITTED_MPDU_COUNT_TID4 0x844
+#define MIB_RW_QOS_G_TRANSMITTED_MPDU_COUNT_TID5 0x848
+#define MIB_RW_QOS_G_TRANSMITTED_MPDU_COUNT_TID6 0x84C
+#define MIB_RW_QOS_G_TRANSMITTED_MPDU_COUNT_TID7 0x850
+#define MIB_DOT11_QOS_FAILED_COUNT0 0x854
+#define MIB_DOT11_QOS_FAILED_COUNT1 0x858
+#define MIB_DOT11_QOS_FAILED_COUNT2 0x85C
+#define MIB_DOT11_QOS_FAILED_COUNT3 0x860
+#define MIB_DOT11_QOS_FAILED_COUNT4 0x864
+#define MIB_DOT11_QOS_FAILED_COUNT5 0x868
+#define MIB_DOT11_QOS_FAILED_COUNT6 0x86C
+#define MIB_DOT11_QOS_FAILED_COUNT7 0x870
+#define MIB_DOT11_QOS_RETRY_COUNT0 0x874
+#define MIB_DOT11_QOS_RETRY_COUNT1 0x878
+#define MIB_DOT11_QOS_RETRY_COUNT2 0x87C
+#define MIB_DOT11_QOS_RETRY_COUNT3 0x880
+#define MIB_DOT11_QOS_RETRY_COUNT4 0x884
+#define MIB_DOT11_QOS_RETRY_COUNT5 0x888
+#define MIB_DOT11_QOS_RETRY_COUNT6 0x88C
+#define MIB_DOT11_QOS_RETRY_COUNT7 0x890
+#define MIB_DOT11_QOS_RTS_SUCCESS_COUNT0 0x894
+#define MIB_DOT11_QOS_RTS_SUCCESS_COUNT1 0x898
+#define MIB_DOT11_QOS_RTS_SUCCESS_COUNT2 0x89C
+#define MIB_DOT11_QOS_RTS_SUCCESS_COUNT3 0x8A0
+#define MIB_DOT11_QOS_RTS_SUCCESS_COUNT4 0x8A4
+#define MIB_DOT11_QOS_RTS_SUCCESS_COUNT5 0x8A8
+#define MIB_DOT11_QOS_RTS_SUCCESS_COUNT6 0x8AC
+#define MIB_DOT11_QOS_RTS_SUCCESS_COUNT7 0x8B0
+#define MIB_DOT11_QOS_RTS_FAILURE_COUNT0 0x8B4
+#define MIB_DOT11_QOS_RTS_FAILURE_COUNT1 0x8B8
+#define MIB_DOT11_QOS_RTS_FAILURE_COUNT2 0x8BC
+#define MIB_DOT11_QOS_RTS_FAILURE_COUNT3 0x8C0
+#define MIB_DOT11_QOS_RTS_FAILURE_COUNT4 0x8C4
+#define MIB_DOT11_QOS_RTS_FAILURE_COUNT5 0x8C8
+#define MIB_DOT11_QOS_RTS_FAILURE_COUNT6 0x8CC
+#define MIB_DOT11_QOS_RTS_FAILURE_COUNT7 0x8D0
+#define MIB_RW_QOS_ACK_FAILURE_COUNT0 0x8D4
+#define MIB_RW_QOS_ACK_FAILURE_COUNT1 0x8D8
+#define MIB_RW_QOS_ACK_FAILURE_COUNT2 0x8DC
+#define MIB_RW_QOS_ACK_FAILURE_COUNT3 0x8E0
+#define MIB_RW_QOS_ACK_FAILURE_COUNT4 0x8E4
+#define MIB_RW_QOS_ACK_FAILURE_COUNT5 0x8E8
+#define MIB_RW_QOS_ACK_FAILURE_COUNT6 0x8EC
+#define MIB_RW_QOS_ACK_FAILURE_COUNT7 0x8F0
+#define MIB_RW_QOS_U_RECEIVED_MPDU_COUNT0 0x8F4
+#define MIB_RW_QOS_U_RECEIVED_MPDU_COUNT1 0x8F8
+#define MIB_RW_QOS_U_RECEIVED_MPDU_COUNT2 0x8FC
+#define MIB_RW_QOS_U_RECEIVED_MPDU_COUNT3 0x900
+#define MIB_RW_QOS_U_RECEIVED_MPDU_COUNT4 0x904
+#define MIB_RW_QOS_U_RECEIVED_MPDU_COUNT5 0x908
+#define MIB_RW_QOS_U_RECEIVED_MPDU_COUNT6 0x90C
+#define MIB_RW_QOS_U_RECEIVED_MPDU_COUNT7 0x910
+#define MIB_RW_QOS_G_RECEIVED_MPDU_COUNT0 0x914
+#define MIB_RW_QOS_G_RECEIVED_MPDU_COUNT1 0x918
+#define MIB_RW_QOS_G_RECEIVED_MPDU_COUNT2 0x91C
+#define MIB_RW_QOS_G_RECEIVED_MPDU_COUNT3 0x920
+#define MIB_RW_QOS_G_RECEIVED_MPDU_COUNT4 0x924
+#define MIB_RW_QOS_G_RECEIVED_MPDU_COUNT5 0x928
+#define MIB_RW_QOS_G_RECEIVED_MPDU_COUNT6 0x92C
+#define MIB_RW_QOS_G_RECEIVED_MPDU_COUNT7 0x930
+#define MIB_RW_QOS_U_RECEIVED_OTHER_MPDU0 0x934
+#define MIB_RW_QOS_U_RECEIVED_OTHER_MPDU1 0x938
+#define MIB_RW_QOS_U_RECEIVED_OTHER_MPDU2 0x93C
+#define MIB_RW_QOS_U_RECEIVED_OTHER_MPDU3 0x940
+#define MIB_RW_QOS_U_RECEIVED_OTHER_MPDU4 0x944
+#define MIB_RW_QOS_U_RECEIVED_OTHER_MPDU5 0x948
+#define MIB_RW_QOS_U_RECEIVED_OTHER_MPDU6 0x94C
+#define MIB_RW_QOS_U_RECEIVED_OTHER_MPDU7 0x950
+#define MIB_DOT11_QOS_RETRIES_RECEIVED_COUNT0 0x954
+#define MIB_DOT11_QOS_RETRIES_RECEIVED_COUNT1 0x958
+#define MIB_DOT11_QOS_RETRIES_RECEIVED_COUNT2 0x95C
+#define MIB_DOT11_QOS_RETRIES_RECEIVED_COUNT3 0x960
+#define MIB_DOT11_QOS_RETRIES_RECEIVED_COUNT4 0x964
+#define MIB_DOT11_QOS_RETRIES_RECEIVED_COUNT5 0x968
+#define MIB_DOT11_QOS_RETRIES_RECEIVED_COUNT6 0x96C
+#define MIB_DOT11_QOS_RETRIES_RECEIVED_COUNT7 0x970
+#define MIB_RW_U_TRANSMITTED_AMSDU_COUNT0 0x974
+#define MIB_RW_U_TRANSMITTED_AMSDU_COUNT1 0x978
+#define MIB_RW_U_TRANSMITTED_AMSDU_COUNT2 0x97C
+#define MIB_RW_U_TRANSMITTED_AMSDU_COUNT3 0x980
+#define MIB_RW_U_TRANSMITTED_AMSDU_COUNT4 0x984
+#define MIB_RW_U_TRANSMITTED_AMSDU_COUNT5 0x988
+#define MIB_RW_U_TRANSMITTED_AMSDU_COUNT6 0x98C
+#define MIB_RW_U_TRANSMITTED_AMSDU_COUNT7 0x990
+#define MIB_RW_G_TRANSMITTED_AMSDU_COUNT0 0x994
+#define MIB_RW_G_TRANSMITTED_AMSDU_COUNT1 0x998
+#define MIB_RW_G_TRANSMITTED_AMSDU_COUNT2 0x99C
+#define MIB_RW_G_TRANSMITTED_AMSDU_COUNT3 0x9A0
+#define MIB_RW_G_TRANSMITTED_AMSDU_COUNT4 0x9A4
+#define MIB_RW_G_TRANSMITTED_AMSDU_COUNT5 0x9A8
+#define MIB_RW_G_TRANSMITTED_AMSDU_COUNT6 0x9AC
+#define MIB_RW_G_TRANSMITTED_AMSDU_COUNT7 0x9B0
+#define MIB_DOT11_FAILED_AMSDU_COUNT0 0x9B4
+#define MIB_DOT11_FAILED_AMSDU_COUNT1 0x9B8
+#define MIB_DOT11_FAILED_AMSDU_COUNT2 0x9BC
+#define MIB_DOT11_FAILED_AMSDU_COUNT3 0x9C0
+#define MIB_DOT11_FAILED_AMSDU_COUNT4 0x9C4
+#define MIB_DOT11_FAILED_AMSDU_COUNT5 0x9C8
+#define MIB_DOT11_FAILED_AMSDU_COUNT6 0x9CC
+#define MIB_DOT11_FAILED_AMSDU_COUNT7 0x9D0
+#define MIB_DOT11_RETRY_AMSDU_COUNT0 0x9D4
+#define MIB_DOT11_RETRY_AMSDU_COUNT1 0x9D8
+#define MIB_DOT11_RETRY_AMSDU_COUNT2 0x9DC
+#define MIB_DOT11_RETRY_AMSDU_COUNT3 0x9E0
+#define MIB_DOT11_RETRY_AMSDU_COUNT4 0x9E4
+#define MIB_DOT11_RETRY_AMSDU_COUNT5 0x9E8
+#define MIB_DOT11_RETRY_AMSDU_COUNT6 0x9EC
+#define MIB_DOT11_RETRY_AMSDU_COUNT7 0x9F0
+#define MIB_DOT11_TRANSMITTED_OCTETS_IN_AMSDU0 0x9F4
+#define MIB_DOT11_TRANSMITTED_OCTETS_IN_AMSDU1 0x9F8
+#define MIB_DOT11_TRANSMITTED_OCTETS_IN_AMSDU2 0x9FC
+#define MIB_DOT11_TRANSMITTED_OCTETS_IN_AMSDU3 0xA00
+#define MIB_DOT11_TRANSMITTED_OCTETS_IN_AMSDU4 0xA04
+#define MIB_DOT11_TRANSMITTED_OCTETS_IN_AMSDU5 0xA08
+#define MIB_DOT11_TRANSMITTED_OCTETS_IN_AMSDU6 0xA0C
+#define MIB_DOT11_TRANSMITTED_OCTETS_IN_AMSDU7 0xA10
+#define MIB_DOT11_AMSDU_ACK_FAILURE_COUNT0 0xA14
+#define MIB_DOT11_AMSDU_ACK_FAILURE_COUNT1 0xA18
+#define MIB_DOT11_AMSDU_ACK_FAILURE_COUNT2 0xA1C
+#define MIB_DOT11_AMSDU_ACK_FAILURE_COUNT3 0xA20
+#define MIB_DOT11_AMSDU_ACK_FAILURE_COUNT4 0xA24
+#define MIB_DOT11_AMSDU_ACK_FAILURE_COUNT5 0xA28
+#define MIB_DOT11_AMSDU_ACK_FAILURE_COUNT6 0xA2C
+#define MIB_DOT11_AMSDU_ACK_FAILURE_COUNT7 0xA30
+#define MIB_RW_U_RECEIVED_AMSDU_COUNT0 0xA34
+#define MIB_RW_U_RECEIVED_AMSDU_COUNT1 0xA38
+#define MIB_RW_U_RECEIVED_AMSDU_COUNT2 0xA3C
+#define MIB_RW_U_RECEIVED_AMSDU_COUNT3 0xA40
+#define MIB_RW_U_RECEIVED_AMSDU_COUNT4 0xA44
+#define MIB_RW_U_RECEIVED_AMSDU_COUNT5 0xA48
+#define MIB_RW_U_RECEIVED_AMSDU_COUNT6 0xA4C
+#define MIB_RW_U_RECEIVED_AMSDU_COUNT7 0xA50
+#define MIB_RW_G_RECEIVED_AMSDU_COUNT0 0xA54
+#define MIB_RW_G_RECEIVED_AMSDU_COUNT1 0xA58
+#define MIB_RW_G_RECEIVED_AMSDU_COUNT2 0xA5C
+#define MIB_RW_G_RECEIVED_AMSDU_COUNT3 0xA60
+#define MIB_RW_G_RECEIVED_AMSDU_COUNT4 0xA64
+#define MIB_RW_G_RECEIVED_AMSDU_COUNT5 0xA68
+#define MIB_RW_G_RECEIVED_AMSDU_COUNT6 0xA6C
+#define MIB_RW_G_RECEIVED_AMSDU_COUNT7 0xA70
+#define MIB_RW_U_RECEIVED_OTHER_COUNT0 0xA74
+#define MIB_RW_U_RECEIVED_OTHER_COUNT1 0xA78
+#define MIB_RW_U_RECEIVED_OTHER_COUNT2 0xA7C
+#define MIB_RW_U_RECEIVED_OTHER_COUNT3 0xA80
+#define MIB_RW_U_RECEIVED_OTHER_COUNT4 0xA84
+#define MIB_RW_U_RECEIVED_OTHER_COUNT5 0xA88
+#define MIB_RW_U_RECEIVED_OTHER_COUNT6 0xA8C
+#define MIB_RW_U_RECEIVED_OTHER_COUNT7 0xA90
+#define MIB_DOT11_RECEIVED_OCTETS_IN_AMSDU_COUNT0 0xA94
+#define MIB_DOT11_RECEIVED_OCTETS_IN_AMSDU_COUNT1 0xA98
+#define MIB_DOT11_RECEIVED_OCTETS_IN_AMSDU_COUNT2 0xA9C
+#define MIB_DOT11_RECEIVED_OCTETS_IN_AMSDU_COUNT3 0xAA0
+#define MIB_DOT11_RECEIVED_OCTETS_IN_AMSDU_COUNT4 0xAA4
+#define MIB_DOT11_RECEIVED_OCTETS_IN_AMSDU_COUNT5 0xAA8
+#define MIB_DOT11_RECEIVED_OCTETS_IN_AMSDU_COUNT6 0xAAC
+#define MIB_DOT11_RECEIVED_OCTETS_IN_AMSDU_COUNT7 0xAB0
+
+/* RESERVED 173 - 176 */
+
+#define MIB_DOT11_BEAMFORMING_FRAME_COUNT 0xAC0
+#define BEAMFORMING_RECEIVED_FRAME_COUNT 0xAC4
+#define MIB_RW_SU_BFR_TRANSMITTED_COUNT 0xAC8
+#define MIB_RW_MU_BFR_TRANSMITTED_COUNT 0xACC
+#define MIB_RW_BFR_RECEIVED_COUNT 0xAD0
+#define MIB_RW_MU_RECEIVED_FRAME_COUNT 0xAD4
+
+/* RESERVED 182 - 203 */
+
+#define MIB_DOT11_TRANSMITTED_AMPDU_COUNT 0xB30
+#define MIB_DOT11_TRANSMITTED_MPDUIN_AMPDU_COUNT 0xB34
+#define MIB_DOT11_TRANSMITTED_OCTESTS_IN_AMPDU_COUNT 0xB38
+#define MIB_RW_U_AMPDU_RECEIVED_COUNT 0xB3C
+#define MIB_RW_G_AMPDU_RECEIVED_COUNT 0xB40
+#define MIB_RW_OTHER_AMPDU_RECEIVED_COUNT 0xB44
+#define MIB_DOT11_MPDU_IN_RECEIVED_AMPDU_COUNT 0xB48
+#define MIB_DOT11_RECEIVED_OCTETS_IN_AMPDU_COUNT 0xB4C
+#define MIB_DOT11_AMPDU_DELIMITER_CRC_ERROR_COUNT 0xB50
+#define MIB_DOT11_IMPLICIT_BAR_FAILURE_COUNT 0xB54
+#define MIB_DOT11_EXPLICIT_BAR_FAILURE_COUNT 0xB58
+
+/* RESERVED  215-219 */
+
+#define MIB_DOT11_20MHZ_FRAME_TRANSMITTED_COUNT 0xB70
+#define MIB_DOT11_40MHZ_FRAME_TRANSMITTED_COUNT 0xB74
+#define MIB_DOT11_80MHZ_FRAME_TRANSMITTED_COUNT 0xB78
+#define MIB_DOT11_160MHZ_FRAME_TRANSMITTED_COUNT 0xB7C
+#define MIB_DOT11_20MHZ_FRAME_RECEIVED_COUNT 0xB80
+#define MIB_DOT11_40MHZ_FRAME_RECEIVED_COUNT 0xB84
+#define MIB_DOT11_80MHZ_FRAME_RECEIVED_COUNT 0xB88
+#define MIB_DOT11_160MHZ_FRAME_RECEIVED_COUNT 0xB8C
+#define MIB_RW_20MHZ_FAILED_TXOP_COUNT 0xB90
+#define MIB_RW_20MHZ_SUCCESSFUL_TXOP_COUNT 0xB94
+#define MIB_RW_40MHZ_FAILED_TXOP_COUNT 0xB98
+#define MIB_RW_40MHZ_SUCCESSFUL_TXOP_COUNT 0xB9C
+#define MIB_RW_80MHZ_FAILED_TXOP_COUNT 0xBA0
+#define MIB_RW_80MHZ_SUCCESSFUL_TXOP_COUNT 0xBA4
+#define MIB_RW_160MHZ_FAILED_TXOP_COUNT 0xBA8
+#define MIB_RW_160MHZ_SUCCESSFUL_TXOP_COUNT 0xBAC
+#define MIB_RW_DYN_BW_DROP_COUNT 0xBB0
+#define MIB_RW_STA_BW_FAILED_COUNT 0xBB4
+
+/* RESERVED 238-239 */
+
+#define MIB_DOT11_DUAL_CTS_SUCCESS_COUNT 0xBC0
+#define MIB_DOT11_STBC_CTS_SUCCESS_COUNT 0xBC4
+#define MIB_DOT11_STBC_CTS_FAILURE_COUNT 0xBC8
+#define MIB_DOT11_NON_STBC_CTS_SUCCESS_COUNT 0xBCC
+#define MIB_DOT11_NON_STBC_CTS_FAILURE_COUNT 0xBD0
+
+/*
+ * MIB counters Celeno
+ */
+#define MIB_TX_UND_DISCARD_FCS_COUNT 0xBD4
+#define MIB_AMPDU_INCORRECT_RCVED_COUNT 0xBD8
+#define MIB_CL_RX_CLASS0_MATCH_COUNT 0xBDC
+#define MIB_CL_RX_CLASS1_MATCH_COUNT 0xBE0
+#define MIB_CL_RX_CLASS2_MATCH_COUNT 0xBE4
+#define MIB_CL_RX_CLASS3_MATCH_COUNT 0xBE8
+#define MIB_CL_RX_CLASS4_MATCH_COUNT 0xBEC
+#define MIB_CL_RX_CLASS5_MATCH_COUNT 0xBF0
+#define MIB_RW_RX_MPIF_OVERFLOW_COUNT 0xBF4
+
+#define MIB_RESP_SET_BY_FW 0xAD8
+#define MIB_RESP_FORCE_BY_FW 0xADC
+#define MIB_RESP_SET_BY_HW 0xAE0
+#define MIB_RESP_FORCED_BY_HW 0xAE4
+#define MIB_RX_UNEXPECTED_FRAME_TYPE_IN_AMPDU 0xAE8
+#define MIB_RX_MILTI_TID 0xAEC
+#define MIB_KSR_MISS_QOS_DATA_IN_AMPDU 0xAF0
+#define MIB_KSR_MISS_MULTI_TID 0xAF4
+#define MIB_KSR_MISS_QOS_DATA_IN_AMPDUHE_TB 0xAF8
+#define MIB_RX_UNASSOCIATED_MGMT_IN_HE_TB 0xAFC
+#define MIB_HTP_FAILED_MEDIUM_CHECK_COUNT 0xB00
+#define MIB_RX_ERROR_VECTOR0 0xB04
+#define MIB_RX_ERROR_VECTOR1 0xB08
+#define MIB_RX_ERROR_VECTOR2 0xB0C
+#define MIB_RX_ERROR_VECTOR3 0xB10
+#define MIB_RX_ERROR_VECTOR4 0xB14
+#define MIB_RX_ERROR_VECTOR5 0xB18
+#define MIB_RX_ERROR_VECTOR6 0xB1C
+#define MIB_RX_ERROR_VECTOR7 0xB20
+#define MIB_RX_ERROR_VECTOR8 0xB24
+#define MIB_RX_ERROR_VECTOR9 0xB28
+#define MIB_RX_ERROR_VECTOR10 0xB2C
+#define MIB_RX_ERROR_VECTOR11 0xB5C
+#define MIB_RX_ERROR_VECTOR12 0xB60
+#define MIB_RX_ERROR_VECTOR13 0xB64
+#define MIB_RX_ERROR_VECTOR14 0xB68
+#define MIB_RX_ERROR_VECTOR15 0xB6C
+
+void cl_mib_cntrs_dump(struct cl_hw *cl_hw);
+u32 cl_mib_cntr_read(struct cl_hw *cl_hw, u32 addr);
+
+#endif /* CL_MIB_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.
________________________________


^ permalink raw reply related	[flat|nested] 262+ messages in thread

* [RFC v1 115/256] cl8k: add motion_sense.c
  2021-06-17 15:58 [RFC v1 000/256] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (113 preceding siblings ...)
  2021-06-17 16:00 ` [RFC v1 114/256] cl8k: add mib.h viktor.barna
@ 2021-06-17 16:00 ` viktor.barna
  2021-06-17 16:00 ` [RFC v1 116/256] cl8k: add motion_sense.h viktor.barna
                   ` (142 subsequent siblings)
  257 siblings, 0 replies; 262+ messages in thread
From: viktor.barna @ 2021-06-17 16:00 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Oleksandr Savchenko, Shay Bar, Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

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

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 .../net/wireless/celeno/cl8k/motion_sense.c   | 458 ++++++++++++++++++
 1 file changed, 458 insertions(+)
 create mode 100644 drivers/net/wireless/celeno/cl8k/motion_sense.c

diff --git a/drivers/net/wireless/celeno/cl8k/motion_sense.c b/drivers/net/wireless/celeno/cl8k/motion_sense.c
new file mode 100644
index 000000000000..bd8b1c6df08e
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/motion_sense.c
@@ -0,0 +1,458 @@
+// SPDX-License-Identifier: MIT
+/* Copyright(c) 2019-2021, Celeno Communications Ltd. */
+
+#include "motion_sense.h"
+#include "rssi.h"
+#include "chip.h"
+
+#define MOTION_PRINT(...) \
+       do { \
+               if (cl_hw->motion_sense_dbg) \
+                       pr_debug(__VA_ARGS__); \
+       } while (0)
+
+/* Minimum time (+1) for taking a decison */
+#define MOTION_SENSE_MIN_DECISION_MGMT_CTL 4
+#define MOTION_SENSE_MIN_DECISION_DATA     9
+#define MOTION_SENSE_MIN_DECISION_BA       9
+
+#define MOTION_STATE_STR(state) \
+       (((state) == STATE_NULL) ? "NULL" : \
+       (((state) == STATE_MOVING) ? "MOVING" : "STATIC")) \
+
+static void _cl_motion_sense_sta_add(struct cl_motion_rssi *motion_rssi)
+{
+       motion_rssi->max = S8_MIN;
+       motion_rssi->min = S8_MAX;
+}
+
+void cl_motion_sense_sta_add(struct cl_hw *cl_hw, struct cl_sta *cl_sta)
+{
+       _cl_motion_sense_sta_add(&cl_sta->motion_sense.rssi_mgmt_ctl);
+       _cl_motion_sense_sta_add(&cl_sta->motion_sense.rssi_data);
+       _cl_motion_sense_sta_add(&cl_sta->motion_sense.rssi_ba);
+}
+
+static void cl_motion_sense_rssi_handler(struct cl_hw *cl_hw,
+                                        struct cl_motion_rssi *motion_rssi,
+                                        s8 rssi[MAX_ANTENNAS])
+{
+       u8 i;
+
+       motion_rssi->cnt++;
+
+       for (i = 0; i < cl_hw->num_antennas; i++)
+               motion_rssi->sum[i] += rssi[i];
+}
+
+void cl_motion_sense_rssi_mgmt_ctl(struct cl_hw *cl_hw, struct cl_sta *cl_sta,
+                                  struct hw_rxhdr *rxhdr)
+{
+       /* RSSI of mgmt and ctl packets */
+       if (cl_hw->conf->ci_motion_sense_en) {
+               s8 rssi[MAX_ANTENNAS] = RX_HDR_RSSI(rxhdr);
+
+               cl_motion_sense_rssi_handler(cl_hw, &cl_sta->motion_sense.rssi_mgmt_ctl, rssi);
+       }
+}
+
+void cl_motion_sense_rssi_data(struct cl_hw *cl_hw, struct cl_sta *cl_sta,
+                              struct hw_rxhdr *rxhdr)
+{
+       /* RSSI of data packets */
+       s8 rssi[MAX_ANTENNAS] = RX_HDR_RSSI(rxhdr);
+
+       if (!cl_hw->conf->ci_motion_sense_en)
+               return;
+
+       cl_motion_sense_rssi_handler(cl_hw, &cl_sta->motion_sense.rssi_data, rssi);
+}
+
+void cl_motion_sense_rssi_ba(struct cl_hw *cl_hw, struct cl_sta *cl_sta, s8 rssi[MAX_ANTENNAS])
+{
+       /* RSSI of block-acks */
+       if (cl_hw->conf->ci_motion_sense_en)
+               cl_motion_sense_rssi_handler(cl_hw, &cl_sta->motion_sense.rssi_ba, rssi);
+}
+
+static s8 cl_motion_sense_calc_new_rssi(struct cl_hw *cl_hw, struct cl_motion_rssi *motion_rssi)
+{
+       u8 i = 0;
+       s8 rssi_avg[MAX_ANTENNAS] = {0};
+
+       /* Calculate average rssi */
+       for (i = 0; i < cl_hw->num_antennas; i++)
+               rssi_avg[i] = (s8)(motion_rssi->sum[i] / motion_rssi->cnt);
+
+       /* Reset rssi sum for next maintenance cycle */
+       memset(motion_rssi->sum, 0, sizeof(motion_rssi->sum));
+       motion_rssi->cnt = 0;
+
+       return cl_rssi_calc_equivalent(cl_hw, rssi_avg);
+}
+
+static void cl_motion_sense_state(struct cl_hw *cl_hw, struct cl_motion_rssi *motion_rssi,
+                                 u8 sta_idx, u8 min_history, const s8 *type)
+{
+       u8 i = 0;
+       s8 rssi_new = 0, rssi_old = 0;
+
+       if (motion_rssi->cnt == 0)
+               return;
+
+       /* Get new and old rssi */
+       rssi_new = cl_motion_sense_calc_new_rssi(cl_hw, motion_rssi);
+       rssi_old = motion_rssi->history[motion_rssi->idx];
+
+       /* Add new rssi to history and increase history index */
+       motion_rssi->history[motion_rssi->idx] = rssi_new;
+
+       motion_rssi->idx++;
+       if (motion_rssi->idx == MOTION_SENSE_SIZE)
+               motion_rssi->idx = 0;
+
+       /* Check if new rssi is max or min */
+       if (rssi_new > motion_rssi->max) {
+               motion_rssi->max = rssi_new;
+               goto out;
+       } else if (rssi_new < motion_rssi->min) {
+               motion_rssi->min = rssi_new;
+               goto out;
+       }
+
+       /*
+        * Check if old rssi was max or min.
+        * If so, go over history and find new max/min
+        */
+       if (rssi_old == motion_rssi->max) {
+               motion_rssi->max = S8_MIN;
+
+               for (i = 0; i < MOTION_SENSE_SIZE; i++) {
+                       if (motion_rssi->history[i] == 0)
+                               break;
+
+                       if (motion_rssi->history[i] > motion_rssi->max)
+                               motion_rssi->max = motion_rssi->history[i];
+               }
+       } else if (rssi_old == motion_rssi->min) {
+               motion_rssi->min = S8_MAX;
+
+               for (i = 0; i < MOTION_SENSE_SIZE; i++) {
+                       if (motion_rssi->history[i] == 0)
+                               break;
+
+                       if (motion_rssi->history[i] < motion_rssi->min)
+                               motion_rssi->min = motion_rssi->history[i];
+               }
+       }
+
+out:
+       /* Wait X second after connection, before making first decision */
+       if (motion_rssi->history[min_history] == 0)
+               return;
+
+       /* According to delta decide if station is STATIC or in MOTION */
+       if ((motion_rssi->max - motion_rssi->min) < cl_hw->conf->ci_motion_sense_rssi_thr) {
+               if (motion_rssi->state == STATE_STATIC)
+                       return;
+
+               motion_rssi->state = STATE_STATIC;
+
+               MOTION_PRINT("[MOTION_SENSE] %s - sta_idx=%u, min=%d, max=%d, state=STATIC\n",
+                            type, sta_idx, motion_rssi->min, motion_rssi->max);
+       } else {
+               if (motion_rssi->state == STATE_MOVING)
+                       return;
+
+               motion_rssi->state = STATE_MOVING;
+
+               MOTION_PRINT("[MOTION_SENSE] %s - sta_idx=%u, min=%d, max=%d, state=MOVING\n",
+                            type, sta_idx, motion_rssi->min, motion_rssi->max);
+       }
+}
+
+static void _cl_motion_sense_dump(char **buf, int *len, ssize_t *buf_size,
+                                 struct cl_motion_rssi *motion_rssi,
+                                 const s8 *type)
+{
+       int delta = motion_rssi->max - motion_rssi->min;
+       int i;
+
+       cl_snprintf(buf, len, buf_size, "\n");
+       cl_snprintf(buf, len, buf_size, "type = %s\n", type);
+       cl_snprintf(buf, len, buf_size,
+                   "state = %s\n", MOTION_STATE_STR(motion_rssi->state));
+       cl_snprintf(buf, len, buf_size,
+                   "min = %d\n", motion_rssi->min);
+       cl_snprintf(buf, len, buf_size,
+                   "max = %d\n", motion_rssi->max);
+       cl_snprintf(buf, len, buf_size,
+                   "delta = %d\n", delta);
+       cl_snprintf(buf, len, buf_size,
+                   "idx = %u\n", motion_rssi->idx);
+
+       for (i = 0; i < MOTION_SENSE_SIZE; i++) {
+               if (motion_rssi->history[i])
+                       cl_snprintf(buf, len, buf_size,
+                                   "%2i) = %3d, ", i, motion_rssi->history[i]);
+               else
+                       break;
+
+               if ((i % 8) == 7)
+                       cl_snprintf(buf, len, buf_size, "\n");
+       }
+
+       cl_snprintf(buf, len, buf_size, "\n");
+}
+
+static int cl_motion_sense_dump(struct cl_hw *cl_hw, u8 sta_idx)
+{
+       struct cl_sta *cl_sta = NULL;
+       struct cl_motion_sense *motion_sense = NULL;
+       char *buf = NULL;
+       ssize_t buf_size;
+       int err = 0;
+       int len = 0;
+
+       cl_sta_lock_bh(cl_hw);
+       cl_sta = cl_sta_get(cl_hw, sta_idx);
+
+       if (!cl_sta) {
+               pr_err("[MS] Invalid sta_idx = %u\n", sta_idx);
+               goto out;
+       }
+
+       motion_sense = &cl_sta->motion_sense;
+
+       cl_snprintf(&buf, &len, &buf_size,
+                   "sta_idx = %u\n", sta_idx);
+
+       if (motion_sense->forced_state != STATE_NULL) {
+               cl_snprintf(&buf, &len, &buf_size,
+                           "forced_state = %s\n",
+                           MOTION_STATE_STR(motion_sense->forced_state));
+               goto out;
+       }
+
+       cl_snprintf(&buf, &len, &buf_size,
+                   "combined_state = %s\n",
+                   MOTION_STATE_STR(motion_sense->combined_state));
+
+       _cl_motion_sense_dump(&buf, &len, &buf_size, &motion_sense->rssi_mgmt_ctl, "mgmt/ctl");
+       _cl_motion_sense_dump(&buf, &len, &buf_size, &motion_sense->rssi_ba, "ba");
+       _cl_motion_sense_dump(&buf, &len, &buf_size, &motion_sense->rssi_data, "data");
+
+out:
+       cl_sta_unlock_bh(cl_hw);
+
+       err = cl_vendor_reply(cl_hw, buf, len);
+       kfree(buf);
+
+       return err;
+}
+
+static void cl_motion_sense_moving(struct cl_hw *cl_hw, struct cl_sta *cl_sta,
+                                  struct cl_motion_sense *motion_sense)
+{
+       if (motion_sense->combined_state != STATE_MOVING) {
+               motion_sense->combined_state = STATE_MOVING;
+               MOTION_PRINT("[MOTION_SENSE] sta_idx = %u, combined_state = MOVING\n",
+                            cl_sta->sta_idx);
+       }
+}
+
+static void cl_motion_sense_static(struct cl_hw *cl_hw, struct cl_sta *cl_sta,
+                                  struct cl_motion_sense *motion_sense)
+{
+       if (motion_sense->combined_state != STATE_STATIC) {
+               motion_sense->combined_state = STATE_STATIC;
+               MOTION_PRINT("[MOTION_SENSE] sta_idx = %u, combined_state = STATIC\n",
+                            cl_sta->sta_idx);
+       }
+}
+
+static void cl_motion_sense_combined_state(struct cl_hw *cl_hw, struct cl_sta *cl_sta)
+{
+       struct cl_motion_sense *motion_sense = &cl_sta->motion_sense;
+
+       if (motion_sense->rssi_mgmt_ctl.history[MOTION_SENSE_MIN_DECISION_MGMT_CTL] == 0 &&
+           motion_sense->rssi_data.history[MOTION_SENSE_MIN_DECISION_DATA] == 0 &&
+           motion_sense->rssi_ba.history[MOTION_SENSE_MIN_DECISION_BA] == 0)
+               return;
+
+       if (motion_sense->rssi_mgmt_ctl.state == STATE_MOVING ||
+           motion_sense->rssi_data.state == STATE_MOVING ||
+           motion_sense->rssi_ba.state == STATE_MOVING)
+               cl_motion_sense_moving(cl_hw, cl_sta, motion_sense);
+       else
+               cl_motion_sense_static(cl_hw, cl_sta, motion_sense);
+}
+
+static void cl_motion_sense_maintenance_sta(struct cl_hw *cl_hw, struct cl_sta *cl_sta)
+{
+       u8 sta_idx = cl_sta->sta_idx;
+       struct cl_motion_sense *motion_sense = &cl_sta->motion_sense;
+
+       cl_motion_sense_state(cl_hw, &motion_sense->rssi_mgmt_ctl, sta_idx,
+                             MOTION_SENSE_MIN_DECISION_MGMT_CTL, "mgmt/ctl");
+       cl_motion_sense_state(cl_hw, &motion_sense->rssi_data, sta_idx,
+                             MOTION_SENSE_MIN_DECISION_DATA, "data");
+       cl_motion_sense_state(cl_hw, &motion_sense->rssi_ba, sta_idx,
+                             MOTION_SENSE_MIN_DECISION_BA, "ba");
+
+       if (motion_sense->forced_state != STATE_NULL)
+               return;
+
+       cl_motion_sense_combined_state(cl_hw, cl_sta);
+}
+
+void cl_motion_sense_maintenance(struct cl_hw *cl_hw)
+{
+       cl_sta_loop(cl_hw, cl_motion_sense_maintenance_sta);
+}
+
+bool cl_motion_sense_is_static(struct cl_hw *cl_hw, struct cl_sta *cl_sta)
+{
+       return (cl_sta->motion_sense.combined_state == STATE_STATIC);
+}
+
+static void cl_motion_sense_force_state(struct cl_hw *cl_hw, u8 sta_idx, u8 state)
+{
+       struct cl_sta *cl_sta = NULL;
+       struct cl_motion_sense *motion_sense = NULL;
+
+       cl_sta_lock_bh(cl_hw);
+       cl_sta = cl_sta_get(cl_hw, sta_idx);
+
+       if (!cl_sta) {
+               pr_err("[MS] Invalid station (%u)\n", sta_idx);
+               goto out;
+       }
+
+       motion_sense = &cl_sta->motion_sense;
+
+       switch (state) {
+       case STATE_NULL:
+               pr_debug("[MS] Disable force state\n");
+               break;
+       case STATE_MOVING:
+               pr_debug("[MS] Force state - MOVING\n");
+               cl_motion_sense_moving(cl_hw, cl_sta, motion_sense);
+               break;
+       case STATE_STATIC:
+               pr_debug("[MS] Force state - STATIC\n");
+               cl_motion_sense_static(cl_hw, cl_sta, motion_sense);
+               break;
+       default:
+               pr_warn("[MS] Invalid state (%u)\n", state);
+               goto out;
+       }
+
+       motion_sense->forced_state = state;
+
+out:
+       cl_sta_unlock_bh(cl_hw);
+}
+
+static int cl_motion_sense_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,
+                "motion usage:\n"
+                "-d: Set debug [0/1]\n"
+                "-e: Set enable [0/1]\n"
+                "-f: Force state [sta_idx].[0-null, 1-moving, 2-static]\n"
+                "-i: Dump info [sta_idx]\n"
+                "-r: Set rssi threshold [rssi]\n");
+
+       err = cl_vendor_reply(cl_hw, buf, strlen(buf));
+       kfree(buf);
+
+       return err;
+}
+
+int cl_motion_sense_cli(struct cl_hw *cl_hw, struct cli_params *cli_params)
+{
+       u32 expected_params = 0;
+       bool set_debug = false;
+       bool set_enable = false;
+       bool force_state = false;
+       bool dump_info = false;
+       bool set_rssi_thr = false;
+
+       switch (cli_params->option) {
+       case 'd':
+               set_debug = true;
+               expected_params = 1;
+               break;
+       case 'e':
+               set_enable = true;
+               expected_params = 1;
+               break;
+       case 'f':
+               force_state = true;
+               expected_params = 2;
+               break;
+       case 'i':
+               dump_info = true;
+               expected_params = 1;
+               break;
+       case 'r':
+               set_rssi_thr = true;
+               expected_params = 1;
+               break;
+       case '?':
+               return cl_motion_sense_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 (set_debug) {
+               cl_hw->motion_sense_dbg = (bool)cli_params->params[0];
+               pr_debug("[MS] debug = %u\n", cl_hw->motion_sense_dbg);
+               return 0;
+       }
+
+       if (dump_info) {
+               u8 sta_idx = (u8)cli_params->params[0];
+
+               return cl_motion_sense_dump(cl_hw, sta_idx);
+       }
+
+       if (set_enable) {
+               cl_hw->conf->ci_motion_sense_en = (bool)cli_params->params[0];
+               pr_debug("[MS] ci_motion_sense_en = %s\n",
+                        cl_hw->conf->ci_motion_sense_en ? "true" : "false");
+               return 0;
+       }
+
+       if (force_state) {
+               u8 sta_idx = (u8)cli_params->params[0];
+               u8 state = (u8)cli_params->params[1];
+
+               cl_motion_sense_force_state(cl_hw, sta_idx, state);
+               return 0;
+       }
+
+       if (set_rssi_thr) {
+               cl_hw->conf->ci_motion_sense_rssi_thr = (s8)cli_params->params[0];
+               pr_debug("[MS] ci_motion_sense_rssi_thr = %d\n",
+                        cl_hw->conf->ci_motion_sense_rssi_thr);
+               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.
________________________________


^ permalink raw reply related	[flat|nested] 262+ messages in thread

* [RFC v1 116/256] cl8k: add motion_sense.h
  2021-06-17 15:58 [RFC v1 000/256] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (114 preceding siblings ...)
  2021-06-17 16:00 ` [RFC v1 115/256] cl8k: add motion_sense.c viktor.barna
@ 2021-06-17 16:00 ` viktor.barna
  2021-06-17 16:00 ` [RFC v1 117/256] cl8k: add netlink.c viktor.barna
                   ` (141 subsequent siblings)
  257 siblings, 0 replies; 262+ messages in thread
From: viktor.barna @ 2021-06-17 16:00 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Oleksandr Savchenko, Shay Bar, Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

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

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 .../net/wireless/celeno/cl8k/motion_sense.h   | 47 +++++++++++++++++++
 1 file changed, 47 insertions(+)
 create mode 100644 drivers/net/wireless/celeno/cl8k/motion_sense.h

diff --git a/drivers/net/wireless/celeno/cl8k/motion_sense.h b/drivers/net/wireless/celeno/cl8k/motion_sense.h
new file mode 100644
index 000000000000..a3846acf278f
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/motion_sense.h
@@ -0,0 +1,47 @@
+/* SPDX-License-Identifier: MIT */
+/* Copyright(c) 2019-2021, Celeno Communications Ltd. */
+
+#ifndef CL_MOTION_SENSE_H
+#define CL_MOTION_SENSE_H
+
+#include "hw.h"
+#include "rx/rx.h"
+#include <linux/types.h>
+
+#define MOTION_SENSE_SIZE 30
+
+enum cl_motion_state {
+       STATE_NULL,
+       STATE_MOVING,
+       STATE_STATIC
+};
+
+struct cl_motion_rssi {
+       s32 sum[MAX_ANTENNAS];
+       s32 cnt;
+       s8 history[MOTION_SENSE_SIZE];
+       u8 idx;
+       s8 max;
+       s8 min;
+       enum cl_motion_state state;
+};
+
+struct cl_motion_sense {
+       struct cl_motion_rssi rssi_mgmt_ctl;
+       struct cl_motion_rssi rssi_data;
+       struct cl_motion_rssi rssi_ba;
+       enum cl_motion_state combined_state;
+       enum cl_motion_state forced_state;
+};
+
+void cl_motion_sense_sta_add(struct cl_hw *cl_hw, struct cl_sta *cl_sta);
+void cl_motion_sense_rssi_mgmt_ctl(struct cl_hw *cl_hw, struct cl_sta *cl_sta,
+                                  struct hw_rxhdr *rxhdr);
+void cl_motion_sense_rssi_data(struct cl_hw *cl_hw, struct cl_sta *cl_sta,
+                              struct hw_rxhdr *rxhdr);
+void cl_motion_sense_rssi_ba(struct cl_hw *cl_hw, struct cl_sta *cl_sta, s8 rssi[MAX_ANTENNAS]);
+void cl_motion_sense_maintenance(struct cl_hw *cl_hw);
+bool cl_motion_sense_is_static(struct cl_hw *cl_hw, struct cl_sta *cl_sta);
+int cl_motion_sense_cli(struct cl_hw *cl_hw, struct cli_params *cli_params);
+
+#endif /* CL_MOTION_SENSE_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.
________________________________


^ permalink raw reply related	[flat|nested] 262+ messages in thread

* [RFC v1 117/256] cl8k: add netlink.c
  2021-06-17 15:58 [RFC v1 000/256] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (115 preceding siblings ...)
  2021-06-17 16:00 ` [RFC v1 116/256] cl8k: add motion_sense.h viktor.barna
@ 2021-06-17 16:00 ` viktor.barna
  2021-06-17 16:00 ` [RFC v1 118/256] cl8k: add netlink.h viktor.barna
                   ` (140 subsequent siblings)
  257 siblings, 0 replies; 262+ messages in thread
From: viktor.barna @ 2021-06-17 16:00 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Oleksandr Savchenko, Shay Bar, Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

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

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 drivers/net/wireless/celeno/cl8k/netlink.c | 41 ++++++++++++++++++++++
 1 file changed, 41 insertions(+)
 create mode 100644 drivers/net/wireless/celeno/cl8k/netlink.c

diff --git a/drivers/net/wireless/celeno/cl8k/netlink.c b/drivers/net/wireless/celeno/cl8k/netlink.c
new file mode 100644
index 000000000000..cc03575704ad
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/netlink.c
@@ -0,0 +1,41 @@
+// SPDX-License-Identifier: MIT
+/* Copyright(c) 2019-2021, Celeno Communications Ltd. */
+
+#include <linux/kernel.h>
+#include <linux/version.h>
+#include <linux/socket.h>
+#include <linux/rtnetlink.h>
+#include <net/cfg80211.h>
+
+#include "netlink.h"
+
+void cl_netlink_send_async(struct cl_hw *cl_hw, struct cl_nl_event *event)
+{
+       struct sk_buff *skb = NULL;
+       int msg_len;
+
+       msg_len = sizeof(*event);
+       skb = cfg80211_vendor_event_alloc(cl_hw->hw->wiphy, NULL, msg_len,
+                                         CL_VENDOR_EVENT_ASYNC, GFP_ATOMIC);
+       if (!skb) {
+               cl_dbg_err(cl_hw, "vendor_event_alloc(len:%u) failed\n", msg_len);
+               return;
+       }
+
+       if (nla_put(skb, CL_VENDOR_ATTR_DATA, msg_len, event)) {
+               kfree_skb(skb);
+               return;
+       }
+
+       cfg80211_vendor_event(skb, GFP_ATOMIC);
+}
+
+void cl_netlink_send_event_co_locate_update(struct cl_hw *cl_hw)
+{
+       struct cl_nl_event event = {0};
+
+       event.tcv_idx = cl_hw->idx;
+       event.event_id = CL_NL_EVENT_ID_CO_LOCATE_UPDATE;
+
+       cl_netlink_send_async(cl_hw, &event);
+}
--
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.
________________________________


^ permalink raw reply related	[flat|nested] 262+ messages in thread

* [RFC v1 118/256] cl8k: add netlink.h
  2021-06-17 15:58 [RFC v1 000/256] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (116 preceding siblings ...)
  2021-06-17 16:00 ` [RFC v1 117/256] cl8k: add netlink.c viktor.barna
@ 2021-06-17 16:00 ` viktor.barna
  2021-06-17 16:00 ` [RFC v1 119/256] cl8k: add noise.c viktor.barna
                   ` (139 subsequent siblings)
  257 siblings, 0 replies; 262+ messages in thread
From: viktor.barna @ 2021-06-17 16:00 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Oleksandr Savchenko, Shay Bar, Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

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

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 drivers/net/wireless/celeno/cl8k/netlink.h | 28 ++++++++++++++++++++++
 1 file changed, 28 insertions(+)
 create mode 100644 drivers/net/wireless/celeno/cl8k/netlink.h

diff --git a/drivers/net/wireless/celeno/cl8k/netlink.h b/drivers/net/wireless/celeno/cl8k/netlink.h
new file mode 100644
index 000000000000..7bc7f0404a73
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/netlink.h
@@ -0,0 +1,28 @@
+/* SPDX-License-Identifier: MIT */
+/* Copyright(c) 2019-2021, Celeno Communications Ltd. */
+
+#ifndef CL_NETLINK_H
+#define CL_NETLINK_H
+
+#include "hw.h"
+#include "vif.h"
+
+#define CL_NL_MAX_PAYLOAD 512
+
+struct cl_nl_event {
+       char event_id;
+       char tcv_idx;
+       char data[CL_NL_MAX_PAYLOAD];
+};
+
+enum cl_nl_event_id {
+       CL_NL_EVENT_ID_UNSPEC,
+       CL_NL_EVENT_ID_CO_LOCATE_UPDATE,
+
+       CL_NL_EVENT_ID_MAX
+};
+
+void cl_netlink_send_async(struct cl_hw *cl_hw, struct cl_nl_event *event);
+void cl_netlink_send_event_co_locate_update(struct cl_hw *cl_hw);
+
+#endif /* CL_NETLINK_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.
________________________________


^ permalink raw reply related	[flat|nested] 262+ messages in thread

* [RFC v1 119/256] cl8k: add noise.c
  2021-06-17 15:58 [RFC v1 000/256] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (117 preceding siblings ...)
  2021-06-17 16:00 ` [RFC v1 118/256] cl8k: add netlink.h viktor.barna
@ 2021-06-17 16:00 ` viktor.barna
  2021-06-17 16:00 ` [RFC v1 120/256] cl8k: add noise.h viktor.barna
                   ` (138 subsequent siblings)
  257 siblings, 0 replies; 262+ messages in thread
From: viktor.barna @ 2021-06-17 16:00 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Oleksandr Savchenko, Shay Bar, Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

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

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 drivers/net/wireless/celeno/cl8k/noise.c | 499 +++++++++++++++++++++++
 1 file changed, 499 insertions(+)
 create mode 100644 drivers/net/wireless/celeno/cl8k/noise.c

diff --git a/drivers/net/wireless/celeno/cl8k/noise.c b/drivers/net/wireless/celeno/cl8k/noise.c
new file mode 100644
index 000000000000..0bfd025196a6
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/noise.c
@@ -0,0 +1,499 @@
+// SPDX-License-Identifier: MIT
+/* Copyright(c) 2019-2021, Celeno Communications Ltd. */
+
+#include <linux/list.h>
+#include "hw.h"
+#include "noise.h"
+#include "reg/reg_riu.h"
+#include "utils/utils.h"
+
+#define NOISE_LOWER_LIMIT -100
+#define NOISE_UPPER_LIMIT -30
+/* Range is -100dBm to -30dBm */
+#define NOISE_SCALE_RANGE  (NOISE_UPPER_LIMIT - NOISE_LOWER_LIMIT + 1)
+#define NOISE_MAX_SAMPLES  U8_MAX
+#define MAX_20M_SUB_BAND   8
+#define MAX_SEC_BW_CNT     3
+#define MAX_ANT_PER_REG    4
+
+static s8 cl_noise_process_sample(u32 sample, u8 cnt)
+{
+       s8 val = (s8)((sample >> (8 * cnt)) & 0xff);
+
+       if (val < NOISE_LOWER_LIMIT)
+               val = NOISE_LOWER_LIMIT;
+       else if (val > NOISE_UPPER_LIMIT)
+               val = NOISE_UPPER_LIMIT;
+
+       return val;
+}
+
+static bool cl_noise_is_hist_line_empty(u8 *hist, u8 cnt)
+{
+       u8 i;
+
+       for (i = 0; i < cnt; i++)
+               if (hist[i] != 0)
+                       return false;
+
+       return true;
+}
+
+static int cl_noise_print_hist(struct cl_hw *cl_hw, bool nasp_stats)
+{
+       struct cl_noise_db *noise_db = &cl_hw->noise_db;
+       struct cl_noise_reg *reg = NULL;
+       u8 hist[NOISE_SCALE_RANGE][MAX_ANTENNAS] = { { 0 } };
+       u8 num_antennas = cl_hw->num_antennas;
+       s8 val_stat;
+       u8 i = 0, j = 0;
+       char *buf = NULL;
+       ssize_t buf_size;
+       int err = 0;
+       int len = 0;
+
+       if (list_empty(&noise_db->reg_list))
+               return 0;
+
+       list_for_each_entry(reg, &noise_db->reg_list, list) {
+               for (i = 0; i < min_t(u8, num_antennas, MAX_ANT_PER_REG); i++) {
+                       if (nasp_stats)
+                               val_stat = cl_noise_process_sample(reg->nasp_prim20_per_ant, i);
+                       else
+                               val_stat = cl_noise_process_sample(reg->np_prim20_per_ant, i);
+
+                       hist[(val_stat * -1) + NOISE_UPPER_LIMIT][i]++;
+               }
+
+               if (num_antennas <= MAX_ANT_PER_REG)
+                       continue;
+
+               for (i = 0; i < num_antennas - MAX_ANT_PER_REG; i++) {
+                       if (nasp_stats)
+                               val_stat = cl_noise_process_sample(reg->nasp_prim20_per_ant2, i);
+                       else
+                               val_stat = cl_noise_process_sample(reg->np_prim20_per_ant2, i);
+
+                       hist[(val_stat * -1) + NOISE_UPPER_LIMIT][i + MAX_ANT_PER_REG]++;
+               }
+       }
+
+       cl_snprintf(&buf, &len, &buf_size,
+                   "Noise %sstrength histogram (dBm):\n", nasp_stats ? "and signal " : "");
+
+       cl_snprintf(&buf, &len, &buf_size, "------------------");
+       for (j = 0; j < num_antennas; j++)
+               cl_snprintf(&buf, &len, &buf_size, "-------");
+
+       cl_snprintf(&buf, &len, &buf_size, "\n| Noise Strength ");
+
+       for (j = 0; j < num_antennas; j++)
+               cl_snprintf(&buf, &len, &buf_size, "| Ant%u ", j);
+
+       cl_snprintf(&buf, &len, &buf_size, "|\n|----------------");
+
+       for (j = 0; j < num_antennas; j++)
+               cl_snprintf(&buf, &len, &buf_size, "+------");
+
+       cl_snprintf(&buf, &len, &buf_size, "|\n");
+
+       for (i = 0; i < NOISE_SCALE_RANGE; i++) {
+               if (cl_noise_is_hist_line_empty(hist[i], num_antennas))
+                       continue;
+
+               cl_snprintf(&buf, &len, &buf_size, "|%9d       ", -i + NOISE_UPPER_LIMIT);
+               for (j = 0; j < num_antennas; j++)
+                       cl_snprintf(&buf, &len, &buf_size, "| %3u  ", hist[i][j]);
+
+               cl_snprintf(&buf, &len, &buf_size, "|\n");
+       }
+
+       cl_snprintf(&buf, &len, &buf_size, "|----------------");
+       for (j = 0; j < num_antennas; j++)
+               cl_snprintf(&buf, &len, &buf_size, "+------");
+
+       cl_snprintf(&buf, &len, &buf_size, "|\n");
+
+       err = cl_vendor_reply(cl_hw, buf, len);
+       kfree(buf);
+
+       return err;
+}
+
+static int cl_noise_print_hist_per_channel(struct cl_hw *cl_hw,
+                                          bool nasp_stats)
+{
+       struct cl_noise_db *noise_db = &cl_hw->noise_db;
+       struct cl_noise_reg *reg = NULL;
+       u8 ch_bw = cl_hw->conf->ce_channel_bandwidth;
+       u8 ch_cnt = 1 << ch_bw;
+       u8 hist[NOISE_SCALE_RANGE][MAX_20M_SUB_BAND] = { { 0 } };
+       s8 val1, val2;
+       u8 i = 0, j = 0;
+       char *buf = NULL;
+       ssize_t buf_size;
+       int err = 0;
+       int len = 0;
+
+       if (list_empty(&noise_db->reg_list))
+               return 0;
+
+       list_for_each_entry(reg, &noise_db->reg_list, list) {
+               for (i = 0; i < min_t(u8, ch_cnt, MAX_ANT_PER_REG); i++) {
+                       if (nasp_stats) {
+                               val1 = cl_noise_process_sample(reg->nasp_sub20_per_chn, i);
+
+                               if (ch_bw == CHNL_BW_160)
+                                       val2 = cl_noise_process_sample(reg->nasp_sub20_per_chn2, i);
+                       } else {
+                               val1 = cl_noise_process_sample(reg->np_sub20_per_chn, i);
+
+                               if (ch_bw == CHNL_BW_160)
+                                       val2 = cl_noise_process_sample(reg->np_sub20_per_chn2, i);
+                       }
+
+                       hist[(val1 * -1) + NOISE_UPPER_LIMIT][i]++;
+                       if (ch_bw == CHNL_BW_160)
+                               hist[(val2 * -1) + NOISE_UPPER_LIMIT][i + MAX_ANT_PER_REG]++;
+               }
+       }
+
+       cl_snprintf(&buf, &len, &buf_size,
+                   "Noise %sstrength per 20 Mhz channel histogram ant %u (dBm):\n"
+                   "------------------",
+                   nasp_stats ? "and signal " : "", noise_db->active_ant);
+
+       for (j = 0; j < ch_cnt; j++)
+               cl_snprintf(&buf, &len, &buf_size, "--------");
+
+       cl_snprintf(&buf, &len, &buf_size, "\n| Noise Strength ");
+       for (j = 0; j < ch_cnt; j++)
+               cl_snprintf(&buf, &len, &buf_size, "| Chan%u ", j);
+
+       cl_snprintf(&buf, &len, &buf_size, "|\n|----------------");
+
+       for (j = 0; j < ch_cnt; j++)
+               cl_snprintf(&buf, &len, &buf_size, "+-------");
+
+       cl_snprintf(&buf, &len, &buf_size, "|\n");
+
+       for (i = 0; i < NOISE_SCALE_RANGE; i++) {
+               if (cl_noise_is_hist_line_empty(hist[i], ch_cnt))
+                       continue;
+
+               cl_snprintf(&buf, &len, &buf_size, "|%9d       ", -i + NOISE_UPPER_LIMIT);
+
+               for (j = 0; j < ch_cnt; j++)
+                       cl_snprintf(&buf, &len, &buf_size, "| %3u   ", hist[i][j]);
+
+               cl_snprintf(&buf, &len, &buf_size, "|\n");
+       }
+
+       cl_snprintf(&buf, &len, &buf_size, "|----------------");
+
+       for (j = 0; j < ch_cnt; j++)
+               cl_snprintf(&buf, &len, &buf_size, "+-------");
+
+       cl_snprintf(&buf, &len, &buf_size, "|\n");
+
+       err = cl_vendor_reply(cl_hw, buf, len);
+       kfree(buf);
+
+       return err;
+}
+
+static int cl_noise_print_hist_dens(struct cl_hw *cl_hw, bool nasp_stats)
+{
+       struct cl_noise_db *noise_db = &cl_hw->noise_db;
+       struct cl_noise_reg *reg = NULL;
+       u8 hist[NOISE_SCALE_RANGE][MAX_SEC_BW_CNT] = { { 0 } };
+       u8 ch_bw = cl_hw->conf->ce_channel_bandwidth;
+       s8 val;
+       u8 i = 0, j = 0;
+       char *buf = NULL;
+       ssize_t buf_size;
+       int err = 0;
+       int len = 0;
+
+       if (list_empty(&noise_db->reg_list) || ch_bw == 0)
+               return 0;
+
+       list_for_each_entry(reg, &noise_db->reg_list, list) {
+               for (i = 0; i < ch_bw; i++) {
+                       if (nasp_stats)
+                               val = cl_noise_process_sample(reg->nasp_sec20_dens_per_ant, i);
+                       else
+                               val = cl_noise_process_sample(reg->np_sec20_dens_per_ant, i);
+
+                       hist[(val * -1) + NOISE_UPPER_LIMIT][i]++;
+               }
+       }
+
+       cl_snprintf(&buf, &len, &buf_size,
+                   "Noise %spower density histogram ant %u (dBm/20Mhz):\n",
+                   nasp_stats ? "and signal " : "", noise_db->active_ant);
+
+       cl_snprintf(&buf, &len, &buf_size, "-----------------");
+
+       for (j = 0; j < ch_bw; j++)
+               cl_snprintf(&buf, &len, &buf_size, "--------");
+
+       cl_snprintf(&buf, &len, &buf_size, "\n| Noise Density ");
+
+       for (j = 0; j < ch_bw; j++)
+               cl_snprintf(&buf, &len, &buf_size, "| SEC%u ", 20 * (1 << j));
+
+       cl_snprintf(&buf, &len, &buf_size, "|\n|---------------");
+       for (j = 0; j < ch_bw; j++)
+               cl_snprintf(&buf, &len, &buf_size, "+-------");
+
+       cl_snprintf(&buf, &len, &buf_size, "|\n");
+
+       for (i = 0; i < NOISE_SCALE_RANGE; i++) {
+               if (cl_noise_is_hist_line_empty(hist[i], ch_bw))
+                       continue;
+
+               cl_snprintf(&buf, &len, &buf_size, "|%9d      ", -i + NOISE_UPPER_LIMIT);
+               for (j = 0; j < ch_bw; j++)
+                       cl_snprintf(&buf, &len, &buf_size, "| %3u   ", hist[i][j]);
+
+               cl_snprintf(&buf, &len, &buf_size, "|\n");
+       }
+
+       cl_snprintf(&buf, &len, &buf_size, "|---------------");
+       for (j = 0; j < ch_bw; j++)
+               cl_snprintf(&buf, &len, &buf_size, "+-------");
+
+       cl_snprintf(&buf, &len, &buf_size, "|\n");
+
+       err = cl_vendor_reply(cl_hw, buf, len);
+       kfree(buf);
+
+       return err;
+}
+
+static int cl_noise_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,
+                "stats usage:\n"
+                "-a : Set antenna\n"
+                "-b : En/Dis noise histogram [0-stop, max samples-255]\n"
+                "-c : Print 20Mhz channels noise power\n"
+                "-d : Print 20Mhz channels noise and signal power\n"
+                "-e : Print noise density histogram\n"
+                "-f : Print noise and signal density histogram\n"
+                "-g : Print noise power histogram\n"
+                "-h : Print noise and signal power histogram\n"
+                "-r : Reset histogram\n");
+
+       err = cl_vendor_reply(cl_hw, buf, strlen(buf));
+       kfree(buf);
+
+       return err;
+}
+
+static void cl_noise_set_ant(struct cl_hw *cl_hw, u8 active_ant)
+{
+       struct cl_noise_db *noise_db = &cl_hw->noise_db;
+       u8 max_ant = cl_hw->num_antennas - 1;
+
+       if (noise_db->sample_cnt != 0) {
+               pr_warn("Can't set antenna during statistics collection\n");
+               return;
+       }
+
+       if (active_ant > max_ant) {
+               pr_err("Invalid antennas configuration. Should be 0-%u!\n", max_ant);
+               return;
+       }
+
+       if (active_ant == noise_db->active_ant) {
+               pr_warn("Ant %u already set!\n", active_ant);
+               return;
+       }
+
+       /* Antenna is different now so clear all stats */
+       cl_noise_close(cl_hw);
+
+       riu_rwnxagcccactrl_cca_main_ant_sel_setf(cl_hw, active_ant);
+
+       noise_db->active_ant = active_ant;
+
+       pr_debug("Antenna selected : %u\n", active_ant);
+}
+
+void cl_noise_init(struct cl_hw *cl_hw)
+{
+       struct cl_noise_db *noise_db = &cl_hw->noise_db;
+
+       INIT_LIST_HEAD(&noise_db->reg_list);
+}
+
+void cl_noise_close(struct cl_hw *cl_hw)
+{
+       struct cl_noise_db *noise_db = &cl_hw->noise_db;
+       struct cl_noise_reg *elem = NULL;
+       struct cl_noise_reg *tmp = NULL;
+
+       list_for_each_entry_safe(elem, tmp, &noise_db->reg_list, list) {
+               list_del(&elem->list);
+               kfree(elem);
+       }
+}
+
+void cl_noise_maintenance(struct cl_hw *cl_hw)
+{
+       struct cl_noise_db *noise_db = &cl_hw->noise_db;
+       struct cl_noise_reg *reg = NULL;
+       u8 ch_bw = cl_hw->conf->ce_channel_bandwidth;
+
+       if (noise_db->sample_cnt == 0)
+               return;
+
+       reg = kzalloc(sizeof(*reg), GFP_ATOMIC);
+
+       if (!reg)
+               return;
+
+       /*collect statistics */
+       reg->np_prim20_per_ant = riu_agcinbdpow_20_pnoisestat_get(cl_hw);
+       reg->np_sub20_per_chn = riu_agcinbdpownoiseper_20_stat_0_get(cl_hw);
+       reg->np_sec20_dens_per_ant = riu_agcinbdpowsecnoisestat_get(cl_hw);
+       reg->nasp_prim20_per_ant = riu_inbdpowformac_0_get(cl_hw);
+       reg->nasp_sub20_per_chn = riu_inbdpowformac_3_get(cl_hw);
+       reg->nasp_sec20_dens_per_ant = riu_inbdpowformac_2_get(cl_hw);
+
+       if (ch_bw == CHNL_BW_160) {
+               reg->np_sub20_per_chn2 = riu_agcinbdpownoiseper_20_stat_1_get(cl_hw);
+               reg->nasp_sub20_per_chn2 = riu_inbdpowformac_4_get(cl_hw);
+       }
+
+       if (cl_hw->num_antennas > MAX_ANT_PER_REG) {
+               reg->np_prim20_per_ant2 = riu_agcinbdpow_20_pnoisestat_2_get(cl_hw);
+               reg->nasp_prim20_per_ant2 = riu_inbdpowformac_1_get(cl_hw);
+       }
+
+       list_add(&reg->list, &noise_db->reg_list);
+
+       noise_db->sample_cnt--;
+
+       if (noise_db->sample_cnt == 0)
+               pr_debug("record done\n");
+}
+
+int cl_noise_cli(struct cl_hw *cl_hw, struct cli_params *cli_params)
+{
+       struct cl_noise_db *noise_db = &cl_hw->noise_db;
+       bool set_ant = false;
+       bool hist_enable = false;
+       bool hist_per_channel = false;
+       bool hist_mac_per_channel = false;
+       bool hist_dens = false;
+       bool hist_mac_dens = false;
+       bool hist_pwr_print = false;
+       bool hist_mac_pwr_print = false;
+       bool hist_reset = false;
+       u32 param = (u32)cli_params->params[0];
+       u32 expected_params = -1;
+
+       switch (cli_params->option) {
+       case 'a':
+               set_ant = true;
+               expected_params = 1;
+               break;
+       case 'b':
+               hist_enable = true;
+               expected_params = 1;
+               break;
+       case 'c':
+               hist_per_channel = true;
+               expected_params = 0;
+               break;
+       case 'd':
+               hist_mac_per_channel = true;
+               expected_params = 0;
+               break;
+       case 'e':
+               hist_dens = true;
+               expected_params = 0;
+               break;
+       case 'f':
+               hist_mac_dens = true;
+               expected_params = 0;
+               break;
+       case 'g':
+               hist_pwr_print = true;
+               expected_params = 0;
+               break;
+       case 'h':
+               hist_mac_pwr_print = true;
+               expected_params = 0;
+               break;
+       case 'r':
+               hist_reset = true;
+               expected_params = 0;
+               break;
+       case '?':
+               return cl_noise_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 (set_ant) {
+               cl_noise_set_ant(cl_hw, (u8)param);
+
+               return 0;
+       }
+
+       if (hist_enable) {
+               if (param > NOISE_MAX_SAMPLES) {
+                       pr_err("Error! Max samples should be < %u\n", NOISE_MAX_SAMPLES);
+               } else {
+                       pr_debug("%s record histogram\n", param ? "Start" : "Stop");
+                       noise_db->sample_cnt = param;
+               }
+
+               return 0;
+       }
+
+       if (hist_per_channel)
+               return cl_noise_print_hist_per_channel(cl_hw, false);
+
+       if (hist_mac_per_channel)
+               return cl_noise_print_hist_per_channel(cl_hw, true);
+
+       if (hist_dens)
+               return cl_noise_print_hist_dens(cl_hw, false);
+
+       if (hist_mac_dens)
+               return cl_noise_print_hist_dens(cl_hw, true);
+
+       if (hist_pwr_print)
+               return cl_noise_print_hist(cl_hw, false);
+
+       if (hist_mac_pwr_print)
+               return cl_noise_print_hist(cl_hw, true);
+
+       if (hist_reset) {
+               pr_debug("Clear histogram\n");
+               cl_noise_close(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.
________________________________


^ permalink raw reply related	[flat|nested] 262+ messages in thread

* [RFC v1 120/256] cl8k: add noise.h
  2021-06-17 15:58 [RFC v1 000/256] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (118 preceding siblings ...)
  2021-06-17 16:00 ` [RFC v1 119/256] cl8k: add noise.c viktor.barna
@ 2021-06-17 16:00 ` viktor.barna
  2021-06-17 16:00 ` [RFC v1 121/256] cl8k: add omi.c viktor.barna
                   ` (137 subsequent siblings)
  257 siblings, 0 replies; 262+ messages in thread
From: viktor.barna @ 2021-06-17 16:00 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Oleksandr Savchenko, Shay Bar, Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

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

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 drivers/net/wireless/celeno/cl8k/noise.h | 15 +++++++++++++++
 1 file changed, 15 insertions(+)
 create mode 100644 drivers/net/wireless/celeno/cl8k/noise.h

diff --git a/drivers/net/wireless/celeno/cl8k/noise.h b/drivers/net/wireless/celeno/cl8k/noise.h
new file mode 100644
index 000000000000..292705e60925
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/noise.h
@@ -0,0 +1,15 @@
+/* SPDX-License-Identifier: MIT */
+/* Copyright(c) 2019-2021, Celeno Communications Ltd. */
+
+#ifndef CL_NOISE_H
+#define CL_NOISE_H
+
+struct cl_hw;
+struct cli_params;
+
+void cl_noise_init(struct cl_hw *cl_hw);
+void cl_noise_close(struct cl_hw *cl_hw);
+void cl_noise_maintenance(struct cl_hw *cl_hw);
+int cl_noise_cli(struct cl_hw *cl_hw, struct cli_params *cli_params);
+
+#endif /* CL_NOISE_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.
________________________________


^ permalink raw reply related	[flat|nested] 262+ messages in thread

* [RFC v1 121/256] cl8k: add omi.c
  2021-06-17 15:58 [RFC v1 000/256] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (119 preceding siblings ...)
  2021-06-17 16:00 ` [RFC v1 120/256] cl8k: add noise.h viktor.barna
@ 2021-06-17 16:00 ` viktor.barna
  2021-06-17 16:00 ` [RFC v1 122/256] cl8k: add omi.h viktor.barna
                   ` (136 subsequent siblings)
  257 siblings, 0 replies; 262+ messages in thread
From: viktor.barna @ 2021-06-17 16:00 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Oleksandr Savchenko, Shay Bar, Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

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

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 drivers/net/wireless/celeno/cl8k/omi.c | 214 +++++++++++++++++++++++++
 1 file changed, 214 insertions(+)
 create mode 100644 drivers/net/wireless/celeno/cl8k/omi.c

diff --git a/drivers/net/wireless/celeno/cl8k/omi.c b/drivers/net/wireless/celeno/cl8k/omi.c
new file mode 100644
index 000000000000..d25cbc12ac7a
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/omi.c
@@ -0,0 +1,214 @@
+// SPDX-License-Identifier: MIT
+/* Copyright(c) 2019-2021, Celeno Communications Ltd. */
+
+#include "omi.h"
+#include "mac80211.h"
+#include "sta.h"
+#include "mac_addr.h"
+#include "tx/tx.h"
+#include "wrs/wrs_api.h"
+#include "enhanced_tim.h"
+
+#define MAX_OMI_NSTS (WRS_SS_MAX - 1)
+
+static int cl_omi_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,
+                "omi usage:\n"
+                "-e : Enable/Disable OMI [0-dis, 1-en]\n"
+                "-s : Send OM control frame [sta_idx].[bw].[nss].[mu_ul_dis]."
+                       "[mu_ul_data_dis].[tx_nsts]\n");
+
+       err = cl_vendor_reply(cl_hw, buf, strlen(buf));
+       kfree(buf);
+
+       return err;
+}
+
+static bool cl_omi_validate_parms(u8 bw, u8 nss, u8 ul_mu_dis, u8 ul_mu_data_dis, u8 tx_nsts)
+{
+       return (bw < CHNL_BW_MAX && nss < WRS_SS_MAX && tx_nsts <= MAX_OMI_NSTS);
+}
+
+static int cl_omi_send(struct cl_hw *cl_hw, struct cl_sta *cl_sta, u8 bw, u8 nss, u8 ul_mu_dis,
+                      u8 ul_mu_data_dis, u8 tx_nsts)
+{
+       struct ieee80211_sub_if_data *sdata = NULL;
+       struct sk_buff *skb = NULL;
+       struct ieee80211_qos_htc_hdr *hdr = NULL;
+       struct cl_om_ctrl om_ctrl;
+       struct ieee80211_vif *vif = NULL;
+       int hdr_len = offsetof(struct ieee80211_qos_htc_hdr, a_ctrl) + sizeof(hdr->a_ctrl);
+
+       if (!cl_hw->conf->ce_omi_en || !cl_sta)
+               return -1;
+
+       vif = cl_sta->cl_vif->vif;
+       sdata = cl_sta->stainfo->sdata;
+
+       if (!cl_omi_validate_parms(bw, nss, ul_mu_dis, ul_mu_data_dis, tx_nsts) ||
+           vif->type != NL80211_IFTYPE_STATION)
+               return -1;
+
+       skb = dev_alloc_skb(cl_hw->hw->extra_tx_headroom + hdr_len);
+
+       if (!skb)
+               return -ENOMEM;
+
+       skb_reserve(skb, cl_hw->hw->extra_tx_headroom);
+
+       hdr = (struct ieee80211_qos_htc_hdr *)skb_put_zero(skb, hdr_len);
+       cl_mac_addr_copy(hdr->addr1, cl_sta->addr);
+       cl_mac_addr_copy(hdr->addr2, sdata->vif.addr);
+       cl_mac_addr_copy(hdr->addr3, sdata->u.mgd.bssid);
+
+       hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_ACTION |
+                                        IEEE80211_FCTL_ORDER);
+
+       om_ctrl.u.fields.chan_width = bw;
+       om_ctrl.u.fields.rx_nss = nss;
+       om_ctrl.u.fields.ul_mu_dis = ul_mu_dis;
+       om_ctrl.u.fields.ul_mu_data_dis = ul_mu_data_dis;
+       om_ctrl.u.fields.tx_nsts = tx_nsts;
+
+       /* Set A-control subfield */
+       hdr->a_ctrl.u.fields.b0 = 1;
+       hdr->a_ctrl.u.fields.b1 = 1;
+       hdr->a_ctrl.u.fields.control_id = IEEE80211_CTRL_A_CTRL_ID_OM;
+       hdr->a_ctrl.u.fields.control_info = om_ctrl.u.value;
+
+       if (!ieee80211_tx_prepare_skb(cl_hw->hw, vif, skb, cl_hw->nl_band, NULL))
+               return -1;
+
+       /* Send the OMI frame */
+       cl_tx_single(cl_hw, cl_sta, skb, false, true);
+       pr_debug("OM control frame was sent!\n");
+
+       return 0;
+}
+
+static void cl_omi_set_tb_mode(struct cl_hw *cl_hw, struct cl_sta *cl_sta,
+                              u8 ul_mu_dis, u8 ul_mu_data_dis)
+{
+       struct ieee80211_sta_he_cap *he_cap = &cl_hw->iftype_data[1].he_cap;
+       bool mu_dis_rx_sup = (he_cap->he_cap_elem.mac_cap_info[5] &
+                             IEEE80211_HE_MAC_CAP5_OM_CTRL_UL_MU_DATA_DIS_RX) ? true : false;
+       u8 ac;
+
+       /*
+        * According to Table 9-24a - UL MU Disable and UL MU Data Disable subfields encoding
+        * At this point we need to suspend/resume trigger base flow
+        */
+
+       for (ac = 0; ac < AC_MAX; ac++)
+               cl_sta->data_pending[ac] = 0;
+
+       if (!ul_mu_dis && !ul_mu_data_dis) {
+               pr_debug("All trigger based UL MU transmissions are enabled!\n");
+       } else if (!ul_mu_dis && ul_mu_data_dis && mu_dis_rx_sup) {
+               cl_enhanced_tim_clear_rx_sta(cl_hw, cl_sta->sta_idx);
+               pr_debug("Basic Trigger is suspended!\n");
+       } else if (ul_mu_dis && !ul_mu_data_dis) {
+               cl_enhanced_tim_clear_rx_sta(cl_hw, cl_sta->sta_idx);
+               pr_debug("All trigger based UL MU transmissions are suspended!\n");
+       }
+}
+
+void cl_omi_parse_om_ctrl_frm(struct cl_hw *cl_hw, struct cl_sta *cl_sta, struct sk_buff *skb)
+{
+       struct ieee80211_qos_htc_hdr *hdr = (struct ieee80211_qos_htc_hdr *)skb->data;
+       struct cl_wrs_rate *wrs_rate = &cl_sta->wrs_sta.max_rate_cap;
+       struct cl_om_ctrl om_ctrl;
+       u8 nss, bw, ul_mu_dis, ul_mu_data_dis, tx_nsts;
+
+       if (!cl_hw->conf->ce_omi_en)
+               return;
+
+       om_ctrl.u.value = hdr->a_ctrl.u.fields.control_info;
+       nss = om_ctrl.u.fields.rx_nss;
+       bw = om_ctrl.u.fields.chan_width;
+       ul_mu_dis = om_ctrl.u.fields.ul_mu_dis;
+       ul_mu_data_dis = om_ctrl.u.fields.ul_mu_data_dis;
+       tx_nsts = om_ctrl.u.fields.tx_nsts;
+
+       if (!cl_omi_validate_parms(bw, nss, ul_mu_dis, ul_mu_data_dis, tx_nsts))
+               return;
+
+       /* Set TB mode */
+       cl_omi_set_tb_mode(cl_hw, cl_sta, ul_mu_dis, ul_mu_data_dis);
+
+       if (nss != wrs_rate->nss)
+               cl_wrs_api_nss_changed(cl_hw, &cl_sta->stainfo->sta, nss);
+
+       if (bw != wrs_rate->bw)
+               cl_wrs_api_bw_changed(cl_hw, &cl_sta->stainfo->sta, bw);
+}
+
+int cl_omi_cli(struct cl_hw *cl_hw, struct cli_params *cli_params)
+{
+       u32 expected_params = 0;
+       bool send_om_ctrl = false;
+       bool enable = false;
+
+       switch (cli_params->option) {
+       case 'e':
+               enable = true;
+               expected_params = 1;
+               break;
+       case 's':
+               send_om_ctrl = true;
+               expected_params = 6;
+               break;
+       case '?':
+               return cl_omi_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 (enable) {
+               bool enable = (bool)cli_params->params[0];
+
+               if (enable != cl_hw->conf->ce_omi_en) {
+                       cl_hw->conf->ce_omi_en = enable;
+                       pr_debug("OMI %s\n", enable ? "Enabled" : "Disabled");
+               } else {
+                       pr_debug("OMI already %s\n", enable ? "Enabled" : "Disabled");
+               }
+       }
+
+       if (send_om_ctrl) {
+               u8 sta_idx = (u8)cli_params->params[0];
+               u8 bw = (u8)cli_params->params[1];
+               u8 nss = (u8)cli_params->params[2];
+               bool ul_mu_dis = (bool)cli_params->params[3];
+               bool ul_mu_data_dis = (bool)cli_params->params[4];
+               u8 tx_nsts = (u8)cli_params->params[5];
+               struct cl_sta *cl_sta;
+
+               cl_sta_lock_bh(cl_hw);
+               cl_sta = cl_sta_get(cl_hw, sta_idx);
+
+               if (cl_omi_send(cl_hw, cl_sta, bw, nss, ul_mu_dis, ul_mu_data_dis, tx_nsts))
+                       pr_warn("Failed to send OM control frame!\n");
+
+               cl_sta_unlock_bh(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.
________________________________


^ permalink raw reply related	[flat|nested] 262+ messages in thread

* [RFC v1 122/256] cl8k: add omi.h
  2021-06-17 15:58 [RFC v1 000/256] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (120 preceding siblings ...)
  2021-06-17 16:00 ` [RFC v1 121/256] cl8k: add omi.c viktor.barna
@ 2021-06-17 16:00 ` viktor.barna
  2021-06-17 16:00 ` [RFC v1 123/256] cl8k: add ops.c viktor.barna
                   ` (135 subsequent siblings)
  257 siblings, 0 replies; 262+ messages in thread
From: viktor.barna @ 2021-06-17 16:00 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Oleksandr Savchenko, Shay Bar, Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

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

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 drivers/net/wireless/celeno/cl8k/omi.h | 31 ++++++++++++++++++++++++++
 1 file changed, 31 insertions(+)
 create mode 100644 drivers/net/wireless/celeno/cl8k/omi.h

diff --git a/drivers/net/wireless/celeno/cl8k/omi.h b/drivers/net/wireless/celeno/cl8k/omi.h
new file mode 100644
index 000000000000..dfcb13f0f476
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/omi.h
@@ -0,0 +1,31 @@
+/* SPDX-License-Identifier: MIT */
+/* Copyright(c) 2019-2021, Celeno Communications Ltd. */
+
+#ifndef CL_OMI_H
+#define CL_OMI_H
+
+#include "hw.h"
+
+/**
+ * OMI (=Operating Mode Indication, 802.11ax)
+ */
+
+struct cl_om_ctrl {
+       union {
+               struct {
+                       u32 rx_nss : 3,
+                          chan_width : 2,
+                          ul_mu_dis : 1,
+                          tx_nsts : 3,
+                          er_su_dis : 1,
+                          dl_mu_mimo_resound : 1,
+                          ul_mu_data_dis : 1;
+               } __packed fields;
+               u32 value;
+       } u;
+} __packed;
+
+void cl_omi_parse_om_ctrl_frm(struct cl_hw *cl_hw, struct cl_sta *cl_sta, struct sk_buff *skb);
+int cl_omi_cli(struct cl_hw *cl_hw, struct cli_params *cli_params);
+
+#endif /* CL_OMI_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.
________________________________


^ permalink raw reply related	[flat|nested] 262+ messages in thread

* [RFC v1 123/256] cl8k: add ops.c
  2021-06-17 15:58 [RFC v1 000/256] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (121 preceding siblings ...)
  2021-06-17 16:00 ` [RFC v1 122/256] cl8k: add omi.h viktor.barna
@ 2021-06-17 16:00 ` viktor.barna
  2021-06-17 16:00 ` [RFC v1 124/256] cl8k: add ops.h viktor.barna
                   ` (134 subsequent siblings)
  257 siblings, 0 replies; 262+ messages in thread
From: viktor.barna @ 2021-06-17 16:00 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Oleksandr Savchenko, Shay Bar, Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

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

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 drivers/net/wireless/celeno/cl8k/ops.c | 889 +++++++++++++++++++++++++
 1 file changed, 889 insertions(+)
 create mode 100644 drivers/net/wireless/celeno/cl8k/ops.c

diff --git a/drivers/net/wireless/celeno/cl8k/ops.c b/drivers/net/wireless/celeno/cl8k/ops.c
new file mode 100644
index 000000000000..16934984b7cd
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/ops.c
@@ -0,0 +1,889 @@
+// SPDX-License-Identifier: MIT
+/* Copyright(c) 2019-2021, Celeno Communications Ltd. */
+
+#include <linux/log2.h>
+#include "ops.h"
+#include "utils/ip.h"
+#include "chip.h"
+#include "ampdu.h"
+#include "fw/msg_tx.h"
+#include "tx/tx.h"
+#include "tx/tx_queue.h"
+#include "radio.h"
+#include "recovery.h"
+#include "rate_ctrl.h"
+#include "temperature.h"
+#include "band.h"
+#include "rx/rx.h"
+#include "edca.h"
+#include "utils/math.h"
+#include "utils/utils.h"
+#include "ext/dyn_mcast_rate.h"
+#include "ext/dyn_bcast_rate.h"
+#include "vns.h"
+#include "dfs/dfs.h"
+#include "key.h"
+#include "temperature.h"
+#include "calib.h"
+#include "wrs/wrs_api.h"
+#include "chandef.h"
+#include "version.h"
+#include "power.h"
+#include "tx/tx_inject.h"
+#include "stats.h"
+#include "netlink.h"
+#include "calib.h"
+#ifdef CONFIG_CL_PCIE
+#include "bus/pci/ipc.h"
+#endif
+
+static const int cl_ac2hwq[AC_MAX] = {
+       [NL80211_TXQ_Q_VO] = CL_HWQ_VO,
+       [NL80211_TXQ_Q_VI] = CL_HWQ_VI,
+       [NL80211_TXQ_Q_BE] = CL_HWQ_BE,
+       [NL80211_TXQ_Q_BK] = CL_HWQ_BK
+};
+
+static const int cl_ac2edca[AC_MAX] = {
+       [NL80211_TXQ_Q_VO] = EDCA_AC_VO,
+       [NL80211_TXQ_Q_VI] = EDCA_AC_VI,
+       [NL80211_TXQ_Q_BE] = EDCA_AC_BE,
+       [NL80211_TXQ_Q_BK] = EDCA_AC_BK
+};
+
+static void cl_ops_tx_agg(struct cl_hw *cl_hw,
+                         struct sk_buff *skb,
+                         struct ieee80211_tx_info *tx_info,
+                         struct cl_sta *cl_sta)
+{
+       cl_hw->tx_packet_cntr.forward.from_mac_agg++;
+
+       if (!cl_sta) {
+               kfree_skb(skb);
+               cl_dbg_err(cl_hw, "cl_sta null in agg packet\n");
+               cl_hw->tx_packet_cntr.drop.sta_null_in_agg++;
+               return;
+       }
+
+       /* AMSDU in HW can work only with header conversion. */
+       tx_info->control.flags &= ~IEEE80211_TX_CTRL_AMSDU;
+       cl_tx_agg(cl_hw, cl_sta, skb, false, true);
+}
+
+static void cl_ops_tx_single(struct cl_hw *cl_hw,
+                            struct sk_buff *skb,
+                            struct ieee80211_tx_info *tx_info,
+                            struct cl_sta *cl_sta)
+{
+       bool is_vns = cl_vns_is_very_near(cl_hw, cl_sta, skb);
+
+       cl_hw->tx_packet_cntr.forward.from_mac_single++;
+
+       cl_tx_single(cl_hw, cl_sta, skb, is_vns, true);
+}
+
+void cl_ops_tx(struct ieee80211_hw *hw, struct ieee80211_tx_control *control, struct sk_buff *skb)
+{
+       /*
+        * Almost all traffic passing here is singles.
+        * Only when opening a BA session some packets with
+        * IEEE80211_TX_CTL_AMPDU set can pass here.
+        * All skbs passing here did header conversion.
+        */
+       struct cl_hw *cl_hw = (struct cl_hw *)hw->priv;
+       struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
+       struct ieee80211_sta *sta = control->sta;
+       struct cl_sta *cl_sta = NULL;
+
+       if (sta) {
+               cl_sta = IEEE80211_STA_TO_CL_STA(sta);
+
+               /*
+                * Prior to STA connection sta can be set but we don't
+                * want cl_sta to be used since it's not initialized yet
+                */
+               if (cl_sta->sta_idx == STA_IDX_INVALID)
+                       cl_sta = NULL;
+       }
+
+       if (cl_recovery_in_progress(cl_hw)) {
+               cl_hw->tx_packet_cntr.drop.in_recovery++;
+               cl_tx_drop_dkb(skb);
+               return;
+       }
+
+       if (tx_info->flags & IEEE80211_TX_CTL_AMPDU)
+               cl_ops_tx_agg(cl_hw, skb, tx_info, cl_sta);
+       else
+               cl_ops_tx_single(cl_hw, skb, tx_info, cl_sta);
+}
+
+int cl_ops_start(struct ieee80211_hw *hw)
+{
+       /*
+        * Called before the first netdevice attached to the hardware
+        * is enabled. This should turn on the hardware and must turn on
+        * frame reception (for possibly enabled monitor interfaces.)
+        * Returns negative error codes, these may be seen in userspace,
+        * or zero.
+        * When the device is started it should not have a MAC address
+        * to avoid acknowledging frames before a non-monitor device
+        * is added.
+        * Must be implemented and can sleep.
+        * It does not return until the firmware is up and running.
+        */
+       int error = 0;
+       struct cl_hw *cl_hw = hw->priv;
+       struct cl_tcv_conf *conf = cl_hw->conf;
+
+#ifdef CONFIG_CL_PCIE
+       if (!cl_hw->ipc_env) {
+               CL_DBG_ERROR(cl_hw, "ipc_env is NULL! 'no_dhcpcd' is missing in nvram folder\n");
+               return -1;
+       }
+#endif
+
+       /* Exits if device is already started */
+       if (WARN_ON(test_bit(CL_DEV_STARTED, &cl_hw->drv_flags)))
+               return -EBUSY;
+
+       /* Start firmware */
+       error = cl_msg_tx_start(cl_hw);
+       if (error)
+               return error;
+
+       /* Device is now started.
+        * Set CL_DEV_STARTED bit before the calls to other messages sent to
+        * firmware, to prevent them from being blocked*
+        */
+       set_bit(CL_DEV_STARTED, &cl_hw->drv_flags);
+
+       if (!cl_recovery_in_progress(cl_hw)) {
+               /* Read version */
+               error = cl_version_update(cl_hw);
+               if (error)
+                       return error;
+
+               error = cl_temperature_diff_e2p_read(cl_hw);
+               if (error)
+                       return error;
+       }
+
+       /* Set firmware debug module filter */
+       error = cl_msg_tx_dbg_set_ce_mod_filter(cl_hw, conf->ci_fw_dbg_module);
+       if (error)
+               return error;
+
+       /* Set firmware debug severity level */
+       error = cl_msg_tx_dbg_set_sev_filter(cl_hw, conf->ci_fw_dbg_severity);
+       if (error)
+               return error;
+
+       /* Set firmware rate fallbacks */
+       error = cl_msg_tx_set_rate_fallback(cl_hw);
+       if (error)
+               return error;
+
+       error = cl_msg_tx_ndp_tx_control(cl_hw,
+                                        conf->ci_ndp_tx_chain_mask,
+                                        conf->ci_ndp_tx_bw,
+                                        conf->ci_ndp_tx_format,
+                                        conf->ci_ndp_tx_num_ltf);
+       if (error)
+               return error;
+
+       /* Set default, multicast, broadcast rate */
+       cl_rate_ctrl_set_default(cl_hw);
+       cl_dyn_mcast_rate_set(cl_hw);
+       cl_dyn_bcast_rate_set(cl_hw, 0);
+
+       ieee80211_wake_queues(hw);
+
+       cl_calib_start(cl_hw);
+
+       clear_bit(CL_DEV_INIT, &cl_hw->drv_flags);
+
+       cl_edca_hw_conf(cl_hw);
+
+       return error;
+}
+
+void cl_ops_stop(struct ieee80211_hw *hw)
+{
+       /*
+        * Called after last netdevice attached to the hardware
+        * is disabled. This should turn off the hardware (at least
+        * it must turn off frame reception.)
+        * May be called right after add_interface if that rejects
+        * an interface. If you added any work onto the mac80211 workqueue
+        * you should ensure to cancel it on this callback.
+        * Must be implemented and can sleep.
+        */
+       struct cl_hw *cl_hw = hw->priv;
+
+       /* Go to idle */
+       cl_msg_tx_set_idle(cl_hw, MAC_IDLE_SYNC);
+
+       /*
+        * Clear CL_DEV_STARTED to prevent message to be sent (besides reset and start).
+        * It also blocks transmission of new packets
+        */
+       clear_bit(CL_DEV_STARTED, &cl_hw->drv_flags);
+
+       /* Stop mac80211 queues */
+       ieee80211_stop_queues(hw);
+
+       /* Send reset message to firmware */
+       cl_msg_tx_reset(cl_hw);
+
+#ifdef CONFIG_CL_PCIE
+       /* Reset IPC */
+       cl_ipc_reset(cl_hw);
+#endif
+
+       cl_hw->num_ap_started = 0;
+       cl_hw->radio_status = RADIO_STATUS_OFF;
+}
+
+static int add_interface_to_firmware(struct cl_hw *cl_hw, struct ieee80211_vif *vif, u8 vif_index)
+{
+       struct mm_add_if_cfm *add_if_cfm;
+       int ret = 0;
+
+       /* Forward the information to the firmware */
+       ret = cl_msg_tx_add_if(cl_hw, vif, vif_index);
+       if (ret)
+               return ret;
+
+       add_if_cfm = (struct mm_add_if_cfm *)(cl_hw->msg_cfm_params[MM_ADD_IF_CFM]);
+       if (!add_if_cfm)
+               return -ENOMSG;
+
+       if (add_if_cfm->status != 0) {
+               cl_dbg_verbose(cl_hw, "Status Error (%u)\n", add_if_cfm->status);
+               ret = -EIO;
+       }
+
+       cl_msg_tx_free_cfm_params(cl_hw, MM_ADD_IF_CFM);
+
+       return ret;
+}
+
+int cl_ops_add_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
+{
+       /*
+        * Called when a netdevice attached to the hardware is
+        * enabled. Because it is not called for monitor mode devices, start
+        * and stop must be implemented.
+        * The driver should perform any initialization it needs before
+        * the device can be enabled. The initial configuration for the
+        * interface is given in the conf parameter.
+        * The callback may refuse to add an interface by returning a
+        * negative error code (which will be seen in userspace.)
+        * Must be implemented and can sleep.
+        */
+       struct cl_hw *cl_hw = hw->priv;
+       struct cl_chip *chip = cl_hw->chip;
+       struct cl_vif *cl_vif = (struct cl_vif *)vif->drv_priv;
+       struct ieee80211_sub_if_data *sdata = container_of(vif, struct ieee80211_sub_if_data, vif);
+       struct net_device *dev = sdata->dev;
+       u8 ac;
+
+       if (!dev)
+               return -1;
+
+       /*
+        * In recovery just send the message to firmware and exit
+        * (also make sure cl_vif already exists).
+        */
+       if (cl_recovery_in_progress(cl_hw) && cl_vif_get_by_dev(cl_hw, dev))
+               return add_interface_to_firmware(cl_hw, vif, cl_vif->vif_index);
+
+       cl_vif->cl_hw = cl_hw;
+       cl_vif->vif = vif;
+       cl_vif->dev = dev;
+
+       if (chip->conf->ce_production_mode)
+               cl_vif->tx_en = true;
+
+       /* Copy dev ops and change ndo_start_xmit to point at cl_tx_start() */
+       cl_vif->orig_dev_ops = dev->netdev_ops;
+       memcpy(&cl_vif->dev_ops, dev->netdev_ops, sizeof(struct net_device_ops));
+       cl_vif->dev_ops.ndo_start_xmit = cl_tx_start;
+       dev->netdev_ops = &cl_vif->dev_ops;
+
+       if (chip->idx == CHIP0) {
+               if (cl_hw_is_tcv0(cl_hw))
+                       sscanf(dev->name, CL_IFACE_PREFIX "0_%hhu", &cl_vif->vif_index);
+               else
+                       sscanf(dev->name, CL_IFACE_PREFIX "1_%hhu", &cl_vif->vif_index);
+       } else {
+               if (cl_hw_is_tcv0(cl_hw))
+                       sscanf(dev->name, CL_IFACE_PREFIX "2_%hhu", &cl_vif->vif_index);
+               else
+                       sscanf(dev->name, CL_IFACE_PREFIX "3_%hhu", &cl_vif->vif_index);
+       }
+
+       if (add_interface_to_firmware(cl_hw, vif, cl_vif->vif_index))
+               return -1;
+
+       if (vif->type != NL80211_IFTYPE_STATION)
+               vif->cab_queue = CL_HWQ_VO;
+
+       cl_vif_add(cl_hw, cl_vif);
+
+       for (ac = 0; ac < AC_MAX; ac++)
+               vif->hw_queue[ac] = cl_ac2hwq[ac];
+
+       if (vif->type == NL80211_IFTYPE_MESH_POINT) {
+               tasklet_init(&cl_hw->tx_mesh_bcn_task, cl_tx_bcn_mesh_task,
+                            (unsigned long)cl_vif);
+               cl_radio_on(cl_hw);
+               cl_vif->tx_en = true;
+       }
+
+       /* Set active state in station mode after ifconfig down and up */
+       if (cl_radio_is_on(cl_hw) && vif->type == NL80211_IFTYPE_STATION)
+               cl_msg_tx_set_idle(cl_hw, MAC_ACTIVE);
+
+       return 0;
+}
+
+void cl_ops_remove_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
+{
+       /*
+        * Notifies a driver that an interface is going down.
+        * The stop callback is called after this if it is the last interface
+        * and no monitor interfaces are present.
+        * When all interfaces are removed, the MAC address in the hardware
+        * must be cleared so the device no longer acknowledges packets,
+        * the mac_addr member of the conf structure is, however, set to the
+        * MAC address of the device going away.
+        * Hence, this callback must be implemented. It can sleep.
+        */
+       struct cl_hw *cl_hw = hw->priv;
+       struct cl_vif *cl_vif = (struct cl_vif *)vif->drv_priv;
+
+       if (vif->type == NL80211_IFTYPE_MESH_POINT)
+               tasklet_kill(&cl_hw->tx_mesh_bcn_task);
+
+       if (!cl_recovery_in_progress(cl_hw)) {
+               cl_vif_remove(cl_hw, cl_vif);
+               cl_msg_tx_remove_if(cl_hw, cl_vif->vif_index);
+       } else {
+               cl_vif_remove(cl_hw, cl_vif);
+       }
+
+       /* Return netdev_ops back to it's original configuration */
+       cl_vif->dev->netdev_ops = cl_vif->orig_dev_ops;
+
+       cl_vif->cl_hw = NULL;
+       cl_vif->vif = NULL;
+       cl_vif->dev = NULL;
+}
+
+static int cl_ops_conf_change_channel(struct ieee80211_hw *hw)
+{
+       struct cl_hw *cl_hw = hw->priv;
+       struct cl_chip *chip = cl_hw->chip;
+       struct cfg80211_chan_def *chandef = &hw->conf.chandef;
+       enum nl80211_chan_width width = chandef->width;
+       u32 primary = chandef->chan->center_freq;
+       u32 center = chandef->center_freq1;
+       u8 channel = ieee80211_frequency_to_channel(primary);
+       u8 bw;
+
+       if (!test_bit(CL_DEV_STARTED, &cl_hw->drv_flags) ||
+           test_bit(CL_DEV_INIT, &cl_hw->drv_flags))
+               return -EBUSY;
+
+       /* WA: for the first set-channel in production mode use the nvram values */
+       if (chip->conf->ce_production_mode && !cl_hw->chandef_set) {
+               cl_hw->chandef_set = true;
+               cl_chandef_get_default(cl_hw, &width, &primary, &center);
+               channel = cl_hw->conf->ha_channel;
+       }
+
+       bw = width_to_bw(width);
+
+       if (cl_hw->channel == channel &&
+           cl_hw->bw == bw &&
+           cl_hw->primary_freq == primary &&
+           cl_hw->center_freq == center)
+               goto check_cac;
+
+       /*
+        * Flush the pending data to ensure that we will finish the pending
+        * transmissions before changing the channel
+        */
+       cl_ops_flush(hw, NULL, -1, false);
+
+       if (cl_band_is_6g(cl_hw))
+               cl_netlink_send_event_co_locate_update(cl_hw);
+
+       if (cl_msg_tx_set_channel(cl_hw, channel, bw, primary, center))
+               return -EIO;
+
+check_cac:
+       /*
+        * TODO: This callback is being spawned even in STA mode, moreover,
+        * "start_ap" comes later - it is unclear whether we are an AP at this
+        * stage. Likely, may be solved by moving "force_cac_*" states to beginning
+        * of "start_ap", but the request should stay in current callback
+        */
+       if (!cl_band_is_5g(cl_hw))
+               return 0;
+
+       /*
+        * Radar listening may occur at DFS channels during in-service mode,
+        * so CAC may clear the channels, but radar listening should be
+        * still active, and should start it as soon as we can.
+        */
+       if (hw->conf.radar_enabled) {
+               /* If channel policy demans to be in CAC - need to request it */
+               if (!cl_dfs_is_in_cac(cl_hw) &&
+                   chandef->chan->dfs_state == NL80211_DFS_USABLE)
+                       cl_dfs_request_cac(cl_hw, true);
+
+               if (!cl_dfs_radar_listening(cl_hw))
+                       cl_dfs_radar_listen_start(cl_hw);
+       } else {
+               /*
+                * No sense to continue be in silent mode if the channel was
+                * cleared
+                */
+               if (cl_dfs_is_in_cac(cl_hw) &&
+                   chandef->chan->dfs_state == NL80211_DFS_AVAILABLE)
+                       cl_dfs_request_cac(cl_hw, false);
+
+               if (cl_dfs_radar_listening(cl_hw))
+                       cl_dfs_radar_listen_end(cl_hw);
+       }
+
+       /*
+        * We have just finished channel switch.
+        * Now, check what to do with CAC.
+        */
+       if (cl_dfs_requested_cac(cl_hw))
+               cl_dfs_force_cac_start(cl_hw);
+       else if (cl_dfs_is_in_cac(cl_hw))
+               cl_dfs_force_cac_end(cl_hw);
+
+       return 0;
+}
+
+int cl_ops_config(struct ieee80211_hw *hw, u32 changed)
+{
+       /*
+        * Handler for configuration requests. IEEE 802.11 code calls this
+        * function to change hardware configuration, e.g., channel.
+        * This function should never fail but returns a negative error code
+        * if it does. The callback can sleep
+        */
+       int error = 0;
+
+       if (changed & IEEE80211_CONF_CHANGE_CHANNEL)
+               error = cl_ops_conf_change_channel(hw);
+
+       return error;
+}
+
+/*
+ * @bss_info_changed: Handler for configuration requests related to BSS
+ *  parameters that may vary during BSS's lifespan, and may affect low
+ *  level driver (e.g. assoc/disassoc status, erp parameters).
+ *  This function should not be used if no BSS has been set, unless
+ *  for association indication. The @changed parameter indicates which
+ *  of the bss parameters has changed when a call is made. The callback
+ *  can sleep.
+ */
+void cl_ops_bss_info_changed(struct ieee80211_hw *hw,
+                            struct ieee80211_vif *vif,
+                            struct ieee80211_bss_conf *info,
+                            u32 changed)
+{
+       struct cl_hw *cl_hw = hw->priv;
+       struct cl_vif *cl_vif = (struct cl_vif *)vif->drv_priv;
+
+       if (changed & BSS_CHANGED_ASSOC) {
+               if (cl_msg_tx_set_associated(cl_hw, info))
+                       return;
+       }
+
+       if (changed & BSS_CHANGED_BSSID) {
+               if (cl_msg_tx_set_bssid(cl_hw, info->bssid, cl_vif->vif_index))
+                       return;
+       }
+
+       if (changed & BSS_CHANGED_BEACON_INT) {
+               if (vif->type == NL80211_IFTYPE_AP ||
+                   cl_hw->iface_conf == CL_IFCONF_MESH_ONLY) {
+                       if (cl_msg_tx_set_beacon_int(cl_hw, info->beacon_int,
+                                                    cl_vif->vif_index))
+                               return;
+                       if (cl_msg_tx_dtim(cl_hw, info->dtim_period))
+                               return;
+               }
+
+               if (vif->type == NL80211_IFTYPE_MESH_POINT &&
+                   cl_hw->iface_conf == CL_IFCONF_MESH_AP)
+                       cl_hw->mesh_tbtt_div = (info->beacon_int /
+                                           cl_hw->conf->ha_beacon_int);
+       }
+
+       if (changed & BSS_CHANGED_BASIC_RATES) {
+               int shift = hw->wiphy->bands[hw->conf.chandef.chan->band]->bitrates[0].hw_value;
+
+               if (cl_msg_tx_set_basic_rates(cl_hw, info->basic_rates << shift))
+                       return;
+               /* TODO: check if cl_msg_tx_set_mode() should be called */
+       }
+
+       if (changed & BSS_CHANGED_ERP_SLOT) {
+               /*
+                * We must be in 11g mode here
+                * TODO: we can add a check on the mode
+                */
+               if (cl_msg_tx_set_slottime(cl_hw, info->use_short_slot))
+                       return;
+       }
+
+       if (changed & BSS_CHANGED_BANDWIDTH)
+               cl_wrs_api_bss_set_bw(cl_hw, width_to_bw(info->chandef.width));
+}
+
+int cl_ops_start_ap(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
+{
+       struct cl_hw *cl_hw = hw->priv;
+       u8 num_ap = cl_tcv_config_get_num_ap(cl_hw);
+
+       /*
+        * Increase num_ap_started counter and turn radio on only after
+        * all AP's were started.
+        */
+       cl_hw->num_ap_started++;
+
+       if (num_ap == cl_hw->num_ap_started &&
+           cl_hw->conf->ce_radio_on) {
+               cl_radio_on(cl_hw);
+
+               return 0;
+       }
+
+       /*
+        * Set active state when cl_ops_start_ap() is called not during first driver start
+        * but rather after removing all interfaces and then doing up again to one interface.
+        */
+       if (cl_radio_is_on(cl_hw) && !cl_recovery_in_progress(cl_hw))
+               cl_msg_tx_set_idle(cl_hw, MAC_ACTIVE);
+
+       return 0;
+}
+
+void cl_ops_stop_ap(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
+{
+       struct cl_hw *cl_hw = hw->priv;
+
+       cl_hw->num_ap_started--;
+}
+
+u64 cl_ops_prepare_multicast(struct ieee80211_hw *hw, struct netdev_hw_addr_list *mc_list)
+{
+       return netdev_hw_addr_list_count(mc_list);
+}
+
+void cl_ops_configure_filter(struct ieee80211_hw *hw, u32 changed_flags,
+                            u32 *total_flags, u64 multicast)
+{
+       /*
+        * configure_filter: Configure the device's RX filter.
+        * See the section "Frame filtering" for more information.
+        * This callback must be implemented and can sleep.
+        */
+       struct cl_hw *cl_hw = hw->priv;
+
+       cl_dbg_trace(cl_hw, "total_flags = 0x%08x\n", *total_flags);
+
+       /*
+        * Reset our filter flags since our start/stop ops reset
+        * the programmed settings
+        */
+       if (!test_bit(CL_DEV_STARTED, &cl_hw->drv_flags)) {
+               *total_flags = 0;
+               return;
+       }
+
+       if (multicast)
+               *total_flags |= FIF_ALLMULTI;
+       else
+               *total_flags &= ~FIF_ALLMULTI;
+
+       /* TODO optimize with changed_flags vs multicast */
+       cl_msg_tx_set_filter(cl_hw, *total_flags, false);
+
+       /* TODO update total_flags with truly set flags */
+       *total_flags &= ~(1 << 31);
+}
+
+int cl_ops_set_key(struct ieee80211_hw *hw,
+                  enum set_key_cmd cmd,
+                  struct ieee80211_vif *vif,
+                  struct ieee80211_sta *sta,
+                  struct ieee80211_key_conf *key)
+{
+       struct cl_hw *cl_hw = hw->priv;
+
+       return cl_key_set(cl_hw, cmd, vif, sta, key);
+}
+
+void cl_ops_sw_scan_start(struct ieee80211_hw *hw,
+                         struct ieee80211_vif *vif,
+                         const u8 *mac_addr)
+{
+       struct cl_hw *cl_hw = hw->priv;
+
+       if (cl_hw->conf->ce_radio_on &&
+           cl_radio_is_off(cl_hw) &&
+           vif->type == NL80211_IFTYPE_STATION)
+               cl_radio_on(cl_hw);
+}
+
+int cl_ops_sta_state(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_sta *sta,
+                    enum ieee80211_sta_state old_state, enum ieee80211_sta_state new_state)
+{
+       struct cl_hw *cl_hw = hw->priv;
+       int error = 0;
+
+       if (old_state == new_state)
+               return 0;
+
+       if (old_state == IEEE80211_STA_NOTEXIST &&
+           new_state == IEEE80211_STA_NONE) {
+               struct sta_info *stainfo = container_of(sta, struct sta_info, sta);
+
+               cl_sta_init_stainfo(cl_hw, stainfo);
+       } else if (old_state == IEEE80211_STA_AUTH &&
+                  new_state == IEEE80211_STA_ASSOC) {
+               error = cl_sta_add(cl_hw, vif, sta);
+       } else if (old_state == IEEE80211_STA_ASSOC &&
+                  new_state == IEEE80211_STA_AUTH) {
+               cl_sta_remove(cl_hw, vif, sta);
+       } else if (old_state == IEEE80211_STA_ASSOC &&
+                  new_state == IEEE80211_STA_AUTHORIZED) {
+               /* Do nothing, yet */
+       }
+
+       return error;
+}
+
+void cl_ops_sta_notify(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
+                      enum sta_notify_cmd cmd, struct ieee80211_sta *sta)
+{
+       struct cl_hw *cl_hw = (struct cl_hw *)hw->priv;
+       struct cl_sta *cl_sta = IEEE80211_STA_TO_CL_STA(sta);
+       bool is_ps = (bool)!cmd;
+
+       cl_sta_ps_notify(cl_hw, cl_sta, is_ps);
+}
+
+int cl_ops_conf_tx(struct ieee80211_hw *hw,
+                  struct ieee80211_vif *vif,
+                  u16 ac_queue,
+                  const struct ieee80211_tx_queue_params *params)
+{
+       /*
+        * Configure TX queue parameters (EDCF (aifs, cw_min, cw_max),
+        * bursting) for a hardware TX queue.
+        * Returns a negative error code on failure.
+        * The callback can sleep.
+        */
+
+       /* We only handle STA edca here */
+       if (vif->type == NL80211_IFTYPE_STATION) {
+               struct cl_hw *cl_hw = hw->priv;
+               struct ieee80211_he_mu_edca_param_ac_rec mu_edca = {0};
+               struct edca_params edca_params = {
+                       .aifsn = (u8)(params->aifs),
+                       .cw_min = (u8)(ilog2(params->cw_min + 1)),
+                       .cw_max = (u8)(ilog2(params->cw_max + 1)),
+                       .txop = (u8)(params->txop)
+               };
+
+               if (cl_hw->conf->ce_wireless_mode > WIRELESS_MODE_HT_VHT)
+                       memcpy(&mu_edca, &params->mu_edca_param_rec, sizeof(mu_edca));
+
+               cl_edca_set(cl_hw, cl_ac2edca[ac_queue], &edca_params, &mu_edca);
+       }
+       return 0;
+}
+
+void cl_ops_sta_rc_update(struct ieee80211_hw *hw,
+                         struct ieee80211_vif *vif,
+                         struct ieee80211_sta *sta,
+                         u32 changed)
+{
+       struct cl_hw *cl_hw = (struct cl_hw *)hw->priv;
+
+       if (changed & IEEE80211_RC_BW_CHANGED)
+               cl_wrs_api_bw_changed(cl_hw, sta, sta->bandwidth);
+
+       if (changed & IEEE80211_RC_SMPS_CHANGED) {
+               struct sta_info *stainfo = container_of(sta, struct sta_info, sta);
+
+               cl_wrs_api_set_smps_mode(cl_hw, sta, stainfo->cur_max_bandwidth);
+       }
+
+       WARN_ON(sta->rx_nss == 0);
+       if (changed & IEEE80211_RC_NSS_CHANGED) {
+               u8 nss = min_t(u8, sta->rx_nss, WRS_SS_MAX) - 1;
+
+               cl_wrs_api_nss_changed(cl_hw, sta, nss);
+       }
+}
+
+int cl_ops_ampdu_action(struct ieee80211_hw *hw,
+                       struct ieee80211_vif *vif,
+                       struct ieee80211_ampdu_params *params)
+{
+       struct cl_hw *cl_hw = (struct cl_hw *)hw->priv;
+       struct cl_sta *cl_sta = IEEE80211_STA_TO_CL_STA(params->sta);
+       int ret = 0;
+
+       switch (params->action) {
+       case IEEE80211_AMPDU_RX_START:
+               ret = cl_ampdu_rx_start(cl_hw, cl_sta, params->tid,
+                                       params->ssn, params->buf_size);
+               break;
+       case IEEE80211_AMPDU_RX_STOP:
+               cl_ampdu_rx_stop(cl_hw, cl_sta, params->tid);
+               break;
+       case IEEE80211_AMPDU_TX_START:
+               ret = cl_ampdu_tx_start(cl_hw, vif, cl_sta, params->tid,
+                                       params->ssn);
+               break;
+       case IEEE80211_AMPDU_TX_OPERATIONAL:
+               ret = cl_ampdu_tx_operational(cl_hw, cl_sta, params->tid,
+                                             params->buf_size, params->amsdu);
+               break;
+       case IEEE80211_AMPDU_TX_STOP_CONT:
+       case IEEE80211_AMPDU_TX_STOP_FLUSH:
+       case IEEE80211_AMPDU_TX_STOP_FLUSH_CONT:
+               ret = cl_ampdu_tx_stop(cl_hw, vif, params->action, cl_sta,
+                                      params->tid);
+               break;
+       default:
+               pr_warn("Error: Unknown AMPDU action (%d)\n", params->action);
+       }
+
+       return ret;
+}
+
+int cl_ops_post_channel_switch(struct ieee80211_hw *hw,
+                              struct ieee80211_vif *vif)
+{
+       /* TODO: Handle event */
+
+       return 0;
+}
+
+void cl_ops_flush(struct ieee80211_hw *hw, struct ieee80211_vif *vif, u32 queues, bool drop)
+{
+       struct cl_hw *cl_hw = hw->priv;
+       int flush_duration;
+
+       if (test_bit(CL_DEV_HW_RESTART, &cl_hw->drv_flags)) {
+               cl_dbg_verbose(cl_hw, ": bypassing (CL_DEV_HW_RESTART set)\n");
+               return;
+       }
+
+       /* Wait for a maximum time of 200ms until all pending frames are flushed */
+       for (flush_duration = 0; flush_duration < 200; flush_duration++) {
+               if (!cl_txq_frames_pending(cl_hw))
+                       return;
+
+               /* Lets sleep and hope for the best */
+               usleep_range(1000, 2000);
+       }
+}
+
+bool cl_ops_tx_frames_pending(struct ieee80211_hw *hw)
+{
+       struct cl_hw *cl_hw = hw->priv;
+
+       return cl_txq_frames_pending(cl_hw);
+}
+
+void cl_ops_reconfig_complete(struct ieee80211_hw *hw,
+                             enum ieee80211_reconfig_type reconfig_type)
+{
+       struct cl_hw *cl_hw = hw->priv;
+
+       cl_recovery_reconfig_complete(cl_hw);
+}
+
+int cl_ops_get_txpower(struct ieee80211_hw *hw, struct ieee80211_vif *vif, int *dbm)
+{
+       struct cl_hw *cl_hw = hw->priv;
+
+       if (cl_hw->phy_data_info.data)
+               *dbm = cl_power_get_max(cl_hw);
+       else
+               *dbm = 0;
+
+       return 0;
+}
+
+int cl_ops_set_rts_threshold(struct ieee80211_hw *hw, u32 value)
+{
+       return 0;
+}
+
+static void cl_ops_mgd_assoc(struct cl_hw *cl_hw, struct ieee80211_vif *vif)
+{
+       struct ieee80211_sub_if_data *sdata = container_of(vif, struct ieee80211_sub_if_data, vif);
+       struct cl_vif *cl_vif = (struct cl_vif *)vif->drv_priv;
+       struct ieee80211_sta *sta = ieee80211_find_sta(vif, sdata->u.mgd.bssid);
+
+       if (!sta) {
+               /* Should never happen */
+               cl_dbg_verbose(cl_hw, "sta is NULL !!!\n");
+               return;
+       }
+
+       cl_sta_mgd_add(cl_hw, cl_vif, sta);
+
+       if (cl_hw->iface_conf == CL_IFCONF_REPEATER) {
+               cl_vif_ap_tx_enable(cl_hw, true);
+               set_bit(CL_DEV_REPEATER, &cl_hw->drv_flags);
+       }
+}
+
+static void cl_ops_mgd_disassoc(struct cl_hw *cl_hw)
+{
+       if (cl_hw->iface_conf == CL_IFCONF_REPEATER) {
+               cl_sta_disassociate_ap_iface(cl_hw);
+               cl_vif_ap_tx_enable(cl_hw, false);
+               clear_bit(CL_DEV_REPEATER, &cl_hw->drv_flags);
+       }
+}
+
+void cl_ops_event_callback(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
+                          const struct ieee80211_event *event)
+{
+       struct cl_hw *cl_hw = hw->priv;
+
+       if (event->type == MLME_EVENT) {
+               if (event->u.mlme.data == ASSOC_EVENT &&
+                   event->u.mlme.status == MLME_SUCCESS)
+                       cl_ops_mgd_assoc(cl_hw, vif);
+               else if (event->u.mlme.data == DEAUTH_TX_EVENT ||
+                        event->u.mlme.data == DEAUTH_RX_EVENT)
+                       cl_ops_mgd_disassoc(cl_hw);
+       }
+}
+
+/* This function is required for PS flow - do not remove */
+int cl_ops_set_tim(struct ieee80211_hw *hw, struct ieee80211_sta *sta, bool set)
+{
+       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.
________________________________


^ permalink raw reply related	[flat|nested] 262+ messages in thread

* [RFC v1 124/256] cl8k: add ops.h
  2021-06-17 15:58 [RFC v1 000/256] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (122 preceding siblings ...)
  2021-06-17 16:00 ` [RFC v1 123/256] cl8k: add ops.c viktor.barna
@ 2021-06-17 16:00 ` viktor.barna
  2021-06-17 16:00 ` [RFC v1 125/256] cl8k: add phy/phy.c viktor.barna
                   ` (133 subsequent siblings)
  257 siblings, 0 replies; 262+ messages in thread
From: viktor.barna @ 2021-06-17 16:00 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Oleksandr Savchenko, Shay Bar, Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

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

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 drivers/net/wireless/celeno/cl8k/ops.h | 59 ++++++++++++++++++++++++++
 1 file changed, 59 insertions(+)
 create mode 100644 drivers/net/wireless/celeno/cl8k/ops.h

diff --git a/drivers/net/wireless/celeno/cl8k/ops.h b/drivers/net/wireless/celeno/cl8k/ops.h
new file mode 100644
index 000000000000..24532f9efacc
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/ops.h
@@ -0,0 +1,59 @@
+/* SPDX-License-Identifier: MIT */
+/* Copyright(c) 2019-2021, Celeno Communications Ltd. */
+
+#ifndef CL_OPS_H
+#define CL_OPS_H
+
+#include <net/mac80211.h>
+
+void cl_ops_tx(struct ieee80211_hw *hw, struct ieee80211_tx_control *control, struct sk_buff *skb);
+int cl_ops_start(struct ieee80211_hw *hw);
+void cl_ops_stop(struct ieee80211_hw *hw);
+int cl_ops_add_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif);
+void cl_ops_remove_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif);
+int cl_ops_config(struct ieee80211_hw *hw, u32 changed);
+void cl_ops_bss_info_changed(struct ieee80211_hw *hw,
+                            struct ieee80211_vif *vif,
+                            struct ieee80211_bss_conf *info,
+                            u32 changed);
+int cl_ops_start_ap(struct ieee80211_hw *hw, struct ieee80211_vif *vif);
+void cl_ops_stop_ap(struct ieee80211_hw *hw, struct ieee80211_vif *vif);
+u64 cl_ops_prepare_multicast(struct ieee80211_hw *hw, struct netdev_hw_addr_list *mc_list);
+void cl_ops_configure_filter(struct ieee80211_hw *hw, u32 changed_flags,
+                            u32 *total_flags, u64 multicast);
+int cl_ops_set_key(struct ieee80211_hw *hw,
+                  enum set_key_cmd cmd,
+                  struct ieee80211_vif *vif,
+                  struct ieee80211_sta *sta,
+                  struct ieee80211_key_conf *key);
+void cl_ops_sw_scan_start(struct ieee80211_hw *hw,
+                         struct ieee80211_vif *vif,
+                         const u8 *mac_addr);
+int cl_ops_sta_state(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_sta *sta,
+                    enum ieee80211_sta_state old_state, enum ieee80211_sta_state new_state);
+void cl_ops_sta_notify(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
+                      enum sta_notify_cmd cmd, struct ieee80211_sta *sta);
+int cl_ops_conf_tx(struct ieee80211_hw *hw,
+                  struct ieee80211_vif *vif,
+                  u16 ac_queue,
+                  const struct ieee80211_tx_queue_params *params);
+void cl_ops_sta_rc_update(struct ieee80211_hw *hw,
+                         struct ieee80211_vif *vif,
+                         struct ieee80211_sta *sta,
+                         u32 changed);
+int cl_ops_ampdu_action(struct ieee80211_hw *hw,
+                       struct ieee80211_vif *vif,
+                       struct ieee80211_ampdu_params *params);
+int cl_ops_post_channel_switch(struct ieee80211_hw *hw,
+                              struct ieee80211_vif *vif);
+void cl_ops_flush(struct ieee80211_hw *hw, struct ieee80211_vif *vif, u32 queues, bool drop);
+bool cl_ops_tx_frames_pending(struct ieee80211_hw *hw);
+void cl_ops_reconfig_complete(struct ieee80211_hw *hw,
+                             enum ieee80211_reconfig_type reconfig_type);
+int cl_ops_get_txpower(struct ieee80211_hw *hw, struct ieee80211_vif *vif, int *dbm);
+int cl_ops_set_rts_threshold(struct ieee80211_hw *hw, u32 value);
+void cl_ops_event_callback(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
+                          const struct ieee80211_event *event);
+int cl_ops_set_tim(struct ieee80211_hw *hw, struct ieee80211_sta *sta, bool set);
+
+#endif /* CL_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.
________________________________


^ permalink raw reply related	[flat|nested] 262+ messages in thread

* [RFC v1 125/256] cl8k: add phy/phy.c
  2021-06-17 15:58 [RFC v1 000/256] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (123 preceding siblings ...)
  2021-06-17 16:00 ` [RFC v1 124/256] cl8k: add ops.h viktor.barna
@ 2021-06-17 16:00 ` viktor.barna
  2021-06-17 16:00 ` [RFC v1 126/256] cl8k: add phy/phy.h viktor.barna
                   ` (132 subsequent siblings)
  257 siblings, 0 replies; 262+ messages in thread
From: viktor.barna @ 2021-06-17 16:00 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Oleksandr Savchenko, Shay Bar, Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

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

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 drivers/net/wireless/celeno/cl8k/phy/phy.c | 272 +++++++++++++++++++++
 1 file changed, 272 insertions(+)
 create mode 100644 drivers/net/wireless/celeno/cl8k/phy/phy.c

diff --git a/drivers/net/wireless/celeno/cl8k/phy/phy.c b/drivers/net/wireless/celeno/cl8k/phy/phy.c
new file mode 100644
index 000000000000..f58c7f83f600
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/phy/phy.c
@@ -0,0 +1,272 @@
+// SPDX-License-Identifier: MIT
+/* Copyright(c) 2019-2021, Celeno Communications Ltd. */
+
+#include "phy/phy.h"
+#include "reg/reg_modem_gcu.h"
+#include "reg/reg_cmu.h"
+#include "reg/reg_mac_hw.h"
+#include "reg/reg_mac_hw_mu.h"
+#include "reg/reg_macsys_gcu.h"
+#include "reg/reg_lcu_phy.h"
+#include "rf_boot.h"
+#include "dsp.h"
+
+static void ceva_disable(struct cl_hw *cl_hw)
+{
+       struct cl_chip *chip = cl_hw->chip;
+
+       if (cl_hw_is_tcv0(cl_hw)) {
+               cmu_phy_0_rst_ceva_0_global_rst_n_setf(chip, 0);
+               cmu_phy_0_clk_en_ceva_0_clk_en_setf(chip, 0);
+       } else {
+               cmu_phy_1_rst_ceva_1_global_rst_n_setf(chip, 0);
+               cmu_phy_1_clk_en_ceva_1_clk_en_setf(chip, 0);
+       }
+}
+
+static void ceva_reset(struct cl_hw *cl_hw)
+{
+       if (cl_hw_is_tcv0(cl_hw))
+               cmu_phy_0_rst_set(cl_hw->chip, CMU_PHY0_RST_EN);
+       else
+               cmu_phy_1_rst_set(cl_hw->chip, CMU_PHY1_RST_EN);
+}
+
+static void phy_disable(struct cl_hw *cl_hw)
+{
+       /* Modem GCU modules - Reset */
+
+       /* Disable clocks (reset is not asserted) */
+       modem_gcu_mpu_set(cl_hw, MODEM_GCU_MPU_RST_N_BIT | MODEM_GCU_MPU_REG_RST_N_BIT);
+       modem_gcu_bpu_set(cl_hw, MODEM_GCU_BPU_RST_N_BIT | MODEM_GCU_BPU_RX_RST_N_BIT |
+                         MODEM_GCU_BPU_TX_RST_N_BIT | MODEM_GCU_BPU_REG_RST_N_BIT);
+       modem_gcu_tfu_set(cl_hw, MODEM_GCU_TFU_RST_N_BIT | MODEM_GCU_TFU_REG_RST_N_BIT);
+       modem_gcu_smu_set(cl_hw, MODEM_GCU_SMU_RST_N_BIT | MODEM_GCU_SMU_REG_RST_N_BIT);
+       modem_gcu_spu_set(cl_hw, MODEM_GCU_SPU_RST_N_BIT | MODEM_GCU_SPU_REG_RST_N_BIT);
+       modem_gcu_bf_set(cl_hw, MODEM_GCU_BF_RST_N_BIT | MODEM_GCU_BF_REG_RST_N_BIT);
+       modem_gcu_epa_set(cl_hw, MODEM_GCU_EPA_RST_N_BIT | MODEM_GCU_EPA_REG_RST_N_BIT);
+       modem_gcu_lcu_set(cl_hw, MODEM_GCU_LCU_HLF_RST_N_BIT | MODEM_GCU_LCU_RST_N_BIT |
+                         MODEM_GCU_LCU_REG_RST_N_BIT);
+       modem_gcu_mux_fic_set(cl_hw, MODEM_GCU_MUX_FIC_SOFT_RST_N_BIT |
+                             MODEM_GCU_MUX_FIC_RST_N_BIT);
+       modem_gcu_riu_clk_set(cl_hw, 0);
+       modem_gcu_riu_clk_1_set(cl_hw, 0);
+
+       /* Assert reset (clocks already disabled) */
+       modem_gcu_mpu_set(cl_hw, 0);
+       modem_gcu_bpu_set(cl_hw, 0);
+       modem_gcu_tfu_set(cl_hw, 0);
+       modem_gcu_smu_set(cl_hw, 0);
+       modem_gcu_spu_set(cl_hw, 0);
+       modem_gcu_bf_set(cl_hw, 0);
+       modem_gcu_epa_set(cl_hw, 0);
+       modem_gcu_lcu_set(cl_hw, 0);
+       modem_gcu_mux_fic_set(cl_hw, MODEM_GCU_MUX_FIC_SOFT_RST_N_BIT);
+       modem_gcu_riu_rst_set(cl_hw, 0);
+}
+
+static void phy_reset(struct cl_hw *cl_hw)
+{
+       /* Isolate FIC bus in case CEVA reset is not required */
+       modem_gcu_mux_fic_config_fic_isolate_setf(cl_hw, 1);
+       while (modem_gcu_mux_fic_config_fic_isolated_getf(cl_hw) == 0)
+               ;
+       modem_gcu_mux_fic_config_fic_isolate_setf(cl_hw, 0);
+
+       /*
+        * Stop the LCU recording.
+        * Stop on one channel actually stops the recording on all channels.
+        * This stop is required because PHY LCU is going to be reset.
+        */
+       if (cl_hw_is_tcv0(cl_hw))
+               lcu_phy_lcu_ch_0_stop_set(cl_hw, 1);
+       else
+               lcu_phy_lcu_ch_1_stop_set(cl_hw, 1);
+
+       /* PHY reset sequence */
+       phy_disable(cl_hw);
+}
+
+static void phy0_off(struct cl_chip *chip)
+{
+       /* Disable APB0 clock but keep other clocks (main clock and DSP0 clock) active */
+       cmu_phy_0_clk_en_pack(chip, 1, 0, 1);
+       /* DSP0, MPIF0, APB0 reset */
+       cmu_phy_0_rst_set(chip, CMU_PHY_0_RST_N_BIT);
+       /* DSP0, MPIF0 are still in reset, but take APB0 out of reset to allow writing to GCU */
+       cmu_phy_0_rst_set(chip, CMU_PHY_0_RST_N_BIT | CMU_PHY_0_PRESET_N_BIT);
+       /* Enable APB0 clock (all other clocks are already active) */
+       cmu_phy_0_clk_en_phy_0_apb_clk_en_setf(chip, 1);
+}
+
+static void phy1_off(struct cl_chip *chip)
+{
+       /* Disable APB0 clock but keep other clocks (main clock and DSP0 clock) active */
+       cmu_phy_1_clk_en_pack(chip, 1, 0, 1);
+       /* DSP0, MPIF0, APB0 reset */
+       cmu_phy_1_rst_set(chip, CMU_PHY_0_RST_N_BIT);
+       /* DSP0, MPIF0 are still in reset, but take APB0 out of reset to allow writing to GCU */
+       cmu_phy_1_rst_set(chip, CMU_PHY_0_RST_N_BIT | CMU_PHY_0_PRESET_N_BIT);
+       /* Enable APB0 clock (all other clocks are already active) */
+       cmu_phy_1_clk_en_phy_1_apb_clk_en_setf(chip, 1);
+}
+
+static void phy_off(struct cl_hw *cl_hw)
+{
+       struct cl_chip *chip = cl_hw->chip;
+
+       if (cl_hw_is_tcv0(cl_hw))
+               phy0_off(chip);
+       else
+               phy1_off(chip);
+
+       phy_disable(cl_hw);
+}
+
+static void system_ctrl_reg_reset(struct cl_hw *cl_hw)
+{
+       struct cl_chip *chip = cl_hw->chip;
+       u32 regval = macsys_gcu_xt_control_get(chip);
+       u8 i;
+
+       /* Set XMAC_RUN_STALL */
+       regval |= cl_hw->controller_reg.run_stall;
+       /* Clear XMAC_OCD_HALT_ON_RESET and clear XMAC_BRESET */
+       regval &= ~(cl_hw->controller_reg.ocd_halt_on_reset | cl_hw->controller_reg.breset);
+
+       /* Reset MACHW */
+       macsys_gcu_xt_control_set(chip, regval);
+
+       for (i = 0; i < cl_hw->max_mu_cnt; i++)
+               mac_hw_mu_mac_cntrl_2_set(cl_hw, 1, i);
+}
+
+void cl_phy_off(struct cl_hw *cl_hw)
+{
+       system_ctrl_reg_reset(cl_hw);
+       phy_off(cl_hw);
+       ceva_disable(cl_hw);
+}
+
+static void save_ela_state(struct cl_hw *cl_hw)
+{
+       struct cl_recovery_db *recovery_db = &cl_hw->recovery_db;
+
+       /* Save eLA state before MAC-HW reset */
+       recovery_db->ela_en = mac_hw_debug_port_en_get(cl_hw);
+
+       if (recovery_db->ela_en) {
+               recovery_db->ela_sel_a = mac_hw_debug_port_sel_a_get(cl_hw);
+               recovery_db->ela_sel_b = mac_hw_debug_port_sel_b_get(cl_hw);
+               recovery_db->ela_sel_c = mac_hw_debug_port_sel_c_get(cl_hw);
+       }
+}
+
+void cl_phy_reset(struct cl_hw *cl_hw)
+{
+       save_ela_state(cl_hw);
+       system_ctrl_reg_reset(cl_hw);
+       phy_reset(cl_hw);
+       ceva_reset(cl_hw);
+}
+
+int cl_phy_load_recovery(struct cl_hw *cl_hw)
+{
+       int ret = cl_rf_boot_recovery(cl_hw);
+
+       if (ret) {
+               cl_dbg_err(cl_hw, "cl_rf_boot_recovery failed %d\n", ret);
+               return ret;
+       }
+
+       /* Load DSP */
+       ret = cl_dsp_load_recovery(cl_hw);
+       if (ret) {
+               cl_dbg_err(cl_hw, "cl_dsp_load_recovery failed %d\n", ret);
+               return ret;
+       }
+
+       /*
+        * FIXME: It looks like there is a bug in the DSP. If we poll REG_CFG_SPACE
+        * (0x600018) at this point to verify that DSP has been initialized
+        * successfully, we read '1' and continue.
+        * However, the calibration fails.
+        *
+        * Please note that this is a WORKAROUND, not a final fix.
+        * The problem should be investigated
+        * further by the DSP team.
+        */
+       msleep(500);
+       return 0;
+}
+
+int cl_phy_data_alloc(struct cl_hw *cl_hw)
+{
+       struct cl_phy_data *buf = NULL;
+       u32 len = (u32)PAGE_SIZE;
+       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->phy_data_info.data = buf;
+       cl_hw->phy_data_info.dma_addr = cpu_to_le32(phys_dma_addr);
+
+       return 0;
+}
+
+void cl_phy_data_free(struct cl_hw *cl_hw)
+{
+       dma_addr_t phys_dma_addr = le32_to_cpu(cl_hw->phy_data_info.dma_addr);
+
+       if (!cl_hw->phy_data_info.data)
+               return;
+
+       dma_free_coherent(cl_hw->chip->dev, PAGE_SIZE,
+                         (void *)cl_hw->phy_data_info.data, phys_dma_addr);
+       cl_hw->phy_data_info.data = NULL;
+}
+
+void cl_phy_enable(struct cl_hw *cl_hw)
+{
+       /* Modem GCU modules - De-assert Reset */
+
+       /* De-assert reset (clocks disabled) */
+       modem_gcu_mpu_set(cl_hw, MODEM_GCU_MPU_RST_N_BIT | MODEM_GCU_MPU_REG_RST_N_BIT);
+       modem_gcu_bpu_set(cl_hw, MODEM_GCU_BPU_RST_N_BIT | MODEM_GCU_BPU_RX_RST_N_BIT |
+                         MODEM_GCU_BPU_TX_RST_N_BIT | MODEM_GCU_BPU_REG_RST_N_BIT);
+       modem_gcu_tfu_set(cl_hw, MODEM_GCU_TFU_RST_N_BIT | MODEM_GCU_TFU_REG_RST_N_BIT);
+       modem_gcu_smu_set(cl_hw, MODEM_GCU_SMU_RST_N_BIT | MODEM_GCU_SMU_REG_RST_N_BIT);
+       modem_gcu_spu_set(cl_hw, MODEM_GCU_SPU_RST_N_BIT | MODEM_GCU_SPU_REG_RST_N_BIT);
+       modem_gcu_bf_set(cl_hw, MODEM_GCU_BF_RST_N_BIT | MODEM_GCU_BF_REG_RST_N_BIT);
+       modem_gcu_epa_set(cl_hw, MODEM_GCU_EPA_RST_N_BIT | MODEM_GCU_EPA_REG_RST_N_BIT);
+       modem_gcu_lcu_set(cl_hw, MODEM_GCU_LCU_HLF_RST_N_BIT | MODEM_GCU_LCU_RST_N_BIT |
+                         MODEM_GCU_LCU_REG_RST_N_BIT);
+       modem_gcu_mux_fic_set(cl_hw, MODEM_GCU_MUX_FIC_SOFT_RST_N_BIT |
+                             MODEM_GCU_MUX_FIC_RST_N_BIT);
+       modem_gcu_riu_rst_set(cl_hw, MODEM_GCU_RIU_FE_RST_N_BIT | MODEM_GCU_RIU_AGC_RST_N_BIT |
+                             MODEM_GCU_RIU_MDM_B_RST_N_BIT | MODEM_GCU_RIU_LB_RST_N_BIT |
+                             MODEM_GCU_RIU_RC_RST_N_BIT | MODEM_GCU_RIU_RADAR_RST_N_BIT |
+                             MODEM_GCU_RIU_RST_N_BIT | MODEM_GCU_RIU_REG_RST_N_BIT);
+
+       /* Enable clocks */
+       modem_gcu_mpu_set(cl_hw, 0xFFFFFFFF);
+       modem_gcu_bpu_set(cl_hw, 0xFFFFFFFF);
+       modem_gcu_tfu_set(cl_hw, 0xFFFFFFFF);
+       modem_gcu_smu_set(cl_hw, 0xFFFFFFFF);
+       modem_gcu_spu_set(cl_hw, 0xFFFFFFFF);
+       modem_gcu_bf_set(cl_hw, 0xFFFFFFFF);
+       modem_gcu_epa_set(cl_hw, 0xFFFFFFFF);
+       modem_gcu_lcu_set(cl_hw, 0xFFFFFFFF);
+       modem_gcu_mux_fic_set(cl_hw, 0xFFFFFFFF);
+       modem_gcu_riu_clk_set(cl_hw, 0xFFFFFFFF);
+       modem_gcu_riu_clk_1_set(cl_hw, 0xFFFFFFFF);
+
+       /*
+        * Configure minimum latency between 2 masters connected
+        * to same FIC, Read/Write transaction
+        */
+       modem_gcu_mux_fic_config_set(cl_hw, 0x00000808);
+}
--
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.
________________________________


^ permalink raw reply related	[flat|nested] 262+ messages in thread

* [RFC v1 126/256] cl8k: add phy/phy.h
  2021-06-17 15:58 [RFC v1 000/256] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (124 preceding siblings ...)
  2021-06-17 16:00 ` [RFC v1 125/256] cl8k: add phy/phy.c viktor.barna
@ 2021-06-17 16:00 ` viktor.barna
  2021-06-17 16:00 ` [RFC v1 127/256] cl8k: add phy/phy_athos_lut.c viktor.barna
                   ` (131 subsequent siblings)
  257 siblings, 0 replies; 262+ messages in thread
From: viktor.barna @ 2021-06-17 16:00 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Oleksandr Savchenko, Shay Bar, Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

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

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 drivers/net/wireless/celeno/cl8k/phy/phy.h | 17 +++++++++++++++++
 1 file changed, 17 insertions(+)
 create mode 100644 drivers/net/wireless/celeno/cl8k/phy/phy.h

diff --git a/drivers/net/wireless/celeno/cl8k/phy/phy.h b/drivers/net/wireless/celeno/cl8k/phy/phy.h
new file mode 100644
index 000000000000..6a58faf2cfd8
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/phy/phy.h
@@ -0,0 +1,17 @@
+/* SPDX-License-Identifier: MIT */
+/* Copyright(c) 2019-2021, Celeno Communications Ltd. */
+
+#ifndef CL_PHY_H
+#define CL_PHY_H
+
+#include "hw.h"
+#include "chip.h"
+
+void cl_phy_reset(struct cl_hw *cl_hw);
+void cl_phy_off(struct cl_hw *cl_hw);
+int cl_phy_load_recovery(struct cl_hw *cl_hw);
+int cl_phy_data_alloc(struct cl_hw *cl_hw);
+void cl_phy_data_free(struct cl_hw *cl_hw);
+void cl_phy_enable(struct cl_hw *cl_hw);
+
+#endif /* CL_PHY_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.
________________________________


^ permalink raw reply related	[flat|nested] 262+ messages in thread

* [RFC v1 127/256] cl8k: add phy/phy_athos_lut.c
  2021-06-17 15:58 [RFC v1 000/256] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (125 preceding siblings ...)
  2021-06-17 16:00 ` [RFC v1 126/256] cl8k: add phy/phy.h viktor.barna
@ 2021-06-17 16:00 ` viktor.barna
  2021-06-17 16:00 ` [RFC v1 128/256] cl8k: add phy/phy_athos_lut.h viktor.barna
                   ` (130 subsequent siblings)
  257 siblings, 0 replies; 262+ messages in thread
From: viktor.barna @ 2021-06-17 16:00 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Oleksandr Savchenko, Shay Bar, Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

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

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 .../wireless/celeno/cl8k/phy/phy_athos_lut.c  | 2069 +++++++++++++++++
 1 file changed, 2069 insertions(+)
 create mode 100644 drivers/net/wireless/celeno/cl8k/phy/phy_athos_lut.c

diff --git a/drivers/net/wireless/celeno/cl8k/phy/phy_athos_lut.c b/drivers/net/wireless/celeno/cl8k/phy/phy_athos_lut.c
new file mode 100644
index 000000000000..5a42e55116c0
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/phy/phy_athos_lut.c
@@ -0,0 +1,2069 @@
+// SPDX-License-Identifier: MIT
+/* Copyright(c) 2019-2021, Celeno Communications Ltd. */
+
+#include "phy_athos_lut.h"
+
+const struct athos_lut_line athos_lut_6g_40_mhz[ATHOS_LUT_CHAN_6G_MAX] = {
+       [ATHOS_LUT_CHAN_593000_IDX] = { 23720, 0x0, 0x62, 0x1AAAAB, 0x7B9 },
+       [ATHOS_LUT_CHAN_593125_IDX] = { 23725, 0x0, 0x62, 0x1B5555, 0x7B9 },
+       [ATHOS_LUT_CHAN_593250_IDX] = { 23730, 0x0, 0x62, 0x1C0000, 0x7BA },
+       [ATHOS_LUT_CHAN_593375_IDX] = { 23735, 0x0, 0x62, 0x1CAAAB, 0x7BA },
+       [ATHOS_LUT_CHAN_593500_IDX] = { 23740, 0x0, 0x62, 0x1D5555, 0x7BA },
+       [ATHOS_LUT_CHAN_593625_IDX] = { 23745, 0x0, 0x62, 0x1E0000, 0x7BB },
+       [ATHOS_LUT_CHAN_593750_IDX] = { 23750, 0x0, 0x62, 0x1EAAAB, 0x7BB },
+       [ATHOS_LUT_CHAN_593875_IDX] = { 23755, 0x0, 0x62, 0x1F5555, 0x7BC },
+       [ATHOS_LUT_CHAN_594000_IDX] = { 23760, 0x0, 0x63, 0x0, 0x7BC },
+       [ATHOS_LUT_CHAN_594125_IDX] = { 23765, 0x0, 0x63, 0xAAAB, 0x7BC },
+       [ATHOS_LUT_CHAN_594250_IDX] = { 23770, 0x0, 0x63, 0x15555, 0x7BD },
+       [ATHOS_LUT_CHAN_594375_IDX] = { 23775, 0x0, 0x63, 0x20000, 0x7BD },
+       [ATHOS_LUT_CHAN_594500_IDX] = { 23780, 0x0, 0x63, 0x2AAAB, 0x7BE },
+       [ATHOS_LUT_CHAN_594625_IDX] = { 23785, 0x0, 0x63, 0x35555, 0x7BE },
+       [ATHOS_LUT_CHAN_594750_IDX] = { 23790, 0x0, 0x63, 0x40000, 0x7BF },
+       [ATHOS_LUT_CHAN_594875_IDX] = { 23795, 0x0, 0x63, 0x4AAAB, 0x7BF },
+       [ATHOS_LUT_CHAN_595000_IDX] = { 23800, 0x0, 0x63, 0x55555, 0x7BF },
+       [ATHOS_LUT_CHAN_595125_IDX] = { 23805, 0x0, 0x63, 0x60000, 0x7C0 },
+       [ATHOS_LUT_CHAN_595250_IDX] = { 23810, 0x0, 0x63, 0x6AAAB, 0x7C0 },
+       [ATHOS_LUT_CHAN_595375_IDX] = { 23815, 0x0, 0x63, 0x75555, 0x7C1 },
+       [ATHOS_LUT_CHAN_595500_IDX] = { 23820, 0x0, 0x63, 0x80000, 0x7C1 },
+       [ATHOS_LUT_CHAN_595625_IDX] = { 23825, 0x0, 0x63, 0x8AAAB, 0x7C1 },
+       [ATHOS_LUT_CHAN_595750_IDX] = { 23830, 0x0, 0x63, 0x95555, 0x7C2 },
+       [ATHOS_LUT_CHAN_595875_IDX] = { 23835, 0x0, 0x63, 0xA0000, 0x7C2 },
+       [ATHOS_LUT_CHAN_596000_IDX] = { 23840, 0x0, 0x63, 0xAAAAB, 0x7C3 },
+       [ATHOS_LUT_CHAN_596125_IDX] = { 23845, 0x0, 0x63, 0xB5555, 0x7C3 },
+       [ATHOS_LUT_CHAN_596250_IDX] = { 23850, 0x0, 0x63, 0xC0000, 0x7C4 },
+       [ATHOS_LUT_CHAN_596375_IDX] = { 23855, 0x0, 0x63, 0xCAAAB, 0x7C4 },
+       [ATHOS_LUT_CHAN_596500_IDX] = { 23860, 0x0, 0x63, 0xD5555, 0x7C4 },
+       [ATHOS_LUT_CHAN_596625_IDX] = { 23865, 0x0, 0x63, 0xE0000, 0x7C5 },
+       [ATHOS_LUT_CHAN_596750_IDX] = { 23870, 0x0, 0x63, 0xEAAAB, 0x7C5 },
+       [ATHOS_LUT_CHAN_596875_IDX] = { 23875, 0x0, 0x63, 0xF5555, 0x7C6 },
+       [ATHOS_LUT_CHAN_597000_IDX] = { 23880, 0x0, 0x63, 0x100000, 0x7C6 },
+       [ATHOS_LUT_CHAN_597125_IDX] = { 23885, 0x0, 0x63, 0x10AAAB, 0x7C6 },
+       [ATHOS_LUT_CHAN_597250_IDX] = { 23890, 0x0, 0x63, 0x115555, 0x7C7 },
+       [ATHOS_LUT_CHAN_597375_IDX] = { 23895, 0x0, 0x63, 0x120000, 0x7C7 },
+       [ATHOS_LUT_CHAN_597500_IDX] = { 23900, 0x0, 0x63, 0x12AAAB, 0x7C8 },
+       [ATHOS_LUT_CHAN_597625_IDX] = { 23905, 0x0, 0x63, 0x135555, 0x7C8 },
+       [ATHOS_LUT_CHAN_597750_IDX] = { 23910, 0x0, 0x63, 0x140000, 0x7C9 },
+       [ATHOS_LUT_CHAN_597875_IDX] = { 23915, 0x0, 0x63, 0x14AAAB, 0x7C9 },
+       [ATHOS_LUT_CHAN_598000_IDX] = { 23920, 0x0, 0x63, 0x155555, 0x7C9 },
+       [ATHOS_LUT_CHAN_598125_IDX] = { 23925, 0x0, 0x63, 0x160000, 0x7CA },
+       [ATHOS_LUT_CHAN_598250_IDX] = { 23930, 0x0, 0x63, 0x16AAAB, 0x7CA },
+       [ATHOS_LUT_CHAN_598375_IDX] = { 23935, 0x0, 0x63, 0x175555, 0x7CB },
+       [ATHOS_LUT_CHAN_598500_IDX] = { 23940, 0x0, 0x63, 0x180000, 0x7CB },
+       [ATHOS_LUT_CHAN_598625_IDX] = { 23945, 0x0, 0x63, 0x18AAAB, 0x7CB },
+       [ATHOS_LUT_CHAN_598750_IDX] = { 23950, 0x0, 0x63, 0x195555, 0x7CC },
+       [ATHOS_LUT_CHAN_598875_IDX] = { 23955, 0x0, 0x63, 0x1A0000, 0x7CC },
+       [ATHOS_LUT_CHAN_599000_IDX] = { 23960, 0x0, 0x63, 0x1AAAAB, 0x7CD },
+       [ATHOS_LUT_CHAN_599125_IDX] = { 23965, 0x0, 0x63, 0x1B5555, 0x7CD },
+       [ATHOS_LUT_CHAN_599250_IDX] = { 23970, 0x0, 0x63, 0x1C0000, 0x7CE },
+       [ATHOS_LUT_CHAN_599375_IDX] = { 23975, 0x0, 0x63, 0x1CAAAB, 0x7CE },
+       [ATHOS_LUT_CHAN_599500_IDX] = { 23980, 0x0, 0x63, 0x1D5555, 0x7CE },
+       [ATHOS_LUT_CHAN_599625_IDX] = { 23985, 0x0, 0x63, 0x1E0000, 0x7CF },
+       [ATHOS_LUT_CHAN_599750_IDX] = { 23990, 0x0, 0x63, 0x1EAAAB, 0x7CF },
+       [ATHOS_LUT_CHAN_599875_IDX] = { 23995, 0x0, 0x63, 0x1F5555, 0x7D0 },
+       [ATHOS_LUT_CHAN_600000_IDX] = { 24000, 0x0, 0x64, 0x0, 0x7D0 },
+       [ATHOS_LUT_CHAN_600125_IDX] = { 24005, 0x0, 0x64, 0xAAAB, 0x7D0 },
+       [ATHOS_LUT_CHAN_600250_IDX] = { 24010, 0x0, 0x64, 0x15555, 0x7D1 },
+       [ATHOS_LUT_CHAN_600375_IDX] = { 24015, 0x0, 0x64, 0x20000, 0x7D1 },
+       [ATHOS_LUT_CHAN_600500_IDX] = { 24020, 0x0, 0x64, 0x2AAAB, 0x7D2 },
+       [ATHOS_LUT_CHAN_600625_IDX] = { 24025, 0x0, 0x64, 0x35555, 0x7D2 },
+       [ATHOS_LUT_CHAN_600750_IDX] = { 24030, 0x0, 0x64, 0x40000, 0x7D3 },
+       [ATHOS_LUT_CHAN_600875_IDX] = { 24035, 0x0, 0x64, 0x4AAAB, 0x7D3 },
+       [ATHOS_LUT_CHAN_601000_IDX] = { 24040, 0x0, 0x64, 0x55555, 0x7D3 },
+       [ATHOS_LUT_CHAN_601125_IDX] = { 24045, 0x0, 0x64, 0x60000, 0x7D4 },
+       [ATHOS_LUT_CHAN_601250_IDX] = { 24050, 0x0, 0x64, 0x6AAAB, 0x7D4 },
+       [ATHOS_LUT_CHAN_601375_IDX] = { 24055, 0x0, 0x64, 0x75555, 0x7D5 },
+       [ATHOS_LUT_CHAN_601500_IDX] = { 24060, 0x0, 0x64, 0x80000, 0x7D5 },
+       [ATHOS_LUT_CHAN_601625_IDX] = { 24065, 0x0, 0x64, 0x8AAAB, 0x7D5 },
+       [ATHOS_LUT_CHAN_601750_IDX] = { 24070, 0x0, 0x64, 0x95555, 0x7D6 },
+       [ATHOS_LUT_CHAN_601875_IDX] = { 24075, 0x0, 0x64, 0xA0000, 0x7D6 },
+       [ATHOS_LUT_CHAN_602000_IDX] = { 24080, 0x0, 0x64, 0xAAAAB, 0x7D7 },
+       [ATHOS_LUT_CHAN_602125_IDX] = { 24085, 0x0, 0x64, 0xB5555, 0x7D7 },
+       [ATHOS_LUT_CHAN_602250_IDX] = { 24090, 0x0, 0x64, 0xC0000, 0x7D8 },
+       [ATHOS_LUT_CHAN_602375_IDX] = { 24095, 0x0, 0x64, 0xCAAAB, 0x7D8 },
+       [ATHOS_LUT_CHAN_602500_IDX] = { 24100, 0x0, 0x64, 0xD5555, 0x7D8 },
+       [ATHOS_LUT_CHAN_602625_IDX] = { 24105, 0x0, 0x64, 0xE0000, 0x7D9 },
+       [ATHOS_LUT_CHAN_602750_IDX] = { 24110, 0x0, 0x64, 0xEAAAB, 0x7D9 },
+       [ATHOS_LUT_CHAN_602875_IDX] = { 24115, 0x0, 0x64, 0xF5555, 0x7DA },
+       [ATHOS_LUT_CHAN_603000_IDX] = { 24120, 0x0, 0x64, 0x100000, 0x7DA },
+       [ATHOS_LUT_CHAN_603125_IDX] = { 24125, 0x0, 0x64, 0x10AAAB, 0x7DA },
+       [ATHOS_LUT_CHAN_603250_IDX] = { 24130, 0x0, 0x64, 0x115555, 0x7DB },
+       [ATHOS_LUT_CHAN_603375_IDX] = { 24135, 0x0, 0x64, 0x120000, 0x7DB },
+       [ATHOS_LUT_CHAN_603500_IDX] = { 24140, 0x0, 0x64, 0x12AAAB, 0x7DC },
+       [ATHOS_LUT_CHAN_603625_IDX] = { 24145, 0x0, 0x64, 0x135555, 0x7DC },
+       [ATHOS_LUT_CHAN_603750_IDX] = { 24150, 0x0, 0x64, 0x140000, 0x7DD },
+       [ATHOS_LUT_CHAN_603875_IDX] = { 24155, 0x0, 0x64, 0x14AAAB, 0x7DD },
+       [ATHOS_LUT_CHAN_604000_IDX] = { 24160, 0x0, 0x64, 0x155555, 0x7DD },
+       [ATHOS_LUT_CHAN_604125_IDX] = { 24165, 0x0, 0x64, 0x160000, 0x7DE },
+       [ATHOS_LUT_CHAN_604250_IDX] = { 24170, 0x0, 0x64, 0x16AAAB, 0x7DE },
+       [ATHOS_LUT_CHAN_604375_IDX] = { 24175, 0x0, 0x64, 0x175555, 0x7DF },
+       [ATHOS_LUT_CHAN_604500_IDX] = { 24180, 0x0, 0x64, 0x180000, 0x7DF },
+       [ATHOS_LUT_CHAN_604625_IDX] = { 24185, 0x0, 0x64, 0x18AAAB, 0x7DF },
+       [ATHOS_LUT_CHAN_604750_IDX] = { 24190, 0x0, 0x64, 0x195555, 0x7E0 },
+       [ATHOS_LUT_CHAN_604875_IDX] = { 24195, 0x0, 0x64, 0x1A0000, 0x7E0 },
+       [ATHOS_LUT_CHAN_605000_IDX] = { 24200, 0x0, 0x64, 0x1AAAAB, 0x7E1 },
+       [ATHOS_LUT_CHAN_605125_IDX] = { 24205, 0x0, 0x64, 0x1B5555, 0x7E1 },
+       [ATHOS_LUT_CHAN_605250_IDX] = { 24210, 0x0, 0x64, 0x1C0000, 0x7E2 },
+       [ATHOS_LUT_CHAN_605375_IDX] = { 24215, 0x0, 0x64, 0x1CAAAB, 0x7E2 },
+       [ATHOS_LUT_CHAN_605500_IDX] = { 24220, 0x0, 0x64, 0x1D5555, 0x7E2 },
+       [ATHOS_LUT_CHAN_605625_IDX] = { 24225, 0x0, 0x64, 0x1E0000, 0x7E3 },
+       [ATHOS_LUT_CHAN_605750_IDX] = { 24230, 0x0, 0x64, 0x1EAAAB, 0x7E3 },
+       [ATHOS_LUT_CHAN_605875_IDX] = { 24235, 0x0, 0x64, 0x1F5555, 0x7E4 },
+       [ATHOS_LUT_CHAN_606000_IDX] = { 24240, 0x0, 0x65, 0x0, 0x7E4 },
+       [ATHOS_LUT_CHAN_606125_IDX] = { 24245, 0x0, 0x65, 0xAAAB, 0x7E4 },
+       [ATHOS_LUT_CHAN_606250_IDX] = { 24250, 0x0, 0x65, 0x15555, 0x7E5 },
+       [ATHOS_LUT_CHAN_606375_IDX] = { 24255, 0x0, 0x65, 0x20000, 0x7E5 },
+       [ATHOS_LUT_CHAN_606500_IDX] = { 24260, 0x0, 0x65, 0x2AAAB, 0x7E6 },
+       [ATHOS_LUT_CHAN_606625_IDX] = { 24265, 0x0, 0x65, 0x35555, 0x7E6 },
+       [ATHOS_LUT_CHAN_606750_IDX] = { 24270, 0x0, 0x65, 0x40000, 0x7E7 },
+       [ATHOS_LUT_CHAN_606875_IDX] = { 24275, 0x0, 0x65, 0x4AAAB, 0x7E7 },
+       [ATHOS_LUT_CHAN_607000_IDX] = { 24280, 0x0, 0x65, 0x55555, 0x7E7 },
+       [ATHOS_LUT_CHAN_607125_IDX] = { 24285, 0x0, 0x65, 0x60000, 0x7E8 },
+       [ATHOS_LUT_CHAN_607250_IDX] = { 24290, 0x0, 0x65, 0x6AAAB, 0x7E8 },
+       [ATHOS_LUT_CHAN_607375_IDX] = { 24295, 0x0, 0x65, 0x75555, 0x7E9 },
+       [ATHOS_LUT_CHAN_607500_IDX] = { 24300, 0x0, 0x65, 0x80000, 0x7E9 },
+       [ATHOS_LUT_CHAN_607625_IDX] = { 24305, 0x0, 0x65, 0x8AAAB, 0x7E9 },
+       [ATHOS_LUT_CHAN_607750_IDX] = { 24310, 0x0, 0x65, 0x95555, 0x7EA },
+       [ATHOS_LUT_CHAN_607875_IDX] = { 24315, 0x0, 0x65, 0xA0000, 0x7EA },
+       [ATHOS_LUT_CHAN_608000_IDX] = { 24320, 0x0, 0x65, 0xAAAAB, 0x7EB },
+       [ATHOS_LUT_CHAN_608125_IDX] = { 24325, 0x0, 0x65, 0xB5555, 0x7EB },
+       [ATHOS_LUT_CHAN_608250_IDX] = { 24330, 0x0, 0x65, 0xC0000, 0x7EC },
+       [ATHOS_LUT_CHAN_608375_IDX] = { 24335, 0x0, 0x65, 0xCAAAB, 0x7EC },
+       [ATHOS_LUT_CHAN_608500_IDX] = { 24340, 0x0, 0x65, 0xD5555, 0x7EC },
+       [ATHOS_LUT_CHAN_608625_IDX] = { 24345, 0x0, 0x65, 0xE0000, 0x7ED },
+       [ATHOS_LUT_CHAN_608750_IDX] = { 24350, 0x0, 0x65, 0xEAAAB, 0x7ED },
+       [ATHOS_LUT_CHAN_608875_IDX] = { 24355, 0x0, 0x65, 0xF5555, 0x7EE },
+       [ATHOS_LUT_CHAN_609000_IDX] = { 24360, 0x0, 0x65, 0x100000, 0x7EE },
+       [ATHOS_LUT_CHAN_609125_IDX] = { 24365, 0x0, 0x65, 0x10AAAB, 0x7EE },
+       [ATHOS_LUT_CHAN_609250_IDX] = { 24370, 0x0, 0x65, 0x115555, 0x7EF },
+       [ATHOS_LUT_CHAN_609375_IDX] = { 24375, 0x0, 0x65, 0x120000, 0x7EF },
+       [ATHOS_LUT_CHAN_609500_IDX] = { 24380, 0x0, 0x65, 0x12AAAB, 0x7F0 },
+       [ATHOS_LUT_CHAN_609625_IDX] = { 24385, 0x0, 0x65, 0x135555, 0x7F0 },
+       [ATHOS_LUT_CHAN_609750_IDX] = { 24390, 0x0, 0x65, 0x140000, 0x7F1 },
+       [ATHOS_LUT_CHAN_609875_IDX] = { 24395, 0x0, 0x65, 0x14AAAB, 0x7F1 },
+       [ATHOS_LUT_CHAN_610000_IDX] = { 24400, 0x1, 0x65, 0x155555, 0x7F1 },
+       [ATHOS_LUT_CHAN_610125_IDX] = { 24405, 0x1, 0x65, 0x160000, 0x7F2 },
+       [ATHOS_LUT_CHAN_610250_IDX] = { 24410, 0x1, 0x65, 0x16AAAB, 0x7F2 },
+       [ATHOS_LUT_CHAN_610375_IDX] = { 24415, 0x1, 0x65, 0x175555, 0x7F3 },
+       [ATHOS_LUT_CHAN_610500_IDX] = { 24420, 0x1, 0x65, 0x180000, 0x7F3 },
+       [ATHOS_LUT_CHAN_610625_IDX] = { 24425, 0x1, 0x65, 0x18AAAB, 0x7F3 },
+       [ATHOS_LUT_CHAN_610750_IDX] = { 24430, 0x1, 0x65, 0x195555, 0x7F4 },
+       [ATHOS_LUT_CHAN_610875_IDX] = { 24435, 0x1, 0x65, 0x1A0000, 0x7F4 },
+       [ATHOS_LUT_CHAN_611000_IDX] = { 24440, 0x1, 0x65, 0x1AAAAB, 0x7F5 },
+       [ATHOS_LUT_CHAN_611125_IDX] = { 24445, 0x1, 0x65, 0x1B5555, 0x7F5 },
+       [ATHOS_LUT_CHAN_611250_IDX] = { 24450, 0x1, 0x65, 0x1C0000, 0x7F6 },
+       [ATHOS_LUT_CHAN_611375_IDX] = { 24455, 0x1, 0x65, 0x1CAAAB, 0x7F6 },
+       [ATHOS_LUT_CHAN_611500_IDX] = { 24460, 0x1, 0x65, 0x1D5555, 0x7F6 },
+       [ATHOS_LUT_CHAN_611625_IDX] = { 24465, 0x1, 0x65, 0x1E0000, 0x7F7 },
+       [ATHOS_LUT_CHAN_611750_IDX] = { 24470, 0x1, 0x65, 0x1EAAAB, 0x7F7 },
+       [ATHOS_LUT_CHAN_611875_IDX] = { 24475, 0x1, 0x65, 0x1F5555, 0x7F8 },
+       [ATHOS_LUT_CHAN_612000_IDX] = { 24480, 0x1, 0x66, 0x0, 0x7F8 },
+       [ATHOS_LUT_CHAN_612125_IDX] = { 24485, 0x1, 0x66, 0xAAAB, 0x7F8 },
+       [ATHOS_LUT_CHAN_612250_IDX] = { 24490, 0x1, 0x66, 0x15555, 0x7F9 },
+       [ATHOS_LUT_CHAN_612375_IDX] = { 24495, 0x1, 0x66, 0x20000, 0x7F9 },
+       [ATHOS_LUT_CHAN_612500_IDX] = { 24500, 0x1, 0x66, 0x2AAAB, 0x7FA },
+       [ATHOS_LUT_CHAN_612625_IDX] = { 24505, 0x1, 0x66, 0x35555, 0x7FA },
+       [ATHOS_LUT_CHAN_612750_IDX] = { 24510, 0x1, 0x66, 0x40000, 0x7FB },
+       [ATHOS_LUT_CHAN_612875_IDX] = { 24515, 0x1, 0x66, 0x4AAAB, 0x7FB },
+       [ATHOS_LUT_CHAN_613000_IDX] = { 24520, 0x1, 0x66, 0x55555, 0x7FB },
+       [ATHOS_LUT_CHAN_613125_IDX] = { 24525, 0x1, 0x66, 0x60000, 0x7FC },
+       [ATHOS_LUT_CHAN_613250_IDX] = { 24530, 0x1, 0x66, 0x6AAAB, 0x7FC },
+       [ATHOS_LUT_CHAN_613375_IDX] = { 24535, 0x1, 0x66, 0x75555, 0x7FD },
+       [ATHOS_LUT_CHAN_613500_IDX] = { 24540, 0x1, 0x66, 0x80000, 0x7FD },
+       [ATHOS_LUT_CHAN_613625_IDX] = { 24545, 0x1, 0x66, 0x8AAAB, 0x7FD },
+       [ATHOS_LUT_CHAN_613750_IDX] = { 24550, 0x1, 0x66, 0x95555, 0x7FE },
+       [ATHOS_LUT_CHAN_613875_IDX] = { 24555, 0x1, 0x66, 0xA0000, 0x7FE },
+       [ATHOS_LUT_CHAN_614000_IDX] = { 24560, 0x1, 0x66, 0xAAAAB, 0x7FF },
+       [ATHOS_LUT_CHAN_614125_IDX] = { 24565, 0x1, 0x66, 0xB5555, 0x7FF },
+       [ATHOS_LUT_CHAN_614250_IDX] = { 24570, 0x1, 0x66, 0xC0000, 0x800 },
+       [ATHOS_LUT_CHAN_614375_IDX] = { 24575, 0x1, 0x66, 0xCAAAB, 0x800 },
+       [ATHOS_LUT_CHAN_614500_IDX] = { 24580, 0x1, 0x66, 0xD5555, 0x800 },
+       [ATHOS_LUT_CHAN_614625_IDX] = { 24585, 0x1, 0x66, 0xE0000, 0x801 },
+       [ATHOS_LUT_CHAN_614750_IDX] = { 24590, 0x1, 0x66, 0xEAAAB, 0x801 },
+       [ATHOS_LUT_CHAN_614875_IDX] = { 24595, 0x1, 0x66, 0xF5555, 0x802 },
+       [ATHOS_LUT_CHAN_615000_IDX] = { 24600, 0x1, 0x66, 0x100000, 0x802 },
+       [ATHOS_LUT_CHAN_615125_IDX] = { 24605, 0x1, 0x66, 0x10AAAB, 0x802 },
+       [ATHOS_LUT_CHAN_615250_IDX] = { 24610, 0x1, 0x66, 0x115555, 0x803 },
+       [ATHOS_LUT_CHAN_615375_IDX] = { 24615, 0x1, 0x66, 0x120000, 0x803 },
+       [ATHOS_LUT_CHAN_615500_IDX] = { 24620, 0x1, 0x66, 0x12AAAB, 0x804 },
+       [ATHOS_LUT_CHAN_615625_IDX] = { 24625, 0x1, 0x66, 0x135555, 0x804 },
+       [ATHOS_LUT_CHAN_615750_IDX] = { 24630, 0x1, 0x66, 0x140000, 0x805 },
+       [ATHOS_LUT_CHAN_615875_IDX] = { 24635, 0x1, 0x66, 0x14AAAB, 0x805 },
+       [ATHOS_LUT_CHAN_616000_IDX] = { 24640, 0x1, 0x66, 0x155555, 0x805 },
+       [ATHOS_LUT_CHAN_616125_IDX] = { 24645, 0x1, 0x66, 0x160000, 0x806 },
+       [ATHOS_LUT_CHAN_616250_IDX] = { 24650, 0x1, 0x66, 0x16AAAB, 0x806 },
+       [ATHOS_LUT_CHAN_616375_IDX] = { 24655, 0x1, 0x66, 0x175555, 0x807 },
+       [ATHOS_LUT_CHAN_616500_IDX] = { 24660, 0x1, 0x66, 0x180000, 0x807 },
+       [ATHOS_LUT_CHAN_616625_IDX] = { 24665, 0x1, 0x66, 0x18AAAB, 0x807 },
+       [ATHOS_LUT_CHAN_616750_IDX] = { 24670, 0x1, 0x66, 0x195555, 0x808 },
+       [ATHOS_LUT_CHAN_616875_IDX] = { 24675, 0x1, 0x66, 0x1A0000, 0x808 },
+       [ATHOS_LUT_CHAN_617000_IDX] = { 24680, 0x1, 0x66, 0x1AAAAB, 0x809 },
+       [ATHOS_LUT_CHAN_617125_IDX] = { 24685, 0x1, 0x66, 0x1B5555, 0x809 },
+       [ATHOS_LUT_CHAN_617250_IDX] = { 24690, 0x1, 0x66, 0x1C0000, 0x80A },
+       [ATHOS_LUT_CHAN_617375_IDX] = { 24695, 0x1, 0x66, 0x1CAAAB, 0x80A },
+       [ATHOS_LUT_CHAN_617500_IDX] = { 24700, 0x1, 0x66, 0x1D5555, 0x80A },
+       [ATHOS_LUT_CHAN_617625_IDX] = { 24705, 0x1, 0x66, 0x1E0000, 0x80B },
+       [ATHOS_LUT_CHAN_617750_IDX] = { 24710, 0x1, 0x66, 0x1EAAAB, 0x80B },
+       [ATHOS_LUT_CHAN_617875_IDX] = { 24715, 0x1, 0x66, 0x1F5555, 0x80C },
+       [ATHOS_LUT_CHAN_618000_IDX] = { 24720, 0x1, 0x67, 0x0, 0x80C },
+       [ATHOS_LUT_CHAN_618125_IDX] = { 24725, 0x1, 0x67, 0xAAAB, 0x80C },
+       [ATHOS_LUT_CHAN_618250_IDX] = { 24730, 0x1, 0x67, 0x15555, 0x80D },
+       [ATHOS_LUT_CHAN_618375_IDX] = { 24735, 0x1, 0x67, 0x20000, 0x80D },
+       [ATHOS_LUT_CHAN_618500_IDX] = { 24740, 0x1, 0x67, 0x2AAAB, 0x80E },
+       [ATHOS_LUT_CHAN_618625_IDX] = { 24745, 0x1, 0x67, 0x35555, 0x80E },
+       [ATHOS_LUT_CHAN_618750_IDX] = { 24750, 0x1, 0x67, 0x40000, 0x80F },
+       [ATHOS_LUT_CHAN_618875_IDX] = { 24755, 0x1, 0x67, 0x4AAAB, 0x80F },
+       [ATHOS_LUT_CHAN_619000_IDX] = { 24760, 0x1, 0x67, 0x55555, 0x80F },
+       [ATHOS_LUT_CHAN_619125_IDX] = { 24765, 0x1, 0x67, 0x60000, 0x810 },
+       [ATHOS_LUT_CHAN_619250_IDX] = { 24770, 0x1, 0x67, 0x6AAAB, 0x810 },
+       [ATHOS_LUT_CHAN_619375_IDX] = { 24775, 0x1, 0x67, 0x75555, 0x811 },
+       [ATHOS_LUT_CHAN_619500_IDX] = { 24780, 0x1, 0x67, 0x80000, 0x811 },
+       [ATHOS_LUT_CHAN_619625_IDX] = { 24785, 0x1, 0x67, 0x8AAAB, 0x811 },
+       [ATHOS_LUT_CHAN_619750_IDX] = { 24790, 0x1, 0x67, 0x95555, 0x812 },
+       [ATHOS_LUT_CHAN_619875_IDX] = { 24795, 0x1, 0x67, 0xA0000, 0x812 },
+       [ATHOS_LUT_CHAN_620000_IDX] = { 24800, 0x1, 0x67, 0xAAAAB, 0x813 },
+       [ATHOS_LUT_CHAN_620125_IDX] = { 24805, 0x1, 0x67, 0xB5555, 0x813 },
+       [ATHOS_LUT_CHAN_620250_IDX] = { 24810, 0x1, 0x67, 0xC0000, 0x814 },
+       [ATHOS_LUT_CHAN_620375_IDX] = { 24815, 0x1, 0x67, 0xCAAAB, 0x814 },
+       [ATHOS_LUT_CHAN_620500_IDX] = { 24820, 0x1, 0x67, 0xD5555, 0x814 },
+       [ATHOS_LUT_CHAN_620625_IDX] = { 24825, 0x1, 0x67, 0xE0000, 0x815 },
+       [ATHOS_LUT_CHAN_620750_IDX] = { 24830, 0x1, 0x67, 0xEAAAB, 0x815 },
+       [ATHOS_LUT_CHAN_620875_IDX] = { 24835, 0x1, 0x67, 0xF5555, 0x816 },
+       [ATHOS_LUT_CHAN_621000_IDX] = { 24840, 0x1, 0x67, 0x100000, 0x816 },
+       [ATHOS_LUT_CHAN_621125_IDX] = { 24845, 0x1, 0x67, 0x10AAAB, 0x816 },
+       [ATHOS_LUT_CHAN_621250_IDX] = { 24850, 0x1, 0x67, 0x115555, 0x817 },
+       [ATHOS_LUT_CHAN_621375_IDX] = { 24855, 0x1, 0x67, 0x120000, 0x817 },
+       [ATHOS_LUT_CHAN_621500_IDX] = { 24860, 0x1, 0x67, 0x12AAAB, 0x818 },
+       [ATHOS_LUT_CHAN_621625_IDX] = { 24865, 0x1, 0x67, 0x135555, 0x818 },
+       [ATHOS_LUT_CHAN_621750_IDX] = { 24870, 0x1, 0x67, 0x140000, 0x819 },
+       [ATHOS_LUT_CHAN_621875_IDX] = { 24875, 0x1, 0x67, 0x14AAAB, 0x819 },
+       [ATHOS_LUT_CHAN_622000_IDX] = { 24880, 0x1, 0x67, 0x155555, 0x819 },
+       [ATHOS_LUT_CHAN_622125_IDX] = { 24885, 0x1, 0x67, 0x160000, 0x81A },
+       [ATHOS_LUT_CHAN_622250_IDX] = { 24890, 0x1, 0x67, 0x16AAAB, 0x81A },
+       [ATHOS_LUT_CHAN_622375_IDX] = { 24895, 0x1, 0x67, 0x175555, 0x81B },
+       [ATHOS_LUT_CHAN_622500_IDX] = { 24900, 0x1, 0x67, 0x180000, 0x81B },
+       [ATHOS_LUT_CHAN_622625_IDX] = { 24905, 0x1, 0x67, 0x18AAAB, 0x81B },
+       [ATHOS_LUT_CHAN_622750_IDX] = { 24910, 0x1, 0x67, 0x195555, 0x81C },
+       [ATHOS_LUT_CHAN_622875_IDX] = { 24915, 0x1, 0x67, 0x1A0000, 0x81C },
+       [ATHOS_LUT_CHAN_623000_IDX] = { 24920, 0x1, 0x67, 0x1AAAAB, 0x81D },
+       [ATHOS_LUT_CHAN_623125_IDX] = { 24925, 0x1, 0x67, 0x1B5555, 0x81D },
+       [ATHOS_LUT_CHAN_623250_IDX] = { 24930, 0x1, 0x67, 0x1C0000, 0x81E },
+       [ATHOS_LUT_CHAN_623375_IDX] = { 24935, 0x1, 0x67, 0x1CAAAB, 0x81E },
+       [ATHOS_LUT_CHAN_623500_IDX] = { 24940, 0x1, 0x67, 0x1D5555, 0x81E },
+       [ATHOS_LUT_CHAN_623625_IDX] = { 24945, 0x1, 0x67, 0x1E0000, 0x81F },
+       [ATHOS_LUT_CHAN_623750_IDX] = { 24950, 0x1, 0x67, 0x1EAAAB, 0x81F },
+       [ATHOS_LUT_CHAN_623875_IDX] = { 24955, 0x1, 0x67, 0x1F5555, 0x820 },
+       [ATHOS_LUT_CHAN_624000_IDX] = { 24960, 0x1, 0x68, 0x0, 0x820 },
+       [ATHOS_LUT_CHAN_624125_IDX] = { 24965, 0x1, 0x68, 0xAAAB, 0x820 },
+       [ATHOS_LUT_CHAN_624250_IDX] = { 24970, 0x1, 0x68, 0x15555, 0x821 },
+       [ATHOS_LUT_CHAN_624375_IDX] = { 24975, 0x1, 0x68, 0x20000, 0x821 },
+       [ATHOS_LUT_CHAN_624500_IDX] = { 24980, 0x1, 0x68, 0x2AAAB, 0x822 },
+       [ATHOS_LUT_CHAN_624625_IDX] = { 24985, 0x1, 0x68, 0x35555, 0x822 },
+       [ATHOS_LUT_CHAN_624750_IDX] = { 24990, 0x1, 0x68, 0x40000, 0x823 },
+       [ATHOS_LUT_CHAN_624875_IDX] = { 24995, 0x1, 0x68, 0x4AAAB, 0x823 },
+       [ATHOS_LUT_CHAN_625000_IDX] = { 25000, 0x1, 0x68, 0x55555, 0x823 },
+       [ATHOS_LUT_CHAN_625125_IDX] = { 25005, 0x1, 0x68, 0x60000, 0x824 },
+       [ATHOS_LUT_CHAN_625250_IDX] = { 25010, 0x1, 0x68, 0x6AAAB, 0x824 },
+       [ATHOS_LUT_CHAN_625375_IDX] = { 25015, 0x1, 0x68, 0x75555, 0x825 },
+       [ATHOS_LUT_CHAN_625500_IDX] = { 25020, 0x1, 0x68, 0x80000, 0x825 },
+       [ATHOS_LUT_CHAN_625625_IDX] = { 25025, 0x1, 0x68, 0x8AAAB, 0x825 },
+       [ATHOS_LUT_CHAN_625750_IDX] = { 25030, 0x1, 0x68, 0x95555, 0x826 },
+       [ATHOS_LUT_CHAN_625875_IDX] = { 25035, 0x1, 0x68, 0xA0000, 0x826 },
+       [ATHOS_LUT_CHAN_626000_IDX] = { 25040, 0x1, 0x68, 0xAAAAB, 0x827 },
+       [ATHOS_LUT_CHAN_626125_IDX] = { 25045, 0x1, 0x68, 0xB5555, 0x827 },
+       [ATHOS_LUT_CHAN_626250_IDX] = { 25050, 0x1, 0x68, 0xC0000, 0x828 },
+       [ATHOS_LUT_CHAN_626375_IDX] = { 25055, 0x1, 0x68, 0xCAAAB, 0x828 },
+       [ATHOS_LUT_CHAN_626500_IDX] = { 25060, 0x1, 0x68, 0xD5555, 0x828 },
+       [ATHOS_LUT_CHAN_626625_IDX] = { 25065, 0x1, 0x68, 0xE0000, 0x829 },
+       [ATHOS_LUT_CHAN_626750_IDX] = { 25070, 0x1, 0x68, 0xEAAAB, 0x829 },
+       [ATHOS_LUT_CHAN_626875_IDX] = { 25075, 0x1, 0x68, 0xF5555, 0x82A },
+       [ATHOS_LUT_CHAN_627000_IDX] = { 25080, 0x1, 0x68, 0x100000, 0x82A },
+       [ATHOS_LUT_CHAN_627125_IDX] = { 25085, 0x1, 0x68, 0x10AAAB, 0x82A },
+       [ATHOS_LUT_CHAN_627250_IDX] = { 25090, 0x1, 0x68, 0x115555, 0x82B },
+       [ATHOS_LUT_CHAN_627375_IDX] = { 25095, 0x1, 0x68, 0x120000, 0x82B },
+       [ATHOS_LUT_CHAN_627500_IDX] = { 25100, 0x1, 0x68, 0x12AAAB, 0x82C },
+       [ATHOS_LUT_CHAN_627625_IDX] = { 25105, 0x1, 0x68, 0x135555, 0x82C },
+       [ATHOS_LUT_CHAN_627750_IDX] = { 25110, 0x1, 0x68, 0x140000, 0x82D },
+       [ATHOS_LUT_CHAN_627875_IDX] = { 25115, 0x1, 0x68, 0x14AAAB, 0x82D },
+       [ATHOS_LUT_CHAN_628000_IDX] = { 25120, 0x1, 0x68, 0x155555, 0x82D },
+       [ATHOS_LUT_CHAN_628125_IDX] = { 25125, 0x1, 0x68, 0x160000, 0x82E },
+       [ATHOS_LUT_CHAN_628250_IDX] = { 25130, 0x1, 0x68, 0x16AAAB, 0x82E },
+       [ATHOS_LUT_CHAN_628375_IDX] = { 25135, 0x1, 0x68, 0x175555, 0x82F },
+       [ATHOS_LUT_CHAN_628500_IDX] = { 25140, 0x1, 0x68, 0x180000, 0x82F },
+       [ATHOS_LUT_CHAN_628625_IDX] = { 25145, 0x1, 0x68, 0x18AAAB, 0x82F },
+       [ATHOS_LUT_CHAN_628750_IDX] = { 25150, 0x1, 0x68, 0x195555, 0x830 },
+       [ATHOS_LUT_CHAN_628875_IDX] = { 25155, 0x1, 0x68, 0x1A0000, 0x830 },
+       [ATHOS_LUT_CHAN_629000_IDX] = { 25160, 0x1, 0x68, 0x1AAAAB, 0x831 },
+       [ATHOS_LUT_CHAN_629125_IDX] = { 25165, 0x1, 0x68, 0x1B5555, 0x831 },
+       [ATHOS_LUT_CHAN_629250_IDX] = { 25170, 0x1, 0x68, 0x1C0000, 0x832 },
+       [ATHOS_LUT_CHAN_629375_IDX] = { 25175, 0x1, 0x68, 0x1CAAAB, 0x832 },
+       [ATHOS_LUT_CHAN_629500_IDX] = { 25180, 0x1, 0x68, 0x1D5555, 0x832 },
+       [ATHOS_LUT_CHAN_629625_IDX] = { 25185, 0x1, 0x68, 0x1E0000, 0x833 },
+       [ATHOS_LUT_CHAN_629750_IDX] = { 25190, 0x1, 0x68, 0x1EAAAB, 0x833 },
+       [ATHOS_LUT_CHAN_629875_IDX] = { 25195, 0x1, 0x68, 0x1F5555, 0x834 },
+       [ATHOS_LUT_CHAN_630000_IDX] = { 25200, 0x1, 0x69, 0x0, 0x834 },
+       [ATHOS_LUT_CHAN_630125_IDX] = { 25205, 0x1, 0x69, 0xAAAB, 0x834 },
+       [ATHOS_LUT_CHAN_630250_IDX] = { 25210, 0x1, 0x69, 0x15555, 0x835 },
+       [ATHOS_LUT_CHAN_630375_IDX] = { 25215, 0x1, 0x69, 0x20000, 0x835 },
+       [ATHOS_LUT_CHAN_630500_IDX] = { 25220, 0x1, 0x69, 0x2AAAB, 0x836 },
+       [ATHOS_LUT_CHAN_630625_IDX] = { 25225, 0x1, 0x69, 0x35555, 0x836 },
+       [ATHOS_LUT_CHAN_630750_IDX] = { 25230, 0x1, 0x69, 0x40000, 0x837 },
+       [ATHOS_LUT_CHAN_630875_IDX] = { 25235, 0x1, 0x69, 0x4AAAB, 0x837 },
+       [ATHOS_LUT_CHAN_631000_IDX] = { 25240, 0x1, 0x69, 0x55555, 0x837 },
+       [ATHOS_LUT_CHAN_631125_IDX] = { 25245, 0x1, 0x69, 0x60000, 0x838 },
+       [ATHOS_LUT_CHAN_631250_IDX] = { 25250, 0x1, 0x69, 0x6AAAB, 0x838 },
+       [ATHOS_LUT_CHAN_631375_IDX] = { 25255, 0x1, 0x69, 0x75555, 0x839 },
+       [ATHOS_LUT_CHAN_631500_IDX] = { 25260, 0x1, 0x69, 0x80000, 0x839 },
+       [ATHOS_LUT_CHAN_631625_IDX] = { 25265, 0x1, 0x69, 0x8AAAB, 0x839 },
+       [ATHOS_LUT_CHAN_631750_IDX] = { 25270, 0x1, 0x69, 0x95555, 0x83A },
+       [ATHOS_LUT_CHAN_631875_IDX] = { 25275, 0x1, 0x69, 0xA0000, 0x83A },
+       [ATHOS_LUT_CHAN_632000_IDX] = { 25280, 0x1, 0x69, 0xAAAAB, 0x83B },
+       [ATHOS_LUT_CHAN_632125_IDX] = { 25285, 0x1, 0x69, 0xB5555, 0x83B },
+       [ATHOS_LUT_CHAN_632250_IDX] = { 25290, 0x1, 0x69, 0xC0000, 0x83C },
+       [ATHOS_LUT_CHAN_632375_IDX] = { 25295, 0x1, 0x69, 0xCAAAB, 0x83C },
+       [ATHOS_LUT_CHAN_632500_IDX] = { 25300, 0x1, 0x69, 0xD5555, 0x83C },
+       [ATHOS_LUT_CHAN_632625_IDX] = { 25305, 0x1, 0x69, 0xE0000, 0x83D },
+       [ATHOS_LUT_CHAN_632750_IDX] = { 25310, 0x1, 0x69, 0xEAAAB, 0x83D },
+       [ATHOS_LUT_CHAN_632875_IDX] = { 25315, 0x1, 0x69, 0xF5555, 0x83E },
+       [ATHOS_LUT_CHAN_633000_IDX] = { 25320, 0x1, 0x69, 0x100000, 0x83E },
+       [ATHOS_LUT_CHAN_633125_IDX] = { 25325, 0x1, 0x69, 0x10AAAB, 0x83E },
+       [ATHOS_LUT_CHAN_633250_IDX] = { 25330, 0x1, 0x69, 0x115555, 0x83F },
+       [ATHOS_LUT_CHAN_633375_IDX] = { 25335, 0x1, 0x69, 0x120000, 0x83F },
+       [ATHOS_LUT_CHAN_633500_IDX] = { 25340, 0x1, 0x69, 0x12AAAB, 0x840 },
+       [ATHOS_LUT_CHAN_633625_IDX] = { 25345, 0x1, 0x69, 0x135555, 0x840 },
+       [ATHOS_LUT_CHAN_633750_IDX] = { 25350, 0x1, 0x69, 0x140000, 0x841 },
+       [ATHOS_LUT_CHAN_633875_IDX] = { 25355, 0x1, 0x69, 0x14AAAB, 0x841 },
+       [ATHOS_LUT_CHAN_634000_IDX] = { 25360, 0x1, 0x69, 0x155555, 0x841 },
+       [ATHOS_LUT_CHAN_634125_IDX] = { 25365, 0x1, 0x69, 0x160000, 0x842 },
+       [ATHOS_LUT_CHAN_634250_IDX] = { 25370, 0x1, 0x69, 0x16AAAB, 0x842 },
+       [ATHOS_LUT_CHAN_634375_IDX] = { 25375, 0x1, 0x69, 0x175555, 0x843 },
+       [ATHOS_LUT_CHAN_634500_IDX] = { 25380, 0x1, 0x69, 0x180000, 0x843 },
+       [ATHOS_LUT_CHAN_634625_IDX] = { 25385, 0x1, 0x69, 0x18AAAB, 0x843 },
+       [ATHOS_LUT_CHAN_634750_IDX] = { 25390, 0x1, 0x69, 0x195555, 0x844 },
+       [ATHOS_LUT_CHAN_634875_IDX] = { 25395, 0x1, 0x69, 0x1A0000, 0x844 },
+       [ATHOS_LUT_CHAN_635000_IDX] = { 25400, 0x1, 0x69, 0x1AAAAB, 0x845 },
+       [ATHOS_LUT_CHAN_635125_IDX] = { 25405, 0x1, 0x69, 0x1B5555, 0x845 },
+       [ATHOS_LUT_CHAN_635250_IDX] = { 25410, 0x1, 0x69, 0x1C0000, 0x846 },
+       [ATHOS_LUT_CHAN_635375_IDX] = { 25415, 0x1, 0x69, 0x1CAAAB, 0x846 },
+       [ATHOS_LUT_CHAN_635500_IDX] = { 25420, 0x1, 0x69, 0x1D5555, 0x846 },
+       [ATHOS_LUT_CHAN_635625_IDX] = { 25425, 0x1, 0x69, 0x1E0000, 0x847 },
+       [ATHOS_LUT_CHAN_635750_IDX] = { 25430, 0x1, 0x69, 0x1EAAAB, 0x847 },
+       [ATHOS_LUT_CHAN_635875_IDX] = { 25435, 0x1, 0x69, 0x1F5555, 0x848 },
+       [ATHOS_LUT_CHAN_636000_IDX] = { 25440, 0x1, 0x6A, 0x0, 0x848 },
+       [ATHOS_LUT_CHAN_636125_IDX] = { 25445, 0x1, 0x6A, 0xAAAB, 0x848 },
+       [ATHOS_LUT_CHAN_636250_IDX] = { 25450, 0x1, 0x6A, 0x15555, 0x849 },
+       [ATHOS_LUT_CHAN_636375_IDX] = { 25455, 0x1, 0x6A, 0x20000, 0x849 },
+       [ATHOS_LUT_CHAN_636500_IDX] = { 25460, 0x1, 0x6A, 0x2AAAB, 0x84A },
+       [ATHOS_LUT_CHAN_636625_IDX] = { 25465, 0x1, 0x6A, 0x35555, 0x84A },
+       [ATHOS_LUT_CHAN_636750_IDX] = { 25470, 0x1, 0x6A, 0x40000, 0x84B },
+       [ATHOS_LUT_CHAN_636875_IDX] = { 25475, 0x1, 0x6A, 0x4AAAB, 0x84B },
+       [ATHOS_LUT_CHAN_637000_IDX] = { 25480, 0x1, 0x6A, 0x55555, 0x84B },
+       [ATHOS_LUT_CHAN_637125_IDX] = { 25485, 0x1, 0x6A, 0x60000, 0x84C },
+       [ATHOS_LUT_CHAN_637250_IDX] = { 25490, 0x1, 0x6A, 0x6AAAB, 0x84C },
+       [ATHOS_LUT_CHAN_637375_IDX] = { 25495, 0x1, 0x6A, 0x75555, 0x84D },
+       [ATHOS_LUT_CHAN_637500_IDX] = { 25500, 0x1, 0x6A, 0x80000, 0x84D },
+       [ATHOS_LUT_CHAN_637625_IDX] = { 25505, 0x1, 0x6A, 0x8AAAB, 0x84D },
+       [ATHOS_LUT_CHAN_637750_IDX] = { 25510, 0x1, 0x6A, 0x95555, 0x84E },
+       [ATHOS_LUT_CHAN_637875_IDX] = { 25515, 0x1, 0x6A, 0xA0000, 0x84E },
+       [ATHOS_LUT_CHAN_638000_IDX] = { 25520, 0x1, 0x6A, 0xAAAAB, 0x84F },
+       [ATHOS_LUT_CHAN_638125_IDX] = { 25525, 0x1, 0x6A, 0xB5555, 0x84F },
+       [ATHOS_LUT_CHAN_638250_IDX] = { 25530, 0x1, 0x6A, 0xC0000, 0x850 },
+       [ATHOS_LUT_CHAN_638375_IDX] = { 25535, 0x1, 0x6A, 0xCAAAB, 0x850 },
+       [ATHOS_LUT_CHAN_638500_IDX] = { 25540, 0x1, 0x6A, 0xD5555, 0x850 },
+       [ATHOS_LUT_CHAN_638625_IDX] = { 25545, 0x1, 0x6A, 0xE0000, 0x851 },
+       [ATHOS_LUT_CHAN_638750_IDX] = { 25550, 0x1, 0x6A, 0xEAAAB, 0x851 },
+       [ATHOS_LUT_CHAN_638875_IDX] = { 25555, 0x1, 0x6A, 0xF5555, 0x852 },
+       [ATHOS_LUT_CHAN_639000_IDX] = { 25560, 0x1, 0x6A, 0x100000, 0x852 },
+       [ATHOS_LUT_CHAN_639125_IDX] = { 25565, 0x1, 0x6A, 0x10AAAB, 0x852 },
+       [ATHOS_LUT_CHAN_639250_IDX] = { 25570, 0x1, 0x6A, 0x115555, 0x853 },
+       [ATHOS_LUT_CHAN_639375_IDX] = { 25575, 0x1, 0x6A, 0x120000, 0x853 },
+       [ATHOS_LUT_CHAN_639500_IDX] = { 25580, 0x1, 0x6A, 0x12AAAB, 0x854 },
+       [ATHOS_LUT_CHAN_639625_IDX] = { 25585, 0x1, 0x6A, 0x135555, 0x854 },
+       [ATHOS_LUT_CHAN_639750_IDX] = { 25590, 0x1, 0x6A, 0x140000, 0x855 },
+       [ATHOS_LUT_CHAN_639875_IDX] = { 25595, 0x1, 0x6A, 0x14AAAB, 0x855 },
+       [ATHOS_LUT_CHAN_640000_IDX] = { 25600, 0x1, 0x6A, 0x155555, 0x855 },
+       [ATHOS_LUT_CHAN_640125_IDX] = { 25605, 0x1, 0x6A, 0x160000, 0x856 },
+       [ATHOS_LUT_CHAN_640250_IDX] = { 25610, 0x1, 0x6A, 0x16AAAB, 0x856 },
+       [ATHOS_LUT_CHAN_640375_IDX] = { 25615, 0x1, 0x6A, 0x175555, 0x857 },
+       [ATHOS_LUT_CHAN_640500_IDX] = { 25620, 0x1, 0x6A, 0x180000, 0x857 },
+       [ATHOS_LUT_CHAN_640625_IDX] = { 25625, 0x1, 0x6A, 0x18AAAB, 0x857 },
+       [ATHOS_LUT_CHAN_640750_IDX] = { 25630, 0x1, 0x6A, 0x195555, 0x858 },
+       [ATHOS_LUT_CHAN_640875_IDX] = { 25635, 0x1, 0x6A, 0x1A0000, 0x858 },
+       [ATHOS_LUT_CHAN_641000_IDX] = { 25640, 0x1, 0x6A, 0x1AAAAB, 0x859 },
+       [ATHOS_LUT_CHAN_641125_IDX] = { 25645, 0x1, 0x6A, 0x1B5555, 0x859 },
+       [ATHOS_LUT_CHAN_641250_IDX] = { 25650, 0x1, 0x6A, 0x1C0000, 0x85A },
+       [ATHOS_LUT_CHAN_641375_IDX] = { 25655, 0x1, 0x6A, 0x1CAAAB, 0x85A },
+       [ATHOS_LUT_CHAN_641500_IDX] = { 25660, 0x1, 0x6A, 0x1D5555, 0x85A },
+       [ATHOS_LUT_CHAN_641625_IDX] = { 25665, 0x1, 0x6A, 0x1E0000, 0x85B },
+       [ATHOS_LUT_CHAN_641750_IDX] = { 25670, 0x1, 0x6A, 0x1EAAAB, 0x85B },
+       [ATHOS_LUT_CHAN_641875_IDX] = { 25675, 0x1, 0x6A, 0x1F5555, 0x85C },
+       [ATHOS_LUT_CHAN_642000_IDX] = { 25680, 0x1, 0x6B, 0x0, 0x85C },
+       [ATHOS_LUT_CHAN_642125_IDX] = { 25685, 0x1, 0x6B, 0xAAAB, 0x85C },
+       [ATHOS_LUT_CHAN_642250_IDX] = { 25690, 0x1, 0x6B, 0x15555, 0x85D },
+       [ATHOS_LUT_CHAN_642375_IDX] = { 25695, 0x1, 0x6B, 0x20000, 0x85D },
+       [ATHOS_LUT_CHAN_642500_IDX] = { 25700, 0x1, 0x6B, 0x2AAAB, 0x85E },
+       [ATHOS_LUT_CHAN_642625_IDX] = { 25705, 0x1, 0x6B, 0x35555, 0x85E },
+       [ATHOS_LUT_CHAN_642750_IDX] = { 25710, 0x1, 0x6B, 0x40000, 0x85F },
+       [ATHOS_LUT_CHAN_642875_IDX] = { 25715, 0x1, 0x6B, 0x4AAAB, 0x85F },
+       [ATHOS_LUT_CHAN_643000_IDX] = { 25720, 0x1, 0x6B, 0x55555, 0x85F },
+       [ATHOS_LUT_CHAN_643125_IDX] = { 25725, 0x1, 0x6B, 0x60000, 0x860 },
+       [ATHOS_LUT_CHAN_643250_IDX] = { 25730, 0x1, 0x6B, 0x6AAAB, 0x860 },
+       [ATHOS_LUT_CHAN_643375_IDX] = { 25735, 0x1, 0x6B, 0x75555, 0x861 },
+       [ATHOS_LUT_CHAN_643500_IDX] = { 25740, 0x1, 0x6B, 0x80000, 0x861 },
+       [ATHOS_LUT_CHAN_643625_IDX] = { 25745, 0x1, 0x6B, 0x8AAAB, 0x861 },
+       [ATHOS_LUT_CHAN_643750_IDX] = { 25750, 0x1, 0x6B, 0x95555, 0x862 },
+       [ATHOS_LUT_CHAN_643875_IDX] = { 25755, 0x1, 0x6B, 0xA0000, 0x862 },
+       [ATHOS_LUT_CHAN_644000_IDX] = { 25760, 0x1, 0x6B, 0xAAAAB, 0x863 },
+       [ATHOS_LUT_CHAN_644125_IDX] = { 25765, 0x1, 0x6B, 0xB5555, 0x863 },
+       [ATHOS_LUT_CHAN_644250_IDX] = { 25770, 0x1, 0x6B, 0xC0000, 0x864 },
+       [ATHOS_LUT_CHAN_644375_IDX] = { 25775, 0x1, 0x6B, 0xCAAAB, 0x864 },
+       [ATHOS_LUT_CHAN_644500_IDX] = { 25780, 0x1, 0x6B, 0xD5555, 0x864 },
+       [ATHOS_LUT_CHAN_644625_IDX] = { 25785, 0x1, 0x6B, 0xE0000, 0x865 },
+       [ATHOS_LUT_CHAN_644750_IDX] = { 25790, 0x1, 0x6B, 0xEAAAB, 0x865 },
+       [ATHOS_LUT_CHAN_644875_IDX] = { 25795, 0x1, 0x6B, 0xF5555, 0x866 },
+       [ATHOS_LUT_CHAN_645000_IDX] = { 25800, 0x1, 0x6B, 0x100000, 0x866 },
+       [ATHOS_LUT_CHAN_645125_IDX] = { 25805, 0x1, 0x6B, 0x10AAAB, 0x866 },
+       [ATHOS_LUT_CHAN_645250_IDX] = { 25810, 0x1, 0x6B, 0x115555, 0x867 },
+       [ATHOS_LUT_CHAN_645375_IDX] = { 25815, 0x1, 0x6B, 0x120000, 0x867 },
+       [ATHOS_LUT_CHAN_645500_IDX] = { 25820, 0x1, 0x6B, 0x12AAAB, 0x868 },
+       [ATHOS_LUT_CHAN_645625_IDX] = { 25825, 0x1, 0x6B, 0x135555, 0x868 },
+       [ATHOS_LUT_CHAN_645750_IDX] = { 25830, 0x1, 0x6B, 0x140000, 0x869 },
+       [ATHOS_LUT_CHAN_645875_IDX] = { 25835, 0x1, 0x6B, 0x14AAAB, 0x869 },
+       [ATHOS_LUT_CHAN_646000_IDX] = { 25840, 0x1, 0x6B, 0x155555, 0x869 },
+       [ATHOS_LUT_CHAN_646125_IDX] = { 25845, 0x1, 0x6B, 0x160000, 0x86A },
+       [ATHOS_LUT_CHAN_646250_IDX] = { 25850, 0x1, 0x6B, 0x16AAAB, 0x86A },
+       [ATHOS_LUT_CHAN_646375_IDX] = { 25855, 0x1, 0x6B, 0x175555, 0x86B },
+       [ATHOS_LUT_CHAN_646500_IDX] = { 25860, 0x1, 0x6B, 0x180000, 0x86B },
+       [ATHOS_LUT_CHAN_646625_IDX] = { 25865, 0x1, 0x6B, 0x18AAAB, 0x86B },
+       [ATHOS_LUT_CHAN_646750_IDX] = { 25870, 0x1, 0x6B, 0x195555, 0x86C },
+       [ATHOS_LUT_CHAN_646875_IDX] = { 25875, 0x1, 0x6B, 0x1A0000, 0x86C },
+       [ATHOS_LUT_CHAN_647000_IDX] = { 25880, 0x1, 0x6B, 0x1AAAAB, 0x86D },
+       [ATHOS_LUT_CHAN_647125_IDX] = { 25885, 0x1, 0x6B, 0x1B5555, 0x86D },
+       [ATHOS_LUT_CHAN_647250_IDX] = { 25890, 0x1, 0x6B, 0x1C0000, 0x86E },
+       [ATHOS_LUT_CHAN_647375_IDX] = { 25895, 0x1, 0x6B, 0x1CAAAB, 0x86E },
+       [ATHOS_LUT_CHAN_647500_IDX] = { 25900, 0x1, 0x6B, 0x1D5555, 0x86E },
+       [ATHOS_LUT_CHAN_647625_IDX] = { 25905, 0x1, 0x6B, 0x1E0000, 0x86F },
+       [ATHOS_LUT_CHAN_647750_IDX] = { 25910, 0x1, 0x6B, 0x1EAAAB, 0x86F },
+       [ATHOS_LUT_CHAN_647875_IDX] = { 25915, 0x1, 0x6B, 0x1F5555, 0x870 },
+       [ATHOS_LUT_CHAN_648000_IDX] = { 25920, 0x1, 0x6C, 0x0, 0x870 },
+       [ATHOS_LUT_CHAN_648125_IDX] = { 25925, 0x1, 0x6C, 0xAAAB, 0x870 },
+       [ATHOS_LUT_CHAN_648250_IDX] = { 25930, 0x1, 0x6C, 0x15555, 0x871 },
+       [ATHOS_LUT_CHAN_648375_IDX] = { 25935, 0x1, 0x6C, 0x20000, 0x871 },
+       [ATHOS_LUT_CHAN_648500_IDX] = { 25940, 0x1, 0x6C, 0x2AAAB, 0x872 },
+       [ATHOS_LUT_CHAN_648625_IDX] = { 25945, 0x1, 0x6C, 0x35555, 0x872 },
+       [ATHOS_LUT_CHAN_648750_IDX] = { 25950, 0x1, 0x6C, 0x40000, 0x873 },
+       [ATHOS_LUT_CHAN_648875_IDX] = { 25955, 0x1, 0x6C, 0x4AAAB, 0x873 },
+       [ATHOS_LUT_CHAN_649000_IDX] = { 25960, 0x1, 0x6C, 0x55555, 0x873 },
+       [ATHOS_LUT_CHAN_649125_IDX] = { 25965, 0x1, 0x6C, 0x60000, 0x874 },
+       [ATHOS_LUT_CHAN_649250_IDX] = { 25970, 0x1, 0x6C, 0x6AAAB, 0x874 },
+       [ATHOS_LUT_CHAN_649375_IDX] = { 25975, 0x1, 0x6C, 0x75555, 0x875 },
+       [ATHOS_LUT_CHAN_649500_IDX] = { 25980, 0x1, 0x6C, 0x80000, 0x875 },
+       [ATHOS_LUT_CHAN_649625_IDX] = { 25985, 0x1, 0x6C, 0x8AAAB, 0x875 },
+       [ATHOS_LUT_CHAN_649750_IDX] = { 25990, 0x1, 0x6C, 0x95555, 0x876 },
+       [ATHOS_LUT_CHAN_649875_IDX] = { 25995, 0x1, 0x6C, 0xA0000, 0x876 },
+       [ATHOS_LUT_CHAN_650000_IDX] = { 26000, 0x1, 0x6C, 0xAAAAB, 0x877 },
+       [ATHOS_LUT_CHAN_650125_IDX] = { 26005, 0x1, 0x6C, 0xB5555, 0x877 },
+       [ATHOS_LUT_CHAN_650250_IDX] = { 26010, 0x1, 0x6C, 0xC0000, 0x878 },
+       [ATHOS_LUT_CHAN_650375_IDX] = { 26015, 0x1, 0x6C, 0xCAAAB, 0x878 },
+       [ATHOS_LUT_CHAN_650500_IDX] = { 26020, 0x1, 0x6C, 0xD5555, 0x878 },
+       [ATHOS_LUT_CHAN_650625_IDX] = { 26025, 0x1, 0x6C, 0xE0000, 0x879 },
+       [ATHOS_LUT_CHAN_650750_IDX] = { 26030, 0x1, 0x6C, 0xEAAAB, 0x879 },
+       [ATHOS_LUT_CHAN_650875_IDX] = { 26035, 0x1, 0x6C, 0xF5555, 0x87A },
+       [ATHOS_LUT_CHAN_651000_IDX] = { 26040, 0x1, 0x6C, 0x100000, 0x87A },
+       [ATHOS_LUT_CHAN_651125_IDX] = { 26045, 0x1, 0x6C, 0x10AAAB, 0x87A },
+       [ATHOS_LUT_CHAN_651250_IDX] = { 26050, 0x1, 0x6C, 0x115555, 0x87B },
+       [ATHOS_LUT_CHAN_651375_IDX] = { 26055, 0x1, 0x6C, 0x120000, 0x87B },
+       [ATHOS_LUT_CHAN_651500_IDX] = { 26060, 0x1, 0x6C, 0x12AAAB, 0x87C },
+       [ATHOS_LUT_CHAN_651625_IDX] = { 26065, 0x1, 0x6C, 0x135555, 0x87C },
+       [ATHOS_LUT_CHAN_651750_IDX] = { 26070, 0x1, 0x6C, 0x140000, 0x87D },
+       [ATHOS_LUT_CHAN_651875_IDX] = { 26075, 0x1, 0x6C, 0x14AAAB, 0x87D },
+       [ATHOS_LUT_CHAN_652000_IDX] = { 26080, 0x1, 0x6C, 0x155555, 0x87D },
+       [ATHOS_LUT_CHAN_652125_IDX] = { 26085, 0x1, 0x6C, 0x160000, 0x87E },
+       [ATHOS_LUT_CHAN_652250_IDX] = { 26090, 0x1, 0x6C, 0x16AAAB, 0x87E },
+       [ATHOS_LUT_CHAN_652375_IDX] = { 26095, 0x1, 0x6C, 0x175555, 0x87F },
+       [ATHOS_LUT_CHAN_652500_IDX] = { 26100, 0x1, 0x6C, 0x180000, 0x87F },
+       [ATHOS_LUT_CHAN_652625_IDX] = { 26105, 0x1, 0x6C, 0x18AAAB, 0x87F },
+       [ATHOS_LUT_CHAN_652750_IDX] = { 26110, 0x1, 0x6C, 0x195555, 0x880 },
+       [ATHOS_LUT_CHAN_652875_IDX] = { 26115, 0x1, 0x6C, 0x1A0000, 0x880 },
+       [ATHOS_LUT_CHAN_653000_IDX] = { 26120, 0x1, 0x6C, 0x1AAAAB, 0x881 },
+       [ATHOS_LUT_CHAN_653125_IDX] = { 26125, 0x1, 0x6C, 0x1B5555, 0x881 },
+       [ATHOS_LUT_CHAN_653250_IDX] = { 26130, 0x1, 0x6C, 0x1C0000, 0x882 },
+       [ATHOS_LUT_CHAN_653375_IDX] = { 26135, 0x1, 0x6C, 0x1CAAAB, 0x882 },
+       [ATHOS_LUT_CHAN_653500_IDX] = { 26140, 0x1, 0x6C, 0x1D5555, 0x882 },
+       [ATHOS_LUT_CHAN_653625_IDX] = { 26145, 0x1, 0x6C, 0x1E0000, 0x883 },
+       [ATHOS_LUT_CHAN_653750_IDX] = { 26150, 0x1, 0x6C, 0x1EAAAB, 0x883 },
+       [ATHOS_LUT_CHAN_653875_IDX] = { 26155, 0x1, 0x6C, 0x1F5555, 0x884 },
+       [ATHOS_LUT_CHAN_654000_IDX] = { 26160, 0x1, 0x6D, 0x0, 0x884 },
+       [ATHOS_LUT_CHAN_654125_IDX] = { 26165, 0x1, 0x6D, 0xAAAB, 0x884 },
+       [ATHOS_LUT_CHAN_654250_IDX] = { 26170, 0x1, 0x6D, 0x15555, 0x885 },
+       [ATHOS_LUT_CHAN_654375_IDX] = { 26175, 0x1, 0x6D, 0x20000, 0x885 },
+       [ATHOS_LUT_CHAN_654500_IDX] = { 26180, 0x1, 0x6D, 0x2AAAB, 0x886 },
+       [ATHOS_LUT_CHAN_654625_IDX] = { 26185, 0x1, 0x6D, 0x35555, 0x886 },
+       [ATHOS_LUT_CHAN_654750_IDX] = { 26190, 0x1, 0x6D, 0x40000, 0x887 },
+       [ATHOS_LUT_CHAN_654875_IDX] = { 26195, 0x1, 0x6D, 0x4AAAB, 0x887 },
+       [ATHOS_LUT_CHAN_655000_IDX] = { 26200, 0x1, 0x6D, 0x55555, 0x887 },
+       [ATHOS_LUT_CHAN_655125_IDX] = { 26205, 0x1, 0x6D, 0x60000, 0x888 },
+       [ATHOS_LUT_CHAN_655250_IDX] = { 26210, 0x1, 0x6D, 0x6AAAB, 0x888 },
+       [ATHOS_LUT_CHAN_655375_IDX] = { 26215, 0x1, 0x6D, 0x75555, 0x889 },
+       [ATHOS_LUT_CHAN_655500_IDX] = { 26220, 0x1, 0x6D, 0x80000, 0x889 },
+       [ATHOS_LUT_CHAN_655625_IDX] = { 26225, 0x1, 0x6D, 0x8AAAB, 0x889 },
+       [ATHOS_LUT_CHAN_655750_IDX] = { 26230, 0x1, 0x6D, 0x95555, 0x88A },
+       [ATHOS_LUT_CHAN_655875_IDX] = { 26235, 0x1, 0x6D, 0xA0000, 0x88A },
+       [ATHOS_LUT_CHAN_656000_IDX] = { 26240, 0x1, 0x6D, 0xAAAAB, 0x88B },
+       [ATHOS_LUT_CHAN_656125_IDX] = { 26245, 0x1, 0x6D, 0xB5555, 0x88B },
+       [ATHOS_LUT_CHAN_656250_IDX] = { 26250, 0x1, 0x6D, 0xC0000, 0x88C },
+       [ATHOS_LUT_CHAN_656375_IDX] = { 26255, 0x1, 0x6D, 0xCAAAB, 0x88C },
+       [ATHOS_LUT_CHAN_656500_IDX] = { 26260, 0x1, 0x6D, 0xD5555, 0x88C },
+       [ATHOS_LUT_CHAN_656625_IDX] = { 26265, 0x1, 0x6D, 0xE0000, 0x88D },
+       [ATHOS_LUT_CHAN_656750_IDX] = { 26270, 0x1, 0x6D, 0xEAAAB, 0x88D },
+       [ATHOS_LUT_CHAN_656875_IDX] = { 26275, 0x1, 0x6D, 0xF5555, 0x88E },
+       [ATHOS_LUT_CHAN_657000_IDX] = { 26280, 0x1, 0x6D, 0x100000, 0x88E },
+       [ATHOS_LUT_CHAN_657125_IDX] = { 26285, 0x1, 0x6D, 0x10AAAB, 0x88E },
+       [ATHOS_LUT_CHAN_657250_IDX] = { 26290, 0x1, 0x6D, 0x115555, 0x88F },
+       [ATHOS_LUT_CHAN_657375_IDX] = { 26295, 0x1, 0x6D, 0x120000, 0x88F },
+       [ATHOS_LUT_CHAN_657500_IDX] = { 26300, 0x1, 0x6D, 0x12AAAB, 0x890 },
+       [ATHOS_LUT_CHAN_657625_IDX] = { 26305, 0x1, 0x6D, 0x135555, 0x890 },
+       [ATHOS_LUT_CHAN_657750_IDX] = { 26310, 0x1, 0x6D, 0x140000, 0x891 },
+       [ATHOS_LUT_CHAN_657875_IDX] = { 26315, 0x1, 0x6D, 0x14AAAB, 0x891 },
+       [ATHOS_LUT_CHAN_658000_IDX] = { 26320, 0x1, 0x6D, 0x155555, 0x891 },
+       [ATHOS_LUT_CHAN_658125_IDX] = { 26325, 0x1, 0x6D, 0x160000, 0x892 },
+       [ATHOS_LUT_CHAN_658250_IDX] = { 26330, 0x1, 0x6D, 0x16AAAB, 0x892 },
+       [ATHOS_LUT_CHAN_658375_IDX] = { 26335, 0x1, 0x6D, 0x175555, 0x893 },
+       [ATHOS_LUT_CHAN_658500_IDX] = { 26340, 0x1, 0x6D, 0x180000, 0x893 },
+       [ATHOS_LUT_CHAN_658625_IDX] = { 26345, 0x1, 0x6D, 0x18AAAB, 0x893 },
+       [ATHOS_LUT_CHAN_658750_IDX] = { 26350, 0x1, 0x6D, 0x195555, 0x894 },
+       [ATHOS_LUT_CHAN_658875_IDX] = { 26355, 0x1, 0x6D, 0x1A0000, 0x894 },
+       [ATHOS_LUT_CHAN_659000_IDX] = { 26360, 0x1, 0x6D, 0x1AAAAB, 0x895 },
+       [ATHOS_LUT_CHAN_659125_IDX] = { 26365, 0x1, 0x6D, 0x1B5555, 0x895 },
+       [ATHOS_LUT_CHAN_659250_IDX] = { 26370, 0x1, 0x6D, 0x1C0000, 0x896 },
+       [ATHOS_LUT_CHAN_659375_IDX] = { 26375, 0x1, 0x6D, 0x1CAAAB, 0x896 },
+       [ATHOS_LUT_CHAN_659500_IDX] = { 26380, 0x1, 0x6D, 0x1D5555, 0x896 },
+       [ATHOS_LUT_CHAN_659625_IDX] = { 26385, 0x1, 0x6D, 0x1E0000, 0x897 },
+       [ATHOS_LUT_CHAN_659750_IDX] = { 26390, 0x1, 0x6D, 0x1EAAAB, 0x897 },
+       [ATHOS_LUT_CHAN_659875_IDX] = { 26395, 0x1, 0x6D, 0x1F5555, 0x898 },
+       [ATHOS_LUT_CHAN_660000_IDX] = { 26400, 0x1, 0x6E, 0x0, 0x898 },
+       [ATHOS_LUT_CHAN_660125_IDX] = { 26405, 0x1, 0x6E, 0xAAAB, 0x898 },
+       [ATHOS_LUT_CHAN_660250_IDX] = { 26410, 0x1, 0x6E, 0x15555, 0x899 },
+       [ATHOS_LUT_CHAN_660375_IDX] = { 26415, 0x1, 0x6E, 0x20000, 0x899 },
+       [ATHOS_LUT_CHAN_660500_IDX] = { 26420, 0x1, 0x6E, 0x2AAAB, 0x89A },
+       [ATHOS_LUT_CHAN_660625_IDX] = { 26425, 0x1, 0x6E, 0x35555, 0x89A },
+       [ATHOS_LUT_CHAN_660750_IDX] = { 26430, 0x1, 0x6E, 0x40000, 0x89B },
+       [ATHOS_LUT_CHAN_660875_IDX] = { 26435, 0x1, 0x6E, 0x4AAAB, 0x89B },
+       [ATHOS_LUT_CHAN_661000_IDX] = { 26440, 0x1, 0x6E, 0x55555, 0x89B },
+       [ATHOS_LUT_CHAN_661125_IDX] = { 26445, 0x1, 0x6E, 0x60000, 0x89C },
+       [ATHOS_LUT_CHAN_661250_IDX] = { 26450, 0x1, 0x6E, 0x6AAAB, 0x89C },
+       [ATHOS_LUT_CHAN_661375_IDX] = { 26455, 0x1, 0x6E, 0x75555, 0x89D },
+       [ATHOS_LUT_CHAN_661500_IDX] = { 26460, 0x1, 0x6E, 0x80000, 0x89D },
+       [ATHOS_LUT_CHAN_661625_IDX] = { 26465, 0x1, 0x6E, 0x8AAAB, 0x89D },
+       [ATHOS_LUT_CHAN_661750_IDX] = { 26470, 0x1, 0x6E, 0x95555, 0x89E },
+       [ATHOS_LUT_CHAN_661875_IDX] = { 26475, 0x1, 0x6E, 0xA0000, 0x89E },
+       [ATHOS_LUT_CHAN_662000_IDX] = { 26480, 0x1, 0x6E, 0xAAAAB, 0x89F },
+       [ATHOS_LUT_CHAN_662125_IDX] = { 26485, 0x1, 0x6E, 0xB5555, 0x89F },
+       [ATHOS_LUT_CHAN_662250_IDX] = { 26490, 0x1, 0x6E, 0xC0000, 0x8A0 },
+       [ATHOS_LUT_CHAN_662375_IDX] = { 26495, 0x1, 0x6E, 0xCAAAB, 0x8A0 },
+       [ATHOS_LUT_CHAN_662500_IDX] = { 26500, 0x1, 0x6E, 0xD5555, 0x8A0 },
+       [ATHOS_LUT_CHAN_662625_IDX] = { 26505, 0x1, 0x6E, 0xE0000, 0x8A1 },
+       [ATHOS_LUT_CHAN_662750_IDX] = { 26510, 0x1, 0x6E, 0xEAAAB, 0x8A1 },
+       [ATHOS_LUT_CHAN_662875_IDX] = { 26515, 0x1, 0x6E, 0xF5555, 0x8A2 },
+       [ATHOS_LUT_CHAN_663000_IDX] = { 26520, 0x1, 0x6E, 0x100000, 0x8A2 },
+       [ATHOS_LUT_CHAN_663125_IDX] = { 26525, 0x1, 0x6E, 0x10AAAB, 0x8A2 },
+       [ATHOS_LUT_CHAN_663250_IDX] = { 26530, 0x1, 0x6E, 0x115555, 0x8A3 },
+       [ATHOS_LUT_CHAN_663375_IDX] = { 26535, 0x1, 0x6E, 0x120000, 0x8A3 },
+       [ATHOS_LUT_CHAN_663500_IDX] = { 26540, 0x1, 0x6E, 0x12AAAB, 0x8A4 },
+       [ATHOS_LUT_CHAN_663625_IDX] = { 26545, 0x1, 0x6E, 0x135555, 0x8A4 },
+       [ATHOS_LUT_CHAN_663750_IDX] = { 26550, 0x1, 0x6E, 0x140000, 0x8A5 },
+       [ATHOS_LUT_CHAN_663875_IDX] = { 26555, 0x1, 0x6E, 0x14AAAB, 0x8A5 },
+       [ATHOS_LUT_CHAN_664000_IDX] = { 26560, 0x1, 0x6E, 0x155555, 0x8A5 },
+       [ATHOS_LUT_CHAN_664125_IDX] = { 26565, 0x1, 0x6E, 0x160000, 0x8A6 },
+       [ATHOS_LUT_CHAN_664250_IDX] = { 26570, 0x1, 0x6E, 0x16AAAB, 0x8A6 },
+       [ATHOS_LUT_CHAN_664375_IDX] = { 26575, 0x1, 0x6E, 0x175555, 0x8A7 },
+       [ATHOS_LUT_CHAN_664500_IDX] = { 26580, 0x1, 0x6E, 0x180000, 0x8A7 },
+       [ATHOS_LUT_CHAN_664625_IDX] = { 26585, 0x1, 0x6E, 0x18AAAB, 0x8A7 },
+       [ATHOS_LUT_CHAN_664750_IDX] = { 26590, 0x1, 0x6E, 0x195555, 0x8A8 },
+       [ATHOS_LUT_CHAN_664875_IDX] = { 26595, 0x1, 0x6E, 0x1A0000, 0x8A8 },
+       [ATHOS_LUT_CHAN_665000_IDX] = { 26600, 0x1, 0x6E, 0x1AAAAB, 0x8A9 },
+       [ATHOS_LUT_CHAN_665125_IDX] = { 26605, 0x1, 0x6E, 0x1B5555, 0x8A9 },
+       [ATHOS_LUT_CHAN_665250_IDX] = { 26610, 0x1, 0x6E, 0x1C0000, 0x8AA },
+       [ATHOS_LUT_CHAN_665375_IDX] = { 26615, 0x1, 0x6E, 0x1CAAAB, 0x8AA },
+       [ATHOS_LUT_CHAN_665500_IDX] = { 26620, 0x1, 0x6E, 0x1D5555, 0x8AA },
+       [ATHOS_LUT_CHAN_665625_IDX] = { 26625, 0x1, 0x6E, 0x1E0000, 0x8AB },
+       [ATHOS_LUT_CHAN_665750_IDX] = { 26630, 0x1, 0x6E, 0x1EAAAB, 0x8AB },
+       [ATHOS_LUT_CHAN_665875_IDX] = { 26635, 0x1, 0x6E, 0x1F5555, 0x8AC },
+       [ATHOS_LUT_CHAN_666000_IDX] = { 26640, 0x1, 0x6F, 0x0, 0x8AC },
+       [ATHOS_LUT_CHAN_666125_IDX] = { 26645, 0x1, 0x6F, 0xAAAB, 0x8AC },
+       [ATHOS_LUT_CHAN_666250_IDX] = { 26650, 0x1, 0x6F, 0x15555, 0x8AD },
+       [ATHOS_LUT_CHAN_666375_IDX] = { 26655, 0x1, 0x6F, 0x20000, 0x8AD },
+       [ATHOS_LUT_CHAN_666500_IDX] = { 26660, 0x1, 0x6F, 0x2AAAB, 0x8AE },
+       [ATHOS_LUT_CHAN_666625_IDX] = { 26665, 0x1, 0x6F, 0x35555, 0x8AE },
+       [ATHOS_LUT_CHAN_666750_IDX] = { 26670, 0x1, 0x6F, 0x40000, 0x8AF },
+       [ATHOS_LUT_CHAN_666875_IDX] = { 26675, 0x1, 0x6F, 0x4AAAB, 0x8AF },
+       [ATHOS_LUT_CHAN_667000_IDX] = { 26680, 0x1, 0x6F, 0x55555, 0x8AF },
+       [ATHOS_LUT_CHAN_667125_IDX] = { 26685, 0x1, 0x6F, 0x60000, 0x8B0 },
+       [ATHOS_LUT_CHAN_667250_IDX] = { 26690, 0x1, 0x6F, 0x6AAAB, 0x8B0 },
+       [ATHOS_LUT_CHAN_667375_IDX] = { 26695, 0x1, 0x6F, 0x75555, 0x8B1 },
+       [ATHOS_LUT_CHAN_667500_IDX] = { 26700, 0x1, 0x6F, 0x80000, 0x8B1 },
+       [ATHOS_LUT_CHAN_667625_IDX] = { 26705, 0x1, 0x6F, 0x8AAAB, 0x8B1 },
+       [ATHOS_LUT_CHAN_667750_IDX] = { 26710, 0x1, 0x6F, 0x95555, 0x8B2 },
+       [ATHOS_LUT_CHAN_667875_IDX] = { 26715, 0x1, 0x6F, 0xA0000, 0x8B2 },
+       [ATHOS_LUT_CHAN_668000_IDX] = { 26720, 0x1, 0x6F, 0xAAAAB, 0x8B3 },
+       [ATHOS_LUT_CHAN_668125_IDX] = { 26725, 0x1, 0x6F, 0xB5555, 0x8B3 },
+       [ATHOS_LUT_CHAN_668250_IDX] = { 26730, 0x1, 0x6F, 0xC0000, 0x8B4 },
+       [ATHOS_LUT_CHAN_668375_IDX] = { 26735, 0x1, 0x6F, 0xCAAAB, 0x8B4 },
+       [ATHOS_LUT_CHAN_668500_IDX] = { 26740, 0x1, 0x6F, 0xD5555, 0x8B4 },
+       [ATHOS_LUT_CHAN_668625_IDX] = { 26745, 0x1, 0x6F, 0xE0000, 0x8B5 },
+       [ATHOS_LUT_CHAN_668750_IDX] = { 26750, 0x1, 0x6F, 0xEAAAB, 0x8B5 },
+       [ATHOS_LUT_CHAN_668875_IDX] = { 26755, 0x1, 0x6F, 0xF5555, 0x8B6 },
+       [ATHOS_LUT_CHAN_669000_IDX] = { 26760, 0x1, 0x6F, 0x100000, 0x8B6 },
+       [ATHOS_LUT_CHAN_669125_IDX] = { 26765, 0x1, 0x6F, 0x10AAAB, 0x8B6 },
+       [ATHOS_LUT_CHAN_669250_IDX] = { 26770, 0x1, 0x6F, 0x115555, 0x8B7 },
+       [ATHOS_LUT_CHAN_669375_IDX] = { 26775, 0x1, 0x6F, 0x120000, 0x8B7 },
+       [ATHOS_LUT_CHAN_669500_IDX] = { 26780, 0x1, 0x6F, 0x12AAAB, 0x8B8 },
+       [ATHOS_LUT_CHAN_669625_IDX] = { 26785, 0x1, 0x6F, 0x135555, 0x8B8 },
+       [ATHOS_LUT_CHAN_669750_IDX] = { 26790, 0x1, 0x6F, 0x140000, 0x8B9 },
+       [ATHOS_LUT_CHAN_669875_IDX] = { 26795, 0x1, 0x6F, 0x14AAAB, 0x8B9 },
+       [ATHOS_LUT_CHAN_670000_IDX] = { 26800, 0x1, 0x6F, 0x155555, 0x8B9 },
+       [ATHOS_LUT_CHAN_670125_IDX] = { 26805, 0x1, 0x6F, 0x160000, 0x8BA },
+       [ATHOS_LUT_CHAN_670250_IDX] = { 26810, 0x1, 0x6F, 0x16AAAB, 0x8BA },
+       [ATHOS_LUT_CHAN_670375_IDX] = { 26815, 0x1, 0x6F, 0x175555, 0x8BB },
+       [ATHOS_LUT_CHAN_670500_IDX] = { 26820, 0x1, 0x6F, 0x180000, 0x8BB },
+       [ATHOS_LUT_CHAN_670625_IDX] = { 26825, 0x1, 0x6F, 0x18AAAB, 0x8BB },
+       [ATHOS_LUT_CHAN_670750_IDX] = { 26830, 0x1, 0x6F, 0x195555, 0x8BC },
+       [ATHOS_LUT_CHAN_670875_IDX] = { 26835, 0x1, 0x6F, 0x1A0000, 0x8BC },
+       [ATHOS_LUT_CHAN_671000_IDX] = { 26840, 0x1, 0x6F, 0x1AAAAB, 0x8BD },
+       [ATHOS_LUT_CHAN_671125_IDX] = { 26845, 0x1, 0x6F, 0x1B5555, 0x8BD },
+       [ATHOS_LUT_CHAN_671250_IDX] = { 26850, 0x1, 0x6F, 0x1C0000, 0x8BE },
+       [ATHOS_LUT_CHAN_671375_IDX] = { 26855, 0x1, 0x6F, 0x1CAAAB, 0x8BE },
+       [ATHOS_LUT_CHAN_671500_IDX] = { 26860, 0x1, 0x6F, 0x1D5555, 0x8BE },
+       [ATHOS_LUT_CHAN_671625_IDX] = { 26865, 0x1, 0x6F, 0x1E0000, 0x8BF },
+       [ATHOS_LUT_CHAN_671750_IDX] = { 26870, 0x1, 0x6F, 0x1EAAAB, 0x8BF },
+       [ATHOS_LUT_CHAN_671875_IDX] = { 26875, 0x1, 0x6F, 0x1F5555, 0x8C0 },
+       [ATHOS_LUT_CHAN_672000_IDX] = { 26880, 0x1, 0x70, 0x0, 0x8C0 },
+       [ATHOS_LUT_CHAN_672125_IDX] = { 26885, 0x1, 0x70, 0xAAAB, 0x8C0 },
+       [ATHOS_LUT_CHAN_672250_IDX] = { 26890, 0x1, 0x70, 0x15555, 0x8C1 },
+       [ATHOS_LUT_CHAN_672375_IDX] = { 26895, 0x1, 0x70, 0x20000, 0x8C1 },
+       [ATHOS_LUT_CHAN_672500_IDX] = { 26900, 0x1, 0x70, 0x2AAAB, 0x8C2 },
+       [ATHOS_LUT_CHAN_672625_IDX] = { 26905, 0x1, 0x70, 0x35555, 0x8C2 },
+       [ATHOS_LUT_CHAN_672750_IDX] = { 26910, 0x1, 0x70, 0x40000, 0x8C3 },
+       [ATHOS_LUT_CHAN_672875_IDX] = { 26915, 0x1, 0x70, 0x4AAAB, 0x8C3 },
+       [ATHOS_LUT_CHAN_673000_IDX] = { 26920, 0x1, 0x70, 0x55555, 0x8C3 },
+       [ATHOS_LUT_CHAN_673125_IDX] = { 26925, 0x1, 0x70, 0x60000, 0x8C4 },
+       [ATHOS_LUT_CHAN_673250_IDX] = { 26930, 0x1, 0x70, 0x6AAAB, 0x8C4 },
+       [ATHOS_LUT_CHAN_673375_IDX] = { 26935, 0x1, 0x70, 0x75555, 0x8C5 },
+       [ATHOS_LUT_CHAN_673500_IDX] = { 26940, 0x1, 0x70, 0x80000, 0x8C5 },
+       [ATHOS_LUT_CHAN_673625_IDX] = { 26945, 0x1, 0x70, 0x8AAAB, 0x8C5 },
+       [ATHOS_LUT_CHAN_673750_IDX] = { 26950, 0x1, 0x70, 0x95555, 0x8C6 },
+       [ATHOS_LUT_CHAN_673875_IDX] = { 26955, 0x1, 0x70, 0xA0000, 0x8C6 },
+       [ATHOS_LUT_CHAN_674000_IDX] = { 26960, 0x1, 0x70, 0xAAAAB, 0x8C7 },
+       [ATHOS_LUT_CHAN_674125_IDX] = { 26965, 0x1, 0x70, 0xB5555, 0x8C7 },
+       [ATHOS_LUT_CHAN_674250_IDX] = { 26970, 0x1, 0x70, 0xC0000, 0x8C8 },
+       [ATHOS_LUT_CHAN_674375_IDX] = { 26975, 0x1, 0x70, 0xCAAAB, 0x8C8 },
+       [ATHOS_LUT_CHAN_674500_IDX] = { 26980, 0x1, 0x70, 0xD5555, 0x8C8 },
+       [ATHOS_LUT_CHAN_674625_IDX] = { 26985, 0x1, 0x70, 0xE0000, 0x8C9 },
+       [ATHOS_LUT_CHAN_674750_IDX] = { 26990, 0x1, 0x70, 0xEAAAB, 0x8C9 },
+       [ATHOS_LUT_CHAN_674875_IDX] = { 26995, 0x1, 0x70, 0xF5555, 0x8CA },
+       [ATHOS_LUT_CHAN_675000_IDX] = { 27000, 0x1, 0x70, 0x100000, 0x8CA },
+       [ATHOS_LUT_CHAN_675125_IDX] = { 27005, 0x1, 0x70, 0x10AAAB, 0x8CA },
+       [ATHOS_LUT_CHAN_675250_IDX] = { 27010, 0x1, 0x70, 0x115555, 0x8CB },
+       [ATHOS_LUT_CHAN_675375_IDX] = { 27015, 0x1, 0x70, 0x120000, 0x8CB },
+       [ATHOS_LUT_CHAN_675500_IDX] = { 27020, 0x1, 0x70, 0x12AAAB, 0x8CC },
+       [ATHOS_LUT_CHAN_675625_IDX] = { 27025, 0x1, 0x70, 0x135555, 0x8CC },
+       [ATHOS_LUT_CHAN_675750_IDX] = { 27030, 0x1, 0x70, 0x140000, 0x8CD },
+       [ATHOS_LUT_CHAN_675875_IDX] = { 27035, 0x1, 0x70, 0x14AAAB, 0x8CD },
+       [ATHOS_LUT_CHAN_676000_IDX] = { 27040, 0x1, 0x70, 0x155555, 0x8CD },
+       [ATHOS_LUT_CHAN_676125_IDX] = { 27045, 0x1, 0x70, 0x160000, 0x8CE },
+       [ATHOS_LUT_CHAN_676250_IDX] = { 27050, 0x1, 0x70, 0x16AAAB, 0x8CE },
+       [ATHOS_LUT_CHAN_676375_IDX] = { 27055, 0x1, 0x70, 0x175555, 0x8CF },
+       [ATHOS_LUT_CHAN_676500_IDX] = { 27060, 0x1, 0x70, 0x180000, 0x8CF },
+       [ATHOS_LUT_CHAN_676625_IDX] = { 27065, 0x1, 0x70, 0x18AAAB, 0x8CF },
+       [ATHOS_LUT_CHAN_676750_IDX] = { 27070, 0x1, 0x70, 0x195555, 0x8D0 },
+       [ATHOS_LUT_CHAN_676875_IDX] = { 27075, 0x1, 0x70, 0x1A0000, 0x8D0 },
+       [ATHOS_LUT_CHAN_677000_IDX] = { 27080, 0x1, 0x70, 0x1AAAAB, 0x8D1 },
+       [ATHOS_LUT_CHAN_677125_IDX] = { 27085, 0x1, 0x70, 0x1B5555, 0x8D1 },
+       [ATHOS_LUT_CHAN_677250_IDX] = { 27090, 0x1, 0x70, 0x1C0000, 0x8D2 },
+       [ATHOS_LUT_CHAN_677375_IDX] = { 27095, 0x1, 0x70, 0x1CAAAB, 0x8D2 },
+       [ATHOS_LUT_CHAN_677500_IDX] = { 27100, 0x1, 0x70, 0x1D5555, 0x8D2 },
+       [ATHOS_LUT_CHAN_677625_IDX] = { 27105, 0x1, 0x70, 0x1E0000, 0x8D3 },
+       [ATHOS_LUT_CHAN_677750_IDX] = { 27110, 0x1, 0x70, 0x1EAAAB, 0x8D3 },
+       [ATHOS_LUT_CHAN_677875_IDX] = { 27115, 0x1, 0x70, 0x1F5555, 0x8D4 },
+       [ATHOS_LUT_CHAN_678000_IDX] = { 27120, 0x1, 0x71, 0x0, 0x8D4 },
+       [ATHOS_LUT_CHAN_678125_IDX] = { 27125, 0x1, 0x71, 0xAAAB, 0x8D4 },
+       [ATHOS_LUT_CHAN_678250_IDX] = { 27130, 0x1, 0x71, 0x15555, 0x8D5 },
+       [ATHOS_LUT_CHAN_678375_IDX] = { 27135, 0x1, 0x71, 0x20000, 0x8D5 },
+       [ATHOS_LUT_CHAN_678500_IDX] = { 27140, 0x1, 0x71, 0x2AAAB, 0x8D6 },
+       [ATHOS_LUT_CHAN_678625_IDX] = { 27145, 0x1, 0x71, 0x35555, 0x8D6 },
+       [ATHOS_LUT_CHAN_678750_IDX] = { 27150, 0x1, 0x71, 0x40000, 0x8D7 },
+       [ATHOS_LUT_CHAN_678875_IDX] = { 27155, 0x1, 0x71, 0x4AAAB, 0x8D7 },
+       [ATHOS_LUT_CHAN_679000_IDX] = { 27160, 0x1, 0x71, 0x55555, 0x8D7 },
+       [ATHOS_LUT_CHAN_679125_IDX] = { 27165, 0x1, 0x71, 0x60000, 0x8D8 },
+       [ATHOS_LUT_CHAN_679250_IDX] = { 27170, 0x1, 0x71, 0x6AAAB, 0x8D8 },
+       [ATHOS_LUT_CHAN_679375_IDX] = { 27175, 0x1, 0x71, 0x75555, 0x8D9 },
+       [ATHOS_LUT_CHAN_679500_IDX] = { 27180, 0x1, 0x71, 0x80000, 0x8D9 },
+       [ATHOS_LUT_CHAN_679625_IDX] = { 27185, 0x1, 0x71, 0x8AAAB, 0x8D9 },
+       [ATHOS_LUT_CHAN_679750_IDX] = { 27190, 0x1, 0x71, 0x95555, 0x8DA },
+       [ATHOS_LUT_CHAN_679875_IDX] = { 27195, 0x1, 0x71, 0xA0000, 0x8DA },
+       [ATHOS_LUT_CHAN_680000_IDX] = { 27200, 0x1, 0x71, 0xAAAAB, 0x8DB },
+       [ATHOS_LUT_CHAN_680125_IDX] = { 27205, 0x1, 0x71, 0xB5555, 0x8DB },
+       [ATHOS_LUT_CHAN_680250_IDX] = { 27210, 0x1, 0x71, 0xC0000, 0x8DC },
+       [ATHOS_LUT_CHAN_680375_IDX] = { 27215, 0x1, 0x71, 0xCAAAB, 0x8DC },
+       [ATHOS_LUT_CHAN_680500_IDX] = { 27220, 0x1, 0x71, 0xD5555, 0x8DC },
+       [ATHOS_LUT_CHAN_680625_IDX] = { 27225, 0x1, 0x71, 0xE0000, 0x8DD },
+       [ATHOS_LUT_CHAN_680750_IDX] = { 27230, 0x1, 0x71, 0xEAAAB, 0x8DD },
+       [ATHOS_LUT_CHAN_680875_IDX] = { 27235, 0x1, 0x71, 0xF5555, 0x8DE },
+       [ATHOS_LUT_CHAN_681000_IDX] = { 27240, 0x1, 0x71, 0x100000, 0x8DE },
+       [ATHOS_LUT_CHAN_681125_IDX] = { 27245, 0x1, 0x71, 0x10AAAB, 0x8DE },
+       [ATHOS_LUT_CHAN_681250_IDX] = { 27250, 0x1, 0x71, 0x115555, 0x8DF },
+       [ATHOS_LUT_CHAN_681375_IDX] = { 27255, 0x1, 0x71, 0x120000, 0x8DF },
+       [ATHOS_LUT_CHAN_681500_IDX] = { 27260, 0x1, 0x71, 0x12AAAB, 0x8E0 },
+       [ATHOS_LUT_CHAN_681625_IDX] = { 27265, 0x1, 0x71, 0x135555, 0x8E0 },
+       [ATHOS_LUT_CHAN_681750_IDX] = { 27270, 0x1, 0x71, 0x140000, 0x8E1 },
+       [ATHOS_LUT_CHAN_681875_IDX] = { 27275, 0x1, 0x71, 0x14AAAB, 0x8E1 },
+       [ATHOS_LUT_CHAN_682000_IDX] = { 27280, 0x1, 0x71, 0x155555, 0x8E1 },
+       [ATHOS_LUT_CHAN_682125_IDX] = { 27285, 0x1, 0x71, 0x160000, 0x8E2 },
+       [ATHOS_LUT_CHAN_682250_IDX] = { 27290, 0x1, 0x71, 0x16AAAB, 0x8E2 },
+       [ATHOS_LUT_CHAN_682375_IDX] = { 27295, 0x1, 0x71, 0x175555, 0x8E3 },
+       [ATHOS_LUT_CHAN_682500_IDX] = { 27300, 0x1, 0x71, 0x180000, 0x8E3 },
+       [ATHOS_LUT_CHAN_682625_IDX] = { 27305, 0x1, 0x71, 0x18AAAB, 0x8E3 },
+       [ATHOS_LUT_CHAN_682750_IDX] = { 27310, 0x1, 0x71, 0x195555, 0x8E4 },
+       [ATHOS_LUT_CHAN_682875_IDX] = { 27315, 0x1, 0x71, 0x1A0000, 0x8E4 },
+       [ATHOS_LUT_CHAN_683000_IDX] = { 27320, 0x1, 0x71, 0x1AAAAB, 0x8E5 },
+       [ATHOS_LUT_CHAN_683125_IDX] = { 27325, 0x1, 0x71, 0x1B5555, 0x8E5 },
+       [ATHOS_LUT_CHAN_683250_IDX] = { 27330, 0x1, 0x71, 0x1C0000, 0x8E6 },
+       [ATHOS_LUT_CHAN_683375_IDX] = { 27335, 0x1, 0x71, 0x1CAAAB, 0x8E6 },
+       [ATHOS_LUT_CHAN_683500_IDX] = { 27340, 0x1, 0x71, 0x1D5555, 0x8E6 },
+       [ATHOS_LUT_CHAN_683625_IDX] = { 27345, 0x1, 0x71, 0x1E0000, 0x8E7 },
+       [ATHOS_LUT_CHAN_683750_IDX] = { 27350, 0x1, 0x71, 0x1EAAAB, 0x8E7 },
+       [ATHOS_LUT_CHAN_683875_IDX] = { 27355, 0x1, 0x71, 0x1F5555, 0x8E8 },
+       [ATHOS_LUT_CHAN_684000_IDX] = { 27360, 0x1, 0x72, 0x0, 0x8E8 },
+       [ATHOS_LUT_CHAN_684125_IDX] = { 27365, 0x1, 0x72, 0xAAAB, 0x8E8 },
+       [ATHOS_LUT_CHAN_684250_IDX] = { 27370, 0x1, 0x72, 0x15555, 0x8E9 },
+       [ATHOS_LUT_CHAN_684375_IDX] = { 27375, 0x1, 0x72, 0x20000, 0x8E9 },
+       [ATHOS_LUT_CHAN_684500_IDX] = { 27380, 0x1, 0x72, 0x2AAAB, 0x8EA },
+       [ATHOS_LUT_CHAN_684625_IDX] = { 27385, 0x1, 0x72, 0x35555, 0x8EA },
+       [ATHOS_LUT_CHAN_684750_IDX] = { 27390, 0x1, 0x72, 0x40000, 0x8EB },
+       [ATHOS_LUT_CHAN_684875_IDX] = { 27395, 0x1, 0x72, 0x4AAAB, 0x8EB },
+       [ATHOS_LUT_CHAN_685000_IDX] = { 27400, 0x1, 0x72, 0x55555, 0x8EB },
+       [ATHOS_LUT_CHAN_685125_IDX] = { 27405, 0x1, 0x72, 0x60000, 0x8EC },
+       [ATHOS_LUT_CHAN_685250_IDX] = { 27410, 0x1, 0x72, 0x6AAAB, 0x8EC },
+       [ATHOS_LUT_CHAN_685375_IDX] = { 27415, 0x1, 0x72, 0x75555, 0x8ED },
+       [ATHOS_LUT_CHAN_685500_IDX] = { 27420, 0x1, 0x72, 0x80000, 0x8ED },
+       [ATHOS_LUT_CHAN_685625_IDX] = { 27425, 0x1, 0x72, 0x8AAAB, 0x8ED },
+       [ATHOS_LUT_CHAN_685750_IDX] = { 27430, 0x1, 0x72, 0x95555, 0x8EE },
+       [ATHOS_LUT_CHAN_685875_IDX] = { 27435, 0x1, 0x72, 0xA0000, 0x8EE },
+       [ATHOS_LUT_CHAN_686000_IDX] = { 27440, 0x1, 0x72, 0xAAAAB, 0x8EF },
+       [ATHOS_LUT_CHAN_686125_IDX] = { 27445, 0x1, 0x72, 0xB5555, 0x8EF },
+       [ATHOS_LUT_CHAN_686250_IDX] = { 27450, 0x1, 0x72, 0xC0000, 0x8F0 },
+       [ATHOS_LUT_CHAN_686375_IDX] = { 27455, 0x1, 0x72, 0xCAAAB, 0x8F0 },
+       [ATHOS_LUT_CHAN_686500_IDX] = { 27460, 0x1, 0x72, 0xD5555, 0x8F0 },
+       [ATHOS_LUT_CHAN_686625_IDX] = { 27465, 0x1, 0x72, 0xE0000, 0x8F1 },
+       [ATHOS_LUT_CHAN_686750_IDX] = { 27470, 0x1, 0x72, 0xEAAAB, 0x8F1 },
+       [ATHOS_LUT_CHAN_686875_IDX] = { 27475, 0x1, 0x72, 0xF5555, 0x8F2 },
+       [ATHOS_LUT_CHAN_687000_IDX] = { 27480, 0x1, 0x72, 0x100000, 0x8F2 },
+       [ATHOS_LUT_CHAN_687125_IDX] = { 27485, 0x1, 0x72, 0x10AAAB, 0x8F2 },
+       [ATHOS_LUT_CHAN_687250_IDX] = { 27490, 0x1, 0x72, 0x115555, 0x8F3 },
+       [ATHOS_LUT_CHAN_687375_IDX] = { 27495, 0x1, 0x72, 0x120000, 0x8F3 },
+       [ATHOS_LUT_CHAN_687500_IDX] = { 27500, 0x1, 0x72, 0x12AAAB, 0x8F4 },
+       [ATHOS_LUT_CHAN_687625_IDX] = { 27505, 0x1, 0x72, 0x135555, 0x8F4 },
+       [ATHOS_LUT_CHAN_687750_IDX] = { 27510, 0x1, 0x72, 0x140000, 0x8F5 },
+       [ATHOS_LUT_CHAN_687875_IDX] = { 27515, 0x1, 0x72, 0x14AAAB, 0x8F5 },
+       [ATHOS_LUT_CHAN_688000_IDX] = { 27520, 0x1, 0x72, 0x155555, 0x8F5 },
+       [ATHOS_LUT_CHAN_688125_IDX] = { 27525, 0x1, 0x72, 0x160000, 0x8F6 },
+       [ATHOS_LUT_CHAN_688250_IDX] = { 27530, 0x1, 0x72, 0x16AAAB, 0x8F6 },
+       [ATHOS_LUT_CHAN_688375_IDX] = { 27535, 0x1, 0x72, 0x175555, 0x8F7 },
+       [ATHOS_LUT_CHAN_688500_IDX] = { 27540, 0x1, 0x72, 0x180000, 0x8F7 },
+       [ATHOS_LUT_CHAN_688625_IDX] = { 27545, 0x1, 0x72, 0x18AAAB, 0x8F7 },
+       [ATHOS_LUT_CHAN_688750_IDX] = { 27550, 0x1, 0x72, 0x195555, 0x8F8 },
+       [ATHOS_LUT_CHAN_688875_IDX] = { 27555, 0x1, 0x72, 0x1A0000, 0x8F8 },
+       [ATHOS_LUT_CHAN_689000_IDX] = { 27560, 0x1, 0x72, 0x1AAAAB, 0x8F9 },
+       [ATHOS_LUT_CHAN_689125_IDX] = { 27565, 0x1, 0x72, 0x1B5555, 0x8F9 },
+       [ATHOS_LUT_CHAN_689250_IDX] = { 27570, 0x1, 0x72, 0x1C0000, 0x8FA },
+       [ATHOS_LUT_CHAN_689375_IDX] = { 27575, 0x1, 0x72, 0x1CAAAB, 0x8FA },
+       [ATHOS_LUT_CHAN_689500_IDX] = { 27580, 0x1, 0x72, 0x1D5555, 0x8FA },
+       [ATHOS_LUT_CHAN_689625_IDX] = { 27585, 0x1, 0x72, 0x1E0000, 0x8FB },
+       [ATHOS_LUT_CHAN_689750_IDX] = { 27590, 0x1, 0x72, 0x1EAAAB, 0x8FB },
+       [ATHOS_LUT_CHAN_689875_IDX] = { 27595, 0x1, 0x72, 0x1F5555, 0x8FC },
+       [ATHOS_LUT_CHAN_690000_IDX] = { 27600, 0x1, 0x73, 0x0, 0x8FC },
+       [ATHOS_LUT_CHAN_690125_IDX] = { 27605, 0x1, 0x73, 0xAAAB, 0x8FC },
+       [ATHOS_LUT_CHAN_690250_IDX] = { 27610, 0x1, 0x73, 0x15555, 0x8FD },
+       [ATHOS_LUT_CHAN_690375_IDX] = { 27615, 0x1, 0x73, 0x20000, 0x8FD },
+       [ATHOS_LUT_CHAN_690500_IDX] = { 27620, 0x1, 0x73, 0x2AAAB, 0x8FE },
+       [ATHOS_LUT_CHAN_690625_IDX] = { 27625, 0x1, 0x73, 0x35555, 0x8FE },
+       [ATHOS_LUT_CHAN_690750_IDX] = { 27630, 0x1, 0x73, 0x40000, 0x8FF },
+       [ATHOS_LUT_CHAN_690875_IDX] = { 27635, 0x1, 0x73, 0x4AAAB, 0x8FF },
+       [ATHOS_LUT_CHAN_691000_IDX] = { 27640, 0x1, 0x73, 0x55555, 0x8FF },
+       [ATHOS_LUT_CHAN_691125_IDX] = { 27645, 0x1, 0x73, 0x60000, 0x900 },
+       [ATHOS_LUT_CHAN_691250_IDX] = { 27650, 0x1, 0x73, 0x6AAAB, 0x900 },
+       [ATHOS_LUT_CHAN_691375_IDX] = { 27655, 0x1, 0x73, 0x75555, 0x901 },
+       [ATHOS_LUT_CHAN_691500_IDX] = { 27660, 0x1, 0x73, 0x80000, 0x901 },
+       [ATHOS_LUT_CHAN_691625_IDX] = { 27665, 0x1, 0x73, 0x8AAAB, 0x901 },
+       [ATHOS_LUT_CHAN_691750_IDX] = { 27670, 0x1, 0x73, 0x95555, 0x902 },
+       [ATHOS_LUT_CHAN_691875_IDX] = { 27675, 0x1, 0x73, 0xA0000, 0x902 },
+       [ATHOS_LUT_CHAN_692000_IDX] = { 27680, 0x1, 0x73, 0xAAAAB, 0x903 },
+       [ATHOS_LUT_CHAN_692125_IDX] = { 27685, 0x1, 0x73, 0xB5555, 0x903 },
+       [ATHOS_LUT_CHAN_692250_IDX] = { 27690, 0x1, 0x73, 0xC0000, 0x904 },
+       [ATHOS_LUT_CHAN_692375_IDX] = { 27695, 0x1, 0x73, 0xCAAAB, 0x904 },
+       [ATHOS_LUT_CHAN_692500_IDX] = { 27700, 0x1, 0x73, 0xD5555, 0x904 },
+       [ATHOS_LUT_CHAN_692625_IDX] = { 27705, 0x1, 0x73, 0xE0000, 0x905 },
+       [ATHOS_LUT_CHAN_692750_IDX] = { 27710, 0x1, 0x73, 0xEAAAB, 0x905 },
+       [ATHOS_LUT_CHAN_692875_IDX] = { 27715, 0x1, 0x73, 0xF5555, 0x906 },
+       [ATHOS_LUT_CHAN_693000_IDX] = { 27720, 0x1, 0x73, 0x100000, 0x906 },
+       [ATHOS_LUT_CHAN_693125_IDX] = { 27725, 0x1, 0x73, 0x10AAAB, 0x906 },
+       [ATHOS_LUT_CHAN_693250_IDX] = { 27730, 0x1, 0x73, 0x115555, 0x907 },
+       [ATHOS_LUT_CHAN_693375_IDX] = { 27735, 0x1, 0x73, 0x120000, 0x907 },
+       [ATHOS_LUT_CHAN_693500_IDX] = { 27740, 0x1, 0x73, 0x12AAAB, 0x908 },
+       [ATHOS_LUT_CHAN_693625_IDX] = { 27745, 0x1, 0x73, 0x135555, 0x908 },
+       [ATHOS_LUT_CHAN_693750_IDX] = { 27750, 0x1, 0x73, 0x140000, 0x909 },
+       [ATHOS_LUT_CHAN_693875_IDX] = { 27755, 0x1, 0x73, 0x14AAAB, 0x909 },
+       [ATHOS_LUT_CHAN_694000_IDX] = { 27760, 0x1, 0x73, 0x155555, 0x909 },
+       [ATHOS_LUT_CHAN_694125_IDX] = { 27765, 0x1, 0x73, 0x160000, 0x90A },
+       [ATHOS_LUT_CHAN_694250_IDX] = { 27770, 0x1, 0x73, 0x16AAAB, 0x90A },
+       [ATHOS_LUT_CHAN_694375_IDX] = { 27775, 0x1, 0x73, 0x175555, 0x90B },
+       [ATHOS_LUT_CHAN_694500_IDX] = { 27780, 0x1, 0x73, 0x180000, 0x90B },
+       [ATHOS_LUT_CHAN_694625_IDX] = { 27785, 0x1, 0x73, 0x18AAAB, 0x90B },
+       [ATHOS_LUT_CHAN_694750_IDX] = { 27790, 0x1, 0x73, 0x195555, 0x90C },
+       [ATHOS_LUT_CHAN_694875_IDX] = { 27795, 0x1, 0x73, 0x1A0000, 0x90C },
+       [ATHOS_LUT_CHAN_695000_IDX] = { 27800, 0x1, 0x73, 0x1AAAAB, 0x90D },
+       [ATHOS_LUT_CHAN_695125_IDX] = { 27805, 0x1, 0x73, 0x1B5555, 0x90D },
+       [ATHOS_LUT_CHAN_695250_IDX] = { 27810, 0x1, 0x73, 0x1C0000, 0x90E },
+       [ATHOS_LUT_CHAN_695375_IDX] = { 27815, 0x1, 0x73, 0x1CAAAB, 0x90E },
+       [ATHOS_LUT_CHAN_695500_IDX] = { 27820, 0x1, 0x73, 0x1D5555, 0x90E },
+       [ATHOS_LUT_CHAN_695625_IDX] = { 27825, 0x1, 0x73, 0x1E0000, 0x90F },
+       [ATHOS_LUT_CHAN_695750_IDX] = { 27830, 0x1, 0x73, 0x1EAAAB, 0x90F },
+       [ATHOS_LUT_CHAN_695875_IDX] = { 27835, 0x1, 0x73, 0x1F5555, 0x910 },
+       [ATHOS_LUT_CHAN_696000_IDX] = { 27840, 0x1, 0x74, 0x0, 0x910 },
+       [ATHOS_LUT_CHAN_696125_IDX] = { 27845, 0x1, 0x74, 0xAAAB, 0x910 },
+       [ATHOS_LUT_CHAN_696250_IDX] = { 27850, 0x1, 0x74, 0x15555, 0x911 },
+       [ATHOS_LUT_CHAN_696375_IDX] = { 27855, 0x1, 0x74, 0x20000, 0x911 },
+       [ATHOS_LUT_CHAN_696500_IDX] = { 27860, 0x1, 0x74, 0x2AAAB, 0x912 },
+       [ATHOS_LUT_CHAN_696625_IDX] = { 27865, 0x1, 0x74, 0x35555, 0x912 },
+       [ATHOS_LUT_CHAN_696750_IDX] = { 27870, 0x1, 0x74, 0x40000, 0x913 },
+       [ATHOS_LUT_CHAN_696875_IDX] = { 27875, 0x1, 0x74, 0x4AAAB, 0x913 },
+       [ATHOS_LUT_CHAN_697000_IDX] = { 27880, 0x1, 0x74, 0x55555, 0x913 },
+       [ATHOS_LUT_CHAN_697125_IDX] = { 27885, 0x1, 0x74, 0x60000, 0x914 },
+       [ATHOS_LUT_CHAN_697250_IDX] = { 27890, 0x1, 0x74, 0x6AAAB, 0x914 },
+       [ATHOS_LUT_CHAN_697375_IDX] = { 27895, 0x1, 0x74, 0x75555, 0x915 },
+       [ATHOS_LUT_CHAN_697500_IDX] = { 27900, 0x1, 0x74, 0x80000, 0x915 },
+       [ATHOS_LUT_CHAN_697625_IDX] = { 27905, 0x1, 0x74, 0x8AAAB, 0x915 },
+       [ATHOS_LUT_CHAN_697750_IDX] = { 27910, 0x1, 0x74, 0x95555, 0x916 },
+       [ATHOS_LUT_CHAN_697875_IDX] = { 27915, 0x1, 0x74, 0xA0000, 0x916 },
+       [ATHOS_LUT_CHAN_698000_IDX] = { 27920, 0x1, 0x74, 0xAAAAB, 0x917 },
+       [ATHOS_LUT_CHAN_698125_IDX] = { 27925, 0x1, 0x74, 0xB5555, 0x917 },
+       [ATHOS_LUT_CHAN_698250_IDX] = { 27930, 0x1, 0x74, 0xC0000, 0x918 },
+       [ATHOS_LUT_CHAN_698375_IDX] = { 27935, 0x1, 0x74, 0xCAAAB, 0x918 },
+       [ATHOS_LUT_CHAN_698500_IDX] = { 27940, 0x1, 0x74, 0xD5555, 0x918 },
+       [ATHOS_LUT_CHAN_698625_IDX] = { 27945, 0x1, 0x74, 0xE0000, 0x919 },
+       [ATHOS_LUT_CHAN_698750_IDX] = { 27950, 0x1, 0x74, 0xEAAAB, 0x919 },
+       [ATHOS_LUT_CHAN_698875_IDX] = { 27955, 0x1, 0x74, 0xF5555, 0x91A },
+       [ATHOS_LUT_CHAN_699000_IDX] = { 27960, 0x1, 0x74, 0x100000, 0x91A },
+       [ATHOS_LUT_CHAN_699125_IDX] = { 27965, 0x1, 0x74, 0x10AAAB, 0x91A },
+       [ATHOS_LUT_CHAN_699250_IDX] = { 27970, 0x1, 0x74, 0x115555, 0x91B },
+       [ATHOS_LUT_CHAN_699375_IDX] = { 27975, 0x1, 0x74, 0x120000, 0x91B },
+       [ATHOS_LUT_CHAN_699500_IDX] = { 27980, 0x1, 0x74, 0x12AAAB, 0x91C },
+       [ATHOS_LUT_CHAN_699625_IDX] = { 27985, 0x1, 0x74, 0x135555, 0x91C },
+       [ATHOS_LUT_CHAN_699750_IDX] = { 27990, 0x1, 0x74, 0x140000, 0x91D },
+       [ATHOS_LUT_CHAN_699875_IDX] = { 27995, 0x1, 0x74, 0x14AAAB, 0x91D },
+       [ATHOS_LUT_CHAN_700000_IDX] = { 28000, 0x1, 0x74, 0x155555, 0x91D },
+       [ATHOS_LUT_CHAN_700125_IDX] = { 28005, 0x1, 0x74, 0x160000, 0x91E },
+       [ATHOS_LUT_CHAN_700250_IDX] = { 28010, 0x1, 0x74, 0x16AAAB, 0x91E },
+       [ATHOS_LUT_CHAN_700375_IDX] = { 28015, 0x1, 0x74, 0x175555, 0x91F },
+       [ATHOS_LUT_CHAN_700500_IDX] = { 28020, 0x1, 0x74, 0x180000, 0x91F },
+       [ATHOS_LUT_CHAN_700625_IDX] = { 28025, 0x1, 0x74, 0x18AAAB, 0x91F },
+       [ATHOS_LUT_CHAN_700750_IDX] = { 28030, 0x1, 0x74, 0x195555, 0x920 },
+       [ATHOS_LUT_CHAN_700875_IDX] = { 28035, 0x1, 0x74, 0x1A0000, 0x920 },
+       [ATHOS_LUT_CHAN_701000_IDX] = { 28040, 0x1, 0x74, 0x1AAAAB, 0x921 },
+       [ATHOS_LUT_CHAN_701125_IDX] = { 28045, 0x1, 0x74, 0x1B5555, 0x921 },
+       [ATHOS_LUT_CHAN_701250_IDX] = { 28050, 0x1, 0x74, 0x1C0000, 0x922 },
+       [ATHOS_LUT_CHAN_701375_IDX] = { 28055, 0x1, 0x74, 0x1CAAAB, 0x922 },
+       [ATHOS_LUT_CHAN_701500_IDX] = { 28060, 0x1, 0x74, 0x1D5555, 0x922 },
+       [ATHOS_LUT_CHAN_701625_IDX] = { 28065, 0x1, 0x74, 0x1E0000, 0x923 },
+       [ATHOS_LUT_CHAN_701750_IDX] = { 28070, 0x1, 0x74, 0x1EAAAB, 0x923 },
+       [ATHOS_LUT_CHAN_701875_IDX] = { 28075, 0x1, 0x74, 0x1F5555, 0x924 },
+       [ATHOS_LUT_CHAN_702000_IDX] = { 28080, 0x1, 0x75, 0x0, 0x924 },
+       [ATHOS_LUT_CHAN_702125_IDX] = { 28085, 0x1, 0x75, 0xAAAB, 0x924 },
+       [ATHOS_LUT_CHAN_702250_IDX] = { 28090, 0x1, 0x75, 0x15555, 0x925 },
+       [ATHOS_LUT_CHAN_702375_IDX] = { 28095, 0x1, 0x75, 0x20000, 0x925 },
+       [ATHOS_LUT_CHAN_702500_IDX] = { 28100, 0x1, 0x75, 0x2AAAB, 0x926 },
+       [ATHOS_LUT_CHAN_702625_IDX] = { 28105, 0x1, 0x75, 0x35555, 0x926 },
+       [ATHOS_LUT_CHAN_702750_IDX] = { 28110, 0x1, 0x75, 0x40000, 0x927 },
+       [ATHOS_LUT_CHAN_702875_IDX] = { 28115, 0x1, 0x75, 0x4AAAB, 0x927 },
+       [ATHOS_LUT_CHAN_703000_IDX] = { 28120, 0x1, 0x75, 0x55555, 0x927 },
+       [ATHOS_LUT_CHAN_703125_IDX] = { 28125, 0x1, 0x75, 0x60000, 0x928 },
+       [ATHOS_LUT_CHAN_703250_IDX] = { 28130, 0x1, 0x75, 0x6AAAB, 0x928 },
+       [ATHOS_LUT_CHAN_703375_IDX] = { 28135, 0x1, 0x75, 0x75555, 0x929 },
+       [ATHOS_LUT_CHAN_703500_IDX] = { 28140, 0x1, 0x75, 0x80000, 0x929 },
+       [ATHOS_LUT_CHAN_703625_IDX] = { 28145, 0x1, 0x75, 0x8AAAB, 0x929 },
+       [ATHOS_LUT_CHAN_703750_IDX] = { 28150, 0x1, 0x75, 0x95555, 0x92A },
+       [ATHOS_LUT_CHAN_703875_IDX] = { 28155, 0x1, 0x75, 0xA0000, 0x92A },
+       [ATHOS_LUT_CHAN_704000_IDX] = { 28160, 0x1, 0x75, 0xAAAAB, 0x92B },
+       [ATHOS_LUT_CHAN_704125_IDX] = { 28165, 0x1, 0x75, 0xB5555, 0x92B },
+       [ATHOS_LUT_CHAN_704250_IDX] = { 28170, 0x1, 0x75, 0xC0000, 0x92C },
+       [ATHOS_LUT_CHAN_704375_IDX] = { 28175, 0x1, 0x75, 0xCAAAB, 0x92C },
+       [ATHOS_LUT_CHAN_704500_IDX] = { 28180, 0x1, 0x75, 0xD5555, 0x92C },
+       [ATHOS_LUT_CHAN_704625_IDX] = { 28185, 0x1, 0x75, 0xE0000, 0x92D },
+       [ATHOS_LUT_CHAN_704750_IDX] = { 28190, 0x1, 0x75, 0xEAAAB, 0x92D },
+       [ATHOS_LUT_CHAN_704875_IDX] = { 28195, 0x1, 0x75, 0xF5555, 0x92E },
+       [ATHOS_LUT_CHAN_705000_IDX] = { 28200, 0x1, 0x75, 0x100000, 0x92E },
+       [ATHOS_LUT_CHAN_705125_IDX] = { 28205, 0x1, 0x75, 0x10AAAB, 0x92E },
+       [ATHOS_LUT_CHAN_705250_IDX] = { 28210, 0x1, 0x75, 0x115555, 0x92F },
+       [ATHOS_LUT_CHAN_705375_IDX] = { 28215, 0x1, 0x75, 0x120000, 0x92F },
+       [ATHOS_LUT_CHAN_705500_IDX] = { 28220, 0x1, 0x75, 0x12AAAB, 0x930 },
+       [ATHOS_LUT_CHAN_705625_IDX] = { 28225, 0x1, 0x75, 0x135555, 0x930 },
+       [ATHOS_LUT_CHAN_705750_IDX] = { 28230, 0x1, 0x75, 0x140000, 0x931 },
+       [ATHOS_LUT_CHAN_705875_IDX] = { 28235, 0x1, 0x75, 0x14AAAB, 0x931 },
+       [ATHOS_LUT_CHAN_706000_IDX] = { 28240, 0x1, 0x75, 0x155555, 0x931 },
+       [ATHOS_LUT_CHAN_706125_IDX] = { 28245, 0x1, 0x75, 0x160000, 0x932 },
+       [ATHOS_LUT_CHAN_706250_IDX] = { 28250, 0x1, 0x75, 0x16AAAB, 0x932 },
+       [ATHOS_LUT_CHAN_706375_IDX] = { 28255, 0x1, 0x75, 0x175555, 0x933 },
+       [ATHOS_LUT_CHAN_706500_IDX] = { 28260, 0x1, 0x75, 0x180000, 0x933 },
+       [ATHOS_LUT_CHAN_706625_IDX] = { 28265, 0x1, 0x75, 0x18AAAB, 0x933 },
+       [ATHOS_LUT_CHAN_706750_IDX] = { 28270, 0x1, 0x75, 0x195555, 0x934 },
+       [ATHOS_LUT_CHAN_706875_IDX] = { 28275, 0x1, 0x75, 0x1A0000, 0x934 },
+       [ATHOS_LUT_CHAN_707000_IDX] = { 28280, 0x1, 0x75, 0x1AAAAB, 0x935 },
+       [ATHOS_LUT_CHAN_707125_IDX] = { 28285, 0x1, 0x75, 0x1B5555, 0x935 },
+       [ATHOS_LUT_CHAN_707250_IDX] = { 28290, 0x1, 0x75, 0x1C0000, 0x936 },
+       [ATHOS_LUT_CHAN_707375_IDX] = { 28295, 0x1, 0x75, 0x1CAAAB, 0x936 },
+       [ATHOS_LUT_CHAN_707500_IDX] = { 28300, 0x1, 0x75, 0x1D5555, 0x936 },
+       [ATHOS_LUT_CHAN_707625_IDX] = { 28305, 0x1, 0x75, 0x1E0000, 0x937 },
+       [ATHOS_LUT_CHAN_707750_IDX] = { 28310, 0x1, 0x75, 0x1EAAAB, 0x937 },
+       [ATHOS_LUT_CHAN_707875_IDX] = { 28315, 0x1, 0x75, 0x1F5555, 0x938 },
+       [ATHOS_LUT_CHAN_708000_IDX] = { 28320, 0x1, 0x76, 0x0, 0x938 },
+       [ATHOS_LUT_CHAN_708125_IDX] = { 28325, 0x1, 0x76, 0xAAAB, 0x938 },
+       [ATHOS_LUT_CHAN_708250_IDX] = { 28330, 0x1, 0x76, 0x15555, 0x939 },
+       [ATHOS_LUT_CHAN_708375_IDX] = { 28335, 0x1, 0x76, 0x20000, 0x939 },
+       [ATHOS_LUT_CHAN_708500_IDX] = { 28340, 0x1, 0x76, 0x2AAAB, 0x93A },
+       [ATHOS_LUT_CHAN_708625_IDX] = { 28345, 0x1, 0x76, 0x35555, 0x93A },
+       [ATHOS_LUT_CHAN_708750_IDX] = { 28350, 0x1, 0x76, 0x40000, 0x93B },
+       [ATHOS_LUT_CHAN_708875_IDX] = { 28355, 0x1, 0x76, 0x4AAAB, 0x93B },
+       [ATHOS_LUT_CHAN_709000_IDX] = { 28360, 0x1, 0x76, 0x55555, 0x93B },
+       [ATHOS_LUT_CHAN_709125_IDX] = { 28365, 0x1, 0x76, 0x60000, 0x93C },
+       [ATHOS_LUT_CHAN_709250_IDX] = { 28370, 0x1, 0x76, 0x6AAAB, 0x93C },
+       [ATHOS_LUT_CHAN_709375_IDX] = { 28375, 0x1, 0x76, 0x75555, 0x93D },
+       [ATHOS_LUT_CHAN_709500_IDX] = { 28380, 0x1, 0x76, 0x80000, 0x93D },
+       [ATHOS_LUT_CHAN_709625_IDX] = { 28385, 0x1, 0x76, 0x8AAAB, 0x93D },
+       [ATHOS_LUT_CHAN_709750_IDX] = { 28390, 0x1, 0x76, 0x95555, 0x93E },
+       [ATHOS_LUT_CHAN_709875_IDX] = { 28395, 0x1, 0x76, 0xA0000, 0x93E },
+       [ATHOS_LUT_CHAN_710000_IDX] = { 28400, 0x1, 0x76, 0xAAAAB, 0x93F },
+       [ATHOS_LUT_CHAN_710125_IDX] = { 28405, 0x1, 0x76, 0xB5555, 0x93F },
+       [ATHOS_LUT_CHAN_710250_IDX] = { 28410, 0x1, 0x76, 0xC0000, 0x940 },
+       [ATHOS_LUT_CHAN_710375_IDX] = { 28415, 0x1, 0x76, 0xCAAAB, 0x940 },
+       [ATHOS_LUT_CHAN_710500_IDX] = { 28420, 0x1, 0x76, 0xD5555, 0x940 },
+       [ATHOS_LUT_CHAN_710625_IDX] = { 28425, 0x1, 0x76, 0xE0000, 0x941 },
+       [ATHOS_LUT_CHAN_710750_IDX] = { 28430, 0x1, 0x76, 0xEAAAB, 0x941 },
+       [ATHOS_LUT_CHAN_710875_IDX] = { 28435, 0x1, 0x76, 0xF5555, 0x942 },
+       [ATHOS_LUT_CHAN_711000_IDX] = { 28440, 0x1, 0x76, 0x100000, 0x942 },
+       [ATHOS_LUT_CHAN_711125_IDX] = { 28445, 0x1, 0x76, 0x10AAAB, 0x942 },
+       [ATHOS_LUT_CHAN_711250_IDX] = { 28450, 0x1, 0x76, 0x115555, 0x943 },
+       [ATHOS_LUT_CHAN_711375_IDX] = { 28455, 0x1, 0x76, 0x120000, 0x943 },
+       [ATHOS_LUT_CHAN_711500_IDX] = { 28460, 0x1, 0x76, 0x12AAAB, 0x944 },
+       [ATHOS_LUT_CHAN_711625_IDX] = { 28465, 0x1, 0x76, 0x135555, 0x944 },
+       [ATHOS_LUT_CHAN_711750_IDX] = { 28470, 0x1, 0x76, 0x140000, 0x945 },
+       [ATHOS_LUT_CHAN_711875_IDX] = { 28475, 0x1, 0x76, 0x14AAAB, 0x945 },
+       [ATHOS_LUT_CHAN_712000_IDX] = { 28480, 0x1, 0x76, 0x155555, 0x945 },
+       [ATHOS_LUT_CHAN_712125_IDX] = { 28485, 0x1, 0x76, 0x160000, 0x946 },
+       [ATHOS_LUT_CHAN_712250_IDX] = { 28490, 0x1, 0x76, 0x16AAAB, 0x946 },
+       [ATHOS_LUT_CHAN_712375_IDX] = { 28495, 0x1, 0x76, 0x175555, 0x947 },
+       [ATHOS_LUT_CHAN_712500_IDX] = { 28500, 0x1, 0x76, 0x180000, 0x947 },
+       [ATHOS_LUT_CHAN_712625_IDX] = { 28505, 0x1, 0x76, 0x18AAAB, 0x947 },
+       [ATHOS_LUT_CHAN_712750_IDX] = { 28510, 0x1, 0x76, 0x195555, 0x948 },
+       [ATHOS_LUT_CHAN_712875_IDX] = { 28515, 0x1, 0x76, 0x1A0000, 0x948 },
+       [ATHOS_LUT_CHAN_713000_IDX] = { 28520, 0x1, 0x76, 0x1AAAAB, 0x949 },
+       [ATHOS_LUT_CHAN_713125_IDX] = { 28525, 0x1, 0x76, 0x1B5555, 0x949 },
+       [ATHOS_LUT_CHAN_713250_IDX] = { 28530, 0x1, 0x76, 0x1C0000, 0x94A },
+       [ATHOS_LUT_CHAN_713375_IDX] = { 28535, 0x1, 0x76, 0x1CAAAB, 0x94A },
+       [ATHOS_LUT_CHAN_713500_IDX] = { 28540, 0x1, 0x76, 0x1D5555, 0x94A },
+       [ATHOS_LUT_CHAN_713625_IDX] = { 28545, 0x1, 0x76, 0x1E0000, 0x94B },
+       [ATHOS_LUT_CHAN_713750_IDX] = { 28550, 0x1, 0x76, 0x1EAAAB, 0x94B },
+       [ATHOS_LUT_CHAN_713875_IDX] = { 28555, 0x1, 0x76, 0x1F5555, 0x94C },
+       [ATHOS_LUT_CHAN_714000_IDX] = { 28560, 0x1, 0x77, 0x0, 0x94C },
+       [ATHOS_LUT_CHAN_714125_IDX] = { 28565, 0x1, 0x77, 0xAAAB, 0x94C },
+       [ATHOS_LUT_CHAN_714250_IDX] = { 28570, 0x1, 0x77, 0x15555, 0x94D },
+       [ATHOS_LUT_CHAN_714375_IDX] = { 28575, 0x1, 0x77, 0x20000, 0x94D },
+       [ATHOS_LUT_CHAN_714500_IDX] = { 28580, 0x1, 0x77, 0x2AAAB, 0x94E },
+       [ATHOS_LUT_CHAN_714625_IDX] = { 28585, 0x1, 0x77, 0x35555, 0x94E },
+       [ATHOS_LUT_CHAN_714750_IDX] = { 28590, 0x1, 0x77, 0x40000, 0x94F },
+       [ATHOS_LUT_CHAN_714875_IDX] = { 28595, 0x1, 0x77, 0x4AAAB, 0x94F },
+       [ATHOS_LUT_CHAN_715000_IDX] = { 28600, 0x1, 0x77, 0x55555, 0x94F },
+       [ATHOS_LUT_CHAN_715125_IDX] = { 28605, 0x1, 0x77, 0x60000, 0x950 },
+       [ATHOS_LUT_CHAN_715250_IDX] = { 28610, 0x1, 0x77, 0x6AAAB, 0x950 },
+       [ATHOS_LUT_CHAN_715375_IDX] = { 28615, 0x1, 0x77, 0x75555, 0x951 },
+       [ATHOS_LUT_CHAN_715500_IDX] = { 28620, 0x1, 0x77, 0x80000, 0x951 },
+       [ATHOS_LUT_CHAN_715625_IDX] = { 28625, 0x1, 0x77, 0x8AAAB, 0x951 },
+       [ATHOS_LUT_CHAN_715750_IDX] = { 28630, 0x1, 0x77, 0x95555, 0x952 },
+       [ATHOS_LUT_CHAN_715875_IDX] = { 28635, 0x1, 0x77, 0xA0000, 0x952 },
+       [ATHOS_LUT_CHAN_716000_IDX] = { 28640, 0x1, 0x77, 0xAAAAB, 0x953 },
+       [ATHOS_LUT_CHAN_716125_IDX] = { 28645, 0x1, 0x77, 0xB5555, 0x953 },
+       [ATHOS_LUT_CHAN_716250_IDX] = { 28650, 0x1, 0x77, 0xC0000, 0x954 },
+       [ATHOS_LUT_CHAN_716375_IDX] = { 28655, 0x1, 0x77, 0xCAAAB, 0x954 },
+       [ATHOS_LUT_CHAN_716500_IDX] = { 28660, 0x1, 0x77, 0xD5555, 0x954 },
+       [ATHOS_LUT_CHAN_716625_IDX] = { 28665, 0x1, 0x77, 0xE0000, 0x955 },
+       [ATHOS_LUT_CHAN_716750_IDX] = { 28670, 0x1, 0x77, 0xEAAAB, 0x955 },
+       [ATHOS_LUT_CHAN_716875_IDX] = { 28675, 0x1, 0x77, 0xF5555, 0x956 },
+       [ATHOS_LUT_CHAN_717000_IDX] = { 28680, 0x1, 0x77, 0x100000, 0x956 },
+       [ATHOS_LUT_CHAN_717125_IDX] = { 28685, 0x1, 0x77, 0x10AAAB, 0x956 },
+       [ATHOS_LUT_CHAN_717250_IDX] = { 28690, 0x1, 0x77, 0x115555, 0x957 },
+       [ATHOS_LUT_CHAN_717375_IDX] = { 28695, 0x1, 0x77, 0x120000, 0x957 },
+       [ATHOS_LUT_CHAN_717500_IDX] = { 28700, 0x1, 0x77, 0x12AAAB, 0x958 },
+       [ATHOS_LUT_CHAN_717625_IDX] = { 28705, 0x1, 0x77, 0x135555, 0x958 },
+       [ATHOS_LUT_CHAN_717750_IDX] = { 28710, 0x1, 0x77, 0x140000, 0x959 },
+       [ATHOS_LUT_CHAN_717875_IDX] = { 28715, 0x1, 0x77, 0x14AAAB, 0x959 },
+       [ATHOS_LUT_CHAN_718000_IDX] = { 28720, 0x1, 0x77, 0x155555, 0x959 },
+       [ATHOS_LUT_CHAN_718125_IDX] = { 28725, 0x1, 0x77, 0x160000, 0x95A },
+       [ATHOS_LUT_CHAN_718250_IDX] = { 28730, 0x1, 0x77, 0x16AAAB, 0x95A },
+       [ATHOS_LUT_CHAN_718375_IDX] = { 28735, 0x1, 0x77, 0x175555, 0x95B },
+       [ATHOS_LUT_CHAN_718500_IDX] = { 28740, 0x1, 0x77, 0x180000, 0x95B },
+       [ATHOS_LUT_CHAN_718625_IDX] = { 28745, 0x1, 0x77, 0x18AAAB, 0x95B },
+       [ATHOS_LUT_CHAN_718750_IDX] = { 28750, 0x1, 0x77, 0x195555, 0x95C },
+       [ATHOS_LUT_CHAN_718875_IDX] = { 28755, 0x1, 0x77, 0x1A0000, 0x95C },
+       [ATHOS_LUT_CHAN_719000_IDX] = { 28760, 0x1, 0x77, 0x1AAAAB, 0x95D },
+       [ATHOS_LUT_CHAN_719125_IDX] = { 28765, 0x1, 0x77, 0x1B5555, 0x95D },
+       [ATHOS_LUT_CHAN_719250_IDX] = { 28770, 0x1, 0x77, 0x1C0000, 0x95E },
+       [ATHOS_LUT_CHAN_719375_IDX] = { 28775, 0x1, 0x77, 0x1CAAAB, 0x95E },
+       [ATHOS_LUT_CHAN_719500_IDX] = { 28780, 0x1, 0x77, 0x1D5555, 0x95E },
+       [ATHOS_LUT_CHAN_719625_IDX] = { 28785, 0x1, 0x77, 0x1E0000, 0x95F },
+       [ATHOS_LUT_CHAN_719750_IDX] = { 28790, 0x1, 0x77, 0x1EAAAB, 0x95F },
+       [ATHOS_LUT_CHAN_719875_IDX] = { 28795, 0x1, 0x77, 0x1F5555, 0x960 },
+       [ATHOS_LUT_CHAN_720000_IDX] = { 28800, 0x1, 0x78, 0x0, 0x960 },
+       [ATHOS_LUT_CHAN_720125_IDX] = { 28805, 0x1, 0x78, 0xAAAB, 0x960 },
+       [ATHOS_LUT_CHAN_720250_IDX] = { 28810, 0x1, 0x78, 0x15555, 0x961 },
+       [ATHOS_LUT_CHAN_720375_IDX] = { 28815, 0x1, 0x78, 0x20000, 0x961 },
+       [ATHOS_LUT_CHAN_720500_IDX] = { 28820, 0x1, 0x78, 0x2AAAB, 0x962 },
+       [ATHOS_LUT_CHAN_720625_IDX] = { 28825, 0x1, 0x78, 0x35555, 0x962 },
+       [ATHOS_LUT_CHAN_720750_IDX] = { 28830, 0x1, 0x78, 0x40000, 0x963 },
+       [ATHOS_LUT_CHAN_720875_IDX] = { 28835, 0x1, 0x78, 0x4AAAB, 0x963 },
+       [ATHOS_LUT_CHAN_721000_IDX] = { 28840, 0x1, 0x78, 0x55555, 0x963 },
+       [ATHOS_LUT_CHAN_721125_IDX] = { 28845, 0x1, 0x78, 0x60000, 0x964 },
+       [ATHOS_LUT_CHAN_721250_IDX] = { 28850, 0x1, 0x78, 0x6AAAB, 0x964 },
+       [ATHOS_LUT_CHAN_721375_IDX] = { 28855, 0x1, 0x78, 0x75555, 0x965 },
+       [ATHOS_LUT_CHAN_721500_IDX] = { 28860, 0x1, 0x78, 0x80000, 0x965 }
+};
+
+const struct athos_lut_line athos_lut_6g_60_mhz[ATHOS_LUT_CHAN_6G_MAX] = {
+       [ATHOS_LUT_CHAN_593000_IDX] = { 23720, 0x0, 0x41, 0x1C71C7, 0x7B9 },
+       [ATHOS_LUT_CHAN_593125_IDX] = { 23725, 0x0, 0x41, 0x1CE38E, 0x7B9 },
+       [ATHOS_LUT_CHAN_593250_IDX] = { 23730, 0x0, 0x41, 0x1D5555, 0x7BA },
+       [ATHOS_LUT_CHAN_593375_IDX] = { 23735, 0x0, 0x41, 0x1DC71C, 0x7BA },
+       [ATHOS_LUT_CHAN_593500_IDX] = { 23740, 0x0, 0x41, 0x1E38E4, 0x7BA },
+       [ATHOS_LUT_CHAN_593625_IDX] = { 23745, 0x0, 0x41, 0x1EAAAB, 0x7BB },
+       [ATHOS_LUT_CHAN_593750_IDX] = { 23750, 0x0, 0x41, 0x1F1C72, 0x7BB },
+       [ATHOS_LUT_CHAN_593875_IDX] = { 23755, 0x0, 0x41, 0x1F8E39, 0x7BC },
+       [ATHOS_LUT_CHAN_594000_IDX] = { 23760, 0x0, 0x42, 0x0, 0x7BC },
+       [ATHOS_LUT_CHAN_594125_IDX] = { 23765, 0x0, 0x42, 0x71C7, 0x7BC },
+       [ATHOS_LUT_CHAN_594250_IDX] = { 23770, 0x0, 0x42, 0xE38E, 0x7BD },
+       [ATHOS_LUT_CHAN_594375_IDX] = { 23775, 0x0, 0x42, 0x15555, 0x7BD },
+       [ATHOS_LUT_CHAN_594500_IDX] = { 23780, 0x0, 0x42, 0x1C71C, 0x7BE },
+       [ATHOS_LUT_CHAN_594625_IDX] = { 23785, 0x0, 0x42, 0x238E4, 0x7BE },
+       [ATHOS_LUT_CHAN_594750_IDX] = { 23790, 0x0, 0x42, 0x2AAAB, 0x7BF },
+       [ATHOS_LUT_CHAN_594875_IDX] = { 23795, 0x0, 0x42, 0x31C72, 0x7BF },
+       [ATHOS_LUT_CHAN_595000_IDX] = { 23800, 0x0, 0x42, 0x38E39, 0x7BF },
+       [ATHOS_LUT_CHAN_595125_IDX] = { 23805, 0x0, 0x42, 0x40000, 0x7C0 },
+       [ATHOS_LUT_CHAN_595250_IDX] = { 23810, 0x0, 0x42, 0x471C7, 0x7C0 },
+       [ATHOS_LUT_CHAN_595375_IDX] = { 23815, 0x0, 0x42, 0x4E38E, 0x7C1 },
+       [ATHOS_LUT_CHAN_595500_IDX] = { 23820, 0x0, 0x42, 0x55555, 0x7C1 },
+       [ATHOS_LUT_CHAN_595625_IDX] = { 23825, 0x0, 0x42, 0x5C71C, 0x7C1 },
+       [ATHOS_LUT_CHAN_595750_IDX] = { 23830, 0x0, 0x42, 0x638E4, 0x7C2 },
+       [ATHOS_LUT_CHAN_595875_IDX] = { 23835, 0x0, 0x42, 0x6AAAB, 0x7C2 },
+       [ATHOS_LUT_CHAN_596000_IDX] = { 23840, 0x0, 0x42, 0x71C72, 0x7C3 },
+       [ATHOS_LUT_CHAN_596125_IDX] = { 23845, 0x0, 0x42, 0x78E39, 0x7C3 },
+       [ATHOS_LUT_CHAN_596250_IDX] = { 23850, 0x0, 0x42, 0x80000, 0x7C4 },
+       [ATHOS_LUT_CHAN_596375_IDX] = { 23855, 0x0, 0x42, 0x871C7, 0x7C4 },
+       [ATHOS_LUT_CHAN_596500_IDX] = { 23860, 0x0, 0x42, 0x8E38E, 0x7C4 },
+       [ATHOS_LUT_CHAN_596625_IDX] = { 23865, 0x0, 0x42, 0x95555, 0x7C5 },
+       [ATHOS_LUT_CHAN_596750_IDX] = { 23870, 0x0, 0x42, 0x9C71C, 0x7C5 },
+       [ATHOS_LUT_CHAN_596875_IDX] = { 23875, 0x0, 0x42, 0xA38E4, 0x7C6 },
+       [ATHOS_LUT_CHAN_597000_IDX] = { 23880, 0x0, 0x42, 0xAAAAB, 0x7C6 },
+       [ATHOS_LUT_CHAN_597125_IDX] = { 23885, 0x0, 0x42, 0xB1C72, 0x7C6 },
+       [ATHOS_LUT_CHAN_597250_IDX] = { 23890, 0x0, 0x42, 0xB8E39, 0x7C7 },
+       [ATHOS_LUT_CHAN_597375_IDX] = { 23895, 0x0, 0x42, 0xC0000, 0x7C7 },
+       [ATHOS_LUT_CHAN_597500_IDX] = { 23900, 0x0, 0x42, 0xC71C7, 0x7C8 },
+       [ATHOS_LUT_CHAN_597625_IDX] = { 23905, 0x0, 0x42, 0xCE38E, 0x7C8 },
+       [ATHOS_LUT_CHAN_597750_IDX] = { 23910, 0x0, 0x42, 0xD5555, 0x7C9 },
+       [ATHOS_LUT_CHAN_597875_IDX] = { 23915, 0x0, 0x42, 0xDC71C, 0x7C9 },
+       [ATHOS_LUT_CHAN_598000_IDX] = { 23920, 0x0, 0x42, 0xE38E4, 0x7C9 },
+       [ATHOS_LUT_CHAN_598125_IDX] = { 23925, 0x0, 0x42, 0xEAAAB, 0x7CA },
+       [ATHOS_LUT_CHAN_598250_IDX] = { 23930, 0x0, 0x42, 0xF1C72, 0x7CA },
+       [ATHOS_LUT_CHAN_598375_IDX] = { 23935, 0x0, 0x42, 0xF8E39, 0x7CB },
+       [ATHOS_LUT_CHAN_598500_IDX] = { 23940, 0x0, 0x42, 0x100000, 0x7CB },
+       [ATHOS_LUT_CHAN_598625_IDX] = { 23945, 0x0, 0x42, 0x1071C7, 0x7CB },
+       [ATHOS_LUT_CHAN_598750_IDX] = { 23950, 0x0, 0x42, 0x10E38E, 0x7CC },
+       [ATHOS_LUT_CHAN_598875_IDX] = { 23955, 0x0, 0x42, 0x115555, 0x7CC },
+       [ATHOS_LUT_CHAN_599000_IDX] = { 23960, 0x0, 0x42, 0x11C71C, 0x7CD },
+       [ATHOS_LUT_CHAN_599125_IDX] = { 23965, 0x0, 0x42, 0x1238E4, 0x7CD },
+       [ATHOS_LUT_CHAN_599250_IDX] = { 23970, 0x0, 0x42, 0x12AAAB, 0x7CE },
+       [ATHOS_LUT_CHAN_599375_IDX] = { 23975, 0x0, 0x42, 0x131C72, 0x7CE },
+       [ATHOS_LUT_CHAN_599500_IDX] = { 23980, 0x0, 0x42, 0x138E39, 0x7CE },
+       [ATHOS_LUT_CHAN_599625_IDX] = { 23985, 0x0, 0x42, 0x140000, 0x7CF },
+       [ATHOS_LUT_CHAN_599750_IDX] = { 23990, 0x0, 0x42, 0x1471C7, 0x7CF },
+       [ATHOS_LUT_CHAN_599875_IDX] = { 23995, 0x0, 0x42, 0x14E38E, 0x7D0 },
+       [ATHOS_LUT_CHAN_600000_IDX] = { 24000, 0x0, 0x42, 0x155555, 0x7D0 },
+       [ATHOS_LUT_CHAN_600125_IDX] = { 24005, 0x0, 0x42, 0x15C71C, 0x7D0 },
+       [ATHOS_LUT_CHAN_600250_IDX] = { 24010, 0x0, 0x42, 0x1638E4, 0x7D1 },
+       [ATHOS_LUT_CHAN_600375_IDX] = { 24015, 0x0, 0x42, 0x16AAAB, 0x7D1 },
+       [ATHOS_LUT_CHAN_600500_IDX] = { 24020, 0x0, 0x42, 0x171C72, 0x7D2 },
+       [ATHOS_LUT_CHAN_600625_IDX] = { 24025, 0x0, 0x42, 0x178E39, 0x7D2 },
+       [ATHOS_LUT_CHAN_600750_IDX] = { 24030, 0x0, 0x42, 0x180000, 0x7D3 },
+       [ATHOS_LUT_CHAN_600875_IDX] = { 24035, 0x0, 0x42, 0x1871C7, 0x7D3 },
+       [ATHOS_LUT_CHAN_601000_IDX] = { 24040, 0x0, 0x42, 0x18E38E, 0x7D3 },
+       [ATHOS_LUT_CHAN_601125_IDX] = { 24045, 0x0, 0x42, 0x195555, 0x7D4 },
+       [ATHOS_LUT_CHAN_601250_IDX] = { 24050, 0x0, 0x42, 0x19C71C, 0x7D4 },
+       [ATHOS_LUT_CHAN_601375_IDX] = { 24055, 0x0, 0x42, 0x1A38E4, 0x7D5 },
+       [ATHOS_LUT_CHAN_601500_IDX] = { 24060, 0x0, 0x42, 0x1AAAAB, 0x7D5 },
+       [ATHOS_LUT_CHAN_601625_IDX] = { 24065, 0x0, 0x42, 0x1B1C72, 0x7D5 },
+       [ATHOS_LUT_CHAN_601750_IDX] = { 24070, 0x0, 0x42, 0x1B8E39, 0x7D6 },
+       [ATHOS_LUT_CHAN_601875_IDX] = { 24075, 0x0, 0x42, 0x1C0000, 0x7D6 },
+       [ATHOS_LUT_CHAN_602000_IDX] = { 24080, 0x0, 0x42, 0x1C71C7, 0x7D7 },
+       [ATHOS_LUT_CHAN_602125_IDX] = { 24085, 0x0, 0x42, 0x1CE38E, 0x7D7 },
+       [ATHOS_LUT_CHAN_602250_IDX] = { 24090, 0x0, 0x42, 0x1D5555, 0x7D8 },
+       [ATHOS_LUT_CHAN_602375_IDX] = { 24095, 0x0, 0x42, 0x1DC71C, 0x7D8 },
+       [ATHOS_LUT_CHAN_602500_IDX] = { 24100, 0x0, 0x42, 0x1E38E4, 0x7D8 },
+       [ATHOS_LUT_CHAN_602625_IDX] = { 24105, 0x0, 0x42, 0x1EAAAB, 0x7D9 },
+       [ATHOS_LUT_CHAN_602750_IDX] = { 24110, 0x0, 0x42, 0x1F1C72, 0x7D9 },
+       [ATHOS_LUT_CHAN_602875_IDX] = { 24115, 0x0, 0x42, 0x1F8E39, 0x7DA },
+       [ATHOS_LUT_CHAN_603000_IDX] = { 24120, 0x0, 0x43, 0x0, 0x7DA },
+       [ATHOS_LUT_CHAN_603125_IDX] = { 24125, 0x0, 0x43, 0x71C7, 0x7DA },
+       [ATHOS_LUT_CHAN_603250_IDX] = { 24130, 0x0, 0x43, 0xE38E, 0x7DB },
+       [ATHOS_LUT_CHAN_603375_IDX] = { 24135, 0x0, 0x43, 0x15555, 0x7DB },
+       [ATHOS_LUT_CHAN_603500_IDX] = { 24140, 0x0, 0x43, 0x1C71C, 0x7DC },
+       [ATHOS_LUT_CHAN_603625_IDX] = { 24145, 0x0, 0x43, 0x238E4, 0x7DC },
+       [ATHOS_LUT_CHAN_603750_IDX] = { 24150, 0x0, 0x43, 0x2AAAB, 0x7DD },
+       [ATHOS_LUT_CHAN_603875_IDX] = { 24155, 0x0, 0x43, 0x31C72, 0x7DD },
+       [ATHOS_LUT_CHAN_604000_IDX] = { 24160, 0x0, 0x43, 0x38E39, 0x7DD },
+       [ATHOS_LUT_CHAN_604125_IDX] = { 24165, 0x0, 0x43, 0x40000, 0x7DE },
+       [ATHOS_LUT_CHAN_604250_IDX] = { 24170, 0x0, 0x43, 0x471C7, 0x7DE },
+       [ATHOS_LUT_CHAN_604375_IDX] = { 24175, 0x0, 0x43, 0x4E38E, 0x7DF },
+       [ATHOS_LUT_CHAN_604500_IDX] = { 24180, 0x0, 0x43, 0x55555, 0x7DF },
+       [ATHOS_LUT_CHAN_604625_IDX] = { 24185, 0x0, 0x43, 0x5C71C, 0x7DF },
+       [ATHOS_LUT_CHAN_604750_IDX] = { 24190, 0x0, 0x43, 0x638E4, 0x7E0 },
+       [ATHOS_LUT_CHAN_604875_IDX] = { 24195, 0x0, 0x43, 0x6AAAB, 0x7E0 },
+       [ATHOS_LUT_CHAN_605000_IDX] = { 24200, 0x0, 0x43, 0x71C72, 0x7E1 },
+       [ATHOS_LUT_CHAN_605125_IDX] = { 24205, 0x0, 0x43, 0x78E39, 0x7E1 },
+       [ATHOS_LUT_CHAN_605250_IDX] = { 24210, 0x0, 0x43, 0x80000, 0x7E2 },
+       [ATHOS_LUT_CHAN_605375_IDX] = { 24215, 0x0, 0x43, 0x871C7, 0x7E2 },
+       [ATHOS_LUT_CHAN_605500_IDX] = { 24220, 0x0, 0x43, 0x8E38E, 0x7E2 },
+       [ATHOS_LUT_CHAN_605625_IDX] = { 24225, 0x0, 0x43, 0x95555, 0x7E3 },
+       [ATHOS_LUT_CHAN_605750_IDX] = { 24230, 0x0, 0x43, 0x9C71C, 0x7E3 },
+       [ATHOS_LUT_CHAN_605875_IDX] = { 24235, 0x0, 0x43, 0xA38E4, 0x7E4 },
+       [ATHOS_LUT_CHAN_606000_IDX] = { 24240, 0x0, 0x43, 0xAAAAB, 0x7E4 },
+       [ATHOS_LUT_CHAN_606125_IDX] = { 24245, 0x0, 0x43, 0xB1C72, 0x7E4 },
+       [ATHOS_LUT_CHAN_606250_IDX] = { 24250, 0x0, 0x43, 0xB8E39, 0x7E5 },
+       [ATHOS_LUT_CHAN_606375_IDX] = { 24255, 0x0, 0x43, 0xC0000, 0x7E5 },
+       [ATHOS_LUT_CHAN_606500_IDX] = { 24260, 0x0, 0x43, 0xC71C7, 0x7E6 },
+       [ATHOS_LUT_CHAN_606625_IDX] = { 24265, 0x0, 0x43, 0xCE38E, 0x7E6 },
+       [ATHOS_LUT_CHAN_606750_IDX] = { 24270, 0x0, 0x43, 0xD5555, 0x7E7 },
+       [ATHOS_LUT_CHAN_606875_IDX] = { 24275, 0x0, 0x43, 0xDC71C, 0x7E7 },
+       [ATHOS_LUT_CHAN_607000_IDX] = { 24280, 0x0, 0x43, 0xE38E4, 0x7E7 },
+       [ATHOS_LUT_CHAN_607125_IDX] = { 24285, 0x0, 0x43, 0xEAAAB, 0x7E8 },
+       [ATHOS_LUT_CHAN_607250_IDX] = { 24290, 0x0, 0x43, 0xF1C72, 0x7E8 },
+       [ATHOS_LUT_CHAN_607375_IDX] = { 24295, 0x0, 0x43, 0xF8E39, 0x7E9 },
+       [ATHOS_LUT_CHAN_607500_IDX] = { 24300, 0x0, 0x43, 0x100000, 0x7E9 },
+       [ATHOS_LUT_CHAN_607625_IDX] = { 24305, 0x0, 0x43, 0x1071C7, 0x7E9 },
+       [ATHOS_LUT_CHAN_607750_IDX] = { 24310, 0x0, 0x43, 0x10E38E, 0x7EA },
+       [ATHOS_LUT_CHAN_607875_IDX] = { 24315, 0x0, 0x43, 0x115555, 0x7EA },
+       [ATHOS_LUT_CHAN_608000_IDX] = { 24320, 0x0, 0x43, 0x11C71C, 0x7EB },
+       [ATHOS_LUT_CHAN_608125_IDX] = { 24325, 0x0, 0x43, 0x1238E4, 0x7EB },
+       [ATHOS_LUT_CHAN_608250_IDX] = { 24330, 0x0, 0x43, 0x12AAAB, 0x7EC },
+       [ATHOS_LUT_CHAN_608375_IDX] = { 24335, 0x0, 0x43, 0x131C72, 0x7EC },
+       [ATHOS_LUT_CHAN_608500_IDX] = { 24340, 0x0, 0x43, 0x138E39, 0x7EC },
+       [ATHOS_LUT_CHAN_608625_IDX] = { 24345, 0x0, 0x43, 0x140000, 0x7ED },
+       [ATHOS_LUT_CHAN_608750_IDX] = { 24350, 0x0, 0x43, 0x1471C7, 0x7ED },
+       [ATHOS_LUT_CHAN_608875_IDX] = { 24355, 0x0, 0x43, 0x14E38E, 0x7EE },
+       [ATHOS_LUT_CHAN_609000_IDX] = { 24360, 0x0, 0x43, 0x155555, 0x7EE },
+       [ATHOS_LUT_CHAN_609125_IDX] = { 24365, 0x0, 0x43, 0x15C71C, 0x7EE },
+       [ATHOS_LUT_CHAN_609250_IDX] = { 24370, 0x0, 0x43, 0x1638E4, 0x7EF },
+       [ATHOS_LUT_CHAN_609375_IDX] = { 24375, 0x0, 0x43, 0x16AAAB, 0x7EF },
+       [ATHOS_LUT_CHAN_609500_IDX] = { 24380, 0x0, 0x43, 0x171C72, 0x7F0 },
+       [ATHOS_LUT_CHAN_609625_IDX] = { 24385, 0x0, 0x43, 0x178E39, 0x7F0 },
+       [ATHOS_LUT_CHAN_609750_IDX] = { 24390, 0x0, 0x43, 0x180000, 0x7F1 },
+       [ATHOS_LUT_CHAN_609875_IDX] = { 24395, 0x0, 0x43, 0x1871C7, 0x7F1 },
+       [ATHOS_LUT_CHAN_610000_IDX] = { 24400, 0x1, 0x43, 0x18E38E, 0x7F1 },
+       [ATHOS_LUT_CHAN_610125_IDX] = { 24405, 0x1, 0x43, 0x195555, 0x7F2 },
+       [ATHOS_LUT_CHAN_610250_IDX] = { 24410, 0x1, 0x43, 0x19C71C, 0x7F2 },
+       [ATHOS_LUT_CHAN_610375_IDX] = { 24415, 0x1, 0x43, 0x1A38E4, 0x7F3 },
+       [ATHOS_LUT_CHAN_610500_IDX] = { 24420, 0x1, 0x43, 0x1AAAAB, 0x7F3 },
+       [ATHOS_LUT_CHAN_610625_IDX] = { 24425, 0x1, 0x43, 0x1B1C72, 0x7F3 },
+       [ATHOS_LUT_CHAN_610750_IDX] = { 24430, 0x1, 0x43, 0x1B8E39, 0x7F4 },
+       [ATHOS_LUT_CHAN_610875_IDX] = { 24435, 0x1, 0x43, 0x1C0000, 0x7F4 },
+       [ATHOS_LUT_CHAN_611000_IDX] = { 24440, 0x1, 0x43, 0x1C71C7, 0x7F5 },
+       [ATHOS_LUT_CHAN_611125_IDX] = { 24445, 0x1, 0x43, 0x1CE38E, 0x7F5 },
+       [ATHOS_LUT_CHAN_611250_IDX] = { 24450, 0x1, 0x43, 0x1D5555, 0x7F6 },
+       [ATHOS_LUT_CHAN_611375_IDX] = { 24455, 0x1, 0x43, 0x1DC71C, 0x7F6 },
+       [ATHOS_LUT_CHAN_611500_IDX] = { 24460, 0x1, 0x43, 0x1E38E4, 0x7F6 },
+       [ATHOS_LUT_CHAN_611625_IDX] = { 24465, 0x1, 0x43, 0x1EAAAB, 0x7F7 },
+       [ATHOS_LUT_CHAN_611750_IDX] = { 24470, 0x1, 0x43, 0x1F1C72, 0x7F7 },
+       [ATHOS_LUT_CHAN_611875_IDX] = { 24475, 0x1, 0x43, 0x1F8E39, 0x7F8 },
+       [ATHOS_LUT_CHAN_612000_IDX] = { 24480, 0x1, 0x44, 0x0, 0x7F8 },
+       [ATHOS_LUT_CHAN_612125_IDX] = { 24485, 0x1, 0x44, 0x71C7, 0x7F8 },
+       [ATHOS_LUT_CHAN_612250_IDX] = { 24490, 0x1, 0x44, 0xE38E, 0x7F9 },
+       [ATHOS_LUT_CHAN_612375_IDX] = { 24495, 0x1, 0x44, 0x15555, 0x7F9 },
+       [ATHOS_LUT_CHAN_612500_IDX] = { 24500, 0x1, 0x44, 0x1C71C, 0x7FA },
+       [ATHOS_LUT_CHAN_612625_IDX] = { 24505, 0x1, 0x44, 0x238E4, 0x7FA },
+       [ATHOS_LUT_CHAN_612750_IDX] = { 24510, 0x1, 0x44, 0x2AAAB, 0x7FB },
+       [ATHOS_LUT_CHAN_612875_IDX] = { 24515, 0x1, 0x44, 0x31C72, 0x7FB },
+       [ATHOS_LUT_CHAN_613000_IDX] = { 24520, 0x1, 0x44, 0x38E39, 0x7FB },
+       [ATHOS_LUT_CHAN_613125_IDX] = { 24525, 0x1, 0x44, 0x40000, 0x7FC },
+       [ATHOS_LUT_CHAN_613250_IDX] = { 24530, 0x1, 0x44, 0x471C7, 0x7FC },
+       [ATHOS_LUT_CHAN_613375_IDX] = { 24535, 0x1, 0x44, 0x4E38E, 0x7FD },
+       [ATHOS_LUT_CHAN_613500_IDX] = { 24540, 0x1, 0x44, 0x55555, 0x7FD },
+       [ATHOS_LUT_CHAN_613625_IDX] = { 24545, 0x1, 0x44, 0x5C71C, 0x7FD },
+       [ATHOS_LUT_CHAN_613750_IDX] = { 24550, 0x1, 0x44, 0x638E4, 0x7FE },
+       [ATHOS_LUT_CHAN_613875_IDX] = { 24555, 0x1, 0x44, 0x6AAAB, 0x7FE },
+       [ATHOS_LUT_CHAN_614000_IDX] = { 24560, 0x1, 0x44, 0x71C72, 0x7FF },
+       [ATHOS_LUT_CHAN_614125_IDX] = { 24565, 0x1, 0x44, 0x78E39, 0x7FF },
+       [ATHOS_LUT_CHAN_614250_IDX] = { 24570, 0x1, 0x44, 0x80000, 0x800 },
+       [ATHOS_LUT_CHAN_614375_IDX] = { 24575, 0x1, 0x44, 0x871C7, 0x800 },
+       [ATHOS_LUT_CHAN_614500_IDX] = { 24580, 0x1, 0x44, 0x8E38E, 0x800 },
+       [ATHOS_LUT_CHAN_614625_IDX] = { 24585, 0x1, 0x44, 0x95555, 0x801 },
+       [ATHOS_LUT_CHAN_614750_IDX] = { 24590, 0x1, 0x44, 0x9C71C, 0x801 },
+       [ATHOS_LUT_CHAN_614875_IDX] = { 24595, 0x1, 0x44, 0xA38E4, 0x802 },
+       [ATHOS_LUT_CHAN_615000_IDX] = { 24600, 0x1, 0x44, 0xAAAAB, 0x802 },
+       [ATHOS_LUT_CHAN_615125_IDX] = { 24605, 0x1, 0x44, 0xB1C72, 0x802 },
+       [ATHOS_LUT_CHAN_615250_IDX] = { 24610, 0x1, 0x44, 0xB8E39, 0x803 },
+       [ATHOS_LUT_CHAN_615375_IDX] = { 24615, 0x1, 0x44, 0xC0000, 0x803 },
+       [ATHOS_LUT_CHAN_615500_IDX] = { 24620, 0x1, 0x44, 0xC71C7, 0x804 },
+       [ATHOS_LUT_CHAN_615625_IDX] = { 24625, 0x1, 0x44, 0xCE38E, 0x804 },
+       [ATHOS_LUT_CHAN_615750_IDX] = { 24630, 0x1, 0x44, 0xD5555, 0x805 },
+       [ATHOS_LUT_CHAN_615875_IDX] = { 24635, 0x1, 0x44, 0xDC71C, 0x805 },
+       [ATHOS_LUT_CHAN_616000_IDX] = { 24640, 0x1, 0x44, 0xE38E4, 0x805 },
+       [ATHOS_LUT_CHAN_616125_IDX] = { 24645, 0x1, 0x44, 0xEAAAB, 0x806 },
+       [ATHOS_LUT_CHAN_616250_IDX] = { 24650, 0x1, 0x44, 0xF1C72, 0x806 },
+       [ATHOS_LUT_CHAN_616375_IDX] = { 24655, 0x1, 0x44, 0xF8E39, 0x807 },
+       [ATHOS_LUT_CHAN_616500_IDX] = { 24660, 0x1, 0x44, 0x100000, 0x807 },
+       [ATHOS_LUT_CHAN_616625_IDX] = { 24665, 0x1, 0x44, 0x1071C7, 0x807 },
+       [ATHOS_LUT_CHAN_616750_IDX] = { 24670, 0x1, 0x44, 0x10E38E, 0x808 },
+       [ATHOS_LUT_CHAN_616875_IDX] = { 24675, 0x1, 0x44, 0x115555, 0x808 },
+       [ATHOS_LUT_CHAN_617000_IDX] = { 24680, 0x1, 0x44, 0x11C71C, 0x809 },
+       [ATHOS_LUT_CHAN_617125_IDX] = { 24685, 0x1, 0x44, 0x1238E4, 0x809 },
+       [ATHOS_LUT_CHAN_617250_IDX] = { 24690, 0x1, 0x44, 0x12AAAB, 0x80A },
+       [ATHOS_LUT_CHAN_617375_IDX] = { 24695, 0x1, 0x44, 0x131C72, 0x80A },
+       [ATHOS_LUT_CHAN_617500_IDX] = { 24700, 0x1, 0x44, 0x138E39, 0x80A },
+       [ATHOS_LUT_CHAN_617625_IDX] = { 24705, 0x1, 0x44, 0x140000, 0x80B },
+       [ATHOS_LUT_CHAN_617750_IDX] = { 24710, 0x1, 0x44, 0x1471C7, 0x80B },
+       [ATHOS_LUT_CHAN_617875_IDX] = { 24715, 0x1, 0x44, 0x14E38E, 0x80C },
+       [ATHOS_LUT_CHAN_618000_IDX] = { 24720, 0x1, 0x44, 0x155555, 0x80C },
+       [ATHOS_LUT_CHAN_618125_IDX] = { 24725, 0x1, 0x44, 0x15C71C, 0x80C },
+       [ATHOS_LUT_CHAN_618250_IDX] = { 24730, 0x1, 0x44, 0x1638E4, 0x80D },
+       [ATHOS_LUT_CHAN_618375_IDX] = { 24735, 0x1, 0x44, 0x16AAAB, 0x80D },
+       [ATHOS_LUT_CHAN_618500_IDX] = { 24740, 0x1, 0x44, 0x171C72, 0x80E },
+       [ATHOS_LUT_CHAN_618625_IDX] = { 24745, 0x1, 0x44, 0x178E39, 0x80E },
+       [ATHOS_LUT_CHAN_618750_IDX] = { 24750, 0x1, 0x44, 0x180000, 0x80F },
+       [ATHOS_LUT_CHAN_618875_IDX] = { 24755, 0x1, 0x44, 0x1871C7, 0x80F },
+       [ATHOS_LUT_CHAN_619000_IDX] = { 24760, 0x1, 0x44, 0x18E38E, 0x80F },
+       [ATHOS_LUT_CHAN_619125_IDX] = { 24765, 0x1, 0x44, 0x195555, 0x810 },
+       [ATHOS_LUT_CHAN_619250_IDX] = { 24770, 0x1, 0x44, 0x19C71C, 0x810 },
+       [ATHOS_LUT_CHAN_619375_IDX] = { 24775, 0x1, 0x44, 0x1A38E4, 0x811 },
+       [ATHOS_LUT_CHAN_619500_IDX] = { 24780, 0x1, 0x44, 0x1AAAAB, 0x811 },
+       [ATHOS_LUT_CHAN_619625_IDX] = { 24785, 0x1, 0x44, 0x1B1C72, 0x811 },
+       [ATHOS_LUT_CHAN_619750_IDX] = { 24790, 0x1, 0x44, 0x1B8E39, 0x812 },
+       [ATHOS_LUT_CHAN_619875_IDX] = { 24795, 0x1, 0x44, 0x1C0000, 0x812 },
+       [ATHOS_LUT_CHAN_620000_IDX] = { 24800, 0x1, 0x44, 0x1C71C7, 0x813 },
+       [ATHOS_LUT_CHAN_620125_IDX] = { 24805, 0x1, 0x44, 0x1CE38E, 0x813 },
+       [ATHOS_LUT_CHAN_620250_IDX] = { 24810, 0x1, 0x44, 0x1D5555, 0x814 },
+       [ATHOS_LUT_CHAN_620375_IDX] = { 24815, 0x1, 0x44, 0x1DC71C, 0x814 },
+       [ATHOS_LUT_CHAN_620500_IDX] = { 24820, 0x1, 0x44, 0x1E38E4, 0x814 },
+       [ATHOS_LUT_CHAN_620625_IDX] = { 24825, 0x1, 0x44, 0x1EAAAB, 0x815 },
+       [ATHOS_LUT_CHAN_620750_IDX] = { 24830, 0x1, 0x44, 0x1F1C72, 0x815 },
+       [ATHOS_LUT_CHAN_620875_IDX] = { 24835, 0x1, 0x44, 0x1F8E39, 0x816 },
+       [ATHOS_LUT_CHAN_621000_IDX] = { 24840, 0x1, 0x45, 0x0, 0x816 },
+       [ATHOS_LUT_CHAN_621125_IDX] = { 24845, 0x1, 0x45, 0x71C7, 0x816 },
+       [ATHOS_LUT_CHAN_621250_IDX] = { 24850, 0x1, 0x45, 0xE38E, 0x817 },
+       [ATHOS_LUT_CHAN_621375_IDX] = { 24855, 0x1, 0x45, 0x15555, 0x817 },
+       [ATHOS_LUT_CHAN_621500_IDX] = { 24860, 0x1, 0x45, 0x1C71C, 0x818 },
+       [ATHOS_LUT_CHAN_621625_IDX] = { 24865, 0x1, 0x45, 0x238E4, 0x818 },
+       [ATHOS_LUT_CHAN_621750_IDX] = { 24870, 0x1, 0x45, 0x2AAAB, 0x819 },
+       [ATHOS_LUT_CHAN_621875_IDX] = { 24875, 0x1, 0x45, 0x31C72, 0x819 },
+       [ATHOS_LUT_CHAN_622000_IDX] = { 24880, 0x1, 0x45, 0x38E39, 0x819 },
+       [ATHOS_LUT_CHAN_622125_IDX] = { 24885, 0x1, 0x45, 0x40000, 0x81A },
+       [ATHOS_LUT_CHAN_622250_IDX] = { 24890, 0x1, 0x45, 0x471C7, 0x81A },
+       [ATHOS_LUT_CHAN_622375_IDX] = { 24895, 0x1, 0x45, 0x4E38E, 0x81B },
+       [ATHOS_LUT_CHAN_622500_IDX] = { 24900, 0x1, 0x45, 0x55555, 0x81B },
+       [ATHOS_LUT_CHAN_622625_IDX] = { 24905, 0x1, 0x45, 0x5C71C, 0x81B },
+       [ATHOS_LUT_CHAN_622750_IDX] = { 24910, 0x1, 0x45, 0x638E4, 0x81C },
+       [ATHOS_LUT_CHAN_622875_IDX] = { 24915, 0x1, 0x45, 0x6AAAB, 0x81C },
+       [ATHOS_LUT_CHAN_623000_IDX] = { 24920, 0x1, 0x45, 0x71C72, 0x81D },
+       [ATHOS_LUT_CHAN_623125_IDX] = { 24925, 0x1, 0x45, 0x78E39, 0x81D },
+       [ATHOS_LUT_CHAN_623250_IDX] = { 24930, 0x1, 0x45, 0x80000, 0x81E },
+       [ATHOS_LUT_CHAN_623375_IDX] = { 24935, 0x1, 0x45, 0x871C7, 0x81E },
+       [ATHOS_LUT_CHAN_623500_IDX] = { 24940, 0x1, 0x45, 0x8E38E, 0x81E },
+       [ATHOS_LUT_CHAN_623625_IDX] = { 24945, 0x1, 0x45, 0x95555, 0x81F },
+       [ATHOS_LUT_CHAN_623750_IDX] = { 24950, 0x1, 0x45, 0x9C71C, 0x81F },
+       [ATHOS_LUT_CHAN_623875_IDX] = { 24955, 0x1, 0x45, 0xA38E4, 0x820 },
+       [ATHOS_LUT_CHAN_624000_IDX] = { 24960, 0x1, 0x45, 0xAAAAB, 0x820 },
+       [ATHOS_LUT_CHAN_624125_IDX] = { 24965, 0x1, 0x45, 0xB1C72, 0x820 },
+       [ATHOS_LUT_CHAN_624250_IDX] = { 24970, 0x1, 0x45, 0xB8E39, 0x821 },
+       [ATHOS_LUT_CHAN_624375_IDX] = { 24975, 0x1, 0x45, 0xC0000, 0x821 },
+       [ATHOS_LUT_CHAN_624500_IDX] = { 24980, 0x1, 0x45, 0xC71C7, 0x822 },
+       [ATHOS_LUT_CHAN_624625_IDX] = { 24985, 0x1, 0x45, 0xCE38E, 0x822 },
+       [ATHOS_LUT_CHAN_624750_IDX] = { 24990, 0x1, 0x45, 0xD5555, 0x823 },
+       [ATHOS_LUT_CHAN_624875_IDX] = { 24995, 0x1, 0x45, 0xDC71C, 0x823 },
+       [ATHOS_LUT_CHAN_625000_IDX] = { 25000, 0x1, 0x45, 0xE38E4, 0x823 },
+       [ATHOS_LUT_CHAN_625125_IDX] = { 25005, 0x1, 0x45, 0xEAAAB, 0x824 },
+       [ATHOS_LUT_CHAN_625250_IDX] = { 25010, 0x1, 0x45, 0xF1C72, 0x824 },
+       [ATHOS_LUT_CHAN_625375_IDX] = { 25015, 0x1, 0x45, 0xF8E39, 0x825 },
+       [ATHOS_LUT_CHAN_625500_IDX] = { 25020, 0x1, 0x45, 0x100000, 0x825 },
+       [ATHOS_LUT_CHAN_625625_IDX] = { 25025, 0x1, 0x45, 0x1071C7, 0x825 },
+       [ATHOS_LUT_CHAN_625750_IDX] = { 25030, 0x1, 0x45, 0x10E38E, 0x826 },
+       [ATHOS_LUT_CHAN_625875_IDX] = { 25035, 0x1, 0x45, 0x115555, 0x826 },
+       [ATHOS_LUT_CHAN_626000_IDX] = { 25040, 0x1, 0x45, 0x11C71C, 0x827 },
+       [ATHOS_LUT_CHAN_626125_IDX] = { 25045, 0x1, 0x45, 0x1238E4, 0x827 },
+       [ATHOS_LUT_CHAN_626250_IDX] = { 25050, 0x1, 0x45, 0x12AAAB, 0x828 },
+       [ATHOS_LUT_CHAN_626375_IDX] = { 25055, 0x1, 0x45, 0x131C72, 0x828 },
+       [ATHOS_LUT_CHAN_626500_IDX] = { 25060, 0x1, 0x45, 0x138E39, 0x828 },
+       [ATHOS_LUT_CHAN_626625_IDX] = { 25065, 0x1, 0x45, 0x140000, 0x829 },
+       [ATHOS_LUT_CHAN_626750_IDX] = { 25070, 0x1, 0x45, 0x1471C7, 0x829 },
+       [ATHOS_LUT_CHAN_626875_IDX] = { 25075, 0x1, 0x45, 0x14E38E, 0x82A },
+       [ATHOS_LUT_CHAN_627000_IDX] = { 25080, 0x1, 0x45, 0x155555, 0x82A },
+       [ATHOS_LUT_CHAN_627125_IDX] = { 25085, 0x1, 0x45, 0x15C71C, 0x82A },
+       [ATHOS_LUT_CHAN_627250_IDX] = { 25090, 0x1, 0x45, 0x1638E4, 0x82B },
+       [ATHOS_LUT_CHAN_627375_IDX] = { 25095, 0x1, 0x45, 0x16AAAB, 0x82B },
+       [ATHOS_LUT_CHAN_627500_IDX] = { 25100, 0x1, 0x45, 0x171C72, 0x82C },
+       [ATHOS_LUT_CHAN_627625_IDX] = { 25105, 0x1, 0x45, 0x178E39, 0x82C },
+       [ATHOS_LUT_CHAN_627750_IDX] = { 25110, 0x1, 0x45, 0x180000, 0x82D },
+       [ATHOS_LUT_CHAN_627875_IDX] = { 25115, 0x1, 0x45, 0x1871C7, 0x82D },
+       [ATHOS_LUT_CHAN_628000_IDX] = { 25120, 0x1, 0x45, 0x18E38E, 0x82D },
+       [ATHOS_LUT_CHAN_628125_IDX] = { 25125, 0x1, 0x45, 0x195555, 0x82E },
+       [ATHOS_LUT_CHAN_628250_IDX] = { 25130, 0x1, 0x45, 0x19C71C, 0x82E },
+       [ATHOS_LUT_CHAN_628375_IDX] = { 25135, 0x1, 0x45, 0x1A38E4, 0x82F },
+       [ATHOS_LUT_CHAN_628500_IDX] = { 25140, 0x1, 0x45, 0x1AAAAB, 0x82F },
+       [ATHOS_LUT_CHAN_628625_IDX] = { 25145, 0x1, 0x45, 0x1B1C72, 0x82F },
+       [ATHOS_LUT_CHAN_628750_IDX] = { 25150, 0x1, 0x45, 0x1B8E39, 0x830 },
+       [ATHOS_LUT_CHAN_628875_IDX] = { 25155, 0x1, 0x45, 0x1C0000, 0x830 },
+       [ATHOS_LUT_CHAN_629000_IDX] = { 25160, 0x1, 0x45, 0x1C71C7, 0x831 },
+       [ATHOS_LUT_CHAN_629125_IDX] = { 25165, 0x1, 0x45, 0x1CE38E, 0x831 },
+       [ATHOS_LUT_CHAN_629250_IDX] = { 25170, 0x1, 0x45, 0x1D5555, 0x832 },
+       [ATHOS_LUT_CHAN_629375_IDX] = { 25175, 0x1, 0x45, 0x1DC71C, 0x832 },
+       [ATHOS_LUT_CHAN_629500_IDX] = { 25180, 0x1, 0x45, 0x1E38E4, 0x832 },
+       [ATHOS_LUT_CHAN_629625_IDX] = { 25185, 0x1, 0x45, 0x1EAAAB, 0x833 },
+       [ATHOS_LUT_CHAN_629750_IDX] = { 25190, 0x1, 0x45, 0x1F1C72, 0x833 },
+       [ATHOS_LUT_CHAN_629875_IDX] = { 25195, 0x1, 0x45, 0x1F8E39, 0x834 },
+       [ATHOS_LUT_CHAN_630000_IDX] = { 25200, 0x1, 0x46, 0x0, 0x834 },
+       [ATHOS_LUT_CHAN_630125_IDX] = { 25205, 0x1, 0x46, 0x71C7, 0x834 },
+       [ATHOS_LUT_CHAN_630250_IDX] = { 25210, 0x1, 0x46, 0xE38E, 0x835 },
+       [ATHOS_LUT_CHAN_630375_IDX] = { 25215, 0x1, 0x46, 0x15555, 0x835 },
+       [ATHOS_LUT_CHAN_630500_IDX] = { 25220, 0x1, 0x46, 0x1C71C, 0x836 },
+       [ATHOS_LUT_CHAN_630625_IDX] = { 25225, 0x1, 0x46, 0x238E4, 0x836 },
+       [ATHOS_LUT_CHAN_630750_IDX] = { 25230, 0x1, 0x46, 0x2AAAB, 0x837 },
+       [ATHOS_LUT_CHAN_630875_IDX] = { 25235, 0x1, 0x46, 0x31C72, 0x837 },
+       [ATHOS_LUT_CHAN_631000_IDX] = { 25240, 0x1, 0x46, 0x38E39, 0x837 },
+       [ATHOS_LUT_CHAN_631125_IDX] = { 25245, 0x1, 0x46, 0x40000, 0x838 },
+       [ATHOS_LUT_CHAN_631250_IDX] = { 25250, 0x1, 0x46, 0x471C7, 0x838 },
+       [ATHOS_LUT_CHAN_631375_IDX] = { 25255, 0x1, 0x46, 0x4E38E, 0x839 },
+       [ATHOS_LUT_CHAN_631500_IDX] = { 25260, 0x1, 0x46, 0x55555, 0x839 },
+       [ATHOS_LUT_CHAN_631625_IDX] = { 25265, 0x1, 0x46, 0x5C71C, 0x839 },
+       [ATHOS_LUT_CHAN_631750_IDX] = { 25270, 0x1, 0x46, 0x638E4, 0x83A },
+       [ATHOS_LUT_CHAN_631875_IDX] = { 25275, 0x1, 0x46, 0x6AAAB, 0x83A },
+       [ATHOS_LUT_CHAN_632000_IDX] = { 25280, 0x1, 0x46, 0x71C72, 0x83B },
+       [ATHOS_LUT_CHAN_632125_IDX] = { 25285, 0x1, 0x46, 0x78E39, 0x83B },
+       [ATHOS_LUT_CHAN_632250_IDX] = { 25290, 0x1, 0x46, 0x80000, 0x83C },
+       [ATHOS_LUT_CHAN_632375_IDX] = { 25295, 0x1, 0x46, 0x871C7, 0x83C },
+       [ATHOS_LUT_CHAN_632500_IDX] = { 25300, 0x1, 0x46, 0x8E38E, 0x83C },
+       [ATHOS_LUT_CHAN_632625_IDX] = { 25305, 0x1, 0x46, 0x95555, 0x83D },
+       [ATHOS_LUT_CHAN_632750_IDX] = { 25310, 0x1, 0x46, 0x9C71C, 0x83D },
+       [ATHOS_LUT_CHAN_632875_IDX] = { 25315, 0x1, 0x46, 0xA38E4, 0x83E },
+       [ATHOS_LUT_CHAN_633000_IDX] = { 25320, 0x1, 0x46, 0xAAAAB, 0x83E },
+       [ATHOS_LUT_CHAN_633125_IDX] = { 25325, 0x1, 0x46, 0xB1C72, 0x83E },
+       [ATHOS_LUT_CHAN_633250_IDX] = { 25330, 0x1, 0x46, 0xB8E39, 0x83F },
+       [ATHOS_LUT_CHAN_633375_IDX] = { 25335, 0x1, 0x46, 0xC0000, 0x83F },
+       [ATHOS_LUT_CHAN_633500_IDX] = { 25340, 0x1, 0x46, 0xC71C7, 0x840 },
+       [ATHOS_LUT_CHAN_633625_IDX] = { 25345, 0x1, 0x46, 0xCE38E, 0x840 },
+       [ATHOS_LUT_CHAN_633750_IDX] = { 25350, 0x1, 0x46, 0xD5555, 0x841 },
+       [ATHOS_LUT_CHAN_633875_IDX] = { 25355, 0x1, 0x46, 0xDC71C, 0x841 },
+       [ATHOS_LUT_CHAN_634000_IDX] = { 25360, 0x1, 0x46, 0xE38E4, 0x841 },
+       [ATHOS_LUT_CHAN_634125_IDX] = { 25365, 0x1, 0x46, 0xEAAAB, 0x842 },
+       [ATHOS_LUT_CHAN_634250_IDX] = { 25370, 0x1, 0x46, 0xF1C72, 0x842 },
+       [ATHOS_LUT_CHAN_634375_IDX] = { 25375, 0x1, 0x46, 0xF8E39, 0x843 },
+       [ATHOS_LUT_CHAN_634500_IDX] = { 25380, 0x1, 0x46, 0x100000, 0x843 },
+       [ATHOS_LUT_CHAN_634625_IDX] = { 25385, 0x1, 0x46, 0x1071C7, 0x843 },
+       [ATHOS_LUT_CHAN_634750_IDX] = { 25390, 0x1, 0x46, 0x10E38E, 0x844 },
+       [ATHOS_LUT_CHAN_634875_IDX] = { 25395, 0x1, 0x46, 0x115555, 0x844 },
+       [ATHOS_LUT_CHAN_635000_IDX] = { 25400, 0x1, 0x46, 0x11C71C, 0x845 },
+       [ATHOS_LUT_CHAN_635125_IDX] = { 25405, 0x1, 0x46, 0x1238E4, 0x845 },
+       [ATHOS_LUT_CHAN_635250_IDX] = { 25410, 0x1, 0x46, 0x12AAAB, 0x846 },
+       [ATHOS_LUT_CHAN_635375_IDX] = { 25415, 0x1, 0x46, 0x131C72, 0x846 },
+       [ATHOS_LUT_CHAN_635500_IDX] = { 25420, 0x1, 0x46, 0x138E39, 0x846 },
+       [ATHOS_LUT_CHAN_635625_IDX] = { 25425, 0x1, 0x46, 0x140000, 0x847 },
+       [ATHOS_LUT_CHAN_635750_IDX] = { 25430, 0x1, 0x46, 0x1471C7, 0x847 },
+       [ATHOS_LUT_CHAN_635875_IDX] = { 25435, 0x1, 0x46, 0x14E38E, 0x848 },
+       [ATHOS_LUT_CHAN_636000_IDX] = { 25440, 0x1, 0x46, 0x155555, 0x848 },
+       [ATHOS_LUT_CHAN_636125_IDX] = { 25445, 0x1, 0x46, 0x15C71C, 0x848 },
+       [ATHOS_LUT_CHAN_636250_IDX] = { 25450, 0x1, 0x46, 0x1638E4, 0x849 },
+       [ATHOS_LUT_CHAN_636375_IDX] = { 25455, 0x1, 0x46, 0x16AAAB, 0x849 },
+       [ATHOS_LUT_CHAN_636500_IDX] = { 25460, 0x1, 0x46, 0x171C72, 0x84A },
+       [ATHOS_LUT_CHAN_636625_IDX] = { 25465, 0x1, 0x46, 0x178E39, 0x84A },
+       [ATHOS_LUT_CHAN_636750_IDX] = { 25470, 0x1, 0x46, 0x180000, 0x84B },
+       [ATHOS_LUT_CHAN_636875_IDX] = { 25475, 0x1, 0x46, 0x1871C7, 0x84B },
+       [ATHOS_LUT_CHAN_637000_IDX] = { 25480, 0x1, 0x46, 0x18E38E, 0x84B },
+       [ATHOS_LUT_CHAN_637125_IDX] = { 25485, 0x1, 0x46, 0x195555, 0x84C },
+       [ATHOS_LUT_CHAN_637250_IDX] = { 25490, 0x1, 0x46, 0x19C71C, 0x84C },
+       [ATHOS_LUT_CHAN_637375_IDX] = { 25495, 0x1, 0x46, 0x1A38E4, 0x84D },
+       [ATHOS_LUT_CHAN_637500_IDX] = { 25500, 0x1, 0x46, 0x1AAAAB, 0x84D },
+       [ATHOS_LUT_CHAN_637625_IDX] = { 25505, 0x1, 0x46, 0x1B1C72, 0x84D },
+       [ATHOS_LUT_CHAN_637750_IDX] = { 25510, 0x1, 0x46, 0x1B8E39, 0x84E },
+       [ATHOS_LUT_CHAN_637875_IDX] = { 25515, 0x1, 0x46, 0x1C0000, 0x84E },
+       [ATHOS_LUT_CHAN_638000_IDX] = { 25520, 0x1, 0x46, 0x1C71C7, 0x84F },
+       [ATHOS_LUT_CHAN_638125_IDX] = { 25525, 0x1, 0x46, 0x1CE38E, 0x84F },
+       [ATHOS_LUT_CHAN_638250_IDX] = { 25530, 0x1, 0x46, 0x1D5555, 0x850 },
+       [ATHOS_LUT_CHAN_638375_IDX] = { 25535, 0x1, 0x46, 0x1DC71C, 0x850 },
+       [ATHOS_LUT_CHAN_638500_IDX] = { 25540, 0x1, 0x46, 0x1E38E4, 0x850 },
+       [ATHOS_LUT_CHAN_638625_IDX] = { 25545, 0x1, 0x46, 0x1EAAAB, 0x851 },
+       [ATHOS_LUT_CHAN_638750_IDX] = { 25550, 0x1, 0x46, 0x1F1C72, 0x851 },
+       [ATHOS_LUT_CHAN_638875_IDX] = { 25555, 0x1, 0x46, 0x1F8E39, 0x852 },
+       [ATHOS_LUT_CHAN_639000_IDX] = { 25560, 0x1, 0x47, 0x0, 0x852 },
+       [ATHOS_LUT_CHAN_639125_IDX] = { 25565, 0x1, 0x47, 0x71C7, 0x852 },
+       [ATHOS_LUT_CHAN_639250_IDX] = { 25570, 0x1, 0x47, 0xE38E, 0x853 },
+       [ATHOS_LUT_CHAN_639375_IDX] = { 25575, 0x1, 0x47, 0x15555, 0x853 },
+       [ATHOS_LUT_CHAN_639500_IDX] = { 25580, 0x1, 0x47, 0x1C71C, 0x854 },
+       [ATHOS_LUT_CHAN_639625_IDX] = { 25585, 0x1, 0x47, 0x238E4, 0x854 },
+       [ATHOS_LUT_CHAN_639750_IDX] = { 25590, 0x1, 0x47, 0x2AAAB, 0x855 },
+       [ATHOS_LUT_CHAN_639875_IDX] = { 25595, 0x1, 0x47, 0x31C72, 0x855 },
+       [ATHOS_LUT_CHAN_640000_IDX] = { 25600, 0x1, 0x47, 0x38E39, 0x855 },
+       [ATHOS_LUT_CHAN_640125_IDX] = { 25605, 0x1, 0x47, 0x40000, 0x856 },
+       [ATHOS_LUT_CHAN_640250_IDX] = { 25610, 0x1, 0x47, 0x471C7, 0x856 },
+       [ATHOS_LUT_CHAN_640375_IDX] = { 25615, 0x1, 0x47, 0x4E38E, 0x857 },
+       [ATHOS_LUT_CHAN_640500_IDX] = { 25620, 0x1, 0x47, 0x55555, 0x857 },
+       [ATHOS_LUT_CHAN_640625_IDX] = { 25625, 0x1, 0x47, 0x5C71C, 0x857 },
+       [ATHOS_LUT_CHAN_640750_IDX] = { 25630, 0x1, 0x47, 0x638E4, 0x858 },
+       [ATHOS_LUT_CHAN_640875_IDX] = { 25635, 0x1, 0x47, 0x6AAAB, 0x858 },
+       [ATHOS_LUT_CHAN_641000_IDX] = { 25640, 0x1, 0x47, 0x71C72, 0x859 },
+       [ATHOS_LUT_CHAN_641125_IDX] = { 25645, 0x1, 0x47, 0x78E39, 0x859 },
+       [ATHOS_LUT_CHAN_641250_IDX] = { 25650, 0x1, 0x47, 0x80000, 0x85A },
+       [ATHOS_LUT_CHAN_641375_IDX] = { 25655, 0x1, 0x47, 0x871C7, 0x85A },
+       [ATHOS_LUT_CHAN_641500_IDX] = { 25660, 0x1, 0x47, 0x8E38E, 0x85A },
+       [ATHOS_LUT_CHAN_641625_IDX] = { 25665, 0x1, 0x47, 0x95555, 0x85B },
+       [ATHOS_LUT_CHAN_641750_IDX] = { 25670, 0x1, 0x47, 0x9C71C, 0x85B },
+       [ATHOS_LUT_CHAN_641875_IDX] = { 25675, 0x1, 0x47, 0xA38E4, 0x85C },
+       [ATHOS_LUT_CHAN_642000_IDX] = { 25680, 0x1, 0x47, 0xAAAAB, 0x85C },
+       [ATHOS_LUT_CHAN_642125_IDX] = { 25685, 0x1, 0x47, 0xB1C72, 0x85C },
+       [ATHOS_LUT_CHAN_642250_IDX] = { 25690, 0x1, 0x47, 0xB8E39, 0x85D },
+       [ATHOS_LUT_CHAN_642375_IDX] = { 25695, 0x1, 0x47, 0xC0000, 0x85D },
+       [ATHOS_LUT_CHAN_642500_IDX] = { 25700, 0x1, 0x47, 0xC71C7, 0x85E },
+       [ATHOS_LUT_CHAN_642625_IDX] = { 25705, 0x1, 0x47, 0xCE38E, 0x85E },
+       [ATHOS_LUT_CHAN_642750_IDX] = { 25710, 0x1, 0x47, 0xD5555, 0x85F },
+       [ATHOS_LUT_CHAN_642875_IDX] = { 25715, 0x1, 0x47, 0xDC71C, 0x85F },
+       [ATHOS_LUT_CHAN_643000_IDX] = { 25720, 0x1, 0x47, 0xE38E4, 0x85F },
+       [ATHOS_LUT_CHAN_643125_IDX] = { 25725, 0x1, 0x47, 0xEAAAB, 0x860 },
+       [ATHOS_LUT_CHAN_643250_IDX] = { 25730, 0x1, 0x47, 0xF1C72, 0x860 },
+       [ATHOS_LUT_CHAN_643375_IDX] = { 25735, 0x1, 0x47, 0xF8E39, 0x861 },
+       [ATHOS_LUT_CHAN_643500_IDX] = { 25740, 0x1, 0x47, 0x100000, 0x861 },
+       [ATHOS_LUT_CHAN_643625_IDX] = { 25745, 0x1, 0x47, 0x1071C7, 0x861 },
+       [ATHOS_LUT_CHAN_643750_IDX] = { 25750, 0x1, 0x47, 0x10E38E, 0x862 },
+       [ATHOS_LUT_CHAN_643875_IDX] = { 25755, 0x1, 0x47, 0x115555, 0x862 },
+       [ATHOS_LUT_CHAN_644000_IDX] = { 25760, 0x1, 0x47, 0x11C71C, 0x863 },
+       [ATHOS_LUT_CHAN_644125_IDX] = { 25765, 0x1, 0x47, 0x1238E4, 0x863 },
+       [ATHOS_LUT_CHAN_644250_IDX] = { 25770, 0x1, 0x47, 0x12AAAB, 0x864 },
+       [ATHOS_LUT_CHAN_644375_IDX] = { 25775, 0x1, 0x47, 0x131C72, 0x864 },
+       [ATHOS_LUT_CHAN_644500_IDX] = { 25780, 0x1, 0x47, 0x138E39, 0x864 },
+       [ATHOS_LUT_CHAN_644625_IDX] = { 25785, 0x1, 0x47, 0x140000, 0x865 },
+       [ATHOS_LUT_CHAN_644750_IDX] = { 25790, 0x1, 0x47, 0x1471C7, 0x865 },
+       [ATHOS_LUT_CHAN_644875_IDX] = { 25795, 0x1, 0x47, 0x14E38E, 0x866 },
+       [ATHOS_LUT_CHAN_645000_IDX] = { 25800, 0x1, 0x47, 0x155555, 0x866 },
+       [ATHOS_LUT_CHAN_645125_IDX] = { 25805, 0x1, 0x47, 0x15C71C, 0x866 },
+       [ATHOS_LUT_CHAN_645250_IDX] = { 25810, 0x1, 0x47, 0x1638E4, 0x867 },
+       [ATHOS_LUT_CHAN_645375_IDX] = { 25815, 0x1, 0x47, 0x16AAAB, 0x867 },
+       [ATHOS_LUT_CHAN_645500_IDX] = { 25820, 0x1, 0x47, 0x171C72, 0x868 },
+       [ATHOS_LUT_CHAN_645625_IDX] = { 25825, 0x1, 0x47, 0x178E39, 0x868 },
+       [ATHOS_LUT_CHAN_645750_IDX] = { 25830, 0x1, 0x47, 0x180000, 0x869 },
+       [ATHOS_LUT_CHAN_645875_IDX] = { 25835, 0x1, 0x47, 0x1871C7, 0x869 },
+       [ATHOS_LUT_CHAN_646000_IDX] = { 25840, 0x1, 0x47, 0x18E38E, 0x869 },
+       [ATHOS_LUT_CHAN_646125_IDX] = { 25845, 0x1, 0x47, 0x195555, 0x86A },
+       [ATHOS_LUT_CHAN_646250_IDX] = { 25850, 0x1, 0x47, 0x19C71C, 0x86A },
+       [ATHOS_LUT_CHAN_646375_IDX] = { 25855, 0x1, 0x47, 0x1A38E4, 0x86B },
+       [ATHOS_LUT_CHAN_646500_IDX] = { 25860, 0x1, 0x47, 0x1AAAAB, 0x86B },
+       [ATHOS_LUT_CHAN_646625_IDX] = { 25865, 0x1, 0x47, 0x1B1C72, 0x86B },
+       [ATHOS_LUT_CHAN_646750_IDX] = { 25870, 0x1, 0x47, 0x1B8E39, 0x86C },
+       [ATHOS_LUT_CHAN_646875_IDX] = { 25875, 0x1, 0x47, 0x1C0000, 0x86C },
+       [ATHOS_LUT_CHAN_647000_IDX] = { 25880, 0x1, 0x47, 0x1C71C7, 0x86D },
+       [ATHOS_LUT_CHAN_647125_IDX] = { 25885, 0x1, 0x47, 0x1CE38E, 0x86D },
+       [ATHOS_LUT_CHAN_647250_IDX] = { 25890, 0x1, 0x47, 0x1D5555, 0x86E },
+       [ATHOS_LUT_CHAN_647375_IDX] = { 25895, 0x1, 0x47, 0x1DC71C, 0x86E },
+       [ATHOS_LUT_CHAN_647500_IDX] = { 25900, 0x1, 0x47, 0x1E38E4, 0x86E },
+       [ATHOS_LUT_CHAN_647625_IDX] = { 25905, 0x1, 0x47, 0x1EAAAB, 0x86F },
+       [ATHOS_LUT_CHAN_647750_IDX] = { 25910, 0x1, 0x47, 0x1F1C72, 0x86F },
+       [ATHOS_LUT_CHAN_647875_IDX] = { 25915, 0x1, 0x47, 0x1F8E39, 0x870 },
+       [ATHOS_LUT_CHAN_648000_IDX] = { 25920, 0x1, 0x48, 0x0, 0x870 },
+       [ATHOS_LUT_CHAN_648125_IDX] = { 25925, 0x1, 0x48, 0x71C7, 0x870 },
+       [ATHOS_LUT_CHAN_648250_IDX] = { 25930, 0x1, 0x48, 0xE38E, 0x871 },
+       [ATHOS_LUT_CHAN_648375_IDX] = { 25935, 0x1, 0x48, 0x15555, 0x871 },
+       [ATHOS_LUT_CHAN_648500_IDX] = { 25940, 0x1, 0x48, 0x1C71C, 0x872 },
+       [ATHOS_LUT_CHAN_648625_IDX] = { 25945, 0x1, 0x48, 0x238E4, 0x872 },
+       [ATHOS_LUT_CHAN_648750_IDX] = { 25950, 0x1, 0x48, 0x2AAAB, 0x873 },
+       [ATHOS_LUT_CHAN_648875_IDX] = { 25955, 0x1, 0x48, 0x31C72, 0x873 },
+       [ATHOS_LUT_CHAN_649000_IDX] = { 25960, 0x1, 0x48, 0x38E39, 0x873 },
+       [ATHOS_LUT_CHAN_649125_IDX] = { 25965, 0x1, 0x48, 0x40000, 0x874 },
+       [ATHOS_LUT_CHAN_649250_IDX] = { 25970, 0x1, 0x48, 0x471C7, 0x874 },
+       [ATHOS_LUT_CHAN_649375_IDX] = { 25975, 0x1, 0x48, 0x4E38E, 0x875 },
+       [ATHOS_LUT_CHAN_649500_IDX] = { 25980, 0x1, 0x48, 0x55555, 0x875 },
+       [ATHOS_LUT_CHAN_649625_IDX] = { 25985, 0x1, 0x48, 0x5C71C, 0x875 },
+       [ATHOS_LUT_CHAN_649750_IDX] = { 25990, 0x1, 0x48, 0x638E4, 0x876 },
+       [ATHOS_LUT_CHAN_649875_IDX] = { 25995, 0x1, 0x48, 0x6AAAB, 0x876 },
+       [ATHOS_LUT_CHAN_650000_IDX] = { 26000, 0x1, 0x48, 0x71C72, 0x877 },
+       [ATHOS_LUT_CHAN_650125_IDX] = { 26005, 0x1, 0x48, 0x78E39, 0x877 },
+       [ATHOS_LUT_CHAN_650250_IDX] = { 26010, 0x1, 0x48, 0x80000, 0x878 },
+       [ATHOS_LUT_CHAN_650375_IDX] = { 26015, 0x1, 0x48, 0x871C7, 0x878 },
+       [ATHOS_LUT_CHAN_650500_IDX] = { 26020, 0x1, 0x48, 0x8E38E, 0x878 },
+       [ATHOS_LUT_CHAN_650625_IDX] = { 26025, 0x1, 0x48, 0x95555, 0x879 },
+       [ATHOS_LUT_CHAN_650750_IDX] = { 26030, 0x1, 0x48, 0x9C71C, 0x879 },
+       [ATHOS_LUT_CHAN_650875_IDX] = { 26035, 0x1, 0x48, 0xA38E4, 0x87A },
+       [ATHOS_LUT_CHAN_651000_IDX] = { 26040, 0x1, 0x48, 0xAAAAB, 0x87A },
+       [ATHOS_LUT_CHAN_651125_IDX] = { 26045, 0x1, 0x48, 0xB1C72, 0x87A },
+       [ATHOS_LUT_CHAN_651250_IDX] = { 26050, 0x1, 0x48, 0xB8E39, 0x87B },
+       [ATHOS_LUT_CHAN_651375_IDX] = { 26055, 0x1, 0x48, 0xC0000, 0x87B },
+       [ATHOS_LUT_CHAN_651500_IDX] = { 26060, 0x1, 0x48, 0xC71C7, 0x87C },
+       [ATHOS_LUT_CHAN_651625_IDX] = { 26065, 0x1, 0x48, 0xCE38E, 0x87C },
+       [ATHOS_LUT_CHAN_651750_IDX] = { 26070, 0x1, 0x48, 0xD5555, 0x87D },
+       [ATHOS_LUT_CHAN_651875_IDX] = { 26075, 0x1, 0x48, 0xDC71C, 0x87D },
+       [ATHOS_LUT_CHAN_652000_IDX] = { 26080, 0x1, 0x48, 0xE38E4, 0x87D },
+       [ATHOS_LUT_CHAN_652125_IDX] = { 26085, 0x1, 0x48, 0xEAAAB, 0x87E },
+       [ATHOS_LUT_CHAN_652250_IDX] = { 26090, 0x1, 0x48, 0xF1C72, 0x87E },
+       [ATHOS_LUT_CHAN_652375_IDX] = { 26095, 0x1, 0x48, 0xF8E39, 0x87F },
+       [ATHOS_LUT_CHAN_652500_IDX] = { 26100, 0x1, 0x48, 0x100000, 0x87F },
+       [ATHOS_LUT_CHAN_652625_IDX] = { 26105, 0x1, 0x48, 0x1071C7, 0x87F },
+       [ATHOS_LUT_CHAN_652750_IDX] = { 26110, 0x1, 0x48, 0x10E38E, 0x880 },
+       [ATHOS_LUT_CHAN_652875_IDX] = { 26115, 0x1, 0x48, 0x115555, 0x880 },
+       [ATHOS_LUT_CHAN_653000_IDX] = { 26120, 0x1, 0x48, 0x11C71C, 0x881 },
+       [ATHOS_LUT_CHAN_653125_IDX] = { 26125, 0x1, 0x48, 0x1238E4, 0x881 },
+       [ATHOS_LUT_CHAN_653250_IDX] = { 26130, 0x1, 0x48, 0x12AAAB, 0x882 },
+       [ATHOS_LUT_CHAN_653375_IDX] = { 26135, 0x1, 0x48, 0x131C72, 0x882 },
+       [ATHOS_LUT_CHAN_653500_IDX] = { 26140, 0x1, 0x48, 0x138E39, 0x882 },
+       [ATHOS_LUT_CHAN_653625_IDX] = { 26145, 0x1, 0x48, 0x140000, 0x883 },
+       [ATHOS_LUT_CHAN_653750_IDX] = { 26150, 0x1, 0x48, 0x1471C7, 0x883 },
+       [ATHOS_LUT_CHAN_653875_IDX] = { 26155, 0x1, 0x48, 0x14E38E, 0x884 },
+       [ATHOS_LUT_CHAN_654000_IDX] = { 26160, 0x1, 0x48, 0x155555, 0x884 },
+       [ATHOS_LUT_CHAN_654125_IDX] = { 26165, 0x1, 0x48, 0x15C71C, 0x884 },
+       [ATHOS_LUT_CHAN_654250_IDX] = { 26170, 0x1, 0x48, 0x1638E4, 0x885 },
+       [ATHOS_LUT_CHAN_654375_IDX] = { 26175, 0x1, 0x48, 0x16AAAB, 0x885 },
+       [ATHOS_LUT_CHAN_654500_IDX] = { 26180, 0x1, 0x48, 0x171C72, 0x886 },
+       [ATHOS_LUT_CHAN_654625_IDX] = { 26185, 0x1, 0x48, 0x178E39, 0x886 },
+       [ATHOS_LUT_CHAN_654750_IDX] = { 26190, 0x1, 0x48, 0x180000, 0x887 },
+       [ATHOS_LUT_CHAN_654875_IDX] = { 26195, 0x1, 0x48, 0x1871C7, 0x887 },
+       [ATHOS_LUT_CHAN_655000_IDX] = { 26200, 0x1, 0x48, 0x18E38E, 0x887 },
+       [ATHOS_LUT_CHAN_655125_IDX] = { 26205, 0x1, 0x48, 0x195555, 0x888 },
+       [ATHOS_LUT_CHAN_655250_IDX] = { 26210, 0x1, 0x48, 0x19C71C, 0x888 },
+       [ATHOS_LUT_CHAN_655375_IDX] = { 26215, 0x1, 0x48, 0x1A38E4, 0x889 },
+       [ATHOS_LUT_CHAN_655500_IDX] = { 26220, 0x1, 0x48, 0x1AAAAB, 0x889 },
+       [ATHOS_LUT_CHAN_655625_IDX] = { 26225, 0x1, 0x48, 0x1B1C72, 0x889 },
+       [ATHOS_LUT_CHAN_655750_IDX] = { 26230, 0x1, 0x48, 0x1B8E39, 0x88A },
+       [ATHOS_LUT_CHAN_655875_IDX] = { 26235, 0x1, 0x48, 0x1C0000, 0x88A },
+       [ATHOS_LUT_CHAN_656000_IDX] = { 26240, 0x1, 0x48, 0x1C71C7, 0x88B },
+       [ATHOS_LUT_CHAN_656125_IDX] = { 26245, 0x1, 0x48, 0x1CE38E, 0x88B },
+       [ATHOS_LUT_CHAN_656250_IDX] = { 26250, 0x1, 0x48, 0x1D5555, 0x88C },
+       [ATHOS_LUT_CHAN_656375_IDX] = { 26255, 0x1, 0x48, 0x1DC71C, 0x88C },
+       [ATHOS_LUT_CHAN_656500_IDX] = { 26260, 0x1, 0x48, 0x1E38E4, 0x88C },
+       [ATHOS_LUT_CHAN_656625_IDX] = { 26265, 0x1, 0x48, 0x1EAAAB, 0x88D },
+       [ATHOS_LUT_CHAN_656750_IDX] = { 26270, 0x1, 0x48, 0x1F1C72, 0x88D },
+       [ATHOS_LUT_CHAN_656875_IDX] = { 26275, 0x1, 0x48, 0x1F8E39, 0x88E },
+       [ATHOS_LUT_CHAN_657000_IDX] = { 26280, 0x1, 0x49, 0x0, 0x88E },
+       [ATHOS_LUT_CHAN_657125_IDX] = { 26285, 0x1, 0x49, 0x71C7, 0x88E },
+       [ATHOS_LUT_CHAN_657250_IDX] = { 26290, 0x1, 0x49, 0xE38E, 0x88F },
+       [ATHOS_LUT_CHAN_657375_IDX] = { 26295, 0x1, 0x49, 0x15555, 0x88F },
+       [ATHOS_LUT_CHAN_657500_IDX] = { 26300, 0x1, 0x49, 0x1C71C, 0x890 },
+       [ATHOS_LUT_CHAN_657625_IDX] = { 26305, 0x1, 0x49, 0x238E4, 0x890 },
+       [ATHOS_LUT_CHAN_657750_IDX] = { 26310, 0x1, 0x49, 0x2AAAB, 0x891 },
+       [ATHOS_LUT_CHAN_657875_IDX] = { 26315, 0x1, 0x49, 0x31C72, 0x891 },
+       [ATHOS_LUT_CHAN_658000_IDX] = { 26320, 0x1, 0x49, 0x38E39, 0x891 },
+       [ATHOS_LUT_CHAN_658125_IDX] = { 26325, 0x1, 0x49, 0x40000, 0x892 },
+       [ATHOS_LUT_CHAN_658250_IDX] = { 26330, 0x1, 0x49, 0x471C7, 0x892 },
+       [ATHOS_LUT_CHAN_658375_IDX] = { 26335, 0x1, 0x49, 0x4E38E, 0x893 },
+       [ATHOS_LUT_CHAN_658500_IDX] = { 26340, 0x1, 0x49, 0x55555, 0x893 },
+       [ATHOS_LUT_CHAN_658625_IDX] = { 26345, 0x1, 0x49, 0x5C71C, 0x893 },
+       [ATHOS_LUT_CHAN_658750_IDX] = { 26350, 0x1, 0x49, 0x638E4, 0x894 },
+       [ATHOS_LUT_CHAN_658875_IDX] = { 26355, 0x1, 0x49, 0x6AAAB, 0x894 },
+       [ATHOS_LUT_CHAN_659000_IDX] = { 26360, 0x1, 0x49, 0x71C72, 0x895 },
+       [ATHOS_LUT_CHAN_659125_IDX] = { 26365, 0x1, 0x49, 0x78E39, 0x895 },
+       [ATHOS_LUT_CHAN_659250_IDX] = { 26370, 0x1, 0x49, 0x80000, 0x896 },
+       [ATHOS_LUT_CHAN_659375_IDX] = { 26375, 0x1, 0x49, 0x871C7, 0x896 },
+       [ATHOS_LUT_CHAN_659500_IDX] = { 26380, 0x1, 0x49, 0x8E38E, 0x896 },
+       [ATHOS_LUT_CHAN_659625_IDX] = { 26385, 0x1, 0x49, 0x95555, 0x897 },
+       [ATHOS_LUT_CHAN_659750_IDX] = { 26390, 0x1, 0x49, 0x9C71C, 0x897 },
+       [ATHOS_LUT_CHAN_659875_IDX] = { 26395, 0x1, 0x49, 0xA38E4, 0x898 },
+       [ATHOS_LUT_CHAN_660000_IDX] = { 26400, 0x1, 0x49, 0xAAAAB, 0x898 },
+       [ATHOS_LUT_CHAN_660125_IDX] = { 26405, 0x1, 0x49, 0xB1C72, 0x898 },
+       [ATHOS_LUT_CHAN_660250_IDX] = { 26410, 0x1, 0x49, 0xB8E39, 0x899 },
+       [ATHOS_LUT_CHAN_660375_IDX] = { 26415, 0x1, 0x49, 0xC0000, 0x899 },
+       [ATHOS_LUT_CHAN_660500_IDX] = { 26420, 0x1, 0x49, 0xC71C7, 0x89A },
+       [ATHOS_LUT_CHAN_660625_IDX] = { 26425, 0x1, 0x49, 0xCE38E, 0x89A },
+       [ATHOS_LUT_CHAN_660750_IDX] = { 26430, 0x1, 0x49, 0xD5555, 0x89B },
+       [ATHOS_LUT_CHAN_660875_IDX] = { 26435, 0x1, 0x49, 0xDC71C, 0x89B },
+       [ATHOS_LUT_CHAN_661000_IDX] = { 26440, 0x1, 0x49, 0xE38E4, 0x89B },
+       [ATHOS_LUT_CHAN_661125_IDX] = { 26445, 0x1, 0x49, 0xEAAAB, 0x89C },
+       [ATHOS_LUT_CHAN_661250_IDX] = { 26450, 0x1, 0x49, 0xF1C72, 0x89C },
+       [ATHOS_LUT_CHAN_661375_IDX] = { 26455, 0x1, 0x49, 0xF8E39, 0x89D },
+       [ATHOS_LUT_CHAN_661500_IDX] = { 26460, 0x1, 0x49, 0x100000, 0x89D },
+       [ATHOS_LUT_CHAN_661625_IDX] = { 26465, 0x1, 0x49, 0x1071C7, 0x89D },
+       [ATHOS_LUT_CHAN_661750_IDX] = { 26470, 0x1, 0x49, 0x10E38E, 0x89E },
+       [ATHOS_LUT_CHAN_661875_IDX] = { 26475, 0x1, 0x49, 0x115555, 0x89E },
+       [ATHOS_LUT_CHAN_662000_IDX] = { 26480, 0x1, 0x49, 0x11C71C, 0x89F },
+       [ATHOS_LUT_CHAN_662125_IDX] = { 26485, 0x1, 0x49, 0x1238E4, 0x89F },
+       [ATHOS_LUT_CHAN_662250_IDX] = { 26490, 0x1, 0x49, 0x12AAAB, 0x8A0 },
+       [ATHOS_LUT_CHAN_662375_IDX] = { 26495, 0x1, 0x49, 0x131C72, 0x8A0 },
+       [ATHOS_LUT_CHAN_662500_IDX] = { 26500, 0x1, 0x49, 0x138E39, 0x8A0 },
+       [ATHOS_LUT_CHAN_662625_IDX] = { 26505, 0x1, 0x49, 0x140000, 0x8A1 },
+       [ATHOS_LUT_CHAN_662750_IDX] = { 26510, 0x1, 0x49, 0x1471C7, 0x8A1 },
+       [ATHOS_LUT_CHAN_662875_IDX] = { 26515, 0x1, 0x49, 0x14E38E, 0x8A2 },
+       [ATHOS_LUT_CHAN_663000_IDX] = { 26520, 0x1, 0x49, 0x155555, 0x8A2 },
+       [ATHOS_LUT_CHAN_663125_IDX] = { 26525, 0x1, 0x49, 0x15C71C, 0x8A2 },
+       [ATHOS_LUT_CHAN_663250_IDX] = { 26530, 0x1, 0x49, 0x1638E4, 0x8A3 },
+       [ATHOS_LUT_CHAN_663375_IDX] = { 26535, 0x1, 0x49, 0x16AAAB, 0x8A3 },
+       [ATHOS_LUT_CHAN_663500_IDX] = { 26540, 0x1, 0x49, 0x171C72, 0x8A4 },
+       [ATHOS_LUT_CHAN_663625_IDX] = { 26545, 0x1, 0x49, 0x178E39, 0x8A4 },
+       [ATHOS_LUT_CHAN_663750_IDX] = { 26550, 0x1, 0x49, 0x180000, 0x8A5 },
+       [ATHOS_LUT_CHAN_663875_IDX] = { 26555, 0x1, 0x49, 0x1871C7, 0x8A5 },
+       [ATHOS_LUT_CHAN_664000_IDX] = { 26560, 0x1, 0x49, 0x18E38E, 0x8A5 },
+       [ATHOS_LUT_CHAN_664125_IDX] = { 26565, 0x1, 0x49, 0x195555, 0x8A6 },
+       [ATHOS_LUT_CHAN_664250_IDX] = { 26570, 0x1, 0x49, 0x19C71C, 0x8A6 },
+       [ATHOS_LUT_CHAN_664375_IDX] = { 26575, 0x1, 0x49, 0x1A38E4, 0x8A7 },
+       [ATHOS_LUT_CHAN_664500_IDX] = { 26580, 0x1, 0x49, 0x1AAAAB, 0x8A7 },
+       [ATHOS_LUT_CHAN_664625_IDX] = { 26585, 0x1, 0x49, 0x1B1C72, 0x8A7 },
+       [ATHOS_LUT_CHAN_664750_IDX] = { 26590, 0x1, 0x49, 0x1B8E39, 0x8A8 },
+       [ATHOS_LUT_CHAN_664875_IDX] = { 26595, 0x1, 0x49, 0x1C0000, 0x8A8 },
+       [ATHOS_LUT_CHAN_665000_IDX] = { 26600, 0x1, 0x49, 0x1C71C7, 0x8A9 },
+       [ATHOS_LUT_CHAN_665125_IDX] = { 26605, 0x1, 0x49, 0x1CE38E, 0x8A9 },
+       [ATHOS_LUT_CHAN_665250_IDX] = { 26610, 0x1, 0x49, 0x1D5555, 0x8AA },
+       [ATHOS_LUT_CHAN_665375_IDX] = { 26615, 0x1, 0x49, 0x1DC71C, 0x8AA },
+       [ATHOS_LUT_CHAN_665500_IDX] = { 26620, 0x1, 0x49, 0x1E38E4, 0x8AA },
+       [ATHOS_LUT_CHAN_665625_IDX] = { 26625, 0x1, 0x49, 0x1EAAAB, 0x8AB },
+       [ATHOS_LUT_CHAN_665750_IDX] = { 26630, 0x1, 0x49, 0x1F1C72, 0x8AB },
+       [ATHOS_LUT_CHAN_665875_IDX] = { 26635, 0x1, 0x49, 0x1F8E39, 0x8AC },
+       [ATHOS_LUT_CHAN_666000_IDX] = { 26640, 0x1, 0x4A, 0x0, 0x8AC },
+       [ATHOS_LUT_CHAN_666125_IDX] = { 26645, 0x1, 0x4A, 0x71C7, 0x8AC },
+       [ATHOS_LUT_CHAN_666250_IDX] = { 26650, 0x1, 0x4A, 0xE38E, 0x8AD },
+       [ATHOS_LUT_CHAN_666375_IDX] = { 26655, 0x1, 0x4A, 0x15555, 0x8AD },
+       [ATHOS_LUT_CHAN_666500_IDX] = { 26660, 0x1, 0x4A, 0x1C71C, 0x8AE },
+       [ATHOS_LUT_CHAN_666625_IDX] = { 26665, 0x1, 0x4A, 0x238E4, 0x8AE },
+       [ATHOS_LUT_CHAN_666750_IDX] = { 26670, 0x1, 0x4A, 0x2AAAB, 0x8AF },
+       [ATHOS_LUT_CHAN_666875_IDX] = { 26675, 0x1, 0x4A, 0x31C72, 0x8AF },
+       [ATHOS_LUT_CHAN_667000_IDX] = { 26680, 0x1, 0x4A, 0x38E39, 0x8AF },
+       [ATHOS_LUT_CHAN_667125_IDX] = { 26685, 0x1, 0x4A, 0x40000, 0x8B0 },
+       [ATHOS_LUT_CHAN_667250_IDX] = { 26690, 0x1, 0x4A, 0x471C7, 0x8B0 },
+       [ATHOS_LUT_CHAN_667375_IDX] = { 26695, 0x1, 0x4A, 0x4E38E, 0x8B1 },
+       [ATHOS_LUT_CHAN_667500_IDX] = { 26700, 0x1, 0x4A, 0x55555, 0x8B1 },
+       [ATHOS_LUT_CHAN_667625_IDX] = { 26705, 0x1, 0x4A, 0x5C71C, 0x8B1 },
+       [ATHOS_LUT_CHAN_667750_IDX] = { 26710, 0x1, 0x4A, 0x638E4, 0x8B2 },
+       [ATHOS_LUT_CHAN_667875_IDX] = { 26715, 0x1, 0x4A, 0x6AAAB, 0x8B2 },
+       [ATHOS_LUT_CHAN_668000_IDX] = { 26720, 0x1, 0x4A, 0x71C72, 0x8B3 },
+       [ATHOS_LUT_CHAN_668125_IDX] = { 26725, 0x1, 0x4A, 0x78E39, 0x8B3 },
+       [ATHOS_LUT_CHAN_668250_IDX] = { 26730, 0x1, 0x4A, 0x80000, 0x8B4 },
+       [ATHOS_LUT_CHAN_668375_IDX] = { 26735, 0x1, 0x4A, 0x871C7, 0x8B4 },
+       [ATHOS_LUT_CHAN_668500_IDX] = { 26740, 0x1, 0x4A, 0x8E38E, 0x8B4 },
+       [ATHOS_LUT_CHAN_668625_IDX] = { 26745, 0x1, 0x4A, 0x95555, 0x8B5 },
+       [ATHOS_LUT_CHAN_668750_IDX] = { 26750, 0x1, 0x4A, 0x9C71C, 0x8B5 },
+       [ATHOS_LUT_CHAN_668875_IDX] = { 26755, 0x1, 0x4A, 0xA38E4, 0x8B6 },
+       [ATHOS_LUT_CHAN_669000_IDX] = { 26760, 0x1, 0x4A, 0xAAAAB, 0x8B6 },
+       [ATHOS_LUT_CHAN_669125_IDX] = { 26765, 0x1, 0x4A, 0xB1C72, 0x8B6 },
+       [ATHOS_LUT_CHAN_669250_IDX] = { 26770, 0x1, 0x4A, 0xB8E39, 0x8B7 },
+       [ATHOS_LUT_CHAN_669375_IDX] = { 26775, 0x1, 0x4A, 0xC0000, 0x8B7 },
+       [ATHOS_LUT_CHAN_669500_IDX] = { 26780, 0x1, 0x4A, 0xC71C7, 0x8B8 },
+       [ATHOS_LUT_CHAN_669625_IDX] = { 26785, 0x1, 0x4A, 0xCE38E, 0x8B8 },
+       [ATHOS_LUT_CHAN_669750_IDX] = { 26790, 0x1, 0x4A, 0xD5555, 0x8B9 },
+       [ATHOS_LUT_CHAN_669875_IDX] = { 26795, 0x1, 0x4A, 0xDC71C, 0x8B9 },
+       [ATHOS_LUT_CHAN_670000_IDX] = { 26800, 0x1, 0x4A, 0xE38E4, 0x8B9 },
+       [ATHOS_LUT_CHAN_670125_IDX] = { 26805, 0x1, 0x4A, 0xEAAAB, 0x8BA },
+       [ATHOS_LUT_CHAN_670250_IDX] = { 26810, 0x1, 0x4A, 0xF1C72, 0x8BA },
+       [ATHOS_LUT_CHAN_670375_IDX] = { 26815, 0x1, 0x4A, 0xF8E39, 0x8BB },
+       [ATHOS_LUT_CHAN_670500_IDX] = { 26820, 0x1, 0x4A, 0x100000, 0x8BB },
+       [ATHOS_LUT_CHAN_670625_IDX] = { 26825, 0x1, 0x4A, 0x1071C7, 0x8BB },
+       [ATHOS_LUT_CHAN_670750_IDX] = { 26830, 0x1, 0x4A, 0x10E38E, 0x8BC },
+       [ATHOS_LUT_CHAN_670875_IDX] = { 26835, 0x1, 0x4A, 0x115555, 0x8BC },
+       [ATHOS_LUT_CHAN_671000_IDX] = { 26840, 0x1, 0x4A, 0x11C71C, 0x8BD },
+       [ATHOS_LUT_CHAN_671125_IDX] = { 26845, 0x1, 0x4A, 0x1238E4, 0x8BD },
+       [ATHOS_LUT_CHAN_671250_IDX] = { 26850, 0x1, 0x4A, 0x12AAAB, 0x8BE },
+       [ATHOS_LUT_CHAN_671375_IDX] = { 26855, 0x1, 0x4A, 0x131C72, 0x8BE },
+       [ATHOS_LUT_CHAN_671500_IDX] = { 26860, 0x1, 0x4A, 0x138E39, 0x8BE },
+       [ATHOS_LUT_CHAN_671625_IDX] = { 26865, 0x1, 0x4A, 0x140000, 0x8BF },
+       [ATHOS_LUT_CHAN_671750_IDX] = { 26870, 0x1, 0x4A, 0x1471C7, 0x8BF },
+       [ATHOS_LUT_CHAN_671875_IDX] = { 26875, 0x1, 0x4A, 0x14E38E, 0x8C0 },
+       [ATHOS_LUT_CHAN_672000_IDX] = { 26880, 0x1, 0x4A, 0x155555, 0x8C0 },
+       [ATHOS_LUT_CHAN_672125_IDX] = { 26885, 0x1, 0x4A, 0x15C71C, 0x8C0 },
+       [ATHOS_LUT_CHAN_672250_IDX] = { 26890, 0x1, 0x4A, 0x1638E4, 0x8C1 },
+       [ATHOS_LUT_CHAN_672375_IDX] = { 26895, 0x1, 0x4A, 0x16AAAB, 0x8C1 },
+       [ATHOS_LUT_CHAN_672500_IDX] = { 26900, 0x1, 0x4A, 0x171C72, 0x8C2 },
+       [ATHOS_LUT_CHAN_672625_IDX] = { 26905, 0x1, 0x4A, 0x178E39, 0x8C2 },
+       [ATHOS_LUT_CHAN_672750_IDX] = { 26910, 0x1, 0x4A, 0x180000, 0x8C3 },
+       [ATHOS_LUT_CHAN_672875_IDX] = { 26915, 0x1, 0x4A, 0x1871C7, 0x8C3 },
+       [ATHOS_LUT_CHAN_673000_IDX] = { 26920, 0x1, 0x4A, 0x18E38E, 0x8C3 },
+       [ATHOS_LUT_CHAN_673125_IDX] = { 26925, 0x1, 0x4A, 0x195555, 0x8C4 },
+       [ATHOS_LUT_CHAN_673250_IDX] = { 26930, 0x1, 0x4A, 0x19C71C, 0x8C4 },
+       [ATHOS_LUT_CHAN_673375_IDX] = { 26935, 0x1, 0x4A, 0x1A38E4, 0x8C5 },
+       [ATHOS_LUT_CHAN_673500_IDX] = { 26940, 0x1, 0x4A, 0x1AAAAB, 0x8C5 },
+       [ATHOS_LUT_CHAN_673625_IDX] = { 26945, 0x1, 0x4A, 0x1B1C72, 0x8C5 },
+       [ATHOS_LUT_CHAN_673750_IDX] = { 26950, 0x1, 0x4A, 0x1B8E39, 0x8C6 },
+       [ATHOS_LUT_CHAN_673875_IDX] = { 26955, 0x1, 0x4A, 0x1C0000, 0x8C6 },
+       [ATHOS_LUT_CHAN_674000_IDX] = { 26960, 0x1, 0x4A, 0x1C71C7, 0x8C7 },
+       [ATHOS_LUT_CHAN_674125_IDX] = { 26965, 0x1, 0x4A, 0x1CE38E, 0x8C7 },
+       [ATHOS_LUT_CHAN_674250_IDX] = { 26970, 0x1, 0x4A, 0x1D5555, 0x8C8 },
+       [ATHOS_LUT_CHAN_674375_IDX] = { 26975, 0x1, 0x4A, 0x1DC71C, 0x8C8 },
+       [ATHOS_LUT_CHAN_674500_IDX] = { 26980, 0x1, 0x4A, 0x1E38E4, 0x8C8 },
+       [ATHOS_LUT_CHAN_674625_IDX] = { 26985, 0x1, 0x4A, 0x1EAAAB, 0x8C9 },
+       [ATHOS_LUT_CHAN_674750_IDX] = { 26990, 0x1, 0x4A, 0x1F1C72, 0x8C9 },
+       [ATHOS_LUT_CHAN_674875_IDX] = { 26995, 0x1, 0x4A, 0x1F8E39, 0x8CA },
+       [ATHOS_LUT_CHAN_675000_IDX] = { 27000, 0x1, 0x4B, 0x0, 0x8CA },
+       [ATHOS_LUT_CHAN_675125_IDX] = { 27005, 0x1, 0x4B, 0x71C7, 0x8CA },
+       [ATHOS_LUT_CHAN_675250_IDX] = { 27010, 0x1, 0x4B, 0xE38E, 0x8CB },
+       [ATHOS_LUT_CHAN_675375_IDX] = { 27015, 0x1, 0x4B, 0x15555, 0x8CB },
+       [ATHOS_LUT_CHAN_675500_IDX] = { 27020, 0x1, 0x4B, 0x1C71C, 0x8CC },
+       [ATHOS_LUT_CHAN_675625_IDX] = { 27025, 0x1, 0x4B, 0x238E4, 0x8CC },
+       [ATHOS_LUT_CHAN_675750_IDX] = { 27030, 0x1, 0x4B, 0x2AAAB, 0x8CD },
+       [ATHOS_LUT_CHAN_675875_IDX] = { 27035, 0x1, 0x4B, 0x31C72, 0x8CD },
+       [ATHOS_LUT_CHAN_676000_IDX] = { 27040, 0x1, 0x4B, 0x38E39, 0x8CD },
+       [ATHOS_LUT_CHAN_676125_IDX] = { 27045, 0x1, 0x4B, 0x40000, 0x8CE },
+       [ATHOS_LUT_CHAN_676250_IDX] = { 27050, 0x1, 0x4B, 0x471C7, 0x8CE },
+       [ATHOS_LUT_CHAN_676375_IDX] = { 27055, 0x1, 0x4B, 0x4E38E, 0x8CF },
+       [ATHOS_LUT_CHAN_676500_IDX] = { 27060, 0x1, 0x4B, 0x55555, 0x8CF },
+       [ATHOS_LUT_CHAN_676625_IDX] = { 27065, 0x1, 0x4B, 0x5C71C, 0x8CF },
+       [ATHOS_LUT_CHAN_676750_IDX] = { 27070, 0x1, 0x4B, 0x638E4, 0x8D0 },
+       [ATHOS_LUT_CHAN_676875_IDX] = { 27075, 0x1, 0x4B, 0x6AAAB, 0x8D0 },
+       [ATHOS_LUT_CHAN_677000_IDX] = { 27080, 0x1, 0x4B, 0x71C72, 0x8D1 },
+       [ATHOS_LUT_CHAN_677125_IDX] = { 27085, 0x1, 0x4B, 0x78E39, 0x8D1 },
+       [ATHOS_LUT_CHAN_677250_IDX] = { 27090, 0x1, 0x4B, 0x80000, 0x8D2 },
+       [ATHOS_LUT_CHAN_677375_IDX] = { 27095, 0x1, 0x4B, 0x871C7, 0x8D2 },
+       [ATHOS_LUT_CHAN_677500_IDX] = { 27100, 0x1, 0x4B, 0x8E38E, 0x8D2 },
+       [ATHOS_LUT_CHAN_677625_IDX] = { 27105, 0x1, 0x4B, 0x95555, 0x8D3 },
+       [ATHOS_LUT_CHAN_677750_IDX] = { 27110, 0x1, 0x4B, 0x9C71C, 0x8D3 },
+       [ATHOS_LUT_CHAN_677875_IDX] = { 27115, 0x1, 0x4B, 0xA38E4, 0x8D4 },
+       [ATHOS_LUT_CHAN_678000_IDX] = { 27120, 0x1, 0x4B, 0xAAAAB, 0x8D4 },
+       [ATHOS_LUT_CHAN_678125_IDX] = { 27125, 0x1, 0x4B, 0xB1C72, 0x8D4 },
+       [ATHOS_LUT_CHAN_678250_IDX] = { 27130, 0x1, 0x4B, 0xB8E39, 0x8D5 },
+       [ATHOS_LUT_CHAN_678375_IDX] = { 27135, 0x1, 0x4B, 0xC0000, 0x8D5 },
+       [ATHOS_LUT_CHAN_678500_IDX] = { 27140, 0x1, 0x4B, 0xC71C7, 0x8D6 },
+       [ATHOS_LUT_CHAN_678625_IDX] = { 27145, 0x1, 0x4B, 0xCE38E, 0x8D6 },
+       [ATHOS_LUT_CHAN_678750_IDX] = { 27150, 0x1, 0x4B, 0xD5555, 0x8D7 },
+       [ATHOS_LUT_CHAN_678875_IDX] = { 27155, 0x1, 0x4B, 0xDC71C, 0x8D7 },
+       [ATHOS_LUT_CHAN_679000_IDX] = { 27160, 0x1, 0x4B, 0xE38E4, 0x8D7 },
+       [ATHOS_LUT_CHAN_679125_IDX] = { 27165, 0x1, 0x4B, 0xEAAAB, 0x8D8 },
+       [ATHOS_LUT_CHAN_679250_IDX] = { 27170, 0x1, 0x4B, 0xF1C72, 0x8D8 },
+       [ATHOS_LUT_CHAN_679375_IDX] = { 27175, 0x1, 0x4B, 0xF8E39, 0x8D9 },
+       [ATHOS_LUT_CHAN_679500_IDX] = { 27180, 0x1, 0x4B, 0x100000, 0x8D9 },
+       [ATHOS_LUT_CHAN_679625_IDX] = { 27185, 0x1, 0x4B, 0x1071C7, 0x8D9 },
+       [ATHOS_LUT_CHAN_679750_IDX] = { 27190, 0x1, 0x4B, 0x10E38E, 0x8DA },
+       [ATHOS_LUT_CHAN_679875_IDX] = { 27195, 0x1, 0x4B, 0x115555, 0x8DA },
+       [ATHOS_LUT_CHAN_680000_IDX] = { 27200, 0x1, 0x4B, 0x11C71C, 0x8DB },
+       [ATHOS_LUT_CHAN_680125_IDX] = { 27205, 0x1, 0x4B, 0x1238E4, 0x8DB },
+       [ATHOS_LUT_CHAN_680250_IDX] = { 27210, 0x1, 0x4B, 0x12AAAB, 0x8DC },
+       [ATHOS_LUT_CHAN_680375_IDX] = { 27215, 0x1, 0x4B, 0x131C72, 0x8DC },
+       [ATHOS_LUT_CHAN_680500_IDX] = { 27220, 0x1, 0x4B, 0x138E39, 0x8DC },
+       [ATHOS_LUT_CHAN_680625_IDX] = { 27225, 0x1, 0x4B, 0x140000, 0x8DD },
+       [ATHOS_LUT_CHAN_680750_IDX] = { 27230, 0x1, 0x4B, 0x1471C7, 0x8DD },
+       [ATHOS_LUT_CHAN_680875_IDX] = { 27235, 0x1, 0x4B, 0x14E38E, 0x8DE },
+       [ATHOS_LUT_CHAN_681000_IDX] = { 27240, 0x1, 0x4B, 0x155555, 0x8DE },
+       [ATHOS_LUT_CHAN_681125_IDX] = { 27245, 0x1, 0x4B, 0x15C71C, 0x8DE },
+       [ATHOS_LUT_CHAN_681250_IDX] = { 27250, 0x1, 0x4B, 0x1638E4, 0x8DF },
+       [ATHOS_LUT_CHAN_681375_IDX] = { 27255, 0x1, 0x4B, 0x16AAAB, 0x8DF },
+       [ATHOS_LUT_CHAN_681500_IDX] = { 27260, 0x1, 0x4B, 0x171C72, 0x8E0 },
+       [ATHOS_LUT_CHAN_681625_IDX] = { 27265, 0x1, 0x4B, 0x178E39, 0x8E0 },
+       [ATHOS_LUT_CHAN_681750_IDX] = { 27270, 0x1, 0x4B, 0x180000, 0x8E1 },
+       [ATHOS_LUT_CHAN_681875_IDX] = { 27275, 0x1, 0x4B, 0x1871C7, 0x8E1 },
+       [ATHOS_LUT_CHAN_682000_IDX] = { 27280, 0x1, 0x4B, 0x18E38E, 0x8E1 },
+       [ATHOS_LUT_CHAN_682125_IDX] = { 27285, 0x1, 0x4B, 0x195555, 0x8E2 },
+       [ATHOS_LUT_CHAN_682250_IDX] = { 27290, 0x1, 0x4B, 0x19C71C, 0x8E2 },
+       [ATHOS_LUT_CHAN_682375_IDX] = { 27295, 0x1, 0x4B, 0x1A38E4, 0x8E3 },
+       [ATHOS_LUT_CHAN_682500_IDX] = { 27300, 0x1, 0x4B, 0x1AAAAB, 0x8E3 },
+       [ATHOS_LUT_CHAN_682625_IDX] = { 27305, 0x1, 0x4B, 0x1B1C72, 0x8E3 },
+       [ATHOS_LUT_CHAN_682750_IDX] = { 27310, 0x1, 0x4B, 0x1B8E39, 0x8E4 },
+       [ATHOS_LUT_CHAN_682875_IDX] = { 27315, 0x1, 0x4B, 0x1C0000, 0x8E4 },
+       [ATHOS_LUT_CHAN_683000_IDX] = { 27320, 0x1, 0x4B, 0x1C71C7, 0x8E5 },
+       [ATHOS_LUT_CHAN_683125_IDX] = { 27325, 0x1, 0x4B, 0x1CE38E, 0x8E5 },
+       [ATHOS_LUT_CHAN_683250_IDX] = { 27330, 0x1, 0x4B, 0x1D5555, 0x8E6 },
+       [ATHOS_LUT_CHAN_683375_IDX] = { 27335, 0x1, 0x4B, 0x1DC71C, 0x8E6 },
+       [ATHOS_LUT_CHAN_683500_IDX] = { 27340, 0x1, 0x4B, 0x1E38E4, 0x8E6 },
+       [ATHOS_LUT_CHAN_683625_IDX] = { 27345, 0x1, 0x4B, 0x1EAAAB, 0x8E7 },
+       [ATHOS_LUT_CHAN_683750_IDX] = { 27350, 0x1, 0x4B, 0x1F1C72, 0x8E7 },
+       [ATHOS_LUT_CHAN_683875_IDX] = { 27355, 0x1, 0x4B, 0x1F8E39, 0x8E8 },
+       [ATHOS_LUT_CHAN_684000_IDX] = { 27360, 0x1, 0x4C, 0x0, 0x8E8 },
+       [ATHOS_LUT_CHAN_684125_IDX] = { 27365, 0x1, 0x4C, 0x71C7, 0x8E8 },
+       [ATHOS_LUT_CHAN_684250_IDX] = { 27370, 0x1, 0x4C, 0xE38E, 0x8E9 },
+       [ATHOS_LUT_CHAN_684375_IDX] = { 27375, 0x1, 0x4C, 0x15555, 0x8E9 },
+       [ATHOS_LUT_CHAN_684500_IDX] = { 27380, 0x1, 0x4C, 0x1C71C, 0x8EA },
+       [ATHOS_LUT_CHAN_684625_IDX] = { 27385, 0x1, 0x4C, 0x238E4, 0x8EA },
+       [ATHOS_LUT_CHAN_684750_IDX] = { 27390, 0x1, 0x4C, 0x2AAAB, 0x8EB },
+       [ATHOS_LUT_CHAN_684875_IDX] = { 27395, 0x1, 0x4C, 0x31C72, 0x8EB },
+       [ATHOS_LUT_CHAN_685000_IDX] = { 27400, 0x1, 0x4C, 0x38E39, 0x8EB },
+       [ATHOS_LUT_CHAN_685125_IDX] = { 27405, 0x1, 0x4C, 0x40000, 0x8EC },
+       [ATHOS_LUT_CHAN_685250_IDX] = { 27410, 0x1, 0x4C, 0x471C7, 0x8EC },
+       [ATHOS_LUT_CHAN_685375_IDX] = { 27415, 0x1, 0x4C, 0x4E38E, 0x8ED },
+       [ATHOS_LUT_CHAN_685500_IDX] = { 27420, 0x1, 0x4C, 0x55555, 0x8ED },
+       [ATHOS_LUT_CHAN_685625_IDX] = { 27425, 0x1, 0x4C, 0x5C71C, 0x8ED },
+       [ATHOS_LUT_CHAN_685750_IDX] = { 27430, 0x1, 0x4C, 0x638E4, 0x8EE },
+       [ATHOS_LUT_CHAN_685875_IDX] = { 27435, 0x1, 0x4C, 0x6AAAB, 0x8EE },
+       [ATHOS_LUT_CHAN_686000_IDX] = { 27440, 0x1, 0x4C, 0x71C72, 0x8EF },
+       [ATHOS_LUT_CHAN_686125_IDX] = { 27445, 0x1, 0x4C, 0x78E39, 0x8EF },
+       [ATHOS_LUT_CHAN_686250_IDX] = { 27450, 0x1, 0x4C, 0x80000, 0x8F0 },
+       [ATHOS_LUT_CHAN_686375_IDX] = { 27455, 0x1, 0x4C, 0x871C7, 0x8F0 },
+       [ATHOS_LUT_CHAN_686500_IDX] = { 27460, 0x1, 0x4C, 0x8E38E, 0x8F0 },
+       [ATHOS_LUT_CHAN_686625_IDX] = { 27465, 0x1, 0x4C, 0x95555, 0x8F1 },
+       [ATHOS_LUT_CHAN_686750_IDX] = { 27470, 0x1, 0x4C, 0x9C71C, 0x8F1 },
+       [ATHOS_LUT_CHAN_686875_IDX] = { 27475, 0x1, 0x4C, 0xA38E4, 0x8F2 },
+       [ATHOS_LUT_CHAN_687000_IDX] = { 27480, 0x1, 0x4C, 0xAAAAB, 0x8F2 },
+       [ATHOS_LUT_CHAN_687125_IDX] = { 27485, 0x1, 0x4C, 0xB1C72, 0x8F2 },
+       [ATHOS_LUT_CHAN_687250_IDX] = { 27490, 0x1, 0x4C, 0xB8E39, 0x8F3 },
+       [ATHOS_LUT_CHAN_687375_IDX] = { 27495, 0x1, 0x4C, 0xC0000, 0x8F3 },
+       [ATHOS_LUT_CHAN_687500_IDX] = { 27500, 0x1, 0x4C, 0xC71C7, 0x8F4 },
+       [ATHOS_LUT_CHAN_687625_IDX] = { 27505, 0x1, 0x4C, 0xCE38E, 0x8F4 },
+       [ATHOS_LUT_CHAN_687750_IDX] = { 27510, 0x1, 0x4C, 0xD5555, 0x8F5 },
+       [ATHOS_LUT_CHAN_687875_IDX] = { 27515, 0x1, 0x4C, 0xDC71C, 0x8F5 },
+       [ATHOS_LUT_CHAN_688000_IDX] = { 27520, 0x1, 0x4C, 0xE38E4, 0x8F5 },
+       [ATHOS_LUT_CHAN_688125_IDX] = { 27525, 0x1, 0x4C, 0xEAAAB, 0x8F6 },
+       [ATHOS_LUT_CHAN_688250_IDX] = { 27530, 0x1, 0x4C, 0xF1C72, 0x8F6 },
+       [ATHOS_LUT_CHAN_688375_IDX] = { 27535, 0x1, 0x4C, 0xF8E39, 0x8F7 },
+       [ATHOS_LUT_CHAN_688500_IDX] = { 27540, 0x1, 0x4C, 0x100000, 0x8F7 },
+       [ATHOS_LUT_CHAN_688625_IDX] = { 27545, 0x1, 0x4C, 0x1071C7, 0x8F7 },
+       [ATHOS_LUT_CHAN_688750_IDX] = { 27550, 0x1, 0x4C, 0x10E38E, 0x8F8 },
+       [ATHOS_LUT_CHAN_688875_IDX] = { 27555, 0x1, 0x4C, 0x115555, 0x8F8 },
+       [ATHOS_LUT_CHAN_689000_IDX] = { 27560, 0x1, 0x4C, 0x11C71C, 0x8F9 },
+       [ATHOS_LUT_CHAN_689125_IDX] = { 27565, 0x1, 0x4C, 0x1238E4, 0x8F9 },
+       [ATHOS_LUT_CHAN_689250_IDX] = { 27570, 0x1, 0x4C, 0x12AAAB, 0x8FA },
+       [ATHOS_LUT_CHAN_689375_IDX] = { 27575, 0x1, 0x4C, 0x131C72, 0x8FA },
+       [ATHOS_LUT_CHAN_689500_IDX] = { 27580, 0x1, 0x4C, 0x138E39, 0x8FA },
+       [ATHOS_LUT_CHAN_689625_IDX] = { 27585, 0x1, 0x4C, 0x140000, 0x8FB },
+       [ATHOS_LUT_CHAN_689750_IDX] = { 27590, 0x1, 0x4C, 0x1471C7, 0x8FB },
+       [ATHOS_LUT_CHAN_689875_IDX] = { 27595, 0x1, 0x4C, 0x14E38E, 0x8FC },
+       [ATHOS_LUT_CHAN_690000_IDX] = { 27600, 0x1, 0x4C, 0x155555, 0x8FC },
+       [ATHOS_LUT_CHAN_690125_IDX] = { 27605, 0x1, 0x4C, 0x15C71C, 0x8FC },
+       [ATHOS_LUT_CHAN_690250_IDX] = { 27610, 0x1, 0x4C, 0x1638E4, 0x8FD },
+       [ATHOS_LUT_CHAN_690375_IDX] = { 27615, 0x1, 0x4C, 0x16AAAB, 0x8FD },
+       [ATHOS_LUT_CHAN_690500_IDX] = { 27620, 0x1, 0x4C, 0x171C72, 0x8FE },
+       [ATHOS_LUT_CHAN_690625_IDX] = { 27625, 0x1, 0x4C, 0x178E39, 0x8FE },
+       [ATHOS_LUT_CHAN_690750_IDX] = { 27630, 0x1, 0x4C, 0x180000, 0x8FF },
+       [ATHOS_LUT_CHAN_690875_IDX] = { 27635, 0x1, 0x4C, 0x1871C7, 0x8FF },
+       [ATHOS_LUT_CHAN_691000_IDX] = { 27640, 0x1, 0x4C, 0x18E38E, 0x8FF },
+       [ATHOS_LUT_CHAN_691125_IDX] = { 27645, 0x1, 0x4C, 0x195555, 0x900 },
+       [ATHOS_LUT_CHAN_691250_IDX] = { 27650, 0x1, 0x4C, 0x19C71C, 0x900 },
+       [ATHOS_LUT_CHAN_691375_IDX] = { 27655, 0x1, 0x4C, 0x1A38E4, 0x901 },
+       [ATHOS_LUT_CHAN_691500_IDX] = { 27660, 0x1, 0x4C, 0x1AAAAB, 0x901 },
+       [ATHOS_LUT_CHAN_691625_IDX] = { 27665, 0x1, 0x4C, 0x1B1C72, 0x901 },
+       [ATHOS_LUT_CHAN_691750_IDX] = { 27670, 0x1, 0x4C, 0x1B8E39, 0x902 },
+       [ATHOS_LUT_CHAN_691875_IDX] = { 27675, 0x1, 0x4C, 0x1C0000, 0x902 },
+       [ATHOS_LUT_CHAN_692000_IDX] = { 27680, 0x1, 0x4C, 0x1C71C7, 0x903 },
+       [ATHOS_LUT_CHAN_692125_IDX] = { 27685, 0x1, 0x4C, 0x1CE38E, 0x903 },
+       [ATHOS_LUT_CHAN_692250_IDX] = { 27690, 0x1, 0x4C, 0x1D5555, 0x904 },
+       [ATHOS_LUT_CHAN_692375_IDX] = { 27695, 0x1, 0x4C, 0x1DC71C, 0x904 },
+       [ATHOS_LUT_CHAN_692500_IDX] = { 27700, 0x1, 0x4C, 0x1E38E4, 0x904 },
+       [ATHOS_LUT_CHAN_692625_IDX] = { 27705, 0x1, 0x4C, 0x1EAAAB, 0x905 },
+       [ATHOS_LUT_CHAN_692750_IDX] = { 27710, 0x1, 0x4C, 0x1F1C72, 0x905 },
+       [ATHOS_LUT_CHAN_692875_IDX] = { 27715, 0x1, 0x4C, 0x1F8E39, 0x906 },
+       [ATHOS_LUT_CHAN_693000_IDX] = { 27720, 0x1, 0x4D, 0x0, 0x906 },
+       [ATHOS_LUT_CHAN_693125_IDX] = { 27725, 0x1, 0x4D, 0x71C7, 0x906 },
+       [ATHOS_LUT_CHAN_693250_IDX] = { 27730, 0x1, 0x4D, 0xE38E, 0x907 },
+       [ATHOS_LUT_CHAN_693375_IDX] = { 27735, 0x1, 0x4D, 0x15555, 0x907 },
+       [ATHOS_LUT_CHAN_693500_IDX] = { 27740, 0x1, 0x4D, 0x1C71C, 0x908 },
+       [ATHOS_LUT_CHAN_693625_IDX] = { 27745, 0x1, 0x4D, 0x238E4, 0x908 },
+       [ATHOS_LUT_CHAN_693750_IDX] = { 27750, 0x1, 0x4D, 0x2AAAB, 0x909 },
+       [ATHOS_LUT_CHAN_693875_IDX] = { 27755, 0x1, 0x4D, 0x31C72, 0x909 },
+       [ATHOS_LUT_CHAN_694000_IDX] = { 27760, 0x1, 0x4D, 0x38E39, 0x909 },
+       [ATHOS_LUT_CHAN_694125_IDX] = { 27765, 0x1, 0x4D, 0x40000, 0x90A },
+       [ATHOS_LUT_CHAN_694250_IDX] = { 27770, 0x1, 0x4D, 0x471C7, 0x90A },
+       [ATHOS_LUT_CHAN_694375_IDX] = { 27775, 0x1, 0x4D, 0x4E38E, 0x90B },
+       [ATHOS_LUT_CHAN_694500_IDX] = { 27780, 0x1, 0x4D, 0x55555, 0x90B },
+       [ATHOS_LUT_CHAN_694625_IDX] = { 27785, 0x1, 0x4D, 0x5C71C, 0x90B },
+       [ATHOS_LUT_CHAN_694750_IDX] = { 27790, 0x1, 0x4D, 0x638E4, 0x90C },
+       [ATHOS_LUT_CHAN_694875_IDX] = { 27795, 0x1, 0x4D, 0x6AAAB, 0x90C },
+       [ATHOS_LUT_CHAN_695000_IDX] = { 27800, 0x1, 0x4D, 0x71C72, 0x90D },
+       [ATHOS_LUT_CHAN_695125_IDX] = { 27805, 0x1, 0x4D, 0x78E39, 0x90D },
+       [ATHOS_LUT_CHAN_695250_IDX] = { 27810, 0x1, 0x4D, 0x80000, 0x90E },
+       [ATHOS_LUT_CHAN_695375_IDX] = { 27815, 0x1, 0x4D, 0x871C7, 0x90E },
+       [ATHOS_LUT_CHAN_695500_IDX] = { 27820, 0x1, 0x4D, 0x8E38E, 0x90E },
+       [ATHOS_LUT_CHAN_695625_IDX] = { 27825, 0x1, 0x4D, 0x95555, 0x90F },
+       [ATHOS_LUT_CHAN_695750_IDX] = { 27830, 0x1, 0x4D, 0x9C71C, 0x90F },
+       [ATHOS_LUT_CHAN_695875_IDX] = { 27835, 0x1, 0x4D, 0xA38E4, 0x910 },
+       [ATHOS_LUT_CHAN_696000_IDX] = { 27840, 0x1, 0x4D, 0xAAAAB, 0x910 },
+       [ATHOS_LUT_CHAN_696125_IDX] = { 27845, 0x1, 0x4D, 0xB1C72, 0x910 },
+       [ATHOS_LUT_CHAN_696250_IDX] = { 27850, 0x1, 0x4D, 0xB8E39, 0x911 },
+       [ATHOS_LUT_CHAN_696375_IDX] = { 27855, 0x1, 0x4D, 0xC0000, 0x911 },
+       [ATHOS_LUT_CHAN_696500_IDX] = { 27860, 0x1, 0x4D, 0xC71C7, 0x912 },
+       [ATHOS_LUT_CHAN_696625_IDX] = { 27865, 0x1, 0x4D, 0xCE38E, 0x912 },
+       [ATHOS_LUT_CHAN_696750_IDX] = { 27870, 0x1, 0x4D, 0xD5555, 0x913 },
+       [ATHOS_LUT_CHAN_696875_IDX] = { 27875, 0x1, 0x4D, 0xDC71C, 0x913 },
+       [ATHOS_LUT_CHAN_697000_IDX] = { 27880, 0x1, 0x4D, 0xE38E4, 0x913 },
+       [ATHOS_LUT_CHAN_697125_IDX] = { 27885, 0x1, 0x4D, 0xEAAAB, 0x914 },
+       [ATHOS_LUT_CHAN_697250_IDX] = { 27890, 0x1, 0x4D, 0xF1C72, 0x914 },
+       [ATHOS_LUT_CHAN_697375_IDX] = { 27895, 0x1, 0x4D, 0xF8E39, 0x915 },
+       [ATHOS_LUT_CHAN_697500_IDX] = { 27900, 0x1, 0x4D, 0x100000, 0x915 },
+       [ATHOS_LUT_CHAN_697625_IDX] = { 27905, 0x1, 0x4D, 0x1071C7, 0x915 },
+       [ATHOS_LUT_CHAN_697750_IDX] = { 27910, 0x1, 0x4D, 0x10E38E, 0x916 },
+       [ATHOS_LUT_CHAN_697875_IDX] = { 27915, 0x1, 0x4D, 0x115555, 0x916 },
+       [ATHOS_LUT_CHAN_698000_IDX] = { 27920, 0x1, 0x4D, 0x11C71C, 0x917 },
+       [ATHOS_LUT_CHAN_698125_IDX] = { 27925, 0x1, 0x4D, 0x1238E4, 0x917 },
+       [ATHOS_LUT_CHAN_698250_IDX] = { 27930, 0x1, 0x4D, 0x12AAAB, 0x918 },
+       [ATHOS_LUT_CHAN_698375_IDX] = { 27935, 0x1, 0x4D, 0x131C72, 0x918 },
+       [ATHOS_LUT_CHAN_698500_IDX] = { 27940, 0x1, 0x4D, 0x138E39, 0x918 },
+       [ATHOS_LUT_CHAN_698625_IDX] = { 27945, 0x1, 0x4D, 0x140000, 0x919 },
+       [ATHOS_LUT_CHAN_698750_IDX] = { 27950, 0x1, 0x4D, 0x1471C7, 0x919 },
+       [ATHOS_LUT_CHAN_698875_IDX] = { 27955, 0x1, 0x4D, 0x14E38E, 0x91A },
+       [ATHOS_LUT_CHAN_699000_IDX] = { 27960, 0x1, 0x4D, 0x155555, 0x91A },
+       [ATHOS_LUT_CHAN_699125_IDX] = { 27965, 0x1, 0x4D, 0x15C71C, 0x91A },
+       [ATHOS_LUT_CHAN_699250_IDX] = { 27970, 0x1, 0x4D, 0x1638E4, 0x91B },
+       [ATHOS_LUT_CHAN_699375_IDX] = { 27975, 0x1, 0x4D, 0x16AAAB, 0x91B },
+       [ATHOS_LUT_CHAN_699500_IDX] = { 27980, 0x1, 0x4D, 0x171C72, 0x91C },
+       [ATHOS_LUT_CHAN_699625_IDX] = { 27985, 0x1, 0x4D, 0x178E39, 0x91C },
+       [ATHOS_LUT_CHAN_699750_IDX] = { 27990, 0x1, 0x4D, 0x180000, 0x91D },
+       [ATHOS_LUT_CHAN_699875_IDX] = { 27995, 0x1, 0x4D, 0x1871C7, 0x91D },
+       [ATHOS_LUT_CHAN_700000_IDX] = { 28000, 0x1, 0x4D, 0x18E38E, 0x91D },
+       [ATHOS_LUT_CHAN_700125_IDX] = { 28005, 0x1, 0x4D, 0x195555, 0x91E },
+       [ATHOS_LUT_CHAN_700250_IDX] = { 28010, 0x1, 0x4D, 0x19C71C, 0x91E },
+       [ATHOS_LUT_CHAN_700375_IDX] = { 28015, 0x1, 0x4D, 0x1A38E4, 0x91F },
+       [ATHOS_LUT_CHAN_700500_IDX] = { 28020, 0x1, 0x4D, 0x1AAAAB, 0x91F },
+       [ATHOS_LUT_CHAN_700625_IDX] = { 28025, 0x1, 0x4D, 0x1B1C72, 0x91F },
+       [ATHOS_LUT_CHAN_700750_IDX] = { 28030, 0x1, 0x4D, 0x1B8E39, 0x920 },
+       [ATHOS_LUT_CHAN_700875_IDX] = { 28035, 0x1, 0x4D, 0x1C0000, 0x920 },
+       [ATHOS_LUT_CHAN_701000_IDX] = { 28040, 0x1, 0x4D, 0x1C71C7, 0x921 },
+       [ATHOS_LUT_CHAN_701125_IDX] = { 28045, 0x1, 0x4D, 0x1CE38E, 0x921 },
+       [ATHOS_LUT_CHAN_701250_IDX] = { 28050, 0x1, 0x4D, 0x1D5555, 0x922 },
+       [ATHOS_LUT_CHAN_701375_IDX] = { 28055, 0x1, 0x4D, 0x1DC71C, 0x922 },
+       [ATHOS_LUT_CHAN_701500_IDX] = { 28060, 0x1, 0x4D, 0x1E38E4, 0x922 },
+       [ATHOS_LUT_CHAN_701625_IDX] = { 28065, 0x1, 0x4D, 0x1EAAAB, 0x923 },
+       [ATHOS_LUT_CHAN_701750_IDX] = { 28070, 0x1, 0x4D, 0x1F1C72, 0x923 },
+       [ATHOS_LUT_CHAN_701875_IDX] = { 28075, 0x1, 0x4D, 0x1F8E39, 0x924 },
+       [ATHOS_LUT_CHAN_702000_IDX] = { 28080, 0x1, 0x4E, 0x0, 0x924 },
+       [ATHOS_LUT_CHAN_702125_IDX] = { 28085, 0x1, 0x4E, 0x71C7, 0x924 },
+       [ATHOS_LUT_CHAN_702250_IDX] = { 28090, 0x1, 0x4E, 0xE38E, 0x925 },
+       [ATHOS_LUT_CHAN_702375_IDX] = { 28095, 0x1, 0x4E, 0x15555, 0x925 },
+       [ATHOS_LUT_CHAN_702500_IDX] = { 28100, 0x1, 0x4E, 0x1C71C, 0x926 },
+       [ATHOS_LUT_CHAN_702625_IDX] = { 28105, 0x1, 0x4E, 0x238E4, 0x926 },
+       [ATHOS_LUT_CHAN_702750_IDX] = { 28110, 0x1, 0x4E, 0x2AAAB, 0x927 },
+       [ATHOS_LUT_CHAN_702875_IDX] = { 28115, 0x1, 0x4E, 0x31C72, 0x927 },
+       [ATHOS_LUT_CHAN_703000_IDX] = { 28120, 0x1, 0x4E, 0x38E39, 0x927 },
+       [ATHOS_LUT_CHAN_703125_IDX] = { 28125, 0x1, 0x4E, 0x40000, 0x928 },
+       [ATHOS_LUT_CHAN_703250_IDX] = { 28130, 0x1, 0x4E, 0x471C7, 0x928 },
+       [ATHOS_LUT_CHAN_703375_IDX] = { 28135, 0x1, 0x4E, 0x4E38E, 0x929 },
+       [ATHOS_LUT_CHAN_703500_IDX] = { 28140, 0x1, 0x4E, 0x55555, 0x929 },
+       [ATHOS_LUT_CHAN_703625_IDX] = { 28145, 0x1, 0x4E, 0x5C71C, 0x929 },
+       [ATHOS_LUT_CHAN_703750_IDX] = { 28150, 0x1, 0x4E, 0x638E4, 0x92A },
+       [ATHOS_LUT_CHAN_703875_IDX] = { 28155, 0x1, 0x4E, 0x6AAAB, 0x92A },
+       [ATHOS_LUT_CHAN_704000_IDX] = { 28160, 0x1, 0x4E, 0x71C72, 0x92B },
+       [ATHOS_LUT_CHAN_704125_IDX] = { 28165, 0x1, 0x4E, 0x78E39, 0x92B },
+       [ATHOS_LUT_CHAN_704250_IDX] = { 28170, 0x1, 0x4E, 0x80000, 0x92C },
+       [ATHOS_LUT_CHAN_704375_IDX] = { 28175, 0x1, 0x4E, 0x871C7, 0x92C },
+       [ATHOS_LUT_CHAN_704500_IDX] = { 28180, 0x1, 0x4E, 0x8E38E, 0x92C },
+       [ATHOS_LUT_CHAN_704625_IDX] = { 28185, 0x1, 0x4E, 0x95555, 0x92D },
+       [ATHOS_LUT_CHAN_704750_IDX] = { 28190, 0x1, 0x4E, 0x9C71C, 0x92D },
+       [ATHOS_LUT_CHAN_704875_IDX] = { 28195, 0x1, 0x4E, 0xA38E4, 0x92E },
+       [ATHOS_LUT_CHAN_705000_IDX] = { 28200, 0x1, 0x4E, 0xAAAAB, 0x92E },
+       [ATHOS_LUT_CHAN_705125_IDX] = { 28205, 0x1, 0x4E, 0xB1C72, 0x92E },
+       [ATHOS_LUT_CHAN_705250_IDX] = { 28210, 0x1, 0x4E, 0xB8E39, 0x92F },
+       [ATHOS_LUT_CHAN_705375_IDX] = { 28215, 0x1, 0x4E, 0xC0000, 0x92F },
+       [ATHOS_LUT_CHAN_705500_IDX] = { 28220, 0x1, 0x4E, 0xC71C7, 0x930 },
+       [ATHOS_LUT_CHAN_705625_IDX] = { 28225, 0x1, 0x4E, 0xCE38E, 0x930 },
+       [ATHOS_LUT_CHAN_705750_IDX] = { 28230, 0x1, 0x4E, 0xD5555, 0x931 },
+       [ATHOS_LUT_CHAN_705875_IDX] = { 28235, 0x1, 0x4E, 0xDC71C, 0x931 },
+       [ATHOS_LUT_CHAN_706000_IDX] = { 28240, 0x1, 0x4E, 0xE38E4, 0x931 },
+       [ATHOS_LUT_CHAN_706125_IDX] = { 28245, 0x1, 0x4E, 0xEAAAB, 0x932 },
+       [ATHOS_LUT_CHAN_706250_IDX] = { 28250, 0x1, 0x4E, 0xF1C72, 0x932 },
+       [ATHOS_LUT_CHAN_706375_IDX] = { 28255, 0x1, 0x4E, 0xF8E39, 0x933 },
+       [ATHOS_LUT_CHAN_706500_IDX] = { 28260, 0x1, 0x4E, 0x100000, 0x933 },
+       [ATHOS_LUT_CHAN_706625_IDX] = { 28265, 0x1, 0x4E, 0x1071C7, 0x933 },
+       [ATHOS_LUT_CHAN_706750_IDX] = { 28270, 0x1, 0x4E, 0x10E38E, 0x934 },
+       [ATHOS_LUT_CHAN_706875_IDX] = { 28275, 0x1, 0x4E, 0x115555, 0x934 },
+       [ATHOS_LUT_CHAN_707000_IDX] = { 28280, 0x1, 0x4E, 0x11C71C, 0x935 },
+       [ATHOS_LUT_CHAN_707125_IDX] = { 28285, 0x1, 0x4E, 0x1238E4, 0x935 },
+       [ATHOS_LUT_CHAN_707250_IDX] = { 28290, 0x1, 0x4E, 0x12AAAB, 0x936 },
+       [ATHOS_LUT_CHAN_707375_IDX] = { 28295, 0x1, 0x4E, 0x131C72, 0x936 },
+       [ATHOS_LUT_CHAN_707500_IDX] = { 28300, 0x1, 0x4E, 0x138E39, 0x936 },
+       [ATHOS_LUT_CHAN_707625_IDX] = { 28305, 0x1, 0x4E, 0x140000, 0x937 },
+       [ATHOS_LUT_CHAN_707750_IDX] = { 28310, 0x1, 0x4E, 0x1471C7, 0x937 },
+       [ATHOS_LUT_CHAN_707875_IDX] = { 28315, 0x1, 0x4E, 0x14E38E, 0x938 },
+       [ATHOS_LUT_CHAN_708000_IDX] = { 28320, 0x1, 0x4E, 0x155555, 0x938 },
+       [ATHOS_LUT_CHAN_708125_IDX] = { 28325, 0x1, 0x4E, 0x15C71C, 0x938 },
+       [ATHOS_LUT_CHAN_708250_IDX] = { 28330, 0x1, 0x4E, 0x1638E4, 0x939 },
+       [ATHOS_LUT_CHAN_708375_IDX] = { 28335, 0x1, 0x4E, 0x16AAAB, 0x939 },
+       [ATHOS_LUT_CHAN_708500_IDX] = { 28340, 0x1, 0x4E, 0x171C72, 0x93A },
+       [ATHOS_LUT_CHAN_708625_IDX] = { 28345, 0x1, 0x4E, 0x178E39, 0x93A },
+       [ATHOS_LUT_CHAN_708750_IDX] = { 28350, 0x1, 0x4E, 0x180000, 0x93B },
+       [ATHOS_LUT_CHAN_708875_IDX] = { 28355, 0x1, 0x4E, 0x1871C7, 0x93B },
+       [ATHOS_LUT_CHAN_709000_IDX] = { 28360, 0x1, 0x4E, 0x18E38E, 0x93B },
+       [ATHOS_LUT_CHAN_709125_IDX] = { 28365, 0x1, 0x4E, 0x195555, 0x93C },
+       [ATHOS_LUT_CHAN_709250_IDX] = { 28370, 0x1, 0x4E, 0x19C71C, 0x93C },
+       [ATHOS_LUT_CHAN_709375_IDX] = { 28375, 0x1, 0x4E, 0x1A38E4, 0x93D },
+       [ATHOS_LUT_CHAN_709500_IDX] = { 28380, 0x1, 0x4E, 0x1AAAAB, 0x93D },
+       [ATHOS_LUT_CHAN_709625_IDX] = { 28385, 0x1, 0x4E, 0x1B1C72, 0x93D },
+       [ATHOS_LUT_CHAN_709750_IDX] = { 28390, 0x1, 0x4E, 0x1B8E39, 0x93E },
+       [ATHOS_LUT_CHAN_709875_IDX] = { 28395, 0x1, 0x4E, 0x1C0000, 0x93E },
+       [ATHOS_LUT_CHAN_710000_IDX] = { 28400, 0x1, 0x4E, 0x1C71C7, 0x93F },
+       [ATHOS_LUT_CHAN_710125_IDX] = { 28405, 0x1, 0x4E, 0x1CE38E, 0x93F },
+       [ATHOS_LUT_CHAN_710250_IDX] = { 28410, 0x1, 0x4E, 0x1D5555, 0x940 },
+       [ATHOS_LUT_CHAN_710375_IDX] = { 28415, 0x1, 0x4E, 0x1DC71C, 0x940 },
+       [ATHOS_LUT_CHAN_710500_IDX] = { 28420, 0x1, 0x4E, 0x1E38E4, 0x940 },
+       [ATHOS_LUT_CHAN_710625_IDX] = { 28425, 0x1, 0x4E, 0x1EAAAB, 0x941 },
+       [ATHOS_LUT_CHAN_710750_IDX] = { 28430, 0x1, 0x4E, 0x1F1C72, 0x941 },
+       [ATHOS_LUT_CHAN_710875_IDX] = { 28435, 0x1, 0x4E, 0x1F8E39, 0x942 },
+       [ATHOS_LUT_CHAN_711000_IDX] = { 28440, 0x1, 0x4F, 0x0, 0x942 },
+       [ATHOS_LUT_CHAN_711125_IDX] = { 28445, 0x1, 0x4F, 0x71C7, 0x942 },
+       [ATHOS_LUT_CHAN_711250_IDX] = { 28450, 0x1, 0x4F, 0xE38E, 0x943 },
+       [ATHOS_LUT_CHAN_711375_IDX] = { 28455, 0x1, 0x4F, 0x15555, 0x943 },
+       [ATHOS_LUT_CHAN_711500_IDX] = { 28460, 0x1, 0x4F, 0x1C71C, 0x944 },
+       [ATHOS_LUT_CHAN_711625_IDX] = { 28465, 0x1, 0x4F, 0x238E4, 0x944 },
+       [ATHOS_LUT_CHAN_711750_IDX] = { 28470, 0x1, 0x4F, 0x2AAAB, 0x945 },
+       [ATHOS_LUT_CHAN_711875_IDX] = { 28475, 0x1, 0x4F, 0x31C72, 0x945 },
+       [ATHOS_LUT_CHAN_712000_IDX] = { 28480, 0x1, 0x4F, 0x38E39, 0x945 },
+       [ATHOS_LUT_CHAN_712125_IDX] = { 28485, 0x1, 0x4F, 0x40000, 0x946 },
+       [ATHOS_LUT_CHAN_712250_IDX] = { 28490, 0x1, 0x4F, 0x471C7, 0x946 },
+       [ATHOS_LUT_CHAN_712375_IDX] = { 28495, 0x1, 0x4F, 0x4E38E, 0x947 },
+       [ATHOS_LUT_CHAN_712500_IDX] = { 28500, 0x1, 0x4F, 0x55555, 0x947 },
+       [ATHOS_LUT_CHAN_712625_IDX] = { 28505, 0x1, 0x4F, 0x5C71C, 0x947 },
+       [ATHOS_LUT_CHAN_712750_IDX] = { 28510, 0x1, 0x4F, 0x638E4, 0x948 },
+       [ATHOS_LUT_CHAN_712875_IDX] = { 28515, 0x1, 0x4F, 0x6AAAB, 0x948 },
+       [ATHOS_LUT_CHAN_713000_IDX] = { 28520, 0x1, 0x4F, 0x71C72, 0x949 },
+       [ATHOS_LUT_CHAN_713125_IDX] = { 28525, 0x1, 0x4F, 0x78E39, 0x949 },
+       [ATHOS_LUT_CHAN_713250_IDX] = { 28530, 0x1, 0x4F, 0x80000, 0x94A },
+       [ATHOS_LUT_CHAN_713375_IDX] = { 28535, 0x1, 0x4F, 0x871C7, 0x94A },
+       [ATHOS_LUT_CHAN_713500_IDX] = { 28540, 0x1, 0x4F, 0x8E38E, 0x94A },
+       [ATHOS_LUT_CHAN_713625_IDX] = { 28545, 0x1, 0x4F, 0x95555, 0x94B },
+       [ATHOS_LUT_CHAN_713750_IDX] = { 28550, 0x1, 0x4F, 0x9C71C, 0x94B },
+       [ATHOS_LUT_CHAN_713875_IDX] = { 28555, 0x1, 0x4F, 0xA38E4, 0x94C },
+       [ATHOS_LUT_CHAN_714000_IDX] = { 28560, 0x1, 0x4F, 0xAAAAB, 0x94C },
+       [ATHOS_LUT_CHAN_714125_IDX] = { 28565, 0x1, 0x4F, 0xB1C72, 0x94C },
+       [ATHOS_LUT_CHAN_714250_IDX] = { 28570, 0x1, 0x4F, 0xB8E39, 0x94D },
+       [ATHOS_LUT_CHAN_714375_IDX] = { 28575, 0x1, 0x4F, 0xC0000, 0x94D },
+       [ATHOS_LUT_CHAN_714500_IDX] = { 28580, 0x1, 0x4F, 0xC71C7, 0x94E },
+       [ATHOS_LUT_CHAN_714625_IDX] = { 28585, 0x1, 0x4F, 0xCE38E, 0x94E },
+       [ATHOS_LUT_CHAN_714750_IDX] = { 28590, 0x1, 0x4F, 0xD5555, 0x94F },
+       [ATHOS_LUT_CHAN_714875_IDX] = { 28595, 0x1, 0x4F, 0xDC71C, 0x94F },
+       [ATHOS_LUT_CHAN_715000_IDX] = { 28600, 0x1, 0x4F, 0xE38E4, 0x94F },
+       [ATHOS_LUT_CHAN_715125_IDX] = { 28605, 0x1, 0x4F, 0xEAAAB, 0x950 },
+       [ATHOS_LUT_CHAN_715250_IDX] = { 28610, 0x1, 0x4F, 0xF1C72, 0x950 },
+       [ATHOS_LUT_CHAN_715375_IDX] = { 28615, 0x1, 0x4F, 0xF8E39, 0x951 },
+       [ATHOS_LUT_CHAN_715500_IDX] = { 28620, 0x1, 0x4F, 0x100000, 0x951 },
+       [ATHOS_LUT_CHAN_715625_IDX] = { 28625, 0x1, 0x4F, 0x1071C7, 0x951 },
+       [ATHOS_LUT_CHAN_715750_IDX] = { 28630, 0x1, 0x4F, 0x10E38E, 0x952 },
+       [ATHOS_LUT_CHAN_715875_IDX] = { 28635, 0x1, 0x4F, 0x115555, 0x952 },
+       [ATHOS_LUT_CHAN_716000_IDX] = { 28640, 0x1, 0x4F, 0x11C71C, 0x953 },
+       [ATHOS_LUT_CHAN_716125_IDX] = { 28645, 0x1, 0x4F, 0x1238E4, 0x953 },
+       [ATHOS_LUT_CHAN_716250_IDX] = { 28650, 0x1, 0x4F, 0x12AAAB, 0x954 },
+       [ATHOS_LUT_CHAN_716375_IDX] = { 28655, 0x1, 0x4F, 0x131C72, 0x954 },
+       [ATHOS_LUT_CHAN_716500_IDX] = { 28660, 0x1, 0x4F, 0x138E39, 0x954 },
+       [ATHOS_LUT_CHAN_716625_IDX] = { 28665, 0x1, 0x4F, 0x140000, 0x955 },
+       [ATHOS_LUT_CHAN_716750_IDX] = { 28670, 0x1, 0x4F, 0x1471C7, 0x955 },
+       [ATHOS_LUT_CHAN_716875_IDX] = { 28675, 0x1, 0x4F, 0x14E38E, 0x956 },
+       [ATHOS_LUT_CHAN_717000_IDX] = { 28680, 0x1, 0x4F, 0x155555, 0x956 },
+       [ATHOS_LUT_CHAN_717125_IDX] = { 28685, 0x1, 0x4F, 0x15C71C, 0x956 },
+       [ATHOS_LUT_CHAN_717250_IDX] = { 28690, 0x1, 0x4F, 0x1638E4, 0x957 },
+       [ATHOS_LUT_CHAN_717375_IDX] = { 28695, 0x1, 0x4F, 0x16AAAB, 0x957 },
+       [ATHOS_LUT_CHAN_717500_IDX] = { 28700, 0x1, 0x4F, 0x171C72, 0x958 },
+       [ATHOS_LUT_CHAN_717625_IDX] = { 28705, 0x1, 0x4F, 0x178E39, 0x958 },
+       [ATHOS_LUT_CHAN_717750_IDX] = { 28710, 0x1, 0x4F, 0x180000, 0x959 },
+       [ATHOS_LUT_CHAN_717875_IDX] = { 28715, 0x1, 0x4F, 0x1871C7, 0x959 },
+       [ATHOS_LUT_CHAN_718000_IDX] = { 28720, 0x1, 0x4F, 0x18E38E, 0x959 },
+       [ATHOS_LUT_CHAN_718125_IDX] = { 28725, 0x1, 0x4F, 0x195555, 0x95A },
+       [ATHOS_LUT_CHAN_718250_IDX] = { 28730, 0x1, 0x4F, 0x19C71C, 0x95A },
+       [ATHOS_LUT_CHAN_718375_IDX] = { 28735, 0x1, 0x4F, 0x1A38E4, 0x95B },
+       [ATHOS_LUT_CHAN_718500_IDX] = { 28740, 0x1, 0x4F, 0x1AAAAB, 0x95B },
+       [ATHOS_LUT_CHAN_718625_IDX] = { 28745, 0x1, 0x4F, 0x1B1C72, 0x95B },
+       [ATHOS_LUT_CHAN_718750_IDX] = { 28750, 0x1, 0x4F, 0x1B8E39, 0x95C },
+       [ATHOS_LUT_CHAN_718875_IDX] = { 28755, 0x1, 0x4F, 0x1C0000, 0x95C },
+       [ATHOS_LUT_CHAN_719000_IDX] = { 28760, 0x1, 0x4F, 0x1C71C7, 0x95D },
+       [ATHOS_LUT_CHAN_719125_IDX] = { 28765, 0x1, 0x4F, 0x1CE38E, 0x95D },
+       [ATHOS_LUT_CHAN_719250_IDX] = { 28770, 0x1, 0x4F, 0x1D5555, 0x95E },
+       [ATHOS_LUT_CHAN_719375_IDX] = { 28775, 0x1, 0x4F, 0x1DC71C, 0x95E },
+       [ATHOS_LUT_CHAN_719500_IDX] = { 28780, 0x1, 0x4F, 0x1E38E4, 0x95E },
+       [ATHOS_LUT_CHAN_719625_IDX] = { 28785, 0x1, 0x4F, 0x1EAAAB, 0x95F },
+       [ATHOS_LUT_CHAN_719750_IDX] = { 28790, 0x1, 0x4F, 0x1F1C72, 0x95F },
+       [ATHOS_LUT_CHAN_719875_IDX] = { 28795, 0x1, 0x4F, 0x1F8E39, 0x960 },
+       [ATHOS_LUT_CHAN_720000_IDX] = { 28800, 0x1, 0x50, 0x0, 0x960 },
+       [ATHOS_LUT_CHAN_720125_IDX] = { 28805, 0x1, 0x50, 0x71C7, 0x960 },
+       [ATHOS_LUT_CHAN_720250_IDX] = { 28810, 0x1, 0x50, 0xE38E, 0x961 },
+       [ATHOS_LUT_CHAN_720375_IDX] = { 28815, 0x1, 0x50, 0x15555, 0x961 },
+       [ATHOS_LUT_CHAN_720500_IDX] = { 28820, 0x1, 0x50, 0x1C71C, 0x962 },
+       [ATHOS_LUT_CHAN_720625_IDX] = { 28825, 0x1, 0x50, 0x238E4, 0x962 },
+       [ATHOS_LUT_CHAN_720750_IDX] = { 28830, 0x1, 0x50, 0x2AAAB, 0x963 },
+       [ATHOS_LUT_CHAN_720875_IDX] = { 28835, 0x1, 0x50, 0x31C72, 0x963 },
+       [ATHOS_LUT_CHAN_721000_IDX] = { 28840, 0x1, 0x50, 0x38E39, 0x963 },
+       [ATHOS_LUT_CHAN_721125_IDX] = { 28845, 0x1, 0x50, 0x40000, 0x964 },
+       [ATHOS_LUT_CHAN_721250_IDX] = { 28850, 0x1, 0x50, 0x471C7, 0x964 },
+       [ATHOS_LUT_CHAN_721375_IDX] = { 28855, 0x1, 0x50, 0x4E38E, 0x965 },
+       [ATHOS_LUT_CHAN_721500_IDX] = { 28860, 0x1, 0x50, 0x55555, 0x965 }
+};
+
--
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.
________________________________


^ permalink raw reply related	[flat|nested] 262+ messages in thread

* [RFC v1 128/256] cl8k: add phy/phy_athos_lut.h
  2021-06-17 15:58 [RFC v1 000/256] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (126 preceding siblings ...)
  2021-06-17 16:00 ` [RFC v1 127/256] cl8k: add phy/phy_athos_lut.c viktor.barna
@ 2021-06-17 16:00 ` viktor.barna
  2021-06-17 16:00 ` [RFC v1 129/256] cl8k: add phy/phy_common_lut.c viktor.barna
                   ` (129 subsequent siblings)
  257 siblings, 0 replies; 262+ messages in thread
From: viktor.barna @ 2021-06-17 16:00 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Oleksandr Savchenko, Shay Bar, Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

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

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 .../wireless/celeno/cl8k/phy/phy_athos_lut.h  | 1049 +++++++++++++++++
 1 file changed, 1049 insertions(+)
 create mode 100644 drivers/net/wireless/celeno/cl8k/phy/phy_athos_lut.h

diff --git a/drivers/net/wireless/celeno/cl8k/phy/phy_athos_lut.h b/drivers/net/wireless/celeno/cl8k/phy/phy_athos_lut.h
new file mode 100644
index 000000000000..8c81a0e29d10
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/phy/phy_athos_lut.h
@@ -0,0 +1,1049 @@
+/* SPDX-License-Identifier: MIT */
+/* Copyright(c) 2019-2021, Celeno Communications Ltd. */
+
+#ifndef CL_PHY_ATHOS_LUT_H
+#define CL_PHY_ATHOS_LUT_H
+
+#include <linux/types.h>
+#include "phy_common_lut.h"
+#include "fw/fw_msg.h"
+
+enum athos_lut_idx_6g {
+       ATHOS_LUT_CHAN_593000_IDX,
+       ATHOS_LUT_CHAN_593125_IDX,
+       ATHOS_LUT_CHAN_593250_IDX,
+       ATHOS_LUT_CHAN_593375_IDX,
+       ATHOS_LUT_CHAN_593500_IDX,
+       ATHOS_LUT_CHAN_593625_IDX,
+       ATHOS_LUT_CHAN_593750_IDX,
+       ATHOS_LUT_CHAN_593875_IDX,
+       ATHOS_LUT_CHAN_594000_IDX,
+       ATHOS_LUT_CHAN_594125_IDX,
+       ATHOS_LUT_CHAN_594250_IDX,
+       ATHOS_LUT_CHAN_594375_IDX,
+       ATHOS_LUT_CHAN_594500_IDX,
+       ATHOS_LUT_CHAN_594625_IDX,
+       ATHOS_LUT_CHAN_594750_IDX,
+       ATHOS_LUT_CHAN_594875_IDX,
+       ATHOS_LUT_CHAN_595000_IDX,
+       ATHOS_LUT_CHAN_595125_IDX,
+       ATHOS_LUT_CHAN_595250_IDX,
+       ATHOS_LUT_CHAN_595375_IDX,
+       ATHOS_LUT_CHAN_595500_IDX,
+       ATHOS_LUT_CHAN_595625_IDX,
+       ATHOS_LUT_CHAN_595750_IDX,
+       ATHOS_LUT_CHAN_595875_IDX,
+       ATHOS_LUT_CHAN_596000_IDX,
+       ATHOS_LUT_CHAN_596125_IDX,
+       ATHOS_LUT_CHAN_596250_IDX,
+       ATHOS_LUT_CHAN_596375_IDX,
+       ATHOS_LUT_CHAN_596500_IDX,
+       ATHOS_LUT_CHAN_596625_IDX,
+       ATHOS_LUT_CHAN_596750_IDX,
+       ATHOS_LUT_CHAN_596875_IDX,
+       ATHOS_LUT_CHAN_597000_IDX,
+       ATHOS_LUT_CHAN_597125_IDX,
+       ATHOS_LUT_CHAN_597250_IDX,
+       ATHOS_LUT_CHAN_597375_IDX,
+       ATHOS_LUT_CHAN_597500_IDX,
+       ATHOS_LUT_CHAN_597625_IDX,
+       ATHOS_LUT_CHAN_597750_IDX,
+       ATHOS_LUT_CHAN_597875_IDX,
+       ATHOS_LUT_CHAN_598000_IDX,
+       ATHOS_LUT_CHAN_598125_IDX,
+       ATHOS_LUT_CHAN_598250_IDX,
+       ATHOS_LUT_CHAN_598375_IDX,
+       ATHOS_LUT_CHAN_598500_IDX,
+       ATHOS_LUT_CHAN_598625_IDX,
+       ATHOS_LUT_CHAN_598750_IDX,
+       ATHOS_LUT_CHAN_598875_IDX,
+       ATHOS_LUT_CHAN_599000_IDX,
+       ATHOS_LUT_CHAN_599125_IDX,
+       ATHOS_LUT_CHAN_599250_IDX,
+       ATHOS_LUT_CHAN_599375_IDX,
+       ATHOS_LUT_CHAN_599500_IDX,
+       ATHOS_LUT_CHAN_599625_IDX,
+       ATHOS_LUT_CHAN_599750_IDX,
+       ATHOS_LUT_CHAN_599875_IDX,
+       ATHOS_LUT_CHAN_600000_IDX,
+       ATHOS_LUT_CHAN_600125_IDX,
+       ATHOS_LUT_CHAN_600250_IDX,
+       ATHOS_LUT_CHAN_600375_IDX,
+       ATHOS_LUT_CHAN_600500_IDX,
+       ATHOS_LUT_CHAN_600625_IDX,
+       ATHOS_LUT_CHAN_600750_IDX,
+       ATHOS_LUT_CHAN_600875_IDX,
+       ATHOS_LUT_CHAN_601000_IDX,
+       ATHOS_LUT_CHAN_601125_IDX,
+       ATHOS_LUT_CHAN_601250_IDX,
+       ATHOS_LUT_CHAN_601375_IDX,
+       ATHOS_LUT_CHAN_601500_IDX,
+       ATHOS_LUT_CHAN_601625_IDX,
+       ATHOS_LUT_CHAN_601750_IDX,
+       ATHOS_LUT_CHAN_601875_IDX,
+       ATHOS_LUT_CHAN_602000_IDX,
+       ATHOS_LUT_CHAN_602125_IDX,
+       ATHOS_LUT_CHAN_602250_IDX,
+       ATHOS_LUT_CHAN_602375_IDX,
+       ATHOS_LUT_CHAN_602500_IDX,
+       ATHOS_LUT_CHAN_602625_IDX,
+       ATHOS_LUT_CHAN_602750_IDX,
+       ATHOS_LUT_CHAN_602875_IDX,
+       ATHOS_LUT_CHAN_603000_IDX,
+       ATHOS_LUT_CHAN_603125_IDX,
+       ATHOS_LUT_CHAN_603250_IDX,
+       ATHOS_LUT_CHAN_603375_IDX,
+       ATHOS_LUT_CHAN_603500_IDX,
+       ATHOS_LUT_CHAN_603625_IDX,
+       ATHOS_LUT_CHAN_603750_IDX,
+       ATHOS_LUT_CHAN_603875_IDX,
+       ATHOS_LUT_CHAN_604000_IDX,
+       ATHOS_LUT_CHAN_604125_IDX,
+       ATHOS_LUT_CHAN_604250_IDX,
+       ATHOS_LUT_CHAN_604375_IDX,
+       ATHOS_LUT_CHAN_604500_IDX,
+       ATHOS_LUT_CHAN_604625_IDX,
+       ATHOS_LUT_CHAN_604750_IDX,
+       ATHOS_LUT_CHAN_604875_IDX,
+       ATHOS_LUT_CHAN_605000_IDX,
+       ATHOS_LUT_CHAN_605125_IDX,
+       ATHOS_LUT_CHAN_605250_IDX,
+       ATHOS_LUT_CHAN_605375_IDX,
+       ATHOS_LUT_CHAN_605500_IDX,
+       ATHOS_LUT_CHAN_605625_IDX,
+       ATHOS_LUT_CHAN_605750_IDX,
+       ATHOS_LUT_CHAN_605875_IDX,
+       ATHOS_LUT_CHAN_606000_IDX,
+       ATHOS_LUT_CHAN_606125_IDX,
+       ATHOS_LUT_CHAN_606250_IDX,
+       ATHOS_LUT_CHAN_606375_IDX,
+       ATHOS_LUT_CHAN_606500_IDX,
+       ATHOS_LUT_CHAN_606625_IDX,
+       ATHOS_LUT_CHAN_606750_IDX,
+       ATHOS_LUT_CHAN_606875_IDX,
+       ATHOS_LUT_CHAN_607000_IDX,
+       ATHOS_LUT_CHAN_607125_IDX,
+       ATHOS_LUT_CHAN_607250_IDX,
+       ATHOS_LUT_CHAN_607375_IDX,
+       ATHOS_LUT_CHAN_607500_IDX,
+       ATHOS_LUT_CHAN_607625_IDX,
+       ATHOS_LUT_CHAN_607750_IDX,
+       ATHOS_LUT_CHAN_607875_IDX,
+       ATHOS_LUT_CHAN_608000_IDX,
+       ATHOS_LUT_CHAN_608125_IDX,
+       ATHOS_LUT_CHAN_608250_IDX,
+       ATHOS_LUT_CHAN_608375_IDX,
+       ATHOS_LUT_CHAN_608500_IDX,
+       ATHOS_LUT_CHAN_608625_IDX,
+       ATHOS_LUT_CHAN_608750_IDX,
+       ATHOS_LUT_CHAN_608875_IDX,
+       ATHOS_LUT_CHAN_609000_IDX,
+       ATHOS_LUT_CHAN_609125_IDX,
+       ATHOS_LUT_CHAN_609250_IDX,
+       ATHOS_LUT_CHAN_609375_IDX,
+       ATHOS_LUT_CHAN_609500_IDX,
+       ATHOS_LUT_CHAN_609625_IDX,
+       ATHOS_LUT_CHAN_609750_IDX,
+       ATHOS_LUT_CHAN_609875_IDX,
+       ATHOS_LUT_CHAN_610000_IDX,
+       ATHOS_LUT_CHAN_610125_IDX,
+       ATHOS_LUT_CHAN_610250_IDX,
+       ATHOS_LUT_CHAN_610375_IDX,
+       ATHOS_LUT_CHAN_610500_IDX,
+       ATHOS_LUT_CHAN_610625_IDX,
+       ATHOS_LUT_CHAN_610750_IDX,
+       ATHOS_LUT_CHAN_610875_IDX,
+       ATHOS_LUT_CHAN_611000_IDX,
+       ATHOS_LUT_CHAN_611125_IDX,
+       ATHOS_LUT_CHAN_611250_IDX,
+       ATHOS_LUT_CHAN_611375_IDX,
+       ATHOS_LUT_CHAN_611500_IDX,
+       ATHOS_LUT_CHAN_611625_IDX,
+       ATHOS_LUT_CHAN_611750_IDX,
+       ATHOS_LUT_CHAN_611875_IDX,
+       ATHOS_LUT_CHAN_612000_IDX,
+       ATHOS_LUT_CHAN_612125_IDX,
+       ATHOS_LUT_CHAN_612250_IDX,
+       ATHOS_LUT_CHAN_612375_IDX,
+       ATHOS_LUT_CHAN_612500_IDX,
+       ATHOS_LUT_CHAN_612625_IDX,
+       ATHOS_LUT_CHAN_612750_IDX,
+       ATHOS_LUT_CHAN_612875_IDX,
+       ATHOS_LUT_CHAN_613000_IDX,
+       ATHOS_LUT_CHAN_613125_IDX,
+       ATHOS_LUT_CHAN_613250_IDX,
+       ATHOS_LUT_CHAN_613375_IDX,
+       ATHOS_LUT_CHAN_613500_IDX,
+       ATHOS_LUT_CHAN_613625_IDX,
+       ATHOS_LUT_CHAN_613750_IDX,
+       ATHOS_LUT_CHAN_613875_IDX,
+       ATHOS_LUT_CHAN_614000_IDX,
+       ATHOS_LUT_CHAN_614125_IDX,
+       ATHOS_LUT_CHAN_614250_IDX,
+       ATHOS_LUT_CHAN_614375_IDX,
+       ATHOS_LUT_CHAN_614500_IDX,
+       ATHOS_LUT_CHAN_614625_IDX,
+       ATHOS_LUT_CHAN_614750_IDX,
+       ATHOS_LUT_CHAN_614875_IDX,
+       ATHOS_LUT_CHAN_615000_IDX,
+       ATHOS_LUT_CHAN_615125_IDX,
+       ATHOS_LUT_CHAN_615250_IDX,
+       ATHOS_LUT_CHAN_615375_IDX,
+       ATHOS_LUT_CHAN_615500_IDX,
+       ATHOS_LUT_CHAN_615625_IDX,
+       ATHOS_LUT_CHAN_615750_IDX,
+       ATHOS_LUT_CHAN_615875_IDX,
+       ATHOS_LUT_CHAN_616000_IDX,
+       ATHOS_LUT_CHAN_616125_IDX,
+       ATHOS_LUT_CHAN_616250_IDX,
+       ATHOS_LUT_CHAN_616375_IDX,
+       ATHOS_LUT_CHAN_616500_IDX,
+       ATHOS_LUT_CHAN_616625_IDX,
+       ATHOS_LUT_CHAN_616750_IDX,
+       ATHOS_LUT_CHAN_616875_IDX,
+       ATHOS_LUT_CHAN_617000_IDX,
+       ATHOS_LUT_CHAN_617125_IDX,
+       ATHOS_LUT_CHAN_617250_IDX,
+       ATHOS_LUT_CHAN_617375_IDX,
+       ATHOS_LUT_CHAN_617500_IDX,
+       ATHOS_LUT_CHAN_617625_IDX,
+       ATHOS_LUT_CHAN_617750_IDX,
+       ATHOS_LUT_CHAN_617875_IDX,
+       ATHOS_LUT_CHAN_618000_IDX,
+       ATHOS_LUT_CHAN_618125_IDX,
+       ATHOS_LUT_CHAN_618250_IDX,
+       ATHOS_LUT_CHAN_618375_IDX,
+       ATHOS_LUT_CHAN_618500_IDX,
+       ATHOS_LUT_CHAN_618625_IDX,
+       ATHOS_LUT_CHAN_618750_IDX,
+       ATHOS_LUT_CHAN_618875_IDX,
+       ATHOS_LUT_CHAN_619000_IDX,
+       ATHOS_LUT_CHAN_619125_IDX,
+       ATHOS_LUT_CHAN_619250_IDX,
+       ATHOS_LUT_CHAN_619375_IDX,
+       ATHOS_LUT_CHAN_619500_IDX,
+       ATHOS_LUT_CHAN_619625_IDX,
+       ATHOS_LUT_CHAN_619750_IDX,
+       ATHOS_LUT_CHAN_619875_IDX,
+       ATHOS_LUT_CHAN_620000_IDX,
+       ATHOS_LUT_CHAN_620125_IDX,
+       ATHOS_LUT_CHAN_620250_IDX,
+       ATHOS_LUT_CHAN_620375_IDX,
+       ATHOS_LUT_CHAN_620500_IDX,
+       ATHOS_LUT_CHAN_620625_IDX,
+       ATHOS_LUT_CHAN_620750_IDX,
+       ATHOS_LUT_CHAN_620875_IDX,
+       ATHOS_LUT_CHAN_621000_IDX,
+       ATHOS_LUT_CHAN_621125_IDX,
+       ATHOS_LUT_CHAN_621250_IDX,
+       ATHOS_LUT_CHAN_621375_IDX,
+       ATHOS_LUT_CHAN_621500_IDX,
+       ATHOS_LUT_CHAN_621625_IDX,
+       ATHOS_LUT_CHAN_621750_IDX,
+       ATHOS_LUT_CHAN_621875_IDX,
+       ATHOS_LUT_CHAN_622000_IDX,
+       ATHOS_LUT_CHAN_622125_IDX,
+       ATHOS_LUT_CHAN_622250_IDX,
+       ATHOS_LUT_CHAN_622375_IDX,
+       ATHOS_LUT_CHAN_622500_IDX,
+       ATHOS_LUT_CHAN_622625_IDX,
+       ATHOS_LUT_CHAN_622750_IDX,
+       ATHOS_LUT_CHAN_622875_IDX,
+       ATHOS_LUT_CHAN_623000_IDX,
+       ATHOS_LUT_CHAN_623125_IDX,
+       ATHOS_LUT_CHAN_623250_IDX,
+       ATHOS_LUT_CHAN_623375_IDX,
+       ATHOS_LUT_CHAN_623500_IDX,
+       ATHOS_LUT_CHAN_623625_IDX,
+       ATHOS_LUT_CHAN_623750_IDX,
+       ATHOS_LUT_CHAN_623875_IDX,
+       ATHOS_LUT_CHAN_624000_IDX,
+       ATHOS_LUT_CHAN_624125_IDX,
+       ATHOS_LUT_CHAN_624250_IDX,
+       ATHOS_LUT_CHAN_624375_IDX,
+       ATHOS_LUT_CHAN_624500_IDX,
+       ATHOS_LUT_CHAN_624625_IDX,
+       ATHOS_LUT_CHAN_624750_IDX,
+       ATHOS_LUT_CHAN_624875_IDX,
+       ATHOS_LUT_CHAN_625000_IDX,
+       ATHOS_LUT_CHAN_625125_IDX,
+       ATHOS_LUT_CHAN_625250_IDX,
+       ATHOS_LUT_CHAN_625375_IDX,
+       ATHOS_LUT_CHAN_625500_IDX,
+       ATHOS_LUT_CHAN_625625_IDX,
+       ATHOS_LUT_CHAN_625750_IDX,
+       ATHOS_LUT_CHAN_625875_IDX,
+       ATHOS_LUT_CHAN_626000_IDX,
+       ATHOS_LUT_CHAN_626125_IDX,
+       ATHOS_LUT_CHAN_626250_IDX,
+       ATHOS_LUT_CHAN_626375_IDX,
+       ATHOS_LUT_CHAN_626500_IDX,
+       ATHOS_LUT_CHAN_626625_IDX,
+       ATHOS_LUT_CHAN_626750_IDX,
+       ATHOS_LUT_CHAN_626875_IDX,
+       ATHOS_LUT_CHAN_627000_IDX,
+       ATHOS_LUT_CHAN_627125_IDX,
+       ATHOS_LUT_CHAN_627250_IDX,
+       ATHOS_LUT_CHAN_627375_IDX,
+       ATHOS_LUT_CHAN_627500_IDX,
+       ATHOS_LUT_CHAN_627625_IDX,
+       ATHOS_LUT_CHAN_627750_IDX,
+       ATHOS_LUT_CHAN_627875_IDX,
+       ATHOS_LUT_CHAN_628000_IDX,
+       ATHOS_LUT_CHAN_628125_IDX,
+       ATHOS_LUT_CHAN_628250_IDX,
+       ATHOS_LUT_CHAN_628375_IDX,
+       ATHOS_LUT_CHAN_628500_IDX,
+       ATHOS_LUT_CHAN_628625_IDX,
+       ATHOS_LUT_CHAN_628750_IDX,
+       ATHOS_LUT_CHAN_628875_IDX,
+       ATHOS_LUT_CHAN_629000_IDX,
+       ATHOS_LUT_CHAN_629125_IDX,
+       ATHOS_LUT_CHAN_629250_IDX,
+       ATHOS_LUT_CHAN_629375_IDX,
+       ATHOS_LUT_CHAN_629500_IDX,
+       ATHOS_LUT_CHAN_629625_IDX,
+       ATHOS_LUT_CHAN_629750_IDX,
+       ATHOS_LUT_CHAN_629875_IDX,
+       ATHOS_LUT_CHAN_630000_IDX,
+       ATHOS_LUT_CHAN_630125_IDX,
+       ATHOS_LUT_CHAN_630250_IDX,
+       ATHOS_LUT_CHAN_630375_IDX,
+       ATHOS_LUT_CHAN_630500_IDX,
+       ATHOS_LUT_CHAN_630625_IDX,
+       ATHOS_LUT_CHAN_630750_IDX,
+       ATHOS_LUT_CHAN_630875_IDX,
+       ATHOS_LUT_CHAN_631000_IDX,
+       ATHOS_LUT_CHAN_631125_IDX,
+       ATHOS_LUT_CHAN_631250_IDX,
+       ATHOS_LUT_CHAN_631375_IDX,
+       ATHOS_LUT_CHAN_631500_IDX,
+       ATHOS_LUT_CHAN_631625_IDX,
+       ATHOS_LUT_CHAN_631750_IDX,
+       ATHOS_LUT_CHAN_631875_IDX,
+       ATHOS_LUT_CHAN_632000_IDX,
+       ATHOS_LUT_CHAN_632125_IDX,
+       ATHOS_LUT_CHAN_632250_IDX,
+       ATHOS_LUT_CHAN_632375_IDX,
+       ATHOS_LUT_CHAN_632500_IDX,
+       ATHOS_LUT_CHAN_632625_IDX,
+       ATHOS_LUT_CHAN_632750_IDX,
+       ATHOS_LUT_CHAN_632875_IDX,
+       ATHOS_LUT_CHAN_633000_IDX,
+       ATHOS_LUT_CHAN_633125_IDX,
+       ATHOS_LUT_CHAN_633250_IDX,
+       ATHOS_LUT_CHAN_633375_IDX,
+       ATHOS_LUT_CHAN_633500_IDX,
+       ATHOS_LUT_CHAN_633625_IDX,
+       ATHOS_LUT_CHAN_633750_IDX,
+       ATHOS_LUT_CHAN_633875_IDX,
+       ATHOS_LUT_CHAN_634000_IDX,
+       ATHOS_LUT_CHAN_634125_IDX,
+       ATHOS_LUT_CHAN_634250_IDX,
+       ATHOS_LUT_CHAN_634375_IDX,
+       ATHOS_LUT_CHAN_634500_IDX,
+       ATHOS_LUT_CHAN_634625_IDX,
+       ATHOS_LUT_CHAN_634750_IDX,
+       ATHOS_LUT_CHAN_634875_IDX,
+       ATHOS_LUT_CHAN_635000_IDX,
+       ATHOS_LUT_CHAN_635125_IDX,
+       ATHOS_LUT_CHAN_635250_IDX,
+       ATHOS_LUT_CHAN_635375_IDX,
+       ATHOS_LUT_CHAN_635500_IDX,
+       ATHOS_LUT_CHAN_635625_IDX,
+       ATHOS_LUT_CHAN_635750_IDX,
+       ATHOS_LUT_CHAN_635875_IDX,
+       ATHOS_LUT_CHAN_636000_IDX,
+       ATHOS_LUT_CHAN_636125_IDX,
+       ATHOS_LUT_CHAN_636250_IDX,
+       ATHOS_LUT_CHAN_636375_IDX,
+       ATHOS_LUT_CHAN_636500_IDX,
+       ATHOS_LUT_CHAN_636625_IDX,
+       ATHOS_LUT_CHAN_636750_IDX,
+       ATHOS_LUT_CHAN_636875_IDX,
+       ATHOS_LUT_CHAN_637000_IDX,
+       ATHOS_LUT_CHAN_637125_IDX,
+       ATHOS_LUT_CHAN_637250_IDX,
+       ATHOS_LUT_CHAN_637375_IDX,
+       ATHOS_LUT_CHAN_637500_IDX,
+       ATHOS_LUT_CHAN_637625_IDX,
+       ATHOS_LUT_CHAN_637750_IDX,
+       ATHOS_LUT_CHAN_637875_IDX,
+       ATHOS_LUT_CHAN_638000_IDX,
+       ATHOS_LUT_CHAN_638125_IDX,
+       ATHOS_LUT_CHAN_638250_IDX,
+       ATHOS_LUT_CHAN_638375_IDX,
+       ATHOS_LUT_CHAN_638500_IDX,
+       ATHOS_LUT_CHAN_638625_IDX,
+       ATHOS_LUT_CHAN_638750_IDX,
+       ATHOS_LUT_CHAN_638875_IDX,
+       ATHOS_LUT_CHAN_639000_IDX,
+       ATHOS_LUT_CHAN_639125_IDX,
+       ATHOS_LUT_CHAN_639250_IDX,
+       ATHOS_LUT_CHAN_639375_IDX,
+       ATHOS_LUT_CHAN_639500_IDX,
+       ATHOS_LUT_CHAN_639625_IDX,
+       ATHOS_LUT_CHAN_639750_IDX,
+       ATHOS_LUT_CHAN_639875_IDX,
+       ATHOS_LUT_CHAN_640000_IDX,
+       ATHOS_LUT_CHAN_640125_IDX,
+       ATHOS_LUT_CHAN_640250_IDX,
+       ATHOS_LUT_CHAN_640375_IDX,
+       ATHOS_LUT_CHAN_640500_IDX,
+       ATHOS_LUT_CHAN_640625_IDX,
+       ATHOS_LUT_CHAN_640750_IDX,
+       ATHOS_LUT_CHAN_640875_IDX,
+       ATHOS_LUT_CHAN_641000_IDX,
+       ATHOS_LUT_CHAN_641125_IDX,
+       ATHOS_LUT_CHAN_641250_IDX,
+       ATHOS_LUT_CHAN_641375_IDX,
+       ATHOS_LUT_CHAN_641500_IDX,
+       ATHOS_LUT_CHAN_641625_IDX,
+       ATHOS_LUT_CHAN_641750_IDX,
+       ATHOS_LUT_CHAN_641875_IDX,
+       ATHOS_LUT_CHAN_642000_IDX,
+       ATHOS_LUT_CHAN_642125_IDX,
+       ATHOS_LUT_CHAN_642250_IDX,
+       ATHOS_LUT_CHAN_642375_IDX,
+       ATHOS_LUT_CHAN_642500_IDX,
+       ATHOS_LUT_CHAN_642625_IDX,
+       ATHOS_LUT_CHAN_642750_IDX,
+       ATHOS_LUT_CHAN_642875_IDX,
+       ATHOS_LUT_CHAN_643000_IDX,
+       ATHOS_LUT_CHAN_643125_IDX,
+       ATHOS_LUT_CHAN_643250_IDX,
+       ATHOS_LUT_CHAN_643375_IDX,
+       ATHOS_LUT_CHAN_643500_IDX,
+       ATHOS_LUT_CHAN_643625_IDX,
+       ATHOS_LUT_CHAN_643750_IDX,
+       ATHOS_LUT_CHAN_643875_IDX,
+       ATHOS_LUT_CHAN_644000_IDX,
+       ATHOS_LUT_CHAN_644125_IDX,
+       ATHOS_LUT_CHAN_644250_IDX,
+       ATHOS_LUT_CHAN_644375_IDX,
+       ATHOS_LUT_CHAN_644500_IDX,
+       ATHOS_LUT_CHAN_644625_IDX,
+       ATHOS_LUT_CHAN_644750_IDX,
+       ATHOS_LUT_CHAN_644875_IDX,
+       ATHOS_LUT_CHAN_645000_IDX,
+       ATHOS_LUT_CHAN_645125_IDX,
+       ATHOS_LUT_CHAN_645250_IDX,
+       ATHOS_LUT_CHAN_645375_IDX,
+       ATHOS_LUT_CHAN_645500_IDX,
+       ATHOS_LUT_CHAN_645625_IDX,
+       ATHOS_LUT_CHAN_645750_IDX,
+       ATHOS_LUT_CHAN_645875_IDX,
+       ATHOS_LUT_CHAN_646000_IDX,
+       ATHOS_LUT_CHAN_646125_IDX,
+       ATHOS_LUT_CHAN_646250_IDX,
+       ATHOS_LUT_CHAN_646375_IDX,
+       ATHOS_LUT_CHAN_646500_IDX,
+       ATHOS_LUT_CHAN_646625_IDX,
+       ATHOS_LUT_CHAN_646750_IDX,
+       ATHOS_LUT_CHAN_646875_IDX,
+       ATHOS_LUT_CHAN_647000_IDX,
+       ATHOS_LUT_CHAN_647125_IDX,
+       ATHOS_LUT_CHAN_647250_IDX,
+       ATHOS_LUT_CHAN_647375_IDX,
+       ATHOS_LUT_CHAN_647500_IDX,
+       ATHOS_LUT_CHAN_647625_IDX,
+       ATHOS_LUT_CHAN_647750_IDX,
+       ATHOS_LUT_CHAN_647875_IDX,
+       ATHOS_LUT_CHAN_648000_IDX,
+       ATHOS_LUT_CHAN_648125_IDX,
+       ATHOS_LUT_CHAN_648250_IDX,
+       ATHOS_LUT_CHAN_648375_IDX,
+       ATHOS_LUT_CHAN_648500_IDX,
+       ATHOS_LUT_CHAN_648625_IDX,
+       ATHOS_LUT_CHAN_648750_IDX,
+       ATHOS_LUT_CHAN_648875_IDX,
+       ATHOS_LUT_CHAN_649000_IDX,
+       ATHOS_LUT_CHAN_649125_IDX,
+       ATHOS_LUT_CHAN_649250_IDX,
+       ATHOS_LUT_CHAN_649375_IDX,
+       ATHOS_LUT_CHAN_649500_IDX,
+       ATHOS_LUT_CHAN_649625_IDX,
+       ATHOS_LUT_CHAN_649750_IDX,
+       ATHOS_LUT_CHAN_649875_IDX,
+       ATHOS_LUT_CHAN_650000_IDX,
+       ATHOS_LUT_CHAN_650125_IDX,
+       ATHOS_LUT_CHAN_650250_IDX,
+       ATHOS_LUT_CHAN_650375_IDX,
+       ATHOS_LUT_CHAN_650500_IDX,
+       ATHOS_LUT_CHAN_650625_IDX,
+       ATHOS_LUT_CHAN_650750_IDX,
+       ATHOS_LUT_CHAN_650875_IDX,
+       ATHOS_LUT_CHAN_651000_IDX,
+       ATHOS_LUT_CHAN_651125_IDX,
+       ATHOS_LUT_CHAN_651250_IDX,
+       ATHOS_LUT_CHAN_651375_IDX,
+       ATHOS_LUT_CHAN_651500_IDX,
+       ATHOS_LUT_CHAN_651625_IDX,
+       ATHOS_LUT_CHAN_651750_IDX,
+       ATHOS_LUT_CHAN_651875_IDX,
+       ATHOS_LUT_CHAN_652000_IDX,
+       ATHOS_LUT_CHAN_652125_IDX,
+       ATHOS_LUT_CHAN_652250_IDX,
+       ATHOS_LUT_CHAN_652375_IDX,
+       ATHOS_LUT_CHAN_652500_IDX,
+       ATHOS_LUT_CHAN_652625_IDX,
+       ATHOS_LUT_CHAN_652750_IDX,
+       ATHOS_LUT_CHAN_652875_IDX,
+       ATHOS_LUT_CHAN_653000_IDX,
+       ATHOS_LUT_CHAN_653125_IDX,
+       ATHOS_LUT_CHAN_653250_IDX,
+       ATHOS_LUT_CHAN_653375_IDX,
+       ATHOS_LUT_CHAN_653500_IDX,
+       ATHOS_LUT_CHAN_653625_IDX,
+       ATHOS_LUT_CHAN_653750_IDX,
+       ATHOS_LUT_CHAN_653875_IDX,
+       ATHOS_LUT_CHAN_654000_IDX,
+       ATHOS_LUT_CHAN_654125_IDX,
+       ATHOS_LUT_CHAN_654250_IDX,
+       ATHOS_LUT_CHAN_654375_IDX,
+       ATHOS_LUT_CHAN_654500_IDX,
+       ATHOS_LUT_CHAN_654625_IDX,
+       ATHOS_LUT_CHAN_654750_IDX,
+       ATHOS_LUT_CHAN_654875_IDX,
+       ATHOS_LUT_CHAN_655000_IDX,
+       ATHOS_LUT_CHAN_655125_IDX,
+       ATHOS_LUT_CHAN_655250_IDX,
+       ATHOS_LUT_CHAN_655375_IDX,
+       ATHOS_LUT_CHAN_655500_IDX,
+       ATHOS_LUT_CHAN_655625_IDX,
+       ATHOS_LUT_CHAN_655750_IDX,
+       ATHOS_LUT_CHAN_655875_IDX,
+       ATHOS_LUT_CHAN_656000_IDX,
+       ATHOS_LUT_CHAN_656125_IDX,
+       ATHOS_LUT_CHAN_656250_IDX,
+       ATHOS_LUT_CHAN_656375_IDX,
+       ATHOS_LUT_CHAN_656500_IDX,
+       ATHOS_LUT_CHAN_656625_IDX,
+       ATHOS_LUT_CHAN_656750_IDX,
+       ATHOS_LUT_CHAN_656875_IDX,
+       ATHOS_LUT_CHAN_657000_IDX,
+       ATHOS_LUT_CHAN_657125_IDX,
+       ATHOS_LUT_CHAN_657250_IDX,
+       ATHOS_LUT_CHAN_657375_IDX,
+       ATHOS_LUT_CHAN_657500_IDX,
+       ATHOS_LUT_CHAN_657625_IDX,
+       ATHOS_LUT_CHAN_657750_IDX,
+       ATHOS_LUT_CHAN_657875_IDX,
+       ATHOS_LUT_CHAN_658000_IDX,
+       ATHOS_LUT_CHAN_658125_IDX,
+       ATHOS_LUT_CHAN_658250_IDX,
+       ATHOS_LUT_CHAN_658375_IDX,
+       ATHOS_LUT_CHAN_658500_IDX,
+       ATHOS_LUT_CHAN_658625_IDX,
+       ATHOS_LUT_CHAN_658750_IDX,
+       ATHOS_LUT_CHAN_658875_IDX,
+       ATHOS_LUT_CHAN_659000_IDX,
+       ATHOS_LUT_CHAN_659125_IDX,
+       ATHOS_LUT_CHAN_659250_IDX,
+       ATHOS_LUT_CHAN_659375_IDX,
+       ATHOS_LUT_CHAN_659500_IDX,
+       ATHOS_LUT_CHAN_659625_IDX,
+       ATHOS_LUT_CHAN_659750_IDX,
+       ATHOS_LUT_CHAN_659875_IDX,
+       ATHOS_LUT_CHAN_660000_IDX,
+       ATHOS_LUT_CHAN_660125_IDX,
+       ATHOS_LUT_CHAN_660250_IDX,
+       ATHOS_LUT_CHAN_660375_IDX,
+       ATHOS_LUT_CHAN_660500_IDX,
+       ATHOS_LUT_CHAN_660625_IDX,
+       ATHOS_LUT_CHAN_660750_IDX,
+       ATHOS_LUT_CHAN_660875_IDX,
+       ATHOS_LUT_CHAN_661000_IDX,
+       ATHOS_LUT_CHAN_661125_IDX,
+       ATHOS_LUT_CHAN_661250_IDX,
+       ATHOS_LUT_CHAN_661375_IDX,
+       ATHOS_LUT_CHAN_661500_IDX,
+       ATHOS_LUT_CHAN_661625_IDX,
+       ATHOS_LUT_CHAN_661750_IDX,
+       ATHOS_LUT_CHAN_661875_IDX,
+       ATHOS_LUT_CHAN_662000_IDX,
+       ATHOS_LUT_CHAN_662125_IDX,
+       ATHOS_LUT_CHAN_662250_IDX,
+       ATHOS_LUT_CHAN_662375_IDX,
+       ATHOS_LUT_CHAN_662500_IDX,
+       ATHOS_LUT_CHAN_662625_IDX,
+       ATHOS_LUT_CHAN_662750_IDX,
+       ATHOS_LUT_CHAN_662875_IDX,
+       ATHOS_LUT_CHAN_663000_IDX,
+       ATHOS_LUT_CHAN_663125_IDX,
+       ATHOS_LUT_CHAN_663250_IDX,
+       ATHOS_LUT_CHAN_663375_IDX,
+       ATHOS_LUT_CHAN_663500_IDX,
+       ATHOS_LUT_CHAN_663625_IDX,
+       ATHOS_LUT_CHAN_663750_IDX,
+       ATHOS_LUT_CHAN_663875_IDX,
+       ATHOS_LUT_CHAN_664000_IDX,
+       ATHOS_LUT_CHAN_664125_IDX,
+       ATHOS_LUT_CHAN_664250_IDX,
+       ATHOS_LUT_CHAN_664375_IDX,
+       ATHOS_LUT_CHAN_664500_IDX,
+       ATHOS_LUT_CHAN_664625_IDX,
+       ATHOS_LUT_CHAN_664750_IDX,
+       ATHOS_LUT_CHAN_664875_IDX,
+       ATHOS_LUT_CHAN_665000_IDX,
+       ATHOS_LUT_CHAN_665125_IDX,
+       ATHOS_LUT_CHAN_665250_IDX,
+       ATHOS_LUT_CHAN_665375_IDX,
+       ATHOS_LUT_CHAN_665500_IDX,
+       ATHOS_LUT_CHAN_665625_IDX,
+       ATHOS_LUT_CHAN_665750_IDX,
+       ATHOS_LUT_CHAN_665875_IDX,
+       ATHOS_LUT_CHAN_666000_IDX,
+       ATHOS_LUT_CHAN_666125_IDX,
+       ATHOS_LUT_CHAN_666250_IDX,
+       ATHOS_LUT_CHAN_666375_IDX,
+       ATHOS_LUT_CHAN_666500_IDX,
+       ATHOS_LUT_CHAN_666625_IDX,
+       ATHOS_LUT_CHAN_666750_IDX,
+       ATHOS_LUT_CHAN_666875_IDX,
+       ATHOS_LUT_CHAN_667000_IDX,
+       ATHOS_LUT_CHAN_667125_IDX,
+       ATHOS_LUT_CHAN_667250_IDX,
+       ATHOS_LUT_CHAN_667375_IDX,
+       ATHOS_LUT_CHAN_667500_IDX,
+       ATHOS_LUT_CHAN_667625_IDX,
+       ATHOS_LUT_CHAN_667750_IDX,
+       ATHOS_LUT_CHAN_667875_IDX,
+       ATHOS_LUT_CHAN_668000_IDX,
+       ATHOS_LUT_CHAN_668125_IDX,
+       ATHOS_LUT_CHAN_668250_IDX,
+       ATHOS_LUT_CHAN_668375_IDX,
+       ATHOS_LUT_CHAN_668500_IDX,
+       ATHOS_LUT_CHAN_668625_IDX,
+       ATHOS_LUT_CHAN_668750_IDX,
+       ATHOS_LUT_CHAN_668875_IDX,
+       ATHOS_LUT_CHAN_669000_IDX,
+       ATHOS_LUT_CHAN_669125_IDX,
+       ATHOS_LUT_CHAN_669250_IDX,
+       ATHOS_LUT_CHAN_669375_IDX,
+       ATHOS_LUT_CHAN_669500_IDX,
+       ATHOS_LUT_CHAN_669625_IDX,
+       ATHOS_LUT_CHAN_669750_IDX,
+       ATHOS_LUT_CHAN_669875_IDX,
+       ATHOS_LUT_CHAN_670000_IDX,
+       ATHOS_LUT_CHAN_670125_IDX,
+       ATHOS_LUT_CHAN_670250_IDX,
+       ATHOS_LUT_CHAN_670375_IDX,
+       ATHOS_LUT_CHAN_670500_IDX,
+       ATHOS_LUT_CHAN_670625_IDX,
+       ATHOS_LUT_CHAN_670750_IDX,
+       ATHOS_LUT_CHAN_670875_IDX,
+       ATHOS_LUT_CHAN_671000_IDX,
+       ATHOS_LUT_CHAN_671125_IDX,
+       ATHOS_LUT_CHAN_671250_IDX,
+       ATHOS_LUT_CHAN_671375_IDX,
+       ATHOS_LUT_CHAN_671500_IDX,
+       ATHOS_LUT_CHAN_671625_IDX,
+       ATHOS_LUT_CHAN_671750_IDX,
+       ATHOS_LUT_CHAN_671875_IDX,
+       ATHOS_LUT_CHAN_672000_IDX,
+       ATHOS_LUT_CHAN_672125_IDX,
+       ATHOS_LUT_CHAN_672250_IDX,
+       ATHOS_LUT_CHAN_672375_IDX,
+       ATHOS_LUT_CHAN_672500_IDX,
+       ATHOS_LUT_CHAN_672625_IDX,
+       ATHOS_LUT_CHAN_672750_IDX,
+       ATHOS_LUT_CHAN_672875_IDX,
+       ATHOS_LUT_CHAN_673000_IDX,
+       ATHOS_LUT_CHAN_673125_IDX,
+       ATHOS_LUT_CHAN_673250_IDX,
+       ATHOS_LUT_CHAN_673375_IDX,
+       ATHOS_LUT_CHAN_673500_IDX,
+       ATHOS_LUT_CHAN_673625_IDX,
+       ATHOS_LUT_CHAN_673750_IDX,
+       ATHOS_LUT_CHAN_673875_IDX,
+       ATHOS_LUT_CHAN_674000_IDX,
+       ATHOS_LUT_CHAN_674125_IDX,
+       ATHOS_LUT_CHAN_674250_IDX,
+       ATHOS_LUT_CHAN_674375_IDX,
+       ATHOS_LUT_CHAN_674500_IDX,
+       ATHOS_LUT_CHAN_674625_IDX,
+       ATHOS_LUT_CHAN_674750_IDX,
+       ATHOS_LUT_CHAN_674875_IDX,
+       ATHOS_LUT_CHAN_675000_IDX,
+       ATHOS_LUT_CHAN_675125_IDX,
+       ATHOS_LUT_CHAN_675250_IDX,
+       ATHOS_LUT_CHAN_675375_IDX,
+       ATHOS_LUT_CHAN_675500_IDX,
+       ATHOS_LUT_CHAN_675625_IDX,
+       ATHOS_LUT_CHAN_675750_IDX,
+       ATHOS_LUT_CHAN_675875_IDX,
+       ATHOS_LUT_CHAN_676000_IDX,
+       ATHOS_LUT_CHAN_676125_IDX,
+       ATHOS_LUT_CHAN_676250_IDX,
+       ATHOS_LUT_CHAN_676375_IDX,
+       ATHOS_LUT_CHAN_676500_IDX,
+       ATHOS_LUT_CHAN_676625_IDX,
+       ATHOS_LUT_CHAN_676750_IDX,
+       ATHOS_LUT_CHAN_676875_IDX,
+       ATHOS_LUT_CHAN_677000_IDX,
+       ATHOS_LUT_CHAN_677125_IDX,
+       ATHOS_LUT_CHAN_677250_IDX,
+       ATHOS_LUT_CHAN_677375_IDX,
+       ATHOS_LUT_CHAN_677500_IDX,
+       ATHOS_LUT_CHAN_677625_IDX,
+       ATHOS_LUT_CHAN_677750_IDX,
+       ATHOS_LUT_CHAN_677875_IDX,
+       ATHOS_LUT_CHAN_678000_IDX,
+       ATHOS_LUT_CHAN_678125_IDX,
+       ATHOS_LUT_CHAN_678250_IDX,
+       ATHOS_LUT_CHAN_678375_IDX,
+       ATHOS_LUT_CHAN_678500_IDX,
+       ATHOS_LUT_CHAN_678625_IDX,
+       ATHOS_LUT_CHAN_678750_IDX,
+       ATHOS_LUT_CHAN_678875_IDX,
+       ATHOS_LUT_CHAN_679000_IDX,
+       ATHOS_LUT_CHAN_679125_IDX,
+       ATHOS_LUT_CHAN_679250_IDX,
+       ATHOS_LUT_CHAN_679375_IDX,
+       ATHOS_LUT_CHAN_679500_IDX,
+       ATHOS_LUT_CHAN_679625_IDX,
+       ATHOS_LUT_CHAN_679750_IDX,
+       ATHOS_LUT_CHAN_679875_IDX,
+       ATHOS_LUT_CHAN_680000_IDX,
+       ATHOS_LUT_CHAN_680125_IDX,
+       ATHOS_LUT_CHAN_680250_IDX,
+       ATHOS_LUT_CHAN_680375_IDX,
+       ATHOS_LUT_CHAN_680500_IDX,
+       ATHOS_LUT_CHAN_680625_IDX,
+       ATHOS_LUT_CHAN_680750_IDX,
+       ATHOS_LUT_CHAN_680875_IDX,
+       ATHOS_LUT_CHAN_681000_IDX,
+       ATHOS_LUT_CHAN_681125_IDX,
+       ATHOS_LUT_CHAN_681250_IDX,
+       ATHOS_LUT_CHAN_681375_IDX,
+       ATHOS_LUT_CHAN_681500_IDX,
+       ATHOS_LUT_CHAN_681625_IDX,
+       ATHOS_LUT_CHAN_681750_IDX,
+       ATHOS_LUT_CHAN_681875_IDX,
+       ATHOS_LUT_CHAN_682000_IDX,
+       ATHOS_LUT_CHAN_682125_IDX,
+       ATHOS_LUT_CHAN_682250_IDX,
+       ATHOS_LUT_CHAN_682375_IDX,
+       ATHOS_LUT_CHAN_682500_IDX,
+       ATHOS_LUT_CHAN_682625_IDX,
+       ATHOS_LUT_CHAN_682750_IDX,
+       ATHOS_LUT_CHAN_682875_IDX,
+       ATHOS_LUT_CHAN_683000_IDX,
+       ATHOS_LUT_CHAN_683125_IDX,
+       ATHOS_LUT_CHAN_683250_IDX,
+       ATHOS_LUT_CHAN_683375_IDX,
+       ATHOS_LUT_CHAN_683500_IDX,
+       ATHOS_LUT_CHAN_683625_IDX,
+       ATHOS_LUT_CHAN_683750_IDX,
+       ATHOS_LUT_CHAN_683875_IDX,
+       ATHOS_LUT_CHAN_684000_IDX,
+       ATHOS_LUT_CHAN_684125_IDX,
+       ATHOS_LUT_CHAN_684250_IDX,
+       ATHOS_LUT_CHAN_684375_IDX,
+       ATHOS_LUT_CHAN_684500_IDX,
+       ATHOS_LUT_CHAN_684625_IDX,
+       ATHOS_LUT_CHAN_684750_IDX,
+       ATHOS_LUT_CHAN_684875_IDX,
+       ATHOS_LUT_CHAN_685000_IDX,
+       ATHOS_LUT_CHAN_685125_IDX,
+       ATHOS_LUT_CHAN_685250_IDX,
+       ATHOS_LUT_CHAN_685375_IDX,
+       ATHOS_LUT_CHAN_685500_IDX,
+       ATHOS_LUT_CHAN_685625_IDX,
+       ATHOS_LUT_CHAN_685750_IDX,
+       ATHOS_LUT_CHAN_685875_IDX,
+       ATHOS_LUT_CHAN_686000_IDX,
+       ATHOS_LUT_CHAN_686125_IDX,
+       ATHOS_LUT_CHAN_686250_IDX,
+       ATHOS_LUT_CHAN_686375_IDX,
+       ATHOS_LUT_CHAN_686500_IDX,
+       ATHOS_LUT_CHAN_686625_IDX,
+       ATHOS_LUT_CHAN_686750_IDX,
+       ATHOS_LUT_CHAN_686875_IDX,
+       ATHOS_LUT_CHAN_687000_IDX,
+       ATHOS_LUT_CHAN_687125_IDX,
+       ATHOS_LUT_CHAN_687250_IDX,
+       ATHOS_LUT_CHAN_687375_IDX,
+       ATHOS_LUT_CHAN_687500_IDX,
+       ATHOS_LUT_CHAN_687625_IDX,
+       ATHOS_LUT_CHAN_687750_IDX,
+       ATHOS_LUT_CHAN_687875_IDX,
+       ATHOS_LUT_CHAN_688000_IDX,
+       ATHOS_LUT_CHAN_688125_IDX,
+       ATHOS_LUT_CHAN_688250_IDX,
+       ATHOS_LUT_CHAN_688375_IDX,
+       ATHOS_LUT_CHAN_688500_IDX,
+       ATHOS_LUT_CHAN_688625_IDX,
+       ATHOS_LUT_CHAN_688750_IDX,
+       ATHOS_LUT_CHAN_688875_IDX,
+       ATHOS_LUT_CHAN_689000_IDX,
+       ATHOS_LUT_CHAN_689125_IDX,
+       ATHOS_LUT_CHAN_689250_IDX,
+       ATHOS_LUT_CHAN_689375_IDX,
+       ATHOS_LUT_CHAN_689500_IDX,
+       ATHOS_LUT_CHAN_689625_IDX,
+       ATHOS_LUT_CHAN_689750_IDX,
+       ATHOS_LUT_CHAN_689875_IDX,
+       ATHOS_LUT_CHAN_690000_IDX,
+       ATHOS_LUT_CHAN_690125_IDX,
+       ATHOS_LUT_CHAN_690250_IDX,
+       ATHOS_LUT_CHAN_690375_IDX,
+       ATHOS_LUT_CHAN_690500_IDX,
+       ATHOS_LUT_CHAN_690625_IDX,
+       ATHOS_LUT_CHAN_690750_IDX,
+       ATHOS_LUT_CHAN_690875_IDX,
+       ATHOS_LUT_CHAN_691000_IDX,
+       ATHOS_LUT_CHAN_691125_IDX,
+       ATHOS_LUT_CHAN_691250_IDX,
+       ATHOS_LUT_CHAN_691375_IDX,
+       ATHOS_LUT_CHAN_691500_IDX,
+       ATHOS_LUT_CHAN_691625_IDX,
+       ATHOS_LUT_CHAN_691750_IDX,
+       ATHOS_LUT_CHAN_691875_IDX,
+       ATHOS_LUT_CHAN_692000_IDX,
+       ATHOS_LUT_CHAN_692125_IDX,
+       ATHOS_LUT_CHAN_692250_IDX,
+       ATHOS_LUT_CHAN_692375_IDX,
+       ATHOS_LUT_CHAN_692500_IDX,
+       ATHOS_LUT_CHAN_692625_IDX,
+       ATHOS_LUT_CHAN_692750_IDX,
+       ATHOS_LUT_CHAN_692875_IDX,
+       ATHOS_LUT_CHAN_693000_IDX,
+       ATHOS_LUT_CHAN_693125_IDX,
+       ATHOS_LUT_CHAN_693250_IDX,
+       ATHOS_LUT_CHAN_693375_IDX,
+       ATHOS_LUT_CHAN_693500_IDX,
+       ATHOS_LUT_CHAN_693625_IDX,
+       ATHOS_LUT_CHAN_693750_IDX,
+       ATHOS_LUT_CHAN_693875_IDX,
+       ATHOS_LUT_CHAN_694000_IDX,
+       ATHOS_LUT_CHAN_694125_IDX,
+       ATHOS_LUT_CHAN_694250_IDX,
+       ATHOS_LUT_CHAN_694375_IDX,
+       ATHOS_LUT_CHAN_694500_IDX,
+       ATHOS_LUT_CHAN_694625_IDX,
+       ATHOS_LUT_CHAN_694750_IDX,
+       ATHOS_LUT_CHAN_694875_IDX,
+       ATHOS_LUT_CHAN_695000_IDX,
+       ATHOS_LUT_CHAN_695125_IDX,
+       ATHOS_LUT_CHAN_695250_IDX,
+       ATHOS_LUT_CHAN_695375_IDX,
+       ATHOS_LUT_CHAN_695500_IDX,
+       ATHOS_LUT_CHAN_695625_IDX,
+       ATHOS_LUT_CHAN_695750_IDX,
+       ATHOS_LUT_CHAN_695875_IDX,
+       ATHOS_LUT_CHAN_696000_IDX,
+       ATHOS_LUT_CHAN_696125_IDX,
+       ATHOS_LUT_CHAN_696250_IDX,
+       ATHOS_LUT_CHAN_696375_IDX,
+       ATHOS_LUT_CHAN_696500_IDX,
+       ATHOS_LUT_CHAN_696625_IDX,
+       ATHOS_LUT_CHAN_696750_IDX,
+       ATHOS_LUT_CHAN_696875_IDX,
+       ATHOS_LUT_CHAN_697000_IDX,
+       ATHOS_LUT_CHAN_697125_IDX,
+       ATHOS_LUT_CHAN_697250_IDX,
+       ATHOS_LUT_CHAN_697375_IDX,
+       ATHOS_LUT_CHAN_697500_IDX,
+       ATHOS_LUT_CHAN_697625_IDX,
+       ATHOS_LUT_CHAN_697750_IDX,
+       ATHOS_LUT_CHAN_697875_IDX,
+       ATHOS_LUT_CHAN_698000_IDX,
+       ATHOS_LUT_CHAN_698125_IDX,
+       ATHOS_LUT_CHAN_698250_IDX,
+       ATHOS_LUT_CHAN_698375_IDX,
+       ATHOS_LUT_CHAN_698500_IDX,
+       ATHOS_LUT_CHAN_698625_IDX,
+       ATHOS_LUT_CHAN_698750_IDX,
+       ATHOS_LUT_CHAN_698875_IDX,
+       ATHOS_LUT_CHAN_699000_IDX,
+       ATHOS_LUT_CHAN_699125_IDX,
+       ATHOS_LUT_CHAN_699250_IDX,
+       ATHOS_LUT_CHAN_699375_IDX,
+       ATHOS_LUT_CHAN_699500_IDX,
+       ATHOS_LUT_CHAN_699625_IDX,
+       ATHOS_LUT_CHAN_699750_IDX,
+       ATHOS_LUT_CHAN_699875_IDX,
+       ATHOS_LUT_CHAN_700000_IDX,
+       ATHOS_LUT_CHAN_700125_IDX,
+       ATHOS_LUT_CHAN_700250_IDX,
+       ATHOS_LUT_CHAN_700375_IDX,
+       ATHOS_LUT_CHAN_700500_IDX,
+       ATHOS_LUT_CHAN_700625_IDX,
+       ATHOS_LUT_CHAN_700750_IDX,
+       ATHOS_LUT_CHAN_700875_IDX,
+       ATHOS_LUT_CHAN_701000_IDX,
+       ATHOS_LUT_CHAN_701125_IDX,
+       ATHOS_LUT_CHAN_701250_IDX,
+       ATHOS_LUT_CHAN_701375_IDX,
+       ATHOS_LUT_CHAN_701500_IDX,
+       ATHOS_LUT_CHAN_701625_IDX,
+       ATHOS_LUT_CHAN_701750_IDX,
+       ATHOS_LUT_CHAN_701875_IDX,
+       ATHOS_LUT_CHAN_702000_IDX,
+       ATHOS_LUT_CHAN_702125_IDX,
+       ATHOS_LUT_CHAN_702250_IDX,
+       ATHOS_LUT_CHAN_702375_IDX,
+       ATHOS_LUT_CHAN_702500_IDX,
+       ATHOS_LUT_CHAN_702625_IDX,
+       ATHOS_LUT_CHAN_702750_IDX,
+       ATHOS_LUT_CHAN_702875_IDX,
+       ATHOS_LUT_CHAN_703000_IDX,
+       ATHOS_LUT_CHAN_703125_IDX,
+       ATHOS_LUT_CHAN_703250_IDX,
+       ATHOS_LUT_CHAN_703375_IDX,
+       ATHOS_LUT_CHAN_703500_IDX,
+       ATHOS_LUT_CHAN_703625_IDX,
+       ATHOS_LUT_CHAN_703750_IDX,
+       ATHOS_LUT_CHAN_703875_IDX,
+       ATHOS_LUT_CHAN_704000_IDX,
+       ATHOS_LUT_CHAN_704125_IDX,
+       ATHOS_LUT_CHAN_704250_IDX,
+       ATHOS_LUT_CHAN_704375_IDX,
+       ATHOS_LUT_CHAN_704500_IDX,
+       ATHOS_LUT_CHAN_704625_IDX,
+       ATHOS_LUT_CHAN_704750_IDX,
+       ATHOS_LUT_CHAN_704875_IDX,
+       ATHOS_LUT_CHAN_705000_IDX,
+       ATHOS_LUT_CHAN_705125_IDX,
+       ATHOS_LUT_CHAN_705250_IDX,
+       ATHOS_LUT_CHAN_705375_IDX,
+       ATHOS_LUT_CHAN_705500_IDX,
+       ATHOS_LUT_CHAN_705625_IDX,
+       ATHOS_LUT_CHAN_705750_IDX,
+       ATHOS_LUT_CHAN_705875_IDX,
+       ATHOS_LUT_CHAN_706000_IDX,
+       ATHOS_LUT_CHAN_706125_IDX,
+       ATHOS_LUT_CHAN_706250_IDX,
+       ATHOS_LUT_CHAN_706375_IDX,
+       ATHOS_LUT_CHAN_706500_IDX,
+       ATHOS_LUT_CHAN_706625_IDX,
+       ATHOS_LUT_CHAN_706750_IDX,
+       ATHOS_LUT_CHAN_706875_IDX,
+       ATHOS_LUT_CHAN_707000_IDX,
+       ATHOS_LUT_CHAN_707125_IDX,
+       ATHOS_LUT_CHAN_707250_IDX,
+       ATHOS_LUT_CHAN_707375_IDX,
+       ATHOS_LUT_CHAN_707500_IDX,
+       ATHOS_LUT_CHAN_707625_IDX,
+       ATHOS_LUT_CHAN_707750_IDX,
+       ATHOS_LUT_CHAN_707875_IDX,
+       ATHOS_LUT_CHAN_708000_IDX,
+       ATHOS_LUT_CHAN_708125_IDX,
+       ATHOS_LUT_CHAN_708250_IDX,
+       ATHOS_LUT_CHAN_708375_IDX,
+       ATHOS_LUT_CHAN_708500_IDX,
+       ATHOS_LUT_CHAN_708625_IDX,
+       ATHOS_LUT_CHAN_708750_IDX,
+       ATHOS_LUT_CHAN_708875_IDX,
+       ATHOS_LUT_CHAN_709000_IDX,
+       ATHOS_LUT_CHAN_709125_IDX,
+       ATHOS_LUT_CHAN_709250_IDX,
+       ATHOS_LUT_CHAN_709375_IDX,
+       ATHOS_LUT_CHAN_709500_IDX,
+       ATHOS_LUT_CHAN_709625_IDX,
+       ATHOS_LUT_CHAN_709750_IDX,
+       ATHOS_LUT_CHAN_709875_IDX,
+       ATHOS_LUT_CHAN_710000_IDX,
+       ATHOS_LUT_CHAN_710125_IDX,
+       ATHOS_LUT_CHAN_710250_IDX,
+       ATHOS_LUT_CHAN_710375_IDX,
+       ATHOS_LUT_CHAN_710500_IDX,
+       ATHOS_LUT_CHAN_710625_IDX,
+       ATHOS_LUT_CHAN_710750_IDX,
+       ATHOS_LUT_CHAN_710875_IDX,
+       ATHOS_LUT_CHAN_711000_IDX,
+       ATHOS_LUT_CHAN_711125_IDX,
+       ATHOS_LUT_CHAN_711250_IDX,
+       ATHOS_LUT_CHAN_711375_IDX,
+       ATHOS_LUT_CHAN_711500_IDX,
+       ATHOS_LUT_CHAN_711625_IDX,
+       ATHOS_LUT_CHAN_711750_IDX,
+       ATHOS_LUT_CHAN_711875_IDX,
+       ATHOS_LUT_CHAN_712000_IDX,
+       ATHOS_LUT_CHAN_712125_IDX,
+       ATHOS_LUT_CHAN_712250_IDX,
+       ATHOS_LUT_CHAN_712375_IDX,
+       ATHOS_LUT_CHAN_712500_IDX,
+       ATHOS_LUT_CHAN_712625_IDX,
+       ATHOS_LUT_CHAN_712750_IDX,
+       ATHOS_LUT_CHAN_712875_IDX,
+       ATHOS_LUT_CHAN_713000_IDX,
+       ATHOS_LUT_CHAN_713125_IDX,
+       ATHOS_LUT_CHAN_713250_IDX,
+       ATHOS_LUT_CHAN_713375_IDX,
+       ATHOS_LUT_CHAN_713500_IDX,
+       ATHOS_LUT_CHAN_713625_IDX,
+       ATHOS_LUT_CHAN_713750_IDX,
+       ATHOS_LUT_CHAN_713875_IDX,
+       ATHOS_LUT_CHAN_714000_IDX,
+       ATHOS_LUT_CHAN_714125_IDX,
+       ATHOS_LUT_CHAN_714250_IDX,
+       ATHOS_LUT_CHAN_714375_IDX,
+       ATHOS_LUT_CHAN_714500_IDX,
+       ATHOS_LUT_CHAN_714625_IDX,
+       ATHOS_LUT_CHAN_714750_IDX,
+       ATHOS_LUT_CHAN_714875_IDX,
+       ATHOS_LUT_CHAN_715000_IDX,
+       ATHOS_LUT_CHAN_715125_IDX,
+       ATHOS_LUT_CHAN_715250_IDX,
+       ATHOS_LUT_CHAN_715375_IDX,
+       ATHOS_LUT_CHAN_715500_IDX,
+       ATHOS_LUT_CHAN_715625_IDX,
+       ATHOS_LUT_CHAN_715750_IDX,
+       ATHOS_LUT_CHAN_715875_IDX,
+       ATHOS_LUT_CHAN_716000_IDX,
+       ATHOS_LUT_CHAN_716125_IDX,
+       ATHOS_LUT_CHAN_716250_IDX,
+       ATHOS_LUT_CHAN_716375_IDX,
+       ATHOS_LUT_CHAN_716500_IDX,
+       ATHOS_LUT_CHAN_716625_IDX,
+       ATHOS_LUT_CHAN_716750_IDX,
+       ATHOS_LUT_CHAN_716875_IDX,
+       ATHOS_LUT_CHAN_717000_IDX,
+       ATHOS_LUT_CHAN_717125_IDX,
+       ATHOS_LUT_CHAN_717250_IDX,
+       ATHOS_LUT_CHAN_717375_IDX,
+       ATHOS_LUT_CHAN_717500_IDX,
+       ATHOS_LUT_CHAN_717625_IDX,
+       ATHOS_LUT_CHAN_717750_IDX,
+       ATHOS_LUT_CHAN_717875_IDX,
+       ATHOS_LUT_CHAN_718000_IDX,
+       ATHOS_LUT_CHAN_718125_IDX,
+       ATHOS_LUT_CHAN_718250_IDX,
+       ATHOS_LUT_CHAN_718375_IDX,
+       ATHOS_LUT_CHAN_718500_IDX,
+       ATHOS_LUT_CHAN_718625_IDX,
+       ATHOS_LUT_CHAN_718750_IDX,
+       ATHOS_LUT_CHAN_718875_IDX,
+       ATHOS_LUT_CHAN_719000_IDX,
+       ATHOS_LUT_CHAN_719125_IDX,
+       ATHOS_LUT_CHAN_719250_IDX,
+       ATHOS_LUT_CHAN_719375_IDX,
+       ATHOS_LUT_CHAN_719500_IDX,
+       ATHOS_LUT_CHAN_719625_IDX,
+       ATHOS_LUT_CHAN_719750_IDX,
+       ATHOS_LUT_CHAN_719875_IDX,
+       ATHOS_LUT_CHAN_720000_IDX,
+       ATHOS_LUT_CHAN_720125_IDX,
+       ATHOS_LUT_CHAN_720250_IDX,
+       ATHOS_LUT_CHAN_720375_IDX,
+       ATHOS_LUT_CHAN_720500_IDX,
+       ATHOS_LUT_CHAN_720625_IDX,
+       ATHOS_LUT_CHAN_720750_IDX,
+       ATHOS_LUT_CHAN_720875_IDX,
+       ATHOS_LUT_CHAN_721000_IDX,
+       ATHOS_LUT_CHAN_721125_IDX,
+       ATHOS_LUT_CHAN_721250_IDX,
+       ATHOS_LUT_CHAN_721375_IDX,
+       ATHOS_LUT_CHAN_721500_IDX,
+       ATHOS_LUT_CHAN_6G_MAX
+};
+
+#define athos_lut_line common_lut_line
+
+extern const struct athos_lut_line athos_lut_6g_40_mhz[ATHOS_LUT_CHAN_6G_MAX];
+extern const struct athos_lut_line athos_lut_6g_60_mhz[ATHOS_LUT_CHAN_6G_MAX];
+
+#endif /* CL_PHY_ATHOS_LUT_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.
________________________________


^ permalink raw reply related	[flat|nested] 262+ messages in thread

* [RFC v1 129/256] cl8k: add phy/phy_common_lut.c
  2021-06-17 15:58 [RFC v1 000/256] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (127 preceding siblings ...)
  2021-06-17 16:00 ` [RFC v1 128/256] cl8k: add phy/phy_athos_lut.h viktor.barna
@ 2021-06-17 16:00 ` viktor.barna
  2021-06-17 16:00 ` [RFC v1 130/256] cl8k: add phy/phy_common_lut.h viktor.barna
                   ` (128 subsequent siblings)
  257 siblings, 0 replies; 262+ messages in thread
From: viktor.barna @ 2021-06-17 16:00 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Oleksandr Savchenko, Shay Bar, Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

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

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 .../wireless/celeno/cl8k/phy/phy_common_lut.c | 143 ++++++++++++++++++
 1 file changed, 143 insertions(+)
 create mode 100644 drivers/net/wireless/celeno/cl8k/phy/phy_common_lut.c

diff --git a/drivers/net/wireless/celeno/cl8k/phy/phy_common_lut.c b/drivers/net/wireless/celeno/cl8k/phy/phy_common_lut.c
new file mode 100644
index 000000000000..73a79f297718
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/phy/phy_common_lut.c
@@ -0,0 +1,143 @@
+// SPDX-License-Identifier: MIT
+/* Copyright(c) 2019-2021, Celeno Communications Ltd. */
+
+#include "phy_common_lut.h"
+#include "phy_athos_lut.h"
+#include "phy_olympus_lut.h"
+
+const struct common_lut_line *cl_phy_oly_get_lut_index(const struct common_lut_line *lut_table,
+                                                      const u16 lut_table_size, u16 freq)
+{
+       u16 frequency_idx;
+
+       /* Fine highest frequency in  lut table that is lower or equal freq */
+       for (frequency_idx = 0;
+               frequency_idx < lut_table_size && lut_table[frequency_idx].frequency_q2 <= freq;
+               ++frequency_idx)
+               ;
+
+       if (frequency_idx)
+               frequency_idx--;
+
+       return &lut_table[frequency_idx];
+}
+
+void cl_phy_lut_2_lines_update(u16 freq,
+                              const struct common_lut_line *lut_table_60m,
+                              const u16 lut_table_60m_size,
+                              const struct common_lut_line *lut_table_40m,
+                              const u16 lut_table_40m_size,
+                              struct mm_mac_api_lut_line *api_lut_line)
+{
+       /* 1. configure the 40M xco lut table */
+       const struct common_lut_line *data_line =
+               cl_phy_oly_get_lut_index(lut_table_40m, lut_table_40m_size, freq);
+
+       api_lut_line->rfic_specific.olympus_2_lines.xco_40M.freqmeastarg =
+               cpu_to_le32(data_line->freqmeastarg);
+       api_lut_line->rfic_specific.olympus_2_lines.xco_40M.nfrac =
+               cpu_to_le32(data_line->nfrac);
+       api_lut_line->rfic_specific.olympus_2_lines.xco_40M.nint =
+               data_line->nint;
+       api_lut_line->rfic_specific.olympus_2_lines.xco_40M.vcocalsel =
+               data_line->vcocalsel;
+
+       /* 2. configure the 60M xco lut table */
+       data_line = cl_phy_oly_get_lut_index(lut_table_60m, lut_table_60m_size, freq);
+       api_lut_line->rfic_specific.olympus_2_lines.xco_60M.freqmeastarg =
+               cpu_to_le32(data_line->freqmeastarg);
+       api_lut_line->rfic_specific.olympus_2_lines.xco_60M.nfrac =
+               cpu_to_le32(data_line->nfrac);
+       api_lut_line->rfic_specific.olympus_2_lines.xco_60M.nint =
+               data_line->nint;
+       api_lut_line->rfic_specific.olympus_2_lines.xco_60M.vcocalsel =
+               data_line->vcocalsel;
+
+       /* 3. set frequency */
+       api_lut_line->frequency_q2 = cpu_to_le16(freq);
+}
+
+void cl_phy_lut_3_lines_update(u16 freq,
+                              const struct common_lut_line *lut_table_60m_s1,
+                              const u16 lut_table_60m_s1_size,
+                              const struct common_lut_line *lut_table_60m_s0,
+                              const u16 lut_table_60m_s0_size,
+                              const struct common_lut_line *lut_table_40m,
+                              const u16 lut_table_40m_size,
+                              struct mm_mac_api_lut_line *api_lut_line)
+{
+       /* 1. configure the 40M xco lut table */
+       const struct common_lut_line *data_line =
+       cl_phy_oly_get_lut_index(lut_table_40m, lut_table_40m_size, freq);
+
+       api_lut_line->rfic_specific.olympus_3_lines.xco_40M.freqmeastarg =
+       cpu_to_le32(data_line->freqmeastarg);
+       api_lut_line->rfic_specific.olympus_3_lines.xco_40M.nfrac =
+       cpu_to_le32(data_line->nfrac);
+       api_lut_line->rfic_specific.olympus_3_lines.xco_40M.nint =
+       data_line->nint;
+       api_lut_line->rfic_specific.olympus_3_lines.xco_40M.vcocalsel =
+       data_line->vcocalsel;
+
+       /* 2. configure the 60M xco lut table , sxpfddesel=1*/
+       data_line = cl_phy_oly_get_lut_index(lut_table_60m_s1, lut_table_60m_s1_size, freq);
+       api_lut_line->rfic_specific.olympus_3_lines.xco_60M_s1.freqmeastarg =
+       cpu_to_le32(data_line->freqmeastarg);
+       api_lut_line->rfic_specific.olympus_3_lines.xco_60M_s1.nfrac =
+       cpu_to_le32(data_line->nfrac);
+       api_lut_line->rfic_specific.olympus_3_lines.xco_60M_s1.nint =
+       data_line->nint;
+       api_lut_line->rfic_specific.olympus_3_lines.xco_60M_s1.vcocalsel =
+       data_line->vcocalsel;
+
+       /* 3. configure the 60M xco lut table , sxpfddesel=0*/
+       data_line = cl_phy_oly_get_lut_index(lut_table_60m_s0, lut_table_60m_s0_size, freq);
+       api_lut_line->rfic_specific.olympus_3_lines.xco_60M_s0.freqmeastarg =
+       cpu_to_le32(data_line->freqmeastarg);
+       api_lut_line->rfic_specific.olympus_3_lines.xco_60M_s0.nfrac =
+       cpu_to_le32(data_line->nfrac);
+       api_lut_line->rfic_specific.olympus_3_lines.xco_60M_s0.nint =
+       data_line->nint;
+       api_lut_line->rfic_specific.olympus_3_lines.xco_60M_s0.vcocalsel =
+       data_line->vcocalsel;
+
+       /* 4. set frequency */
+       api_lut_line->frequency_q2 = cpu_to_le16(freq);
+}
+
+void cl_phy_oly_lut_update(u8 nl_band, u16 freq,
+                          struct mm_mac_api_lut_line *api_lut_line)
+{
+       switch (nl_band) {
+       case NL80211_BAND_2GHZ:
+               cl_phy_lut_3_lines_update(freq,
+                                         olympus_lut_24g_60_mhz_s1,
+                                         OLYMPUS_LUT_CHAN_24G_MAX,
+                                         olympus_lut_24g_60_mhz_s0,
+                                         OLYMPUS_LUT_CHAN_24G_MAX,
+                                         olympus_lut_24g_40_mhz,
+                                         OLYMPUS_LUT_CHAN_24G_MAX,
+                                         api_lut_line);
+               break;
+       case NL80211_BAND_5GHZ:
+               cl_phy_lut_3_lines_update(freq,
+                                         olympus_lut_5g_60_mhz_s1,
+                                         OLYMPUS_LUT_CHAN_5G_MAX,
+                                         olympus_lut_5g_60_mhz_s0,
+                                         OLYMPUS_LUT_CHAN_5G_MAX,
+                                         olympus_lut_5g_40_mhz,
+                                         OLYMPUS_LUT_CHAN_5G_MAX,
+                                         api_lut_line);
+               break;
+       case NL80211_BAND_6GHZ:
+               cl_phy_lut_2_lines_update(freq,
+                                         athos_lut_6g_60_mhz, ATHOS_LUT_CHAN_6G_MAX,
+                                         athos_lut_6g_40_mhz, ATHOS_LUT_CHAN_6G_MAX,
+                                         api_lut_line);
+               break;
+       default:
+               /* If nl_band is not supported return zero's */
+               memset(api_lut_line, 0, sizeof(struct mm_mac_api_lut_line));
+               api_lut_line->frequency_q2 = cpu_to_le16(freq);
+       }
+}
--
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.
________________________________


^ permalink raw reply related	[flat|nested] 262+ messages in thread

* [RFC v1 130/256] cl8k: add phy/phy_common_lut.h
  2021-06-17 15:58 [RFC v1 000/256] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (128 preceding siblings ...)
  2021-06-17 16:00 ` [RFC v1 129/256] cl8k: add phy/phy_common_lut.c viktor.barna
@ 2021-06-17 16:00 ` viktor.barna
  2021-06-17 16:00 ` [RFC v1 131/256] cl8k: add phy/phy_olympus_lut.c viktor.barna
                   ` (127 subsequent siblings)
  257 siblings, 0 replies; 262+ messages in thread
From: viktor.barna @ 2021-06-17 16:00 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Oleksandr Savchenko, Shay Bar, Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

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

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 .../wireless/celeno/cl8k/phy/phy_common_lut.h | 21 +++++++++++++++++++
 1 file changed, 21 insertions(+)
 create mode 100644 drivers/net/wireless/celeno/cl8k/phy/phy_common_lut.h

diff --git a/drivers/net/wireless/celeno/cl8k/phy/phy_common_lut.h b/drivers/net/wireless/celeno/cl8k/phy/phy_common_lut.h
new file mode 100644
index 000000000000..7ff17cb81ca3
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/phy/phy_common_lut.h
@@ -0,0 +1,21 @@
+/* SPDX-License-Identifier: MIT */
+/* Copyright(c) 2019-2021, Celeno Communications Ltd. */
+
+#ifndef CL_PHY_COMMON_LUT_H
+#define CL_PHY_COMMON_LUT_H
+
+#include <linux/types.h>
+#include "fw/fw_msg.h"
+
+struct common_lut_line {
+       u16 frequency_q2;
+       u8 vcocalsel;
+       u8 nint;
+       u32 nfrac;
+       u32 freqmeastarg;
+};
+
+void cl_phy_oly_lut_update(u8 nl_band, u16 freq,
+                          struct mm_mac_api_lut_line *api_lut_line);
+
+#endif /* CL_PHY_COMMON_LUT_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.
________________________________


^ permalink raw reply related	[flat|nested] 262+ messages in thread

* [RFC v1 131/256] cl8k: add phy/phy_olympus_lut.c
  2021-06-17 15:58 [RFC v1 000/256] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (129 preceding siblings ...)
  2021-06-17 16:00 ` [RFC v1 130/256] cl8k: add phy/phy_common_lut.h viktor.barna
@ 2021-06-17 16:00 ` viktor.barna
  2021-06-17 16:00 ` [RFC v1 132/256] cl8k: add phy/phy_olympus_lut.h viktor.barna
                   ` (126 subsequent siblings)
  257 siblings, 0 replies; 262+ messages in thread
From: viktor.barna @ 2021-06-17 16:00 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Oleksandr Savchenko, Shay Bar, Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

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

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 .../celeno/cl8k/phy/phy_olympus_lut.c         | 2189 +++++++++++++++++
 1 file changed, 2189 insertions(+)
 create mode 100644 drivers/net/wireless/celeno/cl8k/phy/phy_olympus_lut.c

diff --git a/drivers/net/wireless/celeno/cl8k/phy/phy_olympus_lut.c b/drivers/net/wireless/celeno/cl8k/phy/phy_olympus_lut.c
new file mode 100644
index 000000000000..c33f4460d6fa
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/phy/phy_olympus_lut.c
@@ -0,0 +1,2189 @@
+// SPDX-License-Identifier: MIT
+/* Copyright(c) 2019-2021, Celeno Communications Ltd. */
+
+#include "phy_olympus_lut.h"
+
+const struct olympus_lut_line olympus_lut_5g_40_mhz[OLYMPUS_LUT_CHAN_5G_MAX] = {
+       [OLYMPUS_LUT_CHAN_516000_IDX] = { 20640, 0x0, 0x56, 0x0, 0x6B8 },
+       [OLYMPUS_LUT_CHAN_516125_IDX] = { 20645, 0x0, 0x56, 0xAAAB, 0x6B8 },
+       [OLYMPUS_LUT_CHAN_516250_IDX] = { 20650, 0x0, 0x56, 0x15555, 0x6B9 },
+       [OLYMPUS_LUT_CHAN_516375_IDX] = { 20655, 0x0, 0x56, 0x20000, 0x6B9 },
+       [OLYMPUS_LUT_CHAN_516500_IDX] = { 20660, 0x0, 0x56, 0x2AAAB, 0x6BA },
+       [OLYMPUS_LUT_CHAN_516625_IDX] = { 20665, 0x0, 0x56, 0x35555, 0x6BA },
+       [OLYMPUS_LUT_CHAN_516750_IDX] = { 20670, 0x0, 0x56, 0x40000, 0x6BB },
+       [OLYMPUS_LUT_CHAN_516875_IDX] = { 20675, 0x0, 0x56, 0x4AAAB, 0x6BB },
+       [OLYMPUS_LUT_CHAN_517000_IDX] = { 20680, 0x0, 0x56, 0x55555, 0x6BB },
+       [OLYMPUS_LUT_CHAN_517125_IDX] = { 20685, 0x0, 0x56, 0x60000, 0x6BC },
+       [OLYMPUS_LUT_CHAN_517250_IDX] = { 20690, 0x0, 0x56, 0x6AAAB, 0x6BC },
+       [OLYMPUS_LUT_CHAN_517375_IDX] = { 20695, 0x0, 0x56, 0x75555, 0x6BD },
+       [OLYMPUS_LUT_CHAN_517500_IDX] = { 20700, 0x0, 0x56, 0x80000, 0x6BD },
+       [OLYMPUS_LUT_CHAN_517625_IDX] = { 20705, 0x0, 0x56, 0x8AAAB, 0x6BD },
+       [OLYMPUS_LUT_CHAN_517750_IDX] = { 20710, 0x0, 0x56, 0x95555, 0x6BE },
+       [OLYMPUS_LUT_CHAN_517875_IDX] = { 20715, 0x0, 0x56, 0xA0000, 0x6BE },
+       [OLYMPUS_LUT_CHAN_518000_IDX] = { 20720, 0x1, 0x56, 0xAAAAB, 0x6BF },
+       [OLYMPUS_LUT_CHAN_518125_IDX] = { 20725, 0x1, 0x56, 0xB5555, 0x6BF },
+       [OLYMPUS_LUT_CHAN_518250_IDX] = { 20730, 0x1, 0x56, 0xC0000, 0x6C0 },
+       [OLYMPUS_LUT_CHAN_518375_IDX] = { 20735, 0x1, 0x56, 0xCAAAB, 0x6C0 },
+       [OLYMPUS_LUT_CHAN_518500_IDX] = { 20740, 0x1, 0x56, 0xD5555, 0x6C0 },
+       [OLYMPUS_LUT_CHAN_518625_IDX] = { 20745, 0x1, 0x56, 0xE0000, 0x6C1 },
+       [OLYMPUS_LUT_CHAN_518750_IDX] = { 20750, 0x1, 0x56, 0xEAAAB, 0x6C1 },
+       [OLYMPUS_LUT_CHAN_518875_IDX] = { 20755, 0x1, 0x56, 0xF5555, 0x6C2 },
+       [OLYMPUS_LUT_CHAN_519000_IDX] = { 20760, 0x1, 0x56, 0x100000, 0x6C2 },
+       [OLYMPUS_LUT_CHAN_519125_IDX] = { 20765, 0x1, 0x56, 0x10AAAB, 0x6C2 },
+       [OLYMPUS_LUT_CHAN_519250_IDX] = { 20770, 0x1, 0x56, 0x115555, 0x6C3 },
+       [OLYMPUS_LUT_CHAN_519375_IDX] = { 20775, 0x1, 0x56, 0x120000, 0x6C3 },
+       [OLYMPUS_LUT_CHAN_519500_IDX] = { 20780, 0x1, 0x56, 0x12AAAB, 0x6C4 },
+       [OLYMPUS_LUT_CHAN_519625_IDX] = { 20785, 0x1, 0x56, 0x135555, 0x6C4 },
+       [OLYMPUS_LUT_CHAN_519750_IDX] = { 20790, 0x1, 0x56, 0x140000, 0x6C5 },
+       [OLYMPUS_LUT_CHAN_519875_IDX] = { 20795, 0x1, 0x56, 0x14AAAB, 0x6C5 },
+       [OLYMPUS_LUT_CHAN_520000_IDX] = { 20800, 0x1, 0x56, 0x155555, 0x6C5 },
+       [OLYMPUS_LUT_CHAN_520125_IDX] = { 20805, 0x1, 0x56, 0x160000, 0x6C6 },
+       [OLYMPUS_LUT_CHAN_520250_IDX] = { 20810, 0x1, 0x56, 0x16AAAB, 0x6C6 },
+       [OLYMPUS_LUT_CHAN_520375_IDX] = { 20815, 0x1, 0x56, 0x175555, 0x6C7 },
+       [OLYMPUS_LUT_CHAN_520500_IDX] = { 20820, 0x1, 0x56, 0x180000, 0x6C7 },
+       [OLYMPUS_LUT_CHAN_520625_IDX] = { 20825, 0x1, 0x56, 0x18AAAB, 0x6C7 },
+       [OLYMPUS_LUT_CHAN_520750_IDX] = { 20830, 0x1, 0x56, 0x195555, 0x6C8 },
+       [OLYMPUS_LUT_CHAN_520875_IDX] = { 20835, 0x1, 0x56, 0x1A0000, 0x6C8 },
+       [OLYMPUS_LUT_CHAN_521000_IDX] = { 20840, 0x1, 0x56, 0x1AAAAB, 0x6C9 },
+       [OLYMPUS_LUT_CHAN_521125_IDX] = { 20845, 0x1, 0x56, 0x1B5555, 0x6C9 },
+       [OLYMPUS_LUT_CHAN_521250_IDX] = { 20850, 0x1, 0x56, 0x1C0000, 0x6CA },
+       [OLYMPUS_LUT_CHAN_521375_IDX] = { 20855, 0x1, 0x56, 0x1CAAAB, 0x6CA },
+       [OLYMPUS_LUT_CHAN_521500_IDX] = { 20860, 0x1, 0x56, 0x1D5555, 0x6CA },
+       [OLYMPUS_LUT_CHAN_521625_IDX] = { 20865, 0x1, 0x56, 0x1E0000, 0x6CB },
+       [OLYMPUS_LUT_CHAN_521750_IDX] = { 20870, 0x1, 0x56, 0x1EAAAB, 0x6CB },
+       [OLYMPUS_LUT_CHAN_521875_IDX] = { 20875, 0x1, 0x56, 0x1F5555, 0x6CC },
+       [OLYMPUS_LUT_CHAN_522000_IDX] = { 20880, 0x1, 0x57, 0x0, 0x6CC },
+       [OLYMPUS_LUT_CHAN_522125_IDX] = { 20885, 0x1, 0x57, 0xAAAB, 0x6CC },
+       [OLYMPUS_LUT_CHAN_522250_IDX] = { 20890, 0x1, 0x57, 0x15555, 0x6CD },
+       [OLYMPUS_LUT_CHAN_522375_IDX] = { 20895, 0x1, 0x57, 0x20000, 0x6CD },
+       [OLYMPUS_LUT_CHAN_522500_IDX] = { 20900, 0x1, 0x57, 0x2AAAB, 0x6CE },
+       [OLYMPUS_LUT_CHAN_522625_IDX] = { 20905, 0x1, 0x57, 0x35555, 0x6CE },
+       [OLYMPUS_LUT_CHAN_522750_IDX] = { 20910, 0x1, 0x57, 0x40000, 0x6CF },
+       [OLYMPUS_LUT_CHAN_522875_IDX] = { 20915, 0x1, 0x57, 0x4AAAB, 0x6CF },
+       [OLYMPUS_LUT_CHAN_523000_IDX] = { 20920, 0x1, 0x57, 0x55555, 0x6CF },
+       [OLYMPUS_LUT_CHAN_523125_IDX] = { 20925, 0x1, 0x57, 0x60000, 0x6D0 },
+       [OLYMPUS_LUT_CHAN_523250_IDX] = { 20930, 0x1, 0x57, 0x6AAAB, 0x6D0 },
+       [OLYMPUS_LUT_CHAN_523375_IDX] = { 20935, 0x1, 0x57, 0x75555, 0x6D1 },
+       [OLYMPUS_LUT_CHAN_523500_IDX] = { 20940, 0x1, 0x57, 0x80000, 0x6D1 },
+       [OLYMPUS_LUT_CHAN_523625_IDX] = { 20945, 0x1, 0x57, 0x8AAAB, 0x6D1 },
+       [OLYMPUS_LUT_CHAN_523750_IDX] = { 20950, 0x1, 0x57, 0x95555, 0x6D2 },
+       [OLYMPUS_LUT_CHAN_523875_IDX] = { 20955, 0x1, 0x57, 0xA0000, 0x6D2 },
+       [OLYMPUS_LUT_CHAN_524000_IDX] = { 20960, 0x1, 0x57, 0xAAAAB, 0x6D3 },
+       [OLYMPUS_LUT_CHAN_524125_IDX] = { 20965, 0x1, 0x57, 0xB5555, 0x6D3 },
+       [OLYMPUS_LUT_CHAN_524250_IDX] = { 20970, 0x1, 0x57, 0xC0000, 0x6D4 },
+       [OLYMPUS_LUT_CHAN_524375_IDX] = { 20975, 0x1, 0x57, 0xCAAAB, 0x6D4 },
+       [OLYMPUS_LUT_CHAN_524500_IDX] = { 20980, 0x1, 0x57, 0xD5555, 0x6D4 },
+       [OLYMPUS_LUT_CHAN_524625_IDX] = { 20985, 0x1, 0x57, 0xE0000, 0x6D5 },
+       [OLYMPUS_LUT_CHAN_524750_IDX] = { 20990, 0x1, 0x57, 0xEAAAB, 0x6D5 },
+       [OLYMPUS_LUT_CHAN_524875_IDX] = { 20995, 0x1, 0x57, 0xF5555, 0x6D6 },
+       [OLYMPUS_LUT_CHAN_525000_IDX] = { 21000, 0x1, 0x57, 0x100000, 0x6D6 },
+       [OLYMPUS_LUT_CHAN_525125_IDX] = { 21005, 0x1, 0x57, 0x10AAAB, 0x6D6 },
+       [OLYMPUS_LUT_CHAN_525250_IDX] = { 21010, 0x1, 0x57, 0x115555, 0x6D7 },
+       [OLYMPUS_LUT_CHAN_525375_IDX] = { 21015, 0x1, 0x57, 0x120000, 0x6D7 },
+       [OLYMPUS_LUT_CHAN_525500_IDX] = { 21020, 0x1, 0x57, 0x12AAAB, 0x6D8 },
+       [OLYMPUS_LUT_CHAN_525625_IDX] = { 21025, 0x1, 0x57, 0x135555, 0x6D8 },
+       [OLYMPUS_LUT_CHAN_525750_IDX] = { 21030, 0x1, 0x57, 0x140000, 0x6D9 },
+       [OLYMPUS_LUT_CHAN_525875_IDX] = { 21035, 0x1, 0x57, 0x14AAAB, 0x6D9 },
+       [OLYMPUS_LUT_CHAN_526000_IDX] = { 21040, 0x1, 0x57, 0x155555, 0x6D9 },
+       [OLYMPUS_LUT_CHAN_526125_IDX] = { 21045, 0x1, 0x57, 0x160000, 0x6DA },
+       [OLYMPUS_LUT_CHAN_526250_IDX] = { 21050, 0x1, 0x57, 0x16AAAB, 0x6DA },
+       [OLYMPUS_LUT_CHAN_526375_IDX] = { 21055, 0x1, 0x57, 0x175555, 0x6DB },
+       [OLYMPUS_LUT_CHAN_526500_IDX] = { 21060, 0x1, 0x57, 0x180000, 0x6DB },
+       [OLYMPUS_LUT_CHAN_526625_IDX] = { 21065, 0x1, 0x57, 0x18AAAB, 0x6DB },
+       [OLYMPUS_LUT_CHAN_526750_IDX] = { 21070, 0x1, 0x57, 0x195555, 0x6DC },
+       [OLYMPUS_LUT_CHAN_526875_IDX] = { 21075, 0x1, 0x57, 0x1A0000, 0x6DC },
+       [OLYMPUS_LUT_CHAN_527000_IDX] = { 21080, 0x1, 0x57, 0x1AAAAB, 0x6DD },
+       [OLYMPUS_LUT_CHAN_527125_IDX] = { 21085, 0x1, 0x57, 0x1B5555, 0x6DD },
+       [OLYMPUS_LUT_CHAN_527250_IDX] = { 21090, 0x1, 0x57, 0x1C0000, 0x6DE },
+       [OLYMPUS_LUT_CHAN_527375_IDX] = { 21095, 0x1, 0x57, 0x1CAAAB, 0x6DE },
+       [OLYMPUS_LUT_CHAN_527500_IDX] = { 21100, 0x1, 0x57, 0x1D5555, 0x6DE },
+       [OLYMPUS_LUT_CHAN_527625_IDX] = { 21105, 0x1, 0x57, 0x1E0000, 0x6DF },
+       [OLYMPUS_LUT_CHAN_527750_IDX] = { 21110, 0x1, 0x57, 0x1EAAAB, 0x6DF },
+       [OLYMPUS_LUT_CHAN_527875_IDX] = { 21115, 0x1, 0x57, 0x1F5555, 0x6E0 },
+       [OLYMPUS_LUT_CHAN_528000_IDX] = { 21120, 0x1, 0x58, 0x0, 0x6E0 },
+       [OLYMPUS_LUT_CHAN_528125_IDX] = { 21125, 0x1, 0x58, 0xAAAB, 0x6E0 },
+       [OLYMPUS_LUT_CHAN_528250_IDX] = { 21130, 0x1, 0x58, 0x15555, 0x6E1 },
+       [OLYMPUS_LUT_CHAN_528375_IDX] = { 21135, 0x1, 0x58, 0x20000, 0x6E1 },
+       [OLYMPUS_LUT_CHAN_528500_IDX] = { 21140, 0x1, 0x58, 0x2AAAB, 0x6E2 },
+       [OLYMPUS_LUT_CHAN_528625_IDX] = { 21145, 0x1, 0x58, 0x35555, 0x6E2 },
+       [OLYMPUS_LUT_CHAN_528750_IDX] = { 21150, 0x1, 0x58, 0x40000, 0x6E3 },
+       [OLYMPUS_LUT_CHAN_528875_IDX] = { 21155, 0x1, 0x58, 0x4AAAB, 0x6E3 },
+       [OLYMPUS_LUT_CHAN_529000_IDX] = { 21160, 0x1, 0x58, 0x55555, 0x6E3 },
+       [OLYMPUS_LUT_CHAN_529125_IDX] = { 21165, 0x1, 0x58, 0x60000, 0x6E4 },
+       [OLYMPUS_LUT_CHAN_529250_IDX] = { 21170, 0x1, 0x58, 0x6AAAB, 0x6E4 },
+       [OLYMPUS_LUT_CHAN_529375_IDX] = { 21175, 0x1, 0x58, 0x75555, 0x6E5 },
+       [OLYMPUS_LUT_CHAN_529500_IDX] = { 21180, 0x1, 0x58, 0x80000, 0x6E5 },
+       [OLYMPUS_LUT_CHAN_529625_IDX] = { 21185, 0x1, 0x58, 0x8AAAB, 0x6E5 },
+       [OLYMPUS_LUT_CHAN_529750_IDX] = { 21190, 0x1, 0x58, 0x95555, 0x6E6 },
+       [OLYMPUS_LUT_CHAN_529875_IDX] = { 21195, 0x1, 0x58, 0xA0000, 0x6E6 },
+       [OLYMPUS_LUT_CHAN_530000_IDX] = { 21200, 0x1, 0x58, 0xAAAAB, 0x6E7 },
+       [OLYMPUS_LUT_CHAN_530125_IDX] = { 21205, 0x1, 0x58, 0xB5555, 0x6E7 },
+       [OLYMPUS_LUT_CHAN_530250_IDX] = { 21210, 0x1, 0x58, 0xC0000, 0x6E8 },
+       [OLYMPUS_LUT_CHAN_530375_IDX] = { 21215, 0x1, 0x58, 0xCAAAB, 0x6E8 },
+       [OLYMPUS_LUT_CHAN_530500_IDX] = { 21220, 0x1, 0x58, 0xD5555, 0x6E8 },
+       [OLYMPUS_LUT_CHAN_530625_IDX] = { 21225, 0x1, 0x58, 0xE0000, 0x6E9 },
+       [OLYMPUS_LUT_CHAN_530750_IDX] = { 21230, 0x1, 0x58, 0xEAAAB, 0x6E9 },
+       [OLYMPUS_LUT_CHAN_530875_IDX] = { 21235, 0x1, 0x58, 0xF5555, 0x6EA },
+       [OLYMPUS_LUT_CHAN_531000_IDX] = { 21240, 0x1, 0x58, 0x100000, 0x6EA },
+       [OLYMPUS_LUT_CHAN_531125_IDX] = { 21245, 0x1, 0x58, 0x10AAAB, 0x6EA },
+       [OLYMPUS_LUT_CHAN_531250_IDX] = { 21250, 0x1, 0x58, 0x115555, 0x6EB },
+       [OLYMPUS_LUT_CHAN_531375_IDX] = { 21255, 0x1, 0x58, 0x120000, 0x6EB },
+       [OLYMPUS_LUT_CHAN_531500_IDX] = { 21260, 0x1, 0x58, 0x12AAAB, 0x6EC },
+       [OLYMPUS_LUT_CHAN_531625_IDX] = { 21265, 0x1, 0x58, 0x135555, 0x6EC },
+       [OLYMPUS_LUT_CHAN_531750_IDX] = { 21270, 0x1, 0x58, 0x140000, 0x6ED },
+       [OLYMPUS_LUT_CHAN_531875_IDX] = { 21275, 0x1, 0x58, 0x14AAAB, 0x6ED },
+       [OLYMPUS_LUT_CHAN_532000_IDX] = { 21280, 0x1, 0x58, 0x155555, 0x6ED },
+       [OLYMPUS_LUT_CHAN_532125_IDX] = { 21285, 0x1, 0x58, 0x160000, 0x6EE },
+       [OLYMPUS_LUT_CHAN_532250_IDX] = { 21290, 0x1, 0x58, 0x16AAAB, 0x6EE },
+       [OLYMPUS_LUT_CHAN_532375_IDX] = { 21295, 0x1, 0x58, 0x175555, 0x6EF },
+       [OLYMPUS_LUT_CHAN_532500_IDX] = { 21300, 0x1, 0x58, 0x180000, 0x6EF },
+       [OLYMPUS_LUT_CHAN_532625_IDX] = { 21305, 0x1, 0x58, 0x18AAAB, 0x6EF },
+       [OLYMPUS_LUT_CHAN_532750_IDX] = { 21310, 0x1, 0x58, 0x195555, 0x6F0 },
+       [OLYMPUS_LUT_CHAN_532875_IDX] = { 21315, 0x1, 0x58, 0x1A0000, 0x6F0 },
+       [OLYMPUS_LUT_CHAN_533000_IDX] = { 21320, 0x1, 0x58, 0x1AAAAB, 0x6F1 },
+       [OLYMPUS_LUT_CHAN_533125_IDX] = { 21325, 0x1, 0x58, 0x1B5555, 0x6F1 },
+       [OLYMPUS_LUT_CHAN_533250_IDX] = { 21330, 0x1, 0x58, 0x1C0000, 0x6F2 },
+       [OLYMPUS_LUT_CHAN_533375_IDX] = { 21335, 0x1, 0x58, 0x1CAAAB, 0x6F2 },
+       [OLYMPUS_LUT_CHAN_533500_IDX] = { 21340, 0x1, 0x58, 0x1D5555, 0x6F2 },
+       [OLYMPUS_LUT_CHAN_533625_IDX] = { 21345, 0x1, 0x58, 0x1E0000, 0x6F3 },
+       [OLYMPUS_LUT_CHAN_533750_IDX] = { 21350, 0x1, 0x58, 0x1EAAAB, 0x6F3 },
+       [OLYMPUS_LUT_CHAN_533875_IDX] = { 21355, 0x1, 0x58, 0x1F5555, 0x6F4 },
+       [OLYMPUS_LUT_CHAN_534000_IDX] = { 21360, 0x1, 0x59, 0x0, 0x6F4 },
+       [OLYMPUS_LUT_CHAN_534125_IDX] = { 21365, 0x1, 0x59, 0xAAAB, 0x6F4 },
+       [OLYMPUS_LUT_CHAN_534250_IDX] = { 21370, 0x1, 0x59, 0x15555, 0x6F5 },
+       [OLYMPUS_LUT_CHAN_534375_IDX] = { 21375, 0x1, 0x59, 0x20000, 0x6F5 },
+       [OLYMPUS_LUT_CHAN_534500_IDX] = { 21380, 0x1, 0x59, 0x2AAAB, 0x6F6 },
+       [OLYMPUS_LUT_CHAN_534625_IDX] = { 21385, 0x1, 0x59, 0x35555, 0x6F6 },
+       [OLYMPUS_LUT_CHAN_534750_IDX] = { 21390, 0x1, 0x59, 0x40000, 0x6F7 },
+       [OLYMPUS_LUT_CHAN_534875_IDX] = { 21395, 0x1, 0x59, 0x4AAAB, 0x6F7 },
+       [OLYMPUS_LUT_CHAN_535000_IDX] = { 21400, 0x1, 0x59, 0x55555, 0x6F7 },
+       [OLYMPUS_LUT_CHAN_535125_IDX] = { 21405, 0x1, 0x59, 0x60000, 0x6F8 },
+       [OLYMPUS_LUT_CHAN_535250_IDX] = { 21410, 0x1, 0x59, 0x6AAAB, 0x6F8 },
+       [OLYMPUS_LUT_CHAN_535375_IDX] = { 21415, 0x1, 0x59, 0x75555, 0x6F9 },
+       [OLYMPUS_LUT_CHAN_535500_IDX] = { 21420, 0x1, 0x59, 0x80000, 0x6F9 },
+       [OLYMPUS_LUT_CHAN_535625_IDX] = { 21425, 0x1, 0x59, 0x8AAAB, 0x6F9 },
+       [OLYMPUS_LUT_CHAN_535750_IDX] = { 21430, 0x1, 0x59, 0x95555, 0x6FA },
+       [OLYMPUS_LUT_CHAN_535875_IDX] = { 21435, 0x1, 0x59, 0xA0000, 0x6FA },
+       [OLYMPUS_LUT_CHAN_536000_IDX] = { 21440, 0x1, 0x59, 0xAAAAB, 0x6FB },
+       [OLYMPUS_LUT_CHAN_536125_IDX] = { 21445, 0x1, 0x59, 0xB5555, 0x6FB },
+       [OLYMPUS_LUT_CHAN_536250_IDX] = { 21450, 0x1, 0x59, 0xC0000, 0x6FC },
+       [OLYMPUS_LUT_CHAN_536375_IDX] = { 21455, 0x1, 0x59, 0xCAAAB, 0x6FC },
+       [OLYMPUS_LUT_CHAN_536500_IDX] = { 21460, 0x1, 0x59, 0xD5555, 0x6FC },
+       [OLYMPUS_LUT_CHAN_536625_IDX] = { 21465, 0x1, 0x59, 0xE0000, 0x6FD },
+       [OLYMPUS_LUT_CHAN_536750_IDX] = { 21470, 0x1, 0x59, 0xEAAAB, 0x6FD },
+       [OLYMPUS_LUT_CHAN_536875_IDX] = { 21475, 0x1, 0x59, 0xF5555, 0x6FE },
+       [OLYMPUS_LUT_CHAN_537000_IDX] = { 21480, 0x1, 0x59, 0x100000, 0x6FE },
+       [OLYMPUS_LUT_CHAN_537125_IDX] = { 21485, 0x1, 0x59, 0x10AAAB, 0x6FE },
+       [OLYMPUS_LUT_CHAN_537250_IDX] = { 21490, 0x1, 0x59, 0x115555, 0x6FF },
+       [OLYMPUS_LUT_CHAN_537375_IDX] = { 21495, 0x1, 0x59, 0x120000, 0x6FF },
+       [OLYMPUS_LUT_CHAN_537500_IDX] = { 21500, 0x1, 0x59, 0x12AAAB, 0x700 },
+       [OLYMPUS_LUT_CHAN_537625_IDX] = { 21505, 0x1, 0x59, 0x135555, 0x700 },
+       [OLYMPUS_LUT_CHAN_537750_IDX] = { 21510, 0x1, 0x59, 0x140000, 0x701 },
+       [OLYMPUS_LUT_CHAN_537875_IDX] = { 21515, 0x1, 0x59, 0x14AAAB, 0x701 },
+       [OLYMPUS_LUT_CHAN_538000_IDX] = { 21520, 0x1, 0x59, 0x155555, 0x701 },
+       [OLYMPUS_LUT_CHAN_538125_IDX] = { 21525, 0x1, 0x59, 0x160000, 0x702 },
+       [OLYMPUS_LUT_CHAN_538250_IDX] = { 21530, 0x1, 0x59, 0x16AAAB, 0x702 },
+       [OLYMPUS_LUT_CHAN_538375_IDX] = { 21535, 0x1, 0x59, 0x175555, 0x703 },
+       [OLYMPUS_LUT_CHAN_538500_IDX] = { 21540, 0x1, 0x59, 0x180000, 0x703 },
+       [OLYMPUS_LUT_CHAN_538625_IDX] = { 21545, 0x1, 0x59, 0x18AAAB, 0x703 },
+       [OLYMPUS_LUT_CHAN_538750_IDX] = { 21550, 0x1, 0x59, 0x195555, 0x704 },
+       [OLYMPUS_LUT_CHAN_538875_IDX] = { 21555, 0x1, 0x59, 0x1A0000, 0x704 },
+       [OLYMPUS_LUT_CHAN_539000_IDX] = { 21560, 0x1, 0x59, 0x1AAAAB, 0x705 },
+       [OLYMPUS_LUT_CHAN_539125_IDX] = { 21565, 0x1, 0x59, 0x1B5555, 0x705 },
+       [OLYMPUS_LUT_CHAN_539250_IDX] = { 21570, 0x1, 0x59, 0x1C0000, 0x706 },
+       [OLYMPUS_LUT_CHAN_539375_IDX] = { 21575, 0x1, 0x59, 0x1CAAAB, 0x706 },
+       [OLYMPUS_LUT_CHAN_539500_IDX] = { 21580, 0x1, 0x59, 0x1D5555, 0x706 },
+       [OLYMPUS_LUT_CHAN_539625_IDX] = { 21585, 0x1, 0x59, 0x1E0000, 0x707 },
+       [OLYMPUS_LUT_CHAN_539750_IDX] = { 21590, 0x1, 0x59, 0x1EAAAB, 0x707 },
+       [OLYMPUS_LUT_CHAN_539875_IDX] = { 21595, 0x1, 0x59, 0x1F5555, 0x708 },
+       [OLYMPUS_LUT_CHAN_540000_IDX] = { 21600, 0x1, 0x5A, 0x0, 0x708 },
+       [OLYMPUS_LUT_CHAN_540125_IDX] = { 21605, 0x1, 0x5A, 0xAAAB, 0x708 },
+       [OLYMPUS_LUT_CHAN_540250_IDX] = { 21610, 0x1, 0x5A, 0x15555, 0x709 },
+       [OLYMPUS_LUT_CHAN_540375_IDX] = { 21615, 0x1, 0x5A, 0x20000, 0x709 },
+       [OLYMPUS_LUT_CHAN_540500_IDX] = { 21620, 0x1, 0x5A, 0x2AAAB, 0x70A },
+       [OLYMPUS_LUT_CHAN_540625_IDX] = { 21625, 0x1, 0x5A, 0x35555, 0x70A },
+       [OLYMPUS_LUT_CHAN_540750_IDX] = { 21630, 0x1, 0x5A, 0x40000, 0x70B },
+       [OLYMPUS_LUT_CHAN_540875_IDX] = { 21635, 0x1, 0x5A, 0x4AAAB, 0x70B },
+       [OLYMPUS_LUT_CHAN_541000_IDX] = { 21640, 0x1, 0x5A, 0x55555, 0x70B },
+       [OLYMPUS_LUT_CHAN_541125_IDX] = { 21645, 0x1, 0x5A, 0x60000, 0x70C },
+       [OLYMPUS_LUT_CHAN_541250_IDX] = { 21650, 0x1, 0x5A, 0x6AAAB, 0x70C },
+       [OLYMPUS_LUT_CHAN_541375_IDX] = { 21655, 0x1, 0x5A, 0x75555, 0x70D },
+       [OLYMPUS_LUT_CHAN_541500_IDX] = { 21660, 0x1, 0x5A, 0x80000, 0x70D },
+       [OLYMPUS_LUT_CHAN_541625_IDX] = { 21665, 0x1, 0x5A, 0x8AAAB, 0x70D },
+       [OLYMPUS_LUT_CHAN_541750_IDX] = { 21670, 0x1, 0x5A, 0x95555, 0x70E },
+       [OLYMPUS_LUT_CHAN_541875_IDX] = { 21675, 0x1, 0x5A, 0xA0000, 0x70E },
+       [OLYMPUS_LUT_CHAN_542000_IDX] = { 21680, 0x1, 0x5A, 0xAAAAB, 0x70F },
+       [OLYMPUS_LUT_CHAN_542125_IDX] = { 21685, 0x1, 0x5A, 0xB5555, 0x70F },
+       [OLYMPUS_LUT_CHAN_542250_IDX] = { 21690, 0x1, 0x5A, 0xC0000, 0x710 },
+       [OLYMPUS_LUT_CHAN_542375_IDX] = { 21695, 0x1, 0x5A, 0xCAAAB, 0x710 },
+       [OLYMPUS_LUT_CHAN_542500_IDX] = { 21700, 0x1, 0x5A, 0xD5555, 0x710 },
+       [OLYMPUS_LUT_CHAN_542625_IDX] = { 21705, 0x1, 0x5A, 0xE0000, 0x711 },
+       [OLYMPUS_LUT_CHAN_542750_IDX] = { 21710, 0x1, 0x5A, 0xEAAAB, 0x711 },
+       [OLYMPUS_LUT_CHAN_542875_IDX] = { 21715, 0x1, 0x5A, 0xF5555, 0x712 },
+       [OLYMPUS_LUT_CHAN_543000_IDX] = { 21720, 0x1, 0x5A, 0x100000, 0x712 },
+       [OLYMPUS_LUT_CHAN_543125_IDX] = { 21725, 0x1, 0x5A, 0x10AAAB, 0x712 },
+       [OLYMPUS_LUT_CHAN_543250_IDX] = { 21730, 0x1, 0x5A, 0x115555, 0x713 },
+       [OLYMPUS_LUT_CHAN_543375_IDX] = { 21735, 0x1, 0x5A, 0x120000, 0x713 },
+       [OLYMPUS_LUT_CHAN_543500_IDX] = { 21740, 0x1, 0x5A, 0x12AAAB, 0x714 },
+       [OLYMPUS_LUT_CHAN_543625_IDX] = { 21745, 0x1, 0x5A, 0x135555, 0x714 },
+       [OLYMPUS_LUT_CHAN_543750_IDX] = { 21750, 0x1, 0x5A, 0x140000, 0x715 },
+       [OLYMPUS_LUT_CHAN_543875_IDX] = { 21755, 0x1, 0x5A, 0x14AAAB, 0x715 },
+       [OLYMPUS_LUT_CHAN_544000_IDX] = { 21760, 0x1, 0x5A, 0x155555, 0x715 },
+       [OLYMPUS_LUT_CHAN_544125_IDX] = { 21765, 0x1, 0x5A, 0x160000, 0x716 },
+       [OLYMPUS_LUT_CHAN_544250_IDX] = { 21770, 0x1, 0x5A, 0x16AAAB, 0x716 },
+       [OLYMPUS_LUT_CHAN_544375_IDX] = { 21775, 0x1, 0x5A, 0x175555, 0x717 },
+       [OLYMPUS_LUT_CHAN_544500_IDX] = { 21780, 0x1, 0x5A, 0x180000, 0x717 },
+       [OLYMPUS_LUT_CHAN_544625_IDX] = { 21785, 0x1, 0x5A, 0x18AAAB, 0x717 },
+       [OLYMPUS_LUT_CHAN_544750_IDX] = { 21790, 0x1, 0x5A, 0x195555, 0x718 },
+       [OLYMPUS_LUT_CHAN_544875_IDX] = { 21795, 0x1, 0x5A, 0x1A0000, 0x718 },
+       [OLYMPUS_LUT_CHAN_545000_IDX] = { 21800, 0x1, 0x5A, 0x1AAAAB, 0x719 },
+       [OLYMPUS_LUT_CHAN_545125_IDX] = { 21805, 0x1, 0x5A, 0x1B5555, 0x719 },
+       [OLYMPUS_LUT_CHAN_545250_IDX] = { 21810, 0x1, 0x5A, 0x1C0000, 0x71A },
+       [OLYMPUS_LUT_CHAN_545375_IDX] = { 21815, 0x1, 0x5A, 0x1CAAAB, 0x71A },
+       [OLYMPUS_LUT_CHAN_545500_IDX] = { 21820, 0x1, 0x5A, 0x1D5555, 0x71A },
+       [OLYMPUS_LUT_CHAN_545625_IDX] = { 21825, 0x1, 0x5A, 0x1E0000, 0x71B },
+       [OLYMPUS_LUT_CHAN_545750_IDX] = { 21830, 0x1, 0x5A, 0x1EAAAB, 0x71B },
+       [OLYMPUS_LUT_CHAN_545875_IDX] = { 21835, 0x1, 0x5A, 0x1F5555, 0x71C },
+       [OLYMPUS_LUT_CHAN_546000_IDX] = { 21840, 0x1, 0x5B, 0x0, 0x71C },
+       [OLYMPUS_LUT_CHAN_546125_IDX] = { 21845, 0x1, 0x5B, 0xAAAB, 0x71C },
+       [OLYMPUS_LUT_CHAN_546250_IDX] = { 21850, 0x1, 0x5B, 0x15555, 0x71D },
+       [OLYMPUS_LUT_CHAN_546375_IDX] = { 21855, 0x1, 0x5B, 0x20000, 0x71D },
+       [OLYMPUS_LUT_CHAN_546500_IDX] = { 21860, 0x1, 0x5B, 0x2AAAB, 0x71E },
+       [OLYMPUS_LUT_CHAN_546625_IDX] = { 21865, 0x1, 0x5B, 0x35555, 0x71E },
+       [OLYMPUS_LUT_CHAN_546750_IDX] = { 21870, 0x1, 0x5B, 0x40000, 0x71F },
+       [OLYMPUS_LUT_CHAN_546875_IDX] = { 21875, 0x1, 0x5B, 0x4AAAB, 0x71F },
+       [OLYMPUS_LUT_CHAN_547000_IDX] = { 21880, 0x1, 0x5B, 0x55555, 0x71F },
+       [OLYMPUS_LUT_CHAN_547125_IDX] = { 21885, 0x1, 0x5B, 0x60000, 0x720 },
+       [OLYMPUS_LUT_CHAN_547250_IDX] = { 21890, 0x1, 0x5B, 0x6AAAB, 0x720 },
+       [OLYMPUS_LUT_CHAN_547375_IDX] = { 21895, 0x1, 0x5B, 0x75555, 0x721 },
+       [OLYMPUS_LUT_CHAN_547500_IDX] = { 21900, 0x1, 0x5B, 0x80000, 0x721 },
+       [OLYMPUS_LUT_CHAN_547625_IDX] = { 21905, 0x1, 0x5B, 0x8AAAB, 0x721 },
+       [OLYMPUS_LUT_CHAN_547750_IDX] = { 21910, 0x1, 0x5B, 0x95555, 0x722 },
+       [OLYMPUS_LUT_CHAN_547875_IDX] = { 21915, 0x1, 0x5B, 0xA0000, 0x722 },
+       [OLYMPUS_LUT_CHAN_548000_IDX] = { 21920, 0x1, 0x5B, 0xAAAAB, 0x723 },
+       [OLYMPUS_LUT_CHAN_548125_IDX] = { 21925, 0x1, 0x5B, 0xB5555, 0x723 },
+       [OLYMPUS_LUT_CHAN_548250_IDX] = { 21930, 0x1, 0x5B, 0xC0000, 0x724 },
+       [OLYMPUS_LUT_CHAN_548375_IDX] = { 21935, 0x1, 0x5B, 0xCAAAB, 0x724 },
+       [OLYMPUS_LUT_CHAN_548500_IDX] = { 21940, 0x1, 0x5B, 0xD5555, 0x724 },
+       [OLYMPUS_LUT_CHAN_548625_IDX] = { 21945, 0x1, 0x5B, 0xE0000, 0x725 },
+       [OLYMPUS_LUT_CHAN_548750_IDX] = { 21950, 0x1, 0x5B, 0xEAAAB, 0x725 },
+       [OLYMPUS_LUT_CHAN_548875_IDX] = { 21955, 0x1, 0x5B, 0xF5555, 0x726 },
+       [OLYMPUS_LUT_CHAN_549000_IDX] = { 21960, 0x1, 0x5B, 0x100000, 0x726 },
+       [OLYMPUS_LUT_CHAN_549125_IDX] = { 21965, 0x1, 0x5B, 0x10AAAB, 0x726 },
+       [OLYMPUS_LUT_CHAN_549250_IDX] = { 21970, 0x1, 0x5B, 0x115555, 0x727 },
+       [OLYMPUS_LUT_CHAN_549375_IDX] = { 21975, 0x1, 0x5B, 0x120000, 0x727 },
+       [OLYMPUS_LUT_CHAN_549500_IDX] = { 21980, 0x1, 0x5B, 0x12AAAB, 0x728 },
+       [OLYMPUS_LUT_CHAN_549625_IDX] = { 21985, 0x1, 0x5B, 0x135555, 0x728 },
+       [OLYMPUS_LUT_CHAN_549750_IDX] = { 21990, 0x1, 0x5B, 0x140000, 0x729 },
+       [OLYMPUS_LUT_CHAN_549875_IDX] = { 21995, 0x1, 0x5B, 0x14AAAB, 0x729 },
+       [OLYMPUS_LUT_CHAN_550000_IDX] = { 22000, 0x1, 0x5B, 0x155555, 0x729 },
+       [OLYMPUS_LUT_CHAN_550125_IDX] = { 22005, 0x1, 0x5B, 0x160000, 0x72A },
+       [OLYMPUS_LUT_CHAN_550250_IDX] = { 22010, 0x1, 0x5B, 0x16AAAB, 0x72A },
+       [OLYMPUS_LUT_CHAN_550375_IDX] = { 22015, 0x1, 0x5B, 0x175555, 0x72B },
+       [OLYMPUS_LUT_CHAN_550500_IDX] = { 22020, 0x1, 0x5B, 0x180000, 0x72B },
+       [OLYMPUS_LUT_CHAN_550625_IDX] = { 22025, 0x1, 0x5B, 0x18AAAB, 0x72B },
+       [OLYMPUS_LUT_CHAN_550750_IDX] = { 22030, 0x1, 0x5B, 0x195555, 0x72C },
+       [OLYMPUS_LUT_CHAN_550875_IDX] = { 22035, 0x1, 0x5B, 0x1A0000, 0x72C },
+       [OLYMPUS_LUT_CHAN_551000_IDX] = { 22040, 0x1, 0x5B, 0x1AAAAB, 0x72D },
+       [OLYMPUS_LUT_CHAN_551125_IDX] = { 22045, 0x1, 0x5B, 0x1B5555, 0x72D },
+       [OLYMPUS_LUT_CHAN_551250_IDX] = { 22050, 0x1, 0x5B, 0x1C0000, 0x72E },
+       [OLYMPUS_LUT_CHAN_551375_IDX] = { 22055, 0x1, 0x5B, 0x1CAAAB, 0x72E },
+       [OLYMPUS_LUT_CHAN_551500_IDX] = { 22060, 0x1, 0x5B, 0x1D5555, 0x72E },
+       [OLYMPUS_LUT_CHAN_551625_IDX] = { 22065, 0x1, 0x5B, 0x1E0000, 0x72F },
+       [OLYMPUS_LUT_CHAN_551750_IDX] = { 22070, 0x1, 0x5B, 0x1EAAAB, 0x72F },
+       [OLYMPUS_LUT_CHAN_551875_IDX] = { 22075, 0x1, 0x5B, 0x1F5555, 0x730 },
+       [OLYMPUS_LUT_CHAN_552000_IDX] = { 22080, 0x1, 0x5C, 0x0, 0x730 },
+       [OLYMPUS_LUT_CHAN_552125_IDX] = { 22085, 0x1, 0x5C, 0xAAAB, 0x730 },
+       [OLYMPUS_LUT_CHAN_552250_IDX] = { 22090, 0x1, 0x5C, 0x15555, 0x731 },
+       [OLYMPUS_LUT_CHAN_552375_IDX] = { 22095, 0x1, 0x5C, 0x20000, 0x731 },
+       [OLYMPUS_LUT_CHAN_552500_IDX] = { 22100, 0x1, 0x5C, 0x2AAAB, 0x732 },
+       [OLYMPUS_LUT_CHAN_552625_IDX] = { 22105, 0x1, 0x5C, 0x35555, 0x732 },
+       [OLYMPUS_LUT_CHAN_552750_IDX] = { 22110, 0x1, 0x5C, 0x40000, 0x733 },
+       [OLYMPUS_LUT_CHAN_552875_IDX] = { 22115, 0x1, 0x5C, 0x4AAAB, 0x733 },
+       [OLYMPUS_LUT_CHAN_553000_IDX] = { 22120, 0x1, 0x5C, 0x55555, 0x733 },
+       [OLYMPUS_LUT_CHAN_553125_IDX] = { 22125, 0x1, 0x5C, 0x60000, 0x734 },
+       [OLYMPUS_LUT_CHAN_553250_IDX] = { 22130, 0x1, 0x5C, 0x6AAAB, 0x734 },
+       [OLYMPUS_LUT_CHAN_553375_IDX] = { 22135, 0x1, 0x5C, 0x75555, 0x735 },
+       [OLYMPUS_LUT_CHAN_553500_IDX] = { 22140, 0x1, 0x5C, 0x80000, 0x735 },
+       [OLYMPUS_LUT_CHAN_553625_IDX] = { 22145, 0x1, 0x5C, 0x8AAAB, 0x735 },
+       [OLYMPUS_LUT_CHAN_553750_IDX] = { 22150, 0x1, 0x5C, 0x95555, 0x736 },
+       [OLYMPUS_LUT_CHAN_553875_IDX] = { 22155, 0x1, 0x5C, 0xA0000, 0x736 },
+       [OLYMPUS_LUT_CHAN_554000_IDX] = { 22160, 0x1, 0x5C, 0xAAAAB, 0x737 },
+       [OLYMPUS_LUT_CHAN_554125_IDX] = { 22165, 0x1, 0x5C, 0xB5555, 0x737 },
+       [OLYMPUS_LUT_CHAN_554250_IDX] = { 22170, 0x1, 0x5C, 0xC0000, 0x738 },
+       [OLYMPUS_LUT_CHAN_554375_IDX] = { 22175, 0x1, 0x5C, 0xCAAAB, 0x738 },
+       [OLYMPUS_LUT_CHAN_554500_IDX] = { 22180, 0x1, 0x5C, 0xD5555, 0x738 },
+       [OLYMPUS_LUT_CHAN_554625_IDX] = { 22185, 0x1, 0x5C, 0xE0000, 0x739 },
+       [OLYMPUS_LUT_CHAN_554750_IDX] = { 22190, 0x1, 0x5C, 0xEAAAB, 0x739 },
+       [OLYMPUS_LUT_CHAN_554875_IDX] = { 22195, 0x1, 0x5C, 0xF5555, 0x73A },
+       [OLYMPUS_LUT_CHAN_555000_IDX] = { 22200, 0x1, 0x5C, 0x100000, 0x73A },
+       [OLYMPUS_LUT_CHAN_555125_IDX] = { 22205, 0x1, 0x5C, 0x10AAAB, 0x73A },
+       [OLYMPUS_LUT_CHAN_555250_IDX] = { 22210, 0x1, 0x5C, 0x115555, 0x73B },
+       [OLYMPUS_LUT_CHAN_555375_IDX] = { 22215, 0x1, 0x5C, 0x120000, 0x73B },
+       [OLYMPUS_LUT_CHAN_555500_IDX] = { 22220, 0x1, 0x5C, 0x12AAAB, 0x73C },
+       [OLYMPUS_LUT_CHAN_555625_IDX] = { 22225, 0x1, 0x5C, 0x135555, 0x73C },
+       [OLYMPUS_LUT_CHAN_555750_IDX] = { 22230, 0x1, 0x5C, 0x140000, 0x73D },
+       [OLYMPUS_LUT_CHAN_555875_IDX] = { 22235, 0x1, 0x5C, 0x14AAAB, 0x73D },
+       [OLYMPUS_LUT_CHAN_556000_IDX] = { 22240, 0x1, 0x5C, 0x155555, 0x73D },
+       [OLYMPUS_LUT_CHAN_556125_IDX] = { 22245, 0x1, 0x5C, 0x160000, 0x73E },
+       [OLYMPUS_LUT_CHAN_556250_IDX] = { 22250, 0x1, 0x5C, 0x16AAAB, 0x73E },
+       [OLYMPUS_LUT_CHAN_556375_IDX] = { 22255, 0x1, 0x5C, 0x175555, 0x73F },
+       [OLYMPUS_LUT_CHAN_556500_IDX] = { 22260, 0x1, 0x5C, 0x180000, 0x73F },
+       [OLYMPUS_LUT_CHAN_556625_IDX] = { 22265, 0x1, 0x5C, 0x18AAAB, 0x73F },
+       [OLYMPUS_LUT_CHAN_556750_IDX] = { 22270, 0x1, 0x5C, 0x195555, 0x740 },
+       [OLYMPUS_LUT_CHAN_556875_IDX] = { 22275, 0x1, 0x5C, 0x1A0000, 0x740 },
+       [OLYMPUS_LUT_CHAN_557000_IDX] = { 22280, 0x1, 0x5C, 0x1AAAAB, 0x741 },
+       [OLYMPUS_LUT_CHAN_557125_IDX] = { 22285, 0x1, 0x5C, 0x1B5555, 0x741 },
+       [OLYMPUS_LUT_CHAN_557250_IDX] = { 22290, 0x1, 0x5C, 0x1C0000, 0x742 },
+       [OLYMPUS_LUT_CHAN_557375_IDX] = { 22295, 0x1, 0x5C, 0x1CAAAB, 0x742 },
+       [OLYMPUS_LUT_CHAN_557500_IDX] = { 22300, 0x1, 0x5C, 0x1D5555, 0x742 },
+       [OLYMPUS_LUT_CHAN_557625_IDX] = { 22305, 0x1, 0x5C, 0x1E0000, 0x743 },
+       [OLYMPUS_LUT_CHAN_557750_IDX] = { 22310, 0x1, 0x5C, 0x1EAAAB, 0x743 },
+       [OLYMPUS_LUT_CHAN_557875_IDX] = { 22315, 0x1, 0x5C, 0x1F5555, 0x744 },
+       [OLYMPUS_LUT_CHAN_558000_IDX] = { 22320, 0x1, 0x5D, 0x0, 0x744 },
+       [OLYMPUS_LUT_CHAN_558125_IDX] = { 22325, 0x1, 0x5D, 0xAAAB, 0x744 },
+       [OLYMPUS_LUT_CHAN_558250_IDX] = { 22330, 0x1, 0x5D, 0x15555, 0x745 },
+       [OLYMPUS_LUT_CHAN_558375_IDX] = { 22335, 0x1, 0x5D, 0x20000, 0x745 },
+       [OLYMPUS_LUT_CHAN_558500_IDX] = { 22340, 0x1, 0x5D, 0x2AAAB, 0x746 },
+       [OLYMPUS_LUT_CHAN_558625_IDX] = { 22345, 0x1, 0x5D, 0x35555, 0x746 },
+       [OLYMPUS_LUT_CHAN_558750_IDX] = { 22350, 0x1, 0x5D, 0x40000, 0x747 },
+       [OLYMPUS_LUT_CHAN_558875_IDX] = { 22355, 0x1, 0x5D, 0x4AAAB, 0x747 },
+       [OLYMPUS_LUT_CHAN_559000_IDX] = { 22360, 0x1, 0x5D, 0x55555, 0x747 },
+       [OLYMPUS_LUT_CHAN_559125_IDX] = { 22365, 0x1, 0x5D, 0x60000, 0x748 },
+       [OLYMPUS_LUT_CHAN_559250_IDX] = { 22370, 0x1, 0x5D, 0x6AAAB, 0x748 },
+       [OLYMPUS_LUT_CHAN_559375_IDX] = { 22375, 0x1, 0x5D, 0x75555, 0x749 },
+       [OLYMPUS_LUT_CHAN_559500_IDX] = { 22380, 0x1, 0x5D, 0x80000, 0x749 },
+       [OLYMPUS_LUT_CHAN_559625_IDX] = { 22385, 0x1, 0x5D, 0x8AAAB, 0x749 },
+       [OLYMPUS_LUT_CHAN_559750_IDX] = { 22390, 0x1, 0x5D, 0x95555, 0x74A },
+       [OLYMPUS_LUT_CHAN_559875_IDX] = { 22395, 0x1, 0x5D, 0xA0000, 0x74A },
+       [OLYMPUS_LUT_CHAN_560000_IDX] = { 22400, 0x1, 0x5D, 0xAAAAB, 0x74B },
+       [OLYMPUS_LUT_CHAN_560125_IDX] = { 22405, 0x1, 0x5D, 0xB5555, 0x74B },
+       [OLYMPUS_LUT_CHAN_560250_IDX] = { 22410, 0x1, 0x5D, 0xC0000, 0x74C },
+       [OLYMPUS_LUT_CHAN_560375_IDX] = { 22415, 0x1, 0x5D, 0xCAAAB, 0x74C },
+       [OLYMPUS_LUT_CHAN_560500_IDX] = { 22420, 0x1, 0x5D, 0xD5555, 0x74C },
+       [OLYMPUS_LUT_CHAN_560625_IDX] = { 22425, 0x1, 0x5D, 0xE0000, 0x74D },
+       [OLYMPUS_LUT_CHAN_560750_IDX] = { 22430, 0x1, 0x5D, 0xEAAAB, 0x74D },
+       [OLYMPUS_LUT_CHAN_560875_IDX] = { 22435, 0x1, 0x5D, 0xF5555, 0x74E },
+       [OLYMPUS_LUT_CHAN_561000_IDX] = { 22440, 0x1, 0x5D, 0x100000, 0x74E },
+       [OLYMPUS_LUT_CHAN_561125_IDX] = { 22445, 0x1, 0x5D, 0x10AAAB, 0x74E },
+       [OLYMPUS_LUT_CHAN_561250_IDX] = { 22450, 0x1, 0x5D, 0x115555, 0x74F },
+       [OLYMPUS_LUT_CHAN_561375_IDX] = { 22455, 0x1, 0x5D, 0x120000, 0x74F },
+       [OLYMPUS_LUT_CHAN_561500_IDX] = { 22460, 0x1, 0x5D, 0x12AAAB, 0x750 },
+       [OLYMPUS_LUT_CHAN_561625_IDX] = { 22465, 0x1, 0x5D, 0x135555, 0x750 },
+       [OLYMPUS_LUT_CHAN_561750_IDX] = { 22470, 0x1, 0x5D, 0x140000, 0x751 },
+       [OLYMPUS_LUT_CHAN_561875_IDX] = { 22475, 0x1, 0x5D, 0x14AAAB, 0x751 },
+       [OLYMPUS_LUT_CHAN_562000_IDX] = { 22480, 0x1, 0x5D, 0x155555, 0x751 },
+       [OLYMPUS_LUT_CHAN_562125_IDX] = { 22485, 0x1, 0x5D, 0x160000, 0x752 },
+       [OLYMPUS_LUT_CHAN_562250_IDX] = { 22490, 0x1, 0x5D, 0x16AAAB, 0x752 },
+       [OLYMPUS_LUT_CHAN_562375_IDX] = { 22495, 0x1, 0x5D, 0x175555, 0x753 },
+       [OLYMPUS_LUT_CHAN_562500_IDX] = { 22500, 0x1, 0x5D, 0x180000, 0x753 },
+       [OLYMPUS_LUT_CHAN_562625_IDX] = { 22505, 0x1, 0x5D, 0x18AAAB, 0x753 },
+       [OLYMPUS_LUT_CHAN_562750_IDX] = { 22510, 0x1, 0x5D, 0x195555, 0x754 },
+       [OLYMPUS_LUT_CHAN_562875_IDX] = { 22515, 0x1, 0x5D, 0x1A0000, 0x754 },
+       [OLYMPUS_LUT_CHAN_563000_IDX] = { 22520, 0x1, 0x5D, 0x1AAAAB, 0x755 },
+       [OLYMPUS_LUT_CHAN_563125_IDX] = { 22525, 0x1, 0x5D, 0x1B5555, 0x755 },
+       [OLYMPUS_LUT_CHAN_563250_IDX] = { 22530, 0x1, 0x5D, 0x1C0000, 0x756 },
+       [OLYMPUS_LUT_CHAN_563375_IDX] = { 22535, 0x1, 0x5D, 0x1CAAAB, 0x756 },
+       [OLYMPUS_LUT_CHAN_563500_IDX] = { 22540, 0x1, 0x5D, 0x1D5555, 0x756 },
+       [OLYMPUS_LUT_CHAN_563625_IDX] = { 22545, 0x1, 0x5D, 0x1E0000, 0x757 },
+       [OLYMPUS_LUT_CHAN_563750_IDX] = { 22550, 0x1, 0x5D, 0x1EAAAB, 0x757 },
+       [OLYMPUS_LUT_CHAN_563875_IDX] = { 22555, 0x1, 0x5D, 0x1F5555, 0x758 },
+       [OLYMPUS_LUT_CHAN_564000_IDX] = { 22560, 0x1, 0x5E, 0x0, 0x758 },
+       [OLYMPUS_LUT_CHAN_564125_IDX] = { 22565, 0x1, 0x5E, 0xAAAB, 0x758 },
+       [OLYMPUS_LUT_CHAN_564250_IDX] = { 22570, 0x1, 0x5E, 0x15555, 0x759 },
+       [OLYMPUS_LUT_CHAN_564375_IDX] = { 22575, 0x1, 0x5E, 0x20000, 0x759 },
+       [OLYMPUS_LUT_CHAN_564500_IDX] = { 22580, 0x1, 0x5E, 0x2AAAB, 0x75A },
+       [OLYMPUS_LUT_CHAN_564625_IDX] = { 22585, 0x1, 0x5E, 0x35555, 0x75A },
+       [OLYMPUS_LUT_CHAN_564750_IDX] = { 22590, 0x1, 0x5E, 0x40000, 0x75B },
+       [OLYMPUS_LUT_CHAN_564875_IDX] = { 22595, 0x1, 0x5E, 0x4AAAB, 0x75B },
+       [OLYMPUS_LUT_CHAN_565000_IDX] = { 22600, 0x1, 0x5E, 0x55555, 0x75B },
+       [OLYMPUS_LUT_CHAN_565125_IDX] = { 22605, 0x1, 0x5E, 0x60000, 0x75C },
+       [OLYMPUS_LUT_CHAN_565250_IDX] = { 22610, 0x1, 0x5E, 0x6AAAB, 0x75C },
+       [OLYMPUS_LUT_CHAN_565375_IDX] = { 22615, 0x1, 0x5E, 0x75555, 0x75D },
+       [OLYMPUS_LUT_CHAN_565500_IDX] = { 22620, 0x1, 0x5E, 0x80000, 0x75D },
+       [OLYMPUS_LUT_CHAN_565625_IDX] = { 22625, 0x1, 0x5E, 0x8AAAB, 0x75D },
+       [OLYMPUS_LUT_CHAN_565750_IDX] = { 22630, 0x1, 0x5E, 0x95555, 0x75E },
+       [OLYMPUS_LUT_CHAN_565875_IDX] = { 22635, 0x1, 0x5E, 0xA0000, 0x75E },
+       [OLYMPUS_LUT_CHAN_566000_IDX] = { 22640, 0x1, 0x5E, 0xAAAAB, 0x75F },
+       [OLYMPUS_LUT_CHAN_566125_IDX] = { 22645, 0x1, 0x5E, 0xB5555, 0x75F },
+       [OLYMPUS_LUT_CHAN_566250_IDX] = { 22650, 0x1, 0x5E, 0xC0000, 0x760 },
+       [OLYMPUS_LUT_CHAN_566375_IDX] = { 22655, 0x1, 0x5E, 0xCAAAB, 0x760 },
+       [OLYMPUS_LUT_CHAN_566500_IDX] = { 22660, 0x1, 0x5E, 0xD5555, 0x760 },
+       [OLYMPUS_LUT_CHAN_566625_IDX] = { 22665, 0x1, 0x5E, 0xE0000, 0x761 },
+       [OLYMPUS_LUT_CHAN_566750_IDX] = { 22670, 0x1, 0x5E, 0xEAAAB, 0x761 },
+       [OLYMPUS_LUT_CHAN_566875_IDX] = { 22675, 0x1, 0x5E, 0xF5555, 0x762 },
+       [OLYMPUS_LUT_CHAN_567000_IDX] = { 22680, 0x1, 0x5E, 0x100000, 0x762 },
+       [OLYMPUS_LUT_CHAN_567125_IDX] = { 22685, 0x1, 0x5E, 0x10AAAB, 0x762 },
+       [OLYMPUS_LUT_CHAN_567250_IDX] = { 22690, 0x1, 0x5E, 0x115555, 0x763 },
+       [OLYMPUS_LUT_CHAN_567375_IDX] = { 22695, 0x1, 0x5E, 0x120000, 0x763 },
+       [OLYMPUS_LUT_CHAN_567500_IDX] = { 22700, 0x1, 0x5E, 0x12AAAB, 0x764 },
+       [OLYMPUS_LUT_CHAN_567625_IDX] = { 22705, 0x1, 0x5E, 0x135555, 0x764 },
+       [OLYMPUS_LUT_CHAN_567750_IDX] = { 22710, 0x1, 0x5E, 0x140000, 0x765 },
+       [OLYMPUS_LUT_CHAN_567875_IDX] = { 22715, 0x1, 0x5E, 0x14AAAB, 0x765 },
+       [OLYMPUS_LUT_CHAN_568000_IDX] = { 22720, 0x1, 0x5E, 0x155555, 0x765 },
+       [OLYMPUS_LUT_CHAN_568125_IDX] = { 22725, 0x1, 0x5E, 0x160000, 0x766 },
+       [OLYMPUS_LUT_CHAN_568250_IDX] = { 22730, 0x1, 0x5E, 0x16AAAB, 0x766 },
+       [OLYMPUS_LUT_CHAN_568375_IDX] = { 22735, 0x1, 0x5E, 0x175555, 0x767 },
+       [OLYMPUS_LUT_CHAN_568500_IDX] = { 22740, 0x1, 0x5E, 0x180000, 0x767 },
+       [OLYMPUS_LUT_CHAN_568625_IDX] = { 22745, 0x1, 0x5E, 0x18AAAB, 0x767 },
+       [OLYMPUS_LUT_CHAN_568750_IDX] = { 22750, 0x1, 0x5E, 0x195555, 0x768 },
+       [OLYMPUS_LUT_CHAN_568875_IDX] = { 22755, 0x1, 0x5E, 0x1A0000, 0x768 },
+       [OLYMPUS_LUT_CHAN_569000_IDX] = { 22760, 0x1, 0x5E, 0x1AAAAB, 0x769 },
+       [OLYMPUS_LUT_CHAN_569125_IDX] = { 22765, 0x1, 0x5E, 0x1B5555, 0x769 },
+       [OLYMPUS_LUT_CHAN_569250_IDX] = { 22770, 0x1, 0x5E, 0x1C0000, 0x76A },
+       [OLYMPUS_LUT_CHAN_569375_IDX] = { 22775, 0x1, 0x5E, 0x1CAAAB, 0x76A },
+       [OLYMPUS_LUT_CHAN_569500_IDX] = { 22780, 0x1, 0x5E, 0x1D5555, 0x76A },
+       [OLYMPUS_LUT_CHAN_569625_IDX] = { 22785, 0x1, 0x5E, 0x1E0000, 0x76B },
+       [OLYMPUS_LUT_CHAN_569750_IDX] = { 22790, 0x1, 0x5E, 0x1EAAAB, 0x76B },
+       [OLYMPUS_LUT_CHAN_569875_IDX] = { 22795, 0x1, 0x5E, 0x1F5555, 0x76C },
+       [OLYMPUS_LUT_CHAN_570000_IDX] = { 22800, 0x1, 0x5F, 0x0, 0x76C },
+       [OLYMPUS_LUT_CHAN_570125_IDX] = { 22805, 0x1, 0x5F, 0xAAAB, 0x76C },
+       [OLYMPUS_LUT_CHAN_570250_IDX] = { 22810, 0x1, 0x5F, 0x15555, 0x76D },
+       [OLYMPUS_LUT_CHAN_570375_IDX] = { 22815, 0x1, 0x5F, 0x20000, 0x76D },
+       [OLYMPUS_LUT_CHAN_570500_IDX] = { 22820, 0x1, 0x5F, 0x2AAAB, 0x76E },
+       [OLYMPUS_LUT_CHAN_570625_IDX] = { 22825, 0x1, 0x5F, 0x35555, 0x76E },
+       [OLYMPUS_LUT_CHAN_570750_IDX] = { 22830, 0x1, 0x5F, 0x40000, 0x76F },
+       [OLYMPUS_LUT_CHAN_570875_IDX] = { 22835, 0x1, 0x5F, 0x4AAAB, 0x76F },
+       [OLYMPUS_LUT_CHAN_571000_IDX] = { 22840, 0x1, 0x5F, 0x55555, 0x76F },
+       [OLYMPUS_LUT_CHAN_571125_IDX] = { 22845, 0x1, 0x5F, 0x60000, 0x770 },
+       [OLYMPUS_LUT_CHAN_571250_IDX] = { 22850, 0x1, 0x5F, 0x6AAAB, 0x770 },
+       [OLYMPUS_LUT_CHAN_571375_IDX] = { 22855, 0x1, 0x5F, 0x75555, 0x771 },
+       [OLYMPUS_LUT_CHAN_571500_IDX] = { 22860, 0x1, 0x5F, 0x80000, 0x771 },
+       [OLYMPUS_LUT_CHAN_571625_IDX] = { 22865, 0x1, 0x5F, 0x8AAAB, 0x771 },
+       [OLYMPUS_LUT_CHAN_571750_IDX] = { 22870, 0x1, 0x5F, 0x95555, 0x772 },
+       [OLYMPUS_LUT_CHAN_571875_IDX] = { 22875, 0x1, 0x5F, 0xA0000, 0x772 },
+       [OLYMPUS_LUT_CHAN_572000_IDX] = { 22880, 0x1, 0x5F, 0xAAAAB, 0x773 },
+       [OLYMPUS_LUT_CHAN_572125_IDX] = { 22885, 0x1, 0x5F, 0xB5555, 0x773 },
+       [OLYMPUS_LUT_CHAN_572250_IDX] = { 22890, 0x1, 0x5F, 0xC0000, 0x774 },
+       [OLYMPUS_LUT_CHAN_572375_IDX] = { 22895, 0x1, 0x5F, 0xCAAAB, 0x774 },
+       [OLYMPUS_LUT_CHAN_572500_IDX] = { 22900, 0x1, 0x5F, 0xD5555, 0x774 },
+       [OLYMPUS_LUT_CHAN_572625_IDX] = { 22905, 0x1, 0x5F, 0xE0000, 0x775 },
+       [OLYMPUS_LUT_CHAN_572750_IDX] = { 22910, 0x1, 0x5F, 0xEAAAB, 0x775 },
+       [OLYMPUS_LUT_CHAN_572875_IDX] = { 22915, 0x1, 0x5F, 0xF5555, 0x776 },
+       [OLYMPUS_LUT_CHAN_573000_IDX] = { 22920, 0x1, 0x5F, 0x100000, 0x776 },
+       [OLYMPUS_LUT_CHAN_573125_IDX] = { 22925, 0x1, 0x5F, 0x10AAAB, 0x776 },
+       [OLYMPUS_LUT_CHAN_573250_IDX] = { 22930, 0x1, 0x5F, 0x115555, 0x777 },
+       [OLYMPUS_LUT_CHAN_573375_IDX] = { 22935, 0x1, 0x5F, 0x120000, 0x777 },
+       [OLYMPUS_LUT_CHAN_573500_IDX] = { 22940, 0x1, 0x5F, 0x12AAAB, 0x778 },
+       [OLYMPUS_LUT_CHAN_573625_IDX] = { 22945, 0x1, 0x5F, 0x135555, 0x778 },
+       [OLYMPUS_LUT_CHAN_573750_IDX] = { 22950, 0x1, 0x5F, 0x140000, 0x779 },
+       [OLYMPUS_LUT_CHAN_573875_IDX] = { 22955, 0x1, 0x5F, 0x14AAAB, 0x779 },
+       [OLYMPUS_LUT_CHAN_574000_IDX] = { 22960, 0x1, 0x5F, 0x155555, 0x779 },
+       [OLYMPUS_LUT_CHAN_574125_IDX] = { 22965, 0x1, 0x5F, 0x160000, 0x77A },
+       [OLYMPUS_LUT_CHAN_574250_IDX] = { 22970, 0x1, 0x5F, 0x16AAAB, 0x77A },
+       [OLYMPUS_LUT_CHAN_574375_IDX] = { 22975, 0x1, 0x5F, 0x175555, 0x77B },
+       [OLYMPUS_LUT_CHAN_574500_IDX] = { 22980, 0x1, 0x5F, 0x180000, 0x77B },
+       [OLYMPUS_LUT_CHAN_574625_IDX] = { 22985, 0x1, 0x5F, 0x18AAAB, 0x77B },
+       [OLYMPUS_LUT_CHAN_574750_IDX] = { 22990, 0x1, 0x5F, 0x195555, 0x77C },
+       [OLYMPUS_LUT_CHAN_574875_IDX] = { 22995, 0x1, 0x5F, 0x1A0000, 0x77C },
+       [OLYMPUS_LUT_CHAN_575000_IDX] = { 23000, 0x1, 0x5F, 0x1AAAAB, 0x77D },
+       [OLYMPUS_LUT_CHAN_575125_IDX] = { 23005, 0x1, 0x5F, 0x1B5555, 0x77D },
+       [OLYMPUS_LUT_CHAN_575250_IDX] = { 23010, 0x1, 0x5F, 0x1C0000, 0x77E },
+       [OLYMPUS_LUT_CHAN_575375_IDX] = { 23015, 0x1, 0x5F, 0x1CAAAB, 0x77E },
+       [OLYMPUS_LUT_CHAN_575500_IDX] = { 23020, 0x1, 0x5F, 0x1D5555, 0x77E },
+       [OLYMPUS_LUT_CHAN_575625_IDX] = { 23025, 0x1, 0x5F, 0x1E0000, 0x77F },
+       [OLYMPUS_LUT_CHAN_575750_IDX] = { 23030, 0x1, 0x5F, 0x1EAAAB, 0x77F },
+       [OLYMPUS_LUT_CHAN_575875_IDX] = { 23035, 0x1, 0x5F, 0x1F5555, 0x780 },
+       [OLYMPUS_LUT_CHAN_576000_IDX] = { 23040, 0x1, 0x60, 0x0, 0x780 },
+       [OLYMPUS_LUT_CHAN_576125_IDX] = { 23045, 0x1, 0x60, 0xAAAB, 0x780 },
+       [OLYMPUS_LUT_CHAN_576250_IDX] = { 23050, 0x1, 0x60, 0x15555, 0x781 },
+       [OLYMPUS_LUT_CHAN_576375_IDX] = { 23055, 0x1, 0x60, 0x20000, 0x781 },
+       [OLYMPUS_LUT_CHAN_576500_IDX] = { 23060, 0x1, 0x60, 0x2AAAB, 0x782 },
+       [OLYMPUS_LUT_CHAN_576625_IDX] = { 23065, 0x1, 0x60, 0x35555, 0x782 },
+       [OLYMPUS_LUT_CHAN_576750_IDX] = { 23070, 0x1, 0x60, 0x40000, 0x783 },
+       [OLYMPUS_LUT_CHAN_576875_IDX] = { 23075, 0x1, 0x60, 0x4AAAB, 0x783 },
+       [OLYMPUS_LUT_CHAN_577000_IDX] = { 23080, 0x1, 0x60, 0x55555, 0x783 },
+       [OLYMPUS_LUT_CHAN_577125_IDX] = { 23085, 0x1, 0x60, 0x60000, 0x784 },
+       [OLYMPUS_LUT_CHAN_577250_IDX] = { 23090, 0x1, 0x60, 0x6AAAB, 0x784 },
+       [OLYMPUS_LUT_CHAN_577375_IDX] = { 23095, 0x1, 0x60, 0x75555, 0x785 },
+       [OLYMPUS_LUT_CHAN_577500_IDX] = { 23100, 0x1, 0x60, 0x80000, 0x785 },
+       [OLYMPUS_LUT_CHAN_577625_IDX] = { 23105, 0x1, 0x60, 0x8AAAB, 0x785 },
+       [OLYMPUS_LUT_CHAN_577750_IDX] = { 23110, 0x1, 0x60, 0x95555, 0x786 },
+       [OLYMPUS_LUT_CHAN_577875_IDX] = { 23115, 0x1, 0x60, 0xA0000, 0x786 },
+       [OLYMPUS_LUT_CHAN_578000_IDX] = { 23120, 0x1, 0x60, 0xAAAAB, 0x787 },
+       [OLYMPUS_LUT_CHAN_578125_IDX] = { 23125, 0x1, 0x60, 0xB5555, 0x787 },
+       [OLYMPUS_LUT_CHAN_578250_IDX] = { 23130, 0x1, 0x60, 0xC0000, 0x788 },
+       [OLYMPUS_LUT_CHAN_578375_IDX] = { 23135, 0x1, 0x60, 0xCAAAB, 0x788 },
+       [OLYMPUS_LUT_CHAN_578500_IDX] = { 23140, 0x1, 0x60, 0xD5555, 0x788 },
+       [OLYMPUS_LUT_CHAN_578625_IDX] = { 23145, 0x1, 0x60, 0xE0000, 0x789 },
+       [OLYMPUS_LUT_CHAN_578750_IDX] = { 23150, 0x1, 0x60, 0xEAAAB, 0x789 },
+       [OLYMPUS_LUT_CHAN_578875_IDX] = { 23155, 0x1, 0x60, 0xF5555, 0x78A },
+       [OLYMPUS_LUT_CHAN_579000_IDX] = { 23160, 0x1, 0x60, 0x100000, 0x78A },
+       [OLYMPUS_LUT_CHAN_579125_IDX] = { 23165, 0x1, 0x60, 0x10AAAB, 0x78A },
+       [OLYMPUS_LUT_CHAN_579250_IDX] = { 23170, 0x1, 0x60, 0x115555, 0x78B },
+       [OLYMPUS_LUT_CHAN_579375_IDX] = { 23175, 0x1, 0x60, 0x120000, 0x78B },
+       [OLYMPUS_LUT_CHAN_579500_IDX] = { 23180, 0x1, 0x60, 0x12AAAB, 0x78C },
+       [OLYMPUS_LUT_CHAN_579625_IDX] = { 23185, 0x1, 0x60, 0x135555, 0x78C },
+       [OLYMPUS_LUT_CHAN_579750_IDX] = { 23190, 0x1, 0x60, 0x140000, 0x78D },
+       [OLYMPUS_LUT_CHAN_579875_IDX] = { 23195, 0x1, 0x60, 0x14AAAB, 0x78D },
+       [OLYMPUS_LUT_CHAN_580000_IDX] = { 23200, 0x1, 0x60, 0x155555, 0x78D },
+       [OLYMPUS_LUT_CHAN_580125_IDX] = { 23205, 0x1, 0x60, 0x160000, 0x78E },
+       [OLYMPUS_LUT_CHAN_580250_IDX] = { 23210, 0x1, 0x60, 0x16AAAB, 0x78E },
+       [OLYMPUS_LUT_CHAN_580375_IDX] = { 23215, 0x1, 0x60, 0x175555, 0x78F },
+       [OLYMPUS_LUT_CHAN_580500_IDX] = { 23220, 0x1, 0x60, 0x180000, 0x78F },
+       [OLYMPUS_LUT_CHAN_580625_IDX] = { 23225, 0x1, 0x60, 0x18AAAB, 0x78F },
+       [OLYMPUS_LUT_CHAN_580750_IDX] = { 23230, 0x1, 0x60, 0x195555, 0x790 },
+       [OLYMPUS_LUT_CHAN_580875_IDX] = { 23235, 0x1, 0x60, 0x1A0000, 0x790 },
+       [OLYMPUS_LUT_CHAN_581000_IDX] = { 23240, 0x1, 0x60, 0x1AAAAB, 0x791 },
+       [OLYMPUS_LUT_CHAN_581125_IDX] = { 23245, 0x1, 0x60, 0x1B5555, 0x791 },
+       [OLYMPUS_LUT_CHAN_581250_IDX] = { 23250, 0x1, 0x60, 0x1C0000, 0x792 },
+       [OLYMPUS_LUT_CHAN_581375_IDX] = { 23255, 0x1, 0x60, 0x1CAAAB, 0x792 },
+       [OLYMPUS_LUT_CHAN_581500_IDX] = { 23260, 0x1, 0x60, 0x1D5555, 0x792 },
+       [OLYMPUS_LUT_CHAN_581625_IDX] = { 23265, 0x1, 0x60, 0x1E0000, 0x793 },
+       [OLYMPUS_LUT_CHAN_581750_IDX] = { 23270, 0x1, 0x60, 0x1EAAAB, 0x793 },
+       [OLYMPUS_LUT_CHAN_581875_IDX] = { 23275, 0x1, 0x60, 0x1F5555, 0x794 },
+       [OLYMPUS_LUT_CHAN_582000_IDX] = { 23280, 0x1, 0x61, 0x0, 0x794 },
+       [OLYMPUS_LUT_CHAN_582125_IDX] = { 23285, 0x1, 0x61, 0xAAAB, 0x794 },
+       [OLYMPUS_LUT_CHAN_582250_IDX] = { 23290, 0x1, 0x61, 0x15555, 0x795 },
+       [OLYMPUS_LUT_CHAN_582375_IDX] = { 23295, 0x1, 0x61, 0x20000, 0x795 },
+       [OLYMPUS_LUT_CHAN_582500_IDX] = { 23300, 0x1, 0x61, 0x2AAAB, 0x796 },
+       [OLYMPUS_LUT_CHAN_582625_IDX] = { 23305, 0x1, 0x61, 0x35555, 0x796 },
+       [OLYMPUS_LUT_CHAN_582750_IDX] = { 23310, 0x1, 0x61, 0x40000, 0x797 },
+       [OLYMPUS_LUT_CHAN_582875_IDX] = { 23315, 0x1, 0x61, 0x4AAAB, 0x797 },
+       [OLYMPUS_LUT_CHAN_583000_IDX] = { 23320, 0x1, 0x61, 0x55555, 0x797 },
+       [OLYMPUS_LUT_CHAN_583125_IDX] = { 23325, 0x1, 0x61, 0x60000, 0x798 },
+       [OLYMPUS_LUT_CHAN_583250_IDX] = { 23330, 0x1, 0x61, 0x6AAAB, 0x798 },
+       [OLYMPUS_LUT_CHAN_583375_IDX] = { 23335, 0x1, 0x61, 0x75555, 0x799 },
+       [OLYMPUS_LUT_CHAN_583500_IDX] = { 23340, 0x1, 0x61, 0x80000, 0x799 },
+       [OLYMPUS_LUT_CHAN_583625_IDX] = { 23345, 0x1, 0x61, 0x8AAAB, 0x799 },
+       [OLYMPUS_LUT_CHAN_583750_IDX] = { 23350, 0x1, 0x61, 0x95555, 0x79A },
+       [OLYMPUS_LUT_CHAN_583875_IDX] = { 23355, 0x1, 0x61, 0xA0000, 0x79A },
+       [OLYMPUS_LUT_CHAN_584000_IDX] = { 23360, 0x1, 0x61, 0xAAAAB, 0x79B },
+       [OLYMPUS_LUT_CHAN_584125_IDX] = { 23365, 0x1, 0x61, 0xB5555, 0x79B },
+       [OLYMPUS_LUT_CHAN_584250_IDX] = { 23370, 0x1, 0x61, 0xC0000, 0x79C },
+       [OLYMPUS_LUT_CHAN_584375_IDX] = { 23375, 0x1, 0x61, 0xCAAAB, 0x79C },
+       [OLYMPUS_LUT_CHAN_584500_IDX] = { 23380, 0x1, 0x61, 0xD5555, 0x79C },
+       [OLYMPUS_LUT_CHAN_584625_IDX] = { 23385, 0x1, 0x61, 0xE0000, 0x79D },
+       [OLYMPUS_LUT_CHAN_584750_IDX] = { 23390, 0x1, 0x61, 0xEAAAB, 0x79D },
+       [OLYMPUS_LUT_CHAN_584875_IDX] = { 23395, 0x1, 0x61, 0xF5555, 0x79E },
+       [OLYMPUS_LUT_CHAN_585000_IDX] = { 23400, 0x1, 0x61, 0x100000, 0x79E },
+       [OLYMPUS_LUT_CHAN_585125_IDX] = { 23405, 0x1, 0x61, 0x10AAAB, 0x79E },
+       [OLYMPUS_LUT_CHAN_585250_IDX] = { 23410, 0x1, 0x61, 0x115555, 0x79F },
+       [OLYMPUS_LUT_CHAN_585375_IDX] = { 23415, 0x1, 0x61, 0x120000, 0x79F },
+       [OLYMPUS_LUT_CHAN_585500_IDX] = { 23420, 0x1, 0x61, 0x12AAAB, 0x7A0 },
+       [OLYMPUS_LUT_CHAN_585625_IDX] = { 23425, 0x1, 0x61, 0x135555, 0x7A0 },
+       [OLYMPUS_LUT_CHAN_585750_IDX] = { 23430, 0x1, 0x61, 0x140000, 0x7A1 },
+       [OLYMPUS_LUT_CHAN_585875_IDX] = { 23435, 0x1, 0x61, 0x14AAAB, 0x7A1 },
+       [OLYMPUS_LUT_CHAN_586000_IDX] = { 23440, 0x1, 0x61, 0x155555, 0x7A1 },
+       [OLYMPUS_LUT_CHAN_586125_IDX] = { 23445, 0x1, 0x61, 0x160000, 0x7A2 },
+       [OLYMPUS_LUT_CHAN_586250_IDX] = { 23450, 0x1, 0x61, 0x16AAAB, 0x7A2 },
+       [OLYMPUS_LUT_CHAN_586375_IDX] = { 23455, 0x1, 0x61, 0x175555, 0x7A3 },
+       [OLYMPUS_LUT_CHAN_586500_IDX] = { 23460, 0x1, 0x61, 0x180000, 0x7A3 },
+       [OLYMPUS_LUT_CHAN_586625_IDX] = { 23465, 0x1, 0x61, 0x18AAAB, 0x7A3 },
+       [OLYMPUS_LUT_CHAN_586750_IDX] = { 23470, 0x1, 0x61, 0x195555, 0x7A4 },
+       [OLYMPUS_LUT_CHAN_586875_IDX] = { 23475, 0x1, 0x61, 0x1A0000, 0x7A4 },
+       [OLYMPUS_LUT_CHAN_587000_IDX] = { 23480, 0x1, 0x61, 0x1AAAAB, 0x7A5 },
+       [OLYMPUS_LUT_CHAN_587125_IDX] = { 23485, 0x1, 0x61, 0x1B5555, 0x7A5 },
+       [OLYMPUS_LUT_CHAN_587250_IDX] = { 23490, 0x1, 0x61, 0x1C0000, 0x7A6 },
+       [OLYMPUS_LUT_CHAN_587375_IDX] = { 23495, 0x1, 0x61, 0x1CAAAB, 0x7A6 },
+       [OLYMPUS_LUT_CHAN_587500_IDX] = { 23500, 0x1, 0x61, 0x1D5555, 0x7A6 },
+       [OLYMPUS_LUT_CHAN_587625_IDX] = { 23505, 0x1, 0x61, 0x1E0000, 0x7A7 },
+       [OLYMPUS_LUT_CHAN_587750_IDX] = { 23510, 0x1, 0x61, 0x1EAAAB, 0x7A7 },
+       [OLYMPUS_LUT_CHAN_587875_IDX] = { 23515, 0x1, 0x61, 0x1F5555, 0x7A8 },
+       [OLYMPUS_LUT_CHAN_588000_IDX] = { 23520, 0x1, 0x62, 0x0, 0x7A8 },
+       [OLYMPUS_LUT_CHAN_588125_IDX] = { 23525, 0x1, 0x62, 0xAAAB, 0x7A8 },
+       [OLYMPUS_LUT_CHAN_588250_IDX] = { 23530, 0x1, 0x62, 0x15555, 0x7A9 },
+       [OLYMPUS_LUT_CHAN_588375_IDX] = { 23535, 0x1, 0x62, 0x20000, 0x7A9 },
+       [OLYMPUS_LUT_CHAN_588500_IDX] = { 23540, 0x1, 0x62, 0x2AAAB, 0x7AA },
+       [OLYMPUS_LUT_CHAN_588625_IDX] = { 23545, 0x1, 0x62, 0x35555, 0x7AA },
+       [OLYMPUS_LUT_CHAN_588750_IDX] = { 23550, 0x1, 0x62, 0x40000, 0x7AB },
+       [OLYMPUS_LUT_CHAN_588875_IDX] = { 23555, 0x1, 0x62, 0x4AAAB, 0x7AB },
+       [OLYMPUS_LUT_CHAN_589000_IDX] = { 23560, 0x1, 0x62, 0x55555, 0x7AB },
+       [OLYMPUS_LUT_CHAN_589125_IDX] = { 23565, 0x1, 0x62, 0x60000, 0x7AC },
+       [OLYMPUS_LUT_CHAN_589250_IDX] = { 23570, 0x1, 0x62, 0x6AAAB, 0x7AC },
+       [OLYMPUS_LUT_CHAN_589375_IDX] = { 23575, 0x1, 0x62, 0x75555, 0x7AD },
+       [OLYMPUS_LUT_CHAN_589500_IDX] = { 23580, 0x1, 0x62, 0x80000, 0x7AD },
+       [OLYMPUS_LUT_CHAN_589625_IDX] = { 23585, 0x1, 0x62, 0x8AAAB, 0x7AD },
+       [OLYMPUS_LUT_CHAN_589750_IDX] = { 23590, 0x1, 0x62, 0x95555, 0x7AE },
+       [OLYMPUS_LUT_CHAN_589875_IDX] = { 23595, 0x1, 0x62, 0xA0000, 0x7AE },
+       [OLYMPUS_LUT_CHAN_590000_IDX] = { 23600, 0x1, 0x62, 0xAAAAB, 0x7AF },
+       [OLYMPUS_LUT_CHAN_590125_IDX] = { 23605, 0x1, 0x62, 0xB5555, 0x7AF },
+       [OLYMPUS_LUT_CHAN_590250_IDX] = { 23610, 0x1, 0x62, 0xC0000, 0x7B0 },
+       [OLYMPUS_LUT_CHAN_590375_IDX] = { 23615, 0x1, 0x62, 0xCAAAB, 0x7B0 },
+       [OLYMPUS_LUT_CHAN_590500_IDX] = { 23620, 0x1, 0x62, 0xD5555, 0x7B0 },
+       [OLYMPUS_LUT_CHAN_590625_IDX] = { 23625, 0x1, 0x62, 0xE0000, 0x7B1 },
+       [OLYMPUS_LUT_CHAN_590750_IDX] = { 23630, 0x1, 0x62, 0xEAAAB, 0x7B1 },
+       [OLYMPUS_LUT_CHAN_590875_IDX] = { 23635, 0x1, 0x62, 0xF5555, 0x7B2 },
+       [OLYMPUS_LUT_CHAN_591000_IDX] = { 23640, 0x1, 0x62, 0x100000, 0x7B2 },
+       [OLYMPUS_LUT_CHAN_591125_IDX] = { 23645, 0x1, 0x62, 0x10AAAB, 0x7B2 },
+       [OLYMPUS_LUT_CHAN_591250_IDX] = { 23650, 0x1, 0x62, 0x115555, 0x7B3 },
+       [OLYMPUS_LUT_CHAN_591375_IDX] = { 23655, 0x1, 0x62, 0x120000, 0x7B3 },
+       [OLYMPUS_LUT_CHAN_591500_IDX] = { 23660, 0x1, 0x62, 0x12AAAB, 0x7B4 },
+       [OLYMPUS_LUT_CHAN_591625_IDX] = { 23665, 0x1, 0x62, 0x135555, 0x7B4 },
+       [OLYMPUS_LUT_CHAN_591750_IDX] = { 23670, 0x1, 0x62, 0x140000, 0x7B5 },
+       [OLYMPUS_LUT_CHAN_591875_IDX] = { 23675, 0x1, 0x62, 0x14AAAB, 0x7B5 },
+       [OLYMPUS_LUT_CHAN_592000_IDX] = { 23680, 0x1, 0x62, 0x155555, 0x7B5 },
+       [OLYMPUS_LUT_CHAN_592125_IDX] = { 23685, 0x1, 0x62, 0x160000, 0x7B6 },
+       [OLYMPUS_LUT_CHAN_592250_IDX] = { 23690, 0x1, 0x62, 0x16AAAB, 0x7B6 },
+       [OLYMPUS_LUT_CHAN_592375_IDX] = { 23695, 0x1, 0x62, 0x175555, 0x7B7 },
+       [OLYMPUS_LUT_CHAN_592500_IDX] = { 23700, 0x1, 0x62, 0x180000, 0x7B7 },
+       [OLYMPUS_LUT_CHAN_592625_IDX] = { 23705, 0x1, 0x62, 0x18AAAB, 0x7B7 },
+       [OLYMPUS_LUT_CHAN_592750_IDX] = { 23710, 0x1, 0x62, 0x195555, 0x7B8 },
+       [OLYMPUS_LUT_CHAN_592875_IDX] = { 23715, 0x1, 0x62, 0x1A0000, 0x7B8 },
+       [OLYMPUS_LUT_CHAN_593000_IDX] = { 23720, 0x1, 0x62, 0x1AAAAB, 0x7B9 },
+       [OLYMPUS_LUT_CHAN_593125_IDX] = { 23725, 0x1, 0x62, 0x1B5555, 0x7B9 },
+       [OLYMPUS_LUT_CHAN_593250_IDX] = { 23730, 0x1, 0x62, 0x1C0000, 0x7BA },
+       [OLYMPUS_LUT_CHAN_593375_IDX] = { 23735, 0x1, 0x62, 0x1CAAAB, 0x7BA },
+       [OLYMPUS_LUT_CHAN_593500_IDX] = { 23740, 0x1, 0x62, 0x1D5555, 0x7BA },
+       [OLYMPUS_LUT_CHAN_593625_IDX] = { 23745, 0x1, 0x62, 0x1E0000, 0x7BB },
+       [OLYMPUS_LUT_CHAN_593750_IDX] = { 23750, 0x1, 0x62, 0x1EAAAB, 0x7BB },
+       [OLYMPUS_LUT_CHAN_593875_IDX] = { 23755, 0x1, 0x62, 0x1F5555, 0x7BC },
+       [OLYMPUS_LUT_CHAN_594000_IDX] = { 23760, 0x1, 0x63, 0x0, 0x7BC },
+       [OLYMPUS_LUT_CHAN_594125_IDX] = { 23765, 0x1, 0x63, 0xAAAB, 0x7BC },
+       [OLYMPUS_LUT_CHAN_594250_IDX] = { 23770, 0x1, 0x63, 0x15555, 0x7BD },
+       [OLYMPUS_LUT_CHAN_594375_IDX] = { 23775, 0x1, 0x63, 0x20000, 0x7BD },
+       [OLYMPUS_LUT_CHAN_594500_IDX] = { 23780, 0x1, 0x63, 0x2AAAB, 0x7BE },
+       [OLYMPUS_LUT_CHAN_594625_IDX] = { 23785, 0x1, 0x63, 0x35555, 0x7BE },
+       [OLYMPUS_LUT_CHAN_594750_IDX] = { 23790, 0x1, 0x63, 0x40000, 0x7BF },
+       [OLYMPUS_LUT_CHAN_594875_IDX] = { 23795, 0x1, 0x63, 0x4AAAB, 0x7BF },
+       [OLYMPUS_LUT_CHAN_595000_IDX] = { 23800, 0x1, 0x63, 0x55555, 0x7BF },
+       [OLYMPUS_LUT_CHAN_595125_IDX] = { 23805, 0x1, 0x63, 0x60000, 0x7C0 },
+       [OLYMPUS_LUT_CHAN_595250_IDX] = { 23810, 0x1, 0x63, 0x6AAAB, 0x7C0 },
+       [OLYMPUS_LUT_CHAN_595375_IDX] = { 23815, 0x1, 0x63, 0x75555, 0x7C1 },
+       [OLYMPUS_LUT_CHAN_595500_IDX] = { 23820, 0x1, 0x63, 0x80000, 0x7C1 },
+       [OLYMPUS_LUT_CHAN_595625_IDX] = { 23825, 0x1, 0x63, 0x8AAAB, 0x7C1 },
+       [OLYMPUS_LUT_CHAN_595750_IDX] = { 23830, 0x1, 0x63, 0x95555, 0x7C2 },
+       [OLYMPUS_LUT_CHAN_595875_IDX] = { 23835, 0x1, 0x63, 0xA0000, 0x7C2 },
+       [OLYMPUS_LUT_CHAN_596000_IDX] = { 23840, 0x1, 0x63, 0xAAAAB, 0x7C3 },
+       [OLYMPUS_LUT_CHAN_596125_IDX] = { 23845, 0x1, 0x63, 0xB5555, 0x7C3 },
+       [OLYMPUS_LUT_CHAN_596250_IDX] = { 23850, 0x1, 0x63, 0xC0000, 0x7C4 },
+       [OLYMPUS_LUT_CHAN_596375_IDX] = { 23855, 0x1, 0x63, 0xCAAAB, 0x7C4 },
+       [OLYMPUS_LUT_CHAN_596500_IDX] = { 23860, 0x1, 0x63, 0xD5555, 0x7C4 },
+       [OLYMPUS_LUT_CHAN_596625_IDX] = { 23865, 0x1, 0x63, 0xE0000, 0x7C5 },
+       [OLYMPUS_LUT_CHAN_596750_IDX] = { 23870, 0x1, 0x63, 0xEAAAB, 0x7C5 },
+       [OLYMPUS_LUT_CHAN_596875_IDX] = { 23875, 0x1, 0x63, 0xF5555, 0x7C6 },
+       [OLYMPUS_LUT_CHAN_597000_IDX] = { 23880, 0x1, 0x63, 0x100000, 0x7C6 },
+       [OLYMPUS_LUT_CHAN_597125_IDX] = { 23885, 0x1, 0x63, 0x10AAAB, 0x7C6 },
+       [OLYMPUS_LUT_CHAN_597250_IDX] = { 23890, 0x1, 0x63, 0x115555, 0x7C7 },
+       [OLYMPUS_LUT_CHAN_597375_IDX] = { 23895, 0x1, 0x63, 0x120000, 0x7C7 },
+       [OLYMPUS_LUT_CHAN_597500_IDX] = { 23900, 0x1, 0x63, 0x12AAAB, 0x7C8 },
+       [OLYMPUS_LUT_CHAN_597625_IDX] = { 23905, 0x1, 0x63, 0x135555, 0x7C8 },
+       [OLYMPUS_LUT_CHAN_597750_IDX] = { 23910, 0x1, 0x63, 0x140000, 0x7C9 },
+       [OLYMPUS_LUT_CHAN_597875_IDX] = { 23915, 0x1, 0x63, 0x14AAAB, 0x7C9 },
+       [OLYMPUS_LUT_CHAN_598000_IDX] = { 23920, 0x1, 0x63, 0x155555, 0x7C9 },
+       [OLYMPUS_LUT_CHAN_598125_IDX] = { 23925, 0x1, 0x63, 0x160000, 0x7CA },
+       [OLYMPUS_LUT_CHAN_598250_IDX] = { 23930, 0x1, 0x63, 0x16AAAB, 0x7CA },
+       [OLYMPUS_LUT_CHAN_598375_IDX] = { 23935, 0x1, 0x63, 0x175555, 0x7CB },
+       [OLYMPUS_LUT_CHAN_598500_IDX] = { 23940, 0x1, 0x63, 0x180000, 0x7CB },
+       [OLYMPUS_LUT_CHAN_598625_IDX] = { 23945, 0x1, 0x63, 0x18AAAB, 0x7CB },
+       [OLYMPUS_LUT_CHAN_598750_IDX] = { 23950, 0x1, 0x63, 0x195555, 0x7CC },
+       [OLYMPUS_LUT_CHAN_598875_IDX] = { 23955, 0x1, 0x63, 0x1A0000, 0x7CC },
+       [OLYMPUS_LUT_CHAN_599000_IDX] = { 23960, 0x1, 0x63, 0x1AAAAB, 0x7CD },
+       [OLYMPUS_LUT_CHAN_599125_IDX] = { 23965, 0x1, 0x63, 0x1B5555, 0x7CD },
+       [OLYMPUS_LUT_CHAN_599250_IDX] = { 23970, 0x1, 0x63, 0x1C0000, 0x7CE },
+       [OLYMPUS_LUT_CHAN_599375_IDX] = { 23975, 0x1, 0x63, 0x1CAAAB, 0x7CE },
+       [OLYMPUS_LUT_CHAN_599500_IDX] = { 23980, 0x1, 0x63, 0x1D5555, 0x7CE },
+       [OLYMPUS_LUT_CHAN_599625_IDX] = { 23985, 0x1, 0x63, 0x1E0000, 0x7CF },
+       [OLYMPUS_LUT_CHAN_599750_IDX] = { 23990, 0x1, 0x63, 0x1EAAAB, 0x7CF },
+       [OLYMPUS_LUT_CHAN_599875_IDX] = { 23995, 0x1, 0x63, 0x1F5555, 0x7D0 },
+       [OLYMPUS_LUT_CHAN_600000_IDX] = { 24000, 0x1, 0x64, 0x0, 0x7D0 }
+};
+
+const struct olympus_lut_line olympus_lut_5g_60_mhz_s1[OLYMPUS_LUT_CHAN_5G_MAX] = {
+       [OLYMPUS_LUT_CHAN_516000_IDX] = { 20640, 0x0, 0x39, 0x11C71C, 0x6BF },
+       [OLYMPUS_LUT_CHAN_516125_IDX] = { 20645, 0x0, 0x39, 0xB1C72, 0x6B8 },
+       [OLYMPUS_LUT_CHAN_516250_IDX] = { 20650, 0x0, 0x39, 0xB8E39, 0x6B9 },
+       [OLYMPUS_LUT_CHAN_516375_IDX] = { 20655, 0x0, 0x39, 0xC0000, 0x6B9 },
+       [OLYMPUS_LUT_CHAN_516500_IDX] = { 20660, 0x0, 0x39, 0xC71C7, 0x6BA },
+       [OLYMPUS_LUT_CHAN_516625_IDX] = { 20665, 0x0, 0x39, 0xCE38E, 0x6BA },
+       [OLYMPUS_LUT_CHAN_516750_IDX] = { 20670, 0x0, 0x39, 0xD5555, 0x6BB },
+       [OLYMPUS_LUT_CHAN_516875_IDX] = { 20675, 0x0, 0x39, 0xDC71C, 0x6BB },
+       [OLYMPUS_LUT_CHAN_517000_IDX] = { 20680, 0x0, 0x39, 0xE38E4, 0x6BB },
+       [OLYMPUS_LUT_CHAN_517125_IDX] = { 20685, 0x0, 0x39, 0xEAAAB, 0x6BC },
+       [OLYMPUS_LUT_CHAN_517250_IDX] = { 20690, 0x0, 0x39, 0xF1C72, 0x6BC },
+       [OLYMPUS_LUT_CHAN_517375_IDX] = { 20695, 0x0, 0x39, 0xF8E39, 0x6BD },
+       [OLYMPUS_LUT_CHAN_517500_IDX] = { 20700, 0x0, 0x39, 0x100000, 0x6BD },
+       [OLYMPUS_LUT_CHAN_517625_IDX] = { 20705, 0x0, 0x39, 0x1071C7, 0x6BD },
+       [OLYMPUS_LUT_CHAN_517750_IDX] = { 20710, 0x0, 0x39, 0x10E38E, 0x6BE },
+       [OLYMPUS_LUT_CHAN_517875_IDX] = { 20715, 0x0, 0x39, 0x115555, 0x6BE },
+       [OLYMPUS_LUT_CHAN_518000_IDX] = { 20720, 0x1, 0x39, 0x11C71C, 0x6BF },
+       [OLYMPUS_LUT_CHAN_518125_IDX] = { 20725, 0x1, 0x39, 0x1238E4, 0x6BF },
+       [OLYMPUS_LUT_CHAN_518250_IDX] = { 20730, 0x1, 0x39, 0x12AAAB, 0x6C0 },
+       [OLYMPUS_LUT_CHAN_518375_IDX] = { 20735, 0x1, 0x39, 0x131C72, 0x6C0 },
+       [OLYMPUS_LUT_CHAN_518500_IDX] = { 20740, 0x1, 0x39, 0x138E39, 0x6C0 },
+       [OLYMPUS_LUT_CHAN_518625_IDX] = { 20745, 0x1, 0x39, 0x140000, 0x6C1 },
+       [OLYMPUS_LUT_CHAN_518750_IDX] = { 20750, 0x1, 0x39, 0x1471C7, 0x6C1 },
+       [OLYMPUS_LUT_CHAN_518875_IDX] = { 20755, 0x1, 0x39, 0x14E38E, 0x6C2 },
+       [OLYMPUS_LUT_CHAN_519000_IDX] = { 20760, 0x1, 0x39, 0x155555, 0x6C2 },
+       [OLYMPUS_LUT_CHAN_519125_IDX] = { 20765, 0x1, 0x39, 0x15C71C, 0x6C2 },
+       [OLYMPUS_LUT_CHAN_519250_IDX] = { 20770, 0x1, 0x39, 0x1638E4, 0x6C3 },
+       [OLYMPUS_LUT_CHAN_519375_IDX] = { 20775, 0x1, 0x39, 0x16AAAB, 0x6C3 },
+       [OLYMPUS_LUT_CHAN_519500_IDX] = { 20780, 0x1, 0x39, 0x171C72, 0x6C4 },
+       [OLYMPUS_LUT_CHAN_519625_IDX] = { 20785, 0x1, 0x39, 0x178E39, 0x6C4 },
+       [OLYMPUS_LUT_CHAN_519750_IDX] = { 20790, 0x1, 0x39, 0x180000, 0x6C5 },
+       [OLYMPUS_LUT_CHAN_519875_IDX] = { 20795, 0x1, 0x39, 0x1871C7, 0x6C5 },
+       [OLYMPUS_LUT_CHAN_520000_IDX] = { 20800, 0x1, 0x39, 0x18E38E, 0x6C5 },
+       [OLYMPUS_LUT_CHAN_520125_IDX] = { 20805, 0x1, 0x39, 0x195555, 0x6C6 },
+       [OLYMPUS_LUT_CHAN_520250_IDX] = { 20810, 0x1, 0x39, 0x19C71C, 0x6C6 },
+       [OLYMPUS_LUT_CHAN_520375_IDX] = { 20815, 0x1, 0x39, 0x1A38E4, 0x6C7 },
+       [OLYMPUS_LUT_CHAN_520500_IDX] = { 20820, 0x1, 0x39, 0x1AAAAB, 0x6C7 },
+       [OLYMPUS_LUT_CHAN_520625_IDX] = { 20825, 0x1, 0x39, 0x1B1C72, 0x6C7 },
+       [OLYMPUS_LUT_CHAN_520750_IDX] = { 20830, 0x1, 0x39, 0x1B8E39, 0x6C8 },
+       [OLYMPUS_LUT_CHAN_520875_IDX] = { 20835, 0x1, 0x39, 0x1C0000, 0x6C8 },
+       [OLYMPUS_LUT_CHAN_521000_IDX] = { 20840, 0x1, 0x39, 0x1C71C7, 0x6C9 },
+       [OLYMPUS_LUT_CHAN_521125_IDX] = { 20845, 0x1, 0x39, 0x1CE38E, 0x6C9 },
+       [OLYMPUS_LUT_CHAN_521250_IDX] = { 20850, 0x1, 0x39, 0x1D5555, 0x6CA },
+       [OLYMPUS_LUT_CHAN_521375_IDX] = { 20855, 0x1, 0x39, 0x1DC71C, 0x6CA },
+       [OLYMPUS_LUT_CHAN_521500_IDX] = { 20860, 0x1, 0x39, 0x1E38E4, 0x6CA },
+       [OLYMPUS_LUT_CHAN_521625_IDX] = { 20865, 0x1, 0x39, 0x1EAAAB, 0x6CB },
+       [OLYMPUS_LUT_CHAN_521750_IDX] = { 20870, 0x1, 0x39, 0x1F1C72, 0x6CB },
+       [OLYMPUS_LUT_CHAN_521875_IDX] = { 20875, 0x1, 0x39, 0x1F8E39, 0x6CC },
+       [OLYMPUS_LUT_CHAN_522000_IDX] = { 20880, 0x1, 0x3A, 0x0, 0x6CC },
+       [OLYMPUS_LUT_CHAN_522125_IDX] = { 20885, 0x1, 0x3A, 0x71C7, 0x6CC },
+       [OLYMPUS_LUT_CHAN_522250_IDX] = { 20890, 0x1, 0x3A, 0xE38E, 0x6CD },
+       [OLYMPUS_LUT_CHAN_522375_IDX] = { 20895, 0x1, 0x3A, 0x15555, 0x6CD },
+       [OLYMPUS_LUT_CHAN_522500_IDX] = { 20900, 0x1, 0x3A, 0x1C71C, 0x6CE },
+       [OLYMPUS_LUT_CHAN_522625_IDX] = { 20905, 0x1, 0x3A, 0x238E4, 0x6CE },
+       [OLYMPUS_LUT_CHAN_522750_IDX] = { 20910, 0x1, 0x3A, 0x2AAAB, 0x6CF },
+       [OLYMPUS_LUT_CHAN_522875_IDX] = { 20915, 0x1, 0x3A, 0x31C72, 0x6CF },
+       [OLYMPUS_LUT_CHAN_523000_IDX] = { 20920, 0x1, 0x3A, 0x38E39, 0x6CF },
+       [OLYMPUS_LUT_CHAN_523125_IDX] = { 20925, 0x1, 0x3A, 0x40000, 0x6D0 },
+       [OLYMPUS_LUT_CHAN_523250_IDX] = { 20930, 0x1, 0x3A, 0x471C7, 0x6D0 },
+       [OLYMPUS_LUT_CHAN_523375_IDX] = { 20935, 0x1, 0x3A, 0x4E38E, 0x6D1 },
+       [OLYMPUS_LUT_CHAN_523500_IDX] = { 20940, 0x1, 0x3A, 0x55555, 0x6D1 },
+       [OLYMPUS_LUT_CHAN_523625_IDX] = { 20945, 0x1, 0x3A, 0x5C71C, 0x6D1 },
+       [OLYMPUS_LUT_CHAN_523750_IDX] = { 20950, 0x1, 0x3A, 0x638E4, 0x6D2 },
+       [OLYMPUS_LUT_CHAN_523875_IDX] = { 20955, 0x1, 0x3A, 0x6AAAB, 0x6D2 },
+       [OLYMPUS_LUT_CHAN_524000_IDX] = { 20960, 0x1, 0x3A, 0x71C72, 0x6D3 },
+       [OLYMPUS_LUT_CHAN_524125_IDX] = { 20965, 0x1, 0x3A, 0x78E39, 0x6D3 },
+       [OLYMPUS_LUT_CHAN_524250_IDX] = { 20970, 0x1, 0x3A, 0x80000, 0x6D4 },
+       [OLYMPUS_LUT_CHAN_524375_IDX] = { 20975, 0x1, 0x3A, 0x871C7, 0x6D4 },
+       [OLYMPUS_LUT_CHAN_524500_IDX] = { 20980, 0x1, 0x3A, 0x8E38E, 0x6D4 },
+       [OLYMPUS_LUT_CHAN_524625_IDX] = { 20985, 0x1, 0x3A, 0x95555, 0x6D5 },
+       [OLYMPUS_LUT_CHAN_524750_IDX] = { 20990, 0x1, 0x3A, 0x9C71C, 0x6D5 },
+       [OLYMPUS_LUT_CHAN_524875_IDX] = { 20995, 0x1, 0x3A, 0xA38E4, 0x6D6 },
+       [OLYMPUS_LUT_CHAN_525000_IDX] = { 21000, 0x1, 0x3A, 0xAAAAB, 0x6D6 },
+       [OLYMPUS_LUT_CHAN_525125_IDX] = { 21005, 0x1, 0x3A, 0xB1C72, 0x6D6 },
+       [OLYMPUS_LUT_CHAN_525250_IDX] = { 21010, 0x1, 0x3A, 0xB8E39, 0x6D7 },
+       [OLYMPUS_LUT_CHAN_525375_IDX] = { 21015, 0x1, 0x3A, 0xC0000, 0x6D7 },
+       [OLYMPUS_LUT_CHAN_525500_IDX] = { 21020, 0x1, 0x3A, 0xC71C7, 0x6D8 },
+       [OLYMPUS_LUT_CHAN_525625_IDX] = { 21025, 0x1, 0x3A, 0xCE38E, 0x6D8 },
+       [OLYMPUS_LUT_CHAN_525750_IDX] = { 21030, 0x1, 0x3A, 0xD5555, 0x6D9 },
+       [OLYMPUS_LUT_CHAN_525875_IDX] = { 21035, 0x1, 0x3A, 0xDC71C, 0x6D9 },
+       [OLYMPUS_LUT_CHAN_526000_IDX] = { 21040, 0x1, 0x3A, 0xE38E4, 0x6D9 },
+       [OLYMPUS_LUT_CHAN_526125_IDX] = { 21045, 0x1, 0x3A, 0xEAAAB, 0x6DA },
+       [OLYMPUS_LUT_CHAN_526250_IDX] = { 21050, 0x1, 0x3A, 0xF1C72, 0x6DA },
+       [OLYMPUS_LUT_CHAN_526375_IDX] = { 21055, 0x1, 0x3A, 0xF8E39, 0x6DB },
+       [OLYMPUS_LUT_CHAN_526500_IDX] = { 21060, 0x1, 0x3A, 0x100000, 0x6DB },
+       [OLYMPUS_LUT_CHAN_526625_IDX] = { 21065, 0x1, 0x3A, 0x1071C7, 0x6DB },
+       [OLYMPUS_LUT_CHAN_526750_IDX] = { 21070, 0x1, 0x3A, 0x10E38E, 0x6DC },
+       [OLYMPUS_LUT_CHAN_526875_IDX] = { 21075, 0x1, 0x3A, 0x115555, 0x6DC },
+       [OLYMPUS_LUT_CHAN_527000_IDX] = { 21080, 0x1, 0x3A, 0x11C71C, 0x6DD },
+       [OLYMPUS_LUT_CHAN_527125_IDX] = { 21085, 0x1, 0x3A, 0x1238E4, 0x6DD },
+       [OLYMPUS_LUT_CHAN_527250_IDX] = { 21090, 0x1, 0x3A, 0x12AAAB, 0x6DE },
+       [OLYMPUS_LUT_CHAN_527375_IDX] = { 21095, 0x1, 0x3A, 0x131C72, 0x6DE },
+       [OLYMPUS_LUT_CHAN_527500_IDX] = { 21100, 0x1, 0x3A, 0x138E39, 0x6DE },
+       [OLYMPUS_LUT_CHAN_527625_IDX] = { 21105, 0x1, 0x3A, 0x140000, 0x6DF },
+       [OLYMPUS_LUT_CHAN_527750_IDX] = { 21110, 0x1, 0x3A, 0x1471C7, 0x6DF },
+       [OLYMPUS_LUT_CHAN_527875_IDX] = { 21115, 0x1, 0x3A, 0x14E38E, 0x6E0 },
+       [OLYMPUS_LUT_CHAN_528000_IDX] = { 21120, 0x1, 0x3A, 0x155555, 0x6E0 },
+       [OLYMPUS_LUT_CHAN_528125_IDX] = { 21125, 0x1, 0x3A, 0x15C71C, 0x6E0 },
+       [OLYMPUS_LUT_CHAN_528250_IDX] = { 21130, 0x1, 0x3A, 0x1638E4, 0x6E1 },
+       [OLYMPUS_LUT_CHAN_528375_IDX] = { 21135, 0x1, 0x3A, 0x16AAAB, 0x6E1 },
+       [OLYMPUS_LUT_CHAN_528500_IDX] = { 21140, 0x1, 0x3A, 0x171C72, 0x6E2 },
+       [OLYMPUS_LUT_CHAN_528625_IDX] = { 21145, 0x1, 0x3A, 0x178E39, 0x6E2 },
+       [OLYMPUS_LUT_CHAN_528750_IDX] = { 21150, 0x1, 0x3A, 0x180000, 0x6E3 },
+       [OLYMPUS_LUT_CHAN_528875_IDX] = { 21155, 0x1, 0x3A, 0x1871C7, 0x6E3 },
+       [OLYMPUS_LUT_CHAN_529000_IDX] = { 21160, 0x1, 0x3A, 0x18E38E, 0x6E3 },
+       [OLYMPUS_LUT_CHAN_529125_IDX] = { 21165, 0x1, 0x3A, 0x195555, 0x6E4 },
+       [OLYMPUS_LUT_CHAN_529250_IDX] = { 21170, 0x1, 0x3A, 0x19C71C, 0x6E4 },
+       [OLYMPUS_LUT_CHAN_529375_IDX] = { 21175, 0x1, 0x3A, 0x1A38E4, 0x6E5 },
+       [OLYMPUS_LUT_CHAN_529500_IDX] = { 21180, 0x1, 0x3A, 0x1AAAAB, 0x6E5 },
+       [OLYMPUS_LUT_CHAN_529625_IDX] = { 21185, 0x1, 0x3A, 0x1B1C72, 0x6E5 },
+       [OLYMPUS_LUT_CHAN_529750_IDX] = { 21190, 0x1, 0x3A, 0x1B8E39, 0x6E6 },
+       [OLYMPUS_LUT_CHAN_529875_IDX] = { 21195, 0x1, 0x3A, 0x1C0000, 0x6E6 },
+       [OLYMPUS_LUT_CHAN_530000_IDX] = { 21200, 0x1, 0x3A, 0x1C71C7, 0x6E7 },
+       [OLYMPUS_LUT_CHAN_530125_IDX] = { 21205, 0x1, 0x3A, 0x1CE38E, 0x6E7 },
+       [OLYMPUS_LUT_CHAN_530250_IDX] = { 21210, 0x1, 0x3A, 0x1D5555, 0x6E8 },
+       [OLYMPUS_LUT_CHAN_530375_IDX] = { 21215, 0x1, 0x3A, 0x1DC71C, 0x6E8 },
+       [OLYMPUS_LUT_CHAN_530500_IDX] = { 21220, 0x1, 0x3A, 0x1E38E4, 0x6E8 },
+       [OLYMPUS_LUT_CHAN_530625_IDX] = { 21225, 0x1, 0x3A, 0x1EAAAB, 0x6E9 },
+       [OLYMPUS_LUT_CHAN_530750_IDX] = { 21230, 0x1, 0x3A, 0x1F1C72, 0x6E9 },
+       [OLYMPUS_LUT_CHAN_530875_IDX] = { 21235, 0x1, 0x3A, 0x1F8E39, 0x6EA },
+       [OLYMPUS_LUT_CHAN_531000_IDX] = { 21240, 0x1, 0x3B, 0x0, 0x6EA },
+       [OLYMPUS_LUT_CHAN_531125_IDX] = { 21245, 0x1, 0x3B, 0x71C7, 0x6EA },
+       [OLYMPUS_LUT_CHAN_531250_IDX] = { 21250, 0x1, 0x3B, 0xE38E, 0x6EB },
+       [OLYMPUS_LUT_CHAN_531375_IDX] = { 21255, 0x1, 0x3B, 0x15555, 0x6EB },
+       [OLYMPUS_LUT_CHAN_531500_IDX] = { 21260, 0x1, 0x3B, 0x1C71C, 0x6EC },
+       [OLYMPUS_LUT_CHAN_531625_IDX] = { 21265, 0x1, 0x3B, 0x238E4, 0x6EC },
+       [OLYMPUS_LUT_CHAN_531750_IDX] = { 21270, 0x1, 0x3B, 0x2AAAB, 0x6ED },
+       [OLYMPUS_LUT_CHAN_531875_IDX] = { 21275, 0x1, 0x3B, 0x31C72, 0x6ED },
+       [OLYMPUS_LUT_CHAN_532000_IDX] = { 21280, 0x1, 0x3B, 0x38E39, 0x6ED },
+       [OLYMPUS_LUT_CHAN_532125_IDX] = { 21285, 0x1, 0x3B, 0x40000, 0x6EE },
+       [OLYMPUS_LUT_CHAN_532250_IDX] = { 21290, 0x1, 0x3B, 0x471C7, 0x6EE },
+       [OLYMPUS_LUT_CHAN_532375_IDX] = { 21295, 0x1, 0x3B, 0x4E38E, 0x6EF },
+       [OLYMPUS_LUT_CHAN_532500_IDX] = { 21300, 0x1, 0x3B, 0x55555, 0x6EF },
+       [OLYMPUS_LUT_CHAN_532625_IDX] = { 21305, 0x1, 0x3B, 0x5C71C, 0x6EF },
+       [OLYMPUS_LUT_CHAN_532750_IDX] = { 21310, 0x1, 0x3B, 0x638E4, 0x6F0 },
+       [OLYMPUS_LUT_CHAN_532875_IDX] = { 21315, 0x1, 0x3B, 0x6AAAB, 0x6F0 },
+       [OLYMPUS_LUT_CHAN_533000_IDX] = { 21320, 0x1, 0x3B, 0x71C72, 0x6F1 },
+       [OLYMPUS_LUT_CHAN_533125_IDX] = { 21325, 0x1, 0x3B, 0x78E39, 0x6F1 },
+       [OLYMPUS_LUT_CHAN_533250_IDX] = { 21330, 0x1, 0x3B, 0x80000, 0x6F2 },
+       [OLYMPUS_LUT_CHAN_533375_IDX] = { 21335, 0x1, 0x3B, 0x871C7, 0x6F2 },
+       [OLYMPUS_LUT_CHAN_533500_IDX] = { 21340, 0x1, 0x3B, 0x8E38E, 0x6F2 },
+       [OLYMPUS_LUT_CHAN_533625_IDX] = { 21345, 0x1, 0x3B, 0x95555, 0x6F3 },
+       [OLYMPUS_LUT_CHAN_533750_IDX] = { 21350, 0x1, 0x3B, 0x9C71C, 0x6F3 },
+       [OLYMPUS_LUT_CHAN_533875_IDX] = { 21355, 0x1, 0x3B, 0xA38E4, 0x6F4 },
+       [OLYMPUS_LUT_CHAN_534000_IDX] = { 21360, 0x1, 0x3B, 0xAAAAB, 0x6F4 },
+       [OLYMPUS_LUT_CHAN_534125_IDX] = { 21365, 0x1, 0x3B, 0xB1C72, 0x6F4 },
+       [OLYMPUS_LUT_CHAN_534250_IDX] = { 21370, 0x1, 0x3B, 0xB8E39, 0x6F5 },
+       [OLYMPUS_LUT_CHAN_534375_IDX] = { 21375, 0x1, 0x3B, 0xC0000, 0x6F5 },
+       [OLYMPUS_LUT_CHAN_534500_IDX] = { 21380, 0x1, 0x3B, 0xC71C7, 0x6F6 },
+       [OLYMPUS_LUT_CHAN_534625_IDX] = { 21385, 0x1, 0x3B, 0xCE38E, 0x6F6 },
+       [OLYMPUS_LUT_CHAN_534750_IDX] = { 21390, 0x1, 0x3B, 0xD5555, 0x6F7 },
+       [OLYMPUS_LUT_CHAN_534875_IDX] = { 21395, 0x1, 0x3B, 0xDC71C, 0x6F7 },
+       [OLYMPUS_LUT_CHAN_535000_IDX] = { 21400, 0x1, 0x3B, 0xE38E4, 0x6F7 },
+       [OLYMPUS_LUT_CHAN_535125_IDX] = { 21405, 0x1, 0x3B, 0xEAAAB, 0x6F8 },
+       [OLYMPUS_LUT_CHAN_535250_IDX] = { 21410, 0x1, 0x3B, 0xF1C72, 0x6F8 },
+       [OLYMPUS_LUT_CHAN_535375_IDX] = { 21415, 0x1, 0x3B, 0xF8E39, 0x6F9 },
+       [OLYMPUS_LUT_CHAN_535500_IDX] = { 21420, 0x1, 0x3B, 0x100000, 0x6F9 },
+       [OLYMPUS_LUT_CHAN_535625_IDX] = { 21425, 0x1, 0x3B, 0x1071C7, 0x6F9 },
+       [OLYMPUS_LUT_CHAN_535750_IDX] = { 21430, 0x1, 0x3B, 0x10E38E, 0x6FA },
+       [OLYMPUS_LUT_CHAN_535875_IDX] = { 21435, 0x1, 0x3B, 0x115555, 0x6FA },
+       [OLYMPUS_LUT_CHAN_536000_IDX] = { 21440, 0x1, 0x3B, 0x11C71C, 0x6FB },
+       [OLYMPUS_LUT_CHAN_536125_IDX] = { 21445, 0x1, 0x3B, 0x1238E4, 0x6FB },
+       [OLYMPUS_LUT_CHAN_536250_IDX] = { 21450, 0x1, 0x3B, 0x12AAAB, 0x6FC },
+       [OLYMPUS_LUT_CHAN_536375_IDX] = { 21455, 0x1, 0x3B, 0x131C72, 0x6FC },
+       [OLYMPUS_LUT_CHAN_536500_IDX] = { 21460, 0x1, 0x3B, 0x138E39, 0x6FC },
+       [OLYMPUS_LUT_CHAN_536625_IDX] = { 21465, 0x1, 0x3B, 0x140000, 0x6FD },
+       [OLYMPUS_LUT_CHAN_536750_IDX] = { 21470, 0x1, 0x3B, 0x1471C7, 0x6FD },
+       [OLYMPUS_LUT_CHAN_536875_IDX] = { 21475, 0x1, 0x3B, 0x14E38E, 0x6FE },
+       [OLYMPUS_LUT_CHAN_537000_IDX] = { 21480, 0x1, 0x3B, 0x155555, 0x6FE },
+       [OLYMPUS_LUT_CHAN_537125_IDX] = { 21485, 0x1, 0x3B, 0x15C71C, 0x6FE },
+       [OLYMPUS_LUT_CHAN_537250_IDX] = { 21490, 0x1, 0x3B, 0x1638E4, 0x6FF },
+       [OLYMPUS_LUT_CHAN_537375_IDX] = { 21495, 0x1, 0x3B, 0x16AAAB, 0x6FF },
+       [OLYMPUS_LUT_CHAN_537500_IDX] = { 21500, 0x1, 0x3B, 0x171C72, 0x700 },
+       [OLYMPUS_LUT_CHAN_537625_IDX] = { 21505, 0x1, 0x3B, 0x178E39, 0x700 },
+       [OLYMPUS_LUT_CHAN_537750_IDX] = { 21510, 0x1, 0x3B, 0x180000, 0x701 },
+       [OLYMPUS_LUT_CHAN_537875_IDX] = { 21515, 0x1, 0x3B, 0x1871C7, 0x701 },
+       [OLYMPUS_LUT_CHAN_538000_IDX] = { 21520, 0x1, 0x3B, 0x18E38E, 0x701 },
+       [OLYMPUS_LUT_CHAN_538125_IDX] = { 21525, 0x1, 0x3B, 0x195555, 0x702 },
+       [OLYMPUS_LUT_CHAN_538250_IDX] = { 21530, 0x1, 0x3B, 0x19C71C, 0x702 },
+       [OLYMPUS_LUT_CHAN_538375_IDX] = { 21535, 0x1, 0x3B, 0x1A38E4, 0x703 },
+       [OLYMPUS_LUT_CHAN_538500_IDX] = { 21540, 0x1, 0x3B, 0x1AAAAB, 0x703 },
+       [OLYMPUS_LUT_CHAN_538625_IDX] = { 21545, 0x1, 0x3B, 0x1B1C72, 0x703 },
+       [OLYMPUS_LUT_CHAN_538750_IDX] = { 21550, 0x1, 0x3B, 0x1B8E39, 0x704 },
+       [OLYMPUS_LUT_CHAN_538875_IDX] = { 21555, 0x1, 0x3B, 0x1C0000, 0x704 },
+       [OLYMPUS_LUT_CHAN_539000_IDX] = { 21560, 0x1, 0x3B, 0x1C71C7, 0x705 },
+       [OLYMPUS_LUT_CHAN_539125_IDX] = { 21565, 0x1, 0x3B, 0x1CE38E, 0x705 },
+       [OLYMPUS_LUT_CHAN_539250_IDX] = { 21570, 0x1, 0x3B, 0x1D5555, 0x706 },
+       [OLYMPUS_LUT_CHAN_539375_IDX] = { 21575, 0x1, 0x3B, 0x1DC71C, 0x706 },
+       [OLYMPUS_LUT_CHAN_539500_IDX] = { 21580, 0x1, 0x3B, 0x1E38E4, 0x706 },
+       [OLYMPUS_LUT_CHAN_539625_IDX] = { 21585, 0x1, 0x3B, 0x1EAAAB, 0x707 },
+       [OLYMPUS_LUT_CHAN_539750_IDX] = { 21590, 0x1, 0x3B, 0x1F1C72, 0x707 },
+       [OLYMPUS_LUT_CHAN_539875_IDX] = { 21595, 0x1, 0x3B, 0x1F8E39, 0x708 },
+       [OLYMPUS_LUT_CHAN_540000_IDX] = { 21600, 0x1, 0x3C, 0x0, 0x708 },
+       [OLYMPUS_LUT_CHAN_540125_IDX] = { 21605, 0x1, 0x3C, 0x71C7, 0x708 },
+       [OLYMPUS_LUT_CHAN_540250_IDX] = { 21610, 0x1, 0x3C, 0xE38E, 0x709 },
+       [OLYMPUS_LUT_CHAN_540375_IDX] = { 21615, 0x1, 0x3C, 0x15555, 0x709 },
+       [OLYMPUS_LUT_CHAN_540500_IDX] = { 21620, 0x1, 0x3C, 0x1C71C, 0x70A },
+       [OLYMPUS_LUT_CHAN_540625_IDX] = { 21625, 0x1, 0x3C, 0x238E4, 0x70A },
+       [OLYMPUS_LUT_CHAN_540750_IDX] = { 21630, 0x1, 0x3C, 0x2AAAB, 0x70B },
+       [OLYMPUS_LUT_CHAN_540875_IDX] = { 21635, 0x1, 0x3C, 0x31C72, 0x70B },
+       [OLYMPUS_LUT_CHAN_541000_IDX] = { 21640, 0x1, 0x3C, 0x38E39, 0x70B },
+       [OLYMPUS_LUT_CHAN_541125_IDX] = { 21645, 0x1, 0x3C, 0x40000, 0x70C },
+       [OLYMPUS_LUT_CHAN_541250_IDX] = { 21650, 0x1, 0x3C, 0x471C7, 0x70C },
+       [OLYMPUS_LUT_CHAN_541375_IDX] = { 21655, 0x1, 0x3C, 0x4E38E, 0x70D },
+       [OLYMPUS_LUT_CHAN_541500_IDX] = { 21660, 0x1, 0x3C, 0x55555, 0x70D },
+       [OLYMPUS_LUT_CHAN_541625_IDX] = { 21665, 0x1, 0x3C, 0x5C71C, 0x70D },
+       [OLYMPUS_LUT_CHAN_541750_IDX] = { 21670, 0x1, 0x3C, 0x638E4, 0x70E },
+       [OLYMPUS_LUT_CHAN_541875_IDX] = { 21675, 0x1, 0x3C, 0x6AAAB, 0x70E },
+       [OLYMPUS_LUT_CHAN_542000_IDX] = { 21680, 0x1, 0x3C, 0x71C72, 0x70F },
+       [OLYMPUS_LUT_CHAN_542125_IDX] = { 21685, 0x1, 0x3C, 0x78E39, 0x70F },
+       [OLYMPUS_LUT_CHAN_542250_IDX] = { 21690, 0x1, 0x3C, 0x80000, 0x710 },
+       [OLYMPUS_LUT_CHAN_542375_IDX] = { 21695, 0x1, 0x3C, 0x871C7, 0x710 },
+       [OLYMPUS_LUT_CHAN_542500_IDX] = { 21700, 0x1, 0x3C, 0x8E38E, 0x710 },
+       [OLYMPUS_LUT_CHAN_542625_IDX] = { 21705, 0x1, 0x3C, 0x95555, 0x711 },
+       [OLYMPUS_LUT_CHAN_542750_IDX] = { 21710, 0x1, 0x3C, 0x9C71C, 0x711 },
+       [OLYMPUS_LUT_CHAN_542875_IDX] = { 21715, 0x1, 0x3C, 0xA38E4, 0x712 },
+       [OLYMPUS_LUT_CHAN_543000_IDX] = { 21720, 0x1, 0x3C, 0xAAAAB, 0x712 },
+       [OLYMPUS_LUT_CHAN_543125_IDX] = { 21725, 0x1, 0x3C, 0xB1C72, 0x712 },
+       [OLYMPUS_LUT_CHAN_543250_IDX] = { 21730, 0x1, 0x3C, 0xB8E39, 0x713 },
+       [OLYMPUS_LUT_CHAN_543375_IDX] = { 21735, 0x1, 0x3C, 0xC0000, 0x713 },
+       [OLYMPUS_LUT_CHAN_543500_IDX] = { 21740, 0x1, 0x3C, 0xC71C7, 0x714 },
+       [OLYMPUS_LUT_CHAN_543625_IDX] = { 21745, 0x1, 0x3C, 0xCE38E, 0x714 },
+       [OLYMPUS_LUT_CHAN_543750_IDX] = { 21750, 0x1, 0x3C, 0xD5555, 0x715 },
+       [OLYMPUS_LUT_CHAN_543875_IDX] = { 21755, 0x1, 0x3C, 0xDC71C, 0x715 },
+       [OLYMPUS_LUT_CHAN_544000_IDX] = { 21760, 0x1, 0x3C, 0xE38E4, 0x715 },
+       [OLYMPUS_LUT_CHAN_544125_IDX] = { 21765, 0x1, 0x3C, 0xEAAAB, 0x716 },
+       [OLYMPUS_LUT_CHAN_544250_IDX] = { 21770, 0x1, 0x3C, 0xF1C72, 0x716 },
+       [OLYMPUS_LUT_CHAN_544375_IDX] = { 21775, 0x1, 0x3C, 0xF8E39, 0x717 },
+       [OLYMPUS_LUT_CHAN_544500_IDX] = { 21780, 0x1, 0x3C, 0x100000, 0x717 },
+       [OLYMPUS_LUT_CHAN_544625_IDX] = { 21785, 0x1, 0x3C, 0x1071C7, 0x717 },
+       [OLYMPUS_LUT_CHAN_544750_IDX] = { 21790, 0x1, 0x3C, 0x10E38E, 0x718 },
+       [OLYMPUS_LUT_CHAN_544875_IDX] = { 21795, 0x1, 0x3C, 0x115555, 0x718 },
+       [OLYMPUS_LUT_CHAN_545000_IDX] = { 21800, 0x1, 0x3C, 0x11C71C, 0x719 },
+       [OLYMPUS_LUT_CHAN_545125_IDX] = { 21805, 0x1, 0x3C, 0x1238E4, 0x719 },
+       [OLYMPUS_LUT_CHAN_545250_IDX] = { 21810, 0x1, 0x3C, 0x12AAAB, 0x71A },
+       [OLYMPUS_LUT_CHAN_545375_IDX] = { 21815, 0x1, 0x3C, 0x131C72, 0x71A },
+       [OLYMPUS_LUT_CHAN_545500_IDX] = { 21820, 0x1, 0x3C, 0x138E39, 0x71A },
+       [OLYMPUS_LUT_CHAN_545625_IDX] = { 21825, 0x1, 0x3C, 0x140000, 0x71B },
+       [OLYMPUS_LUT_CHAN_545750_IDX] = { 21830, 0x1, 0x3C, 0x1471C7, 0x71B },
+       [OLYMPUS_LUT_CHAN_545875_IDX] = { 21835, 0x1, 0x3C, 0x14E38E, 0x71C },
+       [OLYMPUS_LUT_CHAN_546000_IDX] = { 21840, 0x1, 0x3C, 0x155555, 0x71C },
+       [OLYMPUS_LUT_CHAN_546125_IDX] = { 21845, 0x1, 0x3C, 0x15C71C, 0x71C },
+       [OLYMPUS_LUT_CHAN_546250_IDX] = { 21850, 0x1, 0x3C, 0x1638E4, 0x71D },
+       [OLYMPUS_LUT_CHAN_546375_IDX] = { 21855, 0x1, 0x3C, 0x16AAAB, 0x71D },
+       [OLYMPUS_LUT_CHAN_546500_IDX] = { 21860, 0x1, 0x3C, 0x171C72, 0x71E },
+       [OLYMPUS_LUT_CHAN_546625_IDX] = { 21865, 0x1, 0x3C, 0x178E39, 0x71E },
+       [OLYMPUS_LUT_CHAN_546750_IDX] = { 21870, 0x1, 0x3C, 0x180000, 0x71F },
+       [OLYMPUS_LUT_CHAN_546875_IDX] = { 21875, 0x1, 0x3C, 0x1871C7, 0x71F },
+       [OLYMPUS_LUT_CHAN_547000_IDX] = { 21880, 0x1, 0x3C, 0x18E38E, 0x71F },
+       [OLYMPUS_LUT_CHAN_547125_IDX] = { 21885, 0x1, 0x3C, 0x195555, 0x720 },
+       [OLYMPUS_LUT_CHAN_547250_IDX] = { 21890, 0x1, 0x3C, 0x19C71C, 0x720 },
+       [OLYMPUS_LUT_CHAN_547375_IDX] = { 21895, 0x1, 0x3C, 0x1A38E4, 0x721 },
+       [OLYMPUS_LUT_CHAN_547500_IDX] = { 21900, 0x1, 0x3C, 0x1AAAAB, 0x721 },
+       [OLYMPUS_LUT_CHAN_547625_IDX] = { 21905, 0x1, 0x3C, 0x1B1C72, 0x721 },
+       [OLYMPUS_LUT_CHAN_547750_IDX] = { 21910, 0x1, 0x3C, 0x1B8E39, 0x722 },
+       [OLYMPUS_LUT_CHAN_547875_IDX] = { 21915, 0x1, 0x3C, 0x1C0000, 0x722 },
+       [OLYMPUS_LUT_CHAN_548000_IDX] = { 21920, 0x1, 0x3C, 0x1C71C7, 0x723 },
+       [OLYMPUS_LUT_CHAN_548125_IDX] = { 21925, 0x1, 0x3C, 0x1CE38E, 0x723 },
+       [OLYMPUS_LUT_CHAN_548250_IDX] = { 21930, 0x1, 0x3C, 0x1D5555, 0x724 },
+       [OLYMPUS_LUT_CHAN_548375_IDX] = { 21935, 0x1, 0x3C, 0x1DC71C, 0x724 },
+       [OLYMPUS_LUT_CHAN_548500_IDX] = { 21940, 0x1, 0x3C, 0x1E38E4, 0x724 },
+       [OLYMPUS_LUT_CHAN_548625_IDX] = { 21945, 0x1, 0x3C, 0x1EAAAB, 0x725 },
+       [OLYMPUS_LUT_CHAN_548750_IDX] = { 21950, 0x1, 0x3C, 0x1F1C72, 0x725 },
+       [OLYMPUS_LUT_CHAN_548875_IDX] = { 21955, 0x1, 0x3C, 0x1F8E39, 0x726 },
+       [OLYMPUS_LUT_CHAN_549000_IDX] = { 21960, 0x1, 0x3D, 0x0, 0x726 },
+       [OLYMPUS_LUT_CHAN_549125_IDX] = { 21965, 0x1, 0x3D, 0x71C7, 0x726 },
+       [OLYMPUS_LUT_CHAN_549250_IDX] = { 21970, 0x1, 0x3D, 0xE38E, 0x727 },
+       [OLYMPUS_LUT_CHAN_549375_IDX] = { 21975, 0x1, 0x3D, 0x15555, 0x727 },
+       [OLYMPUS_LUT_CHAN_549500_IDX] = { 21980, 0x1, 0x3D, 0x1C71C, 0x728 },
+       [OLYMPUS_LUT_CHAN_549625_IDX] = { 21985, 0x1, 0x3D, 0x238E4, 0x728 },
+       [OLYMPUS_LUT_CHAN_549750_IDX] = { 21990, 0x1, 0x3D, 0x2AAAB, 0x729 },
+       [OLYMPUS_LUT_CHAN_549875_IDX] = { 21995, 0x1, 0x3D, 0x31C72, 0x729 },
+       [OLYMPUS_LUT_CHAN_550000_IDX] = { 22000, 0x1, 0x3D, 0x38E39, 0x729 },
+       [OLYMPUS_LUT_CHAN_550125_IDX] = { 22005, 0x1, 0x3D, 0x40000, 0x72A },
+       [OLYMPUS_LUT_CHAN_550250_IDX] = { 22010, 0x1, 0x3D, 0x471C7, 0x72A },
+       [OLYMPUS_LUT_CHAN_550375_IDX] = { 22015, 0x1, 0x3D, 0x4E38E, 0x72B },
+       [OLYMPUS_LUT_CHAN_550500_IDX] = { 22020, 0x1, 0x3D, 0x55555, 0x72B },
+       [OLYMPUS_LUT_CHAN_550625_IDX] = { 22025, 0x1, 0x3D, 0x5C71C, 0x72B },
+       [OLYMPUS_LUT_CHAN_550750_IDX] = { 22030, 0x1, 0x3D, 0x638E4, 0x72C },
+       [OLYMPUS_LUT_CHAN_550875_IDX] = { 22035, 0x1, 0x3D, 0x6AAAB, 0x72C },
+       [OLYMPUS_LUT_CHAN_551000_IDX] = { 22040, 0x1, 0x3D, 0x71C72, 0x72D },
+       [OLYMPUS_LUT_CHAN_551125_IDX] = { 22045, 0x1, 0x3D, 0x78E39, 0x72D },
+       [OLYMPUS_LUT_CHAN_551250_IDX] = { 22050, 0x1, 0x3D, 0x80000, 0x72E },
+       [OLYMPUS_LUT_CHAN_551375_IDX] = { 22055, 0x1, 0x3D, 0x871C7, 0x72E },
+       [OLYMPUS_LUT_CHAN_551500_IDX] = { 22060, 0x1, 0x3D, 0x8E38E, 0x72E },
+       [OLYMPUS_LUT_CHAN_551625_IDX] = { 22065, 0x1, 0x3D, 0x95555, 0x72F },
+       [OLYMPUS_LUT_CHAN_551750_IDX] = { 22070, 0x1, 0x3D, 0x9C71C, 0x72F },
+       [OLYMPUS_LUT_CHAN_551875_IDX] = { 22075, 0x1, 0x3D, 0xA38E4, 0x730 },
+       [OLYMPUS_LUT_CHAN_552000_IDX] = { 22080, 0x1, 0x3D, 0xAAAAB, 0x730 },
+       [OLYMPUS_LUT_CHAN_552125_IDX] = { 22085, 0x1, 0x3D, 0xB1C72, 0x730 },
+       [OLYMPUS_LUT_CHAN_552250_IDX] = { 22090, 0x1, 0x3D, 0xB8E39, 0x731 },
+       [OLYMPUS_LUT_CHAN_552375_IDX] = { 22095, 0x1, 0x3D, 0xC0000, 0x731 },
+       [OLYMPUS_LUT_CHAN_552500_IDX] = { 22100, 0x1, 0x3D, 0xC71C7, 0x732 },
+       [OLYMPUS_LUT_CHAN_552625_IDX] = { 22105, 0x1, 0x3D, 0xCE38E, 0x732 },
+       [OLYMPUS_LUT_CHAN_552750_IDX] = { 22110, 0x1, 0x3D, 0xD5555, 0x733 },
+       [OLYMPUS_LUT_CHAN_552875_IDX] = { 22115, 0x1, 0x3D, 0xDC71C, 0x733 },
+       [OLYMPUS_LUT_CHAN_553000_IDX] = { 22120, 0x1, 0x3D, 0xE38E4, 0x733 },
+       [OLYMPUS_LUT_CHAN_553125_IDX] = { 22125, 0x1, 0x3D, 0xEAAAB, 0x734 },
+       [OLYMPUS_LUT_CHAN_553250_IDX] = { 22130, 0x1, 0x3D, 0xF1C72, 0x734 },
+       [OLYMPUS_LUT_CHAN_553375_IDX] = { 22135, 0x1, 0x3D, 0xF8E39, 0x735 },
+       [OLYMPUS_LUT_CHAN_553500_IDX] = { 22140, 0x1, 0x3D, 0x100000, 0x735 },
+       [OLYMPUS_LUT_CHAN_553625_IDX] = { 22145, 0x1, 0x3D, 0x1071C7, 0x735 },
+       [OLYMPUS_LUT_CHAN_553750_IDX] = { 22150, 0x1, 0x3D, 0x10E38E, 0x736 },
+       [OLYMPUS_LUT_CHAN_553875_IDX] = { 22155, 0x1, 0x3D, 0x115555, 0x736 },
+       [OLYMPUS_LUT_CHAN_554000_IDX] = { 22160, 0x1, 0x3D, 0x11C71C, 0x737 },
+       [OLYMPUS_LUT_CHAN_554125_IDX] = { 22165, 0x1, 0x3D, 0x1238E4, 0x737 },
+       [OLYMPUS_LUT_CHAN_554250_IDX] = { 22170, 0x1, 0x3D, 0x12AAAB, 0x738 },
+       [OLYMPUS_LUT_CHAN_554375_IDX] = { 22175, 0x1, 0x3D, 0x131C72, 0x738 },
+       [OLYMPUS_LUT_CHAN_554500_IDX] = { 22180, 0x1, 0x3D, 0x138E39, 0x738 },
+       [OLYMPUS_LUT_CHAN_554625_IDX] = { 22185, 0x1, 0x3D, 0x140000, 0x739 },
+       [OLYMPUS_LUT_CHAN_554750_IDX] = { 22190, 0x1, 0x3D, 0x1471C7, 0x739 },
+       [OLYMPUS_LUT_CHAN_554875_IDX] = { 22195, 0x1, 0x3D, 0x14E38E, 0x73A },
+       [OLYMPUS_LUT_CHAN_555000_IDX] = { 22200, 0x1, 0x3D, 0x155555, 0x73A },
+       [OLYMPUS_LUT_CHAN_555125_IDX] = { 22205, 0x1, 0x3D, 0x15C71C, 0x73A },
+       [OLYMPUS_LUT_CHAN_555250_IDX] = { 22210, 0x1, 0x3D, 0x1638E4, 0x73B },
+       [OLYMPUS_LUT_CHAN_555375_IDX] = { 22215, 0x1, 0x3D, 0x16AAAB, 0x73B },
+       [OLYMPUS_LUT_CHAN_555500_IDX] = { 22220, 0x1, 0x3D, 0x171C72, 0x73C },
+       [OLYMPUS_LUT_CHAN_555625_IDX] = { 22225, 0x1, 0x3D, 0x178E39, 0x73C },
+       [OLYMPUS_LUT_CHAN_555750_IDX] = { 22230, 0x1, 0x3D, 0x180000, 0x73D },
+       [OLYMPUS_LUT_CHAN_555875_IDX] = { 22235, 0x1, 0x3D, 0x1871C7, 0x73D },
+       [OLYMPUS_LUT_CHAN_556000_IDX] = { 22240, 0x1, 0x3D, 0x18E38E, 0x73D },
+       [OLYMPUS_LUT_CHAN_556125_IDX] = { 22245, 0x1, 0x3D, 0x195555, 0x73E },
+       [OLYMPUS_LUT_CHAN_556250_IDX] = { 22250, 0x1, 0x3D, 0x19C71C, 0x73E },
+       [OLYMPUS_LUT_CHAN_556375_IDX] = { 22255, 0x1, 0x3D, 0x1A38E4, 0x73F },
+       [OLYMPUS_LUT_CHAN_556500_IDX] = { 22260, 0x1, 0x3D, 0x1AAAAB, 0x73F },
+       [OLYMPUS_LUT_CHAN_556625_IDX] = { 22265, 0x1, 0x3D, 0x1B1C72, 0x73F },
+       [OLYMPUS_LUT_CHAN_556750_IDX] = { 22270, 0x1, 0x3D, 0x1B8E39, 0x740 },
+       [OLYMPUS_LUT_CHAN_556875_IDX] = { 22275, 0x1, 0x3D, 0x1C0000, 0x740 },
+       [OLYMPUS_LUT_CHAN_557000_IDX] = { 22280, 0x1, 0x3D, 0x1C71C7, 0x741 },
+       [OLYMPUS_LUT_CHAN_557125_IDX] = { 22285, 0x1, 0x3D, 0x1CE38E, 0x741 },
+       [OLYMPUS_LUT_CHAN_557250_IDX] = { 22290, 0x1, 0x3D, 0x1D5555, 0x742 },
+       [OLYMPUS_LUT_CHAN_557375_IDX] = { 22295, 0x1, 0x3D, 0x1DC71C, 0x742 },
+       [OLYMPUS_LUT_CHAN_557500_IDX] = { 22300, 0x1, 0x3D, 0x1E38E4, 0x742 },
+       [OLYMPUS_LUT_CHAN_557625_IDX] = { 22305, 0x1, 0x3D, 0x1EAAAB, 0x743 },
+       [OLYMPUS_LUT_CHAN_557750_IDX] = { 22310, 0x1, 0x3D, 0x1F1C72, 0x743 },
+       [OLYMPUS_LUT_CHAN_557875_IDX] = { 22315, 0x1, 0x3D, 0x1F8E39, 0x744 },
+       [OLYMPUS_LUT_CHAN_558000_IDX] = { 22320, 0x1, 0x3E, 0x0, 0x744 },
+       [OLYMPUS_LUT_CHAN_558125_IDX] = { 22325, 0x1, 0x3E, 0x71C7, 0x744 },
+       [OLYMPUS_LUT_CHAN_558250_IDX] = { 22330, 0x1, 0x3E, 0xE38E, 0x745 },
+       [OLYMPUS_LUT_CHAN_558375_IDX] = { 22335, 0x1, 0x3E, 0x15555, 0x745 },
+       [OLYMPUS_LUT_CHAN_558500_IDX] = { 22340, 0x1, 0x3E, 0x1C71C, 0x746 },
+       [OLYMPUS_LUT_CHAN_558625_IDX] = { 22345, 0x1, 0x3E, 0x238E4, 0x746 },
+       [OLYMPUS_LUT_CHAN_558750_IDX] = { 22350, 0x1, 0x3E, 0x2AAAB, 0x747 },
+       [OLYMPUS_LUT_CHAN_558875_IDX] = { 22355, 0x1, 0x3E, 0x31C72, 0x747 },
+       [OLYMPUS_LUT_CHAN_559000_IDX] = { 22360, 0x1, 0x3E, 0x38E39, 0x747 },
+       [OLYMPUS_LUT_CHAN_559125_IDX] = { 22365, 0x1, 0x3E, 0x40000, 0x748 },
+       [OLYMPUS_LUT_CHAN_559250_IDX] = { 22370, 0x1, 0x3E, 0x471C7, 0x748 },
+       [OLYMPUS_LUT_CHAN_559375_IDX] = { 22375, 0x1, 0x3E, 0x4E38E, 0x749 },
+       [OLYMPUS_LUT_CHAN_559500_IDX] = { 22380, 0x1, 0x3E, 0x55555, 0x749 },
+       [OLYMPUS_LUT_CHAN_559625_IDX] = { 22385, 0x1, 0x3E, 0x5C71C, 0x749 },
+       [OLYMPUS_LUT_CHAN_559750_IDX] = { 22390, 0x1, 0x3E, 0x638E4, 0x74A },
+       [OLYMPUS_LUT_CHAN_559875_IDX] = { 22395, 0x1, 0x3E, 0x6AAAB, 0x74A },
+       [OLYMPUS_LUT_CHAN_560000_IDX] = { 22400, 0x1, 0x3E, 0x71C72, 0x74B },
+       [OLYMPUS_LUT_CHAN_560125_IDX] = { 22405, 0x1, 0x3E, 0x78E39, 0x74B },
+       [OLYMPUS_LUT_CHAN_560250_IDX] = { 22410, 0x1, 0x3E, 0x80000, 0x74C },
+       [OLYMPUS_LUT_CHAN_560375_IDX] = { 22415, 0x1, 0x3E, 0x871C7, 0x74C },
+       [OLYMPUS_LUT_CHAN_560500_IDX] = { 22420, 0x1, 0x3E, 0x8E38E, 0x74C },
+       [OLYMPUS_LUT_CHAN_560625_IDX] = { 22425, 0x1, 0x3E, 0x95555, 0x74D },
+       [OLYMPUS_LUT_CHAN_560750_IDX] = { 22430, 0x1, 0x3E, 0x9C71C, 0x74D },
+       [OLYMPUS_LUT_CHAN_560875_IDX] = { 22435, 0x1, 0x3E, 0xA38E4, 0x74E },
+       [OLYMPUS_LUT_CHAN_561000_IDX] = { 22440, 0x1, 0x3E, 0xAAAAB, 0x74E },
+       [OLYMPUS_LUT_CHAN_561125_IDX] = { 22445, 0x1, 0x3E, 0xB1C72, 0x74E },
+       [OLYMPUS_LUT_CHAN_561250_IDX] = { 22450, 0x1, 0x3E, 0xB8E39, 0x74F },
+       [OLYMPUS_LUT_CHAN_561375_IDX] = { 22455, 0x1, 0x3E, 0xC0000, 0x74F },
+       [OLYMPUS_LUT_CHAN_561500_IDX] = { 22460, 0x1, 0x3E, 0xC71C7, 0x750 },
+       [OLYMPUS_LUT_CHAN_561625_IDX] = { 22465, 0x1, 0x3E, 0xCE38E, 0x750 },
+       [OLYMPUS_LUT_CHAN_561750_IDX] = { 22470, 0x1, 0x3E, 0xD5555, 0x751 },
+       [OLYMPUS_LUT_CHAN_561875_IDX] = { 22475, 0x1, 0x3E, 0xDC71C, 0x751 },
+       [OLYMPUS_LUT_CHAN_562000_IDX] = { 22480, 0x1, 0x3E, 0xE38E4, 0x751 },
+       [OLYMPUS_LUT_CHAN_562125_IDX] = { 22485, 0x1, 0x3E, 0xEAAAB, 0x752 },
+       [OLYMPUS_LUT_CHAN_562250_IDX] = { 22490, 0x1, 0x3E, 0xF1C72, 0x752 },
+       [OLYMPUS_LUT_CHAN_562375_IDX] = { 22495, 0x1, 0x3E, 0xF8E39, 0x753 },
+       [OLYMPUS_LUT_CHAN_562500_IDX] = { 22500, 0x1, 0x3E, 0x100000, 0x753 },
+       [OLYMPUS_LUT_CHAN_562625_IDX] = { 22505, 0x1, 0x3E, 0x1071C7, 0x753 },
+       [OLYMPUS_LUT_CHAN_562750_IDX] = { 22510, 0x1, 0x3E, 0x10E38E, 0x754 },
+       [OLYMPUS_LUT_CHAN_562875_IDX] = { 22515, 0x1, 0x3E, 0x115555, 0x754 },
+       [OLYMPUS_LUT_CHAN_563000_IDX] = { 22520, 0x1, 0x3E, 0x11C71C, 0x755 },
+       [OLYMPUS_LUT_CHAN_563125_IDX] = { 22525, 0x1, 0x3E, 0x1238E4, 0x755 },
+       [OLYMPUS_LUT_CHAN_563250_IDX] = { 22530, 0x1, 0x3E, 0x12AAAB, 0x756 },
+       [OLYMPUS_LUT_CHAN_563375_IDX] = { 22535, 0x1, 0x3E, 0x131C72, 0x756 },
+       [OLYMPUS_LUT_CHAN_563500_IDX] = { 22540, 0x1, 0x3E, 0x138E39, 0x756 },
+       [OLYMPUS_LUT_CHAN_563625_IDX] = { 22545, 0x1, 0x3E, 0x140000, 0x757 },
+       [OLYMPUS_LUT_CHAN_563750_IDX] = { 22550, 0x1, 0x3E, 0x1471C7, 0x757 },
+       [OLYMPUS_LUT_CHAN_563875_IDX] = { 22555, 0x1, 0x3E, 0x14E38E, 0x758 },
+       [OLYMPUS_LUT_CHAN_564000_IDX] = { 22560, 0x1, 0x3E, 0x155555, 0x758 },
+       [OLYMPUS_LUT_CHAN_564125_IDX] = { 22565, 0x1, 0x3E, 0x15C71C, 0x758 },
+       [OLYMPUS_LUT_CHAN_564250_IDX] = { 22570, 0x1, 0x3E, 0x1638E4, 0x759 },
+       [OLYMPUS_LUT_CHAN_564375_IDX] = { 22575, 0x1, 0x3E, 0x16AAAB, 0x759 },
+       [OLYMPUS_LUT_CHAN_564500_IDX] = { 22580, 0x1, 0x3E, 0x171C72, 0x75A },
+       [OLYMPUS_LUT_CHAN_564625_IDX] = { 22585, 0x1, 0x3E, 0x178E39, 0x75A },
+       [OLYMPUS_LUT_CHAN_564750_IDX] = { 22590, 0x1, 0x3E, 0x180000, 0x75B },
+       [OLYMPUS_LUT_CHAN_564875_IDX] = { 22595, 0x1, 0x3E, 0x1871C7, 0x75B },
+       [OLYMPUS_LUT_CHAN_565000_IDX] = { 22600, 0x1, 0x3E, 0x18E38E, 0x75B },
+       [OLYMPUS_LUT_CHAN_565125_IDX] = { 22605, 0x1, 0x3E, 0x195555, 0x75C },
+       [OLYMPUS_LUT_CHAN_565250_IDX] = { 22610, 0x1, 0x3E, 0x19C71C, 0x75C },
+       [OLYMPUS_LUT_CHAN_565375_IDX] = { 22615, 0x1, 0x3E, 0x1A38E4, 0x75D },
+       [OLYMPUS_LUT_CHAN_565500_IDX] = { 22620, 0x1, 0x3E, 0x1AAAAB, 0x75D },
+       [OLYMPUS_LUT_CHAN_565625_IDX] = { 22625, 0x1, 0x3E, 0x1B1C72, 0x75D },
+       [OLYMPUS_LUT_CHAN_565750_IDX] = { 22630, 0x1, 0x3E, 0x1B8E39, 0x75E },
+       [OLYMPUS_LUT_CHAN_565875_IDX] = { 22635, 0x1, 0x3E, 0x1C0000, 0x75E },
+       [OLYMPUS_LUT_CHAN_566000_IDX] = { 22640, 0x1, 0x3E, 0x1C71C7, 0x75F },
+       [OLYMPUS_LUT_CHAN_566125_IDX] = { 22645, 0x1, 0x3E, 0x1CE38E, 0x75F },
+       [OLYMPUS_LUT_CHAN_566250_IDX] = { 22650, 0x1, 0x3E, 0x1D5555, 0x760 },
+       [OLYMPUS_LUT_CHAN_566375_IDX] = { 22655, 0x1, 0x3E, 0x1DC71C, 0x760 },
+       [OLYMPUS_LUT_CHAN_566500_IDX] = { 22660, 0x1, 0x3E, 0x1E38E4, 0x760 },
+       [OLYMPUS_LUT_CHAN_566625_IDX] = { 22665, 0x1, 0x3E, 0x1EAAAB, 0x761 },
+       [OLYMPUS_LUT_CHAN_566750_IDX] = { 22670, 0x1, 0x3E, 0x1F1C72, 0x761 },
+       [OLYMPUS_LUT_CHAN_566875_IDX] = { 22675, 0x1, 0x3E, 0x1F8E39, 0x762 },
+       [OLYMPUS_LUT_CHAN_567000_IDX] = { 22680, 0x1, 0x3F, 0x0, 0x762 },
+       [OLYMPUS_LUT_CHAN_567125_IDX] = { 22685, 0x1, 0x3F, 0x71C7, 0x762 },
+       [OLYMPUS_LUT_CHAN_567250_IDX] = { 22690, 0x1, 0x3F, 0xE38E, 0x763 },
+       [OLYMPUS_LUT_CHAN_567375_IDX] = { 22695, 0x1, 0x3F, 0x15555, 0x763 },
+       [OLYMPUS_LUT_CHAN_567500_IDX] = { 22700, 0x1, 0x3F, 0x1C71C, 0x764 },
+       [OLYMPUS_LUT_CHAN_567625_IDX] = { 22705, 0x1, 0x3F, 0x238E4, 0x764 },
+       [OLYMPUS_LUT_CHAN_567750_IDX] = { 22710, 0x1, 0x3F, 0x2AAAB, 0x765 },
+       [OLYMPUS_LUT_CHAN_567875_IDX] = { 22715, 0x1, 0x3F, 0x31C72, 0x765 },
+       [OLYMPUS_LUT_CHAN_568000_IDX] = { 22720, 0x1, 0x3F, 0x38E39, 0x765 },
+       [OLYMPUS_LUT_CHAN_568125_IDX] = { 22725, 0x1, 0x3F, 0x40000, 0x766 },
+       [OLYMPUS_LUT_CHAN_568250_IDX] = { 22730, 0x1, 0x3F, 0x471C7, 0x766 },
+       [OLYMPUS_LUT_CHAN_568375_IDX] = { 22735, 0x1, 0x3F, 0x4E38E, 0x767 },
+       [OLYMPUS_LUT_CHAN_568500_IDX] = { 22740, 0x1, 0x3F, 0x55555, 0x767 },
+       [OLYMPUS_LUT_CHAN_568625_IDX] = { 22745, 0x1, 0x3F, 0x5C71C, 0x767 },
+       [OLYMPUS_LUT_CHAN_568750_IDX] = { 22750, 0x1, 0x3F, 0x638E4, 0x768 },
+       [OLYMPUS_LUT_CHAN_568875_IDX] = { 22755, 0x1, 0x3F, 0x6AAAB, 0x768 },
+       [OLYMPUS_LUT_CHAN_569000_IDX] = { 22760, 0x1, 0x3F, 0x71C72, 0x769 },
+       [OLYMPUS_LUT_CHAN_569125_IDX] = { 22765, 0x1, 0x3F, 0x78E39, 0x769 },
+       [OLYMPUS_LUT_CHAN_569250_IDX] = { 22770, 0x1, 0x3F, 0x80000, 0x76A },
+       [OLYMPUS_LUT_CHAN_569375_IDX] = { 22775, 0x1, 0x3F, 0x871C7, 0x76A },
+       [OLYMPUS_LUT_CHAN_569500_IDX] = { 22780, 0x1, 0x3F, 0x8E38E, 0x76A },
+       [OLYMPUS_LUT_CHAN_569625_IDX] = { 22785, 0x1, 0x3F, 0x95555, 0x76B },
+       [OLYMPUS_LUT_CHAN_569750_IDX] = { 22790, 0x1, 0x3F, 0x9C71C, 0x76B },
+       [OLYMPUS_LUT_CHAN_569875_IDX] = { 22795, 0x1, 0x3F, 0xA38E4, 0x76C },
+       [OLYMPUS_LUT_CHAN_570000_IDX] = { 22800, 0x1, 0x3F, 0xAAAAB, 0x76C },
+       [OLYMPUS_LUT_CHAN_570125_IDX] = { 22805, 0x1, 0x3F, 0xB1C72, 0x76C },
+       [OLYMPUS_LUT_CHAN_570250_IDX] = { 22810, 0x1, 0x3F, 0xB8E39, 0x76D },
+       [OLYMPUS_LUT_CHAN_570375_IDX] = { 22815, 0x1, 0x3F, 0xC0000, 0x76D },
+       [OLYMPUS_LUT_CHAN_570500_IDX] = { 22820, 0x1, 0x3F, 0xC71C7, 0x76E },
+       [OLYMPUS_LUT_CHAN_570625_IDX] = { 22825, 0x1, 0x3F, 0xCE38E, 0x76E },
+       [OLYMPUS_LUT_CHAN_570750_IDX] = { 22830, 0x1, 0x3F, 0xD5555, 0x76F },
+       [OLYMPUS_LUT_CHAN_570875_IDX] = { 22835, 0x1, 0x3F, 0xDC71C, 0x76F },
+       [OLYMPUS_LUT_CHAN_571000_IDX] = { 22840, 0x1, 0x3F, 0xE38E4, 0x76F },
+       [OLYMPUS_LUT_CHAN_571125_IDX] = { 22845, 0x1, 0x3F, 0xEAAAB, 0x770 },
+       [OLYMPUS_LUT_CHAN_571250_IDX] = { 22850, 0x1, 0x3F, 0xF1C72, 0x770 },
+       [OLYMPUS_LUT_CHAN_571375_IDX] = { 22855, 0x1, 0x3F, 0xF8E39, 0x771 },
+       [OLYMPUS_LUT_CHAN_571500_IDX] = { 22860, 0x1, 0x3F, 0x100000, 0x771 },
+       [OLYMPUS_LUT_CHAN_571625_IDX] = { 22865, 0x1, 0x3F, 0x1071C7, 0x771 },
+       [OLYMPUS_LUT_CHAN_571750_IDX] = { 22870, 0x1, 0x3F, 0x10E38E, 0x772 },
+       [OLYMPUS_LUT_CHAN_571875_IDX] = { 22875, 0x1, 0x3F, 0x115555, 0x772 },
+       [OLYMPUS_LUT_CHAN_572000_IDX] = { 22880, 0x1, 0x3F, 0x11C71C, 0x773 },
+       [OLYMPUS_LUT_CHAN_572125_IDX] = { 22885, 0x1, 0x3F, 0x1238E4, 0x773 },
+       [OLYMPUS_LUT_CHAN_572250_IDX] = { 22890, 0x1, 0x3F, 0x12AAAB, 0x774 },
+       [OLYMPUS_LUT_CHAN_572375_IDX] = { 22895, 0x1, 0x3F, 0x131C72, 0x774 },
+       [OLYMPUS_LUT_CHAN_572500_IDX] = { 22900, 0x1, 0x3F, 0x138E39, 0x774 },
+       [OLYMPUS_LUT_CHAN_572625_IDX] = { 22905, 0x1, 0x3F, 0x140000, 0x775 },
+       [OLYMPUS_LUT_CHAN_572750_IDX] = { 22910, 0x1, 0x3F, 0x1471C7, 0x775 },
+       [OLYMPUS_LUT_CHAN_572875_IDX] = { 22915, 0x1, 0x3F, 0x14E38E, 0x776 },
+       [OLYMPUS_LUT_CHAN_573000_IDX] = { 22920, 0x1, 0x3F, 0x155555, 0x776 },
+       [OLYMPUS_LUT_CHAN_573125_IDX] = { 22925, 0x1, 0x3F, 0x15C71C, 0x776 },
+       [OLYMPUS_LUT_CHAN_573250_IDX] = { 22930, 0x1, 0x3F, 0x1638E4, 0x777 },
+       [OLYMPUS_LUT_CHAN_573375_IDX] = { 22935, 0x1, 0x3F, 0x16AAAB, 0x777 },
+       [OLYMPUS_LUT_CHAN_573500_IDX] = { 22940, 0x1, 0x3F, 0x171C72, 0x778 },
+       [OLYMPUS_LUT_CHAN_573625_IDX] = { 22945, 0x1, 0x3F, 0x178E39, 0x778 },
+       [OLYMPUS_LUT_CHAN_573750_IDX] = { 22950, 0x1, 0x3F, 0x180000, 0x779 },
+       [OLYMPUS_LUT_CHAN_573875_IDX] = { 22955, 0x1, 0x3F, 0x1871C7, 0x779 },
+       [OLYMPUS_LUT_CHAN_574000_IDX] = { 22960, 0x1, 0x3F, 0x18E38E, 0x779 },
+       [OLYMPUS_LUT_CHAN_574125_IDX] = { 22965, 0x1, 0x3F, 0x195555, 0x77A },
+       [OLYMPUS_LUT_CHAN_574250_IDX] = { 22970, 0x1, 0x3F, 0x19C71C, 0x77A },
+       [OLYMPUS_LUT_CHAN_574375_IDX] = { 22975, 0x1, 0x3F, 0x1A38E4, 0x77B },
+       [OLYMPUS_LUT_CHAN_574500_IDX] = { 22980, 0x1, 0x3F, 0x1AAAAB, 0x77B },
+       [OLYMPUS_LUT_CHAN_574625_IDX] = { 22985, 0x1, 0x3F, 0x1B1C72, 0x77B },
+       [OLYMPUS_LUT_CHAN_574750_IDX] = { 22990, 0x1, 0x3F, 0x1B8E39, 0x77C },
+       [OLYMPUS_LUT_CHAN_574875_IDX] = { 22995, 0x1, 0x3F, 0x1C0000, 0x77C },
+       [OLYMPUS_LUT_CHAN_575000_IDX] = { 23000, 0x1, 0x3F, 0x1C71C7, 0x77D },
+       [OLYMPUS_LUT_CHAN_575125_IDX] = { 23005, 0x1, 0x3F, 0x1CE38E, 0x77D },
+       [OLYMPUS_LUT_CHAN_575250_IDX] = { 23010, 0x1, 0x3F, 0x1D5555, 0x77E },
+       [OLYMPUS_LUT_CHAN_575375_IDX] = { 23015, 0x1, 0x3F, 0x1DC71C, 0x77E },
+       [OLYMPUS_LUT_CHAN_575500_IDX] = { 23020, 0x1, 0x3F, 0x1E38E4, 0x77E },
+       [OLYMPUS_LUT_CHAN_575625_IDX] = { 23025, 0x1, 0x3F, 0x1EAAAB, 0x77F },
+       [OLYMPUS_LUT_CHAN_575750_IDX] = { 23030, 0x1, 0x3F, 0x1F1C72, 0x77F },
+       [OLYMPUS_LUT_CHAN_575875_IDX] = { 23035, 0x1, 0x3F, 0x1F8E39, 0x780 },
+       [OLYMPUS_LUT_CHAN_576000_IDX] = { 23040, 0x1, 0x40, 0x0, 0x780 },
+       [OLYMPUS_LUT_CHAN_576125_IDX] = { 23045, 0x1, 0x40, 0x71C7, 0x780 },
+       [OLYMPUS_LUT_CHAN_576250_IDX] = { 23050, 0x1, 0x40, 0xE38E, 0x781 },
+       [OLYMPUS_LUT_CHAN_576375_IDX] = { 23055, 0x1, 0x40, 0x15555, 0x781 },
+       [OLYMPUS_LUT_CHAN_576500_IDX] = { 23060, 0x1, 0x40, 0x1C71C, 0x782 },
+       [OLYMPUS_LUT_CHAN_576625_IDX] = { 23065, 0x1, 0x40, 0x238E4, 0x782 },
+       [OLYMPUS_LUT_CHAN_576750_IDX] = { 23070, 0x1, 0x40, 0x2AAAB, 0x783 },
+       [OLYMPUS_LUT_CHAN_576875_IDX] = { 23075, 0x1, 0x40, 0x31C72, 0x783 },
+       [OLYMPUS_LUT_CHAN_577000_IDX] = { 23080, 0x1, 0x40, 0x38E39, 0x783 },
+       [OLYMPUS_LUT_CHAN_577125_IDX] = { 23085, 0x1, 0x40, 0x40000, 0x784 },
+       [OLYMPUS_LUT_CHAN_577250_IDX] = { 23090, 0x1, 0x40, 0x471C7, 0x784 },
+       [OLYMPUS_LUT_CHAN_577375_IDX] = { 23095, 0x1, 0x40, 0x4E38E, 0x785 },
+       [OLYMPUS_LUT_CHAN_577500_IDX] = { 23100, 0x1, 0x40, 0x55555, 0x785 },
+       [OLYMPUS_LUT_CHAN_577625_IDX] = { 23105, 0x1, 0x40, 0x5C71C, 0x785 },
+       [OLYMPUS_LUT_CHAN_577750_IDX] = { 23110, 0x1, 0x40, 0x638E4, 0x786 },
+       [OLYMPUS_LUT_CHAN_577875_IDX] = { 23115, 0x1, 0x40, 0x6AAAB, 0x786 },
+       [OLYMPUS_LUT_CHAN_578000_IDX] = { 23120, 0x1, 0x40, 0x71C72, 0x787 },
+       [OLYMPUS_LUT_CHAN_578125_IDX] = { 23125, 0x1, 0x40, 0x78E39, 0x787 },
+       [OLYMPUS_LUT_CHAN_578250_IDX] = { 23130, 0x1, 0x40, 0x80000, 0x788 },
+       [OLYMPUS_LUT_CHAN_578375_IDX] = { 23135, 0x1, 0x40, 0x871C7, 0x788 },
+       [OLYMPUS_LUT_CHAN_578500_IDX] = { 23140, 0x1, 0x40, 0x8E38E, 0x788 },
+       [OLYMPUS_LUT_CHAN_578625_IDX] = { 23145, 0x1, 0x40, 0x95555, 0x789 },
+       [OLYMPUS_LUT_CHAN_578750_IDX] = { 23150, 0x1, 0x40, 0x9C71C, 0x789 },
+       [OLYMPUS_LUT_CHAN_578875_IDX] = { 23155, 0x1, 0x40, 0xA38E4, 0x78A },
+       [OLYMPUS_LUT_CHAN_579000_IDX] = { 23160, 0x1, 0x40, 0xAAAAB, 0x78A },
+       [OLYMPUS_LUT_CHAN_579125_IDX] = { 23165, 0x1, 0x40, 0xB1C72, 0x78A },
+       [OLYMPUS_LUT_CHAN_579250_IDX] = { 23170, 0x1, 0x40, 0xB8E39, 0x78B },
+       [OLYMPUS_LUT_CHAN_579375_IDX] = { 23175, 0x1, 0x40, 0xC0000, 0x78B },
+       [OLYMPUS_LUT_CHAN_579500_IDX] = { 23180, 0x1, 0x40, 0xC71C7, 0x78C },
+       [OLYMPUS_LUT_CHAN_579625_IDX] = { 23185, 0x1, 0x40, 0xCE38E, 0x78C },
+       [OLYMPUS_LUT_CHAN_579750_IDX] = { 23190, 0x1, 0x40, 0xD5555, 0x78D },
+       [OLYMPUS_LUT_CHAN_579875_IDX] = { 23195, 0x1, 0x40, 0xDC71C, 0x78D },
+       [OLYMPUS_LUT_CHAN_580000_IDX] = { 23200, 0x1, 0x40, 0xE38E4, 0x78D },
+       [OLYMPUS_LUT_CHAN_580125_IDX] = { 23205, 0x1, 0x40, 0xEAAAB, 0x78E },
+       [OLYMPUS_LUT_CHAN_580250_IDX] = { 23210, 0x1, 0x40, 0xF1C72, 0x78E },
+       [OLYMPUS_LUT_CHAN_580375_IDX] = { 23215, 0x1, 0x40, 0xF8E39, 0x78F },
+       [OLYMPUS_LUT_CHAN_580500_IDX] = { 23220, 0x1, 0x40, 0x100000, 0x78F },
+       [OLYMPUS_LUT_CHAN_580625_IDX] = { 23225, 0x1, 0x40, 0x1071C7, 0x78F },
+       [OLYMPUS_LUT_CHAN_580750_IDX] = { 23230, 0x1, 0x40, 0x10E38E, 0x790 },
+       [OLYMPUS_LUT_CHAN_580875_IDX] = { 23235, 0x1, 0x40, 0x115555, 0x790 },
+       [OLYMPUS_LUT_CHAN_581000_IDX] = { 23240, 0x1, 0x40, 0x11C71C, 0x791 },
+       [OLYMPUS_LUT_CHAN_581125_IDX] = { 23245, 0x1, 0x40, 0x1238E4, 0x791 },
+       [OLYMPUS_LUT_CHAN_581250_IDX] = { 23250, 0x1, 0x40, 0x12AAAB, 0x792 },
+       [OLYMPUS_LUT_CHAN_581375_IDX] = { 23255, 0x1, 0x40, 0x131C72, 0x792 },
+       [OLYMPUS_LUT_CHAN_581500_IDX] = { 23260, 0x1, 0x40, 0x138E39, 0x792 },
+       [OLYMPUS_LUT_CHAN_581625_IDX] = { 23265, 0x1, 0x40, 0x140000, 0x793 },
+       [OLYMPUS_LUT_CHAN_581750_IDX] = { 23270, 0x1, 0x40, 0x1471C7, 0x793 },
+       [OLYMPUS_LUT_CHAN_581875_IDX] = { 23275, 0x1, 0x40, 0x14E38E, 0x794 },
+       [OLYMPUS_LUT_CHAN_582000_IDX] = { 23280, 0x1, 0x40, 0x155555, 0x794 },
+       [OLYMPUS_LUT_CHAN_582125_IDX] = { 23285, 0x1, 0x40, 0x15C71C, 0x794 },
+       [OLYMPUS_LUT_CHAN_582250_IDX] = { 23290, 0x1, 0x40, 0x1638E4, 0x795 },
+       [OLYMPUS_LUT_CHAN_582375_IDX] = { 23295, 0x1, 0x40, 0x16AAAB, 0x795 },
+       [OLYMPUS_LUT_CHAN_582500_IDX] = { 23300, 0x1, 0x40, 0x171C72, 0x796 },
+       [OLYMPUS_LUT_CHAN_582625_IDX] = { 23305, 0x1, 0x40, 0x178E39, 0x796 },
+       [OLYMPUS_LUT_CHAN_582750_IDX] = { 23310, 0x1, 0x40, 0x180000, 0x797 },
+       [OLYMPUS_LUT_CHAN_582875_IDX] = { 23315, 0x1, 0x40, 0x1871C7, 0x797 },
+       [OLYMPUS_LUT_CHAN_583000_IDX] = { 23320, 0x1, 0x40, 0x18E38E, 0x797 },
+       [OLYMPUS_LUT_CHAN_583125_IDX] = { 23325, 0x1, 0x40, 0x195555, 0x798 },
+       [OLYMPUS_LUT_CHAN_583250_IDX] = { 23330, 0x1, 0x40, 0x19C71C, 0x798 },
+       [OLYMPUS_LUT_CHAN_583375_IDX] = { 23335, 0x1, 0x40, 0x1A38E4, 0x799 },
+       [OLYMPUS_LUT_CHAN_583500_IDX] = { 23340, 0x1, 0x40, 0x1AAAAB, 0x799 },
+       [OLYMPUS_LUT_CHAN_583625_IDX] = { 23345, 0x1, 0x40, 0x1B1C72, 0x799 },
+       [OLYMPUS_LUT_CHAN_583750_IDX] = { 23350, 0x1, 0x40, 0x1B8E39, 0x79A },
+       [OLYMPUS_LUT_CHAN_583875_IDX] = { 23355, 0x1, 0x40, 0x1C0000, 0x79A },
+       [OLYMPUS_LUT_CHAN_584000_IDX] = { 23360, 0x1, 0x40, 0x1C71C7, 0x79B },
+       [OLYMPUS_LUT_CHAN_584125_IDX] = { 23365, 0x1, 0x40, 0x1CE38E, 0x79B },
+       [OLYMPUS_LUT_CHAN_584250_IDX] = { 23370, 0x1, 0x40, 0x1D5555, 0x79C },
+       [OLYMPUS_LUT_CHAN_584375_IDX] = { 23375, 0x1, 0x40, 0x1DC71C, 0x79C },
+       [OLYMPUS_LUT_CHAN_584500_IDX] = { 23380, 0x1, 0x40, 0x1E38E4, 0x79C },
+       [OLYMPUS_LUT_CHAN_584625_IDX] = { 23385, 0x1, 0x40, 0x1EAAAB, 0x79D },
+       [OLYMPUS_LUT_CHAN_584750_IDX] = { 23390, 0x1, 0x40, 0x1F1C72, 0x79D },
+       [OLYMPUS_LUT_CHAN_584875_IDX] = { 23395, 0x1, 0x40, 0x1F8E39, 0x79E },
+       [OLYMPUS_LUT_CHAN_585000_IDX] = { 23400, 0x1, 0x41, 0x0, 0x79E },
+       [OLYMPUS_LUT_CHAN_585125_IDX] = { 23405, 0x1, 0x41, 0x71C7, 0x79E },
+       [OLYMPUS_LUT_CHAN_585250_IDX] = { 23410, 0x1, 0x41, 0xE38E, 0x79F },
+       [OLYMPUS_LUT_CHAN_585375_IDX] = { 23415, 0x1, 0x41, 0x15555, 0x79F },
+       [OLYMPUS_LUT_CHAN_585500_IDX] = { 23420, 0x1, 0x41, 0x1C71C, 0x7A0 },
+       [OLYMPUS_LUT_CHAN_585625_IDX] = { 23425, 0x1, 0x41, 0x238E4, 0x7A0 },
+       [OLYMPUS_LUT_CHAN_585750_IDX] = { 23430, 0x1, 0x41, 0x2AAAB, 0x7A1 },
+       [OLYMPUS_LUT_CHAN_585875_IDX] = { 23435, 0x1, 0x41, 0x31C72, 0x7A1 },
+       [OLYMPUS_LUT_CHAN_586000_IDX] = { 23440, 0x1, 0x41, 0x38E39, 0x7A1 },
+       [OLYMPUS_LUT_CHAN_586125_IDX] = { 23445, 0x1, 0x41, 0x40000, 0x7A2 },
+       [OLYMPUS_LUT_CHAN_586250_IDX] = { 23450, 0x1, 0x41, 0x471C7, 0x7A2 },
+       [OLYMPUS_LUT_CHAN_586375_IDX] = { 23455, 0x1, 0x41, 0x4E38E, 0x7A3 },
+       [OLYMPUS_LUT_CHAN_586500_IDX] = { 23460, 0x1, 0x41, 0x55555, 0x7A3 },
+       [OLYMPUS_LUT_CHAN_586625_IDX] = { 23465, 0x1, 0x41, 0x5C71C, 0x7A3 },
+       [OLYMPUS_LUT_CHAN_586750_IDX] = { 23470, 0x1, 0x41, 0x638E4, 0x7A4 },
+       [OLYMPUS_LUT_CHAN_586875_IDX] = { 23475, 0x1, 0x41, 0x6AAAB, 0x7A4 },
+       [OLYMPUS_LUT_CHAN_587000_IDX] = { 23480, 0x1, 0x41, 0x71C72, 0x7A5 },
+       [OLYMPUS_LUT_CHAN_587125_IDX] = { 23485, 0x1, 0x41, 0x78E39, 0x7A5 },
+       [OLYMPUS_LUT_CHAN_587250_IDX] = { 23490, 0x1, 0x41, 0x80000, 0x7A6 },
+       [OLYMPUS_LUT_CHAN_587375_IDX] = { 23495, 0x1, 0x41, 0x871C7, 0x7A6 },
+       [OLYMPUS_LUT_CHAN_587500_IDX] = { 23500, 0x1, 0x41, 0x8E38E, 0x7A6 },
+       [OLYMPUS_LUT_CHAN_587625_IDX] = { 23505, 0x1, 0x41, 0x95555, 0x7A7 },
+       [OLYMPUS_LUT_CHAN_587750_IDX] = { 23510, 0x1, 0x41, 0x9C71C, 0x7A7 },
+       [OLYMPUS_LUT_CHAN_587875_IDX] = { 23515, 0x1, 0x41, 0xA38E4, 0x7A8 },
+       [OLYMPUS_LUT_CHAN_588000_IDX] = { 23520, 0x1, 0x41, 0xAAAAB, 0x7A8 },
+       [OLYMPUS_LUT_CHAN_588125_IDX] = { 23525, 0x1, 0x41, 0xB1C72, 0x7A8 },
+       [OLYMPUS_LUT_CHAN_588250_IDX] = { 23530, 0x1, 0x41, 0xB8E39, 0x7A9 },
+       [OLYMPUS_LUT_CHAN_588375_IDX] = { 23535, 0x1, 0x41, 0xC0000, 0x7A9 },
+       [OLYMPUS_LUT_CHAN_588500_IDX] = { 23540, 0x1, 0x41, 0xC71C7, 0x7AA },
+       [OLYMPUS_LUT_CHAN_588625_IDX] = { 23545, 0x1, 0x41, 0xCE38E, 0x7AA },
+       [OLYMPUS_LUT_CHAN_588750_IDX] = { 23550, 0x1, 0x41, 0xD5555, 0x7AB },
+       [OLYMPUS_LUT_CHAN_588875_IDX] = { 23555, 0x1, 0x41, 0xDC71C, 0x7AB },
+       [OLYMPUS_LUT_CHAN_589000_IDX] = { 23560, 0x1, 0x41, 0xE38E4, 0x7AB },
+       [OLYMPUS_LUT_CHAN_589125_IDX] = { 23565, 0x1, 0x41, 0xEAAAB, 0x7AC },
+       [OLYMPUS_LUT_CHAN_589250_IDX] = { 23570, 0x1, 0x41, 0xF1C72, 0x7AC },
+       [OLYMPUS_LUT_CHAN_589375_IDX] = { 23575, 0x1, 0x41, 0xF8E39, 0x7AD },
+       [OLYMPUS_LUT_CHAN_589500_IDX] = { 23580, 0x1, 0x41, 0x100000, 0x7AD },
+       [OLYMPUS_LUT_CHAN_589625_IDX] = { 23585, 0x1, 0x41, 0x1071C7, 0x7AD },
+       [OLYMPUS_LUT_CHAN_589750_IDX] = { 23590, 0x1, 0x41, 0x10E38E, 0x7AE },
+       [OLYMPUS_LUT_CHAN_589875_IDX] = { 23595, 0x1, 0x41, 0x115555, 0x7AE },
+       [OLYMPUS_LUT_CHAN_590000_IDX] = { 23600, 0x1, 0x41, 0x11C71C, 0x7AF },
+       [OLYMPUS_LUT_CHAN_590125_IDX] = { 23605, 0x1, 0x41, 0x1238E4, 0x7AF },
+       [OLYMPUS_LUT_CHAN_590250_IDX] = { 23610, 0x1, 0x41, 0x12AAAB, 0x7B0 },
+       [OLYMPUS_LUT_CHAN_590375_IDX] = { 23615, 0x1, 0x41, 0x131C72, 0x7B0 },
+       [OLYMPUS_LUT_CHAN_590500_IDX] = { 23620, 0x1, 0x41, 0x138E39, 0x7B0 },
+       [OLYMPUS_LUT_CHAN_590625_IDX] = { 23625, 0x1, 0x41, 0x140000, 0x7B1 },
+       [OLYMPUS_LUT_CHAN_590750_IDX] = { 23630, 0x1, 0x41, 0x1471C7, 0x7B1 },
+       [OLYMPUS_LUT_CHAN_590875_IDX] = { 23635, 0x1, 0x41, 0x14E38E, 0x7B2 },
+       [OLYMPUS_LUT_CHAN_591000_IDX] = { 23640, 0x1, 0x41, 0x155555, 0x7B2 },
+       [OLYMPUS_LUT_CHAN_591125_IDX] = { 23645, 0x1, 0x41, 0x15C71C, 0x7B2 },
+       [OLYMPUS_LUT_CHAN_591250_IDX] = { 23650, 0x1, 0x41, 0x1638E4, 0x7B3 },
+       [OLYMPUS_LUT_CHAN_591375_IDX] = { 23655, 0x1, 0x41, 0x16AAAB, 0x7B3 },
+       [OLYMPUS_LUT_CHAN_591500_IDX] = { 23660, 0x1, 0x41, 0x171C72, 0x7B4 },
+       [OLYMPUS_LUT_CHAN_591625_IDX] = { 23665, 0x1, 0x41, 0x178E39, 0x7B4 },
+       [OLYMPUS_LUT_CHAN_591750_IDX] = { 23670, 0x1, 0x41, 0x180000, 0x7B5 },
+       [OLYMPUS_LUT_CHAN_591875_IDX] = { 23675, 0x1, 0x41, 0x1871C7, 0x7B5 },
+       [OLYMPUS_LUT_CHAN_592000_IDX] = { 23680, 0x1, 0x41, 0x18E38E, 0x7B5 },
+       [OLYMPUS_LUT_CHAN_592125_IDX] = { 23685, 0x1, 0x41, 0x195555, 0x7B6 },
+       [OLYMPUS_LUT_CHAN_592250_IDX] = { 23690, 0x1, 0x41, 0x19C71C, 0x7B6 },
+       [OLYMPUS_LUT_CHAN_592375_IDX] = { 23695, 0x1, 0x41, 0x1A38E4, 0x7B7 },
+       [OLYMPUS_LUT_CHAN_592500_IDX] = { 23700, 0x1, 0x41, 0x1AAAAB, 0x7B7 },
+       [OLYMPUS_LUT_CHAN_592625_IDX] = { 23705, 0x1, 0x41, 0x1B1C72, 0x7B7 },
+       [OLYMPUS_LUT_CHAN_592750_IDX] = { 23710, 0x1, 0x41, 0x1B8E39, 0x7B8 },
+       [OLYMPUS_LUT_CHAN_592875_IDX] = { 23715, 0x1, 0x41, 0x1C0000, 0x7B8 },
+       [OLYMPUS_LUT_CHAN_593000_IDX] = { 23720, 0x1, 0x41, 0x1C71C7, 0x7B9 },
+       [OLYMPUS_LUT_CHAN_593125_IDX] = { 23725, 0x1, 0x41, 0x1CE38E, 0x7B9 },
+       [OLYMPUS_LUT_CHAN_593250_IDX] = { 23730, 0x1, 0x41, 0x1D5555, 0x7BA },
+       [OLYMPUS_LUT_CHAN_593375_IDX] = { 23735, 0x1, 0x41, 0x1DC71C, 0x7BA },
+       [OLYMPUS_LUT_CHAN_593500_IDX] = { 23740, 0x1, 0x41, 0x1E38E4, 0x7BA },
+       [OLYMPUS_LUT_CHAN_593625_IDX] = { 23745, 0x1, 0x41, 0x1EAAAB, 0x7BB },
+       [OLYMPUS_LUT_CHAN_593750_IDX] = { 23750, 0x1, 0x41, 0x1F1C72, 0x7BB },
+       [OLYMPUS_LUT_CHAN_593875_IDX] = { 23755, 0x1, 0x41, 0x1F8E39, 0x7BC },
+       [OLYMPUS_LUT_CHAN_594000_IDX] = { 23760, 0x1, 0x42, 0x0, 0x7BC },
+       [OLYMPUS_LUT_CHAN_594125_IDX] = { 23765, 0x1, 0x42, 0x71C7, 0x7BC },
+       [OLYMPUS_LUT_CHAN_594250_IDX] = { 23770, 0x1, 0x42, 0xE38E, 0x7BD },
+       [OLYMPUS_LUT_CHAN_594375_IDX] = { 23775, 0x1, 0x42, 0x15555, 0x7BD },
+       [OLYMPUS_LUT_CHAN_594500_IDX] = { 23780, 0x1, 0x42, 0x1C71C, 0x7BE },
+       [OLYMPUS_LUT_CHAN_594625_IDX] = { 23785, 0x1, 0x42, 0x238E4, 0x7BE },
+       [OLYMPUS_LUT_CHAN_594750_IDX] = { 23790, 0x1, 0x42, 0x2AAAB, 0x7BF },
+       [OLYMPUS_LUT_CHAN_594875_IDX] = { 23795, 0x1, 0x42, 0x31C72, 0x7BF },
+       [OLYMPUS_LUT_CHAN_595000_IDX] = { 23800, 0x1, 0x42, 0x38E39, 0x7BF }
+};
+
+const struct olympus_lut_line olympus_lut_24g_40_mhz[OLYMPUS_LUT_CHAN_24G_MAX] = {
+       [OLYMPUS_LUT_CHAN_240700_IDX] = { 9628, 0x0, 0x50, 0x77777, 0x645 },
+       [OLYMPUS_LUT_CHAN_240825_IDX] = { 9633, 0x0, 0x50, 0x8CCCD, 0x646 },
+       [OLYMPUS_LUT_CHAN_240950_IDX] = { 9638, 0x0, 0x50, 0xA2222, 0x646 },
+       [OLYMPUS_LUT_CHAN_241075_IDX] = { 9643, 0x0, 0x50, 0xB7777, 0x647 },
+       [OLYMPUS_LUT_CHAN_241200_IDX] = { 9648, 0x0, 0x50, 0xCCCCD, 0x648 },
+       [OLYMPUS_LUT_CHAN_241325_IDX] = { 9653, 0x0, 0x50, 0xE2222, 0x649 },
+       [OLYMPUS_LUT_CHAN_241450_IDX] = { 9658, 0x0, 0x50, 0xF7777, 0x64A },
+       [OLYMPUS_LUT_CHAN_241575_IDX] = { 9663, 0x0, 0x50, 0x10CCCD, 0x64B },
+       [OLYMPUS_LUT_CHAN_241700_IDX] = { 9668, 0x0, 0x50, 0x122222, 0x64B },
+       [OLYMPUS_LUT_CHAN_241825_IDX] = { 9673, 0x0, 0x50, 0x137777, 0x64C },
+       [OLYMPUS_LUT_CHAN_241950_IDX] = { 9678, 0x0, 0x50, 0x14CCCD, 0x64D },
+       [OLYMPUS_LUT_CHAN_242075_IDX] = { 9683, 0x0, 0x50, 0x162222, 0x64E },
+       [OLYMPUS_LUT_CHAN_242200_IDX] = { 9688, 0x0, 0x50, 0x177777, 0x64F },
+       [OLYMPUS_LUT_CHAN_242325_IDX] = { 9693, 0x0, 0x50, 0x18CCCD, 0x650 },
+       [OLYMPUS_LUT_CHAN_242450_IDX] = { 9698, 0x0, 0x50, 0x1A2222, 0x650 },
+       [OLYMPUS_LUT_CHAN_242575_IDX] = { 9703, 0x0, 0x50, 0x1B7777, 0x651 },
+       [OLYMPUS_LUT_CHAN_242700_IDX] = { 9708, 0x0, 0x50, 0x1CCCCD, 0x652 },
+       [OLYMPUS_LUT_CHAN_242825_IDX] = { 9713, 0x0, 0x50, 0x1E2222, 0x653 },
+       [OLYMPUS_LUT_CHAN_242950_IDX] = { 9718, 0x0, 0x50, 0x1F7777, 0x654 },
+       [OLYMPUS_LUT_CHAN_243075_IDX] = { 9723, 0x0, 0x51, 0xCCCD, 0x655 },
+       [OLYMPUS_LUT_CHAN_243200_IDX] = { 9728, 0x0, 0x51, 0x22222, 0x655 },
+       [OLYMPUS_LUT_CHAN_243325_IDX] = { 9733, 0x0, 0x51, 0x37777, 0x656 },
+       [OLYMPUS_LUT_CHAN_243450_IDX] = { 9738, 0x0, 0x51, 0x4CCCD, 0x657 },
+       [OLYMPUS_LUT_CHAN_243575_IDX] = { 9743, 0x0, 0x51, 0x62222, 0x658 },
+       [OLYMPUS_LUT_CHAN_243700_IDX] = { 9748, 0x0, 0x51, 0x77777, 0x659 },
+       [OLYMPUS_LUT_CHAN_243825_IDX] = { 9753, 0x0, 0x51, 0x8CCCD, 0x65A },
+       [OLYMPUS_LUT_CHAN_243950_IDX] = { 9758, 0x0, 0x51, 0xA2222, 0x65A },
+       [OLYMPUS_LUT_CHAN_244075_IDX] = { 9763, 0x0, 0x51, 0xB7777, 0x65B },
+       [OLYMPUS_LUT_CHAN_244200_IDX] = { 9768, 0x0, 0x51, 0xCCCCD, 0x65C },
+       [OLYMPUS_LUT_CHAN_244325_IDX] = { 9773, 0x0, 0x51, 0xE2222, 0x65D },
+       [OLYMPUS_LUT_CHAN_244450_IDX] = { 9778, 0x0, 0x51, 0xF7777, 0x65E },
+       [OLYMPUS_LUT_CHAN_244575_IDX] = { 9783, 0x0, 0x51, 0x10CCCD, 0x65F },
+       [OLYMPUS_LUT_CHAN_244700_IDX] = { 9788, 0x0, 0x51, 0x122222, 0x65F },
+       [OLYMPUS_LUT_CHAN_244825_IDX] = { 9793, 0x0, 0x51, 0x137777, 0x660 },
+       [OLYMPUS_LUT_CHAN_244950_IDX] = { 9798, 0x0, 0x51, 0x14CCCD, 0x661 },
+       [OLYMPUS_LUT_CHAN_245075_IDX] = { 9803, 0x0, 0x51, 0x162222, 0x662 },
+       [OLYMPUS_LUT_CHAN_245200_IDX] = { 9808, 0x0, 0x51, 0x177777, 0x663 },
+       [OLYMPUS_LUT_CHAN_245325_IDX] = { 9813, 0x0, 0x51, 0x18CCCD, 0x664 },
+       [OLYMPUS_LUT_CHAN_245450_IDX] = { 9818, 0x0, 0x51, 0x1A2222, 0x664 },
+       [OLYMPUS_LUT_CHAN_245575_IDX] = { 9823, 0x0, 0x51, 0x1B7777, 0x665 },
+       [OLYMPUS_LUT_CHAN_245700_IDX] = { 9828, 0x0, 0x51, 0x1CCCCD, 0x666 },
+       [OLYMPUS_LUT_CHAN_245825_IDX] = { 9833, 0x0, 0x51, 0x1E2222, 0x667 },
+       [OLYMPUS_LUT_CHAN_245950_IDX] = { 9838, 0x0, 0x51, 0x1F7777, 0x668 },
+       [OLYMPUS_LUT_CHAN_246075_IDX] = { 9843, 0x0, 0x52, 0xCCCD, 0x669 },
+       [OLYMPUS_LUT_CHAN_246200_IDX] = { 9848, 0x0, 0x52, 0x22222, 0x669 },
+       [OLYMPUS_LUT_CHAN_246325_IDX] = { 9853, 0x0, 0x52, 0x37777, 0x66A },
+       [OLYMPUS_LUT_CHAN_246450_IDX] = { 9858, 0x0, 0x52, 0x4CCCD, 0x66B },
+       [OLYMPUS_LUT_CHAN_246575_IDX] = { 9863, 0x0, 0x52, 0x62222, 0x66C },
+       [OLYMPUS_LUT_CHAN_246700_IDX] = { 9868, 0x0, 0x52, 0x77777, 0x66D },
+       [OLYMPUS_LUT_CHAN_246825_IDX] = { 9873, 0x0, 0x52, 0x8CCCD, 0x66E },
+       [OLYMPUS_LUT_CHAN_246950_IDX] = { 9878, 0x0, 0x52, 0xA2222, 0x66E },
+       [OLYMPUS_LUT_CHAN_247075_IDX] = { 9883, 0x0, 0x52, 0xB7777, 0x66F },
+       [OLYMPUS_LUT_CHAN_247200_IDX] = { 9888, 0x0, 0x52, 0xCCCCD, 0x670 },
+       [OLYMPUS_LUT_CHAN_247325_IDX] = { 9893, 0x0, 0x52, 0xE2222, 0x671 },
+       [OLYMPUS_LUT_CHAN_247450_IDX] = { 9898, 0x0, 0x52, 0xF7777, 0x672 },
+       [OLYMPUS_LUT_CHAN_247575_IDX] = { 9903, 0x0, 0x52, 0x10CCCD, 0x673 },
+       [OLYMPUS_LUT_CHAN_247700_IDX] = { 9908, 0x0, 0x52, 0x122222, 0x673 },
+       [OLYMPUS_LUT_CHAN_247825_IDX] = { 9913, 0x0, 0x52, 0x137777, 0x674 },
+       [OLYMPUS_LUT_CHAN_247950_IDX] = { 9918, 0x0, 0x52, 0x14CCCD, 0x675 },
+       [OLYMPUS_LUT_CHAN_248075_IDX] = { 9923, 0x0, 0x52, 0x162222, 0x676 },
+       [OLYMPUS_LUT_CHAN_248200_IDX] = { 9928, 0x0, 0x52, 0x177777, 0x677 },
+       [OLYMPUS_LUT_CHAN_248325_IDX] = { 9933, 0x0, 0x52, 0x18CCCD, 0x678 },
+       [OLYMPUS_LUT_CHAN_248450_IDX] = { 9938, 0x0, 0x52, 0x1A2222, 0x678 },
+       [OLYMPUS_LUT_CHAN_248575_IDX] = { 9943, 0x0, 0x52, 0x1B7777, 0x679 },
+       [OLYMPUS_LUT_CHAN_248700_IDX] = { 9948, 0x0, 0x52, 0x1CCCCD, 0x67A },
+       [OLYMPUS_LUT_CHAN_248825_IDX] = { 9953, 0x0, 0x52, 0x1E2222, 0x67B },
+       [OLYMPUS_LUT_CHAN_248950_IDX] = { 9958, 0x0, 0x52, 0x1F7777, 0x67C },
+       [OLYMPUS_LUT_CHAN_249075_IDX] = { 9963, 0x0, 0x53, 0xCCCD, 0x67D },
+       [OLYMPUS_LUT_CHAN_249200_IDX] = { 9968, 0x0, 0x53, 0x22222, 0x67D },
+       [OLYMPUS_LUT_CHAN_249325_IDX] = { 9973, 0x0, 0x53, 0x37777, 0x67E },
+       [OLYMPUS_LUT_CHAN_249450_IDX] = { 9978, 0x0, 0x53, 0x4CCCD, 0x67F },
+       [OLYMPUS_LUT_CHAN_249575_IDX] = { 9983, 0x0, 0x53, 0x62222, 0x680 },
+       [OLYMPUS_LUT_CHAN_249700_IDX] = { 9988, 0x0, 0x53, 0x77777, 0x681 },
+       [OLYMPUS_LUT_CHAN_249825_IDX] = { 9993, 0x0, 0x53, 0x8CCCD, 0x682 },
+       [OLYMPUS_LUT_CHAN_249950_IDX] = { 9998, 0x0, 0x53, 0xA2222, 0x682 },
+       [OLYMPUS_LUT_CHAN_250075_IDX] = { 10003, 0x0, 0x53, 0xB7777, 0x683 }
+};
+
+const struct olympus_lut_line olympus_lut_24g_60_mhz_s0[OLYMPUS_LUT_CHAN_24G_MAX] = {
+       [OLYMPUS_LUT_CHAN_240700_IDX] = { 9628, 0x0, 0x6A, 0x1F49F5, 0x645 },
+       [OLYMPUS_LUT_CHAN_240825_IDX] = { 9633, 0x0, 0x6B, 0x11111, 0x646 },
+       [OLYMPUS_LUT_CHAN_240950_IDX] = { 9638, 0x0, 0x6B, 0x2D82E, 0x646 },
+       [OLYMPUS_LUT_CHAN_241075_IDX] = { 9643, 0x0, 0x6B, 0x49F4A, 0x647 },
+       [OLYMPUS_LUT_CHAN_241200_IDX] = { 9648, 0x0, 0x6B, 0x66666, 0x648 },
+       [OLYMPUS_LUT_CHAN_241325_IDX] = { 9653, 0x0, 0x6B, 0x82D83, 0x649 },
+       [OLYMPUS_LUT_CHAN_241450_IDX] = { 9658, 0x0, 0x6B, 0x9F49F, 0x64A },
+       [OLYMPUS_LUT_CHAN_241575_IDX] = { 9663, 0x0, 0x6B, 0xBBBBC, 0x64B },
+       [OLYMPUS_LUT_CHAN_241700_IDX] = { 9668, 0x0, 0x6B, 0xD82D8, 0x64B },
+       [OLYMPUS_LUT_CHAN_241825_IDX] = { 9673, 0x0, 0x6B, 0xF49F5, 0x64C },
+       [OLYMPUS_LUT_CHAN_241950_IDX] = { 9678, 0x0, 0x6B, 0x111111, 0x64D },
+       [OLYMPUS_LUT_CHAN_242075_IDX] = { 9683, 0x0, 0x6B, 0x12D82E, 0x64E },
+       [OLYMPUS_LUT_CHAN_242200_IDX] = { 9688, 0x0, 0x6B, 0x149F4A, 0x64F },
+       [OLYMPUS_LUT_CHAN_242325_IDX] = { 9693, 0x0, 0x6B, 0x166666, 0x650 },
+       [OLYMPUS_LUT_CHAN_242450_IDX] = { 9698, 0x0, 0x6B, 0x182D83, 0x650 },
+       [OLYMPUS_LUT_CHAN_242575_IDX] = { 9703, 0x0, 0x6B, 0x19F49F, 0x651 },
+       [OLYMPUS_LUT_CHAN_242700_IDX] = { 9708, 0x0, 0x6B, 0x1BBBBC, 0x652 },
+       [OLYMPUS_LUT_CHAN_242825_IDX] = { 9713, 0x0, 0x6B, 0x1D82D8, 0x653 },
+       [OLYMPUS_LUT_CHAN_242950_IDX] = { 9718, 0x0, 0x6B, 0x1F49F5, 0x654 },
+       [OLYMPUS_LUT_CHAN_243075_IDX] = { 9723, 0x0, 0x6C, 0x11111, 0x655 },
+       [OLYMPUS_LUT_CHAN_243200_IDX] = { 9728, 0x0, 0x6C, 0x2D82E, 0x655 },
+       [OLYMPUS_LUT_CHAN_243325_IDX] = { 9733, 0x0, 0x6C, 0x49F4A, 0x656 },
+       [OLYMPUS_LUT_CHAN_243450_IDX] = { 9738, 0x0, 0x6C, 0x66666, 0x657 },
+       [OLYMPUS_LUT_CHAN_243575_IDX] = { 9743, 0x0, 0x6C, 0x82D83, 0x658 },
+       [OLYMPUS_LUT_CHAN_243700_IDX] = { 9748, 0x0, 0x6C, 0x9F49F, 0x659 },
+       [OLYMPUS_LUT_CHAN_243825_IDX] = { 9753, 0x0, 0x6C, 0xBBBBC, 0x65A },
+       [OLYMPUS_LUT_CHAN_243950_IDX] = { 9758, 0x0, 0x6C, 0xD82D8, 0x65A },
+       [OLYMPUS_LUT_CHAN_244075_IDX] = { 9763, 0x0, 0x6C, 0xF49F5, 0x65B },
+       [OLYMPUS_LUT_CHAN_244200_IDX] = { 9768, 0x0, 0x6C, 0x111111, 0x65C },
+       [OLYMPUS_LUT_CHAN_244325_IDX] = { 9773, 0x0, 0x6C, 0x12D82E, 0x65D },
+       [OLYMPUS_LUT_CHAN_244450_IDX] = { 9778, 0x0, 0x6C, 0x149F4A, 0x65E },
+       [OLYMPUS_LUT_CHAN_244575_IDX] = { 9783, 0x0, 0x6C, 0x166666, 0x65F },
+       [OLYMPUS_LUT_CHAN_244700_IDX] = { 9788, 0x0, 0x6C, 0x182D83, 0x65F },
+       [OLYMPUS_LUT_CHAN_244825_IDX] = { 9793, 0x0, 0x6C, 0x19F49F, 0x660 },
+       [OLYMPUS_LUT_CHAN_244950_IDX] = { 9798, 0x0, 0x6C, 0x1BBBBC, 0x661 },
+       [OLYMPUS_LUT_CHAN_245075_IDX] = { 9803, 0x0, 0x6C, 0x1D82D8, 0x662 },
+       [OLYMPUS_LUT_CHAN_245200_IDX] = { 9808, 0x0, 0x6C, 0x1F49F5, 0x663 },
+       [OLYMPUS_LUT_CHAN_245325_IDX] = { 9813, 0x0, 0x6D, 0x11111, 0x664 },
+       [OLYMPUS_LUT_CHAN_245450_IDX] = { 9818, 0x0, 0x6D, 0x2D82E, 0x664 },
+       [OLYMPUS_LUT_CHAN_245575_IDX] = { 9823, 0x0, 0x6D, 0x49F4A, 0x665 },
+       [OLYMPUS_LUT_CHAN_245700_IDX] = { 9828, 0x0, 0x6D, 0x66666, 0x666 },
+       [OLYMPUS_LUT_CHAN_245825_IDX] = { 9833, 0x0, 0x6D, 0x82D83, 0x667 },
+       [OLYMPUS_LUT_CHAN_245950_IDX] = { 9838, 0x0, 0x6D, 0x9F49F, 0x668 },
+       [OLYMPUS_LUT_CHAN_246075_IDX] = { 9843, 0x0, 0x6D, 0xBBBBC, 0x669 },
+       [OLYMPUS_LUT_CHAN_246200_IDX] = { 9848, 0x0, 0x6D, 0xD82D8, 0x669 },
+       [OLYMPUS_LUT_CHAN_246325_IDX] = { 9853, 0x0, 0x6D, 0xF49F5, 0x66A },
+       [OLYMPUS_LUT_CHAN_246450_IDX] = { 9858, 0x0, 0x6D, 0x111111, 0x66B },
+       [OLYMPUS_LUT_CHAN_246575_IDX] = { 9863, 0x0, 0x6D, 0x12D82E, 0x66C },
+       [OLYMPUS_LUT_CHAN_246700_IDX] = { 9868, 0x0, 0x6D, 0x149F4A, 0x66D },
+       [OLYMPUS_LUT_CHAN_246825_IDX] = { 9873, 0x0, 0x6D, 0x166666, 0x66E },
+       [OLYMPUS_LUT_CHAN_246950_IDX] = { 9878, 0x0, 0x6D, 0x182D83, 0x66E },
+       [OLYMPUS_LUT_CHAN_247075_IDX] = { 9883, 0x0, 0x6D, 0x19F49F, 0x66F },
+       [OLYMPUS_LUT_CHAN_247200_IDX] = { 9888, 0x0, 0x6D, 0x1BBBBC, 0x670 },
+       [OLYMPUS_LUT_CHAN_247325_IDX] = { 9893, 0x0, 0x6D, 0x1D82D8, 0x671 },
+       [OLYMPUS_LUT_CHAN_247450_IDX] = { 9898, 0x0, 0x6D, 0x1F49F5, 0x672 },
+       [OLYMPUS_LUT_CHAN_247575_IDX] = { 9903, 0x0, 0x6E, 0x11111, 0x673 },
+       [OLYMPUS_LUT_CHAN_247700_IDX] = { 9908, 0x0, 0x6E, 0x2D82E, 0x673 },
+       [OLYMPUS_LUT_CHAN_247825_IDX] = { 9913, 0x0, 0x6E, 0x49F4A, 0x674 },
+       [OLYMPUS_LUT_CHAN_247950_IDX] = { 9918, 0x0, 0x6E, 0x66666, 0x675 },
+       [OLYMPUS_LUT_CHAN_248075_IDX] = { 9923, 0x0, 0x6E, 0x82D83, 0x676 },
+       [OLYMPUS_LUT_CHAN_248200_IDX] = { 9928, 0x0, 0x6E, 0x9F49F, 0x677 },
+       [OLYMPUS_LUT_CHAN_248325_IDX] = { 9933, 0x0, 0x6E, 0xBBBBC, 0x678 },
+       [OLYMPUS_LUT_CHAN_248450_IDX] = { 9938, 0x0, 0x6E, 0xD82D8, 0x678 },
+       [OLYMPUS_LUT_CHAN_248575_IDX] = { 9943, 0x0, 0x6E, 0xF49F5, 0x679 },
+       [OLYMPUS_LUT_CHAN_248700_IDX] = { 9948, 0x0, 0x6E, 0x111111, 0x67A },
+       [OLYMPUS_LUT_CHAN_248825_IDX] = { 9953, 0x0, 0x6E, 0x12D82E, 0x67B },
+       [OLYMPUS_LUT_CHAN_248950_IDX] = { 9958, 0x0, 0x6E, 0x149F4A, 0x67C },
+       [OLYMPUS_LUT_CHAN_249075_IDX] = { 9963, 0x0, 0x6E, 0x166666, 0x67D },
+       [OLYMPUS_LUT_CHAN_249200_IDX] = { 9968, 0x0, 0x6E, 0x182D83, 0x67D },
+       [OLYMPUS_LUT_CHAN_249325_IDX] = { 9973, 0x0, 0x6E, 0x19F49F, 0x67E },
+       [OLYMPUS_LUT_CHAN_249450_IDX] = { 9978, 0x0, 0x6E, 0x1BBBBC, 0x67F },
+       [OLYMPUS_LUT_CHAN_249575_IDX] = { 9983, 0x0, 0x6E, 0x1D82D8, 0x680 },
+       [OLYMPUS_LUT_CHAN_249700_IDX] = { 9988, 0x0, 0x6E, 0x1F49F5, 0x681 },
+       [OLYMPUS_LUT_CHAN_249825_IDX] = { 9993, 0x0, 0x6F, 0x11111, 0x682 },
+       [OLYMPUS_LUT_CHAN_249950_IDX] = { 9998, 0x0, 0x6F, 0x2D82E, 0x682 },
+       [OLYMPUS_LUT_CHAN_250075_IDX] = { 10003, 0x0, 0x6F, 0x49F4A, 0x683 }
+};
+
+const struct olympus_lut_line olympus_lut_24g_60_mhz_s1[OLYMPUS_LUT_CHAN_24G_MAX] = {
+       [OLYMPUS_LUT_CHAN_240700_IDX] = { 9628, 0x0, 0x35, 0xFA4FA, 0x645 },
+       [OLYMPUS_LUT_CHAN_240825_IDX] = { 9633, 0x0, 0x35, 0x108889, 0x646 },
+       [OLYMPUS_LUT_CHAN_240950_IDX] = { 9638, 0x0, 0x35, 0x116C17, 0x646 },
+       [OLYMPUS_LUT_CHAN_241075_IDX] = { 9643, 0x0, 0x35, 0x124FA5, 0x647 },
+       [OLYMPUS_LUT_CHAN_241200_IDX] = { 9648, 0x0, 0x35, 0x133333, 0x648 },
+       [OLYMPUS_LUT_CHAN_241325_IDX] = { 9653, 0x0, 0x35, 0x1416C1, 0x649 },
+       [OLYMPUS_LUT_CHAN_241450_IDX] = { 9658, 0x0, 0x35, 0x14FA50, 0x64A },
+       [OLYMPUS_LUT_CHAN_241575_IDX] = { 9663, 0x0, 0x35, 0x15DDDE, 0x64B },
+       [OLYMPUS_LUT_CHAN_241700_IDX] = { 9668, 0x0, 0x35, 0x16C16C, 0x64B },
+       [OLYMPUS_LUT_CHAN_241825_IDX] = { 9673, 0x0, 0x35, 0x17A4FA, 0x64C },
+       [OLYMPUS_LUT_CHAN_241950_IDX] = { 9678, 0x0, 0x35, 0x188889, 0x64D },
+       [OLYMPUS_LUT_CHAN_242075_IDX] = { 9683, 0x0, 0x35, 0x196C17, 0x64E },
+       [OLYMPUS_LUT_CHAN_242200_IDX] = { 9688, 0x0, 0x35, 0x1A4FA5, 0x64F },
+       [OLYMPUS_LUT_CHAN_242325_IDX] = { 9693, 0x0, 0x35, 0x1B3333, 0x650 },
+       [OLYMPUS_LUT_CHAN_242450_IDX] = { 9698, 0x0, 0x35, 0x1C16C1, 0x650 },
+       [OLYMPUS_LUT_CHAN_242575_IDX] = { 9703, 0x0, 0x35, 0x1CFA50, 0x651 },
+       [OLYMPUS_LUT_CHAN_242700_IDX] = { 9708, 0x0, 0x35, 0x1DDDDE, 0x652 },
+       [OLYMPUS_LUT_CHAN_242825_IDX] = { 9713, 0x0, 0x35, 0x1EC16C, 0x653 },
+       [OLYMPUS_LUT_CHAN_242950_IDX] = { 9718, 0x0, 0x35, 0x1FA4FA, 0x654 },
+       [OLYMPUS_LUT_CHAN_243075_IDX] = { 9723, 0x0, 0x36, 0x8889, 0x655 },
+       [OLYMPUS_LUT_CHAN_243200_IDX] = { 9728, 0x0, 0x36, 0x16C17, 0x655 },
+       [OLYMPUS_LUT_CHAN_243325_IDX] = { 9733, 0x0, 0x36, 0x24FA5, 0x656 },
+       [OLYMPUS_LUT_CHAN_243450_IDX] = { 9738, 0x0, 0x36, 0x33333, 0x657 },
+       [OLYMPUS_LUT_CHAN_243575_IDX] = { 9743, 0x0, 0x36, 0x416C1, 0x658 },
+       [OLYMPUS_LUT_CHAN_243700_IDX] = { 9748, 0x0, 0x36, 0x4FA50, 0x659 },
+       [OLYMPUS_LUT_CHAN_243825_IDX] = { 9753, 0x0, 0x36, 0x5DDDE, 0x65A },
+       [OLYMPUS_LUT_CHAN_243950_IDX] = { 9758, 0x0, 0x36, 0x6C16C, 0x65A },
+       [OLYMPUS_LUT_CHAN_244075_IDX] = { 9763, 0x0, 0x36, 0x7A4FA, 0x65B },
+       [OLYMPUS_LUT_CHAN_244200_IDX] = { 9768, 0x0, 0x36, 0x88889, 0x65C },
+       [OLYMPUS_LUT_CHAN_244325_IDX] = { 9773, 0x0, 0x36, 0x96C17, 0x65D },
+       [OLYMPUS_LUT_CHAN_244450_IDX] = { 9778, 0x0, 0x36, 0xA4FA5, 0x65E },
+       [OLYMPUS_LUT_CHAN_244575_IDX] = { 9783, 0x0, 0x36, 0xB3333, 0x65F },
+       [OLYMPUS_LUT_CHAN_244700_IDX] = { 9788, 0x0, 0x36, 0xC16C1, 0x65F },
+       [OLYMPUS_LUT_CHAN_244825_IDX] = { 9793, 0x0, 0x36, 0xCFA50, 0x660 },
+       [OLYMPUS_LUT_CHAN_244950_IDX] = { 9798, 0x0, 0x36, 0xDDDDE, 0x661 },
+       [OLYMPUS_LUT_CHAN_245075_IDX] = { 9803, 0x0, 0x36, 0xEC16C, 0x662 },
+       [OLYMPUS_LUT_CHAN_245200_IDX] = { 9808, 0x0, 0x36, 0xFA4FA, 0x663 },
+       [OLYMPUS_LUT_CHAN_245325_IDX] = { 9813, 0x0, 0x36, 0x108889, 0x664 },
+       [OLYMPUS_LUT_CHAN_245450_IDX] = { 9818, 0x0, 0x36, 0x116C17, 0x664 },
+       [OLYMPUS_LUT_CHAN_245575_IDX] = { 9823, 0x0, 0x36, 0x124FA5, 0x665 },
+       [OLYMPUS_LUT_CHAN_245700_IDX] = { 9828, 0x0, 0x36, 0x133333, 0x666 },
+       [OLYMPUS_LUT_CHAN_245825_IDX] = { 9833, 0x0, 0x36, 0x1416C1, 0x667 },
+       [OLYMPUS_LUT_CHAN_245950_IDX] = { 9838, 0x0, 0x36, 0x14FA50, 0x668 },
+       [OLYMPUS_LUT_CHAN_246075_IDX] = { 9843, 0x0, 0x36, 0x15DDDE, 0x669 },
+       [OLYMPUS_LUT_CHAN_246200_IDX] = { 9848, 0x0, 0x36, 0x16C16C, 0x669 },
+       [OLYMPUS_LUT_CHAN_246325_IDX] = { 9853, 0x0, 0x36, 0x17A4FA, 0x66A },
+       [OLYMPUS_LUT_CHAN_246450_IDX] = { 9858, 0x0, 0x36, 0x188889, 0x66B },
+       [OLYMPUS_LUT_CHAN_246575_IDX] = { 9863, 0x0, 0x36, 0x196C17, 0x66C },
+       [OLYMPUS_LUT_CHAN_246700_IDX] = { 9868, 0x0, 0x36, 0x1A4FA5, 0x66D },
+       [OLYMPUS_LUT_CHAN_246825_IDX] = { 9873, 0x0, 0x36, 0x1B3333, 0x66E },
+       [OLYMPUS_LUT_CHAN_246950_IDX] = { 9878, 0x0, 0x36, 0x1C16C1, 0x66E },
+       [OLYMPUS_LUT_CHAN_247075_IDX] = { 9883, 0x0, 0x36, 0x1CFA50, 0x66F },
+       [OLYMPUS_LUT_CHAN_247200_IDX] = { 9888, 0x0, 0x36, 0x1DDDDE, 0x670 },
+       [OLYMPUS_LUT_CHAN_247325_IDX] = { 9893, 0x0, 0x36, 0x1EC16C, 0x671 },
+       [OLYMPUS_LUT_CHAN_247450_IDX] = { 9898, 0x0, 0x36, 0x1FA4FA, 0x672 },
+       [OLYMPUS_LUT_CHAN_247575_IDX] = { 9903, 0x0, 0x37, 0x8889, 0x673 },
+       [OLYMPUS_LUT_CHAN_247700_IDX] = { 9908, 0x0, 0x37, 0x16C17, 0x673 },
+       [OLYMPUS_LUT_CHAN_247825_IDX] = { 9913, 0x0, 0x37, 0x24FA5, 0x674 },
+       [OLYMPUS_LUT_CHAN_247950_IDX] = { 9918, 0x0, 0x37, 0x33333, 0x675 },
+       [OLYMPUS_LUT_CHAN_248075_IDX] = { 9923, 0x0, 0x37, 0x416C1, 0x676 },
+       [OLYMPUS_LUT_CHAN_248200_IDX] = { 9928, 0x0, 0x37, 0x4FA50, 0x677 },
+       [OLYMPUS_LUT_CHAN_248325_IDX] = { 9933, 0x0, 0x37, 0x5DDDE, 0x678 },
+       [OLYMPUS_LUT_CHAN_248450_IDX] = { 9938, 0x0, 0x37, 0x6C16C, 0x678 },
+       [OLYMPUS_LUT_CHAN_248575_IDX] = { 9943, 0x0, 0x37, 0x7A4FA, 0x679 },
+       [OLYMPUS_LUT_CHAN_248700_IDX] = { 9948, 0x0, 0x37, 0x88889, 0x67A },
+       [OLYMPUS_LUT_CHAN_248825_IDX] = { 9953, 0x0, 0x37, 0x96C17, 0x67B },
+       [OLYMPUS_LUT_CHAN_248950_IDX] = { 9958, 0x0, 0x37, 0xA4FA5, 0x67C },
+       [OLYMPUS_LUT_CHAN_249075_IDX] = { 9963, 0x0, 0x37, 0xB3333, 0x67D },
+       [OLYMPUS_LUT_CHAN_249200_IDX] = { 9968, 0x0, 0x37, 0xC16C1, 0x67D },
+       [OLYMPUS_LUT_CHAN_249325_IDX] = { 9973, 0x0, 0x37, 0xCFA50, 0x67E },
+       [OLYMPUS_LUT_CHAN_249450_IDX] = { 9978, 0x0, 0x37, 0xDDDDE, 0x67F },
+       [OLYMPUS_LUT_CHAN_249575_IDX] = { 9983, 0x0, 0x37, 0xEC16C, 0x680 },
+       [OLYMPUS_LUT_CHAN_249700_IDX] = { 9988, 0x0, 0x37, 0xFA4FA, 0x681 },
+       [OLYMPUS_LUT_CHAN_249825_IDX] = { 9993, 0x0, 0x37, 0x108889, 0x682 },
+       [OLYMPUS_LUT_CHAN_249950_IDX] = { 9998, 0x0, 0x37, 0x116C17, 0x682 },
+       [OLYMPUS_LUT_CHAN_250075_IDX] = { 10003, 0x0, 0x37, 0x124FA5, 0x683 }
+};
+
+const struct olympus_lut_line olympus_lut_5g_60_mhz_s0[OLYMPUS_LUT_CHAN_5G_MAX] = {
+       [OLYMPUS_LUT_CHAN_516000_IDX] = { 20640, 0x0, 0x73, 0x38E39, 0x6BF },
+       [OLYMPUS_LUT_CHAN_516125_IDX] = { 20645, 0x0, 0x72, 0x1638E4, 0x6B8 },
+       [OLYMPUS_LUT_CHAN_516250_IDX] = { 20650, 0x0, 0x72, 0x171C72, 0x6B9 },
+       [OLYMPUS_LUT_CHAN_516375_IDX] = { 20655, 0x0, 0x72, 0x180000, 0x6B9 },
+       [OLYMPUS_LUT_CHAN_516500_IDX] = { 20660, 0x0, 0x72, 0x18E38E, 0x6BA },
+       [OLYMPUS_LUT_CHAN_516625_IDX] = { 20665, 0x0, 0x72, 0x19C71C, 0x6BA },
+       [OLYMPUS_LUT_CHAN_516750_IDX] = { 20670, 0x0, 0x72, 0x1AAAAB, 0x6BB },
+       [OLYMPUS_LUT_CHAN_516875_IDX] = { 20675, 0x0, 0x72, 0x1B8E39, 0x6BB },
+       [OLYMPUS_LUT_CHAN_517000_IDX] = { 20680, 0x0, 0x72, 0x1C71C7, 0x6BB },
+       [OLYMPUS_LUT_CHAN_517125_IDX] = { 20685, 0x0, 0x72, 0x1D5555, 0x6BC },
+       [OLYMPUS_LUT_CHAN_517250_IDX] = { 20690, 0x0, 0x72, 0x1E38E4, 0x6BC },
+       [OLYMPUS_LUT_CHAN_517375_IDX] = { 20695, 0x0, 0x72, 0x1F1C72, 0x6BD },
+       [OLYMPUS_LUT_CHAN_517500_IDX] = { 20700, 0x0, 0x73, 0x0, 0x6BD },
+       [OLYMPUS_LUT_CHAN_517625_IDX] = { 20705, 0x0, 0x73, 0xE38E, 0x6BD },
+       [OLYMPUS_LUT_CHAN_517750_IDX] = { 20710, 0x0, 0x73, 0x1C71C, 0x6BE },
+       [OLYMPUS_LUT_CHAN_517875_IDX] = { 20715, 0x0, 0x73, 0x2AAAB, 0x6BE },
+       [OLYMPUS_LUT_CHAN_518000_IDX] = { 20720, 0x0, 0x73, 0x38E39, 0x6BF },
+       [OLYMPUS_LUT_CHAN_518125_IDX] = { 20725, 0x0, 0x73, 0x471C7, 0x6BF },
+       [OLYMPUS_LUT_CHAN_518250_IDX] = { 20730, 0x0, 0x73, 0x55555, 0x6C0 },
+       [OLYMPUS_LUT_CHAN_518375_IDX] = { 20735, 0x0, 0x73, 0x638E4, 0x6C0 },
+       [OLYMPUS_LUT_CHAN_518500_IDX] = { 20740, 0x0, 0x73, 0x71C72, 0x6C0 },
+       [OLYMPUS_LUT_CHAN_518625_IDX] = { 20745, 0x0, 0x73, 0x80000, 0x6C1 },
+       [OLYMPUS_LUT_CHAN_518750_IDX] = { 20750, 0x0, 0x73, 0x8E38E, 0x6C1 },
+       [OLYMPUS_LUT_CHAN_518875_IDX] = { 20755, 0x0, 0x73, 0x9C71C, 0x6C2 },
+       [OLYMPUS_LUT_CHAN_519000_IDX] = { 20760, 0x0, 0x73, 0xAAAAB, 0x6C2 },
+       [OLYMPUS_LUT_CHAN_519125_IDX] = { 20765, 0x0, 0x73, 0xB8E39, 0x6C2 },
+       [OLYMPUS_LUT_CHAN_519250_IDX] = { 20770, 0x0, 0x73, 0xC71C7, 0x6C3 },
+       [OLYMPUS_LUT_CHAN_519375_IDX] = { 20775, 0x0, 0x73, 0xD5555, 0x6C3 },
+       [OLYMPUS_LUT_CHAN_519500_IDX] = { 20780, 0x0, 0x73, 0xE38E4, 0x6C4 },
+       [OLYMPUS_LUT_CHAN_519625_IDX] = { 20785, 0x0, 0x73, 0xF1C72, 0x6C4 },
+       [OLYMPUS_LUT_CHAN_519750_IDX] = { 20790, 0x0, 0x73, 0x100000, 0x6C5 },
+       [OLYMPUS_LUT_CHAN_519875_IDX] = { 20795, 0x0, 0x73, 0x10E38E, 0x6C5 },
+       [OLYMPUS_LUT_CHAN_520000_IDX] = { 20800, 0x1, 0x73, 0x11C71C, 0x6C5 },
+       [OLYMPUS_LUT_CHAN_520125_IDX] = { 20805, 0x1, 0x73, 0x12AAAB, 0x6C6 },
+       [OLYMPUS_LUT_CHAN_520250_IDX] = { 20810, 0x1, 0x73, 0x138E39, 0x6C6 },
+       [OLYMPUS_LUT_CHAN_520375_IDX] = { 20815, 0x1, 0x73, 0x1471C7, 0x6C7 },
+       [OLYMPUS_LUT_CHAN_520500_IDX] = { 20820, 0x1, 0x73, 0x155555, 0x6C7 },
+       [OLYMPUS_LUT_CHAN_520625_IDX] = { 20825, 0x1, 0x73, 0x1638E4, 0x6C7 },
+       [OLYMPUS_LUT_CHAN_520750_IDX] = { 20830, 0x1, 0x73, 0x171C72, 0x6C8 },
+       [OLYMPUS_LUT_CHAN_520875_IDX] = { 20835, 0x1, 0x73, 0x180000, 0x6C8 },
+       [OLYMPUS_LUT_CHAN_521000_IDX] = { 20840, 0x1, 0x73, 0x18E38E, 0x6C9 },
+       [OLYMPUS_LUT_CHAN_521125_IDX] = { 20845, 0x1, 0x73, 0x19C71C, 0x6C9 },
+       [OLYMPUS_LUT_CHAN_521250_IDX] = { 20850, 0x1, 0x73, 0x1AAAAB, 0x6CA },
+       [OLYMPUS_LUT_CHAN_521375_IDX] = { 20855, 0x1, 0x73, 0x1B8E39, 0x6CA },
+       [OLYMPUS_LUT_CHAN_521500_IDX] = { 20860, 0x1, 0x73, 0x1C71C7, 0x6CA },
+       [OLYMPUS_LUT_CHAN_521625_IDX] = { 20865, 0x1, 0x73, 0x1D5555, 0x6CB },
+       [OLYMPUS_LUT_CHAN_521750_IDX] = { 20870, 0x1, 0x73, 0x1E38E4, 0x6CB },
+       [OLYMPUS_LUT_CHAN_521875_IDX] = { 20875, 0x1, 0x73, 0x1F1C72, 0x6CC },
+       [OLYMPUS_LUT_CHAN_522000_IDX] = { 20880, 0x1, 0x74, 0x0, 0x6CC },
+       [OLYMPUS_LUT_CHAN_522125_IDX] = { 20885, 0x1, 0x74, 0xE38E, 0x6CC },
+       [OLYMPUS_LUT_CHAN_522250_IDX] = { 20890, 0x1, 0x74, 0x1C71C, 0x6CD },
+       [OLYMPUS_LUT_CHAN_522375_IDX] = { 20895, 0x1, 0x74, 0x2AAAB, 0x6CD },
+       [OLYMPUS_LUT_CHAN_522500_IDX] = { 20900, 0x1, 0x74, 0x38E39, 0x6CE },
+       [OLYMPUS_LUT_CHAN_522625_IDX] = { 20905, 0x1, 0x74, 0x471C7, 0x6CE },
+       [OLYMPUS_LUT_CHAN_522750_IDX] = { 20910, 0x1, 0x74, 0x55555, 0x6CF },
+       [OLYMPUS_LUT_CHAN_522875_IDX] = { 20915, 0x1, 0x74, 0x638E4, 0x6CF },
+       [OLYMPUS_LUT_CHAN_523000_IDX] = { 20920, 0x1, 0x74, 0x71C72, 0x6CF },
+       [OLYMPUS_LUT_CHAN_523125_IDX] = { 20925, 0x1, 0x74, 0x80000, 0x6D0 },
+       [OLYMPUS_LUT_CHAN_523250_IDX] = { 20930, 0x1, 0x74, 0x8E38E, 0x6D0 },
+       [OLYMPUS_LUT_CHAN_523375_IDX] = { 20935, 0x1, 0x74, 0x9C71C, 0x6D1 },
+       [OLYMPUS_LUT_CHAN_523500_IDX] = { 20940, 0x1, 0x74, 0xAAAAB, 0x6D1 },
+       [OLYMPUS_LUT_CHAN_523625_IDX] = { 20945, 0x1, 0x74, 0xB8E39, 0x6D1 },
+       [OLYMPUS_LUT_CHAN_523750_IDX] = { 20950, 0x1, 0x74, 0xC71C7, 0x6D2 },
+       [OLYMPUS_LUT_CHAN_523875_IDX] = { 20955, 0x1, 0x74, 0xD5555, 0x6D2 },
+       [OLYMPUS_LUT_CHAN_524000_IDX] = { 20960, 0x1, 0x74, 0xE38E4, 0x6D3 },
+       [OLYMPUS_LUT_CHAN_524125_IDX] = { 20965, 0x1, 0x74, 0xF1C72, 0x6D3 },
+       [OLYMPUS_LUT_CHAN_524250_IDX] = { 20970, 0x1, 0x74, 0x100000, 0x6D4 },
+       [OLYMPUS_LUT_CHAN_524375_IDX] = { 20975, 0x1, 0x74, 0x10E38E, 0x6D4 },
+       [OLYMPUS_LUT_CHAN_524500_IDX] = { 20980, 0x1, 0x74, 0x11C71C, 0x6D4 },
+       [OLYMPUS_LUT_CHAN_524625_IDX] = { 20985, 0x1, 0x74, 0x12AAAB, 0x6D5 },
+       [OLYMPUS_LUT_CHAN_524750_IDX] = { 20990, 0x1, 0x74, 0x138E39, 0x6D5 },
+       [OLYMPUS_LUT_CHAN_524875_IDX] = { 20995, 0x1, 0x74, 0x1471C7, 0x6D6 },
+       [OLYMPUS_LUT_CHAN_525000_IDX] = { 21000, 0x1, 0x74, 0x155555, 0x6D6 },
+       [OLYMPUS_LUT_CHAN_525125_IDX] = { 21005, 0x1, 0x74, 0x1638E4, 0x6D6 },
+       [OLYMPUS_LUT_CHAN_525250_IDX] = { 21010, 0x1, 0x74, 0x171C72, 0x6D7 },
+       [OLYMPUS_LUT_CHAN_525375_IDX] = { 21015, 0x1, 0x74, 0x180000, 0x6D7 },
+       [OLYMPUS_LUT_CHAN_525500_IDX] = { 21020, 0x1, 0x74, 0x18E38E, 0x6D8 },
+       [OLYMPUS_LUT_CHAN_525625_IDX] = { 21025, 0x1, 0x74, 0x19C71C, 0x6D8 },
+       [OLYMPUS_LUT_CHAN_525750_IDX] = { 21030, 0x1, 0x74, 0x1AAAAB, 0x6D9 },
+       [OLYMPUS_LUT_CHAN_525875_IDX] = { 21035, 0x1, 0x74, 0x1B8E39, 0x6D9 },
+       [OLYMPUS_LUT_CHAN_526000_IDX] = { 21040, 0x1, 0x74, 0x1C71C7, 0x6D9 },
+       [OLYMPUS_LUT_CHAN_526125_IDX] = { 21045, 0x1, 0x74, 0x1D5555, 0x6DA },
+       [OLYMPUS_LUT_CHAN_526250_IDX] = { 21050, 0x1, 0x74, 0x1E38E4, 0x6DA },
+       [OLYMPUS_LUT_CHAN_526375_IDX] = { 21055, 0x1, 0x74, 0x1F1C72, 0x6DB },
+       [OLYMPUS_LUT_CHAN_526500_IDX] = { 21060, 0x1, 0x75, 0x0, 0x6DB },
+       [OLYMPUS_LUT_CHAN_526625_IDX] = { 21065, 0x1, 0x75, 0xE38E, 0x6DB },
+       [OLYMPUS_LUT_CHAN_526750_IDX] = { 21070, 0x1, 0x75, 0x1C71C, 0x6DC },
+       [OLYMPUS_LUT_CHAN_526875_IDX] = { 21075, 0x1, 0x75, 0x2AAAB, 0x6DC },
+       [OLYMPUS_LUT_CHAN_527000_IDX] = { 21080, 0x1, 0x75, 0x38E39, 0x6DD },
+       [OLYMPUS_LUT_CHAN_527125_IDX] = { 21085, 0x1, 0x75, 0x471C7, 0x6DD },
+       [OLYMPUS_LUT_CHAN_527250_IDX] = { 21090, 0x1, 0x75, 0x55555, 0x6DE },
+       [OLYMPUS_LUT_CHAN_527375_IDX] = { 21095, 0x1, 0x75, 0x638E4, 0x6DE },
+       [OLYMPUS_LUT_CHAN_527500_IDX] = { 21100, 0x1, 0x75, 0x71C72, 0x6DE },
+       [OLYMPUS_LUT_CHAN_527625_IDX] = { 21105, 0x1, 0x75, 0x80000, 0x6DF },
+       [OLYMPUS_LUT_CHAN_527750_IDX] = { 21110, 0x1, 0x75, 0x8E38E, 0x6DF },
+       [OLYMPUS_LUT_CHAN_527875_IDX] = { 21115, 0x1, 0x75, 0x9C71C, 0x6E0 },
+       [OLYMPUS_LUT_CHAN_528000_IDX] = { 21120, 0x1, 0x75, 0xAAAAB, 0x6E0 },
+       [OLYMPUS_LUT_CHAN_528125_IDX] = { 21125, 0x1, 0x75, 0xB8E39, 0x6E0 },
+       [OLYMPUS_LUT_CHAN_528250_IDX] = { 21130, 0x1, 0x75, 0xC71C7, 0x6E1 },
+       [OLYMPUS_LUT_CHAN_528375_IDX] = { 21135, 0x1, 0x75, 0xD5555, 0x6E1 },
+       [OLYMPUS_LUT_CHAN_528500_IDX] = { 21140, 0x1, 0x75, 0xE38E4, 0x6E2 },
+       [OLYMPUS_LUT_CHAN_528625_IDX] = { 21145, 0x1, 0x75, 0xF1C72, 0x6E2 },
+       [OLYMPUS_LUT_CHAN_528750_IDX] = { 21150, 0x1, 0x75, 0x100000, 0x6E3 },
+       [OLYMPUS_LUT_CHAN_528875_IDX] = { 21155, 0x1, 0x75, 0x10E38E, 0x6E3 },
+       [OLYMPUS_LUT_CHAN_529000_IDX] = { 21160, 0x1, 0x75, 0x11C71C, 0x6E3 },
+       [OLYMPUS_LUT_CHAN_529125_IDX] = { 21165, 0x1, 0x75, 0x12AAAB, 0x6E4 },
+       [OLYMPUS_LUT_CHAN_529250_IDX] = { 21170, 0x1, 0x75, 0x138E39, 0x6E4 },
+       [OLYMPUS_LUT_CHAN_529375_IDX] = { 21175, 0x1, 0x75, 0x1471C7, 0x6E5 },
+       [OLYMPUS_LUT_CHAN_529500_IDX] = { 21180, 0x1, 0x75, 0x155555, 0x6E5 },
+       [OLYMPUS_LUT_CHAN_529625_IDX] = { 21185, 0x1, 0x75, 0x1638E4, 0x6E5 },
+       [OLYMPUS_LUT_CHAN_529750_IDX] = { 21190, 0x1, 0x75, 0x171C72, 0x6E6 },
+       [OLYMPUS_LUT_CHAN_529875_IDX] = { 21195, 0x1, 0x75, 0x180000, 0x6E6 },
+       [OLYMPUS_LUT_CHAN_530000_IDX] = { 21200, 0x1, 0x75, 0x18E38E, 0x6E7 },
+       [OLYMPUS_LUT_CHAN_530125_IDX] = { 21205, 0x1, 0x75, 0x19C71C, 0x6E7 },
+       [OLYMPUS_LUT_CHAN_530250_IDX] = { 21210, 0x1, 0x75, 0x1AAAAB, 0x6E8 },
+       [OLYMPUS_LUT_CHAN_530375_IDX] = { 21215, 0x1, 0x75, 0x1B8E39, 0x6E8 },
+       [OLYMPUS_LUT_CHAN_530500_IDX] = { 21220, 0x1, 0x75, 0x1C71C7, 0x6E8 },
+       [OLYMPUS_LUT_CHAN_530625_IDX] = { 21225, 0x1, 0x75, 0x1D5555, 0x6E9 },
+       [OLYMPUS_LUT_CHAN_530750_IDX] = { 21230, 0x1, 0x75, 0x1E38E4, 0x6E9 },
+       [OLYMPUS_LUT_CHAN_530875_IDX] = { 21235, 0x1, 0x75, 0x1F1C72, 0x6EA },
+       [OLYMPUS_LUT_CHAN_531000_IDX] = { 21240, 0x1, 0x76, 0x0, 0x6EA },
+       [OLYMPUS_LUT_CHAN_531125_IDX] = { 21245, 0x1, 0x76, 0xE38E, 0x6EA },
+       [OLYMPUS_LUT_CHAN_531250_IDX] = { 21250, 0x1, 0x76, 0x1C71C, 0x6EB },
+       [OLYMPUS_LUT_CHAN_531375_IDX] = { 21255, 0x1, 0x76, 0x2AAAB, 0x6EB },
+       [OLYMPUS_LUT_CHAN_531500_IDX] = { 21260, 0x1, 0x76, 0x38E39, 0x6EC },
+       [OLYMPUS_LUT_CHAN_531625_IDX] = { 21265, 0x1, 0x76, 0x471C7, 0x6EC },
+       [OLYMPUS_LUT_CHAN_531750_IDX] = { 21270, 0x1, 0x76, 0x55555, 0x6ED },
+       [OLYMPUS_LUT_CHAN_531875_IDX] = { 21275, 0x1, 0x76, 0x638E4, 0x6ED },
+       [OLYMPUS_LUT_CHAN_532000_IDX] = { 21280, 0x1, 0x76, 0x71C72, 0x6ED },
+       [OLYMPUS_LUT_CHAN_532125_IDX] = { 21285, 0x1, 0x76, 0x80000, 0x6EE },
+       [OLYMPUS_LUT_CHAN_532250_IDX] = { 21290, 0x1, 0x76, 0x8E38E, 0x6EE },
+       [OLYMPUS_LUT_CHAN_532375_IDX] = { 21295, 0x1, 0x76, 0x9C71C, 0x6EF },
+       [OLYMPUS_LUT_CHAN_532500_IDX] = { 21300, 0x1, 0x76, 0xAAAAB, 0x6EF },
+       [OLYMPUS_LUT_CHAN_532625_IDX] = { 21305, 0x1, 0x76, 0xB8E39, 0x6EF },
+       [OLYMPUS_LUT_CHAN_532750_IDX] = { 21310, 0x1, 0x76, 0xC71C7, 0x6F0 },
+       [OLYMPUS_LUT_CHAN_532875_IDX] = { 21315, 0x1, 0x76, 0xD5555, 0x6F0 },
+       [OLYMPUS_LUT_CHAN_533000_IDX] = { 21320, 0x1, 0x76, 0xE38E4, 0x6F1 },
+       [OLYMPUS_LUT_CHAN_533125_IDX] = { 21325, 0x1, 0x76, 0xF1C72, 0x6F1 },
+       [OLYMPUS_LUT_CHAN_533250_IDX] = { 21330, 0x1, 0x76, 0x100000, 0x6F2 },
+       [OLYMPUS_LUT_CHAN_533375_IDX] = { 21335, 0x1, 0x76, 0x10E38E, 0x6F2 },
+       [OLYMPUS_LUT_CHAN_533500_IDX] = { 21340, 0x1, 0x76, 0x11C71C, 0x6F2 },
+       [OLYMPUS_LUT_CHAN_533625_IDX] = { 21345, 0x1, 0x76, 0x12AAAB, 0x6F3 },
+       [OLYMPUS_LUT_CHAN_533750_IDX] = { 21350, 0x1, 0x76, 0x138E39, 0x6F3 },
+       [OLYMPUS_LUT_CHAN_533875_IDX] = { 21355, 0x1, 0x76, 0x1471C7, 0x6F4 },
+       [OLYMPUS_LUT_CHAN_534000_IDX] = { 21360, 0x1, 0x76, 0x155555, 0x6F4 },
+       [OLYMPUS_LUT_CHAN_534125_IDX] = { 21365, 0x1, 0x76, 0x1638E4, 0x6F4 },
+       [OLYMPUS_LUT_CHAN_534250_IDX] = { 21370, 0x1, 0x76, 0x171C72, 0x6F5 },
+       [OLYMPUS_LUT_CHAN_534375_IDX] = { 21375, 0x1, 0x76, 0x180000, 0x6F5 },
+       [OLYMPUS_LUT_CHAN_534500_IDX] = { 21380, 0x1, 0x76, 0x18E38E, 0x6F6 },
+       [OLYMPUS_LUT_CHAN_534625_IDX] = { 21385, 0x1, 0x76, 0x19C71C, 0x6F6 },
+       [OLYMPUS_LUT_CHAN_534750_IDX] = { 21390, 0x1, 0x76, 0x1AAAAB, 0x6F7 },
+       [OLYMPUS_LUT_CHAN_534875_IDX] = { 21395, 0x1, 0x76, 0x1B8E39, 0x6F7 },
+       [OLYMPUS_LUT_CHAN_535000_IDX] = { 21400, 0x1, 0x76, 0x1C71C7, 0x6F7 },
+       [OLYMPUS_LUT_CHAN_535125_IDX] = { 21405, 0x1, 0x76, 0x1D5555, 0x6F8 },
+       [OLYMPUS_LUT_CHAN_535250_IDX] = { 21410, 0x1, 0x76, 0x1E38E4, 0x6F8 },
+       [OLYMPUS_LUT_CHAN_535375_IDX] = { 21415, 0x1, 0x76, 0x1F1C72, 0x6F9 },
+       [OLYMPUS_LUT_CHAN_535500_IDX] = { 21420, 0x1, 0x77, 0x0, 0x6F9 },
+       [OLYMPUS_LUT_CHAN_535625_IDX] = { 21425, 0x1, 0x77, 0xE38E, 0x6F9 },
+       [OLYMPUS_LUT_CHAN_535750_IDX] = { 21430, 0x1, 0x77, 0x1C71C, 0x6FA },
+       [OLYMPUS_LUT_CHAN_535875_IDX] = { 21435, 0x1, 0x77, 0x2AAAB, 0x6FA },
+       [OLYMPUS_LUT_CHAN_536000_IDX] = { 21440, 0x1, 0x77, 0x38E39, 0x6FB },
+       [OLYMPUS_LUT_CHAN_536125_IDX] = { 21445, 0x1, 0x77, 0x471C7, 0x6FB },
+       [OLYMPUS_LUT_CHAN_536250_IDX] = { 21450, 0x1, 0x77, 0x55555, 0x6FC },
+       [OLYMPUS_LUT_CHAN_536375_IDX] = { 21455, 0x1, 0x77, 0x638E4, 0x6FC },
+       [OLYMPUS_LUT_CHAN_536500_IDX] = { 21460, 0x1, 0x77, 0x71C72, 0x6FC },
+       [OLYMPUS_LUT_CHAN_536625_IDX] = { 21465, 0x1, 0x77, 0x80000, 0x6FD },
+       [OLYMPUS_LUT_CHAN_536750_IDX] = { 21470, 0x1, 0x77, 0x8E38E, 0x6FD },
+       [OLYMPUS_LUT_CHAN_536875_IDX] = { 21475, 0x1, 0x77, 0x9C71C, 0x6FE },
+       [OLYMPUS_LUT_CHAN_537000_IDX] = { 21480, 0x1, 0x77, 0xAAAAB, 0x6FE },
+       [OLYMPUS_LUT_CHAN_537125_IDX] = { 21485, 0x1, 0x77, 0xB8E39, 0x6FE },
+       [OLYMPUS_LUT_CHAN_537250_IDX] = { 21490, 0x1, 0x77, 0xC71C7, 0x6FF },
+       [OLYMPUS_LUT_CHAN_537375_IDX] = { 21495, 0x1, 0x77, 0xD5555, 0x6FF },
+       [OLYMPUS_LUT_CHAN_537500_IDX] = { 21500, 0x1, 0x77, 0xE38E4, 0x700 },
+       [OLYMPUS_LUT_CHAN_537625_IDX] = { 21505, 0x1, 0x77, 0xF1C72, 0x700 },
+       [OLYMPUS_LUT_CHAN_537750_IDX] = { 21510, 0x1, 0x77, 0x100000, 0x701 },
+       [OLYMPUS_LUT_CHAN_537875_IDX] = { 21515, 0x1, 0x77, 0x10E38E, 0x701 },
+       [OLYMPUS_LUT_CHAN_538000_IDX] = { 21520, 0x1, 0x77, 0x11C71C, 0x701 },
+       [OLYMPUS_LUT_CHAN_538125_IDX] = { 21525, 0x1, 0x77, 0x12AAAB, 0x702 },
+       [OLYMPUS_LUT_CHAN_538250_IDX] = { 21530, 0x1, 0x77, 0x138E39, 0x702 },
+       [OLYMPUS_LUT_CHAN_538375_IDX] = { 21535, 0x1, 0x77, 0x1471C7, 0x703 },
+       [OLYMPUS_LUT_CHAN_538500_IDX] = { 21540, 0x1, 0x77, 0x155555, 0x703 },
+       [OLYMPUS_LUT_CHAN_538625_IDX] = { 21545, 0x1, 0x77, 0x1638E4, 0x703 },
+       [OLYMPUS_LUT_CHAN_538750_IDX] = { 21550, 0x1, 0x77, 0x171C72, 0x704 },
+       [OLYMPUS_LUT_CHAN_538875_IDX] = { 21555, 0x1, 0x77, 0x180000, 0x704 },
+       [OLYMPUS_LUT_CHAN_539000_IDX] = { 21560, 0x1, 0x77, 0x18E38E, 0x705 },
+       [OLYMPUS_LUT_CHAN_539125_IDX] = { 21565, 0x1, 0x77, 0x19C71C, 0x705 },
+       [OLYMPUS_LUT_CHAN_539250_IDX] = { 21570, 0x1, 0x77, 0x1AAAAB, 0x706 },
+       [OLYMPUS_LUT_CHAN_539375_IDX] = { 21575, 0x1, 0x77, 0x1B8E39, 0x706 },
+       [OLYMPUS_LUT_CHAN_539500_IDX] = { 21580, 0x1, 0x77, 0x1C71C7, 0x706 },
+       [OLYMPUS_LUT_CHAN_539625_IDX] = { 21585, 0x1, 0x77, 0x1D5555, 0x707 },
+       [OLYMPUS_LUT_CHAN_539750_IDX] = { 21590, 0x1, 0x77, 0x1E38E4, 0x707 },
+       [OLYMPUS_LUT_CHAN_539875_IDX] = { 21595, 0x1, 0x77, 0x1F1C72, 0x708 },
+       [OLYMPUS_LUT_CHAN_540000_IDX] = { 21600, 0x1, 0x78, 0x0, 0x708 },
+       [OLYMPUS_LUT_CHAN_540125_IDX] = { 21605, 0x1, 0x78, 0xE38E, 0x708 },
+       [OLYMPUS_LUT_CHAN_540250_IDX] = { 21610, 0x1, 0x78, 0x1C71C, 0x709 },
+       [OLYMPUS_LUT_CHAN_540375_IDX] = { 21615, 0x1, 0x78, 0x2AAAB, 0x709 },
+       [OLYMPUS_LUT_CHAN_540500_IDX] = { 21620, 0x1, 0x78, 0x38E39, 0x70A },
+       [OLYMPUS_LUT_CHAN_540625_IDX] = { 21625, 0x1, 0x78, 0x471C7, 0x70A },
+       [OLYMPUS_LUT_CHAN_540750_IDX] = { 21630, 0x1, 0x78, 0x55555, 0x70B },
+       [OLYMPUS_LUT_CHAN_540875_IDX] = { 21635, 0x1, 0x78, 0x638E4, 0x70B },
+       [OLYMPUS_LUT_CHAN_541000_IDX] = { 21640, 0x1, 0x78, 0x71C72, 0x70B },
+       [OLYMPUS_LUT_CHAN_541125_IDX] = { 21645, 0x1, 0x78, 0x80000, 0x70C },
+       [OLYMPUS_LUT_CHAN_541250_IDX] = { 21650, 0x1, 0x78, 0x8E38E, 0x70C },
+       [OLYMPUS_LUT_CHAN_541375_IDX] = { 21655, 0x1, 0x78, 0x9C71C, 0x70D },
+       [OLYMPUS_LUT_CHAN_541500_IDX] = { 21660, 0x1, 0x78, 0xAAAAB, 0x70D },
+       [OLYMPUS_LUT_CHAN_541625_IDX] = { 21665, 0x1, 0x78, 0xB8E39, 0x70D },
+       [OLYMPUS_LUT_CHAN_541750_IDX] = { 21670, 0x1, 0x78, 0xC71C7, 0x70E },
+       [OLYMPUS_LUT_CHAN_541875_IDX] = { 21675, 0x1, 0x78, 0xD5555, 0x70E },
+       [OLYMPUS_LUT_CHAN_542000_IDX] = { 21680, 0x1, 0x78, 0xE38E4, 0x70F },
+       [OLYMPUS_LUT_CHAN_542125_IDX] = { 21685, 0x1, 0x78, 0xF1C72, 0x70F },
+       [OLYMPUS_LUT_CHAN_542250_IDX] = { 21690, 0x1, 0x78, 0x100000, 0x710 },
+       [OLYMPUS_LUT_CHAN_542375_IDX] = { 21695, 0x1, 0x78, 0x10E38E, 0x710 },
+       [OLYMPUS_LUT_CHAN_542500_IDX] = { 21700, 0x1, 0x78, 0x11C71C, 0x710 },
+       [OLYMPUS_LUT_CHAN_542625_IDX] = { 21705, 0x1, 0x78, 0x12AAAB, 0x711 },
+       [OLYMPUS_LUT_CHAN_542750_IDX] = { 21710, 0x1, 0x78, 0x138E39, 0x711 },
+       [OLYMPUS_LUT_CHAN_542875_IDX] = { 21715, 0x1, 0x78, 0x1471C7, 0x712 },
+       [OLYMPUS_LUT_CHAN_543000_IDX] = { 21720, 0x1, 0x78, 0x155555, 0x712 },
+       [OLYMPUS_LUT_CHAN_543125_IDX] = { 21725, 0x1, 0x78, 0x1638E4, 0x712 },
+       [OLYMPUS_LUT_CHAN_543250_IDX] = { 21730, 0x1, 0x78, 0x171C72, 0x713 },
+       [OLYMPUS_LUT_CHAN_543375_IDX] = { 21735, 0x1, 0x78, 0x180000, 0x713 },
+       [OLYMPUS_LUT_CHAN_543500_IDX] = { 21740, 0x1, 0x78, 0x18E38E, 0x714 },
+       [OLYMPUS_LUT_CHAN_543625_IDX] = { 21745, 0x1, 0x78, 0x19C71C, 0x714 },
+       [OLYMPUS_LUT_CHAN_543750_IDX] = { 21750, 0x1, 0x78, 0x1AAAAB, 0x715 },
+       [OLYMPUS_LUT_CHAN_543875_IDX] = { 21755, 0x1, 0x78, 0x1B8E39, 0x715 },
+       [OLYMPUS_LUT_CHAN_544000_IDX] = { 21760, 0x1, 0x78, 0x1C71C7, 0x715 },
+       [OLYMPUS_LUT_CHAN_544125_IDX] = { 21765, 0x1, 0x78, 0x1D5555, 0x716 },
+       [OLYMPUS_LUT_CHAN_544250_IDX] = { 21770, 0x1, 0x78, 0x1E38E4, 0x716 },
+       [OLYMPUS_LUT_CHAN_544375_IDX] = { 21775, 0x1, 0x78, 0x1F1C72, 0x717 },
+       [OLYMPUS_LUT_CHAN_544500_IDX] = { 21780, 0x1, 0x79, 0x0, 0x717 },
+       [OLYMPUS_LUT_CHAN_544625_IDX] = { 21785, 0x1, 0x79, 0xE38E, 0x717 },
+       [OLYMPUS_LUT_CHAN_544750_IDX] = { 21790, 0x1, 0x79, 0x1C71C, 0x718 },
+       [OLYMPUS_LUT_CHAN_544875_IDX] = { 21795, 0x1, 0x79, 0x2AAAB, 0x718 },
+       [OLYMPUS_LUT_CHAN_545000_IDX] = { 21800, 0x1, 0x79, 0x38E39, 0x719 },
+       [OLYMPUS_LUT_CHAN_545125_IDX] = { 21805, 0x1, 0x79, 0x471C7, 0x719 },
+       [OLYMPUS_LUT_CHAN_545250_IDX] = { 21810, 0x1, 0x79, 0x55555, 0x71A },
+       [OLYMPUS_LUT_CHAN_545375_IDX] = { 21815, 0x1, 0x79, 0x638E4, 0x71A },
+       [OLYMPUS_LUT_CHAN_545500_IDX] = { 21820, 0x1, 0x79, 0x71C72, 0x71A },
+       [OLYMPUS_LUT_CHAN_545625_IDX] = { 21825, 0x1, 0x79, 0x80000, 0x71B },
+       [OLYMPUS_LUT_CHAN_545750_IDX] = { 21830, 0x1, 0x79, 0x8E38E, 0x71B },
+       [OLYMPUS_LUT_CHAN_545875_IDX] = { 21835, 0x1, 0x79, 0x9C71C, 0x71C },
+       [OLYMPUS_LUT_CHAN_546000_IDX] = { 21840, 0x1, 0x79, 0xAAAAB, 0x71C },
+       [OLYMPUS_LUT_CHAN_546125_IDX] = { 21845, 0x1, 0x79, 0xB8E39, 0x71C },
+       [OLYMPUS_LUT_CHAN_546250_IDX] = { 21850, 0x1, 0x79, 0xC71C7, 0x71D },
+       [OLYMPUS_LUT_CHAN_546375_IDX] = { 21855, 0x1, 0x79, 0xD5555, 0x71D },
+       [OLYMPUS_LUT_CHAN_546500_IDX] = { 21860, 0x1, 0x79, 0xE38E4, 0x71E },
+       [OLYMPUS_LUT_CHAN_546625_IDX] = { 21865, 0x1, 0x79, 0xF1C72, 0x71E },
+       [OLYMPUS_LUT_CHAN_546750_IDX] = { 21870, 0x1, 0x79, 0x100000, 0x71F },
+       [OLYMPUS_LUT_CHAN_546875_IDX] = { 21875, 0x1, 0x79, 0x10E38E, 0x71F },
+       [OLYMPUS_LUT_CHAN_547000_IDX] = { 21880, 0x1, 0x79, 0x11C71C, 0x71F },
+       [OLYMPUS_LUT_CHAN_547125_IDX] = { 21885, 0x1, 0x79, 0x12AAAB, 0x720 },
+       [OLYMPUS_LUT_CHAN_547250_IDX] = { 21890, 0x1, 0x79, 0x138E39, 0x720 },
+       [OLYMPUS_LUT_CHAN_547375_IDX] = { 21895, 0x1, 0x79, 0x1471C7, 0x721 },
+       [OLYMPUS_LUT_CHAN_547500_IDX] = { 21900, 0x1, 0x79, 0x155555, 0x721 },
+       [OLYMPUS_LUT_CHAN_547625_IDX] = { 21905, 0x1, 0x79, 0x1638E4, 0x721 },
+       [OLYMPUS_LUT_CHAN_547750_IDX] = { 21910, 0x1, 0x79, 0x171C72, 0x722 },
+       [OLYMPUS_LUT_CHAN_547875_IDX] = { 21915, 0x1, 0x79, 0x180000, 0x722 },
+       [OLYMPUS_LUT_CHAN_548000_IDX] = { 21920, 0x1, 0x79, 0x18E38E, 0x723 },
+       [OLYMPUS_LUT_CHAN_548125_IDX] = { 21925, 0x1, 0x79, 0x19C71C, 0x723 },
+       [OLYMPUS_LUT_CHAN_548250_IDX] = { 21930, 0x1, 0x79, 0x1AAAAB, 0x724 },
+       [OLYMPUS_LUT_CHAN_548375_IDX] = { 21935, 0x1, 0x79, 0x1B8E39, 0x724 },
+       [OLYMPUS_LUT_CHAN_548500_IDX] = { 21940, 0x1, 0x79, 0x1C71C7, 0x724 },
+       [OLYMPUS_LUT_CHAN_548625_IDX] = { 21945, 0x1, 0x79, 0x1D5555, 0x725 },
+       [OLYMPUS_LUT_CHAN_548750_IDX] = { 21950, 0x1, 0x79, 0x1E38E4, 0x725 },
+       [OLYMPUS_LUT_CHAN_548875_IDX] = { 21955, 0x1, 0x79, 0x1F1C72, 0x726 },
+       [OLYMPUS_LUT_CHAN_549000_IDX] = { 21960, 0x1, 0x7A, 0x0, 0x726 },
+       [OLYMPUS_LUT_CHAN_549125_IDX] = { 21965, 0x1, 0x7A, 0xE38E, 0x726 },
+       [OLYMPUS_LUT_CHAN_549250_IDX] = { 21970, 0x1, 0x7A, 0x1C71C, 0x727 },
+       [OLYMPUS_LUT_CHAN_549375_IDX] = { 21975, 0x1, 0x7A, 0x2AAAB, 0x727 },
+       [OLYMPUS_LUT_CHAN_549500_IDX] = { 21980, 0x1, 0x7A, 0x38E39, 0x728 },
+       [OLYMPUS_LUT_CHAN_549625_IDX] = { 21985, 0x1, 0x7A, 0x471C7, 0x728 },
+       [OLYMPUS_LUT_CHAN_549750_IDX] = { 21990, 0x1, 0x7A, 0x55555, 0x729 },
+       [OLYMPUS_LUT_CHAN_549875_IDX] = { 21995, 0x1, 0x7A, 0x638E4, 0x729 },
+       [OLYMPUS_LUT_CHAN_550000_IDX] = { 22000, 0x1, 0x7A, 0x71C72, 0x729 },
+       [OLYMPUS_LUT_CHAN_550125_IDX] = { 22005, 0x1, 0x7A, 0x80000, 0x72A },
+       [OLYMPUS_LUT_CHAN_550250_IDX] = { 22010, 0x1, 0x7A, 0x8E38E, 0x72A },
+       [OLYMPUS_LUT_CHAN_550375_IDX] = { 22015, 0x1, 0x7A, 0x9C71C, 0x72B },
+       [OLYMPUS_LUT_CHAN_550500_IDX] = { 22020, 0x1, 0x7A, 0xAAAAB, 0x72B },
+       [OLYMPUS_LUT_CHAN_550625_IDX] = { 22025, 0x1, 0x7A, 0xB8E39, 0x72B },
+       [OLYMPUS_LUT_CHAN_550750_IDX] = { 22030, 0x1, 0x7A, 0xC71C7, 0x72C },
+       [OLYMPUS_LUT_CHAN_550875_IDX] = { 22035, 0x1, 0x7A, 0xD5555, 0x72C },
+       [OLYMPUS_LUT_CHAN_551000_IDX] = { 22040, 0x1, 0x7A, 0xE38E4, 0x72D },
+       [OLYMPUS_LUT_CHAN_551125_IDX] = { 22045, 0x1, 0x7A, 0xF1C72, 0x72D },
+       [OLYMPUS_LUT_CHAN_551250_IDX] = { 22050, 0x1, 0x7A, 0x100000, 0x72E },
+       [OLYMPUS_LUT_CHAN_551375_IDX] = { 22055, 0x1, 0x7A, 0x10E38E, 0x72E },
+       [OLYMPUS_LUT_CHAN_551500_IDX] = { 22060, 0x1, 0x7A, 0x11C71C, 0x72E },
+       [OLYMPUS_LUT_CHAN_551625_IDX] = { 22065, 0x1, 0x7A, 0x12AAAB, 0x72F },
+       [OLYMPUS_LUT_CHAN_551750_IDX] = { 22070, 0x1, 0x7A, 0x138E39, 0x72F },
+       [OLYMPUS_LUT_CHAN_551875_IDX] = { 22075, 0x1, 0x7A, 0x1471C7, 0x730 },
+       [OLYMPUS_LUT_CHAN_552000_IDX] = { 22080, 0x1, 0x7A, 0x155555, 0x730 },
+       [OLYMPUS_LUT_CHAN_552125_IDX] = { 22085, 0x1, 0x7A, 0x1638E4, 0x730 },
+       [OLYMPUS_LUT_CHAN_552250_IDX] = { 22090, 0x1, 0x7A, 0x171C72, 0x731 },
+       [OLYMPUS_LUT_CHAN_552375_IDX] = { 22095, 0x1, 0x7A, 0x180000, 0x731 },
+       [OLYMPUS_LUT_CHAN_552500_IDX] = { 22100, 0x1, 0x7A, 0x18E38E, 0x732 },
+       [OLYMPUS_LUT_CHAN_552625_IDX] = { 22105, 0x1, 0x7A, 0x19C71C, 0x732 },
+       [OLYMPUS_LUT_CHAN_552750_IDX] = { 22110, 0x1, 0x7A, 0x1AAAAB, 0x733 },
+       [OLYMPUS_LUT_CHAN_552875_IDX] = { 22115, 0x1, 0x7A, 0x1B8E39, 0x733 },
+       [OLYMPUS_LUT_CHAN_553000_IDX] = { 22120, 0x1, 0x7A, 0x1C71C7, 0x733 },
+       [OLYMPUS_LUT_CHAN_553125_IDX] = { 22125, 0x1, 0x7A, 0x1D5555, 0x734 },
+       [OLYMPUS_LUT_CHAN_553250_IDX] = { 22130, 0x1, 0x7A, 0x1E38E4, 0x734 },
+       [OLYMPUS_LUT_CHAN_553375_IDX] = { 22135, 0x1, 0x7A, 0x1F1C72, 0x735 },
+       [OLYMPUS_LUT_CHAN_553500_IDX] = { 22140, 0x1, 0x7B, 0x0, 0x735 },
+       [OLYMPUS_LUT_CHAN_553625_IDX] = { 22145, 0x1, 0x7B, 0xE38E, 0x735 },
+       [OLYMPUS_LUT_CHAN_553750_IDX] = { 22150, 0x1, 0x7B, 0x1C71C, 0x736 },
+       [OLYMPUS_LUT_CHAN_553875_IDX] = { 22155, 0x1, 0x7B, 0x2AAAB, 0x736 },
+       [OLYMPUS_LUT_CHAN_554000_IDX] = { 22160, 0x1, 0x7B, 0x38E39, 0x737 },
+       [OLYMPUS_LUT_CHAN_554125_IDX] = { 22165, 0x1, 0x7B, 0x471C7, 0x737 },
+       [OLYMPUS_LUT_CHAN_554250_IDX] = { 22170, 0x1, 0x7B, 0x55555, 0x738 },
+       [OLYMPUS_LUT_CHAN_554375_IDX] = { 22175, 0x1, 0x7B, 0x638E4, 0x738 },
+       [OLYMPUS_LUT_CHAN_554500_IDX] = { 22180, 0x1, 0x7B, 0x71C72, 0x738 },
+       [OLYMPUS_LUT_CHAN_554625_IDX] = { 22185, 0x1, 0x7B, 0x80000, 0x739 },
+       [OLYMPUS_LUT_CHAN_554750_IDX] = { 22190, 0x1, 0x7B, 0x8E38E, 0x739 },
+       [OLYMPUS_LUT_CHAN_554875_IDX] = { 22195, 0x1, 0x7B, 0x9C71C, 0x73A },
+       [OLYMPUS_LUT_CHAN_555000_IDX] = { 22200, 0x1, 0x7B, 0xAAAAB, 0x73A },
+       [OLYMPUS_LUT_CHAN_555125_IDX] = { 22205, 0x1, 0x7B, 0xB8E39, 0x73A },
+       [OLYMPUS_LUT_CHAN_555250_IDX] = { 22210, 0x1, 0x7B, 0xC71C7, 0x73B },
+       [OLYMPUS_LUT_CHAN_555375_IDX] = { 22215, 0x1, 0x7B, 0xD5555, 0x73B },
+       [OLYMPUS_LUT_CHAN_555500_IDX] = { 22220, 0x1, 0x7B, 0xE38E4, 0x73C },
+       [OLYMPUS_LUT_CHAN_555625_IDX] = { 22225, 0x1, 0x7B, 0xF1C72, 0x73C },
+       [OLYMPUS_LUT_CHAN_555750_IDX] = { 22230, 0x1, 0x7B, 0x100000, 0x73D },
+       [OLYMPUS_LUT_CHAN_555875_IDX] = { 22235, 0x1, 0x7B, 0x10E38E, 0x73D },
+       [OLYMPUS_LUT_CHAN_556000_IDX] = { 22240, 0x1, 0x7B, 0x11C71C, 0x73D },
+       [OLYMPUS_LUT_CHAN_556125_IDX] = { 22245, 0x1, 0x7B, 0x12AAAB, 0x73E },
+       [OLYMPUS_LUT_CHAN_556250_IDX] = { 22250, 0x1, 0x7B, 0x138E39, 0x73E },
+       [OLYMPUS_LUT_CHAN_556375_IDX] = { 22255, 0x1, 0x7B, 0x1471C7, 0x73F },
+       [OLYMPUS_LUT_CHAN_556500_IDX] = { 22260, 0x1, 0x7B, 0x155555, 0x73F },
+       [OLYMPUS_LUT_CHAN_556625_IDX] = { 22265, 0x1, 0x7B, 0x1638E4, 0x73F },
+       [OLYMPUS_LUT_CHAN_556750_IDX] = { 22270, 0x1, 0x7B, 0x171C72, 0x740 },
+       [OLYMPUS_LUT_CHAN_556875_IDX] = { 22275, 0x1, 0x7B, 0x180000, 0x740 },
+       [OLYMPUS_LUT_CHAN_557000_IDX] = { 22280, 0x1, 0x7B, 0x18E38E, 0x741 },
+       [OLYMPUS_LUT_CHAN_557125_IDX] = { 22285, 0x1, 0x7B, 0x19C71C, 0x741 },
+       [OLYMPUS_LUT_CHAN_557250_IDX] = { 22290, 0x1, 0x7B, 0x1AAAAB, 0x742 },
+       [OLYMPUS_LUT_CHAN_557375_IDX] = { 22295, 0x1, 0x7B, 0x1B8E39, 0x742 },
+       [OLYMPUS_LUT_CHAN_557500_IDX] = { 22300, 0x1, 0x7B, 0x1C71C7, 0x742 },
+       [OLYMPUS_LUT_CHAN_557625_IDX] = { 22305, 0x1, 0x7B, 0x1D5555, 0x743 },
+       [OLYMPUS_LUT_CHAN_557750_IDX] = { 22310, 0x1, 0x7B, 0x1E38E4, 0x743 },
+       [OLYMPUS_LUT_CHAN_557875_IDX] = { 22315, 0x1, 0x7B, 0x1F1C72, 0x744 },
+       [OLYMPUS_LUT_CHAN_558000_IDX] = { 22320, 0x1, 0x7C, 0x0, 0x744 },
+       [OLYMPUS_LUT_CHAN_558125_IDX] = { 22325, 0x1, 0x7C, 0xE38E, 0x744 },
+       [OLYMPUS_LUT_CHAN_558250_IDX] = { 22330, 0x1, 0x7C, 0x1C71C, 0x745 },
+       [OLYMPUS_LUT_CHAN_558375_IDX] = { 22335, 0x1, 0x7C, 0x2AAAB, 0x745 },
+       [OLYMPUS_LUT_CHAN_558500_IDX] = { 22340, 0x1, 0x7C, 0x38E39, 0x746 },
+       [OLYMPUS_LUT_CHAN_558625_IDX] = { 22345, 0x1, 0x7C, 0x471C7, 0x746 },
+       [OLYMPUS_LUT_CHAN_558750_IDX] = { 22350, 0x1, 0x7C, 0x55555, 0x747 },
+       [OLYMPUS_LUT_CHAN_558875_IDX] = { 22355, 0x1, 0x7C, 0x638E4, 0x747 },
+       [OLYMPUS_LUT_CHAN_559000_IDX] = { 22360, 0x1, 0x7C, 0x71C72, 0x747 },
+       [OLYMPUS_LUT_CHAN_559125_IDX] = { 22365, 0x1, 0x7C, 0x80000, 0x748 },
+       [OLYMPUS_LUT_CHAN_559250_IDX] = { 22370, 0x1, 0x7C, 0x8E38E, 0x748 },
+       [OLYMPUS_LUT_CHAN_559375_IDX] = { 22375, 0x1, 0x7C, 0x9C71C, 0x749 },
+       [OLYMPUS_LUT_CHAN_559500_IDX] = { 22380, 0x1, 0x7C, 0xAAAAB, 0x749 },
+       [OLYMPUS_LUT_CHAN_559625_IDX] = { 22385, 0x1, 0x7C, 0xB8E39, 0x749 },
+       [OLYMPUS_LUT_CHAN_559750_IDX] = { 22390, 0x1, 0x7C, 0xC71C7, 0x74A },
+       [OLYMPUS_LUT_CHAN_559875_IDX] = { 22395, 0x1, 0x7C, 0xD5555, 0x74A },
+       [OLYMPUS_LUT_CHAN_560000_IDX] = { 22400, 0x1, 0x7C, 0xE38E4, 0x74B },
+       [OLYMPUS_LUT_CHAN_560125_IDX] = { 22405, 0x1, 0x7C, 0xF1C72, 0x74B },
+       [OLYMPUS_LUT_CHAN_560250_IDX] = { 22410, 0x1, 0x7C, 0x100000, 0x74C },
+       [OLYMPUS_LUT_CHAN_560375_IDX] = { 22415, 0x1, 0x7C, 0x10E38E, 0x74C },
+       [OLYMPUS_LUT_CHAN_560500_IDX] = { 22420, 0x1, 0x7C, 0x11C71C, 0x74C },
+       [OLYMPUS_LUT_CHAN_560625_IDX] = { 22425, 0x1, 0x7C, 0x12AAAB, 0x74D },
+       [OLYMPUS_LUT_CHAN_560750_IDX] = { 22430, 0x1, 0x7C, 0x138E39, 0x74D },
+       [OLYMPUS_LUT_CHAN_560875_IDX] = { 22435, 0x1, 0x7C, 0x1471C7, 0x74E },
+       [OLYMPUS_LUT_CHAN_561000_IDX] = { 22440, 0x1, 0x7C, 0x155555, 0x74E },
+       [OLYMPUS_LUT_CHAN_561125_IDX] = { 22445, 0x1, 0x7C, 0x1638E4, 0x74E },
+       [OLYMPUS_LUT_CHAN_561250_IDX] = { 22450, 0x1, 0x7C, 0x171C72, 0x74F },
+       [OLYMPUS_LUT_CHAN_561375_IDX] = { 22455, 0x1, 0x7C, 0x180000, 0x74F },
+       [OLYMPUS_LUT_CHAN_561500_IDX] = { 22460, 0x1, 0x7C, 0x18E38E, 0x750 },
+       [OLYMPUS_LUT_CHAN_561625_IDX] = { 22465, 0x1, 0x7C, 0x19C71C, 0x750 },
+       [OLYMPUS_LUT_CHAN_561750_IDX] = { 22470, 0x1, 0x7C, 0x1AAAAB, 0x751 },
+       [OLYMPUS_LUT_CHAN_561875_IDX] = { 22475, 0x1, 0x7C, 0x1B8E39, 0x751 },
+       [OLYMPUS_LUT_CHAN_562000_IDX] = { 22480, 0x1, 0x7C, 0x1C71C7, 0x751 },
+       [OLYMPUS_LUT_CHAN_562125_IDX] = { 22485, 0x1, 0x7C, 0x1D5555, 0x752 },
+       [OLYMPUS_LUT_CHAN_562250_IDX] = { 22490, 0x1, 0x7C, 0x1E38E4, 0x752 },
+       [OLYMPUS_LUT_CHAN_562375_IDX] = { 22495, 0x1, 0x7C, 0x1F1C72, 0x753 },
+       [OLYMPUS_LUT_CHAN_562500_IDX] = { 22500, 0x1, 0x7D, 0x0, 0x753 },
+       [OLYMPUS_LUT_CHAN_562625_IDX] = { 22505, 0x1, 0x7D, 0xE38E, 0x753 },
+       [OLYMPUS_LUT_CHAN_562750_IDX] = { 22510, 0x1, 0x7D, 0x1C71C, 0x754 },
+       [OLYMPUS_LUT_CHAN_562875_IDX] = { 22515, 0x1, 0x7D, 0x2AAAB, 0x754 },
+       [OLYMPUS_LUT_CHAN_563000_IDX] = { 22520, 0x1, 0x7D, 0x38E39, 0x755 },
+       [OLYMPUS_LUT_CHAN_563125_IDX] = { 22525, 0x1, 0x7D, 0x471C7, 0x755 },
+       [OLYMPUS_LUT_CHAN_563250_IDX] = { 22530, 0x1, 0x7D, 0x55555, 0x756 },
+       [OLYMPUS_LUT_CHAN_563375_IDX] = { 22535, 0x1, 0x7D, 0x638E4, 0x756 },
+       [OLYMPUS_LUT_CHAN_563500_IDX] = { 22540, 0x1, 0x7D, 0x71C72, 0x756 },
+       [OLYMPUS_LUT_CHAN_563625_IDX] = { 22545, 0x1, 0x7D, 0x80000, 0x757 },
+       [OLYMPUS_LUT_CHAN_563750_IDX] = { 22550, 0x1, 0x7D, 0x8E38E, 0x757 },
+       [OLYMPUS_LUT_CHAN_563875_IDX] = { 22555, 0x1, 0x7D, 0x9C71C, 0x758 },
+       [OLYMPUS_LUT_CHAN_564000_IDX] = { 22560, 0x1, 0x7D, 0xAAAAB, 0x758 },
+       [OLYMPUS_LUT_CHAN_564125_IDX] = { 22565, 0x1, 0x7D, 0xB8E39, 0x758 },
+       [OLYMPUS_LUT_CHAN_564250_IDX] = { 22570, 0x1, 0x7D, 0xC71C7, 0x759 },
+       [OLYMPUS_LUT_CHAN_564375_IDX] = { 22575, 0x1, 0x7D, 0xD5555, 0x759 },
+       [OLYMPUS_LUT_CHAN_564500_IDX] = { 22580, 0x1, 0x7D, 0xE38E4, 0x75A },
+       [OLYMPUS_LUT_CHAN_564625_IDX] = { 22585, 0x1, 0x7D, 0xF1C72, 0x75A },
+       [OLYMPUS_LUT_CHAN_564750_IDX] = { 22590, 0x1, 0x7D, 0x100000, 0x75B },
+       [OLYMPUS_LUT_CHAN_564875_IDX] = { 22595, 0x1, 0x7D, 0x10E38E, 0x75B },
+       [OLYMPUS_LUT_CHAN_565000_IDX] = { 22600, 0x1, 0x7D, 0x11C71C, 0x75B },
+       [OLYMPUS_LUT_CHAN_565125_IDX] = { 22605, 0x1, 0x7D, 0x12AAAB, 0x75C },
+       [OLYMPUS_LUT_CHAN_565250_IDX] = { 22610, 0x1, 0x7D, 0x138E39, 0x75C },
+       [OLYMPUS_LUT_CHAN_565375_IDX] = { 22615, 0x1, 0x7D, 0x1471C7, 0x75D },
+       [OLYMPUS_LUT_CHAN_565500_IDX] = { 22620, 0x1, 0x7D, 0x155555, 0x75D },
+       [OLYMPUS_LUT_CHAN_565625_IDX] = { 22625, 0x1, 0x7D, 0x1638E4, 0x75D },
+       [OLYMPUS_LUT_CHAN_565750_IDX] = { 22630, 0x1, 0x7D, 0x171C72, 0x75E },
+       [OLYMPUS_LUT_CHAN_565875_IDX] = { 22635, 0x1, 0x7D, 0x180000, 0x75E },
+       [OLYMPUS_LUT_CHAN_566000_IDX] = { 22640, 0x1, 0x7D, 0x18E38E, 0x75F },
+       [OLYMPUS_LUT_CHAN_566125_IDX] = { 22645, 0x1, 0x7D, 0x19C71C, 0x75F },
+       [OLYMPUS_LUT_CHAN_566250_IDX] = { 22650, 0x1, 0x7D, 0x1AAAAB, 0x760 },
+       [OLYMPUS_LUT_CHAN_566375_IDX] = { 22655, 0x1, 0x7D, 0x1B8E39, 0x760 },
+       [OLYMPUS_LUT_CHAN_566500_IDX] = { 22660, 0x1, 0x7D, 0x1C71C7, 0x760 },
+       [OLYMPUS_LUT_CHAN_566625_IDX] = { 22665, 0x1, 0x7D, 0x1D5555, 0x761 },
+       [OLYMPUS_LUT_CHAN_566750_IDX] = { 22670, 0x1, 0x7D, 0x1E38E4, 0x761 },
+       [OLYMPUS_LUT_CHAN_566875_IDX] = { 22675, 0x1, 0x7D, 0x1F1C72, 0x762 },
+       [OLYMPUS_LUT_CHAN_567000_IDX] = { 22680, 0x1, 0x7E, 0x0, 0x762 },
+       [OLYMPUS_LUT_CHAN_567125_IDX] = { 22685, 0x1, 0x7E, 0xE38E, 0x762 },
+       [OLYMPUS_LUT_CHAN_567250_IDX] = { 22690, 0x1, 0x7E, 0x1C71C, 0x763 },
+       [OLYMPUS_LUT_CHAN_567375_IDX] = { 22695, 0x1, 0x7E, 0x2AAAB, 0x763 },
+       [OLYMPUS_LUT_CHAN_567500_IDX] = { 22700, 0x1, 0x7E, 0x38E39, 0x764 },
+       [OLYMPUS_LUT_CHAN_567625_IDX] = { 22705, 0x1, 0x7E, 0x471C7, 0x764 },
+       [OLYMPUS_LUT_CHAN_567750_IDX] = { 22710, 0x1, 0x7E, 0x55555, 0x765 },
+       [OLYMPUS_LUT_CHAN_567875_IDX] = { 22715, 0x1, 0x7E, 0x638E4, 0x765 },
+       [OLYMPUS_LUT_CHAN_568000_IDX] = { 22720, 0x1, 0x7E, 0x71C72, 0x765 },
+       [OLYMPUS_LUT_CHAN_568125_IDX] = { 22725, 0x1, 0x7E, 0x80000, 0x766 },
+       [OLYMPUS_LUT_CHAN_568250_IDX] = { 22730, 0x1, 0x7E, 0x8E38E, 0x766 },
+       [OLYMPUS_LUT_CHAN_568375_IDX] = { 22735, 0x1, 0x7E, 0x9C71C, 0x767 },
+       [OLYMPUS_LUT_CHAN_568500_IDX] = { 22740, 0x1, 0x7E, 0xAAAAB, 0x767 },
+       [OLYMPUS_LUT_CHAN_568625_IDX] = { 22745, 0x1, 0x7E, 0xB8E39, 0x767 },
+       [OLYMPUS_LUT_CHAN_568750_IDX] = { 22750, 0x1, 0x7E, 0xC71C7, 0x768 },
+       [OLYMPUS_LUT_CHAN_568875_IDX] = { 22755, 0x1, 0x7E, 0xD5555, 0x768 },
+       [OLYMPUS_LUT_CHAN_569000_IDX] = { 22760, 0x1, 0x7E, 0xE38E4, 0x769 },
+       [OLYMPUS_LUT_CHAN_569125_IDX] = { 22765, 0x1, 0x7E, 0xF1C72, 0x769 },
+       [OLYMPUS_LUT_CHAN_569250_IDX] = { 22770, 0x1, 0x7E, 0x100000, 0x76A },
+       [OLYMPUS_LUT_CHAN_569375_IDX] = { 22775, 0x1, 0x7E, 0x10E38E, 0x76A },
+       [OLYMPUS_LUT_CHAN_569500_IDX] = { 22780, 0x1, 0x7E, 0x11C71C, 0x76A },
+       [OLYMPUS_LUT_CHAN_569625_IDX] = { 22785, 0x1, 0x7E, 0x12AAAB, 0x76B },
+       [OLYMPUS_LUT_CHAN_569750_IDX] = { 22790, 0x1, 0x7E, 0x138E39, 0x76B },
+       [OLYMPUS_LUT_CHAN_569875_IDX] = { 22795, 0x1, 0x7E, 0x1471C7, 0x76C },
+       [OLYMPUS_LUT_CHAN_570000_IDX] = { 22800, 0x1, 0x7E, 0x155555, 0x76C },
+       [OLYMPUS_LUT_CHAN_570125_IDX] = { 22805, 0x1, 0x7E, 0x1638E4, 0x76C },
+       [OLYMPUS_LUT_CHAN_570250_IDX] = { 22810, 0x1, 0x7E, 0x171C72, 0x76D },
+       [OLYMPUS_LUT_CHAN_570375_IDX] = { 22815, 0x1, 0x7E, 0x180000, 0x76D },
+       [OLYMPUS_LUT_CHAN_570500_IDX] = { 22820, 0x1, 0x7E, 0x18E38E, 0x76E },
+       [OLYMPUS_LUT_CHAN_570625_IDX] = { 22825, 0x1, 0x7E, 0x19C71C, 0x76E },
+       [OLYMPUS_LUT_CHAN_570750_IDX] = { 22830, 0x1, 0x7E, 0x1AAAAB, 0x76F },
+       [OLYMPUS_LUT_CHAN_570875_IDX] = { 22835, 0x1, 0x7E, 0x1B8E39, 0x76F },
+       [OLYMPUS_LUT_CHAN_571000_IDX] = { 22840, 0x1, 0x7E, 0x1C71C7, 0x76F },
+       [OLYMPUS_LUT_CHAN_571125_IDX] = { 22845, 0x1, 0x7E, 0x1D5555, 0x770 },
+       [OLYMPUS_LUT_CHAN_571250_IDX] = { 22850, 0x1, 0x7E, 0x1E38E4, 0x770 },
+       [OLYMPUS_LUT_CHAN_571375_IDX] = { 22855, 0x1, 0x7E, 0x1F1C72, 0x771 },
+       [OLYMPUS_LUT_CHAN_571500_IDX] = { 22860, 0x1, 0x7F, 0x0, 0x771 },
+       [OLYMPUS_LUT_CHAN_571625_IDX] = { 22865, 0x1, 0x7F, 0xE38E, 0x771 },
+       [OLYMPUS_LUT_CHAN_571750_IDX] = { 22870, 0x1, 0x7F, 0x1C71C, 0x772 },
+       [OLYMPUS_LUT_CHAN_571875_IDX] = { 22875, 0x1, 0x7F, 0x2AAAB, 0x772 },
+       [OLYMPUS_LUT_CHAN_572000_IDX] = { 22880, 0x1, 0x7F, 0x38E39, 0x773 },
+       [OLYMPUS_LUT_CHAN_572125_IDX] = { 22885, 0x1, 0x7F, 0x471C7, 0x773 },
+       [OLYMPUS_LUT_CHAN_572250_IDX] = { 22890, 0x1, 0x7F, 0x55555, 0x774 },
+       [OLYMPUS_LUT_CHAN_572375_IDX] = { 22895, 0x1, 0x7F, 0x638E4, 0x774 },
+       [OLYMPUS_LUT_CHAN_572500_IDX] = { 22900, 0x1, 0x7F, 0x71C72, 0x774 },
+       [OLYMPUS_LUT_CHAN_572625_IDX] = { 22905, 0x1, 0x7F, 0x80000, 0x775 },
+       [OLYMPUS_LUT_CHAN_572750_IDX] = { 22910, 0x1, 0x7F, 0x8E38E, 0x775 },
+       [OLYMPUS_LUT_CHAN_572875_IDX] = { 22915, 0x1, 0x7F, 0x9C71C, 0x776 },
+       [OLYMPUS_LUT_CHAN_573000_IDX] = { 22920, 0x1, 0x7F, 0xAAAAB, 0x776 },
+       [OLYMPUS_LUT_CHAN_573125_IDX] = { 22925, 0x1, 0x7F, 0xB8E39, 0x776 },
+       [OLYMPUS_LUT_CHAN_573250_IDX] = { 22930, 0x1, 0x7F, 0xC71C7, 0x777 },
+       [OLYMPUS_LUT_CHAN_573375_IDX] = { 22935, 0x1, 0x7F, 0xD5555, 0x777 },
+       [OLYMPUS_LUT_CHAN_573500_IDX] = { 22940, 0x1, 0x7F, 0xE38E4, 0x778 },
+       [OLYMPUS_LUT_CHAN_573625_IDX] = { 22945, 0x1, 0x7F, 0xF1C72, 0x778 },
+       [OLYMPUS_LUT_CHAN_573750_IDX] = { 22950, 0x1, 0x7F, 0x100000, 0x779 },
+       [OLYMPUS_LUT_CHAN_573875_IDX] = { 22955, 0x1, 0x7F, 0x10E38E, 0x779 },
+       [OLYMPUS_LUT_CHAN_574000_IDX] = { 22960, 0x1, 0x7F, 0x11C71C, 0x779 },
+       [OLYMPUS_LUT_CHAN_574125_IDX] = { 22965, 0x1, 0x7F, 0x12AAAB, 0x77A },
+       [OLYMPUS_LUT_CHAN_574250_IDX] = { 22970, 0x1, 0x7F, 0x138E39, 0x77A },
+       [OLYMPUS_LUT_CHAN_574375_IDX] = { 22975, 0x1, 0x7F, 0x1471C7, 0x77B },
+       [OLYMPUS_LUT_CHAN_574500_IDX] = { 22980, 0x1, 0x7F, 0x155555, 0x77B },
+       [OLYMPUS_LUT_CHAN_574625_IDX] = { 22985, 0x1, 0x7F, 0x1638E4, 0x77B },
+       [OLYMPUS_LUT_CHAN_574750_IDX] = { 22990, 0x1, 0x7F, 0x171C72, 0x77C },
+       [OLYMPUS_LUT_CHAN_574875_IDX] = { 22995, 0x1, 0x7F, 0x180000, 0x77C },
+       [OLYMPUS_LUT_CHAN_575000_IDX] = { 23000, 0x1, 0x7F, 0x18E38E, 0x77D },
+       [OLYMPUS_LUT_CHAN_575125_IDX] = { 23005, 0x1, 0x7F, 0x19C71C, 0x77D },
+       [OLYMPUS_LUT_CHAN_575250_IDX] = { 23010, 0x1, 0x7F, 0x1AAAAB, 0x77E },
+       [OLYMPUS_LUT_CHAN_575375_IDX] = { 23015, 0x1, 0x7F, 0x1B8E39, 0x77E },
+       [OLYMPUS_LUT_CHAN_575500_IDX] = { 23020, 0x1, 0x7F, 0x1C71C7, 0x77E },
+       [OLYMPUS_LUT_CHAN_575625_IDX] = { 23025, 0x1, 0x7F, 0x1D5555, 0x77F },
+       [OLYMPUS_LUT_CHAN_575750_IDX] = { 23030, 0x1, 0x7F, 0x1E38E4, 0x77F },
+       [OLYMPUS_LUT_CHAN_575875_IDX] = { 23035, 0x1, 0x7F, 0x1F1C72, 0x780 },
+       [OLYMPUS_LUT_CHAN_576000_IDX] = { 23040, 0x1, 0x80, 0x0, 0x780 },
+       [OLYMPUS_LUT_CHAN_576125_IDX] = { 23045, 0x1, 0x80, 0xE38E, 0x780 },
+       [OLYMPUS_LUT_CHAN_576250_IDX] = { 23050, 0x1, 0x80, 0x1C71C, 0x781 },
+       [OLYMPUS_LUT_CHAN_576375_IDX] = { 23055, 0x1, 0x80, 0x2AAAB, 0x781 },
+       [OLYMPUS_LUT_CHAN_576500_IDX] = { 23060, 0x1, 0x80, 0x38E39, 0x782 },
+       [OLYMPUS_LUT_CHAN_576625_IDX] = { 23065, 0x1, 0x80, 0x471C7, 0x782 },
+       [OLYMPUS_LUT_CHAN_576750_IDX] = { 23070, 0x1, 0x80, 0x55555, 0x783 },
+       [OLYMPUS_LUT_CHAN_576875_IDX] = { 23075, 0x1, 0x80, 0x638E4, 0x783 },
+       [OLYMPUS_LUT_CHAN_577000_IDX] = { 23080, 0x1, 0x80, 0x71C72, 0x783 },
+       [OLYMPUS_LUT_CHAN_577125_IDX] = { 23085, 0x1, 0x80, 0x80000, 0x784 },
+       [OLYMPUS_LUT_CHAN_577250_IDX] = { 23090, 0x1, 0x80, 0x8E38E, 0x784 },
+       [OLYMPUS_LUT_CHAN_577375_IDX] = { 23095, 0x1, 0x80, 0x9C71C, 0x785 },
+       [OLYMPUS_LUT_CHAN_577500_IDX] = { 23100, 0x1, 0x80, 0xAAAAB, 0x785 },
+       [OLYMPUS_LUT_CHAN_577625_IDX] = { 23105, 0x1, 0x80, 0xB8E39, 0x785 },
+       [OLYMPUS_LUT_CHAN_577750_IDX] = { 23110, 0x1, 0x80, 0xC71C7, 0x786 },
+       [OLYMPUS_LUT_CHAN_577875_IDX] = { 23115, 0x1, 0x80, 0xD5555, 0x786 },
+       [OLYMPUS_LUT_CHAN_578000_IDX] = { 23120, 0x1, 0x80, 0xE38E4, 0x787 },
+       [OLYMPUS_LUT_CHAN_578125_IDX] = { 23125, 0x1, 0x80, 0xF1C72, 0x787 },
+       [OLYMPUS_LUT_CHAN_578250_IDX] = { 23130, 0x1, 0x80, 0x100000, 0x788 },
+       [OLYMPUS_LUT_CHAN_578375_IDX] = { 23135, 0x1, 0x80, 0x10E38E, 0x788 },
+       [OLYMPUS_LUT_CHAN_578500_IDX] = { 23140, 0x1, 0x80, 0x11C71C, 0x788 },
+       [OLYMPUS_LUT_CHAN_578625_IDX] = { 23145, 0x1, 0x80, 0x12AAAB, 0x789 },
+       [OLYMPUS_LUT_CHAN_578750_IDX] = { 23150, 0x1, 0x80, 0x138E39, 0x789 },
+       [OLYMPUS_LUT_CHAN_578875_IDX] = { 23155, 0x1, 0x80, 0x1471C7, 0x78A },
+       [OLYMPUS_LUT_CHAN_579000_IDX] = { 23160, 0x1, 0x80, 0x155555, 0x78A },
+       [OLYMPUS_LUT_CHAN_579125_IDX] = { 23165, 0x1, 0x80, 0x1638E4, 0x78A },
+       [OLYMPUS_LUT_CHAN_579250_IDX] = { 23170, 0x1, 0x80, 0x171C72, 0x78B },
+       [OLYMPUS_LUT_CHAN_579375_IDX] = { 23175, 0x1, 0x80, 0x180000, 0x78B },
+       [OLYMPUS_LUT_CHAN_579500_IDX] = { 23180, 0x1, 0x80, 0x18E38E, 0x78C },
+       [OLYMPUS_LUT_CHAN_579625_IDX] = { 23185, 0x1, 0x80, 0x19C71C, 0x78C },
+       [OLYMPUS_LUT_CHAN_579750_IDX] = { 23190, 0x1, 0x80, 0x1AAAAB, 0x78D },
+       [OLYMPUS_LUT_CHAN_579875_IDX] = { 23195, 0x1, 0x80, 0x1B8E39, 0x78D },
+       [OLYMPUS_LUT_CHAN_580000_IDX] = { 23200, 0x1, 0x80, 0x1C71C7, 0x78D },
+       [OLYMPUS_LUT_CHAN_580125_IDX] = { 23205, 0x1, 0x80, 0x1D5555, 0x78E },
+       [OLYMPUS_LUT_CHAN_580250_IDX] = { 23210, 0x1, 0x80, 0x1E38E4, 0x78E },
+       [OLYMPUS_LUT_CHAN_580375_IDX] = { 23215, 0x1, 0x80, 0x1F1C72, 0x78F },
+       [OLYMPUS_LUT_CHAN_580500_IDX] = { 23220, 0x1, 0x81, 0x0, 0x78F },
+       [OLYMPUS_LUT_CHAN_580625_IDX] = { 23225, 0x1, 0x81, 0xE38E, 0x78F },
+       [OLYMPUS_LUT_CHAN_580750_IDX] = { 23230, 0x1, 0x81, 0x1C71C, 0x790 },
+       [OLYMPUS_LUT_CHAN_580875_IDX] = { 23235, 0x1, 0x81, 0x2AAAB, 0x790 },
+       [OLYMPUS_LUT_CHAN_581000_IDX] = { 23240, 0x1, 0x81, 0x38E39, 0x791 },
+       [OLYMPUS_LUT_CHAN_581125_IDX] = { 23245, 0x1, 0x81, 0x471C7, 0x791 },
+       [OLYMPUS_LUT_CHAN_581250_IDX] = { 23250, 0x1, 0x81, 0x55555, 0x792 },
+       [OLYMPUS_LUT_CHAN_581375_IDX] = { 23255, 0x1, 0x81, 0x638E4, 0x792 },
+       [OLYMPUS_LUT_CHAN_581500_IDX] = { 23260, 0x1, 0x81, 0x71C72, 0x792 },
+       [OLYMPUS_LUT_CHAN_581625_IDX] = { 23265, 0x1, 0x81, 0x80000, 0x793 },
+       [OLYMPUS_LUT_CHAN_581750_IDX] = { 23270, 0x1, 0x81, 0x8E38E, 0x793 },
+       [OLYMPUS_LUT_CHAN_581875_IDX] = { 23275, 0x1, 0x81, 0x9C71C, 0x794 },
+       [OLYMPUS_LUT_CHAN_582000_IDX] = { 23280, 0x1, 0x81, 0xAAAAB, 0x794 },
+       [OLYMPUS_LUT_CHAN_582125_IDX] = { 23285, 0x1, 0x81, 0xB8E39, 0x794 },
+       [OLYMPUS_LUT_CHAN_582250_IDX] = { 23290, 0x1, 0x81, 0xC71C7, 0x795 },
+       [OLYMPUS_LUT_CHAN_582375_IDX] = { 23295, 0x1, 0x81, 0xD5555, 0x795 },
+       [OLYMPUS_LUT_CHAN_582500_IDX] = { 23300, 0x1, 0x81, 0xE38E4, 0x796 },
+       [OLYMPUS_LUT_CHAN_582625_IDX] = { 23305, 0x1, 0x81, 0xF1C72, 0x796 },
+       [OLYMPUS_LUT_CHAN_582750_IDX] = { 23310, 0x1, 0x81, 0x100000, 0x797 },
+       [OLYMPUS_LUT_CHAN_582875_IDX] = { 23315, 0x1, 0x81, 0x10E38E, 0x797 },
+       [OLYMPUS_LUT_CHAN_583000_IDX] = { 23320, 0x1, 0x81, 0x11C71C, 0x797 },
+       [OLYMPUS_LUT_CHAN_583125_IDX] = { 23325, 0x1, 0x81, 0x12AAAB, 0x798 },
+       [OLYMPUS_LUT_CHAN_583250_IDX] = { 23330, 0x1, 0x81, 0x138E39, 0x798 },
+       [OLYMPUS_LUT_CHAN_583375_IDX] = { 23335, 0x1, 0x81, 0x1471C7, 0x799 },
+       [OLYMPUS_LUT_CHAN_583500_IDX] = { 23340, 0x1, 0x81, 0x155555, 0x799 },
+       [OLYMPUS_LUT_CHAN_583625_IDX] = { 23345, 0x1, 0x81, 0x1638E4, 0x799 },
+       [OLYMPUS_LUT_CHAN_583750_IDX] = { 23350, 0x1, 0x81, 0x171C72, 0x79A },
+       [OLYMPUS_LUT_CHAN_583875_IDX] = { 23355, 0x1, 0x81, 0x180000, 0x79A },
+       [OLYMPUS_LUT_CHAN_584000_IDX] = { 23360, 0x1, 0x81, 0x18E38E, 0x79B },
+       [OLYMPUS_LUT_CHAN_584125_IDX] = { 23365, 0x1, 0x81, 0x19C71C, 0x79B },
+       [OLYMPUS_LUT_CHAN_584250_IDX] = { 23370, 0x1, 0x81, 0x1AAAAB, 0x79C },
+       [OLYMPUS_LUT_CHAN_584375_IDX] = { 23375, 0x1, 0x81, 0x1B8E39, 0x79C },
+       [OLYMPUS_LUT_CHAN_584500_IDX] = { 23380, 0x1, 0x81, 0x1C71C7, 0x79C },
+       [OLYMPUS_LUT_CHAN_584625_IDX] = { 23385, 0x1, 0x81, 0x1D5555, 0x79D },
+       [OLYMPUS_LUT_CHAN_584750_IDX] = { 23390, 0x1, 0x81, 0x1E38E4, 0x79D },
+       [OLYMPUS_LUT_CHAN_584875_IDX] = { 23395, 0x1, 0x81, 0x1F1C72, 0x79E },
+       [OLYMPUS_LUT_CHAN_585000_IDX] = { 23400, 0x1, 0x82, 0x0, 0x79E },
+       [OLYMPUS_LUT_CHAN_585125_IDX] = { 23405, 0x1, 0x82, 0xE38E, 0x79E },
+       [OLYMPUS_LUT_CHAN_585250_IDX] = { 23410, 0x1, 0x82, 0x1C71C, 0x79F },
+       [OLYMPUS_LUT_CHAN_585375_IDX] = { 23415, 0x1, 0x82, 0x2AAAB, 0x79F },
+       [OLYMPUS_LUT_CHAN_585500_IDX] = { 23420, 0x1, 0x82, 0x38E39, 0x7A0 },
+       [OLYMPUS_LUT_CHAN_585625_IDX] = { 23425, 0x1, 0x82, 0x471C7, 0x7A0 },
+       [OLYMPUS_LUT_CHAN_585750_IDX] = { 23430, 0x1, 0x82, 0x55555, 0x7A1 },
+       [OLYMPUS_LUT_CHAN_585875_IDX] = { 23435, 0x1, 0x82, 0x638E4, 0x7A1 },
+       [OLYMPUS_LUT_CHAN_586000_IDX] = { 23440, 0x1, 0x82, 0x71C72, 0x7A1 },
+       [OLYMPUS_LUT_CHAN_586125_IDX] = { 23445, 0x1, 0x82, 0x80000, 0x7A2 },
+       [OLYMPUS_LUT_CHAN_586250_IDX] = { 23450, 0x1, 0x82, 0x8E38E, 0x7A2 },
+       [OLYMPUS_LUT_CHAN_586375_IDX] = { 23455, 0x1, 0x82, 0x9C71C, 0x7A3 },
+       [OLYMPUS_LUT_CHAN_586500_IDX] = { 23460, 0x1, 0x82, 0xAAAAB, 0x7A3 },
+       [OLYMPUS_LUT_CHAN_586625_IDX] = { 23465, 0x1, 0x82, 0xB8E39, 0x7A3 },
+       [OLYMPUS_LUT_CHAN_586750_IDX] = { 23470, 0x1, 0x82, 0xC71C7, 0x7A4 },
+       [OLYMPUS_LUT_CHAN_586875_IDX] = { 23475, 0x1, 0x82, 0xD5555, 0x7A4 },
+       [OLYMPUS_LUT_CHAN_587000_IDX] = { 23480, 0x1, 0x82, 0xE38E4, 0x7A5 },
+       [OLYMPUS_LUT_CHAN_587125_IDX] = { 23485, 0x1, 0x82, 0xF1C72, 0x7A5 },
+       [OLYMPUS_LUT_CHAN_587250_IDX] = { 23490, 0x1, 0x82, 0x100000, 0x7A6 },
+       [OLYMPUS_LUT_CHAN_587375_IDX] = { 23495, 0x1, 0x82, 0x10E38E, 0x7A6 },
+       [OLYMPUS_LUT_CHAN_587500_IDX] = { 23500, 0x1, 0x82, 0x11C71C, 0x7A6 },
+       [OLYMPUS_LUT_CHAN_587625_IDX] = { 23505, 0x1, 0x82, 0x12AAAB, 0x7A7 },
+       [OLYMPUS_LUT_CHAN_587750_IDX] = { 23510, 0x1, 0x82, 0x138E39, 0x7A7 },
+       [OLYMPUS_LUT_CHAN_587875_IDX] = { 23515, 0x1, 0x82, 0x1471C7, 0x7A8 },
+       [OLYMPUS_LUT_CHAN_588000_IDX] = { 23520, 0x1, 0x82, 0x155555, 0x7A8 },
+       [OLYMPUS_LUT_CHAN_588125_IDX] = { 23525, 0x1, 0x82, 0x1638E4, 0x7A8 },
+       [OLYMPUS_LUT_CHAN_588250_IDX] = { 23530, 0x1, 0x82, 0x171C72, 0x7A9 },
+       [OLYMPUS_LUT_CHAN_588375_IDX] = { 23535, 0x1, 0x82, 0x180000, 0x7A9 },
+       [OLYMPUS_LUT_CHAN_588500_IDX] = { 23540, 0x1, 0x82, 0x18E38E, 0x7AA },
+       [OLYMPUS_LUT_CHAN_588625_IDX] = { 23545, 0x1, 0x82, 0x19C71C, 0x7AA },
+       [OLYMPUS_LUT_CHAN_588750_IDX] = { 23550, 0x1, 0x82, 0x1AAAAB, 0x7AB },
+       [OLYMPUS_LUT_CHAN_588875_IDX] = { 23555, 0x1, 0x82, 0x1B8E39, 0x7AB },
+       [OLYMPUS_LUT_CHAN_589000_IDX] = { 23560, 0x1, 0x82, 0x1C71C7, 0x7AB },
+       [OLYMPUS_LUT_CHAN_589125_IDX] = { 23565, 0x1, 0x82, 0x1D5555, 0x7AC },
+       [OLYMPUS_LUT_CHAN_589250_IDX] = { 23570, 0x1, 0x82, 0x1E38E4, 0x7AC },
+       [OLYMPUS_LUT_CHAN_589375_IDX] = { 23575, 0x1, 0x82, 0x1F1C72, 0x7AD },
+       [OLYMPUS_LUT_CHAN_589500_IDX] = { 23580, 0x1, 0x83, 0x0, 0x7AD },
+       [OLYMPUS_LUT_CHAN_589625_IDX] = { 23585, 0x1, 0x83, 0xE38E, 0x7AD },
+       [OLYMPUS_LUT_CHAN_589750_IDX] = { 23590, 0x1, 0x83, 0x1C71C, 0x7AE },
+       [OLYMPUS_LUT_CHAN_589875_IDX] = { 23595, 0x1, 0x83, 0x2AAAB, 0x7AE },
+       [OLYMPUS_LUT_CHAN_590000_IDX] = { 23600, 0x1, 0x83, 0x38E39, 0x7AF },
+       [OLYMPUS_LUT_CHAN_590125_IDX] = { 23605, 0x1, 0x83, 0x471C7, 0x7AF },
+       [OLYMPUS_LUT_CHAN_590250_IDX] = { 23610, 0x1, 0x83, 0x55555, 0x7B0 },
+       [OLYMPUS_LUT_CHAN_590375_IDX] = { 23615, 0x1, 0x83, 0x638E4, 0x7B0 },
+       [OLYMPUS_LUT_CHAN_590500_IDX] = { 23620, 0x1, 0x83, 0x71C72, 0x7B0 },
+       [OLYMPUS_LUT_CHAN_590625_IDX] = { 23625, 0x1, 0x83, 0x80000, 0x7B1 },
+       [OLYMPUS_LUT_CHAN_590750_IDX] = { 23630, 0x1, 0x83, 0x8E38E, 0x7B1 },
+       [OLYMPUS_LUT_CHAN_590875_IDX] = { 23635, 0x1, 0x83, 0x9C71C, 0x7B2 },
+       [OLYMPUS_LUT_CHAN_591000_IDX] = { 23640, 0x1, 0x83, 0xAAAAB, 0x7B2 },
+       [OLYMPUS_LUT_CHAN_591125_IDX] = { 23645, 0x1, 0x83, 0xB8E39, 0x7B2 },
+       [OLYMPUS_LUT_CHAN_591250_IDX] = { 23650, 0x1, 0x83, 0xC71C7, 0x7B3 },
+       [OLYMPUS_LUT_CHAN_591375_IDX] = { 23655, 0x1, 0x83, 0xD5555, 0x7B3 },
+       [OLYMPUS_LUT_CHAN_591500_IDX] = { 23660, 0x1, 0x83, 0xE38E4, 0x7B4 },
+       [OLYMPUS_LUT_CHAN_591625_IDX] = { 23665, 0x1, 0x83, 0xF1C72, 0x7B4 },
+       [OLYMPUS_LUT_CHAN_591750_IDX] = { 23670, 0x1, 0x83, 0x100000, 0x7B5 },
+       [OLYMPUS_LUT_CHAN_591875_IDX] = { 23675, 0x1, 0x83, 0x10E38E, 0x7B5 },
+       [OLYMPUS_LUT_CHAN_592000_IDX] = { 23680, 0x1, 0x83, 0x11C71C, 0x7B5 },
+       [OLYMPUS_LUT_CHAN_592125_IDX] = { 23685, 0x1, 0x83, 0x12AAAB, 0x7B6 },
+       [OLYMPUS_LUT_CHAN_592250_IDX] = { 23690, 0x1, 0x83, 0x138E39, 0x7B6 },
+       [OLYMPUS_LUT_CHAN_592375_IDX] = { 23695, 0x1, 0x83, 0x1471C7, 0x7B7 },
+       [OLYMPUS_LUT_CHAN_592500_IDX] = { 23700, 0x1, 0x83, 0x155555, 0x7B7 },
+       [OLYMPUS_LUT_CHAN_592625_IDX] = { 23705, 0x1, 0x83, 0x1638E4, 0x7B7 },
+       [OLYMPUS_LUT_CHAN_592750_IDX] = { 23710, 0x1, 0x83, 0x171C72, 0x7B8 },
+       [OLYMPUS_LUT_CHAN_592875_IDX] = { 23715, 0x1, 0x83, 0x180000, 0x7B8 },
+       [OLYMPUS_LUT_CHAN_593000_IDX] = { 23720, 0x1, 0x83, 0x18E38E, 0x7B9 },
+       [OLYMPUS_LUT_CHAN_593125_IDX] = { 23725, 0x1, 0x83, 0x19C71C, 0x7B9 },
+       [OLYMPUS_LUT_CHAN_593250_IDX] = { 23730, 0x1, 0x83, 0x1AAAAB, 0x7BA },
+       [OLYMPUS_LUT_CHAN_593375_IDX] = { 23735, 0x1, 0x83, 0x1B8E39, 0x7BA },
+       [OLYMPUS_LUT_CHAN_593500_IDX] = { 23740, 0x1, 0x83, 0x1C71C7, 0x7BA },
+       [OLYMPUS_LUT_CHAN_593625_IDX] = { 23745, 0x1, 0x83, 0x1D5555, 0x7BB },
+       [OLYMPUS_LUT_CHAN_593750_IDX] = { 23750, 0x1, 0x83, 0x1E38E4, 0x7BB },
+       [OLYMPUS_LUT_CHAN_593875_IDX] = { 23755, 0x1, 0x83, 0x1F1C72, 0x7BC },
+       [OLYMPUS_LUT_CHAN_594000_IDX] = { 23760, 0x1, 0x84, 0x0, 0x7BC },
+       [OLYMPUS_LUT_CHAN_594125_IDX] = { 23765, 0x1, 0x84, 0xE38E, 0x7BC },
+       [OLYMPUS_LUT_CHAN_594250_IDX] = { 23770, 0x1, 0x84, 0x1C71C, 0x7BD },
+       [OLYMPUS_LUT_CHAN_594375_IDX] = { 23775, 0x1, 0x84, 0x2AAAB, 0x7BD },
+       [OLYMPUS_LUT_CHAN_594500_IDX] = { 23780, 0x1, 0x84, 0x38E39, 0x7BE },
+       [OLYMPUS_LUT_CHAN_594625_IDX] = { 23785, 0x1, 0x84, 0x471C7, 0x7BE },
+       [OLYMPUS_LUT_CHAN_594750_IDX] = { 23790, 0x1, 0x84, 0x55555, 0x7BF },
+       [OLYMPUS_LUT_CHAN_594875_IDX] = { 23795, 0x1, 0x84, 0x638E4, 0x7BF },
+       [OLYMPUS_LUT_CHAN_595000_IDX] = { 23800, 0x1, 0x84, 0x71C72, 0x7BF }
+};
--
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.
________________________________


^ permalink raw reply related	[flat|nested] 262+ messages in thread

* [RFC v1 132/256] cl8k: add phy/phy_olympus_lut.h
  2021-06-17 15:58 [RFC v1 000/256] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (130 preceding siblings ...)
  2021-06-17 16:00 ` [RFC v1 131/256] cl8k: add phy/phy_olympus_lut.c viktor.barna
@ 2021-06-17 16:00 ` viktor.barna
  2021-06-17 16:00 ` [RFC v1 133/256] cl8k: add power.c viktor.barna
                   ` (125 subsequent siblings)
  257 siblings, 0 replies; 262+ messages in thread
From: viktor.barna @ 2021-06-17 16:00 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Oleksandr Savchenko, Shay Bar, Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

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

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 .../celeno/cl8k/phy/phy_olympus_lut.h         | 777 ++++++++++++++++++
 1 file changed, 777 insertions(+)
 create mode 100644 drivers/net/wireless/celeno/cl8k/phy/phy_olympus_lut.h

diff --git a/drivers/net/wireless/celeno/cl8k/phy/phy_olympus_lut.h b/drivers/net/wireless/celeno/cl8k/phy/phy_olympus_lut.h
new file mode 100644
index 000000000000..3a8a9fa3ca38
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/phy/phy_olympus_lut.h
@@ -0,0 +1,777 @@
+/* SPDX-License-Identifier: MIT */
+/* Copyright(c) 2019-2021, Celeno Communications Ltd. */
+
+#ifndef CL_PHY_OLYMPUS_LUT_H
+#define CL_PHY_OLYMPUS_LUT_H
+
+#include <linux/types.h>
+#include "phy_common_lut.h"
+#include "fw/fw_msg.h"
+
+enum OLYMPUS_lut_idx_5g {
+       OLYMPUS_LUT_CHAN_516000_IDX,
+       OLYMPUS_LUT_CHAN_516125_IDX,
+       OLYMPUS_LUT_CHAN_516250_IDX,
+       OLYMPUS_LUT_CHAN_516375_IDX,
+       OLYMPUS_LUT_CHAN_516500_IDX,
+       OLYMPUS_LUT_CHAN_516625_IDX,
+       OLYMPUS_LUT_CHAN_516750_IDX,
+       OLYMPUS_LUT_CHAN_516875_IDX,
+       OLYMPUS_LUT_CHAN_517000_IDX,
+       OLYMPUS_LUT_CHAN_517125_IDX,
+       OLYMPUS_LUT_CHAN_517250_IDX,
+       OLYMPUS_LUT_CHAN_517375_IDX,
+       OLYMPUS_LUT_CHAN_517500_IDX,
+       OLYMPUS_LUT_CHAN_517625_IDX,
+       OLYMPUS_LUT_CHAN_517750_IDX,
+       OLYMPUS_LUT_CHAN_517875_IDX,
+       OLYMPUS_LUT_CHAN_518000_IDX,
+       OLYMPUS_LUT_CHAN_518125_IDX,
+       OLYMPUS_LUT_CHAN_518250_IDX,
+       OLYMPUS_LUT_CHAN_518375_IDX,
+       OLYMPUS_LUT_CHAN_518500_IDX,
+       OLYMPUS_LUT_CHAN_518625_IDX,
+       OLYMPUS_LUT_CHAN_518750_IDX,
+       OLYMPUS_LUT_CHAN_518875_IDX,
+       OLYMPUS_LUT_CHAN_519000_IDX,
+       OLYMPUS_LUT_CHAN_519125_IDX,
+       OLYMPUS_LUT_CHAN_519250_IDX,
+       OLYMPUS_LUT_CHAN_519375_IDX,
+       OLYMPUS_LUT_CHAN_519500_IDX,
+       OLYMPUS_LUT_CHAN_519625_IDX,
+       OLYMPUS_LUT_CHAN_519750_IDX,
+       OLYMPUS_LUT_CHAN_519875_IDX,
+       OLYMPUS_LUT_CHAN_520000_IDX,
+       OLYMPUS_LUT_CHAN_520125_IDX,
+       OLYMPUS_LUT_CHAN_520250_IDX,
+       OLYMPUS_LUT_CHAN_520375_IDX,
+       OLYMPUS_LUT_CHAN_520500_IDX,
+       OLYMPUS_LUT_CHAN_520625_IDX,
+       OLYMPUS_LUT_CHAN_520750_IDX,
+       OLYMPUS_LUT_CHAN_520875_IDX,
+       OLYMPUS_LUT_CHAN_521000_IDX,
+       OLYMPUS_LUT_CHAN_521125_IDX,
+       OLYMPUS_LUT_CHAN_521250_IDX,
+       OLYMPUS_LUT_CHAN_521375_IDX,
+       OLYMPUS_LUT_CHAN_521500_IDX,
+       OLYMPUS_LUT_CHAN_521625_IDX,
+       OLYMPUS_LUT_CHAN_521750_IDX,
+       OLYMPUS_LUT_CHAN_521875_IDX,
+       OLYMPUS_LUT_CHAN_522000_IDX,
+       OLYMPUS_LUT_CHAN_522125_IDX,
+       OLYMPUS_LUT_CHAN_522250_IDX,
+       OLYMPUS_LUT_CHAN_522375_IDX,
+       OLYMPUS_LUT_CHAN_522500_IDX,
+       OLYMPUS_LUT_CHAN_522625_IDX,
+       OLYMPUS_LUT_CHAN_522750_IDX,
+       OLYMPUS_LUT_CHAN_522875_IDX,
+       OLYMPUS_LUT_CHAN_523000_IDX,
+       OLYMPUS_LUT_CHAN_523125_IDX,
+       OLYMPUS_LUT_CHAN_523250_IDX,
+       OLYMPUS_LUT_CHAN_523375_IDX,
+       OLYMPUS_LUT_CHAN_523500_IDX,
+       OLYMPUS_LUT_CHAN_523625_IDX,
+       OLYMPUS_LUT_CHAN_523750_IDX,
+       OLYMPUS_LUT_CHAN_523875_IDX,
+       OLYMPUS_LUT_CHAN_524000_IDX,
+       OLYMPUS_LUT_CHAN_524125_IDX,
+       OLYMPUS_LUT_CHAN_524250_IDX,
+       OLYMPUS_LUT_CHAN_524375_IDX,
+       OLYMPUS_LUT_CHAN_524500_IDX,
+       OLYMPUS_LUT_CHAN_524625_IDX,
+       OLYMPUS_LUT_CHAN_524750_IDX,
+       OLYMPUS_LUT_CHAN_524875_IDX,
+       OLYMPUS_LUT_CHAN_525000_IDX,
+       OLYMPUS_LUT_CHAN_525125_IDX,
+       OLYMPUS_LUT_CHAN_525250_IDX,
+       OLYMPUS_LUT_CHAN_525375_IDX,
+       OLYMPUS_LUT_CHAN_525500_IDX,
+       OLYMPUS_LUT_CHAN_525625_IDX,
+       OLYMPUS_LUT_CHAN_525750_IDX,
+       OLYMPUS_LUT_CHAN_525875_IDX,
+       OLYMPUS_LUT_CHAN_526000_IDX,
+       OLYMPUS_LUT_CHAN_526125_IDX,
+       OLYMPUS_LUT_CHAN_526250_IDX,
+       OLYMPUS_LUT_CHAN_526375_IDX,
+       OLYMPUS_LUT_CHAN_526500_IDX,
+       OLYMPUS_LUT_CHAN_526625_IDX,
+       OLYMPUS_LUT_CHAN_526750_IDX,
+       OLYMPUS_LUT_CHAN_526875_IDX,
+       OLYMPUS_LUT_CHAN_527000_IDX,
+       OLYMPUS_LUT_CHAN_527125_IDX,
+       OLYMPUS_LUT_CHAN_527250_IDX,
+       OLYMPUS_LUT_CHAN_527375_IDX,
+       OLYMPUS_LUT_CHAN_527500_IDX,
+       OLYMPUS_LUT_CHAN_527625_IDX,
+       OLYMPUS_LUT_CHAN_527750_IDX,
+       OLYMPUS_LUT_CHAN_527875_IDX,
+       OLYMPUS_LUT_CHAN_528000_IDX,
+       OLYMPUS_LUT_CHAN_528125_IDX,
+       OLYMPUS_LUT_CHAN_528250_IDX,
+       OLYMPUS_LUT_CHAN_528375_IDX,
+       OLYMPUS_LUT_CHAN_528500_IDX,
+       OLYMPUS_LUT_CHAN_528625_IDX,
+       OLYMPUS_LUT_CHAN_528750_IDX,
+       OLYMPUS_LUT_CHAN_528875_IDX,
+       OLYMPUS_LUT_CHAN_529000_IDX,
+       OLYMPUS_LUT_CHAN_529125_IDX,
+       OLYMPUS_LUT_CHAN_529250_IDX,
+       OLYMPUS_LUT_CHAN_529375_IDX,
+       OLYMPUS_LUT_CHAN_529500_IDX,
+       OLYMPUS_LUT_CHAN_529625_IDX,
+       OLYMPUS_LUT_CHAN_529750_IDX,
+       OLYMPUS_LUT_CHAN_529875_IDX,
+       OLYMPUS_LUT_CHAN_530000_IDX,
+       OLYMPUS_LUT_CHAN_530125_IDX,
+       OLYMPUS_LUT_CHAN_530250_IDX,
+       OLYMPUS_LUT_CHAN_530375_IDX,
+       OLYMPUS_LUT_CHAN_530500_IDX,
+       OLYMPUS_LUT_CHAN_530625_IDX,
+       OLYMPUS_LUT_CHAN_530750_IDX,
+       OLYMPUS_LUT_CHAN_530875_IDX,
+       OLYMPUS_LUT_CHAN_531000_IDX,
+       OLYMPUS_LUT_CHAN_531125_IDX,
+       OLYMPUS_LUT_CHAN_531250_IDX,
+       OLYMPUS_LUT_CHAN_531375_IDX,
+       OLYMPUS_LUT_CHAN_531500_IDX,
+       OLYMPUS_LUT_CHAN_531625_IDX,
+       OLYMPUS_LUT_CHAN_531750_IDX,
+       OLYMPUS_LUT_CHAN_531875_IDX,
+       OLYMPUS_LUT_CHAN_532000_IDX,
+       OLYMPUS_LUT_CHAN_532125_IDX,
+       OLYMPUS_LUT_CHAN_532250_IDX,
+       OLYMPUS_LUT_CHAN_532375_IDX,
+       OLYMPUS_LUT_CHAN_532500_IDX,
+       OLYMPUS_LUT_CHAN_532625_IDX,
+       OLYMPUS_LUT_CHAN_532750_IDX,
+       OLYMPUS_LUT_CHAN_532875_IDX,
+       OLYMPUS_LUT_CHAN_533000_IDX,
+       OLYMPUS_LUT_CHAN_533125_IDX,
+       OLYMPUS_LUT_CHAN_533250_IDX,
+       OLYMPUS_LUT_CHAN_533375_IDX,
+       OLYMPUS_LUT_CHAN_533500_IDX,
+       OLYMPUS_LUT_CHAN_533625_IDX,
+       OLYMPUS_LUT_CHAN_533750_IDX,
+       OLYMPUS_LUT_CHAN_533875_IDX,
+       OLYMPUS_LUT_CHAN_534000_IDX,
+       OLYMPUS_LUT_CHAN_534125_IDX,
+       OLYMPUS_LUT_CHAN_534250_IDX,
+       OLYMPUS_LUT_CHAN_534375_IDX,
+       OLYMPUS_LUT_CHAN_534500_IDX,
+       OLYMPUS_LUT_CHAN_534625_IDX,
+       OLYMPUS_LUT_CHAN_534750_IDX,
+       OLYMPUS_LUT_CHAN_534875_IDX,
+       OLYMPUS_LUT_CHAN_535000_IDX,
+       OLYMPUS_LUT_CHAN_535125_IDX,
+       OLYMPUS_LUT_CHAN_535250_IDX,
+       OLYMPUS_LUT_CHAN_535375_IDX,
+       OLYMPUS_LUT_CHAN_535500_IDX,
+       OLYMPUS_LUT_CHAN_535625_IDX,
+       OLYMPUS_LUT_CHAN_535750_IDX,
+       OLYMPUS_LUT_CHAN_535875_IDX,
+       OLYMPUS_LUT_CHAN_536000_IDX,
+       OLYMPUS_LUT_CHAN_536125_IDX,
+       OLYMPUS_LUT_CHAN_536250_IDX,
+       OLYMPUS_LUT_CHAN_536375_IDX,
+       OLYMPUS_LUT_CHAN_536500_IDX,
+       OLYMPUS_LUT_CHAN_536625_IDX,
+       OLYMPUS_LUT_CHAN_536750_IDX,
+       OLYMPUS_LUT_CHAN_536875_IDX,
+       OLYMPUS_LUT_CHAN_537000_IDX,
+       OLYMPUS_LUT_CHAN_537125_IDX,
+       OLYMPUS_LUT_CHAN_537250_IDX,
+       OLYMPUS_LUT_CHAN_537375_IDX,
+       OLYMPUS_LUT_CHAN_537500_IDX,
+       OLYMPUS_LUT_CHAN_537625_IDX,
+       OLYMPUS_LUT_CHAN_537750_IDX,
+       OLYMPUS_LUT_CHAN_537875_IDX,
+       OLYMPUS_LUT_CHAN_538000_IDX,
+       OLYMPUS_LUT_CHAN_538125_IDX,
+       OLYMPUS_LUT_CHAN_538250_IDX,
+       OLYMPUS_LUT_CHAN_538375_IDX,
+       OLYMPUS_LUT_CHAN_538500_IDX,
+       OLYMPUS_LUT_CHAN_538625_IDX,
+       OLYMPUS_LUT_CHAN_538750_IDX,
+       OLYMPUS_LUT_CHAN_538875_IDX,
+       OLYMPUS_LUT_CHAN_539000_IDX,
+       OLYMPUS_LUT_CHAN_539125_IDX,
+       OLYMPUS_LUT_CHAN_539250_IDX,
+       OLYMPUS_LUT_CHAN_539375_IDX,
+       OLYMPUS_LUT_CHAN_539500_IDX,
+       OLYMPUS_LUT_CHAN_539625_IDX,
+       OLYMPUS_LUT_CHAN_539750_IDX,
+       OLYMPUS_LUT_CHAN_539875_IDX,
+       OLYMPUS_LUT_CHAN_540000_IDX,
+       OLYMPUS_LUT_CHAN_540125_IDX,
+       OLYMPUS_LUT_CHAN_540250_IDX,
+       OLYMPUS_LUT_CHAN_540375_IDX,
+       OLYMPUS_LUT_CHAN_540500_IDX,
+       OLYMPUS_LUT_CHAN_540625_IDX,
+       OLYMPUS_LUT_CHAN_540750_IDX,
+       OLYMPUS_LUT_CHAN_540875_IDX,
+       OLYMPUS_LUT_CHAN_541000_IDX,
+       OLYMPUS_LUT_CHAN_541125_IDX,
+       OLYMPUS_LUT_CHAN_541250_IDX,
+       OLYMPUS_LUT_CHAN_541375_IDX,
+       OLYMPUS_LUT_CHAN_541500_IDX,
+       OLYMPUS_LUT_CHAN_541625_IDX,
+       OLYMPUS_LUT_CHAN_541750_IDX,
+       OLYMPUS_LUT_CHAN_541875_IDX,
+       OLYMPUS_LUT_CHAN_542000_IDX,
+       OLYMPUS_LUT_CHAN_542125_IDX,
+       OLYMPUS_LUT_CHAN_542250_IDX,
+       OLYMPUS_LUT_CHAN_542375_IDX,
+       OLYMPUS_LUT_CHAN_542500_IDX,
+       OLYMPUS_LUT_CHAN_542625_IDX,
+       OLYMPUS_LUT_CHAN_542750_IDX,
+       OLYMPUS_LUT_CHAN_542875_IDX,
+       OLYMPUS_LUT_CHAN_543000_IDX,
+       OLYMPUS_LUT_CHAN_543125_IDX,
+       OLYMPUS_LUT_CHAN_543250_IDX,
+       OLYMPUS_LUT_CHAN_543375_IDX,
+       OLYMPUS_LUT_CHAN_543500_IDX,
+       OLYMPUS_LUT_CHAN_543625_IDX,
+       OLYMPUS_LUT_CHAN_543750_IDX,
+       OLYMPUS_LUT_CHAN_543875_IDX,
+       OLYMPUS_LUT_CHAN_544000_IDX,
+       OLYMPUS_LUT_CHAN_544125_IDX,
+       OLYMPUS_LUT_CHAN_544250_IDX,
+       OLYMPUS_LUT_CHAN_544375_IDX,
+       OLYMPUS_LUT_CHAN_544500_IDX,
+       OLYMPUS_LUT_CHAN_544625_IDX,
+       OLYMPUS_LUT_CHAN_544750_IDX,
+       OLYMPUS_LUT_CHAN_544875_IDX,
+       OLYMPUS_LUT_CHAN_545000_IDX,
+       OLYMPUS_LUT_CHAN_545125_IDX,
+       OLYMPUS_LUT_CHAN_545250_IDX,
+       OLYMPUS_LUT_CHAN_545375_IDX,
+       OLYMPUS_LUT_CHAN_545500_IDX,
+       OLYMPUS_LUT_CHAN_545625_IDX,
+       OLYMPUS_LUT_CHAN_545750_IDX,
+       OLYMPUS_LUT_CHAN_545875_IDX,
+       OLYMPUS_LUT_CHAN_546000_IDX,
+       OLYMPUS_LUT_CHAN_546125_IDX,
+       OLYMPUS_LUT_CHAN_546250_IDX,
+       OLYMPUS_LUT_CHAN_546375_IDX,
+       OLYMPUS_LUT_CHAN_546500_IDX,
+       OLYMPUS_LUT_CHAN_546625_IDX,
+       OLYMPUS_LUT_CHAN_546750_IDX,
+       OLYMPUS_LUT_CHAN_546875_IDX,
+       OLYMPUS_LUT_CHAN_547000_IDX,
+       OLYMPUS_LUT_CHAN_547125_IDX,
+       OLYMPUS_LUT_CHAN_547250_IDX,
+       OLYMPUS_LUT_CHAN_547375_IDX,
+       OLYMPUS_LUT_CHAN_547500_IDX,
+       OLYMPUS_LUT_CHAN_547625_IDX,
+       OLYMPUS_LUT_CHAN_547750_IDX,
+       OLYMPUS_LUT_CHAN_547875_IDX,
+       OLYMPUS_LUT_CHAN_548000_IDX,
+       OLYMPUS_LUT_CHAN_548125_IDX,
+       OLYMPUS_LUT_CHAN_548250_IDX,
+       OLYMPUS_LUT_CHAN_548375_IDX,
+       OLYMPUS_LUT_CHAN_548500_IDX,
+       OLYMPUS_LUT_CHAN_548625_IDX,
+       OLYMPUS_LUT_CHAN_548750_IDX,
+       OLYMPUS_LUT_CHAN_548875_IDX,
+       OLYMPUS_LUT_CHAN_549000_IDX,
+       OLYMPUS_LUT_CHAN_549125_IDX,
+       OLYMPUS_LUT_CHAN_549250_IDX,
+       OLYMPUS_LUT_CHAN_549375_IDX,
+       OLYMPUS_LUT_CHAN_549500_IDX,
+       OLYMPUS_LUT_CHAN_549625_IDX,
+       OLYMPUS_LUT_CHAN_549750_IDX,
+       OLYMPUS_LUT_CHAN_549875_IDX,
+       OLYMPUS_LUT_CHAN_550000_IDX,
+       OLYMPUS_LUT_CHAN_550125_IDX,
+       OLYMPUS_LUT_CHAN_550250_IDX,
+       OLYMPUS_LUT_CHAN_550375_IDX,
+       OLYMPUS_LUT_CHAN_550500_IDX,
+       OLYMPUS_LUT_CHAN_550625_IDX,
+       OLYMPUS_LUT_CHAN_550750_IDX,
+       OLYMPUS_LUT_CHAN_550875_IDX,
+       OLYMPUS_LUT_CHAN_551000_IDX,
+       OLYMPUS_LUT_CHAN_551125_IDX,
+       OLYMPUS_LUT_CHAN_551250_IDX,
+       OLYMPUS_LUT_CHAN_551375_IDX,
+       OLYMPUS_LUT_CHAN_551500_IDX,
+       OLYMPUS_LUT_CHAN_551625_IDX,
+       OLYMPUS_LUT_CHAN_551750_IDX,
+       OLYMPUS_LUT_CHAN_551875_IDX,
+       OLYMPUS_LUT_CHAN_552000_IDX,
+       OLYMPUS_LUT_CHAN_552125_IDX,
+       OLYMPUS_LUT_CHAN_552250_IDX,
+       OLYMPUS_LUT_CHAN_552375_IDX,
+       OLYMPUS_LUT_CHAN_552500_IDX,
+       OLYMPUS_LUT_CHAN_552625_IDX,
+       OLYMPUS_LUT_CHAN_552750_IDX,
+       OLYMPUS_LUT_CHAN_552875_IDX,
+       OLYMPUS_LUT_CHAN_553000_IDX,
+       OLYMPUS_LUT_CHAN_553125_IDX,
+       OLYMPUS_LUT_CHAN_553250_IDX,
+       OLYMPUS_LUT_CHAN_553375_IDX,
+       OLYMPUS_LUT_CHAN_553500_IDX,
+       OLYMPUS_LUT_CHAN_553625_IDX,
+       OLYMPUS_LUT_CHAN_553750_IDX,
+       OLYMPUS_LUT_CHAN_553875_IDX,
+       OLYMPUS_LUT_CHAN_554000_IDX,
+       OLYMPUS_LUT_CHAN_554125_IDX,
+       OLYMPUS_LUT_CHAN_554250_IDX,
+       OLYMPUS_LUT_CHAN_554375_IDX,
+       OLYMPUS_LUT_CHAN_554500_IDX,
+       OLYMPUS_LUT_CHAN_554625_IDX,
+       OLYMPUS_LUT_CHAN_554750_IDX,
+       OLYMPUS_LUT_CHAN_554875_IDX,
+       OLYMPUS_LUT_CHAN_555000_IDX,
+       OLYMPUS_LUT_CHAN_555125_IDX,
+       OLYMPUS_LUT_CHAN_555250_IDX,
+       OLYMPUS_LUT_CHAN_555375_IDX,
+       OLYMPUS_LUT_CHAN_555500_IDX,
+       OLYMPUS_LUT_CHAN_555625_IDX,
+       OLYMPUS_LUT_CHAN_555750_IDX,
+       OLYMPUS_LUT_CHAN_555875_IDX,
+       OLYMPUS_LUT_CHAN_556000_IDX,
+       OLYMPUS_LUT_CHAN_556125_IDX,
+       OLYMPUS_LUT_CHAN_556250_IDX,
+       OLYMPUS_LUT_CHAN_556375_IDX,
+       OLYMPUS_LUT_CHAN_556500_IDX,
+       OLYMPUS_LUT_CHAN_556625_IDX,
+       OLYMPUS_LUT_CHAN_556750_IDX,
+       OLYMPUS_LUT_CHAN_556875_IDX,
+       OLYMPUS_LUT_CHAN_557000_IDX,
+       OLYMPUS_LUT_CHAN_557125_IDX,
+       OLYMPUS_LUT_CHAN_557250_IDX,
+       OLYMPUS_LUT_CHAN_557375_IDX,
+       OLYMPUS_LUT_CHAN_557500_IDX,
+       OLYMPUS_LUT_CHAN_557625_IDX,
+       OLYMPUS_LUT_CHAN_557750_IDX,
+       OLYMPUS_LUT_CHAN_557875_IDX,
+       OLYMPUS_LUT_CHAN_558000_IDX,
+       OLYMPUS_LUT_CHAN_558125_IDX,
+       OLYMPUS_LUT_CHAN_558250_IDX,
+       OLYMPUS_LUT_CHAN_558375_IDX,
+       OLYMPUS_LUT_CHAN_558500_IDX,
+       OLYMPUS_LUT_CHAN_558625_IDX,
+       OLYMPUS_LUT_CHAN_558750_IDX,
+       OLYMPUS_LUT_CHAN_558875_IDX,
+       OLYMPUS_LUT_CHAN_559000_IDX,
+       OLYMPUS_LUT_CHAN_559125_IDX,
+       OLYMPUS_LUT_CHAN_559250_IDX,
+       OLYMPUS_LUT_CHAN_559375_IDX,
+       OLYMPUS_LUT_CHAN_559500_IDX,
+       OLYMPUS_LUT_CHAN_559625_IDX,
+       OLYMPUS_LUT_CHAN_559750_IDX,
+       OLYMPUS_LUT_CHAN_559875_IDX,
+       OLYMPUS_LUT_CHAN_560000_IDX,
+       OLYMPUS_LUT_CHAN_560125_IDX,
+       OLYMPUS_LUT_CHAN_560250_IDX,
+       OLYMPUS_LUT_CHAN_560375_IDX,
+       OLYMPUS_LUT_CHAN_560500_IDX,
+       OLYMPUS_LUT_CHAN_560625_IDX,
+       OLYMPUS_LUT_CHAN_560750_IDX,
+       OLYMPUS_LUT_CHAN_560875_IDX,
+       OLYMPUS_LUT_CHAN_561000_IDX,
+       OLYMPUS_LUT_CHAN_561125_IDX,
+       OLYMPUS_LUT_CHAN_561250_IDX,
+       OLYMPUS_LUT_CHAN_561375_IDX,
+       OLYMPUS_LUT_CHAN_561500_IDX,
+       OLYMPUS_LUT_CHAN_561625_IDX,
+       OLYMPUS_LUT_CHAN_561750_IDX,
+       OLYMPUS_LUT_CHAN_561875_IDX,
+       OLYMPUS_LUT_CHAN_562000_IDX,
+       OLYMPUS_LUT_CHAN_562125_IDX,
+       OLYMPUS_LUT_CHAN_562250_IDX,
+       OLYMPUS_LUT_CHAN_562375_IDX,
+       OLYMPUS_LUT_CHAN_562500_IDX,
+       OLYMPUS_LUT_CHAN_562625_IDX,
+       OLYMPUS_LUT_CHAN_562750_IDX,
+       OLYMPUS_LUT_CHAN_562875_IDX,
+       OLYMPUS_LUT_CHAN_563000_IDX,
+       OLYMPUS_LUT_CHAN_563125_IDX,
+       OLYMPUS_LUT_CHAN_563250_IDX,
+       OLYMPUS_LUT_CHAN_563375_IDX,
+       OLYMPUS_LUT_CHAN_563500_IDX,
+       OLYMPUS_LUT_CHAN_563625_IDX,
+       OLYMPUS_LUT_CHAN_563750_IDX,
+       OLYMPUS_LUT_CHAN_563875_IDX,
+       OLYMPUS_LUT_CHAN_564000_IDX,
+       OLYMPUS_LUT_CHAN_564125_IDX,
+       OLYMPUS_LUT_CHAN_564250_IDX,
+       OLYMPUS_LUT_CHAN_564375_IDX,
+       OLYMPUS_LUT_CHAN_564500_IDX,
+       OLYMPUS_LUT_CHAN_564625_IDX,
+       OLYMPUS_LUT_CHAN_564750_IDX,
+       OLYMPUS_LUT_CHAN_564875_IDX,
+       OLYMPUS_LUT_CHAN_565000_IDX,
+       OLYMPUS_LUT_CHAN_565125_IDX,
+       OLYMPUS_LUT_CHAN_565250_IDX,
+       OLYMPUS_LUT_CHAN_565375_IDX,
+       OLYMPUS_LUT_CHAN_565500_IDX,
+       OLYMPUS_LUT_CHAN_565625_IDX,
+       OLYMPUS_LUT_CHAN_565750_IDX,
+       OLYMPUS_LUT_CHAN_565875_IDX,
+       OLYMPUS_LUT_CHAN_566000_IDX,
+       OLYMPUS_LUT_CHAN_566125_IDX,
+       OLYMPUS_LUT_CHAN_566250_IDX,
+       OLYMPUS_LUT_CHAN_566375_IDX,
+       OLYMPUS_LUT_CHAN_566500_IDX,
+       OLYMPUS_LUT_CHAN_566625_IDX,
+       OLYMPUS_LUT_CHAN_566750_IDX,
+       OLYMPUS_LUT_CHAN_566875_IDX,
+       OLYMPUS_LUT_CHAN_567000_IDX,
+       OLYMPUS_LUT_CHAN_567125_IDX,
+       OLYMPUS_LUT_CHAN_567250_IDX,
+       OLYMPUS_LUT_CHAN_567375_IDX,
+       OLYMPUS_LUT_CHAN_567500_IDX,
+       OLYMPUS_LUT_CHAN_567625_IDX,
+       OLYMPUS_LUT_CHAN_567750_IDX,
+       OLYMPUS_LUT_CHAN_567875_IDX,
+       OLYMPUS_LUT_CHAN_568000_IDX,
+       OLYMPUS_LUT_CHAN_568125_IDX,
+       OLYMPUS_LUT_CHAN_568250_IDX,
+       OLYMPUS_LUT_CHAN_568375_IDX,
+       OLYMPUS_LUT_CHAN_568500_IDX,
+       OLYMPUS_LUT_CHAN_568625_IDX,
+       OLYMPUS_LUT_CHAN_568750_IDX,
+       OLYMPUS_LUT_CHAN_568875_IDX,
+       OLYMPUS_LUT_CHAN_569000_IDX,
+       OLYMPUS_LUT_CHAN_569125_IDX,
+       OLYMPUS_LUT_CHAN_569250_IDX,
+       OLYMPUS_LUT_CHAN_569375_IDX,
+       OLYMPUS_LUT_CHAN_569500_IDX,
+       OLYMPUS_LUT_CHAN_569625_IDX,
+       OLYMPUS_LUT_CHAN_569750_IDX,
+       OLYMPUS_LUT_CHAN_569875_IDX,
+       OLYMPUS_LUT_CHAN_570000_IDX,
+       OLYMPUS_LUT_CHAN_570125_IDX,
+       OLYMPUS_LUT_CHAN_570250_IDX,
+       OLYMPUS_LUT_CHAN_570375_IDX,
+       OLYMPUS_LUT_CHAN_570500_IDX,
+       OLYMPUS_LUT_CHAN_570625_IDX,
+       OLYMPUS_LUT_CHAN_570750_IDX,
+       OLYMPUS_LUT_CHAN_570875_IDX,
+       OLYMPUS_LUT_CHAN_571000_IDX,
+       OLYMPUS_LUT_CHAN_571125_IDX,
+       OLYMPUS_LUT_CHAN_571250_IDX,
+       OLYMPUS_LUT_CHAN_571375_IDX,
+       OLYMPUS_LUT_CHAN_571500_IDX,
+       OLYMPUS_LUT_CHAN_571625_IDX,
+       OLYMPUS_LUT_CHAN_571750_IDX,
+       OLYMPUS_LUT_CHAN_571875_IDX,
+       OLYMPUS_LUT_CHAN_572000_IDX,
+       OLYMPUS_LUT_CHAN_572125_IDX,
+       OLYMPUS_LUT_CHAN_572250_IDX,
+       OLYMPUS_LUT_CHAN_572375_IDX,
+       OLYMPUS_LUT_CHAN_572500_IDX,
+       OLYMPUS_LUT_CHAN_572625_IDX,
+       OLYMPUS_LUT_CHAN_572750_IDX,
+       OLYMPUS_LUT_CHAN_572875_IDX,
+       OLYMPUS_LUT_CHAN_573000_IDX,
+       OLYMPUS_LUT_CHAN_573125_IDX,
+       OLYMPUS_LUT_CHAN_573250_IDX,
+       OLYMPUS_LUT_CHAN_573375_IDX,
+       OLYMPUS_LUT_CHAN_573500_IDX,
+       OLYMPUS_LUT_CHAN_573625_IDX,
+       OLYMPUS_LUT_CHAN_573750_IDX,
+       OLYMPUS_LUT_CHAN_573875_IDX,
+       OLYMPUS_LUT_CHAN_574000_IDX,
+       OLYMPUS_LUT_CHAN_574125_IDX,
+       OLYMPUS_LUT_CHAN_574250_IDX,
+       OLYMPUS_LUT_CHAN_574375_IDX,
+       OLYMPUS_LUT_CHAN_574500_IDX,
+       OLYMPUS_LUT_CHAN_574625_IDX,
+       OLYMPUS_LUT_CHAN_574750_IDX,
+       OLYMPUS_LUT_CHAN_574875_IDX,
+       OLYMPUS_LUT_CHAN_575000_IDX,
+       OLYMPUS_LUT_CHAN_575125_IDX,
+       OLYMPUS_LUT_CHAN_575250_IDX,
+       OLYMPUS_LUT_CHAN_575375_IDX,
+       OLYMPUS_LUT_CHAN_575500_IDX,
+       OLYMPUS_LUT_CHAN_575625_IDX,
+       OLYMPUS_LUT_CHAN_575750_IDX,
+       OLYMPUS_LUT_CHAN_575875_IDX,
+       OLYMPUS_LUT_CHAN_576000_IDX,
+       OLYMPUS_LUT_CHAN_576125_IDX,
+       OLYMPUS_LUT_CHAN_576250_IDX,
+       OLYMPUS_LUT_CHAN_576375_IDX,
+       OLYMPUS_LUT_CHAN_576500_IDX,
+       OLYMPUS_LUT_CHAN_576625_IDX,
+       OLYMPUS_LUT_CHAN_576750_IDX,
+       OLYMPUS_LUT_CHAN_576875_IDX,
+       OLYMPUS_LUT_CHAN_577000_IDX,
+       OLYMPUS_LUT_CHAN_577125_IDX,
+       OLYMPUS_LUT_CHAN_577250_IDX,
+       OLYMPUS_LUT_CHAN_577375_IDX,
+       OLYMPUS_LUT_CHAN_577500_IDX,
+       OLYMPUS_LUT_CHAN_577625_IDX,
+       OLYMPUS_LUT_CHAN_577750_IDX,
+       OLYMPUS_LUT_CHAN_577875_IDX,
+       OLYMPUS_LUT_CHAN_578000_IDX,
+       OLYMPUS_LUT_CHAN_578125_IDX,
+       OLYMPUS_LUT_CHAN_578250_IDX,
+       OLYMPUS_LUT_CHAN_578375_IDX,
+       OLYMPUS_LUT_CHAN_578500_IDX,
+       OLYMPUS_LUT_CHAN_578625_IDX,
+       OLYMPUS_LUT_CHAN_578750_IDX,
+       OLYMPUS_LUT_CHAN_578875_IDX,
+       OLYMPUS_LUT_CHAN_579000_IDX,
+       OLYMPUS_LUT_CHAN_579125_IDX,
+       OLYMPUS_LUT_CHAN_579250_IDX,
+       OLYMPUS_LUT_CHAN_579375_IDX,
+       OLYMPUS_LUT_CHAN_579500_IDX,
+       OLYMPUS_LUT_CHAN_579625_IDX,
+       OLYMPUS_LUT_CHAN_579750_IDX,
+       OLYMPUS_LUT_CHAN_579875_IDX,
+       OLYMPUS_LUT_CHAN_580000_IDX,
+       OLYMPUS_LUT_CHAN_580125_IDX,
+       OLYMPUS_LUT_CHAN_580250_IDX,
+       OLYMPUS_LUT_CHAN_580375_IDX,
+       OLYMPUS_LUT_CHAN_580500_IDX,
+       OLYMPUS_LUT_CHAN_580625_IDX,
+       OLYMPUS_LUT_CHAN_580750_IDX,
+       OLYMPUS_LUT_CHAN_580875_IDX,
+       OLYMPUS_LUT_CHAN_581000_IDX,
+       OLYMPUS_LUT_CHAN_581125_IDX,
+       OLYMPUS_LUT_CHAN_581250_IDX,
+       OLYMPUS_LUT_CHAN_581375_IDX,
+       OLYMPUS_LUT_CHAN_581500_IDX,
+       OLYMPUS_LUT_CHAN_581625_IDX,
+       OLYMPUS_LUT_CHAN_581750_IDX,
+       OLYMPUS_LUT_CHAN_581875_IDX,
+       OLYMPUS_LUT_CHAN_582000_IDX,
+       OLYMPUS_LUT_CHAN_582125_IDX,
+       OLYMPUS_LUT_CHAN_582250_IDX,
+       OLYMPUS_LUT_CHAN_582375_IDX,
+       OLYMPUS_LUT_CHAN_582500_IDX,
+       OLYMPUS_LUT_CHAN_582625_IDX,
+       OLYMPUS_LUT_CHAN_582750_IDX,
+       OLYMPUS_LUT_CHAN_582875_IDX,
+       OLYMPUS_LUT_CHAN_583000_IDX,
+       OLYMPUS_LUT_CHAN_583125_IDX,
+       OLYMPUS_LUT_CHAN_583250_IDX,
+       OLYMPUS_LUT_CHAN_583375_IDX,
+       OLYMPUS_LUT_CHAN_583500_IDX,
+       OLYMPUS_LUT_CHAN_583625_IDX,
+       OLYMPUS_LUT_CHAN_583750_IDX,
+       OLYMPUS_LUT_CHAN_583875_IDX,
+       OLYMPUS_LUT_CHAN_584000_IDX,
+       OLYMPUS_LUT_CHAN_584125_IDX,
+       OLYMPUS_LUT_CHAN_584250_IDX,
+       OLYMPUS_LUT_CHAN_584375_IDX,
+       OLYMPUS_LUT_CHAN_584500_IDX,
+       OLYMPUS_LUT_CHAN_584625_IDX,
+       OLYMPUS_LUT_CHAN_584750_IDX,
+       OLYMPUS_LUT_CHAN_584875_IDX,
+       OLYMPUS_LUT_CHAN_585000_IDX,
+       OLYMPUS_LUT_CHAN_585125_IDX,
+       OLYMPUS_LUT_CHAN_585250_IDX,
+       OLYMPUS_LUT_CHAN_585375_IDX,
+       OLYMPUS_LUT_CHAN_585500_IDX,
+       OLYMPUS_LUT_CHAN_585625_IDX,
+       OLYMPUS_LUT_CHAN_585750_IDX,
+       OLYMPUS_LUT_CHAN_585875_IDX,
+       OLYMPUS_LUT_CHAN_586000_IDX,
+       OLYMPUS_LUT_CHAN_586125_IDX,
+       OLYMPUS_LUT_CHAN_586250_IDX,
+       OLYMPUS_LUT_CHAN_586375_IDX,
+       OLYMPUS_LUT_CHAN_586500_IDX,
+       OLYMPUS_LUT_CHAN_586625_IDX,
+       OLYMPUS_LUT_CHAN_586750_IDX,
+       OLYMPUS_LUT_CHAN_586875_IDX,
+       OLYMPUS_LUT_CHAN_587000_IDX,
+       OLYMPUS_LUT_CHAN_587125_IDX,
+       OLYMPUS_LUT_CHAN_587250_IDX,
+       OLYMPUS_LUT_CHAN_587375_IDX,
+       OLYMPUS_LUT_CHAN_587500_IDX,
+       OLYMPUS_LUT_CHAN_587625_IDX,
+       OLYMPUS_LUT_CHAN_587750_IDX,
+       OLYMPUS_LUT_CHAN_587875_IDX,
+       OLYMPUS_LUT_CHAN_588000_IDX,
+       OLYMPUS_LUT_CHAN_588125_IDX,
+       OLYMPUS_LUT_CHAN_588250_IDX,
+       OLYMPUS_LUT_CHAN_588375_IDX,
+       OLYMPUS_LUT_CHAN_588500_IDX,
+       OLYMPUS_LUT_CHAN_588625_IDX,
+       OLYMPUS_LUT_CHAN_588750_IDX,
+       OLYMPUS_LUT_CHAN_588875_IDX,
+       OLYMPUS_LUT_CHAN_589000_IDX,
+       OLYMPUS_LUT_CHAN_589125_IDX,
+       OLYMPUS_LUT_CHAN_589250_IDX,
+       OLYMPUS_LUT_CHAN_589375_IDX,
+       OLYMPUS_LUT_CHAN_589500_IDX,
+       OLYMPUS_LUT_CHAN_589625_IDX,
+       OLYMPUS_LUT_CHAN_589750_IDX,
+       OLYMPUS_LUT_CHAN_589875_IDX,
+       OLYMPUS_LUT_CHAN_590000_IDX,
+       OLYMPUS_LUT_CHAN_590125_IDX,
+       OLYMPUS_LUT_CHAN_590250_IDX,
+       OLYMPUS_LUT_CHAN_590375_IDX,
+       OLYMPUS_LUT_CHAN_590500_IDX,
+       OLYMPUS_LUT_CHAN_590625_IDX,
+       OLYMPUS_LUT_CHAN_590750_IDX,
+       OLYMPUS_LUT_CHAN_590875_IDX,
+       OLYMPUS_LUT_CHAN_591000_IDX,
+       OLYMPUS_LUT_CHAN_591125_IDX,
+       OLYMPUS_LUT_CHAN_591250_IDX,
+       OLYMPUS_LUT_CHAN_591375_IDX,
+       OLYMPUS_LUT_CHAN_591500_IDX,
+       OLYMPUS_LUT_CHAN_591625_IDX,
+       OLYMPUS_LUT_CHAN_591750_IDX,
+       OLYMPUS_LUT_CHAN_591875_IDX,
+       OLYMPUS_LUT_CHAN_592000_IDX,
+       OLYMPUS_LUT_CHAN_592125_IDX,
+       OLYMPUS_LUT_CHAN_592250_IDX,
+       OLYMPUS_LUT_CHAN_592375_IDX,
+       OLYMPUS_LUT_CHAN_592500_IDX,
+       OLYMPUS_LUT_CHAN_592625_IDX,
+       OLYMPUS_LUT_CHAN_592750_IDX,
+       OLYMPUS_LUT_CHAN_592875_IDX,
+       OLYMPUS_LUT_CHAN_593000_IDX,
+       OLYMPUS_LUT_CHAN_593125_IDX,
+       OLYMPUS_LUT_CHAN_593250_IDX,
+       OLYMPUS_LUT_CHAN_593375_IDX,
+       OLYMPUS_LUT_CHAN_593500_IDX,
+       OLYMPUS_LUT_CHAN_593625_IDX,
+       OLYMPUS_LUT_CHAN_593750_IDX,
+       OLYMPUS_LUT_CHAN_593875_IDX,
+       OLYMPUS_LUT_CHAN_594000_IDX,
+       OLYMPUS_LUT_CHAN_594125_IDX,
+       OLYMPUS_LUT_CHAN_594250_IDX,
+       OLYMPUS_LUT_CHAN_594375_IDX,
+       OLYMPUS_LUT_CHAN_594500_IDX,
+       OLYMPUS_LUT_CHAN_594625_IDX,
+       OLYMPUS_LUT_CHAN_594750_IDX,
+       OLYMPUS_LUT_CHAN_594875_IDX,
+       OLYMPUS_LUT_CHAN_595000_IDX,
+       OLYMPUS_LUT_CHAN_595125_IDX,
+       OLYMPUS_LUT_CHAN_595250_IDX,
+       OLYMPUS_LUT_CHAN_595375_IDX,
+       OLYMPUS_LUT_CHAN_595500_IDX,
+       OLYMPUS_LUT_CHAN_595625_IDX,
+       OLYMPUS_LUT_CHAN_595750_IDX,
+       OLYMPUS_LUT_CHAN_595875_IDX,
+       OLYMPUS_LUT_CHAN_596000_IDX,
+       OLYMPUS_LUT_CHAN_596125_IDX,
+       OLYMPUS_LUT_CHAN_596250_IDX,
+       OLYMPUS_LUT_CHAN_596375_IDX,
+       OLYMPUS_LUT_CHAN_596500_IDX,
+       OLYMPUS_LUT_CHAN_596625_IDX,
+       OLYMPUS_LUT_CHAN_596750_IDX,
+       OLYMPUS_LUT_CHAN_596875_IDX,
+       OLYMPUS_LUT_CHAN_597000_IDX,
+       OLYMPUS_LUT_CHAN_597125_IDX,
+       OLYMPUS_LUT_CHAN_597250_IDX,
+       OLYMPUS_LUT_CHAN_597375_IDX,
+       OLYMPUS_LUT_CHAN_597500_IDX,
+       OLYMPUS_LUT_CHAN_597625_IDX,
+       OLYMPUS_LUT_CHAN_597750_IDX,
+       OLYMPUS_LUT_CHAN_597875_IDX,
+       OLYMPUS_LUT_CHAN_598000_IDX,
+       OLYMPUS_LUT_CHAN_598125_IDX,
+       OLYMPUS_LUT_CHAN_598250_IDX,
+       OLYMPUS_LUT_CHAN_598375_IDX,
+       OLYMPUS_LUT_CHAN_598500_IDX,
+       OLYMPUS_LUT_CHAN_598625_IDX,
+       OLYMPUS_LUT_CHAN_598750_IDX,
+       OLYMPUS_LUT_CHAN_598875_IDX,
+       OLYMPUS_LUT_CHAN_599000_IDX,
+       OLYMPUS_LUT_CHAN_599125_IDX,
+       OLYMPUS_LUT_CHAN_599250_IDX,
+       OLYMPUS_LUT_CHAN_599375_IDX,
+       OLYMPUS_LUT_CHAN_599500_IDX,
+       OLYMPUS_LUT_CHAN_599625_IDX,
+       OLYMPUS_LUT_CHAN_599750_IDX,
+       OLYMPUS_LUT_CHAN_599875_IDX,
+       OLYMPUS_LUT_CHAN_600000_IDX,
+       OLYMPUS_LUT_CHAN_5G_MAX
+};
+
+enum OLYMPUS_lut_idx_24g {
+       OLYMPUS_LUT_CHAN_240700_IDX,
+       OLYMPUS_LUT_CHAN_240825_IDX,
+       OLYMPUS_LUT_CHAN_240950_IDX,
+       OLYMPUS_LUT_CHAN_241075_IDX,
+       OLYMPUS_LUT_CHAN_241200_IDX,
+       OLYMPUS_LUT_CHAN_241325_IDX,
+       OLYMPUS_LUT_CHAN_241450_IDX,
+       OLYMPUS_LUT_CHAN_241575_IDX,
+       OLYMPUS_LUT_CHAN_241700_IDX,
+       OLYMPUS_LUT_CHAN_241825_IDX,
+       OLYMPUS_LUT_CHAN_241950_IDX,
+       OLYMPUS_LUT_CHAN_242075_IDX,
+       OLYMPUS_LUT_CHAN_242200_IDX,
+       OLYMPUS_LUT_CHAN_242325_IDX,
+       OLYMPUS_LUT_CHAN_242450_IDX,
+       OLYMPUS_LUT_CHAN_242575_IDX,
+       OLYMPUS_LUT_CHAN_242700_IDX,
+       OLYMPUS_LUT_CHAN_242825_IDX,
+       OLYMPUS_LUT_CHAN_242950_IDX,
+       OLYMPUS_LUT_CHAN_243075_IDX,
+       OLYMPUS_LUT_CHAN_243200_IDX,
+       OLYMPUS_LUT_CHAN_243325_IDX,
+       OLYMPUS_LUT_CHAN_243450_IDX,
+       OLYMPUS_LUT_CHAN_243575_IDX,
+       OLYMPUS_LUT_CHAN_243700_IDX,
+       OLYMPUS_LUT_CHAN_243825_IDX,
+       OLYMPUS_LUT_CHAN_243950_IDX,
+       OLYMPUS_LUT_CHAN_244075_IDX,
+       OLYMPUS_LUT_CHAN_244200_IDX,
+       OLYMPUS_LUT_CHAN_244325_IDX,
+       OLYMPUS_LUT_CHAN_244450_IDX,
+       OLYMPUS_LUT_CHAN_244575_IDX,
+       OLYMPUS_LUT_CHAN_244700_IDX,
+       OLYMPUS_LUT_CHAN_244825_IDX,
+       OLYMPUS_LUT_CHAN_244950_IDX,
+       OLYMPUS_LUT_CHAN_245075_IDX,
+       OLYMPUS_LUT_CHAN_245200_IDX,
+       OLYMPUS_LUT_CHAN_245325_IDX,
+       OLYMPUS_LUT_CHAN_245450_IDX,
+       OLYMPUS_LUT_CHAN_245575_IDX,
+       OLYMPUS_LUT_CHAN_245700_IDX,
+       OLYMPUS_LUT_CHAN_245825_IDX,
+       OLYMPUS_LUT_CHAN_245950_IDX,
+       OLYMPUS_LUT_CHAN_246075_IDX,
+       OLYMPUS_LUT_CHAN_246200_IDX,
+       OLYMPUS_LUT_CHAN_246325_IDX,
+       OLYMPUS_LUT_CHAN_246450_IDX,
+       OLYMPUS_LUT_CHAN_246575_IDX,
+       OLYMPUS_LUT_CHAN_246700_IDX,
+       OLYMPUS_LUT_CHAN_246825_IDX,
+       OLYMPUS_LUT_CHAN_246950_IDX,
+       OLYMPUS_LUT_CHAN_247075_IDX,
+       OLYMPUS_LUT_CHAN_247200_IDX,
+       OLYMPUS_LUT_CHAN_247325_IDX,
+       OLYMPUS_LUT_CHAN_247450_IDX,
+       OLYMPUS_LUT_CHAN_247575_IDX,
+       OLYMPUS_LUT_CHAN_247700_IDX,
+       OLYMPUS_LUT_CHAN_247825_IDX,
+       OLYMPUS_LUT_CHAN_247950_IDX,
+       OLYMPUS_LUT_CHAN_248075_IDX,
+       OLYMPUS_LUT_CHAN_248200_IDX,
+       OLYMPUS_LUT_CHAN_248325_IDX,
+       OLYMPUS_LUT_CHAN_248450_IDX,
+       OLYMPUS_LUT_CHAN_248575_IDX,
+       OLYMPUS_LUT_CHAN_248700_IDX,
+       OLYMPUS_LUT_CHAN_248825_IDX,
+       OLYMPUS_LUT_CHAN_248950_IDX,
+       OLYMPUS_LUT_CHAN_249075_IDX,
+       OLYMPUS_LUT_CHAN_249200_IDX,
+       OLYMPUS_LUT_CHAN_249325_IDX,
+       OLYMPUS_LUT_CHAN_249450_IDX,
+       OLYMPUS_LUT_CHAN_249575_IDX,
+       OLYMPUS_LUT_CHAN_249700_IDX,
+       OLYMPUS_LUT_CHAN_249825_IDX,
+       OLYMPUS_LUT_CHAN_249950_IDX,
+       OLYMPUS_LUT_CHAN_250075_IDX,
+       OLYMPUS_LUT_CHAN_24G_MAX
+};
+
+#define olympus_lut_line common_lut_line
+
+extern const struct olympus_lut_line olympus_lut_5g_40_mhz[OLYMPUS_LUT_CHAN_5G_MAX];
+extern const struct olympus_lut_line olympus_lut_5g_60_mhz_s1[OLYMPUS_LUT_CHAN_5G_MAX];
+extern const struct olympus_lut_line olympus_lut_24g_40_mhz[OLYMPUS_LUT_CHAN_24G_MAX];
+extern const struct olympus_lut_line olympus_lut_24g_60_mhz_s0[OLYMPUS_LUT_CHAN_24G_MAX];
+extern const struct olympus_lut_line olympus_lut_24g_60_mhz_s1[OLYMPUS_LUT_CHAN_24G_MAX];
+extern const struct olympus_lut_line olympus_lut_5g_60_mhz_s0[OLYMPUS_LUT_CHAN_5G_MAX];
+
+#endif /* CL_PHY_OLYMPUS_LUT_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.
________________________________


^ permalink raw reply related	[flat|nested] 262+ messages in thread

* [RFC v1 133/256] cl8k: add power.c
  2021-06-17 15:58 [RFC v1 000/256] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (131 preceding siblings ...)
  2021-06-17 16:00 ` [RFC v1 132/256] cl8k: add phy/phy_olympus_lut.h viktor.barna
@ 2021-06-17 16:00 ` viktor.barna
  2021-06-17 16:00 ` [RFC v1 134/256] cl8k: add power.h viktor.barna
                   ` (124 subsequent siblings)
  257 siblings, 0 replies; 262+ messages in thread
From: viktor.barna @ 2021-06-17 16:00 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Oleksandr Savchenko, Shay Bar, Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

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

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 drivers/net/wireless/celeno/cl8k/power.c | 946 +++++++++++++++++++++++
 1 file changed, 946 insertions(+)
 create mode 100644 drivers/net/wireless/celeno/cl8k/power.c

diff --git a/drivers/net/wireless/celeno/cl8k/power.c b/drivers/net/wireless/celeno/cl8k/power.c
new file mode 100644
index 000000000000..6662bc0ebd66
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/power.c
@@ -0,0 +1,946 @@
+// SPDX-License-Identifier: MIT
+/* Copyright(c) 2019-2021, Celeno Communications Ltd. */
+
+#include <linux/string.h>
+#include "power.h"
+#include "reg/reg_access.h"
+#include "chan_info.h"
+#include "utils/utils.h"
+#include "band.h"
+#include "utils/string.h"
+#include "channel.h"
+
+static s32 convert_str_int_q8(s8 *str)
+{
+       s32 x, y;
+
+       if (!str)
+               return 0;
+       if (sscanf(str, "%d.%2d", &x, &y) == 0)
+               return 0;
+       if (!strstr(str, "."))
+               return x << 8;
+       if (y < 10 && (*(strstr(str, ".") + 1) != '0'))
+               y *= 10;
+       return ((x * 100 + y) << 8) / 100;
+}
+
+u8 cl_power_tx_ant(struct cl_hw *cl_hw, enum cl_wrs_mode mode)
+{
+       if (mode == WRS_MODE_CCK)
+               return hweight8(cl_hw->conf->ce_cck_tx_ant_mask);
+
+       if (mode <= WRS_MODE_VHT)
+               return min_t(u8, cl_hw->num_antennas, MAX_ANTENNAS_OFDM_HT_VHT);
+
+       return cl_hw->num_antennas;
+}
+
+s32 cl_power_antenna_gain_q8(struct cl_hw *cl_hw)
+{
+       u8 channel = cl_hw->channel;
+
+       if (channel >= 36 && channel <= 64)
+               return convert_str_int_q8(cl_hw->conf->ce_ant_gain_36_64);
+       else if (channel >= 100 && channel <= 140)
+               return convert_str_int_q8(cl_hw->conf->ce_ant_gain_100_140);
+       else if (channel >= 149 && channel < 165)
+               return convert_str_int_q8(cl_hw->conf->ce_ant_gain_149_165);
+       else
+               return convert_str_int_q8(cl_hw->conf->ce_ant_gain); /* 2.4g and 6g */
+}
+
+s32 cl_power_antenna_gain_q1(struct cl_hw *cl_hw)
+{
+       return cl_power_antenna_gain_q8(cl_hw) >> 7;
+}
+
+s32 cl_power_array_gain_q8(struct cl_hw *cl_hw, u8 tx_ant)
+{
+       /*
+        * Format in NVRAM of ce_arr_gain=A,B,C,D,E,F
+        * A is the array gain with 1 tx_ant, B is with 2 tx_ant and so on...
+        */
+       int arr_gain_val = 0;
+       int arr_gain_len = 0;
+       int idx = 0;
+       s8 *arr_gain_cpy = NULL;
+       s8 *arr_gain_str = NULL;
+       s8 *arr_gain_tmp = NULL;
+
+       arr_gain_len = strlen(cl_hw->conf->ce_arr_gain) + 1;
+       arr_gain_cpy = kzalloc(arr_gain_len, GFP_ATOMIC);
+
+       if (!arr_gain_cpy)
+               return 0;
+
+       /* Copy cl_hw->conf->ce_arr_gain so its value won't be changed by cl_strtok_r() */
+       memcpy(arr_gain_cpy, cl_hw->conf->ce_arr_gain, arr_gain_len);
+
+       /* Arr_gain_str points to the array gain of 1 tx_ant */
+       arr_gain_str = cl_strtok_r(arr_gain_cpy, ",", &arr_gain_tmp);
+
+       /* Only a single value in ce_arr_gain - same value will be applied for all tx_ant */
+       if (!arr_gain_tmp) {
+               arr_gain_val = convert_str_int_q8(arr_gain_cpy);
+       } else {
+               /* Keep iterating until getting to the correct ant idx */
+               for (idx = 1; arr_gain_str && (idx < tx_ant); idx++)
+                       arr_gain_str = cl_strtok_r(NULL, ",", &arr_gain_tmp);
+
+               arr_gain_val = arr_gain_str ? convert_str_int_q8(arr_gain_str) : 0;
+       }
+
+       kfree(arr_gain_cpy);
+
+       return arr_gain_val;
+}
+
+s8 cl_power_array_gain_q2(struct cl_hw *cl_hw, u8 tx_ant)
+{
+       return (s8)(cl_power_array_gain_q8(cl_hw, tx_ant) >> 6);
+}
+
+s32 cl_power_array_gain_q1(struct cl_hw *cl_hw, u8 tx_ant)
+{
+       return cl_power_array_gain_q8(cl_hw, tx_ant) >> 7;
+}
+
+static s32 cl_power_bf_gain_q8(struct cl_hw *cl_hw, u8 tx_ant, u8 nss)
+{
+       /*
+        * Format in NVRAM of ce_bf_gain=A,B,C,D
+        * A is the bf gain with 1 NSS, B is with 2 NSS and so on...
+        */
+       int bf_gain_val = 0;
+       int bf_gain_len = 0;
+       int idx = 0;
+       s8 *bf_gain_ptr = NULL;
+       s8 *bf_gain_cpy = NULL;
+       s8 *bf_gain_str = NULL;
+       s8 *bf_gain_tmp = NULL;
+
+       if (tx_ant == 6) {
+               bf_gain_ptr = cl_hw->conf->ce_bf_gain_6_ant;
+       } else if (tx_ant == 5) {
+               bf_gain_ptr = cl_hw->conf->ce_bf_gain_5_ant;
+       } else if (tx_ant == 4) {
+               bf_gain_ptr = cl_hw->conf->ce_bf_gain_4_ant;
+       } else if (tx_ant == 3) {
+               bf_gain_ptr = cl_hw->conf->ce_bf_gain_3_ant;
+       } else if (tx_ant == 2) {
+               bf_gain_ptr = cl_hw->conf->ce_bf_gain_2_ant;
+       } else if (tx_ant == 1) {
+               goto out;
+       } else {
+               pr_err("[%s]: invalid tx_ant %u\n", __func__, tx_ant);
+               goto out;
+       }
+
+       bf_gain_len = strlen(bf_gain_ptr) + 1;
+       bf_gain_cpy = kzalloc(bf_gain_len, GFP_ATOMIC);
+
+       if (!bf_gain_cpy)
+               return 0;
+
+       /* Copy cl_hw->conf->ce_bf_gain_*_ant so its value won't be changed by cl_strtok_r() */
+       memcpy(bf_gain_cpy, bf_gain_ptr, bf_gain_len);
+
+       /* Bf_gain_str points to the bf gain of 1 SS */
+       bf_gain_str = cl_strtok_r(bf_gain_cpy, ",", &bf_gain_tmp);
+
+       /* Keep iterating until getting to the correct ss index */
+       for (idx = 0; bf_gain_str && (idx < nss); idx++)
+               bf_gain_str = cl_strtok_r(NULL, ",", &bf_gain_tmp);
+
+       bf_gain_val = bf_gain_str ? convert_str_int_q8(bf_gain_str) : 0;
+
+       kfree(bf_gain_cpy);
+ out:
+       return bf_gain_val;
+}
+
+s32 cl_power_bf_gain_q1(struct cl_hw *cl_hw, u8 tx_ant, u8 nss)
+{
+       return cl_power_bf_gain_q8(cl_hw, tx_ant, nss) >> 7;
+}
+
+static s32 cl_power_min_ant_q8(struct cl_hw *cl_hw)
+{
+       return convert_str_int_q8(cl_hw->conf->ci_min_ant_pwr);
+}
+
+s32 cl_power_min_ant_q1(struct cl_hw *cl_hw)
+{
+       return cl_power_min_ant_q8(cl_hw) >> 7;
+};
+
+s8 cl_power_bw_factor_q2(struct cl_hw *cl_hw, u8 bw)
+{
+       /*
+        * Format in NVRAM of ci_bw_factor=A,B,C,D
+        * A is the bw factor for bw 20MHz, B is for 40MHz and so on..
+        */
+       int bw_factor_val = 0;
+       int bw_factor_len = 0;
+       int idx = 0;
+       s8 *bw_factor_cpy = NULL;
+       s8 *bw_factor_str = NULL;
+       s8 *bw_factor_tmp = NULL;
+
+       bw_factor_len = strlen(cl_hw->conf->ci_bw_factor) + 1;
+       bw_factor_cpy = kzalloc(bw_factor_len, GFP_ATOMIC);
+
+       if (!bw_factor_cpy)
+               return 0;
+
+       /* Copy cl_hw->conf->ci_bw_factor so its value won't be changed by cl_strtok_r() */
+       memcpy(bw_factor_cpy, cl_hw->conf->ci_bw_factor, bw_factor_len);
+
+       /* Bw_factor_str points to the bw factor of 20MHz */
+       bw_factor_str = cl_strtok_r(bw_factor_cpy, ",", &bw_factor_tmp);
+
+       /* Only a single value in ci_bw_factor - same value will be applied for all bandwidths */
+       if (!bw_factor_tmp) {
+               bw_factor_val = convert_str_int_q8(bw_factor_cpy);
+       } else {
+               /* Keep iterating until getting to the correct bw index */
+               for (idx = 0; bw_factor_str && (idx < bw); idx++)
+                       bw_factor_str = cl_strtok_r(NULL, ",", &bw_factor_tmp);
+
+               bw_factor_val = bw_factor_str ? convert_str_int_q8(bw_factor_str) : 0;
+       }
+
+       kfree(bw_factor_cpy);
+
+       return (s8)(bw_factor_val >> 6);
+}
+
+static s32 cl_power_average_calib_q8(struct cl_hw *cl_hw, u8 ant_num)
+{
+       u8 ant = 0;
+       u8 chan_idx = cl_channel_to_index(cl_hw, cl_hw->channel);
+       s32 total_calib_pow = 0;
+
+       if (chan_idx == INVALID_CHAN_IDX)
+               return 0;
+
+       for (ant = 0; ant < ant_num; ant++)
+               total_calib_pow += cl_hw->tx_pow_info[chan_idx][ant].power;
+
+       return ((total_calib_pow << 8) / ant_num);
+}
+
+s32 cl_power_average_calib_q1(struct cl_hw *cl_hw, u8 ant_num)
+{
+       return cl_power_average_calib_q8(cl_hw, ant_num) >> 7;
+}
+
+static s32 cl_power_total_q8(struct cl_hw *cl_hw, s8 pwr_offset_q1, u8 tx_ant, u8 nss,
+                            enum cl_wrs_mode mode, bool is_auto_resp)
+{
+       s32 bf_gain_q8 =  0;
+       s32 antenna_gain_q8 = cl_power_antenna_gain_q8(cl_hw);
+       s32 array_gain_q8 = cl_power_array_gain_q8(cl_hw, tx_ant);
+       s32 pwr_offset_q8 = (s32)pwr_offset_q1 << 7;
+       s32 calib_power_q8 = cl_power_average_calib_q8(cl_hw, tx_ant);
+       s32 total_power_q8 = 0;
+
+       if (!is_auto_resp)
+               bf_gain_q8 = (mode > WRS_MODE_OFDM) ? cl_power_bf_gain_q8(cl_hw, tx_ant, nss) : 0;
+
+       total_power_q8 = calib_power_q8 + bf_gain_q8 + array_gain_q8 +
+               antenna_gain_q8 + pwr_offset_q8;
+
+       /* FCC calculation */
+       if (cl_hw->channel_info.standard == CL_STANDARD_FCC)
+               total_power_q8 -= min(bf_gain_q8 + antenna_gain_q8, 6 << 8);
+
+       return total_power_q8;
+}
+
+s32 cl_power_total_q1(struct cl_hw *cl_hw, s8 pwr_offset_q1, u8 tx_ant, u8 nss,
+                     enum cl_wrs_mode mode, bool is_auto_resp)
+{
+       return cl_power_total_q8(cl_hw, pwr_offset_q1, tx_ant, nss, mode, is_auto_resp) >> 7;
+}
+
+static s32 cl_power_eirp_delta_q1(struct cl_hw *cl_hw, u8 bw, s8 pwr_offset_q1, u8 tx_ant,
+                                 u8 nss, enum cl_wrs_mode mode, bool is_auto_resp)
+{
+       /* Calculate total TX power */
+       s32 total_power_q8 = cl_power_total_q8(cl_hw, pwr_offset_q1, tx_ant, nss,
+                                              mode, is_auto_resp);
+
+       /* EIRP power limit */
+       s32 eirp_power_limit_q8 = cl_chan_info_get_eirp_limit_q8(cl_hw, bw);
+
+       /* Delta between total TX power and EIRP limit */
+       return (total_power_q8 - eirp_power_limit_q8) >> 7;
+}
+
+static s8 cl_power_calc_q1(struct cl_hw *cl_hw, s8 mcs_offset_q1, u8 bw, u8 nss,
+                          enum cl_wrs_mode mode, bool is_auto_resp, u8 *trunc_pwr_q1)
+{
+       /* Result is in 0.5dBm resolution */
+       u8 tx_ant = cl_power_tx_ant(cl_hw, mode);
+       s32 calib_power_q1 = cl_power_average_calib_q1(cl_hw, tx_ant);
+       s32 res_q1 = calib_power_q1 + mcs_offset_q1;
+       s32 min_pwr_q1 = POWER_MIN_DB_Q1;
+
+       if (cl_hw->channel_info.use_channel_info && cl_hw->conf->ci_eirp_regulatory_en) {
+               s32 delta_power_q1 = cl_power_eirp_delta_q1(cl_hw, bw, mcs_offset_q1,
+                                                           tx_ant, nss, mode, is_auto_resp);
+
+               if (delta_power_q1 > 0) {
+                       /*
+                        * If tx power is greater than the limitation
+                        * subtract delta power from the result
+                        */
+                       res_q1 -= delta_power_q1;
+                       *trunc_pwr_q1 = delta_power_q1;
+               } else {
+                       *trunc_pwr_q1 = 0;
+               }
+       } else {
+               *trunc_pwr_q1 = 0;
+       }
+
+       if (is_auto_resp)
+               min_pwr_q1 += cl_power_min_ant_q1(cl_hw);
+
+       if (res_q1 < min_pwr_q1) {
+               *trunc_pwr_q1 = max((s32)(*trunc_pwr_q1) - min_pwr_q1 - res_q1, 0);
+               res_q1 = min_pwr_q1;
+       }
+
+       if (is_auto_resp)
+               res_q1 += cl_power_array_gain_q1(cl_hw, tx_ant);
+
+       return (s8)res_q1;
+}
+
+static s8 cl_power_offset_he(struct cl_hw *cl_hw, u8 bw, u8 mcs)
+{
+       u8 channel = cl_hw->channel;
+       s8 *ppmcs = NULL;
+
+       switch (cl_hw->conf->ci_band_num) {
+       case BAND_5G:
+               if (channel >= 36 && channel <= 64)
+                       ppmcs = cl_hw->conf->ce_ppmcs_offset_he_36_64;
+               else if (channel >= 100 && channel <= 140)
+                       ppmcs = cl_hw->conf->ce_ppmcs_offset_he_100_140;
+               else
+                       ppmcs = cl_hw->conf->ce_ppmcs_offset_he_149_165;
+               break;
+       case BAND_24G:
+               ppmcs = cl_hw->conf->ce_ppmcs_offset_he;
+               break;
+       case BAND_6G:
+               ppmcs = cl_hw->conf->ce_ppmcs_offset_he_6g;
+               break;
+       default:
+               return 0;
+       }
+
+       return ppmcs[mcs] + cl_hw->conf->ce_ppbw_offset[bw];
+}
+
+static s8 cl_power_offset_ht_vht(struct cl_hw *cl_hw, u8 bw, u8 mcs)
+{
+       u8 channel = cl_hw->channel;
+       s8 *ppmcs = NULL;
+
+       switch (cl_hw->conf->ci_band_num) {
+       case BAND_5G:
+               if (channel >= 36 && channel <= 64)
+                       ppmcs = cl_hw->conf->ce_ppmcs_offset_ht_vht_36_64;
+               else if (channel >= 100 && channel <= 140)
+                       ppmcs = cl_hw->conf->ce_ppmcs_offset_ht_vht_100_140;
+               else
+                       ppmcs = cl_hw->conf->ce_ppmcs_offset_ht_vht_149_165;
+               break;
+       case BAND_24G:
+               ppmcs = cl_hw->conf->ce_ppmcs_offset_ht;
+               break;
+       case BAND_6G:
+       default:
+               return 0;
+       }
+
+       return ppmcs[mcs] + cl_hw->conf->ce_ppbw_offset[bw];
+}
+
+static s8 cl_power_offset_ofdm(struct cl_hw *cl_hw, u8 mcs)
+{
+       u8 channel = cl_hw->channel;
+       s8 *ppmcs = NULL;
+
+       switch (cl_hw->conf->ci_band_num) {
+       case BAND_5G:
+               if (channel >= 36 && channel <= 64)
+                       ppmcs = cl_hw->conf->ce_ppmcs_offset_ofdm_36_64;
+               else if (channel >= 100 && channel <= 140)
+                       ppmcs = cl_hw->conf->ce_ppmcs_offset_ofdm_100_140;
+               else
+                       ppmcs = cl_hw->conf->ce_ppmcs_offset_ofdm_149_165;
+               break;
+       case BAND_24G:
+               ppmcs = cl_hw->conf->ce_ppmcs_offset_ofdm;
+               break;
+       case BAND_6G:
+       default:
+               return 0;
+       }
+
+       return ppmcs[mcs] + cl_hw->conf->ce_ppbw_offset[CHNL_BW_20];
+}
+
+static s8 cl_power_offset_cck(struct cl_hw *cl_hw, u8 mcs)
+{
+       s8 *ppmcs = cl_hw->conf->ce_ppmcs_offset_cck;
+
+       if (cl_band_is_24g(cl_hw))
+               return ppmcs[mcs] + cl_hw->conf->ce_ppbw_offset[CHNL_BW_20];
+
+       return 0;
+}
+
+s8 cl_power_offset_q1(struct cl_hw *cl_hw, u8 mode, u8 bw, u8 mcs)
+{
+       if (mode == WRS_MODE_HE)
+               return cl_power_offset_he(cl_hw, bw, mcs);
+       else if (mode == WRS_MODE_HT || mode == WRS_MODE_VHT)
+               return cl_power_offset_ht_vht(cl_hw, bw, mcs);
+       else if (mode == WRS_MODE_OFDM)
+               return cl_power_offset_ofdm(cl_hw, mcs);
+       else if (mode == WRS_MODE_CCK)
+               return cl_power_offset_cck(cl_hw, mcs);
+
+       return 0;
+}
+
+#define UPPER_POWER_MARGIN_Q2 (38 << 2)
+#define LOWER_POWER_MARGIN_Q2 (50 << 2)
+
+s8 cl_power_offset_check_margin(struct cl_hw *cl_hw, u8 bw, u8 ant_idx, s8 offset_q2)
+{
+       s8 new_offset_q2 = 0;
+       s8 bw_factor_q2 = cl_hw->power_db.bw_factor_q2[bw];
+       s8 ant_factor_q2 = cl_hw->power_db.ant_factor_q2[ant_idx];
+       s8 total_offset_upper_q2 = bw_factor_q2 + offset_q2;
+       s8 total_offset_lower_q2 = bw_factor_q2 + ant_factor_q2 + offset_q2;
+       bool upper_limit_valid = (total_offset_upper_q2 <= UPPER_POWER_MARGIN_Q2);
+       bool lower_limit_valid = (total_offset_lower_q2 <= LOWER_POWER_MARGIN_Q2);
+
+       if (upper_limit_valid && lower_limit_valid) {
+               return offset_q2;
+       } else if (!upper_limit_valid && lower_limit_valid) {
+               new_offset_q2 = UPPER_POWER_MARGIN_Q2 - bw_factor_q2;
+
+               return new_offset_q2;
+       } else if (upper_limit_valid && !lower_limit_valid) {
+               new_offset_q2 = LOWER_POWER_MARGIN_Q2 - bw_factor_q2 - ant_factor_q2;
+
+               return new_offset_q2;
+       }
+
+       new_offset_q2 = min(UPPER_POWER_MARGIN_Q2 - bw_factor_q2,
+                           LOWER_POWER_MARGIN_Q2 - bw_factor_q2 - ant_factor_q2);
+
+       return new_offset_q2;
+}
+
+static void cl_power_tables_update_cck(struct cl_hw *cl_hw,
+                                      struct cl_pwr_tables *pwr_tables)
+{
+       u8 mcs;
+       u8 trunc_value = 0;
+       s8 pwr_offset_q1;
+
+       /* CCK - Enforce EIRP limitations */
+       for (mcs = 0; mcs < WRS_MCS_MAX_CCK; mcs++) {
+               pwr_offset_q1 = cl_power_offset_q1(cl_hw, WRS_MODE_CCK, CHNL_BW_20, mcs);
+
+               pwr_tables->ant_pwr_cck[mcs] =
+                       cl_power_calc_q1(cl_hw, pwr_offset_q1, 0, 0,
+                                        WRS_MODE_CCK, false, &trunc_value);
+
+               cl_hw->pwr_trunc.cck[mcs] = trunc_value;
+
+               /* Auto response */
+               pwr_tables->pwr_auto_resp_cck[mcs] =
+                       cl_power_calc_q1(cl_hw, pwr_offset_q1, 0, 0,
+                                        WRS_MODE_CCK, true, &trunc_value);
+       }
+}
+
+static void cl_power_tables_update_ofdm(struct cl_hw *cl_hw,
+                                       struct cl_pwr_tables *pwr_tables)
+{
+       u8 mcs;
+       u8 trunc_value = 0;
+       s8 pwr_offset_q1;
+
+       /* OFDM - Enforce EIRP limitations */
+       for (mcs = 0; mcs < WRS_MCS_MAX_OFDM; mcs++) {
+               pwr_offset_q1 = cl_power_offset_q1(cl_hw, WRS_MODE_OFDM, CHNL_BW_20, mcs);
+
+               pwr_tables->ant_pwr_ofdm[mcs] =
+                       cl_power_calc_q1(cl_hw, pwr_offset_q1, 0, 0,
+                                        WRS_MODE_OFDM, false, &trunc_value);
+
+               cl_hw->pwr_trunc.ofdm[mcs] = trunc_value;
+
+               /* Auto response */
+               pwr_tables->pwr_auto_resp_ofdm[mcs] =
+                       cl_power_calc_q1(cl_hw, pwr_offset_q1, 0, 0,
+                                        WRS_MODE_OFDM, true, &trunc_value);
+       }
+}
+
+static u8 cl_power_tables_update_ht_vht(struct cl_hw *cl_hw,
+                                       struct cl_pwr_tables *pwr_tables)
+{
+       bool is_24g = cl_band_is_24g(cl_hw);
+       bool is_5g = cl_band_is_5g(cl_hw);
+       u8 bw;
+       u8 nss;
+       u8 mcs;
+       u8 trunc_value = 0;
+       u8 min_bw_idx_limit_vht = 0;
+       u8 max_mcs_ht_vht = (is_5g || (is_24g && cl_hw->conf->ci_vht_cap_24g)) ?
+               WRS_MCS_MAX_VHT : WRS_MCS_MAX_HT;
+       s8 pwr_offset_q1;
+       s16 min_bw_limit = 0;
+       s32 eirp_power_limit_q8;
+
+       for (bw = 0, min_bw_limit = 0xFFFF; bw < max_bw_idx(WRS_MODE_VHT, is_24g); bw++) {
+               if (!cl_hw->chip->conf->ce_production_mode &&
+                   !cl_chan_info_get(cl_hw, cl_hw->channel, bw))
+                       continue;
+
+               /* Find lowest EIRP power limitation among all bw for auto resp calculations */
+               eirp_power_limit_q8 = cl_chan_info_get_eirp_limit_q8(cl_hw, bw);
+               if (eirp_power_limit_q8 < min_bw_limit) {
+                       min_bw_limit = eirp_power_limit_q8;
+                       min_bw_idx_limit_vht = bw;
+               }
+
+               /* HT/VHT - Enforce EIRP limitations */
+               for (mcs = 0; mcs < max_mcs_ht_vht; mcs++) {
+                       pwr_offset_q1 = cl_power_offset_q1(cl_hw, WRS_MODE_VHT, bw, mcs);
+
+                       for (nss = 0; nss < PWR_TBL_VHT_BF_SIZE; nss++) {
+                               pwr_tables->ant_pwr_ht_vht[bw][mcs][nss] =
+                                       cl_power_calc_q1(cl_hw, pwr_offset_q1,
+                                                        bw, nss, WRS_MODE_VHT, false,
+                                                        &trunc_value);
+                               cl_hw->pwr_trunc.ht_vht[bw][mcs][nss] = trunc_value;
+                       }
+               }
+       }
+
+       /* Auto resp HT/VHT - Enforce EIRP limitations */
+       for (mcs = 0; mcs < max_mcs_ht_vht; mcs++) {
+               pwr_offset_q1 = cl_power_offset_q1(cl_hw, WRS_MODE_VHT, CHNL_BW_20, mcs);
+
+               pwr_tables->pwr_auto_resp_ht_vht[mcs] =
+                       cl_power_calc_q1(cl_hw, pwr_offset_q1,
+                                        min_bw_idx_limit_vht, 0, WRS_MODE_VHT,
+                                        true, &trunc_value);
+       }
+
+       return min_bw_idx_limit_vht;
+}
+
+static u8 cl_power_tables_update_he(struct cl_hw *cl_hw,
+                                   struct cl_pwr_tables *pwr_tables)
+{
+       bool is_24g = cl_band_is_24g(cl_hw);
+       u8 bw;
+       u8 nss;
+       u8 mcs;
+       u8 trunc_value = 0;
+       u8 min_bw_idx_limit_he = 0;
+       s8 pwr_offset_q1;
+       s16 min_bw_limit = 0;
+       s32 eirp_power_limit_q8;
+
+       for (bw = 0, min_bw_limit = 0xFFFF; bw < max_bw_idx(WRS_MODE_HE, is_24g); bw++) {
+               if (!cl_hw->chip->conf->ce_production_mode &&
+                   !cl_chan_info_get(cl_hw, cl_hw->channel, bw))
+                       continue;
+
+               /* Find lowest EIRP power limitation among all bw for auto resp calculations */
+               eirp_power_limit_q8 = cl_chan_info_get_eirp_limit_q8(cl_hw, bw);
+               if (eirp_power_limit_q8 < min_bw_limit) {
+                       min_bw_limit = eirp_power_limit_q8;
+                       min_bw_idx_limit_he = bw;
+               }
+
+               /* HE - Enforce EIRP limitations */
+               for (mcs = 0; mcs < WRS_MCS_MAX_HE; mcs++) {
+                       pwr_offset_q1 = cl_power_offset_q1(cl_hw, WRS_MODE_HE, bw, mcs);
+
+                       for (nss = 0; nss < PWR_TBL_HE_BF_SIZE; nss++) {
+                               pwr_tables->ant_pwr_he[bw][mcs][nss] =
+                                       cl_power_calc_q1(cl_hw, pwr_offset_q1,
+                                                        bw, nss, WRS_MODE_HE, false,
+                                                        &trunc_value);
+                               cl_hw->pwr_trunc.he[bw][mcs][nss] = trunc_value;
+                       }
+               }
+       }
+
+       /* Auto resp HE - Enforce EIRP limitations */
+       for (mcs = 0; mcs < WRS_MCS_MAX_HE; mcs++) {
+               pwr_offset_q1 = cl_power_offset_q1(cl_hw, WRS_MODE_HE, CHNL_BW_20, mcs);
+
+               pwr_tables->pwr_auto_resp_he[mcs] =
+                       cl_power_calc_q1(cl_hw, pwr_offset_q1, min_bw_idx_limit_he,
+                                        nss, WRS_MODE_HE, true, &trunc_value);
+       }
+
+       return min_bw_idx_limit_he;
+}
+
+static u8 cl_power_calc_max(struct cl_hw *cl_hw, u8 bw, enum cl_wrs_mode mode)
+{
+       u8 tx_ant = cl_power_tx_ant(cl_hw, mode);
+       /* Total TX power - pass is_auto_resp = true in order to ignore bf gain */
+       s32 total_power_q8 = cl_power_total_q8(cl_hw, 0, tx_ant, 0, mode, true);
+       /* EIRP power limit */
+       s32 eirp_power_limit_q8 = cl_chan_info_get_eirp_limit_q8(cl_hw, bw);
+
+       return (min(total_power_q8, eirp_power_limit_q8) >> 8);
+}
+
+static s8 cl_power_vns_calc_q1(struct cl_hw *cl_hw, u8 bw,
+                              enum cl_wrs_mode mode, bool is_auto_resp)
+{
+       u8 max_tx_pwr = cl_power_calc_max(cl_hw, bw, mode);
+       u8 tx_ant = cl_power_tx_ant(cl_hw, mode);
+       s32 vns_pwr_limit_q8 = min_t(u8, cl_hw->conf->ci_vns_pwr_limit, max_tx_pwr) << 8;
+       s32 antenna_gain_q8 = cl_power_antenna_gain_q8(cl_hw);
+       s32 array_gain_q8 = (is_auto_resp ? 0 : cl_power_array_gain_q8(cl_hw, tx_ant));
+       s32 min_ant_pwr_q8 = cl_power_min_ant_q8(cl_hw);
+       s32 min_pwr_q8 = is_auto_resp ? (POWER_MIN_DB_Q8 + min_ant_pwr_q8) : POWER_MIN_DB_Q8;
+       s32 res_q8 = vns_pwr_limit_q8 - antenna_gain_q8 - array_gain_q8;
+
+       if (res_q8 < min_pwr_q8)
+               res_q8 = min_pwr_q8;
+
+       /* Result should be in 0.5dBm resolution */
+       return (s8)(res_q8 >> 7);
+}
+
+static void cl_power_tables_update_vns(struct cl_hw *cl_hw,
+                                      struct cl_pwr_tables *pwr_tables,
+                                      u8 min_bw_idx_limit_vht,
+                                      u8 min_bw_idx_limit_he)
+{
+       /* VNS */
+       pwr_tables->ant_pwr_vns_he =
+               cl_power_vns_calc_q1(cl_hw, min_bw_idx_limit_he, WRS_MODE_HE, false);
+       pwr_tables->ant_pwr_vns_ht_vht =
+               cl_power_vns_calc_q1(cl_hw, min_bw_idx_limit_vht, WRS_MODE_VHT, false);
+       pwr_tables->ant_pwr_vns_ofdm =
+               cl_power_vns_calc_q1(cl_hw, 0, WRS_MODE_OFDM, false);
+       pwr_tables->ant_pwr_vns_cck =
+               cl_power_vns_calc_q1(cl_hw, 0, WRS_MODE_CCK, false);
+
+       /* Auto response VNS */
+       pwr_tables->pwr_auto_resp_vns_he =
+               cl_power_vns_calc_q1(cl_hw, min_bw_idx_limit_he, WRS_MODE_HE, true);
+       pwr_tables->pwr_auto_resp_vns_ht_vht =
+               cl_power_vns_calc_q1(cl_hw, min_bw_idx_limit_vht, WRS_MODE_VHT, true);
+       pwr_tables->pwr_auto_resp_vns_ofdm =
+               cl_power_vns_calc_q1(cl_hw, 0, WRS_MODE_OFDM, true);
+       pwr_tables->pwr_auto_resp_vns_cck =
+               cl_power_vns_calc_q1(cl_hw, 0, WRS_MODE_CCK, true);
+}
+
+static void cl_power_tables_update_by_offset(struct cl_hw *cl_hw,
+                                            struct cl_pwr_tables *pwr_tables,
+                                            s8 offset)
+{
+       u8 mcs = 0;
+       u8 bw = 0;
+       u8 nss = 0;
+
+       /* CCK - Enforce EIRP limitations */
+       for (mcs = 0; mcs < WRS_MCS_MAX_CCK; mcs++) {
+               pwr_tables->ant_pwr_cck[mcs] += offset;
+
+               /* Auto response */
+               pwr_tables->pwr_auto_resp_cck[mcs] += offset;
+       }
+
+       /* OFDM - Enforce EIRP limitations */
+       for (mcs = 0; mcs < WRS_MCS_MAX_OFDM; mcs++) {
+               pwr_tables->ant_pwr_ofdm[mcs] += offset;
+
+               /* Auto response */
+               pwr_tables->pwr_auto_resp_ofdm[mcs] += offset;
+       }
+
+       for (bw = 0; bw < CHNL_BW_MAX; bw++) {
+               /* HT/VHT - Enforce EIRP limitations */
+               for (mcs = 0; mcs < WRS_MCS_MAX_VHT; mcs++) {
+                       for (nss = 0; nss < PWR_TBL_VHT_BF_SIZE; nss++)
+                               pwr_tables->ant_pwr_ht_vht[bw][mcs][nss] += offset;
+
+                       /*
+                        * Auto response:
+                        * always with disabled BF so the offset of the last nss is used
+                        */
+                       pwr_tables->pwr_auto_resp_ht_vht[mcs] += offset;
+               }
+
+               /* HE - Enforce EIRP limitations */
+               for (mcs = 0; mcs < WRS_MCS_MAX_HE; mcs++) {
+                       for (nss = 0; nss < PWR_TBL_HE_BF_SIZE; nss++)
+                               pwr_tables->ant_pwr_he[bw][mcs][nss] += offset;
+
+                       /*
+                        * Auto response:
+                        * always with disabled BF so the offset of the last nss is used
+                        */
+                       pwr_tables->pwr_auto_resp_he[mcs] += offset;
+               }
+       }
+}
+
+static s8 cl_power_get_offset(u16 percentage)
+{
+       if (percentage >= 94)
+               return 0;
+       else if (percentage >= 84)
+               return -1; /* -0.5dBm */
+       else if (percentage >= 75)
+               return -2; /* -1dBm */
+       else if (percentage >= 67)
+               return -3; /* -1.5dBm */
+       else if (percentage >= 59)
+               return -4; /* -2dBm */
+       else if (percentage >= 54)
+               return -5; /* -2.5dBm */
+       else if (percentage >= 48)
+               return -6; /* -3dBm */
+       else if (percentage >= 43)
+               return -7; /* -3.5dBm */
+       else if (percentage >= 38)
+               return -8; /* -4dBm */
+       else if (percentage >= 34)
+               return -9; /* -4.5dBm */
+       else if (percentage >= 30)
+               return -10; /* -5dBm */
+       else if (percentage >= 27)
+               return -11; /* -5.5dBm */
+       else if (percentage >= 24)
+               return -12; /* -6dBm */
+       else if (percentage >= 22)
+               return -13; /* -6.5dBm */
+       else if (percentage >= 19)
+               return -14; /* -7dBm */
+       else if (percentage >= 17)
+               return -15; /* -7.5dBm */
+       else if (percentage >= 15)
+               return -16; /* -8dBm */
+       else if (percentage >= 14)
+               return -17; /* -8.5dBm */
+       else if (percentage >= 12)
+               return -18; /* -9dBm */
+       else if (percentage >= 11)
+               return -19; /* -9.5dBm */
+       else if (percentage >= 10)
+               return -20; /* -10dBm */
+       else if (percentage >= 9)
+               return -21; /* -10.5dBm */
+       else if (percentage >= 8)
+               return -22; /* -11dBm */
+       else if (percentage >= 7)
+               return -23; /* -11.5dBm */
+       else if (percentage >= 6)
+               return -24; /* -12dBm */
+       else if (percentage >= 5)
+               return -26; /* -13dBm */
+       else if (percentage >= 4)
+               return -28; /* -14dBm */
+       else if (percentage >= 3)
+               return -30; /* -15dBm */
+       else if (percentage >= 2)
+               return -34; /* -17dBm */
+       else if (percentage >= 1)
+               return -40; /* -20dBm */
+
+       /* Should not get here */
+       return 0;
+}
+
+static void cl_power_control_apply_percentage(struct cl_hw *cl_hw)
+{
+       struct cl_power_db *power_db = &cl_hw->power_db;
+       u8 percentage = cl_hw->conf->ce_tx_power_control;
+
+       power_db->curr_percentage = percentage;
+
+       if (percentage != 100) {
+               power_db->curr_offset = cl_power_get_offset(percentage);
+               cl_power_tables_update_by_offset(cl_hw,
+                                                &cl_hw->phy_data_info.data->pwr_tables,
+                                                power_db->curr_offset);
+       }
+}
+
+void cl_power_tables_update(struct cl_hw *cl_hw, struct cl_pwr_tables *pwr_tables)
+{
+       bool is_24g = cl_band_is_24g(cl_hw);
+       bool is_6g = cl_band_is_6g(cl_hw);
+       u8 min_bw_idx_limit_he = 0;
+       u8 min_bw_idx_limit_vht = 0;
+
+       /*
+        * If tx_power is set then we are in calibration process and
+        * need to set all values in power tables to this value x2.
+        */
+       if (cl_hw->ate_db.active &&
+           cl_hw->ate_db.tx_power >= POWER_MIN_DB &&
+           cl_hw->ate_db.tx_power <= POWER_MAX_DB) {
+               s8 tx_power_q1 = cl_hw->ate_db.tx_power << 1;
+
+               memset(pwr_tables, tx_power_q1, sizeof(struct cl_pwr_tables));
+               return;
+       }
+
+       memset(pwr_tables, 0, sizeof(struct cl_pwr_tables));
+
+       if (is_24g)
+               cl_power_tables_update_cck(cl_hw, pwr_tables);
+
+       if (!is_6g) {
+               cl_power_tables_update_ofdm(cl_hw, pwr_tables);
+               min_bw_idx_limit_vht = cl_power_tables_update_ht_vht(cl_hw, pwr_tables);
+       }
+
+       min_bw_idx_limit_he = cl_power_tables_update_he(cl_hw, pwr_tables);
+
+       cl_power_tables_update_vns(cl_hw, pwr_tables, min_bw_idx_limit_vht, min_bw_idx_limit_he);
+
+       cl_power_control_apply_percentage(cl_hw);
+}
+
+static s32 cl_power_get_max_cck(struct cl_hw *cl_hw)
+{
+       struct cl_pwr_tables *pwr_tables = &cl_hw->phy_data_info.data->pwr_tables;
+       u8 mcs = 0;
+       u8 tx_ant = cl_power_tx_ant(cl_hw, WRS_MODE_CCK);
+       s32 ant_gain_q1 = cl_power_antenna_gain_q1(cl_hw);
+       s32 arr_gain_q1 = cl_power_array_gain_q1(cl_hw, tx_ant);
+       s32 total_pwr_q1 = 0;
+       s32 max_pwr_q1 = 0;
+
+       for (mcs = 0; mcs < WRS_MCS_MAX_CCK; mcs++) {
+               total_pwr_q1 = pwr_tables->ant_pwr_cck[mcs] + ant_gain_q1 + arr_gain_q1;
+
+               if (total_pwr_q1 > max_pwr_q1)
+                       max_pwr_q1 = total_pwr_q1;
+       }
+
+       return max_pwr_q1;
+}
+
+static s32 cl_power_get_max_ofdm(struct cl_hw *cl_hw)
+{
+       struct cl_pwr_tables *pwr_tables = &cl_hw->phy_data_info.data->pwr_tables;
+       u8 mcs = 0;
+       u8 tx_ant = cl_power_tx_ant(cl_hw, WRS_MODE_OFDM);
+       s32 ant_gain_q1 = cl_power_antenna_gain_q1(cl_hw);
+       s32 arr_gain_q1 = cl_power_array_gain_q1(cl_hw, tx_ant);
+       s32 total_pwr_q1 = 0;
+       s32 max_pwr_q1 = 0;
+
+       for (mcs = 0; mcs < WRS_MCS_MAX_OFDM; mcs++) {
+               total_pwr_q1 = pwr_tables->ant_pwr_ofdm[mcs] + ant_gain_q1 + arr_gain_q1;
+
+               if (total_pwr_q1 > max_pwr_q1)
+                       max_pwr_q1 = total_pwr_q1;
+       }
+
+       return max_pwr_q1;
+}
+
+static s32 cl_power_get_max_ht_vht(struct cl_hw *cl_hw)
+{
+       struct cl_pwr_tables *pwr_tables = &cl_hw->phy_data_info.data->pwr_tables;
+       u8 tx_ant = cl_power_tx_ant(cl_hw, WRS_MODE_VHT);
+       u8 mcs = 0;
+       u8 bw = 0;
+       u8 bf = 0;
+       s32 ant_gain_q1 = cl_power_antenna_gain_q1(cl_hw);
+       s32 arr_gain_q1 = cl_power_array_gain_q1(cl_hw, tx_ant);
+       s32 total_pwr_q1 = 0;
+       s32 max_pwr_q1 = 0;
+
+       for (bw = 0; bw < CHNL_BW_MAX; bw++) {
+               for (mcs = 0; mcs < WRS_MCS_MAX_VHT; mcs++) {
+                       for (bf = 0; bf < PWR_TBL_VHT_BF_SIZE; bf++) {
+                               total_pwr_q1 = pwr_tables->ant_pwr_ht_vht[bw][mcs][bf] +
+                                       ant_gain_q1 + arr_gain_q1;
+
+                               if (total_pwr_q1 > max_pwr_q1)
+                                       max_pwr_q1 = total_pwr_q1;
+                       }
+               }
+       }
+
+       return max_pwr_q1;
+}
+
+static s32 cl_power_get_max_he(struct cl_hw *cl_hw)
+{
+       struct cl_pwr_tables *pwr_tables = &cl_hw->phy_data_info.data->pwr_tables;
+       u8 tx_ant = cl_power_tx_ant(cl_hw, WRS_MODE_HE);
+       u8 mcs = 0;
+       u8 bw = 0;
+       u8 bf = 0;
+       s32 ant_gain_q1 = cl_power_antenna_gain_q1(cl_hw);
+       s32 arr_gain_q1 = cl_power_array_gain_q1(cl_hw, tx_ant);
+       s32 total_pwr_q1 = 0;
+       s32 max_pwr_q1 = 0;
+
+       for (bw = 0; bw < CHNL_BW_MAX; bw++) {
+               for (mcs = 0; mcs < WRS_MCS_MAX_HE; mcs++) {
+                       for (bf = 0; bf < PWR_TBL_HE_BF_SIZE; bf++) {
+                               total_pwr_q1 = pwr_tables->ant_pwr_he[bw][mcs][bf] +
+                                       ant_gain_q1 + arr_gain_q1;
+
+                               if (total_pwr_q1 > max_pwr_q1)
+                                       max_pwr_q1 = total_pwr_q1;
+                       }
+               }
+       }
+
+       return max_pwr_q1;
+}
+
+s32 cl_power_get_max(struct cl_hw *cl_hw)
+{
+       bool is_24g = cl_band_is_24g(cl_hw);
+       bool is_6g = cl_band_is_6g(cl_hw);
+       s32 max_pwr_cck_q1 = is_24g ? cl_power_get_max_cck(cl_hw) : S32_MIN;
+       s32 max_pwr_ofdm_q1 = !is_6g ? cl_power_get_max_ofdm(cl_hw) : S32_MIN;
+       s32 max_pwr_ht_vht_q1 = !is_6g ? cl_power_get_max_ht_vht(cl_hw) : S32_MIN;
+       s32 max_pwr_he_q1 = cl_power_get_max_he(cl_hw);
+       s32 max_pwr_q1 = 0;
+
+       max_pwr_q1 = max(max_pwr_q1, max_pwr_cck_q1);
+       max_pwr_q1 = max(max_pwr_q1, max_pwr_ofdm_q1);
+       max_pwr_q1 = max(max_pwr_q1, max_pwr_ht_vht_q1);
+       max_pwr_q1 = max(max_pwr_q1, max_pwr_he_q1);
+
+       return (max_pwr_q1 >> 1);
+}
+
--
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.
________________________________


^ permalink raw reply related	[flat|nested] 262+ messages in thread

* [RFC v1 134/256] cl8k: add power.h
  2021-06-17 15:58 [RFC v1 000/256] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (132 preceding siblings ...)
  2021-06-17 16:00 ` [RFC v1 133/256] cl8k: add power.c viktor.barna
@ 2021-06-17 16:00 ` viktor.barna
  2021-06-17 16:00 ` [RFC v1 135/256] cl8k: add power_cli.c viktor.barna
                   ` (123 subsequent siblings)
  257 siblings, 0 replies; 262+ messages in thread
From: viktor.barna @ 2021-06-17 16:00 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Oleksandr Savchenko, Shay Bar, Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

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

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 drivers/net/wireless/celeno/cl8k/power.h | 37 ++++++++++++++++++++++++
 1 file changed, 37 insertions(+)
 create mode 100644 drivers/net/wireless/celeno/cl8k/power.h

diff --git a/drivers/net/wireless/celeno/cl8k/power.h b/drivers/net/wireless/celeno/cl8k/power.h
new file mode 100644
index 000000000000..3dc12d618c7c
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/power.h
@@ -0,0 +1,37 @@
+/* SPDX-License-Identifier: MIT */
+/* Copyright(c) 2019-2021, Celeno Communications Ltd. */
+
+#ifndef CL_POWER_H
+#define CL_POWER_H
+
+#include "hw.h"
+
+#define POWER_MAX_DB 30
+#define POWER_MIN_DB -10
+
+#define POWER_MIN_DB_Q1 (POWER_MIN_DB << 1)
+#define POWER_MIN_DB_Q8 (POWER_MIN_DB << 8)
+
+#define POWER_OFFSET_RES 4
+
+#define POWER_OFFSET_MAX_Q2 (16 << 2)  /* +16dB * 4 */
+#define POWER_OFFSET_MIN_Q2 (-16 << 2) /* -16dB * 4 */
+
+u8 cl_power_tx_ant(struct cl_hw *cl_hw, enum cl_wrs_mode mode);
+s32 cl_power_antenna_gain_q8(struct cl_hw *cl_hw);
+s32 cl_power_antenna_gain_q1(struct cl_hw *cl_hw);
+s32 cl_power_array_gain_q8(struct cl_hw *cl_hw, u8 tx_ant);
+s8 cl_power_array_gain_q2(struct cl_hw *cl_hw, u8 tx_ant);
+s32 cl_power_array_gain_q1(struct cl_hw *cl_hw, u8 tx_ant);
+s32 cl_power_bf_gain_q1(struct cl_hw *cl_hw, u8 tx_ant, u8 nss);
+s32 cl_power_min_ant_q1(struct cl_hw *cl_hw);
+s8 cl_power_bw_factor_q2(struct cl_hw *cl_hw, u8 bw);
+s32 cl_power_average_calib_q1(struct cl_hw *cl_hw, u8 ant_num);
+s32 cl_power_total_q1(struct cl_hw *cl_hw, s8 pwr_offset_q1, u8 tx_ant, u8 nss,
+                     enum cl_wrs_mode mode, bool is_auto_resp);
+s8 cl_power_offset_q1(struct cl_hw *cl_hw, u8 mode, u8 bw, u8 mcs);
+s8 cl_power_offset_check_margin(struct cl_hw *cl_hw, u8 bw, u8 ant_idx, s8 offset_q2);
+void cl_power_tables_update(struct cl_hw *cl_hw, struct cl_pwr_tables *pwr_tables);
+s32 cl_power_get_max(struct cl_hw *cl_hw);
+
+#endif /* CL_POWER_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.
________________________________


^ permalink raw reply related	[flat|nested] 262+ messages in thread

* [RFC v1 135/256] cl8k: add power_cli.c
  2021-06-17 15:58 [RFC v1 000/256] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (133 preceding siblings ...)
  2021-06-17 16:00 ` [RFC v1 134/256] cl8k: add power.h viktor.barna
@ 2021-06-17 16:00 ` viktor.barna
  2021-06-17 16:00 ` [RFC v1 136/256] cl8k: add power_cli.h viktor.barna
                   ` (122 subsequent siblings)
  257 siblings, 0 replies; 262+ messages in thread
From: viktor.barna @ 2021-06-17 16:00 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Oleksandr Savchenko, Shay Bar, Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

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

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 drivers/net/wireless/celeno/cl8k/power_cli.c | 878 +++++++++++++++++++
 1 file changed, 878 insertions(+)
 create mode 100644 drivers/net/wireless/celeno/cl8k/power_cli.c

diff --git a/drivers/net/wireless/celeno/cl8k/power_cli.c b/drivers/net/wireless/celeno/cl8k/power_cli.c
new file mode 100644
index 000000000000..7adcb93cbf9c
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/power_cli.c
@@ -0,0 +1,878 @@
+// SPDX-License-Identifier: MIT
+/* Copyright(c) 2019-2021, Celeno Communications Ltd. */
+
+#include "power_cli.h"
+#include "power.h"
+#include "band.h"
+#include "chip.h"
+#include "utils/utils.h"
+
+static void cl_power_float_to_buf(char **buf, int *len, ssize_t *buf_size,
+                                 s32 x, s32 y, bool zero_pad)
+{
+       bool sign = (x >= 0 && y > 0) || (x < 0 && y < 0);
+       s32 absx = abs(x);
+       s32 absy = abs(y);
+       s32 abs_integer = 0;
+       s32 fraction = 0;
+       s32 signed_integer = 0;
+
+       if (x != 0 && y != 0) {
+               abs_integer = (absx / absy);
+               if (y == 2)
+                       fraction = (10 * (absx - absy * abs_integer) / absy);
+               else
+                       fraction = (100 * (absx - absy * abs_integer) / absy);
+               signed_integer = sign ? abs_integer : -abs_integer;
+       }
+
+       if (y == 2) {
+               if (signed_integer == 0 && !sign)
+                       cl_snprintf(buf, len, buf_size, "-0.%d", fraction);
+               else if (zero_pad)
+                       cl_snprintf(buf, len, buf_size, "%2d.%d", signed_integer, fraction);
+               else
+                       cl_snprintf(buf, len, buf_size, "%d.%d", signed_integer, fraction);
+       } else {
+               if (signed_integer == 0 && !sign)
+                       cl_snprintf(buf, len, buf_size, "-0.%02d", fraction);
+               else if (zero_pad)
+                       cl_snprintf(buf, len, buf_size, "%2d.%02d", signed_integer, fraction);
+               else
+                       cl_snprintf(buf, len, buf_size, "%d.%02d", signed_integer, fraction);
+       }
+}
+
+static void cl_power_q1_to_buf(char **buf, int *len, ssize_t *buf_size, const s8 *prefix, s32 x,
+                              const s8 *suffix, bool zero_pad)
+{
+       cl_snprintf(buf, len, buf_size, "%s", prefix);
+       cl_power_float_to_buf(buf, len, buf_size, x, 2, zero_pad);
+       cl_snprintf(buf, len, buf_size, "%s", suffix);
+}
+
+static void cl_power_q8_to_buf(char **buf, int *len, ssize_t *buf_size, const s8 *prefix, s32 x,
+                              const s8 *suffix, bool zero_pad)
+{
+       cl_snprintf(buf, len, buf_size, "%s", prefix);
+       cl_power_float_to_buf(buf, len, buf_size, x, 256, zero_pad);
+       cl_snprintf(buf, len, buf_size, "%s", suffix);
+}
+
+static void multi_print(char **buf, int *len, ssize_t *buf_size, u8 num_prints, const s8 *str)
+{
+       u8 i;
+
+       for (i = 0; i < num_prints; i++)
+               cl_snprintf(buf, len, buf_size, "%s", str);
+
+       cl_snprintf(buf, len, buf_size, "\n");
+}
+
+static void cl_power_offset_to_buf(struct cl_hw *cl_hw, char **buf,
+                                  int *len, ssize_t *buf_size,
+                                  u8 mode, u8 max_bw, u8 max_mcs)
+{
+       u8 bw, mcs;
+       s8 offset_q1;
+
+       cl_snprintf(buf, len, buf_size, "\nPower Offset per BW & MCS\n");
+
+       cl_snprintf(buf, len, buf_size, "-----");
+       multi_print(buf, len, buf_size, max_mcs, "-----");
+
+       cl_snprintf(buf, len, buf_size, "|   ");
+       for (mcs = 0; mcs < max_mcs; mcs++)
+               cl_snprintf(buf, len, buf_size, "|%4u", mcs);
+
+       cl_snprintf(buf, len, buf_size, "|\n");
+
+       cl_snprintf(buf, len, buf_size, "|---");
+       for (mcs = 0; mcs < max_mcs - 1; mcs++)
+               cl_snprintf(buf, len, buf_size, "+----");
+
+       cl_snprintf(buf, len, buf_size, "+----|\n");
+
+       for (bw = 0; bw < max_bw; bw++) {
+               cl_snprintf(buf, len, buf_size, "|%3u", BW_TO_MHZ(bw));
+
+               for (mcs = 0; mcs < max_mcs; mcs++) {
+                       offset_q1 = cl_power_offset_q1(cl_hw, mode, bw, mcs);
+                       cl_power_q1_to_buf(buf, len, buf_size, "|", offset_q1, "", true);
+               }
+
+               cl_snprintf(buf, len, buf_size, "|\n");
+       }
+
+       cl_snprintf(buf, len, buf_size, "-----");
+       multi_print(buf, len, buf_size, max_mcs, "-----");
+}
+
+static void cl_power_bf_gain_to_buf(char **buf, int *len, ssize_t *buf_size,
+                                   u8 max_nss, s32 *bf_gain_q1)
+{
+       u8 nss;
+
+       cl_snprintf(buf, len, buf_size, "BF gain per NSS = ");
+
+       for (nss = 0; nss < max_nss; nss++) {
+               if (nss == max_nss - 1)
+                       cl_power_q1_to_buf(buf, len, buf_size, "", bf_gain_q1[nss], "\n", false);
+               else
+                       cl_power_q1_to_buf(buf, len, buf_size, "", bf_gain_q1[nss], ",", false);
+       }
+}
+
+static void cl_power_table_ht_vht_he_to_buf(struct cl_hw *cl_hw, char **buf, int *len,
+                                           ssize_t *buf_size, u8 max_bw, u8 max_nss,
+                                           u8 max_mcs, u8 max_nss_arr,
+                                           u8 max_mcs_arr, s8 *ant_pwr_q1,
+                                           s32 *bf_gain_q1, s32 arr_gain_q1,
+                                           s32 ant_gain_q1)
+{
+       u8 bw, nss, mcs, one_d_idx;
+       s32 conducted_q1, final_q1;
+
+       cl_snprintf(buf, len, buf_size, "\nPower Table\n");
+
+       cl_snprintf(buf, len, buf_size, "---------");
+       multi_print(buf, len, buf_size, max_bw, "----------");
+
+       cl_snprintf(buf, len, buf_size, "|MCS|BF |");
+       for (bw = 0; bw < max_bw; bw++)
+               cl_snprintf(buf, len, buf_size, " %3uMHz  |", BW_TO_MHZ(bw));
+
+       cl_snprintf(buf, len, buf_size, "\n");
+
+       cl_snprintf(buf, len, buf_size, "|   |NSS|");
+       multi_print(buf, len, buf_size, max_bw, "Cond|Finl|");
+
+       for (mcs = 0; mcs < max_mcs; mcs++) {
+               cl_snprintf(buf, len, buf_size, "|---+---|");
+               multi_print(buf, len, buf_size, max_bw, "----+----|");
+
+               for (nss = 0; nss < max_nss; nss++) {
+                       cl_snprintf(buf, len, buf_size, "|%3u|%3u|", mcs, nss);
+
+                       for (bw = 0; bw < max_bw; bw++) {
+                               one_d_idx = (bw * max_mcs_arr + mcs) * max_nss_arr + nss;
+                               conducted_q1 = ant_pwr_q1[one_d_idx];
+                               final_q1 = conducted_q1 + ant_gain_q1 +
+                                       arr_gain_q1 + bf_gain_q1[nss];
+
+                               if (cl_hw->channel_info.standard == CL_STANDARD_FCC)
+                                       final_q1 -= min(bf_gain_q1[nss] + ant_gain_q1, 6 << 1);
+
+                               cl_power_q1_to_buf(buf, len, buf_size, "", conducted_q1, "|", true);
+                               cl_power_q1_to_buf(buf, len, buf_size, "", final_q1, "|", true);
+                       }
+
+                       cl_snprintf(buf, len, buf_size, "\n");
+               }
+       }
+
+       cl_snprintf(buf, len, buf_size, "---------");
+       multi_print(buf, len, buf_size, max_bw, "----------");
+
+       cl_snprintf(buf, len, buf_size, "(*) BF disabled = BF NSS #%u", max_nss - 1);
+}
+
+static void cl_power_table_cck_ofdm_to_buf(struct cl_hw *cl_hw, char **buf,
+                                          int *len, ssize_t *buf_size,
+                                          u8 max_mcs, s8 *ant_pwr_q1,
+                                          s32 arr_gain_q1, s32 ant_gain_q1)
+{
+       u8 mcs;
+       s32 conducted_q1, final_q1;
+
+       cl_snprintf(buf, len, buf_size,
+                   "\nPower Table\n"
+                   "|-------------|\n"
+                   "|MCS|Cond|Finl|\n"
+                   "|---+----+----|\n");
+
+       for (mcs = 0; mcs < max_mcs; mcs++) {
+               conducted_q1 = ant_pwr_q1[mcs];
+               final_q1 = conducted_q1 + ant_gain_q1 + arr_gain_q1;
+
+               if (cl_hw->channel_info.standard == CL_STANDARD_FCC)
+                       final_q1 -= min(ant_gain_q1, 6 << 1);
+
+               cl_snprintf(buf, len, buf_size, "|%3u|", mcs);
+               cl_power_q1_to_buf(buf, len, buf_size, "", conducted_q1, "|", true);
+               cl_power_q1_to_buf(buf, len, buf_size, "",  final_q1, "|\n", true);
+       }
+
+       cl_snprintf(buf, len, buf_size, "|-------------|\n");
+}
+
+static void cl_power_trunc_ht_vht_he_to_buf(struct cl_hw *cl_hw, char **buf,
+                                           int *len, ssize_t *buf_size,
+                                           enum cl_wrs_mode mode, u8 max_bw,
+                                           u8 max_nss, u8 max_mcs,
+                                           u8 max_nss_arr, u8 max_mcs_arr,
+                                           u8 *trunc_pwr_q1)
+{
+       u8 bw, nss, mcs, one_d_idx;
+       u8 tx_ant = cl_power_tx_ant(cl_hw, mode);
+       s8 pwr_offset_q1;
+       s32 truncate_q1, total_q1;
+
+       cl_snprintf(buf, len, buf_size, "\nTruncate Table\n");
+
+       cl_snprintf(buf, len, buf_size, "---------");
+       multi_print(buf, len, buf_size, max_bw, "----------");
+
+       cl_snprintf(buf, len, buf_size, "|MCS|BF |");
+       for (bw = 0; bw < max_bw; bw++)
+               cl_snprintf(buf, len, buf_size, " %3uMHz  |", BW_TO_MHZ(bw));
+
+       cl_snprintf(buf, len, buf_size, "\n");
+
+       cl_snprintf(buf, len, buf_size, "|   |NSS|");
+       multi_print(buf, len, buf_size, max_bw, "Totl|Trnc|");
+
+       for (mcs = 0; mcs < max_mcs; mcs++) {
+               cl_snprintf(buf, len, buf_size, "|---+---|");
+               multi_print(buf, len, buf_size, max_bw, "----+----|");
+
+               for (nss = 0; nss < max_nss; nss++) {
+                       cl_snprintf(buf, len, buf_size, "|%3u|%3u|", mcs, nss);
+
+                       for (bw = 0; bw < max_bw; bw++) {
+                               one_d_idx = (bw * max_mcs_arr + mcs) * max_nss_arr + nss;
+                               truncate_q1 = (s32)trunc_pwr_q1[one_d_idx];
+                               pwr_offset_q1 = cl_power_offset_q1(cl_hw, mode, bw, mcs);
+                               total_q1 = cl_power_total_q1(cl_hw, pwr_offset_q1,
+                                                            tx_ant, nss, mode, false);
+
+                               cl_power_q1_to_buf(buf, len, buf_size, "", total_q1, "|", true);
+                               cl_power_q1_to_buf(buf, len, buf_size, "", truncate_q1, "|", true);
+                       }
+
+                       cl_snprintf(buf, len, buf_size, "\n");
+               }
+       }
+
+       cl_snprintf(buf, len, buf_size, "---------");
+       multi_print(buf, len, buf_size, max_bw, "----------");
+}
+
+static void cl_power_trunc_cck_ofdm_to_buf(struct cl_hw *cl_hw, char **buf,
+                                          int *len, ssize_t *buf_size,
+                                          enum cl_wrs_mode mode, u8 max_mcs, u8 *trunc_pwr_q1)
+{
+       u8 mcs;
+       u8 tx_ant = cl_power_tx_ant(cl_hw, mode);
+       s8 pwr_offset_q1;
+       s32 truncate_q1, total_q1;
+
+       cl_snprintf(buf, len, buf_size,
+                   "\nTruncate Table\n"
+                   "|-------------|\n"
+                   "|MCS|Totl|Trnc|\n"
+                   "|---+----+----|\n");
+
+       for (mcs = 0; mcs < max_mcs; mcs++) {
+               truncate_q1 = (s32)trunc_pwr_q1[mcs];
+               pwr_offset_q1 = cl_power_offset_q1(cl_hw, mode, CHNL_BW_20, mcs);
+               total_q1 = cl_power_total_q1(cl_hw, pwr_offset_q1, tx_ant, 0, mode, false);
+
+               cl_snprintf(buf, len, buf_size, "|%3u|", mcs);
+               cl_power_q1_to_buf(buf, len, buf_size, "", total_q1, "|", true);
+               cl_power_q1_to_buf(buf, len, buf_size, "", truncate_q1, "|\n", true);
+       }
+
+       cl_snprintf(buf, len, buf_size, "|-------------|\n");
+}
+
+static void cl_power_config_to_buf(char **buf, int *len,
+                                  ssize_t *buf_size,
+                                  char *mode,
+                                  u8 tx_ant_num,
+                                  s32 arr_gain_q1,
+                                  s32 calib_power_q1,
+                                  s8 ant_pwr_vns,
+                                  s8 pwr_auto_resp_vns,
+                                  s32 vns_actual_q1)
+{
+       cl_snprintf(buf, len, buf_size,
+                   "%s power debug info\n", mode);
+       cl_snprintf(buf, len, buf_size,
+                   "-----------------------\n");
+       cl_snprintf(buf, len, buf_size,
+                   "Tx antenna = %u\n", tx_ant_num);
+       cl_power_q1_to_buf(buf, len, buf_size, "Array gain = ",
+                          arr_gain_q1, "\n", false);
+       cl_power_q1_to_buf(buf, len, buf_size, "Calib power = ",
+                          calib_power_q1, "\n", false);
+       cl_power_q1_to_buf(buf, len, buf_size, "VNS power = ",
+                          ant_pwr_vns, "\n", false);
+       cl_power_q1_to_buf(buf, len, buf_size, "VNS auto resp power = ",
+                          pwr_auto_resp_vns, "\n", false);
+       cl_power_q1_to_buf(buf, len, buf_size, "VNS actual = ",
+                          vns_actual_q1, "\n", false);
+}
+
+static void _cl_power_table_print_he(struct cl_hw *cl_hw, char **buf, int *len, ssize_t *buf_size)
+{
+       struct cl_pwr_tables *pwr_tables = &cl_hw->phy_data_info.data->pwr_tables;
+       u8 tx_ant = cl_power_tx_ant(cl_hw, WRS_MODE_HE);
+       u8 max_bw = max_bw_idx(WRS_MODE_HE, cl_band_is_24g(cl_hw));
+       u8 max_nss = min_t(u8, tx_ant, PWR_TBL_HE_BF_SIZE);
+       u8 nss;
+       s32 ant_gain_q1 = cl_power_antenna_gain_q1(cl_hw);
+       s32 arr_gain_q1 = cl_power_array_gain_q1(cl_hw, tx_ant);
+       s32 calib_power_q1 = cl_power_average_calib_q1(cl_hw, tx_ant);
+       s32 bf_gain_tbl_q1[PWR_TBL_HE_BF_SIZE] = {0};
+       s32 vns_actual_q1 = pwr_tables->ant_pwr_vns_he + ant_gain_q1 + arr_gain_q1;
+
+       for (nss = 0; nss < max_nss; nss++)
+               bf_gain_tbl_q1[nss] = cl_power_bf_gain_q1(cl_hw, tx_ant, nss);
+
+       cl_power_config_to_buf(buf, len, buf_size, "HE", tx_ant, arr_gain_q1,
+                              calib_power_q1, pwr_tables->ant_pwr_vns_he,
+                              pwr_tables->pwr_auto_resp_vns_he, vns_actual_q1);
+
+       cl_power_bf_gain_to_buf(buf, len, buf_size, max_nss, bf_gain_tbl_q1);
+
+       cl_power_offset_to_buf(cl_hw, buf, len, buf_size, WRS_MODE_HE,
+                              CHNL_BW_MAX_HE, WRS_MCS_MAX_HE);
+
+       cl_power_table_ht_vht_he_to_buf(cl_hw, buf, len, buf_size,
+                                       max_bw, max_nss, WRS_MCS_MAX_HE,
+                                       PWR_TBL_HE_BF_SIZE, WRS_MCS_MAX_HE,
+                                       &pwr_tables->ant_pwr_he[0][0][0],
+                                       bf_gain_tbl_q1, arr_gain_q1, ant_gain_q1);
+}
+
+static void _cl_power_table_print_ht_vht(struct cl_hw *cl_hw, char **buf,
+                                        int *len, ssize_t *buf_size)
+{
+       struct cl_pwr_tables *pwr_tables = &cl_hw->phy_data_info.data->pwr_tables;
+       bool is_24g = cl_band_is_24g(cl_hw);
+       bool is_5g = cl_band_is_5g(cl_hw);
+       u8 tx_ant = cl_power_tx_ant(cl_hw, WRS_MODE_VHT);
+       u8 max_bw = max_bw_idx(WRS_MODE_VHT, is_24g);
+       u8 max_nss = min_t(u8, tx_ant, PWR_TBL_VHT_BF_SIZE);
+       u8 max_mcs = (is_5g || (is_24g && cl_hw->conf->ci_vht_cap_24g)) ?
+               WRS_MCS_MAX_VHT : WRS_MCS_MAX_HT;
+       u8 nss;
+       s32 ant_gain_q1 = cl_power_antenna_gain_q1(cl_hw);
+       s32 arr_gain_q1 = cl_power_array_gain_q1(cl_hw, tx_ant);
+       s32 calib_power_q1 = cl_power_average_calib_q1(cl_hw, tx_ant);
+       s32 bf_gain_tbl_q1[PWR_TBL_VHT_BF_SIZE] = {0};
+       s32 vns_actual_q1 = pwr_tables->ant_pwr_vns_ht_vht + ant_gain_q1 + arr_gain_q1;
+
+       for (nss = 0; nss < max_nss; nss++)
+               bf_gain_tbl_q1[nss] = cl_power_bf_gain_q1(cl_hw, tx_ant, nss);
+
+       cl_power_config_to_buf(buf, len, buf_size, "HT/VHT", tx_ant, arr_gain_q1,
+                              calib_power_q1, pwr_tables->ant_pwr_vns_ht_vht,
+                              pwr_tables->pwr_auto_resp_vns_ht_vht, vns_actual_q1);
+
+       cl_power_bf_gain_to_buf(buf, len, buf_size, max_nss, bf_gain_tbl_q1);
+
+       cl_power_offset_to_buf(cl_hw, buf, len, buf_size,
+                              WRS_MODE_VHT, CHNL_BW_MAX_VHT, WRS_MCS_MAX_VHT);
+
+       cl_power_table_ht_vht_he_to_buf(cl_hw, buf, len, buf_size,
+                                       max_bw, max_nss, max_mcs,
+                                       PWR_TBL_VHT_BF_SIZE, WRS_MCS_MAX_VHT,
+                                       &pwr_tables->ant_pwr_ht_vht[0][0][0],
+                                       bf_gain_tbl_q1, arr_gain_q1, ant_gain_q1);
+}
+
+static void _cl_power_table_print_ofdm(struct cl_hw *cl_hw, char **buf,
+                                      int *len, ssize_t *buf_size)
+{
+       struct cl_pwr_tables *pwr_tables = &cl_hw->phy_data_info.data->pwr_tables;
+       u8 tx_ant = cl_power_tx_ant(cl_hw, WRS_MODE_OFDM);
+       s32 ant_gain_q1 = cl_power_antenna_gain_q1(cl_hw);
+       s32 arr_gain_q1 = cl_power_array_gain_q1(cl_hw, tx_ant);
+       s32 calib_power_q1 = cl_power_average_calib_q1(cl_hw, tx_ant);
+       s32 vns_actual_q1 = pwr_tables->ant_pwr_vns_ofdm + ant_gain_q1 + arr_gain_q1;
+
+       cl_power_config_to_buf(buf, len, buf_size, "OFDM", tx_ant, arr_gain_q1,
+                              calib_power_q1, pwr_tables->ant_pwr_vns_ofdm,
+                              pwr_tables->pwr_auto_resp_vns_ofdm, vns_actual_q1);
+
+       cl_power_offset_to_buf(cl_hw, buf, len, buf_size, WRS_MODE_OFDM,
+                              CHNL_BW_MAX_OFDM, WRS_MCS_MAX_OFDM);
+
+       cl_power_table_cck_ofdm_to_buf(cl_hw, buf, len, buf_size, WRS_MCS_MAX_OFDM,
+                                      pwr_tables->ant_pwr_ofdm,
+                                      arr_gain_q1, ant_gain_q1);
+}
+
+static void _cl_power_table_print_cck(struct cl_hw *cl_hw, char **buf,
+                                     int *len, ssize_t *buf_size)
+{
+       struct cl_pwr_tables *pwr_tables = &cl_hw->phy_data_info.data->pwr_tables;
+       u8 tx_ant = cl_power_tx_ant(cl_hw, WRS_MODE_CCK);
+       s32 ant_gain_q1 = cl_power_antenna_gain_q1(cl_hw);
+       s32 arr_gain_q1 = cl_power_array_gain_q1(cl_hw, tx_ant);
+       s32 calib_power_q1 = cl_power_average_calib_q1(cl_hw, tx_ant);
+       s32 vns_actual_q1 = pwr_tables->ant_pwr_vns_cck + ant_gain_q1 + arr_gain_q1;
+
+       cl_power_config_to_buf(buf, len, buf_size, "CCK", tx_ant, arr_gain_q1,
+                              calib_power_q1, pwr_tables->ant_pwr_vns_cck,
+                              pwr_tables->pwr_auto_resp_vns_cck,
+                              vns_actual_q1);
+
+       cl_power_offset_to_buf(cl_hw, buf, len, buf_size, WRS_MODE_CCK,
+                              CHNL_BW_MAX_CCK, WRS_MCS_MAX_CCK);
+
+       cl_power_table_cck_ofdm_to_buf(cl_hw, buf, len, buf_size, WRS_MCS_MAX_CCK,
+                                      pwr_tables->ant_pwr_cck,
+                                      arr_gain_q1, ant_gain_q1);
+}
+
+static void _cl_power_trunc_print_he(struct cl_hw *cl_hw, char **buf,
+                                    int *len, ssize_t *buf_size)
+{
+       u8 tx_ant = cl_power_tx_ant(cl_hw, WRS_MODE_HE);
+       u8 max_bw = max_bw_idx(WRS_MODE_HE, cl_band_is_24g(cl_hw));
+       u8 max_nss = min_t(u8, tx_ant, PWR_TBL_HE_BF_SIZE);
+
+       cl_power_trunc_ht_vht_he_to_buf(cl_hw, buf, len, buf_size, WRS_MODE_HE,
+                                       max_bw, max_nss, WRS_MCS_MAX_HE,
+                                       PWR_TBL_HE_BF_SIZE, WRS_MCS_MAX_HE,
+                                       &cl_hw->pwr_trunc.he[0][0][0]);
+}
+
+static void _cl_power_trunc_print_ht_vht(struct cl_hw *cl_hw, char **buf,
+                                        int *len, ssize_t *buf_size)
+{
+       bool is_24g = cl_band_is_24g(cl_hw);
+       bool is_5g = cl_band_is_5g(cl_hw);
+       enum cl_wrs_mode mode;
+       u8 tx_ant, max_bw, max_nss, max_mcs;
+
+       if (is_5g || (is_24g && cl_hw->conf->ci_vht_cap_24g)) {
+               mode = WRS_MODE_VHT;
+               max_bw = CHNL_BW_MAX_VHT;
+               max_mcs = WRS_MCS_MAX_VHT;
+       } else {
+               mode = WRS_MODE_HT;
+               max_bw = CHNL_BW_MAX_HT;
+               max_mcs = WRS_MCS_MAX_HT;
+       }
+
+       tx_ant = cl_power_tx_ant(cl_hw, mode);
+       max_nss = min_t(u8, tx_ant, PWR_TBL_VHT_BF_SIZE);
+
+       cl_power_trunc_ht_vht_he_to_buf(cl_hw, buf, len, buf_size, mode,
+                                       max_bw, max_nss, max_mcs,
+                                       PWR_TBL_VHT_BF_SIZE, WRS_MCS_MAX_VHT,
+                                       &cl_hw->pwr_trunc.ht_vht[0][0][0]);
+}
+
+static void _cl_power_trunc_print_ofdm(struct cl_hw *cl_hw, char **buf,
+                                      int *len, ssize_t *buf_size)
+{
+       cl_power_trunc_cck_ofdm_to_buf(cl_hw, buf, len, buf_size,
+                                      WRS_MODE_OFDM, WRS_MCS_MAX_OFDM,
+                                      cl_hw->pwr_trunc.ofdm);
+}
+
+static void _cl_power_trunc_print_cck(struct cl_hw *cl_hw, char **buf,
+                                     int *len, ssize_t *buf_size)
+{
+       cl_power_trunc_cck_ofdm_to_buf(cl_hw, buf, len, buf_size,
+                                      WRS_MODE_CCK, WRS_MCS_MAX_CCK,
+                                      cl_hw->pwr_trunc.cck);
+}
+
+static void cl_power_print_limits(struct cl_hw *cl_hw, char **buf,
+                                 int *len, ssize_t *buf_size, u8 channel)
+{
+       bool is_24g = cl_band_is_24g(cl_hw);
+       bool country_limit = cl_hw->channel_info.use_channel_info;
+       bool hardware_limit = strlen(cl_hw->conf->ce_hardware_power_table) > 0;
+       bool eirp_limit = cl_hw->conf->ci_eirp_regulatory_en;
+       u8 bw = 0;
+       s16 country_val_q8 = 0;
+       s16 hardware_val_q8 = 0;
+       s16 eirp_val_q8 = 0;
+
+       cl_snprintf(buf, len, buf_size,
+                   "\nPower regulation/limitations\n"
+                   "============================\n");
+       cl_snprintf(buf, len, buf_size,
+                   "Country regulation  = %s\n", country_limit ?
+                   "On" : "Off");
+       cl_snprintf(buf, len, buf_size,
+                   "Hardware limitation = %s\n", hardware_limit ?
+                   "On" : "Off");
+       cl_snprintf(buf, len, buf_size,
+                   "EIRP enable         = %s\n\n", eirp_limit ?
+                   "True" : "False");
+
+       if (!eirp_limit || (!country_limit && !hardware_limit))
+               return;
+
+       cl_snprintf(buf, len, buf_size,
+                   "|-----------------------------------|\n"
+                   "| BW  | COUNTRY | HARDWARE |  EIRP  |\n"
+                   "|-----------------------------------|\n");
+
+       for (bw = 0; bw < max_bw_idx(WRS_MODE_HE, is_24g); bw++) {
+               country_val_q8 = cl_chan_info_get_country_limit_q8(cl_hw, channel, bw);
+               hardware_val_q8 = cl_chan_info_get_hardware_limit_q8(cl_hw, channel, bw);
+               eirp_val_q8 = cl_chan_info_get_eirp_limit_q8(cl_hw, bw);
+
+               cl_snprintf(buf, len, buf_size, "| %3u |", BW_TO_MHZ(bw));
+
+               if (country_limit)
+                       cl_power_q8_to_buf(buf, len, buf_size, "   ",
+                                          country_val_q8, " |", true);
+               else
+                       cl_snprintf(buf, len, buf_size, "    X    |");
+
+               if (hardware_limit)
+                       cl_power_q8_to_buf(buf, len, buf_size, "    ",
+                                          hardware_val_q8, " |", true);
+               else
+                       cl_snprintf(buf, len, buf_size, "    X     |");
+
+               cl_power_q8_to_buf(buf, len, buf_size, "  ", eirp_val_q8, " |\n", true);
+       }
+       cl_snprintf(buf, len, buf_size,
+                   "|-----------------------------------|\n"
+                   "(*) EIRP = MIN(COUNTRY, HARDWARE)\n\n");
+}
+
+static int cl_power_general_print(struct cl_hw *cl_hw)
+{
+       u8 channel = cl_hw->channel;
+       char *buf = NULL;
+       ssize_t buf_size;
+       int err = 0;
+       int len = 0;
+
+       cl_snprintf(&buf, &len, &buf_size,
+                   "Power general information\n"
+                   "=========================\n");
+       cl_snprintf(&buf, &len, &buf_size,
+                   "Channel               = %u\n", channel);
+       cl_snprintf(&buf, &len, &buf_size,
+                   "Standard              = %s\n",
+                   (cl_hw->channel_info.standard == CL_STANDARD_FCC) ?
+                   "FCC" : "ETSI");
+       cl_snprintf(&buf, &len, &buf_size,
+                   "Country code          = %s\n",
+                   cl_hw->chip->conf->ce_country_code);
+       cl_power_q8_to_buf(&buf, &len, &buf_size, "Antenna gain          = ",
+                          cl_power_antenna_gain_q8(cl_hw), "\n", false);
+       cl_snprintf(&buf, &len, &buf_size,
+                   "Power control percent = %u%%\n",
+                   cl_hw->power_db.curr_percentage);
+       cl_snprintf(&buf, &len, &buf_size,
+                   "Power control offset  = %d\n",
+                   cl_hw->power_db.curr_offset);
+       cl_snprintf(&buf, &len, &buf_size,
+                   "VNS mode              = %u\n",
+                   cl_hw->conf->ci_vns_pwr_mode);
+
+       if (cl_hw->conf->ci_vns_pwr_mode)
+               cl_snprintf(&buf, &len, &buf_size,
+                           "VNS limit             = %d\n",
+                           cl_hw->conf->ci_vns_pwr_limit);
+
+       cl_power_print_limits(cl_hw, &buf, &len, &buf_size, channel);
+
+       cl_snprintf(&buf, &len, &buf_size,
+                   "!!! Notice:\n"
+                   "Conducted power = Calibrated power + PPMCS offset - EIRP delta value\n"
+                   "where EIRP delata value = Total - Truncated !!!\n");
+
+       err = cl_vendor_reply(cl_hw, buf, len);
+       kfree(buf);
+
+       return err;
+}
+
+static int cl_power_table_print_he(struct cl_hw *cl_hw)
+{
+       char *buf = NULL;
+       ssize_t buf_size;
+       int err = 0;
+       int len = 0;
+
+       _cl_power_table_print_he(cl_hw, &buf, &len, &buf_size);
+
+       err = cl_vendor_reply(cl_hw, buf, len);
+       kfree(buf);
+
+       return err;
+}
+
+static int cl_power_table_print_ht_vht(struct cl_hw *cl_hw)
+{
+       char *buf = NULL;
+       ssize_t buf_size;
+       int err = 0;
+       int len = 0;
+
+       if (cl_band_is_6g(cl_hw))
+               return 0;
+
+       _cl_power_table_print_ht_vht(cl_hw, &buf, &len, &buf_size);
+
+       err = cl_vendor_reply(cl_hw, buf, len);
+       kfree(buf);
+
+       return err;
+}
+
+static int cl_power_table_print_ofdm(struct cl_hw *cl_hw)
+{
+       char *buf = NULL;
+       ssize_t buf_size;
+       int err = 0;
+       int len = 0;
+
+       if (cl_band_is_6g(cl_hw))
+               return 0;
+
+       _cl_power_table_print_ofdm(cl_hw, &buf, &len, &buf_size);
+
+       err = cl_vendor_reply(cl_hw, buf, len);
+       kfree(buf);
+
+       return err;
+}
+
+static int cl_power_table_print_cck(struct cl_hw *cl_hw)
+{
+       char *buf = NULL;
+       ssize_t buf_size;
+       int err = 0;
+       int len = 0;
+
+       if (!cl_band_is_24g(cl_hw))
+               return 0;
+
+       _cl_power_table_print_cck(cl_hw, &buf, &len, &buf_size);
+
+       err = cl_vendor_reply(cl_hw, buf, len);
+       kfree(buf);
+
+       return err;
+}
+
+static int cl_power_trunc_print_he(struct cl_hw *cl_hw)
+{
+       char *buf = NULL;
+       ssize_t buf_size;
+       int err = 0;
+       int len = 0;
+
+       _cl_power_trunc_print_he(cl_hw, &buf, &len, &buf_size);
+
+       err = cl_vendor_reply(cl_hw, buf, len);
+       kfree(buf);
+
+       return err;
+}
+
+static int cl_power_trunc_print_ht_vht(struct cl_hw *cl_hw)
+{
+       char *buf = NULL;
+       ssize_t buf_size;
+       int err = 0;
+       int len = 0;
+
+       if (cl_band_is_6g(cl_hw))
+               return 0;
+
+       _cl_power_trunc_print_ht_vht(cl_hw, &buf, &len, &buf_size);
+
+       err = cl_vendor_reply(cl_hw, buf, len);
+       kfree(buf);
+
+       return err;
+}
+
+static int cl_power_trunc_print_ofdm(struct cl_hw *cl_hw)
+{
+       char *buf = NULL;
+       ssize_t buf_size;
+       int err = 0;
+       int len = 0;
+
+       if (cl_band_is_6g(cl_hw))
+               return 0;
+
+       _cl_power_trunc_print_ofdm(cl_hw, &buf, &len, &buf_size);
+
+       err = cl_vendor_reply(cl_hw, buf, len);
+       kfree(buf);
+
+       return err;
+}
+
+static int cl_power_trunc_print_cck(struct cl_hw *cl_hw)
+{
+       char *buf = NULL;
+       ssize_t buf_size;
+       int err = 0;
+       int len = 0;
+
+       if (!cl_band_is_24g(cl_hw))
+               return 0;
+
+       _cl_power_trunc_print_cck(cl_hw, &buf, &len, &buf_size);
+
+       err = cl_vendor_reply(cl_hw, buf, len);
+       kfree(buf);
+
+       return err;
+}
+
+static void cl_power_auto_resp_to_buf(struct cl_hw *cl_hw, char **buf,
+                                     int *len, ssize_t *buf_size, u8 mode,
+                                     u8 max_mcs, s8 *pwr_auto_resp, const char *text)
+{
+       u8 mcs;
+       u8 tx_ant_num = cl_power_tx_ant(cl_hw, mode);
+       s32 ant_gain_q1 = cl_power_antenna_gain_q1(cl_hw);
+       s32 arr_gain_q1 = cl_power_array_gain_q1(cl_hw, tx_ant_num);
+       s32 conducted_q1, truncated_q1;
+
+       cl_snprintf(buf, len, buf_size,
+                   "\n%s Auto response\n"
+                   "|------------------|\n"
+                   "|MCS|Cond|Tot |Tab |\n"
+                   "|---+----+----+----|\n",
+                   text);
+
+       for (mcs = 0; mcs < max_mcs; mcs++) {
+               conducted_q1 = pwr_auto_resp[mcs] - arr_gain_q1;
+               truncated_q1 = pwr_auto_resp[mcs] + ant_gain_q1;
+
+               cl_snprintf(buf, len, buf_size,
+                           "|%3u|", mcs);
+               cl_power_q1_to_buf(buf, len, buf_size, "",
+                                  conducted_q1, "|", true);
+               cl_power_q1_to_buf(buf, len, buf_size, "",
+                                  truncated_q1, "|", true);
+               cl_power_q1_to_buf(buf, len, buf_size, "",
+                                  pwr_auto_resp[mcs], "|\n", true);
+       }
+
+       cl_snprintf(buf, len, buf_size,
+                   "|------------------|\n");
+}
+
+static int cl_power_auto_response_print(struct cl_hw *cl_hw)
+{
+       struct cl_pwr_tables *pwr_tables = &cl_hw->phy_data_info.data->pwr_tables;
+       char *buf = NULL;
+       ssize_t buf_size;
+       int len = 0;
+       int err = 0;
+       bool is_24g = cl_band_is_24g(cl_hw);
+       bool is_5g = cl_band_is_5g(cl_hw);
+       bool is_6g = cl_band_is_6g(cl_hw);
+
+       cl_power_auto_resp_to_buf(cl_hw, &buf, &len, &buf_size, WRS_MODE_HE, WRS_MCS_MAX_HE,
+                                 pwr_tables->pwr_auto_resp_he, "HE");
+
+       if (is_6g)
+               goto out;
+
+       if (is_5g || (is_24g && cl_hw->conf->ci_vht_cap_24g))
+               cl_power_auto_resp_to_buf(cl_hw, &buf, &len, &buf_size,
+                                         WRS_MODE_VHT, WRS_MCS_MAX_VHT,
+                                         pwr_tables->pwr_auto_resp_ht_vht, "VHT/HT");
+       else
+               cl_power_auto_resp_to_buf(cl_hw, &buf, &len, &buf_size,
+                                         WRS_MODE_HT, WRS_MCS_MAX_HT,
+                                         pwr_tables->pwr_auto_resp_ht_vht, "HT");
+
+       cl_power_auto_resp_to_buf(cl_hw, &buf, &len, &buf_size,
+                                 WRS_MODE_OFDM, WRS_MCS_MAX_OFDM,
+                                 pwr_tables->pwr_auto_resp_ofdm, "OFDM");
+
+       if (is_24g)
+               cl_power_auto_resp_to_buf(cl_hw, &buf, &len, &buf_size,
+                                         WRS_MODE_CCK, WRS_MCS_MAX_CCK,
+                                         pwr_tables->pwr_auto_resp_cck, "CCK");
+
+out:
+       err = cl_vendor_reply(cl_hw, buf, len);
+       kfree(buf);
+
+       return err;
+}
+
+static int cl_power_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,
+                "usage:\n"
+                "-a : General power information\n"
+                "-b : HE power table\n"
+                "-c : HT/VHT power table\n"
+                "-d : OFDM power table\n"
+                "-e : CCK power table\n"
+                "-f : HE power truncate\n"
+                "-g : HT/VHT power truncate\n"
+                "-h : OFDM power truncate\n"
+                "-i : CCK power truncate\n"
+                "-j : Auto-response power tables\n");
+
+       err = cl_vendor_reply(cl_hw, buf, strlen(buf));
+       kfree(buf);
+
+       return err;
+}
+
+int cl_power_cli(struct cl_hw *cl_hw, struct cli_params *cli_params)
+{
+       if (cli_params->num_params != 0)
+               goto err_num_params;
+
+       switch (cli_params->option) {
+       case 'a':
+               return cl_power_general_print(cl_hw);
+       case 'b':
+               return cl_power_table_print_he(cl_hw);
+       case 'c':
+               return cl_power_table_print_ht_vht(cl_hw);
+       case 'd':
+               return cl_power_table_print_ofdm(cl_hw);
+       case 'e':
+               return cl_power_table_print_cck(cl_hw);
+       case 'f':
+               return cl_power_trunc_print_he(cl_hw);
+       case 'g':
+               return cl_power_trunc_print_ht_vht(cl_hw);
+       case 'h':
+               return cl_power_trunc_print_ofdm(cl_hw);
+       case 'i':
+               return cl_power_trunc_print_cck(cl_hw);
+       case 'j':
+               return cl_power_auto_response_print(cl_hw);
+       case '?':
+               return cl_power_cli_help(cl_hw);
+       default:
+               cl_dbg_err(cl_hw, "Illegal option (%c) - try '?' for help\n", cli_params->option);
+               break;
+       }
+
+       return 0;
+
+err_num_params:
+       cl_dbg_err(cl_hw, "Wrong number of arguments\n");
+
+       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.
________________________________


^ permalink raw reply related	[flat|nested] 262+ messages in thread

* [RFC v1 136/256] cl8k: add power_cli.h
  2021-06-17 15:58 [RFC v1 000/256] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (134 preceding siblings ...)
  2021-06-17 16:00 ` [RFC v1 135/256] cl8k: add power_cli.c viktor.barna
@ 2021-06-17 16:00 ` viktor.barna
  2021-06-17 16:00 ` [RFC v1 137/256] cl8k: add power_table.c viktor.barna
                   ` (121 subsequent siblings)
  257 siblings, 0 replies; 262+ messages in thread
From: viktor.barna @ 2021-06-17 16:00 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Oleksandr Savchenko, Shay Bar, Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

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

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 drivers/net/wireless/celeno/cl8k/power_cli.h | 12 ++++++++++++
 1 file changed, 12 insertions(+)
 create mode 100644 drivers/net/wireless/celeno/cl8k/power_cli.h

diff --git a/drivers/net/wireless/celeno/cl8k/power_cli.h b/drivers/net/wireless/celeno/cl8k/power_cli.h
new file mode 100644
index 000000000000..c88e34a249da
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/power_cli.h
@@ -0,0 +1,12 @@
+/* SPDX-License-Identifier: MIT */
+/* Copyright(c) 2019-2021, Celeno Communications Ltd. */
+
+#ifndef CL_POWER_CLI_H
+#define CL_POWER_CLI_H
+
+#include "vendor_cmd.h"
+#include "hw.h"
+
+int cl_power_cli(struct cl_hw *cl_hw, struct cli_params *cli_params);
+
+#endif /* CL_POWER_CLI_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.
________________________________


^ permalink raw reply related	[flat|nested] 262+ messages in thread

* [RFC v1 137/256] cl8k: add power_table.c
  2021-06-17 15:58 [RFC v1 000/256] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (135 preceding siblings ...)
  2021-06-17 16:00 ` [RFC v1 136/256] cl8k: add power_cli.h viktor.barna
@ 2021-06-17 16:00 ` viktor.barna
  2021-06-17 16:00 ` [RFC v1 138/256] cl8k: add power_table.h viktor.barna
                   ` (120 subsequent siblings)
  257 siblings, 0 replies; 262+ messages in thread
From: viktor.barna @ 2021-06-17 16:00 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Oleksandr Savchenko, Shay Bar, Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

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

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 .../net/wireless/celeno/cl8k/power_table.c    | 218 ++++++++++++++++++
 1 file changed, 218 insertions(+)
 create mode 100644 drivers/net/wireless/celeno/cl8k/power_table.c

diff --git a/drivers/net/wireless/celeno/cl8k/power_table.c b/drivers/net/wireless/celeno/cl8k/power_table.c
new file mode 100644
index 000000000000..27cbe5596af0
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/power_table.c
@@ -0,0 +1,218 @@
+// SPDX-License-Identifier: MIT
+/* Copyright(c) 2019-2021, Celeno Communications Ltd. */
+
+#include "power_table.h"
+#include "chip.h"
+#include "e2p.h"
+#include "debug.h"
+#include "band.h"
+
+/*
+ * How to fill power table:
+ * Set 81 values in the range of 100 - 180 according to the Excel file.
+ * 100 corresponds to power of -10dBm (Pout Ant).
+ * 180 corresponds to power of +30dBm (Pout Ant).
+ * All values between 0 - 99 should be same as the value of 100.
+ * All values between 181 - 255 should be same as the value of 180.
+ */
+
+static const u8 power_to_powerword_conv_table_id_0[NUM_POWER_WORDS] = {
+       0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, /* 0 - 7 */
+       0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, /* 8 - 15 */
+       0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, /* 16 - 23 */
+       0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, /* 24 - 31 */
+       0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, /* 32 - 39 */
+       0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, /* 40 - 47 */
+       0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, /* 48 - 55 */
+       0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, /* 56 - 63 */
+       0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, /* 64 - 71 */
+       0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, /* 72 - 79 */
+       0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, /* 80 - 87 */
+       0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, /* 88 - 95 */
+       0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0F, 0x10, 0x11, /* 96 - 103 */
+       0x12, 0x13, 0x14, 0x40, 0x41, 0x42, 0x43, 0x44, /* 104 - 111 */
+       0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x4B, 0x4C, /* 112 - 119 */
+       0x4D, 0x4E, 0x4F, 0x50, 0x51, 0x52, 0x53, 0x54, /* 120 - 127 */
+       0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x5B, 0x5C, /* 128 - 135 */
+       0x5D, 0x5E, 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, /* 136 - 143 */
+       0x66, 0x67, 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, /* 144 - 151 */
+       0x6E, 0x6F, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, /* 152 - 159 */
+       0x76, 0x77, 0x78, 0x79, 0x7A, 0x7B, 0x7C, 0x7D, /* 160 - 167 */
+       0xB9, 0xBA, 0xBB, 0xBC, 0xBD, 0xF9, 0xFA, 0xFB, /* 168 - 175 */
+       0xFC, 0xFD, 0xFD, 0xFD, 0xFD, 0xFD, 0xFD, 0xFD, /* 176 - 183 */
+       0xFD, 0xFD, 0xFD, 0xFD, 0xFD, 0xFD, 0xFD, 0xFD, /* 184 - 191 */
+       0xFD, 0xFD, 0xFD, 0xFD, 0xFD, 0xFD, 0xFD, 0xFD, /* 192 - 199 */
+       0xFD, 0xFD, 0xFD, 0xFD, 0xFD, 0xFD, 0xFD, 0xFD, /* 200 - 207 */
+       0xFD, 0xFD, 0xFD, 0xFD, 0xFD, 0xFD, 0xFD, 0xFD, /* 208 - 215 */
+       0xFD, 0xFD, 0xFD, 0xFD, 0xFD, 0xFD, 0xFD, 0xFD, /* 216 - 223 */
+       0xFD, 0xFD, 0xFD, 0xFD, 0xFD, 0xFD, 0xFD, 0xFD, /* 224 - 231 */
+       0xFD, 0xFD, 0xFD, 0xFD, 0xFD, 0xFD, 0xFD, 0xFD, /* 232 - 239 */
+       0xFD, 0xFD, 0xFD, 0xFD, 0xFD, 0xFD, 0xFD, 0xFD, /* 240 - 247 */
+       0xFD, 0xFD, 0xFD, 0xFD, 0xFD, 0xFD, 0xFD, 0xFD  /* 248 - 255 */
+};
+
+static const u8 power_to_powerword_conv_table_id_1[NUM_POWER_WORDS] = {
+       0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, /* 0 - 7 */
+       0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, /* 8 - 15 */
+       0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, /* 16 - 23 */
+       0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, /* 24 - 31 */
+       0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, /* 32 - 39 */
+       0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, /* 40 - 47 */
+       0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, /* 48 - 55 */
+       0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, /* 56 - 63 */
+       0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, /* 64 - 71 */
+       0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, /* 72 - 79 */
+       0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, /* 80 - 87 */
+       0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, /* 88 - 95 */
+       0x03, 0x03, 0x03, 0x03, 0x03, 0x04, 0x05, 0x06, /* 96 - 103 */
+       0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, /* 104 - 111 */
+       0x0F, 0x10, 0x11, 0x12, 0x40, 0x41, 0x42, 0x43, /* 112 - 119 */
+       0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x4B, /* 120 - 127 */
+       0x4C, 0x4D, 0x4E, 0x4F, 0x50, 0x51, 0x52, 0x53, /* 128 - 135 */
+       0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x5B, /* 136 - 143 */
+       0x5C, 0x5D, 0x5E, 0x60, 0x61, 0x62, 0x63, 0x64, /* 144 - 151 */
+       0x65, 0x66, 0x67, 0x68, 0x69, 0x6A, 0x6B, 0x6C, /* 152 - 159 */
+       0x6D, 0x6E, 0x6F, 0x70, 0x71, 0x72, 0x73, 0x74, /* 160 - 167 */
+       0x75, 0x76, 0x77, 0x78, 0x79, 0x7A, 0x7B, 0x7C, /* 168 - 175 */
+       0x7D, 0xB9, 0xBA, 0xBB, 0xBC, 0xBC, 0xBC, 0xBC, /* 176 - 183 */
+       0xBC, 0xBC, 0xBC, 0xBC, 0xBC, 0xBC, 0xBC, 0xBC, /* 184 - 191 */
+       0xBC, 0xBC, 0xBC, 0xBC, 0xBC, 0xBC, 0xBC, 0xBC, /* 192 - 199 */
+       0xBC, 0xBC, 0xBC, 0xBC, 0xBC, 0xBC, 0xBC, 0xBC, /* 200 - 207 */
+       0xBC, 0xBC, 0xBC, 0xBC, 0xBC, 0xBC, 0xBC, 0xBC, /* 208 - 215 */
+       0xBC, 0xBC, 0xBC, 0xBC, 0xBC, 0xBC, 0xBC, 0xBC, /* 216 - 223 */
+       0xBC, 0xBC, 0xBC, 0xBC, 0xBC, 0xBC, 0xBC, 0xBC, /* 224 - 231 */
+       0xBC, 0xBC, 0xBC, 0xBC, 0xBC, 0xBC, 0xBC, 0xBC, /* 232 - 239 */
+       0xBC, 0xBC, 0xBC, 0xBC, 0xBC, 0xBC, 0xBC, 0xBC, /* 240 - 247 */
+       0xBC, 0xBC, 0xBC, 0xBC, 0xBC, 0xBC, 0xBC, 0xBC  /* 248 - 255 */
+};
+
+static const u8 power_to_powerword_conv_table_id_2[NUM_POWER_WORDS] = {
+       0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, /* 0 - 7 */
+       0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, /* 8 - 15 */
+       0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, /* 16 - 23 */
+       0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, /* 24 - 31 */
+       0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, /* 32 - 39 */
+       0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, /* 40 - 47 */
+       0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, /* 48 - 55 */
+       0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, /* 56 - 63 */
+       0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, /* 64 - 71 */
+       0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, /* 72 - 79 */
+       0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, /* 80 - 87 */
+       0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, /* 88 - 95 */
+       0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0F, 0x10, 0x11, /* 96 - 103 */
+       0x12, 0x13, 0x14, 0x40, 0x41, 0x42, 0x43, 0x44, /* 104 - 111 */
+       0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x4B, 0x4C, /* 112 - 119 */
+       0x4D, 0x4E, 0x4F, 0x50, 0x51, 0x52, 0x53, 0x54, /* 120 - 127 */
+       0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x5B, 0x5C, /* 128 - 135 */
+       0x5D, 0x5E, 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, /* 136 - 143 */
+       0x66, 0x67, 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, /* 144 - 151 */
+       0x6E, 0x6F, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, /* 152 - 159 */
+       0x76, 0x77, 0x78, 0x79, 0x7A, 0x7B, 0x7C, 0x7D, /* 160 - 167 */
+       0xB9, 0xBA, 0xBB, 0xBC, 0xBD, 0xBD, 0xBD, 0xBD, /* 168 - 175 */
+       0xBD, 0xBD, 0xBD, 0xBD, 0xBD, 0xBD, 0xBD, 0xBD, /* 176 - 183 */
+       0xBD, 0xBD, 0xBD, 0xBD, 0xBD, 0xBD, 0xBD, 0xBD, /* 184 - 191 */
+       0xBD, 0xBD, 0xBD, 0xBD, 0xBD, 0xBD, 0xBD, 0xBD, /* 192 - 199 */
+       0xBD, 0xBD, 0xBD, 0xBD, 0xBD, 0xBD, 0xBD, 0xBD, /* 200 - 207 */
+       0xBD, 0xBD, 0xBD, 0xBD, 0xBD, 0xBD, 0xBD, 0xBD, /* 208 - 215 */
+       0xBD, 0xBD, 0xBD, 0xBD, 0xBD, 0xBD, 0xBD, 0xBD, /* 216 - 223 */
+       0xBD, 0xBD, 0xBD, 0xBD, 0xBD, 0xBD, 0xBD, 0xBD, /* 224 - 231 */
+       0xBD, 0xBD, 0xBD, 0xBD, 0xBD, 0xBD, 0xBD, 0xBD, /* 232 - 239 */
+       0xBD, 0xBD, 0xBD, 0xBD, 0xBD, 0xBD, 0xBD, 0xBD, /* 240 - 247 */
+       0xBD, 0xBD, 0xBD, 0xBD, 0xBD, 0xBD, 0xBD, 0xBD  /* 248 - 255 */
+};
+
+static u8 cl_power_table_read(struct cl_hw *cl_hw)
+{
+       u8 pwr_table_id = 0;
+
+       if (cl_e2p_read(cl_hw->chip, &pwr_table_id, 1, ADDR_GEN_PWR_TABLE_ID + cl_hw->tcv_idx))
+               return U8_MAX;
+
+       return pwr_table_id;
+}
+
+static int cl_power_table_fill(struct cl_hw *cl_hw)
+{
+       u8 pwr_table_id = cl_power_table_read(cl_hw);
+
+       switch (pwr_table_id) {
+       case 0:
+               if (cl_band_is_5g(cl_hw)) {
+                       memcpy(cl_hw->power_table_info.data->conv_table,
+                              power_to_powerword_conv_table_id_0, NUM_POWER_WORDS);
+                       cl_hw->tx_power_version = 5;
+               } else {
+                       CL_DBG_ERROR(cl_hw, "Power table ID (%u) is valid for 5g only\n",
+                                    pwr_table_id);
+
+                       if (!cl_hw->chip->conf->ce_production_mode)
+                               return -1;
+               }
+               break;
+       case 1:
+               if (cl_band_is_24g(cl_hw)) {
+                       memcpy(cl_hw->power_table_info.data->conv_table,
+                              power_to_powerword_conv_table_id_1, NUM_POWER_WORDS);
+                       cl_hw->tx_power_version = 25;
+               } else {
+                       CL_DBG_ERROR(cl_hw, "Power table ID (%u) is valid for 2.4g only\n",
+                                    pwr_table_id);
+
+                       if (!cl_hw->chip->conf->ce_production_mode)
+                               return -1;
+               }
+               break;
+       case 2:
+               if (cl_band_is_6g(cl_hw)) {
+                       memcpy(cl_hw->power_table_info.data->conv_table,
+                              power_to_powerword_conv_table_id_2, NUM_POWER_WORDS);
+                       cl_hw->tx_power_version = 1;
+               } else {
+                       CL_DBG_ERROR(cl_hw, "Power table ID (%u) is valid for 6g only\n",
+                                    pwr_table_id);
+
+                       if (!cl_hw->chip->conf->ce_production_mode)
+                               return -1;
+               }
+               break;
+       default:
+               CL_DBG_ERROR(cl_hw, "Power table ID is not configured in EEPROM\n");
+
+               if (!cl_hw->chip->conf->ce_production_mode)
+                       return -1;
+       }
+
+       cl_dbg_verbose(cl_hw, "Power table ID %u (V%u)\n", pwr_table_id, cl_hw->tx_power_version);
+
+       return 0;
+}
+
+int cl_power_table_alloc(struct cl_hw *cl_hw)
+{
+       struct cl_power_table_data *buf = NULL;
+       u32 len = sizeof(struct cl_power_table_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->power_table_info.data = buf;
+       cl_hw->power_table_info.dma_addr = cpu_to_le32(phys_dma_addr);
+
+       return cl_power_table_fill(cl_hw);
+}
+
+void cl_power_table_free(struct cl_hw *cl_hw)
+{
+       struct cl_power_table_info *power_table_info = &cl_hw->power_table_info;
+       u32 len = sizeof(struct cl_power_table_data);
+       dma_addr_t phys_dma_addr = le32_to_cpu(power_table_info->dma_addr);
+
+       if (!power_table_info->data)
+               return;
+
+       dma_free_coherent(cl_hw->chip->dev, len, (void *)power_table_info->data, phys_dma_addr);
+       power_table_info->data = 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.
________________________________


^ permalink raw reply related	[flat|nested] 262+ messages in thread

* [RFC v1 138/256] cl8k: add power_table.h
  2021-06-17 15:58 [RFC v1 000/256] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (136 preceding siblings ...)
  2021-06-17 16:00 ` [RFC v1 137/256] cl8k: add power_table.c viktor.barna
@ 2021-06-17 16:00 ` viktor.barna
  2021-06-17 16:00 ` [RFC v1 139/256] cl8k: add prot_mode.c viktor.barna
                   ` (119 subsequent siblings)
  257 siblings, 0 replies; 262+ messages in thread
From: viktor.barna @ 2021-06-17 16:00 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Oleksandr Savchenko, Shay Bar, Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

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

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 .../net/wireless/celeno/cl8k/power_table.h    | 25 +++++++++++++++++++
 1 file changed, 25 insertions(+)
 create mode 100644 drivers/net/wireless/celeno/cl8k/power_table.h

diff --git a/drivers/net/wireless/celeno/cl8k/power_table.h b/drivers/net/wireless/celeno/cl8k/power_table.h
new file mode 100644
index 000000000000..ba2c45f8d408
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/power_table.h
@@ -0,0 +1,25 @@
+/* SPDX-License-Identifier: MIT */
+/* Copyright(c) 2019-2021, Celeno Communications Ltd. */
+
+#ifndef CL_POWER_TABLE_H
+#define CL_POWER_TABLE_H
+
+#include <linux/types.h>
+
+#define NUM_POWER_WORDS 256
+
+struct cl_power_table_data {
+       u8 conv_table[NUM_POWER_WORDS];
+};
+
+struct cl_power_table_info {
+       struct cl_power_table_data *data;
+       u32 dma_addr;
+};
+
+struct cl_hw;
+
+int cl_power_table_alloc(struct cl_hw *cl_hw);
+void cl_power_table_free(struct cl_hw *cl_hw);
+
+#endif /* CL_POWER_TABLE_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.
________________________________


^ permalink raw reply related	[flat|nested] 262+ messages in thread

* [RFC v1 139/256] cl8k: add prot_mode.c
  2021-06-17 15:58 [RFC v1 000/256] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (137 preceding siblings ...)
  2021-06-17 16:00 ` [RFC v1 138/256] cl8k: add power_table.h viktor.barna
@ 2021-06-17 16:00 ` viktor.barna
  2021-06-17 16:00 ` [RFC v1 140/256] cl8k: add prot_mode.h viktor.barna
                   ` (118 subsequent siblings)
  257 siblings, 0 replies; 262+ messages in thread
From: viktor.barna @ 2021-06-17 16:00 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Oleksandr Savchenko, Shay Bar, Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

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

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 drivers/net/wireless/celeno/cl8k/prot_mode.c | 53 ++++++++++++++++++++
 1 file changed, 53 insertions(+)
 create mode 100644 drivers/net/wireless/celeno/cl8k/prot_mode.c

diff --git a/drivers/net/wireless/celeno/cl8k/prot_mode.c b/drivers/net/wireless/celeno/cl8k/prot_mode.c
new file mode 100644
index 000000000000..34e20328772e
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/prot_mode.c
@@ -0,0 +1,53 @@
+// SPDX-License-Identifier: MIT
+/* Copyright(c) 2019-2021, Celeno Communications Ltd. */
+
+#include "prot_mode.h"
+#include "fw/msg_tx.h"
+#include <linux/string.h>
+
+void cl_prot_mode_init(struct cl_hw *cl_hw)
+{
+       struct cl_prot_mode *prot_mode = &cl_hw->prot_mode;
+       u8 init = cl_hw->conf->ce_prot_mode;
+
+       prot_mode->current_val = init;
+       prot_mode->default_val = init;
+       prot_mode->dynamic_val = (init != TXL_NO_PROT) ? init : TXL_PROT_RTS;
+}
+
+void cl_prot_mode_set(struct cl_hw *cl_hw, u8 prot_mode_new)
+{
+       struct cl_prot_mode *prot_mode = &cl_hw->prot_mode;
+       struct cl_tcv_conf *conf = cl_hw->conf;
+
+       if (prot_mode->current_val != prot_mode_new) {
+               prot_mode->current_val = prot_mode_new;
+               cl_msg_tx_prot_mode(cl_hw,
+                                   conf->ce_prot_log_nav_en,
+                                   prot_mode_new,
+                                   conf->ce_prot_rate_format,
+                                   conf->ce_prot_rate_mcs,
+                                   conf->ce_prot_rate_pre_type);
+       }
+}
+
+void cl_prot_mode_disable(struct cl_hw *cl_hw)
+{
+       cl_prot_mode_set(cl_hw, TXL_NO_PROT);
+}
+
+void cl_prot_mode_enable(struct cl_hw *cl_hw)
+{
+       cl_prot_mode_set(cl_hw, cl_hw->prot_mode.dynamic_val);
+}
+
+void cl_prot_mode_restore_default(struct cl_hw *cl_hw)
+{
+       cl_prot_mode_set(cl_hw, cl_hw->prot_mode.default_val);
+}
+
+u8 cl_prot_mode_get(struct cl_hw *cl_hw)
+{
+       return cl_hw->prot_mode.current_val;
+}
+
--
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.
________________________________


^ permalink raw reply related	[flat|nested] 262+ messages in thread

* [RFC v1 140/256] cl8k: add prot_mode.h
  2021-06-17 15:58 [RFC v1 000/256] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (138 preceding siblings ...)
  2021-06-17 16:00 ` [RFC v1 139/256] cl8k: add prot_mode.c viktor.barna
@ 2021-06-17 16:00 ` viktor.barna
  2021-06-17 16:00 ` [RFC v1 141/256] cl8k: add radio.c viktor.barna
                   ` (117 subsequent siblings)
  257 siblings, 0 replies; 262+ messages in thread
From: viktor.barna @ 2021-06-17 16:00 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Oleksandr Savchenko, Shay Bar, Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

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

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 drivers/net/wireless/celeno/cl8k/prot_mode.h | 30 ++++++++++++++++++++
 1 file changed, 30 insertions(+)
 create mode 100644 drivers/net/wireless/celeno/cl8k/prot_mode.h

diff --git a/drivers/net/wireless/celeno/cl8k/prot_mode.h b/drivers/net/wireless/celeno/cl8k/prot_mode.h
new file mode 100644
index 000000000000..177559edf62f
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/prot_mode.h
@@ -0,0 +1,30 @@
+/* SPDX-License-Identifier: MIT */
+/* Copyright(c) 2019-2021, Celeno Communications Ltd. */
+
+#ifndef CL_PROT_MODE_H
+#define CL_PROT_MODE_H
+
+#include "hw.h"
+
+/**
+ * Protection mode (RTS/CTS) control
+ */
+
+enum cl_txl_prot_mode {
+       TXL_NO_PROT,
+       TXL_PROT_RTS,
+       TXL_PROT_CTS,
+       TXL_PROT_RTS_FW,
+       TXL_PROT_CTS_FW,
+
+       TXL_PROT_MAX,
+};
+
+void cl_prot_mode_init(struct cl_hw *cl_hw);
+void cl_prot_mode_disable(struct cl_hw *cl_hw);
+void cl_prot_mode_enable(struct cl_hw *cl_hw);
+void cl_prot_mode_restore_default(struct cl_hw *cl_hw);
+void cl_prot_mode_set(struct cl_hw *cl_hw, u8 prot_mode_new);
+u8 cl_prot_mode_get(struct cl_hw *cl_hw);
+
+#endif /* CL_PROT_MODE_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.
________________________________


^ permalink raw reply related	[flat|nested] 262+ messages in thread

* [RFC v1 141/256] cl8k: add radio.c
  2021-06-17 15:58 [RFC v1 000/256] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (139 preceding siblings ...)
  2021-06-17 16:00 ` [RFC v1 140/256] cl8k: add prot_mode.h viktor.barna
@ 2021-06-17 16:00 ` viktor.barna
  2021-06-17 16:00 ` [RFC v1 142/256] cl8k: add radio.h viktor.barna
                   ` (116 subsequent siblings)
  257 siblings, 0 replies; 262+ messages in thread
From: viktor.barna @ 2021-06-17 16:00 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Oleksandr Savchenko, Shay Bar, Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

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

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 drivers/net/wireless/celeno/cl8k/radio.c | 171 +++++++++++++++++++++++
 1 file changed, 171 insertions(+)
 create mode 100644 drivers/net/wireless/celeno/cl8k/radio.c

diff --git a/drivers/net/wireless/celeno/cl8k/radio.c b/drivers/net/wireless/celeno/cl8k/radio.c
new file mode 100644
index 000000000000..165d90332254
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/radio.c
@@ -0,0 +1,171 @@
+// SPDX-License-Identifier: MIT
+/* Copyright(c) 2019-2021, Celeno Communications Ltd. */
+
+#include <linux/kthread.h>
+#include <linux/jiffies.h>
+#include "radio.h"
+#include "vendor_cmd.h"
+#include "fw/msg_tx.h"
+#include "vif.h"
+#include "sta.h"
+#include "chip.h"
+
+static int cl_radio_off_kthread(void *arg)
+{
+       struct cl_hw *cl_hw = (struct cl_hw *)arg;
+       struct cl_vif *cl_vif;
+
+       cl_sta_disassociate_all(cl_hw);
+
+       cl_dbg_verbose(cl_hw, "Waiting for stations to disconnect\n");
+
+       if (wait_event_timeout(cl_hw->radio_wait_queue,
+                              cl_sta_num_bh(cl_hw) == 0,
+                              msecs_to_jiffies(5000)) == 0) {
+               cl_dbg_verbose(cl_hw,
+                              "Failed to disconnect stations. %u stations still remaining\n",
+                              cl_sta_num_bh(cl_hw));
+               return 1;
+       }
+
+       cl_dbg_trace(cl_hw, "Stopping queues ...\n");
+
+       list_for_each_entry(cl_vif, &cl_hw->vif_db.head, list) {
+               cl_vif->tx_en = false;
+               cl_dbg_verbose(cl_hw, "Radio OFF vif_index = %u\n",
+                              cl_vif->vif_index);
+       }
+
+       cl_msg_tx_set_idle(cl_hw, MAC_IDLE_SYNC);
+
+       cl_dbg_trace(cl_hw, "Radio shut down successfully\n");
+
+       cl_hw->radio_status = RADIO_STATUS_OFF;
+       atomic_set(&cl_hw->radio_lock, 0);
+
+       return 0;
+}
+
+static int cl_radio_off(struct cl_hw *cl_hw)
+{
+       struct task_struct *k;
+
+       if (cl_hw->radio_status != RADIO_STATUS_ON ||
+           atomic_xchg(&cl_hw->radio_lock, 1))
+               return 1;
+
+       cl_hw->radio_status = RADIO_STATUS_GOING_DOWN;
+
+       /* Relegate the job to a kthread to free the system call. */
+       k = kthread_run(cl_radio_off_kthread, cl_hw, "cl_radio_off_kthread");
+       if (IS_ERR(k))
+               cl_dbg_verbose(cl_hw,
+                              "Error: failed to run cl_radio_off_kthread\n");
+       return 0;
+}
+
+static void _cl_radio_on(struct cl_hw *cl_hw)
+{
+       struct cl_vif *cl_vif;
+
+       list_for_each_entry(cl_vif, &cl_hw->vif_db.head, list) {
+               if (cl_vif->vif->type == NL80211_IFTYPE_AP) {
+                       if (cl_hw->iface_conf == CL_IFCONF_REPEATER &&
+                           !test_bit(CL_DEV_REPEATER, &cl_hw->drv_flags))
+                               continue;
+                       if (cl_hw->iface_conf == CL_IFCONF_MESH_AP &&
+                           !test_bit(CL_DEV_MESH_AP, &cl_hw->drv_flags))
+                               continue;
+               }
+
+               cl_vif->tx_en = true;
+               cl_dbg_verbose(cl_hw, "Radio ON vif=%u\n", cl_vif->vif_index);
+       }
+
+       cl_msg_tx_set_idle(cl_hw, MAC_ACTIVE);
+
+       cl_dbg_verbose(cl_hw, "Radio has been started\n");
+
+       cl_hw->radio_status = RADIO_STATUS_ON;
+       atomic_set(&cl_hw->radio_lock, 0);
+}
+
+int cl_radio_on(struct cl_hw *cl_hw)
+{
+       struct cl_chip *chip = cl_hw->chip;
+       struct cl_hw *cl_hw_other = cl_hw_other_tcv(cl_hw);
+       bool other_tcv_radio_on_needed = false;
+
+       if (cl_hw->radio_status != RADIO_STATUS_OFF ||
+           atomic_xchg(&cl_hw->radio_lock, 1))
+               return 1;
+
+       cl_hw->calib_ready = true;
+
+       if (cl_chip_is_both_enabled(chip) && cl_hw_other->conf->ce_radio_on) {
+               if (cl_hw_other->calib_ready)
+                       other_tcv_radio_on_needed = true;
+               else
+                       return 1;
+       }
+
+       _cl_radio_on(cl_hw);
+
+       if (other_tcv_radio_on_needed)
+               _cl_radio_on(cl_hw_other);
+
+       if (chip->conf->ce_calib_scan_en && !chip->calib_db.scan_complete)
+               cl_calib_start_work(cl_hw);
+
+       return 0;
+}
+
+void cl_radio_off_chip(struct cl_chip *chip)
+{
+       if (cl_chip_is_tcv0_enabled(chip))
+               cl_radio_off(chip->cl_hw_tcv0);
+
+       if (cl_chip_is_tcv1_enabled(chip))
+               cl_radio_off(chip->cl_hw_tcv1);
+}
+
+void cl_radio_on_chip(struct cl_chip *chip)
+{
+       if (cl_chip_is_tcv0_enabled(chip))
+               cl_radio_on(chip->cl_hw_tcv0);
+
+       if (cl_chip_is_tcv1_enabled(chip))
+               cl_radio_on(chip->cl_hw_tcv1);
+}
+
+bool cl_radio_is_off(struct cl_hw *cl_hw)
+{
+       return cl_hw->radio_status == RADIO_STATUS_OFF;
+}
+
+bool cl_radio_is_on(struct cl_hw *cl_hw)
+{
+       return cl_hw->radio_status == RADIO_STATUS_ON;
+}
+
+bool cl_radio_is_going_down(struct cl_hw *cl_hw)
+{
+       return cl_hw->radio_status == RADIO_STATUS_GOING_DOWN;
+}
+
+int cl_radio_cli(struct cl_hw *cl_hw, bool radio_on)
+{
+       cl_hw->conf->ce_radio_on = radio_on;
+
+       if (radio_on)
+               cl_radio_on(cl_hw);
+       else
+               cl_radio_off(cl_hw);
+
+       return 0;
+}
+
+void cl_radio_off_wake_up(struct cl_hw *cl_hw)
+{
+       wake_up(&cl_hw->radio_wait_queue);
+}
--
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.
________________________________


^ permalink raw reply related	[flat|nested] 262+ messages in thread

* [RFC v1 142/256] cl8k: add radio.h
  2021-06-17 15:58 [RFC v1 000/256] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (140 preceding siblings ...)
  2021-06-17 16:00 ` [RFC v1 141/256] cl8k: add radio.c viktor.barna
@ 2021-06-17 16:00 ` viktor.barna
  2021-06-17 16:00 ` [RFC v1 143/256] cl8k: add rate_ctrl.c viktor.barna
                   ` (115 subsequent siblings)
  257 siblings, 0 replies; 262+ messages in thread
From: viktor.barna @ 2021-06-17 16:00 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Oleksandr Savchenko, Shay Bar, Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

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

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 drivers/net/wireless/celeno/cl8k/radio.h | 24 ++++++++++++++++++++++++
 1 file changed, 24 insertions(+)
 create mode 100644 drivers/net/wireless/celeno/cl8k/radio.h

diff --git a/drivers/net/wireless/celeno/cl8k/radio.h b/drivers/net/wireless/celeno/cl8k/radio.h
new file mode 100644
index 000000000000..d95a2d526d1b
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/radio.h
@@ -0,0 +1,24 @@
+/* SPDX-License-Identifier: MIT */
+/* Copyright(c) 2019-2021, Celeno Communications Ltd. */
+
+#ifndef CL_RADIO_H
+#define CL_RADIO_H
+
+#include "hw.h"
+
+#define RADIO_STATUS_OFF        0
+#define RADIO_STATUS_ON         1
+#define RADIO_STATUS_GOING_DOWN 2
+
+int cl_radio_on(struct cl_hw *cl_hw);
+void cl_radio_off_chip(struct cl_chip *chip);
+void cl_radio_on_chip(struct cl_chip *chip);
+bool cl_radio_is_off(struct cl_hw *cl_hw);
+bool cl_radio_is_on(struct cl_hw *cl_hw);
+bool cl_radio_is_going_down(struct cl_hw *cl_hw);
+int cl_radio_cli(struct cl_hw *cl_hw, bool radio_on);
+
+/* Wakes up cl_radio_off_kthread after all the stations have disconnected. */
+void cl_radio_off_wake_up(struct cl_hw *cl_hw);
+
+#endif /* CL_RADIO_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.
________________________________


^ permalink raw reply related	[flat|nested] 262+ messages in thread

* [RFC v1 143/256] cl8k: add rate_ctrl.c
  2021-06-17 15:58 [RFC v1 000/256] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (141 preceding siblings ...)
  2021-06-17 16:00 ` [RFC v1 142/256] cl8k: add radio.h viktor.barna
@ 2021-06-17 16:00 ` viktor.barna
  2021-06-17 16:00 ` [RFC v1 144/256] cl8k: add rate_ctrl.h viktor.barna
                   ` (114 subsequent siblings)
  257 siblings, 0 replies; 262+ messages in thread
From: viktor.barna @ 2021-06-17 16:00 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Oleksandr Savchenko, Shay Bar, Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

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

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 drivers/net/wireless/celeno/cl8k/rate_ctrl.c | 276 +++++++++++++++++++
 1 file changed, 276 insertions(+)
 create mode 100644 drivers/net/wireless/celeno/cl8k/rate_ctrl.c

diff --git a/drivers/net/wireless/celeno/cl8k/rate_ctrl.c b/drivers/net/wireless/celeno/cl8k/rate_ctrl.c
new file mode 100644
index 000000000000..960ca4ea4473
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/rate_ctrl.c
@@ -0,0 +1,276 @@
+// SPDX-License-Identifier: MIT
+/* Copyright(c) 2019-2021, Celeno Communications Ltd. */
+
+#include "rate_ctrl.h"
+#include "tx/tx.h"
+#include "band.h"
+#include "bf.h"
+#include "fw/msg_tx.h"
+#include "utils/utils.h"
+
+u32 cl_rate_ctrl_generate(struct cl_hw *cl_hw, struct cl_sta *cl_sta,
+                         u8 mode, u8 bw, u8 nss, u8 mcs, u8 gi,
+                         bool fallback_en)
+{
+       union cl_rate_ctrl_info rate_ctrl_info;
+
+       rate_ctrl_info.word = 0;
+
+       /* Format_mod + mcs_index */
+       if (mode == WRS_MODE_HE) {
+               rate_ctrl_info.field.mcs_index = (nss << 4) | mcs;
+               rate_ctrl_info.field.format_mod = FORMATMOD_HE_SU;
+       } else if (mode == WRS_MODE_VHT) {
+               rate_ctrl_info.field.mcs_index = (nss << 4) | mcs;
+               rate_ctrl_info.field.format_mod = FORMATMOD_VHT;
+       } else if (mode == WRS_MODE_HT) {
+               rate_ctrl_info.field.mcs_index = (nss << 3) | mcs;
+               rate_ctrl_info.field.format_mod = FORMATMOD_HT_MF;
+       } else if (mode == WRS_MODE_OFDM) {
+               rate_ctrl_info.field.mcs_index = mcs + RATE_CTRL_OFFSET_OFDM;
+               rate_ctrl_info.field.format_mod =
+                       (bw == CHNL_BW_20) ? FORMATMOD_NON_HT : FORMATMOD_NON_HT_DUP_OFDM;
+       } else { /* WRS_MODE_CCK */
+               rate_ctrl_info.field.mcs_index = mcs;
+               rate_ctrl_info.field.format_mod = FORMATMOD_NON_HT;
+       }
+
+       /* Gi */
+       rate_ctrl_info.field.gi = convert_gi_format_wrs_to_fw(mode, gi);
+
+       /* Bw */
+       rate_ctrl_info.field.bw = bw;
+
+       /* Fallback */
+       rate_ctrl_info.field.fallback = fallback_en;
+
+       /* Tx_bf */
+       if (cl_sta && cl_bf_is_on(cl_hw, cl_sta, nss))
+               rate_ctrl_info.field.tx_bf = true;
+
+       /* Pre_type/stbc */
+       if (rate_ctrl_info.field.format_mod == FORMATMOD_NON_HT)
+               rate_ctrl_info.field.pre_type_or_stbc = 1;
+
+       return rate_ctrl_info.word;
+}
+
+void cl_rate_ctrl_convert(union cl_rate_ctrl_info *rate_ctrl_info)
+{
+       u32 format_mod = rate_ctrl_info->field.format_mod;
+
+       /*
+        * Convert gi from firmware format to driver format
+        * !!! Must be done before converting the format mode !!!
+        */
+       rate_ctrl_info->field.gi = convert_gi_format_fw_to_wrs(format_mod,
+                                                              rate_ctrl_info->field.gi);
+
+       /* Convert format_mod from firmware format to WRS format */
+       if (format_mod >= FORMATMOD_HE_SU) {
+               rate_ctrl_info->field.format_mod = WRS_MODE_HE;
+       } else if (format_mod == FORMATMOD_VHT) {
+               rate_ctrl_info->field.format_mod = WRS_MODE_VHT;
+       } else if (format_mod >= FORMATMOD_HT_MF) {
+               rate_ctrl_info->field.format_mod = WRS_MODE_HT;
+       } else if (format_mod == FORMATMOD_NON_HT_DUP_OFDM) {
+               rate_ctrl_info->field.format_mod = WRS_MODE_OFDM;
+       } else {
+               if (rate_ctrl_info->field.mcs_index >= RATE_CTRL_OFFSET_OFDM)
+                       rate_ctrl_info->field.format_mod = WRS_MODE_OFDM;
+               else
+                       rate_ctrl_info->field.format_mod = WRS_MODE_CCK;
+       }
+}
+
+void cl_rate_ctrl_parse(union cl_rate_ctrl_info *rate_ctrl_info, u8 *nss, u8 *mcs)
+{
+       switch (rate_ctrl_info->field.format_mod) {
+       case WRS_MODE_HE:
+       case WRS_MODE_VHT:
+               *nss = (rate_ctrl_info->field.mcs_index >> 4);
+               *mcs = (rate_ctrl_info->field.mcs_index & 0xF);
+               break;
+       case WRS_MODE_HT:
+               *nss = (rate_ctrl_info->field.mcs_index >> 3);
+               *mcs = (rate_ctrl_info->field.mcs_index & 0x7);
+               break;
+       case WRS_MODE_OFDM:
+               *nss = 0;
+               *mcs = rate_ctrl_info->field.mcs_index - RATE_CTRL_OFFSET_OFDM;
+               break;
+       case WRS_MODE_CCK:
+               *nss = 0;
+               *mcs = rate_ctrl_info->field.mcs_index;
+               break;
+       default:
+               *nss = *mcs = 0;
+       }
+}
+
+void cl_rate_ctrl_set_default(struct cl_hw *cl_hw)
+{
+       u32 rate_ctrl = 0;
+       union cl_rate_ctrl_info_he rate_ctrl_he;
+
+       /* HE default */
+       rate_ctrl_he.word = 0;
+       rate_ctrl_he.field.spatial_conf = RATE_CNTRL_HE_SPATIAL_CONF_DEF;
+       rate_ctrl = cl_rate_ctrl_generate(cl_hw, NULL, WRS_MODE_HE,
+                                         0, 0, 0, 0, false);
+
+       cl_msg_tx_update_rate_dl(cl_hw, 0xff, rate_ctrl, 0, 0,
+                                RATE_OP_MODE_DEFAULT_HE, LTF_X4, 0, rate_ctrl_he.word);
+
+       /* OFDM default */
+       rate_ctrl = cl_rate_ctrl_generate(cl_hw, NULL, WRS_MODE_OFDM, 0, 0,
+                                         cl_hw->conf->ce_default_mcs_ofdm, 0, false);
+
+       cl_msg_tx_update_rate_dl(cl_hw, 0xff, rate_ctrl, 0, 0,
+                                RATE_OP_MODE_DEFAULT_OFDM, 0, 0, 0);
+
+       /* CCK default */
+       if (cl_band_is_24g(cl_hw)) {
+               rate_ctrl = cl_rate_ctrl_generate(cl_hw, NULL, WRS_MODE_CCK, 0, 0,
+                                                 cl_hw->conf->ce_default_mcs_cck, 0, false);
+
+               cl_msg_tx_update_rate_dl(cl_hw, 0xff, rate_ctrl, 0, 0,
+                                        RATE_OP_MODE_DEFAULT_CCK, 0, 0, 0);
+       }
+}
+
+void cl_rate_ctrl_set_default_per_he_minrate(struct cl_hw *cl_hw, u8 bw,
+                                            u8 nss, u8 mcs, u8 gi)
+{
+       union cl_rate_ctrl_info_he rate_ctrl_he;
+       u32 rate_ctrl = 0;
+       u8 ltf = cl_map_gi_to_ltf(WRS_MODE_HE, gi);
+
+       rate_ctrl_he.word = 0;
+       rate_ctrl_he.field.spatial_conf = RATE_CNTRL_HE_SPATIAL_CONF_DEF;
+       rate_ctrl = cl_rate_ctrl_generate(cl_hw, NULL, WRS_MODE_HE, bw,
+                                         nss, mcs, gi, false);
+
+       cl_msg_tx_update_rate_dl(cl_hw, 0xff, rate_ctrl, 0, 0,
+                                RATE_OP_MODE_DEFAULT_HE, ltf,
+                                0, rate_ctrl_he.word);
+
+       cl_msg_tx_update_rate_dl(cl_hw, 0xff, rate_ctrl, 0, 0,
+                                RATE_OP_MODE_MCAST, ltf, 0, 0);
+
+       cl_msg_tx_update_rate_dl(cl_hw, 0xff, rate_ctrl, 0, 0,
+                                RATE_OP_MODE_BCAST, ltf, 0, 0);
+}
+
+bool cl_rate_ctrl_set_mcast(struct cl_hw *cl_hw, u8 mode, u8 mcs)
+{
+       u32 rate_ctrl_mcast = cl_rate_ctrl_generate(cl_hw, NULL, mode, 0, 0, mcs,
+                                                   WRS_GI_LONG, false);
+       u8 ltf = cl_map_gi_to_ltf(mode, WRS_GI_LONG);
+
+       if (cl_msg_tx_update_rate_dl(cl_hw, 0xff, rate_ctrl_mcast, 0, 0,
+                                    RATE_OP_MODE_MCAST, ltf, 0, 0))
+               return false;
+
+       return true;
+}
+
+bool cl_rate_ctrl_set_fixed(struct cl_hw *cl_hw, u32 rate_ctrl_he, u8 mode, u8 mcs, u8 nss,
+                           u8 bw, u8 gi, u8 ltf_field)
+{
+       u32 rate_ctrl_fixed = cl_rate_ctrl_generate(cl_hw, NULL, mode, bw, nss,
+                                                   mcs, gi, false);
+
+       if (cl_msg_tx_update_rate_dl(cl_hw, 0xff, rate_ctrl_fixed, 0, bw, RATE_OP_MODE_FIXED,
+                                    ltf_field, 0, rate_ctrl_he))
+               return false;
+
+       return true;
+}
+
+bool cl_rate_ctrl_set_dbgfs(struct cl_hw *cl_hw, u8 sta_idx, u32 rate_ctrl, u32 rate_ctrl_he,
+                           u8 op_mode, u8 bw, u8 ltf_field)
+{
+       /*
+        * op_mode can be RATE_OP_MODE_FIXED or RATE_OP_MODE_STA_MU.
+        * Therefore rate_fallback should be 0.
+        */
+       if (cl_msg_tx_update_rate_dl(cl_hw, sta_idx, rate_ctrl, 0, bw, op_mode,
+                                    ltf_field, 0, rate_ctrl_he))
+               return false;
+
+       return true;
+}
+
+void cl_rate_ctrl_set_ate_agg(struct cl_hw *cl_hw, struct cl_sta *cl_sta)
+{
+       struct cl_ate_db *ate_db = &cl_hw->ate_db;
+       union cl_rate_ctrl_info rate_ctrl;
+       union cl_rate_ctrl_info_he rate_ctrl_he;
+       u8 ltf_mode = cl_map_gi_to_ltf(ate_db->mode, ate_db->gi);
+       u8 sta_idx = cl_sta->sta_idx;
+
+       rate_ctrl_he.word = 0;
+       rate_ctrl_he.field.spatial_conf = RATE_CNTRL_HE_SPATIAL_CONF_DEF;
+
+       rate_ctrl.word = cl_rate_ctrl_generate(cl_hw, cl_sta, ate_db->mode, ate_db->bw,
+                                              ate_db->nss, ate_db->mcs, ate_db->gi, false);
+
+       cl_msg_tx_update_rate_dl(cl_hw, sta_idx, rate_ctrl.word, 0, ate_db->bw,
+                                RATE_OP_MODE_STA_SU, ltf_mode, 0, rate_ctrl_he.word);
+}
+
+static u8 cl_rate_ctrl_get_min(struct cl_hw *cl_hw)
+{
+       if (cl_hw->conf->ci_min_he_en &&
+           cl_hw->conf->ce_wireless_mode == WIRELESS_MODE_HE)
+               return RATE_CTRL_ENTRY_MIN_HE;
+
+       if (cl_hw_mode_is_b_or_bg(cl_hw))
+               return RATE_CTRL_ENTRY_MIN_CCK;
+
+       return RATE_CTRL_ENTRY_MIN_OFDM;
+}
+
+void cl_rate_ctrl_update_desc_single(struct cl_hw *cl_hw, struct tx_host_info *info,
+                                    struct cl_sw_txhdr *sw_txhdr)
+{
+       struct ieee80211_hdr *mac_hdr = sw_txhdr->hdr80211;
+       struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(sw_txhdr->skb);
+       bool is_data = ieee80211_is_data(sw_txhdr->fc);
+
+       if (sw_txhdr->cl_sta && is_data) {
+               if (cl_tx_ctrl_is_eapol(tx_info)) {
+                       info->rate_ctrl_entry = cl_rate_ctrl_get_min(cl_hw);
+               } else {
+                       if (cl_hw->entry_fixed_rate)
+                               info->rate_ctrl_entry = RATE_CTRL_ENTRY_FIXED_RATE;
+                       else
+                               info->rate_ctrl_entry = RATE_CTRL_ENTRY_STA;
+               }
+       } else {
+               if (sw_txhdr->is_bcn) {
+                       info->rate_ctrl_entry = cl_rate_ctrl_get_min(cl_hw);
+               } else if (is_multicast_ether_addr(mac_hdr->addr1) &&
+                          !is_broadcast_ether_addr(mac_hdr->addr1)) {
+                       info->rate_ctrl_entry = RATE_CTRL_ENTRY_MCAST;
+               } else if (is_broadcast_ether_addr(mac_hdr->addr1) &&
+                          !cl_hw->entry_fixed_rate) {
+                       info->rate_ctrl_entry = RATE_CTRL_ENTRY_BCAST;
+               } else {
+                       if (cl_hw->entry_fixed_rate && is_data)
+                               info->rate_ctrl_entry = RATE_CTRL_ENTRY_FIXED_RATE;
+                       else
+                               info->rate_ctrl_entry = cl_rate_ctrl_get_min(cl_hw);
+               }
+       }
+}
+
+void cl_rate_ctrl_update_desc_agg(struct cl_hw *cl_hw, struct tx_host_info *info)
+{
+       /* For aggregation there are only two options - STA and FIXED_RATE */
+       if (cl_hw->entry_fixed_rate)
+               info->rate_ctrl_entry = RATE_CTRL_ENTRY_FIXED_RATE;
+       else
+               info->rate_ctrl_entry = RATE_CTRL_ENTRY_STA;
+}
--
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.
________________________________


^ permalink raw reply related	[flat|nested] 262+ messages in thread

* [RFC v1 144/256] cl8k: add rate_ctrl.h
  2021-06-17 15:58 [RFC v1 000/256] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (142 preceding siblings ...)
  2021-06-17 16:00 ` [RFC v1 143/256] cl8k: add rate_ctrl.c viktor.barna
@ 2021-06-17 16:00 ` viktor.barna
  2021-06-17 16:00 ` [RFC v1 145/256] cl8k: add recovery.c viktor.barna
                   ` (113 subsequent siblings)
  257 siblings, 0 replies; 262+ messages in thread
From: viktor.barna @ 2021-06-17 16:00 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Oleksandr Savchenko, Shay Bar, Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

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

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 drivers/net/wireless/celeno/cl8k/rate_ctrl.h | 106 +++++++++++++++++++
 1 file changed, 106 insertions(+)
 create mode 100644 drivers/net/wireless/celeno/cl8k/rate_ctrl.h

diff --git a/drivers/net/wireless/celeno/cl8k/rate_ctrl.h b/drivers/net/wireless/celeno/cl8k/rate_ctrl.h
new file mode 100644
index 000000000000..181f6e31ca00
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/rate_ctrl.h
@@ -0,0 +1,106 @@
+/* SPDX-License-Identifier: MIT */
+/* Copyright(c) 2019-2021, Celeno Communications Ltd. */
+
+#ifndef CL_RATE_CTRL_H
+#define CL_RATE_CTRL_H
+
+#include <linux/types.h>
+#include "ipc_shared.h"
+
+#define RATE_CTRL_OFFSET_OFDM          4
+#define RATE_CNTRL_HE_SPATIAL_CONF_DEF 0xF
+
+/* Op_mode field in mm_update_rate_dl_req structure */
+enum cl_op_mode {
+       RATE_OP_MODE_FIXED,
+       RATE_OP_MODE_DEFAULT_HE,
+       RATE_OP_MODE_DEFAULT_OFDM,
+       RATE_OP_MODE_DEFAULT_CCK,
+       RATE_OP_MODE_STA_SU,
+       RATE_OP_MODE_STA_MU,
+       RATE_OP_MODE_MCAST,
+       RATE_OP_MODE_BCAST
+};
+
+/* Value to be set in tx_host_info */
+enum cl_rate_ctrl_entry {
+       RATE_CTRL_ENTRY_NA = 0,
+
+       RATE_CTRL_ENTRY_STA,
+       RATE_CTRL_ENTRY_FIXED_RATE,
+       RATE_CTRL_ENTRY_MIN_HE,
+       RATE_CTRL_ENTRY_MIN_OFDM,
+       RATE_CTRL_ENTRY_MIN_CCK,
+       RATE_CTRL_ENTRY_MCAST,
+       RATE_CTRL_ENTRY_BCAST,
+
+       /* Entry size in firmware is represented by 3 bits */
+       RATE_CTRL_ENTRY_MAX = 8
+};
+
+/*
+ * sw_ctrl includes eights bits (16 - 23) to be used by software.
+ * Bit 16 is used by driver to indicate tx_bf.
+ * Bit 17 is used by driver to indicate fallback.
+ * Bit 18 - 23 are still free.
+ */
+struct cl_rate_ctrl_info_fields {
+       u32 mcs_index        : 7;   /* [6:0] */
+       u32 bw               : 2;   /* [8:7] */
+       u32 gi               : 2;   /* [10:9] */
+       u32 pre_type_or_stbc : 1;   /* [11] */
+       u32 format_mod       : 4;   /* [15:12] */
+       u32 tx_bf            : 1;   /* [16] */
+       u32 fallback         : 1;   /* [17] */
+       u32 sw_ctrl          : 6;   /* [23:18] */
+       u32 tx_chains        : 8;   /* [31:24] */
+};
+
+union cl_rate_ctrl_info {
+       struct cl_rate_ctrl_info_fields field;
+       u32 word;
+};
+
+struct cl_rate_ctrl_info_he_fields {
+       u32 spatial_conf    : 4;   /* [3:0] */
+       u32 starting_sts    : 3;   /* [6:4] */
+       u32 ru_index        : 6;   /* [12:7] */
+       u32 ru_type         : 3;   /* [15:13] */
+       u32 ru_band         : 1;   /* [16] */
+       u32 mu_usr_pos      : 2;   /* [18:17] */
+       u32 dcm_data        : 1;   /* [19] */
+       u32 num_usrs_mu_dl  : 4;   /* [23:20] */
+       u32 ru_alloc        : 8;   /* [31:24] */
+};
+
+union cl_rate_ctrl_info_he {
+       struct cl_rate_ctrl_info_he_fields field;
+       u32 word;
+};
+
+struct cl_hw;
+struct cl_sta;
+struct cl_sw_txhdr;
+
+u32 cl_rate_ctrl_generate(struct cl_hw *cl_hw, struct cl_sta *cl_sta,
+                         u8 mode, u8 bw, u8 nss, u8 mcs, u8 gi,
+                         bool fallback_en);
+void cl_rate_ctrl_convert(union cl_rate_ctrl_info *rate_ctrl_info);
+void cl_rate_ctrl_parse(union cl_rate_ctrl_info *rate_ctrl_info, u8 *nss, u8 *mcs);
+
+void cl_rate_ctrl_set_default(struct cl_hw *cl_hw);
+
+void cl_rate_ctrl_set_default_per_he_minrate(struct cl_hw *cl_hw, u8 bw,
+                                            u8 nss, u8 mcs, u8 gi);
+bool cl_rate_ctrl_set_mcast(struct cl_hw *cl_hw, u8 mode, u8 mcs);
+bool cl_rate_ctrl_set_fixed(struct cl_hw *cl_hw, u32 rate_ctrl_he, u8 mode, u8 mcs, u8 nss,
+                           u8 bw, u8 gi, u8 ltf_field);
+bool cl_rate_ctrl_set_dbgfs(struct cl_hw *cl_hw, u8 sta_idx, u32 rate_ctrl, u32 rate_ctrl_he,
+                           u8 op_mode, u8 bw, u8 ltf_field);
+void cl_rate_ctrl_set_ate_agg(struct cl_hw *cl_hw, struct cl_sta *cl_sta);
+
+void cl_rate_ctrl_update_desc_single(struct cl_hw *cl_hw, struct tx_host_info *info,
+                                    struct cl_sw_txhdr *sw_txhdr);
+void cl_rate_ctrl_update_desc_agg(struct cl_hw *cl_hw, struct tx_host_info *info);
+
+#endif /* CL_RATE_CTRL_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.
________________________________


^ permalink raw reply related	[flat|nested] 262+ messages in thread

* [RFC v1 145/256] cl8k: add recovery.c
  2021-06-17 15:58 [RFC v1 000/256] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (143 preceding siblings ...)
  2021-06-17 16:00 ` [RFC v1 144/256] cl8k: add rate_ctrl.h viktor.barna
@ 2021-06-17 16:00 ` viktor.barna
  2021-06-17 16:00 ` [RFC v1 146/256] cl8k: add recovery.h viktor.barna
                   ` (112 subsequent siblings)
  257 siblings, 0 replies; 262+ messages in thread
From: viktor.barna @ 2021-06-17 16:00 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Oleksandr Savchenko, Shay Bar, Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

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

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 drivers/net/wireless/celeno/cl8k/recovery.c | 264 ++++++++++++++++++++
 1 file changed, 264 insertions(+)
 create mode 100644 drivers/net/wireless/celeno/cl8k/recovery.c

diff --git a/drivers/net/wireless/celeno/cl8k/recovery.c b/drivers/net/wireless/celeno/cl8k/recovery.c
new file mode 100644
index 000000000000..1bba86ea4882
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/recovery.c
@@ -0,0 +1,264 @@
+// SPDX-License-Identifier: MIT
+/* Copyright(c) 2019-2021, Celeno Communications Ltd. */
+
+#include "recovery.h"
+#include "rx/rx_amsdu.h"
+#include "main.h"
+#include "phy/phy.h"
+#include "vif.h"
+#include "dfs/dfs.h"
+#include "maintenance.h"
+#include "tx/tx_inject.h"
+#include "ext/dyn_mcast_rate.h"
+#include "ext/dyn_bcast_rate.h"
+#include "vns.h"
+#include "radio.h"
+#include "wrs/wrs_api.h"
+#include "config.h"
+#include "fw/msg_tx.h"
+#include "coredump.h"
+#ifdef CONFIG_CL_PCIE
+#include "bus/pci/irq.h"
+#endif
+
+struct cl_recovery_work {
+       struct work_struct ws;
+       struct cl_hw *cl_hw;
+       int reason;
+};
+
+#define RECOVERY_POLL_TIMEOUT 6
+
+static void cl_recovery_poll_completion(struct cl_hw *cl_hw)
+{
+       u8 cntr = 0;
+
+       while (test_bit(CL_DEV_SW_RESTART, &cl_hw->drv_flags)) {
+               msleep(1000);
+
+               if (++cntr == RECOVERY_POLL_TIMEOUT) {
+                       cl_dbg_verbose(cl_hw, "\n");
+                       cl_dbg_err(cl_hw, "Driver handgup was detected!...");
+                       break;
+               }
+       }
+}
+
+static void cl_recovery_start_hw(struct cl_hw *cl_hw)
+{
+       clear_bit(CL_DEV_STOP_HW, &cl_hw->drv_flags);
+
+       /* Restart MAC firmware... */
+       if (cl_main_on(cl_hw)) {
+               cl_dbg_err(cl_hw, "Couldn't turn platform on .. aborting\n");
+               return;
+       }
+
+       if (cl_msg_tx_reset(cl_hw)) {
+               cl_dbg_err(cl_hw, "Failed to send firmware reset .. aborting\n");
+               return;
+       }
+
+       set_bit(CL_DEV_SW_RESTART, &cl_hw->drv_flags);
+       clear_bit(CL_DEV_HW_RESTART, &cl_hw->drv_flags);
+
+       /* Hand over to mac80211 from here */
+       ieee80211_restart_hw(cl_hw->hw);
+
+       cl_recovery_poll_completion(cl_hw);
+}
+
+static void cl_recovery_stop_hw(struct cl_hw *cl_hw)
+{
+       /* Start recovery process */
+       cl_hw->recovery_db.in_recovery = true;
+
+       clear_bit(CL_DEV_STARTED, &cl_hw->drv_flags);
+       set_bit(CL_DEV_HW_RESTART, &cl_hw->drv_flags);
+       set_bit(CL_DEV_STOP_HW, &cl_hw->drv_flags);
+#ifdef CONFIG_CL_PCIE
+       /* Disable interrupts */
+       cl_irq_disable(cl_hw, cl_hw->ipc_e2a_irq.all);
+#endif
+       cl_tx_inject_stop_in_recovery(cl_hw);
+       cl_maintenance_stop(cl_hw);
+
+       ieee80211_stop_queues(cl_hw->hw);
+
+       mutex_lock(&cl_hw->dbginfo.mutex);
+
+       cl_main_off(cl_hw);
+
+       cl_hw->fw_active = false;
+       cl_hw->fw_send_start = false;
+
+       cl_coredump_reset_trace(cl_hw);
+
+       mutex_unlock(&cl_hw->dbginfo.mutex);
+
+       /* Reset it so MM_SET_FILTER_REQ will be called during the recovery */
+       cl_hw->rx_filter = 0;
+
+       /*
+        * Reset channel/frequency parameters so that cl_msg_tx_set_channel()
+        * will not be skipped in cl_ops_config()
+        */
+       cl_hw->channel = 0;
+       cl_hw->primary_freq = 0;
+       cl_hw->center_freq = 0;
+}
+
+static void cl_recovery_process(struct cl_hw *cl_hw)
+{
+       int ret;
+
+       cl_dbg_verbose(cl_hw, "Start\n");
+
+       cl_recovery_stop_hw(cl_hw);
+       cl_phy_reset(cl_hw);
+
+       ret = cl_phy_load_recovery(cl_hw);
+       if (ret) {
+               cl_dbg_err(cl_hw, "cl_phy_load_recovery failed %d\n", ret);
+               return;
+       }
+
+       cl_recovery_start_hw(cl_hw);
+}
+
+static void cl_recovery_handler(struct cl_hw *cl_hw, int reason)
+{
+       unsigned long recovery_diff = jiffies_to_msecs(jiffies - cl_hw->recovery_db.last_restart);
+
+       cl_hw->recovery_db.restart_cnt++;
+
+       if (recovery_diff > cl_hw->conf->ce_fw_watchdog_limit_time) {
+               cl_hw->recovery_db.restart_cnt = 1;
+       } else if (cl_hw->recovery_db.restart_cnt > cl_hw->conf->ce_fw_watchdog_limit_count) {
+               cl_dbg_verbose(cl_hw, "Too many failures... aborting\n");
+               cl_hw->conf->ce_fw_watchdog_mode = FW_WD_DISABLE;
+               return;
+       }
+
+       cl_hw->recovery_db.last_restart = jiffies;
+
+       /* Count recovery attempts for statistics */
+       cl_hw->fw_recovery_cntr++;
+       cl_dbg_trace(cl_hw, "Recovering from firmware failure, attempt #%i\n",
+                    cl_hw->fw_recovery_cntr);
+
+       cl_recovery_process(cl_hw);
+}
+
+static void cl_recovery_work_do(struct work_struct *ws)
+{
+       /* Worker for restarting hw. */
+       struct cl_recovery_work *recovery_work = container_of(ws, struct cl_recovery_work, ws);
+
+       recovery_work->cl_hw->assert_info.restart_sched = false;
+       cl_recovery_handler(recovery_work->cl_hw, recovery_work->reason);
+       kfree(recovery_work);
+}
+
+static void cl_recovery_work_sched(struct cl_hw *cl_hw, int reason)
+{
+       /*
+        * Schedule work to restart device and firmware
+        * This is scheduled when driver detects hw assert storm.
+        */
+       struct cl_recovery_work *recovery_work;
+
+       if (!cl_hw->ipc_env || cl_hw->is_stop_context) {
+               cl_dbg_warn(cl_hw, "Skip recovery - Running down!\n");
+               return;
+       }
+
+       /* If restart is already scheduled - exit */
+       if (cl_hw->assert_info.restart_sched)
+               return;
+
+       cl_hw->assert_info.restart_sched = true;
+
+       /* Recovery_work will be freed by cl_recovery_work_do */
+       recovery_work = kzalloc(sizeof(*recovery_work), GFP_ATOMIC);
+
+       if (!recovery_work)
+               return;
+
+       INIT_WORK(&recovery_work->ws, cl_recovery_work_do);
+       recovery_work->cl_hw = cl_hw;
+       recovery_work->reason = reason;
+
+       queue_work(cl_hw->drv_workqueue, &recovery_work->ws);
+}
+
+bool cl_recovery_in_progress(struct cl_hw *cl_hw)
+{
+       return cl_hw->recovery_db.in_recovery;
+}
+
+void cl_recovery_reconfig_complete(struct cl_hw *cl_hw)
+{
+       clear_bit(CL_DEV_SW_RESTART, &cl_hw->drv_flags);
+
+       /* Multicast/Broadcast rate recovery */
+       cl_dyn_mcast_rate_recovery(cl_hw);
+       cl_dyn_bcast_rate_recovery(cl_hw);
+
+       /* DFS recovery */
+       cl_dfs_recovery(cl_hw);
+
+       /* VNS recovery */
+       cl_vns_recovery(cl_hw);
+
+       /* Restore EDCA configuration */
+       cl_edca_recovery(cl_hw);
+
+       /* Temperature  recovery */
+       cl_temperature_recovery(cl_hw);
+
+       /* Sounding recovery */
+       cl_sounding_recovery(cl_hw);
+
+       /*
+        * Update Tx params for all connected stations to sync firmware after the
+        * recovery process.
+        */
+       cl_wrs_api_recovery(cl_hw);
+
+       /* Enable maintenance timers back */
+       cl_maintenance_start(cl_hw);
+
+       if (cl_radio_is_on(cl_hw))
+               cl_msg_tx_set_idle(cl_hw, MAC_ACTIVE);
+
+       cl_hw->recovery_db.in_recovery = false;
+
+       pr_debug("cl_recovery: complete\n");
+
+       cl_rx_post_recovery(cl_hw);
+}
+
+void cl_recovery_start(struct cl_hw *cl_hw, int reason)
+{
+       /* Prevent new messages to be sent until firmware has recovered */
+       set_bit(CL_DEV_FW_ERROR, &cl_hw->drv_flags);
+
+       switch (cl_hw->conf->ce_fw_watchdog_mode) {
+       case FW_WD_DISABLE:
+               cl_dbg_info(cl_hw, "Skip recovery - Watchdog is off!\n");
+               break;
+
+       case FW_WD_INTERNAL_RECOVERY:
+               cl_recovery_work_sched(cl_hw, reason);
+               break;
+
+       case FW_WD_DRV_RELOAD:
+               /* TODO: Implement netlink hint to the userspace */
+               cl_dbg_info(cl_hw, "RELOAD handler is absent, doing nothing");
+               break;
+
+       default:
+               break;
+       }
+}
--
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.
________________________________


^ permalink raw reply related	[flat|nested] 262+ messages in thread

* [RFC v1 146/256] cl8k: add recovery.h
  2021-06-17 15:58 [RFC v1 000/256] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (144 preceding siblings ...)
  2021-06-17 16:00 ` [RFC v1 145/256] cl8k: add recovery.c viktor.barna
@ 2021-06-17 16:00 ` viktor.barna
  2021-06-17 16:00 ` [RFC v1 147/256] cl8k: add reg/ceva.h viktor.barna
                   ` (111 subsequent siblings)
  257 siblings, 0 replies; 262+ messages in thread
From: viktor.barna @ 2021-06-17 16:00 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Oleksandr Savchenko, Shay Bar, Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

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

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 drivers/net/wireless/celeno/cl8k/recovery.h | 27 +++++++++++++++++++++
 1 file changed, 27 insertions(+)
 create mode 100644 drivers/net/wireless/celeno/cl8k/recovery.h

diff --git a/drivers/net/wireless/celeno/cl8k/recovery.h b/drivers/net/wireless/celeno/cl8k/recovery.h
new file mode 100644
index 000000000000..6899faaabf8a
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/recovery.h
@@ -0,0 +1,27 @@
+/* SPDX-License-Identifier: MIT */
+/* Copyright(c) 2019-2021, Celeno Communications Ltd. */
+
+#ifndef CL_RECOVERY_H
+#define CL_RECOVERY_H
+
+#include "hw.h"
+
+enum recovery_reason {
+       RECOVERY_WAIT4CFM,
+       RECOVERY_UNRECOVERABLE_ASSERT,
+       RECOVERY_UNRECOVERABLE_ASSERT_NO_DUMP,
+       RECOVERY_ASSERT_STORM_DETECT,
+       RECOVERY_DRV_FAILED,
+};
+
+enum cl_fw_wd_mode {
+       FW_WD_DISABLE,
+       FW_WD_INTERNAL_RECOVERY,
+       FW_WD_DRV_RELOAD,
+};
+
+bool cl_recovery_in_progress(struct cl_hw *cl_hw);
+void cl_recovery_reconfig_complete(struct cl_hw *cl_hw);
+void cl_recovery_start(struct cl_hw *cl_hw, int reason);
+
+#endif /* CL_RECOVERY_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.
________________________________


^ permalink raw reply related	[flat|nested] 262+ messages in thread

* [RFC v1 147/256] cl8k: add reg/ceva.h
  2021-06-17 15:58 [RFC v1 000/256] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (145 preceding siblings ...)
  2021-06-17 16:00 ` [RFC v1 146/256] cl8k: add recovery.h viktor.barna
@ 2021-06-17 16:00 ` viktor.barna
  2021-06-17 16:00 ` [RFC v1 148/256] cl8k: add reg/reg_access.h viktor.barna
                   ` (110 subsequent siblings)
  257 siblings, 0 replies; 262+ messages in thread
From: viktor.barna @ 2021-06-17 16:00 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Oleksandr Savchenko, Shay Bar, Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

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

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 drivers/net/wireless/celeno/cl8k/reg/ceva.h | 44 +++++++++++++++++++++
 1 file changed, 44 insertions(+)
 create mode 100644 drivers/net/wireless/celeno/cl8k/reg/ceva.h

diff --git a/drivers/net/wireless/celeno/cl8k/reg/ceva.h b/drivers/net/wireless/celeno/cl8k/reg/ceva.h
new file mode 100644
index 000000000000..3e5f79b0cc14
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/reg/ceva.h
@@ -0,0 +1,44 @@
+/* SPDX-License-Identifier: MIT */
+/* Copyright(c) 2019-2021, Celeno Communications Ltd. */
+
+#ifndef CL_CEVA_H
+#define CL_CEVA_H
+
+#define CEVA_MCCI_BASE_ADDR 0x004B0000
+
+#define CEVA_CORE_VERSION_ADDR (CEVA_MCCI_BASE_ADDR + 0x1000)
+#define CEVA_CORE_ID_ADDR (CEVA_MCCI_BASE_ADDR + 0x1004)
+
+#define CEVA_CPM_BASE_ADDR (CEVA_MCCI_BASE_ADDR + 0x2000)
+
+/* PDMA */
+#define CEVA_CPM_PDEA_REG (CEVA_CPM_BASE_ADDR + 0x0008) /* External */
+#define CEVA_CPM_PDIA_REG (CEVA_CPM_BASE_ADDR + 0x000C) /* Internal */
+#define CEVA_CPM_PDTC_REG (CEVA_CPM_BASE_ADDR + 0x0010) /* Control */
+
+/* DDMA */
+#define CEVA_CPM_DDEA_REG (CEVA_CPM_BASE_ADDR + 0x001c) /* External */
+#define CEVA_CPM_DDIA_REG (CEVA_CPM_BASE_ADDR + 0x0020) /* Internal */
+#define CEVA_CPM_DDTC_REG (CEVA_CPM_BASE_ADDR + 0x0024) /* Control */
+
+#define CEVA_CPM_DDTC_WRITE_COMMAND 0x40000000
+
+/* Translated internally to 0x60600000. */
+#define CEVA_SHARED_PMEM_BASE_ADDR_FROM_HOST 0x004C0000
+
+/* Internal address to access Shared */
+#define CEVA_SHARED_PMEM_BASE_ADDR_INTERNAL 0x60600000 /* PMEM */
+#define CEVA_SHARED_XMEM_BASE_ADDR_INTERNAL 0x60900000 /* XMEM */
+
+#define CEVA_DSP_DATA_SIZE 0x80000 /* 512kB. */
+#define CEVA_DSP_EXT_DATA_SIZE 0x60000 /* 384kB. */
+
+/* 512kb */
+#define CEVA_INTERNAL_PMEM_SIZE 0x80000
+
+#define CEVA_SHARED_PMEM_SIZE 0x20000 /* 128kb */
+#define CEVA_SHARED_XMEM_SIZE 0x60000 /* 384kB */
+
+#define CEVA_MAX_PAGES (CEVA_INTERNAL_PMEM_SIZE / CEVA_SHARED_PMEM_SIZE)
+
+#endif /* CL_CEVA_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.
________________________________


^ permalink raw reply related	[flat|nested] 262+ messages in thread

* [RFC v1 148/256] cl8k: add reg/reg_access.h
  2021-06-17 15:58 [RFC v1 000/256] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (146 preceding siblings ...)
  2021-06-17 16:00 ` [RFC v1 147/256] cl8k: add reg/ceva.h viktor.barna
@ 2021-06-17 16:00 ` viktor.barna
  2021-06-17 16:00 ` [RFC v1 149/256] cl8k: add reg/reg_cli.c viktor.barna
                   ` (109 subsequent siblings)
  257 siblings, 0 replies; 262+ messages in thread
From: viktor.barna @ 2021-06-17 16:00 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Oleksandr Savchenko, Shay Bar, Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

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

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 .../net/wireless/celeno/cl8k/reg/reg_access.h | 197 ++++++++++++++++++
 1 file changed, 197 insertions(+)
 create mode 100644 drivers/net/wireless/celeno/cl8k/reg/reg_access.h

diff --git a/drivers/net/wireless/celeno/cl8k/reg/reg_access.h b/drivers/net/wireless/celeno/cl8k/reg/reg_access.h
new file mode 100644
index 000000000000..337f6f809d35
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/reg/reg_access.h
@@ -0,0 +1,197 @@
+/* SPDX-License-Identifier: MIT */
+/* Copyright(c) 2019-2021, Celeno Communications Ltd. */
+
+#ifndef CL_REG_ACCESS_H
+#define CL_REG_ACCESS_H
+
+#include "hw.h"
+#include "chip.h"
+#include "ceva.h"
+#include "fw/msg_tx.h"
+
+#define CL_REG_DBG(...) \
+       do { \
+               if (cl_hw->reg_dbg) \
+                       cl_dbg_verbose(__VA_ARGS__); \
+       } while (0)
+
+#define CL_REG_DBG_CHIP(...) \
+       do { \
+               if (chip->reg_dbg) \
+                       cl_dbg_chip_verbose(__VA_ARGS__); \
+       } while (0)
+
+#define XTENSA_PIF_BASE_ADDR     0x60000000
+
+/*
+ * SHARED_RAM Address.
+ * Actually the PCI BAR4 window will be configured such as SHARED RAM
+ * is accessed with offset 0 (within the AHB Bridge main window)
+ */
+#define SHARED_RAM_START_ADDR    0x00000000
+
+#define REG_MAC_HW_SMAC_OFFSET   0x80000
+#define REG_PHY_SMAC_OFFSET      0x100000
+
+#define REG_MACDSP_API_BASE_ADDR 0x00400000
+#define REG_MAC_HW_BASE_ADDR     0x00600000
+#define REG_RIU_BASE_ADDR        0x00486000
+#define REG_RICU_BASE_ADDR       0x004B4000
+
+#define APB_REGS_BASE_ADDR       0x007C0000
+#define I2C_REG_BASE_ADDR        (APB_REGS_BASE_ADDR + 0x3000)
+#define IPC_REG_BASE_ADDR        (APB_REGS_BASE_ADDR + 0x4000)
+
+/* MACSYS_GCU_XT_CONTROL fields */
+#define SMAC_DEBUG_ENABLE      BIT(21)
+#define SMAC_BREAKPOINT        BIT(20)
+#define SMAC_OCD_HALT_ON_RESET BIT(19)
+#define SMAC_RUN_STALL         BIT(18)
+#define SMAC_DRESET            BIT(17)
+#define SMAC_BRESET            BIT(16)
+#define UMAC_DEBUG_ENABLE      BIT(13)
+#define UMAC_BREAKPOINT        BIT(11)
+#define UMAC_OCD_HALT_ON_RESET BIT(11)
+#define UMAC_RUN_STALL         BIT(10)
+#define UMAC_DRESET            BIT(9)
+#define UMAC_BRESET            BIT(8)
+#define LMAC_DEBUG_ENABLE      BIT(5)
+#define LMAC_BREAKPOINT        BIT(4)
+#define LMAC_OCD_HALT_ON_RESET BIT(3)
+#define LMAC_RUN_STALL         BIT(2)
+#define LMAC_DRESET            BIT(1)
+#define LMAC_BRESET            BIT(0)
+
+#define XMAC_BRESET \
+       (LMAC_BRESET | SMAC_BRESET | UMAC_BRESET)
+#define XMAC_DRESET \
+       (LMAC_DRESET | SMAC_DRESET | UMAC_DRESET)
+#define XMAC_RUN_STALL \
+       (LMAC_RUN_STALL | SMAC_RUN_STALL | UMAC_RUN_STALL)
+#define XMAC_OCD_HALT_ON_RESET \
+       (LMAC_OCD_HALT_ON_RESET | SMAC_OCD_HALT_ON_RESET | UMAC_OCD_HALT_ON_RESET)
+#define XMAC_DEBUG_ENABLE \
+       (LMAC_DEBUG_ENABLE | SMAC_DEBUG_ENABLE | UMAC_DEBUG_ENABLE)
+
+/* Macro to read a platform register */
+#define REG_PL_RD(addr) le32_to_cpu(*(volatile __le32 *)(addr))
+
+/* Macro to write a platform register */
+#define REG_PL_WR(addr, value) ((*(volatile __le32 *)(addr)) = cpu_to_le32(value))
+
+#define CL_BAR_REG_READ(chip, reg) \
+       le32_to_cpu((__force __le32)readl((chip)->pci_bar0_virt_addr + (reg)))
+
+#define CL_BAR_REG_WRITE(chip, reg, val) \
+       writel((__force u32)cpu_to_le32(val), (chip)->pci_bar0_virt_addr + (reg))
+
+static inline u32 get_actual_reg(struct cl_hw *cl_hw, u32 reg)
+{
+       if ((reg & 0x00ff0000) == REG_MAC_HW_BASE_ADDR)
+               return cl_hw->mac_hw_regs_offset + reg;
+
+       if ((reg & 0x00f00000) == REG_MACDSP_API_BASE_ADDR)
+               return cl_hw->phy_regs_offset + reg;
+
+       return reg;
+}
+
+static inline u32 cl_reg_read(struct cl_hw *cl_hw, u32 reg)
+{
+       u32 actual_reg = get_actual_reg(cl_hw, reg);
+       u32 val = 0;
+
+       if (actual_reg == (u32)(-1))
+               return 0xff;
+
+       val = REG_PL_RD(cl_hw->chip->pci_bar0_virt_addr + actual_reg);
+       CL_REG_DBG(cl_hw, "reg=0x%x, val=0x%x\n", actual_reg, val);
+       return val;
+}
+
+static inline void cl_reg_write_direct(struct cl_hw *cl_hw, u32 reg, u32 val)
+{
+       u32 actual_reg = get_actual_reg(cl_hw, reg);
+
+       if (actual_reg == (u32)(-1))
+               return;
+
+       CL_REG_DBG(cl_hw, "reg=0x%x, val=0x%x\n", actual_reg, val);
+       REG_PL_WR(cl_hw->chip->pci_bar0_virt_addr + actual_reg, val);
+}
+
+#define BASE_ADDR(reg) ((ptrdiff_t)(reg) & 0x00fff000)
+
+static inline bool should_send_msg(struct cl_hw *cl_hw, u32 reg)
+{
+       /*
+        * Check in what cases we should send a message to the firmware,
+        * and in what cases we should write directly.
+        */
+       if (!cl_hw->fw_active)
+               return false;
+
+       return ((BASE_ADDR(reg) == REG_RIU_BASE_ADDR) ||
+               (BASE_ADDR(reg) == REG_MAC_HW_BASE_ADDR));
+}
+
+static inline int cl_reg_write(struct cl_hw *cl_hw, u32 reg, u32 val)
+{
+       u32 actual_reg = get_actual_reg(cl_hw, reg);
+       int ret = 0;
+
+       if (actual_reg == (u32)(-1))
+               return -1;
+
+       if (should_send_msg(cl_hw, reg)) {
+               CL_REG_DBG(cl_hw, "calling cl_msg_tx_reg_write: reg=0x%x, val=0x%x\n",
+                          actual_reg, val);
+               cl_msg_tx_reg_write(cl_hw, (XTENSA_PIF_BASE_ADDR + actual_reg), val, U32_MAX);
+       } else {
+               CL_REG_DBG(cl_hw, "reg=0x%x, val=0x%x\n", actual_reg, val);
+               REG_PL_WR((cl_hw->chip->pci_bar0_virt_addr + actual_reg), val);
+       }
+
+       return ret;
+}
+
+static inline int cl_reg_write_mask(struct cl_hw *cl_hw, u32 reg, u32 val, u32 mask)
+{
+       u32 actual_reg = get_actual_reg(cl_hw, reg);
+       int ret = 0;
+
+       if (actual_reg == (u32)(-1))
+               return -1;
+
+       if (should_send_msg(cl_hw, reg)) {
+               CL_REG_DBG(cl_hw, "calling cl_msg_tx_reg_write: reg=0x%x, val=0x%x, mask=0x%x\n",
+                          actual_reg, val, mask);
+               cl_msg_tx_reg_write(cl_hw, (XTENSA_PIF_BASE_ADDR + actual_reg), val, mask);
+       } else {
+               u32 reg_rd = REG_PL_RD(cl_hw->chip->pci_bar0_virt_addr + actual_reg);
+               u32 val_write = ((reg_rd & ~mask) | (val & mask));
+
+               CL_REG_DBG(cl_hw, "reg=0x%x, mask=0x%x, val=0x%x\n", actual_reg, mask, val_write);
+               REG_PL_WR(cl_hw->chip->pci_bar0_virt_addr + actual_reg, val_write);
+       }
+
+       return ret;
+}
+
+static inline void cl_reg_write_chip(struct cl_chip *chip, u32 reg, u32 val)
+{
+       CL_REG_DBG_CHIP(chip, "reg=0x%x, val=0x%x\n", reg, val);
+       REG_PL_WR(chip->pci_bar0_virt_addr + reg, val);
+}
+
+static inline u32 cl_reg_read_chip(struct cl_chip *chip, u32 reg)
+{
+       u32 val = 0;
+
+       val = REG_PL_RD(chip->pci_bar0_virt_addr + reg);
+
+       CL_REG_DBG_CHIP(chip, "reg=0x%x, val=0x%x\n", reg, val);
+       return val;
+}
+
+#endif /* CL_REG_ACCESS_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.
________________________________


^ permalink raw reply related	[flat|nested] 262+ messages in thread

* [RFC v1 149/256] cl8k: add reg/reg_cli.c
  2021-06-17 15:58 [RFC v1 000/256] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (147 preceding siblings ...)
  2021-06-17 16:00 ` [RFC v1 148/256] cl8k: add reg/reg_access.h viktor.barna
@ 2021-06-17 16:00 ` viktor.barna
  2021-06-17 16:00 ` [RFC v1 150/256] cl8k: add reg/reg_cli.h viktor.barna
                   ` (108 subsequent siblings)
  257 siblings, 0 replies; 262+ messages in thread
From: viktor.barna @ 2021-06-17 16:00 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Oleksandr Savchenko, Shay Bar, Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

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

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 .../net/wireless/celeno/cl8k/reg/reg_cli.c    | 277 ++++++++++++++++++
 1 file changed, 277 insertions(+)
 create mode 100644 drivers/net/wireless/celeno/cl8k/reg/reg_cli.c

diff --git a/drivers/net/wireless/celeno/cl8k/reg/reg_cli.c b/drivers/net/wireless/celeno/cl8k/reg/reg_cli.c
new file mode 100644
index 000000000000..2293b09c0da9
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/reg/reg_cli.c
@@ -0,0 +1,277 @@
+// SPDX-License-Identifier: MIT
+/* Copyright(c) 2019-2021, Celeno Communications Ltd. */
+
+#include "reg/reg_cli.h"
+#include "reg/reg_access.h"
+#include "reg/reg_modem_gcu.h"
+
+/*
+ * iwcl command to read registers and write to registers:
+ * iwcl <iface> cecli reg.-r.<reg_addr>
+ * iwcl <iface> cecli reg.-w.<reg_addr>.<reg_value>
+ * iwcl <iface> cecli reg.-m.<reg_addr>.<reg_value>.<reg_mask>
+ * iwcl <iface> cecli reg.-x.<type>.<offset>.<value>
+ * iwcl <iface> cecli reg.-y.<type>.<offset>
+ * iwcl <iface> cecli reg.-z.<type>.<offset>.<value>.<mask>
+ * reg_value should not include PCI base address
+ * The advantage of using iwcl command instead of mem command is
+ * that with using the iwcl command the relevant registers will
+ * be added to the recovery procedure.
+ */
+
+static int cl_reg_cli_write_mask(struct cl_hw *cl_hw, u32 address, u32 value, u32 mask)
+{
+       char reply_str[7] = {0};
+       u16 reply_strlen = 0;
+       int ret = cl_reg_write_mask(cl_hw, address, value, mask);
+
+       cl_dbg_verbose(cl_hw, "WRITE: Address = 0x%x, Value = 0x%x, Mask = 0x%x\n",
+                      address, value, mask);
+       reply_strlen = snprintf(&reply_str[0], sizeof(reply_str), "ret=%d", ret);
+
+       return cl_vendor_reply(cl_hw, reply_str, reply_strlen);
+}
+
+static int cl_reg_cli_read(struct cl_hw *cl_hw, u32 address)
+{
+       u32 value = cl_reg_read(cl_hw, address);
+       char reply_str[11] = {0};
+       u16 reply_strlen = 0;
+
+       reply_strlen = snprintf(&reply_str[0], sizeof(reply_str), "0x%08x", value);
+
+       return cl_vendor_reply(cl_hw, reply_str, reply_strlen);
+}
+
+static void cl_reg_cli_read_block(struct cl_hw *cl_hw, u32 first_address, u32 last_address)
+{
+       u32 address = first_address;
+       u32 value;
+
+       if ((first_address & 0x3) != 0) {
+               pr_err("Invalid first address - 0x%x\n", first_address);
+               return;
+       }
+
+       if ((last_address & 0x3) != 0) {
+               pr_err("Invalid last address - 0x%x\n", last_address);
+               return;
+       }
+
+       if (first_address > last_address) {
+               pr_err("Invalid addresses - first [0x%x] > last [0x%x]\n",
+                      first_address, last_address);
+               return;
+       }
+
+       pr_debug("-------------------------\n");
+       pr_debug("| Address  | Value      |\n");
+       pr_debug("|----------+------------|\n");
+
+       while (address <= last_address) {
+               value = cl_reg_read(cl_hw, address);
+               pr_debug("| 0x%06x | 0x%08x |\n", address, value);
+               address += 4;
+       }
+
+       pr_debug("-------------------------\n");
+}
+
+static int cl_reg_cli_write(struct cl_hw *cl_hw, u32 address, u32 value)
+{
+       char reply_str[7] = {0};
+       u16 reply_strlen = 0;
+       int ret = cl_reg_write(cl_hw, address, value);
+
+       cl_dbg_verbose(cl_hw, "WRITE: Address = 0x%x, Value = 0x%x\n", address, value);
+       reply_strlen = snprintf(&reply_str[0], sizeof(reply_str), "ret=%d", ret);
+
+       return cl_vendor_reply(cl_hw, reply_str, reply_strlen);
+}
+
+static int cl_reg_cli_write_type(struct cl_hw *cl_hw, u32 type, u32 offset, u32 value)
+{
+       if (type == 0) /* GCU */
+               cl_reg_write_direct(cl_hw, REG_MODEM_GCU_BASE_ADDR + offset, value);
+       else /* RIU */
+               cl_reg_write_direct(cl_hw, REG_RIU_BASE_ADDR + offset, value);
+
+       return 0;
+}
+
+static int cl_reg_cli_read_type(struct cl_hw *cl_hw, u32 type, u32 offset)
+{
+       u32 base = (type == 0) ? REG_MODEM_GCU_BASE_ADDR : REG_RIU_BASE_ADDR;
+
+       return cl_reg_cli_read(cl_hw, base + offset);
+}
+
+static int cl_reg_cli_write_type_mask(struct cl_hw *cl_hw, u32 type, u32 offset,
+                                     u32 value, u32 mask)
+{
+       if (type == 0) /* GCU */
+               cl_reg_write_mask(cl_hw, REG_MODEM_GCU_BASE_ADDR + offset, value, mask);
+       else /* RIU */
+               cl_reg_write_mask(cl_hw, REG_RIU_BASE_ADDR + offset, value, mask);
+
+       return 0;
+}
+
+static int cl_reg_cli_set_debug(struct cl_hw *cl_hw, bool enable)
+{
+       if (enable) {
+               cl_hw->reg_dbg = true;
+               cl_hw->chip->reg_dbg |= (1 << cl_hw->tcv_idx);
+       } else {
+               cl_hw->reg_dbg = false;
+               cl_hw->chip->reg_dbg &= ~(1 << cl_hw->tcv_idx);
+       }
+
+       return 0;
+}
+
+static int cl_reg_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,
+                "reg usage:\n"
+                "-d : Set debug [0:Disable|1:Enable]\n"
+                "-m : Write masked value to address [address].[value].[mask]\n"
+                "-r : Read address [address]\n"
+                "-s : Read block [first address].[last address]\n"
+                "-w : Write value to address [address].[value]\n"
+                "-x : Write type [0:GCU|1:RIU][offset].[value]\n"
+                "-y : Read type [0:GCU|1:RIU][offset]\n"
+                "-z : Write type mask [0:GCU|1:RIU][offset].[value].[mask]\n");
+
+       err = cl_vendor_reply(cl_hw, buf, strlen(buf));
+       kfree(buf);
+
+       return err;
+}
+
+int cl_reg_cli(struct cl_hw *cl_hw, struct cli_params *cli_params)
+{
+       u32 expected_params = 0;
+       bool set_debug = false;
+       bool reg_write_mask = false;
+       bool reg_read = false;
+       bool reg_read_block = false;
+       bool reg_write = false;
+       bool reg_write_type = false;
+       bool reg_read_type = false;
+       bool reg_write_type_mask = false;
+
+       switch (cli_params->option) {
+       case 'd':
+               set_debug = true;
+               expected_params = 1;
+               break;
+       case 'm':
+               reg_write_mask = true;
+               expected_params = 3;
+               break;
+       case 'r':
+               reg_read = true;
+               expected_params = 1;
+               break;
+       case 's':
+               reg_read_block = true;
+               expected_params = 2;
+               break;
+       case 'w':
+               reg_write = true;
+               expected_params = 2;
+               break;
+       case 'x':
+               reg_write_type = true;
+               expected_params = 3;
+               break;
+       case 'y':
+               reg_read_type = true;
+               expected_params = 2;
+               break;
+       case 'z':
+               reg_write_type_mask = true;
+               expected_params = 4;
+               break;
+       case '?':
+               return cl_reg_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 (set_debug) {
+               u32 enable = cli_params->params[0];
+
+               return cl_reg_cli_set_debug(cl_hw, enable);
+       }
+
+       if (reg_write_mask) {
+               u32 address = cli_params->params[0];
+               u32 value = cli_params->params[1];
+               u32 mask = cli_params->params[2];
+
+               return cl_reg_cli_write_mask(cl_hw, address, value, mask);
+       }
+
+       if (reg_read) {
+               u32 address = cli_params->params[0];
+
+               return cl_reg_cli_read(cl_hw, address);
+       }
+
+       if (reg_read_block) {
+               u32 first_address = cli_params->params[0];
+               u32 last_address = cli_params->params[1];
+
+               cl_reg_cli_read_block(cl_hw, first_address, last_address);
+               return 0;
+       }
+
+       if (reg_write) {
+               u32 address = cli_params->params[0];
+               u32 value = cli_params->params[1];
+
+               return cl_reg_cli_write(cl_hw, address, value);
+       }
+
+       if (reg_write_type) {
+               u32 type = cli_params->params[0];
+               u32 offset = cli_params->params[1];
+               u32 value = cli_params->params[2];
+
+               return cl_reg_cli_write_type(cl_hw, type, offset, value);
+       }
+
+       if (reg_read_type) {
+               u32 type = cli_params->params[0];
+               u32 offset = cli_params->params[1];
+
+               return cl_reg_cli_read_type(cl_hw, type, offset);
+       }
+
+       if (reg_write_type_mask) {
+               u32 type = cli_params->params[0];
+               u32 offset = cli_params->params[1];
+               u32 value = cli_params->params[2];
+               u32 mask = cli_params->params[3];
+
+               return cl_reg_cli_write_type_mask(cl_hw, type, offset, value, mask);
+       }
+
+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.
________________________________


^ permalink raw reply related	[flat|nested] 262+ messages in thread

* [RFC v1 150/256] cl8k: add reg/reg_cli.h
  2021-06-17 15:58 [RFC v1 000/256] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (148 preceding siblings ...)
  2021-06-17 16:00 ` [RFC v1 149/256] cl8k: add reg/reg_cli.c viktor.barna
@ 2021-06-17 16:00 ` viktor.barna
  2021-06-17 16:00 ` [RFC v1 151/256] cl8k: add reg/reg_cmu.h viktor.barna
                   ` (107 subsequent siblings)
  257 siblings, 0 replies; 262+ messages in thread
From: viktor.barna @ 2021-06-17 16:00 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Oleksandr Savchenko, Shay Bar, Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

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

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 drivers/net/wireless/celeno/cl8k/reg/reg_cli.h | 11 +++++++++++
 1 file changed, 11 insertions(+)
 create mode 100644 drivers/net/wireless/celeno/cl8k/reg/reg_cli.h

diff --git a/drivers/net/wireless/celeno/cl8k/reg/reg_cli.h b/drivers/net/wireless/celeno/cl8k/reg/reg_cli.h
new file mode 100644
index 000000000000..4a77dca136d7
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/reg/reg_cli.h
@@ -0,0 +1,11 @@
+/* SPDX-License-Identifier: MIT */
+/* Copyright(c) 2019-2021, Celeno Communications Ltd. */
+
+#ifndef CL_REG_CLI_H
+#define CL_REG_CLI_H
+
+#include "hw.h"
+
+int cl_reg_cli(struct cl_hw *cl_hw, struct cli_params *cli_params);
+
+#endif /* CL_REG_CLI_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.
________________________________


^ permalink raw reply related	[flat|nested] 262+ messages in thread

* [RFC v1 151/256] cl8k: add reg/reg_cmu.h
  2021-06-17 15:58 [RFC v1 000/256] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (149 preceding siblings ...)
  2021-06-17 16:00 ` [RFC v1 150/256] cl8k: add reg/reg_cli.h viktor.barna
@ 2021-06-17 16:00 ` viktor.barna
  2021-06-17 16:00 ` [RFC v1 152/256] cl8k: add reg/reg_fem.h viktor.barna
                   ` (106 subsequent siblings)
  257 siblings, 0 replies; 262+ messages in thread
From: viktor.barna @ 2021-06-17 16:00 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Oleksandr Savchenko, Shay Bar, Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

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

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 .../net/wireless/celeno/cl8k/reg/reg_cmu.h    | 379 ++++++++++++++++++
 1 file changed, 379 insertions(+)
 create mode 100644 drivers/net/wireless/celeno/cl8k/reg/reg_cmu.h

diff --git a/drivers/net/wireless/celeno/cl8k/reg/reg_cmu.h b/drivers/net/wireless/celeno/cl8k/reg/reg_cmu.h
new file mode 100644
index 000000000000..59428bf81e20
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/reg/reg_cmu.h
@@ -0,0 +1,379 @@
+/* SPDX-License-Identifier: MIT */
+/* Copyright(c) 2019-2021, Celeno Communications Ltd. */
+
+#ifndef CL_REG_CMU_H
+#define CL_REG_CMU_H
+
+#include <linux/types.h>
+#include "reg/reg_access.h"
+#include "chip.h"
+
+#define REG_CMU_BASE_ADDR 0x007C6000
+
+/*
+ * @brief CMU_CLK_EN register definition
+ * <pre>
+ *   Bits           Field Name   Reset Value
+ *  -----   ------------------   -----------
+ *    31    spare_afe_gnrl_en         0
+ *    30    spare_sys_gnrl_en         0
+ *    27    spare_riu44_clk_en        0
+ *    26    spare_riu_clk_en          0
+ *    25    spare_riu2x_clk_en        0
+ *    24    spare_riu4x_clk_en        0
+ *    23    spare_phy_clk_en          0
+ *    22    spare_phy2x_clk_en        0
+ *    21    spare_sysx_clk_en         0
+ *    20    spare_sys2x_clk_en        0
+ *    19    ricu_clk_en               0
+ *    05    smac_proc_clk_en          1
+ *    04    umac_proc_clk_en          1
+ *    03    lmac_proc_clk_en          1
+ * </pre>
+ */
+#define CMU_CLK_EN_ADDR        (REG_CMU_BASE_ADDR + 0x00000000)
+#define CMU_CLK_EN_OFFSET      0x00000000
+#define CMU_CLK_EN_INDEX       0x00000000
+#define CMU_CLK_EN_RESET       0x00000038
+
+/* Field definitions */
+#define CMU_SPARE_AFE_GNRL_EN_BIT           ((u32)0x80000000)
+#define CMU_SPARE_AFE_GNRL_EN_POS           31
+#define CMU_SPARE_SYS_GNRL_EN_BIT           ((u32)0x40000000)
+#define CMU_SPARE_SYS_GNRL_EN_POS           30
+#define CMU_SPARE_RIU_44_CLK_EN_BIT         ((u32)0x08000000)
+#define CMU_SPARE_RIU_44_CLK_EN_POS         27
+#define CMU_SPARE_RIU_CLK_EN_BIT            ((u32)0x04000000)
+#define CMU_SPARE_RIU_CLK_EN_POS            26
+#define CMU_SPARE_RIU_2_X_CLK_EN_BIT        ((u32)0x02000000)
+#define CMU_SPARE_RIU_2_X_CLK_EN_POS        25
+#define CMU_SPARE_RIU_4_X_CLK_EN_BIT        ((u32)0x01000000)
+#define CMU_SPARE_RIU_4_X_CLK_EN_POS        24
+#define CMU_SPARE_PHY_CLK_EN_BIT            ((u32)0x00800000)
+#define CMU_SPARE_PHY_CLK_EN_POS            23
+#define CMU_SPARE_PHY_2_X_CLK_EN_BIT        ((u32)0x00400000)
+#define CMU_SPARE_PHY_2_X_CLK_EN_POS        22
+#define CMU_SPARE_SYSX_CLK_EN_BIT           ((u32)0x00200000)
+#define CMU_SPARE_SYSX_CLK_EN_POS           21
+#define CMU_SPARE_SYS_2_X_CLK_EN_BIT        ((u32)0x00100000)
+#define CMU_SPARE_SYS_2_X_CLK_EN_POS        20
+#define CMU_RICU_CLK_EN_BIT                 ((u32)0x00080000)
+#define CMU_RICU_CLK_EN_POS                 19
+#define CMU_SMAC_PROC_CLK_EN_BIT            ((u32)0x00000020)
+#define CMU_SMAC_PROC_CLK_EN_POS            5
+#define CMU_UMAC_PROC_CLK_EN_BIT            ((u32)0x00000010)
+#define CMU_UMAC_PROC_CLK_EN_POS            4
+#define CMU_LMAC_PROC_CLK_EN_BIT            ((u32)0x00000008)
+#define CMU_LMAC_PROC_CLK_EN_POS            3
+
+#define CMU_MAC_ALL_CLK_EN \
+       (CMU_RICU_CLK_EN_BIT | \
+        CMU_SMAC_PROC_CLK_EN_BIT | \
+        CMU_UMAC_PROC_CLK_EN_BIT | \
+        CMU_LMAC_PROC_CLK_EN_BIT)
+
+static inline void cmu_clk_en_set(struct cl_chip *chip, u32 value)
+{
+       cl_reg_write_chip(chip, CMU_CLK_EN_ADDR, value);
+}
+
+/*
+ * @brief CMU_PHY_0_CLK_EN register definition
+ * <pre>
+ *   Bits           Field Name   Reset Value
+ *  -----   ------------------   -----------
+ *    02    ceva0_clk_en              0
+ *    01    phy0_apb_clk_en           0
+ *    00    phy0_main_clk_en          0
+ * </pre>
+ */
+#define CMU_PHY_0_CLK_EN_ADDR        (REG_CMU_BASE_ADDR + 0x00000004)
+#define CMU_PHY_0_CLK_EN_OFFSET      0x00000004
+#define CMU_PHY_0_CLK_EN_INDEX       0x00000001
+#define CMU_PHY_0_CLK_EN_RESET       0x00000000
+
+static inline void cmu_phy_0_clk_en_set(struct cl_chip *chip, u32 value)
+{
+       cl_reg_write_chip(chip, CMU_PHY_0_CLK_EN_ADDR, value);
+}
+
+/* Field definitions */
+#define CMU_CEVA_0_CLK_EN_BIT               ((u32)0x00000004)
+#define CMU_CEVA_0_CLK_EN_POS               2
+#define CMU_PHY_0_APB_CLK_EN_BIT            ((u32)0x00000002)
+#define CMU_PHY_0_APB_CLK_EN_POS            1
+#define CMU_PHY_0_MAIN_CLK_EN_BIT           ((u32)0x00000001)
+#define CMU_PHY_0_MAIN_CLK_EN_POS           0
+
+#define CMU_PHY0_CLK_EN \
+       (CMU_CEVA_0_CLK_EN_BIT | \
+        CMU_PHY_0_APB_CLK_EN_BIT | \
+        CMU_PHY_0_MAIN_CLK_EN_BIT)
+
+static inline void cmu_phy_0_clk_en_pack(struct cl_chip *chip, u8 ceva0clken, u8 phy0apbclken,
+                                        u8 phy0mainclken)
+{
+       ASSERT_ERR_CHIP((((u32)ceva0clken << 2) & ~((u32)0x00000004)) == 0);
+       ASSERT_ERR_CHIP((((u32)phy0apbclken << 1) & ~((u32)0x00000002)) == 0);
+       ASSERT_ERR_CHIP((((u32)phy0mainclken << 0) & ~((u32)0x00000001)) == 0);
+       cl_reg_write_chip(chip, CMU_PHY_0_CLK_EN_ADDR, ((u32)ceva0clken << 2) |
+                         ((u32)phy0apbclken << 1) | ((u32)phy0mainclken << 0));
+}
+
+static inline void cmu_phy_0_clk_en_ceva_0_clk_en_setf(struct cl_chip *chip, u8 ceva0clken)
+{
+       ASSERT_ERR_CHIP((((u32)ceva0clken << 2) & ~((u32)0x00000004)) == 0);
+       cl_reg_write_chip(chip, CMU_PHY_0_CLK_EN_ADDR,
+                         (cl_reg_read_chip(chip, CMU_PHY_0_CLK_EN_ADDR) & ~((u32)0x00000004)) | ((u32)ceva0clken << 2));
+}
+
+static inline void cmu_phy_0_clk_en_phy_0_apb_clk_en_setf(struct cl_chip *chip, u8 phy0apbclken)
+{
+       ASSERT_ERR_CHIP((((u32)phy0apbclken << 1) & ~((u32)0x00000002)) == 0);
+       cl_reg_write_chip(chip, CMU_PHY_0_CLK_EN_ADDR,
+                         (cl_reg_read_chip(chip, CMU_PHY_0_CLK_EN_ADDR) & ~((u32)0x00000002)) | ((u32)phy0apbclken << 1));
+}
+
+/*
+ * @brief CMU_PHY_1_CLK_EN register definition
+ * <pre>
+ *   Bits           Field Name   Reset Value
+ *  -----   ------------------   -----------
+ *    02    ceva1_clk_en              0
+ *    01    phy1_apb_clk_en           0
+ *    00    phy1_main_clk_en          0
+ * </pre>
+ */
+#define CMU_PHY_1_CLK_EN_ADDR        (REG_CMU_BASE_ADDR + 0x00000008)
+#define CMU_PHY_1_CLK_EN_OFFSET      0x00000008
+#define CMU_PHY_1_CLK_EN_INDEX       0x00000002
+#define CMU_PHY_1_CLK_EN_RESET       0x00000000
+
+static inline void cmu_phy_1_clk_en_set(struct cl_chip *chip, u32 value)
+{
+       cl_reg_write_chip(chip, CMU_PHY_1_CLK_EN_ADDR, value);
+}
+
+/* Field definitions */
+#define CMU_CEVA_1_CLK_EN_BIT               ((u32)0x00000004)
+#define CMU_CEVA_1_CLK_EN_POS               2
+#define CMU_PHY_1_APB_CLK_EN_BIT            ((u32)0x00000002)
+#define CMU_PHY_1_APB_CLK_EN_POS            1
+#define CMU_PHY_1_MAIN_CLK_EN_BIT           ((u32)0x00000001)
+#define CMU_PHY_1_MAIN_CLK_EN_POS           0
+
+#define CMU_PHY1_CLK_EN \
+       (CMU_CEVA_1_CLK_EN_BIT | \
+        CMU_PHY_1_APB_CLK_EN_BIT | \
+        CMU_PHY_1_MAIN_CLK_EN_BIT)
+
+static inline void cmu_phy_1_clk_en_pack(struct cl_chip *chip, u8 ceva1clken, u8 phy1apbclken,
+                                        u8 phy1mainclken)
+{
+       ASSERT_ERR_CHIP((((u32)ceva1clken << 2) & ~((u32)0x00000004)) == 0);
+       ASSERT_ERR_CHIP((((u32)phy1apbclken << 1) & ~((u32)0x00000002)) == 0);
+       ASSERT_ERR_CHIP((((u32)phy1mainclken << 0) & ~((u32)0x00000001)) == 0);
+       cl_reg_write_chip(chip, CMU_PHY_1_CLK_EN_ADDR, ((u32)ceva1clken << 2) |
+                         ((u32)phy1apbclken << 1) | ((u32)phy1mainclken << 0));
+}
+
+static inline void cmu_phy_1_clk_en_ceva_1_clk_en_setf(struct cl_chip *chip, u8 ceva1clken)
+{
+       ASSERT_ERR_CHIP((((u32)ceva1clken << 2) & ~((u32)0x00000004)) == 0);
+       cl_reg_write_chip(chip, CMU_PHY_1_CLK_EN_ADDR,
+                         (cl_reg_read_chip(chip, CMU_PHY_1_CLK_EN_ADDR) & ~((u32)0x00000004)) | ((u32)ceva1clken << 2));
+}
+
+static inline void cmu_phy_1_clk_en_phy_1_apb_clk_en_setf(struct cl_chip *chip, u8 phy1apbclken)
+{
+       ASSERT_ERR_CHIP((((u32)phy1apbclken << 1) & ~((u32)0x00000002)) == 0);
+       cl_reg_write_chip(chip, CMU_PHY_1_CLK_EN_ADDR,
+                         (cl_reg_read_chip(chip, CMU_PHY_1_CLK_EN_ADDR) & ~((u32)0x00000002)) | ((u32)phy1apbclken << 1));
+}
+
+/*
+ * @brief CMU_CONTROL register definition
+ * <pre>
+ *   Bits           Field Name   Reset Value
+ *  -----   ------------------   -----------
+ *    00    gl_mux_sel                0
+ * </pre>
+ */
+#define CMU_CONTROL_ADDR        (REG_CMU_BASE_ADDR + 0x0000000C)
+#define CMU_CONTROL_OFFSET      0x0000000C
+#define CMU_CONTROL_INDEX       0x00000003
+#define CMU_CONTROL_RESET       0x00000000
+
+static inline void cmu_control_gl_mux_sel_setf(struct cl_chip *chip, u8 glmuxsel)
+{
+       ASSERT_ERR_CHIP((((u32)glmuxsel << 0) & ~((u32)0x00000001)) == 0);
+       cl_reg_write_chip(chip, CMU_CONTROL_ADDR, (u32)glmuxsel << 0);
+}
+
+/*
+ * @brief CMU_RST register definition
+ * <pre>
+ *   Bits           Field Name   Reset Value
+ *  -----   ------------------   -----------
+ *    18    spare_riu44_reset_n       0
+ *    17    spare_modem_reset_n       0
+ *    16    spare_sys_reset_n         0
+ *    15    n_RICURst                 1
+ * </pre>
+ */
+#define CMU_RST_ADDR        (REG_CMU_BASE_ADDR + 0x00000010)
+#define CMU_RST_OFFSET      0x00000010
+#define CMU_RST_INDEX       0x00000004
+#define CMU_RST_RESET       0x0000FF80
+
+static inline void cmu_rst_n_ricurst_setf(struct cl_chip *chip, u8 nricurst)
+{
+       ASSERT_ERR_CHIP((((u32)nricurst << 15) & ~((u32)0x00008000)) == 0);
+       cl_reg_write_chip(chip, CMU_RST_ADDR,
+                         (cl_reg_read_chip(chip, CMU_RST_ADDR) & ~((u32)0x00008000)) | ((u32)nricurst << 15));
+}
+
+/*
+ * @brief CMU_PHY_0_RST register definition
+ * <pre>
+ *   Bits           Field Name   Reset Value
+ *  -----   ------------------   -----------
+ *    03    ceva0_global_rst_n        1
+ *    02    mpif0_rst_n               1
+ *    01    phy0_preset_n             1
+ *    00    phy0_rst_n                1
+ * </pre>
+ */
+#define CMU_PHY_0_RST_ADDR        (REG_CMU_BASE_ADDR + 0x00000014)
+#define CMU_PHY_0_RST_OFFSET      0x00000014
+#define CMU_PHY_0_RST_INDEX       0x00000005
+#define CMU_PHY_0_RST_RESET       0x0000000F
+
+static inline void cmu_phy_0_rst_set(struct cl_chip *chip, u32 value)
+{
+       cl_reg_write_chip(chip, CMU_PHY_0_RST_ADDR, value);
+}
+
+/* Field definitions */
+#define CMU_CEVA_0_GLOBAL_RST_N_BIT         ((u32)0x00000008)
+#define CMU_CEVA_0_GLOBAL_RST_N_POS         3
+#define CMU_MPIF_0_RST_N_BIT                ((u32)0x00000004)
+#define CMU_MPIF_0_RST_N_POS                2
+#define CMU_PHY_0_PRESET_N_BIT              ((u32)0x00000002)
+#define CMU_PHY_0_PRESET_N_POS              1
+#define CMU_PHY_0_RST_N_BIT                 ((u32)0x00000001)
+#define CMU_PHY_0_RST_N_POS                 0
+
+#define CMU_PHY0_RST_EN \
+       (CMU_PHY_0_PRESET_N_BIT | \
+        CMU_MPIF_0_RST_N_BIT | \
+        CMU_PHY_0_RST_N_BIT | \
+        CMU_CEVA_0_GLOBAL_RST_N_BIT)
+
+static inline void cmu_phy_0_rst_ceva_0_global_rst_n_setf(struct cl_chip *chip, u8 ceva0globalrstn)
+{
+       ASSERT_ERR_CHIP((((u32)ceva0globalrstn << 3) & ~((u32)0x00000008)) == 0);
+       cl_reg_write_chip(chip, CMU_PHY_0_RST_ADDR,
+                         (cl_reg_read_chip(chip, CMU_PHY_0_RST_ADDR) & ~((u32)0x00000008)) | ((u32)ceva0globalrstn << 3));
+}
+
+/*
+ * @brief CMU_PHY_1_RST register definition
+ * <pre>
+ *   Bits           Field Name   Reset Value
+ *  -----   ------------------   -----------
+ *    03    ceva1_global_rst_n        1
+ *    02    mpif1_rst_n               1
+ *    01    phy1_preset_n             1
+ *    00    phy1_rst_n                1
+ * </pre>
+ */
+#define CMU_PHY_1_RST_ADDR        (REG_CMU_BASE_ADDR + 0x00000018)
+#define CMU_PHY_1_RST_OFFSET      0x00000018
+#define CMU_PHY_1_RST_INDEX       0x00000006
+#define CMU_PHY_1_RST_RESET       0x0000000F
+
+static inline void cmu_phy_1_rst_set(struct cl_chip *chip, u32 value)
+{
+       cl_reg_write_chip(chip, CMU_PHY_1_RST_ADDR, value);
+}
+
+/* Field definitions */
+#define CMU_CEVA_1_GLOBAL_RST_N_BIT         ((u32)0x00000008)
+#define CMU_CEVA_1_GLOBAL_RST_N_POS         3
+#define CMU_MPIF_1_RST_N_BIT                ((u32)0x00000004)
+#define CMU_MPIF_1_RST_N_POS                2
+#define CMU_PHY_1_PRESET_N_BIT              ((u32)0x00000002)
+#define CMU_PHY_1_PRESET_N_POS              1
+#define CMU_PHY_1_RST_N_BIT                 ((u32)0x00000001)
+#define CMU_PHY_1_RST_N_POS                 0
+
+#define CMU_PHY1_RST_EN \
+       (CMU_PHY_1_PRESET_N_BIT | \
+        CMU_MPIF_1_RST_N_BIT | \
+        CMU_PHY_1_RST_N_BIT | \
+        CMU_CEVA_1_GLOBAL_RST_N_BIT)
+
+static inline void cmu_phy_1_rst_ceva_1_global_rst_n_setf(struct cl_chip *chip, u8 ceva1globalrstn)
+{
+       ASSERT_ERR_CHIP((((u32)ceva1globalrstn << 3) & ~((u32)0x00000008)) == 0);
+       cl_reg_write_chip(chip, CMU_PHY_1_RST_ADDR,
+                         (cl_reg_read_chip(chip, CMU_PHY_1_RST_ADDR) & ~((u32)0x00000008)) | ((u32)ceva1globalrstn << 3));
+}
+
+/*
+ * @brief CMU_PLL_1_STAT register definition
+ * <pre>
+ *   Bits           Field Name   Reset Value
+ *  -----   ------------------   -----------
+ *    31    pll_lock                  0
+ * </pre>
+ */
+#define CMU_PLL_1_STAT_ADDR        (REG_CMU_BASE_ADDR + 0x00000050)
+#define CMU_PLL_1_STAT_OFFSET      0x00000050
+#define CMU_PLL_1_STAT_INDEX       0x00000014
+#define CMU_PLL_1_STAT_RESET       0x00000000
+
+static inline u8 cmu_pll_1_stat_pll_lock_getf(struct cl_chip *chip)
+{
+       u32 local_val = cl_reg_read_chip(chip, CMU_PLL_1_STAT_ADDR);
+
+       ASSERT_ERR_CHIP((local_val & ~((u32)0x80000000)) == 0);
+       return (local_val >> 31);
+}
+
+/*
+ * @brief CMU_PHASE_SEL register definition
+ * <pre>
+ *   Bits           Field Name   Reset Value
+ *  -----   ------------------   -----------
+ *    20    gp_clk_phase_sel          1
+ *    19    dac_cdb_clk_phase_sel     0
+ *    18    adc_cdb_clk_phase_sel     0
+ *    17    dac_clk_phase_sel         0
+ *    16    adc_clk_phase_sel         0
+ * </pre>
+ */
+#define CMU_PHASE_SEL_ADDR        (REG_CMU_BASE_ADDR + 0x00000060)
+#define CMU_PHASE_SEL_OFFSET      0x00000060
+#define CMU_PHASE_SEL_INDEX       0x00000018
+#define CMU_PHASE_SEL_RESET       0x00100000
+
+static inline void cmu_phase_sel_set(struct cl_chip *chip, u32 value)
+{
+       cl_reg_write_chip(chip, CMU_PHASE_SEL_ADDR, value);
+}
+
+/* Field definitions */
+#define CMU_GP_CLK_PHASE_SEL_BIT            ((u32)0x00100000)
+#define CMU_GP_CLK_PHASE_SEL_POS            20
+#define CMU_DAC_CDB_CLK_PHASE_SEL_BIT       ((u32)0x00080000)
+#define CMU_DAC_CDB_CLK_PHASE_SEL_POS       19
+#define CMU_ADC_CDB_CLK_PHASE_SEL_BIT       ((u32)0x00040000)
+#define CMU_ADC_CDB_CLK_PHASE_SEL_POS       18
+#define CMU_DAC_CLK_PHASE_SEL_BIT           ((u32)0x00020000)
+#define CMU_DAC_CLK_PHASE_SEL_POS           17
+#define CMU_ADC_CLK_PHASE_SEL_BIT           ((u32)0x00010000)
+#define CMU_ADC_CLK_PHASE_SEL_POS           16
+
+#endif /* CL_REG_CMU_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.
________________________________


^ permalink raw reply related	[flat|nested] 262+ messages in thread

* [RFC v1 152/256] cl8k: add reg/reg_fem.h
  2021-06-17 15:58 [RFC v1 000/256] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (150 preceding siblings ...)
  2021-06-17 16:00 ` [RFC v1 151/256] cl8k: add reg/reg_cmu.h viktor.barna
@ 2021-06-17 16:00 ` viktor.barna
  2021-06-17 16:00 ` [RFC v1 153/256] cl8k: add reg/reg_io_ctrl.h viktor.barna
                   ` (105 subsequent siblings)
  257 siblings, 0 replies; 262+ messages in thread
From: viktor.barna @ 2021-06-17 16:00 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Oleksandr Savchenko, Shay Bar, Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

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

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 .../net/wireless/celeno/cl8k/reg/reg_fem.h    | 102 ++++++++++++++++++
 1 file changed, 102 insertions(+)
 create mode 100644 drivers/net/wireless/celeno/cl8k/reg/reg_fem.h

diff --git a/drivers/net/wireless/celeno/cl8k/reg/reg_fem.h b/drivers/net/wireless/celeno/cl8k/reg/reg_fem.h
new file mode 100644
index 000000000000..ab1aaae23782
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/reg/reg_fem.h
@@ -0,0 +1,102 @@
+/* SPDX-License-Identifier: MIT */
+/* Copyright(c) 2019-2021, Celeno Communications Ltd. */
+
+#ifndef CL_REG_FEM_H
+#define CL_REG_FEM_H
+
+#include "reg/reg_io_ctrl.h"
+
+struct cl_fem_lna_enable_gpio {
+       union {
+               u16 b0 : 1,
+                   b1 : 1,
+                   b2 : 1,
+                   b3 : 1,
+                   b4 : 1,
+                   b5 : 1,
+                   b6 : 1,
+                   b7 : 1,
+                   b8 : 1,
+                   b9 : 1,
+                   b10 : 1,
+                   b11 : 1,
+                   rsv : 4;
+               u16 val;
+       };
+};
+
+struct cl_fem_pa_enable_gpio {
+       union {
+               u16 b0 : 1,
+                   b1 : 1,
+                   b2 : 1,
+                   b3 : 1,
+                   b4 : 1,
+                   b5 : 1,
+                   b6 : 1,
+                   b7 : 1,
+                   b8 : 1,
+                   b9 : 1,
+                   b10 : 1,
+                   b11 : 1,
+                   rsv : 4;
+               u16 val;
+       };
+};
+
+struct cl_fem_rx_active_gpio {
+       union {
+               u8 b0 : 1,
+                  b1 : 1,
+                  b2 : 1,
+                  b3 : 1,
+                  b4 : 1,
+                  b5 : 1,
+                  b6 : 1,
+                  b7 : 1;
+               u8 val;
+       };
+};
+
+#define EXTRACT_OFF_LUT(lut) (((lut) >> 12) & 0x7)
+#define FEM_LUT_MASK         0x0777
+
+#define PA_ENABLE_POS  0
+#define LNA_ENABLE_POS 1
+#define RX_ACTIVE_POS  2
+#define GET_BIT(reg, pos) (((reg) >> (pos)) & 0x1)
+
+/*
+ * LNA_ENABLE
+ * IO_CTRL_LNA_ENABLE_0_GPIO_ENABLE_POS is used for all ioctl APIs -
+ * io_ctrl_lna_enable_0_set() ... io_ctrl_lna_enable_11_set()
+ * because all have the same value
+ */
+#define LNA_ENABLE_GPIO_VAL(val) \
+       (((u32)(val) << IO_CTRL_LNA_ENABLE_0_GPIO_ENABLE_POS) & \
+        IO_CTRL_LNA_ENABLE_0_GPIO_ENABLE_BIT)
+
+/* PA_ENABLE */
+#define PA_ENABLE_GPIO_VAL(val) \
+       (((u32)(val) << IO_CTRL_PA_ENABLE_0_GPIO_ENABLE_POS) & \
+        IO_CTRL_PA_ENABLE_0_GPIO_ENABLE_BIT)
+
+/* RX_ACTIVE */
+#define RX_ACTIVE_GPIO_VAL(val) \
+       (((u32)(val) << IO_CTRL_RX_ACTIVE_0_GPIO_ENABLE_POS) & \
+        IO_CTRL_RX_ACTIVE_0_GPIO_ENABLE_BIT)
+
+#define LNA_ENABLE_GPIO_OUT_CFG(val) \
+       (((1 << IO_CTRL_LNA_ENABLE_0_GPIO_ENABLE_POS) & IO_CTRL_LNA_ENABLE_0_GPIO_ENABLE_BIT) | \
+        ((1 << IO_CTRL_LNA_ENABLE_0_GPIO_OE_POS) & IO_CTRL_LNA_ENABLE_0_GPIO_OE_BIT) | \
+        (((u32)(val) << IO_CTRL_LNA_ENABLE_0_GPIO_OUT_POS) & IO_CTRL_LNA_ENABLE_0_GPIO_OUT_BIT))
+#define PA_ENABLE_GPIO_OUT_CFG(val) \
+        (((1 << IO_CTRL_PA_ENABLE_0_GPIO_ENABLE_POS) & IO_CTRL_PA_ENABLE_0_GPIO_ENABLE_BIT) | \
+         ((1 << IO_CTRL_PA_ENABLE_0_GPIO_OE_POS) & IO_CTRL_PA_ENABLE_0_GPIO_OE_BIT) | \
+         (((u32)(val) << IO_CTRL_PA_ENABLE_0_GPIO_OUT_POS) & IO_CTRL_PA_ENABLE_0_GPIO_OUT_BIT))
+#define RX_ACTIVE_GPIO_OUT_CFG(val) \
+         (((1 << IO_CTRL_RX_ACTIVE_0_GPIO_ENABLE_POS) & IO_CTRL_RX_ACTIVE_0_GPIO_ENABLE_BIT) | \
+          ((1 << IO_CTRL_RX_ACTIVE_0_GPIO_OE_POS) & IO_CTRL_RX_ACTIVE_0_GPIO_OE_BIT) | \
+          (((u32)(val) << IO_CTRL_RX_ACTIVE_0_GPIO_OUT_POS) & IO_CTRL_RX_ACTIVE_0_GPIO_OUT_BIT))
+
+#endif /* CL_REG_FEM_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.
________________________________


^ permalink raw reply related	[flat|nested] 262+ messages in thread

* [RFC v1 153/256] cl8k: add reg/reg_io_ctrl.h
  2021-06-17 15:58 [RFC v1 000/256] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (151 preceding siblings ...)
  2021-06-17 16:00 ` [RFC v1 152/256] cl8k: add reg/reg_fem.h viktor.barna
@ 2021-06-17 16:00 ` viktor.barna
  2021-06-17 16:00 ` [RFC v1 154/256] cl8k: add reg/reg_ipc.h viktor.barna
                   ` (104 subsequent siblings)
  257 siblings, 0 replies; 262+ messages in thread
From: viktor.barna @ 2021-06-17 16:00 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Oleksandr Savchenko, Shay Bar, Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

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

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 .../wireless/celeno/cl8k/reg/reg_io_ctrl.h    | 1223 +++++++++++++++++
 1 file changed, 1223 insertions(+)
 create mode 100644 drivers/net/wireless/celeno/cl8k/reg/reg_io_ctrl.h

diff --git a/drivers/net/wireless/celeno/cl8k/reg/reg_io_ctrl.h b/drivers/net/wireless/celeno/cl8k/reg/reg_io_ctrl.h
new file mode 100644
index 000000000000..190a7a98ebd3
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/reg/reg_io_ctrl.h
@@ -0,0 +1,1223 @@
+/* SPDX-License-Identifier: MIT */
+/* Copyright(c) 2019-2021, Celeno Communications Ltd. */
+
+#ifndef CL_REG_IO_CTRL_H
+#define CL_REG_IO_CTRL_H
+
+#include <linux/types.h>
+#include "reg/reg_access.h"
+#include "chip.h"
+
+#define REG_IO_CTRL_BASE_ADDR 0x007C7000
+
+/*
+ * @brief RX_ACTIVE_0 register definition
+ * <pre>
+ *  Bits           Field Name   Reset Value
+ * -----   ------------------   -----------
+ *   13    GPIO_IN                   1
+ *   12    GPIO_OUT                  0
+ *   11    GPIO_OE                   0
+ *   10    GPIO_ENABLE               1
+ *   09    input_enable              1
+ *   08    SLEW_RATE                 0
+ *   07:06 DRIVER_PULL_STATE         0x3
+ *   05:04 OUTPUT_PAD_STRENGTH       0x1
+ *   03    SCHMIT_TRIGER             1
+ *   02:00 MUX_SELECT                0x0
+ * </pre>
+ */
+#define IO_CTRL_RX_ACTIVE_0_ADDR        (REG_IO_CTRL_BASE_ADDR + 0x0000005C)
+#define IO_CTRL_RX_ACTIVE_0_OFFSET      0x0000005C
+#define IO_CTRL_RX_ACTIVE_0_INDEX       0x00000017
+#define IO_CTRL_RX_ACTIVE_0_RESET       0x000026D8
+
+static inline void io_ctrl_rx_active_0_set(struct cl_chip *chip, u32 value)
+{
+       cl_reg_write_chip(chip, IO_CTRL_RX_ACTIVE_0_ADDR, value);
+}
+
+/* Field definitions */
+#define IO_CTRL_RX_ACTIVE_0_GPIO_IN_BIT               ((u32)0x00002000)
+#define IO_CTRL_RX_ACTIVE_0_GPIO_IN_POS               13
+#define IO_CTRL_RX_ACTIVE_0_GPIO_OUT_BIT              ((u32)0x00001000)
+#define IO_CTRL_RX_ACTIVE_0_GPIO_OUT_POS              12
+#define IO_CTRL_RX_ACTIVE_0_GPIO_OE_BIT               ((u32)0x00000800)
+#define IO_CTRL_RX_ACTIVE_0_GPIO_OE_POS               11
+#define IO_CTRL_RX_ACTIVE_0_GPIO_ENABLE_BIT           ((u32)0x00000400)
+#define IO_CTRL_RX_ACTIVE_0_GPIO_ENABLE_POS           10
+#define IO_CTRL_RX_ACTIVE_0_INPUT_ENABLE_BIT          ((u32)0x00000200)
+#define IO_CTRL_RX_ACTIVE_0_INPUT_ENABLE_POS          9
+#define IO_CTRL_RX_ACTIVE_0_SLEW_RATE_BIT             ((u32)0x00000100)
+#define IO_CTRL_RX_ACTIVE_0_SLEW_RATE_POS             8
+#define IO_CTRL_RX_ACTIVE_0_DRIVER_PULL_STATE_MASK    ((u32)0x000000C0)
+#define IO_CTRL_RX_ACTIVE_0_DRIVER_PULL_STATE_LSB     6
+#define IO_CTRL_RX_ACTIVE_0_DRIVER_PULL_STATE_WIDTH   ((u32)0x00000002)
+#define IO_CTRL_RX_ACTIVE_0_OUTPUT_PAD_STRENGTH_MASK  ((u32)0x00000030)
+#define IO_CTRL_RX_ACTIVE_0_OUTPUT_PAD_STRENGTH_LSB   4
+#define IO_CTRL_RX_ACTIVE_0_OUTPUT_PAD_STRENGTH_WIDTH ((u32)0x00000002)
+#define IO_CTRL_RX_ACTIVE_0_SCHMIT_TRIGER_BIT         ((u32)0x00000008)
+#define IO_CTRL_RX_ACTIVE_0_SCHMIT_TRIGER_POS         3
+#define IO_CTRL_RX_ACTIVE_0_MUX_SELECT_MASK           ((u32)0x00000007)
+#define IO_CTRL_RX_ACTIVE_0_MUX_SELECT_LSB            0
+#define IO_CTRL_RX_ACTIVE_0_MUX_SELECT_WIDTH          ((u32)0x00000003)
+
+/*
+ * @brief RX_ACTIVE_1 register definition
+ * <pre>
+ *  Bits           Field Name   Reset Value
+ * -----   ------------------   -----------
+ *   13    GPIO_IN                   1
+ *   12    GPIO_OUT                  0
+ *   11    GPIO_OE                   0
+ *   10    GPIO_ENABLE               1
+ *   09    input_enable              1
+ *   08    SLEW_RATE                 0
+ *   07:06 DRIVER_PULL_STATE         0x3
+ *   05:04 OUTPUT_PAD_STRENGTH       0x1
+ *   03    SCHMIT_TRIGER             1
+ *   02:00 MUX_SELECT                0x0
+ * </pre>
+ */
+#define IO_CTRL_RX_ACTIVE_1_ADDR        (REG_IO_CTRL_BASE_ADDR + 0x00000060)
+#define IO_CTRL_RX_ACTIVE_1_OFFSET      0x00000060
+#define IO_CTRL_RX_ACTIVE_1_INDEX       0x00000018
+#define IO_CTRL_RX_ACTIVE_1_RESET       0x000026D8
+
+static inline void io_ctrl_rx_active_1_set(struct cl_chip *chip, u32 value)
+{
+       cl_reg_write_chip(chip, IO_CTRL_RX_ACTIVE_1_ADDR, value);
+}
+
+/*
+ * @brief RX_ACTIVE_2 register definition
+ * <pre>
+ *  Bits           Field Name   Reset Value
+ * -----   ------------------   -----------
+ *   13    GPIO_IN                   1
+ *   12    GPIO_OUT                  0
+ *   11    GPIO_OE                   0
+ *   10    GPIO_ENABLE               1
+ *   09    input_enable              1
+ *   08    SLEW_RATE                 0
+ *   07:06 DRIVER_PULL_STATE         0x3
+ *   05:04 OUTPUT_PAD_STRENGTH       0x1
+ *   03    SCHMIT_TRIGER             1
+ *   02:00 MUX_SELECT                0x0
+ * </pre>
+ */
+#define IO_CTRL_RX_ACTIVE_2_ADDR        (REG_IO_CTRL_BASE_ADDR + 0x00000064)
+#define IO_CTRL_RX_ACTIVE_2_OFFSET      0x00000064
+#define IO_CTRL_RX_ACTIVE_2_INDEX       0x00000019
+#define IO_CTRL_RX_ACTIVE_2_RESET       0x000026D8
+
+static inline void io_ctrl_rx_active_2_set(struct cl_chip *chip, u32 value)
+{
+       cl_reg_write_chip(chip, IO_CTRL_RX_ACTIVE_2_ADDR, value);
+}
+
+/*
+ * @brief RX_ACTIVE_3 register definition
+ * <pre>
+ *  Bits           Field Name   Reset Value
+ * -----   ------------------   -----------
+ *   13    GPIO_IN                   1
+ *   12    GPIO_OUT                  0
+ *   11    GPIO_OE                   0
+ *   10    GPIO_ENABLE               1
+ *   09    input_enable              1
+ *   08    SLEW_RATE                 0
+ *   07:06 DRIVER_PULL_STATE         0x3
+ *   05:04 OUTPUT_PAD_STRENGTH       0x1
+ *   03    SCHMIT_TRIGER             1
+ *   02:00 MUX_SELECT                0x0
+ * </pre>
+ */
+#define IO_CTRL_RX_ACTIVE_3_ADDR        (REG_IO_CTRL_BASE_ADDR + 0x00000068)
+#define IO_CTRL_RX_ACTIVE_3_OFFSET      0x00000068
+#define IO_CTRL_RX_ACTIVE_3_INDEX       0x0000001A
+#define IO_CTRL_RX_ACTIVE_3_RESET       0x000026D8
+
+static inline void io_ctrl_rx_active_3_set(struct cl_chip *chip, u32 value)
+{
+       cl_reg_write_chip(chip, IO_CTRL_RX_ACTIVE_3_ADDR, value);
+}
+
+/*
+ * @brief RX_ACTIVE_4 register definition
+ * <pre>
+ *  Bits           Field Name   Reset Value
+ * -----   ------------------   -----------
+ *   13    GPIO_IN                   1
+ *   12    GPIO_OUT                  0
+ *   11    GPIO_OE                   0
+ *   10    GPIO_ENABLE               1
+ *   09    input_enable              1
+ *   08    SLEW_RATE                 0
+ *   07:06 DRIVER_PULL_STATE         0x3
+ *   05:04 OUTPUT_PAD_STRENGTH       0x1
+ *   03    SCHMIT_TRIGER             1
+ *   02:00 MUX_SELECT                0x0
+ * </pre>
+ */
+#define IO_CTRL_RX_ACTIVE_4_ADDR        (REG_IO_CTRL_BASE_ADDR + 0x0000006C)
+#define IO_CTRL_RX_ACTIVE_4_OFFSET      0x0000006C
+#define IO_CTRL_RX_ACTIVE_4_INDEX       0x0000001B
+#define IO_CTRL_RX_ACTIVE_4_RESET       0x000026D8
+
+static inline void io_ctrl_rx_active_4_set(struct cl_chip *chip, u32 value)
+{
+       cl_reg_write_chip(chip, IO_CTRL_RX_ACTIVE_4_ADDR, value);
+}
+
+/*
+ * @brief RX_ACTIVE_5 register definition
+ * <pre>
+ *  Bits           Field Name   Reset Value
+ * -----   ------------------   -----------
+ *   13    GPIO_IN                   1
+ *   12    GPIO_OUT                  0
+ *   11    GPIO_OE                   0
+ *   10    GPIO_ENABLE               1
+ *   09    input_enable              1
+ *   08    SLEW_RATE                 0
+ *   07:06 DRIVER_PULL_STATE         0x3
+ *   05:04 OUTPUT_PAD_STRENGTH       0x1
+ *   03    SCHMIT_TRIGER             1
+ *   02:00 MUX_SELECT                0x0
+ * </pre>
+ */
+#define IO_CTRL_RX_ACTIVE_5_ADDR        (REG_IO_CTRL_BASE_ADDR + 0x00000070)
+#define IO_CTRL_RX_ACTIVE_5_OFFSET      0x00000070
+#define IO_CTRL_RX_ACTIVE_5_INDEX       0x0000001C
+#define IO_CTRL_RX_ACTIVE_5_RESET       0x000026D8
+
+static inline void io_ctrl_rx_active_5_set(struct cl_chip *chip, u32 value)
+{
+       cl_reg_write_chip(chip, IO_CTRL_RX_ACTIVE_5_ADDR, value);
+}
+
+/*
+ * @brief RX_ACTIVE_6 register definition
+ * <pre>
+ *  Bits           Field Name   Reset Value
+ * -----   ------------------   -----------
+ *   13    GPIO_IN                   1
+ *   12    GPIO_OUT                  0
+ *   11    GPIO_OE                   0
+ *   10    GPIO_ENABLE               1
+ *   09    input_enable              1
+ *   08    SLEW_RATE                 0
+ *   07:06 DRIVER_PULL_STATE         0x3
+ *   05:04 OUTPUT_PAD_STRENGTH       0x1
+ *   03    SCHMIT_TRIGER             1
+ *   02:00 MUX_SELECT                0x0
+ * </pre>
+ */
+#define IO_CTRL_RX_ACTIVE_6_ADDR        (REG_IO_CTRL_BASE_ADDR + 0x00000074)
+#define IO_CTRL_RX_ACTIVE_6_OFFSET      0x00000074
+#define IO_CTRL_RX_ACTIVE_6_INDEX       0x0000001D
+#define IO_CTRL_RX_ACTIVE_6_RESET       0x000026D8
+
+static inline void io_ctrl_rx_active_6_set(struct cl_chip *chip, u32 value)
+{
+       cl_reg_write_chip(chip, IO_CTRL_RX_ACTIVE_6_ADDR, value);
+}
+
+/*
+ * @brief RX_ACTIVE_7 register definition
+ * <pre>
+ *  Bits           Field Name   Reset Value
+ * -----   ------------------   -----------
+ *   13    GPIO_IN                   1
+ *   12    GPIO_OUT                  0
+ *   11    GPIO_OE                   0
+ *   10    GPIO_ENABLE               1
+ *   09    input_enable              1
+ *   08    SLEW_RATE                 0
+ *   07:06 DRIVER_PULL_STATE         0x3
+ *   05:04 OUTPUT_PAD_STRENGTH       0x1
+ *   03    SCHMIT_TRIGER             1
+ *   02:00 MUX_SELECT                0x0
+ * </pre>
+ */
+#define IO_CTRL_RX_ACTIVE_7_ADDR        (REG_IO_CTRL_BASE_ADDR + 0x00000078)
+#define IO_CTRL_RX_ACTIVE_7_OFFSET      0x00000078
+#define IO_CTRL_RX_ACTIVE_7_INDEX       0x0000001E
+#define IO_CTRL_RX_ACTIVE_7_RESET       0x000026D8
+
+static inline void io_ctrl_rx_active_7_set(struct cl_chip *chip, u32 value)
+{
+       cl_reg_write_chip(chip, IO_CTRL_RX_ACTIVE_7_ADDR, value);
+}
+
+/*
+ * @brief LNA_ENABLE_0 register definition
+ * <pre>
+ *  Bits           Field Name   Reset Value
+ * -----   ------------------   -----------
+ *   13    GPIO_IN                   0
+ *   12    GPIO_OUT                  0
+ *   11    GPIO_OE                   0
+ *   10    GPIO_ENABLE               1
+ *   09    input_enable              1
+ *   08    SLEW_RATE                 0
+ *   07:06 DRIVER_PULL_STATE         0x2
+ *   05:04 OUTPUT_PAD_STRENGTH       0x1
+ *   03    SCHMIT_TRIGER             1
+ *   02:00 MUX_SELECT                0x0
+ * </pre>
+ */
+#define IO_CTRL_LNA_ENABLE_0_ADDR        (REG_IO_CTRL_BASE_ADDR + 0x0000007C)
+#define IO_CTRL_LNA_ENABLE_0_OFFSET      0x0000007C
+#define IO_CTRL_LNA_ENABLE_0_INDEX       0x0000001F
+#define IO_CTRL_LNA_ENABLE_0_RESET       0x00000698
+
+static inline void io_ctrl_lna_enable_0_set(struct cl_chip *chip, u32 value)
+{
+       cl_reg_write_chip(chip, IO_CTRL_LNA_ENABLE_0_ADDR, value);
+}
+
+/* Field definitions */
+#define IO_CTRL_LNA_ENABLE_0_GPIO_IN_BIT               ((u32)0x00002000)
+#define IO_CTRL_LNA_ENABLE_0_GPIO_IN_POS               13
+#define IO_CTRL_LNA_ENABLE_0_GPIO_OUT_BIT              ((u32)0x00001000)
+#define IO_CTRL_LNA_ENABLE_0_GPIO_OUT_POS              12
+#define IO_CTRL_LNA_ENABLE_0_GPIO_OE_BIT               ((u32)0x00000800)
+#define IO_CTRL_LNA_ENABLE_0_GPIO_OE_POS               11
+#define IO_CTRL_LNA_ENABLE_0_GPIO_ENABLE_BIT           ((u32)0x00000400)
+#define IO_CTRL_LNA_ENABLE_0_GPIO_ENABLE_POS           10
+#define IO_CTRL_LNA_ENABLE_0_INPUT_ENABLE_BIT          ((u32)0x00000200)
+#define IO_CTRL_LNA_ENABLE_0_INPUT_ENABLE_POS          9
+#define IO_CTRL_LNA_ENABLE_0_SLEW_RATE_BIT             ((u32)0x00000100)
+#define IO_CTRL_LNA_ENABLE_0_SLEW_RATE_POS             8
+#define IO_CTRL_LNA_ENABLE_0_DRIVER_PULL_STATE_MASK    ((u32)0x000000C0)
+#define IO_CTRL_LNA_ENABLE_0_DRIVER_PULL_STATE_LSB     6
+#define IO_CTRL_LNA_ENABLE_0_DRIVER_PULL_STATE_WIDTH   ((u32)0x00000002)
+#define IO_CTRL_LNA_ENABLE_0_OUTPUT_PAD_STRENGTH_MASK  ((u32)0x00000030)
+#define IO_CTRL_LNA_ENABLE_0_OUTPUT_PAD_STRENGTH_LSB   4
+#define IO_CTRL_LNA_ENABLE_0_OUTPUT_PAD_STRENGTH_WIDTH ((u32)0x00000002)
+#define IO_CTRL_LNA_ENABLE_0_SCHMIT_TRIGER_BIT         ((u32)0x00000008)
+#define IO_CTRL_LNA_ENABLE_0_SCHMIT_TRIGER_POS         3
+#define IO_CTRL_LNA_ENABLE_0_MUX_SELECT_MASK           ((u32)0x00000007)
+#define IO_CTRL_LNA_ENABLE_0_MUX_SELECT_LSB            0
+#define IO_CTRL_LNA_ENABLE_0_MUX_SELECT_WIDTH          ((u32)0x00000003)
+
+/*
+ * @brief LNA_ENABLE_1 register definition
+ * <pre>
+ *  Bits           Field Name   Reset Value
+ * -----   ------------------   -----------
+ *   13    GPIO_IN                   0
+ *   12    GPIO_OUT                  0
+ *   11    GPIO_OE                   0
+ *   10    GPIO_ENABLE               1
+ *   09    input_enable              1
+ *   08    SLEW_RATE                 0
+ *   07:06 DRIVER_PULL_STATE         0x2
+ *   05:04 OUTPUT_PAD_STRENGTH       0x1
+ *   03    SCHMIT_TRIGER             1
+ *   02:00 MUX_SELECT                0x0
+ * </pre>
+ */
+#define IO_CTRL_LNA_ENABLE_1_ADDR        (REG_IO_CTRL_BASE_ADDR + 0x00000080)
+#define IO_CTRL_LNA_ENABLE_1_OFFSET      0x00000080
+#define IO_CTRL_LNA_ENABLE_1_INDEX       0x00000020
+#define IO_CTRL_LNA_ENABLE_1_RESET       0x00000698
+
+static inline void io_ctrl_lna_enable_1_set(struct cl_chip *chip, u32 value)
+{
+       cl_reg_write_chip(chip, IO_CTRL_LNA_ENABLE_1_ADDR, value);
+}
+
+/*
+ * @brief LNA_ENABLE_2 register definition
+ * <pre>
+ *  Bits           Field Name   Reset Value
+ * -----   ------------------   -----------
+ *   13    GPIO_IN                   0
+ *   12    GPIO_OUT                  0
+ *   11    GPIO_OE                   0
+ *   10    GPIO_ENABLE               1
+ *   09    input_enable              1
+ *   08    SLEW_RATE                 0
+ *   07:06 DRIVER_PULL_STATE         0x2
+ *   05:04 OUTPUT_PAD_STRENGTH       0x1
+ *   03    SCHMIT_TRIGER             1
+ *   02:00 MUX_SELECT                0x0
+ * </pre>
+ */
+#define IO_CTRL_LNA_ENABLE_2_ADDR        (REG_IO_CTRL_BASE_ADDR + 0x00000084)
+#define IO_CTRL_LNA_ENABLE_2_OFFSET      0x00000084
+#define IO_CTRL_LNA_ENABLE_2_INDEX       0x00000021
+#define IO_CTRL_LNA_ENABLE_2_RESET       0x00000698
+
+static inline void io_ctrl_lna_enable_2_set(struct cl_chip *chip, u32 value)
+{
+       cl_reg_write_chip(chip, IO_CTRL_LNA_ENABLE_2_ADDR, value);
+}
+
+/*
+ * @brief LNA_ENABLE_3 register definition
+ * <pre>
+ *  Bits           Field Name   Reset Value
+ * -----   ------------------   -----------
+ *   13    GPIO_IN                   0
+ *   12    GPIO_OUT                  0
+ *   11    GPIO_OE                   0
+ *   10    GPIO_ENABLE               1
+ *   09    input_enable              1
+ *   08    SLEW_RATE                 0
+ *   07:06 DRIVER_PULL_STATE         0x2
+ *   05:04 OUTPUT_PAD_STRENGTH       0x1
+ *   03    SCHMIT_TRIGER             1
+ *   02:00 MUX_SELECT                0x0
+ * </pre>
+ */
+#define IO_CTRL_LNA_ENABLE_3_ADDR        (REG_IO_CTRL_BASE_ADDR + 0x00000088)
+#define IO_CTRL_LNA_ENABLE_3_OFFSET      0x00000088
+#define IO_CTRL_LNA_ENABLE_3_INDEX       0x00000022
+#define IO_CTRL_LNA_ENABLE_3_RESET       0x00000698
+
+static inline void io_ctrl_lna_enable_3_set(struct cl_chip *chip, u32 value)
+{
+       cl_reg_write_chip(chip, IO_CTRL_LNA_ENABLE_3_ADDR, value);
+}
+
+/*
+ * @brief LNA_ENABLE_4 register definition
+ * <pre>
+ *  Bits           Field Name   Reset Value
+ * -----   ------------------   -----------
+ *   13    GPIO_IN                   0
+ *   12    GPIO_OUT                  0
+ *   11    GPIO_OE                   0
+ *   10    GPIO_ENABLE               1
+ *   09    input_enable              1
+ *   08    SLEW_RATE                 0
+ *   07:06 DRIVER_PULL_STATE         0x2
+ *   05:04 OUTPUT_PAD_STRENGTH       0x1
+ *   03    SCHMIT_TRIGER             1
+ *   02:00 MUX_SELECT                0x0
+ * </pre>
+ */
+#define IO_CTRL_LNA_ENABLE_4_ADDR        (REG_IO_CTRL_BASE_ADDR + 0x0000008C)
+#define IO_CTRL_LNA_ENABLE_4_OFFSET      0x0000008C
+#define IO_CTRL_LNA_ENABLE_4_INDEX       0x00000023
+#define IO_CTRL_LNA_ENABLE_4_RESET       0x00000698
+
+static inline void io_ctrl_lna_enable_4_set(struct cl_chip *chip, u32 value)
+{
+       cl_reg_write_chip(chip, IO_CTRL_LNA_ENABLE_4_ADDR, value);
+}
+
+/*
+ * @brief LNA_ENABLE_5 register definition
+ * <pre>
+ *  Bits           Field Name   Reset Value
+ * -----   ------------------   -----------
+ *   13    GPIO_IN                   0
+ *   12    GPIO_OUT                  0
+ *   11    GPIO_OE                   0
+ *   10    GPIO_ENABLE               1
+ *   09    input_enable              1
+ *   08    SLEW_RATE                 0
+ *   07:06 DRIVER_PULL_STATE         0x2
+ *   05:04 OUTPUT_PAD_STRENGTH       0x1
+ *   03    SCHMIT_TRIGER             1
+ *   02:00 MUX_SELECT                0x0
+ * </pre>
+ */
+#define IO_CTRL_LNA_ENABLE_5_ADDR        (REG_IO_CTRL_BASE_ADDR + 0x00000090)
+#define IO_CTRL_LNA_ENABLE_5_OFFSET      0x00000090
+#define IO_CTRL_LNA_ENABLE_5_INDEX       0x00000024
+#define IO_CTRL_LNA_ENABLE_5_RESET       0x00000698
+
+static inline void io_ctrl_lna_enable_5_set(struct cl_chip *chip, u32 value)
+{
+       cl_reg_write_chip(chip, IO_CTRL_LNA_ENABLE_5_ADDR, value);
+}
+
+/*
+ * @brief LNA_ENABLE_6 register definition
+ * <pre>
+ *  Bits           Field Name   Reset Value
+ * -----   ------------------   -----------
+ *   13    GPIO_IN                   0
+ *   12    GPIO_OUT                  0
+ *   11    GPIO_OE                   0
+ *   10    GPIO_ENABLE               1
+ *   09    input_enable              1
+ *   08    SLEW_RATE                 0
+ *   07:06 DRIVER_PULL_STATE         0x2
+ *   05:04 OUTPUT_PAD_STRENGTH       0x1
+ *   03    SCHMIT_TRIGER             1
+ *   02:00 MUX_SELECT                0x0
+ * </pre>
+ */
+#define IO_CTRL_LNA_ENABLE_6_ADDR        (REG_IO_CTRL_BASE_ADDR + 0x00000094)
+#define IO_CTRL_LNA_ENABLE_6_OFFSET      0x00000094
+#define IO_CTRL_LNA_ENABLE_6_INDEX       0x00000025
+#define IO_CTRL_LNA_ENABLE_6_RESET       0x00000698
+
+static inline void io_ctrl_lna_enable_6_set(struct cl_chip *chip, u32 value)
+{
+       cl_reg_write_chip(chip, IO_CTRL_LNA_ENABLE_6_ADDR, value);
+}
+
+/*
+ * @brief LNA_ENABLE_7 register definition
+ * <pre>
+ *  Bits           Field Name   Reset Value
+ * -----   ------------------   -----------
+ *   13    GPIO_IN                   0
+ *   12    GPIO_OUT                  0
+ *   11    GPIO_OE                   0
+ *   10    GPIO_ENABLE               1
+ *   09    input_enable              1
+ *   08    SLEW_RATE                 0
+ *   07:06 DRIVER_PULL_STATE         0x2
+ *   05:04 OUTPUT_PAD_STRENGTH       0x1
+ *   03    SCHMIT_TRIGER             1
+ *   02:00 MUX_SELECT                0x0
+ * </pre>
+ */
+#define IO_CTRL_LNA_ENABLE_7_ADDR        (REG_IO_CTRL_BASE_ADDR + 0x00000098)
+#define IO_CTRL_LNA_ENABLE_7_OFFSET      0x00000098
+#define IO_CTRL_LNA_ENABLE_7_INDEX       0x00000026
+#define IO_CTRL_LNA_ENABLE_7_RESET       0x00000698
+
+static inline void io_ctrl_lna_enable_7_set(struct cl_chip *chip, u32 value)
+{
+       cl_reg_write_chip(chip, IO_CTRL_LNA_ENABLE_7_ADDR, value);
+}
+
+/*
+ * @brief LNA_ENABLE_8 register definition
+ * <pre>
+ *  Bits           Field Name   Reset Value
+ * -----   ------------------   -----------
+ *   13    GPIO_IN                   0
+ *   12    GPIO_OUT                  0
+ *   11    GPIO_OE                   0
+ *   10    GPIO_ENABLE               1
+ *   09    input_enable              1
+ *   08    SLEW_RATE                 0
+ *   07:06 DRIVER_PULL_STATE         0x2
+ *   05:04 OUTPUT_PAD_STRENGTH       0x1
+ *   03    SCHMIT_TRIGER             1
+ *   02:00 MUX_SELECT                0x0
+ * </pre>
+ */
+#define IO_CTRL_LNA_ENABLE_8_ADDR        (REG_IO_CTRL_BASE_ADDR + 0x0000009C)
+#define IO_CTRL_LNA_ENABLE_8_OFFSET      0x0000009C
+#define IO_CTRL_LNA_ENABLE_8_INDEX       0x00000027
+#define IO_CTRL_LNA_ENABLE_8_RESET       0x00000698
+
+static inline void io_ctrl_lna_enable_8_set(struct cl_chip *chip, u32 value)
+{
+       cl_reg_write_chip(chip, IO_CTRL_LNA_ENABLE_8_ADDR, value);
+}
+
+/*
+ * @brief LNA_ENABLE_9 register definition
+ * <pre>
+ *  Bits           Field Name   Reset Value
+ * -----   ------------------   -----------
+ *   13    GPIO_IN                   0
+ *   12    GPIO_OUT                  0
+ *   11    GPIO_OE                   0
+ *   10    GPIO_ENABLE               1
+ *   09    input_enable              1
+ *   08    SLEW_RATE                 0
+ *   07:06 DRIVER_PULL_STATE         0x2
+ *   05:04 OUTPUT_PAD_STRENGTH       0x1
+ *   03    SCHMIT_TRIGER             1
+ *   02:00 MUX_SELECT                0x0
+ * </pre>
+ */
+#define IO_CTRL_LNA_ENABLE_9_ADDR        (REG_IO_CTRL_BASE_ADDR + 0x000000A0)
+#define IO_CTRL_LNA_ENABLE_9_OFFSET      0x000000A0
+#define IO_CTRL_LNA_ENABLE_9_INDEX       0x00000028
+#define IO_CTRL_LNA_ENABLE_9_RESET       0x00000698
+
+static inline void io_ctrl_lna_enable_9_set(struct cl_chip *chip, u32 value)
+{
+       cl_reg_write_chip(chip, IO_CTRL_LNA_ENABLE_9_ADDR, value);
+}
+
+/*
+ * @brief LNA_ENABLE_10 register definition
+ * <pre>
+ *  Bits           Field Name   Reset Value
+ * -----   ------------------   -----------
+ *   13    GPIO_IN                   0
+ *   12    GPIO_OUT                  0
+ *   11    GPIO_OE                   0
+ *   10    GPIO_ENABLE               1
+ *   09    input_enable              1
+ *   08    SLEW_RATE                 0
+ *   07:06 DRIVER_PULL_STATE         0x2
+ *   05:04 OUTPUT_PAD_STRENGTH       0x1
+ *   03    SCHMIT_TRIGER             1
+ *   02:00 MUX_SELECT                0x0
+ * </pre>
+ */
+#define IO_CTRL_LNA_ENABLE_10_ADDR        (REG_IO_CTRL_BASE_ADDR + 0x000000A4)
+#define IO_CTRL_LNA_ENABLE_10_OFFSET      0x000000A4
+#define IO_CTRL_LNA_ENABLE_10_INDEX       0x00000029
+#define IO_CTRL_LNA_ENABLE_10_RESET       0x00000698
+
+static inline void io_ctrl_lna_enable_10_set(struct cl_chip *chip, u32 value)
+{
+       cl_reg_write_chip(chip, IO_CTRL_LNA_ENABLE_10_ADDR, value);
+}
+
+/*
+ * @brief LNA_ENABLE_11 register definition
+ * <pre>
+ *  Bits           Field Name   Reset Value
+ * -----   ------------------   -----------
+ *   13    GPIO_IN                   0
+ *   12    GPIO_OUT                  0
+ *   11    GPIO_OE                   0
+ *   10    GPIO_ENABLE               1
+ *   09    input_enable              1
+ *   08    SLEW_RATE                 0
+ *   07:06 DRIVER_PULL_STATE         0x2
+ *   05:04 OUTPUT_PAD_STRENGTH       0x1
+ *   03    SCHMIT_TRIGER             1
+ *   02:00 MUX_SELECT                0x0
+ * </pre>
+ */
+#define IO_CTRL_LNA_ENABLE_11_ADDR        (REG_IO_CTRL_BASE_ADDR + 0x000000A8)
+#define IO_CTRL_LNA_ENABLE_11_OFFSET      0x000000A8
+#define IO_CTRL_LNA_ENABLE_11_INDEX       0x0000002A
+#define IO_CTRL_LNA_ENABLE_11_RESET       0x00000698
+
+static inline void io_ctrl_lna_enable_11_set(struct cl_chip *chip, u32 value)
+{
+       cl_reg_write_chip(chip, IO_CTRL_LNA_ENABLE_11_ADDR, value);
+}
+
+/*
+ * @brief PA_ENABLE_0 register definition
+ * <pre>
+ *  Bits           Field Name   Reset Value
+ * -----   ------------------   -----------
+ *   13    GPIO_IN                   0
+ *   12    GPIO_OUT                  0
+ *   11    GPIO_OE                   0
+ *   10    GPIO_ENABLE               1
+ *   09    input_enable              1
+ *   08    SLEW_RATE                 0
+ *   07:06 DRIVER_PULL_STATE         0x2
+ *   05:04 OUTPUT_PAD_STRENGTH       0x1
+ *   03    SCHMIT_TRIGER             1
+ *   02:00 MUX_SELECT                0x0
+ * </pre>
+ */
+#define IO_CTRL_PA_ENABLE_0_ADDR        (REG_IO_CTRL_BASE_ADDR + 0x000000AC)
+#define IO_CTRL_PA_ENABLE_0_OFFSET      0x000000AC
+#define IO_CTRL_PA_ENABLE_0_INDEX       0x0000002B
+#define IO_CTRL_PA_ENABLE_0_RESET       0x00000698
+
+static inline void io_ctrl_pa_enable_0_set(struct cl_chip *chip, u32 value)
+{
+       cl_reg_write_chip(chip, IO_CTRL_PA_ENABLE_0_ADDR, value);
+}
+
+/* Field definitions */
+#define IO_CTRL_PA_ENABLE_0_GPIO_IN_BIT               ((u32)0x00002000)
+#define IO_CTRL_PA_ENABLE_0_GPIO_IN_POS               13
+#define IO_CTRL_PA_ENABLE_0_GPIO_OUT_BIT              ((u32)0x00001000)
+#define IO_CTRL_PA_ENABLE_0_GPIO_OUT_POS              12
+#define IO_CTRL_PA_ENABLE_0_GPIO_OE_BIT               ((u32)0x00000800)
+#define IO_CTRL_PA_ENABLE_0_GPIO_OE_POS               11
+#define IO_CTRL_PA_ENABLE_0_GPIO_ENABLE_BIT           ((u32)0x00000400)
+#define IO_CTRL_PA_ENABLE_0_GPIO_ENABLE_POS           10
+#define IO_CTRL_PA_ENABLE_0_INPUT_ENABLE_BIT          ((u32)0x00000200)
+#define IO_CTRL_PA_ENABLE_0_INPUT_ENABLE_POS          9
+#define IO_CTRL_PA_ENABLE_0_SLEW_RATE_BIT             ((u32)0x00000100)
+#define IO_CTRL_PA_ENABLE_0_SLEW_RATE_POS             8
+#define IO_CTRL_PA_ENABLE_0_DRIVER_PULL_STATE_MASK    ((u32)0x000000C0)
+#define IO_CTRL_PA_ENABLE_0_DRIVER_PULL_STATE_LSB     6
+#define IO_CTRL_PA_ENABLE_0_DRIVER_PULL_STATE_WIDTH   ((u32)0x00000002)
+#define IO_CTRL_PA_ENABLE_0_OUTPUT_PAD_STRENGTH_MASK  ((u32)0x00000030)
+#define IO_CTRL_PA_ENABLE_0_OUTPUT_PAD_STRENGTH_LSB   4
+#define IO_CTRL_PA_ENABLE_0_OUTPUT_PAD_STRENGTH_WIDTH ((u32)0x00000002)
+#define IO_CTRL_PA_ENABLE_0_SCHMIT_TRIGER_BIT         ((u32)0x00000008)
+#define IO_CTRL_PA_ENABLE_0_SCHMIT_TRIGER_POS         3
+#define IO_CTRL_PA_ENABLE_0_MUX_SELECT_MASK           ((u32)0x00000007)
+#define IO_CTRL_PA_ENABLE_0_MUX_SELECT_LSB            0
+#define IO_CTRL_PA_ENABLE_0_MUX_SELECT_WIDTH          ((u32)0x00000003)
+
+/*
+ * @brief PA_ENABLE_1 register definition
+ * <pre>
+ *  Bits           Field Name   Reset Value
+ * -----   ------------------   -----------
+ *   13    GPIO_IN                   0
+ *   12    GPIO_OUT                  0
+ *   11    GPIO_OE                   0
+ *   10    GPIO_ENABLE               1
+ *   09    input_enable              1
+ *   08    SLEW_RATE                 0
+ *   07:06 DRIVER_PULL_STATE         0x2
+ *   05:04 OUTPUT_PAD_STRENGTH       0x1
+ *   03    SCHMIT_TRIGER             1
+ *   02:00 MUX_SELECT                0x0
+ * </pre>
+ */
+#define IO_CTRL_PA_ENABLE_1_ADDR        (REG_IO_CTRL_BASE_ADDR + 0x000000B0)
+#define IO_CTRL_PA_ENABLE_1_OFFSET      0x000000B0
+#define IO_CTRL_PA_ENABLE_1_INDEX       0x0000002C
+#define IO_CTRL_PA_ENABLE_1_RESET       0x00000698
+
+static inline void io_ctrl_pa_enable_1_set(struct cl_chip *chip, u32 value)
+{
+       cl_reg_write_chip(chip, IO_CTRL_PA_ENABLE_1_ADDR, value);
+}
+
+/*
+ * @brief PA_ENABLE_2 register definition
+ * <pre>
+ *  Bits           Field Name   Reset Value
+ * -----   ------------------   -----------
+ *   13    GPIO_IN                   0
+ *   12    GPIO_OUT                  0
+ *   11    GPIO_OE                   0
+ *   10    GPIO_ENABLE               1
+ *   09    input_enable              1
+ *   08    SLEW_RATE                 0
+ *   07:06 DRIVER_PULL_STATE         0x2
+ *   05:04 OUTPUT_PAD_STRENGTH       0x1
+ *   03    SCHMIT_TRIGER             1
+ *   02:00 MUX_SELECT                0x0
+ * </pre>
+ */
+#define IO_CTRL_PA_ENABLE_2_ADDR        (REG_IO_CTRL_BASE_ADDR + 0x000000B4)
+#define IO_CTRL_PA_ENABLE_2_OFFSET      0x000000B4
+#define IO_CTRL_PA_ENABLE_2_INDEX       0x0000002D
+#define IO_CTRL_PA_ENABLE_2_RESET       0x00000698
+
+static inline void io_ctrl_pa_enable_2_set(struct cl_chip *chip, u32 value)
+{
+       cl_reg_write_chip(chip, IO_CTRL_PA_ENABLE_2_ADDR, value);
+}
+
+/*
+ * @brief PA_ENABLE_3 register definition
+ * <pre>
+ *  Bits           Field Name   Reset Value
+ * -----   ------------------   -----------
+ *   13    GPIO_IN                   0
+ *   12    GPIO_OUT                  0
+ *   11    GPIO_OE                   0
+ *   10    GPIO_ENABLE               1
+ *   09    input_enable              1
+ *   08    SLEW_RATE                 0
+ *   07:06 DRIVER_PULL_STATE         0x2
+ *   05:04 OUTPUT_PAD_STRENGTH       0x1
+ *   03    SCHMIT_TRIGER             1
+ *   02:00 MUX_SELECT                0x0
+ * </pre>
+ */
+#define IO_CTRL_PA_ENABLE_3_ADDR        (REG_IO_CTRL_BASE_ADDR + 0x000000B8)
+#define IO_CTRL_PA_ENABLE_3_OFFSET      0x000000B8
+#define IO_CTRL_PA_ENABLE_3_INDEX       0x0000002E
+#define IO_CTRL_PA_ENABLE_3_RESET       0x00000698
+
+static inline void io_ctrl_pa_enable_3_set(struct cl_chip *chip, u32 value)
+{
+       cl_reg_write_chip(chip, IO_CTRL_PA_ENABLE_3_ADDR, value);
+}
+
+/*
+ * @brief PA_ENABLE_4 register definition
+ * <pre>
+ *  Bits           Field Name   Reset Value
+ * -----   ------------------   -----------
+ *   13    GPIO_IN                   0
+ *   12    GPIO_OUT                  0
+ *   11    GPIO_OE                   0
+ *   10    GPIO_ENABLE               1
+ *   09    input_enable              1
+ *   08    SLEW_RATE                 0
+ *   07:06 DRIVER_PULL_STATE         0x2
+ *   05:04 OUTPUT_PAD_STRENGTH       0x1
+ *   03    SCHMIT_TRIGER             1
+ *   02:00 MUX_SELECT                0x0
+ * </pre>
+ */
+#define IO_CTRL_PA_ENABLE_4_ADDR        (REG_IO_CTRL_BASE_ADDR + 0x000000BC)
+#define IO_CTRL_PA_ENABLE_4_OFFSET      0x000000BC
+#define IO_CTRL_PA_ENABLE_4_INDEX       0x0000002F
+#define IO_CTRL_PA_ENABLE_4_RESET       0x00000698
+
+static inline void io_ctrl_pa_enable_4_set(struct cl_chip *chip, u32 value)
+{
+       cl_reg_write_chip(chip, IO_CTRL_PA_ENABLE_4_ADDR, value);
+}
+
+/*
+ * @brief PA_ENABLE_5 register definition
+ * <pre>
+ *  Bits           Field Name   Reset Value
+ * -----   ------------------   -----------
+ *   13    GPIO_IN                   0
+ *   12    GPIO_OUT                  0
+ *   11    GPIO_OE                   0
+ *   10    GPIO_ENABLE               1
+ *   09    input_enable              1
+ *   08    SLEW_RATE                 0
+ *   07:06 DRIVER_PULL_STATE         0x2
+ *   05:04 OUTPUT_PAD_STRENGTH       0x1
+ *   03    SCHMIT_TRIGER             1
+ *   02:00 MUX_SELECT                0x0
+ * </pre>
+ */
+#define IO_CTRL_PA_ENABLE_5_ADDR        (REG_IO_CTRL_BASE_ADDR + 0x000000C0)
+#define IO_CTRL_PA_ENABLE_5_OFFSET      0x000000C0
+#define IO_CTRL_PA_ENABLE_5_INDEX       0x00000030
+#define IO_CTRL_PA_ENABLE_5_RESET       0x00000698
+
+static inline void io_ctrl_pa_enable_5_set(struct cl_chip *chip, u32 value)
+{
+       cl_reg_write_chip(chip, IO_CTRL_PA_ENABLE_5_ADDR, value);
+}
+
+/*
+ * @brief PA_ENABLE_6 register definition
+ * <pre>
+ *  Bits           Field Name   Reset Value
+ * -----   ------------------   -----------
+ *   13    GPIO_IN                   0
+ *   12    GPIO_OUT                  0
+ *   11    GPIO_OE                   0
+ *   10    GPIO_ENABLE               1
+ *   09    input_enable              1
+ *   08    SLEW_RATE                 0
+ *   07:06 DRIVER_PULL_STATE         0x2
+ *   05:04 OUTPUT_PAD_STRENGTH       0x1
+ *   03    SCHMIT_TRIGER             1
+ *   02:00 MUX_SELECT                0x0
+ * </pre>
+ */
+#define IO_CTRL_PA_ENABLE_6_ADDR        (REG_IO_CTRL_BASE_ADDR + 0x000000C4)
+#define IO_CTRL_PA_ENABLE_6_OFFSET      0x000000C4
+#define IO_CTRL_PA_ENABLE_6_INDEX       0x00000031
+#define IO_CTRL_PA_ENABLE_6_RESET       0x00000698
+
+static inline void io_ctrl_pa_enable_6_set(struct cl_chip *chip, u32 value)
+{
+       cl_reg_write_chip(chip, IO_CTRL_PA_ENABLE_6_ADDR, value);
+}
+
+/*
+ * @brief PA_ENABLE_7 register definition
+ * <pre>
+ *  Bits           Field Name   Reset Value
+ * -----   ------------------   -----------
+ *   13    GPIO_IN                   0
+ *   12    GPIO_OUT                  0
+ *   11    GPIO_OE                   0
+ *   10    GPIO_ENABLE               1
+ *   09    input_enable              1
+ *   08    SLEW_RATE                 0
+ *   07:06 DRIVER_PULL_STATE         0x2
+ *   05:04 OUTPUT_PAD_STRENGTH       0x1
+ *   03    SCHMIT_TRIGER             1
+ *   02:00 MUX_SELECT                0x0
+ * </pre>
+ */
+#define IO_CTRL_PA_ENABLE_7_ADDR        (REG_IO_CTRL_BASE_ADDR + 0x000000C8)
+#define IO_CTRL_PA_ENABLE_7_OFFSET      0x000000C8
+#define IO_CTRL_PA_ENABLE_7_INDEX       0x00000032
+#define IO_CTRL_PA_ENABLE_7_RESET       0x00000698
+
+static inline void io_ctrl_pa_enable_7_set(struct cl_chip *chip, u32 value)
+{
+       cl_reg_write_chip(chip, IO_CTRL_PA_ENABLE_7_ADDR, value);
+}
+
+/*
+ * @brief PA_ENABLE_8 register definition
+ * <pre>
+ *  Bits           Field Name   Reset Value
+ * -----   ------------------   -----------
+ *   13    GPIO_IN                   0
+ *   12    GPIO_OUT                  0
+ *   11    GPIO_OE                   0
+ *   10    GPIO_ENABLE               1
+ *   09    input_enable              1
+ *   08    SLEW_RATE                 0
+ *   07:06 DRIVER_PULL_STATE         0x2
+ *   05:04 OUTPUT_PAD_STRENGTH       0x1
+ *   03    SCHMIT_TRIGER             1
+ *   02:00 MUX_SELECT                0x0
+ * </pre>
+ */
+#define IO_CTRL_PA_ENABLE_8_ADDR        (REG_IO_CTRL_BASE_ADDR + 0x000000CC)
+#define IO_CTRL_PA_ENABLE_8_OFFSET      0x000000CC
+#define IO_CTRL_PA_ENABLE_8_INDEX       0x00000033
+#define IO_CTRL_PA_ENABLE_8_RESET       0x00000698
+
+static inline void io_ctrl_pa_enable_8_set(struct cl_chip *chip, u32 value)
+{
+       cl_reg_write_chip(chip, IO_CTRL_PA_ENABLE_8_ADDR, value);
+}
+
+/*
+ * @brief PA_ENABLE_9 register definition
+ * <pre>
+ *  Bits           Field Name   Reset Value
+ * -----   ------------------   -----------
+ *   13    GPIO_IN                   0
+ *   12    GPIO_OUT                  0
+ *   11    GPIO_OE                   0
+ *   10    GPIO_ENABLE               1
+ *   09    input_enable              1
+ *   08    SLEW_RATE                 0
+ *   07:06 DRIVER_PULL_STATE         0x2
+ *   05:04 OUTPUT_PAD_STRENGTH       0x1
+ *   03    SCHMIT_TRIGER             1
+ *   02:00 MUX_SELECT                0x0
+ * </pre>
+ */
+#define IO_CTRL_PA_ENABLE_9_ADDR        (REG_IO_CTRL_BASE_ADDR + 0x000000D0)
+#define IO_CTRL_PA_ENABLE_9_OFFSET      0x000000D0
+#define IO_CTRL_PA_ENABLE_9_INDEX       0x00000034
+#define IO_CTRL_PA_ENABLE_9_RESET       0x00000698
+
+static inline void io_ctrl_pa_enable_9_set(struct cl_chip *chip, u32 value)
+{
+       cl_reg_write_chip(chip, IO_CTRL_PA_ENABLE_9_ADDR, value);
+}
+
+/*
+ * @brief PA_ENABLE_10 register definition
+ * <pre>
+ *  Bits           Field Name   Reset Value
+ * -----   ------------------   -----------
+ *   13    GPIO_IN                   0
+ *   12    GPIO_OUT                  0
+ *   11    GPIO_OE                   0
+ *   10    GPIO_ENABLE               1
+ *   09    input_enable              1
+ *   08    SLEW_RATE                 0
+ *   07:06 DRIVER_PULL_STATE         0x2
+ *   05:04 OUTPUT_PAD_STRENGTH       0x1
+ *   03    SCHMIT_TRIGER             1
+ *   02:00 MUX_SELECT                0x0
+ * </pre>
+ */
+#define IO_CTRL_PA_ENABLE_10_ADDR        (REG_IO_CTRL_BASE_ADDR + 0x000000D4)
+#define IO_CTRL_PA_ENABLE_10_OFFSET      0x000000D4
+#define IO_CTRL_PA_ENABLE_10_INDEX       0x00000035
+#define IO_CTRL_PA_ENABLE_10_RESET       0x00000698
+
+static inline void io_ctrl_pa_enable_10_set(struct cl_chip *chip, u32 value)
+{
+       cl_reg_write_chip(chip, IO_CTRL_PA_ENABLE_10_ADDR, value);
+}
+
+/*
+ * @brief PA_ENABLE_11 register definition
+ * <pre>
+ *  Bits           Field Name   Reset Value
+ * -----   ------------------   -----------
+ *   13    GPIO_IN                   0
+ *   12    GPIO_OUT                  0
+ *   11    GPIO_OE                   0
+ *   10    GPIO_ENABLE               1
+ *   09    input_enable              1
+ *   08    SLEW_RATE                 0
+ *   07:06 DRIVER_PULL_STATE         0x2
+ *   05:04 OUTPUT_PAD_STRENGTH       0x1
+ *   03    SCHMIT_TRIGER             1
+ *   02:00 MUX_SELECT                0x0
+ * </pre>
+ */
+#define IO_CTRL_PA_ENABLE_11_ADDR        (REG_IO_CTRL_BASE_ADDR + 0x000000D8)
+#define IO_CTRL_PA_ENABLE_11_OFFSET      0x000000D8
+#define IO_CTRL_PA_ENABLE_11_INDEX       0x00000036
+#define IO_CTRL_PA_ENABLE_11_RESET       0x00000698
+
+static inline void io_ctrl_pa_enable_11_set(struct cl_chip *chip, u32 value)
+{
+       cl_reg_write_chip(chip, IO_CTRL_PA_ENABLE_11_ADDR, value);
+}
+
+/*
+ * @brief SPICLK register definition
+ * <pre>
+ *  Bits           Field Name   Reset Value
+ * -----   ------------------   -----------
+ *   13    GPIO_IN                   0
+ *   12    GPIO_OUT                  0
+ *   11    GPIO_OE                   0
+ *   10    GPIO_ENABLE               0
+ *   09    input_enable              1
+ *   08    SLEW_RATE                 1
+ *   07:06 DRIVER_PULL_STATE         0x0
+ *   05:04 OUTPUT_PAD_STRENGTH       0x1
+ *   03    SCHMIT_TRIGER             1
+ *   02:00 MUX_SELECT                0x0
+ * </pre>
+ */
+#define IO_CTRL_SPICLK_ADDR        (REG_IO_CTRL_BASE_ADDR + 0x000000DC)
+#define IO_CTRL_SPICLK_OFFSET      0x000000DC
+#define IO_CTRL_SPICLK_INDEX       0x00000037
+#define IO_CTRL_SPICLK_RESET       0x00000318
+
+static inline void io_ctrl_spiclk_set(struct cl_chip *chip, u32 value)
+{
+       cl_reg_write_chip(chip, IO_CTRL_SPICLK_ADDR, value);
+}
+
+/*
+ * @brief FWR_EN_1 register definition
+ * <pre>
+ *  Bits           Field Name   Reset Value
+ * -----   ------------------   -----------
+ *   13    GPIO_IN                   0
+ *   12    GPIO_OUT                  0
+ *   11    GPIO_OE                   0
+ *   10    GPIO_ENABLE               0
+ *   09    input_enable              1
+ *   08    SLEW_RATE                 1
+ *   07:06 DRIVER_PULL_STATE         0x0
+ *   05:04 OUTPUT_PAD_STRENGTH       0x1
+ *   03    SCHMIT_TRIGER             1
+ *   02:00 MUX_SELECT                0x0
+ * </pre>
+ */
+#define IO_CTRL_FWR_EN_1_ADDR        (REG_IO_CTRL_BASE_ADDR + 0x000000F0)
+#define IO_CTRL_FWR_EN_1_OFFSET      0x000000F0
+#define IO_CTRL_FWR_EN_1_INDEX       0x0000003C
+#define IO_CTRL_FWR_EN_1_RESET       0x00000318
+
+static inline void io_ctrl_fwr_en_1_set(struct cl_chip *chip, u32 value)
+{
+       cl_reg_write_chip(chip, IO_CTRL_FWR_EN_1_ADDR, value);
+}
+
+/*
+ * @brief FASTWR_7 register definition
+ * <pre>
+ *  Bits           Field Name   Reset Value
+ * -----   ------------------   -----------
+ *   13    GPIO_IN                   0
+ *   12    GPIO_OUT                  0
+ *   11    GPIO_OE                   0
+ *   10    GPIO_ENABLE               0
+ *   09    input_enable              1
+ *   08    SLEW_RATE                 1
+ *   07:06 DRIVER_PULL_STATE         0x0
+ *   05:04 OUTPUT_PAD_STRENGTH       0x1
+ *   03    SCHMIT_TRIGER             1
+ *   02:00 MUX_SELECT                0x0
+ * </pre>
+ */
+#define IO_CTRL_FASTWR_7_ADDR        (REG_IO_CTRL_BASE_ADDR + 0x000000F8)
+#define IO_CTRL_FASTWR_7_OFFSET      0x000000F8
+#define IO_CTRL_FASTWR_7_INDEX       0x0000003E
+#define IO_CTRL_FASTWR_7_RESET       0x00000318
+
+static inline void io_ctrl_fastwr_7_set(struct cl_chip *chip, u32 value)
+{
+       cl_reg_write_chip(chip, IO_CTRL_FASTWR_7_ADDR, value);
+}
+
+/*
+ * @brief FASTWR_6 register definition
+ * <pre>
+ *  Bits           Field Name   Reset Value
+ * -----   ------------------   -----------
+ *   13    GPIO_IN                   0
+ *   12    GPIO_OUT                  0
+ *   11    GPIO_OE                   0
+ *   10    GPIO_ENABLE               0
+ *   09    input_enable              1
+ *   08    SLEW_RATE                 1
+ *   07:06 DRIVER_PULL_STATE         0x0
+ *   05:04 OUTPUT_PAD_STRENGTH       0x1
+ *   03    SCHMIT_TRIGER             1
+ *   02:00 MUX_SELECT                0x0
+ * </pre>
+ */
+#define IO_CTRL_FASTWR_6_ADDR        (REG_IO_CTRL_BASE_ADDR + 0x000000FC)
+#define IO_CTRL_FASTWR_6_OFFSET      0x000000FC
+#define IO_CTRL_FASTWR_6_INDEX       0x0000003F
+#define IO_CTRL_FASTWR_6_RESET       0x00000318
+
+static inline void io_ctrl_fastwr_6_set(struct cl_chip *chip, u32 value)
+{
+       cl_reg_write_chip(chip, IO_CTRL_FASTWR_6_ADDR, value);
+}
+
+/*
+ * @brief FASTWR_5 register definition
+ * <pre>
+ *  Bits           Field Name   Reset Value
+ * -----   ------------------   -----------
+ *   13    GPIO_IN                   0
+ *   12    GPIO_OUT                  0
+ *   11    GPIO_OE                   0
+ *   10    GPIO_ENABLE               0
+ *   09    input_enable              1
+ *   08    SLEW_RATE                 1
+ *   07:06 DRIVER_PULL_STATE         0x0
+ *   05:04 OUTPUT_PAD_STRENGTH       0x1
+ *   03    SCHMIT_TRIGER             1
+ *   02:00 MUX_SELECT                0x0
+ * </pre>
+ */
+#define IO_CTRL_FASTWR_5_ADDR        (REG_IO_CTRL_BASE_ADDR + 0x00000100)
+#define IO_CTRL_FASTWR_5_OFFSET      0x00000100
+#define IO_CTRL_FASTWR_5_INDEX       0x00000040
+#define IO_CTRL_FASTWR_5_RESET       0x00000318
+
+static inline void io_ctrl_fastwr_5_set(struct cl_chip *chip, u32 value)
+{
+       cl_reg_write_chip(chip, IO_CTRL_FASTWR_5_ADDR, value);
+}
+
+/*
+ * @brief FASTWR_4 register definition
+ * <pre>
+ *  Bits           Field Name   Reset Value
+ * -----   ------------------   -----------
+ *   13    GPIO_IN                   0
+ *   12    GPIO_OUT                  0
+ *   11    GPIO_OE                   0
+ *   10    GPIO_ENABLE               0
+ *   09    input_enable              1
+ *   08    SLEW_RATE                 1
+ *   07:06 DRIVER_PULL_STATE         0x0
+ *   05:04 OUTPUT_PAD_STRENGTH       0x1
+ *   03    SCHMIT_TRIGER             1
+ *   02:00 MUX_SELECT                0x0
+ * </pre>
+ */
+#define IO_CTRL_FASTWR_4_ADDR        (REG_IO_CTRL_BASE_ADDR + 0x00000104)
+#define IO_CTRL_FASTWR_4_OFFSET      0x00000104
+#define IO_CTRL_FASTWR_4_INDEX       0x00000041
+#define IO_CTRL_FASTWR_4_RESET       0x00000318
+
+static inline void io_ctrl_fastwr_4_set(struct cl_chip *chip, u32 value)
+{
+       cl_reg_write_chip(chip, IO_CTRL_FASTWR_4_ADDR, value);
+}
+
+/*
+ * @brief FASTWR_3 register definition
+ * <pre>
+ *  Bits           Field Name   Reset Value
+ * -----   ------------------   -----------
+ *   13    GPIO_IN                   0
+ *   12    GPIO_OUT                  0
+ *   11    GPIO_OE                   0
+ *   10    GPIO_ENABLE               0
+ *   09    input_enable              1
+ *   08    SLEW_RATE                 1
+ *   07:06 DRIVER_PULL_STATE         0x0
+ *   05:04 OUTPUT_PAD_STRENGTH       0x1
+ *   03    SCHMIT_TRIGER             1
+ *   02:00 MUX_SELECT                0x0
+ * </pre>
+ */
+#define IO_CTRL_FASTWR_3_ADDR        (REG_IO_CTRL_BASE_ADDR + 0x00000108)
+#define IO_CTRL_FASTWR_3_OFFSET      0x00000108
+#define IO_CTRL_FASTWR_3_INDEX       0x00000042
+#define IO_CTRL_FASTWR_3_RESET       0x00000318
+
+static inline void io_ctrl_fastwr_3_set(struct cl_chip *chip, u32 value)
+{
+       cl_reg_write_chip(chip, IO_CTRL_FASTWR_3_ADDR, value);
+}
+
+/*
+ * @brief FASTWR_2 register definition
+ * <pre>
+ *  Bits           Field Name   Reset Value
+ * -----   ------------------   -----------
+ *   13    GPIO_IN                   0
+ *   12    GPIO_OUT                  0
+ *   11    GPIO_OE                   0
+ *   10    GPIO_ENABLE               0
+ *   09    input_enable              1
+ *   08    SLEW_RATE                 1
+ *   07:06 DRIVER_PULL_STATE         0x0
+ *   05:04 OUTPUT_PAD_STRENGTH       0x1
+ *   03    SCHMIT_TRIGER             1
+ *   02:00 MUX_SELECT                0x0
+ * </pre>
+ */
+#define IO_CTRL_FASTWR_2_ADDR        (REG_IO_CTRL_BASE_ADDR + 0x0000010C)
+#define IO_CTRL_FASTWR_2_OFFSET      0x0000010C
+#define IO_CTRL_FASTWR_2_INDEX       0x00000043
+#define IO_CTRL_FASTWR_2_RESET       0x00000318
+
+static inline void io_ctrl_fastwr_2_set(struct cl_chip *chip, u32 value)
+{
+       cl_reg_write_chip(chip, IO_CTRL_FASTWR_2_ADDR, value);
+}
+
+/*
+ * @brief FASTWR_1 register definition
+ * <pre>
+ *  Bits           Field Name   Reset Value
+ * -----   ------------------   -----------
+ *   13    GPIO_IN                   0
+ *   12    GPIO_OUT                  0
+ *   11    GPIO_OE                   0
+ *   10    GPIO_ENABLE               0
+ *   09    input_enable              1
+ *   08    SLEW_RATE                 1
+ *   07:06 DRIVER_PULL_STATE         0x0
+ *   05:04 OUTPUT_PAD_STRENGTH       0x1
+ *   03    SCHMIT_TRIGER             1
+ *   02:00 MUX_SELECT                0x0
+ * </pre>
+ */
+#define IO_CTRL_FASTWR_1_ADDR        (REG_IO_CTRL_BASE_ADDR + 0x00000110)
+#define IO_CTRL_FASTWR_1_OFFSET      0x00000110
+#define IO_CTRL_FASTWR_1_INDEX       0x00000044
+#define IO_CTRL_FASTWR_1_RESET       0x00000318
+
+static inline void io_ctrl_fastwr_1_set(struct cl_chip *chip, u32 value)
+{
+       cl_reg_write_chip(chip, IO_CTRL_FASTWR_1_ADDR, value);
+}
+
+
+/*
+ * @brief FASTWR_0 register definition
+ * <pre>
+ *  Bits           Field Name   Reset Value
+ * -----   ------------------   -----------
+ *   13    GPIO_IN                   0
+ *   12    GPIO_OUT                  0
+ *   11    GPIO_OE                   0
+ *   10    GPIO_ENABLE               0
+ *   09    input_enable              1
+ *   08    SLEW_RATE                 1
+ *   07:06 DRIVER_PULL_STATE         0x0
+ *   05:04 OUTPUT_PAD_STRENGTH       0x1
+ *   03    SCHMIT_TRIGER             1
+ *   02:00 MUX_SELECT                0x0
+ * </pre>
+ */
+#define IO_CTRL_FASTWR_0_ADDR        (REG_IO_CTRL_BASE_ADDR + 0x00000114)
+#define IO_CTRL_FASTWR_0_OFFSET      0x00000114
+#define IO_CTRL_FASTWR_0_INDEX       0x00000045
+#define IO_CTRL_FASTWR_0_RESET       0x00000318
+
+static inline void io_ctrl_fastwr_0_set(struct cl_chip *chip, u32 value)
+{
+       cl_reg_write_chip(chip, IO_CTRL_FASTWR_0_ADDR, value);
+}
+
+#endif /* CL_REG_IO_CTRL_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.
________________________________


^ permalink raw reply related	[flat|nested] 262+ messages in thread

* [RFC v1 154/256] cl8k: add reg/reg_ipc.h
  2021-06-17 15:58 [RFC v1 000/256] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (152 preceding siblings ...)
  2021-06-17 16:00 ` [RFC v1 153/256] cl8k: add reg/reg_io_ctrl.h viktor.barna
@ 2021-06-17 16:00 ` viktor.barna
  2021-06-17 16:00 ` [RFC v1 155/256] cl8k: add reg/reg_lcu_common.h viktor.barna
                   ` (103 subsequent siblings)
  257 siblings, 0 replies; 262+ messages in thread
From: viktor.barna @ 2021-06-17 16:00 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Oleksandr Savchenko, Shay Bar, Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

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

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 .../net/wireless/celeno/cl8k/reg/reg_ipc.h    | 157 ++++++++++++++++++
 1 file changed, 157 insertions(+)
 create mode 100644 drivers/net/wireless/celeno/cl8k/reg/reg_ipc.h

diff --git a/drivers/net/wireless/celeno/cl8k/reg/reg_ipc.h b/drivers/net/wireless/celeno/cl8k/reg/reg_ipc.h
new file mode 100644
index 000000000000..d825b8559aae
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/reg/reg_ipc.h
@@ -0,0 +1,157 @@
+/* SPDX-License-Identifier: MIT */
+/* Copyright(c) 2019-2021, Celeno Communications Ltd. */
+
+#ifndef CL_REG_IPC_H
+#define CL_REG_IPC_H
+
+#include <linux/types.h>
+#include "reg/reg_access.h"
+#include "chip.h"
+
+#define REG_IPC_BASE_ADDR 0x007C4000
+
+/*
+ * @brief XMAC_2_HOST_RAW_STATUS register definition
+ * <pre>
+ *   Bits           Field Name   Reset Value
+ *  -----   ------------------   -----------
+ *    31:00 xmac2host_raw_status      0x0
+ * </pre>
+ */
+#define IPC_XMAC_2_HOST_RAW_STATUS_ADDR        (REG_IPC_BASE_ADDR + 0x00000004)
+#define IPC_XMAC_2_HOST_RAW_STATUS_OFFSET      0x00000004
+#define IPC_XMAC_2_HOST_RAW_STATUS_INDEX       0x00000001
+#define IPC_XMAC_2_HOST_RAW_STATUS_RESET       0x00000000
+
+static inline u32 ipc_xmac_2_host_raw_status_get(struct cl_chip *chip)
+{
+       return cl_reg_read_chip(chip, IPC_XMAC_2_HOST_RAW_STATUS_ADDR);
+}
+
+/*
+ * @brief XMAC_2_HOST_ACK register definition
+ * <pre>
+ *   Bits           Field Name   Reset Value
+ *  -----   ------------------   -----------
+ *    31:00 xmac2host_trigger_clr     0x0
+ * </pre>
+ */
+#define IPC_XMAC_2_HOST_ACK_ADDR        (REG_IPC_BASE_ADDR + 0x00000008)
+#define IPC_XMAC_2_HOST_ACK_OFFSET      0x00000008
+#define IPC_XMAC_2_HOST_ACK_INDEX       0x00000002
+#define IPC_XMAC_2_HOST_ACK_RESET       0x00000000
+
+static inline void ipc_xmac_2_host_ack_set(struct cl_chip *chip, u32 value)
+{
+       cl_reg_write_chip(chip, IPC_XMAC_2_HOST_ACK_ADDR, value);
+}
+
+/*
+ * @brief XMAC_2_HOST_ENABLE_SET register definition
+ * <pre>
+ *   Bits           Field Name   Reset Value
+ *  -----   ------------------   -----------
+ *    31:00 xmac2host_enable_set      0x0
+ * </pre>
+ */
+#define IPC_XMAC_2_HOST_ENABLE_SET_ADDR        (REG_IPC_BASE_ADDR + 0x0000000C)
+#define IPC_XMAC_2_HOST_ENABLE_SET_OFFSET      0x0000000C
+#define IPC_XMAC_2_HOST_ENABLE_SET_INDEX       0x00000003
+#define IPC_XMAC_2_HOST_ENABLE_SET_RESET       0x00000000
+
+static inline void ipc_xmac_2_host_enable_set_set(struct cl_chip *chip, u32 value)
+{
+       cl_reg_write_chip(chip, IPC_XMAC_2_HOST_ENABLE_SET_ADDR, value);
+}
+
+/*
+ * @brief XMAC_2_HOST_ENABLE_CLEAR register definition
+ * <pre>
+ *   Bits           Field Name   Reset Value
+ *  -----   ------------------   -----------
+ *    31:00 xmac2host_enable_clear    0x0
+ * </pre>
+ */
+#define IPC_XMAC_2_HOST_ENABLE_CLEAR_ADDR        (REG_IPC_BASE_ADDR + 0x00000010)
+#define IPC_XMAC_2_HOST_ENABLE_CLEAR_OFFSET      0x00000010
+#define IPC_XMAC_2_HOST_ENABLE_CLEAR_INDEX       0x00000004
+#define IPC_XMAC_2_HOST_ENABLE_CLEAR_RESET       0x00000000
+
+static inline void ipc_xmac_2_host_enable_clear_set(struct cl_chip *chip, u32 value)
+{
+       cl_reg_write_chip(chip, IPC_XMAC_2_HOST_ENABLE_CLEAR_ADDR, value);
+}
+
+/*
+ * @brief XMAC_2_HOST_STATUS register definition
+ * <pre>
+ *   Bits           Field Name   Reset Value
+ *  -----   ------------------   -----------
+ *    31:00 xmac2host_status          0x0
+ * </pre>
+ */
+#define IPC_XMAC_2_HOST_STATUS_ADDR        (REG_IPC_BASE_ADDR + 0x00000014)
+#define IPC_XMAC_2_HOST_STATUS_OFFSET      0x00000014
+#define IPC_XMAC_2_HOST_STATUS_INDEX       0x00000005
+#define IPC_XMAC_2_HOST_STATUS_RESET       0x00000000
+
+static inline u32 ipc_xmac_2_host_status_get(struct cl_chip *chip)
+{
+       return cl_reg_read_chip(chip, IPC_XMAC_2_HOST_STATUS_ADDR);
+}
+
+/*
+ * @brief HOST_GLOBAL_INT_EN register definition
+ * <pre>
+ *   Bits           Field Name   Reset Value
+ *  -----   ------------------   -----------
+ *    00    master_int_enable         0
+ * </pre>
+ */
+#define IPC_HOST_GLOBAL_INT_EN_ADDR        (REG_IPC_BASE_ADDR + 0x00000030)
+#define IPC_HOST_GLOBAL_INT_EN_OFFSET      0x00000030
+#define IPC_HOST_GLOBAL_INT_EN_INDEX       0x0000000C
+#define IPC_HOST_GLOBAL_INT_EN_RESET       0x00000000
+
+static inline void ipc_host_global_int_en_set(struct cl_chip *chip, u32 value)
+{
+       cl_reg_write_chip(chip, IPC_HOST_GLOBAL_INT_EN_ADDR, value);
+}
+
+/*
+ * @brief HOST_2_LMAC_TRIGGER register definition
+ * <pre>
+ *   Bits           Field Name   Reset Value
+ *  -----   ------------------   -----------
+ *    31:00 host2lmac_trigger         0x0
+ * </pre>
+ */
+#define IPC_HOST_2_LMAC_TRIGGER_ADDR        (REG_IPC_BASE_ADDR + 0x00000080)
+#define IPC_HOST_2_LMAC_TRIGGER_OFFSET      0x00000080
+#define IPC_HOST_2_LMAC_TRIGGER_INDEX       0x00000020
+#define IPC_HOST_2_LMAC_TRIGGER_RESET       0x00000000
+
+static inline void ipc_host_2_lmac_trigger_set(struct cl_chip *chip, u32 value)
+{
+       cl_reg_write_chip(chip, IPC_HOST_2_LMAC_TRIGGER_ADDR, value);
+}
+
+/*
+ * @brief HOST_2_SMAC_TRIGGER register definition
+ * <pre>
+ *   Bits           Field Name   Reset Value
+ *  -----   ------------------   -----------
+ *    31:00 host2smac_trigger         0x0
+ * </pre>
+ */
+#define IPC_HOST_2_SMAC_TRIGGER_ADDR        (REG_IPC_BASE_ADDR + 0x00000088)
+#define IPC_HOST_2_SMAC_TRIGGER_OFFSET      0x00000088
+#define IPC_HOST_2_SMAC_TRIGGER_INDEX       0x00000022
+#define IPC_HOST_2_SMAC_TRIGGER_RESET       0x00000000
+
+static inline void ipc_host_2_smac_trigger_set(struct cl_chip *chip, u32 value)
+{
+       cl_reg_write_chip(chip, IPC_HOST_2_SMAC_TRIGGER_ADDR, value);
+}
+
+#endif /* CL_REG_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.
________________________________


^ permalink raw reply related	[flat|nested] 262+ messages in thread

* [RFC v1 155/256] cl8k: add reg/reg_lcu_common.h
  2021-06-17 15:58 [RFC v1 000/256] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (153 preceding siblings ...)
  2021-06-17 16:00 ` [RFC v1 154/256] cl8k: add reg/reg_ipc.h viktor.barna
@ 2021-06-17 16:00 ` viktor.barna
  2021-06-17 16:00 ` [RFC v1 156/256] cl8k: add reg/reg_lcu_phy.h viktor.barna
                   ` (102 subsequent siblings)
  257 siblings, 0 replies; 262+ messages in thread
From: viktor.barna @ 2021-06-17 16:00 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Oleksandr Savchenko, Shay Bar, Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

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

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 .../wireless/celeno/cl8k/reg/reg_lcu_common.h | 32 +++++++++++++++++++
 1 file changed, 32 insertions(+)
 create mode 100644 drivers/net/wireless/celeno/cl8k/reg/reg_lcu_common.h

diff --git a/drivers/net/wireless/celeno/cl8k/reg/reg_lcu_common.h b/drivers/net/wireless/celeno/cl8k/reg/reg_lcu_common.h
new file mode 100644
index 000000000000..0f4695b7f66f
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/reg/reg_lcu_common.h
@@ -0,0 +1,32 @@
+/* SPDX-License-Identifier: MIT */
+/* Copyright(c) 2019-2021, Celeno Communications Ltd. */
+
+#ifndef REG_LCU_COMMON_H
+#define REG_LCU_COMMON_H
+
+#include <linux/types.h>
+#include "reg/reg_access.h"
+#include "chip.h"
+
+#define REG_LCU_COMMON_BASE_ADDR 0x007CF000
+
+/*
+ * @brief LCU_COMMON_SW_RST register definition
+ *  Software reset register description
+ * <pre>
+ *   Bits           Field Name   Reset Value
+ *  -----   ------------------   -----------
+ *    00    SW_RST                    0
+ * </pre>
+ */
+#define LCU_COMMON_SW_RST_ADDR        (REG_LCU_COMMON_BASE_ADDR + 0x00000048)
+#define LCU_COMMON_SW_RST_OFFSET      0x00000048
+#define LCU_COMMON_SW_RST_INDEX       0x00000012
+#define LCU_COMMON_SW_RST_RESET       0x00000000
+
+static inline void lcu_common_sw_rst_set(struct cl_chip *chip, u32 value)
+{
+       cl_reg_write_chip(chip, LCU_COMMON_SW_RST_ADDR, value);
+}
+
+#endif /* REG_LCU_COMMON_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.
________________________________


^ permalink raw reply related	[flat|nested] 262+ messages in thread

* [RFC v1 156/256] cl8k: add reg/reg_lcu_phy.h
  2021-06-17 15:58 [RFC v1 000/256] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (154 preceding siblings ...)
  2021-06-17 16:00 ` [RFC v1 155/256] cl8k: add reg/reg_lcu_common.h viktor.barna
@ 2021-06-17 16:00 ` viktor.barna
  2021-06-17 16:00 ` [RFC v1 157/256] cl8k: add reg/reg_macdsp_api.h viktor.barna
                   ` (101 subsequent siblings)
  257 siblings, 0 replies; 262+ messages in thread
From: viktor.barna @ 2021-06-17 16:00 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Oleksandr Savchenko, Shay Bar, Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

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

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 .../wireless/celeno/cl8k/reg/reg_lcu_phy.h    | 92 +++++++++++++++++++
 1 file changed, 92 insertions(+)
 create mode 100644 drivers/net/wireless/celeno/cl8k/reg/reg_lcu_phy.h

diff --git a/drivers/net/wireless/celeno/cl8k/reg/reg_lcu_phy.h b/drivers/net/wireless/celeno/cl8k/reg/reg_lcu_phy.h
new file mode 100644
index 000000000000..b59f327ff6a4
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/reg/reg_lcu_phy.h
@@ -0,0 +1,92 @@
+/* SPDX-License-Identifier: MIT */
+/* Copyright(c) 2019-2021, Celeno Communications Ltd. */
+
+#ifndef CL_REG_LCU_PHY_H
+#define CL_REG_LCU_PHY_H
+
+#include <linux/types.h>
+#include "reg/reg_access.h"
+#include "hw.h"
+
+#define REG_LCU_PHY_BASE_ADDR 0x0048E000
+
+/*
+ * @brief LCU_CH_0_STOP register definition
+ * <pre>
+ *   Bits           Field Name   Reset Value
+ *  -----   ------------------   -----------
+ *    00    CH0_STOP                  0
+ * </pre>
+ */
+#define LCU_PHY_LCU_CH_0_STOP_ADDR        (REG_LCU_PHY_BASE_ADDR + 0x00000070)
+#define LCU_PHY_LCU_CH_0_STOP_OFFSET      0x00000070
+#define LCU_PHY_LCU_CH_0_STOP_INDEX       0x0000001C
+#define LCU_PHY_LCU_CH_0_STOP_RESET       0x00000000
+
+static inline void lcu_phy_lcu_ch_0_stop_set(struct cl_hw *cl_hw, u32 value)
+{
+       cl_reg_write(cl_hw, LCU_PHY_LCU_CH_0_STOP_ADDR, value);
+}
+
+/* Field definitions */
+#define LCU_PHY_CH_0_STOP_BIT               ((u32)0x00000001)
+#define LCU_PHY_CH_0_STOP_POS               0
+
+#define LCU_PHY_CH_0_STOP_RST               0x0
+
+static inline void lcu_phy_lcu_ch_0_stop_ch_0_stop_setf(struct cl_hw *cl_hw, u8 ch0stop)
+{
+       ASSERT_ERR((((u32)ch0stop << 0) & ~((u32)0x00000001)) == 0);
+       cl_reg_write(cl_hw, LCU_PHY_LCU_CH_0_STOP_ADDR, (u32)ch0stop << 0);
+}
+
+/*
+ * @brief LCU_CH_1_STOP register definition
+ * <pre>
+ *   Bits           Field Name   Reset Value
+ *  -----   ------------------   -----------
+ *    00    CH1_STOP                  0
+ * </pre>
+ */
+#define LCU_PHY_LCU_CH_1_STOP_ADDR        (REG_LCU_PHY_BASE_ADDR + 0x00000074)
+#define LCU_PHY_LCU_CH_1_STOP_OFFSET      0x00000074
+#define LCU_PHY_LCU_CH_1_STOP_INDEX       0x0000001D
+#define LCU_PHY_LCU_CH_1_STOP_RESET       0x00000000
+
+static inline void lcu_phy_lcu_ch_1_stop_set(struct cl_hw *cl_hw, u32 value)
+{
+       cl_reg_write(cl_hw, LCU_PHY_LCU_CH_1_STOP_ADDR, value);
+}
+
+/* Field definitions */
+#define LCU_PHY_CH_1_STOP_BIT               ((u32)0x00000001)
+#define LCU_PHY_CH_1_STOP_POS               0
+
+#define LCU_PHY_CH_1_STOP_RST               0x0
+
+static inline void lcu_phy_lcu_ch_1_stop_ch_1_stop_setf(struct cl_hw *cl_hw, u8 ch1stop)
+{
+       ASSERT_ERR((((u32)ch1stop << 0) & ~((u32)0x00000001)) == 0);
+       cl_reg_write(cl_hw, LCU_PHY_LCU_CH_1_STOP_ADDR, (u32)ch1stop << 0);
+}
+
+/*
+ * @brief LCU_SW_RST register definition
+ * <pre>
+ *   Bits           Field Name   Reset Value
+ *  -----   ------------------   -----------
+ *    00    SW_RST                    0
+ * </pre>
+ */
+
+#define LCU_PHY_LCU_SW_RST_ADDR        (REG_LCU_PHY_BASE_ADDR + 0x00000154)
+#define LCU_PHY_LCU_SW_RST_OFFSET      0x00000154
+#define LCU_PHY_LCU_SW_RST_INDEX       0x00000055
+#define LCU_PHY_LCU_SW_RST_RESET       0x00000000
+
+static inline void lcu_phy_lcu_sw_rst_set(struct cl_hw *cl_hw, u32 value)
+{
+       cl_reg_write(cl_hw, LCU_PHY_LCU_SW_RST_ADDR, value);
+}
+
+#endif /* CL_REG_LCU_PHY_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.
________________________________


^ permalink raw reply related	[flat|nested] 262+ messages in thread

* [RFC v1 157/256] cl8k: add reg/reg_macdsp_api.h
  2021-06-17 15:58 [RFC v1 000/256] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (155 preceding siblings ...)
  2021-06-17 16:00 ` [RFC v1 156/256] cl8k: add reg/reg_lcu_phy.h viktor.barna
@ 2021-06-17 16:00 ` viktor.barna
  2021-06-17 16:00 ` [RFC v1 158/256] cl8k: add reg/reg_macsys_gcu.h viktor.barna
                   ` (100 subsequent siblings)
  257 siblings, 0 replies; 262+ messages in thread
From: viktor.barna @ 2021-06-17 16:00 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Oleksandr Savchenko, Shay Bar, Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

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

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 .../wireless/celeno/cl8k/reg/reg_macdsp_api.h | 66 +++++++++++++++++++
 1 file changed, 66 insertions(+)
 create mode 100644 drivers/net/wireless/celeno/cl8k/reg/reg_macdsp_api.h

diff --git a/drivers/net/wireless/celeno/cl8k/reg/reg_macdsp_api.h b/drivers/net/wireless/celeno/cl8k/reg/reg_macdsp_api.h
new file mode 100644
index 000000000000..434f963650a2
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/reg/reg_macdsp_api.h
@@ -0,0 +1,66 @@
+/* SPDX-License-Identifier: MIT */
+/* Copyright(c) 2019-2021, Celeno Communications Ltd. */
+
+#ifndef CL_REG_MACDSP_API_H
+#define CL_REG_MACDSP_API_H
+
+#include <linux/types.h>
+#include "reg/reg_access.h"
+#include "hw.h"
+
+/*
+ * @brief CONFIG_SPACE register definition
+ * <pre>
+ *   Bits           Field Name   Reset Value
+ *  -----   ------------------   -----------
+ *    31:26 ActiveAntennaSet          0x0
+ *    25:20 RxCckActiveChain          0x0
+ *    19:14 RxOfdmActiveChain         0x0
+ *    13:08 TxCckActiveChain          0x0
+ *    07:06 Band                      0x0
+ *    05:04 ChannelBandwidth          0x0
+ *    03    OfdmOnly                  0
+ *    02    RxSensingMode             0
+ *    01    UpdateSync                0
+ *    00    StartupSync               0
+ * </pre>
+ */
+#define MACDSP_API_CONFIG_SPACE_ADDR        (REG_MACDSP_API_BASE_ADDR + 0x00000010)
+#define MACDSP_API_CONFIG_SPACE_OFFSET      0x00000010
+#define MACDSP_API_CONFIG_SPACE_INDEX       0x00000004
+#define MACDSP_API_CONFIG_SPACE_RESET       0x00000000
+
+static inline void macdsp_api_config_space_set(struct cl_hw *cl_hw, u32 value)
+{
+       cl_reg_write(cl_hw, MACDSP_API_CONFIG_SPACE_ADDR, value);
+}
+
+/*
+ * @brief INBDPOW_20 register definition
+ * <pre>
+ *   Bits           Field Name   Reset Value
+ *  -----   ------------------   -----------
+ *    31:24 Inbdpow20Pdbm3            0x0
+ *    23:16 Inbdpow20Pdbm2            0x0
+ *    15:08 Inbdpow20Pdbm1            0x0
+ *    07:00 Inbdpow20Pdbm0            0x0
+ * </pre>
+ */
+#define MACDSP_API_INBDPOW_20_ADDR        (REG_MACDSP_API_BASE_ADDR + 0x00000974)
+#define MACDSP_API_INBDPOW_20_OFFSET      0x00000974
+#define MACDSP_API_INBDPOW_20_INDEX       0x0000025D
+#define MACDSP_API_INBDPOW_20_RESET       0x00000000
+
+static inline void macdsp_api_inbdpow_20_unpack(struct cl_hw *cl_hw,
+                                               u8 *inbdpow20pdbm3, u8 *inbdpow20pdbm2,
+                                               u8 *inbdpow20pdbm1, u8 *inbdpow20pdbm0)
+{
+       u32 local_val = cl_reg_read(cl_hw, MACDSP_API_INBDPOW_20_ADDR);
+
+       *inbdpow20pdbm3 = (local_val & ((u32)0xFF000000)) >> 24;
+       *inbdpow20pdbm2 = (local_val & ((u32)0x00FF0000)) >> 16;
+       *inbdpow20pdbm1 = (local_val & ((u32)0x0000FF00)) >> 8;
+       *inbdpow20pdbm0 = (local_val & ((u32)0x000000FF)) >> 0;
+}
+
+#endif /* CL_REG_MACDSP_API_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.
________________________________


^ permalink raw reply related	[flat|nested] 262+ messages in thread

* [RFC v1 158/256] cl8k: add reg/reg_macsys_gcu.h
  2021-06-17 15:58 [RFC v1 000/256] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (156 preceding siblings ...)
  2021-06-17 16:00 ` [RFC v1 157/256] cl8k: add reg/reg_macdsp_api.h viktor.barna
@ 2021-06-17 16:00 ` viktor.barna
  2021-06-17 16:00 ` [RFC v1 159/256] cl8k: add reg/reg_mac_hw.h viktor.barna
                   ` (99 subsequent siblings)
  257 siblings, 0 replies; 262+ messages in thread
From: viktor.barna @ 2021-06-17 16:00 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Oleksandr Savchenko, Shay Bar, Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

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

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 .../wireless/celeno/cl8k/reg/reg_macsys_gcu.h | 94 +++++++++++++++++++
 1 file changed, 94 insertions(+)
 create mode 100644 drivers/net/wireless/celeno/cl8k/reg/reg_macsys_gcu.h

diff --git a/drivers/net/wireless/celeno/cl8k/reg/reg_macsys_gcu.h b/drivers/net/wireless/celeno/cl8k/reg/reg_macsys_gcu.h
new file mode 100644
index 000000000000..41eb196f4b7c
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/reg/reg_macsys_gcu.h
@@ -0,0 +1,94 @@
+/* SPDX-License-Identifier: MIT */
+/* Copyright(c) 2019-2021, Celeno Communications Ltd. */
+
+#ifndef CL_REG_MACSYS_GCU_H
+#define CL_REG_MACSYS_GCU_H
+
+#include <linux/types.h>
+#include "reg/reg_access.h"
+#include "chip.h"
+
+#define REG_MACSYS_GCU_BASE_ADDR 0x007C5000
+#define REG_MACSYS_GCU_COUNT 63
+
+/*
+ * @brief CHIP_VERSION register definition
+ * Chip Version 8000B0 register description
+ * <pre>
+ * Bits           Field Name   Reset Value
+ * -----   ------------------   -----------
+ *  23:08 PRODUCT_ID                0x8000
+ *  07:04 STEP_ID                   0xB
+ *  03:00 REV_ID                    0x0
+ * </pre>
+ */
+#define MACSYS_GCU_CHIP_VERSION_ADDR        (REG_MACSYS_GCU_BASE_ADDR + 0x00000050)
+#define MACSYS_GCU_CHIP_VERSION_OFFSET      0x00000050
+#define MACSYS_GCU_CHIP_VERSION_INDEX       0x00000014
+#define MACSYS_GCU_CHIP_VERSION_RESET       0x008000B0
+
+static inline u32 macsys_gcu_chip_version_get(struct cl_chip *chip)
+{
+       return cl_reg_read_chip(chip, MACSYS_GCU_CHIP_VERSION_ADDR);
+}
+
+/* Field definitions */
+#define MACSYS_GCU_CHIP_VERSION_PRODUCT_ID_MASK  ((u32)0x00FFFF00)
+#define MACSYS_GCU_CHIP_VERSION_PRODUCT_ID_LSB   8
+#define MACSYS_GCU_CHIP_VERSION_PRODUCT_ID_WIDTH ((u32)0x00000010)
+#define MACSYS_GCU_CHIP_VERSION_STEP_ID_MASK     ((u32)0x000000F0)
+#define MACSYS_GCU_CHIP_VERSION_STEP_ID_LSB      4
+#define MACSYS_GCU_CHIP_VERSION_STEP_ID_WIDTH    ((u32)0x00000004)
+#define MACSYS_GCU_CHIP_VERSION_REV_ID_MASK      ((u32)0x0000000F)
+#define MACSYS_GCU_CHIP_VERSION_REV_ID_LSB       0
+#define MACSYS_GCU_CHIP_VERSION_REV_ID_WIDTH     ((u32)0x00000004)
+
+static inline u8 macsys_gcu_chip_version_step_id_getf(struct cl_chip *chip)
+{
+       u32 local_val = cl_reg_read_chip(chip, MACSYS_GCU_CHIP_VERSION_ADDR);
+
+       return ((local_val & ((u32)0x000000F0)) >> 4);
+}
+
+/*
+ * @brief XT_CONTROL register definition
+ * Tensilica control register description
+ * <pre>
+ *  Bits           Field Name   Reset Value
+ * -----   ------------------   -----------
+ *   21    smac_debug_en             0
+ *   20    smac_break_in             0
+ *   19    smac_ocd_halt_on_reset    1
+ *   18    smac_run_stall            0
+ *   17    smac_dreset_n             1
+ *   16    smac_breset_n             0
+ *   13    umac_debug_en             0
+ *   12    umac_break_in             0
+ *   11    umac_ocd_halt_on_reset    1
+ *   10    umac_run_stall            0
+ *   09    umac_dreset_n             1
+ *   08    umac_breset_n             0
+ *   05    lmac_debug_en             0
+ *   04    lmac_break_in             0
+ *   03    lmac_ocd_halt_on_reset    1
+ *   02    lmac_run_stall            0
+ *   01    lmac_dreset_n             1
+ *   00    lmac_breset_n             0
+ * </pre>
+ */
+#define MACSYS_GCU_XT_CONTROL_ADDR        (REG_MACSYS_GCU_BASE_ADDR + 0x000000F0)
+#define MACSYS_GCU_XT_CONTROL_OFFSET      0x000000F0
+#define MACSYS_GCU_XT_CONTROL_INDEX       0x0000003C
+#define MACSYS_GCU_XT_CONTROL_RESET       0x000A0A0A
+
+static inline u32 macsys_gcu_xt_control_get(struct cl_chip *chip)
+{
+       return cl_reg_read_chip(chip, MACSYS_GCU_XT_CONTROL_ADDR);
+}
+
+static inline void macsys_gcu_xt_control_set(struct cl_chip *chip, u32 value)
+{
+       cl_reg_write_chip(chip, MACSYS_GCU_XT_CONTROL_ADDR, value);
+}
+
+#endif /* CL_REG_MACSYS_GCU_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.
________________________________


^ permalink raw reply related	[flat|nested] 262+ messages in thread

* [RFC v1 159/256] cl8k: add reg/reg_mac_hw.h
  2021-06-17 15:58 [RFC v1 000/256] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (157 preceding siblings ...)
  2021-06-17 16:00 ` [RFC v1 158/256] cl8k: add reg/reg_macsys_gcu.h viktor.barna
@ 2021-06-17 16:00 ` viktor.barna
  2021-06-17 16:00 ` [RFC v1 160/256] cl8k: add reg/reg_mac_hw_mu.h viktor.barna
                   ` (98 subsequent siblings)
  257 siblings, 0 replies; 262+ messages in thread
From: viktor.barna @ 2021-06-17 16:00 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Oleksandr Savchenko, Shay Bar, Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

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

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 .../net/wireless/celeno/cl8k/reg/reg_mac_hw.h | 490 ++++++++++++++++++
 1 file changed, 490 insertions(+)
 create mode 100644 drivers/net/wireless/celeno/cl8k/reg/reg_mac_hw.h

diff --git a/drivers/net/wireless/celeno/cl8k/reg/reg_mac_hw.h b/drivers/net/wireless/celeno/cl8k/reg/reg_mac_hw.h
new file mode 100644
index 000000000000..50ee26b2c5fa
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/reg/reg_mac_hw.h
@@ -0,0 +1,490 @@
+/* SPDX-License-Identifier: MIT */
+/* Copyright(c) 2019-2021, Celeno Communications Ltd. */
+
+#ifndef CL_REG_MAC_HW_H
+#define CL_REG_MAC_HW_H
+
+#include <linux/types.h>
+#include "reg/reg_access.h"
+#include "hw.h"
+
+/*
+ * @brief STATE_CNTRL register definition
+ * This register controls the core's state transitions. register description
+ * <pre>
+ *  Bits           Field Name   Reset Value
+ *  -----   ------------------   -----------
+ *   07:04 NEXT_STATE                0x0
+ *   03:00 CURRENT_STATE             0x0
+ * </pre>
+ */
+#define MAC_HW_STATE_CNTRL_ADDR        (REG_MAC_HW_BASE_ADDR + 0x00000038)
+#define MAC_HW_STATE_CNTRL_OFFSET      0x00000038
+#define MAC_HW_STATE_CNTRL_INDEX       0x0000000E
+#define MAC_HW_STATE_CNTRL_RESET       0x00000000
+
+/* Field definitions */
+#define MAC_HW_STATE_CNTRL_NEXT_STATE_MASK     ((u32)0x000000F0)
+#define MAC_HW_STATE_CNTRL_NEXT_STATE_LSB      4
+#define MAC_HW_STATE_CNTRL_NEXT_STATE_WIDTH    ((u32)0x00000004)
+#define MAC_HW_STATE_CNTRL_CURRENT_STATE_MASK  ((u32)0x0000000F)
+#define MAC_HW_STATE_CNTRL_CURRENT_STATE_LSB   0
+#define MAC_HW_STATE_CNTRL_CURRENT_STATE_WIDTH ((u32)0x00000004)
+
+static inline void mac_hw_state_cntrl_next_state_setf(struct cl_hw *cl_hw, u8 nextstate)
+{
+       ASSERT_ERR((((u32)nextstate << 4) & ~((u32)0x000000F0)) == 0);
+       cl_reg_write(cl_hw, MAC_HW_STATE_CNTRL_ADDR,
+                    (cl_reg_read(cl_hw, MAC_HW_STATE_CNTRL_ADDR) & ~((u32)0x000000F0)) | ((u32)nextstate << 4));
+}
+
+/*
+ * @brief MAC_CNTRL_1 register definition
+ * Contains various settings for controlling the operation of the core. register description
+ * <pre>
+ *  Bits           Field Name   Reset Value
+ *  -----   ------------------   -----------
+ *   31    EOF_PAD_FOR_HE            1
+ *   30    EOF_PAD_FOR_VHT           0
+ *   29:28 IMPLICIT_BF_INT_CONF      0x0
+ *   27    DISABLE_BFR_RESP          0
+ *   26    RX_RIFS_EN                0
+ *   25    TSF_MGT_DISABLE           0
+ *   24    TSF_UPDATED_BY_SW         0
+ *   22    MAC_DETECT_UNDERRUN_EN    0
+ *   21    DISABLE_MU_CTS_RESP       0
+ *   20    BQRP_RESP_BY_FW           0
+ *   19    BSRP_RESP_BY_FW           0
+ *   18    ENABLE_NORMAL_ACK_RESP_IN_HE_MU_W_TRIG 0
+ *   17    DISABLE_NORMAL_ACK_RESP_IN_HE_MU_WO_TRIG 0
+ *   16:14 ABGN_MODE                 0x3
+ *   13    KEY_STO_RAM_RESET         0
+ *   12    MIB_TABLE_RESET           0
+ *   11    RATE_CONTROLLER_MPIF      1
+ *   10    DISABLE_BA_RESP           0
+ *   09    DISABLE_CTS_RESP          0
+ *   08    DISABLE_ACK_RESP          0
+ *   07    ACTIVE_CLK_GATING         1
+ *   06    ENABLE_LP_CLK_SWITCH      0
+ *   05    FORCE_MSTA_BA             0
+ *   04    DISABLE_FAST_COMPARE      0
+ *   03    CFP_AWARE                 0
+ *   02    PWR_MGT                   0
+ *   01    AP                        0
+ *   00    BSS_TYPE                  1
+ * </pre>
+ */
+#define MAC_HW_MAC_CNTRL_1_ADDR        (REG_MAC_HW_BASE_ADDR + 0x0000004C)
+#define MAC_HW_MAC_CNTRL_1_OFFSET      0x0000004C
+#define MAC_HW_MAC_CNTRL_1_INDEX       0x00000013
+#define MAC_HW_MAC_CNTRL_1_RESET       0x8000C881
+
+/* Field definitions */
+#define MAC_HW_MAC_CNTRL_1_EOF_PAD_FOR_HE_BIT                           ((u32)0x80000000)
+#define MAC_HW_MAC_CNTRL_1_EOF_PAD_FOR_HE_POS                           31
+#define MAC_HW_MAC_CNTRL_1_EOF_PAD_FOR_VHT_BIT                          ((u32)0x40000000)
+#define MAC_HW_MAC_CNTRL_1_EOF_PAD_FOR_VHT_POS                          30
+#define MAC_HW_MAC_CNTRL_1_IMPLICIT_BF_INT_CONF_MASK                    ((u32)0x30000000)
+#define MAC_HW_MAC_CNTRL_1_IMPLICIT_BF_INT_CONF_LSB                     28
+#define MAC_HW_MAC_CNTRL_1_IMPLICIT_BF_INT_CONF_WIDTH                   ((u32)0x00000002)
+#define MAC_HW_MAC_CNTRL_1_DISABLE_BFR_RESP_BIT                         ((u32)0x08000000)
+#define MAC_HW_MAC_CNTRL_1_DISABLE_BFR_RESP_POS                         27
+#define MAC_HW_MAC_CNTRL_1_RX_RIFS_EN_BIT                               ((u32)0x04000000)
+#define MAC_HW_MAC_CNTRL_1_RX_RIFS_EN_POS                               26
+#define MAC_HW_MAC_CNTRL_1_TSF_MGT_DISABLE_BIT                          ((u32)0x02000000)
+#define MAC_HW_MAC_CNTRL_1_TSF_MGT_DISABLE_POS                          25
+#define MAC_HW_MAC_CNTRL_1_TSF_UPDATED_BY_SW_BIT                        ((u32)0x01000000)
+#define MAC_HW_MAC_CNTRL_1_TSF_UPDATED_BY_SW_POS                        24
+#define MAC_HW_MAC_CNTRL_1_MAC_DETECT_UNDERRUN_EN_BIT                   ((u32)0x00400000)
+#define MAC_HW_MAC_CNTRL_1_MAC_DETECT_UNDERRUN_EN_POS                   22
+#define MAC_HW_MAC_CNTRL_1_DISABLE_MU_CTS_RESP_BIT                      ((u32)0x00200000)
+#define MAC_HW_MAC_CNTRL_1_DISABLE_MU_CTS_RESP_POS                      21
+#define MAC_HW_MAC_CNTRL_1_BQRP_RESP_BY_FW_BIT                          ((u32)0x00100000)
+#define MAC_HW_MAC_CNTRL_1_BQRP_RESP_BY_FW_POS                          20
+#define MAC_HW_MAC_CNTRL_1_BSRP_RESP_BY_FW_BIT                          ((u32)0x00080000)
+#define MAC_HW_MAC_CNTRL_1_BSRP_RESP_BY_FW_POS                          19
+#define MAC_HW_MAC_CNTRL_1_ENABLE_NORMAL_ACK_RESP_IN_HE_MU_W_TRIG_BIT   ((u32)0x00040000)
+#define MAC_HW_MAC_CNTRL_1_ENABLE_NORMAL_ACK_RESP_IN_HE_MU_W_TRIG_POS   18
+#define MAC_HW_MAC_CNTRL_1_DISABLE_NORMAL_ACK_RESP_IN_HE_MU_WO_TRIG_BIT ((u32)0x00020000)
+#define MAC_HW_MAC_CNTRL_1_DISABLE_NORMAL_ACK_RESP_IN_HE_MU_WO_TRIG_POS 17
+#define MAC_HW_MAC_CNTRL_1_ABGN_MODE_MASK                               ((u32)0x0001C000)
+#define MAC_HW_MAC_CNTRL_1_ABGN_MODE_LSB                                14
+#define MAC_HW_MAC_CNTRL_1_ABGN_MODE_WIDTH                              ((u32)0x00000003)
+#define MAC_HW_MAC_CNTRL_1_KEY_STO_RAM_RESET_BIT                        ((u32)0x00002000)
+#define MAC_HW_MAC_CNTRL_1_KEY_STO_RAM_RESET_POS                        13
+#define MAC_HW_MAC_CNTRL_1_MIB_TABLE_RESET_BIT                          ((u32)0x00001000)
+#define MAC_HW_MAC_CNTRL_1_MIB_TABLE_RESET_POS                          12
+#define MAC_HW_MAC_CNTRL_1_RATE_CONTROLLER_MPIF_BIT                     ((u32)0x00000800)
+#define MAC_HW_MAC_CNTRL_1_RATE_CONTROLLER_MPIF_POS                     11
+#define MAC_HW_MAC_CNTRL_1_DISABLE_BA_RESP_BIT                          ((u32)0x00000400)
+#define MAC_HW_MAC_CNTRL_1_DISABLE_BA_RESP_POS                          10
+#define MAC_HW_MAC_CNTRL_1_DISABLE_CTS_RESP_BIT                         ((u32)0x00000200)
+#define MAC_HW_MAC_CNTRL_1_DISABLE_CTS_RESP_POS                         9
+#define MAC_HW_MAC_CNTRL_1_DISABLE_ACK_RESP_BIT                         ((u32)0x00000100)
+#define MAC_HW_MAC_CNTRL_1_DISABLE_ACK_RESP_POS                         8
+#define MAC_HW_MAC_CNTRL_1_ACTIVE_CLK_GATING_BIT                        ((u32)0x00000080)
+#define MAC_HW_MAC_CNTRL_1_ACTIVE_CLK_GATING_POS                        7
+#define MAC_HW_MAC_CNTRL_1_ENABLE_LP_CLK_SWITCH_BIT                     ((u32)0x00000040)
+#define MAC_HW_MAC_CNTRL_1_ENABLE_LP_CLK_SWITCH_POS                     6
+#define MAC_HW_MAC_CNTRL_1_FORCE_MSTA_BA_BIT                            ((u32)0x00000020)
+#define MAC_HW_MAC_CNTRL_1_FORCE_MSTA_BA_POS                            5
+#define MAC_HW_MAC_CNTRL_1_DISABLE_FAST_COMPARE_BIT                     ((u32)0x00000010)
+#define MAC_HW_MAC_CNTRL_1_DISABLE_FAST_COMPARE_POS                     4
+#define MAC_HW_MAC_CNTRL_1_CFP_AWARE_BIT                                ((u32)0x00000008)
+#define MAC_HW_MAC_CNTRL_1_CFP_AWARE_POS                                3
+#define MAC_HW_MAC_CNTRL_1_PWR_MGT_BIT                                  ((u32)0x00000004)
+#define MAC_HW_MAC_CNTRL_1_PWR_MGT_POS                                  2
+#define MAC_HW_MAC_CNTRL_1_AP_BIT                                       ((u32)0x00000002)
+#define MAC_HW_MAC_CNTRL_1_AP_POS                                       1
+#define MAC_HW_MAC_CNTRL_1_BSS_TYPE_BIT                                 ((u32)0x00000001)
+#define MAC_HW_MAC_CNTRL_1_BSS_TYPE_POS                                 0
+
+static inline void mac_hw_mac_cntrl_1_active_clk_gating_setf(struct cl_hw *cl_hw, u8 activeclkgating)
+{
+       ASSERT_ERR((((u32)activeclkgating << 7) & ~((u32)0x00000080)) == 0);
+       cl_reg_write(cl_hw, MAC_HW_MAC_CNTRL_1_ADDR,
+                    (cl_reg_read(cl_hw, MAC_HW_MAC_CNTRL_1_ADDR) & ~((u32)0x00000080)) | ((u32)activeclkgating << 7));
+}
+
+/*
+ * @brief EDCA_CCA_BUSY register definition
+ * Indicates the CCA busy time. register description
+ * <pre>
+ *  Bits           Field Name   Reset Value
+ *  -----   ------------------   -----------
+ *   31:00 CCA_BUSY_DUR              0x0
+ * </pre>
+ */
+#define MAC_HW_EDCA_CCA_BUSY_ADDR        (REG_MAC_HW_BASE_ADDR + 0x00000220)
+#define MAC_HW_EDCA_CCA_BUSY_OFFSET      0x00000220
+#define MAC_HW_EDCA_CCA_BUSY_INDEX       0x00000088
+#define MAC_HW_EDCA_CCA_BUSY_RESET       0x00000000
+
+static inline u32 mac_hw_edca_cca_busy_get(struct cl_hw *cl_hw)
+{
+       return cl_reg_read(cl_hw, MAC_HW_EDCA_CCA_BUSY_ADDR);
+}
+
+/*
+ * @brief RX_MINE_BUSY register definition
+ * RX Busy time by my frames counter register description
+ * <pre>
+ *  Bits           Field Name   Reset Value
+ *  -----   ------------------   -----------
+ *   31:00 rx_mine_time              0x0
+ * </pre>
+ */
+#define MAC_HW_RX_MINE_BUSY_ADDR        (REG_MAC_HW_BASE_ADDR + 0x00000234)
+#define MAC_HW_RX_MINE_BUSY_OFFSET      0x00000234
+#define MAC_HW_RX_MINE_BUSY_INDEX       0x0000008D
+#define MAC_HW_RX_MINE_BUSY_RESET       0x00000000
+
+static inline u32 mac_hw_rx_mine_busy_get(struct cl_hw *cl_hw)
+{
+       return cl_reg_read(cl_hw, MAC_HW_RX_MINE_BUSY_ADDR);
+}
+
+/*
+ * @brief TX_MINE_BUSY register definition
+ * TX BUSY time by my TX frames register description
+ * <pre>
+ *  Bits           Field Name   Reset Value
+ *  -----   ------------------   -----------
+ *   31:00 TX_MINE_TIME              0x0
+ * </pre>
+ */
+#define MAC_HW_TX_MINE_BUSY_ADDR        (REG_MAC_HW_BASE_ADDR + 0x00000238)
+#define MAC_HW_TX_MINE_BUSY_OFFSET      0x00000238
+#define MAC_HW_TX_MINE_BUSY_INDEX       0x0000008E
+#define MAC_HW_TX_MINE_BUSY_RESET       0x00000000
+
+static inline u32 mac_hw_tx_mine_busy_get(struct cl_hw *cl_hw)
+{
+       return cl_reg_read(cl_hw, MAC_HW_TX_MINE_BUSY_ADDR);
+}
+
+/*
+ * @brief EDCA_NAV_BUSY register definition
+ * Indicates the NAV busy time register description
+ * <pre>
+ *  Bits           Field Name   Reset Value
+ *  -----   ------------------   -----------
+ *   31:00 NAV_BUSY_DUR              0x0
+ * </pre>
+ */
+#define MAC_HW_EDCA_NAV_BUSY_ADDR        (REG_MAC_HW_BASE_ADDR + 0x00000248)
+#define MAC_HW_EDCA_NAV_BUSY_OFFSET      0x00000248
+#define MAC_HW_EDCA_NAV_BUSY_INDEX       0x00000092
+#define MAC_HW_EDCA_NAV_BUSY_RESET       0x00000000
+
+static inline u32 mac_hw_edca_nav_busy_get(struct cl_hw *cl_hw)
+{
+       return cl_reg_read(cl_hw, MAC_HW_EDCA_NAV_BUSY_ADDR);
+}
+
+/*
+ * @brief ADD_CCA_BUSY_SEC_20 register definition
+ * Indicates the CCA on Secondary 20MHz busy time. register description
+ * <pre>
+ *  Bits           Field Name   Reset Value
+ *  -----   ------------------   -----------
+ *   31:00 CCA_BUSY_DUR_SEC_20       0x0
+ * </pre>
+ */
+#define MAC_HW_ADD_CCA_BUSY_SEC_20_ADDR        (REG_MAC_HW_BASE_ADDR + 0x00000290)
+#define MAC_HW_ADD_CCA_BUSY_SEC_20_OFFSET      0x00000290
+#define MAC_HW_ADD_CCA_BUSY_SEC_20_INDEX       0x000000A4
+#define MAC_HW_ADD_CCA_BUSY_SEC_20_RESET       0x00000000
+
+static inline u32 mac_hw_add_cca_busy_sec_20_get(struct cl_hw *cl_hw)
+{
+       return cl_reg_read(cl_hw, MAC_HW_ADD_CCA_BUSY_SEC_20_ADDR);
+}
+
+/*
+ * @brief ADD_CCA_BUSY_SEC_40 register definition
+ * Indicates the CCA on Secondary 40MHz busy time. register description
+ * <pre>
+ *  Bits           Field Name   Reset Value
+ *  -----   ------------------   -----------
+ *   31:00 CCA_BUSY_DUR_SEC_40       0x0
+ * </pre>
+ */
+#define MAC_HW_ADD_CCA_BUSY_SEC_40_ADDR        (REG_MAC_HW_BASE_ADDR + 0x00000294)
+#define MAC_HW_ADD_CCA_BUSY_SEC_40_OFFSET      0x00000294
+#define MAC_HW_ADD_CCA_BUSY_SEC_40_INDEX       0x000000A5
+#define MAC_HW_ADD_CCA_BUSY_SEC_40_RESET       0x00000000
+
+static inline u32 mac_hw_add_cca_busy_sec_40_get(struct cl_hw *cl_hw)
+{
+       return cl_reg_read(cl_hw, MAC_HW_ADD_CCA_BUSY_SEC_40_ADDR);
+}
+
+/*
+ * @brief ADD_CCA_BUSY_SEC_80 register definition
+ * Indicates the CCA on Secondary 80MHz busy time. register description
+ * <pre>
+ *  Bits           Field Name   Reset Value
+ *  -----   ------------------   -----------
+ *   31:00 CCA_BUSY_DUR_SEC_80       0x0
+ * </pre>
+ */
+#define MAC_HW_ADD_CCA_BUSY_SEC_80_ADDR        (REG_MAC_HW_BASE_ADDR + 0x00000298)
+#define MAC_HW_ADD_CCA_BUSY_SEC_80_OFFSET      0x00000298
+#define MAC_HW_ADD_CCA_BUSY_SEC_80_INDEX       0x000000A6
+#define MAC_HW_ADD_CCA_BUSY_SEC_80_RESET       0x00000000
+
+static inline u32 mac_hw_add_cca_busy_sec_80_get(struct cl_hw *cl_hw)
+{
+       return cl_reg_read(cl_hw, MAC_HW_ADD_CCA_BUSY_SEC_80_ADDR);
+}
+
+/*
+ * @brief INTRA_BSS_NAV_BUSY register definition
+ * Count intra BSS NAV busy period register description
+ * <pre>
+ *  Bits           Field Name   Reset Value
+ *  -----   ------------------   -----------
+ *   31:00 INTRA_BSS_NAV_BUSY_DUR    0x0
+ * </pre>
+ */
+#define MAC_HW_INTRA_BSS_NAV_BUSY_ADDR        (REG_MAC_HW_BASE_ADDR + 0x00000408)
+#define MAC_HW_INTRA_BSS_NAV_BUSY_OFFSET      0x00000408
+#define MAC_HW_INTRA_BSS_NAV_BUSY_INDEX       0x00000102
+#define MAC_HW_INTRA_BSS_NAV_BUSY_RESET       0x00000000
+
+static inline u32 mac_hw_intra_bss_nav_busy_get(struct cl_hw *cl_hw)
+{
+       return cl_reg_read(cl_hw, MAC_HW_INTRA_BSS_NAV_BUSY_ADDR);
+}
+
+/*
+ * @brief INTER_BSS_NAV_BUSY register definition
+ * Count inter BSS NAV busy period register description
+ * <pre>
+ *  Bits           Field Name   Reset Value
+ *  -----   ------------------   -----------
+ *   31:00 INTER_BSS_NAV_BUSY_DUR    0x0
+ * </pre>
+ */
+#define MAC_HW_INTER_BSS_NAV_BUSY_ADDR        (REG_MAC_HW_BASE_ADDR + 0x0000040C)
+#define MAC_HW_INTER_BSS_NAV_BUSY_OFFSET      0x0000040C
+#define MAC_HW_INTER_BSS_NAV_BUSY_INDEX       0x00000103
+#define MAC_HW_INTER_BSS_NAV_BUSY_RESET       0x00000000
+
+static inline u32 mac_hw_inter_bss_nav_busy_get(struct cl_hw *cl_hw)
+{
+       return cl_reg_read(cl_hw, MAC_HW_INTER_BSS_NAV_BUSY_ADDR);
+}
+
+/*
+ * @brief DEBUG_PORT_SEL_A register definition
+ * Used to multiplex different sets of signals on the debug pins. register description
+ * <pre>
+ *  Bits           Field Name   Reset Value
+ *  -----   ------------------   -----------
+ *   15:08 DEBUG_PORT_SEL_1          0x0
+ *   07:00 DEBUG_PORT_SEL_0          0x0
+ * </pre>
+ */
+#define MAC_HW_DEBUG_PORT_SEL_A_ADDR        (REG_MAC_HW_BASE_ADDR + 0x00000510)
+#define MAC_HW_DEBUG_PORT_SEL_A_OFFSET      0x00000510
+#define MAC_HW_DEBUG_PORT_SEL_A_INDEX       0x00000144
+#define MAC_HW_DEBUG_PORT_SEL_A_RESET       0x00000000
+
+static inline u32 mac_hw_debug_port_sel_a_get(struct cl_hw *cl_hw)
+{
+       return cl_reg_read(cl_hw, MAC_HW_DEBUG_PORT_SEL_A_ADDR);
+}
+
+static inline void mac_hw_debug_port_sel_a_set(struct cl_hw *cl_hw, u32 value)
+{
+       cl_reg_write(cl_hw, MAC_HW_DEBUG_PORT_SEL_A_ADDR, value);
+}
+
+/*
+ * @brief DEBUG_PORT_SEL_B register definition
+ * Used to multiplex different sets of signals on the register description
+ * <pre>
+ *  Bits           Field Name   Reset Value
+ *  -----   ------------------   -----------
+ *   15:08 DEBUG_PORT_SEL_3          0x0
+ *   07:00 DEBUG_PORT_SEL_2          0x0
+ * </pre>
+ */
+#define MAC_HW_DEBUG_PORT_SEL_B_ADDR        (REG_MAC_HW_BASE_ADDR + 0x00000530)
+#define MAC_HW_DEBUG_PORT_SEL_B_OFFSET      0x00000530
+#define MAC_HW_DEBUG_PORT_SEL_B_INDEX       0x0000014C
+#define MAC_HW_DEBUG_PORT_SEL_B_RESET       0x00000000
+
+static inline u32 mac_hw_debug_port_sel_b_get(struct cl_hw *cl_hw)
+{
+       return cl_reg_read(cl_hw, MAC_HW_DEBUG_PORT_SEL_B_ADDR);
+}
+
+static inline void mac_hw_debug_port_sel_b_set(struct cl_hw *cl_hw, u32 value)
+{
+       cl_reg_write(cl_hw, MAC_HW_DEBUG_PORT_SEL_B_ADDR, value);
+}
+
+/*
+ * @brief DEBUG_PORT_SEL_C register definition
+ * Used to multiplex different sets of signals on the register description
+ * <pre>
+ *  Bits           Field Name   Reset Value
+ *  -----   ------------------   -----------
+ *   15:08 DEBUG_PORT_SEL_5          0x0
+ *   07:00 DEBUG_PORT_SEL_4          0x0
+ * </pre>
+ */
+#define MAC_HW_DEBUG_PORT_SEL_C_ADDR        (REG_MAC_HW_BASE_ADDR + 0x00000534)
+#define MAC_HW_DEBUG_PORT_SEL_C_OFFSET      0x00000534
+#define MAC_HW_DEBUG_PORT_SEL_C_INDEX       0x0000014D
+#define MAC_HW_DEBUG_PORT_SEL_C_RESET       0x00000000
+
+static inline u32 mac_hw_debug_port_sel_c_get(struct cl_hw *cl_hw)
+{
+       return cl_reg_read(cl_hw, MAC_HW_DEBUG_PORT_SEL_C_ADDR);
+}
+
+static inline void mac_hw_debug_port_sel_c_set(struct cl_hw *cl_hw, u32 value)
+{
+       cl_reg_write(cl_hw, MAC_HW_DEBUG_PORT_SEL_C_ADDR, value);
+}
+
+/*
+ * @brief DEBUG_PORT_EN register definition
+ * Used to determine which debug ports are enabled register description
+ * <pre>
+ *  Bits           Field Name   Reset Value
+ *  -----   ------------------   -----------
+ *   05    EN5                       0
+ *   04    EN4                       0
+ *   03    EN3                       0
+ *   02    EN2                       0
+ *   01    EN1                       0
+ *   00    EN0                       0
+ * </pre>
+ */
+#define MAC_HW_DEBUG_PORT_EN_ADDR        (REG_MAC_HW_BASE_ADDR + 0x00000538)
+#define MAC_HW_DEBUG_PORT_EN_OFFSET      0x00000538
+#define MAC_HW_DEBUG_PORT_EN_INDEX       0x0000014E
+#define MAC_HW_DEBUG_PORT_EN_RESET       0x00000000
+
+static inline u32 mac_hw_debug_port_en_get(struct cl_hw *cl_hw)
+{
+       return cl_reg_read(cl_hw, MAC_HW_DEBUG_PORT_EN_ADDR);
+}
+
+static inline void mac_hw_debug_port_en_set(struct cl_hw *cl_hw, u32 value)
+{
+       cl_reg_write(cl_hw, MAC_HW_DEBUG_PORT_EN_ADDR, value);
+}
+
+/*
+ * @brief DOZE_CNTRL_2 register definition
+ * Contains settings for controlling DOZE state. register description
+ * <pre>
+ *  Bits           Field Name   Reset Value
+ *  -----   ------------------   -----------
+ *   31    WAKE_UP_FROM_DOZE         0
+ *   00    WAKE_UP_SW                1
+ * </pre>
+ */
+#define MAC_HW_DOZE_CNTRL_2_ADDR        (REG_MAC_HW_BASE_ADDR + 0x00008048)
+#define MAC_HW_DOZE_CNTRL_2_OFFSET      0x00008048
+#define MAC_HW_DOZE_CNTRL_2_INDEX       0x00002012
+#define MAC_HW_DOZE_CNTRL_2_RESET       0x00000001
+
+/* Field definitions */
+#define MAC_HW_DOZE_CNTRL_2_WAKE_UP_FROM_DOZE_BIT ((u32)0x80000000)
+#define MAC_HW_DOZE_CNTRL_2_WAKE_UP_FROM_DOZE_POS 31
+#define MAC_HW_DOZE_CNTRL_2_WAKE_UP_SW_BIT        ((u32)0x00000001)
+#define MAC_HW_DOZE_CNTRL_2_WAKE_UP_SW_POS        0
+
+static inline void mac_hw_doze_cntrl_2_wake_up_sw_setf(struct cl_hw *cl_hw, u8 wakeupsw)
+{
+       ASSERT_ERR((((u32)wakeupsw << 0) & ~((u32)0x00000001)) == 0);
+       cl_reg_write(cl_hw, MAC_HW_DOZE_CNTRL_2_ADDR,
+                    (cl_reg_read(cl_hw, MAC_HW_DOZE_CNTRL_2_ADDR) & ~((u32)0x00000001)) | ((u32)wakeupsw << 0));
+}
+
+/*
+ * @brief TSF_LO register definition
+ * Contains the TSF bits. register description
+ * <pre>
+ *  Bits           Field Name   Reset Value
+ *  -----   ------------------   -----------
+ *   31:00 TSF_TIMER_LOW             0x0
+ * </pre>
+ */
+#define MAC_HW_TSF_LO_ADDR        (REG_MAC_HW_BASE_ADDR + 0x000080A4)
+#define MAC_HW_TSF_LO_OFFSET      0x000080A4
+#define MAC_HW_TSF_LO_INDEX       0x00002029
+#define MAC_HW_TSF_LO_RESET       0x00000000
+
+static inline u32 mac_hw_tsf_lo_get(struct cl_hw *cl_hw)
+{
+       return cl_reg_read(cl_hw, MAC_HW_TSF_LO_ADDR);
+}
+
+/*
+ * @brief TSF_HI register definition
+ * Contains the TSF bits. register description
+ * <pre>
+ *  Bits           Field Name   Reset Value
+ *  -----   ------------------   -----------
+ *   31:00 TSF_TIMER_HIGH            0x0
+ * </pre>
+ */
+#define MAC_HW_TSF_HI_ADDR        (REG_MAC_HW_BASE_ADDR + 0x000080A8)
+#define MAC_HW_TSF_HI_OFFSET      0x000080A8
+#define MAC_HW_TSF_HI_INDEX       0x0000202A
+#define MAC_HW_TSF_HI_RESET       0x00000000
+
+static inline u32 mac_hw_tsf_hi_get(struct cl_hw *cl_hw)
+{
+       return cl_reg_read(cl_hw, MAC_HW_TSF_HI_ADDR);
+}
+
+#endif /*CL_REG_MAC_HW_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.
________________________________


^ permalink raw reply related	[flat|nested] 262+ messages in thread

* [RFC v1 160/256] cl8k: add reg/reg_mac_hw_mu.h
  2021-06-17 15:58 [RFC v1 000/256] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (158 preceding siblings ...)
  2021-06-17 16:00 ` [RFC v1 159/256] cl8k: add reg/reg_mac_hw.h viktor.barna
@ 2021-06-17 16:00 ` viktor.barna
  2021-06-17 16:00 ` [RFC v1 161/256] cl8k: add reg/reg_modem_gcu.h viktor.barna
                   ` (97 subsequent siblings)
  257 siblings, 0 replies; 262+ messages in thread
From: viktor.barna @ 2021-06-17 16:00 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Oleksandr Savchenko, Shay Bar, Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

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

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 .../wireless/celeno/cl8k/reg/reg_mac_hw_mu.h  | 33 +++++++++++++++++++
 1 file changed, 33 insertions(+)
 create mode 100644 drivers/net/wireless/celeno/cl8k/reg/reg_mac_hw_mu.h

diff --git a/drivers/net/wireless/celeno/cl8k/reg/reg_mac_hw_mu.h b/drivers/net/wireless/celeno/cl8k/reg/reg_mac_hw_mu.h
new file mode 100644
index 000000000000..45368cfc36d6
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/reg/reg_mac_hw_mu.h
@@ -0,0 +1,33 @@
+/* SPDX-License-Identifier: MIT */
+/* Copyright(c) 2019-2021, Celeno Communications Ltd. */
+
+#ifndef CL_REG_MAC_HW_MU_H
+#define CL_REG_MAC_HW_MU_H
+
+#include <linux/types.h>
+#include "reg/reg_access.h"
+#include "hw.h"
+
+#define MU_ADDR_OFFSET(i) ((i) << 16)
+
+/*
+ * @brief MAC_CNTRL_2 register definition
+ * Contains various settings for controlling the operation of the core. register description
+ * <pre>
+ *  Bits           Field Name   Reset Value
+ *  -----   ------------------   -----------
+ *   00    SOFT_RESET                0
+ * </pre>
+ */
+#define MAC_HW_MU_MAC_CNTRL_2_ADDR        (REG_MAC_HW_BASE_ADDR + 0x00008050)
+#define MAC_HW_MU_MAC_CNTRL_2_OFFSET      0x00008050
+#define MAC_HW_MU_MAC_CNTRL_2_INDEX       0x00002014
+#define MAC_HW_MU_MAC_CNTRL_2_RESET       0x00000000
+
+static inline void  mac_hw_mu_mac_cntrl_2_set(struct cl_hw *cl_hw, u32 value, u8 mu_idx)
+{
+       ASSERT_ERR(mu_idx < cl_hw->max_mu_cnt);
+       cl_reg_write(cl_hw, (MAC_HW_MU_MAC_CNTRL_2_ADDR + MU_ADDR_OFFSET(mu_idx)), value);
+}
+
+#endif /* CL_REG_MAC_HW_MU_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.
________________________________


^ permalink raw reply related	[flat|nested] 262+ messages in thread

* [RFC v1 161/256] cl8k: add reg/reg_modem_gcu.h
  2021-06-17 15:58 [RFC v1 000/256] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (159 preceding siblings ...)
  2021-06-17 16:00 ` [RFC v1 160/256] cl8k: add reg/reg_mac_hw_mu.h viktor.barna
@ 2021-06-17 16:00 ` viktor.barna
  2021-06-17 16:00 ` [RFC v1 162/256] cl8k: add reg/reg_otp_pvt.h viktor.barna
                   ` (96 subsequent siblings)
  257 siblings, 0 replies; 262+ messages in thread
From: viktor.barna @ 2021-06-17 16:00 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Oleksandr Savchenko, Shay Bar, Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

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

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 .../wireless/celeno/cl8k/reg/reg_modem_gcu.h  | 628 ++++++++++++++++++
 1 file changed, 628 insertions(+)
 create mode 100644 drivers/net/wireless/celeno/cl8k/reg/reg_modem_gcu.h

diff --git a/drivers/net/wireless/celeno/cl8k/reg/reg_modem_gcu.h b/drivers/net/wireless/celeno/cl8k/reg/reg_modem_gcu.h
new file mode 100644
index 000000000000..3073a364acec
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/reg/reg_modem_gcu.h
@@ -0,0 +1,628 @@
+/* SPDX-License-Identifier: MIT */
+/* Copyright(c) 2019-2021, Celeno Communications Ltd. */
+
+#ifndef CL_REG_MODEM_GCU_H
+#define CL_REG_MODEM_GCU_H
+
+#include <linux/types.h>
+#include "reg/reg_access.h"
+#include "hw.h"
+
+#define REG_MODEM_GCU_BASE_ADDR 0x00480000
+
+/*
+ * @brief MPU register definition
+ * <pre>
+ *  Bits           Field Name   Reset Value
+ *  -----   ------------------   -----------
+ *   21    MPU_CLK_F                 0
+ *   20    MPU_REG_CLK_F             0
+ *   13    MPU_CLK_EN                0
+ *   12    MPU_REG_CLK_EN            0
+ *   01    MPU_RST_N                 0
+ *   00    MPU_REG_RST_N             0
+ * </pre>
+ */
+#define MODEM_GCU_MPU_ADDR        (REG_MODEM_GCU_BASE_ADDR + 0x00000004)
+#define MODEM_GCU_MPU_OFFSET      0x00000004
+#define MODEM_GCU_MPU_INDEX       0x00000001
+#define MODEM_GCU_MPU_RESET       0x00000000
+
+static inline void modem_gcu_mpu_set(struct cl_hw *cl_hw, u32 value)
+{
+       cl_reg_write(cl_hw, MODEM_GCU_MPU_ADDR, value);
+}
+
+/* Field definitions */
+#define MODEM_GCU_MPU_CLK_F_BIT         ((u32)0x00200000)
+#define MODEM_GCU_MPU_CLK_F_POS         21
+#define MODEM_GCU_MPU_REG_CLK_F_BIT     ((u32)0x00100000)
+#define MODEM_GCU_MPU_REG_CLK_F_POS     20
+#define MODEM_GCU_MPU_CLK_EN_BIT        ((u32)0x00002000)
+#define MODEM_GCU_MPU_CLK_EN_POS        13
+#define MODEM_GCU_MPU_REG_CLK_EN_BIT    ((u32)0x00001000)
+#define MODEM_GCU_MPU_REG_CLK_EN_POS    12
+#define MODEM_GCU_MPU_RST_N_BIT         ((u32)0x00000002)
+#define MODEM_GCU_MPU_RST_N_POS         1
+#define MODEM_GCU_MPU_REG_RST_N_BIT     ((u32)0x00000001)
+#define MODEM_GCU_MPU_REG_RST_N_POS     0
+
+/*
+ * @brief BPU register definition
+ * <pre>
+ *  Bits           Field Name   Reset Value
+ *  -----   ------------------   -----------
+ *   24    BPUL_RX_CLK_F             0
+ *   23    BPU_CLK_F                 0
+ *   22    BPU_RX_CLK_F              0
+ *   21    BPU_TX_CLK_F              0
+ *   20    BPU_REG_CLK_F             0
+ *   16    BPUL_RX_CLK_EN            0
+ *   15    BPU_CLK_EN                0
+ *   14    BPU_RX_CLK_EN             0
+ *   13    BPU_TX_CLK_EN             0
+ *   12    BPU_REG_CLK_EN            0
+ *   03    BPU_RST_N                 0
+ *   02    BPU_RX_RST_N              0
+ *   01    BPU_TX_RST_N              0
+ *   00    BPU_REG_RST_N             0
+ * </pre>
+ */
+#define MODEM_GCU_BPU_ADDR        (REG_MODEM_GCU_BASE_ADDR + 0x00000008)
+#define MODEM_GCU_BPU_OFFSET      0x00000008
+#define MODEM_GCU_BPU_INDEX       0x00000002
+#define MODEM_GCU_BPU_RESET       0x00000000
+
+static inline void modem_gcu_bpu_set(struct cl_hw *cl_hw, u32 value)
+{
+       cl_reg_write(cl_hw, MODEM_GCU_BPU_ADDR, value);
+}
+
+/* Field definitions */
+#define MODEM_GCU_BPU_BPUL_RX_CLK_F_BIT  ((u32)0x01000000)
+#define MODEM_GCU_BPU_BPUL_RX_CLK_F_POS  24
+#define MODEM_GCU_BPU_CLK_F_BIT          ((u32)0x00800000)
+#define MODEM_GCU_BPU_CLK_F_POS          23
+#define MODEM_GCU_BPU_RX_CLK_F_BIT       ((u32)0x00400000)
+#define MODEM_GCU_BPU_RX_CLK_F_POS       22
+#define MODEM_GCU_BPU_TX_CLK_F_BIT       ((u32)0x00200000)
+#define MODEM_GCU_BPU_TX_CLK_F_POS       21
+#define MODEM_GCU_BPU_REG_CLK_F_BIT      ((u32)0x00100000)
+#define MODEM_GCU_BPU_REG_CLK_F_POS      20
+#define MODEM_GCU_BPU_BPUL_RX_CLK_EN_BIT ((u32)0x00010000)
+#define MODEM_GCU_BPU_BPUL_RX_CLK_EN_POS 16
+#define MODEM_GCU_BPU_CLK_EN_BIT         ((u32)0x00008000)
+#define MODEM_GCU_BPU_CLK_EN_POS         15
+#define MODEM_GCU_BPU_RX_CLK_EN_BIT      ((u32)0x00004000)
+#define MODEM_GCU_BPU_RX_CLK_EN_POS      14
+#define MODEM_GCU_BPU_TX_CLK_EN_BIT      ((u32)0x00002000)
+#define MODEM_GCU_BPU_TX_CLK_EN_POS      13
+#define MODEM_GCU_BPU_REG_CLK_EN_BIT     ((u32)0x00001000)
+#define MODEM_GCU_BPU_REG_CLK_EN_POS     12
+#define MODEM_GCU_BPU_RST_N_BIT          ((u32)0x00000008)
+#define MODEM_GCU_BPU_RST_N_POS          3
+#define MODEM_GCU_BPU_RX_RST_N_BIT       ((u32)0x00000004)
+#define MODEM_GCU_BPU_RX_RST_N_POS       2
+#define MODEM_GCU_BPU_TX_RST_N_BIT       ((u32)0x00000002)
+#define MODEM_GCU_BPU_TX_RST_N_POS       1
+#define MODEM_GCU_BPU_REG_RST_N_BIT      ((u32)0x00000001)
+#define MODEM_GCU_BPU_REG_RST_N_POS      0
+/*
+ * @brief TFU register definition
+ * <pre>
+ *  Bits           Field Name   Reset Value
+ *  -----   ------------------   -----------
+ *   21    TFU_CLK_F                 0
+ *   20    TFU_REG_CLK_F             0
+ *   13    TFU_CLK_EN                0
+ *   12    TFU_REG_CLK_EN            0
+ *   01    TFU_RST_N                 0
+ *   00    TFU_REG_RST_N             0
+ * </pre>
+ */
+#define MODEM_GCU_TFU_ADDR        (REG_MODEM_GCU_BASE_ADDR + 0x0000000C)
+#define MODEM_GCU_TFU_OFFSET      0x0000000C
+#define MODEM_GCU_TFU_INDEX       0x00000003
+#define MODEM_GCU_TFU_RESET       0x00000000
+
+static inline void modem_gcu_tfu_set(struct cl_hw *cl_hw, u32 value)
+{
+       cl_reg_write(cl_hw, MODEM_GCU_TFU_ADDR, value);
+}
+
+/* Field definitions */
+#define MODEM_GCU_TFU_CLK_F_BIT         ((u32)0x00200000)
+#define MODEM_GCU_TFU_CLK_F_POS         21
+#define MODEM_GCU_TFU_REG_CLK_F_BIT     ((u32)0x00100000)
+#define MODEM_GCU_TFU_REG_CLK_F_POS     20
+#define MODEM_GCU_TFU_CLK_EN_BIT        ((u32)0x00002000)
+#define MODEM_GCU_TFU_CLK_EN_POS        13
+#define MODEM_GCU_TFU_REG_CLK_EN_BIT    ((u32)0x00001000)
+#define MODEM_GCU_TFU_REG_CLK_EN_POS    12
+#define MODEM_GCU_TFU_RST_N_BIT         ((u32)0x00000002)
+#define MODEM_GCU_TFU_RST_N_POS         1
+#define MODEM_GCU_TFU_REG_RST_N_BIT     ((u32)0x00000001)
+#define MODEM_GCU_TFU_REG_RST_N_POS     0
+
+/*
+ * @brief SMU register definition
+ * <pre>
+ *  Bits           Field Name   Reset Value
+ *  -----   ------------------   -----------
+ *   21    SMU_CLK_F                 0
+ *   20    SMU_REG_CLK_F             0
+ *   13    SMU_CLK_EN                0
+ *   12    SMU_REG_CLK_EN            0
+ *   01    SMU_RST_N                 0
+ *   00    SMU_REG_RST_N             0
+ * </pre>
+ */
+#define MODEM_GCU_SMU_ADDR        (REG_MODEM_GCU_BASE_ADDR + 0x00000010)
+#define MODEM_GCU_SMU_OFFSET      0x00000010
+#define MODEM_GCU_SMU_INDEX       0x00000004
+#define MODEM_GCU_SMU_RESET       0x00000000
+
+static inline void modem_gcu_smu_set(struct cl_hw *cl_hw, u32 value)
+{
+       cl_reg_write(cl_hw, MODEM_GCU_SMU_ADDR, value);
+}
+
+/* Field definitions */
+#define MODEM_GCU_SMU_CLK_F_BIT         ((u32)0x00200000)
+#define MODEM_GCU_SMU_CLK_F_POS         21
+#define MODEM_GCU_SMU_REG_CLK_F_BIT     ((u32)0x00100000)
+#define MODEM_GCU_SMU_REG_CLK_F_POS     20
+#define MODEM_GCU_SMU_CLK_EN_BIT        ((u32)0x00002000)
+#define MODEM_GCU_SMU_CLK_EN_POS        13
+#define MODEM_GCU_SMU_REG_CLK_EN_BIT    ((u32)0x00001000)
+#define MODEM_GCU_SMU_REG_CLK_EN_POS    12
+#define MODEM_GCU_SMU_RST_N_BIT         ((u32)0x00000002)
+#define MODEM_GCU_SMU_RST_N_POS         1
+#define MODEM_GCU_SMU_REG_RST_N_BIT     ((u32)0x00000001)
+#define MODEM_GCU_SMU_REG_RST_N_POS     0
+
+/*
+ * @brief MUX_FIC register definition
+ * <pre>
+ *  Bits           Field Name   Reset Value
+ *  -----   ------------------   -----------
+ *   20    MUX_FIC_CLK_F             0
+ *   12    MUX_FIC_CLK_EN            0
+ *   01    FIC_MUX_SOFT_RST_N        1
+ *   00    MUX_FIC_RST_N             0
+ * </pre>
+ */
+#define MODEM_GCU_MUX_FIC_ADDR        (REG_MODEM_GCU_BASE_ADDR + 0x00000014)
+#define MODEM_GCU_MUX_FIC_OFFSET      0x00000014
+#define MODEM_GCU_MUX_FIC_INDEX       0x00000005
+#define MODEM_GCU_MUX_FIC_RESET       0x00000002
+
+static inline void modem_gcu_mux_fic_set(struct cl_hw *cl_hw, u32 value)
+{
+       cl_reg_write(cl_hw, MODEM_GCU_MUX_FIC_ADDR, value);
+}
+
+/* Field definitions */
+#define MODEM_GCU_MUX_FIC_CLK_F_BIT      ((u32)0x00100000)
+#define MODEM_GCU_MUX_FIC_CLK_F_POS      20
+#define MODEM_GCU_MUX_FIC_CLK_EN_BIT     ((u32)0x00001000)
+#define MODEM_GCU_MUX_FIC_CLK_EN_POS     12
+#define MODEM_GCU_MUX_FIC_SOFT_RST_N_BIT ((u32)0x00000002)
+#define MODEM_GCU_MUX_FIC_SOFT_RST_N_POS 1
+#define MODEM_GCU_MUX_FIC_RST_N_BIT      ((u32)0x00000001)
+#define MODEM_GCU_MUX_FIC_RST_N_POS      0
+
+/*
+ * @brief MUX_FIC_CONFIG register definition
+ * <pre>
+ *  Bits           Field Name   Reset Value
+ *  -----   ------------------   -----------
+ *   31    FIC_ISOLATED              0
+ *   17    FIC_ISOLATE               0
+ *   16    DISABLE_FIC_MESS          0
+ *   15:08 MUX_FIC_CONFLICT_DELAY_WRITE 0x0
+ *   07:00 MUX_FIC_CONFLICT_DELAY_READ 0x0
+ * </pre>
+ */
+#define MODEM_GCU_MUX_FIC_CONFIG_ADDR        (REG_MODEM_GCU_BASE_ADDR + 0x0000001C)
+#define MODEM_GCU_MUX_FIC_CONFIG_OFFSET      0x0000001C
+#define MODEM_GCU_MUX_FIC_CONFIG_INDEX       0x00000007
+#define MODEM_GCU_MUX_FIC_CONFIG_RESET       0x00000000
+
+static inline void modem_gcu_mux_fic_config_set(struct cl_hw *cl_hw, u32 value)
+{
+       cl_reg_write(cl_hw, MODEM_GCU_MUX_FIC_CONFIG_ADDR, value);
+}
+
+static inline u8 modem_gcu_mux_fic_config_fic_isolate_getf(struct cl_hw *cl_hw)
+{
+       u32 local_val = cl_reg_read(cl_hw, MODEM_GCU_MUX_FIC_CONFIG_ADDR);
+
+       return ((local_val & ((u32)0x00020000)) >> 17);
+}
+
+static inline void modem_gcu_mux_fic_config_fic_isolate_setf(struct cl_hw *cl_hw, u8 ficisolate)
+{
+       ASSERT_ERR((((u32)ficisolate << 17) & ~((u32)0x00020000)) == 0);
+       cl_reg_write(cl_hw, MODEM_GCU_MUX_FIC_CONFIG_ADDR,
+                    (cl_reg_read(cl_hw, MODEM_GCU_MUX_FIC_CONFIG_ADDR) & ~((u32)0x00020000)) | ((u32)ficisolate << 17));
+}
+
+static inline u8 modem_gcu_mux_fic_config_fic_isolated_getf(struct cl_hw *cl_hw)
+{
+       u32 local_val = cl_reg_read(cl_hw, MODEM_GCU_MUX_FIC_CONFIG_ADDR);
+
+       return ((local_val & ((u32)0x80000000)) >> 31);
+}
+
+/*
+ * @brief RIU_RST register definition
+ * <pre>
+ *  Bits           Field Name   Reset Value
+ *  -----   ------------------   -----------
+ *   07    RIUFE_RST_N               0
+ *   06    RIUAGC_RST_N              0
+ *   05    RIU_MDM_B_RST_N           0
+ *   04    RIULB_RST_N               0
+ *   03    RIURC_RST_N               0
+ *   02    RIU_RADAR_RST_N           0
+ *   01    RIU_RST_N                 0
+ *   00    RIU_REG_RST_N             0
+ * </pre>
+ */
+#define MODEM_GCU_RIU_RST_ADDR        (REG_MODEM_GCU_BASE_ADDR + 0x00000020)
+#define MODEM_GCU_RIU_RST_OFFSET      0x00000020
+#define MODEM_GCU_RIU_RST_INDEX       0x00000008
+#define MODEM_GCU_RIU_RST_RESET       0x00000000
+
+static inline void modem_gcu_riu_rst_set(struct cl_hw *cl_hw, u32 value)
+{
+       cl_reg_write(cl_hw, MODEM_GCU_RIU_RST_ADDR, value);
+}
+
+/* Field definitions */
+#define MODEM_GCU_RIU_FE_RST_N_BIT    ((u32)0x00000080)
+#define MODEM_GCU_RIU_FE_RST_N_POS    7
+#define MODEM_GCU_RIU_AGC_RST_N_BIT   ((u32)0x00000040)
+#define MODEM_GCU_RIU_AGC_RST_N_POS   6
+#define MODEM_GCU_RIU_MDM_B_RST_N_BIT ((u32)0x00000020)
+#define MODEM_GCU_RIU_MDM_B_RST_N_POS 5
+#define MODEM_GCU_RIU_LB_RST_N_BIT    ((u32)0x00000010)
+#define MODEM_GCU_RIU_LB_RST_N_POS    4
+#define MODEM_GCU_RIU_RC_RST_N_BIT    ((u32)0x00000008)
+#define MODEM_GCU_RIU_RC_RST_N_POS    3
+#define MODEM_GCU_RIU_RADAR_RST_N_BIT ((u32)0x00000004)
+#define MODEM_GCU_RIU_RADAR_RST_N_POS 2
+#define MODEM_GCU_RIU_RST_N_BIT       ((u32)0x00000002)
+#define MODEM_GCU_RIU_RST_N_POS       1
+#define MODEM_GCU_RIU_REG_RST_N_BIT   ((u32)0x00000001)
+#define MODEM_GCU_RIU_REG_RST_N_POS   0
+
+/*
+ * @brief RIU_CLK register definition
+ * <pre>
+ *  Bits           Field Name   Reset Value
+ *  -----   ------------------   -----------
+ *   31    RIUADC_PWR_CLK_F          0
+ *   30    RIUFEA_5_CLK_F            0
+ *   29    RIUFEA_4_CLK_F            0
+ *   28    RIUFEA_3_CLK_F            0
+ *   27    RIUFEA_2_CLK_F            0
+ *   26    RIUFEA_1_CLK_F            0
+ *   25    RIUFEA_0_CLK_F            0
+ *   24    RIU_MDM_B_TX_CLK_F        0
+ *   23    RIU_MDM_B_RX_CLK_F        0
+ *   22    RIU_MDM_B_CLK_F           0
+ *   21    RIULB_CLK_F               0
+ *   20    RIURC_CLK_F               0
+ *   19    RIU_RADAR_CLK_F           0
+ *   18    RIUAGC_CLK_F              0
+ *   17    RIU_CLK_F                 0
+ *   16    RIU_REG_CLK_F             0
+ *   15    RIUADC_PWR_CLK_EN         0
+ *   14    RIUFEA_5_CLK_EN           0
+ *   13    RIUFEA_4_CLK_EN           0
+ *   12    RIUFEA_3_CLK_EN           0
+ *   11    RIUFEA_2_CLK_EN           0
+ *   10    RIUFEA_1_CLK_EN           0
+ *   09    RIUFEA_0_CLK_EN           0
+ *   08    RIU_MDM_B_TX_CLK_EN       0
+ *   07    RIU_MDM_B_RX_CLK_EN       0
+ *   06    RIU_MDM_B_CLK_EN          0
+ *   05    RIULB_CLK_EN              0
+ *   04    RIURCR_CLK_EN             0
+ *   03    RIU_RADAR_CLK_EN          0
+ *   02    RIUAGC_CLK_EN             0
+ *   01    RIU_CLK_EN                0
+ *   00    RIU_REG_CLK_EN            0
+ * </pre>
+ */
+#define MODEM_GCU_RIU_CLK_ADDR        (REG_MODEM_GCU_BASE_ADDR + 0x00000024)
+#define MODEM_GCU_RIU_CLK_OFFSET      0x00000024
+#define MODEM_GCU_RIU_CLK_INDEX       0x00000009
+#define MODEM_GCU_RIU_CLK_RESET       0x00000000
+
+static inline void modem_gcu_riu_clk_set(struct cl_hw *cl_hw, u32 value)
+{
+       cl_reg_write(cl_hw, MODEM_GCU_RIU_CLK_ADDR, value);
+}
+
+/*
+ * @brief SPU register definition
+ * <pre>
+ *  Bits           Field Name   Reset Value
+ *  -----   ------------------   -----------
+ *   21    SPU_CLK_F                 0
+ *   20    SPU_REG_CLK_F             0
+ *   13    SPU_CLK_EN                0
+ *   12    SPU_REG_CLK_EN            0
+ *   01    SPU_RST_N                 0
+ *   00    SPU_REG_RST_N             0
+ * </pre>
+ */
+#define MODEM_GCU_SPU_ADDR        (REG_MODEM_GCU_BASE_ADDR + 0x00000030)
+#define MODEM_GCU_SPU_OFFSET      0x00000030
+#define MODEM_GCU_SPU_INDEX       0x0000000C
+#define MODEM_GCU_SPU_RESET       0x00000000
+
+static inline void modem_gcu_spu_set(struct cl_hw *cl_hw, u32 value)
+{
+       cl_reg_write(cl_hw, MODEM_GCU_SPU_ADDR, value);
+}
+
+/* Field definitions */
+#define MODEM_GCU_SPU_CLK_F_BIT         ((u32)0x00200000)
+#define MODEM_GCU_SPU_CLK_F_POS         21
+#define MODEM_GCU_SPU_REG_CLK_F_BIT     ((u32)0x00100000)
+#define MODEM_GCU_SPU_REG_CLK_F_POS     20
+#define MODEM_GCU_SPU_CLK_EN_BIT        ((u32)0x00002000)
+#define MODEM_GCU_SPU_CLK_EN_POS        13
+#define MODEM_GCU_SPU_REG_CLK_EN_BIT    ((u32)0x00001000)
+#define MODEM_GCU_SPU_REG_CLK_EN_POS    12
+#define MODEM_GCU_SPU_RST_N_BIT         ((u32)0x00000002)
+#define MODEM_GCU_SPU_RST_N_POS         1
+#define MODEM_GCU_SPU_REG_RST_N_BIT     ((u32)0x00000001)
+#define MODEM_GCU_SPU_REG_RST_N_POS     0
+
+/*
+ * @brief LCU register definition
+ * <pre>
+ *  Bits           Field Name   Reset Value
+ *  -----   ------------------   -----------
+ *   14    LCU_HLF_CLK_EN            0
+ *   13    LCU_CLK_EN                0
+ *   12    LCU_REG_CLK_EN            0
+ *   02    LCU_HLF_RST_N             0
+ *   01    LCU_RST_N                 0
+ *   00    LCU_REG_RST_N             0
+ * </pre>
+ */
+#define MODEM_GCU_LCU_ADDR        (REG_MODEM_GCU_BASE_ADDR + 0x00000034)
+#define MODEM_GCU_LCU_OFFSET      0x00000034
+#define MODEM_GCU_LCU_INDEX       0x0000000D
+#define MODEM_GCU_LCU_RESET       0x00000000
+
+static inline void modem_gcu_lcu_set(struct cl_hw *cl_hw, u32 value)
+{
+       cl_reg_write(cl_hw, MODEM_GCU_LCU_ADDR, value);
+}
+
+/* Field definitions */
+#define MODEM_GCU_LCU_HLF_CLK_EN_BIT    ((u32)0x00004000)
+#define MODEM_GCU_LCU_HLF_CLK_EN_POS    14
+#define MODEM_GCU_LCU_CLK_EN_BIT        ((u32)0x00002000)
+#define MODEM_GCU_LCU_CLK_EN_POS        13
+#define MODEM_GCU_LCU_REG_CLK_EN_BIT    ((u32)0x00001000)
+#define MODEM_GCU_LCU_REG_CLK_EN_POS    12
+#define MODEM_GCU_LCU_HLF_RST_N_BIT     ((u32)0x00000004)
+#define MODEM_GCU_LCU_HLF_RST_N_POS     2
+#define MODEM_GCU_LCU_RST_N_BIT         ((u32)0x00000002)
+#define MODEM_GCU_LCU_RST_N_POS         1
+#define MODEM_GCU_LCU_REG_RST_N_BIT     ((u32)0x00000001)
+#define MODEM_GCU_LCU_REG_RST_N_POS     0
+
+/*
+ * @brief EPA register definition
+ * <pre>
+ *  Bits           Field Name   Reset Value
+ *  -----   ------------------   -----------
+ *   13    EPA_CLK_EN                0
+ *   12    EPA_REG_CLK_EN            0
+ *   01    EPA_RST_N                 0
+ *   00    EPA_REG_RST_N             0
+ * </pre>
+ */
+#define MODEM_GCU_EPA_ADDR        (REG_MODEM_GCU_BASE_ADDR + 0x00000038)
+#define MODEM_GCU_EPA_OFFSET      0x00000038
+#define MODEM_GCU_EPA_INDEX       0x0000000E
+#define MODEM_GCU_EPA_RESET       0x00000000
+
+static inline void modem_gcu_epa_set(struct cl_hw *cl_hw, u32 value)
+{
+       cl_reg_write(cl_hw, MODEM_GCU_EPA_ADDR, value);
+}
+
+/* Field definitions */
+#define MODEM_GCU_EPA_CLK_EN_BIT        ((u32)0x00002000)
+#define MODEM_GCU_EPA_CLK_EN_POS        13
+#define MODEM_GCU_EPA_REG_CLK_EN_BIT    ((u32)0x00001000)
+#define MODEM_GCU_EPA_REG_CLK_EN_POS    12
+#define MODEM_GCU_EPA_RST_N_BIT         ((u32)0x00000002)
+#define MODEM_GCU_EPA_RST_N_POS         1
+#define MODEM_GCU_EPA_REG_RST_N_BIT     ((u32)0x00000001)
+#define MODEM_GCU_EPA_REG_RST_N_POS     0
+
+/*
+ * @brief BF register definition
+ * <pre>
+ *  Bits           Field Name   Reset Value
+ *  -----   ------------------   -----------
+ *   13    BF_CLK_EN                 0
+ *   12    BF_REG_CLK_EN             0
+ *   01    BF_RST_N                  0
+ *   00    BF_REG_RST_N              0
+ * </pre>
+ */
+#define MODEM_GCU_BF_ADDR        (REG_MODEM_GCU_BASE_ADDR + 0x0000003C)
+#define MODEM_GCU_BF_OFFSET      0x0000003C
+#define MODEM_GCU_BF_INDEX       0x0000000F
+#define MODEM_GCU_BF_RESET       0x00000000
+
+static inline void modem_gcu_bf_set(struct cl_hw *cl_hw, u32 value)
+{
+       cl_reg_write(cl_hw, MODEM_GCU_BF_ADDR, value);
+}
+
+/* Field definitions */
+#define MODEM_GCU_BF_CLK_EN_BIT          ((u32)0x00002000)
+#define MODEM_GCU_BF_CLK_EN_POS          13
+#define MODEM_GCU_BF_REG_CLK_EN_BIT      ((u32)0x00001000)
+#define MODEM_GCU_BF_REG_CLK_EN_POS      12
+#define MODEM_GCU_BF_RST_N_BIT           ((u32)0x00000002)
+#define MODEM_GCU_BF_RST_N_POS           1
+#define MODEM_GCU_BF_REG_RST_N_BIT       ((u32)0x00000001)
+#define MODEM_GCU_BF_REG_RST_N_POS       0
+
+/*
+ * @brief RIU_CLK_1 register definition
+ * <pre>
+ *  Bits           Field Name   Reset Value
+ *  -----   ------------------   -----------
+ *   17    RIUFE_EXT_CLK_F           0
+ *   16    RIUFRC_CLK_F              0
+ *   01    RIUFE_EXT_CLK_EN          0
+ *   00    RIUFRC_CLK_EN             0
+ * </pre>
+ */
+#define MODEM_GCU_RIU_CLK_1_ADDR        (REG_MODEM_GCU_BASE_ADDR + 0x00000124)
+#define MODEM_GCU_RIU_CLK_1_OFFSET      0x00000124
+#define MODEM_GCU_RIU_CLK_1_INDEX       0x00000049
+#define MODEM_GCU_RIU_CLK_1_RESET       0x00000000
+
+static inline void modem_gcu_riu_clk_1_set(struct cl_hw *cl_hw, u32 value)
+{
+       cl_reg_write(cl_hw, MODEM_GCU_RIU_CLK_1_ADDR, value);
+}
+
+/*
+ * @brief CEVA_CTRL register definition
+ * <pre>
+ *  Bits           Field Name   Reset Value
+ *  -----   ------------------   -----------
+ *   16    MCCI_ADDR_BASE            0
+ *   14    VINTC                     0
+ *   12    NMI                       0
+ *   10:09 EXT_VOM                   0x0
+ *   08    EXT_PV                    0
+ *   07:06 UIA                       0x0
+ *   05    STOP_SD                   0
+ *   04    MON_STAT                  0
+ *   02    EXTERNAL_WAIT             1
+ *   00    BOOT                      0
+ * </pre>
+ */
+#define MODEM_GCU_CEVA_CTRL_ADDR        (REG_MODEM_GCU_BASE_ADDR + 0x00001004)
+#define MODEM_GCU_CEVA_CTRL_OFFSET      0x00001004
+#define MODEM_GCU_CEVA_CTRL_INDEX       0x00000401
+#define MODEM_GCU_CEVA_CTRL_RESET       0x00000004
+
+static inline u32 modem_gcu_ceva_ctrl_get(struct cl_hw *cl_hw)
+{
+       return cl_reg_read(cl_hw, MODEM_GCU_CEVA_CTRL_ADDR);
+}
+
+static inline void modem_gcu_ceva_ctrl_set(struct cl_hw *cl_hw, u32 value)
+{
+       cl_reg_write(cl_hw, MODEM_GCU_CEVA_CTRL_ADDR, value);
+}
+
+/* Field definitions */
+#define MODEM_GCU_CEVA_CTRL_MCCI_ADDR_BASE_BIT ((u32)0x00010000)
+#define MODEM_GCU_CEVA_CTRL_MCCI_ADDR_BASE_POS 16
+#define MODEM_GCU_CEVA_CTRL_VINTC_BIT          ((u32)0x00004000)
+#define MODEM_GCU_CEVA_CTRL_VINTC_POS          14
+#define MODEM_GCU_CEVA_CTRL_NMI_BIT            ((u32)0x00001000)
+#define MODEM_GCU_CEVA_CTRL_NMI_POS            12
+#define MODEM_GCU_CEVA_CTRL_EXT_VOM_MASK       ((u32)0x00000600)
+#define MODEM_GCU_CEVA_CTRL_EXT_VOM_LSB        9
+#define MODEM_GCU_CEVA_CTRL_EXT_VOM_WIDTH      ((u32)0x00000002)
+#define MODEM_GCU_CEVA_CTRL_EXT_PV_BIT         ((u32)0x00000100)
+#define MODEM_GCU_CEVA_CTRL_EXT_PV_POS         8
+#define MODEM_GCU_CEVA_CTRL_UIA_MASK           ((u32)0x000000C0)
+#define MODEM_GCU_CEVA_CTRL_UIA_LSB            6
+#define MODEM_GCU_CEVA_CTRL_UIA_WIDTH          ((u32)0x00000002)
+#define MODEM_GCU_CEVA_CTRL_STOP_SD_BIT        ((u32)0x00000020)
+#define MODEM_GCU_CEVA_CTRL_STOP_SD_POS        5
+#define MODEM_GCU_CEVA_CTRL_MON_STAT_BIT       ((u32)0x00000010)
+#define MODEM_GCU_CEVA_CTRL_MON_STAT_POS       4
+#define MODEM_GCU_CEVA_CTRL_EXTERNAL_WAIT_BIT  ((u32)0x00000004)
+#define MODEM_GCU_CEVA_CTRL_EXTERNAL_WAIT_POS  2
+#define MODEM_GCU_CEVA_CTRL_BOOT_BIT           ((u32)0x00000001)
+#define MODEM_GCU_CEVA_CTRL_BOOT_POS           0
+
+static inline void modem_gcu_ceva_ctrl_external_wait_setf(struct cl_hw *cl_hw, u8 externalwait)
+{
+       ASSERT_ERR((((u32)externalwait << 2) & ~((u32)0x00000004)) == 0);
+       cl_reg_write(cl_hw, MODEM_GCU_CEVA_CTRL_ADDR,
+                    (cl_reg_read(cl_hw, MODEM_GCU_CEVA_CTRL_ADDR) & ~((u32)0x00000004)) | ((u32)externalwait << 2));
+}
+
+static inline void modem_gcu_ceva_ctrl_boot_setf(struct cl_hw *cl_hw, u8 boot)
+{
+       ASSERT_ERR((((u32)boot << 0) & ~((u32)0x00000001)) == 0);
+       cl_reg_write(cl_hw, MODEM_GCU_CEVA_CTRL_ADDR,
+                    (cl_reg_read(cl_hw, MODEM_GCU_CEVA_CTRL_ADDR) & ~((u32)0x00000001)) | ((u32)boot << 0));
+}
+
+/*
+ * @brief CEVA_VEC register definition
+ * Ceva Vector register description
+ * <pre>
+ *  Bits           Field Name   Reset Value
+ *  -----   ------------------   -----------
+ *   31:00 VECTOR                    0x0
+ * </pre>
+ */
+#define MODEM_GCU_CEVA_VEC_ADDR        (REG_MODEM_GCU_BASE_ADDR + 0x00001008)
+#define MODEM_GCU_CEVA_VEC_OFFSET      0x00001008
+#define MODEM_GCU_CEVA_VEC_INDEX       0x00000402
+#define MODEM_GCU_CEVA_VEC_RESET       0x00000000
+
+static inline void modem_gcu_ceva_vec_set(struct cl_hw *cl_hw, u32 value)
+{
+       cl_reg_write(cl_hw, MODEM_GCU_CEVA_VEC_ADDR, value);
+}
+
+/*
+ * @brief RIU_CLK_BW register definition
+ * RIU clocks BW. register description
+ * <pre>
+ *  Bits           Field Name   Reset Value
+ *  -----   ------------------   -----------
+ *   13    agc_clk_bw                0
+ *   12:10 lb_mem_clk_bw             0x2
+ *   09:08 agc_mem_clk_bw            0x1
+ *   07:06 riu_afe_clk_bw            0x2
+ *   05:04 phyfesync_bw              0x2
+ *   03:02 adcpowclk_bw              0x2
+ *   01:00 riulbgclk_bw              0x2
+ * </pre>
+ */
+#define MODEM_GCU_RIU_CLK_BW_ADDR        (REG_MODEM_GCU_BASE_ADDR + 0x00001240)
+#define MODEM_GCU_RIU_CLK_BW_OFFSET      0x00001240
+#define MODEM_GCU_RIU_CLK_BW_INDEX       0x00000490
+#define MODEM_GCU_RIU_CLK_BW_RESET       0x000009AA
+
+static inline void modem_gcu_riu_clk_bw_set(struct cl_hw *cl_hw, u32 value)
+{
+       cl_reg_write(cl_hw, MODEM_GCU_RIU_CLK_BW_ADDR, value);
+}
+
+static inline void modem_gcu_riu_clk_bw_agc_mem_clk_bw_setf(struct cl_hw *cl_hw, u8 agcmemclkbw)
+{
+       ASSERT_ERR((((u32)agcmemclkbw << 8) & ~((u32)0x00000300)) == 0);
+       cl_reg_write(cl_hw, MODEM_GCU_RIU_CLK_BW_ADDR,
+                    (cl_reg_read(cl_hw, MODEM_GCU_RIU_CLK_BW_ADDR) & ~((u32)0x00000300)) | ((u32)agcmemclkbw << 8));
+}
+
+#endif /* CL_REG_MODEM_GCU_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.
________________________________


^ permalink raw reply related	[flat|nested] 262+ messages in thread

* [RFC v1 162/256] cl8k: add reg/reg_otp_pvt.h
  2021-06-17 15:58 [RFC v1 000/256] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (160 preceding siblings ...)
  2021-06-17 16:00 ` [RFC v1 161/256] cl8k: add reg/reg_modem_gcu.h viktor.barna
@ 2021-06-17 16:00 ` viktor.barna
  2021-06-17 16:00 ` [RFC v1 163/256] cl8k: add reg/reg_ricu.h viktor.barna
                   ` (95 subsequent siblings)
  257 siblings, 0 replies; 262+ messages in thread
From: viktor.barna @ 2021-06-17 16:00 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Oleksandr Savchenko, Shay Bar, Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

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

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 .../wireless/celeno/cl8k/reg/reg_otp_pvt.h    | 219 ++++++++++++++++++
 1 file changed, 219 insertions(+)
 create mode 100644 drivers/net/wireless/celeno/cl8k/reg/reg_otp_pvt.h

diff --git a/drivers/net/wireless/celeno/cl8k/reg/reg_otp_pvt.h b/drivers/net/wireless/celeno/cl8k/reg/reg_otp_pvt.h
new file mode 100644
index 000000000000..18866c1c3710
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/reg/reg_otp_pvt.h
@@ -0,0 +1,219 @@
+/* SPDX-License-Identifier: MIT */
+/* Copyright(c) 2019-2021, Celeno Communications Ltd. */
+
+#ifndef CL_REG_OTP_PVT
+#define CL_REG_OTP_PVT
+
+#include <linux/types.h>
+#include "reg/reg_access.h"
+#include "chip.h"
+
+#define REG_OTP_PVT_BASE_ADDR 0x007C9000
+
+/*
+ * @brief OTP_CMD register definition
+ *  OTP command register description
+ * <pre>
+ *   Bits           Field Name   Reset Value
+ *  -----   ------------------   -----------
+ *    28    OTP_PR_ACC                0
+ *    24    OTP_ABORT_CLR             0
+ *    16    OTP_READY                 1
+ *    12    OTP_WRITE_FAILED          0
+ *    01:00 OTP_CMD                   0x0
+ * </pre>
+ */
+#define OTP_PVT_OTP_CMD_ADDR        (REG_OTP_PVT_BASE_ADDR + 0x00000000)
+#define OTP_PVT_OTP_CMD_OFFSET      0x00000000
+#define OTP_PVT_OTP_CMD_INDEX       0x00000000
+#define OTP_PVT_OTP_CMD_RESET       0x00010000
+
+static inline u8 otp_pvt_otp_cmd_otp_pr_acc_getf(struct cl_chip *chip)
+{
+       u32 local_val = cl_reg_read_chip(chip, OTP_PVT_OTP_CMD_ADDR);
+
+       return ((local_val & ((u32)0x10000000)) >> 28);
+}
+
+static inline u8 otp_pvt_otp_cmd_otp_ready_getf(struct cl_chip *chip)
+{
+       u32 local_val = cl_reg_read_chip(chip, OTP_PVT_OTP_CMD_ADDR);
+
+       return ((local_val & ((u32)0x00010000)) >> 16);
+}
+
+static inline u8 otp_pvt_otp_cmd_otp_write_failed_getf(struct cl_chip *chip)
+{
+       u32 local_val = cl_reg_read_chip(chip, OTP_PVT_OTP_CMD_ADDR);
+
+       return ((local_val & ((u32)0x00001000)) >> 12);
+}
+
+static inline void otp_pvt_otp_cmd_otp_cmd_setf(struct cl_chip *chip, u8 otpcmd)
+{
+       ASSERT_ERR_CHIP((((u32)otpcmd << 0) & ~((u32)0x00000003)) == 0);
+       cl_reg_write_chip(chip, OTP_PVT_OTP_CMD_ADDR,
+                         (cl_reg_read_chip(chip, OTP_PVT_OTP_CMD_ADDR) & ~((u32)0x00000003)) | ((u32)otpcmd << 0));
+}
+
+/*
+ * @brief OTP_READ_VAL register definition
+ *  OTP read value register description
+ * <pre>
+ *   Bits           Field Name   Reset Value
+ *  -----   ------------------   -----------
+ *    31:00 OTP_READ_VAL              0x0
+ * </pre>
+ */
+#define OTP_PVT_OTP_READ_VAL_ADDR        (REG_OTP_PVT_BASE_ADDR + 0x00000004)
+#define OTP_PVT_OTP_READ_VAL_OFFSET      0x00000004
+#define OTP_PVT_OTP_READ_VAL_INDEX       0x00000001
+#define OTP_PVT_OTP_READ_VAL_RESET       0x00000000
+
+static inline u32 otp_pvt_otp_read_val_get(struct cl_chip *chip)
+{
+       return cl_reg_read_chip(chip, OTP_PVT_OTP_READ_VAL_ADDR);
+}
+
+/*
+ * @brief OTP_ADDR register definition
+ *  OTP address register description
+ * <pre>
+ *   Bits           Field Name   Reset Value
+ *  -----   ------------------   -----------
+ *    12:00 OTP_ADDR                  0x0
+ * </pre>
+ */
+#define OTP_PVT_OTP_ADDR_ADDR        (REG_OTP_PVT_BASE_ADDR + 0x00000008)
+#define OTP_PVT_OTP_ADDR_OFFSET      0x00000008
+#define OTP_PVT_OTP_ADDR_INDEX       0x00000002
+#define OTP_PVT_OTP_ADDR_RESET       0x00000000
+
+static inline void otp_pvt_otp_addr_set(struct cl_chip *chip, u32 value)
+{
+       cl_reg_write_chip(chip, OTP_PVT_OTP_ADDR_ADDR, value);
+}
+
+/*
+ * @brief OTP_TIMINGS_1 register definition
+ * <pre>
+ *   Bits           Field Name   Reset Value
+ *  -----   ------------------   -----------
+ *    31:25 otp_t_CPH                 0xa
+ *    24:18 t_PES                     0xa
+ *    17:16 t_UT                      0x0
+ *    15:08 t_RW                      0x15
+ *    07:00 t_CSRT                    0x29
+ * </pre>
+ */
+#define OTP_PVT_OTP_TIMINGS_1_ADDR        (REG_OTP_PVT_BASE_ADDR + 0x0000000C)
+#define OTP_PVT_OTP_TIMINGS_1_OFFSET      0x0000000C
+#define OTP_PVT_OTP_TIMINGS_1_INDEX       0x00000003
+#define OTP_PVT_OTP_TIMINGS_1_RESET       0x14281529
+
+static inline void otp_pvt_otp_timings_1_set(struct cl_chip *chip, u32 value)
+{
+       cl_reg_write_chip(chip, OTP_PVT_OTP_TIMINGS_1_ADDR, value);
+}
+
+/*
+ * @brief OTP_TIMINGS_2 register definition
+ * <pre>
+ *   Bits           Field Name   Reset Value
+ *  -----   ------------------   -----------
+ *    30:26 t_RD                      0x5
+ *    25:16 t_PW                      0x50
+ *    15:08 t_PEH                     0x20
+ *    07:00 t_CPS                     0x20
+ * </pre>
+ */
+#define OTP_PVT_OTP_TIMINGS_2_ADDR        (REG_OTP_PVT_BASE_ADDR + 0x00000010)
+#define OTP_PVT_OTP_TIMINGS_2_OFFSET      0x00000010
+#define OTP_PVT_OTP_TIMINGS_2_INDEX       0x00000004
+#define OTP_PVT_OTP_TIMINGS_2_RESET       0x14502020
+
+static inline void otp_pvt_otp_timings_2_set(struct cl_chip *chip, u32 value)
+{
+       cl_reg_write_chip(chip, OTP_PVT_OTP_TIMINGS_2_ADDR, value);
+}
+
+/*
+ * @brief OTP_WRITE_VAL register definition
+ *  OTP write value register description
+ * <pre>
+ *   Bits           Field Name   Reset Value
+ *  -----   ------------------   -----------
+ *    00    OTP_WRITE_VAL             0
+ * </pre>
+ */
+#define OTP_PVT_OTP_WRITE_VAL_ADDR        (REG_OTP_PVT_BASE_ADDR + 0x00000014)
+#define OTP_PVT_OTP_WRITE_VAL_OFFSET      0x00000014
+#define OTP_PVT_OTP_WRITE_VAL_INDEX       0x00000005
+#define OTP_PVT_OTP_WRITE_VAL_RESET       0x00000000
+
+static inline void otp_pvt_otp_write_val_set(struct cl_chip *chip, u32 value)
+{
+       cl_reg_write_chip(chip, OTP_PVT_OTP_WRITE_VAL_ADDR, value);
+}
+
+/*
+ * @brief OTP_KEY register definition
+ *  OTP key register description
+ * <pre>
+ *   Bits           Field Name   Reset Value
+ *  -----   ------------------   -----------
+ *    31:00 OTP_KEY                   0x0
+ * </pre>
+ */
+#define OTP_PVT_OTP_KEY_ADDR        (REG_OTP_PVT_BASE_ADDR + 0x00000018)
+#define OTP_PVT_OTP_KEY_OFFSET      0x00000018
+#define OTP_PVT_OTP_KEY_INDEX       0x00000006
+#define OTP_PVT_OTP_KEY_RESET       0x00000000
+
+static inline void otp_pvt_otp_key_set(struct cl_chip *chip, u32 value)
+{
+       cl_reg_write_chip(chip, OTP_PVT_OTP_KEY_ADDR, value);
+}
+
+/*
+ * @brief OTP_CLK_DIV register definition
+ *  OTP clock divisor register description
+ * <pre>
+ *   Bits           Field Name   Reset Value
+ *  -----   ------------------   -----------
+ *    08:00 OTP_CLK_DIV               0x1
+ * </pre>
+ */
+#define OTP_PVT_OTP_CLK_DIV_ADDR        (REG_OTP_PVT_BASE_ADDR + 0x0000001C)
+#define OTP_PVT_OTP_CLK_DIV_OFFSET      0x0000001C
+#define OTP_PVT_OTP_CLK_DIV_INDEX       0x00000007
+#define OTP_PVT_OTP_CLK_DIV_RESET       0x00000001
+
+static inline void otp_pvt_otp_clk_div_set(struct cl_chip *chip, u32 value)
+{
+       cl_reg_write_chip(chip, OTP_PVT_OTP_CLK_DIV_ADDR, value);
+}
+
+/*
+ * @brief OTP_PROTECT register definition
+ *  OTP address protection register description
+ * <pre>
+ *   Bits           Field Name   Reset Value
+ *  -----   ------------------   -----------
+ *    01    OTP_PR_DIS                0
+ *    00    OTP_PR_SEL                0
+ * </pre>
+ */
+#define OTP_PVT_OTP_PROTECT_ADDR        (REG_OTP_PVT_BASE_ADDR + 0x00000024)
+#define OTP_PVT_OTP_PROTECT_OFFSET      0x00000024
+#define OTP_PVT_OTP_PROTECT_INDEX       0x00000009
+#define OTP_PVT_OTP_PROTECT_RESET       0x00000000
+
+static inline void otp_pvt_otp_protect_otp_pr_dis_setf(struct cl_chip *chip, u8 otpprdis)
+{
+       ASSERT_ERR_CHIP((((u32)otpprdis << 1) & ~((u32)0x00000002)) == 0);
+       cl_reg_write_chip(chip, OTP_PVT_OTP_PROTECT_ADDR,
+                         (cl_reg_read_chip(chip, OTP_PVT_OTP_PROTECT_ADDR) & ~((u32)0x00000002)) | ((u32)otpprdis << 1));
+}
+
+#endif /* CL_REG_OTP_PVT */
--
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.
________________________________


^ permalink raw reply related	[flat|nested] 262+ messages in thread

* [RFC v1 163/256] cl8k: add reg/reg_ricu.h
  2021-06-17 15:58 [RFC v1 000/256] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (161 preceding siblings ...)
  2021-06-17 16:00 ` [RFC v1 162/256] cl8k: add reg/reg_otp_pvt.h viktor.barna
@ 2021-06-17 16:00 ` viktor.barna
  2021-06-17 16:00 ` [RFC v1 164/256] cl8k: add reg/reg_riu.h viktor.barna
                   ` (94 subsequent siblings)
  257 siblings, 0 replies; 262+ messages in thread
From: viktor.barna @ 2021-06-17 16:00 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Oleksandr Savchenko, Shay Bar, Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

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

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 .../net/wireless/celeno/cl8k/reg/reg_ricu.h   | 1326 +++++++++++++++++
 1 file changed, 1326 insertions(+)
 create mode 100644 drivers/net/wireless/celeno/cl8k/reg/reg_ricu.h

diff --git a/drivers/net/wireless/celeno/cl8k/reg/reg_ricu.h b/drivers/net/wireless/celeno/cl8k/reg/reg_ricu.h
new file mode 100644
index 000000000000..00e4759db751
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/reg/reg_ricu.h
@@ -0,0 +1,1326 @@
+/* SPDX-License-Identifier: MIT */
+/* Copyright(c) 2019-2021, Celeno Communications Ltd. */
+
+#ifndef CL_REG_RICU_H
+#define CL_REG_RICU_H
+
+#include "reg/reg_access.h"
+#include "chip.h"
+
+/*
+ * @brief STATIC_CONF_0 register definition
+ * <pre>
+ *   Bits           Field Name   Reset Value
+ *  -----   ------------------   -----------
+ *    30    ARB_ONESHOT_BYPASS        1
+ *    28    BTC_SEL                   0
+ *    27    CLK_SAVE_MODE             0
+ *    26    RF_RST_N_DEFAULT          0
+ *    25    RF_RST_N_REQ              0
+ *    24    FORCE_RSSI_ON             0
+ *    23:20 RSSI_M                    0x2
+ *    19:16 RSSI_N                    0x6
+ *    03:00 CDB_MODE_MAJ              0x0
+ * </pre>
+ */
+#define RICU_STATIC_CONF_0_ADDR        (REG_RICU_BASE_ADDR + 0x00000004)
+#define RICU_STATIC_CONF_0_OFFSET      0x00000004
+#define RICU_STATIC_CONF_0_INDEX       0x00000001
+#define RICU_STATIC_CONF_0_RESET       0x40260000
+
+static inline void ricu_static_conf_0_btc_sel_setf(struct cl_chip *chip, u8 btcsel)
+{
+       ASSERT_ERR_CHIP((((u32)btcsel << 28) & ~((u32)0x10000000)) == 0);
+       cl_reg_write_chip(chip, RICU_STATIC_CONF_0_ADDR, (cl_reg_read_chip(chip, RICU_STATIC_CONF_0_ADDR) & ~((u32)0x10000000)) | ((u32)btcsel << 28));
+}
+
+static inline void ricu_static_conf_0_rf_rst_n_req_setf(struct cl_chip *chip, u8 rfrstnreq)
+{
+       ASSERT_ERR_CHIP((((u32)rfrstnreq << 25) & ~((u32)0x02000000)) == 0);
+       cl_reg_write_chip(chip, RICU_STATIC_CONF_0_ADDR, (cl_reg_read_chip(chip, RICU_STATIC_CONF_0_ADDR) & ~((u32)0x02000000)) | ((u32)rfrstnreq << 25));
+}
+
+static inline u8 ricu_static_conf_0_cdb_mode_maj_getf(struct cl_chip *chip)
+{
+       u32 local_val = cl_reg_read_chip(chip, RICU_STATIC_CONF_0_ADDR);
+
+       return ((local_val & ((u32)0x0000000F)) >> 0);
+}
+
+static inline void ricu_static_conf_0_cdb_mode_maj_setf(struct cl_chip *chip, u8 cdbmodemaj)
+{
+       ASSERT_ERR_CHIP((((u32)cdbmodemaj << 0) & ~((u32)0x0000000F)) == 0);
+       cl_reg_write_chip(chip, RICU_STATIC_CONF_0_ADDR, (cl_reg_read_chip(chip, RICU_STATIC_CONF_0_ADDR) & ~((u32)0x0000000F)) | ((u32)cdbmodemaj << 0));
+}
+
+/*
+ * @brief AFE_CTL_0 register definition
+ * <pre>
+ *   Bits           Field Name   Reset Value
+ *  -----   ------------------   -----------
+ *    31    PBIAS_CTRL_EN_LC          0
+ *    30    PBIAS_CTRL_EN             0
+ *    29    LRD_EN_LC                 0
+ *    28    LRD_EN                    0
+ *    27    LOCK_EN_LC                0
+ *    26    LOCK_EN                   1
+ *    25    EN_GPADC_CLK              0
+ *    24    EN_GPADC                  0
+ *    23    FEED_EN_LC                0
+ *    22    FEED_EN                   0
+ *    21    EN_CS                     1
+ *    20    EN_CML_GEN                1
+ *    18    EN_AFE_LDO                1
+ *    17    EN_ADC_CLK                1
+ *    15    AFC_ENB_LC                0
+ *    14    AFC_ENB                   0
+ *    13    CP_MODE_LC                1
+ *    12    BYPASS_LC                 0
+ *    11    BYPASS                    0
+ *    10    AFCINIT_SEL_LC            1
+ *    09    AFCINIT_SEL               1
+ *    08    EN_CLK_MON                0
+ *    07    EN_DAC_CLK                1
+ *    06    EN_CDB_DAC_CLK            0
+ *    05    EN_CDB_ADC_CLK            0
+ *    03    EN_CDB_GEN                0
+ *    02    DACCLK_PHASESEL           0
+ *    01    ADCCLK_PHASESEL           0
+ *    00    CDB_CLK_RESETB            0
+ * </pre>
+ */
+#define RICU_AFE_CTL_0_ADDR        (REG_RICU_BASE_ADDR + 0x00000010)
+#define RICU_AFE_CTL_0_OFFSET      0x00000010
+#define RICU_AFE_CTL_0_INDEX       0x00000004
+#define RICU_AFE_CTL_0_RESET       0x04362680
+
+static inline u32 ricu_afe_ctl_0_get(struct cl_chip *chip)
+{
+       return cl_reg_read_chip(chip, RICU_AFE_CTL_0_ADDR);
+}
+
+static inline void ricu_afe_ctl_0_set(struct cl_chip *chip, u32 value)
+{
+       cl_reg_write_chip(chip, RICU_AFE_CTL_0_ADDR, value);
+}
+
+/* Field definitions */
+#define RICU_AFE_CTL_0_PBIAS_CTRL_EN_LC_BIT    ((u32)0x80000000)
+#define RICU_AFE_CTL_0_PBIAS_CTRL_EN_LC_POS    31
+#define RICU_AFE_CTL_0_PBIAS_CTRL_EN_BIT    ((u32)0x40000000)
+#define RICU_AFE_CTL_0_PBIAS_CTRL_EN_POS    30
+#define RICU_AFE_CTL_0_LRD_EN_LC_BIT        ((u32)0x20000000)
+#define RICU_AFE_CTL_0_LRD_EN_LC_POS        29
+#define RICU_AFE_CTL_0_LRD_EN_BIT           ((u32)0x10000000)
+#define RICU_AFE_CTL_0_LRD_EN_POS           28
+#define RICU_AFE_CTL_0_LOCK_EN_LC_BIT       ((u32)0x08000000)
+#define RICU_AFE_CTL_0_LOCK_EN_LC_POS       27
+#define RICU_AFE_CTL_0_LOCK_EN_BIT          ((u32)0x04000000)
+#define RICU_AFE_CTL_0_LOCK_EN_POS          26
+#define RICU_AFE_CTL_0_EN_GPADC_CLK_BIT     ((u32)0x02000000)
+#define RICU_AFE_CTL_0_EN_GPADC_CLK_POS     25
+#define RICU_AFE_CTL_0_EN_GPADC_BIT         ((u32)0x01000000)
+#define RICU_AFE_CTL_0_EN_GPADC_POS         24
+#define RICU_AFE_CTL_0_FEED_EN_LC_BIT       ((u32)0x00800000)
+#define RICU_AFE_CTL_0_FEED_EN_LC_POS       23
+#define RICU_AFE_CTL_0_FEED_EN_BIT          ((u32)0x00400000)
+#define RICU_AFE_CTL_0_FEED_EN_POS          22
+#define RICU_AFE_CTL_0_EN_CS_BIT            ((u32)0x00200000)
+#define RICU_AFE_CTL_0_EN_CS_POS            21
+#define RICU_AFE_CTL_0_EN_CML_GEN_BIT       ((u32)0x00100000)
+#define RICU_AFE_CTL_0_EN_CML_GEN_POS       20
+#define RICU_AFE_CTL_0_EN_AFE_LDO_BIT       ((u32)0x00040000)
+#define RICU_AFE_CTL_0_EN_AFE_LDO_POS       18
+#define RICU_AFE_CTL_0_EN_ADC_CLK_BIT       ((u32)0x00020000)
+#define RICU_AFE_CTL_0_EN_ADC_CLK_POS       17
+#define RICU_AFE_CTL_0_AFC_ENB_LC_BIT       ((u32)0x00008000)
+#define RICU_AFE_CTL_0_AFC_ENB_LC_POS       15
+#define RICU_AFE_CTL_0_AFC_ENB_BIT          ((u32)0x00004000)
+#define RICU_AFE_CTL_0_AFC_ENB_POS          14
+#define RICU_AFE_CTL_0_CP_MODE_LC_BIT       ((u32)0x00002000)
+#define RICU_AFE_CTL_0_CP_MODE_LC_POS       13
+#define RICU_AFE_CTL_0_BYPASS_LC_BIT        ((u32)0x00001000)
+#define RICU_AFE_CTL_0_BYPASS_LC_POS        12
+#define RICU_AFE_CTL_0_BYPASS_BIT           ((u32)0x00000800)
+#define RICU_AFE_CTL_0_BYPASS_POS           11
+#define RICU_AFE_CTL_0_AFCINIT_SEL_LC_BIT    ((u32)0x00000400)
+#define RICU_AFE_CTL_0_AFCINIT_SEL_LC_POS    10
+#define RICU_AFE_CTL_0_AFCINIT_SEL_BIT      ((u32)0x00000200)
+#define RICU_AFE_CTL_0_AFCINIT_SEL_POS      9
+#define RICU_AFE_CTL_0_EN_CLK_MON_BIT       ((u32)0x00000100)
+#define RICU_AFE_CTL_0_EN_CLK_MON_POS       8
+#define RICU_AFE_CTL_0_EN_DAC_CLK_BIT       ((u32)0x00000080)
+#define RICU_AFE_CTL_0_EN_DAC_CLK_POS       7
+#define RICU_AFE_CTL_0_EN_CDB_DAC_CLK_BIT    ((u32)0x00000040)
+#define RICU_AFE_CTL_0_EN_CDB_DAC_CLK_POS    6
+#define RICU_AFE_CTL_0_EN_CDB_ADC_CLK_BIT    ((u32)0x00000020)
+#define RICU_AFE_CTL_0_EN_CDB_ADC_CLK_POS    5
+#define RICU_AFE_CTL_0_EN_CDB_GEN_BIT       ((u32)0x00000008)
+#define RICU_AFE_CTL_0_EN_CDB_GEN_POS       3
+#define RICU_AFE_CTL_0_DACCLK_PHASESEL_BIT    ((u32)0x00000004)
+#define RICU_AFE_CTL_0_DACCLK_PHASESEL_POS    2
+#define RICU_AFE_CTL_0_ADCCLK_PHASESEL_BIT    ((u32)0x00000002)
+#define RICU_AFE_CTL_0_ADCCLK_PHASESEL_POS    1
+#define RICU_AFE_CTL_0_CDB_CLK_RESETB_BIT    ((u32)0x00000001)
+#define RICU_AFE_CTL_0_CDB_CLK_RESETB_POS    0
+
+static inline void ricu_afe_ctl_0_pbias_ctrl_en_lc_setf(struct cl_chip *chip, u8 pbiasctrlenlc)
+{
+       cl_reg_write_chip(chip, RICU_AFE_CTL_0_ADDR, (cl_reg_read_chip(chip, RICU_AFE_CTL_0_ADDR) & ~((u32)0x80000000)) | ((u32)pbiasctrlenlc << 31));
+}
+
+static inline void ricu_afe_ctl_0_cdb_clk_resetb_setf(struct cl_chip *chip, u8 cdbclkresetb)
+{
+       ASSERT_ERR_CHIP((((u32)cdbclkresetb << 0) & ~((u32)0x00000001)) == 0);
+       cl_reg_write_chip(chip, RICU_AFE_CTL_0_ADDR, (cl_reg_read_chip(chip, RICU_AFE_CTL_0_ADDR) & ~((u32)0x00000001)) | ((u32)cdbclkresetb << 0));
+}
+
+/*
+ * @brief AFE_CTL_1 register definition
+ * <pre>
+ *   Bits           Field Name   Reset Value
+ *  -----   ------------------   -----------
+ *    14    VCO_BOOST                 0
+ *    13    SYS_ADCCLK_SEL            0
+ *    12    SOC_PHASE_SEL             1
+ *    11    SOC_CLK_SEL               1
+ *    10    RESETB_LC                 0
+ *    09    RESETB                    1
+ *    08    PBIAS_CTRL_LC             0
+ *    07    PBIAS_CTRL                0
+ *    06    GP_CLK_PHASESEL           0
+ *    05    FSEL_LC                   0
+ *    04    FSEL                      0
+ *    03    FOUT_MASK_LC              0
+ *    02    FOUT_MASK                 0
+ *    01    EXTCLK_SEL                0
+ *    00    EN_PLL_LDO                0
+ * </pre>
+ */
+#define RICU_AFE_CTL_1_ADDR        (REG_RICU_BASE_ADDR + 0x00000014)
+#define RICU_AFE_CTL_1_OFFSET      0x00000014
+#define RICU_AFE_CTL_1_INDEX       0x00000005
+#define RICU_AFE_CTL_1_RESET       0x00001A00
+
+static inline void ricu_afe_ctl_1_resetb_lc_setf(struct cl_chip *chip, u8 resetblc)
+{
+       ASSERT_ERR_CHIP((((u32)resetblc << 10) & ~((u32)0x00000400)) == 0);
+       cl_reg_write_chip(chip, RICU_AFE_CTL_1_ADDR, (cl_reg_read_chip(chip, RICU_AFE_CTL_1_ADDR) & ~((u32)0x00000400)) | ((u32)resetblc << 10));
+}
+
+static inline void ricu_afe_ctl_1_en_pll_ldo_setf(struct cl_chip *chip, u8 enpllldo)
+{
+       ASSERT_ERR_CHIP((((u32)enpllldo << 0) & ~((u32)0x00000001)) == 0);
+       cl_reg_write_chip(chip, RICU_AFE_CTL_1_ADDR, (cl_reg_read_chip(chip, RICU_AFE_CTL_1_ADDR) & ~((u32)0x00000001)) | ((u32)enpllldo << 0));
+}
+
+/*
+ * @brief AFE_CTL_2 register definition
+ * <pre>
+ *   Bits           Field Name   Reset Value
+ *  -----   ------------------   -----------
+ *    23:22 LOCK_CON_REV_LC           0x0
+ *    21:20 LOCK_CON_REV              0x0
+ *    19:18 LOCK_CON_OUT_LC           0x3
+ *    17:16 LOCK_CON_OUT              0x3
+ *    15:14 LOCK_CON_IN_LC            0x3
+ *    13:12 LOCK_CON_IN               0x3
+ *    11:10 LOCK_CON_DLY_LC           0x3
+ *    09:08 LOCK_CON_DLY              0x3
+ *    07:06 ICP                       0x1
+ *    03:02 CTRL_IB                   0x2
+ *    01:00 CLK_MON_SEL               0x0
+ * </pre>
+ */
+#define RICU_AFE_CTL_2_ADDR        (REG_RICU_BASE_ADDR + 0x00000018)
+#define RICU_AFE_CTL_2_OFFSET      0x00000018
+#define RICU_AFE_CTL_2_INDEX       0x00000006
+#define RICU_AFE_CTL_2_RESET       0x000FFF48
+
+static inline void ricu_afe_ctl_2_lock_con_rev_lc_setf(struct cl_chip *chip, u8 lockconrevlc)
+{
+       ASSERT_ERR_CHIP((((u32)lockconrevlc << 22) & ~((u32)0x00C00000)) == 0);
+       cl_reg_write_chip(chip, RICU_AFE_CTL_2_ADDR, (cl_reg_read_chip(chip, RICU_AFE_CTL_2_ADDR) & ~((u32)0x00C00000)) | ((u32)lockconrevlc << 22));
+}
+
+/*
+ * @brief AFE_CTL_3 register definition
+ * <pre>
+ *   Bits           Field Name   Reset Value
+ *  -----   ------------------   -----------
+ *    31:28 RSEL                      0x0
+ *    27:24 I_CSEL_LC                 0xc
+ *    23:20 GM_LC                     0xf
+ *    19:16 CSEL_LC                   0x3
+ *    15:12 CML_SEL                   0x9
+ *    11:09 S_LC                      0x0
+ *    08:06 S                         0x0
+ *    05:03 LBW_LC                    0x7
+ *    02:00 ICP_LC                    0x7
+ * </pre>
+ */
+#define RICU_AFE_CTL_3_ADDR        (REG_RICU_BASE_ADDR + 0x0000001C)
+#define RICU_AFE_CTL_3_OFFSET      0x0000001C
+#define RICU_AFE_CTL_3_INDEX       0x00000007
+#define RICU_AFE_CTL_3_RESET       0x0CF3903F
+
+static inline void ricu_afe_ctl_3_cml_sel_setf(struct cl_chip *chip, u8 cmlsel)
+{
+       ASSERT_ERR_CHIP((((u32)cmlsel << 12) & ~((u32)0x0000F000)) == 0);
+       cl_reg_write_chip(chip, RICU_AFE_CTL_3_ADDR, (cl_reg_read_chip(chip, RICU_AFE_CTL_3_ADDR) & ~((u32)0x0000F000)) | ((u32)cmlsel << 12));
+}
+
+/*
+ * @brief AFE_CTL_5 register definition
+ * <pre>
+ *   Bits           Field Name   Reset Value
+ *  -----   ------------------   -----------
+ *    23:18 MAIN_SEL_7_2              0x0
+ *    17:12 P_LC                      0x1
+ *    11:06 P                         0xA
+ *    05:00 CAP_BIAS_CODE_LC          0x4
+ * </pre>
+ */
+#define RICU_AFE_CTL_5_ADDR        (REG_RICU_BASE_ADDR + 0x00000024)
+#define RICU_AFE_CTL_5_OFFSET      0x00000024
+#define RICU_AFE_CTL_5_INDEX       0x00000009
+#define RICU_AFE_CTL_5_RESET       0x00001284
+
+static inline void ricu_afe_ctl_5_main_sel_7_2_setf(struct cl_chip *chip, u8 mainsel72)
+{
+       ASSERT_ERR_CHIP((((u32)mainsel72 << 18) & ~((u32)0x00FC0000)) == 0);
+       cl_reg_write_chip(chip, RICU_AFE_CTL_5_ADDR, (cl_reg_read_chip(chip, RICU_AFE_CTL_5_ADDR) & ~((u32)0x00FC0000)) | ((u32)mainsel72 << 18));
+}
+
+/*
+ * @brief AFE_CTL_8 register definition
+ * <pre>
+ *   Bits           Field Name   Reset Value
+ *  -----   ------------------   -----------
+ *    31    EN_REF7                   0
+ *    30    EN_REF6                   0
+ *    29    EN_REF5                   0
+ *    28    EN_REF4                   0
+ *    27    EN_REF3                   0
+ *    26    EN_REF2                   0
+ *    25    EN_REF1                   0
+ *    24    EN_REF0                   0
+ *    23    EN_EXT_LOAD7              0
+ *    22    EN_EXT_LOAD6              0
+ *    21    EN_EXT_LOAD5              0
+ *    20    EN_EXT_LOAD4              0
+ *    19    EN_EXT_LOAD3              0
+ *    18    EN_EXT_LOAD2              0
+ *    17    EN_EXT_LOAD1              0
+ *    16    EN_EXT_LOAD0              0
+ *    15    CH_CML_SEL7               0
+ *    14    CH_CML_SEL6               0
+ *    13    CH_CML_SEL5               0
+ *    12    CH_CML_SEL4               0
+ *    11    CH_CML_SEL3               0
+ *    10    CH_CML_SEL2               0
+ *    09    CH_CML_SEL1               0
+ *    08    CH_CML_SEL0               0
+ *    07    EN_BGR7                   0
+ *    06    EN_BGR6                   0
+ *    05    EN_BGR5                   0
+ *    04    EN_BGR4                   0
+ *    03    EN_BGR3                   0
+ *    02    EN_BGR2                   0
+ *    01    EN_BGR1                   0
+ *    00    EN_BGR0                   0
+ * </pre>
+ */
+#define RICU_AFE_CTL_8_ADDR        (REG_RICU_BASE_ADDR + 0x00000030)
+#define RICU_AFE_CTL_8_OFFSET      0x00000030
+#define RICU_AFE_CTL_8_INDEX       0x0000000C
+#define RICU_AFE_CTL_8_RESET       0x00000000
+
+static inline u32 ricu_afe_ctl_8_get(struct cl_chip *chip)
+{
+       return cl_reg_read_chip(chip, RICU_AFE_CTL_8_ADDR);
+}
+
+static inline void ricu_afe_ctl_8_set(struct cl_chip *chip, u32 value)
+{
+       cl_reg_write_chip(chip, RICU_AFE_CTL_8_ADDR, value);
+}
+
+/* Field definitions */
+#define RICU_AFE_CTL_8_EN_REF_7_BIT         ((u32)0x80000000)
+#define RICU_AFE_CTL_8_EN_REF_7_POS         31
+#define RICU_AFE_CTL_8_EN_REF_6_BIT         ((u32)0x40000000)
+#define RICU_AFE_CTL_8_EN_REF_6_POS         30
+#define RICU_AFE_CTL_8_EN_REF_5_BIT         ((u32)0x20000000)
+#define RICU_AFE_CTL_8_EN_REF_5_POS         29
+#define RICU_AFE_CTL_8_EN_REF_4_BIT         ((u32)0x10000000)
+#define RICU_AFE_CTL_8_EN_REF_4_POS         28
+#define RICU_AFE_CTL_8_EN_REF_3_BIT         ((u32)0x08000000)
+#define RICU_AFE_CTL_8_EN_REF_3_POS         27
+#define RICU_AFE_CTL_8_EN_REF_2_BIT         ((u32)0x04000000)
+#define RICU_AFE_CTL_8_EN_REF_2_POS         26
+#define RICU_AFE_CTL_8_EN_REF_1_BIT         ((u32)0x02000000)
+#define RICU_AFE_CTL_8_EN_REF_1_POS         25
+#define RICU_AFE_CTL_8_EN_REF_0_BIT         ((u32)0x01000000)
+#define RICU_AFE_CTL_8_EN_REF_0_POS         24
+#define RICU_AFE_CTL_8_EN_EXT_LOAD_7_BIT    ((u32)0x00800000)
+#define RICU_AFE_CTL_8_EN_EXT_LOAD_7_POS    23
+#define RICU_AFE_CTL_8_EN_EXT_LOAD_6_BIT    ((u32)0x00400000)
+#define RICU_AFE_CTL_8_EN_EXT_LOAD_6_POS    22
+#define RICU_AFE_CTL_8_EN_EXT_LOAD_5_BIT    ((u32)0x00200000)
+#define RICU_AFE_CTL_8_EN_EXT_LOAD_5_POS    21
+#define RICU_AFE_CTL_8_EN_EXT_LOAD_4_BIT    ((u32)0x00100000)
+#define RICU_AFE_CTL_8_EN_EXT_LOAD_4_POS    20
+#define RICU_AFE_CTL_8_EN_EXT_LOAD_3_BIT    ((u32)0x00080000)
+#define RICU_AFE_CTL_8_EN_EXT_LOAD_3_POS    19
+#define RICU_AFE_CTL_8_EN_EXT_LOAD_2_BIT    ((u32)0x00040000)
+#define RICU_AFE_CTL_8_EN_EXT_LOAD_2_POS    18
+#define RICU_AFE_CTL_8_EN_EXT_LOAD_1_BIT    ((u32)0x00020000)
+#define RICU_AFE_CTL_8_EN_EXT_LOAD_1_POS    17
+#define RICU_AFE_CTL_8_EN_EXT_LOAD_0_BIT    ((u32)0x00010000)
+#define RICU_AFE_CTL_8_EN_EXT_LOAD_0_POS    16
+#define RICU_AFE_CTL_8_CH_CML_SEL_7_BIT     ((u32)0x00008000)
+#define RICU_AFE_CTL_8_CH_CML_SEL_7_POS     15
+#define RICU_AFE_CTL_8_CH_CML_SEL_6_BIT     ((u32)0x00004000)
+#define RICU_AFE_CTL_8_CH_CML_SEL_6_POS     14
+#define RICU_AFE_CTL_8_CH_CML_SEL_5_BIT     ((u32)0x00002000)
+#define RICU_AFE_CTL_8_CH_CML_SEL_5_POS     13
+#define RICU_AFE_CTL_8_CH_CML_SEL_4_BIT     ((u32)0x00001000)
+#define RICU_AFE_CTL_8_CH_CML_SEL_4_POS     12
+#define RICU_AFE_CTL_8_CH_CML_SEL_3_BIT     ((u32)0x00000800)
+#define RICU_AFE_CTL_8_CH_CML_SEL_3_POS     11
+#define RICU_AFE_CTL_8_CH_CML_SEL_2_BIT     ((u32)0x00000400)
+#define RICU_AFE_CTL_8_CH_CML_SEL_2_POS     10
+#define RICU_AFE_CTL_8_CH_CML_SEL_1_BIT     ((u32)0x00000200)
+#define RICU_AFE_CTL_8_CH_CML_SEL_1_POS     9
+#define RICU_AFE_CTL_8_CH_CML_SEL_0_BIT     ((u32)0x00000100)
+#define RICU_AFE_CTL_8_CH_CML_SEL_0_POS     8
+#define RICU_AFE_CTL_8_EN_BGR_7_BIT         ((u32)0x00000080)
+#define RICU_AFE_CTL_8_EN_BGR_7_POS         7
+#define RICU_AFE_CTL_8_EN_BGR_6_BIT         ((u32)0x00000040)
+#define RICU_AFE_CTL_8_EN_BGR_6_POS         6
+#define RICU_AFE_CTL_8_EN_BGR_5_BIT         ((u32)0x00000020)
+#define RICU_AFE_CTL_8_EN_BGR_5_POS         5
+#define RICU_AFE_CTL_8_EN_BGR_4_BIT         ((u32)0x00000010)
+#define RICU_AFE_CTL_8_EN_BGR_4_POS         4
+#define RICU_AFE_CTL_8_EN_BGR_3_BIT         ((u32)0x00000008)
+#define RICU_AFE_CTL_8_EN_BGR_3_POS         3
+#define RICU_AFE_CTL_8_EN_BGR_2_BIT         ((u32)0x00000004)
+#define RICU_AFE_CTL_8_EN_BGR_2_POS         2
+#define RICU_AFE_CTL_8_EN_BGR_1_BIT         ((u32)0x00000002)
+#define RICU_AFE_CTL_8_EN_BGR_1_POS         1
+#define RICU_AFE_CTL_8_EN_BGR_0_BIT         ((u32)0x00000001)
+#define RICU_AFE_CTL_8_EN_BGR_0_POS         0
+
+/*
+ * @brief AFE_CTL_9 register definition
+ * <pre>
+ *   Bits           Field Name   Reset Value
+ *  -----   ------------------   -----------
+ *    31    EN_SIN2_BIAS7             1
+ *    30    EN_SIN2_BIAS6             1
+ *    29    EN_SIN2_BIAS5             1
+ *    28    EN_SIN2_BIAS4             1
+ *    27    EN_SIN2_BIAS3             1
+ *    26    EN_SIN2_BIAS2             1
+ *    25    EN_SIN2_BIAS1             1
+ *    24    EN_SIN2_BIAS0             1
+ *    23    EN_DAC_REF7               0
+ *    22    EN_DAC_REF6               0
+ *    21    EN_DAC_REF5               0
+ *    20    EN_DAC_REF4               0
+ *    19    EN_DAC_REF3               0
+ *    18    EN_DAC_REF2               0
+ *    17    EN_DAC_REF1               0
+ *    16    EN_DAC_REF0               0
+ * </pre>
+ */
+#define RICU_AFE_CTL_9_ADDR        (REG_RICU_BASE_ADDR + 0x00000034)
+#define RICU_AFE_CTL_9_OFFSET      0x00000034
+#define RICU_AFE_CTL_9_INDEX       0x0000000D
+#define RICU_AFE_CTL_9_RESET       0xFF000000
+
+static inline u32 ricu_afe_ctl_9_get(struct cl_chip *chip)
+{
+       return cl_reg_read_chip(chip, RICU_AFE_CTL_9_ADDR);
+}
+
+static inline void ricu_afe_ctl_9_set(struct cl_chip *chip, u32 value)
+{
+       cl_reg_write_chip(chip, RICU_AFE_CTL_9_ADDR, value);
+}
+
+/* Field definitions */
+#define RICU_AFE_CTL_9_EN_SIN_2_BIAS_7_BIT    ((u32)0x80000000)
+#define RICU_AFE_CTL_9_EN_SIN_2_BIAS_7_POS    31
+#define RICU_AFE_CTL_9_EN_SIN_2_BIAS_6_BIT    ((u32)0x40000000)
+#define RICU_AFE_CTL_9_EN_SIN_2_BIAS_6_POS    30
+#define RICU_AFE_CTL_9_EN_SIN_2_BIAS_5_BIT    ((u32)0x20000000)
+#define RICU_AFE_CTL_9_EN_SIN_2_BIAS_5_POS    29
+#define RICU_AFE_CTL_9_EN_SIN_2_BIAS_4_BIT    ((u32)0x10000000)
+#define RICU_AFE_CTL_9_EN_SIN_2_BIAS_4_POS    28
+#define RICU_AFE_CTL_9_EN_SIN_2_BIAS_3_BIT    ((u32)0x08000000)
+#define RICU_AFE_CTL_9_EN_SIN_2_BIAS_3_POS    27
+#define RICU_AFE_CTL_9_EN_SIN_2_BIAS_2_BIT    ((u32)0x04000000)
+#define RICU_AFE_CTL_9_EN_SIN_2_BIAS_2_POS    26
+#define RICU_AFE_CTL_9_EN_SIN_2_BIAS_1_BIT    ((u32)0x02000000)
+#define RICU_AFE_CTL_9_EN_SIN_2_BIAS_1_POS    25
+#define RICU_AFE_CTL_9_EN_SIN_2_BIAS_0_BIT    ((u32)0x01000000)
+#define RICU_AFE_CTL_9_EN_SIN_2_BIAS_0_POS    24
+#define RICU_AFE_CTL_9_EN_DAC_REF_7_BIT     ((u32)0x00800000)
+#define RICU_AFE_CTL_9_EN_DAC_REF_7_POS     23
+#define RICU_AFE_CTL_9_EN_DAC_REF_6_BIT     ((u32)0x00400000)
+#define RICU_AFE_CTL_9_EN_DAC_REF_6_POS     22
+#define RICU_AFE_CTL_9_EN_DAC_REF_5_BIT     ((u32)0x00200000)
+#define RICU_AFE_CTL_9_EN_DAC_REF_5_POS     21
+#define RICU_AFE_CTL_9_EN_DAC_REF_4_BIT     ((u32)0x00100000)
+#define RICU_AFE_CTL_9_EN_DAC_REF_4_POS     20
+#define RICU_AFE_CTL_9_EN_DAC_REF_3_BIT     ((u32)0x00080000)
+#define RICU_AFE_CTL_9_EN_DAC_REF_3_POS     19
+#define RICU_AFE_CTL_9_EN_DAC_REF_2_BIT     ((u32)0x00040000)
+#define RICU_AFE_CTL_9_EN_DAC_REF_2_POS     18
+#define RICU_AFE_CTL_9_EN_DAC_REF_1_BIT     ((u32)0x00020000)
+#define RICU_AFE_CTL_9_EN_DAC_REF_1_POS     17
+#define RICU_AFE_CTL_9_EN_DAC_REF_0_BIT     ((u32)0x00010000)
+#define RICU_AFE_CTL_9_EN_DAC_REF_0_POS     16
+
+/*
+ * @brief AFE_CTL_10 register definition
+ * <pre>
+ *   Bits           Field Name   Reset Value
+ *  -----   ------------------   -----------
+ *    31    VC_LD7                    0
+ *    30    VC_LD6                    0
+ *    29    VC_LD5                    0
+ *    28    VC_LD4                    0
+ *    27    VC_LD3                    0
+ *    26    VC_LD2                    0
+ *    25    VC_LD1                    0
+ *    24    VC_LD0                    0
+ *    23    TWOS7                     0
+ *    22    TWOS6                     0
+ *    21    TWOS5                     0
+ *    20    TWOS4                     0
+ *    19    TWOS3                     0
+ *    18    TWOS2                     0
+ *    17    TWOS1                     0
+ *    16    TWOS0                     0
+ *    07    MINV7                     1
+ *    06    MINV6                     1
+ *    05    MINV5                     1
+ *    04    MINV4                     1
+ *    03    MINV3                     1
+ *    02    MINV2                     1
+ *    01    MINV1                     1
+ *    00    MINV0                     1
+ * </pre>
+ */
+#define RICU_AFE_CTL_10_ADDR        (REG_RICU_BASE_ADDR + 0x00000038)
+#define RICU_AFE_CTL_10_OFFSET      0x00000038
+#define RICU_AFE_CTL_10_INDEX       0x0000000E
+#define RICU_AFE_CTL_10_RESET       0x000000FF
+
+static inline void ricu_afe_ctl_10_set(struct cl_chip *chip, u32 value)
+{
+       cl_reg_write_chip(chip, RICU_AFE_CTL_10_ADDR, value);
+}
+
+/*
+ * @brief AFE_CTL_12 register definition
+ * <pre>
+ *   Bits           Field Name   Reset Value
+ *  -----   ------------------   -----------
+ *    31:30 EOC_CTRL7                 0x0
+ *    29:28 EOC_CTRL6                 0x0
+ *    27:26 EOC_CTRL5                 0x0
+ *    25:24 EOC_CTRL4                 0x0
+ *    23:22 EOC_CTRL3                 0x0
+ *    21:20 EOC_CTRL2                 0x0
+ *    19:18 EOC_CTRL1                 0x0
+ *    17:16 EOC_CTRL0                 0x0
+ *    15:14 IC_REFSSF7                0x1
+ *    13:12 IC_REFSSF6                0x1
+ *    11:10 IC_REFSSF5                0x1
+ *    09:08 IC_REFSSF4                0x1
+ *    07:06 IC_REFSSF3                0x1
+ *    05:04 IC_REFSSF2                0x1
+ *    03:02 IC_REFSSF1                0x1
+ *    01:00 IC_REFSSF0                0x1
+ * </pre>
+ */
+#define RICU_AFE_CTL_12_ADDR        (REG_RICU_BASE_ADDR + 0x00000040)
+#define RICU_AFE_CTL_12_OFFSET      0x00000040
+#define RICU_AFE_CTL_12_INDEX       0x00000010
+#define RICU_AFE_CTL_12_RESET       0x00005555
+
+static inline void ricu_afe_ctl_12_set(struct cl_chip *chip, u32 value)
+{
+       cl_reg_write_chip(chip, RICU_AFE_CTL_12_ADDR, value);
+}
+
+/*
+ * @brief AFE_CTL_17 register definition
+ * <pre>
+ *   Bits           Field Name   Reset Value
+ *  -----   ------------------   -----------
+ *    30:28 VC_REF7                   0x1
+ *    26:24 VC_REF6                   0x1
+ *    22:20 VC_REF5                   0x1
+ *    18:16 VC_REF4                   0x1
+ *    14:12 VC_REF3                   0x1
+ *    10:08 VC_REF2                   0x1
+ *    06:04 VC_REF1                   0x1
+ *    02:00 VC_REF0                   0x1
+ * </pre>
+ */
+#define RICU_AFE_CTL_17_ADDR        (REG_RICU_BASE_ADDR + 0x00000054)
+#define RICU_AFE_CTL_17_OFFSET      0x00000054
+#define RICU_AFE_CTL_17_INDEX       0x00000015
+#define RICU_AFE_CTL_17_RESET       0x11111111
+
+static inline void ricu_afe_ctl_17_set(struct cl_chip *chip, u32 value)
+{
+       cl_reg_write_chip(chip, RICU_AFE_CTL_17_ADDR, value);
+}
+
+/*
+ * @brief AFE_CTL_19 register definition
+ * <pre>
+ *   Bits           Field Name   Reset Value
+ *  -----   ------------------   -----------
+ *    31:28 COMP_CTRL7                0x4
+ *    27:24 COMP_CTRL6                0x4
+ *    23:20 COMP_CTRL5                0x4
+ *    19:16 COMP_CTRL4                0x4
+ *    15:12 COMP_CTRL3                0x4
+ *    11:08 COMP_CTRL2                0x4
+ *    07:04 COMP_CTRL1                0x4
+ *    03:00 COMP_CTRL0                0x4
+ * </pre>
+ */
+#define RICU_AFE_CTL_19_ADDR        (REG_RICU_BASE_ADDR + 0x0000005C)
+#define RICU_AFE_CTL_19_OFFSET      0x0000005C
+#define RICU_AFE_CTL_19_INDEX       0x00000017
+#define RICU_AFE_CTL_19_RESET       0x44444444
+
+static inline void ricu_afe_ctl_19_set(struct cl_chip *chip, u32 value)
+{
+       cl_reg_write_chip(chip, RICU_AFE_CTL_19_ADDR, value);
+}
+
+/*
+ * @brief AFE_CTL_23 register definition
+ * <pre>
+ *   Bits           Field Name   Reset Value
+ *  -----   ------------------   -----------
+ *    30:28 VC_LD_AVDI7               0x3
+ *    26:24 VC_LD_AVDI6               0x3
+ *    22:20 VC_LD_AVDI5               0x3
+ *    18:16 VC_LD_AVDI4               0x3
+ *    14:12 VC_LD_AVDI3               0x3
+ *    10:08 VC_LD_AVDI2               0x3
+ *    06:04 VC_LD_AVDI1               0x3
+ *    02:00 VC_LD_AVDI0               0x3
+ * </pre>
+ */
+#define RICU_AFE_CTL_23_ADDR        (REG_RICU_BASE_ADDR + 0x0000006C)
+#define RICU_AFE_CTL_23_OFFSET      0x0000006C
+#define RICU_AFE_CTL_23_INDEX       0x0000001B
+#define RICU_AFE_CTL_23_RESET       0x33333333
+
+static inline void ricu_afe_ctl_23_set(struct cl_chip *chip, u32 value)
+{
+       cl_reg_write_chip(chip, RICU_AFE_CTL_23_ADDR, value);
+}
+
+/*
+ * @brief AFE_CTL_24 register definition
+ * <pre>
+ *   Bits           Field Name   Reset Value
+ *  -----   ------------------   -----------
+ *    30:28 VC_LD_AVDQ7               0x3
+ *    26:24 VC_LD_AVDQ6               0x3
+ *    22:20 VC_LD_AVDQ5               0x3
+ *    18:16 VC_LD_AVDQ4               0x3
+ *    14:12 VC_LD_AVDQ3               0x3
+ *    10:08 VC_LD_AVDQ2               0x3
+ *    06:04 VC_LD_AVDQ1               0x3
+ *    02:00 VC_LD_AVDQ0               0x3
+ * </pre>
+ */
+#define RICU_AFE_CTL_24_ADDR        (REG_RICU_BASE_ADDR + 0x00000070)
+#define RICU_AFE_CTL_24_OFFSET      0x00000070
+#define RICU_AFE_CTL_24_INDEX       0x0000001C
+#define RICU_AFE_CTL_24_RESET       0x33333333
+
+static inline void ricu_afe_ctl_24_set(struct cl_chip *chip, u32 value)
+{
+       cl_reg_write_chip(chip, RICU_AFE_CTL_24_ADDR, value);
+}
+
+/*
+ * @brief AFE_CTL_25 register definition
+ * <pre>
+ *   Bits           Field Name   Reset Value
+ *  -----   ------------------   -----------
+ *    16    ROSEL0                    0
+ *    14:08 RO_CTRLQ0                 0x7
+ *    06:00 RO_CTRLI0                 0x7
+ * </pre>
+ */
+#define RICU_AFE_CTL_25_ADDR        (REG_RICU_BASE_ADDR + 0x00000074)
+#define RICU_AFE_CTL_25_OFFSET      0x00000074
+#define RICU_AFE_CTL_25_INDEX       0x0000001D
+#define RICU_AFE_CTL_25_RESET       0x00000707
+
+static inline void ricu_afe_ctl_25_pack(struct cl_chip *chip, u8 rosel0, u8 roctrlq0, u8 roctrli0)
+{
+       ASSERT_ERR_CHIP((((u32)rosel0 << 16) & ~((u32)0x00010000)) == 0);
+       ASSERT_ERR_CHIP((((u32)roctrlq0 << 8) & ~((u32)0x00007F00)) == 0);
+       ASSERT_ERR_CHIP((((u32)roctrli0 << 0) & ~((u32)0x0000007F)) == 0);
+       cl_reg_write_chip(chip, RICU_AFE_CTL_25_ADDR, ((u32)rosel0 << 16) | ((u32)roctrlq0 << 8) | ((u32)roctrli0 << 0));
+}
+
+/*
+ * @brief AFE_CTL_26 register definition
+ * <pre>
+ *   Bits           Field Name   Reset Value
+ *  -----   ------------------   -----------
+ *    16    ROSEL1                    0
+ *    14:08 RO_CTRLQ1                 0x7
+ *    06:00 RO_CTRLI1                 0x7
+ * </pre>
+ */
+#define RICU_AFE_CTL_26_ADDR        (REG_RICU_BASE_ADDR + 0x00000078)
+#define RICU_AFE_CTL_26_OFFSET      0x00000078
+#define RICU_AFE_CTL_26_INDEX       0x0000001E
+#define RICU_AFE_CTL_26_RESET       0x00000707
+
+static inline void ricu_afe_ctl_26_pack(struct cl_chip *chip, u8 rosel1, u8 roctrlq1, u8 roctrli1)
+{
+       ASSERT_ERR_CHIP((((u32)rosel1 << 16) & ~((u32)0x00010000)) == 0);
+       ASSERT_ERR_CHIP((((u32)roctrlq1 << 8) & ~((u32)0x00007F00)) == 0);
+       ASSERT_ERR_CHIP((((u32)roctrli1 << 0) & ~((u32)0x0000007F)) == 0);
+       cl_reg_write_chip(chip, RICU_AFE_CTL_26_ADDR, ((u32)rosel1 << 16) | ((u32)roctrlq1 << 8) | ((u32)roctrli1 << 0));
+}
+
+/*
+ * @brief AFE_CTL_27 register definition
+ * <pre>
+ *   Bits           Field Name   Reset Value
+ *  -----   ------------------   -----------
+ *    16    ROSEL2                    0
+ *    14:08 RO_CTRLQ2                 0x7
+ *    06:00 RO_CTRLI2                 0x7
+ * </pre>
+ */
+#define RICU_AFE_CTL_27_ADDR        (REG_RICU_BASE_ADDR + 0x0000007C)
+#define RICU_AFE_CTL_27_OFFSET      0x0000007C
+#define RICU_AFE_CTL_27_INDEX       0x0000001F
+#define RICU_AFE_CTL_27_RESET       0x00000707
+
+static inline void ricu_afe_ctl_27_pack(struct cl_chip *chip, u8 rosel2, u8 roctrlq2, u8 roctrli2)
+{
+       ASSERT_ERR_CHIP((((u32)rosel2 << 16) & ~((u32)0x00010000)) == 0);
+       ASSERT_ERR_CHIP((((u32)roctrlq2 << 8) & ~((u32)0x00007F00)) == 0);
+       ASSERT_ERR_CHIP((((u32)roctrli2 << 0) & ~((u32)0x0000007F)) == 0);
+       cl_reg_write_chip(chip, RICU_AFE_CTL_27_ADDR, ((u32)rosel2 << 16) | ((u32)roctrlq2 << 8) | ((u32)roctrli2 << 0));
+}
+
+/*
+ * @brief AFE_CTL_29 register definition
+ * <pre>
+ *   Bits           Field Name   Reset Value
+ *  -----   ------------------   -----------
+ *    30:28 VC_CML7_I                 0x5
+ *    26:24 VC_CML6_I                 0x5
+ *    22:20 VC_CML5_I                 0x5
+ *    18:16 VC_CML4_I                 0x5
+ *    14:12 VC_CML3_I                 0x5
+ *    10:08 VC_CML2_I                 0x5
+ *    06:04 VC_CML1_I                 0x5
+ *    02:00 VC_CML0_I                 0x5
+ * </pre>
+ */
+#define RICU_AFE_CTL_29_ADDR        (REG_RICU_BASE_ADDR + 0x00000084)
+#define RICU_AFE_CTL_29_OFFSET      0x00000084
+#define RICU_AFE_CTL_29_INDEX       0x00000021
+#define RICU_AFE_CTL_29_RESET       0x55555555
+
+static inline void ricu_afe_ctl_29_set(struct cl_chip *chip, u32 value)
+{
+       cl_reg_write_chip(chip, RICU_AFE_CTL_29_ADDR, value);
+}
+
+/*
+ * @brief AFE_CTL_30 register definition
+ * <pre>
+ *   Bits           Field Name   Reset Value
+ *  -----   ------------------   -----------
+ *    30:28 VC_CML7_Q                 0x5
+ *    26:24 VC_CML6_Q                 0x5
+ *    22:20 VC_CML5_Q                 0x5
+ *    18:16 VC_CML4_Q                 0x5
+ *    14:12 VC_CML3_Q                 0x5
+ *    10:08 VC_CML2_Q                 0x5
+ *    06:04 VC_CML1_Q                 0x5
+ *    02:00 VC_CML0_Q                 0x5
+ * </pre>
+ */
+#define RICU_AFE_CTL_30_ADDR        (REG_RICU_BASE_ADDR + 0x00000088)
+#define RICU_AFE_CTL_30_OFFSET      0x00000088
+#define RICU_AFE_CTL_30_INDEX       0x00000022
+#define RICU_AFE_CTL_30_RESET       0x55555555
+
+static inline void ricu_afe_ctl_30_set(struct cl_chip *chip, u32 value)
+{
+       cl_reg_write_chip(chip, RICU_AFE_CTL_30_ADDR, value);
+}
+
+/*
+ * @brief AFE_CTL_33 register definition
+ * <pre>
+ *   Bits           Field Name   Reset Value
+ *  -----   ------------------   -----------
+ *    16    ROSEL3                    0
+ *    14:08 RO_CTRL3_Q                0x7
+ *    06:00 RO_CTRL3_I                0x7
+ * </pre>
+ */
+#define RICU_AFE_CTL_33_ADDR        (REG_RICU_BASE_ADDR + 0x00000094)
+#define RICU_AFE_CTL_33_OFFSET      0x00000094
+#define RICU_AFE_CTL_33_INDEX       0x00000025
+#define RICU_AFE_CTL_33_RESET       0x00000707
+
+static inline void ricu_afe_ctl_33_pack(struct cl_chip *chip, u8 rosel3, u8 roctrl3q, u8 roctrl3i)
+{
+       ASSERT_ERR_CHIP((((u32)rosel3 << 16) & ~((u32)0x00010000)) == 0);
+       ASSERT_ERR_CHIP((((u32)roctrl3q << 8) & ~((u32)0x00007F00)) == 0);
+       ASSERT_ERR_CHIP((((u32)roctrl3i << 0) & ~((u32)0x0000007F)) == 0);
+       cl_reg_write_chip(chip, RICU_AFE_CTL_33_ADDR, ((u32)rosel3 << 16) | ((u32)roctrl3q << 8) | ((u32)roctrl3i << 0));
+}
+
+/*
+ * @brief AFE_CTRL_34_PHY_0 register definition
+ * <pre>
+ *   Bits           Field Name   Reset Value
+ *  -----   ------------------   -----------
+ *    06    PHY0_ADC_SB_IGNORE_FIFO_INDICATION 0
+ *    05:02 PHY0_ADC_SB_RD_DELAY      0x4
+ *    01:00 PHY0_ADC_SB_MODE          0x0
+ * </pre>
+ */
+#define RICU_AFE_CTRL_34_PHY_0_ADDR        (REG_RICU_BASE_ADDR + 0x0000009C)
+#define RICU_AFE_CTRL_34_PHY_0_OFFSET      0x0000009C
+#define RICU_AFE_CTRL_34_PHY_0_INDEX       0x00000027
+#define RICU_AFE_CTRL_34_PHY_0_RESET       0x00000010
+
+static inline void ricu_afe_ctrl_34_phy_0_adc_sb_ignore_fifo_indication_setf(struct cl_chip *chip, u8 phy0adcsbignorefifoindication)
+{
+       ASSERT_ERR_CHIP((((u32)phy0adcsbignorefifoindication << 6) & ~((u32)0x00000040)) == 0);
+       cl_reg_write_chip(chip, RICU_AFE_CTRL_34_PHY_0_ADDR, (cl_reg_read_chip(chip, RICU_AFE_CTRL_34_PHY_0_ADDR) & ~((u32)0x00000040)) | ((u32)phy0adcsbignorefifoindication << 6));
+}
+
+static inline void ricu_afe_ctrl_34_phy_0_adc_sb_rd_delay_setf(struct cl_chip *chip, u8 phy0adcsbrddelay)
+{
+       ASSERT_ERR_CHIP((((u32)phy0adcsbrddelay << 2) & ~((u32)0x0000003C)) == 0);
+       cl_reg_write_chip(chip, RICU_AFE_CTRL_34_PHY_0_ADDR, (cl_reg_read_chip(chip, RICU_AFE_CTRL_34_PHY_0_ADDR) & ~((u32)0x0000003C)) | ((u32)phy0adcsbrddelay << 2));
+}
+
+/*
+ * @brief AFE_CTRL_36_PHY_0 register definition
+ * <pre>
+ *   Bits           Field Name   Reset Value
+ *  -----   ------------------   -----------
+ *    07    PHY0_ADC_ALWAYS_EN_LD_IR  0
+ *    06    PHY0_ADC_ALWAYS_EN_LD_AVDQ 0
+ *    05    PHY0_ADC_ALWAYS_EN_LD_AVDI 0
+ *    04    PHY0_ADC_ALWAYS_EN_ADCQ   0
+ *    03    PHY0_ADC_ALWAYS_EN_ADCI   0
+ *    01    PHY0_HW_MODE_DAC          0
+ *    00    PHY0_HW_MODE_ADC          0
+ * </pre>
+ */
+#define RICU_AFE_CTRL_36_PHY_0_ADDR        (REG_RICU_BASE_ADDR + 0x000000A0)
+#define RICU_AFE_CTRL_36_PHY_0_OFFSET      0x000000A0
+#define RICU_AFE_CTRL_36_PHY_0_INDEX       0x00000028
+#define RICU_AFE_CTRL_36_PHY_0_RESET       0x00000000
+
+static inline u32 ricu_afe_ctrl_36_phy_0_get(struct cl_chip *chip)
+{
+       return cl_reg_read_chip(chip, RICU_AFE_CTRL_36_PHY_0_ADDR);
+}
+
+static inline void ricu_afe_ctrl_36_phy_0_set(struct cl_chip *chip, u32 value)
+{
+       cl_reg_write_chip(chip, RICU_AFE_CTRL_36_PHY_0_ADDR, value);
+}
+
+/* Field definitions */
+#define RICU_AFE_CTRL_36_PHY_0_ADC_ALWAYS_EN_LD_IR_BIT    ((u32)0x00000080)
+#define RICU_AFE_CTRL_36_PHY_0_ADC_ALWAYS_EN_LD_IR_POS    7
+#define RICU_AFE_CTRL_36_PHY_0_ADC_ALWAYS_EN_LD_AVDQ_BIT    ((u32)0x00000040)
+#define RICU_AFE_CTRL_36_PHY_0_ADC_ALWAYS_EN_LD_AVDQ_POS    6
+#define RICU_AFE_CTRL_36_PHY_0_ADC_ALWAYS_EN_LD_AVDI_BIT    ((u32)0x00000020)
+#define RICU_AFE_CTRL_36_PHY_0_ADC_ALWAYS_EN_LD_AVDI_POS    5
+#define RICU_AFE_CTRL_36_PHY_0_ADC_ALWAYS_EN_ADCQ_BIT    ((u32)0x00000010)
+#define RICU_AFE_CTRL_36_PHY_0_ADC_ALWAYS_EN_ADCQ_POS    4
+#define RICU_AFE_CTRL_36_PHY_0_ADC_ALWAYS_EN_ADCI_BIT    ((u32)0x00000008)
+#define RICU_AFE_CTRL_36_PHY_0_ADC_ALWAYS_EN_ADCI_POS    3
+#define RICU_AFE_CTRL_36_PHY_0_HW_MODE_DAC_BIT    ((u32)0x00000002)
+#define RICU_AFE_CTRL_36_PHY_0_HW_MODE_DAC_POS    1
+#define RICU_AFE_CTRL_36_PHY_0_HW_MODE_ADC_BIT    ((u32)0x00000001)
+#define RICU_AFE_CTRL_36_PHY_0_HW_MODE_ADC_POS    0
+
+static inline void ricu_afe_ctrl_36_phy_0_hw_mode_dac_setf(struct cl_chip *chip, u8 phy0hwmodedac)
+{
+       ASSERT_ERR_CHIP((((u32)phy0hwmodedac << 1) & ~((u32)0x00000002)) == 0);
+       cl_reg_write_chip(chip, RICU_AFE_CTRL_36_PHY_0_ADDR, (cl_reg_read_chip(chip, RICU_AFE_CTRL_36_PHY_0_ADDR) & ~((u32)0x00000002)) | ((u32)phy0hwmodedac << 1));
+}
+
+static inline void ricu_afe_ctrl_36_phy_0_hw_mode_adc_setf(struct cl_chip *chip, u8 phy0hwmodeadc)
+{
+       ASSERT_ERR_CHIP((((u32)phy0hwmodeadc << 0) & ~((u32)0x00000001)) == 0);
+       cl_reg_write_chip(chip, RICU_AFE_CTRL_36_PHY_0_ADDR, (cl_reg_read_chip(chip, RICU_AFE_CTRL_36_PHY_0_ADDR) & ~((u32)0x00000001)) | ((u32)phy0hwmodeadc << 0));
+}
+
+/*
+ * @brief AFE_CTRL_34_PHY_1 register definition
+ * <pre>
+ *   Bits           Field Name   Reset Value
+ *  -----   ------------------   -----------
+ *    06    PHY1_ADC_SB_IGNORE_FIFO_INDICATION 0
+ *    05:02 PHY1_ADC_SB_RD_DELAY      0x4
+ *    01:00 PHY1_ADC_SB_MODE          0x0
+ * </pre>
+ */
+#define RICU_AFE_CTRL_34_PHY_1_ADDR        (REG_RICU_BASE_ADDR + 0x000000A4)
+#define RICU_AFE_CTRL_34_PHY_1_OFFSET      0x000000A4
+#define RICU_AFE_CTRL_34_PHY_1_INDEX       0x00000029
+#define RICU_AFE_CTRL_34_PHY_1_RESET       0x00000010
+
+static inline void ricu_afe_ctrl_34_phy_1_adc_sb_ignore_fifo_indication_setf(struct cl_chip *chip, u8 phy1adcsbignorefifoindication)
+{
+       ASSERT_ERR_CHIP((((u32)phy1adcsbignorefifoindication << 6) & ~((u32)0x00000040)) == 0);
+       cl_reg_write_chip(chip, RICU_AFE_CTRL_34_PHY_1_ADDR, (cl_reg_read_chip(chip, RICU_AFE_CTRL_34_PHY_1_ADDR) & ~((u32)0x00000040)) | ((u32)phy1adcsbignorefifoindication << 6));
+}
+
+static inline void ricu_afe_ctrl_34_phy_1_adc_sb_rd_delay_setf(struct cl_chip *chip, u8 phy1adcsbrddelay)
+{
+       ASSERT_ERR_CHIP((((u32)phy1adcsbrddelay << 2) & ~((u32)0x0000003C)) == 0);
+       cl_reg_write_chip(chip, RICU_AFE_CTRL_34_PHY_1_ADDR, (cl_reg_read_chip(chip, RICU_AFE_CTRL_34_PHY_1_ADDR) & ~((u32)0x0000003C)) | ((u32)phy1adcsbrddelay << 2));
+}
+
+/*
+ * @brief AFE_CTRL_35_PHY_0 register definition
+ * <pre>
+ *   Bits           Field Name   Reset Value
+ *  -----   ------------------   -----------
+ *    06    PHY0_DAC_SB_IGNORE_FIFO_INDICATION 0
+ *    05:02 PHY0_DAC_SB_RD_DELAY      0x1
+ *    01:00 PHY0_DAC_SB_MODE          0x0
+ * </pre>
+ */
+#define RICU_AFE_CTRL_35_PHY_0_ADDR        (REG_RICU_BASE_ADDR + 0x000000A8)
+#define RICU_AFE_CTRL_35_PHY_0_OFFSET      0x000000A8
+#define RICU_AFE_CTRL_35_PHY_0_INDEX       0x0000002A
+#define RICU_AFE_CTRL_35_PHY_0_RESET       0x00000004
+
+static inline void ricu_afe_ctrl_35_phy_0_dac_sb_ignore_fifo_indication_setf(struct cl_chip *chip, u8 phy0dacsbignorefifoindication)
+{
+       ASSERT_ERR_CHIP((((u32)phy0dacsbignorefifoindication << 6) & ~((u32)0x00000040)) == 0);
+       cl_reg_write_chip(chip, RICU_AFE_CTRL_35_PHY_0_ADDR, (cl_reg_read_chip(chip, RICU_AFE_CTRL_35_PHY_0_ADDR) & ~((u32)0x00000040)) | ((u32)phy0dacsbignorefifoindication << 6));
+}
+
+static inline void ricu_afe_ctrl_35_phy_0_dac_sb_rd_delay_setf(struct cl_chip *chip, u8 phy0dacsbrddelay)
+{
+       ASSERT_ERR_CHIP((((u32)phy0dacsbrddelay << 2) & ~((u32)0x0000003C)) == 0);
+       cl_reg_write_chip(chip, RICU_AFE_CTRL_35_PHY_0_ADDR, (cl_reg_read_chip(chip, RICU_AFE_CTRL_35_PHY_0_ADDR) & ~((u32)0x0000003C)) | ((u32)phy0dacsbrddelay << 2));
+}
+
+/*
+ * @brief AFE_CTRL_35_PHY_1 register definition
+ * <pre>
+ *   Bits           Field Name   Reset Value
+ *  -----   ------------------   -----------
+ *    06    PHY1_DAC_SB_IGNORE_FIFO_INDICATION 0
+ *    05:02 PHY1_DAC_SB_RD_DELAY      0x1
+ *    01:00 PHY1_DAC_SB_MODE          0x0
+ * </pre>
+ */
+#define RICU_AFE_CTRL_35_PHY_1_ADDR        (REG_RICU_BASE_ADDR + 0x000000AC)
+#define RICU_AFE_CTRL_35_PHY_1_OFFSET      0x000000AC
+#define RICU_AFE_CTRL_35_PHY_1_INDEX       0x0000002B
+#define RICU_AFE_CTRL_35_PHY_1_RESET       0x00000004
+
+static inline void ricu_afe_ctrl_35_phy_1_dac_sb_ignore_fifo_indication_setf(struct cl_chip *chip, u8 phy1dacsbignorefifoindication)
+{
+       ASSERT_ERR_CHIP((((u32)phy1dacsbignorefifoindication << 6) & ~((u32)0x00000040)) == 0);
+       cl_reg_write_chip(chip, RICU_AFE_CTRL_35_PHY_1_ADDR, (cl_reg_read_chip(chip, RICU_AFE_CTRL_35_PHY_1_ADDR) & ~((u32)0x00000040)) | ((u32)phy1dacsbignorefifoindication << 6));
+}
+
+static inline void ricu_afe_ctrl_35_phy_1_dac_sb_rd_delay_setf(struct cl_chip *chip, u8 phy1dacsbrddelay)
+{
+       ASSERT_ERR_CHIP((((u32)phy1dacsbrddelay << 2) & ~((u32)0x0000003C)) == 0);
+       cl_reg_write_chip(chip, RICU_AFE_CTRL_35_PHY_1_ADDR, (cl_reg_read_chip(chip, RICU_AFE_CTRL_35_PHY_1_ADDR) & ~((u32)0x0000003C)) | ((u32)phy1dacsbrddelay << 2));
+}
+
+/*
+ * @brief AFE_CTRL_37_PHY_0 register definition
+ * <pre>
+ *   Bits           Field Name   Reset Value
+ *  -----   ------------------   -----------
+ *    05    PHY0_EN_DAC5              0
+ *    04    PHY0_EN_DAC4              0
+ *    03    PHY0_EN_DAC3              0
+ *    02    PHY0_EN_DAC2              0
+ *    01    PHY0_EN_DAC1              0
+ *    00    PHY0_EN_DAC0              0
+ * </pre>
+ */
+#define RICU_AFE_CTRL_37_PHY_0_ADDR        (REG_RICU_BASE_ADDR + 0x000000BC)
+#define RICU_AFE_CTRL_37_PHY_0_OFFSET      0x000000BC
+#define RICU_AFE_CTRL_37_PHY_0_INDEX       0x0000002F
+#define RICU_AFE_CTRL_37_PHY_0_RESET       0x00000000
+
+static inline u32 ricu_afe_ctrl_37_phy_0_get(struct cl_chip *chip)
+{
+       return cl_reg_read_chip(chip, RICU_AFE_CTRL_37_PHY_0_ADDR);
+}
+
+static inline void ricu_afe_ctrl_37_phy_0_set(struct cl_chip *chip, u32 value)
+{
+       cl_reg_write_chip(chip, RICU_AFE_CTRL_37_PHY_0_ADDR, value);
+}
+
+/* Field definitions */
+#define RICU_AFE_CTRL_37_PHY_0_EN_DAC_5_BIT    ((u32)0x00000020)
+#define RICU_AFE_CTRL_37_PHY_0_EN_DAC_5_POS    5
+#define RICU_AFE_CTRL_37_PHY_0_EN_DAC_4_BIT    ((u32)0x00000010)
+#define RICU_AFE_CTRL_37_PHY_0_EN_DAC_4_POS    4
+#define RICU_AFE_CTRL_37_PHY_0_EN_DAC_3_BIT    ((u32)0x00000008)
+#define RICU_AFE_CTRL_37_PHY_0_EN_DAC_3_POS    3
+#define RICU_AFE_CTRL_37_PHY_0_EN_DAC_2_BIT    ((u32)0x00000004)
+#define RICU_AFE_CTRL_37_PHY_0_EN_DAC_2_POS    2
+#define RICU_AFE_CTRL_37_PHY_0_EN_DAC_1_BIT    ((u32)0x00000002)
+#define RICU_AFE_CTRL_37_PHY_0_EN_DAC_1_POS    1
+#define RICU_AFE_CTRL_37_PHY_0_EN_DAC_0_BIT    ((u32)0x00000001)
+#define RICU_AFE_CTRL_37_PHY_0_EN_DAC_0_POS    0
+
+/*
+ * @brief AFE_CTRL_37_PHY_1 register definition
+ * <pre>
+ *   Bits           Field Name   Reset Value
+ *  -----   ------------------   -----------
+ *    05    PHY1_EN_DAC5              0
+ *    04    PHY1_EN_DAC4              0
+ *    03    PHY1_EN_DAC3              0
+ *    02    PHY1_EN_DAC2              0
+ *    01    PHY1_EN_DAC1              0
+ *    00    PHY1_EN_DAC0              0
+ * </pre>
+ */
+#define RICU_AFE_CTRL_37_PHY_1_ADDR        (REG_RICU_BASE_ADDR + 0x000000C0)
+#define RICU_AFE_CTRL_37_PHY_1_OFFSET      0x000000C0
+#define RICU_AFE_CTRL_37_PHY_1_INDEX       0x00000030
+#define RICU_AFE_CTRL_37_PHY_1_RESET       0x00000000
+
+static inline u32 ricu_afe_ctrl_37_phy_1_get(struct cl_chip *chip)
+{
+       return cl_reg_read_chip(chip, RICU_AFE_CTRL_37_PHY_1_ADDR);
+}
+
+static inline void ricu_afe_ctrl_37_phy_1_set(struct cl_chip *chip, u32 value)
+{
+       cl_reg_write_chip(chip, RICU_AFE_CTRL_37_PHY_1_ADDR, value);
+}
+
+/* Field definitions */
+#define RICU_AFE_CTRL_37_PHY_1_EN_DAC_5_BIT    ((u32)0x00000020)
+#define RICU_AFE_CTRL_37_PHY_1_EN_DAC_5_POS    5
+#define RICU_AFE_CTRL_37_PHY_1_EN_DAC_4_BIT    ((u32)0x00000010)
+#define RICU_AFE_CTRL_37_PHY_1_EN_DAC_4_POS    4
+#define RICU_AFE_CTRL_37_PHY_1_EN_DAC_3_BIT    ((u32)0x00000008)
+#define RICU_AFE_CTRL_37_PHY_1_EN_DAC_3_POS    3
+#define RICU_AFE_CTRL_37_PHY_1_EN_DAC_2_BIT    ((u32)0x00000004)
+#define RICU_AFE_CTRL_37_PHY_1_EN_DAC_2_POS    2
+#define RICU_AFE_CTRL_37_PHY_1_EN_DAC_1_BIT    ((u32)0x00000002)
+#define RICU_AFE_CTRL_37_PHY_1_EN_DAC_1_POS    1
+#define RICU_AFE_CTRL_37_PHY_1_EN_DAC_0_BIT    ((u32)0x00000001)
+#define RICU_AFE_CTRL_37_PHY_1_EN_DAC_0_POS    0
+
+/*
+ * @brief AFE_CTRL_39 register definition
+ * <pre>
+ *   Bits           Field Name   Reset Value
+ *  -----   ------------------   -----------
+ *    16    ROSEL4                    0
+ *    14:08 RO_CTRLQ4                 0x7
+ *    06:00 RO_CTRLI4                 0x7
+ * </pre>
+ */
+#define RICU_AFE_CTRL_39_ADDR        (REG_RICU_BASE_ADDR + 0x000000CC)
+#define RICU_AFE_CTRL_39_OFFSET      0x000000CC
+#define RICU_AFE_CTRL_39_INDEX       0x00000033
+#define RICU_AFE_CTRL_39_RESET       0x00000707
+
+static inline void ricu_afe_ctrl_39_pack(struct cl_chip *chip, u8 rosel4, u8 roctrlq4, u8 roctrli4)
+{
+       ASSERT_ERR_CHIP((((u32)rosel4 << 16) & ~((u32)0x00010000)) == 0);
+       ASSERT_ERR_CHIP((((u32)roctrlq4 << 8) & ~((u32)0x00007F00)) == 0);
+       ASSERT_ERR_CHIP((((u32)roctrli4 << 0) & ~((u32)0x0000007F)) == 0);
+       cl_reg_write_chip(chip, RICU_AFE_CTRL_39_ADDR, ((u32)rosel4 << 16) | ((u32)roctrlq4 << 8) | ((u32)roctrli4 << 0));
+}
+
+/*
+ * @brief AFE_CTRL_40 register definition
+ * <pre>
+ *   Bits           Field Name   Reset Value
+ *  -----   ------------------   -----------
+ *    16    ROSEL5                    0
+ *    14:08 RO_CTRLQ5                 0x7
+ *    06:00 RO_CTRLI5                 0x7
+ * </pre>
+ */
+#define RICU_AFE_CTRL_40_ADDR        (REG_RICU_BASE_ADDR + 0x000000D0)
+#define RICU_AFE_CTRL_40_OFFSET      0x000000D0
+#define RICU_AFE_CTRL_40_INDEX       0x00000034
+#define RICU_AFE_CTRL_40_RESET       0x00000707
+
+static inline void ricu_afe_ctrl_40_pack(struct cl_chip *chip, u8 rosel5, u8 roctrlq5, u8 roctrli5)
+{
+       ASSERT_ERR_CHIP((((u32)rosel5 << 16) & ~((u32)0x00010000)) == 0);
+       ASSERT_ERR_CHIP((((u32)roctrlq5 << 8) & ~((u32)0x00007F00)) == 0);
+       ASSERT_ERR_CHIP((((u32)roctrli5 << 0) & ~((u32)0x0000007F)) == 0);
+       cl_reg_write_chip(chip, RICU_AFE_CTRL_40_ADDR, ((u32)rosel5 << 16) | ((u32)roctrlq5 << 8) | ((u32)roctrli5 << 0));
+}
+
+/*
+ * @brief AFE_CTRL_41 register definition
+ * <pre>
+ *   Bits           Field Name   Reset Value
+ *  -----   ------------------   -----------
+ *    16    ROSEL6                    0
+ *    14:08 RO_CTRLQ6                 0x7
+ *    06:00 RO_CTRLI6                 0x7
+ * </pre>
+ */
+#define RICU_AFE_CTRL_41_ADDR        (REG_RICU_BASE_ADDR + 0x000000D4)
+#define RICU_AFE_CTRL_41_OFFSET      0x000000D4
+#define RICU_AFE_CTRL_41_INDEX       0x00000035
+#define RICU_AFE_CTRL_41_RESET       0x00000707
+
+static inline void ricu_afe_ctrl_41_pack(struct cl_chip *chip, u8 rosel6, u8 roctrlq6, u8 roctrli6)
+{
+       ASSERT_ERR_CHIP((((u32)rosel6 << 16) & ~((u32)0x00010000)) == 0);
+       ASSERT_ERR_CHIP((((u32)roctrlq6 << 8) & ~((u32)0x00007F00)) == 0);
+       ASSERT_ERR_CHIP((((u32)roctrli6 << 0) & ~((u32)0x0000007F)) == 0);
+       cl_reg_write_chip(chip, RICU_AFE_CTRL_41_ADDR, ((u32)rosel6 << 16) | ((u32)roctrlq6 << 8) | ((u32)roctrli6 << 0));
+}
+
+/*
+ * @brief AFE_CTRL_42 register definition
+ * <pre>
+ *   Bits           Field Name   Reset Value
+ *  -----   ------------------   -----------
+ *    16    ROSEL7                    0
+ *    14:08 RO_CTRLQ7                 0x7
+ *    06:00 RO_CTRLI7                 0x7
+ * </pre>
+ */
+#define RICU_AFE_CTRL_42_ADDR        (REG_RICU_BASE_ADDR + 0x000000D8)
+#define RICU_AFE_CTRL_42_OFFSET      0x000000D8
+#define RICU_AFE_CTRL_42_INDEX       0x00000036
+#define RICU_AFE_CTRL_42_RESET       0x00000707
+
+static inline void ricu_afe_ctrl_42_pack(struct cl_chip *chip, u8 rosel7, u8 roctrlq7, u8 roctrli7)
+{
+       ASSERT_ERR_CHIP((((u32)rosel7 << 16) & ~((u32)0x00010000)) == 0);
+       ASSERT_ERR_CHIP((((u32)roctrlq7 << 8) & ~((u32)0x00007F00)) == 0);
+       ASSERT_ERR_CHIP((((u32)roctrli7 << 0) & ~((u32)0x0000007F)) == 0);
+       cl_reg_write_chip(chip, RICU_AFE_CTRL_42_ADDR, ((u32)rosel7 << 16) | ((u32)roctrlq7 << 8) | ((u32)roctrli7 << 0));
+}
+
+/*
+ * @brief AFE_CTRL_43 register definition
+ * <pre>
+ *   Bits           Field Name   Reset Value
+ *  -----   ------------------   -----------
+ *    01:00 FREQ_SEL                  0x3
+ * </pre>
+ */
+#define RICU_AFE_CTRL_43_ADDR        (REG_RICU_BASE_ADDR + 0x000000DC)
+#define RICU_AFE_CTRL_43_OFFSET      0x000000DC
+#define RICU_AFE_CTRL_43_INDEX       0x00000037
+#define RICU_AFE_CTRL_43_RESET       0x00000003
+
+static inline void ricu_afe_ctrl_43_freq_sel_setf(struct cl_chip *chip, u8 freqsel)
+{
+       ASSERT_ERR_CHIP((((u32)freqsel << 0) & ~((u32)0x00000003)) == 0);
+       cl_reg_write_chip(chip, RICU_AFE_CTRL_43_ADDR, (u32)freqsel << 0);
+}
+
+/*
+ * @brief AFE_CTRL_44 register definition
+ * <pre>
+ *   Bits           Field Name   Reset Value
+ *  -----   ------------------   -----------
+ *    01:00 CDB_FREQ_SEL              0x3
+ * </pre>
+ */
+#define RICU_AFE_CTRL_44_ADDR        (REG_RICU_BASE_ADDR + 0x000000E0)
+#define RICU_AFE_CTRL_44_OFFSET      0x000000E0
+#define RICU_AFE_CTRL_44_INDEX       0x00000038
+#define RICU_AFE_CTRL_44_RESET       0x00000003
+
+static inline void ricu_afe_ctrl_44_cdb_freq_sel_setf(struct cl_chip *chip, u8 cdbfreqsel)
+{
+       ASSERT_ERR_CHIP((((u32)cdbfreqsel << 0) & ~((u32)0x00000003)) == 0);
+       cl_reg_write_chip(chip, RICU_AFE_CTRL_44_ADDR, (u32)cdbfreqsel << 0);
+}
+
+/*
+ * @brief SPI_CLK_CTRL register definition
+ * <pre>
+ *   Bits           Field Name   Reset Value
+ *  -----   ------------------   -----------
+ *    05:00 SPI_CLK_BITMAP            0xE
+ * </pre>
+ */
+#define RICU_SPI_CLK_CTRL_ADDR        (REG_RICU_BASE_ADDR + 0x000000E4)
+#define RICU_SPI_CLK_CTRL_OFFSET      0x000000E4
+#define RICU_SPI_CLK_CTRL_INDEX       0x00000039
+#define RICU_SPI_CLK_CTRL_RESET       0x0000000E
+
+static inline void ricu_spi_clk_ctrl_set(struct cl_chip *chip, u32 value)
+{
+       cl_reg_write_chip(chip, RICU_SPI_CLK_CTRL_ADDR, value);
+}
+
+/*
+ * @brief FEM_CONF_0 register definition
+ * <pre>
+ *   Bits           Field Name   Reset Value
+ *  -----   ------------------   -----------
+ *    23:20 FEM5_CTL_SEL              0x5
+ *    19:16 FEM4_CTL_SEL              0x4
+ *    15:12 FEM3_CTL_SEL              0x3
+ *    11:08 FEM2_CTL_SEL              0x2
+ *    07:04 FEM1_CTL_SEL              0x1
+ *    03:00 FEM0_CTL_SEL              0x0
+ * </pre>
+ */
+#define RICU_FEM_CONF_0_ADDR        (REG_RICU_BASE_ADDR + 0x000000F0)
+#define RICU_FEM_CONF_0_OFFSET      0x000000F0
+#define RICU_FEM_CONF_0_INDEX       0x0000003C
+#define RICU_FEM_CONF_0_RESET       0x00543210
+
+static inline void ricu_fem_conf_0_set(struct cl_chip *chip, u32 value)
+{
+       cl_reg_write_chip(chip, RICU_FEM_CONF_0_ADDR, value);
+}
+
+/*
+ * @brief FEM_CONF_1 register definition
+ * <pre>
+ *   Bits           Field Name   Reset Value
+ *  -----   ------------------   -----------
+ *    23:20 FEM11_CTL_SEL             0xd
+ *    19:16 FEM10_CTL_SEL             0xc
+ *    15:12 FEM9_CTL_SEL              0xb
+ *    11:08 FEM8_CTL_SEL              0xa
+ *    07:04 FEM7_CTL_SEL              0x9
+ *    03:00 FEM6_CTL_SEL              0x8
+ * </pre>
+ */
+#define RICU_FEM_CONF_1_ADDR        (REG_RICU_BASE_ADDR + 0x000000F4)
+#define RICU_FEM_CONF_1_OFFSET      0x000000F4
+#define RICU_FEM_CONF_1_INDEX       0x0000003D
+#define RICU_FEM_CONF_1_RESET       0x00DCBA98
+
+static inline void ricu_fem_conf_1_set(struct cl_chip *chip, u32 value)
+{
+       cl_reg_write_chip(chip, RICU_FEM_CONF_1_ADDR, value);
+}
+
+/*
+ * @brief AFE_CTRL_36_PHY_1 register definition
+ * <pre>
+ *   Bits           Field Name   Reset Value
+ *  -----   ------------------   -----------
+ *    07    PHY1_ADC_ALWAYS_EN_LD_IR  0
+ *    06    PHY1_ADC_ALWAYS_EN_LD_AVDQ 0
+ *    05    PHY1_ADC_ALWAYS_EN_LD_AVDI 0
+ *    04    PHY1_ADC_ALWAYS_EN_ADCQ   0
+ *    03    PHY1_ADC_ALWAYS_EN_ADCI   0
+ *    01    PHY1_HW_MODE_DAC          0
+ *    00    PHY1_HW_MODE_ADC          0
+ * </pre>
+ */
+#define RICU_AFE_CTRL_36_PHY_1_ADDR        (REG_RICU_BASE_ADDR + 0x000000F8)
+#define RICU_AFE_CTRL_36_PHY_1_OFFSET      0x000000F8
+#define RICU_AFE_CTRL_36_PHY_1_INDEX       0x0000003E
+#define RICU_AFE_CTRL_36_PHY_1_RESET       0x00000000
+
+static inline u32 ricu_afe_ctrl_36_phy_1_get(struct cl_chip *chip)
+{
+       return cl_reg_read_chip(chip, RICU_AFE_CTRL_36_PHY_1_ADDR);
+}
+
+static inline void ricu_afe_ctrl_36_phy_1_set(struct cl_chip *chip, u32 value)
+{
+       cl_reg_write_chip(chip, RICU_AFE_CTRL_36_PHY_1_ADDR, value);
+}
+
+/* Field definitions */
+#define RICU_AFE_CTRL_36_PHY_1_ADC_ALWAYS_EN_LD_IR_BIT    ((u32)0x00000080)
+#define RICU_AFE_CTRL_36_PHY_1_ADC_ALWAYS_EN_LD_IR_POS    7
+#define RICU_AFE_CTRL_36_PHY_1_ADC_ALWAYS_EN_LD_AVDQ_BIT    ((u32)0x00000040)
+#define RICU_AFE_CTRL_36_PHY_1_ADC_ALWAYS_EN_LD_AVDQ_POS    6
+#define RICU_AFE_CTRL_36_PHY_1_ADC_ALWAYS_EN_LD_AVDI_BIT    ((u32)0x00000020)
+#define RICU_AFE_CTRL_36_PHY_1_ADC_ALWAYS_EN_LD_AVDI_POS    5
+#define RICU_AFE_CTRL_36_PHY_1_ADC_ALWAYS_EN_ADCQ_BIT    ((u32)0x00000010)
+#define RICU_AFE_CTRL_36_PHY_1_ADC_ALWAYS_EN_ADCQ_POS    4
+#define RICU_AFE_CTRL_36_PHY_1_ADC_ALWAYS_EN_ADCI_BIT    ((u32)0x00000008)
+#define RICU_AFE_CTRL_36_PHY_1_ADC_ALWAYS_EN_ADCI_POS    3
+#define RICU_AFE_CTRL_36_PHY_1_HW_MODE_DAC_BIT    ((u32)0x00000002)
+#define RICU_AFE_CTRL_36_PHY_1_HW_MODE_DAC_POS    1
+#define RICU_AFE_CTRL_36_PHY_1_HW_MODE_ADC_BIT    ((u32)0x00000001)
+#define RICU_AFE_CTRL_36_PHY_1_HW_MODE_ADC_POS    0
+
+static inline void ricu_afe_ctrl_36_phy_1_hw_mode_dac_setf(struct cl_chip *chip, u8 phy1hwmodedac)
+{
+       ASSERT_ERR_CHIP((((u32)phy1hwmodedac << 1) & ~((u32)0x00000002)) == 0);
+       cl_reg_write_chip(chip, RICU_AFE_CTRL_36_PHY_1_ADDR, (cl_reg_read_chip(chip, RICU_AFE_CTRL_36_PHY_1_ADDR) & ~((u32)0x00000002)) | ((u32)phy1hwmodedac << 1));
+}
+
+static inline void ricu_afe_ctrl_36_phy_1_hw_mode_adc_setf(struct cl_chip *chip, u8 phy1hwmodeadc)
+{
+       ASSERT_ERR_CHIP((((u32)phy1hwmodeadc << 0) & ~((u32)0x00000001)) == 0);
+       cl_reg_write_chip(chip, RICU_AFE_CTRL_36_PHY_1_ADDR, (cl_reg_read_chip(chip, RICU_AFE_CTRL_36_PHY_1_ADDR) & ~((u32)0x00000001)) | ((u32)phy1hwmodeadc << 0));
+}
+
+/*
+ * @brief AFE_ADC_CH_ALLOC register definition
+ * <pre>
+ *   Bits           Field Name   Reset Value
+ *  -----   ------------------   -----------
+ *    07:00 AFE_ADC_CH_ALLOC          0xFF
+ * </pre>
+ */
+#define RICU_AFE_ADC_CH_ALLOC_ADDR        (REG_RICU_BASE_ADDR + 0x000000FC)
+#define RICU_AFE_ADC_CH_ALLOC_OFFSET      0x000000FC
+#define RICU_AFE_ADC_CH_ALLOC_INDEX       0x0000003F
+#define RICU_AFE_ADC_CH_ALLOC_RESET       0x000000FF
+
+/* Field definitions */
+#define RICU_AFE_ADC_CH_ALLOC_AFE_ADC_CH_ALLOC_MASK    ((u32)0x000000FF)
+#define RICU_AFE_ADC_CH_ALLOC_AFE_ADC_CH_ALLOC_LSB    0
+#define RICU_AFE_ADC_CH_ALLOC_AFE_ADC_CH_ALLOC_WIDTH    ((u32)0x00000008)
+
+static inline void ricu_afe_adc_ch_alloc_afe_adc_ch_alloc_setf(struct cl_chip *chip, u8 afeadcchalloc)
+{
+       cl_reg_write_chip(chip, RICU_AFE_ADC_CH_ALLOC_ADDR, (u32)afeadcchalloc << 0);
+}
+
+#endif /*CL_REG_RICU_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.
________________________________


^ permalink raw reply related	[flat|nested] 262+ messages in thread

* [RFC v1 164/256] cl8k: add reg/reg_riu.h
  2021-06-17 15:58 [RFC v1 000/256] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (162 preceding siblings ...)
  2021-06-17 16:00 ` [RFC v1 163/256] cl8k: add reg/reg_ricu.h viktor.barna
@ 2021-06-17 16:00 ` viktor.barna
  2021-06-17 16:00 ` [RFC v1 165/256] cl8k: add reg/reg_riu_rc.h viktor.barna
                   ` (93 subsequent siblings)
  257 siblings, 0 replies; 262+ messages in thread
From: viktor.barna @ 2021-06-17 16:00 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Oleksandr Savchenko, Shay Bar, Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

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

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 .../net/wireless/celeno/cl8k/reg/reg_riu.h    | 902 ++++++++++++++++++
 1 file changed, 902 insertions(+)
 create mode 100644 drivers/net/wireless/celeno/cl8k/reg/reg_riu.h

diff --git a/drivers/net/wireless/celeno/cl8k/reg/reg_riu.h b/drivers/net/wireless/celeno/cl8k/reg/reg_riu.h
new file mode 100644
index 000000000000..15df2dcb13ee
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/reg/reg_riu.h
@@ -0,0 +1,902 @@
+/* SPDX-License-Identifier: MIT */
+/* Copyright(c) 2019-2021, Celeno Communications Ltd. */
+
+#ifndef CL_REG_RIU_H
+#define CL_REG_RIU_H
+
+#include <linux/types.h>
+#include "reg/reg_access.h"
+#include "hw.h"
+
+#define RIU_RSF_FILE_SIZE 0x60C
+
+/*
+ * @brief CCA_CNT_CS register definition
+ * <pre>
+ *   Bits           Field Name   Reset Value
+ *  -----   ------------------   -----------
+ *    31:00 CCA_CNT_CS                0x0
+ * </pre>
+ */
+#define RIU_CCA_CNT_CS_ADDR        (REG_RIU_BASE_ADDR + 0x00000058)
+#define RIU_CCA_CNT_CS_OFFSET      0x00000058
+#define RIU_CCA_CNT_CS_INDEX       0x00000016
+#define RIU_CCA_CNT_CS_RESET       0x00000000
+
+static inline u32 riu_cca_cnt_cs_get(struct cl_hw *cl_hw)
+{
+       return cl_reg_read(cl_hw, RIU_CCA_CNT_CS_ADDR);
+}
+
+/*
+ * @brief RSF_CONTROL register definition
+ *  resampling filter operation mode register description
+ * <pre>
+ *   Bits           Field Name   Reset Value
+ *  -----   ------------------   -----------
+ *    31    rsf_init_en               1
+ *    07    rsf_tx_bypass_type        0
+ *    06    rsf_tx_bypass_mode        1
+ *    05    rsf_rx_bypass_type        0
+ *    04    rsf_rx_bypass_mode        1
+ *    01    rsf_rx_ctl_from_reg       1
+ * </pre>
+ */
+#define RIU_RSF_CONTROL_ADDR        (REG_RIU_BASE_ADDR + 0x000001A8)
+#define RIU_RSF_CONTROL_OFFSET      0x000001A8
+#define RIU_RSF_CONTROL_INDEX       0x0000006A
+#define RIU_RSF_CONTROL_RESET       0x80000053
+
+static inline void riu_rsf_control_rsf_init_en_setf(struct cl_hw *cl_hw, u8 rsfiniten)
+{
+       cl_reg_write(cl_hw, RIU_RSF_CONTROL_ADDR,
+                    (cl_reg_read(cl_hw, RIU_RSF_CONTROL_ADDR) & ~((u32)0x80000000)) | ((u32)rsfiniten << 31));
+}
+
+/*
+ * @brief RSF_INIT register definition
+ *  resampling filter initialization data register description
+ * <pre>
+ *   Bits           Field Name   Reset Value
+ *  -----   ------------------   -----------
+ *    31:00 RSF_INIT_DATA             0x0
+ * </pre>
+ */
+#define RIU_RSF_INIT_ADDR        (REG_RIU_BASE_ADDR + 0x000001AC)
+#define RIU_RSF_INIT_OFFSET      0x000001AC
+#define RIU_RSF_INIT_INDEX       0x0000006B
+#define RIU_RSF_INIT_RESET       0x00000000
+
+static inline void riu_rsf_init_set(struct cl_hw *cl_hw, u32 value)
+{
+       cl_reg_write(cl_hw, RIU_RSF_INIT_ADDR, value);
+}
+
+/*
+ * @brief AGCFSM_RAM_INIT_1 register definition
+ * <pre>
+ *   Bits           Field Name   Reset Value
+ *  -----   ------------------   -----------
+ *    31    AGC_FSM_RAM_INIT_EN       0
+ *    29    AGC_FSM_RAM_INIT_AINC2    0
+ *    28    AGC_FSM_RAM_INIT_AINC1    0
+ *    12    AGC_FSM_RAM_INIT_WPTR_SET 0
+ *    10:00 AGC_FSM_RAM_INIT_WPTR     0x0
+ * </pre>
+ */
+#define RIU_AGCFSM_RAM_INIT_1_ADDR        (REG_RIU_BASE_ADDR + 0x000001B0)
+#define RIU_AGCFSM_RAM_INIT_1_OFFSET      0x000001B0
+#define RIU_AGCFSM_RAM_INIT_1_INDEX       0x0000006C
+#define RIU_AGCFSM_RAM_INIT_1_RESET       0x00000000
+
+static inline void riu_agcfsm_ram_init_1_agc_fsm_ram_init_wptr_setf(struct cl_hw *cl_hw,
+                                                                   u16 agcfsmraminitwptr)
+{
+       ASSERT_ERR((((u32)agcfsmraminitwptr << 0) & ~((u32)0x000007FF)) == 0);
+       cl_reg_write(cl_hw, RIU_AGCFSM_RAM_INIT_1_ADDR,
+                    (cl_reg_read(cl_hw, RIU_AGCFSM_RAM_INIT_1_ADDR) & ~((u32)0x000007FF)) | ((u32)agcfsmraminitwptr << 0));
+}
+
+static inline void riu_agcfsm_ram_init_1_agc_fsm_ram_init_wptr_set_setf(struct cl_hw *cl_hw, u8 agcfsmraminitwptrset)
+{
+       ASSERT_ERR((((u32)agcfsmraminitwptrset << 12) & ~((u32)0x00001000)) == 0);
+       cl_reg_write(cl_hw, RIU_AGCFSM_RAM_INIT_1_ADDR,
+                    (cl_reg_read(cl_hw, RIU_AGCFSM_RAM_INIT_1_ADDR) & ~((u32)0x00001000)) | ((u32)agcfsmraminitwptrset << 12));
+}
+
+static inline void riu_agcfsm_ram_init_1_agc_fsm_ram_init_ainc_1_setf(struct cl_hw *cl_hw,
+                                                                     u8 agcfsmraminitainc1)
+{
+       ASSERT_ERR((((u32)agcfsmraminitainc1 << 28) & ~((u32)0x10000000)) == 0);
+       cl_reg_write(cl_hw, RIU_AGCFSM_RAM_INIT_1_ADDR,
+                    (cl_reg_read(cl_hw, RIU_AGCFSM_RAM_INIT_1_ADDR) & ~((u32)0x10000000)) | ((u32)agcfsmraminitainc1 << 28));
+}
+
+static inline void riu_agcfsm_ram_init_1_agc_fsm_ram_init_en_setf(struct cl_hw *cl_hw,
+                                                                 u8 agcfsmraminiten)
+{
+       cl_reg_write(cl_hw, RIU_AGCFSM_RAM_INIT_1_ADDR,
+                    (cl_reg_read(cl_hw, RIU_AGCFSM_RAM_INIT_1_ADDR) & ~((u32)0x80000000)) | ((u32)agcfsmraminiten << 31));
+}
+
+/*
+ * @brief AGCFSM_RAM_INIT_2 register definition
+ * <pre>
+ *   Bits           Field Name   Reset Value
+ *  -----   ------------------   -----------
+ *    31:00 AGC_FSM_RAM_INIT_WDATA    0x0
+ * </pre>
+ */
+#define RIU_AGCFSM_RAM_INIT_2_ADDR        (REG_RIU_BASE_ADDR + 0x000001B4)
+#define RIU_AGCFSM_RAM_INIT_2_OFFSET      0x000001B4
+#define RIU_AGCFSM_RAM_INIT_2_INDEX       0x0000006D
+#define RIU_AGCFSM_RAM_INIT_2_RESET       0x00000000
+
+static inline void riu_agcfsm_ram_init_2_set(struct cl_hw *cl_hw, u32 value)
+{
+       cl_reg_write(cl_hw, RIU_AGCFSM_RAM_INIT_2_ADDR, value);
+}
+
+/*
+ * @brief AGCINBDPOW_20_STAT register definition
+ * <pre>
+ *   Bits           Field Name   Reset Value
+ *  -----   ------------------   -----------
+ *    31:24 INBDPOW20_PDBM3           0x0
+ *    23:16 INBDPOW20_PDBM2           0x0
+ *    15:08 INBDPOW20_PDBM1           0x0
+ *    07:00 INBDPOW20_PDBM0           0x0
+ * </pre>
+ */
+#define RIU_AGCINBDPOW_20_STAT_ADDR        (REG_RIU_BASE_ADDR + 0x0000020C)
+#define RIU_AGCINBDPOW_20_STAT_OFFSET      0x0000020C
+#define RIU_AGCINBDPOW_20_STAT_INDEX       0x00000083
+#define RIU_AGCINBDPOW_20_STAT_RESET       0x00000000
+
+static inline void riu_agcinbdpow_20_stat_unpack(struct cl_hw *cl_hw,
+                                                u8 *inbdpow20pdbm3, u8 *inbdpow20pdbm2,
+                                                u8 *inbdpow20pdbm1, u8 *inbdpow20pdbm0)
+{
+       u32 local_val = cl_reg_read(cl_hw, RIU_AGCINBDPOW_20_STAT_ADDR);
+
+       *inbdpow20pdbm3 = (local_val & ((u32)0xFF000000)) >> 24;
+       *inbdpow20pdbm2 = (local_val & ((u32)0x00FF0000)) >> 16;
+       *inbdpow20pdbm1 = (local_val & ((u32)0x0000FF00)) >> 8;
+       *inbdpow20pdbm0 = (local_val & ((u32)0x000000FF)) >> 0;
+}
+
+/*
+ * @brief AGCINBDPOW_20_PNOISESTAT register definition
+ * <pre>
+ *   Bits           Field Name   Reset Value
+ *  -----   ------------------   -----------
+ *    31:24 INBDPOW20_PNOISEDBM3      0x0
+ *    23:16 INBDPOW20_PNOISEDBM2      0x0
+ *    15:08 INBDPOW20_PNOISEDBM1      0x0
+ *    07:00 INBDPOW20_PNOISEDBM0      0x0
+ * </pre>
+ */
+#define RIU_AGCINBDPOW_20_PNOISESTAT_ADDR        (REG_RIU_BASE_ADDR + 0x00000228)
+#define RIU_AGCINBDPOW_20_PNOISESTAT_OFFSET      0x00000228
+#define RIU_AGCINBDPOW_20_PNOISESTAT_INDEX       0x0000008A
+#define RIU_AGCINBDPOW_20_PNOISESTAT_RESET       0x00000000
+
+static inline u32 riu_agcinbdpow_20_pnoisestat_get(struct cl_hw *cl_hw)
+{
+       return cl_reg_read(cl_hw, RIU_AGCINBDPOW_20_PNOISESTAT_ADDR);
+}
+
+/*
+ * @brief AGCINBDPOWSECNOISESTAT register definition
+ * <pre>
+ *   Bits           Field Name   Reset Value
+ *  -----   ------------------   -----------
+ *    23:16 INBDPOW80_SNOISEDBM       0x0
+ *    15:08 INBDPOW40_SNOISEDBM       0x0
+ *    07:00 INBDPOW20_SNOISEDBM       0x0
+ * </pre>
+ */
+#define RIU_AGCINBDPOWSECNOISESTAT_ADDR        (REG_RIU_BASE_ADDR + 0x00000230)
+#define RIU_AGCINBDPOWSECNOISESTAT_OFFSET      0x00000230
+#define RIU_AGCINBDPOWSECNOISESTAT_INDEX       0x0000008C
+#define RIU_AGCINBDPOWSECNOISESTAT_RESET       0x00000000
+
+static inline u32 riu_agcinbdpowsecnoisestat_get(struct cl_hw *cl_hw)
+{
+       return cl_reg_read(cl_hw, RIU_AGCINBDPOWSECNOISESTAT_ADDR);
+}
+
+/*
+ * @brief CCA_CNT_MODEM_STATE_P register definition
+ * <pre>
+ *   Bits           Field Name   Reset Value
+ *  -----   ------------------   -----------
+ *    31:00 CCA_CNT_MODEM_STATE_P     0x0
+ * </pre>
+ */
+#define RIU_CCA_CNT_MODEM_STATE_P_ADDR        (REG_RIU_BASE_ADDR + 0x000002DC)
+#define RIU_CCA_CNT_MODEM_STATE_P_OFFSET      0x000002DC
+#define RIU_CCA_CNT_MODEM_STATE_P_INDEX       0x000000B7
+#define RIU_CCA_CNT_MODEM_STATE_P_RESET       0x00000000
+
+static inline u32 riu_cca_cnt_modem_state_p_get(struct cl_hw *cl_hw)
+{
+       return cl_reg_read(cl_hw, RIU_CCA_CNT_MODEM_STATE_P_ADDR);
+}
+
+/*
+ * @brief CCA_CNT_MODEM_STATE_20_S register definition
+ * <pre>
+ *   Bits           Field Name   Reset Value
+ *  -----   ------------------   -----------
+ *    31:00 CCA_CNT_MODEM_STATE_20_S  0x0
+ * </pre>
+ */
+#define RIU_CCA_CNT_MODEM_STATE_20_S_ADDR        (REG_RIU_BASE_ADDR + 0x000002E0)
+#define RIU_CCA_CNT_MODEM_STATE_20_S_OFFSET      0x000002E0
+#define RIU_CCA_CNT_MODEM_STATE_20_S_INDEX       0x000000B8
+#define RIU_CCA_CNT_MODEM_STATE_20_S_RESET       0x00000000
+
+static inline u32 riu_cca_cnt_modem_state_20_s_get(struct cl_hw *cl_hw)
+{
+       return cl_reg_read(cl_hw, RIU_CCA_CNT_MODEM_STATE_20_S_ADDR);
+}
+
+/*
+ * @brief CCA_CNT_MODEM_STATE_40_S register definition
+ * <pre>
+ *   Bits           Field Name   Reset Value
+ *  -----   ------------------   -----------
+ *    31:00 CCA_CNT_MODEM_STATE_40_S  0x0
+ * </pre>
+ */
+#define RIU_CCA_CNT_MODEM_STATE_40_S_ADDR        (REG_RIU_BASE_ADDR + 0x000002E4)
+#define RIU_CCA_CNT_MODEM_STATE_40_S_OFFSET      0x000002E4
+#define RIU_CCA_CNT_MODEM_STATE_40_S_INDEX       0x000000B9
+#define RIU_CCA_CNT_MODEM_STATE_40_S_RESET       0x00000000
+
+static inline u32 riu_cca_cnt_modem_state_40_s_get(struct cl_hw *cl_hw)
+{
+       return cl_reg_read(cl_hw, RIU_CCA_CNT_MODEM_STATE_40_S_ADDR);
+}
+
+/*
+ * @brief CCA_CNT_MODEM_STATE_80_S register definition
+ * <pre>
+ *   Bits           Field Name   Reset Value
+ *  -----   ------------------   -----------
+ *    31:00 CCA_CNT_MODEM_STATE_80_S  0x0
+ * </pre>
+ */
+#define RIU_CCA_CNT_MODEM_STATE_80_S_ADDR        (REG_RIU_BASE_ADDR + 0x000002E8)
+#define RIU_CCA_CNT_MODEM_STATE_80_S_OFFSET      0x000002E8
+#define RIU_CCA_CNT_MODEM_STATE_80_S_INDEX       0x000000BA
+#define RIU_CCA_CNT_MODEM_STATE_80_S_RESET       0x00000000
+
+static inline u32 riu_cca_cnt_modem_state_80_s_get(struct cl_hw *cl_hw)
+{
+       return cl_reg_read(cl_hw, RIU_CCA_CNT_MODEM_STATE_80_S_ADDR);
+}
+
+/*
+ * @brief CCA_CNT_ENERGY_THR_P register definition
+ * <pre>
+ *   Bits           Field Name   Reset Value
+ *  -----   ------------------   -----------
+ *    31:00 CCA_CNT_ENERGY_THR_P      0x0
+ * </pre>
+ */
+#define RIU_CCA_CNT_ENERGY_THR_P_ADDR        (REG_RIU_BASE_ADDR + 0x000002F4)
+#define RIU_CCA_CNT_ENERGY_THR_P_OFFSET      0x000002F4
+#define RIU_CCA_CNT_ENERGY_THR_P_INDEX       0x000000BD
+#define RIU_CCA_CNT_ENERGY_THR_P_RESET       0x00000000
+
+static inline u32 riu_cca_cnt_energy_thr_p_get(struct cl_hw *cl_hw)
+{
+       return cl_reg_read(cl_hw, RIU_CCA_CNT_ENERGY_THR_P_ADDR);
+}
+
+/*
+ * @brief CCA_CNT_ENERGY_THR_20_S register definition
+ * <pre>
+ *   Bits           Field Name   Reset Value
+ *  -----   ------------------   -----------
+ *    31:00 CCA_CNT_ENERGY_THR_20_S   0x0
+ * </pre>
+ */
+#define RIU_CCA_CNT_ENERGY_THR_20_S_ADDR        (REG_RIU_BASE_ADDR + 0x000002F8)
+#define RIU_CCA_CNT_ENERGY_THR_20_S_OFFSET      0x000002F8
+#define RIU_CCA_CNT_ENERGY_THR_20_S_INDEX       0x000000BE
+#define RIU_CCA_CNT_ENERGY_THR_20_S_RESET       0x00000000
+
+static inline u32 riu_cca_cnt_energy_thr_20_s_get(struct cl_hw *cl_hw)
+{
+       return cl_reg_read(cl_hw, RIU_CCA_CNT_ENERGY_THR_20_S_ADDR);
+}
+
+/*
+ * @brief CCA_CNT_GI_20_P register definition
+ * <pre>
+ *   Bits           Field Name   Reset Value
+ *  -----   ------------------   -----------
+ *    31:00 CCA_CNT_GI_20_P           0x0
+ * </pre>
+ */
+#define RIU_CCA_CNT_GI_20_P_ADDR        (REG_RIU_BASE_ADDR + 0x000002FC)
+#define RIU_CCA_CNT_GI_20_P_OFFSET      0x000002FC
+#define RIU_CCA_CNT_GI_20_P_INDEX       0x000000BF
+#define RIU_CCA_CNT_GI_20_P_RESET       0x00000000
+
+static inline u32 riu_cca_cnt_gi_20_p_get(struct cl_hw *cl_hw)
+{
+       return cl_reg_read(cl_hw, RIU_CCA_CNT_GI_20_P_ADDR);
+}
+
+/*
+ * @brief RWNXAGCRAMP register definition
+ * <pre>
+ *   Bits           Field Name   Reset Value
+ *  -----   ------------------   -----------
+ *    26:24 RAMPDNNDLINDEX            0x5
+ *    23:16 RAMPDNGAPQDB              0x20
+ *    10:08 RAMPUPNDLINDEX            0x7
+ *    07:00 RAMPUPGAPQDB              0x10
+ * </pre>
+ */
+#define RIU_RWNXAGCRAMP_ADDR        (REG_RIU_BASE_ADDR + 0x0000036C)
+#define RIU_RWNXAGCRAMP_OFFSET      0x0000036C
+#define RIU_RWNXAGCRAMP_INDEX       0x000000DB
+#define RIU_RWNXAGCRAMP_RESET       0x05200710
+
+static inline u8 riu_rwnxagcramp_rampupgapqdb_getf(struct cl_hw *cl_hw)
+{
+       u32 local_val = cl_reg_read(cl_hw, RIU_RWNXAGCRAMP_ADDR);
+
+       return ((local_val & ((u32)0x000000FF)) >> 0);
+}
+
+static inline void riu_rwnxagcramp_rampupgapqdb_setf(struct cl_hw *cl_hw, u8 rampupgapqdb)
+{
+       cl_reg_write(cl_hw, RIU_RWNXAGCRAMP_ADDR,
+                    (cl_reg_read(cl_hw, RIU_RWNXAGCRAMP_ADDR) & ~((u32)0x000000FF)) | ((u32)rampupgapqdb << 0));
+}
+
+/*
+ * @brief RWNXAGCCNTL register definition
+ * <pre>
+ *   Bits           Field Name   Reset Value
+ *  -----   ------------------   -----------
+ *    31:26 COMBPATHSEL               0x3F
+ *    25:20 GAINKEEP                  0x0
+ *    16    HTSTFGAINEN               1
+ *    15    NOISE_CAPTURE_DELAY_MODE  0
+ *    14    EST_PATH_SEL_2            0
+ *    13    CCA_MDM_ST_CLEAR          0
+ *    12    AGCFSMRESET               0
+ *    11    RADARDETEN                0
+ *    10    RIFSDETEN                 1
+ *    09    DSSSONLY                  0
+ *    08    OFDMONLY                  0
+ *    07:04 GPSTATUS                  0x0
+ *    03    EST_PATH_SEL              0
+ *    01    ADC_SEL_RADAR_DETECTOR    0
+ *    00    ADC_SEL_COMP_MODULE       0
+ * </pre>
+ */
+#define RIU_RWNXAGCCNTL_ADDR        (REG_RIU_BASE_ADDR + 0x00000390)
+#define RIU_RWNXAGCCNTL_OFFSET      0x00000390
+#define RIU_RWNXAGCCNTL_INDEX       0x000000E4
+#define RIU_RWNXAGCCNTL_RESET       0xFC010400
+
+static inline void riu_rwnxagccntl_agcfsmreset_setf(struct cl_hw *cl_hw, u8 agcfsmreset)
+{
+       ASSERT_ERR((((u32)agcfsmreset << 12) & ~((u32)0x00001000)) == 0);
+       cl_reg_write(cl_hw, RIU_RWNXAGCCNTL_ADDR,
+                    (cl_reg_read(cl_hw, RIU_RWNXAGCCNTL_ADDR) & ~((u32)0x00001000)) | ((u32)agcfsmreset << 12));
+}
+
+/*
+ * @brief RWNXAGCCCA_1 register definition
+ * <pre>
+ *   Bits           Field Name   Reset Value
+ *  -----   ------------------   -----------
+ *    31    CCA_CNT_CLEAR             0
+ *    30:29 CCA_CNT_RATE              0x0
+ *    28:20 INBDCCAPOWMINDBM          0x1B5
+ *    19:12 CCAFALLTHRDBM             0xBF
+ *    10    CCAEnergy_Reset_Type      0
+ *    09    DISCCAEN                  1
+ *    08    SATCCAEN                  1
+ *    07:00 CCARISETHRDBM             0xC2
+ * </pre>
+ */
+#define RIU_RWNXAGCCCA_1_ADDR        (REG_RIU_BASE_ADDR + 0x000003AC)
+#define RIU_RWNXAGCCCA_1_OFFSET      0x000003AC
+#define RIU_RWNXAGCCCA_1_INDEX       0x000000EB
+#define RIU_RWNXAGCCCA_1_RESET       0x1B5BF3C2
+
+static inline void riu_rwnxagccca_1_cca_cnt_clear_setf(struct cl_hw *cl_hw, u8 ccacntclear)
+{
+       cl_reg_write(cl_hw, RIU_RWNXAGCCCA_1_ADDR,
+                    (cl_reg_read(cl_hw, RIU_RWNXAGCCCA_1_ADDR) & ~((u32)0x80000000)) | ((u32)ccacntclear << 31));
+}
+
+/*
+ * @brief RWNXAGCCCACTRL register definition
+ * <pre>
+ *   Bits           Field Name   Reset Value
+ *  -----   ------------------   -----------
+ *    31:28 CCAFLAG3_CTRL             0xA
+ *    27:24 CCAFLAG2_CTRL             0x2
+ *    23:20 CCAFLAG1_CTRL             0x8
+ *    19:16 CCAFLAG0_CTRL             0x0
+ *    14:12 CCA_SECOND_ANT_SEL        0x1
+ *    10:08 CCA_MAIN_ANT_SEL          0x0
+ *    07:04 CCADEMOD                  0xF
+ *    00    CCACSEN                   1
+ * </pre>
+ */
+#define RIU_RWNXAGCCCACTRL_ADDR        (REG_RIU_BASE_ADDR + 0x000003B0)
+#define RIU_RWNXAGCCCACTRL_OFFSET      0x000003B0
+#define RIU_RWNXAGCCCACTRL_INDEX       0x000000EC
+#define RIU_RWNXAGCCCACTRL_RESET       0xA28010F1
+
+static inline void riu_rwnxagcccactrl_cca_main_ant_sel_setf(struct cl_hw *cl_hw, u8 ccamainantsel)
+{
+       ASSERT_ERR((((u32)ccamainantsel << 8) & ~((u32)0x00000700)) == 0);
+       cl_reg_write(cl_hw, RIU_RWNXAGCCCACTRL_ADDR,
+                    (cl_reg_read(cl_hw, RIU_RWNXAGCCCACTRL_ADDR) & ~((u32)0x00000700)) | ((u32)ccamainantsel << 8));
+}
+
+/*
+ * @brief RWNXAGCCCASTATE_0 register definition
+ * <pre>
+ *   Bits           Field Name   Reset Value
+ *  -----   ------------------   -----------
+ *    28    CCAMDMSTFORCEEN           0
+ *    27:24 CCAMDMSTFORCE             0x0
+ *    23:12 RXSTATECCA20_SSEL         0x380
+ *    11:00 RXSTATECCA20_PSEL         0x3F8
+ * </pre>
+ */
+#define RIU_RWNXAGCCCASTATE_0_ADDR        (REG_RIU_BASE_ADDR + 0x000003B4)
+#define RIU_RWNXAGCCCASTATE_0_OFFSET      0x000003B4
+#define RIU_RWNXAGCCCASTATE_0_INDEX       0x000000ED
+#define RIU_RWNXAGCCCASTATE_0_RESET       0x003803F8
+
+static inline void riu_rwnxagcccastate_0_rxstatecca_20_psel_setf(struct cl_hw *cl_hw,
+                                                                u16 rxstatecca20psel)
+{
+       ASSERT_ERR((((u32)rxstatecca20psel << 0) & ~((u32)0x00000FFF)) == 0);
+       cl_reg_write(cl_hw, RIU_RWNXAGCCCASTATE_0_ADDR,
+                    (cl_reg_read(cl_hw, RIU_RWNXAGCCCASTATE_0_ADDR) & ~((u32)0x00000FFF)) | ((u32)rxstatecca20psel << 0));
+}
+
+/*
+ * @brief AGCINBDPOWNOISEPER_20_STAT_0 register definition
+ * <pre>
+ *   Bits           Field Name   Reset Value
+ *  -----   ------------------   -----------
+ *    31:24 INBDPOWNOISEDBMPER20_3    0x0
+ *    23:16 INBDPOWNOISEDBMPER20_2    0x0
+ *    15:08 INBDPOWNOISEDBMPER20_1    0x0
+ *    07:00 INBDPOWNOISEDBMPER20_0    0x0
+ * </pre>
+ */
+#define RIU_AGCINBDPOWNOISEPER_20_STAT_0_ADDR        (REG_RIU_BASE_ADDR + 0x00000478)
+#define RIU_AGCINBDPOWNOISEPER_20_STAT_0_OFFSET      0x00000478
+#define RIU_AGCINBDPOWNOISEPER_20_STAT_0_INDEX       0x0000011E
+#define RIU_AGCINBDPOWNOISEPER_20_STAT_0_RESET       0x00000000
+
+static inline u32 riu_agcinbdpownoiseper_20_stat_0_get(struct cl_hw *cl_hw)
+{
+       return cl_reg_read(cl_hw, RIU_AGCINBDPOWNOISEPER_20_STAT_0_ADDR);
+}
+
+/*
+ * @brief AGCINBDPOWNOISEPER_20_STAT_1 register definition
+ * <pre>
+ *   Bits           Field Name   Reset Value
+ *  -----   ------------------   -----------
+ *    31:24 INBDPOWNOISEDBMPER20_7    0x0
+ *    23:16 INBDPOWNOISEDBMPER20_6    0x0
+ *    15:08 INBDPOWNOISEDBMPER20_5    0x0
+ *    07:00 INBDPOWNOISEDBMPER20_4    0x0
+ * </pre>
+ */
+#define RIU_AGCINBDPOWNOISEPER_20_STAT_1_ADDR        (REG_RIU_BASE_ADDR + 0x0000047C)
+#define RIU_AGCINBDPOWNOISEPER_20_STAT_1_OFFSET      0x0000047C
+#define RIU_AGCINBDPOWNOISEPER_20_STAT_1_INDEX       0x0000011F
+#define RIU_AGCINBDPOWNOISEPER_20_STAT_1_RESET       0x00000000
+
+static inline u32 riu_agcinbdpownoiseper_20_stat_1_get(struct cl_hw *cl_hw)
+{
+       return cl_reg_read(cl_hw, RIU_AGCINBDPOWNOISEPER_20_STAT_1_ADDR);
+}
+
+/*
+ * @brief INBDPOWFORMAC_0 register definition
+ * <pre>
+ *   Bits           Field Name   Reset Value
+ *  -----   ------------------   -----------
+ *    31:24 INBDPOW20_PDBMA3_MAC      0x0
+ *    23:16 INBDPOW20_PDBMA2_MAC      0x0
+ *    15:08 INBDPOW20_PDBMA1_MAC      0x0
+ *    07:00 INBDPOW20_PDBMA0_MAC      0x0
+ * </pre>
+ */
+#define RIU_INBDPOWFORMAC_0_ADDR        (REG_RIU_BASE_ADDR + 0x00000480)
+#define RIU_INBDPOWFORMAC_0_OFFSET      0x00000480
+#define RIU_INBDPOWFORMAC_0_INDEX       0x00000120
+#define RIU_INBDPOWFORMAC_0_RESET       0x00000000
+
+static inline u32 riu_inbdpowformac_0_get(struct cl_hw *cl_hw)
+{
+       return cl_reg_read(cl_hw, RIU_INBDPOWFORMAC_0_ADDR);
+}
+
+/*
+ * @brief INBDPOWFORMAC_1 register definition
+ * <pre>
+ *   Bits           Field Name   Reset Value
+ *  -----   ------------------   -----------
+ *    15:08 INBDPOW20_PDBMA5_MAC      0x0
+ *    07:00 INBDPOW20_PDBMA4_MAC      0x0
+ * </pre>
+ */
+#define RIU_INBDPOWFORMAC_1_ADDR        (REG_RIU_BASE_ADDR + 0x00000484)
+#define RIU_INBDPOWFORMAC_1_OFFSET      0x00000484
+#define RIU_INBDPOWFORMAC_1_INDEX       0x00000121
+#define RIU_INBDPOWFORMAC_1_RESET       0x00000000
+
+static inline u32 riu_inbdpowformac_1_get(struct cl_hw *cl_hw)
+{
+       return cl_reg_read(cl_hw, RIU_INBDPOWFORMAC_1_ADDR);
+}
+
+/*
+ * @brief INBDPOWFORMAC_2 register definition
+ * <pre>
+ *   Bits           Field Name   Reset Value
+ *  -----   ------------------   -----------
+ *    23:16 INBDPOW80_SDBM_MAC        0x0
+ *    15:08 INBDPOW40_SDBM_MAC        0x0
+ *    07:00 INBDPOW20_SDBM_MAC        0x0
+ * </pre>
+ */
+#define RIU_INBDPOWFORMAC_2_ADDR        (REG_RIU_BASE_ADDR + 0x00000488)
+#define RIU_INBDPOWFORMAC_2_OFFSET      0x00000488
+#define RIU_INBDPOWFORMAC_2_INDEX       0x00000122
+#define RIU_INBDPOWFORMAC_2_RESET       0x00000000
+
+static inline u32 riu_inbdpowformac_2_get(struct cl_hw *cl_hw)
+{
+       return cl_reg_read(cl_hw, RIU_INBDPOWFORMAC_2_ADDR);
+}
+
+/*
+ * @brief INBDPOWFORMAC_3 register definition
+ * <pre>
+ *   Bits           Field Name   Reset Value
+ *  -----   ------------------   -----------
+ *    31:24 INBDPOWPER20_PDBM_3_MAC   0x0
+ *    23:16 INBDPOWPER20_PDBM_2_MAC   0x0
+ *    15:08 INBDPOWPER20_PDBM_1_MAC   0x0
+ *    07:00 INBDPOWPER20_PDBM_0_MAC   0x0
+ * </pre>
+ */
+#define RIU_INBDPOWFORMAC_3_ADDR        (REG_RIU_BASE_ADDR + 0x0000048C)
+#define RIU_INBDPOWFORMAC_3_OFFSET      0x0000048C
+#define RIU_INBDPOWFORMAC_3_INDEX       0x00000123
+#define RIU_INBDPOWFORMAC_3_RESET       0x00000000
+
+static inline u32 riu_inbdpowformac_3_get(struct cl_hw *cl_hw)
+{
+       return cl_reg_read(cl_hw, RIU_INBDPOWFORMAC_3_ADDR);
+}
+
+/*
+ * @brief INBDPOWFORMAC_4 register definition
+ * <pre>
+ *   Bits           Field Name   Reset Value
+ *  -----   ------------------   -----------
+ *    31:24 INBDPOWPER20_PDBM_7_MAC   0x0
+ *    23:16 INBDPOWPER20_PDBM_6_MAC   0x0
+ *    15:08 INBDPOWPER20_PDBM_5_MAC   0x0
+ *    07:00 INBDPOWPER20_PDBM_4_MAC   0x0
+ * </pre>
+ */
+#define RIU_INBDPOWFORMAC_4_ADDR        (REG_RIU_BASE_ADDR + 0x00000490)
+#define RIU_INBDPOWFORMAC_4_OFFSET      0x00000490
+#define RIU_INBDPOWFORMAC_4_INDEX       0x00000124
+#define RIU_INBDPOWFORMAC_4_RESET       0x00000000
+
+static inline u32 riu_inbdpowformac_4_get(struct cl_hw *cl_hw)
+{
+       return cl_reg_read(cl_hw, RIU_INBDPOWFORMAC_4_ADDR);
+}
+
+/*
+ * @brief CCA_CNT_GI_20_S register definition
+ * <pre>
+ *   Bits           Field Name   Reset Value
+ *  -----   ------------------   -----------
+ *    31:00 CCA_CNT_GI_20_S           0x0
+ * </pre>
+ */
+#define RIU_CCA_CNT_GI_20_S_ADDR        (REG_RIU_BASE_ADDR + 0x00000494)
+#define RIU_CCA_CNT_GI_20_S_OFFSET      0x00000494
+#define RIU_CCA_CNT_GI_20_S_INDEX       0x00000125
+#define RIU_CCA_CNT_GI_20_S_RESET       0x00000000
+
+static inline u32 riu_cca_cnt_gi_20_s_get(struct cl_hw *cl_hw)
+{
+       return cl_reg_read(cl_hw, RIU_CCA_CNT_GI_20_S_ADDR);
+}
+
+/*
+ * @brief CCA_CNT_GI_40_S register definition
+ * <pre>
+ *   Bits           Field Name   Reset Value
+ *  -----   ------------------   -----------
+ *    31:00 CCA_CNT_GI_40_S           0x0
+ * </pre>
+ */
+#define RIU_CCA_CNT_GI_40_S_ADDR        (REG_RIU_BASE_ADDR + 0x00000498)
+#define RIU_CCA_CNT_GI_40_S_OFFSET      0x00000498
+#define RIU_CCA_CNT_GI_40_S_INDEX       0x00000126
+#define RIU_CCA_CNT_GI_40_S_RESET       0x00000000
+
+static inline u32 riu_cca_cnt_gi_40_s_get(struct cl_hw *cl_hw)
+{
+       return cl_reg_read(cl_hw, RIU_CCA_CNT_GI_40_S_ADDR);
+}
+
+/*
+ * @brief CCA_CNT_GI_80_S register definition
+ * <pre>
+ *   Bits           Field Name   Reset Value
+ *  -----   ------------------   -----------
+ *    31:00 CCA_CNT_GI_80_S           0x0
+ * </pre>
+ */
+#define RIU_CCA_CNT_GI_80_S_ADDR        (REG_RIU_BASE_ADDR + 0x0000049C)
+#define RIU_CCA_CNT_GI_80_S_OFFSET      0x0000049C
+#define RIU_CCA_CNT_GI_80_S_INDEX       0x00000127
+#define RIU_CCA_CNT_GI_80_S_RESET       0x00000000
+
+static inline u32 riu_cca_cnt_gi_80_s_get(struct cl_hw *cl_hw)
+{
+       return cl_reg_read(cl_hw, RIU_CCA_CNT_GI_80_S_ADDR);
+}
+
+/*
+ * @brief CCA_CNT_ENERGY_THR_40_S register definition
+ * <pre>
+ *   Bits           Field Name   Reset Value
+ *  -----   ------------------   -----------
+ *    31:00 CCA_CNT_ENERGY_THR_40_S   0x0
+ * </pre>
+ */
+#define RIU_CCA_CNT_ENERGY_THR_40_S_ADDR        (REG_RIU_BASE_ADDR + 0x000004A0)
+#define RIU_CCA_CNT_ENERGY_THR_40_S_OFFSET      0x000004A0
+#define RIU_CCA_CNT_ENERGY_THR_40_S_INDEX       0x00000128
+#define RIU_CCA_CNT_ENERGY_THR_40_S_RESET       0x00000000
+
+static inline u32 riu_cca_cnt_energy_thr_40_s_get(struct cl_hw *cl_hw)
+{
+       return cl_reg_read(cl_hw, RIU_CCA_CNT_ENERGY_THR_40_S_ADDR);
+}
+
+/*
+ * @brief CCA_CNT_ENERGY_THR_80_S register definition
+ * <pre>
+ *   Bits           Field Name   Reset Value
+ *  -----   ------------------   -----------
+ *    31:00 CCA_CNT_ENERGY_THR_80_S   0x0
+ * </pre>
+ */
+#define RIU_CCA_CNT_ENERGY_THR_80_S_ADDR        (REG_RIU_BASE_ADDR + 0x000004A4)
+#define RIU_CCA_CNT_ENERGY_THR_80_S_OFFSET      0x000004A4
+#define RIU_CCA_CNT_ENERGY_THR_80_S_INDEX       0x00000129
+#define RIU_CCA_CNT_ENERGY_THR_80_S_RESET       0x00000000
+
+static inline u32 riu_cca_cnt_energy_thr_80_s_get(struct cl_hw *cl_hw)
+{
+       return cl_reg_read(cl_hw, RIU_CCA_CNT_ENERGY_THR_80_S_ADDR);
+}
+
+/*
+ * @brief CCA_CNT_ENERGY_THR_20_BAND_0 register definition
+ * <pre>
+ *   Bits           Field Name   Reset Value
+ *  -----   ------------------   -----------
+ *    31:00 CCA_CNT_ENERGY_THR_20_BAND_0 0x0
+ * </pre>
+ */
+#define RIU_CCA_CNT_ENERGY_THR_20_BAND_0_ADDR        (REG_RIU_BASE_ADDR + 0x000004A8)
+#define RIU_CCA_CNT_ENERGY_THR_20_BAND_0_OFFSET      0x000004A8
+#define RIU_CCA_CNT_ENERGY_THR_20_BAND_0_INDEX       0x0000012A
+#define RIU_CCA_CNT_ENERGY_THR_20_BAND_0_RESET       0x00000000
+
+static inline u32 riu_cca_cnt_energy_thr_20_band_0_get(struct cl_hw *cl_hw)
+{
+       return cl_reg_read(cl_hw, RIU_CCA_CNT_ENERGY_THR_20_BAND_0_ADDR);
+}
+
+/*
+ * @brief CCA_CNT_ENERGY_THR_20_BAND_1 register definition
+ * <pre>
+ *   Bits           Field Name   Reset Value
+ *  -----   ------------------   -----------
+ *    31:00 CCA_CNT_ENERGY_THR_20_BAND_1 0x0
+ * </pre>
+ */
+#define RIU_CCA_CNT_ENERGY_THR_20_BAND_1_ADDR        (REG_RIU_BASE_ADDR + 0x000004AC)
+#define RIU_CCA_CNT_ENERGY_THR_20_BAND_1_OFFSET      0x000004AC
+#define RIU_CCA_CNT_ENERGY_THR_20_BAND_1_INDEX       0x0000012B
+#define RIU_CCA_CNT_ENERGY_THR_20_BAND_1_RESET       0x00000000
+
+static inline u32 riu_cca_cnt_energy_thr_20_band_1_get(struct cl_hw *cl_hw)
+{
+       return cl_reg_read(cl_hw, RIU_CCA_CNT_ENERGY_THR_20_BAND_1_ADDR);
+}
+
+/*
+ * @brief CCA_CNT_ENERGY_THR_20_BAND_2 register definition
+ * <pre>
+ *   Bits           Field Name   Reset Value
+ *  -----   ------------------   -----------
+ *    31:00 CCA_CNT_ENERGY_THR_20_BAND_2 0x0
+ * </pre>
+ */
+#define RIU_CCA_CNT_ENERGY_THR_20_BAND_2_ADDR        (REG_RIU_BASE_ADDR + 0x000004B0)
+#define RIU_CCA_CNT_ENERGY_THR_20_BAND_2_OFFSET      0x000004B0
+#define RIU_CCA_CNT_ENERGY_THR_20_BAND_2_INDEX       0x0000012C
+#define RIU_CCA_CNT_ENERGY_THR_20_BAND_2_RESET       0x00000000
+
+static inline u32 riu_cca_cnt_energy_thr_20_band_2_get(struct cl_hw *cl_hw)
+{
+       return cl_reg_read(cl_hw, RIU_CCA_CNT_ENERGY_THR_20_BAND_2_ADDR);
+}
+
+/*
+ * @brief CCA_CNT_ENERGY_THR_20_BAND_3 register definition
+ * <pre>
+ *   Bits           Field Name   Reset Value
+ *  -----   ------------------   -----------
+ *    31:00 CCA_CNT_ENERGY_THR_20_BAND_3 0x0
+ * </pre>
+ */
+#define RIU_CCA_CNT_ENERGY_THR_20_BAND_3_ADDR        (REG_RIU_BASE_ADDR + 0x000004B4)
+#define RIU_CCA_CNT_ENERGY_THR_20_BAND_3_OFFSET      0x000004B4
+#define RIU_CCA_CNT_ENERGY_THR_20_BAND_3_INDEX       0x0000012D
+#define RIU_CCA_CNT_ENERGY_THR_20_BAND_3_RESET       0x00000000
+
+static inline u32 riu_cca_cnt_energy_thr_20_band_3_get(struct cl_hw *cl_hw)
+{
+       return cl_reg_read(cl_hw, RIU_CCA_CNT_ENERGY_THR_20_BAND_3_ADDR);
+}
+
+/*
+ * @brief CCA_CNT_ENERGY_THR_20_BAND_4 register definition
+ * <pre>
+ *   Bits           Field Name   Reset Value
+ *  -----   ------------------   -----------
+ *    31:00 CCA_CNT_ENERGY_THR_20_BAND_4 0x0
+ * </pre>
+ */
+#define RIU_CCA_CNT_ENERGY_THR_20_BAND_4_ADDR        (REG_RIU_BASE_ADDR + 0x000004B8)
+#define RIU_CCA_CNT_ENERGY_THR_20_BAND_4_OFFSET      0x000004B8
+#define RIU_CCA_CNT_ENERGY_THR_20_BAND_4_INDEX       0x0000012E
+#define RIU_CCA_CNT_ENERGY_THR_20_BAND_4_RESET       0x00000000
+
+static inline u32 riu_cca_cnt_energy_thr_20_band_4_get(struct cl_hw *cl_hw)
+{
+       return cl_reg_read(cl_hw, RIU_CCA_CNT_ENERGY_THR_20_BAND_4_ADDR);
+}
+
+/*
+ * @brief CCA_CNT_ENERGY_THR_20_BAND_5 register definition
+ * <pre>
+ *   Bits           Field Name   Reset Value
+ *  -----   ------------------   -----------
+ *    31:00 CCA_CNT_ENERGY_THR_20_BAND_5 0x0
+ * </pre>
+ */
+#define RIU_CCA_CNT_ENERGY_THR_20_BAND_5_ADDR        (REG_RIU_BASE_ADDR + 0x000004BC)
+#define RIU_CCA_CNT_ENERGY_THR_20_BAND_5_OFFSET      0x000004BC
+#define RIU_CCA_CNT_ENERGY_THR_20_BAND_5_INDEX       0x0000012F
+#define RIU_CCA_CNT_ENERGY_THR_20_BAND_5_RESET       0x00000000
+
+static inline u32 riu_cca_cnt_energy_thr_20_band_5_get(struct cl_hw *cl_hw)
+{
+       return cl_reg_read(cl_hw, RIU_CCA_CNT_ENERGY_THR_20_BAND_5_ADDR);
+}
+
+/*
+ * @brief CCA_CNT_ENERGY_THR_20_BAND_6 register definition
+ * <pre>
+ *   Bits           Field Name   Reset Value
+ *  -----   ------------------   -----------
+ *    31:00 CCA_CNT_ENERGY_THR_20_BAND_6 0x0
+ * </pre>
+ */
+#define RIU_CCA_CNT_ENERGY_THR_20_BAND_6_ADDR        (REG_RIU_BASE_ADDR + 0x000004C0)
+#define RIU_CCA_CNT_ENERGY_THR_20_BAND_6_OFFSET      0x000004C0
+#define RIU_CCA_CNT_ENERGY_THR_20_BAND_6_INDEX       0x00000130
+#define RIU_CCA_CNT_ENERGY_THR_20_BAND_6_RESET       0x00000000
+
+static inline u32 riu_cca_cnt_energy_thr_20_band_6_get(struct cl_hw *cl_hw)
+{
+       return cl_reg_read(cl_hw, RIU_CCA_CNT_ENERGY_THR_20_BAND_6_ADDR);
+}
+
+/*
+ * @brief CCA_CNT_ENERGY_THR_20_BAND_7 register definition
+ * <pre>
+ *   Bits           Field Name   Reset Value
+ *  -----   ------------------   -----------
+ *    31:00 CCA_CNT_ENERGY_THR_20_BAND_7 0x0
+ * </pre>
+ */
+#define RIU_CCA_CNT_ENERGY_THR_20_BAND_7_ADDR        (REG_RIU_BASE_ADDR + 0x000004C4)
+#define RIU_CCA_CNT_ENERGY_THR_20_BAND_7_OFFSET      0x000004C4
+#define RIU_CCA_CNT_ENERGY_THR_20_BAND_7_INDEX       0x00000131
+#define RIU_CCA_CNT_ENERGY_THR_20_BAND_7_RESET       0x00000000
+
+static inline u32 riu_cca_cnt_energy_thr_20_band_7_get(struct cl_hw *cl_hw)
+{
+       return cl_reg_read(cl_hw, RIU_CCA_CNT_ENERGY_THR_20_BAND_7_ADDR);
+}
+
+/*
+ * @brief AGCADCPOWSTAT_2 register definition
+ * <pre>
+ *   Bits           Field Name   Reset Value
+ *  -----   ------------------   -----------
+ *    31:24 INBDPOW20_PDBM5           0x0
+ *    23:16 INBDPOW20_PDBM4           0x0
+ *    14:08 ADCPOWDBV5                0x0
+ *    06:00 ADCPOWDBV4                0x0
+ * </pre>
+ */
+#define RIU_AGCADCPOWSTAT_2_ADDR        (REG_RIU_BASE_ADDR + 0x00000670)
+#define RIU_AGCADCPOWSTAT_2_OFFSET      0x00000670
+#define RIU_AGCADCPOWSTAT_2_INDEX       0x0000019C
+#define RIU_AGCADCPOWSTAT_2_RESET       0x00000000
+
+static inline void riu_agcadcpowstat_2_unpack(struct cl_hw *cl_hw,
+                                             u8 *inbdpow20pdbm5, u8 *inbdpow20pdbm4,
+                                             u8 *adcpowdbv5, u8 *adcpowdbv4)
+{
+       u32 local_val = cl_reg_read(cl_hw, RIU_AGCADCPOWSTAT_2_ADDR);
+
+       *inbdpow20pdbm5 = (local_val & ((u32)0xFF000000)) >> 24;
+       *inbdpow20pdbm4 = (local_val & ((u32)0x00FF0000)) >> 16;
+       *adcpowdbv5 = (local_val & ((u32)0x00007F00)) >> 8;
+       *adcpowdbv4 = (local_val & ((u32)0x0000007F)) >> 0;
+}
+
+/*
+ * @brief AGCINBDPOW_20_PNOISESTAT_2 register definition
+ * <pre>
+ *   Bits           Field Name   Reset Value
+ *  -----   ------------------   -----------
+ *    31:24 INBDPOW20_PNOISEDBM5      0x0
+ *    23:16 INBDPOW20_PNOISEDBM4      0x0
+ *    15:08 ADCPOWDBM5                0x0
+ *    07:00 ADCPOWDBM4                0x0
+ * </pre>
+ */
+#define RIU_AGCINBDPOW_20_PNOISESTAT_2_ADDR        (REG_RIU_BASE_ADDR + 0x0000067C)
+#define RIU_AGCINBDPOW_20_PNOISESTAT_2_OFFSET      0x0000067C
+#define RIU_AGCINBDPOW_20_PNOISESTAT_2_INDEX       0x0000019F
+#define RIU_AGCINBDPOW_20_PNOISESTAT_2_RESET       0x00000000
+
+static inline u32 riu_agcinbdpow_20_pnoisestat_2_get(struct cl_hw *cl_hw)
+{
+       return cl_reg_read(cl_hw, RIU_AGCINBDPOW_20_PNOISESTAT_2_ADDR);
+}
+
+#endif /*_REG_RIU_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.
________________________________


^ permalink raw reply related	[flat|nested] 262+ messages in thread

* [RFC v1 165/256] cl8k: add reg/reg_riu_rc.h
  2021-06-17 15:58 [RFC v1 000/256] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (163 preceding siblings ...)
  2021-06-17 16:00 ` [RFC v1 164/256] cl8k: add reg/reg_riu.h viktor.barna
@ 2021-06-17 16:00 ` viktor.barna
  2021-06-17 16:00 ` [RFC v1 166/256] cl8k: add rf_boot.c viktor.barna
                   ` (92 subsequent siblings)
  257 siblings, 0 replies; 262+ messages in thread
From: viktor.barna @ 2021-06-17 16:00 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Oleksandr Savchenko, Shay Bar, Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

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

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 .../net/wireless/celeno/cl8k/reg/reg_riu_rc.h | 115 ++++++++++++++++++
 1 file changed, 115 insertions(+)
 create mode 100644 drivers/net/wireless/celeno/cl8k/reg/reg_riu_rc.h

diff --git a/drivers/net/wireless/celeno/cl8k/reg/reg_riu_rc.h b/drivers/net/wireless/celeno/cl8k/reg/reg_riu_rc.h
new file mode 100644
index 000000000000..320a460df4f1
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/reg/reg_riu_rc.h
@@ -0,0 +1,115 @@
+/* SPDX-License-Identifier: MIT */
+/* Copyright(c) 2019-2021, Celeno Communications Ltd. */
+
+#ifndef CL_REG_RC_H
+#define CL_REG_RC_H
+
+#include <linux/types.h>
+#include "reg/reg_access.h"
+#include "hw.h"
+
+#define REG_RIU_RC_BASE_ADDR 0x00485000
+
+/*
+ * @brief SW_CTRL register definition
+ * This register provides write access to the radio SPI interface register description
+ * <pre>
+ *  Bits           Field Name   Reset Value
+ * -----   ------------------   -----------
+ *   31    START_DONE                0
+ *   30    MORE                      0
+ *   29    FASTWR_SPD                0
+ *   28    FASTWR_FORCE              0
+ *   27    FWR_HW_ENABLE             1
+ *   26    FWR_SW_ENABLE             1
+ *   25    FWR_ENABLE                1
+ *   24    RF_RESET_B                0
+ *   23:19 PRESCALER                 0x1
+ *   16    READNOTWRITE              0
+ *   14:08 ADDRESS                   0x0
+ *   07:00 DATA                      0x0
+ * </pre>
+ */
+#define RIU_RC_SW_CTRL_ADDR        (REG_RIU_RC_BASE_ADDR + 0x00000000)
+#define RIU_RC_SW_CTRL_OFFSET      0x00000000
+#define RIU_RC_SW_CTRL_INDEX       0x00000000
+#define RIU_RC_SW_CTRL_RESET       0x0E080000
+
+static inline void riu_rc_sw_ctrl_pack(struct cl_hw *cl_hw, u8 startdone, u8 more, u8 fastwrspd,
+                                      u8 fastwrforce, u8 fwrhwenable, u8 fwrswenable, u8 fwrenable,
+                                      u8 rfresetb, u8 prescaler, u8 readnotwrite, u8 address,
+                                      u8 data)
+{
+       ASSERT_ERR((((u32)more << 30) & ~((u32)0x40000000)) == 0);
+       ASSERT_ERR((((u32)fastwrspd << 29) & ~((u32)0x20000000)) == 0);
+       ASSERT_ERR((((u32)fastwrforce << 28) & ~((u32)0x10000000)) == 0);
+       ASSERT_ERR((((u32)fwrhwenable << 27) & ~((u32)0x08000000)) == 0);
+       ASSERT_ERR((((u32)fwrswenable << 26) & ~((u32)0x04000000)) == 0);
+       ASSERT_ERR((((u32)fwrenable << 25) & ~((u32)0x02000000)) == 0);
+       ASSERT_ERR((((u32)rfresetb << 24) & ~((u32)0x01000000)) == 0);
+       ASSERT_ERR((((u32)prescaler << 19) & ~((u32)0x00F80000)) == 0);
+       ASSERT_ERR((((u32)readnotwrite << 16) & ~((u32)0x00010000)) == 0);
+       ASSERT_ERR((((u32)address << 8) & ~((u32)0x00007F00)) == 0);
+
+       cl_reg_write(cl_hw, RIU_RC_SW_CTRL_ADDR, ((u32)startdone << 31) | ((u32)more << 30) |
+                    ((u32)fastwrspd << 29) | ((u32)fastwrforce << 28) | ((u32)fwrhwenable << 27) |
+                    ((u32)fwrswenable << 26) | ((u32)fwrenable << 25) | ((u32)rfresetb << 24) |
+                    ((u32)prescaler << 19) | ((u32)readnotwrite << 16) | ((u32)address << 8) |
+                    ((u32)data << 0));
+}
+
+static inline u8 riu_rc_sw_ctrl_start_done_getf(struct cl_hw *cl_hw)
+{
+       u32 local_val = cl_reg_read(cl_hw, RIU_RC_SW_CTRL_ADDR);
+
+       return ((local_val & ((u32)0x80000000)) >> 31);
+}
+
+static inline u8 riu_rc_sw_ctrl_data_getf(struct cl_hw *cl_hw)
+{
+       u32 local_val = cl_reg_read(cl_hw, RIU_RC_SW_CTRL_ADDR);
+
+       return ((local_val & ((u32)0x000000FF)) >> 0);
+}
+
+/*
+ * @brief RF_LNA_LUT register definition
+ * These registers provide control of the RF LNA assertion by decoding each possible value the AGC
+ * LNA gain setting, from minimum LNA gain to maximum LNA gain. register description
+ * <pre>
+ *  Bits           Field Name   Reset Value
+ * -----   ------------------   -----------
+ *   26:24 RFLNALUT6                 0x6
+ *   22:20 RFLNALUT5                 0x5
+ *   18:16 RFLNALUT4                 0x4
+ *   14:12 RFLNALUT3                 0x3
+ *   10:08 RFLNALUT2                 0x2
+ *   06:04 RFLNALUT1                 0x1
+ *   02:00 RFLNALUT0                 0x0
+ * </pre>
+ */
+
+/* Field definitions */
+#define RIU_RC_RF_LNA_LUT_RFLNALUT_6_MASK  ((u32)0x07000000)
+#define RIU_RC_RF_LNA_LUT_RFLNALUT_6_LSB   24
+#define RIU_RC_RF_LNA_LUT_RFLNALUT_6_WIDTH ((u32)0x00000003)
+#define RIU_RC_RF_LNA_LUT_RFLNALUT_5_MASK  ((u32)0x00700000)
+#define RIU_RC_RF_LNA_LUT_RFLNALUT_5_LSB   20
+#define RIU_RC_RF_LNA_LUT_RFLNALUT_5_WIDTH ((u32)0x00000003)
+#define RIU_RC_RF_LNA_LUT_RFLNALUT_4_MASK  ((u32)0x00070000)
+#define RIU_RC_RF_LNA_LUT_RFLNALUT_4_LSB   16
+#define RIU_RC_RF_LNA_LUT_RFLNALUT_4_WIDTH ((u32)0x00000003)
+#define RIU_RC_RF_LNA_LUT_RFLNALUT_3_MASK  ((u32)0x00007000)
+#define RIU_RC_RF_LNA_LUT_RFLNALUT_3_LSB   12
+#define RIU_RC_RF_LNA_LUT_RFLNALUT_3_WIDTH ((u32)0x00000003)
+#define RIU_RC_RF_LNA_LUT_RFLNALUT_2_MASK  ((u32)0x00000700)
+#define RIU_RC_RF_LNA_LUT_RFLNALUT_2_LSB   8
+#define RIU_RC_RF_LNA_LUT_RFLNALUT_2_WIDTH ((u32)0x00000003)
+#define RIU_RC_RF_LNA_LUT_RFLNALUT_1_MASK  ((u32)0x00000070)
+#define RIU_RC_RF_LNA_LUT_RFLNALUT_1_LSB   4
+#define RIU_RC_RF_LNA_LUT_RFLNALUT_1_WIDTH ((u32)0x00000003)
+#define RIU_RC_RF_LNA_LUT_RFLNALUT_0_MASK  ((u32)0x00000007)
+#define RIU_RC_RF_LNA_LUT_RFLNALUT_0_LSB   0
+#define RIU_RC_RF_LNA_LUT_RFLNALUT_0_WIDTH ((u32)0x00000003)
+
+#endif /* CL_REG_RC_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.
________________________________


^ permalink raw reply related	[flat|nested] 262+ messages in thread

* [RFC v1 166/256] cl8k: add rf_boot.c
  2021-06-17 15:58 [RFC v1 000/256] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (164 preceding siblings ...)
  2021-06-17 16:00 ` [RFC v1 165/256] cl8k: add reg/reg_riu_rc.h viktor.barna
@ 2021-06-17 16:00 ` viktor.barna
  2021-06-17 16:00 ` [RFC v1 167/256] cl8k: add rf_boot.h viktor.barna
                   ` (91 subsequent siblings)
  257 siblings, 0 replies; 262+ messages in thread
From: viktor.barna @ 2021-06-17 16:00 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Oleksandr Savchenko, Shay Bar, Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

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

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 drivers/net/wireless/celeno/cl8k/rf_boot.c | 354 +++++++++++++++++++++
 1 file changed, 354 insertions(+)
 create mode 100644 drivers/net/wireless/celeno/cl8k/rf_boot.c

diff --git a/drivers/net/wireless/celeno/cl8k/rf_boot.c b/drivers/net/wireless/celeno/cl8k/rf_boot.c
new file mode 100644
index 000000000000..4202c153661b
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/rf_boot.c
@@ -0,0 +1,354 @@
+// SPDX-License-Identifier: MIT
+/* Copyright(c) 2019-2021, Celeno Communications Ltd. */
+
+#include "rf_boot.h"
+#include "hw.h"
+#include "afe.h"
+#include "utils/file.h"
+#include "phy/phy.h"
+#include "reg/reg_access.h"
+#include "reg/reg_cmu.h"
+#include "reg/reg_modem_gcu.h"
+#include "reg/reg_ricu.h"
+#include "reg/reg_riu.h"
+#include "reg/reg_mac_hw.h"
+#include "reg/reg_lcu_phy.h"
+
+static void cl_clk_init(struct cl_chip *chip)
+{
+       cmu_clk_en_set(chip, CMU_MAC_ALL_CLK_EN);
+
+       cmu_phy_0_clk_en_set(chip, CMU_PHY_0_APB_CLK_EN_BIT | CMU_PHY_0_MAIN_CLK_EN_BIT);
+       cmu_phy_1_clk_en_set(chip, CMU_PHY_1_APB_CLK_EN_BIT | CMU_PHY_1_MAIN_CLK_EN_BIT);
+
+       cmu_phy_0_rst_ceva_0_global_rst_n_setf(chip, 0);
+       modem_gcu_ceva_ctrl_external_wait_setf(chip->cl_hw_tcv0, 1);
+       cmu_phy_0_rst_ceva_0_global_rst_n_setf(chip, 1);
+
+       cmu_phy_1_rst_ceva_1_global_rst_n_setf(chip, 0);
+       modem_gcu_ceva_ctrl_external_wait_setf(chip->cl_hw_tcv1, 1);
+       cmu_phy_1_rst_ceva_1_global_rst_n_setf(chip, 1);
+
+       cmu_phy_0_clk_en_ceva_0_clk_en_setf(chip, 1);
+       cmu_phy_1_clk_en_ceva_1_clk_en_setf(chip, 1);
+}
+
+static int cl_pll1_init(struct cl_chip *chip)
+{
+       int retry = 0;
+
+       /* Verify pll is locked */
+       while (!cmu_pll_1_stat_pll_lock_getf(chip) && (++retry < 10)) {
+               cl_dbg_chip_verbose(chip, "retry=%d\n", retry);
+               usleep_range(100, 200);
+       }
+
+       /* Pll is not locked - fatal error */
+       if (retry == 10) {
+               cl_dbg_chip_err(chip, "retry limit reached - pll is not locked !!!\n");
+               return -1;
+       }
+
+       return 0;
+}
+
+static int cl_cmu_init(struct cl_chip *chip)
+{
+       if (cl_pll1_init(chip))
+               return -1;
+
+       /* Set gl_mux_sel bit to work with pll1 instead of crystal */
+       cmu_control_gl_mux_sel_setf(chip, 1);
+
+       cmu_rst_n_ricurst_setf(chip, 1);
+
+       cmu_phy_0_rst_set(chip, CMU_PHY0_RST_EN);
+       cmu_phy_1_rst_set(chip, CMU_PHY1_RST_EN);
+       cmu_phy_0_rst_set(chip, 0x0);
+       cmu_phy_1_rst_set(chip, 0x0);
+       cmu_rst_n_ricurst_setf(chip, 1);
+       cmu_phy_0_rst_set(chip, CMU_PHY0_RST_EN);
+       cmu_phy_1_rst_set(chip, CMU_PHY1_RST_EN);
+
+       return 0;
+}
+
+static void cl_riu_clk_bw_init(struct cl_hw *cl_hw)
+{
+       u32 regval;
+
+       switch (cl_hw->conf->ce_channel_bandwidth) {
+       case CHNL_BW_20:
+               regval = 0x00000100;
+               break;
+       case CHNL_BW_40:
+               regval = 0x00000555;
+               break;
+       case CHNL_BW_160:
+               regval = 0x00000dff;
+               break;
+       case CHNL_BW_80:
+       default:
+               regval = 0x000009aa;
+               break;
+       }
+
+       /* Set RIU modules clock BW */
+       modem_gcu_riu_clk_bw_set(cl_hw, regval);
+}
+
+static int cl_load_riu_rsf_memory(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;
+       char *buf = NULL;
+       loff_t size, i = 0;
+       int ret = 0;
+
+       size = cl_file_open_and_read(chip, filename, &buf);
+
+       if (!buf)
+               return -ENOMEM;
+
+       if (size > RIU_RSF_FILE_SIZE) {
+               ret = -EFBIG;
+               goto out;
+       }
+
+       /* Enable re-sampling filter init. */
+       riu_rsf_control_rsf_init_en_setf(cl_hw_tcv0, 0x1);
+       if (cl_hw_tcv1)
+               riu_rsf_control_rsf_init_en_setf(cl_hw_tcv1, 0x1);
+
+       while (i < size) {
+               riu_rsf_init_set(cl_hw_tcv0, *(u32 *)&buf[i]);
+               if (cl_hw_tcv1)
+                       riu_rsf_init_set(cl_hw_tcv1, *(u32 *)&buf[i]);
+               i += 4;
+       }
+
+out:
+       kfree(buf);
+       return ret;
+}
+
+static int cl_load_riu_rsf_memory_recovery(struct cl_hw *cl_hw, const char *filename)
+{
+       struct cl_chip *chip = cl_hw->chip;
+       char *buf = NULL;
+       loff_t size, i = 0;
+       int ret = 0;
+
+       size = cl_file_open_and_read(chip, filename, &buf);
+
+       if (!buf)
+               return -ENOMEM;
+
+       if (size > RIU_RSF_FILE_SIZE) {
+               ret = -EFBIG;
+               goto out;
+       }
+
+       /* Enable re-sampling filter init. */
+       riu_rsf_control_rsf_init_en_setf(cl_hw, 0x1);
+
+       while (i < size) {
+               riu_rsf_init_set(cl_hw, *(u32 *)&buf[i]);
+               i += 4;
+       }
+
+out:
+       kfree(buf);
+       return ret;
+}
+
+static int cl_load_agc_data(struct cl_hw *cl_hw, const char *filename)
+{
+       struct cl_chip *chip = cl_hw->chip;
+       char *buf = NULL;
+       loff_t size, i = 0;
+
+       size = cl_file_open_and_read(chip, filename, &buf);
+
+       if (!buf)
+               return -ENOMEM;
+
+       /* Enable AGC FSM ram init state */
+       riu_agcfsm_ram_init_1_agc_fsm_ram_init_en_setf(cl_hw, 0x1);
+       /* Start writing the firmware from WPTR=0 */
+       riu_agcfsm_ram_init_1_agc_fsm_ram_init_wptr_setf(cl_hw, 0x0);
+       /* Allow WPTR register to be writable */
+       riu_agcfsm_ram_init_1_agc_fsm_ram_init_wptr_set_setf(cl_hw, 0x1);
+       /* Enable auto increment WPTR by 1 upon any write */
+       riu_agcfsm_ram_init_1_agc_fsm_ram_init_ainc_1_setf(cl_hw, 0x1);
+
+       while (i < size) {
+               riu_agcfsm_ram_init_2_set(cl_hw, *(u32 *)&buf[i]);
+               i += 4;
+       }
+
+       /* Disable AGC FSM ram init state */
+       riu_agcfsm_ram_init_1_agc_fsm_ram_init_en_setf(cl_hw, 0x0);
+
+       kfree(buf);
+
+       return 0;
+}
+
+static int cl_load_agc_fw(struct cl_hw *cl_hw, const char *filename)
+{
+       int ret = 0;
+
+       /* Switch AGC to programming mode */
+
+       /* Disable RIU Modules clocks (RC,LB,ModemB,FE,ADC,Regs,AGC,Radar) */
+       modem_gcu_riu_clk_set(cl_hw, 0);
+
+       /* Switch AGC MEM clock to 480MHz */
+       modem_gcu_riu_clk_bw_agc_mem_clk_bw_setf(cl_hw, 3);
+
+       /* Enable RIU Modules clocks (RC,LB,ModemB,FE,ADC,Regs,AGC,Radar) */
+       modem_gcu_riu_clk_set(cl_hw, 0xFFFFFFFF);
+
+       /* Assert AGC FSM reset */
+       riu_rwnxagccntl_agcfsmreset_setf(cl_hw, 1);
+
+       /* Load AGC RAM data */
+       ret = cl_load_agc_data(cl_hw, filename);
+       if (ret)
+               goto out;
+
+       /* Switch AGC back to operational mode */
+
+       /* Disable RIU Modules clocks (RC, LB, ModemB, FE, ADC, Regs, AGC, Radar) */
+       modem_gcu_riu_clk_set(cl_hw, 0);
+       /* Switch AGC MEM clock back to 80M */
+       modem_gcu_riu_clk_bw_agc_mem_clk_bw_setf(cl_hw, 1);
+       /* Enable RIU Modules clocks (RC, LB, ModemB, FE, ADC, Regs, AGC, Radar) */
+       modem_gcu_riu_clk_set(cl_hw, 0xFFFFFFFF);
+
+       /* Release AGC FSM reset */
+       riu_rwnxagccntl_agcfsmreset_setf(cl_hw, 0);
+
+out:
+       return ret;
+}
+
+int cl_rf_boot(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;
+
+       /* Call only once per chip after ASIC reset - configure both phys */
+       ret = cl_cmu_init(chip);
+       if (ret != 0)
+               goto out;
+
+       cl_clk_init(chip);
+       cmu_phase_sel_set(chip, (CMU_GP_CLK_PHASE_SEL_BIT |
+                                CMU_DAC_CDB_CLK_PHASE_SEL_BIT |
+                                CMU_DAC_CLK_PHASE_SEL_BIT) &
+                                ~(CMU_ADC_CDB_CLK_PHASE_SEL_BIT |
+                                CMU_ADC_CLK_PHASE_SEL_BIT));
+
+       mac_hw_mac_cntrl_1_active_clk_gating_setf(cl_hw_tcv0, 1); /* Disable MPIF clock */
+       mac_hw_state_cntrl_next_state_setf(cl_hw_tcv0, 2);        /* Move to doze */
+
+       mac_hw_mac_cntrl_1_active_clk_gating_setf(cl_hw_tcv1, 1); /* Disable MPIF clock */
+       mac_hw_state_cntrl_next_state_setf(cl_hw_tcv1, 2);        /* Move to doze */
+
+       /* Enable all PHY modules */
+       cl_phy_enable(cl_hw_tcv0);
+       cl_phy_enable(cl_hw_tcv1);
+
+       mac_hw_doze_cntrl_2_wake_up_sw_setf(cl_hw_tcv0, 1); /* Exit from doze */
+       mac_hw_state_cntrl_next_state_setf(cl_hw_tcv0, 0);  /* Move to idle */
+
+       mac_hw_doze_cntrl_2_wake_up_sw_setf(cl_hw_tcv1, 1); /* Exit from doze */
+       mac_hw_state_cntrl_next_state_setf(cl_hw_tcv1, 0);  /* Move to idle */
+
+       cl_riu_clk_bw_init(cl_hw_tcv0);
+       cl_riu_clk_bw_init(cl_hw_tcv1);
+
+       /* Load RIU re-sampling filter memory with coefficients */
+       ret = cl_load_riu_rsf_memory(chip, "riu_rsf.bin");
+       if (ret != 0) {
+               pr_err("cl_load_riu_rsf_memory failed with error code %d.\n", ret);
+               goto out;
+       }
+
+       /* Load AGC FW */
+       ret = cl_load_agc_fw(cl_hw_tcv0, "agcram.bin");
+       if (ret) {
+               pr_err("cl_load_agc_fw failed for tcv0 with error code %d.\n", ret);
+               goto out;
+       }
+
+       ret = cl_load_agc_fw(cl_hw_tcv1, "agcram.bin");
+       if (ret) {
+               pr_err("cl_load_agc_fw failed for tcv1 with error code %d.\n", ret);
+               goto out;
+       }
+
+       /* AFE Registers configuration */
+       ret = cl_afe_cfg(chip);
+
+out:
+       return ret;
+}
+
+static void restore_ela_state(struct cl_hw *cl_hw)
+{
+       struct cl_recovery_db *recovery_db = &cl_hw->recovery_db;
+
+       /* Restore eLA state after MAC-HW reset */
+       if (recovery_db->ela_en) {
+               mac_hw_debug_port_sel_a_set(cl_hw, recovery_db->ela_sel_a);
+               mac_hw_debug_port_sel_b_set(cl_hw, recovery_db->ela_sel_b);
+               mac_hw_debug_port_sel_c_set(cl_hw, recovery_db->ela_sel_c);
+       }
+
+       mac_hw_debug_port_en_set(cl_hw, recovery_db->ela_en);
+}
+
+int cl_rf_boot_recovery(struct cl_hw *cl_hw)
+{
+       int ret = 0;
+
+       mac_hw_mac_cntrl_1_active_clk_gating_setf(cl_hw, 1); /* Disable MPIF clock */
+       mac_hw_state_cntrl_next_state_setf(cl_hw, 2);        /* Move to doze */
+
+       /* Enable all PHY modules */
+       cl_phy_enable(cl_hw);
+
+       /* Restart LCU recording */
+       if (cl_hw_is_tcv0(cl_hw))
+               lcu_phy_lcu_ch_0_stop_set(cl_hw, 0);
+       else
+               lcu_phy_lcu_ch_1_stop_set(cl_hw, 0);
+
+       restore_ela_state(cl_hw);
+
+       mac_hw_doze_cntrl_2_wake_up_sw_setf(cl_hw, 1); /* Exit from doze */
+       mac_hw_state_cntrl_next_state_setf(cl_hw, 0);  /* Move to idle */
+
+       cl_riu_clk_bw_init(cl_hw);
+
+       /* Load RIU re-sampling filter memory with coefficients */
+       ret = cl_load_riu_rsf_memory_recovery(cl_hw, "riu_rsf.bin");
+       if (ret != 0) {
+               pr_err("cl_load_riu_rsf_memory failed with error code %d.\n", ret);
+               goto out;
+       }
+
+       /* Load AGC FW */
+       ret = cl_load_agc_fw(cl_hw, "agcram.bin");
+       if (ret) {
+               pr_err("cl_load_agc_fw failed for with error code %d.\n", ret);
+               goto out;
+       }
+
+out:
+       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.
________________________________


^ permalink raw reply related	[flat|nested] 262+ messages in thread

* [RFC v1 167/256] cl8k: add rf_boot.h
  2021-06-17 15:58 [RFC v1 000/256] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (165 preceding siblings ...)
  2021-06-17 16:00 ` [RFC v1 166/256] cl8k: add rf_boot.c viktor.barna
@ 2021-06-17 16:00 ` viktor.barna
  2021-06-17 16:00 ` [RFC v1 168/256] cl8k: add rsrc_mgmt.c viktor.barna
                   ` (90 subsequent siblings)
  257 siblings, 0 replies; 262+ messages in thread
From: viktor.barna @ 2021-06-17 16:00 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Oleksandr Savchenko, Shay Bar, Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

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

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 drivers/net/wireless/celeno/cl8k/rf_boot.h | 12 ++++++++++++
 1 file changed, 12 insertions(+)
 create mode 100644 drivers/net/wireless/celeno/cl8k/rf_boot.h

diff --git a/drivers/net/wireless/celeno/cl8k/rf_boot.h b/drivers/net/wireless/celeno/cl8k/rf_boot.h
new file mode 100644
index 000000000000..c246ed41cccd
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/rf_boot.h
@@ -0,0 +1,12 @@
+/* SPDX-License-Identifier: MIT */
+/* Copyright(c) 2019-2021, Celeno Communications Ltd. */
+
+#ifndef CL_RF_BOOT_H
+#define CL_RF_BOOT_H
+
+#include "chip.h"
+
+int cl_rf_boot(struct cl_chip *chip);
+int cl_rf_boot_recovery(struct cl_hw *cl_hw);
+
+#endif /* CL_RF_BOOT_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.
________________________________


^ permalink raw reply related	[flat|nested] 262+ messages in thread

* [RFC v1 168/256] cl8k: add rsrc_mgmt.c
  2021-06-17 15:58 [RFC v1 000/256] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (166 preceding siblings ...)
  2021-06-17 16:00 ` [RFC v1 167/256] cl8k: add rf_boot.h viktor.barna
@ 2021-06-17 16:00 ` viktor.barna
  2021-06-17 16:00 ` [RFC v1 169/256] cl8k: add rsrc_mgmt.h viktor.barna
                   ` (89 subsequent siblings)
  257 siblings, 0 replies; 262+ messages in thread
From: viktor.barna @ 2021-06-17 16:00 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Oleksandr Savchenko, Shay Bar, Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

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

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 drivers/net/wireless/celeno/cl8k/rsrc_mgmt.c | 279 +++++++++++++++++++
 1 file changed, 279 insertions(+)
 create mode 100644 drivers/net/wireless/celeno/cl8k/rsrc_mgmt.c

diff --git a/drivers/net/wireless/celeno/cl8k/rsrc_mgmt.c b/drivers/net/wireless/celeno/cl8k/rsrc_mgmt.c
new file mode 100644
index 000000000000..9ba8407a1306
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/rsrc_mgmt.c
@@ -0,0 +1,279 @@
+// SPDX-License-Identifier: MIT
+/* Copyright(c) 2019-2021, Celeno Communications Ltd. */
+#include "fw/msg_tx.h"
+#include "rsrc_mgmt.h"
+#include "rx/rx_amsdu.h"
+#include "prot_mode.h"
+#include "env_det.h"
+
+#ifndef ETYPE2STR
+#define ETYPE2STR(_e) case _e: return # _e
+#endif
+
+static const char *subtype2str(enum mm_rsrc_mgmt_subtype subtype)
+{
+       switch (subtype) {
+       ETYPE2STR(MM_RSRC_MGMT_API_SANITY);
+       ETYPE2STR(MM_RSRC_MGMT_TRAFFIC_START);
+       ETYPE2STR(MM_RSRC_MGMT_TRAFFIC_STOP);
+       ETYPE2STR(MM_RSRC_MGMT_RATES_UPDATE);
+       ETYPE2STR(MM_RSRC_MGMT_CECLI_HINT);
+
+       ETYPE2STR(MM_RSRC_MGMT_ACTION_HINT);
+       ETYPE2STR(MM_RSRC_MGMT_ENV_CHANGE);
+       ETYPE2STR(MM_RSRC_MGMT_STATS);
+       ETYPE2STR(MM_RSRC_MGMT_CONFIG_QUERY);
+       ETYPE2STR(MM_RSRC_MGMT_NOTIF_POLICY_SET);
+       ETYPE2STR(MM_RSRC_MGMT_MAX);
+       default: return "UNKNOWN_SUBTYPE";
+       }
+}
+
+static const char *action2str(enum mm_rsrc_mgmt_action_hint action)
+{
+       switch (action) {
+       ETYPE2STR(MM_RSRC_MGMT_ACTION_ENABLE);
+       ETYPE2STR(MM_RSRC_MGMT_ACTION_DISABLE);
+       ETYPE2STR(MM_RSRC_MGMT_ACTION_RESTORE_DEFAULT);
+       ETYPE2STR(MM_RSRC_MGMT_ACTION_SET);
+       ETYPE2STR(MM_RSRC_MGMT_ACTION_GET);
+       ETYPE2STR(MM_RSRC_MGMT_ACTION_MAX);
+       default: return "UNKNOWN_ACTION";
+       }
+}
+
+static const char *control2str(enum mm_rsrc_mgmt_control_of control_of)
+{
+       switch (control_of) {
+       ETYPE2STR(MM_RSRC_MGMT_OF_TX_AMSDU);
+       ETYPE2STR(MM_RSRC_MGMT_OF_RX_AMSDU);
+       ETYPE2STR(MM_RSRC_MGMT_OF_PROT_MODE);
+       ETYPE2STR(MM_RSRC_MGMT_OF_CCA);
+       default: return "UNKNOWN_CONTROL_OF";
+       }
+}
+
+static inline bool is_in_low_range(s8 th, s8 v)
+{
+       if (th != -1)
+               return th >= v;
+       return true;
+}
+
+static inline bool is_in_high_range(s8 th, s8 v)
+{
+       if (th != -1)
+               return th <= v;
+       return true;
+}
+
+/*
+ * DRV <- FW: notification_policy.
+ *
+ * Notification filters:
+ * 1. on/off (enabled/disabled);
+ * 2. active sta count (lower and upper);
+ * 3. TODO: frequency (once per 100msec etc);
+ * 4. TODO: amount of failures in feedback;
+ */
+static bool must_notify(struct cl_hw *cl_hw, u8 event_type, u8 active_sta_cnt)
+{
+       struct mm_rsrc_mgmt_notif_policy *p = &cl_hw->rsrc_mgmt_db.notif_policies[event_type];
+
+       return p->enabled &&
+               is_in_low_range(p->active_sta.low_th, active_sta_cnt) &&
+               is_in_high_range(p->active_sta.high_th, active_sta_cnt);
+}
+
+/*
+ * Public API
+ */
+void cl_rsrc_mgmt_init(struct cl_hw *cl_hw)
+{
+       BUILD_BUG_ON(TRAFFIC_LEVEL_MAX >
+                    BITS_PER_TYPE(typeof_member(struct mm_rsrc_mgmt_notif_policy,
+                                                level_mask)));
+       BUILD_BUG_ON(TRAFFIC_DIRECTION_MAX >
+                    BITS_PER_TYPE(typeof_member(struct mm_rsrc_mgmt_notif_policy,
+                                                direction_mask)));
+
+       cl_dbg_trace(cl_hw, "RSRC MGMT Init: sizeof(req):%zu, sizeof(ind):%zu, sizeof(cfm):%zu\n",
+                    sizeof(struct mm_rsrc_mgmt_req),
+                    sizeof(struct mm_rsrc_mgmt_ind),
+                    sizeof(struct mm_rsrc_mgmt_cfm));
+}
+
+/*
+ * Direction: DRV -> FW: Requests/Notifications
+ */
+void cl_rsrc_mgmt_traffic_start(struct cl_hw *cl_hw, enum cl_traffic_level level,
+                               enum cl_traffic_direction direction)
+{
+       u8 event_type = MM_RSRC_MGMT_TRAFFIC_START;
+       u8 active_sta_cnt = cl_hw->traffic_db.num_active_sta_dir[direction][level];
+
+       if (!must_notify(cl_hw, event_type, active_sta_cnt))
+               return;
+
+       cl_msg_tx_rsrc_mgmt_traffic_event(cl_hw, event_type, level, direction,
+                                         active_sta_cnt);
+}
+
+void cl_rsrc_mgmt_traffic_stop(struct cl_hw *cl_hw, enum cl_traffic_level level,
+                              enum cl_traffic_direction direction)
+{
+       u8 event_type = MM_RSRC_MGMT_TRAFFIC_STOP;
+       u8 active_sta_cnt = cl_hw->traffic_db.num_active_sta_dir[direction][level];
+
+       if (!must_notify(cl_hw, event_type, active_sta_cnt))
+               return;
+
+       cl_msg_tx_rsrc_mgmt_traffic_event(cl_hw, event_type, level, direction,
+                                         active_sta_cnt);
+}
+
+void cl_rsrc_mgmt_rates_update(struct cl_hw *cl_hw, struct cl_sta *cl_sta)
+{
+       u8 event_type = MM_RSRC_MGMT_RATES_UPDATE;
+       u8 active_sta_cnt = cl_traffic_num_active_sta(cl_hw);
+
+       if (!must_notify(cl_hw, event_type, active_sta_cnt))
+               return;
+
+       cl_msg_tx_rsrc_mgmt_rates_event(cl_hw, event_type, cl_sta);
+}
+
+void cl_rsrc_mgmt_process_cfm(struct cl_hw *cl_hw, struct mm_rsrc_mgmt_cfm *cfm)
+{
+       cl_dbg_trace(cl_hw, "CFM: subtype:%s(%u), status:%d\n",
+                    subtype2str(cfm->subtype), cfm->subtype, cfm->status);
+}
+
+/*
+ * DRV <- FW: Indications processings
+ */
+static void process_env_change(struct cl_hw *cl_hw, enum cl_env_type type)
+{
+       cl_env_det_set_type(cl_hw, type);
+}
+
+static void process_notif_policy(struct cl_hw *cl_hw, u8 subtype,
+                                struct mm_rsrc_mgmt_notif_policy *np)
+{
+       struct cl_rsrc_mgmt_db *db = &cl_hw->rsrc_mgmt_db;
+
+       cl_dbg_trace(cl_hw, "[%s(%u)] enabled:%u, sta.low_th:%d, sta.high_th:%d\n",
+                    subtype2str(subtype), subtype, np->enabled,
+                    np->active_sta.low_th, np->active_sta.high_th);
+
+       if (subtype < ARRAY_SIZE(db->notif_policies))
+               db->notif_policies[subtype] = *np;
+       else
+               cl_dbg_err(cl_hw, "Invalid subtype index:%s(%u)\n",
+                          subtype2str(subtype), subtype);
+}
+
+static void process_action_hint(struct cl_hw *cl_hw, uint16_t target, uint8_t action)
+{
+       int rc = 0;
+
+       cl_dbg_info(cl_hw, "Processing hint: target - %s(%u), action - %s(%u)\n",
+                   control2str(target), target, action2str(action), action);
+
+       switch (target) {
+       case MM_RSRC_MGMT_OF_TX_AMSDU:
+               switch (action) {
+               case MM_RSRC_MGMT_ACTION_ENABLE:
+                       cl_hw->txamsdu_en = 1;
+                       break;
+               case MM_RSRC_MGMT_ACTION_DISABLE:
+                       cl_hw->txamsdu_en = 0;
+                       break;
+               case MM_RSRC_MGMT_ACTION_RESTORE_DEFAULT:
+                       cl_hw->txamsdu_en = cl_hw->conf->ce_txamsdu_en;
+                       break;
+               default:
+                       rc = -EOPNOTSUPP;
+               };
+               break;
+       case MM_RSRC_MGMT_OF_RX_AMSDU:
+               switch (action) {
+               case MM_RSRC_MGMT_ACTION_ENABLE:
+                       cl_rx_amsdu_hw_en(cl_hw->hw, true);
+                       break;
+               case MM_RSRC_MGMT_ACTION_DISABLE:
+                       cl_rx_amsdu_hw_en(cl_hw->hw, false);
+                       break;
+               case MM_RSRC_MGMT_ACTION_RESTORE_DEFAULT:
+                       cl_rx_amsdu_hw_en(cl_hw->hw, cl_hw->conf->ce_rxamsdu_en);
+                       break;
+               default:
+                       rc = -EOPNOTSUPP;
+               };
+               break;
+       case MM_RSRC_MGMT_OF_PROT_MODE:
+               switch (action) {
+               case MM_RSRC_MGMT_ACTION_ENABLE:
+                       cl_prot_mode_enable(cl_hw);
+                       break;
+               case MM_RSRC_MGMT_ACTION_DISABLE:
+                       cl_prot_mode_disable(cl_hw);
+                       break;
+               case MM_RSRC_MGMT_ACTION_RESTORE_DEFAULT:
+                       cl_prot_mode_restore_default(cl_hw);
+                       break;
+               default:
+                       rc = -EOPNOTSUPP;
+               };
+               break;
+       case MM_RSRC_MGMT_OF_CCA:
+               switch (action) {
+               case MM_RSRC_MGMT_ACTION_DISABLE:
+                       cl_msg_tx_config_cca(cl_hw, false);
+                       break;
+               case MM_RSRC_MGMT_ACTION_ENABLE:
+               case MM_RSRC_MGMT_ACTION_RESTORE_DEFAULT:
+                       cl_msg_tx_config_cca(cl_hw, true);
+                       break;
+               default:
+                       rc = -EOPNOTSUPP;
+               };
+               break;
+       default:
+               rc = -EOPNOTSUPP;
+               break;
+       };
+
+       if (rc) {
+               cl_dbg_err(cl_hw, "Hint process failure, rc:%d [%s(%u):%s(%u)]\n",
+                          rc, control2str(target), target, action2str(action),
+                          action);
+       }
+}
+
+void cl_rsrc_mgmt_process_ind(struct cl_hw *cl_hw, struct mm_rsrc_mgmt_ind *ind)
+{
+       switch (ind->subtype) {
+       case MM_RSRC_MGMT_ACTION_HINT:
+               process_action_hint(cl_hw,
+                                   le16_to_cpu(ind->u.action_hint.target),
+                                   ind->u.action_hint.action);
+               break;
+       case MM_RSRC_MGMT_ENV_CHANGE:
+               process_env_change(cl_hw, ind->u.env_event.state);
+               break;
+       case MM_RSRC_MGMT_NOTIF_POLICY_SET:
+               process_notif_policy(cl_hw,
+                                    ind->u.notif_policy_set.subtype,
+                                    &ind->u.notif_policy_set.settings);
+               break;
+       case MM_RSRC_MGMT_STATS:
+       case MM_RSRC_MGMT_CONFIG_QUERY:
+       case MM_RSRC_MGMT_MAX:
+       default:
+               cl_dbg_err(cl_hw, "Invalid subtype %s(%u)\n",
+                          subtype2str(ind->subtype), ind->subtype);
+               break;
+       }
+}
+
--
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.
________________________________


^ permalink raw reply related	[flat|nested] 262+ messages in thread

* [RFC v1 169/256] cl8k: add rsrc_mgmt.h
  2021-06-17 15:58 [RFC v1 000/256] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (167 preceding siblings ...)
  2021-06-17 16:00 ` [RFC v1 168/256] cl8k: add rsrc_mgmt.c viktor.barna
@ 2021-06-17 16:00 ` viktor.barna
  2021-06-17 16:00 ` [RFC v1 170/256] cl8k: add rssi.c viktor.barna
                   ` (88 subsequent siblings)
  257 siblings, 0 replies; 262+ messages in thread
From: viktor.barna @ 2021-06-17 16:00 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Oleksandr Savchenko, Shay Bar, Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

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

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 drivers/net/wireless/celeno/cl8k/rsrc_mgmt.h | 29 ++++++++++++++++++++
 1 file changed, 29 insertions(+)
 create mode 100644 drivers/net/wireless/celeno/cl8k/rsrc_mgmt.h

diff --git a/drivers/net/wireless/celeno/cl8k/rsrc_mgmt.h b/drivers/net/wireless/celeno/cl8k/rsrc_mgmt.h
new file mode 100644
index 000000000000..7fde3c777c85
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/rsrc_mgmt.h
@@ -0,0 +1,29 @@
+/* SPDX-License-Identifier: MIT */
+/* Copyright(c) 2019-2021, Celeno Communications Ltd. */
+#ifndef CL_RSRC_MGMT_H
+#define CL_RSRC_MGMT_H
+
+#include "traffic.h"
+
+/**
+ * DOC: Resource management
+ *
+ * Responsible for control over dynamic features of the driver from the
+ * firmware, regarding the collected information about traffic intensity,
+ * environment state etc.
+ */
+
+struct cl_rsrc_mgmt_db {
+       struct mm_rsrc_mgmt_notif_policy notif_policies[MM_RSRC_MGMT_MAX];
+};
+
+void cl_rsrc_mgmt_init(struct cl_hw *cl_hw);
+void cl_rsrc_mgmt_traffic_start(struct cl_hw *cl_hw, enum cl_traffic_level level,
+                               enum cl_traffic_direction direction);
+void cl_rsrc_mgmt_traffic_stop(struct cl_hw *cl_hw, enum cl_traffic_level level,
+                              enum cl_traffic_direction direction);
+void cl_rsrc_mgmt_rates_update(struct cl_hw *cl_hw, struct cl_sta *cl_sta);
+void cl_rsrc_mgmt_process_ind(struct cl_hw *cl_hw, struct mm_rsrc_mgmt_ind *ind);
+void cl_rsrc_mgmt_process_cfm(struct cl_hw *cl_hw, struct mm_rsrc_mgmt_cfm *cfm);
+
+#endif /* CL_RSRC_MGMT_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.
________________________________


^ permalink raw reply related	[flat|nested] 262+ messages in thread

* [RFC v1 170/256] cl8k: add rssi.c
  2021-06-17 15:58 [RFC v1 000/256] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (168 preceding siblings ...)
  2021-06-17 16:00 ` [RFC v1 169/256] cl8k: add rsrc_mgmt.h viktor.barna
@ 2021-06-17 16:00 ` viktor.barna
  2021-06-17 16:00 ` [RFC v1 171/256] cl8k: add rssi.h viktor.barna
                   ` (87 subsequent siblings)
  257 siblings, 0 replies; 262+ messages in thread
From: viktor.barna @ 2021-06-17 16:00 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Oleksandr Savchenko, Shay Bar, Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

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

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 drivers/net/wireless/celeno/cl8k/rssi.c | 320 ++++++++++++++++++++++++
 1 file changed, 320 insertions(+)
 create mode 100644 drivers/net/wireless/celeno/cl8k/rssi.c

diff --git a/drivers/net/wireless/celeno/cl8k/rssi.c b/drivers/net/wireless/celeno/cl8k/rssi.c
new file mode 100644
index 000000000000..48221007f424
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/rssi.c
@@ -0,0 +1,320 @@
+// SPDX-License-Identifier: MIT
+/* Copyright(c) 2019-2021, Celeno Communications Ltd. */
+
+#include "rssi.h"
+#include "vns.h"
+#include "stats.h"
+#include "sta.h"
+#include "motion_sense.h"
+#include "mac_addr.h"
+#include "chip.h"
+
+/*
+ * cl_rssi_assoc_###()
+ * -------------------
+ * RSSI values of association packets (request in AP mode and respone in STA mode)
+ * are not added to rssi pool sample, because at this stage station is not added
+ * to driver database.
+ * RSSI of association is important for WRS in order to select its initial rate.
+ * The goal of this code is to save MAC address and RSSI values of all association
+ * packets, and after station fully connects, search for the correct RSSI and add
+ * it to the rssi pool sample.
+ */
+struct assoc_queue_elem {
+       struct list_head list;
+       u8 addr[ETH_ALEN];
+       s8 rssi[MAX_ANTENNAS];
+       unsigned long timestamp;
+};
+
+#define CL_RSSI_LIFETIME_MS 5000
+
+static void cl_rssi_add_to_wrs(struct cl_hw *cl_hw, struct cl_sta *cl_sta, s8 rssi[MAX_ANTENNAS])
+{
+       struct cl_wrs_rssi *wrs_rssi = &cl_sta->wrs_rssi;
+       int i = 0;
+
+       for (i = 0; i < cl_hw->num_antennas; i++)
+               wrs_rssi->sum[i] += rssi[i];
+
+       wrs_rssi->cnt++;
+}
+
+void cl_rssi_assoc_init(struct cl_hw *cl_hw)
+{
+       INIT_LIST_HEAD(&cl_hw->assoc_queue.list);
+       spin_lock_init(&cl_hw->assoc_queue.lock);
+}
+
+void cl_rssi_assoc_exit(struct cl_hw *cl_hw)
+{
+       /* Delete all remaining elements in list */
+       spin_lock(&cl_hw->assoc_queue.lock);
+
+       if (!list_empty(&cl_hw->assoc_queue.list)) {
+               struct assoc_queue_elem *elem = NULL;
+               struct assoc_queue_elem *tmp = NULL;
+
+               list_for_each_entry_safe(elem, tmp, &cl_hw->assoc_queue.list, list) {
+                       list_del(&elem->list);
+                       kfree(elem);
+               }
+       }
+
+       spin_unlock(&cl_hw->assoc_queue.lock);
+}
+
+void cl_rssi_assoc_handle(struct cl_hw *cl_hw, u8 *mac_addr, struct hw_rxhdr *rxhdr)
+{
+       /* Allocate new element and add to list */
+       struct assoc_queue_elem *elem = kmalloc(sizeof(*elem), GFP_ATOMIC);
+
+       if (elem) {
+               INIT_LIST_HEAD(&elem->list);
+               cl_mac_addr_copy(elem->addr, mac_addr);
+
+               elem->rssi[0] = (s8)rxhdr->rssi1;
+               elem->rssi[1] = (s8)rxhdr->rssi2;
+               elem->rssi[2] = (s8)rxhdr->rssi3;
+               elem->rssi[3] = (s8)rxhdr->rssi4;
+               elem->rssi[4] = (s8)rxhdr->rssi5;
+               elem->rssi[5] = (s8)rxhdr->rssi6;
+
+               elem->timestamp = jiffies;
+
+               spin_lock(&cl_hw->assoc_queue.lock);
+               list_add(&elem->list, &cl_hw->assoc_queue.list);
+               spin_unlock(&cl_hw->assoc_queue.lock);
+       }
+}
+
+void cl_rssi_assoc_find(struct cl_hw *cl_hw, struct cl_sta *cl_sta, u8 num_sta)
+{
+       /* Search for rssi of association according to mac address */
+       spin_lock(&cl_hw->assoc_queue.lock);
+
+       if (!list_empty(&cl_hw->assoc_queue.list)) {
+               unsigned long lifetime = 0;
+               struct assoc_queue_elem *elem = NULL;
+               struct assoc_queue_elem *tmp = NULL;
+
+               list_for_each_entry_safe(elem, tmp, &cl_hw->assoc_queue.list, list) {
+                       lifetime = jiffies_to_msecs(CL_TIME_DIFF(jiffies, elem->timestamp));
+
+                       /* Check lifetime of rssi before using it */
+                       if (lifetime > CL_RSSI_LIFETIME_MS) {
+                               /* Delete element from list */
+                               list_del(&elem->list);
+                               kfree(elem);
+                               continue;
+                       }
+
+                       if (ether_addr_equal(elem->addr, cl_sta->addr)) {
+                               struct hw_rxhdr rxhdr;
+                               s8 equivalent_rssi = cl_rssi_calc_equivalent(cl_hw, elem->rssi);
+
+                               rxhdr.rssi1 = elem->rssi[0];
+                               rxhdr.rssi2 = elem->rssi[1];
+                               rxhdr.rssi3 = elem->rssi[2];
+                               rxhdr.rssi4 = elem->rssi[3];
+                               rxhdr.rssi5 = elem->rssi[4];
+                               rxhdr.rssi6 = elem->rssi[5];
+
+                               cl_rssi_rx_handler(cl_hw, cl_sta, &rxhdr, equivalent_rssi);
+
+                               /* Delete element from list */
+                               list_del(&elem->list);
+                               kfree(elem);
+                       }
+               }
+       }
+
+       spin_unlock(&cl_hw->assoc_queue.lock);
+}
+
+void cl_rssi_sort_descending(s8 rssi[MAX_ANTENNAS], u8 num_ant)
+{
+       int i, j;
+
+       for (i = 0; i < num_ant - 1; i++)
+               for (j = 0; j < num_ant - i - 1; j++)
+                       if (rssi[j] < rssi[j + 1])
+                               swap(rssi[j], rssi[j + 1]);
+}
+
+static s8 cl_rssi_equivalent_2_phys(s8 rssi_max, s8 rssi_min)
+{
+       s8 rssi_diff = rssi_min - rssi_max;
+
+       if (rssi_diff > (-2))
+               return (rssi_max + 3);
+       else if (rssi_diff > (-5))
+               return (rssi_max + 2);
+       else if (rssi_diff > (-9))
+               return (rssi_max + 1);
+       else
+               return rssi_max;
+}
+
+s8 cl_rssi_calc_equivalent(struct cl_hw *cl_hw, s8 rssi[MAX_ANTENNAS])
+{
+       s8 rssi_tmp[MAX_ANTENNAS] = {0};
+       u8 rx_ant = cl_hw->num_antennas;
+       int i, j;
+
+       /* Copy to rssi_tmp */
+       memcpy(rssi_tmp, rssi, rx_ant);
+
+       /* Sort the rssi's in desceding order */
+       cl_rssi_sort_descending(rssi_tmp, rx_ant);
+
+       /*
+        * 1) Calc equivalent rssi between the two lowest values.
+        * 2) Sort again
+        * 3) Repeat steps 1 and 2 according to number of antennas.
+        */
+       for (i = 0; i < rx_ant - 1; i++) {
+               rssi_tmp[rx_ant - i - 2] = cl_rssi_equivalent_2_phys(rssi_tmp[rx_ant - i - 2],
+                                                                    rssi_tmp[rx_ant - i - 1]);
+
+               for (j = rx_ant - i - 2; j > 0; j--) {
+                       if (rssi_tmp[j] > rssi_tmp[j - 1])
+                               swap(rssi_tmp[j], rssi_tmp[j - 1]);
+                       else
+                               break;
+               }
+       }
+
+       return rssi_tmp[0];
+}
+
+s8 cl_rssi_get_strongest(struct cl_hw *cl_hw, s8 rssi[MAX_ANTENNAS])
+{
+       int i;
+       s8 strongest_rssi = S8_MIN;
+
+       for (i = 0; i < cl_hw->num_antennas; i++) {
+               if (rssi[i] > strongest_rssi)
+                       strongest_rssi = rssi[i];
+       }
+
+       return strongest_rssi;
+}
+
+static void cl_update_sta_rssi(struct cl_hw *cl_hw, struct cl_sta *cl_sta,
+                              s8 rssi[MAX_ANTENNAS], s8 equivalent_rssi)
+{
+       /* Last RSSI */
+       memcpy(cl_sta->last_rssi, rssi, cl_hw->num_antennas);
+
+       if (cl_sta->manual_alpha_rssi)
+               return;
+
+       /* Alpha RSSI - use alpha filter (87.5% current + 12.5% new) */
+       if (cl_sta->alpha_rssi)
+               cl_sta->alpha_rssi =
+                       ((cl_sta->alpha_rssi << 3) - cl_sta->alpha_rssi + equivalent_rssi) >> 3;
+       else
+               cl_sta->alpha_rssi = equivalent_rssi;
+}
+
+void cl_rssi_block_ack_handler(struct cl_hw *cl_hw, struct cl_sta *cl_sta,
+                              struct cl_agg_tx_report *agg_report)
+{
+       /* Handle RSSI of block-ack's */
+       union cl_rate_ctrl_info *rate_ctrl_info =
+               (union cl_rate_ctrl_info *)&agg_report->rate_cntrl_info;
+       u8 bw = (u8)rate_ctrl_info->field.bw;
+       s8 rssi[MAX_ANTENNAS];
+       s8 equivalent_rssi;
+       int i;
+       s8 bw_factor = 0;
+
+       /*
+        * For TCV1 fill in the rxhdr rssi "holes" so that values will start from rssi1.
+        * The implementation below takes into account elastic mimo, and maximum number
+        * of antennas for each TCV.
+        */
+       if (cl_chip_is_8ant(cl_hw->chip)) {
+               rssi[0] = (s8)agg_report->rssi1;
+               rssi[1] = (s8)agg_report->rssi2;
+               rssi[2] = (s8)agg_report->rssi3;
+               rssi[3] = (s8)agg_report->rssi4;
+               rssi[4] = (s8)agg_report->rssi5;
+               rssi[5] = (s8)agg_report->rssi6;
+       } else if (cl_chip_is_6ant(cl_hw->chip)) {
+               if (cl_hw_is_tcv0(cl_hw)) {
+                       rssi[0] = (s8)agg_report->rssi1;
+                       rssi[1] = (s8)agg_report->rssi2;
+                       rssi[2] = (s8)agg_report->rssi3;
+                       rssi[3] = (s8)agg_report->rssi4;
+                       rssi[4] = (s8)agg_report->rssi5;
+               } else {
+                       /* Chain 1 is not used */
+                       rssi[0] = (s8)agg_report->rssi2;
+                       rssi[1] = (s8)agg_report->rssi3;
+                       rssi[2] = (s8)agg_report->rssi4;
+                       rssi[3] = (s8)agg_report->rssi5;
+                       rssi[4] = (s8)agg_report->rssi6;
+               }
+       } else {
+               if (cl_hw_is_tcv0(cl_hw)) {
+                       rssi[0] = (s8)agg_report->rssi1;
+                       rssi[1] = (s8)agg_report->rssi2;
+                       rssi[2] = (s8)agg_report->rssi3;
+                       rssi[3] = (s8)agg_report->rssi4;
+               } else {
+                       /* Chains 0 & 1 are not used */
+                       rssi[0] = (s8)agg_report->rssi3;
+                       rssi[1] = (s8)agg_report->rssi4;
+                       rssi[2] = (s8)agg_report->rssi5;
+                       rssi[3] = (s8)agg_report->rssi6;
+               }
+       }
+
+       /*
+        * RSSI adjustment according to BW
+        * The BA is transmitted in the BW of the aggregation it acknowledges
+        */
+       if (bw == CHNL_BW_160)
+               bw_factor = 9;
+       else if (bw == CHNL_BW_80)
+               bw_factor = 6;
+       else if (bw == CHNL_BW_40)
+               bw_factor = 3;
+
+       for (i = 0; i < cl_hw->num_antennas; i++)
+               rssi[i] += bw_factor;
+
+       equivalent_rssi = cl_rssi_calc_equivalent(cl_hw, rssi);
+
+       /* Handle RSSI after BW adjustment */
+       cl_rssi_add_to_wrs(cl_hw, cl_sta, rssi);
+       cl_stats_update_rx_rssi(cl_hw, cl_sta, rssi);
+       cl_vns_handle_rssi(cl_hw, cl_sta, rssi);
+       cl_update_sta_rssi(cl_hw, cl_sta, rssi, equivalent_rssi);
+       cl_motion_sense_rssi_ba(cl_hw, cl_sta, rssi);
+}
+
+void cl_rssi_rx_handler(struct cl_hw *cl_hw, struct cl_sta *cl_sta,
+                       struct hw_rxhdr *rxhdr, s8 equivalent_rssi)
+{
+       /* Called after BW adjustment */
+       s8 rssi[MAX_ANTENNAS] = RX_HDR_RSSI(rxhdr);
+
+       cl_rssi_add_to_wrs(cl_hw, cl_sta, rssi);
+       cl_stats_update_rx_rssi(cl_hw, cl_sta, rssi);
+       cl_vns_handle_rssi(cl_hw, cl_sta, rssi);
+       cl_update_sta_rssi(cl_hw, cl_sta, rssi, equivalent_rssi);
+}
+
+void cl_rssi_bw_adjust(struct cl_hw *cl_hw, struct hw_rxhdr *rxhdr, s8 bw_factor)
+{
+       rxhdr->rssi1 += bw_factor;
+       rxhdr->rssi2 += bw_factor;
+       rxhdr->rssi3 += bw_factor;
+       rxhdr->rssi4 += bw_factor;
+       rxhdr->rssi5 += bw_factor;
+       rxhdr->rssi6 += bw_factor;
+}
+
--
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.
________________________________


^ permalink raw reply related	[flat|nested] 262+ messages in thread

* [RFC v1 171/256] cl8k: add rssi.h
  2021-06-17 15:58 [RFC v1 000/256] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (169 preceding siblings ...)
  2021-06-17 16:00 ` [RFC v1 170/256] cl8k: add rssi.c viktor.barna
@ 2021-06-17 16:00 ` viktor.barna
  2021-06-17 16:00 ` [RFC v1 172/256] cl8k: add rx/rx.c viktor.barna
                   ` (86 subsequent siblings)
  257 siblings, 0 replies; 262+ messages in thread
From: viktor.barna @ 2021-06-17 16:00 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Oleksandr Savchenko, Shay Bar, Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

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

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 drivers/net/wireless/celeno/cl8k/rssi.h | 28 +++++++++++++++++++++++++
 1 file changed, 28 insertions(+)
 create mode 100644 drivers/net/wireless/celeno/cl8k/rssi.h

diff --git a/drivers/net/wireless/celeno/cl8k/rssi.h b/drivers/net/wireless/celeno/cl8k/rssi.h
new file mode 100644
index 000000000000..26ea2b0693a0
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/rssi.h
@@ -0,0 +1,28 @@
+/* SPDX-License-Identifier: MIT */
+/* Copyright(c) 2019-2021, Celeno Communications Ltd. */
+
+#ifndef CL_RSSI_H
+#define CL_RSSI_H
+
+#include "rx/rx.h"
+#include "hw.h"
+#include "tx/agg_tx_report.h"
+
+#define RX_HDR_RSSI(rxhdr) \
+       {(rxhdr)->rssi1, (rxhdr)->rssi2, (rxhdr)->rssi3, \
+        (rxhdr)->rssi4, (rxhdr)->rssi5, (rxhdr)->rssi6}
+
+void cl_rssi_assoc_init(struct cl_hw *cl_hw);
+void cl_rssi_assoc_exit(struct cl_hw *cl_hw);
+void cl_rssi_assoc_handle(struct cl_hw *cl_hw, u8 *mac_addr, struct hw_rxhdr *rxhdr);
+void cl_rssi_assoc_find(struct cl_hw *cl_hw, struct cl_sta *cl_sta, u8 num_sta);
+void cl_rssi_sort_descending(s8 rssi[MAX_ANTENNAS], u8 num_ant);
+s8 cl_rssi_calc_equivalent(struct cl_hw *cl_hw, s8 rssi[MAX_ANTENNAS]);
+s8 cl_rssi_get_strongest(struct cl_hw *cl_hw, s8 rssi[MAX_ANTENNAS]);
+void cl_rssi_block_ack_handler(struct cl_hw *cl_hw, struct cl_sta *cl_sta,
+                              struct cl_agg_tx_report *agg_report);
+void cl_rssi_rx_handler(struct cl_hw *cl_hw, struct cl_sta *cl_sta,
+                       struct hw_rxhdr *rxhdr, s8 equivalent_rssi);
+void cl_rssi_bw_adjust(struct cl_hw *cl_hw, struct hw_rxhdr *rxhdr, s8 bw_factor);
+
+#endif /* CL_RSSI_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.
________________________________


^ permalink raw reply related	[flat|nested] 262+ messages in thread

* [RFC v1 172/256] cl8k: add rx/rx.c
  2021-06-17 15:58 [RFC v1 000/256] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (170 preceding siblings ...)
  2021-06-17 16:00 ` [RFC v1 171/256] cl8k: add rssi.h viktor.barna
@ 2021-06-17 16:00 ` viktor.barna
  2021-06-17 16:01 ` [RFC v1 173/256] cl8k: add rx/rx.h viktor.barna
                   ` (85 subsequent siblings)
  257 siblings, 0 replies; 262+ messages in thread
From: viktor.barna @ 2021-06-17 16:00 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Oleksandr Savchenko, Shay Bar, Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

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

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 drivers/net/wireless/celeno/cl8k/rx/rx.c | 1108 ++++++++++++++++++++++
 1 file changed, 1108 insertions(+)
 create mode 100644 drivers/net/wireless/celeno/cl8k/rx/rx.c

diff --git a/drivers/net/wireless/celeno/cl8k/rx/rx.c b/drivers/net/wireless/celeno/cl8k/rx/rx.c
new file mode 100644
index 000000000000..d55038ae2e85
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/rx/rx.c
@@ -0,0 +1,1108 @@
+// SPDX-License-Identifier: MIT
+/* Copyright(c) 2019-2021, Celeno Communications Ltd. */
+
+#include "tx/tx.h"
+#include "rx/rx.h"
+#include "rx/rx_amsdu.h"
+#include "stats.h"
+#include "rate_ctrl.h"
+#include "rssi.h"
+#include "band.h"
+#include "utils/utils.h"
+#include "vns.h"
+#include "dfs/dfs.h"
+#include "wrs/wrs_api.h"
+#include "twt.h"
+#include "recovery.h"
+#include "fw/fw_dbg.h"
+#include "def.h"
+#include "rx/rx_reorder.h"
+#include "ops.h"
+#include "chip.h"
+#include "channel.h"
+#ifdef CONFIG_CL_PCIE
+#include "bus/pci/rx_pci.h"
+#endif
+#ifdef TRACE_SUPPORT
+#include "trace.h"
+#endif
+
+/* Must correspond to FW definition of MM_SEC_DEFAULT_KEY_COUNT */
+#define MM_SEC_DEFAULT_KEY_COUNT 64
+
+#define VHT_MCS_MASK 0x0F
+#define VHT_MCS_OFT  0
+
+/* Number of entries in HW legacy rate conversion table */
+#define LEGACY_RATE_MAX 16
+
+static const s8 legacy_rates_lut[LEGACY_RATE_MAX] = {
+       0,      /* 0: 1 Mbps   */
+       1,      /* 1: 2 Mbps   */
+       2,      /* 2: 5.5 Mbps */
+       3,      /* 3: 11 Mbps  */
+       -1,     /* 4: Invalid  */
+       -1,     /* 5: Invalid  */
+       -1,     /* 6: Invalid  */
+       -1,     /* 7: Invalid  */
+       10,     /* 8: 48 Mbps  */
+       8,      /* 9: 24 Mbps  */
+       6,      /* 10: 12 Mbps */
+       4,      /* 11: 6 Mbps  */
+       11,     /* 12: 54 Mbps */
+       9,      /* 13: 36 Mbps */
+       7,      /* 14: 18 Mbps */
+       5       /* 15: 9 Mbps  */
+};
+
+/*
+ * rx_skb_cnt is an atomic counter that tracks the total number of skbs in
+ * the entire host.
+ * The counter is incremented when skb is allocated, and freed when the skb
+ * is freed (=destructor function called).
+ * Therefore the counter is global (and not part of cl_hw or cl_chip).
+ *
+ * rx_skb_max is the configured to:
+ * max(chip0->conf->ci_rx_skb_max, chip1->conf->ci_rx_skb_max)
+ */
+static atomic_t rx_skb_cnt = ATOMIC_INIT(0);
+static u32 rx_skb_max;
+
+static void cl_rx_skb_destructor(struct sk_buff *skb)
+{
+       atomic_dec(&rx_skb_cnt);
+}
+
+static DEFINE_PER_CPU(struct tasklet_struct, rx_remote_tasklet_mac[TCV_TOTAL]);
+
+static void cl_rx_remote_cpu_mac(struct cl_hw *cl_hw)
+{
+       int cpu = cl_hw->conf->ci_rx_remote_cpu_mac;
+       struct tasklet_struct *t = &per_cpu(rx_remote_tasklet_mac[cl_hw->idx], cpu);
+
+       if (!test_bit(TASKLET_STATE_SCHED, &t->state))
+               smp_call_function_single(cpu, cl_rx_remote_tasklet_sched, t, 0);
+}
+
+static int cl_rx_check_err(struct cl_hw *cl_hw, struct sk_buff *skb, struct hw_rxhdr *rxhdr)
+{
+       u32 status;
+
+       if (rxhdr->frm_successful_rx)
+               return 0;
+
+       /* The status field is in offset of 14 u32's */
+       status = *((u32 *)rxhdr + 14);
+
+       if (rxhdr->fcs_err) {
+               cl_hw->radio_stats[CL_RADIO_FCS_ERROR]++;
+               cl_dbg_err(cl_hw, "fcs_err (status 0x%x)\n", status);
+       }
+
+       if (rxhdr->rx_fifo_oflow) {
+               cl_hw->radio_stats[CL_RADIO_RX_FIFO_OVERFLOW]++;
+               cl_dbg_err(cl_hw, "rx_fifo_oflow (status 0x%x)\n", status);
+       }
+
+       if (rxhdr->undef_err) {
+               cl_hw->radio_stats[CL_RADIO_UNDEFINED_ERROR]++;
+               cl_dbg_err(cl_hw, "undef_err (status 0x%x)\n", status);
+       }
+
+       if (rxhdr->phy_err) {
+               cl_hw->radio_stats[CL_RADIO_PHY_ERROR]++;
+               cl_dbg_err(cl_hw, "phy_err (status 0x%x)\n", status);
+       }
+
+       if (rxhdr->addr_mismatch) {
+               cl_hw->radio_stats[CL_RADIO_ADDRESS_MISMATCH]++;
+               cl_dbg_err(cl_hw, "addr_mismatch (status 0x%x)\n", status);
+       }
+
+       cl_hw->rx_info.pkt_drop_not_success++;
+       kfree_skb(skb);
+
+       return -1;
+}
+
+static u8 chnl_bw_to_rate_info_bw[CHNL_BW_MAX] = {
+       [CHNL_BW_20] = RATE_INFO_BW_20,
+       [CHNL_BW_40] = RATE_INFO_BW_40,
+       [CHNL_BW_80] = RATE_INFO_BW_80,
+       [CHNL_BW_160] = RATE_INFO_BW_160,
+};
+
+static u8 chnl_bw_factor[CHNL_BW_MAX] = {
+       [CHNL_BW_20] = 0,
+       [CHNL_BW_40] = 3,
+       [CHNL_BW_80] = 6,
+       [CHNL_BW_160] = 9,
+};
+
+static int cl_rx_fill_status(struct cl_hw *cl_hw, struct cl_sta *cl_sta, struct sk_buff *skb,
+                            struct hw_rxhdr *rxhdr, u8 *encrypt_len)
+{
+       s8 rssi[MAX_ANTENNAS] = RX_HDR_RSSI(rxhdr);
+       struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
+       struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);
+       u8 tid = ieee80211_get_tid(hdr);
+       u8 factor;
+
+       memset(status, 0, sizeof(struct ieee80211_rx_status));
+
+       status->mactime = ((u64)le32_to_cpu((rxhdr->tsf_hi)) << 32) | le32_to_cpu(rxhdr->tsf_lo);
+       status->flag |= RX_FLAG_MACTIME_END;
+
+       if (cl_sta && cl_sta->tid_agg_rx[tid])
+               status->flag |= RX_FLAG_DUP_VALIDATED;
+
+       status->antenna = rxhdr->antenna_set;
+       status->band = cl_band_from_fw_idx(rxhdr->phy_band);
+
+       if (rxhdr->format_mod >= FORMATMOD_HE_SU) {
+               status->encoding = RX_ENC_HE;
+               status->rate_idx = (rxhdr->mcs & VHT_MCS_MASK) >> VHT_MCS_OFT;
+               status->nss = rxhdr->n_sts + 1;
+
+               /* he_gi expectes to get values according to enum nl80211_he_gi */
+               status->he_gi = convert_gi_format_wrs_to_fw(WRS_MODE_HE, rxhdr->gi_type);
+       } else if (rxhdr->format_mod == FORMATMOD_VHT) {
+               status->encoding = RX_ENC_VHT;
+               status->rate_idx = (rxhdr->mcs & VHT_MCS_MASK) >> VHT_MCS_OFT;
+               status->nss = rxhdr->n_sts + 1;
+
+               if (rxhdr->gi_type)
+                       status->enc_flags |= RX_ENC_FLAG_SHORT_GI;
+       } else if (rxhdr->format_mod == FORMATMOD_HT_GF) {
+               status->encoding = RX_ENC_HT;
+               status->enc_flags |= RX_ENC_FLAG_HT_GF;
+               status->rate_idx = rxhdr->mcs;
+
+               if (rxhdr->gi_type)
+                       status->enc_flags |= RX_ENC_FLAG_SHORT_GI;
+
+       } else if (rxhdr->format_mod == FORMATMOD_HT_MF) {
+               status->encoding = RX_ENC_HT;
+               status->rate_idx = rxhdr->mcs;
+
+               if (rxhdr->gi_type)
+                       status->enc_flags |= RX_ENC_FLAG_SHORT_GI;
+       } else {
+               if (legacy_rates_lut[rxhdr->leg_rate] != -1)
+                       status->rate_idx = legacy_rates_lut[rxhdr->leg_rate];
+               if (status->band != NL80211_BAND_2GHZ)
+                       status->rate_idx -= RATE_CTRL_OFFSET_OFDM;
+               if (!rxhdr->pre_type)
+                       status->enc_flags |= RX_ENC_FLAG_SHORTPRE;
+       }
+
+       if (rxhdr->aggregation) {
+               status->flag |= RX_FLAG_AMPDU_DETAILS;
+               status->ampdu_reference = rxhdr->ampdu_cnt;
+       }
+
+       /* Set bw field */
+       status->bw = chnl_bw_to_rate_info_bw[rxhdr->ch_bw];
+
+       factor = chnl_bw_factor[rxhdr->ch_bw];
+       cl_rssi_bw_adjust(cl_hw, rxhdr, factor);
+
+       /*
+        * Todo check if when a frame is received on 40MHz or more bandwidth,
+        * we need to take the center1_freq instead of the prim20_freq
+        */
+       status->freq = le16_to_cpu(Q2_TO_FREQ(rxhdr->phy_prim20_freq));
+
+       status->signal = cl_rssi_calc_equivalent(cl_hw, rssi);
+
+       switch (rxhdr->decr_status) {
+       case CL_RX_HDR_DECR_UNENC:
+               if (ieee80211_has_protected(hdr->frame_control)) {
+                       cl_dbg_warn(cl_hw, "Protected frame unencrypted\n");
+                       cl_hw->rx_info.pkt_drop_unencrypted++;
+                       return -1;
+               }
+               break;
+       case CL_RX_HDR_DECR_ICVFAIL:
+       case CL_RX_HDR_DECR_AMSDUDISCARD:
+       case CL_RX_HDR_DECR_NULLKEY:
+       case CL_RX_HDR_DECR_CCMPFAIL:
+               cl_dbg_warn(cl_hw, "Decryption failed (%u)\n", rxhdr->decr_status);
+               cl_hw->rx_info.pkt_drop_decrypt_fail++;
+               *encrypt_len = 0;
+               return -1;
+       case CL_RX_HDR_DECR_WEPSUCCESS:
+       case CL_RX_HDR_DECR_TKIPSUCCESS:
+               *encrypt_len = IEEE80211_WEP_ICV_LEN;
+               status->flag |= (RX_FLAG_DECRYPTED | RX_FLAG_ICV_STRIPPED);
+               break;
+       case CL_RX_HDR_DECR_CCMPSUCCESS:
+               *encrypt_len = IEEE80211_CCMP_HDR_LEN;
+               status->flag |= (RX_FLAG_DECRYPTED | RX_FLAG_MIC_STRIPPED);
+               status->flag |= RX_FLAG_PN_VALIDATED;
+               break;
+       }
+
+       return 0;
+}
+
+static void cl_rx_action_twt_setup(struct cl_hw *cl_hw, struct cl_ieee80211_mgmt *mgmt,
+                                  int len, struct cl_sta *cl_sta)
+{
+       u32 min_size = 0;
+       u8 negotiation_type =
+               mgmt->u.action.u.twt_individual_setup.twt_elem.control.fields.negotiation_type;
+
+       /* Individual TWT */
+       if ((negotiation_type & 0x2) == 0) {
+               /* Verify min size */
+               min_size = IEEE80211_MIN_ACTION_SIZE  + 4 +
+                       sizeof(mgmt->u.action.u.twt_individual_setup.twt_elem);
+
+               if (len < min_size) {
+                       cl_dbg_err(cl_hw, "TWT: Individual setup action frame length error\n");
+                       return;
+               }
+
+               /* Regular individual TWT */
+               if (negotiation_type == 0)
+                       cl_twt_handle_individual_setup_request(cl_hw, cl_sta, mgmt);
+       } else { /* Broadcast TWT */
+               /* Verify min size */
+               min_size = IEEE80211_MIN_ACTION_SIZE  + 4 +
+                       sizeof(mgmt->u.action.u.twt_broadcast_setup.twt_elem);
+
+               if (len < min_size) {
+                       cl_dbg_err(cl_hw, "TWT: Broadcast setup action frame length error\n");
+                       return;
+               }
+       }
+}
+
+static void cl_rx_action_twt_teardown(struct cl_hw *cl_hw, struct cl_ieee80211_mgmt *mgmt,
+                                     int len, struct cl_sta *cl_sta)
+{
+       u8 negotiation_type;
+
+       if (len < IEEE80211_MIN_ACTION_SIZE + 2) {
+               cl_dbg_err(cl_hw, "Invalid length of TWT teardown action frame\n");
+               return;
+       }
+
+       negotiation_type = mgmt->u.action.u.twt_individual_teardown.negotiation_type;
+
+       if (negotiation_type <= 1)
+               cl_twt_handle_individual_teardown_request(cl_hw, cl_sta, mgmt);
+}
+
+static void cl_rx_action_frame_handler(struct cl_hw *cl_hw, struct cl_ieee80211_mgmt *mgmt,
+                                      int len, struct cl_sta *cl_sta)
+{
+       /* Verify action code is present */
+       if (len < IEEE80211_MIN_ACTION_SIZE + 1)
+               return;
+
+       switch (mgmt->u.action.category) {
+       case WLAN_CATEGORY_UNPROTECTED_S1G:
+               if (!cl_twt_is_enabled(cl_hw))
+                       break;
+
+               if (cl_sta->cl_vif->vif->type != NL80211_IFTYPE_AP)
+                       break;
+
+               switch (mgmt->u.action.u.twt_individual_setup.action_code) {
+               case WLAN_UNPROT_S1G_ACTION_TWT_SETUP:
+                       cl_rx_action_twt_setup(cl_hw, mgmt, len, cl_sta);
+                       break;
+               case WLAN_UNPROT_S1G_ACTION_TWT_TEARDOWN:
+                       cl_rx_action_twt_teardown(cl_hw, mgmt, len, cl_sta);
+                       break;
+               default:
+                       break;
+               }
+               break;
+       case WLAN_CATEGORY_WNM:
+               /* TODO: Here may be bss_color_check_action */
+               break;
+       default:
+               break;
+       }
+}
+
+static void cl_rx_mgmt_check(struct cl_hw *cl_hw, struct sk_buff *skb,
+                            struct cl_sta *cl_sta, struct hw_rxhdr *rxhdr)
+{
+       struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)skb->data;
+       __le16 fc = mgmt->frame_control;
+
+       if (!ieee80211_is_mgmt(fc))
+               return;
+
+       if (cl_sta) {
+               if (ieee80211_is_action(fc))
+                       cl_rx_action_frame_handler(cl_hw, (struct cl_ieee80211_mgmt *)mgmt,
+                                                  skb->len, cl_sta);
+       } else {
+               s8 rssi[MAX_ANTENNAS] = RX_HDR_RSSI(rxhdr);
+
+               cl_vns_mgmt_handler(cl_hw, mgmt->sa, rssi);
+
+               if (ieee80211_is_assoc_req(fc) || ieee80211_is_assoc_resp(fc))
+                       cl_rssi_assoc_handle(cl_hw, mgmt->sa, rxhdr);
+       }
+}
+
+static void cl_rx_data_check(struct cl_hw *cl_hw, struct sk_buff *skb,
+                            struct cl_sta *cl_sta, u32 packet_len, struct hw_rxhdr *rxhdr)
+{
+       if (cl_sta) {
+               cl_traffic_rx_handler(cl_hw, cl_sta, packet_len);
+
+               if (!rxhdr->aggregation || (rxhdr->aggregation && rxhdr->mpdu_cnt == 0))
+                       cl_motion_sense_rssi_data(cl_hw, cl_sta, rxhdr);
+       }
+}
+
+static bool cl_rx_skb_done(struct cl_hw *cl_hw, struct sk_buff *skb,
+                          struct cl_sta *cl_sta, struct hw_rxhdr *rxhdr)
+{
+       struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);
+       struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
+       __le16 fc = hdr->frame_control;
+       struct cl_vif *cl_vif = NULL;
+
+       /* Update trigger base statistics */
+       cl_fw_dbg_trigger_based_update(cl_hw, rxhdr, hdr);
+
+       if (cl_sta) {
+               cl_vif = cl_sta->cl_vif;
+               skb->dev = cl_vif->dev;
+
+               cl_stats_update_rx_rate(cl_hw, cl_sta, rxhdr);
+
+               if (!rxhdr->aggregation || (rxhdr->aggregation && rxhdr->mpdu_cnt == 0))
+                       cl_rssi_rx_handler(cl_hw, cl_sta, rxhdr, status->signal);
+       } else {
+               cl_vif = cl_vif_get_by_mac(cl_hw, hdr->addr3);
+               skb->dev = cl_vif ? cl_vif->dev : NULL;
+
+               if (cl_hw->chip->conf->ce_production_mode)
+                       cl_stats_update_rx_rate_production(cl_hw, rxhdr);
+       }
+
+       /* DATA */
+       if (ieee80211_is_data(fc)) {
+               cl_rx_data_check(cl_hw, skb, cl_sta, skb->len, rxhdr);
+               goto out;
+       }
+
+       /* MGMT/CTL */
+       if (cl_sta)
+               cl_motion_sense_rssi_mgmt_ctl(cl_hw, cl_sta, rxhdr);
+
+       /* MGMT */
+       cl_rx_mgmt_check(cl_hw, skb, cl_sta, rxhdr);
+
+out:
+       if (rx_skb_max &&
+           atomic_read(&rx_skb_cnt) >= rx_skb_max) {
+               cl_hw->rx_info.pkt_drop_host_limit++;
+               kfree_skb(skb);
+               return false;
+       }
+
+       return true;
+}
+
+static void cl_rx_pass_to_mac(struct cl_hw *cl_hw,
+                             struct ieee80211_sta *sta,
+                             struct sk_buff_head *frames)
+{
+       if (cl_hw->conf->ci_rx_remote_cpu_mac == -1) {
+               struct sk_buff *skb = NULL;
+
+               while ((skb = __skb_dequeue(frames)))
+                       ieee80211_rx_napi(cl_hw->hw, sta, skb, NULL);
+       } else {
+               struct sk_buff_head *rx_remote_queue_mac = &cl_hw->rx_remote_queue_mac;
+
+               spin_lock(&rx_remote_queue_mac->lock);
+               skb_queue_splice_tail_init(frames, rx_remote_queue_mac);
+               spin_unlock(&rx_remote_queue_mac->lock);
+
+               cl_rx_remote_cpu_mac(cl_hw);
+       }
+}
+
+static void cl_rx_amsdu_done_reorder(struct cl_hw *cl_hw, struct cl_sta *cl_sta,
+                                    struct sk_buff_head *frames)
+{
+       struct sk_buff *skb = NULL;
+       struct sk_buff_head reorder_buf;
+
+       /* Init the reorder buffer */
+       __skb_queue_head_init(&reorder_buf);
+
+       while ((skb = __skb_dequeue(frames)))
+               cl_rx_reorder_ampdu(cl_hw, cl_sta, skb, &reorder_buf);
+
+       if (!skb_queue_empty(&reorder_buf))
+               cl_rx_pass_to_mac(cl_hw, &cl_sta->stainfo->sta, &reorder_buf);
+}
+
+static void cl_rx_amsdu_done(struct cl_hw *cl_hw, struct cl_amsdu_rx_state *amsdu_rx_state)
+{
+       struct sk_buff_head *frames = &amsdu_rx_state->frames;
+       struct sk_buff *skb = __skb_peek(frames);
+       struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);
+       struct cl_sta *cl_sta;
+       struct cl_vif *cl_vif;
+       struct hw_rxhdr *rxhdr = amsdu_rx_state->rxhdr;
+       u32 packet_len = amsdu_rx_state->packet_len;
+       struct ieee80211_sta *sta;
+
+       /* START - cl_sta protected block */
+       cl_sta_lock(cl_hw);
+       cl_sta = cl_sta_get(cl_hw, amsdu_rx_state->sta_idx);
+
+       if (!cl_sta) {
+               cl_sta_unlock(cl_hw);
+               cl_hw->rx_info.pkt_drop_sta_null += amsdu_rx_state->msdu_cnt;
+               __skb_queue_purge(frames);
+               return;
+       }
+
+       sta = &cl_sta->stainfo->sta;
+       cl_vif = cl_sta->cl_vif;
+       skb->dev = cl_vif->dev;
+
+       cl_rx_data_check(cl_hw, skb, cl_sta, packet_len, rxhdr);
+       cl_stats_update_rx_rate(cl_hw, cl_sta, rxhdr);
+
+       if (!rxhdr->aggregation || (rxhdr->aggregation && rxhdr->mpdu_cnt == 0))
+               cl_rssi_rx_handler(cl_hw, cl_sta, rxhdr, status->signal);
+
+       cl_sta_unlock(cl_hw);
+       /* END - cl_sta protected block */
+
+       if (rx_skb_max &&
+           (atomic_read(&rx_skb_cnt) + amsdu_rx_state->msdu_cnt) >= rx_skb_max) {
+               cl_hw->rx_info.pkt_drop_host_limit += amsdu_rx_state->msdu_cnt;
+               __skb_queue_purge(frames);
+               return;
+       }
+
+       if (cl_sta->tid_agg_rx[amsdu_rx_state->tid])
+               cl_rx_amsdu_done_reorder(cl_hw, cl_sta, frames);
+       else
+               cl_rx_pass_to_mac(cl_hw, sta, frames);
+}
+
+static void cl_rx_invalid_tailroom(struct cl_hw *cl_hw, struct sk_buff *skb, u32 len)
+{
+       cl_dbg_err(cl_hw, "Invalid RX header length - tailroom=%d, len=%u\n",
+                  skb_tailroom(skb), len);
+       cl_hw->rx_info.pkt_drop_rxhdr_len_error++;
+       kfree_skb(skb);
+}
+
+static void cl_rx_invalid_pattern(struct cl_hw *cl_hw, struct sk_buff *skb, u32 pattern)
+{
+       cl_dbg_err(cl_hw, "WRONG PATTERN - 0x%x\n", pattern);
+       cl_hw->rx_info.pkt_drop_wrong_pattern++;
+       kfree_skb(skb);
+}
+
+static int cl_rx_get_sta_idx(struct cl_hw *cl_hw, struct hw_rxhdr *rxhdr)
+{
+       int sta_idx = rxhdr->key_sram_index - MM_SEC_DEFAULT_KEY_COUNT;
+
+       if (sta_idx >= 0 && sta_idx < CL_MAX_NUM_STA)
+               return sta_idx;
+
+       cl_dbg_err(cl_hw, "invalid sta_idx %d, key_sram_index=%d\n",
+                  sta_idx, rxhdr->key_sram_index);
+
+       return -1;
+}
+
+static void cl_rx_handle_first_amsdu(struct cl_hw *cl_hw, struct sk_buff *skb,
+                                    struct cl_amsdu_rx_state *amsdu_rx_state,
+                                    struct hw_rxhdr *rxhdr, u8 sta_idx, u8 tid, u8 encrypt_len)
+{
+       /*
+        * First MSDU recived frame:
+        * ------------------------------------------
+        * || WLAN_HDR || MSDU HDR || MSDU PAYLOAD ||
+        * ------------------------------------------
+        */
+       cl_rx_amsdu_stats(cl_hw, rxhdr->msdu_cnt);
+
+       if (rxhdr->corrupted_amsdu) {
+               cl_rx_amsdu_first_corrupted(cl_hw, skb, rxhdr);
+       } else {
+               cl_rx_amsdu_first(cl_hw, skb, rxhdr, sta_idx, tid, encrypt_len);
+
+               /* If there are more MSDU's, hold on with the update
+                * to the upper layer until A-MSDU is complete
+                */
+               if (amsdu_rx_state->msdu_remaining_cnt == 0)
+                       cl_rx_amsdu_done(cl_hw, amsdu_rx_state);
+       }
+}
+
+static void cl_rx_handle_sub_amsdu(struct cl_hw *cl_hw, struct sk_buff *skb,
+                                  struct cl_amsdu_rx_state *amsdu_rx_state)
+{
+       /* Update the remaining MSDU counter */
+       amsdu_rx_state->msdu_remaining_cnt--;
+
+       /* Free MSDU with error */
+       if (amsdu_rx_state->amsdu_error) {
+               cl_rx_amsdu_sub_error(cl_hw, skb);
+               return;
+       }
+
+       /* Add the sub-MSDU to the existing ones */
+       if (!cl_rx_amsdu_sub(cl_hw, skb))
+               return;
+
+       /* This is the last MSDU, A-MSDU is complete, push to upper layer */
+       if (amsdu_rx_state->msdu_remaining_cnt == 0)
+               cl_rx_amsdu_done(cl_hw, amsdu_rx_state);
+}
+
+static void cl_rx_handle_ps(struct cl_hw *cl_hw, struct cl_sta *cl_sta, struct sk_buff *skb)
+{
+       struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)(skb->data);
+       struct ieee80211_sta *sta = &cl_sta->stainfo->sta;
+       bool is_ps;
+       __le16 fc = hdr->frame_control;
+
+       if (ieee80211_is_pspoll(fc) ||
+           ieee80211_has_morefrags(fc) ||
+           !(ieee80211_is_mgmt(fc) ||
+             ieee80211_is_data(fc)))
+               return;
+
+       is_ps = ieee80211_has_pm(hdr->frame_control);
+
+       cl_sta_ps_notify(cl_hw, cl_sta, is_ps);
+       ieee80211_sta_ps_transition(sta, is_ps);
+}
+
+static void cl_rx_handle_skb(struct cl_hw *cl_hw, struct sk_buff *skb)
+{
+       u8 encrypt_len = 0;
+       u8 tid = 0;
+       u32 mpdu_offset = 0;
+       u32 len = 0;
+       int sta_idx = -1;
+       bool is_amsdu = false;
+       bool skb_done = false;
+       struct cl_sta *cl_sta = NULL;
+       struct ieee80211_sta *sta = NULL;
+       struct hw_rxhdr *rxhdr = NULL;
+       struct cl_tid_ampdu_rx *tid_agg_rx = NULL;
+       struct cl_amsdu_rx_state *amsdu_rx_state = &cl_hw->amsdu_rx_state;
+       s8 remote_cpu_mac = cl_hw->conf->ci_rx_remote_cpu_mac;
+
+       if (amsdu_rx_state->msdu_remaining_cnt > 0) {
+               cl_rx_handle_sub_amsdu(cl_hw, skb, amsdu_rx_state);
+               return;
+       }
+
+       rxhdr = (struct hw_rxhdr *)skb->data;
+       mpdu_offset = sizeof(struct hw_rxhdr);
+
+       if (rxhdr->rx_padding_done)
+               mpdu_offset += CL_PADDING_IN_BYTES;
+
+       /* Pull the HW RX header */
+       skb_reserve(skb, mpdu_offset);
+
+       /*
+        * Sanity check - the embedded layer is responsible to validate the pattern correctness.
+        * If pattern is invalid then it is likely that the embedded layer did some thing wrong.
+        */
+       if (rxhdr->pattern != IPC_RX_DMA_OVER_PATTERN) {
+               cl_rx_invalid_pattern(cl_hw, skb, rxhdr->pattern);
+               return;
+       }
+
+       if (cl_rx_check_err(cl_hw, skb, rxhdr))
+               return;
+
+       /* Convert gi from firmware format to driver format */
+       rxhdr->gi_type = convert_gi_format_fw_to_wrs(rxhdr->format_mod, rxhdr->gi_type);
+
+       /*
+        * For TCV1 fill in the rxhdr rssi "holes" so that values will start from rssi1.
+        * The implementation below takes into account elastic mimo, and maximum number
+        * of antennas for TCV1.
+        */
+       if (cl_hw_is_tcv1(cl_hw)) {
+               if (cl_chip_is_6ant(cl_hw->chip)) {
+                       rxhdr->rssi1 = rxhdr->rssi2;
+                       rxhdr->rssi2 = rxhdr->rssi3;
+                       rxhdr->rssi3 = rxhdr->rssi4;
+                       rxhdr->rssi4 = rxhdr->rssi5;
+                       rxhdr->rssi5 = rxhdr->rssi6;
+               } else if (cl_chip_is_4ant(cl_hw->chip)) {
+                       rxhdr->rssi1 = rxhdr->rssi3;
+                       rxhdr->rssi2 = rxhdr->rssi4;
+                       rxhdr->rssi3 = rxhdr->rssi5;
+                       rxhdr->rssi4 = rxhdr->rssi6;
+               }
+       }
+
+       if (rxhdr->key_sram_v)
+               sta_idx = cl_rx_get_sta_idx(cl_hw, rxhdr);
+
+       cl_sta_lock(cl_hw);
+
+       if (sta_idx != -1) {
+               cl_sta = cl_sta_get(cl_hw, sta_idx);
+
+               if (cl_sta) {
+                       sta = &cl_sta->stainfo->sta;
+
+                       if (cl_hw->conf->ci_fast_rx_en) {
+                               tid = ieee80211_get_tid((struct ieee80211_hdr *)skb->data);
+                               tid_agg_rx = cl_sta->tid_agg_rx[tid];
+                               cl_rx_handle_ps(cl_hw, cl_sta, skb);
+                       }
+
+                       /* Store the pointer to sta in the skb->sk field */
+                       if (remote_cpu_mac != -1)
+                               skb->sk = (struct sock *)sta;
+               }
+       }
+
+       if (unlikely(cl_rx_fill_status(cl_hw, cl_sta, skb, rxhdr, &encrypt_len))) {
+               cl_sta_unlock(cl_hw);
+               kfree_skb(skb);
+               return;
+       }
+
+       /*
+        * RXM sets rxhdr->msdu_cnt=1 also for non AMSDU, so the correct check
+        * is the new amsdu_present bit.
+        */
+       is_amsdu = rxhdr->amsdu_present;
+
+       /* Is A-MSDU frame? */
+       if (is_amsdu) {
+               cl_rx_handle_first_amsdu(cl_hw, skb, amsdu_rx_state, rxhdr, sta_idx,
+                                        tid, encrypt_len);
+               cl_sta_unlock(cl_hw);
+               return;
+       }
+
+       len = le32_to_cpu(rxhdr->len);
+
+       if (skb_tailroom(skb) >= len) {
+               /* Push the WLAN HDR + MDPU payload to the skb data */
+               skb_put(skb, len);
+               cl_hw->rx_info.non_amsdu++;
+       } else {
+               cl_sta_unlock(cl_hw);
+               cl_rx_invalid_tailroom(cl_hw, skb, len);
+               return;
+       }
+
+       skb_done = cl_rx_skb_done(cl_hw, skb, cl_sta, rxhdr);
+
+       cl_sta_unlock(cl_hw);
+
+       if (!skb_done)
+               return;
+
+       if (tid_agg_rx) {
+               struct sk_buff_head reorder_buf;
+
+               /* Init the reorder buffer */
+               __skb_queue_head_init(&reorder_buf);
+               cl_rx_reorder_ampdu(cl_hw, cl_sta, skb, &reorder_buf);
+
+               if (!skb_queue_empty(&reorder_buf))
+                       cl_rx_pass_to_mac(cl_hw, sta, &reorder_buf);
+       } else {
+               if (remote_cpu_mac == -1) {
+                       ieee80211_rx_napi(cl_hw->hw, sta, skb, NULL);
+               } else {
+                       skb_queue_tail(&cl_hw->rx_remote_queue_mac, skb);
+                       cl_rx_remote_cpu_mac(cl_hw);
+               }
+       }
+}
+
+static void cl_rx_tasklet(unsigned long data)
+{
+       struct cl_hw *cl_hw = (struct cl_hw *)data;
+       struct sk_buff *skb = NULL;
+       u16 pkt_cnt = 0;
+
+       if (cl_recovery_in_progress(cl_hw))
+               return;
+
+#ifdef TRACE_SUPPORT
+       trace_cl_trace_rx_tasklet_start(cl_hw->idx);
+#endif
+
+       while ((skb = skb_dequeue(&cl_hw->rx_skb_queue))) {
+               cl_rx_handle_skb(cl_hw, skb);
+
+               if (++pkt_cnt > cl_hw->conf->ce_rx_pkts_budget) {
+                       if (cl_hw->chip->conf->ci_rx_resched_tasklet)
+                               tasklet_schedule(&cl_hw->rx_resched_tasklet);
+                       else
+                               tasklet_schedule(&cl_hw->rx_tasklet);
+
+                       cl_hw->rx_info.exceed_pkt_budget++;
+                       return;
+               }
+       }
+
+#ifdef TRACE_SUPPORT
+       trace_cl_trace_rx_tasklet_end(cl_hw->idx, pkt_cnt);
+#endif
+}
+
+static void cl_rx_resched_tasklet(unsigned long data)
+{
+       struct cl_hw *cl_hw = (struct cl_hw *)data;
+
+       tasklet_schedule(&cl_hw->rx_tasklet);
+}
+
+static void cl_rx_remote_tasklet_mac(unsigned long data)
+{
+       struct cl_hw *cl_hw = (struct cl_hw *)data;
+       struct sk_buff *skb = NULL;
+       struct ieee80211_sta *sta;
+
+       if (cl_recovery_in_progress(cl_hw))
+               return;
+
+       cl_rx_remote_cpu_info(cl_hw);
+
+       while ((skb = skb_dequeue(&cl_hw->rx_remote_queue_mac))) {
+               /*
+                * Get sta pointer from skb->sk (stored their in cl_rx_remote_cpu_mac)
+                * and reset skb->sk.
+                */
+               sta = (struct ieee80211_sta *)skb->sk;
+               skb->sk = NULL;
+
+               ieee80211_rx_napi(cl_hw->hw, sta, skb, NULL);
+       }
+}
+
+void cl_rx_init(struct cl_hw *cl_hw)
+{
+       s8 cpu_mac = cl_hw->conf->ci_rx_remote_cpu_mac;
+
+       /* Set rx_skb_max to be the maximum of ci_rx_skb_max configured for each chip */
+       rx_skb_max = max(cl_hw->chip->conf->ci_rx_skb_max, rx_skb_max);
+
+       skb_queue_head_init(&cl_hw->rx_remote_queue_mac);
+       skb_queue_head_init(&cl_hw->rx_skb_queue);
+       __skb_queue_head_init(&cl_hw->amsdu_rx_state.frames);
+
+       tasklet_init(&cl_hw->rx_tasklet, cl_rx_tasklet, (unsigned long)cl_hw);
+       tasklet_init(&cl_hw->rx_resched_tasklet, cl_rx_resched_tasklet, (unsigned long)cl_hw);
+
+       if (cpu_mac >= 0)
+               tasklet_init(&per_cpu(rx_remote_tasklet_mac[cl_hw->idx], cpu_mac),
+                            cl_rx_remote_tasklet_mac,
+                            (unsigned long)cl_hw);
+#ifdef CONFIG_CL_PCIE
+       cl_rx_pci_init(cl_hw);
+#endif
+}
+
+void cl_rx_off(struct cl_hw *cl_hw)
+{
+       s8 cpu_mac = cl_hw->conf->ci_rx_remote_cpu_mac;
+
+       if (cpu_mac >= 0)
+               tasklet_kill(&per_cpu(rx_remote_tasklet_mac[cl_hw->idx], cpu_mac));
+
+       tasklet_kill(&cl_hw->rx_tasklet);
+       tasklet_kill(&cl_hw->rx_resched_tasklet);
+
+       skb_queue_purge(&cl_hw->rx_remote_queue_mac);
+       skb_queue_purge(&cl_hw->rx_skb_queue);
+
+       cl_rx_amsdu_reset(cl_hw);
+#ifdef CONFIG_CL_PCIE
+       cl_rx_pci_deinit(cl_hw);
+#endif
+}
+
+void cl_rx_remote_tasklet_sched(void *t)
+{
+       tasklet_schedule((struct tasklet_struct *)t);
+}
+
+void cl_rx_remote_cpu_info(struct cl_hw *cl_hw)
+{
+       u32 processor_id = smp_processor_id();
+
+       if (processor_id < CPU_MAX_NUM)
+               cl_hw->rx_info.remote_cpu[processor_id]++;
+}
+
+void cl_rx_push_queue(struct cl_hw *cl_hw, struct sk_buff *skb)
+{
+       skb_queue_tail(&cl_hw->rx_skb_queue, skb);
+       tasklet_schedule(&cl_hw->rx_tasklet);
+}
+
+void cl_rx_skb_alloc_handler(struct sk_buff *skb)
+{
+       skb->destructor = cl_rx_skb_destructor;
+       atomic_inc(&rx_skb_cnt);
+}
+
+void cl_rx_post_recovery(struct cl_hw *cl_hw)
+{
+       if (!skb_queue_empty(&cl_hw->rx_skb_queue))
+               tasklet_schedule(&cl_hw->rx_tasklet);
+
+       if (!skb_queue_empty(&cl_hw->rx_remote_queue_mac))
+               tasklet_schedule(&per_cpu(rx_remote_tasklet_mac[cl_hw->idx],
+                                         cl_hw->conf->ci_rx_remote_cpu_mac));
+}
+
+void cl_rx_info_reset(struct cl_hw *cl_hw)
+{
+       pr_debug("Reset uplink stats\n");
+       memset(&cl_hw->rx_info, 0, sizeof(struct cl_rx_path_info));
+}
+
+int cl_rx_info_print(struct cl_hw *cl_hw)
+{
+       struct cl_rx_path_info *rx_info = &cl_hw->rx_info;
+       struct ieee80211_local *local = hw_to_local(cl_hw->hw);
+       int i;
+       bool uplink_amsdu = false;
+       char *buf = NULL;
+       ssize_t buf_size;
+       int err = 0;
+       int len = 0;
+
+       for (i = 0; i < RX_MAX_MSDU_IN_AMSDU; i++)
+               if (rx_info->amsdu_cnt[i] > 0) {
+                       uplink_amsdu = true;
+                       break;
+               }
+
+       cl_snprintf(&buf, &len, &buf_size,
+                   "Uplink counters\n"
+                   "-----------------------------------\n");
+       cl_snprintf(&buf, &len, &buf_size,
+                   "rx_desc[RXM]                 = %u\n",
+                   rx_info->rx_desc[CL_RX_BUF_RXM]);
+       cl_snprintf(&buf, &len, &buf_size,
+                   "rx_desc[FW]                  = %u\n",
+                   rx_info->rx_desc[CL_RX_BUF_FW]);
+       cl_snprintf(&buf, &len, &buf_size,
+                   "elem_alloc_fail              = %u\n",
+                   rx_info->elem_alloc_fail);
+       cl_snprintf(&buf, &len, &buf_size,
+                   "skb_null                     = %u\n",
+                   rx_info->skb_null);
+       cl_snprintf(&buf, &len, &buf_size,
+                   "pkt_drop_amsdu_corrupted     = %u\n",
+                   rx_info->pkt_drop_amsdu_corrupted);
+       cl_snprintf(&buf, &len, &buf_size,
+                   "pkt_drop_sub_amsdu_corrupted = %u\n",
+                   rx_info->pkt_drop_sub_amsdu_corrupted);
+       cl_snprintf(&buf, &len, &buf_size,
+                   "pkt_drop_amsdu_len_error     = %u\n",
+                   rx_info->pkt_drop_amsdu_len_error);
+       cl_snprintf(&buf, &len, &buf_size,
+                   "pkt_drop_sub_amsdu_len_error = %u\n",
+                   rx_info->pkt_drop_sub_amsdu_len_error);
+       cl_snprintf(&buf, &len, &buf_size,
+                   "pkt_drop_wrong_pattern       = %u\n",
+                   rx_info->pkt_drop_wrong_pattern);
+       cl_snprintf(&buf, &len, &buf_size,
+                   "pkt_drop_not_success         = %u\n",
+                   rx_info->pkt_drop_not_success);
+       cl_snprintf(&buf, &len, &buf_size,
+                   "pkt_drop_unencrypted         = %u\n",
+                   rx_info->pkt_drop_unencrypted);
+       cl_snprintf(&buf, &len, &buf_size,
+                   "pkt_drop_decrypt_fail        = %u\n",
+                   rx_info->pkt_drop_decrypt_fail);
+       cl_snprintf(&buf, &len, &buf_size,
+                   "pkt_drop_rxhdr_len_error     = %u\n",
+                   rx_info->pkt_drop_rxhdr_len_error);
+       cl_snprintf(&buf, &len, &buf_size,
+                   "pkt_drop_sta_null            = %u\n",
+                   rx_info->pkt_drop_sta_null);
+       cl_snprintf(&buf, &len, &buf_size,
+                   "pkt_drop_host_limit          = %u\n",
+                   rx_info->pkt_drop_host_limit);
+       cl_snprintf(&buf, &len, &buf_size,
+                   "netif_rx                     = %u\n",
+                   rx_info->netif_rx);
+
+       len += snprintf(buf + len, PAGE_SIZE - len,
+                       "\nQueue length\n"
+                       "-----------------------------------\n");
+       len += snprintf(buf + len, PAGE_SIZE - len,
+                       "rx_skb_queue                 = %u\n",
+                       skb_queue_len(&cl_hw->rx_skb_queue));
+       len += snprintf(buf + len, PAGE_SIZE - len,
+                       "rx_remote_queue_mac          = %u\n",
+                       skb_queue_len(&cl_hw->rx_remote_queue_mac));
+       len += snprintf(buf + len, PAGE_SIZE - len,
+                       "local_skb_queue              = %u\n",
+                       skb_queue_len(&local->skb_queue));
+
+       cl_snprintf(&buf, &len, &buf_size,
+                   "\nSKB count\n"
+                   "-----------------------------------\n");
+       cl_snprintf(&buf, &len, &buf_size,
+                   "rx_skb_max                   = %u\n",
+                   rx_skb_max);
+       cl_snprintf(&buf, &len, &buf_size,
+                   "rx_skb_cnt                   = %u\n",
+                   atomic_read(&rx_skb_cnt));
+
+       cl_snprintf(&buf, &len, &buf_size,
+                   "\nBuffer processing\n"
+                   "-----------------------------------\n");
+       cl_snprintf(&buf, &len, &buf_size,
+                   "IRQ                          = %u\n",
+                   rx_info->buffer_process_irq);
+       cl_snprintf(&buf, &len, &buf_size,
+                   "Tasklet                      = %u\n",
+                   rx_info->buffer_process_tasklet);
+
+       cl_snprintf(&buf, &len, &buf_size,
+                   "\nUplink Non AMSDU\n"
+                   "-----------------------------------\n"
+                   "NON AMSDU = %u\n", rx_info->non_amsdu);
+
+       if (uplink_amsdu) {
+               cl_snprintf(&buf, &len, &buf_size,
+                           "\nUplink AMSDU\n"
+                           "-----------------------------------\n");
+
+               for (i = 0; i < RX_MAX_MSDU_IN_AMSDU; i++)
+                       if (rx_info->amsdu_cnt[i] > 0)
+                               cl_snprintf(&buf, &len, &buf_size,
+                                           "AMSDU[%d] = %u\n", i + 1, rx_info->amsdu_cnt[i]);
+       }
+
+       if (cl_hw->conf->ci_rx_remote_cpu_drv != -1 ||
+           cl_hw->conf->ci_rx_remote_cpu_mac != -1) {
+               cl_snprintf(&buf, &len, &buf_size,
+                           "\nRemote CPU\n"
+                           "-----------------------------------\n");
+
+               for (i = 0; i < CPU_MAX_NUM; i++) {
+                       if (rx_info->remote_cpu[i] == 0)
+                               continue;
+
+                       cl_snprintf(&buf, &len, &buf_size, "cpu #%u: %u\n",
+                                   i, rx_info->remote_cpu[i]);
+               }
+       }
+
+       cl_snprintf(&buf, &len, &buf_size,
+                   "\nUplink schedule\n"
+                   "-----------------------------------\n"
+                   "exceed_pkt_budget = %u\n",
+                   rx_info->exceed_pkt_budget);
+
+       cl_snprintf(&buf, &len, &buf_size,
+                   "\nUplink buckets RXM\n"
+                   "-----------------------------------\n");
+
+       for (i = 0; i < IPC_RXBUF_NUM_BUCKETS_RXM; i++) {
+               if (rx_info->pkt_handle_bucket_rxm[i] == 0)
+                       continue;
+
+               cl_snprintf(&buf, &len, &buf_size,
+                           "Bucket [%lu -> %lu]: %u\n",
+                           i * IPC_RXBUF_BUCKET_SIZE,
+                           (i + 1) * IPC_RXBUF_BUCKET_SIZE - 1,
+                           rx_info->pkt_handle_bucket_rxm[i]);
+       }
+
+       cl_snprintf(&buf, &len, &buf_size,
+                   "\nUplink buckets FW\n"
+                   "-----------------------------------\n");
+
+       for (i = 0; i < IPC_RXBUF_NUM_BUCKETS_FW; i++) {
+               if (rx_info->pkt_handle_bucket_fw[i] == 0)
+                       continue;
+
+               cl_snprintf(&buf, &len, &buf_size,
+                           "Bucket [%lu -> %lu]: %u\n",
+                           i * IPC_RXBUF_BUCKET_SIZE,
+                           (i + 1) * IPC_RXBUF_BUCKET_SIZE - 1,
+                           rx_info->pkt_handle_bucket_fw[i]);
+       }
+
+       err = cl_vendor_reply(cl_hw, buf, len);
+       kfree(buf);
+
+       return err;
+}
+
+void cl_rx_netif(struct cl_hw *cl_hw, struct cl_vif *cl_vif, struct sk_buff *skb)
+{
+#ifdef TRACE_SUPPORT
+       trace_cl_trace_netif_rx_start(cl_hw->idx);
+#endif
+
+       cl_hw->rx_info.netif_rx++;
+
+       netif_receive_skb(skb);
+
+#ifdef TRACE_SUPPORT
+       trace_cl_trace_netif_rx_end(cl_hw->idx);
+#endif
+}
+
+void cl_rx_finish(struct cl_hw *cl_hw, struct sk_buff *skb)
+{
+       struct cl_vif *cl_vif = NETDEV_TO_CL_VIF(skb->dev);
+
+       cl_rx_netif(cl_hw, cl_vif, skb);
+}
+
+u8 cl_rx_get_skb_ac(struct ieee80211_hdr *hdr)
+{
+       if (ieee80211_is_data_qos(hdr->frame_control)) {
+               u8 *qos_ctl = ieee80211_get_qos_ctl(hdr);
+               u8 tid = *qos_ctl & IEEE80211_QOS_CTL_TAG1D_MASK;
+               return tid_to_ac[tid];
+       }
+
+       return AC_BE;
+}
+
+bool cl_rx_process_in_irq(struct cl_hw *cl_hw)
+{
+       struct cl_ipc_ring_indices *indices = cl_hw->ipc_env->ring_indices_elem->indices;
+       u32 read_idx = le32_to_cpu(indices->rxdesc_read_idx[CL_RX_BUF_RXM]);
+       u32 write_idx = le32_to_cpu(indices->rxdesc_write_idx[CL_RX_BUF_RXM]);
+       u32 free_buffers = read_idx - write_idx;
+
+       if (free_buffers < (IPC_RXBUF_CNT_RXM / 2)) {
+               cl_hw->rx_info.buffer_process_irq++;
+               return true;
+       }
+
+       cl_hw->rx_info.buffer_process_tasklet++;
+       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.
________________________________


^ permalink raw reply related	[flat|nested] 262+ messages in thread

* [RFC v1 173/256] cl8k: add rx/rx.h
  2021-06-17 15:58 [RFC v1 000/256] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (171 preceding siblings ...)
  2021-06-17 16:00 ` [RFC v1 172/256] cl8k: add rx/rx.c viktor.barna
@ 2021-06-17 16:01 ` viktor.barna
  2021-06-17 16:01 ` [RFC v1 174/256] cl8k: add rx/rx_amsdu.c viktor.barna
                   ` (84 subsequent siblings)
  257 siblings, 0 replies; 262+ messages in thread
From: viktor.barna @ 2021-06-17 16:01 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Oleksandr Savchenko, Shay Bar, Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

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

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 drivers/net/wireless/celeno/cl8k/rx/rx.h | 173 +++++++++++++++++++++++
 1 file changed, 173 insertions(+)
 create mode 100644 drivers/net/wireless/celeno/cl8k/rx/rx.h

diff --git a/drivers/net/wireless/celeno/cl8k/rx/rx.h b/drivers/net/wireless/celeno/cl8k/rx/rx.h
new file mode 100644
index 000000000000..17225990ab50
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/rx/rx.h
@@ -0,0 +1,173 @@
+/* SPDX-License-Identifier: MIT */
+/* Copyright(c) 2019-2021, Celeno Communications Ltd. */
+
+#ifndef CL_RX_H
+#define CL_RX_H
+
+#include "wrs/wrs_db.h"
+#include "hw.h"
+
+/* Decryption status subfields */
+enum cl_rx_hd_decr {
+       CL_RX_HDR_DECR_UNENC,
+       CL_RX_HDR_DECR_ICVFAIL,
+       CL_RX_HDR_DECR_CCMPFAIL,
+       CL_RX_HDR_DECR_AMSDUDISCARD,
+       CL_RX_HDR_DECR_NULLKEY,
+       CL_RX_HDR_DECR_WEPSUCCESS,
+       CL_RX_HDR_DECR_TKIPSUCCESS,
+       CL_RX_HDR_DECR_CCMPSUCCESS
+};
+
+#define CL_PADDING_IN_BYTES 2
+
+struct hw_rxhdr {
+       u32 msdu_cnt           : 8,   /* [7:0] */
+           corrupted_amsdu    : 1,   /* [8] */
+           reserved           : 1,   /* [9] */
+           msdu_dma_align     : 2,   /* [11:10] */
+           amsdu_error_code   : 4,   /* [15:12] */
+           reserved_2         :16;   /* [31:16] */
+
+       /* Total length for the MPDU transfer */
+       u32 len                :14,   /* [13:0] */
+           ampdu_cnt          : 2,   /* [15:14] */
+           rx_padding_done    : 1,   /* [16] */
+           rx_class_rule_res  : 7,   /* [23:17] */
+
+       /* AMPDU Status Information */
+           mpdu_cnt           : 8;   /* [31:24] */
+
+       /* TSF Low */
+       __le32 tsf_lo;
+       /* TSF High */
+       __le32 tsf_hi;
+
+       /* Receive Vector 1a */
+       u32 leg_length         :12,   /* [11:0] */
+           leg_rate           : 4,   /* [15:12] */
+           ht_length_l        :16;   /* [31:16] */
+
+       /* Receive Vector 1b */
+       u32 ht_length_h        : 8,   /* [7:0] */
+           mcs                : 7,   /* [14:8] */
+           pre_type           : 1,   /* [15] */
+           format_mod         : 4,   /* [19:16] */
+           reserved_1b        : 1,   /* [20] */
+           n_sts              : 3,   /* [23:21] */
+           lsig_valid         : 1,   /* [24] */
+           sounding           : 1,   /* [25] */
+           num_extn_ss        : 2,   /* [27:26] */
+           aggregation        : 1,   /* [28] */
+           fec_coding         : 1,   /* [29] */
+           dyn_bw             : 1,   /* [30] */
+           doze_not_allowed   : 1;   /* [31] */
+
+       /* Receive Vector 1c */
+       u32 sn                 : 4,  /* [3:0] */
+           warn_1c            : 1,  /* [4] */
+           stbc               : 2,  /* [6:5] */
+           smoothing          : 1,  /* [7] */
+           partial_aid        : 9,  /* [16:8] */
+           group_id           : 6,  /* [22:17] */
+           reserved_1c        : 1,  /* [23] */
+           rssi1              : 8;  /* [31:24] */
+
+       /* Receive Vector 1d */
+       s32 rssi2              : 8,  /* [7:0] */
+           rssi3              : 8,  /* [15:8] */
+           rssi4              : 8,  /* [23:16] */
+           rx_chains          : 8;  /* [31:24] */
+
+       /* Receive Vector 1e */
+       u32 txop_duration      : 7,  /* [6:0] */
+           beam_change        : 1,  /* [7] */
+           mcs_sig_b          : 3,  /* [10:8] */
+           dcm                : 1,  /* [11] */
+           dcm_sig_b          : 1,  /* [12] */
+           beamformed         : 1,  /* [13] */
+           ltf_type           : 2,  /* [15:14] */
+           ru_band            : 1,  /* [16] */
+           ru_type            : 3,  /* [19:17] */
+           ru_index           : 6,  /* [25:20] */
+           pe_duration        : 3,  /* [28:26] */
+           ch_bw              : 2,  /* [30:29] */
+           reserved_1e        : 1;  /* [31] */
+
+       /* Receive Vector 1f */
+       u32 spatial_reuse      : 16, /* [16:0] */
+           service            : 16; /* [32:17] */
+
+       /* Receive Vector 1g */
+       u32 bss_color          : 6,  /* [5:0] */
+           gi_type            : 2,  /* [7:6] */
+           antenna_set        : 16, /* [23:8] */
+           rssi5              : 8;  /* [31:24] */
+
+       /* Receive Vector 1h */
+       s32 rssi6              : 8,  /* [7:0] */
+           rssi7              : 8,  /* [15:8] */
+           rssi8              : 8,  /* [23:16] */
+           future_1           : 8;  /* [31:24] */
+
+       /* Receive Vector 2a */
+       u32 rcpi               : 8,  /* [7:0] */
+           evm1               : 8,  /* [15:8] */
+           evm2               : 8,  /* [23:16] */
+           evm3               : 8;  /* [31:24] */
+
+       /* Receive Vector 2b */
+       u32 evm4               : 8,  /* [7:0] */
+           warn_2b            : 1,  /* [8] */
+           reserved2b_1       : 7,  /* [15:9] */
+           reserved2b_2       : 8,  /* [23:16] */
+           reserved2b_3       : 8;  /* [31:24] */
+
+       /* Status **/
+       u32 rx_vect2_valid     : 1,  /* [0] */
+           resp_frame         : 1,  /* [1] */
+           decr_status        : 3,  /* [4:2] */
+           rx_fifo_oflow      : 1,  /* [5] */
+           undef_err          : 1,  /* [6] */
+           phy_err            : 1,  /* [7] */
+           fcs_err            : 1,  /* [8] */
+           addr_mismatch      : 1,  /* [9] */
+           ga_frame           : 1,  /* [10] */
+           first_qos_data     : 1,  /* [11] */
+           amsdu_present      : 1,  /* [12] */
+           frm_successful_rx  : 1,  /* [13] */
+           desc_done_rx       : 1,  /* [14] */
+           desc_spare         : 1,  /* [15] */
+           key_sram_index     : 9,  /* [24:16] */
+           key_sram_v         : 1,  /* [25] */
+           type               : 2,  /* [27:26] */
+           subtype            : 4;  /* [31:28] */
+
+       /* PHY channel information 1 */
+       u32 phy_band           : 8,  /* [7:0] */
+           phy_channel_type   : 8,  /* [15:8] */
+           phy_prim20_freq    : 16; /* [31:16] */
+
+       /* PHY channel information 2 */
+       u32 phy_center1_freq   : 16, /* [15:0] */
+           phy_center2_freq   : 16; /* [31:16] */
+
+       /* Patten **/
+       u32 pattern;
+};
+
+void cl_rx_init(struct cl_hw *cl_hw);
+void cl_rx_off(struct cl_hw *cl_hw);
+void cl_rx_remote_tasklet_sched(void *t);
+void cl_rx_remote_cpu_info(struct cl_hw *cl_hw);
+void cl_rx_push_queue(struct cl_hw *cl_hw, struct sk_buff *skb);
+void cl_rx_skb_alloc_handler(struct sk_buff *skb);
+void cl_rx_post_recovery(struct cl_hw *cl_hw);
+void cl_rx_info_reset(struct cl_hw *cl_hw);
+int cl_rx_info_print(struct cl_hw *cl_hw);
+void cl_rx_netif(struct cl_hw *cl_hw, struct cl_vif *cl_vif, struct sk_buff *skb);
+void cl_rx_finish(struct cl_hw *cl_hw, struct sk_buff *skb);
+u8 cl_rx_get_skb_ac(struct ieee80211_hdr *hdr);
+bool cl_rx_process_in_irq(struct cl_hw *cl_hw);
+
+#endif /* CL_RX_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.
________________________________


^ permalink raw reply related	[flat|nested] 262+ messages in thread

* [RFC v1 174/256] cl8k: add rx/rx_amsdu.c
  2021-06-17 15:58 [RFC v1 000/256] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (172 preceding siblings ...)
  2021-06-17 16:01 ` [RFC v1 173/256] cl8k: add rx/rx.h viktor.barna
@ 2021-06-17 16:01 ` viktor.barna
  2021-06-17 16:01 ` [RFC v1 175/256] cl8k: add rx/rx_amsdu.h viktor.barna
                   ` (83 subsequent siblings)
  257 siblings, 0 replies; 262+ messages in thread
From: viktor.barna @ 2021-06-17 16:01 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Oleksandr Savchenko, Shay Bar, Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

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

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 .../net/wireless/celeno/cl8k/rx/rx_amsdu.c    | 257 ++++++++++++++++++
 1 file changed, 257 insertions(+)
 create mode 100644 drivers/net/wireless/celeno/cl8k/rx/rx_amsdu.c

diff --git a/drivers/net/wireless/celeno/cl8k/rx/rx_amsdu.c b/drivers/net/wireless/celeno/cl8k/rx/rx_amsdu.c
new file mode 100644
index 000000000000..512a317227a1
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/rx/rx_amsdu.c
@@ -0,0 +1,257 @@
+// SPDX-License-Identifier: MIT
+/* Copyright(c) 2019-2021, Celeno Communications Ltd. */
+
+#include "rx/rx_amsdu.h"
+
+struct msduhdr {
+       u8 dest[ETH_ALEN];
+       u8 source[ETH_ALEN];
+       __be16 len;
+} __packed;
+
+enum rx_amsdu_error {
+       RX_AMSDU_ERR_CORRUPTED = 0x1,
+       RX_AMSDU_ERR_LENGTH = 0x2,
+};
+
+static void set_flag_amsdu_more(struct sk_buff *skb)
+{
+       struct ieee80211_rx_status *rx_status = IEEE80211_SKB_RXCB(skb);
+
+       rx_status->flag |= RX_FLAG_AMSDU_MORE;
+}
+
+static void clear_flag_amsdu_more(struct sk_buff *skb)
+{
+       struct ieee80211_rx_status *rx_status = IEEE80211_SKB_RXCB(skb);
+
+       rx_status->flag &= ~RX_FLAG_AMSDU_MORE;
+}
+
+static void add_80211_hdr(struct cl_amsdu_rx_state *amsdu_rx_state,
+                         struct sk_buff *skb, struct sk_buff *first_skb)
+{
+       /* Copy the 802.11 header of the first skb */
+       struct ieee80211_hdr *hdr_first = (struct ieee80211_hdr *)(first_skb->data);
+       u32 hdrlen_first = ieee80211_hdrlen(hdr_first->frame_control);
+       u32 total_bytes = hdrlen_first + amsdu_rx_state->encrypt_len;
+
+       /* Total_bytes must be smaller than IPC_RXBUF_EXTRA_HEADROOM */
+       skb_push(skb, total_bytes);
+       memcpy(skb->data, first_skb->data, total_bytes);
+}
+
+static void copy_status(struct cl_amsdu_rx_state *amsdu_rx_state,
+                       struct sk_buff *skb, struct sk_buff *first_skb)
+{
+       struct ieee80211_rx_status *rx_status = IEEE80211_SKB_RXCB(skb);
+       struct ieee80211_rx_status *rx_status_first = IEEE80211_SKB_RXCB(first_skb);
+
+       /* Copy rx_status from the first skb */
+       memcpy(rx_status, rx_status_first, sizeof(struct ieee80211_rx_status));
+
+       /* If it is the last sub-frame clear RX_FLAG_AMSDU_MORE */
+       if (amsdu_rx_state->msdu_remaining_cnt == 0)
+               rx_status->flag &= ~RX_FLAG_AMSDU_MORE;
+}
+
+static void cl_rx_amsdu_set_state(struct cl_hw *cl_hw, struct sk_buff *skb, struct hw_rxhdr *rxhdr,
+                                 u8 sta_idx, u8 tid, u32 packet_len, u8 encrypt_len)
+{
+       struct cl_amsdu_rx_state *amsdu_rx_state = &cl_hw->amsdu_rx_state;
+
+       amsdu_rx_state->msdu_cnt = rxhdr->msdu_cnt;
+       amsdu_rx_state->msdu_remaining_cnt = rxhdr->msdu_cnt - 1;
+       amsdu_rx_state->msdu_dma_align = rxhdr->msdu_dma_align;
+       amsdu_rx_state->amsdu_error = 0;
+       amsdu_rx_state->encrypt_len = encrypt_len;
+       amsdu_rx_state->packet_len = packet_len;
+       amsdu_rx_state->rxhdr = rxhdr;
+       amsdu_rx_state->first_skb = skb;
+       amsdu_rx_state->sta_idx = sta_idx;
+       amsdu_rx_state->tid = tid;
+
+       __skb_queue_head(&cl_hw->amsdu_rx_state.frames, skb);
+}
+
+static void cl_rx_amsdu_set_state_error(struct cl_hw *cl_hw,
+                                       struct hw_rxhdr *rxhdr,
+                                       enum rx_amsdu_error err)
+{
+       struct cl_amsdu_rx_state *amsdu_rx_state = &cl_hw->amsdu_rx_state;
+
+       amsdu_rx_state->msdu_cnt = rxhdr->msdu_cnt;
+       amsdu_rx_state->msdu_remaining_cnt = rxhdr->msdu_cnt - 1;
+       amsdu_rx_state->amsdu_error = err;
+}
+
+static void cl_rx_amsdu_first_length_error(struct cl_hw *cl_hw, struct sk_buff *skb,
+                                          struct hw_rxhdr *rxhdr, u32 len)
+{
+       cl_dbg_err(cl_hw, "RX-AMSDU length error (1/%u) - tailroom=%d, len=%u\n",
+                  rxhdr->msdu_cnt, skb_tailroom(skb), len);
+
+       cl_rx_amsdu_set_state_error(cl_hw, rxhdr, RX_AMSDU_ERR_LENGTH);
+
+       cl_hw->rx_info.pkt_drop_amsdu_len_error++;
+       kfree_skb(skb);
+}
+
+static void cl_rx_amsdu_sub_length_error(struct cl_hw *cl_hw, struct sk_buff *skb, u32 len)
+{
+       struct cl_amsdu_rx_state *amsdu_rx_state = &cl_hw->amsdu_rx_state;
+       struct sk_buff *skb_tail;
+       u8 sub_cnt = amsdu_rx_state->msdu_cnt - amsdu_rx_state->msdu_remaining_cnt;
+
+       cl_dbg_err(cl_hw, "RX-AMSDU length error (%u/%u) - tailroom=%d, len=%u\n",
+                  sub_cnt, amsdu_rx_state->msdu_cnt, skb_tailroom(skb), len);
+
+       /* All remaining skbs in the AMSDU will be treated as errors */
+       amsdu_rx_state->amsdu_error = RX_AMSDU_ERR_LENGTH;
+
+       /* Clear RX_FLAG_AMSDU_MORE in the last success skb that was received */
+       skb_tail = skb_peek_tail(&amsdu_rx_state->frames);
+       clear_flag_amsdu_more(skb_tail);
+
+       cl_hw->rx_info.pkt_drop_sub_amsdu_len_error++;
+       kfree_skb(skb);
+}
+
+void cl_rx_amsdu_first(struct cl_hw *cl_hw, struct sk_buff *skb,
+                      struct hw_rxhdr *rxhdr, u8 sta_idx, u8 tid, u8 encrypt_len)
+{
+       struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)(skb->data);
+       u32 hdr_len = ieee80211_hdrlen(hdr->frame_control);
+       struct msduhdr *msdu_hdr = (struct msduhdr *)(skb->data + hdr_len + encrypt_len);
+       u32 packet_len = hdr_len + encrypt_len + sizeof(struct msduhdr) + ntohs(msdu_hdr->len);
+
+       if (skb_tailroom(skb) < packet_len) {
+               cl_rx_amsdu_first_length_error(cl_hw, skb, rxhdr, packet_len);
+               return;
+       }
+
+       /* Put the WLAN header + MSDU header + payload in the skb data */
+       skb_put(skb, packet_len);
+
+       cl_rx_amsdu_set_state(cl_hw, skb, rxhdr, sta_idx, tid, packet_len, encrypt_len);
+
+       /* Must be called after cl_rx_amsdu_set_state() */
+       if (cl_hw->amsdu_rx_state.msdu_remaining_cnt > 0)
+               set_flag_amsdu_more(skb);
+}
+
+bool cl_rx_amsdu_sub(struct cl_hw *cl_hw, struct sk_buff *skb)
+{
+       /*
+        * ----------------------------------------------------------
+        * | DMA padding 4 byte alignment | MSDU HDR | MSDU PAYLOAD |
+        *  ---------------------------------------------------------
+        */
+       struct cl_amsdu_rx_state *amsdu_rx_state = &cl_hw->amsdu_rx_state;
+       struct sk_buff *first_skb = amsdu_rx_state->first_skb;
+       struct msduhdr *msdu_hdr;
+       u32 packet_len;
+
+       /*
+        * Push the dma alignment to the reserved area, so that skb->data will
+        * point to the MSDU header
+        */
+       skb_reserve(skb, amsdu_rx_state->msdu_dma_align);
+
+       msdu_hdr = (struct msduhdr *)(skb->data);
+       packet_len = sizeof(struct msduhdr) + ntohs(msdu_hdr->len);
+
+       if (skb_tailroom(skb) < packet_len) {
+               cl_rx_amsdu_sub_length_error(cl_hw, skb, packet_len);
+               return false;
+       }
+
+       /* Put the MSDU HDR + MSDU PAYLOAD into the skb data area */
+       skb_put(skb, packet_len);
+
+       amsdu_rx_state->packet_len += packet_len;
+
+       add_80211_hdr(amsdu_rx_state, skb, first_skb);
+       copy_status(amsdu_rx_state, skb, first_skb);
+
+       /* Store the pointer to sta in the skb->sk field */
+       skb->sk = first_skb->sk;
+
+       __skb_queue_tail(&amsdu_rx_state->frames, skb);
+
+       return true;
+}
+
+void cl_rx_amsdu_first_corrupted(struct cl_hw *cl_hw, struct sk_buff *skb,
+                                struct hw_rxhdr *rxhdr)
+{
+       struct ieee80211_hdr *mac_hdr = (struct ieee80211_hdr *)(skb->data);
+
+       cl_dbg_verbose(cl_hw, "Corrupted RX-AMSDU (1/%u), dest_addr=%pM\n",
+                      rxhdr->msdu_cnt, mac_hdr->addr1);
+
+       cl_rx_amsdu_set_state_error(cl_hw, rxhdr, RX_AMSDU_ERR_CORRUPTED);
+
+       cl_hw->rx_info.pkt_drop_amsdu_corrupted++;
+       kfree_skb(skb);
+}
+
+void cl_rx_amsdu_sub_error(struct cl_hw *cl_hw, struct sk_buff *skb)
+{
+       struct cl_amsdu_rx_state *amsdu_rx_state = &cl_hw->amsdu_rx_state;
+       u8 sub_cnt = amsdu_rx_state->msdu_cnt - amsdu_rx_state->msdu_remaining_cnt;
+
+       if (amsdu_rx_state->amsdu_error & RX_AMSDU_ERR_CORRUPTED) {
+               cl_hw->rx_info.pkt_drop_sub_amsdu_corrupted++;
+
+               cl_dbg_verbose(cl_hw, "Corrupted RX-AMSDU (%u/%u)\n",
+                              sub_cnt, amsdu_rx_state->msdu_cnt);
+       } else if (amsdu_rx_state->amsdu_error & RX_AMSDU_ERR_LENGTH) {
+               cl_hw->rx_info.pkt_drop_sub_amsdu_len_error++;
+
+               cl_dbg_verbose(cl_hw, "RX-AMSDU length error (%u/%u)\n",
+                              sub_cnt, amsdu_rx_state->msdu_cnt);
+       }
+
+       kfree_skb(skb);
+}
+
+void cl_rx_amsdu_reset(struct cl_hw *cl_hw)
+{
+       /* Free pending frames */
+       __skb_queue_purge(&cl_hw->amsdu_rx_state.frames);
+
+       /* Reset RX A-MSDU state */
+       memset(&cl_hw->amsdu_rx_state, 0, sizeof(struct cl_amsdu_rx_state));
+
+       __skb_queue_head_init(&cl_hw->amsdu_rx_state.frames);
+}
+
+void cl_rx_amsdu_stats(struct cl_hw *cl_hw, u8 msdu_cnt)
+{
+       /*
+        * Update A-MSDU statistics
+        * msdu_cnt 1 - 128 is mapped to 0 - 127.
+        */
+       if (msdu_cnt <= RX_MAX_MSDU_IN_AMSDU)
+               cl_hw->rx_info.amsdu_cnt[msdu_cnt - 1]++;
+       else
+               cl_dbg_err(cl_hw, "Invalid msdu_cnt [%u]\n", msdu_cnt);
+}
+
+/* Only ieee80211_hw_set() is defined in mac80211.h */
+static inline void _ieee80211_hw_clear(struct ieee80211_hw *hw,
+                                      enum ieee80211_hw_flags flg)
+{
+       return __clear_bit(flg, hw->flags);
+}
+
+#define ieee80211_hw_clear(hw, flg) _ieee80211_hw_clear(hw, IEEE80211_HW_##flg)
+
+void cl_rx_amsdu_hw_en(struct ieee80211_hw *hw, bool rxamsdu_en)
+{
+       if (rxamsdu_en)
+               ieee80211_hw_set(hw, SUPPORTS_AMSDU_IN_AMPDU);
+       else
+               ieee80211_hw_clear(hw, SUPPORTS_AMSDU_IN_AMPDU);
+}
--
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.
________________________________


^ permalink raw reply related	[flat|nested] 262+ messages in thread

* [RFC v1 175/256] cl8k: add rx/rx_amsdu.h
  2021-06-17 15:58 [RFC v1 000/256] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (173 preceding siblings ...)
  2021-06-17 16:01 ` [RFC v1 174/256] cl8k: add rx/rx_amsdu.c viktor.barna
@ 2021-06-17 16:01 ` viktor.barna
  2021-06-17 16:01 ` [RFC v1 176/256] cl8k: add rx/rx_filter.c viktor.barna
                   ` (82 subsequent siblings)
  257 siblings, 0 replies; 262+ messages in thread
From: viktor.barna @ 2021-06-17 16:01 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Oleksandr Savchenko, Shay Bar, Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

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

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 .../net/wireless/celeno/cl8k/rx/rx_amsdu.h    | 20 +++++++++++++++++++
 1 file changed, 20 insertions(+)
 create mode 100644 drivers/net/wireless/celeno/cl8k/rx/rx_amsdu.h

diff --git a/drivers/net/wireless/celeno/cl8k/rx/rx_amsdu.h b/drivers/net/wireless/celeno/cl8k/rx/rx_amsdu.h
new file mode 100644
index 000000000000..a445f4a83187
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/rx/rx_amsdu.h
@@ -0,0 +1,20 @@
+/* SPDX-License-Identifier: MIT */
+/* Copyright(c) 2019-2021, Celeno Communications Ltd. */
+
+#ifndef CL_RX_AMSDU_H
+#define CL_RX_AMSDU_H
+
+#include "hw.h"
+#include "rx/rx.h"
+
+void cl_rx_amsdu_first(struct cl_hw *cl_hw, struct sk_buff *skb, struct hw_rxhdr *rxhdr,
+                      u8 sta_idx, u8 tid, u8 encrypt_len);
+bool cl_rx_amsdu_sub(struct cl_hw *cl_hw, struct sk_buff *skb);
+void cl_rx_amsdu_first_corrupted(struct cl_hw *cl_hw, struct sk_buff *skb,
+                                struct hw_rxhdr *rxhdr);
+void cl_rx_amsdu_sub_error(struct cl_hw *cl_hw, struct sk_buff *skb);
+void cl_rx_amsdu_reset(struct cl_hw *cl_hw);
+void cl_rx_amsdu_stats(struct cl_hw *cl_hw, u8 msdu_cnt);
+void cl_rx_amsdu_hw_en(struct ieee80211_hw *hw, bool rxamsdu_en);
+
+#endif /* CL_RX_AMSDU_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.
________________________________


^ permalink raw reply related	[flat|nested] 262+ messages in thread

* [RFC v1 176/256] cl8k: add rx/rx_filter.c
  2021-06-17 15:58 [RFC v1 000/256] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (174 preceding siblings ...)
  2021-06-17 16:01 ` [RFC v1 175/256] cl8k: add rx/rx_amsdu.h viktor.barna
@ 2021-06-17 16:01 ` viktor.barna
  2021-06-17 16:01 ` [RFC v1 177/256] cl8k: add rx/rx_filter.h viktor.barna
                   ` (81 subsequent siblings)
  257 siblings, 0 replies; 262+ messages in thread
From: viktor.barna @ 2021-06-17 16:01 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Oleksandr Savchenko, Shay Bar, Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

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

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 .../net/wireless/celeno/cl8k/rx/rx_filter.c   | 88 +++++++++++++++++++
 1 file changed, 88 insertions(+)
 create mode 100644 drivers/net/wireless/celeno/cl8k/rx/rx_filter.c

diff --git a/drivers/net/wireless/celeno/cl8k/rx/rx_filter.c b/drivers/net/wireless/celeno/cl8k/rx/rx_filter.c
new file mode 100644
index 000000000000..95415ec6aad0
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/rx/rx_filter.c
@@ -0,0 +1,88 @@
+// SPDX-License-Identifier: MIT
+/* Copyright(c) 2019-2021, Celeno Communications Ltd. */
+
+#include "rx/rx_filter.h"
+#include "fw/msg_tx.h"
+#include "ieee80211_i.h"
+
+u32 cl_rx_filter_update_flags(struct cl_hw *cl_hw, u32 filter)
+{
+       u32 rx_filter = 0;
+
+       if (filter & FIF_ALLMULTI)
+               rx_filter |= RX_CNTRL_ACCEPT_MULTICAST_BIT;
+
+       if (filter & (FIF_FCSFAIL | FIF_PLCPFAIL))
+               rx_filter |= RX_CNTRL_ACCEPT_ERROR_FRAMES_BIT;
+
+       if (filter & FIF_BCN_PRBRESP_PROMISC)
+               rx_filter |= RX_CNTRL_ACCEPT_OTHER_BSSID_BIT;
+
+       if (filter & FIF_CONTROL)
+               rx_filter |= RX_CNTRL_ACCEPT_OTHER_CNTRL_FRAMES_BIT |
+                            RX_CNTRL_ACCEPT_CF_END_BIT |
+                            RX_CNTRL_ACCEPT_ACK_BIT |
+                            RX_CNTRL_ACCEPT_CTS_BIT |
+                            RX_CNTRL_ACCEPT_RTS_BIT |
+                            RX_CNTRL_ACCEPT_BA_BIT | RX_CNTRL_ACCEPT_BAR_BIT;
+
+       if (filter & FIF_OTHER_BSS)
+               rx_filter |= RX_CNTRL_ACCEPT_OTHER_BSSID_BIT;
+
+       if (filter & FIF_PSPOLL)
+               rx_filter |= RX_CNTRL_ACCEPT_PS_POLL_BIT;
+
+       if (filter & FIF_PROBE_REQ)
+               rx_filter |= RX_CNTRL_ACCEPT_PROBE_REQ_BIT;
+
+       /* Add the filter flags that are set by default and cannot be changed here */
+       rx_filter |= CL_MAC80211_NOT_CHANGEABLE;
+
+       if (ieee80211_hw_check(cl_hw->hw, AMPDU_AGGREGATION))
+               rx_filter |= RX_CNTRL_ACCEPT_BA_BIT;
+
+       /*
+        * work around for HW bug (AD 14672)
+        * In order for the response frames to BAR and RTS be with correct
+        * power they should always be accepted and found in the KSR
+        */
+       rx_filter |= RX_CNTRL_ACCEPT_BAR_BIT | RX_CNTRL_ACCEPT_RTS_BIT;
+
+       return rx_filter;
+}
+
+static u32 cl_filter_get_flags(struct net_device *dev)
+{
+       struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+
+       return sdata->local->filter_flags;
+}
+
+void cl_rx_filter_restore_flags(struct cl_hw *cl_hw)
+{
+       struct net_device *dev = cl_vif_get_first_net_device(cl_hw);
+       u32 filter = 0;
+
+       if (!dev)
+               return;
+
+       filter = cl_filter_get_flags(dev);
+       cl_dbg_verbose(cl_hw, "Restoring filter flags to 0x%x\n", filter);
+       cl_msg_tx_set_filter(cl_hw, filter, false);
+}
+
+void cl_rx_filter_set_promiscuous_off(unsigned long data)
+{
+       struct cl_hw *cl_hw = (struct cl_hw *)data;
+
+       cl_rx_filter_restore_flags(cl_hw);
+}
+
+void cl_rx_filter_set_promiscuous(struct cl_hw *cl_hw)
+{
+       u32 filter = ~(FIF_FCSFAIL | FIF_PLCPFAIL | (1 << 31));
+
+       cl_dbg_verbose(cl_hw, "set promiscuous mode 0x%x\n", filter);
+       cl_msg_tx_set_filter(cl_hw, filter, 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.
________________________________


^ permalink raw reply related	[flat|nested] 262+ messages in thread

* [RFC v1 177/256] cl8k: add rx/rx_filter.h
  2021-06-17 15:58 [RFC v1 000/256] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (175 preceding siblings ...)
  2021-06-17 16:01 ` [RFC v1 176/256] cl8k: add rx/rx_filter.c viktor.barna
@ 2021-06-17 16:01 ` viktor.barna
  2021-06-17 16:01 ` [RFC v1 178/256] cl8k: add rx/rx_reorder.c viktor.barna
                   ` (80 subsequent siblings)
  257 siblings, 0 replies; 262+ messages in thread
From: viktor.barna @ 2021-06-17 16:01 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Oleksandr Savchenko, Shay Bar, Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

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

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 .../net/wireless/celeno/cl8k/rx/rx_filter.h   | 91 +++++++++++++++++++
 1 file changed, 91 insertions(+)
 create mode 100644 drivers/net/wireless/celeno/cl8k/rx/rx_filter.h

diff --git a/drivers/net/wireless/celeno/cl8k/rx/rx_filter.h b/drivers/net/wireless/celeno/cl8k/rx/rx_filter.h
new file mode 100644
index 000000000000..a51f730019d3
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/rx/rx_filter.h
@@ -0,0 +1,91 @@
+/* SPDX-License-Identifier: MIT */
+/* Copyright(c) 2019-2021, Celeno Communications Ltd. */
+
+#ifndef CL_RX_FILTER_H
+#define CL_RX_FILTER_H
+
+#include "hw.h"
+#include "vendor_cmd.h"
+
+/* Field definitions */
+#define RX_CNTRL_EN_DUPLICATE_DETECTION_BIT      ((u32)0x80000000)
+#define RX_CNTRL_EN_DUPLICATE_DETECTION_POS      31
+#define RX_CNTRL_ACCEPT_UNKNOWN_BIT              ((u32)0x40000000)
+#define RX_CNTRL_ACCEPT_UNKNOWN_POS              30
+#define RX_CNTRL_ACCEPT_OTHER_DATA_FRAMES_BIT    ((u32)0x20000000)
+#define RX_CNTRL_ACCEPT_OTHER_DATA_FRAMES_POS    29
+#define RX_CNTRL_ACCEPT_QO_S_NULL_BIT            ((u32)0x10000000)
+#define RX_CNTRL_ACCEPT_QO_S_NULL_POS            28
+#define RX_CNTRL_ACCEPT_QCFWO_DATA_BIT           ((u32)0x08000000)
+#define RX_CNTRL_ACCEPT_QCFWO_DATA_POS           27
+#define RX_CNTRL_ACCEPT_Q_DATA_BIT               ((u32)0x04000000)
+#define RX_CNTRL_ACCEPT_Q_DATA_POS               26
+#define RX_CNTRL_ACCEPT_CFWO_DATA_BIT            ((u32)0x02000000)
+#define RX_CNTRL_ACCEPT_CFWO_DATA_POS            25
+#define RX_CNTRL_ACCEPT_DATA_BIT                 ((u32)0x01000000)
+#define RX_CNTRL_ACCEPT_DATA_POS                 24
+#define RX_CNTRL_ACCEPT_OTHER_CNTRL_FRAMES_BIT   ((u32)0x00800000)
+#define RX_CNTRL_ACCEPT_OTHER_CNTRL_FRAMES_POS   23
+#define RX_CNTRL_ACCEPT_CF_END_BIT               ((u32)0x00400000)
+#define RX_CNTRL_ACCEPT_CF_END_POS               22
+#define RX_CNTRL_ACCEPT_ACK_BIT                  ((u32)0x00200000)
+#define RX_CNTRL_ACCEPT_ACK_POS                  21
+#define RX_CNTRL_ACCEPT_CTS_BIT                  ((u32)0x00100000)
+#define RX_CNTRL_ACCEPT_CTS_POS                  20
+#define RX_CNTRL_ACCEPT_RTS_BIT                  ((u32)0x00080000)
+#define RX_CNTRL_ACCEPT_RTS_POS                  19
+#define RX_CNTRL_ACCEPT_PS_POLL_BIT              ((u32)0x00040000)
+#define RX_CNTRL_ACCEPT_PS_POLL_POS              18
+#define RX_CNTRL_ACCEPT_BA_BIT                   ((u32)0x00020000)
+#define RX_CNTRL_ACCEPT_BA_POS                   17
+#define RX_CNTRL_ACCEPT_BAR_BIT                  ((u32)0x00010000)
+#define RX_CNTRL_ACCEPT_BAR_POS                  16
+#define RX_CNTRL_ACCEPT_OTHER_MGMT_FRAMES_BIT    ((u32)0x00008000)
+#define RX_CNTRL_ACCEPT_OTHER_MGMT_FRAMES_POS    15
+#define RX_CNTRL_ACCEPT_ALL_BEACON_BIT           ((u32)0x00002000)
+#define RX_CNTRL_ACCEPT_ALL_BEACON_POS           13
+#define RX_CNTRL_ACCEPT_NOT_EXPECTED_BA_BIT      ((u32)0x00001000)
+#define RX_CNTRL_ACCEPT_NOT_EXPECTED_BA_POS      12
+#define RX_CNTRL_ACCEPT_DECRYPT_ERROR_FRAMES_BIT ((u32)0x00000800)
+#define RX_CNTRL_ACCEPT_DECRYPT_ERROR_FRAMES_POS 11
+#define RX_CNTRL_ACCEPT_BEACON_BIT               ((u32)0x00000400)
+#define RX_CNTRL_ACCEPT_BEACON_POS               10
+#define RX_CNTRL_ACCEPT_PROBE_RESP_BIT           ((u32)0x00000200)
+#define RX_CNTRL_ACCEPT_PROBE_RESP_POS           9
+#define RX_CNTRL_ACCEPT_PROBE_REQ_BIT            ((u32)0x00000100)
+#define RX_CNTRL_ACCEPT_PROBE_REQ_POS            8
+#define RX_CNTRL_ACCEPT_MY_UNICAST_BIT           ((u32)0x00000080)
+#define RX_CNTRL_ACCEPT_MY_UNICAST_POS           7
+#define RX_CNTRL_ACCEPT_UNICAST_BIT              ((u32)0x00000040)
+#define RX_CNTRL_ACCEPT_UNICAST_POS              6
+#define RX_CNTRL_ACCEPT_ERROR_FRAMES_BIT         ((u32)0x00000020)
+#define RX_CNTRL_ACCEPT_ERROR_FRAMES_POS         5
+#define RX_CNTRL_ACCEPT_OTHER_BSSID_BIT          ((u32)0x00000010)
+#define RX_CNTRL_ACCEPT_OTHER_BSSID_POS          4
+#define RX_CNTRL_ACCEPT_BROADCAST_BIT            ((u32)0x00000008)
+#define RX_CNTRL_ACCEPT_BROADCAST_POS            3
+#define RX_CNTRL_ACCEPT_MULTICAST_BIT            ((u32)0x00000004)
+#define RX_CNTRL_ACCEPT_MULTICAST_POS            2
+#define RX_CNTRL_DONT_DECRYPT_BIT                ((u32)0x00000002)
+#define RX_CNTRL_DONT_DECRYPT_POS                1
+#define RX_CNTRL_EXC_UNENCRYPTED_BIT             ((u32)0x00000001)
+#define RX_CNTRL_EXC_UNENCRYPTED_POS             0
+
+/* Default MAC Rx filters that cannot be changed by mac80211 */
+#define CL_MAC80211_NOT_CHANGEABLE (            \
+       RX_CNTRL_ACCEPT_QO_S_NULL_BIT         | \
+       RX_CNTRL_ACCEPT_Q_DATA_BIT            | \
+       RX_CNTRL_ACCEPT_DATA_BIT              | \
+       RX_CNTRL_ACCEPT_OTHER_MGMT_FRAMES_BIT | \
+       RX_CNTRL_ACCEPT_MY_UNICAST_BIT        | \
+       RX_CNTRL_ACCEPT_BROADCAST_BIT         | \
+       RX_CNTRL_ACCEPT_BEACON_BIT            | \
+       RX_CNTRL_ACCEPT_PROBE_RESP_BIT          \
+       )
+
+u32 cl_rx_filter_update_flags(struct cl_hw *cl_hw, u32 filter);
+void cl_rx_filter_restore_flags(struct cl_hw *cl_hw);
+void cl_rx_filter_set_promiscuous_off(unsigned long data);
+void cl_rx_filter_set_promiscuous(struct cl_hw *cl_hw);
+
+#endif /* CL_RX_FILTER_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.
________________________________


^ permalink raw reply related	[flat|nested] 262+ messages in thread

* [RFC v1 178/256] cl8k: add rx/rx_reorder.c
  2021-06-17 15:58 [RFC v1 000/256] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (176 preceding siblings ...)
  2021-06-17 16:01 ` [RFC v1 177/256] cl8k: add rx/rx_filter.h viktor.barna
@ 2021-06-17 16:01 ` viktor.barna
  2021-06-17 16:01 ` [RFC v1 179/256] cl8k: add rx/rx_reorder.h viktor.barna
                   ` (79 subsequent siblings)
  257 siblings, 0 replies; 262+ messages in thread
From: viktor.barna @ 2021-06-17 16:01 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Oleksandr Savchenko, Shay Bar, Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

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

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 .../net/wireless/celeno/cl8k/rx/rx_reorder.c  | 335 ++++++++++++++++++
 1 file changed, 335 insertions(+)
 create mode 100644 drivers/net/wireless/celeno/cl8k/rx/rx_reorder.c

diff --git a/drivers/net/wireless/celeno/cl8k/rx/rx_reorder.c b/drivers/net/wireless/celeno/cl8k/rx/rx_reorder.c
new file mode 100644
index 000000000000..7a5c38369d2e
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/rx/rx_reorder.c
@@ -0,0 +1,335 @@
+// SPDX-License-Identifier: MIT
+/* Copyright(c) 2019-2021, Celeno Communications Ltd. */
+
+#include "rx_reorder.h"
+#include "sta.h"
+#include "utils/utils.h"
+
+#define REORDER_BUF_TIMEOUT (HZ / 10)
+
+static bool cl_rx_reorder_ready(struct cl_tid_ampdu_rx *tid_agg_rx, u8 index)
+{
+       struct sk_buff_head *frames = &tid_agg_rx->reorder_buf[index];
+       struct sk_buff *tail = skb_peek_tail(frames);
+       struct ieee80211_rx_status *status;
+
+       if (tid_agg_rx->reorder_buf_filtered & BIT_ULL(index))
+               return true;
+
+       if (!tail)
+               return false;
+
+       status = IEEE80211_SKB_RXCB(tail);
+
+       if (status->flag & RX_FLAG_AMSDU_MORE)
+               return false;
+
+       return true;
+}
+
+static void cl_rx_release_reorder_frame(struct cl_tid_ampdu_rx *tid_agg_rx, int index,
+                                       struct sk_buff_head *frames)
+{
+       struct sk_buff_head *skb_list = &tid_agg_rx->reorder_buf[index];
+       struct sk_buff *skb;
+
+       lockdep_assert_held(&tid_agg_rx->reorder_lock);
+
+       if (skb_queue_empty(skb_list))
+               goto no_frame;
+
+       if (!cl_rx_reorder_ready(tid_agg_rx, index)) {
+               __skb_queue_purge(skb_list);
+               goto no_frame;
+       }
+
+       tid_agg_rx->stored_mpdu_num--;
+
+       while ((skb = __skb_dequeue(skb_list)))
+               __skb_queue_tail(frames, skb);
+
+no_frame:
+       tid_agg_rx->reorder_buf_filtered &= ~BIT_ULL(index);
+       tid_agg_rx->head_seq_num = ieee80211_sn_inc(tid_agg_rx->head_seq_num);
+}
+
+static void cl_rx_release_reorder_frames(struct cl_tid_ampdu_rx *tid_agg_rx,
+                                        u16 head_seq_num,
+                                        struct sk_buff_head *frames)
+{
+       int index;
+
+       lockdep_assert_held(&tid_agg_rx->reorder_lock);
+
+       while (ieee80211_sn_less(tid_agg_rx->head_seq_num, head_seq_num)) {
+               index = tid_agg_rx->head_seq_num % tid_agg_rx->buf_size;
+               cl_rx_release_reorder_frame(tid_agg_rx, index, frames);
+       }
+}
+
+static void cl_reorder_release(struct cl_tid_ampdu_rx *tid_agg_rx, struct sk_buff_head *frames)
+{
+       u8 index, i, j;
+
+       lockdep_assert_held(&tid_agg_rx->reorder_lock);
+
+       /* Release buffer until next hole */
+       index = tid_agg_rx->head_seq_num % tid_agg_rx->buf_size;
+       if (!cl_rx_reorder_ready(tid_agg_rx, index) && tid_agg_rx->stored_mpdu_num) {
+               u8 skipped = 1;
+
+               for (j = (index + 1) % tid_agg_rx->buf_size; j != index;
+                    j = (j + 1) % tid_agg_rx->buf_size) {
+                       if (!cl_rx_reorder_ready(tid_agg_rx, j)) {
+                               skipped++;
+                               continue;
+                       }
+                       if (skipped &&
+                           !time_after(jiffies, tid_agg_rx->reorder_time[j] +
+                                       REORDER_BUF_TIMEOUT))
+                               goto set_release_timer;
+
+                       /* Incomplete A-MSDUs */
+                       for (i = (index + 1) % tid_agg_rx->buf_size; i != j;
+                            i = (i + 1) % tid_agg_rx->buf_size) {
+                               __skb_queue_purge(&tid_agg_rx->reorder_buf[i]);
+                       }
+
+                       cl_rx_release_reorder_frame(tid_agg_rx, j, frames);
+
+                       tid_agg_rx->head_seq_num =
+                               (tid_agg_rx->head_seq_num +
+                                skipped) & IEEE80211_SN_MASK;
+                       skipped = 0;
+               }
+       } else {
+               while (cl_rx_reorder_ready(tid_agg_rx, index)) {
+                       cl_rx_release_reorder_frame(tid_agg_rx, index, frames);
+                       index = tid_agg_rx->head_seq_num % tid_agg_rx->buf_size;
+               }
+       }
+
+       if (tid_agg_rx->stored_mpdu_num) {
+               j = tid_agg_rx->head_seq_num % tid_agg_rx->buf_size;
+               index = j;
+               for (; j != (index - 1) % tid_agg_rx->buf_size;
+                    j = (j + 1) % tid_agg_rx->buf_size) {
+                       if (cl_rx_reorder_ready(tid_agg_rx, j))
+                               break;
+               }
+
+ set_release_timer:
+               if (!tid_agg_rx->removed)
+                       cl_timer_rearm_offset(&tid_agg_rx->reorder_timer,
+                                             tid_agg_rx->reorder_time[j]);
+       } else {
+               cl_timer_disable(&tid_agg_rx->reorder_timer);
+       }
+}
+
+static void cl_rx_reorder_release_timeout(unsigned long data)
+{
+       struct cl_tid_ampdu_rx *tid_agg_rx = (struct cl_tid_ampdu_rx *)data;
+       struct sk_buff *skb = NULL;
+       struct cl_hw *cl_hw = NULL;
+       struct ieee80211_sta *sta = NULL;
+       struct sk_buff_head buffer;
+
+       if (!tid_agg_rx)
+               return;
+
+       __skb_queue_head_init(&buffer);
+
+       spin_lock(&tid_agg_rx->reorder_lock);
+
+       cl_hw = tid_agg_rx->cl_hw;
+       sta = tid_agg_rx->sta;
+       cl_reorder_release(tid_agg_rx, &buffer);
+
+       spin_unlock(&tid_agg_rx->reorder_lock);
+
+       while (!skb_queue_empty(&buffer)) {
+               skb = __skb_dequeue(&buffer);
+               ieee80211_rx_napi(cl_hw->hw, sta, skb, NULL);
+       }
+}
+
+static bool cl_rx_manage_reorder_buf(struct cl_tid_ampdu_rx *tid_agg_rx,
+                                    struct sk_buff *skb,
+                                    struct sk_buff_head *ordered_mpdu)
+{
+       struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
+       struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);
+       u16 sc = le16_to_cpu(hdr->seq_ctrl);
+       u16 mpdu_seq_num = (sc & IEEE80211_SCTL_SEQ) >> 4;
+       u16 head_seq_num, buf_size;
+       u8 index;
+       bool ret = true;
+
+       if (unlikely(tid_agg_rx->auto_seq)) {
+               tid_agg_rx->auto_seq = false;
+               tid_agg_rx->ssn = mpdu_seq_num;
+               tid_agg_rx->head_seq_num = mpdu_seq_num;
+       }
+
+       buf_size = tid_agg_rx->buf_size;
+       head_seq_num = tid_agg_rx->head_seq_num;
+
+       /* Current SN is smaller than the SSN */
+       if (unlikely(!tid_agg_rx->started)) {
+               if (ieee80211_sn_less(mpdu_seq_num, head_seq_num)) {
+                       ret = false;
+                       goto out;
+               }
+               tid_agg_rx->started = true;
+       }
+
+       /* Out of date sequence number */
+       if (ieee80211_sn_less(mpdu_seq_num, head_seq_num)) {
+               dev_kfree_skb(skb);
+               goto out;
+       }
+
+       /* SN exceeds buffer window */
+       if (!ieee80211_sn_less(mpdu_seq_num, head_seq_num + buf_size)) {
+               head_seq_num = ieee80211_sn_inc(ieee80211_sn_sub(mpdu_seq_num, buf_size));
+               cl_rx_release_reorder_frames(tid_agg_rx, head_seq_num, ordered_mpdu);
+       }
+
+       index = mpdu_seq_num % tid_agg_rx->buf_size;
+
+       /* Frame already stored */
+       if (cl_rx_reorder_ready(tid_agg_rx, index)) {
+               dev_kfree_skb(skb);
+               goto out;
+       }
+
+       if (mpdu_seq_num == tid_agg_rx->head_seq_num &&
+           tid_agg_rx->stored_mpdu_num == 0) {
+               if (!(status->flag & RX_FLAG_AMSDU_MORE)) {
+                       tid_agg_rx->head_seq_num =
+                               ieee80211_sn_inc(tid_agg_rx->head_seq_num);
+               }
+               ret = false;
+               goto out;
+       }
+
+       /* Insert frame into reorder buffer */
+       __skb_queue_tail(&tid_agg_rx->reorder_buf[index], skb);
+       if (!(status->flag & RX_FLAG_AMSDU_MORE)) {
+               tid_agg_rx->reorder_time[index] = jiffies;
+               tid_agg_rx->stored_mpdu_num++;
+               cl_reorder_release(tid_agg_rx, ordered_mpdu);
+       }
+
+ out:
+       return ret;
+}
+
+void cl_rx_reorder_ampdu(struct cl_hw *cl_hw, struct cl_sta *cl_sta,
+                        struct sk_buff *skb, struct sk_buff_head *ordered_mpdu)
+{
+       struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
+       struct cl_tid_ampdu_rx *tid_agg_rx;
+       u8 tid, ack_policy;
+
+       if (!cl_sta)
+               return;
+
+       ack_policy = *ieee80211_get_qos_ctl(hdr) &
+                    IEEE80211_QOS_CTL_ACK_POLICY_MASK;
+       tid = ieee80211_get_tid(hdr);
+
+       tid_agg_rx = cl_sta->tid_agg_rx[tid];
+       if (!tid_agg_rx)
+               return;
+
+       spin_lock(&tid_agg_rx->reorder_lock);
+       if (!ieee80211_is_data_qos(hdr->frame_control) ||
+           is_multicast_ether_addr(hdr->addr1))
+               goto dont_reorder;
+
+       if (unlikely(hdr->frame_control & cpu_to_le16(IEEE80211_STYPE_NULLFUNC)))
+               goto dont_reorder;
+
+       if (ack_policy != IEEE80211_QOS_CTL_ACK_POLICY_BLOCKACK &&
+           ack_policy != IEEE80211_QOS_CTL_ACK_POLICY_NORMAL)
+               goto dont_reorder;
+
+       /* Ignore EAPOL frames */
+       if (cl_is_eapol(skb))
+               goto dont_reorder;
+
+       if (cl_rx_manage_reorder_buf(tid_agg_rx, skb, ordered_mpdu)) {
+               spin_unlock(&tid_agg_rx->reorder_lock);
+               return;
+       }
+
+ dont_reorder:
+       spin_unlock(&tid_agg_rx->reorder_lock);
+       __skb_queue_tail(ordered_mpdu, skb);
+}
+
+void cl_rx_reorder_close(struct cl_sta *cl_sta, u8 tid)
+{
+       struct cl_tid_ampdu_rx *tid_agg_rx = cl_sta->tid_agg_rx[tid];
+       u16 i;
+
+       spin_lock_bh(&tid_agg_rx->reorder_lock);
+       tid_agg_rx->removed = true;
+       spin_unlock_bh(&tid_agg_rx->reorder_lock);
+
+       cl_timer_disable_sync(&tid_agg_rx->reorder_timer);
+
+       spin_lock_bh(&tid_agg_rx->reorder_lock);
+       for (i = 0; i < tid_agg_rx->buf_size; i++)
+               __skb_queue_purge(&tid_agg_rx->reorder_buf[i]);
+
+       kfree(tid_agg_rx->reorder_buf);
+       kfree(tid_agg_rx->reorder_time);
+       cl_sta->tid_agg_rx[tid] = NULL;
+
+       spin_unlock_bh(&tid_agg_rx->reorder_lock);
+       kfree(tid_agg_rx);
+}
+
+void cl_rx_reorder_init(struct cl_hw *cl_hw, struct cl_sta *cl_sta, u8 tid, u16 buf_size)
+{
+       struct cl_tid_ampdu_rx *tid_agg_rx;
+       u16 i;
+
+       tid_agg_rx = kzalloc(sizeof(*tid_agg_rx), GFP_KERNEL);
+       if (!tid_agg_rx)
+               return;
+
+       spin_lock_init(&tid_agg_rx->reorder_lock);
+
+       cl_timer_init(&tid_agg_rx->reorder_timer, cl_rx_reorder_release_timeout,
+                     (unsigned long)tid_agg_rx, REORDER_BUF_TIMEOUT + 1, false);
+
+       tid_agg_rx->reorder_buf =
+               kcalloc(buf_size, sizeof(struct sk_buff_head), GFP_KERNEL);
+       tid_agg_rx->reorder_time =
+               kcalloc(buf_size, sizeof(unsigned long), GFP_KERNEL);
+       if (!tid_agg_rx->reorder_buf || !tid_agg_rx->reorder_time) {
+               pr_err("Allocation failed!\n");
+               kfree(tid_agg_rx->reorder_buf);
+               kfree(tid_agg_rx->reorder_time);
+               return;
+       }
+
+       for (i = 0; i < buf_size; i++)
+               __skb_queue_head_init(&tid_agg_rx->reorder_buf[i]);
+
+       tid_agg_rx->ssn = 0;
+       tid_agg_rx->head_seq_num = 0;
+       tid_agg_rx->buf_size = buf_size;
+       tid_agg_rx->stored_mpdu_num = 0;
+       tid_agg_rx->auto_seq = 0;
+       tid_agg_rx->started = false;
+       tid_agg_rx->reorder_buf_filtered = 0;
+       tid_agg_rx->tid = tid;
+       tid_agg_rx->sta = &cl_sta->stainfo->sta;
+       tid_agg_rx->cl_hw = cl_hw;
+       cl_sta->tid_agg_rx[tid] = tid_agg_rx;
+}
--
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.
________________________________


^ permalink raw reply related	[flat|nested] 262+ messages in thread

* [RFC v1 179/256] cl8k: add rx/rx_reorder.h
  2021-06-17 15:58 [RFC v1 000/256] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (177 preceding siblings ...)
  2021-06-17 16:01 ` [RFC v1 178/256] cl8k: add rx/rx_reorder.c viktor.barna
@ 2021-06-17 16:01 ` viktor.barna
  2021-06-17 16:01 ` [RFC v1 180/256] cl8k: add sounding.c viktor.barna
                   ` (78 subsequent siblings)
  257 siblings, 0 replies; 262+ messages in thread
From: viktor.barna @ 2021-06-17 16:01 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Oleksandr Savchenko, Shay Bar, Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

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

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 drivers/net/wireless/celeno/cl8k/rx/rx_reorder.h | 14 ++++++++++++++
 1 file changed, 14 insertions(+)
 create mode 100644 drivers/net/wireless/celeno/cl8k/rx/rx_reorder.h

diff --git a/drivers/net/wireless/celeno/cl8k/rx/rx_reorder.h b/drivers/net/wireless/celeno/cl8k/rx/rx_reorder.h
new file mode 100644
index 000000000000..7fa98236c1ff
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/rx/rx_reorder.h
@@ -0,0 +1,14 @@
+/* SPDX-License-Identifier: MIT */
+/* Copyright(c) 2019-2021, Celeno Communications Ltd. */
+
+#ifndef CL_RX_REORDER_H
+#define CL_RX_REORDER_H
+
+#include "hw.h"
+
+void cl_rx_reorder_ampdu(struct cl_hw *cl_hw, struct cl_sta *cl_sta,
+                        struct sk_buff *skb, struct sk_buff_head *ordered_mpdu);
+void cl_rx_reorder_close(struct cl_sta *cl_sta, u8 tid);
+void cl_rx_reorder_init(struct cl_hw *cl_hw, struct cl_sta *cl_sta, u8 tid, u16 buf_size);
+
+#endif /* CL_RX_REORDER_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.
________________________________


^ permalink raw reply related	[flat|nested] 262+ messages in thread

* [RFC v1 180/256] cl8k: add sounding.c
  2021-06-17 15:58 [RFC v1 000/256] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (178 preceding siblings ...)
  2021-06-17 16:01 ` [RFC v1 179/256] cl8k: add rx/rx_reorder.h viktor.barna
@ 2021-06-17 16:01 ` viktor.barna
  2021-06-17 16:01 ` [RFC v1 181/256] cl8k: add sounding.h viktor.barna
                   ` (77 subsequent siblings)
  257 siblings, 0 replies; 262+ messages in thread
From: viktor.barna @ 2021-06-17 16:01 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Oleksandr Savchenko, Shay Bar, Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

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

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 drivers/net/wireless/celeno/cl8k/sounding.c | 1432 +++++++++++++++++++
 1 file changed, 1432 insertions(+)
 create mode 100644 drivers/net/wireless/celeno/cl8k/sounding.c

diff --git a/drivers/net/wireless/celeno/cl8k/sounding.c b/drivers/net/wireless/celeno/cl8k/sounding.c
new file mode 100644
index 000000000000..a51348eacbe7
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/sounding.c
@@ -0,0 +1,1432 @@
+// SPDX-License-Identifier: MIT
+/* Copyright(c) 2019-2021, Celeno Communications Ltd. */
+
+#include "sounding.h"
+#include "fw/msg_tx.h"
+#include "debug.h"
+#include "bf.h"
+#include "chip.h"
+#include "band.h"
+#include "recovery.h"
+
+#define DBG_PREFIX_MAX_LENGTH 64
+#define sounding_pr(level, format, ...) \
+       do { \
+               if ((level) <= cl_hw->sounding.dbg_level) { \
+                       char __dbg_prefix[DBG_PREFIX_MAX_LENGTH] = {0}; \
+                       if ((level) >= DBG_LVL_TRACE) \
+                               snprintf(__dbg_prefix, DBG_PREFIX_MAX_LENGTH, "[%s][%d]", \
+                                        __func__, __LINE__); \
+                       pr_debug("%s [Sounding] " format, __dbg_prefix, ##__VA_ARGS__); \
+               } \
+       } while (0)
+
+#define sounding_pr_verbose(...) sounding_pr(DBG_LVL_VERBOSE, ##__VA_ARGS__)
+#define sounding_pr_err(...)     sounding_pr(DBG_LVL_ERROR, ##__VA_ARGS__)
+#define sounding_pr_warn(...)    sounding_pr(DBG_LVL_WARNING, ##__VA_ARGS__)
+#define sounding_pr_trace(...)   sounding_pr(DBG_LVL_TRACE, ##__VA_ARGS__)
+#define sounding_pr_info(...)    sounding_pr(DBG_LVL_INFO, ##__VA_ARGS__)
+
+#define CL_SOUNDING_TYPE_2_STR(type) ((type) == SOUNDING_TYPE_HE_SU ? "HE_SU" : \
+                                     (type) == SOUNDING_TYPE_HE_SU_TB ? "HE_SU_TB" : \
+                                     (type) == SOUNDING_TYPE_VHT_SU ? "VHT_SU" : \
+                                     (type) == SOUNDING_TYPE_HE_CQI ? "HE_CQI" : \
+                                     (type) == SOUNDING_TYPE_HE_CQI_TB ? "HE_CQI_TB" :\
+                                     (type) == SOUNDING_TYPE_HE_MU ? "HE_MU" : \
+                                     (type) == SOUNDING_TYPE_VHT_MU ? "VHT_MU" : "INVALID")
+
+#define CL_SOUNDING_ALL_STA          0xff
+#define CL_SOUNDING_LIFETIME_MAX     4095
+#define CL_SOUNDING_LIFETIME_FACTOR  5
+#define CL_SOUNDING_V_MATRIX_PADDING 32
+#define V_MATRIX_MAC_OVERHEAD        41
+#define Q_MATRIX_BITMAP_MASK         0xf
+
+enum cl_sounding_feedback_type {
+       CL_SOUNDING_FEEDBACK_TYPE_SU = 0,
+       CL_SOUNDING_FEEDBACK_TYPE_MU,
+};
+
+enum cl_sounding_ng {
+       CL_SOUNDING_NG_4 = 0,
+       CL_SOUNDING_NG_16,
+       CL_SOUNDING_NG_MAX
+};
+
+struct sounding_work_data {
+       struct work_struct  work;
+       struct cl_hw *cl_hw;
+       bool start;
+       bool is_recovery;
+       struct cl_sounding_info *elem; /* For stop and recovery cases */
+       enum sounding_type sounding_type;
+       u8 gid;
+       u8 sta_num;
+       u8 bw;
+       u8 q_matrix_bitmap;
+       u8 sta_indices[CL_MU_MAX_STA_PER_GROUP];
+};
+
+static u16 ng_bw_to_nsc[CL_SOUNDING_NG_MAX][CHNL_BW_MAX_HE] = {
+       {64, 122, 250, 500},
+       {20, 32, 64, 128}
+};
+
+static int cl_sounding_check_response(struct cl_hw *cl_hw, u8 param_err)
+{
+       int ret = -1;
+
+       switch (param_err) {
+       case CL_SOUNDING_RSP_OK:
+               sounding_pr_trace("param OK!\n");
+               ret = 0;
+               break;
+       case CL_SOUNDING_RSP_ERR_RLIMIT:
+               sounding_pr_err("error, resource limit reached\n");
+               break;
+       case CL_SOUNDING_RSP_ERR_BW:
+               sounding_pr_err("error, unsupported BW tx requested\n");
+               break;
+       case CL_SOUNDING_RSP_ERR_NSS:
+               sounding_pr_err("error, unsupported ndp NSS tx requested\n");
+               break;
+       case CL_SOUNDING_RSP_ERR_INTERVAL:
+               sounding_pr_err("error, interval value is invalid\n");
+               break;
+       case CL_SOUNDING_RSP_ERR_ALREADY:
+               sounding_pr_err("error, station already associated/disassociated with sounding\n");
+               break;
+       case CL_SOUNDING_RSP_ERR_STA:
+               sounding_pr_err("error, station is inactive/active\n");
+               break;
+       case CL_SOUNDING_RSP_ERR_TYPE:
+               sounding_pr_err("error, invalid sounding type\n");
+               break;
+       default:
+               sounding_pr_err("error status unknown, BUG\n");
+               break;
+       }
+
+       return ret;
+}
+
+static u32 cl_sounding_get_lifetime(struct cl_hw *cl_hw, u32 interval)
+{
+       u32 lifetime = (interval * CL_SOUNDING_LIFETIME_FACTOR) >> 1;
+
+       if (lifetime > CL_SOUNDING_LIFETIME_MAX) {
+               sounding_pr_err("lifetime (%u) exceeds 4095\n", lifetime);
+               lifetime = CL_SOUNDING_LIFETIME_MAX;
+       }
+
+       return lifetime;
+}
+
+static bool cl_sounding_is_sta_ng_16_capable(struct cl_hw *cl_hw, struct cl_sta *cl_sta,
+                                            bool mu_cap)
+{
+       struct ieee80211_sta_he_cap *he_cap = &cl_sta->stainfo->sta.he_cap;
+
+       if (he_cap->has_he) {
+               if (mu_cap)
+                       return (he_cap->he_cap_elem.phy_cap_info[5] &
+                               IEEE80211_HE_PHY_CAP5_NG16_MU_FEEDBACK) ? true : false;
+               else
+                       return (he_cap->he_cap_elem.phy_cap_info[5] &
+                               IEEE80211_HE_PHY_CAP5_NG16_SU_FEEDBACK) ? true : false;
+       }
+
+       return false;
+}
+
+static bool cl_sounding_is_sta_codebook_size_75_capable(struct cl_hw *cl_hw, struct cl_sta *cl_sta)
+{
+       struct ieee80211_sta_he_cap *he_cap = &cl_sta->stainfo->sta.he_cap;
+
+       if (he_cap->has_he)
+               return (he_cap->he_cap_elem.phy_cap_info[6] &
+                       IEEE80211_HE_PHY_CAP6_CODEBOOK_SIZE_75_MU) ? true : false;
+
+       return false;
+}
+
+static void cl_sounding_extract_ng_cb_size(struct cl_hw *cl_hw, u8 fb_type_ng_cb_size,
+                                          enum cl_sounding_ng *ng, u8 *phi_psi_sum)
+{
+       enum cl_sounding_feedback_type fb_type =
+               SOUNDING_FEEDBACK_TYPE_VAL(fb_type_ng_cb_size);
+       u8 cb_size = SOUNDING_CODEBOOK_SIZE_VAL(fb_type_ng_cb_size);
+
+       *ng = SOUNDING_NG_VAL(fb_type_ng_cb_size);
+
+       switch (fb_type) {
+       case CL_SOUNDING_FEEDBACK_TYPE_SU:
+               *phi_psi_sum = (cb_size ? 10 : 6);
+               break;
+       case CL_SOUNDING_FEEDBACK_TYPE_MU:
+               *phi_psi_sum = (cb_size ? 16 : 12);
+               break;
+       default:
+               sounding_pr_err("Invalid feedback_type %d\n", fb_type);
+               break;
+       }
+}
+
+static u32 cl_sounding_get_v_matrix_size(struct cl_hw *cl_hw, u8 sta_idx, u8 bw, u8 nc, u8 nr,
+                                        u8 fb_type_ng_cb_size)
+{
+       enum cl_sounding_ng ng = 0;
+       u8 phi_psi_sum = 0;
+       u8 nsc;
+       u32 v_size;
+
+       cl_sounding_extract_ng_cb_size(cl_hw, fb_type_ng_cb_size, &ng, &phi_psi_sum);
+       nsc = ng_bw_to_nsc[ng][bw];
+
+       /* NC and NR should start from 1 and not 0 for the below calculation */
+       nc++;
+       nr++;
+
+       /* v_size = [8*41 + 8*nc + (phi + psi)/2 * nsc*(nc * (2*nr-nc-1))] / 8 + extra padding */
+       v_size = V_MATRIX_MAC_OVERHEAD + nc +
+                    ((phi_psi_sum * nsc * nc * (2 * nr - nc - 1)) >> 4) +
+                    CL_SOUNDING_V_MATRIX_PADDING;
+
+       sounding_pr_info("sta %u, nc %u, nr %u, ng %d, phi_psi_sum %u, nsc %u, v_size %u\n",
+                        sta_idx, nc, nr, ng, phi_psi_sum, nsc, v_size);
+
+       return v_size;
+}
+
+static u32 cl_sounding_get_v_matrices_data_size(struct cl_hw *cl_hw,
+                                               struct sounding_info_per_sta *info_per_sta,
+                                               u8 sta_num, u8 bw, u8 nr)
+{
+       u8 i;
+       u32 v_size = 0;
+
+       for (i = 0; i < sta_num; i++)
+               v_size += cl_sounding_get_v_matrix_size(cl_hw, info_per_sta[i].sta_idx,
+                                                       bw, info_per_sta[i].nc,
+                                                       nr, info_per_sta[i].fb_type_ng_cb_size);
+
+       sounding_pr_info("v_matrices data size %u, sta_num %u\n", v_size, sta_num);
+
+       return v_size;
+}
+
+static u32 cl_sounding_get_q_matrix_size(struct cl_hw *cl_hw,
+                                        const struct sounding_info_per_sta *info_per_sta,
+                                        u8 sta_num, u8 bw, u8 nr)
+{
+       u8 i;
+       u8 nc = 0;
+       enum cl_sounding_ng ng = 0;
+       u8 nsc, phi_psi_sum = 0;
+       u32 q_size = 0;
+
+       /*
+        * NC and NR should start from 1 and not 0 for the below calculation
+        * In MU-MIMO case, when sta_num > 1, we should take the sum of all nc's
+        */
+       for (i = 0; i < sta_num; i++)
+               nc += info_per_sta[i].nc + 1;
+
+       nr++;
+
+       cl_sounding_extract_ng_cb_size(cl_hw, info_per_sta[0].fb_type_ng_cb_size, &ng,
+                                      &phi_psi_sum);
+       nsc = ng_bw_to_nsc[ng][bw];
+       q_size = (nr * nc * nsc) << 2;
+
+       sounding_pr_info("q_matrix size %u, sta_num %u\n", q_size, sta_num);
+
+       return q_size;
+}
+
+static u32 cl_sounding_get_required_xmem_size(struct cl_hw *cl_hw,
+                                             const struct mm_sounding_req *sounding_req,
+                                             const struct sounding_info_per_sta *info_per_sta)
+{
+       u8 i;
+       u8 sta_num = sounding_req->sta_num;
+       u8 q_matrix_bitmap = sounding_req->q_matrix_bitmap;
+       u8 bw = sounding_req->req_txbw;
+       u8 nr = sounding_req->ndp_nsts;
+       u32 total_size = 0;
+
+       /*
+        * In case of MU sounding only one Q matrix is generated.
+        * Otherwise, the number of Q matrices equals to the number of stations
+        */
+       if (sta_num > 1 &&
+           sounding_req->sounding_type != SOUNDING_TYPE_HE_MU &&
+           sounding_req->sounding_type != SOUNDING_TYPE_VHT_MU)
+               for (i = 0; i < sta_num; i++)
+                       total_size +=
+                       cl_sounding_get_q_matrix_size(cl_hw, &info_per_sta[i], 1, bw, nr);
+       else
+               total_size =
+                       cl_sounding_get_q_matrix_size(cl_hw, info_per_sta, sta_num, bw, nr);
+
+       /*
+        * If additional SU Q matrices should be generated - consider them also when calculating
+        * the required XMEM space
+        */
+       if (q_matrix_bitmap) {
+               for (i = 0; i < CL_MU_MIMO_MAX_STA_PER_GRP; i++)
+                       if (q_matrix_bitmap & BIT(i))
+                               total_size +=
+                               cl_sounding_get_q_matrix_size(cl_hw, &info_per_sta[i], 1, bw, nr);
+       }
+
+       return total_size;
+}
+
+static bool cl_sounding_is_enough_xmem_space(struct cl_hw *cl_hw,
+                                            const struct mm_sounding_req *sounding_req,
+                                            const struct sounding_info_per_sta *info_per_sta,
+                                            u32 *required_size)
+{
+       struct cl_xmem *xmem_db = &cl_hw->chip->xmem_db;
+       u32 req_mem = cl_sounding_get_required_xmem_size(cl_hw, sounding_req, info_per_sta);
+
+       if (required_size)
+               *required_size = req_mem;
+
+       return ((xmem_db->size - xmem_db->total_used) >= req_mem);
+}
+
+static void cl_sounding_fill_info_per_sta(struct cl_hw *cl_hw, u8 sounding_type, u8 bw, u8 sta_num,
+                                         struct cl_sta **cl_sta_arr,
+                                         struct sounding_info_per_sta *info_per_sta,
+                                         u8 *n_sts)
+{
+       u8 i;
+       u8 min_sts = cl_hw->num_antennas;
+       struct cl_sta *cl_sta = NULL;
+       u8 mu_fb_type_ng_cb_size = FEEDBACK_TYPE_MU_NG_4_CODEBOOK_SIZE_9_7;
+       u8 curr_fb_type_ng_cb_size;
+       bool should_update_fb_type_ng_cb_size = false;
+
+       for (i = 0; i < sta_num; i++) {
+               cl_sta = cl_sta_arr[i];
+
+               if (!cl_sta)
+                       continue;
+
+               info_per_sta[i].sta_idx = cl_sta->sta_idx;
+               info_per_sta[i].nc = cl_sta->bf_db.nc;
+
+               /* TODO: Add handling of MU-MIMO case. The nc should be taken from the group */
+
+               min_sts = min(min_sts, cl_sta->bf_db.beamformee_sts);
+
+               switch (sounding_type) {
+               case SOUNDING_TYPE_HE_CQI:
+               case SOUNDING_TYPE_HE_SU:
+               case SOUNDING_TYPE_VHT_SU:
+               case SOUNDING_TYPE_VHT_MU:
+                       info_per_sta[i].fb_type_ng_cb_size =
+                               FEEDBACK_TYPE_SU_NG_4_CODEBOOK_SIZE_4_2;
+                       break;
+               case SOUNDING_TYPE_HE_SU_TB:
+                       info_per_sta[i].fb_type_ng_cb_size =
+                               FEEDBACK_TYPE_SU_NG_4_CODEBOOK_SIZE_6_4;
+                       break;
+               case SOUNDING_TYPE_HE_CQI_TB:
+                       info_per_sta[i].fb_type_ng_cb_size =
+                               FEEDBACK_TYPE_CQI_TB;
+                       break;
+               case SOUNDING_TYPE_HE_MU:
+                       if (bw == CHNL_BW_160 &&
+                           info_per_sta[i].nc >= WRS_SS_3 &&
+                           min_sts == MAX_ANTENNAS) {
+                               should_update_fb_type_ng_cb_size = true;
+
+                               if (cl_sounding_is_sta_codebook_size_75_capable(cl_hw, cl_sta)) {
+                                       curr_fb_type_ng_cb_size =
+                                               FEEDBACK_TYPE_MU_NG_4_CODEBOOK_SIZE_7_5;
+                               } else if (cl_sounding_is_sta_ng_16_capable(cl_hw, cl_sta, true)) {
+                                       curr_fb_type_ng_cb_size =
+                                               FEEDBACK_TYPE_MU_NG_16_CODEBOOK_SIZE_9_7;
+                               } else {
+                                       curr_fb_type_ng_cb_size =
+                                               FEEDBACK_TYPE_MU_NG_4_CODEBOOK_SIZE_9_7;
+                                       mu_fb_type_ng_cb_size =
+                                               FEEDBACK_TYPE_MU_NG_4_CODEBOOK_SIZE_9_7;
+                                       min_sts--;
+                               }
+
+                               if ((SOUNDING_NG_VAL(curr_fb_type_ng_cb_size) >
+                                                       SOUNDING_NG_VAL(mu_fb_type_ng_cb_size)) ||
+                                   (SOUNDING_CODEBOOK_SIZE_VAL(curr_fb_type_ng_cb_size) <
+                                    SOUNDING_CODEBOOK_SIZE_VAL(mu_fb_type_ng_cb_size)))
+                                       mu_fb_type_ng_cb_size = curr_fb_type_ng_cb_size;
+                       }
+
+                       info_per_sta[i].fb_type_ng_cb_size = mu_fb_type_ng_cb_size;
+                       break;
+               default:
+                       sounding_pr_trace("Invalid sounding type %u\n", sounding_type);
+                       break;
+               }
+       }
+
+       *n_sts = min_sts;
+
+       if (should_update_fb_type_ng_cb_size)
+               for (i = 0; i < sta_num; i++)
+                       info_per_sta[i].fb_type_ng_cb_size = mu_fb_type_ng_cb_size;
+}
+
+struct cl_sounding_info *cl_sounding_elem_alloc(struct cl_hw *cl_hw, u32 v_mat_len)
+{
+       struct cl_sounding_info *elem = NULL;
+       dma_addr_t phys_dma_addr;
+       struct v_matrix_header *buf = NULL;
+
+       elem = kzalloc(sizeof(*elem), GFP_KERNEL);
+
+       if (!elem) {
+               CL_DBG(cl_hw, DBG_LVL_ERROR, "kzalloc failed\n");
+               return NULL;
+       }
+
+       buf = dma_alloc_coherent(cl_hw->chip->dev, v_mat_len, &phys_dma_addr, GFP_KERNEL);
+
+       if (!buf) {
+               CL_DBG(cl_hw, DBG_LVL_ERROR, "dma_alloc_coherent failed. size=%u\n", v_mat_len);
+               kfree(elem);
+               return NULL;
+       }
+
+       elem->v_matrices_data = buf;
+       elem->v_matrices_dma_addr = phys_dma_addr;
+       elem->v_matrices_data_len = v_mat_len;
+
+       return elem;
+}
+
+void cl_sounding_elem_free(struct cl_hw *cl_hw, struct cl_sounding_info *elem)
+{
+       struct v_matrix_header *v_data = elem->v_matrices_data;
+
+       if (v_data) {
+               dma_free_coherent(cl_hw->chip->dev, elem->v_matrices_data_len, (void *)v_data,
+                                 elem->v_matrices_dma_addr);
+       } else {
+               sounding_pr_err("%s: v_matrices_data is NULL for sid %u\n",
+                               __func__, elem->sounding_id);
+       }
+
+       elem->v_matrices_data = NULL;
+       kfree(elem);
+}
+
+void cl_sounding_req_success(struct cl_hw *cl_hw, struct cl_sounding_info *elem)
+{
+       if (!elem->gid)
+               cl_bf_sounding_req_success(cl_hw, elem);
+}
+
+void cl_sounding_req_failure(struct cl_hw *cl_hw, struct cl_sounding_info *elem)
+{
+       if (!elem->gid)
+               cl_bf_sounding_req_failure(cl_hw, elem);
+}
+
+static void cl_sounding_increase_num_profiles(struct cl_hw *cl_hw, u8 sounding_type, u8 sta_num)
+{
+       if (SOUNDING_TYPE_IS_CQI(sounding_type))
+               cl_hw->sounding.cqi_profiles += sta_num;
+       else
+               cl_hw->sounding.active_profiles += sta_num;
+}
+
+static void cl_sounding_decrease_num_profiles(struct cl_hw *cl_hw, u8 sounding_type, u8 sta_num)
+{
+       if (SOUNDING_TYPE_IS_CQI(sounding_type))
+               cl_hw->sounding.cqi_profiles -= sta_num;
+       else
+               cl_hw->sounding.active_profiles -= sta_num;
+}
+
+static void _cl_sounding_add(struct cl_hw *cl_hw, struct cl_sounding_info *elem, u8 sounding_id,
+                            u32 req_xmem)
+{
+       write_lock_bh(&cl_hw->sounding.list_lock);
+       elem->sounding_id = sounding_id;
+       elem->xmem_space = req_xmem;
+       cl_hw->chip->xmem_db.total_used += req_xmem;
+       cl_hw->sounding.num_soundings++;
+       list_add_tail(&elem->list, &cl_hw->sounding.head);
+       cl_sounding_increase_num_profiles(cl_hw, elem->type, elem->sta_num);
+       write_unlock_bh(&cl_hw->sounding.list_lock);
+}
+
+static void cl_sounding_remove_from_list(struct cl_hw *cl_hw, struct cl_sounding_info *elem)
+{
+       /* Remove the sounding sequence from the list and update the XMEM and profile counters */
+       write_lock_bh(&cl_hw->sounding.list_lock);
+       list_del(&elem->list);
+       cl_hw->chip->xmem_db.total_used -= elem->xmem_space;
+       cl_hw->sounding.num_soundings--;
+       cl_sounding_decrease_num_profiles(cl_hw, elem->type, elem->sta_num);
+       write_unlock_bh(&cl_hw->sounding.list_lock);
+}
+
+static void cl_sounding_remove_recovery(struct cl_hw *cl_hw, struct cl_sounding_info *elem)
+{
+       u8 i;
+
+       cl_sounding_remove_from_list(cl_hw, elem);
+
+       /* Set invalid sid for all STAs related to this sounding sequence */
+       for (i = 0; i < elem->sta_num; i++) {
+               struct cl_sta *cl_sta = elem->su_cl_sta_arr[i];
+
+               if (cl_sta)
+                       cl_sta->su_sid = INVALID_SID;
+       }
+
+       /* Free the deleted sounding element */
+       cl_sounding_elem_free(cl_hw, elem);
+}
+
+static void cl_sounding_start_handler(struct cl_hw *cl_hw, struct sounding_work_data *data)
+{
+       struct mm_sounding_req sounding_req;
+       struct mm_sounding_cfm *cfm = NULL;
+       int ret = 0;
+       u32 len = 0;
+       u32 req_xmem = 0;
+       struct cl_sounding_info *elem = NULL;
+       u8 sounding_type = data->sounding_type;
+       u8 bw = data->bw;
+       u8 i, sta_num = 0;
+       u8 q_matrix_bitmap = data->q_matrix_bitmap;
+       u8 min_nsts = 0;
+       struct cl_sta *cl_sta_arr[CL_MU_MAX_STA_PER_GROUP] = {0};
+
+       cl_sta_lock_bh(cl_hw);
+
+       for (i = 0; i < data->sta_num; i++) {
+               u8 sta_idx = data->sta_indices[i];
+               struct cl_sta *cl_sta;
+
+               cl_sta = cl_sta_get(cl_hw, sta_idx);
+
+               if (!cl_sta)
+                       continue;
+
+               cl_sta_arr[sta_num] = cl_sta;
+               sta_num++;
+       }
+
+       if (!sta_num) {
+               cl_sta_unlock_bh(cl_hw);
+               sounding_pr_err("%s: No STA found!\n", __func__);
+               return;
+       }
+
+       q_matrix_bitmap &= Q_MATRIX_BITMAP_MASK;
+
+       /* Configure sounding request parameters */
+       sounding_req.start = true;
+       sounding_req.sounding_type = sounding_type;
+       sounding_req.req_txbw = bw;
+       sounding_req.sta_num = sta_num;
+       sounding_req.interval = cl_sounding_get_interval(cl_hw);
+       sounding_req.lifetime = cl_sounding_get_lifetime(cl_hw, sounding_req.interval);
+       sounding_req.q_matrix_bitmap = q_matrix_bitmap;
+       cl_sounding_fill_info_per_sta(cl_hw, sounding_type, bw, sta_num, cl_sta_arr,
+                                     sounding_req.info_per_sta, &min_nsts);
+       cl_sta_unlock_bh(cl_hw);
+
+       sounding_req.ndp_nsts = min_nsts;
+
+       if (data->is_recovery) {
+               elem = data->elem;
+       } else {
+               /*
+                * Check if there is enough XMEM space.
+                * Should be called after filling sounding req struct
+                */
+               if (!cl_sounding_is_enough_xmem_space(cl_hw, &sounding_req,
+                                                     sounding_req.info_per_sta, &req_xmem)) {
+                       sounding_pr_err("There is not enough space in XMEM!\n");
+                       return;
+               }
+
+               /* Should be called after filling info per STA */
+               len = cl_sounding_get_v_matrices_data_size(cl_hw, sounding_req.info_per_sta,
+                                                          sta_num, bw, min_nsts);
+               elem = cl_sounding_elem_alloc(cl_hw, len);
+
+               if (!elem)
+                       return;
+
+               elem->type = sounding_type;
+               elem->bw = bw;
+               elem->sta_num = sta_num;
+               elem->q_matrix_bitmap = q_matrix_bitmap;
+
+               if (data->gid)
+                       elem->gid = data->gid;
+               else
+                       memcpy(elem->su_cl_sta_arr, cl_sta_arr,
+                              sta_num * sizeof(cl_sta_arr[0]));
+       }
+
+       sounding_req.host_address = cpu_to_le32(elem->v_matrices_dma_addr);
+
+       /* Print request parameters */
+       sounding_pr_trace("Request: start=%u, bfr_lifetime=%u, interval=%u, "
+                          "req_txbw=%u, ndp_nsts=%u, sounding_type=%u\n",
+                          sounding_req.start,
+                          sounding_req.lifetime,
+                          sounding_req.interval,
+                          sounding_req.req_txbw,
+                          sounding_req.ndp_nsts,
+                          sounding_req.sounding_type);
+
+       /* Send message to firmware */
+       ret = cl_msg_tx_sounding(cl_hw, &sounding_req);
+
+       cfm = cl_hw->msg_cfm_params[MM_SOUNDING_CFM];
+
+       /* Check firmware response */
+       if (ret == 0 && cfm) {
+
+               ret = cl_sounding_check_response(cl_hw, cfm->param_err);
+
+               if (ret == 0) {
+                       if (!data->is_recovery)
+                               _cl_sounding_add(cl_hw, elem, cfm->sounding_id, req_xmem);
+
+                       cl_sounding_req_success(cl_hw, elem);
+
+                       sounding_pr_trace("Sounding %u was enabled successfully\n",
+                                         cfm->sounding_id);
+               } else {
+                       cl_sounding_req_failure(cl_hw, elem);
+
+                       if (data->is_recovery)
+                               cl_sounding_remove_recovery(cl_hw, elem);
+               }
+       } else {
+               sounding_pr_err("%s: failed to send message (%d)\n", __func__, ret);
+               cl_sounding_req_failure(cl_hw, elem);
+
+               if (data->is_recovery)
+                       cl_sounding_remove_recovery(cl_hw, elem);
+               else
+                       cl_sounding_elem_free(cl_hw, elem);
+       }
+
+       /* Free message confirmation */
+       cl_msg_tx_free_cfm_params(cl_hw, MM_SOUNDING_CFM);
+}
+
+static void _cl_sounding_remove(struct cl_hw *cl_hw, struct cl_sounding_info *elem)
+{
+       u8 i;
+       struct sounding_work_data data = {
+               .cl_hw = cl_hw,
+               .bw = elem->bw,
+               .start = true,
+               .is_recovery = false,
+               .sta_num = 0
+       };
+
+       cl_sounding_remove_from_list(cl_hw, elem);
+
+       for (i = 0; i < elem->sta_num; i++) {
+               struct cl_sta *cl_sta = elem->su_cl_sta_arr[i];
+
+               if (!cl_sta)
+                       continue;
+
+               cl_sta->su_sid = INVALID_SID;
+
+               /* After stopping the multi STA sounding - check if a new sounding is needed */
+               if (elem->sounding_restart_required) {
+                       if (!cl_sta->bf_db.sounding_remove_required) {
+                               data.sta_indices[data.sta_num] = cl_sta->sta_idx;
+                               data.sta_num++;
+                       } else {
+                               cl_sta->bf_db.sounding_remove_required = false;
+                       }
+               }
+       }
+
+       /* Start a new sounding for the remaining stations only when needed */
+       if (data.sta_num) {
+               /* Determine new sounding type */
+               if (SOUNDING_TYPE_IS_CQI(elem->type)) {
+                       if (data.sta_num > 1)
+                               data.sounding_type = elem->type;
+                       else
+                               data.sounding_type = SOUNDING_TYPE_HE_CQI;
+               } else if (SOUNDING_TYPE_IS_VHT(elem->type)) {
+                       data.sounding_type = SOUNDING_TYPE_VHT_SU;
+               } else {
+                       if (data.sta_num > 1)
+                               data.sounding_type = SOUNDING_TYPE_HE_SU_TB;
+                       else
+                               data.sounding_type = SOUNDING_TYPE_HE_SU;
+               }
+
+               cl_sounding_start_handler(cl_hw, &data);
+       }
+
+       /* Free the deleted sounding element */
+       cl_sounding_elem_free(cl_hw, elem);
+}
+
+static void cl_sounding_stop_handler(struct cl_hw *cl_hw, struct cl_sounding_info *elem)
+{
+       struct mm_sounding_req sounding_req;
+       int ret = 0;
+
+       if (!elem) {
+               sounding_pr_err("elem is NULL!!\n");
+               return;
+       }
+
+       /* Configure sounding request parameters */
+       sounding_req.start = false;
+       sounding_req.sounding_type = elem->type;
+       sounding_req.sid = elem->sounding_id;
+
+       /* Print request parameters */
+       sounding_pr_trace("Delete request: sid=%u, sounding_type=%u\n",
+                         elem->sounding_id, elem->type);
+
+       /* Send message to firmware */
+       ret = cl_msg_tx_sounding(cl_hw, &sounding_req);
+
+       /* Check firmware response */
+       if (ret)
+               sounding_pr_err("%s: failed to send message (%d)\n", __func__, ret);
+       else
+               /* Free message confirmation */
+               cl_msg_tx_free_cfm_params(cl_hw, MM_SOUNDING_CFM);
+
+       /* Remove the sounding sequence from the list and update the used XMEM counter.
+        * Notice that elem is freed and shouldn't be accessed after the call to this function.
+        */
+       _cl_sounding_remove(cl_hw, elem);
+}
+
+static void cl_sounding_handler_send_request(struct work_struct *work)
+{
+       struct sounding_work_data *data = (struct sounding_work_data *)work;
+       struct cl_hw *cl_hw = data->cl_hw;
+
+       if (data->start) {
+               cl_sounding_start_handler(cl_hw, data);
+       } else {
+               u8 sid;
+               u8 sta_idx = data->sta_indices[0];
+               struct cl_sta *cl_sta;
+
+               cl_sta_lock_bh(cl_hw);
+               cl_sta = cl_sta_get(cl_hw, sta_idx);
+               sid = cl_sta ? cl_sta->su_sid : U8_MAX;
+               cl_sta_unlock_bh(cl_hw);
+
+               if (data->elem)
+                       cl_sounding_stop_handler(cl_hw, data->elem);
+               else
+                       cl_sounding_stop_by_sid(cl_hw, sid, false);
+       }
+
+       kfree(data);
+}
+
+static u16 cl_sounding_calc_interval(struct cl_hw *cl_hw, u8 active_profiles)
+{
+       /* Sounding interval = min interval + [(active_profiles - 1) / STA step] * interval step */
+
+       u16 *coefs = cl_hw->conf->ce_sounding_interval_coefs;
+       u16 min_interval = coefs[SOUNDING_INTERVAL_COEF_MIN_INTERVAL];
+       u16 max_interval = coefs[SOUNDING_INTERVAL_COEF_MAX_INTERVAL];
+       u8 sta_step = coefs[SOUNDING_INTERVAL_COEF_STA_STEP];
+       u8 interval_step = coefs[SOUNDING_INTERVAL_COEF_INTERVAL_STEP];
+       u16 ret = min_interval;
+
+       if (active_profiles <= sta_step)
+               return ret;
+
+       active_profiles--;
+       ret += (active_profiles / sta_step) * interval_step;
+
+       return min(ret, max_interval);
+}
+
+static void cl_sounding_handler_change_interval(struct work_struct *work)
+{
+       struct sounding_work_data *data = (struct sounding_work_data *)work;
+       struct cl_hw *cl_hw = data->cl_hw;
+       struct mm_sounding_interval_cfm *sounding_interval_cfm = NULL;
+       int ret = 0;
+       /* Configure sounding request parameters */
+       u16 interval = cl_sounding_get_interval(cl_hw);
+       u16 lifetime = cl_sounding_get_lifetime(cl_hw, interval);
+
+       sounding_pr_trace("Sounding interval request: sta_idx=%d, interval=%u, "
+                         "lifetime=%u, sounding_type=%u\n",
+                         CL_SOUNDING_ALL_STA, interval, lifetime, data->sounding_type);
+
+       /* Start/Stop synchronize sounding request periodically */
+       ret = cl_msg_tx_sounding_interval(cl_hw, interval, lifetime, data->sounding_type,
+                                         CL_SOUNDING_ALL_STA);
+       sounding_interval_cfm = (struct mm_sounding_interval_cfm *)
+                               (cl_hw->msg_cfm_params[MM_SOUNDING_INTERVAL_CFM]);
+
+       if (ret == 0 && sounding_interval_cfm)
+               cl_sounding_check_response(cl_hw, sounding_interval_cfm->param_err);
+       else
+               sounding_pr_err("%s: failed to send message (%d)\n", __func__, ret);
+
+       cl_msg_tx_free_cfm_params(cl_hw, MM_SOUNDING_INTERVAL_CFM);
+       kfree(data);
+}
+
+static void cl_sounding_recovery_reset(struct cl_hw *cl_hw)
+{
+       struct cl_sounding_db *sounding_db = &cl_hw->sounding;
+
+       memset(sounding_db->active_profiles_prev, 0, sizeof(u8) * CL_SOUNDING_STABILITY_TIME);
+       sounding_db->active_profiles_idx = 0;
+       cl_sta_loop(cl_hw, cl_bf_reset_sounding_ind);
+}
+
+static int cl_sounding_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,
+                "sounding usage\n"
+                "-a: Create a sounding sequence [type].[bw].[gid].[q_matrix_bitmap].[sta_idx 1]"
+                "...[sta_idx n]\n\t* Available types: 0-HE_SU, 1-HE_SU_TB, 2-VHT_SU, 3-HE_CQI, "
+                "4-HE_CQI_TB, 5-HE_MU, 6-VHT_MU\n\t"
+                "* Notice that gid and q_matrix_bitmap should be passed only for MU sounding\n"
+                "-b: Delete a sounding sequence [sounding_id]\n"
+                "-c: Print sounding configuration\n"
+                "-d: Set debug level [0-Off, ..., 4-Highest]\n"
+                "-p: Print sounding db\n"
+                "-s: Simulate sounding indication [sid].[sta_idx (255 in case of MU)]\n");
+
+       err = cl_vendor_reply(cl_hw, ret_buf, strlen(ret_buf));
+       kfree(ret_buf);
+
+       return err;
+}
+
+void cl_sounding_init(struct cl_hw *cl_hw)
+{
+       struct cl_sounding_db *sounding_db = &cl_hw->sounding;
+
+       memset(sounding_db, 0, sizeof(*sounding_db));
+       sounding_db->sounding_wq = create_workqueue("cl_sounding_wq");
+       sounding_db->current_interval =
+               cl_hw->conf->ce_sounding_interval_coefs[SOUNDING_INTERVAL_COEF_MIN_INTERVAL];
+       sounding_db->dbg_level = 1;
+       cl_hw->chip->xmem_db.size = XMEM_SIZE;
+       INIT_LIST_HEAD(&sounding_db->head);
+       rwlock_init(&sounding_db->list_lock);
+}
+
+void cl_sounding_close(struct cl_hw *cl_hw)
+{
+       struct cl_sounding_info *elem, *tmp;
+
+       if (cl_hw->sounding.sounding_wq)
+               destroy_workqueue(cl_hw->sounding.sounding_wq);
+
+       list_for_each_entry_safe(elem, tmp, &cl_hw->sounding.head, list) {
+               /* Don't try to start a new sounding sequence after stopping this one */
+               elem->sounding_restart_required = false;
+               cl_sounding_stop_handler(cl_hw, elem);
+       }
+}
+
+struct cl_sounding_info *cl_sounding_get_elem(struct cl_hw *cl_hw, u8 sounding_id)
+{
+       struct cl_sounding_info *elem = NULL;
+
+       read_lock_bh(&cl_hw->sounding.list_lock);
+
+       list_for_each_entry(elem, &cl_hw->sounding.head, list) {
+               if (elem->sounding_id == sounding_id) {
+                       read_unlock_bh(&cl_hw->sounding.list_lock);
+                       return elem;
+               }
+       }
+
+       read_unlock_bh(&cl_hw->sounding.list_lock);
+
+       return NULL;
+}
+
+void cl_sounding_send_request(struct cl_hw *cl_hw, struct cl_sta **cl_sta_arr,
+                             u8 sta_num, bool enable, u8 sounding_type, u8 bw,
+                             u8 q_matrix_bitmap, struct cl_sounding_info *recovery_elem)
+{
+       struct sounding_work_data *data;
+       struct cl_sounding_info *elem = NULL;
+       u8 i;
+       bool background = (preempt_count() != 0);
+
+       if (!cl_sta_arr) {
+               sounding_pr_err("Sta_indices is NULL! for sounding type %u\n", sounding_type);
+               return;
+       }
+
+       if (cl_band_is_24g(cl_hw) && SOUNDING_TYPE_IS_VHT(sounding_type)) {
+               sounding_pr_err("A VHT sounding type (%u) is not supported in 2.4g band\n",
+                               sounding_type);
+               return;
+       }
+
+       /*
+        * When Multiple STAs are members of a single sounding process, that is about to be stopped,
+        * we want to schedule the stopping work only once and possibly start another sounding
+        * sequence for STAs that still want to use it.
+        */
+       if (!enable) {
+               struct cl_sta *cl_sta = cl_sta_arr[0];
+
+               if (cl_sta) {
+                       u8 sid = cl_sta->su_sid;
+
+                       if (sid != INVALID_SID) {
+                               elem = cl_sounding_get_elem(cl_hw, sid);
+
+                               if (!elem) {
+                                       sounding_pr_trace("Sounding %u not found\n", sid);
+                                       return;
+                               }
+
+                               cl_sta->bf_db.sounding_remove_required = true;
+
+                               if (elem->sounding_restart_required)
+                                       return;
+
+                               elem->sounding_restart_required = true;
+                       }
+               }
+       }
+
+       /* data will be freed in work handler */
+       data = kzalloc(sizeof(*data), GFP_ATOMIC);
+
+       if (!data)
+               return;
+
+       data->cl_hw = cl_hw;
+       data->start = enable;
+       data->sounding_type = sounding_type;
+       data->bw = bw;
+       data->is_recovery = cl_recovery_in_progress(cl_hw);
+       data->elem = recovery_elem ? recovery_elem : elem;
+
+       /* Fill cl_sta_arr */
+       for (i = 0; i < sta_num; i++)
+               data->sta_indices[i] = cl_sta_arr[i]->sta_idx;
+
+       data->sta_num = sta_num;
+
+       if (background) {
+               INIT_WORK(&data->work, cl_sounding_handler_send_request);
+               queue_work(cl_hw->sounding.sounding_wq, &data->work);
+       } else {
+               cl_sounding_handler_send_request((struct work_struct *)data);
+       }
+}
+
+static void cl_sounding_change_interval(struct cl_hw *cl_hw, u8 sounding_type)
+{
+       /* Data will be freed in work handler */
+       struct sounding_work_data *data = kzalloc(sizeof(*data), GFP_ATOMIC);
+
+       if (!data)
+               return;
+
+       INIT_WORK(&data->work, cl_sounding_handler_change_interval);
+       data->cl_hw = cl_hw;
+       data->sounding_type = sounding_type;
+       queue_work(cl_hw->sounding.sounding_wq, &data->work);
+}
+
+u8 cl_sounding_get_active_profiles(struct cl_hw *cl_hw)
+{
+       return cl_hw->sounding.active_profiles;
+}
+
+void cl_sounding_stop_by_sid(struct cl_hw *cl_hw, u8 sid, bool sounding_restart_check)
+{
+       struct cl_sounding_info *elem = cl_sounding_get_elem(cl_hw, sid);
+
+       if (!elem) {
+               sounding_pr_trace("Sounding with id %u not found or is in the middle of removal\n",
+                                 sid);
+               return;
+       }
+
+       elem->sounding_restart_required = sounding_restart_check;
+       cl_sounding_stop_handler(cl_hw, elem);
+}
+
+void cl_sounding_maintenance(struct cl_hw *cl_hw)
+{
+       /*
+        * Change sounding_index according to the number of active_profiles.
+        * sounding_index is modified only if number of active_profiles is stable for 5 seconds.
+        *
+        * Examples:
+        * e.g #1: active_profiles=2, active_profiles_prev=3,3,3,3,3 - stabilised on 3
+        * e.g #3: active_profiles=2, active_profiles_prev=1,1,1,1,1 - stabilised on 1
+        * e.g #2: active_profiles=5, active_profiles_prev=6,7,7,6,6 - stabilised on 6
+        * e.g #4: active_profiles=5, active_profiles_prev=4,3,3,2,4 - stabilised on 4
+        */
+
+       int i = 0;
+       u8 active_profiles_min = 255;
+       u8 active_profiles_max = 0;
+       u8 active_profiles = cl_hw->sounding.last_conf_active_profiles;
+       u8 active_profiles_new = 0;
+       u16 interval;
+       u16 interval_new;
+
+       /* Add to last 5 sec buffer */
+       cl_hw->sounding.active_profiles_prev[cl_hw->sounding.active_profiles_idx] =
+               cl_hw->sounding.active_profiles;
+
+       /* Increase cyclic index */
+       cl_hw->sounding.active_profiles_idx++;
+       if (cl_hw->sounding.active_profiles_idx == CL_SOUNDING_STABILITY_TIME)
+               cl_hw->sounding.active_profiles_idx = 0;
+
+       /* Find active_profiles min/max in last 5 seconds */
+       for (i = 0; i < CL_SOUNDING_STABILITY_TIME; i++) {
+               if (cl_hw->sounding.active_profiles_prev[i] < active_profiles_min)
+                       active_profiles_min = cl_hw->sounding.active_profiles_prev[i];
+
+               if (cl_hw->sounding.active_profiles_prev[i] > active_profiles_max)
+                       active_profiles_max = cl_hw->sounding.active_profiles_prev[i];
+       }
+
+       if (active_profiles < active_profiles_min)
+               active_profiles_new = active_profiles_min;
+       else if (active_profiles > active_profiles_max)
+               active_profiles_new = active_profiles_max;
+       else /* Active_profiles in last 5 seconds did not change or is not stable */
+               return;
+
+       interval = cl_sounding_calc_interval(cl_hw, active_profiles);
+       interval_new = cl_sounding_calc_interval(cl_hw, active_profiles_new);
+
+       /* Check if sounding interval changed */
+       if (interval != interval_new) {
+               cl_hw->sounding.last_conf_active_profiles = active_profiles_new;
+               cl_hw->sounding.current_interval = interval_new;
+               cl_sounding_change_interval(cl_hw, SOUNDING_TYPE_MAX);
+               sounding_pr_trace("Interval: current = %u, new = %u\n",
+                                 interval, interval_new);
+       }
+}
+
+u16 cl_sounding_get_interval(struct cl_hw *cl_hw)
+{
+       return cl_hw->sounding.current_interval;
+}
+
+static void cl_sounding_indication_pr(struct cl_hw *cl_hw,
+                                     struct mm_sounding_ind *ind,
+                                     struct v_matrix_header *v_matrix,
+                                     u8 *avg_snr)
+{
+       sounding_pr_info("Sounding indication: nc index = %u, BFR BW = %u, "
+                 "SNR1 = %u, SNR2 = %u, SNR3 = %u, SNR4 = %u, SNR5 = %u, SNR6 = %u,"
+                 "feedback type = %u, sta index = %u\n",
+                 v_matrix->nc_index, v_matrix->bw,
+                 avg_snr[0], avg_snr[1], avg_snr[2], avg_snr[3], avg_snr[4],
+                 avg_snr[5], ind->sounding_type, ind->sta_idx);
+}
+
+static void cl_sounding_indication_su(struct cl_hw *cl_hw,
+                                     struct mm_sounding_ind *ind,
+                                     struct cl_sounding_info *sounding_elem)
+{
+       struct cl_sta *cl_sta;
+       struct v_matrix_header *v_matrix = NULL;
+       u8 *avg_snr = NULL;
+       bool pairing = false;
+
+       v_matrix = sounding_elem->v_matrices_data + ind->v_matrix_offset[0];
+       avg_snr = (u8 *)v_matrix + v_matrix->padding;
+
+       cl_sta_lock(cl_hw);
+       cl_sta = cl_sta_get(cl_hw, ind->sta_idx);
+
+       if (cl_sta) {
+               struct cl_bf_sta_db *bf_db = &cl_sta->bf_db;
+
+               /* Update Nc for the current STA */
+               bf_db->nc = v_matrix->nc_index;
+               bf_db->sounding_indications++;
+
+               if (bf_db->sounding_indications == 1) {
+                       /*
+                        * After getting first indication disable the timer and set the BF
+                        * bit in the firmware rate flags.
+                        */
+                       cl_timer_disable(&bf_db->timer);
+                       cl_bf_update_rate(cl_hw, cl_sta);
+                       pairing = true;
+               }
+       }
+
+       cl_sta_unlock(cl_hw);
+
+       /* Send a msg to fw to pair the STA with sounding ID */
+       if (pairing)
+               cl_msg_tx_sounding_pairing(cl_hw, ind->sid, ind->sounding_type, 0, ind->sta_idx);
+
+       cl_sounding_indication_pr(cl_hw, ind, v_matrix, avg_snr);
+}
+
+void cl_sounding_indication(struct cl_hw *cl_hw, struct mm_sounding_ind *ind)
+{
+       struct cl_sounding_info *sounding_elem = NULL;
+       bool is_mu = false;
+
+       sounding_elem = cl_sounding_get_elem(cl_hw, ind->sid);
+
+       if (!sounding_elem) {
+               sounding_pr_err("[%s]: sounding id %u not found!\n", __func__, ind->sid);
+               return;
+       }
+
+       switch (ind->sounding_type) {
+       case SOUNDING_TYPE_HE_SU:
+       case SOUNDING_TYPE_HE_SU_TB:
+       case SOUNDING_TYPE_VHT_SU:
+       case SOUNDING_TYPE_HE_CQI:
+       case SOUNDING_TYPE_HE_CQI_TB:
+               is_mu = false;
+               break;
+       case SOUNDING_TYPE_HE_MU:
+               is_mu = ind->mu;
+               break;
+       case SOUNDING_TYPE_VHT_MU:
+               is_mu = true;
+               break;
+       default:
+               sounding_pr_err("[%s]: Invalid sounding type %u\n", __func__,
+                               ind->sounding_type);
+               return;
+       }
+
+       cl_sounding_indication_su(cl_hw, ind, sounding_elem);
+}
+
+void cl_sounding_recovery(struct cl_hw *cl_hw)
+{
+       /*
+        * After recovery process we need to update sounding requests and
+        * sounding interval in firmware
+        */
+       struct cl_sounding_info *elem;
+
+       /* No sounding is active */
+       if (!cl_hw->sounding.num_soundings)
+               return;
+
+       /* Reset sounding parameters */
+       cl_sounding_recovery_reset(cl_hw);
+
+       /*
+        * Go over all clients that had sounding before recovery,
+        * and send a new sounding request to firmware.
+        */
+
+       sounding_pr_trace("Start sounding recovery\n");
+
+       list_for_each_entry(elem, &cl_hw->sounding.head, list)
+               cl_bf_sounding_start(cl_hw, elem->type, elem->su_cl_sta_arr, elem->sta_num, elem);
+}
+
+int cl_sounding_cli_create(struct cl_hw *cl_hw, struct cli_params *cli_params)
+{
+       u8 i;
+       u8 max_sta_params = 0;
+       u8 curr_param_idx = 0;
+       bool is_mu = false;
+       struct sounding_work_data *data = NULL;
+       int err = 0;
+
+       /* parameters extraction and validity checks */
+       if (cli_params->num_params < 4) {
+               sounding_pr_err("Too few parameters..\n");
+               return -EIO;
+       }
+
+       data = kzalloc(sizeof(*data), GFP_KERNEL);
+
+       if (!data)
+               return -ENOMEM;
+
+       data->sounding_type = (u8)cli_params->params[curr_param_idx++];
+       data->bw = (u8)cli_params->params[curr_param_idx++];
+       data->gid = (u8)cli_params->params[curr_param_idx++];
+       data->q_matrix_bitmap = (u8)cli_params->params[curr_param_idx++];
+
+       if (cl_band_is_24g(cl_hw) && SOUNDING_TYPE_IS_VHT(data->sounding_type)) {
+               sounding_pr_err("A VHT sounding type (%u) is not supported in 2.4g band\n",
+                               data->sounding_type);
+               err = -EIO;
+               goto out_err;
+       }
+
+       switch (data->sounding_type) {
+       case SOUNDING_TYPE_VHT_SU:
+       case SOUNDING_TYPE_HE_CQI:
+       case SOUNDING_TYPE_HE_SU:
+               max_sta_params = 1;
+               break;
+       case SOUNDING_TYPE_HE_SU_TB:
+       case SOUNDING_TYPE_HE_CQI_TB:
+               max_sta_params = CL_MU_OFDMA_MAX_STA_PER_GRP;
+               break;
+       case SOUNDING_TYPE_VHT_MU:
+       case SOUNDING_TYPE_HE_MU:
+               max_sta_params = 0;
+               is_mu = true;
+               break;
+       default:
+               sounding_pr_err("Invalid sounding type %u\n", data->sounding_type);
+               err = -EIO;
+               goto out_err;
+       }
+
+       if (cli_params->num_params > (curr_param_idx + max_sta_params)) {
+               sounding_pr_err("Too many parameters..\n");
+               err = -EIO;
+               goto out_err;
+       }
+
+       /* SU case */
+       struct cl_sta *cl_sta;
+
+       if (data->gid || data->q_matrix_bitmap) {
+               sounding_pr_err("Don't insert gid or q_matrix_bitmap != 0 for SU types\n");
+               err = -EIO;
+               goto out_err;
+       }
+
+       if (cli_params->num_params < curr_param_idx + 1) {
+               sounding_pr_err("For SU sounding types at least 1 STA idx is required\n");
+               err = -EIO;
+               goto out_err;
+       }
+
+       /* Fill cl_sta_arr */
+       for (i = 0;
+            curr_param_idx < cli_params->num_params; curr_param_idx++, i++) {
+               u8 sta_idx = (u8)cli_params->params[curr_param_idx];
+
+               cl_sta_lock_bh(cl_hw);
+               cl_sta = cl_sta_get(cl_hw, sta_idx);
+
+               if (!cl_sta || cl_sta->su_sid != INVALID_SID) {
+                       if (!cl_sta)
+                               sounding_pr_err("Invalid STA index %u\n", sta_idx);
+                       else
+                               sounding_pr_err("STA %u already associated with sid %u\n",
+                                               cl_sta->sta_idx, cl_sta->su_sid);
+                       cl_sta_unlock_bh(cl_hw);
+                       err = -EIO;
+                       goto out_err;
+               }
+
+               data->sta_indices[i] = cl_sta->sta_idx;
+               cl_sta_unlock_bh(cl_hw);
+       }
+
+       data->sta_num = i;
+
+       /* Start the new sounding sequence */
+       cl_sounding_start_handler(cl_hw, data);
+
+out_err:
+       kfree(data);
+       return err;
+}
+
+void cl_sounding_cli_print_configuration(struct cl_hw *cl_hw)
+{
+       struct cl_tcv_conf *conf = cl_hw->conf;
+
+       pr_debug("Min sounding interval:      %u\n",
+                conf->ce_sounding_interval_coefs[SOUNDING_INTERVAL_COEF_MIN_INTERVAL]);
+       pr_debug("Sounding interval STA step: %u\n",
+                conf->ce_sounding_interval_coefs[SOUNDING_INTERVAL_COEF_STA_STEP]);
+       pr_debug("Sounding interval step:     %u\n",
+                conf->ce_sounding_interval_coefs[SOUNDING_INTERVAL_COEF_INTERVAL_STEP]);
+       pr_debug("Max sounding interval:      %u\n",
+                conf->ce_sounding_interval_coefs[SOUNDING_INTERVAL_COEF_MAX_INTERVAL]);
+       pr_debug("Current interval:           %u\n\n", cl_sounding_get_interval(cl_hw));
+}
+
+void cl_sounding_cli_print_sounding_db(struct cl_hw *cl_hw)
+{
+#define STA_INDICES_STR_LEN 64
+
+       struct cl_sounding_info *elem = NULL;
+       char sta_indices_str[STA_INDICES_STR_LEN];
+       struct cl_sounding_db *sounding_db = &cl_hw->sounding;
+       struct cl_xmem *xmem_db = &cl_hw->chip->xmem_db;
+
+       pr_debug("----------------------------------------------------------------------"
+                "-------------------------------------------------------\n");
+       pr_debug("| sid |   type    | bw  | gid | sta num |            sta indices           |"
+                " q matrix bitmap | xmem space | v matrices size |");
+
+       read_lock_bh(&cl_hw->sounding.list_lock);
+
+       list_for_each_entry(elem, &cl_hw->sounding.head, list) {
+               u8 i, len = 0;
+
+               memset(sta_indices_str, '\0', sizeof(sta_indices_str));
+
+               for (i = 0; i < elem->sta_num; i++) {
+                       len += snprintf(sta_indices_str + len, STA_INDICES_STR_LEN - len,
+                                       "%u%s", elem->su_cl_sta_arr[i]->sta_idx,
+                                       (i == elem->sta_num - 1 ? "" : ","));
+               }
+
+               pr_debug("+-----+-----------+-----+-----+---------+"
+                        "----------------------------------+-----------------+------------+"
+                        "-----------------+\n");
+               pr_debug("| %2u  | %-9s | %3u | %2u  |    %1u    | %-32s |       0x%01x       |"
+                        "  %6u    |     %6u      |",
+                        elem->sounding_id, CL_SOUNDING_TYPE_2_STR(elem->type), BW_TO_MHZ(elem->bw),
+                        elem->gid, elem->sta_num, sta_indices_str, elem->q_matrix_bitmap,
+                        elem->xmem_space, elem->v_matrices_data_len);
+       }
+
+       read_unlock_bh(&cl_hw->sounding.list_lock);
+
+       pr_debug("-----------------------------------------------------------------------"
+                "------------------------------------------------------\n\n");
+       pr_debug("Num of soundings:         %u\n", sounding_db->num_soundings);
+       pr_debug("Active non-CQI profiles:  %u\n", sounding_db->active_profiles);
+       pr_debug("Active CQI profiles:      %u\n", sounding_db->cqi_profiles);
+       pr_debug("Xmem size:                %u\n", xmem_db->size);
+       pr_debug("Total xmem used:          %u\n", xmem_db->total_used);
+#undef STA_INDICES_STR_LEN
+}
+
+static void cl_sounding_cli_simulate_indication(struct cl_hw *cl_hw, u8 sid, u8 sta_idx)
+{
+       struct cl_sounding_info *sounding_elem = NULL;
+       struct mm_sounding_ind ind = {
+               .sid = sid,
+               .status = 1
+       };
+
+       sounding_elem = cl_sounding_get_elem(cl_hw, sid);
+
+       if (!sounding_elem) {
+               sounding_pr_err("[%s]: sounding id %u not found!\n", __func__, sid);
+               return;
+       }
+
+       ind.sounding_type = sounding_elem->type;
+       ind.sta_idx = sta_idx;
+
+       cl_sounding_indication_su(cl_hw, &ind, sounding_elem);
+}
+
+int cl_sounding_cli(struct cl_hw *cl_hw, struct cli_params *cli_params)
+{
+       u32 expected_params = 0;
+       bool create_sounding = false;
+       bool delete_sounding = false;
+       bool print_conf = false;
+       bool set_debug_level = false;
+       bool print_sounding_db = false;
+       bool simulate_indication = false;
+
+       switch (cli_params->option) {
+       case 'a':
+               create_sounding = true;
+               goto skip_exp_params_check;
+       case 'b':
+               delete_sounding = true;
+               expected_params = 1;
+               break;
+       case 'c':
+               print_conf = true;
+               expected_params = 0;
+               break;
+       case 'd':
+               set_debug_level = true;
+               expected_params = 1;
+               break;
+       case 'p':
+               print_sounding_db = true;
+               expected_params = 0;
+               break;
+       case 's':
+               simulate_indication = true;
+               expected_params = 2;
+               break;
+       case '?':
+               return cl_sounding_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;
+       }
+
+skip_exp_params_check:
+       if (create_sounding) {
+               cl_sounding_cli_create(cl_hw, cli_params);
+       } else if (delete_sounding) {
+               u8 sid = (u8)cli_params->params[0];
+
+               cl_sounding_stop_by_sid(cl_hw, sid, false);
+       } else if (print_conf) {
+               cl_sounding_cli_print_configuration(cl_hw);
+       } else if (set_debug_level) {
+               u8 dbg_level = (u8)cli_params->params[0];
+
+               cl_hw->sounding.dbg_level = dbg_level;
+       } else if (print_sounding_db) {
+               cl_sounding_cli_print_sounding_db(cl_hw);
+       } else if (simulate_indication) {
+               u8 sid = (u8)cli_params->params[0];
+               u8 sta_idx = (u8)cli_params->params[1];
+
+               cl_sounding_cli_simulate_indication(cl_hw, sid, sta_idx);
+       }
+
+       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.
________________________________


^ permalink raw reply related	[flat|nested] 262+ messages in thread

* [RFC v1 181/256] cl8k: add sounding.h
  2021-06-17 15:58 [RFC v1 000/256] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (179 preceding siblings ...)
  2021-06-17 16:01 ` [RFC v1 180/256] cl8k: add sounding.c viktor.barna
@ 2021-06-17 16:01 ` viktor.barna
  2021-06-17 16:01 ` [RFC v1 182/256] cl8k: add sta.c viktor.barna
                   ` (76 subsequent siblings)
  257 siblings, 0 replies; 262+ messages in thread
From: viktor.barna @ 2021-06-17 16:01 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Oleksandr Savchenko, Shay Bar, Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

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

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 drivers/net/wireless/celeno/cl8k/sounding.h | 148 ++++++++++++++++++++
 1 file changed, 148 insertions(+)
 create mode 100644 drivers/net/wireless/celeno/cl8k/sounding.h

diff --git a/drivers/net/wireless/celeno/cl8k/sounding.h b/drivers/net/wireless/celeno/cl8k/sounding.h
new file mode 100644
index 000000000000..d5d9d4941b23
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/sounding.h
@@ -0,0 +1,148 @@
+/* SPDX-License-Identifier: MIT */
+/* Copyright(c) 2019-2021, Celeno Communications Ltd. */
+
+#ifndef CL_SOUNDING_H
+#define CL_SOUNDING_H
+
+#include <linux/types.h>
+#include "fw/fw_msg.h"
+
+#define SOUNDING_ENABLE                                true
+#define SOUNDING_DISABLE                               false
+#define INVALID_SID                                    0xff
+#define XMEM_SIZE                                      (0x180 << 10) /* 384KB */
+#define CL_SOUNDING_STABILITY_TIME                     5
+#define CL_SOUNDING_FACTOR                             10
+
+#define SOUNDING_FEEDBACK_TYPE_SHIFT                   2
+#define SOUNDING_FEEDBACK_TYPE_MASK                    (BIT(SOUNDING_FEEDBACK_TYPE_SHIFT))
+#define SOUNDING_NG_SHIFT                              1
+#define SOUNDING_NG_MASK                               (BIT(SOUNDING_NG_SHIFT))
+#define SOUNDING_MU_CODEBOOK_SIZE_SHIFT                0
+#define SOUNDING_MU_CODEBOOK_SIZE_MASK                 (BIT(SOUNDING_MU_CODEBOOK_SIZE_SHIFT))
+#define SOUNDING_FEEDBACK_TYPE_VAL(fb_type_ng_cb_size) (((fb_type_ng_cb_size) & \
+                                                         SOUNDING_FEEDBACK_TYPE_MASK) >> \
+                                                         SOUNDING_FEEDBACK_TYPE_SHIFT)
+#define SOUNDING_NG_VAL(fb_type_ng_cb_size)            (((fb_type_ng_cb_size) & \
+                                                         SOUNDING_NG_MASK) >> SOUNDING_NG_SHIFT)
+#define SOUNDING_CODEBOOK_SIZE_VAL(fb_type_ng_cb_size) (((fb_type_ng_cb_size) & \
+                                                         SOUNDING_MU_CODEBOOK_SIZE_MASK) >> \
+                                                         SOUNDING_MU_CODEBOOK_SIZE_SHIFT)
+
+#define SOUNDING_TYPE_IS_VHT(type)                     ((type) == SOUNDING_TYPE_VHT_SU || \
+                                                       (type) == SOUNDING_TYPE_VHT_MU)
+#define SOUNDING_TYPE_IS_CQI(type)                     ((type) == SOUNDING_TYPE_HE_CQI || \
+                                                       (type) == SOUNDING_TYPE_HE_CQI_TB)
+
+enum fb_type_ng_cb_size {
+       FEEDBACK_TYPE_SU_NG_4_CODEBOOK_SIZE_4_2 = 0x0,
+       FEEDBACK_TYPE_SU_NG_4_CODEBOOK_SIZE_6_4,
+       FEEDBACK_TYPE_SU_NG_16_CODEBOOK_SIZE_4_2,
+       FEEDBACK_TYPE_SU_NG_16_CODEBOOK_SIZE_6_4,
+       FEEDBACK_TYPE_MU_NG_4_CODEBOOK_SIZE_7_5,
+       FEEDBACK_TYPE_MU_NG_4_CODEBOOK_SIZE_9_7,
+       FEEDBACK_TYPE_CQI_TB,
+       FEEDBACK_TYPE_MU_NG_16_CODEBOOK_SIZE_9_7,
+};
+
+enum cl_sounding_response {
+       CL_SOUNDING_RSP_OK = 0,
+
+       CL_SOUNDING_RSP_ERR_RLIMIT,
+       CL_SOUNDING_RSP_ERR_BW,
+       CL_SOUNDING_RSP_ERR_NSS,
+       CL_SOUNDING_RSP_ERR_INTERVAL,
+       CL_SOUNDING_RSP_ERR_ALREADY,
+       CL_SOUNDING_RSP_ERR_STA,
+       CL_SOUNDING_RSP_ERR_TYPE,
+};
+
+enum sounding_type {
+       SOUNDING_TYPE_HE_SU = 0,
+       SOUNDING_TYPE_HE_SU_TB,
+       SOUNDING_TYPE_VHT_SU,
+       SOUNDING_TYPE_HE_CQI,
+       SOUNDING_TYPE_HE_CQI_TB,
+       SOUNDING_TYPE_HE_MU,
+       SOUNDING_TYPE_VHT_MU,
+
+       SOUNDING_TYPE_MAX
+};
+
+enum sounding_interval_coef {
+       SOUNDING_INTERVAL_COEF_MIN_INTERVAL = 0,
+       SOUNDING_INTERVAL_COEF_STA_STEP,
+       SOUNDING_INTERVAL_COEF_INTERVAL_STEP,
+       SOUNDING_INTERVAL_COEF_MAX_INTERVAL,
+       SOUNDING_INTERVAL_COEF_MAX
+};
+
+struct cl_hw;
+
+struct v_matrix_header {
+       u32 format        : 2,
+           rsv1          : 30;
+       u32 bw            : 2,
+           nr_index      : 3,
+           nc_index      : 3,
+           rsv2          : 24;
+       u32 grouping      : 4,
+           rsv3          : 28;
+       u32 feedback_type : 1,
+           codebook_info : 3,
+           rsv4          : 28;
+       u32 ru_start_idx  : 7,
+           rsv5          : 25;
+       u32 ru_end_idx    : 7,
+           rsv6          : 25;
+       u32 padding       : 6,
+           rsv7          : 26;
+       u32 rsv8;
+};
+
+struct cl_sounding_info {
+       enum sounding_type type;
+       u8 sounding_id;
+       struct v_matrix_header *v_matrices_data;
+       u32 v_matrices_data_len;
+       u32 v_matrices_dma_addr;
+       u8 gid;
+       u8 bw;
+       u8 sta_num;
+       u8 q_matrix_bitmap;
+       struct cl_sta *su_cl_sta_arr[CL_MU_MAX_STA_PER_GROUP];
+       u32 xmem_space;
+       bool sounding_restart_required;
+       struct list_head list;
+};
+
+struct cl_sounding_db {
+       struct workqueue_struct *sounding_wq;
+       u8 num_soundings;
+       u8 cqi_profiles; /* Num of STAs with CQI active sounding */
+       u8 active_profiles; /* Num of STAs with non-CQI active sounding */
+       u8 active_profiles_prev[CL_SOUNDING_STABILITY_TIME];
+       u8 active_profiles_idx;
+       u8 dbg_level;
+       u8 current_interval;
+       u8 last_conf_active_profiles;
+       rwlock_t list_lock;
+       struct list_head head;
+};
+
+void cl_sounding_init(struct cl_hw *cl_hw);
+void cl_sounding_close(struct cl_hw *cl_hw);
+void cl_sounding_send_request(struct cl_hw *cl_hw, struct cl_sta **cl_sta_arr,
+                             u8 sta_num, bool enable, u8 sounding_type, u8 bw,
+                             u8 q_matrix_bitmap, struct cl_sounding_info *recovery_elem);
+void cl_sounding_switch_profile(struct cl_hw *cl_hw, u8 sta_idx_en, u8 sta_idx_dis);
+u8 cl_sounding_get_active_profiles(struct cl_hw *cl_hw);
+void cl_sounding_stop_by_sid(struct cl_hw *cl_hw, u8 sid, bool sounding_restart_check);
+void cl_sounding_maintenance(struct cl_hw *cl_hw);
+u16 cl_sounding_get_interval(struct cl_hw *cl_hw);
+void cl_sounding_recovery(struct cl_hw *cl_hw);
+struct cl_sounding_info *cl_sounding_get_elem(struct cl_hw *cl_hw, u8 sounding_id);
+void cl_sounding_indication(struct cl_hw *cl_hw, struct mm_sounding_ind *ind);
+int cl_sounding_cli(struct cl_hw *cl_hw, struct cli_params *cli_params);
+
+#endif /* CL_SOUNDING_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.
________________________________


^ permalink raw reply related	[flat|nested] 262+ messages in thread

* [RFC v1 182/256] cl8k: add sta.c
  2021-06-17 15:58 [RFC v1 000/256] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (180 preceding siblings ...)
  2021-06-17 16:01 ` [RFC v1 181/256] cl8k: add sounding.h viktor.barna
@ 2021-06-17 16:01 ` viktor.barna
  2021-06-17 16:01 ` [RFC v1 183/256] cl8k: add sta.h viktor.barna
                   ` (75 subsequent siblings)
  257 siblings, 0 replies; 262+ messages in thread
From: viktor.barna @ 2021-06-17 16:01 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Oleksandr Savchenko, Shay Bar, Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

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

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 drivers/net/wireless/celeno/cl8k/sta.c | 536 +++++++++++++++++++++++++
 1 file changed, 536 insertions(+)
 create mode 100644 drivers/net/wireless/celeno/cl8k/sta.c

diff --git a/drivers/net/wireless/celeno/cl8k/sta.c b/drivers/net/wireless/celeno/cl8k/sta.c
new file mode 100644
index 000000000000..625edd51cb93
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/sta.c
@@ -0,0 +1,536 @@
+// SPDX-License-Identifier: MIT
+/* Copyright(c) 2019-2021, Celeno Communications Ltd. */
+
+#include "sta.h"
+#include "rssi.h"
+#include "bf.h"
+#include "stats.h"
+#include "wrs/wrs_api.h"
+#include "utils/utils.h"
+#include "band.h"
+#include "vns.h"
+#include "radio.h"
+#include "tx/tx_inject.h"
+#include "twt.h"
+#include "motion_sense.h"
+#include "mac_addr.h"
+#include "tx/baw.h"
+#include "recovery.h"
+#include "tx/tx_queue.h"
+#include "tx/single_cfm.h"
+#include "ext/dyn_mcast_rate.h"
+#include "ext/dyn_bcast_rate.h"
+#include "chip.h"
+#include "fw/msg_tx.h"
+
+void cl_sta_init(struct cl_hw *cl_hw)
+{
+       u32 i;
+
+       rwlock_init(&cl_hw->cl_sta_db.lock);
+       INIT_LIST_HEAD(&cl_hw->cl_sta_db.head);
+
+       for (i = 0; i < CL_STA_HASH_SIZE; i++)
+               INIT_LIST_HEAD(&cl_hw->cl_sta_db.hash[i]);
+}
+
+void cl_sta_init_stainfo(struct cl_hw *cl_hw, struct sta_info *stainfo)
+{
+       if (!cl_recovery_in_progress(cl_hw)) {
+
+               struct cl_sta *cl_sta = STA_INFO_TO_CL_STA(stainfo);
+
+               /* Reset all cl_sta structure */
+               memset(cl_sta, 0, sizeof(struct cl_sta));
+               cl_sta->stainfo = stainfo;
+               /*
+                * Set sta_idx to 0xFF since FW expects this value as long as
+                * the STA is not fully connected
+                */
+               cl_sta->sta_idx = STA_IDX_INVALID;
+       }
+}
+
+static void cl_sta_add_to_lut(struct cl_hw *cl_hw, struct cl_vif *cl_vif, struct cl_sta *cl_sta)
+{
+       write_lock_bh(&cl_hw->cl_sta_db.lock);
+
+       cl_hw->cl_sta_db.num++;
+       cl_vif->num_sta++;
+       cl_hw->cl_sta_db.lut[cl_sta->sta_idx] = cl_sta;
+
+       /* Done here inside the lock because it allocates cl_stats */
+       cl_stats_sta_add(cl_hw, cl_sta);
+
+       write_unlock_bh(&cl_hw->cl_sta_db.lock);
+
+       cl_dbg_verbose(cl_hw, "mac=%pM, sta_idx=%u, vif_index=%u\n",
+                      cl_sta->addr, cl_sta->sta_idx, cl_sta->cl_vif->vif_index);
+}
+
+static void cl_sta_add_to_list(struct cl_hw *cl_hw, struct cl_sta *cl_sta)
+{
+       u8 hash_idx = CL_STA_HASH_IDX(cl_sta->addr[5]);
+
+       write_lock_bh(&cl_hw->cl_sta_db.lock);
+
+       /* Add to hash table */
+       list_add(&cl_sta->list_hash, &cl_hw->cl_sta_db.hash[hash_idx]);
+
+       /* Make sure that cl_sta's are stored in the list according to their sta_idx. */
+       if (list_empty(&cl_hw->cl_sta_db.head)) {
+               list_add(&cl_sta->list, &cl_hw->cl_sta_db.head);
+       } else if (list_is_singular(&cl_hw->cl_sta_db.head)) {
+               struct cl_sta *cl_sta_singular =
+                       list_first_entry(&cl_hw->cl_sta_db.head, struct cl_sta, list);
+
+               if (cl_sta_singular->sta_idx < cl_sta->sta_idx)
+                       list_add_tail(&cl_sta->list, &cl_hw->cl_sta_db.head);
+               else
+                       list_add(&cl_sta->list, &cl_hw->cl_sta_db.head);
+       } else {
+               struct cl_sta *cl_sta_last =
+                       list_last_entry(&cl_hw->cl_sta_db.head, struct cl_sta, list);
+
+               if (cl_sta->sta_idx > cl_sta_last->sta_idx) {
+                       list_add_tail(&cl_sta->list, &cl_hw->cl_sta_db.head);
+               } else {
+                       struct cl_sta *cl_sta_next = NULL;
+                       struct cl_sta *cl_sta_prev = NULL;
+
+                       list_for_each_entry(cl_sta_next, &cl_hw->cl_sta_db.head, list) {
+                               if (cl_sta_next->sta_idx < cl_sta->sta_idx)
+                                       continue;
+
+                               cl_sta_prev = list_prev_entry(cl_sta_next, list);
+                               __list_add(&cl_sta->list, &cl_sta_prev->list, &cl_sta_next->list);
+                               break;
+                       }
+               }
+       }
+
+       write_unlock_bh(&cl_hw->cl_sta_db.lock);
+
+       cl_sta->add_complete = true;
+}
+
+static void _cl_sta_add(struct cl_hw *cl_hw, struct ieee80211_vif *vif, struct ieee80211_sta *sta)
+{
+       struct cl_vif *cl_vif = (struct cl_vif *)vif->drv_priv;
+       struct cl_sta *cl_sta = IEEE80211_STA_TO_CL_STA(sta);
+
+       /* !!! Must be first !!! */
+       cl_sta_add_to_lut(cl_hw, cl_vif, cl_sta);
+
+       cl_baw_init(cl_sta);
+       cl_txq_sta_add(cl_hw, cl_sta);
+       cl_vns_sta_add(cl_hw, cl_sta);
+
+       /*
+        * Add rssi of association request to rssi pool
+        * Make sure to call it before cl_wrs_api_sta_add()
+        */
+       cl_rssi_assoc_find(cl_hw, cl_sta, cl_hw->cl_sta_db.num);
+
+       cl_motion_sense_sta_add(cl_hw, cl_sta);
+       cl_bf_sta_add(cl_hw, cl_sta, sta);
+       cl_wrs_api_sta_add(cl_hw, sta);
+       cl_wrs_api_set_smps_mode(cl_hw, sta,
+                                cl_sta->stainfo->cur_max_bandwidth);
+       /* Should be called after cl_wrs_api_sta_add() */
+       cl_dyn_mcast_rate_update_upon_assoc(cl_hw, cl_sta->wrs_sta.mode,
+                                           cl_hw->cl_sta_db.num);
+       cl_dyn_bcast_rate_update_upon_assoc(cl_hw,
+                                           cl_sta->wrs_sta.su_params.tx_params.mcs,
+                                           cl_hw->cl_sta_db.num);
+
+       /* !!! Must be last !!! */
+       cl_sta_add_to_list(cl_hw, cl_sta);
+}
+
+static void cl_sta_disassociate(struct cl_hw *cl_hw, bool ap_only)
+{
+       struct cl_sta *cl_sta;
+       int sta_idx;
+       int cnt = 0;
+       int sta_num = cl_hw->cl_sta_db.num;
+
+       for (sta_idx = 0; ((sta_idx < CL_MAX_NUM_STA) && (cnt < sta_num)); sta_idx++) {
+               cl_sta = cl_hw->cl_sta_db.lut[sta_idx];
+               if (cl_sta) {
+                       cnt++;
+                       if (ap_only && cl_sta->cl_vif->vif->type != NL80211_IFTYPE_AP)
+                               continue;
+                       cfg80211_del_sta(cl_sta->cl_vif->dev, cl_sta->addr, GFP_ATOMIC);
+               }
+       }
+}
+
+/*
+ * Parse the ampdu density to retrieve the value in usec, according to
+ * the values defined in ieee80211.h
+ */
+static u8 cl_sta_density2usec(u8 ampdu_density)
+{
+       switch (ampdu_density) {
+       case IEEE80211_HT_MPDU_DENSITY_NONE:
+               return 0;
+               /* 1 microsecond is our granularity */
+       case IEEE80211_HT_MPDU_DENSITY_0_25:
+       case IEEE80211_HT_MPDU_DENSITY_0_5:
+       case IEEE80211_HT_MPDU_DENSITY_1:
+               return 1;
+       case IEEE80211_HT_MPDU_DENSITY_2:
+               return 2;
+       case IEEE80211_HT_MPDU_DENSITY_4:
+               return 4;
+       case IEEE80211_HT_MPDU_DENSITY_8:
+               return 8;
+       case IEEE80211_HT_MPDU_DENSITY_16:
+               return 16;
+       default:
+               return 0;
+       }
+}
+
+static void cl_sta_set_min_spacing(struct cl_hw *cl_hw,
+                                  struct ieee80211_sta *sta)
+{
+       bool is_6g = cl_band_is_6g(cl_hw);
+       u8 sta_min_spacing = 0;
+       struct cl_sta *cl_sta = IEEE80211_STA_TO_CL_STA(sta);
+
+       if (is_6g)
+               sta_min_spacing =
+                       cl_sta_density2usec(sta->he_6ghz_capa.capa &
+                                       IEEE80211_HE_6GHZ_CAP_MIN_MPDU_START);
+       else if (sta->ht_cap.ht_supported)
+               sta_min_spacing =
+                       cl_sta_density2usec(sta->ht_cap.ampdu_density);
+       else
+               cl_dbg_err(cl_hw, "HT is not supported - cannot set sta_min_spacing\n");
+
+       cl_sta->ampdu_min_spacing =
+               max(cl_sta_density2usec(cl_hw->sband.ht_cap.ampdu_density), sta_min_spacing);
+}
+
+u32 cl_sta_num(struct cl_hw *cl_hw)
+{
+       u32 num = 0;
+
+       read_lock(&cl_hw->cl_sta_db.lock);
+       num = cl_hw->cl_sta_db.num;
+       read_unlock(&cl_hw->cl_sta_db.lock);
+
+       return num;
+}
+
+u32 cl_sta_num_bh(struct cl_hw *cl_hw)
+{
+       u32 num = 0;
+
+       read_lock_bh(&cl_hw->cl_sta_db.lock);
+       num = cl_hw->cl_sta_db.num;
+       read_unlock_bh(&cl_hw->cl_sta_db.lock);
+
+       return num;
+}
+
+bool cl_sta_is_assoc(struct cl_hw *cl_hw, u8 sta_idx)
+{
+       bool is_assoc = false;
+
+       if (sta_idx < CL_MAX_NUM_STA) {
+               read_lock_bh(&cl_hw->cl_sta_db.lock);
+               is_assoc = cl_hw->cl_sta_db.lut[sta_idx] ? true : false;
+               read_unlock_bh(&cl_hw->cl_sta_db.lock);
+       }
+
+       return is_assoc;
+}
+
+struct cl_sta *cl_sta_get(struct cl_hw *cl_hw, u8 sta_idx)
+{
+       if (sta_idx < CL_MAX_NUM_STA)
+               return cl_hw->cl_sta_db.lut[sta_idx];
+
+       return NULL;
+}
+
+struct cl_sta *cl_sta_get_by_addr(struct cl_hw *cl_hw, u8 *addr)
+{
+       struct cl_sta *cl_sta = NULL;
+       u8 hash_idx = CL_STA_HASH_IDX(addr[5]);
+
+       if (is_multicast_ether_addr(addr))
+               return NULL;
+
+       list_for_each_entry(cl_sta, &cl_hw->cl_sta_db.hash[hash_idx], list_hash)
+               if (cl_mac_addr_compare(cl_sta->addr, addr))
+                       return cl_sta;
+
+       return NULL;
+}
+
+void cl_sta_loop(struct cl_hw *cl_hw, sta_callback callback)
+{
+       struct cl_sta *cl_sta = NULL;
+
+       /* Go over all stations */
+       read_lock(&cl_hw->cl_sta_db.lock);
+
+       list_for_each_entry(cl_sta, &cl_hw->cl_sta_db.head, list)
+               callback(cl_hw, cl_sta);
+
+       read_unlock(&cl_hw->cl_sta_db.lock);
+}
+
+void cl_sta_loop_bh(struct cl_hw *cl_hw, sta_callback callback)
+{
+       struct cl_sta *cl_sta = NULL;
+
+       /* 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)
+               callback(cl_hw, cl_sta);
+
+       read_unlock_bh(&cl_hw->cl_sta_db.lock);
+}
+
+void cl_sta_loop_safe(struct cl_hw *cl_hw, sta_callback callback)
+{
+       struct cl_sta *cl_sta = NULL;
+       struct cl_sta *cl_sta_tmp = NULL;
+
+       /* Go over all stations */
+       read_lock(&cl_hw->cl_sta_db.lock);
+
+       list_for_each_entry_safe(cl_sta, cl_sta_tmp, &cl_hw->cl_sta_db.head, list)
+               callback(cl_hw, cl_sta);
+
+       read_unlock(&cl_hw->cl_sta_db.lock);
+}
+
+static int cl_sta_add_to_firmware(struct cl_hw *cl_hw, struct ieee80211_vif *vif,
+                                 struct ieee80211_sta *sta)
+{
+       struct cl_sta *cl_sta = (struct cl_sta *)sta->drv_priv;
+       struct cl_vif *cl_vif = (struct cl_vif *)vif->drv_priv;
+       struct mm_sta_add_cfm *sta_add_cfm;
+       int error = 0;
+       u8 recovery_sta_idx = 0;
+       u32 rate_ctrl_info = 0;
+
+       if (cl_recovery_in_progress(cl_hw)) {
+               struct cl_wrs_tx_params *tx_params = &cl_sta->wrs_sta.su_params.tx_params;
+
+               /*
+                * If station is added to firmware during recovery, the driver passes to firmware
+                * the station index to be used instead of firmware selecting a free index
+                */
+               recovery_sta_idx = cl_sta->sta_idx;
+
+               /* Keep current rate value */
+               rate_ctrl_info = cl_rate_ctrl_generate(cl_hw, cl_sta, tx_params->mode,
+                                                      tx_params->bw, tx_params->nss,
+                                                      tx_params->mcs, tx_params->gi,
+                                                      false);
+       } else {
+               bool is_cck = cl_band_is_24g(cl_hw) && cl_hw_mode_is_b_or_bg(cl_hw);
+               u8 mode = is_cck ? WRS_MODE_CCK : WRS_MODE_OFDM;
+
+               /*
+                * Not in recovery:
+                * firmware will set sta_idx and will return in confirmation message
+                */
+               recovery_sta_idx = STA_IDX_INVALID;
+
+               /* Default rate value */
+               rate_ctrl_info = cl_rate_ctrl_generate(cl_hw, cl_sta, mode,
+                                                      0, 0, 0, 0, false);
+       }
+
+       /* Must be called before cl_msg_tx_sta_add() */
+       cl_sta_set_min_spacing(cl_hw, sta);
+
+       /* Send message to firmware */
+       error = cl_msg_tx_sta_add(cl_hw, sta, cl_vif, recovery_sta_idx, rate_ctrl_info);
+       if (error)
+               return error;
+
+       sta_add_cfm = (struct mm_sta_add_cfm *)(cl_hw->msg_cfm_params[MM_STA_ADD_CFM]);
+       if (!sta_add_cfm)
+               return -ENOMSG;
+
+       if (sta_add_cfm->status != 0) {
+               cl_dbg_verbose(cl_hw, "Status Error (%u)\n", sta_add_cfm->status);
+               cl_msg_tx_free_cfm_params(cl_hw, MM_STA_ADD_CFM);
+               return -EIO;
+       }
+
+       /* Save the index retrieved from firmware */
+       cl_sta->sta_idx = sta_add_cfm->sta_idx;
+
+       /* Release cfm msg */
+       cl_msg_tx_free_cfm_params(cl_hw, MM_STA_ADD_CFM);
+
+       return 0;
+}
+
+int cl_sta_add(struct cl_hw *cl_hw, struct ieee80211_vif *vif,
+              struct ieee80211_sta *sta)
+{
+       struct cl_sta *cl_sta = (struct cl_sta *)sta->drv_priv;
+       struct cl_vif *cl_vif = (struct cl_vif *)vif->drv_priv;
+       int error = 0;
+
+       if (cl_radio_is_going_down(cl_hw))
+               return -EPERM;
+
+       cl_sta->cl_vif = cl_vif;
+       cl_mac_addr_copy(cl_sta->addr, sta->addr);
+
+       error = cl_sta_add_to_firmware(cl_hw, vif, sta);
+       if (error)
+               return error;
+
+       if (!cl_recovery_in_progress(cl_hw))
+               if (vif->type != NL80211_IFTYPE_STATION ||
+                   cl_hw->chip->conf->ce_production_mode)
+                       _cl_sta_add(cl_hw, vif, sta);
+
+       if (vif->type == NL80211_IFTYPE_MESH_POINT &&
+           cl_vif->num_sta == 1) {
+               cl_vif_ap_tx_enable(cl_hw, true);
+               set_bit(CL_DEV_MESH_AP, &cl_hw->drv_flags);
+       }
+
+       return 0;
+}
+
+void cl_sta_mgd_add(struct cl_hw *cl_hw, struct cl_vif *cl_vif, struct ieee80211_sta *sta)
+{
+       /* Should be called in station mode */
+       struct cl_sta *cl_sta = (struct cl_sta *)sta->drv_priv;
+
+       /* !!! Must be first !!! */
+       cl_sta_add_to_lut(cl_hw, cl_vif, cl_sta);
+
+       cl_baw_init(cl_sta);
+       cl_txq_sta_add(cl_hw, cl_sta);
+       cl_vns_sta_add(cl_hw, cl_sta);
+
+       /*
+        * Add rssi of association response to rssi pool
+        * Make sure to call it before cl_wrs_api_sta_add()
+        */
+       cl_rssi_assoc_find(cl_hw, cl_sta, cl_hw->cl_sta_db.num);
+
+       /* In station mode we assume that the AP we connect to is static */
+       cl_motion_sense_sta_add(cl_hw, cl_sta);
+       cl_bf_sta_add(cl_hw, cl_sta, sta);
+       cl_wrs_api_sta_add(cl_hw, sta);
+       /* Should be called after cl_wrs_api_sta_add() */
+       cl_dyn_mcast_rate_update_upon_assoc(cl_hw, cl_sta->wrs_sta.mode,
+                                           cl_hw->cl_sta_db.num);
+       cl_dyn_bcast_rate_update_upon_assoc(cl_hw,
+                                           cl_sta->wrs_sta.su_params.tx_params.mcs,
+                                           cl_hw->cl_sta_db.num);
+
+       /* !!! Must be last !!! */
+       cl_sta_add_to_list(cl_hw, cl_sta);
+}
+
+static void _cl_sta_remove(struct cl_hw *cl_hw, struct cl_sta *cl_sta)
+{
+       write_lock_bh(&cl_hw->cl_sta_db.lock);
+
+       list_del(&cl_sta->list);
+       list_del(&cl_sta->list_hash);
+
+       cl_hw->cl_sta_db.lut[cl_sta->sta_idx] = NULL;
+       cl_hw->cl_sta_db.num--;
+       cl_sta->cl_vif->num_sta--;
+
+       cl_dbg_verbose(cl_hw, "mac=%pM, sta_idx=%u, vif_index=%u\n",
+                      cl_sta->addr, cl_sta->sta_idx, cl_sta->cl_vif->vif_index);
+
+       write_unlock_bh(&cl_hw->cl_sta_db.lock);
+}
+
+void cl_sta_remove(struct cl_hw *cl_hw, struct ieee80211_vif *vif, struct ieee80211_sta *sta)
+{
+       struct cl_vif *cl_vif = (struct cl_vif *)vif->drv_priv;
+       struct cl_sta *cl_sta = (struct cl_sta *)sta->drv_priv;
+       u8 sta_idx = cl_sta->sta_idx;
+
+       /* !!! Must be first - remove from list and LUT !!! */
+       _cl_sta_remove(cl_hw, cl_sta);
+
+       cl_traffic_sta_remove(cl_hw, cl_sta);
+       cl_bf_sta_remove(cl_hw, cl_sta);
+       cl_dyn_mcast_rate_update_upon_disassoc(cl_hw,
+                                              cl_sta->wrs_sta.mode,
+                                              cl_hw->cl_sta_db.num);
+       cl_dyn_bcast_rate_update_upon_disassoc(cl_hw,
+                                              cl_sta->wrs_sta.su_params.tx_params.mcs,
+                                              cl_hw->cl_sta_db.num);
+       cl_wrs_api_sta_remove(cl_hw, cl_sta);
+       cl_tx_inject_sta_remove(cl_hw, cl_sta);
+       cl_twt_sta_remove(cl_hw, cl_sta);
+       cl_stats_sta_remove(cl_hw, cl_sta);
+
+       /*
+        * TX stop flow:
+        * 1) Flush TX queues
+        * 2) Poll confirmation queue and clear enhanced TIM
+        * 3) Send MM_STA_DEL_REQ message to firmware
+        * 4) Flush confirmation queue
+        * 5) Reset write index
+        */
+
+       cl_txq_flush_sta(cl_hw, cl_sta);
+       cl_single_cfm_poll_empty_sta(cl_hw, sta_idx);
+       cl_txq_sta_remove(cl_hw, sta_idx);
+
+       if (cl_vif->vif->type == NL80211_IFTYPE_MESH_POINT &&
+           cl_vif->num_sta == 0) {
+               cl_sta_disassociate_ap_iface(cl_hw);
+               cl_vif_ap_tx_enable(cl_hw, false);
+               clear_bit(CL_DEV_MESH_AP, &cl_hw->drv_flags);
+       }
+
+       cl_msg_tx_sta_del(cl_hw, sta_idx);
+
+       cl_single_cfm_flush_sta(cl_hw, sta_idx);
+
+       if (cl_vif->num_sta == 0)
+               cl_radio_off_wake_up(cl_hw);
+}
+
+void cl_sta_disassociate_all(struct cl_hw *cl_hw)
+{
+       /* Disassociate all associated stations (AP + STA mode) */
+       cl_sta_disassociate(cl_hw, false);
+}
+
+void cl_sta_disassociate_ap_iface(struct cl_hw *cl_hw)
+{
+       /* Disassociate all AP associated stations (AP mode only) */
+       cl_sta_disassociate(cl_hw, true);
+}
+
+void cl_sta_ps_notify(struct cl_hw *cl_hw, struct cl_sta *cl_sta, bool is_ps)
+{
+       /*
+        * PS-Poll & UAPSD are handled by FW, by setting
+        * WLAN_STA_SP we ensure mac80211 does not re-handle.
+        * flag is unset at ieee80211_sta_ps_deliver_wakeup
+        */
+       if (is_ps)
+               set_sta_flag(cl_sta->stainfo, WLAN_STA_SP);
+
+       cl_stats_update_ps(cl_hw, cl_sta, is_ps);
+}
+
--
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.
________________________________


^ permalink raw reply related	[flat|nested] 262+ messages in thread

* [RFC v1 183/256] cl8k: add sta.h
  2021-06-17 15:58 [RFC v1 000/256] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (181 preceding siblings ...)
  2021-06-17 16:01 ` [RFC v1 182/256] cl8k: add sta.c viktor.barna
@ 2021-06-17 16:01 ` viktor.barna
  2021-06-17 16:01 ` [RFC v1 184/256] cl8k: add stats.c viktor.barna
                   ` (74 subsequent siblings)
  257 siblings, 0 replies; 262+ messages in thread
From: viktor.barna @ 2021-06-17 16:01 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Oleksandr Savchenko, Shay Bar, Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

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

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 drivers/net/wireless/celeno/cl8k/sta.h | 241 +++++++++++++++++++++++++
 1 file changed, 241 insertions(+)
 create mode 100644 drivers/net/wireless/celeno/cl8k/sta.h

diff --git a/drivers/net/wireless/celeno/cl8k/sta.h b/drivers/net/wireless/celeno/cl8k/sta.h
new file mode 100644
index 000000000000..8e1e47316cf8
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/sta.h
@@ -0,0 +1,241 @@
+/* SPDX-License-Identifier: MIT */
+/* Copyright(c) 2019-2021, Celeno Communications Ltd. */
+
+#ifndef CL_STA_H
+#define CL_STA_H
+
+#include "sta_info.h"
+#include "utils/timer.h"
+#include "rate_ctrl.h"
+#include "motion_sense.h"
+
+#define IEEE80211_STA_TO_CL_STA(sta) ((struct cl_sta *)(sta)->drv_priv)
+#define STA_INFO_TO_CL_STA(sta_info) ((struct cl_sta *)(sta_info)->sta.drv_priv)
+
+#define STA_IDX_INVALID U8_MAX
+
+struct cl_wrs_info {
+       u64 epr_acc;
+       u32 tx_success;
+       u32 tx_fail;
+       u32 tx_fail_prev;
+       u32 ba_not_rcv;
+       u8 ba_not_rcv_consecutive;
+       u8 ba_not_rcv_consecutive_max;
+       bool synced;
+       u32 sync_attempts;
+       u8 quick_rate_agg_cntr;
+       u16 quick_rate_pkt_cntr;
+       bool quick_rate_check;
+};
+
+struct cl_wrs_rssi {
+       s32 sum[MAX_ANTENNAS];
+       s32 cnt;
+};
+
+struct cl_amsdu_ctrl {
+       struct cl_sw_txhdr *sw_txhdr;
+       u16 rem_len;
+       u16 max_len;
+       u16 hdrlen;
+       u8 packet_cnt;
+       bool is_sw_amsdu;
+};
+
+struct cl_bf_sta_db {
+       bool traffic_active;
+       bool sounding_start;
+       bool sounding_remove_required;
+       bool indication_timeout;
+       bool synced;
+       bool is_on;
+       bool is_on_fallback;
+       u8 num_ss;
+       u8 num_ss_fallback;
+       u8 beamformee_sts;
+       u8 nc;
+       u32 sounding_indications;
+       struct cl_timer timer;
+};
+
+#define RSSI_ARR_SIZE 128
+#define BF_IDX_MAX 2
+
+struct cl_tx_cntrs {
+       u32 success;
+       u32 fail;
+};
+
+struct cl_tx_stats {
+       struct cl_tx_cntrs he[CHNL_BW_MAX][WRS_SS_MAX][WRS_MCS_MAX][WRS_GI_MAX][BF_IDX_MAX];
+       struct cl_tx_cntrs
+               vht[CHNL_BW_MAX_VHT][WRS_SS_MAX][WRS_MCS_MAX_VHT][WRS_GI_MAX_VHT][BF_IDX_MAX];
+       struct cl_tx_cntrs ht[CHNL_BW_MAX_HT][WRS_SS_MAX][WRS_MCS_MAX_HT][WRS_GI_MAX_HT];
+       struct cl_tx_cntrs ofdm[WRS_MCS_MAX_OFDM];
+       struct cl_tx_cntrs cck[WRS_MCS_MAX_CCK];
+       u32 agg_cntr;
+       u32 fail_cntr;
+};
+
+enum cl_ps_period {
+       PS_PERIOD_50MS,
+       PS_PERIOD_100MS,
+       PS_PERIOD_250MS,
+       PS_PERIOD_500MS,
+       PS_PERIOD_750MS,
+       PS_PERIOD_1000MS,
+       PS_PERIOD_2000MS,
+       PS_PERIOD_5000MS,
+       PS_PERIOD_10000MS,
+       PS_PERIOD_ABOVE,
+
+       PS_PERIOD_MAX
+};
+
+struct cl_ps_stats {
+       bool is_ps;
+       unsigned long timestamp_sleep;
+       u32 period[PS_PERIOD_MAX];
+};
+
+enum cl_fec_coding {
+       CL_FEC_CODING_BCC,
+       CL_FEC_CODING_LDPC,
+       CL_FEC_CODING_MAX
+};
+
+struct cl_stats {
+       struct cl_tx_stats tx;
+       struct cl_rx_stats rx;
+       u32 rssi[RSSI_ARR_SIZE][MAX_ANTENNAS];
+       u32 fec_coding[CL_FEC_CODING_MAX];
+       struct cl_ps_stats ps;
+};
+
+/* Per RA/TID Data for AMPDU TX */
+struct cl_baw {
+       u8 fw_agg_idx;
+       bool amsdu;
+       bool action_start;
+       u16 ssn;
+       u16 tid_seq;
+       struct sk_buff_head pending;
+};
+
+struct cl_vns_sta_db {
+       bool is_very_near;
+       bool prev_decision;
+       s32 rssi_sum[MAX_ANTENNAS];
+       s32 rssi_samples;
+};
+
+struct cl_agc_cd_rssi {
+       s32 samples;
+       s32 sum[MAX_ANTENNAS];
+       s8 prev;
+};
+
+struct cl_tid_ampdu_rx {
+       spinlock_t reorder_lock;
+       u64 reorder_buf_filtered;
+       struct sk_buff_head *reorder_buf;
+       unsigned long *reorder_time;
+       struct ieee80211_sta *sta;
+       struct cl_timer reorder_timer;
+       struct cl_hw *cl_hw;
+       u16 head_seq_num;
+       u16 stored_mpdu_num;
+       u16 ssn;
+       u16 buf_size;
+       u16 timeout;
+       u8 tid;
+       u8 auto_seq:1,
+          removed:1,
+          started:1;
+};
+
+/*
+ * Structure used to save information relative to the managed stations.
+ * Will be used as the 'drv_priv' field of the "struct ieee80211_sta" structure.
+ */
+struct cl_sta {
+       struct list_head list;
+       struct list_head list_hash;
+       u8 sta_idx;
+       u8 su_sid;
+       bool key_disable;
+       u8 addr[ETH_ALEN];
+       struct cl_baw baws[IEEE80211_NUM_TIDS];
+       struct cl_amsdu_ctrl amsdu_anchor[IEEE80211_NUM_TIDS];
+       struct cl_tx_queue *agg_tx_queues[IEEE80211_NUM_TIDS];
+       struct cl_vif *cl_vif;
+       struct sta_info *stainfo;
+       struct ieee80211_key_conf *key_conf;
+       struct cl_bf_sta_db bf_db;
+       struct cl_stats *stats;
+       s32 alpha_rssi;
+       bool manual_alpha_rssi;
+       s8 last_rssi[MAX_ANTENNAS];
+       u8 ampdu_min_spacing;
+       struct cl_traffic_sta traffic_db[TRAFFIC_DIRECTION_MAX];
+       struct cl_vns_sta_db vns_db;
+       struct cl_agc_cd_rssi agc_cd_rssi;
+       u32 retry_count;
+       u32 data_pending[AC_MAX];
+       struct cl_wrs_info wrs_info;
+       struct cl_wrs_rssi wrs_rssi;
+       bool add_complete;
+       struct cl_wrs_sta wrs_sta;
+       struct cl_motion_sense motion_sense;
+       union cl_rate_ctrl_info_he rate_ctrl_he;
+       struct cl_tid_ampdu_rx *tid_agg_rx[IEEE80211_NUM_TIDS];
+};
+
+typedef void (*sta_callback)(struct cl_hw *, struct cl_sta *);
+
+void cl_sta_init(struct cl_hw *cl_hw);
+
+/* These functions take the lock inside */
+u32 cl_sta_num(struct cl_hw *cl_hw);
+u32 cl_sta_num_bh(struct cl_hw *cl_hw);
+bool cl_sta_is_assoc(struct cl_hw *cl_hw, u8 sta_idx);
+
+/* Must take lock before calling these functions */
+struct cl_sta *cl_sta_get(struct cl_hw *cl_hw, u8 sta_idx);
+struct cl_sta *cl_sta_get_by_addr(struct cl_hw *cl_hw, u8 *addr);
+
+/* Loop over list of stations and run the callback for each station */
+void cl_sta_loop(struct cl_hw *cl_hw, sta_callback callback);
+void cl_sta_loop_bh(struct cl_hw *cl_hw, sta_callback callback);
+void cl_sta_loop_safe(struct cl_hw *cl_hw, sta_callback callback);
+
+void cl_sta_init_stainfo(struct cl_hw *cl_hw, struct sta_info *stainfo);
+int cl_sta_add(struct cl_hw *cl_hw, struct ieee80211_vif *vif, struct ieee80211_sta *sta);
+void cl_sta_mgd_add(struct cl_hw *cl_hw, struct cl_vif *cl_vif, struct ieee80211_sta *sta);
+void cl_sta_remove(struct cl_hw *cl_hw, struct ieee80211_vif *vif, struct ieee80211_sta *sta);
+void cl_sta_disassociate_all(struct cl_hw *cl_hw);
+void cl_sta_disassociate_ap_iface(struct cl_hw *cl_hw);
+void cl_sta_ps_notify(struct cl_hw *cl_hw, struct cl_sta *cl_sta, bool is_ps);
+
+static inline void cl_sta_lock_bh(struct cl_hw *cl_hw)
+{
+       read_lock_bh(&cl_hw->cl_sta_db.lock);
+}
+
+static inline void cl_sta_unlock_bh(struct cl_hw *cl_hw)
+{
+       read_unlock_bh(&cl_hw->cl_sta_db.lock);
+}
+
+static inline void cl_sta_lock(struct cl_hw *cl_hw)
+{
+       read_lock(&cl_hw->cl_sta_db.lock);
+}
+
+static inline void cl_sta_unlock(struct cl_hw *cl_hw)
+{
+       read_unlock(&cl_hw->cl_sta_db.lock);
+}
+
+#endif /* CL_STA_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.
________________________________


^ permalink raw reply related	[flat|nested] 262+ messages in thread

* [RFC v1 184/256] cl8k: add stats.c
  2021-06-17 15:58 [RFC v1 000/256] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (182 preceding siblings ...)
  2021-06-17 16:01 ` [RFC v1 183/256] cl8k: add sta.h viktor.barna
@ 2021-06-17 16:01 ` viktor.barna
  2021-06-17 16:01 ` [RFC v1 185/256] cl8k: add stats.h viktor.barna
                   ` (73 subsequent siblings)
  257 siblings, 0 replies; 262+ messages in thread
From: viktor.barna @ 2021-06-17 16:01 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Oleksandr Savchenko, Shay Bar, Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

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

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 drivers/net/wireless/celeno/cl8k/stats.c | 1402 ++++++++++++++++++++++
 1 file changed, 1402 insertions(+)
 create mode 100644 drivers/net/wireless/celeno/cl8k/stats.c

diff --git a/drivers/net/wireless/celeno/cl8k/stats.c b/drivers/net/wireless/celeno/cl8k/stats.c
new file mode 100644
index 000000000000..f340f60ebab9
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/stats.c
@@ -0,0 +1,1402 @@
+// SPDX-License-Identifier: MIT
+/* Copyright(c) 2019-2021, Celeno Communications Ltd. */
+
+#include <linux/string.h>
+#include "stats.h"
+#include "rx/rx.h"
+#include "reg/reg_access.h"
+#include "sta.h"
+#include "band.h"
+#include "mib.h"
+#include "rate_ctrl.h"
+#include "vif.h"
+#include "data_rates.h"
+
+typedef void (*stats_callback)(struct cl_hw *, struct cl_sta *);
+
+static const char *bw_str[CHNL_BW_MAX_OFDMA] = {
+       [CHNL_BW_2_5] = "2.5",
+       [CHNL_BW_5] = "5",
+       [CHNL_BW_10] = "10",
+       [CHNL_BW_20] = "20",
+       [CHNL_BW_40] = "40",
+       [CHNL_BW_80] = "80",
+       [CHNL_BW_160] = "160"
+};
+
+static const char *gi_he_str[WRS_GI_MAX_HE] = {
+       [WRS_GI_LONG] = "3.2",
+       [WRS_GI_SHORT] = "1.6",
+       [WRS_GI_VSHORT] = "0.8"
+};
+
+static const char *gi_ht_vht_str[WRS_GI_MAX_HT] = {
+       [WRS_GI_LONG] = "0.8",
+       [WRS_GI_SHORT] = "0.4",
+};
+
+static void cl_stats_sta_reset(struct cl_hw *cl_hw, struct cl_sta *cl_sta)
+{
+       struct cl_ps_stats *ps = &cl_sta->stats->ps;
+       bool is_ps = ps->is_ps;
+       unsigned long timestamp_sleep = ps->timestamp_sleep;
+
+       memset(cl_sta->stats, 0, sizeof(struct cl_stats));
+
+       /* Restore value of power-save state and timestamp */
+       ps->is_ps = is_ps;
+       ps->timestamp_sleep = timestamp_sleep;
+}
+
+static void cl_stats_print_per(struct cl_hw *cl_hw, u32 delay)
+{
+       u32 system_per = 0, air_per = 0, ampdu_all,
+               old_phy_error, old_fcs_error, old_overflow, old_complete,
+               old_ampdu_failed, old_real_fcs, old_ampdu_success,
+               new_phy_error, new_fcs_error, new_overflow, new_complete,
+               new_ampdu_failed, new_real_fcs, new_ampdu_success;
+       char *buf = NULL;
+       ssize_t buf_size;
+       int len = 0;
+
+       old_phy_error = cl_mib_cntr_read(cl_hw, MIB_DOT11_RX_PHY_ERROR_COUNT);
+       old_fcs_error = cl_mib_cntr_read(cl_hw, MIB_DOT11_FCS_ERROR_COUNT);
+       old_overflow = cl_mib_cntr_read(cl_hw, MIB_DOT11_RX_FIFO_OVERFLOW_COUNT);
+       old_complete = cl_mib_cntr_read(cl_hw, MIB_RW_QOS_U_RECEIVED_MPDU_COUNT0) +
+                      cl_mib_cntr_read(cl_hw, MIB_RW_QOS_U_RECEIVED_MPDU_COUNT1) +
+                      cl_mib_cntr_read(cl_hw, MIB_RW_QOS_U_RECEIVED_MPDU_COUNT2) +
+                      cl_mib_cntr_read(cl_hw, MIB_RW_QOS_U_RECEIVED_MPDU_COUNT3) +
+                      cl_mib_cntr_read(cl_hw, MIB_RW_QOS_U_RECEIVED_MPDU_COUNT4) +
+                      cl_mib_cntr_read(cl_hw, MIB_RW_QOS_U_RECEIVED_MPDU_COUNT5) +
+                      cl_mib_cntr_read(cl_hw, MIB_RW_QOS_U_RECEIVED_MPDU_COUNT6) +
+                      cl_mib_cntr_read(cl_hw, MIB_RW_QOS_U_RECEIVED_MPDU_COUNT7);
+       old_ampdu_failed = cl_mib_cntr_read(cl_hw, MIB_AMPDU_INCORRECT_RCVED_COUNT);
+       old_ampdu_success = cl_mib_cntr_read(cl_hw, MIB_RW_U_AMPDU_RECEIVED_COUNT);
+       old_real_fcs = old_fcs_error - old_overflow;
+
+       mdelay(delay);
+
+       new_phy_error = cl_mib_cntr_read(cl_hw, MIB_DOT11_RX_PHY_ERROR_COUNT);
+       new_fcs_error = cl_mib_cntr_read(cl_hw, MIB_DOT11_FCS_ERROR_COUNT);
+       new_overflow = cl_mib_cntr_read(cl_hw, MIB_DOT11_RX_FIFO_OVERFLOW_COUNT);
+       new_complete = cl_mib_cntr_read(cl_hw, MIB_RW_QOS_U_RECEIVED_MPDU_COUNT0) +
+               cl_mib_cntr_read(cl_hw, MIB_RW_QOS_U_RECEIVED_MPDU_COUNT1) +
+               cl_mib_cntr_read(cl_hw, MIB_RW_QOS_U_RECEIVED_MPDU_COUNT2) +
+               cl_mib_cntr_read(cl_hw, MIB_RW_QOS_U_RECEIVED_MPDU_COUNT3) +
+               cl_mib_cntr_read(cl_hw, MIB_RW_QOS_U_RECEIVED_MPDU_COUNT4) +
+               cl_mib_cntr_read(cl_hw, MIB_RW_QOS_U_RECEIVED_MPDU_COUNT5) +
+               cl_mib_cntr_read(cl_hw, MIB_RW_QOS_U_RECEIVED_MPDU_COUNT6) +
+               cl_mib_cntr_read(cl_hw, MIB_RW_QOS_U_RECEIVED_MPDU_COUNT7);
+       new_ampdu_failed = cl_mib_cntr_read(cl_hw, MIB_AMPDU_INCORRECT_RCVED_COUNT);
+       new_ampdu_success = cl_mib_cntr_read(cl_hw, MIB_RW_U_AMPDU_RECEIVED_COUNT);
+       new_real_fcs = new_fcs_error - new_overflow;
+
+       /* Overflow handling */
+       if (old_complete > new_complete ||
+           old_overflow > new_overflow ||
+           old_fcs_error > new_fcs_error ||
+           old_phy_error > new_phy_error ||
+           old_ampdu_failed > new_ampdu_failed)
+               return;
+
+       ampdu_all = (new_ampdu_failed - old_ampdu_failed) +
+               (new_ampdu_success - old_ampdu_success);
+
+       if (new_complete - old_complete) {
+               system_per = ((new_overflow - old_overflow) * 100 /
+                             (new_complete - old_complete));
+       } else {
+               cl_snprintf(&buf, &len, &buf_size, "No successfully received packets\n");
+               goto out;
+       }
+
+       if ((new_fcs_error + new_phy_error + new_complete) -
+           (old_fcs_error + old_phy_error + old_complete))
+               air_per = (new_real_fcs - old_real_fcs) * 100 /
+               ((new_real_fcs + new_complete) - (old_real_fcs + old_complete));
+
+       cl_snprintf(&buf, &len, &buf_size,
+                   "Air PER = [%u%%]\n"
+                   "System PER = [%u%%]\n"
+                   "Successfully received packets = [%u]\n"
+                   "Number of phy errors received: [%u]\n"
+                   "Aggregation failure ratio: [%u/%u]\n",
+                   air_per, system_per, new_complete - old_complete,
+                   new_phy_error - old_phy_error,
+                   new_ampdu_failed - old_ampdu_failed, ampdu_all);
+
+out:
+       cl_vendor_reply(cl_hw, buf, len);
+       kfree(buf);
+}
+
+static void cl_stats_print_rssi(struct cl_hw *cl_hw, struct cl_sta *cl_sta)
+{
+       struct cl_stats *stats = cl_sta->stats;
+       u32 i = 0, j = 0;
+       u64 avg_rssi[MAX_ANTENNAS] = {0};
+       u64 sum_rssi[MAX_ANTENNAS] = {0};
+       u64 total_rssi = 0;
+       char *buf = NULL;
+       ssize_t buf_size;
+       int len = 0;
+
+       cl_snprintf(&buf, &len, &buf_size,
+                   "STA #%u, MAC %pM\n", cl_sta->sta_idx, cl_sta->addr);
+
+       cl_snprintf(&buf, &len, &buf_size, "|----");
+       for (j = 0; j < cl_hw->num_antennas; j++)
+               cl_snprintf(&buf, &len, &buf_size, "-----------");
+       cl_snprintf(&buf, &len, &buf_size, "|\n");
+
+       cl_snprintf(&buf, &len, &buf_size, "|RSSI");
+       for (j = 0; j < cl_hw->num_antennas; j++)
+               cl_snprintf(&buf, &len, &buf_size, "|   Ant%u   ", j + 1);
+       cl_snprintf(&buf, &len, &buf_size, "|\n");
+
+       cl_snprintf(&buf, &len, &buf_size, "|----");
+       for (j = 0; j < cl_hw->num_antennas; j++)
+               cl_snprintf(&buf, &len, &buf_size, "+----------");
+       cl_snprintf(&buf, &len, &buf_size, "|\n");
+
+       for (i = 0; i < RSSI_ARR_SIZE; i++) {
+               total_rssi = 0;
+
+               for (j = 0; j < cl_hw->num_antennas; j++) {
+                       total_rssi += stats->rssi[i][j];
+                       sum_rssi[j] += stats->rssi[i][j];
+                       avg_rssi[j] += (i * stats->rssi[i][j]);
+               }
+
+               /* Does not print rssi entries with 0 packets */
+               if (total_rssi == 0)
+                       continue;
+
+               cl_snprintf(&buf, &len, &buf_size, "|%3d ", -i);
+               for (j = 0; j < cl_hw->num_antennas; j++)
+                       cl_snprintf(&buf, &len, &buf_size,
+                                   "|%10u", stats->rssi[i][j]);
+               cl_snprintf(&buf, &len, &buf_size, "|\n");
+       }
+
+       total_rssi = 0;
+
+       for (j = 0; j < cl_hw->num_antennas; j++) {
+               if (sum_rssi[j] == 0)
+                       goto out;
+
+               avg_rssi[j] = div64_u64(avg_rssi[j], sum_rssi[j]);
+       }
+
+       cl_snprintf(&buf, &len, &buf_size, "|----");
+       for (j = 0; j < cl_hw->num_antennas; j++)
+               cl_snprintf(&buf, &len, &buf_size, "+----------");
+       cl_snprintf(&buf, &len, &buf_size, "|\n");
+
+       cl_snprintf(&buf, &len, &buf_size, "|AVG ");
+       for (j = 0; j < cl_hw->num_antennas; j++)
+               cl_snprintf(&buf, &len, &buf_size, "|%10lld", -avg_rssi[j]);
+       cl_snprintf(&buf, &len, &buf_size, "|\n");
+
+       cl_snprintf(&buf, &len, &buf_size, "|----");
+       for (j = 0; j < cl_hw->num_antennas; j++)
+               cl_snprintf(&buf, &len, &buf_size, "-----------");
+       cl_snprintf(&buf, &len, &buf_size, "|\n");
+
+out:
+       cl_vendor_reply(cl_hw, buf, len);
+       kfree(buf);
+}
+
+static void cl_stats_print_fec_coding(struct cl_hw *cl_hw, struct cl_sta *cl_sta)
+{
+       struct cl_stats *stats = cl_sta->stats;
+       char *buf = NULL;
+       ssize_t buf_size;
+       int len = 0;
+
+       cl_snprintf(&buf, &len, &buf_size,
+                   "\nSTA #%u, MAC %pM\n", cl_sta->sta_idx, cl_sta->addr);
+       cl_snprintf(&buf, &len, &buf_size,
+                   "BCC  = %u\n", stats->fec_coding[CL_FEC_CODING_BCC]);
+       cl_snprintf(&buf, &len, &buf_size,
+                   "LDPC = %u\n", stats->fec_coding[CL_FEC_CODING_LDPC]);
+
+       cl_vendor_reply(cl_hw, buf, len);
+       kfree(buf);
+}
+
+static void cl_stats_print_power_save(struct cl_hw *cl_hw, struct cl_sta *cl_sta)
+{
+       struct cl_ps_stats *ps_stats = &cl_sta->stats->ps;
+       char *buf = NULL;
+       ssize_t buf_size;
+       int len = 0;
+
+       cl_snprintf(&buf, &len, &buf_size,
+                   "\n");
+       cl_snprintf(&buf, &len, &buf_size,
+                   "STA #%u, MAC %pM\n", cl_sta->sta_idx, cl_sta->addr);
+       cl_snprintf(&buf, &len, &buf_size,
+                   "Current state = %s\n", ps_stats->is_ps ? "SLEEP" : "AWAKE");
+       cl_snprintf(&buf, &len, &buf_size,
+                   "|-------------------------|\n");
+       cl_snprintf(&buf, &len, &buf_size,
+                   "| Period     | Counter    |\n");
+       cl_snprintf(&buf, &len, &buf_size,
+                   "|-------------------------|\n");
+       cl_snprintf(&buf, &len, &buf_size,
+                   "| <= 50ms    | %10u |\n", ps_stats->period[PS_PERIOD_50MS]);
+       cl_snprintf(&buf, &len, &buf_size,
+                   "| <= 100ms   | %10u |\n", ps_stats->period[PS_PERIOD_100MS]);
+       cl_snprintf(&buf, &len, &buf_size,
+                   "| <= 250ms   | %10u |\n", ps_stats->period[PS_PERIOD_250MS]);
+       cl_snprintf(&buf, &len, &buf_size,
+                   "| <= 500ms   | %10u |\n", ps_stats->period[PS_PERIOD_500MS]);
+       cl_snprintf(&buf, &len, &buf_size,
+                   "| <= 750ms   | %10u |\n", ps_stats->period[PS_PERIOD_750MS]);
+       cl_snprintf(&buf, &len, &buf_size,
+                   "| <= 1000ms  | %10u |\n", ps_stats->period[PS_PERIOD_1000MS]);
+       cl_snprintf(&buf, &len, &buf_size,
+                   "| <= 2000ms  | %10u |\n", ps_stats->period[PS_PERIOD_2000MS]);
+       cl_snprintf(&buf, &len, &buf_size,
+                   "| <= 5000ms  | %10u |\n", ps_stats->period[PS_PERIOD_5000MS]);
+       cl_snprintf(&buf, &len, &buf_size,
+                   "| <= 10000ms | %10u |\n", ps_stats->period[PS_PERIOD_10000MS]);
+       cl_snprintf(&buf, &len, &buf_size,
+                   "|  > 10000ms | %10u |\n", ps_stats->period[PS_PERIOD_ABOVE]);
+       cl_snprintf(&buf, &len, &buf_size,
+                   "|-------------------------|\n");
+
+       cl_vendor_reply(cl_hw, buf, len);
+       kfree(buf);
+}
+
+static void _cl_stats_print_tx(char **buf, int *len, ssize_t *buf_size,
+                              struct cl_tx_cntrs *cntrs,
+                              const char *mode_str, const char *bw_str, const char *gi_str,
+                              u8 nss, u8 mcs, u8 bf,
+                              u64 *total_success, u64 *total_fail)
+{
+       u8 per = 0;
+
+       if (cntrs->fail == 0 && cntrs->success == 0)
+               return;
+
+       per = (u8)div64_u64(100 * (u64)cntrs->fail, cntrs->fail + cntrs->success);
+
+       cl_snprintf(buf, len, buf_size,
+                   "|%-8s|%-3s|%2u|%3u|%3s|%2u|%10u|%10u|%3u|\n",
+                   mode_str, bw_str, nss, mcs, gi_str, bf, cntrs->success, cntrs->fail, per);
+
+       *total_success += cntrs->success;
+       *total_fail += cntrs->fail;
+}
+
+static void cl_stats_print_tx_he(char **buf, int *len, ssize_t *buf_size,
+                                struct cl_stats *stats, u64 *total_success, u64 *total_fail)
+{
+       struct cl_tx_cntrs *cntrs;
+       u8 bw = 0, nss = 0, mcs = 0, gi = 0, bf = 0;
+
+       for (bw = 0; bw < CHNL_BW_MAX; bw++)
+               for (nss = 0; nss < WRS_SS_MAX; nss++)
+                       for (mcs = 0; mcs < WRS_MCS_MAX; mcs++)
+                               for (gi = 0; gi < WRS_GI_MAX; gi++)
+                                       for (bf = 0; bf < BF_IDX_MAX; bf++) {
+                                               cntrs = &stats->tx.he[bw][nss][mcs][gi][bf];
+                                               _cl_stats_print_tx(buf, len, buf_size,
+                                                                  cntrs,
+                                                                  "HE",
+                                                                  bw_str[bw], gi_he_str[gi],
+                                                                  nss, mcs, bf,
+                                                                  total_success, total_fail);
+                                       }
+}
+
+static void cl_stats_print_tx_vht(char **buf, int *len, ssize_t *buf_size,
+                                 struct cl_stats *stats, u64 *total_success, u64 *total_fail)
+{
+       struct cl_tx_cntrs *cntrs;
+       u8 bw = 0, nss = 0, mcs = 0, gi = 0, bf = 0;
+
+       for (bw = 0; bw < CHNL_BW_MAX_VHT; bw++)
+               for (nss = 0; nss < WRS_SS_MAX; nss++)
+                       for (mcs = 0; mcs < WRS_MCS_MAX_VHT; mcs++)
+                               for (gi = 0; gi < WRS_GI_MAX_VHT; gi++)
+                                       for (bf = 0; bf < BF_IDX_MAX; bf++) {
+                                               cntrs = &stats->tx.vht[bw][nss][mcs][gi][bf];
+                                               _cl_stats_print_tx(buf, len, buf_size,
+                                                                  cntrs,
+                                                                  "VHT",
+                                                                  bw_str[bw], gi_ht_vht_str[gi],
+                                                                  nss, mcs, bf,
+                                                                  total_success, total_fail);
+                                       }
+}
+
+static void cl_stats_print_tx_ht(char **buf, int *len, ssize_t *buf_size,
+                                struct cl_stats *stats, u64 *total_success, u64 *total_fail)
+{
+       struct cl_tx_cntrs *cntrs;
+       u8 bw = 0, nss = 0, mcs = 0, gi = 0;
+
+       for (bw = 0; bw < CHNL_BW_MAX_HT; bw++)
+               for (nss = 0; nss < WRS_SS_MAX; nss++)
+                       for (mcs = 0; mcs < WRS_MCS_MAX_HT; mcs++)
+                               for (gi = 0; gi < WRS_GI_MAX_HT; gi++) {
+                                       cntrs = &stats->tx.ht[bw][nss][mcs][gi];
+                                       _cl_stats_print_tx(buf, len, buf_size,
+                                                          cntrs,
+                                                          "HT",
+                                                          bw_str[bw], gi_ht_vht_str[gi],
+                                                          nss, mcs, 0,
+                                                          total_success, total_fail);
+                               }
+}
+
+static void cl_stats_print_tx_ofdm(char **buf, int *len, ssize_t *buf_size,
+                                  struct cl_stats *stats, u64 *total_success, u64 *total_fail)
+{
+       struct cl_tx_cntrs *cntrs;
+       u8 mcs;
+
+       for (mcs = 0; mcs < WRS_MCS_MAX_OFDM; mcs++) {
+               cntrs = &stats->tx.ofdm[mcs];
+               _cl_stats_print_tx(buf, len, buf_size,
+                                  cntrs,
+                                  "OFDM", bw_str[0], "0",
+                                  0, mcs, 0,
+                                  total_success, total_fail);
+       }
+}
+
+static void cl_stats_print_tx_cck(char **buf, int *len, ssize_t *buf_size,
+                                 struct cl_stats *stats, u64 *total_success, u64 *total_fail)
+{
+       struct cl_tx_cntrs *cntrs;
+       u8 mcs;
+
+       for (mcs = 0; mcs < WRS_MCS_MAX_CCK; mcs++) {
+               cntrs = &stats->tx.cck[mcs];
+               _cl_stats_print_tx(buf, len, buf_size,
+                                  cntrs,
+                                  "CCK", bw_str[0], "0",
+                                  0, mcs, 0,
+                                  total_success, total_fail);
+       }
+}
+
+static void cl_stats_print_tx(struct cl_hw *cl_hw, struct cl_sta *cl_sta)
+{
+       struct cl_stats *stats = cl_sta->stats;
+       u64 total_success = 0, total_fail = 0;
+       char *buf = NULL;
+       ssize_t buf_size;
+       int len = 0;
+
+       cl_snprintf(&buf, &len, &buf_size,
+                   "\nSTA #%u, MAC %pM\n", cl_sta->sta_idx, cl_sta->addr);
+       cl_snprintf(&buf, &len, &buf_size,
+                   "------------------------------------------------------\n");
+       cl_snprintf(&buf, &len, &buf_size,
+                   "|MODE    |BW |SS|MCS|GI |BF| Success  |   Fail   |PER|\n");
+       cl_snprintf(&buf, &len, &buf_size,
+                   "|--------+---+--+---+---+--+----------+----------+---|\n");
+
+       cl_stats_print_tx_he(&buf, &len, &buf_size, stats, &total_success, &total_fail);
+       cl_stats_print_tx_vht(&buf, &len, &buf_size, stats, &total_success, &total_fail);
+       cl_stats_print_tx_ht(&buf, &len, &buf_size, stats, &total_success, &total_fail);
+       cl_stats_print_tx_ofdm(&buf, &len, &buf_size, stats, &total_success, &total_fail);
+       cl_stats_print_tx_cck(&buf, &len, &buf_size, stats, &total_success, &total_fail);
+
+       cl_snprintf(&buf, &len, &buf_size,
+                   "------------------------------------------------------\n");
+       cl_snprintf(&buf, &len, &buf_size,
+                   "                           |%10llu|%10llu|\n", total_success, total_fail);
+       cl_snprintf(&buf, &len, &buf_size,
+                   "                           -----------------------\n");
+       cl_snprintf(&buf, &len, &buf_size,
+                   "\n");
+
+       cl_vendor_reply(cl_hw, buf, len);
+       kfree(buf);
+}
+
+static void _cl_stats_print_rx(struct cl_hw *cl_hw, struct cl_rx_stats *rx_stats,
+                              struct cl_sta *cl_sta)
+{
+       u8 mode = 0, mcs = 0, nss = 0, bw = 0, gi = 0, flag = rx_stats->flag;
+       u16 data_rate = 0, data_rate_div_10 = 0, data_rate_mod_10 = 0;
+       u64 remainder = 0, packets = 0, total_packets[WRS_MODE_MAX] = {0},
+               total_data_rate[WRS_MODE_MAX] = {0}, equivalent_data_rate = 0;
+       char *buf = NULL;
+       ssize_t buf_size;
+       int len = 0;
+
+       if (cl_sta)
+               cl_snprintf(&buf, &len, &buf_size,
+                           "\nSTA #%u, MAC %pM\n",
+                           cl_sta->sta_idx, cl_sta->addr);
+
+       cl_snprintf(&buf, &len, &buf_size,
+                   "-------------------------------------------------------\n");
+       cl_snprintf(&buf, &len, &buf_size,
+                   "|  MODE   | BW | SS | MCS | GI | Data-Rate | #Packets |\n");
+       cl_snprintf(&buf, &len, &buf_size,
+                   "|---------+----+----+-----+----+-----------+----------|\n");
+
+       if ((flag & RX_STATS_HE_TRIG) == 0)
+               goto stats_he_ext;
+
+       for (bw = 0; bw < CHNL_BW_MAX_HE; bw++) {
+               for (nss = 0; nss < WRS_SS_MAX; nss++) {
+                       for (mcs = 0; mcs < WRS_MCS_MAX_HE; mcs++) {
+                               for (gi = 0; gi < WRS_GI_MAX_HE; gi++) {
+                                       packets = rx_stats->he_trig[bw][nss][mcs][gi];
+
+                                       if (packets == 0)
+                                               continue;
+
+                                       data_rate = cl_data_rates_get_x10(WRS_MODE_HE, bw,
+                                                                         nss, mcs, gi);
+                                       data_rate_div_10 = data_rate / 10;
+                                       data_rate_mod_10 = data_rate % 10;
+
+                                       total_packets[WRS_MODE_HE] += packets;
+                                       total_data_rate[WRS_MODE_HE] += (packets * data_rate);
+
+                                       cl_snprintf(&buf, &len, &buf_size,
+                                                   "| HE_TRIG |%4u|%4u|%5u|%4s| %7u.%u |%10llu|\n",
+                                                   BW_TO_MHZ(bw), nss, mcs, gi_he_str[gi],
+                                                   data_rate_div_10, data_rate_mod_10, packets);
+                               }
+                       }
+               }
+       }
+
+stats_he_ext:
+       if ((flag & RX_STATS_HE_EXT) == 0)
+               goto stats_he_mu;
+
+       for (bw = 0; bw < CHNL_BW_MAX_HE; bw++) {
+               for (nss = 0; nss < WRS_SS_MAX; nss++) {
+                       for (mcs = 0; mcs < WRS_MCS_MAX_HE; mcs++) {
+                               for (gi = 0; gi < WRS_GI_MAX_HE; gi++) {
+                                       packets = rx_stats->he_ext[bw][nss][mcs][gi];
+
+                                       if (packets == 0)
+                                               continue;
+
+                                       data_rate = cl_data_rates_get_x10(WRS_MODE_HE, bw,
+                                                                         nss, mcs, gi);
+                                       data_rate_div_10 = data_rate / 10;
+                                       data_rate_mod_10 = data_rate % 10;
+
+                                       total_packets[WRS_MODE_HE] += packets;
+                                       total_data_rate[WRS_MODE_HE] += (packets * data_rate);
+
+                                       cl_snprintf(&buf, &len, &buf_size,
+                                                   "| HE_EXT  |%4u|%4u|%5u|%4s| %7u.%u |%10llu|\n",
+                                                   BW_TO_MHZ(bw), nss, mcs, gi_he_str[gi],
+                                                   data_rate_div_10, data_rate_mod_10, packets);
+                               }
+                       }
+               }
+       }
+
+stats_he_mu:
+       if ((flag & RX_STATS_HE_MU) == 0)
+               goto stats_he_su;
+
+       for (bw = 0; bw < CHNL_BW_MAX_HE; bw++) {
+               for (nss = 0; nss < WRS_SS_MAX; nss++) {
+                       for (mcs = 0; mcs < WRS_MCS_MAX_HE; mcs++) {
+                               for (gi = 0; gi < WRS_GI_MAX_HE; gi++) {
+                                       packets = rx_stats->he_mu[bw][nss][mcs][gi];
+
+                                       if (packets == 0)
+                                               continue;
+
+                                       data_rate = cl_data_rates_get_x10(WRS_MODE_HE, bw,
+                                                                         nss, mcs, gi);
+                                       data_rate_div_10 = data_rate / 10;
+                                       data_rate_mod_10 = data_rate % 10;
+
+                                       total_packets[WRS_MODE_HE] += packets;
+                                       total_data_rate[WRS_MODE_HE] += (packets * data_rate);
+
+                                       cl_snprintf(&buf, &len, &buf_size,
+                                                   "| HE_MU   |%4u|%4u|%5u|%4s| %7u.%u |%10llu|\n",
+                                                   BW_TO_MHZ(bw), nss, mcs, gi_he_str[gi],
+                                                   data_rate_div_10, data_rate_mod_10, packets);
+                               }
+                       }
+               }
+       }
+
+stats_he_su:
+       if ((flag & RX_STATS_HE_SU) == 0)
+               goto stats_vht;
+
+       for (bw = 0; bw < CHNL_BW_MAX_HE; bw++) {
+               for (nss = 0; nss < WRS_SS_MAX; nss++) {
+                       for (mcs = 0; mcs < WRS_MCS_MAX_HE; mcs++) {
+                               for (gi = 0; gi < WRS_GI_MAX_HE; gi++) {
+                                       packets = rx_stats->he_su[bw][nss][mcs][gi];
+
+                                       if (packets == 0)
+                                               continue;
+
+                                       data_rate = cl_data_rates_get_x10(WRS_MODE_HE, bw,
+                                                                         nss, mcs, gi);
+                                       data_rate_div_10 = data_rate / 10;
+                                       data_rate_mod_10 = data_rate % 10;
+
+                                       total_packets[WRS_MODE_HE] += packets;
+                                       total_data_rate[WRS_MODE_HE] += (packets * data_rate);
+
+                                       cl_snprintf(&buf, &len, &buf_size,
+                                                   "| HE_SU   |%4u|%4u|%5u|%4s| %7u.%u |%10llu|\n",
+                                                   BW_TO_MHZ(bw), nss, mcs, gi_he_str[gi],
+                                                   data_rate_div_10, data_rate_mod_10, packets);
+                               }
+                       }
+               }
+       }
+
+stats_vht:
+       if ((flag & RX_STATS_VHT) == 0)
+               goto stats_ht;
+
+       for (bw = 0; bw < CHNL_BW_MAX_VHT; bw++) {
+               for (nss = 0; nss < WRS_SS_MAX; nss++) {
+                       for (mcs = 0; mcs < WRS_MCS_MAX_VHT; mcs++) {
+                               for (gi = 0; gi < WRS_GI_MAX_VHT; gi++) {
+                                       packets = rx_stats->vht[bw][nss][mcs][gi];
+
+                                       if (packets == 0)
+                                               continue;
+
+                                       data_rate = cl_data_rates_get_x10(WRS_MODE_VHT,
+                                                                         bw, nss, mcs, gi);
+                                       data_rate_div_10 = data_rate / 10;
+                                       data_rate_mod_10 = data_rate % 10;
+
+                                       total_packets[WRS_MODE_VHT] += packets;
+                                       total_data_rate[WRS_MODE_VHT] += (packets * data_rate);
+
+                                       cl_snprintf(&buf, &len, &buf_size,
+                                                   "| VHT     |%4u|%4u|%5u|%4s| %7u.%u |%10llu|\n",
+                                                   BW_TO_MHZ(bw), nss, mcs, gi_ht_vht_str[gi],
+                                                   data_rate_div_10, data_rate_mod_10, packets);
+                               }
+                       }
+               }
+       }
+
+stats_ht:
+       if ((flag & RX_STATS_HT) == 0)
+               goto stats_ofdm;
+
+       for (bw = 0; bw < CHNL_BW_MAX_HT; bw++) {
+               for (nss = 0; nss < WRS_SS_MAX; nss++) {
+                       for (mcs = 0; mcs < WRS_MCS_MAX_HT; mcs++) {
+                               for (gi = 0; gi < WRS_GI_MAX_HT; gi++) {
+                                       packets = rx_stats->ht[bw][nss][mcs][gi];
+
+                                       if (packets == 0)
+                                               continue;
+
+                                       data_rate = cl_data_rates_get_x10(WRS_MODE_HT,
+                                                                         bw, nss, mcs, gi);
+                                       data_rate_div_10 = data_rate / 10;
+                                       data_rate_mod_10 = data_rate % 10;
+
+                                       total_packets[WRS_MODE_HT] += packets;
+                                       total_data_rate[WRS_MODE_HT] += (packets * data_rate);
+
+                                       cl_snprintf(&buf, &len, &buf_size,
+                                                   "| HT      |%4u|%4u|%5u|%4s| %7u.%u |%10llu|\n",
+                                                   BW_TO_MHZ(bw), nss, mcs, gi_ht_vht_str[gi],
+                                                   data_rate_div_10, data_rate_mod_10, packets);
+                               }
+                       }
+               }
+       }
+
+stats_ofdm:
+       if ((flag & RX_STATS_OFDM) == 0)
+               goto stats_cck;
+
+       for (mcs = 0; mcs < WRS_MCS_MAX_OFDM; mcs++) {
+               packets = rx_stats->ofdm[mcs];
+
+               if (packets == 0)
+                       continue;
+
+               data_rate = cl_data_rates_get_x10(WRS_MODE_OFDM, 0, 0, mcs, 0);
+               data_rate_div_10 = data_rate / 10;
+               data_rate_mod_10 = data_rate % 10;
+
+               total_packets[WRS_MODE_OFDM] += packets;
+               total_data_rate[WRS_MODE_OFDM] += (packets * data_rate);
+
+               cl_snprintf(&buf, &len, &buf_size,
+                           "| OFDM    |  20|   0|%5u|   0| %7u.%u |%10llu|\n",
+                           mcs, data_rate_div_10, data_rate_mod_10, packets);
+       }
+
+stats_cck:
+       if ((flag & RX_STATS_CCK) == 0)
+               goto stats_end;
+
+       for (mcs = 0; mcs < WRS_MCS_MAX_CCK; mcs++) {
+               packets = rx_stats->cck[mcs];
+
+               if (packets == 0)
+                       continue;
+
+               data_rate = cl_data_rates_get_x10(WRS_MODE_CCK, 0, 0, mcs, 0);
+               data_rate_div_10 = data_rate / 10;
+               data_rate_mod_10 = data_rate % 10;
+
+               total_packets[WRS_MODE_CCK] += packets;
+               total_data_rate[WRS_MODE_CCK] += (packets * data_rate);
+
+               cl_snprintf(&buf, &len, &buf_size,
+                           "| CCK     |  20|   0|%5u|   0| %7u.%u |%10llu|\n",
+                           mcs, data_rate_div_10, data_rate_mod_10, packets);
+       }
+
+stats_end:
+       cl_snprintf(&buf, &len, &buf_size,
+                   "-------------------------------------------------------\n");
+
+       for (mode = 0; mode < WRS_MODE_MAX; mode++) {
+               if (total_packets[mode] == 0)
+                       continue;
+
+               equivalent_data_rate = div64_u64(total_data_rate[mode], total_packets[mode]);
+               data_rate_div_10 = (u16)div64_u64_rem(equivalent_data_rate, 10, &remainder);
+
+               cl_snprintf(&buf, &len, &buf_size,
+                           "%s: Equivalent data rate = %u.%u Mbps\n\n",
+                           WRS_MODE_STR(mode), data_rate_div_10, (u16)remainder);
+       }
+
+       cl_vendor_reply(cl_hw, buf, len);
+       kfree(buf);
+}
+
+static void cl_stats_print_rx(struct cl_hw *cl_hw, struct cl_sta *cl_sta)
+{
+       if (cl_hw->chip->conf->ce_production_mode)
+               _cl_stats_print_rx(cl_hw, cl_hw->rx_stats, NULL);
+       else
+               _cl_stats_print_rx(cl_hw, &cl_sta->stats->rx, cl_sta);
+}
+
+static void cl_stats_print_cpu(struct cl_hw *cl_hw)
+{
+       u32 cpu = 0;
+       char *buf = NULL;
+       ssize_t buf_size;
+       int len = 0;
+       struct cl_cpu_cntr *cpu_cntr = &cl_hw->cpu_cntr;
+
+       cl_snprintf(&buf, &len, &buf_size, "|-------------------------|\n");
+       cl_snprintf(&buf, &len, &buf_size, "|CPU|Tx Agg    |Tx Single |\n");
+       cl_snprintf(&buf, &len, &buf_size, "|---+----------+----------|\n");
+
+       for (cpu = 0; cpu < CPU_MAX_NUM; cpu++) {
+               if (cpu_cntr->tx_agg[cpu] == 0 && cpu_cntr->tx_single[cpu] == 0)
+                       continue;
+
+               cl_snprintf(&buf, &len, &buf_size, "| %u |%10u|%10u|\n",
+                           cpu,
+                           cpu_cntr->tx_agg[cpu],
+                           cpu_cntr->tx_single[cpu]);
+       }
+
+       cl_snprintf(&buf, &len, &buf_size, "|-------------------------|\n");
+
+       cl_vendor_reply(cl_hw, buf, len);
+       kfree(buf);
+}
+
+static void cl_sta_print_do(struct cl_hw *cl_hw, u8 sta_idx, stats_callback callback)
+{
+       struct cl_sta *cl_sta;
+
+       cl_sta_lock(cl_hw);
+
+       cl_sta = cl_sta_get(cl_hw, sta_idx);
+       if (cl_sta)
+               callback(cl_hw, cl_sta);
+
+       cl_sta_unlock(cl_hw);
+}
+
+static void cl_stats_cli_cpu(struct cl_hw *cl_hw, bool action)
+{
+       if (action)
+               cl_stats_print_cpu(cl_hw);
+       else
+               memset(&cl_hw->cpu_cntr, 0, sizeof(struct cl_cpu_cntr));
+}
+
+static void cl_stats_cli_rx_info(struct cl_hw *cl_hw, bool action)
+{
+       if (action)
+               cl_rx_info_print(cl_hw);
+       else
+               cl_rx_info_reset(cl_hw);
+}
+
+static void cll_stats_config_ps(struct cl_sta *cl_sta)
+{
+       cl_sta->stats->ps.timestamp_sleep = jiffies;
+       cl_sta->stats->ps.is_ps = test_sta_flag(cl_sta->stainfo, WLAN_STA_PS_STA) ? true : false;
+}
+
+static void cl_stats_free(struct cl_hw *cl_hw, struct cl_sta *cl_sta)
+{
+       kfree(cl_sta->stats);
+       cl_sta->stats = NULL;
+}
+
+static void cl_stats_disable(struct cl_hw *cl_hw)
+{
+       pr_debug("Statistics disabled\n");
+       cl_hw->conf->ci_stats_en = false;
+       cl_sta_loop(cl_hw, cl_stats_free);
+
+       if (cl_hw->chip->conf->ce_production_mode) {
+               kfree(cl_hw->rx_stats);
+               cl_hw->rx_stats = NULL;
+       }
+}
+
+static void cl_stats_enable(struct cl_hw *cl_hw)
+{
+       /*
+        * Allocate for all existing stations.
+        * If one of the allocations fails disable ci_stats_en (and free the
+        * stations that were already allocated).
+        * In production mode also allocate cl_hw->rx_stats
+        */
+       struct cl_sta *cl_sta = NULL;
+       bool success = true;
+
+       if (cl_hw->chip->conf->ce_production_mode) {
+               cl_hw->rx_stats = kzalloc(sizeof(*cl_hw->rx_stats), GFP_ATOMIC);
+
+               if (!cl_hw->rx_stats)
+                       goto out;
+       }
+
+       read_lock(&cl_hw->cl_sta_db.lock);
+
+       list_for_each_entry(cl_sta, &cl_hw->cl_sta_db.head, list) {
+               cl_sta->stats = kzalloc(sizeof(*cl_sta->stats), GFP_ATOMIC);
+
+               if (cl_sta->stats) {
+                       cll_stats_config_ps(cl_sta);
+               } else {
+                       success = false;
+                       break;
+               }
+       }
+
+       if (success) {
+               pr_debug("Statistics enabled\n");
+               cl_hw->conf->ci_stats_en = true;
+       } else {
+               list_for_each_entry(cl_sta, &cl_hw->cl_sta_db.head, list)
+                       cl_stats_free(cl_hw, cl_sta);
+       }
+
+out:
+       read_unlock(&cl_hw->cl_sta_db.lock);
+}
+
+static void cl_stats_cli_enable(struct cl_hw *cl_hw, bool enable)
+{
+       spin_lock_bh(&cl_hw->lock_stats);
+
+       if (enable == cl_hw->conf->ci_stats_en) {
+               pr_debug("Statistics are already %s\n", enable ? "Enabled" : "Disabled");
+               goto out;
+       }
+
+       if (enable)
+               cl_stats_enable(cl_hw);
+       else
+               cl_stats_disable(cl_hw);
+
+out:
+       spin_unlock_bh(&cl_hw->lock_stats);
+}
+
+static void cl_stats_cli_rx(struct cl_hw *cl_hw, u8 sta_idx)
+{
+       spin_lock_bh(&cl_hw->lock_stats);
+
+       if (!cl_hw->conf->ci_stats_en)
+               goto out;
+
+       if (cl_hw->chip->conf->ce_production_mode) {
+               cl_stats_print_rx(cl_hw, NULL);
+       } else {
+               if (sta_idx == STA_IDX_INVALID)
+                       cl_sta_loop(cl_hw, cl_stats_print_rx);
+               else
+                       cl_sta_print_do(cl_hw, sta_idx, cl_stats_print_rx);
+       }
+
+out:
+       spin_unlock_bh(&cl_hw->lock_stats);
+}
+
+static void cl_stats_cli_rssi(struct cl_hw *cl_hw, u8 sta_idx)
+{
+       spin_lock_bh(&cl_hw->lock_stats);
+
+       if (!cl_hw->conf->ci_stats_en)
+               goto out;
+
+       if (sta_idx == STA_IDX_INVALID)
+               cl_sta_loop(cl_hw, cl_stats_print_rssi);
+       else
+               cl_sta_print_do(cl_hw, sta_idx, cl_stats_print_rssi);
+
+out:
+       spin_unlock_bh(&cl_hw->lock_stats);
+}
+
+static void cl_stats_cli_fec_coding(struct cl_hw *cl_hw, u8 sta_idx)
+{
+       spin_lock_bh(&cl_hw->lock_stats);
+
+       if (!cl_hw->conf->ci_stats_en)
+               goto out;
+
+       if (sta_idx == STA_IDX_INVALID)
+               cl_sta_loop(cl_hw, cl_stats_print_fec_coding);
+       else
+               cl_sta_print_do(cl_hw, sta_idx, cl_stats_print_fec_coding);
+
+out:
+       spin_unlock_bh(&cl_hw->lock_stats);
+}
+
+static void cl_stats_cli_ps(struct cl_hw *cl_hw, u8 sta_idx)
+{
+       spin_lock_bh(&cl_hw->lock_stats);
+
+       if (!cl_hw->conf->ci_stats_en)
+               goto out;
+
+       if (sta_idx == STA_IDX_INVALID)
+               cl_sta_loop(cl_hw, cl_stats_print_power_save);
+       else
+               cl_sta_print_do(cl_hw, sta_idx, cl_stats_print_power_save);
+
+out:
+       spin_unlock_bh(&cl_hw->lock_stats);
+}
+
+static void cl_stats_cli_tx(struct cl_hw *cl_hw, u8 sta_idx)
+{
+       spin_lock_bh(&cl_hw->lock_stats);
+
+       if (!cl_hw->conf->ci_stats_en)
+               goto out;
+
+       if (sta_idx == STA_IDX_INVALID)
+               cl_sta_loop(cl_hw, cl_stats_print_tx);
+       else
+               cl_sta_print_do(cl_hw, sta_idx, cl_stats_print_tx);
+
+out:
+       spin_unlock_bh(&cl_hw->lock_stats);
+}
+
+static void cl_stats_cli_reset(struct cl_hw *cl_hw, u8 sta_idx)
+{
+       spin_lock_bh(&cl_hw->lock_stats);
+
+       if (!cl_hw->conf->ci_stats_en)
+               goto out;
+
+       if (cl_hw->chip->conf->ce_production_mode) {
+               memset(cl_hw->rx_stats, 0, sizeof(struct cl_rx_stats));
+       } else {
+               if (sta_idx == STA_IDX_INVALID)
+                       cl_sta_loop(cl_hw, cl_stats_sta_reset);
+               else
+                       cl_sta_print_do(cl_hw, sta_idx, cl_stats_sta_reset);
+       }
+
+out:
+       spin_unlock_bh(&cl_hw->lock_stats);
+}
+
+static int cl_stats_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,
+                "stats usage:\n"
+                "-a : Print air PER and system PER [delay-ms)]\n"
+                "-b : CPU stats [0-reset, 1-print]\n"
+                "-e : Enable/Disable statistics [0-dis, 1-en]\n"
+                "-f : Print RX FEC coding counters [sta_idx]\n"
+                "-p : Print power-save statistics [sta_idx]\n"
+                "-r : Print RX stats table [sta_idx]\n"
+                "-s : Print RSSI stats tables [sta_idx]\n"
+                "-t : Print TX stats table [sta_idx]\n"
+                "-u : Uplink stats [0-reset, 1-print]\n"
+                "-z : Reset stats tables [sta_idx]\n");
+
+       err = cl_vendor_reply(cl_hw, buf, strlen(buf));
+       kfree(buf);
+
+       return err;
+}
+
+static void _cl_stats_update_tx(struct cl_hw *cl_hw, struct cl_sta *cl_sta,
+                               struct cl_agg_tx_report *agg_report)
+{
+       struct cl_stats *stats = cl_sta->stats;
+       struct cl_tx_cntrs *cntrs;
+       union cl_rate_ctrl_info rate_ctrl_info = {.word = agg_report->rate_cntrl_info};
+       u8 bw, nss, mcs, gi, bf;
+
+       switch (rate_ctrl_info.field.format_mod) {
+       case WRS_MODE_HE:
+               nss = (rate_ctrl_info.field.mcs_index >> 4);
+               mcs = (rate_ctrl_info.field.mcs_index & 0xF);
+               gi = rate_ctrl_info.field.gi;
+               bw = rate_ctrl_info.field.bw;
+               bf = agg_report->bf;
+               cntrs = &stats->tx.he[bw][nss][mcs][gi][bf];
+               break;
+       case WRS_MODE_VHT:
+               bw = rate_ctrl_info.field.bw;
+               nss = (rate_ctrl_info.field.mcs_index >> 4);
+               mcs = (rate_ctrl_info.field.mcs_index & 0xF);
+               gi = rate_ctrl_info.field.gi;
+               bf = agg_report->bf;
+               cntrs = &stats->tx.vht[bw][nss][mcs][gi][bf];
+               break;
+       case WRS_MODE_HT:
+               bw = rate_ctrl_info.field.bw;
+               nss = (rate_ctrl_info.field.mcs_index >> 3);
+               mcs = (rate_ctrl_info.field.mcs_index & 0x7);
+               gi = rate_ctrl_info.field.gi;
+               cntrs = &stats->tx.ht[bw][nss][mcs][gi];
+               break;
+       case WRS_MODE_OFDM:
+               mcs = rate_ctrl_info.field.mcs_index - RATE_CTRL_OFFSET_OFDM;
+               cntrs = &stats->tx.ofdm[mcs];
+               break;
+       case WRS_MODE_CCK:
+               mcs = rate_ctrl_info.field.mcs_index;
+               cntrs = &stats->tx.cck[mcs];
+               break;
+       default:
+               return;
+       }
+
+       cntrs->success += agg_report->success;
+       cntrs->fail += agg_report->fail;
+}
+
+void cl_stats_init(struct cl_hw *cl_hw)
+{
+       spin_lock_init(&cl_hw->lock_stats);
+
+       if (cl_hw->conf->ci_stats_en && cl_hw->chip->conf->ce_production_mode) {
+               cl_hw->rx_stats = kzalloc(sizeof(*cl_hw->rx_stats), GFP_ATOMIC);
+
+               if (!cl_hw->rx_stats)
+                       cl_hw->conf->ci_stats_en = false;
+       }
+}
+
+void cl_stats_deinit(struct cl_hw *cl_hw)
+{
+       spin_lock_bh(&cl_hw->lock_stats);
+
+       if (cl_hw->conf->ci_stats_en && cl_hw->chip->conf->ce_production_mode) {
+               cl_hw->conf->ci_stats_en = false;
+
+               kfree(cl_hw->rx_stats);
+               cl_hw->rx_stats = NULL;
+       }
+
+       spin_unlock_bh(&cl_hw->lock_stats);
+}
+
+void cl_stats_sta_add(struct cl_hw *cl_hw, struct cl_sta *cl_sta)
+{
+       /* If allocation failed disable ci_stats_en, and free the memory of all other stations */
+       bool disable = false;
+
+       /* Take regular lock and not BH, because cl_sta_add_to_lut() already disables BH */
+       spin_lock(&cl_hw->lock_stats);
+
+       if (cl_hw->conf->ci_stats_en) {
+               cl_sta->stats = kzalloc(sizeof(*cl_sta->stats), GFP_ATOMIC);
+
+               if (cl_sta->stats)
+                       cll_stats_config_ps(cl_sta);
+               else
+                       disable = true;
+       }
+
+       spin_unlock(&cl_hw->lock_stats);
+
+       if (disable)
+               cl_stats_cli_enable(cl_hw, false);
+}
+
+void cl_stats_sta_remove(struct cl_hw *cl_hw, struct cl_sta *cl_sta)
+{
+       spin_lock_bh(&cl_hw->lock_stats);
+
+       if (cl_hw->conf->ci_stats_en)
+               cl_stats_free(cl_hw, cl_sta);
+
+       spin_unlock_bh(&cl_hw->lock_stats);
+}
+
+void cl_stats_update_tx_agg(struct cl_hw *cl_hw, struct cl_sta *cl_sta,
+                           struct cl_agg_tx_report *agg_report)
+{
+       spin_lock(&cl_hw->lock_stats);
+
+       if (cl_hw->conf->ci_stats_en) {
+               struct cl_stats *stats = cl_sta->stats;
+
+               stats->tx.agg_cntr++;
+               stats->tx.fail_cntr += agg_report->fail;
+               _cl_stats_update_tx(cl_hw, cl_sta, agg_report);
+       }
+
+       spin_unlock(&cl_hw->lock_stats);
+}
+
+void cl_stats_update_tx_single(struct cl_hw *cl_hw, struct cl_sta *cl_sta,
+                              struct cl_agg_tx_report *agg_report)
+{
+       spin_lock(&cl_hw->lock_stats);
+
+       if (cl_hw->conf->ci_stats_en) {
+               cl_sta->stats->tx.fail_cntr += agg_report->fail;
+               _cl_stats_update_tx(cl_hw, cl_sta, agg_report);
+       }
+
+       spin_unlock(&cl_hw->lock_stats);
+}
+
+void cl_stats_update_rx_rssi(struct cl_hw *cl_hw, struct cl_sta *cl_sta, s8 rssi[MAX_ANTENNAS])
+{
+       int i;
+       s8 rx_rssi;
+
+       spin_lock(&cl_hw->lock_stats);
+
+       if (!cl_hw->conf->ci_stats_en)
+               goto out;
+
+       for (i = 0; i < cl_hw->num_antennas; i++) {
+               rx_rssi = rssi[i] * -1;
+
+               if (rx_rssi >= 0 && rx_rssi < RSSI_ARR_SIZE)
+                       cl_sta->stats->rssi[rx_rssi][i]++;
+       }
+
+out:
+       spin_unlock(&cl_hw->lock_stats);
+}
+
+void _cl_stats_update_rx_rate(struct cl_hw *cl_hw, struct cl_rx_stats *rx_stats,
+                             struct hw_rxhdr *rxhdr)
+{
+       u8 bw, nss, mcs, gi;
+
+       switch (rxhdr->format_mod) {
+       case FORMATMOD_HE_TRIG:
+               nss = rxhdr->n_sts & 0x3;
+               mcs = min_t(u8, rxhdr->mcs, WRS_MCS_MAX_HE);
+               gi = min_t(u8, rxhdr->gi_type, WRS_GI_MAX_HE);
+               rx_stats->he_trig[rxhdr->ch_bw][nss][mcs][gi] += rxhdr->frm_successful_rx;
+               rx_stats->flag |= RX_STATS_HE_TRIG;
+               break;
+       case FORMATMOD_HE_EXT:
+               nss = rxhdr->n_sts & 0x3;
+               mcs = min_t(u8, rxhdr->mcs, WRS_MCS_MAX_HE);
+               gi = min_t(u8, rxhdr->gi_type, WRS_GI_MAX_HE);
+               rx_stats->he_ext[rxhdr->ch_bw][nss][mcs][gi] += rxhdr->frm_successful_rx;
+               rx_stats->flag |= RX_STATS_HE_EXT;
+               break;
+       case FORMATMOD_HE_MU:
+               nss = rxhdr->n_sts & 0x3;
+               mcs = min_t(u8, rxhdr->mcs, WRS_MCS_MAX_HE);
+               gi = min_t(u8, rxhdr->gi_type, WRS_GI_MAX_HE);
+               rx_stats->he_mu[rxhdr->ch_bw][nss][mcs][gi] += rxhdr->frm_successful_rx;
+               rx_stats->flag |= RX_STATS_HE_MU;
+               break;
+       case FORMATMOD_HE_SU:
+               nss = rxhdr->n_sts & 0x3;
+               mcs = min_t(u8, rxhdr->mcs, WRS_MCS_MAX_HE);
+               gi = min_t(u8, rxhdr->gi_type, WRS_GI_MAX_HE);
+               rx_stats->he_su[rxhdr->ch_bw][nss][mcs][gi] += rxhdr->frm_successful_rx;
+               rx_stats->flag |= RX_STATS_HE_SU;
+               break;
+       case FORMATMOD_VHT:
+               nss = rxhdr->n_sts & 0x3;
+               mcs = min_t(u8, rxhdr->mcs, WRS_MCS_MAX_VHT);
+               gi = rxhdr->gi_type & 0x1;
+               rx_stats->vht[rxhdr->ch_bw][nss][mcs][gi] += rxhdr->frm_successful_rx;
+               rx_stats->flag |= RX_STATS_VHT;
+               break;
+       case FORMATMOD_HT_MF:
+       case FORMATMOD_HT_GF:
+               bw = rxhdr->ch_bw & 0x1;
+               nss = (rxhdr->mcs >> 3) & 0x3;
+               mcs = rxhdr->mcs & 0x7;
+               gi = rxhdr->gi_type & 0x1;
+               rx_stats->ht[bw][nss][mcs][gi] += rxhdr->frm_successful_rx;
+               rx_stats->flag |= RX_STATS_HT;
+               break;
+       case FORMATMOD_NON_HT:
+               if (rxhdr->mcs >= RATE_CTRL_OFFSET_OFDM) {
+                       mcs = (rxhdr->mcs - RATE_CTRL_OFFSET_OFDM) & 0x7;
+                       rx_stats->ofdm[mcs] += rxhdr->frm_successful_rx;
+                       rx_stats->flag |= RX_STATS_OFDM;
+               } else if (cl_band_is_24g(cl_hw)) {
+                       mcs = rxhdr->mcs & 0x3;
+                       rx_stats->cck[mcs] += rxhdr->frm_successful_rx;
+                       rx_stats->flag |= RX_STATS_CCK;
+               }
+               break;
+       }
+}
+
+void cl_stats_update_rx_rate(struct cl_hw *cl_hw, struct cl_sta *cl_sta, struct hw_rxhdr *rxhdr)
+{
+       spin_lock(&cl_hw->lock_stats);
+
+       if (cl_hw->conf->ci_stats_en) {
+               _cl_stats_update_rx_rate(cl_hw, &cl_sta->stats->rx, rxhdr);
+               cl_sta->stats->fec_coding[rxhdr->fec_coding]++;
+       }
+
+       spin_unlock(&cl_hw->lock_stats);
+}
+
+void cl_stats_update_rx_rate_production(struct cl_hw *cl_hw, struct hw_rxhdr *rxhdr)
+{
+       spin_lock(&cl_hw->lock_stats);
+
+       if (cl_hw->conf->ci_stats_en)
+               _cl_stats_update_rx_rate(cl_hw, cl_hw->rx_stats, rxhdr);
+
+       spin_unlock(&cl_hw->lock_stats);
+}
+
+void cl_stats_update_ps(struct cl_hw *cl_hw, struct cl_sta *cl_sta, bool is_ps)
+{
+       struct cl_ps_stats *ps;
+
+       spin_lock(&cl_hw->lock_stats);
+
+       if (!cl_hw->conf->ci_stats_en)
+               goto out;
+
+       ps = &cl_sta->stats->ps;
+
+       if (ps->is_ps == is_ps)
+               goto out;
+
+       ps->is_ps = is_ps;
+
+       if (is_ps) {
+               ps->timestamp_sleep = jiffies;
+       } else {
+               unsigned long sleep_time = jiffies_to_msecs(jiffies - ps->timestamp_sleep);
+
+               if (sleep_time <= 50)
+                       ps->period[PS_PERIOD_50MS]++;
+               else if (sleep_time <= 100)
+                       ps->period[PS_PERIOD_100MS]++;
+               else if (sleep_time <= 250)
+                       ps->period[PS_PERIOD_250MS]++;
+               else if (sleep_time <= 500)
+                       ps->period[PS_PERIOD_500MS]++;
+               else if (sleep_time <= 750)
+                       ps->period[PS_PERIOD_750MS]++;
+               else if (sleep_time <= 1000)
+                       ps->period[PS_PERIOD_1000MS]++;
+               else if (sleep_time <= 2000)
+                       ps->period[PS_PERIOD_2000MS]++;
+               else if (sleep_time <= 5000)
+                       ps->period[PS_PERIOD_5000MS]++;
+               else if (sleep_time <= 10000)
+                       ps->period[PS_PERIOD_10000MS]++;
+               else
+                       ps->period[PS_PERIOD_ABOVE]++;
+       }
+
+out:
+       spin_unlock(&cl_hw->lock_stats);
+}
+
+int cl_stats_cli(struct cl_hw *cl_hw, struct cl_vif *cl_vif, struct cli_params *cli_params)
+{
+       bool print_per = false;
+       bool cpu_stats = false;
+       bool enable_tx_rx_rssi = false;
+       bool print_rx = false;
+       bool print_rssi = false;
+       bool print_fec_coding = false;
+       bool print_power_save = false;
+       bool print_tx = false;
+       bool uplink_stats = false;
+       bool reset_stats = false;
+       u32 expected_params = -1;
+
+       switch (cli_params->option) {
+       case 'a':
+               print_per = true;
+               expected_params = 1;
+               break;
+       case 'b':
+               cpu_stats = true;
+               expected_params = 1;
+               break;
+       case 'e':
+               enable_tx_rx_rssi = true;
+               expected_params = 1;
+               break;
+       case 'f':
+               print_fec_coding = true;
+               expected_params = 1;
+               break;
+       case 'p':
+               print_power_save = true;
+               expected_params = 1;
+               break;
+       case 't':
+               print_tx = true;
+               expected_params = 1;
+               break;
+       case 'r':
+               print_rx = true;
+               expected_params = cl_hw->chip->conf->ce_production_mode ? 0 : 1;
+               break;
+       case 'z':
+               reset_stats = true;
+               expected_params = cl_hw->chip->conf->ce_production_mode ? 0 : 1;
+               break;
+       case 's':
+               print_rssi = true;
+               expected_params = 1;
+               break;
+       case 'u':
+               uplink_stats = true;
+               expected_params = 1;
+               break;
+       case '?':
+               return cl_stats_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_per) {
+               cl_stats_print_per(cl_hw, (u32)cli_params->params[0]);
+               return 0;
+       }
+
+       if (cpu_stats) {
+               cl_stats_cli_cpu(cl_hw, (bool)cli_params->params[0]);
+               return 0;
+       }
+
+       if (uplink_stats) {
+               cl_stats_cli_rx_info(cl_hw, (bool)cli_params->params[0]);
+               return 0;
+       }
+
+       if (enable_tx_rx_rssi) {
+               cl_stats_cli_enable(cl_hw, (bool)cli_params->params[0]);
+               return 0;
+       }
+
+       if (!cl_hw->conf->ci_stats_en) {
+               pr_debug("Statistics are disabled!\n"
+                        "To enable them type: "
+                        "'iwcl <interface> cecli stats -e.1'\n");
+               return 0;
+       }
+
+       if (print_rx) {
+               u8 sta_idx = (u8)cli_params->params[0];
+
+               cl_stats_cli_rx(cl_hw, sta_idx);
+               return 0;
+       }
+
+       if (print_rssi) {
+               u8 sta_idx = (u8)cli_params->params[0];
+
+               cl_stats_cli_rssi(cl_hw, sta_idx);
+               return 0;
+       }
+
+       if (print_fec_coding) {
+               u8 sta_idx = (u8)cli_params->params[0];
+
+               cl_stats_cli_fec_coding(cl_hw, sta_idx);
+               return 0;
+       }
+
+       if (print_power_save) {
+               u8 sta_idx = (u8)cli_params->params[0];
+
+               cl_stats_cli_ps(cl_hw, sta_idx);
+               return 0;
+       }
+
+       if (print_tx) {
+               u8 sta_idx = (u8)cli_params->params[0];
+
+               cl_stats_cli_tx(cl_hw, sta_idx);
+               return 0;
+       }
+
+       if (reset_stats) {
+               u8 sta_idx = (u8)cli_params->params[0];
+
+               cl_stats_cli_reset(cl_hw, sta_idx);
+               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.
________________________________


^ permalink raw reply related	[flat|nested] 262+ messages in thread

* [RFC v1 185/256] cl8k: add stats.h
  2021-06-17 15:58 [RFC v1 000/256] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (183 preceding siblings ...)
  2021-06-17 16:01 ` [RFC v1 184/256] cl8k: add stats.c viktor.barna
@ 2021-06-17 16:01 ` viktor.barna
  2021-06-17 16:01 ` [RFC v1 186/256] cl8k: add tcv_config.c viktor.barna
                   ` (72 subsequent siblings)
  257 siblings, 0 replies; 262+ messages in thread
From: viktor.barna @ 2021-06-17 16:01 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Oleksandr Savchenko, Shay Bar, Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

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

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 drivers/net/wireless/celeno/cl8k/stats.h | 27 ++++++++++++++++++++++++
 1 file changed, 27 insertions(+)
 create mode 100644 drivers/net/wireless/celeno/cl8k/stats.h

diff --git a/drivers/net/wireless/celeno/cl8k/stats.h b/drivers/net/wireless/celeno/cl8k/stats.h
new file mode 100644
index 000000000000..91a7bed25a2a
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/stats.h
@@ -0,0 +1,27 @@
+/* SPDX-License-Identifier: MIT */
+/* Copyright(c) 2019-2021, Celeno Communications Ltd. */
+
+#ifndef CL_STATS_H
+#define CL_STATS_H
+
+#include "hw.h"
+#include "rx/rx.h"
+#include "utils/timer.h"
+#include "tx/agg_tx_report.h"
+#include "vendor_cmd.h"
+
+void cl_stats_init(struct cl_hw *cl_hw);
+void cl_stats_deinit(struct cl_hw *cl_hw);
+void cl_stats_sta_add(struct cl_hw *cl_hw, struct cl_sta *cl_sta);
+void cl_stats_sta_remove(struct cl_hw *cl_hw, struct cl_sta *cl_sta);
+void cl_stats_update_tx_agg(struct cl_hw *cl_hw, struct cl_sta *cl_sta,
+                           struct cl_agg_tx_report *agg_report);
+void cl_stats_update_tx_single(struct cl_hw *cl_hw, struct cl_sta *cl_sta,
+                              struct cl_agg_tx_report *agg_report);
+void cl_stats_update_rx_rssi(struct cl_hw *cl_hw, struct cl_sta *cl_sta, s8 rssi[MAX_ANTENNAS]);
+void cl_stats_update_rx_rate(struct cl_hw *cl_hw, struct cl_sta *cl_sta, struct hw_rxhdr *rxhdr);
+void cl_stats_update_rx_rate_production(struct cl_hw *cl_hw, struct hw_rxhdr *rxhdr);
+void cl_stats_update_ps(struct cl_hw *cl_hw, struct cl_sta *cl_sta, bool is_ps);
+int cl_stats_cli(struct cl_hw *cl_hw, struct cl_vif *cl_vif, struct cli_params *cli_params);
+
+#endif /* CL_STATS_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.
________________________________


^ permalink raw reply related	[flat|nested] 262+ messages in thread

* [RFC v1 186/256] cl8k: add tcv_config.c
  2021-06-17 15:58 [RFC v1 000/256] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (184 preceding siblings ...)
  2021-06-17 16:01 ` [RFC v1 185/256] cl8k: add stats.h viktor.barna
@ 2021-06-17 16:01 ` viktor.barna
  2021-06-17 16:01 ` [RFC v1 187/256] cl8k: add tcv_config.h viktor.barna
                   ` (71 subsequent siblings)
  257 siblings, 0 replies; 262+ messages in thread
From: viktor.barna @ 2021-06-17 16:01 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Oleksandr Savchenko, Shay Bar, Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

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

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 drivers/net/wireless/celeno/cl8k/tcv_config.c | 1463 +++++++++++++++++
 1 file changed, 1463 insertions(+)
 create mode 100644 drivers/net/wireless/celeno/cl8k/tcv_config.c

diff --git a/drivers/net/wireless/celeno/cl8k/tcv_config.c b/drivers/net/wireless/celeno/cl8k/tcv_config.c
new file mode 100644
index 000000000000..bb09ae332006
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/tcv_config.c
@@ -0,0 +1,1463 @@
+// SPDX-License-Identifier: MIT
+/* Copyright(c) 2019-2021, Celeno Communications Ltd. */
+
+#include <linux/slab.h>
+#include <linux/moduleparam.h>
+#include <linux/uaccess.h>
+#include "utils/file.h"
+#include "utils/utils.h"
+#include "prot_mode.h"
+#include "chip.h"
+#include "tx/tx_amsdu.h"
+#include "recovery.h"
+#include "band.h"
+#include "vns.h"
+#include "fw/msg_tx.h"
+#include "utils/string.h"
+#include "twt.h"
+#include "cap.h"
+#include "config.h"
+
+#define TX_BCN_PENDING_CHAIN_MIN_TIME 10 /* Usec */
+
+#define CL_MAX_NUM_OF_RETRY 15
+
+struct cl_tcv_conf conf = {
+       .ce_bss_num = 1,
+       .ce_debug_level = DBG_LVL_ERROR,
+       .ce_radio_on = true,
+       .ce_ps_ctrl_enabled = true,
+       .ha_channel = 0,
+       .ci_ieee80211w = false,
+       .ci_ieee80211h = false,
+       .ha_short_guard_interval = 1,
+       .ha_max_mpdu_len = IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_7991,
+       .ha_vht_max_ampdu_len_exp = IEEE80211_VHT_MAX_AMPDU_1024K,
+       .ha_beacon_int = 100,
+       .ce_dsp_code = "fwC.hex",
+       .ce_dsp_data = "fwD.hex",
+       .ce_dsp_external_data = "fwD.ext.hex",
+       .ce_uapsd_en = true,
+       .ci_eirp_regulatory_en = true,
+       .ci_agg_tx = true,
+       .ci_agg_rx = true,
+       .ce_txldpc_en = true,
+       .ce_ht_rxldpc_en = true,
+       .ce_vht_rxldpc_en = true,
+       .ce_he_rxldpc_en = true,
+       .ci_cs_required = false,
+       .ci_rx_sensitivity_prod = {
+               [0 ... MAX_ANTENNAS - 1] = -96,
+       },
+       .ci_rx_sensitivity_op = {
+               [0 ... MAX_ANTENNAS - 1] = -99,
+       },
+       .ce_cck_bcn_en = false,
+       .ci_min_he_en = false,
+       .ce_cck_tx_ant_mask = 0x1,
+       .ce_cck_rx_ant_mask = 0x1,
+       .ce_rx_nss = 4,
+       .ce_tx_nss = 4,
+       .ce_num_antennas = 4,
+       .ce_wireless_mode = WIRELESS_MODE_HT_VHT_HE,
+       .ha_wmm_enabled = {
+               [0 ... MAX_BSS_NUM - 1] = 1,
+       },
+       .ce_max_agg_size_tx = IEEE80211_MAX_AMPDU_BUF,
+       .ce_max_agg_size_rx = IEEE80211_MAX_AMPDU_BUF,
+       .ce_rxamsdu_en = true,
+       .ce_txamsdu_en = CL_AMSDU_TX_PAYLOAD_MAX,
+       .ci_tx_amsdu_min_data_rate = 26, /* 26Mbps (= BW 20, NSS 0, MCS 3, GI 0) */
+       .ci_tx_sw_amsdu_max_packets = 0,
+       .ci_tx_packet_limit = 5000,
+       .ci_tx_queue_size_agg = 500,
+       .ci_tx_queue_size_single = 50,
+       .ci_ipc_rxbuf_size = {
+               [CL_RX_BUF_RXM] = IPC_RXBUF_SIZE,
+               [CL_RX_BUF_FW] = IPC_RXBUF_SIZE
+       },
+       .ce_max_retry = 8,
+       .ce_short_retry_limit = 4,
+       .ce_long_retry_limit = 4,
+       .ci_assoc_auth_retry_limit = 0,
+       .ce_channel_bandwidth = 0,
+       .ce_iface_type = {
+               [0] = NL80211_IFTYPE_AP,
+               [1 ... MAX_BSS_NUM - 1] = NL80211_IFTYPE_UNSPECIFIED,
+       },
+       .ha_hw_mode = HW_MODE_A,
+       .ce_temp_comp_slope = 8,
+       .ci_fw_dbg_severity = CL_MACFW_DBG_SEV_WARNING,
+       .ci_fw_dbg_module = 0x0FFFFF,
+       .ci_hal_idle_to = CL_DEFAULT_HAL_IDLE_TIMEOUT,
+       .ci_tx_ac0_to = CL_TX_DEFAULT_AC0_TIMEOUT,
+       .ci_tx_ac1_to = CL_TX_DEFAULT_AC1_TIMEOUT,
+       .ci_tx_ac2_to = CL_TX_DEFAULT_AC2_TIMEOUT,
+       .ci_tx_ac3_to = CL_TX_DEFAULT_AC3_TIMEOUT,
+       .ci_tx_bcn_to = CL_TX_DEFAULT_BCN_TIMEOUT,
+       .ce_hardware_power_table = {0},
+       .ce_arr_gain = "0,3,4.75,6,7,7.75",
+       .ce_bf_gain_2_ant = "0",
+       .ce_bf_gain_3_ant = "0",
+       .ce_bf_gain_4_ant = "0",
+       .ce_bf_gain_5_ant = "0",
+       .ce_bf_gain_6_ant = "0",
+       .ce_ant_gain = "0",
+       .ce_ant_gain_36_64 = "0",
+       .ce_ant_gain_100_140 = "0",
+       .ce_ant_gain_149_165 = "0",
+       .ci_min_ant_pwr = "0",
+       .ci_bw_factor = "0,0,0,0",
+       .ce_mcast_rate = 0,
+       .ce_dyn_mcast_rate_en = false,
+       .ce_dyn_bcast_rate_en = false,
+       .ce_default_mcs_ofdm = 0,
+       .ce_default_mcs_cck = 0,
+       .ce_prot_log_nav_en = false,
+       .ce_prot_mode = TXL_PROT_RTS,
+       .ce_prot_rate_format = 1,
+       .ce_prot_rate_mcs = 4,
+       .ce_prot_rate_pre_type = 0,
+       .ce_bw_signaling_mode = 0,
+       .ci_dyn_cts_sta_thr = 2,
+       .ci_vns_pwr_limit = 0,
+       .ci_vns_pwr_mode = VNS_MODE_ALL,
+       .ci_vns_rssi_auto_resp_thr = -40,
+       .ci_vns_rssi_thr = -40,
+       .ci_vns_rssi_hys = 3,
+       .ci_vns_maintenance_time = 2000,
+       .ce_bcn_tx_path_min_time = 1000,
+       .ci_backup_bcn_en = true,
+       .ce_tx_txop_cut_en = true,
+       .ci_bcns_flushed_cnt_thr = 9,
+       .ci_phy_err_prevents_phy_dump = false,
+       .ci_tx_rx_delay = 0,
+       .ci_fw_assert_time_diff_sec = 5,
+       .ci_fw_assert_storm_detect_thd = 15,
+       .ce_hw_assert_time_max = CL_HW_ASSERT_TIME_MAX,
+       .ce_fw_watchdog_mode = FW_WD_INTERNAL_RECOVERY,
+       .ce_fw_watchdog_limit_count = 5,
+       .ce_fw_watchdog_limit_time = 30 * 1000, /* Msecs */
+       .ci_rx_remote_cpu_drv = -1,
+       .ci_rx_remote_cpu_mac = -1,
+       .ci_tx_remote_cpu = -1,
+       .ci_pending_queue_size = 500,
+       .ce_tx_power_control = 100,
+       .ce_standby_mode_en = false,
+       .ce_coex_en = false,
+       .ce_extension_channel = 1,
+       .ci_dfs_initial_gain = 77,
+       .ci_dfs_agc_cd_th = 48,
+       .ci_dfs_long_pulse_min = 100,
+       .ci_dfs_long_pulse_max = 5000,
+       .ce_dfs_tbl_overwrite = {0},
+       .ce_dfs_jump_channels = "36,40,44,48",
+       /* 6G */
+       .ce_ppmcs_offset_he_6g = {
+               [WRS_MCS_0] = PPMCS_DFLT_OFT_V3_MCS_0,
+               [WRS_MCS_1] = PPMCS_DFLT_OFT_V3_MCS_1,
+               [WRS_MCS_2] = PPMCS_DFLT_OFT_V3_MCS_2,
+               [WRS_MCS_3] = PPMCS_DFLT_OFT_V3_MCS_3,
+               [WRS_MCS_4] = PPMCS_DFLT_OFT_V3_MCS_4,
+               [WRS_MCS_5] = PPMCS_DFLT_OFT_V3_MCS_5,
+               [WRS_MCS_6] = PPMCS_DFLT_OFT_V3_MCS_6,
+               [WRS_MCS_7] = PPMCS_DFLT_OFT_V3_MCS_7,
+               [WRS_MCS_8] = PPMCS_DFLT_OFT_V3_MCS_8,
+               [WRS_MCS_9] = PPMCS_DFLT_OFT_V3_MCS_9,
+               [WRS_MCS_10] = PPMCS_DFLT_OFT_V3_MCS_10,
+               [WRS_MCS_11] = PPMCS_DFLT_OFT_V3_MCS_11,
+       },
+       /* 5G */
+       .ce_ppmcs_offset_he_36_64 = {
+               [WRS_MCS_0] = PPMCS_DFLT_OFT_V1_MCS_0,
+               [WRS_MCS_1] = PPMCS_DFLT_OFT_V1_MCS_1,
+               [WRS_MCS_2] = PPMCS_DFLT_OFT_V1_MCS_2,
+               [WRS_MCS_3] = PPMCS_DFLT_OFT_V1_MCS_3,
+               [WRS_MCS_4] = PPMCS_DFLT_OFT_V1_MCS_4,
+               [WRS_MCS_5] = PPMCS_DFLT_OFT_V1_MCS_5,
+               [WRS_MCS_6] = PPMCS_DFLT_OFT_V1_MCS_6,
+               [WRS_MCS_7] = PPMCS_DFLT_OFT_V1_MCS_7,
+               [WRS_MCS_8] = PPMCS_DFLT_OFT_V1_MCS_8,
+               [WRS_MCS_9] = PPMCS_DFLT_OFT_V1_MCS_9,
+               [WRS_MCS_10] = PPMCS_DFLT_OFT_V1_MCS_10,
+               [WRS_MCS_11] = PPMCS_DFLT_OFT_V1_MCS_11,
+       },
+       .ce_ppmcs_offset_he_100_140 = {
+               [WRS_MCS_0] = PPMCS_DFLT_OFT_V1_MCS_0,
+               [WRS_MCS_1] = PPMCS_DFLT_OFT_V1_MCS_1,
+               [WRS_MCS_2] = PPMCS_DFLT_OFT_V1_MCS_2,
+               [WRS_MCS_3] = PPMCS_DFLT_OFT_V1_MCS_3,
+               [WRS_MCS_4] = PPMCS_DFLT_OFT_V1_MCS_4,
+               [WRS_MCS_5] = PPMCS_DFLT_OFT_V1_MCS_5,
+               [WRS_MCS_6] = PPMCS_DFLT_OFT_V1_MCS_6,
+               [WRS_MCS_7] = PPMCS_DFLT_OFT_V1_MCS_7,
+               [WRS_MCS_8] = PPMCS_DFLT_OFT_V1_MCS_8,
+               [WRS_MCS_9] = PPMCS_DFLT_OFT_V1_MCS_9,
+               [WRS_MCS_10] = PPMCS_DFLT_OFT_V1_MCS_10,
+               [WRS_MCS_11] = PPMCS_DFLT_OFT_V1_MCS_11,
+       },
+       .ce_ppmcs_offset_he_149_165 = {
+               [WRS_MCS_0] = PPMCS_DFLT_OFT_V1_MCS_0,
+               [WRS_MCS_1] = PPMCS_DFLT_OFT_V1_MCS_1,
+               [WRS_MCS_2] = PPMCS_DFLT_OFT_V1_MCS_2,
+               [WRS_MCS_3] = PPMCS_DFLT_OFT_V1_MCS_3,
+               [WRS_MCS_4] = PPMCS_DFLT_OFT_V1_MCS_4,
+               [WRS_MCS_5] = PPMCS_DFLT_OFT_V1_MCS_5,
+               [WRS_MCS_6] = PPMCS_DFLT_OFT_V1_MCS_6,
+               [WRS_MCS_7] = PPMCS_DFLT_OFT_V1_MCS_7,
+               [WRS_MCS_8] = PPMCS_DFLT_OFT_V1_MCS_8,
+               [WRS_MCS_9] = PPMCS_DFLT_OFT_V1_MCS_9,
+               [WRS_MCS_10] = PPMCS_DFLT_OFT_V1_MCS_10,
+               [WRS_MCS_11] = PPMCS_DFLT_OFT_V1_MCS_11,
+       },
+       .ce_ppmcs_offset_ht_vht_36_64 = {
+               [WRS_MCS_0] = PPMCS_DFLT_OFT_V1_MCS_0,
+               [WRS_MCS_1] = PPMCS_DFLT_OFT_V1_MCS_1,
+               [WRS_MCS_2] = PPMCS_DFLT_OFT_V1_MCS_2,
+               [WRS_MCS_3] = PPMCS_DFLT_OFT_V1_MCS_3,
+               [WRS_MCS_4] = PPMCS_DFLT_OFT_V1_MCS_4,
+               [WRS_MCS_5] = PPMCS_DFLT_OFT_V1_MCS_5,
+               [WRS_MCS_6] = PPMCS_DFLT_OFT_V1_MCS_6,
+               [WRS_MCS_7] = PPMCS_DFLT_OFT_V1_MCS_7,
+               [WRS_MCS_8] = PPMCS_DFLT_OFT_V1_MCS_8,
+               [WRS_MCS_9] = PPMCS_DFLT_OFT_V1_MCS_9,
+       },
+       .ce_ppmcs_offset_ht_vht_100_140 = {
+               [WRS_MCS_0] = PPMCS_DFLT_OFT_V1_MCS_0,
+               [WRS_MCS_1] = PPMCS_DFLT_OFT_V1_MCS_1,
+               [WRS_MCS_2] = PPMCS_DFLT_OFT_V1_MCS_2,
+               [WRS_MCS_3] = PPMCS_DFLT_OFT_V1_MCS_3,
+               [WRS_MCS_4] = PPMCS_DFLT_OFT_V1_MCS_4,
+               [WRS_MCS_5] = PPMCS_DFLT_OFT_V1_MCS_5,
+               [WRS_MCS_6] = PPMCS_DFLT_OFT_V1_MCS_6,
+               [WRS_MCS_7] = PPMCS_DFLT_OFT_V1_MCS_7,
+               [WRS_MCS_8] = PPMCS_DFLT_OFT_V1_MCS_8,
+               [WRS_MCS_9] = PPMCS_DFLT_OFT_V1_MCS_9,
+       },
+       .ce_ppmcs_offset_ht_vht_149_165 = {
+               [WRS_MCS_0] = PPMCS_DFLT_OFT_V1_MCS_0,
+               [WRS_MCS_1] = PPMCS_DFLT_OFT_V1_MCS_1,
+               [WRS_MCS_2] = PPMCS_DFLT_OFT_V1_MCS_2,
+               [WRS_MCS_3] = PPMCS_DFLT_OFT_V1_MCS_3,
+               [WRS_MCS_4] = PPMCS_DFLT_OFT_V1_MCS_4,
+               [WRS_MCS_5] = PPMCS_DFLT_OFT_V1_MCS_5,
+               [WRS_MCS_6] = PPMCS_DFLT_OFT_V1_MCS_6,
+               [WRS_MCS_7] = PPMCS_DFLT_OFT_V1_MCS_7,
+               [WRS_MCS_8] = PPMCS_DFLT_OFT_V1_MCS_8,
+               [WRS_MCS_9] = PPMCS_DFLT_OFT_V1_MCS_9,
+       },
+       .ce_ppmcs_offset_ofdm_36_64 = {
+               [WRS_MCS_0] = PPMCS_DFLT_OFT_V1_MCS_0,
+               [WRS_MCS_1] = PPMCS_DFLT_OFT_V1_MCS_1,
+               [WRS_MCS_2] = PPMCS_DFLT_OFT_V1_MCS_2,
+               [WRS_MCS_3] = PPMCS_DFLT_OFT_V1_MCS_3,
+               [WRS_MCS_4] = PPMCS_DFLT_OFT_V1_MCS_4,
+               [WRS_MCS_5] = PPMCS_DFLT_OFT_V1_MCS_5,
+               [WRS_MCS_6] = PPMCS_DFLT_OFT_V1_MCS_6,
+               [WRS_MCS_7] = PPMCS_DFLT_OFT_V1_MCS_7,
+       },
+       .ce_ppmcs_offset_ofdm_100_140 = {
+               [WRS_MCS_0] = PPMCS_DFLT_OFT_V1_MCS_0,
+               [WRS_MCS_1] = PPMCS_DFLT_OFT_V1_MCS_1,
+               [WRS_MCS_2] = PPMCS_DFLT_OFT_V1_MCS_2,
+               [WRS_MCS_3] = PPMCS_DFLT_OFT_V1_MCS_3,
+               [WRS_MCS_4] = PPMCS_DFLT_OFT_V1_MCS_4,
+               [WRS_MCS_5] = PPMCS_DFLT_OFT_V1_MCS_5,
+               [WRS_MCS_6] = PPMCS_DFLT_OFT_V1_MCS_6,
+               [WRS_MCS_7] = PPMCS_DFLT_OFT_V1_MCS_7,
+       },
+       .ce_ppmcs_offset_ofdm_149_165 = {
+               [WRS_MCS_0] = PPMCS_DFLT_OFT_V1_MCS_0,
+               [WRS_MCS_1] = PPMCS_DFLT_OFT_V1_MCS_1,
+               [WRS_MCS_2] = PPMCS_DFLT_OFT_V1_MCS_2,
+               [WRS_MCS_3] = PPMCS_DFLT_OFT_V1_MCS_3,
+               [WRS_MCS_4] = PPMCS_DFLT_OFT_V1_MCS_4,
+               [WRS_MCS_5] = PPMCS_DFLT_OFT_V1_MCS_5,
+               [WRS_MCS_6] = PPMCS_DFLT_OFT_V1_MCS_6,
+               [WRS_MCS_7] = PPMCS_DFLT_OFT_V1_MCS_7,
+       },
+       /* 24G */
+       .ce_ppmcs_offset_he = {
+               [WRS_MCS_0] = PPMCS_DFLT_OFT_V2_MCS_0,
+               [WRS_MCS_1] = PPMCS_DFLT_OFT_V2_MCS_1,
+               [WRS_MCS_2] = PPMCS_DFLT_OFT_V2_MCS_2,
+               [WRS_MCS_3] = PPMCS_DFLT_OFT_V2_MCS_3,
+               [WRS_MCS_4] = PPMCS_DFLT_OFT_V2_MCS_4,
+               [WRS_MCS_5] = PPMCS_DFLT_OFT_V2_MCS_5,
+               [WRS_MCS_6] = PPMCS_DFLT_OFT_V2_MCS_6,
+               [WRS_MCS_7] = PPMCS_DFLT_OFT_V2_MCS_7,
+               [WRS_MCS_8] = PPMCS_DFLT_OFT_V2_MCS_8,
+               [WRS_MCS_9] = PPMCS_DFLT_OFT_V2_MCS_9,
+               [WRS_MCS_10] = PPMCS_DFLT_OFT_V2_MCS_10,
+               [WRS_MCS_11] = PPMCS_DFLT_OFT_V2_MCS_11,
+       },
+       .ce_ppmcs_offset_ht = {
+               [WRS_MCS_0] = PPMCS_DFLT_OFT_V2_MCS_0,
+               [WRS_MCS_1] = PPMCS_DFLT_OFT_V2_MCS_1,
+               [WRS_MCS_2] = PPMCS_DFLT_OFT_V2_MCS_2,
+               [WRS_MCS_3] = PPMCS_DFLT_OFT_V2_MCS_3,
+               [WRS_MCS_4] = PPMCS_DFLT_OFT_V2_MCS_4,
+               [WRS_MCS_5] = PPMCS_DFLT_OFT_V2_MCS_5,
+               [WRS_MCS_6] = PPMCS_DFLT_OFT_V2_MCS_6,
+               [WRS_MCS_7] = PPMCS_DFLT_OFT_V2_MCS_7,
+       },
+       .ce_ppmcs_offset_ofdm = {
+               [WRS_MCS_0] = PPMCS_DFLT_OFT_V2_MCS_0,
+               [WRS_MCS_1] = PPMCS_DFLT_OFT_V2_MCS_1,
+               [WRS_MCS_2] = PPMCS_DFLT_OFT_V2_MCS_2,
+               [WRS_MCS_3] = PPMCS_DFLT_OFT_V2_MCS_3,
+               [WRS_MCS_4] = PPMCS_DFLT_OFT_V2_MCS_4,
+               [WRS_MCS_5] = PPMCS_DFLT_OFT_V2_MCS_5,
+               [WRS_MCS_6] = PPMCS_DFLT_OFT_V2_MCS_6,
+               [WRS_MCS_7] = PPMCS_DFLT_OFT_V2_MCS_7,
+       },
+       .ce_ppmcs_offset_cck = {
+               [WRS_MCS_0] = 0,
+               [WRS_MCS_1] = 0,
+               [WRS_MCS_2] = 0,
+               [WRS_MCS_3] = 0,
+       },
+       .ce_ppbw_offset = {
+               [CHNL_BW_20] = PPBW_DFLT_OFT_BW_20,
+               [CHNL_BW_40] = PPBW_DFLT_OFT_BW_40,
+               [CHNL_BW_80] = PPBW_DFLT_OFT_BW_80,
+               [CHNL_BW_160] = PPBW_DFLT_OFT_BW_160,
+       },
+       .ce_power_offset_prod_en = true,
+       .ce_bf_en = 0,
+       .ci_bf_max_nss = 2,
+       .ce_sounding_interval_coefs = {
+               [SOUNDING_INTERVAL_COEF_MIN_INTERVAL] = 100,
+               [SOUNDING_INTERVAL_COEF_STA_STEP] = 4,
+               [SOUNDING_INTERVAL_COEF_INTERVAL_STEP] = 50,
+               [SOUNDING_INTERVAL_COEF_MAX_INTERVAL] = 500,
+       },
+       .ci_rate_fallback = {
+               [CL_RATE_FALLBACK_COUNT_SU] = 4,
+               [CL_RATE_FALLBACK_COUNT_MU] = 2,
+               [CL_RATE_FALLBACK_RETRY_COUNT_THR] = 2,
+               [CL_RATE_FALLBACK_BA_PER_THR] = 25,
+               [CL_RATE_FALLBACK_BA_NOT_RECEIVED_THR] = 2,
+               [CL_RATE_FALLBACK_DISABLE_MCS] = 1
+       },
+       .ce_rx_pkts_budget = 512,
+       .ci_band_num = 5,
+       .ci_mult_ampdu_in_txop_en = false,
+       .ce_wmm_aifsn = {
+               [AC_BK] = 3,
+               [AC_BE] = 7,
+               [AC_VI] = 1,
+               [AC_VO] = 1
+       },
+       .ce_wmm_cwmin = {
+               [AC_BK] = 4,
+               [AC_BE] = 4,
+               [AC_VI] = 3,
+               [AC_VO] = 2
+       },
+       .ce_wmm_cwmax = {
+               [AC_BK] = 10,
+               [AC_BE] = 10,
+               [AC_VI] = 4,
+               [AC_VO] = 3
+       },
+       .ce_wmm_txop = {
+               [AC_BK] = 0,
+               [AC_BE] = 0,
+               [AC_VI] = 94,
+               [AC_VO] = 47
+       },
+       .ci_su_force_min_spacing = CL_TX_MPDU_SPACING_INVALID,
+       .ci_mu_force_min_spacing = CL_TX_MPDU_SPACING_INVALID,
+       .ci_tf_mac_pad_dur = 0,
+       .ci_cca_timeout = 300,
+       .ce_tx_ba_session_timeout = 30000,
+       .ci_motion_sense_en = true,
+       .ci_motion_sense_rssi_thr = 8,
+       .ci_wrs_max_bw = CHNL_BW_160,
+       .ci_wrs_min_bw = CHNL_BW_20,
+       .ci_wrs_fixed_rate = {
+               [WRS_FIXED_PARAM_MODE] = -1,
+               [WRS_FIXED_PARAM_BW] = -1,
+               [WRS_FIXED_PARAM_NSS] = -1,
+               [WRS_FIXED_PARAM_MCS] = -1,
+               [WRS_FIXED_PARAM_GI] = -1
+       },
+       .ce_he_mcs_nss_supp_tx = {
+               [WRS_SS_1 ... WRS_SS_4] = 11,
+       },
+       .ce_he_mcs_nss_supp_rx = {
+               [WRS_SS_1 ... WRS_SS_4] = 11,
+       },
+       .ce_vht_mcs_nss_supp_tx = {
+               [WRS_SS_1 ... WRS_SS_4] = 9,
+       },
+       .ce_vht_mcs_nss_supp_rx = {
+               [WRS_SS_1 ... WRS_SS_4] = 9,
+       },
+       .ci_pe_duration = U8_MAX,
+       .ci_pe_duration_bcast = PPE_16US,
+       .ci_coredump_diff_time_ms = 0,
+       .ci_gain_update_enable = 1,
+       .ci_mcs_sig_b = 0,
+       .ci_spp_ksr_value = 1,
+       .ci_rx_padding_en = false,
+       .ci_stats_en = false,
+       .ci_bar_disable = false,
+       .ci_ofdm_only = true,
+       .ci_drop_to_lower_bw = false,
+       .ce_twt_en = false,
+       .ce_twt_default_interval = CL_TWT_DEFAULT_INTERVAL_US,
+       .ce_twt_default_min_wake_duration = CL_TWT_DEFAULT_MIN_WAKE_DURATION_US,
+       .ce_twt_max_sessions = CL_TWT_MAX_SESSIONS,
+       .ci_hr_factor = {
+               [CHNL_BW_20] = 2,
+               [CHNL_BW_40] = 2,
+               [CHNL_BW_80] = 2,
+               [CHNL_BW_160] = 1
+       },
+       .ci_csd_en = false,
+       .ci_signal_extension_en = false,
+       .ce_dscp_vlan_enable = {
+               [0] = true,
+               [1 ... MAX_BSS_NUM - 1] = false,
+       },
+       .ce_up0_7_default_vlan_user_prio = {0},
+       .ce_up0_7_layer_based = {0},
+       .ce_dscp_to_up0_7dec0 = "0,8,16,24,32,40,48,56",
+       .ce_dscp_to_up0_7dec1 = "0,8,16,24,32,40,48,56",
+       .ce_dscp_to_up0_7dec2 = "0,8,16,24,32,40,48,56",
+       .ce_dscp_to_up0_7dec3 = "0,8,16,24,32,40,48,56",
+       .ce_dscp_to_up0_7dec4 = "0,8,16,24,32,40,48,56",
+       .ce_dscp_to_up0_7dec5 = "0,8,16,24,32,40,48,56",
+       .ce_dscp_to_up0_7dec6 = "0,8,16,24,32,40,48,56",
+       .ce_dscp_to_up0_7dec7 = "0,8,16,24,32,40,48,56",
+       .ce_vlan_to_up0_7dec0 = "7,5,6,4,3,1,1,0",
+       .ce_vlan_to_up0_7dec1 = "7,5,6,4,3,1,1,0",
+       .ce_vlan_to_up0_7dec2 = "7,5,6,4,3,1,1,0",
+       .ce_vlan_to_up0_7dec3 = "7,5,6,4,3,1,1,0",
+       .ce_vlan_to_up0_7dec4 = "7,5,6,4,3,1,1,0",
+       .ce_vlan_to_up0_7dec5 = "7,5,6,4,3,1,1,0",
+       .ce_vlan_to_up0_7dec6 = "7,5,6,4,3,1,1,0",
+       .ce_vlan_to_up0_7dec7 = "7,5,6,4,3,1,1,0",
+       .ci_vht_cap_24g = false,
+       .ce_omi_en = false,
+       .ci_tx_digital_gain = 0x28282828,
+       .ci_tx_digital_gain_cck = 0x63636363,
+       .ci_ofdm_cck_power_offset = -13,
+       .ci_mac_clk_gating_en = true,
+       .ci_phy_clk_gating_en = true,
+       .ci_imaging_blocker = false,
+       .ci_ndp_tx_chain_mask = NDP_TX_PHY0,
+       .ci_ndp_tx_bw = CHNL_BW_MAX,
+       .ci_ndp_tx_format = FORMATMOD_NON_HT,
+       .ci_ndp_tx_num_ltf = LTF_X1,
+       .ci_calib_ant_tx = {
+               [0 ... MAX_ANTENNAS - 1] = U8_MAX,
+       },
+       .ci_calib_ant_rx = {
+               [0 ... MAX_ANTENNAS - 1] = U8_MAX,
+       },
+       .ci_cca_ed_rise_thr_dbm = -62,
+       .ci_cca_ed_fall_thr_dbm = -65,
+       .ci_cca_cs_en = 1,
+       .ci_cca_modem_en = 0xf,
+       .ci_cca_main_ant = 0,
+       .ci_cca_second_ant = 1,
+       .ci_cca_flag0_ctrl = 0x8,
+       .ci_cca_flag1_ctrl = 0x8,
+       .ci_cca_flag2_ctrl = 0x2,
+       .ci_cca_flag3_ctrl = 0xa,
+       .ci_cca_gi_rise_thr_dbm = -72,
+       .ci_cca_gi_fall_thr_dbm = -75,
+       .ci_cca_gi_pow_lim_dbm = -59,
+       .ci_cca_ed_en = 0x7ff,
+       .ci_cca_gi_en = 0,
+       .ci_rx_he_mu_ppdu = false,
+       .ci_fast_rx_en = true,
+       .ci_distance_auto_resp_all = 0,
+       .ci_distance_auto_resp_msta = 0,
+};
+
+static int update_config(struct cl_hw *cl_hw, char *name, char *value)
+{
+       struct cl_tcv_conf *conf = cl_hw->conf;
+
+       READ_U8(ce_bss_num);
+       READ_S8(ce_debug_level);
+       READ_BOOL(ce_radio_on);
+       READ_BOOL(ce_ps_ctrl_enabled);
+       READ_U8(ha_channel);
+       READ_BOOL(ci_ieee80211w);
+       READ_BOOL(ci_ieee80211h);
+       READ_U8(ha_short_guard_interval);
+       READ_U8(ha_max_mpdu_len);
+       READ_U8(ha_vht_max_ampdu_len_exp);
+       READ_U32(ha_beacon_int);
+       READ_STR(ce_dsp_code);
+       READ_STR(ce_dsp_data);
+       READ_STR(ce_dsp_external_data);
+       READ_BOOL(ce_uapsd_en);
+       READ_BOOL(ci_eirp_regulatory_en);
+       READ_BOOL(ci_agg_tx);
+       READ_BOOL(ci_agg_rx);
+       READ_BOOL(ce_txldpc_en);
+       READ_BOOL(ce_ht_rxldpc_en);
+       READ_BOOL(ce_vht_rxldpc_en);
+       READ_BOOL(ce_he_rxldpc_en);
+       READ_BOOL(ci_cs_required);
+       READ_S8_ARR(ci_rx_sensitivity_prod, MAX_ANTENNAS);
+       READ_S8_ARR(ci_rx_sensitivity_op, MAX_ANTENNAS);
+       READ_BOOL(ce_cck_bcn_en);
+       READ_BOOL(ci_min_he_en);
+       READ_U8(ce_cck_tx_ant_mask);
+       READ_U8(ce_cck_rx_ant_mask);
+       READ_U8(ce_rx_nss);
+       READ_U8(ce_tx_nss);
+       READ_U8(ce_num_antennas);
+       READ_U8(ce_wireless_mode);
+       READ_BOOL_ARR(ha_wmm_enabled, MAX_BSS_NUM);
+       READ_U16(ce_max_agg_size_tx);
+       READ_U16(ce_max_agg_size_rx);
+       READ_BOOL(ce_rxamsdu_en);
+       READ_U8(ce_txamsdu_en);
+       READ_U16(ci_tx_amsdu_min_data_rate);
+       READ_U8(ci_tx_sw_amsdu_max_packets);
+       READ_U16(ci_tx_packet_limit);
+       READ_U16(ci_tx_queue_size_agg);
+       READ_U16(ci_tx_queue_size_single);
+       READ_U16_ARR(ci_ipc_rxbuf_size, CL_RX_BUF_MAX);
+       READ_U16(ce_max_retry);
+       READ_U8(ce_short_retry_limit);
+       READ_U8(ce_long_retry_limit);
+       READ_U8(ci_assoc_auth_retry_limit);
+       READ_U8(ce_channel_bandwidth);
+       READ_U8_ARR(ce_iface_type, MAX_BSS_NUM);
+       READ_U8(ha_hw_mode);
+       READ_S8(ce_temp_comp_slope);
+       READ_U32(ci_fw_dbg_severity);
+       READ_U32(ci_fw_dbg_module);
+       READ_U32(ci_hal_idle_to);
+       READ_U32(ci_tx_ac0_to);
+       READ_U32(ci_tx_ac1_to);
+       READ_U32(ci_tx_ac2_to);
+       READ_U32(ci_tx_ac3_to);
+       READ_U32(ci_tx_bcn_to);
+       READ_STR(ce_hardware_power_table);
+       READ_STR(ce_arr_gain);
+       READ_STR(ce_bf_gain_2_ant);
+       READ_STR(ce_bf_gain_3_ant);
+       READ_STR(ce_bf_gain_4_ant);
+       READ_STR(ce_bf_gain_5_ant);
+       READ_STR(ce_bf_gain_6_ant);
+       READ_STR(ce_ant_gain);
+       READ_STR(ce_ant_gain_36_64);
+       READ_STR(ce_ant_gain_100_140);
+       READ_STR(ce_ant_gain_149_165);
+       READ_STR(ci_min_ant_pwr);
+       READ_STR(ci_bw_factor);
+       READ_U8(ce_mcast_rate);
+       READ_BOOL(ce_dyn_mcast_rate_en);
+       READ_BOOL(ce_dyn_bcast_rate_en);
+       READ_U8(ce_default_mcs_ofdm);
+       READ_U8(ce_default_mcs_cck);
+       READ_BOOL(ce_prot_log_nav_en);
+       READ_U8(ce_prot_mode);
+       READ_U8(ce_prot_rate_format);
+       READ_U8(ce_prot_rate_mcs);
+       READ_U8(ce_prot_rate_pre_type);
+       READ_U8(ce_bw_signaling_mode);
+       READ_U8(ci_dyn_cts_sta_thr);
+       READ_S8(ci_vns_pwr_limit);
+       READ_U8(ci_vns_pwr_mode);
+       READ_S8(ci_vns_rssi_auto_resp_thr);
+       READ_S8(ci_vns_rssi_thr);
+       READ_S8(ci_vns_rssi_hys);
+       READ_U16(ci_vns_maintenance_time);
+       READ_U16(ce_bcn_tx_path_min_time);
+       READ_BOOL(ci_backup_bcn_en);
+       READ_BOOL(ce_tx_txop_cut_en);
+       READ_U8(ci_bcns_flushed_cnt_thr);
+       READ_BOOL(ci_phy_err_prevents_phy_dump);
+       READ_U8(ci_tx_rx_delay);
+       READ_U8(ci_fw_assert_time_diff_sec);
+       READ_U8(ci_fw_assert_storm_detect_thd);
+       READ_U32(ce_hw_assert_time_max);
+       READ_U8(ce_fw_watchdog_mode);
+       READ_U8(ce_fw_watchdog_limit_count);
+       READ_U32(ce_fw_watchdog_limit_time);
+       READ_S8(ci_rx_remote_cpu_drv);
+       READ_S8(ci_rx_remote_cpu_mac);
+       READ_S8(ci_tx_remote_cpu);
+       READ_U16(ci_pending_queue_size);
+       READ_U8(ce_tx_power_control);
+       READ_BOOL(ce_standby_mode_en);
+       READ_BOOL(ce_coex_en);
+       READ_S8(ce_extension_channel);
+       READ_U8(ci_dfs_initial_gain);
+       READ_U8(ci_dfs_agc_cd_th);
+       READ_U16(ci_dfs_long_pulse_min);
+       READ_U16(ci_dfs_long_pulse_max);
+       READ_STR(ce_dfs_tbl_overwrite);
+       READ_STR(ce_dfs_jump_channels);
+       READ_S8_ARR(ce_ppmcs_offset_he_6g, WRS_MCS_MAX_HE);
+       READ_S8_ARR(ce_ppmcs_offset_he_36_64, WRS_MCS_MAX_HE);
+       READ_S8_ARR(ce_ppmcs_offset_he_100_140, WRS_MCS_MAX_HE);
+       READ_S8_ARR(ce_ppmcs_offset_he_149_165, WRS_MCS_MAX_HE);
+       READ_S8_ARR(ce_ppmcs_offset_ht_vht_36_64, WRS_MCS_MAX_VHT);
+       READ_S8_ARR(ce_ppmcs_offset_ht_vht_100_140, WRS_MCS_MAX_VHT);
+       READ_S8_ARR(ce_ppmcs_offset_ht_vht_149_165, WRS_MCS_MAX_VHT);
+       READ_S8_ARR(ce_ppmcs_offset_ofdm_36_64, WRS_MCS_MAX_OFDM);
+       READ_S8_ARR(ce_ppmcs_offset_ofdm_100_140, WRS_MCS_MAX_OFDM);
+       READ_S8_ARR(ce_ppmcs_offset_ofdm_149_165, WRS_MCS_MAX_OFDM);
+       READ_S8_ARR(ce_ppmcs_offset_he, WRS_MCS_MAX_HE);
+       READ_S8_ARR(ce_ppmcs_offset_ht, WRS_MCS_MAX_HT);
+       READ_S8_ARR(ce_ppmcs_offset_ofdm, WRS_MCS_MAX_OFDM);
+       READ_S8_ARR(ce_ppmcs_offset_cck, WRS_MCS_MAX_CCK);
+       READ_S8_ARR(ce_ppbw_offset, CHNL_BW_MAX);
+       READ_BOOL(ce_power_offset_prod_en);
+       READ_BOOL(ce_bf_en);
+       READ_U8(ci_bf_max_nss);
+       READ_U16_ARR(ce_sounding_interval_coefs, SOUNDING_INTERVAL_COEF_MAX);
+       READ_U8_ARR(ci_rate_fallback, CL_RATE_FALLBACK_MAX);
+       READ_U16(ce_rx_pkts_budget);
+       READ_U8(ci_band_num);
+       READ_BOOL(ci_mult_ampdu_in_txop_en);
+       READ_U8_ARR(ce_wmm_aifsn, AC_MAX);
+       READ_U8_ARR(ce_wmm_cwmin, AC_MAX);
+       READ_U8_ARR(ce_wmm_cwmax, AC_MAX);
+       READ_U16_ARR(ce_wmm_txop, AC_MAX);
+       READ_U8(ci_su_force_min_spacing);
+       READ_U8(ci_mu_force_min_spacing);
+       READ_U8(ci_tf_mac_pad_dur);
+       READ_U32(ci_cca_timeout);
+       READ_U16(ce_tx_ba_session_timeout);
+       READ_BOOL(ci_motion_sense_en);
+       READ_S8(ci_motion_sense_rssi_thr);
+       READ_U8(ci_wrs_max_bw);
+       READ_U8(ci_wrs_min_bw);
+       READ_S8_ARR(ci_wrs_fixed_rate, WRS_FIXED_PARAM_MAX);
+       READ_U8_ARR(ce_he_mcs_nss_supp_tx, WRS_SS_MAX);
+       READ_U8_ARR(ce_he_mcs_nss_supp_rx, WRS_SS_MAX);
+       READ_U8_ARR(ce_vht_mcs_nss_supp_tx, WRS_SS_MAX);
+       READ_U8_ARR(ce_vht_mcs_nss_supp_rx, WRS_SS_MAX);
+       READ_U8(ci_pe_duration);
+       READ_U8(ci_pe_duration_bcast);
+       READ_U32(ci_coredump_diff_time_ms);
+       READ_U8(ci_gain_update_enable);
+       READ_U8(ci_mcs_sig_b);
+       READ_U8(ci_spp_ksr_value);
+       READ_BOOL(ci_rx_padding_en);
+       READ_BOOL(ci_stats_en);
+       READ_BOOL(ci_bar_disable);
+       READ_BOOL(ci_ofdm_only);
+       READ_BOOL(ci_drop_to_lower_bw);
+       READ_BOOL(ce_twt_en);
+       READ_BOOL(ci_csd_en);
+       READ_U32(ce_twt_default_interval);
+       READ_U32(ce_twt_default_min_wake_duration);
+       READ_U8(ce_twt_max_sessions);
+       READ_U8_ARR(ci_hr_factor, CHNL_BW_MAX);
+       READ_BOOL(ci_signal_extension_en);
+       READ_BOOL_ARR(ce_dscp_vlan_enable, MAX_BSS_NUM);
+       READ_U8_ARR(ce_up0_7_default_vlan_user_prio, MAX_BSS_NUM);
+       READ_U8_ARR(ce_up0_7_layer_based, MAX_BSS_NUM);
+       READ_STR(ce_dscp_to_up0_7dec0);
+       READ_STR(ce_dscp_to_up0_7dec1);
+       READ_STR(ce_dscp_to_up0_7dec2);
+       READ_STR(ce_dscp_to_up0_7dec3);
+       READ_STR(ce_dscp_to_up0_7dec4);
+       READ_STR(ce_dscp_to_up0_7dec5);
+       READ_STR(ce_dscp_to_up0_7dec6);
+       READ_STR(ce_dscp_to_up0_7dec7);
+       READ_STR(ce_vlan_to_up0_7dec0);
+       READ_STR(ce_vlan_to_up0_7dec1);
+       READ_STR(ce_vlan_to_up0_7dec2);
+       READ_STR(ce_vlan_to_up0_7dec3);
+       READ_STR(ce_vlan_to_up0_7dec4);
+       READ_STR(ce_vlan_to_up0_7dec5);
+       READ_STR(ce_vlan_to_up0_7dec6);
+       READ_STR(ce_vlan_to_up0_7dec7);
+       READ_BOOL(ci_vht_cap_24g);
+       READ_BOOL(ce_omi_en);
+       READ_U32(ci_tx_digital_gain);
+       READ_U32(ci_tx_digital_gain_cck);
+       READ_S8(ci_ofdm_cck_power_offset);
+       READ_BOOL(ci_mac_clk_gating_en);
+       READ_BOOL(ci_phy_clk_gating_en);
+       READ_BOOL(ci_imaging_blocker);
+       READ_U8(ci_ndp_tx_chain_mask);
+       READ_U8(ci_ndp_tx_bw);
+       READ_U8(ci_ndp_tx_format);
+       READ_U8(ci_ndp_tx_num_ltf);
+       READ_U8_ARR(ci_calib_ant_tx, MAX_ANTENNAS);
+       READ_U8_ARR(ci_calib_ant_rx, MAX_ANTENNAS);
+       READ_S8(ci_cca_ed_rise_thr_dbm);
+       READ_S8(ci_cca_ed_fall_thr_dbm);
+       READ_U8(ci_cca_cs_en);
+       READ_U8(ci_cca_modem_en);
+       READ_U8(ci_cca_main_ant);
+       READ_U8(ci_cca_second_ant);
+       READ_U8(ci_cca_flag0_ctrl);
+       READ_U8(ci_cca_flag1_ctrl);
+       READ_U8(ci_cca_flag2_ctrl);
+       READ_U8(ci_cca_flag3_ctrl);
+       READ_S8(ci_cca_gi_rise_thr_dbm);
+       READ_S8(ci_cca_gi_fall_thr_dbm);
+       READ_S8(ci_cca_gi_pow_lim_dbm);
+       READ_U16(ci_cca_ed_en);
+       READ_U8(ci_cca_gi_en);
+       READ_BOOL(ci_rx_he_mu_ppdu);
+       READ_BOOL(ci_fast_rx_en);
+       READ_U8(ci_distance_auto_resp_all);
+       READ_U8(ci_distance_auto_resp_msta);
+
+       if (!cl_config_is_non_driver_param(name)) {
+               CL_DBG_ERROR(cl_hw, "No matching conf for nvram parameter %s\n", name);
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static int set_all_params_from_buf(struct cl_hw *cl_hw, char *buf, size_t size)
+{
+       char *line = buf;
+       char name[MAX_PARAM_NAME_LENGTH];
+       char value[STR_LEN_256B];
+       char *begin;
+       char *end;
+       int ret = 0;
+       int name_length = 0;
+       int value_length = 0;
+
+       while (line && strlen(line) && (line != (buf + size))) {
+               if ((*line == '#') || (*line == '\n')) {
+                       /* Skip comment or blank line */
+                       line = strstr(line, "\n") + 1;
+               } else if (*line) {
+                       begin = line;
+                       end = strstr(begin, "=");
+
+                       if (!end) {
+                               ret = -EBADMSG;
+                               goto exit;
+                       }
+
+                       end++;
+                       name_length = end - begin;
+                       value_length = strstr(end, "\n") - end + 1;
+
+                       if (name_length >= MAX_PARAM_NAME_LENGTH) {
+                               cl_dbg_err(cl_hw,
+                                          "Name too long (%u)\n", name_length);
+                               ret = -EBADMSG;
+                               goto exit;
+                       }
+                       if (value_length >= STR_LEN_256B) {
+                               cl_dbg_err(cl_hw,
+                                          "Value too long (%u)\n", value_length);
+                               ret = -EBADMSG;
+                               goto exit;
+                       }
+
+                       snprintf(name, name_length, "%s", begin);
+                       snprintf(value, value_length, "%s", end);
+
+                       ret = update_config(cl_hw, name, value);
+                       if (ret)
+                               goto exit;
+
+                       line = strstr(line, "\n") + 1;
+               }
+       }
+
+exit:
+
+       return ret;
+}
+
+static bool is_valid_min_spacing(u8 min_spacing)
+{
+       return ((min_spacing == 0) ||
+               (min_spacing == 1) ||
+               (min_spacing == 2) ||
+               (min_spacing == 3) ||
+               (min_spacing == 4) ||
+               (min_spacing == 6) ||
+               (min_spacing == 8) ||
+               (min_spacing == 10) ||
+               (min_spacing == 12) ||
+               (min_spacing == 14) ||
+               (min_spacing == 16) ||
+               (min_spacing == 18) ||
+               (min_spacing == 20) ||
+               (min_spacing == 24) ||
+               (min_spacing ==  CL_TX_MPDU_SPACING_INVALID));
+}
+
+static bool is_valid_cca_config(struct cl_hw *cl_hw, struct cl_tcv_conf *conf)
+{
+       if (conf->ci_cca_ed_rise_thr_dbm <= conf->ci_cca_ed_fall_thr_dbm) {
+               CL_DBG_ERROR(cl_hw, "cca_ed_rise_thr_dbm (%u) <= cca_ed_fall_thr_dbm (%u)\n",
+                            conf->ci_cca_ed_rise_thr_dbm, conf->ci_cca_ed_fall_thr_dbm);
+               return false;
+       }
+
+       if (conf->ci_cca_gi_rise_thr_dbm <= conf->ci_cca_gi_fall_thr_dbm) {
+               CL_DBG_ERROR(cl_hw, "cca_gi_rise_thr_dbm (%u) <= cca_gi_fall_thr_dbm (%u)\n",
+                            conf->ci_cca_gi_rise_thr_dbm, conf->ci_cca_gi_fall_thr_dbm);
+               return false;
+       }
+
+       if (conf->ci_cca_gi_pow_lim_dbm <= conf->ci_cca_ed_rise_thr_dbm) {
+               CL_DBG_ERROR(cl_hw, "cca_gi_pow_lim_dbm (%u) <= cca_ed_rise_thr_dbm (%u)\n",
+                            conf->ci_cca_gi_pow_lim_dbm, conf->ci_cca_ed_rise_thr_dbm);
+               return false;
+       }
+
+       return true;
+}
+
+static enum cl_iface_conf get_iface_conf(struct cl_tcv_conf *conf)
+{
+       u8 i, num_ap = 0, num_sta = 0, num_mp = 0;
+
+       for (i = 0; i < conf->ce_bss_num; i++) {
+               if (conf->ce_iface_type[i] == NL80211_IFTYPE_AP)
+                       num_ap++;
+               else if (conf->ce_iface_type[i] == NL80211_IFTYPE_STATION)
+                       num_sta++;
+               else if (conf->ce_iface_type[i] == NL80211_IFTYPE_MESH_POINT)
+                       num_mp++;
+       }
+
+       if (num_ap > 0 && num_sta == 0 && num_mp == 0)
+               return CL_IFCONF_AP;
+
+       if (num_ap == 0 && num_sta == 1 && num_mp == 0)
+               return CL_IFCONF_STA;
+
+       if (num_ap == 1 && num_sta == 1 && num_mp == 0)
+               return CL_IFCONF_REPEATER;
+
+       if (num_ap > 0 && num_sta == 0 && num_mp == 1)
+               return CL_IFCONF_MESH_AP;
+
+       if (num_ap == 0 && num_sta == 0 && num_mp == 1)
+               return CL_IFCONF_MESH_ONLY;
+
+       return CL_IFCONF_MAX;
+}
+
+static int post_configuration(struct cl_hw *cl_hw)
+{
+       struct cl_tcv_conf *conf = cl_hw->conf;
+       struct cl_chip *chip = cl_hw->chip;
+
+       /* Production mode */
+       if (chip->conf->ce_production_mode) {
+               memcpy(cl_hw->rx_sensitivity, conf->ci_rx_sensitivity_prod, MAX_ANTENNAS);
+               conf->ce_prot_mode = 0;
+               /* Production is done in station mode */
+               conf->ce_iface_type[0] = NL80211_IFTYPE_STATION;
+       } else {
+               memcpy(cl_hw->rx_sensitivity, conf->ci_rx_sensitivity_op, MAX_ANTENNAS);
+       }
+
+       cl_hw->iface_conf = get_iface_conf(conf);
+       if (cl_hw->iface_conf == CL_IFCONF_MAX) {
+               CL_DBG_ERROR(cl_hw, "Invalid interface configuration\n");
+               return -EINVAL;
+       }
+
+       if (!is_valid_cca_config(cl_hw, conf))
+               return -EINVAL;
+
+       /* Validate: ce_bss_num */
+       if (conf->ce_bss_num > MAX_BSS_NUM) {
+               CL_DBG_ERROR(cl_hw, "Invalid ce_bss_num (%u). Must be <= %u\n",
+                            conf->ce_bss_num, MAX_BSS_NUM);
+               return -EINVAL;
+       }
+
+       /* Validate: ce_num_antennas, ce_rx_nss, ce_tx_nss */
+       if (conf->ce_num_antennas < MIN_ANTENNAS ||
+           conf->ce_num_antennas > MAX_ANTENNAS) {
+               CL_DBG_ERROR(cl_hw, "Invalid ce_num_antennas (%u)\n", conf->ce_num_antennas);
+               return -EINVAL;
+       }
+
+       if (conf->ce_rx_nss < 1 ||
+           conf->ce_rx_nss > WRS_SS_MAX ||
+           conf->ce_rx_nss > conf->ce_num_antennas) {
+               CL_DBG_ERROR(cl_hw, "Invalid ce_rx_nss (%u)\n", conf->ce_rx_nss);
+               return -EINVAL;
+       }
+
+       if (conf->ce_tx_nss < 1 ||
+           conf->ce_tx_nss > WRS_SS_MAX ||
+           conf->ce_tx_nss > conf->ce_num_antennas) {
+               CL_DBG_ERROR(cl_hw, "Invalid ce_tx_nss (%u)\n", conf->ce_tx_nss);
+               return -EINVAL;
+       }
+
+       /* Validate: ce_cck_tx_ant_mask and ce_cck_rx_ant_mask */
+       if (cl_band_is_24g(cl_hw)) {
+               u8 ant_bitmap = ((1 << conf->ce_num_antennas) - 1);
+               u8 num_cck_ant_tx = hweight8(conf->ce_cck_tx_ant_mask);
+               u8 num_cck_ant_rx = hweight8(conf->ce_cck_rx_ant_mask);
+
+               if ((ant_bitmap & conf->ce_cck_tx_ant_mask) != conf->ce_cck_tx_ant_mask) {
+                       CL_DBG_ERROR(cl_hw, "Invalid ce_cck_tx_ant_mask (0x%x), "
+                                           "does not match ce_num_antennas mask (0x%x)\n",
+                                    conf->ce_cck_tx_ant_mask, ant_bitmap);
+                       return -EINVAL;
+               }
+
+               if ((ant_bitmap & conf->ce_cck_rx_ant_mask) != conf->ce_cck_rx_ant_mask) {
+                       CL_DBG_ERROR(cl_hw, "Invalid ce_cck_rx_ant_mask (0x%x), "
+                                           "does not match ce_num_antennas mask (0x%x)\n",
+                                    conf->ce_cck_rx_ant_mask, ant_bitmap);
+                       return -EINVAL;
+               }
+
+               if (conf->ce_cck_tx_ant_mask == 0) {
+                       CL_DBG_ERROR(cl_hw, "Invalid ce_cck_tx_ant_mask, can't be 0x0\n");
+                       return -EINVAL;
+               }
+
+               if (conf->ce_cck_rx_ant_mask == 0) {
+                       CL_DBG_ERROR(cl_hw, "Invalid ce_cck_rx_ant_mask, can't be 0x0\n");
+                       return -EINVAL;
+               }
+
+               if (num_cck_ant_tx > MAX_ANTENNAS_CCK) {
+                       CL_DBG_ERROR(cl_hw, "Invalid ce_cck_tx_ant_mask (0x%x), "
+                                           "number of set bits exceeds %u\n",
+                                    num_cck_ant_tx, MAX_ANTENNAS_CCK);
+                       return -EINVAL;
+               }
+
+               if (num_cck_ant_rx > MAX_ANTENNAS_CCK) {
+                       CL_DBG_ERROR(cl_hw, "Invalid ce_cck_rx_ant_mask (0x%x), "
+                                           "number of set bits exceeds %u\n",
+                                    num_cck_ant_rx, MAX_ANTENNAS_CCK);
+                       return -EINVAL;
+               }
+       }
+
+       if (cl_band_is_5g(cl_hw) && !(conf->ci_ofdm_only)) {
+               CL_DBG_ERROR(cl_hw, "ci_ofdm_only must be set to 1 for 5g band\n");
+               return -EINVAL;
+       }
+
+       /* Validate ce_bcn_tx_path_min_time */
+       if (conf->ce_bcn_tx_path_min_time <= TX_BCN_PENDING_CHAIN_MIN_TIME) {
+               CL_DBG_ERROR(cl_hw, "Invalid ce_bcn_tx_path_min_time (%u)\n",
+                            conf->ce_bcn_tx_path_min_time);
+               return -EINVAL;
+       }
+
+       if (conf->ci_tx_sw_amsdu_max_packets > MAX_TX_SW_AMSDU_PACKET) {
+               cl_dbg_err(cl_hw,
+                          "ERROR: Invalid ci_tx_sw_amsdu_max_packets (%u), "
+                          "set default (%u)\n",
+                          conf->ci_tx_sw_amsdu_max_packets, MAX_TX_SW_AMSDU_PACKET);
+
+               conf->ci_tx_sw_amsdu_max_packets = MAX_TX_SW_AMSDU_PACKET;
+       }
+
+       if (conf->ce_tx_power_control > 100 || conf->ce_tx_power_control < 1) {
+               cl_dbg_err(cl_hw,
+                          "ERROR: Invalid ce_tx_power_control (%u), set default 100\n",
+                          conf->ce_tx_power_control);
+
+               conf->ce_tx_power_control = 100;
+       }
+
+       if (conf->ce_max_retry > CL_MAX_NUM_OF_RETRY) {
+               cl_dbg_err(cl_hw,
+                          "ERROR: Invalid ce_max_retry (%u), "
+                          "set default to maximum (%u)\n",
+                          conf->ce_max_retry, CL_MAX_NUM_OF_RETRY);
+
+               conf->ce_max_retry = CL_MAX_NUM_OF_RETRY;
+       }
+
+       if (!is_valid_min_spacing(conf->ci_su_force_min_spacing)) {
+               cl_dbg_err(cl_hw,
+                          "ERROR: Invalid ci_su_force_min_spacing (%u), must "
+                          "be 0/1/2/3/4/6/8/10/12/14/16/18/20/24, set default %u\n",
+                          conf->ci_su_force_min_spacing, CL_TX_MPDU_SPACING_INVALID);
+
+               conf->ci_su_force_min_spacing = CL_TX_MPDU_SPACING_INVALID;
+       }
+
+       if (!is_valid_min_spacing(conf->ci_mu_force_min_spacing)) {
+               cl_dbg_err(cl_hw,
+                          "ERROR: Invalid ci_mu_force_min_spacing (%u), must "
+                          "be 0/1/2/3/4/6/8/10/12/14/16/18/20/24, set default %u\n",
+                          conf->ci_mu_force_min_spacing, CL_TX_MPDU_SPACING_INVALID);
+
+               conf->ci_mu_force_min_spacing = CL_TX_MPDU_SPACING_INVALID;
+       }
+
+       if (conf->ha_max_mpdu_len != IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_3895 &&
+           conf->ha_max_mpdu_len != IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_7991 &&
+           conf->ha_max_mpdu_len != IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_11454) {
+               cl_dbg_err(cl_hw,
+                          "ERROR: Invalid 'ha_max_mpdu_len' (%u). "
+                          "Must be 0/1/2. Setting to 0\n",
+                          conf->ha_max_mpdu_len);
+
+               conf->ha_max_mpdu_len = IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_3895;
+       }
+
+       if (cl_hw_is_tcv1(cl_hw) && cl_chip_is_both_enabled(chip)) {
+               /*
+                * Check that sum of ce_num_antennas in both TCV's is smaller
+                * than max_antennas
+                */
+               struct cl_hw *cl_hw_tcv0 = chip->cl_hw_tcv0;
+               u8 num_ant_tcv0 = cl_hw_tcv0->conf->ce_num_antennas;
+               u8 num_ant_tcv1 = conf->ce_num_antennas;
+               u8 total_ant = num_ant_tcv0 + num_ant_tcv1;
+
+               if (total_ant > chip->max_antennas) {
+                       CL_DBG_ERROR(cl_hw,
+                                    "Invalid ce_num_antennas tcv0=%u, "
+                                    "tcv1=%u, total=%u, max=%u\n",
+                                    num_ant_tcv0, num_ant_tcv1,
+                                    total_ant, chip->max_antennas);
+                       return -EINVAL;
+               }
+
+               if (cl_hw_tcv0->conf->ci_band_num == 5 &&
+                   cl_hw->conf->ci_band_num == 5) {
+                       u8 bw_tcv0 = cl_hw_tcv0->conf->ce_channel_bandwidth;
+                       u8 bw_tcv1 = cl_hw->conf->ce_channel_bandwidth;
+
+                       if (bw_tcv0 == CHNL_BW_80 && bw_tcv1 == CHNL_BW_80) {
+                               chip->conf->ci_dma_lli_max_chan[0] = 8;
+                               chip->conf->ci_dma_lli_max_chan[1] = 8;
+
+                               cl_dbg_verbose(cl_hw, "Overwrite ci_dma_lli_max_chan to 8,8\n");
+                       }
+               }
+       }
+
+       if (chip->conf->ce_production_mode && !conf->ce_power_offset_prod_en) {
+               cl_dbg_err(cl_hw, "Disable PPMCS/PPBW in production mode\n");
+
+               if (cl_band_is_6g(cl_hw)) {
+                       memset(conf->ce_ppmcs_offset_he_6g, 0,
+                              sizeof(conf->ce_ppmcs_offset_he_6g));
+               } else if (cl_band_is_5g(cl_hw)) {
+                       memset(conf->ce_ppmcs_offset_he_36_64, 0,
+                              sizeof(conf->ce_ppmcs_offset_he_36_64));
+                       memset(conf->ce_ppmcs_offset_he_100_140, 0,
+                              sizeof(conf->ce_ppmcs_offset_he_100_140));
+                       memset(conf->ce_ppmcs_offset_he_149_165, 0,
+                              sizeof(conf->ce_ppmcs_offset_he_149_165));
+                       memset(conf->ce_ppmcs_offset_ht_vht_36_64, 0,
+                              sizeof(conf->ce_ppmcs_offset_ht_vht_36_64));
+                       memset(conf->ce_ppmcs_offset_ht_vht_100_140, 0,
+                              sizeof(conf->ce_ppmcs_offset_ht_vht_100_140));
+                       memset(conf->ce_ppmcs_offset_ht_vht_149_165, 0,
+                              sizeof(conf->ce_ppmcs_offset_ht_vht_149_165));
+                       memset(conf->ce_ppmcs_offset_ofdm_36_64, 0,
+                              sizeof(conf->ce_ppmcs_offset_ofdm_36_64));
+                       memset(conf->ce_ppmcs_offset_ofdm_100_140, 0,
+                              sizeof(conf->ce_ppmcs_offset_ofdm_100_140));
+                       memset(conf->ce_ppmcs_offset_ofdm_149_165, 0,
+                              sizeof(conf->ce_ppmcs_offset_ofdm_149_165));
+               } else {
+                       memset(conf->ce_ppmcs_offset_he, 0, sizeof(conf->ce_ppmcs_offset_he));
+                       memset(conf->ce_ppmcs_offset_ht, 0, sizeof(conf->ce_ppmcs_offset_ht));
+                       memset(conf->ce_ppmcs_offset_ofdm, 0, sizeof(conf->ce_ppmcs_offset_ofdm));
+                       memset(conf->ce_ppmcs_offset_cck, 0, sizeof(conf->ce_ppmcs_offset_cck));
+               }
+
+               memset(conf->ce_ppbw_offset, 0, sizeof(conf->ce_ppbw_offset));
+       }
+
+       if (conf->ce_twt_default_min_wake_duration > conf->ce_twt_default_interval) {
+               CL_DBG_ERROR(cl_hw,
+                            "ce_twt_default_min_wake_duration > "
+                            "ce_twt_default_interval\n");
+               return -EINVAL;
+       }
+
+       /* 6g supports HE only */
+       if (cl_band_is_6g(cl_hw) && conf->ce_wireless_mode < WIRELESS_MODE_HE) {
+               CL_DBG_ERROR(cl_hw,
+                            "Invalid wireless_mode (%u) for 6g\n",
+                            conf->ce_wireless_mode);
+               return -EINVAL;
+       }
+
+       if (cl_calib_validate_ants(cl_hw))
+               return -EINVAL;
+
+       if (conf->ce_twt_max_sessions > CL_TWT_MAX_SESSIONS) {
+               cl_dbg_err(cl_hw,
+                          "ce_twt_max_sessions (%u) is too high. "
+                          "Setting it to the max value %u\n",
+                          conf->ce_twt_max_sessions, CL_TWT_MAX_SESSIONS);
+               conf->ce_twt_max_sessions = CL_TWT_MAX_SESSIONS;
+       }
+
+       if (!cl_band_is_24g(cl_hw) && conf->ci_signal_extension_en) {
+               cl_dbg_err(cl_hw,
+                          "ERROR: Invalid 'ci_signal_extension_en' (%u). "
+                          "Must be 0 for non 2.4Ghz band. Setting to 0\n",
+                          conf->ce_dyn_mcast_rate_en);
+
+               conf->ci_signal_extension_en = false;
+       }
+
+       if (conf->ce_dyn_mcast_rate_en && cl_band_is_6g(cl_hw)) {
+               cl_dbg_err(cl_hw,
+                          "ERROR: Invalid 'ce_dyn_mcast_rate_en' (%u). "
+                          "Must be 0 on 6Ghz band. Setting to 0\n",
+                          conf->ce_dyn_mcast_rate_en);
+
+               conf->ce_dyn_mcast_rate_en = 0;
+       }
+
+       if (conf->ce_dyn_bcast_rate_en && cl_band_is_6g(cl_hw)) {
+               cl_dbg_err(cl_hw,
+                          "ERROR: Invalid 'ce_dyn_bcast_rate_en' (%u). "
+                          "Must be 0 on 6Ghz band. Setting to 0\n",
+                          conf->ce_dyn_bcast_rate_en);
+
+               conf->ce_dyn_bcast_rate_en = 0;
+       }
+
+       return 0;
+}
+
+int cl_tcv_config_read(struct cl_hw *cl_hw)
+{
+       struct cl_chip *chip = cl_hw->chip;
+       char *buf = NULL;
+       size_t size = 0;
+       int ret = 0;
+       char filename[CL_FILENAME_MAX] = {0};
+       u8 tcv_idx = cl_hw->idx;
+
+       snprintf(filename, sizeof(filename), "cl_tcv%u.dat", tcv_idx);
+       pr_debug("%s: %s\n", __func__, filename);
+       size = cl_file_open_and_read(chip, filename, &buf);
+
+       if (!buf) {
+               pr_err("read %s failed !!!\n", filename);
+               return -ENODATA;
+       }
+
+       ret = set_all_params_from_buf(cl_hw, buf, size);
+       if (ret) {
+               kfree(buf);
+               return ret;
+       }
+
+       kfree(buf);
+
+       ret = post_configuration(cl_hw);
+
+       return ret;
+}
+
+int cl_tcv_config_set(struct cl_hw *cl_hw, char *buf, size_t size)
+{
+       size_t new_size = size + 1;
+       char *new_buf = kzalloc(new_size, GFP_KERNEL);
+       int ret;
+
+       if (!new_buf)
+               return -ENOMEM;
+
+       /* Add '\n' at the end of the string, before the NULL */
+       memcpy(new_buf, buf, size);
+       new_buf[size - 1] = '\n';
+
+       ret = set_all_params_from_buf(cl_hw, new_buf, new_size);
+       if (ret == 0)
+               ret = post_configuration(cl_hw);
+
+       kfree(new_buf);
+
+       return ret;
+}
+
+u8 cl_tcv_config_get_num_ap(struct cl_hw *cl_hw)
+{
+       struct cl_tcv_conf *conf = cl_hw->conf;
+       u8 types_cnt = min_t(u8, conf->ce_bss_num, ARRAY_SIZE(conf->ce_iface_type));
+       u8 i;
+       u8 num_ap = 0;
+
+       for (i = 0; i < types_cnt; i++)
+               if (conf->ce_iface_type[i] == NL80211_IFTYPE_AP)
+                       num_ap++;
+
+       return num_ap;
+}
+
+int cl_tcv_config_alloc(struct cl_hw *cl_hw)
+{
+       cl_hw->conf = kzalloc(sizeof(*cl_hw->conf), GFP_KERNEL);
+
+       if (!cl_hw->conf)
+               return -ENOMEM;
+
+       /* Copy default values */
+       memcpy(cl_hw->conf, &conf, sizeof(*cl_hw->conf));
+
+       return 0;
+}
+
+void cl_tcv_config_free(struct cl_hw *cl_hw)
+{
+       kfree(cl_hw->conf);
+       cl_hw->conf = NULL;
+}
+
+void cl_tcv_config_print(struct cl_hw *cl_hw)
+{
+       struct cl_tcv_conf *conf = cl_hw->conf;
+
+       pr_debug("======================\n");
+       pr_debug("  TCV%u configuration\n", cl_hw->tcv_idx);
+       pr_debug("======================\n");
+
+       print_unsigned(ce_bss_num);
+       print_signed(ce_debug_level);
+       print_bool(ce_radio_on);
+       print_bool(ce_ps_ctrl_enabled);
+       print_unsigned(ha_channel);
+       print_bool(ci_ieee80211w);
+       print_bool(ci_ieee80211h);
+       print_unsigned(ha_short_guard_interval);
+       print_unsigned(ha_max_mpdu_len);
+       print_unsigned(ha_vht_max_ampdu_len_exp);
+       print_unsigned(ha_beacon_int);
+       print_str(ce_dsp_code);
+       print_str(ce_dsp_data);
+       print_str(ce_dsp_external_data);
+       print_bool(ce_uapsd_en);
+       print_bool(ci_eirp_regulatory_en);
+       print_bool(ci_agg_tx);
+       print_bool(ci_agg_rx);
+       print_bool(ce_txldpc_en);
+       print_bool(ce_ht_rxldpc_en);
+       print_bool(ce_vht_rxldpc_en);
+       print_bool(ce_he_rxldpc_en);
+       print_bool(ci_cs_required);
+       print_signed_arr(ci_rx_sensitivity_prod, MAX_ANTENNAS);
+       print_signed_arr(ci_rx_sensitivity_op, MAX_ANTENNAS);
+       print_bool(ce_cck_bcn_en);
+       print_bool(ci_min_he_en);
+       print_hex(ce_cck_tx_ant_mask);
+       print_hex(ce_cck_rx_ant_mask);
+       print_unsigned(ce_rx_nss);
+       print_unsigned(ce_tx_nss);
+       print_unsigned(ce_num_antennas);
+       print_unsigned(ce_wireless_mode);
+       print_unsigned_arr(ha_wmm_enabled, MAX_BSS_NUM);
+       print_unsigned(ce_max_agg_size_tx);
+       print_unsigned(ce_max_agg_size_rx);
+       print_bool(ce_rxamsdu_en);
+       print_unsigned(ce_txamsdu_en);
+       print_unsigned(ci_tx_amsdu_min_data_rate);
+       print_unsigned(ci_tx_sw_amsdu_max_packets);
+       print_unsigned(ci_tx_packet_limit);
+       print_unsigned(ci_tx_queue_size_agg);
+       print_unsigned(ci_tx_queue_size_single);
+       print_unsigned_arr(ci_ipc_rxbuf_size, CL_RX_BUF_MAX);
+       print_unsigned(ce_max_retry);
+       print_unsigned(ce_short_retry_limit);
+       print_unsigned(ce_long_retry_limit);
+       print_unsigned(ci_assoc_auth_retry_limit);
+       print_unsigned(ce_channel_bandwidth);
+       print_unsigned_arr(ce_iface_type, MAX_BSS_NUM);
+       print_unsigned(ha_hw_mode);
+       print_signed(ce_temp_comp_slope);
+       print_unsigned(ci_fw_dbg_severity);
+       print_hex(ci_fw_dbg_module);
+       print_unsigned(ci_hal_idle_to);
+       print_unsigned(ci_tx_ac0_to);
+       print_unsigned(ci_tx_ac1_to);
+       print_unsigned(ci_tx_ac2_to);
+       print_unsigned(ci_tx_ac3_to);
+       print_unsigned(ci_tx_bcn_to);
+       print_str(ce_hardware_power_table);
+       print_str(ce_arr_gain);
+       print_str(ce_bf_gain_2_ant);
+       print_str(ce_bf_gain_3_ant);
+       print_str(ce_bf_gain_4_ant);
+       print_str(ce_bf_gain_5_ant);
+       print_str(ce_bf_gain_6_ant);
+       print_str(ce_ant_gain);
+       print_str(ce_ant_gain_36_64);
+       print_str(ce_ant_gain_100_140);
+       print_str(ce_ant_gain_149_165);
+       print_str(ci_min_ant_pwr);
+       print_str(ci_bw_factor);
+       print_unsigned(ce_mcast_rate);
+       print_bool(ce_dyn_mcast_rate_en);
+       print_bool(ce_dyn_bcast_rate_en);
+       print_unsigned(ce_default_mcs_ofdm);
+       print_unsigned(ce_default_mcs_cck);
+       print_bool(ce_prot_log_nav_en);
+       print_unsigned(ce_prot_mode);
+       print_unsigned(ce_prot_rate_format);
+       print_unsigned(ce_prot_rate_mcs);
+       print_unsigned(ce_prot_rate_pre_type);
+       print_unsigned(ce_bw_signaling_mode);
+       print_unsigned(ci_dyn_cts_sta_thr);
+       print_signed(ci_vns_pwr_limit);
+       print_unsigned(ci_vns_pwr_mode);
+       print_signed(ci_vns_rssi_auto_resp_thr);
+       print_signed(ci_vns_rssi_thr);
+       print_signed(ci_vns_rssi_hys);
+       print_unsigned(ci_vns_maintenance_time);
+       print_unsigned(ce_bcn_tx_path_min_time);
+       print_bool(ci_backup_bcn_en);
+       print_bool(ce_tx_txop_cut_en);
+       print_unsigned(ci_bcns_flushed_cnt_thr);
+       print_bool(ci_phy_err_prevents_phy_dump);
+       print_unsigned(ci_tx_rx_delay);
+       print_unsigned(ci_fw_assert_time_diff_sec);
+       print_unsigned(ci_fw_assert_storm_detect_thd);
+       print_unsigned(ce_hw_assert_time_max);
+       print_unsigned(ce_fw_watchdog_mode);
+       print_unsigned(ce_fw_watchdog_limit_count);
+       print_unsigned(ce_fw_watchdog_limit_time);
+       print_signed(ci_rx_remote_cpu_drv);
+       print_signed(ci_rx_remote_cpu_mac);
+       print_signed(ci_tx_remote_cpu);
+       print_unsigned(ci_pending_queue_size);
+       print_unsigned(ce_tx_power_control);
+       print_bool(ce_standby_mode_en);
+       print_bool(ce_coex_en);
+       print_unsigned(ce_extension_channel);
+       print_unsigned(ci_dfs_initial_gain);
+       print_unsigned(ci_dfs_agc_cd_th);
+       print_unsigned(ci_dfs_long_pulse_min);
+       print_unsigned(ci_dfs_long_pulse_max);
+       print_str(ce_dfs_tbl_overwrite);
+       print_str(ce_dfs_jump_channels);
+       print_signed_arr(ce_ppmcs_offset_he_36_64, WRS_MCS_MAX_HE);
+       print_signed_arr(ce_ppmcs_offset_he_100_140, WRS_MCS_MAX_HE);
+       print_signed_arr(ce_ppmcs_offset_he_149_165, WRS_MCS_MAX_HE);
+       print_signed_arr(ce_ppmcs_offset_he_6g, WRS_MCS_MAX_HE);
+       print_signed_arr(ce_ppmcs_offset_ht_vht_36_64, WRS_MCS_MAX_VHT);
+       print_signed_arr(ce_ppmcs_offset_ht_vht_100_140, WRS_MCS_MAX_VHT);
+       print_signed_arr(ce_ppmcs_offset_ht_vht_149_165, WRS_MCS_MAX_VHT);
+       print_signed_arr(ce_ppmcs_offset_ofdm_36_64, WRS_MCS_MAX_OFDM);
+       print_signed_arr(ce_ppmcs_offset_ofdm_100_140, WRS_MCS_MAX_OFDM);
+       print_signed_arr(ce_ppmcs_offset_ofdm_149_165, WRS_MCS_MAX_OFDM);
+       print_signed_arr(ce_ppmcs_offset_he, WRS_MCS_MAX_HE);
+       print_signed_arr(ce_ppmcs_offset_ht, WRS_MCS_MAX_HT);
+       print_signed_arr(ce_ppmcs_offset_ofdm, WRS_MCS_MAX_OFDM);
+       print_signed_arr(ce_ppmcs_offset_cck, WRS_MCS_MAX_CCK);
+       print_signed_arr(ce_ppbw_offset, CHNL_BW_MAX);
+       print_bool(ce_power_offset_prod_en);
+       print_bool(ce_bf_en);
+       print_unsigned(ci_bf_max_nss);
+       print_unsigned_arr(ce_sounding_interval_coefs, SOUNDING_INTERVAL_COEF_MAX);
+       print_unsigned_arr(ci_rate_fallback, CL_RATE_FALLBACK_MAX);
+       print_unsigned(ce_rx_pkts_budget);
+       print_unsigned(ci_band_num);
+       print_bool(ci_mult_ampdu_in_txop_en);
+       print_unsigned_arr(ce_wmm_aifsn, AC_MAX);
+       print_unsigned_arr(ce_wmm_cwmin, AC_MAX);
+       print_unsigned_arr(ce_wmm_cwmax, AC_MAX);
+       print_unsigned_arr(ce_wmm_txop, AC_MAX);
+       print_unsigned(ci_su_force_min_spacing);
+       print_unsigned(ci_mu_force_min_spacing);
+       print_unsigned(ci_tf_mac_pad_dur);
+       print_unsigned(ci_cca_timeout);
+       print_unsigned(ce_tx_ba_session_timeout);
+       print_bool(ci_motion_sense_en);
+       print_unsigned(ci_motion_sense_rssi_thr);
+       print_unsigned(ci_wrs_max_bw);
+       print_unsigned(ci_wrs_min_bw);
+       print_signed_arr(ci_wrs_fixed_rate, WRS_FIXED_PARAM_MAX);
+       print_unsigned_arr(ce_he_mcs_nss_supp_tx, WRS_SS_MAX);
+       print_unsigned_arr(ce_he_mcs_nss_supp_rx, WRS_SS_MAX);
+       print_unsigned_arr(ce_vht_mcs_nss_supp_tx, WRS_SS_MAX);
+       print_unsigned_arr(ce_vht_mcs_nss_supp_rx, WRS_SS_MAX);
+       print_unsigned(ci_pe_duration);
+       print_unsigned(ci_pe_duration_bcast);
+       print_unsigned(ci_coredump_diff_time_ms);
+       print_unsigned(ci_gain_update_enable);
+       print_unsigned(ci_mcs_sig_b);
+       print_unsigned(ci_spp_ksr_value);
+       print_bool(ci_rx_padding_en);
+       print_bool(ci_stats_en);
+       print_bool(ci_bar_disable);
+       print_bool(ci_ofdm_only);
+       print_bool(ci_drop_to_lower_bw);
+       print_bool(ce_twt_en);
+       print_bool(ci_csd_en);
+       print_unsigned(ce_twt_default_interval);
+       print_unsigned(ce_twt_default_min_wake_duration);
+       print_unsigned(ce_twt_max_sessions);
+       print_unsigned_arr(ci_hr_factor, CHNL_BW_MAX);
+       print_bool(ci_signal_extension_en);
+       print_unsigned_arr(ce_dscp_vlan_enable, MAX_BSS_NUM);
+       print_unsigned_arr(ce_up0_7_default_vlan_user_prio, MAX_BSS_NUM);
+       print_unsigned_arr(ce_up0_7_layer_based, MAX_BSS_NUM);
+       print_str(ce_dscp_to_up0_7dec0);
+       print_str(ce_dscp_to_up0_7dec1);
+       print_str(ce_dscp_to_up0_7dec2);
+       print_str(ce_dscp_to_up0_7dec3);
+       print_str(ce_dscp_to_up0_7dec4);
+       print_str(ce_dscp_to_up0_7dec5);
+       print_str(ce_dscp_to_up0_7dec6);
+       print_str(ce_dscp_to_up0_7dec7);
+       print_str(ce_vlan_to_up0_7dec0);
+       print_str(ce_vlan_to_up0_7dec1);
+       print_str(ce_vlan_to_up0_7dec2);
+       print_str(ce_vlan_to_up0_7dec3);
+       print_str(ce_vlan_to_up0_7dec4);
+       print_str(ce_vlan_to_up0_7dec5);
+       print_str(ce_vlan_to_up0_7dec6);
+       print_str(ce_vlan_to_up0_7dec7);
+       print_bool(ci_vht_cap_24g);
+       print_bool(ce_omi_en);
+       print_hex(ci_tx_digital_gain);
+       print_hex(ci_tx_digital_gain_cck);
+       print_signed(ci_ofdm_cck_power_offset);
+       print_bool(ci_mac_clk_gating_en);
+       print_bool(ci_phy_clk_gating_en);
+       print_bool(ci_imaging_blocker);
+       print_hex(ci_ndp_tx_chain_mask);
+       print_unsigned(ci_ndp_tx_bw);
+       print_unsigned(ci_ndp_tx_format);
+       print_unsigned(ci_ndp_tx_num_ltf);
+       print_unsigned_arr(ci_calib_ant_tx, MAX_ANTENNAS);
+       print_unsigned_arr(ci_calib_ant_rx, MAX_ANTENNAS);
+       print_signed(ci_cca_ed_rise_thr_dbm);
+       print_signed(ci_cca_ed_fall_thr_dbm);
+       print_hex(ci_cca_cs_en);
+       print_hex(ci_cca_modem_en);
+       print_hex(ci_cca_main_ant);
+       print_hex(ci_cca_second_ant);
+       print_hex(ci_cca_flag0_ctrl);
+       print_hex(ci_cca_flag1_ctrl);
+       print_hex(ci_cca_flag2_ctrl);
+       print_hex(ci_cca_flag3_ctrl);
+       print_signed(ci_cca_gi_rise_thr_dbm);
+       print_signed(ci_cca_gi_fall_thr_dbm);
+       print_signed(ci_cca_gi_pow_lim_dbm);
+       print_hex(ci_cca_ed_en);
+       print_hex(ci_cca_gi_en);
+       print_bool(ci_rx_he_mu_ppdu);
+       print_bool(ci_fast_rx_en);
+       print_unsigned(ci_distance_auto_resp_all);
+       print_unsigned(ci_distance_auto_resp_msta);
+}
--
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.
________________________________


^ permalink raw reply related	[flat|nested] 262+ messages in thread

* [RFC v1 187/256] cl8k: add tcv_config.h
  2021-06-17 15:58 [RFC v1 000/256] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (185 preceding siblings ...)
  2021-06-17 16:01 ` [RFC v1 186/256] cl8k: add tcv_config.c viktor.barna
@ 2021-06-17 16:01 ` viktor.barna
  2021-06-17 16:01 ` [RFC v1 188/256] cl8k: add temperature.c viktor.barna
                   ` (70 subsequent siblings)
  257 siblings, 0 replies; 262+ messages in thread
From: viktor.barna @ 2021-06-17 16:01 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Oleksandr Savchenko, Shay Bar, Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

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

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 drivers/net/wireless/celeno/cl8k/tcv_config.h | 333 ++++++++++++++++++
 1 file changed, 333 insertions(+)
 create mode 100644 drivers/net/wireless/celeno/cl8k/tcv_config.h

diff --git a/drivers/net/wireless/celeno/cl8k/tcv_config.h b/drivers/net/wireless/celeno/cl8k/tcv_config.h
new file mode 100644
index 000000000000..f849cecb5656
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/tcv_config.h
@@ -0,0 +1,333 @@
+/* SPDX-License-Identifier: MIT */
+/* Copyright(c) 2019-2021, Celeno Communications Ltd. */
+
+#ifndef CL_TCV_CONFIG_H
+#define CL_TCV_CONFIG_H
+
+#include "def.h"
+#include "ipc_shared.h"
+#include "wrs/wrs_db.h"
+#include "dfs/dfs_db.h"
+#include "edca.h"
+#include "utils/string.h"
+#include "sounding.h"
+
+/**
+ * TCV (=Tranceiver) configuration, is related to the specific band on top
+ * of specific chipset.
+ */
+
+#define CL_DEFAULT_HAL_IDLE_TIMEOUT 16000  /* Idle request - 16ms */
+#define CL_TX_DEFAULT_AC0_TIMEOUT   500000 /* Background - 500ms */
+#define CL_TX_DEFAULT_AC1_TIMEOUT   300000 /* Best effort - 300ms */
+#define CL_TX_DEFAULT_AC2_TIMEOUT   200000 /* Video - 200ms */
+#define CL_TX_DEFAULT_AC3_TIMEOUT   200000 /* Voice - 200ms */
+#define CL_TX_DEFAULT_BCN_TIMEOUT   150000 /* Beacon - 150ms */
+
+/* Minimal MPDU spacing we support in TX - correspond to FW NX_TX_MPDU_SPACING */
+#define CL_TX_MPDU_SPACING_INVALID 0xFF
+
+/* Default Power Per MCS (PPMCS) offsets in Q1 format */
+#define PPMCS_DFLT_OFT_V1_MCS_0  8   /* 4.0 */
+#define PPMCS_DFLT_OFT_V1_MCS_1  8
+#define PPMCS_DFLT_OFT_V1_MCS_2  6   /* 3.0 */
+#define PPMCS_DFLT_OFT_V1_MCS_3  6
+#define PPMCS_DFLT_OFT_V1_MCS_4  6
+#define PPMCS_DFLT_OFT_V1_MCS_5  4   /* 2.0 */
+#define PPMCS_DFLT_OFT_V1_MCS_6  4
+#define PPMCS_DFLT_OFT_V1_MCS_7  0
+#define PPMCS_DFLT_OFT_V1_MCS_8  -2  /* -1.0 */
+#define PPMCS_DFLT_OFT_V1_MCS_9  -2
+#define PPMCS_DFLT_OFT_V1_MCS_10 -6  /* -3.0 */
+#define PPMCS_DFLT_OFT_V1_MCS_11 -10 /* -5.0 */
+
+#define PPMCS_DFLT_OFT_V2_MCS_0  6
+#define PPMCS_DFLT_OFT_V2_MCS_1  6
+#define PPMCS_DFLT_OFT_V2_MCS_2  4
+#define PPMCS_DFLT_OFT_V2_MCS_3  4
+#define PPMCS_DFLT_OFT_V2_MCS_4  4
+#define PPMCS_DFLT_OFT_V2_MCS_5  2
+#define PPMCS_DFLT_OFT_V2_MCS_6  2
+#define PPMCS_DFLT_OFT_V2_MCS_7  0
+#define PPMCS_DFLT_OFT_V2_MCS_8  -2
+#define PPMCS_DFLT_OFT_V2_MCS_9  -2
+#define PPMCS_DFLT_OFT_V2_MCS_10 -6
+#define PPMCS_DFLT_OFT_V2_MCS_11 -10
+
+#define PPMCS_DFLT_OFT_V3_MCS_0  6   /* 3.0 */
+#define PPMCS_DFLT_OFT_V3_MCS_1  6
+#define PPMCS_DFLT_OFT_V3_MCS_2  4   /* 2.0 */
+#define PPMCS_DFLT_OFT_V3_MCS_3  4
+#define PPMCS_DFLT_OFT_V3_MCS_4  4
+#define PPMCS_DFLT_OFT_V3_MCS_5  2   /* 1.0 */
+#define PPMCS_DFLT_OFT_V3_MCS_6  2
+#define PPMCS_DFLT_OFT_V3_MCS_7  0
+#define PPMCS_DFLT_OFT_V3_MCS_8  -2  /* -1.0 */
+#define PPMCS_DFLT_OFT_V3_MCS_9  -2
+#define PPMCS_DFLT_OFT_V3_MCS_10 -10 /* -5.0 */
+#define PPMCS_DFLT_OFT_V3_MCS_11 -10
+
+/* Default Power Per Bandwidth (PPBW) offsets in Q1 format*/
+#define PPBW_DFLT_OFT_BW_20  0
+#define PPBW_DFLT_OFT_BW_40  0
+#define PPBW_DFLT_OFT_BW_80  -2
+#define PPBW_DFLT_OFT_BW_160 -2
+
+enum {
+       CL_RATE_FALLBACK_COUNT_SU,
+       CL_RATE_FALLBACK_COUNT_MU,
+       CL_RATE_FALLBACK_RETRY_COUNT_THR,
+       CL_RATE_FALLBACK_BA_PER_THR,
+       CL_RATE_FALLBACK_BA_NOT_RECEIVED_THR,
+       CL_RATE_FALLBACK_DISABLE_MCS,
+
+       CL_RATE_FALLBACK_MAX,
+};
+
+struct cl_tcv_conf {
+       u8 ce_bss_num;
+       s8 ce_debug_level;
+       bool ce_radio_on;
+       bool ce_ps_ctrl_enabled;
+       u8 ha_channel;
+       bool ci_ieee80211w;
+       bool ci_ieee80211h;
+       u8 ha_short_guard_interval;
+       u8 ha_max_mpdu_len;
+       u8 ha_vht_max_ampdu_len_exp;
+       u32 ha_beacon_int;
+       s8 ce_dsp_code[STR_LEN_32B];
+       s8 ce_dsp_data[STR_LEN_32B];
+       s8 ce_dsp_external_data[STR_LEN_32B];
+       bool ce_uapsd_en;
+       bool ci_eirp_regulatory_en;
+       bool ci_agg_tx;
+       bool ci_agg_rx;
+       bool ce_txldpc_en;
+       bool ce_ht_rxldpc_en;
+       bool ce_vht_rxldpc_en;
+       bool ce_he_rxldpc_en;
+       bool ci_cs_required;
+       s8 ci_rx_sensitivity_prod[MAX_ANTENNAS];
+       s8 ci_rx_sensitivity_op[MAX_ANTENNAS];
+       bool ce_cck_bcn_en;
+       bool ci_min_he_en;
+       u8 ce_cck_tx_ant_mask;
+       u8 ce_cck_rx_ant_mask;
+       u8 ce_rx_nss;
+       u8 ce_tx_nss;
+       u8 ce_num_antennas;
+       u8 ce_wireless_mode;
+       bool ha_wmm_enabled[MAX_BSS_NUM];
+       u16 ce_max_agg_size_tx;
+       u16 ce_max_agg_size_rx;
+       bool ce_rxamsdu_en;
+       u8 ce_txamsdu_en;
+       u16 ci_tx_amsdu_min_data_rate;
+       u8 ci_tx_sw_amsdu_max_packets;
+       u16 ci_tx_packet_limit;
+       u16 ci_tx_queue_size_agg;
+       u16 ci_tx_queue_size_single;
+       u16 ci_ipc_rxbuf_size[CL_RX_BUF_MAX];
+       u16 ce_max_retry;
+       u8 ce_short_retry_limit;
+       u8 ce_long_retry_limit;
+       u8 ci_assoc_auth_retry_limit;
+       u8 ce_channel_bandwidth;
+       u8 ce_iface_type[MAX_BSS_NUM];
+       u8 ha_hw_mode;
+       s8 ce_temp_comp_slope;
+       u32 ci_fw_dbg_severity;
+       u32 ci_fw_dbg_module;
+       u32 ci_hal_idle_to;
+       u32 ci_tx_ac0_to;
+       u32 ci_tx_ac1_to;
+       u32 ci_tx_ac2_to;
+       u32 ci_tx_ac3_to;
+       u32 ci_tx_bcn_to;
+       s8 ce_hardware_power_table[STR_LEN_256B];
+       s8 ce_arr_gain[STR_LEN_32B];
+       s8 ce_bf_gain_2_ant[STR_LEN_32B];
+       s8 ce_bf_gain_3_ant[STR_LEN_32B];
+       s8 ce_bf_gain_4_ant[STR_LEN_32B];
+       s8 ce_bf_gain_5_ant[STR_LEN_32B];
+       s8 ce_bf_gain_6_ant[STR_LEN_32B];
+       s8 ce_ant_gain[STR_LEN_32B];
+       s8 ce_ant_gain_36_64[STR_LEN_32B];
+       s8 ce_ant_gain_100_140[STR_LEN_32B];
+       s8 ce_ant_gain_149_165[STR_LEN_32B];
+       s8 ci_min_ant_pwr[STR_LEN_32B];
+       s8 ci_bw_factor[STR_LEN_32B];
+       u8 ce_mcast_rate;
+       bool ce_dyn_mcast_rate_en;
+       bool ce_dyn_bcast_rate_en;
+       u8 ce_default_mcs_ofdm;
+       u8 ce_default_mcs_cck;
+       bool ce_prot_log_nav_en;
+       u8 ce_prot_mode;
+       u8 ce_prot_rate_format;
+       u8 ce_prot_rate_mcs;
+       u8 ce_prot_rate_pre_type;
+       u8 ce_bw_signaling_mode;
+       u8 ci_dyn_cts_sta_thr;
+       s8 ci_vns_pwr_limit;
+       u8 ci_vns_pwr_mode;
+       s8 ci_vns_rssi_auto_resp_thr;
+       s8 ci_vns_rssi_thr;
+       s8 ci_vns_rssi_hys;
+       u16 ci_vns_maintenance_time;
+       u16 ce_bcn_tx_path_min_time;
+       bool ci_backup_bcn_en;
+       bool ce_tx_txop_cut_en;
+       u8 ci_bcns_flushed_cnt_thr;
+       bool ci_phy_err_prevents_phy_dump;
+       u8 ci_tx_rx_delay;
+       u8 ci_fw_assert_time_diff_sec;
+       u8 ci_fw_assert_storm_detect_thd;
+       u32 ce_hw_assert_time_max;
+       u8 ce_fw_watchdog_mode;
+       u8 ce_fw_watchdog_limit_count;
+       u32 ce_fw_watchdog_limit_time;
+       s8 ci_rx_remote_cpu_drv;
+       s8 ci_rx_remote_cpu_mac;
+       s8 ci_tx_remote_cpu;
+       u16 ci_pending_queue_size;
+       u8 ce_tx_power_control;
+       bool ce_standby_mode_en;
+       bool ce_coex_en;
+       s8 ce_extension_channel;
+       u8 ci_dfs_initial_gain;
+       u8 ci_dfs_agc_cd_th;
+       u16 ci_dfs_long_pulse_min;
+       u16 ci_dfs_long_pulse_max;
+       s8 ce_dfs_tbl_overwrite[STR_LEN_64B];
+       s8 ce_dfs_jump_channels[STR_LEN_32B];
+       /* Power Per MCS values - 6g */
+       s8 ce_ppmcs_offset_he_6g[WRS_MCS_MAX_HE];
+       /* Power Per MCS values - 5g */
+       s8 ce_ppmcs_offset_he_36_64[WRS_MCS_MAX_HE];
+       s8 ce_ppmcs_offset_he_100_140[WRS_MCS_MAX_HE];
+       s8 ce_ppmcs_offset_he_149_165[WRS_MCS_MAX_HE];
+       s8 ce_ppmcs_offset_ht_vht_36_64[WRS_MCS_MAX_VHT];
+       s8 ce_ppmcs_offset_ht_vht_100_140[WRS_MCS_MAX_VHT];
+       s8 ce_ppmcs_offset_ht_vht_149_165[WRS_MCS_MAX_VHT];
+       s8 ce_ppmcs_offset_ofdm_36_64[WRS_MCS_MAX_OFDM];
+       s8 ce_ppmcs_offset_ofdm_100_140[WRS_MCS_MAX_OFDM];
+       s8 ce_ppmcs_offset_ofdm_149_165[WRS_MCS_MAX_OFDM];
+       /* Power Per MCS values - 24g */
+       s8 ce_ppmcs_offset_he[WRS_MCS_MAX_HE];
+       s8 ce_ppmcs_offset_ht[WRS_MCS_MAX_HT];
+       s8 ce_ppmcs_offset_ofdm[WRS_MCS_MAX_OFDM];
+       s8 ce_ppmcs_offset_cck[WRS_MCS_MAX_CCK];
+       /* Power Per BW values - all bands */
+       s8 ce_ppbw_offset[CHNL_BW_MAX];
+       bool ce_power_offset_prod_en;
+       bool ce_bf_en;
+       u8 ci_bf_max_nss;
+       u16 ce_sounding_interval_coefs[SOUNDING_INTERVAL_COEF_MAX];
+       u8 ci_rate_fallback[CL_RATE_FALLBACK_MAX];
+       u16 ce_rx_pkts_budget;
+       u8 ci_band_num;
+       bool ci_mult_ampdu_in_txop_en;
+       u8 ce_wmm_aifsn[AC_MAX];
+       u8 ce_wmm_cwmin[AC_MAX];
+       u8 ce_wmm_cwmax[AC_MAX];
+       u16 ce_wmm_txop[AC_MAX];
+       u8 ci_su_force_min_spacing;
+       u8 ci_mu_force_min_spacing;
+       u8 ci_tf_mac_pad_dur;
+       u32 ci_cca_timeout;
+       u16 ce_tx_ba_session_timeout;
+       bool ci_motion_sense_en;
+       s8 ci_motion_sense_rssi_thr;
+       u8 ci_wrs_max_bw;
+       u8 ci_wrs_min_bw;
+       s8 ci_wrs_fixed_rate[WRS_FIXED_PARAM_MAX];
+       u8 ce_he_mcs_nss_supp_tx[WRS_SS_MAX];
+       u8 ce_he_mcs_nss_supp_rx[WRS_SS_MAX];
+       u8 ce_vht_mcs_nss_supp_tx[WRS_SS_MAX];
+       u8 ce_vht_mcs_nss_supp_rx[WRS_SS_MAX];
+       u8 ci_pe_duration;
+       u8 ci_pe_duration_bcast;
+       u32 ci_coredump_diff_time_ms;
+       u8 ci_gain_update_enable;
+       u8 ci_mcs_sig_b;
+       u8 ci_spp_ksr_value;
+       bool ci_rx_padding_en;
+       bool ci_stats_en;
+       bool ci_bar_disable;
+       bool ci_ofdm_only;
+       bool ci_drop_to_lower_bw;
+       bool ce_twt_en;
+       u32 ce_twt_default_interval;
+       u32 ce_twt_default_min_wake_duration;
+       u8 ce_twt_max_sessions;
+       u8 ci_hr_factor[CHNL_BW_MAX];
+       bool ci_csd_en;
+       bool ci_signal_extension_en;
+       bool ce_dscp_vlan_enable[MAX_BSS_NUM];
+       u8 ce_up0_7_default_vlan_user_prio[MAX_BSS_NUM];
+       u8 ce_up0_7_layer_based[MAX_BSS_NUM];
+       s8 ce_dscp_to_up0_7dec0[STR_LEN_128B];
+       s8 ce_dscp_to_up0_7dec1[STR_LEN_128B];
+       s8 ce_dscp_to_up0_7dec2[STR_LEN_128B];
+       s8 ce_dscp_to_up0_7dec3[STR_LEN_128B];
+       s8 ce_dscp_to_up0_7dec4[STR_LEN_128B];
+       s8 ce_dscp_to_up0_7dec5[STR_LEN_128B];
+       s8 ce_dscp_to_up0_7dec6[STR_LEN_128B];
+       s8 ce_dscp_to_up0_7dec7[STR_LEN_128B];
+       s8 ce_vlan_to_up0_7dec0[STR_LEN_128B];
+       s8 ce_vlan_to_up0_7dec1[STR_LEN_128B];
+       s8 ce_vlan_to_up0_7dec2[STR_LEN_128B];
+       s8 ce_vlan_to_up0_7dec3[STR_LEN_128B];
+       s8 ce_vlan_to_up0_7dec4[STR_LEN_128B];
+       s8 ce_vlan_to_up0_7dec5[STR_LEN_128B];
+       s8 ce_vlan_to_up0_7dec6[STR_LEN_128B];
+       s8 ce_vlan_to_up0_7dec7[STR_LEN_128B];
+       bool ci_vht_cap_24g;
+       bool ce_omi_en;
+       u32 ci_tx_digital_gain;
+       u32 ci_tx_digital_gain_cck;
+       s8 ci_ofdm_cck_power_offset;
+       bool ci_mac_clk_gating_en;
+       bool ci_phy_clk_gating_en;
+       bool ci_imaging_blocker;
+       u8 ci_ndp_tx_chain_mask;
+       u8 ci_ndp_tx_bw;
+       u8 ci_ndp_tx_format;
+       u8 ci_ndp_tx_num_ltf;
+       u8 ci_calib_ant_tx[MAX_ANTENNAS];
+       u8 ci_calib_ant_rx[MAX_ANTENNAS];
+       s8 ci_cca_ed_rise_thr_dbm;
+       s8 ci_cca_ed_fall_thr_dbm;
+       u8 ci_cca_cs_en;
+       u8 ci_cca_modem_en;
+       u8 ci_cca_main_ant;
+       u8 ci_cca_second_ant;
+       u8 ci_cca_flag0_ctrl;
+       u8 ci_cca_flag1_ctrl;
+       u8 ci_cca_flag2_ctrl;
+       u8 ci_cca_flag3_ctrl;
+       s8 ci_cca_gi_rise_thr_dbm;
+       s8 ci_cca_gi_fall_thr_dbm;
+       s8 ci_cca_gi_pow_lim_dbm;
+       u16 ci_cca_ed_en;
+       u8 ci_cca_gi_en;
+       bool ci_rx_he_mu_ppdu;
+       bool ci_fast_rx_en;
+       u8 ci_distance_auto_resp_all;
+       u8 ci_distance_auto_resp_msta;
+
+       /* New NVRAM parameters must be added to cl_tcv_config_print() */
+};
+
+struct cl_hw;
+
+int cl_tcv_config_read(struct cl_hw *cl_hw);
+int cl_tcv_config_set(struct cl_hw *cl_hw, char *buf, size_t size);
+u8 cl_tcv_config_get_num_ap(struct cl_hw *cl_hw);
+int cl_tcv_config_alloc(struct cl_hw *cl_hw);
+void cl_tcv_config_free(struct cl_hw *cl_hw);
+void cl_tcv_config_print(struct cl_hw *cl_hw);
+
+#endif /* CL_TCV_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.
________________________________


^ permalink raw reply related	[flat|nested] 262+ messages in thread

* [RFC v1 188/256] cl8k: add temperature.c
  2021-06-17 15:58 [RFC v1 000/256] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (186 preceding siblings ...)
  2021-06-17 16:01 ` [RFC v1 187/256] cl8k: add tcv_config.h viktor.barna
@ 2021-06-17 16:01 ` viktor.barna
  2021-06-17 16:01 ` [RFC v1 189/256] cl8k: add temperature.h viktor.barna
                   ` (69 subsequent siblings)
  257 siblings, 0 replies; 262+ messages in thread
From: viktor.barna @ 2021-06-17 16:01 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Oleksandr Savchenko, Shay Bar, Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

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

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 .../net/wireless/celeno/cl8k/temperature.c    | 858 ++++++++++++++++++
 1 file changed, 858 insertions(+)
 create mode 100644 drivers/net/wireless/celeno/cl8k/temperature.c

diff --git a/drivers/net/wireless/celeno/cl8k/temperature.c b/drivers/net/wireless/celeno/cl8k/temperature.c
new file mode 100644
index 000000000000..1fde1acfe386
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/temperature.c
@@ -0,0 +1,858 @@
+// SPDX-License-Identifier: MIT
+/* Copyright(c) 2019-2021, Celeno Communications Ltd. */
+
+#include <linux/kthread.h>
+#include "temperature.h"
+#include "radio.h"
+#include "utils/math.h"
+#include "utils/utils.h"
+#include "calib.h"
+#include "chip.h"
+#include "e2p.h"
+#include "channel.h"
+#include "power.h"
+#include "fw/msg_tx.h"
+
+#define TEMP_PROTECT_STATE_STR(delta) \
+       ((delta) == TEMP_PROTECT_OFF ? "DISABLE" : \
+       ((delta) == TEMP_PROTECT_INTERNAL ? "INTERNAL" : \
+       ((delta) == TEMP_PROTECT_EXTERNAL ? "EXTERNAL" : \
+       ((delta) == TEMP_PROTECT_DIFF ? "DIFF" : "UNKNOWN"))))
+
+#define TEMP_DIFF_INVALID 0x7F
+
+#define TEMPERATURE_MIN 0
+#define TEMPERATURE_MAX 127
+
+#define DUTY_CYCLE_MAX  100
+#define DUTY_CYCLE_MIN  20
+#define DUTY_CYCLE_STEP 20
+
+static int cl_temperature_read_fw(struct cl_hw *cl_hw, enum cl_temp_mode desired_temp_mode,
+                                 u16 *raw_bits)
+{
+       u8 retval = 0;
+       struct mm_anamon_read_cfm *cfm;
+
+       if (cl_msg_tx_anamon_read(cl_hw, ANAMON_MODE_TEMPERATURE, desired_temp_mode, 0) != 0) {
+               cl_dbg_err(cl_hw, "cl_msg_tx_anamon_read failed\n");
+               cl_msg_tx_free_cfm_params(cl_hw, MM_ANAMON_READ_CFM);
+               return -ENODATA;
+       }
+
+       cfm = (struct mm_anamon_read_cfm *)(cl_hw->msg_cfm_params[MM_ANAMON_READ_CFM]);
+
+       if (!cfm)
+               return -ENOMSG;
+
+       retval = cfm->retval;
+       *raw_bits = ((le16_to_cpu(cfm->raw_bits_data_0) + le16_to_cpu(cfm->raw_bits_data_1)) / 2);
+       cl_msg_tx_free_cfm_params(cl_hw, MM_ANAMON_READ_CFM);
+
+       return retval ? 0 : -EILSEQ;
+}
+
+static u16 cl_adc_to_mv(u16 adc)
+{
+       return (adc * 1800) >> 12;
+}
+
+static s16 cl_raw_bits_to_temperature(u16 raw_bits, enum cl_temp_mode desired_temp_mode)
+{
+       s16 adcmv = cl_adc_to_mv(raw_bits);
+
+       /* Calculation of external thermistor */
+       if (desired_temp_mode == TEMP_MODE_EXTERNAL) {
+
+               /*
+                * External-temperature calculation:
+                * Ext_tmp = -169 * adcv ^ 3 + 342 * adcv ^ 2 - 316 * adcv + 139
+                *
+                * Ext_tmp = -169 * (adcmv / 1000) ^ 3 +
+                *           342 * (adcmv / 1000) ^ 2 -
+                *           316 * (adcmv / 1000) +
+                *           139
+                *
+                * Ext_tmp = (-169 * adcmv ^ 3 +
+                *            342000 * adcmv ^ 2 -
+                *            316000000 * adcmv +
+                *            139000000000) / 1000000000
+                */
+               return (s16)div_s64(-169UL * adcmv * adcmv * adcmv +
+                                   342000UL * adcmv * adcmv -
+                                   316000000UL * adcmv +
+                                   139000000000UL,
+                                   1000000000);
+       }
+
+       /* Calculation of internal thermistor - ADCmv * slope - 163 (slope=0.290) */
+       if (desired_temp_mode == TEMP_MODE_INTERNAL)
+               return ((adcmv * 29) / 100) - 163;
+
+       return 0;
+}
+
+void cl_temperature_set_power_offset(struct cl_hw *cl_hw, s8 power_offset)
+{
+       s8 total_pwr_offset[MAX_ANTENNAS] = {0};
+       u8 chan_idx = cl_channel_to_index(cl_hw, cl_hw->channel);
+       int i = 0;
+
+       cl_hw->temp_comp_db.power_offset = power_offset;
+
+       if (chan_idx == INVALID_CHAN_IDX)
+               goto out;
+
+       for (i = 0; i < cl_hw->num_antennas; i++)
+               total_pwr_offset[i] =
+                       (cl_hw->tx_pow_info[chan_idx][i].offset + POWER_OFFSET_RES * power_offset);
+
+out:
+       cl_msg_tx_set_ant_pwr_offset(cl_hw, total_pwr_offset);
+}
+
+static void cl_temperature_comp_tcv(struct cl_chip *chip, struct cl_hw *cl_hw, s16 temp_internal)
+{
+       struct cl_temp_comp_db *temp_comp_db = &cl_hw->temp_comp_db;
+       s8 new_power_offset = 0;
+
+       /* Accumulate temperature delta */
+       temp_comp_db->acc_temp_delta += (temp_internal - temp_comp_db->calib_temperature);
+
+       /* Check if it is time to make a new decision */
+       if ((chip->temperature.comp_iterations % CL_TEMP_COMP_ITERATIONS) != 0)
+               return;
+
+       /* Average the temperature delta over the last CL_TEMP_COMP_ITERATIONS samples */
+       temp_comp_db->avg_temp_delta = DIV_ROUND_CLOSEST(temp_comp_db->acc_temp_delta,
+                                                        CL_TEMP_COMP_ITERATIONS);
+
+       /* Reset accumulated temp delta */
+       temp_comp_db->acc_temp_delta = 0;
+
+       new_power_offset = (s8)DIV_ROUND_CLOSEST(temp_comp_db->avg_temp_delta *
+                                                cl_hw->conf->ce_temp_comp_slope, 100);
+
+       if (temp_comp_db->power_offset == new_power_offset)
+               return;
+
+       cl_dbg_trace(cl_hw, "calib_temperature %d, avg_temp_delta %d, power_offset %d\n",
+                    temp_comp_db->calib_temperature,
+                    temp_comp_db->avg_temp_delta,
+                    new_power_offset);
+
+       cl_temperature_set_power_offset(cl_hw, new_power_offset);
+}
+
+static void cl_temperature_comp(struct cl_chip *chip, struct cl_hw *cl_hw)
+{
+       struct cl_temperature *temperature = &chip->temperature;
+       s16 temp_internal = 0;
+
+       if (!chip->conf->ce_temp_comp_en)
+               return;
+
+       temp_internal = cl_temperature_read(cl_hw, TEMP_MODE_INTERNAL);
+       temperature->comp_iterations++;
+
+       cl_dbg_chip_trace(chip, "comp_iterations = %u, temp_internal = %d\n",
+                         (temperature->comp_iterations % CL_TEMP_COMP_ITERATIONS), temp_internal);
+
+       if (cl_chip_is_tcv0_enabled(chip))
+               cl_temperature_comp_tcv(chip, chip->cl_hw_tcv0, temp_internal);
+
+       if (cl_chip_is_tcv1_enabled(chip))
+               cl_temperature_comp_tcv(chip, chip->cl_hw_tcv1, temp_internal);
+}
+
+static void cl_temperature_tx_duty_cycle(struct cl_chip *chip, u8 duty_cycle)
+{
+       u16 periodic_tx_time_on = chip->conf->ce_temp_protect_tx_period_ms * duty_cycle / 100;
+       u16 periodic_tx_time_off = chip->conf->ce_temp_protect_tx_period_ms - periodic_tx_time_on;
+
+       if (cl_chip_is_tcv0_enabled(chip))
+               cl_msg_tx_start_periodic_tx_time(chip->cl_hw_tcv0,
+                                                periodic_tx_time_off, periodic_tx_time_on);
+
+       if (cl_chip_is_tcv1_enabled(chip))
+               cl_msg_tx_start_periodic_tx_time(chip->cl_hw_tcv1,
+                                                periodic_tx_time_off, periodic_tx_time_on);
+}
+
+static void cl_temperature_protect_radio_off(struct cl_chip *chip, s16 temp_avg)
+{
+       struct cl_temp_protect_db *temp_protect_db = &chip->temperature.protect_db;
+       struct cl_chip_conf *conf = chip->conf;
+
+       if (temp_protect_db->force_radio_off)
+               return;
+
+       cl_radio_off_chip(chip);
+       temp_protect_db->force_radio_off = true;
+       cl_dbg_chip_verbose(chip, "temperature [%d] >= radio off threshold [%d] --> radio off!\n",
+                           temp_avg, conf->ce_temp_protect_radio_off_th);
+}
+
+static void cl_temperature_protect_radio_on(struct cl_chip *chip, s16 temp_avg)
+{
+       struct cl_temp_protect_db *temp_protect_db = &chip->temperature.protect_db;
+       struct cl_chip_conf *conf = chip->conf;
+       s16 temp_thr = conf->ce_temp_protect_radio_off_th - CL_TEMP_PROTECT_RADIO_OFF_HYST;
+
+       if (temp_avg >= temp_thr)
+               return;
+
+       cl_radio_on_chip(chip);
+       temp_protect_db->force_radio_off = false;
+       cl_dbg_chip_verbose(chip, "temperature [%d] < radio off threshold - hysteresis [%d] "
+                                 "--> radio on!\n",
+                           temp_avg, temp_thr);
+}
+
+static void cl_temperature_protect_dec_duty_cycle(struct cl_chip *chip, s16 temp_avg)
+{
+       struct cl_temp_protect_db *temp_protect_db = &chip->temperature.protect_db;
+       struct cl_chip_conf *conf = chip->conf;
+
+       if (temp_protect_db->duty_cycle == DUTY_CYCLE_MIN)
+               return;
+
+       temp_protect_db->duty_cycle -= DUTY_CYCLE_STEP;
+       cl_temperature_tx_duty_cycle(chip, temp_protect_db->duty_cycle);
+       cl_dbg_chip_warn(chip,
+                        "temperature [%d] > protect_th_max [%d] --> decrease duty cycle [%u]!\n",
+                        temp_avg, conf->ce_temp_protect_th_max, temp_protect_db->duty_cycle);
+}
+
+static void cl_temperature_protect_inc_duty_cycle(struct cl_chip *chip, s16 temp_avg)
+{
+       struct cl_temp_protect_db *temp_protect_db = &chip->temperature.protect_db;
+       struct cl_chip_conf *conf = chip->conf;
+
+       if (temp_protect_db->duty_cycle == DUTY_CYCLE_MAX)
+               return;
+
+       temp_protect_db->duty_cycle += DUTY_CYCLE_STEP;
+       cl_temperature_tx_duty_cycle(chip, temp_protect_db->duty_cycle);
+       cl_dbg_chip_warn(chip,
+                        "temperature [%d] < protect_th_min [%d] --> increase duty cycle [%u]!\n",
+                        temp_avg, conf->ce_temp_protect_th_min, temp_protect_db->duty_cycle);
+}
+
+static void cl_temperature_protect_decision(struct cl_chip *chip, s16 temp_avg)
+{
+       struct cl_temp_protect_db *temp_protect_db = &chip->temperature.protect_db;
+       struct cl_chip_conf *conf = chip->conf;
+
+       /* Test mode - force test_mode_duty_cycle */
+       if (unlikely(temp_protect_db->test_mode_duty_cycle != DUTY_CYCLE_MAX)) {
+               cl_temperature_tx_duty_cycle(chip, temp_protect_db->test_mode_duty_cycle);
+               return;
+       }
+
+       /* Temperature protection logic:
+        *
+        * If the temperature is greater or equal to the radio off threshold
+        * then set the radio off.
+        * If the temperature is below the (radio off threshold - hysteresis [10])
+        * then set the radio on again.
+        *
+        * Any time the temperature is greater than the max threshold then we
+        * decrease the duty cycle.
+        * Any time the temperature is below the min threshold then we increase
+        * the duty cycle.
+        */
+       if (temp_avg >= conf->ce_temp_protect_radio_off_th) {
+               cl_temperature_protect_radio_off(chip, temp_avg);
+               return;
+       }
+
+       if (temp_protect_db->force_radio_off) {
+               cl_temperature_protect_radio_on(chip, temp_avg);
+               return;
+       }
+
+       if (temp_avg > conf->ce_temp_protect_th_max) {
+               cl_temperature_protect_dec_duty_cycle(chip, temp_avg);
+               return;
+       }
+
+       if (temp_avg < chip->conf->ce_temp_protect_th_min) {
+               cl_temperature_protect_inc_duty_cycle(chip, temp_avg);
+               return;
+       }
+}
+
+static s16 cl_temperature_avg_protect(struct cl_temp_protect_db *temp_protect_db)
+{
+       /* Calculate average of last_samples */
+       u8 i;
+       s32 temp_avg = 0;
+
+       for (i = 0; i < CL_TEMP_PROTECT_NUM_SAMPLES; i++)
+               temp_avg += temp_protect_db->last_samples[i];
+
+       return (s16)(temp_avg / CL_TEMP_PROTECT_NUM_SAMPLES);
+}
+
+static void cl_temperature_protect_handle_read(struct cl_chip *chip, s16 temp)
+{
+       struct cl_temp_protect_db *temp_protect_db = &chip->temperature.protect_db;
+       unsigned long curr_time = jiffies_to_msecs(jiffies);
+       unsigned long delta_time = CL_TIME_DIFF(curr_time, temp_protect_db->last_timestamp);
+
+       /* Add current read */
+       temp_protect_db->last_samples[temp_protect_db->curr_idx] = temp;
+       temp_protect_db->curr_idx = (temp_protect_db->curr_idx + 1) % CL_TEMP_PROTECT_NUM_SAMPLES;
+
+       if (delta_time >= CL_TEMP_PROTECT_INTERVAL_MS) {
+               s16 temp_avg = cl_temperature_avg_protect(temp_protect_db);
+
+               cl_dbg_chip_trace(chip, "temp_avg = %d, delta_time = %lu\n", temp_avg, delta_time);
+               cl_temperature_protect_decision(chip, temp_avg);
+               temp_protect_db->last_timestamp = curr_time;
+       }
+}
+
+static void cl_temperature_protect(struct cl_chip *chip, struct cl_hw *cl_hw)
+{
+       s16 protect_temp = 0;
+       struct cl_chip_conf *conf = chip->conf;
+
+       switch (conf->ce_temp_protect_en) {
+       case TEMP_PROTECT_OFF:
+               return;
+       case TEMP_PROTECT_INTERNAL:
+               protect_temp = cl_temperature_read(cl_hw, TEMP_MODE_INTERNAL) +
+                       conf->ce_temp_protect_delta;
+               break;
+       case TEMP_PROTECT_EXTERNAL:
+               protect_temp = cl_temperature_read(cl_hw, TEMP_MODE_EXTERNAL) +
+                       conf->ce_temp_protect_delta;
+               break;
+       case TEMP_PROTECT_DIFF:
+               protect_temp = cl_temperature_read(cl_hw, TEMP_MODE_INTERNAL) -
+                       chip->temperature.diff_internal_external + conf->ce_temp_protect_delta;
+               break;
+       }
+
+       cl_temperature_protect_handle_read(chip, protect_temp);
+}
+
+static int cl_temperature_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,
+                "temp usage:\n"
+                "Temperature compensation:\n"
+                "-a : Print the temperature compensation configuration\n"
+                "-b : Set temperature compensation on/off [0:Dis,1:En]\n"
+                "-c : Set temperature compensation slope "
+                       "[3 digit number without a point] "
+                       "example: '109'=>1.09, '76'=>0.76\n"
+                "Temperature protect:\n"
+                "-k : Print temperature protection configuration\n"
+                "-l : Print temperature protect current status\n"
+                "-m : Set test mode [0 - 100, 100 = disable]\n"
+                "Temperature general:\n"
+                "-u : Update temperature diff\n"
+                "-v : Read temperature [0:internal, 1:external, "
+                       "2:internal+delta, 3=external+delta, "
+                       "4=internal-diff+delta]\n");
+
+       err = cl_vendor_reply(cl_hw, buf, strlen(buf));
+       kfree(buf);
+
+       return err;
+}
+
+static int cl_temperature_protect_print_config(struct cl_hw *cl_hw)
+{
+       struct cl_chip_conf *conf = cl_hw->chip->conf;
+       char *buf = NULL;
+       ssize_t buf_size;
+       int err = 0;
+       int len = 0;
+
+       cl_snprintf(&buf, &len, &buf_size,
+                   "Temperature protect configuration:\n");
+       cl_snprintf(&buf, &len, &buf_size,
+                   "ce_temp_protect_en           : %s\n",
+                   TEMP_PROTECT_STATE_STR(conf->ce_temp_protect_en));
+       cl_snprintf(&buf, &len, &buf_size,
+                   "ce_temp_protect_delta        : %3d [Celsius]\n",
+                   conf->ce_temp_protect_delta);
+       cl_snprintf(&buf, &len, &buf_size,
+                   "ce_temp_protect_th_max       : %3d [Celsius]\n",
+                   conf->ce_temp_protect_th_max);
+       cl_snprintf(&buf, &len, &buf_size,
+                   "ce_temp_protect_th_min       : %3d [Celsius]\n",
+                   conf->ce_temp_protect_th_min);
+       cl_snprintf(&buf, &len, &buf_size,
+                   "ce_temp_protect_radio_off_th : %3d [Celsius]\n",
+                   conf->ce_temp_protect_radio_off_th);
+       cl_snprintf(&buf, &len, &buf_size,
+                   "ce_temp_protect_tx_period_ms : %5u [ms]\n",
+                   conf->ce_temp_protect_tx_period_ms);
+
+       err = cl_vendor_reply(cl_hw, buf, strlen(buf));
+       kfree(buf);
+
+       return err;
+}
+
+static int cl_temperature_protect_print_status(struct cl_hw *cl_hw)
+{
+       struct cl_temp_protect_db *protect_db =
+                                       &cl_hw->chip->temperature.protect_db;
+       char *buf = NULL;
+       ssize_t buf_size;
+       int err = 0;
+       int len = 0;
+
+       cl_snprintf(&buf, &len, &buf_size,
+                   "Temperature protect status:\n"
+                   "Force radio off      = %u\n",
+                   protect_db->force_radio_off);
+       cl_snprintf(&buf, &len, &buf_size,
+                   "Duty cycle           = %u\n",
+                   protect_db->duty_cycle);
+       cl_snprintf(&buf, &len, &buf_size,
+                   "Test mode duty cycle = %u\n",
+                   protect_db->test_mode_duty_cycle);
+
+       err = cl_vendor_reply(cl_hw, buf, strlen(buf));
+       kfree(buf);
+
+       return err;
+}
+
+static void cl_temperature_protect_test_mode_set(struct cl_chip *chip, u8 duty_cycle)
+{
+       chip->temperature.protect_db.test_mode_duty_cycle = duty_cycle;
+
+       if (duty_cycle == DUTY_CYCLE_MAX)
+               pr_debug("Disable temp protection test mode\n");
+       else
+               pr_debug("Enable temp protection test mode [%u]\n", duty_cycle);
+}
+
+static void cl_temperature_comp_comp_slope_set(struct cl_hw *cl_hw, s8 slope)
+{
+       cl_hw->conf->ce_temp_comp_slope = slope;
+
+       pr_debug("Temperature compensation slope: %d.%02d\n", slope / 100, slope % 100);
+}
+
+static int cl_e2p_read_temp_diff(struct cl_chip *chip, s8 *temp_diff)
+{
+       /* Read temp_diff from eeprom */
+       return cl_e2p_read(chip, temp_diff, SIZE_GEN_TEMP_DIFF, ADDR_GEN_TEMP_DIFF);
+}
+
+static int cl_e2p_write_temp_diff(struct cl_chip *chip, s8 temp_diff)
+{
+       /* Writing temp_diff to eeprom */
+       return cl_e2p_write(chip, (u8 *)&temp_diff, SIZE_GEN_TEMP_DIFF, ADDR_GEN_TEMP_DIFF);
+}
+
+static int cl_temperature_diff_update(struct cl_hw *cl_hw)
+{
+       s8 temp_diff = cl_temperature_read(cl_hw, TEMP_MODE_INTERNAL) -
+               cl_temperature_read(cl_hw, TEMP_MODE_EXTERNAL);
+
+       if (cl_e2p_write_temp_diff(cl_hw->chip, temp_diff)) {
+               cl_dbg_err(cl_hw, "Error occurred while writing temperature diff to EEPROM.\n");
+               return -1;
+       }
+
+       cl_hw->chip->temperature.diff_internal_external = temp_diff;
+       return 0;
+}
+
+static void cl_temperature_comp_enable(struct cl_chip *chip, s32 enable)
+{
+       if (enable) {
+               cl_dbg_chip_verbose(chip, "enable\n");
+               chip->conf->ce_temp_comp_en = true;
+       } else {
+               cl_dbg_chip_verbose(chip, "disable\n");
+               chip->conf->ce_temp_comp_en = false;
+
+               if (cl_chip_is_tcv0_enabled(chip))
+                       cl_temperature_set_power_offset(chip->cl_hw_tcv0, 0);
+
+               if (cl_chip_is_tcv1_enabled(chip))
+                       cl_temperature_set_power_offset(chip->cl_hw_tcv1, 0);
+       }
+}
+
+static int cl_temperature_kthread(void *arg)
+{
+       struct cl_chip *chip = (struct cl_chip *)arg;
+       struct cl_hw *cl_hw = NULL;
+       unsigned long timeout = msecs_to_jiffies(CL_TEMPERATURE_TIMER_INTERVAL_MS);
+
+       while (true) {
+               cl_hw = cl_chip_is_tcv0_enabled(chip) ? chip->cl_hw_tcv0 : chip->cl_hw_tcv1;
+
+               if (cl_hw &&
+                   !chip->conf->ce_production_mode &&
+                   test_bit(CL_DEV_STARTED, &cl_hw->drv_flags)) {
+                       cl_temperature_comp(chip, cl_hw);
+                       cl_temperature_protect(chip, cl_hw);
+               }
+
+               if (wait_event_timeout(chip->temperature.wait_q, kthread_should_stop(), timeout)) {
+                       cl_dbg_chip_trace(chip, "exit temperature kthread\n");
+                       return 0;
+               }
+       }
+}
+
+static void cl_temperature_recovery_protect(struct cl_hw *cl_hw)
+{
+       struct cl_chip *chip = cl_hw->chip;
+
+       if (chip->conf->ce_temp_protect_en != TEMP_PROTECT_OFF) {
+               u8 duty_cycle = chip->temperature.protect_db.duty_cycle;
+
+               if (duty_cycle < DUTY_CYCLE_MAX) {
+                       u16 periodic_tx_time_on =
+                               chip->conf->ce_temp_protect_tx_period_ms * duty_cycle / 100;
+                       u16 periodic_tx_time_off =
+                               chip->conf->ce_temp_protect_tx_period_ms - periodic_tx_time_on;
+
+                       cl_msg_tx_start_periodic_tx_time(cl_hw, periodic_tx_time_off,
+                                                        periodic_tx_time_on);
+               }
+       }
+}
+
+static void cl_temperature_recovery_comp(struct cl_hw *cl_hw)
+{
+       struct cl_chip *chip = cl_hw->chip;
+       s8 power_offset = cl_hw->temp_comp_db.power_offset;
+
+       if (!chip->conf->ce_temp_comp_en)
+               return;
+
+       if (power_offset)
+               cl_temperature_set_power_offset(cl_hw, power_offset);
+}
+
+void cl_temperature_init(struct cl_chip *chip)
+{
+       struct cl_temperature *temperature = &chip->temperature;
+       struct cl_temp_protect_db *temp_protect_db = &temperature->protect_db;
+       unsigned long curr_time_ms = jiffies_to_msecs(jiffies);
+
+       temperature->kthread = kthread_run(cl_temperature_kthread,
+                                          chip,
+                                          "cl_temperature_kthread_%u",
+                                          chip->idx);
+       if (IS_ERR(temperature->kthread)) {
+               cl_dbg_chip_err(chip, "Failed to create temperature kthread\n");
+               temperature->kthread = NULL;
+       }
+
+       init_waitqueue_head(&temperature->wait_q);
+
+       mutex_init(&temperature->mutex);
+       temperature->internal_last = UNCALIBRATED_TEMPERATURE;
+       temperature->internal_read_timestamp = curr_time_ms;
+       temperature->external_last = UNCALIBRATED_TEMPERATURE;
+       temperature->external_read_timestamp = curr_time_ms;
+
+       /* Temp_protect_db init */
+       temp_protect_db->duty_cycle = DUTY_CYCLE_MAX;
+       temp_protect_db->test_mode_duty_cycle = DUTY_CYCLE_MAX;
+       temp_protect_db->last_timestamp = curr_time_ms;
+}
+
+void cl_temperature_close(struct cl_chip *chip)
+{
+       struct cl_temperature *temperature = &chip->temperature;
+
+       if (temperature->kthread) {
+               cl_dbg_chip_trace(chip, "stopping temperature kthread\n");
+               if (kthread_stop(temperature->kthread) != -EINTR)
+                       wake_up(&temperature->wait_q);
+
+               temperature->kthread = NULL;
+       }
+}
+
+s16 cl_temperature_get_internal(struct cl_hw *cl_hw)
+{
+       return cl_hw->chip->temperature.internal_last;
+}
+
+s8 cl_temperature_read(struct cl_hw *cl_hw, enum cl_temp_mode mode)
+{
+       u16 raw_bits = 0;
+       s16 temp_val = 0;
+       unsigned long curr_time = jiffies_to_msecs(jiffies);
+       unsigned long diff_time = 0;
+       struct cl_chip *chip = cl_hw->chip;
+       struct cl_temperature *temperature = &chip->temperature;
+
+       mutex_lock(&temperature->mutex);
+
+       switch (mode) {
+       case TEMP_MODE_INTERNAL:
+               diff_time = CL_TIME_DIFF(curr_time, temperature->internal_read_timestamp);
+               if (diff_time <= CL_TEMPERATURE_UPDATE_INTERVAL_MS) {
+                       temp_val = temperature->internal_last;
+                       cl_dbg_chip_trace(chip, "Return last internal temperature %d\n", temp_val);
+                       goto read_out;
+               }
+               break;
+       case TEMP_MODE_EXTERNAL:
+               diff_time = CL_TIME_DIFF(curr_time, temperature->external_read_timestamp);
+               if (diff_time <= CL_TEMPERATURE_UPDATE_INTERVAL_MS) {
+                       temp_val = temperature->external_last;
+                       cl_dbg_chip_trace(chip, "Return last external temperature %d\n", temp_val);
+                       goto read_out;
+               }
+               break;
+       default:
+               cl_dbg_chip_err(chip, "Invalid temperature mode %d\n", mode);
+               goto read_err;
+       }
+
+       if (cl_temperature_read_fw(cl_hw, mode, &raw_bits)) {
+               cl_dbg_chip_err(chip, "Temperature read failed\n");
+               goto read_err;
+       }
+
+       temp_val = cl_raw_bits_to_temperature(raw_bits, mode);
+
+       if (temp_val > TEMPERATURE_MAX || temp_val < TEMPERATURE_MIN) {
+               cl_dbg_chip_err(chip, "Invalid temperature value %d\n", temp_val);
+               goto read_err;
+       }
+
+       /* Update temperature read db */
+       if (mode == TEMP_MODE_INTERNAL) {
+               temperature->internal_last = temp_val;
+               temperature->internal_read_timestamp = jiffies_to_msecs(jiffies);
+               cl_dbg_chip_trace(chip, "Read and save internal temperature %d\n", temp_val);
+       } else {
+               temperature->external_last = temp_val;
+               temperature->external_read_timestamp = jiffies_to_msecs(jiffies);
+               cl_dbg_chip_trace(chip, "Read and save external temperature %d\n", temp_val);
+       }
+
+read_out:
+       mutex_unlock(&temperature->mutex);
+       return temp_val;
+
+read_err:
+       /* If temperature read failed return the last valid value */
+       mutex_unlock(&temperature->mutex);
+
+       return (mode == TEMP_MODE_INTERNAL) ?
+               temperature->internal_last : temperature->external_last;
+}
+
+static int cl_temperature_comp_print_config(struct cl_hw *cl_hw)
+{
+       struct cl_temp_comp_db *temp_comp_db = &cl_hw->temp_comp_db;
+       s8 temp_comp_slope = cl_hw->conf->ce_temp_comp_slope;
+       char *buf = NULL;
+       ssize_t buf_size;
+       int err = 0;
+       int len = 0;
+
+       cl_snprintf(&buf, &len, &buf_size,
+                   "Internal temperature: %d\n",
+                   cl_hw->chip->temperature.internal_last);
+       cl_snprintf(&buf, &len, &buf_size,
+                   "Calib temperature:    %d\n",
+                   temp_comp_db->calib_temperature);
+       cl_snprintf(&buf, &len, &buf_size,
+                   "Delta temperature:    %d\n",
+                   temp_comp_db->avg_temp_delta);
+       cl_snprintf(&buf, &len, &buf_size,
+                   "Slope:                %d.%02d\n\n",
+                   temp_comp_slope / 100, temp_comp_slope % 100);
+       cl_snprintf(&buf, &len, &buf_size,
+                   "Power offset:         %d\n",
+                   temp_comp_db->power_offset);
+
+       err = cl_vendor_reply(cl_hw, buf, len);
+       kfree(buf);
+
+       return err;
+}
+
+static int cl_temperature_ret(struct cl_hw *cl_hw, u8 param)
+{
+       struct cl_chip *chip = cl_hw->chip;
+       s8 curr_temp = 0;
+       char reply_str[5] = {0};
+       u16 reply_strlen = 0;
+
+       switch (param) {
+       case 0: /* Internal temp only */
+               curr_temp = cl_temperature_read(cl_hw, TEMP_MODE_INTERNAL);
+               cl_dbg_chip_trace(chip, "%d\n", curr_temp);
+               break;
+       case 1: /* External temp only */
+               curr_temp = cl_temperature_read(cl_hw, TEMP_MODE_EXTERNAL);
+               cl_dbg_chip_trace(chip, "%d\n", curr_temp);
+               break;
+       case 2: /* Internal temp + delta */
+               curr_temp = cl_temperature_read(cl_hw, TEMP_MODE_INTERNAL) +
+                       chip->conf->ce_temp_protect_delta;
+               cl_dbg_chip_trace(chip, "Internal + Delta = %d\n", curr_temp);
+               break;
+       case 3: /* External temp + delta */
+               curr_temp = cl_temperature_read(cl_hw, TEMP_MODE_EXTERNAL) +
+                       chip->conf->ce_temp_protect_delta;
+               cl_dbg_chip_trace(chip, "External + Delta = %d\n", curr_temp);
+               break;
+       case 4: /* Internal temp - temp_diff + delta */
+               curr_temp = cl_temperature_read(cl_hw, TEMP_MODE_INTERNAL) -
+                       chip->temperature.diff_internal_external +
+                       chip->conf->ce_temp_protect_delta;
+               cl_dbg_chip_trace(chip, "Actual temperature: Internal - Diff + Delta = %d\n",
+                                 curr_temp);
+               break;
+       default:
+               cl_dbg_chip_err(chip, "Invalid argument! must be between 0 and 4.\n");
+               return 0;
+       }
+
+       reply_strlen = snprintf(&reply_str[0], sizeof(reply_str), "%d", curr_temp);
+       return cl_vendor_reply(cl_hw, reply_str, reply_strlen);
+}
+
+int cl_temperature_cli(struct cl_hw *cl_hw, struct cli_params *cli_params)
+{
+       s32 *params = cli_params->params;
+
+       switch (cli_params->option) {
+               /* Temperature compenation */
+       case 'a':
+               if (cli_params->num_params != 0)
+                       goto err_num_params;
+
+               return cl_temperature_comp_print_config(cl_hw);
+       case 'b':
+               if (cli_params->num_params != 1)
+                       goto err_num_params;
+
+               cl_temperature_comp_enable(cl_hw->chip, params[0]);
+               break;
+       case 'c':
+               if (cli_params->num_params != 1)
+                       goto err_num_params;
+
+               cl_temperature_comp_comp_slope_set(cl_hw, params[0]);
+               break;
+               /* Temperature protect */
+       case 'k':
+               return cl_temperature_protect_print_config(cl_hw);
+       case 'l':
+               return cl_temperature_protect_print_status(cl_hw);
+       case 'm':
+               if (cli_params->num_params != 1)
+                       goto err_num_params;
+
+               cl_temperature_protect_test_mode_set(cl_hw->chip, params[0]);
+               break;
+               /* Temperature general */
+       case 'u':
+               if (cl_temperature_diff_update(cl_hw))
+                       return -1;
+               break;
+       case 'v':
+               if (cli_params->num_params != 1)
+                       goto err_num_params;
+               cl_temperature_ret(cl_hw, params[0]);
+               break;
+               /* Help */
+       case '?':
+               return cl_temperature_cli_help(cl_hw);
+       default:
+               cl_dbg_err(cl_hw, "Illegal option (%c) - try '?' for help\n", cli_params->option);
+               break;
+       }
+
+       return 0;
+
+err_num_params:
+       cl_dbg_err(cl_hw, "Wrong number of arguments\n");
+       return 0;
+}
+
+void cl_temperature_recovery(struct cl_hw *cl_hw)
+{
+       cl_temperature_recovery_protect(cl_hw);
+       cl_temperature_recovery_comp(cl_hw);
+}
+
+bool cl_temperature_protect_did_reduce_duty_cycle(struct cl_hw *cl_hw)
+{
+       return cl_hw->chip->temperature.protect_db.duty_cycle < DUTY_CYCLE_MAX;
+}
+
+int cl_temperature_diff_e2p_read(struct cl_hw *cl_hw)
+{
+       struct cl_chip *chip = cl_hw->chip;
+       struct cl_temperature *temperature = &chip->temperature;
+
+       if (cl_e2p_read_temp_diff(chip, &temperature->diff_internal_external) ||
+           temperature->diff_internal_external == TEMP_DIFF_INVALID) {
+               if (cl_temperature_diff_update(cl_hw))
+                       return -1;
+
+               cl_dbg_chip_verbose(chip, "Temperature difference: Internal - External = %d\n",
+                                   temperature->diff_internal_external);
+       }
+
+       return 0;
+}
+
+s16 cl_temperature_calib_calc(struct cl_hw *cl_hw, u16 raw_bits)
+{
+       struct cl_chip *chip = cl_hw->chip;
+       s16 temperature = cl_raw_bits_to_temperature(raw_bits, TEMP_MODE_INTERNAL) +
+               chip->conf->ce_temp_protect_delta;
+
+       if (temperature >= TEMPERATURE_MIN && temperature <= TEMPERATURE_MAX)
+               return temperature;
+
+       cl_dbg_chip_err(chip, "Invalid temperature = %d\n", temperature);
+
+       return (chip->temperature.internal_last + chip->conf->ce_temp_protect_delta);
+}
+
+void cl_temperature_comp_update_calib(struct cl_hw *cl_hw)
+{
+       u8 chan_idx = cl_channel_to_index(cl_hw, cl_hw->channel);
+       u8 ant;
+       s16 total_temp = 0;
+       struct cl_tx_power_info *info = NULL;
+
+       if (unlikely(chan_idx == INVALID_CHAN_IDX)) {
+               cl_dbg_err(cl_hw, "Unsupported frequency %u\n", cl_hw->center_freq);
+               return;
+       }
+
+       info = &cl_hw->tx_pow_info[chan_idx][0];
+
+       /* Sum up the temperature of all phys */
+       for (ant = 0; ant < cl_hw->num_antennas; ant++)
+               total_temp += info[ant].temperature;
+
+       /* Average the total temperature and update chan_params */
+       cl_hw->temp_comp_db.calib_temperature = DIV_ROUND_CLOSEST(total_temp, cl_hw->num_antennas);
+}
--
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.
________________________________


^ permalink raw reply related	[flat|nested] 262+ messages in thread

* [RFC v1 189/256] cl8k: add temperature.h
  2021-06-17 15:58 [RFC v1 000/256] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (187 preceding siblings ...)
  2021-06-17 16:01 ` [RFC v1 188/256] cl8k: add temperature.c viktor.barna
@ 2021-06-17 16:01 ` viktor.barna
  2021-06-17 16:01 ` [RFC v1 190/256] cl8k: add trace.c viktor.barna
                   ` (68 subsequent siblings)
  257 siblings, 0 replies; 262+ messages in thread
From: viktor.barna @ 2021-06-17 16:01 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Oleksandr Savchenko, Shay Bar, Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

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

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 .../net/wireless/celeno/cl8k/temperature.h    | 74 +++++++++++++++++++
 1 file changed, 74 insertions(+)
 create mode 100644 drivers/net/wireless/celeno/cl8k/temperature.h

diff --git a/drivers/net/wireless/celeno/cl8k/temperature.h b/drivers/net/wireless/celeno/cl8k/temperature.h
new file mode 100644
index 000000000000..9f34d06b64eb
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/temperature.h
@@ -0,0 +1,74 @@
+/* SPDX-License-Identifier: MIT */
+/* Copyright(c) 2019-2021, Celeno Communications Ltd. */
+
+#ifndef CL_TEMPERATURE_H
+#define CL_TEMPERATURE_H
+
+#include <net/mac80211.h>
+#include "vendor_cmd.h"
+
+#define CL_TEMP_PROTECT_INTERVAL_MS       40000
+#define CL_TEMP_PROTECT_NUM_SAMPLES       4
+#define CL_TEMP_PROTECT_RADIO_OFF_HYST    10
+
+#define CL_TEMP_COMP_ITERATIONS           4
+
+#define CL_TEMPERATURE_TIMER_INTERVAL_MS  4000
+#define CL_TEMPERATURE_UPDATE_INTERVAL_MS (CL_TEMPERATURE_TIMER_INTERVAL_MS - 100)
+
+enum cl_temp_state {
+       TEMP_PROTECT_OFF,
+       TEMP_PROTECT_INTERNAL,
+       TEMP_PROTECT_EXTERNAL,
+       TEMP_PROTECT_DIFF
+};
+
+enum cl_temp_mode {
+       TEMP_MODE_INTERNAL,
+       TEMP_MODE_EXTERNAL
+};
+
+struct cl_temp_comp_db {
+       s8 calib_temperature;
+       s8 power_offset;
+       s32 acc_temp_delta;
+       s32 avg_temp_delta;
+};
+
+struct cl_temp_protect_db {
+       bool force_radio_off;
+       u8 duty_cycle;
+       u8 test_mode_duty_cycle;
+       u8 curr_idx;
+       s16 last_samples[CL_TEMP_PROTECT_NUM_SAMPLES];
+       unsigned long last_timestamp;
+};
+
+struct cl_temperature {
+       s8 diff_internal_external;
+       u8 comp_iterations;
+       struct cl_temp_protect_db protect_db;
+       struct task_struct *kthread;
+       wait_queue_head_t wait_q;
+       s16 internal_last;
+       s16 external_last;
+       unsigned long internal_read_timestamp;
+       unsigned long external_read_timestamp;
+       struct mutex mutex;
+};
+
+struct cl_chip;
+struct cl_hw;
+
+void cl_temperature_init(struct cl_chip *chip);
+void cl_temperature_close(struct cl_chip *chip);
+s16 cl_temperature_get_internal(struct cl_hw *cl_hw);
+s8 cl_temperature_read(struct cl_hw *cl_hw, enum cl_temp_mode mode);
+int cl_temperature_cli(struct cl_hw *cl_hw, struct cli_params *cli_params);
+void cl_temperature_recovery(struct cl_hw *cl_hw);
+bool cl_temperature_protect_did_reduce_duty_cycle(struct cl_hw *cl_hw);
+int cl_temperature_diff_e2p_read(struct cl_hw *cl_hw);
+s16 cl_temperature_calib_calc(struct cl_hw *cl_hw, u16 raw_bits);
+void cl_temperature_comp_update_calib(struct cl_hw *cl_hw);
+
+#endif /* CL_TEMPERATURE_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.
________________________________


^ permalink raw reply related	[flat|nested] 262+ messages in thread

* [RFC v1 190/256] cl8k: add trace.c
  2021-06-17 15:58 [RFC v1 000/256] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (188 preceding siblings ...)
  2021-06-17 16:01 ` [RFC v1 189/256] cl8k: add temperature.h viktor.barna
@ 2021-06-17 16:01 ` viktor.barna
  2021-06-17 16:01 ` [RFC v1 191/256] cl8k: add trace.h viktor.barna
                   ` (67 subsequent siblings)
  257 siblings, 0 replies; 262+ messages in thread
From: viktor.barna @ 2021-06-17 16:01 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Oleksandr Savchenko, Shay Bar, Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

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

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 drivers/net/wireless/celeno/cl8k/trace.c | 9 +++++++++
 1 file changed, 9 insertions(+)
 create mode 100644 drivers/net/wireless/celeno/cl8k/trace.c

diff --git a/drivers/net/wireless/celeno/cl8k/trace.c b/drivers/net/wireless/celeno/cl8k/trace.c
new file mode 100644
index 000000000000..4644f4132bdd
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/trace.c
@@ -0,0 +1,9 @@
+// SPDX-License-Identifier: MIT
+/* Copyright(c) 2019-2021, Celeno Communications Ltd. */
+
+/*
+ * The definition below generates all the relevant code for the tracepoints.
+ * It should appear in only one translation unit.
+ */
+#define CREATE_TRACE_POINTS
+#include "trace.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.
________________________________


^ permalink raw reply related	[flat|nested] 262+ messages in thread

* [RFC v1 191/256] cl8k: add trace.h
  2021-06-17 15:58 [RFC v1 000/256] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (189 preceding siblings ...)
  2021-06-17 16:01 ` [RFC v1 190/256] cl8k: add trace.c viktor.barna
@ 2021-06-17 16:01 ` viktor.barna
  2021-06-17 16:01 ` [RFC v1 192/256] cl8k: add traffic.c viktor.barna
                   ` (66 subsequent siblings)
  257 siblings, 0 replies; 262+ messages in thread
From: viktor.barna @ 2021-06-17 16:01 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Oleksandr Savchenko, Shay Bar, Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

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

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 drivers/net/wireless/celeno/cl8k/trace.h | 203 +++++++++++++++++++++++
 1 file changed, 203 insertions(+)
 create mode 100644 drivers/net/wireless/celeno/cl8k/trace.h

diff --git a/drivers/net/wireless/celeno/cl8k/trace.h b/drivers/net/wireless/celeno/cl8k/trace.h
new file mode 100644
index 000000000000..21b9927c0f99
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/trace.h
@@ -0,0 +1,203 @@
+/* SPDX-License-Identifier: MIT */
+/* Copyright(c) 2019-2021, Celeno Communications Ltd. */
+
+#undef TRACE_SYSTEM
+#define TRACE_SYSTEM cl_trace
+
+#if !defined(_TRACE_H) || defined(TRACE_HEADER_MULTI_READ)
+#define _TRACE_H
+
+#include <linux/tracepoint.h>
+
+/* Here, we need to include headers for definitions used in TP_PROTO */
+#include <net/mac80211.h>
+#include <linux/skbuff.h>
+#include <linux/ieee80211.h>
+#include "rx/rx.h"
+
+/* Add your tracepoint definitions here. */
+TRACE_EVENT(cl_trace_tx_start,
+       TP_PROTO(unsigned char cl_hw_idx,
+                struct sk_buff *skb,
+                int buffer_cnt),
+       TP_ARGS(cl_hw_idx, skb, buffer_cnt),
+       TP_STRUCT__entry(),
+       TP_fast_assign(),
+       TP_printk("%d", 0)
+);
+
+TRACE_EVENT(cl_trace_tx_push,
+       TP_PROTO(unsigned char cl_hw_idx,
+                struct sk_buff *skb,
+                unsigned char packet_cnt,
+                unsigned short seq_ctrl,
+                unsigned char tid),
+       TP_ARGS(cl_hw_idx, skb, packet_cnt, seq_ctrl, tid),
+       TP_STRUCT__entry(),
+       TP_fast_assign(),
+       TP_printk("%d", 0)
+);
+
+TRACE_EVENT(cl_trace_tx_pci_single_cfm_tasklet_start,
+       TP_PROTO(unsigned char cl_hw_idx,
+                unsigned int cfm_used_idx),
+       TP_ARGS(cl_hw_idx, cfm_used_idx),
+       TP_STRUCT__entry(),
+       TP_fast_assign(),
+       TP_printk("%d", 0)
+);
+
+TRACE_EVENT(cl_trace_tx_pci_single_cfm_tasklet_end,
+       TP_PROTO(unsigned char cl_hw_idx,
+                unsigned int cfm_used_idx),
+       TP_ARGS(cl_hw_idx, cfm_used_idx),
+       TP_STRUCT__entry(),
+       TP_fast_assign(),
+       TP_printk("%d", 0)
+);
+
+TRACE_EVENT(cl_trace_msg_rx_handler_start,
+       TP_PROTO(unsigned char cl_hw_idx,
+                unsigned short msg_id,
+                unsigned long msg_pattern,
+                unsigned long *cfm_flags),
+       TP_ARGS(cl_hw_idx, msg_id, msg_pattern, cfm_flags),
+       TP_STRUCT__entry(),
+       TP_fast_assign(),
+       TP_printk("%d", 0)
+)
+
+TRACE_EVENT(cl_trace_msg_rx_handler_end,
+       TP_PROTO(unsigned char cl_hw_idx,
+                unsigned long *cfm_flags),
+       TP_ARGS(cl_hw_idx, cfm_flags),
+       TP_STRUCT__entry(),
+       TP_fast_assign(),
+       TP_printk("%d", 0)
+);
+
+TRACE_EVENT(cl_trace_msg_rx_tasklet_start,
+       TP_PROTO(unsigned char cl_hw_idx),
+       TP_ARGS(cl_hw_idx),
+       TP_STRUCT__entry(),
+       TP_fast_assign(),
+       TP_printk("%d", 0)
+);
+
+TRACE_EVENT(cl_trace_msg_rx_tasklet_end,
+       TP_PROTO(unsigned char cl_hw_idx,
+                int msg_handled),
+       TP_ARGS(cl_hw_idx, msg_handled),
+       TP_STRUCT__entry(),
+       TP_fast_assign(),
+       TP_printk("%d", 0)
+);
+
+TRACE_EVENT(cl_trace_dbgfile_tasklet_start,
+       TP_PROTO(unsigned char cl_hw_idx),
+       TP_ARGS(cl_hw_idx),
+       TP_STRUCT__entry(),
+       TP_fast_assign(),
+       TP_printk("%d", 0)
+);
+
+TRACE_EVENT(cl_trace_dbgfile_tasklet_end,
+       TP_PROTO(unsigned char cl_hw_idx,
+                int dbg_handled),
+       TP_ARGS(cl_hw_idx, dbg_handled),
+       TP_STRUCT__entry(),
+       TP_fast_assign(),
+       TP_printk("%d", 0)
+);
+
+TRACE_EVENT(cl_trace_tx_agg_cfm_tasklet_start,
+       TP_PROTO(unsigned char cl_hw_idx),
+       TP_ARGS(cl_hw_idx),
+       TP_STRUCT__entry(),
+       TP_fast_assign(),
+       TP_printk("%d", 0)
+);
+
+TRACE_EVENT(cl_trace_tx_agg_cfm_tasklet_end,
+       TP_PROTO(unsigned char cl_hw_idx,
+                int cfm_handled),
+       TP_ARGS(cl_hw_idx, cfm_handled),
+       TP_STRUCT__entry(),
+       TP_fast_assign(),
+       TP_printk("%d", 0)
+);
+
+TRACE_EVENT(cl_trace_rx_desc_tasklet_start,
+       TP_PROTO(unsigned char cl_hw_idx,
+                unsigned int write_idx_rxm,
+                unsigned int write_idx_fw),
+       TP_ARGS(cl_hw_idx, write_idx_rxm, write_idx_fw),
+       TP_STRUCT__entry(),
+       TP_fast_assign(),
+       TP_printk("%d", 0)
+);
+
+TRACE_EVENT(cl_trace_rx_desc_tasklet_end,
+       TP_PROTO(unsigned char cl_hw_idx,
+                unsigned int write_idx_rxm,
+                unsigned int write_idx_fw),
+       TP_ARGS(cl_hw_idx, write_idx_rxm, write_idx_fw),
+       TP_STRUCT__entry(),
+       TP_fast_assign(),
+       TP_printk("%d", 0)
+);
+
+TRACE_EVENT(cl_trace_rx_tasklet_start,
+       TP_PROTO(unsigned char cl_hw_idx),
+       TP_ARGS(cl_hw_idx),
+       TP_STRUCT__entry(),
+       TP_fast_assign(),
+       TP_printk("%d", 0)
+);
+
+TRACE_EVENT(cl_trace_rx_tasklet_end,
+       TP_PROTO(unsigned char cl_hw_idx,
+                int handled),
+       TP_ARGS(cl_hw_idx, handled),
+       TP_STRUCT__entry(),
+       TP_fast_assign(),
+       TP_printk("%d", 0)
+);
+
+TRACE_EVENT(cl_trace_netif_rx_start,
+       TP_PROTO(unsigned char cl_hw_idx),
+       TP_ARGS(cl_hw_idx),
+       TP_STRUCT__entry(),
+       TP_fast_assign(),
+       TP_printk("%d", 0)
+);
+
+TRACE_EVENT(cl_trace_netif_rx_end,
+       TP_PROTO(unsigned char cl_hw_idx),
+       TP_ARGS(cl_hw_idx),
+       TP_STRUCT__entry(),
+       TP_fast_assign(),
+       TP_printk("%d", 0)
+);
+
+TRACE_EVENT(cl_trace_cl_msg_fw_send,
+       TP_PROTO(unsigned char cl_hw_idx,
+                int msg_id),
+       TP_ARGS(cl_hw_idx, msg_id),
+       TP_STRUCT__entry(),
+       TP_fast_assign(),
+       TP_printk("%d", 0)
+);
+
+#endif /* !defined(_TRACE_H) || defined(TRACE_HEADER_MULTI_READ) */
+
+/*
+ * Without these two lines, the tracepoint will be searched
+ * for in include/trace/events, which is not what we desire.
+ */
+#undef TRACE_INCLUDE_PATH
+#define TRACE_INCLUDE_PATH .
+#undef TRACE_INCLUDE_FILE
+#define TRACE_INCLUDE_FILE cl_trace
+
+#include <trace/define_trace.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.
________________________________


^ permalink raw reply related	[flat|nested] 262+ messages in thread

* [RFC v1 192/256] cl8k: add traffic.c
  2021-06-17 15:58 [RFC v1 000/256] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (190 preceding siblings ...)
  2021-06-17 16:01 ` [RFC v1 191/256] cl8k: add trace.h viktor.barna
@ 2021-06-17 16:01 ` viktor.barna
  2021-06-17 16:01 ` [RFC v1 193/256] cl8k: add traffic.h viktor.barna
                   ` (65 subsequent siblings)
  257 siblings, 0 replies; 262+ messages in thread
From: viktor.barna @ 2021-06-17 16:01 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Oleksandr Savchenko, Shay Bar, Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

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

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 drivers/net/wireless/celeno/cl8k/traffic.c | 315 +++++++++++++++++++++
 1 file changed, 315 insertions(+)
 create mode 100644 drivers/net/wireless/celeno/cl8k/traffic.c

diff --git a/drivers/net/wireless/celeno/cl8k/traffic.c b/drivers/net/wireless/celeno/cl8k/traffic.c
new file mode 100644
index 000000000000..19d91eb3e999
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/traffic.c
@@ -0,0 +1,315 @@
+// SPDX-License-Identifier: MIT
+/* Copyright(c) 2019-2021, Celeno Communications Ltd. */
+
+#include "traffic.h"
+#include "env_det.h"
+#include "edca.h"
+#include "bf.h"
+#include "prot_mode.h"
+#include "band.h"
+#include "utils/utils.h"
+#include "rsrc_mgmt.h"
+
+#define TRAFFIC_CNTR_ACTIVE_THR     3       /* 3 * 100ms = 300ms */
+#define TRAFFIC_CNTR_IDLE_THR       20      /* 20 * 100ms = 2sec */
+
+/* Threshold in bytes */
+#define TRAFFIC_ACTIVE_THR_DRV      1920    /* = 150Kbit/sec (150 * 1024 / 8 / 10) */
+#define TRAFFIC_ACTIVE_THR_BF       26214   /* = 2mbit/sec (2 * 1024 * 1024 / 8 / 10) */
+#define TRAFFIC_ACTIVE_THR_EDCA_6G  2621440 /* = 200mbit/sec (200 * 1024 * 1024 / 8 / 10) */
+#define TRAFFIC_ACTIVE_THR_EDCA_5G  2621440 /* = 200mbit/sec (200 * 1024 * 1024 / 8 / 10) */
+#define TRAFFIC_ACTIVE_THR_EDCA_24G 655360  /* = 50mbit/sec (50 * 1024 * 1024 / 8 / 10) */
+#define TRAFFIC_ACTIVE_THR_DFS      13107   /* = 1mbit/sec (1 * 1024 * 1024 / 8 / 10) */
+
+static const char *level_str[TRAFFIC_LEVEL_MAX] = {
+       [TRAFFIC_LEVEL_DRV]  = "DRV",
+       [TRAFFIC_LEVEL_BF]   = "BF",
+       [TRAFFIC_LEVEL_EDCA] = "EDCA",
+       [TRAFFIC_LEVEL_DFS]  = "DFS"
+};
+
+static void cl_traffic_sta_start(struct cl_hw *cl_hw, struct cl_sta *cl_sta,
+                                enum cl_traffic_level level, enum cl_traffic_direction direction)
+{
+       cl_hw->traffic_db.num_active_sta_dir[direction][level]++;
+
+       /* If other direction is not active increase num_active_sta */
+       if (!cl_sta->traffic_db[1 - direction].activity_db[level].is_active)
+               cl_hw->traffic_db.num_active_sta[level]++;
+
+       if (level == TRAFFIC_LEVEL_DRV) {
+               /*
+                * Dynamic CTS:
+                * If protection mode is disabled, environment is clean
+                * and station threshold was reached switch to CTS.
+                */
+               if (cl_hw->traffic_db.num_active_sta[TRAFFIC_LEVEL_DRV] ==
+                    cl_hw->conf->ci_dyn_cts_sta_thr)
+                       if (cl_env_det_is_clean(cl_hw) &&
+                           (cl_prot_mode_get(cl_hw) == TXL_NO_PROT)) {
+                               cl_hw->traffic_db.dynamic_cts = true;
+                               cl_prot_mode_set(cl_hw, TXL_PROT_CTS);
+                       }
+       } else if (level == TRAFFIC_LEVEL_BF) {
+               if (direction == TRAFFIC_DIRECTION_TX)
+                       cl_bf_sta_active(cl_hw, cl_sta, true);
+       } else if (level == TRAFFIC_LEVEL_EDCA) {
+               /* No action */
+       }
+
+       cl_rsrc_mgmt_traffic_start(cl_hw, level, direction);
+}
+
+static void cl_traffic_sta_stop(struct cl_hw *cl_hw, struct cl_sta *cl_sta,
+                               enum cl_traffic_level level, enum cl_traffic_direction direction)
+{
+       cl_hw->traffic_db.num_active_sta_dir[direction][level]--;
+
+       /* If other direction is not active decrease num_active_sta */
+       if (!cl_sta->traffic_db[1 - direction].activity_db[level].is_active)
+               cl_hw->traffic_db.num_active_sta[level]--;
+
+       if (level == TRAFFIC_LEVEL_DRV) {
+               /*
+                * Dynamic CTS:
+                * If it was turned on and active station count became lower than
+                * threshold --> return to no protection
+                */
+               if (cl_hw->traffic_db.dynamic_cts) {
+                       if (cl_hw->traffic_db.num_active_sta[TRAFFIC_LEVEL_DRV] ==
+                           (cl_hw->conf->ci_dyn_cts_sta_thr - 1)) {
+                               cl_hw->traffic_db.dynamic_cts = false;
+                               cl_prot_mode_set(cl_hw, TXL_NO_PROT);
+                       }
+               }
+       } else if (level == TRAFFIC_LEVEL_BF) {
+               if (direction == TRAFFIC_DIRECTION_TX)
+                       cl_bf_sta_active(cl_hw, cl_sta, false);
+       } else if (level == TRAFFIC_LEVEL_EDCA) {
+               /* No action */
+       }
+
+       cl_rsrc_mgmt_traffic_stop(cl_hw, level, direction);
+}
+
+static void cl_traffic_check_activity(struct cl_hw *cl_hw, struct cl_sta *cl_sta,
+                                     enum cl_traffic_level level,
+                                     enum cl_traffic_direction direction)
+{
+       struct cl_traffic_activity *activity_db =
+               &cl_sta->traffic_db[direction].activity_db[level];
+       u32 num_bytes = cl_sta->traffic_db[direction].num_bytes;
+
+       if (num_bytes > cl_hw->traffic_db.active_bytes_thr[level]) {
+               activity_db->cntr_active++;
+               activity_db->cntr_idle = 0;
+
+               /* If traffic is above threshold for X consecutive times change state to active */
+               if (!activity_db->is_active &&
+                   activity_db->cntr_active >= TRAFFIC_CNTR_ACTIVE_THR) {
+                       activity_db->is_active = true;
+                       cl_traffic_sta_start(cl_hw, cl_sta, level, direction);
+               }
+       } else {
+               activity_db->cntr_active = 0;
+               activity_db->cntr_idle++;
+
+               /* If traffic is below threshold for Y consecutive times change state to idle */
+               if (activity_db->is_active && activity_db->cntr_idle >= TRAFFIC_CNTR_IDLE_THR) {
+                       activity_db->is_active = false;
+                       cl_traffic_sta_stop(cl_hw, cl_sta, level, direction);
+               }
+       }
+}
+
+static void cl_traffic_maintenance_sta(struct cl_hw *cl_hw, struct cl_sta *cl_sta)
+{
+       enum cl_traffic_level level = 0;
+
+       /* Check Tx & Rx activity in all levels */
+       for (level = 0; level < TRAFFIC_LEVEL_MAX; level++) {
+               cl_traffic_check_activity(cl_hw, cl_sta, level, TRAFFIC_DIRECTION_TX);
+               cl_traffic_check_activity(cl_hw, cl_sta, level, TRAFFIC_DIRECTION_RX);
+       }
+
+       /* Reset num_bytes */
+       cl_sta->traffic_db[TRAFFIC_DIRECTION_TX].num_bytes = 0;
+       cl_sta->traffic_db[TRAFFIC_DIRECTION_RX].num_bytes = 0;
+}
+
+static int cl_traffic_print_state(struct cl_hw *cl_hw,
+                                 enum cl_traffic_level level)
+{
+       struct cl_sta *cl_sta = NULL;
+       char *buf = NULL;
+       ssize_t buf_size;
+       int err = 0;
+       int len = 0;
+       struct cl_traffic_main *db = &cl_hw->traffic_db;
+
+       if (level >= TRAFFIC_LEVEL_MAX) {
+               cl_snprintf(&buf, &len, &buf_size,
+                           "invalid level %d\n", level);
+               goto out;
+       }
+
+       cl_snprintf(&buf, &len, &buf_size,
+                   "Level %s (%d)\n", level_str[level], level);
+       cl_snprintf(&buf, &len, &buf_size,
+                   "Active stations    - %u\n",
+                   db->num_active_sta[level]);
+       cl_snprintf(&buf, &len, &buf_size,
+                   "Active stations TX - %u\n",
+                   db->num_active_sta_dir[TRAFFIC_DIRECTION_TX][level]);
+       cl_snprintf(&buf, &len, &buf_size,
+                   "Active stations RX - %u\n",
+                   db->num_active_sta_dir[TRAFFIC_DIRECTION_RX][level]);
+
+       if (db->num_active_sta[level] == 0)
+               goto out;
+
+       cl_snprintf(&buf, &len, &buf_size,
+                   "|---------------------|\n"
+                   "|Sta|ActiveTx|ActiveRx|\n"
+                   "|---------------------|\n");
+
+       /* Go over all stations */
+       cl_sta_lock_bh(cl_hw);
+
+       list_for_each_entry(cl_sta, &cl_hw->cl_sta_db.head, list)
+               cl_snprintf(&buf, &len, &buf_size,
+                           "|%3u|%-8s|%-8s|\n",
+                           cl_sta->sta_idx,
+                           cl_sta->traffic_db[TRAFFIC_DIRECTION_TX].activity_db[level].is_active ?
+                           "True" : "False",
+                           cl_sta->traffic_db[TRAFFIC_DIRECTION_RX].activity_db[level].is_active ?
+                           "True" : "False");
+
+       cl_sta_unlock_bh(cl_hw);
+
+       cl_snprintf(&buf, &len, &buf_size,
+                   "|---------------------|\n");
+out:
+       err = cl_vendor_reply(cl_hw, buf, strlen(buf));
+       kfree(buf);
+
+       return err;
+}
+
+static int cl_traffic_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,
+                "traffic usage:\n"
+                "-s : Print traffic state [0-drv/1-bf/2-edca/3-dfs]\n");
+
+       err = cl_vendor_reply(cl_hw, buf, strlen(buf));
+       kfree(buf);
+
+       return err;
+}
+
+void cl_traffic_init(struct cl_hw *cl_hw)
+{
+       struct cl_traffic_main *traffic_db = &cl_hw->traffic_db;
+
+       traffic_db->active_bytes_thr[TRAFFIC_LEVEL_DRV] = TRAFFIC_ACTIVE_THR_DRV;
+       traffic_db->active_bytes_thr[TRAFFIC_LEVEL_BF] = TRAFFIC_ACTIVE_THR_BF;
+
+       if (cl_band_is_6g(cl_hw))
+               traffic_db->active_bytes_thr[TRAFFIC_LEVEL_EDCA] = TRAFFIC_ACTIVE_THR_EDCA_6G;
+       else if (cl_band_is_5g(cl_hw))
+               traffic_db->active_bytes_thr[TRAFFIC_LEVEL_EDCA] = TRAFFIC_ACTIVE_THR_EDCA_5G;
+       else
+               traffic_db->active_bytes_thr[TRAFFIC_LEVEL_EDCA] = TRAFFIC_ACTIVE_THR_EDCA_24G;
+
+       traffic_db->active_bytes_thr[TRAFFIC_LEVEL_DFS] = TRAFFIC_ACTIVE_THR_DFS;
+}
+
+void cl_traffic_tx_handler(struct cl_hw *cl_hw, struct cl_sta *cl_sta, u32 num_bytes)
+{
+       cl_sta->traffic_db[TRAFFIC_DIRECTION_TX].num_bytes += num_bytes;
+}
+
+void cl_traffic_rx_handler(struct cl_hw *cl_hw, struct cl_sta *cl_sta, u32 num_bytes)
+{
+       cl_sta->traffic_db[TRAFFIC_DIRECTION_RX].num_bytes += num_bytes;
+}
+
+void cl_traffic_maintenance(struct cl_hw *cl_hw)
+{
+       cl_sta_loop(cl_hw, cl_traffic_maintenance_sta);
+}
+
+void cl_traffic_sta_remove(struct cl_hw *cl_hw, struct cl_sta *cl_sta)
+{
+       /* Check if station disconnected during traffic */
+       enum cl_traffic_level level = 0;
+       enum cl_traffic_direction direction = 0;
+
+       for (direction = 0; direction < TRAFFIC_DIRECTION_MAX; direction++) {
+               for (level = 0; level < TRAFFIC_LEVEL_MAX; level++) {
+                       if (cl_sta->traffic_db[direction].activity_db[level].is_active)
+                               cl_traffic_sta_stop(cl_hw, cl_sta, level, direction);
+               }
+
+               memset(&cl_sta->traffic_db, 0, sizeof(cl_sta->traffic_db));
+       }
+}
+
+bool cl_traffic_is_sta_active(struct cl_hw *cl_hw, struct cl_sta *cl_sta)
+{
+       return (cl_sta->traffic_db[TRAFFIC_DIRECTION_TX].activity_db[TRAFFIC_LEVEL_DRV].is_active ||
+               cl_sta->traffic_db[TRAFFIC_DIRECTION_RX].activity_db[TRAFFIC_LEVEL_DRV].is_active);
+}
+
+bool cl_traffic_is_sta_active_tx(struct cl_hw *cl_hw, struct cl_sta *cl_sta)
+{
+       return cl_sta->traffic_db[TRAFFIC_DIRECTION_TX].activity_db[TRAFFIC_LEVEL_DRV].is_active;
+}
+
+u32 cl_traffic_num_active_sta(struct cl_hw *cl_hw)
+{
+       return cl_hw->traffic_db.num_active_sta[TRAFFIC_LEVEL_DRV];
+}
+
+u32 cl_traffic_num_active_dfs(struct cl_hw *cl_hw)
+{
+       return cl_hw->traffic_db.num_active_sta[TRAFFIC_LEVEL_DFS];
+}
+
+int cl_traffic_cli(struct cl_hw *cl_hw, struct cli_params *cli_params)
+{
+       bool print_state = false;
+       int expected_params = -1;
+
+       switch (cli_params->option) {
+       case 's':
+               print_state = true;
+               expected_params = 1;
+               break;
+       case '?':
+               return cl_traffic_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_state)
+               return cl_traffic_print_state(cl_hw,
+                                             (u8)(cli_params->params[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.
________________________________


^ permalink raw reply related	[flat|nested] 262+ messages in thread

* [RFC v1 193/256] cl8k: add traffic.h
  2021-06-17 15:58 [RFC v1 000/256] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (191 preceding siblings ...)
  2021-06-17 16:01 ` [RFC v1 192/256] cl8k: add traffic.c viktor.barna
@ 2021-06-17 16:01 ` viktor.barna
  2021-06-17 16:01 ` [RFC v1 194/256] cl8k: add twt.c viktor.barna
                   ` (64 subsequent siblings)
  257 siblings, 0 replies; 262+ messages in thread
From: viktor.barna @ 2021-06-17 16:01 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Oleksandr Savchenko, Shay Bar, Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

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

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 drivers/net/wireless/celeno/cl8k/traffic.h | 57 ++++++++++++++++++++++
 1 file changed, 57 insertions(+)
 create mode 100644 drivers/net/wireless/celeno/cl8k/traffic.h

diff --git a/drivers/net/wireless/celeno/cl8k/traffic.h b/drivers/net/wireless/celeno/cl8k/traffic.h
new file mode 100644
index 000000000000..810bec60647d
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/traffic.h
@@ -0,0 +1,57 @@
+/* SPDX-License-Identifier: MIT */
+/* Copyright(c) 2019-2021, Celeno Communications Ltd. */
+
+#ifndef CL_TRAFFIC_H
+#define CL_TRAFFIC_H
+
+#include "vendor_cmd.h"
+
+enum cl_traffic_direction {
+       TRAFFIC_DIRECTION_TX,
+       TRAFFIC_DIRECTION_RX,
+
+       TRAFFIC_DIRECTION_MAX
+};
+
+enum cl_traffic_level {
+       TRAFFIC_LEVEL_DRV,
+       TRAFFIC_LEVEL_BF,
+       TRAFFIC_LEVEL_EDCA,
+       TRAFFIC_LEVEL_DFS,
+
+       TRAFFIC_LEVEL_MAX
+};
+
+struct cl_traffic_activity {
+       u8 cntr_active;
+       u8 cntr_idle;
+       bool is_active;
+};
+
+struct cl_traffic_sta {
+       struct cl_traffic_activity activity_db[TRAFFIC_LEVEL_MAX];
+       u32 num_bytes;
+};
+
+struct cl_traffic_main {
+       u32 num_active_sta[TRAFFIC_LEVEL_MAX];
+       u32 num_active_sta_dir[TRAFFIC_DIRECTION_MAX][TRAFFIC_LEVEL_MAX];
+       u32 active_bytes_thr[TRAFFIC_LEVEL_MAX];
+       bool dynamic_cts;
+};
+
+struct cl_hw;
+struct cl_sta;
+
+void cl_traffic_init(struct cl_hw *cl_hw);
+void cl_traffic_tx_handler(struct cl_hw *cl_hw, struct cl_sta *cl_sta, u32 num_bytes);
+void cl_traffic_rx_handler(struct cl_hw *cl_hw, struct cl_sta *cl_sta, u32 num_bytes);
+void cl_traffic_maintenance(struct cl_hw *cl_hw);
+void cl_traffic_sta_remove(struct cl_hw *cl_hw, struct cl_sta *cl_sta);
+bool cl_traffic_is_sta_active(struct cl_hw *cl_hw, struct cl_sta *cl_sta);
+bool cl_traffic_is_sta_active_tx(struct cl_hw *cl_hw, struct cl_sta *cl_sta);
+u32 cl_traffic_num_active_sta(struct cl_hw *cl_hw);
+u32 cl_traffic_num_active_dfs(struct cl_hw *cl_hw);
+int cl_traffic_cli(struct cl_hw *cl_hw, struct cli_params *cli_params);
+
+#endif /* CL_TRAFFIC_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.
________________________________


^ permalink raw reply related	[flat|nested] 262+ messages in thread

* [RFC v1 194/256] cl8k: add twt.c
  2021-06-17 15:58 [RFC v1 000/256] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (192 preceding siblings ...)
  2021-06-17 16:01 ` [RFC v1 193/256] cl8k: add traffic.h viktor.barna
@ 2021-06-17 16:01 ` viktor.barna
  2021-06-17 16:01 ` [RFC v1 195/256] cl8k: add twt.h viktor.barna
                   ` (63 subsequent siblings)
  257 siblings, 0 replies; 262+ messages in thread
From: viktor.barna @ 2021-06-17 16:01 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Oleksandr Savchenko, Shay Bar, Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

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

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 drivers/net/wireless/celeno/cl8k/twt.c | 455 +++++++++++++++++++++++++
 1 file changed, 455 insertions(+)
 create mode 100644 drivers/net/wireless/celeno/cl8k/twt.c

diff --git a/drivers/net/wireless/celeno/cl8k/twt.c b/drivers/net/wireless/celeno/cl8k/twt.c
new file mode 100644
index 000000000000..3a601c1a3fb7
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/twt.c
@@ -0,0 +1,455 @@
+// SPDX-License-Identifier: MIT
+/* Copyright(c) 2019-2021, Celeno Communications Ltd. */
+
+#include "twt.h"
+#include "twt_frame.h"
+#include "fw/msg_tx.h"
+#include "sta.h"
+#include "utils/utils.h"
+
+#define CL_TWT_CONST_TARGET_WAKE_TIME_OFFSET_US 500000
+#define WIFI_AWARE_TARGET_WAKE_TIME_MASK        ~0xFULL
+
+struct cl_next_start_time {
+       struct cl_twt_session_db *session;
+       u64 time;
+};
+
+static struct cl_twt_session_db *cl_twt_get_free_session(struct cl_hw *cl_hw)
+{
+       u8 i, max_sessions = cl_hw->conf->ce_twt_max_sessions;
+       struct cl_twt_session_db *session;
+
+       for (i = 0, session = &cl_hw->twt_db.cl_twt_sessions[0];
+            i < max_sessions;
+            i++, session++)
+               if (!session->cl_sta)
+                       return session;
+
+       return NULL;
+}
+
+static void cl_twt_remove_session_by_params(struct cl_hw *cl_hw,
+                                           struct cl_sta *cl_sta,
+                                           u8 flow_id,
+                                           bool send_teardown_req)
+{
+       u8 i, handled_sessions = 0, num_sessions = cl_hw->twt_db.num_sessions;
+       u8 max_sessions = cl_hw->conf->ce_twt_max_sessions;
+       struct cl_twt_session_db *session;
+
+       /* If flow_id == CL_TWT_FLOW_ID_INVALID then we'd like to remove all the sessions of STA */
+       bool remove_all_flows = (flow_id == CL_TWT_FLOW_ID_ALL);
+
+       for (i = 0, session = &cl_hw->twt_db.cl_twt_sessions[0];
+            (i < max_sessions) && (handled_sessions < num_sessions);
+            i++, session++) {
+               if (session->cl_sta == cl_sta &&
+                   (remove_all_flows ||
+                    session->twt_setup.req_type.fields.flow_id == flow_id)) {
+                       cl_twt_remove_session(cl_hw, session, send_teardown_req);
+
+                       if (!remove_all_flows)
+                               break;
+
+                       handled_sessions++;
+               }
+       }
+}
+
+static void cl_twt_remove_all_sta_sessions(struct cl_hw *cl_hw,
+                                          struct cl_sta *cl_sta,
+                                          bool send_teardown_req)
+{
+
+       if (send_teardown_req)
+               cl_twt_frame_send_individual_teardown_request(cl_hw, cl_sta, CL_TWT_FLOW_ID_ALL);
+
+       cl_twt_remove_session_by_params(cl_hw, cl_sta, CL_TWT_FLOW_ID_ALL, false);
+}
+
+static u64 cl_twt_get_next_start_time(struct cl_hw *cl_hw,
+                                     struct cl_twt_session_db *session,
+                                     u64 tsf)
+{
+       struct ieee80211_twt_individual_elem *elem = &session->twt_setup;
+       u64 start_time = elem->target_wake_time;
+       u64 interval = cl_twt_get_wake_interval_us(elem);
+       u64 remainder = 0;
+       u64 intervals_from_start_to_tsf = div64_u64_rem(tsf - start_time, interval, &remainder);
+       u64 next_time = 0;
+
+       if (remainder)
+               /* We add 1 to intervals_from_start_to_tsf to get next_time > tsf */
+               next_time = ((intervals_from_start_to_tsf + 1) * interval + start_time);
+       else
+               /* No remainder means that the next start time equals exactly to tsf */
+               next_time = tsf;
+
+       return next_time;
+}
+
+static void cl_twt_get_next_start_times_sorted_array(struct cl_hw *cl_hw,
+                                                    u64 tsf,
+                                                    struct cl_next_start_time *next_start_times)
+{
+       u64 next_time;
+       u8 i, j, handled_sessions = 0, num_sessions = cl_hw->twt_db.num_sessions;
+       u8 max_sessions = cl_hw->conf->ce_twt_max_sessions;
+       u8 bytes_to_move = 0;
+       struct cl_twt_session_db *session;
+
+       /* Calculate the next TWT time of all sessions and save them in a sorted array. */
+       for (i = 0, session = &cl_hw->twt_db.cl_twt_sessions[0];
+            i < max_sessions && handled_sessions < num_sessions;
+            i++, session++) {
+               if (!session->cl_sta)
+                       continue;
+
+               /* Calculate the current session's next start time */
+               next_time = cl_twt_get_next_start_time(cl_hw, session, tsf);
+
+               /* Find the correct position in the sorted array */
+               for (j = 0;
+                    (j < handled_sessions) && (next_start_times[j].time <= next_time);
+                     j++)
+                       ;
+
+               /* Make room for the current session's next start time */
+               bytes_to_move = (handled_sessions - j) * sizeof(next_start_times[0]);
+
+               if (bytes_to_move)
+                       memmove(&next_start_times[j + 1], &next_start_times[j],
+                               bytes_to_move);
+
+               /* Insert the current session's next start time to the array */
+               next_start_times[j].session = session;
+               next_start_times[j].time = next_time;
+               handled_sessions++;
+       }
+}
+
+bool cl_twt_is_enabled(struct cl_hw *cl_hw)
+{
+       return cl_hw->conf->ce_twt_en;
+}
+
+void cl_twt_init(struct cl_hw *cl_hw)
+{
+       if (!cl_twt_is_enabled(cl_hw))
+               return;
+
+       memset(&cl_hw->twt_db, 0, sizeof(cl_hw->twt_db));
+}
+
+void cl_twt_close(struct cl_hw *cl_hw)
+{
+       u8 i, max_sessions = cl_hw->conf->ce_twt_max_sessions;
+       struct cl_twt_session_db *session;
+
+       if (!cl_hw->twt_db.num_sessions)
+               return;
+
+       /* Remove all sessions */
+       for (i = 0, session = &cl_hw->twt_db.cl_twt_sessions[0];
+             (i < max_sessions) && (cl_hw->twt_db.num_sessions);
+             i++, session++) {
+               if (!session->cl_sta)
+                       continue;
+
+               cl_twt_remove_all_sta_sessions(cl_hw, session->cl_sta, false);
+       }
+}
+
+struct cl_twt_session_db *
+cl_twt_get_session(struct cl_hw *cl_hw, struct cl_sta *cl_sta, u8 flow_id)
+{
+       u8 i, max_sessions = cl_hw->conf->ce_twt_max_sessions;
+       struct cl_twt_session_db *session;
+
+       for (i = 0, session = &cl_hw->twt_db.cl_twt_sessions[0];
+            i < max_sessions;
+            i++, session++)
+               if (session->cl_sta == cl_sta &&
+                   session->twt_setup.req_type.fields.flow_id == flow_id)
+                       return session;
+
+       return NULL;
+}
+
+int cl_twt_update_session(struct cl_hw *cl_hw,
+                         struct cl_sta *cl_sta,
+                         struct ieee80211_twt_individual_elem *twt_elem,
+                         struct  cl_twt_session_db *session)
+{
+       session->cl_sta = cl_sta;
+       session->twt_setup = *twt_elem;
+
+       return 0;
+}
+
+int cl_twt_add_session(struct cl_hw *cl_hw,
+                      struct cl_sta *cl_sta,
+                      struct ieee80211_twt_individual_elem *twt_elem,
+                      struct  cl_twt_session_db **session)
+{
+       struct cl_twt_session_db *session_db = cl_twt_get_free_session(cl_hw);
+
+       if (!session_db) {
+               cl_dbg_err(cl_hw, "There are no available TWT sessions\n");
+               return -1;
+       }
+
+       cl_twt_update_session(cl_hw, cl_sta, twt_elem, session_db);
+       cl_hw->twt_db.num_sessions++;
+       *session = session_db;
+
+       return 0;
+}
+
+void cl_twt_remove_session(struct cl_hw *cl_hw,
+                          struct cl_twt_session_db *session,
+                          bool send_teardown_req)
+{
+       /* Send a TWT teardown frame */
+       if (send_teardown_req) {
+               u8 flow_id = session->twt_setup.req_type.fields.flow_id;
+
+               cl_twt_frame_send_individual_teardown_request(cl_hw, session->cl_sta, flow_id);
+       }
+
+       session->cl_sta = NULL;
+       memset(&session->twt_setup, 0, sizeof(session->twt_setup));
+       cl_hw->twt_db.num_sessions--;
+}
+
+int cl_twt_teardown_individual_sesseion(struct cl_hw *cl_hw,
+                                       struct cl_sta *cl_sta,
+                                       u8 flow_id,
+                                       bool send_teardown_req)
+{
+       struct cl_twt_session_db *session;
+       struct mm_twt_teardown_req req_msg = {
+               .sta_idx = cl_sta->sta_idx,
+               .twt_flow_id = flow_id
+       };
+
+       /* There are no sessions */
+       if (!cl_hw->twt_db.num_sessions)
+               return -1;
+
+       /* Remove the session(s) from the db */
+       if (flow_id == CL_TWT_FLOW_ID_ALL) {
+               cl_twt_remove_all_sta_sessions(cl_hw, cl_sta, send_teardown_req);
+       } else {
+               /* Check if the session exists */
+               session = cl_twt_get_session(cl_hw, cl_sta, flow_id);
+
+               if (!session) {
+                       cl_dbg_err(cl_hw, "Cannot handle the TWT teardown request "
+                                         "since no such session was found: "
+                                         "sta_idx %u, flow_id %u\n",
+                                  cl_sta->sta_idx, flow_id);
+                       return -1;
+               }
+
+               cl_twt_remove_session(cl_hw, session, send_teardown_req);
+       }
+
+       /* Send a msg to fw */
+       cl_msg_tx_twt_teardown(cl_hw, &req_msg);
+       return 0;
+}
+
+void cl_twt_sta_remove(struct cl_hw *cl_hw,
+                      struct cl_sta *cl_sta)
+{
+       struct mm_twt_teardown_req req_msg = {
+               .sta_idx = cl_sta->sta_idx,
+               .twt_flow_id = CL_TWT_FLOW_ID_ALL
+       };
+
+       if (!cl_twt_is_enabled(cl_hw))
+               return;
+
+       /* Remove all sessions of STA from the db */
+       cl_twt_remove_all_sta_sessions(cl_hw, cl_sta, false);
+
+       /* Send a msg to fw */
+       cl_msg_tx_twt_teardown(cl_hw, &req_msg);
+}
+
+u64 cl_twt_get_wake_interval_us(struct ieee80211_twt_individual_elem *elem)
+{
+       u8 exponent = elem->req_type.fields.wake_interval_exponent;
+       u64 mantissa = elem->wake_interval_mantissa;
+
+       return (mantissa << exponent);
+}
+
+u32 cl_twt_get_min_wake_time_us(struct ieee80211_twt_individual_elem *elem)
+{
+       u8 duration_unit_exp = (elem->control.fields.wake_duration_unit << 1);
+       u32 wake_time = elem->min_wake_duration;
+
+       /* Convert to us (1 unit = 256us/1024us) */
+       return (wake_time << (8 + duration_unit_exp));
+}
+
+void cl_twt_set_target_wake_time(struct cl_hw *cl_hw,
+                                struct ieee80211_twt_individual_elem *elem)
+{
+       /*
+        * Read TSF and add it an offset to make sure we set a future TSF.
+        * Make sure that tsf mod 16 = 0 to support WiFi aware requirement.
+        */
+       u64 tsf = (cl_get_tsf_u64(cl_hw) + CL_TWT_CONST_TARGET_WAKE_TIME_OFFSET_US) &
+               WIFI_AWARE_TARGET_WAKE_TIME_MASK;
+       u64 start_time = tsf;
+       struct cl_next_start_time sorted_next_start_times[CL_TWT_MAX_SESSIONS] = { { 0 } };
+       u8 i, num_sessions = cl_hw->twt_db.num_sessions;
+
+       if (cl_hw->twt_db.num_sessions > 0) {
+               u32 min_wake_time = cl_twt_get_min_wake_time_us(elem);
+
+               cl_twt_get_next_start_times_sorted_array(cl_hw, tsf, sorted_next_start_times);
+
+               /* Find the closest time for the new session */
+
+               for (i = 0; i < num_sessions; i++) {
+                       struct cl_twt_session_db *curr_session =
+                               sorted_next_start_times[i].session;
+                       u32 curr_min_wake_time =
+                               cl_twt_get_min_wake_time_us(&curr_session->twt_setup);
+                       u64 curr_next_time = sorted_next_start_times[i].time;
+                       u64 next_next_time;
+
+                       /*
+                        * We set the new session's start time such that the new TWT window
+                        * would start right after the min wake time of the last session since
+                        * we couldn't find a closer time for it.
+                        */
+
+                       if (i == num_sessions - 1) {
+                               start_time = curr_next_time + curr_min_wake_time;
+                               break;
+                       }
+
+                       next_next_time = sorted_next_start_times[i + 1].time;
+
+                       /*
+                        * We can put the new session between sessions i and i+1 without
+                        * overlapping.
+                        * The TWT windows would not overlap only if the intervals are a
+                        * multiply of each other.
+                        */
+
+                       if (next_next_time - curr_next_time >=
+                           curr_min_wake_time + min_wake_time) {
+                               start_time = curr_next_time + curr_min_wake_time;
+                               break;
+                       }
+               }
+       }
+
+       elem->target_wake_time = start_time;
+}
+
+void cl_twt_set_min_wake_duration(struct cl_hw *cl_hw,
+                                 struct ieee80211_twt_individual_elem *elem,
+                                 u32 duration_us)
+{
+       u16 duration_in_units_of_256_us = (duration_us >> 8);
+
+       if (duration_in_units_of_256_us <= U8_MAX) {
+               elem->min_wake_duration = duration_in_units_of_256_us;
+               elem->control.fields.wake_duration_unit = 0;
+       } else {
+               /* Convert to units of 1024us */
+               duration_in_units_of_256_us >>= 2;
+               elem->min_wake_duration = duration_in_units_of_256_us;
+               elem->control.fields.wake_duration_unit = 1;
+       }
+
+       if (duration_in_units_of_256_us > U8_MAX)
+               cl_dbg_err(cl_hw, "Invalid min wake duration %u! exceeds 8 bits\n", duration_us);
+
+       cl_dbg_info(cl_hw, "Set TWT min wake duration to %u us: "
+                          "duration val - %u, duration unit - %u us\n",
+                   duration_us, elem->min_wake_duration,
+                   (elem->control.fields.wake_duration_unit ? 1024 : 256));
+}
+
+void cl_twt_set_interval(struct cl_hw *cl_hw,
+                        struct ieee80211_twt_individual_elem *elem,
+                        u64 interval_us)
+{
+       u8 exponent;
+       u16 mantissa;
+
+       if (!interval_us)
+               return;
+
+       exponent = ffs((u32)interval_us) - 1;
+
+       elem->req_type.fields.wake_interval_exponent = exponent;
+       mantissa = (interval_us >> exponent);
+       elem->wake_interval_mantissa = mantissa;
+
+       if (mantissa > U16_MAX)
+               cl_dbg_err(cl_hw, "Invalid interval! mantissa exceeds 16 bits\n");
+
+       cl_dbg_info(cl_hw, "Set TWT interval to %llu us: exponent %u, mantissa %u\n",
+                   interval_us, elem->req_type.fields.wake_interval_exponent,
+                   elem->wake_interval_mantissa);
+}
+
+int cl_twt_handle_individual_setup_request(struct cl_hw *cl_hw,
+                                          struct cl_sta *cl_sta,
+                                          struct cl_ieee80211_mgmt *request)
+{
+       struct mm_twt_setup_req req_msg;
+       struct cl_twt_session_db *session = NULL;
+
+       /* Max sessions reached */
+       if (cl_hw->twt_db.num_sessions >= cl_hw->conf->ce_twt_max_sessions)
+               return -1;
+
+       /* Check the validity of the request */
+       if (!cl_twt_frame_is_individual_setup_request_valid(cl_hw, request)) {
+               cl_dbg_err(cl_hw, "TWT individual request is invalid!\n");
+               return -1;
+       }
+
+       /* Send a TWT response and add a new TWT session to the db */
+       if (cl_twt_frame_send_individual_setup_response(cl_hw, cl_sta, request, &session)) {
+               cl_dbg_err(cl_hw, "TWT response failed!\n");
+               return -1;
+       }
+
+       /* Fill and send a msg to fw */
+       req_msg.sta_idx = session->cl_sta->sta_idx;
+       req_msg.twt_flow_id = session->twt_setup.req_type.fields.flow_id;
+       req_msg.min_wake_duration_us = cl_twt_get_min_wake_time_us(&session->twt_setup);
+       req_msg.twt_interval_us = cl_twt_get_wake_interval_us(&session->twt_setup);
+       req_msg.twt_start_time_tsf = session->twt_setup.target_wake_time;
+       req_msg.announced = !(session->twt_setup.req_type.fields.flow_type);
+       req_msg.triggered = session->twt_setup.req_type.fields.trigger;
+
+       cl_msg_tx_twt_setup(cl_hw, &req_msg);
+       return 0;
+}
+
+int cl_twt_handle_individual_teardown_request(struct cl_hw *cl_hw,
+                                             struct cl_sta *cl_sta,
+                                             struct cl_ieee80211_mgmt *request)
+{
+       u8 flow_id = request->u.action.u.twt_individual_teardown.flow_id;
+       bool all_twt = request->u.action.u.twt_individual_teardown.teardown_all_twt;
+
+       if (all_twt)
+               flow_id = CL_TWT_FLOW_ID_ALL;
+
+       cl_twt_teardown_individual_sesseion(cl_hw, cl_sta, flow_id, false);
+       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.
________________________________


^ permalink raw reply related	[flat|nested] 262+ messages in thread

* [RFC v1 195/256] cl8k: add twt.h
  2021-06-17 15:58 [RFC v1 000/256] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (193 preceding siblings ...)
  2021-06-17 16:01 ` [RFC v1 194/256] cl8k: add twt.c viktor.barna
@ 2021-06-17 16:01 ` viktor.barna
  2021-06-17 16:01 ` [RFC v1 196/256] cl8k: add twt_cli.c viktor.barna
                   ` (62 subsequent siblings)
  257 siblings, 0 replies; 262+ messages in thread
From: viktor.barna @ 2021-06-17 16:01 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Oleksandr Savchenko, Shay Bar, Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

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

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 drivers/net/wireless/celeno/cl8k/twt.h | 58 ++++++++++++++++++++++++++
 1 file changed, 58 insertions(+)
 create mode 100644 drivers/net/wireless/celeno/cl8k/twt.h

diff --git a/drivers/net/wireless/celeno/cl8k/twt.h b/drivers/net/wireless/celeno/cl8k/twt.h
new file mode 100644
index 000000000000..fa01c69abf4f
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/twt.h
@@ -0,0 +1,58 @@
+/* SPDX-License-Identifier: MIT */
+/* Copyright(c) 2019-2021, Celeno Communications Ltd. */
+
+#ifndef CL_TWT_H
+#define CL_TWT_H
+
+#include "hw.h"
+#include <linux/ieee80211.h>
+
+/**
+ * TWT (=Target Wake Time, 802.11ax)
+ */
+
+#define CL_TWT_DEFAULT_INTERVAL_US 524288 /* 512 TU */
+#define CL_TWT_DEFAULT_MIN_WAKE_DURATION_US 64000 /* 62.5 TU */
+#define CL_TWT_FLOW_ID_ALL 0xFF
+#define CL_TWT_FLOW_ID_MAX 0x7
+
+bool cl_twt_is_enabled(struct cl_hw *cl_hw);
+void cl_twt_init(struct cl_hw *cl_hw);
+void cl_twt_close(struct cl_hw *cl_hw);
+struct cl_twt_session_db *
+cl_twt_get_session(struct cl_hw *cl_hw, struct cl_sta *cl_sta, u8 flow_id);
+int cl_twt_update_session(struct cl_hw *cl_hw,
+                         struct cl_sta *cl_sta,
+                         struct ieee80211_twt_individual_elem *twt_elem,
+                         struct  cl_twt_session_db *session);
+int cl_twt_add_session(struct cl_hw *cl_hw,
+                      struct cl_sta *cl_sta,
+                      struct ieee80211_twt_individual_elem *twt_elem,
+                      struct  cl_twt_session_db **session_ptr);
+void cl_twt_remove_session(struct cl_hw *cl_hw,
+                          struct cl_twt_session_db *session,
+                          bool send_teardown_req);
+int cl_twt_teardown_individual_sesseion(struct cl_hw *cl_hw,
+                                       struct cl_sta *cl_sta,
+                                       u8 flow_id,
+                                       bool send_teardown_req);
+void cl_twt_sta_remove(struct cl_hw *cl_hw,
+                      struct cl_sta *cl_sta);
+u64 cl_twt_get_wake_interval_us(struct ieee80211_twt_individual_elem *elem);
+u32 cl_twt_get_min_wake_time_us(struct ieee80211_twt_individual_elem *elem);
+void cl_twt_set_target_wake_time(struct cl_hw *cl_hw,
+                                struct ieee80211_twt_individual_elem *elem);
+void cl_twt_set_min_wake_duration(struct cl_hw *cl_hw,
+                                 struct ieee80211_twt_individual_elem *elem,
+                                 u32 duration_us);
+void cl_twt_set_interval(struct cl_hw *cl_hw,
+                        struct ieee80211_twt_individual_elem *elem,
+                        u64 interval_us);
+int cl_twt_handle_individual_setup_request(struct cl_hw *cl_hw,
+                                          struct cl_sta *cl_sta,
+                                          struct cl_ieee80211_mgmt *request);
+int cl_twt_handle_individual_teardown_request(struct cl_hw *cl_hw,
+                                             struct cl_sta *cl_sta,
+                                             struct cl_ieee80211_mgmt *request);
+
+#endif /* CL_TWT_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.
________________________________


^ permalink raw reply related	[flat|nested] 262+ messages in thread

* [RFC v1 196/256] cl8k: add twt_cli.c
  2021-06-17 15:58 [RFC v1 000/256] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (194 preceding siblings ...)
  2021-06-17 16:01 ` [RFC v1 195/256] cl8k: add twt.h viktor.barna
@ 2021-06-17 16:01 ` viktor.barna
  2021-06-17 16:01 ` [RFC v1 197/256] cl8k: add twt_cli.h viktor.barna
                   ` (61 subsequent siblings)
  257 siblings, 0 replies; 262+ messages in thread
From: viktor.barna @ 2021-06-17 16:01 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Oleksandr Savchenko, Shay Bar, Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

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

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 drivers/net/wireless/celeno/cl8k/twt_cli.c | 359 +++++++++++++++++++++
 1 file changed, 359 insertions(+)
 create mode 100644 drivers/net/wireless/celeno/cl8k/twt_cli.c

diff --git a/drivers/net/wireless/celeno/cl8k/twt_cli.c b/drivers/net/wireless/celeno/cl8k/twt_cli.c
new file mode 100644
index 000000000000..258df0c83c48
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/twt_cli.c
@@ -0,0 +1,359 @@
+// SPDX-License-Identifier: MIT
+/* Copyright(c) 2019-2021, Celeno Communications Ltd. */
+
+#include "twt_cli.h"
+#include "twt.h"
+#include "twt_frame.h"
+#include "sta.h"
+#include "utils/utils.h"
+
+#define CL_TWT_MIN_WAKE_DURATION_MAX_VAL_US (0xFFU << 10)
+
+static int cl_twt_cli_configuration_print(struct cl_hw *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,
+                   "TWT configuration:\n");
+       cl_snprintf(&buf, &len, &buf_size,
+                   "TWT enabled:                   %u\n",
+                   conf->ce_twt_en);
+       cl_snprintf(&buf, &len, &buf_size,
+                   "TWT default interval:          %u\n",
+                   conf->ce_twt_default_interval);
+       cl_snprintf(&buf, &len, &buf_size,
+                   "TWT default min wake duration: %u\n",
+                   conf->ce_twt_default_min_wake_duration);
+       cl_snprintf(&buf, &len, &buf_size,
+                   "TWT num of sessions:           %u\n",
+                   cl_hw->twt_db.num_sessions);
+       cl_snprintf(&buf, &len, &buf_size,
+                   "TWT max sessions:              %u\n",
+                   conf->ce_twt_max_sessions);
+
+       err = cl_vendor_reply(cl_hw, buf, len);
+       kfree(buf);
+
+       return err;
+}
+
+static int cl_twt_cli_sessions_print(struct cl_hw *cl_hw)
+{
+       u8 i, handled_sessions = 0, num_sessions = cl_hw->twt_db.num_sessions;
+       u8 max_sessions = cl_hw->conf->ce_twt_max_sessions;
+       struct cl_twt_session_db *session;
+       char *buf = NULL;
+       ssize_t buf_size;
+       int err = 0;
+       int len = 0;
+
+       cl_snprintf(&buf, &len, &buf_size,
+                   "-----------------------------------------------------"
+                   "---------------------------------\n"
+                   "| STA idx | Flow id | Announced | Triggered | "
+                   "Interval us | Min wake    | Start time |\n"
+                   "|         |         |           |           |        "
+                   "     | duration us |            |\n");
+       for (i = 0, session = &cl_hw->twt_db.cl_twt_sessions[0];
+            (i < max_sessions) && (handled_sessions < num_sessions);
+            i++, session++) {
+               if (!session->cl_sta)
+                       continue;
+
+               cl_snprintf(&buf, &len, &buf_size,
+                           "+---------+---------+-----------+-----------+"
+                           "-------------+-------------+------------+\n"
+                           "|   %3u   |    %1u    |     %1u     |     %1u"
+                           "     | %10llu  |   %6u    | %10llu |\n",
+                           session->cl_sta->sta_idx,
+                           session->twt_setup.req_type.fields.flow_id,
+                           !(session->twt_setup.req_type.fields.flow_type),
+                           session->twt_setup.req_type.fields.trigger,
+                           cl_twt_get_wake_interval_us(&session->twt_setup),
+                           cl_twt_get_min_wake_time_us(&session->twt_setup),
+                           session->twt_setup.target_wake_time);
+               handled_sessions++;
+       }
+
+       cl_snprintf(&buf, &len, &buf_size,
+                   "-----------------------------------------------------"
+                   "---------------------------------\n");
+
+       err = cl_vendor_reply(cl_hw, buf, len);
+       kfree(buf);
+
+       return err;
+}
+
+static int cl_twt_cli_send_individual_setup_request(struct cl_hw *cl_hw,
+                                                   struct cli_params *cli_params,
+                                                   bool simulate)
+{
+       u8 sta_idx = (u8)cli_params->params[0];
+       u8 setup_cmd = (u8)cli_params->params[1];
+       u8 flow_id = (u8)cli_params->params[2];
+       bool announced = (bool)cli_params->params[3];
+       bool triggered = (bool)cli_params->params[4];
+       u32 interval = (u32)cli_params->params[5];
+       u32 min_wake_dur = (u32)cli_params->params[6];
+       struct cl_sta *cl_sta;
+       int res = -1;
+
+       if (!cl_twt_is_enabled(cl_hw)) {
+               cl_dbg_verbose(cl_hw, "Please enable TWT first\n");
+               return -1;
+       }
+
+       cl_sta_lock_bh(cl_hw);
+       cl_sta = cl_sta_get(cl_hw, sta_idx);
+
+       if (!cl_sta) {
+               cl_dbg_err(cl_hw, "Invalid sta idx %u\n", sta_idx);
+               goto out;
+       }
+
+       if (setup_cmd > IEEE80211_TWT_SETUP_COMMAND_DEMAND) {
+               cl_dbg_verbose(cl_hw,
+                              "Invalid setup cmd %u. Must be lower than %u\n",
+                              setup_cmd, IEEE80211_TWT_SETUP_COMMAND_DEMAND);
+               goto out;
+       }
+
+       if (flow_id > CL_TWT_FLOW_ID_MAX) {
+               cl_dbg_verbose(cl_hw,
+                              "Invalid flow id %u. Must be lower than %u\n",
+                              flow_id, CL_TWT_FLOW_ID_MAX);
+               goto out;
+       }
+
+       if (min_wake_dur > CL_TWT_MIN_WAKE_DURATION_MAX_VAL_US) {
+               cl_dbg_verbose(cl_hw,
+                              "Invalid min wake duration (%u). Must be no greater than %u\n",
+                              min_wake_dur, CL_TWT_MIN_WAKE_DURATION_MAX_VAL_US);
+               goto out;
+       }
+
+       if (min_wake_dur > interval) {
+               cl_dbg_verbose(cl_hw,
+                              "Min wake duration (%u) cannot be greater than interval (%u)\n",
+                              min_wake_dur, interval);
+               goto out;
+       }
+
+       cl_dbg_info(cl_hw,
+                   "sta_idx %u, setup_cmd %u, flow_id %u, announced %u, "
+                   "triggered %u, interval %u, min wake duration %u\n",
+                   sta_idx, setup_cmd, flow_id, announced, triggered, interval, min_wake_dur);
+
+       if (simulate)
+               res = cl_twt_frame_simulate_individual_setup_request(cl_hw, cl_sta,
+                                                                    setup_cmd, flow_id,
+                                                                    announced, triggered,
+                                                                    (u64)interval, min_wake_dur);
+       else
+               res = cl_twt_frame_send_individual_setup_request(cl_hw, cl_sta, setup_cmd,
+                                                                flow_id, announced, triggered,
+                                                                (u64)interval, min_wake_dur);
+
+out:
+       cl_sta_unlock_bh(cl_hw);
+
+       return res;
+}
+
+static int cl_twt_cli_send_individual_teardown_request(struct cl_hw *cl_hw,
+                                                      struct cli_params *cli_params,
+                                                      bool simulate)
+{
+       u8 sta_idx = (u8)cli_params->params[0];
+       u8 flow_id = (u8)cli_params->params[1];
+       struct cl_sta *cl_sta;
+       int res = 0;
+
+       if (!cl_twt_is_enabled(cl_hw)) {
+               cl_dbg_verbose(cl_hw, "Please enable TWT first\n");
+               return -1;
+       }
+
+       cl_sta_lock_bh(cl_hw);
+       cl_sta = cl_sta_get(cl_hw, sta_idx);
+
+       if (!cl_sta) {
+               cl_dbg_err(cl_hw, "Invalid sta idx %u\n", sta_idx);
+               res = -1;
+               goto out;
+       }
+
+       if (flow_id > CL_TWT_FLOW_ID_MAX && flow_id != CL_TWT_FLOW_ID_ALL) {
+               cl_dbg_verbose(cl_hw,
+                              "Invalid flow id %u. Must be lower than %u or %u\n",
+                              flow_id, CL_TWT_FLOW_ID_MAX, CL_TWT_FLOW_ID_ALL);
+               res = -1;
+               goto out;
+       }
+
+       if (simulate) {
+               res = cl_twt_frame_simulate_individual_teardown_request(cl_hw, cl_sta, flow_id);
+       } else {
+               /*
+                * If the session doesn't exist or couldn't be removed -
+                * send a teardown request anyway
+                */
+               if (cl_twt_teardown_individual_sesseion(cl_hw, cl_sta, flow_id, true))
+                       cl_twt_frame_send_individual_teardown_request(cl_hw, cl_sta, flow_id);
+       }
+
+out:
+       cl_sta_unlock_bh(cl_hw);
+
+       return res;
+}
+
+static void cl_twt_cli_enable(struct cl_hw *cl_hw, bool enable)
+{
+       if (cl_hw->conf->ce_twt_en == enable) {
+               pr_debug("TWT is already %s\n", enable ? "enabled" : "disabled");
+               return;
+       }
+
+       cl_hw->conf->ce_twt_en = enable;
+
+       if (enable)
+               cl_twt_init(cl_hw);
+       else
+               cl_twt_close(cl_hw);
+
+       pr_debug("TWT has been %s\n", (enable ? "enabled" : "disabled"));
+}
+
+static int cl_twt_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,
+                "twt usage\n"
+                "-c: Print configuration\n"
+                "-e: Enable/Disable TWT [0 - disable, 1 - enable]\n"
+                "-m: Simulate a reception of a TWT individual request:\n"
+                       "\t[sta_idx].[setup_cmd (0:request, 1:suggest, "
+                       "2:demand)].[flow_id (0-7))].[announced].[triggered]."
+                       "[interval].[min_wake_duration]\n"
+                "-n: Simulate a reception of a TWT individual teardown "
+                       "request:\n\t[sta_idx].[flow_id (0-7; 255 all_twt)]\n"
+                "-p: Print sessions\n"
+                "-s: Send a TWT individual setup request:\n"
+                       "\t[sta_idx].[setup_cmd (0:request, 1:suggest, "
+                       "2:demand)].[flow_id (0-7))].[announced].[triggered]."
+                       "[interval].[min_wake_duration]\n"
+                "-t: Send a TWT individual teardown request:\n"
+                       "\t[sta_idx].[flow_id (0-7; 255 for all_twt)]\n");
+
+       err = cl_vendor_reply(cl_hw, buf, strlen(buf));
+       kfree(buf);
+
+       return err;
+}
+
+int cl_twt_cli(struct cl_hw *cl_hw, struct cli_params *cli_params)
+{
+       u32 expected_params = 0;
+       bool print_conf = false;
+       bool enable = false;
+       bool simulate_req = false;
+       bool simulate_teardown = false;
+       bool print_sessions = false;
+       bool send_req = false;
+       bool send_teardown = false;
+
+       switch (cli_params->option) {
+       case 'c':
+               print_conf = true;
+               expected_params = 0;
+               break;
+       case 'e':
+               enable = true;
+               expected_params = 1;
+               break;
+       case 'm':
+               simulate_req = true;
+               expected_params = 7;
+               break;
+       case 'n':
+               simulate_teardown = true;
+               expected_params = 2;
+               break;
+       case 'p':
+               print_sessions = true;
+               expected_params = 0;
+               break;
+       case 's':
+               send_req = true;
+               expected_params = 7;
+               break;
+       case 't':
+               send_teardown = true;
+               expected_params = 2;
+               break;
+       case '?':
+               return cl_twt_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_conf)
+               return cl_twt_cli_configuration_print(cl_hw);
+
+       if (enable) {
+               cl_twt_cli_enable(cl_hw, (bool)cli_params->params[0]);
+               return 0;
+       }
+
+       if (simulate_req) {
+               int res = cl_twt_cli_send_individual_setup_request(cl_hw, cli_params, true);
+
+               if (res)
+                       cl_dbg_verbose(cl_hw, "Error %d trying to simulate TWT request\n", res);
+
+               return 0;
+       }
+
+       if (simulate_teardown) {
+               cl_twt_cli_send_individual_teardown_request(cl_hw, cli_params, true);
+               return 0;
+       }
+
+       if (print_sessions)
+               return cl_twt_cli_sessions_print(cl_hw);
+
+       if (send_req) {
+               int res = cl_twt_cli_send_individual_setup_request(cl_hw, cli_params, false);
+
+               if (res)
+                       cl_dbg_verbose(cl_hw, "Error %d trying to send TWT request\n", res);
+
+               return 0;
+       }
+
+       if (send_teardown) {
+               cl_twt_cli_send_individual_teardown_request(cl_hw, cli_params, false);
+               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.
________________________________


^ permalink raw reply related	[flat|nested] 262+ messages in thread

* [RFC v1 197/256] cl8k: add twt_cli.h
  2021-06-17 15:58 [RFC v1 000/256] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (195 preceding siblings ...)
  2021-06-17 16:01 ` [RFC v1 196/256] cl8k: add twt_cli.c viktor.barna
@ 2021-06-17 16:01 ` viktor.barna
  2021-06-17 16:01 ` [RFC v1 198/256] cl8k: add twt_frame.c viktor.barna
                   ` (60 subsequent siblings)
  257 siblings, 0 replies; 262+ messages in thread
From: viktor.barna @ 2021-06-17 16:01 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Oleksandr Savchenko, Shay Bar, Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

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

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 drivers/net/wireless/celeno/cl8k/twt_cli.h | 11 +++++++++++
 1 file changed, 11 insertions(+)
 create mode 100644 drivers/net/wireless/celeno/cl8k/twt_cli.h

diff --git a/drivers/net/wireless/celeno/cl8k/twt_cli.h b/drivers/net/wireless/celeno/cl8k/twt_cli.h
new file mode 100644
index 000000000000..2bfdb8d110f0
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/twt_cli.h
@@ -0,0 +1,11 @@
+/* SPDX-License-Identifier: MIT */
+/* Copyright(c) 2019-2021, Celeno Communications Ltd. */
+
+#ifndef CL_TWT_CLI_H
+#define CL_TWT_CLI_H
+
+#include "hw.h"
+
+int cl_twt_cli(struct cl_hw *cl_hw, struct cli_params *cli_params);
+
+#endif /* CL_TWT_CLI_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.
________________________________


^ permalink raw reply related	[flat|nested] 262+ messages in thread

* [RFC v1 198/256] cl8k: add twt_frame.c
  2021-06-17 15:58 [RFC v1 000/256] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (196 preceding siblings ...)
  2021-06-17 16:01 ` [RFC v1 197/256] cl8k: add twt_cli.h viktor.barna
@ 2021-06-17 16:01 ` viktor.barna
  2021-06-17 16:01 ` [RFC v1 199/256] cl8k: add twt_frame.h viktor.barna
                   ` (59 subsequent siblings)
  257 siblings, 0 replies; 262+ messages in thread
From: viktor.barna @ 2021-06-17 16:01 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Oleksandr Savchenko, Shay Bar, Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

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

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 drivers/net/wireless/celeno/cl8k/twt_frame.c | 385 +++++++++++++++++++
 1 file changed, 385 insertions(+)
 create mode 100644 drivers/net/wireless/celeno/cl8k/twt_frame.c

diff --git a/drivers/net/wireless/celeno/cl8k/twt_frame.c b/drivers/net/wireless/celeno/cl8k/twt_frame.c
new file mode 100644
index 000000000000..52373e8e950e
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/twt_frame.c
@@ -0,0 +1,385 @@
+// SPDX-License-Identifier: MIT
+/* Copyright(c) 2019-2021, Celeno Communications Ltd. */
+
+#include "twt_frame.h"
+#include "twt.h"
+#include "sta.h"
+#include "mac_addr.h"
+#include "tx/tx.h"
+
+static int cl_twt_frame_build_individual_setup(struct cl_hw *cl_hw,
+                                              struct sk_buff **skb_ptr,
+                                              struct cl_sta *cl_sta)
+{
+       struct ieee80211_sub_if_data *sdata = cl_sta->stainfo->sdata;
+       struct sk_buff *skb;
+       struct cl_ieee80211_mgmt *mgmt;
+       int hdr_len = offsetof(struct cl_ieee80211_mgmt, u.action.u.twt_individual_setup) +
+               sizeof(mgmt->u.action.u.twt_individual_setup);
+       u8 *bssid;
+
+       skb = dev_alloc_skb(cl_hw->hw->extra_tx_headroom + hdr_len);
+
+       if (!skb)
+               return -ENOMEM;
+
+       if (sdata->vif.type == NL80211_IFTYPE_STATION)
+               bssid = sdata->u.mgd.bssid;
+       else
+               bssid = sdata->vif.addr;
+
+       skb_reserve(skb, cl_hw->hw->extra_tx_headroom);
+       mgmt = (struct cl_ieee80211_mgmt *)skb_put_zero(skb, hdr_len);
+       cl_mac_addr_copy(mgmt->sa, sdata->vif.addr);
+       cl_mac_addr_copy(mgmt->da, cl_sta->addr);
+       cl_mac_addr_copy(mgmt->bssid, bssid);
+       mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
+                                         IEEE80211_STYPE_ACTION);
+
+       mgmt->u.action.category = WLAN_CATEGORY_UNPROTECTED_S1G;
+       mgmt->u.action.u.twt_individual_setup.action_code = WLAN_UNPROT_S1G_ACTION_TWT_SETUP;
+       mgmt->u.action.u.twt_individual_setup.dialog_token = cl_hw->twt_db.dialog_token++;
+
+       mgmt->u.action.u.twt_individual_setup.twt_elem_id = WLAN_EID_TWT;
+       mgmt->u.action.u.twt_individual_setup.twt_elem_length =
+               sizeof(struct ieee80211_twt_individual_elem);
+
+       *skb_ptr = skb;
+       return 0;
+}
+
+static int cl_twt_frame_build_individual_teardown(struct cl_hw *cl_hw,
+                                                 struct sk_buff **skb_ptr,
+                                                 struct cl_sta *cl_sta,
+                                                 u8 flow_id)
+{
+       struct ieee80211_sub_if_data *sdata = cl_sta->stainfo->sdata;
+       struct sk_buff *skb;
+       struct cl_ieee80211_mgmt *mgmt;
+       int hdr_len = offsetof(struct cl_ieee80211_mgmt, u.action.u.twt_individual_teardown) +
+               sizeof(mgmt->u.action.u.twt_individual_teardown);
+       u8 *bssid;
+
+       skb = dev_alloc_skb(cl_hw->hw->extra_tx_headroom + hdr_len);
+
+       if (!skb)
+               return -ENOMEM;
+
+       if (sdata->vif.type == NL80211_IFTYPE_STATION)
+               bssid = sdata->u.mgd.bssid;
+       else
+               bssid = sdata->vif.addr;
+
+       skb_reserve(skb, cl_hw->hw->extra_tx_headroom);
+       mgmt = (struct cl_ieee80211_mgmt *)skb_put_zero(skb, hdr_len);
+       cl_mac_addr_copy(mgmt->sa, sdata->vif.addr);
+       cl_mac_addr_copy(mgmt->da, cl_sta->addr);
+       cl_mac_addr_copy(mgmt->bssid, bssid);
+       mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
+                                         IEEE80211_STYPE_ACTION);
+
+       mgmt->u.action.category = WLAN_CATEGORY_UNPROTECTED_S1G;
+       mgmt->u.action.u.twt_individual_teardown.action_code = WLAN_UNPROT_S1G_ACTION_TWT_TEARDOWN;
+       mgmt->u.action.u.twt_individual_teardown.negotiation_type = 0;
+
+       if (flow_id == CL_TWT_FLOW_ID_ALL) {
+               mgmt->u.action.u.twt_individual_teardown.teardown_all_twt = 1;
+               mgmt->u.action.u.twt_individual_teardown.flow_id = 0;
+       } else {
+               mgmt->u.action.u.twt_individual_teardown.teardown_all_twt = 0;
+               mgmt->u.action.u.twt_individual_teardown.flow_id = flow_id;
+       }
+
+       *skb_ptr = skb;
+       return 0;
+}
+
+static void
+cl_twt_frame_fill_setup_response_parameters(struct cl_hw *cl_hw,
+                                           struct ieee80211_twt_individual_elem *request_ie,
+                                           struct cl_ieee80211_mgmt *mgmt)
+{
+       struct ieee80211_twt_individual_elem *twt_elem =
+               &mgmt->u.action.u.twt_individual_setup.twt_elem;
+       u64 interval;
+       u32 default_interval = cl_hw->conf->ce_twt_default_interval;
+       u32 default_min_wake_duration = cl_hw->conf->ce_twt_default_min_wake_duration;
+
+       /* Copy TWT element parameters from the request */
+       *twt_elem = *request_ie;
+
+       /* Override the relevant parameters */
+       twt_elem->req_type.fields.request = 0;
+       twt_elem->control.fields.negotiation_type = 0;
+       twt_elem->req_type.fields.setup_cmd = IEEE80211_TWT_SETUP_COMMAND_ACCEPT;
+       twt_elem->req_type.fields.protection = 0;
+       twt_elem->channel = 0;
+
+       /*
+        * Set default values of wake interval exponent/mantissa and min
+        * wake duration in case that at least one of them equals to 0
+        */
+       interval = cl_twt_get_wake_interval_us(twt_elem);
+
+       if (!twt_elem->min_wake_duration) {
+               if (default_min_wake_duration < interval) {
+                       cl_twt_set_min_wake_duration(cl_hw, twt_elem, default_min_wake_duration);
+               } else if (interval) {
+                       /* If default min wake time > interval - set it to half of the interval */
+                       cl_twt_set_min_wake_duration(cl_hw, twt_elem, (interval >> 1));
+               } else {
+                       /* Set default interval and min wake duration */
+                       cl_twt_set_interval(cl_hw, twt_elem, default_interval);
+                       cl_twt_set_min_wake_duration(cl_hw, twt_elem, default_min_wake_duration);
+               }
+       } else if (!interval) {
+               u32 min_wake_duration = cl_twt_get_min_wake_time_us(twt_elem);
+
+               if (min_wake_duration < default_interval)
+                       cl_twt_set_interval(cl_hw, twt_elem, default_interval);
+               else
+                       /*
+                        * If the default interval < min wake duration -
+                        * set it to be double the min wake duration
+                        */
+                       cl_twt_set_interval(cl_hw, twt_elem, (min_wake_duration << 1));
+       }
+
+       cl_twt_set_target_wake_time(cl_hw, twt_elem);
+}
+
+static void cl_twt_frmae_fill_setup_request_parameters(struct cl_hw *cl_hw,
+                                                      struct cl_ieee80211_mgmt *mgmt,
+                                                      enum ieee80211_twt_setup_command setup_cmd,
+                                                      u8 flow_id,
+                                                      bool announced,
+                                                      bool triggered,
+                                                      u64 interval_us,
+                                                      u32 min_wake_duration_us)
+{
+       struct ieee80211_twt_individual_elem *twt_elem =
+               &mgmt->u.action.u.twt_individual_setup.twt_elem;
+       u64 _interval_us = interval_us;
+       u32 _min_wake_duration_us = min_wake_duration_us;
+
+       /* Override the relevant parameters */
+
+       twt_elem->control.fields.negotiation_type = 0;
+       twt_elem->req_type.fields.protection = 0;
+       twt_elem->channel = 0;
+       twt_elem->req_type.fields.request = 1;
+       twt_elem->req_type.fields.implicit = 1;
+       twt_elem->req_type.fields.setup_cmd = setup_cmd;
+       twt_elem->req_type.fields.flow_id = flow_id;
+       twt_elem->req_type.fields.flow_type = !announced;
+       twt_elem->req_type.fields.trigger = triggered;
+
+       if (!interval_us)
+               _interval_us = cl_hw->conf->ce_twt_default_interval;
+
+       if (!min_wake_duration_us)
+               _min_wake_duration_us = cl_hw->conf->ce_twt_default_min_wake_duration;
+
+       if (_min_wake_duration_us < _interval_us) {
+               /* Min wake duration < interval */
+               cl_twt_set_interval(cl_hw, twt_elem, _interval_us);
+               cl_twt_set_min_wake_duration(cl_hw, twt_elem, _min_wake_duration_us);
+       } else {
+               if (!interval_us) {
+                       /*
+                        * Min wake duration argument >= default interval =>
+                        * Set the interval to be double the min wake duration
+                        */
+                       cl_twt_set_min_wake_duration(cl_hw, twt_elem, _min_wake_duration_us);
+                       cl_twt_set_interval(cl_hw, twt_elem, (_min_wake_duration_us << 1));
+               } else {
+                       /*
+                        * Interval argument <= default min wake duration =>
+                        * Set the min wake duration to be half the interval
+                        */
+                       cl_twt_set_interval(cl_hw, twt_elem, _interval_us);
+                       cl_twt_set_min_wake_duration(cl_hw, twt_elem, (_interval_us >> 1));
+               }
+       }
+}
+
+bool cl_twt_frame_is_individual_setup_request_valid(struct cl_hw *cl_hw,
+                                                   struct cl_ieee80211_mgmt *request)
+{
+       u8 twt_elem_len = request->u.action.u.twt_individual_setup.twt_elem_length;
+       struct ieee80211_twt_individual_elem *twt_elem =
+               &request->u.action.u.twt_individual_setup.twt_elem;
+       u64 wake_interval_us;
+       u32 min_wake_time_us;
+
+       if (twt_elem_len != sizeof(struct ieee80211_twt_individual_elem)) {
+               cl_dbg_err(cl_hw, "Illegal size of twt individual element %u (should be %zu)\n",
+                          twt_elem_len, sizeof(struct ieee80211_twt_individual_elem));
+               return false;
+       }
+
+       wake_interval_us = cl_twt_get_wake_interval_us(twt_elem);
+       min_wake_time_us = cl_twt_get_min_wake_time_us(twt_elem);
+
+       if (min_wake_time_us && wake_interval_us && min_wake_time_us > wake_interval_us) {
+               cl_dbg_err(cl_hw, "min wake duration (%u) > wake interval (%llu)!\n",
+                          min_wake_time_us, wake_interval_us);
+               return false;
+       }
+
+       return true;
+}
+
+int cl_twt_frame_send_individual_setup_response(struct cl_hw *cl_hw,
+                                               struct cl_sta *cl_sta,
+                                               struct cl_ieee80211_mgmt *request,
+                                               struct cl_twt_session_db **session)
+{
+       struct sk_buff *skb;
+       struct cl_ieee80211_mgmt *mgmt;
+       struct ieee80211_twt_individual_elem *req_twt_elem;
+       struct ieee80211_twt_individual_elem *res_twt_elem;
+       u8 flow_id;
+
+       if (cl_twt_frame_build_individual_setup(cl_hw, &skb, cl_sta)) {
+               cl_dbg_err(cl_hw, "Build of TWT individual setup request failed!\n");
+               return -1;
+       }
+
+       req_twt_elem = &request->u.action.u.twt_individual_setup.twt_elem;
+       mgmt = (struct cl_ieee80211_mgmt *)skb->data;
+       cl_twt_frame_fill_setup_response_parameters(cl_hw, req_twt_elem, mgmt);
+       flow_id = req_twt_elem->req_type.fields.flow_id;
+       res_twt_elem = &mgmt->u.action.u.twt_individual_setup.twt_elem;
+
+       /* Check if a session with the same sta_idx and flow_id already exists */
+       *session = cl_twt_get_session(cl_hw, cl_sta, flow_id);
+
+       /*
+        * If the seesion already exists - update it.
+        * Otherwise add a new TWT session to the db.
+        */
+       if (*session) {
+               cl_dbg_info(cl_hw, "Updating an existing TWT session sta_idx %u, flow_id %u\n",
+                           cl_sta->sta_idx, flow_id);
+               cl_twt_update_session(cl_hw, cl_sta, res_twt_elem, *session);
+       } else if (cl_twt_add_session(cl_hw, cl_sta, res_twt_elem, session)) {
+               cl_dbg_err(cl_hw, "Session for sta %u could not be added. Aborting\n",
+                          cl_sta->sta_idx);
+               dev_kfree_skb_any(skb);
+               goto error;
+       } else {
+               cl_dbg_info(cl_hw, "A new TWT session was added. sta_idx %u, flow_id %u\n",
+                           cl_sta->sta_idx, flow_id);
+       }
+
+       /* Send the TWT response */
+       ieee80211_tx_prepare_skb(cl_hw->hw, cl_sta->cl_vif->vif, skb, cl_hw->nl_band, NULL);
+       cl_tx_single(cl_hw, cl_sta, skb, false, true);
+       cl_dbg_trace(cl_hw, "TWT individual setup response sent to STA %u\n", cl_sta->sta_idx);
+
+       return 0;
+ error:
+       return -1;
+}
+
+int cl_twt_frame_send_individual_setup_request(struct cl_hw *cl_hw,
+                                              struct cl_sta *cl_sta,
+                                              enum ieee80211_twt_setup_command setup_cmd,
+                                              u8 flow_id,
+                                              bool announced,
+                                              bool triggered,
+                                              u64 interval_us,
+                                              u32 min_wake_duration_us)
+{
+       /* Send a TWT individual setup request (should be used in STA mode) */
+       struct sk_buff *skb;
+
+       if (cl_twt_frame_build_individual_setup(cl_hw, &skb, cl_sta)) {
+               cl_dbg_err(cl_hw, "Build of TWT individual setup request failed!\n");
+               return -1;
+       }
+
+       cl_twt_frmae_fill_setup_request_parameters(cl_hw, (struct cl_ieee80211_mgmt *)skb->data,
+                                                  setup_cmd, flow_id, announced, triggered,
+                                                  interval_us, min_wake_duration_us);
+
+       /* Send the TWT request */
+       ieee80211_tx_prepare_skb(cl_hw->hw, cl_sta->cl_vif->vif, skb, cl_hw->nl_band, NULL);
+       cl_tx_single(cl_hw, cl_sta, skb, false, true);
+       cl_dbg_trace(cl_hw, "TWT individual setup request sent\n");
+
+       return 0;
+}
+
+int cl_twt_frame_simulate_individual_setup_request(struct cl_hw *cl_hw,
+                                                  struct cl_sta *cl_sta,
+                                                  enum ieee80211_twt_setup_command setup_cmd,
+                                                  u8 flow_id,
+                                                  bool announced,
+                                                  bool triggered,
+                                                  u64 interval_us,
+                                                  u32 min_wake_duration_us)
+{
+       /* Simulates a TWT individual setup request in STA mode */
+       struct sk_buff *skb;
+       struct cl_ieee80211_mgmt *mgmt;
+
+       if (cl_twt_frame_build_individual_setup(cl_hw, &skb, cl_sta)) {
+               cl_dbg_err(cl_hw, "Build of TWT individual setup request failed!\n");
+               return -1;
+       }
+
+       mgmt = (struct cl_ieee80211_mgmt *)skb->data;
+
+       cl_twt_frmae_fill_setup_request_parameters(cl_hw, mgmt, setup_cmd,
+                                                  flow_id, announced, triggered,
+                                                  interval_us, min_wake_duration_us);
+       cl_dbg_trace(cl_hw, "TWT individual setup request simulated\n");
+       cl_twt_handle_individual_setup_request(cl_hw, cl_sta, mgmt);
+
+       dev_kfree_skb_any(skb);
+       return 0;
+}
+
+int cl_twt_frame_send_individual_teardown_request(struct cl_hw *cl_hw,
+                                                 struct cl_sta *cl_sta,
+                                                 u8 flow_id)
+{
+       /* Send a TWT individual teardown request */
+       struct sk_buff *skb;
+
+       if (cl_twt_frame_build_individual_teardown(cl_hw, &skb, cl_sta, flow_id)) {
+               cl_dbg_err(cl_hw, "Build of a TWT individual teardown request failed!\n");
+               return -1;
+       }
+
+       /* Send the TWT request */
+       ieee80211_tx_prepare_skb(cl_hw->hw, cl_sta->cl_vif->vif, skb, cl_hw->nl_band, NULL);
+       cl_tx_single(cl_hw, cl_sta, skb, false, true);
+       cl_dbg_trace(cl_hw, "TWT individual teardown request sent\n");
+
+       return 0;
+}
+
+int cl_twt_frame_simulate_individual_teardown_request(struct cl_hw *cl_hw,
+                                                     struct cl_sta *cl_sta,
+                                                     u8 flow_id)
+{
+       /* Simulate a TWT individual teardown request */
+       struct sk_buff *skb;
+       struct cl_ieee80211_mgmt *mgmt;
+
+       if (cl_twt_frame_build_individual_teardown(cl_hw, &skb, cl_sta, flow_id)) {
+               cl_dbg_err(cl_hw, "Build of TWT individual teardown request failed!\n");
+               return -1;
+       }
+
+       mgmt = (struct cl_ieee80211_mgmt *)skb->data;
+
+       cl_dbg_trace(cl_hw, "TWT individual teardown request simulated\n");
+       cl_twt_handle_individual_teardown_request(cl_hw, cl_sta, mgmt);
+
+       dev_kfree_skb_any(skb);
+       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.
________________________________


^ permalink raw reply related	[flat|nested] 262+ messages in thread

* [RFC v1 199/256] cl8k: add twt_frame.h
  2021-06-17 15:58 [RFC v1 000/256] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (197 preceding siblings ...)
  2021-06-17 16:01 ` [RFC v1 198/256] cl8k: add twt_frame.c viktor.barna
@ 2021-06-17 16:01 ` viktor.barna
  2021-06-17 16:01 ` [RFC v1 200/256] cl8k: add tx/agg_cfm.c viktor.barna
                   ` (58 subsequent siblings)
  257 siblings, 0 replies; 262+ messages in thread
From: viktor.barna @ 2021-06-17 16:01 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Oleksandr Savchenko, Shay Bar, Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

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

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 drivers/net/wireless/celeno/cl8k/twt_frame.h | 39 ++++++++++++++++++++
 1 file changed, 39 insertions(+)
 create mode 100644 drivers/net/wireless/celeno/cl8k/twt_frame.h

diff --git a/drivers/net/wireless/celeno/cl8k/twt_frame.h b/drivers/net/wireless/celeno/cl8k/twt_frame.h
new file mode 100644
index 000000000000..92d462caba6f
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/twt_frame.h
@@ -0,0 +1,39 @@
+/* SPDX-License-Identifier: MIT */
+/* Copyright(c) 2019-2021, Celeno Communications Ltd. */
+
+#ifndef CL_TWT_FRAME_H
+#define CL_TWT_FRAME_H
+
+#include "hw.h"
+#include "mac80211.h"
+
+bool cl_twt_frame_is_individual_setup_request_valid(struct cl_hw *cl_hw,
+                                                   struct cl_ieee80211_mgmt *request);
+int cl_twt_frame_send_individual_setup_response(struct cl_hw *cl_hw,
+                                               struct cl_sta *cl_sta,
+                                               struct cl_ieee80211_mgmt *request,
+                                               struct cl_twt_session_db **session);
+int cl_twt_frame_send_individual_setup_request(struct cl_hw *cl_hw,
+                                              struct cl_sta *cl_sta,
+                                              enum ieee80211_twt_setup_command setup_cmd,
+                                              u8 flow_id,
+                                              bool announced,
+                                              bool triggered,
+                                              u64 interval_us,
+                                              u32 min_wake_duration_us);
+int cl_twt_frame_simulate_individual_setup_request(struct cl_hw *cl_hw,
+                                                  struct cl_sta *cl_sta,
+                                                  enum ieee80211_twt_setup_command setup_cmd,
+                                                  u8 flow_id,
+                                                  bool announced,
+                                                  bool triggered,
+                                                  u64 interval_us,
+                                                  u32 min_wake_duration_us);
+int cl_twt_frame_send_individual_teardown_request(struct cl_hw *cl_hw,
+                                                 struct cl_sta *cl_sta,
+                                                 u8 flow_id);
+int cl_twt_frame_simulate_individual_teardown_request(struct cl_hw *cl_hw,
+                                                     struct cl_sta *cl_sta,
+                                                     u8 flow_id);
+
+#endif /* CL_TWT_FRAME_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.
________________________________


^ permalink raw reply related	[flat|nested] 262+ messages in thread

* [RFC v1 200/256] cl8k: add tx/agg_cfm.c
  2021-06-17 15:58 [RFC v1 000/256] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (198 preceding siblings ...)
  2021-06-17 16:01 ` [RFC v1 199/256] cl8k: add twt_frame.h viktor.barna
@ 2021-06-17 16:01 ` viktor.barna
  2021-06-17 16:01 ` [RFC v1 201/256] cl8k: add tx/agg_cfm.h viktor.barna
                   ` (57 subsequent siblings)
  257 siblings, 0 replies; 262+ messages in thread
From: viktor.barna @ 2021-06-17 16:01 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Oleksandr Savchenko, Shay Bar, Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

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

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 drivers/net/wireless/celeno/cl8k/tx/agg_cfm.c | 219 ++++++++++++++++++
 1 file changed, 219 insertions(+)
 create mode 100644 drivers/net/wireless/celeno/cl8k/tx/agg_cfm.c

diff --git a/drivers/net/wireless/celeno/cl8k/tx/agg_cfm.c b/drivers/net/wireless/celeno/cl8k/tx/agg_cfm.c
new file mode 100644
index 000000000000..a3c74f57f197
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/tx/agg_cfm.c
@@ -0,0 +1,219 @@
+// SPDX-License-Identifier: MIT
+/* Copyright(c) 2019-2021, Celeno Communications Ltd. */
+
+#include "tx/agg_cfm.h"
+#include "sta.h"
+#include "enhanced_tim.h"
+#include "tx/sw_txhdr.h"
+#include "chip.h"
+#include "tx/tx_inject.h"
+#include "tx/tx_amsdu.h"
+
+#define AGG_POLL_TIMEOUT 50
+
+/*
+ * cl_hw->agg_cfm_queues:
+ * These queues are used to keep pointers to skb's sent
+ * as aggregation and waiting for confirmation.
+ */
+
+void cl_agg_cfm_init(struct cl_hw *cl_hw)
+{
+       int i = 0;
+
+       for (i = 0; i < IPC_MAX_BA_SESSIONS; i++)
+               INIT_LIST_HEAD(&cl_hw->agg_cfm_queues[i].head);
+}
+
+void cl_agg_cfm_add(struct cl_hw *cl_hw, struct cl_sw_txhdr *sw_txhdr, u8 agg_idx)
+{
+       spin_lock(&cl_hw->tx_lock_cfm_agg);
+       list_add_tail(&sw_txhdr->cfm_list, &cl_hw->agg_cfm_queues[agg_idx].head);
+       spin_unlock(&cl_hw->tx_lock_cfm_agg);
+}
+
+static void cl_agg_cfm_amsdu_free(struct cl_hw *cl_hw, struct cl_sw_txhdr *sw_txhdr)
+{
+       struct cl_amsdu_txhdr *amsdu_txhdr = NULL;
+       struct cl_amsdu_txhdr *tmp = NULL;
+       struct sk_buff *sub_skb = NULL;
+       struct ieee80211_tx_info *tx_info_sub_skb = NULL;
+
+       list_for_each_entry_safe(amsdu_txhdr, tmp, &sw_txhdr->amsdu_txhdr.list, list) {
+               sub_skb = amsdu_txhdr->skb;
+               tx_info_sub_skb = IEEE80211_SKB_CB(sub_skb);
+
+               if (cl_tx_ctrl_is_inject(tx_info_sub_skb))
+                       cl_tx_inject_cfm(cl_hw);
+
+               list_del(&amsdu_txhdr->list);
+               dma_unmap_single(cl_hw->chip->dev, amsdu_txhdr->dma_addr,
+                                (size_t)sub_skb->len, DMA_TO_DEVICE);
+               kfree_skb(sub_skb);
+               cl_tx_amsdu_txhdr_free(cl_hw, amsdu_txhdr);
+       }
+}
+
+void cl_agg_cfm_free_head_skb(struct cl_hw *cl_hw,
+                             struct cl_agg_cfm_queue *cfm_queue,
+                             u8 ba_queue_idx)
+{
+       struct cl_sw_txhdr *sw_txhdr = list_first_entry(&cfm_queue->head,
+                                                       struct cl_sw_txhdr,
+                                                       cfm_list);
+       struct sk_buff *skb = sw_txhdr->skb;
+       struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
+       dma_addr_t dma_addr = le32_to_cpu(sw_txhdr->txdesc.umacdesc.packet_addr[0]);
+
+       dma_unmap_single(cl_hw->chip->dev, dma_addr, sw_txhdr->map_len, DMA_TO_DEVICE);
+
+       /* If amsdu list not empty free sub MSDU frames first, including amsdu_txhdr */
+       if (cl_tx_ctrl_is_amsdu(tx_info))
+               if (!list_empty(&sw_txhdr->amsdu_txhdr.list))
+                       cl_agg_cfm_amsdu_free(cl_hw, sw_txhdr);
+
+       if (cl_tx_ctrl_is_inject(tx_info))
+               cl_tx_inject_cfm(cl_hw);
+
+       consume_skb(skb);
+       list_del(&sw_txhdr->cfm_list);
+       cl_sw_txhdr_free(cl_hw, sw_txhdr);
+}
+
+static void cl_agg_cfm_flush_queue(struct cl_hw *cl_hw, u8 agg_idx)
+{
+       struct cl_agg_cfm_queue *cfm_queue = &cl_hw->agg_cfm_queues[agg_idx];
+       struct cl_tx_queue *tx_queue = cfm_queue->tx_queue;
+       struct sk_buff *skb = NULL;
+       struct cl_sw_txhdr *sw_txhdr = NULL;
+       dma_addr_t dma_addr = 0;
+       struct ieee80211_tx_info *tx_info;
+
+       if (!tx_queue)
+               return;
+
+       if (list_empty(&cfm_queue->head))
+               return;
+
+       do {
+               sw_txhdr = list_first_entry(&cfm_queue->head, struct cl_sw_txhdr, cfm_list);
+               skb = sw_txhdr->skb;
+
+               dma_addr = le32_to_cpu(sw_txhdr->txdesc.umacdesc.packet_addr[0]);
+               dma_unmap_single(cl_hw->chip->dev, dma_addr, sw_txhdr->map_len, DMA_TO_DEVICE);
+
+               tx_info = IEEE80211_SKB_CB(skb);
+
+               /* If amsdu list not empty free sub MSDU frames first, including amsdu_txhdr */
+               if (cl_tx_ctrl_is_amsdu(tx_info))
+                       if (!list_empty(&sw_txhdr->amsdu_txhdr.list))
+                               cl_agg_cfm_amsdu_free(cl_hw, sw_txhdr);
+
+               tx_queue->total_fw_cfm++;
+
+               if (cl_tx_ctrl_is_inject(tx_info))
+                       cl_tx_inject_cfm(cl_hw);
+
+               kfree_skb(skb);
+               list_del(&sw_txhdr->cfm_list);
+               cl_sw_txhdr_free(cl_hw, sw_txhdr);
+       } while (!list_empty(&cfm_queue->head));
+
+       /*
+        * Set fw_free_space back to maximum after flushing the queue
+        * and clear the enhanced TIM.
+        */
+       tx_queue->fw_free_space = tx_queue->fw_max_size;
+       cl_enhanced_tim_clear_tx_agg(cl_hw, agg_idx, tx_queue->hw_index,
+                                    tx_queue->cl_sta, tx_queue->tid);
+
+       cfm_queue->tx_queue = NULL;
+}
+
+void cl_agg_cfm_flush_all(struct cl_hw *cl_hw)
+{
+       int i = 0;
+
+       /* Don't use BH lock, because cl_agg_cfm_flush_all() is called with BH disabled */
+       spin_lock(&cl_hw->tx_lock_cfm_agg);
+
+       for (i = 0; i < IPC_MAX_BA_SESSIONS; i++)
+               cl_agg_cfm_flush_queue(cl_hw, i);
+
+       spin_unlock(&cl_hw->tx_lock_cfm_agg);
+}
+
+static void cl_agg_cfm_poll_timeout(struct cl_hw *cl_hw, struct cl_tx_queue *tx_queue,
+                                   u8 agg_idx, bool flush)
+{
+       /*
+        * When polling failed clear the enhanced TIM so that firmware will
+        * not try to transmit these packets.
+        * If flush is set cl_enhanced_tim_clear_tx_agg() is called inside
+        * cl_agg_cfm_flush_queue().
+        */
+       cl_dbg_err(cl_hw, "Polling timeout (queue_idx = %u)\n", agg_idx);
+
+       spin_lock_bh(&cl_hw->tx_lock_cfm_agg);
+
+       if (flush)
+               cl_agg_cfm_flush_queue(cl_hw, agg_idx);
+       else
+               cl_enhanced_tim_clear_tx_agg(cl_hw, agg_idx, tx_queue->hw_index,
+                                            tx_queue->cl_sta, tx_queue->tid);
+
+       spin_unlock_bh(&cl_hw->tx_lock_cfm_agg);
+}
+
+void cl_agg_cfm_poll_empty(struct cl_hw *cl_hw, u8 agg_idx, bool flush)
+{
+       struct cl_agg_cfm_queue *cfm_queue = &cl_hw->agg_cfm_queues[agg_idx];
+       bool empty = false;
+       int i = 0;
+
+       if (test_bit(CL_DEV_FW_ERROR, &cl_hw->drv_flags))
+               return;
+
+       while (true) {
+               spin_lock_bh(&cl_hw->tx_lock_cfm_agg);
+               empty = list_empty(&cfm_queue->head);
+               spin_unlock_bh(&cl_hw->tx_lock_cfm_agg);
+
+               if (empty)
+                       return;
+
+               if (++i == AGG_POLL_TIMEOUT) {
+                       cl_agg_cfm_poll_timeout(cl_hw, cfm_queue->tx_queue, agg_idx, flush);
+                       return;
+               }
+
+               msleep(20);
+       }
+}
+
+void cl_agg_cfm_poll_empty_sta(struct cl_hw *cl_hw, struct cl_sta *cl_sta)
+{
+       int i = 0;
+       struct cl_tx_queue *tx_queue = NULL;
+
+       for (i = 0; i < IEEE80211_NUM_TIDS; i++) {
+               tx_queue = cl_sta->agg_tx_queues[i];
+
+               if (tx_queue)
+                       cl_agg_cfm_poll_empty(cl_hw, tx_queue->index, false);
+       }
+}
+
+void cl_agg_cfm_set_ssn(struct cl_hw *cl_hw, u16 ssn, u8 idx)
+{
+       spin_lock_bh(&cl_hw->tx_lock_cfm_agg);
+       cl_hw->agg_cfm_queues[idx].ssn = ssn;
+       spin_unlock_bh(&cl_hw->tx_lock_cfm_agg);
+}
+
+void cl_agg_cfm_set_tx_queue(struct cl_hw *cl_hw, struct cl_tx_queue *tx_queue, u8 idx)
+{
+       spin_lock_bh(&cl_hw->tx_lock_cfm_agg);
+       cl_hw->agg_cfm_queues[idx].tx_queue = tx_queue;
+       spin_unlock_bh(&cl_hw->tx_lock_cfm_agg);
+}
--
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.
________________________________


^ permalink raw reply related	[flat|nested] 262+ messages in thread

* [RFC v1 201/256] cl8k: add tx/agg_cfm.h
  2021-06-17 15:58 [RFC v1 000/256] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (199 preceding siblings ...)
  2021-06-17 16:01 ` [RFC v1 200/256] cl8k: add tx/agg_cfm.c viktor.barna
@ 2021-06-17 16:01 ` viktor.barna
  2021-06-17 16:01 ` [RFC v1 202/256] cl8k: add tx/agg_tx_report.c viktor.barna
                   ` (56 subsequent siblings)
  257 siblings, 0 replies; 262+ messages in thread
From: viktor.barna @ 2021-06-17 16:01 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Oleksandr Savchenko, Shay Bar, Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

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

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 drivers/net/wireless/celeno/cl8k/tx/agg_cfm.h | 21 +++++++++++++++++++
 1 file changed, 21 insertions(+)
 create mode 100644 drivers/net/wireless/celeno/cl8k/tx/agg_cfm.h

diff --git a/drivers/net/wireless/celeno/cl8k/tx/agg_cfm.h b/drivers/net/wireless/celeno/cl8k/tx/agg_cfm.h
new file mode 100644
index 000000000000..d998e7fa4415
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/tx/agg_cfm.h
@@ -0,0 +1,21 @@
+/* SPDX-License-Identifier: MIT */
+/* Copyright(c) 2019-2021, Celeno Communications Ltd. */
+
+#ifndef CL_AGG_CFM_H
+#define CL_AGG_CFM_H
+
+#include "tx/tx_queue.h"
+#include "ipc_shared.h"
+
+void cl_agg_cfm_init(struct cl_hw *cl_hw);
+void cl_agg_cfm_add(struct cl_hw *cl_hw, struct cl_sw_txhdr *sw_txhdr, u8 agg_idx);
+void cl_agg_cfm_free_head_skb(struct cl_hw *cl_hw,
+                             struct cl_agg_cfm_queue *cfm_queue,
+                             u8 ba_queue_idx);
+void cl_agg_cfm_flush_all(struct cl_hw *cl_hw);
+void cl_agg_cfm_poll_empty(struct cl_hw *cl_hw, u8 agg_idx, bool flush);
+void cl_agg_cfm_poll_empty_sta(struct cl_hw *cl_hw, struct cl_sta *cl_sta);
+void cl_agg_cfm_set_ssn(struct cl_hw *cl_hw, u16 ssn, u8 idx);
+void cl_agg_cfm_set_tx_queue(struct cl_hw *cl_hw, struct cl_tx_queue *tx_queue, u8 idx);
+
+#endif /* CL_AGG_CFM_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.
________________________________


^ permalink raw reply related	[flat|nested] 262+ messages in thread

* [RFC v1 202/256] cl8k: add tx/agg_tx_report.c
  2021-06-17 15:58 [RFC v1 000/256] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (200 preceding siblings ...)
  2021-06-17 16:01 ` [RFC v1 201/256] cl8k: add tx/agg_cfm.h viktor.barna
@ 2021-06-17 16:01 ` viktor.barna
  2021-06-17 16:01 ` [RFC v1 203/256] cl8k: add tx/agg_tx_report.h viktor.barna
                   ` (55 subsequent siblings)
  257 siblings, 0 replies; 262+ messages in thread
From: viktor.barna @ 2021-06-17 16:01 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Oleksandr Savchenko, Shay Bar, Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

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

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 .../wireless/celeno/cl8k/tx/agg_tx_report.c   | 196 ++++++++++++++++++
 1 file changed, 196 insertions(+)
 create mode 100644 drivers/net/wireless/celeno/cl8k/tx/agg_tx_report.c

diff --git a/drivers/net/wireless/celeno/cl8k/tx/agg_tx_report.c b/drivers/net/wireless/celeno/cl8k/tx/agg_tx_report.c
new file mode 100644
index 000000000000..478e5e734f08
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/tx/agg_tx_report.c
@@ -0,0 +1,196 @@
+// SPDX-License-Identifier: MIT
+/* Copyright(c) 2019-2021, Celeno Communications Ltd. */
+
+#include "tx/agg_tx_report.h"
+#include "stats.h"
+#include "rate_ctrl.h"
+#include "wrs/wrs_api.h"
+#include "data_rates.h"
+
+static bool is_same_rate(struct cl_agg_tx_report *agg_report, struct cl_wrs_tx_params *tx_params)
+{
+       union cl_rate_ctrl_info rate_ctrl_info = {.word = agg_report->rate_cntrl_info};
+       u8 mcs = U8_MAX, nss = U8_MAX;
+
+       if (agg_report->bw_requested != tx_params->bw ||
+           rate_ctrl_info.field.gi != tx_params->gi)
+               return false;
+
+       cl_rate_ctrl_parse(&rate_ctrl_info, &nss, &mcs);
+
+       return ((mcs == tx_params->mcs) && (nss == tx_params->nss));
+}
+
+static void sync_tx_rate(struct cl_hw *cl_hw, struct cl_sta *cl_sta,
+                        struct cl_agg_tx_report *agg_report,
+                        struct cl_wrs_info *wrs_info, struct cl_wrs_params *wrs_params)
+{
+       if (!agg_report->is_fallback && is_same_rate(agg_report, &wrs_params->tx_params)) {
+               cl_wrs_api_rate_sync(cl_hw, cl_sta, wrs_params);
+
+               wrs_info->synced = true;
+               wrs_info->quick_rate_check = true;
+               wrs_info->quick_rate_agg_cntr = 0;
+               wrs_info->quick_rate_pkt_cntr = 0;
+       } else {
+               wrs_info->sync_attempts++;
+       }
+}
+
+static void ba_not_received_handler(struct cl_hw *cl_hw, struct cl_wrs_info *wrs_info,
+                                   struct cl_agg_tx_report *agg_report)
+{
+       /* Ignore 'BA not received' if station is in power-save or if RTS limit was reached */
+       if (agg_report->is_sta_ps || agg_report->is_rts_retry_limit_reached)
+               return;
+
+       /* Count number of consecutive 'BA not received' */
+       wrs_info->ba_not_rcv_consecutive++;
+
+       /* Save longest sequence of consecutive 'BA not received' */
+       if (wrs_info->ba_not_rcv_consecutive > wrs_info->ba_not_rcv_consecutive_max)
+               wrs_info->ba_not_rcv_consecutive_max = wrs_info->ba_not_rcv_consecutive;
+
+       if (cl_hw->wrs_db.ba_not_rcv_collision_filter) {
+               /*
+                * First 'BA not received' - might just be a collision.
+                * Don't add fail to ba_not_rcv but keep aside.
+                * Second consecutive 'BA not received' - not likely to be a collisions.
+                * Add fail to ba_not_rcv including previous fail that was kept aside.
+                * More than two consecutive 'BA not received' - very unlikely to be a collisions.
+                * Add fail to ba_not_rcv.
+                */
+               if (wrs_info->ba_not_rcv_consecutive == 1)
+                       wrs_info->tx_fail_prev = agg_report->fail;
+               else if (wrs_info->ba_not_rcv_consecutive == 2)
+                       wrs_info->ba_not_rcv += (agg_report->fail + wrs_info->tx_fail_prev);
+               else
+                       wrs_info->ba_not_rcv += agg_report->fail;
+       } else {
+               wrs_info->ba_not_rcv += agg_report->fail;
+       }
+}
+
+void cl_agg_tx_report_handler(struct cl_hw *cl_hw, struct cl_sta *cl_sta,
+                             struct cl_agg_tx_report *agg_report)
+{
+       struct cl_wrs_info *wrs_info = &cl_sta->wrs_info;
+       struct cl_wrs_params *wrs_params = &cl_sta->wrs_sta.su_params;
+       bool skip_epr_update = false;
+       union cl_rate_ctrl_info rate_ctrl_info = {.word = agg_report->rate_cntrl_info};
+
+       /* Retry_count for cl_wlan */
+       cl_sta->retry_count += agg_report->success_after_retry;
+
+       /*
+        * In case of big packets (4300 in VHT and 5400 in HE) and low
+        * rate (BW 20, NSS 1, MCS 0), firmware will increase rate to MCS 1,
+        * and give an indication to driver (set rate_fix_mcs1 in cl_agg_tx_report).
+        * WRS should also move to MCS 1, and give the maximum time
+        * penalty time from MCS 0 toMCS 1.
+        */
+       if (agg_report->rate_fix_mcs1 && !agg_report->is_fallback)
+               if (cl_wrs_api_up_mcs1(cl_hw, cl_sta, wrs_params))
+                       return;
+
+       /* WRS sync mechanism */
+       if (!wrs_info->synced)
+               sync_tx_rate(cl_hw, cl_sta, agg_report, wrs_info, wrs_params);
+
+       if (agg_report->bf && cl_sta->bf_db.is_on && !cl_sta->bf_db.synced) {
+               cl_sta->bf_db.synced = true;
+               /* Resetting the WRS UP weights */
+               cl_wrs_api_beamforming_sync(cl_hw, cl_sta);
+       }
+
+       if (agg_report->ba_not_received) {
+               ba_not_received_handler(cl_hw, wrs_info, agg_report);
+       } else {
+               if (!skip_epr_update)
+                       wrs_info->tx_fail += agg_report->fail;
+
+               wrs_info->ba_not_rcv_consecutive = 0;
+       }
+
+       if (!skip_epr_update) {
+               u8 mcs = 0, nss = 0, bw = 0;
+               u16 data_rate = 0;
+
+               switch (agg_report->bw_requested) {
+               case CHNL_BW_160:
+                       bw = (cl_hw->wrs_db.adjacent_interference20 ||
+                             cl_hw->wrs_db.adjacent_interference40 ||
+                             cl_hw->wrs_db.adjacent_interference80) ?
+                               rate_ctrl_info.field.bw : agg_report->bw_requested;
+                       break;
+               case CHNL_BW_80:
+                       bw = (cl_hw->wrs_db.adjacent_interference20 ||
+                             cl_hw->wrs_db.adjacent_interference40) ?
+                               rate_ctrl_info.field.bw : agg_report->bw_requested;
+                       break;
+               case CHNL_BW_40:
+                       bw = cl_hw->wrs_db.adjacent_interference20 ?
+                               rate_ctrl_info.field.bw : agg_report->bw_requested;
+                       break;
+               case CHNL_BW_20:
+                       bw = agg_report->bw_requested;
+                       break;
+               }
+
+               cl_rate_ctrl_parse(&rate_ctrl_info, &nss, &mcs);
+
+               data_rate = cl_data_rates_get_x10(rate_ctrl_info.field.format_mod,
+                                                 bw,
+                                                 nss,
+                                                 mcs,
+                                                 rate_ctrl_info.field.gi);
+
+               wrs_info->epr_acc += ((u64)agg_report->success * data_rate);
+               wrs_info->tx_success += agg_report->success;
+       }
+
+       if (cl_hw->wrs_db.quick_down_en && wrs_info->quick_rate_check) {
+               if (is_same_rate(agg_report, &wrs_params->tx_params)) {
+                       wrs_info->quick_rate_agg_cntr++;
+                       wrs_info->quick_rate_pkt_cntr += (agg_report->success + agg_report->fail);
+
+                       if (wrs_info->quick_rate_agg_cntr >= cl_hw->wrs_db.quick_down_agg_thr &&
+                           wrs_info->quick_rate_pkt_cntr > cl_hw->wrs_db.quick_down_pkt_thr) {
+                               wrs_info->quick_rate_check = false;
+                               cl_wrs_api_quick_down_check(cl_hw, cl_sta, wrs_params);
+                       }
+               }
+       }
+}
+
+void cl_agg_tx_report_simulate_for_single(struct cl_hw *cl_hw, struct cl_sta *cl_sta,
+                                         struct cl_hw_tx_status *status)
+{
+       /* Assign statistics struct */
+       struct cl_agg_tx_report agg_report;
+       union cl_rate_ctrl_info rate_ctrl_info;
+
+       memset(&agg_report, 0, sizeof(struct cl_agg_tx_report));
+
+       agg_report.bf = status->bf;
+       agg_report.success = status->frm_successful;
+       agg_report.fail = status->num_mpdu_retries + (status->frm_successful ? 0 : 1);
+       agg_report.success_after_retry =
+               (status->frm_successful && status->num_mpdu_retries) ? 1 : 0;
+       agg_report.retry_limit_reached = !status->frm_successful ? 1 : 0;
+       agg_report.success_more_one_retry =
+               (status->frm_successful && (status->num_mpdu_retries > 1)) ? 1 : 0;
+       agg_report.sta_idx = cl_sta->sta_idx;
+       agg_report.bw_requested = status->bw_requested;
+
+       rate_ctrl_info.field.bw = status->bw_transmitted;
+       rate_ctrl_info.field.gi = status->gi;
+       rate_ctrl_info.field.format_mod = status->format_mod;
+       rate_ctrl_info.field.mcs_index = status->mcs_index;
+
+       cl_rate_ctrl_convert(&rate_ctrl_info);
+
+       agg_report.rate_cntrl_info = rate_ctrl_info.word;
+       cl_agg_tx_report_handler(cl_hw, cl_sta, &agg_report);
+       cl_stats_update_tx_single(cl_hw, cl_sta, &agg_report);
+}
--
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.
________________________________


^ permalink raw reply related	[flat|nested] 262+ messages in thread

* [RFC v1 203/256] cl8k: add tx/agg_tx_report.h
  2021-06-17 15:58 [RFC v1 000/256] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (201 preceding siblings ...)
  2021-06-17 16:01 ` [RFC v1 202/256] cl8k: add tx/agg_tx_report.c viktor.barna
@ 2021-06-17 16:01 ` viktor.barna
  2021-06-17 16:01 ` [RFC v1 204/256] cl8k: add tx/baw.c viktor.barna
                   ` (54 subsequent siblings)
  257 siblings, 0 replies; 262+ messages in thread
From: viktor.barna @ 2021-06-17 16:01 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Oleksandr Savchenko, Shay Bar, Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

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

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 .../wireless/celeno/cl8k/tx/agg_tx_report.h   | 92 +++++++++++++++++++
 1 file changed, 92 insertions(+)
 create mode 100644 drivers/net/wireless/celeno/cl8k/tx/agg_tx_report.h

diff --git a/drivers/net/wireless/celeno/cl8k/tx/agg_tx_report.h b/drivers/net/wireless/celeno/cl8k/tx/agg_tx_report.h
new file mode 100644
index 000000000000..def24d2accd8
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/tx/agg_tx_report.h
@@ -0,0 +1,92 @@
+/* SPDX-License-Identifier: MIT */
+/* Copyright(c) 2019-2021, Celeno Communications Ltd. */
+
+#ifndef CL_AGG_TX_REPORT_H
+#define CL_AGG_TX_REPORT_H
+
+#include "tx/tx.h"
+
+/* Structure containing the parameters of the MM_AGG_TX_REPORT_IND message. */
+struct cl_agg_tx_report {
+       u32 rate_cntrl_info;
+       u32 rate_cntrl_info_he;
+
+#if defined(__LITTLE_ENDIAN_BITFIELD)
+       u32 sta_idx                    : 8,
+           is_sta_ps                  : 1,
+           bw_requested               : 2,
+           is_agg                     : 1,
+           ba_not_received            : 1,
+           ba_received_empty          : 1,
+           bf                         : 1,
+           is_fallback                : 1,
+           mu_su_gid                  : 6,
+           mu_mimo_valid              : 1,
+           mu_ofdma_valid             : 1,
+           rate_fix_mcs1              : 1,
+           rsv0                       : 7;
+
+       u32 success                    : 9,
+           fail                       : 9,
+           below_baw_cnt              : 9,
+           num_prot_retries           : 5;
+
+       u32 success_after_retry        : 9,
+           success_more_one_retry     : 9,
+           retry_limit_reached        : 9,
+           is_retry                   : 1,
+           is_rts_retry_limit_reached : 1,
+           prot_type                  : 3;
+
+       u32 rssi1                      : 8,
+           rssi2                      : 8,
+           rssi3                      : 8,
+           rssi4                      : 8;
+
+       u32 rssi5                      : 8,
+           rssi6                      : 8,
+           rsv1                       : 16;
+#else
+       u32 rsv0                       : 7,
+           rate_fix_mcs1              : 1,
+           mu_ofdma_valid             : 1,
+           mu_mimo_valid              : 1,
+           mu_su_gid                  : 6,
+           is_fallback                : 1,
+           bf                         : 1,
+           ba_received_empty          : 1,
+           ba_not_received            : 1,
+           is_agg                     : 1,
+           bw_requested               : 2,
+           is_sta_ps                  : 1,
+           sta_idx                    : 8;
+
+       u32 num_prot_retries           : 5,
+           below_baw_cnt              : 9,
+           fail                       : 9,
+           success                    : 9;
+
+       u32 prot_type                  : 3,
+           is_rts_retry_limit_reached : 1,
+           is_retry                   : 1,
+           retry_limit_reached        : 9,
+           success_more_one_retry     : 9,
+           success_after_retry        : 9;
+
+       u32 rssi4                      : 8,
+           rssi3                      : 8,
+           rssi2                      : 8,
+           rssi1                      : 8;
+
+       u32 rsv1                       : 16,
+           rssi6                      : 8,
+           rssi5                      : 8;
+#endif
+};
+
+void cl_agg_tx_report_handler(struct cl_hw *cl_hw, struct cl_sta *cl_sta,
+                             struct cl_agg_tx_report *agg_report);
+void cl_agg_tx_report_simulate_for_single(struct cl_hw *cl_hw, struct cl_sta *cl_sta,
+                                         struct cl_hw_tx_status *status);
+
+#endif /* CL_AGG_TX_REPORT_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.
________________________________


^ permalink raw reply related	[flat|nested] 262+ messages in thread

* [RFC v1 204/256] cl8k: add tx/baw.c
  2021-06-17 15:58 [RFC v1 000/256] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (202 preceding siblings ...)
  2021-06-17 16:01 ` [RFC v1 203/256] cl8k: add tx/agg_tx_report.h viktor.barna
@ 2021-06-17 16:01 ` viktor.barna
  2021-06-17 16:01 ` [RFC v1 205/256] cl8k: add tx/baw.h viktor.barna
                   ` (53 subsequent siblings)
  257 siblings, 0 replies; 262+ messages in thread
From: viktor.barna @ 2021-06-17 16:01 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Oleksandr Savchenko, Shay Bar, Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

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

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 drivers/net/wireless/celeno/cl8k/tx/baw.c | 74 +++++++++++++++++++++++
 1 file changed, 74 insertions(+)
 create mode 100644 drivers/net/wireless/celeno/cl8k/tx/baw.c

diff --git a/drivers/net/wireless/celeno/cl8k/tx/baw.c b/drivers/net/wireless/celeno/cl8k/tx/baw.c
new file mode 100644
index 000000000000..d6c11db6c1e9
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/tx/baw.c
@@ -0,0 +1,74 @@
+// SPDX-License-Identifier: MIT
+/* Copyright(c) 2019-2021, Celeno Communications Ltd. */
+
+#include "tx/baw.h"
+#include "tx/tx.h"
+
+void cl_baw_init(struct cl_sta *cl_sta)
+{
+       u8 tid;
+
+       for (tid = 0; tid < IEEE80211_NUM_TIDS; tid++)
+               __skb_queue_head_init(&cl_sta->baws[tid].pending);
+}
+
+void cl_baw_start(struct cl_baw *baw, u16 ssn)
+{
+       baw->ssn = ssn;
+       baw->action_start = true;
+}
+
+void cl_baw_operational(struct cl_hw *cl_hw, struct cl_baw *baw,
+                       u8 fw_agg_idx, bool amsdu_supported)
+{
+       baw->fw_agg_idx = fw_agg_idx;
+       baw->tid_seq = IEEE80211_SN_TO_SEQ(baw->ssn);
+       baw->action_start = false;
+       baw->amsdu = (cl_hw->txamsdu_en && amsdu_supported);
+}
+
+void cl_baw_stop(struct cl_baw *baw)
+{
+       baw->action_start = false;
+}
+
+void cl_baw_tx_inject(struct cl_hw *cl_hw,
+                     struct cl_baw *baw,
+                     u8 fw_agg_idx)
+{
+       baw->ssn = 0;
+       baw->fw_agg_idx = fw_agg_idx;
+       baw->tid_seq = IEEE80211_SN_TO_SEQ(0);
+       baw->amsdu = cl_hw->txamsdu_en;
+}
+
+void cl_baw_pending_to_agg(struct cl_hw *cl_hw,
+                          struct cl_sta *cl_sta,
+                          u8 tid)
+{
+       struct cl_baw *baw = &cl_sta->baws[tid];
+       struct sk_buff *skb;
+
+       while (!skb_queue_empty(&baw->pending)) {
+               skb = __skb_dequeue(&baw->pending);
+               cl_tx_fast_agg(cl_hw, cl_sta, skb, false);
+       }
+}
+
+void cl_baw_pending_to_single(struct cl_hw *cl_hw,
+                             struct cl_sta *cl_sta,
+                             struct cl_baw *baw)
+{
+       struct sk_buff *skb;
+
+       while (!skb_queue_empty(&baw->pending)) {
+               skb = __skb_dequeue(&baw->pending);
+               cl_tx_fast_single(cl_hw, cl_sta, skb, false);
+       }
+}
+
+void cl_baw_pending_purge(struct cl_baw *baw)
+{
+       if (!skb_queue_empty(&baw->pending))
+               __skb_queue_purge(&baw->pending);
+}
--
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.
________________________________


^ permalink raw reply related	[flat|nested] 262+ messages in thread

* [RFC v1 205/256] cl8k: add tx/baw.h
  2021-06-17 15:58 [RFC v1 000/256] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (203 preceding siblings ...)
  2021-06-17 16:01 ` [RFC v1 204/256] cl8k: add tx/baw.c viktor.barna
@ 2021-06-17 16:01 ` viktor.barna
  2021-06-17 16:01 ` [RFC v1 206/256] cl8k: add tx/bcmc_cfm.c viktor.barna
                   ` (52 subsequent siblings)
  257 siblings, 0 replies; 262+ messages in thread
From: viktor.barna @ 2021-06-17 16:01 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Oleksandr Savchenko, Shay Bar, Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

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

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 drivers/net/wireless/celeno/cl8k/tx/baw.h | 26 +++++++++++++++++++++++
 1 file changed, 26 insertions(+)
 create mode 100644 drivers/net/wireless/celeno/cl8k/tx/baw.h

diff --git a/drivers/net/wireless/celeno/cl8k/tx/baw.h b/drivers/net/wireless/celeno/cl8k/tx/baw.h
new file mode 100644
index 000000000000..448fea76422a
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/tx/baw.h
@@ -0,0 +1,26 @@
+/* SPDX-License-Identifier: MIT */
+/* Copyright(c) 2019-2021, Celeno Communications Ltd. */
+
+#ifndef CL_BAW_H
+#define CL_BAW_H
+
+#include "hw.h"
+#include "sta.h"
+
+void cl_baw_init(struct cl_sta *cl_sta);
+void cl_baw_start(struct cl_baw *baw, u16 ssn);
+void cl_baw_operational(struct cl_hw *cl_hw, struct cl_baw *baw,
+                       u8 fw_agg_idx, bool amsdu_supported);
+void cl_baw_stop(struct cl_baw *baw);
+void cl_baw_tx_inject(struct cl_hw *cl_hw,
+                     struct cl_baw *baw,
+                     u8 fw_agg_idx);
+void cl_baw_pending_to_agg(struct cl_hw *cl_hw,
+                          struct cl_sta *cl_sta,
+                          u8 tid);
+void cl_baw_pending_to_single(struct cl_hw *cl_hw,
+                             struct cl_sta *cl_sta,
+                             struct cl_baw *baw);
+void cl_baw_pending_purge(struct cl_baw *baw);
+
+#endif /* CL_BAW_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.
________________________________


^ permalink raw reply related	[flat|nested] 262+ messages in thread

* [RFC v1 206/256] cl8k: add tx/bcmc_cfm.c
  2021-06-17 15:58 [RFC v1 000/256] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (204 preceding siblings ...)
  2021-06-17 16:01 ` [RFC v1 205/256] cl8k: add tx/baw.h viktor.barna
@ 2021-06-17 16:01 ` viktor.barna
  2021-06-17 16:01 ` [RFC v1 207/256] cl8k: add tx/bcmc_cfm.h viktor.barna
                   ` (51 subsequent siblings)
  257 siblings, 0 replies; 262+ messages in thread
From: viktor.barna @ 2021-06-17 16:01 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Oleksandr Savchenko, Shay Bar, Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

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

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 .../net/wireless/celeno/cl8k/tx/bcmc_cfm.c    | 64 +++++++++++++++++++
 1 file changed, 64 insertions(+)
 create mode 100644 drivers/net/wireless/celeno/cl8k/tx/bcmc_cfm.c

diff --git a/drivers/net/wireless/celeno/cl8k/tx/bcmc_cfm.c b/drivers/net/wireless/celeno/cl8k/tx/bcmc_cfm.c
new file mode 100644
index 000000000000..bc4bbdf40f54
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/tx/bcmc_cfm.c
@@ -0,0 +1,64 @@
+// SPDX-License-Identifier: MIT
+/* Copyright(c) 2019-2021, Celeno Communications Ltd. */
+
+#include "tx/bcmc_cfm.h"
+#include "chip.h"
+#include "tx/sw_txhdr.h"
+
+/*
+ * cl_hw->bcmc_cfm_queue:
+ * This queue is used to keep pointers to already sent
+ * beacon skb's that are waiting for confirmation.
+ */
+
+void cl_bcmc_cfm_init(struct cl_hw *cl_hw)
+{
+       INIT_LIST_HEAD(&cl_hw->bcmc_cfm_queue.head);
+}
+
+void cl_bcmc_cfm_add(struct cl_hw *cl_hw, struct cl_sw_txhdr *sw_txhdr)
+{
+       list_add_tail(&sw_txhdr->cfm_list, &cl_hw->bcmc_cfm_queue.head);
+}
+
+struct cl_sw_txhdr *cl_bcmc_cfm_find(struct cl_hw *cl_hw, dma_addr_t dma_addr, bool keep_in_list)
+{
+       struct cl_single_cfm_queue *cfm_queue = &cl_hw->bcmc_cfm_queue;
+       struct cl_sw_txhdr *sw_txhdr = NULL;
+       struct cl_sw_txhdr *tmp = NULL;
+
+       list_for_each_entry_safe(sw_txhdr, tmp, &cfm_queue->head, cfm_list) {
+               if (le32_to_cpu(sw_txhdr->txdesc.umacdesc.packet_addr[0]) == dma_addr) {
+                       if (!keep_in_list)
+                               list_del(&sw_txhdr->cfm_list);
+
+                       return sw_txhdr;
+               }
+       }
+
+       return NULL;
+}
+
+void cl_bcmc_cfm_flush_queue(struct cl_hw *cl_hw)
+{
+       struct cl_single_cfm_queue *cfm_queue = &cl_hw->bcmc_cfm_queue;
+       struct cl_sw_txhdr *sw_txhdr = NULL;
+       struct sk_buff *skb = NULL;
+       struct ieee80211_tx_info *tx_info = NULL;
+       dma_addr_t dma_addr;
+
+       while (!list_empty(&cfm_queue->head)) {
+               sw_txhdr = list_first_entry(&cfm_queue->head, struct cl_sw_txhdr, cfm_list);
+               dma_addr = le32_to_cpu(sw_txhdr->txdesc.umacdesc.packet_addr[0]);
+               skb = sw_txhdr->skb;
+               tx_info = IEEE80211_SKB_CB(skb);
+
+               dma_unmap_single(cl_hw->chip->dev, dma_addr, sw_txhdr->map_len, DMA_TO_DEVICE);
+               dev_kfree_skb_irq(skb);
+               list_del(&sw_txhdr->cfm_list);
+               cl_sw_txhdr_free(cl_hw, sw_txhdr);
+       }
+
+       /* Set fw_free_space back to maximum after flushing the queue */
+       cl_hw->tx_queues.bcmc.fw_free_space = cl_hw->tx_queues.bcmc.fw_max_size;
+}
--
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.
________________________________


^ permalink raw reply related	[flat|nested] 262+ messages in thread

* [RFC v1 207/256] cl8k: add tx/bcmc_cfm.h
  2021-06-17 15:58 [RFC v1 000/256] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (205 preceding siblings ...)
  2021-06-17 16:01 ` [RFC v1 206/256] cl8k: add tx/bcmc_cfm.c viktor.barna
@ 2021-06-17 16:01 ` viktor.barna
  2021-06-17 16:01 ` [RFC v1 208/256] cl8k: add tx/single_cfm.c viktor.barna
                   ` (50 subsequent siblings)
  257 siblings, 0 replies; 262+ messages in thread
From: viktor.barna @ 2021-06-17 16:01 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Oleksandr Savchenko, Shay Bar, Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

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

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 drivers/net/wireless/celeno/cl8k/tx/bcmc_cfm.h | 14 ++++++++++++++
 1 file changed, 14 insertions(+)
 create mode 100644 drivers/net/wireless/celeno/cl8k/tx/bcmc_cfm.h

diff --git a/drivers/net/wireless/celeno/cl8k/tx/bcmc_cfm.h b/drivers/net/wireless/celeno/cl8k/tx/bcmc_cfm.h
new file mode 100644
index 000000000000..b30c96587191
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/tx/bcmc_cfm.h
@@ -0,0 +1,14 @@
+/* SPDX-License-Identifier: MIT */
+/* Copyright(c) 2019-2021, Celeno Communications Ltd. */
+
+#ifndef CL_BCMC_CFM_H
+#define CL_BCMC_CFM_H
+
+#include "tx/tx.h"
+
+void cl_bcmc_cfm_init(struct cl_hw *cl_hw);
+void cl_bcmc_cfm_add(struct cl_hw *cl_hw, struct cl_sw_txhdr *sw_txhdr);
+struct cl_sw_txhdr *cl_bcmc_cfm_find(struct cl_hw *cl_hw, dma_addr_t dma_addr, bool keep_in_list);
+void cl_bcmc_cfm_flush_queue(struct cl_hw *cl_hw);
+
+#endif /* CL_BCMC_CFM_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.
________________________________


^ permalink raw reply related	[flat|nested] 262+ messages in thread

* [RFC v1 208/256] cl8k: add tx/single_cfm.c
  2021-06-17 15:58 [RFC v1 000/256] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (206 preceding siblings ...)
  2021-06-17 16:01 ` [RFC v1 207/256] cl8k: add tx/bcmc_cfm.h viktor.barna
@ 2021-06-17 16:01 ` viktor.barna
  2021-06-17 16:01 ` [RFC v1 209/256] cl8k: add tx/single_cfm.h viktor.barna
                   ` (49 subsequent siblings)
  257 siblings, 0 replies; 262+ messages in thread
From: viktor.barna @ 2021-06-17 16:01 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Oleksandr Savchenko, Shay Bar, Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

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

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 .../net/wireless/celeno/cl8k/tx/single_cfm.c  | 214 ++++++++++++++++++
 1 file changed, 214 insertions(+)
 create mode 100644 drivers/net/wireless/celeno/cl8k/tx/single_cfm.c

diff --git a/drivers/net/wireless/celeno/cl8k/tx/single_cfm.c b/drivers/net/wireless/celeno/cl8k/tx/single_cfm.c
new file mode 100644
index 000000000000..d90148d3f9bf
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/tx/single_cfm.c
@@ -0,0 +1,214 @@
+// SPDX-License-Identifier: MIT
+/* Copyright(c) 2019-2021, Celeno Communications Ltd. */
+
+#include "tx/single_cfm.h"
+#include "tx/tx_queue.h"
+#include "tx/tx_inject.h"
+#include "chip.h"
+#include "tx/sw_txhdr.h"
+#include "enhanced_tim.h"
+
+/*
+ * cl_hw->single_cfm_queues:
+ * These queues are used to keep pointers to skb's sent
+ * as singles and waiting for confirmation.
+ */
+
+#define SINGLE_POLL_TIMEOUT 50
+
+void cl_single_cfm_init(struct cl_hw *cl_hw)
+{
+       int i = 0;
+
+       for (i = 0; i < MAX_SINGLE_QUEUES; i++)
+               INIT_LIST_HEAD(&cl_hw->single_cfm_queues[i].head);
+}
+
+void cl_single_cfm_add(struct cl_hw *cl_hw, struct cl_sw_txhdr *sw_txhdr, u32 queue_idx)
+{
+       list_add_tail(&sw_txhdr->cfm_list, &cl_hw->single_cfm_queues[queue_idx].head);
+}
+
+struct cl_sw_txhdr *cl_single_cfm_find(struct cl_hw *cl_hw, u32 queue_idx,
+                                      dma_addr_t dma_addr)
+{
+       struct cl_single_cfm_queue *cfm_queue = NULL;
+       struct cl_sw_txhdr *sw_txhdr = NULL;
+       struct cl_sw_txhdr *tmp = NULL;
+
+       if (queue_idx >= MAX_SINGLE_QUEUES)
+               return NULL;
+
+       cfm_queue = &cl_hw->single_cfm_queues[queue_idx];
+
+       list_for_each_entry_safe(sw_txhdr, tmp, &cfm_queue->head, cfm_list)
+               if (le32_to_cpu(sw_txhdr->txdesc.umacdesc.packet_addr[0]) == dma_addr) {
+                       list_del(&sw_txhdr->cfm_list);
+
+                       return sw_txhdr;
+               }
+
+       return NULL;
+}
+
+static void cl_single_cfm_flush_queue(struct cl_hw *cl_hw, u32 queue_idx)
+{
+       struct cl_single_cfm_queue *cfm_queue = &cl_hw->single_cfm_queues[queue_idx];
+       struct cl_tx_queue *tx_queue = NULL;
+       struct cl_sw_txhdr *sw_txhdr = NULL;
+       struct sk_buff *skb = NULL;
+       struct ieee80211_tx_info *tx_info = NULL;
+       dma_addr_t dma_addr;
+
+       if (list_empty(&cfm_queue->head))
+               return;
+
+       do {
+               sw_txhdr = list_first_entry(&cfm_queue->head, struct cl_sw_txhdr, cfm_list);
+               dma_addr = le32_to_cpu(sw_txhdr->txdesc.umacdesc.packet_addr[0]);
+               skb = sw_txhdr->skb;
+               tx_info = IEEE80211_SKB_CB(skb);
+
+               dma_unmap_single(cl_hw->chip->dev, dma_addr, sw_txhdr->map_len, DMA_TO_DEVICE);
+
+               if (cl_tx_ctrl_is_inject(tx_info))
+                       cl_tx_inject_cfm(cl_hw);
+
+               cl_tx_single_free_skb(cl_hw, skb);
+               list_del(&sw_txhdr->cfm_list);
+               cl_sw_txhdr_free(cl_hw, sw_txhdr);
+       } while (!list_empty(&cfm_queue->head));
+
+       /*
+        * Set fw_free_space back to maximum after flushing the queue
+        * and clear the enhanced TIM.
+        */
+       tx_queue = &cl_hw->tx_queues.single[queue_idx];
+       tx_queue->fw_free_space = tx_queue->fw_max_size;
+       cl_enhanced_tim_clear_tx_single(cl_hw, queue_idx, tx_queue->hw_index,
+                                       false, tx_queue->cl_sta, tx_queue->tid);
+}
+
+void cl_single_cfm_flush_all(struct cl_hw *cl_hw)
+{
+       u32 i = 0;
+
+       for (i = 0; i < MAX_SINGLE_QUEUES; i++)
+               cl_single_cfm_flush_queue(cl_hw, i);
+}
+
+void cl_single_cfm_flush_sta(struct cl_hw *cl_hw, u8 sta_idx)
+{
+       /* Flush all single confirmation queues of this sta, and reset write index */
+       u8 ac;
+       u16 queue_idx;
+
+       spin_lock_bh(&cl_hw->tx_lock_single);
+
+       for (ac = 0; ac < AC_MAX; ac++) {
+               queue_idx = QUEUE_IDX(sta_idx, ac);
+               cl_single_cfm_flush_queue(cl_hw, queue_idx);
+
+#ifdef CONFIG_CL_PCIE
+               cl_hw->ipc_env->ring_indices_elem->indices->txdesc_write_idx.single[queue_idx] = 0;
+#endif
+       }
+
+       spin_unlock_bh(&cl_hw->tx_lock_single);
+}
+
+static void cl_single_cfm_poll_timeout(struct cl_hw *cl_hw, u32 queue_idx)
+{
+       /*
+        * When polling failed clear the enhanced TIM so that firmware will
+        * not try to transmit these packets.
+        */
+       struct cl_tx_queue *tx_queue = &cl_hw->tx_queues.single[queue_idx];
+
+       cl_dbg_err(cl_hw, "Polling timeout (queue_idx = %u)\n", queue_idx);
+
+       spin_lock_bh(&cl_hw->tx_lock_single);
+       cl_enhanced_tim_clear_tx_single(cl_hw, queue_idx, tx_queue->hw_index,
+                                       false, tx_queue->cl_sta, tx_queue->tid);
+       spin_unlock_bh(&cl_hw->tx_lock_single);
+}
+
+void cl_single_cfm_poll_empty(struct cl_hw *cl_hw, u32 queue_idx)
+{
+       struct cl_single_cfm_queue *cfm_queue = &cl_hw->single_cfm_queues[queue_idx];
+       bool empty = false;
+       int i = 0;
+
+       if (test_bit(CL_DEV_FW_ERROR, &cl_hw->drv_flags))
+               return;
+
+       while (true) {
+               spin_lock_bh(&cl_hw->tx_lock_single);
+               empty = list_empty(&cfm_queue->head);
+               spin_unlock_bh(&cl_hw->tx_lock_single);
+
+               if (empty)
+                       return;
+
+               if (++i == SINGLE_POLL_TIMEOUT) {
+                       cl_single_cfm_poll_timeout(cl_hw, queue_idx);
+                       return;
+               }
+
+               msleep(20);
+       }
+}
+
+static bool list_hp_empty_sta(struct cl_hw *cl_hw, u8 sta_idx)
+{
+       struct cl_single_cfm_queue *hp_cfm_queue = &cl_hw->single_cfm_queues[HIGH_PRIORITY_QUEUE];
+       struct cl_sw_txhdr *sw_txhdr = NULL;
+
+       list_for_each_entry(sw_txhdr, &hp_cfm_queue->head, cfm_list)
+               if (sw_txhdr->sta_idx == sta_idx)
+                       return false;
+
+       return true;
+}
+
+static void cl_single_cfm_poll_empty_hp(struct cl_hw *cl_hw, u8 sta_idx)
+{
+       bool empty = false;
+       int i = 0;
+
+       if (test_bit(CL_DEV_FW_ERROR, &cl_hw->drv_flags))
+               return;
+
+       while (true) {
+               spin_lock_bh(&cl_hw->tx_lock_single);
+               empty = list_hp_empty_sta(cl_hw, sta_idx);
+               spin_unlock_bh(&cl_hw->tx_lock_single);
+
+               if (empty)
+                       return;
+
+               if (++i == SINGLE_POLL_TIMEOUT) {
+                       cl_single_cfm_poll_timeout(cl_hw, HIGH_PRIORITY_QUEUE);
+                       return;
+               }
+
+               msleep(20);
+       }
+}
+
+void cl_single_cfm_poll_empty_sta(struct cl_hw *cl_hw, u8 sta_idx)
+{
+       /*
+        * Poll all single queues belonging to this station, and poll all
+        * packets belonging to this station in the high priority queue.
+        */
+       u8 ac;
+       u16 queue_idx;
+
+       for (ac = 0; ac < AC_MAX; ac++) {
+               queue_idx = QUEUE_IDX(sta_idx, ac);
+               cl_single_cfm_poll_empty(cl_hw, queue_idx);
+       }
+
+       cl_single_cfm_poll_empty_hp(cl_hw, sta_idx);
+}
--
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.
________________________________


^ permalink raw reply related	[flat|nested] 262+ messages in thread

* [RFC v1 209/256] cl8k: add tx/single_cfm.h
  2021-06-17 15:58 [RFC v1 000/256] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (207 preceding siblings ...)
  2021-06-17 16:01 ` [RFC v1 208/256] cl8k: add tx/single_cfm.c viktor.barna
@ 2021-06-17 16:01 ` viktor.barna
  2021-06-17 16:01 ` [RFC v1 210/256] cl8k: add tx/sw_txhdr.c viktor.barna
                   ` (48 subsequent siblings)
  257 siblings, 0 replies; 262+ messages in thread
From: viktor.barna @ 2021-06-17 16:01 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Oleksandr Savchenko, Shay Bar, Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

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

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 .../net/wireless/celeno/cl8k/tx/single_cfm.h   | 18 ++++++++++++++++++
 1 file changed, 18 insertions(+)
 create mode 100644 drivers/net/wireless/celeno/cl8k/tx/single_cfm.h

diff --git a/drivers/net/wireless/celeno/cl8k/tx/single_cfm.h b/drivers/net/wireless/celeno/cl8k/tx/single_cfm.h
new file mode 100644
index 000000000000..f04b93a51ba5
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/tx/single_cfm.h
@@ -0,0 +1,18 @@
+/* SPDX-License-Identifier: MIT */
+/* Copyright(c) 2019-2021, Celeno Communications Ltd. */
+
+#ifndef CL_SINGLE_CFM_H
+#define CL_SINGLE_CFM_H
+
+#include "tx/tx.h"
+
+void cl_single_cfm_init(struct cl_hw *cl_hw);
+void cl_single_cfm_add(struct cl_hw *cl_hw, struct cl_sw_txhdr *sw_txhdr, u32 queue_idx);
+struct cl_sw_txhdr *cl_single_cfm_find(struct cl_hw *cl_hw, u32 queue_idx,
+                                      dma_addr_t dma_addr);
+void cl_single_cfm_flush_all(struct cl_hw *cl_hw);
+void cl_single_cfm_flush_sta(struct cl_hw *cl_hw, u8 sta_idx);
+void cl_single_cfm_poll_empty(struct cl_hw *cl_hw, u32 queue_idx);
+void cl_single_cfm_poll_empty_sta(struct cl_hw *cl_hw, u8 sta_idx);
+
+#endif /* CL_SINGLE_CFM_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.
________________________________


^ permalink raw reply related	[flat|nested] 262+ messages in thread

* [RFC v1 210/256] cl8k: add tx/sw_txhdr.c
  2021-06-17 15:58 [RFC v1 000/256] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (208 preceding siblings ...)
  2021-06-17 16:01 ` [RFC v1 209/256] cl8k: add tx/single_cfm.h viktor.barna
@ 2021-06-17 16:01 ` viktor.barna
  2021-06-17 16:01 ` [RFC v1 211/256] cl8k: add tx/sw_txhdr.h viktor.barna
                   ` (47 subsequent siblings)
  257 siblings, 0 replies; 262+ messages in thread
From: viktor.barna @ 2021-06-17 16:01 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Oleksandr Savchenko, Shay Bar, Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

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

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 .../net/wireless/celeno/cl8k/tx/sw_txhdr.c    | 40 +++++++++++++++++++
 1 file changed, 40 insertions(+)
 create mode 100644 drivers/net/wireless/celeno/cl8k/tx/sw_txhdr.c

diff --git a/drivers/net/wireless/celeno/cl8k/tx/sw_txhdr.c b/drivers/net/wireless/celeno/cl8k/tx/sw_txhdr.c
new file mode 100644
index 000000000000..3ba63ab9a335
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/tx/sw_txhdr.c
@@ -0,0 +1,40 @@
+// SPDX-License-Identifier: MIT
+/* Copyright(c) 2019-2021, Celeno Communications Ltd. */
+
+#include "tx/sw_txhdr.h"
+
+int cl_sw_txhdr_init(struct cl_hw *cl_hw)
+{
+       char sw_txhdr_cache_name[MODULE_NAME_LEN + 32] = {0};
+
+       snprintf(sw_txhdr_cache_name, sizeof(sw_txhdr_cache_name),
+                "%s_sw_txhdr_cache", THIS_MODULE->name);
+
+       cl_hw->sw_txhdr_cache = kmem_cache_create(sw_txhdr_cache_name,
+                                                 sizeof(struct cl_sw_txhdr),
+                                                 0,
+                                                 (SLAB_HWCACHE_ALIGN | SLAB_PANIC),
+                                                 NULL);
+
+       if (!cl_hw->sw_txhdr_cache) {
+               cl_dbg_verbose(cl_hw, "sw_txhdr_cache NULL\n");
+               return -1;
+       }
+
+       return 0;
+}
+
+void cl_sw_txhdr_deinit(struct cl_hw *cl_hw)
+{
+       kmem_cache_destroy(cl_hw->sw_txhdr_cache);
+}
+
+struct cl_sw_txhdr *cl_sw_txhdr_alloc(struct cl_hw *cl_hw)
+{
+       return kmem_cache_alloc(cl_hw->sw_txhdr_cache, GFP_ATOMIC);
+}
+
+void cl_sw_txhdr_free(struct cl_hw *cl_hw, struct cl_sw_txhdr *sw_txhdr)
+{
+       kmem_cache_free(cl_hw->sw_txhdr_cache, sw_txhdr);
+}
--
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.
________________________________


^ permalink raw reply related	[flat|nested] 262+ messages in thread

* [RFC v1 211/256] cl8k: add tx/sw_txhdr.h
  2021-06-17 15:58 [RFC v1 000/256] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (209 preceding siblings ...)
  2021-06-17 16:01 ` [RFC v1 210/256] cl8k: add tx/sw_txhdr.c viktor.barna
@ 2021-06-17 16:01 ` viktor.barna
  2021-06-17 16:01 ` [RFC v1 212/256] cl8k: add tx/tx.c viktor.barna
                   ` (46 subsequent siblings)
  257 siblings, 0 replies; 262+ messages in thread
From: viktor.barna @ 2021-06-17 16:01 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Oleksandr Savchenko, Shay Bar, Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

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

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 .../net/wireless/celeno/cl8k/tx/sw_txhdr.h    | 45 +++++++++++++++++++
 1 file changed, 45 insertions(+)
 create mode 100644 drivers/net/wireless/celeno/cl8k/tx/sw_txhdr.h

diff --git a/drivers/net/wireless/celeno/cl8k/tx/sw_txhdr.h b/drivers/net/wireless/celeno/cl8k/tx/sw_txhdr.h
new file mode 100644
index 000000000000..3374439b0de4
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/tx/sw_txhdr.h
@@ -0,0 +1,45 @@
+/* SPDX-License-Identifier: MIT */
+/* Copyright(c) 2019-2021, Celeno Communications Ltd. */
+
+#ifndef CL_SW_TXHDR_H
+#define CL_SW_TXHDR_H
+
+#include "utils/utils.h"
+#include "tx/tx_amsdu.h"
+
+struct cl_sw_txhdr {
+       struct list_head list_pool;
+       struct list_head tx_queue_list;
+       struct list_head cfm_list;
+       struct ieee80211_hdr *hdr80211;
+       struct cl_tx_queue *tx_queue;
+       struct cl_sta *cl_sta;
+       struct cl_vif *cl_vif;
+       struct cl_amsdu_txhdr amsdu_txhdr;
+       u8 hw_queue            : 3,
+          is_bcn              : 1,
+          tid                 : 4;
+       u8 ac                  : 2,
+          is_sw_amsdu         : 1,
+          sw_amsdu_packet_cnt : 4,
+          rsv                 : 1;
+       /*
+        * singles queue index used to push the txdesc to the ipc layer
+        * this issue solve race condition in which we
+        * CFM of packet that associated with disconnected STA and has invalid
+        * cl_sta pointerinside this struct
+        */
+       u8 sta_idx;
+       __le16 fc;
+       struct sk_buff *skb;
+       struct txdesc txdesc;
+       size_t map_len;
+       u16 total_pkt_len;
+};
+
+int cl_sw_txhdr_init(struct cl_hw *cl_hw);
+void cl_sw_txhdr_deinit(struct cl_hw *cl_hw);
+struct cl_sw_txhdr *cl_sw_txhdr_alloc(struct cl_hw *cl_hw);
+void cl_sw_txhdr_free(struct cl_hw *cl_hw, struct cl_sw_txhdr *sw_txhdr);
+
+#endif /* CL_SW_TXHDR_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.
________________________________


^ permalink raw reply related	[flat|nested] 262+ messages in thread

* [RFC v1 212/256] cl8k: add tx/tx.c
  2021-06-17 15:58 [RFC v1 000/256] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (210 preceding siblings ...)
  2021-06-17 16:01 ` [RFC v1 211/256] cl8k: add tx/sw_txhdr.h viktor.barna
@ 2021-06-17 16:01 ` viktor.barna
  2021-06-17 16:01 ` [RFC v1 213/256] cl8k: add tx/tx.h viktor.barna
                   ` (45 subsequent siblings)
  257 siblings, 0 replies; 262+ messages in thread
From: viktor.barna @ 2021-06-17 16:01 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Oleksandr Savchenko, Shay Bar, Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

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

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 drivers/net/wireless/celeno/cl8k/tx/tx.c | 1325 ++++++++++++++++++++++
 1 file changed, 1325 insertions(+)
 create mode 100644 drivers/net/wireless/celeno/cl8k/tx/tx.c

diff --git a/drivers/net/wireless/celeno/cl8k/tx/tx.c b/drivers/net/wireless/celeno/cl8k/tx/tx.c
new file mode 100644
index 000000000000..ccf81dbeb8ec
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/tx/tx.c
@@ -0,0 +1,1325 @@
+// SPDX-License-Identifier: MIT
+/* Copyright(c) 2019-2021, Celeno Communications Ltd. */
+
+#include "chip.h"
+#include "tx/tx.h"
+#include "tx/agg_cfm.h"
+#include "tx/single_cfm.h"
+#include "tx/bcmc_cfm.h"
+#include "tx/tx_queue.h"
+#include "stats.h"
+#include "fw/msg_tx.h"
+#include "rate_ctrl.h"
+#include "tx/tx_amsdu.h"
+#include "traffic.h"
+#include "dfs/dfs.h"
+#include "band.h"
+#include "vns.h"
+#include "utils/utils.h"
+#include "enhanced_tim.h"
+#include "mac_addr.h"
+#include "key.h"
+#include "utils/ip.h"
+#include "radio.h"
+#include "recovery.h"
+#include "ext/vlan_dscp.h"
+#include "wrs/wrs_api.h"
+#include "drv_ops.h"
+#ifdef TRACE_SUPPORT
+#include "trace.h"
+#endif
+
+/* Expected Acknowledgment */
+#define EXPECTED_NO_ACK 0
+#define EXPECTED_ACK    1
+
+const u8 dscp_to_up[TID_MAX] = {0, 8, 16, 24, 32, 40, 48, 56};
+
+static DEFINE_PER_CPU(struct tasklet_struct, tx_remote_tasklet[TCV_TOTAL]);
+
+static void cl_tx_remote_tasklet_sched(void *t)
+{
+       tasklet_schedule((struct tasklet_struct *)t);
+}
+
+static void cl_tx_remote_cpu(struct cl_hw *cl_hw, struct sk_buff *skb, int cpu)
+{
+       /* Move driver TX path to a different CPU */
+       struct tasklet_struct *t = &per_cpu(tx_remote_tasklet[cl_hw->idx], cpu);
+
+       skb_queue_tail(&cl_hw->tx_remote_queue, skb);
+
+       if (!test_bit(TASKLET_STATE_SCHED, &t->state))
+               smp_call_function_single(cpu, cl_tx_remote_tasklet_sched, t, 0);
+}
+
+static void cl_tx_remote_tasklet(unsigned long data)
+{
+       struct cl_hw *cl_hw = (struct cl_hw *)data;
+       struct sk_buff *skb = NULL;
+
+       while ((skb = skb_dequeue(&cl_hw->tx_remote_queue)))
+               __cl_tx_start(cl_hw, skb, skb->dev);
+}
+
+void cl_tx_init(struct cl_hw *cl_hw)
+{
+       int cpu = cl_hw->conf->ci_tx_remote_cpu;
+
+       skb_queue_head_init(&cl_hw->tx_remote_queue);
+
+       if (cpu >= 0)
+               tasklet_init(&per_cpu(tx_remote_tasklet[cl_hw->idx], cpu),
+                            cl_tx_remote_tasklet,
+                            (unsigned long)cl_hw);
+}
+
+static void cl_tx_stop_remote_cpu(struct cl_hw *cl_hw)
+{
+       int cpu = cl_hw->conf->ci_tx_remote_cpu;
+
+       if (cpu >= 0) {
+               tasklet_kill(&per_cpu(tx_remote_tasklet[cl_hw->idx], cpu));
+               skb_queue_purge(&cl_hw->tx_remote_queue);
+       }
+}
+
+static void cl_tx_cpu_single(struct cl_hw *cl_hw)
+{
+       u32 processor_id = smp_processor_id();
+
+       if (processor_id < CPU_MAX_NUM)
+               cl_hw->cpu_cntr.tx_single[processor_id]++;
+}
+
+static void cl_tx_cpu_agg(struct cl_hw *cl_hw)
+{
+       u32 processor_id = smp_processor_id();
+
+       if (processor_id < CPU_MAX_NUM)
+               cl_hw->cpu_cntr.tx_agg[processor_id]++;
+}
+
+static inline void cl_tx_update_stats(struct sk_buff *skb, struct cl_sta *cl_sta, u16 ac, u8 tid)
+{
+       struct sta_info *stainfo = cl_sta->stainfo;
+       struct net_device *dev = skb->dev;
+       struct pcpu_sw_netstats *tstats = this_cpu_ptr(dev->tstats);
+
+       u64_stats_update_begin(&tstats->syncp);
+       tstats->tx_packets++;
+       tstats->tx_bytes += skb->len;
+       u64_stats_update_end(&tstats->syncp);
+
+       stainfo->tx_stats.bytes[ac] += skb->len;
+       stainfo->tx_stats.packets[ac]++;
+       stainfo->tx_stats.msdu[tid]++;
+}
+
+static char cl_tx_ctrl_single_frame_type(__le16 fc)
+{
+       if (ieee80211_is_data_qos(fc))
+               return CL_TX_SINGLE_FRAME_TYPE_QOS_DATA;
+       else if (ieee80211_is_qos_nullfunc(fc))
+               return CL_TX_SINGLE_FRAME_TYPE_QOS_NULL;
+       else if (ieee80211_is_mgmt(fc))
+               return CL_TX_SINGLE_FRAME_TYPE_MANAGEMENT;
+       else
+               return CL_TX_SINGLE_FRAME_TYPE_OTHER;
+}
+
+static void cl_tx_single_prep(struct cl_hw *cl_hw, struct cl_sw_txhdr *sw_txhdr,
+                             u16 frame_len, u8 hdr_pads, bool is_vns)
+{
+       struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(sw_txhdr->skb);
+       struct ieee80211_key_conf *key_conf = tx_info->control.hw_key;
+       struct txdesc *txdesc = &sw_txhdr->txdesc;
+       struct tx_host_info *host_info = &txdesc->host_info;
+
+       /* Reset txdesc */
+       memset(txdesc, 0, sizeof(struct txdesc));
+
+       /* Vif_index must be filled in even without header conversion */
+       if (!cl_tx_ctrl_is_inject(tx_info)) {
+               struct cl_vif *cl_vif = (struct cl_vif *)tx_info->control.vif->drv_priv;
+
+               host_info->vif_index = cl_vif->vif_index;
+       }
+
+       if (hdr_pads)
+               host_info->host_padding |= BIT(0);
+
+       host_info->is_bcn = sw_txhdr->is_bcn;
+       host_info->expected_ack = (tx_info->flags & IEEE80211_TX_CTL_NO_ACK) ?
+               EXPECTED_NO_ACK : EXPECTED_ACK;
+
+       /* Beware when prot and sta is unknown */
+       if (key_conf) {
+               frame_len += key_conf->icv_len;
+               host_info->is_protected = true;
+               host_info->hw_key_idx = key_conf->hw_key_idx;
+       }
+
+       host_info->packet_cnt = 1;
+
+       txdesc->umacdesc.packet_len[0] = cpu_to_le16(frame_len);
+       txdesc->e2w_result.bcmc = (sw_txhdr->sta_idx == STA_IDX_INVALID);
+       txdesc->e2w_result.tid = sw_txhdr->tid;
+       txdesc->e2w_result.is_vns = is_vns;
+       txdesc->e2w_result.is_txinject = cl_tx_ctrl_is_inject(tx_info);
+       txdesc->e2w_result.single_type = cl_tx_ctrl_single_frame_type(sw_txhdr->fc);
+       txdesc->e2w_result.single_valid_sta__agg_e2w_tx_done = sw_txhdr->cl_sta ? 1 : 0;
+       txdesc->e2w_natt_param.sta_index = sw_txhdr->sta_idx;
+
+       /* Set rate control */
+       cl_rate_ctrl_update_desc_single(cl_hw, host_info, sw_txhdr);
+}
+
+static void cl_tx_sub_frame_set(struct cl_sta *cl_sta, u8 tid)
+{
+       struct cl_tx_queue *tx_queue = cl_sta->agg_tx_queues[tid];
+
+       if (tx_queue)
+               tx_queue->total_packets++;
+}
+
+static void cl_tx_send(struct cl_hw *cl_hw, struct cl_sw_txhdr *sw_txhdr,
+                      struct cl_amsdu_ctrl *amsdu_anchor)
+{
+       struct cl_tx_queue *tx_queue = sw_txhdr->tx_queue;
+
+       tx_queue->total_packets++;
+
+       if (cl_txq_is_fw_full(tx_queue)) {
+               /* If firmware is full push the packet to the queue */
+               cl_txq_push(cl_hw, sw_txhdr);
+       } else if (amsdu_anchor && amsdu_anchor->is_sw_amsdu) {
+               cl_txq_push(cl_hw, sw_txhdr);
+               tasklet_schedule(&cl_hw->tx_task);
+       } else if (!list_empty(&tx_queue->hdrs)) {
+               /*
+                * If queue in driver is not empty push the packet to the queue,
+                * and call cl_txq_sched() to transfer packets from the queue to firmware
+                */
+               cl_txq_push(cl_hw, sw_txhdr);
+               cl_txq_sched(cl_hw, tx_queue);
+       } else {
+               /* Push the packet directly to firmware */
+               cl_tx_push(cl_hw, sw_txhdr, tx_queue);
+       }
+}
+
+void cl_tx_push(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 ieee80211_key_conf *keyconf = tx_info->control.hw_key;
+       struct cl_sta *cl_sta = sw_txhdr->cl_sta;
+       struct cl_vif *cl_vif = sw_txhdr->cl_vif;
+       u8 tid = sw_txhdr->tid;
+       struct txdesc *txdesc = &sw_txhdr->txdesc;
+       struct tx_host_info *host_info = &txdesc->host_info;
+       struct cl_e2w_txhdr_param *e2w_txhdr_param = &txdesc->e2w_txhdr_param;
+       struct ieee80211_hdr *hdr80211 = sw_txhdr->hdr80211;
+       u8 queue_type = tx_queue->type;
+       bool is_mgmt = ieee80211_is_mgmt(sw_txhdr->fc);
+
+       if (cl_key_is_cipher_ccmp_gcmp(keyconf)) {
+               /*
+                * In case of CCMP or GCMP encryption we need to inc pn.
+                * In case of amsdu/header_conversion we need to pass it to firmware as well
+                */
+               u64 pn = atomic64_inc_return(&keyconf->tx_pn);
+
+               if (txdesc->e2w_natt_param.hdr_conv_enable) {
+                       memcpy(&e2w_txhdr_param->encrypt_pn, &pn, CL_CCMP_GCMP_PN_SIZE);
+               } else {
+                       u8 hdrlen = ieee80211_hdrlen(sw_txhdr->fc);
+
+                       cl_key_ccmp_gcmp_pn_to_hdr((u8 *)hdr80211 + hdrlen, pn, keyconf->keyidx);
+               }
+       }
+
+       if (queue_type == QUEUE_TYPE_AGG) {
+               struct cl_baw *baw = &cl_sta->baws[tid];
+               bool is_amsdu = cl_tx_ctrl_is_amsdu(tx_info);
+
+               if (is_amsdu) {
+                       struct cl_amsdu_ctrl *amsdu_anchor = &cl_sta->amsdu_anchor[tid];
+
+                       if (sw_txhdr->is_sw_amsdu) {
+                               u8 pkt_cnt = sw_txhdr->sw_amsdu_packet_cnt;
+
+                               if (pkt_cnt == 1)
+                                       cl_tx_amsdu_unset(sw_txhdr); /* Clear AMSDU bit. */
+
+                               if (hdr80211)
+                                       hdr80211->seq_ctrl = cpu_to_le16(baw->tid_seq);
+
+                               tx_queue->stats_sw_amsdu_cnt[pkt_cnt - 1]++;
+                       } else {
+                               u8 pkt_cnt = host_info->packet_cnt;
+
+                               if (pkt_cnt == 1)
+                                       cl_tx_amsdu_unset(sw_txhdr); /* Clear AMSDU bit. */
+
+                               tx_queue->stats_hw_amsdu_cnt[pkt_cnt - 1]++;
+                       }
+
+                       /* Reset anchor if needed */
+                       if (amsdu_anchor->sw_txhdr == sw_txhdr)
+                               cl_tx_amsdu_anchor_init(amsdu_anchor);
+               }
+
+               /* Update sequence number and increase it */
+               e2w_txhdr_param->seq_ctrl = cpu_to_le16(baw->tid_seq);
+               baw->tid_seq = INC_SN(baw->tid_seq);
+       } else {
+               /*
+                * Update sequence number and increase it
+                * Management sequence number is set by firmware.
+                */
+               if (!is_mgmt) {
+                       hdr80211->seq_ctrl |= cpu_to_le16(cl_vif->sequence_number);
+                       cl_vif->sequence_number = INC_SN(cl_vif->sequence_number);
+               }
+       }
+
+       cl_drv_ops_pkt_fw_send(cl_hw, sw_txhdr, tx_queue);
+}
+
+void cl_tx_single_free_skb(struct cl_hw *cl_hw, struct sk_buff *skb)
+{
+       if (IEEE80211_SKB_CB(skb)->ack_frame_id)
+               ieee80211_tx_status(cl_hw->hw, skb);
+       else
+               dev_kfree_skb_any(skb);
+}
+
+void cl_tx_single(struct cl_hw *cl_hw, struct cl_sta *cl_sta,
+                 struct sk_buff *skb, bool is_vns, bool lock)
+{
+       struct cl_tx_queue *tx_queue;
+       struct cl_sw_txhdr *sw_txhdr;
+       struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
+       struct cl_vif *cl_vif = (struct cl_vif *)tx_info->control.vif->drv_priv;
+       struct ieee80211_hdr *hdr80211 = (struct ieee80211_hdr *)skb->data;
+       u8 hdr_pads = CL_SKB_DATA_ALIGN_PADS(hdr80211);
+       __le16 fc = hdr80211->frame_control;
+       u16 frame_len = (u16)skb->len;
+       u8 tid = ieee80211_is_data_qos(fc) ? ieee80211_get_tid(hdr80211) : 0;
+       u8 ac = tid_to_ac[tid];
+       bool is_beacon = ieee80211_is_beacon(fc);
+
+       cl_tx_cpu_single(cl_hw);
+
+       if (unlikely(!test_bit(CL_DEV_STARTED, &cl_hw->drv_flags) ||
+                    test_bit(CL_DEV_FW_ERROR, &cl_hw->drv_flags))) {
+               cl_tx_single_free_skb(cl_hw, skb);
+               cl_hw->tx_packet_cntr.drop.dev_flags++;
+               return;
+       }
+
+       if (unlikely(!cl_vif->tx_en || cl_hw->tx_disable_flags)) {
+               cl_tx_single_free_skb(cl_hw, skb);
+               cl_hw->tx_packet_cntr.drop.tx_disable++;
+               return;
+       }
+
+       /* Check if packet length exceeds max size */
+       if (unlikely(frame_len > CL_TX_MAX_FRAME_LEN_SINGLE)) {
+               cl_tx_single_free_skb(cl_hw, skb);
+               cl_dbg_err(cl_hw, "frame_len (%u) exceeds max size\n", frame_len);
+               cl_hw->tx_packet_cntr.drop.length_limit++;
+               return;
+       }
+
+       if (cl_sta && cl_sta->key_disable) {
+               cl_tx_single_free_skb(cl_hw, skb);
+               cl_hw->tx_packet_cntr.drop.key_disable++;
+               return;
+       }
+
+       /* Allocate sw_txhdr */
+       sw_txhdr = cl_sw_txhdr_alloc(cl_hw);
+
+       if (unlikely(!sw_txhdr)) {
+               cl_tx_single_free_skb(cl_hw, skb);
+               cl_dbg_verbose(cl_hw, "sw_txhdr alloc failed\n");
+               cl_hw->tx_packet_cntr.drop.txhdr_alloc_fail++;
+               return;
+       }
+
+       /* Prepare sw_txhdr */
+       sw_txhdr->hdr80211 = hdr80211;
+       sw_txhdr->hw_queue = tx_info->hw_queue;
+       sw_txhdr->is_bcn = is_beacon;
+       sw_txhdr->skb = skb;
+       sw_txhdr->map_len = frame_len + hdr_pads;
+       sw_txhdr->fc = fc;
+       sw_txhdr->cl_vif = cl_vif;
+       sw_txhdr->tid = tid;
+       sw_txhdr->ac = ac;
+
+       if (cl_sta) {
+               sw_txhdr->cl_sta = cl_sta;
+               sw_txhdr->sta_idx = cl_sta->sta_idx;
+       } else {
+               sw_txhdr->cl_sta = NULL;
+               sw_txhdr->sta_idx = STA_IDX_INVALID;
+       }
+
+       /* Prepare txdesc */
+       cl_tx_single_prep(cl_hw, sw_txhdr, frame_len, hdr_pads, is_vns);
+
+       /*
+        * Fetch the driver queue.
+        * IEEE80211_TX_CTL_AMPDU is not set in tx_info->flags, otherwise cl_tx_agg()
+        * would have been called and not cl_tx_single().
+        * Therefore there is no need to check if tx_queue is NULL or if queue type
+        * is QUEUE_TYPE_AGG.
+        */
+       tx_queue = cl_txq_get(cl_hw, sw_txhdr);
+       sw_txhdr->tx_queue = tx_queue;
+
+       if (lock) {
+               if (tx_queue->type == QUEUE_TYPE_BCMC) {
+                       /*
+                        * There is no need to take spin_lock_irqsave() because bcmb queue
+                        * will be called only from interrupt context - cl_irq_status_tbtt().
+                        * All other broadcast/multicast packets are buffered in
+                        * ieee80211_tx_h_multicast_ps_buf() and will follow the beacon.
+                        */
+                       spin_lock(&cl_hw->tx_lock_bcmc);
+                       cl_tx_send(cl_hw, sw_txhdr, NULL);
+                       spin_unlock(&cl_hw->tx_lock_bcmc);
+               } else {
+                       spin_lock_bh(&cl_hw->tx_lock_single);
+                       cl_tx_send(cl_hw, sw_txhdr, NULL);
+                       spin_unlock_bh(&cl_hw->tx_lock_single);
+               }
+       } else {
+               cl_tx_send(cl_hw, sw_txhdr, NULL);
+       }
+}
+
+void cl_tx_fast_single(struct cl_hw *cl_hw, struct cl_sta *cl_sta,
+                      struct sk_buff *skb, bool lock)
+{
+       struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
+       u8 tid = skb->priority & IEEE80211_QOS_CTL_TID_MASK;
+
+       /* hw_key must be set before calling cl_tx_8023_to_wlan() */
+       tx_info->control.hw_key = cl_key_get(cl_sta);
+
+       /* Convert 802.3 to 802.11 header */
+       if (cl_tx_8023_to_wlan(cl_hw, skb, cl_sta, tid) == 0) {
+               bool is_vns = cl_vns_is_very_near(cl_hw, cl_sta, skb);
+               u8 ac = tid_to_ac[tid];
+
+               tx_info->hw_queue = ac;
+               tx_info->control.vif = cl_sta->cl_vif->vif;
+
+               cl_tx_update_stats(skb, cl_sta, ac, tid);
+
+               cl_hw->tx_packet_cntr.forward.drv_fast_single++;
+
+               cl_tx_single(cl_hw, cl_sta, skb, is_vns, lock);
+       }
+}
+
+void cl_tx_agg_prep(struct cl_hw *cl_hw, struct cl_sw_txhdr *sw_txhdr,
+                   u16 frame_len, u8 hdr_pads, bool hdr_conv)
+{
+       struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(sw_txhdr->skb);
+       struct ieee80211_key_conf *key_conf = tx_info->control.hw_key;
+       struct txdesc *txdesc = &sw_txhdr->txdesc;
+       struct lmacapi *umacdesc = &txdesc->umacdesc;
+       struct tx_host_info *host_info = &txdesc->host_info;
+       u16 qos_ctrl = sw_txhdr->tid;
+
+       /* Reset txdesc */
+       memset(txdesc, 0, sizeof(struct txdesc));
+
+       txdesc->e2w_result.tid = sw_txhdr->tid;
+       txdesc->e2w_result.is_txinject = cl_tx_ctrl_is_inject(tx_info);
+       txdesc->e2w_natt_param.sta_index = sw_txhdr->sta_idx;
+       txdesc->e2w_natt_param.ampdu = true;
+       txdesc->e2w_natt_param.hdr_conv_enable = hdr_conv;
+
+       if (hdr_conv) {
+               if (cl_tx_ctrl_is_amsdu(tx_info))
+                       qos_ctrl |= IEEE80211_QOS_CTL_A_MSDU_PRESENT;
+
+               txdesc->e2w_txhdr_param.frame_ctrl = cpu_to_le16(sw_txhdr->fc);
+               txdesc->e2w_txhdr_param.qos_ctrl = cpu_to_le16(qos_ctrl);
+       }
+
+       if (hdr_pads)
+               host_info->host_padding |= BIT(0);
+
+       /* Vif_index must be filled in even without header conversion */
+       host_info->vif_index = sw_txhdr->cl_sta->cl_vif->vif_index;
+
+       /* Set the expected_ack flag */
+       host_info->expected_ack = (tx_info->flags & IEEE80211_TX_CTL_NO_ACK) ?
+               EXPECTED_NO_ACK : EXPECTED_ACK;
+
+       if (key_conf) {
+               host_info->is_protected = true;
+               host_info->hw_key_idx = key_conf->hw_key_idx;
+
+               if (!hdr_conv)
+                       frame_len += key_conf->icv_len;
+       }
+
+       host_info->packet_cnt = 1;
+       umacdesc->packet_len[0] = cpu_to_le16(frame_len);
+
+       /* Set rate control */
+       cl_rate_ctrl_update_desc_agg(cl_hw, host_info);
+}
+
+static __le16 cl_tx_agg_frame_control(struct cl_vif *cl_vif,
+                                     struct ieee80211_key_conf *key_conf,
+                                     u8 *hdrlen)
+{
+       struct ieee80211_vif *vif = cl_vif->vif;
+       struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif);
+       enum nl80211_iftype type = vif->type;
+       __le16 fc = cpu_to_le16(IEEE80211_FTYPE_DATA | IEEE80211_STYPE_QOS_DATA);
+
+       if (type == NL80211_IFTYPE_AP) {
+               fc |= cpu_to_le16(IEEE80211_FCTL_FROMDS);
+               *hdrlen = 26;
+       } else if (type == NL80211_IFTYPE_STATION) {
+               fc |= cpu_to_le16(IEEE80211_FCTL_TODS);
+
+               if (sdata->u.mgd.use_4addr) {
+                       fc |= cpu_to_le16(IEEE80211_FCTL_FROMDS);
+                       *hdrlen = 32;
+               } else {
+                       *hdrlen = 26;
+               }
+       }
+
+       if (key_conf)
+               fc |= cpu_to_le16(IEEE80211_FCTL_PROTECTED);
+
+       return fc;
+}
+
+static void _cl_tx_agg(struct cl_hw *cl_hw, struct cl_sta *cl_sta,
+                      struct sk_buff *skb, bool hdr_conv)
+{
+       struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
+       struct ieee80211_key_conf *key_conf = tx_info->control.hw_key;
+       struct cl_sw_txhdr *sw_txhdr = NULL;
+       struct cl_tx_queue *tx_queue = NULL;
+       struct cl_vif *cl_vif = cl_sta->cl_vif;
+       u16 frame_len = (u16)skb->len;
+       u16 total_frame_len = 0;
+       u8 hdr_pads = CL_SKB_DATA_ALIGN_PADS(skb->data);
+       u8 is_amsdu = cl_tx_ctrl_is_amsdu(tx_info);
+       u8 tid = skb->priority & IEEE80211_QOS_CTL_TAG1D_MASK;
+       u8 ac = tid_to_ac[tid];
+       u8 hdrlen = 0;
+
+       cl_tx_cpu_agg(cl_hw);
+
+       if (unlikely(!test_bit(CL_DEV_STARTED, &cl_hw->drv_flags) ||
+                    test_bit(CL_DEV_FW_ERROR, &cl_hw->drv_flags))) {
+               kfree_skb(skb);
+               cl_hw->tx_packet_cntr.drop.dev_flags++;
+               return;
+       }
+
+       if (unlikely(!cl_vif->tx_en || cl_hw->tx_disable_flags)) {
+               kfree_skb(skb);
+               cl_hw->tx_packet_cntr.drop.tx_disable++;
+               return;
+       }
+
+       /* Check if packet length exceeds max size */
+       if (unlikely(frame_len > CL_TX_MAX_FRAME_LEN_AGG)) {
+               kfree_skb(skb);
+               cl_dbg_err(cl_hw, "frame_len exceeds max size %d\n", frame_len);
+               cl_hw->tx_packet_cntr.drop.length_limit++;
+               return;
+       }
+
+       if (cl_sta->key_disable) {
+               kfree_skb(skb);
+               cl_hw->tx_packet_cntr.drop.key_disable++;
+               return;
+       }
+
+       /* Check if amsdu is enable for current skb */
+       if (is_amsdu) {
+               enum cl_amsdu_result amsdu_res = cl_tx_amsdu_set(cl_hw, cl_sta, skb, tid);
+
+               switch (amsdu_res) {
+               case CL_AMSDU_SKIP:
+                       is_amsdu = false;
+                       tx_info->control.flags &= ~IEEE80211_TX_CTRL_AMSDU;
+               case CL_AMSDU_ANCHOR_SET:
+                       /*
+                        * If new anchor was set, or AMSDU is
+                        * skipped continue building sw_txhdr
+                        */
+                       break;
+               case CL_AMSDU_SUB_FRAME_SET:
+                       cl_tx_sub_frame_set(cl_sta, tid);
+                       fallthrough;
+               case CL_AMSDU_FAILED:
+               default:
+                       return;
+               }
+       } else {
+               /*
+                * If not amsdu & anchor exist. reset current anchor
+                * in order to avoid reordring packets.
+                */
+               if (cl_sta->amsdu_anchor[tid].sw_txhdr)
+                       cl_tx_amsdu_anchor_init(&cl_sta->amsdu_anchor[tid]);
+       }
+
+       /* Allocate sw_txhdr */
+       sw_txhdr = cl_sw_txhdr_alloc(cl_hw);
+       if (unlikely(!sw_txhdr)) {
+               kfree_skb(skb);
+               cl_dbg_err(cl_hw, "sw_txhdr alloc failed\n");
+               cl_hw->tx_packet_cntr.drop.txhdr_alloc_fail++;
+               return;
+       }
+
+       /* Fill sw_txhdr */
+       sw_txhdr->tid = tid;
+       sw_txhdr->ac = ac;
+       sw_txhdr->hw_queue = tx_info->hw_queue;
+       sw_txhdr->cl_sta = cl_sta;
+       sw_txhdr->sta_idx = cl_sta->sta_idx;
+       sw_txhdr->is_bcn = 0;
+       sw_txhdr->skb = skb;
+       sw_txhdr->map_len = frame_len + hdr_pads;
+       sw_txhdr->cl_vif = cl_vif;
+
+       if (cl_sta->amsdu_anchor[tid].is_sw_amsdu) {
+               sw_txhdr->is_sw_amsdu = true;
+               sw_txhdr->sw_amsdu_packet_cnt = 1;
+       } else {
+               sw_txhdr->is_sw_amsdu = false;
+       }
+
+       if (hdr_conv) {
+               sw_txhdr->hdr80211 = NULL;
+               sw_txhdr->fc = cl_tx_agg_frame_control(cl_vif, key_conf, &hdrlen);
+       } else {
+               struct ieee80211_hdr *hdr80211 = (struct ieee80211_hdr *)skb->data;
+               __le16 fc = hdr80211->frame_control;
+
+               sw_txhdr->hdr80211 = hdr80211;
+               sw_txhdr->fc = fc;
+               hdrlen = ieee80211_hdrlen(fc);
+       }
+
+       /* Fetch the relevant agg queue */
+       tx_queue = cl_sta->agg_tx_queues[tid];
+
+       if (unlikely(!tx_queue)) {
+               kfree_skb(skb);
+               cl_sw_txhdr_free(cl_hw, sw_txhdr);
+               cl_dbg_err(cl_hw, "tx_queue is NULL [sta_idx = %u] [tid = %u]\n",
+                          cl_sta->sta_idx, tid);
+               cl_hw->tx_packet_cntr.drop.queue_null++;
+               return;
+       }
+
+       sw_txhdr->tx_queue = tx_queue;
+
+       total_frame_len = frame_len + hdrlen - sizeof(struct ethhdr);
+
+       if (key_conf)
+               total_frame_len += key_conf->icv_len;
+
+       /* Prepare txdesc */
+       cl_tx_agg_prep(cl_hw, sw_txhdr, frame_len, hdr_pads, hdr_conv);
+
+       /*
+        * AMSDU - first sub frame
+        * !!! Must be done after calling cl_tx_agg_prep() !!!
+        */
+       if (is_amsdu)
+               cl_tx_amsdu_first_sub_frame(sw_txhdr, cl_sta, skb, tid);
+
+       cl_tx_send(cl_hw, sw_txhdr, &cl_sta->amsdu_anchor[tid]);
+}
+
+void cl_tx_agg(struct cl_hw *cl_hw, struct cl_sta *cl_sta,
+              struct sk_buff *skb, bool hdr_conv, bool lock)
+{
+       if (lock) {
+               spin_lock_bh(&cl_hw->tx_lock_agg);
+               _cl_tx_agg(cl_hw, cl_sta, skb, hdr_conv);
+               spin_unlock_bh(&cl_hw->tx_lock_agg);
+       } else {
+               _cl_tx_agg(cl_hw, cl_sta, skb, hdr_conv);
+       }
+}
+
+static bool cl_tx_check_agg(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb)
+{
+       u16 ethertype = (skb->data[12] << 8) | skb->data[13];
+
+       /* Control port protocol needs a lot of special handling */
+       if (cpu_to_be16(ethertype) == sdata->control_port_protocol)
+               return false;
+
+       /* Only RFC 1042 SNAP */
+       if (ethertype < ETH_P_802_3_MIN)
+               return false;
+
+       /* Don't handle TX status request here either */
+       if (skb->sk && skb_shinfo(skb)->tx_flags & SKBTX_WIFI_STATUS)
+               return false;
+
+       return true;
+}
+
+static void cl_tx_reset_session_timer(struct sta_info *stainfo, u8 tid)
+{
+       struct tid_ampdu_tx *tid_tx = NULL;
+
+       tid_tx = rcu_dereference(stainfo->ampdu_mlme.tid_tx[tid]);
+
+       if (tid_tx && tid_tx->timeout)
+               tid_tx->last_tx = jiffies;
+}
+
+void cl_tx_fast_agg(struct cl_hw *cl_hw, struct cl_sta *cl_sta,
+                   struct sk_buff *skb, bool lock)
+{
+       struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
+       struct ieee80211_vif *vif = cl_sta->cl_vif->vif;
+       u16 ac = skb_get_queue_mapping(skb);
+       u8 tid = skb->priority & IEEE80211_QOS_CTL_TAG1D_MASK;
+
+       tx_info->control.vif = vif;
+       tx_info->control.hw_key = cl_key_get(cl_sta);
+       tx_info->hw_queue = vif->hw_queue[ac];
+       tx_info->flags |= IEEE80211_TX_CTL_AMPDU;
+
+       if (cl_sta->baws[tid].amsdu &&
+           (cl_wrs_api_get_sta_data_rate(cl_sta) > cl_hw->conf->ci_tx_amsdu_min_data_rate))
+               tx_info->control.flags |= IEEE80211_TX_CTRL_AMSDU;
+
+       cl_tx_update_stats(skb, cl_sta, ac, tid);
+       cl_tx_agg(cl_hw, cl_sta, skb, true, lock);
+       cl_tx_reset_session_timer(cl_sta->stainfo, tid);
+       cl_hw->tx_packet_cntr.forward.drv_fast_agg++;
+}
+
+void cl_tx_wlan_to_8023(struct sk_buff *skb)
+{
+       struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
+       struct ethhdr tmp_eth;
+       struct ethhdr *ehdr;
+       struct {
+               u8 hdr[ETH_ALEN]__aligned(2);
+               __be16 proto;
+       } payload;
+       u16 hdrlen = ieee80211_hdrlen(hdr->frame_control);
+       u8 enc_len = cl_key_get_cipher_len(skb);
+
+       cl_mac_addr_copy(tmp_eth.h_dest, ieee80211_get_DA(hdr));
+       cl_mac_addr_copy(tmp_eth.h_source, ieee80211_get_SA(hdr));
+       skb_copy_bits(skb, hdrlen, &payload, sizeof(payload));
+       tmp_eth.h_proto = payload.proto;
+
+       if (enc_len) {
+               memcpy(skb->data + hdrlen,
+                      skb->data + hdrlen + enc_len,
+                      skb->len - hdrlen - enc_len);
+               skb_trim(skb, skb->len - enc_len);
+       }
+
+       if (likely((ether_addr_equal(payload.hdr, rfc1042_header) &&
+                   tmp_eth.h_proto != htons(ETH_P_AARP) &&
+                   tmp_eth.h_proto != htons(ETH_P_IPX)) ||
+                  ether_addr_equal(payload.hdr, bridge_tunnel_header)))
+               /* Remove RFC1042 or Bridge-Tunnel encapsulation and replace ether_type */
+               hdrlen += ETH_ALEN + 2;
+       else
+               tmp_eth.h_proto = htons(skb->len - hdrlen);
+
+       skb_pull(skb, hdrlen);
+       ehdr = skb_push(skb, sizeof(struct ethhdr));
+       memcpy(ehdr, &tmp_eth, sizeof(tmp_eth));
+}
+
+u16 cl_tx_prepare_wlan_hdr(struct cl_hw *cl_hw, struct cl_sta *cl_sta,
+                          struct sk_buff *skb, struct ieee80211_hdr *hdr)
+{
+       struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(skb->dev);
+       struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
+       u16 hdrlen = 0;
+       __le16 fc = cpu_to_le16(IEEE80211_FTYPE_DATA | IEEE80211_STYPE_DATA);
+
+       if (tx_info->control.hw_key)
+               fc |= cpu_to_le16(IEEE80211_FCTL_PROTECTED);
+
+       switch (sdata->vif.type) {
+       case NL80211_IFTYPE_AP:
+               fc |= cpu_to_le16(IEEE80211_FCTL_FROMDS);
+               /* DA BSSID SA */
+               memcpy(hdr->addr1, skb->data, ETH_ALEN);
+               memcpy(hdr->addr2, sdata->vif.addr, ETH_ALEN);
+               memcpy(hdr->addr3, skb->data + ETH_ALEN, ETH_ALEN);
+               hdrlen = 24;
+               break;
+       case NL80211_IFTYPE_STATION:
+               if (sdata->u.mgd.use_4addr) {
+                       fc |= cpu_to_le16(IEEE80211_FCTL_FROMDS |
+                                         IEEE80211_FCTL_TODS);
+                       /* RA TA DA SA */
+                       memcpy(hdr->addr1, sdata->u.mgd.bssid, ETH_ALEN);
+                       memcpy(hdr->addr2, sdata->vif.addr, ETH_ALEN);
+                       memcpy(hdr->addr3, skb->data, ETH_ALEN);
+                       memcpy(hdr->addr4, skb->data + ETH_ALEN, ETH_ALEN);
+                       hdrlen = 30;
+               } else {
+                       fc |= cpu_to_le16(IEEE80211_FCTL_TODS);
+                       /* BSSID SA DA */
+                       memcpy(hdr->addr1, sdata->u.mgd.bssid, ETH_ALEN);
+                       memcpy(hdr->addr2, skb->data + ETH_ALEN, ETH_ALEN);
+                       memcpy(hdr->addr3, skb->data, ETH_ALEN);
+                       hdrlen = 24;
+               }
+               break;
+       default:
+               cl_dbg_err(cl_hw, "Unknown vif type %d !!!\n", sdata->vif.type);
+               return 0;
+       }
+
+       if (cl_sta->stainfo->sta.wme) {
+               fc |= cpu_to_le16(IEEE80211_STYPE_QOS_DATA);
+               hdrlen += 2;
+       }
+
+       hdr->frame_control = fc;
+       hdr->duration_id = 0;
+       hdr->seq_ctrl = 0;
+
+       return hdrlen;
+}
+
+int cl_tx_8023_to_wlan(struct cl_hw *cl_hw, struct sk_buff *skb, struct cl_sta *cl_sta, u8 tid)
+{
+       struct ieee80211_hdr hdr;
+       int head_need, ret = 0;
+       u16 ethertype, hdrlen;
+       const u8 *encaps_data = NULL;
+       int encaps_len = 0, skip_header_bytes = ETH_HLEN;
+       u8 enc_len = cl_key_get_cipher_len(skb);
+
+       /* Convert Ethernet header to proper 802.11 header */
+       ethertype = (skb->data[12] << 8) | skb->data[13];
+
+       hdrlen = cl_tx_prepare_wlan_hdr(cl_hw, cl_sta, skb, &hdr);
+       if (!hdrlen) {
+               ret = -EINVAL;
+               goto free;
+       }
+
+       if (ethertype >= ETH_P_802_3_MIN) {
+               encaps_data = rfc1042_header;
+               encaps_len = sizeof(rfc1042_header);
+               skip_header_bytes -= 2;
+       }
+
+       skb_pull(skb, skip_header_bytes);
+       head_need = hdrlen + enc_len + encaps_len - skb_headroom(skb);
+
+       if (head_need > 0) {
+               head_need = ((head_need + 3) & ~3);
+               if (pskb_expand_head(skb, head_need, 0, GFP_ATOMIC)) {
+                       ret = -ENOMEM;
+                       goto free;
+               }
+       }
+
+       if (encaps_data)
+               memcpy(skb_push(skb, encaps_len), encaps_data, encaps_len);
+
+       skb_push(skb, hdrlen + enc_len);
+
+       if (cl_sta->stainfo->sta.wme) {
+               u16 qos_ctrl = tid;
+
+               memcpy(skb->data, &hdr, hdrlen - 2);
+               memcpy(skb->data + hdrlen - 2, &qos_ctrl, 2);
+       } else {
+               memcpy(skb->data, &hdr, hdrlen);
+       }
+
+       skb_reset_mac_header(skb);
+
+       return ret;
+free:
+       cl_hw->tx_packet_cntr.drop.build_hdr_fail++;
+       kfree_skb(skb);
+       skb = NULL;
+
+       return ret;
+}
+
+void cl_tx_check_start_ba_session(struct cl_hw *cl_hw,
+                                 struct sta_info *stainfo,
+                                 struct sk_buff *skb)
+{
+       struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
+       struct ieee80211_sta *sta = &stainfo->sta;
+       struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
+       u8 tid;
+
+       /* TODO: What about HE? */
+       if (!sta->ht_cap.ht_supported &&
+           !sta->vht_cap.vht_supported &&
+           !cl_band_is_6g(cl_hw))
+               return;
+
+       if (test_sta_flag(stainfo, WLAN_STA_PS_STA))
+               return;
+
+       if ((tx_info->flags & IEEE80211_TX_CTL_AMPDU) &&
+           !(tx_info->flags & IEEE80211_TX_STAT_AMPDU))
+               return;
+
+       if (cl_tx_ctrl_is_eapol(tx_info))
+               return;
+
+       if (unlikely(!ieee80211_is_data_qos(hdr->frame_control)))
+               return;
+
+       if (unlikely(skb->protocol == cpu_to_be16(ETH_P_PAE)))
+               return;
+
+       tid = ieee80211_get_tid(hdr);
+
+       if (likely(stainfo->ampdu_mlme.tid_tx[tid]))
+               return;
+
+       ieee80211_start_tx_ba_session(sta, tid, cl_hw->conf->ce_tx_ba_session_timeout);
+}
+
+static struct sk_buff *cl_tx_beacon_get(struct ieee80211_hw *hw,
+                                       struct ieee80211_vif *vif)
+{
+       struct ieee80211_local *local = hw_to_local(hw);
+       struct sk_buff *skb = NULL;
+       struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif);
+       struct ieee80211_if_ap *ap = &sdata->u.ap;
+       struct beacon_data *beacon = rcu_dereference(ap->beacon);
+
+       local->tim_in_locked_section = true;
+       if (beacon) {
+               if (beacon->cntdwn_counter_offsets[0] &&
+                   beacon->cntdwn_current_counter == 1) {
+                       ieee80211_csa_finish(vif);
+                       goto out;
+               }
+       }
+
+       skb = ieee80211_beacon_get(hw, vif);
+out:
+       local->tim_in_locked_section = false;
+
+       return skb;
+}
+
+static void cl_tx_mc(struct cl_vif *cl_vif, int *mc_fw_free)
+{
+       struct cl_hw *cl_hw = cl_vif->cl_hw;
+       struct ieee80211_vif *vif = cl_vif->vif;
+       struct sk_buff *skb = NULL;
+       struct ieee80211_tx_info *tx_info;
+
+       if (unlikely(!vif))
+               return;
+
+       while (((*mc_fw_free) > 0) &&
+              (skb = ieee80211_get_buffered_bc(cl_hw->hw, vif))) {
+               /* Route this MCBC frame to the BCN ipc queue */
+               tx_info = IEEE80211_SKB_CB(skb);
+               tx_info->hw_queue = CL_HWQ_BCN;
+
+               (*mc_fw_free)--;
+
+               /* Clear more data bit if this is the last frame in this SP */
+               if (*mc_fw_free == 0) {
+                       struct ieee80211_hdr *hdr =
+                                       (struct ieee80211_hdr *)skb->data;
+                       hdr->frame_control &=
+                                       cpu_to_le16(~IEEE80211_FCTL_MOREDATA);
+               }
+
+               cl_tx_single(cl_hw, NULL, skb, false, true);
+       }
+}
+
+void cl_tx_bcn_mesh_task(unsigned long data)
+{
+       struct cl_vif *cl_vif = (struct cl_vif *)data;
+       struct cl_hw *cl_hw = cl_vif->cl_hw;
+       struct ieee80211_tx_info *tx_info;
+       struct sk_buff *skb;
+       int mc_fw_free;
+
+       if (cl_radio_is_off(cl_hw) ||
+           cl_recovery_in_progress(cl_hw) ||
+           !test_bit(CL_DEV_STARTED, &cl_hw->drv_flags) ||
+           test_bit(CL_DEV_FW_ERROR, &cl_hw->drv_flags) ||
+           cl_hw->tx_disable_flags)
+               return;
+
+       skb = cl_tx_beacon_get(cl_hw->hw, cl_vif->vif);
+       if (!skb)
+               return;
+
+       /* Route this BCN to the BCN ipc queue */
+       tx_info = IEEE80211_SKB_CB(skb);
+       tx_info->hw_queue = CL_HWQ_BCN;
+
+       cl_tx_single(cl_hw, NULL, skb, false, true);
+
+       mc_fw_free = cl_hw->tx_queues.bcmc.fw_free_space;
+       cl_tx_mc(cl_vif, &mc_fw_free);
+}
+
+static void cl_tx_bcn(struct cl_vif *cl_vif)
+{
+       struct cl_hw *cl_hw = cl_vif->cl_hw;
+       u8 vif_index = cl_vif->vif_index;
+       struct ieee80211_vif *vif = cl_vif->vif;
+       struct ieee80211_tx_info *tx_info;
+       struct sk_buff *skb;
+       struct ieee80211_sub_if_data *sdata = NULL;
+
+       if (!vif || vif->type != NL80211_IFTYPE_AP)
+               return;
+
+       sdata = vif_to_sdata(vif);
+       /* TODO: Check if this is really needed */
+       sdata->u.ap.ps.dtim_count =
+               cl_hw->ipc_env->ring_indices_elem->indices->dtim_count[vif_index];
+
+       /*
+        * If we are in the middle of the CAC, we allow regular channel switch
+        * and retrigger the CAC (If needed).
+        */
+       if (cl_dfs_is_in_cac(cl_hw) && vif->csa_active) {
+               /*
+                * TODO: if radar is detected, we wait for all CSAs to be transmitted,
+                * before allowing channel switch
+                */
+
+               ieee80211_csa_finish(vif);
+               return;
+       }
+
+       skb = cl_tx_beacon_get(cl_hw->hw, vif);
+       if (!skb)
+               return;
+
+       /* Route this BCN to the BCN ipc queue */
+       tx_info = IEEE80211_SKB_CB(skb);
+       tx_info->hw_queue = CL_HWQ_BCN;
+
+       cl_tx_single(cl_hw, NULL, skb, false, true);
+}
+
+/* Cl_tx_bcns - generate BCNs and TX buffered MC frames each BCN DTIM interval
+ *
+ * Beacons are sent first followed by cyclic MC for fairness between VIF's
+ * the FW buffer is restricted to "IPC_TXDESC_CNT_BCMC" buffer size.
+ */
+void cl_tx_bcns(struct cl_hw *cl_hw)
+{
+       struct cl_vif *cl_vif = NULL;
+       int mc_fw_free = 0;
+
+       /* Don't send beacons during scan */
+       if (cl_channel_is_scan_active(cl_hw))
+               return;
+
+       list_for_each_entry(cl_vif, &cl_hw->vif_db.head, list)
+               cl_tx_bcn(cl_vif);
+
+       cl_vif = cl_hw->mc_vif;
+       mc_fw_free = cl_hw->tx_queues.bcmc.fw_free_space;
+
+       do {
+               cl_tx_mc(cl_vif, &mc_fw_free);
+               /* Cl_vif_get_next() is cyclic */
+               cl_vif = cl_vif_get_next(cl_hw, cl_vif);
+       } while ((cl_vif != cl_hw->mc_vif) && mc_fw_free);
+
+       cl_hw->mc_vif = cl_vif_get_next(cl_hw, cl_hw->mc_vif);
+}
+
+void cl_tx_en(struct cl_hw *cl_hw, u8 reason, bool enable)
+{
+       unsigned long tx_disable_flags_prev = cl_hw->tx_disable_flags;
+
+       if (enable) {
+               clear_bit(reason, &cl_hw->tx_disable_flags);
+
+               if (tx_disable_flags_prev != 0 && cl_hw->tx_disable_flags == 0)
+                       if (cl_hw->conf->ci_backup_bcn_en)
+                               cl_msg_tx_backup_bcn_en(cl_hw, true);
+       } else {
+               set_bit(reason, &cl_hw->tx_disable_flags);
+
+               if (tx_disable_flags_prev == 0)
+                       if (cl_hw->conf->ci_backup_bcn_en)
+                               cl_msg_tx_backup_bcn_en(cl_hw, false);
+       }
+}
+
+static void cl_tx_flush(struct cl_hw *cl_hw)
+{
+       unsigned long flags;
+
+       /* Flush bcmc */
+       spin_lock_irqsave(&cl_hw->tx_lock_bcmc, flags);
+       cl_bcmc_cfm_flush_queue(cl_hw);
+       spin_unlock_irqrestore(&cl_hw->tx_lock_bcmc, flags);
+
+       /* Flush single */
+       spin_lock_bh(&cl_hw->tx_lock_single);
+       cl_txq_flush_all_single(cl_hw);
+       cl_single_cfm_flush_all(cl_hw);
+       spin_unlock_bh(&cl_hw->tx_lock_single);
+
+       /* Flush agg */
+       spin_lock_bh(&cl_hw->tx_lock_agg);
+       cl_txq_flush_all_agg(cl_hw);
+       cl_agg_cfm_flush_all(cl_hw);
+       spin_unlock_bh(&cl_hw->tx_lock_agg);
+}
+
+void cl_tx_off(struct cl_hw *cl_hw)
+{
+       cl_tx_stop_remote_cpu(cl_hw);
+       cl_txq_stop(cl_hw);
+       cl_tx_flush(cl_hw);
+}
+
+static void cl_tx_set_mapping(struct cl_hw *cl_hw, struct sk_buff *skb, struct net_device *dev)
+{
+       struct cl_vif *cl_vif = NETDEV_TO_CL_VIF(dev);
+       u8 vif_index = cl_vif->vif_index;
+
+       if (!cl_hw->conf->ha_wmm_enabled[vif_index]) {
+               skb->priority = 0;
+               goto set_queue_mapping;
+       }
+
+       if (cl_vlan_dscp_is_enabled(cl_hw, cl_vif)) {
+               skb->priority = cl_vlan_dscp_check_ether_type(cl_hw, skb, vif_index);
+       } else {
+               /*
+                * TODO: IPv6 support
+                * TODO: VLAN user priority support
+                */
+
+               u8 i = 0, dcsp_val = 0, *src_buf = NULL;
+               u16 ether_type = get_ether_type(2 * ETH_ALEN, skb->data);
+
+               /* Patch until IPv6 will be supported - set priority to 0 */
+               if (ether_type != ETH_P_IP) {
+                       skb->priority = 0;
+                       goto set_queue_mapping;
+               }
+
+               src_buf = skb->data;
+               src_buf += ETH_HLEN;
+               dcsp_val = (*(src_buf + 1) & 0xec) >> 2;
+
+               for (i = 0; i < TID_MAX; i++)
+                       if (dscp_to_up[i] == dcsp_val) {
+                               skb->priority = i;
+                               break;
+                       }
+       }
+
+set_queue_mapping:
+       skb_set_queue_mapping(skb, ieee802_1d_to_ac[skb->priority]);
+}
+
+static bool cl_tx_packet_limit(struct cl_hw *cl_hw, struct sk_buff *skb)
+{
+       if (cl_hw->conf->ci_tx_packet_limit > 0)
+               return (atomic_read(&cl_hw->tx_packet_count) >= cl_hw->conf->ci_tx_packet_limit);
+
+       return false;
+}
+
+static void cl_tx_destructor(struct sk_buff *skb)
+{
+       struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(skb->dev);
+       struct cl_hw *cl_hw = sdata->local->hw.priv;
+
+       atomic_dec(&cl_hw->tx_packet_count);
+}
+
+void cl_tx_drop_dkb(struct sk_buff *skb)
+{
+       skb->dev->stats.rx_dropped++;
+       kfree_skb(skb);
+}
+
+static netdev_tx_t _____cl_tx_start(struct cl_hw *cl_hw, struct sk_buff *skb,
+                                   struct net_device *dev, struct cl_sta *cl_sta)
+{
+       struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+       struct ieee80211_vif *vif = &sdata->vif;
+       struct cl_vif *cl_vif = (struct cl_vif *)vif->drv_priv;
+       struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
+       int buffer_cnt = 0;
+       u8 hw_queue = vif->hw_queue[skb_get_queue_mapping(skb)];
+
+       cl_hw->tx_packet_cntr.forward.tx_start++;
+
+       if (cl_hw->wd_restart_drv) {
+               cl_hw->tx_packet_cntr.drop.wd_restart++;
+               cl_tx_drop_dkb(skb);
+               return NETDEV_TX_OK;
+       }
+
+       if (cl_radio_is_off(cl_hw)) {
+               cl_hw->tx_packet_cntr.drop.radio_off++;
+               cl_tx_drop_dkb(skb);
+               return NETDEV_TX_OK;
+       }
+
+       if (cl_recovery_in_progress(cl_hw)) {
+               cl_hw->tx_packet_cntr.drop.in_recovery++;
+               cl_tx_drop_dkb(skb);
+               return NETDEV_TX_OK;
+       }
+
+       if (skb->len < ETH_HLEN) {
+               cl_hw->tx_packet_cntr.drop.short_length++;
+               cl_tx_drop_dkb(skb);
+               return NETDEV_TX_OK;
+       }
+
+       if (skb_queue_len(&sdata->local->pending[hw_queue]) >=
+           cl_hw->conf->ci_pending_queue_size) {
+               cl_hw->tx_packet_cntr.drop.pending_full++;
+               cl_tx_drop_dkb(skb);
+               tasklet_schedule(&sdata->local->tx_pending_tasklet);
+               return NETDEV_TX_OK;
+       }
+
+       /* Limit total packets for TX */
+       if (cl_tx_packet_limit(cl_hw, skb)) {
+               cl_hw->tx_packet_cntr.drop.packet_limit++;
+               cl_tx_drop_dkb(skb);
+               return NETDEV_TX_OK;
+       }
+
+       if (!skb->destructor) {
+               skb->destructor = cl_tx_destructor;
+               buffer_cnt = atomic_inc_return(&cl_hw->tx_packet_count);
+       }
+
+       memset(tx_info, 0, sizeof(struct ieee80211_tx_info));
+
+#ifdef TRACE_SUPPORT
+       trace_cl_trace_tx_start(cl_hw->idx, skb, buffer_cnt);
+#endif
+       if (cl_sta && cl_sta->stainfo &&
+           (test_sta_flag(cl_sta->stainfo, WLAN_STA_AUTHORIZED))) {
+               u8 tid = skb->priority & IEEE80211_QOS_CTL_TAG1D_MASK;
+               bool is_agg = cl_tx_check_agg(sdata, skb);
+
+               cl_traffic_tx_handler(cl_hw, cl_sta, skb->len);
+
+               if (!ieee80211_vif_is_mesh(&sdata->vif)) {
+                       if (is_agg && cl_sta->agg_tx_queues[tid])
+                               cl_tx_fast_agg(cl_hw, cl_sta, skb, true);
+                       else if (is_agg && cl_sta->baws[tid].action_start)
+                               __skb_queue_tail(&cl_sta->baws[tid].pending, skb);
+                       else
+                               cl_tx_fast_single(cl_hw, cl_sta, skb, true);
+
+                       return NETDEV_TX_OK;
+               }
+       }
+
+       cl_hw->tx_packet_cntr.forward.to_mac++;
+       cl_vif->orig_dev_ops->ndo_start_xmit(skb, dev);
+
+       return NETDEV_TX_OK;
+}
+
+netdev_tx_t ____cl_tx_start(struct cl_hw *cl_hw, struct sk_buff *skb, struct net_device *dev)
+{
+       struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+       struct cl_sta *cl_sta;
+
+       cl_sta_lock(cl_hw);
+
+       if (sdata->vif.type == NL80211_IFTYPE_STATION)
+               cl_sta = cl_sta_get_by_addr(cl_hw, sdata->u.mgd.bssid);
+       else
+               cl_sta = cl_sta_get_by_addr(cl_hw, skb->data);
+
+       if (cl_sta) {
+               netdev_tx_t ret = _____cl_tx_start(cl_hw, skb, dev, cl_sta);
+
+               cl_sta_unlock(cl_hw);
+               return ret;
+       }
+
+       cl_sta_unlock(cl_hw);
+       return _____cl_tx_start(cl_hw, skb, dev, NULL);
+}
+
+netdev_tx_t ___cl_tx_start(struct cl_hw *cl_hw, struct sk_buff *skb, struct net_device *dev)
+{
+       skb->dev = dev;
+       cl_tx_set_mapping(cl_hw, skb, dev);
+
+       return ____cl_tx_start(cl_hw, skb, dev);
+}
+
+netdev_tx_t __cl_tx_start(struct cl_hw *cl_hw, struct sk_buff *skb, struct net_device *dev)
+{
+       if (!skb_mac_header_was_set(skb))
+               skb_reset_mac_header(skb);
+
+       return ___cl_tx_start(cl_hw, skb, dev);
+}
+
+netdev_tx_t _cl_tx_start(struct cl_hw *cl_hw, struct sk_buff *skb, struct net_device *dev)
+{
+       int cpu = cl_hw->conf->ci_tx_remote_cpu;
+
+       if (cpu == -1)
+               return __cl_tx_start(cl_hw, skb, dev);
+
+       skb->dev = dev;
+       cl_tx_remote_cpu(cl_hw, skb, cpu);
+       return NETDEV_TX_OK;
+}
+
+netdev_tx_t cl_tx_start(struct sk_buff *skb, struct net_device *dev)
+{
+       struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+       struct cl_hw *cl_hw = sdata->local->hw.priv;
+
+       return _cl_tx_start(cl_hw, skb, dev);
+}
+
--
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.
________________________________


^ permalink raw reply related	[flat|nested] 262+ messages in thread

* [RFC v1 213/256] cl8k: add tx/tx.h
  2021-06-17 15:58 [RFC v1 000/256] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (211 preceding siblings ...)
  2021-06-17 16:01 ` [RFC v1 212/256] cl8k: add tx/tx.c viktor.barna
@ 2021-06-17 16:01 ` viktor.barna
  2021-06-17 16:01 ` [RFC v1 214/256] cl8k: add tx/tx_amsdu.c viktor.barna
                   ` (44 subsequent siblings)
  257 siblings, 0 replies; 262+ messages in thread
From: viktor.barna @ 2021-06-17 16:01 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Oleksandr Savchenko, Shay Bar, Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

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

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 drivers/net/wireless/celeno/cl8k/tx/tx.h | 109 +++++++++++++++++++++++
 1 file changed, 109 insertions(+)
 create mode 100644 drivers/net/wireless/celeno/cl8k/tx/tx.h

diff --git a/drivers/net/wireless/celeno/cl8k/tx/tx.h b/drivers/net/wireless/celeno/cl8k/tx/tx.h
new file mode 100644
index 000000000000..01c8f6b6306f
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/tx/tx.h
@@ -0,0 +1,109 @@
+/* SPDX-License-Identifier: MIT */
+/* Copyright(c) 2019-2021, Celeno Communications Ltd. */
+
+#ifndef CL_TX_H
+#define CL_TX_H
+
+#include "hw.h"
+#include "sta.h"
+#include "vif.h"
+#include "debugfs.h"
+#include "ipc_shared.h"
+#include "tx/sw_txhdr.h"
+
+#define INC_SN(sn) (((sn) + 0x10) & IEEE80211_SCTL_SEQ)
+#define DEC_SN(sn) (((sn) - 0x10) & IEEE80211_SCTL_SEQ)
+
+#define CL_TX_LIFETIME_MS 4000
+
+#define CL_SKB_DATA_ALIGN_SZ      4
+#define CL_SKB_DATA_ALIGN_MSK     (CL_SKB_DATA_ALIGN_SZ - 1)
+#define CL_SKB_DATA_ALIGN_PADS(x) \
+       ((CL_SKB_DATA_ALIGN_SZ - ((ptrdiff_t)(x) & CL_SKB_DATA_ALIGN_MSK)) & CL_SKB_DATA_ALIGN_MSK)
+
+#define CL_TX_MAX_FRAME_LEN_SINGLE 4096
+#define CL_TX_MAX_FRAME_LEN_AGG 2000
+
+struct cl_hw_tx_status {
+       u32 mcs_index          : 7; /* [6:0] */
+       u32 is_bcmc            : 1; /* [7] */
+       u32 num_mpdu_retries   : 4; /* [11:8] */
+       u32 rsv                : 4; /* [15:12] */
+       u32 format_mod         : 4; /* [19:16] */
+       u32 bw_requested       : 2; /* [21:20] */
+       u32 bf                 : 1; /* [22] */
+       u32 frm_successful     : 1; /* [23] */
+       u32 bw_transmitted     : 2; /* [25:24] */
+       u32 freespace_inc_skip : 1; /* [26] */
+       u32 keep_skb           : 1; /* [27] */
+       u32 gi                 : 2; /* [29:28] */
+       u32 descriptor_done_sw : 1; /* [30] */
+       u32 descriptor_done_hw : 1; /* [31] */
+};
+
+enum cl_tx_flags {
+       CL_TX_EN_DFS,
+       CL_TX_EN_ACS,
+};
+
+enum cl_tx_single_frame_type {
+       CL_TX_SINGLE_FRAME_TYPE_QOS_DATA,
+       CL_TX_SINGLE_FRAME_TYPE_QOS_NULL,
+       CL_TX_SINGLE_FRAME_TYPE_MANAGEMENT,
+       CL_TX_SINGLE_FRAME_TYPE_OTHER
+};
+
+void cl_tx_init(struct cl_hw *cl_hw);
+void cl_tx_check_start_ba_session(struct cl_hw *cl_hw,
+                                 struct sta_info *stainfo,
+                                 struct sk_buff *skb);
+void cl_tx_bcns(struct cl_hw *cl_hw);
+void cl_tx_single_free_skb(struct cl_hw *cl_hw, struct sk_buff *skb);
+void cl_tx_single(struct cl_hw *cl_hw, struct cl_sta *cl_sta,
+                 struct sk_buff *skb, bool is_vns, bool lock);
+void cl_tx_fast_single(struct cl_hw *cl_hw, struct cl_sta *cl_sta,
+                      struct sk_buff *skb, bool lock);
+void cl_tx_agg_prep(struct cl_hw *cl_hw, struct cl_sw_txhdr *sw_txhdr,
+                   u16 frame_len, u8 hdr_pads, bool hdr_conv);
+void cl_tx_agg(struct cl_hw *cl_hw, struct cl_sta *cl_sta,
+              struct sk_buff *skb, bool hdr_conv, bool lock);
+void cl_tx_fast_agg(struct cl_hw *cl_hw, struct cl_sta *cl_sta,
+                   struct sk_buff *skb, bool lock);
+u16 cl_tx_prepare_wlan_hdr(struct cl_hw *cl_hw, struct cl_sta *cl_sta,
+                          struct sk_buff *skb, struct ieee80211_hdr *hdr);
+void cl_tx_wlan_to_8023(struct sk_buff *skb);
+int cl_tx_8023_to_wlan(struct cl_hw *cl_hw, struct sk_buff *skb, struct cl_sta *cl_sta, u8 tid);
+void cl_tx_push(struct cl_hw *cl_hw, struct cl_sw_txhdr *sw_txhdr, struct cl_tx_queue *tx_queue);
+void cl_tx_bcn_mesh_task(unsigned long data);
+void cl_tx_en(struct cl_hw *cl_hw, u8 reason, bool enable);
+void cl_tx_off(struct cl_hw *cl_hw);
+void cl_tx_drop_dkb(struct sk_buff *skb);
+netdev_tx_t ____cl_tx_start(struct cl_hw *cl_hw, struct sk_buff *skb, struct net_device *dev);
+netdev_tx_t ___cl_tx_start(struct cl_hw *cl_hw, struct sk_buff *skb, struct net_device *dev);
+netdev_tx_t __cl_tx_start(struct cl_hw *cl_hw, struct sk_buff *skb, struct net_device *dev);
+netdev_tx_t _cl_tx_start(struct cl_hw *cl_hw, struct sk_buff *skb, struct net_device *dev);
+netdev_tx_t cl_tx_start(struct sk_buff *skb, struct net_device *dev);
+
+static inline bool cl_tx_ctrl_is_amsdu(struct ieee80211_tx_info *tx_info)
+{
+       return !!(tx_info->control.flags & IEEE80211_TX_CTRL_AMSDU);
+}
+
+static inline bool cl_tx_ctrl_is_eapol(struct ieee80211_tx_info *tx_info)
+{
+       return !!(tx_info->control.flags & IEEE80211_TX_CTRL_PORT_CTRL_PROTO);
+}
+
+static inline bool cl_tx_ctrl_is_inject(struct ieee80211_tx_info *tx_info)
+{
+       /*
+        * Check that IEEE80211_TX_CTL_INJECTED is set and that
+        * IEEE80211_TX_INTFL_NL80211_FRAME_TX isn't to distinguish between
+        * TX-inject packets that Celeno driver generates and TX-inject packets
+        * that mac80211 generates in ieee80211_tx_control_port().
+        */
+       return ((tx_info->flags & IEEE80211_TX_CTL_INJECTED) &&
+               !(tx_info->flags & IEEE80211_TX_INTFL_NL80211_FRAME_TX));
+}
+
+#endif /* CL_TX_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.
________________________________


^ permalink raw reply related	[flat|nested] 262+ messages in thread

* [RFC v1 214/256] cl8k: add tx/tx_amsdu.c
  2021-06-17 15:58 [RFC v1 000/256] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (212 preceding siblings ...)
  2021-06-17 16:01 ` [RFC v1 213/256] cl8k: add tx/tx.h viktor.barna
@ 2021-06-17 16:01 ` viktor.barna
  2021-06-17 16:01 ` [RFC v1 215/256] cl8k: add tx/tx_amsdu.h viktor.barna
                   ` (43 subsequent siblings)
  257 siblings, 0 replies; 262+ messages in thread
From: viktor.barna @ 2021-06-17 16:01 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Oleksandr Savchenko, Shay Bar, Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

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

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 .../net/wireless/celeno/cl8k/tx/tx_amsdu.c    | 483 ++++++++++++++++++
 1 file changed, 483 insertions(+)
 create mode 100644 drivers/net/wireless/celeno/cl8k/tx/tx_amsdu.c

diff --git a/drivers/net/wireless/celeno/cl8k/tx/tx_amsdu.c b/drivers/net/wireless/celeno/cl8k/tx/tx_amsdu.c
new file mode 100644
index 000000000000..688f2af15e4a
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/tx/tx_amsdu.c
@@ -0,0 +1,483 @@
+// SPDX-License-Identifier: MIT
+/* Copyright(c) 2019-2021, Celeno Communications Ltd. */
+
+#include "tx/tx_amsdu.h"
+#include "tx/tx.h"
+#include "utils/math.h"
+#include "chip.h"
+#include "tx/tx_queue.h"
+#include "band.h"
+#include "def.h"
+#include "key.h"
+#include "utils/ip.h"
+#include "wrs/wrs_api.h"
+
+#define CL_AMSDU_HDR_LEN 14
+
+static bool cl_tx_amsdu_is_sw(struct cl_hw *cl_hw, struct cl_sta *cl_sta,
+                             struct sk_buff *skb, u16 pkt_len)
+{
+       bool syn_rst_push = false;
+       bool tcp_ack = false;
+
+       if (cl_hw->conf->ci_tx_sw_amsdu_max_packets <= 1)
+               return false;
+
+       tcp_ack = is_tcp_ack(skb, &syn_rst_push);
+
+       if (!tcp_ack || syn_rst_push)
+               return false;
+
+       if ((cl_wrs_api_get_sta_data_rate(cl_sta) * cl_sta->ampdu_min_spacing) <=
+           (pkt_len << 3))
+               return false;
+
+       return true;
+}
+
+static int cl_tx_amsdu_anchor_set(struct cl_hw *cl_hw, struct cl_sta *cl_sta,
+                                 struct sk_buff *skb, u8 tid)
+{
+       /*
+        * Packet length calculation in HW -
+        * Add 802.11 header (maximum possible size) instead if 802.3
+        * Add AMSDU header
+        * Add RFC1042 header (according to ether-type)
+        * Add IV and ICV (if there is encryption)
+        */
+       struct cl_amsdu_ctrl *amsdu_anchor = &cl_sta->amsdu_anchor[tid];
+       struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
+       struct ieee80211_key_conf *key_conf = tx_info->control.hw_key;
+       u16 ethertype = (skb->data[12] << 8) | skb->data[13];
+       u16 pkt_len = skb->len + CL_WLAN_HEADER_MAX_SIZE;
+
+       if (key_conf)
+               pkt_len += (key_conf->iv_len + key_conf->icv_len);
+
+       if (ethertype >= ETH_P_802_3_MIN)
+               pkt_len += sizeof(rfc1042_header);
+
+       amsdu_anchor->rem_len = amsdu_anchor->max_len - pkt_len;
+       amsdu_anchor->packet_cnt = 1;
+       amsdu_anchor->is_sw_amsdu = cl_tx_amsdu_is_sw(cl_hw, cl_sta, skb, pkt_len);
+
+       return CL_AMSDU_ANCHOR_SET;
+}
+
+static void cl_tx_amsdu_anchor_umacdesc_update(struct txdesc *txdesc, u8 idx,
+                                              u16 len, dma_addr_t dma_addr,
+                                              bool is_padding)
+{
+       struct lmacapi *umacdesc = &txdesc->umacdesc;
+
+       umacdesc->packet_len[idx] = cpu_to_le16(len);
+       umacdesc->packet_addr[idx] = cpu_to_le32(dma_addr);
+       txdesc->host_info.packet_cnt++;
+
+       /* Update padding bit of current msdu sub-frame */
+       if (is_padding)
+               txdesc->host_info.host_padding |= BIT(idx);
+}
+
+static void _cl_tx_amsdu_transfer_single(struct cl_hw *cl_hw,
+                                        struct sk_buff *skb,
+                                        struct cl_sta *cl_sta,
+                                        u8 tid)
+{
+       struct ieee80211_tx_info *tx_info;
+
+       tx_info = IEEE80211_SKB_CB(skb);
+       tx_info->flags &= ~IEEE80211_TX_CTL_AMPDU;
+       tx_info->control.flags &= ~IEEE80211_TX_CTRL_AMSDU;
+
+       if (cl_tx_8023_to_wlan(cl_hw, skb, cl_sta, tid) == 0) {
+               cl_hw->tx_packet_cntr.transfer.agg_to_single++;
+               cl_tx_single(cl_hw, cl_sta, skb, false, false);
+       }
+}
+
+static void cl_tx_amsdu_set_sw_sub_amsdu_hdr(struct sk_buff *skb)
+{
+       u16 ethertype = (skb->data[12] << 8) | skb->data[13];
+       int rfc1042_len = 0;
+       void *data;
+       struct ethhdr *amsdu_hdr;
+
+       if (ethertype >= ETH_P_802_3_MIN)
+               rfc1042_len = sizeof(rfc1042_header);
+
+       data = skb_push(skb, rfc1042_len + 2);
+       memmove(data, data + rfc1042_len + 2, 2 * ETH_ALEN);
+
+       amsdu_hdr = (struct ethhdr *)data;
+       amsdu_hdr->h_proto = cpu_to_be16(skb->len - ETH_HLEN);
+
+       memcpy(data + ETH_HLEN, rfc1042_header, rfc1042_len);
+}
+
+static int cl_tx_amsdu_add_sw_amsdu_hdr(struct cl_hw *cl_hw,
+                                       struct cl_amsdu_ctrl *amsdu_anchor)
+{
+       struct cl_sw_txhdr *anchor_sw_txhdr = amsdu_anchor->sw_txhdr;
+       struct sk_buff *skb = anchor_sw_txhdr->skb;
+       struct cl_sta *cl_sta = anchor_sw_txhdr->cl_sta;
+       struct ieee80211_hdr hdr;
+       u16 ethertype = (skb->data[12] << 8) | skb->data[13];
+       u16 hdrlen = cl_tx_prepare_wlan_hdr(cl_hw, cl_sta, skb, &hdr);
+       int rfc1042_len = 0;
+       int head_need = 0;
+       u8 enc_len = cl_key_get_cipher_len(skb);
+       u16 qos_ctrl = anchor_sw_txhdr->tid | IEEE80211_QOS_CTL_A_MSDU_PRESENT;
+
+       if (!hdrlen)
+               return -EINVAL;
+
+       if (ethertype >= ETH_P_802_3_MIN)
+               rfc1042_len = sizeof(rfc1042_header);
+
+       amsdu_anchor->hdrlen = hdrlen;
+       head_need = hdrlen + enc_len + rfc1042_len - skb_headroom(skb);
+       if (head_need > 0) {
+               head_need = ((head_need + 3) & ~3);
+               if (pskb_expand_head(skb, head_need, 0, GFP_ATOMIC))
+                       return -ENOMEM;
+       }
+
+       cl_tx_amsdu_set_sw_sub_amsdu_hdr(skb);
+
+       skb_push(skb, hdrlen + enc_len);
+       memcpy(skb->data, &hdr, hdrlen - 2);
+       memcpy(skb->data + hdrlen - 2, &qos_ctrl, 2);
+       skb_reset_mac_header(skb);
+       anchor_sw_txhdr->txdesc.e2w_natt_param.hdr_conv_enable = false;
+       anchor_sw_txhdr->hdr80211 = (struct ieee80211_hdr *)skb->data;
+
+       return 0;
+}
+
+static int cl_tx_amsdu_sw_aggregate(struct cl_hw *cl_hw,
+                                   struct cl_amsdu_ctrl *amsdu_anchor,
+                                   struct sk_buff *skb)
+{
+       struct cl_sw_txhdr *anchor_sw_txhdr = amsdu_anchor->sw_txhdr;
+       struct sk_buff *anchor_skb = anchor_sw_txhdr->skb;
+       struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(anchor_skb);
+       struct ieee80211_key_conf *key_conf = tx_info->control.hw_key;
+       u16 total_frame_len = 0;
+       struct cl_tx_queue *tx_queue = anchor_sw_txhdr->tx_queue;
+       int head_pad = 0;
+       int sub_pad = 0;
+       bool syn_rst_push = false;
+       bool tcp_ack = is_tcp_ack(skb, &syn_rst_push);
+
+       /* Worst case: rfc1042(6) + ET(2) + pad(2) = 10 */
+       if (!tcp_ack ||
+           (skb_tailroom(anchor_skb) < (skb->len + 10))) {
+               if (tx_queue->num_packets == 1)
+                       cl_txq_sched(cl_hw, tx_queue);
+               cl_tx_amsdu_anchor_init(amsdu_anchor);
+               return cl_tx_amsdu_anchor_set(cl_hw, anchor_sw_txhdr->cl_sta,
+                                             skb, anchor_sw_txhdr->tid);
+       }
+
+       if (amsdu_anchor->packet_cnt == 1 &&
+           cl_tx_amsdu_add_sw_amsdu_hdr(cl_hw, amsdu_anchor))
+               return CL_AMSDU_FAILED;
+
+       cl_tx_amsdu_set_sw_sub_amsdu_hdr(skb);
+       sub_pad = CL_SKB_DATA_ALIGN_PADS(anchor_skb->len -
+                                        amsdu_anchor->hdrlen);
+       memset(skb_push(skb, sub_pad), 0, sub_pad);
+       memcpy(skb_put(anchor_skb, skb->len), skb->data, skb->len);
+
+       kfree_skb(skb);
+       amsdu_anchor->packet_cnt++;
+       anchor_sw_txhdr->sw_amsdu_packet_cnt++;
+       head_pad = CL_SKB_DATA_ALIGN_PADS(anchor_skb->data);
+
+       if (head_pad) {
+               anchor_sw_txhdr->map_len = anchor_skb->len + head_pad;
+               anchor_sw_txhdr->txdesc.host_info.host_padding |= BIT(0);
+       } else {
+               anchor_sw_txhdr->map_len = anchor_skb->len;
+               anchor_sw_txhdr->txdesc.host_info.host_padding = 0;
+       }
+
+       total_frame_len = anchor_skb->len;
+       if (key_conf)
+               total_frame_len += key_conf->icv_len;
+
+       anchor_sw_txhdr->txdesc.umacdesc.packet_len[0] = cpu_to_le16(total_frame_len);
+
+       if (amsdu_anchor->packet_cnt == cl_hw->conf->ci_tx_sw_amsdu_max_packets ||
+           syn_rst_push) {
+               if (tx_queue->num_packets == 1)
+                       cl_txq_sched(cl_hw, tx_queue);
+               cl_tx_amsdu_anchor_init(amsdu_anchor);
+       }
+
+       return CL_AMSDU_SUB_FRAME_SET;
+}
+
+void cl_tx_amsdu_anchor_init(struct cl_amsdu_ctrl *amsdu_anchor)
+{
+       amsdu_anchor->rem_len = amsdu_anchor->max_len;
+       amsdu_anchor->sw_txhdr = NULL;
+       amsdu_anchor->packet_cnt = 0;
+       amsdu_anchor->is_sw_amsdu = false;
+}
+
+void cl_tx_amsdu_anchor_reset(struct cl_amsdu_ctrl *amsdu_anchor)
+{
+       amsdu_anchor->sw_txhdr = NULL;
+       amsdu_anchor->rem_len = 0;
+       amsdu_anchor->max_len = 0;
+       amsdu_anchor->packet_cnt = 0;
+       amsdu_anchor->is_sw_amsdu = false;
+}
+
+void cl_tx_amsdu_set_max_len(struct cl_hw *cl_hw, struct cl_sta *cl_sta, u8 tid)
+{
+       struct ieee80211_sta_vht_cap *vht_cap = &cl_sta->stainfo->sta.vht_cap;
+       struct cl_amsdu_ctrl *amsdu_anchor = &cl_sta->amsdu_anchor[tid];
+       u32 length = U32_MAX;
+
+       amsdu_anchor->max_len = 3839;
+
+       if (cl_band_is_6g(cl_hw)) {
+               u16 capa = cl_sta->stainfo->sta.he_6ghz_capa.capa;
+
+               length = (capa & IEEE80211_HE_6GHZ_CAP_MAX_MPDU_LEN) >>
+                       HE_6GHZ_CAP_MAX_MPDU_LEN_OFFSET;
+       } else if (vht_cap->vht_supported) {
+               length = vht_cap->cap & IEEE80211_VHT_CAP_MAX_MPDU_MASK;
+       }
+
+       switch (length) {
+       case IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_3895:
+               amsdu_anchor->max_len = 3895;
+               break;
+       case IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_7991:
+               amsdu_anchor->max_len = 7991;
+               break;
+       case IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_11454:
+               amsdu_anchor->max_len = 11454;
+               break;
+       default:
+               break;
+       }
+
+       amsdu_anchor->rem_len = amsdu_anchor->max_len;
+
+       cl_dbg_trace(cl_hw, "AMSDU supported - sta_idx=%u, max_len=%d\n",
+                    cl_sta->sta_idx, amsdu_anchor->max_len);
+}
+
+void cl_tx_amsdu_first_sub_frame(struct cl_sw_txhdr *sw_txhdr, struct cl_sta *cl_sta,
+                                struct sk_buff *skb, u8 tid)
+{
+       /* Set the anchor sw_txhdr */
+       cl_sta->amsdu_anchor[tid].sw_txhdr = sw_txhdr;
+
+       INIT_LIST_HEAD(&sw_txhdr->amsdu_txhdr.list);
+       sw_txhdr->amsdu_txhdr.skb = skb;
+}
+
+void cl_tx_amsdu_flush_sub_frames(struct cl_hw *cl_hw, struct cl_sw_txhdr *sw_txhdr)
+{
+       struct cl_amsdu_txhdr *amsdu_txhdr = NULL, *tmp = NULL;
+       struct sk_buff *sub_skb = NULL;
+
+       /* Free mid & last AMSDU sub frames */
+       list_for_each_entry_safe(amsdu_txhdr, tmp, &sw_txhdr->amsdu_txhdr.list, list) {
+               sub_skb = amsdu_txhdr->skb;
+               list_del(&amsdu_txhdr->list);
+
+               dma_unmap_single(cl_hw->chip->dev, amsdu_txhdr->dma_addr,
+                                (size_t)sub_skb->len, DMA_TO_DEVICE);
+               kfree_skb(sub_skb);
+               cl_tx_amsdu_txhdr_free(cl_hw, amsdu_txhdr);
+               cl_hw->tx_packet_cntr.drop.queue_flush++;
+       }
+
+       /* Free first AMSDU sub frame */
+       kfree_skb(sw_txhdr->skb);
+       cl_sw_txhdr_free(cl_hw, sw_txhdr);
+}
+
+void cl_tx_amsdu_transfer_single(struct cl_hw *cl_hw, struct cl_sw_txhdr *sw_txhdr)
+{
+       /*
+        * Transfer all skbs in sw_txhdr to a temporary list, free sw_txhdr,
+        * and then push the temporary list to the single path.
+        */
+       struct cl_amsdu_txhdr *amsdu_txhdr, *tmp;
+       struct sk_buff *skb;
+       struct cl_sta *cl_sta = sw_txhdr->cl_sta;
+       u8 tid = sw_txhdr->tid;
+
+       /* Transfer first AMSDU sub frame */
+       _cl_tx_amsdu_transfer_single(cl_hw, sw_txhdr->skb, cl_sta, tid);
+
+       /* Transfer mid & last AMSDU sub frames */
+       list_for_each_entry_safe(amsdu_txhdr, tmp, &sw_txhdr->amsdu_txhdr.list, list) {
+               skb = amsdu_txhdr->skb;
+
+               list_del(&amsdu_txhdr->list);
+               dma_unmap_single(cl_hw->chip->dev, amsdu_txhdr->dma_addr,
+                                (size_t)skb->len, DMA_TO_DEVICE);
+               cl_tx_amsdu_txhdr_free(cl_hw, amsdu_txhdr);
+
+               _cl_tx_amsdu_transfer_single(cl_hw, skb, cl_sta, tid);
+       }
+}
+
+int cl_tx_amsdu_set(struct cl_hw *cl_hw, struct cl_sta *cl_sta, struct sk_buff *skb, u8 tid)
+{
+       struct cl_amsdu_ctrl *amsdu_anchor = &cl_sta->amsdu_anchor[tid];
+       struct cl_sw_txhdr *anchor_sw_txhdr = amsdu_anchor->sw_txhdr;
+       u16 packet_len = skb->len;
+       u8 packet_cnt;
+       bool is_mesh = ieee80211_vif_is_mesh(cl_sta->cl_vif->vif);
+
+       /* Check if anchor exist */
+       if (!anchor_sw_txhdr) {
+               /* Sanity check - skb len < amsdu_max_len */
+               if (unlikely(packet_len > amsdu_anchor->max_len) || is_mesh)
+                       return CL_AMSDU_SKIP;
+               else
+                       return cl_tx_amsdu_anchor_set(cl_hw, cl_sta, skb, tid);
+       }
+
+       if (amsdu_anchor->is_sw_amsdu)
+               return cl_tx_amsdu_sw_aggregate(cl_hw, amsdu_anchor, skb);
+
+       /*
+        * 1. Check if there is enough space in AMSDU
+        * 2. Check if A-MSDU packet count is less than maximum.
+        */
+       packet_cnt = amsdu_anchor->packet_cnt;
+
+       if (amsdu_anchor->rem_len > packet_len &&
+           packet_cnt < cl_hw->txamsdu_en &&
+           !is_mesh) {
+               struct cl_amsdu_txhdr *amsdu_txhdr = NULL;
+               u8 hdr_pads = CL_SKB_DATA_ALIGN_PADS(skb->data);
+               u16 ethertype = (skb->data[12] << 8) | skb->data[13];
+               u16 total_packet_len = packet_len + hdr_pads;
+               u16 curr_amsdu_len = amsdu_anchor->max_len - amsdu_anchor->rem_len;
+               dma_addr_t dma_addr;
+               /*
+                * High number of MSDUs in AMSDU can cause underrun in the
+                * E2W module.
+                * Therefore, host is required to set Num MSDU in AMSDU using
+                * the following rules
+                *
+                * AMSDU Length      AMSDU agg size
+                * len  < 4*256      3 or less
+                * len >= 4*256      4 or less
+                * len >= 5*256      5 or less
+                * len >= 6*256      6 or less
+                * len >= 7*256      7 or less
+                * len >= 8*256      8 or less
+                */
+               u16 new_amsdu_len = curr_amsdu_len + packet_len;
+
+               if (ethertype >= ETH_P_802_3_MIN)
+                       total_packet_len += sizeof(rfc1042_header);
+
+               if (packet_cnt >= CL_AMSDU_MIN_AGG_SIZE)
+                       if (new_amsdu_len < ((packet_cnt + 1) * CL_AMSDU_CONST_LEN))
+                               return cl_tx_amsdu_anchor_set(cl_hw, cl_sta, skb, tid);
+
+               amsdu_txhdr = kmem_cache_alloc(cl_hw->amsdu_txhdr_cache, GFP_ATOMIC);
+               if (unlikely(!amsdu_txhdr)) {
+                       kfree_skb(skb);
+                       cl_dbg_err(cl_hw, "Failed to alloc amsdu txhdr\n");
+                       cl_hw->tx_packet_cntr.drop.amsdu_alloc_fail++;
+                       return CL_AMSDU_FAILED;
+               }
+
+               amsdu_txhdr->skb = skb;
+               list_add_tail(&amsdu_txhdr->list, &anchor_sw_txhdr->amsdu_txhdr.list);
+
+               /* Update anchor fields */
+               amsdu_anchor->rem_len -= total_packet_len;
+               amsdu_anchor->packet_cnt++;
+
+               /* Get DMA address for skb */
+               dma_addr = dma_map_single(cl_hw->chip->dev, (u8 *)skb->data - hdr_pads,
+                                         packet_len + hdr_pads, DMA_TO_DEVICE);
+               if (WARN_ON(dma_mapping_error(cl_hw->chip->dev, dma_addr))) {
+                       kfree_skb(skb);
+                       cl_tx_amsdu_txhdr_free(cl_hw, amsdu_txhdr);
+                       cl_dbg_err(cl_hw, "dma_mapping_error\n");
+                       cl_hw->tx_packet_cntr.drop.amsdu_dma_map_err++;
+                       return CL_AMSDU_FAILED;
+               }
+
+               /* Add AMSDU HDR len of the first packet */
+               if (amsdu_anchor->packet_cnt == 2)
+                       total_packet_len += CL_AMSDU_HDR_LEN;
+
+               amsdu_txhdr->dma_addr = dma_addr;
+
+               /* Update sw_txhdr packet_len, packet_addr, packet_cnt fields */
+               cl_tx_amsdu_anchor_umacdesc_update(&anchor_sw_txhdr->txdesc, packet_cnt,
+                                                  packet_len, dma_addr, hdr_pads);
+
+               /* If we reached max AMSDU payload count, mark anchor as NULL */
+               if (amsdu_anchor->packet_cnt >= cl_hw->txamsdu_en)
+                       cl_tx_amsdu_anchor_init(amsdu_anchor);
+
+               return CL_AMSDU_SUB_FRAME_SET;
+       }
+       /* Not enough space remain, set new anchor length is ok */
+       if (unlikely(packet_len > amsdu_anchor->max_len) || is_mesh) {
+               cl_tx_amsdu_anchor_init(amsdu_anchor);
+               return CL_AMSDU_SKIP;
+       } else {
+               return cl_tx_amsdu_anchor_set(cl_hw, cl_sta, skb, tid);
+       }
+}
+
+void cl_tx_amsdu_unset(struct cl_sw_txhdr *sw_txhdr)
+{
+       struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(sw_txhdr->skb);
+
+       tx_info->control.flags &= ~IEEE80211_TX_CTRL_AMSDU;
+
+       sw_txhdr->txdesc.e2w_txhdr_param.qos_ctrl &=
+                               ~cpu_to_le16(IEEE80211_QOS_CTL_A_MSDU_PRESENT);
+}
+
+int cl_tx_amsdu_txhdr_init(struct cl_hw *cl_hw)
+{
+       char amsdu_txhdr_cache_name[MODULE_NAME_LEN + 32] = {0};
+
+       snprintf(amsdu_txhdr_cache_name, sizeof(amsdu_txhdr_cache_name),
+                "%s_amsdu_txhdr_cache", THIS_MODULE->name);
+
+       cl_hw->amsdu_txhdr_cache = kmem_cache_create(amsdu_txhdr_cache_name,
+                                                    sizeof(struct cl_amsdu_txhdr),
+                                                    0,
+                                                    (SLAB_HWCACHE_ALIGN | SLAB_PANIC),
+                                                    NULL);
+
+       if (!cl_hw->amsdu_txhdr_cache) {
+               cl_dbg_err(cl_hw, "amsdu_txhdr_cache NULL\n");
+               return -1;
+       }
+
+       return 0;
+}
+
+void cl_tx_amsdu_txhdr_deinit(struct cl_hw *cl_hw)
+{
+       kmem_cache_destroy(cl_hw->amsdu_txhdr_cache);
+}
+
+void cl_tx_amsdu_txhdr_free(struct cl_hw *cl_hw, struct cl_amsdu_txhdr *amsdu_txhdr)
+{
+       kmem_cache_free(cl_hw->amsdu_txhdr_cache, amsdu_txhdr);
+}
--
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.
________________________________


^ permalink raw reply related	[flat|nested] 262+ messages in thread

* [RFC v1 215/256] cl8k: add tx/tx_amsdu.h
  2021-06-17 15:58 [RFC v1 000/256] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (213 preceding siblings ...)
  2021-06-17 16:01 ` [RFC v1 214/256] cl8k: add tx/tx_amsdu.c viktor.barna
@ 2021-06-17 16:01 ` viktor.barna
  2021-06-17 16:01 ` [RFC v1 216/256] cl8k: add tx/tx_inject.c viktor.barna
                   ` (42 subsequent siblings)
  257 siblings, 0 replies; 262+ messages in thread
From: viktor.barna @ 2021-06-17 16:01 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Oleksandr Savchenko, Shay Bar, Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

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

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 .../net/wireless/celeno/cl8k/tx/tx_amsdu.h    | 43 +++++++++++++++++++
 1 file changed, 43 insertions(+)
 create mode 100644 drivers/net/wireless/celeno/cl8k/tx/tx_amsdu.h

diff --git a/drivers/net/wireless/celeno/cl8k/tx/tx_amsdu.h b/drivers/net/wireless/celeno/cl8k/tx/tx_amsdu.h
new file mode 100644
index 000000000000..efabed0c561c
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/tx/tx_amsdu.h
@@ -0,0 +1,43 @@
+/* SPDX-License-Identifier: MIT */
+/* Copyright(c) 2019-2021, Celeno Communications Ltd. */
+
+#ifndef CL_TX_AMSDU_H
+#define CL_TX_AMSDU_H
+
+#include "sta.h"
+
+enum cl_amsdu_result {
+       CL_AMSDU_ANCHOR_SET,
+       CL_AMSDU_SUB_FRAME_SET,
+       CL_AMSDU_SKIP,
+       CL_AMSDU_FAILED
+};
+
+/* Max size of 802.11 WLAN header */
+#define CL_WLAN_HEADER_MAX_SIZE 36
+
+#define CL_AMSDU_MIN_AGG_SIZE 3
+#define CL_AMSDU_CONST_LEN    256
+
+struct cl_amsdu_txhdr {
+       struct list_head list;
+       struct list_head list_pool;
+       struct sk_buff *skb;
+       dma_addr_t dma_addr;
+};
+
+void cl_tx_amsdu_anchor_init(struct cl_amsdu_ctrl *amsdu_anchor);
+void cl_tx_amsdu_anchor_reset(struct cl_amsdu_ctrl *amsdu_anchor);
+void cl_tx_amsdu_set_max_len(struct cl_hw *cl_hw, struct cl_sta *cl_sta, u8 tid);
+void cl_tx_amsdu_first_sub_frame(struct cl_sw_txhdr *sw_txhdr, struct cl_sta *cl_sta,
+                                struct sk_buff *skb, u8 tid);
+void cl_tx_amsdu_flush_sub_frames(struct cl_hw *cl_hw, struct cl_sw_txhdr *sw_txhdr);
+void cl_tx_amsdu_transfer_single(struct cl_hw *cl_hw, struct cl_sw_txhdr *sw_txhdr);
+int cl_tx_amsdu_set(struct cl_hw *cl_hw, struct cl_sta *cl_sta, struct sk_buff *skb, u8 tid);
+void cl_tx_amsdu_unset(struct cl_sw_txhdr *sw_txhdr);
+
+int cl_tx_amsdu_txhdr_init(struct cl_hw *cl_hw);
+void cl_tx_amsdu_txhdr_deinit(struct cl_hw *cl_hw);
+void cl_tx_amsdu_txhdr_free(struct cl_hw *cl_hw, struct cl_amsdu_txhdr *amsdu_txhdr);
+
+#endif /* CL_TX_AMSDU_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.
________________________________


^ permalink raw reply related	[flat|nested] 262+ messages in thread

* [RFC v1 216/256] cl8k: add tx/tx_inject.c
  2021-06-17 15:58 [RFC v1 000/256] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (214 preceding siblings ...)
  2021-06-17 16:01 ` [RFC v1 215/256] cl8k: add tx/tx_amsdu.h viktor.barna
@ 2021-06-17 16:01 ` viktor.barna
  2021-06-17 16:01 ` [RFC v1 217/256] cl8k: add tx/tx_inject.h viktor.barna
                   ` (41 subsequent siblings)
  257 siblings, 0 replies; 262+ messages in thread
From: viktor.barna @ 2021-06-17 16:01 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Oleksandr Savchenko, Shay Bar, Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

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

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 .../net/wireless/celeno/cl8k/tx/tx_inject.c   | 364 ++++++++++++++++++
 1 file changed, 364 insertions(+)
 create mode 100644 drivers/net/wireless/celeno/cl8k/tx/tx_inject.c

diff --git a/drivers/net/wireless/celeno/cl8k/tx/tx_inject.c b/drivers/net/wireless/celeno/cl8k/tx/tx_inject.c
new file mode 100644
index 000000000000..a311b7b8406a
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/tx/tx_inject.c
@@ -0,0 +1,364 @@
+// SPDX-License-Identifier: MIT
+/* Copyright(c) 2019-2021, Celeno Communications Ltd. */
+
+#include "tx/tx_inject.h"
+#include "tx/tx.h"
+#include "edca.h"
+#include "reg/reg_access.h"
+#include "rate_ctrl.h"
+#include "edca.h"
+#include "tx/tx_queue.h"
+#include "ate.h"
+#include "tx/single_cfm.h"
+#include "mac_addr.h"
+#include "tx/baw.h"
+#include "ampdu.h"
+#include "key.h"
+
+#define TX_BA_SESSION_TIMEOUT 10
+
+const static u8 skb_inject_prefix_single[] = {
+       0x88, 0x02,                         /* Frame control - DATA, QOS-DATA, FROM-DS */
+       0x00, 0x00,                         /* Duration / ID */
+       0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, /* Addr1 - RA = DA */
+       0x00, 0x11, 0x22, 0x33, 0x44, 0x55, /* Addr2 - TA = BSSID */
+       0x00, 0x11, 0x22, 0x33, 0x44, 0x55, /* Addr3 - SA */
+       0x00, 0x00,                         /* Sequence control */
+       0x00, 0x00,                         /* QoS control */
+};
+
+struct sk_buff *cl_tx_inject_alloc_skb(struct cl_hw *cl_hw, struct cl_sta *cl_sta)
+{
+       u8 *skb_data = NULL;
+       u8 cyclic_data = 0;
+       u32 i;
+       struct sk_buff *skb = NULL;
+       struct ieee80211_tx_info *tx_info = NULL;
+       struct cl_tx_inject *tx_inject = &cl_hw->tx_inject;
+       u32 prefix_size = sizeof(skb_inject_prefix_single);
+
+       skb = dev_alloc_skb(tx_inject->packet_len);
+
+       if (!skb)
+               return NULL;
+
+       tx_info = IEEE80211_SKB_CB(skb);
+       memset(tx_info, 0, sizeof(struct ieee80211_tx_info));
+
+       /* Copy data */
+       skb_data = skb_put(skb, tx_inject->packet_len);
+
+       memcpy(skb_data, skb_inject_prefix_single, prefix_size);
+
+       if (cl_sta) {
+               skb->dev = cl_sta->cl_vif->dev;
+               struct ieee80211_qos_hdr *qos_hdr = (struct ieee80211_qos_hdr *)skb->data;
+
+               cl_mac_addr_copy(qos_hdr->addr1, cl_sta->addr);
+               cl_mac_addr_copy(qos_hdr->addr2, cl_sta->cl_vif->vif->addr);
+               cl_mac_addr_copy(qos_hdr->addr3, cl_sta->cl_vif->vif->addr);
+       }
+
+       for (i = prefix_size; i < tx_inject->packet_len; i++) {
+               *(skb_data + i) = cyclic_data;
+               cyclic_data++;
+       }
+
+       tx_info->band = cl_hw->nl_band;
+       tx_info->flags = IEEE80211_TX_CTL_INJECTED;
+
+       if (cl_sta) {
+               tx_info->hw_queue = CL_HWQ_BE;
+               tx_info->control.vif = cl_sta->cl_vif->vif;
+               tx_info->control.hw_key = cl_key_get(cl_sta);
+       } else {
+               struct cl_vif *cl_vif = cl_vif_get_first(cl_hw);
+
+               if (!cl_vif) {
+                       kfree_skb(skb);
+                       return NULL;
+               }
+
+               tx_info->hw_queue = CL_HWQ_VO;
+               tx_info->flags |= IEEE80211_TX_CTL_NO_ACK;
+               tx_info->control.vif = cl_vif->vif;
+       }
+
+       tx_inject->alloc_counter++;
+
+       return skb;
+}
+
+static struct cl_sta *get_first_sta(struct cl_hw *cl_hw)
+{
+       return list_first_entry_or_null(&cl_hw->cl_sta_db.head, struct cl_sta, list);
+}
+
+static struct cl_sta *get_next_sta(struct cl_hw *cl_hw, struct cl_sta *cl_sta)
+{
+       if (list_is_last(&cl_sta->list, &cl_hw->cl_sta_db.head))
+               return get_first_sta(cl_hw);
+       else
+               return list_next_entry(cl_sta, list);
+}
+
+static void cl_tx_inject_tasklet(unsigned long data)
+{
+       struct cl_hw *cl_hw = (struct cl_hw *)data;
+       struct cl_tx_inject *tx_inject = &cl_hw->tx_inject;
+       struct sk_buff *skb = NULL;
+
+       while ((tx_inject->current_counter < tx_inject->max_counter) || tx_inject->continuous) {
+               u16 queue_idx = tx_inject->cl_sta ?
+                       QUEUE_IDX(tx_inject->cl_sta->sta_idx, TX_INJECT_SINGLE_AC) :
+                       HIGH_PRIORITY_QUEUE;
+
+               if (cl_txq_single_is_full(cl_hw, queue_idx))
+                       return;
+
+               if (tx_inject->alloc_counter == TX_INJECT_MAX_SKBS)
+                       return;
+
+               skb = cl_tx_inject_alloc_skb(cl_hw, tx_inject->cl_sta);
+
+               if (!skb)
+                       return;
+
+               cl_tx_single(cl_hw, tx_inject->cl_sta, skb, false, true);
+
+               if (tx_inject->cl_sta)
+                       tx_inject->cl_sta = get_next_sta(cl_hw, tx_inject->cl_sta);
+
+               if (!tx_inject->continuous)
+                       tx_inject->current_counter++;
+       }
+}
+
+static void edca_set_aggressive(struct cl_hw *cl_hw)
+{
+       struct cl_tx_inject *tx_inject = &cl_hw->tx_inject;
+
+       if (!tx_inject->aggressive_edca) {
+               struct edca_params aggressive_params = {
+                       .aifsn = 1, .cw_min = 0, .cw_max = 1, .txop = 0
+               };
+
+               cl_edca_set(cl_hw, EDCA_AC_VO, &aggressive_params, NULL);
+               tx_inject->aggressive_edca = true;
+       }
+}
+
+static void edca_restore_default(struct cl_hw *cl_hw)
+{
+       struct cl_tx_inject *tx_inject = &cl_hw->tx_inject;
+
+       if (tx_inject->aggressive_edca) {
+               cl_edca_restore_conf(cl_hw, EDCA_AC_VO);
+               tx_inject->aggressive_edca = false;
+       }
+}
+
+void cl_tx_inject_init(struct cl_hw *cl_hw)
+{
+       tasklet_init(&cl_hw->tx_inject.tasklet, cl_tx_inject_tasklet, (unsigned long)cl_hw);
+}
+
+void cl_tx_inject_close(struct cl_hw *cl_hw)
+{
+       struct cl_tx_inject *tx_inject = &cl_hw->tx_inject;
+
+       tasklet_kill(&tx_inject->tasklet);
+}
+
+void cl_tx_inject_reset(struct cl_hw *cl_hw)
+{
+       struct cl_tx_inject *tx_inject = &cl_hw->tx_inject;
+
+       /* Return packet_len tp default */
+       tx_inject->packet_len = TX_INJECT_SKB_LEN_DEFAULT;
+       tx_inject->cl_sta = NULL;
+}
+
+static void _cl_tx_inject_start(struct cl_tx_inject *tx_inject,
+                               u32 max_counter,
+                               bool continuous)
+
+{
+       tx_inject->current_counter = 0;
+       tx_inject->max_counter = max_counter;
+       tx_inject->continuous = continuous;
+       tx_inject->is_running = true;
+}
+
+void cl_tx_inject_start(struct cl_hw *cl_hw, u32 tx_cnt)
+{
+       struct cl_tx_inject *tx_inject = &cl_hw->tx_inject;
+
+       edca_set_aggressive(cl_hw);
+
+       _cl_tx_inject_start(tx_inject, tx_cnt, false);
+
+       if (!tx_inject->cl_sta)
+               tx_inject->cl_sta = get_first_sta(cl_hw);
+
+       tasklet_schedule(&tx_inject->tasklet);
+}
+
+void cl_tx_inject_start_continuous(struct cl_hw *cl_hw)
+{
+       struct cl_tx_inject *tx_inject = &cl_hw->tx_inject;
+
+       edca_set_aggressive(cl_hw);
+
+       _cl_tx_inject_start(tx_inject, 0, true);
+
+       if (!tx_inject->cl_sta)
+               tx_inject->cl_sta = get_first_sta(cl_hw);
+
+       tasklet_schedule(&tx_inject->tasklet);
+}
+
+static void _cl_tx_inject_stop(struct cl_tx_inject *tx_inject)
+{
+       tx_inject->current_counter = 0;
+       tx_inject->max_counter = 0;
+       tx_inject->continuous = false;
+       tx_inject->is_running = false;
+}
+
+void cl_tx_inject_stop(struct cl_hw *cl_hw)
+{
+       struct cl_tx_inject *tx_inject = &cl_hw->tx_inject;
+
+       /* Return to default EDCA */
+       edca_restore_default(cl_hw);
+
+       _cl_tx_inject_stop(tx_inject);
+
+       if (tx_inject->cl_sta) {
+               struct cl_sta *cl_sta = NULL;
+
+               list_for_each_entry(cl_sta, &cl_hw->cl_sta_db.head, list) {
+                       u16 queue_idx = QUEUE_IDX(cl_sta->sta_idx, TX_INJECT_SINGLE_AC);
+
+                       cl_txq_flush_single(cl_hw, queue_idx);
+                       cl_single_cfm_poll_empty(cl_hw, queue_idx);
+               }
+       } else {
+               cl_txq_flush_single(cl_hw, HIGH_PRIORITY_QUEUE);
+               cl_single_cfm_poll_empty(cl_hw, HIGH_PRIORITY_QUEUE);
+       }
+}
+
+void cl_tx_inject_stop_in_recovery(struct cl_hw *cl_hw)
+{
+       /*
+        * When recovery starts:
+        *  - change edca back to default
+        *  - stop traffic
+        *  - kill tasklet
+        *  - free stations
+        */
+       struct cl_tx_inject *tx_inject = &cl_hw->tx_inject;
+
+       if (!tx_inject->is_running)
+               return;
+
+       pr_debug("[TX inject] Stop due to recovery\n");
+
+       edca_restore_default(cl_hw);
+
+       _cl_tx_inject_stop(tx_inject);
+
+       cl_tx_inject_close(cl_hw);
+
+       cl_hw->ate_db.active = false;
+       cl_hw->entry_fixed_rate = false;
+}
+
+void cl_tx_inject_stop_traffic(struct cl_hw *cl_hw)
+{
+       struct cl_tx_inject *tx_inject = &cl_hw->tx_inject;
+
+       _cl_tx_inject_stop(tx_inject);
+}
+
+bool cl_tx_inject_is_running(struct cl_hw *cl_hw)
+{
+       return cl_hw->tx_inject.is_running;
+}
+
+static void cl_tx_inject_cfm_single(struct cl_hw *cl_hw)
+{
+       struct cl_sta *cl_sta = NULL;
+
+       cl_sta_lock(cl_hw);
+
+       list_for_each_entry(cl_sta, &cl_hw->cl_sta_db.head, list) {
+               u16 queue_idx =  QUEUE_IDX(cl_sta->sta_idx, TX_INJECT_SINGLE_AC);
+
+               cl_txq_single_sched(cl_hw, queue_idx);
+       }
+
+       cl_sta_unlock(cl_hw);
+
+       cl_txq_single_sched(cl_hw, HIGH_PRIORITY_QUEUE);
+}
+
+void cl_tx_inject_cfm(struct cl_hw *cl_hw)
+{
+       struct cl_tx_inject *tx_inject = &cl_hw->tx_inject;
+
+       tx_inject->alloc_counter--;
+
+       if (tx_inject->current_counter < tx_inject->max_counter || tx_inject->continuous)
+               tasklet_schedule(&tx_inject->tasklet);
+       else
+               cl_tx_inject_cfm_single(cl_hw);
+
+       if (tx_inject->is_running &&
+           tx_inject->alloc_counter == 0 &&
+           tx_inject->current_counter == tx_inject->max_counter) {
+               pr_debug("[TX inject] Complete - %u packets\n", tx_inject->max_counter);
+               _cl_tx_inject_stop(tx_inject);
+       }
+}
+
+void cl_tx_inject_sta_remove(struct cl_hw *cl_hw, struct cl_sta *cl_sta)
+{
+       struct cl_tx_inject *tx_inject = &cl_hw->tx_inject;
+       bool stop_ate = false;
+
+       tasklet_disable(&tx_inject->tasklet);
+
+       if (cl_tx_inject_is_running(cl_hw)) {
+               if (tx_inject->cl_sta == cl_sta) {
+                       tx_inject->cl_sta = get_next_sta(cl_hw, cl_sta);
+
+                       /*
+                        * If next STA is the same then only the current cl_sta exists.
+                        * In this case - stop ATE
+                        */
+                       if (tx_inject->cl_sta == cl_sta)
+                               stop_ate = true;
+               }
+       }
+
+       if (stop_ate)
+               cl_ate_stop(cl_hw->hw->wiphy, NULL, NULL, 0);
+
+       tasklet_enable(&tx_inject->tasklet);
+}
+
+int cl_tx_inject_set_length(struct cl_hw *cl_hw, u32 length)
+{
+       if (length >= TX_INJECT_SKB_LEN_MIN && length <= TX_INJECT_SKB_LEN_MAX) {
+               cl_hw->tx_inject.packet_len = length;
+               return 0;
+       }
+
+       pr_debug("[TX inject] Packet length must be between %u and %u\n",
+                TX_INJECT_SKB_LEN_MIN, TX_INJECT_SKB_LEN_MAX);
+
+       return -EINVAL;
+}
--
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.
________________________________


^ permalink raw reply related	[flat|nested] 262+ messages in thread

* [RFC v1 217/256] cl8k: add tx/tx_inject.h
  2021-06-17 15:58 [RFC v1 000/256] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (215 preceding siblings ...)
  2021-06-17 16:01 ` [RFC v1 216/256] cl8k: add tx/tx_inject.c viktor.barna
@ 2021-06-17 16:01 ` viktor.barna
  2021-06-17 16:01 ` [RFC v1 218/256] cl8k: add tx/tx_queue.c viktor.barna
                   ` (40 subsequent siblings)
  257 siblings, 0 replies; 262+ messages in thread
From: viktor.barna @ 2021-06-17 16:01 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Oleksandr Savchenko, Shay Bar, Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

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

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 .../net/wireless/celeno/cl8k/tx/tx_inject.h   | 39 +++++++++++++++++++
 1 file changed, 39 insertions(+)
 create mode 100644 drivers/net/wireless/celeno/cl8k/tx/tx_inject.h

diff --git a/drivers/net/wireless/celeno/cl8k/tx/tx_inject.h b/drivers/net/wireless/celeno/cl8k/tx/tx_inject.h
new file mode 100644
index 000000000000..9f20c336985a
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/tx/tx_inject.h
@@ -0,0 +1,39 @@
+/* SPDX-License-Identifier: MIT */
+/* Copyright(c) 2019-2021, Celeno Communications Ltd. */
+
+#ifndef CL_TX_INJECT_H
+#define CL_TX_INJECT_H
+
+#include <linux/version.h>
+#include <linux/kernel.h>
+#include <linux/kmod.h>
+#include <linux/debugfs.h>
+#include <linux/string.h>
+
+#include "hw.h"
+
+#define TX_INJECT_SINGLE_AC       AC_BE
+#define TX_INJECT_MAX_SKBS        8192
+#define TX_INJECT_SKB_LEN_MAX     4096
+#define TX_INJECT_SKB_LEN_MIN     16
+#define TX_INJECT_SKB_LEN_DEFAULT 1024
+
+extern int ce_tx_inject_real_sta;
+
+void cl_tx_inject_init(struct cl_hw *cl_hw);
+void cl_tx_inject_close(struct cl_hw *cl_hw);
+void cl_tx_inject_reset(struct cl_hw *cl_hw);
+void cl_tx_inject_start(struct cl_hw *cl_hw, u32 tx_cnt);
+void cl_tx_inject_start_continuous(struct cl_hw *cl_hw);
+void cl_tx_inject_stop(struct cl_hw *cl_hw);
+void cl_tx_inject_stop_in_recovery(struct cl_hw *cl_hw);
+void cl_tx_inject_stop_traffic(struct cl_hw *cl_hw);
+void cl_tx_inject_stop_ba_session(struct cl_hw *cl_hw, struct cl_sta *cl_sta, u8 tid);
+bool cl_tx_inject_is_running(struct cl_hw *cl_hw);
+void cl_tx_inject_cfm(struct cl_hw *cl_hw);
+void cl_tx_inject_sta_remove(struct cl_hw *cl_hw, struct cl_sta *cl_sta);
+void cl_tx_inject_iface_remove(struct cl_hw *cl_hw, struct cl_vif *cl_vif);
+int cl_tx_inject_set_length(struct cl_hw *cl_hw, u32 length);
+struct sk_buff *cl_tx_inject_alloc_skb(struct cl_hw *cl_hw, struct cl_sta *cl_sta);
+
+#endif /* CL_TX_INJECT_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.
________________________________


^ permalink raw reply related	[flat|nested] 262+ messages in thread

* [RFC v1 218/256] cl8k: add tx/tx_queue.c
  2021-06-17 15:58 [RFC v1 000/256] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (216 preceding siblings ...)
  2021-06-17 16:01 ` [RFC v1 217/256] cl8k: add tx/tx_inject.h viktor.barna
@ 2021-06-17 16:01 ` viktor.barna
  2021-06-17 16:01 ` [RFC v1 219/256] cl8k: add tx/tx_queue.h viktor.barna
                   ` (39 subsequent siblings)
  257 siblings, 0 replies; 262+ messages in thread
From: viktor.barna @ 2021-06-17 16:01 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Oleksandr Savchenko, Shay Bar, Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

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

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 .../net/wireless/celeno/cl8k/tx/tx_queue.c    | 1620 +++++++++++++++++
 1 file changed, 1620 insertions(+)
 create mode 100644 drivers/net/wireless/celeno/cl8k/tx/tx_queue.c

diff --git a/drivers/net/wireless/celeno/cl8k/tx/tx_queue.c b/drivers/net/wireless/celeno/cl8k/tx/tx_queue.c
new file mode 100644
index 000000000000..18c5bd2b81f7
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/tx/tx_queue.c
@@ -0,0 +1,1620 @@
+// SPDX-License-Identifier: MIT
+/* Copyright(c) 2019-2021, Celeno Communications Ltd. */
+
+#include <net/cfg80211.h>
+#include <net/mac80211.h>
+#include <linux/ieee80211.h>
+#include <linux/types.h>
+
+#include "tx/tx_queue.h"
+#include "tx/tx.h"
+#include "tx/sw_txhdr.h"
+#include "tx/tx_amsdu.h"
+#include "tx/baw.h"
+#ifdef CONFIG_CL_PCIE
+#include "bus/pci/ipc.h"
+#endif
+#include "tx/agg_cfm.h"
+
+const u8 cl_tid2hwq[IEEE80211_NUM_TIDS] = {
+       CL_HWQ_BE,
+       CL_HWQ_BK,
+       CL_HWQ_BK,
+       CL_HWQ_BE,
+       CL_HWQ_VI,
+       CL_HWQ_VI,
+       CL_HWQ_VO,
+       CL_HWQ_VO,
+       /* At the moment, all others TID are mapped to BE */
+       CL_HWQ_BE,
+       CL_HWQ_BE,
+       CL_HWQ_BE,
+       CL_HWQ_BE,
+       CL_HWQ_BE,
+       CL_HWQ_BE,
+       CL_HWQ_BE,
+       CL_HWQ_BE,
+};
+
+static u32 cl_txq_total_dump_drv(struct cl_tx_queue *tx_queue)
+{
+       return tx_queue->dump_queue_full + tx_queue->dump_dma_map_fail;
+}
+
+static void cl_txq_sched_list_add(struct cl_tx_queue *tx_queue, struct cl_hw *cl_hw)
+{
+       /* Add to schedule queue */
+       if (tx_queue->sched)
+               return;
+
+       tx_queue->sched = true;
+       if (tx_queue->type == QUEUE_TYPE_AGG)
+               list_add_tail(&tx_queue->sched_list, &cl_hw->list_sched_q_agg);
+       else
+               list_add_tail(&tx_queue->sched_list, &cl_hw->list_sched_q_single);
+}
+
+static void cl_txq_sched_list_remove(struct cl_tx_queue *tx_queue)
+{
+       /* Remove from schedule queue */
+       if (tx_queue->sched) {
+               tx_queue->sched = false;
+               list_del(&tx_queue->sched_list);
+       }
+}
+
+static void cl_txq_sched_list_remove_if_empty(struct cl_tx_queue *tx_queue)
+{
+       /* If queue is empty remove it from schedule list */
+       if (list_empty(&tx_queue->hdrs))
+               cl_txq_sched_list_remove(tx_queue);
+}
+
+static void cl_txq_transfer_single_to_agg(struct cl_hw *cl_hw,
+                                         struct cl_tx_queue *single_queue,
+                                         struct cl_tx_queue *agg_queue, u8 tid)
+{
+       struct cl_sw_txhdr *sw_txhdr, *sw_txhdr_tmp;
+       struct ieee80211_tx_info *tx_info;
+       struct sk_buff *skb;
+       u8 hdr_pads;
+
+       spin_lock_bh(&cl_hw->tx_lock_single);
+
+       if (single_queue->num_packets == 0)
+               goto out;
+
+       list_for_each_entry_safe(sw_txhdr, sw_txhdr_tmp, &single_queue->hdrs, tx_queue_list) {
+               if (sw_txhdr->tid != tid)
+                       continue;
+
+               if (!ieee80211_is_data_qos(sw_txhdr->fc))
+                       continue;
+
+               cl_hw->tx_packet_cntr.transfer.single_to_agg++;
+
+               /* Remove from single queue */
+               list_del(&sw_txhdr->tx_queue_list);
+
+               /* Update single queue counters */
+               single_queue->num_packets--;
+               single_queue->total_packets--;
+
+               /* Turn on AMPDU flag */
+               skb = sw_txhdr->skb;
+               tx_info = IEEE80211_SKB_CB(skb);
+               tx_info->flags |= IEEE80211_TX_CTL_AMPDU;
+
+               /* Push skb to agg queue */
+               hdr_pads = CL_SKB_DATA_ALIGN_PADS(skb->data);
+               cl_tx_agg_prep(cl_hw, sw_txhdr, skb->len, hdr_pads, false);
+               agg_queue->total_packets++;
+               sw_txhdr->tx_queue = agg_queue;
+               cl_txq_push(cl_hw, sw_txhdr);
+       }
+
+       /* If single queue is empty remove it from schedule list */
+       cl_txq_sched_list_remove_if_empty(single_queue);
+
+out:
+       spin_unlock_bh(&cl_hw->tx_lock_single);
+}
+
+static void cl_txq_delete_packets(struct cl_hw *cl_hw, struct cl_tx_queue *tx_queue, u8 sta_idx)
+{
+       struct cl_sw_txhdr *sw_txhdr, *sw_txhdr_tmp;
+
+       list_for_each_entry_safe(sw_txhdr, sw_txhdr_tmp, &tx_queue->hdrs, tx_queue_list) {
+               /*
+                * Brodcast frames do not have cl_sta and should not be
+                * deleted at station remove sequence.
+                */
+               if (!sw_txhdr->cl_sta)
+                       continue;
+
+               if (sw_txhdr->sta_idx != sta_idx)
+                       continue;
+
+               list_del(&sw_txhdr->tx_queue_list);
+               tx_queue->num_packets--;
+
+               cl_tx_single_free_skb(cl_hw, sw_txhdr->skb);
+               cl_sw_txhdr_free(cl_hw, sw_txhdr);
+       }
+
+       /* If queue is empty remove it from schedule list */
+       cl_txq_sched_list_remove_if_empty(tx_queue);
+}
+
+static void cl_txq_reset_counters(struct cl_tx_queue *tx_queue)
+{
+       tx_queue->total_fw_push_desc = 0;
+       tx_queue->total_fw_push_skb = 0;
+       tx_queue->total_fw_cfm = 0;
+       tx_queue->total_packets = 0;
+       tx_queue->dump_queue_full = 0;
+       tx_queue->dump_dma_map_fail = 0;
+
+       memset(tx_queue->stats_hw_amsdu_cnt, 0,
+              sizeof(tx_queue->stats_hw_amsdu_cnt));
+
+       memset(tx_queue->stats_sw_amsdu_cnt, 0,
+              sizeof(tx_queue->stats_sw_amsdu_cnt));
+}
+
+static u16 cl_txq_desc_in_fw(struct cl_tx_queue *tx_queue)
+{
+       return (tx_queue->fw_max_size - tx_queue->fw_free_space);
+}
+
+static void cl_txq_reset_counters_during_traffic(struct cl_tx_queue *tx_queue)
+{
+       /*
+        * This function can be called during traffic, while descriptors
+        * are waiting in firmware. We set total_fw_cfm to minus the number
+        * of descriptors in firmware so that after confirmation arrives
+        * total_fw_cfm will be equal to total_fw_push_desc.
+        */
+       u32 desc_in_fw = cl_txq_desc_in_fw(tx_queue);
+
+       cl_txq_reset_counters(tx_queue);
+       tx_queue->total_fw_cfm = -desc_in_fw;
+}
+
+static void cl_txq_agg_size_set(struct cl_hw *cl_hw)
+{
+       struct cl_tx_queue *tx_queue = NULL;
+       u16 new_size = 0;
+       u16 drv_max_size = 0;
+       int i = 0;
+       int j = 0;
+
+       if (!cl_hw->used_agg_queues || !cl_hw->conf->ci_tx_packet_limit)
+               return;
+
+       new_size = cl_hw->conf->ci_tx_packet_limit / cl_hw->used_agg_queues;
+       drv_max_size = max(new_size, cl_hw->conf->ci_tx_queue_size_agg);
+
+       for (i = 0; i < IPC_MAX_BA_SESSIONS; i++) {
+               tx_queue = &cl_hw->tx_queues.agg[i];
+
+               if (!tx_queue->cl_sta)
+                       continue;
+
+               tx_queue->max_packets = drv_max_size;
+
+               j++;
+               if (j == cl_hw->used_agg_queues)
+                       break;
+       }
+
+       cl_dbg_trace(cl_hw, "drv_max_size = %u\n", drv_max_size);
+}
+
+static int cl_txq_request_find(struct cl_hw *cl_hw, u8 sta_idx, u8 tid)
+{
+       int i = 0;
+       struct cl_req_agg_db *req_agg_db = NULL;
+       u8 req_agg_queues = 0;
+
+       for (i = 0; (i < IPC_MAX_BA_SESSIONS) && (req_agg_queues < cl_hw->req_agg_queues); i++) {
+               req_agg_db = &cl_hw->req_agg_db[i];
+
+               if (!req_agg_db->is_used)
+                       continue;
+
+               req_agg_queues++;
+
+               if (sta_idx == req_agg_db->sta_idx && tid == req_agg_db->tid)
+                       return i;
+       }
+
+       return -1;
+}
+
+static void cl_txq_traffic_counters_print_bcmc(struct cl_hw *cl_hw,
+                                              char **buf, int *len, ssize_t *buf_size)
+{
+       struct cl_tx_queue *tx_queue = &cl_hw->tx_queues.bcmc;
+       unsigned long flags;
+       u8 hw_index;
+       u32 total_packets;
+       u16 fw_curr;
+       u32 total_push;
+       u32 total_cfm;
+       u32 dump;
+
+       spin_lock_irqsave(&cl_hw->tx_lock_bcmc, flags);
+
+       hw_index = tx_queue->hw_index;
+       total_packets = tx_queue->total_packets;
+       fw_curr = cl_txq_desc_in_fw(tx_queue);
+       total_push = tx_queue->total_fw_push_skb;
+       total_cfm = tx_queue->total_fw_cfm;
+       dump = cl_txq_total_dump_drv(tx_queue);
+
+       spin_unlock_irqrestore(&cl_hw->tx_lock_bcmc, flags);
+
+       if (total_packets == 0)
+               return;
+
+       cl_snprintf(buf, len, buf_size,
+                   "\nTX MULTICAST AND BOROADCAST QUEUE (MAX 1):\n"
+                   "|-----------------------------------------------------------|\n"
+                   "| hw  | driver   | fw      | fw total | fw total | dump     |\n"
+                   "| idx | total    | current | push     | cfm      |          |\n"
+                   "|-----+----------+---------+----------+----------+----------|\n"
+                   "| %3u |%10u|%9u|%10u|%10u|%10u|\n",
+                   hw_index, total_packets, fw_curr, total_push, total_cfm, dump);
+       cl_snprintf(buf, len, buf_size,
+                   "|-----------------------------------------------------------|\n");
+}
+
+static void cl_txq_traffic_counters_print_single(struct cl_hw *cl_hw,
+                                                char **buf, int *len, ssize_t *buf_size)
+{
+       u16 queue_idx = 0;
+       u32 sta_idx = 0, ac = 0;
+       struct cl_tx_queue *tx_queue;
+
+       cl_snprintf(buf, len, buf_size,
+                   "\nTX SINGLE QUEUES (MAX %d):\n", MAX_SINGLE_QUEUES);
+       cl_snprintf(buf, len, buf_size,
+                   "|----------------------------------------------------------------------"
+                   "----------|\n"
+                   "| idx | sta | ac | driver   | driver  | fw      | fw total | fw total |"
+                   " dump     |\n"
+                   "|     |     |    | total    | current | current | push     | cfm      |"
+                   "          |\n"
+                   "|-----+-----+----+----------+---------+---------+----------+----------+"
+                   "----------|\n");
+
+       spin_lock_bh(&cl_hw->tx_lock_single);
+
+       for (sta_idx = 0; sta_idx < FW_MAX_NUM_STA; sta_idx++) {
+               for (ac = 0; ac < AC_MAX; ac++) {
+                       queue_idx = QUEUE_IDX(sta_idx, ac);
+                       tx_queue = &cl_hw->tx_queues.single[queue_idx];
+
+                       if (tx_queue->total_packets == 0)
+                               continue;
+
+                       if (tx_queue->index == HIGH_PRIORITY_QUEUE)
+                               cl_snprintf(buf, len, buf_size,
+                                           "|-----+-----+----+----------+---------+---------+"
+                                           "----------+----------+----------|\n");
+
+                       cl_snprintf(buf, len, buf_size,
+                                   "| %3u | %3u | %2u |%10u|%9u|%9u|%10u|%10u|%10u|\n",
+                                   tx_queue->index,
+                                   sta_idx,
+                                   tx_queue->hw_index,
+                                   tx_queue->total_packets,
+                                   tx_queue->num_packets,
+                                   cl_txq_desc_in_fw(tx_queue),
+                                   tx_queue->total_fw_push_skb,
+                                   tx_queue->total_fw_cfm,
+                                   cl_txq_total_dump_drv(tx_queue));
+               }
+       }
+
+       cl_snprintf(buf, len, buf_size,
+                   "|------------------------------------------------------------------------"
+                   "--------|\n");
+
+       spin_unlock_bh(&cl_hw->tx_lock_single);
+}
+
+static void cl_txq_traffic_counters_print_agg(struct cl_hw *cl_hw,
+                                             char **buf, int *len, ssize_t *buf_size)
+{
+       u32 ba_idx = 0;
+       struct cl_tx_queue *tx_queue;
+
+       spin_lock_bh(&cl_hw->tx_lock_agg);
+
+       if (cl_hw->used_agg_queues == 0)
+               goto out;
+
+       cl_snprintf(buf, len, buf_size,
+                   "\nTX AGGREGATION QUEUES (MAX %d):\n", IPC_MAX_BA_SESSIONS);
+       cl_snprintf(buf, len, buf_size,
+                   "|-----------------------------------------------------------------------"
+                   "---------------------|\n"
+                   "| idx | sta | tid | driver   | driver  | fw      | fw total | fw total |"
+                   " fw total | dump     |\n"
+                   "|     | idx |     | total    | current | current | push skb | push desc|"
+                   " cfm      |          |\n"
+                   "|-----+-----+-----+----------+---------+---------+----------+----------+"
+                   "----------+----------|\n");
+
+       for (ba_idx = 0; ba_idx < IPC_MAX_BA_SESSIONS; ba_idx++) {
+               tx_queue = &cl_hw->tx_queues.agg[ba_idx];
+
+               if (!cl_hw->tx_queues.agg[ba_idx].cl_sta)
+                       continue;
+
+               if (tx_queue->total_packets == 0)
+                       continue;
+
+               cl_snprintf(buf, len, buf_size,
+                           "| %3u | %3u | %3u |%10u|%9u|%9u|%10u|%10u|%10u|%10u|\n",
+                           tx_queue->index,
+                           tx_queue->cl_sta->sta_idx,
+                           tx_queue->tid,
+                           tx_queue->total_packets,
+                           tx_queue->num_packets,
+                           cl_txq_desc_in_fw(tx_queue),
+                           tx_queue->total_fw_push_skb,
+                           tx_queue->total_fw_push_desc,
+                           tx_queue->total_fw_cfm,
+                           cl_txq_total_dump_drv(tx_queue));
+       }
+
+       cl_snprintf(buf, len, buf_size,
+                   "|------------------------------------------------------------------------"
+                   "--------------------|\n");
+
+out:
+       spin_unlock_bh(&cl_hw->tx_lock_agg);
+}
+
+static void cl_txq_traffic_counters_print_mac(struct cl_hw *cl_hw,
+                                             char **buf, int *len, ssize_t *buf_size)
+{
+       struct ieee80211_local *local = hw_to_local(cl_hw->hw);
+       u32 i = 0, total_len = 0, q_len[IEEE80211_MAX_QUEUES] = {0};
+       unsigned long flags;
+
+       spin_lock_irqsave(&local->queue_stop_reason_lock, flags);
+
+       for (i = 0; i < IEEE80211_MAX_QUEUES; i++) {
+               q_len[i] = skb_queue_len(&local->pending[i]);
+               total_len += q_len[i];
+       }
+
+       spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags);
+
+       if (total_len == 0)
+               return;
+
+       cl_snprintf(buf, len, buf_size,
+                   "\nMAC80211 PENDING QUEUES (MAX %d):\n", IEEE80211_MAX_QUEUES);
+       cl_snprintf(buf, len, buf_size,
+                   "|--------------------|\n"
+                   "| queue |  current   |\n"
+                   "|-------+------------|\n");
+
+       for (i = 0; i < IEEE80211_MAX_QUEUES; i++)
+               if (q_len[i] > 0)
+                       cl_snprintf(buf, len, buf_size, "| %5u | %10u |\n", i, q_len[i]);
+
+       cl_snprintf(buf, len, buf_size, "|--------------------|\n");
+}
+
+static int cl_txq_traffic_counters_print(struct cl_hw *cl_hw)
+{
+       char *buf = NULL;
+       ssize_t buf_size;
+       int err = 0;
+       int len = 0;
+
+       cl_txq_traffic_counters_print_bcmc(cl_hw, &buf, &len, &buf_size);
+       cl_txq_traffic_counters_print_single(cl_hw, &buf, &len, &buf_size);
+       cl_txq_traffic_counters_print_agg(cl_hw, &buf, &len, &buf_size);
+       cl_txq_traffic_counters_print_mac(cl_hw, &buf, &len, &buf_size);
+
+       err = cl_vendor_reply(cl_hw, buf, len);
+       kfree(buf);
+
+       return err;
+}
+
+static void cl_txq_drop_reasons_print_bcmc(struct cl_hw *cl_hw,
+                                          char **buf, int *len, ssize_t *buf_size)
+{
+       u32 total = 0;
+       u32 dump_queue_full = 0;
+       u32 dump_dma_map_fail = 0;
+       struct cl_tx_queue *tx_queue = &cl_hw->tx_queues.bcmc;
+       unsigned long flags;
+
+       spin_lock_irqsave(&cl_hw->tx_lock_bcmc, flags);
+
+       total = cl_txq_total_dump_drv(tx_queue);
+       dump_queue_full = tx_queue->dump_queue_full;
+       dump_dma_map_fail = tx_queue->dump_dma_map_fail;
+
+       spin_unlock_irqrestore(&cl_hw->tx_lock_bcmc, flags);
+
+       if (total > 0)
+               cl_snprintf(buf, len, buf_size,
+                           "|bcmc  |     |%10u|%10u|%10u|\n",
+                           dump_queue_full, dump_dma_map_fail, total);
+}
+
+static void cl_txq_drop_reasons_print_single(struct cl_hw *cl_hw,
+                                            char **buf, int *len, ssize_t *buf_size)
+{
+       u32 i = 0, total = 0;
+       struct cl_tx_queue *tx_queue;
+
+       spin_lock_bh(&cl_hw->tx_lock_single);
+
+       for (i = 0; i < MAX_SINGLE_QUEUES; i++) {
+               tx_queue = &cl_hw->tx_queues.single[i];
+               total = cl_txq_total_dump_drv(tx_queue);
+
+               if (total == 0)
+                       continue;
+
+               cl_snprintf(buf, len, buf_size,
+                           "|single|%5u|%10u|%10u|%10u|\n",
+                           tx_queue->index,
+                           tx_queue->dump_queue_full,
+                           tx_queue->dump_dma_map_fail,
+                           total);
+       }
+
+       spin_unlock_bh(&cl_hw->tx_lock_single);
+}
+
+static void cl_txq_drop_reasons_print_agg(struct cl_hw *cl_hw,
+                                         char **buf, int *len, ssize_t *buf_size)
+{
+       u32 i = 0, total = 0;
+       struct cl_tx_queue *tx_queue;
+
+       spin_lock_bh(&cl_hw->tx_lock_agg);
+
+       for (i = 0; i < IPC_MAX_BA_SESSIONS; i++) {
+               tx_queue = &cl_hw->tx_queues.agg[i];
+               total = cl_txq_total_dump_drv(tx_queue);
+
+               if (total == 0)
+                       continue;
+
+               cl_snprintf(buf, len, buf_size,
+                           "|agg   |%5u|%10u|%10u|%10u|\n",
+                           tx_queue->index,
+                           tx_queue->dump_queue_full,
+                           tx_queue->dump_dma_map_fail,
+                           total);
+       }
+
+       spin_unlock_bh(&cl_hw->tx_lock_agg);
+}
+
+static int cl_txq_drop_reasons_print(struct cl_hw *cl_hw)
+{
+       char *buf = NULL;
+       ssize_t buf_size;
+       int err = 0;
+       int len = 0;
+
+       cl_snprintf(&buf, &len, &buf_size,
+                   "-----------------------------------------------\n"
+                   "| type | idx | queue    | dma map  | total    |\n"
+                   "|      |     | full     | fail     | dump     |\n"
+                   "|------+-----+----------+----------+----------|\n");
+
+       cl_txq_drop_reasons_print_bcmc(cl_hw, &buf, &len, &buf_size);
+       cl_txq_drop_reasons_print_single(cl_hw, &buf, &len, &buf_size);
+       cl_txq_drop_reasons_print_agg(cl_hw, &buf, &len, &buf_size);
+
+       cl_snprintf(&buf, &len, &buf_size,
+                   "-----------------------------------------------\n");
+
+       err = cl_vendor_reply(cl_hw, buf, len);
+       kfree(buf);
+
+       return err;
+}
+
+static int cl_txq_global_counters_print(struct cl_hw *cl_hw)
+{
+       struct cl_tx_forward_cntr *forward = &cl_hw->tx_packet_cntr.forward;
+       struct cl_tx_drop_cntr *drop = &cl_hw->tx_packet_cntr.drop;
+       struct cl_tx_transfer_cntr *transfer = &cl_hw->tx_packet_cntr.transfer;
+       char *buf = NULL;
+       ssize_t buf_size;
+       int err = 0;
+       int len = 0;
+
+       cl_snprintf(&buf, &len, &buf_size,
+                   "FORWARD\n"
+                   "----------------------------\n"
+                   "tx_start          = %u\n", forward->tx_start);
+       cl_snprintf(&buf, &len, &buf_size,
+                   "drv_fast_agg      = %u\n", forward->drv_fast_agg);
+       cl_snprintf(&buf, &len, &buf_size,
+                   "drv_fast_single   = %u\n", forward->drv_fast_single);
+       cl_snprintf(&buf, &len, &buf_size,
+                   "to_mac            = %u\n", forward->to_mac);
+       cl_snprintf(&buf, &len, &buf_size,
+                   "from_mac_single   = %u\n", forward->from_mac_single);
+       cl_snprintf(&buf, &len, &buf_size,
+                   "from_mac_agg      = %u\n", forward->from_mac_agg);
+       cl_snprintf(&buf, &len, &buf_size,
+                   "DROP\n"
+                   "----------------------------\n"
+                   "wd_restart        = %u\n", drop->wd_restart);
+       cl_snprintf(&buf, &len, &buf_size,
+                   "radio_off         = %u\n", drop->radio_off);
+       cl_snprintf(&buf, &len, &buf_size,
+                   "in_recovery       = %u\n", drop->in_recovery);
+       cl_snprintf(&buf, &len, &buf_size,
+                   "short_length      = %u\n", drop->short_length);
+       cl_snprintf(&buf, &len, &buf_size,
+                   "pending_full      = %u\n", drop->pending_full);
+       cl_snprintf(&buf, &len, &buf_size,
+                   "packet_limit      = %u\n", drop->packet_limit);
+       cl_snprintf(&buf, &len, &buf_size,
+                   "dev_flags         = %u\n", drop->dev_flags);
+       cl_snprintf(&buf, &len, &buf_size,
+                   "length_limit      = %u\n", drop->length_limit);
+       cl_snprintf(&buf, &len, &buf_size,
+                   "txhdr_alloc_fail  = %u\n", drop->txhdr_alloc_fail);
+       cl_snprintf(&buf, &len, &buf_size,
+                   "queue_null        = %u\n", drop->queue_null);
+       cl_snprintf(&buf, &len, &buf_size,
+                   "amsdu_alloc_fail  = %u\n", drop->amsdu_alloc_fail);
+       cl_snprintf(&buf, &len, &buf_size,
+                   "amsdu_dma_map_err = %u\n", drop->amsdu_dma_map_err);
+       cl_snprintf(&buf, &len, &buf_size,
+                   "build_hdr_fail    = %u\n", drop->build_hdr_fail);
+       cl_snprintf(&buf, &len, &buf_size,
+                   "key_disable       = %u\n", drop->key_disable);
+       cl_snprintf(&buf, &len, &buf_size,
+                   "queue_flush       = %u\n", drop->queue_flush);
+       cl_snprintf(&buf, &len, &buf_size,
+                   "sta_null_in_agg   = %u\n", drop->sta_null_in_agg);
+       cl_snprintf(&buf, &len, &buf_size,
+                   "TRANSFER\n"
+                   "----------------------------\n"
+                   "single_to_agg     = %u\n", transfer->single_to_agg);
+       cl_snprintf(&buf, &len, &buf_size,
+                   "agg_to_single     = %u\n", transfer->agg_to_single);
+
+       err = cl_vendor_reply(cl_hw, buf, len);
+       kfree(buf);
+
+       return err;
+}
+
+static int cl_txq_stop_reasons_print(struct cl_hw *cl_hw)
+{
+       struct ieee80211_local *local = hw_to_local(cl_hw->hw);
+       unsigned long queue_stop_reasons;
+       unsigned long flags;
+       u8 i = 0;
+       char *buf = NULL;
+       ssize_t buf_size;
+       int err = 0;
+       int len = 0;
+
+       cl_snprintf(&buf, &len, &buf_size,
+                   "|------------------------|\n"
+                   "|queue|queue_stop_reasons|\n"
+                   "|-----+------------------|\n");
+
+       for (i = 0; i < IEEE80211_MAX_QUEUES; i++) {
+               spin_lock_irqsave(&local->queue_stop_reason_lock, flags);
+               queue_stop_reasons = local->queue_stop_reasons[i];
+               spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags);
+
+               if (queue_stop_reasons)
+                       cl_snprintf(&buf, &len, &buf_size, "|%5u|0x%-16lx|\n",
+                                   i, queue_stop_reasons);
+       }
+
+       cl_snprintf(&buf, &len, &buf_size, "|------------------------|\n");
+
+       err = cl_vendor_reply(cl_hw, buf, len);
+       kfree(buf);
+
+       return err;
+}
+
+static int cl_txq_requested_agg_print(struct cl_hw *cl_hw)
+{
+       u8 i = 0;
+       char *buf = NULL;
+       ssize_t buf_size;
+       int err = 0;
+       int len = 0;
+
+       spin_lock_bh(&cl_hw->tx_lock_agg);
+
+       cl_snprintf(&buf, &len, &buf_size,
+                   "## used_agg_queues = %u\n", cl_hw->used_agg_queues);
+
+       if (cl_hw->used_agg_queues) {
+               for (i = 0; i < IPC_MAX_BA_SESSIONS; i++) {
+                       if (!cl_hw->tx_queues.agg[i].cl_sta)
+                               continue;
+
+                       cl_snprintf(&buf, &len, &buf_size,
+                                   "%u) sta_idx = %u, tid = %u\n", i + 1,
+                                   cl_hw->tx_queues.agg[i].cl_sta->sta_idx,
+                                   cl_hw->tx_queues.agg[i].tid);
+               }
+       }
+
+       cl_snprintf(&buf, &len, &buf_size, "## req_agg_queues = %u\n", cl_hw->req_agg_queues);
+
+       if (cl_hw->req_agg_queues) {
+               for (i = 0; i < IPC_MAX_BA_SESSIONS; i++) {
+                       if (!cl_hw->req_agg_db[i].is_used)
+                               continue;
+
+                       cl_snprintf(&buf, &len, &buf_size, "%u) sta_idx = %u, tid = %u\n",
+                                   i + 1, cl_hw->req_agg_db[i].sta_idx,
+                                   cl_hw->req_agg_db[i].tid);
+               }
+       }
+
+       spin_unlock_bh(&cl_hw->tx_lock_agg);
+       err = cl_vendor_reply(cl_hw, buf, len);
+       kfree(buf);
+
+       return err;
+}
+
+static void cl_txq_hw_amsdu_stats_print(struct cl_hw *cl_hw,
+                                       char **buf, int *len, ssize_t *buf_size)
+{
+       u32 i, j;
+       struct cl_tx_queue *tx_queue;
+
+       cl_snprintf(buf, len, buf_size, "HW TX-AMSDU STATS:\n");
+
+       cl_snprintf(buf, len, buf_size, "|-----------");
+       for (i = 0; i < CL_AMSDU_TX_PAYLOAD_MAX; i++)
+               cl_snprintf(buf, len, buf_size, "-----------");
+
+       cl_snprintf(buf, len, buf_size, "|\n|agg|sta|tid");
+       for (i = 0; i < CL_AMSDU_TX_PAYLOAD_MAX; i++)
+               cl_snprintf(buf, len, buf_size, "| amsdu #%u ", i + 1);
+
+       cl_snprintf(buf, len, buf_size, "|\n|---+---+---");
+       for (i = 0; i < CL_AMSDU_TX_PAYLOAD_MAX; i++)
+               cl_snprintf(buf, len, buf_size, "+----------");
+
+       cl_snprintf(buf, len, buf_size, "|\n");
+
+       for (j = 0; j < IPC_MAX_BA_SESSIONS; j++) {
+               tx_queue = &cl_hw->tx_queues.agg[j];
+
+               if (!tx_queue->cl_sta)
+                       continue;
+
+               if (tx_queue->total_packets == 0)
+                       continue;
+
+               cl_snprintf(buf, len, buf_size, "|%3u|%3u|%3u",
+                           tx_queue->index,
+                           tx_queue->cl_sta->sta_idx,
+                           tx_queue->tid);
+
+               for (i = 0; i < CL_AMSDU_TX_PAYLOAD_MAX; i++)
+                       cl_snprintf(buf, len, buf_size, "|%10u", tx_queue->stats_hw_amsdu_cnt[i]);
+
+               cl_snprintf(buf, len, buf_size, "|\n");
+       }
+
+       cl_snprintf(buf, len, buf_size,  "|-----------");
+       for (i = 0; i < CL_AMSDU_TX_PAYLOAD_MAX; i++)
+               cl_snprintf(buf, len, buf_size, "-----------");
+
+       cl_snprintf(buf, len, buf_size, "|\n");
+}
+
+static void cl_txq_sw_amsdu_stats_print(struct cl_hw *cl_hw,
+                                       char **buf, int *len, ssize_t *buf_size)
+{
+       u32 i, j;
+       struct cl_tx_queue *tx_queue;
+
+       if (cl_hw->conf->ci_tx_sw_amsdu_max_packets < 2)
+               return;
+
+       cl_snprintf(buf, len, buf_size, "SW TX-AMSDU STATS:\n");
+
+       for (j = 0; j < IPC_MAX_BA_SESSIONS; j++) {
+               tx_queue = &cl_hw->tx_queues.agg[j];
+
+               if (!tx_queue->cl_sta)
+                       continue;
+
+               if (tx_queue->total_packets == 0)
+                       continue;
+
+               cl_snprintf(buf, len, buf_size,
+                           "\nagg idx %u, sta %u, tid %u :\n",
+                           tx_queue->index,
+                           tx_queue->cl_sta->sta_idx,
+                           tx_queue->tid);
+               cl_snprintf(buf, len, buf_size, "----------------------------\n");
+
+               for (i = 0; i < cl_hw->conf->ci_tx_sw_amsdu_max_packets; i++)
+                       if (tx_queue->stats_sw_amsdu_cnt[i] > 0)
+                               cl_snprintf(buf, len, buf_size,
+                                           "amsdu #%u = %u\n", i + 1,
+                                           tx_queue->stats_sw_amsdu_cnt[i]);
+       }
+}
+
+static int cl_txq_amsdu_stats_print(struct cl_hw *cl_hw)
+{
+       char *buf = NULL;
+       ssize_t buf_size;
+       int err = 0;
+       int len = 0;
+
+       spin_lock_bh(&cl_hw->tx_lock_agg);
+
+       if (cl_hw->used_agg_queues == 0)
+               goto out;
+
+       cl_txq_hw_amsdu_stats_print(cl_hw, &buf, &len, &buf_size);
+       cl_txq_sw_amsdu_stats_print(cl_hw, &buf, &len, &buf_size);
+out:
+       spin_unlock_bh(&cl_hw->tx_lock_agg);
+       err = cl_vendor_reply(cl_hw, buf, len);
+       kfree(buf);
+
+       return err;
+}
+
+static void cl_txq_max_size_print_single(struct cl_hw *cl_hw,
+                                        char **buf, int *len, ssize_t *buf_size)
+{
+       u8 ac = 0;
+       u8 sta_idx = 0;
+       u16 queue_idx = 0;
+       struct cl_tx_queue *tx_queue;
+
+       cl_snprintf(buf, len, buf_size,
+                   "MAX SIZE SINGLE QUEUES:\n"
+                   "|----------------------|\n"
+                   "|idx|sta|ac| drv | fw  |\n"
+                   "|---+---+--+-----+-----|\n");
+
+       spin_lock_bh(&cl_hw->tx_lock_single);
+
+       for (sta_idx = 0; sta_idx < FW_MAX_NUM_STA; sta_idx++) {
+               for (ac = 0; ac < AC_MAX; ac++) {
+                       queue_idx = QUEUE_IDX(sta_idx, ac);
+                       tx_queue = &cl_hw->tx_queues.single[queue_idx];
+
+                       if (tx_queue->total_fw_push_skb == 0)
+                               continue;
+
+                       cl_snprintf(buf, len, buf_size,
+                                   "|%3u|%3u|%2u|%5u|%5u|\n",
+                                   tx_queue->index,
+                                   sta_idx,
+                                   tx_queue->hw_index,
+                                   tx_queue->max_packets,
+                                   tx_queue->fw_max_size);
+               }
+       }
+
+       spin_unlock_bh(&cl_hw->tx_lock_single);
+
+       cl_snprintf(buf, len, buf_size, "|----------------------|\n");
+}
+
+static void cl_txq_max_size_print_agg(struct cl_hw *cl_hw,
+                                     char **buf, int *len, ssize_t *buf_size)
+{
+       u8 agg_idx = 0;
+       struct cl_tx_queue *tx_queue;
+
+       spin_lock_bh(&cl_hw->tx_lock_agg);
+
+       if (cl_hw->used_agg_queues == 0)
+               goto out;
+
+       cl_snprintf(buf, len, buf_size,
+                   "MAX SIZE AGGREGATION QUEUES:\n"
+                   "|-----------------------|\n"
+                   "|idx|sta|tid| drv | fw  |\n"
+                   "|---+---+---+-----+-----|\n");
+
+       for (agg_idx = 0; agg_idx < IPC_MAX_BA_SESSIONS; agg_idx++) {
+               tx_queue = &cl_hw->tx_queues.agg[agg_idx];
+
+               if (!tx_queue->cl_sta)
+                       continue;
+
+               cl_snprintf(buf, len, buf_size,
+                           "|%3u|%3u|%3u|%5u|%5u|\n",
+                           tx_queue->index,
+                           tx_queue->cl_sta->sta_idx,
+                           tx_queue->tid,
+                           tx_queue->max_packets,
+                           tx_queue->fw_max_size);
+       }
+
+       cl_snprintf(buf, len, buf_size, "|----------------------|\n");
+
+out:
+       spin_unlock_bh(&cl_hw->tx_lock_agg);
+}
+
+static int cl_txq_max_size_print(struct cl_hw *cl_hw)
+{
+       char *buf = NULL;
+       ssize_t buf_size;
+       int err = 0;
+       int len = 0;
+
+       cl_txq_max_size_print_single(cl_hw, &buf, &len, &buf_size);
+       cl_txq_max_size_print_agg(cl_hw, &buf, &len, &buf_size);
+
+       err = cl_vendor_reply(cl_hw, buf, len);
+       kfree(buf);
+
+       return err;
+}
+
+static void cl_txq_stats_reset_bcmc(struct cl_hw *cl_hw)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&cl_hw->tx_lock_bcmc, flags);
+       cl_txq_reset_counters_during_traffic(&cl_hw->tx_queues.bcmc);
+       spin_unlock_irqrestore(&cl_hw->tx_lock_bcmc, flags);
+}
+
+static void cl_txq_stats_reset_single(struct cl_hw *cl_hw)
+{
+       u16 i = 0;
+
+       spin_lock_bh(&cl_hw->tx_lock_single);
+
+       for (i = 0; i < MAX_SINGLE_QUEUES; i++)
+               cl_txq_reset_counters_during_traffic(&cl_hw->tx_queues.single[i]);
+
+       spin_unlock_bh(&cl_hw->tx_lock_single);
+}
+
+static void cl_txq_stats_reset_agg(struct cl_hw *cl_hw)
+{
+       u16 i = 0;
+
+       spin_lock_bh(&cl_hw->tx_lock_agg);
+
+       for (i = 0; i < IPC_MAX_BA_SESSIONS; i++)
+               cl_txq_reset_counters_during_traffic(&cl_hw->tx_queues.agg[i]);
+
+       spin_unlock_bh(&cl_hw->tx_lock_agg);
+}
+
+static void cl_txq_stats_reset(struct cl_hw *cl_hw)
+{
+       cl_txq_stats_reset_bcmc(cl_hw);
+       cl_txq_stats_reset_single(cl_hw);
+       cl_txq_stats_reset_agg(cl_hw);
+
+       memset(&cl_hw->tx_packet_cntr, 0, sizeof(struct cl_tx_packet_cntr));
+
+       pr_debug("Reset queue stats\n");
+}
+
+static void cl_txq_sched_list_print_single(struct cl_hw *cl_hw,
+                                          char **buf, int *len, ssize_t *buf_size)
+{
+       struct cl_tx_queue *tx_queue;
+       u32 num_queues = 0;
+
+       cl_snprintf(buf, len, buf_size, "TX single sched list:\n");
+
+       spin_lock_bh(&cl_hw->tx_lock_single);
+
+       list_for_each_entry(tx_queue, &cl_hw->list_sched_q_single, sched_list) {
+               num_queues++;
+               cl_snprintf(buf, len, buf_size, "%u) Index = %u\n", num_queues, tx_queue->index);
+       }
+
+       spin_unlock_bh(&cl_hw->tx_lock_single);
+
+       if (num_queues == 0)
+               cl_snprintf(buf, len, buf_size, "empty\n");
+}
+
+static void cl_txq_sched_list_print_agg(struct cl_hw *cl_hw,
+                                       char **buf, int *len, ssize_t *buf_size)
+{
+       struct cl_tx_queue *tx_queue;
+       u32 num_queues = 0;
+
+       cl_snprintf(buf, len, buf_size, "\nTX agg sched list:\n");
+
+       spin_lock_bh(&cl_hw->tx_lock_agg);
+
+       list_for_each_entry(tx_queue, &cl_hw->list_sched_q_agg, sched_list) {
+               num_queues++;
+               cl_snprintf(buf, len, buf_size, "%u) Index = %u\n", num_queues, tx_queue->index);
+       }
+
+       spin_unlock_bh(&cl_hw->tx_lock_agg);
+
+       if (num_queues == 0)
+               cl_snprintf(buf, len, buf_size, "empty\n");
+}
+
+static int cl_txq_sched_list_print(struct cl_hw *cl_hw)
+{
+       char *buf = NULL;
+       ssize_t buf_size;
+       int err = 0;
+       int len = 0;
+
+       cl_txq_sched_list_print_single(cl_hw, &buf, &len, &buf_size);
+       cl_txq_sched_list_print_agg(cl_hw, &buf, &len, &buf_size);
+
+       err = cl_vendor_reply(cl_hw, buf, len);
+       kfree(buf);
+
+       return err;
+}
+
+static int cl_txq_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,
+                "txq usage:\n"
+                "-a : Print traffic counters\n"
+                "-b : Print drop counters\n"
+                "-c : Print global counters\n"
+                "-d : Print stop reasons\n"
+                "-e : Print requested aggregations\n"
+                "-f : Print AMSDU statistics\n"
+                "-m : Print maximum queues size\n"
+                "-r : Reset queue stats\n"
+                "-s : Print schedule list\n");
+
+       err = cl_vendor_reply(cl_hw, buf, strlen(buf));
+       kfree(buf);
+
+       return err;
+}
+
+static void cl_txq_task_single(struct cl_hw *cl_hw)
+{
+       /* Schedule single queues */
+       struct cl_tx_queue *tx_queue, *tx_queue_tmp;
+
+       spin_lock(&cl_hw->tx_lock_single);
+
+       list_for_each_entry_safe(tx_queue, tx_queue_tmp, &cl_hw->list_sched_q_single, sched_list)
+               cl_txq_sched(cl_hw, tx_queue);
+
+       /* Rotate the queue so next schedule will start with a different queue */
+       list_rotate_left(&cl_hw->list_sched_q_single);
+
+       spin_unlock(&cl_hw->tx_lock_single);
+}
+
+static void cl_txq_task_agg(struct cl_hw *cl_hw)
+{
+       /* Schedule agg queueus */
+       struct cl_tx_queue *tx_queue, *tx_queue_tmp;
+
+       spin_lock(&cl_hw->tx_lock_agg);
+
+       list_for_each_entry_safe(tx_queue, tx_queue_tmp, &cl_hw->list_sched_q_agg, sched_list)
+               cl_txq_sched(cl_hw, tx_queue);
+
+       /* Rotate the queue so next schedule will start with a different queue */
+       list_rotate_left(&cl_hw->list_sched_q_agg);
+
+       spin_unlock(&cl_hw->tx_lock_agg);
+}
+
+static void cl_txq_task(unsigned long data)
+{
+       struct cl_hw *cl_hw = (struct cl_hw *)data;
+
+       cl_txq_task_single(cl_hw);
+       cl_txq_task_agg(cl_hw);
+}
+
+static void cl_txq_agg_inc_usage_cntr(struct cl_hw *cl_hw)
+{
+       /* Should be called in cl_hw->tx_lock_agg context */
+       cl_hw->used_agg_queues++;
+       cl_txq_agg_size_set(cl_hw);
+}
+
+static void cl_txq_agg_dec_usage_cntr(struct cl_hw *cl_hw)
+{
+       /* Should be called in cl_hw->tx_lock_agg context */
+       WARN_ON_ONCE(cl_hw->used_agg_queues == 0);
+
+       cl_hw->used_agg_queues--;
+       cl_txq_agg_size_set(cl_hw);
+}
+
+static void cl_txq_init_single(struct cl_hw *cl_hw)
+{
+       struct cl_tx_queue *tx_queue;
+       u32 i;
+
+       spin_lock_bh(&cl_hw->tx_lock_single);
+
+       INIT_LIST_HEAD(&cl_hw->list_sched_q_single);
+
+       for (i = 0; i < MAX_SINGLE_QUEUES; i++) {
+               tx_queue = &cl_hw->tx_queues.single[i];
+               memset(tx_queue, 0, sizeof(struct cl_tx_queue));
+               INIT_LIST_HEAD(&tx_queue->hdrs);
+               tx_queue->hw_index = i / FW_MAX_NUM_STA;
+               tx_queue->fw_max_size = IPC_TXDESC_CNT_SINGLE;
+               tx_queue->fw_free_space = IPC_TXDESC_CNT_SINGLE;
+               tx_queue->index = i;
+               tx_queue->max_packets = cl_hw->conf->ci_tx_queue_size_single;
+               tx_queue->type = QUEUE_TYPE_SINGLE;
+       }
+
+       spin_unlock_bh(&cl_hw->tx_lock_single);
+}
+
+static void cl_txq_init_bcmc(struct cl_hw *cl_hw)
+{
+       unsigned long flags;
+       struct cl_tx_queue *tx_queue;
+
+       spin_lock_irqsave(&cl_hw->tx_lock_bcmc, flags);
+
+       tx_queue = &cl_hw->tx_queues.bcmc;
+       memset(tx_queue, 0, sizeof(struct cl_tx_queue));
+       INIT_LIST_HEAD(&tx_queue->hdrs);
+       tx_queue->hw_index = CL_HWQ_BCN;
+       tx_queue->fw_max_size = IPC_TXDESC_CNT_BCMC;
+       tx_queue->fw_free_space = IPC_TXDESC_CNT_BCMC;
+       tx_queue->index = 0;
+       tx_queue->max_packets = 0;
+       tx_queue->type = QUEUE_TYPE_BCMC;
+
+       spin_unlock_irqrestore(&cl_hw->tx_lock_bcmc, flags);
+}
+
+static void cl_txq_init_agg(struct cl_hw *cl_hw)
+{
+       spin_lock_bh(&cl_hw->tx_lock_agg);
+       INIT_LIST_HEAD(&cl_hw->list_sched_q_agg);
+       spin_unlock_bh(&cl_hw->tx_lock_agg);
+}
+
+static void cl_txq_agg_request_reset(struct cl_hw *cl_hw)
+{
+       cl_hw->req_agg_queues = 0;
+       memset(cl_hw->req_agg_db, 0, sizeof(cl_hw->req_agg_db));
+}
+
+void cl_txq_init(struct cl_hw *cl_hw)
+{
+       tasklet_init(&cl_hw->tx_task, cl_txq_task, (unsigned long)cl_hw);
+
+       cl_txq_agg_request_reset(cl_hw);
+       cl_txq_init_single(cl_hw);
+       cl_txq_init_bcmc(cl_hw);
+       cl_txq_init_agg(cl_hw);
+}
+
+void cl_txq_stop(struct cl_hw *cl_hw)
+{
+       tasklet_kill(&cl_hw->tx_task);
+}
+
+struct cl_tx_queue *cl_txq_get(struct cl_hw *cl_hw, struct cl_sw_txhdr *sw_txhdr)
+{
+       struct cl_sta *cl_sta = sw_txhdr->cl_sta;
+       struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(sw_txhdr->skb);
+       u8 hw_queue = sw_txhdr->hw_queue;
+
+       if (!cl_sta &&
+           hw_queue == CL_HWQ_VO &&
+           is_multicast_ether_addr(sw_txhdr->hdr80211->addr1)) {
+               /*
+                * If HW queue is VO and packet is multicast, it was not buffered
+                * by mac80211, and it should be pushed to the high-priority queue
+                * and not to the bcmc queue.
+                */
+               return &cl_hw->tx_queues.single[HIGH_PRIORITY_QUEUE];
+       } else if (!cl_sta &&
+                  (hw_queue != CL_HWQ_BCN) &&
+                  !(tx_info->flags & IEEE80211_TX_CTL_NO_PS_BUFFER)) {
+               /*
+                * If station is NULL, but HW queue is not BCN,
+                * it most go to the high-priority queue.
+                */
+               tx_info->flags |= IEEE80211_TX_CTL_NO_PS_BUFFER;
+               sw_txhdr->hw_queue = CL_HWQ_VO;
+               return &cl_hw->tx_queues.single[HIGH_PRIORITY_QUEUE];
+       } else if (cl_sta && (tx_info->flags & IEEE80211_TX_CTL_AMPDU)) {
+               /* Agg packet */
+               return cl_sta->agg_tx_queues[sw_txhdr->tid];
+       } else if (hw_queue == CL_HWQ_BCN) {
+               return &cl_hw->tx_queues.bcmc;
+       } else if (tx_info->flags & IEEE80211_TX_CTL_NO_PS_BUFFER) {
+               /*
+                * Only frames that are power save response or non-bufferable MMPDU
+                * will have this flag set our driver will push those frame to the
+                * highiest priority queue.
+                */
+               return &cl_hw->tx_queues.single[HIGH_PRIORITY_QUEUE];
+       }
+
+       return &cl_hw->tx_queues.single[QUEUE_IDX(sw_txhdr->sta_idx, hw_queue)];
+}
+
+void cl_txq_push(struct cl_hw *cl_hw, struct cl_sw_txhdr *sw_txhdr)
+{
+       struct cl_tx_queue *tx_queue = sw_txhdr->tx_queue;
+
+       if (tx_queue->num_packets < tx_queue->max_packets) {
+               tx_queue->num_packets++;
+
+               /*
+                * This prioritization of action frames helps Samsung Galaxy Note 8 to
+                * open BA session more easily, when phy dev is PHY_DEV_OLYMPUS
+                */
+               if (ieee80211_is_action(sw_txhdr->fc))
+                       list_add(&sw_txhdr->tx_queue_list, &tx_queue->hdrs);
+               else
+                       list_add_tail(&sw_txhdr->tx_queue_list, &tx_queue->hdrs);
+
+               /* If it is the first packet in the queue, add the queue to the sched list */
+               cl_txq_sched_list_add(tx_queue, cl_hw);
+       } else {
+               struct cl_sta *cl_sta = sw_txhdr->cl_sta;
+               u8 tid = sw_txhdr->tid;
+
+               /* If the SW queue full, release the packet */
+               tx_queue->dump_queue_full++;
+
+               if (cl_sta && cl_sta->amsdu_anchor[tid].sw_txhdr) {
+                       if (cl_sta->amsdu_anchor[tid].sw_txhdr == sw_txhdr) {
+                               cl_sta->amsdu_anchor[tid].sw_txhdr = NULL;
+                               cl_sta->amsdu_anchor[tid].packet_cnt = 0;
+                       }
+               }
+
+               dev_kfree_skb_any(sw_txhdr->skb);
+               cl_sw_txhdr_free(cl_hw, sw_txhdr);
+
+               /* Schedule tasklet to try and empty the queue */
+               tasklet_schedule(&cl_hw->tx_task);
+       }
+}
+
+void cl_txq_sched(struct cl_hw *cl_hw, struct cl_tx_queue *tx_queue)
+{
+       struct cl_sw_txhdr *sw_txhdr, *sw_txhdr_tmp;
+
+       if (!test_bit(CL_DEV_STARTED, &cl_hw->drv_flags) ||
+           cl_hw->tx_disable_flags ||
+           cl_txq_is_fw_full(tx_queue))
+               return;
+
+       /* Go over all descriptors in queue */
+       list_for_each_entry_safe(sw_txhdr, sw_txhdr_tmp, &tx_queue->hdrs, tx_queue_list) {
+               list_del(&sw_txhdr->tx_queue_list);
+               tx_queue->num_packets--;
+
+               cl_tx_push(cl_hw, sw_txhdr, tx_queue);
+
+               if (cl_txq_is_fw_full(tx_queue))
+                       break;
+       }
+
+       /* If queue is empty remove it from schedule list */
+       cl_txq_sched_list_remove_if_empty(tx_queue);
+}
+
+void cl_txq_agg_alloc(struct cl_hw *cl_hw, struct cl_sta *cl_sta,
+                     struct mm_ba_add_cfm *ba_add_cfm, u16 buf_size)
+{
+       u8 tid = ba_add_cfm->tid;
+       u8 fw_agg_idx = ba_add_cfm->agg_idx;
+       u8 sta_idx = cl_sta->sta_idx;
+       u8 ac = cl_tid2hwq[tid];
+       u16 single_queue_idx = QUEUE_IDX(sta_idx, ac);
+       struct cl_tx_queue *tx_queue = &cl_hw->tx_queues.agg[fw_agg_idx];
+
+       spin_lock_bh(&cl_hw->tx_lock_agg);
+
+       /* Init aggregated queue struct */
+       memset(tx_queue, 0, sizeof(struct cl_tx_queue));
+       INIT_LIST_HEAD(&tx_queue->hdrs);
+
+       /*
+        * Firmware agg queues size is static and set to 512, so that for the worst
+        * case of HE stations,that support AMPDU of 256, it has room for two full
+        * aggregation.
+        * To keep this logic, of room for two aggregations, for non-HE stations, or
+        * for HE stations that do not support AMPDU of 256, we initialize fw_max_size
+        to twice the buffer size supported by the station.
+        */
+       tx_queue->fw_max_size = min_t(u16, cl_hw->max_agg_tx_q_size, buf_size * 2);
+       tx_queue->fw_free_space = tx_queue->fw_max_size;
+
+       tx_queue->max_packets = cl_hw->conf->ci_tx_queue_size_agg;
+       tx_queue->hw_index = ac;
+       tx_queue->cl_sta = cl_sta;
+       tx_queue->type = QUEUE_TYPE_AGG;
+       tx_queue->tid = tid;
+       tx_queue->index = fw_agg_idx;
+
+#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
+
+       /* Attach the cl_hw chosen queue to the station and agg queues DB */
+       cl_sta->agg_tx_queues[tid] = tx_queue;
+       cl_agg_cfm_set_tx_queue(cl_hw, tx_queue, fw_agg_idx);
+
+       /* Notify upper mac80211 layer of queues resources status */
+       cl_txq_agg_inc_usage_cntr(cl_hw);
+       cl_txq_agg_request_del(cl_hw, sta_idx, tid);
+
+       /*
+        * Move the qos descriptors to the new allocated aggregated queues,
+        * otherwise we might reorder packets)
+        */
+       cl_txq_transfer_single_to_agg(cl_hw, &cl_hw->tx_queues.single[single_queue_idx],
+                                     tx_queue, tid);
+       /* Move the BA window pending packets to agg path */
+       cl_baw_pending_to_agg(cl_hw, cl_sta, tid);
+
+       spin_unlock_bh(&cl_hw->tx_lock_agg);
+
+       cl_dbg_trace(cl_hw, "Allocate queue [%u] to station [%u] tid [%u]\n",
+                    fw_agg_idx, sta_idx, tid);
+}
+
+void cl_txq_agg_free(struct cl_hw *cl_hw, struct cl_tx_queue *tx_queue,
+                    struct cl_sta *cl_sta, u8 tid)
+{
+       spin_lock_bh(&cl_hw->tx_lock_agg);
+
+       cl_dbg_trace(cl_hw, "Free queue [%u] of station [%u] tid [%u]\n",
+                    tx_queue->index, cl_sta->sta_idx, tid);
+
+       memset(tx_queue, 0, sizeof(struct cl_tx_queue));
+
+       cl_txq_agg_dec_usage_cntr(cl_hw);
+
+       spin_unlock_bh(&cl_hw->tx_lock_agg);
+}
+
+void cl_txq_agg_stop(struct cl_sta *cl_sta, u8 tid)
+{
+       cl_sta->agg_tx_queues[tid] = NULL;
+}
+
+void cl_txq_sta_add(struct cl_hw *cl_hw, struct cl_sta *cl_sta)
+{
+       /* Set cl_sta field for all single queues of this station */
+       u8 ac;
+       u16 queue_idx;
+
+       for (ac = 0; ac < AC_MAX; ac++) {
+               queue_idx = QUEUE_IDX(cl_sta->sta_idx, ac);
+               cl_hw->tx_queues.single[queue_idx].cl_sta = cl_sta;
+       }
+
+       /* Reset pointers to TX agg queues */
+       memset(cl_sta->agg_tx_queues, 0, sizeof(cl_sta->agg_tx_queues));
+}
+
+void cl_txq_sta_remove(struct cl_hw *cl_hw, u8 sta_idx)
+{
+       /* Clear cl_sta field for all single queues of this station */
+       u8 ac;
+       u16 queue_idx;
+
+       for (ac = 0; ac < AC_MAX; ac++) {
+               queue_idx = QUEUE_IDX(sta_idx, ac);
+               cl_hw->tx_queues.single[queue_idx].cl_sta = NULL;
+       }
+}
+
+void cl_txq_transfer_agg_to_single(struct cl_hw *cl_hw, struct cl_tx_queue *agg_queue)
+{
+       /*
+        * 1) Remove from aggregation queue
+        * 2) Free sw_txhdr
+        * 3) Push to single queue
+        */
+       struct cl_sw_txhdr *sw_txhdr, *sw_txhdr_tmp;
+       struct sk_buff *skb;
+       struct ieee80211_tx_info *tx_info;
+       struct cl_tx_queue *single_queue;
+       struct cl_sta *cl_sta = agg_queue->cl_sta;
+       u16 single_queue_idx = 0;
+
+       if (agg_queue->num_packets == 0)
+               return;
+
+       single_queue_idx = QUEUE_IDX(cl_sta->sta_idx, agg_queue->hw_index);
+       single_queue = &cl_hw->tx_queues.single[single_queue_idx];
+
+       list_for_each_entry_safe(sw_txhdr, sw_txhdr_tmp, &agg_queue->hdrs, tx_queue_list) {
+               list_del(&sw_txhdr->tx_queue_list);
+               agg_queue->num_packets--;
+
+               skb = sw_txhdr->skb;
+               tx_info = IEEE80211_SKB_CB(skb);
+
+               if (cl_tx_ctrl_is_amsdu(tx_info)) {
+                       cl_tx_amsdu_transfer_single(cl_hw, sw_txhdr);
+               } else {
+                       tx_info->flags &= ~IEEE80211_TX_CTL_AMPDU;
+
+                       if (cl_tx_8023_to_wlan(cl_hw, skb, cl_sta, sw_txhdr->tid) == 0) {
+                               cl_hw->tx_packet_cntr.transfer.agg_to_single++;
+                               cl_tx_single(cl_hw, cl_sta, skb, false, false);
+                       }
+               }
+
+               cl_sw_txhdr_free(cl_hw, sw_txhdr);
+       }
+
+       /* If queue is empty remove it from schedule list */
+       cl_txq_sched_list_remove_if_empty(agg_queue);
+}
+
+void cl_txq_flush(struct cl_hw *cl_hw, struct cl_tx_queue *tx_queue)
+{
+       struct cl_sw_txhdr *sw_txhdr, *sw_txhdr_tmp;
+       struct ieee80211_tx_info *tx_info;
+
+       if (tx_queue->num_packets == 0)
+               return;
+
+       list_for_each_entry_safe(sw_txhdr, sw_txhdr_tmp, &tx_queue->hdrs, tx_queue_list) {
+               list_del(&sw_txhdr->tx_queue_list);
+               tx_queue->num_packets--;
+
+               /* Can not send AMSDU frames as singles */
+               tx_info = IEEE80211_SKB_CB(sw_txhdr->skb);
+
+               /* Free mid & last AMSDU sub frames */
+               if (cl_tx_ctrl_is_amsdu(tx_info)) {
+                       cl_tx_amsdu_flush_sub_frames(cl_hw, sw_txhdr);
+               } else {
+                       if (tx_queue->type == QUEUE_TYPE_SINGLE)
+                               cl_tx_single_free_skb(cl_hw, sw_txhdr->skb);
+                       else
+                               kfree_skb(sw_txhdr->skb);
+
+                       cl_sw_txhdr_free(cl_hw, sw_txhdr);
+                       cl_hw->tx_packet_cntr.drop.queue_flush++;
+               }
+       }
+
+       /* Remove from schedule queue */
+       cl_txq_sched_list_remove(tx_queue);
+
+       /* Sanity check that queue is empty */
+       WARN_ON(tx_queue->num_packets > 0);
+}
+
+void cl_txq_flush_single(struct cl_hw *cl_hw, u16 idx)
+{
+       spin_lock_bh(&cl_hw->tx_lock_single);
+       cl_txq_flush(cl_hw, &cl_hw->tx_queues.single[idx]);
+       spin_unlock_bh(&cl_hw->tx_lock_single);
+}
+
+void cl_txq_flush_all_agg(struct cl_hw *cl_hw)
+{
+       int i = 0;
+
+       for (i = 0; i < IPC_MAX_BA_SESSIONS; i++)
+               cl_txq_flush(cl_hw, &cl_hw->tx_queues.agg[i]);
+}
+
+void cl_txq_flush_all_single(struct cl_hw *cl_hw)
+{
+       int i = 0;
+
+       for (i = 0; i < MAX_SINGLE_QUEUES; i++)
+               cl_txq_flush(cl_hw, &cl_hw->tx_queues.single[i]);
+}
+
+void cl_txq_flush_sta(struct cl_hw *cl_hw, struct cl_sta *cl_sta)
+{
+       int i = 0;
+       u8 sta_idx = cl_sta->sta_idx;
+       u32 queue_idx = 0;
+       struct cl_tx_queue *tx_queue = NULL;
+
+       spin_lock_bh(&cl_hw->tx_lock_agg);
+
+       /* Flush all aggregation queues for this station */
+       for (i = 0; i < IEEE80211_NUM_TIDS; i++)
+               if (cl_sta->agg_tx_queues[i])
+                       cl_txq_flush(cl_hw, cl_sta->agg_tx_queues[i]);
+
+       spin_unlock_bh(&cl_hw->tx_lock_agg);
+
+       spin_lock_bh(&cl_hw->tx_lock_single);
+
+       /* Flush all single queues for this station */
+       for (i = 0; i < AC_MAX; i++) {
+               queue_idx = QUEUE_IDX(sta_idx, i);
+               tx_queue = &cl_hw->tx_queues.single[queue_idx];
+               cl_txq_flush(cl_hw, tx_queue);
+               cl_txq_reset_counters(tx_queue);
+       }
+
+       /* Go over high prioirty queue and delete packets belonging to this station */
+       cl_txq_delete_packets(cl_hw, &cl_hw->tx_queues.single[HIGH_PRIORITY_QUEUE], sta_idx);
+
+       spin_unlock_bh(&cl_hw->tx_lock_single);
+}
+
+void cl_txq_agg_request_add(struct cl_hw *cl_hw, u8 sta_idx, u8 tid)
+{
+       int i = cl_txq_request_find(cl_hw, sta_idx, tid);
+       struct cl_req_agg_db *req_agg_db = NULL;
+
+       if (i != -1) {
+               cl_dbg_trace(cl_hw, "ALREADY_ADDED - entry = %d, sta_idx = %u, tid = %u\n",
+                            i, sta_idx, tid);
+               return;
+       }
+
+       for (i = 0; i < IPC_MAX_BA_SESSIONS; i++) {
+               req_agg_db = &cl_hw->req_agg_db[i];
+
+               if (!req_agg_db->is_used) {
+                       cl_dbg_trace(cl_hw, "ADD - entry = %d, sta_idx = %u, tid = %u\n",
+                                    i, sta_idx, tid);
+                       req_agg_db->is_used = true;
+                       req_agg_db->sta_idx = sta_idx;
+                       req_agg_db->tid = tid;
+                       cl_hw->req_agg_queues++;
+                       return;
+               }
+       }
+}
+
+void cl_txq_agg_request_del(struct cl_hw *cl_hw, u8 sta_idx, u8 tid)
+{
+       int i = cl_txq_request_find(cl_hw, sta_idx, tid);
+
+       if (i != -1) {
+               cl_dbg_trace(cl_hw, "DEL - entry = %d, sta_idx = %u, tid = %u\n",
+                            i, sta_idx, tid);
+               cl_hw->req_agg_db[i].is_used = false;
+               cl_hw->req_agg_queues--;
+       }
+}
+
+bool cl_txq_is_agg_available(struct cl_hw *cl_hw)
+{
+       u8 total_agg_queues = cl_hw->used_agg_queues + cl_hw->req_agg_queues;
+
+       return (total_agg_queues < IPC_MAX_BA_SESSIONS);
+}
+
+bool cl_txq_single_is_full(struct cl_hw *cl_hw, u16 idx)
+{
+       struct cl_tx_queue *tx_queue = &cl_hw->tx_queues.single[idx];
+       bool is_full = 0;
+
+       spin_lock_bh(&cl_hw->tx_lock_single);
+       is_full = (tx_queue->max_packets == tx_queue->num_packets);
+       spin_unlock_bh(&cl_hw->tx_lock_single);
+
+       return is_full;
+}
+
+void cl_txq_single_sched(struct cl_hw *cl_hw, u16 idx)
+{
+       /*
+        * Don't take lock because it is already taken by
+        * all functions that call cl_txq_single_sched().
+        */
+       struct cl_tx_queue *tx_queue = &cl_hw->tx_queues.single[idx];
+
+       if (tx_queue->num_packets)
+               cl_txq_sched(cl_hw, tx_queue);
+}
+
+bool cl_txq_is_fw_empty(struct cl_tx_queue *tx_queue)
+{
+       return (tx_queue->fw_free_space == tx_queue->fw_max_size);
+}
+
+bool cl_txq_is_fw_full(struct cl_tx_queue *tx_queue)
+{
+       return (tx_queue->fw_free_space == 0);
+}
+
+bool cl_txq_frames_pending(struct cl_hw *cl_hw)
+{
+       int i = 0;
+
+       /* Check if we have multicast/bradcast frame in FW queues */
+       if (!cl_txq_is_fw_empty(&cl_hw->tx_queues.bcmc))
+               return true;
+
+       /* Check if we have singles frame in FW queues */
+       for (i = 0; i < MAX_SINGLE_QUEUES; i++)
+               if (!cl_txq_is_fw_empty(&cl_hw->tx_queues.single[i]))
+                       return true;
+
+       /* Check if we have aggregation frame in FW queues */
+       for (i = 0; i < IPC_MAX_BA_SESSIONS; i++)
+               if (!cl_txq_is_fw_empty(&cl_hw->tx_queues.agg[i]))
+                       return true;
+
+       return false;
+}
+
+int cl_txq_cli(struct cl_hw *cl_hw, struct cli_params *cli_params)
+{
+       switch (cli_params->option) {
+       case 'a':
+               return cl_txq_traffic_counters_print(cl_hw);
+       case 'b':
+               return cl_txq_drop_reasons_print(cl_hw);
+       case 'c':
+               return cl_txq_global_counters_print(cl_hw);
+       case 'd':
+               return cl_txq_stop_reasons_print(cl_hw);
+       case 'e':
+               return cl_txq_requested_agg_print(cl_hw);
+       case 'f':
+               return cl_txq_amsdu_stats_print(cl_hw);
+       case 'm':
+               return cl_txq_max_size_print(cl_hw);
+       case 'r':
+               cl_txq_stats_reset(cl_hw);
+               break;
+       case 's':
+               return cl_txq_sched_list_print(cl_hw);
+       case '?':
+               return cl_txq_cli_help(cl_hw);
+       default:
+               cl_dbg_err(cl_hw, "Illegal option (%c) - try '?' for help\n", cli_params->option);
+               break;
+       }
+
+       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.
________________________________


^ permalink raw reply related	[flat|nested] 262+ messages in thread

* [RFC v1 219/256] cl8k: add tx/tx_queue.h
  2021-06-17 15:58 [RFC v1 000/256] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (217 preceding siblings ...)
  2021-06-17 16:01 ` [RFC v1 218/256] cl8k: add tx/tx_queue.c viktor.barna
@ 2021-06-17 16:01 ` viktor.barna
  2021-06-17 16:01 ` [RFC v1 220/256] cl8k: add utils/file.c viktor.barna
                   ` (38 subsequent siblings)
  257 siblings, 0 replies; 262+ messages in thread
From: viktor.barna @ 2021-06-17 16:01 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Oleksandr Savchenko, Shay Bar, Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

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

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 .../net/wireless/celeno/cl8k/tx/tx_queue.h    | 48 +++++++++++++++++++
 1 file changed, 48 insertions(+)
 create mode 100644 drivers/net/wireless/celeno/cl8k/tx/tx_queue.h

diff --git a/drivers/net/wireless/celeno/cl8k/tx/tx_queue.h b/drivers/net/wireless/celeno/cl8k/tx/tx_queue.h
new file mode 100644
index 000000000000..e8232b605b2b
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/tx/tx_queue.h
@@ -0,0 +1,48 @@
+/* SPDX-License-Identifier: MIT */
+/* Copyright(c) 2019-2021, Celeno Communications Ltd. */
+
+#ifndef CL_TX_QUEUE_H
+#define CL_TX_QUEUE_H
+
+#include "hw.h"
+#include "tx/tx.h"
+
+enum cl_queue_type {
+       QUEUE_TYPE_SINGLE,
+       QUEUE_TYPE_AGG,
+       QUEUE_TYPE_BCMC,
+
+       QUEUE_TYPE_MAX
+};
+
+#define QUEUE_IDX(sta, ac) ((sta) + (ac) * FW_MAX_NUM_STA)
+
+void cl_txq_init(struct cl_hw *cl_hw);
+void cl_txq_stop(struct cl_hw *cl_hw);
+struct cl_tx_queue *cl_txq_get(struct cl_hw *cl_hw, struct cl_sw_txhdr *sw_txhdr);
+void cl_txq_push(struct cl_hw *cl_hw, struct cl_sw_txhdr *sw_txhdr);
+void cl_txq_sched(struct cl_hw *cl_hw, struct cl_tx_queue *tx_queue);
+void cl_txq_agg_alloc(struct cl_hw *cl_hw, struct cl_sta *cl_sta,
+                     struct mm_ba_add_cfm *ba_add_cfm, u16 buf_size);
+void cl_txq_agg_free(struct cl_hw *cl_hw, struct cl_tx_queue *tx_queue,
+                    struct cl_sta *cl_sta, u8 tid);
+void cl_txq_agg_stop(struct cl_sta *cl_sta, u8 tid);
+void cl_txq_sta_add(struct cl_hw *cl_hw, struct cl_sta *cl_sta);
+void cl_txq_sta_remove(struct cl_hw *cl_hw, u8 sta_idx);
+void cl_txq_transfer_agg_to_single(struct cl_hw *cl_hw, struct cl_tx_queue *agg_queue);
+void cl_txq_flush(struct cl_hw *cl_hw, struct cl_tx_queue *tx_queue);
+void cl_txq_flush_single(struct cl_hw *cl_hw, u16 idx);
+void cl_txq_flush_all_agg(struct cl_hw *cl_hw);
+void cl_txq_flush_all_single(struct cl_hw *cl_hw);
+void cl_txq_flush_sta(struct cl_hw *cl_hw, struct cl_sta *cl_sta);
+void cl_txq_agg_request_add(struct cl_hw *cl_hw, u8 sta_idx, u8 tid);
+void cl_txq_agg_request_del(struct cl_hw *cl_hw, u8 sta_idx, u8 tid);
+bool cl_txq_is_agg_available(struct cl_hw *cl_hw);
+bool cl_txq_single_is_full(struct cl_hw *cl_hw, u16 idx);
+void cl_txq_single_sched(struct cl_hw *cl_hw, u16 idx);
+bool cl_txq_is_fw_empty(struct cl_tx_queue *tx_queue);
+bool cl_txq_is_fw_full(struct cl_tx_queue *tx_queue);
+bool cl_txq_frames_pending(struct cl_hw *cl_hw);
+int cl_txq_cli(struct cl_hw *cl_hw, struct cli_params *cli_params);
+
+#endif /* CL_TX_QUEUE_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.
________________________________


^ permalink raw reply related	[flat|nested] 262+ messages in thread

* [RFC v1 220/256] cl8k: add utils/file.c
  2021-06-17 15:58 [RFC v1 000/256] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (218 preceding siblings ...)
  2021-06-17 16:01 ` [RFC v1 219/256] cl8k: add tx/tx_queue.h viktor.barna
@ 2021-06-17 16:01 ` viktor.barna
  2021-06-17 16:01 ` [RFC v1 221/256] cl8k: add utils/file.h viktor.barna
                   ` (37 subsequent siblings)
  257 siblings, 0 replies; 262+ messages in thread
From: viktor.barna @ 2021-06-17 16:01 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Oleksandr Savchenko, Shay Bar, Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

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

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 drivers/net/wireless/celeno/cl8k/utils/file.c | 52 +++++++++++++++++++
 1 file changed, 52 insertions(+)
 create mode 100644 drivers/net/wireless/celeno/cl8k/utils/file.c

diff --git a/drivers/net/wireless/celeno/cl8k/utils/file.c b/drivers/net/wireless/celeno/cl8k/utils/file.c
new file mode 100644
index 000000000000..b42d78f386e4
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/utils/file.c
@@ -0,0 +1,52 @@
+// SPDX-License-Identifier: MIT
+/* Copyright(c) 2019-2021, Celeno Communications Ltd. */
+
+#include "utils/file.h"
+#include "reg/reg_access.h"
+#include <linux/firmware.h>
+#include <linux/fs.h>
+#include <linux/vmalloc.h>
+
+size_t cl_file_open_and_read(struct cl_chip *chip, const char *filename,
+                            char **buf)
+{
+       const struct firmware *fw;
+       size_t size = 0;
+       int ret = 0;
+       char path_name[CL_PATH_MAX] = {0};
+
+       snprintf(path_name, sizeof(path_name), "cl8k/%s", filename);
+       ret = request_firmware(&fw, path_name, chip->dev);
+
+       if (ret) {
+               cl_dbg_chip_err(chip, "request_firmware %s failed\n",
+                               path_name);
+               return 0;
+       }
+
+       if (!fw || !fw->data) {
+               cl_dbg_chip_err(chip, "Invalid firmware %s\n", path_name);
+               goto out;
+       }
+
+       size = fw->size;
+
+       /*
+        * Add one byte with a '\0' so that string manipulation functions
+        * used for parsing these files can find the string '\0' terminator.
+        * Make sure size is aligned to 4.
+        */
+       *buf = kzalloc(ALIGN(size + 1, 4), GFP_KERNEL);
+       if (!(*buf)) {
+               size = 0;
+               goto out;
+       }
+
+       memcpy(*buf, fw->data, size);
+
+out:
+       release_firmware(fw);
+
+       return size;
+}
+
--
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.
________________________________


^ permalink raw reply related	[flat|nested] 262+ messages in thread

* [RFC v1 221/256] cl8k: add utils/file.h
  2021-06-17 15:58 [RFC v1 000/256] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (219 preceding siblings ...)
  2021-06-17 16:01 ` [RFC v1 220/256] cl8k: add utils/file.c viktor.barna
@ 2021-06-17 16:01 ` viktor.barna
  2021-06-17 16:01 ` [RFC v1 222/256] cl8k: add utils/ip.c viktor.barna
                   ` (36 subsequent siblings)
  257 siblings, 0 replies; 262+ messages in thread
From: viktor.barna @ 2021-06-17 16:01 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Oleksandr Savchenko, Shay Bar, Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

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

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 drivers/net/wireless/celeno/cl8k/utils/file.h | 18 ++++++++++++++++++
 1 file changed, 18 insertions(+)
 create mode 100644 drivers/net/wireless/celeno/cl8k/utils/file.h

diff --git a/drivers/net/wireless/celeno/cl8k/utils/file.h b/drivers/net/wireless/celeno/cl8k/utils/file.h
new file mode 100644
index 000000000000..331666524ef5
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/utils/file.h
@@ -0,0 +1,18 @@
+/* SPDX-License-Identifier: MIT */
+/* Copyright(c) 2019-2021, Celeno Communications Ltd. */
+
+#ifndef CL_FILE_H
+#define CL_FILE_H
+
+#include "hw.h"
+
+/*
+ * cl_file_open_and_read - Read the whole file into an allocated buffer.
+ *
+ * Allocates a buffer large enough to hold the contents of file at @filename and reads the
+ * contents of that file into that buffer. Upon success, the address of the allocated buffer
+ * is returned (which needs to be free later). Upon failure, returns NULL.
+ */
+size_t cl_file_open_and_read(struct cl_chip *chip, const char *filename,
+                            char **buf);
+#endif /* CL_FILE_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.
________________________________


^ permalink raw reply related	[flat|nested] 262+ messages in thread

* [RFC v1 222/256] cl8k: add utils/ip.c
  2021-06-17 15:58 [RFC v1 000/256] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (220 preceding siblings ...)
  2021-06-17 16:01 ` [RFC v1 221/256] cl8k: add utils/file.h viktor.barna
@ 2021-06-17 16:01 ` viktor.barna
  2021-06-17 16:01 ` [RFC v1 223/256] cl8k: add utils/ip.h viktor.barna
                   ` (35 subsequent siblings)
  257 siblings, 0 replies; 262+ messages in thread
From: viktor.barna @ 2021-06-17 16:01 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Oleksandr Savchenko, Shay Bar, Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

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

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 drivers/net/wireless/celeno/cl8k/utils/ip.c | 140 ++++++++++++++++++++
 1 file changed, 140 insertions(+)
 create mode 100644 drivers/net/wireless/celeno/cl8k/utils/ip.c

diff --git a/drivers/net/wireless/celeno/cl8k/utils/ip.c b/drivers/net/wireless/celeno/cl8k/utils/ip.c
new file mode 100644
index 000000000000..798119bca294
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/utils/ip.c
@@ -0,0 +1,140 @@
+// SPDX-License-Identifier: MIT
+/* Copyright(c) 2019-2021, Celeno Communications Ltd. */
+
+#include "utils/ip.h"
+
+/* Chromecast" 239.255.255.250 */
+#define MCAST_CHROMECAST_ADDR htonl(0xEFFFFFFAL)
+
+/*
+ * Local-group multicast address | internetwork multicast address =
+ *   = 224.0.0.0/24 | 224.0.1.0/24 = 224.0.0.0/23
+ */
+#define MCAST_IP_SERVICE_MASK __constant_htonl(0xFFFFFE00UL)
+
+static __be16 get_eth_proto(struct sk_buff *skb)
+{
+       if (!skb->mac_header)
+               skb_reset_mac_header(skb);
+
+       if (eth_hdr(skb)->h_proto == htons(ETH_P_8021Q))
+               return vlan_eth_hdr(skb)->h_vlan_encapsulated_proto;
+       else
+               return eth_hdr(skb)->h_proto;
+}
+
+bool set_network_header_if_proto(struct sk_buff *skb, u16 protocol)
+{
+       if (get_eth_proto(skb) == htons(protocol)) {
+               const bool has_vlan_header = eth_hdr(skb)->h_proto == htons(ETH_P_8021Q);
+               const size_t h_offset =
+                       (eth_hdr(skb) == (struct ethhdr *)(skb->data)) ? ETH_HLEN : 0;
+
+               skb_set_network_header(skb, h_offset + ((has_vlan_header) ? VLAN_HLEN : 0));
+
+               return true;
+       }
+
+       return false;
+}
+
+bool is_ipv4_packet(struct sk_buff *skb)
+{
+       return set_network_header_if_proto(skb, ETH_P_IP) &&
+              (ip_hdr(skb)->ihl >= 5) &&
+              (ip_hdr(skb)->version == IPVERSION);
+}
+
+bool is_ipv6_packet(struct sk_buff *skb)
+{
+       return set_network_header_if_proto(skb, ETH_P_IPV6) &&
+              (ipv6_hdr(skb)->version == 6);
+}
+
+bool is_ssdp_packet(struct sk_buff *skb)
+{
+       bool status = false;
+
+       if (get_unaligned((const u32 *)&ip_hdr(skb)->daddr) == MCAST_CHROMECAST_ADDR)
+               status = true;
+
+       return status;
+}
+
+bool is_mdns_packet(const u8 *dest_mac)
+{
+       /*
+        * Multicast DNS packets should be sent as multicast, since no IGMP
+        * registration is performed on them
+        */
+       u8 mdns_mac[] = {0x01, 0x00, 0x5e, 0x00, 0x00};
+
+       if (!memcmp(dest_mac, mdns_mac, 5) && (dest_mac[5] == 0xfb || dest_mac[5] == 0xfc))
+               return true;
+
+       return false;
+}
+
+bool is_ipv4_service_multicast_packet(struct sk_buff *skb)
+{
+       /* Check if sk_buff contains IGMP packet, addressed to 224.0.0.0/23 */
+       return ((IGMP_LOCAL_GROUP == (ip_hdr(skb)->daddr & MCAST_IP_SERVICE_MASK)) &&
+               (IPPROTO_IGMP != ip_hdr(skb)->protocol || IGMP_ALL_HOSTS == ip_hdr(skb)->daddr));
+}
+
+bool is_ipv6_service_multicast_packet(struct sk_buff *skb)
+{
+       /* Check if sk_buff contains ICMP packet, or addressed to ff02::/16 */
+       const struct ipv6hdr *ip6h = ipv6_hdr(skb);
+       u8 protocol = ip6h->nexthdr;
+
+       /* If hop-by-hop option header, get the first u8 field from this header */
+       if (protocol == IPPROTO_HOPOPTS)
+               protocol = ((const struct ipv6_hopopt_hdr *)(ip6h + 1))->nexthdr;
+
+       return (((ip6h->daddr.s6_addr[0] == 0xff) &&
+                (ip6h->daddr.s6_addr[1] == 0x02)) ||
+               (protocol == IPPROTO_ICMPV6));
+}
+
+bool is_tcp_ack(struct sk_buff *skb, bool *syn_rst_push)
+{
+       if (skb->len > TCP_ACK_MAX_LEN)
+               goto out;
+
+       if (is_ipv4_packet(skb)) {
+               struct iphdr *iphdr = ip_hdr(skb);
+
+               if (iphdr->protocol == IPPROTO_TCP) {
+                       struct tcphdr *tcp_hdr = (struct tcphdr *)
+                                                ((char *)iphdr +
+                                                 IPV4_HDR_LEN(iphdr->ihl));
+                       u16 data_size = ntohs(iphdr->tot_len) -
+                                       IPV4_HDR_LEN(iphdr->ihl) -
+                                       (tcp_hdr->doff * 4);
+
+                       *syn_rst_push = tcp_hdr->syn || tcp_hdr->rst || tcp_hdr->psh;
+
+                       return (data_size == 0);
+               }
+       } else if (is_ipv6_packet(skb)) {
+               struct ipv6hdr *ipv6hdr = ipv6_hdr(skb);
+
+               if (ipv6hdr->nexthdr == IPPROTO_TCP) {
+                       struct tcphdr *tcp_hdr = (struct tcphdr *)
+                                                ((char *)ipv6hdr +
+                                                sizeof(struct ipv6hdr));
+                       u16 data_size = ntohs(ipv6hdr->payload_len) -
+                                       (tcp_hdr->doff * 4);
+
+                       *syn_rst_push = tcp_hdr->syn || tcp_hdr->rst || tcp_hdr->psh;
+
+                       return (data_size == 0);
+               }
+       }
+
+out:
+       *syn_rst_push = false;
+       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.
________________________________


^ permalink raw reply related	[flat|nested] 262+ messages in thread

* [RFC v1 223/256] cl8k: add utils/ip.h
  2021-06-17 15:58 [RFC v1 000/256] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (221 preceding siblings ...)
  2021-06-17 16:01 ` [RFC v1 222/256] cl8k: add utils/ip.c viktor.barna
@ 2021-06-17 16:01 ` viktor.barna
  2021-06-17 16:01 ` [RFC v1 224/256] cl8k: add utils/math.h viktor.barna
                   ` (34 subsequent siblings)
  257 siblings, 0 replies; 262+ messages in thread
From: viktor.barna @ 2021-06-17 16:01 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Oleksandr Savchenko, Shay Bar, Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

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

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 drivers/net/wireless/celeno/cl8k/utils/ip.h | 51 +++++++++++++++++++++
 1 file changed, 51 insertions(+)
 create mode 100644 drivers/net/wireless/celeno/cl8k/utils/ip.h

diff --git a/drivers/net/wireless/celeno/cl8k/utils/ip.h b/drivers/net/wireless/celeno/cl8k/utils/ip.h
new file mode 100644
index 000000000000..93aa9fcc2384
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/utils/ip.h
@@ -0,0 +1,51 @@
+/* SPDX-License-Identifier: MIT */
+/* Copyright(c) 2019-2021, Celeno Communications Ltd. */
+
+#ifndef CL_IP_H
+#define CL_IP_H
+
+#include <linux/version.h>
+#include <linux/skbuff.h>
+#include <linux/ip.h>
+#include <linux/ipv6.h>
+#include <linux/if_vlan.h>
+#include <linux/netdevice.h>
+#include <linux/igmp.h>
+#include <asm/unaligned.h>
+
+/* Check if a packet has specific LLC fields e.g. DSAP, SSAP and Control */
+#define PKT_HAS_LLC_HDR(a) ((a[0] == 0xAA) && (a[1] == 0xAA) && (a[2] == 0x03))
+#define LENGTH_LLC 3
+#define LENGTH_SSNAP 5
+
+/* Multiply by 4 because IHL is number of 32-bit words */
+#define IPV4_HDR_LEN(ihl) ((ihl) << 2)
+#define TCP_ACK_MAX_LEN 100
+
+bool set_network_header_if_proto(struct sk_buff *skb, u16 protocol);
+bool is_ipv4_packet(struct sk_buff *skb);
+bool is_ipv6_packet(struct sk_buff *skb);
+bool is_ssdp_packet(struct sk_buff *skb);
+bool is_mdns_packet(const u8 *dest_mac);
+bool is_ipv4_service_multicast_packet(struct sk_buff *skb);
+bool is_ipv6_service_multicast_packet(struct sk_buff *skb);
+bool is_tcp_ack(struct sk_buff *skb, bool *syn_rst_push);
+
+static inline unsigned short get_ether_type(int offset, unsigned char *src_buf)
+{
+       unsigned short type_len = *(unsigned short *)(src_buf + offset);
+
+       return htons(type_len);
+}
+
+static inline bool cl_ip_addr_parse_str(const u8 *str, u8 *addr)
+{
+       return (sscanf(str,
+                      "%hhd.%hhd.%hhd.%hhd",
+                      &addr[0],
+                      &addr[1],
+                      &addr[2],
+                      &addr[3]) == 4);
+}
+
+#endif /* CL_IP_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.
________________________________


^ permalink raw reply related	[flat|nested] 262+ messages in thread

* [RFC v1 224/256] cl8k: add utils/math.h
  2021-06-17 15:58 [RFC v1 000/256] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (222 preceding siblings ...)
  2021-06-17 16:01 ` [RFC v1 223/256] cl8k: add utils/ip.h viktor.barna
@ 2021-06-17 16:01 ` viktor.barna
  2021-06-17 16:01 ` [RFC v1 225/256] cl8k: add utils/string.c viktor.barna
                   ` (33 subsequent siblings)
  257 siblings, 0 replies; 262+ messages in thread
From: viktor.barna @ 2021-06-17 16:01 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Oleksandr Savchenko, Shay Bar, Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

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

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 drivers/net/wireless/celeno/cl8k/utils/math.h | 18 ++++++++++++++++++
 1 file changed, 18 insertions(+)
 create mode 100644 drivers/net/wireless/celeno/cl8k/utils/math.h

diff --git a/drivers/net/wireless/celeno/cl8k/utils/math.h b/drivers/net/wireless/celeno/cl8k/utils/math.h
new file mode 100644
index 000000000000..f03bef46f3eb
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/utils/math.h
@@ -0,0 +1,18 @@
+/* SPDX-License-Identifier: MIT */
+/* Copyright(c) 2019-2021, Celeno Communications Ltd. */
+
+#ifndef CL_MATH_H
+#define CL_MATH_H
+
+#include <linux/types.h>
+#include <linux/math64.h>
+
+static inline void cl_div64_decimal(u64 dividend, u64 divisor, u32 *a, u32 *b)
+{
+       u64 remainder = 0;
+
+       *a = (u32)div64_u64_rem(dividend, divisor, &remainder);
+       *b = (u32)div64_u64(100 * remainder, divisor);
+}
+
+#endif /* CL_MATH_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.
________________________________


^ permalink raw reply related	[flat|nested] 262+ messages in thread

* [RFC v1 225/256] cl8k: add utils/string.c
  2021-06-17 15:58 [RFC v1 000/256] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (223 preceding siblings ...)
  2021-06-17 16:01 ` [RFC v1 224/256] cl8k: add utils/math.h viktor.barna
@ 2021-06-17 16:01 ` viktor.barna
  2021-06-17 16:01 ` [RFC v1 226/256] cl8k: add utils/string.h viktor.barna
                   ` (32 subsequent siblings)
  257 siblings, 0 replies; 262+ messages in thread
From: viktor.barna @ 2021-06-17 16:01 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Oleksandr Savchenko, Shay Bar, Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

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

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 .../net/wireless/celeno/cl8k/utils/string.c   | 235 ++++++++++++++++++
 1 file changed, 235 insertions(+)
 create mode 100644 drivers/net/wireless/celeno/cl8k/utils/string.c

diff --git a/drivers/net/wireless/celeno/cl8k/utils/string.c b/drivers/net/wireless/celeno/cl8k/utils/string.c
new file mode 100644
index 000000000000..1300563e86a6
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/utils/string.c
@@ -0,0 +1,235 @@
+// SPDX-License-Identifier: MIT
+/* Copyright(c) 2019-2021, Celeno Communications Ltd. */
+
+#include "utils/string.h"
+#include "utils/utils.h"
+
+int cl_strtobool_vector(char *src, bool *dest, u8 elem_cnt, char *delim)
+{
+       u8 i = 0;
+       char *buf = NULL;
+       char vector[STR_LEN_256B] = {0};
+
+       if (strlen(src) >= sizeof(vector))
+               return -E2BIG;
+
+       strcpy(vector, src);
+       buf = cl_strtok(vector, delim);
+
+       if (!buf)
+               return -EIO;
+       if (kstrtobool(buf, &dest[0]) != 0)
+               return -EINVAL;
+
+       for (i = 1; i < elem_cnt; i++) {
+               buf = cl_strtok(NULL, delim);
+               if (!buf)
+                       break;
+               if (kstrtobool(buf, &dest[i]) != 0)
+                       return -EINVAL;
+       }
+
+       if (i < elem_cnt) {
+               pr_err("src %s doesn't have %u elements\n", src, elem_cnt);
+               return  -1;
+       }
+
+       return 0;
+}
+
+int cl_strtou8_vector(char *src, u8 *dest, u8 elem_cnt, char *delim)
+{
+       u8 i = 0;
+       char *buf = NULL;
+       char vector[STR_LEN_256B] = {0};
+
+       if (strlen(src) >= sizeof(vector))
+               return -E2BIG;
+
+       strcpy(vector, src);
+       buf = cl_strtok(vector, delim);
+
+       if (!buf)
+               return -EIO;
+       if (kstrtou8(buf, 0, &dest[0]) != 0)
+               return -EINVAL;
+
+       for (i = 1; i < elem_cnt; i++) {
+               buf = cl_strtok(NULL, delim);
+               if (!buf)
+                       break;
+               if (kstrtou8(buf, 0, &dest[i]) != 0)
+                       return -EINVAL;
+       }
+
+       if (i < elem_cnt) {
+               pr_err("src %s doesn't have %u elements\n", src, elem_cnt);
+               return -1;
+       }
+
+       return 0;
+}
+
+int cl_strtou8_hex_vector(char *src, u8 *dest, u8 elem_cnt, char *delim)
+{
+       u8 i = 0;
+       char *buf = NULL;
+       char vector[STR_LEN_32B] = {0};
+
+       if (strlen(src) >= sizeof(vector))
+               return -E2BIG;
+
+       strcpy(vector, src);
+       buf = cl_strtok(vector, delim);
+
+       if (!buf)
+               return -EIO;
+       if (kstrtou8(buf, 16, &dest[0]) != 0)
+               return -EINVAL;
+
+       for (i = 1; i < elem_cnt; i++) {
+               buf = cl_strtok(NULL, delim);
+               if (!buf)
+                       break;
+               if (kstrtou8(buf, 16, &dest[i]) != 0)
+                       return -1;
+       }
+
+       if (i < elem_cnt) {
+               pr_err("src %s doesn't have %u elements\n", src, elem_cnt);
+               return -1;
+       }
+
+       return 0;
+}
+
+int cl_strtou16_vector(char *src, u16 *dest, u8 elem_cnt, char *delim)
+{
+       u8 i = 0;
+       char *buf = NULL;
+       char vector[STR_LEN_256B] = {0};
+
+       if (strlen(src) >= sizeof(vector))
+               return -E2BIG;
+
+       strcpy(vector, src);
+       buf = cl_strtok(vector, delim);
+
+       if (!buf)
+               return -EIO;
+       if (kstrtou16(buf, 0, &dest[0]) != 0)
+               return -EINVAL;
+
+       for (i = 1; i < elem_cnt; i++) {
+               buf = cl_strtok(NULL, delim);
+               if (!buf)
+                       break;
+               if (kstrtou16(buf, 0, &dest[i]) != 0)
+                       return -EINVAL;
+       }
+
+       if (i < elem_cnt) {
+               pr_err("src %s doesn't have %u elements\n", src, elem_cnt);
+               return -1;
+       }
+
+       return 0;
+}
+
+int cl_strtou32_vector(char *src, u32 *dest, u8 elem_cnt, char *delim)
+{
+       u8 i = 0;
+       char *buf = NULL;
+       char vector[STR_LEN_256B] = {0};
+
+       if (strlen(src) >= sizeof(vector))
+               return -E2BIG;
+
+       strcpy(vector, src);
+       buf = cl_strtok(vector, delim);
+
+       if (!buf)
+               return -EIO;
+       if (kstrtou32(buf, 0, &dest[0]) != 0)
+               return -EINVAL;
+
+       for (i = 1; i < elem_cnt; i++) {
+               buf = cl_strtok(NULL, delim);
+               if (!buf)
+                       break;
+               if (kstrtou32(buf, 0, &dest[i]) != 0)
+                       return -EINVAL;
+       }
+
+       if (i < elem_cnt) {
+               pr_err("src %s doesn't have %u elements\n", src, elem_cnt);
+               return -1;
+       }
+
+       return 0;
+}
+
+int cl_strtos8_vector(char *src, s8 *dest, u8 elem_cnt, char *delim)
+{
+       u8 i = 0;
+       char *buf = NULL;
+       char vector[STR_LEN_256B] = {0};
+
+       if (strlen(src) >= sizeof(vector))
+               return -E2BIG;
+
+       strcpy(vector, src);
+       buf = cl_strtok(vector, delim);
+
+       if (!buf)
+               return -EIO;
+       if (kstrtos8(buf, 0, &dest[0]) != 0)
+               return -EINVAL;
+
+       for (i = 1; i < elem_cnt; i++) {
+               buf = cl_strtok(NULL, delim);
+               if (!buf)
+                       break;
+               if (kstrtos8(buf, 0, &dest[i]) != 0)
+                       return -EINVAL;
+       }
+
+       if (i < elem_cnt) {
+               pr_err("src %s doesn't have %u elements\n", src, elem_cnt);
+               return -1;
+       }
+
+       return 0;
+}
+
+static s8 *_strtok;
+
+s8 *cl_strtok(s8 *s, const s8 *ct)
+{
+       return cl_strtok_r(s, ct, &_strtok);
+}
+
+/* cl_strtok_r() is a reentrant version of cl_strtok() */
+s8 *cl_strtok_r(s8 *s, const s8 *ct, s8 **saveptr)
+{
+       s8 *sbegin, *send;
+
+       sbegin  = s ? s : *saveptr;
+       if (!sbegin)
+               return NULL;
+
+       sbegin += strspn(sbegin, ct);
+       if (*sbegin == '\0') {
+               *saveptr = NULL;
+               return NULL;
+       }
+
+       send = strpbrk(sbegin, ct);
+       if (send && *send != '\0')
+               *send++ = '\0';
+
+       *saveptr = send;
+
+       return sbegin;
+}
+
--
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.
________________________________


^ permalink raw reply related	[flat|nested] 262+ messages in thread

* [RFC v1 226/256] cl8k: add utils/string.h
  2021-06-17 15:58 [RFC v1 000/256] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (224 preceding siblings ...)
  2021-06-17 16:01 ` [RFC v1 225/256] cl8k: add utils/string.c viktor.barna
@ 2021-06-17 16:01 ` viktor.barna
  2021-06-17 16:01 ` [RFC v1 227/256] cl8k: add utils/timer.c viktor.barna
                   ` (31 subsequent siblings)
  257 siblings, 0 replies; 262+ messages in thread
From: viktor.barna @ 2021-06-17 16:01 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Oleksandr Savchenko, Shay Bar, Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

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

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 .../net/wireless/celeno/cl8k/utils/string.h   | 25 +++++++++++++++++++
 1 file changed, 25 insertions(+)
 create mode 100644 drivers/net/wireless/celeno/cl8k/utils/string.h

diff --git a/drivers/net/wireless/celeno/cl8k/utils/string.h b/drivers/net/wireless/celeno/cl8k/utils/string.h
new file mode 100644
index 000000000000..aea19516ff99
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/utils/string.h
@@ -0,0 +1,25 @@
+/* SPDX-License-Identifier: MIT */
+/* Copyright(c) 2019-2021, Celeno Communications Ltd. */
+
+#ifndef CL_STRING_H
+#define CL_STRING_H
+
+#include <linux/types.h>
+
+#define STR_LEN_16B  16
+#define STR_LEN_32B  32
+#define STR_LEN_64B  64
+#define STR_LEN_128B 128
+#define STR_LEN_256B 256
+
+int cl_strtobool_vector(char *src, bool *dest, u8 elem_cnt, char *delim);
+int cl_strtou8_vector(char *src, u8 *dest, u8 elem_cnt, char *delim);
+int cl_strtou8_hex_vector(char *src, u8 *dest, u8 elem_cnt, char *delim);
+int cl_strtou16_vector(char *src, u16 *dest, u8 elem_cnt, char *delim);
+int cl_strtou32_vector(char *src, u32 *dest, u8 elem_cnt, char *delim);
+int cl_strtos8_vector(char *src, s8 *dest, u8 elem_cnt, char *delim);
+
+s8 *cl_strtok(s8 *s, const s8 *ct);
+s8 *cl_strtok_r(s8 *s, const s8 *ct, s8 **saveptr);
+
+#endif /* CL_STRING_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.
________________________________


^ permalink raw reply related	[flat|nested] 262+ messages in thread

* [RFC v1 227/256] cl8k: add utils/timer.c
  2021-06-17 15:58 [RFC v1 000/256] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (225 preceding siblings ...)
  2021-06-17 16:01 ` [RFC v1 226/256] cl8k: add utils/string.h viktor.barna
@ 2021-06-17 16:01 ` viktor.barna
  2021-06-17 16:01 ` [RFC v1 228/256] cl8k: add utils/timer.h viktor.barna
                   ` (30 subsequent siblings)
  257 siblings, 0 replies; 262+ messages in thread
From: viktor.barna @ 2021-06-17 16:01 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Oleksandr Savchenko, Shay Bar, Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

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

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 .../net/wireless/celeno/cl8k/utils/timer.c    | 72 +++++++++++++++++++
 1 file changed, 72 insertions(+)
 create mode 100644 drivers/net/wireless/celeno/cl8k/utils/timer.c

diff --git a/drivers/net/wireless/celeno/cl8k/utils/timer.c b/drivers/net/wireless/celeno/cl8k/utils/timer.c
new file mode 100644
index 000000000000..8ab8b44ef085
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/utils/timer.c
@@ -0,0 +1,72 @@
+// SPDX-License-Identifier: MIT
+/* Copyright(c) 2019-2021, Celeno Communications Ltd. */
+
+#include "utils/timer.h"
+
+static void cl_timer_func(struct timer_list *t)
+{
+       struct cl_timer *timer = from_timer(timer, t, obj);
+
+       timer->f(timer->data);
+       if (timer->enable && timer->periodic)
+               cl_timer_enable(timer);
+}
+
+void cl_timer_init(struct cl_timer *timer,
+                  void (*f)(unsigned long),
+                  unsigned long data,
+                  unsigned long period,
+                  bool periodic)
+{
+       timer_setup(&timer->obj, cl_timer_func, 0);
+       cl_timer_period_set(timer, period);
+       timer->data = data;
+       timer->f = f;
+       timer->periodic = periodic;
+       timer->enable = false;
+}
+
+void cl_timer_period_set(struct cl_timer *timer, unsigned long period)
+{
+       atomic_set(&timer->period, msecs_to_jiffies(period));
+}
+
+void cl_timer_enable(struct cl_timer *timer)
+{
+       if (timer_pending(&timer->obj))
+               return;
+
+       timer->obj.expires = jiffies + atomic_read(&timer->period);
+       timer->enable = true;
+       add_timer(&timer->obj);
+}
+
+void cl_timer_disable(struct cl_timer *timer)
+{
+       if (timer->enable) {
+               timer->enable = false;
+               del_timer(&timer->obj);
+       }
+}
+
+void cl_timer_disable_sync(struct cl_timer *timer)
+{
+       if (timer->enable) {
+               timer->enable = false;
+               del_timer_sync(&timer->obj);
+       }
+}
+
+void cl_timer_rearm(struct cl_timer *timer)
+{
+       timer->enable = true;
+
+       mod_timer(&timer->obj, jiffies + atomic_read(&timer->period));
+}
+
+int cl_timer_rearm_offset(struct cl_timer *timer, unsigned long time_offset)
+{
+       timer->enable = true;
+
+       return mod_timer(&timer->obj, time_offset + atomic_read(&timer->period));
+}
--
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.
________________________________


^ permalink raw reply related	[flat|nested] 262+ messages in thread

* [RFC v1 228/256] cl8k: add utils/timer.h
  2021-06-17 15:58 [RFC v1 000/256] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (226 preceding siblings ...)
  2021-06-17 16:01 ` [RFC v1 227/256] cl8k: add utils/timer.c viktor.barna
@ 2021-06-17 16:01 ` viktor.barna
  2021-06-17 16:01 ` [RFC v1 229/256] cl8k: add utils/utils.c viktor.barna
                   ` (29 subsequent siblings)
  257 siblings, 0 replies; 262+ messages in thread
From: viktor.barna @ 2021-06-17 16:01 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Oleksandr Savchenko, Shay Bar, Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

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

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 .../net/wireless/celeno/cl8k/utils/timer.h    | 30 +++++++++++++++++++
 1 file changed, 30 insertions(+)
 create mode 100644 drivers/net/wireless/celeno/cl8k/utils/timer.h

diff --git a/drivers/net/wireless/celeno/cl8k/utils/timer.h b/drivers/net/wireless/celeno/cl8k/utils/timer.h
new file mode 100644
index 000000000000..1481d8d78db4
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/utils/timer.h
@@ -0,0 +1,30 @@
+/* SPDX-License-Identifier: MIT */
+/* Copyright(c) 2019-2021, Celeno Communications Ltd. */
+
+#ifndef CL_TIMER_H
+#define CL_TIMER_H
+
+#include <linux/timer.h>
+
+struct cl_timer {
+       struct timer_list obj;
+       void (*f)(unsigned long data);
+       unsigned long data;
+       atomic_t period;
+       bool periodic;
+       bool enable;
+};
+
+void cl_timer_init(struct cl_timer *timer,
+                  void (*f)(unsigned long data),
+                  unsigned long data,
+                  unsigned long period,
+                  bool periodic);
+void cl_timer_period_set(struct cl_timer *timer, unsigned long period);
+void cl_timer_enable(struct cl_timer *timer);
+void cl_timer_disable(struct cl_timer *timer);
+void cl_timer_disable_sync(struct cl_timer *timer);
+void cl_timer_rearm(struct cl_timer *timer);
+int cl_timer_rearm_offset(struct cl_timer *timer, unsigned long time_offset);
+
+#endif /* CL_TIMER_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.
________________________________


^ permalink raw reply related	[flat|nested] 262+ messages in thread

* [RFC v1 229/256] cl8k: add utils/utils.c
  2021-06-17 15:58 [RFC v1 000/256] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (227 preceding siblings ...)
  2021-06-17 16:01 ` [RFC v1 228/256] cl8k: add utils/timer.h viktor.barna
@ 2021-06-17 16:01 ` viktor.barna
  2021-06-17 16:01 ` [RFC v1 230/256] cl8k: add utils/utils.h viktor.barna
                   ` (28 subsequent siblings)
  257 siblings, 0 replies; 262+ messages in thread
From: viktor.barna @ 2021-06-17 16:01 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Oleksandr Savchenko, Shay Bar, Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

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

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 .../net/wireless/celeno/cl8k/utils/utils.c    | 388 ++++++++++++++++++
 1 file changed, 388 insertions(+)
 create mode 100644 drivers/net/wireless/celeno/cl8k/utils/utils.c

diff --git a/drivers/net/wireless/celeno/cl8k/utils/utils.c b/drivers/net/wireless/celeno/cl8k/utils/utils.c
new file mode 100644
index 000000000000..6d6f913ae95a
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/utils/utils.c
@@ -0,0 +1,388 @@
+// SPDX-License-Identifier: MIT
+/* Copyright(c) 2019-2021, Celeno Communications Ltd. */
+
+#include <linux/dma-mapping.h>
+#include <linux/list.h>
+#include <linux/jiffies.h>
+#include <linux/kthread.h>
+#include <net/mac80211.h>
+#include <linux/sched/signal.h>
+
+#include "utils/utils.h"
+#include "rx/rx.h"
+#include "tx/tx.h"
+#include "fw/msg_tx.h"
+#include "debugfs.h"
+#include "ipc_shared.h"
+#include "rssi.h"
+#include "traffic.h"
+#include "reg/reg_riu.h"
+#include "reg/reg_mac_hw.h"
+#include "utils/ip.h"
+
+#define GI_08  0
+#define GI_16  1
+#define GI_32  2
+#define GI_04  3
+
+#define GI_MAX_FW 4
+#define GI_MAX_HE 3
+#define GI_MAX_HT_VHT 2
+
+#define CL_TSF_LOW_MIGHT_OVERFLOW_TH 0xFFFFF000
+
+static u8 conv_wrs_gi_ht_vht[GI_MAX_HT_VHT] = {
+       [WRS_GI_LONG] = GI_08,
+       [WRS_GI_SHORT] = GI_04
+};
+
+static u8 conv_wrs_gi_he[GI_MAX_HE] = {
+       [WRS_GI_LONG] = GI_32,
+       [WRS_GI_SHORT] = GI_16,
+       [WRS_GI_VSHORT] = GI_08
+};
+
+static u8 conv_fw_gi_ht_vht[GI_MAX_FW] = {
+       [GI_08] = WRS_GI_LONG,
+       [GI_16] = 0,
+       [GI_32] = 0,
+       [GI_04] = WRS_GI_SHORT,
+};
+
+static u8 conv_fw_gi_he[GI_MAX_FW] = {
+       [GI_08] = WRS_GI_VSHORT,
+       [GI_16] = WRS_GI_SHORT,
+       [GI_32] = WRS_GI_LONG,
+       [GI_04] = 0,
+};
+
+void cl_hex_dump(char *caption, u8 *buffer, u32 length, u32 offset, bool is_byte)
+{
+       u8 *pt = buffer;
+       u32 i;
+       bool end_nl = false;
+       char buf[STR_LEN_256B] = {0};
+       int len = 0;
+
+       if (caption)
+               pr_debug("%s: %p, len = %u\n", caption, buffer, length);
+
+       if (is_byte) {
+               for (i = 0; i < length; i++) {
+                       if (i % 16 == 0)
+                               len += snprintf(buf + len, sizeof(buf) - len,
+                                               "0x%04x : ", i + offset);
+                       len += snprintf(buf + len, sizeof(buf) - len,
+                                       "%02x ", ((u8)pt[i]));
+                       end_nl = true;
+                       if (i % 16 == 15) {
+                               pr_debug("%s", buf);
+                               len = 0;
+                               end_nl = false;
+                       }
+               }
+       } else {
+               for (i = 0; i < (length / sizeof(u32)); i++) {
+                       if (i % 4 == 0)
+                               len += snprintf(buf + len, sizeof(buf) - len,
+                                               "0x%04x : ",
+                                               (u32)(i * sizeof(u32) + offset));
+                       len += snprintf(buf + len, sizeof(buf) - len,
+                                       "%08x ", *((u32 *)(pt + i * sizeof(u32))));
+                       end_nl = true;
+                       if (i % 4 == 3) {
+                               pr_debug("%s", buf);
+                               len = 0;
+                               end_nl = false;
+                       }
+               }
+       }
+
+       if (end_nl)
+               pr_debug("%s", buf);
+}
+
+u8 convert_gi_format_wrs_to_fw(u8 wrs_mode, u8 gi)
+{
+       if (wrs_mode == WRS_MODE_HE && gi < GI_MAX_HE)
+               return conv_wrs_gi_he[gi];
+       else if (wrs_mode > WRS_MODE_OFDM && gi < GI_MAX_HT_VHT)
+               return conv_wrs_gi_ht_vht[gi];
+       else
+               return 0;
+}
+
+u8 convert_gi_format_fw_to_wrs(u8 format_mode, u8 gi)
+{
+       if (gi < GI_MAX_FW) {
+               if (format_mode >= FORMATMOD_HE_SU)
+                       return conv_fw_gi_he[gi];
+               else if (format_mode >= FORMATMOD_HT_MF)
+                       return conv_fw_gi_ht_vht[gi];
+       }
+
+       return 0;
+}
+
+static u8 map_gi_to_ltf[WRS_GI_MAX] = {
+       [WRS_GI_LONG] = LTF_X4,
+       [WRS_GI_SHORT] = LTF_X2,
+       [WRS_GI_VSHORT] = LTF_X2,
+};
+
+u8 cl_map_gi_to_ltf(u8 mode, u8 gi)
+{
+       if (mode == WRS_MODE_HE && gi < WRS_GI_MAX)
+               return map_gi_to_ltf[gi];
+
+       return 0;
+}
+
+/* This table holds 10^(-110 -> 0) Q39 values for rx RSSI and noise floor calculations */
+#define CL_EXP_TBL_SIZE 111 /* 10^x table size (-110 -> 0dBm) */
+
+static u64 CL_EXP_10[CL_EXP_TBL_SIZE] = {
+       0x7FFFFFFFFF, 0x65AC8C2F36, 0x50C335D3DB, 0x4026E73CCD, 0x32F52CFEEA, 0x287A26C490,
+       0x2026F30FBB, 0x198A13577C, 0x144960C577, 0x101D3F2D96, 0x0CCCCCCCCD, 0x0A2ADAD185,
+       0x08138561FC, 0x066A4A52E1, 0x0518847FE4, 0x040C3713A8, 0x0337184E5F, 0x028DCEBBF3,
+       0x0207567A25, 0x019C86515C, 0x0147AE147B, 0x01044914F4, 0x00CEC089CC, 0x00A43AA1E3,
+       0x008273A664, 0x00679F1B91, 0x00524F3B0A, 0x0041617932, 0x0033EF0C37, 0x002940A1BC,
+       0x0020C49BA6, 0x001A074EE5, 0x0014ACDA94, 0x00106C4364, 0x000D0B90A4, 0x000A5CB5F5,
+       0x00083B1F81, 0x000689BF52, 0x0005318139, 0x000420102C, 0x000346DC5D, 0x00029A54B1,
+       0x000211490F, 0x0001A46D24, 0x00014DF4DD, 0x0001094565, 0x0000D2B65A, 0x0000A75FEF,
+       0x000084F352, 0x0000699B38, 0x000053E2D6, 0x000042A212, 0x000034EDB5, 0x00002A0AEA,
+       0x0000216549, 0x00001A86F1, 0x000015123C, 0x000010BCCB, 0x00000D4B88, 0x00000A8F86,
+       0x000008637C, 0x000006A9CF, 0x0000054AF8, 0x000004344B, 0x00000356EE, 0x000002A718,
+       0x0000021B6C, 0x000001AC7B, 0x000001545A, 0x0000010E5A, 0x000000D6C0, 0x000000AA95,
+       0x000000877F, 0x0000006BA1, 0x000000557E, 0x00000043E9, 0x00000035F1, 0x0000002AD9,
+       0x0000002209, 0x0000001B09, 0x000000157A, 0x000000110F, 0x0000000D8D, 0x0000000AC3,
+       0x000000088D, 0x00000006CA, 0x0000000565, 0x0000000449, 0x0000000367, 0x00000002B4,
+       0x0000000226, 0x00000001B5, 0x000000015B, 0x0000000114, 0x00000000DB, 0x00000000AE,
+       0x000000008A, 0x000000006E, 0x0000000057, 0x0000000045, 0x0000000037, 0x000000002C,
+       0x0000000023, 0x000000001C, 0x0000000016, 0x0000000011, 0x000000000E, 0x000000000B,
+       0x0000000009, 0x0000000007, 0x0000000005
+};
+
+static s8 cl_eng_to_noise_floor(u64 eng)
+{
+       s8 i = 0;
+       s8 noise = 0;
+       s64 min_delta = S64_MAX;
+
+       for (i = ARRAY_SIZE(CL_EXP_10) - 1; i >= 0; i--) {
+               if (abs((s64)(((s64)eng) - ((s64)CL_EXP_10[i]))) < min_delta) {
+                       min_delta = abs((s64)(((s64)eng) - ((s64)CL_EXP_10[i])));
+                       noise = i;
+               }
+       }
+
+       return (-noise);
+}
+
+static void cl_read_reg_noise(struct cl_hw *cl_hw, s8 res[4])
+{
+       u32 reg_val = riu_agcinbdpow_20_pnoisestat_get(cl_hw);
+       u8 i = 0;
+
+       for (i = 0; i < 4; i++) {
+               u8 curr_val = (reg_val >> (i * 8)) & 0xFF;
+               /* Convert reg value to real value */
+               res[i] = curr_val - 0xFF;
+       }
+}
+
+s8 cl_calc_noise_floor(struct cl_hw *cl_hw, const s8 *reg_noise_floor)
+{
+       s8 noise_floor[4] = {0};
+       u64 noise_floor_eng = 0;
+
+       if (reg_noise_floor)
+               memcpy(noise_floor, reg_noise_floor, sizeof(noise_floor));
+       else
+               cl_read_reg_noise(cl_hw, noise_floor);
+
+       noise_floor[0] = abs(noise_floor[0]);
+       noise_floor[1] = abs(noise_floor[1]);
+       noise_floor[2] = abs(noise_floor[2]);
+       noise_floor[3] = abs(noise_floor[3]);
+
+       BUILD_BUG_ON(CL_EXP_TBL_SIZE > S8_MAX);
+       noise_floor_eng = (CL_EXP_10[min_t(s8, noise_floor[0], CL_EXP_TBL_SIZE - 1)] +
+                          CL_EXP_10[min_t(s8, noise_floor[1], CL_EXP_TBL_SIZE - 1)] +
+                          CL_EXP_10[min_t(s8, noise_floor[2], CL_EXP_TBL_SIZE - 1)] +
+                          CL_EXP_10[min_t(s8, noise_floor[3], CL_EXP_TBL_SIZE - 1)]);
+
+       noise_floor_eng = div64_u64(noise_floor_eng, 4);
+
+       return cl_eng_to_noise_floor(noise_floor_eng);
+}
+
+u8 cl_convert_signed_to_reg_value(s8 val)
+{
+       bool sign = (val < 0 ? true : false);
+       u8 res = abs(val);
+
+       if (sign)
+               res |= (1 << 7);
+
+       return res;
+}
+
+static const int nl_width_to_phy_bw[] = {
+       [NL80211_CHAN_WIDTH_20_NOHT] = CHNL_BW_20,
+       [NL80211_CHAN_WIDTH_20]      = CHNL_BW_20,
+       [NL80211_CHAN_WIDTH_40]      = CHNL_BW_40,
+       [NL80211_CHAN_WIDTH_80]      = CHNL_BW_80,
+       [NL80211_CHAN_WIDTH_80P80]   = CHNL_BW_20,
+       [NL80211_CHAN_WIDTH_160]     = CHNL_BW_160,
+       [NL80211_CHAN_WIDTH_5]       = CHNL_BW_20,
+       [NL80211_CHAN_WIDTH_10]      = CHNL_BW_20,
+};
+
+u8 width_to_bw(enum nl80211_chan_width width)
+{
+       if (width <= NL80211_CHAN_WIDTH_10)
+               return nl_width_to_phy_bw[width];
+
+       return NL80211_CHAN_WIDTH_20;
+}
+
+static const int phy_bw_to_nl_width[] = {
+       [CHNL_BW_20]  = NL80211_CHAN_WIDTH_20,
+       [CHNL_BW_40]  = NL80211_CHAN_WIDTH_40,
+       [CHNL_BW_80]  = NL80211_CHAN_WIDTH_80,
+       [CHNL_BW_160] = NL80211_CHAN_WIDTH_160,
+};
+
+enum nl80211_chan_width bw_to_width(u8 bw)
+{
+       if (bw < CHNL_BW_MAX)
+               return phy_bw_to_nl_width[bw];
+
+       return CHNL_BW_20;
+}
+
+bool cl_is_valid_auth_mode(bool is_wpa, u8 auth_mode)
+{
+       return is_wpa ? (auth_mode <= CL_AKM_SUITE_PSK) :
+               (auth_mode <= CL_AKM_SUITE_FT_FILS_SHA384);
+}
+
+bool cl_is_open_auth_mode(u8 auth_mode)
+{
+       return auth_mode == CL_AKM_SUITE_OPEN;
+}
+
+u64 cl_get_tsf_u64(struct cl_hw *cl_hw)
+{
+       u32 tsf_low = mac_hw_tsf_lo_get(cl_hw);
+       u32 tsf_high = mac_hw_tsf_hi_get(cl_hw);
+       u64 tsf;
+
+       if (tsf_low > CL_TSF_LOW_MIGHT_OVERFLOW_TH) {
+               u32 tmp_tsf_low = mac_hw_tsf_lo_get(cl_hw);
+
+               /* Overflow of tsf_low occurred */
+               if (tmp_tsf_low < 0xFFFFF000)
+                       tsf_high++;
+       }
+
+       tsf = ((u64)tsf_high << 32) | (u64)tsf_low;
+
+       return tsf;
+}
+
+u8 cl_center_freq_offset(u8 bw)
+{
+       if (bw == CHNL_BW_160)
+               return 70;
+
+       if (bw == CHNL_BW_80)
+               return 30;
+
+       if (bw == CHNL_BW_40)
+               return 10;
+
+       return 0;
+}
+
+u8 max_bw_idx(u8 wrs_mode, bool is_24g)
+{
+       if (wrs_mode < WRS_MODE_HT)
+               return CHNL_BW_20 + 1;
+
+       if (wrs_mode == WRS_MODE_HT || is_24g)
+               return CHNL_BW_40 + 1;
+
+       return CHNL_BW_MAX;
+}
+
+bool cl_hw_mode_is_b_or_bg(struct cl_hw *cl_hw)
+{
+       return (cl_hw->conf->ha_hw_mode == HW_MODE_B ||
+               cl_hw->conf->ha_hw_mode == HW_MODE_BG);
+}
+
+void cl_snprintf(char **buf, int *offset, size_t *size, const char *fmt, ...)
+{
+       void *new_buf = NULL;
+       va_list args;
+       u16 str_len = strlen(fmt);
+       u16 new_size;
+
+       if (!*buf) {
+               *size = PAGE_SIZE;
+               *buf = kzalloc(*size, GFP_KERNEL);
+               if (!*buf) {
+                       pr_err("Buffer allocation failed (%u)\n", (u32)*size);
+                       return;
+               }
+       }
+
+       /* Additional space is required */
+       if (str_len > *size - *offset) {
+               new_size = *size * 2;
+               new_buf = kvzalloc(new_size, GFP_KERNEL);
+               if (new_buf) {
+                       *size = new_size;
+                       memcpy(new_buf, *buf, strlen(*buf));
+                       kvfree(*buf);
+                       *buf = new_buf;
+               } else {
+                       pr_err("Buffer allocation failed (%u)\n", (u32)*size);
+                       return;
+               }
+       }
+
+       va_start(args, fmt);
+       *offset += vsnprintf(*buf + *offset, *size, fmt, args);
+       va_end(args);
+}
+
+bool cl_is_eapol(struct sk_buff *skb)
+{
+       struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
+       __le16 fc = hdr->frame_control;
+       unsigned int hdrlen = 0;
+       unsigned short ethertype = 0;
+       u8 *temp = NULL;
+
+       /* Find the wireless header size */
+       hdrlen = ieee80211_has_a4(fc) ? 30 : 24;
+
+       if (ieee80211_is_data_qos(fc)) {
+               hdrlen += IEEE80211_QOS_CTL_LEN;
+
+               if (ieee80211_has_order(fc))
+                       hdrlen += IEEE80211_HT_CTL_LEN;
+       }
+
+       /* Skip wireless header */
+       temp = (u8 *)(skb->data + hdrlen);
+
+       /* Skip LLC and SNAP header */
+       if (PKT_HAS_LLC_HDR(temp))
+               ethertype = get_ether_type(LENGTH_LLC + LENGTH_SSNAP - 2, temp);
+
+       return (ethertype == ETH_P_PAE) ? true : 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.
________________________________


^ permalink raw reply related	[flat|nested] 262+ messages in thread

* [RFC v1 230/256] cl8k: add utils/utils.h
  2021-06-17 15:58 [RFC v1 000/256] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (228 preceding siblings ...)
  2021-06-17 16:01 ` [RFC v1 229/256] cl8k: add utils/utils.c viktor.barna
@ 2021-06-17 16:01 ` viktor.barna
  2021-06-17 16:01 ` [RFC v1 231/256] cl8k: add vendor_cmd.c viktor.barna
                   ` (27 subsequent siblings)
  257 siblings, 0 replies; 262+ messages in thread
From: viktor.barna @ 2021-06-17 16:01 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Oleksandr Savchenko, Shay Bar, Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

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

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 .../net/wireless/celeno/cl8k/utils/utils.h    | 104 ++++++++++++++++++
 1 file changed, 104 insertions(+)
 create mode 100644 drivers/net/wireless/celeno/cl8k/utils/utils.h

diff --git a/drivers/net/wireless/celeno/cl8k/utils/utils.h b/drivers/net/wireless/celeno/cl8k/utils/utils.h
new file mode 100644
index 000000000000..d08cb23513ef
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/utils/utils.h
@@ -0,0 +1,104 @@
+/* SPDX-License-Identifier: MIT */
+/* Copyright(c) 2019-2021, Celeno Communications Ltd. */
+
+#ifndef CL_UTILS_H
+#define CL_UTILS_H
+
+#include "hw.h"
+#include "vendor_cmd.h"
+#include "vif.h"
+#include "ipc_shared.h"
+#include "ieee80211_i.h"
+
+static const u8 tid_to_ac[] = {
+       AC_BE, AC_BK, AC_BK, AC_BE, AC_VI, AC_VI, AC_VO, AC_VO
+};
+
+static inline struct cl_vif *NETDEV_TO_CL_VIF(struct net_device *dev)
+{
+       struct ieee80211_sub_if_data *sdata = netdev_priv(dev);
+
+       return (struct cl_vif *)(sdata->vif.drv_priv);
+}
+
+static inline struct cl_hw *NETDEV_TO_CL_HW(struct net_device *dev)
+{
+       struct ieee80211_sub_if_data *sdata = netdev_priv(dev);
+
+       return sdata->local->hw.priv;
+}
+
+static inline struct cl_hw *WIPHY_TO_CL_HW(struct wiphy *wiphy)
+{
+       struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy);
+
+       return (struct cl_hw *)hw->priv;
+}
+
+void cl_hex_dump(char *caption, u8 *buffer, u32 length, u32 offset, bool is_byte);
+
+bool cl_is_valid_auth_mode(bool wpa_ie, u8 auth_mode);
+bool cl_is_open_auth_mode(u8 auth_mode);
+u8 convert_gi_format_wrs_to_fw(u8 wrs_mode, u8 gi);
+u8 convert_gi_format_fw_to_wrs(u8 format_mode, u8 gi);
+u8 cl_map_gi_to_ltf(u8 mode, u8 gi);
+
+s8 cl_calc_noise_floor(struct cl_hw *cl_hw, const s8 *reg_noise_floor);
+
+u8 cl_convert_signed_to_reg_value(s8 val);
+
+u8 width_to_bw(enum nl80211_chan_width width);
+enum nl80211_chan_width bw_to_width(u8 bw);
+u64 cl_get_tsf_u64(struct cl_hw *cl_hw);
+
+u8 cl_center_freq_offset(u8 bw);
+
+u8 max_bw_idx(u8 wrs_mode, bool is_24g);
+
+bool cl_hw_mode_is_b_or_bg(struct cl_hw *cl_hw);
+
+void cl_snprintf(char **buf, int *offset, size_t *size, const char *fmt, ...);
+
+bool cl_is_eapol(struct sk_buff *skb);
+
+static inline bool cl_are_host_bytes_le(void)
+{
+#ifdef __LITTLE_ENDIAN
+       return true;
+#else
+       return false;
+#endif /* __LITTLE_ENDIAN */
+}
+
+/* Most likely, bit endianess is the same as the byte endianess, but turn on
+ * paranoid mode and check separately */
+static inline bool cl_are_host_bits_le(void)
+{
+#ifdef __LITTLE_ENDIAN_BITFIELD
+       return true;
+#else
+       return false;
+#endif /* __LITTLE_ENDIAN_BITFIELD */
+}
+
+/* We could inverse *_le checks here, but the motivation is the, as per bits
+ * endianess - anyway, it is better to check */
+static inline bool cl_are_host_bytes_be(void)
+{
+#ifdef __BIG_ENDIAN
+       return true;
+#else
+       return false;
+#endif /* __BIG_ENDIAN */
+}
+
+static inline bool cl_are_host_bits_be(void)
+{
+#ifdef __BIG_ENDIAN_BITFIELD
+       return true;
+#else
+       return false;
+#endif /* __BIG_ENDIAN_BITFIELD */
+}
+
+#endif /* CL_UTILS_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.
________________________________


^ permalink raw reply related	[flat|nested] 262+ messages in thread

* [RFC v1 231/256] cl8k: add vendor_cmd.c
  2021-06-17 15:58 [RFC v1 000/256] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (229 preceding siblings ...)
  2021-06-17 16:01 ` [RFC v1 230/256] cl8k: add utils/utils.h viktor.barna
@ 2021-06-17 16:01 ` viktor.barna
  2021-06-17 16:01 ` [RFC v1 232/256] cl8k: add vendor_cmd.h viktor.barna
                   ` (26 subsequent siblings)
  257 siblings, 0 replies; 262+ messages in thread
From: viktor.barna @ 2021-06-17 16:01 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Oleksandr Savchenko, Shay Bar, Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

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

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 drivers/net/wireless/celeno/cl8k/vendor_cmd.c | 377 ++++++++++++++++++
 1 file changed, 377 insertions(+)
 create mode 100644 drivers/net/wireless/celeno/cl8k/vendor_cmd.c

diff --git a/drivers/net/wireless/celeno/cl8k/vendor_cmd.c b/drivers/net/wireless/celeno/cl8k/vendor_cmd.c
new file mode 100644
index 000000000000..812eebe72956
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/vendor_cmd.c
@@ -0,0 +1,377 @@
+// SPDX-License-Identifier: MIT
+/* Copyright(c) 2019-2021, Celeno Communications Ltd. */
+
+#include <net/cfg80211.h>
+#include <net/mac80211.h>
+#include <linux/version.h>
+#include "vendor_cmd.h"
+#include "calib.h"
+#include "e2p.h"
+#include "ate.h"
+#include "cecli.h"
+#include "utils/utils.h"
+
+static int vendor_reply(struct wiphy *wiphy, void *data, u16 len)
+{
+       /* Utility function to send reply message */
+       struct sk_buff *msg = cfg80211_vendor_cmd_alloc_reply_skb(wiphy, len);
+       struct cl_hw *cl_hw = WIPHY_TO_CL_HW(wiphy);
+       struct cl_msg_data *msg_data = (struct cl_msg_data *)data;
+
+       if (!msg)
+               return -ENOMEM;
+
+       if (data) {
+               if (nla_put(msg, CL_VENDOR_ATTR_REPLY, len, (void *)msg_data) < 0) {
+                       kfree_skb(msg);
+                       return -ENOBUFS;
+               }
+       }
+
+       /* Start timer if we waiting for more msg's from userspace */
+       if (msg_data->more_data)
+               cl_timer_enable(&cl_hw->vendor_timer);
+
+       return cfg80211_vendor_cmd_reply(msg);
+}
+
+static int _cl_vendor_reply(struct cl_hw *cl_hw, void *data, u16 len, bool process_data)
+{
+       struct cl_vendor_msg *vendor_msg = &cl_hw->vendor_msg;
+       struct cl_msg_data *msg_data = NULL;
+       int ret = 0;
+       u16 curr_size;
+
+       if (!data || len == 0)
+               return -EIO;
+
+       msg_data = kzalloc(sizeof(*msg_data), GFP_KERNEL);
+       if (!msg_data)
+               return -ENOMEM;
+
+       /* Messages 2..N */
+       if (process_data) {
+               curr_size = vendor_msg->len - vendor_msg->offset;
+               if (curr_size <= MSG_SIZE) {
+                       vendor_msg->in_process = false;
+               } else {
+                       curr_size = MSG_SIZE;
+                       msg_data->more_data = 1;
+               }
+
+               memcpy(msg_data->data, vendor_msg->buf + vendor_msg->offset, curr_size);
+               vendor_msg->offset += curr_size;
+               ret = vendor_reply(cl_hw->hw->wiphy, (void *)msg_data, sizeof(*msg_data));
+
+               /* Last msg */
+               if (!vendor_msg->in_process)
+                       memset(vendor_msg, 0, sizeof(*vendor_msg));
+
+               goto out;
+       }
+
+       /* Single message */
+       if (len < MSG_SIZE) {
+               memcpy(msg_data->data, data, len);
+               ret = vendor_reply(cl_hw->hw->wiphy, (void *)msg_data, sizeof(*msg_data));
+               goto out;
+       } else if (vendor_msg->in_process) {
+               goto out;
+       }
+
+       /* First message */
+       msg_data->more_data = 1;
+
+       /* Allocate buffer in driver */
+       vendor_msg->buf = data;
+
+       vendor_msg->in_process = true;
+       vendor_msg->len = len;
+
+       memcpy(msg_data->data, data, MSG_SIZE);
+       vendor_msg->offset += MSG_SIZE;
+       ret = vendor_reply(cl_hw->hw->wiphy, (void *)msg_data, sizeof(*msg_data));
+
+out:
+       kfree(msg_data);
+       return ret;
+}
+
+static int cl_vendor_cecli_handler(struct wiphy *wiphy,
+                                  struct wireless_dev *wdev,
+                                  const void *data, int len)
+{
+       struct cl_hw *cl_hw = WIPHY_TO_CL_HW(wiphy);
+       u8 cecli_cmd_id = *(u8 *)data;
+       void *real_data = (u8 *)(data + 1);
+
+       len--;
+
+       cl_timer_disable_sync(&cl_hw->vendor_timer);
+       if (cl_hw->vendor_msg.in_process &&
+           cecli_cmd_id == CL_CECLI_MORE_DATA)
+               return _cl_vendor_reply(cl_hw, real_data, len, true);
+
+       switch (cecli_cmd_id) {
+       case CL_CECLI_AGC_PARAMS:
+               return cl_cecli_agc_params(wiphy, wdev, real_data, len);
+       case CL_CECLI_BF:
+               return cl_cecli_bf(wiphy, wdev, real_data, len);
+       case CL_CECLI_CALIB:
+               return cl_cecli_calib(wiphy, wdev, real_data, len);
+       case CL_CECLI_CCA:
+               return cl_cecli_cca(wiphy, wdev, real_data, len);
+       case CL_CECLI_CHIP:
+               return cl_cecli_chip(wiphy, wdev, real_data, len);
+       case CL_CECLI_CONFIG:
+               return cl_cecli_config(wiphy, wdev, real_data, len);
+       case CL_CECLI_DEBUG:
+               return cl_cecli_debug(wiphy, wdev, real_data, len);
+       case CL_CECLI_DFS:
+               return cl_cecli_dfs(wiphy, wdev, real_data, len);
+       case CL_CECLI_EDCA:
+               return cl_cecli_edca(wiphy, wdev, real_data, len);
+       case CL_CECLI_FW:
+               return cl_cecli_fw(wiphy, wdev, real_data, len);
+       case CL_CECLI_MOTION:
+               return cl_cecli_motion(wiphy, wdev, real_data, len);
+       case CL_CECLI_NOISE:
+               return cl_cecli_noise(wiphy, wdev, real_data, len);
+       case CL_CECLI_OMI:
+               return cl_cecli_omi(wiphy, wdev, real_data, len);
+       case CL_CECLI_POWER:
+               return cl_cecli_power(wiphy, wdev, real_data, len);
+       case CL_CECLI_QOS:
+               return cl_cecli_qos(wiphy, wdev, real_data, len);
+       case CL_CECLI_RADIO:
+               return cl_cecli_radio(wiphy, wdev, real_data, len);
+       case CL_CECLI_REG:
+               return cl_cecli_reg(wiphy, wdev, real_data, len);
+       case CL_CECLI_SOUNDING:
+               return cl_cecli_sounding(wiphy, wdev, real_data, len);
+       case CL_CECLI_STATS:
+               return cl_cecli_stats(wiphy, wdev, real_data, len);
+       case CL_CECLI_TCV:
+               return cl_cecli_tcv(wiphy, wdev, real_data, len);
+       case CL_CECLI_TEMP:
+               return cl_cecli_temp(wiphy, wdev, real_data, len);
+       case CL_CECLI_TRAFFIC:
+               return cl_cecli_traffic(wiphy, wdev, real_data, len);
+       case CL_CECLI_TWT:
+               return cl_cecli_twt(wiphy, wdev, real_data, len);
+       case CL_CECLI_TXQ:
+               return cl_cecli_txq(wiphy, wdev, real_data, len);
+       case CL_CECLI_VERSION:
+               return cl_cecli_version(wiphy, wdev, real_data, len);
+       case CL_CECLI_VNS:
+               return cl_cecli_vns(wiphy, wdev, real_data, len);
+       case CL_CECLI_WRS:
+               return cl_cecli_wrs(wiphy, wdev, real_data, len);
+       default:
+               return cl_cecli_help(wiphy, wdev, real_data, len);
+       }
+
+       return 0;
+}
+
+static int cl_vendor_e2p_handler(struct wiphy *wiphy,
+                                struct wireless_dev *wdev,
+                                const void *data, int len)
+{
+       u8 e2p_cmd_id = *(u8 *)data;
+       void *real_data = (u8 *)(data + 1);
+
+       len--;
+
+       switch (e2p_cmd_id) {
+       case CL_E2P_GET_ADDR:
+       case CL_E2P_GET_MAC:
+       case CL_E2P_GET_SERIAL_NUMBER:
+       case CL_E2P_GET_PWR_TABLE_ID:
+       case CL_E2P_GET_FREQ_OFFSET:
+       case CL_E2P_GET_WIRING_ID:
+       case CL_E2P_GET_FEM_LUT:
+       case CL_E2P_GET_PLATFORM_ID:
+       case CL_E2P_GET_HEXDUMP:
+       case CL_E2P_GET_TABLE:
+               return cl_e2p_get_addr(wiphy, wdev, real_data, len);
+       case CL_E2P_GET_CALIB:
+               return cl_calib_get(wiphy, wdev, real_data, len);
+       case CL_E2P_SET_ADDR:
+       case CL_E2P_SET_MAC:
+       case CL_E2P_SET_SERIAL_NUMBER:
+       case CL_E2P_SET_PWR_TABLE_ID:
+       case CL_E2P_SET_FREQ_OFFSET:
+       case CL_E2P_SET_FEM_LUT:
+       case CL_E2P_SET_PLATFORM_ID:
+               return cl_e2p_set_addr(wiphy, wdev, real_data, len);
+       case CL_E2P_SET_WIRING_ID:
+               return cl_e2p_set_wiring_id(wiphy, wdev, real_data, len);
+       case CL_E2P_SET_CALIB:
+               return cl_calib_set(wiphy, wdev, real_data, len);
+       default:
+               return cl_e2p_help(wiphy, wdev, real_data, len);
+       }
+
+       return 0;
+}
+
+static int cl_vendor_ate_handler(struct wiphy *wiphy,
+                                struct wireless_dev *wdev,
+                                const void *data, int len)
+{
+       u8 ate_cmd_id = *(u8 *)data;
+       void *real_data = (u8 *)(data + 1);
+
+       len--;
+
+       switch (ate_cmd_id) {
+       case CL_ATE_RESET:
+               return cl_ate_reset(wiphy, wdev, real_data, len);
+       case CL_ATE_MODE:
+               return cl_ate_mode(wiphy, wdev, real_data, len);
+       case CL_ATE_BW:
+               return cl_ate_bw(wiphy, wdev, real_data, len);
+       case CL_ATE_MCS:
+               return cl_ate_mcs(wiphy, wdev, real_data, len);
+       case CL_ATE_NSS:
+               return cl_ate_nss(wiphy, wdev, real_data, len);
+       case CL_ATE_GI:
+               return cl_ate_gi(wiphy, wdev, real_data, len);
+       case CL_ATE_LTF:
+               return cl_ate_ltf(wiphy, wdev, real_data, len);
+       case CL_ATE_LDPC:
+               return cl_ate_ldpc(wiphy, wdev, real_data, len);
+       case CL_ATE_CHANNEL:
+               return cl_ate_channel(wiphy, wdev, real_data, len);
+       case CL_ATE_ANT:
+               return cl_ate_ant(wiphy, wdev, real_data, len);
+       case CL_ATE_MULTI_ANT:
+               return cl_ate_multi_ant(wiphy, wdev, real_data, len);
+       case CL_ATE_PACKET_LEN:
+               return cl_ate_packet_len(wiphy, wdev, real_data, len);
+       case CL_ATE_VECTOR_RESET:
+               return cl_ate_vector_reset(wiphy, wdev, real_data, len);
+       case CL_ATE_VECTOR:
+               return cl_ate_vector(wiphy, wdev, real_data, len);
+       case CL_ATE_FREQ_OFFSET:
+               return cl_ate_freq_offset(wiphy, wdev, real_data, len);
+       case CL_ATE_STAT_RESET:
+               return cl_ate_stat_reset(wiphy, wdev, real_data, len);
+       case CL_ATE_STAT:
+               return cl_ate_stat(wiphy, wdev, real_data, len);
+       case CL_ATE_POWER:
+               return cl_ate_power(wiphy, wdev, real_data, len);
+       case CL_ATE_POWER_OFFSET:
+               return cl_ate_power_offset(wiphy, wdev, real_data, len);
+       case CL_ATE_TX_START:
+               return cl_ate_tx_start(wiphy, wdev, real_data, len);
+       case CL_ATE_TX_CONTINUOUS:
+               return cl_ate_tx_continuous(wiphy, wdev, real_data, len);
+       case CL_ATE_STOP:
+               return cl_ate_stop(wiphy, wdev, real_data, len);
+       default:
+               return cl_ate_help(wiphy, wdev, real_data, len);
+       }
+
+       return 0;
+}
+
+static int cl_vendor_help_handler(struct wiphy *wiphy,
+                                 struct wireless_dev *wdev,
+                                 const void *data, int len)
+{
+       struct cl_hw *cl_hw = WIPHY_TO_CL_HW(wiphy);
+       char ret_buf[] = {
+               "usage:\n"
+               "cecli - Celeno driver related\n"
+               "e2p   - Celeno eeprom related\n"
+               "ATE   - Celeno production related\n"
+       };
+
+       return cl_vendor_reply(cl_hw, ret_buf, strlen(ret_buf));
+}
+
+static void cl_vendor_handle_timeout(unsigned long data)
+{
+       struct cl_hw *cl_hw = (struct cl_hw *)data;
+       struct cl_vendor_msg *vendor_msg = &cl_hw->vendor_msg;
+
+       memset(vendor_msg, 0, sizeof(*vendor_msg));
+       pr_warn("cl_vendor timer expired!\n");
+}
+
+int cl_vendor_reply(struct cl_hw *cl_hw, void *data, u16 len)
+{
+       return _cl_vendor_reply(cl_hw, data, len, false);
+}
+
+void cl_vendor_timer_init(struct cl_hw *cl_hw)
+{
+       /* Init vendor_cmd timer */
+       cl_timer_init(&cl_hw->vendor_timer, cl_vendor_handle_timeout,
+                     (unsigned long)cl_hw, VENDOR_CMD_TIMER_PERIOD_MS, false);
+}
+
+void cl_vendor_timer_close(struct cl_hw *cl_hw)
+{
+       cl_timer_disable_sync(&cl_hw->vendor_timer);
+}
+
+/* Vendor specific commands */
+const struct wiphy_vendor_command cl_vendor_cmds[] = {
+       {
+               .info.vendor_id = CELENO_OUI,
+               .info.subcmd = CL_VNDR_CMDS_CECLI,
+               .flags = WIPHY_VENDOR_CMD_NEED_WDEV |
+                       WIPHY_VENDOR_CMD_NEED_RUNNING |
+                       WIPHY_VENDOR_CMD_NEED_NETDEV,
+               .policy = VENDOR_CMD_RAW_DATA,
+               .doit = cl_vendor_cecli_handler
+       },
+       {
+               .info.vendor_id = CELENO_OUI,
+               .info.subcmd = CL_VNDR_CMDS_E2P,
+               .flags = WIPHY_VENDOR_CMD_NEED_WDEV |
+                       WIPHY_VENDOR_CMD_NEED_RUNNING |
+                       WIPHY_VENDOR_CMD_NEED_NETDEV,
+               .policy = VENDOR_CMD_RAW_DATA,
+               .doit = cl_vendor_e2p_handler
+       },
+       {
+               .info.vendor_id = CELENO_OUI,
+               .info.subcmd = CL_VNDR_CMDS_ATE,
+               .flags = WIPHY_VENDOR_CMD_NEED_WDEV |
+                       WIPHY_VENDOR_CMD_NEED_RUNNING |
+                       WIPHY_VENDOR_CMD_NEED_NETDEV,
+               .policy = VENDOR_CMD_RAW_DATA,
+               .doit = cl_vendor_ate_handler
+       },
+       {
+               .info.vendor_id = CELENO_OUI,
+               .info.subcmd = CL_VNDR_CMDS_HELP,
+               .flags = WIPHY_VENDOR_CMD_NEED_WDEV |
+                       WIPHY_VENDOR_CMD_NEED_RUNNING |
+                       WIPHY_VENDOR_CMD_NEED_NETDEV,
+               .policy = VENDOR_CMD_RAW_DATA,
+               .doit = cl_vendor_help_handler
+       },
+};
+
+/* Vendor specific events */
+const struct nl80211_vendor_cmd_info cl_vendor_events[] = {
+       {
+               .vendor_id = CELENO_OUI,
+               .subcmd = CL_VENDOR_EVENT_ASYNC,
+       }
+};
+
+void cl_vendor_cmds_init(struct wiphy *wiphy)
+{
+       /* Set celeno vendor commands used by nl80211 */
+       wiphy->vendor_commands = cl_vendor_cmds;
+       wiphy->n_vendor_commands = ARRAY_SIZE(cl_vendor_cmds);
+       wiphy->vendor_events = cl_vendor_events;
+       wiphy->n_vendor_events = ARRAY_SIZE(cl_vendor_events);
+}
+
--
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.
________________________________


^ permalink raw reply related	[flat|nested] 262+ messages in thread

* [RFC v1 232/256] cl8k: add vendor_cmd.h
  2021-06-17 15:58 [RFC v1 000/256] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (230 preceding siblings ...)
  2021-06-17 16:01 ` [RFC v1 231/256] cl8k: add vendor_cmd.c viktor.barna
@ 2021-06-17 16:01 ` viktor.barna
  2021-06-17 16:02 ` [RFC v1 233/256] cl8k: add version.c viktor.barna
                   ` (25 subsequent siblings)
  257 siblings, 0 replies; 262+ messages in thread
From: viktor.barna @ 2021-06-17 16:01 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Oleksandr Savchenko, Shay Bar, Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

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

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 drivers/net/wireless/celeno/cl8k/vendor_cmd.h | 116 ++++++++++++++++++
 1 file changed, 116 insertions(+)
 create mode 100644 drivers/net/wireless/celeno/cl8k/vendor_cmd.h

diff --git a/drivers/net/wireless/celeno/cl8k/vendor_cmd.h b/drivers/net/wireless/celeno/cl8k/vendor_cmd.h
new file mode 100644
index 000000000000..9c7c3fe571be
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/vendor_cmd.h
@@ -0,0 +1,116 @@
+/* SPDX-License-Identifier: MIT */
+/* Copyright(c) 2019-2021, Celeno Communications Ltd. */
+
+#ifndef CL_VENDOR_CMD_H
+#define CL_VENDOR_CMD_H
+
+/*
+ * DOC: Vendor commands
+ *
+ * A driver supporting vendor commands must register them as an array
+ * in struct wiphy, with handlers for each one, each command has an
+ * OUI and sub command ID to identify it.
+ *
+ * Note that this feature should not be (ab)used to implement protocol
+ * features that could openly be shared across drivers. In particular,
+ * it must never be required to use vendor commands to implement any
+ * "normal" functionality that higher-level userspace like connection
+ * managers etc. need.
+ */
+
+#include "def.h"
+#include "e2p.h"
+
+#define VENDOR_CMD_TIMER_PERIOD_MS 5000
+
+/* Celeno OUI - see http://www.my-ip.club/oui-info/00-1C-51 */
+#define CELENO_OUI 0x001c51
+
+struct cl_hw;
+
+enum cl_vndr_cmds {
+       CL_VNDR_CMDS_UNSPEC,
+       CL_VNDR_CMDS_CECLI,
+       CL_VNDR_CMDS_E2P,
+       CL_VNDR_CMDS_ATE,
+       CL_VNDR_CMDS_HELP,
+       CL_VNDR_CMDS_LAST
+};
+
+enum cl_vndr_events {
+       CL_VENDOR_EVENT_ASYNC,
+
+       CL_VENDOR_EVENT_LAST
+};
+
+/* Enum cl_vndr_nlattrs - nl80211 message attributes */
+enum cl_vndr_nlattrs {
+       CL_VENDOR_ATTR_UNSPEC,
+       CL_VENDOR_ATTR_REPLY,
+       CL_VENDOR_ATTR_DATA,
+       CL_VENDOR_ATTR_LEN,
+
+       NUM_CL_VENDOR_ATTR,
+       MAX_CL_VENDOR_ATTR = NUM_CL_VENDOR_ATTR - 1
+};
+
+struct point {
+       u8 chan;
+       u8 phy;
+       u8 idx;
+       u16 addr;
+       struct eeprom_phy_calib calib;
+} __packed;
+
+#define CLI_MAX_PARAMS 32
+
+enum {
+       E2P_MODE_BIN,
+       E2P_MODE_EEPROM,
+
+       E2P_MODE_MAX
+};
+
+struct wiphy;
+void cl_vendor_cmds_init(struct wiphy *wiphy);
+
+/* Note: data structures used by kernel and by userspace */
+struct ate_stats {
+       u32 tx_bw20;
+       u32 tx_bw40;
+       u32 tx_bw80;
+       u32 tx_bw160;
+       u32 rx_bw20;
+       u32 rx_bw40;
+       u32 rx_bw80;
+       u32 rx_bw160;
+       u32 fcs_err;
+       u32 phy_err;
+       u32 delimiter_err;
+       u32 rx_success;
+       s8 rssi0;
+       s8 rssi1;
+       s8 rssi2;
+       s8 rssi3;
+       s8 rssi4;
+       s8 rssi5;
+};
+
+struct cli_params {
+       u32 num_params;
+       char option;
+       s32 params[CLI_MAX_PARAMS];
+};
+
+#define MSG_SIZE 4095
+
+struct cl_msg_data {
+       char more_data;
+       char data[MSG_SIZE];
+} __attribute__((__packed__));
+
+int cl_vendor_reply(struct cl_hw *cl_hw, void *data, u16 len);
+void cl_vendor_timer_init(struct cl_hw *cl_hw);
+void cl_vendor_timer_close(struct cl_hw *cl_hw);
+
+#endif /* CL_VENDOR_CMD_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.
________________________________


^ permalink raw reply related	[flat|nested] 262+ messages in thread

* [RFC v1 233/256] cl8k: add version.c
  2021-06-17 15:58 [RFC v1 000/256] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (231 preceding siblings ...)
  2021-06-17 16:01 ` [RFC v1 232/256] cl8k: add vendor_cmd.h viktor.barna
@ 2021-06-17 16:02 ` viktor.barna
  2021-06-17 16:02 ` [RFC v1 234/256] cl8k: add version.h viktor.barna
                   ` (24 subsequent siblings)
  257 siblings, 0 replies; 262+ messages in thread
From: viktor.barna @ 2021-06-17 16:02 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Oleksandr Savchenko, Shay Bar, Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

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

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 drivers/net/wireless/celeno/cl8k/version.c | 129 +++++++++++++++++++++
 1 file changed, 129 insertions(+)
 create mode 100644 drivers/net/wireless/celeno/cl8k/version.c

diff --git a/drivers/net/wireless/celeno/cl8k/version.c b/drivers/net/wireless/celeno/cl8k/version.c
new file mode 100644
index 000000000000..4ac0bea0ae62
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/version.c
@@ -0,0 +1,129 @@
+// SPDX-License-Identifier: MIT
+/* Copyright(c) 2019-2021, Celeno Communications Ltd. */
+
+#include "version.h"
+#include "fw/msg_tx.h"
+#include "debug.h"
+#include "chip.h"
+#include "utils/utils.h"
+
+/*
+ * Don't move this define to a different file, and
+ * don't change the default version.
+ */
+#define HP_VERSION "8.0.0.0.0.0"
+
+static int cl_version_request(struct cl_hw *cl_hw)
+{
+       struct mm_version_cfm *cfm = NULL;
+       struct cl_version_db *vd = &cl_hw->version_db;
+       int ret = 0;
+
+       ret = cl_msg_tx_version(cl_hw);
+       if (ret)
+               return ret;
+
+       cfm = (struct mm_version_cfm *)cl_hw->msg_cfm_params[MM_VERSION_CFM];
+       if (!cfm)
+               return -ENOMSG;
+
+       vd->last_update = jiffies;
+       vd->dsp = le32_to_cpu(cfm->versions.dsp);
+       vd->rfic_sw = le32_to_cpu(cfm->versions.rfic_sw);
+       vd->rfic_hw = le32_to_cpu(cfm->versions.rfic_hw);
+       vd->agcram = le32_to_cpu(cfm->versions.agcram);
+
+       cl_hw->rf_crystal_mhz = cfm->rf_crystal_mhz;
+
+       strncpy(vd->fw, cfm->versions.fw, sizeof(vd->fw));
+       vd->fw[sizeof(vd->fw) - 1] = '\0';
+
+       strncpy(vd->drv, HP_VERSION, sizeof(vd->drv));
+       vd->drv[sizeof(vd->drv) - 1] = '\0';
+
+       cl_msg_tx_free_cfm_params(cl_hw, MM_VERSION_CFM);
+
+       return ret;
+}
+
+int cl_version_read(struct cl_hw *cl_hw, bool reply)
+{
+       struct cl_chip *chip = cl_hw->chip;
+       struct cl_version_db *vd = &cl_hw->version_db;
+       int ret = 0;
+       struct cl_agc_profile *agc_profile1 = &cl_hw->phy_data_info.data->agc_params.profile1;
+       struct cl_agc_profile *agc_profile2 = &cl_hw->phy_data_info.data->agc_params.profile2;
+       char *buf = NULL;
+       ssize_t bufsz;
+       int len = 0;
+       u32 version_agcram, major, minor, internal;
+
+       /* Request data if existing is not actual */
+       if (!vd->last_update && (ret = cl_version_request(cl_hw)))
+               return ret;
+
+       /* PHY components specifics */
+       cl_snprintf(&buf, &len, &bufsz, "DRV VERSION: %s\n", vd->drv);
+       cl_snprintf(&buf, &len, &bufsz, "FW VERSION: %s\n", vd->fw);
+       cl_snprintf(&buf, &len, &bufsz, "DSP VERSION: 0x%-.8X\n", vd->dsp);
+       cl_snprintf(&buf, &len, &bufsz, "RFIC SW VERSION: %u\n", vd->rfic_sw);
+       cl_snprintf(&buf, &len, &bufsz, "RFIC HW VERSION: 0x%X\n", vd->rfic_hw);
+
+       version_agcram = vd->agcram;
+       major = (version_agcram >> 16) & 0xffff;
+       minor = (version_agcram >> 8) & 0xff;
+       internal = version_agcram & 0xff;
+       cl_snprintf(&buf, &len, &bufsz,
+                   "AGC RAM VERSION: B.%x.%x.%x\n",
+                   major, minor, internal);
+
+       cl_agc_params_print_profile(&buf, &len, &bufsz, agc_profile1,
+                                   "AGC PARAMS PROFILE:");
+       cl_agc_params_print_profile(&buf, &len, &bufsz, agc_profile2,
+                                   "AGC PARAMS PROFILE (Elastic):");
+       cl_snprintf(&buf, &len, &bufsz, "TX POWER VERSION: %u\n", cl_hw->tx_power_version);
+
+       if (IS_PHY_OLYMPUS(chip))
+               cl_snprintf(&buf, &len, &bufsz, "RFIC TYPE: OLYMPUS\n");
+       else
+               cl_snprintf(&buf, &len, &bufsz, "RFIC TYPE: ATHOS\n");
+
+       cl_snprintf(&buf, &len, &bufsz, "RF CRYSTAL: %uMHz\n",
+                   cl_hw->rf_crystal_mhz);
+
+       if (reply)
+               ret = cl_vendor_reply(cl_hw, buf, len);
+       else
+               pr_debug("%s\n", buf);
+
+       kfree(buf);
+
+       return ret;
+}
+
+int cl_version_update(struct cl_hw *cl_hw)
+{
+       int ret = 0;
+
+       /* Force logic to update versions */
+       cl_hw->version_db.last_update = 0;
+
+       ret = cl_version_read(cl_hw, false);
+
+       /* Share version info */
+       if (ret == 0)
+               cl_version_sync_wiphy(cl_hw, cl_hw->hw->wiphy);
+
+       return ret;
+}
+
+void cl_version_sync_wiphy(struct cl_hw *cl_hw, struct wiphy *wiphy)
+{
+       strncpy(wiphy->fw_version, cl_hw->version_db.fw, sizeof(wiphy->fw_version));
+       wiphy->fw_version[sizeof(wiphy->fw_version) - 1] = '\0';
+}
+
+int cl_version_cli(struct cl_hw *cl_hw)
+{
+       return cl_version_read(cl_hw, true);
+}
--
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.
________________________________


^ permalink raw reply related	[flat|nested] 262+ messages in thread

* [RFC v1 234/256] cl8k: add version.h
  2021-06-17 15:58 [RFC v1 000/256] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (232 preceding siblings ...)
  2021-06-17 16:02 ` [RFC v1 233/256] cl8k: add version.c viktor.barna
@ 2021-06-17 16:02 ` viktor.barna
  2021-06-17 16:02 ` [RFC v1 235/256] cl8k: add vif.c viktor.barna
                   ` (23 subsequent siblings)
  257 siblings, 0 replies; 262+ messages in thread
From: viktor.barna @ 2021-06-17 16:02 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Oleksandr Savchenko, Shay Bar, Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

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

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 drivers/net/wireless/celeno/cl8k/version.h | 14 ++++++++++++++
 1 file changed, 14 insertions(+)
 create mode 100644 drivers/net/wireless/celeno/cl8k/version.h

diff --git a/drivers/net/wireless/celeno/cl8k/version.h b/drivers/net/wireless/celeno/cl8k/version.h
new file mode 100644
index 000000000000..d23a45487636
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/version.h
@@ -0,0 +1,14 @@
+/* SPDX-License-Identifier: MIT */
+/* Copyright(c) 2019-2021, Celeno Communications Ltd. */
+
+#ifndef CL_VERSION_H
+#define CL_VERSION_H
+
+#include "hw.h"
+
+int cl_version_read(struct cl_hw *cl_hw, bool reply);
+int cl_version_update(struct cl_hw *cl_hw);
+void cl_version_sync_wiphy(struct cl_hw *cl_hw, struct wiphy *wiphy);
+int cl_version_cli(struct cl_hw *cl_hw);
+
+#endif /* CL_VERSION_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.
________________________________


^ permalink raw reply related	[flat|nested] 262+ messages in thread

* [RFC v1 235/256] cl8k: add vif.c
  2021-06-17 15:58 [RFC v1 000/256] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (233 preceding siblings ...)
  2021-06-17 16:02 ` [RFC v1 234/256] cl8k: add version.h viktor.barna
@ 2021-06-17 16:02 ` viktor.barna
  2021-06-17 16:02 ` [RFC v1 236/256] cl8k: add vif.h viktor.barna
                   ` (22 subsequent siblings)
  257 siblings, 0 replies; 262+ messages in thread
From: viktor.barna @ 2021-06-17 16:02 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Oleksandr Savchenko, Shay Bar, Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

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

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 drivers/net/wireless/celeno/cl8k/vif.c | 143 +++++++++++++++++++++++++
 1 file changed, 143 insertions(+)
 create mode 100644 drivers/net/wireless/celeno/cl8k/vif.c

diff --git a/drivers/net/wireless/celeno/cl8k/vif.c b/drivers/net/wireless/celeno/cl8k/vif.c
new file mode 100644
index 000000000000..80234de0bb7c
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/vif.c
@@ -0,0 +1,143 @@
+// SPDX-License-Identifier: MIT
+/* Copyright(c) 2019-2021, Celeno Communications Ltd. */
+
+#include "vif.h"
+#include "hw.h"
+#include "mac_addr.h"
+#include "utils/utils.h"
+#include <linux/list.h>
+
+void cl_vif_init(struct cl_hw *cl_hw)
+{
+       INIT_LIST_HEAD(&cl_hw->vif_db.head);
+}
+
+void cl_vif_add(struct cl_hw *cl_hw, struct cl_vif *cl_vif)
+{
+       list_add_tail(&cl_vif->list, &cl_hw->vif_db.head);
+
+       if (cl_vif->vif->type != NL80211_IFTYPE_STATION)
+               cl_hw->vif_db.num_iface_bcn++;
+
+       /* Multicast vif set */
+       cl_hw->mc_vif = cl_vif;
+}
+
+void cl_vif_remove(struct cl_hw *cl_hw, struct cl_vif *cl_vif)
+{
+       /* Multicast vif unset */
+       if (cl_hw->mc_vif == cl_vif)
+               cl_hw->mc_vif = cl_vif_get_next(cl_hw, cl_hw->mc_vif);
+
+       list_del(&cl_vif->list);
+
+       if (cl_vif->vif->type != NL80211_IFTYPE_STATION)
+               cl_hw->vif_db.num_iface_bcn--;
+}
+
+struct cl_vif *cl_vif_get_next(struct cl_hw *cl_hw, struct cl_vif *cl_vif)
+{
+       if (list_is_last(&cl_vif->list, &cl_hw->vif_db.head))
+               return list_first_entry_or_null(&cl_hw->vif_db.head,
+                                               struct cl_vif, list);
+       else
+               return list_next_entry(cl_vif, list);
+}
+
+struct cl_vif *cl_vif_get_by_dev(struct cl_hw *cl_hw, struct net_device *dev)
+{
+       struct cl_vif *cl_vif = NULL;
+
+       list_for_each_entry(cl_vif, &cl_hw->vif_db.head, list)
+               if (cl_vif->dev == dev)
+                       return cl_vif;
+
+       return NULL;
+}
+
+struct cl_vif *cl_vif_get_by_mac(struct cl_hw *cl_hw, u8 *mac_addr)
+{
+       struct cl_vif *cl_vif;
+
+       list_for_each_entry(cl_vif, &cl_hw->vif_db.head, list)
+               if (cl_mac_addr_compare(cl_vif->vif->addr, mac_addr))
+                       return cl_vif;
+
+       return NULL;
+}
+
+struct cl_vif *cl_vif_get_first(struct cl_hw *cl_hw)
+{
+       return list_first_entry_or_null(&cl_hw->vif_db.head, struct cl_vif, list);
+}
+
+struct cl_vif *cl_vif_get_first_ap(struct cl_hw *cl_hw)
+{
+       struct cl_vif *cl_vif;
+
+       list_for_each_entry(cl_vif, &cl_hw->vif_db.head, list)
+               if (cl_vif->vif->type == NL80211_IFTYPE_AP ||
+                   cl_vif->vif->type == NL80211_IFTYPE_MESH_POINT)
+                       return cl_vif;
+
+       return NULL;
+}
+
+struct net_device *cl_vif_get_first_net_device(struct cl_hw *cl_hw)
+{
+       struct cl_vif *cl_vif = list_first_entry_or_null(&cl_hw->vif_db.head, struct cl_vif, list);
+
+       return cl_vif ? cl_vif->dev : NULL;
+}
+
+struct net_device *cl_vif_get_dev_by_index(struct cl_hw *cl_hw, u8 index)
+{
+       struct cl_vif *cl_vif = NULL;
+
+       list_for_each_entry(cl_vif, &cl_hw->vif_db.head, list)
+               if (cl_vif->vif_index == index)
+                       return cl_vif->dev;
+
+       return NULL;
+}
+
+bool cl_vif_find_mac(struct cl_hw *cl_hw, u8 *mac_addr)
+{
+       struct cl_vif *cl_vif;
+
+       list_for_each_entry(cl_vif, &cl_hw->vif_db.head, list)
+               if (cl_mac_addr_compare(cl_vif->vif->addr, mac_addr))
+                       return true;
+
+       return false;
+}
+
+void cl_vif_ap_tx_enable(struct cl_hw *cl_hw, bool enable)
+{
+       struct cl_vif *cl_vif;
+       struct ieee80211_vif *vif;
+
+       list_for_each_entry(cl_vif, &cl_hw->vif_db.head, list) {
+               vif = cl_vif->vif;
+
+               if (vif->type != NL80211_IFTYPE_AP)
+                       continue;
+
+               cl_vif->tx_en = enable;
+               cl_dbg_verbose(cl_hw, "Set tx_en=%u for vif_index=%u\n",
+                              enable, cl_vif->vif_index);
+       }
+}
+
+void cl_vif_bring_all_interfaces_down(struct cl_hw *cl_hw)
+{
+       struct cl_vif *cl_vif = NULL, *cl_vif_tmp = NULL;
+
+       /* Remove all interfaces gracefully to avoid of memleaks and kernel panics */
+       list_for_each_entry_safe(cl_vif, cl_vif_tmp, &cl_hw->vif_db.head, list) {
+               rtnl_lock();
+               dev_close(cl_vif->dev);
+               rtnl_unlock();
+       }
+}
+
--
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.
________________________________


^ permalink raw reply related	[flat|nested] 262+ messages in thread

* [RFC v1 236/256] cl8k: add vif.h
  2021-06-17 15:58 [RFC v1 000/256] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (234 preceding siblings ...)
  2021-06-17 16:02 ` [RFC v1 235/256] cl8k: add vif.c viktor.barna
@ 2021-06-17 16:02 ` viktor.barna
  2021-06-17 16:02 ` [RFC v1 237/256] cl8k: add vns.c viktor.barna
                   ` (21 subsequent siblings)
  257 siblings, 0 replies; 262+ messages in thread
From: viktor.barna @ 2021-06-17 16:02 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Oleksandr Savchenko, Shay Bar, Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

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

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 drivers/net/wireless/celeno/cl8k/vif.h | 44 ++++++++++++++++++++++++++
 1 file changed, 44 insertions(+)
 create mode 100644 drivers/net/wireless/celeno/cl8k/vif.h

diff --git a/drivers/net/wireless/celeno/cl8k/vif.h b/drivers/net/wireless/celeno/cl8k/vif.h
new file mode 100644
index 000000000000..2cfd027ee88c
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/vif.h
@@ -0,0 +1,44 @@
+/* SPDX-License-Identifier: MIT */
+/* Copyright(c) 2019-2021, Celeno Communications Ltd. */
+
+#ifndef CL_VIF_H
+#define CL_VIF_H
+
+#include "wrs/wrs_db.h"
+#include <linux/netdevice.h>
+
+/*
+ * Structure used to save information relative to the managed interfaces.
+ * Will be used as the 'drv_priv' field of the "struct ieee80211_vif" structure.
+ * This is also linked within the cl_hw vifs list.
+ */
+struct cl_vif {
+       struct list_head list;
+       struct cl_hw *cl_hw;
+       struct ieee80211_vif *vif;
+       struct net_device *dev;
+       struct net_device_ops dev_ops;
+       struct ieee80211_key_conf *key_conf;
+       const struct net_device_ops *orig_dev_ops;
+       u16 sequence_number;
+       u8 num_sta; /* Number of station connected per SSID */
+       u8 vif_index;
+       bool tx_en;
+       struct mcast_table *mcast_table;
+};
+
+void cl_vif_init(struct cl_hw *cl_hw);
+void cl_vif_add(struct cl_hw *cl_hw, struct cl_vif *cl_vif);
+void cl_vif_remove(struct cl_hw *cl_hw, struct cl_vif *cl_vif);
+struct cl_vif *cl_vif_get_next(struct cl_hw *cl_hw, struct cl_vif *cl_vif);
+struct cl_vif *cl_vif_get_by_dev(struct cl_hw *cl_hw, struct net_device *dev);
+struct cl_vif *cl_vif_get_by_mac(struct cl_hw *cl_hw, u8 *mac_addr);
+struct cl_vif *cl_vif_get_first(struct cl_hw *cl_hw);
+struct cl_vif *cl_vif_get_first_ap(struct cl_hw *cl_hw);
+struct net_device *cl_vif_get_first_net_device(struct cl_hw *cl_hw);
+struct net_device *cl_vif_get_dev_by_index(struct cl_hw *cl_hw, u8 index);
+bool cl_vif_find_mac(struct cl_hw *cl_hw, u8 *mac_addr);
+void cl_vif_ap_tx_enable(struct cl_hw *cl_hw, bool enable);
+void cl_vif_bring_all_interfaces_down(struct cl_hw *cl_hw);
+
+#endif /* CL_VIF_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.
________________________________


^ permalink raw reply related	[flat|nested] 262+ messages in thread

* [RFC v1 237/256] cl8k: add vns.c
  2021-06-17 15:58 [RFC v1 000/256] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (235 preceding siblings ...)
  2021-06-17 16:02 ` [RFC v1 236/256] cl8k: add vif.h viktor.barna
@ 2021-06-17 16:02 ` viktor.barna
  2021-06-17 16:02 ` [RFC v1 238/256] cl8k: add vns.h viktor.barna
                   ` (20 subsequent siblings)
  257 siblings, 0 replies; 262+ messages in thread
From: viktor.barna @ 2021-06-17 16:02 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Oleksandr Savchenko, Shay Bar, Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

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

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 drivers/net/wireless/celeno/cl8k/vns.c | 505 +++++++++++++++++++++++++
 1 file changed, 505 insertions(+)
 create mode 100644 drivers/net/wireless/celeno/cl8k/vns.c

diff --git a/drivers/net/wireless/celeno/cl8k/vns.c b/drivers/net/wireless/celeno/cl8k/vns.c
new file mode 100644
index 000000000000..75c3c0374793
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/vns.c
@@ -0,0 +1,505 @@
+// SPDX-License-Identifier: MIT
+/* Copyright(c) 2019-2021, Celeno Communications Ltd. */
+
+#include "vns.h"
+#include "rssi.h"
+#include "fw/msg_tx.h"
+#include "maintenance.h"
+#include "mac_addr.h"
+
+#define CL_VNS_HASH_IDX    (ETH_ALEN - 2)
+#define CL_VNS_MGMT_AGEOUT 200
+
+#define CL_VNS_DBG(...) \
+       do { \
+               if (unlikely(cl_hw->vns_db.dbg)) \
+                       pr_debug(__VA_ARGS__); \
+       } while (0)
+
+#define CL_VNS_DBG_PER_PACKET(...) \
+       do { \
+               if (unlikely(cl_hw->vns_db.dbg_per_packet)) \
+                       pr_debug(__VA_ARGS__); \
+       } while (0)
+
+static void cl_vns_mgmt_list_add(struct cl_hw *cl_hw, u8 *addr, s8 strongset_rssi)
+{
+       /* Add entry to mgmt list */
+       struct cl_vns_rssi_entry *entry = kzalloc(sizeof(*entry), GFP_ATOMIC);
+
+       if (!entry)
+               return;
+
+       /* Fill entry parameters */
+       INIT_LIST_HEAD(&entry->list_all);
+       INIT_LIST_HEAD(&entry->list_addr);
+       cl_mac_addr_copy(entry->addr, addr);
+       entry->strongset_rssi = strongset_rssi;
+       entry->timestamp = jiffies;
+
+       /* Add to list */
+       cl_hw->vns_db.mgmt_db.num_entries++;
+       list_add(&entry->list_all, &cl_hw->vns_db.mgmt_db.list_all);
+       list_add(&entry->list_addr, &cl_hw->vns_db.mgmt_db.list_addr[addr[CL_VNS_HASH_IDX]]);
+}
+
+static void cl_vns_mgmt_list_remove(struct cl_hw *cl_hw, struct cl_vns_rssi_entry *entry)
+{
+       /* Remove entry from mgmt list */
+       cl_hw->vns_db.mgmt_db.num_entries--;
+       list_del(&entry->list_all);
+       list_del(&entry->list_addr);
+       kfree(entry);
+}
+
+static void cl_vns_mgmt_list_flush(struct cl_hw *cl_hw)
+{
+       /* Flush all mgmt list */
+       if (cl_hw->vns_db.mgmt_db.num_entries > 0) {
+               struct cl_vns_rssi_entry *entry = NULL, *tmp = NULL;
+
+               list_for_each_entry_safe(entry, tmp, &cl_hw->vns_db.mgmt_db.list_all, list_all)
+                       cl_vns_mgmt_list_remove(cl_hw, entry);
+       }
+}
+
+static struct cl_vns_rssi_entry *cl_vns_mgmt_list_find(struct cl_hw *cl_hw, u8 *addr)
+{
+       /* Search for entry in mgmt list */
+       struct cl_vns_mgmt_db *mgmt_db = &cl_hw->vns_db.mgmt_db;
+
+       if (mgmt_db->num_entries > 0) {
+               struct cl_vns_rssi_entry *entry = NULL;
+
+               list_for_each_entry(entry, &mgmt_db->list_addr[addr[CL_VNS_HASH_IDX]], list_addr)
+                       if (ether_addr_equal(entry->addr, addr))
+                               return entry;
+       }
+
+       return NULL;
+}
+
+static bool cl_vns_mgmt_list_find_and_remove(struct cl_hw *cl_hw, u8 *addr)
+{
+       /*
+        * Search for entry in mgmt list
+        * If entry found remove it and return true
+        */
+       struct cl_vns_rssi_entry *entry = cl_vns_mgmt_list_find(cl_hw, addr);
+
+       if (entry) {
+               cl_vns_mgmt_list_remove(cl_hw, entry);
+               return true;
+       }
+
+       return false;
+}
+
+static void cl_vns_mgmt_list_ageout(struct cl_hw *cl_hw)
+{
+       /* Remove old entries from mgmt list */
+       struct cl_vns_mgmt_db *mgmt_db = &cl_hw->vns_db.mgmt_db;
+
+       if (mgmt_db->num_entries > 0) {
+               struct cl_vns_rssi_entry *entry = NULL, *tmp = NULL;
+               unsigned long delta_time;
+
+               list_for_each_entry_safe(entry, tmp, &mgmt_db->list_all, list_all) {
+                       delta_time = jiffies_to_msecs(jiffies - entry->timestamp);
+
+                       if (delta_time > CL_VNS_MGMT_AGEOUT) {
+                               CL_VNS_DBG("[VNS] sta %pM removed from list because of ageout\n",
+                                          entry->addr);
+                               cl_vns_mgmt_list_remove(cl_hw, entry);
+                       }
+               }
+       }
+}
+
+static s8 cl_vns_get_strongest_rssi(struct cl_hw *cl_hw, struct cl_sta *cl_sta)
+{
+       struct cl_vns_sta_db *vns_db = &cl_sta->vns_db;
+       s32 rssi_samples = vns_db->rssi_samples;
+
+       if (rssi_samples > 0) {
+               u8 i;
+               s32 strongest_rssi = S32_MIN;
+
+               for (i = 0; i < cl_hw->num_antennas; i++)
+                       if (vns_db->rssi_sum[i] > strongest_rssi)
+                               strongest_rssi = vns_db->rssi_sum[i];
+
+               /* Reset rssi for next time that cl_vns_get_strongest_rssi() will be called */
+               memset(vns_db->rssi_sum, 0, sizeof(vns_db->rssi_sum));
+               vns_db->rssi_samples = 0;
+
+               return (s8)(strongest_rssi / rssi_samples);
+       }
+
+       return 0;
+}
+
+static void cl_vns_monitor_rssi(struct cl_hw *cl_hw, struct cl_sta *cl_sta)
+{
+       /* Monitor RSSI of associated stations and update state if necessary */
+       struct cl_vns_sta_db *vns_db = &cl_sta->vns_db;
+       s8 strongset_rssi = cl_vns_get_strongest_rssi(cl_hw, cl_sta);
+       s8 rssi_thr = 0;
+       bool is_vns = false;
+
+       if (strongset_rssi == 0)
+               return;
+
+       /*
+        * Calculate RSSI threshold (take hystersis into
+        *  consideration according to current state)
+        */
+       if (vns_db->is_very_near)
+               rssi_thr = cl_hw->conf->ci_vns_rssi_thr - cl_hw->conf->ci_vns_rssi_hys;
+       else
+               rssi_thr = cl_hw->conf->ci_vns_rssi_thr + cl_hw->conf->ci_vns_rssi_hys;
+
+       is_vns = (strongset_rssi > rssi_thr) ? true : false;
+
+       /* Avoid toggling of VNS state - require two consecutive same decisions */
+       if (is_vns != vns_db->prev_decision) {
+               vns_db->prev_decision = is_vns;
+               return;
+       }
+
+       if (is_vns != vns_db->is_very_near) {
+               CL_VNS_DBG("[VNS] sta %pM changed state, strongset_rssi = %d, is_vns = %s\n",
+                          cl_sta->addr, strongset_rssi, is_vns ? "TRUE" : "FALSE");
+               vns_db->is_very_near = is_vns;
+               cl_msg_tx_set_vns(cl_hw, cl_sta->sta_idx, is_vns);
+       }
+}
+
+static void cl_vns_recovery_sta(struct cl_hw *cl_hw, struct cl_sta *cl_sta)
+{
+       if (cl_sta->vns_db.is_very_near)
+               cl_msg_tx_set_vns(cl_hw, cl_sta->sta_idx, true);
+}
+
+static int cl_vns_print_sta_state(struct cl_hw *cl_hw)
+{
+       struct cl_sta *cl_sta = NULL;
+       char *buf = NULL;
+       ssize_t buf_size;
+       int err = 0;
+       int len = 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)
+               cl_snprintf(&buf, &len, &buf_size,
+                           "sta_idx = %u, mac = %pM, is_very_near = %s\n",
+                           cl_sta->sta_idx, cl_sta->addr,
+                           cl_sta->vns_db.is_very_near ?
+                           "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_vns_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,
+                "vns usage\n"
+                "-a: Set rssi auto response threshold [thr]\n"
+                "-d: Set debug [0/1]\n"
+                "-h: Set rssi hystersis [hyst]\n"
+                "-l: Set power limit [limit]\n"
+                "-m: Set power mode [mode]\n"
+                "-p: Set debug per packet [0/1]\n"
+                "-s: Print all stations state\n"
+                "-t: Set rssi threshold [thr]\n");
+
+       err = cl_vendor_reply(cl_hw, buf, strlen(buf));
+       kfree(buf);
+
+       return err;
+}
+
+void cl_vns_init(struct cl_hw *cl_hw)
+{
+       int i = 0;
+       u8 vns_pwr_mode = cl_hw->conf->ci_vns_pwr_mode;
+
+       if (vns_pwr_mode == VNS_MODE_DATA || vns_pwr_mode == VNS_MODE_ALL)
+               cl_hw->vns_db.enable = true;
+
+       spin_lock_init(&cl_hw->vns_db.lock);
+
+       INIT_LIST_HEAD(&cl_hw->vns_db.mgmt_db.list_all);
+
+       for (i = 0; i < STA_HASH_SIZE; i++)
+               INIT_LIST_HEAD(&cl_hw->vns_db.mgmt_db.list_addr[i]);
+}
+
+void cl_vns_close(struct cl_hw *cl_hw)
+{
+       if (cl_hw->vns_db.enable) {
+               spin_lock_bh(&cl_hw->vns_db.lock);
+               cl_vns_mgmt_list_flush(cl_hw);
+               spin_unlock_bh(&cl_hw->vns_db.lock);
+
+               cl_hw->vns_db.enable = false;
+       }
+}
+
+void cl_vns_maintenance(struct cl_hw *cl_hw)
+{
+       /*
+        * Maintenance:
+        * 1) Remove old entries from mgmt list
+        * 2) Update state for associated clients
+        */
+       if (!cl_hw->vns_db.enable)
+               return;
+
+       cl_hw->vns_db.interval_period += CL_MAINTENANCE_PERIOD_SLOW_MS;
+
+       if (cl_hw->vns_db.interval_period < cl_hw->conf->ci_vns_maintenance_time)
+               return;
+
+       cl_hw->vns_db.interval_period = 0;
+
+       spin_lock_bh(&cl_hw->vns_db.lock);
+       cl_vns_mgmt_list_ageout(cl_hw);
+       spin_unlock_bh(&cl_hw->vns_db.lock);
+
+       /* Check RSSI of associated stations */
+       cl_sta_loop(cl_hw, cl_vns_monitor_rssi);
+}
+
+void cl_vns_mgmt_handler(struct cl_hw *cl_hw, u8 *addr, s8 rssi[MAX_ANTENNAS])
+{
+       /*
+        * Handle management frames of non-associated stations,
+        * and save the very-near ones in the mgmt list
+        */
+       s8 strongset_rssi = 0;
+       struct cl_vns_rssi_entry *entry = NULL;
+
+       if (!cl_hw->vns_db.enable)
+               return;
+
+       strongset_rssi = cl_rssi_get_strongest(cl_hw, rssi);
+
+       spin_lock_bh(&cl_hw->vns_db.lock);
+
+       entry = cl_vns_mgmt_list_find(cl_hw, addr);
+
+       if (entry) {
+               if (strongset_rssi > cl_hw->conf->ci_vns_rssi_thr) {
+                       /* Update existing entry */
+                       entry->strongset_rssi = strongset_rssi;
+                       entry->timestamp = jiffies;
+                       CL_VNS_DBG("[VNS] sta %pM updated in list (rssi=%d)\n",
+                                  addr, strongset_rssi);
+               } else {
+                       /* Remove existing entry */
+                       cl_vns_mgmt_list_remove(cl_hw, entry);
+                       CL_VNS_DBG("[VNS] sta %pM removed from list (rssi=%d)\n",
+                                  addr, strongset_rssi);
+               }
+       } else {
+               if (strongset_rssi > cl_hw->conf->ci_vns_rssi_thr) {
+                       /* Add new entry */
+                       cl_vns_mgmt_list_add(cl_hw, addr, strongset_rssi);
+                       CL_VNS_DBG("[VNS] sta %pM added to list (rssi=%d)\n",
+                                  addr, strongset_rssi);
+               }
+       }
+
+       spin_unlock_bh(&cl_hw->vns_db.lock);
+}
+
+bool cl_vns_is_very_near(struct cl_hw *cl_hw, struct cl_sta *cl_sta, struct sk_buff *skb)
+{
+       bool is_vns = false;
+       /* This function checks for every TX packet whether it's VNS or not */
+       if (!cl_hw->vns_db.enable)
+               return false;
+
+       if (unlikely(!cl_sta)) {
+               struct ieee80211_hdr *mac_hdr = (struct ieee80211_hdr *)skb->data;
+
+               spin_lock_bh(&cl_hw->vns_db.lock);
+               is_vns = cl_vns_mgmt_list_find(cl_hw, mac_hdr->addr1) ? true : false;
+               spin_unlock_bh(&cl_hw->vns_db.lock);
+
+               CL_VNS_DBG_PER_PACKET("[VNS] mgmt-sta %pM, is_vns = %s\n",
+                                     mac_hdr->addr1, is_vns ? "TRUE" : "FALSE");
+
+               return is_vns;
+       }
+       is_vns = cl_sta->vns_db.is_very_near;
+
+       CL_VNS_DBG_PER_PACKET("[VNS] assoc-sta %pM, is_vns = %s\n",
+                             cl_sta->addr, is_vns ? "TRUE" : "FALSE");
+
+       return is_vns;
+}
+
+void cl_vns_sta_add(struct cl_hw *cl_hw, struct cl_sta *cl_sta)
+{
+       /* Update is_very_near according to mgmt list */
+       bool is_vns = false;
+
+       if (!cl_hw->vns_db.enable)
+               return;
+
+       spin_lock_bh(&cl_hw->vns_db.lock);
+       is_vns = cl_vns_mgmt_list_find_and_remove(cl_hw, cl_sta->addr);
+       spin_unlock_bh(&cl_hw->vns_db.lock);
+
+       if (is_vns) {
+               CL_VNS_DBG("[VNS] sta %pM connected - is_vns = TRUE\n", cl_sta->addr);
+               cl_sta->vns_db.is_very_near = true;
+               cl_sta->vns_db.prev_decision = true;
+               cl_msg_tx_set_vns(cl_hw, cl_sta->sta_idx, true);
+       } else {
+               CL_VNS_DBG("[VNS] sta %pM connected - is_vns = FALSE\n", cl_sta->addr);
+       }
+}
+
+void cl_vns_handle_rssi(struct cl_hw *cl_hw, struct cl_sta *cl_sta, s8 rssi[MAX_ANTENNAS])
+{
+       /* Collect rssi samples */
+       int i;
+
+       if (!cl_hw->vns_db.enable)
+               return;
+
+       for (i = 0; i < cl_hw->num_antennas; i++)
+               cl_sta->vns_db.rssi_sum[i] += rssi[i];
+
+       cl_sta->vns_db.rssi_samples++;
+}
+
+void cl_vns_recovery(struct cl_hw *cl_hw)
+{
+       CL_VNS_DBG("[VNS] Recovery\n");
+       cl_sta_loop_bh(cl_hw, cl_vns_recovery_sta);
+}
+
+int cl_vns_cli(struct cl_hw *cl_hw, struct cli_params *cli_params)
+{
+       u32 expected_params = 0;
+       bool set_rssi_auto_rsp_thr = false;
+       bool set_dbg = false;
+       bool set_rssi_hyst = false;
+       bool set_pwr_limit = false;
+       bool set_pwr_mode = false;
+       bool set_dbg_per_packet = false;
+       bool print_sta_state = false;
+       bool set_rssi_thr = false;
+
+       switch (cli_params->option) {
+       case 'a':
+               set_rssi_auto_rsp_thr = true;
+               expected_params = 1;
+               break;
+       case 'd':
+               set_dbg = true;
+               expected_params = 1;
+               break;
+       case 'h':
+               set_rssi_hyst = true;
+               expected_params = 1;
+               break;
+       case 'l':
+               set_pwr_limit = true;
+               expected_params = 1;
+               break;
+       case 'm':
+               set_pwr_mode = true;
+               expected_params = 1;
+               break;
+       case 'p':
+               set_dbg_per_packet = true;
+               expected_params = 1;
+               break;
+       case 's':
+               print_sta_state = true;
+               expected_params = 0;
+               break;
+       case 't':
+               set_rssi_thr = true;
+               expected_params = 1;
+               break;
+       case '?':
+               return cl_vns_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 (set_rssi_auto_rsp_thr) {
+               cl_hw->conf->ci_vns_rssi_auto_resp_thr = (s8)cli_params->params[0];
+               pr_debug("[VNS] rssi auto response threshold = %d\n",
+                        cl_hw->conf->ci_vns_rssi_auto_resp_thr);
+               return 0;
+       }
+
+       if (set_dbg) {
+               cl_hw->vns_db.dbg = (bool)cli_params->params[0];
+               pr_debug("[VNS] debug = %s\n", cl_hw->vns_db.dbg ? "enable" : "disable");
+               return 0;
+       }
+
+       if (set_pwr_limit) {
+               cl_hw->conf->ci_vns_pwr_limit = (s8)cli_params->params[0];
+               pr_debug("[VNS] power limit = %d\n", cl_hw->conf->ci_vns_pwr_limit);
+               return 0;
+       }
+
+       if (set_rssi_hyst) {
+               cl_hw->conf->ci_vns_rssi_hys = (s8)cli_params->params[0];
+               pr_debug("[VNS] rssi hystersis = %d\n", cl_hw->conf->ci_vns_rssi_hys);
+               return 0;
+       }
+
+       if (set_pwr_mode) {
+               cl_hw->conf->ci_vns_pwr_mode = (u8)cli_params->params[0];
+               pr_debug("[VNS] power mode = %u\n", cl_hw->conf->ci_vns_pwr_mode);
+               return 0;
+       }
+
+       if (set_dbg_per_packet) {
+               cl_hw->vns_db.dbg_per_packet = (bool)cli_params->params[0];
+               pr_debug("[VNS] debug per packet = %s\n",
+                        cl_hw->vns_db.dbg_per_packet ? "enable" : "disable");
+               return 0;
+       }
+
+       if (set_rssi_thr) {
+               cl_hw->conf->ci_vns_rssi_thr = (s8)cli_params->params[0];
+               pr_debug("[VNS] rssi threshold = %d\n", cl_hw->conf->ci_vns_rssi_thr);
+               return 0;
+       }
+
+       if (print_sta_state)
+               return cl_vns_print_sta_state(cl_hw);
+
+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.
________________________________


^ permalink raw reply related	[flat|nested] 262+ messages in thread

* [RFC v1 238/256] cl8k: add vns.h
  2021-06-17 15:58 [RFC v1 000/256] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (236 preceding siblings ...)
  2021-06-17 16:02 ` [RFC v1 237/256] cl8k: add vns.c viktor.barna
@ 2021-06-17 16:02 ` viktor.barna
  2021-06-17 16:02 ` [RFC v1 239/256] cl8k: add wrs/wrs.c viktor.barna
                   ` (19 subsequent siblings)
  257 siblings, 0 replies; 262+ messages in thread
From: viktor.barna @ 2021-06-17 16:02 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Oleksandr Savchenko, Shay Bar, Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

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

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 drivers/net/wireless/celeno/cl8k/vns.h | 36 ++++++++++++++++++++++++++
 1 file changed, 36 insertions(+)
 create mode 100644 drivers/net/wireless/celeno/cl8k/vns.h

diff --git a/drivers/net/wireless/celeno/cl8k/vns.h b/drivers/net/wireless/celeno/cl8k/vns.h
new file mode 100644
index 000000000000..fc60ce275d52
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/vns.h
@@ -0,0 +1,36 @@
+/* SPDX-License-Identifier: MIT */
+/* Copyright(c) 2019-2021, Celeno Communications Ltd. */
+
+#ifndef CL_VNS_H
+#define CL_VNS_H
+
+#include "hw.h"
+
+/**
+ * DOC: VNS (=Very Near STA)
+ *
+ * Feature is responsible for TX power adjustment regarding to the STA
+ * location. Near stations should get signal with lower power to avoid
+ * saturation. Power is contolled for both transmitted data (%VNS_MODE_DATA)
+ * and autoresponse frames (%VNS_AUTO_REPLY), including both cases for
+ * connected and not connected stations.
+ *
+ * In order to determine, whether a station is in VNS range, we rely on the
+ * RSSI values, received from the firmware for every RX frame.
+ */
+
+#define VNS_MODE_DATA       0x1
+#define VNS_MODE_AUTO_REPLY 0x2
+#define VNS_MODE_ALL        (VNS_MODE_DATA | VNS_MODE_AUTO_REPLY)
+
+void cl_vns_init(struct cl_hw *cl_hw);
+void cl_vns_close(struct cl_hw *cl_hw);
+void cl_vns_maintenance(struct cl_hw *cl_hw);
+void cl_vns_mgmt_handler(struct cl_hw *cl_hw, u8 *addr, s8 rssi[MAX_ANTENNAS]);
+bool cl_vns_is_very_near(struct cl_hw *cl_hw, struct cl_sta *cl_sta, struct sk_buff *skb);
+void cl_vns_sta_add(struct cl_hw *cl_hw, struct cl_sta *cl_sta);
+void cl_vns_handle_rssi(struct cl_hw *cl_hw, struct cl_sta *cl_sta, s8 rssi[MAX_ANTENNAS]);
+void cl_vns_recovery(struct cl_hw *cl_hw);
+int cl_vns_cli(struct cl_hw *cl_hw, struct cli_params *cli_params);
+
+#endif /* CL_VNS_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.
________________________________


^ permalink raw reply related	[flat|nested] 262+ messages in thread

* [RFC v1 239/256] cl8k: add wrs/wrs.c
  2021-06-17 15:58 [RFC v1 000/256] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (237 preceding siblings ...)
  2021-06-17 16:02 ` [RFC v1 238/256] cl8k: add vns.h viktor.barna
@ 2021-06-17 16:02 ` viktor.barna
  2021-06-17 16:02 ` [RFC v1 240/256] cl8k: add wrs/wrs.h viktor.barna
                   ` (18 subsequent siblings)
  257 siblings, 0 replies; 262+ messages in thread
From: viktor.barna @ 2021-06-17 16:02 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Oleksandr Savchenko, Shay Bar, Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

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

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 drivers/net/wireless/celeno/cl8k/wrs/wrs.c | 1159 ++++++++++++++++++++
 1 file changed, 1159 insertions(+)
 create mode 100644 drivers/net/wireless/celeno/cl8k/wrs/wrs.c

diff --git a/drivers/net/wireless/celeno/cl8k/wrs/wrs.c b/drivers/net/wireless/celeno/cl8k/wrs/wrs.c
new file mode 100644
index 000000000000..5e2af5d34c8e
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/wrs/wrs.c
@@ -0,0 +1,1159 @@
+// SPDX-License-Identifier: MIT
+/* Copyright(c) 2019-2021, Celeno Communications Ltd. */
+
+#include <linux/kernel.h>
+#include "wrs/wrs.h"
+#include "wrs/wrs_stats.h"
+#include "wrs/wrs_tables.h"
+#include "wrs/wrs_rssi.h"
+#include "env_det.h"
+#include "utils/math.h"
+#include "rssi.h"
+#include "band.h"
+#include "rate_ctrl.h"
+#include "chip.h"
+#include "ext/dyn_bcast_rate.h"
+#include "reg/reg_mac_hw.h"
+#include "data_rates.h"
+#include "rsrc_mgmt.h"
+
+static void cl_wrs_reset_params_cntrs(struct cl_wrs_params *wrs_params)
+{
+       wrs_params->frames_total = 0;
+       wrs_params->fail_total = 0;
+       wrs_params->ba_not_rcv_total = 0;
+       wrs_params->epr_acc = 0;
+       wrs_params->up_same_time_cnt = 0;
+       wrs_params->down_time_cnt = 0;
+}
+
+static bool cl_wrs_down_epr_check(struct cl_wrs_db *wrs_db, struct cl_wrs_sta *wrs_sta,
+                                 struct cl_wrs_params *wrs_params, u8 drop_factor,
+                                 enum cl_wrs_decision decision)
+{
+       u16 curr_rate_idx = wrs_params->rate_idx;
+       struct cl_wrs_table *curr_rate = &wrs_params->table[curr_rate_idx];
+       u64 curr_epr_acc = curr_rate->epr_acc;
+       u32 curr_total = curr_rate->frames_total;
+       u16 down_rate_idx = curr_rate->rate_down.rate_idx;
+       struct cl_wrs_table *down_rate = &wrs_params->table[down_rate_idx];
+       u64 down_epr_acc = down_rate->epr_acc;
+       u32 down_total = down_rate->frames_total;
+       u16 down_data_rate = 0;
+       u64 condition1 = 0, condition2 = 0;
+       bool down_decision = false, allow_penalty = true;
+
+       if (wrs_params->calc_ba_not_rcv) {
+               curr_total += curr_rate->ba_not_rcv_total;
+               down_total += down_rate->ba_not_rcv_total;
+       }
+
+       /*
+        * In the EPR of down candidate is better than or equal to current EPR => return true
+        *
+        * (1) curr_epr <= down_epr * factor(%)
+        *
+        *       curr_epr_acc     down_epr_acc     factor
+        * (2)  -------------- <= -------------- * --------
+        *        curr_total       down_total       100
+        *
+        * (3) curr_epr_acc * down_total * 100 <= down_epr_acc * curr_total * factor
+        *
+        * (4) conditation1 <= conditation2
+        *                                                         down_epr_acc
+        * If (down_total == 0) we use down_data_rate instead of: --------------
+        *                                                          down_total
+        */
+       if (down_total) {
+               condition1 = curr_epr_acc * down_total * 100;
+               condition2 = down_epr_acc * curr_total * drop_factor;
+       } else {
+               down_data_rate = cl_data_rates_get_x10(wrs_params->tx_params.mode,
+                                                      down_rate->rate.bw,
+                                                      down_rate->rate.nss,
+                                                      down_rate->rate.mcs,
+                                                      down_rate->rate.gi);
+
+               condition1 = curr_epr_acc * 100;
+               condition2 = (u64)down_data_rate * curr_total * drop_factor;
+               allow_penalty = false;
+       }
+
+       wrs_params->penalty_decision_dn = wrs_db->step_down;
+
+       if (condition2 && condition1 <= condition2) {
+               down_decision = true;
+
+               if (allow_penalty) {
+                       /*
+                        * The penalty is calculated as follow:
+                        *
+                        * penalty = MAX_STEP * penalty_factor
+                        *                                      epr_curr
+                        * penalty = MAX_STEP * (100% - 100% * ----------)
+                        *                                      epr_down
+                        *
+                        *                                    conditation1
+                        * penalty = MAX_STEP * (100% - 100% --------------)
+                        *                                    conditation2
+                        */
+
+                       u64 penalty_factor = 100 - div64_u64(condition1 * 100, condition2);
+                       u16 max_step = wrs_db->time_th_max_up - wrs_db->step_down;
+
+                       wrs_params->penalty_decision_dn +=
+                               div64_u64(max_step * penalty_factor, 100);
+               }
+
+               if (decision != WRS_DECISION_SAME)
+                       wrs_pr_info(wrs_db,
+                                   "[WRS] EPR check: sta = %u, pkt_curr = %u, pkt_down = %u, "
+                                   "epr_curr = %llu, epr_down * %u%% = %llu, penalty = %u\n",
+                                   wrs_sta->sta_idx,
+                                   curr_total,
+                                   down_total,
+                                   div64_u64(curr_epr_acc, curr_total * 10),
+                                   drop_factor,
+                                   down_total ?
+                                   div64_u64(down_epr_acc * drop_factor, down_total * 1000) :
+                                   (down_data_rate / 10),
+                                   wrs_params->penalty_decision_dn);
+       }
+
+       return down_decision;
+}
+
+static void cl_wrs_time_thr_max_handler(struct cl_wrs_db *wrs_db,
+                                       struct cl_wrs_table *table, u8 up_idx)
+{
+       /*
+        * Check if there are at least two UP rates,
+        * and all UP rates reached max time threshold
+        */
+       u8 i = 0;
+       u8 time_th_max = 0;
+
+       for (i = 0; i < WRS_TABLE_NODE_UP_MAX; i++) {
+               if (table->rate_up[i].rate_idx == WRS_INVALID_RATE)
+                       continue;
+
+               if (table->rate_up[i].time_th != wrs_db->time_th_max_up)
+                       return;
+
+               time_th_max++;
+       }
+
+       if (time_th_max < 2)
+               return;
+
+       /* Find the next max rate, and decrease its time threshold by 1 */
+       i = 0;
+       while (i < WRS_TABLE_NODE_UP_MAX) {
+               up_idx++;
+               if (up_idx == WRS_TABLE_NODE_UP_MAX)
+                       up_idx = WRS_TABLE_NODE_UP_MCS;
+
+               if (table->rate_up[up_idx].rate_idx != WRS_INVALID_RATE) {
+                       /*
+                        * If all up rates reached max time threshold,the first up
+                        * rate will always be selected.
+                        * To overcome it, we decrease the time threshold of the next
+                        * up rate by 1 (so it will be samller and selected next time)
+                        */
+                       table->rate_up[up_idx].time_th--;
+                       break;
+               }
+
+               i++;
+       }
+}
+
+static bool cl_wrs_find_up_candidate(struct cl_wrs_db *wrs_db, struct cl_wrs_params *wrs_params,
+                                    u16 *up_rate_idx, u32 *up_time_th)
+{
+       bool up_rate_valid = false;
+       u8 up_idx = 0;
+       u8 up_candidate = 0;
+       u16 rate_idx = 0;
+       struct cl_wrs_table *table = &wrs_params->table[wrs_params->rate_idx];
+
+       *up_rate_idx = WRS_INVALID_RATE;
+       *up_time_th = U32_MAX;
+
+       for (up_idx = 0; up_idx < WRS_TABLE_NODE_UP_MAX; up_idx++) {
+               rate_idx = table->rate_up[up_idx].rate_idx;
+
+               if (rate_idx == WRS_INVALID_RATE)
+                       continue;
+
+               if (wrs_db->quick_up_en && table->rate_up[up_idx].quick_up_check) {
+                       *up_rate_idx = rate_idx;
+                       *up_time_th = wrs_db->quick_up_interval;
+                       up_rate_valid = true;
+                       up_candidate = up_idx;
+                       break;
+               } else if (table->rate_up[up_idx].time_th < *up_time_th) {
+                       *up_rate_idx = rate_idx;
+                       *up_time_th = table->rate_up[up_idx].time_th;
+                       up_rate_valid = true;
+                       up_candidate = up_idx;
+               }
+       }
+
+       if (wrs_db->time_th_max_up == *up_time_th)
+               cl_wrs_time_thr_max_handler(wrs_db, table, up_candidate);
+
+       return up_rate_valid;
+}
+
+static bool cl_wrs_epr_immeidate_down(struct cl_hw *cl_hw, struct cl_wrs_db *wrs_db,
+                                     struct cl_wrs_sta *wrs_sta, struct cl_wrs_params *wrs_params,
+                                     u16 down_rate_idx)
+{
+       if (cl_wrs_down_epr_check(wrs_db, wrs_sta, wrs_params,
+                                 wrs_db->immediate_drop_epr_factor,
+                                 WRS_DECISION_DOWN_IMMEDIATE)) {
+               /*
+                * If there are several immediate drops in a row ignore them,
+                * because it is probably not realted to bad TX rate
+                */
+               wrs_params->immediate_drop_cntr++;
+
+               if (wrs_params->immediate_drop_cntr > wrs_db->immediate_drop_max_in_row) {
+                       wrs_params->immediate_drop_ignore++;
+
+                       cl_wrs_tables_reset(wrs_db, wrs_sta, wrs_params);
+                       cl_wrs_reset_params_cntrs(wrs_params);
+
+                       wrs_pr_info(wrs_db,
+                                   "[WRS] sta %u - ignore immediate down decision (cntr=%u)\n",
+                                   wrs_sta->sta_idx, wrs_params->immediate_drop_cntr);
+                       return true;
+               }
+
+               cl_wrs_decision_make(cl_hw, wrs_db, wrs_sta, wrs_params,
+                                    WRS_DECISION_DOWN_IMMEDIATE, down_rate_idx);
+               return true;
+       }
+
+       return false;
+}
+
+static void cl_wrs_decision_up(struct cl_hw *cl_hw, struct cl_wrs_db *wrs_db,
+                              struct cl_wrs_sta *wrs_sta, struct cl_wrs_params *wrs_params,
+                              u16 up_rate_idx, u32 up_th)
+{
+       enum cl_wrs_decision up_decision = (up_th == wrs_db->quick_up_interval) ?
+               WRS_DECISION_UP_QUICK : WRS_DECISION_UP;
+
+       cl_wrs_decision_make(cl_hw, wrs_db, wrs_sta, wrs_params, up_decision, up_rate_idx);
+}
+
+static void cl_wrs_decision_same(struct cl_hw *cl_hw, struct cl_wrs_db *wrs_db,
+                                struct cl_wrs_sta *wrs_sta, struct cl_wrs_params *wrs_params,
+                                u16 rate_idx)
+{
+       cl_wrs_decision_make(cl_hw, wrs_db, wrs_sta, wrs_params, WRS_DECISION_SAME, rate_idx);
+}
+
+static void cl_wrs_epr_decision(struct cl_hw *cl_hw, struct cl_wrs_db *wrs_db,
+                               struct cl_wrs_sta *wrs_sta, struct cl_wrs_params *wrs_params)
+{
+       u16 curr_rate_idx = wrs_params->rate_idx;
+       struct cl_wrs_table *table = &wrs_params->table[curr_rate_idx];
+       u16 down_rate_idx = table->rate_down.rate_idx;
+       u16 up_rate_idx = 0;
+       u16 down_th = table->rate_down.time_th;
+       u32 up_th = 0;
+       bool up_rate_valid = false;
+
+       /* Check if we transmitted enough frames for taking decision */
+       if ((wrs_params->frames_total + wrs_params->ba_not_rcv_total) <
+           wrs_db->min_frames_for_decision)
+               return;
+
+       up_rate_valid = cl_wrs_find_up_candidate(wrs_db, wrs_params, &up_rate_idx, &up_th);
+
+       /* RSSI protect */
+       if (wrs_db->rssi_protect_en)
+               if (cl_wrs_rssi_prot_decision(cl_hw, wrs_db, wrs_sta, up_rate_valid,
+                                             up_rate_idx, down_rate_idx))
+                       return;
+
+       if (down_rate_idx != curr_rate_idx) {
+               /* Down immediate */
+               if (wrs_db->immediate_drop_en)
+                       if (cl_wrs_epr_immeidate_down(cl_hw, wrs_db, wrs_sta,
+                                                     wrs_params, down_rate_idx))
+                               return;
+
+               /* Down */
+               if (wrs_params->down_time_cnt >= down_th) {
+                       if (cl_wrs_down_epr_check(wrs_db, wrs_sta, wrs_params,
+                                                 wrs_db->epr_factor, WRS_DECISION_DOWN)) {
+                               cl_wrs_decision_make(cl_hw, wrs_db, wrs_sta, wrs_params,
+                                                    WRS_DECISION_DOWN, down_rate_idx);
+                               return;
+                       }
+
+                       wrs_params->down_time_cnt = 0;
+               }
+       }
+
+       /* Up-same */
+       if (wrs_params->up_same_time_cnt >= up_th) {
+               if (up_rate_valid)
+                       cl_wrs_decision_up(cl_hw, wrs_db, wrs_sta, wrs_params, up_rate_idx, up_th);
+               else
+                       cl_wrs_decision_same(cl_hw, wrs_db, wrs_sta, wrs_params, curr_rate_idx);
+
+               return;
+       }
+
+       /*
+        * If there is no valid UP rate and the EPR is more
+        * than EPR down threshold => make a same decision
+        */
+       if (!up_rate_valid &&
+           !cl_wrs_down_epr_check(wrs_db, wrs_sta, wrs_params,
+                                  wrs_db->epr_factor, WRS_DECISION_SAME))
+               cl_wrs_decision_same(cl_hw, wrs_db, wrs_sta, wrs_params, curr_rate_idx);
+}
+
+static void cl_wrs_divide_weights_by_two(struct cl_wrs_table *table_node)
+{
+       u8 up_idx = 0;
+       struct cl_wrs_table_node *rate_up;
+
+       /*
+        * Converge weights - divide all weights by 2
+        * (make sure they do not go below their init value)
+        */
+       if (table_node->rate_down.rate_idx != WRS_INVALID_RATE)
+               table_node->rate_down.time_th = max(table_node->rate_down.time_th >> 1,
+                                                   WRS_INIT_MSEC_WEIGHT_DOWN);
+
+       for (up_idx = 0; up_idx < WRS_TABLE_NODE_UP_MAX; up_idx++) {
+               rate_up = &table_node->rate_up[up_idx];
+
+               if (rate_up->rate_idx != WRS_INVALID_RATE)
+                       rate_up->time_th = max(rate_up->time_th >> 1, WRS_INIT_MSEC_WEIGHT_UP);
+
+               if (rate_up->time_th == WRS_INIT_MSEC_WEIGHT_UP)
+                       rate_up->quick_up_check = false;
+       }
+}
+
+static void cl_wrs_converge_weights(struct cl_wrs_params *wrs_params)
+{
+       /*
+        * Converge weights - divide the weights by 2 (except for the current rate),
+        * and reset PER counters (except for current rate, down rate, and down-down rate).
+        */
+       u16 i;
+       u16 curr_idx = wrs_params->rate_idx;
+       u16 down_idx = wrs_params->table[curr_idx].rate_down.rate_idx;
+       u16 down2_idx = wrs_params->table[down_idx].rate_down.rate_idx;
+
+       for (i = 0; i < wrs_params->table_size; i++) {
+               if (i == curr_idx)
+                       continue;
+
+               cl_wrs_divide_weights_by_two(&wrs_params->table[i]);
+
+               if (i != down_idx && i != down2_idx) {
+                       wrs_params->table[i].frames_total = 0;
+                       wrs_params->table[i].ba_not_rcv_total = 0;
+                       wrs_params->table[i].epr_acc = 0;
+               }
+       }
+}
+
+static void cl_wrs_converge_weights_idle_decision(struct cl_hw *cl_hw,
+                                                 struct cl_wrs_db *wrs_db,
+                                                 struct cl_wrs_sta *wrs_sta,
+                                                 struct cl_wrs_params *wrs_params)
+{
+       /*
+        * Continue normal converge (just like during traffic).
+        * After 6 seconds reset table, and select rate based on RSSI.
+        */
+       if (!wrs_db->converge_idle_en)
+               return;
+
+       wrs_params->converge_time_idle += wrs_db->interval;
+
+       if (wrs_params->converge_mode == WRS_CONVERGE_MODE_RESET) {
+               if (wrs_params->converge_time_idle < wrs_db->converge_idle_interval_reset) {
+                       cl_wrs_converge_weights(wrs_params);
+               } else {
+                       wrs_params->converge_mode = WRS_CONVERGE_MODE_RSSI;
+                       wrs_params->converge_time_idle = 0;
+
+                       wrs_pr_info(wrs_db, "[WRS] Converge weights: sta %u - RSSI\n",
+                                   wrs_sta->sta_idx);
+
+                       /* Reset table and choose new rate based on RSSI */
+                       cl_wrs_tables_reset(wrs_db, wrs_sta, wrs_params);
+
+                       cl_wrs_rssi_set_rate(cl_hw, wrs_db, wrs_sta);
+               }
+       } else {
+               if (wrs_params->converge_time_idle < wrs_db->converge_idle_interval_rssi)
+                       return;
+
+               /* Choose new rate based on RSSI */
+               wrs_params->converge_time_idle = 0;
+               cl_wrs_rssi_set_rate(cl_hw, wrs_db, wrs_sta);
+       }
+}
+
+static void cl_wrs_converge_weights_idle_reset(struct cl_wrs_db *wrs_db,
+                                              struct cl_wrs_sta *wrs_sta,
+                                              struct cl_wrs_params *wrs_params)
+{
+       /* There was traffic in last maintenance interval - reset converge parameteres */
+       wrs_params->converge_time_idle = 0;
+
+       if (wrs_params->converge_mode != WRS_CONVERGE_MODE_RESET) {
+               wrs_params->converge_mode = WRS_CONVERGE_MODE_RESET;
+               wrs_pr_info(wrs_db, "[WRS] Converge weights: sta %u - RESET\n",
+                           wrs_sta->sta_idx);
+       }
+}
+
+static void cl_wrs_converge_weights_trfc_decision(struct cl_hw *cl_hw, struct cl_sta *cl_sta,
+                                                 struct cl_wrs_db *wrs_db,
+                                                 struct cl_wrs_params *wrs_params)
+{
+       u32 converge_interval = 0;
+
+       if (!wrs_db->converge_trfc_en)
+               return;
+
+       if (cl_motion_sense_is_static(cl_hw, cl_sta) && cl_env_det_is_clean(cl_hw))
+               converge_interval = wrs_db->converge_trfc_interval_static;
+       else
+               converge_interval = wrs_db->converge_trfc_interval_motion;
+
+       wrs_params->converge_time_trfc += wrs_db->interval;
+
+       if (wrs_params->converge_time_trfc >= converge_interval) {
+               wrs_params->converge_time_trfc = 0;
+               cl_wrs_converge_weights(wrs_params);
+       }
+}
+
+static u32 cl_wrs_get_sync_attempts(struct cl_wrs_sta *wrs_sta, struct cl_wrs_params *wrs_params)
+{
+       struct cl_sta *cl_sta = container_of(wrs_sta, struct cl_sta, wrs_sta);
+
+       return cl_sta->wrs_info.sync_attempts;
+}
+
+static void cl_wrs_sta_no_sync_handler(struct cl_hw *cl_hw,
+                                      struct cl_wrs_db *wrs_db,
+                                      struct cl_wrs_sta *wrs_sta,
+                                      struct cl_wrs_params *wrs_params)
+{
+       unsigned long time_delta = jiffies_to_msecs(jiffies - wrs_params->no_sync_timestamp);
+
+       if (time_delta < wrs_db->sync_timeout)
+               return;
+
+       if (cl_wrs_get_sync_attempts(wrs_sta, wrs_params) < wrs_db->sync_min_attempts) {
+               /*
+                * Rate not synced but there is also hardly no traffic -
+                * change mode to synced!
+                */
+               wrs_params->sync = true;
+               wrs_params->sync_timestamp = jiffies;
+       } else {
+               struct cl_wrs_table *wrs_table = &wrs_params->table[wrs_params->rate_idx];
+               struct cl_wrs_rate *curr_rate = &wrs_table->rate;
+
+               if (!cl_hw->ate_db.active)
+                       pr_warn("[WRS] NO SYNC - sta = %u, bw = %u, nss = %u, mcs = %u, gi = %u\n",
+                               wrs_sta->sta_idx, curr_rate->bw, curr_rate->nss,
+                               curr_rate->mcs, curr_rate->gi);
+
+               if (WRS_IS_DECISION_UP(wrs_params->last_decision)) {
+                       cl_wrs_decision_make(cl_hw, wrs_db, wrs_sta, wrs_params,
+                                            WRS_DECISION_DOWN_NO_SYNC,
+                                            wrs_table->rate_down.rate_idx);
+               } else {
+                       /* If the last decision was DOWN - change state to SYNCED. */
+                       wrs_params->sync = true;
+                       wrs_params->sync_timestamp = jiffies;
+               }
+       }
+}
+
+static void cl_wrs_update_ba_not_rcv(struct cl_wrs_db *wrs_db, struct cl_wrs_params *wrs_params)
+{
+       unsigned long time_since_sync = jiffies_to_msecs(jiffies - wrs_params->sync_timestamp);
+
+       wrs_params->calc_ba_not_rcv = (wrs_db->ba_not_rcv_force ||
+                                      (time_since_sync < wrs_db->ba_not_rcv_time_since_sync));
+}
+
+static void _cl_wrs_tx_cntrs_reset(struct cl_wrs_info *wrs_info)
+{
+       wrs_info->epr_acc = 0;
+       wrs_info->tx_success = 0;
+       wrs_info->tx_fail = 0;
+       wrs_info->ba_not_rcv = 0;
+       wrs_info->ba_not_rcv_consecutive_max = 0;
+}
+
+static void cl_wrs_tx_cntrs_read(struct cl_wrs_sta *wrs_sta,
+                                struct cl_wrs_tx_cntrs *tx_cntrs)
+{
+       struct cl_sta *cl_sta = container_of(wrs_sta, struct cl_sta, wrs_sta);
+       struct cl_wrs_info *wrs_info = &cl_sta->wrs_info;
+
+       tx_cntrs->epr_acc = wrs_info->epr_acc;
+       tx_cntrs->total = wrs_info->tx_success + wrs_info->tx_fail;
+       tx_cntrs->fail = wrs_info->tx_fail;
+       tx_cntrs->ba_not_rcv = wrs_info->ba_not_rcv;
+       tx_cntrs->ba_not_rcv_consecutive = wrs_info->ba_not_rcv_consecutive_max;
+
+       _cl_wrs_tx_cntrs_reset(wrs_info);
+}
+
+static void _cl_wrs_sta_maintenance(struct cl_hw *cl_hw, struct cl_sta *cl_sta,
+                                   struct cl_wrs_params *wrs_params)
+{
+       struct cl_wrs_db *wrs_db = &cl_hw->wrs_db;
+       struct cl_wrs_sta *wrs_sta = &cl_sta->wrs_sta;
+       struct cl_wrs_tx_cntrs tx_cntrs = {0};
+
+       if (!wrs_params->sync) {
+               cl_wrs_sta_no_sync_handler(cl_hw, wrs_db, wrs_sta, wrs_params);
+               return;
+       }
+
+       cl_wrs_update_ba_not_rcv(wrs_db, wrs_params);
+       cl_wrs_tx_cntrs_read(wrs_sta, &tx_cntrs);
+
+       if (wrs_params->is_fixed_rate) {
+               cl_wrs_stats_per_update(wrs_db, wrs_sta, wrs_params, &tx_cntrs);
+               return;
+       }
+
+       wrs_params->down_time_cnt += wrs_db->interval;
+       wrs_params->up_same_time_cnt += wrs_db->interval;
+
+       if ((tx_cntrs.total + tx_cntrs.ba_not_rcv) < wrs_db->converge_idle_packet_th) {
+               /*
+                * Very few frames were sent in last maintenance interval
+                * Check if weights should be converged
+                */
+               cl_wrs_converge_weights_idle_decision(cl_hw, wrs_db, wrs_sta, wrs_params);
+
+               cl_wrs_stats_per_update(wrs_db, wrs_sta, wrs_params, &tx_cntrs);
+
+               return;
+       }
+
+       /* There was traffic in last maintenance interval - reset converge parameteres */
+       cl_wrs_converge_weights_idle_reset(wrs_db, wrs_sta, wrs_params);
+
+       cl_wrs_stats_per_update(wrs_db, wrs_sta, wrs_params, &tx_cntrs);
+
+       wrs_params->quick_up_check =
+               (tx_cntrs.ba_not_rcv_consecutive >= wrs_db->quick_up_ba_thr) ? 1 : 0;
+       cl_wrs_epr_decision(cl_hw, wrs_db, wrs_sta, wrs_params);
+
+       cl_wrs_converge_weights_trfc_decision(cl_hw, cl_sta, wrs_db, wrs_params);
+}
+
+static void cl_wrs_sta_maintenance(struct cl_hw *cl_hw, struct cl_sta *cl_sta)
+{
+       _cl_wrs_sta_maintenance(cl_hw, cl_sta, &cl_sta->wrs_sta.su_params);
+}
+
+static void cl_wrs_cca_calc(struct cl_hw *cl_hw, struct cl_wrs_db *wrs_db, u8 max_bw)
+{
+       u32 cca_primary_new = mac_hw_edca_cca_busy_get(cl_hw);
+       u32 cca_sec80_new = (max_bw > CHNL_BW_80) ? mac_hw_add_cca_busy_sec_80_get(cl_hw) : 0;
+       u32 cca_sec40_new = (max_bw > CHNL_BW_40) ? mac_hw_add_cca_busy_sec_40_get(cl_hw) : 0;
+       u32 cca_sec20_new = mac_hw_add_cca_busy_sec_20_get(cl_hw);
+
+       u32 cca_primary_diff = cca_primary_new - wrs_db->cca_primary;
+       u32 cca_sec80_diff = cca_sec80_new - wrs_db->cca_sec80;
+       u32 cca_sec40_diff = cca_sec40_new - wrs_db->cca_sec40;
+       u32 cca_sec20_diff = cca_sec20_new - wrs_db->cca_sec20;
+
+       wrs_db->cca_primary = cca_primary_new;
+       wrs_db->cca_sec80 = cca_sec80_new;
+       wrs_db->cca_sec40 = cca_sec40_new;
+       wrs_db->cca_sec20 = cca_sec20_new;
+       wrs_db->cca_timestamp = jiffies;
+
+       /* Increase by 25% */
+       cca_primary_diff = cca_primary_diff * WRS_CCA_PRIMARY_FACTOR >> WRS_CCA_PRIMARY_SHIFT;
+
+       /* Adjacent interference - if secondary is higher than primary by 25%. */
+       wrs_db->adjacent_interference80 = (cca_sec80_diff > cca_primary_diff);
+       wrs_db->adjacent_interference40 = (cca_sec40_diff > cca_primary_diff);
+       wrs_db->adjacent_interference20 = (cca_sec20_diff > cca_primary_diff);
+}
+
+static void cl_wrs_cca_maintenance(struct cl_hw *cl_hw, struct cl_wrs_db *wrs_db)
+{
+       u8 max_bw = wrs_db->max_cap.bw;
+
+       if (max_bw == CHNL_BW_20)
+               return;
+
+       if (jiffies_to_msecs(jiffies - wrs_db->cca_timestamp) > WRS_CCA_PERIOD_MS)
+               cl_wrs_cca_calc(cl_hw, wrs_db, max_bw);
+}
+
+static void cl_wrs_maintenance(unsigned long data)
+{
+       struct cl_hw *cl_hw = (struct cl_hw *)data;
+       struct cl_wrs_db *wrs_db = &cl_hw->wrs_db;
+
+       cl_wrs_cca_maintenance(cl_hw, wrs_db);
+
+       cl_wrs_lock(wrs_db);
+       cl_sta_loop(cl_hw, cl_wrs_sta_maintenance);
+       cl_wrs_unlock(wrs_db);
+}
+
+static void cl_wrs_down_decision_weights_update(struct cl_wrs_db *wrs_db,
+                                               struct cl_wrs_sta *wrs_sta,
+                                               u16 new_rate_idx,
+                                               struct cl_wrs_params *wrs_params)
+{
+       u16 old_rate_idx = wrs_params->rate_idx;
+       u8 up_idx = 0;
+       u16 down_th_min = wrs_db->time_th_min;
+       u16 step = wrs_db->step_down;
+       u16 *th_down = &wrs_params->table[old_rate_idx].rate_down.time_th;
+       u16 *th_up = NULL;
+       struct cl_wrs_table *table_node = &wrs_params->table[new_rate_idx];
+
+       /* Decrease the weight from old rate to new rate */
+       if (*th_down > (down_th_min + step))
+               *th_down -= step;
+       else
+               *th_down = down_th_min;
+
+       /* Increase the weight from new rate to old rate */
+       for (up_idx = 0; up_idx < WRS_TABLE_NODE_UP_MAX; up_idx++) {
+               if (old_rate_idx == table_node->rate_up[up_idx].rate_idx) {
+                       th_up = &table_node->rate_up[up_idx].time_th;
+                       table_node->rate_up[up_idx].quick_up_check = !!wrs_params->quick_up_check;
+                       step = wrs_params->penalty_decision_dn;
+                       *th_up = min_t(u16, *th_up + step, wrs_db->time_th_max_up);
+                       break;
+               }
+       }
+
+       wrs_pr_info(wrs_db,
+                   "[WRS] Down update - sta = %u, "
+                   "down weight [%u-->%u] = %u, up weight [%u-->%u] = %u\n",
+                   wrs_sta->sta_idx, old_rate_idx, new_rate_idx,
+                   *th_down, new_rate_idx, old_rate_idx, th_up ? *th_up : 0);
+}
+
+static void cl_wrs_up_same_decision_weights_update(struct cl_wrs_db *wrs_db,
+                                                  struct cl_wrs_sta *wrs_sta,
+                                                  struct cl_wrs_params *wrs_params)
+{
+       u16 curr_rate_idx = wrs_params->rate_idx;
+       u16 down_rate_idx = wrs_params->table[curr_rate_idx].rate_down.rate_idx;
+       u8 up_idx = 0;
+       u16 up_th_min = wrs_db->time_th_min;
+       u16 step = wrs_db->step_up_same;
+       u16 *th_down = &wrs_params->table[curr_rate_idx].rate_down.time_th;
+       u16 *th_up = NULL;
+       u16 th_down_orig = *th_down;
+       u16 th_up_orig = 0;
+       struct cl_wrs_table *table_node = &wrs_params->table[down_rate_idx];
+
+       /* Increase the weight from current rate to down rate */
+       *th_down = min_t(u16, *th_down + step, wrs_db->time_th_max_down);
+
+       /* Decrease the weight from down rate to current rate */
+       for (up_idx = 0; up_idx < WRS_TABLE_NODE_UP_MAX; up_idx++) {
+               if (curr_rate_idx == table_node->rate_up[up_idx].rate_idx) {
+                       th_up = &table_node->rate_up[up_idx].time_th;
+                       table_node->rate_up[up_idx].quick_up_check = false;
+
+                       th_up_orig = *th_up;
+
+                       if (*th_up > (up_th_min + step))
+                               *th_up -= step;
+                       else
+                               *th_up = up_th_min;
+                       break;
+               }
+       }
+
+       if (th_up && (th_up_orig != *th_up || th_down_orig != *th_down))
+               wrs_pr_info(wrs_db,
+                           "[WRS] Up/same update - sta = %u, "
+                           "down weight [%u-->%u] = %u, up weight [%u-->%u] = %u\n",
+                           wrs_sta->sta_idx, curr_rate_idx,
+                           down_rate_idx, *th_down, down_rate_idx, curr_rate_idx, *th_up);
+}
+
+void cl_wrs_init(struct cl_hw *cl_hw)
+{
+       struct cl_wrs_db *wrs_db = &cl_hw->wrs_db;
+
+       /* Default configuration */
+       wrs_db->debug_level = DBG_LVL_ERROR;
+       wrs_db->rssi_protect_en = true;
+       wrs_db->rssi_protect_mode = WRS_RSSI_PROT_MODE_RSSI;
+       wrs_db->rssi_protect_up_thr = WRS_RSSI_PROTECT_UP_THR;
+       wrs_db->rssi_protect_dn_thr = WRS_RSSI_PROTECT_DN_THR;
+       wrs_db->min_frames_for_decision = WRS_MIN_FRAMES_FOR_DECISION;
+       wrs_db->epr_factor = WRS_EPR_FACTOR;
+       wrs_db->converge_idle_en = true;
+       wrs_db->converge_idle_interval_reset = WRS_CONVERGE_IDLE_INTERVAL_RESET;
+       wrs_db->converge_idle_interval_rssi = WRS_CONVERGE_IDLE_INTERVAL_RSSI;
+       wrs_db->converge_idle_packet_th = WRS_CONVERGE_IDLE_PACKET_TH;
+       wrs_db->converge_trfc_en = true;
+       wrs_db->converge_trfc_interval_static = WRS_CONVERGE_TRFC_INTERVAL_STATIC;
+       wrs_db->converge_trfc_interval_motion = WRS_CONVERGE_TRFC_INTERVAL_MOTION;
+       wrs_db->immediate_drop_en = true;
+       wrs_db->immediate_drop_epr_factor = WRS_IMMEDIATE_DROP_EPR_FACTOR;
+       wrs_db->immediate_drop_max_in_row = WRS_IMMEDIATE_DROP_MAX_IN_ROW;
+       wrs_db->time_th_min = WRS_MSEC_WEIGHT_MIN;
+       wrs_db->time_th_max_up = WRS_MSEC_WEIGHT_MAX_UP;
+       wrs_db->time_th_max_down = WRS_MSEC_WEIGHT_MAX_DOWN;
+       wrs_db->step_down = WRS_MSEC_STEP_DOWN;
+       wrs_db->step_up_same = WRS_MSEC_STEP_UP_SAME;
+       wrs_db->interval = msecs_round(WRS_MAINTENANCE_PERIOD_MS);
+       wrs_db->conservative_mcs_noisy_env = false;
+       wrs_db->conservative_nss_noisy_env = false;
+       wrs_db->quick_up_en = true;
+       wrs_db->quick_up_ba_thr = WRS_QUICK_UP_BA_THR;
+       wrs_db->quick_up_interval = msecs_round(WRS_QUICK_UP_INTERVAL_MS);
+       wrs_db->quick_down_en = true;
+       wrs_db->quick_down_epr_factor = WRS_QUICK_DOWN_EPR_FACTOR;
+       wrs_db->quick_down_agg_thr = WRS_QUICK_DOWN_AGG_THR;
+       wrs_db->quick_down_pkt_thr = WRS_QUICK_DOWN_PKT_THR;
+       wrs_db->ba_not_rcv_collision_filter = true;
+       /* Environment of 2.4 is much more noisy, so 'BA not received' are ignored. */
+       wrs_db->ba_not_rcv_force = cl_band_is_24g(cl_hw) ? false : true;
+       wrs_db->ba_not_rcv_time_since_sync = WRS_BA_NOT_RCV_TIME_SINCE_SYNC;
+       wrs_db->sync_timeout = WRS_SYNC_TIMEOUT;
+       wrs_db->sync_min_attempts = WRS_SYNC_MIN_ATTEMPTS;
+
+       /* Init WRS periodic timer */
+       cl_timer_init(&wrs_db->timer_maintenance,
+                     cl_wrs_maintenance,
+                     (unsigned long)cl_hw,
+                     wrs_db->interval, true);
+
+       if (!cl_hw->chip->conf->ce_production_mode) {
+               wrs_db->cca_timestamp = jiffies;
+               cl_timer_enable(&wrs_db->timer_maintenance);
+       }
+
+       spin_lock_init(&wrs_db->lock);
+
+       if ((cl_hw->conf->ci_wrs_fixed_rate[WRS_FIXED_PARAM_MODE] != -1) &&
+           (cl_hw->conf->ci_wrs_fixed_rate[WRS_FIXED_PARAM_BW] != -1) &&
+           (cl_hw->conf->ci_wrs_fixed_rate[WRS_FIXED_PARAM_NSS] != -1) &&
+           (cl_hw->conf->ci_wrs_fixed_rate[WRS_FIXED_PARAM_MCS] != -1) &&
+           (cl_hw->conf->ci_wrs_fixed_rate[WRS_FIXED_PARAM_GI] != -1))
+               wrs_db->is_fixed_rate = WRS_FIXED_FALLBACK_DIS;
+}
+
+inline void cl_wrs_lock_bh(struct cl_wrs_db *wrs_db)
+{
+       spin_lock_bh(&wrs_db->lock);
+}
+
+inline void cl_wrs_unlock_bh(struct cl_wrs_db *wrs_db)
+{
+       spin_unlock_bh(&wrs_db->lock);
+}
+
+inline void cl_wrs_lock(struct cl_wrs_db *wrs_db)
+{
+       spin_lock(&wrs_db->lock);
+}
+
+inline void cl_wrs_unlock(struct cl_wrs_db *wrs_db)
+{
+       spin_unlock(&wrs_db->lock);
+}
+
+void cl_wrs_tx_param_sync(struct cl_wrs_db *wrs_db, struct cl_wrs_sta *wrs_sta,
+                         struct cl_wrs_params *wrs_params)
+{
+       if (wrs_params->sync)
+               return;
+
+       /* Reset the tx Counters */
+       cl_wrs_tx_cntrs_reset(wrs_sta, wrs_params);
+
+       /* Reset counters */
+       cl_wrs_reset_params_cntrs(wrs_params);
+
+       /* Change state to SYNCED */
+       wrs_params->sync = true;
+       wrs_params->sync_timestamp = jiffies;
+
+       wrs_pr_trace(wrs_db, "[WRS] Sync - timestamp = %u, sta = %u, rate_idx = %u\n",
+                    jiffies_to_msecs(jiffies),
+                    wrs_sta->sta_idx,
+                    wrs_params->rate_idx);
+}
+
+void cl_wrs_tx_params_update(struct cl_hw *cl_hw, struct cl_wrs_db *wrs_db,
+                            struct cl_wrs_sta *wrs_sta, struct cl_wrs_params *wrs_params,
+                            u16 new_rate_idx, bool is_sync_required)
+{
+       struct cl_sta *cl_sta = container_of(wrs_sta, struct cl_sta, wrs_sta);
+       struct cl_wrs_tx_params *tx_params = &wrs_params->tx_params;
+       struct cl_wrs_rate *rate = &wrs_params->table[new_rate_idx].rate;
+       u16 fallback_rate_idx = wrs_params->table[new_rate_idx].rate_down.rate_idx;
+       struct cl_wrs_rate *rate_fallback = &wrs_params->table[fallback_rate_idx].rate;
+
+       cl_dyn_bcast_rate_change(cl_hw, cl_sta, tx_params->mcs, rate->mcs);
+
+       tx_params->bw = rate->bw;
+       tx_params->nss = rate->nss;
+       tx_params->mcs = rate->mcs;
+       tx_params->gi = rate->gi;
+       tx_params->mode = wrs_sta->mode;
+       tx_params->fallback_en = (wrs_params->is_fixed_rate != WRS_FIXED_FALLBACK_DIS);
+
+       wrs_pr_trace(wrs_db,
+                    "[WRS] Tx params update - "
+                    "sta = %u, rate_idx = %u, bw = %u, nss = %u, mcs = %u, gi = %u\n",
+                    wrs_sta->sta_idx, new_rate_idx, tx_params->bw,
+                    tx_params->nss, tx_params->mcs, tx_params->gi);
+
+       wrs_params->rate_idx = new_rate_idx;
+
+       /* Converge - restart the time for converging weights of all old rates */
+       wrs_params->converge_time_trfc = 0;
+
+       cl_wrs_tx_param_set(cl_hw, wrs_sta, wrs_params, tx_params, rate_fallback);
+
+       if (is_sync_required) {
+               wrs_params->sync = false;
+               wrs_params->no_sync_timestamp = jiffies;
+       } else {
+               wrs_params->sync = true;
+       }
+
+       /* Reset Counters */
+       cl_wrs_reset_params_cntrs(wrs_params);
+}
+
+void cl_wrs_decision_make(struct cl_hw *cl_hw, struct cl_wrs_db *wrs_db,
+                         struct cl_wrs_sta *wrs_sta, struct cl_wrs_params *wrs_params,
+                         enum cl_wrs_decision decision, u16 new_rate_idx)
+{
+       if (WRS_IS_DECISION_DOWN(decision)) {
+               cl_wrs_down_decision_weights_update(wrs_db, wrs_sta, new_rate_idx, wrs_params);
+       } else if (WRS_IS_DECISION_UP(decision)) {
+               cl_wrs_up_same_decision_weights_update(wrs_db, wrs_sta, wrs_params);
+
+               if (wrs_params->rate_idx != wrs_params->table[new_rate_idx].rate_down.rate_idx) {
+                       /*
+                        * In case the down rate is different from the previous rate,
+                        * update down rate index and reset the thresholds
+                        */
+                       struct cl_wrs_table_node *rate_down =
+                               &wrs_params->table[new_rate_idx].rate_down;
+
+                       rate_down->rate_idx = wrs_params->rate_idx;
+                       rate_down->time_th = WRS_INIT_MSEC_WEIGHT_DOWN;
+               }
+       } else if (decision == WRS_DECISION_SAME) {
+               cl_wrs_up_same_decision_weights_update(wrs_db, wrs_sta, wrs_params);
+
+               /* Reset counters besides down_time_cnt */
+               wrs_params->frames_total = 0;
+               wrs_params->fail_total = 0;
+               wrs_params->ba_not_rcv_total = 0;
+               wrs_params->epr_acc = 0;
+               wrs_params->up_same_time_cnt = 0;
+       }
+
+       cl_wrs_decision_update(wrs_db, wrs_sta, wrs_params, decision, new_rate_idx);
+
+       if (WRS_IS_DECISION_DOWN(decision) || WRS_IS_DECISION_UP(decision))
+               cl_wrs_tx_params_update(cl_hw, wrs_db, wrs_sta, wrs_params,
+                                       new_rate_idx, true);
+}
+
+void cl_wrs_decision_update(struct cl_wrs_db *wrs_db, struct cl_wrs_sta *wrs_sta,
+                           struct cl_wrs_params *wrs_params, enum cl_wrs_decision decision,
+                           u16 new_rate_idx)
+{
+       wrs_params->last_decision = decision;
+       wrs_params->decision_cnt[decision]++;
+
+       if (decision != WRS_DECISION_DOWN_IMMEDIATE)
+               wrs_params->immediate_drop_cntr = 0;
+
+       if (decision == WRS_DECISION_SAME)
+               return;
+
+       wrs_pr_trace(wrs_db,
+                    "[WRS] Decision update - timestamp [%u] sta [%u] decision [%s]\n",
+                    jiffies_to_msecs(jiffies),
+                    wrs_sta->sta_idx,
+                    WRS_DECISION_STR(decision));
+}
+
+void cl_wrs_fixed_rate_set(struct cl_hw *cl_hw, struct cl_wrs_db *wrs_db,
+                          struct cl_wrs_sta *wrs_sta, struct cl_wrs_params *wrs_params,
+                          u8 is_fixed_rate, u8 mode, u8 bw, u8 nss, u8 mcs, u8 gi)
+{
+       u16 rate_idx = 0;
+
+       if (!is_fixed_rate) {
+               wrs_params->is_fixed_rate = WRS_AUTO_RATE;
+               wrs_pr_verbose(wrs_db, "[WRS] Station %u was set to auto rate!\n",
+                              wrs_sta->sta_idx);
+               cl_wrs_rssi_set_rate(cl_hw, wrs_db, wrs_sta);
+               return;
+       }
+
+       if (mode != wrs_sta->mode) {
+               /* Set fixed rate with a different format-mode */
+               struct cl_wrs_tx_params *tx_params = &wrs_params->tx_params;
+               struct cl_sta *cl_sta = container_of(wrs_sta, struct cl_sta, wrs_sta);
+
+               if (cl_band_is_6g(cl_hw) && mode != WRS_MODE_HE) {
+                       wrs_pr_verbose(wrs_db, "[WRS] Invalid format mode [%u] for 6GHz band\n",
+                                      mode);
+                       return;
+               }
+
+               cl_dyn_bcast_rate_change(cl_hw, cl_sta, tx_params->mcs, mcs);
+
+               tx_params->bw = bw;
+               tx_params->nss = nss;
+               tx_params->mcs = mcs;
+               tx_params->gi = gi;
+               tx_params->mode = mode;
+               tx_params->fallback_en = (wrs_params->is_fixed_rate != WRS_FIXED_FALLBACK_DIS);
+
+               wrs_params->is_fixed_rate = is_fixed_rate;
+
+               cl_wrs_tx_param_set(cl_hw, wrs_sta, wrs_params, tx_params, NULL);
+               wrs_pr_verbose(wrs_db,
+                              "[WRS] Station %u set to %s - "
+                              "mode=%u, bw=%u, nss=%u, mcs=%u, gi=%u\n",
+                              wrs_sta->sta_idx, FIXED_RATE_STR(is_fixed_rate),
+                              mode, bw, nss, mcs, gi);
+               return;
+       }
+
+       rate_idx = cl_wrs_tables_find_rate_idx(wrs_params, bw, nss, mcs, gi);
+
+       if (rate_idx == WRS_INVALID_RATE) {
+               wrs_pr_err(wrs_db,
+                          "[WRS] Invalid fixed rate - mode=%u, bw=%u, nss=%u, mcs=%u, gi=%u\n",
+                          mode, bw, nss, mcs, gi);
+               return;
+       }
+
+       wrs_params->is_fixed_rate = is_fixed_rate;
+       cl_wrs_tx_params_update(cl_hw, wrs_db, wrs_sta, wrs_params, rate_idx, false);
+       wrs_pr_verbose(wrs_db,
+                      "[WRS] Station %u set to %s - mode=%u, bw=%u, nss=%u, mcs=%u, gi=%u\n",
+                       wrs_sta->sta_idx, FIXED_RATE_STR(is_fixed_rate),
+                       mode, bw, nss, mcs, gi);
+}
+
+void cl_wrs_quick_down_check(struct cl_hw *cl_hw, struct cl_wrs_db *wrs_db,
+                            struct cl_wrs_sta *wrs_sta, struct cl_wrs_params *wrs_params)
+{
+       struct cl_wrs_tx_cntrs tx_cntrs = {0};
+       struct cl_wrs_table *table = NULL;
+       u16 curr_rate_idx = 0;
+       u16 down_rate_idx = 0;
+
+       if (!wrs_params->sync ||
+           wrs_params->is_fixed_rate ||
+           !WRS_IS_DECISION_UP(wrs_params->last_decision))
+               return;
+
+       cl_wrs_update_ba_not_rcv(wrs_db, wrs_params);
+       cl_wrs_tx_cntrs_read(wrs_sta, &tx_cntrs);
+       cl_wrs_stats_per_update(wrs_db, wrs_sta, wrs_params, &tx_cntrs);
+
+       curr_rate_idx = wrs_params->rate_idx;
+       table = &wrs_params->table[curr_rate_idx];
+       down_rate_idx = table->rate_down.rate_idx;
+
+       /* Check if we transmitted enough frames for taking decision */
+       if (wrs_params->frames_total < wrs_db->min_frames_for_decision)
+               return;
+
+       /* Down decision check */
+       if (down_rate_idx != curr_rate_idx &&
+           cl_wrs_down_epr_check(wrs_db, wrs_sta, wrs_params,
+                                 wrs_db->quick_down_epr_factor, WRS_DECISION_DOWN_QUICK))
+               cl_wrs_decision_make(cl_hw, wrs_db, wrs_sta, wrs_params,
+                                    WRS_DECISION_DOWN_QUICK, down_rate_idx);
+}
+
+bool cl_wrs_up_mcs1(struct cl_hw *cl_hw, struct cl_wrs_db *wrs_db,
+                   struct cl_wrs_sta *wrs_sta, struct cl_wrs_params *wrs_params)
+{
+       /*
+        * In case of big packets (4300 in VHT and 5400 in HE) and low
+        * rate (BW 20, NSS 1, MCS 0), firmware will increase rate to MCS 1,
+        * and give an indication to driver (set rate_fix_mcs1 in cl_agg_tx_report).
+        * WRS should also move to MCS 1, and give the maximum time
+        * penalty time from MCS 0 toMCS 1.
+        */
+       u16 curr_rate_idx = wrs_params->rate_idx;
+       u16 up_rate_idx = 0;
+       struct cl_wrs_table *table = &wrs_params->table[curr_rate_idx];
+
+       if (!table || wrs_params->is_fixed_rate)
+               return false;
+
+       if (table->rate.bw != CHNL_BW_20 ||
+           table->rate.nss != WRS_SS_1 ||
+           table->rate.mcs != WRS_MCS_0)
+               return false;
+
+       up_rate_idx = cl_wrs_tables_find_rate_idx(wrs_params,
+                                                 CHNL_BW_20, WRS_SS_1, WRS_MCS_1, table->rate.gi);
+
+       if (up_rate_idx == WRS_INVALID_RATE)
+               return false;
+
+       wrs_params->table[up_rate_idx].rate_down.time_th = wrs_db->time_th_max_up;
+
+       cl_wrs_tx_cntrs_reset(wrs_sta, wrs_params);
+       cl_wrs_decision_update(wrs_db, wrs_sta, wrs_params, WRS_DECISION_UP_MCS1, up_rate_idx);
+       cl_wrs_tx_params_update(cl_hw, wrs_db, wrs_sta, wrs_params,
+                               up_rate_idx, true);
+
+       return true;
+}
+
+void cl_wrs_tx_param_set(struct cl_hw *cl_hw, struct cl_wrs_sta *wrs_sta,
+                        struct cl_wrs_params *wrs_params,
+                        struct cl_wrs_tx_params *tx_params,
+                        struct cl_wrs_rate *rate_fallback)
+{
+       struct cl_sta *cl_sta = container_of(wrs_sta, struct cl_sta, wrs_sta);
+       struct cl_bf_sta_db *bf_db = &cl_sta->bf_db;
+       struct cl_wrs_info *wrs_info = NULL;
+       u8 ltf = 0;
+       u8 ltf_fallback = 0;
+       u8 sta_idx = cl_sta->sta_idx;
+       union cl_rate_ctrl_info rate_ctrl;
+       union cl_rate_ctrl_info rate_ctrl_fallback;
+       union cl_rate_ctrl_info_he rate_ctrl_he;
+
+       if (cl_hw->ate_db.active)
+               return;
+
+       rate_ctrl_he.word = 0;
+
+       wrs_info = &cl_sta->wrs_info;
+
+       wrs_params->data_rate = cl_data_rates_get(tx_params->mode,
+                                                 tx_params->bw,
+                                                 tx_params->nss,
+                                                 tx_params->mcs,
+                                                 tx_params->gi);
+
+       rate_ctrl.word = cl_rate_ctrl_generate(cl_hw, cl_sta, tx_params->mode,
+                                              tx_params->bw, tx_params->nss,
+                                              tx_params->mcs, tx_params->gi,
+                                              tx_params->fallback_en);
+
+       /* For fallback rate use same mode (if it is NULL use same rate). */
+       if (rate_fallback) {
+               rate_ctrl_fallback.word = cl_rate_ctrl_generate(cl_hw,
+                                                               cl_sta,
+                                                               tx_params->mode,
+                                                               rate_fallback->bw,
+                                                               rate_fallback->nss,
+                                                               rate_fallback->mcs,
+                                                               rate_fallback->gi,
+                                                               tx_params->fallback_en);
+               ltf_fallback = cl_map_gi_to_ltf(tx_params->mode, rate_fallback->gi);
+       } else {
+               rate_ctrl_fallback.word = rate_ctrl.word;
+       }
+
+       /* Save current BF state and SS for the fallback rate */
+       bf_db->is_on = rate_ctrl.field.tx_bf;
+       bf_db->is_on_fallback = rate_ctrl_fallback.field.tx_bf;
+       bf_db->num_ss = tx_params->nss;
+       bf_db->num_ss_fallback = rate_fallback ? rate_fallback->nss : tx_params->nss;
+
+       /* Reset counters */
+       wrs_info->tx_success = 0;
+       wrs_info->tx_fail = 0;
+
+       /* Mark rate as unsynced */
+       wrs_info->synced = false;
+       wrs_info->quick_rate_check = false;
+       wrs_info->sync_attempts = 0;
+
+       ltf = cl_map_gi_to_ltf(tx_params->mode, tx_params->gi);
+
+       if (tx_params->mode == WRS_MODE_HE)
+               rate_ctrl_he.field.spatial_conf = RATE_CNTRL_HE_SPATIAL_CONF_DEF;
+
+       /* Send new rate to firmware */
+       cl_msg_tx_update_rate_dl(cl_hw, sta_idx, rate_ctrl.word,
+                                rate_ctrl_fallback.word, tx_params->bw,
+                                RATE_OP_MODE_STA_SU,
+                                ltf, ltf_fallback, rate_ctrl_he.word);
+
+       /*
+        * TODO: Limit by SU/TX if active function will take control
+        *       over MU-SU/TX-RX.
+        */
+       cl_rsrc_mgmt_rates_update(cl_hw, cl_sta);
+}
+
+s8 cl_wrs_rssi_eq_calc(struct cl_hw *cl_hw, struct cl_wrs_sta *wrs_sta,
+                      bool read_clear, s8 *sorted_rssi)
+{
+       struct cl_sta *cl_sta = container_of(wrs_sta, struct cl_sta, wrs_sta);
+       struct cl_wrs_rssi *wrs_rssi = &cl_sta->wrs_rssi;
+       int i;
+
+       if (wrs_rssi->cnt == 0) {
+               memcpy(sorted_rssi, cl_sta->last_rssi, cl_hw->num_antennas);
+               goto sort;
+       }
+
+       for (i = 0; i < cl_hw->num_antennas; i++)
+               sorted_rssi[i] = (s8)(wrs_rssi->sum[i] / wrs_rssi->cnt);
+
+       if (read_clear)
+               memset(wrs_rssi, 0, sizeof(struct cl_wrs_rssi));
+
+sort:
+       /* Sort RSSI values in descending order */
+       cl_rssi_sort_descending(sorted_rssi, cl_hw->num_antennas);
+
+       /* Calc equivalent RSSI */
+       return cl_rssi_calc_equivalent(cl_hw, sorted_rssi);
+}
+
+void cl_wrs_tx_cntrs_reset(struct cl_wrs_sta *wrs_sta, struct cl_wrs_params *wrs_params)
+{
+       struct cl_sta *cl_sta = container_of(wrs_sta, struct cl_sta, wrs_sta);
+       struct cl_wrs_info *wrs_info = &cl_sta->wrs_info;
+
+       _cl_wrs_tx_cntrs_reset(wrs_info);
+}
--
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.
________________________________


^ permalink raw reply related	[flat|nested] 262+ messages in thread

* [RFC v1 240/256] cl8k: add wrs/wrs.h
  2021-06-17 15:58 [RFC v1 000/256] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (238 preceding siblings ...)
  2021-06-17 16:02 ` [RFC v1 239/256] cl8k: add wrs/wrs.c viktor.barna
@ 2021-06-17 16:02 ` viktor.barna
  2021-06-17 16:02 ` [RFC v1 241/256] cl8k: add wrs/wrs_ap.c viktor.barna
                   ` (17 subsequent siblings)
  257 siblings, 0 replies; 262+ messages in thread
From: viktor.barna @ 2021-06-17 16:02 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Oleksandr Savchenko, Shay Bar, Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

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

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 drivers/net/wireless/celeno/cl8k/wrs/wrs.h | 45 ++++++++++++++++++++++
 1 file changed, 45 insertions(+)
 create mode 100644 drivers/net/wireless/celeno/cl8k/wrs/wrs.h

diff --git a/drivers/net/wireless/celeno/cl8k/wrs/wrs.h b/drivers/net/wireless/celeno/cl8k/wrs/wrs.h
new file mode 100644
index 000000000000..cf525e868341
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/wrs/wrs.h
@@ -0,0 +1,45 @@
+/* SPDX-License-Identifier: MIT */
+/* Copyright(c) 2019-2021, Celeno Communications Ltd. */
+
+#ifndef CL_WRS_H
+#define CL_WRS_H
+
+#include "wrs/wrs_db.h"
+#include "hw.h"
+
+/**
+ * WRS (=Weighted Rate Selection)
+ */
+
+void cl_wrs_init(struct cl_hw *cl_hw);
+void cl_wrs_lock_bh(struct cl_wrs_db *wrs_db);
+void cl_wrs_unlock_bh(struct cl_wrs_db *wrs_db);
+void cl_wrs_lock(struct cl_wrs_db *wrs_db);
+void cl_wrs_unlock(struct cl_wrs_db *wrs_db);
+void cl_wrs_fixed_rate_set(struct cl_hw *cl_hw, struct cl_wrs_db *wrs_db,
+                          struct cl_wrs_sta *wrs_sta, struct cl_wrs_params *wrs_params,
+                          u8 is_fixed_rate, u8 mode, u8 bw, u8 nss, u8 mcs, u8 gi);
+void cl_wrs_tx_param_sync(struct cl_wrs_db *wrs_db, struct cl_wrs_sta *wrs_sta,
+                         struct cl_wrs_params *wrs_params);
+void cl_wrs_tx_params_update(struct cl_hw *cl_hw, struct cl_wrs_db *wrs_db,
+                            struct cl_wrs_sta *wrs_sta, struct cl_wrs_params *wrs_params,
+                            u16 new_rate_idx, bool is_sync_required);
+void cl_wrs_decision_make(struct cl_hw *cl_hw, struct cl_wrs_db *wrs_db,
+                         struct cl_wrs_sta *wrs_sta, struct cl_wrs_params *wrs_params,
+                         enum cl_wrs_decision decision, u16 new_rate_idx);
+void cl_wrs_decision_update(struct cl_wrs_db *wrs_db, struct cl_wrs_sta *wrs_sta,
+                           struct cl_wrs_params *wrs_params, enum cl_wrs_decision decision,
+                           u16 new_rate_idx);
+void cl_wrs_quick_down_check(struct cl_hw *cl_hw, struct cl_wrs_db *wrs_db,
+                            struct cl_wrs_sta *wrs_sta, struct cl_wrs_params *wrs_params);
+bool cl_wrs_up_mcs1(struct cl_hw *cl_hw, struct cl_wrs_db *wrs_db,
+                   struct cl_wrs_sta *wrs_sta, struct cl_wrs_params *wrs_params);
+void cl_wrs_tx_param_set(struct cl_hw *cl_hw, struct cl_wrs_sta *wrs_sta,
+                        struct cl_wrs_params *wrs_params,
+                        struct cl_wrs_tx_params *tx_params,
+                        struct cl_wrs_rate *rate_fallback);
+s8 cl_wrs_rssi_eq_calc(struct cl_hw *cl_hw, struct cl_wrs_sta *wrs_sta,
+                      bool read_clear, s8 *sorted_rssi);
+void cl_wrs_tx_cntrs_reset(struct cl_wrs_sta *wrs_sta, struct cl_wrs_params *wrs_params);
+
+#endif /* CL_WRS_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.
________________________________


^ permalink raw reply related	[flat|nested] 262+ messages in thread

* [RFC v1 241/256] cl8k: add wrs/wrs_ap.c
  2021-06-17 15:58 [RFC v1 000/256] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (239 preceding siblings ...)
  2021-06-17 16:02 ` [RFC v1 240/256] cl8k: add wrs/wrs.h viktor.barna
@ 2021-06-17 16:02 ` viktor.barna
  2021-06-17 16:02 ` [RFC v1 242/256] cl8k: add wrs/wrs_ap.h viktor.barna
                   ` (16 subsequent siblings)
  257 siblings, 0 replies; 262+ messages in thread
From: viktor.barna @ 2021-06-17 16:02 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Oleksandr Savchenko, Shay Bar, Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

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

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 drivers/net/wireless/celeno/cl8k/wrs/wrs_ap.c | 99 +++++++++++++++++++
 1 file changed, 99 insertions(+)
 create mode 100644 drivers/net/wireless/celeno/cl8k/wrs/wrs_ap.c

diff --git a/drivers/net/wireless/celeno/cl8k/wrs/wrs_ap.c b/drivers/net/wireless/celeno/cl8k/wrs/wrs_ap.c
new file mode 100644
index 000000000000..8ac8f7f8c644
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/wrs/wrs_ap.c
@@ -0,0 +1,99 @@
+// SPDX-License-Identifier: MIT
+/* Copyright(c) 2019-2021, Celeno Communications Ltd. */
+
+#include "wrs/wrs_ap.h"
+
+static void cl_wrs_ap_set_bitmap(struct cl_hw *cl_hw, struct cl_wrs_db *wrs_db)
+{
+       u8 mcs, bw, nss, rate_idx;
+
+       memset(wrs_db->ap_supported_rates, 0, sizeof(wrs_db->ap_supported_rates));
+
+       for (bw = cl_hw->conf->ci_wrs_min_bw; bw <= wrs_db->max_cap.bw; bw++)
+               for (nss = 0; nss <= wrs_db->max_cap.nss; nss++)
+                       for (mcs = 0; mcs <= wrs_db->max_cap.mcs; mcs++) {
+                               rate_idx = mcs + (nss * WRS_MCS_MAX);
+                               wrs_db->ap_supported_rates[bw] |= BIT(rate_idx);
+                       }
+}
+
+static void cl_wrs_ap_capab_print(struct cl_hw *cl_hw)
+{
+       struct cl_wrs_db *wrs_db = &cl_hw->wrs_db;
+       struct cl_wrs_rate *max_cap = &wrs_db->max_cap;
+       u8 bw_mhz = BW_TO_MHZ(max_cap->bw);
+
+       pr_debug("\n");
+       pr_debug("AP max capabilities\n");
+       pr_debug("-------------------\n");
+       pr_debug("Band : %ug\n", cl_hw->conf->ci_band_num);
+       pr_debug("Mode : %s\n", WRS_MODE_STR(wrs_db->mode));
+       pr_debug("BW   : %uMHz\n", bw_mhz);
+       pr_debug("NSS  : %u\n", max_cap->nss);
+       pr_debug("MCS  : %u\n", max_cap->mcs);
+       pr_debug("GI   : %u\n", max_cap->gi);
+}
+
+void cl_wrs_ap_capab_set(struct cl_hw *cl_hw)
+{
+       struct cl_wrs_db *wrs_db = &cl_hw->wrs_db;
+       struct cl_wrs_rate *max_cap = &wrs_db->max_cap;
+       u8 conf_bw = cl_hw->conf->ce_channel_bandwidth;
+       u8 conf_nss = cl_hw->conf->ce_tx_nss - 1;
+       u8 conf_gi = cl_hw->conf->ha_short_guard_interval;
+
+       switch (cl_hw->conf->ce_wireless_mode) {
+       case WIRELESS_MODE_HE:
+       case WIRELESS_MODE_HT_VHT_HE:
+               wrs_db->mode = WRS_MODE_HE;
+               max_cap->bw = conf_bw;
+               max_cap->nss = conf_nss;
+               max_cap->mcs = WRS_MCS_11;
+               max_cap->gi = conf_gi ? WRS_GI_VSHORT : 0;
+               break;
+       case WIRELESS_MODE_HT_VHT:
+               wrs_db->mode = WRS_MODE_VHT;
+               max_cap->bw = conf_bw;
+               max_cap->nss = conf_nss;
+               max_cap->mcs = WRS_MCS_9;
+               max_cap->gi = conf_gi ? WRS_GI_SHORT : 0;
+               break;
+       case WIRELESS_MODE_HT:
+               wrs_db->mode = WRS_MODE_HT;
+               max_cap->bw = min_t(u8, conf_bw, CHNL_BW_80);
+               max_cap->nss = conf_nss;
+               max_cap->mcs = WRS_MCS_7;
+               max_cap->gi = conf_gi ? WRS_GI_SHORT : 0;
+               break;
+       case WIRELESS_MODE_LEGACY:
+       default:
+               if (cl_hw->conf->ha_hw_mode == HW_MODE_B) {
+                       wrs_db->mode = WRS_MODE_CCK;
+                       max_cap->mcs = WRS_MCS_3;
+               } else {
+                       wrs_db->mode = WRS_MODE_OFDM;
+                       max_cap->mcs = WRS_MCS_7;
+               }
+
+               max_cap->bw = CHNL_BW_20;
+               max_cap->nss = 0;
+               max_cap->gi = 0;
+               break;
+       }
+
+       if (cl_hw->conf->ci_wrs_max_bw < max_cap->bw) {
+               max_cap->bw = cl_hw->conf->ci_wrs_max_bw;
+               pr_debug("[WRS] Max BW limited to %uMHz\n", BW_TO_MHZ(max_cap->bw));
+       }
+
+       cl_wrs_ap_set_bitmap(cl_hw, wrs_db);
+
+       cl_wrs_ap_capab_print(cl_hw);
+}
+
+void cl_wrs_ap_capab_modify_bw(struct cl_hw *cl_hw, struct cl_wrs_db *wrs_db, u8 max_bw)
+{
+       wrs_db->max_cap.bw = max_bw;
+
+       cl_wrs_ap_set_bitmap(cl_hw, wrs_db);
+}
--
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.
________________________________


^ permalink raw reply related	[flat|nested] 262+ messages in thread

* [RFC v1 242/256] cl8k: add wrs/wrs_ap.h
  2021-06-17 15:58 [RFC v1 000/256] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (240 preceding siblings ...)
  2021-06-17 16:02 ` [RFC v1 241/256] cl8k: add wrs/wrs_ap.c viktor.barna
@ 2021-06-17 16:02 ` viktor.barna
  2021-06-17 16:02 ` [RFC v1 243/256] cl8k: add wrs/wrs_api.c viktor.barna
                   ` (15 subsequent siblings)
  257 siblings, 0 replies; 262+ messages in thread
From: viktor.barna @ 2021-06-17 16:02 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Oleksandr Savchenko, Shay Bar, Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

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

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 drivers/net/wireless/celeno/cl8k/wrs/wrs_ap.h | 13 +++++++++++++
 1 file changed, 13 insertions(+)
 create mode 100644 drivers/net/wireless/celeno/cl8k/wrs/wrs_ap.h

diff --git a/drivers/net/wireless/celeno/cl8k/wrs/wrs_ap.h b/drivers/net/wireless/celeno/cl8k/wrs/wrs_ap.h
new file mode 100644
index 000000000000..a01e9b46bf68
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/wrs/wrs_ap.h
@@ -0,0 +1,13 @@
+/* SPDX-License-Identifier: MIT */
+/* Copyright(c) 2019-2021, Celeno Communications Ltd. */
+
+#ifndef CL_WRS_AP_H
+#define CL_WRS_AP_H
+
+#include "wrs/wrs_db.h"
+#include "hw.h"
+
+void cl_wrs_ap_capab_set(struct cl_hw *cl_hw);
+void cl_wrs_ap_capab_modify_bw(struct cl_hw *cl_hw, struct cl_wrs_db *wrs_db, u8 max_bw);
+
+#endif /* CL_WRS_AP_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.
________________________________


^ permalink raw reply related	[flat|nested] 262+ messages in thread

* [RFC v1 243/256] cl8k: add wrs/wrs_api.c
  2021-06-17 15:58 [RFC v1 000/256] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (241 preceding siblings ...)
  2021-06-17 16:02 ` [RFC v1 242/256] cl8k: add wrs/wrs_ap.h viktor.barna
@ 2021-06-17 16:02 ` viktor.barna
  2021-06-17 16:02 ` [RFC v1 244/256] cl8k: add wrs/wrs_api.h viktor.barna
                   ` (14 subsequent siblings)
  257 siblings, 0 replies; 262+ messages in thread
From: viktor.barna @ 2021-06-17 16:02 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Oleksandr Savchenko, Shay Bar, Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

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

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 .../net/wireless/celeno/cl8k/wrs/wrs_api.c    | 212 ++++++++++++++++++
 1 file changed, 212 insertions(+)
 create mode 100644 drivers/net/wireless/celeno/cl8k/wrs/wrs_api.c

diff --git a/drivers/net/wireless/celeno/cl8k/wrs/wrs_api.c b/drivers/net/wireless/celeno/cl8k/wrs/wrs_api.c
new file mode 100644
index 000000000000..180f234eae5b
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/wrs/wrs_api.c
@@ -0,0 +1,212 @@
+// SPDX-License-Identifier: MIT
+/* Copyright(c) 2019-2021, Celeno Communications Ltd. */
+
+#include "wrs/wrs_api.h"
+#include "wrs/wrs.h"
+#include "wrs/wrs_sta.h"
+#include "wrs/wrs_ap.h"
+#include "wrs/wrs_cli.h"
+#include "rate_ctrl.h"
+#include "prot_mode.h"
+#include "utils/utils.h"
+#include "band.h"
+#include "sta.h"
+#include "data_rates.h"
+
+void cl_wrs_api_init(struct cl_hw *cl_hw)
+{
+       cl_wrs_init(cl_hw);
+       cl_wrs_ap_capab_set(cl_hw);
+}
+
+void cl_wrs_api_close(struct cl_hw *cl_hw)
+{
+       struct cl_wrs_db *wrs_db = &cl_hw->wrs_db;
+
+       cl_timer_disable_sync(&wrs_db->timer_maintenance);
+}
+
+void cl_wrs_api_sta_add(struct cl_hw *cl_hw, struct ieee80211_sta *sta)
+{
+       struct cl_wrs_db *wrs_db = &cl_hw->wrs_db;
+
+       cl_wrs_lock_bh(wrs_db);
+       cl_wrs_sta_add(cl_hw, sta);
+       cl_wrs_unlock_bh(wrs_db);
+}
+
+void cl_wrs_api_sta_remove(struct cl_hw *cl_hw, struct cl_sta *cl_sta)
+{
+       struct cl_wrs_db *wrs_db = &cl_hw->wrs_db;
+
+       cl_wrs_lock_bh(wrs_db);
+       cl_wrs_sta_remove(cl_hw, wrs_db, cl_sta);
+       cl_wrs_unlock_bh(wrs_db);
+}
+
+void cl_wrs_api_bss_set_bw(struct cl_hw *cl_hw, u8 bw)
+{
+       struct cl_wrs_db *wrs_db = &cl_hw->wrs_db;
+
+       cl_wrs_lock_bh(wrs_db);
+       cl_wrs_ap_capab_modify_bw(cl_hw, wrs_db, bw);
+       cl_wrs_unlock_bh(wrs_db);
+}
+
+void cl_wrs_api_bw_changed(struct cl_hw *cl_hw, struct ieee80211_sta *sta, u8 bw)
+{
+       struct cl_wrs_db *wrs_db = &cl_hw->wrs_db;
+       struct cl_sta *cl_sta = IEEE80211_STA_TO_CL_STA(sta);
+       struct cl_wrs_sta *wrs_sta = &cl_sta->wrs_sta;
+
+       cl_wrs_lock_bh(wrs_db);
+
+       wrs_sta->max_rate_cap.bw = bw;
+       cl_wrs_sta_capabilities_set(wrs_db, sta);
+       cl_wrs_tables_build(cl_hw, wrs_sta, &wrs_sta->su_params);
+
+       cl_wrs_unlock_bh(wrs_db);
+}
+
+void cl_wrs_api_nss_changed(struct cl_hw *cl_hw, struct ieee80211_sta *sta, u8 nss)
+{
+       struct cl_wrs_db *wrs_db = &cl_hw->wrs_db;
+       struct cl_sta *cl_sta = IEEE80211_STA_TO_CL_STA(sta);
+       struct cl_wrs_sta *wrs_sta = &cl_sta->wrs_sta;
+
+       cl_wrs_lock_bh(wrs_db);
+
+       wrs_sta->max_rate_cap.nss = nss;
+       cl_wrs_sta_capabilities_set(wrs_db, sta);
+       cl_wrs_tables_build(cl_hw, wrs_sta, &wrs_sta->su_params);
+
+       cl_wrs_unlock_bh(wrs_db);
+}
+
+static void _cl_wrs_api_recovery(struct cl_hw *cl_hw, struct cl_wrs_sta *wrs_sta,
+                                struct cl_wrs_params *wrs_params)
+{
+       u16 fallback_rate_idx = wrs_params->table[wrs_params->rate_idx].rate_down.rate_idx;
+       struct cl_wrs_rate *rate_fallback = &wrs_params->table[fallback_rate_idx].rate;
+       struct cl_wrs_tx_params *tx_params = &wrs_params->tx_params;
+
+       cl_wrs_tx_param_set(cl_hw, wrs_sta, wrs_params, tx_params, rate_fallback);
+}
+
+void cl_wrs_api_recovery(struct cl_hw *cl_hw)
+{
+       struct cl_sta *cl_sta = NULL;
+       struct cl_wrs_db *wrs_db = &cl_hw->wrs_db;
+       struct cl_wrs_sta *wrs_sta = NULL;
+
+       cl_wrs_lock_bh(wrs_db);
+       cl_sta_lock(cl_hw);
+
+       list_for_each_entry(cl_sta, &cl_hw->cl_sta_db.head, list) {
+               wrs_sta = &cl_sta->wrs_sta;
+
+               _cl_wrs_api_recovery(cl_hw, wrs_sta, &wrs_sta->su_params);
+       }
+
+       cl_sta_unlock(cl_hw);
+       cl_wrs_unlock_bh(wrs_db);
+}
+
+void cl_wrs_api_beamforming_sync(struct cl_hw *cl_hw, struct cl_sta *cl_sta)
+{
+       struct cl_wrs_db *wrs_db = &cl_hw->wrs_db;
+       struct cl_wrs_params *wrs_params = &cl_sta->wrs_sta.su_params;
+       u8 up_idx = 0;
+       u16 rate_idx = wrs_params->rate_idx;
+
+       cl_wrs_lock(wrs_db);
+
+       for (up_idx = 0; up_idx < WRS_TABLE_NODE_UP_MAX; up_idx++)
+               wrs_params->table[rate_idx].rate_up[up_idx].time_th = WRS_INIT_MSEC_WEIGHT_UP;
+
+       cl_wrs_unlock(wrs_db);
+
+       wrs_pr_info(wrs_db, "[WRS] sta %u - beamforming sync\n", cl_sta->sta_idx);
+}
+
+void cl_wrs_api_quick_down_check(struct cl_hw *cl_hw, struct cl_sta *cl_sta,
+                                struct cl_wrs_params *wrs_params)
+{
+       struct cl_wrs_db *wrs_db = &cl_hw->wrs_db;
+
+       cl_wrs_lock(wrs_db);
+       cl_wrs_quick_down_check(cl_hw, wrs_db, &cl_sta->wrs_sta, wrs_params);
+       cl_wrs_unlock(wrs_db);
+}
+
+void cl_wrs_api_rate_sync(struct cl_hw *cl_hw, struct cl_sta *cl_sta,
+                         struct cl_wrs_params *wrs_params)
+{
+       struct cl_wrs_db *wrs_db = &cl_hw->wrs_db;
+
+       cl_wrs_lock(wrs_db);
+       cl_wrs_tx_param_sync(wrs_db, &cl_sta->wrs_sta, wrs_params);
+       cl_wrs_unlock(wrs_db);
+}
+
+bool cl_wrs_api_up_mcs1(struct cl_hw *cl_hw, struct cl_sta *cl_sta,
+                       struct cl_wrs_params *wrs_params)
+{
+       struct cl_wrs_db *wrs_db = &cl_hw->wrs_db;
+       bool result = false;
+
+       cl_wrs_lock(wrs_db);
+       result = cl_wrs_up_mcs1(cl_hw, wrs_db, &cl_sta->wrs_sta, wrs_params);
+       cl_wrs_unlock(wrs_db);
+
+       return result;
+}
+
+void cl_wrs_api_set_smps_mode(struct cl_hw *cl_hw, struct ieee80211_sta *sta, const u8 bw)
+{
+       struct cl_wrs_db *wrs_db = &cl_hw->wrs_db;
+       struct cl_sta *cl_sta = IEEE80211_STA_TO_CL_STA(sta);
+       struct cl_wrs_sta *wrs_sta = &cl_sta->wrs_sta;
+       u8 min_bw;
+
+       if (sta->smps_mode == IEEE80211_SMPS_STATIC ||
+           sta->smps_mode == IEEE80211_SMPS_DYNAMIC) {
+               /* If RTS is enabled, there is no need to go down to 1ss */
+               if (cl_prot_mode_get(cl_hw) == TXL_PROT_RTS)
+                       return;
+
+               wrs_sta->smps_enable = true;
+       } else if (sta->smps_mode == IEEE80211_SMPS_OFF && wrs_sta->smps_enable) {
+               wrs_sta->smps_enable = false;
+       }
+
+       cl_wrs_lock_bh(wrs_db);
+       min_bw = min_t(u8, bw, wrs_db->max_cap.bw);
+
+       if (wrs_sta->max_rate_cap.bw != min_bw) {
+               wrs_sta->max_rate_cap.bw = min_bw;
+               wrs_pr_trace(wrs_db, "[WRS] SMPS mode: sta %u, bw %u\n",
+                            wrs_sta->sta_idx, min_bw);
+               cl_wrs_tables_build(cl_hw, wrs_sta, &wrs_sta->su_params);
+       }
+
+       cl_wrs_unlock_bh(wrs_db);
+}
+
+u16 cl_wrs_api_get_sta_data_rate(struct cl_sta *cl_sta)
+{
+       return cl_sta->wrs_sta.su_params.data_rate;
+}
+
+int cl_wrs_api_cli(struct cl_hw *cl_hw, struct cl_vif *cl_vif, struct cli_params *cli_params)
+{
+       struct cl_wrs_db *wrs_db = &cl_hw->wrs_db;
+       int ret;
+
+       cl_wrs_lock_bh(wrs_db);
+       ret = cl_wrs_cli(cl_hw, cl_vif, cli_params);
+       cl_wrs_unlock_bh(wrs_db);
+
+       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.
________________________________


^ permalink raw reply related	[flat|nested] 262+ messages in thread

* [RFC v1 244/256] cl8k: add wrs/wrs_api.h
  2021-06-17 15:58 [RFC v1 000/256] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (242 preceding siblings ...)
  2021-06-17 16:02 ` [RFC v1 243/256] cl8k: add wrs/wrs_api.c viktor.barna
@ 2021-06-17 16:02 ` viktor.barna
  2021-06-17 16:02 ` [RFC v1 245/256] cl8k: add wrs/wrs_cli.c viktor.barna
                   ` (13 subsequent siblings)
  257 siblings, 0 replies; 262+ messages in thread
From: viktor.barna @ 2021-06-17 16:02 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Oleksandr Savchenko, Shay Bar, Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

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

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 .../net/wireless/celeno/cl8k/wrs/wrs_api.h    | 30 +++++++++++++++++++
 1 file changed, 30 insertions(+)
 create mode 100644 drivers/net/wireless/celeno/cl8k/wrs/wrs_api.h

diff --git a/drivers/net/wireless/celeno/cl8k/wrs/wrs_api.h b/drivers/net/wireless/celeno/cl8k/wrs/wrs_api.h
new file mode 100644
index 000000000000..016d606633a0
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/wrs/wrs_api.h
@@ -0,0 +1,30 @@
+/* SPDX-License-Identifier: MIT */
+/* Copyright(c) 2019-2021, Celeno Communications Ltd. */
+
+#ifndef CL_WRS_API_H
+#define CL_WRS_API_H
+
+#include "hw.h"
+#include "vif.h"
+
+/* Driver --> WRS */
+void cl_wrs_api_init(struct cl_hw *cl_hw);
+void cl_wrs_api_close(struct cl_hw *cl_hw);
+void cl_wrs_api_sta_add(struct cl_hw *cl_hw, struct ieee80211_sta *sta);
+void cl_wrs_api_sta_remove(struct cl_hw *cl_hw, struct cl_sta *cl_sta);
+void cl_wrs_api_bss_set_bw(struct cl_hw *cl_hw, u8 bw);
+void cl_wrs_api_bw_changed(struct cl_hw *cl_hw, struct ieee80211_sta *sta, u8 bw);
+void cl_wrs_api_nss_changed(struct cl_hw *cl_hw, struct ieee80211_sta *sta, u8 nss);
+void cl_wrs_api_recovery(struct cl_hw *cl_hw);
+void cl_wrs_api_beamforming_sync(struct cl_hw *cl_hw, struct cl_sta *cl_sta);
+void cl_wrs_api_quick_down_check(struct cl_hw *cl_hw, struct cl_sta *cl_sta,
+                                struct cl_wrs_params *wrs_params);
+void cl_wrs_api_rate_sync(struct cl_hw *cl_hw, struct cl_sta *cl_sta,
+                         struct cl_wrs_params *wrs_params);
+bool cl_wrs_api_up_mcs1(struct cl_hw *cl_hw, struct cl_sta *cl_sta,
+                       struct cl_wrs_params *wrs_params);
+void cl_wrs_api_set_smps_mode(struct cl_hw *cl_hw, struct ieee80211_sta *sta, const u8 bw);
+u16 cl_wrs_api_get_sta_data_rate(struct cl_sta *cl_sta);
+int cl_wrs_api_cli(struct cl_hw *cl_hw, struct cl_vif *cl_vif, struct cli_params *cli_params);
+
+#endif /* CL_WRS_API_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.
________________________________


^ permalink raw reply related	[flat|nested] 262+ messages in thread

* [RFC v1 245/256] cl8k: add wrs/wrs_cli.c
  2021-06-17 15:58 [RFC v1 000/256] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (243 preceding siblings ...)
  2021-06-17 16:02 ` [RFC v1 244/256] cl8k: add wrs/wrs_api.h viktor.barna
@ 2021-06-17 16:02 ` viktor.barna
  2021-06-17 16:02 ` [RFC v1 246/256] cl8k: add wrs/wrs_cli.h viktor.barna
                   ` (12 subsequent siblings)
  257 siblings, 0 replies; 262+ messages in thread
From: viktor.barna @ 2021-06-17 16:02 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Oleksandr Savchenko, Shay Bar, Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

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

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 .../net/wireless/celeno/cl8k/wrs/wrs_cli.c    | 852 ++++++++++++++++++
 1 file changed, 852 insertions(+)
 create mode 100644 drivers/net/wireless/celeno/cl8k/wrs/wrs_cli.c

diff --git a/drivers/net/wireless/celeno/cl8k/wrs/wrs_cli.c b/drivers/net/wireless/celeno/cl8k/wrs/wrs_cli.c
new file mode 100644
index 000000000000..7319ad681358
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/wrs/wrs_cli.c
@@ -0,0 +1,852 @@
+// SPDX-License-Identifier: MIT
+/* Copyright(c) 2019-2021, Celeno Communications Ltd. */
+
+#include "wrs/wrs_cli.h"
+#include "wrs/wrs_sta.h"
+#include "wrs/wrs_rssi.h"
+#include "wrs/wrs.h"
+#include "wrs/wrs_stats.h"
+#include "utils/utils.h"
+#include "sta.h"
+
+#define WRS_ALL_STA U8_MAX
+
+static void cl_wrs_cli_interval_set(struct cl_wrs_db *wrs_db, u32 interval)
+{
+       wrs_db->interval = msecs_round(interval);
+       cl_timer_period_set(&wrs_db->timer_maintenance, wrs_db->interval);
+
+       pr_debug("[WRS] Interval = %u\n", wrs_db->interval);
+}
+
+static void cl_wrs_cli_config_print(struct cl_hw *cl_hw)
+{
+       struct cl_wrs_db *wrs_db = &cl_hw->wrs_db;
+
+       pr_debug("\n");
+       pr_debug("--------------------------------\n");
+       pr_debug("Main database configuration\n");
+       pr_debug("--------------------------------\n");
+       pr_debug("Interval                = [%u]\n",
+                wrs_db->interval);
+       pr_debug("Debug level             = [%u]\n",
+                wrs_db->debug_level);
+       pr_debug("Min frames for decision = [%u]\n",
+                wrs_db->min_frames_for_decision);
+       pr_debug("EPR factor              = [%u]\n",
+                wrs_db->epr_factor);
+       pr_debug("--------------------------------\n");
+       pr_debug("Immediate drop configuration\n");
+       pr_debug("--------------------------------\n");
+       pr_debug("Enabled                 = [%s]\n",
+                wrs_db->immediate_drop_en ? "TRUE" : "FALSE");
+       pr_debug("EPR Factor              = [%u]\n",
+                wrs_db->immediate_drop_epr_factor);
+       pr_debug("Max in row              = [%u]\n",
+                wrs_db->immediate_drop_max_in_row);
+       pr_debug("--------------------------------\n");
+       pr_debug("RSSI protect configuration\n");
+       pr_debug("--------------------------------\n");
+       pr_debug("Enabled                 = [%s]\n",
+                wrs_db->rssi_protect_en ? "TRUE" : "FALSE");
+       pr_debug("Mode                    = [%s]\n",
+                (wrs_db->rssi_protect_mode == WRS_RSSI_PROT_MODE_RSSI) ? "rssi" : "neighbor");
+       pr_debug("Up threshold            = [%d]\n",
+                wrs_db->rssi_protect_up_thr);
+       pr_debug("Down threshold          = [%d]\n",
+                wrs_db->rssi_protect_dn_thr);
+       pr_debug("--------------------------------\n");
+       pr_debug("Converge idle configuration\n");
+       pr_debug("--------------------------------\n");
+       pr_debug("Enable                  = [%s]\n",
+                wrs_db->converge_idle_en ? "TRUE" : "FALSE");
+       pr_debug("Interval reset          = [%u]\n",
+                wrs_db->converge_idle_interval_reset);
+       pr_debug("Interval rssi           = [%u]\n",
+                wrs_db->converge_idle_interval_rssi);
+       pr_debug("Packet threshold        = [%u]\n",
+                wrs_db->converge_idle_packet_th);
+       pr_debug("--------------------------------\n");
+       pr_debug("Converge traffic configuration\n");
+       pr_debug("--------------------------------\n");
+       pr_debug("Traffic enable          = [%s]\n",
+                wrs_db->converge_trfc_en ? "TRUE" : "FALSE");
+       pr_debug("Interval static         = [%u]\n",
+                wrs_db->converge_trfc_interval_static);
+       pr_debug("Interval motion         = [%u]\n",
+                wrs_db->converge_trfc_interval_motion);
+       pr_debug("--------------------------------\n");
+       pr_debug("Steps and min/max thresholds\n");
+       pr_debug("--------------------------------\n");
+       pr_debug("Step down               = [%u]\n",
+                wrs_db->step_down);
+       pr_debug("Step same/up            = [%u]\n",
+                wrs_db->step_up_same);
+       pr_debug("Min threshold           = [%u]\n",
+                wrs_db->time_th_min);
+       pr_debug("Max threshold up        = [%u]\n",
+                wrs_db->time_th_max_up);
+       pr_debug("Max threshold down      = [%u]\n",
+                wrs_db->time_th_max_down);
+       pr_debug("--------------------------------\n");
+       pr_debug("Quick up configuration\n");
+       pr_debug("--------------------------------\n");
+       pr_debug("Enable                  = [%s]\n",
+                wrs_db->quick_up_en ? "TRUE" : "FALSE");
+       pr_debug("BA threshold            = [%u]\n",
+                wrs_db->quick_up_ba_thr);
+       pr_debug("Interval                = [%u]\n",
+                wrs_db->quick_up_interval);
+       pr_debug("--------------------------------\n");
+       pr_debug("Quick down configuration\n");
+       pr_debug("--------------------------------\n");
+       pr_debug("Enable                  = [%s]\n",
+                wrs_db->quick_down_en ? "TRUE" : "FALSE");
+       pr_debug("EPR factor              = [%u]\n",
+                wrs_db->quick_down_epr_factor);
+       pr_debug("Agg threshold           = [%u]\n",
+                wrs_db->quick_down_agg_thr);
+       pr_debug("Packet threshold        = [%u]\n",
+                wrs_db->quick_down_pkt_thr);
+       pr_debug("--------------------------------\n");
+       pr_debug("BA not received configuration\n");
+       pr_debug("--------------------------------\n");
+       pr_debug("Collision filter        = [%s]\n",
+                wrs_db->ba_not_rcv_collision_filter ? "TRUE" : "FALSE");
+       pr_debug("Force                   = [%s]\n",
+                wrs_db->ba_not_rcv_force ? "TRUE" : "FALSE");
+       pr_debug("Time since sync         = [%u]\n",
+                wrs_db->ba_not_rcv_time_since_sync);
+       pr_debug("--------------------------------\n");
+       pr_debug("Sync rate\n");
+       pr_debug("--------------------------------\n");
+       pr_debug("Sync timeout            = [%u]\n",
+                wrs_db->sync_timeout);
+       pr_debug("Sync min attempts       = [%u]\n",
+                wrs_db->sync_min_attempts);
+       pr_debug("\n");
+}
+
+static void cl_wrs_cli_dbg_level_set(struct cl_wrs_db *wrs_db, u32 debug_level)
+{
+       if (debug_level < DBG_LVL_MAX) {
+               wrs_db->debug_level = debug_level;
+               pr_debug("[WRS] Debug level = %u\n", debug_level);
+       } else {
+               pr_err("[WRS] Invalid debug level = %u\n", debug_level);
+       }
+}
+
+static void cl_wrs_cli_fixed_rate_set(struct cl_hw *cl_hw, struct cl_wrs_db *wrs_db, u8 sta_idx,
+                                     u8 is_fixed_rate, u8 mode, u8 bw, u8 nss,
+                                     u8 mcs, u8 gi)
+{
+       struct cl_wrs_sta *wrs_sta = NULL;
+
+       if (is_fixed_rate >= WRS_FIXED_RATE_MAX) {
+               pr_err("[WRS] Invalid fixed rate [%u] -\n"
+                      "0 = auto\n"
+                      "1 = fixed - fallback enable\n"
+                      "2 = fixed - fallback disable\n",
+                      is_fixed_rate);
+               return;
+       }
+
+       if (sta_idx != WRS_ALL_STA) {
+               cl_sta_lock_bh(cl_hw);
+               wrs_sta = cl_wrs_sta_get(cl_hw, sta_idx);
+
+               /* Fixed rate for single station */
+               if (!wrs_sta) {
+                       pr_err("[WRS] Invalid sta_idx [%u]\n", sta_idx);
+                       goto unlock;
+               }
+
+               cl_wrs_fixed_rate_set(cl_hw, wrs_db, wrs_sta, &wrs_sta->su_params, is_fixed_rate,
+                                     mode, bw, nss, mcs, gi);
+
+unlock:
+               cl_sta_unlock_bh(cl_hw);
+       } else {
+               /* Fixed rate for all connected station */
+               struct cl_sta *cl_sta;
+
+               cl_sta_lock_bh(cl_hw);
+
+               list_for_each_entry(cl_sta, &cl_hw->cl_sta_db.head, list) {
+                       wrs_sta = &cl_sta->wrs_sta;
+
+                       cl_wrs_fixed_rate_set(cl_hw, wrs_db, wrs_sta,
+                                             &wrs_sta->su_params, is_fixed_rate,
+                                             mode, bw, nss, mcs, gi);
+               }
+
+               cl_sta_unlock_bh(cl_hw);
+
+               /* Save fixed rate parameters for stations that will connect in the future */
+               wrs_db->is_fixed_rate = is_fixed_rate;
+
+               if (is_fixed_rate) {
+                       cl_hw->conf->ci_wrs_fixed_rate[WRS_FIXED_PARAM_MODE] = mode;
+                       cl_hw->conf->ci_wrs_fixed_rate[WRS_FIXED_PARAM_BW] = bw;
+                       cl_hw->conf->ci_wrs_fixed_rate[WRS_FIXED_PARAM_NSS] = nss;
+                       cl_hw->conf->ci_wrs_fixed_rate[WRS_FIXED_PARAM_MCS] = mcs;
+                       cl_hw->conf->ci_wrs_fixed_rate[WRS_FIXED_PARAM_GI] = gi;
+               }
+       }
+}
+
+static void cl_wrs_cli_converge_idle_param_set(struct cl_wrs_db *wrs_db, u32 param, u32 value)
+{
+       switch (param) {
+       case 0:
+               wrs_db->converge_idle_en = (bool)value;
+               break;
+       case 1:
+               wrs_db->converge_idle_interval_reset = value;
+               break;
+       case 2:
+               wrs_db->converge_idle_interval_rssi = value;
+               break;
+       case 3:
+               wrs_db->converge_idle_packet_th = value;
+               break;
+       default:
+               pr_warn("[WRS] Invalid parameter [%u]\n", param);
+               break;
+       }
+}
+
+static void cl_wrs_cli_converge_trfc_param_set(struct cl_wrs_db *wrs_db, u32 param, u32 value)
+{
+       switch (param) {
+       case 0:
+               wrs_db->converge_trfc_en = (bool)value;
+               break;
+       case 1:
+               wrs_db->converge_trfc_interval_static = value;
+               break;
+       case 2:
+               wrs_db->converge_trfc_interval_motion = value;
+               break;
+       default:
+               pr_warn("[WRS] Invalid parameter [%u]\n", param);
+               break;
+       }
+}
+
+static void cl_wrs_cli_immediate_drop_set(struct cl_wrs_db *wrs_db, bool enable,
+                                         u8 epr_factor, u32 max_in_row)
+{
+       wrs_db->immediate_drop_en = enable;
+       wrs_db->immediate_drop_epr_factor = epr_factor;
+       wrs_db->immediate_drop_max_in_row = max_in_row;
+
+       pr_debug("[WRS] Set immediate drop: %s, epr_factor = %u, max_in_row = %u\n",
+                enable ? "enable" : "disable", epr_factor, max_in_row);
+}
+
+static void cl_wrs_cli_step_max_min_set(struct cl_wrs_db *wrs_db, u16 step_dn, u16 step_same_up,
+                                       u16 time_th_min, u16 time_th_max_up, u16 time_th_max_down)
+{
+       wrs_db->step_down = step_dn;
+       wrs_db->step_up_same = step_same_up;
+       wrs_db->time_th_min = time_th_min;
+       wrs_db->time_th_max_up = time_th_max_up;
+       wrs_db->time_th_max_down = time_th_max_down;
+
+       pr_debug("------------------------------------------\n");
+       pr_debug("Set steps and up/down decision thresholds:\n");
+       pr_debug("------------------------------------------\n");
+       pr_debug("Step down decision    = [%u]\n", wrs_db->step_down);
+       pr_debug("Step same/up Decision = [%u]\n", wrs_db->step_up_same);
+       pr_debug("Min threshold         = [%u]\n", wrs_db->time_th_min);
+       pr_debug("Max threshold up      = [%u]\n", wrs_db->time_th_max_up);
+       pr_debug("Max threshold down    = [%u]\n", wrs_db->time_th_max_down);
+}
+
+static void cl_wrs_cli_down_up_thr_set(struct cl_hw *cl_hw, struct cl_wrs_db *wrs_db,
+                                      u8 sta_idx, u16 time_th_dn, u16 time_th_up_mcs,
+                                      u16 time_th_up_nss, u16 time_th_up_bw, u16 time_th_up_bf,
+                                      u16 time_th_up_gi)
+{
+       struct cl_wrs_sta *wrs_sta = NULL;
+       struct cl_wrs_params *wrs_params = NULL;
+       u16 rate_idx = 0;
+
+       cl_sta_lock_bh(cl_hw);
+       wrs_sta = cl_wrs_sta_get(cl_hw, sta_idx);
+
+       if (!wrs_sta) {
+               cl_sta_unlock_bh(cl_hw);
+               pr_err("[WRS] Invalid sta_idx [%u]\n", sta_idx);
+               return;
+       }
+
+       wrs_params = &wrs_sta->su_params;
+
+       for (rate_idx = 0; rate_idx < wrs_params->table_size; rate_idx++) {
+               wrs_params->table->rate_down.time_th = time_th_dn;
+               wrs_params->table->rate_up[WRS_TABLE_NODE_UP_MCS].time_th = time_th_up_mcs;
+               wrs_params->table->rate_up[WRS_TABLE_NODE_UP_BW].time_th = time_th_up_bw;
+               wrs_params->table->rate_up[WRS_TABLE_NODE_UP_NSS].time_th = time_th_up_nss;
+               wrs_params->table->rate_up[WRS_TABLE_NODE_UP_BF].time_th = time_th_up_bf;
+               wrs_params->table->rate_up[WRS_TABLE_NODE_UP_GI].time_th = time_th_up_gi;
+       }
+
+       cl_sta_unlock_bh(cl_hw);
+
+       pr_debug("Table thresholds - station [%u]\n", sta_idx);
+       pr_debug("------------------------------------------\n");
+       pr_debug("Down   = %u\n", time_th_dn);
+       pr_debug("Up mcs = %u\n", time_th_up_mcs);
+       pr_debug("Up nss = %u\n", time_th_up_nss);
+       pr_debug("Up bw  = %u\n", time_th_up_bw);
+       pr_debug("Up bf  = %u\n", time_th_up_bf);
+       pr_debug("Up gi  = %u\n", time_th_up_gi);
+}
+
+static void cl_wrs_cli_main_print(struct cl_sta *cl_sta, struct cl_wrs_sta *wrs_sta,
+                                 struct cl_wrs_params *wrs_params)
+{
+       struct cl_wrs_tx_params *tx_params = &wrs_params->tx_params;
+
+       pr_debug("\n");
+       pr_debug("--------------------------------------------\n");
+       pr_debug("WRS info for station %u - %pM\n", cl_sta->sta_idx, cl_sta->addr);
+       pr_debug("--------------------------------------------\n");
+       pr_debug("Settings      = [%s]\n", FIXED_RATE_STR(wrs_params->is_fixed_rate));
+       pr_debug("Converge mode = [%s]\n", WRS_CONVERGE_MODE_STR(wrs_params->converge_mode));
+       pr_debug("Synced        = [%s]\n", wrs_params->sync ? "True" : "False");
+       pr_debug("Mode          = [%s]\n", WRS_MODE_STR(tx_params->mode));
+
+       if (wrs_sta->mode == tx_params->mode)
+               pr_debug("Rate index    = [%u]\n", wrs_params->rate_idx);
+
+       pr_debug("Rate params   = [bw=%s, nss=%u, mcs=%u, gi=%s]\n",
+                WRS_BW_STR(tx_params->bw),
+                tx_params->nss,
+                tx_params->mcs,
+                WRS_GI_STR(tx_params->gi));
+}
+
+static void cl_wrs_cli_sta_db_print(struct cl_hw *cl_hw, struct cl_wrs_db *wrs_db,
+                                   u8 sta_idx, u32 print_type)
+{
+       struct cl_wrs_sta *wrs_sta = NULL;
+       struct cl_wrs_params *wrs_params = NULL;
+       struct cl_sta *cl_sta = NULL;
+
+       cl_sta_lock_bh(cl_hw);
+
+       list_for_each_entry(cl_sta, &cl_hw->cl_sta_db.head, list) {
+               wrs_sta = &cl_sta->wrs_sta;
+
+               if (sta_idx != WRS_ALL_STA && sta_idx != wrs_sta->sta_idx)
+                       continue;
+
+               wrs_params = &wrs_sta->su_params;
+
+               cl_wrs_cli_main_print(cl_sta, wrs_sta, wrs_params);
+
+               if (print_type & 0x1)
+                       cl_wrs_tables_print(cl_hw, wrs_params);
+
+               if (print_type & 0x2)
+                       cl_wrs_stats_decision_print(wrs_params);
+
+               if (print_type & 0x4)
+                       cl_wrs_stats_per_print(cl_hw, wrs_sta, wrs_params);
+       }
+
+       cl_sta_unlock_bh(cl_hw);
+
+       if (sta_idx == WRS_ALL_STA)
+               pr_debug("*** END OF WRS STATS ***\n");
+}
+
+static void cl_wrs_cli_sta_db_reset(struct cl_hw *cl_hw, struct cl_wrs_db *wrs_db,
+                                   u8 sta_idx, u32 reset_type)
+{
+       struct cl_wrs_sta *wrs_sta = NULL;
+       struct cl_wrs_params *wrs_params = NULL;
+       struct cl_sta *cl_sta = NULL;
+
+       cl_sta_lock_bh(cl_hw);
+
+       list_for_each_entry(cl_sta, &cl_hw->cl_sta_db.head, list) {
+               wrs_sta = &cl_sta->wrs_sta;
+
+               if (sta_idx != WRS_ALL_STA && sta_idx != wrs_sta->sta_idx)
+                       continue;
+
+               wrs_params = &wrs_sta->su_params;
+
+               if (reset_type & 0x1)
+                       cl_wrs_tables_reset(wrs_db, wrs_sta, wrs_params);
+
+               if (reset_type & 0x2)
+                       cl_wrs_stats_decision_reset(wrs_params);
+
+               if (reset_type & 0x4)
+                       cl_wrs_stats_per_reset(wrs_params);
+       }
+
+       cl_sta_unlock_bh(cl_hw);
+}
+
+static void cl_wrs_cli_sync_params_set(struct cl_wrs_db *wrs_db,
+                                      u16 sync_timeout, u8 sync_min_attempts)
+{
+       wrs_db->sync_timeout = sync_timeout;
+       wrs_db->sync_min_attempts = sync_min_attempts;
+       pr_debug("[WRS] sync_timeout = %u, sync_min_attempts = %u\n",
+                sync_timeout, sync_min_attempts);
+}
+
+static void cl_wrs_cli_min_frames_decision_set(struct cl_wrs_db *wrs_db, u32 min_frames)
+{
+       wrs_db->min_frames_for_decision = min_frames;
+       pr_debug("[WRS] min_frames_for_decision = %u\n", min_frames);
+}
+
+static void cl_wrs_cli_conservative_mode_set(struct cl_wrs_db *wrs_db,
+                                            bool conservative_mcs, bool conservative_nss)
+{
+       wrs_db->conservative_mcs_noisy_env = conservative_mcs;
+       wrs_db->conservative_nss_noisy_env = conservative_nss;
+
+       pr_debug("[WRS] Conservative mode - mcs = %s, nss = %s\n",
+                conservative_mcs ? "true" : "false",
+                conservative_nss ? "true" : "false");
+}
+
+static void cl_wrs_cli_quick_up_set(struct cl_wrs_db *wrs_db, bool enable, u8 ba_thr, u16 interval)
+{
+       wrs_db->quick_up_en = enable;
+       wrs_db->quick_up_ba_thr = ba_thr;
+       wrs_db->quick_up_interval = msecs_round(interval);
+
+       pr_debug("[WRS] Quick up: enable = %s, ba_thr = %u, interval = %u\n",
+                wrs_db->quick_up_en ? "true" : "false",
+                wrs_db->quick_up_ba_thr,
+                wrs_db->quick_up_interval);
+}
+
+static void cl_wrs_cli_quick_down_set(struct cl_wrs_db *wrs_db, bool enable,
+                                     u8 epr_factor, u8 agg_thr, u16 pkt_thr)
+{
+       wrs_db->quick_down_en = enable;
+       wrs_db->quick_down_epr_factor = epr_factor;
+       wrs_db->quick_down_agg_thr = agg_thr;
+       wrs_db->quick_down_pkt_thr = pkt_thr;
+
+       pr_debug("[WRS] Quick down: enable = %s, epr_factor = %u, agg_thr = %u, pkt_thr = %u\n",
+                enable ? "true" : "false", epr_factor, agg_thr, pkt_thr);
+}
+
+static void cl_wrs_cli_ba_not_rcv_set(struct cl_wrs_db *wrs_db, bool collision_filter,
+                                     bool force, u32 time_since_sync)
+{
+       wrs_db->ba_not_rcv_collision_filter = collision_filter;
+       wrs_db->ba_not_rcv_force = force;
+       wrs_db->ba_not_rcv_time_since_sync = msecs_round(time_since_sync);
+
+       pr_debug("[WRS] BA not received: collision_filter = %s, force = %s, time_since_sync = %u\n",
+                wrs_db->ba_not_rcv_collision_filter ? "true" : "false",
+                wrs_db->ba_not_rcv_force ? "true" : "false",
+                wrs_db->ba_not_rcv_time_since_sync);
+}
+
+static int cl_wrs_cli_help(struct cl_hw *cl_hw)
+{
+       char *buf = kzalloc(PAGE_SIZE, GFP_KERNEL);
+       int err = 0;
+       int len = 0;
+
+       if (!buf)
+               return -ENOMEM;
+
+       len += snprintf(buf, PAGE_SIZE,
+                       "wrs usage\n"
+                       "-a : Print station list\n"
+                       "-b : Set maintenance interval [ms]\n"
+                       "-c : Print configuration\n"
+                       "-d : Set debug level [0-off, 1-error, 2-warning, "
+                               "3-trace, 4-info]\n"
+                       "-f : Set fixed rate [sta_idx].[0-auto,1-fixed "
+                               "fallback en,2-fixed fallback dis].[mode]."
+                               "[bw].[nss].[mcs].[gi]\n"
+                       "-g : Set converge idle parameters [0-en, "
+                               "1-interval_reset, 2-interval_rssi, "
+                               "3-packet_th].[value]\n"
+                       "-h : Set converge trfc parameters [0-en, "
+                               "1-interval_static, 2-interval_motion]."
+                               "[value]\n"
+                       "-k : Set EPR factor [factor]\n"
+                       "-l : Set immediate drop [0-disable/1-enable]."
+                               "[per factor].[max in row]\n"
+                       "-m : Print rssi protect debug [sta_idx]\n"
+                       "-n : Set rssi protect parameters [enable 0/1]."
+                               "[mode 0-rssi/1-neighbor].[rssi up thr]."
+                               "[rssi down th]\n"
+                       "-o : Set step and time thresholds [step down]."
+                               "[step same up].[time min].[time max up]."
+                               "[time max down]\n"
+                       "-p : Set down and up time thresholds [sta_idx]."
+                               "[down].[up mcs].[up nss].[up bw].[up bf]."
+                               "[up gi]\n"
+                       "-q : Reset and print station data [sta_idx].[op:"
+                               " 1-weights, 2-decisions, 4-per, 7-all)]\n"
+                       "-r : Reset station data [sta_idx].[op: 1-weights, "
+                               "2-decisions, 4-per, 7-all)]\n"
+                       "-s : Print station data [sta_idx].[op: 1-weights, "
+                               "2-decisions, 4-per, 7-all)]\n"
+                       "-t : Set sync parameters [timeout].[min attempts]\n"
+                       "-u : Set minimum frames for decision [min frames]\n"
+                       "-v : Set conservative mode [mcs-0/1].[nss-0/1]\n"
+                       "-w : Set quick up [enable].[ba_thr].[interval]\n"
+                       "-x : Set quick down [enable].[epr factor]."
+                               "[agg thr][pkt thr]\n"
+                       "-y : Set BA not received [collision filter][force]."
+                               "[time since sync]\n");
+
+       err = cl_vendor_reply(cl_hw, buf, strlen(buf));
+       kfree(buf);
+
+       return err;
+}
+
+int cl_wrs_cli(struct cl_hw *cl_hw, struct cl_vif *cl_vif, struct cli_params *cli_params)
+{
+       struct cl_wrs_db *wrs_db = &cl_hw->wrs_db;
+       u32 expected_params = 0;
+       bool sta_list_print = false;
+       bool interval_set = false;
+       bool config_print = false;
+       bool set_debug_level = false;
+       bool fixed_rate = false;
+       bool converge_idle_set = false;
+       bool converge_trfc_set = false;
+       bool epr_factor_set = false;
+       bool immediate_drop_set = false;
+       bool rssi_prot_print = false;
+       bool rssi_protect_set = false;
+       bool set_step_max_min_th = false;
+       bool set_up_dn_th = false;
+       bool print_reset_sta_db = false;
+       bool reset_sta_db = false;
+       bool print_sta_db = false;
+       bool sync_params_set = false;
+       bool min_frames_set = false;
+       bool conservative_mode_set = false;
+       bool quick_up_set = false;
+       bool quick_down_set = false;
+       bool ba_not_rcv_set = false;
+
+       switch (cli_params->option) {
+       case 'a':
+               sta_list_print = true;
+               expected_params = 0;
+               break;
+       case 'b':
+               interval_set = true;
+               expected_params = 1;
+               break;
+       case 'c':
+               config_print = true;
+               expected_params = 0;
+               break;
+       case 'd':
+               set_debug_level = true;
+               expected_params = 1;
+               break;
+       case 'f':
+               fixed_rate = true;
+               expected_params = 7;
+               break;
+       case 'g':
+               converge_idle_set = true;
+               expected_params = 2;
+               break;
+       case 'h':
+               converge_trfc_set = true;
+               expected_params = 2;
+               break;
+               break;
+       case 'k':
+               epr_factor_set = true;
+               expected_params = 1;
+               break;
+       case 'l':
+               immediate_drop_set = true;
+               expected_params = 3;
+               break;
+       case 'm':
+               rssi_prot_print = true;
+               expected_params = 1;
+               break;
+       case 'n':
+               rssi_protect_set = true;
+               expected_params = 3;
+               break;
+       case 'o':
+               set_step_max_min_th = true;
+               expected_params = 5;
+               break;
+       case 'p':
+               set_up_dn_th = true;
+               expected_params = 7;
+               break;
+       case 'q':
+               print_reset_sta_db = true;
+               expected_params = 2;
+               break;
+       case 'r':
+               reset_sta_db = true;
+               expected_params = 2;
+               break;
+       case 's':
+               print_sta_db = true;
+               expected_params = 2;
+               break;
+       case 't':
+               sync_params_set = true;
+               expected_params = 2;
+               break;
+       case 'u':
+               min_frames_set = true;
+               expected_params = 1;
+               break;
+       case 'v':
+               conservative_mode_set = true;
+               expected_params = 2;
+               break;
+       case 'w':
+               quick_up_set = true;
+               expected_params = 3;
+               break;
+       case 'x':
+               quick_down_set = true;
+               expected_params = 4;
+               break;
+       case 'y':
+               ba_not_rcv_set = true;
+               expected_params = 3;
+               break;
+               break;
+       case '?':
+               return cl_wrs_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 (sta_list_print) {
+               cl_wrs_sta_print_list(cl_hw, wrs_db);
+               return 0;
+       }
+
+       if (interval_set) {
+               u32 interval = (u32)cli_params->params[0];
+
+               cl_wrs_cli_interval_set(wrs_db, interval);
+               return 0;
+       }
+
+       if (config_print) {
+               cl_wrs_cli_config_print(cl_hw);
+               return 0;
+       }
+
+       if (set_debug_level) {
+               u32 debug_level = (u32)cli_params->params[0];
+
+               cl_wrs_cli_dbg_level_set(wrs_db, debug_level);
+               return 0;
+       }
+
+       if (fixed_rate) {
+               u8 sta_idx  = (u8)cli_params->params[0];
+               u8 is_fixed_rate = (u8)cli_params->params[1];
+               u8 mode = (u8)cli_params->params[2];
+               u8 bw = (u8)cli_params->params[3];
+               u8 nss = (u8)cli_params->params[4];
+               u8 mcs = (u8)cli_params->params[5];
+               u8 gi = (u8)cli_params->params[6];
+
+               cl_wrs_cli_fixed_rate_set(cl_hw, wrs_db, sta_idx, is_fixed_rate,
+                                         mode, bw, nss, mcs, gi);
+               return 0;
+       }
+
+       if (converge_idle_set) {
+               u32 param = (u32)cli_params->params[0];
+               u32 value = (u32)cli_params->params[1];
+
+               cl_wrs_cli_converge_idle_param_set(wrs_db, param, value);
+               return 0;
+       }
+
+       if (converge_trfc_set) {
+               u32 param = (u32)cli_params->params[0];
+               u32 value = (u32)cli_params->params[1];
+
+               cl_wrs_cli_converge_trfc_param_set(wrs_db, param, value);
+               return 0;
+       }
+
+       if (epr_factor_set) {
+               wrs_db->epr_factor = (u8)cli_params->params[0];
+               pr_debug("[WRS] epr_factor = %u\n", wrs_db->epr_factor);
+               return 0;
+       }
+
+       if (immediate_drop_set) {
+               bool is_en = (bool)cli_params->params[0];
+               u8 epr_factor = (u8)cli_params->params[1];
+               u32 max_in_row = (u32)cli_params->params[2];
+
+               cl_wrs_cli_immediate_drop_set(wrs_db, is_en, epr_factor, max_in_row);
+               return 0;
+       }
+
+       if (rssi_prot_print) {
+               u8 sta_idx = (u8)cli_params->params[0];
+               struct cl_wrs_sta *wrs_sta;
+
+               cl_sta_lock_bh(cl_hw);
+               wrs_sta = cl_wrs_sta_get(cl_hw, sta_idx);
+
+               if (wrs_sta)
+                       cl_wrs_rssi_prot_dbg(cl_hw, wrs_db, wrs_sta);
+               else
+                       pr_err("[WRS] Invalid sta_idx [%u]\n", sta_idx);
+
+               cl_sta_unlock_bh(cl_hw);
+
+               return 0;
+       }
+
+       if (rssi_protect_set) {
+               bool enable = (bool)cli_params->params[0];
+               bool mode = (bool)cli_params->params[1];
+               s32 rssi_up_th = cli_params->params[2];
+               s32 rssi_dn_th = cli_params->params[3];
+
+               cl_wrs_rssi_prot_config(cl_hw, wrs_db, enable, mode, rssi_up_th, rssi_dn_th);
+               return 0;
+       }
+
+       if (set_step_max_min_th) {
+               u16 step_dn = (u16)cli_params->params[0];
+               u16 step_same_up = (u16)cli_params->params[1];
+               u16 time_th_min = (u16)cli_params->params[2];
+               u16 time_th_max_up = (u16)cli_params->params[3];
+               u16 time_th_max_down = (u16)cli_params->params[4];
+
+               cl_wrs_cli_step_max_min_set(wrs_db, step_dn, step_same_up,
+                                           time_th_min, time_th_max_up, time_th_max_down);
+               return 0;
+       }
+
+       if (set_up_dn_th) {
+               u8 sta_idx = (u8)cli_params->params[0];
+               u16 time_th_dn = (u16)cli_params->params[1];
+               u16 time_th_up_mcs = (u16)cli_params->params[2];
+               u16 time_th_up_nss = (u16)cli_params->params[3];
+               u16 time_th_up_bw = (u16)cli_params->params[4];
+               u16 time_th_up_bf = (u16)cli_params->params[5];
+               u16 time_th_up_gi = (u16)cli_params->params[6];
+
+               cl_wrs_cli_down_up_thr_set(cl_hw, wrs_db, sta_idx, time_th_dn,
+                                          time_th_up_mcs, time_th_up_nss, time_th_up_bw,
+                                          time_th_up_bf, time_th_up_gi);
+               return 0;
+       }
+
+       if (print_reset_sta_db) {
+               u8 sta_idx = (u8)cli_params->params[0];
+               u32 print_type = (u32)cli_params->params[1];
+
+               cl_wrs_cli_sta_db_print(cl_hw, wrs_db, sta_idx, print_type);
+               cl_wrs_cli_sta_db_reset(cl_hw, wrs_db, sta_idx, print_type);
+               return 0;
+       }
+
+       if (reset_sta_db) {
+               u8 sta_idx = (u8)cli_params->params[0];
+               u32 reset_type = (u32)cli_params->params[1];
+
+               cl_wrs_cli_sta_db_reset(cl_hw, wrs_db, sta_idx, reset_type);
+               return 0;
+       }
+
+       if (print_sta_db) {
+               u8 sta_idx = (u8)cli_params->params[0];
+               u32 print_type = (u32)cli_params->params[1];
+
+               cl_wrs_cli_sta_db_print(cl_hw, wrs_db, sta_idx, print_type);
+               return 0;
+       }
+
+       if (sync_params_set) {
+               u16 sync_timeout = (u16)cli_params->params[0];
+               u8 sync_min_attempts = (u16)cli_params->params[1];
+
+               cl_wrs_cli_sync_params_set(wrs_db, sync_timeout, sync_min_attempts);
+               return 0;
+       }
+
+       if (min_frames_set) {
+               u32 min_frames = (u32)cli_params->params[0];
+
+               cl_wrs_cli_min_frames_decision_set(wrs_db, min_frames);
+               return 0;
+       }
+
+       if (conservative_mode_set) {
+               u32 conservative_mcs = (u32)cli_params->params[0];
+               u32 conservative_nss = (u32)cli_params->params[1];
+
+               cl_wrs_cli_conservative_mode_set(wrs_db, conservative_mcs, conservative_nss);
+               return 0;
+       }
+
+       if (quick_up_set) {
+               bool enable = (bool)cli_params->params[0];
+               u8 ba_thr = (u8)cli_params->params[1];
+               u16 interval = (u16)cli_params->params[2];
+
+               cl_wrs_cli_quick_up_set(wrs_db, enable, ba_thr, interval);
+               return 0;
+       }
+
+       if (quick_down_set) {
+               bool enable = (bool)cli_params->params[0];
+               u8 epr_factor = (u8)cli_params->params[1];
+               u8 agg_thr = (u8)cli_params->params[2];
+               u16 pkt_thr = (u16)cli_params->params[3];
+
+               cl_wrs_cli_quick_down_set(wrs_db, enable, epr_factor, agg_thr, pkt_thr);
+               return 0;
+       }
+
+       if (ba_not_rcv_set) {
+               bool collision_filter = (bool)cli_params->params[0];
+               bool force = (bool)cli_params->params[1];
+               u32 time_since_sync = (u32)cli_params->params[2];
+
+               cl_wrs_cli_ba_not_rcv_set(wrs_db, collision_filter, force, time_since_sync);
+               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.
________________________________


^ permalink raw reply related	[flat|nested] 262+ messages in thread

* [RFC v1 246/256] cl8k: add wrs/wrs_cli.h
  2021-06-17 15:58 [RFC v1 000/256] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (244 preceding siblings ...)
  2021-06-17 16:02 ` [RFC v1 245/256] cl8k: add wrs/wrs_cli.c viktor.barna
@ 2021-06-17 16:02 ` viktor.barna
  2021-06-17 16:02 ` [RFC v1 247/256] cl8k: add wrs/wrs_db.h viktor.barna
                   ` (11 subsequent siblings)
  257 siblings, 0 replies; 262+ messages in thread
From: viktor.barna @ 2021-06-17 16:02 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Oleksandr Savchenko, Shay Bar, Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

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

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 drivers/net/wireless/celeno/cl8k/wrs/wrs_cli.h | 12 ++++++++++++
 1 file changed, 12 insertions(+)
 create mode 100644 drivers/net/wireless/celeno/cl8k/wrs/wrs_cli.h

diff --git a/drivers/net/wireless/celeno/cl8k/wrs/wrs_cli.h b/drivers/net/wireless/celeno/cl8k/wrs/wrs_cli.h
new file mode 100644
index 000000000000..7c7cbd9177fa
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/wrs/wrs_cli.h
@@ -0,0 +1,12 @@
+/* SPDX-License-Identifier: MIT */
+/* Copyright(c) 2019-2021, Celeno Communications Ltd. */
+
+#ifndef CL_WRS_CLI_H
+#define CL_WRS_CLI_H
+
+#include "wrs/wrs_db.h"
+#include "hw.h"
+
+int cl_wrs_cli(struct cl_hw *cl_hw, struct cl_vif *cl_vif, struct cli_params *cli_params);
+
+#endif /* CL_WRS_CLI_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.
________________________________


^ permalink raw reply related	[flat|nested] 262+ messages in thread

* [RFC v1 247/256] cl8k: add wrs/wrs_db.h
  2021-06-17 15:58 [RFC v1 000/256] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (245 preceding siblings ...)
  2021-06-17 16:02 ` [RFC v1 246/256] cl8k: add wrs/wrs_cli.h viktor.barna
@ 2021-06-17 16:02 ` viktor.barna
  2021-06-17 16:02 ` [RFC v1 248/256] cl8k: add wrs/wrs_rssi.c viktor.barna
                   ` (10 subsequent siblings)
  257 siblings, 0 replies; 262+ messages in thread
From: viktor.barna @ 2021-06-17 16:02 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Oleksandr Savchenko, Shay Bar, Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

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

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 drivers/net/wireless/celeno/cl8k/wrs/wrs_db.h | 386 ++++++++++++++++++
 1 file changed, 386 insertions(+)
 create mode 100644 drivers/net/wireless/celeno/cl8k/wrs/wrs_db.h

diff --git a/drivers/net/wireless/celeno/cl8k/wrs/wrs_db.h b/drivers/net/wireless/celeno/cl8k/wrs/wrs_db.h
new file mode 100644
index 000000000000..2eefa0abaf8d
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/wrs/wrs_db.h
@@ -0,0 +1,386 @@
+/* SPDX-License-Identifier: MIT */
+/* Copyright(c) 2019-2021, Celeno Communications Ltd. */
+
+#ifndef CL_WRS_DB_H
+#define CL_WRS_DB_H
+
+#include "debug.h"
+#include "utils/timer.h"
+#include "def.h"
+#include "wrs/wrs_tables.h"
+
+#define WRS_MAINTENANCE_PERIOD_MS         40
+#define WRS_DATA_RATE_FACTOR              10
+#define WRS_RSSI_PROTECT_UP_THR           10
+#define WRS_RSSI_PROTECT_DN_THR           10
+#define WRS_MIN_FRAMES_FOR_DECISION       15
+#define WRS_EPR_FACTOR                    105
+#define WRS_CONVERGE_IDLE_PACKET_TH       5
+#define WRS_CONVERGE_IDLE_INTERVAL_RESET  6000  /* 6 sec */
+#define WRS_CONVERGE_IDLE_INTERVAL_RSSI   2000  /* 2 sec */
+#define WRS_CONVERGE_TRFC_INTERVAL_STATIC 30000 /* 30 sec */
+#define WRS_CONVERGE_TRFC_INTERVAL_MOTION 1000  /* 1 sec */
+#define WRS_IMMEDIATE_DROP_EPR_FACTOR     70    /* 70% */
+#define WRS_IMMEDIATE_DROP_MAX_IN_ROW     U32_MAX
+#define WRS_SYNC_MIN_ATTEMPTS             4
+#define WRS_SYNC_TIMEOUT                  1000  /* 1 sec */
+#define WRS_QUICK_UP_BA_THR               5
+#define WRS_QUICK_UP_INTERVAL_MS          1000
+#define WRS_QUICK_DOWN_EPR_FACTOR         85
+#define WRS_QUICK_DOWN_AGG_THR            3
+#define WRS_QUICK_DOWN_PKT_THR            60
+#define WRS_RSSI_PROTECT_SHIFT            7
+#define WRS_RSSI_PROTECT_BUF_SZ_OLD       BIT(WRS_RSSI_PROTECT_SHIFT) /* 2 ^ 7 = 128 */
+#define WRS_RSSI_PROTECT_BUF_SZ_NEW       3
+#define WRS_BA_NOT_RCV_TIME_SINCE_SYNC    1000
+#define WRS_CCA_PERIOD_MS                 1000
+#define WRS_CCA_PRIMARY_SHIFT             7
+#define WRS_CCA_PRIMARY_FACTOR            160 /* 160 / 2^7 = 1.25 = 25% */
+
+enum cl_wrs_rssi_prot_mode {
+       WRS_RSSI_PROT_MODE_RSSI,     /* Up/down based on rssi */
+       WRS_RSSI_PROT_MODE_NEIGHBOR, /* Up/down based on neighbors */
+
+       WRS_RSSI_PROTECT_MODE_MAX
+};
+
+enum cl_wrs_fixed_rate {
+       WRS_AUTO_RATE,
+       WRS_FIXED_FALLBACK_EN,
+       WRS_FIXED_FALLBACK_DIS,
+
+       WRS_FIXED_RATE_MAX
+};
+
+enum cl_wrs_fixed_param {
+       WRS_FIXED_PARAM_MODE,
+       WRS_FIXED_PARAM_BW,
+       WRS_FIXED_PARAM_NSS,
+       WRS_FIXED_PARAM_MCS,
+       WRS_FIXED_PARAM_GI,
+
+       WRS_FIXED_PARAM_MAX
+};
+
+#define FIXED_RATE_STR(x) \
+       (((x) == WRS_AUTO_RATE) ? "auto rate" : \
+       (((x) == WRS_FIXED_FALLBACK_EN) ? "fixed rate (fallbacks enabled)" : \
+       "fixed rate (fallbacks disabled)"))
+
+enum cl_wrs_decision {
+       WRS_DECISION_NONE,
+       WRS_DECISION_SAME,
+       WRS_DECISION_UP,
+       WRS_DECISION_UP_QUICK,
+       WRS_DECISION_UP_RSSI,
+       WRS_DECISION_UP_MCS1,
+       WRS_DECISION_DOWN,
+       WRS_DECISION_DOWN_RSSI,
+       WRS_DECISION_DOWN_IMMEDIATE,
+       WRS_DECISION_DOWN_QUICK,
+       WRS_DECISION_DOWN_NO_SYNC,
+       WRS_DECISION_RSSI_MGMT,
+
+       WRS_DECISION_MAX,
+};
+
+enum cl_wrs_mcs {
+       WRS_MCS_0,
+       WRS_MCS_1,
+       WRS_MCS_2,
+       WRS_MCS_3,
+       WRS_MCS_4,
+       WRS_MCS_5,
+       WRS_MCS_6,
+       WRS_MCS_7,
+       WRS_MCS_8,
+       WRS_MCS_9,
+       WRS_MCS_10,
+       WRS_MCS_11,
+       WRS_MCS_MAX,
+};
+
+#define WRS_MCS_MAX_CCK  WRS_MCS_4
+#define WRS_MCS_MAX_OFDM WRS_MCS_8
+#define WRS_MCS_MAX_HT   WRS_MCS_8
+#define WRS_MCS_MAX_VHT  WRS_MCS_10
+#define WRS_MCS_MAX_HE   WRS_MCS_MAX
+
+enum cl_wrs_ss {
+       WRS_SS_1,
+       WRS_SS_2,
+       WRS_SS_3,
+       WRS_SS_4,
+
+       WRS_SS_MAX
+};
+
+enum cl_wrs_gi {
+       WRS_GI_LONG,
+       WRS_GI_SHORT,
+       WRS_GI_VSHORT,
+
+       WRS_GI_MAX
+};
+
+#define WRS_GI_MAX_HT  WRS_GI_VSHORT
+#define WRS_GI_MAX_VHT WRS_GI_VSHORT
+#define WRS_GI_MAX_HE  WRS_GI_MAX
+
+enum cl_wrs_ltf {
+       LTF_X1,
+       LTF_X2,
+       LTF_X4,
+       LTF_MAX
+};
+
+enum cl_wrs_converge_mode {
+       WRS_CONVERGE_MODE_RESET,
+       WRS_CONVERGE_MODE_RSSI,
+
+       WRS_CONVERGE_MODE_MAX,
+};
+
+enum cl_wrs_mode {
+       WRS_MODE_CCK,
+       WRS_MODE_OFDM,
+       WRS_MODE_HT,
+       WRS_MODE_VHT,
+       WRS_MODE_HE,
+
+       WRS_MODE_MAX,
+};
+
+#define wrs_pr(wrs_db, level, ...) \
+       do { \
+               if ((level) <= (wrs_db)->debug_level) \
+                       pr_debug(__VA_ARGS__); \
+       } while (0)
+
+#define wrs_pr_verbose(wrs_db, ...) wrs_pr(wrs_db, DBG_LVL_VERBOSE, ##__VA_ARGS__)
+#define wrs_pr_err(wrs_db, ...)     wrs_pr(wrs_db, DBG_LVL_ERROR, ##__VA_ARGS__)
+#define wrs_pr_warn(wrs_db, ...)    wrs_pr(wrs_db, DBG_LVL_WARNING, ##__VA_ARGS__)
+#define wrs_pr_trace(wrs_db, ...)   wrs_pr(wrs_db, DBG_LVL_TRACE, ##__VA_ARGS__)
+#define wrs_pr_info(wrs_db, ...)    wrs_pr(wrs_db, DBG_LVL_INFO, ##__VA_ARGS__)
+
+/* m MUST be power of 2 ! */
+#define WRS_INC_POW2(c, m) (((c) + 1) & ((m) - 1))
+
+#define WRS_INC(c, m) \
+       do { \
+               (c)++; \
+               if ((c) == (m)) \
+                       (c) = 0; \
+       } while (0)
+
+#define WRS_IS_DECISION_UP(decision) \
+       (((decision) >= WRS_DECISION_UP) && ((decision) <= WRS_DECISION_UP_MCS1))
+#define WRS_IS_DECISION_DOWN(decision) \
+       (((decision) >= WRS_DECISION_DOWN) && ((decision) <= WRS_DECISION_DOWN_NO_SYNC))
+
+#define WRS_DECISION_STR(decision) (                                   \
+       (decision) == WRS_DECISION_NONE           ? "NONE"           : \
+       (decision) == WRS_DECISION_SAME           ? "SAME"           : \
+       (decision) == WRS_DECISION_UP             ? "UP"             : \
+       (decision) == WRS_DECISION_UP_QUICK       ? "UP QUICK"       : \
+       (decision) == WRS_DECISION_UP_RSSI        ? "UP RSSI"        : \
+       (decision) == WRS_DECISION_UP_MCS1        ? "UP MCS1"        : \
+       (decision) == WRS_DECISION_DOWN           ? "DOWN"           : \
+       (decision) == WRS_DECISION_DOWN_RSSI      ? "DOWN RSSI"      : \
+       (decision) == WRS_DECISION_DOWN_IMMEDIATE ? "DOWN IMMEDIATE" : \
+       (decision) == WRS_DECISION_DOWN_QUICK     ? "DOWN QUICK"     : \
+       (decision) == WRS_DECISION_DOWN_NO_SYNC   ? "DOWN NO_SYNC"   : \
+       (decision) == WRS_DECISION_RSSI_MGMT      ? "RSSI MGMT"      : \
+       "ERROR")
+
+#define WRS_MODE_STR(mode) (               \
+       (mode) == WRS_MODE_CCK  ? "CCK"  : \
+       (mode) == WRS_MODE_OFDM ? "OFDM" : \
+       (mode) == WRS_MODE_HT   ? "HT"   : \
+       (mode) == WRS_MODE_VHT  ? "VHT"  : \
+       (mode) == WRS_MODE_HE   ? "HE"   : \
+       "ERR")
+
+#define WRS_CONVERGE_MODE_STR(mode) \
+       ((mode) == WRS_CONVERGE_MODE_RESET ? "RESET" : "RSSI")
+
+#define WRS_BW_STR(bw) (                  \
+       (bw) == CHNL_BW_20  ? "20"  : \
+       (bw) == CHNL_BW_40  ? "40"  : \
+       (bw) == CHNL_BW_80  ? "80"  : \
+       (bw) == CHNL_BW_160 ? "160" : \
+       "ERR")
+
+#define WRS_GI_STR(gi) (                       \
+       (gi) == WRS_GI_LONG   ? "Long"       : \
+       (gi) == WRS_GI_SHORT  ? "Short"      : \
+       (gi) == WRS_GI_VSHORT ? "VeryShort" :  \
+       "ERROR")
+
+struct cl_wrs_tx_cntrs {
+       u64 epr_acc;
+       u32 total;
+       u32 fail;
+       u32 ba_not_rcv;
+       u32 ba_not_rcv_consecutive;
+};
+
+struct cl_wrs_tx_params {
+       u16 mode        : 3, /* Mode - 0 = CCK, 1 = OFDM, 2 = HT, 3 = VHT, 4 = HE. */
+           gi          : 2, /* GI - O = Long, 1 = Short, 2 = Very short. */
+           bw          : 2, /* Bandwidth - 0 = 20M, 1 = 40M, 2 = 80M, 3 = 160M. */
+           nss         : 3, /* Spatial Streams - 0 = 1SS, 1 = 2SS, .. 7 = 8SS. */
+           mcs         : 4, /* MCS - CCK (0 - 3), OFDM/HT (0 - 7), VHT (0 - 9), HE (0 - 11). */
+           fallback_en : 1,
+           is_fixed    : 1;
+};
+
+struct cl_wrs_logger {
+       unsigned long timestamp;
+       u16 rate_idx;
+       u32 success;
+       u32 fail;
+       u32 ba_not_rcv;
+       u16 down_rate_idx;
+       u16 up_rate_idx;
+       u16 curr_epr;
+       u16 down_epr;
+       u16 down_epr_factorized;
+       u16 penalty;
+       u16 up_time;
+       enum cl_wrs_decision decision;
+       u16 new_rate_idx;
+};
+
+struct cl_wrs_per_stats {
+       struct list_head list;
+       u8 mcs;
+       u8 bw;
+       u8 nss;
+       u8 gi;
+       u32 frames_total;
+       u32 frames_failed;
+       u64 epr_acc;
+};
+
+struct cl_wrs_rssi_prot_db {
+       s8 samples_old[WRS_RSSI_PROTECT_BUF_SZ_OLD];
+       s8 samples_new[WRS_RSSI_PROTECT_BUF_SZ_NEW];
+       u8 curr_idx_old;
+       u8 curr_idx_new;
+       s32 sum;
+};
+
+struct cl_wrs_params {
+       u8 is_fixed_rate  : 2,
+          quick_up_check : 1,
+          rsv            : 5;
+       u32 up_same_time_cnt;
+       u32 down_time_cnt;
+       enum cl_wrs_converge_mode converge_mode;
+       u32 converge_time_idle;
+       u32 converge_time_trfc;
+       u16 data_rate;
+       u16 rate_idx;
+       struct cl_wrs_table *table;
+       u16 table_size;
+       u16 penalty_decision_dn;
+       struct cl_wrs_tx_params tx_params;
+       enum cl_wrs_decision last_decision;
+       u32 decision_cnt[WRS_DECISION_MAX];
+       struct list_head list_rates;
+       u32 frames_total;
+       u32 fail_total;
+       u32 ba_not_rcv_total;
+       u64 epr_acc;
+       bool calc_ba_not_rcv;
+       bool sync;
+       unsigned long sync_timestamp;
+       unsigned long no_sync_timestamp;
+       u32 immediate_drop_cntr;
+       u32 immediate_drop_ignore;
+};
+
+struct cl_wrs_sta {
+       u8 sta_idx;
+       bool smps_enable;
+       u8 assoc_bw;
+       u8 gi_cap[CHNL_BW_MAX];
+       u64 supported_rates[CHNL_BW_MAX];
+       enum cl_wrs_mode mode;
+       struct cl_wrs_rate max_rate_cap;
+       struct cl_wrs_rssi_prot_db rssi_prot_db;
+       struct cl_wrs_params su_params;
+};
+
+struct cl_wrs_db {
+       /* General */
+       spinlock_t lock;
+       enum cl_dbg_level debug_level;
+       /* Timer */
+       struct cl_timer timer_maintenance;
+       u32 interval;
+       /* Fixed rate */
+       u8 is_fixed_rate;
+       /* Conservative initial rate */
+       bool conservative_mcs_noisy_env;
+       bool conservative_nss_noisy_env;
+       /* Immediate drop */
+       bool immediate_drop_en;
+       u8 immediate_drop_epr_factor;
+       u32 immediate_drop_max_in_row;
+       /* Converge idle */
+       bool converge_idle_en;
+       u32 converge_idle_interval_reset;
+       u32 converge_idle_interval_rssi;
+       u32 converge_idle_packet_th;
+       /* Converge traffic */
+       bool converge_trfc_en;
+       u32 converge_trfc_interval_static;
+       u32 converge_trfc_interval_motion;
+       /* Supported rates */
+       u8 mode;
+       u64 ap_supported_rates[CHNL_BW_MAX]; /* Bit array for each bw */
+       struct cl_wrs_rate max_cap;
+       /* RSSI protect */
+       bool rssi_protect_en;
+       u8 rssi_protect_mode;
+       s8 rssi_protect_up_thr;
+       s8 rssi_protect_dn_thr;
+       /* Time + step thresholds */
+       u16 time_th_min;
+       u16 time_th_max_up;
+       u16 time_th_max_down;
+       u16 step_down;
+       u16 step_up_same;
+       /* Quick up */
+       bool quick_up_en;
+       u8 quick_up_ba_thr;
+       u16 quick_up_interval;
+       /* Quick down */
+       bool quick_down_en;
+       u8 quick_down_epr_factor;
+       u8 quick_down_agg_thr;
+       u16 quick_down_pkt_thr;
+       /* BA not received */
+       bool ba_not_rcv_collision_filter;
+       bool ba_not_rcv_force;
+       u32 ba_not_rcv_time_since_sync;
+       /* Sync */
+       u16 sync_timeout;
+       u8 sync_min_attempts;
+       /* CCA counters */
+       unsigned long cca_timestamp;
+       u32 cca_primary;
+       u32 cca_sec80;
+       u32 cca_sec40;
+       u32 cca_sec20;
+       bool adjacent_interference20;
+       bool adjacent_interference40;
+       bool adjacent_interference80;
+       /* All the rest */
+       u32 min_frames_for_decision;
+       u8 epr_factor;
+};
+
+#endif /* CL_WRS_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.
________________________________


^ permalink raw reply related	[flat|nested] 262+ messages in thread

* [RFC v1 248/256] cl8k: add wrs/wrs_rssi.c
  2021-06-17 15:58 [RFC v1 000/256] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (246 preceding siblings ...)
  2021-06-17 16:02 ` [RFC v1 247/256] cl8k: add wrs/wrs_db.h viktor.barna
@ 2021-06-17 16:02 ` viktor.barna
  2021-06-17 16:02 ` [RFC v1 249/256] cl8k: add wrs/wrs_rssi.h viktor.barna
                   ` (9 subsequent siblings)
  257 siblings, 0 replies; 262+ messages in thread
From: viktor.barna @ 2021-06-17 16:02 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Oleksandr Savchenko, Shay Bar, Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

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

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 .../net/wireless/celeno/cl8k/wrs/wrs_rssi.c   | 444 ++++++++++++++++++
 1 file changed, 444 insertions(+)
 create mode 100644 drivers/net/wireless/celeno/cl8k/wrs/wrs_rssi.c

diff --git a/drivers/net/wireless/celeno/cl8k/wrs/wrs_rssi.c b/drivers/net/wireless/celeno/cl8k/wrs/wrs_rssi.c
new file mode 100644
index 000000000000..9f4e691c81db
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/wrs/wrs_rssi.c
@@ -0,0 +1,444 @@
+// SPDX-License-Identifier: MIT
+/* Copyright(c) 2019-2021, Celeno Communications Ltd. */
+
+#include "wrs/wrs_rssi.h"
+#include "wrs/wrs.h"
+#include "def.h"
+#include "rssi.h"
+#include "data_rates.h"
+
+/*
+ * Section #1:
+ * rate based on rssi.
+ */
+static s8 rssi_threshold_he[WRS_MCS_MAX_HE] = {
+       -35, -40, -45, -50, -55, -60, -65, -70, -75, -80, -85, -90
+};
+
+static s8 rssi_threshold_vht[WRS_MCS_MAX_VHT] = {
+       -36, -42, -48, -54, -60, -66, -72, -78, -84, -90
+};
+
+static s8 rssi_threshold_ht[WRS_MCS_MAX_HT] = {
+       -34, -42, -50, -58, -66, -74, -82, -90
+};
+
+static s8 rssi_threshold_ofdm[WRS_MCS_MAX_OFDM] = {
+       -34, -42, -50, -58, -66, -74, -82, -90
+};
+
+static s8 rssi_threshold_cck[WRS_MCS_MAX_CCK] = {
+       -45, -60, -75, -90
+};
+
+static u16 cl_wrs_rssi_find_rate_ht_vht_he(struct cl_hw *cl_hw, struct cl_wrs_db *wrs_db,
+                                          struct cl_wrs_sta *wrs_sta, s8 *rssi_sort,
+                                          s8 *thresholds)
+{
+       struct cl_wrs_params *wrs_params = &wrs_sta->su_params;
+       s8 max_ss = (s8)wrs_sta->max_rate_cap.nss;
+       s8 nss = 0;
+       u8 max_bw = wrs_sta->max_rate_cap.bw;
+       u8 bw = 0;
+       u8 max_mcs = wrs_sta->max_rate_cap.mcs;
+       u8 mcs = 0;
+       u8 gi = WRS_GI_LONG;
+       u8 selected_mcs = 0;
+       u8 selected_nss = 0;
+       u8 selected_bw = 0;
+       u8 i = 0;
+       u16 rate_idx = 0;
+       u16 data_rate = 0;
+       u16 max_data_rate = 0;
+
+       if (max_bw > cl_hw->conf->ci_wrs_max_bw)
+               max_bw = cl_hw->conf->ci_wrs_max_bw;
+
+       for (i = 0; i <= max_mcs; i++) {
+               mcs = max_mcs - i;
+
+               for (nss = max_ss; nss >= 0; nss--) {
+                       if (rssi_sort[nss] <= thresholds[i])
+                               continue;
+
+                       /* In last level decrease BW */
+                       bw = ((i == max_mcs) && (max_bw > CHNL_BW_20)) ? (max_bw - 1) : max_bw;
+
+                       if (wrs_sta->mode == WRS_MODE_HE) {
+                               data_rate = data_rate_he_x10[nss][bw][mcs][WRS_GI_LONG];
+                       } else {
+                               if (wrs_sta->mode == WRS_MODE_VHT) {
+                                       /* 160MHz in VHT is valid only for 1/2 SS */
+                                       if (nss >= WRS_SS_3 && bw == CHNL_BW_160)
+                                               bw = CHNL_BW_80;
+
+                                       /* BW 80, 3 SS MCS 6 is invalid in VHT */
+                                       if (bw == CHNL_BW_80 &&
+                                           nss == WRS_SS_3 &&
+                                           mcs == WRS_MCS_6)
+                                               continue;
+                               }
+
+                               data_rate = data_rate_ht_vht_x10[bw][nss][mcs][gi];
+                       }
+
+                       if (data_rate > max_data_rate) {
+                               selected_mcs = mcs;
+                               selected_nss = nss;
+                               selected_bw = bw;
+                               max_data_rate = data_rate;
+                               rate_idx = cl_wrs_tables_find_rate_idx(wrs_params,
+                                                                      bw, nss, mcs, gi);
+                       }
+
+                       break;
+               }
+       }
+
+       if (cl_env_det_is_noisy(cl_hw) || cl_env_det_is_very_noisy(cl_hw)) {
+               /* In conservative mode select less agressive parameters */
+               if (wrs_db->conservative_nss_noisy_env && selected_nss > 0)
+                       selected_nss--;
+
+               if (wrs_db->conservative_nss_noisy_env && selected_mcs > 0)
+                       selected_mcs--;
+
+               /* BW 80, 3 SS MCS 6 is invalid in VHT */
+               if (wrs_sta->mode == WRS_MODE_VHT &&
+                   selected_bw == CHNL_BW_80 &&
+                   selected_nss == WRS_SS_3 &&
+                   selected_mcs == WRS_MCS_6)
+                       selected_mcs--;
+
+               rate_idx = cl_wrs_tables_find_rate_idx(wrs_params,
+                                                      selected_bw, selected_nss, selected_mcs, gi);
+       }
+
+       return rate_idx;
+}
+
+static u16 cl_wrs_rssi_find_rate_cck_ofdm(struct cl_wrs_sta *wrs_sta,
+                                         s8 *rssi_sort, s8 *thresholds)
+{
+       struct cl_wrs_params *wrs_params = &wrs_sta->su_params;
+       u8 max_mcs = wrs_sta->max_rate_cap.mcs;
+       u8 mcs = 0;
+       u8 i = 0;
+
+       for (i = 0; i <= max_mcs; i++) {
+               mcs = max_mcs - i;
+
+               if (rssi_sort[WRS_SS_1] > thresholds[i])
+                       return cl_wrs_tables_find_rate_idx(wrs_params,
+                                                          CHNL_BW_20, WRS_SS_1, mcs, WRS_GI_LONG);
+       }
+
+       return 0;
+}
+
+static u16 cl_wrs_rssi_find_rate(struct cl_hw *cl_hw, struct cl_wrs_db *wrs_db,
+                                struct cl_wrs_sta *wrs_sta, s8 *rssi_sort)
+{
+       struct cl_wrs_params *wrs_params = &wrs_sta->su_params;
+       u16 rate_idx = 0;
+
+       switch (wrs_sta->mode) {
+       case WRS_MODE_HE:
+               rate_idx = cl_wrs_rssi_find_rate_ht_vht_he(cl_hw, wrs_db, wrs_sta,
+                                                          rssi_sort, rssi_threshold_he);
+               break;
+       case WRS_MODE_VHT:
+               rate_idx = cl_wrs_rssi_find_rate_ht_vht_he(cl_hw, wrs_db, wrs_sta,
+                                                          rssi_sort, rssi_threshold_vht);
+               break;
+       case WRS_MODE_HT:
+               rate_idx = cl_wrs_rssi_find_rate_ht_vht_he(cl_hw, wrs_db, wrs_sta,
+                                                          rssi_sort, rssi_threshold_ht);
+               break;
+       case WRS_MODE_OFDM:
+               rate_idx = cl_wrs_rssi_find_rate_cck_ofdm(wrs_sta, rssi_sort,
+                                                         rssi_threshold_ofdm);
+               break;
+       case WRS_MODE_CCK:
+               rate_idx = cl_wrs_rssi_find_rate_cck_ofdm(wrs_sta, rssi_sort,
+                                                         rssi_threshold_cck);
+               break;
+       default:
+               break;
+       }
+
+       if (rate_idx == WRS_INVALID_RATE)
+               rate_idx = 0;
+
+       wrs_pr_trace(wrs_db,
+                    "[WRS] Select rate based rssi - sta=%u, rssi [%d,%d,%d,%d], "
+                    "rate_idx=%u, bw=%u, nss=%u, mcs=%u\n",
+                    wrs_sta->sta_idx,
+                    rssi_sort[0],
+                    rssi_sort[1],
+                    rssi_sort[2],
+                    rssi_sort[3],
+                    rate_idx,
+                    wrs_params->table[rate_idx].rate.bw,
+                    wrs_params->table[rate_idx].rate.nss,
+                    wrs_params->table[rate_idx].rate.mcs);
+
+       return rate_idx;
+}
+
+bool cl_wrs_rssi_set_rate(struct cl_hw *cl_hw, struct cl_wrs_db *wrs_db,
+                         struct cl_wrs_sta *wrs_sta)
+{
+       struct cl_wrs_params *wrs_params = &wrs_sta->su_params;
+       s8 rssi_sort[MAX_ANTENNAS] = {0};
+       u16 new_rate_idx = 0;
+
+       /* Get rssi */
+       cl_wrs_rssi_eq_calc(cl_hw, wrs_sta, true, rssi_sort);
+
+       /* Find new rate according to rssi thresholds */
+       new_rate_idx = cl_wrs_rssi_find_rate(cl_hw, wrs_db, wrs_sta, rssi_sort);
+
+       if (new_rate_idx != wrs_params->rate_idx) {
+               cl_wrs_decision_update(wrs_db, wrs_sta, wrs_params,
+                                      WRS_DECISION_RSSI_MGMT, new_rate_idx);
+               cl_wrs_tx_params_update(cl_hw, wrs_db, wrs_sta, wrs_params,
+                                       new_rate_idx, false);
+       } else {
+               wrs_params->sync = true;
+       }
+
+       return true;
+}
+
+/*
+ * Section #2:
+ * rssi protect.
+ */
+static void cl_wrs_rssi_prot_set_avg(struct cl_wrs_sta *wrs_sta, s8 avg)
+{
+       struct cl_wrs_rssi_prot_db *rssi_prot_db = &wrs_sta->rssi_prot_db;
+
+       memset(rssi_prot_db->samples_old, avg, WRS_RSSI_PROTECT_BUF_SZ_OLD);
+       memset(rssi_prot_db->samples_new, avg, WRS_RSSI_PROTECT_BUF_SZ_NEW);
+       rssi_prot_db->sum = avg << WRS_RSSI_PROTECT_SHIFT;
+}
+
+static s8 cl_wrs_rssi_prot_add_smpl(struct cl_wrs_sta *wrs_sta, s8 rssi_eq)
+{
+       struct cl_wrs_rssi_prot_db *rssi_prot_db = &wrs_sta->rssi_prot_db;
+       u8 curr_idx_old = rssi_prot_db->curr_idx_old;
+       u8 curr_idx_new = rssi_prot_db->curr_idx_new;
+
+       rssi_prot_db->sum +=
+               rssi_prot_db->samples_new[curr_idx_new] - rssi_prot_db->samples_old[curr_idx_old];
+       rssi_prot_db->samples_old[curr_idx_old] = rssi_prot_db->samples_new[curr_idx_new];
+       rssi_prot_db->samples_new[curr_idx_new] = rssi_eq;
+
+       rssi_prot_db->curr_idx_old =
+               WRS_INC_POW2(rssi_prot_db->curr_idx_old, WRS_RSSI_PROTECT_BUF_SZ_OLD);
+       WRS_INC(rssi_prot_db->curr_idx_new, WRS_RSSI_PROTECT_BUF_SZ_NEW);
+
+       return (s8)(wrs_sta->rssi_prot_db.sum >> WRS_RSSI_PROTECT_SHIFT);
+}
+
+static bool cl_wrs_rssi_prot_decision_up(struct cl_hw *cl_hw, struct cl_wrs_db *wrs_db,
+                                        struct cl_wrs_sta *wrs_sta, s8 rssi_avg, s8 rssi_eq,
+                                        s8 *rssi_sort, u8 up_rate_idx)
+{
+       /* Decide UP only if all new samples are greater than old average */
+       struct cl_wrs_params *wrs_params = &wrs_sta->su_params;
+       s8 *samples_new = wrs_sta->rssi_prot_db.samples_new;
+       s8 up_thr = rssi_avg + wrs_db->rssi_protect_up_thr;
+       u8 i = 0;
+
+       for (i = 0; i < WRS_RSSI_PROTECT_BUF_SZ_NEW; i++)
+               if (samples_new[i] <= up_thr)
+                       return false;
+
+       if (wrs_db->rssi_protect_mode == WRS_RSSI_PROT_MODE_RSSI) {
+               u16 rate_idx_old = wrs_params->rate_idx;
+               u16 rate_idx_new = cl_wrs_rssi_find_rate(cl_hw, wrs_db, wrs_sta, rssi_sort);
+               struct cl_wrs_rate *rate_old = &wrs_params->table[rate_idx_old].rate;
+               struct cl_wrs_rate *rate_new = &wrs_params->table[rate_idx_new].rate;
+               u16 data_rate_old = cl_data_rates_get_x10(wrs_sta->mode, rate_old->bw,
+                                                         rate_old->nss, rate_old->mcs,
+                                                         rate_old->gi);
+               u16 data_rate_new = cl_data_rates_get_x10(wrs_sta->mode, rate_new->bw,
+                                                         rate_new->nss, rate_new->mcs,
+                                                         rate_new->gi);
+
+               if (rate_idx_old == rate_idx_new || data_rate_old >= data_rate_new)
+                       rate_idx_new = up_rate_idx;
+
+               wrs_pr_info(wrs_db, "[WRS] Increase rate based on RSSI - old [%u], new [%u]\n",
+                           rate_idx_old, rate_idx_new);
+               cl_wrs_decision_update(wrs_db, wrs_sta, wrs_params,
+                                      WRS_DECISION_UP_RSSI, rate_idx_new);
+               cl_wrs_tx_params_update(cl_hw, wrs_db, wrs_sta,
+                                       wrs_params, rate_idx_new, true);
+       } else {
+               cl_wrs_decision_make(cl_hw, wrs_db, wrs_sta, wrs_params,
+                                    WRS_DECISION_UP_RSSI, up_rate_idx);
+       }
+
+       cl_wrs_tables_reset(wrs_db, wrs_sta, wrs_params);
+       cl_wrs_rssi_prot_set_avg(wrs_sta, rssi_eq);
+
+       return true;
+}
+
+static bool cl_wrs_rssi_prot_decision_down(struct cl_hw *cl_hw, struct cl_wrs_db *wrs_db,
+                                          struct cl_wrs_sta *wrs_sta, s8 rssi_avg, s8 rssi_eq,
+                                          s8 *rssi_sort, u8 down_rate_idx)
+{
+       /* Decide DOWN only if all new samples are smaller than old average */
+       struct cl_wrs_params *wrs_params = &wrs_sta->su_params;
+       s8 *samples_new = wrs_sta->rssi_prot_db.samples_new;
+       s8 dn_thr = rssi_avg - wrs_db->rssi_protect_dn_thr;
+       u8 i = 0;
+
+       if (wrs_params->rate_idx == 0)
+               return false;
+
+       for (i = 0; i < WRS_RSSI_PROTECT_BUF_SZ_NEW; i++)
+               if (samples_new[i] >= dn_thr)
+                       return false;
+
+       if (wrs_db->rssi_protect_mode == WRS_RSSI_PROT_MODE_RSSI) {
+               u16 rate_idx_old = wrs_params->rate_idx;
+               u16 rate_idx_new = cl_wrs_rssi_find_rate(cl_hw, wrs_db, wrs_sta, rssi_sort);
+               struct cl_wrs_rate *rate_old = &wrs_params->table[rate_idx_old].rate;
+               struct cl_wrs_rate *rate_new = &wrs_params->table[rate_idx_new].rate;
+               u16 data_rate_old = cl_data_rates_get_x10(wrs_sta->mode, rate_old->bw,
+                                                         rate_old->nss, rate_old->mcs,
+                                                         rate_old->gi);
+               u16 data_rate_new = cl_data_rates_get_x10(wrs_sta->mode, rate_new->bw,
+                                                         rate_new->nss, rate_new->mcs,
+                                                         rate_new->gi);
+
+               if (rate_idx_old == rate_idx_new || data_rate_old <= data_rate_new)
+                       rate_idx_new = down_rate_idx;
+
+               wrs_pr_info(wrs_db, "[WRS] Decrease rate based on RSSI - old [%u], new [%u]\n",
+                           rate_idx_old, rate_idx_new);
+               cl_wrs_decision_update(wrs_db, wrs_sta, wrs_params,
+                                      WRS_DECISION_DOWN_RSSI, rate_idx_new);
+               cl_wrs_tx_params_update(cl_hw, wrs_db, wrs_sta, wrs_params,
+                                       rate_idx_new, true);
+       } else {
+               cl_wrs_decision_make(cl_hw, wrs_db, wrs_sta, wrs_params,
+                                    WRS_DECISION_DOWN_RSSI, down_rate_idx);
+       }
+
+       cl_wrs_tables_reset(wrs_db, wrs_sta, wrs_params);
+       cl_wrs_rssi_prot_set_avg(wrs_sta, rssi_eq);
+
+       return true;
+}
+
+static void cl_wrs_rssi_prot_reset(struct cl_hw *cl_hw, struct cl_sta *cl_sta)
+{
+       memset(&cl_sta->wrs_sta.rssi_prot_db, 0, sizeof(struct cl_wrs_rssi_prot_db));
+}
+
+void cl_wrs_rssi_prot_start(struct cl_hw *cl_hw, struct cl_sta *cl_sta)
+{
+       struct cl_wrs_sta *wrs_sta = &cl_sta->wrs_sta;
+       s8 rssi_sort[MAX_ANTENNAS] = {0};
+       s8 rssi_eq = 0;
+
+       if (!cl_hw->wrs_db.rssi_protect_en)
+               return;
+
+       rssi_eq = cl_wrs_rssi_eq_calc(cl_hw, wrs_sta, false, rssi_sort);
+       cl_wrs_rssi_prot_set_avg(wrs_sta, rssi_eq);
+}
+
+bool cl_wrs_rssi_prot_decision(struct cl_hw *cl_hw, struct cl_wrs_db *wrs_db,
+                              struct cl_wrs_sta *wrs_sta, bool up_rate_valid,
+                              u8 up_rate_idx, u8 down_rate_idx)
+{
+       s8 rssi_avg = 0;
+       s8 rssi_eq = 0;
+       s8 rssi_sort[MAX_ANTENNAS] = {0};
+
+       rssi_eq = cl_wrs_rssi_eq_calc(cl_hw, wrs_sta, true, rssi_sort);
+       rssi_avg = cl_wrs_rssi_prot_add_smpl(wrs_sta, rssi_eq);
+
+       if (up_rate_valid)
+               if (cl_wrs_rssi_prot_decision_up(cl_hw, wrs_db, wrs_sta, rssi_avg,
+                                                rssi_eq, rssi_sort, up_rate_idx))
+                       return true;
+
+       return cl_wrs_rssi_prot_decision_down(cl_hw, wrs_db, wrs_sta, rssi_avg,
+                                             rssi_eq, rssi_sort, down_rate_idx);
+}
+
+void cl_wrs_rssi_prot_dbg(struct cl_hw *cl_hw, struct cl_wrs_db *wrs_db,
+                         struct cl_wrs_sta *wrs_sta)
+{
+       struct cl_wrs_rssi_prot_db *rssi_prot_db = NULL;
+       u8 curr_idx_old = 0;
+       u8 curr_idx_new = 0;
+       u8 rate_idx = 0;
+       char *buf = NULL;
+       ssize_t buf_size;
+       int len = 0;
+
+       if (!wrs_db->rssi_protect_en) {
+               cl_snprintf(&buf, &len, &buf_size, "RSSI protect is disabled!\n");
+               goto out;
+       }
+
+       rssi_prot_db = &wrs_sta->rssi_prot_db;
+       curr_idx_old = rssi_prot_db->curr_idx_old;
+       curr_idx_new = rssi_prot_db->curr_idx_new;
+
+       cl_snprintf(&buf, &len, &buf_size, "sta %u\n", wrs_sta->sta_idx);
+       cl_snprintf(&buf, &len, &buf_size, "Old rssi samples:");
+
+       for (rate_idx = 0; rate_idx < WRS_RSSI_PROTECT_BUF_SZ_OLD; rate_idx++) {
+               if (!(rate_idx & 0x7))
+                       cl_snprintf(&buf, &len, &buf_size, "\n");
+
+               cl_snprintf(&buf, &len, &buf_size, "%3u) %d, ",
+                           rate_idx, rssi_prot_db->samples_old[curr_idx_old]);
+               curr_idx_old = WRS_INC_POW2(curr_idx_old, WRS_RSSI_PROTECT_BUF_SZ_OLD);
+       }
+
+       cl_snprintf(&buf, &len, &buf_size, "\nAvg = [%d]\n\n",
+                   wrs_sta->rssi_prot_db.sum >> WRS_RSSI_PROTECT_SHIFT);
+
+       cl_snprintf(&buf, &len, &buf_size, "New rssi samples:\n");
+       for (rate_idx = 0; rate_idx < WRS_RSSI_PROTECT_BUF_SZ_NEW; rate_idx++) {
+               cl_snprintf(&buf, &len, &buf_size, "%u) %d\n", rate_idx,
+                           rssi_prot_db->samples_new[curr_idx_new]);
+               curr_idx_new = WRS_INC_POW2(curr_idx_new, WRS_RSSI_PROTECT_BUF_SZ_NEW);
+       }
+out:
+       cl_vendor_reply(cl_hw, buf, len);
+       kfree(buf);
+}
+
+void cl_wrs_rssi_prot_config(struct cl_hw *cl_hw, struct cl_wrs_db *wrs_db,
+                            bool enable, bool mode, s32 rssi_up_thr, s32 rssi_dn_thr)
+{
+       bool en_prev = wrs_db->rssi_protect_en;
+
+       wrs_db->rssi_protect_en = enable;
+       wrs_db->rssi_protect_mode = mode;
+       wrs_db->rssi_protect_up_thr = (s8)rssi_up_thr;
+       wrs_db->rssi_protect_dn_thr = (s8)rssi_dn_thr;
+
+       if (!en_prev && wrs_db->rssi_protect_en)
+               cl_sta_loop_bh(cl_hw, cl_wrs_rssi_prot_start);
+       else if (en_prev && !wrs_db->rssi_protect_en)
+               cl_sta_loop_bh(cl_hw, cl_wrs_rssi_prot_reset);
+
+       pr_debug("[WRS] Enable = %s, Mode = %s, Up threshold = %d, Down threshold = %d\n",
+                wrs_db->rssi_protect_en ? "true" : "false",
+                wrs_db->rssi_protect_mode ? "rssi" : "neighbor",
+                wrs_db->rssi_protect_up_thr,
+                wrs_db->rssi_protect_dn_thr);
+}
--
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.
________________________________


^ permalink raw reply related	[flat|nested] 262+ messages in thread

* [RFC v1 249/256] cl8k: add wrs/wrs_rssi.h
  2021-06-17 15:58 [RFC v1 000/256] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (247 preceding siblings ...)
  2021-06-17 16:02 ` [RFC v1 248/256] cl8k: add wrs/wrs_rssi.c viktor.barna
@ 2021-06-17 16:02 ` viktor.barna
  2021-06-17 16:02 ` [RFC v1 250/256] cl8k: add wrs/wrs_sta.c viktor.barna
                   ` (8 subsequent siblings)
  257 siblings, 0 replies; 262+ messages in thread
From: viktor.barna @ 2021-06-17 16:02 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Oleksandr Savchenko, Shay Bar, Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

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

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 .../net/wireless/celeno/cl8k/wrs/wrs_rssi.h   | 22 +++++++++++++++++++
 1 file changed, 22 insertions(+)
 create mode 100644 drivers/net/wireless/celeno/cl8k/wrs/wrs_rssi.h

diff --git a/drivers/net/wireless/celeno/cl8k/wrs/wrs_rssi.h b/drivers/net/wireless/celeno/cl8k/wrs/wrs_rssi.h
new file mode 100644
index 000000000000..2a7f64c88aa5
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/wrs/wrs_rssi.h
@@ -0,0 +1,22 @@
+/* SPDX-License-Identifier: MIT */
+/* Copyright(c) 2019-2021, Celeno Communications Ltd. */
+
+#ifndef CL_WRS_RSSI_H
+#define CL_WRS_RSSI_H
+
+#include "hw.h"
+#include "wrs/wrs_db.h"
+
+bool cl_wrs_rssi_set_rate(struct cl_hw *cl_hw, struct cl_wrs_db *wrs_db,
+                         struct cl_wrs_sta *wrs_sta);
+
+void cl_wrs_rssi_prot_start(struct cl_hw *cl_hw, struct cl_sta *cl_sta);
+bool cl_wrs_rssi_prot_decision(struct cl_hw *cl_hw, struct cl_wrs_db *wrs_db,
+                              struct cl_wrs_sta *wrs_sta, bool up_rate_valid,
+                              u8 up_rate_idx, u8 down_rate_idx);
+void cl_wrs_rssi_prot_dbg(struct cl_hw *cl_hw, struct cl_wrs_db *wrs_db,
+                         struct cl_wrs_sta *wrs_sta);
+void cl_wrs_rssi_prot_config(struct cl_hw *cl_hw, struct cl_wrs_db *wrs_db,
+                            bool enable, bool mode, s32 rssi_up_thr, s32 rssi_dn_thr);
+
+#endif /* CL_WRS_RSSI_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.
________________________________


^ permalink raw reply related	[flat|nested] 262+ messages in thread

* [RFC v1 250/256] cl8k: add wrs/wrs_sta.c
  2021-06-17 15:58 [RFC v1 000/256] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (248 preceding siblings ...)
  2021-06-17 16:02 ` [RFC v1 249/256] cl8k: add wrs/wrs_rssi.h viktor.barna
@ 2021-06-17 16:02 ` viktor.barna
  2021-06-17 16:02 ` [RFC v1 251/256] cl8k: add wrs/wrs_sta.h viktor.barna
                   ` (7 subsequent siblings)
  257 siblings, 0 replies; 262+ messages in thread
From: viktor.barna @ 2021-06-17 16:02 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Oleksandr Savchenko, Shay Bar, Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

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

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 .../net/wireless/celeno/cl8k/wrs/wrs_sta.c    | 360 ++++++++++++++++++
 1 file changed, 360 insertions(+)
 create mode 100644 drivers/net/wireless/celeno/cl8k/wrs/wrs_sta.c

diff --git a/drivers/net/wireless/celeno/cl8k/wrs/wrs_sta.c b/drivers/net/wireless/celeno/cl8k/wrs/wrs_sta.c
new file mode 100644
index 000000000000..2ebcb0c984ba
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/wrs/wrs_sta.c
@@ -0,0 +1,360 @@
+// SPDX-License-Identifier: MIT
+/* Copyright(c) 2019-2021, Celeno Communications Ltd. */
+
+#include "wrs/wrs_sta.h"
+#include "wrs/wrs.h"
+#include "wrs/wrs_rssi.h"
+#include "utils/math.h"
+#include "sta.h"
+#include "wrs/wrs_stats.h"
+#include "band.h"
+#include "utils/utils.h"
+
+static void cl_wrs_sta_info_set_he(struct cl_wrs_sta *wrs_sta)
+{
+       wrs_sta->mode = WRS_MODE_HE;
+
+       wrs_sta->gi_cap[CHNL_BW_20] = WRS_GI_VSHORT;
+       wrs_sta->gi_cap[CHNL_BW_40] = WRS_GI_VSHORT;
+       wrs_sta->gi_cap[CHNL_BW_80] = WRS_GI_VSHORT;
+       wrs_sta->gi_cap[CHNL_BW_160] = WRS_GI_VSHORT;
+}
+
+static void cl_wrs_sta_info_set_vht(struct cl_wrs_sta *wrs_sta,
+                                   struct ieee80211_sta_vht_cap *vht_cap,
+                                   struct ieee80211_sta_ht_cap *ht_cap)
+{
+       wrs_sta->mode = WRS_MODE_VHT;
+
+       wrs_sta->gi_cap[CHNL_BW_20] =
+               (ht_cap->cap & IEEE80211_HT_CAP_SGI_20) ? WRS_GI_SHORT : WRS_GI_LONG;
+       wrs_sta->gi_cap[CHNL_BW_40] =
+               (ht_cap->cap & IEEE80211_HT_CAP_SGI_40) ? WRS_GI_SHORT : WRS_GI_LONG;
+       wrs_sta->gi_cap[CHNL_BW_80] =
+               (vht_cap->cap & IEEE80211_VHT_CAP_SHORT_GI_80) ? WRS_GI_SHORT : WRS_GI_LONG;
+       wrs_sta->gi_cap[CHNL_BW_160] =
+               (vht_cap->cap & IEEE80211_VHT_CAP_SHORT_GI_160) ? WRS_GI_SHORT : WRS_GI_LONG;
+}
+
+static void cl_wrs_sta_info_set_ht(struct cl_wrs_sta *wrs_sta,
+                                  struct ieee80211_sta_ht_cap *ht_cap)
+{
+       wrs_sta->mode = WRS_MODE_HT;
+
+       wrs_sta->gi_cap[CHNL_BW_20] =
+               (ht_cap->cap & IEEE80211_HT_CAP_SGI_20) ? WRS_GI_SHORT : WRS_GI_LONG;
+       wrs_sta->gi_cap[CHNL_BW_40] =
+               (ht_cap->cap & IEEE80211_HT_CAP_SGI_40) ? WRS_GI_SHORT : WRS_GI_LONG;
+}
+
+static void cl_wrs_sta_info_set_legacy(struct cl_wrs_sta *wrs_sta,
+                                      struct ieee80211_sta *sta)
+{
+       if (sta->supp_rates[NL80211_BAND_5GHZ] ||
+           (sta->supp_rates[NL80211_BAND_2GHZ] & 0xFF0))
+               wrs_sta->mode = WRS_MODE_OFDM;
+       else
+               wrs_sta->mode = WRS_MODE_CCK;
+}
+
+static void cl_wrs_sta_info_set(struct cl_hw *cl_hw, struct cl_wrs_sta *wrs_sta,
+                               struct ieee80211_sta *sta)
+{
+       struct cl_wrs_db *wrs_db = &cl_hw->wrs_db;
+       struct ieee80211_sta_ht_cap *ht_cap = &sta->ht_cap;
+       struct ieee80211_sta_vht_cap *vht_cap = &sta->vht_cap;
+       struct ieee80211_sta_he_cap *he_cap = &sta->he_cap;
+       u8 bw = min_t(u8, sta->bandwidth, wrs_db->max_cap.bw);
+
+       if (he_cap->has_he)
+               cl_wrs_sta_info_set_he(wrs_sta);
+       else if (vht_cap->vht_supported && ht_cap->ht_supported)
+               cl_wrs_sta_info_set_vht(wrs_sta, vht_cap, ht_cap);
+       else if (ht_cap->ht_supported)
+               cl_wrs_sta_info_set_ht(wrs_sta, ht_cap);
+       else
+               cl_wrs_sta_info_set_legacy(wrs_sta, sta);
+
+       wrs_sta->max_rate_cap.nss = min_t(u8, sta->rx_nss, WRS_SS_MAX) - 1;
+       wrs_sta->max_rate_cap.bw = bw;
+
+       wrs_sta->assoc_bw = bw;
+}
+
+#define TWO_BITS_MASK 0x3
+
+static u8 cl_wrs_calc_max_nss(u16 rx_mcs, u8 max_nss)
+{
+       u8 i, nss = 0;
+
+       for (i = 0; i <= max_nss; i++) {
+               if (((rx_mcs >> (2 * i)) & TWO_BITS_MASK) != IEEE80211_HE_MCS_NOT_SUPPORTED)
+                       nss++;
+               else
+                       break;
+       }
+
+       return nss;
+}
+
+static void cl_supported_rates_he_cap(struct cl_wrs_db *wrs_db, struct ieee80211_sta *sta)
+{
+       struct cl_sta *cl_sta = (struct cl_sta *)sta->drv_priv;
+       struct cl_wrs_sta *wrs_sta = &cl_sta->wrs_sta;
+       struct ieee80211_he_mcs_nss_supp *mcs_nss = &sta->he_cap.he_mcs_nss_supp;
+       int mcs = 0;
+       int supported_mcs = 0;
+       u16 rx_mcs = 0;
+       u8 max_nss = wrs_sta->max_rate_cap.nss;
+       u8 nss = 0, bw = 0;
+       u8 max_nss_80, max_nss_160;
+
+       for (bw = 0; bw <= wrs_sta->max_rate_cap.bw; bw++) {
+               if (bw < CHNL_BW_160) {
+                       rx_mcs = le16_to_cpu(mcs_nss->rx_mcs_80);
+               } else if (bw == CHNL_BW_160) {
+                       max_nss_80 = cl_wrs_calc_max_nss(mcs_nss->rx_mcs_80, max_nss) + 1;
+                       rx_mcs = le16_to_cpu(mcs_nss->rx_mcs_160);
+                       max_nss_160 = cl_wrs_calc_max_nss(rx_mcs, max_nss) + 1;
+                       max_nss = max_nss * max_nss_160 / max_nss_80;
+               } else {
+                       wrs_pr_err(wrs_db, "[WRS] bw %u is not supported\n", bw);
+               }
+
+               for (nss = 0; nss <= max_nss; nss++) {
+                       switch ((rx_mcs >> (2 * nss)) & TWO_BITS_MASK) {
+                       case IEEE80211_HE_MCS_SUPPORT_0_7:
+                               supported_mcs = WRS_MCS_7;
+                               break;
+                       case IEEE80211_HE_MCS_SUPPORT_0_9:
+                               supported_mcs = WRS_MCS_9;
+                               break;
+                       case IEEE80211_HE_MCS_SUPPORT_0_11:
+                               supported_mcs = WRS_MCS_11;
+                               break;
+                       case IEEE80211_HE_MCS_NOT_SUPPORTED:
+                               supported_mcs = -1;
+                               break;
+                       }
+
+                       for (mcs = 0; mcs <= supported_mcs; mcs++)
+                               cl_wrs_sta_set_supported_rate(wrs_sta, bw, nss, mcs);
+               }
+       }
+}
+
+static void cl_supported_rates_vht_cap(struct ieee80211_sta *sta)
+{
+       struct cl_sta *cl_sta = IEEE80211_STA_TO_CL_STA(sta);
+       struct cl_wrs_sta *wrs_sta = &cl_sta->wrs_sta;
+       u16 mcs_map = le16_to_cpu(sta->vht_cap.vht_mcs.rx_mcs_map);
+       u8 bw = 0;
+       u8 nss = 0;
+       int mcs = 0;
+       int supported_mcs = 0;
+
+       for (bw = 0; bw <= wrs_sta->max_rate_cap.bw; bw++) {
+               for (nss = 0; nss <= wrs_sta->max_rate_cap.nss; nss++) {
+                       switch ((mcs_map >> (2 * nss)) & TWO_BITS_MASK) {
+                       case 0:
+                               supported_mcs = WRS_MCS_7;
+                               break;
+                       case 1:
+                               supported_mcs = WRS_MCS_8;
+                               break;
+                       case 2:
+                               supported_mcs = WRS_MCS_9;
+                               break;
+                       case 3:
+                               supported_mcs = -1;
+                               break;
+                       }
+
+                       for (mcs = 0; mcs <= supported_mcs; mcs++)
+                               cl_wrs_sta_set_supported_rate(wrs_sta, bw, nss, mcs);
+               }
+       }
+}
+
+static void cl_supported_rates_ht_cap(struct ieee80211_sta *sta)
+{
+       struct ieee80211_sta_ht_cap *ht_cap = &sta->ht_cap;
+       struct cl_sta *cl_sta = IEEE80211_STA_TO_CL_STA(sta);
+       struct cl_wrs_sta *wrs_sta = &cl_sta->wrs_sta;
+       u8 bw = 0;
+       u8 nss = 0;
+       u8 mcs = 0;
+
+       for (mcs = 0; mcs <= WRS_MCS_7; mcs++) {
+               for (nss = 0; nss <= wrs_sta->max_rate_cap.nss; nss++) {
+                       if ((ht_cap->mcs.rx_mask[nss] & (1 << mcs)) == 0)
+                               continue;
+
+                       for (bw = 0; bw <= wrs_sta->max_rate_cap.bw; bw++)
+                               cl_wrs_sta_set_supported_rate(wrs_sta, bw, nss, mcs);
+               }
+       }
+}
+
+static void cl_supported_rates_legacy_cap(struct cl_hw *cl_hw,
+                                         struct ieee80211_sta *sta,
+                                         u8 max_mcs)
+{
+       struct cl_sta *cl_sta = IEEE80211_STA_TO_CL_STA(sta);
+       struct cl_wrs_sta *wrs_sta = &cl_sta->wrs_sta;
+       u8 mcs = 0;
+
+       for (mcs = 0; mcs < max_mcs; mcs++)
+               if (rate_supported(sta, cl_hw->nl_band, mcs))
+                       cl_wrs_sta_set_supported_rate(wrs_sta, CHNL_BW_20, WRS_SS_1, mcs);
+}
+
+void cl_wrs_sta_add(struct cl_hw *cl_hw, struct ieee80211_sta *sta)
+{
+       struct cl_sta *cl_sta = IEEE80211_STA_TO_CL_STA(sta);
+       struct cl_wrs_db *wrs_db = &cl_hw->wrs_db;
+       struct cl_wrs_sta *wrs_sta = &cl_sta->wrs_sta;
+       struct cl_wrs_params *wrs_params = &wrs_sta->su_params;
+
+       wrs_params->rate_idx = WRS_INVALID_RATE;
+
+       wrs_sta->sta_idx = cl_sta->sta_idx;
+
+       cl_wrs_rssi_prot_start(cl_hw, cl_sta);
+       cl_wrs_stats_per_init(wrs_params);
+       cl_wrs_sta_info_set(cl_hw, wrs_sta, sta);
+       cl_wrs_sta_capabilities_set(wrs_db, sta);
+       cl_wrs_tables_build(cl_hw, wrs_sta, wrs_params);
+       cl_wrs_sta_select_first_rate(cl_hw, wrs_db, wrs_sta, wrs_params);
+
+       wrs_pr_trace(wrs_db, "[WRS] Add station %pM to database (sta_idx %u)\n",
+                    cl_sta->addr, cl_sta->sta_idx);
+}
+
+static void _cl_wrs_sta_remove(struct cl_wrs_params *wrs_params)
+{
+       kfree(wrs_params->table);
+       wrs_params->table = NULL;
+
+       cl_wrs_stats_per_remove(wrs_params);
+}
+
+void cl_wrs_sta_remove(struct cl_hw *cl_hw, struct cl_wrs_db *wrs_db, struct cl_sta *cl_sta)
+{
+       struct cl_wrs_sta *wrs_sta = &cl_sta->wrs_sta;
+
+       _cl_wrs_sta_remove(&wrs_sta->su_params);
+
+       wrs_pr_trace(wrs_db, "[WRS] Remove station %pM from database (sta_idx %u)\n",
+                    cl_sta->addr, cl_sta->sta_idx);
+}
+
+struct cl_wrs_sta *cl_wrs_sta_get(struct cl_hw *cl_hw, u8 sta_idx)
+{
+       struct cl_sta *cl_sta = cl_sta_get(cl_hw, sta_idx);
+
+       return cl_sta ? &cl_sta->wrs_sta : NULL;
+}
+
+void cl_wrs_sta_print_list(struct cl_hw *cl_hw, struct cl_wrs_db *wrs_db)
+{
+       struct cl_sta *cl_sta = NULL;
+       struct cl_wrs_sta *wrs_sta = NULL;
+       struct cl_wrs_rate *max_rate_cap = NULL;
+       u8 num_sta = cl_sta_num_bh(cl_hw);
+       char *buf = NULL;
+       ssize_t buf_size;
+       int len = 0;
+
+       cl_snprintf(&buf, &len, &buf_size,
+                   "\n");
+       cl_snprintf(&buf, &len, &buf_size,
+                   "Station list [%u]\n", num_sta);
+       cl_snprintf(&buf, &len, &buf_size,
+                   "-------------------------------------------------------\n");
+       cl_snprintf(&buf, &len, &buf_size,
+                   "|Sta|    Mac Address    |Mode|MaxBW|MaxSS|MaxMCS|MaxGI|\n");
+       cl_snprintf(&buf, &len, &buf_size,
+                   "|-----------------------------------------------------|\n");
+
+       read_lock_bh(&cl_hw->cl_sta_db.lock);
+
+       list_for_each_entry(cl_sta, &cl_hw->cl_sta_db.head, list) {
+               wrs_sta = &cl_sta->wrs_sta;
+               max_rate_cap = &wrs_sta->max_rate_cap;
+
+               cl_snprintf(&buf, &len, &buf_size,
+                           "|%3u| %pM |%-4s|%-5s|%-5u|%-6u|%-5u|\n",
+                           cl_sta->sta_idx,
+                           cl_sta->addr,
+                           WRS_MODE_STR(wrs_sta->mode),
+                           WRS_BW_STR(max_rate_cap->bw),
+                           max_rate_cap->nss,
+                           max_rate_cap->mcs,
+                           max_rate_cap->gi);
+       }
+
+       read_unlock_bh(&cl_hw->cl_sta_db.lock);
+
+       cl_snprintf(&buf, &len, &buf_size,
+                   "-------------------------------------------------------\n");
+       cl_snprintf(&buf, &len, &buf_size,
+                   "\n");
+
+       cl_vendor_reply(cl_hw, buf, len);
+       kfree(buf);
+}
+
+void cl_wrs_sta_select_first_rate(struct cl_hw *cl_hw, struct cl_wrs_db *wrs_db,
+                                 struct cl_wrs_sta *wrs_sta, struct cl_wrs_params *wrs_params)
+{
+       if (wrs_db->is_fixed_rate) {
+               s8 *fixed_rate = cl_hw->conf->ci_wrs_fixed_rate;
+
+               cl_wrs_fixed_rate_set(cl_hw, wrs_db, wrs_sta, wrs_params, wrs_db->is_fixed_rate,
+                                     fixed_rate[WRS_FIXED_PARAM_MODE],
+                                     fixed_rate[WRS_FIXED_PARAM_BW],
+                                     fixed_rate[WRS_FIXED_PARAM_NSS],
+                                     fixed_rate[WRS_FIXED_PARAM_MCS],
+                                     fixed_rate[WRS_FIXED_PARAM_GI]);
+       }
+
+       if (!wrs_params->is_fixed_rate) {
+               bool result = cl_wrs_rssi_set_rate(cl_hw, wrs_db, wrs_sta);
+
+               /*
+                * If new rate wasn't selected according to
+                * rssi (no samples) set rate to lowest possible
+                */
+               if (!result)
+                       cl_wrs_tx_params_update(cl_hw, wrs_db, wrs_sta,
+                                               wrs_params, 0, false);
+       }
+}
+
+void cl_wrs_sta_capabilities_set(struct cl_wrs_db *wrs_db, struct ieee80211_sta *sta)
+{
+       struct cl_sta *cl_sta = IEEE80211_STA_TO_CL_STA(sta);
+       enum cl_wrs_mode mode = cl_sta->wrs_sta.mode;
+
+       if (mode == WRS_MODE_HE)
+               cl_supported_rates_he_cap(wrs_db, sta);
+       else if (mode == WRS_MODE_VHT)
+               cl_supported_rates_vht_cap(sta);
+       else if (mode == WRS_MODE_HT)
+               cl_supported_rates_ht_cap(sta);
+       else {
+               struct cl_hw *cl_hw = cl_sta->cl_vif->cl_hw;
+               u8 max_mcs = (mode == WRS_MODE_OFDM) ? WRS_MCS_MAX_OFDM : WRS_MCS_MAX_CCK;
+
+               cl_supported_rates_legacy_cap(cl_hw, sta, max_mcs);
+       }
+}
+
+void cl_wrs_sta_set_supported_rate(struct cl_wrs_sta *wrs_sta, u8 bw, u8 nss, u8 mcs)
+{
+       u8 rate_idx = mcs + (nss * WRS_MCS_MAX);
+
+       wrs_sta->supported_rates[bw] |= BIT(rate_idx);
+}
+
--
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.
________________________________


^ permalink raw reply related	[flat|nested] 262+ messages in thread

* [RFC v1 251/256] cl8k: add wrs/wrs_sta.h
  2021-06-17 15:58 [RFC v1 000/256] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (249 preceding siblings ...)
  2021-06-17 16:02 ` [RFC v1 250/256] cl8k: add wrs/wrs_sta.c viktor.barna
@ 2021-06-17 16:02 ` viktor.barna
  2021-06-17 16:02 ` [RFC v1 252/256] cl8k: add wrs/wrs_stats.c viktor.barna
                   ` (6 subsequent siblings)
  257 siblings, 0 replies; 262+ messages in thread
From: viktor.barna @ 2021-06-17 16:02 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Oleksandr Savchenko, Shay Bar, Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

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

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 .../net/wireless/celeno/cl8k/wrs/wrs_sta.h    | 20 +++++++++++++++++++
 1 file changed, 20 insertions(+)
 create mode 100644 drivers/net/wireless/celeno/cl8k/wrs/wrs_sta.h

diff --git a/drivers/net/wireless/celeno/cl8k/wrs/wrs_sta.h b/drivers/net/wireless/celeno/cl8k/wrs/wrs_sta.h
new file mode 100644
index 000000000000..a7a06f71c548
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/wrs/wrs_sta.h
@@ -0,0 +1,20 @@
+/* SPDX-License-Identifier: MIT */
+/* Copyright(c) 2019-2021, Celeno Communications Ltd. */
+
+#ifndef CL_WRS_STA_H
+#define CL_WRS_STA_H
+
+#include "wrs/wrs_db.h"
+#include "vif.h"
+#include "hw.h"
+
+void cl_wrs_sta_add(struct cl_hw *cl_hw, struct ieee80211_sta *sta);
+void cl_wrs_sta_remove(struct cl_hw *cl_hw, struct cl_wrs_db *wrs_db, struct cl_sta *cl_sta);
+struct cl_wrs_sta *cl_wrs_sta_get(struct cl_hw *cl_hw, u8 sta_idx);
+void cl_wrs_sta_print_list(struct cl_hw *cl_hw, struct cl_wrs_db *wrs_db);
+void cl_wrs_sta_select_first_rate(struct cl_hw *cl_hw, struct cl_wrs_db *wrs_db,
+                                 struct cl_wrs_sta *wrs_sta, struct cl_wrs_params *wrs_params);
+void cl_wrs_sta_capabilities_set(struct cl_wrs_db *wrs_db, struct ieee80211_sta *sta);
+void cl_wrs_sta_set_supported_rate(struct cl_wrs_sta *wrs_sta, u8 bw, u8 nss, u8 mcs);
+
+#endif /* CL_WRS_STA_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.
________________________________


^ permalink raw reply related	[flat|nested] 262+ messages in thread

* [RFC v1 252/256] cl8k: add wrs/wrs_stats.c
  2021-06-17 15:58 [RFC v1 000/256] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (250 preceding siblings ...)
  2021-06-17 16:02 ` [RFC v1 251/256] cl8k: add wrs/wrs_sta.h viktor.barna
@ 2021-06-17 16:02 ` viktor.barna
  2021-06-17 16:02 ` [RFC v1 253/256] cl8k: add wrs/wrs_stats.h viktor.barna
                   ` (5 subsequent siblings)
  257 siblings, 0 replies; 262+ messages in thread
From: viktor.barna @ 2021-06-17 16:02 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Oleksandr Savchenko, Shay Bar, Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

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

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 .../net/wireless/celeno/cl8k/wrs/wrs_stats.c  | 242 ++++++++++++++++++
 1 file changed, 242 insertions(+)
 create mode 100644 drivers/net/wireless/celeno/cl8k/wrs/wrs_stats.c

diff --git a/drivers/net/wireless/celeno/cl8k/wrs/wrs_stats.c b/drivers/net/wireless/celeno/cl8k/wrs/wrs_stats.c
new file mode 100644
index 000000000000..3e477e82a16a
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/wrs/wrs_stats.c
@@ -0,0 +1,242 @@
+// SPDX-License-Identifier: MIT
+/* Copyright(c) 2019-2021, Celeno Communications Ltd. */
+
+#include "wrs/wrs_stats.h"
+#include "wrs/wrs.h"
+#include "utils/utils.h"
+
+static struct cl_wrs_per_stats *cl_wrs_stats_per_entry(struct cl_wrs_params *wrs_params)
+{
+       struct cl_wrs_per_stats *per_stats = NULL, *per_stats_new = NULL;
+       struct cl_wrs_tx_params *tx_params = &wrs_params->tx_params;
+       struct list_head *list_rates = &wrs_params->list_rates;
+       u8 bw = tx_params->bw;
+       u8 nss = tx_params->nss;
+       u8 mcs = tx_params->mcs;
+       u8 gi = tx_params->gi;
+
+       list_for_each_entry(per_stats, list_rates, list) {
+               if (per_stats->bw != bw ||
+                   per_stats->nss != nss ||
+                   per_stats->mcs != mcs ||
+                   per_stats->gi != gi)
+                       continue;
+
+               /*
+                * Move the entry to the beginning of the list, so that it
+                * will be faster to find next time.
+                */
+               if (per_stats != list_entry(list_rates->next, struct cl_wrs_per_stats, list)) {
+                       list_del(&per_stats->list);
+                       list_add(&per_stats->list, list_rates);
+               }
+
+               return per_stats;
+       }
+
+       /* Entry not found - allocate new entry and add to list */
+       per_stats_new = kzalloc(sizeof(*per_stats_new), GFP_ATOMIC);
+
+       if (!per_stats_new)
+               return NULL;
+
+       per_stats_new->bw = bw;
+       per_stats_new->nss = nss;
+       per_stats_new->mcs = mcs;
+       per_stats_new->gi = gi;
+
+       list_add(&per_stats_new->list, &wrs_params->list_rates);
+
+       return per_stats_new;
+}
+
+void cl_wrs_stats_per_update(struct cl_wrs_db *wrs_db,
+                            struct cl_wrs_sta *wrs_sta,
+                            struct cl_wrs_params *wrs_params,
+                            struct cl_wrs_tx_cntrs *tx_cntrs)
+{
+       u16 curr_rate_idx = wrs_params->rate_idx;
+       struct cl_wrs_table *table_node = &wrs_params->table[curr_rate_idx];
+       struct cl_wrs_per_stats *per_stats = cl_wrs_stats_per_entry(wrs_params);
+
+       if (!per_stats)
+               return;
+
+       wrs_params->frames_total += tx_cntrs->total;
+       wrs_params->fail_total += tx_cntrs->fail;
+       wrs_params->ba_not_rcv_total += tx_cntrs->ba_not_rcv;
+       wrs_params->epr_acc += tx_cntrs->epr_acc;
+
+       per_stats->frames_total += tx_cntrs->total;
+       per_stats->frames_failed += tx_cntrs->fail;
+       per_stats->epr_acc += tx_cntrs->epr_acc;
+
+       if (wrs_params->calc_ba_not_rcv) {
+               per_stats->frames_total += tx_cntrs->ba_not_rcv;
+               per_stats->frames_failed += tx_cntrs->ba_not_rcv;
+       }
+
+       table_node->frames_total = wrs_params->frames_total;
+       table_node->ba_not_rcv_total = wrs_params->ba_not_rcv_total;
+       table_node->epr_acc = wrs_params->epr_acc;
+}
+
+struct per_info {
+       u32 frames_failed;
+       u32 frames_total;
+       u64 epr_acc;
+};
+
+static void _cl_wrs_stats_per_print(char **buf, int *len, ssize_t *buf_size,
+                                   struct cl_wrs_rate *curr_rate,
+                                   struct per_info *per_info,
+                                   u64 total_all_rates,
+                                   u8 bw, u8 nss, u8 mcs, u8 gi)
+{
+       u64 frames_total = per_info->frames_total;
+       u64 frames_failed = per_info->frames_failed;
+       u64 epr_acc = per_info->epr_acc;
+       u32 per_high = 0, per_low = 0, usage_high = 0, usage_low = 0, epr_high = 0, epr_low = 0;
+
+       if (frames_total == 0)
+               return;
+
+       cl_div64_decimal(100 * frames_failed, frames_total, &per_high, &per_low);
+       cl_div64_decimal(100 * frames_total, total_all_rates, &usage_high, &usage_low);
+       cl_div64_decimal(epr_acc, frames_total * WRS_DATA_RATE_FACTOR, &epr_high, &epr_low);
+
+       cl_snprintf(buf, len, buf_size,
+                   "|%3s|%3u|%3u|%-9s|%4u.%02u|%10llu|%10llu|%3u.%02u|%4u.%02u|",
+                   WRS_BW_STR(bw), nss, mcs, WRS_GI_STR(gi),
+                   usage_high, usage_low, frames_failed,
+                   frames_total, per_high, per_low, epr_high,
+                   epr_low);
+
+       /* Add an arrow to the current rate */
+       if (curr_rate->bw == bw &&
+           curr_rate->nss == nss &&
+           curr_rate->mcs == mcs &&
+           curr_rate->gi == gi)
+               cl_snprintf(buf, len, buf_size, "<==\n");
+       else
+               cl_snprintf(buf, len, buf_size, "\n");
+
+       cl_snprintf(buf, len, buf_size,
+                   "|------------------------------------------------------------------|\n");
+}
+
+void cl_wrs_stats_per_print(struct cl_hw *cl_hw,
+                           struct cl_wrs_sta *wrs_sta,
+                           struct cl_wrs_params *wrs_params)
+{
+       struct cl_wrs_rate *curr_rate = &wrs_params->table[wrs_params->rate_idx].rate;
+       struct cl_wrs_per_stats *per_stats = NULL;
+       u8 bw = 0, nss = 0, mcs = 0, gi = 0;
+       u16 alloc_size = CHNL_BW_MAX * WRS_SS_MAX * WRS_MCS_MAX * WRS_GI_MAX;
+       u32 total_epr_high = 0, total_epr_low = 0;
+       u64 total_epr_acc = 0, total_all_rates = 0;
+       char *buf = NULL;
+       ssize_t buf_size;
+       int len = 0;
+       struct per_info (*per_info_arr)[WRS_SS_MAX][WRS_MCS_MAX][WRS_GI_MAX] =
+               kzalloc(alloc_size * sizeof(struct per_info), GFP_ATOMIC);
+
+       if (!per_info_arr)
+               return;
+
+       list_for_each_entry(per_stats, &wrs_params->list_rates, list) {
+               bw = per_stats->bw;
+               nss = per_stats->nss;
+               mcs = per_stats->mcs;
+               gi = per_stats->gi;
+
+               total_all_rates += per_stats->frames_total;
+               total_epr_acc += per_stats->epr_acc;
+
+               per_info_arr[bw][nss][mcs][gi].frames_failed = per_stats->frames_failed;
+               per_info_arr[bw][nss][mcs][gi].frames_total = per_stats->frames_total;
+               per_info_arr[bw][nss][mcs][gi].epr_acc = per_stats->epr_acc;
+       }
+
+       if (total_all_rates == 0) {
+               cl_snprintf(&buf, &len, &buf_size, "Table rate empty\n");
+               goto out;
+       }
+
+       cl_snprintf(&buf, &len, &buf_size,
+                   "|------------------------------------------------------------------|\n"
+                   "|BW |NSS|MCS|GI       |Usage  |Fail      |Total     |PER   |EPR    |\n"
+                   "|---+---+---+---------+-------+----------+----------+------+-------|\n");
+
+       for (bw = 0; bw <= wrs_sta->max_rate_cap.bw; bw++)
+               for (nss = 0; nss <= wrs_sta->max_rate_cap.nss; nss++)
+                       for (mcs = 0; mcs <= wrs_sta->max_rate_cap.mcs; mcs++)
+                               for (gi = 0; gi <= wrs_sta->max_rate_cap.gi; gi++)
+                                       _cl_wrs_stats_per_print(&buf, &len, &buf_size,
+                                                               curr_rate,
+                                                               &per_info_arr[bw][nss][mcs][gi],
+                                                               total_all_rates,
+                                                               bw, nss, mcs, gi);
+
+       cl_div64_decimal(total_epr_acc, total_all_rates * WRS_DATA_RATE_FACTOR,
+                        &total_epr_high, &total_epr_low);
+       cl_snprintf(&buf, &len, &buf_size,
+                   "###  Effective PHY Rate = %u.%u Mbps  ###\n",
+                   total_epr_high, total_epr_low);
+
+out:
+       kfree(per_info_arr);
+       cl_vendor_reply(cl_hw, buf, len);
+       kfree(buf);
+}
+
+void cl_wrs_stats_per_reset(struct cl_wrs_params *wrs_params)
+{
+       cl_wrs_stats_per_remove(wrs_params);
+}
+
+void cl_wrs_stats_per_init(struct cl_wrs_params *wrs_params)
+{
+       INIT_LIST_HEAD(&wrs_params->list_rates);
+}
+
+void cl_wrs_stats_per_remove(struct cl_wrs_params *wrs_params)
+{
+       struct cl_wrs_per_stats *per_stats = NULL, *per_stats_next = NULL;
+
+       list_for_each_entry_safe(per_stats, per_stats_next, &wrs_params->list_rates, list) {
+               list_del(&per_stats->list);
+               kfree(per_stats);
+       }
+}
+
+void cl_wrs_stats_decision_print(struct cl_wrs_params *wrs_params)
+{
+       u32 *decision_cnt = wrs_params->decision_cnt;
+
+       pr_debug("\n");
+       pr_debug("----------------------------\n");
+       pr_debug("|Decision       |Count     |\n");
+       pr_debug("|--------------------------|\n");
+       pr_debug("|NONE           |%10u|\n", decision_cnt[WRS_DECISION_NONE]);
+       pr_debug("|SAME           |%10u|\n", decision_cnt[WRS_DECISION_SAME]);
+       pr_debug("|UP             |%10u|\n", decision_cnt[WRS_DECISION_UP]);
+       pr_debug("|UP QUICK       |%10u|\n", decision_cnt[WRS_DECISION_UP_QUICK]);
+       pr_debug("|UP RSSI        |%10u|\n", decision_cnt[WRS_DECISION_UP_RSSI]);
+       pr_debug("|UP MCS1        |%10u|\n", decision_cnt[WRS_DECISION_UP_MCS1]);
+       pr_debug("|DOWN           |%10u|\n", decision_cnt[WRS_DECISION_DOWN]);
+       pr_debug("|DOWN RSSI      |%10u|\n", decision_cnt[WRS_DECISION_DOWN_RSSI]);
+       pr_debug("|DOWN IMMEDIATE |%10u|\n", decision_cnt[WRS_DECISION_DOWN_IMMEDIATE]);
+       pr_debug("|DOWN QUICK     |%10u|\n", decision_cnt[WRS_DECISION_DOWN_QUICK]);
+       pr_debug("|DOWN NO SYNC   |%10u|\n", decision_cnt[WRS_DECISION_DOWN_NO_SYNC]);
+       pr_debug("|RSSI MGMT      |%10u|\n", decision_cnt[WRS_DECISION_RSSI_MGMT]);
+       pr_debug("----------------------------\n");
+       pr_debug("\n");
+       pr_debug("Immediate drop ignore = [%u]\n", wrs_params->immediate_drop_ignore);
+}
+
+void cl_wrs_stats_decision_reset(struct cl_wrs_params *wrs_params)
+{
+       memset(&wrs_params->decision_cnt, 0, sizeof(wrs_params->decision_cnt));
+       wrs_params->immediate_drop_ignore = 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.
________________________________


^ permalink raw reply related	[flat|nested] 262+ messages in thread

* [RFC v1 253/256] cl8k: add wrs/wrs_stats.h
  2021-06-17 15:58 [RFC v1 000/256] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (251 preceding siblings ...)
  2021-06-17 16:02 ` [RFC v1 252/256] cl8k: add wrs/wrs_stats.c viktor.barna
@ 2021-06-17 16:02 ` viktor.barna
  2021-06-17 16:02 ` [RFC v1 254/256] cl8k: add wrs/wrs_tables.c viktor.barna
                   ` (4 subsequent siblings)
  257 siblings, 0 replies; 262+ messages in thread
From: viktor.barna @ 2021-06-17 16:02 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Oleksandr Savchenko, Shay Bar, Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

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

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 .../net/wireless/celeno/cl8k/wrs/wrs_stats.h  | 24 +++++++++++++++++++
 1 file changed, 24 insertions(+)
 create mode 100644 drivers/net/wireless/celeno/cl8k/wrs/wrs_stats.h

diff --git a/drivers/net/wireless/celeno/cl8k/wrs/wrs_stats.h b/drivers/net/wireless/celeno/cl8k/wrs/wrs_stats.h
new file mode 100644
index 000000000000..2af2c95bda80
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/wrs/wrs_stats.h
@@ -0,0 +1,24 @@
+/* SPDX-License-Identifier: MIT */
+/* Copyright(c) 2019-2021, Celeno Communications Ltd. */
+
+#ifndef CL_WRS_STATS_H
+#define CL_WRS_STATS_H
+
+#include "wrs/wrs_db.h"
+
+struct cl_hw;
+
+void cl_wrs_stats_per_update(struct cl_wrs_db *wrs_db,
+                            struct cl_wrs_sta *wrs_sta,
+                            struct cl_wrs_params *wrs_params,
+                            struct cl_wrs_tx_cntrs *tx_cntrs);
+void cl_wrs_stats_per_print(struct cl_hw *cl_hw,
+                           struct cl_wrs_sta *wrs_sta,
+                           struct cl_wrs_params *wrs_params);
+void cl_wrs_stats_per_reset(struct cl_wrs_params *wrs_params);
+void cl_wrs_stats_per_init(struct cl_wrs_params *wrs_params);
+void cl_wrs_stats_per_remove(struct cl_wrs_params *wrs_params);
+void cl_wrs_stats_decision_print(struct cl_wrs_params *wrs_params);
+void cl_wrs_stats_decision_reset(struct cl_wrs_params *wrs_params);
+
+#endif /* CL_WRS_STATS_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.
________________________________


^ permalink raw reply related	[flat|nested] 262+ messages in thread

* [RFC v1 254/256] cl8k: add wrs/wrs_tables.c
  2021-06-17 15:58 [RFC v1 000/256] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (252 preceding siblings ...)
  2021-06-17 16:02 ` [RFC v1 253/256] cl8k: add wrs/wrs_stats.h viktor.barna
@ 2021-06-17 16:02 ` viktor.barna
  2021-06-17 16:02 ` [RFC v1 255/256] cl8k: add wrs/wrs_tables.h viktor.barna
                   ` (3 subsequent siblings)
  257 siblings, 0 replies; 262+ messages in thread
From: viktor.barna @ 2021-06-17 16:02 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Oleksandr Savchenko, Shay Bar, Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

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

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 .../net/wireless/celeno/cl8k/wrs/wrs_tables.c | 774 ++++++++++++++++++
 1 file changed, 774 insertions(+)
 create mode 100644 drivers/net/wireless/celeno/cl8k/wrs/wrs_tables.c

diff --git a/drivers/net/wireless/celeno/cl8k/wrs/wrs_tables.c b/drivers/net/wireless/celeno/cl8k/wrs/wrs_tables.c
new file mode 100644
index 000000000000..9349c3251557
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/wrs/wrs_tables.c
@@ -0,0 +1,774 @@
+// SPDX-License-Identifier: MIT
+/* Copyright(c) 2019-2021, Celeno Communications Ltd. */
+
+#include "wrs/wrs_tables.h"
+#include "wrs/wrs.h"
+#include "wrs/wrs_db.h"
+#include "wrs/wrs_sta.h"
+#include "data_rates.h"
+#include "hw.h"
+
+static struct cl_wrs_table
+       ap_rate_table_he[CHNL_BW_MAX][WRS_SS_MAX][WRS_MCS_MAX_HE][WRS_GI_MAX_HE];
+static struct cl_wrs_table
+       ap_rate_table_ht_vht[CHNL_BW_MAX][WRS_SS_MAX][WRS_MCS_MAX_VHT][WRS_GI_MAX_VHT];
+
+/* Rate indexes sorted by data rate */
+static u16 rate_idx_sorted_by_data_rate_he[WRS_HE_RATE_TABLE_SIZE] = {0};
+static u16 rate_idx_sorted_by_data_rate_ht_vht[WRS_HT_VHT_RATE_TABLE_SIZE] = {0};
+
+static void cl_wrs_extract_rate_idx_vht(u16 idx, u8 *bw, u8 *nss, u8 *mcs, u8 *gi)
+{
+       *gi = idx % WRS_GI_MAX_VHT;
+       idx = (idx - *gi) / WRS_GI_MAX_VHT;
+       *mcs = idx % WRS_MCS_MAX_VHT;
+       idx = (idx - *mcs) / WRS_MCS_MAX_VHT;
+       *bw = idx % CHNL_BW_MAX;
+       *nss = (idx - *bw) / WRS_SS_MAX;
+}
+
+static void cl_wrs_extract_rate_idx_he(u16 idx, u8 *bw, u8 *nss, u8 *mcs, u8 *gi)
+{
+       *gi = idx % WRS_GI_MAX_HE;
+       idx = (idx - *gi) / WRS_GI_MAX_HE;
+       *mcs = idx % WRS_MCS_MAX_HE;
+       idx = (idx - *mcs) / WRS_MCS_MAX_HE;
+       *bw = idx % CHNL_BW_MAX;
+       *nss = (idx - *bw) / WRS_SS_MAX;
+}
+
+static void cl_wrs_tables_build_sorted_ht_vht(void)
+{
+       /* Sort according to HT/VHT data rate */
+       u16 i, j;
+       u8 bw1, nss1, mcs1, gi1, bw2, nss2, mcs2, gi2;
+
+       for (i = 0; i < WRS_HT_VHT_RATE_TABLE_SIZE; i++)
+               rate_idx_sorted_by_data_rate_ht_vht[i] = i;
+
+       for (i = 0; i < WRS_HT_VHT_RATE_TABLE_SIZE - 1; i++) {
+               for (j = 0; j < WRS_HT_VHT_RATE_TABLE_SIZE - i - 1; j++) {
+                       cl_wrs_extract_rate_idx_vht(rate_idx_sorted_by_data_rate_ht_vht[j],
+                                                   &bw1, &nss1, &mcs1, &gi1);
+                       cl_wrs_extract_rate_idx_vht(rate_idx_sorted_by_data_rate_ht_vht[j + 1],
+                                                   &bw2, &nss2, &mcs2, &gi2);
+
+                       if (data_rate_ht_vht_x10[bw1][nss1][mcs1][gi1] >
+                           data_rate_ht_vht_x10[bw2][nss2][mcs2][gi2])
+                               swap(rate_idx_sorted_by_data_rate_ht_vht[j],
+                                    rate_idx_sorted_by_data_rate_ht_vht[j + 1]);
+               }
+       }
+}
+
+static void cl_wrs_tables_build_sorted_he(void)
+{
+       /* Sort according to HE data rate */
+       u16 i, j;
+       u8 bw1, nss1, mcs1, gi1, bw2, nss2, mcs2, gi2;
+
+       for (i = 0; i < WRS_HE_RATE_TABLE_SIZE; i++)
+               rate_idx_sorted_by_data_rate_he[i] = i;
+
+       for (i = 0; i < WRS_HE_RATE_TABLE_SIZE - 1; i++) {
+               for (j = 0; j < WRS_HE_RATE_TABLE_SIZE - i - 1; j++) {
+                       cl_wrs_extract_rate_idx_he(rate_idx_sorted_by_data_rate_he[j],
+                                                  &bw1, &nss1, &mcs1, &gi1);
+                       cl_wrs_extract_rate_idx_he(rate_idx_sorted_by_data_rate_he[j + 1],
+                                                  &bw2, &nss2, &mcs2, &gi2);
+
+                       if (data_rate_he_x10[nss1][bw1][mcs1][gi1] >
+                           data_rate_he_x10[nss2][bw2][mcs2][gi2])
+                               swap(rate_idx_sorted_by_data_rate_he[j],
+                                    rate_idx_sorted_by_data_rate_he[j + 1]);
+               }
+       }
+}
+
+static u16 idx_to_offt_ht_vht(u32 bw, u32 nss, u32 mcs, u32 gi)
+{
+       if (bw < CHNL_BW_MAX &&
+           nss < WRS_SS_MAX &&
+           mcs < WRS_MCS_MAX_VHT &&
+           gi < WRS_GI_MAX_VHT)
+               return (gi + WRS_GI_MAX_VHT * (mcs + WRS_MCS_MAX_VHT * (nss + bw * WRS_SS_MAX)));
+       else
+               return -1;
+}
+
+static u16 idx_to_offt_he(u32 bw, u32 nss, u32 mcs, u32 gi)
+{
+       if (bw < CHNL_BW_MAX &&
+           nss < WRS_SS_MAX &&
+           mcs < WRS_MCS_MAX_HE &&
+           gi < WRS_GI_MAX_HE)
+               return (gi + WRS_GI_MAX_HE * (mcs + WRS_MCS_MAX_HE * (nss + bw * WRS_SS_MAX)));
+       else
+               return -1;
+}
+
+static u16 find_down_rate_idx(u32 bw, u32 nss, u32 mcs, u32 gi, u16 *data_rates,
+                             u16 (*idx_to_offt)(u32 bw, u32 nss, u32 mcs, u32 gi))
+{
+       u16 idx;
+
+       if (mcs > 0) {
+               idx = idx_to_offt(bw, nss, mcs - 1, gi);
+               if (data_rates[idx])
+                       return idx;
+               if (mcs > 1)
+                       return idx_to_offt(bw, nss, mcs - 2, gi);
+       }
+
+       if (bw > 0) {
+               idx = idx_to_offt(bw - 1, nss, mcs, gi);
+               if (data_rates[idx])
+                       return idx;
+               if (bw > 1)
+                       return idx_to_offt(bw - 2, nss, mcs, gi);
+       }
+
+       if (nss > 0) {
+               idx = idx_to_offt(bw, nss - 1, mcs, gi);
+               if (data_rates[idx])
+                       return idx;
+               if (nss > 1) {
+                       idx = idx_to_offt(bw, nss - 2, mcs, gi);
+                       if (data_rates[idx])
+                               return idx;
+               }
+       }
+
+       if (gi > 0)
+               return idx_to_offt(bw, nss, mcs, gi - 1);
+
+       return 0;
+}
+
+static u16 find_up_mcs_rate_idx(u32 bw, u32 nss, u32 mcs, u32 gi, u16 *data_rates,
+                               u16 (*idx_to_offt)(u32 bw, u32 nss, u32 mcs, u32 gi))
+{
+       s16 idx = idx_to_offt(bw, nss, mcs + 1, gi);
+
+       if (idx < 0 || !data_rates[idx])
+               idx = idx_to_offt(bw, nss, mcs + 2, gi);
+
+       return (idx < 0) ? WRS_INVALID_RATE : idx;
+}
+
+static u16 find_up_bw_rate_idx(u32 bw, u32 nss, u32 mcs, u32 gi,
+                              u16 *data_rates,
+                              u16 (*idx_to_offt)(u32 bw, u32 nss, u32 mcs, u32 gi))
+{
+       s16 cur_data_rate = data_rates[idx_to_offt(bw, nss, mcs, gi)];
+       s16 min_idx = WRS_INVALID_RATE;
+       s16 idx;
+       s32 min_rate_diff = S32_MAX;
+       s32 rate_diff;
+
+       for (idx = idx_to_offt(++bw, nss, mcs, gi); !(idx < 0);
+            idx = idx_to_offt(bw, nss, --mcs, gi)) {
+               /*
+                * If data_rates[idx] == 0, the difference will be negative,
+                * so the condition below will not hold.
+                * Therefore, no need to check this possiblity specifically.
+                */
+               rate_diff = data_rates[idx] - cur_data_rate;
+               if (rate_diff > 0 &&
+                   rate_diff < min_rate_diff &&
+                   (data_rates[idx] * 100) > (cur_data_rate * WRS_EPR_FACTOR)) {
+                       min_rate_diff = rate_diff;
+                       min_idx = idx;
+               }
+       }
+
+       return min_idx;
+}
+
+static u16 find_up_nss_rate_idx(u32 bw, u32 nss, u32 mcs, u32 gi,
+                               u16 *data_rates,
+                               u16 (*idx_to_offt)(u32 bw, u32 nss, u32 mcs, u32 gi))
+{
+       s16 cur_data_rate = data_rates[idx_to_offt(bw, nss, mcs, gi)];
+       s16 min_idx = WRS_INVALID_RATE;
+       s16 idx;
+       s32 min_rate_diff = S32_MAX;
+       s32 rate_diff;
+
+       for (idx = idx_to_offt(bw, ++nss, mcs, gi); !(idx < 0);
+            idx = idx_to_offt(bw, nss, --mcs, gi)) {
+               /*
+                * If data_rates[idx] == 0, the difference will be negative,
+                * so the condition below will not hold.
+                * Therefore, no need to check this possiblity specifically.
+                */
+               rate_diff = data_rates[idx] - cur_data_rate;
+               if (rate_diff > 0 &&
+                   rate_diff < min_rate_diff &&
+                   (data_rates[idx] * 100) > (cur_data_rate * WRS_EPR_FACTOR)) {
+                       min_rate_diff = rate_diff;
+                       min_idx = idx;
+               }
+       }
+
+       return min_idx;
+}
+
+static u16 find_up_bf_rate_idx(u32 bw, u32 nss, u32 mcs, u32 gi,
+                              u16 *data_rates,
+                              u16 (*idx_to_offt)(u32 bw, u32 nss, u32 mcs, u32 gi))
+{
+       s16 cur_data_rate = data_rates[idx_to_offt(bw, nss, mcs, gi)];
+       s16 min_idx = WRS_INVALID_RATE;
+       s16 idx;
+       s32 min_rate_diff = S32_MAX;
+       s16 rate_diff;
+
+       for (idx = idx_to_offt(bw, --nss, mcs, gi); !(idx < 0);
+            idx = idx_to_offt(bw, nss, ++mcs, gi)) {
+               /*
+                * If data_rates[idx] == 0, the difference will be negative,
+                * so the condition below will not hold.
+                * Therefore, no need to check this possiblity specifically.
+                */
+               rate_diff = data_rates[idx] - cur_data_rate;
+               if (rate_diff > 0 &&
+                   rate_diff < min_rate_diff &&
+                   (data_rates[idx] * 100) > (cur_data_rate * WRS_EPR_FACTOR)) {
+                       min_rate_diff = rate_diff;
+                       min_idx = idx;
+               }
+       }
+
+       return min_idx;
+}
+
+static u16 find_up_gi_rate_idx(u32 bw, u32 nss, u32 mcs, u32 gi,
+                              u16 (*idx_to_offt)(u32 bw, u32 nss, u32 mcs, u32 gi))
+{
+       s16 idx = idx_to_offt(bw, nss, mcs, gi + 1);
+
+       return (idx < 0) ? WRS_INVALID_RATE : idx;
+}
+
+static void _cl_wrs_tables_init(struct cl_wrs_table *ap_rate_table,
+                               u16 *data_rates,
+                               u32 bw, u32 nss, u32 mcs, u32 gi,
+                               u16 (*idx_to_offt)(u32 bw, u32 nss, u32 mcs, u32 gi))
+{
+       struct cl_wrs_table *cur_entry = NULL;
+       int i = 0;
+       u16 offt = idx_to_offt(bw, nss, mcs, gi);
+
+       cur_entry = &ap_rate_table[offt];
+       cur_entry->rate.bw = bw;
+       cur_entry->rate.nss = nss;
+       cur_entry->rate.mcs = mcs;
+       cur_entry->rate.gi = gi;
+
+       /* If current rate is invalid, mark it as such and skip it. */
+       if (!data_rates[offt]) {
+               cur_entry->rate_down.rate_idx = WRS_INVALID_RATE;
+               cur_entry->rate_down.time_th = WRS_MSEC_WEIGHT_MAX_DOWN;
+
+               for (i = 0; i < WRS_TABLE_NODE_UP_MAX; i++) {
+                       cur_entry->rate_up[i].rate_idx = WRS_INVALID_RATE;
+                       cur_entry->rate_up[i].time_th = WRS_MSEC_WEIGHT_MAX_UP;
+               }
+
+               return;
+       }
+
+       cur_entry->rate_down.rate_idx =
+               find_down_rate_idx(bw, nss, mcs, gi, data_rates, idx_to_offt);
+       cur_entry->rate_up[WRS_TABLE_NODE_UP_MCS].rate_idx =
+               find_up_mcs_rate_idx(bw, nss, mcs, gi, data_rates, idx_to_offt);
+       cur_entry->rate_up[WRS_TABLE_NODE_UP_BW].rate_idx =
+               find_up_bw_rate_idx(bw, nss, mcs, gi, data_rates, idx_to_offt);
+       cur_entry->rate_up[WRS_TABLE_NODE_UP_NSS].rate_idx =
+               find_up_nss_rate_idx(bw, nss, mcs, gi, data_rates, idx_to_offt);
+       cur_entry->rate_up[WRS_TABLE_NODE_UP_BF].rate_idx =
+               find_up_bf_rate_idx(bw, nss, mcs, gi, data_rates, idx_to_offt);
+       cur_entry->rate_up[WRS_TABLE_NODE_UP_GI].rate_idx =
+               find_up_gi_rate_idx(bw, nss, mcs, gi, idx_to_offt);
+
+       cur_entry->rate_down.time_th = WRS_INIT_MSEC_WEIGHT_DOWN;
+
+       for (i = 0; i < WRS_TABLE_NODE_UP_MAX; i++)
+               cur_entry->rate_up[i].time_th =
+                       (cur_entry->rate_up[i].rate_idx == WRS_INVALID_RATE) ?
+                       WRS_MSEC_WEIGHT_MAX_UP : WRS_INIT_MSEC_WEIGHT_UP;
+}
+
+static void cl_wrs_tables_init(u8 mode)
+{
+       u32 bw, nss, mcs, gi;
+       u32 max_bw, max_nss, max_mcs, max_gi;
+       u16 (*idx_to_offt)(u32 bw, u32 nss, u32 mcs, u32 gi);
+       struct cl_wrs_table *ap_rate_table = NULL;
+       u16 *data_rates = NULL;
+
+       if (mode == WRS_MODE_HE) {
+               idx_to_offt = idx_to_offt_he;
+               max_bw = CHNL_BW_MAX;
+               max_nss = WRS_SS_MAX;
+               max_mcs = WRS_MCS_MAX_HE;
+               max_gi = WRS_GI_MAX_HE;
+               ap_rate_table = (struct cl_wrs_table *)ap_rate_table_he;
+               data_rates = (u16 *)data_rate_he_x10;
+       } else if (mode == WRS_MODE_VHT) {
+               idx_to_offt = idx_to_offt_ht_vht;
+               max_bw = CHNL_BW_MAX;
+               max_nss = WRS_SS_MAX;
+               max_mcs = WRS_MCS_MAX_VHT;
+               max_gi = WRS_GI_MAX_VHT;
+               ap_rate_table = (struct cl_wrs_table *)ap_rate_table_ht_vht;
+               data_rates = (u16 *)data_rate_ht_vht_x10;
+       } else {
+               return;
+       }
+
+       for (bw = 0; bw < max_bw; bw++)
+               for (nss = 0; nss < max_nss; nss++)
+                       for (mcs = 0; mcs < max_mcs; mcs++)
+                               for (gi = 0; gi < max_gi; gi++)
+                                       _cl_wrs_tables_init(ap_rate_table,
+                                                           data_rates,
+                                                           bw,
+                                                           nss,
+                                                           mcs,
+                                                           gi,
+                                                           idx_to_offt);
+}
+
+void cl_wrs_tables_global_build(void)
+{
+       cl_wrs_tables_init(WRS_MODE_HE);
+       cl_wrs_tables_init(WRS_MODE_VHT);
+       cl_wrs_tables_build_sorted_he();
+       cl_wrs_tables_build_sorted_ht_vht();
+}
+
+void cl_wrs_tables_print(struct cl_hw *cl_hw, struct cl_wrs_params *wrs_params)
+{
+       struct cl_wrs_table *table;
+       u16 i = 0, idx_dn = 0, idx_up1 = 0, idx_up2 = 0, idx_up3 = 0, idx_up4 = 0, idx_up5 = 0;
+
+       pr_debug("\n");
+       pr_debug("                 -------------------------------------------------------------------------------\n");
+       pr_debug("                 ||   Down    || Up #1 mcs || Up #2 bw  || Up #3 ss  || Up #4 bf  || Up #5 gi  |\n");
+       pr_debug("-----------------||-----------||-----------||-----------||-----------||-----------||-----------|\n");
+       pr_debug("|idx|bw|ss|mcs|gi|| idx | thr || idx | thr || idx | thr || idx | thr || idx | thr || idx | thr |\n");
+       pr_debug("|----------------||-----------||-----------||-----------||-----------||-----------||-----------|\n");
+
+       for (i = 0; i < wrs_params->table_size; i++) {
+               table = &wrs_params->table[i];
+
+               idx_dn = table->rate_down.rate_idx;
+               idx_up1 = table->rate_up[WRS_TABLE_NODE_UP_MCS].rate_idx;
+               idx_up2 = table->rate_up[WRS_TABLE_NODE_UP_BW].rate_idx;
+               idx_up3 = table->rate_up[WRS_TABLE_NODE_UP_NSS].rate_idx;
+               idx_up4 = table->rate_up[WRS_TABLE_NODE_UP_BF].rate_idx;
+               idx_up5 = table->rate_up[WRS_TABLE_NODE_UP_GI].rate_idx;
+
+               pr_debug("|%3u|%2u|%2u|%3u|%2u||%5u|%5u||%5u|%5u||%5u|%5u||%5u|%5u||%5u|%5u||%5u|%5u|\n",
+                        i,
+                        table->rate.bw, table->rate.nss, table->rate.mcs, table->rate.gi,
+                        idx_dn, table->rate_down.time_th,
+                        idx_up1, table->rate_up[WRS_TABLE_NODE_UP_MCS].time_th,
+                        idx_up2, table->rate_up[WRS_TABLE_NODE_UP_BW].time_th,
+                        idx_up3, table->rate_up[WRS_TABLE_NODE_UP_NSS].time_th,
+                        idx_up4, table->rate_up[WRS_TABLE_NODE_UP_BF].time_th,
+                        idx_up5, table->rate_up[WRS_TABLE_NODE_UP_GI].time_th);
+       }
+
+       pr_debug("------------------------------------------------------------------------------------------------\n\n");
+}
+
+void cl_wrs_tables_reset(struct cl_wrs_db *wrs_db, struct cl_wrs_sta *wrs_sta,
+                        struct cl_wrs_params *wrs_params)
+{
+       struct cl_wrs_table_node *rate_up;
+       u16 rate_idx = 0;
+       u8 up_idx = 0;
+
+       for (rate_idx = 0; rate_idx < wrs_params->table_size; rate_idx++) {
+               if (wrs_params->table[rate_idx].rate_down.rate_idx != WRS_INVALID_RATE)
+                       wrs_params->table[rate_idx].rate_down.time_th = WRS_INIT_MSEC_WEIGHT_DOWN;
+               else
+                       wrs_params->table[rate_idx].rate_down.time_th = wrs_db->time_th_max_down;
+
+               wrs_params->table[rate_idx].rate_down.quick_up_check = false;
+
+               for (up_idx = 0; up_idx < WRS_TABLE_NODE_UP_MAX; up_idx++) {
+                       rate_up = &wrs_params->table[rate_idx].rate_up[up_idx];
+
+                       if (rate_up->rate_idx != WRS_INVALID_RATE)
+                               rate_up->time_th = WRS_INIT_MSEC_WEIGHT_UP;
+                       else
+                               rate_up->time_th = wrs_db->time_th_max_up;
+
+                       rate_up->quick_up_check = false;
+               }
+
+               wrs_params->table[rate_idx].frames_total = 0;
+               wrs_params->table[rate_idx].ba_not_rcv_total = 0;
+               wrs_params->table[rate_idx].epr_acc = 0;
+       }
+}
+
+static bool cl_wrs_is_rate_valid_he(struct cl_hw *cl_hw, struct cl_wrs_sta *wrs_sta,
+                                   u8 bw, u8 nss, u8 mcs, u8 gi)
+{
+       /* Disable rates according to ce_he_mcs_nss_supp_tx */
+       if ((cl_hw->conf->ce_he_mcs_nss_supp_tx[nss] + 1) <= mcs)
+               return false;
+
+       return true;
+}
+
+static bool cl_wrs_is_rate_valid_vht(struct cl_hw *cl_hw, u8 bw, u8 nss, u8 mcs)
+{
+       /* Disable BW160 */
+       if (bw == CHNL_BW_160)
+               return false;
+
+       /* Disable VHT invalid rates (MCS9 20M 1SS, MCS9 20M 2SS, MCS6 80M 3SS, MCS9 20M 4SS) */
+       if (bw == CHNL_BW_20 && mcs == WRS_MCS_9)
+               if (nss == WRS_SS_1 || nss == WRS_SS_2 || nss == WRS_SS_4)
+                       return false;
+
+       if (bw == CHNL_BW_80 && mcs == WRS_MCS_6 && nss == WRS_SS_3)
+               return false;
+
+       /* Disable rates according to ce_vht_mcs_nss_supp_tx */
+       if ((cl_hw->conf->ce_vht_mcs_nss_supp_tx[nss] + 1) <= mcs)
+               return false;
+
+       return true;
+}
+
+static bool cl_wrs_is_rate_valid(struct cl_hw *cl_hw, struct cl_wrs_sta *wrs_sta,
+                                u8 mode, u8 bw, u8 nss, u8 mcs, u8 gi)
+{
+       struct cl_wrs_db *wrs_db = &cl_hw->wrs_db;
+
+       if (gi > wrs_db->max_cap.gi || gi > wrs_sta->gi_cap[bw])
+               return false;
+
+       if (mode == WRS_MODE_HE)
+               return cl_wrs_is_rate_valid_he(cl_hw, wrs_sta, bw, nss, mcs, gi);
+
+       if (mode == WRS_MODE_VHT)
+               return cl_wrs_is_rate_valid_vht(cl_hw, bw, nss, mcs);
+
+       return true;
+}
+
+static bool cl_wrs_is_rate_supported(u64 *rate_bitmap, u8 bw, u8 nss, u8 mcs)
+{
+       u8 rate_idx = mcs + (nss * WRS_MCS_MAX);
+       u64 mask = BIT(rate_idx);
+
+       return ((rate_bitmap[bw] & mask) ? true : false);
+}
+
+static bool cl_wrs_tables_is_up_invalid(struct cl_wrs_table *table)
+{
+       /*
+        * The UP_GI is not part of this if condition, because we would
+        * like to set the same up candidate for LGI & SGI (except the
+        * up from LGI to SGI).
+        */
+       return ((table->rate_up[WRS_TABLE_NODE_UP_MCS].rate_idx == WRS_INVALID_RATE) &&
+               (table->rate_up[WRS_TABLE_NODE_UP_BW].rate_idx == WRS_INVALID_RATE) &&
+               (table->rate_up[WRS_TABLE_NODE_UP_NSS].rate_idx == WRS_INVALID_RATE) &&
+               (table->rate_up[WRS_TABLE_NODE_UP_BF].rate_idx == WRS_INVALID_RATE));
+}
+
+static int cl_wrs_tables_max(struct cl_hw *cl_hw, struct cl_wrs_sta *wrs_sta,
+                            u8 *max_bw, u8 *max_nss, u8 *max_mcs, u8 *max_gi)
+{
+       *max_bw = wrs_sta->max_rate_cap.bw;
+       *max_nss = wrs_sta->smps_enable ? WRS_SS_1 : wrs_sta->max_rate_cap.nss;
+
+       switch (wrs_sta->mode) {
+       case WRS_MODE_CCK:
+               *max_mcs = WRS_MCS_3;
+               *max_gi = WRS_GI_LONG;
+               break;
+       case WRS_MODE_OFDM:
+               *max_mcs = WRS_MCS_7;
+               *max_gi = WRS_GI_LONG;
+               break;
+       case WRS_MODE_HT:
+               *max_mcs = WRS_MCS_7;
+               *max_gi = WRS_GI_SHORT;
+               break;
+       case WRS_MODE_VHT:
+               *max_mcs = WRS_MCS_9;
+               *max_gi = WRS_GI_SHORT;
+               break;
+       case WRS_MODE_HE:
+               *max_mcs = WRS_MCS_11;
+               *max_gi = WRS_GI_VSHORT;
+
+               if (!cl_hw->conf->ce_txldpc_en) {
+                       struct cl_wrs_db *wrs_db = &cl_hw->wrs_db;
+
+                       wrs_pr_verbose(wrs_db,
+                                      "[WRS] TX LDPC disabled: limit BW to 20MHz and MCS to 9\n");
+                       *max_mcs = WRS_MCS_9;
+                       *max_bw = CHNL_BW_20;
+               }
+               break;
+       default:
+               return -1;
+       }
+
+       return 0;
+}
+
+void cl_wrs_tables_build(struct cl_hw *cl_hw, struct cl_wrs_sta *wrs_sta,
+                        struct cl_wrs_params *wrs_params)
+{
+       struct cl_wrs_db *wrs_db = &cl_hw->wrs_db;
+       u8 bw = 0;
+       u8 nss = 0;
+       u8 mcs = 0;
+       u8 gi = 0;
+       u8 max_bw = 0;
+       u8 max_nss = 0;
+       u8 max_mcs = 0;
+       u8 max_gi = 0;
+       u8 up_idx = 0;
+       u16 rate_idx = 0;
+       u16 new_rate_idx = 0;
+       u16 tmp_rate_idx = 0;
+       u16 max_table_size = 0;
+       u16 new_table_size = 0;
+       u16 (*idx_to_offt)(u32 bw, u32 nss, u32 mcs, u32 gi);
+       u16 *rate_idx_sorted_by_data_rate;
+       struct cl_wrs_table *ap_rate_table;
+       struct cl_wrs_table *new_table = NULL;
+       struct cl_wrs_table_validity *valid_rates = NULL;
+
+       if (cl_wrs_tables_max(cl_hw, wrs_sta, &max_bw, &max_nss, &max_mcs, &max_gi))
+               return;
+
+       if (wrs_sta->mode == WRS_MODE_HE) {
+               max_table_size = WRS_HE_RATE_TABLE_SIZE;
+               idx_to_offt = idx_to_offt_he;
+               ap_rate_table = (struct cl_wrs_table *)ap_rate_table_he;
+               rate_idx_sorted_by_data_rate = rate_idx_sorted_by_data_rate_he;
+       } else {
+               max_table_size = WRS_HT_VHT_RATE_TABLE_SIZE;
+               idx_to_offt = idx_to_offt_ht_vht;
+               ap_rate_table = (struct cl_wrs_table *)ap_rate_table_ht_vht;
+               rate_idx_sorted_by_data_rate = rate_idx_sorted_by_data_rate_ht_vht;
+       }
+
+       valid_rates = kzalloc(max_table_size * sizeof(struct cl_wrs_table_validity), GFP_ATOMIC);
+       if (!valid_rates)
+               goto out;
+
+       wrs_sta->max_rate_cap.mcs = WRS_MCS_0;
+       wrs_sta->max_rate_cap.gi = WRS_GI_LONG;
+
+       for (bw = 0; bw <= max_bw; bw++) {
+               for (nss = 0; nss <= max_nss; nss++) {
+                       for (mcs = 0; mcs <= max_mcs; mcs++) {
+                               for (gi = 0; gi <= max_gi; gi++) {
+                                       rate_idx = idx_to_offt(bw, nss, mcs, gi);
+                                       valid_rates[rate_idx].is_valid =
+                                               cl_wrs_is_rate_supported(wrs_sta->supported_rates,
+                                                                        bw, nss, mcs) &&
+                                               cl_wrs_is_rate_supported(wrs_db->ap_supported_rates,
+                                                                        bw, nss, mcs) &&
+                                               cl_wrs_is_rate_valid(cl_hw, wrs_sta, wrs_sta->mode,
+                                                                    bw, nss, mcs, gi);
+
+                                       if (!valid_rates[rate_idx].is_valid)
+                                               continue;
+
+                                       valid_rates[rate_idx].new_rate_idx = new_table_size;
+                                       new_table_size++;
+
+                                       if (mcs > wrs_sta->max_rate_cap.mcs)
+                                               wrs_sta->max_rate_cap.mcs = mcs;
+
+                                       if (gi > wrs_sta->max_rate_cap.gi)
+                                               wrs_sta->max_rate_cap.gi = gi;
+                               }
+                       }
+               }
+       }
+
+       if (new_table_size == 0) {
+               /* Error - size of table is 0, add single rate (mcs 0, 1 SS, bw 20 Mhz) */
+               wrs_pr_err(wrs_db, "[WRS] Table build error - Size of table is 0\n");
+               cl_wrs_sta_set_supported_rate(wrs_sta, CHNL_BW_20, WRS_SS_1, WRS_MCS_0);
+               valid_rates[0].new_rate_idx = 0;
+               valid_rates[0].is_valid = 1;
+               new_table_size = 1;
+       }
+
+       new_table = kzalloc(new_table_size * sizeof(struct cl_wrs_table), GFP_ATOMIC);
+
+       if (!new_table)
+               goto out;
+
+       for (rate_idx = 0; rate_idx < max_table_size; rate_idx++) {
+               if (!valid_rates[rate_idx].is_valid)
+                       continue;
+
+               memcpy(new_table + new_rate_idx,
+                      ap_rate_table + rate_idx,
+                      sizeof(struct cl_wrs_table));
+
+               /* Set down rate */
+               tmp_rate_idx = ap_rate_table[rate_idx].rate_down.rate_idx;
+
+               while ((!valid_rates[tmp_rate_idx].is_valid) &&
+                      (ap_rate_table[tmp_rate_idx].rate_down.rate_idx != tmp_rate_idx))
+                       tmp_rate_idx = ap_rate_table[tmp_rate_idx].rate_down.rate_idx;
+
+               if (valid_rates[tmp_rate_idx].is_valid) {
+                       new_table[new_rate_idx].rate_down.rate_idx =
+                               valid_rates[tmp_rate_idx].new_rate_idx;
+               } else {
+                       u16 i = 0;
+                       u16 down_idx = 0;
+                       u16 down_rate_idx = new_rate_idx;
+
+                       while (new_table[new_rate_idx].rate_down.rate_idx !=
+                              rate_idx_sorted_by_data_rate[i]) {
+                               down_idx = rate_idx_sorted_by_data_rate[i];
+
+                               if (valid_rates[down_idx].is_valid)
+                                       down_rate_idx = valid_rates[down_idx].new_rate_idx;
+                               i++;
+                       }
+
+                       new_table[new_rate_idx].rate_down.rate_idx = down_rate_idx;
+               }
+
+               /* Set up rates */
+               for (up_idx = 0; up_idx < WRS_TABLE_NODE_UP_MAX; up_idx++) {
+                       tmp_rate_idx = new_table[new_rate_idx].rate_up[up_idx].rate_idx;
+
+                       if (tmp_rate_idx != WRS_INVALID_RATE &&
+                           valid_rates[tmp_rate_idx].is_valid)
+                               new_table[new_rate_idx].rate_up[up_idx].rate_idx =
+                                       valid_rates[tmp_rate_idx].new_rate_idx;
+                       else
+                               new_table[new_rate_idx].rate_up[up_idx].rate_idx = WRS_INVALID_RATE;
+               }
+
+               /*
+                * In case all the UP rates are invalid, find one available UP
+                * rate based on PHY rate
+                */
+               if (cl_wrs_tables_is_up_invalid(&new_table[new_rate_idx])) {
+                       u16 i = 0;
+
+                       for (i = 0; i < max_table_size; i++)
+                               if (rate_idx == rate_idx_sorted_by_data_rate[i])
+                                       break;
+
+                       i++;
+
+                       while (i < max_table_size) {
+                               tmp_rate_idx = rate_idx_sorted_by_data_rate[i];
+                               if (!valid_rates[tmp_rate_idx].is_valid) {
+                                       i++;
+                                       continue;
+                               }
+
+                               new_table[new_rate_idx].rate_up[WRS_TABLE_NODE_UP_MCS].rate_idx =
+                                       valid_rates[tmp_rate_idx].new_rate_idx;
+                               break;
+                       }
+               }
+
+               new_rate_idx++;
+       }
+
+       if (wrs_params->table) {
+               /*
+                * Copy epr_acc, frames_total and ba_not_rcv_total
+                * from the old table to the new table.
+                * Also, if initial_rate_idx is set, find the new
+                * value in the new table.
+                */
+               u16 old_rate_idx = 0;
+
+               for (rate_idx = 0; rate_idx < new_table_size; rate_idx++) {
+                       old_rate_idx = cl_wrs_tables_find_rate_idx(wrs_params,
+                                                                  new_table[rate_idx].rate.bw,
+                                                                  new_table[rate_idx].rate.nss,
+                                                                  new_table[rate_idx].rate.mcs,
+                                                                  new_table[rate_idx].rate.gi);
+
+                       if (old_rate_idx == WRS_INVALID_RATE)
+                               continue;
+
+                       new_table[rate_idx].epr_acc =
+                               wrs_params->table[old_rate_idx].epr_acc;
+                       new_table[rate_idx].frames_total =
+                               wrs_params->table[old_rate_idx].frames_total;
+                       new_table[rate_idx].ba_not_rcv_total =
+                               wrs_params->table[old_rate_idx].ba_not_rcv_total;
+               }
+
+               kfree(wrs_params->table);
+       }
+
+       wrs_params->table = new_table;
+       wrs_params->table_size = new_table_size;
+
+       if (wrs_params->rate_idx != WRS_INVALID_RATE) {
+               /*
+                * Check if current rate is included in the new table.
+                * If not select a rate from the new table accroding to rssi.
+                */
+               struct cl_wrs_tx_params *tx_params = &wrs_params->tx_params;
+
+               rate_idx = cl_wrs_tables_find_rate_idx(wrs_params,
+                                                      tx_params->bw, tx_params->nss,
+                                                      tx_params->mcs, tx_params->gi);
+
+               if (rate_idx != WRS_INVALID_RATE) {
+                       wrs_params->rate_idx = rate_idx;
+               } else {
+                       if (wrs_params->is_fixed_rate) {
+                               wrs_params->is_fixed_rate = false;
+                               wrs_pr_verbose(wrs_db,
+                                              "[WRS] Disable fixed rate for station %u\n",
+                                              wrs_sta->sta_idx);
+                       }
+
+                       cl_wrs_sta_select_first_rate(cl_hw, wrs_db, wrs_sta, wrs_params);
+                       cl_wrs_tx_cntrs_reset(wrs_sta, wrs_params);
+               }
+       }
+
+out:
+       kfree(valid_rates);
+}
+
+u16 cl_wrs_tables_find_rate_idx(struct cl_wrs_params *wrs_params,
+                               u8 bw, u8 nss, u8 mcs, u8 gi)
+{
+       struct cl_wrs_table *table = wrs_params->table;
+       u16 rate_idx = 0;
+
+       for (rate_idx = 0; rate_idx < wrs_params->table_size; rate_idx++)
+               if (bw == table[rate_idx].rate.bw &&
+                   nss == table[rate_idx].rate.nss &&
+                   mcs == table[rate_idx].rate.mcs &&
+                   gi == table[rate_idx].rate.gi)
+                       return rate_idx;
+
+       return WRS_INVALID_RATE;
+}
--
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.
________________________________


^ permalink raw reply related	[flat|nested] 262+ messages in thread

* [RFC v1 255/256] cl8k: add wrs/wrs_tables.h
  2021-06-17 15:58 [RFC v1 000/256] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (253 preceding siblings ...)
  2021-06-17 16:02 ` [RFC v1 254/256] cl8k: add wrs/wrs_tables.c viktor.barna
@ 2021-06-17 16:02 ` viktor.barna
  2021-06-17 16:02 ` [RFC v1 256/256] wireless: add Celeno vendor viktor.barna
                   ` (2 subsequent siblings)
  257 siblings, 0 replies; 262+ messages in thread
From: viktor.barna @ 2021-06-17 16:02 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Oleksandr Savchenko, Shay Bar, Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

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

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 .../net/wireless/celeno/cl8k/wrs/wrs_tables.h | 76 +++++++++++++++++++
 1 file changed, 76 insertions(+)
 create mode 100644 drivers/net/wireless/celeno/cl8k/wrs/wrs_tables.h

diff --git a/drivers/net/wireless/celeno/cl8k/wrs/wrs_tables.h b/drivers/net/wireless/celeno/cl8k/wrs/wrs_tables.h
new file mode 100644
index 000000000000..250755533f28
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/wrs/wrs_tables.h
@@ -0,0 +1,76 @@
+/* SPDX-License-Identifier: MIT */
+/* Copyright(c) 2019-2021, Celeno Communications Ltd. */
+
+#ifndef CL_WRS_TABLES_H
+#define CL_WRS_TABLES_H
+
+#include <linux/types.h>
+
+/* Rate Table Size */
+#define WRS_HE_RATE_TABLE_SIZE     (WRS_MCS_MAX_HE * WRS_SS_MAX * CHNL_BW_MAX * WRS_GI_MAX_HE)
+#define WRS_HT_VHT_RATE_TABLE_SIZE (WRS_MCS_MAX_VHT * WRS_SS_MAX * CHNL_BW_MAX * WRS_GI_MAX_VHT)
+
+/* Initial Thresholds */
+#define WRS_INIT_MSEC_WEIGHT_DOWN  (WRS_MAINTENANCE_PERIOD_MS * 3) /* Msec */
+#define WRS_INIT_MSEC_WEIGHT_UP    (WRS_MAINTENANCE_PERIOD_MS * 3) /* Msec */
+
+#define WRS_MSEC_WEIGHT_MIN        (WRS_MAINTENANCE_PERIOD_MS * 2) /* Msec */
+#define WRS_MSEC_WEIGHT_MAX_UP     30000 /* Msec */
+#define WRS_MSEC_WEIGHT_MAX_DOWN   4000  /* Msec */
+#define WRS_MSEC_STEP_DOWN         5000  /* Msec */
+#define WRS_MSEC_STEP_UP_SAME      1000  /* Msec */
+#define WRS_INVALID_RATE           ((u16)(~0))
+
+enum cl_wrs_table_node_up {
+       WRS_TABLE_NODE_UP_MCS,
+       WRS_TABLE_NODE_UP_BW,
+       WRS_TABLE_NODE_UP_NSS,
+       WRS_TABLE_NODE_UP_BF,
+       WRS_TABLE_NODE_UP_GI,
+
+       WRS_TABLE_NODE_UP_MAX
+};
+
+struct cl_wrs_table_validity {
+       bool is_valid;
+       u16 new_rate_idx;
+};
+
+struct cl_wrs_table_node {
+       u16 rate_idx;
+       u16 time_th;
+       bool quick_up_check;
+};
+
+struct cl_wrs_rate {
+       u16 mcs : 4,
+           nss : 3,
+           bw  : 2,
+           gi  : 2,
+           rsv : 2;
+};
+
+struct cl_wrs_table {
+       struct cl_wrs_rate rate;
+       struct cl_wrs_table_node rate_down;
+       struct cl_wrs_table_node rate_up[WRS_TABLE_NODE_UP_MAX];
+       u32 frames_total;
+       u32 ba_not_rcv_total;
+       u64 epr_acc;
+};
+
+struct cl_hw;
+struct cl_wrs_db;
+struct cl_wrs_sta;
+struct cl_wrs_params;
+
+void cl_wrs_tables_global_build(void);
+void cl_wrs_tables_print(struct cl_hw *cl_hw, struct cl_wrs_params *wrs_params);
+void cl_wrs_tables_reset(struct cl_wrs_db *wrs_db, struct cl_wrs_sta *wrs_sta,
+                        struct cl_wrs_params *wrs_params);
+void cl_wrs_tables_build(struct cl_hw *cl_hw, struct cl_wrs_sta *wrs_sta,
+                        struct cl_wrs_params *wrs_params);
+u16 cl_wrs_tables_find_rate_idx(struct cl_wrs_params *wrs_params,
+                               u8 bw, u8 nss, u8 mcs, u8 gi);
+
+#endif /* CL_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.
________________________________


^ permalink raw reply related	[flat|nested] 262+ messages in thread

* [RFC v1 256/256] wireless: add Celeno vendor
  2021-06-17 15:58 [RFC v1 000/256] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (254 preceding siblings ...)
  2021-06-17 16:02 ` [RFC v1 255/256] cl8k: add wrs/wrs_tables.h viktor.barna
@ 2021-06-17 16:02 ` viktor.barna
  2021-06-17 17:23 ` [RFC v1 000/256] wireless: cl8k driver for Celeno IEEE 802.11ax devices Johannes Berg
  2021-06-19  6:39 ` Kalle Valo
  257 siblings, 0 replies; 262+ messages in thread
From: viktor.barna @ 2021-06-17 16:02 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Oleksandr Savchenko, Shay Bar, Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

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

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 drivers/net/wireless/Kconfig  | 1 +
 drivers/net/wireless/Makefile | 1 +
 2 files changed, 2 insertions(+)

diff --git a/drivers/net/wireless/Kconfig b/drivers/net/wireless/Kconfig
index 7add2002ff4c..444c81e3da06 100644
--- a/drivers/net/wireless/Kconfig
+++ b/drivers/net/wireless/Kconfig
@@ -35,6 +35,7 @@ source "drivers/net/wireless/st/Kconfig"
 source "drivers/net/wireless/ti/Kconfig"
 source "drivers/net/wireless/zydas/Kconfig"
 source "drivers/net/wireless/quantenna/Kconfig"
+source "drivers/net/wireless/celeno/Kconfig"

 config PCMCIA_RAYCS
        tristate "Aviator/Raytheon 2.4GHz wireless support"
diff --git a/drivers/net/wireless/Makefile b/drivers/net/wireless/Makefile
index 80b324499786..3eb57351d0e5 100644
--- a/drivers/net/wireless/Makefile
+++ b/drivers/net/wireless/Makefile
@@ -20,6 +20,7 @@ obj-$(CONFIG_WLAN_VENDOR_ST) += st/
 obj-$(CONFIG_WLAN_VENDOR_TI) += ti/
 obj-$(CONFIG_WLAN_VENDOR_ZYDAS) += zydas/
 obj-$(CONFIG_WLAN_VENDOR_QUANTENNA) += quantenna/
+obj-$(CONFIG_WLAN_VENDOR_CELENO) += celeno/

 # 16-bit wireless PCMCIA client drivers
 obj-$(CONFIG_PCMCIA_RAYCS)     += ray_cs.o
--
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.
________________________________


^ permalink raw reply related	[flat|nested] 262+ messages in thread

* Re: [RFC v1 000/256] wireless: cl8k driver for Celeno IEEE 802.11ax devices
  2021-06-17 15:58 [RFC v1 000/256] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (255 preceding siblings ...)
  2021-06-17 16:02 ` [RFC v1 256/256] wireless: add Celeno vendor viktor.barna
@ 2021-06-17 17:23 ` Johannes Berg
  2022-05-22 17:51   ` viktor.barna
  2021-06-19  6:39 ` Kalle Valo
  257 siblings, 1 reply; 262+ messages in thread
From: Johannes Berg @ 2021-06-17 17:23 UTC (permalink / raw)
  To: viktor.barna, linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Oleksandr Savchenko, Shay Bar

Hi Viktor,

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

Wow, umm, seems big! LOC maybe not, but # of files ... not that easy to
review.

I've only looked a little while now, but for making this easier to
review it would be nice to split it into a "minimum viable product"
first, i.e. have a much smaller driver, and this is probably not an
exhaustive list:

 * without command line interfaces with string parsing built into the
   kernel
   (OK, that's probably something that will never go upstream anyway)
 * Kconfig vs. code inconsistencies cleaned up, you have a TON of
   CONFIG_* ifdefs that don't even exist and can never be set, so remove
   the code, at least for now?
 * remove wrappers like cl_snprintf(), though that seems part of all
   those command line interfaces built into the driver
 * consider joining some of the many header files into bigger chunks,
   header files that are 50% boilerplate aren't really all that useful
 * namespace your things better - e.g. "is_ipv4_packet" and friends?
   (why do you even care?)
 * remove all vendor commands for now, and read the vendor commands
   upstreaming documentation before re-introducing them
   https://wireless.wiki.kernel.org/en/developers/documentation/nl80211#vendor-specific_api
 * remove utils/string.c, obviously, use kernel stuff directly or
   improve where needed I guess - but likely all part of the weird CLI-
   in-kernel stuff?
 * remove abstraction layers like cl_timer
 * what's this VNS stuff? doesn't look like it belongs into a driver
   (a mac80211 one at that!)
 * bitfields in endian-safe code are generally frowned upon, so you
   shouldn't need cl_are_host_bits_le(). And also cl_are_host_bits_be()?
   What?
 * Use ERR_PTR() and friends, instead of out pointer parameters.


You'll probably also notice a lot of issues yourself if you take a step
back and actually read your patches, rather than just the code they were
generated from, e.g. the Kconfig confusion I mentioned below.

Thanks,
johannes


^ permalink raw reply	[flat|nested] 262+ messages in thread

* Re: [RFC v1 000/256] wireless: cl8k driver for Celeno IEEE 802.11ax devices
  2021-06-17 15:58 [RFC v1 000/256] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (256 preceding siblings ...)
  2021-06-17 17:23 ` [RFC v1 000/256] wireless: cl8k driver for Celeno IEEE 802.11ax devices Johannes Berg
@ 2021-06-19  6:39 ` Kalle Valo
  2022-05-13 21:11   ` viktor.barna
  257 siblings, 1 reply; 262+ messages in thread
From: Kalle Valo @ 2021-06-19  6:39 UTC (permalink / raw)
  To: viktor.barna
  Cc: linux-wireless, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Oleksandr Savchenko, Shay Bar

viktor.barna@celeno.com writes:

> From: Viktor Barna <viktor.barna@celeno.com>
>
> 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.

[...]

> ________________________________ 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. ________________________________
>

I'm not going to review a driver with a disclaimer like this.

-- 
https://patchwork.kernel.org/project/linux-wireless/list/

https://wireless.wiki.kernel.org/en/developers/documentation/submittingpatches

^ permalink raw reply	[flat|nested] 262+ messages in thread

* Re: [RFC v1 000/256] wireless: cl8k driver for Celeno IEEE 802.11ax devices
  2021-06-19  6:39 ` Kalle Valo
@ 2022-05-13 21:11   ` viktor.barna
  2022-05-14  4:25     ` Kalle Valo
  0 siblings, 1 reply; 262+ messages in thread
From: viktor.barna @ 2022-05-13 21:11 UTC (permalink / raw)
  To: kvalo
  Cc: aviad.brikman, davem, eliav.farber, kuba, linux-wireless,
	oleksandr.savchenko, shay.bar, viktor.barna

Kalle Valo <kvalo@codeaurora.org> wrote:
> I'm not going to review a driver with a disclaimer like this.
    
Hi Kalle,

first of all, thanks for the comment, we are very sorry for the
prolonged delay in the response - comments from Johannes were taken into
account and the new RFC is almost ready and on the way. Regarding the
disclaimer mistake - our mail gateway automatically appends such text by
modifying original message and it was not detected earlier because of the
advanced filters which skipped such appending in internal tests. Many
apologizes for that. Now the filter has several new exceptions for kernel.org
and friends.

Can you, please, respond to this email with info whether the disclaimer is
still present in your inbox? That will help to continue with RFCv2. 

Best regards,
Viktor Barna

^ permalink raw reply	[flat|nested] 262+ messages in thread

* Re: [RFC v1 000/256] wireless: cl8k driver for Celeno IEEE 802.11ax devices
  2022-05-13 21:11   ` viktor.barna
@ 2022-05-14  4:25     ` Kalle Valo
  0 siblings, 0 replies; 262+ messages in thread
From: Kalle Valo @ 2022-05-14  4:25 UTC (permalink / raw)
  To: viktor.barna
  Cc: aviad.brikman, davem, eliav.farber, kuba, linux-wireless,
	oleksandr.savchenko, shay.bar

viktor.barna@celeno.com writes:

> Kalle Valo <kvalo@codeaurora.org> wrote:
>> I'm not going to review a driver with a disclaimer like this.
>     
> Hi Kalle,
>
> first of all, thanks for the comment, we are very sorry for the
> prolonged delay in the response - comments from Johannes were taken into
> account and the new RFC is almost ready and on the way. Regarding the
> disclaimer mistake - our mail gateway automatically appends such text by
> modifying original message and it was not detected earlier because of the
> advanced filters which skipped such appending in internal tests. Many
> apologizes for that. Now the filter has several new exceptions for kernel.org
> and friends.
>
> Can you, please, respond to this email with info whether the disclaimer is
> still present in your inbox? That will help to continue with RFCv2. 

I don't see any disclaimers now, thanks for fixing it. Also lore looks
good:

https://lore.kernel.org/all/20220513211140.2596547-1-viktor.barna@celeno.com/

-- 
https://patchwork.kernel.org/project/linux-wireless/list/

https://wireless.wiki.kernel.org/en/developers/documentation/submittingpatches

^ permalink raw reply	[flat|nested] 262+ messages in thread

* Re: [RFC v1 000/256] wireless: cl8k driver for Celeno IEEE 802.11ax devices
  2021-06-17 17:23 ` [RFC v1 000/256] wireless: cl8k driver for Celeno IEEE 802.11ax devices Johannes Berg
@ 2022-05-22 17:51   ` viktor.barna
  0 siblings, 0 replies; 262+ messages in thread
From: viktor.barna @ 2022-05-22 17:51 UTC (permalink / raw)
  To: johannes
  Cc: aviad.brikman, davem, eliav.farber, kuba, kvalo, linux-wireless,
	oleksandr.savchenko, shay.bar, viktor.barna

Hi Johannes,

we are very grateful for the initial review and a big sorry for such a
prolonged delayed response from our side - we were working on minimizing driver
and RFCv2 is almost ready.

> * without command line interfaces with string parsing built into the
>   kernel
>   (OK, that's probably something that will never go upstream anyway)

RFCv2 will contain removed CLI, some of the stuff moved to the debugfs
(because in most of the cases that's only debugging commands), but we will
publish that patchset even without that - to have as minimum solution as
possible (as it is also required in the guide). Some time later we can
re-introduce the debugfs solution in the future after aproval of base driver.

> * Kconfig vs. code inconsistencies cleaned up, you have a TON of
>   CONFIG_* ifdefs that don't even exist and can never be set, so remove
>   the code, at least for now?

ACK. Unused defines were removed, and others were refactored in a way, that
allows to tune them via Kconfig.

> * remove wrappers like cl_snprintf(), though that seems part of all
>   those command line interfaces built into the driver

ACK. RFCv2 will be without them at all.

> * consider joining some of the many header files into bigger chunks,
>   header files that are 50% boilerplate aren't really all that useful

ACK. RFCv2 consists of ~98 files now (functionality was merged by some similar
area - like all the TX in tx.c, all the RX stuff in the rx.c etc). If that is
still huge - please, feel free to comment. Maybe, there is some acceptance
criteria? It looks much closer to existing drivers. If the number is still high,
just for the sake of review we can merge header files into bigger pieces.

> * namespace your things better - e.g. "is_ipv4_packet" and friends?
>   (why do you even care?)

ACK. That case was related to the lookup of time-sensitive traffic - to avoid
putting it in the slowpath.

> * remove all vendor commands for now, and read the vendor commands
>   upstreaming documentation before re-introducing them
>   https://wireless.wiki.kernel.org/en/developers/documentation/nl80211#vendor-specific_api

ACK. All the netlink will be removed in RFCv2.

> * remove utils/string.c, obviously, use kernel stuff directly or
>   improve where needed I guess - but likely all part of the weird CLI-
>   in-kernel stuff?

Yep, you are correct, in most the cases, custom abstraction was part of the CLI
(and configuration parsing). It will be removed in RFCv2.

> * remove abstraction layers like cl_timer

ACK.

> * what's this VNS stuff? doesn't look like it belongs into a driver
>   (a mac80211 one at that!)

Very Near STA - extra functionality, that allows to tune TX power regarding STA
position. We can move it out temporary since it has bindings to the FW and
reimplement in the mac80211 if there is necessity.

> * bitfields in endian-safe code are generally frowned upon, so you
>   shouldn't need cl_are_host_bits_le(). And also cl_are_host_bits_be()?
>   What?

cl8k driver is using dev_coredump subsystem for dump preparation, and these
functions were part of dump information about the host - it could be useful for
postmortem analysis of the dump themselves outside of environment where they
were collected.

> * Use ERR_PTR() and friends, instead of out pointer parameters.

ACK. We will take it into account during RFCv3.

Again, thanks for the initial review!

PS: Mr. Kalle confirmed, that disclaimer issue is resolved, that is good,
thanks!

Best regards,
Viktor Barna

^ permalink raw reply	[flat|nested] 262+ messages in thread

end of thread, other threads:[~2022-05-22 17:51 UTC | newest]

Thread overview: 262+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-06-17 15:58 [RFC v1 000/256] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
2021-06-17 15:58 ` [RFC v1 001/256] celeno: add Kconfig viktor.barna
2021-06-17 15:58 ` [RFC v1 002/256] celeno: add Makefile viktor.barna
2021-06-17 15:58 ` [RFC v1 003/256] cl8k: add Kconfig viktor.barna
2021-06-17 15:58 ` [RFC v1 004/256] cl8k: add Makefile viktor.barna
2021-06-17 15:58 ` [RFC v1 005/256] cl8k: add afe.c viktor.barna
2021-06-17 15:58 ` [RFC v1 006/256] cl8k: add afe.h viktor.barna
2021-06-17 15:58 ` [RFC v1 007/256] cl8k: add agc_params.c viktor.barna
2021-06-17 15:58 ` [RFC v1 008/256] cl8k: add agc_params.h viktor.barna
2021-06-17 15:58 ` [RFC v1 009/256] cl8k: add ampdu.c viktor.barna
2021-06-17 15:58 ` [RFC v1 010/256] cl8k: add ampdu.h viktor.barna
2021-06-17 15:58 ` [RFC v1 011/256] cl8k: add ate.c viktor.barna
2021-06-17 15:58 ` [RFC v1 012/256] cl8k: add ate.h viktor.barna
2021-06-17 15:58 ` [RFC v1 013/256] cl8k: add band.c viktor.barna
2021-06-17 15:58 ` [RFC v1 014/256] cl8k: add band.h viktor.barna
2021-06-17 15:58 ` [RFC v1 015/256] cl8k: add bf.c viktor.barna
2021-06-17 15:58 ` [RFC v1 016/256] cl8k: add bf.h viktor.barna
2021-06-17 15:58 ` [RFC v1 017/256] cl8k: add bus/pci/ipc.c viktor.barna
2021-06-17 15:58 ` [RFC v1 018/256] cl8k: add bus/pci/ipc.h viktor.barna
2021-06-17 15:58 ` [RFC v1 019/256] cl8k: add bus/pci/irq.c viktor.barna
2021-06-17 15:58 ` [RFC v1 020/256] cl8k: add bus/pci/irq.h viktor.barna
2021-06-17 15:58 ` [RFC v1 021/256] cl8k: add bus/pci/msg_pci.c viktor.barna
2021-06-17 15:58 ` [RFC v1 022/256] cl8k: add bus/pci/msg_pci.h viktor.barna
2021-06-17 15:58 ` [RFC v1 023/256] cl8k: add bus/pci/pci.c viktor.barna
2021-06-17 15:58 ` [RFC v1 024/256] cl8k: add bus/pci/rx_pci.c viktor.barna
2021-06-17 15:58 ` [RFC v1 025/256] cl8k: add bus/pci/rx_pci.h viktor.barna
2021-06-17 15:58 ` [RFC v1 026/256] cl8k: add bus/pci/tx_pci.c viktor.barna
2021-06-17 15:58 ` [RFC v1 027/256] cl8k: add bus/pci/tx_pci.h viktor.barna
2021-06-17 15:58 ` [RFC v1 028/256] cl8k: add calib.c viktor.barna
2021-06-17 15:58 ` [RFC v1 029/256] cl8k: add calib.h viktor.barna
2021-06-17 15:58 ` [RFC v1 030/256] cl8k: add cap.c viktor.barna
2021-06-17 15:58 ` [RFC v1 031/256] cl8k: add cap.h viktor.barna
2021-06-17 15:58 ` [RFC v1 032/256] cl8k: add cca.c viktor.barna
2021-06-17 15:58 ` [RFC v1 033/256] cl8k: add cca.h viktor.barna
2021-06-17 15:58 ` [RFC v1 034/256] cl8k: add cecli.c viktor.barna
2021-06-17 15:58 ` [RFC v1 035/256] cl8k: add cecli.h viktor.barna
2021-06-17 15:58 ` [RFC v1 036/256] cl8k: add chandef.c viktor.barna
2021-06-17 15:58 ` [RFC v1 037/256] cl8k: add chandef.h viktor.barna
2021-06-17 15:58 ` [RFC v1 038/256] cl8k: add channel.c viktor.barna
2021-06-17 15:58 ` [RFC v1 039/256] cl8k: add channel.h viktor.barna
2021-06-17 15:58 ` [RFC v1 040/256] cl8k: add chan_info.c viktor.barna
2021-06-17 15:58 ` [RFC v1 041/256] cl8k: add chan_info.h viktor.barna
2021-06-17 15:58 ` [RFC v1 042/256] cl8k: add chip.c viktor.barna
2021-06-17 15:58 ` [RFC v1 043/256] cl8k: add chip.h viktor.barna
2021-06-17 15:58 ` [RFC v1 044/256] cl8k: add chip_config.c viktor.barna
2021-06-17 15:58 ` [RFC v1 045/256] cl8k: add chip_config.h viktor.barna
2021-06-17 15:58 ` [RFC v1 046/256] cl8k: add config.c viktor.barna
2021-06-17 15:58 ` [RFC v1 047/256] cl8k: add config.h viktor.barna
2021-06-17 15:58 ` [RFC v1 048/256] cl8k: add coredump.c viktor.barna
2021-06-17 15:58 ` [RFC v1 049/256] cl8k: add coredump.h viktor.barna
2021-06-17 15:58 ` [RFC v1 050/256] cl8k: add data_rates.c viktor.barna
2021-06-17 15:58 ` [RFC v1 051/256] cl8k: add data_rates.h viktor.barna
2021-06-17 15:58 ` [RFC v1 052/256] cl8k: add dbgfile.c viktor.barna
2021-06-17 15:59 ` [RFC v1 053/256] cl8k: add dbgfile.h viktor.barna
2021-06-17 15:59 ` [RFC v1 054/256] cl8k: add debug.h viktor.barna
2021-06-17 15:59 ` [RFC v1 055/256] cl8k: add debugfs.c viktor.barna
2021-06-17 15:59 ` [RFC v1 056/256] cl8k: add debugfs.h viktor.barna
2021-06-17 15:59 ` [RFC v1 057/256] cl8k: add debugfs_defs.h viktor.barna
2021-06-17 15:59 ` [RFC v1 058/256] cl8k: add def.h viktor.barna
2021-06-17 15:59 ` [RFC v1 059/256] cl8k: add dfs/dfs.c viktor.barna
2021-06-17 15:59 ` [RFC v1 060/256] cl8k: add dfs/dfs.h viktor.barna
2021-06-17 15:59 ` [RFC v1 061/256] cl8k: add dfs/dfs_db.h viktor.barna
2021-06-17 15:59 ` [RFC v1 062/256] cl8k: add dfs/radar.c viktor.barna
2021-06-17 15:59 ` [RFC v1 063/256] cl8k: add dfs/radar.h viktor.barna
2021-06-17 15:59 ` [RFC v1 064/256] cl8k: add drv_ops.h viktor.barna
2021-06-17 15:59 ` [RFC v1 065/256] cl8k: add dsp.c viktor.barna
2021-06-17 15:59 ` [RFC v1 066/256] cl8k: add dsp.h viktor.barna
2021-06-17 15:59 ` [RFC v1 067/256] cl8k: add e2p.c viktor.barna
2021-06-17 15:59 ` [RFC v1 068/256] cl8k: add e2p.h viktor.barna
2021-06-17 15:59 ` [RFC v1 069/256] cl8k: add edca.c viktor.barna
2021-06-17 15:59 ` [RFC v1 070/256] cl8k: add edca.h viktor.barna
2021-06-17 15:59 ` [RFC v1 071/256] cl8k: add ela.c viktor.barna
2021-06-17 15:59 ` [RFC v1 072/256] cl8k: add ela.h viktor.barna
2021-06-17 15:59 ` [RFC v1 073/256] cl8k: add enhanced_tim.c viktor.barna
2021-06-17 15:59 ` [RFC v1 074/256] cl8k: add enhanced_tim.h viktor.barna
2021-06-17 15:59 ` [RFC v1 075/256] cl8k: add env_det.c viktor.barna
2021-06-17 15:59 ` [RFC v1 076/256] cl8k: add env_det.h viktor.barna
2021-06-17 15:59 ` [RFC v1 077/256] cl8k: add ext/dyn_bcast_rate.c viktor.barna
2021-06-17 15:59 ` [RFC v1 078/256] cl8k: add ext/dyn_bcast_rate.h viktor.barna
2021-06-17 15:59 ` [RFC v1 079/256] cl8k: add ext/dyn_mcast_rate.c viktor.barna
2021-06-17 15:59 ` [RFC v1 080/256] cl8k: add ext/dyn_mcast_rate.h viktor.barna
2021-06-17 15:59 ` [RFC v1 081/256] cl8k: add ext/vlan_dscp.c viktor.barna
2021-06-17 15:59 ` [RFC v1 082/256] cl8k: add ext/vlan_dscp.h viktor.barna
2021-06-17 15:59 ` [RFC v1 083/256] cl8k: add fem.c viktor.barna
2021-06-17 15:59 ` [RFC v1 084/256] cl8k: add fem.h viktor.barna
2021-06-17 15:59 ` [RFC v1 085/256] cl8k: add fem_common.h viktor.barna
2021-06-17 15:59 ` [RFC v1 086/256] cl8k: add fw/fw_dbg.c viktor.barna
2021-06-17 15:59 ` [RFC v1 087/256] cl8k: add fw/fw_dbg.h viktor.barna
2021-06-17 15:59 ` [RFC v1 088/256] cl8k: add fw/fw_file.c viktor.barna
2021-06-17 15:59 ` [RFC v1 089/256] cl8k: add fw/fw_file.h viktor.barna
2021-06-17 15:59 ` [RFC v1 090/256] cl8k: add fw/fw_msg.c viktor.barna
2021-06-17 15:59 ` [RFC v1 091/256] cl8k: add fw/fw_msg.h viktor.barna
2021-06-17 15:59 ` [RFC v1 092/256] cl8k: add fw/msg_cfm.c viktor.barna
2021-06-17 15:59 ` [RFC v1 093/256] cl8k: add fw/msg_cfm.h viktor.barna
2021-06-17 15:59 ` [RFC v1 094/256] cl8k: add fw/msg_rx.c viktor.barna
2021-06-17 15:59 ` [RFC v1 095/256] cl8k: add fw/msg_rx.h viktor.barna
2021-06-17 15:59 ` [RFC v1 096/256] cl8k: add fw/msg_tx.c viktor.barna
2021-06-17 15:59 ` [RFC v1 097/256] cl8k: add fw/msg_tx.h viktor.barna
2021-06-17 15:59 ` [RFC v1 098/256] cl8k: add hw.c viktor.barna
2021-06-17 15:59 ` [RFC v1 099/256] cl8k: add hw.h viktor.barna
2021-06-17 15:59 ` [RFC v1 100/256] cl8k: add hw_assert.c viktor.barna
2021-06-17 15:59 ` [RFC v1 101/256] cl8k: add hw_assert.h viktor.barna
2021-06-17 15:59 ` [RFC v1 102/256] cl8k: add ipc_shared.h viktor.barna
2021-06-17 15:59 ` [RFC v1 103/256] cl8k: add key.c viktor.barna
2021-06-17 15:59 ` [RFC v1 104/256] cl8k: add key.h viktor.barna
2021-06-17 15:59 ` [RFC v1 105/256] cl8k: add mac80211.c viktor.barna
2021-06-17 15:59 ` [RFC v1 106/256] cl8k: add mac80211.h viktor.barna
2021-06-17 15:59 ` [RFC v1 107/256] cl8k: add mac_addr.c viktor.barna
2021-06-17 15:59 ` [RFC v1 108/256] cl8k: add mac_addr.h viktor.barna
2021-06-17 15:59 ` [RFC v1 109/256] cl8k: add main.c viktor.barna
2021-06-17 15:59 ` [RFC v1 110/256] cl8k: add main.h viktor.barna
2021-06-17 15:59 ` [RFC v1 111/256] cl8k: add maintenance.c viktor.barna
2021-06-17 15:59 ` [RFC v1 112/256] cl8k: add maintenance.h viktor.barna
2021-06-17 16:00 ` [RFC v1 113/256] cl8k: add mib.c viktor.barna
2021-06-17 16:00 ` [RFC v1 114/256] cl8k: add mib.h viktor.barna
2021-06-17 16:00 ` [RFC v1 115/256] cl8k: add motion_sense.c viktor.barna
2021-06-17 16:00 ` [RFC v1 116/256] cl8k: add motion_sense.h viktor.barna
2021-06-17 16:00 ` [RFC v1 117/256] cl8k: add netlink.c viktor.barna
2021-06-17 16:00 ` [RFC v1 118/256] cl8k: add netlink.h viktor.barna
2021-06-17 16:00 ` [RFC v1 119/256] cl8k: add noise.c viktor.barna
2021-06-17 16:00 ` [RFC v1 120/256] cl8k: add noise.h viktor.barna
2021-06-17 16:00 ` [RFC v1 121/256] cl8k: add omi.c viktor.barna
2021-06-17 16:00 ` [RFC v1 122/256] cl8k: add omi.h viktor.barna
2021-06-17 16:00 ` [RFC v1 123/256] cl8k: add ops.c viktor.barna
2021-06-17 16:00 ` [RFC v1 124/256] cl8k: add ops.h viktor.barna
2021-06-17 16:00 ` [RFC v1 125/256] cl8k: add phy/phy.c viktor.barna
2021-06-17 16:00 ` [RFC v1 126/256] cl8k: add phy/phy.h viktor.barna
2021-06-17 16:00 ` [RFC v1 127/256] cl8k: add phy/phy_athos_lut.c viktor.barna
2021-06-17 16:00 ` [RFC v1 128/256] cl8k: add phy/phy_athos_lut.h viktor.barna
2021-06-17 16:00 ` [RFC v1 129/256] cl8k: add phy/phy_common_lut.c viktor.barna
2021-06-17 16:00 ` [RFC v1 130/256] cl8k: add phy/phy_common_lut.h viktor.barna
2021-06-17 16:00 ` [RFC v1 131/256] cl8k: add phy/phy_olympus_lut.c viktor.barna
2021-06-17 16:00 ` [RFC v1 132/256] cl8k: add phy/phy_olympus_lut.h viktor.barna
2021-06-17 16:00 ` [RFC v1 133/256] cl8k: add power.c viktor.barna
2021-06-17 16:00 ` [RFC v1 134/256] cl8k: add power.h viktor.barna
2021-06-17 16:00 ` [RFC v1 135/256] cl8k: add power_cli.c viktor.barna
2021-06-17 16:00 ` [RFC v1 136/256] cl8k: add power_cli.h viktor.barna
2021-06-17 16:00 ` [RFC v1 137/256] cl8k: add power_table.c viktor.barna
2021-06-17 16:00 ` [RFC v1 138/256] cl8k: add power_table.h viktor.barna
2021-06-17 16:00 ` [RFC v1 139/256] cl8k: add prot_mode.c viktor.barna
2021-06-17 16:00 ` [RFC v1 140/256] cl8k: add prot_mode.h viktor.barna
2021-06-17 16:00 ` [RFC v1 141/256] cl8k: add radio.c viktor.barna
2021-06-17 16:00 ` [RFC v1 142/256] cl8k: add radio.h viktor.barna
2021-06-17 16:00 ` [RFC v1 143/256] cl8k: add rate_ctrl.c viktor.barna
2021-06-17 16:00 ` [RFC v1 144/256] cl8k: add rate_ctrl.h viktor.barna
2021-06-17 16:00 ` [RFC v1 145/256] cl8k: add recovery.c viktor.barna
2021-06-17 16:00 ` [RFC v1 146/256] cl8k: add recovery.h viktor.barna
2021-06-17 16:00 ` [RFC v1 147/256] cl8k: add reg/ceva.h viktor.barna
2021-06-17 16:00 ` [RFC v1 148/256] cl8k: add reg/reg_access.h viktor.barna
2021-06-17 16:00 ` [RFC v1 149/256] cl8k: add reg/reg_cli.c viktor.barna
2021-06-17 16:00 ` [RFC v1 150/256] cl8k: add reg/reg_cli.h viktor.barna
2021-06-17 16:00 ` [RFC v1 151/256] cl8k: add reg/reg_cmu.h viktor.barna
2021-06-17 16:00 ` [RFC v1 152/256] cl8k: add reg/reg_fem.h viktor.barna
2021-06-17 16:00 ` [RFC v1 153/256] cl8k: add reg/reg_io_ctrl.h viktor.barna
2021-06-17 16:00 ` [RFC v1 154/256] cl8k: add reg/reg_ipc.h viktor.barna
2021-06-17 16:00 ` [RFC v1 155/256] cl8k: add reg/reg_lcu_common.h viktor.barna
2021-06-17 16:00 ` [RFC v1 156/256] cl8k: add reg/reg_lcu_phy.h viktor.barna
2021-06-17 16:00 ` [RFC v1 157/256] cl8k: add reg/reg_macdsp_api.h viktor.barna
2021-06-17 16:00 ` [RFC v1 158/256] cl8k: add reg/reg_macsys_gcu.h viktor.barna
2021-06-17 16:00 ` [RFC v1 159/256] cl8k: add reg/reg_mac_hw.h viktor.barna
2021-06-17 16:00 ` [RFC v1 160/256] cl8k: add reg/reg_mac_hw_mu.h viktor.barna
2021-06-17 16:00 ` [RFC v1 161/256] cl8k: add reg/reg_modem_gcu.h viktor.barna
2021-06-17 16:00 ` [RFC v1 162/256] cl8k: add reg/reg_otp_pvt.h viktor.barna
2021-06-17 16:00 ` [RFC v1 163/256] cl8k: add reg/reg_ricu.h viktor.barna
2021-06-17 16:00 ` [RFC v1 164/256] cl8k: add reg/reg_riu.h viktor.barna
2021-06-17 16:00 ` [RFC v1 165/256] cl8k: add reg/reg_riu_rc.h viktor.barna
2021-06-17 16:00 ` [RFC v1 166/256] cl8k: add rf_boot.c viktor.barna
2021-06-17 16:00 ` [RFC v1 167/256] cl8k: add rf_boot.h viktor.barna
2021-06-17 16:00 ` [RFC v1 168/256] cl8k: add rsrc_mgmt.c viktor.barna
2021-06-17 16:00 ` [RFC v1 169/256] cl8k: add rsrc_mgmt.h viktor.barna
2021-06-17 16:00 ` [RFC v1 170/256] cl8k: add rssi.c viktor.barna
2021-06-17 16:00 ` [RFC v1 171/256] cl8k: add rssi.h viktor.barna
2021-06-17 16:00 ` [RFC v1 172/256] cl8k: add rx/rx.c viktor.barna
2021-06-17 16:01 ` [RFC v1 173/256] cl8k: add rx/rx.h viktor.barna
2021-06-17 16:01 ` [RFC v1 174/256] cl8k: add rx/rx_amsdu.c viktor.barna
2021-06-17 16:01 ` [RFC v1 175/256] cl8k: add rx/rx_amsdu.h viktor.barna
2021-06-17 16:01 ` [RFC v1 176/256] cl8k: add rx/rx_filter.c viktor.barna
2021-06-17 16:01 ` [RFC v1 177/256] cl8k: add rx/rx_filter.h viktor.barna
2021-06-17 16:01 ` [RFC v1 178/256] cl8k: add rx/rx_reorder.c viktor.barna
2021-06-17 16:01 ` [RFC v1 179/256] cl8k: add rx/rx_reorder.h viktor.barna
2021-06-17 16:01 ` [RFC v1 180/256] cl8k: add sounding.c viktor.barna
2021-06-17 16:01 ` [RFC v1 181/256] cl8k: add sounding.h viktor.barna
2021-06-17 16:01 ` [RFC v1 182/256] cl8k: add sta.c viktor.barna
2021-06-17 16:01 ` [RFC v1 183/256] cl8k: add sta.h viktor.barna
2021-06-17 16:01 ` [RFC v1 184/256] cl8k: add stats.c viktor.barna
2021-06-17 16:01 ` [RFC v1 185/256] cl8k: add stats.h viktor.barna
2021-06-17 16:01 ` [RFC v1 186/256] cl8k: add tcv_config.c viktor.barna
2021-06-17 16:01 ` [RFC v1 187/256] cl8k: add tcv_config.h viktor.barna
2021-06-17 16:01 ` [RFC v1 188/256] cl8k: add temperature.c viktor.barna
2021-06-17 16:01 ` [RFC v1 189/256] cl8k: add temperature.h viktor.barna
2021-06-17 16:01 ` [RFC v1 190/256] cl8k: add trace.c viktor.barna
2021-06-17 16:01 ` [RFC v1 191/256] cl8k: add trace.h viktor.barna
2021-06-17 16:01 ` [RFC v1 192/256] cl8k: add traffic.c viktor.barna
2021-06-17 16:01 ` [RFC v1 193/256] cl8k: add traffic.h viktor.barna
2021-06-17 16:01 ` [RFC v1 194/256] cl8k: add twt.c viktor.barna
2021-06-17 16:01 ` [RFC v1 195/256] cl8k: add twt.h viktor.barna
2021-06-17 16:01 ` [RFC v1 196/256] cl8k: add twt_cli.c viktor.barna
2021-06-17 16:01 ` [RFC v1 197/256] cl8k: add twt_cli.h viktor.barna
2021-06-17 16:01 ` [RFC v1 198/256] cl8k: add twt_frame.c viktor.barna
2021-06-17 16:01 ` [RFC v1 199/256] cl8k: add twt_frame.h viktor.barna
2021-06-17 16:01 ` [RFC v1 200/256] cl8k: add tx/agg_cfm.c viktor.barna
2021-06-17 16:01 ` [RFC v1 201/256] cl8k: add tx/agg_cfm.h viktor.barna
2021-06-17 16:01 ` [RFC v1 202/256] cl8k: add tx/agg_tx_report.c viktor.barna
2021-06-17 16:01 ` [RFC v1 203/256] cl8k: add tx/agg_tx_report.h viktor.barna
2021-06-17 16:01 ` [RFC v1 204/256] cl8k: add tx/baw.c viktor.barna
2021-06-17 16:01 ` [RFC v1 205/256] cl8k: add tx/baw.h viktor.barna
2021-06-17 16:01 ` [RFC v1 206/256] cl8k: add tx/bcmc_cfm.c viktor.barna
2021-06-17 16:01 ` [RFC v1 207/256] cl8k: add tx/bcmc_cfm.h viktor.barna
2021-06-17 16:01 ` [RFC v1 208/256] cl8k: add tx/single_cfm.c viktor.barna
2021-06-17 16:01 ` [RFC v1 209/256] cl8k: add tx/single_cfm.h viktor.barna
2021-06-17 16:01 ` [RFC v1 210/256] cl8k: add tx/sw_txhdr.c viktor.barna
2021-06-17 16:01 ` [RFC v1 211/256] cl8k: add tx/sw_txhdr.h viktor.barna
2021-06-17 16:01 ` [RFC v1 212/256] cl8k: add tx/tx.c viktor.barna
2021-06-17 16:01 ` [RFC v1 213/256] cl8k: add tx/tx.h viktor.barna
2021-06-17 16:01 ` [RFC v1 214/256] cl8k: add tx/tx_amsdu.c viktor.barna
2021-06-17 16:01 ` [RFC v1 215/256] cl8k: add tx/tx_amsdu.h viktor.barna
2021-06-17 16:01 ` [RFC v1 216/256] cl8k: add tx/tx_inject.c viktor.barna
2021-06-17 16:01 ` [RFC v1 217/256] cl8k: add tx/tx_inject.h viktor.barna
2021-06-17 16:01 ` [RFC v1 218/256] cl8k: add tx/tx_queue.c viktor.barna
2021-06-17 16:01 ` [RFC v1 219/256] cl8k: add tx/tx_queue.h viktor.barna
2021-06-17 16:01 ` [RFC v1 220/256] cl8k: add utils/file.c viktor.barna
2021-06-17 16:01 ` [RFC v1 221/256] cl8k: add utils/file.h viktor.barna
2021-06-17 16:01 ` [RFC v1 222/256] cl8k: add utils/ip.c viktor.barna
2021-06-17 16:01 ` [RFC v1 223/256] cl8k: add utils/ip.h viktor.barna
2021-06-17 16:01 ` [RFC v1 224/256] cl8k: add utils/math.h viktor.barna
2021-06-17 16:01 ` [RFC v1 225/256] cl8k: add utils/string.c viktor.barna
2021-06-17 16:01 ` [RFC v1 226/256] cl8k: add utils/string.h viktor.barna
2021-06-17 16:01 ` [RFC v1 227/256] cl8k: add utils/timer.c viktor.barna
2021-06-17 16:01 ` [RFC v1 228/256] cl8k: add utils/timer.h viktor.barna
2021-06-17 16:01 ` [RFC v1 229/256] cl8k: add utils/utils.c viktor.barna
2021-06-17 16:01 ` [RFC v1 230/256] cl8k: add utils/utils.h viktor.barna
2021-06-17 16:01 ` [RFC v1 231/256] cl8k: add vendor_cmd.c viktor.barna
2021-06-17 16:01 ` [RFC v1 232/256] cl8k: add vendor_cmd.h viktor.barna
2021-06-17 16:02 ` [RFC v1 233/256] cl8k: add version.c viktor.barna
2021-06-17 16:02 ` [RFC v1 234/256] cl8k: add version.h viktor.barna
2021-06-17 16:02 ` [RFC v1 235/256] cl8k: add vif.c viktor.barna
2021-06-17 16:02 ` [RFC v1 236/256] cl8k: add vif.h viktor.barna
2021-06-17 16:02 ` [RFC v1 237/256] cl8k: add vns.c viktor.barna
2021-06-17 16:02 ` [RFC v1 238/256] cl8k: add vns.h viktor.barna
2021-06-17 16:02 ` [RFC v1 239/256] cl8k: add wrs/wrs.c viktor.barna
2021-06-17 16:02 ` [RFC v1 240/256] cl8k: add wrs/wrs.h viktor.barna
2021-06-17 16:02 ` [RFC v1 241/256] cl8k: add wrs/wrs_ap.c viktor.barna
2021-06-17 16:02 ` [RFC v1 242/256] cl8k: add wrs/wrs_ap.h viktor.barna
2021-06-17 16:02 ` [RFC v1 243/256] cl8k: add wrs/wrs_api.c viktor.barna
2021-06-17 16:02 ` [RFC v1 244/256] cl8k: add wrs/wrs_api.h viktor.barna
2021-06-17 16:02 ` [RFC v1 245/256] cl8k: add wrs/wrs_cli.c viktor.barna
2021-06-17 16:02 ` [RFC v1 246/256] cl8k: add wrs/wrs_cli.h viktor.barna
2021-06-17 16:02 ` [RFC v1 247/256] cl8k: add wrs/wrs_db.h viktor.barna
2021-06-17 16:02 ` [RFC v1 248/256] cl8k: add wrs/wrs_rssi.c viktor.barna
2021-06-17 16:02 ` [RFC v1 249/256] cl8k: add wrs/wrs_rssi.h viktor.barna
2021-06-17 16:02 ` [RFC v1 250/256] cl8k: add wrs/wrs_sta.c viktor.barna
2021-06-17 16:02 ` [RFC v1 251/256] cl8k: add wrs/wrs_sta.h viktor.barna
2021-06-17 16:02 ` [RFC v1 252/256] cl8k: add wrs/wrs_stats.c viktor.barna
2021-06-17 16:02 ` [RFC v1 253/256] cl8k: add wrs/wrs_stats.h viktor.barna
2021-06-17 16:02 ` [RFC v1 254/256] cl8k: add wrs/wrs_tables.c viktor.barna
2021-06-17 16:02 ` [RFC v1 255/256] cl8k: add wrs/wrs_tables.h viktor.barna
2021-06-17 16:02 ` [RFC v1 256/256] wireless: add Celeno vendor viktor.barna
2021-06-17 17:23 ` [RFC v1 000/256] wireless: cl8k driver for Celeno IEEE 802.11ax devices Johannes Berg
2022-05-22 17:51   ` viktor.barna
2021-06-19  6:39 ` Kalle Valo
2022-05-13 21:11   ` viktor.barna
2022-05-14  4:25     ` Kalle Valo

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.