diff options
Diffstat (limited to 'drivers/net/wireless/mediatek/mt76/mt7615/mcu.c')
| -rw-r--r-- | drivers/net/wireless/mediatek/mt76/mt7615/mcu.c | 299 | 
1 files changed, 210 insertions, 89 deletions
| diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c index 631596fc2f36..aa42af9ebfd6 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c @@ -175,8 +175,8 @@ int mt7615_mcu_parse_response(struct mt76_dev *mdev, int cmd,  	int ret = 0;  	if (!skb) { -		dev_err(mdev->dev, "Message %ld (seq %d) timeout\n", -			cmd & MCU_CMD_MASK, seq); +		dev_err(mdev->dev, "Message %08x (seq %d) timeout\n", +			cmd, seq);  		return -ETIMEDOUT;  	} @@ -274,7 +274,7 @@ int mt7615_rf_wr(struct mt7615_dev *dev, u32 wf, u32 reg, u32 val)  				 sizeof(req), false);  } -static void mt7622_trigger_hif_int(struct mt7615_dev *dev, bool en) +void mt7622_trigger_hif_int(struct mt7615_dev *dev, bool en)  {  	if (!is_mt7622(&dev->mt76))  		return; @@ -283,20 +283,30 @@ static void mt7622_trigger_hif_int(struct mt7615_dev *dev, bool en)  			   MT_INFRACFG_MISC_AP2CONN_WAKE,  			   !en * MT_INFRACFG_MISC_AP2CONN_WAKE);  } +EXPORT_SYMBOL_GPL(mt7622_trigger_hif_int);  static int mt7615_mcu_drv_pmctrl(struct mt7615_dev *dev)  {  	struct mt76_phy *mphy = &dev->mt76.phy; +	struct mt76_connac_pm *pm = &dev->pm;  	struct mt76_dev *mdev = &dev->mt76;  	u32 addr;  	int err; -	addr = is_mt7663(mdev) ? MT_PCIE_DOORBELL_PUSH : MT_CFG_LPCR_HOST; +	if (is_mt7663(mdev)) { +		/* Clear firmware own via N9 eint */ +		mt76_wr(dev, MT_PCIE_DOORBELL_PUSH, MT_CFG_LPCR_HOST_DRV_OWN); +		mt76_poll(dev, MT_CONN_ON_MISC, MT_CFG_LPCR_HOST_FW_OWN, 0, 3000); + +		addr = MT_CONN_HIF_ON_LPCTL; +	} else { +		addr = MT_CFG_LPCR_HOST; +	} +  	mt76_wr(dev, addr, MT_CFG_LPCR_HOST_DRV_OWN);  	mt7622_trigger_hif_int(dev, true); -	addr = is_mt7663(mdev) ? MT_CONN_HIF_ON_LPCTL : MT_CFG_LPCR_HOST;  	err = !mt76_poll_msec(dev, addr, MT_CFG_LPCR_HOST_FW_OWN, 0, 3000);  	mt7622_trigger_hif_int(dev, false); @@ -308,15 +318,22 @@ static int mt7615_mcu_drv_pmctrl(struct mt7615_dev *dev)  	clear_bit(MT76_STATE_PM, &mphy->state); +	pm->stats.last_wake_event = jiffies; +	pm->stats.doze_time += pm->stats.last_wake_event - +			       pm->stats.last_doze_event; +  	return 0;  }  static int mt7615_mcu_lp_drv_pmctrl(struct mt7615_dev *dev)  {  	struct mt76_phy *mphy = &dev->mt76.phy; -	int i; +	struct mt76_connac_pm *pm = &dev->pm; +	int i, err = 0; + +	mutex_lock(&pm->mutex); -	if (!test_and_clear_bit(MT76_STATE_PM, &mphy->state)) +	if (!test_bit(MT76_STATE_PM, &mphy->state))  		goto out;  	for (i = 0; i < MT7615_DRV_OWN_RETRY_COUNT; i++) { @@ -328,24 +345,31 @@ static int mt7615_mcu_lp_drv_pmctrl(struct mt7615_dev *dev)  	if (i == MT7615_DRV_OWN_RETRY_COUNT) {  		dev_err(dev->mt76.dev, "driver own failed\n"); -		set_bit(MT76_STATE_PM, &mphy->state); -		return -EIO; +		err = -EIO; +		goto out;  	} +	clear_bit(MT76_STATE_PM, &mphy->state); +	pm->stats.last_wake_event = jiffies; +	pm->stats.doze_time += pm->stats.last_wake_event - +			       pm->stats.last_doze_event;  out: -	dev->pm.last_activity = jiffies; +	mutex_unlock(&pm->mutex); -	return 0; +	return err;  }  static int mt7615_mcu_fw_pmctrl(struct mt7615_dev *dev)  {  	struct mt76_phy *mphy = &dev->mt76.phy; +	struct mt76_connac_pm *pm = &dev->pm;  	int err = 0;  	u32 addr; -	if (test_and_set_bit(MT76_STATE_PM, &mphy->state)) -		return 0; +	mutex_lock(&pm->mutex); + +	if (mt76_connac_skip_fw_pmctrl(mphy, pm)) +		goto out;  	mt7622_trigger_hif_int(dev, true); @@ -362,6 +386,12 @@ static int mt7615_mcu_fw_pmctrl(struct mt7615_dev *dev)  	mt7622_trigger_hif_int(dev, false); +	pm->stats.last_doze_event = jiffies; +	pm->stats.awake_time += pm->stats.last_doze_event - +				pm->stats.last_wake_event; +out: +	mutex_unlock(&pm->mutex); +  	return err;  } @@ -373,6 +403,23 @@ mt7615_mcu_csa_finish(void *priv, u8 *mac, struct ieee80211_vif *vif)  }  static void +mt7615_mcu_rx_csa_notify(struct mt7615_dev *dev, struct sk_buff *skb) +{ +	struct mt7615_phy *ext_phy = mt7615_ext_phy(dev); +	struct mt76_phy *mphy = &dev->mt76.phy; +	struct mt7615_mcu_csa_notify *c; + +	c = (struct mt7615_mcu_csa_notify *)skb->data; + +	if (ext_phy && ext_phy->omac_mask & BIT_ULL(c->omac_idx)) +		mphy = dev->mt76.phy2; + +	ieee80211_iterate_active_interfaces_atomic(mphy->hw, +			IEEE80211_IFACE_ITER_RESUME_ALL, +			mt7615_mcu_csa_finish, mphy->hw); +} + +static void  mt7615_mcu_rx_radar_detected(struct mt7615_dev *dev, struct sk_buff *skb)  {  	struct mt76_phy *mphy = &dev->mt76.phy; @@ -380,7 +427,7 @@ mt7615_mcu_rx_radar_detected(struct mt7615_dev *dev, struct sk_buff *skb)  	r = (struct mt7615_mcu_rdd_report *)skb->data; -	if (r->idx && dev->mt76.phy2) +	if (r->band_idx && dev->mt76.phy2)  		mphy = dev->mt76.phy2;  	ieee80211_radar_detected(mphy->hw); @@ -406,7 +453,8 @@ mt7615_mcu_rx_log_message(struct mt7615_dev *dev, struct sk_buff *skb)  		break;  	} -	wiphy_info(mt76_hw(dev)->wiphy, "%s: %s", type, data); +	wiphy_info(mt76_hw(dev)->wiphy, "%s: %.*s", type, +		   (int)(skb->len - sizeof(*rxd)), data);  }  static void @@ -419,9 +467,7 @@ mt7615_mcu_rx_ext_event(struct mt7615_dev *dev, struct sk_buff *skb)  		mt7615_mcu_rx_radar_detected(dev, skb);  		break;  	case MCU_EXT_EVENT_CSA_NOTIFY: -		ieee80211_iterate_active_interfaces_atomic(dev->mt76.hw, -				IEEE80211_IFACE_ITER_RESUME_ALL, -				mt7615_mcu_csa_finish, dev); +		mt7615_mcu_rx_csa_notify(dev, skb);  		break;  	case MCU_EXT_EVENT_FW_LOG_2_HOST:  		mt7615_mcu_rx_log_message(dev, skb); @@ -685,6 +731,9 @@ mt7615_mcu_add_beacon_offload(struct mt7615_dev *dev,  	};  	struct sk_buff *skb; +	if (!enable) +		goto out; +  	skb = ieee80211_beacon_get_template(hw, vif, &offs);  	if (!skb)  		return -EINVAL; @@ -714,6 +763,7 @@ mt7615_mcu_add_beacon_offload(struct mt7615_dev *dev,  	}  	dev_kfree_skb(skb); +out:  	return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_BCN_OFFLOAD, &req,  				 sizeof(req), true);  } @@ -973,7 +1023,7 @@ mt7615_mcu_wtbl_sta_add(struct mt7615_phy *phy, struct ieee80211_vif *vif,  	mt76_connac_mcu_sta_basic_tlv(sskb, vif, sta, enable);  	if (enable && sta) -		mt76_connac_mcu_sta_tlv(phy->mt76, sskb, sta, vif); +		mt76_connac_mcu_sta_tlv(phy->mt76, sskb, sta, vif, 0);  	wtbl_hdr = mt76_connac_mcu_alloc_wtbl_req(&dev->mt76, &msta->wcid,  						  WTBL_RESET_AND_SET, NULL, @@ -987,6 +1037,8 @@ mt7615_mcu_wtbl_sta_add(struct mt7615_phy *phy, struct ieee80211_vif *vif,  		if (sta)  			mt76_connac_mcu_wtbl_ht_tlv(&dev->mt76, wskb, sta,  						    NULL, wtbl_hdr); +		mt76_connac_mcu_wtbl_hdr_trans_tlv(wskb, &msta->wcid, NULL, +						   wtbl_hdr);  	}  	cmd = enable ? MCU_EXT_CMD_WTBL_UPDATE : MCU_EXT_CMD_STA_REC_UPDATE; @@ -1040,6 +1092,9 @@ mt7615_mcu_sta_ba(struct mt7615_dev *dev,  	wtbl_hdr = mt76_connac_mcu_alloc_wtbl_req(&dev->mt76, &msta->wcid,  						  WTBL_SET, sta_wtbl, &skb); +	if (IS_ERR(wtbl_hdr)) +		return PTR_ERR(wtbl_hdr); +  	mt76_connac_mcu_wtbl_ba_tlv(&dev->mt76, skb, params, enable, tx,  				    sta_wtbl, wtbl_hdr); @@ -1068,10 +1123,15 @@ __mt7615_mcu_add_sta(struct mt76_phy *phy, struct ieee80211_vif *vif,  		     struct ieee80211_sta *sta, bool enable, int cmd)  {  	struct mt7615_vif *mvif = (struct mt7615_vif *)vif->drv_priv; -	struct mt76_wcid *wcid; +	struct mt76_sta_cmd_info info = { +		.sta = sta, +		.vif = vif, +		.enable = enable, +		.cmd = cmd, +	}; -	wcid = sta ? (struct mt76_wcid *)sta->drv_priv : &mvif->sta.wcid; -	return mt76_connac_mcu_add_sta_cmd(phy, vif, sta, wcid, enable, cmd); +	info.wcid = sta ? (struct mt76_wcid *)sta->drv_priv : &mvif->sta.wcid; +	return mt76_connac_mcu_add_sta_cmd(phy, &info);  }  static int @@ -1094,6 +1154,25 @@ static const struct mt7615_mcu_ops sta_update_ops = {  	.set_fw_ctrl = mt7615_mcu_fw_pmctrl,  }; +int mt7615_mcu_sta_update_hdr_trans(struct mt7615_dev *dev, +				    struct ieee80211_vif *vif, +				    struct ieee80211_sta *sta) +{ +	struct mt7615_sta *msta = (struct mt7615_sta *)sta->drv_priv; +	struct wtbl_req_hdr *wtbl_hdr; +	struct sk_buff *skb = NULL; + +	wtbl_hdr = mt76_connac_mcu_alloc_wtbl_req(&dev->mt76, &msta->wcid, +						  WTBL_SET, NULL, &skb); +	if (IS_ERR(wtbl_hdr)) +		return PTR_ERR(wtbl_hdr); + +	mt76_connac_mcu_wtbl_hdr_trans_tlv(skb, &msta->wcid, NULL, wtbl_hdr); + +	return mt76_mcu_skb_send_msg(&dev->mt76, skb, MCU_EXT_CMD_WTBL_UPDATE, +				     true); +} +  static int  mt7615_mcu_uni_ctrl_pm_state(struct mt7615_dev *dev, int band, int state)  { @@ -1120,8 +1199,8 @@ mt7615_mcu_uni_add_beacon_offload(struct mt7615_dev *dev,  			__le16 tim_ie_pos;  			__le16 csa_ie_pos;  			__le16 bcc_ie_pos; -			/* 0: enable beacon offload -			 * 1: disable beacon offload +			/* 0: disable beacon offload +			 * 1: enable beacon offload  			 * 2: update probe respond offload  			 */  			u8 enable; @@ -1144,6 +1223,9 @@ mt7615_mcu_uni_add_beacon_offload(struct mt7615_dev *dev,  	};  	struct sk_buff *skb; +	if (!enable) +		goto out; +  	skb = ieee80211_beacon_get_template(mt76_hw(dev), vif, &offs);  	if (!skb)  		return -EINVAL; @@ -1168,6 +1250,7 @@ mt7615_mcu_uni_add_beacon_offload(struct mt7615_dev *dev,  	}  	dev_kfree_skb(skb); +out:  	return mt76_mcu_send_msg(&dev->mt76, MCU_UNI_CMD_BSS_INFO_UPDATE,  				 &req, sizeof(req), true);  } @@ -1279,25 +1362,26 @@ static int mt7615_load_patch(struct mt7615_dev *dev, u32 addr, const char *name)  	const struct firmware *fw = NULL;  	int len, ret, sem; +	ret = firmware_request_nowarn(&fw, name, dev->mt76.dev); +	if (ret) +		return ret; + +	if (!fw || !fw->data || fw->size < sizeof(*hdr)) { +		dev_err(dev->mt76.dev, "Invalid firmware\n"); +		ret = -EINVAL; +		goto release_fw; +	} +  	sem = mt76_connac_mcu_patch_sem_ctrl(&dev->mt76, true);  	switch (sem) {  	case PATCH_IS_DL: -		return 0; +		goto release_fw;  	case PATCH_NOT_DL_SEM_SUCCESS:  		break;  	default:  		dev_err(dev->mt76.dev, "Failed to get patch semaphore\n"); -		return -EAGAIN; -	} - -	ret = firmware_request_nowarn(&fw, name, dev->mt76.dev); -	if (ret) -		goto out; - -	if (!fw || !fw->data || fw->size < sizeof(*hdr)) { -		dev_err(dev->mt76.dev, "Invalid firmware\n"); -		ret = -EINVAL; -		goto out; +		ret = -EAGAIN; +		goto release_fw;  	}  	hdr = (const struct mt7615_patch_hdr *)(fw->data); @@ -1326,8 +1410,6 @@ static int mt7615_load_patch(struct mt7615_dev *dev, u32 addr, const char *name)  		dev_err(dev->mt76.dev, "Failed to start patch\n");  out: -	release_firmware(fw); -  	sem = mt76_connac_mcu_patch_sem_ctrl(&dev->mt76, false);  	switch (sem) {  	case PATCH_REL_SEM_SUCCESS: @@ -1338,6 +1420,9 @@ out:  		break;  	} +release_fw: +	release_firmware(fw); +  	return ret;  } @@ -1427,8 +1512,7 @@ static int mt7615_load_n9(struct mt7615_dev *dev, const char *name)  		 sizeof(dev->mt76.hw->wiphy->fw_version),  		 "%.10s-%.15s", hdr->fw_ver, hdr->build_date); -	if (!is_mt7615(&dev->mt76) && -	    !strncmp(hdr->fw_ver, "2.0", sizeof(hdr->fw_ver))) { +	if (!is_mt7615(&dev->mt76)) {  		dev->fw_ver = MT7615_FIRMWARE_V2;  		dev->mcu_ops = &sta_update_ops;  	} else { @@ -2084,16 +2168,80 @@ static void mt7615_mcu_set_txpower_sku(struct mt7615_phy *phy, u8 *sku)  {  	struct mt76_phy *mphy = phy->mt76;  	struct ieee80211_hw *hw = mphy->hw; +	struct mt76_power_limits limits; +	s8 *limits_array = (s8 *)&limits;  	int n_chains = hweight8(mphy->antenna_mask);  	int tx_power;  	int i; +	static const u8 sku_mapping[] = { +#define SKU_FIELD(_type, _field) \ +		[MT_SKU_##_type] = offsetof(struct mt76_power_limits, _field) +		SKU_FIELD(CCK_1_2, cck[0]), +		SKU_FIELD(CCK_55_11, cck[2]), +		SKU_FIELD(OFDM_6_9, ofdm[0]), +		SKU_FIELD(OFDM_12_18, ofdm[2]), +		SKU_FIELD(OFDM_24_36, ofdm[4]), +		SKU_FIELD(OFDM_48, ofdm[6]), +		SKU_FIELD(OFDM_54, ofdm[7]), +		SKU_FIELD(HT20_0_8, mcs[0][0]), +		SKU_FIELD(HT20_32, ofdm[0]), +		SKU_FIELD(HT20_1_2_9_10, mcs[0][1]), +		SKU_FIELD(HT20_3_4_11_12, mcs[0][3]), +		SKU_FIELD(HT20_5_13, mcs[0][5]), +		SKU_FIELD(HT20_6_14, mcs[0][6]), +		SKU_FIELD(HT20_7_15, mcs[0][7]), +		SKU_FIELD(HT40_0_8, mcs[1][0]), +		SKU_FIELD(HT40_32, ofdm[0]), +		SKU_FIELD(HT40_1_2_9_10, mcs[1][1]), +		SKU_FIELD(HT40_3_4_11_12, mcs[1][3]), +		SKU_FIELD(HT40_5_13, mcs[1][5]), +		SKU_FIELD(HT40_6_14, mcs[1][6]), +		SKU_FIELD(HT40_7_15, mcs[1][7]), +		SKU_FIELD(VHT20_0, mcs[0][0]), +		SKU_FIELD(VHT20_1_2, mcs[0][1]), +		SKU_FIELD(VHT20_3_4, mcs[0][3]), +		SKU_FIELD(VHT20_5_6, mcs[0][5]), +		SKU_FIELD(VHT20_7, mcs[0][7]), +		SKU_FIELD(VHT20_8, mcs[0][8]), +		SKU_FIELD(VHT20_9, mcs[0][9]), +		SKU_FIELD(VHT40_0, mcs[1][0]), +		SKU_FIELD(VHT40_1_2, mcs[1][1]), +		SKU_FIELD(VHT40_3_4, mcs[1][3]), +		SKU_FIELD(VHT40_5_6, mcs[1][5]), +		SKU_FIELD(VHT40_7, mcs[1][7]), +		SKU_FIELD(VHT40_8, mcs[1][8]), +		SKU_FIELD(VHT40_9, mcs[1][9]), +		SKU_FIELD(VHT80_0, mcs[2][0]), +		SKU_FIELD(VHT80_1_2, mcs[2][1]), +		SKU_FIELD(VHT80_3_4, mcs[2][3]), +		SKU_FIELD(VHT80_5_6, mcs[2][5]), +		SKU_FIELD(VHT80_7, mcs[2][7]), +		SKU_FIELD(VHT80_8, mcs[2][8]), +		SKU_FIELD(VHT80_9, mcs[2][9]), +		SKU_FIELD(VHT160_0, mcs[3][0]), +		SKU_FIELD(VHT160_1_2, mcs[3][1]), +		SKU_FIELD(VHT160_3_4, mcs[3][3]), +		SKU_FIELD(VHT160_5_6, mcs[3][5]), +		SKU_FIELD(VHT160_7, mcs[3][7]), +		SKU_FIELD(VHT160_8, mcs[3][8]), +		SKU_FIELD(VHT160_9, mcs[3][9]), +#undef SKU_FIELD +	};  	tx_power = hw->conf.power_level * 2 -  		   mt76_tx_power_nss_delta(n_chains); + +	tx_power = mt76_get_rate_power_limits(mphy, mphy->chandef.chan, +					      &limits, tx_power);  	mphy->txpower_cur = tx_power; +	if (is_mt7663(mphy->dev)) { +		memset(sku, tx_power, MT_SKU_4SS_DELTA + 1); +		return; +	} +  	for (i = 0; i < MT_SKU_1SS_DELTA; i++) -		sku[i] = tx_power; +		sku[i] = limits_array[sku_mapping[i]];  	for (i = 0; i < 4; i++) {  		int delta = 0; @@ -2155,7 +2303,7 @@ int mt7615_mcu_set_chan_info(struct mt7615_phy *phy, int cmd)  		.center_chan2 = ieee80211_frequency_to_channel(freq2),  	}; -	if (dev->mt76.hw->conf.flags & IEEE80211_CONF_OFFCHANNEL) +	if (phy->mt76->hw->conf.flags & IEEE80211_CONF_OFFCHANNEL)  		req.switch_reason = CH_SWITCH_SCAN_BYPASS_DPD;  	else if ((chandef->chan->flags & IEEE80211_CHAN_RADAR) &&  		 chandef->chan->dfs_state != NL80211_DFS_AVAILABLE) @@ -2497,6 +2645,26 @@ out:  	return ret;  } +int mt7615_mcu_set_rx_hdr_trans_blacklist(struct mt7615_dev *dev) +{ +	struct { +		u8 operation; +		u8 count; +		u8 _rsv[2]; +		u8 index; +		u8 enable; +		__le16 etype; +	} req = { +		.operation = 1, +		.count = 1, +		.enable = 1, +		.etype = cpu_to_le16(ETH_P_PAE), +	}; + +	return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_RX_HDR_TRANS, +				 &req, sizeof(req), false); +} +  int mt7615_mcu_set_bss_pm(struct mt7615_dev *dev, struct ieee80211_vif *vif,  			  bool enable)  { @@ -2557,53 +2725,6 @@ int mt7615_mcu_set_roc(struct mt7615_phy *phy, struct ieee80211_vif *vif,  				 sizeof(req), false);  } -int mt7615_mcu_update_arp_filter(struct ieee80211_hw *hw, -				 struct ieee80211_vif *vif, -				 struct ieee80211_bss_conf *info) -{ -	struct mt7615_vif *mvif = (struct mt7615_vif *)vif->drv_priv; -	struct mt7615_dev *dev = mt7615_hw_dev(hw); -	struct sk_buff *skb; -	int i, len = min_t(int, info->arp_addr_cnt, -			   IEEE80211_BSS_ARP_ADDR_LIST_LEN); -	struct { -		struct { -			u8 bss_idx; -			u8 pad[3]; -		} __packed hdr; -		struct mt76_connac_arpns_tlv arp; -	} req_hdr = { -		.hdr = { -			.bss_idx = mvif->mt76.idx, -		}, -		.arp = { -			.tag = cpu_to_le16(UNI_OFFLOAD_OFFLOAD_ARP), -			.len = cpu_to_le16(sizeof(struct mt76_connac_arpns_tlv)), -			.ips_num = len, -			.mode = 2,  /* update */ -			.option = 1, -		}, -	}; - -	if (!mt7615_firmware_offload(dev)) -		return 0; - -	skb = mt76_mcu_msg_alloc(&dev->mt76, NULL, -				 sizeof(req_hdr) + len * sizeof(__be32)); -	if (!skb) -		return -ENOMEM; - -	skb_put_data(skb, &req_hdr, sizeof(req_hdr)); -	for (i = 0; i < len; i++) { -		u8 *addr = (u8 *)skb_put(skb, sizeof(__be32)); - -		memcpy(addr, &info->arp_addr_list[i], sizeof(__be32)); -	} - -	return mt76_mcu_skb_send_msg(&dev->mt76, skb, MCU_UNI_CMD_OFFLOAD, -				     true); -} -  int mt7615_mcu_set_p2p_oppps(struct ieee80211_hw *hw,  			     struct ieee80211_vif *vif)  { | 
