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 } 562 563 memcpy(IEEE80211_SKB_RXCB(skb), &status, sizeof(status)); 564 ieee80211_rx_irqsafe(dev->wl->hw, skb); 565 566 return; 567 drop: 568 b43legacydbg(dev->wl, "RX: Packet dropped\n"); 569 dev_kfree_skb_any(skb); 570 } 571 572 void b43legacy_handle_txstatus(struct b43legacy_wldev *dev, 573 const struct b43legacy_txstatus *status) 574 { 575 b43legacy_debugfs_log_txstat(dev, status); 576 577 if (status->intermediate) 578 return; 579 if (status->for_ampdu) 580 return; 581 if (!status->acked) 582 dev->wl->ieee_stats.dot11ACKFailureCount++; 583 if (status->rts_count) { 584 if (status->rts_count == 0xF) /* FIXME */ 585 dev->wl->ieee_stats.dot11RTSFailureCount++; 586 else 587 dev->wl->ieee_stats.dot11RTSSuccessCount++; 588 } 589 590 if (b43legacy_using_pio(dev)) 591 b43legacy_pio_handle_txstatus(dev, status); 592 else 593 b43legacy_dma_handle_txstatus(dev, status); 594 } 595 596 /* Handle TX status report as received through DMA/PIO queues */ 597 void b43legacy_handle_hwtxstatus(struct b43legacy_wldev *dev, 598 const struct b43legacy_hwtxstatus *hw) 599 { 600 struct b43legacy_txstatus status; 601 u8 tmp; 602 603 status.cookie = le16_to_cpu(hw->cookie); 604 status.seq = le16_to_cpu(hw->seq); 605 status.phy_stat = hw->phy_stat; 606 tmp = hw->count; 607 status.frame_count = (tmp >> 4); 608 status.rts_count = (tmp & 0x0F); 609 tmp = hw->flags << 1; 610 status.supp_reason = ((tmp & 0x1C) >> 2); 611 status.pm_indicated = !!(tmp & 0x80); 612 status.intermediate = !!(tmp & 0x40); 613 status.for_ampdu = !!(tmp & 0x20); 614 status.acked = !!(tmp & 0x02); 615 616 b43legacy_handle_txstatus(dev, &status); 617 } 618 619 /* Stop any TX operation on the device (suspend the hardware queues) */ 620 void b43legacy_tx_suspend(struct b43legacy_wldev *dev) 621 { 622 if (b43legacy_using_pio(dev)) 623 b43legacy_pio_freeze_txqueues(dev); 624 else 625 b43legacy_dma_tx_suspend(dev); 626 } 627 628 /* Resume any TX operation on the device (resume the hardware queues) */ 629 void b43legacy_tx_resume(struct b43legacy_wldev *dev) 630 { 631 if (b43legacy_using_pio(dev)) 632 b43legacy_pio_thaw_txqueues(dev); 633 else 634 b43legacy_dma_tx_resume(dev); 635 } 636 637 /* Initialize the QoS parameters */ 638 void b43legacy_qos_init(struct b43legacy_wldev *dev) 639 { 640 /* FIXME: This function must probably be called from the mac80211 641 * config callback. */ 642 return; 643 644 b43legacy_hf_write(dev, b43legacy_hf_read(dev) | B43legacy_HF_EDCF); 645 /* FIXME kill magic */ 646 b43legacy_write16(dev, 0x688, 647 b43legacy_read16(dev, 0x688) | 0x4); 648 649 650 /*TODO: We might need some stack support here to get the values. */ 651 } 652