struct cfg80211_chan_def *chandef)
{
struct mt7996_dev *dev = mt7996_hw_dev(hw);
+ struct mt7996_phy *phy = mt7996_band_phy(dev, chandef->chan->band);
+ struct ieee80211_bss_conf *link_conf;
+ unsigned int link_id;
mutex_lock(&dev->mt76.mutex);
- mt7996_mcu_add_beacon(hw, vif, &vif->bss_conf, vif->bss_conf.enable_beacon);
+
+ for_each_vif_active_link(vif, link_conf, link_id) {
+ struct mt7996_vif_link *link =
+ mt7996_vif_link(dev, vif, link_id);
+
+ if (!link || link->phy != phy)
+ continue;
+
+ /* Reset beacon when channel switch triggered during CAC to let
+ * FW correctly perform CSA countdown
+ */
+ if (!cfg80211_reg_can_beacon(hw->wiphy, &phy->mt76->chandef,
+ vif->type))
+ mt7996_mcu_add_beacon(hw, vif, link_conf, false);
+
+ mt7996_mcu_add_beacon(hw, vif, link_conf, true);
+ break;
+ }
+
mutex_unlock(&dev->mt76.mutex);
}
sizeof(req), false);
}
+struct mt7996_mcu_countdown_data {
+ struct mt76_phy *mphy;
+ u8 omac_idx;
+};
+
static void
mt7996_mcu_csa_finish(void *priv, u8 *mac, struct ieee80211_vif *vif)
{
- if (!vif->bss_conf.csa_active || vif->type == NL80211_IFTYPE_STATION)
+ struct mt7996_mcu_countdown_data *cdata = (void *)priv;
+ struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv;
+ struct ieee80211_bss_conf *link_conf = NULL;
+ unsigned long valid_links = vif->valid_links ?: BIT(0);
+ unsigned int link_id;
+
+ if (vif->type == NL80211_IFTYPE_STATION)
+ return;
+
+ for_each_set_bit(link_id, &valid_links, IEEE80211_MLD_MAX_NUM_LINKS) {
+ struct mt76_vif_link *mlink =
+ rcu_dereference(mvif->mt76.link[link_id]);
+
+ if (mlink && mlink->band_idx == cdata->mphy->band_idx &&
+ mlink->omac_idx == cdata->omac_idx) {
+ link_conf = rcu_dereference(vif->link_conf[link_id]);
+ break;
+ }
+ }
+
+ if (!link_conf || !link_conf->csa_active)
return;
- ieee80211_csa_finish(vif, 0);
+ ieee80211_csa_finish(vif, link_conf->link_id);
+}
+
+static void
+mt7996_mcu_cca_finish(void *priv, u8 *mac, struct ieee80211_vif *vif)
+{
+ struct mt7996_mcu_countdown_data *cdata = (void *)priv;
+ struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv;
+ struct ieee80211_bss_conf *link_conf = NULL;
+ unsigned long valid_links = vif->valid_links ?: BIT(0);
+ unsigned int link_id;
+
+ if (vif->type == NL80211_IFTYPE_STATION)
+ return;
+
+ for_each_set_bit(link_id, &valid_links, IEEE80211_MLD_MAX_NUM_LINKS) {
+ struct mt76_vif_link *mlink =
+ rcu_dereference(mvif->mt76.link[link_id]);
+
+ if (mlink && mlink->band_idx == cdata->mphy->band_idx &&
+ mlink->omac_idx == cdata->omac_idx) {
+ link_conf = rcu_dereference(vif->link_conf[link_id]);
+ break;
+ }
+ }
+
+ if (!link_conf || !link_conf->color_change_active)
+ return;
+
+ ieee80211_color_change_finish(vif, link_conf->link_id);
+}
+
+static void
+mt7996_mcu_ie_countdown(struct mt7996_dev *dev, struct sk_buff *skb)
+{
+#define UNI_EVENT_IE_COUNTDOWN_CSA 0
+#define UNI_EVENT_IE_COUNTDOWN_BCC 1
+ struct header {
+ u8 band;
+ u8 rsv[3];
+ };
+ struct mt7996_mcu_rxd *rxd = (struct mt7996_mcu_rxd *)skb->data;
+ const char *data = (char *)&rxd[1], *tail;
+ struct header *hdr = (struct header *)data;
+ struct tlv *tlv = (struct tlv *)(data + 4);
+ struct mt7996_mcu_countdown_notify *event;
+ struct mt7996_mcu_countdown_data cdata;
+
+ if (hdr->band >= ARRAY_SIZE(dev->mt76.phys))
+ return;
+
+ cdata.mphy = dev->mt76.phys[hdr->band];
+ if (!cdata.mphy)
+ return;
+
+ tail = skb->data + skb->len;
+ data += sizeof(*hdr);
+ while (data + sizeof(*tlv) < tail && le16_to_cpu(tlv->len)) {
+ event = (struct mt7996_mcu_countdown_notify *)tlv->data;
+
+ cdata.omac_idx = event->omac_idx;
+
+ switch (le16_to_cpu(tlv->tag)) {
+ case UNI_EVENT_IE_COUNTDOWN_CSA:
+ ieee80211_iterate_active_interfaces_atomic(mt76_hw(dev),
+ IEEE80211_IFACE_ITER_RESUME_ALL,
+ mt7996_mcu_csa_finish, &cdata);
+ break;
+ case UNI_EVENT_IE_COUNTDOWN_BCC:
+ ieee80211_iterate_active_interfaces_atomic(mt76_hw(dev),
+ IEEE80211_IFACE_ITER_RESUME_ALL,
+ mt7996_mcu_cca_finish, &cdata);
+ break;
+ default:
+ break;
+ }
+
+ data += le16_to_cpu(tlv->len);
+ tlv = (struct tlv *)data;
+ }
}
static void
wiphy_info(mt76_hw(dev)->wiphy, "%s: %.*s", type, len, data);
}
-static void
-mt7996_mcu_cca_finish(void *priv, u8 *mac, struct ieee80211_vif *vif)
-{
- if (!vif->bss_conf.color_change_active || vif->type == NL80211_IFTYPE_STATION)
- return;
-
- ieee80211_color_change_finish(vif, 0);
-}
-
-static void
-mt7996_mcu_ie_countdown(struct mt7996_dev *dev, struct sk_buff *skb)
-{
-#define UNI_EVENT_IE_COUNTDOWN_CSA 0
-#define UNI_EVENT_IE_COUNTDOWN_BCC 1
- struct header {
- u8 band;
- u8 rsv[3];
- };
- struct mt76_phy *mphy = &dev->mt76.phy;
- struct mt7996_mcu_rxd *rxd = (struct mt7996_mcu_rxd *)skb->data;
- const char *data = (char *)&rxd[1], *tail;
- struct header *hdr = (struct header *)data;
- struct tlv *tlv = (struct tlv *)(data + 4);
-
- if (hdr->band >= ARRAY_SIZE(dev->mt76.phys))
- return;
-
- if (hdr->band && dev->mt76.phys[hdr->band])
- mphy = dev->mt76.phys[hdr->band];
-
- tail = skb->data + skb->len;
- data += sizeof(struct header);
- while (data + sizeof(struct tlv) < tail && le16_to_cpu(tlv->len)) {
- switch (le16_to_cpu(tlv->tag)) {
- case UNI_EVENT_IE_COUNTDOWN_CSA:
- ieee80211_iterate_active_interfaces_atomic(mphy->hw,
- IEEE80211_IFACE_ITER_RESUME_ALL,
- mt7996_mcu_csa_finish, mphy->hw);
- break;
- case UNI_EVENT_IE_COUNTDOWN_BCC:
- ieee80211_iterate_active_interfaces_atomic(mphy->hw,
- IEEE80211_IFACE_ITER_RESUME_ALL,
- mt7996_mcu_cca_finish, mphy->hw);
- break;
- }
-
- data += le16_to_cpu(tlv->len);
- tlv = (struct tlv *)data;
- }
-}
-
static int
mt7996_mcu_update_tx_gi(struct rate_info *rate, struct all_sta_trx_rate *mcu_rate)
{