diff --git a/mac80211.c b/mac80211.c index 5fcb2deb..85f8d324 100644 --- a/mac80211.c +++ b/mac80211.c @@ -276,6 +276,7 @@ int mt76_register_device(struct mt76_dev *dev, bool vht, ieee80211_hw_set(hw, TX_AMSDU); ieee80211_hw_set(hw, TX_FRAG_LIST); ieee80211_hw_set(hw, MFP_CAPABLE); + ieee80211_hw_set(hw, AP_LINK_PS); wiphy->flags |= WIPHY_FLAG_IBSS_RSN; @@ -470,6 +471,53 @@ mt76_check_ccmp_pn(struct sk_buff *skb) return 0; } +static void +mt76_check_ps(struct mt76_dev *dev, struct sk_buff *skb) +{ + struct mt76_rx_status *status = (struct mt76_rx_status *) skb->cb; + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; + struct ieee80211_sta *sta; + struct mt76_wcid *wcid = status->wcid; + bool ps; + + if (!wcid || !wcid->sta) + return; + + sta = container_of((void *) wcid, struct ieee80211_sta, drv_priv); + + if (!test_bit(MT_WCID_FLAG_CHECK_PS, &wcid->flags)) + return; + + if (ieee80211_is_pspoll(hdr->frame_control)) { + ieee80211_sta_pspoll(sta); + return; + } + + if (ieee80211_has_morefrags(hdr->frame_control) || + !(ieee80211_is_mgmt(hdr->frame_control) || + ieee80211_is_data(hdr->frame_control))) + return; + + ps = ieee80211_has_pm(hdr->frame_control); + + if (ps && (ieee80211_is_data_qos(hdr->frame_control) || + ieee80211_is_qos_nullfunc(hdr->frame_control))) + ieee80211_sta_uapsd_trigger(sta, status->tid); + + if (!!test_bit(MT_WCID_FLAG_PS, &wcid->flags) == ps) + return; + + if (ps) { + set_bit(MT_WCID_FLAG_PS, &wcid->flags); + mt76_stop_tx_queues(dev, sta, true); + } else { + clear_bit(MT_WCID_FLAG_PS, &wcid->flags); + } + + ieee80211_sta_ps_transition(sta, ps); + dev->drv->sta_ps(dev, sta, ps); +} + void mt76_rx_complete(struct mt76_dev *dev, struct sk_buff_head *frames, int queue) { @@ -498,8 +546,10 @@ void mt76_rx_poll_complete(struct mt76_dev *dev, enum mt76_rxq_id q) __skb_queue_head_init(&frames); - while ((skb = __skb_dequeue(&dev->rx_skb[q])) != NULL) + while ((skb = __skb_dequeue(&dev->rx_skb[q])) != NULL) { + mt76_check_ps(dev, skb); mt76_rx_aggr_reorder(skb, &frames); + } mt76_rx_complete(dev, &frames, q); } diff --git a/mt76.h b/mt76.h index 129015c9..d2ce1509 100644 --- a/mt76.h +++ b/mt76.h @@ -121,11 +121,18 @@ struct mt76_queue_ops { void (*kick)(struct mt76_dev *dev, struct mt76_queue *q); }; +enum mt76_wcid_flags { + MT_WCID_FLAG_CHECK_PS, + MT_WCID_FLAG_PS, +}; + struct mt76_wcid { struct mt76_rx_tid __rcu *aggr[IEEE80211_NUM_TIDS]; struct work_struct aggr_work; + unsigned long flags; + u8 idx; u8 hw_key_idx; @@ -206,6 +213,9 @@ struct mt76_driver_ops { struct sk_buff *skb); void (*rx_poll_complete)(struct mt76_dev *dev, enum mt76_rxq_id q); + + void (*sta_ps)(struct mt76_dev *dev, struct ieee80211_sta *sta, + bool ps); }; struct mt76_channel_state { diff --git a/mt7603.h b/mt7603.h index 6476cc67..9b77adb4 100644 --- a/mt7603.h +++ b/mt7603.h @@ -256,6 +256,7 @@ void mt7603_tx_complete_skb(struct mt76_dev *mdev, struct mt76_queue *q, void mt7603_queue_rx_skb(struct mt76_dev *mdev, enum mt76_rxq_id q, struct sk_buff *skb); void mt7603_rx_poll_complete(struct mt76_dev *mdev, enum mt76_rxq_id q); +void mt7603_sta_ps(struct mt76_dev *mdev, struct ieee80211_sta *sta, bool ps); void mt7603_tbtt(struct mt7603_dev *dev); void mt7603_pre_tbtt_tasklet(unsigned long arg); diff --git a/mt7603_init.c b/mt7603_init.c index 2b9409b8..824967cc 100644 --- a/mt7603_init.c +++ b/mt7603_init.c @@ -27,6 +27,7 @@ struct mt7603_dev *mt7603_alloc_device(struct device *pdev) .tx_complete_skb = mt7603_tx_complete_skb, .rx_skb = mt7603_queue_rx_skb, .rx_poll_complete = mt7603_rx_poll_complete, + .sta_ps = mt7603_sta_ps, }; struct ieee80211_hw *hw; struct mt7603_dev *dev; diff --git a/mt7603_main.c b/mt7603_main.c index a88da1b5..d236918b 100644 --- a/mt7603_main.c +++ b/mt7603_main.c @@ -287,6 +287,9 @@ mt7603_sta_add(struct ieee80211_hw *hw, struct ieee80211_vif *vif, mt7603_wtbl_init(dev, idx, mvif->idx, sta->addr); mt7603_wtbl_update_cap(dev, sta); + if (vif->type == NL80211_IFTYPE_AP) + set_bit(MT_WCID_FLAG_CHECK_PS, &msta->wcid.flags); + rcu_assign_pointer(dev->wcid[idx], &msta->wcid); out: @@ -318,23 +321,14 @@ mt7603_sta_remove(struct ieee80211_hw *hw, struct ieee80211_vif *vif, return 0; } -static void -mt7603_sta_notify(struct ieee80211_hw *hw, struct ieee80211_vif *vif, - enum sta_notify_cmd cmd, struct ieee80211_sta *sta) +void +mt7603_sta_ps(struct mt76_dev *mdev, struct ieee80211_sta *sta, bool ps) { - struct mt7603_dev *dev = hw->priv; + struct mt7603_dev *dev = container_of(mdev, struct mt7603_dev, mt76); struct mt7603_sta *msta = (struct mt7603_sta *) sta->drv_priv; int idx = msta->wcid.idx; - switch (cmd) { - case STA_NOTIFY_SLEEP: - mt7603_wtbl_set_ps(dev, idx, true); - mt76_stop_tx_queues(&dev->mt76, sta, false); - break; - case STA_NOTIFY_AWAKE: - mt7603_wtbl_set_ps(dev, idx, false); - break; - } + mt7603_wtbl_set_ps(dev, idx, ps); } static int @@ -543,6 +537,12 @@ static void mt7603_tx(struct ieee80211_hw *hw, struct ieee80211_tx_control *cont mt76_tx(&dev->mt76, control->sta, wcid, skb); } +static int +mt7603_set_tim(struct ieee80211_hw *hw, struct ieee80211_sta *sta, bool set) +{ + return 0; +} + const struct ieee80211_ops mt7603_ops = { .tx = mt7603_tx, .start = mt7603_start, @@ -554,7 +554,6 @@ const struct ieee80211_ops mt7603_ops = { .bss_info_changed = mt7603_bss_info_changed, .sta_add = mt7603_sta_add, .sta_remove = mt7603_sta_remove, - .sta_notify = mt7603_sta_notify, .set_key = mt7603_set_key, .conf_tx = mt7603_conf_tx, .sw_scan_start = mt7603_sw_scan, @@ -566,6 +565,7 @@ const struct ieee80211_ops mt7603_ops = { .sta_rate_tbl_update = mt7603_sta_rate_tbl_update, .release_buffered_frames = mt76_release_buffered_frames, .set_coverage_class = mt7603_set_coverage_class, + .set_tim = mt7603_set_tim, }; MODULE_LICENSE("Dual BSD/GPL"); diff --git a/mt76x2.h b/mt76x2.h index 17df17af..e62131b8 100644 --- a/mt76x2.h +++ b/mt76x2.h @@ -218,6 +218,8 @@ void mt76x2_rx_poll_complete(struct mt76_dev *mdev, enum mt76_rxq_id q); void mt76x2_queue_rx_skb(struct mt76_dev *mdev, enum mt76_rxq_id q, struct sk_buff *skb); +void mt76x2_sta_ps(struct mt76_dev *dev, struct ieee80211_sta *sta, bool ps); + void mt76x2_update_channel(struct mt76_dev *mdev); s8 mt76x2_tx_get_max_txpwr_adj(struct mt76x2_dev *dev, diff --git a/mt76x2_init.c b/mt76x2_init.c index cb546a33..6c107d63 100644 --- a/mt76x2_init.c +++ b/mt76x2_init.c @@ -637,6 +637,7 @@ struct mt76x2_dev *mt76x2_alloc_device(struct device *pdev) .tx_complete_skb = mt76x2_tx_complete_skb, .rx_skb = mt76x2_queue_rx_skb, .rx_poll_complete = mt76x2_rx_poll_complete, + .sta_ps = mt76x2_sta_ps, }; struct ieee80211_hw *hw; struct mt76x2_dev *dev; diff --git a/mt76x2_main.c b/mt76x2_main.c index bf26284b..205043b4 100644 --- a/mt76x2_main.c +++ b/mt76x2_main.c @@ -282,6 +282,9 @@ mt76x2_sta_add(struct ieee80211_hw *hw, struct ieee80211_vif *vif, for (i = 0; i < ARRAY_SIZE(sta->txq); i++) mt76x2_txq_init(dev, sta->txq[i]); + if (vif->type == NL80211_IFTYPE_AP) + set_bit(MT_WCID_FLAG_CHECK_PS, &msta->wcid.flags); + rcu_assign_pointer(dev->wcid[idx], &msta->wcid); out: @@ -311,23 +314,14 @@ mt76x2_sta_remove(struct ieee80211_hw *hw, struct ieee80211_vif *vif, return 0; } -static void -mt76x2_sta_notify(struct ieee80211_hw *hw, struct ieee80211_vif *vif, - enum sta_notify_cmd cmd, struct ieee80211_sta *sta) +void +mt76x2_sta_ps(struct mt76_dev *mdev, struct ieee80211_sta *sta, bool ps) { struct mt76x2_sta *msta = (struct mt76x2_sta *) sta->drv_priv; - struct mt76x2_dev *dev = hw->priv; + struct mt76x2_dev *dev = container_of(mdev, struct mt76x2_dev, mt76); int idx = msta->wcid.idx; - switch (cmd) { - case STA_NOTIFY_SLEEP: - mt76x2_mac_wcid_set_drop(dev, idx, true); - mt76_stop_tx_queues(&dev->mt76, sta, true); - break; - case STA_NOTIFY_AWAKE: - mt76x2_mac_wcid_set_drop(dev, idx, false); - break; - } + mt76x2_mac_wcid_set_drop(dev, idx, ps); } static int @@ -549,6 +543,12 @@ static void mt76x2_set_coverage_class(struct ieee80211_hw *hw, mutex_unlock(&dev->mutex); } +static int +mt76x2_set_tim(struct ieee80211_hw *hw, struct ieee80211_sta *sta, bool set) +{ + return 0; +} + const struct ieee80211_ops mt76x2_ops = { .tx = mt76x2_tx, .start = mt76x2_start, @@ -560,7 +560,6 @@ const struct ieee80211_ops mt76x2_ops = { .bss_info_changed = mt76x2_bss_info_changed, .sta_add = mt76x2_sta_add, .sta_remove = mt76x2_sta_remove, - .sta_notify = mt76x2_sta_notify, .set_key = mt76x2_set_key, .conf_tx = mt76x2_conf_tx, .sw_scan_start = mt76x2_sw_scan, @@ -573,5 +572,6 @@ const struct ieee80211_ops mt76x2_ops = { .release_buffered_frames = mt76_release_buffered_frames, .set_coverage_class = mt76x2_set_coverage_class, .get_survey = mt76_get_survey, + .set_tim = mt76x2_set_tim, };