xref: /openwifi/driver/sdrctl_intf.c (revision db8c69b6aa4437ad8f8929a3c5137b8df20faeea)
17d0af6dfSXianjun Jiao // Author: Xianjun Jiao, Michael Mehari, Wei Liu
27d0af6dfSXianjun Jiao // SPDX-FileCopyrightText: 2019 UGent
37d0af6dfSXianjun Jiao // SPDX-License-Identifier: AGPL-3.0-or-later
47d0af6dfSXianjun Jiao 
openwifi_testmode_cmd(struct ieee80211_hw * hw,struct ieee80211_vif * vif,void * data,int len)57d0af6dfSXianjun Jiao static int openwifi_testmode_cmd(struct ieee80211_hw *hw, struct ieee80211_vif *vif, void *data, int len)
67d0af6dfSXianjun Jiao {
77d0af6dfSXianjun Jiao 	struct openwifi_priv *priv = hw->priv;
87d0af6dfSXianjun Jiao 	struct nlattr *tb[OPENWIFI_ATTR_MAX + 1];
97d0af6dfSXianjun Jiao 	struct sk_buff *skb;
107d0af6dfSXianjun Jiao 	int err;
117d0af6dfSXianjun Jiao 	u32 tmp=-1, reg_cat, reg_addr, reg_val, reg_addr_idx, tsft_high, tsft_low;
127d0af6dfSXianjun Jiao 	int tmp_int;
137d0af6dfSXianjun Jiao 
147d0af6dfSXianjun Jiao 	err = nla_parse(tb, OPENWIFI_ATTR_MAX, data, len, openwifi_testmode_policy, NULL);
157d0af6dfSXianjun Jiao 	if (err)
167d0af6dfSXianjun Jiao 		return err;
177d0af6dfSXianjun Jiao 
187d0af6dfSXianjun Jiao 	if (!tb[OPENWIFI_ATTR_CMD])
197d0af6dfSXianjun Jiao 		return -EINVAL;
207d0af6dfSXianjun Jiao 
217d0af6dfSXianjun Jiao 	switch (nla_get_u32(tb[OPENWIFI_ATTR_CMD])) {
227d0af6dfSXianjun Jiao 	case OPENWIFI_CMD_SET_GAP:
237d0af6dfSXianjun Jiao 		if (!tb[OPENWIFI_ATTR_GAP])
247d0af6dfSXianjun Jiao 			return -EINVAL;
257d0af6dfSXianjun Jiao 		tmp = nla_get_u32(tb[OPENWIFI_ATTR_GAP]);
267d0af6dfSXianjun Jiao 		printk("%s XPU_REG_CSMA_CFG_write %08x (Check openwifi_conf_tx() in sdr.c to understand)\n", sdr_compatible_str, tmp);
277d0af6dfSXianjun Jiao 		xpu_api->XPU_REG_CSMA_CFG_write(tmp); // unit us
287d0af6dfSXianjun Jiao 		return 0;
297d0af6dfSXianjun Jiao 	case OPENWIFI_CMD_GET_GAP:
30*db8c69b6Srobgar2001 		skb = (struct sk_buff *)cfg80211_testmode_alloc_reply_skb(hw->wiphy, nla_total_size(sizeof(u32)));
317d0af6dfSXianjun Jiao 		if (!skb)
327d0af6dfSXianjun Jiao 			return -ENOMEM;
337d0af6dfSXianjun Jiao 		tmp = xpu_api->XPU_REG_CSMA_CFG_read();
347d0af6dfSXianjun Jiao 		if (nla_put_u32(skb, OPENWIFI_ATTR_GAP, tmp))
357d0af6dfSXianjun Jiao 			goto nla_put_failure;
367d0af6dfSXianjun Jiao 		return cfg80211_testmode_reply(skb);
377d0af6dfSXianjun Jiao 	case OPENWIFI_CMD_SET_SLICE_IDX:
387d0af6dfSXianjun Jiao 		if (!tb[OPENWIFI_ATTR_SLICE_IDX])
397d0af6dfSXianjun Jiao 			return -EINVAL;
407d0af6dfSXianjun Jiao 		tmp = nla_get_u32(tb[OPENWIFI_ATTR_SLICE_IDX]);
417d0af6dfSXianjun Jiao 		printk("%s set openwifi slice_idx in hex: %08x\n", sdr_compatible_str, tmp);
427d0af6dfSXianjun Jiao 		if (tmp == MAX_NUM_HW_QUEUE) {
437d0af6dfSXianjun Jiao 			printk("%s set openwifi slice_idx reset all queue counter.\n", sdr_compatible_str);
447d0af6dfSXianjun Jiao 			xpu_api->XPU_REG_MULTI_RST_write(1<<7); //bit7 reset the counter for all queues at the same time
457d0af6dfSXianjun Jiao 			xpu_api->XPU_REG_MULTI_RST_write(0<<7);
467d0af6dfSXianjun Jiao 		} else {
477d0af6dfSXianjun Jiao 			priv->slice_idx = tmp;
487d0af6dfSXianjun Jiao 		}
497d0af6dfSXianjun Jiao 		return 0;
507d0af6dfSXianjun Jiao 	case OPENWIFI_CMD_GET_SLICE_IDX:
51*db8c69b6Srobgar2001 		skb = (struct sk_buff *)cfg80211_testmode_alloc_reply_skb(hw->wiphy, nla_total_size(sizeof(u32)));
527d0af6dfSXianjun Jiao 		if (!skb)
537d0af6dfSXianjun Jiao 			return -ENOMEM;
547d0af6dfSXianjun Jiao 		tmp = priv->slice_idx;
557d0af6dfSXianjun Jiao 		if (nla_put_u32(skb, OPENWIFI_ATTR_SLICE_IDX, tmp))
567d0af6dfSXianjun Jiao 			goto nla_put_failure;
577d0af6dfSXianjun Jiao 		printk("%s get openwifi slice_idx in hex: %08x\n", sdr_compatible_str, tmp);
587d0af6dfSXianjun Jiao 		return cfg80211_testmode_reply(skb);
597d0af6dfSXianjun Jiao 	case OPENWIFI_CMD_SET_ADDR:
607d0af6dfSXianjun Jiao 		if (!tb[OPENWIFI_ATTR_ADDR])
617d0af6dfSXianjun Jiao 			return -EINVAL;
627d0af6dfSXianjun Jiao 		tmp = nla_get_u32(tb[OPENWIFI_ATTR_ADDR]);
637d0af6dfSXianjun Jiao 		if (priv->slice_idx>=MAX_NUM_HW_QUEUE) {
647d0af6dfSXianjun Jiao 			printk("%s set openwifi slice_target_mac_addr(low32) WARNING: current slice idx %d is invalid!\n", sdr_compatible_str, priv->slice_idx);
657d0af6dfSXianjun Jiao 			return -EOPNOTSUPP;
667d0af6dfSXianjun Jiao 		} else {
677d0af6dfSXianjun Jiao 			printk("%s set openwifi slice_target_mac_addr(low32) in hex: %08x to slice %d\n", sdr_compatible_str, tmp, priv->slice_idx);
687d0af6dfSXianjun Jiao 			priv->dest_mac_addr_queue_map[priv->slice_idx] = reverse32(tmp);
697d0af6dfSXianjun Jiao 		}
707d0af6dfSXianjun Jiao 		return 0;
717d0af6dfSXianjun Jiao 	case OPENWIFI_CMD_GET_ADDR:
72*db8c69b6Srobgar2001 		skb = (struct sk_buff *)cfg80211_testmode_alloc_reply_skb(hw->wiphy, nla_total_size(sizeof(u32)));
737d0af6dfSXianjun Jiao 		if (!skb)
747d0af6dfSXianjun Jiao 			return -ENOMEM;
757d0af6dfSXianjun Jiao 		if (priv->slice_idx>=MAX_NUM_HW_QUEUE) {
767d0af6dfSXianjun Jiao 			tmp = -1;
777d0af6dfSXianjun Jiao 		} else {
787d0af6dfSXianjun Jiao 			tmp = reverse32(priv->dest_mac_addr_queue_map[priv->slice_idx]);
797d0af6dfSXianjun Jiao 		}
807d0af6dfSXianjun Jiao 		if (nla_put_u32(skb, OPENWIFI_ATTR_ADDR, tmp))
817d0af6dfSXianjun Jiao 			goto nla_put_failure;
827d0af6dfSXianjun Jiao 		printk("%s get openwifi slice_target_mac_addr(low32) in hex: %08x of slice %d\n", sdr_compatible_str, tmp, priv->slice_idx);
837d0af6dfSXianjun Jiao 		return cfg80211_testmode_reply(skb);
847d0af6dfSXianjun Jiao 
857d0af6dfSXianjun Jiao 	case OPENWIFI_CMD_SET_SLICE_TOTAL:
867d0af6dfSXianjun Jiao 		if (!tb[OPENWIFI_ATTR_SLICE_TOTAL])
877d0af6dfSXianjun Jiao 			return -EINVAL;
887d0af6dfSXianjun Jiao 		tmp = nla_get_u32(tb[OPENWIFI_ATTR_SLICE_TOTAL]);
897d0af6dfSXianjun Jiao 		if (priv->slice_idx>=MAX_NUM_HW_QUEUE) {
907d0af6dfSXianjun Jiao 			printk("%s set SLICE_TOTAL(duration) WARNING: current slice idx %d is invalid!\n", sdr_compatible_str, priv->slice_idx);
917d0af6dfSXianjun Jiao 			return -EOPNOTSUPP;
927d0af6dfSXianjun Jiao 		} else {
937d0af6dfSXianjun Jiao 			printk("%s set SLICE_TOTAL(duration) %d usec to slice %d\n", sdr_compatible_str, tmp, priv->slice_idx);
947d0af6dfSXianjun Jiao 			xpu_api->XPU_REG_SLICE_COUNT_TOTAL_write((priv->slice_idx<<20)|tmp);
957d0af6dfSXianjun Jiao 		}
967d0af6dfSXianjun Jiao 		return 0;
977d0af6dfSXianjun Jiao 	case OPENWIFI_CMD_GET_SLICE_TOTAL:
98*db8c69b6Srobgar2001 		skb = (struct sk_buff *)cfg80211_testmode_alloc_reply_skb(hw->wiphy, nla_total_size(sizeof(u32)));
997d0af6dfSXianjun Jiao 		if (!skb)
1007d0af6dfSXianjun Jiao 			return -ENOMEM;
1017d0af6dfSXianjun Jiao 		tmp = (xpu_api->XPU_REG_SLICE_COUNT_TOTAL_read());
1027d0af6dfSXianjun Jiao 		printk("%s get SLICE_TOTAL(duration) %d usec of slice %d\n", sdr_compatible_str, tmp&0xFFFFF, tmp>>20);
1037d0af6dfSXianjun Jiao 		if (nla_put_u32(skb, OPENWIFI_ATTR_SLICE_TOTAL, tmp))
1047d0af6dfSXianjun Jiao 			goto nla_put_failure;
1057d0af6dfSXianjun Jiao 		return cfg80211_testmode_reply(skb);
1067d0af6dfSXianjun Jiao 
1077d0af6dfSXianjun Jiao 	case OPENWIFI_CMD_SET_SLICE_START:
1087d0af6dfSXianjun Jiao 		if (!tb[OPENWIFI_ATTR_SLICE_START])
1097d0af6dfSXianjun Jiao 			return -EINVAL;
1107d0af6dfSXianjun Jiao 		tmp = nla_get_u32(tb[OPENWIFI_ATTR_SLICE_START]);
1117d0af6dfSXianjun Jiao 		if (priv->slice_idx>=MAX_NUM_HW_QUEUE) {
1127d0af6dfSXianjun Jiao 			printk("%s set SLICE_START(duration) WARNING: current slice idx %d is invalid!\n", sdr_compatible_str, priv->slice_idx);
1137d0af6dfSXianjun Jiao 			return -EOPNOTSUPP;
1147d0af6dfSXianjun Jiao 		} else {
1157d0af6dfSXianjun Jiao 			printk("%s set SLICE_START(duration) %d usec to slice %d\n", sdr_compatible_str, tmp, priv->slice_idx);
1167d0af6dfSXianjun Jiao 			xpu_api->XPU_REG_SLICE_COUNT_START_write((priv->slice_idx<<20)|tmp);
1177d0af6dfSXianjun Jiao 		}
1187d0af6dfSXianjun Jiao 		return 0;
1197d0af6dfSXianjun Jiao 	case OPENWIFI_CMD_GET_SLICE_START:
120*db8c69b6Srobgar2001 		skb = (struct sk_buff *)cfg80211_testmode_alloc_reply_skb(hw->wiphy, nla_total_size(sizeof(u32)));
1217d0af6dfSXianjun Jiao 		if (!skb)
1227d0af6dfSXianjun Jiao 			return -ENOMEM;
1237d0af6dfSXianjun Jiao 		tmp = (xpu_api->XPU_REG_SLICE_COUNT_START_read());
1247d0af6dfSXianjun Jiao 		printk("%s get SLICE_START(duration) %d usec of slice %d\n", sdr_compatible_str, tmp&0xFFFFF, tmp>>20);
1257d0af6dfSXianjun Jiao 		if (nla_put_u32(skb, OPENWIFI_ATTR_SLICE_START, tmp))
1267d0af6dfSXianjun Jiao 			goto nla_put_failure;
1277d0af6dfSXianjun Jiao 		return cfg80211_testmode_reply(skb);
1287d0af6dfSXianjun Jiao 
1297d0af6dfSXianjun Jiao 	case OPENWIFI_CMD_SET_SLICE_END:
1307d0af6dfSXianjun Jiao 		if (!tb[OPENWIFI_ATTR_SLICE_END])
1317d0af6dfSXianjun Jiao 			return -EINVAL;
1327d0af6dfSXianjun Jiao 		tmp = nla_get_u32(tb[OPENWIFI_ATTR_SLICE_END]);
1337d0af6dfSXianjun Jiao 		if (priv->slice_idx>=MAX_NUM_HW_QUEUE) {
1347d0af6dfSXianjun Jiao 			printk("%s set SLICE_END(duration) WARNING: current slice idx %d is invalid!\n", sdr_compatible_str, priv->slice_idx);
1357d0af6dfSXianjun Jiao 			return -EOPNOTSUPP;
1367d0af6dfSXianjun Jiao 		} else {
1377d0af6dfSXianjun Jiao 			printk("%s set SLICE_END(duration) %d usec to slice %d\n", sdr_compatible_str, tmp, priv->slice_idx);
1387d0af6dfSXianjun Jiao 			xpu_api->XPU_REG_SLICE_COUNT_END_write((priv->slice_idx<<20)|tmp);
1397d0af6dfSXianjun Jiao 		}
1407d0af6dfSXianjun Jiao 		return 0;
1417d0af6dfSXianjun Jiao 	case OPENWIFI_CMD_GET_SLICE_END:
142*db8c69b6Srobgar2001 		skb = (struct sk_buff *)cfg80211_testmode_alloc_reply_skb(hw->wiphy, nla_total_size(sizeof(u32)));
1437d0af6dfSXianjun Jiao 		if (!skb)
1447d0af6dfSXianjun Jiao 			return -ENOMEM;
1457d0af6dfSXianjun Jiao 		tmp = (xpu_api->XPU_REG_SLICE_COUNT_END_read());
1467d0af6dfSXianjun Jiao 		printk("%s get SLICE_END(duration) %d usec of slice %d\n", sdr_compatible_str, tmp&0xFFFFF, tmp>>20);
1477d0af6dfSXianjun Jiao 		if (nla_put_u32(skb, OPENWIFI_ATTR_SLICE_END, tmp))
1487d0af6dfSXianjun Jiao 			goto nla_put_failure;
1497d0af6dfSXianjun Jiao 		return cfg80211_testmode_reply(skb);
1507d0af6dfSXianjun Jiao 
1517d0af6dfSXianjun Jiao 	// case OPENWIFI_CMD_SET_SLICE_TOTAL1:
1527d0af6dfSXianjun Jiao 	// 	if (!tb[OPENWIFI_ATTR_SLICE_TOTAL1])
1537d0af6dfSXianjun Jiao 	// 		return -EINVAL;
1547d0af6dfSXianjun Jiao 	// 	tmp = nla_get_u32(tb[OPENWIFI_ATTR_SLICE_TOTAL1]);
1557d0af6dfSXianjun Jiao 	// 	printk("%s set SLICE_TOTAL1(duration) to %d usec\n", sdr_compatible_str, tmp);
1567d0af6dfSXianjun Jiao 	// 	// xpu_api->XPU_REG_SLICE_COUNT_TOTAL1_write(tmp);
1577d0af6dfSXianjun Jiao 	// 	return 0;
1587d0af6dfSXianjun Jiao 	// case OPENWIFI_CMD_GET_SLICE_TOTAL1:
1597d0af6dfSXianjun Jiao 	// 	skb = cfg80211_testmode_alloc_reply_skb(hw->wiphy, nla_total_size(sizeof(u32)));
1607d0af6dfSXianjun Jiao 	// 	if (!skb)
1617d0af6dfSXianjun Jiao 	// 		return -ENOMEM;
1627d0af6dfSXianjun Jiao 	// 	// tmp = (xpu_api->XPU_REG_SLICE_COUNT_TOTAL1_read());
1637d0af6dfSXianjun Jiao 	// 	if (nla_put_u32(skb, OPENWIFI_ATTR_SLICE_TOTAL1, tmp))
1647d0af6dfSXianjun Jiao 	// 		goto nla_put_failure;
1657d0af6dfSXianjun Jiao 	// 	return cfg80211_testmode_reply(skb);
1667d0af6dfSXianjun Jiao 
1677d0af6dfSXianjun Jiao 	// case OPENWIFI_CMD_SET_SLICE_START1:
1687d0af6dfSXianjun Jiao 	// 	if (!tb[OPENWIFI_ATTR_SLICE_START1])
1697d0af6dfSXianjun Jiao 	// 		return -EINVAL;
1707d0af6dfSXianjun Jiao 	// 	tmp = nla_get_u32(tb[OPENWIFI_ATTR_SLICE_START1]);
1717d0af6dfSXianjun Jiao 	// 	printk("%s set SLICE_START1(duration) to %d usec\n", sdr_compatible_str, tmp);
1727d0af6dfSXianjun Jiao 	// 	// xpu_api->XPU_REG_SLICE_COUNT_START1_write(tmp);
1737d0af6dfSXianjun Jiao 	// 	return 0;
1747d0af6dfSXianjun Jiao 	// case OPENWIFI_CMD_GET_SLICE_START1:
1757d0af6dfSXianjun Jiao 	// 	skb = cfg80211_testmode_alloc_reply_skb(hw->wiphy, nla_total_size(sizeof(u32)));
1767d0af6dfSXianjun Jiao 	// 	if (!skb)
1777d0af6dfSXianjun Jiao 	// 		return -ENOMEM;
1787d0af6dfSXianjun Jiao 	// 	// tmp = (xpu_api->XPU_REG_SLICE_COUNT_START1_read());
1797d0af6dfSXianjun Jiao 	// 	if (nla_put_u32(skb, OPENWIFI_ATTR_SLICE_START1, tmp))
1807d0af6dfSXianjun Jiao 	// 		goto nla_put_failure;
1817d0af6dfSXianjun Jiao 	// 	return cfg80211_testmode_reply(skb);
1827d0af6dfSXianjun Jiao 
1837d0af6dfSXianjun Jiao 	// case OPENWIFI_CMD_SET_SLICE_END1:
1847d0af6dfSXianjun Jiao 	// 	if (!tb[OPENWIFI_ATTR_SLICE_END1])
1857d0af6dfSXianjun Jiao 	// 		return -EINVAL;
1867d0af6dfSXianjun Jiao 	// 	tmp = nla_get_u32(tb[OPENWIFI_ATTR_SLICE_END1]);
1877d0af6dfSXianjun Jiao 	// 	printk("%s set SLICE_END1(duration) to %d usec\n", sdr_compatible_str, tmp);
1887d0af6dfSXianjun Jiao 	// 	// xpu_api->XPU_REG_SLICE_COUNT_END1_write(tmp);
1897d0af6dfSXianjun Jiao 	// 	return 0;
1907d0af6dfSXianjun Jiao 	// case OPENWIFI_CMD_GET_SLICE_END1:
1917d0af6dfSXianjun Jiao 	// 	skb = cfg80211_testmode_alloc_reply_skb(hw->wiphy, nla_total_size(sizeof(u32)));
1927d0af6dfSXianjun Jiao 	// 	if (!skb)
1937d0af6dfSXianjun Jiao 	// 		return -ENOMEM;
1947d0af6dfSXianjun Jiao 	// 	// tmp = (xpu_api->XPU_REG_SLICE_COUNT_END1_read());
1957d0af6dfSXianjun Jiao 	// 	if (nla_put_u32(skb, OPENWIFI_ATTR_SLICE_END1, tmp))
1967d0af6dfSXianjun Jiao 	// 		goto nla_put_failure;
1977d0af6dfSXianjun Jiao 	// 	return cfg80211_testmode_reply(skb);
1987d0af6dfSXianjun Jiao 
1997d0af6dfSXianjun Jiao 	case OPENWIFI_CMD_SET_RSSI_TH:
2007d0af6dfSXianjun Jiao 		if (!tb[OPENWIFI_ATTR_RSSI_TH])
2017d0af6dfSXianjun Jiao 			return -EINVAL;
2027d0af6dfSXianjun Jiao 		tmp = nla_get_u32(tb[OPENWIFI_ATTR_RSSI_TH]);
2037d0af6dfSXianjun Jiao 		// printk("%s set RSSI_TH to %d\n", sdr_compatible_str, tmp);
2047d0af6dfSXianjun Jiao 		// xpu_api->XPU_REG_LBT_TH_write(tmp);
2057d0af6dfSXianjun Jiao 		// return 0;
2067d0af6dfSXianjun Jiao 		printk("%s WARNING Please use command: sdrctl dev sdr0 set reg drv_xpu 0 reg_value! (1~2047, 0 means AUTO)!\n", sdr_compatible_str);
2077d0af6dfSXianjun Jiao 		return -EOPNOTSUPP;
2087d0af6dfSXianjun Jiao 	case OPENWIFI_CMD_GET_RSSI_TH:
209*db8c69b6Srobgar2001 		skb = (struct sk_buff *)cfg80211_testmode_alloc_reply_skb(hw->wiphy, nla_total_size(sizeof(u32)));
2107d0af6dfSXianjun Jiao 		if (!skb)
2117d0af6dfSXianjun Jiao 			return -ENOMEM;
2127d0af6dfSXianjun Jiao 		tmp_int = rssi_half_db_to_rssi_dbm(xpu_api->XPU_REG_LBT_TH_read(), priv->rssi_correction); //rssi_dbm
2137d0af6dfSXianjun Jiao 		tmp = (-tmp_int);
2147d0af6dfSXianjun Jiao 		if (nla_put_u32(skb, OPENWIFI_ATTR_RSSI_TH, tmp))
2157d0af6dfSXianjun Jiao 			goto nla_put_failure;
2167d0af6dfSXianjun Jiao 		return cfg80211_testmode_reply(skb);
2177d0af6dfSXianjun Jiao 
2187d0af6dfSXianjun Jiao 	case OPENWIFI_CMD_SET_TSF:
2197d0af6dfSXianjun Jiao 		printk("openwifi_set_tsf_1");
2207d0af6dfSXianjun Jiao 		if ( (!tb[OPENWIFI_ATTR_HIGH_TSF]) || (!tb[OPENWIFI_ATTR_LOW_TSF]) )
2217d0af6dfSXianjun Jiao 				return -EINVAL;
2227d0af6dfSXianjun Jiao 		printk("openwifi_set_tsf_2");
2237d0af6dfSXianjun Jiao 		tsft_high = nla_get_u32(tb[OPENWIFI_ATTR_HIGH_TSF]);
2247d0af6dfSXianjun Jiao 		tsft_low  = nla_get_u32(tb[OPENWIFI_ATTR_LOW_TSF]);
2257d0af6dfSXianjun Jiao 		xpu_api->XPU_REG_TSF_LOAD_VAL_write(tsft_high,tsft_low);
2267d0af6dfSXianjun Jiao 		printk("%s openwifi_set_tsf: %08x%08x\n", sdr_compatible_str,tsft_high,tsft_low);
2277d0af6dfSXianjun Jiao 		return 0;
2287d0af6dfSXianjun Jiao 
2297d0af6dfSXianjun Jiao 	case REG_CMD_SET:
2307d0af6dfSXianjun Jiao 		if ( (!tb[REG_ATTR_ADDR]) || (!tb[REG_ATTR_VAL]) )
2317d0af6dfSXianjun Jiao 			return -EINVAL;
2327d0af6dfSXianjun Jiao 		reg_addr = nla_get_u32(tb[REG_ATTR_ADDR]);
2337d0af6dfSXianjun Jiao 		reg_val  = nla_get_u32(tb[REG_ATTR_VAL]);
2347d0af6dfSXianjun Jiao 		reg_cat = ((reg_addr>>16)&0xFFFF);
2357d0af6dfSXianjun Jiao 		reg_addr = (reg_addr&0xFFFF);
2367d0af6dfSXianjun Jiao 		reg_addr_idx = (reg_addr>>2);
2377d0af6dfSXianjun Jiao 		printk("%s recv set cmd reg cat %d addr %08x val %08x idx %d\n", sdr_compatible_str, reg_cat, reg_addr, reg_val, reg_addr_idx);
2387d0af6dfSXianjun Jiao 		if (reg_cat==SDRCTL_REG_CAT_RF) {
2397d0af6dfSXianjun Jiao 			// printk("%s WARNING reg cat 1 (rf) is not supported yet!\n", sdr_compatible_str);
2407d0af6dfSXianjun Jiao 			// return -EOPNOTSUPP;
2417d0af6dfSXianjun Jiao 			if (reg_addr_idx>=0 && reg_addr_idx<MAX_NUM_RF_REG) {
2427d0af6dfSXianjun Jiao 				priv->rf_reg_val[reg_addr_idx]=reg_val;
2437d0af6dfSXianjun Jiao 				if (reg_addr_idx==RF_TX_REG_IDX_ATT) {//change the tx ON att (if a RF chain is ON)
2447d0af6dfSXianjun Jiao 					tmp = ad9361_get_tx_atten(priv->ad9361_phy, 1);
2457d0af6dfSXianjun Jiao 					printk("%s ad9361_get_tx_atten ant0 %d\n",sdr_compatible_str, tmp);
2467d0af6dfSXianjun Jiao 					if (tmp<AD9361_RADIO_OFF_TX_ATT) {
2477d0af6dfSXianjun Jiao 						err = ad9361_set_tx_atten(priv->ad9361_phy, AD9361_RADIO_ON_TX_ATT+reg_val, true, false, true);
2487d0af6dfSXianjun Jiao 						if (err < 0) {
2497d0af6dfSXianjun Jiao 							printk("%s WARNING ad9361_set_tx_atten ant0 %d FAIL!\n",sdr_compatible_str, AD9361_RADIO_ON_TX_ATT+reg_val);
2507d0af6dfSXianjun Jiao 							return -EIO;
2517d0af6dfSXianjun Jiao 						} else {
2527d0af6dfSXianjun Jiao 							printk("%s ad9361_set_tx_atten ant0 %d OK\n",sdr_compatible_str, AD9361_RADIO_ON_TX_ATT+reg_val);
2537d0af6dfSXianjun Jiao 						}
2547d0af6dfSXianjun Jiao 					}
2557d0af6dfSXianjun Jiao 					tmp = ad9361_get_tx_atten(priv->ad9361_phy, 2);
2567d0af6dfSXianjun Jiao 					printk("%s ad9361_get_tx_atten ant1 %d\n",sdr_compatible_str, tmp);
2577d0af6dfSXianjun Jiao 					if (tmp<AD9361_RADIO_OFF_TX_ATT) {
2587d0af6dfSXianjun Jiao 						err = ad9361_set_tx_atten(priv->ad9361_phy, AD9361_RADIO_ON_TX_ATT+reg_val, false, true, true);
2597d0af6dfSXianjun Jiao 						if (err < 0) {
2607d0af6dfSXianjun Jiao 							printk("%s WARNING ad9361_set_tx_atten ant1 %d FAIL!\n",sdr_compatible_str, AD9361_RADIO_ON_TX_ATT+reg_val);
2617d0af6dfSXianjun Jiao 							return -EIO;
2627d0af6dfSXianjun Jiao 						} else {
2637d0af6dfSXianjun Jiao 							printk("%s ad9361_set_tx_atten ant1 %d OK\n",sdr_compatible_str, AD9361_RADIO_ON_TX_ATT+reg_val);
2647d0af6dfSXianjun Jiao 						}
2657d0af6dfSXianjun Jiao 					}
266d6c1c3f7SXianjun Jiao 				} else if (reg_addr_idx==RF_TX_REG_IDX_FREQ_MHZ) { // apply the tx fo
267d6c1c3f7SXianjun Jiao 					clk_set_rate(priv->ad9361_phy->clks[TX_RFPLL], ( ((u64)1000000ull)*((u64)priv->rf_reg_val[RF_TX_REG_IDX_FREQ_MHZ]) )>>1 );
268d6c1c3f7SXianjun Jiao 					ad9361_tx_calibration(priv, priv->rf_reg_val[RF_TX_REG_IDX_FREQ_MHZ]);
269d6c1c3f7SXianjun Jiao 					printk("%s clk_set_rate TX_RFPLL %dMHz done\n",sdr_compatible_str, priv->rf_reg_val[RF_TX_REG_IDX_FREQ_MHZ]);
270d6c1c3f7SXianjun Jiao 				} else if (reg_addr_idx==RF_RX_REG_IDX_FREQ_MHZ) { // apply the rx fo
271d6c1c3f7SXianjun Jiao 					clk_set_rate(priv->ad9361_phy->clks[RX_RFPLL], ( ((u64)1000000ull)*((u64)priv->rf_reg_val[RF_RX_REG_IDX_FREQ_MHZ]) )>>1 );
272d6c1c3f7SXianjun Jiao 					openwifi_rf_rx_update_after_tuning(priv, priv->rf_reg_val[RF_RX_REG_IDX_FREQ_MHZ]);
273d6c1c3f7SXianjun Jiao 					printk("%s clk_set_rate RX_RFPLL %dMHz done\n",sdr_compatible_str, priv->rf_reg_val[RF_RX_REG_IDX_FREQ_MHZ]);
2747d0af6dfSXianjun Jiao 				}
2757d0af6dfSXianjun Jiao 			} else {
2767d0af6dfSXianjun Jiao 				printk("%s WARNING reg_addr_idx %d is out of range!\n", sdr_compatible_str, reg_addr_idx);
2777d0af6dfSXianjun Jiao 				return -EOPNOTSUPP;
2787d0af6dfSXianjun Jiao 			}
2797d0af6dfSXianjun Jiao 		}
2807d0af6dfSXianjun Jiao 		else if (reg_cat==SDRCTL_REG_CAT_RX_INTF)
2817d0af6dfSXianjun Jiao 			rx_intf_api->reg_write(reg_addr,reg_val);
2827d0af6dfSXianjun Jiao 		else if (reg_cat==SDRCTL_REG_CAT_TX_INTF)
2837d0af6dfSXianjun Jiao 			tx_intf_api->reg_write(reg_addr,reg_val);
2847d0af6dfSXianjun Jiao 		else if (reg_cat==SDRCTL_REG_CAT_RX)
2857d0af6dfSXianjun Jiao 			openofdm_rx_api->reg_write(reg_addr,reg_val);
2867d0af6dfSXianjun Jiao 		else if (reg_cat==SDRCTL_REG_CAT_TX)
2877d0af6dfSXianjun Jiao 			openofdm_tx_api->reg_write(reg_addr,reg_val);
2887d0af6dfSXianjun Jiao 		else if (reg_cat==SDRCTL_REG_CAT_XPU)
2897d0af6dfSXianjun Jiao 			xpu_api->reg_write(reg_addr,reg_val);
2907d0af6dfSXianjun Jiao 		else if (reg_cat==SDRCTL_REG_CAT_DRV_RX) {
2917d0af6dfSXianjun Jiao 			if (reg_addr_idx>=0 && reg_addr_idx<MAX_NUM_DRV_REG) {
2927d0af6dfSXianjun Jiao 				if (reg_addr_idx==DRV_RX_REG_IDX_ANT_CFG) {
2937d0af6dfSXianjun Jiao 					tmp = openwifi_set_antenna(hw, (priv->drv_tx_reg_val[reg_addr_idx]==0?1:2), (reg_val==0?1:2));
2947d0af6dfSXianjun Jiao 					if (tmp) {
2957d0af6dfSXianjun Jiao 						printk("%s WARNING openwifi_set_antenna return %d!\n", sdr_compatible_str, tmp);
2967d0af6dfSXianjun Jiao 						return -EIO;
2977d0af6dfSXianjun Jiao 					} else {
2987d0af6dfSXianjun Jiao 						priv->drv_rx_reg_val[reg_addr_idx]=reg_val;
2997d0af6dfSXianjun Jiao 					}
3007d0af6dfSXianjun Jiao 				} else {
3017d0af6dfSXianjun Jiao 					priv->drv_rx_reg_val[reg_addr_idx]=reg_val;
3027d0af6dfSXianjun Jiao 					if (reg_addr_idx==DRV_RX_REG_IDX_DEMOD_TH) {
3037d0af6dfSXianjun Jiao 						openofdm_rx_api->OPENOFDM_RX_REG_POWER_THRES_write((OPENOFDM_RX_DC_RUNNING_SUM_TH_INIT<<16)|rssi_dbm_to_rssi_half_db((reg_val==0?OPENOFDM_RX_RSSI_DBM_TH_DEFAULT:(-reg_val)), priv->rssi_correction));
3047d0af6dfSXianjun Jiao 					}
3057d0af6dfSXianjun Jiao 				}
3067d0af6dfSXianjun Jiao 			} else {
3077d0af6dfSXianjun Jiao 				printk("%s WARNING reg_addr_idx %d is out of range!\n", sdr_compatible_str, reg_addr_idx);
3087d0af6dfSXianjun Jiao 				return -EOPNOTSUPP;
3097d0af6dfSXianjun Jiao 			}
3107d0af6dfSXianjun Jiao 		}
3117d0af6dfSXianjun Jiao 		else if (reg_cat==SDRCTL_REG_CAT_DRV_TX) {
3127d0af6dfSXianjun Jiao 			if (reg_addr_idx>=0 && reg_addr_idx<MAX_NUM_DRV_REG) {
3137d0af6dfSXianjun Jiao 				if ((reg_addr_idx == DRV_TX_REG_IDX_RATE || reg_addr_idx == DRV_TX_REG_IDX_RATE_HT) &&
3147d0af6dfSXianjun Jiao 				    (reg_val != 0 && (!((reg_val&0xF)>=4 && (reg_val&0xF)<=11)) ) ) {
3157d0af6dfSXianjun Jiao 					printk("%s WARNING rate override value should be 0 or 4~11!\n", sdr_compatible_str);
3167d0af6dfSXianjun Jiao 					return -EOPNOTSUPP;
3177d0af6dfSXianjun Jiao 				} else {
3187d0af6dfSXianjun Jiao 					if (reg_addr_idx==DRV_TX_REG_IDX_ANT_CFG) {
3197d0af6dfSXianjun Jiao 						tmp = openwifi_set_antenna(hw, reg_val+1, priv->drv_rx_reg_val[reg_addr_idx]+1);
3207d0af6dfSXianjun Jiao 						if (tmp) {
3217d0af6dfSXianjun Jiao 							printk("%s WARNING openwifi_set_antenna return %d!\n", sdr_compatible_str, tmp);
3227d0af6dfSXianjun Jiao 							return -EIO;
3237d0af6dfSXianjun Jiao 						} else {
3247d0af6dfSXianjun Jiao 							priv->drv_tx_reg_val[reg_addr_idx]=reg_val;
3257d0af6dfSXianjun Jiao 						}
3267d0af6dfSXianjun Jiao 					} else {
3277d0af6dfSXianjun Jiao 						priv->drv_tx_reg_val[reg_addr_idx]=reg_val;
3287d0af6dfSXianjun Jiao 					}
3297d0af6dfSXianjun Jiao 				}
3307d0af6dfSXianjun Jiao 			} else {
3317d0af6dfSXianjun Jiao 				printk("%s WARNING reg_addr_idx %d is out of range!\n", sdr_compatible_str, reg_addr_idx);
3327d0af6dfSXianjun Jiao 				return -EOPNOTSUPP;
3337d0af6dfSXianjun Jiao 			}
3347d0af6dfSXianjun Jiao 		}
3357d0af6dfSXianjun Jiao 		else if (reg_cat==SDRCTL_REG_CAT_DRV_XPU) {
3367d0af6dfSXianjun Jiao 			if (reg_addr_idx>=0 && reg_addr_idx<MAX_NUM_DRV_REG) {
3377d0af6dfSXianjun Jiao 				priv->drv_xpu_reg_val[reg_addr_idx]=reg_val;
3387d0af6dfSXianjun Jiao 				if (reg_addr_idx==DRV_XPU_REG_IDX_LBT_TH) {
3397d0af6dfSXianjun Jiao 					if (reg_val) {
3407d0af6dfSXianjun Jiao 						tmp_int = (-reg_val); // rssi_dbm
3417d0af6dfSXianjun Jiao 						tmp = rssi_dbm_to_rssi_half_db(tmp_int, priv->rssi_correction);
3427d0af6dfSXianjun Jiao 						xpu_api->XPU_REG_LBT_TH_write( tmp );
3433d5de438SXianjun Jiao 						printk("%s override FPGA LBT threshold to %d(%ddBm). The last_auto_fpga_lbt_th %d(%ddBm). rssi corr %d (%d/%dMHz)\n", sdr_compatible_str, tmp, tmp_int, priv->last_auto_fpga_lbt_th, rssi_half_db_to_rssi_dbm(priv->last_auto_fpga_lbt_th, priv->rssi_correction), priv->rssi_correction, priv->actual_tx_lo, priv->actual_rx_lo);
3447d0af6dfSXianjun Jiao 					} else {
3457d0af6dfSXianjun Jiao 						xpu_api->XPU_REG_LBT_TH_write(priv->last_auto_fpga_lbt_th);
3463d5de438SXianjun Jiao 						printk("%s Restore last_auto_fpga_lbt_th %d(%ddBm) to FPGA. ad9361_rf_set_channel will take control. rssi corr %d (%d/%dMHz)\n", sdr_compatible_str, priv->last_auto_fpga_lbt_th, rssi_half_db_to_rssi_dbm(priv->last_auto_fpga_lbt_th, priv->rssi_correction), priv->rssi_correction, priv->actual_tx_lo, priv->actual_rx_lo);
3477d0af6dfSXianjun Jiao 					}
3487d0af6dfSXianjun Jiao 				}
3497d0af6dfSXianjun Jiao 			} else {
3507d0af6dfSXianjun Jiao 				printk("%s WARNING reg_addr_idx %d is out of range!\n", sdr_compatible_str, reg_addr_idx);
3517d0af6dfSXianjun Jiao 				return -EOPNOTSUPP;
3527d0af6dfSXianjun Jiao 			}
3537d0af6dfSXianjun Jiao 		}
3547d0af6dfSXianjun Jiao 		else {
3557d0af6dfSXianjun Jiao 			printk("%s WARNING reg cat %d is not supported yet!\n", sdr_compatible_str, reg_cat);
3567d0af6dfSXianjun Jiao 			return -EOPNOTSUPP;
3577d0af6dfSXianjun Jiao 		}
3587d0af6dfSXianjun Jiao 
3597d0af6dfSXianjun Jiao 		return 0;
3607d0af6dfSXianjun Jiao 	case REG_CMD_GET:
361*db8c69b6Srobgar2001 		skb = (struct sk_buff *)cfg80211_testmode_alloc_reply_skb(hw->wiphy, nla_total_size(sizeof(u32)));
3627d0af6dfSXianjun Jiao 		if (!skb)
3637d0af6dfSXianjun Jiao 			return -ENOMEM;
3647d0af6dfSXianjun Jiao 		reg_addr = nla_get_u32(tb[REG_ATTR_ADDR]);
3657d0af6dfSXianjun Jiao 		reg_cat = ((reg_addr>>16)&0xFFFF);
3667d0af6dfSXianjun Jiao 		reg_addr = (reg_addr&0xFFFF);
3677d0af6dfSXianjun Jiao 		reg_addr_idx = (reg_addr>>2);
3687d0af6dfSXianjun Jiao 		printk("%s recv get cmd reg cat %d addr %08x idx %d\n", sdr_compatible_str, reg_cat, reg_addr, reg_addr_idx);
3697d0af6dfSXianjun Jiao 		if (reg_cat==SDRCTL_REG_CAT_RF) {
3707d0af6dfSXianjun Jiao 			// printk("%s WARNING reg cat 1 (rf) is not supported yet!\n", sdr_compatible_str);
3717d0af6dfSXianjun Jiao 			// tmp = 0xFFFFFFFF;
3727d0af6dfSXianjun Jiao 			// return -EOPNOTSUPP;
3737d0af6dfSXianjun Jiao 			if (reg_addr_idx>=0 && reg_addr_idx<MAX_NUM_RF_REG) {
3747d0af6dfSXianjun Jiao 				tmp = priv->rf_reg_val[reg_addr_idx];
3757d0af6dfSXianjun Jiao 			} else {
3767d0af6dfSXianjun Jiao 				printk("%s WARNING reg_addr_idx %d is out of range!\n", sdr_compatible_str, reg_addr_idx);
3777d0af6dfSXianjun Jiao 				return -EOPNOTSUPP;
3787d0af6dfSXianjun Jiao 			}
3797d0af6dfSXianjun Jiao 		}
3807d0af6dfSXianjun Jiao 		else if (reg_cat==SDRCTL_REG_CAT_RX_INTF)
3817d0af6dfSXianjun Jiao 			tmp = rx_intf_api->reg_read(reg_addr);
3827d0af6dfSXianjun Jiao 		else if (reg_cat==SDRCTL_REG_CAT_TX_INTF)
3837d0af6dfSXianjun Jiao 			tmp = tx_intf_api->reg_read(reg_addr);
3847d0af6dfSXianjun Jiao 		else if (reg_cat==SDRCTL_REG_CAT_RX)
3857d0af6dfSXianjun Jiao 			tmp = openofdm_rx_api->reg_read(reg_addr);
3867d0af6dfSXianjun Jiao 		else if (reg_cat==SDRCTL_REG_CAT_TX)
3877d0af6dfSXianjun Jiao 			tmp = openofdm_tx_api->reg_read(reg_addr);
3887d0af6dfSXianjun Jiao 		else if (reg_cat==SDRCTL_REG_CAT_XPU)
3897d0af6dfSXianjun Jiao 			tmp = xpu_api->reg_read(reg_addr);
3907d0af6dfSXianjun Jiao 		else if (reg_cat==SDRCTL_REG_CAT_DRV_RX) {
3917d0af6dfSXianjun Jiao 			if (reg_addr_idx>=0 && reg_addr_idx<MAX_NUM_DRV_REG) {
3927d0af6dfSXianjun Jiao 				tmp = priv->drv_rx_reg_val[reg_addr_idx];
3937d0af6dfSXianjun Jiao 				if (reg_addr_idx==DRV_RX_REG_IDX_ANT_CFG)
3947d0af6dfSXianjun Jiao 					openwifi_get_antenna(hw, &tsft_high, &tsft_low);
3957d0af6dfSXianjun Jiao 			} else {
3967d0af6dfSXianjun Jiao 				printk("%s WARNING reg_addr_idx %d is out of range!\n", sdr_compatible_str, reg_addr_idx);
3977d0af6dfSXianjun Jiao 				return -EOPNOTSUPP;
3987d0af6dfSXianjun Jiao 			}
3997d0af6dfSXianjun Jiao 		}
4007d0af6dfSXianjun Jiao 		else if (reg_cat==SDRCTL_REG_CAT_DRV_TX) {
4017d0af6dfSXianjun Jiao 			if (reg_addr_idx>=0 && reg_addr_idx<MAX_NUM_DRV_REG) {
4027d0af6dfSXianjun Jiao 				tmp = priv->drv_tx_reg_val[reg_addr_idx];
4037d0af6dfSXianjun Jiao 				if (reg_addr_idx==DRV_TX_REG_IDX_ANT_CFG)
4047d0af6dfSXianjun Jiao 					openwifi_get_antenna(hw, &tsft_high, &tsft_low);
4057d0af6dfSXianjun Jiao 			} else {
4067d0af6dfSXianjun Jiao 				printk("%s WARNING reg_addr_idx %d is out of range!\n", sdr_compatible_str, reg_addr_idx);
4077d0af6dfSXianjun Jiao 				return -EOPNOTSUPP;
4087d0af6dfSXianjun Jiao 			}
4097d0af6dfSXianjun Jiao 		}
4107d0af6dfSXianjun Jiao 		else if (reg_cat==SDRCTL_REG_CAT_DRV_XPU) {
4117d0af6dfSXianjun Jiao 			if (reg_addr_idx>=0 && reg_addr_idx<MAX_NUM_DRV_REG) {
4127d0af6dfSXianjun Jiao 				if (reg_addr_idx==DRV_XPU_REG_IDX_LBT_TH) {
4137d0af6dfSXianjun Jiao 					tmp = xpu_api->XPU_REG_LBT_TH_read();//rssi_half_db
4147d0af6dfSXianjun Jiao 					tmp_int = rssi_half_db_to_rssi_dbm(tmp, priv->rssi_correction); //rssi_dbm
4153d5de438SXianjun Jiao 					printk("%s FPGA LBT threshold %d(%ddBm). The last_auto_fpga_lbt_th %d(%ddBm). rssi corr %d (%d/%dMHz)\n", sdr_compatible_str, tmp, tmp_int, priv->last_auto_fpga_lbt_th, rssi_half_db_to_rssi_dbm(priv->last_auto_fpga_lbt_th, priv->rssi_correction), priv->rssi_correction, priv->actual_tx_lo, priv->actual_rx_lo);
4167d0af6dfSXianjun Jiao 				}
4177d0af6dfSXianjun Jiao 				tmp = priv->drv_xpu_reg_val[reg_addr_idx];
4187d0af6dfSXianjun Jiao 			} else {
4197d0af6dfSXianjun Jiao 				printk("%s WARNING reg_addr_idx %d is out of range!\n", sdr_compatible_str, reg_addr_idx);
4207d0af6dfSXianjun Jiao 				return -EOPNOTSUPP;
4217d0af6dfSXianjun Jiao 			}
4227d0af6dfSXianjun Jiao 		}
4237d0af6dfSXianjun Jiao 		else {
4247d0af6dfSXianjun Jiao 			printk("%s WARNING reg cat %d is not supported yet!\n", sdr_compatible_str, reg_cat);
4257d0af6dfSXianjun Jiao 			return -EOPNOTSUPP;
4267d0af6dfSXianjun Jiao 		}
4277d0af6dfSXianjun Jiao 
4287d0af6dfSXianjun Jiao 		if (nla_put_u32(skb, REG_ATTR_VAL, tmp))
4297d0af6dfSXianjun Jiao 			goto nla_put_failure;
4307d0af6dfSXianjun Jiao 		return cfg80211_testmode_reply(skb);
4317d0af6dfSXianjun Jiao 
4327d0af6dfSXianjun Jiao 	default:
4337d0af6dfSXianjun Jiao 		return -EOPNOTSUPP;
4347d0af6dfSXianjun Jiao 	}
4357d0af6dfSXianjun Jiao 
4367d0af6dfSXianjun Jiao  nla_put_failure:
4377d0af6dfSXianjun Jiao 	dev_kfree_skb(skb);
4387d0af6dfSXianjun Jiao 	return -ENOBUFS;
4397d0af6dfSXianjun Jiao }
440