diff options
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/net/sk98lin/Makefile | 5 | ||||
-rw-r--r-- | drivers/net/sk98lin/h/skdrv2nd.h | 4 | ||||
-rw-r--r-- | drivers/net/sk98lin/skcsum.c | 871 | ||||
-rw-r--r-- | drivers/net/sk98lin/skge.c | 165 |
4 files changed, 38 insertions, 1007 deletions
diff --git a/drivers/net/sk98lin/Makefile b/drivers/net/sk98lin/Makefile index 6783039ffb75..7653d6e33aa2 100644 --- a/drivers/net/sk98lin/Makefile +++ b/drivers/net/sk98lin/Makefile | |||
@@ -27,8 +27,7 @@ sk98lin-objs := \ | |||
27 | sktimer.o \ | 27 | sktimer.o \ |
28 | skvpd.o \ | 28 | skvpd.o \ |
29 | skxmac2.o \ | 29 | skxmac2.o \ |
30 | skproc.o \ | 30 | skproc.o |
31 | skcsum.o | ||
32 | 31 | ||
33 | # DBGDEF = \ | 32 | # DBGDEF = \ |
34 | # -DDEBUG | 33 | # -DDEBUG |
@@ -77,7 +76,7 @@ endif | |||
77 | # SK_DBGCAT_DRV_INT_SRC 0x04000000 interrupts sources | 76 | # SK_DBGCAT_DRV_INT_SRC 0x04000000 interrupts sources |
78 | # SK_DBGCAT_DRV_EVENT 0x08000000 driver events | 77 | # SK_DBGCAT_DRV_EVENT 0x08000000 driver events |
79 | 78 | ||
80 | EXTRA_CFLAGS += -Idrivers/net/sk98lin -DSK_DIAG_SUPPORT -DSK_USE_CSUM -DGENESIS -DYUKON $(DBGDEF) $(SKPARAM) | 79 | EXTRA_CFLAGS += -Idrivers/net/sk98lin -DSK_DIAG_SUPPORT -DGENESIS -DYUKON $(DBGDEF) $(SKPARAM) |
81 | 80 | ||
82 | clean: | 81 | clean: |
83 | rm -f core *.o *.a *.s | 82 | rm -f core *.o *.a *.s |
diff --git a/drivers/net/sk98lin/h/skdrv2nd.h b/drivers/net/sk98lin/h/skdrv2nd.h index 542cec57f86a..2dc5728e3ef6 100644 --- a/drivers/net/sk98lin/h/skdrv2nd.h +++ b/drivers/net/sk98lin/h/skdrv2nd.h | |||
@@ -425,10 +425,6 @@ struct s_AC { | |||
425 | TX_PORT TxPort[SK_MAX_MACS][2]; | 425 | TX_PORT TxPort[SK_MAX_MACS][2]; |
426 | RX_PORT RxPort[SK_MAX_MACS]; | 426 | RX_PORT RxPort[SK_MAX_MACS]; |
427 | 427 | ||
428 | unsigned int CsOfs1; /* for checksum calculation */ | ||
429 | unsigned int CsOfs2; /* for checksum calculation */ | ||
430 | SK_U32 CsOfs; /* for checksum calculation */ | ||
431 | |||
432 | SK_BOOL CheckQueue; /* check event queue soon */ | 428 | SK_BOOL CheckQueue; /* check event queue soon */ |
433 | SK_TIMER DrvCleanupTimer;/* to check for pending descriptors */ | 429 | SK_TIMER DrvCleanupTimer;/* to check for pending descriptors */ |
434 | DIM_INFO DynIrqModInfo; /* all data related to DIM */ | 430 | DIM_INFO DynIrqModInfo; /* all data related to DIM */ |
diff --git a/drivers/net/sk98lin/skcsum.c b/drivers/net/sk98lin/skcsum.c deleted file mode 100644 index 38a6e7a631f3..000000000000 --- a/drivers/net/sk98lin/skcsum.c +++ /dev/null | |||
@@ -1,871 +0,0 @@ | |||
1 | /****************************************************************************** | ||
2 | * | ||
3 | * Name: skcsum.c | ||
4 | * Project: GEnesis, PCI Gigabit Ethernet Adapter | ||
5 | * Version: $Revision: 1.12 $ | ||
6 | * Date: $Date: 2003/08/20 13:55:53 $ | ||
7 | * Purpose: Store/verify Internet checksum in send/receive packets. | ||
8 | * | ||
9 | ******************************************************************************/ | ||
10 | |||
11 | /****************************************************************************** | ||
12 | * | ||
13 | * (C)Copyright 1998-2003 SysKonnect GmbH. | ||
14 | * | ||
15 | * This program is free software; you can redistribute it and/or modify | ||
16 | * it under the terms of the GNU General Public License as published by | ||
17 | * the Free Software Foundation; either version 2 of the License, or | ||
18 | * (at your option) any later version. | ||
19 | * | ||
20 | * The information in this file is provided "AS IS" without warranty. | ||
21 | * | ||
22 | ******************************************************************************/ | ||
23 | |||
24 | #ifdef SK_USE_CSUM /* Check if CSUM is to be used. */ | ||
25 | |||
26 | #ifndef lint | ||
27 | static const char SysKonnectFileId[] = | ||
28 | "@(#) $Id: skcsum.c,v 1.12 2003/08/20 13:55:53 mschmid Exp $ (C) SysKonnect."; | ||
29 | #endif /* !lint */ | ||
30 | |||
31 | /****************************************************************************** | ||
32 | * | ||
33 | * Description: | ||
34 | * | ||
35 | * This is the "GEnesis" common module "CSUM". | ||
36 | * | ||
37 | * This module contains the code necessary to calculate, store, and verify the | ||
38 | * Internet Checksum of IP, TCP, and UDP frames. | ||
39 | * | ||
40 | * "GEnesis" is an abbreviation of "Gigabit Ethernet Network System in Silicon" | ||
41 | * and is the code name of this SysKonnect project. | ||
42 | * | ||
43 | * Compilation Options: | ||
44 | * | ||
45 | * SK_USE_CSUM - Define if CSUM is to be used. Otherwise, CSUM will be an | ||
46 | * empty module. | ||
47 | * | ||
48 | * SKCS_OVERWRITE_PROTO - Define to overwrite the default protocol id | ||
49 | * definitions. In this case, all SKCS_PROTO_xxx definitions must be made | ||
50 | * external. | ||
51 | * | ||
52 | * SKCS_OVERWRITE_STATUS - Define to overwrite the default return status | ||
53 | * definitions. In this case, all SKCS_STATUS_xxx definitions must be made | ||
54 | * external. | ||
55 | * | ||
56 | * Include File Hierarchy: | ||
57 | * | ||
58 | * "h/skdrv1st.h" | ||
59 | * "h/skcsum.h" | ||
60 | * "h/sktypes.h" | ||
61 | * "h/skqueue.h" | ||
62 | * "h/skdrv2nd.h" | ||
63 | * | ||
64 | ******************************************************************************/ | ||
65 | |||
66 | #include "h/skdrv1st.h" | ||
67 | #include "h/skcsum.h" | ||
68 | #include "h/skdrv2nd.h" | ||
69 | |||
70 | /* defines ********************************************************************/ | ||
71 | |||
72 | /* The size of an Ethernet MAC header. */ | ||
73 | #define SKCS_ETHERNET_MAC_HEADER_SIZE (6+6+2) | ||
74 | |||
75 | /* The size of the used topology's MAC header. */ | ||
76 | #define SKCS_MAC_HEADER_SIZE SKCS_ETHERNET_MAC_HEADER_SIZE | ||
77 | |||
78 | /* The size of the IP header without any option fields. */ | ||
79 | #define SKCS_IP_HEADER_SIZE 20 | ||
80 | |||
81 | /* | ||
82 | * Field offsets within the IP header. | ||
83 | */ | ||
84 | |||
85 | /* "Internet Header Version" and "Length". */ | ||
86 | #define SKCS_OFS_IP_HEADER_VERSION_AND_LENGTH 0 | ||
87 | |||
88 | /* "Total Length". */ | ||
89 | #define SKCS_OFS_IP_TOTAL_LENGTH 2 | ||
90 | |||
91 | /* "Flags" "Fragment Offset". */ | ||
92 | #define SKCS_OFS_IP_FLAGS_AND_FRAGMENT_OFFSET 6 | ||
93 | |||
94 | /* "Next Level Protocol" identifier. */ | ||
95 | #define SKCS_OFS_IP_NEXT_LEVEL_PROTOCOL 9 | ||
96 | |||
97 | /* Source IP address. */ | ||
98 | #define SKCS_OFS_IP_SOURCE_ADDRESS 12 | ||
99 | |||
100 | /* Destination IP address. */ | ||
101 | #define SKCS_OFS_IP_DESTINATION_ADDRESS 16 | ||
102 | |||
103 | |||
104 | /* | ||
105 | * Field offsets within the UDP header. | ||
106 | */ | ||
107 | |||
108 | /* UDP checksum. */ | ||
109 | #define SKCS_OFS_UDP_CHECKSUM 6 | ||
110 | |||
111 | /* IP "Next Level Protocol" identifiers (see RFC 790). */ | ||
112 | #define SKCS_PROTO_ID_TCP 6 /* Transport Control Protocol */ | ||
113 | #define SKCS_PROTO_ID_UDP 17 /* User Datagram Protocol */ | ||
114 | |||
115 | /* IP "Don't Fragment" bit. */ | ||
116 | #define SKCS_IP_DONT_FRAGMENT SKCS_HTON16(0x4000) | ||
117 | |||
118 | /* Add a byte offset to a pointer. */ | ||
119 | #define SKCS_IDX(pPtr, Ofs) ((void *) ((char *) (pPtr) + (Ofs))) | ||
120 | |||
121 | /* | ||
122 | * Macros that convert host to network representation and vice versa, i.e. | ||
123 | * little/big endian conversion on little endian machines only. | ||
124 | */ | ||
125 | #ifdef SK_LITTLE_ENDIAN | ||
126 | #define SKCS_HTON16(Val16) (((unsigned) (Val16) >> 8) | (((Val16) & 0xff) << 8)) | ||
127 | #endif /* SK_LITTLE_ENDIAN */ | ||
128 | #ifdef SK_BIG_ENDIAN | ||
129 | #define SKCS_HTON16(Val16) (Val16) | ||
130 | #endif /* SK_BIG_ENDIAN */ | ||
131 | #define SKCS_NTOH16(Val16) SKCS_HTON16(Val16) | ||
132 | |||
133 | /* typedefs *******************************************************************/ | ||
134 | |||
135 | /* function prototypes ********************************************************/ | ||
136 | |||
137 | /****************************************************************************** | ||
138 | * | ||
139 | * SkCsGetSendInfo - get checksum information for a send packet | ||
140 | * | ||
141 | * Description: | ||
142 | * Get all checksum information necessary to send a TCP or UDP packet. The | ||
143 | * function checks the IP header passed to it. If the high-level protocol | ||
144 | * is either TCP or UDP the pseudo header checksum is calculated and | ||
145 | * returned. | ||
146 | * | ||
147 | * The function returns the total length of the IP header (including any | ||
148 | * IP option fields), which is the same as the start offset of the IP data | ||
149 | * which in turn is the start offset of the TCP or UDP header. | ||
150 | * | ||
151 | * The function also returns the TCP or UDP pseudo header checksum, which | ||
152 | * should be used as the start value for the hardware checksum calculation. | ||
153 | * (Note that any actual pseudo header checksum can never calculate to | ||
154 | * zero.) | ||
155 | * | ||
156 | * Note: | ||
157 | * There is a bug in the GENESIS ASIC which may lead to wrong checksums. | ||
158 | * | ||
159 | * Arguments: | ||
160 | * pAc - A pointer to the adapter context struct. | ||
161 | * | ||
162 | * pIpHeader - Pointer to IP header. Must be at least the IP header *not* | ||
163 | * including any option fields, i.e. at least 20 bytes. | ||
164 | * | ||
165 | * Note: This pointer will be used to address 8-, 16-, and 32-bit | ||
166 | * variables with the respective alignment offsets relative to the pointer. | ||
167 | * Thus, the pointer should point to a 32-bit aligned address. If the | ||
168 | * target system cannot address 32-bit variables on non 32-bit aligned | ||
169 | * addresses, then the pointer *must* point to a 32-bit aligned address. | ||
170 | * | ||
171 | * pPacketInfo - A pointer to the packet information structure for this | ||
172 | * packet. Before calling this SkCsGetSendInfo(), the following field must | ||
173 | * be initialized: | ||
174 | * | ||
175 | * ProtocolFlags - Initialize with any combination of | ||
176 | * SKCS_PROTO_XXX bit flags. SkCsGetSendInfo() will only work on | ||
177 | * the protocols specified here. Any protocol(s) not specified | ||
178 | * here will be ignored. | ||
179 | * | ||
180 | * Note: Only one checksum can be calculated in hardware. Thus, if | ||
181 | * SKCS_PROTO_IP is specified in the 'ProtocolFlags', | ||
182 | * SkCsGetSendInfo() must calculate the IP header checksum in | ||
183 | * software. It might be a better idea to have the calling | ||
184 | * protocol stack calculate the IP header checksum. | ||
185 | * | ||
186 | * Returns: N/A | ||
187 | * On return, the following fields in 'pPacketInfo' may or may not have | ||
188 | * been filled with information, depending on the protocol(s) found in the | ||
189 | * packet: | ||
190 | * | ||
191 | * ProtocolFlags - Returns the SKCS_PROTO_XXX bit flags of the protocol(s) | ||
192 | * that were both requested by the caller and actually found in the packet. | ||
193 | * Protocol(s) not specified by the caller and/or not found in the packet | ||
194 | * will have their respective SKCS_PROTO_XXX bit flags reset. | ||
195 | * | ||
196 | * Note: For IP fragments, TCP and UDP packet information is ignored. | ||
197 | * | ||
198 | * IpHeaderLength - The total length in bytes of the complete IP header | ||
199 | * including any option fields is returned here. This is the start offset | ||
200 | * of the IP data, i.e. the TCP or UDP header if present. | ||
201 | * | ||
202 | * IpHeaderChecksum - If IP has been specified in the 'ProtocolFlags', the | ||
203 | * 16-bit Internet Checksum of the IP header is returned here. This value | ||
204 | * is to be stored into the packet's 'IP Header Checksum' field. | ||
205 | * | ||
206 | * PseudoHeaderChecksum - If this is a TCP or UDP packet and if TCP or UDP | ||
207 | * has been specified in the 'ProtocolFlags', the 16-bit Internet Checksum | ||
208 | * of the TCP or UDP pseudo header is returned here. | ||
209 | */ | ||
210 | void SkCsGetSendInfo( | ||
211 | SK_AC *pAc, /* Adapter context struct. */ | ||
212 | void *pIpHeader, /* IP header. */ | ||
213 | SKCS_PACKET_INFO *pPacketInfo, /* Packet information struct. */ | ||
214 | int NetNumber) /* Net number */ | ||
215 | { | ||
216 | /* Internet Header Version found in IP header. */ | ||
217 | unsigned InternetHeaderVersion; | ||
218 | |||
219 | /* Length of the IP header as found in IP header. */ | ||
220 | unsigned IpHeaderLength; | ||
221 | |||
222 | /* Bit field specifiying the desired/found protocols. */ | ||
223 | unsigned ProtocolFlags; | ||
224 | |||
225 | /* Next level protocol identifier found in IP header. */ | ||
226 | unsigned NextLevelProtocol; | ||
227 | |||
228 | /* Length of IP data portion. */ | ||
229 | unsigned IpDataLength; | ||
230 | |||
231 | /* TCP/UDP pseudo header checksum. */ | ||
232 | unsigned long PseudoHeaderChecksum; | ||
233 | |||
234 | /* Pointer to next level protocol statistics structure. */ | ||
235 | SKCS_PROTO_STATS *NextLevelProtoStats; | ||
236 | |||
237 | /* Temporary variable. */ | ||
238 | unsigned Tmp; | ||
239 | |||
240 | Tmp = *(SK_U8 *) | ||
241 | SKCS_IDX(pIpHeader, SKCS_OFS_IP_HEADER_VERSION_AND_LENGTH); | ||
242 | |||
243 | /* Get the Internet Header Version (IHV). */ | ||
244 | /* Note: The IHV is stored in the upper four bits. */ | ||
245 | |||
246 | InternetHeaderVersion = Tmp >> 4; | ||
247 | |||
248 | /* Check the Internet Header Version. */ | ||
249 | /* Note: We currently only support IP version 4. */ | ||
250 | |||
251 | if (InternetHeaderVersion != 4) { /* IPv4? */ | ||
252 | SK_DBG_MSG(pAc, SK_DBGMOD_CSUM, SK_DBGCAT_ERR | SK_DBGCAT_TX, | ||
253 | ("Tx: Unknown Internet Header Version %u.\n", | ||
254 | InternetHeaderVersion)); | ||
255 | pPacketInfo->ProtocolFlags = 0; | ||
256 | pAc->Csum.ProtoStats[NetNumber][SKCS_PROTO_STATS_IP].TxUnableCts++; | ||
257 | return; | ||
258 | } | ||
259 | |||
260 | /* Get the IP header length (IHL). */ | ||
261 | /* | ||
262 | * Note: The IHL is stored in the lower four bits as the number of | ||
263 | * 4-byte words. | ||
264 | */ | ||
265 | |||
266 | IpHeaderLength = (Tmp & 0xf) * 4; | ||
267 | pPacketInfo->IpHeaderLength = IpHeaderLength; | ||
268 | |||
269 | /* Check the IP header length. */ | ||
270 | |||
271 | /* 04-Aug-1998 sw - Really check the IHL? Necessary? */ | ||
272 | |||
273 | if (IpHeaderLength < 5*4) { | ||
274 | SK_DBG_MSG(pAc, SK_DBGMOD_CSUM, SK_DBGCAT_ERR | SK_DBGCAT_TX, | ||
275 | ("Tx: Invalid IP Header Length %u.\n", IpHeaderLength)); | ||
276 | pPacketInfo->ProtocolFlags = 0; | ||
277 | pAc->Csum.ProtoStats[NetNumber][SKCS_PROTO_STATS_IP].TxUnableCts++; | ||
278 | return; | ||
279 | } | ||
280 | |||
281 | /* This is an IPv4 frame with a header of valid length. */ | ||
282 | |||
283 | pAc->Csum.ProtoStats[NetNumber][SKCS_PROTO_STATS_IP].TxOkCts++; | ||
284 | |||
285 | /* Check if we should calculate the IP header checksum. */ | ||
286 | |||
287 | ProtocolFlags = pPacketInfo->ProtocolFlags; | ||
288 | |||
289 | if (ProtocolFlags & SKCS_PROTO_IP) { | ||
290 | pPacketInfo->IpHeaderChecksum = | ||
291 | SkCsCalculateChecksum(pIpHeader, IpHeaderLength); | ||
292 | } | ||
293 | |||
294 | /* Get the next level protocol identifier. */ | ||
295 | |||
296 | NextLevelProtocol = | ||
297 | *(SK_U8 *) SKCS_IDX(pIpHeader, SKCS_OFS_IP_NEXT_LEVEL_PROTOCOL); | ||
298 | |||
299 | /* | ||
300 | * Check if this is a TCP or UDP frame and if we should calculate the | ||
301 | * TCP/UDP pseudo header checksum. | ||
302 | * | ||
303 | * Also clear all protocol bit flags of protocols not present in the | ||
304 | * frame. | ||
305 | */ | ||
306 | |||
307 | if ((ProtocolFlags & SKCS_PROTO_TCP) != 0 && | ||
308 | NextLevelProtocol == SKCS_PROTO_ID_TCP) { | ||
309 | /* TCP/IP frame. */ | ||
310 | ProtocolFlags &= SKCS_PROTO_TCP | SKCS_PROTO_IP; | ||
311 | NextLevelProtoStats = | ||
312 | &pAc->Csum.ProtoStats[NetNumber][SKCS_PROTO_STATS_TCP]; | ||
313 | } | ||
314 | else if ((ProtocolFlags & SKCS_PROTO_UDP) != 0 && | ||
315 | NextLevelProtocol == SKCS_PROTO_ID_UDP) { | ||
316 | /* UDP/IP frame. */ | ||
317 | ProtocolFlags &= SKCS_PROTO_UDP | SKCS_PROTO_IP; | ||
318 | NextLevelProtoStats = | ||
319 | &pAc->Csum.ProtoStats[NetNumber][SKCS_PROTO_STATS_UDP]; | ||
320 | } | ||
321 | else { | ||
322 | /* | ||
323 | * Either not a TCP or UDP frame and/or TCP/UDP processing not | ||
324 | * specified. | ||
325 | */ | ||
326 | pPacketInfo->ProtocolFlags = ProtocolFlags & SKCS_PROTO_IP; | ||
327 | return; | ||
328 | } | ||
329 | |||
330 | /* Check if this is an IP fragment. */ | ||
331 | |||
332 | /* | ||
333 | * Note: An IP fragment has a non-zero "Fragment Offset" field and/or | ||
334 | * the "More Fragments" bit set. Thus, if both the "Fragment Offset" | ||
335 | * and the "More Fragments" are zero, it is *not* a fragment. We can | ||
336 | * easily check both at the same time since they are in the same 16-bit | ||
337 | * word. | ||
338 | */ | ||
339 | |||
340 | if ((*(SK_U16 *) | ||
341 | SKCS_IDX(pIpHeader, SKCS_OFS_IP_FLAGS_AND_FRAGMENT_OFFSET) & | ||
342 | ~SKCS_IP_DONT_FRAGMENT) != 0) { | ||
343 | /* IP fragment; ignore all other protocols. */ | ||
344 | pPacketInfo->ProtocolFlags = ProtocolFlags & SKCS_PROTO_IP; | ||
345 | NextLevelProtoStats->TxUnableCts++; | ||
346 | return; | ||
347 | } | ||
348 | |||
349 | /* | ||
350 | * Calculate the TCP/UDP pseudo header checksum. | ||
351 | */ | ||
352 | |||
353 | /* Get total length of IP header and data. */ | ||
354 | |||
355 | IpDataLength = | ||
356 | *(SK_U16 *) SKCS_IDX(pIpHeader, SKCS_OFS_IP_TOTAL_LENGTH); | ||
357 | |||
358 | /* Get length of IP data portion. */ | ||
359 | |||
360 | IpDataLength = SKCS_NTOH16(IpDataLength) - IpHeaderLength; | ||
361 | |||
362 | /* Calculate the sum of all pseudo header fields (16-bit). */ | ||
363 | |||
364 | PseudoHeaderChecksum = | ||
365 | (unsigned long) *(SK_U16 *) SKCS_IDX(pIpHeader, | ||
366 | SKCS_OFS_IP_SOURCE_ADDRESS + 0) + | ||
367 | (unsigned long) *(SK_U16 *) SKCS_IDX(pIpHeader, | ||
368 | SKCS_OFS_IP_SOURCE_ADDRESS + 2) + | ||
369 | (unsigned long) *(SK_U16 *) SKCS_IDX(pIpHeader, | ||
370 | SKCS_OFS_IP_DESTINATION_ADDRESS + 0) + | ||
371 | (unsigned long) *(SK_U16 *) SKCS_IDX(pIpHeader, | ||
372 | SKCS_OFS_IP_DESTINATION_ADDRESS + 2) + | ||
373 | (unsigned long) SKCS_HTON16(NextLevelProtocol) + | ||
374 | (unsigned long) SKCS_HTON16(IpDataLength); | ||
375 | |||
376 | /* Add-in any carries. */ | ||
377 | |||
378 | SKCS_OC_ADD(PseudoHeaderChecksum, PseudoHeaderChecksum, 0); | ||
379 | |||
380 | /* Add-in any new carry. */ | ||
381 | |||
382 | SKCS_OC_ADD(pPacketInfo->PseudoHeaderChecksum, PseudoHeaderChecksum, 0); | ||
383 | |||
384 | pPacketInfo->ProtocolFlags = ProtocolFlags; | ||
385 | NextLevelProtoStats->TxOkCts++; /* Success. */ | ||
386 | } /* SkCsGetSendInfo */ | ||
387 | |||
388 | |||
389 | /****************************************************************************** | ||
390 | * | ||
391 | * SkCsGetReceiveInfo - verify checksum information for a received packet | ||
392 | * | ||
393 | * Description: | ||
394 | * Verify a received frame's checksum. The function returns a status code | ||
395 | * reflecting the result of the verification. | ||
396 | * | ||
397 | * Note: | ||
398 | * Before calling this function you have to verify that the frame is | ||
399 | * not padded and Checksum1 and Checksum2 are bigger than 1. | ||
400 | * | ||
401 | * Arguments: | ||
402 | * pAc - Pointer to adapter context struct. | ||
403 | * | ||
404 | * pIpHeader - Pointer to IP header. Must be at least the length in bytes | ||
405 | * of the received IP header including any option fields. For UDP packets, | ||
406 | * 8 additional bytes are needed to access the UDP checksum. | ||
407 | * | ||
408 | * Note: The actual length of the IP header is stored in the lower four | ||
409 | * bits of the first octet of the IP header as the number of 4-byte words, | ||
410 | * so it must be multiplied by four to get the length in bytes. Thus, the | ||
411 | * maximum IP header length is 15 * 4 = 60 bytes. | ||
412 | * | ||
413 | * Checksum1 - The first 16-bit Internet Checksum calculated by the | ||
414 | * hardware starting at the offset returned by SkCsSetReceiveFlags(). | ||
415 | * | ||
416 | * Checksum2 - The second 16-bit Internet Checksum calculated by the | ||
417 | * hardware starting at the offset returned by SkCsSetReceiveFlags(). | ||
418 | * | ||
419 | * Returns: | ||
420 | * SKCS_STATUS_UNKNOWN_IP_VERSION - Not an IP v4 frame. | ||
421 | * SKCS_STATUS_IP_CSUM_ERROR - IP checksum error. | ||
422 | * SKCS_STATUS_IP_CSUM_ERROR_TCP - IP checksum error in TCP frame. | ||
423 | * SKCS_STATUS_IP_CSUM_ERROR_UDP - IP checksum error in UDP frame | ||
424 | * SKCS_STATUS_IP_FRAGMENT - IP fragment (IP checksum ok). | ||
425 | * SKCS_STATUS_IP_CSUM_OK - IP checksum ok (not a TCP or UDP frame). | ||
426 | * SKCS_STATUS_TCP_CSUM_ERROR - TCP checksum error (IP checksum ok). | ||
427 | * SKCS_STATUS_UDP_CSUM_ERROR - UDP checksum error (IP checksum ok). | ||
428 | * SKCS_STATUS_TCP_CSUM_OK - IP and TCP checksum ok. | ||
429 | * SKCS_STATUS_UDP_CSUM_OK - IP and UDP checksum ok. | ||
430 | * SKCS_STATUS_IP_CSUM_OK_NO_UDP - IP checksum OK and no UDP checksum. | ||
431 | * | ||
432 | * Note: If SKCS_OVERWRITE_STATUS is defined, the SKCS_STATUS_XXX values | ||
433 | * returned here can be defined in some header file by the module using CSUM. | ||
434 | * In this way, the calling module can assign return values for its own needs, | ||
435 | * e.g. by assigning bit flags to the individual protocols. | ||
436 | */ | ||
437 | SKCS_STATUS SkCsGetReceiveInfo( | ||
438 | SK_AC *pAc, /* Adapter context struct. */ | ||
439 | void *pIpHeader, /* IP header. */ | ||
440 | unsigned Checksum1, /* Hardware checksum 1. */ | ||
441 | unsigned Checksum2, /* Hardware checksum 2. */ | ||
442 | int NetNumber) /* Net number */ | ||
443 | { | ||
444 | /* Internet Header Version found in IP header. */ | ||
445 | unsigned InternetHeaderVersion; | ||
446 | |||
447 | /* Length of the IP header as found in IP header. */ | ||
448 | unsigned IpHeaderLength; | ||
449 | |||
450 | /* Length of IP data portion. */ | ||
451 | unsigned IpDataLength; | ||
452 | |||
453 | /* IP header checksum. */ | ||
454 | unsigned IpHeaderChecksum; | ||
455 | |||
456 | /* IP header options checksum, if any. */ | ||
457 | unsigned IpOptionsChecksum; | ||
458 | |||
459 | /* IP data checksum, i.e. TCP/UDP checksum. */ | ||
460 | unsigned IpDataChecksum; | ||
461 | |||
462 | /* Next level protocol identifier found in IP header. */ | ||
463 | unsigned NextLevelProtocol; | ||
464 | |||
465 | /* The checksum of the "next level protocol", i.e. TCP or UDP. */ | ||
466 | unsigned long NextLevelProtocolChecksum; | ||
467 | |||
468 | /* Pointer to next level protocol statistics structure. */ | ||
469 | SKCS_PROTO_STATS *NextLevelProtoStats; | ||
470 | |||
471 | /* Temporary variable. */ | ||
472 | unsigned Tmp; | ||
473 | |||
474 | Tmp = *(SK_U8 *) | ||
475 | SKCS_IDX(pIpHeader, SKCS_OFS_IP_HEADER_VERSION_AND_LENGTH); | ||
476 | |||
477 | /* Get the Internet Header Version (IHV). */ | ||
478 | /* Note: The IHV is stored in the upper four bits. */ | ||
479 | |||
480 | InternetHeaderVersion = Tmp >> 4; | ||
481 | |||
482 | /* Check the Internet Header Version. */ | ||
483 | /* Note: We currently only support IP version 4. */ | ||
484 | |||
485 | if (InternetHeaderVersion != 4) { /* IPv4? */ | ||
486 | SK_DBG_MSG(pAc, SK_DBGMOD_CSUM, SK_DBGCAT_ERR | SK_DBGCAT_RX, | ||
487 | ("Rx: Unknown Internet Header Version %u.\n", | ||
488 | InternetHeaderVersion)); | ||
489 | pAc->Csum.ProtoStats[NetNumber][SKCS_PROTO_STATS_IP].RxUnableCts++; | ||
490 | return (SKCS_STATUS_UNKNOWN_IP_VERSION); | ||
491 | } | ||
492 | |||
493 | /* Get the IP header length (IHL). */ | ||
494 | /* | ||
495 | * Note: The IHL is stored in the lower four bits as the number of | ||
496 | * 4-byte words. | ||
497 | */ | ||
498 | |||
499 | IpHeaderLength = (Tmp & 0xf) * 4; | ||
500 | |||
501 | /* Check the IP header length. */ | ||
502 | |||
503 | /* 04-Aug-1998 sw - Really check the IHL? Necessary? */ | ||
504 | |||
505 | if (IpHeaderLength < 5*4) { | ||
506 | SK_DBG_MSG(pAc, SK_DBGMOD_CSUM, SK_DBGCAT_ERR | SK_DBGCAT_RX, | ||
507 | ("Rx: Invalid IP Header Length %u.\n", IpHeaderLength)); | ||
508 | pAc->Csum.ProtoStats[NetNumber][SKCS_PROTO_STATS_IP].RxErrCts++; | ||
509 | return (SKCS_STATUS_IP_CSUM_ERROR); | ||
510 | } | ||
511 | |||
512 | /* This is an IPv4 frame with a header of valid length. */ | ||
513 | |||
514 | /* Get the IP header and data checksum. */ | ||
515 | |||
516 | IpDataChecksum = Checksum2; | ||
517 | |||
518 | /* | ||
519 | * The IP header checksum is calculated as follows: | ||
520 | * | ||
521 | * IpHeaderChecksum = Checksum1 - Checksum2 | ||
522 | */ | ||
523 | |||
524 | SKCS_OC_SUB(IpHeaderChecksum, Checksum1, Checksum2); | ||
525 | |||
526 | /* Check if any IP header options. */ | ||
527 | |||
528 | if (IpHeaderLength > SKCS_IP_HEADER_SIZE) { | ||
529 | |||
530 | /* Get the IP options checksum. */ | ||
531 | |||
532 | IpOptionsChecksum = SkCsCalculateChecksum( | ||
533 | SKCS_IDX(pIpHeader, SKCS_IP_HEADER_SIZE), | ||
534 | IpHeaderLength - SKCS_IP_HEADER_SIZE); | ||
535 | |||
536 | /* Adjust the IP header and IP data checksums. */ | ||
537 | |||
538 | SKCS_OC_ADD(IpHeaderChecksum, IpHeaderChecksum, IpOptionsChecksum); | ||
539 | |||
540 | SKCS_OC_SUB(IpDataChecksum, IpDataChecksum, IpOptionsChecksum); | ||
541 | } | ||
542 | |||
543 | /* | ||
544 | * Check if the IP header checksum is ok. | ||
545 | * | ||
546 | * NOTE: We must check the IP header checksum even if the caller just wants | ||
547 | * us to check upper-layer checksums, because we cannot do any further | ||
548 | * processing of the packet without a valid IP checksum. | ||
549 | */ | ||
550 | |||
551 | /* Get the next level protocol identifier. */ | ||
552 | |||
553 | NextLevelProtocol = *(SK_U8 *) | ||
554 | SKCS_IDX(pIpHeader, SKCS_OFS_IP_NEXT_LEVEL_PROTOCOL); | ||
555 | |||
556 | if (IpHeaderChecksum != 0xffff) { | ||
557 | pAc->Csum.ProtoStats[NetNumber][SKCS_PROTO_STATS_IP].RxErrCts++; | ||
558 | /* the NDIS tester wants to know the upper level protocol too */ | ||
559 | if (NextLevelProtocol == SKCS_PROTO_ID_TCP) { | ||
560 | return(SKCS_STATUS_IP_CSUM_ERROR_TCP); | ||
561 | } | ||
562 | else if (NextLevelProtocol == SKCS_PROTO_ID_UDP) { | ||
563 | return(SKCS_STATUS_IP_CSUM_ERROR_UDP); | ||
564 | } | ||
565 | return (SKCS_STATUS_IP_CSUM_ERROR); | ||
566 | } | ||
567 | |||
568 | /* | ||
569 | * Check if this is a TCP or UDP frame and if we should calculate the | ||
570 | * TCP/UDP pseudo header checksum. | ||
571 | * | ||
572 | * Also clear all protocol bit flags of protocols not present in the | ||
573 | * frame. | ||
574 | */ | ||
575 | |||
576 | if ((pAc->Csum.ReceiveFlags[NetNumber] & SKCS_PROTO_TCP) != 0 && | ||
577 | NextLevelProtocol == SKCS_PROTO_ID_TCP) { | ||
578 | /* TCP/IP frame. */ | ||
579 | NextLevelProtoStats = | ||
580 | &pAc->Csum.ProtoStats[NetNumber][SKCS_PROTO_STATS_TCP]; | ||
581 | } | ||
582 | else if ((pAc->Csum.ReceiveFlags[NetNumber] & SKCS_PROTO_UDP) != 0 && | ||
583 | NextLevelProtocol == SKCS_PROTO_ID_UDP) { | ||
584 | /* UDP/IP frame. */ | ||
585 | NextLevelProtoStats = | ||
586 | &pAc->Csum.ProtoStats[NetNumber][SKCS_PROTO_STATS_UDP]; | ||
587 | } | ||
588 | else { | ||
589 | /* | ||
590 | * Either not a TCP or UDP frame and/or TCP/UDP processing not | ||
591 | * specified. | ||
592 | */ | ||
593 | return (SKCS_STATUS_IP_CSUM_OK); | ||
594 | } | ||
595 | |||
596 | /* Check if this is an IP fragment. */ | ||
597 | |||
598 | /* | ||
599 | * Note: An IP fragment has a non-zero "Fragment Offset" field and/or | ||
600 | * the "More Fragments" bit set. Thus, if both the "Fragment Offset" | ||
601 | * and the "More Fragments" are zero, it is *not* a fragment. We can | ||
602 | * easily check both at the same time since they are in the same 16-bit | ||
603 | * word. | ||
604 | */ | ||
605 | |||
606 | if ((*(SK_U16 *) | ||
607 | SKCS_IDX(pIpHeader, SKCS_OFS_IP_FLAGS_AND_FRAGMENT_OFFSET) & | ||
608 | ~SKCS_IP_DONT_FRAGMENT) != 0) { | ||
609 | /* IP fragment; ignore all other protocols. */ | ||
610 | NextLevelProtoStats->RxUnableCts++; | ||
611 | return (SKCS_STATUS_IP_FRAGMENT); | ||
612 | } | ||
613 | |||
614 | /* | ||
615 | * 08-May-2000 ra | ||
616 | * | ||
617 | * From RFC 768 (UDP) | ||
618 | * If the computed checksum is zero, it is transmitted as all ones (the | ||
619 | * equivalent in one's complement arithmetic). An all zero transmitted | ||
620 | * checksum value means that the transmitter generated no checksum (for | ||
621 | * debugging or for higher level protocols that don't care). | ||
622 | */ | ||
623 | |||
624 | if (NextLevelProtocol == SKCS_PROTO_ID_UDP && | ||
625 | *(SK_U16*)SKCS_IDX(pIpHeader, IpHeaderLength + 6) == 0x0000) { | ||
626 | |||
627 | NextLevelProtoStats->RxOkCts++; | ||
628 | |||
629 | return (SKCS_STATUS_IP_CSUM_OK_NO_UDP); | ||
630 | } | ||
631 | |||
632 | /* | ||
633 | * Calculate the TCP/UDP checksum. | ||
634 | */ | ||
635 | |||
636 | /* Get total length of IP header and data. */ | ||
637 | |||
638 | IpDataLength = | ||
639 | *(SK_U16 *) SKCS_IDX(pIpHeader, SKCS_OFS_IP_TOTAL_LENGTH); | ||
640 | |||
641 | /* Get length of IP data portion. */ | ||
642 | |||
643 | IpDataLength = SKCS_NTOH16(IpDataLength) - IpHeaderLength; | ||
644 | |||
645 | NextLevelProtocolChecksum = | ||
646 | |||
647 | /* Calculate the pseudo header checksum. */ | ||
648 | |||
649 | (unsigned long) *(SK_U16 *) SKCS_IDX(pIpHeader, | ||
650 | SKCS_OFS_IP_SOURCE_ADDRESS + 0) + | ||
651 | (unsigned long) *(SK_U16 *) SKCS_IDX(pIpHeader, | ||
652 | SKCS_OFS_IP_SOURCE_ADDRESS + 2) + | ||
653 | (unsigned long) *(SK_U16 *) SKCS_IDX(pIpHeader, | ||
654 | SKCS_OFS_IP_DESTINATION_ADDRESS + 0) + | ||
655 | (unsigned long) *(SK_U16 *) SKCS_IDX(pIpHeader, | ||
656 | SKCS_OFS_IP_DESTINATION_ADDRESS + 2) + | ||
657 | (unsigned long) SKCS_HTON16(NextLevelProtocol) + | ||
658 | (unsigned long) SKCS_HTON16(IpDataLength) + | ||
659 | |||
660 | /* Add the TCP/UDP header checksum. */ | ||
661 | |||
662 | (unsigned long) IpDataChecksum; | ||
663 | |||
664 | /* Add-in any carries. */ | ||
665 | |||
666 | SKCS_OC_ADD(NextLevelProtocolChecksum, NextLevelProtocolChecksum, 0); | ||
667 | |||
668 | /* Add-in any new carry. */ | ||
669 | |||
670 | SKCS_OC_ADD(NextLevelProtocolChecksum, NextLevelProtocolChecksum, 0); | ||
671 | |||
672 | /* Check if the TCP/UDP checksum is ok. */ | ||
673 | |||
674 | if ((unsigned) NextLevelProtocolChecksum == 0xffff) { | ||
675 | |||
676 | /* TCP/UDP checksum ok. */ | ||
677 | |||
678 | NextLevelProtoStats->RxOkCts++; | ||
679 | |||
680 | return (NextLevelProtocol == SKCS_PROTO_ID_TCP ? | ||
681 | SKCS_STATUS_TCP_CSUM_OK : SKCS_STATUS_UDP_CSUM_OK); | ||
682 | } | ||
683 | |||
684 | /* TCP/UDP checksum error. */ | ||
685 | |||
686 | NextLevelProtoStats->RxErrCts++; | ||
687 | |||
688 | return (NextLevelProtocol == SKCS_PROTO_ID_TCP ? | ||
689 | SKCS_STATUS_TCP_CSUM_ERROR : SKCS_STATUS_UDP_CSUM_ERROR); | ||
690 | } /* SkCsGetReceiveInfo */ | ||
691 | |||
692 | |||
693 | /****************************************************************************** | ||
694 | * | ||
695 | * SkCsSetReceiveFlags - set checksum receive flags | ||
696 | * | ||
697 | * Description: | ||
698 | * Use this function to set the various receive flags. According to the | ||
699 | * protocol flags set by the caller, the start offsets within received | ||
700 | * packets of the two hardware checksums are returned. These offsets must | ||
701 | * be stored in all receive descriptors. | ||
702 | * | ||
703 | * Arguments: | ||
704 | * pAc - Pointer to adapter context struct. | ||
705 | * | ||
706 | * ReceiveFlags - Any combination of SK_PROTO_XXX flags of the protocols | ||
707 | * for which the caller wants checksum information on received frames. | ||
708 | * | ||
709 | * pChecksum1Offset - The start offset of the first receive descriptor | ||
710 | * hardware checksum to be calculated for received frames is returned | ||
711 | * here. | ||
712 | * | ||
713 | * pChecksum2Offset - The start offset of the second receive descriptor | ||
714 | * hardware checksum to be calculated for received frames is returned | ||
715 | * here. | ||
716 | * | ||
717 | * Returns: N/A | ||
718 | * Returns the two hardware checksum start offsets. | ||
719 | */ | ||
720 | void SkCsSetReceiveFlags( | ||
721 | SK_AC *pAc, /* Adapter context struct. */ | ||
722 | unsigned ReceiveFlags, /* New receive flags. */ | ||
723 | unsigned *pChecksum1Offset, /* Offset for hardware checksum 1. */ | ||
724 | unsigned *pChecksum2Offset, /* Offset for hardware checksum 2. */ | ||
725 | int NetNumber) | ||
726 | { | ||
727 | /* Save the receive flags. */ | ||
728 | |||
729 | pAc->Csum.ReceiveFlags[NetNumber] = ReceiveFlags; | ||
730 | |||
731 | /* First checksum start offset is the IP header. */ | ||
732 | *pChecksum1Offset = SKCS_MAC_HEADER_SIZE; | ||
733 | |||
734 | /* | ||
735 | * Second checksum start offset is the IP data. Note that this may vary | ||
736 | * if there are any IP header options in the actual packet. | ||
737 | */ | ||
738 | *pChecksum2Offset = SKCS_MAC_HEADER_SIZE + SKCS_IP_HEADER_SIZE; | ||
739 | } /* SkCsSetReceiveFlags */ | ||
740 | |||
741 | #ifndef SK_CS_CALCULATE_CHECKSUM | ||
742 | |||
743 | /****************************************************************************** | ||
744 | * | ||
745 | * SkCsCalculateChecksum - calculate checksum for specified data | ||
746 | * | ||
747 | * Description: | ||
748 | * Calculate and return the 16-bit Internet Checksum for the specified | ||
749 | * data. | ||
750 | * | ||
751 | * Arguments: | ||
752 | * pData - Pointer to data for which the checksum shall be calculated. | ||
753 | * Note: The pointer should be aligned on a 16-bit boundary. | ||
754 | * | ||
755 | * Length - Length in bytes of data to checksum. | ||
756 | * | ||
757 | * Returns: | ||
758 | * The 16-bit Internet Checksum for the specified data. | ||
759 | * | ||
760 | * Note: The checksum is calculated in the machine's natural byte order, | ||
761 | * i.e. little vs. big endian. Thus, the resulting checksum is different | ||
762 | * for the same input data on little and big endian machines. | ||
763 | * | ||
764 | * However, when written back to the network packet, the byte order is | ||
765 | * always in correct network order. | ||
766 | */ | ||
767 | unsigned SkCsCalculateChecksum( | ||
768 | void *pData, /* Data to checksum. */ | ||
769 | unsigned Length) /* Length of data. */ | ||
770 | { | ||
771 | SK_U16 *pU16; /* Pointer to the data as 16-bit words. */ | ||
772 | unsigned long Checksum; /* Checksum; must be at least 32 bits. */ | ||
773 | |||
774 | /* Sum up all 16-bit words. */ | ||
775 | |||
776 | pU16 = (SK_U16 *) pData; | ||
777 | for (Checksum = 0; Length > 1; Length -= 2) { | ||
778 | Checksum += *pU16++; | ||
779 | } | ||
780 | |||
781 | /* If this is an odd number of bytes, add-in the last byte. */ | ||
782 | |||
783 | if (Length > 0) { | ||
784 | #ifdef SK_BIG_ENDIAN | ||
785 | /* Add the last byte as the high byte. */ | ||
786 | Checksum += ((unsigned) *(SK_U8 *) pU16) << 8; | ||
787 | #else /* !SK_BIG_ENDIAN */ | ||
788 | /* Add the last byte as the low byte. */ | ||
789 | Checksum += *(SK_U8 *) pU16; | ||
790 | #endif /* !SK_BIG_ENDIAN */ | ||
791 | } | ||
792 | |||
793 | /* Add-in any carries. */ | ||
794 | |||
795 | SKCS_OC_ADD(Checksum, Checksum, 0); | ||
796 | |||
797 | /* Add-in any new carry. */ | ||
798 | |||
799 | SKCS_OC_ADD(Checksum, Checksum, 0); | ||
800 | |||
801 | /* Note: All bits beyond the 16-bit limit are now zero. */ | ||
802 | |||
803 | return ((unsigned) Checksum); | ||
804 | } /* SkCsCalculateChecksum */ | ||
805 | |||
806 | #endif /* SK_CS_CALCULATE_CHECKSUM */ | ||
807 | |||
808 | /****************************************************************************** | ||
809 | * | ||
810 | * SkCsEvent - the CSUM event dispatcher | ||
811 | * | ||
812 | * Description: | ||
813 | * This is the event handler for the CSUM module. | ||
814 | * | ||
815 | * Arguments: | ||
816 | * pAc - Pointer to adapter context. | ||
817 | * | ||
818 | * Ioc - I/O context. | ||
819 | * | ||
820 | * Event - Event id. | ||
821 | * | ||
822 | * Param - Event dependent parameter. | ||
823 | * | ||
824 | * Returns: | ||
825 | * The 16-bit Internet Checksum for the specified data. | ||
826 | * | ||
827 | * Note: The checksum is calculated in the machine's natural byte order, | ||
828 | * i.e. little vs. big endian. Thus, the resulting checksum is different | ||
829 | * for the same input data on little and big endian machines. | ||
830 | * | ||
831 | * However, when written back to the network packet, the byte order is | ||
832 | * always in correct network order. | ||
833 | */ | ||
834 | int SkCsEvent( | ||
835 | SK_AC *pAc, /* Pointer to adapter context. */ | ||
836 | SK_IOC Ioc, /* I/O context. */ | ||
837 | SK_U32 Event, /* Event id. */ | ||
838 | SK_EVPARA Param) /* Event dependent parameter. */ | ||
839 | { | ||
840 | int ProtoIndex; | ||
841 | int NetNumber; | ||
842 | |||
843 | switch (Event) { | ||
844 | /* | ||
845 | * Clear protocol statistics. | ||
846 | * | ||
847 | * Param - Protocol index, or -1 for all protocols. | ||
848 | * - Net number. | ||
849 | */ | ||
850 | case SK_CSUM_EVENT_CLEAR_PROTO_STATS: | ||
851 | |||
852 | ProtoIndex = (int)Param.Para32[1]; | ||
853 | NetNumber = (int)Param.Para32[0]; | ||
854 | if (ProtoIndex < 0) { /* Clear for all protocols. */ | ||
855 | if (NetNumber >= 0) { | ||
856 | SK_MEMSET(&pAc->Csum.ProtoStats[NetNumber][0], 0, | ||
857 | sizeof(pAc->Csum.ProtoStats[NetNumber])); | ||
858 | } | ||
859 | } | ||
860 | else { /* Clear for individual protocol. */ | ||
861 | SK_MEMSET(&pAc->Csum.ProtoStats[NetNumber][ProtoIndex], 0, | ||
862 | sizeof(pAc->Csum.ProtoStats[NetNumber][ProtoIndex])); | ||
863 | } | ||
864 | break; | ||
865 | default: | ||
866 | break; | ||
867 | } | ||
868 | return (0); /* Success. */ | ||
869 | } /* SkCsEvent */ | ||
870 | |||
871 | #endif /* SK_USE_CSUM */ | ||
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 |