From 93c55dda092c7ec2a0bc6a93b5ab220ddbdffb95 Mon Sep 17 00:00:00 2001 From: Ali Bahar Date: Sun, 4 Sep 2011 03:14:22 +0800 Subject: [PATCH] staging: r8712u: Merging Realtek's latest (v2.6.6). Tx aggregation. Tx Aggregation (CONFIG_R8712_TX_AGGR, known as CONFIG_USB_TX_AGGR in the Realtek tarball) is now added. However, its tests have not been successful! The default in the Realtek tarball is to not build it -- and the Release Notes does not seem to list this as a feature. I have tested the driver with and without this feature; the former does not successfully associate when WPA2 is used. Signed-off-by: Ali Bahar Signed-off-by: Larry Finger Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8712/Kconfig | 7 + drivers/staging/rtl8712/rtl8712_xmit.c | 239 +++++++++++++++++++++++++ drivers/staging/rtl8712/rtl8712_xmit.h | 7 + drivers/staging/rtl8712/rtl871x_xmit.h | 15 +- 4 files changed, 266 insertions(+), 2 deletions(-) diff --git a/drivers/staging/rtl8712/Kconfig b/drivers/staging/rtl8712/Kconfig index 041e1e81f315..ea37473f71e5 100644 --- a/drivers/staging/rtl8712/Kconfig +++ b/drivers/staging/rtl8712/Kconfig @@ -16,4 +16,11 @@ config R8712_AP ---help--- This option allows the Realtek RTL8712 USB device to be an Access Point. +config R8712_TX_AGGR + bool "Realtek RTL8712U Transmit Aggregation code" + depends on R8712U && BROKEN + default N + ---help--- + This option provides transmit aggregation for the Realtek RTL8712 USB device. + diff --git a/drivers/staging/rtl8712/rtl8712_xmit.c b/drivers/staging/rtl8712/rtl8712_xmit.c index d09fbba471bb..693331955d67 100644 --- a/drivers/staging/rtl8712/rtl8712_xmit.c +++ b/drivers/staging/rtl8712/rtl8712_xmit.c @@ -260,6 +260,159 @@ void r8712_do_queue_select(struct _adapter *padapter, pattrib->qsel = qsel; } +#ifdef CONFIG_R8712_TX_AGGR +u8 r8712_construct_txaggr_cmd_desc(struct xmit_buf *pxmitbuf) +{ + struct tx_desc *ptx_desc = (struct tx_desc *)pxmitbuf->pbuf; + + /* Fill up TxCmd Descriptor according as USB FW Tx Aaggregation info.*/ + /* dw0 */ + ptx_desc->txdw0 = cpu_to_le32(CMD_HDR_SZ&0xffff); + ptx_desc->txdw0 |= + cpu_to_le32(((TXDESC_SIZE+OFFSET_SZ)<txdw0 |= cpu_to_le32(OWN | FSG | LSG); + + /* dw1 */ + ptx_desc->txdw1 |= cpu_to_le32((0x13<priv_data; + struct _adapter *padapter = pxmitframe->padapter; + struct cmd_priv *pcmdpriv = &(padapter->cmdpriv); + struct cmd_hdr *pcmd_hdr = (struct cmd_hdr *) + (pxmitbuf->pbuf + TXDESC_SIZE); + + /* Fill up Cmd Header for USB FW Tx Aggregation.*/ + /* dw0 */ + pcmd_hdr->cmd_dw0 = cpu_to_le32((GEN_CMD_CODE(_AMSDU_TO_AMPDU) << 16) | + (pcmdpriv->cmd_seq << 24)); + pcmdpriv->cmd_seq++; + + return _SUCCESS; +} + +u8 r8712_append_mpdu_unit(struct xmit_buf *pxmitbuf, + struct xmit_frame *pxmitframe) +{ + struct _adapter *padapter = pxmitframe->padapter; + struct tx_desc *ptx_desc = (struct tx_desc *)pxmitbuf->pbuf; + int last_txcmdsz = 0; + int padding_sz = 0; + + /* 802.3->802.11 convertor */ + r8712_xmitframe_coalesce(padapter, pxmitframe->pkt, pxmitframe); + /* free skb struct */ + r8712_xmit_complete(padapter, pxmitframe); + if (pxmitframe->attrib.ether_type != 0x0806) { + if ((pxmitframe->attrib.ether_type != 0x888e) && + (pxmitframe->attrib.dhcp_pkt != 1)) { + r8712_issue_addbareq_cmd(padapter, + pxmitframe->attrib.priority); + } + } + pxmitframe->last[0] = 1; + update_txdesc(pxmitframe, (uint *)(pxmitframe->buf_addr), + pxmitframe->attrib.last_txcmdsz); + /*padding zero */ + last_txcmdsz = pxmitframe->attrib.last_txcmdsz; + padding_sz = (8 - (last_txcmdsz % 8)); + if ((last_txcmdsz % 8) != 0) { + int i; + for (i = 0; i < padding_sz; i++) + *(pxmitframe->buf_addr+TXDESC_SIZE+last_txcmdsz+i) = 0; + } + /* Add the new mpdu's length */ + ptx_desc->txdw0 = cpu_to_le32((ptx_desc->txdw0&0xffff0000) | + ((ptx_desc->txdw0&0x0000ffff)+ + ((TXDESC_SIZE+last_txcmdsz+padding_sz)&0x0000ffff))); + + return _SUCCESS; +} + + +u8 r8712_xmitframe_aggr_1st(struct xmit_buf *pxmitbuf, + struct xmit_frame *pxmitframe) +{ + /* linux complete context doesnt need to protect */ + pxmitframe->pxmitbuf = pxmitbuf; + pxmitbuf->priv_data = pxmitframe; + pxmitframe->pxmit_urb[0] = pxmitbuf->pxmit_urb[0]; + /* buffer addr assoc */ + pxmitframe->buf_addr = pxmitbuf->pbuf+TXDESC_SIZE+CMD_HDR_SZ; + /*RTL8712_DMA_H2CCMD */ + r8712_construct_txaggr_cmd_desc(pxmitbuf); + r8712_construct_txaggr_cmd_hdr(pxmitbuf); + if (r8712_append_mpdu_unit(pxmitbuf, pxmitframe) == _SUCCESS) + pxmitbuf->aggr_nr = 1; + + return _SUCCESS; +} + +u16 r8712_xmitframe_aggr_next(struct xmit_buf *pxmitbuf, + struct xmit_frame *pxmitframe) +{ + pxmitframe->pxmitbuf = pxmitbuf; + pxmitbuf->priv_data = pxmitframe; + pxmitframe->pxmit_urb[0] = pxmitbuf->pxmit_urb[0]; + /* buffer addr assoc */ + pxmitframe->buf_addr = pxmitbuf->pbuf + TXDESC_SIZE + + (((struct tx_desc *)pxmitbuf->pbuf)->txdw0 & 0x0000ffff); + if (r8712_append_mpdu_unit(pxmitbuf, pxmitframe) == _SUCCESS) { + r8712_free_xmitframe_ex(&pxmitframe->padapter->xmitpriv, + pxmitframe); + pxmitbuf->aggr_nr++; + } + + return TXDESC_SIZE + + (((struct tx_desc *)pxmitbuf->pbuf)->txdw0 & 0x0000ffff); +} + +u8 r8712_dump_aggr_xframe(struct xmit_buf *pxmitbuf, + struct xmit_frame *pxmitframe) +{ + struct _adapter *padapter = pxmitframe->padapter; + struct dvobj_priv *pdvobj = (struct dvobj_priv *) &padapter->dvobjpriv; + struct tx_desc * ptxdesc = (struct tx_desc *)pxmitbuf->pbuf; + struct cmd_hdr *pcmd_hdr = (struct cmd_hdr *) + (pxmitbuf->pbuf + TXDESC_SIZE); + u16 total_length = (u16) (ptxdesc->txdw0 & 0xffff); + + /* use 1st xmitframe as media */ + xmitframe_xmitbuf_attach(pxmitframe, pxmitbuf); + pcmd_hdr->cmd_dw0 = cpu_to_le32(((total_length-CMD_HDR_SZ)&0x0000ffff)| + (pcmd_hdr->cmd_dw0&0xffff0000)); + + /* urb length in cmd_dw1 */ + pcmd_hdr->cmd_dw1 = cpu_to_le32((pxmitbuf->aggr_nr & 0xff)| + ((total_length+TXDESC_SIZE) << 16)); + pxmitframe->last[0] = 1; + pxmitframe->bpending[0] = false; + pxmitframe->mem_addr = pxmitbuf->pbuf; + + if ((pdvobj->ishighspeed && ((total_length+TXDESC_SIZE)%0x200) == 0) || + ((!pdvobj->ishighspeed && + ((total_length+TXDESC_SIZE)%0x40) == 0))) { + ptxdesc->txdw0 |= cpu_to_le32 + (((TXDESC_SIZE+OFFSET_SZ+8)<txdw0 |= cpu_to_le32 + (((TXDESC_SIZE+OFFSET_SZ)<padapter, RTL8712_DMA_H2CCMD, + total_length+TXDESC_SIZE, (u8 *)pxmitframe); + + return _SUCCESS; +} + +#endif + static void update_txdesc(struct xmit_frame *pxmitframe, uint *pmem, int sz) { uint qsel; @@ -270,6 +423,9 @@ static void update_txdesc(struct xmit_frame *pxmitframe, uint *pmem, int sz) struct pkt_attrib *pattrib = &pxmitframe->attrib; struct tx_desc *ptxdesc = (struct tx_desc *)pmem; struct dvobj_priv *pdvobj = (struct dvobj_priv *)&padapter->dvobjpriv; +#ifdef CONFIG_R8712_TX_AGGR + struct cmd_priv *pcmdpriv = (struct cmd_priv *)&padapter->cmdpriv; +#endif u8 blnSetTxDescOffset; sint bmcst = IS_MCAST(pattrib->ra); struct ht_priv *phtpriv = &pmlmepriv->htpriv; @@ -303,8 +459,40 @@ static void update_txdesc(struct xmit_frame *pxmitframe, uint *pmem, int sz) if (pxmitframe->frame_tag == DATA_FRAMETAG) { /* offset 4 */ ptxdesc->txdw1 |= cpu_to_le32((pattrib->mac_id)&0x1f); + +#ifdef CONFIG_R8712_TX_AGGR + /* dirty workaround, need to check if it is aggr cmd. */ + if ((u8 *)pmem != (u8 *)pxmitframe->pxmitbuf->pbuf) { + ptxdesc->txdw0 |= cpu_to_le32 + ((0x3 << TYPE_SHT)&TYPE_MSK); + qsel = (uint)(pattrib->qsel & 0x0000001f); + if (qsel == 2) + qsel = 0; + ptxdesc->txdw1 |= cpu_to_le32 + ((qsel << QSEL_SHT) & 0x00001f00); + ptxdesc->txdw2 = cpu_to_le32 + ((qsel << RTS_RC_SHT)&0x001f0000); + ptxdesc->txdw6 |= cpu_to_le32 + ((0x5 << RSVD6_SHT)&RSVD6_MSK); + } else { + ptxdesc->txdw0 |= cpu_to_le32 + ((0x3 << TYPE_SHT)&TYPE_MSK); + ptxdesc->txdw1 |= cpu_to_le32 + ((0x13 << QSEL_SHT) & 0x00001f00); + qsel = (uint)(pattrib->qsel & 0x0000001f); + if (qsel == 2) + qsel = 0; + ptxdesc->txdw2 = cpu_to_le32 + ((qsel << RTS_RC_SHT)&0x0001f000); + ptxdesc->txdw7 |= cpu_to_le32 + (pcmdpriv->cmd_seq << 24); + pcmdpriv->cmd_seq++; + } + pattrib->qsel = 0x13; +#else qsel = (uint)(pattrib->qsel & 0x0000001f); ptxdesc->txdw1 |= cpu_to_le32((qsel << QSEL_SHT) & 0x00001f00); +#endif if (!pqospriv->qos_option) ptxdesc->txdw1 |= cpu_to_le32(BIT(16));/*Non-QoS*/ if ((pattrib->encrypt > 0) && !pattrib->bswenc) { @@ -426,7 +614,11 @@ int r8712_xmitframe_complete(struct _adapter *padapter, struct hw_xmit *phwxmits; sint hwentry; struct xmit_frame *pxmitframe = NULL; +#ifdef CONFIG_R8712_TX_AGGR + struct xmit_frame *p2ndxmitframe = NULL; +#else int res = _SUCCESS, xcnt = 0; +#endif phwxmits = pxmitpriv->hwxmits; hwentry = pxmitpriv->hwxmit_entry; @@ -434,12 +626,53 @@ int r8712_xmitframe_complete(struct _adapter *padapter, pxmitbuf = r8712_alloc_xmitbuf(pxmitpriv); if (!pxmitbuf) return false; +#ifdef CONFIG_R8712_TX_AGGR + pxmitbuf->aggr_nr = 0; +#endif } /* 1st frame dequeued */ pxmitframe = dequeue_xframe_ex(pxmitpriv, phwxmits, hwentry); /* need to remember the 1st frame */ if (pxmitframe != NULL) { +#ifdef CONFIG_R8712_TX_AGGR + /* 1. dequeue 2nd frame + * 2. aggr if 2nd xframe is dequeued, else dump directly + */ + if (AGGR_NR_HIGH_BOUND > 1) + p2ndxmitframe = dequeue_xframe_ex(pxmitpriv, phwxmits, + hwentry); + if (pxmitframe->frame_tag != DATA_FRAMETAG) { + r8712_free_xmitbuf(pxmitpriv, pxmitbuf); + return false; + } + if (p2ndxmitframe != NULL) + if (p2ndxmitframe->frame_tag != DATA_FRAMETAG) { + r8712_free_xmitbuf(pxmitpriv, pxmitbuf); + return false; + } + r8712_xmitframe_aggr_1st(pxmitbuf, pxmitframe); + if (p2ndxmitframe != NULL) { + u16 total_length; + total_length = r8712_xmitframe_aggr_next( + pxmitbuf, p2ndxmitframe); + do { + p2ndxmitframe = dequeue_xframe_ex( + pxmitpriv, phwxmits, hwentry); + if (p2ndxmitframe != NULL) + total_length = + r8712_xmitframe_aggr_next( + pxmitbuf, + p2ndxmitframe); + else + break; + } while (total_length <= 0x1800 && + pxmitbuf->aggr_nr <= AGGR_NR_HIGH_BOUND); + } + if (pxmitbuf->aggr_nr > 0) + r8712_dump_aggr_xframe(pxmitbuf, pxmitframe); + +#else xmitframe_xmitbuf_attach(pxmitframe, pxmitbuf); if (pxmitframe->frame_tag == DATA_FRAMETAG) { @@ -455,6 +688,7 @@ int r8712_xmitframe_complete(struct _adapter *padapter, else r8712_free_xmitframe_ex(pxmitpriv, pxmitframe); xcnt++; +#endif } else { /* pxmitframe == NULL && p2ndxmitframe == NULL */ r8712_free_xmitbuf(pxmitpriv, pxmitbuf); @@ -493,8 +727,13 @@ static void dump_xframe(struct _adapter *padapter, pxmitframe->mem_addr = mem_addr; pxmitframe->bpending[t] = false; ff_hwaddr = get_ff_hwaddr(pxmitframe); +#ifdef CONFIG_R8712_TX_AGGR + r8712_write_port(padapter, RTL8712_DMA_H2CCMD, w_sz, + (unsigned char *)pxmitframe); +#else r8712_write_port(padapter, ff_hwaddr, w_sz, (unsigned char *)pxmitframe); +#endif mem_addr += w_sz; mem_addr = (u8 *)RND4(((addr_t)(mem_addr))); } diff --git a/drivers/staging/rtl8712/rtl8712_xmit.h b/drivers/staging/rtl8712/rtl8712_xmit.h index db52d13a6864..b50e7a1f3a42 100644 --- a/drivers/staging/rtl8712/rtl8712_xmit.h +++ b/drivers/staging/rtl8712/rtl8712_xmit.h @@ -113,4 +113,11 @@ int r8712_xmitframe_complete(struct _adapter *padapter, void r8712_do_queue_select(struct _adapter *padapter, struct pkt_attrib *pattrib); +#ifdef CONFIG_R8712_TX_AGGR +u8 r8712_xmitframe_aggr_1st(struct xmit_buf *pxmitbuf, + struct xmit_frame *pxmitframe); +u8 r8712_dump_aggr_xframe(struct xmit_buf *pxmitbuf, + struct xmit_frame *pxmitframe); +#endif + #endif diff --git a/drivers/staging/rtl8712/rtl871x_xmit.h b/drivers/staging/rtl8712/rtl871x_xmit.h index a1dccec2a59f..a034c0fec718 100644 --- a/drivers/staging/rtl8712/rtl871x_xmit.h +++ b/drivers/staging/rtl8712/rtl871x_xmit.h @@ -30,8 +30,19 @@ #include "drv_types.h" #include "xmit_osdep.h" -#define MAX_XMITBUF_SZ (2048) -#define NR_XMITBUFF (4) +#ifdef CONFIG_R8712_TX_AGGR +#define MAX_XMITBUF_SZ (16384) +#else +#define MAX_XMITBUF_SZ (2048) +#endif + +#define NR_XMITBUFF (4) + +#ifdef CONFIG_R8712_TX_AGGR +#define AGGR_NR_HIGH_BOUND (4) /*(8) */ +#define AGGR_NR_LOW_BOUND (2) +#endif + #define XMITBUF_ALIGN_SZ 512 #define TX_GUARD_BAND 5 #define MAX_NUMBLKS (1)