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