1 // SPDX-License-Identifier: GPL-2.0-only
3 * Data transmitting implementation.
5 * Copyright (c) 2017-2020, Silicon Laboratories, Inc.
6 * Copyright (c) 2010, ST-Ericsson
8 #include <net/mac80211.h>
9 #include <linux/etherdevice.h>
18 #include "hif_tx_mib.h"
20 static int wfx_get_hw_rate(struct wfx_dev
*wdev
, const struct ieee80211_tx_rate
*rate
)
22 struct ieee80211_supported_band
*band
;
26 if (rate
->flags
& IEEE80211_TX_RC_MCS
) {
28 WARN(1, "wrong rate->idx value: %d", rate
->idx
);
31 return rate
->idx
+ 14;
33 /* The device only support 2GHz, else band information should be retrieved from
36 band
= wdev
->hw
->wiphy
->bands
[NL80211_BAND_2GHZ
];
37 if (rate
->idx
>= band
->n_bitrates
) {
38 WARN(1, "wrong rate->idx value: %d", rate
->idx
);
41 return band
->bitrates
[rate
->idx
].hw_value
;
44 /* TX policy cache implementation */
46 static void wfx_tx_policy_build(struct wfx_vif
*wvif
, struct wfx_tx_policy
*policy
,
47 struct ieee80211_tx_rate
*rates
)
49 struct wfx_dev
*wdev
= wvif
->wdev
;
53 WARN(rates
[0].idx
< 0, "invalid rate policy");
54 memset(policy
, 0, sizeof(*policy
));
55 for (i
= 0; i
< IEEE80211_TX_MAX_RATES
; ++i
) {
58 WARN_ON(rates
[i
].count
> 15);
59 rateid
= wfx_get_hw_rate(wdev
, &rates
[i
]);
60 /* Pack two values in each byte of policy->rates */
61 count
= rates
[i
].count
;
64 policy
->rates
[rateid
/ 2] |= count
;
68 static bool wfx_tx_policy_is_equal(const struct wfx_tx_policy
*a
, const struct wfx_tx_policy
*b
)
70 return !memcmp(a
->rates
, b
->rates
, sizeof(a
->rates
));
73 static int wfx_tx_policy_find(struct wfx_tx_policy_cache
*cache
, struct wfx_tx_policy
*wanted
)
75 struct wfx_tx_policy
*it
;
77 list_for_each_entry(it
, &cache
->used
, link
)
78 if (wfx_tx_policy_is_equal(wanted
, it
))
79 return it
- cache
->cache
;
80 list_for_each_entry(it
, &cache
->free
, link
)
81 if (wfx_tx_policy_is_equal(wanted
, it
))
82 return it
- cache
->cache
;
86 static void wfx_tx_policy_use(struct wfx_tx_policy_cache
*cache
, struct wfx_tx_policy
*entry
)
89 list_move(&entry
->link
, &cache
->used
);
92 static int wfx_tx_policy_release(struct wfx_tx_policy_cache
*cache
, struct wfx_tx_policy
*entry
)
94 int ret
= --entry
->usage_count
;
97 list_move(&entry
->link
, &cache
->free
);
101 static int wfx_tx_policy_get(struct wfx_vif
*wvif
, struct ieee80211_tx_rate
*rates
, bool *renew
)
104 struct wfx_tx_policy_cache
*cache
= &wvif
->tx_policy_cache
;
105 struct wfx_tx_policy wanted
;
106 struct wfx_tx_policy
*entry
;
108 wfx_tx_policy_build(wvif
, &wanted
, rates
);
110 spin_lock_bh(&cache
->lock
);
111 if (list_empty(&cache
->free
)) {
112 WARN(1, "unable to get a valid Tx policy");
113 spin_unlock_bh(&cache
->lock
);
114 return HIF_TX_RETRY_POLICY_INVALID
;
116 idx
= wfx_tx_policy_find(cache
, &wanted
);
120 /* If policy is not found create a new one using the oldest entry in "free" list */
122 entry
= list_entry(cache
->free
.prev
, struct wfx_tx_policy
, link
);
123 memcpy(entry
->rates
, wanted
.rates
, sizeof(entry
->rates
));
124 entry
->uploaded
= false;
125 entry
->usage_count
= 0;
126 idx
= entry
- cache
->cache
;
128 wfx_tx_policy_use(cache
, &cache
->cache
[idx
]);
129 if (list_empty(&cache
->free
))
130 ieee80211_stop_queues(wvif
->wdev
->hw
);
131 spin_unlock_bh(&cache
->lock
);
135 static void wfx_tx_policy_put(struct wfx_vif
*wvif
, int idx
)
138 struct wfx_tx_policy_cache
*cache
= &wvif
->tx_policy_cache
;
140 if (idx
== HIF_TX_RETRY_POLICY_INVALID
)
142 spin_lock_bh(&cache
->lock
);
143 locked
= list_empty(&cache
->free
);
144 usage
= wfx_tx_policy_release(cache
, &cache
->cache
[idx
]);
145 if (locked
&& !usage
)
146 ieee80211_wake_queues(wvif
->wdev
->hw
);
147 spin_unlock_bh(&cache
->lock
);
150 static int wfx_tx_policy_upload(struct wfx_vif
*wvif
)
152 struct wfx_tx_policy
*policies
= wvif
->tx_policy_cache
.cache
;
157 spin_lock_bh(&wvif
->tx_policy_cache
.lock
);
158 for (i
= 0; i
< ARRAY_SIZE(wvif
->tx_policy_cache
.cache
); ++i
) {
159 is_used
= memzcmp(policies
[i
].rates
, sizeof(policies
[i
].rates
));
160 if (!policies
[i
].uploaded
&& is_used
)
163 if (i
< ARRAY_SIZE(wvif
->tx_policy_cache
.cache
)) {
164 policies
[i
].uploaded
= true;
165 memcpy(tmp_rates
, policies
[i
].rates
, sizeof(tmp_rates
));
166 spin_unlock_bh(&wvif
->tx_policy_cache
.lock
);
167 wfx_hif_set_tx_rate_retry_policy(wvif
, i
, tmp_rates
);
169 spin_unlock_bh(&wvif
->tx_policy_cache
.lock
);
171 } while (i
< ARRAY_SIZE(wvif
->tx_policy_cache
.cache
));
175 void wfx_tx_policy_upload_work(struct work_struct
*work
)
177 struct wfx_vif
*wvif
= container_of(work
, struct wfx_vif
, tx_policy_upload_work
);
179 wfx_tx_policy_upload(wvif
);
180 wfx_tx_unlock(wvif
->wdev
);
183 void wfx_tx_policy_init(struct wfx_vif
*wvif
)
185 struct wfx_tx_policy_cache
*cache
= &wvif
->tx_policy_cache
;
188 memset(cache
, 0, sizeof(*cache
));
190 spin_lock_init(&cache
->lock
);
191 INIT_LIST_HEAD(&cache
->used
);
192 INIT_LIST_HEAD(&cache
->free
);
194 for (i
= 0; i
< ARRAY_SIZE(cache
->cache
); ++i
)
195 list_add(&cache
->cache
[i
].link
, &cache
->free
);
198 /* Tx implementation */
200 static bool wfx_is_action_back(struct ieee80211_hdr
*hdr
)
202 struct ieee80211_mgmt
*mgmt
= (struct ieee80211_mgmt
*)hdr
;
204 if (!ieee80211_is_action(mgmt
->frame_control
))
206 if (mgmt
->u
.action
.category
!= WLAN_CATEGORY_BACK
)
211 struct wfx_tx_priv
*wfx_skb_tx_priv(struct sk_buff
*skb
)
213 struct ieee80211_tx_info
*tx_info
;
217 tx_info
= IEEE80211_SKB_CB(skb
);
218 return (struct wfx_tx_priv
*)tx_info
->rate_driver_data
;
221 struct wfx_hif_req_tx
*wfx_skb_txreq(struct sk_buff
*skb
)
223 struct wfx_hif_msg
*hif
= (struct wfx_hif_msg
*)skb
->data
;
224 struct wfx_hif_req_tx
*req
= (struct wfx_hif_req_tx
*)hif
->body
;
229 struct wfx_vif
*wfx_skb_wvif(struct wfx_dev
*wdev
, struct sk_buff
*skb
)
231 struct wfx_tx_priv
*tx_priv
= wfx_skb_tx_priv(skb
);
232 struct wfx_hif_msg
*hif
= (struct wfx_hif_msg
*)skb
->data
;
234 if (tx_priv
->vif_id
!= hif
->interface
&& hif
->interface
!= 2) {
235 dev_err(wdev
->dev
, "corrupted skb");
236 return wdev_to_wvif(wdev
, hif
->interface
);
238 return wdev_to_wvif(wdev
, tx_priv
->vif_id
);
241 static u8
wfx_tx_get_link_id(struct wfx_vif
*wvif
, struct ieee80211_sta
*sta
,
242 struct ieee80211_hdr
*hdr
)
244 struct wfx_sta_priv
*sta_priv
= sta
? (struct wfx_sta_priv
*)&sta
->drv_priv
: NULL
;
245 struct ieee80211_vif
*vif
= wvif_to_vif(wvif
);
246 const u8
*da
= ieee80211_get_DA(hdr
);
248 if (sta_priv
&& sta_priv
->link_id
)
249 return sta_priv
->link_id
;
250 if (vif
->type
!= NL80211_IFTYPE_AP
)
252 if (is_multicast_ether_addr(da
))
254 return HIF_LINK_ID_NOT_ASSOCIATED
;
257 static void wfx_tx_fixup_rates(struct ieee80211_tx_rate
*rates
)
259 bool has_rate0
= false;
262 for (i
= 1, j
= 1; j
< IEEE80211_TX_MAX_RATES
; j
++) {
263 if (rates
[j
].idx
== -1)
265 /* The device use the rates in descending order, whatever the request from minstrel.
266 * We have to trade off here. Most important is to respect the primary rate
267 * requested by minstrel. So, we drops the entries with rate higher than the
270 if (rates
[j
].idx
>= rates
[i
- 1].idx
) {
271 rates
[i
- 1].count
+= rates
[j
].count
;
272 rates
[i
- 1].count
= min_t(u16
, 15, rates
[i
- 1].count
);
274 memcpy(rates
+ i
, rates
+ j
, sizeof(rates
[i
]));
275 if (rates
[i
].idx
== 0)
277 /* The device apply Short GI only on the first rate */
278 rates
[i
].flags
&= ~IEEE80211_TX_RC_SHORT_GI
;
282 /* Ensure that MCS0 or 1Mbps is present at the end of the retry list */
283 if (!has_rate0
&& i
< IEEE80211_TX_MAX_RATES
) {
285 rates
[i
].count
= 8; /* == hw->max_rate_tries */
286 rates
[i
].flags
= rates
[0].flags
& IEEE80211_TX_RC_MCS
;
289 for (; i
< IEEE80211_TX_MAX_RATES
; i
++) {
290 memset(rates
+ i
, 0, sizeof(rates
[i
]));
295 static u8
wfx_tx_get_retry_policy_id(struct wfx_vif
*wvif
, struct ieee80211_tx_info
*tx_info
)
297 bool tx_policy_renew
= false;
300 ret
= wfx_tx_policy_get(wvif
, tx_info
->driver_rates
, &tx_policy_renew
);
301 if (ret
== HIF_TX_RETRY_POLICY_INVALID
)
302 dev_warn(wvif
->wdev
->dev
, "unable to get a valid Tx policy");
304 if (tx_policy_renew
) {
305 wfx_tx_lock(wvif
->wdev
);
306 if (!schedule_work(&wvif
->tx_policy_upload_work
))
307 wfx_tx_unlock(wvif
->wdev
);
312 static int wfx_tx_get_frame_format(struct ieee80211_tx_info
*tx_info
)
314 if (!(tx_info
->driver_rates
[0].flags
& IEEE80211_TX_RC_MCS
))
315 return HIF_FRAME_FORMAT_NON_HT
;
316 else if (!(tx_info
->driver_rates
[0].flags
& IEEE80211_TX_RC_GREEN_FIELD
))
317 return HIF_FRAME_FORMAT_MIXED_FORMAT_HT
;
319 return HIF_FRAME_FORMAT_GF_HT_11N
;
322 static int wfx_tx_get_icv_len(struct ieee80211_key_conf
*hw_key
)
328 if (hw_key
->cipher
== WLAN_CIPHER_SUITE_AES_CMAC
)
330 mic_space
= (hw_key
->cipher
== WLAN_CIPHER_SUITE_TKIP
) ? 8 : 0;
331 return hw_key
->icv_len
+ mic_space
;
334 static int wfx_tx_inner(struct wfx_vif
*wvif
, struct ieee80211_sta
*sta
, struct sk_buff
*skb
)
336 struct wfx_hif_msg
*hif_msg
;
337 struct wfx_hif_req_tx
*req
;
338 struct wfx_tx_priv
*tx_priv
;
339 struct ieee80211_tx_info
*tx_info
= IEEE80211_SKB_CB(skb
);
340 struct ieee80211_key_conf
*hw_key
= tx_info
->control
.hw_key
;
341 struct ieee80211_hdr
*hdr
= (struct ieee80211_hdr
*)skb
->data
;
342 int queue_id
= skb_get_queue_mapping(skb
);
343 size_t offset
= (size_t)skb
->data
& 3;
344 int wmsg_len
= sizeof(struct wfx_hif_msg
) + sizeof(struct wfx_hif_req_tx
) + offset
;
346 WARN(queue_id
>= IEEE80211_NUM_ACS
, "unsupported queue_id");
347 wfx_tx_fixup_rates(tx_info
->driver_rates
);
349 /* From now tx_info->control is unusable */
350 memset(tx_info
->rate_driver_data
, 0, sizeof(struct wfx_tx_priv
));
352 tx_priv
= (struct wfx_tx_priv
*)tx_info
->rate_driver_data
;
353 tx_priv
->icv_size
= wfx_tx_get_icv_len(hw_key
);
354 tx_priv
->vif_id
= wvif
->id
;
357 WARN(skb_headroom(skb
) < wmsg_len
, "not enough space in skb");
358 WARN(offset
& 1, "attempt to transmit an unaligned frame");
359 skb_put(skb
, tx_priv
->icv_size
);
360 skb_push(skb
, wmsg_len
);
361 memset(skb
->data
, 0, wmsg_len
);
362 hif_msg
= (struct wfx_hif_msg
*)skb
->data
;
363 hif_msg
->len
= cpu_to_le16(skb
->len
);
364 hif_msg
->id
= HIF_REQ_ID_TX
;
365 if (tx_info
->flags
& IEEE80211_TX_CTL_TX_OFFCHAN
)
366 hif_msg
->interface
= 2;
368 hif_msg
->interface
= wvif
->id
;
369 if (skb
->len
> le16_to_cpu(wvif
->wdev
->hw_caps
.size_inp_ch_buf
)) {
370 dev_warn(wvif
->wdev
->dev
,
371 "requested frame size (%d) is larger than maximum supported (%d)\n",
372 skb
->len
, le16_to_cpu(wvif
->wdev
->hw_caps
.size_inp_ch_buf
));
373 skb_pull(skb
, wmsg_len
);
377 /* Fill tx request */
378 req
= (struct wfx_hif_req_tx
*)hif_msg
->body
;
379 /* packet_id just need to be unique on device. 32bits are more than necessary for that task,
380 * so we take advantage of it to add some extra data for debug.
382 req
->packet_id
= atomic_add_return(1, &wvif
->wdev
->packet_id
) & 0xFFFF;
383 req
->packet_id
|= IEEE80211_SEQ_TO_SN(le16_to_cpu(hdr
->seq_ctrl
)) << 16;
384 req
->packet_id
|= queue_id
<< 28;
386 req
->fc_offset
= offset
;
387 /* Queue index are inverted between firmware and Linux */
388 req
->queue_id
= 3 - queue_id
;
389 if (tx_info
->flags
& IEEE80211_TX_CTL_TX_OFFCHAN
) {
390 req
->peer_sta_id
= HIF_LINK_ID_NOT_ASSOCIATED
;
391 req
->retry_policy_index
= HIF_TX_RETRY_POLICY_INVALID
;
392 req
->frame_format
= HIF_FRAME_FORMAT_NON_HT
;
394 req
->peer_sta_id
= wfx_tx_get_link_id(wvif
, sta
, hdr
);
395 req
->retry_policy_index
= wfx_tx_get_retry_policy_id(wvif
, tx_info
);
396 req
->frame_format
= wfx_tx_get_frame_format(tx_info
);
398 if (tx_info
->driver_rates
[0].flags
& IEEE80211_TX_RC_SHORT_GI
)
400 if (tx_info
->flags
& IEEE80211_TX_CTL_SEND_AFTER_DTIM
)
403 /* Auxiliary operations */
404 wfx_tx_queues_put(wvif
, skb
);
405 if (tx_info
->flags
& IEEE80211_TX_CTL_SEND_AFTER_DTIM
)
406 schedule_work(&wvif
->update_tim_work
);
407 wfx_bh_request_tx(wvif
->wdev
);
411 void wfx_tx(struct ieee80211_hw
*hw
, struct ieee80211_tx_control
*control
, struct sk_buff
*skb
)
413 struct wfx_dev
*wdev
= hw
->priv
;
414 struct wfx_vif
*wvif
;
415 struct ieee80211_sta
*sta
= control
? control
->sta
: NULL
;
416 struct ieee80211_tx_info
*tx_info
= IEEE80211_SKB_CB(skb
);
417 struct ieee80211_hdr
*hdr
= (struct ieee80211_hdr
*)skb
->data
;
418 size_t driver_data_room
= sizeof_field(struct ieee80211_tx_info
, rate_driver_data
);
420 BUILD_BUG_ON_MSG(sizeof(struct wfx_tx_priv
) > driver_data_room
,
421 "struct tx_priv is too large");
422 WARN(skb
->next
|| skb
->prev
, "skb is already member of a list");
423 /* control.vif can be NULL for injected frames */
424 if (tx_info
->control
.vif
)
425 wvif
= (struct wfx_vif
*)tx_info
->control
.vif
->drv_priv
;
427 wvif
= wvif_iterate(wdev
, NULL
);
430 /* Because of TX_AMPDU_SETUP_IN_HW, mac80211 does not try to send any BlockAck session
431 * management frame. The check below exist just in case.
433 if (wfx_is_action_back(hdr
)) {
434 dev_info(wdev
->dev
, "drop BA action\n");
437 if (wfx_tx_inner(wvif
, sta
, skb
))
443 ieee80211_tx_status_irqsafe(wdev
->hw
, skb
);
446 static void wfx_skb_dtor(struct wfx_vif
*wvif
, struct sk_buff
*skb
)
448 struct wfx_hif_msg
*hif
= (struct wfx_hif_msg
*)skb
->data
;
449 struct wfx_hif_req_tx
*req
= (struct wfx_hif_req_tx
*)hif
->body
;
450 unsigned int offset
= sizeof(struct wfx_hif_msg
) + sizeof(struct wfx_hif_req_tx
) +
454 pr_warn("vif associated with the skb does not exist anymore\n");
457 wfx_tx_policy_put(wvif
, req
->retry_policy_index
);
458 skb_pull(skb
, offset
);
459 ieee80211_tx_status_irqsafe(wvif
->wdev
->hw
, skb
);
462 static void wfx_tx_fill_rates(struct wfx_dev
*wdev
, struct ieee80211_tx_info
*tx_info
,
463 const struct wfx_hif_cnf_tx
*arg
)
465 struct ieee80211_tx_rate
*rate
;
469 tx_count
= arg
->ack_failures
;
470 if (!arg
->status
|| arg
->ack_failures
)
471 tx_count
+= 1; /* Also report success */
472 for (i
= 0; i
< IEEE80211_TX_MAX_RATES
; i
++) {
473 rate
= &tx_info
->status
.rates
[i
];
476 if (tx_count
< rate
->count
&& arg
->status
== HIF_STATUS_TX_FAIL_RETRIES
&&
478 dev_dbg(wdev
->dev
, "all retries were not consumed: %d != %d\n",
479 rate
->count
, tx_count
);
480 if (tx_count
<= rate
->count
&& tx_count
&&
481 arg
->txed_rate
!= wfx_get_hw_rate(wdev
, rate
))
482 dev_dbg(wdev
->dev
, "inconsistent tx_info rates: %d != %d\n",
483 arg
->txed_rate
, wfx_get_hw_rate(wdev
, rate
));
484 if (tx_count
> rate
->count
) {
485 tx_count
-= rate
->count
;
486 } else if (!tx_count
) {
490 rate
->count
= tx_count
;
495 dev_dbg(wdev
->dev
, "%d more retries than expected\n", tx_count
);
498 void wfx_tx_confirm_cb(struct wfx_dev
*wdev
, const struct wfx_hif_cnf_tx
*arg
)
500 const struct wfx_tx_priv
*tx_priv
;
501 struct ieee80211_tx_info
*tx_info
;
502 struct wfx_vif
*wvif
;
505 skb
= wfx_pending_get(wdev
, arg
->packet_id
);
507 dev_warn(wdev
->dev
, "received unknown packet_id (%#.8x) from chip\n",
511 tx_info
= IEEE80211_SKB_CB(skb
);
512 tx_priv
= wfx_skb_tx_priv(skb
);
513 wvif
= wfx_skb_wvif(wdev
, skb
);
518 /* Note that wfx_pending_get_pkt_us_delay() get data from tx_info */
519 _trace_tx_stats(arg
, skb
, wfx_pending_get_pkt_us_delay(wdev
, skb
));
520 wfx_tx_fill_rates(wdev
, tx_info
, arg
);
521 skb_trim(skb
, skb
->len
- tx_priv
->icv_size
);
523 /* From now, you can touch to tx_info->status, but do not touch to tx_priv anymore */
524 /* FIXME: use ieee80211_tx_info_clear_status() */
525 memset(tx_info
->rate_driver_data
, 0, sizeof(tx_info
->rate_driver_data
));
526 memset(tx_info
->pad
, 0, sizeof(tx_info
->pad
));
529 tx_info
->status
.tx_time
= le32_to_cpu(arg
->media_delay
) -
530 le32_to_cpu(arg
->tx_queue_delay
);
531 if (tx_info
->flags
& IEEE80211_TX_CTL_NO_ACK
)
532 tx_info
->flags
|= IEEE80211_TX_STAT_NOACK_TRANSMITTED
;
534 tx_info
->flags
|= IEEE80211_TX_STAT_ACK
;
535 } else if (arg
->status
== HIF_STATUS_TX_FAIL_REQUEUE
) {
536 WARN(!arg
->requeue
, "incoherent status and result_flags");
537 if (tx_info
->flags
& IEEE80211_TX_CTL_SEND_AFTER_DTIM
) {
538 wvif
->after_dtim_tx_allowed
= false; /* DTIM period elapsed */
539 schedule_work(&wvif
->update_tim_work
);
541 tx_info
->flags
|= IEEE80211_TX_STAT_TX_FILTERED
;
543 wfx_skb_dtor(wvif
, skb
);
546 static void wfx_flush_vif(struct wfx_vif
*wvif
, u32 queues
, struct sk_buff_head
*dropped
)
548 struct wfx_queue
*queue
;
551 for (i
= 0; i
< IEEE80211_NUM_ACS
; i
++) {
552 if (!(BIT(i
) & queues
))
554 queue
= &wvif
->tx_queue
[i
];
556 wfx_tx_queue_drop(wvif
, queue
, dropped
);
558 if (wvif
->wdev
->chip_frozen
)
560 for (i
= 0; i
< IEEE80211_NUM_ACS
; i
++) {
561 if (!(BIT(i
) & queues
))
563 queue
= &wvif
->tx_queue
[i
];
564 if (wait_event_timeout(wvif
->wdev
->tx_dequeue
, wfx_tx_queue_empty(wvif
, queue
),
565 msecs_to_jiffies(1000)) <= 0)
566 dev_warn(wvif
->wdev
->dev
, "frames queued while flushing tx queues?");
570 void wfx_flush(struct ieee80211_hw
*hw
, struct ieee80211_vif
*vif
, u32 queues
, bool drop
)
572 struct wfx_dev
*wdev
= hw
->priv
;
573 struct sk_buff_head dropped
;
574 struct wfx_vif
*wvif
;
577 skb_queue_head_init(&dropped
);
579 wvif
= (struct wfx_vif
*)vif
->drv_priv
;
580 wfx_flush_vif(wvif
, queues
, drop
? &dropped
: NULL
);
583 while ((wvif
= wvif_iterate(wdev
, wvif
)) != NULL
)
584 wfx_flush_vif(wvif
, queues
, drop
? &dropped
: NULL
);
587 if (wdev
->chip_frozen
)
588 wfx_pending_drop(wdev
, &dropped
);
589 while ((skb
= skb_dequeue(&dropped
)) != NULL
) {
590 wvif
= wfx_skb_wvif(wdev
, skb
);
591 ieee80211_tx_info_clear_status(IEEE80211_SKB_CB(skb
));
592 wfx_skb_dtor(wvif
, skb
);