1 // SPDX-License-Identifier: GPL-2.0-only
3 * This file is part of wl1271
5 * Copyright (C) 2008-2009 Nokia Corporation
7 * Contact: Luciano Coelho <luciano.coelho@nokia.com>
15 int wl1271_ps_set_mode(struct wl1271
*wl
, struct wl12xx_vif
*wlvif
,
16 enum wl1271_cmd_ps_mode mode
)
19 u16 timeout
= wl
->conf
.conn
.dynamic_ps_timeout
;
22 case STATION_AUTO_PS_MODE
:
23 case STATION_POWER_SAVE_MODE
:
24 wl1271_debug(DEBUG_PSM
, "entering psm (mode=%d,timeout=%u)",
27 ret
= wl1271_acx_wake_up_conditions(wl
, wlvif
,
28 wl
->conf
.conn
.wake_up_event
,
29 wl
->conf
.conn
.listen_interval
);
31 wl1271_error("couldn't set wake up conditions");
35 ret
= wl1271_cmd_ps_mode(wl
, wlvif
, mode
, timeout
);
39 set_bit(WLVIF_FLAG_IN_PS
, &wlvif
->flags
);
42 * enable beacon early termination.
43 * Not relevant for 5GHz and for high rates.
45 if ((wlvif
->band
== NL80211_BAND_2GHZ
) &&
46 (wlvif
->basic_rate
< CONF_HW_BIT_RATE_9MBPS
)) {
47 ret
= wl1271_acx_bet_enable(wl
, wlvif
, true);
52 case STATION_ACTIVE_MODE
:
53 wl1271_debug(DEBUG_PSM
, "leaving psm");
55 /* disable beacon early termination */
56 if ((wlvif
->band
== NL80211_BAND_2GHZ
) &&
57 (wlvif
->basic_rate
< CONF_HW_BIT_RATE_9MBPS
)) {
58 ret
= wl1271_acx_bet_enable(wl
, wlvif
, false);
63 ret
= wl1271_cmd_ps_mode(wl
, wlvif
, mode
, 0);
67 clear_bit(WLVIF_FLAG_IN_PS
, &wlvif
->flags
);
70 wl1271_warning("trying to set ps to unsupported mode %d", mode
);
77 static void wl1271_ps_filter_frames(struct wl1271
*wl
, u8 hlid
)
81 struct ieee80211_tx_info
*info
;
83 int filtered
[NUM_TX_QUEUES
];
84 struct wl1271_link
*lnk
= &wl
->links
[hlid
];
86 /* filter all frames currently in the low level queues for this hlid */
87 for (i
= 0; i
< NUM_TX_QUEUES
; i
++) {
89 while ((skb
= skb_dequeue(&lnk
->tx_queue
[i
]))) {
92 if (WARN_ON(wl12xx_is_dummy_packet(wl
, skb
)))
95 info
= IEEE80211_SKB_CB(skb
);
96 info
->flags
|= IEEE80211_TX_STAT_TX_FILTERED
;
97 info
->status
.rates
[0].idx
= -1;
98 ieee80211_tx_status_ni(wl
->hw
, skb
);
102 spin_lock_irqsave(&wl
->wl_lock
, flags
);
103 for (i
= 0; i
< NUM_TX_QUEUES
; i
++) {
104 wl
->tx_queue_count
[i
] -= filtered
[i
];
106 lnk
->wlvif
->tx_queue_count
[i
] -= filtered
[i
];
108 spin_unlock_irqrestore(&wl
->wl_lock
, flags
);
110 wl1271_handle_tx_low_watermark(wl
);
113 void wl12xx_ps_link_start(struct wl1271
*wl
, struct wl12xx_vif
*wlvif
,
114 u8 hlid
, bool clean_queues
)
116 struct ieee80211_sta
*sta
;
117 struct ieee80211_vif
*vif
= wl12xx_wlvif_to_vif(wlvif
);
119 if (WARN_ON_ONCE(wlvif
->bss_type
!= BSS_TYPE_AP_BSS
))
122 if (!test_bit(hlid
, wlvif
->ap
.sta_hlid_map
) ||
123 test_bit(hlid
, &wl
->ap_ps_map
))
126 wl1271_debug(DEBUG_PSM
, "start mac80211 PSM on hlid %d pkts %d "
127 "clean_queues %d", hlid
, wl
->links
[hlid
].allocated_pkts
,
131 sta
= ieee80211_find_sta(vif
, wl
->links
[hlid
].addr
);
133 wl1271_error("could not find sta %pM for starting ps",
134 wl
->links
[hlid
].addr
);
139 ieee80211_sta_ps_transition_ni(sta
, true);
142 /* do we want to filter all frames from this link's queues? */
144 wl1271_ps_filter_frames(wl
, hlid
);
146 __set_bit(hlid
, &wl
->ap_ps_map
);
149 void wl12xx_ps_link_end(struct wl1271
*wl
, struct wl12xx_vif
*wlvif
, u8 hlid
)
151 struct ieee80211_sta
*sta
;
152 struct ieee80211_vif
*vif
= wl12xx_wlvif_to_vif(wlvif
);
154 if (!test_bit(hlid
, &wl
->ap_ps_map
))
157 wl1271_debug(DEBUG_PSM
, "end mac80211 PSM on hlid %d", hlid
);
159 __clear_bit(hlid
, &wl
->ap_ps_map
);
162 sta
= ieee80211_find_sta(vif
, wl
->links
[hlid
].addr
);
164 wl1271_error("could not find sta %pM for ending ps",
165 wl
->links
[hlid
].addr
);
169 ieee80211_sta_ps_transition_ni(sta
, false);