diff options
Diffstat (limited to 'net')
-rw-r--r-- | net/mac80211/driver-ops.h | 15 | ||||
-rw-r--r-- | net/mac80211/driver-trace.h | 35 | ||||
-rw-r--r-- | net/mac80211/sta_info.c | 82 |
3 files changed, 116 insertions, 16 deletions
diff --git a/net/mac80211/driver-ops.h b/net/mac80211/driver-ops.h index 4f845c0845ee..8fa0d2edf54c 100644 --- a/net/mac80211/driver-ops.h +++ b/net/mac80211/driver-ops.h | |||
@@ -670,4 +670,19 @@ static inline void drv_rssi_callback(struct ieee80211_local *local, | |||
670 | local->ops->rssi_callback(&local->hw, event); | 670 | local->ops->rssi_callback(&local->hw, event); |
671 | trace_drv_return_void(local); | 671 | trace_drv_return_void(local); |
672 | } | 672 | } |
673 | |||
674 | static inline void | ||
675 | drv_release_buffered_frames(struct ieee80211_local *local, | ||
676 | struct sta_info *sta, u16 tids, int num_frames, | ||
677 | enum ieee80211_frame_release_type reason, | ||
678 | bool more_data) | ||
679 | { | ||
680 | trace_drv_release_buffered_frames(local, &sta->sta, tids, num_frames, | ||
681 | reason, more_data); | ||
682 | if (local->ops->release_buffered_frames) | ||
683 | local->ops->release_buffered_frames(&local->hw, &sta->sta, tids, | ||
684 | num_frames, reason, | ||
685 | more_data); | ||
686 | trace_drv_return_void(local); | ||
687 | } | ||
673 | #endif /* __MAC80211_DRIVER_OPS */ | 688 | #endif /* __MAC80211_DRIVER_OPS */ |
diff --git a/net/mac80211/driver-trace.h b/net/mac80211/driver-trace.h index a46b279bbbe4..531fbd086794 100644 --- a/net/mac80211/driver-trace.h +++ b/net/mac80211/driver-trace.h | |||
@@ -1129,6 +1129,41 @@ TRACE_EVENT(drv_rssi_callback, | |||
1129 | ) | 1129 | ) |
1130 | ); | 1130 | ); |
1131 | 1131 | ||
1132 | TRACE_EVENT(drv_release_buffered_frames, | ||
1133 | TP_PROTO(struct ieee80211_local *local, | ||
1134 | struct ieee80211_sta *sta, | ||
1135 | u16 tids, int num_frames, | ||
1136 | enum ieee80211_frame_release_type reason, | ||
1137 | bool more_data), | ||
1138 | |||
1139 | TP_ARGS(local, sta, tids, num_frames, reason, more_data), | ||
1140 | |||
1141 | TP_STRUCT__entry( | ||
1142 | LOCAL_ENTRY | ||
1143 | STA_ENTRY | ||
1144 | __field(u16, tids) | ||
1145 | __field(int, num_frames) | ||
1146 | __field(int, reason) | ||
1147 | __field(bool, more_data) | ||
1148 | ), | ||
1149 | |||
1150 | TP_fast_assign( | ||
1151 | LOCAL_ASSIGN; | ||
1152 | STA_ASSIGN; | ||
1153 | __entry->tids = tids; | ||
1154 | __entry->num_frames = num_frames; | ||
1155 | __entry->reason = reason; | ||
1156 | __entry->more_data = more_data; | ||
1157 | ), | ||
1158 | |||
1159 | TP_printk( | ||
1160 | LOCAL_PR_FMT STA_PR_FMT | ||
1161 | " TIDs:0x%.4x frames:%d reason:%d more:%d", | ||
1162 | LOCAL_PR_ARG, STA_PR_ARG, __entry->tids, __entry->num_frames, | ||
1163 | __entry->reason, __entry->more_data | ||
1164 | ) | ||
1165 | ); | ||
1166 | |||
1132 | /* | 1167 | /* |
1133 | * Tracing for API calls that drivers call. | 1168 | * Tracing for API calls that drivers call. |
1134 | */ | 1169 | */ |
diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c index 4d85672f0b8f..b3f841948c09 100644 --- a/net/mac80211/sta_info.c +++ b/net/mac80211/sta_info.c | |||
@@ -1157,8 +1157,10 @@ void ieee80211_sta_ps_deliver_poll_response(struct sta_info *sta) | |||
1157 | struct ieee80211_sub_if_data *sdata = sta->sdata; | 1157 | struct ieee80211_sub_if_data *sdata = sta->sdata; |
1158 | struct ieee80211_local *local = sdata->local; | 1158 | struct ieee80211_local *local = sdata->local; |
1159 | struct sk_buff *skb = NULL; | 1159 | struct sk_buff *skb = NULL; |
1160 | bool found = false; | ||
1160 | bool more_data = false; | 1161 | bool more_data = false; |
1161 | int ac; | 1162 | int ac; |
1163 | unsigned long driver_release_tids = 0; | ||
1162 | u8 ignore_for_response = sta->sta.uapsd_queues; | 1164 | u8 ignore_for_response = sta->sta.uapsd_queues; |
1163 | 1165 | ||
1164 | /* | 1166 | /* |
@@ -1173,19 +1175,40 @@ void ieee80211_sta_ps_deliver_poll_response(struct sta_info *sta) | |||
1173 | * Get response frame and more data bit for it. | 1175 | * Get response frame and more data bit for it. |
1174 | */ | 1176 | */ |
1175 | for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) { | 1177 | for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) { |
1178 | unsigned long tids; | ||
1179 | |||
1176 | if (ignore_for_response & BIT(ac)) | 1180 | if (ignore_for_response & BIT(ac)) |
1177 | continue; | 1181 | continue; |
1178 | 1182 | ||
1179 | if (!skb) { | 1183 | tids = ieee80211_tids_for_ac(ac); |
1180 | skb = skb_dequeue(&sta->tx_filtered[ac]); | 1184 | |
1181 | if (!skb) { | 1185 | if (!found) { |
1182 | skb = skb_dequeue(&sta->ps_tx_buf[ac]); | 1186 | driver_release_tids = sta->driver_buffered_tids & tids; |
1187 | if (driver_release_tids) { | ||
1188 | found = true; | ||
1189 | } else { | ||
1190 | skb = skb_dequeue(&sta->tx_filtered[ac]); | ||
1191 | if (!skb) { | ||
1192 | skb = skb_dequeue(&sta->ps_tx_buf[ac]); | ||
1193 | if (skb) | ||
1194 | local->total_ps_buffered--; | ||
1195 | } | ||
1183 | if (skb) | 1196 | if (skb) |
1184 | local->total_ps_buffered--; | 1197 | found = true; |
1185 | } | 1198 | } |
1186 | } | ||
1187 | 1199 | ||
1188 | /* FIXME: take into account driver-buffered frames */ | 1200 | /* |
1201 | * If the driver has data on more than one TID then | ||
1202 | * certainly there's more data if we release just a | ||
1203 | * single frame now (from a single TID). | ||
1204 | */ | ||
1205 | if (hweight16(driver_release_tids) > 1) { | ||
1206 | more_data = true; | ||
1207 | driver_release_tids = | ||
1208 | BIT(ffs(driver_release_tids) - 1); | ||
1209 | break; | ||
1210 | } | ||
1211 | } | ||
1189 | 1212 | ||
1190 | if (!skb_queue_empty(&sta->tx_filtered[ac]) || | 1213 | if (!skb_queue_empty(&sta->tx_filtered[ac]) || |
1191 | !skb_queue_empty(&sta->ps_tx_buf[ac])) { | 1214 | !skb_queue_empty(&sta->ps_tx_buf[ac])) { |
@@ -1194,6 +1217,22 @@ void ieee80211_sta_ps_deliver_poll_response(struct sta_info *sta) | |||
1194 | } | 1217 | } |
1195 | } | 1218 | } |
1196 | 1219 | ||
1220 | if (!found) { | ||
1221 | #ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG | ||
1222 | /* | ||
1223 | * FIXME: This can be the result of a race condition between | ||
1224 | * us expiring a frame and the station polling for it. | ||
1225 | * Should we send it a null-func frame indicating we | ||
1226 | * have nothing buffered for it? | ||
1227 | */ | ||
1228 | printk(KERN_DEBUG "%s: STA %pM sent PS Poll even " | ||
1229 | "though there are no buffered frames for it\n", | ||
1230 | sdata->name, sta->sta.addr); | ||
1231 | #endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */ | ||
1232 | |||
1233 | return; | ||
1234 | } | ||
1235 | |||
1197 | if (skb) { | 1236 | if (skb) { |
1198 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); | 1237 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); |
1199 | struct ieee80211_hdr *hdr = | 1238 | struct ieee80211_hdr *hdr = |
@@ -1220,18 +1259,29 @@ void ieee80211_sta_ps_deliver_poll_response(struct sta_info *sta) | |||
1220 | ieee80211_add_pending_skb(local, skb); | 1259 | ieee80211_add_pending_skb(local, skb); |
1221 | 1260 | ||
1222 | sta_info_recalc_tim(sta); | 1261 | sta_info_recalc_tim(sta); |
1223 | #ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG | ||
1224 | } else { | 1262 | } else { |
1225 | /* | 1263 | /* |
1226 | * FIXME: This can be the result of a race condition between | 1264 | * We need to release a frame that is buffered somewhere in the |
1227 | * us expiring a frame and the station polling for it. | 1265 | * driver ... it'll have to handle that. |
1228 | * Should we send it a null-func frame indicating we | 1266 | * Note that, as per the comment above, it'll also have to see |
1229 | * have nothing buffered for it? | 1267 | * if there is more than just one frame on the specific TID that |
1268 | * we're releasing from, and it needs to set the more-data bit | ||
1269 | * accordingly if we tell it that there's no more data. If we do | ||
1270 | * tell it there's more data, then of course the more-data bit | ||
1271 | * needs to be set anyway. | ||
1272 | */ | ||
1273 | drv_release_buffered_frames(local, sta, driver_release_tids, | ||
1274 | 1, IEEE80211_FRAME_RELEASE_PSPOLL, | ||
1275 | more_data); | ||
1276 | |||
1277 | /* | ||
1278 | * Note that we don't recalculate the TIM bit here as it would | ||
1279 | * most likely have no effect at all unless the driver told us | ||
1280 | * that the TID became empty before returning here from the | ||
1281 | * release function. | ||
1282 | * Either way, however, when the driver tells us that the TID | ||
1283 | * became empty we'll do the TIM recalculation. | ||
1230 | */ | 1284 | */ |
1231 | printk(KERN_DEBUG "%s: STA %pM sent PS Poll even " | ||
1232 | "though there are no buffered frames for it\n", | ||
1233 | sdata->name, sta->sta.addr); | ||
1234 | #endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */ | ||
1235 | } | 1285 | } |
1236 | } | 1286 | } |
1237 | 1287 | ||