xref: /linux/drivers/net/wireless/mediatek/mt76/mt7921/testmode.c (revision 78562b2cafc61a0c08dc949eacb942ac756aae37)
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 		phy->test.state = MT76_TM_STATE_ON;
63bce84458SLorenzo Bianconi 	}
64bce84458SLorenzo Bianconi 
65bce84458SLorenzo Bianconi 	if (!mt76_testmode_enabled(phy))
66bce84458SLorenzo Bianconi 		goto out;
67bce84458SLorenzo Bianconi 
68680a2eadSLorenzo Bianconi 	ret = mt76_mcu_send_msg(&dev->mt76, MCU_CE_CMD(TEST_CTRL), &cmd,
69bce84458SLorenzo Bianconi 				sizeof(cmd), false);
70bce84458SLorenzo Bianconi 	if (ret)
71bce84458SLorenzo Bianconi 		goto out;
72bce84458SLorenzo Bianconi 
73bce84458SLorenzo Bianconi 	if (normal) {
74bce84458SLorenzo Bianconi 		/* Switch back to the normal world */
75bce84458SLorenzo Bianconi 		phy->test.state = MT76_TM_STATE_OFF;
76bce84458SLorenzo Bianconi 		pm->enable = true;
77bce84458SLorenzo Bianconi 	}
78bce84458SLorenzo Bianconi out:
79bce84458SLorenzo Bianconi 	mutex_unlock(&dev->mt76.mutex);
80bce84458SLorenzo Bianconi 
81bce84458SLorenzo Bianconi 	return ret;
82bce84458SLorenzo Bianconi }
83bce84458SLorenzo Bianconi 
84bce84458SLorenzo Bianconi static int
85bce84458SLorenzo Bianconi mt7921_tm_query(struct mt7921_dev *dev, struct mt7921_tm_cmd *req,
86bce84458SLorenzo Bianconi 		struct mt7921_tm_evt *evt_resp)
87bce84458SLorenzo Bianconi {
88bce84458SLorenzo Bianconi 	struct mt7921_rftest_cmd cmd = {
89bce84458SLorenzo Bianconi 		.action = req->action,
90bce84458SLorenzo Bianconi 		.param0 = cpu_to_le32(req->param0),
91bce84458SLorenzo Bianconi 		.param1 = cpu_to_le32(req->param1),
92bce84458SLorenzo Bianconi 	};
93bce84458SLorenzo Bianconi 	struct mt7921_rftest_evt *evt;
94bce84458SLorenzo Bianconi 	struct sk_buff *skb;
95bce84458SLorenzo Bianconi 	int ret;
96bce84458SLorenzo Bianconi 
97680a2eadSLorenzo Bianconi 	ret = mt76_mcu_send_and_get_msg(&dev->mt76, MCU_CE_CMD(TEST_CTRL),
98bce84458SLorenzo Bianconi 					&cmd, sizeof(cmd), true, &skb);
99bce84458SLorenzo Bianconi 	if (ret)
100bce84458SLorenzo Bianconi 		goto out;
101bce84458SLorenzo Bianconi 
102bce84458SLorenzo Bianconi 	evt = (struct mt7921_rftest_evt *)skb->data;
103bce84458SLorenzo Bianconi 	evt_resp->param0 = le32_to_cpu(evt->param0);
104bce84458SLorenzo Bianconi 	evt_resp->param1 = le32_to_cpu(evt->param1);
105bce84458SLorenzo Bianconi out:
106bce84458SLorenzo Bianconi 	dev_kfree_skb(skb);
107bce84458SLorenzo Bianconi 
108bce84458SLorenzo Bianconi 	return ret;
109bce84458SLorenzo Bianconi }
110bce84458SLorenzo Bianconi 
111bce84458SLorenzo Bianconi int mt7921_testmode_cmd(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
112bce84458SLorenzo Bianconi 			void *data, int len)
113bce84458SLorenzo Bianconi {
114bce84458SLorenzo Bianconi 	struct nlattr *tb[NUM_MT76_TM_ATTRS];
115bce84458SLorenzo Bianconi 	struct mt76_phy *mphy = hw->priv;
116*78562b2cSLorenzo Bianconi 	struct mt792x_phy *phy = mphy->priv;
117bce84458SLorenzo Bianconi 	int err;
118bce84458SLorenzo Bianconi 
119bce84458SLorenzo Bianconi 	if (!test_bit(MT76_STATE_RUNNING, &mphy->state) ||
120bce84458SLorenzo Bianconi 	    !(hw->conf.flags & IEEE80211_CONF_MONITOR))
121bce84458SLorenzo Bianconi 		return -ENOTCONN;
122bce84458SLorenzo Bianconi 
123bce84458SLorenzo Bianconi 	err = nla_parse_deprecated(tb, MT76_TM_ATTR_MAX, data, len,
124bce84458SLorenzo Bianconi 				   mt76_tm_policy, NULL);
125bce84458SLorenzo Bianconi 	if (err)
126bce84458SLorenzo Bianconi 		return err;
127bce84458SLorenzo Bianconi 
128bce84458SLorenzo Bianconi 	if (tb[MT76_TM_ATTR_DRV_DATA]) {
129bce84458SLorenzo Bianconi 		struct nlattr *drv_tb[NUM_MT7921_TM_ATTRS], *data;
130bce84458SLorenzo Bianconi 		int ret;
131bce84458SLorenzo Bianconi 
132bce84458SLorenzo Bianconi 		data = tb[MT76_TM_ATTR_DRV_DATA];
133bce84458SLorenzo Bianconi 		ret = nla_parse_nested_deprecated(drv_tb,
134bce84458SLorenzo Bianconi 						  MT7921_TM_ATTR_MAX,
135bce84458SLorenzo Bianconi 						  data, mt7921_tm_policy,
136bce84458SLorenzo Bianconi 						  NULL);
137bce84458SLorenzo Bianconi 		if (ret)
138bce84458SLorenzo Bianconi 			return ret;
139bce84458SLorenzo Bianconi 
140bce84458SLorenzo Bianconi 		data = drv_tb[MT7921_TM_ATTR_SET];
141bce84458SLorenzo Bianconi 		if (data)
142bce84458SLorenzo Bianconi 			return mt7921_tm_set(phy->dev, nla_data(data));
143bce84458SLorenzo Bianconi 	}
144bce84458SLorenzo Bianconi 
145bce84458SLorenzo Bianconi 	return -EINVAL;
146bce84458SLorenzo Bianconi }
147bce84458SLorenzo Bianconi 
148bce84458SLorenzo Bianconi int mt7921_testmode_dump(struct ieee80211_hw *hw, struct sk_buff *msg,
149bce84458SLorenzo Bianconi 			 struct netlink_callback *cb, void *data, int len)
150bce84458SLorenzo Bianconi {
151bce84458SLorenzo Bianconi 	struct nlattr *tb[NUM_MT76_TM_ATTRS];
152bce84458SLorenzo Bianconi 	struct mt76_phy *mphy = hw->priv;
153*78562b2cSLorenzo Bianconi 	struct mt792x_phy *phy = mphy->priv;
154bce84458SLorenzo Bianconi 	int err;
155bce84458SLorenzo Bianconi 
156bce84458SLorenzo Bianconi 	if (!test_bit(MT76_STATE_RUNNING, &mphy->state) ||
157bce84458SLorenzo Bianconi 	    !(hw->conf.flags & IEEE80211_CONF_MONITOR) ||
158bce84458SLorenzo Bianconi 	    !mt76_testmode_enabled(mphy))
159bce84458SLorenzo Bianconi 		return -ENOTCONN;
160bce84458SLorenzo Bianconi 
161bce84458SLorenzo Bianconi 	if (cb->args[2]++ > 0)
162bce84458SLorenzo Bianconi 		return -ENOENT;
163bce84458SLorenzo Bianconi 
164bce84458SLorenzo Bianconi 	err = nla_parse_deprecated(tb, MT76_TM_ATTR_MAX, data, len,
165bce84458SLorenzo Bianconi 				   mt76_tm_policy, NULL);
166bce84458SLorenzo Bianconi 	if (err)
167bce84458SLorenzo Bianconi 		return err;
168bce84458SLorenzo Bianconi 
169bce84458SLorenzo Bianconi 	if (tb[MT76_TM_ATTR_DRV_DATA]) {
170bce84458SLorenzo Bianconi 		struct nlattr *drv_tb[NUM_MT7921_TM_ATTRS], *data;
171bce84458SLorenzo Bianconi 		int ret;
172bce84458SLorenzo Bianconi 
173bce84458SLorenzo Bianconi 		data = tb[MT76_TM_ATTR_DRV_DATA];
174bce84458SLorenzo Bianconi 		ret = nla_parse_nested_deprecated(drv_tb,
175bce84458SLorenzo Bianconi 						  MT7921_TM_ATTR_MAX,
176bce84458SLorenzo Bianconi 						  data, mt7921_tm_policy,
177bce84458SLorenzo Bianconi 						  NULL);
178bce84458SLorenzo Bianconi 		if (ret)
179bce84458SLorenzo Bianconi 			return ret;
180bce84458SLorenzo Bianconi 
181bce84458SLorenzo Bianconi 		data = drv_tb[MT7921_TM_ATTR_QUERY];
182bce84458SLorenzo Bianconi 		if (data) {
183bce84458SLorenzo Bianconi 			struct mt7921_tm_evt evt_resp;
184bce84458SLorenzo Bianconi 
185bce84458SLorenzo Bianconi 			err = mt7921_tm_query(phy->dev, nla_data(data),
186bce84458SLorenzo Bianconi 					      &evt_resp);
187bce84458SLorenzo Bianconi 			if (err)
188bce84458SLorenzo Bianconi 				return err;
189bce84458SLorenzo Bianconi 
190bce84458SLorenzo Bianconi 			return nla_put(msg, MT7921_TM_ATTR_RSP,
191bce84458SLorenzo Bianconi 				       sizeof(evt_resp), &evt_resp);
192bce84458SLorenzo Bianconi 		}
193bce84458SLorenzo Bianconi 	}
194bce84458SLorenzo Bianconi 
195bce84458SLorenzo Bianconi 	return -EINVAL;
196bce84458SLorenzo Bianconi }
197