GNU Linux-libre 5.19-rc6-gnu
[releases.git] / drivers / net / wireless / broadcom / b43legacy / xmit.c
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3
4   Broadcom B43legacy wireless driver
5
6   Transmission (TX/RX) related functions.
7
8   Copyright (C) 2005 Martin Langer <martin-langer@gmx.de>
9   Copyright (C) 2005 Stefano Brivio <stefano.brivio@polimi.it>
10   Copyright (C) 2005, 2006 Michael Buesch <m@bues.ch>
11   Copyright (C) 2005 Danny van Dyk <kugelfang@gentoo.org>
12   Copyright (C) 2005 Andreas Jaggi <andreas.jaggi@waterwave.ch>
13   Copyright (C) 2007 Larry Finger <Larry.Finger@lwfinger.net>
14
15
16 */
17
18 #include <net/dst.h>
19
20 #include "xmit.h"
21 #include "phy.h"
22 #include "dma.h"
23 #include "pio.h"
24
25
26 /* Extract the bitrate out of a CCK PLCP header. */
27 static u8 b43legacy_plcp_get_bitrate_idx_cck(struct b43legacy_plcp_hdr6 *plcp)
28 {
29         switch (plcp->raw[0]) {
30         case 0x0A:
31                 return 0;
32         case 0x14:
33                 return 1;
34         case 0x37:
35                 return 2;
36         case 0x6E:
37                 return 3;
38         }
39         B43legacy_BUG_ON(1);
40         return -1;
41 }
42
43 /* Extract the bitrate out of an OFDM PLCP header. */
44 static u8 b43legacy_plcp_get_bitrate_idx_ofdm(struct b43legacy_plcp_hdr6 *plcp,
45                                               bool aphy)
46 {
47         int base = aphy ? 0 : 4;
48
49         switch (plcp->raw[0] & 0xF) {
50         case 0xB:
51                 return base + 0;
52         case 0xF:
53                 return base + 1;
54         case 0xA:
55                 return base + 2;
56         case 0xE:
57                 return base + 3;
58         case 0x9:
59                 return base + 4;
60         case 0xD:
61                 return base + 5;
62         case 0x8:
63                 return base + 6;
64         case 0xC:
65                 return base + 7;
66         }
67         B43legacy_BUG_ON(1);
68         return -1;
69 }
70
71 u8 b43legacy_plcp_get_ratecode_cck(const u8 bitrate)
72 {
73         switch (bitrate) {
74         case B43legacy_CCK_RATE_1MB:
75                 return 0x0A;
76         case B43legacy_CCK_RATE_2MB:
77                 return 0x14;
78         case B43legacy_CCK_RATE_5MB:
79                 return 0x37;
80         case B43legacy_CCK_RATE_11MB:
81                 return 0x6E;
82         }
83         B43legacy_BUG_ON(1);
84         return 0;
85 }
86
87 u8 b43legacy_plcp_get_ratecode_ofdm(const u8 bitrate)
88 {
89         switch (bitrate) {
90         case B43legacy_OFDM_RATE_6MB:
91                 return 0xB;
92         case B43legacy_OFDM_RATE_9MB:
93                 return 0xF;
94         case B43legacy_OFDM_RATE_12MB:
95                 return 0xA;
96         case B43legacy_OFDM_RATE_18MB:
97                 return 0xE;
98         case B43legacy_OFDM_RATE_24MB:
99                 return 0x9;
100         case B43legacy_OFDM_RATE_36MB:
101                 return 0xD;
102         case B43legacy_OFDM_RATE_48MB:
103                 return 0x8;
104         case B43legacy_OFDM_RATE_54MB:
105                 return 0xC;
106         }
107         B43legacy_BUG_ON(1);
108         return 0;
109 }
110
111 void b43legacy_generate_plcp_hdr(struct b43legacy_plcp_hdr4 *plcp,
112                                  const u16 octets, const u8 bitrate)
113 {
114         __le32 *data = &(plcp->data);
115         __u8 *raw = plcp->raw;
116
117         if (b43legacy_is_ofdm_rate(bitrate)) {
118                 u16 d;
119
120                 d = b43legacy_plcp_get_ratecode_ofdm(bitrate);
121                 B43legacy_WARN_ON(octets & 0xF000);
122                 d |= (octets << 5);
123                 *data = cpu_to_le32(d);
124         } else {
125                 u32 plen;
126
127                 plen = octets * 16 / bitrate;
128                 if ((octets * 16 % bitrate) > 0) {
129                         plen++;
130                         if ((bitrate == B43legacy_CCK_RATE_11MB)
131                             && ((octets * 8 % 11) < 4))
132                                 raw[1] = 0x84;
133                         else
134                                 raw[1] = 0x04;
135                 } else
136                         raw[1] = 0x04;
137                 *data |= cpu_to_le32(plen << 16);
138                 raw[0] = b43legacy_plcp_get_ratecode_cck(bitrate);
139         }
140 }
141
142 static u8 b43legacy_calc_fallback_rate(u8 bitrate)
143 {
144         switch (bitrate) {
145         case B43legacy_CCK_RATE_1MB:
146                 return B43legacy_CCK_RATE_1MB;
147         case B43legacy_CCK_RATE_2MB:
148                 return B43legacy_CCK_RATE_1MB;
149         case B43legacy_CCK_RATE_5MB:
150                 return B43legacy_CCK_RATE_2MB;
151         case B43legacy_CCK_RATE_11MB:
152                 return B43legacy_CCK_RATE_5MB;
153         case B43legacy_OFDM_RATE_6MB:
154                 return B43legacy_CCK_RATE_5MB;
155         case B43legacy_OFDM_RATE_9MB:
156                 return B43legacy_OFDM_RATE_6MB;
157         case B43legacy_OFDM_RATE_12MB:
158                 return B43legacy_OFDM_RATE_9MB;
159         case B43legacy_OFDM_RATE_18MB:
160                 return B43legacy_OFDM_RATE_12MB;
161         case B43legacy_OFDM_RATE_24MB:
162                 return B43legacy_OFDM_RATE_18MB;
163         case B43legacy_OFDM_RATE_36MB:
164                 return B43legacy_OFDM_RATE_24MB;
165         case B43legacy_OFDM_RATE_48MB:
166                 return B43legacy_OFDM_RATE_36MB;
167         case B43legacy_OFDM_RATE_54MB:
168                 return B43legacy_OFDM_RATE_48MB;
169         }
170         B43legacy_BUG_ON(1);
171         return 0;
172 }
173
174 static int generate_txhdr_fw3(struct b43legacy_wldev *dev,
175                                struct b43legacy_txhdr_fw3 *txhdr,
176                                const unsigned char *fragment_data,
177                                unsigned int fragment_len,
178                                struct ieee80211_tx_info *info,
179                                u16 cookie)
180 {
181         const struct ieee80211_hdr *wlhdr;
182         int use_encryption = !!info->control.hw_key;
183         u8 rate;
184         struct ieee80211_rate *rate_fb;
185         int rate_ofdm;
186         int rate_fb_ofdm;
187         unsigned int plcp_fragment_len;
188         u32 mac_ctl = 0;
189         u16 phy_ctl = 0;
190         struct ieee80211_rate *tx_rate;
191         struct ieee80211_tx_rate *rates;
192
193         wlhdr = (const struct ieee80211_hdr *)fragment_data;
194
195         memset(txhdr, 0, sizeof(*txhdr));
196
197         tx_rate = ieee80211_get_tx_rate(dev->wl->hw, info);
198
199         rate = tx_rate->hw_value;
200         rate_ofdm = b43legacy_is_ofdm_rate(rate);
201         rate_fb = ieee80211_get_alt_retry_rate(dev->wl->hw, info, 0) ? : tx_rate;
202         rate_fb_ofdm = b43legacy_is_ofdm_rate(rate_fb->hw_value);
203
204         txhdr->mac_frame_ctl = wlhdr->frame_control;
205         memcpy(txhdr->tx_receiver, wlhdr->addr1, ETH_ALEN);
206
207         /* Calculate duration for fallback rate */
208         if ((rate_fb->hw_value == rate) ||
209             (wlhdr->duration_id & cpu_to_le16(0x8000)) ||
210             (wlhdr->duration_id == cpu_to_le16(0))) {
211                 /* If the fallback rate equals the normal rate or the
212                  * dur_id field contains an AID, CFP magic or 0,
213                  * use the original dur_id field. */
214                 txhdr->dur_fb = wlhdr->duration_id;
215         } else {
216                 txhdr->dur_fb = ieee80211_generic_frame_duration(dev->wl->hw,
217                                                          info->control.vif,
218                                                          info->band,
219                                                          fragment_len,
220                                                          rate_fb);
221         }
222
223         plcp_fragment_len = fragment_len + FCS_LEN;
224         if (use_encryption) {
225                 u8 key_idx = info->control.hw_key->hw_key_idx;
226                 struct b43legacy_key *key;
227                 int wlhdr_len;
228                 size_t iv_len;
229
230                 B43legacy_WARN_ON(key_idx >= dev->max_nr_keys);
231                 key = &(dev->key[key_idx]);
232
233                 if (key->enabled) {
234                         /* Hardware appends ICV. */
235                         plcp_fragment_len += info->control.hw_key->icv_len;
236
237                         key_idx = b43legacy_kidx_to_fw(dev, key_idx);
238                         mac_ctl |= (key_idx << B43legacy_TX4_MAC_KEYIDX_SHIFT) &
239                                    B43legacy_TX4_MAC_KEYIDX;
240                         mac_ctl |= (key->algorithm <<
241                                    B43legacy_TX4_MAC_KEYALG_SHIFT) &
242                                    B43legacy_TX4_MAC_KEYALG;
243                         wlhdr_len = ieee80211_hdrlen(wlhdr->frame_control);
244                         iv_len = min_t(size_t, info->control.hw_key->iv_len,
245                                      ARRAY_SIZE(txhdr->iv));
246                         memcpy(txhdr->iv, ((u8 *)wlhdr) + wlhdr_len, iv_len);
247                 } else {
248                         /* This key is invalid. This might only happen
249                          * in a short timeframe after machine resume before
250                          * we were able to reconfigure keys.
251                          * Drop this packet completely. Do not transmit it
252                          * unencrypted to avoid leaking information. */
253                         return -ENOKEY;
254                 }
255         }
256         b43legacy_generate_plcp_hdr((struct b43legacy_plcp_hdr4 *)
257                                     (&txhdr->plcp), plcp_fragment_len,
258                                     rate);
259         b43legacy_generate_plcp_hdr(&txhdr->plcp_fb, plcp_fragment_len,
260                                     rate_fb->hw_value);
261
262         /* PHY TX Control word */
263         if (rate_ofdm)
264                 phy_ctl |= B43legacy_TX4_PHY_ENC_OFDM;
265         if (info->control.rates[0].flags & IEEE80211_TX_RC_USE_SHORT_PREAMBLE)
266                 phy_ctl |= B43legacy_TX4_PHY_SHORTPRMBL;
267         phy_ctl |= B43legacy_TX4_PHY_ANTLAST;
268
269         /* MAC control */
270         rates = info->control.rates;
271         if (!(info->flags & IEEE80211_TX_CTL_NO_ACK))
272                 mac_ctl |= B43legacy_TX4_MAC_ACK;
273         if (info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ)
274                 mac_ctl |= B43legacy_TX4_MAC_HWSEQ;
275         if (info->flags & IEEE80211_TX_CTL_FIRST_FRAGMENT)
276                 mac_ctl |= B43legacy_TX4_MAC_STMSDU;
277         if (rate_fb_ofdm)
278                 mac_ctl |= B43legacy_TX4_MAC_FALLBACKOFDM;
279
280         /* Overwrite rates[0].count to make the retry calculation
281          * in the tx status easier. need the actual retry limit to
282          * detect whether the fallback rate was used.
283          */
284         if ((rates[0].flags & IEEE80211_TX_RC_USE_RTS_CTS) ||
285             (rates[0].count <= dev->wl->hw->conf.long_frame_max_tx_count)) {
286                 rates[0].count = dev->wl->hw->conf.long_frame_max_tx_count;
287                 mac_ctl |= B43legacy_TX4_MAC_LONGFRAME;
288         } else {
289                 rates[0].count = dev->wl->hw->conf.short_frame_max_tx_count;
290         }
291
292         /* Generate the RTS or CTS-to-self frame */
293         if ((rates[0].flags & IEEE80211_TX_RC_USE_RTS_CTS) ||
294             (rates[0].flags & IEEE80211_TX_RC_USE_CTS_PROTECT)) {
295                 unsigned int len;
296                 struct ieee80211_hdr *hdr;
297                 int rts_rate;
298                 int rts_rate_fb;
299                 int rts_rate_fb_ofdm;
300
301                 rts_rate = ieee80211_get_rts_cts_rate(dev->wl->hw, info)->hw_value;
302                 rts_rate_fb = b43legacy_calc_fallback_rate(rts_rate);
303                 rts_rate_fb_ofdm = b43legacy_is_ofdm_rate(rts_rate_fb);
304                 if (rts_rate_fb_ofdm)
305                         mac_ctl |= B43legacy_TX4_MAC_CTSFALLBACKOFDM;
306
307                 if (rates[0].flags & IEEE80211_TX_RC_USE_CTS_PROTECT) {
308                         ieee80211_ctstoself_get(dev->wl->hw,
309                                                 info->control.vif,
310                                                 fragment_data,
311                                                 fragment_len, info,
312                                                 (struct ieee80211_cts *)
313                                                 (txhdr->rts_frame));
314                         mac_ctl |= B43legacy_TX4_MAC_SENDCTS;
315                         len = sizeof(struct ieee80211_cts);
316                 } else {
317                         ieee80211_rts_get(dev->wl->hw,
318                                           info->control.vif,
319                                           fragment_data, fragment_len, info,
320                                           (struct ieee80211_rts *)
321                                           (txhdr->rts_frame));
322                         mac_ctl |= B43legacy_TX4_MAC_SENDRTS;
323                         len = sizeof(struct ieee80211_rts);
324                 }
325                 len += FCS_LEN;
326                 b43legacy_generate_plcp_hdr((struct b43legacy_plcp_hdr4 *)
327                                             (&txhdr->rts_plcp),
328                                             len, rts_rate);
329                 b43legacy_generate_plcp_hdr(&txhdr->rts_plcp_fb,
330                                             len, rts_rate_fb);
331                 hdr = (struct ieee80211_hdr *)(&txhdr->rts_frame);
332                 txhdr->rts_dur_fb = hdr->duration_id;
333         }
334
335         /* Magic cookie */
336         txhdr->cookie = cpu_to_le16(cookie);
337
338         /* Apply the bitfields */
339         txhdr->mac_ctl = cpu_to_le32(mac_ctl);
340         txhdr->phy_ctl = cpu_to_le16(phy_ctl);
341
342         return 0;
343 }
344
345 int b43legacy_generate_txhdr(struct b43legacy_wldev *dev,
346                               u8 *txhdr,
347                               const unsigned char *fragment_data,
348                               unsigned int fragment_len,
349                               struct ieee80211_tx_info *info,
350                               u16 cookie)
351 {
352         return generate_txhdr_fw3(dev, (struct b43legacy_txhdr_fw3 *)txhdr,
353                            fragment_data, fragment_len,
354                            info, cookie);
355 }
356
357 static s8 b43legacy_rssi_postprocess(struct b43legacy_wldev *dev,
358                                      u8 in_rssi, int ofdm,
359                                      int adjust_2053, int adjust_2050)
360 {
361         struct b43legacy_phy *phy = &dev->phy;
362         s32 tmp;
363
364         switch (phy->radio_ver) {
365         case 0x2050:
366                 if (ofdm) {
367                         tmp = in_rssi;
368                         if (tmp > 127)
369                                 tmp -= 256;
370                         tmp *= 73;
371                         tmp /= 64;
372                         if (adjust_2050)
373                                 tmp += 25;
374                         else
375                                 tmp -= 3;
376                 } else {
377                         if (dev->dev->bus->sprom.boardflags_lo
378                             & B43legacy_BFL_RSSI) {
379                                 if (in_rssi > 63)
380                                         in_rssi = 63;
381                                 tmp = phy->nrssi_lt[in_rssi];
382                                 tmp = 31 - tmp;
383                                 tmp *= -131;
384                                 tmp /= 128;
385                                 tmp -= 57;
386                         } else {
387                                 tmp = in_rssi;
388                                 tmp = 31 - tmp;
389                                 tmp *= -149;
390                                 tmp /= 128;
391                                 tmp -= 68;
392                         }
393                         if (phy->type == B43legacy_PHYTYPE_G &&
394                             adjust_2050)
395                                 tmp += 25;
396                 }
397                 break;
398         case 0x2060:
399                 if (in_rssi > 127)
400                         tmp = in_rssi - 256;
401                 else
402                         tmp = in_rssi;
403                 break;
404         default:
405                 tmp = in_rssi;
406                 tmp -= 11;
407                 tmp *= 103;
408                 tmp /= 64;
409                 if (adjust_2053)
410                         tmp -= 109;
411                 else
412                         tmp -= 83;
413         }
414
415         return (s8)tmp;
416 }
417
418 void b43legacy_rx(struct b43legacy_wldev *dev,
419                   struct sk_buff *skb,
420                   const void *_rxhdr)
421 {
422         struct ieee80211_rx_status status;
423         struct b43legacy_plcp_hdr6 *plcp;
424         struct ieee80211_hdr *wlhdr;
425         const struct b43legacy_rxhdr_fw3 *rxhdr = _rxhdr;
426         __le16 fctl;
427         u16 phystat0;
428         u16 phystat3;
429         u16 chanstat;
430         u16 mactime;
431         u32 macstat;
432         u16 chanid;
433         u8 jssi;
434         int padding;
435
436         memset(&status, 0, sizeof(status));
437
438         /* Get metadata about the frame from the header. */
439         phystat0 = le16_to_cpu(rxhdr->phy_status0);
440         phystat3 = le16_to_cpu(rxhdr->phy_status3);
441         jssi = rxhdr->jssi;
442         macstat = le16_to_cpu(rxhdr->mac_status);
443         mactime = le16_to_cpu(rxhdr->mac_time);
444         chanstat = le16_to_cpu(rxhdr->channel);
445
446         if (macstat & B43legacy_RX_MAC_FCSERR)
447                 dev->wl->ieee_stats.dot11FCSErrorCount++;
448
449         /* Skip PLCP and padding */
450         padding = (macstat & B43legacy_RX_MAC_PADDING) ? 2 : 0;
451         if (unlikely(skb->len < (sizeof(struct b43legacy_plcp_hdr6) +
452             padding))) {
453                 b43legacydbg(dev->wl, "RX: Packet size underrun (1)\n");
454                 goto drop;
455         }
456         plcp = (struct b43legacy_plcp_hdr6 *)(skb->data + padding);
457         skb_pull(skb, sizeof(struct b43legacy_plcp_hdr6) + padding);
458         /* The skb contains the Wireless Header + payload data now */
459         if (unlikely(skb->len < (2+2+6/*minimum hdr*/ + FCS_LEN))) {
460                 b43legacydbg(dev->wl, "RX: Packet size underrun (2)\n");
461                 goto drop;
462         }
463         wlhdr = (struct ieee80211_hdr *)(skb->data);
464         fctl = wlhdr->frame_control;
465
466         if ((macstat & B43legacy_RX_MAC_DEC) &&
467             !(macstat & B43legacy_RX_MAC_DECERR)) {
468                 unsigned int keyidx;
469                 int wlhdr_len;
470                 int iv_len;
471                 int icv_len;
472
473                 keyidx = ((macstat & B43legacy_RX_MAC_KEYIDX)
474                           >> B43legacy_RX_MAC_KEYIDX_SHIFT);
475                 /* We must adjust the key index here. We want the "physical"
476                  * key index, but the ucode passed it slightly different.
477                  */
478                 keyidx = b43legacy_kidx_to_raw(dev, keyidx);
479                 B43legacy_WARN_ON(keyidx >= dev->max_nr_keys);
480
481                 if (dev->key[keyidx].algorithm != B43legacy_SEC_ALGO_NONE) {
482                         /* Remove PROTECTED flag to mark it as decrypted. */
483                         B43legacy_WARN_ON(!ieee80211_has_protected(fctl));
484                         fctl &= ~cpu_to_le16(IEEE80211_FCTL_PROTECTED);
485                         wlhdr->frame_control = fctl;
486
487                         wlhdr_len = ieee80211_hdrlen(fctl);
488                         if (unlikely(skb->len < (wlhdr_len + 3))) {
489                                 b43legacydbg(dev->wl, "RX: Packet size"
490                                              " underrun3\n");
491                                 goto drop;
492                         }
493                         if (skb->data[wlhdr_len + 3] & (1 << 5)) {
494                                 /* The Ext-IV Bit is set in the "KeyID"
495                                  * octet of the IV.
496                                  */
497                                 iv_len = 8;
498                                 icv_len = 8;
499                         } else {
500                                 iv_len = 4;
501                                 icv_len = 4;
502                         }
503                         if (unlikely(skb->len < (wlhdr_len + iv_len +
504                             icv_len))) {
505                                 b43legacydbg(dev->wl, "RX: Packet size"
506                                              " underrun4\n");
507                                 goto drop;
508                         }
509                         /* Remove the IV */
510                         memmove(skb->data + iv_len, skb->data, wlhdr_len);
511                         skb_pull(skb, iv_len);
512                         /* Remove the ICV */
513                         skb_trim(skb, skb->len - icv_len);
514
515                         status.flag |= RX_FLAG_DECRYPTED;
516                 }
517         }
518
519         status.signal = b43legacy_rssi_postprocess(dev, jssi,
520                                       (phystat0 & B43legacy_RX_PHYST0_OFDM),
521                                       (phystat0 & B43legacy_RX_PHYST0_GAINCTL),
522                                       (phystat3 & B43legacy_RX_PHYST3_TRSTATE));
523         /* change to support A PHY */
524         if (phystat0 & B43legacy_RX_PHYST0_OFDM)
525                 status.rate_idx = b43legacy_plcp_get_bitrate_idx_ofdm(plcp, false);
526         else
527                 status.rate_idx = b43legacy_plcp_get_bitrate_idx_cck(plcp);
528         status.antenna = !!(phystat0 & B43legacy_RX_PHYST0_ANT);
529
530         /*
531          * All frames on monitor interfaces and beacons always need a full
532          * 64-bit timestamp. Monitor interfaces need it for diagnostic
533          * purposes and beacons for IBSS merging.
534          * This code assumes we get to process the packet within 16 bits
535          * of timestamp, i.e. about 65 milliseconds after the PHY received
536          * the first symbol.
537          */
538         if (ieee80211_is_beacon(fctl) || dev->wl->radiotap_enabled) {
539                 u16 low_mactime_now;
540
541                 b43legacy_tsf_read(dev, &status.mactime);
542                 low_mactime_now = status.mactime;
543                 status.mactime = status.mactime & ~0xFFFFULL;
544                 status.mactime += mactime;
545                 if (low_mactime_now <= mactime)
546                         status.mactime -= 0x10000;
547                 status.flag |= RX_FLAG_MACTIME_START;
548         }
549
550         chanid = (chanstat & B43legacy_RX_CHAN_ID) >>
551                   B43legacy_RX_CHAN_ID_SHIFT;
552         switch (chanstat & B43legacy_RX_CHAN_PHYTYPE) {
553         case B43legacy_PHYTYPE_B:
554         case B43legacy_PHYTYPE_G:
555                 status.band = NL80211_BAND_2GHZ;
556                 status.freq = chanid + 2400;
557                 break;
558         default:
559                 b43legacywarn(dev->wl, "Unexpected value for chanstat (0x%X)\n",
560                        chanstat);
561                 goto drop;
562         }
563
564         memcpy(IEEE80211_SKB_RXCB(skb), &status, sizeof(status));
565         ieee80211_rx_irqsafe(dev->wl->hw, skb);
566
567         return;
568 drop:
569         b43legacydbg(dev->wl, "RX: Packet dropped\n");
570         dev_kfree_skb_any(skb);
571 }
572
573 void b43legacy_handle_txstatus(struct b43legacy_wldev *dev,
574                              const struct b43legacy_txstatus *status)
575 {
576         b43legacy_debugfs_log_txstat(dev, status);
577
578         if (status->intermediate)
579                 return;
580         if (status->for_ampdu)
581                 return;
582         if (!status->acked)
583                 dev->wl->ieee_stats.dot11ACKFailureCount++;
584         if (status->rts_count) {
585                 if (status->rts_count == 0xF) /* FIXME */
586                         dev->wl->ieee_stats.dot11RTSFailureCount++;
587                 else
588                         dev->wl->ieee_stats.dot11RTSSuccessCount++;
589         }
590
591         if (b43legacy_using_pio(dev))
592                 b43legacy_pio_handle_txstatus(dev, status);
593         else
594                 b43legacy_dma_handle_txstatus(dev, status);
595 }
596
597 /* Handle TX status report as received through DMA/PIO queues */
598 void b43legacy_handle_hwtxstatus(struct b43legacy_wldev *dev,
599                                  const struct b43legacy_hwtxstatus *hw)
600 {
601         struct b43legacy_txstatus status;
602         u8 tmp;
603
604         status.cookie = le16_to_cpu(hw->cookie);
605         status.seq = le16_to_cpu(hw->seq);
606         status.phy_stat = hw->phy_stat;
607         tmp = hw->count;
608         status.frame_count = (tmp >> 4);
609         status.rts_count = (tmp & 0x0F);
610         tmp = hw->flags << 1;
611         status.supp_reason = ((tmp & 0x1C) >> 2);
612         status.pm_indicated = !!(tmp & 0x80);
613         status.intermediate = !!(tmp & 0x40);
614         status.for_ampdu = !!(tmp & 0x20);
615         status.acked = !!(tmp & 0x02);
616
617         b43legacy_handle_txstatus(dev, &status);
618 }
619
620 /* Stop any TX operation on the device (suspend the hardware queues) */
621 void b43legacy_tx_suspend(struct b43legacy_wldev *dev)
622 {
623         if (b43legacy_using_pio(dev))
624                 b43legacy_pio_freeze_txqueues(dev);
625         else
626                 b43legacy_dma_tx_suspend(dev);
627 }
628
629 /* Resume any TX operation on the device (resume the hardware queues) */
630 void b43legacy_tx_resume(struct b43legacy_wldev *dev)
631 {
632         if (b43legacy_using_pio(dev))
633                 b43legacy_pio_thaw_txqueues(dev);
634         else
635                 b43legacy_dma_tx_resume(dev);
636 }
637
638 /* Initialize the QoS parameters */
639 void b43legacy_qos_init(struct b43legacy_wldev *dev)
640 {
641         /* FIXME: This function must probably be called from the mac80211
642          * config callback. */
643 return;
644
645         b43legacy_hf_write(dev, b43legacy_hf_read(dev) | B43legacy_HF_EDCF);
646         /* FIXME kill magic */
647         b43legacy_write16(dev, 0x688,
648                           b43legacy_read16(dev, 0x688) | 0x4);
649
650
651         /*TODO: We might need some stack support here to get the values. */
652 }