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

Commit 596f86a8 authored by Stephen Hemminger's avatar Stephen Hemminger Committed by Jeff Garzik
Browse files

[PATCH] sk98lin: fix checksumming code



Remove code from sk98lin that does it's own checksum validation.
This code is incorrect when dealing with nested protocols like
VLAN's, and it is better to use regular receive code path to
handle hardware checksum.

Signed-off-by: default avatarStephen Hemminger <shemminger@osdl.org>
Signed-off-by: default avatarJeff Garzik <jgarzik@pobox.com>
parent a174fd88
Loading
Loading
Loading
Loading
+2 −3
Original line number Original line Diff line number Diff line
@@ -27,8 +27,7 @@ sk98lin-objs := \
		sktimer.o	\
		sktimer.o	\
		skvpd.o		\
		skvpd.o		\
		skxmac2.o	\
		skxmac2.o	\
		skproc.o	\
		skproc.o
		skcsum.o


# DBGDEF =  \
# DBGDEF =  \
# -DDEBUG
# -DDEBUG
@@ -77,7 +76,7 @@ endif
# SK_DBGCAT_DRV_INT_SRC         0x04000000      interrupts sources
# SK_DBGCAT_DRV_INT_SRC         0x04000000      interrupts sources
# SK_DBGCAT_DRV_EVENT           0x08000000      driver events
# SK_DBGCAT_DRV_EVENT           0x08000000      driver events


EXTRA_CFLAGS += -Idrivers/net/sk98lin -DSK_DIAG_SUPPORT -DSK_USE_CSUM -DGENESIS -DYUKON $(DBGDEF) $(SKPARAM)
EXTRA_CFLAGS += -Idrivers/net/sk98lin -DSK_DIAG_SUPPORT -DGENESIS -DYUKON $(DBGDEF) $(SKPARAM)


clean:
clean:
	rm -f core *.o *.a *.s
	rm -f core *.o *.a *.s
+0 −4
Original line number Original line Diff line number Diff line
@@ -425,10 +425,6 @@ struct s_AC {
	TX_PORT		TxPort[SK_MAX_MACS][2];
	TX_PORT		TxPort[SK_MAX_MACS][2];
	RX_PORT		RxPort[SK_MAX_MACS];
	RX_PORT		RxPort[SK_MAX_MACS];


	unsigned int	CsOfs1;		/* for checksum calculation */
	unsigned int	CsOfs2;		/* for checksum calculation */
	SK_U32		CsOfs;		/* for checksum calculation */

	SK_BOOL		CheckQueue;	/* check event queue soon */
	SK_BOOL		CheckQueue;	/* check event queue soon */
	SK_TIMER        DrvCleanupTimer;/* to check for pending descriptors */
	SK_TIMER        DrvCleanupTimer;/* to check for pending descriptors */
	DIM_INFO        DynIrqModInfo;  /* all data related to DIM */
	DIM_INFO        DynIrqModInfo;  /* all data related to DIM */

drivers/net/sk98lin/skcsum.c

deleted100644 → 0
+0 −871

File deleted.

Preview size limit exceeded, changes collapsed.

+36 −129
Original line number Original line Diff line number Diff line
@@ -101,7 +101,6 @@
 *		"h/skgeinit.h"
 *		"h/skgeinit.h"
 *		"h/skaddr.h"
 *		"h/skaddr.h"
 *		"h/skgesirq.h"
 *		"h/skgesirq.h"
 *		"h/skcsum.h"
 *		"h/skrlmt.h"
 *		"h/skrlmt.h"
 *
 *
 ******************************************************************************/
 ******************************************************************************/
@@ -113,6 +112,7 @@
#include	<linux/init.h>
#include	<linux/init.h>
#include 	<linux/proc_fs.h>
#include 	<linux/proc_fs.h>
#include	<linux/dma-mapping.h>
#include	<linux/dma-mapping.h>
#include	<linux/ip.h>


#include	"h/skdrv1st.h"
#include	"h/skdrv1st.h"
#include	"h/skdrv2nd.h"
#include	"h/skdrv2nd.h"
@@ -601,11 +601,6 @@ SK_BOOL DualNet;
       		return(-EAGAIN);
       		return(-EAGAIN);
	}
	}


	SkCsSetReceiveFlags(pAC,
		SKCS_PROTO_IP | SKCS_PROTO_TCP | SKCS_PROTO_UDP,
		&pAC->CsOfs1, &pAC->CsOfs2, 0);
	pAC->CsOfs = (pAC->CsOfs2 << 16) | pAC->CsOfs1;

	BoardInitMem(pAC);
	BoardInitMem(pAC);
	/* tschilling: New common function with minimum size check. */
	/* tschilling: New common function with minimum size check. */
	DualNet = SK_FALSE;
	DualNet = SK_FALSE;
@@ -823,7 +818,7 @@ uintptr_t VNextDescr; /* the virtual bus address of the next descriptor */
		/* set the pointers right */
		/* set the pointers right */
		pDescr->VNextRxd = VNextDescr & 0xffffffffULL;
		pDescr->VNextRxd = VNextDescr & 0xffffffffULL;
		pDescr->pNextRxd = pNextDescr;
		pDescr->pNextRxd = pNextDescr;
		pDescr->TcpSumStarts = pAC->CsOfs;
		pDescr->TcpSumStarts = 0;


		/* advance one step */
		/* advance one step */
		pPrevDescr = pDescr;
		pPrevDescr = pDescr;
@@ -1505,8 +1500,6 @@ struct sk_buff *pMessage) /* pointer to send-message */
	TXD		*pOldTxd;
	TXD		*pOldTxd;
	unsigned long	 Flags;
	unsigned long	 Flags;
	SK_U64		 PhysAddr;
	SK_U64		 PhysAddr;
	int	 	 Protocol;
	int		 IpHeaderLength;
	int		 BytesSend = pMessage->len;
	int		 BytesSend = pMessage->len;


	SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_TX_PROGRESS, ("X"));
	SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_TX_PROGRESS, ("X"));
@@ -1579,8 +1572,10 @@ struct sk_buff *pMessage) /* pointer to send-message */
	pTxd->pMBuf     = pMessage;
	pTxd->pMBuf     = pMessage;


	if (pMessage->ip_summed == CHECKSUM_HW) {
	if (pMessage->ip_summed == CHECKSUM_HW) {
		Protocol = ((SK_U8)pMessage->data[C_OFFSET_IPPROTO] & 0xff);
		u16 hdrlen = pMessage->h.raw - pMessage->data;
		if ((Protocol == C_PROTO_ID_UDP) && 
		u16 offset = hdrlen + pMessage->csum;

		if ((pMessage->h.ipiph->protocol == IPPROTO_UDP ) &&
			(pAC->GIni.GIChipRev == 0) &&
			(pAC->GIni.GIChipRev == 0) &&
			(pAC->GIni.GIChipId == CHIP_ID_YUKON)) {
			(pAC->GIni.GIChipId == CHIP_ID_YUKON)) {
			pTxd->TBControl = BMU_TCP_CHECK;
			pTxd->TBControl = BMU_TCP_CHECK;
@@ -1588,14 +1583,9 @@ struct sk_buff *pMessage) /* pointer to send-message */
			pTxd->TBControl = BMU_UDP_CHECK;
			pTxd->TBControl = BMU_UDP_CHECK;
		}
		}


		IpHeaderLength  = (SK_U8)pMessage->data[C_OFFSET_IPHEADER];
		pTxd->TcpSumOfs = 0;
		IpHeaderLength  = (IpHeaderLength & 0xf) * 4;
		pTxd->TcpSumSt  = hdrlen;
		pTxd->TcpSumOfs = 0; /* PH-Checksum already calculated */
		pTxd->TcpSumWr  = offset;
		pTxd->TcpSumSt  = C_LEN_ETHERMAC_HEADER + IpHeaderLength + 
							(Protocol == C_PROTO_ID_UDP ?
							C_OFFSET_UDPHEADER_UDPCS : 
							C_OFFSET_TCPHEADER_TCPCS);
		pTxd->TcpSumWr  = C_LEN_ETHERMAC_HEADER + IpHeaderLength;


		pTxd->TBControl |= BMU_OWN | BMU_STF | 
		pTxd->TBControl |= BMU_OWN | BMU_STF | 
				   BMU_SW  | BMU_EOF |
				   BMU_SW  | BMU_EOF |
@@ -1658,11 +1648,10 @@ struct sk_buff *pMessage) /* pointer to send-message */
	TXD		*pTxdLst;
	TXD		*pTxdLst;
	int 	 	 CurrFrag;
	int 	 	 CurrFrag;
	int		 BytesSend;
	int		 BytesSend;
	int		 IpHeaderLength; 
	int		 Protocol;
	skb_frag_t	*sk_frag;
	skb_frag_t	*sk_frag;
	SK_U64		 PhysAddr;
	SK_U64		 PhysAddr;
	unsigned long	 Flags;
	unsigned long	 Flags;
	SK_U32		 Control;


	spin_lock_irqsave(&pTxPort->TxDesRingLock, Flags);
	spin_lock_irqsave(&pTxPort->TxDesRingLock, Flags);
#ifndef USE_TX_COMPLETE
#ifndef USE_TX_COMPLETE
@@ -1685,7 +1674,6 @@ struct sk_buff *pMessage) /* pointer to send-message */
	pTxdFst   = pTxd;
	pTxdFst   = pTxd;
	pTxdLst   = pTxd;
	pTxdLst   = pTxd;
	BytesSend = 0;
	BytesSend = 0;
	Protocol  = 0;


	/* 
	/* 
	** Map the first fragment (header) into the DMA-space
	** Map the first fragment (header) into the DMA-space
@@ -1703,32 +1691,31 @@ struct sk_buff *pMessage) /* pointer to send-message */
	** Does the HW need to evaluate checksum for TCP or UDP packets? 
	** Does the HW need to evaluate checksum for TCP or UDP packets? 
	*/
	*/
	if (pMessage->ip_summed == CHECKSUM_HW) {
	if (pMessage->ip_summed == CHECKSUM_HW) {
		pTxd->TBControl = BMU_STF | BMU_STFWD | skb_headlen(pMessage);
		u16 hdrlen = pMessage->h.raw - pMessage->data;
		u16 offset = hdrlen + pMessage->csum;

		Control = BMU_STFWD;

		/* 
		/* 
		** We have to use the opcode for tcp here,  because the
		** We have to use the opcode for tcp here,  because the
		** opcode for udp is not working in the hardware yet 
		** opcode for udp is not working in the hardware yet 
		** (Revision 2.0)
		** (Revision 2.0)
		*/
		*/
		Protocol = ((SK_U8)pMessage->data[C_OFFSET_IPPROTO] & 0xff);
		if ((pMessage->h.ipiph->protocol == IPPROTO_UDP ) &&
		if ((Protocol == C_PROTO_ID_UDP) && 
			(pAC->GIni.GIChipRev == 0) &&
			(pAC->GIni.GIChipRev == 0) &&
			(pAC->GIni.GIChipId == CHIP_ID_YUKON)) {
			(pAC->GIni.GIChipId == CHIP_ID_YUKON)) {
			pTxd->TBControl |= BMU_TCP_CHECK;
			Control |= BMU_TCP_CHECK;
		} else {
		} else {
			pTxd->TBControl |= BMU_UDP_CHECK;
			Control |= BMU_UDP_CHECK;
		}
		}


		IpHeaderLength  = ((SK_U8)pMessage->data[C_OFFSET_IPHEADER] & 0xf)*4;
		pTxd->TcpSumOfs = 0;
		pTxd->TcpSumOfs = 0; /* PH-Checksum already claculated */
		pTxd->TcpSumSt  = hdrlen;
		pTxd->TcpSumSt  = C_LEN_ETHERMAC_HEADER + IpHeaderLength +
		pTxd->TcpSumWr  = offset;
						(Protocol == C_PROTO_ID_UDP ?
	} else
						C_OFFSET_UDPHEADER_UDPCS :
		Control = BMU_CHECK | BMU_SW;
						C_OFFSET_TCPHEADER_TCPCS);

		pTxd->TcpSumWr  = C_LEN_ETHERMAC_HEADER + IpHeaderLength;
	pTxd->TBControl = BMU_STF | Control | skb_headlen(pMessage);
	} else {
		pTxd->TBControl = BMU_CHECK | BMU_SW | BMU_STF |
					skb_headlen(pMessage);
	}


	pTxd = pTxd->pNextTxd;
	pTxd = pTxd->pNextTxd;
	pTxPort->TxdRingFree--;
	pTxPort->TxdRingFree--;
@@ -1752,40 +1739,18 @@ struct sk_buff *pMessage) /* pointer to send-message */
		pTxd->VDataHigh = (SK_U32) (PhysAddr >> 32);
		pTxd->VDataHigh = (SK_U32) (PhysAddr >> 32);
		pTxd->pMBuf     = pMessage;
		pTxd->pMBuf     = pMessage;
		
		
		/* 
		pTxd->TBControl = Control | BMU_OWN | sk_frag->size;;
		** Does the HW need to evaluate checksum for TCP or UDP packets? 
		*/
		if (pMessage->ip_summed == CHECKSUM_HW) {
			pTxd->TBControl = BMU_OWN | BMU_SW | BMU_STFWD;
			/* 
			** We have to use the opcode for tcp here because the 
			** opcode for udp is not working in the hardware yet 
			** (revision 2.0)
			*/
			if ((Protocol == C_PROTO_ID_UDP) && 
				(pAC->GIni.GIChipRev == 0) &&
				(pAC->GIni.GIChipId == CHIP_ID_YUKON)) {
				pTxd->TBControl |= BMU_TCP_CHECK;
			} else {
				pTxd->TBControl |= BMU_UDP_CHECK;
			}
		} else {
			pTxd->TBControl = BMU_CHECK | BMU_SW | BMU_OWN;
		}


		/* 
		/* 
		** Do we have the last fragment? 
		** Do we have the last fragment? 
		*/
		*/
		if( (CurrFrag+1) == skb_shinfo(pMessage)->nr_frags )  {
		if( (CurrFrag+1) == skb_shinfo(pMessage)->nr_frags )  {
#ifdef USE_TX_COMPLETE
#ifdef USE_TX_COMPLETE
			pTxd->TBControl |= BMU_EOF | BMU_IRQ_EOF | sk_frag->size;
			pTxd->TBControl |= BMU_EOF | BMU_IRQ_EOF;
#else
#else
			pTxd->TBControl |= BMU_EOF | sk_frag->size;
			pTxd->TBControl |= BMU_EOF;
#endif
#endif
			pTxdFst->TBControl |= BMU_OWN | BMU_SW;
			pTxdFst->TBControl |= BMU_OWN | BMU_SW;

		} else {
			pTxd->TBControl |= sk_frag->size;
		}
		}
		pTxdLst = pTxd;
		pTxdLst = pTxd;
		pTxd    = pTxd->pNextTxd;
		pTxd    = pTxd->pNextTxd;
@@ -2032,7 +1997,6 @@ SK_U32 Control; /* control field of descriptor */
struct sk_buff	*pMsg;			/* pointer to message holding frame */
struct sk_buff	*pMsg;			/* pointer to message holding frame */
struct sk_buff	*pNewMsg;		/* pointer to a new message for copying frame */
struct sk_buff	*pNewMsg;		/* pointer to a new message for copying frame */
int				FrameLength;	/* total length of received frame */
int				FrameLength;	/* total length of received frame */
int				IpFrameLength;
SK_MBUF			*pRlmtMbuf;		/* ptr to a buffer for giving a frame to rlmt */
SK_MBUF			*pRlmtMbuf;		/* ptr to a buffer for giving a frame to rlmt */
SK_EVPARA		EvPara;			/* an event parameter union */	
SK_EVPARA		EvPara;			/* an event parameter union */	
unsigned long	Flags;			/* for spin lock */
unsigned long	Flags;			/* for spin lock */
@@ -2045,10 +2009,6 @@ SK_BOOL IsMc;
SK_BOOL  IsBadFrame; 			/* Bad frame */
SK_BOOL  IsBadFrame; 			/* Bad frame */


SK_U32			FrameStat;
SK_U32			FrameStat;
unsigned short	Csum1;
unsigned short	Csum2;
unsigned short	Type;
int				Result;
SK_U64			PhysAddr;
SK_U64			PhysAddr;


rx_start:	
rx_start:	
@@ -2177,8 +2137,8 @@ rx_start:
						    (dma_addr_t) PhysAddr,
						    (dma_addr_t) PhysAddr,
						    FrameLength,
						    FrameLength,
						    PCI_DMA_FROMDEVICE);
						    PCI_DMA_FROMDEVICE);
			eth_copy_and_sum(pNewMsg, pMsg->data,
			memcpy(pNewMsg->data, pMsg, FrameLength);
				FrameLength, 0);

			pci_dma_sync_single_for_device(pAC->PciDev,
			pci_dma_sync_single_for_device(pAC->PciDev,
						       (dma_addr_t) PhysAddr,
						       (dma_addr_t) PhysAddr,
						       FrameLength,
						       FrameLength,
@@ -2206,68 +2166,15 @@ rx_start:


			/* set length in message */
			/* set length in message */
			skb_put(pMsg, FrameLength);
			skb_put(pMsg, FrameLength);
			/* hardware checksum */
		} /* frame > SK_COPY_TRESHOLD */
			Type = ntohs(*((short*)&pMsg->data[12]));


#ifdef USE_SK_RX_CHECKSUM
#ifdef USE_SK_RX_CHECKSUM
			if (Type == 0x800) {
		pMsg->csum = pRxd->TcpSums;
				Csum1=le16_to_cpu(pRxd->TcpSums & 0xffff);
		pMsg->ip_summed = CHECKSUM_HW;
				Csum2=le16_to_cpu((pRxd->TcpSums >> 16) & 0xffff);
				IpFrameLength = (int) ntohs((unsigned short)
								((unsigned short *) pMsg->data)[8]);

				/*
				 * Test: If frame is padded, a check is not possible!
				 * Frame not padded? Length difference must be 14 (0xe)!
				 */
				if ((FrameLength - IpFrameLength) != 0xe) {
				/* Frame padded => TCP offload not possible! */
					pMsg->ip_summed = CHECKSUM_NONE;
				} else {
				/* Frame not padded => TCP offload! */
					if ((((Csum1 & 0xfffe) && (Csum2 & 0xfffe)) &&
						(pAC->GIni.GIChipId == CHIP_ID_GENESIS)) ||
						(pAC->ChipsetType)) {
						Result = SkCsGetReceiveInfo(pAC,
							&pMsg->data[14],
							Csum1, Csum2, pRxPort->PortIndex);
						if (Result ==
							SKCS_STATUS_IP_FRAGMENT ||
							Result ==
							SKCS_STATUS_IP_CSUM_OK ||
							Result ==
							SKCS_STATUS_TCP_CSUM_OK ||
							Result ==
							SKCS_STATUS_UDP_CSUM_OK) {
								pMsg->ip_summed =
								CHECKSUM_UNNECESSARY;
						}
						else if (Result ==
							SKCS_STATUS_TCP_CSUM_ERROR ||
							Result ==
							SKCS_STATUS_UDP_CSUM_ERROR ||
							Result ==
							SKCS_STATUS_IP_CSUM_ERROR_UDP ||
							Result ==
							SKCS_STATUS_IP_CSUM_ERROR_TCP ||
							Result ==
							SKCS_STATUS_IP_CSUM_ERROR ) {
							/* HW Checksum error */
							SK_DBG_MSG(NULL, SK_DBGMOD_DRV,
							SK_DBGCAT_DRV_RX_PROGRESS,
							("skge: CRC error. Frame dropped!\n"));
							goto rx_failed;
						} else {
								pMsg->ip_summed =
								CHECKSUM_NONE;
						}
					}/* checksumControl calculation valid */
				} /* Frame length check */
			} /* IP frame */
#else
#else
		pMsg->ip_summed = CHECKSUM_NONE;
		pMsg->ip_summed = CHECKSUM_NONE;
#endif
#endif
		} /* frame > SK_COPY_TRESHOLD */



		SK_DBG_MSG(NULL, SK_DBGMOD_DRV,	1,("V"));
		SK_DBG_MSG(NULL, SK_DBGMOD_DRV,	1,("V"));
		ForRlmt = SK_RLMT_RX_PROTOCOL;
		ForRlmt = SK_RLMT_RX_PROTOCOL;