Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit cfbe1988 authored by Yu Tian's avatar Yu Tian Committed by snandini
Browse files

qcacmn: Add address alignment fix for TXDMA HW

Per HW team's analysis, we find a TXDMA HW limitation:
ADDR0&0x1FFFFFFF8 should not equal ADDR1&0x1FFFFFFF8.
Otherwise, TXDMA will run into exception, which cause TX fail.
ADDR0: the address of last words in previous buffer;
ADDR1: the address of first words in next buffer;

We hit this limitation in NAT forward TSO jumbo case whose buffer
address of two fragments like below:
tso_frags = (
(length = 0x42, vaddr = 0xFFFFFFD0F5FA2F82, paddr =
0x1F5FA2F82),
(length = 0x05A8, vaddr = 0xFFFFFFD0F5FA2FC4, paddr =
0x1F5FA2FC4)
In this case, ADDR0 = 0x1F5FA2F82 + 0x42 -2 = 0x1F5FA2FC2,
ADDR1 = 0x1F5FA2FC4, then
ADDR0&0x1FFFFFFF8 = ADDR1&0x1FFFFFFF8.
To avoid this, shift server bytes for ADDR0.

Change-Id: Ib09afd7e4c14a33bb5347c68b602b360a9e36619
CRs-Fixed: 2585868
parent 081c3c48
Loading
Loading
Loading
Loading
+51 −1
Original line number Diff line number Diff line
@@ -2875,6 +2875,51 @@ struct qdf_tso_cmn_seg_info_t {
	uint32_t tcp_seq_num;
};

/**
 * qdf_nbuf_adj_tso_frag() - adjustment for buffer address of tso fragment
 *
 * @skb: network buffer
 *
 * Return: byte offset length of 8 bytes aligned.
 */
#ifdef FIX_TXDMA_LIMITATION
static uint8_t qdf_nbuf_adj_tso_frag(struct sk_buff *skb)
{
	uint32_t eit_hdr_len;
	uint8_t *eit_hdr;
	uint8_t byte_8_align_offset;

	eit_hdr = skb->data;
	eit_hdr_len = (skb_transport_header(skb)
		 - skb_mac_header(skb)) + tcp_hdrlen(skb);
	byte_8_align_offset = ((unsigned long)(eit_hdr) + eit_hdr_len) & 0x7L;
	if (qdf_unlikely(byte_8_align_offset)) {
		TSO_DEBUG("%pK,Len %d %d",
			  eit_hdr, eit_hdr_len, byte_8_align_offset);
		if (unlikely(skb_headroom(skb) < byte_8_align_offset)) {
			TSO_DEBUG("[%d]Insufficient headroom,[%pK],[%pK],[%d]",
				  __LINE__, skb->head, skb->data,
				 byte_8_align_offset);
			return 0;
		}
		qdf_nbuf_push_head(skb, byte_8_align_offset);
		qdf_mem_move(skb->data,
			     skb->data + byte_8_align_offset,
			     eit_hdr_len);
		skb->len -= byte_8_align_offset;
		skb->mac_header -= byte_8_align_offset;
		skb->network_header -= byte_8_align_offset;
		skb->transport_header -= byte_8_align_offset;
	}
	return byte_8_align_offset;
}
#else
static uint8_t qdf_nbuf_adj_tso_frag(struct sk_buff *skb)
{
	return 0;
}
#endif

/**
 * __qdf_nbuf_get_tso_cmn_seg_info() - get TSO common
 * information
@@ -3045,12 +3090,15 @@ uint32_t __qdf_nbuf_get_tso_info(qdf_device_t osdev, struct sk_buff *skb,
	uint32_t skb_proc = skb->len; /* bytes of skb pending processing */
	uint32_t tso_seg_size = skb_shinfo(skb)->gso_size;
	int j = 0; /* skb fragment index */
	uint8_t byte_8_align_offset;

	memset(&tso_cmn_info, 0x0, sizeof(tso_cmn_info));
	total_num_seg = tso_info->tso_num_seg_list;
	curr_seg = tso_info->tso_seg_list;
	total_num_seg->num_seg.tso_cmn_num_seg = 0;

	byte_8_align_offset = qdf_nbuf_adj_tso_frag(skb);

	if (qdf_unlikely(__qdf_nbuf_get_tso_cmn_seg_info(osdev,
						skb, &tso_cmn_info))) {
		qdf_warn("TSO: error getting common segment info");
@@ -3066,7 +3114,9 @@ uint32_t __qdf_nbuf_get_tso_info(qdf_device_t osdev, struct sk_buff *skb,
	skb_proc -= tso_cmn_info.eit_hdr_len;

	/* get the address to the next tso fragment */
	tso_frag_vaddr = skb->data + tso_cmn_info.eit_hdr_len;
	tso_frag_vaddr = skb->data +
			 tso_cmn_info.eit_hdr_len +
			 byte_8_align_offset;
	/* get the length of the next tso fragment */
	tso_frag_len = min(skb_frag_len, tso_seg_size);