[PATCH v2 19/21] staging: r8712u: Merging Realtek's latest (v2.6.6). Tx aggregation.

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



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 <ali@xxxxxxxxxxxxxxx>
Signed-off-by: Larry Finger <Larry.Finger@xxxxxxxxxxxx>
---
 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 041e1e8..ea37473 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 d09fbba..6933319 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)<<OFFSET_SHT)&0x00ff0000);
+	ptx_desc->txdw0 |= cpu_to_le32(OWN | FSG | LSG);
+
+	/* dw1 */
+	ptx_desc->txdw1 |= cpu_to_le32((0x13<<QSEL_SHT)&0x00001f00);
+
+	return _SUCCESS;
+}
+
+u8 r8712_construct_txaggr_cmd_hdr(struct xmit_buf *pxmitbuf)
+{
+	struct xmit_frame *pxmitframe = (struct xmit_frame *)
+		pxmitbuf->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)<<OFFSET_SHT)&0x00ff0000);
+		/*32 bytes for TX Desc + 8 bytes pending*/
+	} else {
+		ptxdesc->txdw0 |= cpu_to_le32
+			(((TXDESC_SIZE+OFFSET_SZ)<<OFFSET_SHT)&0x00ff0000);
+		/*default = 32 bytes for TX Desc*/
+	}
+	r8712_write_port(pxmitframe->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 db52d13..b50e7a1 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 a1dccec..a034c0f 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)
-- 
1.7.6

_______________________________________________
devel mailing list
devel@xxxxxxxxxxxxxxxxxxxxxx
http://driverdev.linuxdriverproject.org/mailman/listinfo/devel


[Index of Archives]     [Linux Driver Backports]     [DMA Engine]     [Linux GPIO]     [Linux SPI]     [Video for Linux]     [Linux USB Devel]     [Linux Coverity]     [Linux Audio Users]     [Linux Kernel]     [Linux SCSI]     [Yosemite Backpacking]
  Powered by Linux