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
mt7921_tm_set(struct mt792x_dev * dev,struct mt7921_tm_cmd * req)34975e122dSLorenzo Bianconi mt7921_tm_set(struct mt792x_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);
60*5c041325SLorenzo Bianconi __mt792x_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
mt7921_tm_query(struct mt792x_dev * dev,struct mt7921_tm_cmd * req,struct mt7921_tm_evt * evt_resp)85975e122dSLorenzo Bianconi mt7921_tm_query(struct mt792x_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
mt7921_testmode_cmd(struct ieee80211_hw * hw,struct ieee80211_vif * vif,void * data,int len)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;
11678562b2cSLorenzo 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
mt7921_testmode_dump(struct ieee80211_hw * hw,struct sk_buff * msg,struct netlink_callback * cb,void * data,int len)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;
15378562b2cSLorenzo 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