diff options
author | shemminger@osdl.org <shemminger@osdl.org> | 2005-11-24 01:00:49 -0500 |
---|---|---|
committer | Jeff Garzik <jgarzik@pobox.com> | 2005-12-01 02:22:03 -0500 |
commit | 596f86a8d8a70005728944143f08fe5414443355 (patch) | |
tree | 4d03416456411b74fbdcdbf944d81b37f8552496 /drivers/net/sk98lin/skge.c | |
parent | a174fd88d2b73c1933ea24ed533354d618c7d089 (diff) |
[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: Stephen Hemminger <shemminger@osdl.org>
Signed-off-by: Jeff Garzik <jgarzik@pobox.com>
Diffstat (limited to 'drivers/net/sk98lin/skge.c')
-rw-r--r-- | drivers/net/sk98lin/skge.c | 165 |
1 files changed, 36 insertions, 129 deletions
diff --git a/drivers/net/sk98lin/skge.c b/drivers/net/sk98lin/skge.c index b18c92cb629e..857ade447889 100644 --- a/drivers/net/sk98lin/skge.c +++ b/drivers/net/sk98lin/skge.c | |||
@@ -101,7 +101,6 @@ | |||
101 | * "h/skgeinit.h" | 101 | * "h/skgeinit.h" |
102 | * "h/skaddr.h" | 102 | * "h/skaddr.h" |
103 | * "h/skgesirq.h" | 103 | * "h/skgesirq.h" |
104 | * "h/skcsum.h" | ||
105 | * "h/skrlmt.h" | 104 | * "h/skrlmt.h" |
106 | * | 105 | * |
107 | ******************************************************************************/ | 106 | ******************************************************************************/ |
@@ -113,6 +112,7 @@ | |||
113 | #include <linux/init.h> | 112 | #include <linux/init.h> |
114 | #include <linux/proc_fs.h> | 113 | #include <linux/proc_fs.h> |
115 | #include <linux/dma-mapping.h> | 114 | #include <linux/dma-mapping.h> |
115 | #include <linux/ip.h> | ||
116 | 116 | ||
117 | #include "h/skdrv1st.h" | 117 | #include "h/skdrv1st.h" |
118 | #include "h/skdrv2nd.h" | 118 | #include "h/skdrv2nd.h" |
@@ -601,11 +601,6 @@ SK_BOOL DualNet; | |||
601 | return(-EAGAIN); | 601 | return(-EAGAIN); |
602 | } | 602 | } |
603 | 603 | ||
604 | SkCsSetReceiveFlags(pAC, | ||
605 | SKCS_PROTO_IP | SKCS_PROTO_TCP | SKCS_PROTO_UDP, | ||
606 | &pAC->CsOfs1, &pAC->CsOfs2, 0); | ||
607 | pAC->CsOfs = (pAC->CsOfs2 << 16) | pAC->CsOfs1; | ||
608 | |||
609 | BoardInitMem(pAC); | 604 | BoardInitMem(pAC); |
610 | /* tschilling: New common function with minimum size check. */ | 605 | /* tschilling: New common function with minimum size check. */ |
611 | DualNet = SK_FALSE; | 606 | DualNet = SK_FALSE; |
@@ -823,7 +818,7 @@ uintptr_t VNextDescr; /* the virtual bus address of the next descriptor */ | |||
823 | /* set the pointers right */ | 818 | /* set the pointers right */ |
824 | pDescr->VNextRxd = VNextDescr & 0xffffffffULL; | 819 | pDescr->VNextRxd = VNextDescr & 0xffffffffULL; |
825 | pDescr->pNextRxd = pNextDescr; | 820 | pDescr->pNextRxd = pNextDescr; |
826 | pDescr->TcpSumStarts = pAC->CsOfs; | 821 | pDescr->TcpSumStarts = 0; |
827 | 822 | ||
828 | /* advance one step */ | 823 | /* advance one step */ |
829 | pPrevDescr = pDescr; | 824 | pPrevDescr = pDescr; |
@@ -1505,8 +1500,6 @@ struct sk_buff *pMessage) /* pointer to send-message */ | |||
1505 | TXD *pOldTxd; | 1500 | TXD *pOldTxd; |
1506 | unsigned long Flags; | 1501 | unsigned long Flags; |
1507 | SK_U64 PhysAddr; | 1502 | SK_U64 PhysAddr; |
1508 | int Protocol; | ||
1509 | int IpHeaderLength; | ||
1510 | int BytesSend = pMessage->len; | 1503 | int BytesSend = pMessage->len; |
1511 | 1504 | ||
1512 | SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_TX_PROGRESS, ("X")); | 1505 | 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 */ | |||
1579 | pTxd->pMBuf = pMessage; | 1572 | pTxd->pMBuf = pMessage; |
1580 | 1573 | ||
1581 | if (pMessage->ip_summed == CHECKSUM_HW) { | 1574 | if (pMessage->ip_summed == CHECKSUM_HW) { |
1582 | Protocol = ((SK_U8)pMessage->data[C_OFFSET_IPPROTO] & 0xff); | 1575 | u16 hdrlen = pMessage->h.raw - pMessage->data; |
1583 | if ((Protocol == C_PROTO_ID_UDP) && | 1576 | u16 offset = hdrlen + pMessage->csum; |
1577 | |||
1578 | if ((pMessage->h.ipiph->protocol == IPPROTO_UDP ) && | ||
1584 | (pAC->GIni.GIChipRev == 0) && | 1579 | (pAC->GIni.GIChipRev == 0) && |
1585 | (pAC->GIni.GIChipId == CHIP_ID_YUKON)) { | 1580 | (pAC->GIni.GIChipId == CHIP_ID_YUKON)) { |
1586 | pTxd->TBControl = BMU_TCP_CHECK; | 1581 | pTxd->TBControl = BMU_TCP_CHECK; |
@@ -1588,14 +1583,9 @@ struct sk_buff *pMessage) /* pointer to send-message */ | |||
1588 | pTxd->TBControl = BMU_UDP_CHECK; | 1583 | pTxd->TBControl = BMU_UDP_CHECK; |
1589 | } | 1584 | } |
1590 | 1585 | ||
1591 | IpHeaderLength = (SK_U8)pMessage->data[C_OFFSET_IPHEADER]; | 1586 | pTxd->TcpSumOfs = 0; |
1592 | IpHeaderLength = (IpHeaderLength & 0xf) * 4; | 1587 | pTxd->TcpSumSt = hdrlen; |
1593 | pTxd->TcpSumOfs = 0; /* PH-Checksum already calculated */ | 1588 | pTxd->TcpSumWr = offset; |
1594 | pTxd->TcpSumSt = C_LEN_ETHERMAC_HEADER + IpHeaderLength + | ||
1595 | (Protocol == C_PROTO_ID_UDP ? | ||
1596 | C_OFFSET_UDPHEADER_UDPCS : | ||
1597 | C_OFFSET_TCPHEADER_TCPCS); | ||
1598 | pTxd->TcpSumWr = C_LEN_ETHERMAC_HEADER + IpHeaderLength; | ||
1599 | 1589 | ||
1600 | pTxd->TBControl |= BMU_OWN | BMU_STF | | 1590 | pTxd->TBControl |= BMU_OWN | BMU_STF | |
1601 | BMU_SW | BMU_EOF | | 1591 | BMU_SW | BMU_EOF | |
@@ -1658,11 +1648,10 @@ struct sk_buff *pMessage) /* pointer to send-message */ | |||
1658 | TXD *pTxdLst; | 1648 | TXD *pTxdLst; |
1659 | int CurrFrag; | 1649 | int CurrFrag; |
1660 | int BytesSend; | 1650 | int BytesSend; |
1661 | int IpHeaderLength; | ||
1662 | int Protocol; | ||
1663 | skb_frag_t *sk_frag; | 1651 | skb_frag_t *sk_frag; |
1664 | SK_U64 PhysAddr; | 1652 | SK_U64 PhysAddr; |
1665 | unsigned long Flags; | 1653 | unsigned long Flags; |
1654 | SK_U32 Control; | ||
1666 | 1655 | ||
1667 | spin_lock_irqsave(&pTxPort->TxDesRingLock, Flags); | 1656 | spin_lock_irqsave(&pTxPort->TxDesRingLock, Flags); |
1668 | #ifndef USE_TX_COMPLETE | 1657 | #ifndef USE_TX_COMPLETE |
@@ -1685,7 +1674,6 @@ struct sk_buff *pMessage) /* pointer to send-message */ | |||
1685 | pTxdFst = pTxd; | 1674 | pTxdFst = pTxd; |
1686 | pTxdLst = pTxd; | 1675 | pTxdLst = pTxd; |
1687 | BytesSend = 0; | 1676 | BytesSend = 0; |
1688 | Protocol = 0; | ||
1689 | 1677 | ||
1690 | /* | 1678 | /* |
1691 | ** Map the first fragment (header) into the DMA-space | 1679 | ** Map the first fragment (header) into the DMA-space |
@@ -1703,32 +1691,31 @@ struct sk_buff *pMessage) /* pointer to send-message */ | |||
1703 | ** Does the HW need to evaluate checksum for TCP or UDP packets? | 1691 | ** Does the HW need to evaluate checksum for TCP or UDP packets? |
1704 | */ | 1692 | */ |
1705 | if (pMessage->ip_summed == CHECKSUM_HW) { | 1693 | if (pMessage->ip_summed == CHECKSUM_HW) { |
1706 | pTxd->TBControl = BMU_STF | BMU_STFWD | skb_headlen(pMessage); | 1694 | u16 hdrlen = pMessage->h.raw - pMessage->data; |
1695 | u16 offset = hdrlen + pMessage->csum; | ||
1696 | |||
1697 | Control = BMU_STFWD; | ||
1698 | |||
1707 | /* | 1699 | /* |
1708 | ** We have to use the opcode for tcp here, because the | 1700 | ** We have to use the opcode for tcp here, because the |
1709 | ** opcode for udp is not working in the hardware yet | 1701 | ** opcode for udp is not working in the hardware yet |
1710 | ** (Revision 2.0) | 1702 | ** (Revision 2.0) |
1711 | */ | 1703 | */ |
1712 | Protocol = ((SK_U8)pMessage->data[C_OFFSET_IPPROTO] & 0xff); | 1704 | if ((pMessage->h.ipiph->protocol == IPPROTO_UDP ) && |
1713 | if ((Protocol == C_PROTO_ID_UDP) && | ||
1714 | (pAC->GIni.GIChipRev == 0) && | 1705 | (pAC->GIni.GIChipRev == 0) && |
1715 | (pAC->GIni.GIChipId == CHIP_ID_YUKON)) { | 1706 | (pAC->GIni.GIChipId == CHIP_ID_YUKON)) { |
1716 | pTxd->TBControl |= BMU_TCP_CHECK; | 1707 | Control |= BMU_TCP_CHECK; |
1717 | } else { | 1708 | } else { |
1718 | pTxd->TBControl |= BMU_UDP_CHECK; | 1709 | Control |= BMU_UDP_CHECK; |
1719 | } | 1710 | } |
1720 | 1711 | ||
1721 | IpHeaderLength = ((SK_U8)pMessage->data[C_OFFSET_IPHEADER] & 0xf)*4; | 1712 | pTxd->TcpSumOfs = 0; |
1722 | pTxd->TcpSumOfs = 0; /* PH-Checksum already claculated */ | 1713 | pTxd->TcpSumSt = hdrlen; |
1723 | pTxd->TcpSumSt = C_LEN_ETHERMAC_HEADER + IpHeaderLength + | 1714 | pTxd->TcpSumWr = offset; |
1724 | (Protocol == C_PROTO_ID_UDP ? | 1715 | } else |
1725 | C_OFFSET_UDPHEADER_UDPCS : | 1716 | Control = BMU_CHECK | BMU_SW; |
1726 | C_OFFSET_TCPHEADER_TCPCS); | 1717 | |
1727 | pTxd->TcpSumWr = C_LEN_ETHERMAC_HEADER + IpHeaderLength; | 1718 | pTxd->TBControl = BMU_STF | Control | skb_headlen(pMessage); |
1728 | } else { | ||
1729 | pTxd->TBControl = BMU_CHECK | BMU_SW | BMU_STF | | ||
1730 | skb_headlen(pMessage); | ||
1731 | } | ||
1732 | 1719 | ||
1733 | pTxd = pTxd->pNextTxd; | 1720 | pTxd = pTxd->pNextTxd; |
1734 | pTxPort->TxdRingFree--; | 1721 | pTxPort->TxdRingFree--; |
@@ -1752,40 +1739,18 @@ struct sk_buff *pMessage) /* pointer to send-message */ | |||
1752 | pTxd->VDataHigh = (SK_U32) (PhysAddr >> 32); | 1739 | pTxd->VDataHigh = (SK_U32) (PhysAddr >> 32); |
1753 | pTxd->pMBuf = pMessage; | 1740 | pTxd->pMBuf = pMessage; |
1754 | 1741 | ||
1755 | /* | 1742 | pTxd->TBControl = Control | BMU_OWN | sk_frag->size;; |
1756 | ** Does the HW need to evaluate checksum for TCP or UDP packets? | ||
1757 | */ | ||
1758 | if (pMessage->ip_summed == CHECKSUM_HW) { | ||
1759 | pTxd->TBControl = BMU_OWN | BMU_SW | BMU_STFWD; | ||
1760 | /* | ||
1761 | ** We have to use the opcode for tcp here because the | ||
1762 | ** opcode for udp is not working in the hardware yet | ||
1763 | ** (revision 2.0) | ||
1764 | */ | ||
1765 | if ((Protocol == C_PROTO_ID_UDP) && | ||
1766 | (pAC->GIni.GIChipRev == 0) && | ||
1767 | (pAC->GIni.GIChipId == CHIP_ID_YUKON)) { | ||
1768 | pTxd->TBControl |= BMU_TCP_CHECK; | ||
1769 | } else { | ||
1770 | pTxd->TBControl |= BMU_UDP_CHECK; | ||
1771 | } | ||
1772 | } else { | ||
1773 | pTxd->TBControl = BMU_CHECK | BMU_SW | BMU_OWN; | ||
1774 | } | ||
1775 | 1743 | ||
1776 | /* | 1744 | /* |
1777 | ** Do we have the last fragment? | 1745 | ** Do we have the last fragment? |
1778 | */ | 1746 | */ |
1779 | if( (CurrFrag+1) == skb_shinfo(pMessage)->nr_frags ) { | 1747 | if( (CurrFrag+1) == skb_shinfo(pMessage)->nr_frags ) { |
1780 | #ifdef USE_TX_COMPLETE | 1748 | #ifdef USE_TX_COMPLETE |
1781 | pTxd->TBControl |= BMU_EOF | BMU_IRQ_EOF | sk_frag->size; | 1749 | pTxd->TBControl |= BMU_EOF | BMU_IRQ_EOF; |
1782 | #else | 1750 | #else |
1783 | pTxd->TBControl |= BMU_EOF | sk_frag->size; | 1751 | pTxd->TBControl |= BMU_EOF; |
1784 | #endif | 1752 | #endif |
1785 | pTxdFst->TBControl |= BMU_OWN | BMU_SW; | 1753 | pTxdFst->TBControl |= BMU_OWN | BMU_SW; |
1786 | |||
1787 | } else { | ||
1788 | pTxd->TBControl |= sk_frag->size; | ||
1789 | } | 1754 | } |
1790 | pTxdLst = pTxd; | 1755 | pTxdLst = pTxd; |
1791 | pTxd = pTxd->pNextTxd; | 1756 | pTxd = pTxd->pNextTxd; |
@@ -2032,7 +1997,6 @@ SK_U32 Control; /* control field of descriptor */ | |||
2032 | struct sk_buff *pMsg; /* pointer to message holding frame */ | 1997 | struct sk_buff *pMsg; /* pointer to message holding frame */ |
2033 | struct sk_buff *pNewMsg; /* pointer to a new message for copying frame */ | 1998 | struct sk_buff *pNewMsg; /* pointer to a new message for copying frame */ |
2034 | int FrameLength; /* total length of received frame */ | 1999 | int FrameLength; /* total length of received frame */ |
2035 | int IpFrameLength; | ||
2036 | SK_MBUF *pRlmtMbuf; /* ptr to a buffer for giving a frame to rlmt */ | 2000 | SK_MBUF *pRlmtMbuf; /* ptr to a buffer for giving a frame to rlmt */ |
2037 | SK_EVPARA EvPara; /* an event parameter union */ | 2001 | SK_EVPARA EvPara; /* an event parameter union */ |
2038 | unsigned long Flags; /* for spin lock */ | 2002 | unsigned long Flags; /* for spin lock */ |
@@ -2045,10 +2009,6 @@ SK_BOOL IsMc; | |||
2045 | SK_BOOL IsBadFrame; /* Bad frame */ | 2009 | SK_BOOL IsBadFrame; /* Bad frame */ |
2046 | 2010 | ||
2047 | SK_U32 FrameStat; | 2011 | SK_U32 FrameStat; |
2048 | unsigned short Csum1; | ||
2049 | unsigned short Csum2; | ||
2050 | unsigned short Type; | ||
2051 | int Result; | ||
2052 | SK_U64 PhysAddr; | 2012 | SK_U64 PhysAddr; |
2053 | 2013 | ||
2054 | rx_start: | 2014 | rx_start: |
@@ -2177,8 +2137,8 @@ rx_start: | |||
2177 | (dma_addr_t) PhysAddr, | 2137 | (dma_addr_t) PhysAddr, |
2178 | FrameLength, | 2138 | FrameLength, |
2179 | PCI_DMA_FROMDEVICE); | 2139 | PCI_DMA_FROMDEVICE); |
2180 | eth_copy_and_sum(pNewMsg, pMsg->data, | 2140 | memcpy(pNewMsg->data, pMsg, FrameLength); |
2181 | FrameLength, 0); | 2141 | |
2182 | pci_dma_sync_single_for_device(pAC->PciDev, | 2142 | pci_dma_sync_single_for_device(pAC->PciDev, |
2183 | (dma_addr_t) PhysAddr, | 2143 | (dma_addr_t) PhysAddr, |
2184 | FrameLength, | 2144 | FrameLength, |
@@ -2206,69 +2166,16 @@ rx_start: | |||
2206 | 2166 | ||
2207 | /* set length in message */ | 2167 | /* set length in message */ |
2208 | skb_put(pMsg, FrameLength); | 2168 | skb_put(pMsg, FrameLength); |
2209 | /* hardware checksum */ | 2169 | } /* frame > SK_COPY_TRESHOLD */ |
2210 | Type = ntohs(*((short*)&pMsg->data[12])); | ||
2211 | 2170 | ||
2212 | #ifdef USE_SK_RX_CHECKSUM | 2171 | #ifdef USE_SK_RX_CHECKSUM |
2213 | if (Type == 0x800) { | 2172 | pMsg->csum = pRxd->TcpSums; |
2214 | Csum1=le16_to_cpu(pRxd->TcpSums & 0xffff); | 2173 | pMsg->ip_summed = CHECKSUM_HW; |
2215 | Csum2=le16_to_cpu((pRxd->TcpSums >> 16) & 0xffff); | ||
2216 | IpFrameLength = (int) ntohs((unsigned short) | ||
2217 | ((unsigned short *) pMsg->data)[8]); | ||
2218 | |||
2219 | /* | ||
2220 | * Test: If frame is padded, a check is not possible! | ||
2221 | * Frame not padded? Length difference must be 14 (0xe)! | ||
2222 | */ | ||
2223 | if ((FrameLength - IpFrameLength) != 0xe) { | ||
2224 | /* Frame padded => TCP offload not possible! */ | ||
2225 | pMsg->ip_summed = CHECKSUM_NONE; | ||
2226 | } else { | ||
2227 | /* Frame not padded => TCP offload! */ | ||
2228 | if ((((Csum1 & 0xfffe) && (Csum2 & 0xfffe)) && | ||
2229 | (pAC->GIni.GIChipId == CHIP_ID_GENESIS)) || | ||
2230 | (pAC->ChipsetType)) { | ||
2231 | Result = SkCsGetReceiveInfo(pAC, | ||
2232 | &pMsg->data[14], | ||
2233 | Csum1, Csum2, pRxPort->PortIndex); | ||
2234 | if (Result == | ||
2235 | SKCS_STATUS_IP_FRAGMENT || | ||
2236 | Result == | ||
2237 | SKCS_STATUS_IP_CSUM_OK || | ||
2238 | Result == | ||
2239 | SKCS_STATUS_TCP_CSUM_OK || | ||
2240 | Result == | ||
2241 | SKCS_STATUS_UDP_CSUM_OK) { | ||
2242 | pMsg->ip_summed = | ||
2243 | CHECKSUM_UNNECESSARY; | ||
2244 | } | ||
2245 | else if (Result == | ||
2246 | SKCS_STATUS_TCP_CSUM_ERROR || | ||
2247 | Result == | ||
2248 | SKCS_STATUS_UDP_CSUM_ERROR || | ||
2249 | Result == | ||
2250 | SKCS_STATUS_IP_CSUM_ERROR_UDP || | ||
2251 | Result == | ||
2252 | SKCS_STATUS_IP_CSUM_ERROR_TCP || | ||
2253 | Result == | ||
2254 | SKCS_STATUS_IP_CSUM_ERROR ) { | ||
2255 | /* HW Checksum error */ | ||
2256 | SK_DBG_MSG(NULL, SK_DBGMOD_DRV, | ||
2257 | SK_DBGCAT_DRV_RX_PROGRESS, | ||
2258 | ("skge: CRC error. Frame dropped!\n")); | ||
2259 | goto rx_failed; | ||
2260 | } else { | ||
2261 | pMsg->ip_summed = | ||
2262 | CHECKSUM_NONE; | ||
2263 | } | ||
2264 | }/* checksumControl calculation valid */ | ||
2265 | } /* Frame length check */ | ||
2266 | } /* IP frame */ | ||
2267 | #else | 2174 | #else |
2268 | pMsg->ip_summed = CHECKSUM_NONE; | 2175 | pMsg->ip_summed = CHECKSUM_NONE; |
2269 | #endif | 2176 | #endif |
2270 | } /* frame > SK_COPY_TRESHOLD */ | 2177 | |
2271 | 2178 | ||
2272 | SK_DBG_MSG(NULL, SK_DBGMOD_DRV, 1,("V")); | 2179 | SK_DBG_MSG(NULL, SK_DBGMOD_DRV, 1,("V")); |
2273 | ForRlmt = SK_RLMT_RX_PROTOCOL; | 2180 | ForRlmt = SK_RLMT_RX_PROTOCOL; |
2274 | #if 0 | 2181 | #if 0 |