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 34*975e122dSLorenzo 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); 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 85*975e122dSLorenzo 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 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 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