diff options
Diffstat (limited to 'drivers/net/wireless/ath/ath9k/xmit.c')
-rw-r--r-- | drivers/net/wireless/ath/ath9k/xmit.c | 488 |
1 files changed, 349 insertions, 139 deletions
diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c index 02df4cbf179f..b0d345a675fe 100644 --- a/drivers/net/wireless/ath/ath9k/xmit.c +++ b/drivers/net/wireless/ath/ath9k/xmit.c | |||
@@ -15,10 +15,11 @@ | |||
15 | */ | 15 | */ |
16 | 16 | ||
17 | #include "ath9k.h" | 17 | #include "ath9k.h" |
18 | #include "ar9003_mac.h" | ||
18 | 19 | ||
19 | #define BITS_PER_BYTE 8 | 20 | #define BITS_PER_BYTE 8 |
20 | #define OFDM_PLCP_BITS 22 | 21 | #define OFDM_PLCP_BITS 22 |
21 | #define HT_RC_2_MCS(_rc) ((_rc) & 0x0f) | 22 | #define HT_RC_2_MCS(_rc) ((_rc) & 0x1f) |
22 | #define HT_RC_2_STREAMS(_rc) ((((_rc) & 0x78) >> 3) + 1) | 23 | #define HT_RC_2_STREAMS(_rc) ((((_rc) & 0x78) >> 3) + 1) |
23 | #define L_STF 8 | 24 | #define L_STF 8 |
24 | #define L_LTF 8 | 25 | #define L_LTF 8 |
@@ -33,7 +34,7 @@ | |||
33 | 34 | ||
34 | #define OFDM_SIFS_TIME 16 | 35 | #define OFDM_SIFS_TIME 16 |
35 | 36 | ||
36 | static u32 bits_per_symbol[][2] = { | 37 | static u16 bits_per_symbol[][2] = { |
37 | /* 20MHz 40MHz */ | 38 | /* 20MHz 40MHz */ |
38 | { 26, 54 }, /* 0: BPSK */ | 39 | { 26, 54 }, /* 0: BPSK */ |
39 | { 52, 108 }, /* 1: QPSK 1/2 */ | 40 | { 52, 108 }, /* 1: QPSK 1/2 */ |
@@ -43,14 +44,6 @@ static u32 bits_per_symbol[][2] = { | |||
43 | { 208, 432 }, /* 5: 64-QAM 2/3 */ | 44 | { 208, 432 }, /* 5: 64-QAM 2/3 */ |
44 | { 234, 486 }, /* 6: 64-QAM 3/4 */ | 45 | { 234, 486 }, /* 6: 64-QAM 3/4 */ |
45 | { 260, 540 }, /* 7: 64-QAM 5/6 */ | 46 | { 260, 540 }, /* 7: 64-QAM 5/6 */ |
46 | { 52, 108 }, /* 8: BPSK */ | ||
47 | { 104, 216 }, /* 9: QPSK 1/2 */ | ||
48 | { 156, 324 }, /* 10: QPSK 3/4 */ | ||
49 | { 208, 432 }, /* 11: 16-QAM 1/2 */ | ||
50 | { 312, 648 }, /* 12: 16-QAM 3/4 */ | ||
51 | { 416, 864 }, /* 13: 64-QAM 2/3 */ | ||
52 | { 468, 972 }, /* 14: 64-QAM 3/4 */ | ||
53 | { 520, 1080 }, /* 15: 64-QAM 5/6 */ | ||
54 | }; | 47 | }; |
55 | 48 | ||
56 | #define IS_HT_RATE(_rate) ((_rate) & 0x80) | 49 | #define IS_HT_RATE(_rate) ((_rate) & 0x80) |
@@ -70,28 +63,39 @@ static void ath_tx_rc_status(struct ath_buf *bf, struct ath_tx_status *ts, | |||
70 | int nbad, int txok, bool update_rc); | 63 | int nbad, int txok, bool update_rc); |
71 | 64 | ||
72 | enum { | 65 | enum { |
73 | MCS_DEFAULT, | 66 | MCS_HT20, |
67 | MCS_HT20_SGI, | ||
74 | MCS_HT40, | 68 | MCS_HT40, |
75 | MCS_HT40_SGI, | 69 | MCS_HT40_SGI, |
76 | }; | 70 | }; |
77 | 71 | ||
78 | static int ath_max_4ms_framelen[3][16] = { | 72 | static int ath_max_4ms_framelen[4][32] = { |
79 | [MCS_DEFAULT] = { | 73 | [MCS_HT20] = { |
80 | 3216, 6434, 9650, 12868, 19304, 25740, 28956, 32180, | 74 | 3212, 6432, 9648, 12864, 19300, 25736, 28952, 32172, |
81 | 6430, 12860, 19300, 25736, 38600, 51472, 57890, 64320, | 75 | 6424, 12852, 19280, 25708, 38568, 51424, 57852, 64280, |
76 | 9628, 19260, 28896, 38528, 57792, 65532, 65532, 65532, | ||
77 | 12828, 25656, 38488, 51320, 65532, 65532, 65532, 65532, | ||
78 | }, | ||
79 | [MCS_HT20_SGI] = { | ||
80 | 3572, 7144, 10720, 14296, 21444, 28596, 32172, 35744, | ||
81 | 7140, 14284, 21428, 28568, 42856, 57144, 64288, 65532, | ||
82 | 10700, 21408, 32112, 42816, 64228, 65532, 65532, 65532, | ||
83 | 14256, 28516, 42780, 57040, 65532, 65532, 65532, 65532, | ||
82 | }, | 84 | }, |
83 | [MCS_HT40] = { | 85 | [MCS_HT40] = { |
84 | 6684, 13368, 20052, 26738, 40104, 53476, 60156, 66840, | 86 | 6680, 13360, 20044, 26724, 40092, 53456, 60140, 65532, |
85 | 13360, 26720, 40080, 53440, 80160, 106880, 120240, 133600, | 87 | 13348, 26700, 40052, 53400, 65532, 65532, 65532, 65532, |
88 | 20004, 40008, 60016, 65532, 65532, 65532, 65532, 65532, | ||
89 | 26644, 53292, 65532, 65532, 65532, 65532, 65532, 65532, | ||
86 | }, | 90 | }, |
87 | [MCS_HT40_SGI] = { | 91 | [MCS_HT40_SGI] = { |
88 | /* TODO: Only MCS 7 and 15 updated, recalculate the rest */ | 92 | 7420, 14844, 22272, 29696, 44544, 59396, 65532, 65532, |
89 | 6684, 13368, 20052, 26738, 40104, 53476, 60156, 74200, | 93 | 14832, 29668, 44504, 59340, 65532, 65532, 65532, 65532, |
90 | 13360, 26720, 40080, 53440, 80160, 106880, 120240, 148400, | 94 | 22232, 44464, 65532, 65532, 65532, 65532, 65532, 65532, |
95 | 29616, 59232, 65532, 65532, 65532, 65532, 65532, 65532, | ||
91 | } | 96 | } |
92 | }; | 97 | }; |
93 | 98 | ||
94 | |||
95 | /*********************/ | 99 | /*********************/ |
96 | /* Aggregation logic */ | 100 | /* Aggregation logic */ |
97 | /*********************/ | 101 | /*********************/ |
@@ -261,25 +265,46 @@ static void ath_tx_set_retry(struct ath_softc *sc, struct ath_txq *txq, | |||
261 | hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_RETRY); | 265 | hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_RETRY); |
262 | } | 266 | } |
263 | 267 | ||
264 | static struct ath_buf* ath_clone_txbuf(struct ath_softc *sc, struct ath_buf *bf) | 268 | static struct ath_buf *ath_tx_get_buffer(struct ath_softc *sc) |
265 | { | 269 | { |
266 | struct ath_buf *tbf; | 270 | struct ath_buf *bf = NULL; |
267 | 271 | ||
268 | spin_lock_bh(&sc->tx.txbuflock); | 272 | spin_lock_bh(&sc->tx.txbuflock); |
269 | if (WARN_ON(list_empty(&sc->tx.txbuf))) { | 273 | |
274 | if (unlikely(list_empty(&sc->tx.txbuf))) { | ||
270 | spin_unlock_bh(&sc->tx.txbuflock); | 275 | spin_unlock_bh(&sc->tx.txbuflock); |
271 | return NULL; | 276 | return NULL; |
272 | } | 277 | } |
273 | tbf = list_first_entry(&sc->tx.txbuf, struct ath_buf, list); | 278 | |
274 | list_del(&tbf->list); | 279 | bf = list_first_entry(&sc->tx.txbuf, struct ath_buf, list); |
280 | list_del(&bf->list); | ||
281 | |||
275 | spin_unlock_bh(&sc->tx.txbuflock); | 282 | spin_unlock_bh(&sc->tx.txbuflock); |
276 | 283 | ||
284 | return bf; | ||
285 | } | ||
286 | |||
287 | static void ath_tx_return_buffer(struct ath_softc *sc, struct ath_buf *bf) | ||
288 | { | ||
289 | spin_lock_bh(&sc->tx.txbuflock); | ||
290 | list_add_tail(&bf->list, &sc->tx.txbuf); | ||
291 | spin_unlock_bh(&sc->tx.txbuflock); | ||
292 | } | ||
293 | |||
294 | static struct ath_buf* ath_clone_txbuf(struct ath_softc *sc, struct ath_buf *bf) | ||
295 | { | ||
296 | struct ath_buf *tbf; | ||
297 | |||
298 | tbf = ath_tx_get_buffer(sc); | ||
299 | if (WARN_ON(!tbf)) | ||
300 | return NULL; | ||
301 | |||
277 | ATH_TXBUF_RESET(tbf); | 302 | ATH_TXBUF_RESET(tbf); |
278 | 303 | ||
279 | tbf->aphy = bf->aphy; | 304 | tbf->aphy = bf->aphy; |
280 | tbf->bf_mpdu = bf->bf_mpdu; | 305 | tbf->bf_mpdu = bf->bf_mpdu; |
281 | tbf->bf_buf_addr = bf->bf_buf_addr; | 306 | tbf->bf_buf_addr = bf->bf_buf_addr; |
282 | *(tbf->bf_desc) = *(bf->bf_desc); | 307 | memcpy(tbf->bf_desc, bf->bf_desc, sc->sc_ah->caps.tx_desc_len); |
283 | tbf->bf_state = bf->bf_state; | 308 | tbf->bf_state = bf->bf_state; |
284 | tbf->bf_dmacontext = bf->bf_dmacontext; | 309 | tbf->bf_dmacontext = bf->bf_dmacontext; |
285 | 310 | ||
@@ -359,7 +384,7 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq, | |||
359 | acked_cnt++; | 384 | acked_cnt++; |
360 | } else { | 385 | } else { |
361 | if (!(tid->state & AGGR_CLEANUP) && | 386 | if (!(tid->state & AGGR_CLEANUP) && |
362 | ts->ts_flags != ATH9K_TX_SW_ABORTED) { | 387 | !bf_last->bf_tx_aborted) { |
363 | if (bf->bf_retries < ATH_MAX_SW_RETRIES) { | 388 | if (bf->bf_retries < ATH_MAX_SW_RETRIES) { |
364 | ath_tx_set_retry(sc, txq, bf); | 389 | ath_tx_set_retry(sc, txq, bf); |
365 | txpending = 1; | 390 | txpending = 1; |
@@ -378,7 +403,8 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq, | |||
378 | } | 403 | } |
379 | } | 404 | } |
380 | 405 | ||
381 | if (bf_next == NULL) { | 406 | if (!(sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) && |
407 | bf_next == NULL) { | ||
382 | /* | 408 | /* |
383 | * Make sure the last desc is reclaimed if it | 409 | * Make sure the last desc is reclaimed if it |
384 | * not a holding desc. | 410 | * not a holding desc. |
@@ -412,36 +438,43 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq, | |||
412 | !txfail, sendbar); | 438 | !txfail, sendbar); |
413 | } else { | 439 | } else { |
414 | /* retry the un-acked ones */ | 440 | /* retry the un-acked ones */ |
415 | if (bf->bf_next == NULL && bf_last->bf_stale) { | 441 | if (!(sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA)) { |
416 | struct ath_buf *tbf; | 442 | if (bf->bf_next == NULL && bf_last->bf_stale) { |
417 | 443 | struct ath_buf *tbf; | |
418 | tbf = ath_clone_txbuf(sc, bf_last); | 444 | |
419 | /* | 445 | tbf = ath_clone_txbuf(sc, bf_last); |
420 | * Update tx baw and complete the frame with | 446 | /* |
421 | * failed status if we run out of tx buf | 447 | * Update tx baw and complete the |
422 | */ | 448 | * frame with failed status if we |
423 | if (!tbf) { | 449 | * run out of tx buf. |
424 | spin_lock_bh(&txq->axq_lock); | 450 | */ |
425 | ath_tx_update_baw(sc, tid, | 451 | if (!tbf) { |
426 | bf->bf_seqno); | 452 | spin_lock_bh(&txq->axq_lock); |
427 | spin_unlock_bh(&txq->axq_lock); | 453 | ath_tx_update_baw(sc, tid, |
428 | 454 | bf->bf_seqno); | |
429 | bf->bf_state.bf_type |= BUF_XRETRY; | 455 | spin_unlock_bh(&txq->axq_lock); |
430 | ath_tx_rc_status(bf, ts, nbad, | 456 | |
431 | 0, false); | 457 | bf->bf_state.bf_type |= |
432 | ath_tx_complete_buf(sc, bf, txq, | 458 | BUF_XRETRY; |
433 | &bf_head, ts, 0, 0); | 459 | ath_tx_rc_status(bf, ts, nbad, |
434 | break; | 460 | 0, false); |
461 | ath_tx_complete_buf(sc, bf, txq, | ||
462 | &bf_head, | ||
463 | ts, 0, 0); | ||
464 | break; | ||
465 | } | ||
466 | |||
467 | ath9k_hw_cleartxdesc(sc->sc_ah, | ||
468 | tbf->bf_desc); | ||
469 | list_add_tail(&tbf->list, &bf_head); | ||
470 | } else { | ||
471 | /* | ||
472 | * Clear descriptor status words for | ||
473 | * software retry | ||
474 | */ | ||
475 | ath9k_hw_cleartxdesc(sc->sc_ah, | ||
476 | bf->bf_desc); | ||
435 | } | 477 | } |
436 | |||
437 | ath9k_hw_cleartxdesc(sc->sc_ah, tbf->bf_desc); | ||
438 | list_add_tail(&tbf->list, &bf_head); | ||
439 | } else { | ||
440 | /* | ||
441 | * Clear descriptor status words for | ||
442 | * software retry | ||
443 | */ | ||
444 | ath9k_hw_cleartxdesc(sc->sc_ah, bf->bf_desc); | ||
445 | } | 478 | } |
446 | 479 | ||
447 | /* | 480 | /* |
@@ -509,12 +542,13 @@ static u32 ath_lookup_rate(struct ath_softc *sc, struct ath_buf *bf, | |||
509 | break; | 542 | break; |
510 | } | 543 | } |
511 | 544 | ||
512 | if (rates[i].flags & IEEE80211_TX_RC_SHORT_GI) | 545 | if (rates[i].flags & IEEE80211_TX_RC_40_MHZ_WIDTH) |
513 | modeidx = MCS_HT40_SGI; | ||
514 | else if (rates[i].flags & IEEE80211_TX_RC_40_MHZ_WIDTH) | ||
515 | modeidx = MCS_HT40; | 546 | modeidx = MCS_HT40; |
516 | else | 547 | else |
517 | modeidx = MCS_DEFAULT; | 548 | modeidx = MCS_HT20; |
549 | |||
550 | if (rates[i].flags & IEEE80211_TX_RC_SHORT_GI) | ||
551 | modeidx++; | ||
518 | 552 | ||
519 | frmlen = ath_max_4ms_framelen[modeidx][rates[i].idx]; | 553 | frmlen = ath_max_4ms_framelen[modeidx][rates[i].idx]; |
520 | max_4ms_framelen = min(max_4ms_framelen, frmlen); | 554 | max_4ms_framelen = min(max_4ms_framelen, frmlen); |
@@ -559,7 +593,7 @@ static int ath_compute_num_delims(struct ath_softc *sc, struct ath_atx_tid *tid, | |||
559 | u32 nsymbits, nsymbols; | 593 | u32 nsymbits, nsymbols; |
560 | u16 minlen; | 594 | u16 minlen; |
561 | u8 flags, rix; | 595 | u8 flags, rix; |
562 | int width, half_gi, ndelim, mindelim; | 596 | int width, streams, half_gi, ndelim, mindelim; |
563 | 597 | ||
564 | /* Select standard number of delimiters based on frame length alone */ | 598 | /* Select standard number of delimiters based on frame length alone */ |
565 | ndelim = ATH_AGGR_GET_NDELIM(frmlen); | 599 | ndelim = ATH_AGGR_GET_NDELIM(frmlen); |
@@ -599,7 +633,8 @@ static int ath_compute_num_delims(struct ath_softc *sc, struct ath_atx_tid *tid, | |||
599 | if (nsymbols == 0) | 633 | if (nsymbols == 0) |
600 | nsymbols = 1; | 634 | nsymbols = 1; |
601 | 635 | ||
602 | nsymbits = bits_per_symbol[rix][width]; | 636 | streams = HT_RC_2_STREAMS(rix); |
637 | nsymbits = bits_per_symbol[rix % 8][width] * streams; | ||
603 | minlen = (nsymbols * nsymbits) / BITS_PER_BYTE; | 638 | minlen = (nsymbols * nsymbits) / BITS_PER_BYTE; |
604 | 639 | ||
605 | if (frmlen < minlen) { | 640 | if (frmlen < minlen) { |
@@ -665,7 +700,7 @@ static enum ATH_AGGR_STATUS ath_tx_form_aggr(struct ath_softc *sc, | |||
665 | bpad = PADBYTES(al_delta) + (ndelim << 2); | 700 | bpad = PADBYTES(al_delta) + (ndelim << 2); |
666 | 701 | ||
667 | bf->bf_next = NULL; | 702 | bf->bf_next = NULL; |
668 | bf->bf_desc->ds_link = 0; | 703 | ath9k_hw_set_desc_link(sc->sc_ah, bf->bf_desc, 0); |
669 | 704 | ||
670 | /* link buffers of this frame to the aggregate */ | 705 | /* link buffers of this frame to the aggregate */ |
671 | ath_tx_addto_baw(sc, tid, bf); | 706 | ath_tx_addto_baw(sc, tid, bf); |
@@ -673,7 +708,8 @@ static enum ATH_AGGR_STATUS ath_tx_form_aggr(struct ath_softc *sc, | |||
673 | list_move_tail(&bf->list, bf_q); | 708 | list_move_tail(&bf->list, bf_q); |
674 | if (bf_prev) { | 709 | if (bf_prev) { |
675 | bf_prev->bf_next = bf; | 710 | bf_prev->bf_next = bf; |
676 | bf_prev->bf_desc->ds_link = bf->bf_daddr; | 711 | ath9k_hw_set_desc_link(sc->sc_ah, bf_prev->bf_desc, |
712 | bf->bf_daddr); | ||
677 | } | 713 | } |
678 | bf_prev = bf; | 714 | bf_prev = bf; |
679 | 715 | ||
@@ -853,7 +889,7 @@ struct ath_txq *ath_txq_setup(struct ath_softc *sc, int qtype, int subtype) | |||
853 | struct ath_hw *ah = sc->sc_ah; | 889 | struct ath_hw *ah = sc->sc_ah; |
854 | struct ath_common *common = ath9k_hw_common(ah); | 890 | struct ath_common *common = ath9k_hw_common(ah); |
855 | struct ath9k_tx_queue_info qi; | 891 | struct ath9k_tx_queue_info qi; |
856 | int qnum; | 892 | int qnum, i; |
857 | 893 | ||
858 | memset(&qi, 0, sizeof(qi)); | 894 | memset(&qi, 0, sizeof(qi)); |
859 | qi.tqi_subtype = subtype; | 895 | qi.tqi_subtype = subtype; |
@@ -877,11 +913,16 @@ struct ath_txq *ath_txq_setup(struct ath_softc *sc, int qtype, int subtype) | |||
877 | * The UAPSD queue is an exception, since we take a desc- | 913 | * The UAPSD queue is an exception, since we take a desc- |
878 | * based intr on the EOSP frames. | 914 | * based intr on the EOSP frames. |
879 | */ | 915 | */ |
880 | if (qtype == ATH9K_TX_QUEUE_UAPSD) | 916 | if (ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) { |
881 | qi.tqi_qflags = TXQ_FLAG_TXDESCINT_ENABLE; | 917 | qi.tqi_qflags = TXQ_FLAG_TXOKINT_ENABLE | |
882 | else | 918 | TXQ_FLAG_TXERRINT_ENABLE; |
883 | qi.tqi_qflags = TXQ_FLAG_TXEOLINT_ENABLE | | 919 | } else { |
884 | TXQ_FLAG_TXDESCINT_ENABLE; | 920 | if (qtype == ATH9K_TX_QUEUE_UAPSD) |
921 | qi.tqi_qflags = TXQ_FLAG_TXDESCINT_ENABLE; | ||
922 | else | ||
923 | qi.tqi_qflags = TXQ_FLAG_TXEOLINT_ENABLE | | ||
924 | TXQ_FLAG_TXDESCINT_ENABLE; | ||
925 | } | ||
885 | qnum = ath9k_hw_setuptxqueue(ah, qtype, &qi); | 926 | qnum = ath9k_hw_setuptxqueue(ah, qtype, &qi); |
886 | if (qnum == -1) { | 927 | if (qnum == -1) { |
887 | /* | 928 | /* |
@@ -908,6 +949,11 @@ struct ath_txq *ath_txq_setup(struct ath_softc *sc, int qtype, int subtype) | |||
908 | txq->axq_depth = 0; | 949 | txq->axq_depth = 0; |
909 | txq->axq_tx_inprogress = false; | 950 | txq->axq_tx_inprogress = false; |
910 | sc->tx.txqsetup |= 1<<qnum; | 951 | sc->tx.txqsetup |= 1<<qnum; |
952 | |||
953 | txq->txq_headidx = txq->txq_tailidx = 0; | ||
954 | for (i = 0; i < ATH_TXFIFO_DEPTH; i++) | ||
955 | INIT_LIST_HEAD(&txq->txq_fifo[i]); | ||
956 | INIT_LIST_HEAD(&txq->txq_fifo_pending); | ||
911 | } | 957 | } |
912 | return &sc->tx.txq[qnum]; | 958 | return &sc->tx.txq[qnum]; |
913 | } | 959 | } |
@@ -1035,36 +1081,52 @@ void ath_draintxq(struct ath_softc *sc, struct ath_txq *txq, bool retry_tx) | |||
1035 | struct ath_tx_status ts; | 1081 | struct ath_tx_status ts; |
1036 | 1082 | ||
1037 | memset(&ts, 0, sizeof(ts)); | 1083 | memset(&ts, 0, sizeof(ts)); |
1038 | if (!retry_tx) | ||
1039 | ts.ts_flags = ATH9K_TX_SW_ABORTED; | ||
1040 | |||
1041 | INIT_LIST_HEAD(&bf_head); | 1084 | INIT_LIST_HEAD(&bf_head); |
1042 | 1085 | ||
1043 | for (;;) { | 1086 | for (;;) { |
1044 | spin_lock_bh(&txq->axq_lock); | 1087 | spin_lock_bh(&txq->axq_lock); |
1045 | 1088 | ||
1046 | if (list_empty(&txq->axq_q)) { | 1089 | if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) { |
1047 | txq->axq_link = NULL; | 1090 | if (list_empty(&txq->txq_fifo[txq->txq_tailidx])) { |
1048 | spin_unlock_bh(&txq->axq_lock); | 1091 | txq->txq_headidx = txq->txq_tailidx = 0; |
1049 | break; | 1092 | spin_unlock_bh(&txq->axq_lock); |
1050 | } | 1093 | break; |
1051 | 1094 | } else { | |
1052 | bf = list_first_entry(&txq->axq_q, struct ath_buf, list); | 1095 | bf = list_first_entry(&txq->txq_fifo[txq->txq_tailidx], |
1096 | struct ath_buf, list); | ||
1097 | } | ||
1098 | } else { | ||
1099 | if (list_empty(&txq->axq_q)) { | ||
1100 | txq->axq_link = NULL; | ||
1101 | spin_unlock_bh(&txq->axq_lock); | ||
1102 | break; | ||
1103 | } | ||
1104 | bf = list_first_entry(&txq->axq_q, struct ath_buf, | ||
1105 | list); | ||
1053 | 1106 | ||
1054 | if (bf->bf_stale) { | 1107 | if (bf->bf_stale) { |
1055 | list_del(&bf->list); | 1108 | list_del(&bf->list); |
1056 | spin_unlock_bh(&txq->axq_lock); | 1109 | spin_unlock_bh(&txq->axq_lock); |
1057 | 1110 | ||
1058 | spin_lock_bh(&sc->tx.txbuflock); | 1111 | ath_tx_return_buffer(sc, bf); |
1059 | list_add_tail(&bf->list, &sc->tx.txbuf); | 1112 | continue; |
1060 | spin_unlock_bh(&sc->tx.txbuflock); | 1113 | } |
1061 | continue; | ||
1062 | } | 1114 | } |
1063 | 1115 | ||
1064 | lastbf = bf->bf_lastbf; | 1116 | lastbf = bf->bf_lastbf; |
1117 | if (!retry_tx) | ||
1118 | lastbf->bf_tx_aborted = true; | ||
1119 | |||
1120 | if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) { | ||
1121 | list_cut_position(&bf_head, | ||
1122 | &txq->txq_fifo[txq->txq_tailidx], | ||
1123 | &lastbf->list); | ||
1124 | INCR(txq->txq_tailidx, ATH_TXFIFO_DEPTH); | ||
1125 | } else { | ||
1126 | /* remove ath_buf's of the same mpdu from txq */ | ||
1127 | list_cut_position(&bf_head, &txq->axq_q, &lastbf->list); | ||
1128 | } | ||
1065 | 1129 | ||
1066 | /* remove ath_buf's of the same mpdu from txq */ | ||
1067 | list_cut_position(&bf_head, &txq->axq_q, &lastbf->list); | ||
1068 | txq->axq_depth--; | 1130 | txq->axq_depth--; |
1069 | 1131 | ||
1070 | spin_unlock_bh(&txq->axq_lock); | 1132 | spin_unlock_bh(&txq->axq_lock); |
@@ -1087,6 +1149,27 @@ void ath_draintxq(struct ath_softc *sc, struct ath_txq *txq, bool retry_tx) | |||
1087 | spin_unlock_bh(&txq->axq_lock); | 1149 | spin_unlock_bh(&txq->axq_lock); |
1088 | } | 1150 | } |
1089 | } | 1151 | } |
1152 | |||
1153 | if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) { | ||
1154 | spin_lock_bh(&txq->axq_lock); | ||
1155 | while (!list_empty(&txq->txq_fifo_pending)) { | ||
1156 | bf = list_first_entry(&txq->txq_fifo_pending, | ||
1157 | struct ath_buf, list); | ||
1158 | list_cut_position(&bf_head, | ||
1159 | &txq->txq_fifo_pending, | ||
1160 | &bf->bf_lastbf->list); | ||
1161 | spin_unlock_bh(&txq->axq_lock); | ||
1162 | |||
1163 | if (bf_isampdu(bf)) | ||
1164 | ath_tx_complete_aggr(sc, txq, bf, &bf_head, | ||
1165 | &ts, 0); | ||
1166 | else | ||
1167 | ath_tx_complete_buf(sc, bf, txq, &bf_head, | ||
1168 | &ts, 0, 0); | ||
1169 | spin_lock_bh(&txq->axq_lock); | ||
1170 | } | ||
1171 | spin_unlock_bh(&txq->axq_lock); | ||
1172 | } | ||
1090 | } | 1173 | } |
1091 | 1174 | ||
1092 | void ath_drain_all_txq(struct ath_softc *sc, bool retry_tx) | 1175 | void ath_drain_all_txq(struct ath_softc *sc, bool retry_tx) |
@@ -1224,44 +1307,47 @@ static void ath_tx_txqaddbuf(struct ath_softc *sc, struct ath_txq *txq, | |||
1224 | 1307 | ||
1225 | bf = list_first_entry(head, struct ath_buf, list); | 1308 | bf = list_first_entry(head, struct ath_buf, list); |
1226 | 1309 | ||
1227 | list_splice_tail_init(head, &txq->axq_q); | ||
1228 | txq->axq_depth++; | ||
1229 | |||
1230 | ath_print(common, ATH_DBG_QUEUE, | 1310 | ath_print(common, ATH_DBG_QUEUE, |
1231 | "qnum: %d, txq depth: %d\n", txq->axq_qnum, txq->axq_depth); | 1311 | "qnum: %d, txq depth: %d\n", txq->axq_qnum, txq->axq_depth); |
1232 | 1312 | ||
1233 | if (txq->axq_link == NULL) { | 1313 | if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) { |
1314 | if (txq->axq_depth >= ATH_TXFIFO_DEPTH) { | ||
1315 | list_splice_tail_init(head, &txq->txq_fifo_pending); | ||
1316 | return; | ||
1317 | } | ||
1318 | if (!list_empty(&txq->txq_fifo[txq->txq_headidx])) | ||
1319 | ath_print(common, ATH_DBG_XMIT, | ||
1320 | "Initializing tx fifo %d which " | ||
1321 | "is non-empty\n", | ||
1322 | txq->txq_headidx); | ||
1323 | INIT_LIST_HEAD(&txq->txq_fifo[txq->txq_headidx]); | ||
1324 | list_splice_init(head, &txq->txq_fifo[txq->txq_headidx]); | ||
1325 | INCR(txq->txq_headidx, ATH_TXFIFO_DEPTH); | ||
1234 | ath9k_hw_puttxbuf(ah, txq->axq_qnum, bf->bf_daddr); | 1326 | ath9k_hw_puttxbuf(ah, txq->axq_qnum, bf->bf_daddr); |
1235 | ath_print(common, ATH_DBG_XMIT, | 1327 | ath_print(common, ATH_DBG_XMIT, |
1236 | "TXDP[%u] = %llx (%p)\n", | 1328 | "TXDP[%u] = %llx (%p)\n", |
1237 | txq->axq_qnum, ito64(bf->bf_daddr), bf->bf_desc); | 1329 | txq->axq_qnum, ito64(bf->bf_daddr), bf->bf_desc); |
1238 | } else { | 1330 | } else { |
1239 | *txq->axq_link = bf->bf_daddr; | 1331 | list_splice_tail_init(head, &txq->axq_q); |
1240 | ath_print(common, ATH_DBG_XMIT, "link[%u] (%p)=%llx (%p)\n", | ||
1241 | txq->axq_qnum, txq->axq_link, | ||
1242 | ito64(bf->bf_daddr), bf->bf_desc); | ||
1243 | } | ||
1244 | txq->axq_link = &(bf->bf_lastbf->bf_desc->ds_link); | ||
1245 | ath9k_hw_txstart(ah, txq->axq_qnum); | ||
1246 | } | ||
1247 | 1332 | ||
1248 | static struct ath_buf *ath_tx_get_buffer(struct ath_softc *sc) | 1333 | if (txq->axq_link == NULL) { |
1249 | { | 1334 | ath9k_hw_puttxbuf(ah, txq->axq_qnum, bf->bf_daddr); |
1250 | struct ath_buf *bf = NULL; | 1335 | ath_print(common, ATH_DBG_XMIT, |
1251 | 1336 | "TXDP[%u] = %llx (%p)\n", | |
1252 | spin_lock_bh(&sc->tx.txbuflock); | 1337 | txq->axq_qnum, ito64(bf->bf_daddr), |
1253 | 1338 | bf->bf_desc); | |
1254 | if (unlikely(list_empty(&sc->tx.txbuf))) { | 1339 | } else { |
1255 | spin_unlock_bh(&sc->tx.txbuflock); | 1340 | *txq->axq_link = bf->bf_daddr; |
1256 | return NULL; | 1341 | ath_print(common, ATH_DBG_XMIT, |
1342 | "link[%u] (%p)=%llx (%p)\n", | ||
1343 | txq->axq_qnum, txq->axq_link, | ||
1344 | ito64(bf->bf_daddr), bf->bf_desc); | ||
1345 | } | ||
1346 | ath9k_hw_get_desc_link(ah, bf->bf_lastbf->bf_desc, | ||
1347 | &txq->axq_link); | ||
1348 | ath9k_hw_txstart(ah, txq->axq_qnum); | ||
1257 | } | 1349 | } |
1258 | 1350 | txq->axq_depth++; | |
1259 | bf = list_first_entry(&sc->tx.txbuf, struct ath_buf, list); | ||
1260 | list_del(&bf->list); | ||
1261 | |||
1262 | spin_unlock_bh(&sc->tx.txbuflock); | ||
1263 | |||
1264 | return bf; | ||
1265 | } | 1351 | } |
1266 | 1352 | ||
1267 | static void ath_tx_send_ampdu(struct ath_softc *sc, struct ath_atx_tid *tid, | 1353 | static void ath_tx_send_ampdu(struct ath_softc *sc, struct ath_atx_tid *tid, |
@@ -1408,8 +1494,7 @@ static void assign_aggr_tid_seqno(struct sk_buff *skb, | |||
1408 | INCR(tid->seq_next, IEEE80211_SEQ_MAX); | 1494 | INCR(tid->seq_next, IEEE80211_SEQ_MAX); |
1409 | } | 1495 | } |
1410 | 1496 | ||
1411 | static int setup_tx_flags(struct ath_softc *sc, struct sk_buff *skb, | 1497 | static int setup_tx_flags(struct sk_buff *skb, bool use_ldpc) |
1412 | struct ath_txq *txq) | ||
1413 | { | 1498 | { |
1414 | struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); | 1499 | struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); |
1415 | int flags = 0; | 1500 | int flags = 0; |
@@ -1420,6 +1505,9 @@ static int setup_tx_flags(struct ath_softc *sc, struct sk_buff *skb, | |||
1420 | if (tx_info->flags & IEEE80211_TX_CTL_NO_ACK) | 1505 | if (tx_info->flags & IEEE80211_TX_CTL_NO_ACK) |
1421 | flags |= ATH9K_TXDESC_NOACK; | 1506 | flags |= ATH9K_TXDESC_NOACK; |
1422 | 1507 | ||
1508 | if (use_ldpc) | ||
1509 | flags |= ATH9K_TXDESC_LDPC; | ||
1510 | |||
1423 | return flags; | 1511 | return flags; |
1424 | } | 1512 | } |
1425 | 1513 | ||
@@ -1438,8 +1526,9 @@ static u32 ath_pkt_duration(struct ath_softc *sc, u8 rix, struct ath_buf *bf, | |||
1438 | pktlen = bf_isaggr(bf) ? bf->bf_al : bf->bf_frmlen; | 1526 | pktlen = bf_isaggr(bf) ? bf->bf_al : bf->bf_frmlen; |
1439 | 1527 | ||
1440 | /* find number of symbols: PLCP + data */ | 1528 | /* find number of symbols: PLCP + data */ |
1529 | streams = HT_RC_2_STREAMS(rix); | ||
1441 | nbits = (pktlen << 3) + OFDM_PLCP_BITS; | 1530 | nbits = (pktlen << 3) + OFDM_PLCP_BITS; |
1442 | nsymbits = bits_per_symbol[rix][width]; | 1531 | nsymbits = bits_per_symbol[rix % 8][width] * streams; |
1443 | nsymbols = (nbits + nsymbits - 1) / nsymbits; | 1532 | nsymbols = (nbits + nsymbits - 1) / nsymbits; |
1444 | 1533 | ||
1445 | if (!half_gi) | 1534 | if (!half_gi) |
@@ -1448,7 +1537,6 @@ static u32 ath_pkt_duration(struct ath_softc *sc, u8 rix, struct ath_buf *bf, | |||
1448 | duration = SYMBOL_TIME_HALFGI(nsymbols); | 1537 | duration = SYMBOL_TIME_HALFGI(nsymbols); |
1449 | 1538 | ||
1450 | /* addup duration for legacy/ht training and signal fields */ | 1539 | /* addup duration for legacy/ht training and signal fields */ |
1451 | streams = HT_RC_2_STREAMS(rix); | ||
1452 | duration += L_STF + L_LTF + L_SIG + HT_SIG + HT_STF + HT_LTF(streams); | 1540 | duration += L_STF + L_LTF + L_SIG + HT_SIG + HT_STF + HT_LTF(streams); |
1453 | 1541 | ||
1454 | return duration; | 1542 | return duration; |
@@ -1519,6 +1607,8 @@ static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf) | |||
1519 | series[i].Rate = rix | 0x80; | 1607 | series[i].Rate = rix | 0x80; |
1520 | series[i].PktDuration = ath_pkt_duration(sc, rix, bf, | 1608 | series[i].PktDuration = ath_pkt_duration(sc, rix, bf, |
1521 | is_40, is_sgi, is_sp); | 1609 | is_40, is_sgi, is_sp); |
1610 | if (rix < 8 && (tx_info->flags & IEEE80211_TX_CTL_STBC)) | ||
1611 | series[i].RateFlags |= ATH9K_RATESERIES_STBC; | ||
1522 | continue; | 1612 | continue; |
1523 | } | 1613 | } |
1524 | 1614 | ||
@@ -1571,6 +1661,7 @@ static int ath_tx_setup_buffer(struct ieee80211_hw *hw, struct ath_buf *bf, | |||
1571 | int hdrlen; | 1661 | int hdrlen; |
1572 | __le16 fc; | 1662 | __le16 fc; |
1573 | int padpos, padsize; | 1663 | int padpos, padsize; |
1664 | bool use_ldpc = false; | ||
1574 | 1665 | ||
1575 | tx_info->pad[0] = 0; | 1666 | tx_info->pad[0] = 0; |
1576 | switch (txctl->frame_type) { | 1667 | switch (txctl->frame_type) { |
@@ -1597,10 +1688,13 @@ static int ath_tx_setup_buffer(struct ieee80211_hw *hw, struct ath_buf *bf, | |||
1597 | bf->bf_frmlen -= padsize; | 1688 | bf->bf_frmlen -= padsize; |
1598 | } | 1689 | } |
1599 | 1690 | ||
1600 | if (conf_is_ht(&hw->conf)) | 1691 | if (conf_is_ht(&hw->conf)) { |
1601 | bf->bf_state.bf_type |= BUF_HT; | 1692 | bf->bf_state.bf_type |= BUF_HT; |
1693 | if (tx_info->flags & IEEE80211_TX_CTL_LDPC) | ||
1694 | use_ldpc = true; | ||
1695 | } | ||
1602 | 1696 | ||
1603 | bf->bf_flags = setup_tx_flags(sc, skb, txctl->txq); | 1697 | bf->bf_flags = setup_tx_flags(skb, use_ldpc); |
1604 | 1698 | ||
1605 | bf->bf_keytype = get_hw_crypto_keytype(skb); | 1699 | bf->bf_keytype = get_hw_crypto_keytype(skb); |
1606 | if (bf->bf_keytype != ATH9K_KEY_TYPE_CLEAR) { | 1700 | if (bf->bf_keytype != ATH9K_KEY_TYPE_CLEAR) { |
@@ -1659,8 +1753,7 @@ static void ath_tx_start_dma(struct ath_softc *sc, struct ath_buf *bf, | |||
1659 | list_add_tail(&bf->list, &bf_head); | 1753 | list_add_tail(&bf->list, &bf_head); |
1660 | 1754 | ||
1661 | ds = bf->bf_desc; | 1755 | ds = bf->bf_desc; |
1662 | ds->ds_link = 0; | 1756 | ath9k_hw_set_desc_link(ah, ds, 0); |
1663 | ds->ds_data = bf->bf_buf_addr; | ||
1664 | 1757 | ||
1665 | ath9k_hw_set11n_txdesc(ah, ds, bf->bf_frmlen, frm_type, MAX_RATE_POWER, | 1758 | ath9k_hw_set11n_txdesc(ah, ds, bf->bf_frmlen, frm_type, MAX_RATE_POWER, |
1666 | bf->bf_keyix, bf->bf_keytype, bf->bf_flags); | 1759 | bf->bf_keyix, bf->bf_keytype, bf->bf_flags); |
@@ -1669,7 +1762,9 @@ static void ath_tx_start_dma(struct ath_softc *sc, struct ath_buf *bf, | |||
1669 | skb->len, /* segment length */ | 1762 | skb->len, /* segment length */ |
1670 | true, /* first segment */ | 1763 | true, /* first segment */ |
1671 | true, /* last segment */ | 1764 | true, /* last segment */ |
1672 | ds); /* first descriptor */ | 1765 | ds, /* first descriptor */ |
1766 | bf->bf_buf_addr, | ||
1767 | txctl->txq->axq_qnum); | ||
1673 | 1768 | ||
1674 | spin_lock_bh(&txctl->txq->axq_lock); | 1769 | spin_lock_bh(&txctl->txq->axq_lock); |
1675 | 1770 | ||
@@ -1738,9 +1833,7 @@ int ath_tx_start(struct ieee80211_hw *hw, struct sk_buff *skb, | |||
1738 | } | 1833 | } |
1739 | spin_unlock_bh(&txq->axq_lock); | 1834 | spin_unlock_bh(&txq->axq_lock); |
1740 | 1835 | ||
1741 | spin_lock_bh(&sc->tx.txbuflock); | 1836 | ath_tx_return_buffer(sc, bf); |
1742 | list_add_tail(&bf->list, &sc->tx.txbuf); | ||
1743 | spin_unlock_bh(&sc->tx.txbuflock); | ||
1744 | 1837 | ||
1745 | return r; | 1838 | return r; |
1746 | } | 1839 | } |
@@ -1896,7 +1989,7 @@ static int ath_tx_num_badfrms(struct ath_softc *sc, struct ath_buf *bf, | |||
1896 | int nbad = 0; | 1989 | int nbad = 0; |
1897 | int isaggr = 0; | 1990 | int isaggr = 0; |
1898 | 1991 | ||
1899 | if (ts->ts_flags == ATH9K_TX_SW_ABORTED) | 1992 | if (bf->bf_tx_aborted) |
1900 | return 0; | 1993 | return 0; |
1901 | 1994 | ||
1902 | isaggr = bf_isaggr(bf); | 1995 | isaggr = bf_isaggr(bf); |
@@ -2054,13 +2147,12 @@ static void ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq) | |||
2054 | txq->axq_depth--; | 2147 | txq->axq_depth--; |
2055 | txok = !(ts.ts_status & ATH9K_TXERR_MASK); | 2148 | txok = !(ts.ts_status & ATH9K_TXERR_MASK); |
2056 | txq->axq_tx_inprogress = false; | 2149 | txq->axq_tx_inprogress = false; |
2150 | if (bf_held) | ||
2151 | list_del(&bf_held->list); | ||
2057 | spin_unlock_bh(&txq->axq_lock); | 2152 | spin_unlock_bh(&txq->axq_lock); |
2058 | 2153 | ||
2059 | if (bf_held) { | 2154 | if (bf_held) |
2060 | spin_lock_bh(&sc->tx.txbuflock); | 2155 | ath_tx_return_buffer(sc, bf_held); |
2061 | list_move_tail(&bf_held->list, &sc->tx.txbuf); | ||
2062 | spin_unlock_bh(&sc->tx.txbuflock); | ||
2063 | } | ||
2064 | 2156 | ||
2065 | if (!bf_isampdu(bf)) { | 2157 | if (!bf_isampdu(bf)) { |
2066 | /* | 2158 | /* |
@@ -2138,10 +2230,119 @@ void ath_tx_tasklet(struct ath_softc *sc) | |||
2138 | } | 2230 | } |
2139 | } | 2231 | } |
2140 | 2232 | ||
2233 | void ath_tx_edma_tasklet(struct ath_softc *sc) | ||
2234 | { | ||
2235 | struct ath_tx_status txs; | ||
2236 | struct ath_common *common = ath9k_hw_common(sc->sc_ah); | ||
2237 | struct ath_hw *ah = sc->sc_ah; | ||
2238 | struct ath_txq *txq; | ||
2239 | struct ath_buf *bf, *lastbf; | ||
2240 | struct list_head bf_head; | ||
2241 | int status; | ||
2242 | int txok; | ||
2243 | |||
2244 | for (;;) { | ||
2245 | status = ath9k_hw_txprocdesc(ah, NULL, (void *)&txs); | ||
2246 | if (status == -EINPROGRESS) | ||
2247 | break; | ||
2248 | if (status == -EIO) { | ||
2249 | ath_print(common, ATH_DBG_XMIT, | ||
2250 | "Error processing tx status\n"); | ||
2251 | break; | ||
2252 | } | ||
2253 | |||
2254 | /* Skip beacon completions */ | ||
2255 | if (txs.qid == sc->beacon.beaconq) | ||
2256 | continue; | ||
2257 | |||
2258 | txq = &sc->tx.txq[txs.qid]; | ||
2259 | |||
2260 | spin_lock_bh(&txq->axq_lock); | ||
2261 | if (list_empty(&txq->txq_fifo[txq->txq_tailidx])) { | ||
2262 | spin_unlock_bh(&txq->axq_lock); | ||
2263 | return; | ||
2264 | } | ||
2265 | |||
2266 | bf = list_first_entry(&txq->txq_fifo[txq->txq_tailidx], | ||
2267 | struct ath_buf, list); | ||
2268 | lastbf = bf->bf_lastbf; | ||
2269 | |||
2270 | INIT_LIST_HEAD(&bf_head); | ||
2271 | list_cut_position(&bf_head, &txq->txq_fifo[txq->txq_tailidx], | ||
2272 | &lastbf->list); | ||
2273 | INCR(txq->txq_tailidx, ATH_TXFIFO_DEPTH); | ||
2274 | txq->axq_depth--; | ||
2275 | txq->axq_tx_inprogress = false; | ||
2276 | spin_unlock_bh(&txq->axq_lock); | ||
2277 | |||
2278 | txok = !(txs.ts_status & ATH9K_TXERR_MASK); | ||
2279 | |||
2280 | if (!bf_isampdu(bf)) { | ||
2281 | bf->bf_retries = txs.ts_longretry; | ||
2282 | if (txs.ts_status & ATH9K_TXERR_XRETRY) | ||
2283 | bf->bf_state.bf_type |= BUF_XRETRY; | ||
2284 | ath_tx_rc_status(bf, &txs, 0, txok, true); | ||
2285 | } | ||
2286 | |||
2287 | if (bf_isampdu(bf)) | ||
2288 | ath_tx_complete_aggr(sc, txq, bf, &bf_head, &txs, txok); | ||
2289 | else | ||
2290 | ath_tx_complete_buf(sc, bf, txq, &bf_head, | ||
2291 | &txs, txok, 0); | ||
2292 | |||
2293 | spin_lock_bh(&txq->axq_lock); | ||
2294 | if (!list_empty(&txq->txq_fifo_pending)) { | ||
2295 | INIT_LIST_HEAD(&bf_head); | ||
2296 | bf = list_first_entry(&txq->txq_fifo_pending, | ||
2297 | struct ath_buf, list); | ||
2298 | list_cut_position(&bf_head, &txq->txq_fifo_pending, | ||
2299 | &bf->bf_lastbf->list); | ||
2300 | ath_tx_txqaddbuf(sc, txq, &bf_head); | ||
2301 | } else if (sc->sc_flags & SC_OP_TXAGGR) | ||
2302 | ath_txq_schedule(sc, txq); | ||
2303 | spin_unlock_bh(&txq->axq_lock); | ||
2304 | } | ||
2305 | } | ||
2306 | |||
2141 | /*****************/ | 2307 | /*****************/ |
2142 | /* Init, Cleanup */ | 2308 | /* Init, Cleanup */ |
2143 | /*****************/ | 2309 | /*****************/ |
2144 | 2310 | ||
2311 | static int ath_txstatus_setup(struct ath_softc *sc, int size) | ||
2312 | { | ||
2313 | struct ath_descdma *dd = &sc->txsdma; | ||
2314 | u8 txs_len = sc->sc_ah->caps.txs_len; | ||
2315 | |||
2316 | dd->dd_desc_len = size * txs_len; | ||
2317 | dd->dd_desc = dma_alloc_coherent(sc->dev, dd->dd_desc_len, | ||
2318 | &dd->dd_desc_paddr, GFP_KERNEL); | ||
2319 | if (!dd->dd_desc) | ||
2320 | return -ENOMEM; | ||
2321 | |||
2322 | return 0; | ||
2323 | } | ||
2324 | |||
2325 | static int ath_tx_edma_init(struct ath_softc *sc) | ||
2326 | { | ||
2327 | int err; | ||
2328 | |||
2329 | err = ath_txstatus_setup(sc, ATH_TXSTATUS_RING_SIZE); | ||
2330 | if (!err) | ||
2331 | ath9k_hw_setup_statusring(sc->sc_ah, sc->txsdma.dd_desc, | ||
2332 | sc->txsdma.dd_desc_paddr, | ||
2333 | ATH_TXSTATUS_RING_SIZE); | ||
2334 | |||
2335 | return err; | ||
2336 | } | ||
2337 | |||
2338 | static void ath_tx_edma_cleanup(struct ath_softc *sc) | ||
2339 | { | ||
2340 | struct ath_descdma *dd = &sc->txsdma; | ||
2341 | |||
2342 | dma_free_coherent(sc->dev, dd->dd_desc_len, dd->dd_desc, | ||
2343 | dd->dd_desc_paddr); | ||
2344 | } | ||
2345 | |||
2145 | int ath_tx_init(struct ath_softc *sc, int nbufs) | 2346 | int ath_tx_init(struct ath_softc *sc, int nbufs) |
2146 | { | 2347 | { |
2147 | struct ath_common *common = ath9k_hw_common(sc->sc_ah); | 2348 | struct ath_common *common = ath9k_hw_common(sc->sc_ah); |
@@ -2150,7 +2351,7 @@ int ath_tx_init(struct ath_softc *sc, int nbufs) | |||
2150 | spin_lock_init(&sc->tx.txbuflock); | 2351 | spin_lock_init(&sc->tx.txbuflock); |
2151 | 2352 | ||
2152 | error = ath_descdma_setup(sc, &sc->tx.txdma, &sc->tx.txbuf, | 2353 | error = ath_descdma_setup(sc, &sc->tx.txdma, &sc->tx.txbuf, |
2153 | "tx", nbufs, 1); | 2354 | "tx", nbufs, 1, 1); |
2154 | if (error != 0) { | 2355 | if (error != 0) { |
2155 | ath_print(common, ATH_DBG_FATAL, | 2356 | ath_print(common, ATH_DBG_FATAL, |
2156 | "Failed to allocate tx descriptors: %d\n", error); | 2357 | "Failed to allocate tx descriptors: %d\n", error); |
@@ -2158,7 +2359,7 @@ int ath_tx_init(struct ath_softc *sc, int nbufs) | |||
2158 | } | 2359 | } |
2159 | 2360 | ||
2160 | error = ath_descdma_setup(sc, &sc->beacon.bdma, &sc->beacon.bbuf, | 2361 | error = ath_descdma_setup(sc, &sc->beacon.bdma, &sc->beacon.bbuf, |
2161 | "beacon", ATH_BCBUF, 1); | 2362 | "beacon", ATH_BCBUF, 1, 1); |
2162 | if (error != 0) { | 2363 | if (error != 0) { |
2163 | ath_print(common, ATH_DBG_FATAL, | 2364 | ath_print(common, ATH_DBG_FATAL, |
2164 | "Failed to allocate beacon descriptors: %d\n", error); | 2365 | "Failed to allocate beacon descriptors: %d\n", error); |
@@ -2167,6 +2368,12 @@ int ath_tx_init(struct ath_softc *sc, int nbufs) | |||
2167 | 2368 | ||
2168 | INIT_DELAYED_WORK(&sc->tx_complete_work, ath_tx_complete_poll_work); | 2369 | INIT_DELAYED_WORK(&sc->tx_complete_work, ath_tx_complete_poll_work); |
2169 | 2370 | ||
2371 | if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) { | ||
2372 | error = ath_tx_edma_init(sc); | ||
2373 | if (error) | ||
2374 | goto err; | ||
2375 | } | ||
2376 | |||
2170 | err: | 2377 | err: |
2171 | if (error != 0) | 2378 | if (error != 0) |
2172 | ath_tx_cleanup(sc); | 2379 | ath_tx_cleanup(sc); |
@@ -2181,6 +2388,9 @@ void ath_tx_cleanup(struct ath_softc *sc) | |||
2181 | 2388 | ||
2182 | if (sc->tx.txdma.dd_desc_len != 0) | 2389 | if (sc->tx.txdma.dd_desc_len != 0) |
2183 | ath_descdma_cleanup(sc, &sc->tx.txdma, &sc->tx.txbuf); | 2390 | ath_descdma_cleanup(sc, &sc->tx.txdma, &sc->tx.txbuf); |
2391 | |||
2392 | if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) | ||
2393 | ath_tx_edma_cleanup(sc); | ||
2184 | } | 2394 | } |
2185 | 2395 | ||
2186 | void ath_tx_node_init(struct ath_softc *sc, struct ath_node *an) | 2396 | void ath_tx_node_init(struct ath_softc *sc, struct ath_node *an) |