xref: /linux/drivers/net/wireless/mediatek/mt76/mt7921/testmode.c (revision 680a2ead741ad9b479a53adf154ed5eee74d2b9a)
1bce84458SLorenzo Bianconi // SPDX-License-Identifier: ISC
2bce84458SLorenzo Bianconi 
3bce84458SLorenzo Bianconi #include "mt7921.h"
4bce84458SLorenzo Bianconi #include "mcu.h"
5bce84458SLorenzo Bianconi 
6bce84458SLorenzo Bianconi enum mt7921_testmode_attr {
7bce84458SLorenzo Bianconi 	MT7921_TM_ATTR_UNSPEC,
8bce84458SLorenzo Bianconi 	MT7921_TM_ATTR_SET,
9bce84458SLorenzo Bianconi 	MT7921_TM_ATTR_QUERY,
10bce84458SLorenzo Bianconi 	MT7921_TM_ATTR_RSP,
11bce84458SLorenzo Bianconi 
12bce84458SLorenzo Bianconi 	/* keep last */
13bce84458SLorenzo Bianconi 	NUM_MT7921_TM_ATTRS,
14bce84458SLorenzo Bianconi 	MT7921_TM_ATTR_MAX = NUM_MT7921_TM_ATTRS - 1,
15bce84458SLorenzo Bianconi };
16bce84458SLorenzo Bianconi 
17bce84458SLorenzo Bianconi struct mt7921_tm_cmd {
18bce84458SLorenzo Bianconi 	u8 action;
19bce84458SLorenzo Bianconi 	u32 param0;
20bce84458SLorenzo Bianconi 	u32 param1;
21bce84458SLorenzo Bianconi };
22bce84458SLorenzo Bianconi 
23bce84458SLorenzo Bianconi struct mt7921_tm_evt {
24bce84458SLorenzo Bianconi 	u32 param0;
25bce84458SLorenzo Bianconi 	u32 param1;
26bce84458SLorenzo Bianconi };
27bce84458SLorenzo Bianconi 
28bce84458SLorenzo Bianconi static const struct nla_policy mt7921_tm_policy[NUM_MT7921_TM_ATTRS] = {
29bce84458SLorenzo Bianconi 	[MT7921_TM_ATTR_SET] = NLA_POLICY_EXACT_LEN(sizeof(struct mt7921_tm_cmd)),
30bce84458SLorenzo Bianconi 	[MT7921_TM_ATTR_QUERY] = NLA_POLICY_EXACT_LEN(sizeof(struct mt7921_tm_cmd)),
31bce84458SLorenzo Bianconi };
32bce84458SLorenzo Bianconi 
33bce84458SLorenzo Bianconi static int
34bce84458SLorenzo Bianconi mt7921_tm_set(struct mt7921_dev *dev, struct mt7921_tm_cmd *req)
35bce84458SLorenzo Bianconi {
36bce84458SLorenzo Bianconi 	struct mt7921_rftest_cmd cmd = {
37bce84458SLorenzo Bianconi 		.action = req->action,
38bce84458SLorenzo Bianconi 		.param0 = cpu_to_le32(req->param0),
39bce84458SLorenzo Bianconi 		.param1 = cpu_to_le32(req->param1),
40bce84458SLorenzo Bianconi 	};
41bce84458SLorenzo Bianconi 	bool testmode = false, normal = false;
42bce84458SLorenzo Bianconi 	struct mt76_connac_pm *pm = &dev->pm;
43bce84458SLorenzo Bianconi 	struct mt76_phy *phy = &dev->mphy;
44bce84458SLorenzo Bianconi 	int ret = -ENOTCONN;
45bce84458SLorenzo Bianconi 
46bce84458SLorenzo Bianconi 	mutex_lock(&dev->mt76.mutex);
47bce84458SLorenzo Bianconi 
48bce84458SLorenzo Bianconi 	if (req->action == TM_SWITCH_MODE) {
49bce84458SLorenzo Bianconi 		if (req->param0 == MT7921_TM_NORMAL)
50bce84458SLorenzo Bianconi 			normal = true;
51bce84458SLorenzo Bianconi 		else
52bce84458SLorenzo Bianconi 			testmode = true;
53bce84458SLorenzo Bianconi 	}
54bce84458SLorenzo Bianconi 
55bce84458SLorenzo Bianconi 	if (testmode) {
56bce84458SLorenzo Bianconi 		/* Make sure testmode running on full power mode */
57bce84458SLorenzo Bianconi 		pm->enable = false;
58bce84458SLorenzo Bianconi 		cancel_delayed_work_sync(&pm->ps_work);
59bce84458SLorenzo Bianconi 		cancel_work_sync(&pm->wake_work);
60bce84458SLorenzo Bianconi 		__mt7921_mcu_drv_pmctrl(dev);
61bce84458SLorenzo Bianconi 
62bce84458SLorenzo Bianconi 		mt76_wr(dev, MT_WF_RFCR(0), dev->mt76.rxfilter);
63bce84458SLorenzo Bianconi 		phy->test.state = MT76_TM_STATE_ON;
64bce84458SLorenzo Bianconi 	}
65bce84458SLorenzo Bianconi 
66bce84458SLorenzo Bianconi 	if (!mt76_testmode_enabled(phy))
67bce84458SLorenzo Bianconi 		goto out;
68bce84458SLorenzo Bianconi 
69*680a2eadSLorenzo Bianconi 	ret = mt76_mcu_send_msg(&dev->mt76, MCU_CE_CMD(TEST_CTRL), &cmd,
70bce84458SLorenzo Bianconi 				sizeof(cmd), false);
71bce84458SLorenzo Bianconi 	if (ret)
72bce84458SLorenzo Bianconi 		goto out;
73bce84458SLorenzo Bianconi 
74bce84458SLorenzo Bianconi 	if (normal) {
75bce84458SLorenzo Bianconi 		/* Switch back to the normal world */
76bce84458SLorenzo Bianconi 		phy->test.state = MT76_TM_STATE_OFF;
77bce84458SLorenzo Bianconi 		pm->enable = true;
78bce84458SLorenzo Bianconi 	}
79bce84458SLorenzo Bianconi out:
80bce84458SLorenzo Bianconi 	mutex_unlock(&dev->mt76.mutex);
81bce84458SLorenzo Bianconi 
82bce84458SLorenzo Bianconi 	return ret;
83bce84458SLorenzo Bianconi }
84bce84458SLorenzo Bianconi 
85bce84458SLorenzo Bianconi static int
86bce84458SLorenzo Bianconi mt7921_tm_query(struct mt7921_dev *dev, struct mt7921_tm_cmd *req,
87bce84458SLorenzo Bianconi 		struct mt7921_tm_evt *evt_resp)
88bce84458SLorenzo Bianconi {
89bce84458SLorenzo Bianconi 	struct mt7921_rftest_cmd cmd = {
90bce84458SLorenzo Bianconi 		.action = req->action,
91bce84458SLorenzo Bianconi 		.param0 = cpu_to_le32(req->param0),
92bce84458SLorenzo Bianconi 		.param1 = cpu_to_le32(req->param1),
93bce84458SLorenzo Bianconi 	};
94bce84458SLorenzo Bianconi 	struct mt7921_rftest_evt *evt;
95bce84458SLorenzo Bianconi 	struct sk_buff *skb;
96bce84458SLorenzo Bianconi 	int ret;
97bce84458SLorenzo Bianconi 
98*680a2eadSLorenzo Bianconi 	ret = mt76_mcu_send_and_get_msg(&dev->mt76, MCU_CE_CMD(TEST_CTRL),
99bce84458SLorenzo Bianconi 					&cmd, sizeof(cmd), true, &skb);
100bce84458SLorenzo Bianconi 	if (ret)
101bce84458SLorenzo Bianconi 		goto out;
102bce84458SLorenzo Bianconi 
103bce84458SLorenzo Bianconi 	evt = (struct mt7921_rftest_evt *)skb->data;
104bce84458SLorenzo Bianconi 	evt_resp->param0 = le32_to_cpu(evt->param0);
105bce84458SLorenzo Bianconi 	evt_resp->param1 = le32_to_cpu(evt->param1);
106bce84458SLorenzo Bianconi out:
107bce84458SLorenzo Bianconi 	dev_kfree_skb(skb);
108bce84458SLorenzo Bianconi 
109bce84458SLorenzo Bianconi 	return ret;
110bce84458SLorenzo Bianconi }
111bce84458SLorenzo Bianconi 
112bce84458SLorenzo Bianconi int mt7921_testmode_cmd(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
113bce84458SLorenzo Bianconi 			void *data, int len)
114bce84458SLorenzo Bianconi {
115bce84458SLorenzo Bianconi 	struct nlattr *tb[NUM_MT76_TM_ATTRS];
116bce84458SLorenzo Bianconi 	struct mt76_phy *mphy = hw->priv;
117bce84458SLorenzo Bianconi 	struct mt7921_phy *phy = mphy->priv;
118bce84458SLorenzo Bianconi 	int err;
119bce84458SLorenzo Bianconi 
120bce84458SLorenzo Bianconi 	if (!test_bit(MT76_STATE_RUNNING, &mphy->state) ||
121bce84458SLorenzo Bianconi 	    !(hw->conf.flags & IEEE80211_CONF_MONITOR))
122bce84458SLorenzo Bianconi 		return -ENOTCONN;
123bce84458SLorenzo Bianconi 
124bce84458SLorenzo Bianconi 	err = nla_parse_deprecated(tb, MT76_TM_ATTR_MAX, data, len,
125bce84458SLorenzo Bianconi 				   mt76_tm_policy, NULL);
126bce84458SLorenzo Bianconi 	if (err)
127bce84458SLorenzo Bianconi 		return err;
128bce84458SLorenzo Bianconi 
129bce84458SLorenzo Bianconi 	if (tb[MT76_TM_ATTR_DRV_DATA]) {
130bce84458SLorenzo Bianconi 		struct nlattr *drv_tb[NUM_MT7921_TM_ATTRS], *data;
131bce84458SLorenzo Bianconi 		int ret;
132bce84458SLorenzo Bianconi 
133bce84458SLorenzo Bianconi 		data = tb[MT76_TM_ATTR_DRV_DATA];
134bce84458SLorenzo Bianconi 		ret = nla_parse_nested_deprecated(drv_tb,
135bce84458SLorenzo Bianconi 						  MT7921_TM_ATTR_MAX,
136bce84458SLorenzo Bianconi 						  data, mt7921_tm_policy,
137bce84458SLorenzo Bianconi 						  NULL);
138bce84458SLorenzo Bianconi 		if (ret)
139bce84458SLorenzo Bianconi 			return ret;
140bce84458SLorenzo Bianconi 
141bce84458SLorenzo Bianconi 		data = drv_tb[MT7921_TM_ATTR_SET];
142bce84458SLorenzo Bianconi 		if (data)
143bce84458SLorenzo Bianconi 			return mt7921_tm_set(phy->dev, nla_data(data));
144bce84458SLorenzo Bianconi 	}
145bce84458SLorenzo Bianconi 
146bce84458SLorenzo Bianconi 	return -EINVAL;
147bce84458SLorenzo Bianconi }
148bce84458SLorenzo Bianconi 
149bce84458SLorenzo Bianconi int mt7921_testmode_dump(struct ieee80211_hw *hw, struct sk_buff *msg,
150bce84458SLorenzo Bianconi 			 struct netlink_callback *cb, void *data, int len)
151bce84458SLorenzo Bianconi {
152bce84458SLorenzo Bianconi 	struct nlattr *tb[NUM_MT76_TM_ATTRS];
153bce84458SLorenzo Bianconi 	struct mt76_phy *mphy = hw->priv;
154bce84458SLorenzo Bianconi 	struct mt7921_phy *phy = mphy->priv;
155bce84458SLorenzo Bianconi 	int err;
156bce84458SLorenzo Bianconi 
157bce84458SLorenzo Bianconi 	if (!test_bit(MT76_STATE_RUNNING, &mphy->state) ||
158bce84458SLorenzo Bianconi 	    !(hw->conf.flags & IEEE80211_CONF_MONITOR) ||
159bce84458SLorenzo Bianconi 	    !mt76_testmode_enabled(mphy))
160bce84458SLorenzo Bianconi 		return -ENOTCONN;
161bce84458SLorenzo Bianconi 
162bce84458SLorenzo Bianconi 	if (cb->args[2]++ > 0)
163bce84458SLorenzo Bianconi 		return -ENOENT;
164bce84458SLorenzo Bianconi 
165bce84458SLorenzo Bianconi 	err = nla_parse_deprecated(tb, MT76_TM_ATTR_MAX, data, len,
166bce84458SLorenzo Bianconi 				   mt76_tm_policy, NULL);
167bce84458SLorenzo Bianconi 	if (err)
168bce84458SLorenzo Bianconi 		return err;
169bce84458SLorenzo Bianconi 
170bce84458SLorenzo Bianconi 	if (tb[MT76_TM_ATTR_DRV_DATA]) {
171bce84458SLorenzo Bianconi 		struct nlattr *drv_tb[NUM_MT7921_TM_ATTRS], *data;
172bce84458SLorenzo Bianconi 		int ret;
173bce84458SLorenzo Bianconi 
174bce84458SLorenzo Bianconi 		data = tb[MT76_TM_ATTR_DRV_DATA];
175bce84458SLorenzo Bianconi 		ret = nla_parse_nested_deprecated(drv_tb,
176bce84458SLorenzo Bianconi 						  MT7921_TM_ATTR_MAX,
177bce84458SLorenzo Bianconi 						  data, mt7921_tm_policy,
178bce84458SLorenzo Bianconi 						  NULL);
179bce84458SLorenzo Bianconi 		if (ret)
180bce84458SLorenzo Bianconi 			return ret;
181bce84458SLorenzo Bianconi 
182bce84458SLorenzo Bianconi 		data = drv_tb[MT7921_TM_ATTR_QUERY];
183bce84458SLorenzo Bianconi 		if (data) {
184bce84458SLorenzo Bianconi 			struct mt7921_tm_evt evt_resp;
185bce84458SLorenzo Bianconi 
186bce84458SLorenzo Bianconi 			err = mt7921_tm_query(phy->dev, nla_data(data),
187bce84458SLorenzo Bianconi 					      &evt_resp);
188bce84458SLorenzo Bianconi 			if (err)
189bce84458SLorenzo Bianconi 				return err;
190bce84458SLorenzo Bianconi 
191bce84458SLorenzo Bianconi 			return nla_put(msg, MT7921_TM_ATTR_RSP,
192bce84458SLorenzo Bianconi 				       sizeof(evt_resp), &evt_resp);
193bce84458SLorenzo Bianconi 		}
194bce84458SLorenzo Bianconi 	}
195bce84458SLorenzo Bianconi 
196bce84458SLorenzo Bianconi 	return -EINVAL;
197bce84458SLorenzo Bianconi }
198