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

Commit 2297a2da authored by Vladislav Zolotarov's avatar Vladislav Zolotarov Committed by David S. Miller
Browse files

bnx2x: LSO code was broken on BE platforms



Make the LSO code work on BE platforms: parsing_data field of
a parsing BD (PBD) for 57712 was improperly composed which made FW read wrong
values for TCP header's length and offset and, as a result, the corresponding
PCI device was performing bad DMA reads triggering EEH.

Signed-off-by: default avatarVladislav Zolotarov <vladz@broadcom.com>
Signed-off-by: default avatarEilon Greenstein <eilong@broadcom.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 4bc65dd8
Loading
Loading
Loading
Loading
+26 −16
Original line number Original line Diff line number Diff line
@@ -1795,15 +1795,15 @@ static int bnx2x_pkt_req_lin(struct bnx2x *bp, struct sk_buff *skb,
}
}
#endif
#endif


static inline void bnx2x_set_pbd_gso_e2(struct sk_buff *skb,
static inline void bnx2x_set_pbd_gso_e2(struct sk_buff *skb, u32 *parsing_data,
				     struct eth_tx_parse_bd_e2 *pbd,
					u32 xmit_type)
					u32 xmit_type)
{
{
	pbd->parsing_data |= cpu_to_le16(skb_shinfo(skb)->gso_size) <<
	*parsing_data |= (skb_shinfo(skb)->gso_size <<
		ETH_TX_PARSE_BD_E2_LSO_MSS_SHIFT;
			      ETH_TX_PARSE_BD_E2_LSO_MSS_SHIFT) &
			      ETH_TX_PARSE_BD_E2_LSO_MSS;
	if ((xmit_type & XMIT_GSO_V6) &&
	if ((xmit_type & XMIT_GSO_V6) &&
	    (ipv6_hdr(skb)->nexthdr == NEXTHDR_IPV6))
	    (ipv6_hdr(skb)->nexthdr == NEXTHDR_IPV6))
		pbd->parsing_data |= ETH_TX_PARSE_BD_E2_IPV6_WITH_EXT_HDR;
		*parsing_data |= ETH_TX_PARSE_BD_E2_IPV6_WITH_EXT_HDR;
}
}


/**
/**
@@ -1848,15 +1848,15 @@ static inline void bnx2x_set_pbd_gso(struct sk_buff *skb,
 * @return header len
 * @return header len
 */
 */
static inline  u8 bnx2x_set_pbd_csum_e2(struct bnx2x *bp, struct sk_buff *skb,
static inline  u8 bnx2x_set_pbd_csum_e2(struct bnx2x *bp, struct sk_buff *skb,
	struct eth_tx_parse_bd_e2 *pbd,
	u32 *parsing_data, u32 xmit_type)
	u32 xmit_type)
{
{
	pbd->parsing_data |= cpu_to_le16(tcp_hdrlen(skb)/4) <<
	*parsing_data |= ((tcp_hdrlen(skb)/4) <<
		ETH_TX_PARSE_BD_E2_TCP_HDR_LENGTH_DW_SHIFT;
		ETH_TX_PARSE_BD_E2_TCP_HDR_LENGTH_DW_SHIFT) &
		ETH_TX_PARSE_BD_E2_TCP_HDR_LENGTH_DW;


	pbd->parsing_data |= cpu_to_le16(((unsigned char *)tcp_hdr(skb) -
	*parsing_data |= ((((u8 *)tcp_hdr(skb) - skb->data) / 2) <<
					  skb->data) / 2) <<
		ETH_TX_PARSE_BD_E2_TCP_HDR_START_OFFSET_W_SHIFT) &
		ETH_TX_PARSE_BD_E2_TCP_HDR_START_OFFSET_W_SHIFT;
		ETH_TX_PARSE_BD_E2_TCP_HDR_START_OFFSET_W;


	return skb_transport_header(skb) + tcp_hdrlen(skb) - skb->data;
	return skb_transport_header(skb) + tcp_hdrlen(skb) - skb->data;
}
}
@@ -1925,6 +1925,7 @@ netdev_tx_t bnx2x_start_xmit(struct sk_buff *skb, struct net_device *dev)
	struct eth_tx_bd *tx_data_bd, *total_pkt_bd = NULL;
	struct eth_tx_bd *tx_data_bd, *total_pkt_bd = NULL;
	struct eth_tx_parse_bd_e1x *pbd_e1x = NULL;
	struct eth_tx_parse_bd_e1x *pbd_e1x = NULL;
	struct eth_tx_parse_bd_e2 *pbd_e2 = NULL;
	struct eth_tx_parse_bd_e2 *pbd_e2 = NULL;
	u32 pbd_e2_parsing_data = 0;
	u16 pkt_prod, bd_prod;
	u16 pkt_prod, bd_prod;
	int nbd, fp_index;
	int nbd, fp_index;
	dma_addr_t mapping;
	dma_addr_t mapping;
@@ -2046,8 +2047,9 @@ netdev_tx_t bnx2x_start_xmit(struct sk_buff *skb, struct net_device *dev)
		memset(pbd_e2, 0, sizeof(struct eth_tx_parse_bd_e2));
		memset(pbd_e2, 0, sizeof(struct eth_tx_parse_bd_e2));
		/* Set PBD in checksum offload case */
		/* Set PBD in checksum offload case */
		if (xmit_type & XMIT_CSUM)
		if (xmit_type & XMIT_CSUM)
			hlen = bnx2x_set_pbd_csum_e2(bp,
			hlen = bnx2x_set_pbd_csum_e2(bp, skb,
						     skb, pbd_e2, xmit_type);
						     &pbd_e2_parsing_data,
						     xmit_type);
	} else {
	} else {
		pbd_e1x = &fp->tx_desc_ring[bd_prod].parse_bd_e1x;
		pbd_e1x = &fp->tx_desc_ring[bd_prod].parse_bd_e1x;
		memset(pbd_e1x, 0, sizeof(struct eth_tx_parse_bd_e1x));
		memset(pbd_e1x, 0, sizeof(struct eth_tx_parse_bd_e1x));
@@ -2089,10 +2091,18 @@ netdev_tx_t bnx2x_start_xmit(struct sk_buff *skb, struct net_device *dev)
			bd_prod = bnx2x_tx_split(bp, fp, tx_buf, &tx_start_bd,
			bd_prod = bnx2x_tx_split(bp, fp, tx_buf, &tx_start_bd,
						 hlen, bd_prod, ++nbd);
						 hlen, bd_prod, ++nbd);
		if (CHIP_IS_E2(bp))
		if (CHIP_IS_E2(bp))
			bnx2x_set_pbd_gso_e2(skb, pbd_e2, xmit_type);
			bnx2x_set_pbd_gso_e2(skb, &pbd_e2_parsing_data,
					     xmit_type);
		else
		else
			bnx2x_set_pbd_gso(skb, pbd_e1x, xmit_type);
			bnx2x_set_pbd_gso(skb, pbd_e1x, xmit_type);
	}
	}

	/* Set the PBD's parsing_data field if not zero
	 * (for the chips newer than 57711).
	 */
	if (pbd_e2_parsing_data)
		pbd_e2->parsing_data = cpu_to_le32(pbd_e2_parsing_data);

	tx_data_bd = (struct eth_tx_bd *)tx_start_bd;
	tx_data_bd = (struct eth_tx_bd *)tx_start_bd;


	/* Handle fragmented skb */
	/* Handle fragmented skb */