aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEmmanuel Grumbach <emmanuel.grumbach@intel.com>2011-07-03 04:22:15 -0400
committerWey-Yi Guy <wey-yi.w.guy@intel.com>2011-07-16 10:36:36 -0400
commit47c1b496015e41e1068878814596af9a45d4fa84 (patch)
tree26f086a3b95e858a9bd897a655a320f520c43467
parent94f9b97be5b3bf67392e43fb7f567721b09142c2 (diff)
iwlagn: move Tx datapath to transport layer
Split the Tx datapath in two parts: * the first deals with the Tx cmd composition * the second attaches the skb + Tx cmd to the queues Signed-off-by: Emmanuel Grumbach <emmanuel.grumbach@intel.com> Signed-off-by: Wey-Yi Guy <wey-yi.w.guy@intel.com>
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-agn-tx.c158
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-agn.h4
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-dev.h4
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-trans.c156
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-trans.h13
5 files changed, 189 insertions, 146 deletions
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-tx.c b/drivers/net/wireless/iwlwifi/iwl-agn-tx.c
index 7d3aad83e0d..f306824157e 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn-tx.c
+++ b/drivers/net/wireless/iwlwifi/iwl-agn-tx.c
@@ -39,6 +39,7 @@
39#include "iwl-helpers.h" 39#include "iwl-helpers.h"
40#include "iwl-agn-hw.h" 40#include "iwl-agn-hw.h"
41#include "iwl-agn.h" 41#include "iwl-agn.h"
42#include "iwl-trans.h"
42 43
43/* 44/*
44 * mac80211 queues, ACs, hardware queues, FIFOs. 45 * mac80211 queues, ACs, hardware queues, FIFOs.
@@ -98,7 +99,7 @@ static inline int get_fifo_from_tid(struct iwl_rxon_context *ctx, u16 tid)
98/** 99/**
99 * iwlagn_txq_update_byte_cnt_tbl - Set up entry in Tx byte-count array 100 * iwlagn_txq_update_byte_cnt_tbl - Set up entry in Tx byte-count array
100 */ 101 */
101static void iwlagn_txq_update_byte_cnt_tbl(struct iwl_priv *priv, 102void iwlagn_txq_update_byte_cnt_tbl(struct iwl_priv *priv,
102 struct iwl_tx_queue *txq, 103 struct iwl_tx_queue *txq,
103 u16 byte_cnt) 104 u16 byte_cnt)
104{ 105{
@@ -547,26 +548,17 @@ int iwlagn_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
547{ 548{
548 struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; 549 struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
549 struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); 550 struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
550 struct ieee80211_sta *sta = info->control.sta;
551 struct iwl_station_priv *sta_priv = NULL; 551 struct iwl_station_priv *sta_priv = NULL;
552 struct iwl_tx_queue *txq;
553 struct iwl_queue *q;
554 struct iwl_device_cmd *out_cmd;
555 struct iwl_cmd_meta *out_meta;
556 struct iwl_tx_cmd *tx_cmd;
557 struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS]; 552 struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS];
553 struct iwl_tx_cmd *tx_cmd;
558 int txq_id; 554 int txq_id;
559 dma_addr_t phys_addr = 0; 555
560 dma_addr_t txcmd_phys;
561 dma_addr_t scratch_phys;
562 u16 len, firstlen, secondlen;
563 u16 seq_number = 0; 556 u16 seq_number = 0;
564 __le16 fc; 557 __le16 fc;
565 u8 hdr_len; 558 u8 hdr_len;
559 u16 len;
566 u8 sta_id; 560 u8 sta_id;
567 u8 wait_write_ptr = 0;
568 u8 tid = 0; 561 u8 tid = 0;
569 u8 *qc = NULL;
570 unsigned long flags; 562 unsigned long flags;
571 bool is_agg = false; 563 bool is_agg = false;
572 564
@@ -614,8 +606,8 @@ int iwlagn_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
614 606
615 IWL_DEBUG_TX(priv, "station Id %d\n", sta_id); 607 IWL_DEBUG_TX(priv, "station Id %d\n", sta_id);
616 608
617 if (sta) 609 if (info->control.sta)
618 sta_priv = (void *)sta->drv_priv; 610 sta_priv = (void *)info->control.sta->drv_priv;
619 611
620 if (sta_priv && sta_priv->asleep && 612 if (sta_priv && sta_priv->asleep &&
621 (info->flags & IEEE80211_TX_CTL_PSPOLL_RESPONSE)) { 613 (info->flags & IEEE80211_TX_CTL_PSPOLL_RESPONSE)) {
@@ -650,6 +642,7 @@ int iwlagn_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
650 spin_lock(&priv->sta_lock); 642 spin_lock(&priv->sta_lock);
651 643
652 if (ieee80211_is_data_qos(fc)) { 644 if (ieee80211_is_data_qos(fc)) {
645 u8 *qc = NULL;
653 qc = ieee80211_get_qos_ctl(hdr); 646 qc = ieee80211_get_qos_ctl(hdr);
654 tid = qc[0] & IEEE80211_QOS_CTL_TID_MASK; 647 tid = qc[0] & IEEE80211_QOS_CTL_TID_MASK;
655 648
@@ -670,38 +663,13 @@ int iwlagn_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
670 } 663 }
671 } 664 }
672 665
673 txq = &priv->txq[txq_id]; 666 tx_cmd = trans_get_tx_cmd(priv, txq_id);
674 q = &txq->q; 667 if (unlikely(!tx_cmd))
675
676 if (unlikely(iwl_queue_space(q) < q->high_mark))
677 goto drop_unlock_sta; 668 goto drop_unlock_sta;
678 669
679 /* Set up driver data for this TFD */
680 memset(&(txq->txb[q->write_ptr]), 0, sizeof(struct iwl_tx_info));
681 txq->txb[q->write_ptr].skb = skb;
682 txq->txb[q->write_ptr].ctx = ctx;
683
684 /* Set up first empty entry in queue's array of Tx/cmd buffers */
685 out_cmd = txq->cmd[q->write_ptr];
686 out_meta = &txq->meta[q->write_ptr];
687 tx_cmd = &out_cmd->cmd.tx;
688 memset(&out_cmd->hdr, 0, sizeof(out_cmd->hdr));
689 memset(tx_cmd, 0, sizeof(struct iwl_tx_cmd));
690
691 /*
692 * Set up the Tx-command (not MAC!) header.
693 * Store the chosen Tx queue and TFD index within the sequence field;
694 * after Tx, uCode's Tx response will return this value so driver can
695 * locate the frame within the tx queue and do post-tx processing.
696 */
697 out_cmd->hdr.cmd = REPLY_TX;
698 out_cmd->hdr.sequence = cpu_to_le16((u16)(QUEUE_TO_SEQ(txq_id) |
699 INDEX_TO_SEQ(q->write_ptr)));
700
701 /* Copy MAC header from skb into command buffer */ 670 /* Copy MAC header from skb into command buffer */
702 memcpy(tx_cmd->hdr, hdr, hdr_len); 671 memcpy(tx_cmd->hdr, hdr, hdr_len);
703 672
704
705 /* Total # bytes to be transmitted */ 673 /* Total # bytes to be transmitted */
706 len = (u16)skb->len; 674 len = (u16)skb->len;
707 tx_cmd->len = cpu_to_le16(len); 675 tx_cmd->len = cpu_to_le16(len);
@@ -716,54 +684,9 @@ int iwlagn_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
716 iwlagn_tx_cmd_build_rate(priv, tx_cmd, info, fc); 684 iwlagn_tx_cmd_build_rate(priv, tx_cmd, info, fc);
717 685
718 iwl_update_stats(priv, true, fc, len); 686 iwl_update_stats(priv, true, fc, len);
719 /*
720 * Use the first empty entry in this queue's command buffer array
721 * to contain the Tx command and MAC header concatenated together
722 * (payload data will be in another buffer).
723 * Size of this varies, due to varying MAC header length.
724 * If end is not dword aligned, we'll have 2 extra bytes at the end
725 * of the MAC header (device reads on dword boundaries).
726 * We'll tell device about this padding later.
727 */
728 len = sizeof(struct iwl_tx_cmd) +
729 sizeof(struct iwl_cmd_header) + hdr_len;
730 firstlen = (len + 3) & ~3;
731
732 /* Tell NIC about any 2-byte padding after MAC header */
733 if (firstlen != len)
734 tx_cmd->tx_flags |= TX_CMD_FLG_MH_PAD_MSK;
735
736 /* Physical address of this Tx command's header (not MAC header!),
737 * within command buffer array. */
738 txcmd_phys = dma_map_single(priv->bus.dev,
739 &out_cmd->hdr, firstlen,
740 DMA_BIDIRECTIONAL);
741 if (unlikely(dma_mapping_error(priv->bus.dev, txcmd_phys)))
742 goto drop_unlock_sta;
743 dma_unmap_addr_set(out_meta, mapping, txcmd_phys);
744 dma_unmap_len_set(out_meta, len, firstlen);
745 687
746 if (!ieee80211_has_morefrags(hdr->frame_control)) { 688 if (trans_tx(priv, skb, tx_cmd, txq_id, fc, is_agg, ctx))
747 txq->need_update = 1; 689 goto drop_unlock_sta;
748 } else {
749 wait_write_ptr = 1;
750 txq->need_update = 0;
751 }
752
753 /* Set up TFD's 2nd entry to point directly to remainder of skb,
754 * if any (802.11 null frames have no payload). */
755 secondlen = skb->len - hdr_len;
756 if (secondlen > 0) {
757 phys_addr = dma_map_single(priv->bus.dev, skb->data + hdr_len,
758 secondlen, DMA_TO_DEVICE);
759 if (unlikely(dma_mapping_error(priv->bus.dev, phys_addr))) {
760 dma_unmap_single(priv->bus.dev,
761 dma_unmap_addr(out_meta, mapping),
762 dma_unmap_len(out_meta, len),
763 DMA_BIDIRECTIONAL);
764 goto drop_unlock_sta;
765 }
766 }
767 690
768 if (ieee80211_is_data_qos(fc)) { 691 if (ieee80211_is_data_qos(fc)) {
769 priv->stations[sta_id].tid[tid].tfds_in_queue++; 692 priv->stations[sta_id].tid[tid].tfds_in_queue++;
@@ -772,55 +695,9 @@ int iwlagn_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
772 } 695 }
773 696
774 spin_unlock(&priv->sta_lock); 697 spin_unlock(&priv->sta_lock);
775
776 /* Attach buffers to TFD */
777 iwlagn_txq_attach_buf_to_tfd(priv, txq, txcmd_phys, firstlen, 1);
778 if (secondlen > 0)
779 iwlagn_txq_attach_buf_to_tfd(priv, txq, phys_addr,
780 secondlen, 0);
781
782 scratch_phys = txcmd_phys + sizeof(struct iwl_cmd_header) +
783 offsetof(struct iwl_tx_cmd, scratch);
784
785 /* take back ownership of DMA buffer to enable update */
786 dma_sync_single_for_cpu(priv->bus.dev, txcmd_phys, firstlen,
787 DMA_BIDIRECTIONAL);
788 tx_cmd->dram_lsb_ptr = cpu_to_le32(scratch_phys);
789 tx_cmd->dram_msb_ptr = iwl_get_dma_hi_addr(scratch_phys);
790
791 IWL_DEBUG_TX(priv, "sequence nr = 0X%x\n",
792 le16_to_cpu(out_cmd->hdr.sequence));
793 IWL_DEBUG_TX(priv, "tx_flags = 0X%x\n", le32_to_cpu(tx_cmd->tx_flags));
794 iwl_print_hex_dump(priv, IWL_DL_TX, (u8 *)tx_cmd, sizeof(*tx_cmd));
795 iwl_print_hex_dump(priv, IWL_DL_TX, (u8 *)tx_cmd->hdr, hdr_len);
796
797 /* Set up entry for this TFD in Tx byte-count array */
798 if (info->flags & IEEE80211_TX_CTL_AMPDU)
799 iwlagn_txq_update_byte_cnt_tbl(priv, txq,
800 le16_to_cpu(tx_cmd->len));
801
802 dma_sync_single_for_device(priv->bus.dev, txcmd_phys, firstlen,
803 DMA_BIDIRECTIONAL);
804
805 trace_iwlwifi_dev_tx(priv,
806 &((struct iwl_tfd *)txq->tfds)[txq->q.write_ptr],
807 sizeof(struct iwl_tfd),
808 &out_cmd->hdr, firstlen,
809 skb->data + hdr_len, secondlen);
810
811 /* Tell device the write index *just past* this latest filled TFD */
812 q->write_ptr = iwl_queue_inc_wrap(q->write_ptr, q->n_bd);
813 iwl_txq_update_write_ptr(priv, txq);
814 spin_unlock_irqrestore(&priv->lock, flags); 698 spin_unlock_irqrestore(&priv->lock, flags);
815 699
816 /* 700 /*
817 * At this point the frame is "transmitted" successfully
818 * and we will get a TX status notification eventually,
819 * regardless of the value of ret. "ret" only indicates
820 * whether or not we should update the write pointer.
821 */
822
823 /*
824 * Avoid atomic ops if it isn't an associated client. 701 * Avoid atomic ops if it isn't an associated client.
825 * Also, if this is a packet for aggregation, don't 702 * Also, if this is a packet for aggregation, don't
826 * increase the counter because the ucode will stop 703 * increase the counter because the ucode will stop
@@ -830,17 +707,6 @@ int iwlagn_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
830 if (sta_priv && sta_priv->client && !is_agg) 707 if (sta_priv && sta_priv->client && !is_agg)
831 atomic_inc(&sta_priv->pending_frames); 708 atomic_inc(&sta_priv->pending_frames);
832 709
833 if ((iwl_queue_space(q) < q->high_mark) && priv->mac80211_registered) {
834 if (wait_write_ptr) {
835 spin_lock_irqsave(&priv->lock, flags);
836 txq->need_update = 1;
837 iwl_txq_update_write_ptr(priv, txq);
838 spin_unlock_irqrestore(&priv->lock, flags);
839 } else {
840 iwl_stop_queue(priv, txq);
841 }
842 }
843
844 return 0; 710 return 0;
845 711
846drop_unlock_sta: 712drop_unlock_sta:
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.h b/drivers/net/wireless/iwlwifi/iwl-agn.h
index 5f58b44bb2a..aed86c6cd93 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn.h
+++ b/drivers/net/wireless/iwlwifi/iwl-agn.h
@@ -142,6 +142,10 @@ void iwlagn_stop_device(struct iwl_priv *priv);
142/* tx queue */ 142/* tx queue */
143void iwlagn_set_wr_ptrs(struct iwl_priv *priv, 143void iwlagn_set_wr_ptrs(struct iwl_priv *priv,
144 int txq_id, u32 index); 144 int txq_id, u32 index);
145void iwlagn_txq_update_byte_cnt_tbl(struct iwl_priv *priv,
146 struct iwl_tx_queue *txq,
147 u16 byte_cnt);
148
145void iwlagn_tx_queue_set_status(struct iwl_priv *priv, 149void iwlagn_tx_queue_set_status(struct iwl_priv *priv,
146 struct iwl_tx_queue *txq, 150 struct iwl_tx_queue *txq,
147 int tx_fifo_id, int scd_retry); 151 int tx_fifo_id, int scd_retry);
diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h
index a0cca02032e..173fad2ab24 100644
--- a/drivers/net/wireless/iwlwifi/iwl-dev.h
+++ b/drivers/net/wireless/iwlwifi/iwl-dev.h
@@ -1257,6 +1257,10 @@ struct iwl_trans_ops {
1257 1257
1258 int (*send_cmd_pdu)(struct iwl_priv *priv, u8 id, u32 flags, u16 len, 1258 int (*send_cmd_pdu)(struct iwl_priv *priv, u8 id, u32 flags, u16 len,
1259 const void *data); 1259 const void *data);
1260 struct iwl_tx_cmd * (*get_tx_cmd)(struct iwl_priv *priv, int txq_id);
1261 int (*tx)(struct iwl_priv *priv, struct sk_buff *skb,
1262 struct iwl_tx_cmd *tx_cmd, int txq_id, __le16 fc, bool ampdu,
1263 struct iwl_rxon_context *ctx);
1260}; 1264};
1261 1265
1262struct iwl_trans { 1266struct iwl_trans {
diff --git a/drivers/net/wireless/iwlwifi/iwl-trans.c b/drivers/net/wireless/iwlwifi/iwl-trans.c
index d760857c863..acd2a5feec9 100644
--- a/drivers/net/wireless/iwlwifi/iwl-trans.c
+++ b/drivers/net/wireless/iwlwifi/iwl-trans.c
@@ -552,6 +552,159 @@ static int iwl_trans_tx_stop(struct iwl_priv *priv)
552 return 0; 552 return 0;
553} 553}
554 554
555static struct iwl_tx_cmd *iwl_trans_get_tx_cmd(struct iwl_priv *priv,
556 int txq_id)
557{
558 struct iwl_tx_queue *txq = &priv->txq[txq_id];
559 struct iwl_queue *q = &txq->q;
560 struct iwl_device_cmd *dev_cmd;
561
562 if (unlikely(iwl_queue_space(q) < q->high_mark))
563 return NULL;
564
565 /*
566 * Set up the Tx-command (not MAC!) header.
567 * Store the chosen Tx queue and TFD index within the sequence field;
568 * after Tx, uCode's Tx response will return this value so driver can
569 * locate the frame within the tx queue and do post-tx processing.
570 */
571 dev_cmd = txq->cmd[q->write_ptr];
572 memset(dev_cmd, 0, sizeof(*dev_cmd));
573 dev_cmd->hdr.cmd = REPLY_TX;
574 dev_cmd->hdr.sequence = cpu_to_le16((u16)(QUEUE_TO_SEQ(txq_id) |
575 INDEX_TO_SEQ(q->write_ptr)));
576 return &dev_cmd->cmd.tx;
577}
578
579static int iwl_trans_tx(struct iwl_priv *priv, struct sk_buff *skb,
580 struct iwl_tx_cmd *tx_cmd, int txq_id, __le16 fc, bool ampdu,
581 struct iwl_rxon_context *ctx)
582{
583 struct iwl_tx_queue *txq = &priv->txq[txq_id];
584 struct iwl_queue *q = &txq->q;
585 struct iwl_device_cmd *dev_cmd = txq->cmd[q->write_ptr];
586 struct iwl_cmd_meta *out_meta;
587
588 dma_addr_t phys_addr = 0;
589 dma_addr_t txcmd_phys;
590 dma_addr_t scratch_phys;
591 u16 len, firstlen, secondlen;
592 u8 wait_write_ptr = 0;
593 u8 hdr_len = ieee80211_hdrlen(fc);
594
595 /* Set up driver data for this TFD */
596 memset(&(txq->txb[q->write_ptr]), 0, sizeof(struct iwl_tx_info));
597 txq->txb[q->write_ptr].skb = skb;
598 txq->txb[q->write_ptr].ctx = ctx;
599
600 /* Set up first empty entry in queue's array of Tx/cmd buffers */
601 out_meta = &txq->meta[q->write_ptr];
602
603 /*
604 * Use the first empty entry in this queue's command buffer array
605 * to contain the Tx command and MAC header concatenated together
606 * (payload data will be in another buffer).
607 * Size of this varies, due to varying MAC header length.
608 * If end is not dword aligned, we'll have 2 extra bytes at the end
609 * of the MAC header (device reads on dword boundaries).
610 * We'll tell device about this padding later.
611 */
612 len = sizeof(struct iwl_tx_cmd) +
613 sizeof(struct iwl_cmd_header) + hdr_len;
614 firstlen = (len + 3) & ~3;
615
616 /* Tell NIC about any 2-byte padding after MAC header */
617 if (firstlen != len)
618 tx_cmd->tx_flags |= TX_CMD_FLG_MH_PAD_MSK;
619
620 /* Physical address of this Tx command's header (not MAC header!),
621 * within command buffer array. */
622 txcmd_phys = dma_map_single(priv->bus.dev,
623 &dev_cmd->hdr, firstlen,
624 DMA_BIDIRECTIONAL);
625 if (unlikely(dma_mapping_error(priv->bus.dev, txcmd_phys)))
626 return -1;
627 dma_unmap_addr_set(out_meta, mapping, txcmd_phys);
628 dma_unmap_len_set(out_meta, len, firstlen);
629
630 if (!ieee80211_has_morefrags(fc)) {
631 txq->need_update = 1;
632 } else {
633 wait_write_ptr = 1;
634 txq->need_update = 0;
635 }
636
637 /* Set up TFD's 2nd entry to point directly to remainder of skb,
638 * if any (802.11 null frames have no payload). */
639 secondlen = skb->len - hdr_len;
640 if (secondlen > 0) {
641 phys_addr = dma_map_single(priv->bus.dev, skb->data + hdr_len,
642 secondlen, DMA_TO_DEVICE);
643 if (unlikely(dma_mapping_error(priv->bus.dev, phys_addr))) {
644 dma_unmap_single(priv->bus.dev,
645 dma_unmap_addr(out_meta, mapping),
646 dma_unmap_len(out_meta, len),
647 DMA_BIDIRECTIONAL);
648 return -1;
649 }
650 }
651
652 /* Attach buffers to TFD */
653 iwlagn_txq_attach_buf_to_tfd(priv, txq, txcmd_phys, firstlen, 1);
654 if (secondlen > 0)
655 iwlagn_txq_attach_buf_to_tfd(priv, txq, phys_addr,
656 secondlen, 0);
657
658 scratch_phys = txcmd_phys + sizeof(struct iwl_cmd_header) +
659 offsetof(struct iwl_tx_cmd, scratch);
660
661 /* take back ownership of DMA buffer to enable update */
662 dma_sync_single_for_cpu(priv->bus.dev, txcmd_phys, firstlen,
663 DMA_BIDIRECTIONAL);
664 tx_cmd->dram_lsb_ptr = cpu_to_le32(scratch_phys);
665 tx_cmd->dram_msb_ptr = iwl_get_dma_hi_addr(scratch_phys);
666
667 IWL_DEBUG_TX(priv, "sequence nr = 0X%x\n",
668 le16_to_cpu(dev_cmd->hdr.sequence));
669 IWL_DEBUG_TX(priv, "tx_flags = 0X%x\n", le32_to_cpu(tx_cmd->tx_flags));
670 iwl_print_hex_dump(priv, IWL_DL_TX, (u8 *)tx_cmd, sizeof(*tx_cmd));
671 iwl_print_hex_dump(priv, IWL_DL_TX, (u8 *)tx_cmd->hdr, hdr_len);
672
673 /* Set up entry for this TFD in Tx byte-count array */
674 if (ampdu)
675 iwlagn_txq_update_byte_cnt_tbl(priv, txq,
676 le16_to_cpu(tx_cmd->len));
677
678 dma_sync_single_for_device(priv->bus.dev, txcmd_phys, firstlen,
679 DMA_BIDIRECTIONAL);
680
681 trace_iwlwifi_dev_tx(priv,
682 &((struct iwl_tfd *)txq->tfds)[txq->q.write_ptr],
683 sizeof(struct iwl_tfd),
684 &dev_cmd->hdr, firstlen,
685 skb->data + hdr_len, secondlen);
686
687 /* Tell device the write index *just past* this latest filled TFD */
688 q->write_ptr = iwl_queue_inc_wrap(q->write_ptr, q->n_bd);
689 iwl_txq_update_write_ptr(priv, txq);
690
691 /*
692 * At this point the frame is "transmitted" successfully
693 * and we will get a TX status notification eventually,
694 * regardless of the value of ret. "ret" only indicates
695 * whether or not we should update the write pointer.
696 */
697 if ((iwl_queue_space(q) < q->high_mark) && priv->mac80211_registered) {
698 if (wait_write_ptr) {
699 txq->need_update = 1;
700 iwl_txq_update_write_ptr(priv, txq);
701 } else {
702 iwl_stop_queue(priv, txq);
703 }
704 }
705 return 0;
706}
707
555static const struct iwl_trans_ops trans_ops = { 708static const struct iwl_trans_ops trans_ops = {
556 .rx_init = iwl_trans_rx_init, 709 .rx_init = iwl_trans_rx_init,
557 .rx_stop = iwl_trans_rx_stop, 710 .rx_stop = iwl_trans_rx_stop,
@@ -563,6 +716,9 @@ static const struct iwl_trans_ops trans_ops = {
563 716
564 .send_cmd = iwl_send_cmd, 717 .send_cmd = iwl_send_cmd,
565 .send_cmd_pdu = iwl_send_cmd_pdu, 718 .send_cmd_pdu = iwl_send_cmd_pdu,
719
720 .get_tx_cmd = iwl_trans_get_tx_cmd,
721 .tx = iwl_trans_tx,
566}; 722};
567 723
568void iwl_trans_register(struct iwl_trans *trans) 724void iwl_trans_register(struct iwl_trans *trans)
diff --git a/drivers/net/wireless/iwlwifi/iwl-trans.h b/drivers/net/wireless/iwlwifi/iwl-trans.h
index 111acca07d7..f10bee8c1f8 100644
--- a/drivers/net/wireless/iwlwifi/iwl-trans.h
+++ b/drivers/net/wireless/iwlwifi/iwl-trans.h
@@ -102,4 +102,17 @@ static inline int trans_send_cmd_pdu(struct iwl_priv *priv, u8 id, u32 flags,
102 return priv->trans.ops->send_cmd_pdu(priv, id, flags, len, data); 102 return priv->trans.ops->send_cmd_pdu(priv, id, flags, len, data);
103} 103}
104 104
105static inline struct iwl_tx_cmd *trans_get_tx_cmd(struct iwl_priv *priv,
106 int txq_id)
107{
108 return priv->trans.ops->get_tx_cmd(priv, txq_id);
109}
110
111static inline int trans_tx(struct iwl_priv *priv, struct sk_buff *skb,
112 struct iwl_tx_cmd *tx_cmd, int txq_id, __le16 fc, bool ampdu,
113 struct iwl_rxon_context *ctx)
114{
115 return priv->trans.ops->tx(priv, skb, tx_cmd, txq_id, fc, ampdu, ctx);
116}
117
105void iwl_trans_register(struct iwl_trans *trans); 118void iwl_trans_register(struct iwl_trans *trans);