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