File Index
Files and directories
Sign in
FILE

agg.c

File preview with syntax highlighting.

linux-6.19.14/drivers/net/wireless/intel/iwlwifi/mld/agg.c C
  1// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
  2/*
  3 * Copyright (C) 2024-2025 Intel Corporation
  4 */
  5#include "agg.h"
  6#include "sta.h"
  7#include "hcmd.h"
  8
  9static void
 10iwl_mld_reorder_release_frames(struct iwl_mld *mld, struct ieee80211_sta *sta,
 11			       struct napi_struct *napi,
 12			       struct iwl_mld_baid_data *baid_data,
 13			       struct iwl_mld_reorder_buffer *reorder_buf,
 14			       u16 nssn)
 15{
 16	struct iwl_mld_reorder_buf_entry *entries =
 17		&baid_data->entries[reorder_buf->queue *
 18				    baid_data->entries_per_queue];
 19	u16 ssn = reorder_buf->head_sn;
 20
 21	while (ieee80211_sn_less(ssn, nssn)) {
 22		int index = ssn % baid_data->buf_size;
 23		struct sk_buff_head *skb_list = &entries[index].frames;
 24		struct sk_buff *skb;
 25
 26		ssn = ieee80211_sn_inc(ssn);
 27
 28		/* Empty the list. Will have more than one frame for A-MSDU.
 29		 * Empty list is valid as well since nssn indicates frames were
 30		 * received.
 31		 */
 32		while ((skb = __skb_dequeue(skb_list))) {
 33			iwl_mld_pass_packet_to_mac80211(mld, napi, skb,
 34							reorder_buf->queue,
 35							sta);
 36			reorder_buf->num_stored--;
 37		}
 38	}
 39	reorder_buf->head_sn = nssn;
 40}
 41
 42static void iwl_mld_release_frames_from_notif(struct iwl_mld *mld,
 43					      struct napi_struct *napi,
 44					      u8 baid, u16 nssn, int queue)
 45{
 46	struct iwl_mld_reorder_buffer *reorder_buf;
 47	struct iwl_mld_baid_data *ba_data;
 48	struct ieee80211_link_sta *link_sta;
 49	u32 sta_id;
 50
 51	IWL_DEBUG_HT(mld, "Frame release notification for BAID %u, NSSN %d\n",
 52		     baid, nssn);
 53
 54	if (WARN_ON_ONCE(baid == IWL_RX_REORDER_DATA_INVALID_BAID ||
 55			 baid >= ARRAY_SIZE(mld->fw_id_to_ba)))
 56		return;
 57
 58	rcu_read_lock();
 59
 60	ba_data = rcu_dereference(mld->fw_id_to_ba[baid]);
 61	if (!ba_data) {
 62		IWL_DEBUG_HT(mld, "BAID %d not found in map\n", baid);
 63		goto out_unlock;
 64	}
 65
 66	/* pick any STA ID to find the pointer */
 67	sta_id = ffs(ba_data->sta_mask) - 1;
 68	link_sta = rcu_dereference(mld->fw_id_to_link_sta[sta_id]);
 69	if (WARN_ON_ONCE(IS_ERR_OR_NULL(link_sta) || !link_sta->sta))
 70		goto out_unlock;
 71
 72	reorder_buf = &ba_data->reorder_buf[queue];
 73
 74	iwl_mld_reorder_release_frames(mld, link_sta->sta, napi, ba_data,
 75				       reorder_buf, nssn);
 76out_unlock:
 77	rcu_read_unlock();
 78}
 79
 80void iwl_mld_handle_frame_release_notif(struct iwl_mld *mld,
 81					struct napi_struct *napi,
 82					struct iwl_rx_packet *pkt, int queue)
 83{
 84	struct iwl_frame_release *release = (void *)pkt->data;
 85	u32 pkt_len = iwl_rx_packet_payload_len(pkt);
 86
 87	if (IWL_FW_CHECK(mld, pkt_len < sizeof(*release),
 88			 "Unexpected frame release notif size %u (expected %zu)\n",
 89			 pkt_len, sizeof(*release)))
 90		return;
 91
 92	iwl_mld_release_frames_from_notif(mld, napi, release->baid,
 93					  le16_to_cpu(release->nssn),
 94					  queue);
 95}
 96
 97void iwl_mld_handle_bar_frame_release_notif(struct iwl_mld *mld,
 98					    struct napi_struct *napi,
 99					    struct iwl_rx_packet *pkt,
100					    int queue)
101{
102	struct iwl_bar_frame_release *release = (void *)pkt->data;
103	struct iwl_mld_baid_data *baid_data;
104	unsigned int baid, nssn, sta_id, tid;
105	u32 pkt_len = iwl_rx_packet_payload_len(pkt);
106
107	if (IWL_FW_CHECK(mld, pkt_len < sizeof(*release),
108			 "Unexpected frame release notif size %u (expected %zu)\n",
109			 pkt_len, sizeof(*release)))
110		return;
111
112	baid = le32_get_bits(release->ba_info,
113			     IWL_BAR_FRAME_RELEASE_BAID_MASK);
114	nssn = le32_get_bits(release->ba_info,
115			     IWL_BAR_FRAME_RELEASE_NSSN_MASK);
116	sta_id = le32_get_bits(release->sta_tid,
117			       IWL_BAR_FRAME_RELEASE_STA_MASK);
118	tid = le32_get_bits(release->sta_tid,
119			    IWL_BAR_FRAME_RELEASE_TID_MASK);
120
121	if (IWL_FW_CHECK(mld, baid >= ARRAY_SIZE(mld->fw_id_to_ba),
122			 "BAR release: invalid BAID (%x)\n", baid))
123		return;
124
125	rcu_read_lock();
126	baid_data = rcu_dereference(mld->fw_id_to_ba[baid]);
127	if (!baid_data) {
128		IWL_DEBUG_HT(mld,
129			     "Got valid BAID %d but not allocated\n",
130			     baid);
131		goto out_unlock;
132	}
133
134	if (IWL_FW_CHECK(mld, tid != baid_data->tid ||
135			 sta_id > mld->fw->ucode_capa.num_stations ||
136			 !(baid_data->sta_mask & BIT(sta_id)),
137			 "BAID 0x%x is mapped to sta_mask:0x%x tid:%d, but BAR release received for sta:%d tid:%d\n",
138			 baid, baid_data->sta_mask, baid_data->tid, sta_id,
139			 tid))
140		goto out_unlock;
141
142	IWL_DEBUG_DROP(mld, "Received a BAR, expect packet loss: nssn %d\n",
143		       nssn);
144
145	iwl_mld_release_frames_from_notif(mld, napi, baid, nssn, queue);
146out_unlock:
147	rcu_read_unlock();
148}
149
150void iwl_mld_del_ba(struct iwl_mld *mld, int queue,
151		    struct iwl_mld_delba_data *data)
152{
153	struct iwl_mld_baid_data *ba_data;
154	struct iwl_mld_reorder_buffer *reorder_buf;
155	struct ieee80211_link_sta *link_sta;
156	u8 baid = data->baid;
157	u32 sta_id;
158
159	if (WARN_ONCE(baid >= IWL_MAX_BAID, "invalid BAID: %x\n", baid))
160		return;
161
162	rcu_read_lock();
163
164	ba_data = rcu_dereference(mld->fw_id_to_ba[baid]);
165	if (WARN_ON_ONCE(!ba_data))
166		goto out_unlock;
167
168	/* pick any STA ID to find the pointer */
169	sta_id = ffs(ba_data->sta_mask) - 1;
170	link_sta = rcu_dereference(mld->fw_id_to_link_sta[sta_id]);
171	if (WARN_ON_ONCE(IS_ERR_OR_NULL(link_sta) || !link_sta->sta))
172		goto out_unlock;
173
174	reorder_buf = &ba_data->reorder_buf[queue];
175
176	/* release all frames that are in the reorder buffer to the stack */
177	iwl_mld_reorder_release_frames(mld, link_sta->sta, NULL,
178				       ba_data, reorder_buf,
179				       ieee80211_sn_add(reorder_buf->head_sn,
180							ba_data->buf_size));
181out_unlock:
182	rcu_read_unlock();
183}
184
185/* Returns true if the MPDU was buffered\dropped, false if it should be passed
186 * to upper layer.
187 */
188enum iwl_mld_reorder_result
189iwl_mld_reorder(struct iwl_mld *mld, struct napi_struct *napi,
190		int queue, struct ieee80211_sta *sta,
191		struct sk_buff *skb, struct iwl_rx_mpdu_desc *desc)
192{
193	struct ieee80211_hdr *hdr = (void *)skb_mac_header(skb);
194	struct iwl_mld_baid_data *baid_data;
195	struct iwl_mld_reorder_buffer *buffer;
196	struct iwl_mld_reorder_buf_entry *entries;
197	struct iwl_mld_sta *mld_sta = iwl_mld_sta_from_mac80211(sta);
198	struct iwl_mld_link_sta *mld_link_sta;
199	u32 reorder = le32_to_cpu(desc->reorder_data);
200	bool amsdu, last_subframe, is_old_sn, is_dup;
201	u8 tid = ieee80211_get_tid(hdr);
202	u8 baid;
203	u16 nssn, sn;
204	u32 sta_mask = 0;
205	int index;
206	u8 link_id;
207
208	baid = u32_get_bits(reorder, IWL_RX_MPDU_REORDER_BAID_MASK);
209
210	/* This also covers the case of receiving a Block Ack Request
211	 * outside a BA session; we'll pass it to mac80211 and that
212	 * then sends a delBA action frame.
213	 * This also covers pure monitor mode, in which case we won't
214	 * have any BA sessions.
215	 */
216	if (baid == IWL_RX_REORDER_DATA_INVALID_BAID)
217		return IWL_MLD_PASS_SKB;
218
219	/* no sta yet */
220	if (WARN_ONCE(!sta,
221		      "Got valid BAID without a valid station assigned\n"))
222		return IWL_MLD_PASS_SKB;
223
224	/* not a data packet */
225	if (!ieee80211_is_data_qos(hdr->frame_control) ||
226	    is_multicast_ether_addr(hdr->addr1))
227		return IWL_MLD_PASS_SKB;
228
229	if (unlikely(!ieee80211_is_data_present(hdr->frame_control)))
230		return IWL_MLD_PASS_SKB;
231
232	baid_data = rcu_dereference(mld->fw_id_to_ba[baid]);
233	if (!baid_data) {
234		IWL_DEBUG_HT(mld,
235			     "Got valid BAID but no baid allocated, bypass re-ordering (BAID=%d reorder=0x%x)\n",
236			     baid, reorder);
237		return IWL_MLD_PASS_SKB;
238	}
239
240	for_each_mld_link_sta(mld_sta, mld_link_sta, link_id)
241		sta_mask |= BIT(mld_link_sta->fw_id);
242
243	/* verify the BAID is correctly mapped to the sta and tid */
244	if (IWL_FW_CHECK(mld,
245			 tid != baid_data->tid ||
246			 !(sta_mask & baid_data->sta_mask),
247			 "BAID 0x%x is mapped to sta_mask:0x%x tid:%d, but was received for sta_mask:0x%x tid:%d\n",
248			 baid, baid_data->sta_mask, baid_data->tid,
249			 sta_mask, tid))
250		return IWL_MLD_PASS_SKB;
251
252	buffer = &baid_data->reorder_buf[queue];
253	entries = &baid_data->entries[queue * baid_data->entries_per_queue];
254
255	is_old_sn = !!(reorder & IWL_RX_MPDU_REORDER_BA_OLD_SN);
256
257	if (!buffer->valid && is_old_sn)
258		return IWL_MLD_PASS_SKB;
259
260	buffer->valid = true;
261
262	is_dup = !!(desc->status & cpu_to_le32(IWL_RX_MPDU_STATUS_DUPLICATE));
263
264	/* drop any duplicated or outdated packets */
265	if (is_dup || is_old_sn)
266		return IWL_MLD_DROP_SKB;
267
268	sn = u32_get_bits(reorder, IWL_RX_MPDU_REORDER_SN_MASK);
269	nssn = u32_get_bits(reorder, IWL_RX_MPDU_REORDER_NSSN_MASK);
270	amsdu = desc->mac_flags2 & IWL_RX_MPDU_MFLG2_AMSDU;
271	last_subframe = desc->amsdu_info & IWL_RX_MPDU_AMSDU_LAST_SUBFRAME;
272
273	/* release immediately if allowed by nssn and no stored frames */
274	if (!buffer->num_stored && ieee80211_sn_less(sn, nssn)) {
275		if (!amsdu || last_subframe)
276			buffer->head_sn = nssn;
277		return IWL_MLD_PASS_SKB;
278	}
279
280	/* release immediately if there are no stored frames, and the sn is
281	 * equal to the head.
282	 * This can happen due to reorder timer, where NSSN is behind head_sn.
283	 * When we released everything, and we got the next frame in the
284	 * sequence, according to the NSSN we can't release immediately,
285	 * while technically there is no hole and we can move forward.
286	 */
287	if (!buffer->num_stored && sn == buffer->head_sn) {
288		if (!amsdu || last_subframe)
289			buffer->head_sn = ieee80211_sn_inc(buffer->head_sn);
290		return IWL_MLD_PASS_SKB;
291	}
292
293	/* put in reorder buffer */
294	index = sn % baid_data->buf_size;
295	__skb_queue_tail(&entries[index].frames, skb);
296	buffer->num_stored++;
297
298	/* We cannot trust NSSN for AMSDU sub-frames that are not the last. The
299	 * reason is that NSSN advances on the first sub-frame, and may cause
300	 * the reorder buffer to advance before all the sub-frames arrive.
301	 *
302	 * Example: reorder buffer contains SN 0 & 2, and we receive AMSDU with
303	 * SN 1. NSSN for first sub frame will be 3 with the result of driver
304	 * releasing SN 0,1, 2. When sub-frame 1 arrives - reorder buffer is
305	 * already ahead and it will be dropped.
306	 * If the last sub-frame is not on this queue - we will get frame
307	 * release notification with up to date NSSN.
308	 * If this is the first frame that is stored in the buffer, the head_sn
309	 * may be outdated. Update it based on the last NSSN to make sure it
310	 * will be released when the frame release notification arrives.
311	 */
312	if (!amsdu || last_subframe)
313		iwl_mld_reorder_release_frames(mld, sta, napi, baid_data,
314					       buffer, nssn);
315	else if (buffer->num_stored == 1)
316		buffer->head_sn = nssn;
317
318	return IWL_MLD_BUFFERED_SKB;
319}
320EXPORT_SYMBOL_IF_IWLWIFI_KUNIT(iwl_mld_reorder);
321
322static void iwl_mld_rx_agg_session_expired(struct timer_list *t)
323{
324	struct iwl_mld_baid_data *data =
325		timer_container_of(data, t, session_timer);
326	struct iwl_mld_baid_data __rcu **rcu_ptr = data->rcu_ptr;
327	struct iwl_mld_baid_data *ba_data;
328	struct ieee80211_link_sta *link_sta;
329	struct iwl_mld_sta *mld_sta;
330	unsigned long timeout;
331	unsigned int sta_id;
332
333	rcu_read_lock();
334
335	ba_data = rcu_dereference(*rcu_ptr);
336	if (WARN_ON(!ba_data))
337		goto unlock;
338
339	if (WARN_ON(!ba_data->timeout))
340		goto unlock;
341
342	timeout = ba_data->last_rx_timestamp +
343		  TU_TO_JIFFIES(ba_data->timeout * 2);
344	if (time_is_after_jiffies(timeout)) {
345		mod_timer(&ba_data->session_timer, timeout);
346		goto unlock;
347	}
348
349	/* timer expired, pick any STA ID to find the pointer */
350	sta_id = ffs(ba_data->sta_mask) - 1;
351	link_sta = rcu_dereference(ba_data->mld->fw_id_to_link_sta[sta_id]);
352
353	/* sta should be valid unless the following happens:
354	 * The firmware asserts which triggers a reconfig flow, but
355	 * the reconfig fails before we set the pointer to sta into
356	 * the fw_id_to_link_sta pointer table. mac80211 can't stop
357	 * A-MPDU and hence the timer continues to run. Then, the
358	 * timer expires and sta is NULL.
359	 */
360	if (IS_ERR_OR_NULL(link_sta) || WARN_ON(!link_sta->sta))
361		goto unlock;
362
363	mld_sta = iwl_mld_sta_from_mac80211(link_sta->sta);
364	ieee80211_rx_ba_timer_expired(mld_sta->vif, link_sta->sta->addr,
365				      ba_data->tid);
366unlock:
367	rcu_read_unlock();
368}
369
370static int
371iwl_mld_stop_ba_in_fw(struct iwl_mld *mld, struct ieee80211_sta *sta, int tid)
372{
373	struct iwl_rx_baid_cfg_cmd cmd = {
374		.action = cpu_to_le32(IWL_RX_BAID_ACTION_REMOVE),
375		.remove.sta_id_mask =
376			cpu_to_le32(iwl_mld_fw_sta_id_mask(mld, sta)),
377		.remove.tid = cpu_to_le32(tid),
378
379	};
380	int ret;
381
382	ret = iwl_mld_send_cmd_pdu(mld,
383				   WIDE_ID(DATA_PATH_GROUP,
384					   RX_BAID_ALLOCATION_CONFIG_CMD),
385				   &cmd);
386	if (ret)
387		return ret;
388
389	IWL_DEBUG_HT(mld, "RX BA Session stopped in fw\n");
390
391	return ret;
392}
393
394static int
395iwl_mld_start_ba_in_fw(struct iwl_mld *mld, struct ieee80211_sta *sta,
396		       int tid, u16 ssn, u16 buf_size)
397{
398	struct iwl_rx_baid_cfg_cmd cmd = {
399		.action = cpu_to_le32(IWL_RX_BAID_ACTION_ADD),
400		.alloc.sta_id_mask =
401			cpu_to_le32(iwl_mld_fw_sta_id_mask(mld, sta)),
402		.alloc.tid = tid,
403		.alloc.ssn = cpu_to_le16(ssn),
404		.alloc.win_size = cpu_to_le16(buf_size),
405	};
406	struct iwl_host_cmd hcmd = {
407		.id = WIDE_ID(DATA_PATH_GROUP, RX_BAID_ALLOCATION_CONFIG_CMD),
408		.flags = CMD_WANT_SKB,
409		.len[0] = sizeof(cmd),
410		.data[0] = &cmd,
411	};
412	struct iwl_rx_baid_cfg_resp *resp;
413	struct iwl_rx_packet *pkt;
414	u32 resp_len;
415	int ret, baid;
416
417	BUILD_BUG_ON(sizeof(*resp) != sizeof(baid));
418
419	ret = iwl_mld_send_cmd(mld, &hcmd);
420	if (ret)
421		return ret;
422
423	pkt = hcmd.resp_pkt;
424
425	resp_len = iwl_rx_packet_payload_len(pkt);
426	if (IWL_FW_CHECK(mld, resp_len != sizeof(*resp),
427			 "BAID_ALLOC_CMD: unexpected response length %d\n",
428			 resp_len)) {
429		ret = -EIO;
430		goto out;
431	}
432
433	IWL_DEBUG_HT(mld, "RX BA Session started in fw\n");
434
435	resp = (void *)pkt->data;
436	baid = le32_to_cpu(resp->baid);
437
438	if (IWL_FW_CHECK(mld, baid < 0 || baid >= ARRAY_SIZE(mld->fw_id_to_ba),
439			 "BAID_ALLOC_CMD: invalid BAID response %d\n", baid)) {
440		ret = -EINVAL;
441		goto out;
442	}
443
444	ret = baid;
445out:
446	iwl_free_resp(&hcmd);
447	return ret;
448}
449
450static void iwl_mld_init_reorder_buffer(struct iwl_mld *mld,
451					struct iwl_mld_baid_data *data,
452					u16 ssn)
453{
454	for (int i = 0; i < mld->trans->info.num_rxqs; i++) {
455		struct iwl_mld_reorder_buffer *reorder_buf =
456			&data->reorder_buf[i];
457		struct iwl_mld_reorder_buf_entry *entries =
458			&data->entries[i * data->entries_per_queue];
459
460		reorder_buf->head_sn = ssn;
461		reorder_buf->queue = i;
462
463		for (int j = 0; j < data->buf_size; j++)
464			__skb_queue_head_init(&entries[j].frames);
465	}
466}
467
468static void iwl_mld_free_reorder_buffer(struct iwl_mld *mld,
469					struct iwl_mld_baid_data *data)
470{
471	struct iwl_mld_delba_data delba_data = {
472		.baid = data->baid,
473	};
474
475	iwl_mld_sync_rx_queues(mld, IWL_MLD_RXQ_NOTIF_DEL_BA,
476			       &delba_data, sizeof(delba_data));
477
478	for (int i = 0; i < mld->trans->info.num_rxqs; i++) {
479		struct iwl_mld_reorder_buffer *reorder_buf =
480			&data->reorder_buf[i];
481		struct iwl_mld_reorder_buf_entry *entries =
482			&data->entries[i * data->entries_per_queue];
483
484		if (likely(!reorder_buf->num_stored))
485			continue;
486
487		/* This shouldn't happen in regular DELBA since the RX queues
488		 * sync internal DELBA notification should trigger a release
489		 * of all frames in the reorder buffer.
490		 */
491		WARN_ON(1);
492
493		for (int j = 0; j < data->buf_size; j++)
494			__skb_queue_purge(&entries[j].frames);
495	}
496}
497
498int iwl_mld_ampdu_rx_start(struct iwl_mld *mld, struct ieee80211_sta *sta,
499			   int tid, u16 ssn, u16 buf_size, u16 timeout)
500{
501	struct iwl_mld_sta *mld_sta = iwl_mld_sta_from_mac80211(sta);
502	struct iwl_mld_baid_data *baid_data = NULL;
503	u32 reorder_buf_size = buf_size * sizeof(baid_data->entries[0]);
504	int ret, baid;
505	u32 sta_mask;
506
507	lockdep_assert_wiphy(mld->wiphy);
508
509	if (mld->num_rx_ba_sessions >= IWL_MAX_BAID) {
510		IWL_DEBUG_HT(mld,
511			     "Max num of RX BA sessions reached; blocking new session\n");
512		return -ENOSPC;
513	}
514
515	sta_mask = iwl_mld_fw_sta_id_mask(mld, sta);
516	if (WARN_ON(!sta_mask))
517		return -EINVAL;
518
519	/* sparse doesn't like the __align() so don't check */
520#ifndef __CHECKER__
521	/* The division below will be OK if either the cache line size
522	 * can be divided by the entry size (ALIGN will round up) or if
523	 * the entry size can be divided by the cache line size, in which
524	 * case the ALIGN() will do nothing.
525	 */
526	BUILD_BUG_ON(SMP_CACHE_BYTES % sizeof(baid_data->entries[0]) &&
527		     sizeof(baid_data->entries[0]) % SMP_CACHE_BYTES);
528#endif
529
530	/* Upward align the reorder buffer size to fill an entire cache
531	 * line for each queue, to avoid sharing cache lines between
532	 * different queues.
533	 */
534	reorder_buf_size = ALIGN(reorder_buf_size, SMP_CACHE_BYTES);
535
536	/* Allocate here so if allocation fails we can bail out early
537	 * before starting the BA session in the firmware
538	 */
539	baid_data = kzalloc(sizeof(*baid_data) +
540			    mld->trans->info.num_rxqs * reorder_buf_size,
541			    GFP_KERNEL);
542	if (!baid_data)
543		return -ENOMEM;
544
545	/* This division is why we need the above BUILD_BUG_ON(),
546	 * if that doesn't hold then this will not be right.
547	 */
548	baid_data->entries_per_queue =
549		reorder_buf_size / sizeof(baid_data->entries[0]);
550
551	baid = iwl_mld_start_ba_in_fw(mld, sta, tid, ssn, buf_size);
552	if (baid < 0) {
553		ret = baid;
554		goto out_free;
555	}
556
557	mld->num_rx_ba_sessions++;
558	mld_sta->tid_to_baid[tid] = baid;
559
560	baid_data->baid = baid;
561	baid_data->mld = mld;
562	baid_data->tid = tid;
563	baid_data->buf_size = buf_size;
564	baid_data->sta_mask = sta_mask;
565	baid_data->timeout = timeout;
566	baid_data->last_rx_timestamp = jiffies;
567	baid_data->rcu_ptr = &mld->fw_id_to_ba[baid];
568
569	iwl_mld_init_reorder_buffer(mld, baid_data, ssn);
570
571	timer_setup(&baid_data->session_timer, iwl_mld_rx_agg_session_expired,
572		    0);
573	if (timeout)
574		mod_timer(&baid_data->session_timer,
575			  TU_TO_EXP_TIME(timeout * 2));
576
577	IWL_DEBUG_HT(mld, "STA mask=0x%x (tid=%d) is assigned to BAID %d\n",
578		     baid_data->sta_mask, tid, baid);
579
580	/* protect the BA data with RCU to cover a case where our
581	 * internal RX sync mechanism will timeout (not that it's
582	 * supposed to happen) and we will free the session data while
583	 * RX is being processed in parallel
584	 */
585	WARN_ON(rcu_access_pointer(mld->fw_id_to_ba[baid]));
586	rcu_assign_pointer(mld->fw_id_to_ba[baid], baid_data);
587
588	return 0;
589
590out_free:
591	kfree(baid_data);
592	return ret;
593}
594
595int iwl_mld_ampdu_rx_stop(struct iwl_mld *mld, struct ieee80211_sta *sta,
596			  int tid)
597{
598	struct iwl_mld_sta *mld_sta = iwl_mld_sta_from_mac80211(sta);
599	int baid = mld_sta->tid_to_baid[tid];
600	struct iwl_mld_baid_data *baid_data;
601	int ret;
602
603	lockdep_assert_wiphy(mld->wiphy);
604
605	/* during firmware restart, do not send the command as the firmware no
606	 * longer recognizes the session. instead, only clear the driver BA
607	 * session data.
608	 */
609	if (!mld->fw_status.in_hw_restart) {
610		ret = iwl_mld_stop_ba_in_fw(mld, sta, tid);
611		if (ret)
612			return ret;
613	}
614
615	if (!WARN_ON(mld->num_rx_ba_sessions == 0))
616		mld->num_rx_ba_sessions--;
617
618	baid_data = wiphy_dereference(mld->wiphy, mld->fw_id_to_ba[baid]);
619	if (WARN_ON(!baid_data))
620		return -EINVAL;
621
622	if (timer_pending(&baid_data->session_timer))
623		timer_shutdown_sync(&baid_data->session_timer);
624
625	iwl_mld_free_reorder_buffer(mld, baid_data);
626
627	RCU_INIT_POINTER(mld->fw_id_to_ba[baid], NULL);
628	kfree_rcu(baid_data, rcu_head);
629
630	IWL_DEBUG_HT(mld, "BAID %d is free\n", baid);
631
632	return 0;
633}
634
635int iwl_mld_update_sta_baids(struct iwl_mld *mld,
636			     u32 old_sta_mask,
637			     u32 new_sta_mask)
638{
639	struct iwl_rx_baid_cfg_cmd cmd = {
640		.action = cpu_to_le32(IWL_RX_BAID_ACTION_MODIFY),
641		.modify.old_sta_id_mask = cpu_to_le32(old_sta_mask),
642		.modify.new_sta_id_mask = cpu_to_le32(new_sta_mask),
643	};
644	u32 cmd_id = WIDE_ID(DATA_PATH_GROUP, RX_BAID_ALLOCATION_CONFIG_CMD);
645	int baid;
646
647	/* mac80211 will remove sessions later, but we ignore all that */
648	if (mld->fw_status.in_hw_restart)
649		return 0;
650
651	BUILD_BUG_ON(sizeof(struct iwl_rx_baid_cfg_resp) != sizeof(baid));
652
653	for (baid = 0; baid < ARRAY_SIZE(mld->fw_id_to_ba); baid++) {
654		struct iwl_mld_baid_data *data;
655		int ret;
656
657		data = wiphy_dereference(mld->wiphy, mld->fw_id_to_ba[baid]);
658		if (!data)
659			continue;
660
661		if (!(data->sta_mask & old_sta_mask))
662			continue;
663
664		WARN_ONCE(data->sta_mask != old_sta_mask,
665			  "BAID data for %d corrupted - expected 0x%x found 0x%x\n",
666			  baid, old_sta_mask, data->sta_mask);
667
668		cmd.modify.tid = cpu_to_le32(data->tid);
669
670		ret = iwl_mld_send_cmd_pdu(mld, cmd_id, &cmd);
671		if (ret)
672			return ret;
673		data->sta_mask = new_sta_mask;
674	}
675
676	return 0;
677}
~/ Read-only file preview.