[][MAC80211][app][atenl: support mt7986]

[Description]
Add support for mt7986 and rework commands.

[Release-log]
N/A

Change-Id: Ibeb9a0bf260dca17dfae249929af0eac2a6b51f4
Reviewed-on: https://gerrit.mediatek.inc/c/openwrt/feeds/mtk_openwrt_feeds/+/6050196
diff --git a/feed/atenl/src/hqa.c b/feed/atenl/src/hqa.c
index 2196fe2..eabfce5 100644
--- a/feed/atenl/src/hqa.c
+++ b/feed/atenl/src/hqa.c
@@ -200,31 +200,7 @@
 {
 	struct atenl_cmd_hdr *hdr = atenl_hdr(data);
 
-	if (is_mt7986(an)) {
-		u32 sub_id, val;
-		int ret;
-
-		ret = atenl_reg_read(an, 0x18050000, &val);
-		if (ret)
-			return ret;
-
-		switch (val & 0xf) {
-		case MT7975_ONE_ADIE_SINGLE_BAND:
-		case MT7976_ONE_ADIE_SINGLE_BAND:
-			sub_id = htonl(0xa);
-			break;
-		case MT7976_ONE_ADIE_DBDC:
-			sub_id = htonl(0x7);
-			break;
-		case MT7975_DUAL_ADIE_DBDC:
-		case MT7976_DUAL_ADIE_DBDC:
-		default:
-			sub_id = htonl(0xf);
-			break;
-		}
-
-		memcpy(hdr->data + 2, &sub_id, 4);
-	}
+	*(u32 *)(hdr->data + 2) = htonl(an->sub_chip_id);
 
 	return 0;
 }
@@ -266,13 +242,12 @@
 	struct atenl_cmd_hdr *hdr = atenl_hdr(data);
 	enum atenl_cmd cmd = data->cmd;
 	u32 *v = (u32 *)hdr->data;
-	u32 offset = ntohl(v[0]);
+	u32 offset = ntohl(v[0]), res;
 	int ret;
 
 	if (cmd == HQA_CMD_READ_MAC_BBP_REG) {
 		u16 num = ntohs(*(u16 *)(hdr->data + 4));
 		u32 *ptr = (u32 *)(hdr->data + 2);
-		u32 res;
 		int i;
 
 		if (num > SHRT_MAX) {
@@ -289,6 +264,13 @@
 			res = htonl(res);
 			memcpy(ptr + i, &res, 4);
 		}
+	} else if (cmd == HQA_CMD_READ_MAC_BBP_REG_QA) {
+		ret = atenl_reg_read(an, offset, &res);
+		if (ret)
+			goto out;
+
+		res = htonl(res);
+		memcpy(hdr->data + 2, &res, 4);
 	} else {
 		u32 val = ntohl(v[1]);
 
@@ -305,6 +287,49 @@
 }
 
 static int
+atenl_hqa_rf_reg(struct atenl *an, struct atenl_data *data)
+{
+	struct atenl_cmd_hdr *hdr = atenl_hdr(data);
+	enum atenl_cmd cmd = data->cmd;
+	u32 *v = (u32 *)hdr->data;
+	u32 wf_sel = ntohl(v[0]);
+	u32 offset = ntohl(v[1]);
+	u32 num = ntohl(v[2]);
+	int ret, i;
+
+	if (cmd == HQA_CMD_READ_RF_REG) {
+		u32 *ptr = (u32 *)(hdr->data + 2);
+		u32 res;
+
+		hdr->len = htons(2 + num * 4);
+		for (i = 0; i < num && i < sizeof(hdr->data) / 4; i++) {
+			ret = atenl_rf_read(an, wf_sel, offset + i * 4, &res);
+			if (ret)
+				goto out;
+
+			res = htonl(res);
+			memcpy(ptr + i, &res, 4);
+		}
+	} else {
+		u32 *ptr = (u32 *)(hdr->data + 12);
+
+		for (i = 0; i < num && i < sizeof(hdr->data) / 4; i++) {
+			u32 val = ntohl(ptr[i]);
+
+			ret = atenl_rf_write(an, wf_sel, offset + i * 4, val);
+			if (ret)
+				goto out;
+		}
+	}
+
+	ret = 0;
+out:
+	memset(hdr->data, 0, 2);
+
+	return ret;
+}
+
+static int
 atenl_hqa_eeprom_bulk(struct atenl *an, struct atenl_data *data)
 {
 	struct atenl_cmd_hdr *hdr = atenl_hdr(data);
@@ -448,12 +473,6 @@
 }
 
 static int
-atenl_hqa_skip(struct atenl *an, struct atenl_data *data)
-{
-	return 0;
-}
-
-static int
 atenl_hqa_check_efuse_mode(struct atenl *an, struct atenl_data *data)
 {
 	struct atenl_cmd_hdr *hdr = atenl_hdr(data);
@@ -587,7 +606,7 @@
 	if (snprintf_error(sizeof(cmd), ret))
 		return;
 
-	atenl_dbg("[%d]%s: cmd: %s\n", getpid(), __func__, cmd);
+	atenl_dbg("%s: cmd: %s\n", __func__, cmd);
 
 	system(cmd);
 }
@@ -692,6 +711,8 @@
 
 	*(u32 *)(hdr->data + 2) = data->ext_id;
 
+	atenl_nl_set_aid(an, band, 0);
+
 	return 0;
 }
 
@@ -712,314 +733,504 @@
 	return 0;
 }
 
-static inline enum atenl_cmd atenl_get_cmd_by_id(u16 cmd_idx)
-{
-#define CMD_ID_GROUP	GENMASK(15, 8)
-	u8 group = FIELD_GET(CMD_ID_GROUP, cmd_idx);
-
-	if (cmd_idx == 0x1600)
-		return HQA_CMD_EXT;
-
-	if (group == 0x10) {
-		switch (cmd_idx) {
-		case 0x1000:
-			return HQA_CMD_OPEN_ADAPTER;
-		case 0x1001:
-			return HQA_CMD_CLOSE_ADAPTER;
-		case 0x100b:
-			return HQA_CMD_SET_TX_PATH;
-		case 0x100c:
-			return HQA_CMD_SET_RX_PATH;
-		case 0x1011:
-			return HQA_CMD_SET_TX_POWER;
-		case 0x1018:
-			return HQA_CMD_SET_TX_POWER_MANUAL;
-		case 0x100d:
-			return HQA_CMD_LEGACY;
-		default:
-			break;
-		}
-	} else if (group == 0x11) {
-		switch (cmd_idx) {
-		case 0x1104:
-			return HQA_CMD_SET_TX_BW;
-		case 0x1105:
-			return HQA_CMD_SET_TX_PKT_BW;
-		case 0x1106:
-			return HQA_CMD_SET_TX_PRI_BW;
-		case 0x1107:
-			return HQA_CMD_SET_FREQ_OFFSET;
-		case 0x1109:
-			return HQA_CMD_SET_TSSI;
-		case 0x110d:
-			return HQA_CMD_ANT_SWAP_CAP;
-		case 0x1101:
-		case 0x1102:
-			return HQA_CMD_LEGACY;
-		default:
-			break;
-		}
-	} else if (group == 0x12) {
-		switch (cmd_idx) {
-		case 0x1200:
-			return HQA_CMD_RESET_TX_RX_COUNTER;
-		default:
-			break;
-		}
-	} else if (group == 0x13) {
-		switch (cmd_idx) {
-		case 0x1301:
-			return HQA_CMD_WRITE_MAC_BBP_REG;
-		case 0x1302:
-			return HQA_CMD_READ_MAC_BBP_REG;
-		case 0x1307:
-			return HQA_CMD_READ_EEPROM_BULK;
-		case 0x1306:
-		case 0x1308:
-			return HQA_CMD_WRITE_EEPROM_BULK;
-		case 0x1309:
-			return HQA_CMD_CHECK_EFUSE_MODE;
-		case 0x130a:
-			return HQA_CMD_GET_EFUSE_FREE_BLOCK;
-		case 0x130d:
-			return HQA_CMD_GET_TX_POWER;
-		case 0x130e:
-			return HQA_CMD_SET_CFG;
-		case 0x130f:
-			return HQA_CMD_GET_FREQ_OFFSET;
-		case 0x1311:
-			return HQA_CMD_CONTINUOUS_TX;
-		case 0x1312:
-			return HQA_CMD_SET_RX_PKT_LEN;
-		case 0x1313:
-			return HQA_CMD_GET_TX_INFO;
-		case 0x1314:
-			return HQA_CMD_GET_CFG;
-		case 0x131f:
-			return HQA_CMD_UNKNOWN;
-		case 0x131a:
-			return HQA_CMD_GET_TX_TONE_POWER;
-		default:
-			break;
-		}
-	} else if (group == 0x14) {
-		switch (cmd_idx) {
-		case 0x1401:
-			return HQA_CMD_READ_TEMPERATURE;
-		default:
-			break;
-		}
-	} else if (group == 0x15) {
-		switch (cmd_idx) {
-		case 0x1500:
-			return HQA_CMD_GET_FW_INFO;
-		case 0x1505:
-			return HQA_CMD_SET_TSSI;
-		case 0x1509:
-			return HQA_CMD_SET_RF_MODE;
-		case 0x1511:
-			return HQA_CMD_WRITE_BUFFER_DONE;
-		case 0x1514:
-			return HQA_CMD_GET_CHIP_ID;
-		case 0x151b:
-			return HQA_CMD_GET_SUB_CHIP_ID;
-		case 0x151c:
-			return HQA_CMD_GET_RX_INFO;
-		case 0x151e:
-			return HQA_CMD_GET_RF_CAP;
-		case 0x1522:
-			return HQA_CMD_CHECK_EFUSE_MODE_TYPE;
-		case 0x1523:
-			return HQA_CMD_CHECK_EFUSE_MODE_NATIVE;
-		case 0x152d:
-			return HQA_CMD_GET_BAND;
-		case 0x1594:
-			return HQA_CMD_SET_RU;
-		case 0x1502:
-		case 0x150b:
-			return HQA_CMD_LEGACY;
-		default:
-			break;
-		}
-	}
-
-	return HQA_CMD_ERR;
-}
-
-static inline enum atenl_ext_cmd atenl_get_ext_cmd(u16 ext_cmd_idx)
-{
-#define EXT_CMD_ID_GROUP	GENMASK(7, 4)
-	u8 ext_group = FIELD_GET(EXT_CMD_ID_GROUP, ext_cmd_idx);
-
-	if (ext_group == 0) {
-		switch (ext_cmd_idx) {
-		case 0x1:
-			return HQA_EXT_CMD_SET_CHANNEL;
-		case 0x2:
-			return HQA_EXT_CMD_SET_TX;
-		case 0x3:
-			return HQA_EXT_CMD_START_TX;
-		case 0x4:
-			return HQA_EXT_CMD_START_RX;
-		case 0x5:
-			return HQA_EXT_CMD_STOP_TX;
-		case 0x6:
-			return HQA_EXT_CMD_STOP_RX;
-		case 0x8:
-			return HQA_EXT_CMD_IBF_SET_VAL;
-		case 0x9:
-			return HQA_EXT_CMD_IBF_GET_STATUS;
-		case 0xc:
-			return HQA_EXT_CMD_IBF_PROF_UPDATE_ALL;
-		default:
-			break;
-		}
-	} else if (ext_group == 1) {
-	} else if (ext_group == 2) {
-		switch (ext_cmd_idx) {
-		case 0x26:
-			return HQA_EXT_CMD_SET_TX_TIME_OPT;
-		case 0x27:
-			return HQA_EXT_CMD_OFF_CH_SCAN;
-		default:
-			break;
-		}
-	}
-
-	return HQA_EXT_CMD_UNSPEC;
-}
-
-#define ATENL_GROUP(_cmd, _resp_len, _ops)	\
-	[HQA_CMD_##_cmd] = { .resp_len=_resp_len, .ops=_ops }
-static const struct atenl_cmd_ops atenl_ops[] = {
-	ATENL_GROUP(OPEN_ADAPTER, 2, atenl_hqa_adapter),
-	ATENL_GROUP(CLOSE_ADAPTER, 2, atenl_hqa_adapter),
-	ATENL_GROUP(SET_TX_PATH, 2, atenl_nl_process),
-	ATENL_GROUP(SET_RX_PATH, 2, atenl_nl_process),
-	ATENL_GROUP(SET_TX_POWER, 2, atenl_nl_process),
-	ATENL_GROUP(SET_TX_POWER_MANUAL, 2, atenl_hqa_skip),
-	ATENL_GROUP(SET_TX_BW, 2, atenl_hqa_skip),
-	ATENL_GROUP(SET_TX_PKT_BW, 2, atenl_hqa_skip),
-	ATENL_GROUP(SET_TX_PRI_BW, 2, atenl_hqa_skip),
-	ATENL_GROUP(SET_FREQ_OFFSET, 2, atenl_nl_process),
-	ATENL_GROUP(ANT_SWAP_CAP, 6, atenl_hqa_skip),
-	ATENL_GROUP(RESET_TX_RX_COUNTER, 2, atenl_hqa_reset_counter),
-	ATENL_GROUP(WRITE_MAC_BBP_REG, 2, atenl_hqa_mac_bbp_reg),
-	ATENL_GROUP(READ_MAC_BBP_REG, 0, atenl_hqa_mac_bbp_reg),
-	ATENL_GROUP(READ_EEPROM_BULK, 0, atenl_hqa_eeprom_bulk),
-	ATENL_GROUP(WRITE_EEPROM_BULK, 2, atenl_hqa_eeprom_bulk),
-	ATENL_GROUP(CHECK_EFUSE_MODE, 6, atenl_hqa_check_efuse_mode),
-	ATENL_GROUP(GET_EFUSE_FREE_BLOCK, 6, atenl_hqa_get_efuse_free_block),
-	ATENL_GROUP(GET_TX_POWER, 10, atenl_hqa_get_tx_power),
-	ATENL_GROUP(GET_FREQ_OFFSET, 6, atenl_hqa_get_freq_offset), /*TODO: MCU CMD, read eeprom?*/
-	ATENL_GROUP(CONTINUOUS_TX, 6, atenl_nl_process),
-	ATENL_GROUP(SET_RX_PKT_LEN, 2, atenl_hqa_skip),
-	ATENL_GROUP(GET_TX_INFO, 10, atenl_nl_process),
-	ATENL_GROUP(GET_CFG, 6, atenl_hqa_get_cfg), /*TODO*/
-	ATENL_GROUP(GET_TX_TONE_POWER, 6, atenl_hqa_skip),
-	ATENL_GROUP(SET_CFG, 2, atenl_nl_process),
-	ATENL_GROUP(READ_TEMPERATURE, 6, atenl_hqa_read_temperature),
-	ATENL_GROUP(GET_FW_INFO, 32, atenl_hqa_skip), /* TODO: check format */
-	ATENL_GROUP(SET_TSSI, 2, atenl_nl_process),
-	ATENL_GROUP(SET_RF_MODE, 2, atenl_hqa_set_rf_mode),
-	ATENL_GROUP(WRITE_BUFFER_DONE, 2, atenl_hqa_eeprom_bulk),
-	ATENL_GROUP(GET_CHIP_ID, 6, atenl_hqa_get_chip_id),
-	ATENL_GROUP(GET_SUB_CHIP_ID, 6, atenl_hqa_get_sub_chip_id),
-	ATENL_GROUP(GET_RX_INFO, 0, atenl_nl_process),
-	ATENL_GROUP(GET_RF_CAP, 10, atenl_hqa_get_rf_cap),
-	ATENL_GROUP(CHECK_EFUSE_MODE_TYPE, 6, atenl_hqa_check_efuse_mode),
-	ATENL_GROUP(CHECK_EFUSE_MODE_NATIVE, 6, atenl_hqa_check_efuse_mode),
-	ATENL_GROUP(GET_BAND, 6, atenl_hqa_get_band),
-	ATENL_GROUP(SET_RU, 2, atenl_nl_process_many),
-
-	ATENL_GROUP(LEGACY, 2, atenl_hqa_skip),
-	ATENL_GROUP(UNKNOWN, 1024, atenl_hqa_skip),
+/* should be placed in order for binary search */
+static const struct atenl_ops hqa_ops[] = {
+	{
+		.cmd = HQA_CMD_OPEN_ADAPTER,
+		.cmd_id = 0x1000,
+		.resp_len = 2,
+		.ops = atenl_hqa_adapter,
+	},
+	{
+		.cmd = HQA_CMD_CLOSE_ADAPTER,
+		.cmd_id = 0x1001,
+		.resp_len = 2,
+		.ops = atenl_hqa_adapter,
+	},
+	{
+		.cmd = HQA_CMD_SET_TX_PATH,
+		.cmd_id = 0x100b,
+		.resp_len = 2,
+		.ops = atenl_nl_process,
+	},
+	{
+		.cmd = HQA_CMD_SET_RX_PATH,
+		.cmd_id = 0x100c,
+		.resp_len = 2,
+		.ops = atenl_nl_process,
+	},
+	{
+		.cmd = HQA_CMD_LEGACY,
+		.cmd_id = 0x100d,
+		.resp_len = 2,
+		.flags = ATENL_OPS_FLAG_SKIP,
+	},
+	{
+		.cmd = HQA_CMD_SET_TX_POWER,
+		.cmd_id = 0x1011,
+		.resp_len = 2,
+		.ops = atenl_nl_process,
+	},
+	{
+		.cmd = HQA_CMD_SET_TX_POWER_MANUAL,
+		.cmd_id = 0x1018,
+		.resp_len = 2,
+		.flags = ATENL_OPS_FLAG_SKIP,
+	},
+	{
+		.cmd = HQA_CMD_LEGACY,
+		.cmd_id = 0x1101,
+		.resp_len = 2,
+		.flags = ATENL_OPS_FLAG_SKIP,
+	},
+	{
+		.cmd = HQA_CMD_LEGACY,
+		.cmd_id = 0x1102,
+		.resp_len = 2,
+		.flags = ATENL_OPS_FLAG_SKIP,
+	},
+	{
+		.cmd = HQA_CMD_SET_TX_BW,
+		.cmd_id = 0x1104,
+		.resp_len = 2,
+		.flags = ATENL_OPS_FLAG_SKIP,
+	},
+	{
+		.cmd = HQA_CMD_SET_TX_PKT_BW,
+		.cmd_id = 0x1105,
+		.resp_len = 2,
+		.flags = ATENL_OPS_FLAG_SKIP,
+	},
+	{
+		.cmd = HQA_CMD_SET_TX_PRI_BW,
+		.cmd_id = 0x1106,
+		.resp_len = 2,
+		.flags = ATENL_OPS_FLAG_SKIP,
+	},
+	{
+		.cmd = HQA_CMD_SET_FREQ_OFFSET,
+		.cmd_id = 0x1107,
+		.resp_len = 2,
+		.ops = atenl_nl_process,
+	},
+	{
+		.cmd = HQA_CMD_SET_TSSI,
+		.cmd_id = 0x1109,
+		.resp_len = 2,
+		.ops = atenl_nl_process,
+	},
+	{
+		.cmd = HQA_CMD_SET_EEPROM_TO_FW,
+		.cmd_id = 0x110c,
+		.resp_len = 2,
+		.flags = ATENL_OPS_FLAG_SKIP,
+	},
+	{
+		.cmd = HQA_CMD_ANT_SWAP_CAP,
+		.cmd_id = 0x110d,
+		.resp_len = 6,
+		.flags = ATENL_OPS_FLAG_SKIP,
+	},
+	{
+		.cmd = HQA_CMD_RESET_TX_RX_COUNTER,
+		.cmd_id = 0x1200,
+		.resp_len = 2,
+		.ops = atenl_hqa_reset_counter,
+	},
+	{
+		.cmd = HQA_CMD_READ_MAC_BBP_REG_QA,
+		.cmd_id = 0x1300,
+		.resp_len = 6,
+		.ops = atenl_hqa_mac_bbp_reg,
+	},
+	{
+		.cmd = HQA_CMD_WRITE_MAC_BBP_REG,
+		.cmd_id = 0x1301,
+		.resp_len = 2,
+		.ops = atenl_hqa_mac_bbp_reg,
+	},
+	{
+		.cmd = HQA_CMD_READ_MAC_BBP_REG,
+		.cmd_id = 0x1302,
+		.ops = atenl_hqa_mac_bbp_reg,
+	},
+	{
+		.cmd = HQA_CMD_READ_RF_REG,
+		.cmd_id = 0x1303,
+		.ops = atenl_hqa_rf_reg,
+	},
+	{
+		.cmd = HQA_CMD_WRITE_RF_REG,
+		.cmd_id = 0x1304,
+		.resp_len = 2,
+		.ops = atenl_hqa_rf_reg,
+	},
+	{
+		.cmd = HQA_CMD_WRITE_EEPROM_BULK,
+		.cmd_id = 0x1306,
+		.resp_len = 2,
+		.ops = atenl_hqa_eeprom_bulk,
+	},
+	{
+		.cmd = HQA_CMD_READ_EEPROM_BULK,
+		.cmd_id = 0x1307,
+		.ops = atenl_hqa_eeprom_bulk,
+	},
+	{
+		.cmd = HQA_CMD_WRITE_EEPROM_BULK,
+		.cmd_id = 0x1308,
+		.resp_len = 2,
+		.ops = atenl_hqa_eeprom_bulk,
+	},
+	{
+		.cmd = HQA_CMD_CHECK_EFUSE_MODE,
+		.cmd_id = 0x1309,
+		.resp_len = 6,
+		.ops = atenl_hqa_check_efuse_mode,
+	},
+	{
+		.cmd = HQA_CMD_GET_EFUSE_FREE_BLOCK,
+		.cmd_id = 0x130a,
+		.resp_len = 6,
+		.ops = atenl_hqa_get_efuse_free_block,
+	},
+	{
+		.cmd = HQA_CMD_GET_TX_POWER,
+		.cmd_id = 0x130d,
+		.resp_len = 10,
+		.ops = atenl_hqa_get_tx_power,
+	},
+	{
+		.cmd = HQA_CMD_SET_CFG,
+		.cmd_id = 0x130e,
+		.resp_len = 2,
+		.ops = atenl_nl_process,
+	},
+	{
+		.cmd = HQA_CMD_GET_FREQ_OFFSET,
+		.cmd_id = 0x130f,
+		.resp_len = 6,
+		.ops = atenl_hqa_get_freq_offset,
+	},
+	{
+		.cmd = HQA_CMD_CONTINUOUS_TX,
+		.cmd_id = 0x1311,
+		.resp_len = 6,
+		.ops = atenl_nl_process,
+	},
+	{
+		.cmd = HQA_CMD_SET_RX_PKT_LEN,
+		.cmd_id = 0x1312,
+		.resp_len = 2,
+		.flags = ATENL_OPS_FLAG_SKIP,
+	},
+	{
+		.cmd = HQA_CMD_GET_TX_INFO,
+		.cmd_id = 0x1313,
+		.resp_len = 10,
+		.ops = atenl_nl_process,
+	},
+	{
+		.cmd = HQA_CMD_GET_CFG,
+		.cmd_id = 0x1314,
+		.resp_len = 6,
+		.ops = atenl_hqa_get_cfg,
+	},
+	{
+		.cmd = HQA_CMD_GET_TX_TONE_POWER,
+		.cmd_id = 0x131a,
+		.resp_len = 6,
+		.flags = ATENL_OPS_FLAG_SKIP,
+	},
+	{
+		.cmd = HQA_CMD_UNKNOWN,
+		.cmd_id = 0x131f,
+		.resp_len = 1024,
+		.flags = ATENL_OPS_FLAG_SKIP,
+	},
+	{
+		.cmd = HQA_CMD_READ_TEMPERATURE,
+		.cmd_id = 0x1401,
+		.resp_len = 6,
+		.ops = atenl_hqa_read_temperature,
+	},
+	{
+		.cmd = HQA_CMD_GET_FW_INFO,
+		.cmd_id = 0x1500,
+		.resp_len = 32,
+		.flags = ATENL_OPS_FLAG_SKIP,
+	},
+	{
+		.cmd_id = 0x1502,
+		.flags = ATENL_OPS_FLAG_LEGACY,
+	},
+	{
+		.cmd = HQA_CMD_SET_TSSI,
+		.cmd_id = 0x1505,
+		.resp_len = 2,
+		.ops = atenl_nl_process,
+	},
+	{
+		.cmd = HQA_CMD_SET_RF_MODE,
+		.cmd_id = 0x1509,
+		.resp_len = 2,
+		.ops = atenl_hqa_set_rf_mode,
+	},
+	{
+		.cmd_id = 0x150b,
+		.flags = ATENL_OPS_FLAG_LEGACY,
+	},
+	{
+		.cmd = HQA_CMD_WRITE_BUFFER_DONE,
+		.cmd_id = 0x1511,
+		.resp_len = 2,
+		.ops = atenl_hqa_eeprom_bulk,
+	},
+	{
+		.cmd = HQA_CMD_GET_CHIP_ID,
+		.cmd_id = 0x1514,
+		.resp_len = 6,
+		.ops = atenl_hqa_get_chip_id,
+	},
+	{
+		.cmd = HQA_CMD_GET_SUB_CHIP_ID,
+		.cmd_id = 0x151b,
+		.resp_len = 6,
+		.ops = atenl_hqa_get_sub_chip_id,
+	},
+	{
+		.cmd = HQA_CMD_GET_RX_INFO,
+		.cmd_id = 0x151c,
+		.ops = atenl_nl_process,
+	},
+	{
+		.cmd = HQA_CMD_GET_RF_CAP,
+		.cmd_id = 0x151e,
+		.resp_len = 10,
+		.ops = atenl_hqa_get_rf_cap,
+	},
+	{
+		.cmd = HQA_CMD_CHECK_EFUSE_MODE_TYPE,
+		.cmd_id = 0x1522,
+		.resp_len = 6,
+		.ops = atenl_hqa_check_efuse_mode,
+	},
+	{
+		.cmd = HQA_CMD_CHECK_EFUSE_MODE_NATIVE,
+		.cmd_id = 0x1523,
+		.resp_len = 6,
+		.ops = atenl_hqa_check_efuse_mode,
+	},
+	{
+		.cmd = HQA_CMD_GET_BAND,
+		.cmd_id = 0x152d,
+		.resp_len = 6,
+		.ops = atenl_hqa_get_band,
+	},
+	{
+		.cmd = HQA_CMD_SET_RU,
+		.cmd_id = 0x1594,
+		.resp_len = 2,
+		.ops = atenl_nl_process_many,
+	},
 };
-#undef ATENL_GROUP
 
-#define ATENL_EXT(_cmd, _resp_len, _ops)	\
-	[HQA_EXT_CMD_##_cmd] = { .resp_len=_resp_len, .ops=_ops }
-static const struct atenl_cmd_ops atenl_ext_ops[] = {
-	ATENL_EXT(SET_CHANNEL, 6, atenl_hqa_set_channel),
-	ATENL_EXT(SET_TX, 6, atenl_nl_process),
-	ATENL_EXT(START_TX, 6, atenl_nl_process),
-	ATENL_EXT(STOP_TX, 6, atenl_nl_process),
-	ATENL_EXT(START_RX, 6, atenl_nl_process),
-	ATENL_EXT(STOP_RX, 6, atenl_nl_process),
-	ATENL_EXT(SET_TX_TIME_OPT, 6, atenl_hqa_tx_time_option),
-	ATENL_EXT(OFF_CH_SCAN, 6, atenl_nl_process),
-	ATENL_EXT(IBF_SET_VAL, 6, atenl_nl_process),
-	ATENL_EXT(IBF_GET_STATUS, 10, atenl_nl_process),
-	ATENL_EXT(IBF_PROF_UPDATE_ALL, 6, atenl_nl_process_many),
+static const struct atenl_ops hqa_ops_ext[] = {
+	{
+		.cmd = HQA_EXT_CMD_SET_CHANNEL,
+		.cmd_id = 0x01,
+		.resp_len = 6,
+		.ops = atenl_hqa_set_channel,
+		.flags = ATENL_OPS_FLAG_EXT_CMD,
+	},
+	{
+		.cmd = HQA_EXT_CMD_SET_TX,
+		.cmd_id = 0x02,
+		.resp_len = 6,
+		.ops = atenl_nl_process,
+		.flags = ATENL_OPS_FLAG_EXT_CMD,
+	},
+	{
+		.cmd = HQA_EXT_CMD_START_TX,
+		.cmd_id = 0x03,
+		.resp_len = 6,
+		.ops = atenl_nl_process,
+		.flags = ATENL_OPS_FLAG_EXT_CMD,
+	},
+	{
+		.cmd = HQA_EXT_CMD_START_RX,
+		.cmd_id = 0x04,
+		.resp_len = 6,
+		.ops = atenl_nl_process,
+		.flags = ATENL_OPS_FLAG_EXT_CMD,
+	},
+	{
+		.cmd = HQA_EXT_CMD_STOP_TX,
+		.cmd_id = 0x05,
+		.resp_len = 6,
+		.ops = atenl_nl_process,
+		.flags = ATENL_OPS_FLAG_EXT_CMD,
+	},
+	{
+		.cmd = HQA_EXT_CMD_STOP_RX,
+		.cmd_id = 0x06,
+		.resp_len = 6,
+		.ops = atenl_nl_process,
+		.flags = ATENL_OPS_FLAG_EXT_CMD,
+	},
+	{
+		.cmd = HQA_EXT_CMD_IBF_SET_VAL,
+		.cmd_id = 0x08,
+		.resp_len = 6,
+		.ops = atenl_nl_process,
+		.flags = ATENL_OPS_FLAG_EXT_CMD,
+	},
+	{
+		.cmd = HQA_EXT_CMD_IBF_GET_STATUS,
+		.cmd_id = 0x09,
+		.resp_len = 10,
+		.ops = atenl_nl_process,
+		.flags = ATENL_OPS_FLAG_EXT_CMD,
+	},
+	{
+		.cmd = HQA_EXT_CMD_IBF_PROF_UPDATE_ALL,
+		.cmd_id = 0x0c,
+		.resp_len = 6,
+		.ops = atenl_nl_process,
+		.flags = ATENL_OPS_FLAG_EXT_CMD,
+	},
+	{
+		.cmd = HQA_EXT_CMD_SET_TX_TIME_OPT,
+		.cmd_id = 0x26,
+		.resp_len = 6,
+		.ops = atenl_hqa_tx_time_option,
+		.flags = ATENL_OPS_FLAG_EXT_CMD,
+	},
+	{
+		.cmd = HQA_EXT_CMD_OFF_CH_SCAN,
+		.cmd_id = 0x27,
+		.resp_len = 6,
+		.ops = atenl_nl_process,
+		.flags = ATENL_OPS_FLAG_EXT_CMD,
+	},
 };
-#undef ATENL_EXT
 
-int atenl_hqa_recv(struct atenl *an, struct atenl_data *data)
+static const struct atenl_ops *
+atenl_get_ops(struct atenl_data *data)
 {
+	const struct atenl_ops *group;
 	struct atenl_cmd_hdr *hdr = atenl_hdr(data);
-	u16 cmd_type = ntohs(hdr->cmd_type);
-	int fd = an->pipefd[PIPE_WRITE];
-	int ret;
+	u16 cmd_id = ntohs(hdr->cmd_id), id = cmd_id;
+	int size, low = 0, high;
 
-	if (ntohl(hdr->magic_no) != RACFG_MAGIC_NO)
-		return -EINVAL;
-
-	if (FIELD_GET(RACFG_CMD_TYPE_MASK, cmd_type) != RACFG_CMD_TYPE_ETHREQ &&
-	    FIELD_GET(RACFG_CMD_TYPE_MASK, cmd_type) != RACFG_CMD_TYPE_PLATFORM_MODULE) {
-		atenl_err("[%d]%s: cmd type error = 0x%x\n", getpid(), __func__, cmd_type);
-		return -EINVAL;
+	switch (cmd_id) {
+	case 0x1600:
+		group = hqa_ops_ext;
+		size = ARRAY_SIZE(hqa_ops_ext);
+		break;
+	default:
+		group = hqa_ops;
+		size = ARRAY_SIZE(hqa_ops);
+		break;
 	}
 
+	if (group[0].flags & ATENL_OPS_FLAG_EXT_CMD)
+		id = ntohl(*(u32 *)hdr->data);
+
-	atenl_dbg("[%d]%s: recv cmd type = 0x%x, id = 0x%x\n",
-		  getpid(), __func__, cmd_type, ntohs(hdr->cmd_id));
+	/* binary search */
+	high = size - 1;
+	while (low <= high) {
+		int mid = low + (high - low) / 2;
 
-	ret = write(fd, data, data->len);
-	if (ret < 0) {
-		perror("pipe write");
-		return ret;
+		if (group[mid].cmd_id == id)
+			return &group[mid];
+		else if (group[mid].cmd_id > id)
+			high = mid - 1;
+		else
+			low = mid + 1;
 	}
 
-	return 0;
+	return NULL;
 }
 
-int atenl_hqa_proc_cmd(struct atenl *an, struct atenl_data *data)
+static int
+atenl_hqa_handler(struct atenl *an, struct atenl_data *data)
 {
 	struct atenl_cmd_hdr *hdr = atenl_hdr(data);
-	const struct atenl_cmd_ops *ops;
+	const struct atenl_ops *ops = NULL;
 	u16 cmd_id = ntohs(hdr->cmd_id);
 	u16 status = 0;
 
-	data->cmd = atenl_get_cmd_by_id(cmd_id);
-	if (data->cmd == HQA_CMD_ERR) {
-		atenl_err("Unknown command id: 0x%04x\n", cmd_id);
+	atenl_dbg("handle command: 0x%x\n", cmd_id);
+
+	ops = atenl_get_ops(data);
+	if (!ops || (!ops->ops && !ops->flags)) {
+		atenl_err("Unknown command id: 0x%x\n", cmd_id);
 		goto done;
 	}
 
-	if (data->cmd == HQA_CMD_EXT) {
-		data->ext_id = ntohl(*(u32 *)hdr->data);
-		data->ext_cmd = atenl_get_ext_cmd(data->ext_id);
-		if (data->ext_cmd == HQA_EXT_CMD_UNSPEC) {
-			atenl_err("Unknown ext command id: 0x%04x\n", data->ext_id);
-			goto done;
-		}
-
-		ops = &atenl_ext_ops[data->ext_cmd];
-	} else {
-		ops = &atenl_ops[data->cmd];
+	data->cmd = ops->cmd;
+	data->cmd_id = ops->cmd_id;
+	if (ops->flags & ATENL_OPS_FLAG_EXT_CMD) {
+		data->ext_cmd = ops->cmd;
+		data->ext_id = ops->cmd_id;
 	}
 
+	if (ops->flags & ATENL_OPS_FLAG_SKIP)
+		goto done;
+
-	atenl_dbg_print_data(data, __func__,
+	atenl_dbg_print_data(data->buf, __func__,
 			     ntohs(hdr->len) + ETH_HLEN + RACFG_HLEN);
 	if (ops->ops)
 		status = htons(ops->ops(an, data));
 	if (ops->resp_len)
 		hdr->len = htons(ops->resp_len);
 
-	*(u16 *)hdr->data = status;
-
 done:
+	*(u16 *)hdr->data = status;
 	data->len = ntohs(hdr->len) + ETH_HLEN + RACFG_HLEN;
 	hdr->cmd_type |= ~htons(RACFG_CMD_TYPE_MASK);
 
 	return 0;
 }
+
+int atenl_hqa_proc_cmd(struct atenl *an)
+{
+	struct atenl_data *data;
+	struct atenl_cmd_hdr *hdr;
+	u16 cmd_type;
+	int ret = -EINVAL;
+
+	data = calloc(1, sizeof(struct atenl_data));
+	if (!data)
+		return -ENOMEM;
+
+	ret = atenl_eth_recv(an, data);
+	if (ret)
+		goto out;
+
+	hdr = atenl_hdr(data);
+	if (ntohl(hdr->magic_no) != RACFG_MAGIC_NO)
+		goto out;
+
+	cmd_type = ntohs(hdr->cmd_type);
+	if (FIELD_GET(RACFG_CMD_TYPE_MASK, cmd_type) != RACFG_CMD_TYPE_ETHREQ &&
+	    FIELD_GET(RACFG_CMD_TYPE_MASK, cmd_type) != RACFG_CMD_TYPE_PLATFORM_MODULE) {
+		atenl_err("cmd type error = 0x%x\n", cmd_type);
+		goto out;
+	}
+
+	ret = atenl_hqa_handler(an, data);
+	if (ret)
+		goto out;
+
+	ret = atenl_eth_send(an, data);
+	if (ret)
+		goto out;
+
+	ret = 0;
+out:
+	free(data);
+
+	return ret;
+}