All of lore.kernel.org
 help / color / mirror / Atom feed
From: viktor.barna@celeno.com
To: linux-wireless@vger.kernel.org
Cc: Kalle Valo <kvalo@codeaurora.org>,
	"David S . Miller" <davem@davemloft.net>,
	Jakub Kicinski <kuba@kernel.org>,
	Aviad Brikman <aviad.brikman@celeno.com>,
	Eliav Farber <eliav.farber@gmail.com>,
	Maksym Kokhan <maksym.kokhan@celeno.com>,
	Oleksandr Savchenko <oleksandr.savchenko@celeno.com>,
	Shay Bar <shay.bar@celeno.com>,
	Viktor Barna <viktor.barna@celeno.com>
Subject: [RFC v2 11/96] cl8k: add channel.c
Date: Tue, 24 May 2022 14:33:37 +0300	[thread overview]
Message-ID: <20220524113502.1094459-12-viktor.barna@celeno.com> (raw)
In-Reply-To: <20220524113502.1094459-1-viktor.barna@celeno.com>

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 | 1656 ++++++++++++++++++++
 1 file changed, 1656 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..777c5f749059
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/channel.c
@@ -0,0 +1,1656 @@
+// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause
+/* Copyright(c) 2019-2022, Celeno Communications Ltd. */
+
+#include "vif.h"
+#include "dfs.h"
+#include "reg/reg_defs.h"
+#include "hw.h"
+#include "utils.h"
+#include "channel.h"
+
+#define CASE_CHAN2BITMAP_IDX_6G(_chan) { case _chan: return (b6g_ch ## _chan); }
+#define CASE_CHAN2EXT_IDX_6G(_chan) { case _chan: return (ext_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_BITMAP_IDX2FREQ_6G(_chan) { case (b6g_ch ## _chan): return FREQ6G(_chan); }
+#define CASE_EXT_IDX2FREQ_6G(_chan) { case (ext_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_bitmap_index_6g(struct cl_hw *cl_hw, u32 channel)
+{
+	switch (channel) {
+	CASE_CHAN2BITMAP_IDX_6G(1);
+	CASE_CHAN2BITMAP_IDX_6G(2);
+	CASE_CHAN2BITMAP_IDX_6G(5);
+	CASE_CHAN2BITMAP_IDX_6G(9);
+	CASE_CHAN2BITMAP_IDX_6G(13);
+	CASE_CHAN2BITMAP_IDX_6G(17);
+	CASE_CHAN2BITMAP_IDX_6G(21);
+	CASE_CHAN2BITMAP_IDX_6G(25);
+	CASE_CHAN2BITMAP_IDX_6G(29);
+	CASE_CHAN2BITMAP_IDX_6G(33);
+	CASE_CHAN2BITMAP_IDX_6G(37);
+	CASE_CHAN2BITMAP_IDX_6G(41);
+	CASE_CHAN2BITMAP_IDX_6G(45);
+	CASE_CHAN2BITMAP_IDX_6G(49);
+	CASE_CHAN2BITMAP_IDX_6G(53);
+	CASE_CHAN2BITMAP_IDX_6G(57);
+	CASE_CHAN2BITMAP_IDX_6G(61);
+	CASE_CHAN2BITMAP_IDX_6G(65);
+	CASE_CHAN2BITMAP_IDX_6G(69);
+	CASE_CHAN2BITMAP_IDX_6G(73);
+	CASE_CHAN2BITMAP_IDX_6G(77);
+	CASE_CHAN2BITMAP_IDX_6G(81);
+	CASE_CHAN2BITMAP_IDX_6G(85);
+	CASE_CHAN2BITMAP_IDX_6G(89);
+	CASE_CHAN2BITMAP_IDX_6G(93);
+	CASE_CHAN2BITMAP_IDX_6G(97);
+	CASE_CHAN2BITMAP_IDX_6G(101);
+	CASE_CHAN2BITMAP_IDX_6G(105);
+	CASE_CHAN2BITMAP_IDX_6G(109);
+	CASE_CHAN2BITMAP_IDX_6G(113);
+	CASE_CHAN2BITMAP_IDX_6G(117);
+	CASE_CHAN2BITMAP_IDX_6G(121);
+	CASE_CHAN2BITMAP_IDX_6G(125);
+	CASE_CHAN2BITMAP_IDX_6G(129);
+	CASE_CHAN2BITMAP_IDX_6G(133);
+	CASE_CHAN2BITMAP_IDX_6G(137);
+	CASE_CHAN2BITMAP_IDX_6G(141);
+	CASE_CHAN2BITMAP_IDX_6G(145);
+	CASE_CHAN2BITMAP_IDX_6G(149);
+	CASE_CHAN2BITMAP_IDX_6G(153);
+	CASE_CHAN2BITMAP_IDX_6G(157);
+	CASE_CHAN2BITMAP_IDX_6G(161);
+	CASE_CHAN2BITMAP_IDX_6G(165);
+	CASE_CHAN2BITMAP_IDX_6G(169);
+	CASE_CHAN2BITMAP_IDX_6G(173);
+	CASE_CHAN2BITMAP_IDX_6G(177);
+	CASE_CHAN2BITMAP_IDX_6G(181);
+	CASE_CHAN2BITMAP_IDX_6G(185);
+	CASE_CHAN2BITMAP_IDX_6G(189);
+	CASE_CHAN2BITMAP_IDX_6G(193);
+	CASE_CHAN2BITMAP_IDX_6G(197);
+	CASE_CHAN2BITMAP_IDX_6G(201);
+	CASE_CHAN2BITMAP_IDX_6G(205);
+	CASE_CHAN2BITMAP_IDX_6G(209);
+	CASE_CHAN2BITMAP_IDX_6G(213);
+	CASE_CHAN2BITMAP_IDX_6G(217);
+	CASE_CHAN2BITMAP_IDX_6G(221);
+	CASE_CHAN2BITMAP_IDX_6G(225);
+	CASE_CHAN2BITMAP_IDX_6G(229);
+	CASE_CHAN2BITMAP_IDX_6G(233);
+	};
+
+	return INVALID_CHAN_IDX;
+}
+
+u8 cl_channel_to_ext_index_6g(struct cl_hw *cl_hw, u32 channel)
+{
+	switch (channel) {
+	CASE_CHAN2EXT_IDX_6G(1);
+	CASE_CHAN2EXT_IDX_6G(2);
+	CASE_CHAN2EXT_IDX_6G(3);
+	CASE_CHAN2EXT_IDX_6G(5);
+	CASE_CHAN2EXT_IDX_6G(7);
+	CASE_CHAN2EXT_IDX_6G(9);
+	CASE_CHAN2EXT_IDX_6G(11);
+	CASE_CHAN2EXT_IDX_6G(13);
+	CASE_CHAN2EXT_IDX_6G(15);
+	CASE_CHAN2EXT_IDX_6G(17);
+	CASE_CHAN2EXT_IDX_6G(19);
+	CASE_CHAN2EXT_IDX_6G(21);
+	CASE_CHAN2EXT_IDX_6G(23);
+	CASE_CHAN2EXT_IDX_6G(25);
+	CASE_CHAN2EXT_IDX_6G(27);
+	CASE_CHAN2EXT_IDX_6G(29);
+	CASE_CHAN2EXT_IDX_6G(31);
+	CASE_CHAN2EXT_IDX_6G(33);
+	CASE_CHAN2EXT_IDX_6G(35);
+	CASE_CHAN2EXT_IDX_6G(37);
+	CASE_CHAN2EXT_IDX_6G(39);
+	CASE_CHAN2EXT_IDX_6G(41);
+	CASE_CHAN2EXT_IDX_6G(43);
+	CASE_CHAN2EXT_IDX_6G(45);
+	CASE_CHAN2EXT_IDX_6G(47);
+	CASE_CHAN2EXT_IDX_6G(49);
+	CASE_CHAN2EXT_IDX_6G(51);
+	CASE_CHAN2EXT_IDX_6G(53);
+	CASE_CHAN2EXT_IDX_6G(55);
+	CASE_CHAN2EXT_IDX_6G(57);
+	CASE_CHAN2EXT_IDX_6G(59);
+	CASE_CHAN2EXT_IDX_6G(61);
+	CASE_CHAN2EXT_IDX_6G(63);
+	CASE_CHAN2EXT_IDX_6G(65);
+	CASE_CHAN2EXT_IDX_6G(67);
+	CASE_CHAN2EXT_IDX_6G(69);
+	CASE_CHAN2EXT_IDX_6G(71);
+	CASE_CHAN2EXT_IDX_6G(73);
+	CASE_CHAN2EXT_IDX_6G(75);
+	CASE_CHAN2EXT_IDX_6G(77);
+	CASE_CHAN2EXT_IDX_6G(79);
+	CASE_CHAN2EXT_IDX_6G(81);
+	CASE_CHAN2EXT_IDX_6G(83);
+	CASE_CHAN2EXT_IDX_6G(85);
+	CASE_CHAN2EXT_IDX_6G(87);
+	CASE_CHAN2EXT_IDX_6G(89);
+	CASE_CHAN2EXT_IDX_6G(91);
+	CASE_CHAN2EXT_IDX_6G(93);
+	CASE_CHAN2EXT_IDX_6G(95);
+	CASE_CHAN2EXT_IDX_6G(97);
+	CASE_CHAN2EXT_IDX_6G(99);
+	CASE_CHAN2EXT_IDX_6G(101);
+	CASE_CHAN2EXT_IDX_6G(103);
+	CASE_CHAN2EXT_IDX_6G(105);
+	CASE_CHAN2EXT_IDX_6G(107);
+	CASE_CHAN2EXT_IDX_6G(109);
+	CASE_CHAN2EXT_IDX_6G(111);
+	CASE_CHAN2EXT_IDX_6G(113);
+	CASE_CHAN2EXT_IDX_6G(115);
+	CASE_CHAN2EXT_IDX_6G(117);
+	CASE_CHAN2EXT_IDX_6G(119);
+	CASE_CHAN2EXT_IDX_6G(121);
+	CASE_CHAN2EXT_IDX_6G(123);
+	CASE_CHAN2EXT_IDX_6G(125);
+	CASE_CHAN2EXT_IDX_6G(127);
+	CASE_CHAN2EXT_IDX_6G(129);
+	CASE_CHAN2EXT_IDX_6G(131);
+	CASE_CHAN2EXT_IDX_6G(133);
+	CASE_CHAN2EXT_IDX_6G(135);
+	CASE_CHAN2EXT_IDX_6G(137);
+	CASE_CHAN2EXT_IDX_6G(139);
+	CASE_CHAN2EXT_IDX_6G(141);
+	CASE_CHAN2EXT_IDX_6G(143);
+	CASE_CHAN2EXT_IDX_6G(145);
+	CASE_CHAN2EXT_IDX_6G(147);
+	CASE_CHAN2EXT_IDX_6G(149);
+	CASE_CHAN2EXT_IDX_6G(151);
+	CASE_CHAN2EXT_IDX_6G(153);
+	CASE_CHAN2EXT_IDX_6G(155);
+	CASE_CHAN2EXT_IDX_6G(157);
+	CASE_CHAN2EXT_IDX_6G(159);
+	CASE_CHAN2EXT_IDX_6G(161);
+	CASE_CHAN2EXT_IDX_6G(163);
+	CASE_CHAN2EXT_IDX_6G(165);
+	CASE_CHAN2EXT_IDX_6G(167);
+	CASE_CHAN2EXT_IDX_6G(169);
+	CASE_CHAN2EXT_IDX_6G(171);
+	CASE_CHAN2EXT_IDX_6G(173);
+	CASE_CHAN2EXT_IDX_6G(175);
+	CASE_CHAN2EXT_IDX_6G(177);
+	CASE_CHAN2EXT_IDX_6G(179);
+	CASE_CHAN2EXT_IDX_6G(181);
+	CASE_CHAN2EXT_IDX_6G(183);
+	CASE_CHAN2EXT_IDX_6G(185);
+	CASE_CHAN2EXT_IDX_6G(187);
+	CASE_CHAN2EXT_IDX_6G(189);
+	CASE_CHAN2EXT_IDX_6G(191);
+	CASE_CHAN2EXT_IDX_6G(193);
+	CASE_CHAN2EXT_IDX_6G(195);
+	CASE_CHAN2EXT_IDX_6G(197);
+	CASE_CHAN2EXT_IDX_6G(199);
+	CASE_CHAN2EXT_IDX_6G(201);
+	CASE_CHAN2EXT_IDX_6G(203);
+	CASE_CHAN2EXT_IDX_6G(205);
+	CASE_CHAN2EXT_IDX_6G(207);
+	CASE_CHAN2EXT_IDX_6G(209);
+	CASE_CHAN2EXT_IDX_6G(211);
+	CASE_CHAN2EXT_IDX_6G(213);
+	CASE_CHAN2EXT_IDX_6G(215);
+	CASE_CHAN2EXT_IDX_6G(217);
+	CASE_CHAN2EXT_IDX_6G(219);
+	CASE_CHAN2EXT_IDX_6G(221);
+	CASE_CHAN2EXT_IDX_6G(223);
+	CASE_CHAN2EXT_IDX_6G(225);
+	CASE_CHAN2EXT_IDX_6G(227);
+	CASE_CHAN2EXT_IDX_6G(229);
+	CASE_CHAN2EXT_IDX_6G(231);
+	CASE_CHAN2EXT_IDX_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_ext_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);
+}
+
+u8 cl_channel_to_bitmap_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_bitmap_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_bitmap_idx_to_freq_6g(struct cl_hw *cl_hw, u8 index)
+{
+	switch (index) {
+	CASE_BITMAP_IDX2FREQ_6G(1);
+	CASE_BITMAP_IDX2FREQ_6G(2);
+	CASE_BITMAP_IDX2FREQ_6G(5);
+	CASE_BITMAP_IDX2FREQ_6G(9);
+	CASE_BITMAP_IDX2FREQ_6G(13);
+	CASE_BITMAP_IDX2FREQ_6G(17);
+	CASE_BITMAP_IDX2FREQ_6G(21);
+	CASE_BITMAP_IDX2FREQ_6G(25);
+	CASE_BITMAP_IDX2FREQ_6G(29);
+	CASE_BITMAP_IDX2FREQ_6G(33);
+	CASE_BITMAP_IDX2FREQ_6G(37);
+	CASE_BITMAP_IDX2FREQ_6G(41);
+	CASE_BITMAP_IDX2FREQ_6G(45);
+	CASE_BITMAP_IDX2FREQ_6G(49);
+	CASE_BITMAP_IDX2FREQ_6G(53);
+	CASE_BITMAP_IDX2FREQ_6G(57);
+	CASE_BITMAP_IDX2FREQ_6G(61);
+	CASE_BITMAP_IDX2FREQ_6G(65);
+	CASE_BITMAP_IDX2FREQ_6G(69);
+	CASE_BITMAP_IDX2FREQ_6G(73);
+	CASE_BITMAP_IDX2FREQ_6G(77);
+	CASE_BITMAP_IDX2FREQ_6G(81);
+	CASE_BITMAP_IDX2FREQ_6G(85);
+	CASE_BITMAP_IDX2FREQ_6G(89);
+	CASE_BITMAP_IDX2FREQ_6G(93);
+	CASE_BITMAP_IDX2FREQ_6G(97);
+	CASE_BITMAP_IDX2FREQ_6G(101);
+	CASE_BITMAP_IDX2FREQ_6G(105);
+	CASE_BITMAP_IDX2FREQ_6G(109);
+	CASE_BITMAP_IDX2FREQ_6G(113);
+	CASE_BITMAP_IDX2FREQ_6G(117);
+	CASE_BITMAP_IDX2FREQ_6G(121);
+	CASE_BITMAP_IDX2FREQ_6G(125);
+	CASE_BITMAP_IDX2FREQ_6G(129);
+	CASE_BITMAP_IDX2FREQ_6G(133);
+	CASE_BITMAP_IDX2FREQ_6G(137);
+	CASE_BITMAP_IDX2FREQ_6G(141);
+	CASE_BITMAP_IDX2FREQ_6G(145);
+	CASE_BITMAP_IDX2FREQ_6G(149);
+	CASE_BITMAP_IDX2FREQ_6G(153);
+	CASE_BITMAP_IDX2FREQ_6G(157);
+	CASE_BITMAP_IDX2FREQ_6G(161);
+	CASE_BITMAP_IDX2FREQ_6G(165);
+	CASE_BITMAP_IDX2FREQ_6G(169);
+	CASE_BITMAP_IDX2FREQ_6G(173);
+	CASE_BITMAP_IDX2FREQ_6G(177);
+	CASE_BITMAP_IDX2FREQ_6G(181);
+	CASE_BITMAP_IDX2FREQ_6G(185);
+	CASE_BITMAP_IDX2FREQ_6G(189);
+	CASE_BITMAP_IDX2FREQ_6G(193);
+	CASE_BITMAP_IDX2FREQ_6G(197);
+	CASE_BITMAP_IDX2FREQ_6G(201);
+	CASE_BITMAP_IDX2FREQ_6G(205);
+	CASE_BITMAP_IDX2FREQ_6G(209);
+	CASE_BITMAP_IDX2FREQ_6G(213);
+	CASE_BITMAP_IDX2FREQ_6G(217);
+	CASE_BITMAP_IDX2FREQ_6G(221);
+	CASE_BITMAP_IDX2FREQ_6G(225);
+	CASE_BITMAP_IDX2FREQ_6G(229);
+	CASE_BITMAP_IDX2FREQ_6G(233);
+	};
+
+	return INVALID_FREQ;
+}
+
+u16 cl_channel_ext_idx_to_freq_6g(struct cl_hw *cl_hw, u8 index)
+{
+	switch (index) {
+	CASE_EXT_IDX2FREQ_6G(1);
+	CASE_EXT_IDX2FREQ_6G(2);
+	CASE_EXT_IDX2FREQ_6G(3);
+	CASE_EXT_IDX2FREQ_6G(5);
+	CASE_EXT_IDX2FREQ_6G(7);
+	CASE_EXT_IDX2FREQ_6G(9);
+	CASE_EXT_IDX2FREQ_6G(11);
+	CASE_EXT_IDX2FREQ_6G(13);
+	CASE_EXT_IDX2FREQ_6G(15);
+	CASE_EXT_IDX2FREQ_6G(17);
+	CASE_EXT_IDX2FREQ_6G(19);
+	CASE_EXT_IDX2FREQ_6G(21);
+	CASE_EXT_IDX2FREQ_6G(23);
+	CASE_EXT_IDX2FREQ_6G(25);
+	CASE_EXT_IDX2FREQ_6G(27);
+	CASE_EXT_IDX2FREQ_6G(29);
+	CASE_EXT_IDX2FREQ_6G(31);
+	CASE_EXT_IDX2FREQ_6G(33);
+	CASE_EXT_IDX2FREQ_6G(35);
+	CASE_EXT_IDX2FREQ_6G(37);
+	CASE_EXT_IDX2FREQ_6G(39);
+	CASE_EXT_IDX2FREQ_6G(41);
+	CASE_EXT_IDX2FREQ_6G(43);
+	CASE_EXT_IDX2FREQ_6G(45);
+	CASE_EXT_IDX2FREQ_6G(47);
+	CASE_EXT_IDX2FREQ_6G(49);
+	CASE_EXT_IDX2FREQ_6G(51);
+	CASE_EXT_IDX2FREQ_6G(53);
+	CASE_EXT_IDX2FREQ_6G(55);
+	CASE_EXT_IDX2FREQ_6G(57);
+	CASE_EXT_IDX2FREQ_6G(59);
+	CASE_EXT_IDX2FREQ_6G(61);
+	CASE_EXT_IDX2FREQ_6G(63);
+	CASE_EXT_IDX2FREQ_6G(65);
+	CASE_EXT_IDX2FREQ_6G(67);
+	CASE_EXT_IDX2FREQ_6G(69);
+	CASE_EXT_IDX2FREQ_6G(71);
+	CASE_EXT_IDX2FREQ_6G(73);
+	CASE_EXT_IDX2FREQ_6G(75);
+	CASE_EXT_IDX2FREQ_6G(77);
+	CASE_EXT_IDX2FREQ_6G(79);
+	CASE_EXT_IDX2FREQ_6G(81);
+	CASE_EXT_IDX2FREQ_6G(83);
+	CASE_EXT_IDX2FREQ_6G(85);
+	CASE_EXT_IDX2FREQ_6G(87);
+	CASE_EXT_IDX2FREQ_6G(89);
+	CASE_EXT_IDX2FREQ_6G(91);
+	CASE_EXT_IDX2FREQ_6G(93);
+	CASE_EXT_IDX2FREQ_6G(95);
+	CASE_EXT_IDX2FREQ_6G(97);
+	CASE_EXT_IDX2FREQ_6G(99);
+	CASE_EXT_IDX2FREQ_6G(101);
+	CASE_EXT_IDX2FREQ_6G(103);
+	CASE_EXT_IDX2FREQ_6G(105);
+	CASE_EXT_IDX2FREQ_6G(107);
+	CASE_EXT_IDX2FREQ_6G(109);
+	CASE_EXT_IDX2FREQ_6G(111);
+	CASE_EXT_IDX2FREQ_6G(113);
+	CASE_EXT_IDX2FREQ_6G(115);
+	CASE_EXT_IDX2FREQ_6G(117);
+	CASE_EXT_IDX2FREQ_6G(119);
+	CASE_EXT_IDX2FREQ_6G(121);
+	CASE_EXT_IDX2FREQ_6G(123);
+	CASE_EXT_IDX2FREQ_6G(125);
+	CASE_EXT_IDX2FREQ_6G(127);
+	CASE_EXT_IDX2FREQ_6G(129);
+	CASE_EXT_IDX2FREQ_6G(131);
+	CASE_EXT_IDX2FREQ_6G(133);
+	CASE_EXT_IDX2FREQ_6G(135);
+	CASE_EXT_IDX2FREQ_6G(137);
+	CASE_EXT_IDX2FREQ_6G(139);
+	CASE_EXT_IDX2FREQ_6G(141);
+	CASE_EXT_IDX2FREQ_6G(143);
+	CASE_EXT_IDX2FREQ_6G(145);
+	CASE_EXT_IDX2FREQ_6G(147);
+	CASE_EXT_IDX2FREQ_6G(149);
+	CASE_EXT_IDX2FREQ_6G(151);
+	CASE_EXT_IDX2FREQ_6G(153);
+	CASE_EXT_IDX2FREQ_6G(155);
+	CASE_EXT_IDX2FREQ_6G(157);
+	CASE_EXT_IDX2FREQ_6G(159);
+	CASE_EXT_IDX2FREQ_6G(161);
+	CASE_EXT_IDX2FREQ_6G(163);
+	CASE_EXT_IDX2FREQ_6G(165);
+	CASE_EXT_IDX2FREQ_6G(167);
+	CASE_EXT_IDX2FREQ_6G(169);
+	CASE_EXT_IDX2FREQ_6G(171);
+	CASE_EXT_IDX2FREQ_6G(173);
+	CASE_EXT_IDX2FREQ_6G(175);
+	CASE_EXT_IDX2FREQ_6G(177);
+	CASE_EXT_IDX2FREQ_6G(179);
+	CASE_EXT_IDX2FREQ_6G(181);
+	CASE_EXT_IDX2FREQ_6G(183);
+	CASE_EXT_IDX2FREQ_6G(185);
+	CASE_EXT_IDX2FREQ_6G(187);
+	CASE_EXT_IDX2FREQ_6G(189);
+	CASE_EXT_IDX2FREQ_6G(191);
+	CASE_EXT_IDX2FREQ_6G(193);
+	CASE_EXT_IDX2FREQ_6G(195);
+	CASE_EXT_IDX2FREQ_6G(197);
+	CASE_EXT_IDX2FREQ_6G(199);
+	CASE_EXT_IDX2FREQ_6G(201);
+	CASE_EXT_IDX2FREQ_6G(203);
+	CASE_EXT_IDX2FREQ_6G(205);
+	CASE_EXT_IDX2FREQ_6G(207);
+	CASE_EXT_IDX2FREQ_6G(209);
+	CASE_EXT_IDX2FREQ_6G(211);
+	CASE_EXT_IDX2FREQ_6G(213);
+	CASE_EXT_IDX2FREQ_6G(215);
+	CASE_EXT_IDX2FREQ_6G(217);
+	CASE_EXT_IDX2FREQ_6G(219);
+	CASE_EXT_IDX2FREQ_6G(221);
+	CASE_EXT_IDX2FREQ_6G(223);
+	CASE_EXT_IDX2FREQ_6G(225);
+	CASE_EXT_IDX2FREQ_6G(227);
+	CASE_EXT_IDX2FREQ_6G(229);
+	CASE_EXT_IDX2FREQ_6G(231);
+	CASE_EXT_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_bitmap_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_BITMAP_CHANNELS_6G;
+
+	if (cl_hw->conf->ci_band_num == 5)
+		return NUM_CHANNELS_5G;
+
+	return NUM_CHANNELS_24G;
+}
+
+bool cl_channel_is_dfs(struct cl_hw *cl_hw, u8 channel)
+{
+	if (!cl_band_is_5g(cl_hw))
+		return false;
+
+	return channel >= 36 && channel <= 144;
+}
+
+u32 cl_channel_get_cac_time_ms(struct cl_hw *cl_hw, u8 channel)
+{
+	if (!cl_band_is_5g(cl_hw))
+		return 0;
+
+	if (!cl_channel_is_dfs(cl_hw, channel))
+		return 0;
+
+	/* FIXME: CAC time for weather channels may differ for some regions */
+	if (channel >= 120 && channel <= 128)
+		return IEEE80211_DFS_WEATHER_MIN_CAC_TIME_MS;
+
+	return IEEE80211_DFS_MIN_CAC_TIME_MS;
+}
+
+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,
+				  u32 flags, u32 dfs_cac_ms)
+{
+	struct cl_chan_info *chan_info = &cl_hw->channel_info.channels[bw][ch_idx];
+
+	chan_info->channel = channel;
+	chan_info->country_max_power_q2 = country_max_power_q2;
+	chan_info->max_power_q2 = max_power_q2;
+	chan_info->flags = flags;
+	chan_info->dfs_cac_ms = dfs_cac_ms;
+}
+
+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)
+{
+	_cl_fill_channel_info(cl_hw, bw, ch_idx, channel, country_max_power_q2, max_power_q2, 0, 0);
+}
+
+static void cl_fill_channel_info_5g(struct cl_hw *cl_hw, u8 bw, u8 ch_idx, u8 channel,
+				    u8 country_max_power_q2, u8 max_power_q2)
+{
+	u32 flags = 0;
+	u32 dfs_cac_ms = 0;
+
+	if (cl_hw->conf->ci_ieee80211h && cl_channel_is_dfs(cl_hw, channel)) {
+		flags |= IEEE80211_CHAN_RADAR;
+		dfs_cac_ms = cl_channel_get_cac_time_ms(cl_hw, channel);
+	}
+
+	_cl_fill_channel_info(cl_hw, bw, ch_idx, channel, country_max_power_q2,
+			      max_power_q2, flags, dfs_cac_ms);
+}
+
+static inline s32 cl_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 = NL80211_DFS_FCC;
+		cl_dbg_info(cl_hw, "Standard = FCC\n");
+		return 0;
+	}
+
+	if (strstr(token, "ETSI")) {
+		cl_hw->channel_info.standard = NL80211_DFS_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 = NL80211_DFS_UNSET;
+	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)
+	 */
+
+	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;
+	char file_name[CL_FILENAME_MAX] = {0};
+
+	snprintf(file_name, sizeof(file_name), "channel_info_chip%d.txt", cl_hw->chip->idx);
+
+	/* Read channel_info.txt into buf */
+	size = cl_file_open_and_read(cl_hw->chip, file_name, &buf);
+
+	if (!buf)
+		return false;
+
+	/* Jump to the correct country in the file */
+	snprintf(cc_str, sizeof(cc_str), "[%s", cl_hw->chip->conf->ci_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')) {
+			u32 flags = 0, dfs_cac_ms = 0;
+
+			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;
+
+			if (cl_hw->conf->ci_ieee80211h && cl_channel_is_dfs(cl_hw, channel)) {
+				flags |= IEEE80211_CHAN_RADAR;
+				dfs_cac_ms = cl_channel_get_cac_time_ms(cl_hw, channel);
+			}
+
+			_cl_fill_channel_info(cl_hw, bw, i, channel, max_power << 2,
+					      max_power << 2, flags, dfs_cac_ms);
+
+			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_BITMAP_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 */
+/* Default regulatory domain:
+ * country US: DFS-FCC
+ *       (2400 - 2472 @ 40), (N/A, 30), (N/A)
+ *       (5150 - 5250 @ 80), (N/A, 23), (N/A), AUTO-BW
+ *       (5250 - 5350 @ 80), (N/A, 23), (0 ms), DFS, AUTO-BW
+ *       (5470 - 5730 @ 160), (N/A, 23), (0 ms), DFS
+ *       (5730 - 5850 @ 80), (N/A, 30), (N/A), AUTO-BW
+ *       (5850 - 5895 @ 40), (N/A, 27), (N/A), NO-OUTDOOR, AUTO-BW, PASSIVE-SCAN
+ *       (57240 - 71000 @ 2160), (N/A, 40), (N/A)
+ */
+#define UNII_1_POW_Q2     (23 << 2)
+#define UNII_2_POW_Q2     (23 << 2)
+#define UNII_2_EXT_POW_Q2 (23 << 2)
+#define UNII_3_POW_Q2     (30 << 2)
+
+/* Band 2.4G - default power */
+#define BAND_24G_POW_Q2   (30 << 2)
+
+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_5g(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_5g(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_5g(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_5g(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 = NL80211_DFS_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);
+}
+
+/*
+ * 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 beteen 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)
+{
+	char *table_str = NULL;
+	char *table_str_p = NULL;
+	char *channel_str = NULL;
+	char *channel_str_p = NULL;
+	char *bw_set = NULL;
+	char *out_tok = 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_p = kzalloc(CL_MAX_STR_BUFFER_SIZE / 2, GFP_KERNEL);
+	if (!table_str_p)
+		return;
+
+	channel_str_p = kzalloc(CL_MAX_STR_BUFFER_SIZE / 2, GFP_KERNEL);
+	if (!channel_str_p) {
+		kfree(table_str_p);
+		cl_dbg_err(cl_hw, "Failed to allocate channel_str\n");
+		return;
+	}
+
+	table_str = table_str_p;
+
+	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 = strsep(&table_str, "#");
+	while (bw_set) {
+		channel_str = channel_str_p;
+		if (sscanf(bw_set, "%hhu(%s)", &bw_mhz, channel_str) != 2) {
+			bw_set = strsep(&table_str, "#");
+			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 = strsep(&channel_str, ";");
+
+		while (out_tok) {
+			if (sscanf(out_tok, "%hhu=%s", &chan_end, in_reg_pwr) == 2) {
+				next_pwr_q2 = cl_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 = strsep(&channel_str, ";");
+		}
+
+		/* 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 = strsep(&table_str, "#");
+	}
+
+	kfree(table_str_p);
+	kfree(channel_str_p);
+}
+
+static void cl_chan_info_ieee80211_update_max_power(struct cl_hw *cl_hw)
+{
+	struct ieee80211_supported_band *sband =  &cl_hw->sband;
+	struct ieee80211_channel *chan = NULL;
+	int i = 0, channel;
+
+	for (i = 0; i < sband->n_channels; i++) {
+		chan = &sband->channels[i];
+		channel = ieee80211_frequency_to_channel(chan->center_freq);
+		chan->max_power = cl_chan_info_get_max_power(cl_hw, channel);
+	}
+}
+
+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 = true;
+
+	if (channel_info->use_channel_info) {
+		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_ieee80211_update_max_power(cl_hw);
+		cl_chan_info_set_max_bw(cl_hw);
+		cl_chan_info_dbg(cl_hw);
+	} else {
+		cl_set_default_channel_info(cl_hw);
+	}
+
+	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;
+}
+
+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 < CHNL_BW_MAX; 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;
+}
+
+static void cl_chan_update_channel_info(struct cl_hw *cl_hw, struct ieee80211_channel *channel)
+{
+	u8 bw;
+	u32 chan = ieee80211_frequency_to_channel(channel->center_freq);
+	struct cl_chan_info *chan_info;
+
+	for (bw = CHNL_BW_20; bw < CHNL_BW_MAX; bw++) {
+		chan_info = cl_chan_info_get(cl_hw, chan, bw);
+		if (!chan_info || chan_info->channel == 0)
+			continue;
+
+		chan_info->max_power_q2         = channel->max_power << 2;
+		chan_info->country_max_power_q2 = channel->max_reg_power << 2;
+		chan_info->flags = channel->flags;
+		chan_info->dfs_cac_ms = channel->dfs_cac_ms;
+	}
+}
+
+void cl_chan_update_channels_info(struct cl_hw *cl_hw,
+				  const struct ieee80211_supported_band *cfg_band)
+{
+	int i = 0;
+
+	spin_lock_bh(&cl_hw->channel_info_lock);
+	for (i = 0; i < cfg_band->n_channels; ++i)
+		cl_chan_update_channel_info(cl_hw, &cfg_band->channels[i]);
+	spin_unlock_bh(&cl_hw->channel_info_lock);
+}
+
+#define CENTER_FREQ_24G_BW_80MHZ  2442
+#define CENTER_FREQ_24G_BW_160MHZ 2482
+
+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 (bw == CHNL_BW_40) {
+		if (freq <= FREQ2G(4)) {
+			/* Above extension channel */
+			*center = *primary + offset;
+		} else if (freq >= FREQ2G(10)) {
+			/* Below extension channel */
+			*center = *primary - offset;
+		} else {
+			/* Channels 8-9 must be below if channel 13 is not supported */
+			if (freq >= FREQ2G(8) && !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 the current hapd configuration.
+				 * If undefined, preffer above offset.
+				 */
+				if (cl_hw->ht40_preffered_ch_type == NL80211_CHAN_HT40MINUS)
+					*center = *primary - offset;
+				else
+					*center = *primary + offset;
+			}
+		}
+	} else if (bw == CHNL_BW_80) {
+		*center = CENTER_FREQ_24G_BW_80MHZ;
+	} else {
+		/* 160MHz */
+		*center = CENTER_FREQ_24G_BW_160MHZ;
+	}
+
+	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_hw->chip->conf->ce_production_mode && 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:
+		/* Verify 2.4G bandwidth validity only in operational mode */
+		if (!cl_hw->chip->conf->ce_production_mode && 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, u32 *channel, u8 *bw,
+			   enum nl80211_chan_width *width,
+			   u32 *primary, u32 *center)
+{
+	*bw = cl_hw->conf->ci_chandef_bandwidth;
+	*channel = cl_hw->conf->ci_chandef_channel;
+
+	return cl_chandef_calc(cl_hw, *channel, *bw, width, primary, center);
+}
+
+int cl_init_channel_stats(struct cl_hw *cl_hw,
+			  struct cl_channel_stats *ch_stats, u32 freq)
+{
+	memset(ch_stats, 0, sizeof(*ch_stats));
+
+	ch_stats->channel = ieee80211_frequency_to_channel(freq);
+	if (ch_stats->channel == INVALID_CHAN_IDX) {
+		cl_dbg_err(cl_hw, "Failed to get channel num for freq %u\n", freq);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+void cl_get_final_channel_stats(struct cl_hw *cl_hw, struct cl_channel_stats *ch_stats)
+{
+	u32 tx_mine, rx_mine, edca_cca;
+
+	/*
+	 * Currently mac_hw_rx_mine_busy_get() doesn't work properly,
+	 * so use mac_hw_edca_cca_busy_get() as workaround.
+	 * After scan mac_hw_rx_mine_busy_get almost always returns zeros
+	 * or some very small values.
+	 * Use of EDCA CCA is less accurate, since it also includes non-wifi noise
+	 */
+	tx_mine = mac_hw_tx_mine_busy_get(cl_hw);
+	edca_cca = mac_hw_edca_cca_busy_get(cl_hw);
+	rx_mine = edca_cca;
+
+	ch_stats->util_time_tx = max_t(s64, tx_mine - ch_stats->util_time_tx_total, 0);
+	ch_stats->util_time_rx = max_t(s64, rx_mine - ch_stats->util_time_rx_total, 0);
+	ch_stats->edca_cca_time = max_t(s64, edca_cca - ch_stats->edca_cca_time_total, 0);
+
+	ch_stats->util_time_busy = ch_stats->edca_cca_time + ch_stats->util_time_tx;
+
+	ch_stats->ch_noise = cl_calc_noise_floor(cl_hw, NULL);
+
+	ch_stats->scan_time_ms = jiffies_to_msecs(get_jiffies_64() - ch_stats->scan_start_jiffies);
+}
+
+void cl_get_initial_channel_stats(struct cl_hw *cl_hw, struct cl_channel_stats *ch_stats)
+{
+	ch_stats->util_time_tx = 0;
+	ch_stats->util_time_rx = 0;
+	ch_stats->edca_cca_time = 0;
+	ch_stats->util_time_busy = 0;
+	ch_stats->ch_noise = 0;
+	ch_stats->scan_time_ms = 0;
+
+	ch_stats->util_time_tx_total = mac_hw_tx_mine_busy_get(cl_hw);
+	ch_stats->edca_cca_time_total = mac_hw_edca_cca_busy_get(cl_hw);
+	ch_stats->util_time_rx_total = ch_stats->edca_cca_time_total;
+
+	ch_stats->scan_start_jiffies = get_jiffies_64();
+}
-- 
2.36.1


  parent reply	other threads:[~2022-05-24 11:38 UTC|newest]

Thread overview: 125+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2022-05-24 11:33 [RFC v2 00/96] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
2022-05-24 11:33 ` [RFC v2 01/96] celeno: add Kconfig viktor.barna
2022-05-24 11:33 ` [RFC v2 02/96] celeno: add Makefile viktor.barna
2022-05-24 11:33 ` [RFC v2 03/96] cl8k: add Kconfig viktor.barna
2022-05-26 18:18   ` Johannes Berg
2022-05-27  6:09     ` Kalle Valo
2022-07-11 23:04       ` Viktor Barna
2022-07-13  7:32   ` Kalle Valo
2022-05-24 11:33 ` [RFC v2 04/96] cl8k: add Makefile viktor.barna
2022-05-26 18:24   ` Johannes Berg
2022-07-13  7:39   ` Kalle Valo
2022-05-24 11:33 ` [RFC v2 05/96] cl8k: add ampdu.c viktor.barna
2022-05-26 18:19   ` Johannes Berg
2022-05-26 18:22   ` Johannes Berg
2022-05-24 11:33 ` [RFC v2 06/96] cl8k: add ampdu.h viktor.barna
2022-05-24 11:33 ` [RFC v2 07/96] cl8k: add bf.c viktor.barna
2022-05-24 17:24   ` Jeff Johnson
2022-05-24 11:33 ` [RFC v2 08/96] cl8k: add bf.h viktor.barna
2022-05-24 11:33 ` [RFC v2 09/96] cl8k: add calib.c viktor.barna
2022-05-24 11:33 ` [RFC v2 10/96] cl8k: add calib.h viktor.barna
2022-05-24 11:33 ` viktor.barna [this message]
2022-05-24 11:33 ` [RFC v2 12/96] cl8k: add channel.h viktor.barna
2022-05-24 11:33 ` [RFC v2 13/96] cl8k: add chip.c viktor.barna
2022-05-24 11:33 ` [RFC v2 14/96] cl8k: add chip.h viktor.barna
2022-05-24 11:33 ` [RFC v2 15/96] cl8k: add config.c viktor.barna
2022-05-24 11:33 ` [RFC v2 16/96] cl8k: add config.h viktor.barna
2022-05-25 18:31   ` Jeff Johnson
2022-05-24 11:33 ` [RFC v2 17/96] cl8k: add debug.c viktor.barna
2022-05-24 11:33 ` [RFC v2 18/96] cl8k: add debug.h viktor.barna
2022-05-24 11:33 ` [RFC v2 19/96] cl8k: add def.h viktor.barna
2022-05-25 18:39   ` Jeff Johnson
2022-05-24 11:33 ` [RFC v2 20/96] cl8k: add dfs.c viktor.barna
2022-05-24 11:33 ` [RFC v2 21/96] cl8k: add dfs.h viktor.barna
2022-05-24 11:33 ` [RFC v2 22/96] cl8k: add dsp.c viktor.barna
2022-05-24 11:33 ` [RFC v2 23/96] cl8k: add dsp.h viktor.barna
2022-05-24 11:33 ` [RFC v2 24/96] cl8k: add e2p.c viktor.barna
2022-05-24 11:33 ` [RFC v2 25/96] cl8k: add e2p.h viktor.barna
2022-05-24 11:33 ` [RFC v2 26/96] cl8k: add eeprom.h viktor.barna
2022-05-24 11:33 ` [RFC v2 27/96] cl8k: add ela.c viktor.barna
2022-05-24 11:33 ` [RFC v2 28/96] cl8k: add ela.h viktor.barna
2022-05-24 11:33 ` [RFC v2 29/96] cl8k: add enhanced_tim.c viktor.barna
2022-05-24 11:33 ` [RFC v2 30/96] cl8k: add enhanced_tim.h viktor.barna
2022-05-24 11:33 ` [RFC v2 31/96] cl8k: add fw.c viktor.barna
2022-05-24 11:33 ` [RFC v2 32/96] cl8k: add fw.h viktor.barna
2022-05-25 18:58   ` Jeff Johnson
2022-05-24 11:33 ` [RFC v2 33/96] cl8k: add hw.c viktor.barna
2022-05-24 11:34 ` [RFC v2 34/96] cl8k: add hw.h viktor.barna
2022-05-24 11:34 ` [RFC v2 35/96] cl8k: add ipc_shared.h viktor.barna
2022-05-24 11:34 ` [RFC v2 36/96] cl8k: add key.c viktor.barna
2022-05-26 19:38   ` Johannes Berg
2022-07-11 23:10     ` Viktor Barna
2022-05-24 11:34 ` [RFC v2 37/96] cl8k: add key.h viktor.barna
2022-05-24 11:34 ` [RFC v2 38/96] cl8k: add mac80211.c viktor.barna
2022-05-26 19:49   ` Johannes Berg
2022-07-11 23:13     ` Viktor Barna
2022-05-24 11:34 ` [RFC v2 39/96] cl8k: add mac80211.h viktor.barna
2022-05-26 19:52   ` Johannes Berg
2022-05-24 11:34 ` [RFC v2 40/96] cl8k: add mac_addr.c viktor.barna
2022-05-26 22:31   ` Jeff Johnson
2022-05-24 11:34 ` [RFC v2 41/96] cl8k: add mac_addr.h viktor.barna
2022-05-24 11:34 ` [RFC v2 42/96] cl8k: add main.c viktor.barna
2022-05-26 23:01   ` Jeff Johnson
2022-05-24 11:34 ` [RFC v2 43/96] cl8k: add main.h viktor.barna
2022-05-24 11:34 ` [RFC v2 44/96] cl8k: add maintenance.c viktor.barna
2022-05-24 11:34 ` [RFC v2 45/96] cl8k: add maintenance.h viktor.barna
2022-05-24 11:34 ` [RFC v2 46/96] cl8k: add motion_sense.c viktor.barna
2022-05-24 11:34 ` [RFC v2 47/96] cl8k: add motion_sense.h viktor.barna
2022-05-24 11:34 ` [RFC v2 48/96] cl8k: add pci.c viktor.barna
2022-05-24 11:34 ` [RFC v2 49/96] cl8k: add pci.h viktor.barna
2022-05-24 11:34 ` [RFC v2 50/96] cl8k: add phy.c viktor.barna
2022-06-01  0:27   ` Jeff Johnson
2022-07-11 23:16     ` Viktor Barna
2022-05-24 11:34 ` [RFC v2 51/96] cl8k: add phy.h viktor.barna
2022-05-24 11:34 ` [RFC v2 52/96] cl8k: add platform.c viktor.barna
2022-05-24 11:34 ` [RFC v2 53/96] cl8k: add platform.h viktor.barna
2022-05-24 11:34 ` [RFC v2 54/96] cl8k: add power.c viktor.barna
2022-05-24 11:34 ` [RFC v2 55/96] cl8k: add power.h viktor.barna
2022-05-24 11:34 ` [RFC v2 56/96] cl8k: add radio.c viktor.barna
2022-05-24 11:34 ` [RFC v2 57/96] cl8k: add radio.h viktor.barna
2022-05-24 11:34 ` [RFC v2 58/96] cl8k: add rates.c viktor.barna
2022-05-24 11:34 ` [RFC v2 59/96] cl8k: add rates.h viktor.barna
2022-05-26 19:54   ` Johannes Berg
2022-07-11 23:17     ` Viktor Barna
2022-07-12  7:17       ` Johannes Berg
2022-05-24 11:34 ` [RFC v2 60/96] cl8k: add recovery.c viktor.barna
2022-05-24 11:34 ` [RFC v2 61/96] cl8k: add recovery.h viktor.barna
2022-05-24 11:34 ` [RFC v2 62/96] cl8k: add regdom.c viktor.barna
2022-05-24 11:34 ` [RFC v2 63/96] cl8k: add regdom.h viktor.barna
2022-05-24 11:34 ` [RFC v2 64/96] cl8k: add reg/reg_access.h viktor.barna
2022-05-24 11:34 ` [RFC v2 65/96] cl8k: add reg/reg_defs.h viktor.barna
2022-05-24 11:34 ` [RFC v2 66/96] cl8k: add rfic.c viktor.barna
2022-05-24 11:34 ` [RFC v2 67/96] cl8k: add rfic.h viktor.barna
2022-06-02 20:40   ` Jeff Johnson
2022-07-11 23:18     ` Viktor Barna
2022-05-24 11:34 ` [RFC v2 68/96] cl8k: add rx.c viktor.barna
2022-05-24 11:34 ` [RFC v2 69/96] cl8k: add rx.h viktor.barna
2022-05-24 11:34 ` [RFC v2 70/96] cl8k: add scan.c viktor.barna
2022-05-24 11:34 ` [RFC v2 71/96] cl8k: add scan.h viktor.barna
2022-05-24 11:34 ` [RFC v2 72/96] cl8k: add sounding.c viktor.barna
2022-05-24 11:34 ` [RFC v2 73/96] cl8k: add sounding.h viktor.barna
2022-05-24 11:34 ` [RFC v2 74/96] cl8k: add sta.c viktor.barna
2022-05-24 11:34 ` [RFC v2 75/96] cl8k: add sta.h viktor.barna
2022-05-24 11:34 ` [RFC v2 76/96] cl8k: add stats.c viktor.barna
2022-06-02 20:59   ` Jeff Johnson
2022-07-11 23:20     ` Viktor Barna
2022-05-24 11:34 ` [RFC v2 77/96] cl8k: add stats.h viktor.barna
2022-05-24 11:34 ` [RFC v2 78/96] cl8k: add tcv.c viktor.barna
2022-05-24 11:34 ` [RFC v2 79/96] cl8k: add tcv.h viktor.barna
2022-05-24 11:34 ` [RFC v2 80/96] cl8k: add temperature.c viktor.barna
2022-05-24 11:34 ` [RFC v2 81/96] cl8k: add temperature.h viktor.barna
2022-05-24 11:34 ` [RFC v2 82/96] cl8k: add traffic.c viktor.barna
2022-05-24 11:34 ` [RFC v2 83/96] cl8k: add traffic.h viktor.barna
2022-05-24 11:34 ` [RFC v2 84/96] cl8k: add tx.c viktor.barna
2022-05-24 11:34 ` [RFC v2 85/96] cl8k: add tx.h viktor.barna
2022-05-24 11:34 ` [RFC v2 86/96] cl8k: add utils.c viktor.barna
2022-05-24 11:34 ` [RFC v2 87/96] cl8k: add utils.h viktor.barna
2022-05-24 11:34 ` [RFC v2 88/96] cl8k: add version.c viktor.barna
2022-05-24 11:34 ` [RFC v2 89/96] cl8k: add version.h viktor.barna
2022-05-24 11:34 ` [RFC v2 90/96] cl8k: add vif.c viktor.barna
2022-05-24 11:34 ` [RFC v2 91/96] cl8k: add vif.h viktor.barna
2022-05-24 11:34 ` [RFC v2 92/96] cl8k: add vns.c viktor.barna
2022-05-24 11:34 ` [RFC v2 93/96] cl8k: add vns.h viktor.barna
2022-05-24 11:35 ` [RFC v2 94/96] cl8k: add wrs.c viktor.barna
2022-05-24 11:35 ` [RFC v2 95/96] cl8k: add wrs.h viktor.barna
2022-05-24 11:35 ` [RFC v2 96/96] wireless: add Celeno vendor viktor.barna

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20220524113502.1094459-12-viktor.barna@celeno.com \
    --to=viktor.barna@celeno.com \
    --cc=aviad.brikman@celeno.com \
    --cc=davem@davemloft.net \
    --cc=eliav.farber@gmail.com \
    --cc=kuba@kernel.org \
    --cc=kvalo@codeaurora.org \
    --cc=linux-wireless@vger.kernel.org \
    --cc=maksym.kokhan@celeno.com \
    --cc=oleksandr.savchenko@celeno.com \
    --cc=shay.bar@celeno.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
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.