net: wireless: rockchip: add rtl8822be pcie wifi driver
[firefly-linux-kernel-4.4.55.git] / drivers / net / wireless / rockchip_wlan / rtl8822be / hal / rtl8822b / pci / rtl8822be_xmit.c
diff --git a/drivers/net/wireless/rockchip_wlan/rtl8822be/hal/rtl8822b/pci/rtl8822be_xmit.c b/drivers/net/wireless/rockchip_wlan/rtl8822be/hal/rtl8822b/pci/rtl8822be_xmit.c
new file mode 100644 (file)
index 0000000..98ef42a
--- /dev/null
@@ -0,0 +1,1576 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2015 - 2016 Realtek Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ *
+ ******************************************************************************/
+#define _RTL8822BE_XMIT_C_
+
+#include <drv_types.h>         /* PADAPTER, rtw_xmit.h and etc. */
+#include <hal_data.h>          /* HAL_DATA_TYPE */
+#include "../halmac/halmac_api.h"
+#include "../rtl8822b.h"
+#include "rtl8822be.h"
+
+/* Debug Buffer Descriptor Ring */
+/*#define BUF_DESC_DEBUG*/
+#ifdef BUF_DESC_DEBUG
+#define buf_desc_debug(...) do {\
+               RTW_INFO("BUF_DESC:" __VA_ARGS__);\
+       } while (0)
+#else
+#define buf_desc_debug(...)  do {} while (0)
+#endif
+
+static void rtl8822be_xmit_tasklet(void *priv)
+{
+       _irqL irqL;
+       _adapter *padapter = (_adapter *)priv;
+       HAL_DATA_TYPE *pHalData = GET_HAL_DATA(padapter);
+       struct dvobj_priv *pdvobjpriv = adapter_to_dvobj(padapter);
+
+       /* try to deal with the pending packets */
+       rtl8822be_xmitframe_resume(padapter);
+
+}
+
+s32 rtl8822be_init_xmit_priv(_adapter *padapter)
+{
+       s32 ret = _SUCCESS;
+       struct xmit_priv *pxmitpriv = &padapter->xmitpriv;
+       struct dvobj_priv *pdvobjpriv = adapter_to_dvobj(padapter);
+
+       _rtw_spinlock_init(&pdvobjpriv->irq_th_lock);
+
+#ifdef PLATFORM_LINUX
+       tasklet_init(&pxmitpriv->xmit_tasklet,
+                    (void(*)(unsigned long))rtl8822be_xmit_tasklet,
+                    (unsigned long)padapter);
+#endif
+
+       return ret;
+}
+
+void rtl8822be_free_xmit_priv(_adapter *padapter)
+{
+       struct dvobj_priv *pdvobjpriv = adapter_to_dvobj(padapter);
+
+       _rtw_spinlock_free(&pdvobjpriv->irq_th_lock);
+}
+
+static s32 rtl8822be_enqueue_xmitbuf(struct rtw_tx_ring        *ring,
+                                    struct xmit_buf *pxmitbuf)
+{
+       _irqL irqL;
+       _queue *ppending_queue = &ring->queue;
+
+       _func_enter_;
+
+       if (pxmitbuf == NULL)
+               return _FAIL;
+
+       rtw_list_delete(&pxmitbuf->list);
+       rtw_list_insert_tail(&(pxmitbuf->list), get_list_head(ppending_queue));
+       ring->qlen++;
+
+       _func_exit_;
+
+       return _SUCCESS;
+}
+
+struct xmit_buf *rtl8822be_dequeue_xmitbuf(struct rtw_tx_ring  *ring)
+{
+       _irqL irqL;
+       _list *plist, *phead;
+       struct xmit_buf *pxmitbuf =  NULL;
+       _queue *ppending_queue = &ring->queue;
+
+       _func_enter_;
+
+       if (_rtw_queue_empty(ppending_queue) == _TRUE)
+               pxmitbuf = NULL;
+       else {
+
+               phead = get_list_head(ppending_queue);
+               plist = get_next(phead);
+               pxmitbuf = LIST_CONTAINOR(plist, struct xmit_buf, list);
+               rtw_list_delete(&(pxmitbuf->list));
+               ring->qlen--;
+       }
+
+       _func_exit_;
+
+       return pxmitbuf;
+}
+
+static u8 *get_txbd(_adapter *padapter, u8 q_idx)
+{
+       struct xmit_priv *pxmitpriv = &padapter->xmitpriv;
+       struct rtw_tx_ring *ring;
+       u8 *ptxbd = NULL;
+       int idx = 0;
+
+       ring = &pxmitpriv->tx_ring[q_idx];
+
+       /* DO NOT use last entry. */
+       /* (len -1) to avoid wrap around overlap problem in cycler queue. */
+       if (ring->qlen == (ring->entries - 1)) {
+               RTW_INFO("No more TX desc@%d, ring->idx = %d,idx = %d\n",
+                        q_idx, ring->idx, idx);
+               return NULL;
+       }
+
+       if (q_idx == BCN_QUEUE_INX)
+               idx = 0;
+       else
+               idx = (ring->idx + ring->qlen) % ring->entries;
+
+       ptxbd = (u8 *)&ring->buf_desc[idx];
+
+       return ptxbd;
+}
+
+/*
+ * Get txbd reg addr according to q_sel
+ */
+static u16 get_txbd_rw_reg(u16 q_idx)
+{
+       u16 txbd_reg_addr = REG_BEQ_TXBD_IDX;
+
+       switch (q_idx) {
+
+       case BK_QUEUE_INX:
+               txbd_reg_addr = REG_BKQ_TXBD_IDX;
+               break;
+
+       case BE_QUEUE_INX:
+               txbd_reg_addr = REG_BEQ_TXBD_IDX;
+               break;
+
+       case VI_QUEUE_INX:
+               txbd_reg_addr = REG_VIQ_TXBD_IDX;
+               break;
+
+       case VO_QUEUE_INX:
+               txbd_reg_addr = REG_VOQ_TXBD_IDX;
+               break;
+
+       case BCN_QUEUE_INX:
+               txbd_reg_addr = REG_BEQ_TXBD_IDX;       /* need check */
+               break;
+
+       case TXCMD_QUEUE_INX:
+               txbd_reg_addr = REG_H2CQ_TXBD_IDX;
+               break;
+
+       case MGT_QUEUE_INX:
+               txbd_reg_addr = REG_MGQ_TXBD_IDX;
+               break;
+
+       case HIGH_QUEUE_INX:
+               txbd_reg_addr = REG_HI0Q_TXBD_IDX;   /* need check */
+               break;
+
+       default:
+               break;
+       }
+
+       return txbd_reg_addr;
+}
+
+struct xmit_frame *__rtw_alloc_cmdxmitframe_8822be(struct xmit_priv *pxmitpriv,
+               enum cmdbuf_type buf_type)
+{
+       _adapter *padapter;
+       u16     queue_idx = BCN_QUEUE_INX;
+       u8 *ptxdesc = NULL;
+
+       padapter = GET_PRIMARY_ADAPTER(pxmitpriv->adapter);
+       ptxdesc = get_txbd(padapter, BCN_QUEUE_INX);
+
+       /* set OWN bit in Beacon tx descriptor */
+       if (ptxdesc != NULL)
+               SET_TX_BD_OWN(ptxdesc, 0);
+       else
+               return NULL;
+
+       return __rtw_alloc_cmdxmitframe(pxmitpriv, CMDBUF_BEACON);
+}
+
+/*
+ * Update Read/Write pointer
+ *     Read pointer is h/w descriptor index
+ *     Write pointer is host desciptor index:
+ *     For tx side, if own bit is set in packet index n,
+ *     host pointer (write pointer) point to index n + 1.)
+ */
+void fill_txbd_own(_adapter *padapter, u8 *txbd, u16 queue_idx,
+       struct rtw_tx_ring *ptxring)
+{
+       struct xmit_priv *pxmitpriv = &padapter->xmitpriv;
+       struct rtw_tx_ring *ring;
+       u16 host_wp = 0;
+
+       if (queue_idx == BCN_QUEUE_INX) {
+
+               SET_TX_BD_OWN(txbd, 1);
+
+               /* kick start */
+               rtw_write8(padapter, REG_RX_RXBD_NUM + 1,
+                       rtw_read8(padapter, REG_RX_RXBD_NUM + 1) | BIT(4));
+
+               return;
+       }
+
+       /*
+        * update h/w index
+        * for tx side, if own bit is set in packet index n,
+        * host pointer (write pointer) point to index n + 1.
+        */
+
+        /* for current tx packet, enqueue has been ring->qlen++ before.
+         * so, host_wp = ring->idx + ring->qlen.
+         */
+        host_wp = (ptxring->idx + ptxring->qlen) % ptxring->entries;
+        rtw_write16(padapter, get_txbd_rw_reg(queue_idx), host_wp);
+}
+
+static u16 ffaddr2dma(u32 addr)
+{
+       u16     dma_ctrl;
+
+       switch (addr) {
+       case VO_QUEUE_INX:
+               dma_ctrl = BIT3;
+               break;
+       case VI_QUEUE_INX:
+               dma_ctrl = BIT2;
+               break;
+       case BE_QUEUE_INX:
+               dma_ctrl = BIT1;
+               break;
+       case BK_QUEUE_INX:
+               dma_ctrl = BIT0;
+               break;
+       case BCN_QUEUE_INX:
+               dma_ctrl = BIT4;
+               break;
+       case MGT_QUEUE_INX:
+               dma_ctrl = BIT6;
+               break;
+       case HIGH_QUEUE_INX:
+               dma_ctrl = BIT7;
+               break;
+       default:
+               dma_ctrl = 0;
+               break;
+       }
+
+       return dma_ctrl;
+}
+
+/*
+ * Fill tx buffer desciptor. Map each buffer address in tx buffer descriptor
+ * segment. Designed for tx buffer descriptor architecture
+ * Input *pmem: pointer to the Tx Buffer Descriptor
+ */
+static void rtl8822be_update_txbd(struct xmit_frame *pxmitframe,
+                                 u8 *txbd, s32 sz)
+{
+       _adapter *padapter = pxmitframe->padapter;
+       struct dvobj_priv *pdvobjpriv = adapter_to_dvobj(padapter);
+       dma_addr_t mapping;
+       u32 i = 0;
+       u16 seg_num =
+               ((TX_BUFFER_SEG_NUM == 0) ? 2 : ((TX_BUFFER_SEG_NUM == 1) ? 4 : 8));
+       u16 tx_page_size_reg = 1;
+       u16 page_size_length = 0;
+
+       /* map TX DESC buf_addr (including TX DESC + tx data) */
+       mapping = pci_map_single(pdvobjpriv->ppcidev, pxmitframe->buf_addr ,
+                                sz + TX_WIFI_INFO_SIZE, PCI_DMA_TODEVICE);
+
+       /* Calculate page size.
+        * Total buffer length including TX_WIFI_INFO and PacketLen */
+       if (tx_page_size_reg > 0) {
+               page_size_length = (sz + TX_WIFI_INFO_SIZE) /
+                                  (tx_page_size_reg * 128);
+               if (((sz + TX_WIFI_INFO_SIZE) % (tx_page_size_reg * 128)) > 0)
+                       page_size_length++;
+       }
+
+       /*
+        * Reset all tx buffer desciprtor content
+        * -- Reset first element
+        */
+       SET_TX_BD_TX_BUFF_SIZE0(txbd, 0);
+       SET_TX_BD_PSB(txbd, 0);
+       SET_TX_BD_OWN(txbd, 0);
+
+       /* -- Reset second and other element */
+       for (i = 1 ; i < seg_num ; i++) {
+               SET_TXBUFFER_DESC_LEN_WITH_OFFSET(txbd, i, 0);
+               SET_TXBUFFER_DESC_AMSDU_WITH_OFFSET(txbd, i, 0);
+               SET_TXBUFFER_DESC_ADD_LOW_WITH_OFFSET(txbd, i, 0);
+       }
+
+       /*
+        * Fill buffer length of the first buffer,
+        * For 8822be, it is required that TX_WIFI_INFO is put in first segment,
+        * and the size of the first segment cannot be larger than
+        * TX_WIFI_INFO_SIZE.
+        */
+       SET_TX_BD_TX_BUFF_SIZE0(txbd, TX_WIFI_INFO_SIZE);
+       SET_TX_BD_PSB(txbd, page_size_length);
+       /* starting addr of TXDESC */
+       SET_TX_BD_PHYSICAL_ADDR0_LOW(txbd, mapping);
+
+       /*
+        * It is assumed that in linux implementation, packet is coalesced
+        * in only one buffer. Extension mode is not supported here
+        */
+       SET_TXBUFFER_DESC_LEN_WITH_OFFSET(txbd, 1, sz);
+       /* don't using extendsion mode. */
+       SET_TXBUFFER_DESC_AMSDU_WITH_OFFSET(txbd, 1, 0);
+       SET_TXBUFFER_DESC_ADD_LOW_WITH_OFFSET(txbd, 1,
+                                     mapping + TX_WIFI_INFO_SIZE); /* pkt */
+
+       /*buf_desc_debug("TX:%s, txbd = 0x%p\n", __FUNCTION__, txbd);*/
+       buf_desc_debug("%s, txbd = 0x%08x\n", __func__, txbd);
+       buf_desc_debug("TXBD:, 00h(0x%08x)\n", *((u32 *)(txbd)));
+       buf_desc_debug("TXBD:, 04h(0x%08x)\n", *((u32 *)(txbd + 4)));
+       buf_desc_debug("TXBD:, 08h(0x%08x)\n", *((u32 *)(txbd + 8)));
+       buf_desc_debug("TXBD:, 12h(0x%08x)\n", *((u32 *)(txbd + 12)));
+
+}
+
+static s32 update_txdesc(struct xmit_frame *pxmitframe, s32 sz)
+{
+       uint qsel;
+       u8 data_rate, pwr_status;
+       _adapter *padapter = pxmitframe->padapter;
+       struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
+       struct dvobj_priv *pdvobjpriv = adapter_to_dvobj(padapter);
+       struct pkt_attrib *pattrib = &pxmitframe->attrib;
+       HAL_DATA_TYPE *pHalData = GET_HAL_DATA(padapter);
+       struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
+       struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info);
+       u8 *ptxdesc;
+       sint bmcst = IS_MCAST(pattrib->ra);
+       u16 SWDefineContent = 0x0;
+       u8 DriverFixedRate = 0x0;
+
+       ptxdesc = pxmitframe->buf_addr;
+       _rtw_memset(ptxdesc, 0, TXDESC_SIZE);
+
+       /* offset 0 */
+       /*SET_TX_DESC_FIRST_SEG_8812(ptxdesc, 1);*/
+       SET_TX_DESC_LS_8822B(ptxdesc, 1);
+       /*SET_TX_DESC_OWN_8812(ptxdesc, 1);*/
+
+       SET_TX_DESC_TXPKTSIZE_8822B(ptxdesc, sz);
+       SET_TX_DESC_OFFSET_8822B(ptxdesc, TXDESC_SIZE);
+
+#ifdef CONFIG_TX_EARLY_MODE
+       SET_TX_DESC_PKT_OFFSET_8812(ptxdesc, 1);
+       SET_TX_DESC_OFFSET_8822B(ptxdesc, TXDESC_SIZE + EARLY_MODE_INFO_SIZE);
+#endif
+
+       if (bmcst)
+               SET_TX_DESC_BMC_8822B(ptxdesc, 1);
+
+       SET_TX_DESC_MACID_8822B(ptxdesc, pattrib->mac_id);
+       SET_TX_DESC_RATE_ID_8822B(ptxdesc, pattrib->raid);
+
+       SET_TX_DESC_QSEL_8822B(ptxdesc,  pattrib->qsel);
+
+       if (!pattrib->qos_en) {
+               /* Hw set sequence number */
+               SET_TX_DESC_EN_HWSEQ_8822B(ptxdesc, 1);
+               SET_TX_DESC_EN_HWEXSEQ_8822B(ptxdesc, 0);
+               SET_TX_DESC_DISQSELSEQ_8822B(ptxdesc, 1);
+               SET_TX_DESC_HW_SSN_SEL_8822B(ptxdesc, 0);
+       } else
+               SET_TX_DESC_SW_SEQ_8822B(ptxdesc, pattrib->seqnum);
+
+       if ((pxmitframe->frame_tag & 0x0f) == DATA_FRAMETAG) {
+               rtl8822b_fill_txdesc_sectype(pattrib, ptxdesc);
+               rtl8822b_fill_txdesc_vcs(padapter, pattrib, ptxdesc);
+
+#ifdef CONFIG_CONCURRENT_MODE
+               if (bmcst)
+                       rtl8822b_fill_txdesc_force_bmc_camid(pattrib, ptxdesc);
+#endif
+
+               if ((pattrib->ether_type != 0x888e) &&
+                   (pattrib->ether_type != 0x0806) &&
+                   (pattrib->ether_type != 0x88b4) &&
+                   (pattrib->dhcp_pkt != 1)
+#ifdef CONFIG_AUTO_AP_MODE
+                   && (pattrib->pctrl != _TRUE)
+#endif
+                  ) {
+                       /* Non EAP & ARP & DHCP type data packet */
+
+                       if (pattrib->ampdu_en == _TRUE) {
+                               /* 8822b does NOT support AGG broadcast pkt */
+                               if (!bmcst)
+                                       SET_TX_DESC_AGG_EN_8822B(ptxdesc, 1);
+
+                               SET_TX_DESC_MAX_AGG_NUM_8822B(ptxdesc, 0x1f);
+                               /* Set A-MPDU aggregation. */
+                               SET_TX_DESC_AMPDU_DENSITY_8822B(ptxdesc,
+                                                       pattrib->ampdu_spacing);
+                       } else
+                               SET_TX_DESC_BK_8822B(ptxdesc, 1);
+
+                       rtl8822b_fill_txdesc_phy(padapter, pattrib, ptxdesc);
+
+                       /* DATA  Rate FB LMT */
+                       /* compatibility for MCC consideration, use pmlmeext->cur_channel */
+                       if (pmlmeext->cur_channel > 14)
+                               /* for 5G. OFMD 6M */
+                               SET_TX_DESC_DATA_RTY_LOWEST_RATE_8822B(
+                                       ptxdesc, 4);
+                       else
+                               /* for 2.4G. CCK 1M */
+                               SET_TX_DESC_DATA_RTY_LOWEST_RATE_8822B(
+                                       ptxdesc, 0);
+
+                       if (pHalData->fw_ractrl == _FALSE) {
+                               SET_TX_DESC_USE_RATE_8822B(ptxdesc, 1);
+                               DriverFixedRate = 0x01;
+
+                               if (pHalData->INIDATA_RATE[pattrib->mac_id] &
+                                   BIT(7))
+                                       SET_TX_DESC_DATA_SHORT_8822B(
+                                               ptxdesc, 1);
+
+                               SET_TX_DESC_DATARATE_8822B(ptxdesc,
+                                       pHalData->INIDATA_RATE[pattrib->mac_id]
+                                                          & 0x7F);
+                       }
+
+                       if (padapter->fix_rate != 0xFF) {
+                               /* modify data rate by iwpriv */
+                               SET_TX_DESC_USE_RATE_8822B(ptxdesc, 1);
+
+                               DriverFixedRate = 0x01;
+                               if (padapter->fix_rate & BIT(7))
+                                       SET_TX_DESC_DATA_SHORT_8822B(
+                                               ptxdesc, 1);
+
+                               SET_TX_DESC_DATARATE_8822B(ptxdesc,
+                                                  (padapter->fix_rate & 0x7F));
+                               if (!padapter->data_fb)
+                                       SET_TX_DESC_DISDATAFB_8822B(ptxdesc, 1);
+                       }
+
+                       if (pattrib->ldpc)
+                               SET_TX_DESC_DATA_LDPC_8822B(ptxdesc, 1);
+                       if (pattrib->stbc)
+                               SET_TX_DESC_DATA_STBC_8822B(ptxdesc, 1);
+               } else {
+                       /*
+                        * EAP data packet and ARP packet and DHCP.
+                        * Use the 1M data rate to send the EAP/ARP packet.
+                        * This will maybe make the handshake smooth.
+                        */
+
+                       SET_TX_DESC_USE_RATE_8822B(ptxdesc, 1);
+                       DriverFixedRate = 0x01;
+                       SET_TX_DESC_BK_8822B(ptxdesc, 1);
+
+                       /* HW will ignore this setting if the transmission rate
+                        * is legacy OFDM. */
+                       if (pmlmeinfo->preamble_mode == PREAMBLE_SHORT)
+                               SET_TX_DESC_DATA_SHORT_8822B(ptxdesc, 1);
+
+                       SET_TX_DESC_DATARATE_8822B(ptxdesc,
+                                          MRateToHwRate(pmlmeext->tx_rate));
+               }
+
+#ifdef CONFIG_TDLS
+#ifdef CONFIG_XMIT_ACK
+               /* CCX-TXRPT ack for xmit mgmt frames. */
+               if (pxmitframe->ack_report) {
+                       SET_TX_DESC_SPE_RPT_8812(ptxdesc, 1);
+#ifdef DBG_CCX
+                       RTW_INFO("%s set tx report\n", __func__);
+#endif
+               }
+#endif /* CONFIG_XMIT_ACK */
+#endif
+       } else if ((pxmitframe->frame_tag & 0x0f) == MGNT_FRAMETAG) {
+               SET_TX_DESC_USE_RATE_8822B(ptxdesc, 1);
+               DriverFixedRate = 0x01;
+
+#ifdef CONFIG_INTEL_PROXIM
+               if ((padapter->proximity.proxim_on == _TRUE) &&
+                   (pattrib->intel_proxim == _TRUE)) {
+                       RTW_INFO("\n %s pattrib->rate=%d\n",
+                                __func__, pattrib->rate);
+                       SET_TX_DESC_DATARATE_8822B(ptxdesc, pattrib->rate);
+               } else
+#endif
+                       SET_TX_DESC_DATARATE_8822B(ptxdesc,
+                                          MRateToHwRate(pattrib->rate));
+
+#if 1 /* 8822bu add */
+               /* VHT NDPA or HT NDPA Packet for Beamformer. */
+               if ((pattrib->subtype == WIFI_NDPA) ||
+                   ((pattrib->subtype == WIFI_ACTION_NOACK) &&
+                    (pattrib->order == 1))) {
+
+                       SET_TX_DESC_NAVUSEHDR_8822B(ptxdesc, 1);
+
+                       SET_TX_DESC_DATA_BW_8822B(ptxdesc,
+                                 rtl8822b_bw_mapping(padapter, pattrib));
+                       SET_TX_DESC_RTS_SC_8822B(ptxdesc,
+                                rtl8822b_sc_mapping(padapter, pattrib));
+
+                       SET_TX_DESC_RTY_LMT_EN_8822B(ptxdesc, 1);
+                       SET_TX_DESC_RTS_DATA_RTY_LMT_8822B(ptxdesc, 5);
+                       SET_TX_DESC_DISRTSFB_8822B(ptxdesc, 1);
+                       SET_TX_DESC_NDPA_8822B(ptxdesc, 1);
+               } else {
+                       SET_TX_DESC_RTY_LMT_EN_8822B(ptxdesc, 1);
+                       if (pattrib->retry_ctrl == _TRUE)
+                               SET_TX_DESC_RTS_DATA_RTY_LMT_8822B(ptxdesc, 6);
+                       else
+                               SET_TX_DESC_RTS_DATA_RTY_LMT_8822B(ptxdesc, 12);
+               }
+#endif
+
+#ifdef CONFIG_XMIT_ACK
+               /* CCX-TXRPT ack for xmit mgmt frames. */
+               if (pxmitframe->ack_report) {
+                       SET_TX_DESC_SPE_RPT_8822B(ptxdesc, 1);
+#ifdef DBG_CCX
+                       RTW_INFO("%s set tx report\n", __func__);
+#endif
+               }
+#endif /* CONFIG_XMIT_ACK */
+       } else if ((pxmitframe->frame_tag & 0x0f) == TXAGG_FRAMETAG)
+               RTW_INFO("pxmitframe->frame_tag == TXAGG_FRAMETAG\n");
+#ifdef CONFIG_MP_INCLUDED
+       else if (((pxmitframe->frame_tag & 0x0f) == MP_FRAMETAG) &&
+                (padapter->registrypriv.mp_mode == 1))
+               fill_txdesc_for_mp(padapter, ptxdesc);
+#endif
+       else {
+               RTW_INFO("pxmitframe->frame_tag = %d\n",
+                        pxmitframe->frame_tag);
+
+               SET_TX_DESC_USE_RATE_8822B(ptxdesc, 1);
+               DriverFixedRate = 0x01;
+               SET_TX_DESC_DATARATE_8822B(ptxdesc,
+                                          MRateToHwRate(pmlmeext->tx_rate));
+       }
+
+#ifdef CONFIG_ANTENNA_DIVERSITY
+       ODM_SetTxAntByTxInfo(&pHalData->odmpriv, ptxdesc,
+                            pxmitframe->attrib.mac_id);
+#endif
+
+#ifdef CONFIG_BEAMFORMING
+       SET_TX_DESC_G_ID_8822B(ptxdesc, pattrib->txbf_g_id);
+       SET_TX_DESC_P_AID_8822B(ptxdesc, pattrib->txbf_p_aid);
+#endif
+
+       /*SET_TX_DESC_TX_BUFFER_SIZE_8812(ptxdesc, sz);*/
+
+       if (DriverFixedRate)
+               SWDefineContent |= 0x01;
+
+       SET_TX_DESC_SW_DEFINE_8822B(ptxdesc, SWDefineContent);
+
+       rtl8822b_cal_txdesc_chksum(padapter, ptxdesc);
+       rtl8822b_dbg_dump_tx_desc(padapter, pxmitframe->frame_tag, ptxdesc);
+       return 0;
+}
+
+s32 rtl8822be_dump_xframe(_adapter *padapter, struct xmit_frame *pxmitframe)
+{
+       s32 ret = _SUCCESS;
+       s32 inner_ret = _SUCCESS;
+       _irqL irqL;
+       int t, sz, w_sz, pull = 0;
+       u32 ff_hwaddr;
+       struct xmit_buf *pxmitbuf = pxmitframe->pxmitbuf;
+       struct pkt_attrib *pattrib = &pxmitframe->attrib;
+       struct xmit_priv *pxmitpriv = &padapter->xmitpriv;
+       struct dvobj_priv *pdvobjpriv = adapter_to_dvobj(padapter);
+       struct security_priv *psecuritypriv = &padapter->securitypriv;
+       u8 *txbd;
+       struct rtw_tx_ring *ptx_ring;
+
+       DBG_COUNTER(padapter->tx_logs.intf_tx_dump_xframe);
+       RT_TRACE(_module_rtl871x_xmit_c_, _drv_info_,
+                ("rtl8822be_dump_xframe()\n"));
+
+       if ((pxmitframe->frame_tag == DATA_FRAMETAG) &&
+           (pxmitframe->attrib.ether_type != 0x0806) &&
+           (pxmitframe->attrib.ether_type != 0x888e) &&
+           (pxmitframe->attrib.dhcp_pkt != 1))
+               rtw_issue_addbareq_cmd(padapter, pxmitframe);
+
+       for (t = 0; t < pattrib->nr_frags; t++) {
+
+               if (inner_ret != _SUCCESS && ret == _SUCCESS)
+                       ret = _FAIL;
+
+               if (t != (pattrib->nr_frags - 1)) {
+                       RT_TRACE(_module_rtl871x_xmit_c_, _drv_err_,
+                                ("pattrib->nr_frags=%d\n", pattrib->nr_frags));
+
+                       sz = pxmitpriv->frag_len - 4;
+
+                       if (!psecuritypriv->sw_encrypt)
+                               sz -= pattrib->icv_len;
+               } else {
+                       /* no frag */
+                       sz = pattrib->last_txcmdsz;
+               }
+
+               ff_hwaddr = rtw_get_ff_hwaddr(pxmitframe);
+
+               _enter_critical(&pdvobjpriv->irq_th_lock, &irqL);
+               txbd = get_txbd(GET_PRIMARY_ADAPTER(padapter), ff_hwaddr);
+
+               ptx_ring = &(GET_PRIMARY_ADAPTER(padapter)->xmitpriv.tx_ring[ff_hwaddr]);
+
+#ifndef CONFIG_BCN_ICF
+               if (BCN_QUEUE_INX == ff_hwaddr)
+                       padapter->xmitpriv.beaconDMAing = _TRUE;
+#endif
+
+               if (txbd == NULL) {
+                       _exit_critical(&pdvobjpriv->irq_th_lock, &irqL);
+                       rtw_sctx_done_err(&pxmitbuf->sctx,
+                                         RTW_SCTX_DONE_TX_DESC_NA);
+                       rtw_free_xmitbuf(pxmitpriv, pxmitbuf);
+                       RTW_INFO("##### Tx desc unavailable !#####\n");
+                       DBG_COUNTER(padapter->tx_logs.intf_tx_dump_xframe_err_txdesc);
+                       break;
+               }
+
+               if (pattrib->qsel != HALMAC_TXDESC_QSEL_H2C_CMD)
+                       update_txdesc(pxmitframe, sz);
+
+               /* rtl8822be_update_txbd() must be called after update_txdesc().
+                * It rely on rtl8822be_update_txbd() to map it into non cache
+                * memory */
+
+               rtl8822be_update_txbd(pxmitframe, txbd, sz);
+
+               if (pxmitbuf->buf_tag != XMITBUF_CMD)
+                       rtl8822be_enqueue_xmitbuf(ptx_ring, pxmitbuf);
+
+               pxmitbuf->len = sz + TX_WIFI_INFO_SIZE;
+               w_sz = sz;
+
+               /* Please comment here */
+               wmb();
+               fill_txbd_own(padapter, txbd, ff_hwaddr, ptx_ring);
+
+               _exit_critical(&pdvobjpriv->irq_th_lock, &irqL);
+
+               inner_ret = rtw_write_port(padapter, ff_hwaddr, w_sz,
+                                          (unsigned char *)pxmitbuf);
+               if (inner_ret != _SUCCESS)
+                       DBG_COUNTER(padapter->tx_logs.intf_tx_dump_xframe_err_port);
+
+               rtw_count_tx_stats(padapter, pxmitframe, sz);
+               RT_TRACE(_module_rtl871x_xmit_c_, _drv_info_,
+                        ("rtw_write_port, w_sz=%d\n", w_sz));
+       }
+
+       rtw_free_xmitframe(pxmitpriv, pxmitframe);
+
+       if (ret != _SUCCESS)
+               rtw_sctx_done_err(&pxmitbuf->sctx, RTW_SCTX_DONE_UNKNOWN);
+
+       return ret;
+}
+
+/*
+ * Packet should not be dequeued if there is no available descriptor
+ * return: _SUCCESS if there is available descriptor
+ */
+static u8 check_tx_desc_resource(_adapter *padapter, int prio)
+{
+       struct xmit_priv        *pxmitpriv = &padapter->xmitpriv;
+       struct rtw_tx_ring      *ring;
+
+       ring = &pxmitpriv->tx_ring[prio];
+
+       /*
+        * for now we reserve two free descriptor as a safety boundary
+        * between the tail and the head
+        */
+
+       if ((ring->entries - ring->qlen) >= 2)
+               return _TRUE;
+       else
+               return _FALSE;
+}
+
+static u8 check_nic_enough_desc_all(_adapter *padapter)
+{
+       u8 status = (check_tx_desc_resource(padapter, VI_QUEUE_INX) &&
+                    check_tx_desc_resource(padapter, VO_QUEUE_INX) &&
+                    check_tx_desc_resource(padapter, BE_QUEUE_INX) &&
+                    check_tx_desc_resource(padapter, BK_QUEUE_INX) &&
+                    check_tx_desc_resource(padapter, MGT_QUEUE_INX) &&
+                    check_tx_desc_resource(padapter, TXCMD_QUEUE_INX) &&
+                    check_tx_desc_resource(padapter, HIGH_QUEUE_INX));
+       return status;
+}
+#ifdef TX_AMSDU
+static s32 xmitframe_amsdu_direct(_adapter *padapter, struct xmit_frame *pxmitframe)
+{
+       struct xmit_buf *pxmitbuf = pxmitframe->pxmitbuf;
+       struct xmit_priv *pxmitpriv = &padapter->xmitpriv;
+       s32 res = _SUCCESS;
+
+       res = rtw_xmitframe_coalesce_amsdu(padapter, pxmitframe, NULL);
+
+       if(res == _FAIL)
+               goto free_frame;
+
+       DBG_COUNTER(padapter->tx_logs.intf_tx_dequeue);
+       res = rtl8822be_dump_xframe(padapter, pxmitframe);
+
+       if (res == _FAIL) {
+               DBG_COUNTER(padapter->tx_logs.intf_tx_dequeue_err_coalesce);
+               goto free_frame;
+       }
+
+       return res;
+
+free_frame:
+       rtw_free_xmitbuf(pxmitpriv, pxmitbuf);
+       rtw_free_xmitframe(pxmitpriv, pxmitframe);
+
+       return res;
+}
+#endif
+
+static s32 xmitframe_direct(_adapter *padapter, struct xmit_frame *pxmitframe)
+{
+       s32 res = _SUCCESS;
+
+       DBG_COUNTER(padapter->tx_logs.intf_tx_direct);
+       res = rtw_xmitframe_coalesce(padapter, pxmitframe->pkt, pxmitframe);
+       if (res == _SUCCESS)
+               rtl8822be_dump_xframe(padapter, pxmitframe);
+       else
+               DBG_COUNTER(padapter->tx_logs.intf_tx_direct_err_coalesce);
+
+       return res;
+}
+
+void rtl8822be_xmitframe_resume(_adapter *padapter)
+{
+       struct xmit_priv        *pxmitpriv = &padapter->xmitpriv;
+       struct xmit_frame *pxmitframe = NULL;
+       struct xmit_buf *pxmitbuf = NULL;
+       int res = _SUCCESS, xcnt = 0;
+
+#ifdef TX_AMSDU
+       struct mlme_priv *pmlmepriv =  &padapter->mlmepriv;
+       struct dvobj_priv       *pdvobjpriv = adapter_to_dvobj(padapter);
+
+       int tx_amsdu = padapter->tx_amsdu;
+       int tx_amsdu_rate = padapter->tx_amsdu_rate;
+       int current_tx_rate = pdvobjpriv->traffic_stat.cur_tx_tp;
+
+       struct pkt_attrib *pattrib = NULL;
+
+       struct xmit_frame *pxmitframe_next = NULL;
+       struct xmit_buf *pxmitbuf_next = NULL;
+       struct pkt_attrib *pattrib_next = NULL;
+       int num_frame = 0;
+
+       u8 amsdu_timeout = 0;
+#endif
+
+       RT_TRACE(_module_rtl871x_xmit_c_, _drv_info_, ("%s()\n", __func__));
+
+       while (1) {
+               if (RTW_CANNOT_RUN(padapter)) {
+                       RTW_INFO("%s => bDriverStopped or bSurpriseRemoved\n",
+                                __func__);
+                       break;
+               }
+
+               if (!check_nic_enough_desc_all(padapter))
+                       break;
+
+               pxmitbuf = rtw_alloc_xmitbuf(pxmitpriv);
+               if (!pxmitbuf)
+                       break;
+
+       #ifdef TX_AMSDU
+               if(tx_amsdu == 0)
+                       goto dump_pkt;
+
+               if(!check_fwstate(pmlmepriv, WIFI_STATION_STATE))
+                        goto dump_pkt;
+
+               pxmitframe = rtw_get_xframe(pxmitpriv, &num_frame);
+
+               if(num_frame == 0 || pxmitframe == NULL || !check_amsdu(pxmitframe))
+                       goto dump_pkt;
+
+               if(tx_amsdu == 1)
+               {
+                       pxmitframe =  rtw_dequeue_xframe(pxmitpriv, pxmitpriv->hwxmits, pxmitpriv->hwxmit_entry);
+                       if (pxmitframe)
+                       {
+                               pxmitframe->pxmitbuf = pxmitbuf;
+                               pxmitframe->buf_addr = pxmitbuf->pbuf;
+                               pxmitbuf->priv_data = pxmitframe;
+                               xmitframe_amsdu_direct(padapter, pxmitframe);
+                               pxmitpriv->amsdu_debug_coalesce_one++;
+                               continue;
+                       }
+                       else
+                       {
+                               rtw_free_xmitbuf(pxmitpriv, pxmitbuf);
+                               break;
+                       }
+               }
+               else if(tx_amsdu == 2 && ((tx_amsdu_rate == 0) || (current_tx_rate > tx_amsdu_rate)))
+               {
+
+                       if(num_frame == 1)
+                       {
+                               pattrib = &pxmitframe->attrib;
+                               amsdu_timeout = rtw_amsdu_get_timer_status(padapter, pattrib->priority);
+
+                               if(amsdu_timeout == RTW_AMSDU_TIMER_UNSET)
+                               {
+                                       rtw_free_xmitbuf(pxmitpriv, pxmitbuf);
+                                       rtw_amsdu_set_timer_status(padapter, pattrib->priority, RTW_AMSDU_TIMER_SETTING);
+                                       rtw_amsdu_set_timer(padapter, pattrib->priority);
+                                       pxmitpriv->amsdu_debug_set_timer++;
+                                       break;
+                               }
+                               else if(amsdu_timeout == RTW_AMSDU_TIMER_SETTING)
+                               {
+                                       rtw_free_xmitbuf(pxmitpriv, pxmitbuf);
+                                       break;
+                               }
+                               else if(amsdu_timeout == RTW_AMSDU_TIMER_TIMEOUT)
+                               {
+                                       rtw_amsdu_set_timer_status(padapter, pattrib->priority, RTW_AMSDU_TIMER_UNSET);
+                                       pxmitpriv->amsdu_debug_timeout++;
+                                       pxmitframe = rtw_dequeue_xframe(pxmitpriv, pxmitpriv->hwxmits, pxmitpriv->hwxmit_entry);
+                                       if (pxmitframe)
+                                       {
+                                               pxmitframe->pxmitbuf = pxmitbuf;
+                                               pxmitframe->buf_addr = pxmitbuf->pbuf;
+                                               pxmitbuf->priv_data = pxmitframe;
+                                               xmitframe_amsdu_direct(padapter, pxmitframe);
+                                               break;
+                                       }
+                                       else
+                                       {
+                                               rtw_free_xmitbuf(pxmitpriv, pxmitbuf);
+                                               break;
+                                       }
+
+                               }
+                       }
+                       else/* num_frame > 1*/
+                       {
+                               pxmitframe = rtw_dequeue_xframe(pxmitpriv, pxmitpriv->hwxmits, pxmitpriv->hwxmit_entry);
+
+                               if(!pxmitframe)
+                               {
+                                       rtw_free_xmitbuf(pxmitpriv, pxmitbuf);
+                                       break;
+                               }
+
+                               pxmitframe->pxmitbuf = pxmitbuf;
+                               pxmitframe->buf_addr = pxmitbuf->pbuf;
+                               pxmitbuf->priv_data = pxmitframe;
+
+                               pxmitframe_next = rtw_get_xframe(pxmitpriv, &num_frame);
+
+                               if(num_frame == 0)
+                               {
+                                       xmitframe_amsdu_direct(padapter, pxmitframe);
+                                       pxmitpriv->amsdu_debug_coalesce_one++;
+                                       break;
+                               }
+
+                               if(!check_amsdu(pxmitframe_next))
+                               {
+                                       xmitframe_amsdu_direct(padapter, pxmitframe);
+                                       pxmitpriv->amsdu_debug_coalesce_one++;
+                                       continue;
+                               }
+                               else
+                               {
+                                       pxmitbuf_next = rtw_alloc_xmitbuf(pxmitpriv);
+                                       if (!pxmitbuf_next)
+                                       {
+                                               xmitframe_amsdu_direct(padapter, pxmitframe);
+                                               pxmitpriv->amsdu_debug_coalesce_one++;
+                                               continue;
+                                       }
+
+                                       pxmitframe_next = rtw_dequeue_xframe(pxmitpriv, pxmitpriv->hwxmits, pxmitpriv->hwxmit_entry);
+                                       if(!pxmitframe_next)
+                                       {
+                                               rtw_free_xmitbuf(pxmitpriv, pxmitbuf_next);
+                                               xmitframe_amsdu_direct(padapter, pxmitframe);
+                                               pxmitpriv->amsdu_debug_coalesce_one++;
+                                               continue;
+                                       }
+                                       pxmitframe_next->pxmitbuf = pxmitbuf_next;
+                                       pxmitframe_next->buf_addr = pxmitbuf_next->pbuf;
+                                       pxmitbuf_next->priv_data = pxmitframe_next;
+
+                                       rtw_xmitframe_coalesce_amsdu(padapter, pxmitframe_next , pxmitframe);
+                                       rtw_free_xmitframe(pxmitpriv, pxmitframe);
+                                       rtw_free_xmitbuf(pxmitpriv, pxmitbuf);
+
+                                       rtl8822be_dump_xframe(padapter, pxmitframe_next);
+                                       pxmitpriv->amsdu_debug_coalesce_two++;
+
+                                       continue;
+                               }
+
+                       }
+
+               }
+dump_pkt:
+       #endif
+
+               pxmitframe =  rtw_dequeue_xframe(pxmitpriv, pxmitpriv->hwxmits,
+                                                pxmitpriv->hwxmit_entry);
+
+               if (pxmitframe) {
+                       pxmitframe->pxmitbuf = pxmitbuf;
+                       pxmitframe->buf_addr = pxmitbuf->pbuf;
+                       pxmitbuf->priv_data = pxmitframe;
+
+                       if ((pxmitframe->frame_tag & 0x0f) == DATA_FRAMETAG) {
+                               if (pxmitframe->attrib.priority <= 15) {
+                                       /* TID0~15 */
+                                       res = rtw_xmitframe_coalesce(padapter,
+                                               pxmitframe->pkt, pxmitframe);
+                               }
+
+                               /* always return ndis_packet after
+                                * rtw_xmitframe_coalesce */
+                               rtw_os_xmit_complete(padapter, pxmitframe);
+                       }
+
+                       DBG_COUNTER(padapter->tx_logs.intf_tx_dequeue);
+                       RT_TRACE(_module_rtl871x_xmit_c_, _drv_info_,
+                                ("%s(): rtl8822be_dump_xframe\n", __func__));
+
+                       if (res == _SUCCESS)
+                               rtl8822be_dump_xframe(padapter, pxmitframe);
+                       else {
+                               DBG_COUNTER(padapter->tx_logs.intf_tx_dequeue_err_coalesce);
+                               rtw_free_xmitbuf(pxmitpriv, pxmitbuf);
+                               rtw_free_xmitframe(pxmitpriv, pxmitframe);
+                       }
+
+                       xcnt++;
+               } else {
+                       rtw_free_xmitbuf(pxmitpriv, pxmitbuf);
+                       break;
+               }
+       }
+}
+
+static u8 check_nic_enough_desc(_adapter *padapter, struct pkt_attrib *pattrib)
+{
+       u32 prio;
+       struct xmit_priv        *pxmitpriv = &padapter->xmitpriv;
+       struct rtw_tx_ring      *ring;
+
+       switch (pattrib->qsel) {
+       case 0:
+       case 3:
+               prio = BE_QUEUE_INX;
+               break;
+       case 1:
+       case 2:
+               prio = BK_QUEUE_INX;
+               break;
+       case 4:
+       case 5:
+               prio = VI_QUEUE_INX;
+               break;
+       case 6:
+       case 7:
+               prio = VO_QUEUE_INX;
+               break;
+       default:
+               prio = BE_QUEUE_INX;
+               break;
+       }
+
+       ring = &pxmitpriv->tx_ring[prio];
+
+       /*
+        * for now we reserve two free descriptor as a safety boundary
+        * between the tail and the head
+        */
+       if ((ring->entries - ring->qlen) >= 2)
+               return _TRUE;
+       else
+               return _FALSE;
+}
+
+/*
+ * Return
+ *     _TRUE   dump packet directly
+ *     _FALSE  enqueue packet
+ */
+static s32 pre_xmitframe(_adapter *padapter, struct xmit_frame *pxmitframe)
+{
+       _irqL irqL;
+       s32 res;
+       struct xmit_buf *pxmitbuf = NULL;
+       struct xmit_priv *pxmitpriv = &padapter->xmitpriv;
+       struct pkt_attrib *pattrib = &pxmitframe->attrib;
+       struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
+
+#ifdef TX_AMSDU
+       struct dvobj_priv       *pdvobjpriv = adapter_to_dvobj(padapter);
+       int tx_amsdu = padapter->tx_amsdu;
+       int tx_amsdu_rate = padapter->tx_amsdu_rate;
+       int current_tx_rate = pdvobjpriv->traffic_stat.cur_tx_tp;
+
+       u8 amsdu_timeout = 0;
+#endif
+
+       _enter_critical_bh(&pxmitpriv->lock, &irqL);
+
+       if ((rtw_txframes_sta_ac_pending(padapter, pattrib) > 0) ||
+           (check_nic_enough_desc(padapter, pattrib) == _FALSE)) {
+           DBG_COUNTER(padapter->tx_logs.intf_tx_pending_ac);
+               goto enqueue;
+       }
+
+       if (rtw_xmit_ac_blocked(padapter) == _TRUE) {
+               DBG_COUNTER(padapter->tx_logs.intf_tx_pending_fw_under_survey);
+               goto enqueue;
+       }
+
+       if (padapter->dvobj->iface_state.lg_sta_num) {
+               DBG_COUNTER(padapter->tx_logs.intf_tx_pending_fw_under_linking);
+               goto enqueue;
+       }
+
+#ifdef TX_AMSDU
+       if(check_fwstate(pmlmepriv, WIFI_STATION_STATE))
+       {
+               if(tx_amsdu == 1)
+                       goto enqueue;
+               else if(tx_amsdu == 2 && (tx_amsdu_rate == 0 || current_tx_rate > tx_amsdu_rate))
+                       goto enqueue;
+       }
+#endif
+
+       pxmitbuf = rtw_alloc_xmitbuf(pxmitpriv);
+       if (pxmitbuf == NULL) {
+               DBG_COUNTER(padapter->tx_logs.intf_tx_pending_xmitbuf);
+               goto enqueue;
+       }
+
+       _exit_critical_bh(&pxmitpriv->lock, &irqL);
+
+       pxmitframe->pxmitbuf = pxmitbuf;
+       pxmitframe->buf_addr = pxmitbuf->pbuf;
+       pxmitbuf->priv_data = pxmitframe;
+
+       if (xmitframe_direct(padapter, pxmitframe) != _SUCCESS) {
+               rtw_free_xmitbuf(pxmitpriv, pxmitbuf);
+               rtw_free_xmitframe(pxmitpriv, pxmitframe);
+       }
+
+       return _TRUE;
+
+enqueue:
+       res = rtw_xmitframe_enqueue(padapter, pxmitframe);
+
+#ifdef TX_AMSDU
+       if(res == _SUCCESS && tx_amsdu == 2)
+       {
+               amsdu_timeout = rtw_amsdu_get_timer_status(padapter, pattrib->priority);
+               if(amsdu_timeout == RTW_AMSDU_TIMER_SETTING)
+               {
+                       rtw_amsdu_cancel_timer(padapter, pattrib->priority);
+                       rtw_amsdu_set_timer_status(padapter, pattrib->priority, RTW_AMSDU_TIMER_UNSET);
+               }
+       }
+#endif
+
+       _exit_critical_bh(&pxmitpriv->lock, &irqL);
+
+       if (res != _SUCCESS) {
+               RT_TRACE(_module_xmit_osdep_c_, _drv_err_,
+                        ("pre_xmitframe: enqueue xmitframe fail\n"));
+               rtw_free_xmitframe(pxmitpriv, pxmitframe);
+
+               pxmitpriv->tx_drop++;
+               return _TRUE;
+       }
+
+#ifdef TX_AMSDU
+       tasklet_hi_schedule(&pxmitpriv->xmit_tasklet);
+#endif
+
+       return _FALSE;
+}
+
+s32 rtl8822be_mgnt_xmit(_adapter *padapter, struct xmit_frame *pmgntframe)
+{
+       return rtl8822be_dump_xframe(padapter, pmgntframe);
+}
+
+/*
+ * Return
+ *     _TRUE   dump packet directly ok
+ *     _FALSE  temporary can't transmit packets to hardware
+ */
+s32 rtl8822be_hal_xmit(_adapter *padapter, struct xmit_frame *pxmitframe)
+{
+       DBG_COUNTER(padapter->tx_logs.intf_tx);
+       return pre_xmitframe(padapter, pxmitframe);
+}
+
+s32 rtl8822be_hal_xmitframe_enqueue(_adapter *padapter,
+                                   struct xmit_frame *pxmitframe)
+{
+       struct xmit_priv *pxmitpriv = &padapter->xmitpriv;
+       s32 err;
+
+       DBG_COUNTER(padapter->tx_logs.intf_tx_enqueue);
+       err = rtw_xmitframe_enqueue(padapter, pxmitframe);
+       if (err != _SUCCESS) {
+               rtw_free_xmitframe(pxmitpriv, pxmitframe);
+               pxmitpriv->tx_drop++;
+       } else {
+#ifdef PLATFORM_LINUX
+               if (check_nic_enough_desc(padapter,
+                                         &pxmitframe->attrib) == _TRUE)
+                       tasklet_hi_schedule(&pxmitpriv->xmit_tasklet);
+#endif
+       }
+
+       return err;
+}
+
+int rtl8822be_init_txbd_ring(_adapter *padapter, unsigned int q_idx,
+                            unsigned int entries)
+{
+       struct xmit_priv *t_priv = &padapter->xmitpriv;
+       struct dvobj_priv *pdvobjpriv = adapter_to_dvobj(padapter);
+       struct pci_dev *pdev = pdvobjpriv->ppcidev;
+       struct tx_buf_desc *txbd;
+       u8 *tx_desc;
+       dma_addr_t dma;
+       int i;
+
+       _func_enter_;
+
+       RTW_INFO("%s entries num:%d\n", __func__, entries);
+
+       txbd = pci_alloc_consistent(pdev, sizeof(*txbd) * entries, &dma);
+
+       if (!txbd || (unsigned long)txbd & 0xFF) {
+               RTW_INFO("Cannot allocate TXBD (q_idx = %d)\n", q_idx);
+               return _FAIL;
+       }
+
+       _rtw_memset(txbd, 0, sizeof(*txbd) * entries);
+       t_priv->tx_ring[q_idx].buf_desc = txbd;
+       t_priv->tx_ring[q_idx].dma = dma;
+       t_priv->tx_ring[q_idx].idx = 0;
+       t_priv->tx_ring[q_idx].entries = entries;
+       _rtw_init_queue(&t_priv->tx_ring[q_idx].queue);
+       t_priv->tx_ring[q_idx].qlen = 0;
+
+       RTW_INFO("%s queue:%d, ring_addr:%p\n", __func__, q_idx, txbd);
+
+       _func_exit_;
+
+       return _SUCCESS;
+}
+
+void rtl8822be_free_txbd_ring(_adapter *padapter, unsigned int prio)
+{
+       struct xmit_priv *t_priv = &padapter->xmitpriv;
+       struct dvobj_priv *pdvobjpriv = adapter_to_dvobj(padapter);
+       struct pci_dev *pdev = pdvobjpriv->ppcidev;
+       struct rtw_tx_ring *ring = &t_priv->tx_ring[prio];
+       u8 *txbd;
+       struct xmit_buf *pxmitbuf;
+
+       _func_enter_;
+
+       while (ring->qlen) {
+               txbd = (u8 *)(&ring->buf_desc[ring->idx]);
+               SET_TX_BD_OWN(txbd, 0);
+
+               if (prio != BCN_QUEUE_INX)
+                       ring->idx = (ring->idx + 1) % ring->entries;
+
+               pxmitbuf = rtl8822be_dequeue_xmitbuf(ring);
+
+               if (pxmitbuf) {
+                       pci_unmap_single(pdev,
+                               GET_TX_BD_PHYSICAL_ADDR0_LOW(txbd),
+                               pxmitbuf->len, PCI_DMA_TODEVICE);
+
+                       rtw_free_xmitbuf(t_priv, pxmitbuf);
+
+               } else {
+                       RTW_INFO("%s qlen=%d!=0,but have xmitbuf in pendingQ\n",
+                                __func__, ring->qlen);
+                       break;
+               }
+       }
+
+       pci_free_consistent(pdev, sizeof(*ring->buf_desc) * ring->entries,
+                           ring->buf_desc, ring->dma);
+       ring->buf_desc = NULL;
+
+       _func_exit_;
+}
+
+/*
+ * Draw a line to show queue status. For debug
+ * i: queue index / W:HW index / h:host index / .: enpty entry / *:ready to DMA
+ * Example:  R- 3- 4- 8 ..iW***h..... (i=3,W=4,h=8,
+ * *** means 3 tx_desc is reaady to dma)
+ */
+#ifdef BUF_DESC_DEBUG
+static void _draw_queue(PADAPTER Adapter, int prio)
+{
+       int i;
+       u8 line[TXBD_NUM + 1];
+       u16 hw, host;
+       u32     index, tmp_4bytes = 0;
+
+       struct xmit_priv        *t_priv = &Adapter->xmitpriv;
+       struct rtw_tx_ring      *ring = &t_priv->tx_ring[prio];
+
+       tmp_4bytes = rtw_read32(Adapter, get_txbd_rw_reg(prio));
+       hw   = (u16)((tmp_4bytes >> 16) & 0x7ff);
+       host = (u16)(tmp_4bytes & 0x7ff);
+
+       index = ring->idx;
+       _rtw_memset(line, '.', TXBD_NUM);
+
+       /* ready to return to driver */
+       if (index <= hw) {
+               for (i = index; i < hw; i++)
+                       line[i] = ':';
+       } else { /* wrap */
+               for (i = index; i < TXBD_NUM; i++)
+                       line[i] = ':';
+               for (i = 0; i < hw; i++)
+                       line[i] = ':';
+       }
+
+       /* ready to dma */
+       if (hw <= host) {
+               for (i = hw; i < host; i++)
+                       line[i] = '*';
+       } else { /* wrap */
+               for (i = hw; i < TXBD_NUM; i++)
+                       line[i] = '*';
+               for (i = 0; i < host; i++)
+                       line[i] = '*';
+       }
+
+       line[index] = 'i'; /* software queue index */
+       line[host] = 'h';  /* host index */
+       line[hw] = 'W';    /* hardware index */
+       line[TXBD_NUM] = 0x0;
+
+       /* Q2:10-20-30: */
+       buf_desc_debug("Q%d:%02d-%02d-%02d %s\n", prio, index, hw, host, line);
+}
+#endif
+
+/*
+ * Read pointer is h/w descriptor index
+ * Write pointer is host desciptor index: For tx side, if own bit is set in
+ * packet index n, host pointer (write pointer) point to index n + 1.
+ */
+static u32 rtl8822be_check_txdesc_closed(PADAPTER Adapter, u32 queue_idx,
+               struct rtw_tx_ring *ring)
+{
+       /*
+        * hw_rp_cache is used to reduce REG access.
+        */
+       u32     tmp32;
+
+       /* bcn queue should not enter this function */
+       if (queue_idx == BCN_QUEUE_INX)
+               return _TRUE;
+
+       /* qlen == 0 --> don't need to process */
+       if (ring->qlen == 0)
+               return _FALSE;
+
+       /* sw_rp == hw_rp_cache --> sync hw_rp */
+       if (ring->idx == ring->hw_rp_cache) {
+
+               tmp32 = rtw_read32(Adapter, get_txbd_rw_reg(queue_idx));
+
+               ring->hw_rp_cache = (tmp32 >> 16) & 0x0FFF;
+       }
+
+       /* check if need to handle TXOK */
+       if (ring->idx == ring->hw_rp_cache)
+               return _FALSE;
+
+       return _TRUE;
+}
+
+#ifdef CONFIG_BCN_ICF
+void rtl8822be_tx_isr(PADAPTER Adapter, int prio)
+{
+       struct xmit_priv *t_priv = &Adapter->xmitpriv;
+       struct dvobj_priv *pdvobjpriv = adapter_to_dvobj(Adapter);
+       struct rtw_tx_ring *ring = &t_priv->tx_ring[prio];
+       struct xmit_buf *pxmitbuf;
+       u8 *tx_desc;
+       u16 tmp_4bytes;
+       u16 desc_idx_hw = 0, desc_idx_host = 0;
+
+
+       while (ring->qlen) {
+               tx_desc = (u8 *)&ring->buf_desc[ring->idx];
+
+               /*  beacon use cmd buf Never run into here */
+               if (!rtl8822be_check_txdesc_closed(Adapter, prio, ring))
+                       return;
+
+               buf_desc_debug("TX: %s, q_idx = %d, tx_bd = %04x, close [%04x] r_idx [%04x]\n",
+                              __func__, prio, (u32)tx_desc, ring->idx,
+                              (ring->idx + 1) % ring->entries);
+
+               ring->idx = (ring->idx + 1) % ring->entries;
+               pxmitbuf = rtl8822be_dequeue_xmitbuf(ring);
+
+               if (pxmitbuf) {
+                       pci_unmap_single(pdvobjpriv->ppcidev,
+                               GET_TX_BD_PHYSICAL_ADDR0_LOW(tx_desc),
+                               pxmitbuf->len, PCI_DMA_TODEVICE);
+
+                       rtw_sctx_done(&pxmitbuf->sctx);
+                       rtw_free_xmitbuf(&(pxmitbuf->padapter->xmitpriv),
+                                        pxmitbuf);
+               } else {
+                       RTW_INFO("%s qlen=%d!=0,but have xmitbuf in pendingQ\n",
+                                __func__, ring->qlen);
+               }
+       }
+
+       if (check_tx_desc_resource(Adapter, prio)
+           && rtw_xmit_ac_blocked(Adapter) != _TRUE)
+               rtw_mi_xmit_tasklet_schedule(Adapter);
+}
+
+#else /* !CONFIG_BCN_ICF */
+void rtl8822be_tx_isr(PADAPTER Adapter, int prio)
+{
+       struct xmit_priv *t_priv = &Adapter->xmitpriv;
+       struct dvobj_priv *pdvobjpriv = adapter_to_dvobj(Adapter);
+       struct rtw_tx_ring *ring = &t_priv->tx_ring[prio];
+       struct xmit_buf *pxmitbuf;
+       u8 *tx_desc;
+       u16 tmp_4bytes;
+       u16 desc_idx_hw = 0, desc_idx_host = 0;
+
+
+       while (ring->qlen) {
+               tx_desc = (u8 *)&ring->buf_desc[ring->idx];
+
+               /*
+                * beacon packet will only use the first descriptor defautly,
+                * check register to see whether h/w has consumed buffer
+                * descriptor
+                */
+               if (prio != BCN_QUEUE_INX) {
+                       if (!rtl8822be_check_txdesc_closed(Adapter,
+                                                          prio, ring->idx))
+                               return;
+
+                       buf_desc_debug("TX: %s, queue_idx = %d, tx_desc = %04x, close desc [%04x] and update ring->idx to [%04x]\n",
+                                      __func__, prio, (u32)tx_desc, ring->idx,
+                                      (ring->idx + 1) % ring->entries);
+                       ring->idx = (ring->idx + 1) % ring->entries;
+               }
+               #if 0 /* 8822b change 00[31] to DISQSELSEQ */
+               else if (prio == BCN_QUEUE_INX)
+                       SET_TX_DESC_OWN_92E(tx_desc, 0);
+               #endif
+
+               pxmitbuf = rtl8822be_dequeue_xmitbuf(ring);
+               if (pxmitbuf) {
+                       pci_unmap_single(pdvobjpriv->ppcidev,
+                                GET_TX_BD_PHYSICAL_ADDR0_LOW(tx_desc),
+                                        pxmitbuf->len, PCI_DMA_TODEVICE);
+                       rtw_sctx_done(&pxmitbuf->sctx);
+                       rtw_free_xmitbuf(&(pxmitbuf->padapter->xmitpriv),
+                                        pxmitbuf);
+               } else {
+                       RTW_INFO("%s qlen=%d!=0,but have xmitbuf in pendingQ\n",
+                                __func__, ring->qlen);
+               }
+       }
+
+       if ((prio != BCN_QUEUE_INX) && check_tx_desc_resource(Adapter, prio)
+           && rtw_xmit_ac_blocked(Adapter) != _TRUE)
+               rtw_mi_xmit_tasklet_schedule(Adapter);
+}
+#endif /* CONFIG_BCN_ICF */
+
+#ifdef CONFIG_HOSTAPD_MLME
+static void rtl8812ae_hostap_mgnt_xmit_cb(struct urb *urb)
+{
+#ifdef PLATFORM_LINUX
+       struct sk_buff *skb = (struct sk_buff *)urb->context;
+
+       dev_kfree_skb_any(skb);
+#endif
+}
+
+s32 rtl8822be_hostap_mgnt_xmit_entry(_adapter *padapter, _pkt *pkt)
+{
+#ifdef PLATFORM_LINUX
+       u16 fc;
+       int rc, len, pipe;
+       unsigned int bmcst, tid, qsel;
+       struct sk_buff *skb, *pxmit_skb;
+       struct urb *urb;
+       unsigned char *pxmitbuf;
+       struct tx_desc *ptxdesc;
+       struct rtw_ieee80211_hdr *tx_hdr;
+       struct hostapd_priv *phostapdpriv = padapter->phostapdpriv;
+       struct net_device *pnetdev = padapter->pnetdev;
+       HAL_DATA_TYPE *pHalData = GET_HAL_DATA(padapter);
+       struct dvobj_priv *pdvobj = adapter_to_dvobj(padapter);
+
+
+       skb = pkt;
+       len = skb->len;
+       tx_hdr = (struct rtw_ieee80211_hdr *)(skb->data);
+       fc = le16_to_cpu(tx_hdr->frame_ctl);
+       bmcst = IS_MCAST(tx_hdr->addr1);
+
+       if ((fc & RTW_IEEE80211_FCTL_FTYPE) != RTW_IEEE80211_FTYPE_MGMT)
+               goto _exit;
+
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 18))
+       /* http://www.mail-archive.com/netdev@vger.kernel.org/msg17214.html */
+       pxmit_skb = dev_alloc_skb(len + TXDESC_SIZE);
+#else
+       pxmit_skb = netdev_alloc_skb(pnetdev, len + TXDESC_SIZE);
+#endif
+
+       if (!pxmit_skb)
+               goto _exit;
+
+       pxmitbuf = pxmit_skb->data;
+
+       urb = usb_alloc_urb(0, GFP_ATOMIC);
+       if (!urb)
+               goto _exit;
+
+       /* ----- fill tx desc ----- */
+       ptxdesc = (struct tx_desc *)pxmitbuf;
+       _rtw_memset(ptxdesc, 0, sizeof(*ptxdesc));
+
+       /* offset 0 */
+       ptxdesc->txdw0 |= cpu_to_le32(len & 0x0000ffff);
+       /* default = 32 bytes for TX Desc */
+       ptxdesc->txdw0 |= cpu_to_le32(((TXDESC_SIZE + OFFSET_SZ) << OFFSET_SHT) &
+                                     0x00ff0000);
+       ptxdesc->txdw0 |= cpu_to_le32(OWN | FSG | LSG);
+
+       if (bmcst)
+               ptxdesc->txdw0 |= cpu_to_le32(BIT(24));
+
+       /* offset 4 */
+       ptxdesc->txdw1 |= cpu_to_le32(0x00);/* MAC_ID */
+
+       ptxdesc->txdw1 |= cpu_to_le32((0x12 << QSEL_SHT) & 0x00001f00);
+
+       ptxdesc->txdw1 |= cpu_to_le32((0x06 << 16) & 0x000f0000);/* b mode */
+
+       /* offset 8 */
+
+       /* offset 12 */
+       ptxdesc->txdw3 |= cpu_to_le32((le16_to_cpu(tx_hdr->seq_ctl) << 16) &
+                                     0xffff0000);
+
+       /* offset 16 */
+       ptxdesc->txdw4 |= cpu_to_le32(BIT(8));/* driver uses rate */
+
+       /* offset 20 */
+
+       rtl8188e_cal_txdesc_chksum(ptxdesc);
+       /* ----- end of fill tx desc ----- */
+
+       skb_put(pxmit_skb, len + TXDESC_SIZE);
+       pxmitbuf = pxmitbuf + TXDESC_SIZE;
+       _rtw_memcpy(pxmitbuf, skb->data, len);
+
+       /* ----- prepare urb for submit ----- */
+
+       /* translate DMA FIFO addr to pipehandle */
+       /*pipe = ffaddr2pipehdl(pdvobj, MGT_QUEUE_INX);*/
+       pipe = usb_sndbulkpipe(pdvobj->pusbdev,
+                              pHalData->Queue2EPNum[(u8)MGT_QUEUE_INX] & 0x0f);
+
+       usb_fill_bulk_urb(urb, pdvobj->pusbdev, pipe, pxmit_skb->data,
+                 pxmit_skb->len, rtl8188ee_hostap_mgnt_xmit_cb, pxmit_skb);
+
+       urb->transfer_flags |= URB_ZERO_PACKET;
+       usb_anchor_urb(urb, &phostapdpriv->anchored);
+       rc = usb_submit_urb(urb, GFP_ATOMIC);
+       if (rc < 0) {
+               usb_unanchor_urb(urb);
+               kfree_skb(skb);
+       }
+       usb_free_urb(urb);
+
+
+_exit:
+
+       dev_kfree_skb_any(skb);
+#endif
+       return 0;
+
+}
+#endif