]>
Commit | Line | Data |
---|---|---|
7152b1d0 WD |
1 | /****************************************************************************** |
2 | * | |
3 | * Name: skge.c | |
4 | * Project: GEnesis, PCI Gigabit Ethernet Adapter | |
5 | * Version: $Revision: 1.46 $ | |
53677ef1 | 6 | * Date: $Date: 2003/02/25 14:16:36 $ |
7152b1d0 WD |
7 | * Purpose: The main driver source module |
8 | * | |
9 | ******************************************************************************/ | |
42d1f039 | 10 | |
7152b1d0 WD |
11 | /****************************************************************************** |
12 | * | |
13 | * (C)Copyright 1998-2003 SysKonnect GmbH. | |
14 | * | |
15 | * Driver for SysKonnect Gigabit Ethernet Server Adapters: | |
16 | * | |
17 | * SK-9871 (single link 1000Base-ZX) | |
18 | * SK-9872 (dual link 1000Base-ZX) | |
19 | * SK-9861 (single link 1000Base-SX, VF45 Volition Plug) | |
20 | * SK-9862 (dual link 1000Base-SX, VF45 Volition Plug) | |
21 | * SK-9841 (single link 1000Base-LX) | |
22 | * SK-9842 (dual link 1000Base-LX) | |
23 | * SK-9843 (single link 1000Base-SX) | |
24 | * SK-9844 (dual link 1000Base-SX) | |
25 | * SK-9821 (single link 1000Base-T) | |
26 | * SK-9822 (dual link 1000Base-T) | |
27 | * SK-9881 (single link 1000Base-SX V2 LC) | |
28 | * SK-9871 (single link 1000Base-ZX V2) | |
29 | * SK-9861 (single link 1000Base-SX V2, VF45 Volition Plug) | |
30 | * SK-9841 (single link 1000Base-LX V2) | |
31 | * SK-9843 (single link 1000Base-SX V2) | |
32 | * SK-9821 (single link 1000Base-T V2) | |
33 | * | |
42d1f039 | 34 | * Created 10-Feb-1999, based on Linux' acenic.c, 3c59x.c and |
7152b1d0 WD |
35 | * SysKonnects GEnesis Solaris driver |
36 | * Author: Christoph Goos (cgoos@syskonnect.de) | |
37 | * Mirko Lindner (mlindner@syskonnect.de) | |
38 | * | |
39 | * Address all question to: linux@syskonnect.de | |
40 | * | |
41 | * The technical manual for the adapters is available from SysKonnect's | |
42 | * web pages: www.syskonnect.com | |
43 | * Goto "Support" and search Knowledge Base for "manual". | |
42d1f039 | 44 | * |
7152b1d0 WD |
45 | * This program is free software; you can redistribute it and/or modify |
46 | * it under the terms of the GNU General Public License as published by | |
47 | * the Free Software Foundation; either version 2 of the License, or | |
48 | * (at your option) any later version. | |
49 | * | |
50 | * The information in this file is provided "AS IS" without warranty. | |
51 | * | |
52 | ******************************************************************************/ | |
53 | ||
54 | /****************************************************************************** | |
55 | * | |
56 | * History: | |
57 | * | |
58 | * $Log: skge.c,v $ | |
59 | * Revision 1.46 2003/02/25 14:16:36 mlindner | |
60 | * Fix: Copyright statement | |
42d1f039 | 61 | * |
7152b1d0 WD |
62 | * Revision 1.45 2003/02/25 13:25:55 mlindner |
63 | * Add: Performance improvements | |
64 | * Add: Support for various vendors | |
65 | * Fix: Init function | |
42d1f039 | 66 | * |
7152b1d0 WD |
67 | * Revision 1.44 2003/01/09 09:25:26 mlindner |
68 | * Fix: Remove useless init_module/cleanup_module forward declarations | |
42d1f039 | 69 | * |
7152b1d0 WD |
70 | * Revision 1.43 2002/11/29 08:42:41 mlindner |
71 | * Fix: Boot message | |
42d1f039 | 72 | * |
7152b1d0 WD |
73 | * Revision 1.42 2002/11/28 13:30:23 mlindner |
74 | * Add: New frame check | |
42d1f039 | 75 | * |
7152b1d0 WD |
76 | * Revision 1.41 2002/11/27 13:55:18 mlindner |
77 | * Fix: Drop wrong csum packets | |
78 | * Fix: Initialize proc_entry after hw check | |
42d1f039 | 79 | * |
7152b1d0 WD |
80 | * Revision 1.40 2002/10/31 07:50:37 tschilli |
81 | * Function SkGeInitAssignRamToQueues() from common module inserted. | |
82 | * Autonegotiation is set to ON for all adapters. | |
83 | * LinkSpeedUsed is used in link up status report. | |
84 | * Role parameter will show up for 1000 Mbps links only. | |
85 | * GetConfiguration() inserted after init level 1 in SkGeChangeMtu(). | |
86 | * All return values of SkGeInit() and SkGeInitPort() are checked. | |
42d1f039 | 87 | * |
7152b1d0 WD |
88 | * Revision 1.39 2002/10/02 12:56:05 mlindner |
89 | * Add: Support for Yukon | |
90 | * Add: Support for ZEROCOPY, scatter-gather and hw checksum | |
91 | * Add: New transmit ring function (use SG and TCP/UDP hardware checksumming) | |
92 | * Add: New init function | |
93 | * Add: Speed check and setup | |
94 | * Add: Merge source for kernel 2.2.x and 2.4.x | |
95 | * Add: Opcode check for tcp | |
96 | * Add: Frame length check | |
97 | * Fix: Transmit complete interrupt | |
98 | * Fix: Interrupt moderation | |
42d1f039 | 99 | * |
7152b1d0 WD |
100 | * Revision 1.29.2.13 2002/01/14 12:44:52 mlindner |
101 | * Fix: Rlmt modes | |
42d1f039 | 102 | * |
7152b1d0 WD |
103 | * Revision 1.29.2.12 2001/12/07 12:06:18 mlindner |
104 | * Fix: malloc -> slab changes | |
42d1f039 | 105 | * |
7152b1d0 WD |
106 | * Revision 1.29.2.11 2001/12/06 15:19:20 mlindner |
107 | * Add: DMA attributes | |
108 | * Fix: Module initialisation | |
109 | * Fix: pci_map_single and pci_unmap_single replaced | |
42d1f039 | 110 | * |
7152b1d0 WD |
111 | * Revision 1.29.2.10 2001/12/06 09:56:50 mlindner |
112 | * Corrected some printk's | |
42d1f039 | 113 | * |
7152b1d0 WD |
114 | * Revision 1.29.2.9 2001/09/05 12:15:34 mlindner |
115 | * Add: LBFO Changes | |
116 | * Fix: Counter Errors (Jumbo == to long errors) | |
117 | * Fix: Changed pAC->PciDev declaration | |
118 | * Fix: too short counters | |
42d1f039 | 119 | * |
7152b1d0 WD |
120 | * Revision 1.29.2.8 2001/06/25 12:10:44 mlindner |
121 | * fix: ReceiveIrq() changed. | |
42d1f039 | 122 | * |
7152b1d0 WD |
123 | * Revision 1.29.2.7 2001/06/25 08:07:05 mlindner |
124 | * fix: RLMT locking in ReceiveIrq() changed. | |
42d1f039 | 125 | * |
7152b1d0 WD |
126 | * Revision 1.29.2.6 2001/05/21 07:59:29 mlindner |
127 | * fix: MTU init problems | |
42d1f039 | 128 | * |
7152b1d0 WD |
129 | * Revision 1.29.2.5 2001/05/08 11:25:08 mlindner |
130 | * fix: removed VLAN error message | |
42d1f039 | 131 | * |
7152b1d0 WD |
132 | * Revision 1.29.2.4 2001/05/04 13:31:43 gklug |
133 | * fix: do not handle eth_copy on bad fragments received. | |
42d1f039 | 134 | * |
7152b1d0 WD |
135 | * Revision 1.29.2.3 2001/04/23 08:06:43 mlindner |
136 | * Fix: error handling | |
42d1f039 | 137 | * |
7152b1d0 WD |
138 | * Revision 1.29.2.2 2001/03/15 12:04:54 mlindner |
139 | * Fixed memory problem | |
42d1f039 | 140 | * |
7152b1d0 WD |
141 | * Revision 1.29.2.1 2001/03/12 16:41:44 mlindner |
142 | * add: procfs function | |
143 | * add: dual-net function | |
144 | * add: RLMT networks | |
145 | * add: extended PNMI features | |
42d1f039 | 146 | * |
7152b1d0 WD |
147 | * Kernel 2.4.x specific: |
148 | * Revision 1.xx 2000/09/12 13:31:56 cgoos | |
149 | * Fixed missign "dev=NULL in skge_probe. | |
150 | * Added counting for jumbo frames (corrects error statistic). | |
151 | * Removed VLAN tag check (enables VLAN support). | |
42d1f039 | 152 | * |
7152b1d0 WD |
153 | * Kernel 2.2.x specific: |
154 | * Revision 1.29 2000/02/21 13:31:56 cgoos | |
155 | * Fixed "unused" warning for UltraSPARC change. | |
42d1f039 | 156 | * |
7152b1d0 WD |
157 | * Partially kernel 2.2.x specific: |
158 | * Revision 1.28 2000/02/21 10:32:36 cgoos | |
159 | * Added fixes for UltraSPARC. | |
160 | * Now printing RlmtMode and PrefPort setting at startup. | |
161 | * Changed XmitFrame return value. | |
162 | * Fixed rx checksum calculation for BIG ENDIAN systems. | |
163 | * Fixed rx jumbo frames counted as ierrors. | |
42d1f039 WD |
164 | * |
165 | * | |
7152b1d0 WD |
166 | * Revision 1.27 1999/11/25 09:06:28 cgoos |
167 | * Changed base_addr to unsigned long. | |
42d1f039 | 168 | * |
7152b1d0 WD |
169 | * Revision 1.26 1999/11/22 13:29:16 cgoos |
170 | * Changed license header to GPL. | |
171 | * Changes for inclusion in linux kernel (2.2.13). | |
172 | * Removed 2.0.x defines. | |
173 | * Changed SkGeProbe to skge_probe. | |
174 | * Added checks in SkGeIoctl. | |
42d1f039 | 175 | * |
7152b1d0 WD |
176 | * Revision 1.25 1999/10/07 14:47:52 cgoos |
177 | * Changed 984x to 98xx. | |
42d1f039 | 178 | * |
7152b1d0 WD |
179 | * Revision 1.24 1999/09/30 07:21:01 cgoos |
180 | * Removed SK_RLMT_SLOW_LOOKAHEAD option. | |
181 | * Giving spanning tree packets also to OS now. | |
42d1f039 | 182 | * |
7152b1d0 WD |
183 | * Revision 1.23 1999/09/29 07:36:50 cgoos |
184 | * Changed assignment for IsBc/IsMc. | |
42d1f039 | 185 | * |
7152b1d0 WD |
186 | * Revision 1.22 1999/09/28 12:57:09 cgoos |
187 | * Added CheckQueue also to Single-Port-ISR. | |
42d1f039 | 188 | * |
7152b1d0 WD |
189 | * Revision 1.21 1999/09/28 12:42:41 cgoos |
190 | * Changed parameter strings for RlmtMode. | |
42d1f039 | 191 | * |
7152b1d0 WD |
192 | * Revision 1.20 1999/09/28 12:37:57 cgoos |
193 | * Added CheckQueue for fast delivery of RLMT frames. | |
42d1f039 | 194 | * |
7152b1d0 WD |
195 | * Revision 1.19 1999/09/16 07:57:25 cgoos |
196 | * Copperfield changes. | |
42d1f039 | 197 | * |
7152b1d0 WD |
198 | * Revision 1.18 1999/09/03 13:06:30 cgoos |
199 | * Fixed RlmtMode=CheckSeg bug: wrong DEV_KFREE_SKB in RLMT_SEND caused | |
200 | * double allocated skb's. | |
201 | * FrameStat in ReceiveIrq was accessed via wrong Rxd. | |
202 | * Queue size for async. standby Tx queue was zero. | |
203 | * FillRxLimit of 0 could cause problems with ReQueue, changed to 1. | |
204 | * Removed debug output of checksum statistic. | |
42d1f039 | 205 | * |
7152b1d0 WD |
206 | * Revision 1.17 1999/08/11 13:55:27 cgoos |
207 | * Transmit descriptor polling was not reenabled after SkGePortInit. | |
42d1f039 | 208 | * |
7152b1d0 WD |
209 | * Revision 1.16 1999/07/27 15:17:29 cgoos |
210 | * Added some "\n" in output strings (removed while debuging...). | |
42d1f039 | 211 | * |
7152b1d0 WD |
212 | * Revision 1.15 1999/07/23 12:09:30 cgoos |
213 | * Performance optimization, rx checksumming, large frame support. | |
42d1f039 | 214 | * |
7152b1d0 WD |
215 | * Revision 1.14 1999/07/14 11:26:27 cgoos |
216 | * Removed Link LED settings (now in RLMT). | |
217 | * Added status output at NET UP. | |
218 | * Fixed SMP problems with Tx and SWITCH running in parallel. | |
219 | * Fixed return code problem at RLMT_SEND event. | |
42d1f039 | 220 | * |
7152b1d0 WD |
221 | * Revision 1.13 1999/04/07 10:11:42 cgoos |
222 | * Fixed Single Port problems. | |
223 | * Fixed Multi-Adapter problems. | |
224 | * Always display startup string. | |
42d1f039 | 225 | * |
7152b1d0 WD |
226 | * Revision 1.12 1999/03/29 12:26:37 cgoos |
227 | * Reversed locking to fine granularity. | |
228 | * Fixed skb double alloc problem (caused by incorrect xmit return code). | |
229 | * Enhanced function descriptions. | |
42d1f039 | 230 | * |
7152b1d0 WD |
231 | * Revision 1.11 1999/03/15 13:10:51 cgoos |
232 | * Changed device identifier in output string to ethX. | |
42d1f039 | 233 | * |
7152b1d0 WD |
234 | * Revision 1.10 1999/03/15 12:12:34 cgoos |
235 | * Changed copyright notice. | |
42d1f039 | 236 | * |
7152b1d0 WD |
237 | * Revision 1.9 1999/03/15 12:10:17 cgoos |
238 | * Changed locking to one driver lock. | |
239 | * Added check of SK_AC-size (for consistency with library). | |
42d1f039 | 240 | * |
7152b1d0 WD |
241 | * Revision 1.8 1999/03/08 11:44:02 cgoos |
242 | * Fixed missing dev->tbusy in SkGeXmit. | |
243 | * Changed large frame (jumbo) buffer number. | |
244 | * Added copying of short frames. | |
42d1f039 | 245 | * |
7152b1d0 WD |
246 | * Revision 1.7 1999/03/04 13:26:57 cgoos |
247 | * Fixed spinlock calls for SMP. | |
42d1f039 | 248 | * |
7152b1d0 WD |
249 | * Revision 1.6 1999/03/02 09:53:51 cgoos |
250 | * Added descriptor revertion for big endian machines. | |
42d1f039 | 251 | * |
7152b1d0 WD |
252 | * Revision 1.5 1999/03/01 08:50:59 cgoos |
253 | * Fixed SkGeChangeMtu. | |
254 | * Fixed pci config space accesses. | |
42d1f039 | 255 | * |
7152b1d0 WD |
256 | * Revision 1.4 1999/02/18 15:48:44 cgoos |
257 | * Corrected some printk's. | |
42d1f039 | 258 | * |
7152b1d0 WD |
259 | * Revision 1.3 1999/02/18 12:45:55 cgoos |
260 | * Changed SK_MAX_CARD_PARAM to default 16 | |
42d1f039 | 261 | * |
7152b1d0 WD |
262 | * Revision 1.2 1999/02/18 10:55:32 cgoos |
263 | * Removed SkGeDrvTimeStamp function. | |
264 | * Printing "ethX:" before adapter type at adapter init. | |
7152b1d0 | 265 | * |
42d1f039 WD |
266 | * |
267 | * 10-Feb-1999 cg Created, based on Linux' acenic.c, 3c59x.c and | |
7152b1d0 WD |
268 | * SysKonnects GEnesis Solaris driver |
269 | * | |
270 | ******************************************************************************/ | |
271 | ||
272 | /****************************************************************************** | |
273 | * | |
274 | * Possible compiler options (#define xxx / -Dxxx): | |
275 | * | |
42d1f039 | 276 | * debugging can be enable by changing SK_DEBUG_CHKMOD and |
7152b1d0 WD |
277 | * SK_DEBUG_CHKCAT in makefile (described there). |
278 | * | |
279 | ******************************************************************************/ | |
42d1f039 | 280 | |
7152b1d0 WD |
281 | /****************************************************************************** |
282 | * | |
283 | * Description: | |
284 | * | |
285 | * This is the main module of the Linux GE driver. | |
42d1f039 | 286 | * |
7152b1d0 WD |
287 | * All source files except skge.c, skdrv1st.h, skdrv2nd.h and sktypes.h |
288 | * are part of SysKonnect's COMMON MODULES for the SK-98xx adapters. | |
289 | * Those are used for drivers on multiple OS', so some thing may seem | |
290 | * unnecessary complicated on Linux. Please do not try to 'clean up' | |
291 | * them without VERY good reasons, because this will make it more | |
292 | * difficult to keep the Linux driver in synchronisation with the | |
293 | * other versions. | |
294 | * | |
295 | * Include file hierarchy: | |
296 | * | |
297 | * <linux/module.h> | |
298 | * | |
299 | * "h/skdrv1st.h" | |
300 | * <linux/version.h> | |
301 | * <linux/types.h> | |
302 | * <linux/kernel.h> | |
303 | * <linux/string.h> | |
304 | * <linux/errno.h> | |
305 | * <linux/ioport.h> | |
306 | * <linux/slab.h> | |
307 | * <linux/interrupt.h> | |
308 | * <linux/pci.h> | |
309 | * <asm/byteorder.h> | |
310 | * <asm/bitops.h> | |
311 | * <asm/io.h> | |
312 | * <linux/netdevice.h> | |
313 | * <linux/etherdevice.h> | |
314 | * <linux/skbuff.h> | |
315 | * those three depending on kernel version used: | |
316 | * <linux/bios32.h> | |
317 | * <linux/init.h> | |
318 | * <asm/uaccess.h> | |
319 | * <net/checksum.h> | |
320 | * | |
321 | * "h/skerror.h" | |
322 | * "h/skdebug.h" | |
323 | * "h/sktypes.h" | |
324 | * "h/lm80.h" | |
325 | * "h/xmac_ii.h" | |
326 | * | |
327 | * "h/skdrv2nd.h" | |
328 | * "h/skqueue.h" | |
329 | * "h/skgehwt.h" | |
330 | * "h/sktimer.h" | |
331 | * "h/ski2c.h" | |
332 | * "h/skgepnmi.h" | |
333 | * "h/skvpd.h" | |
334 | * "h/skgehw.h" | |
335 | * "h/skgeinit.h" | |
336 | * "h/skaddr.h" | |
337 | * "h/skgesirq.h" | |
338 | * "h/skcsum.h" | |
339 | * "h/skrlmt.h" | |
340 | * | |
341 | ******************************************************************************/ | |
342 | ||
149dded2 WD |
343 | #include <config.h> |
344 | ||
7152b1d0 WD |
345 | #include "h/skversion.h" |
346 | #if 0 | |
347 | #include <linux/module.h> | |
348 | #include <linux/init.h> | |
53677ef1 | 349 | #include <linux/proc_fs.h> |
7152b1d0 WD |
350 | #endif |
351 | #include "h/skdrv1st.h" | |
352 | #include "h/skdrv2nd.h" | |
353 | ||
354 | ||
355 | /* defines ******************************************************************/ | |
356 | /* for debuging on x86 only */ | |
357 | /* #define BREAKPOINT() asm(" int $3"); */ | |
358 | ||
359 | /* use the scatter-gather functionality with sendfile() */ | |
360 | #if 0 | |
361 | #define SK_ZEROCOPY | |
362 | #endif | |
363 | ||
364 | /* use of a transmit complete interrupt */ | |
365 | #define USE_TX_COMPLETE | |
366 | ||
367 | /* use interrupt moderation (for tx complete only) */ | |
368 | #define USE_INT_MOD | |
369 | #define INTS_PER_SEC 1000 | |
370 | ||
371 | /* | |
372 | * threshold for copying small receive frames | |
373 | * set to 0 to avoid copying, set to 9001 to copy all frames | |
374 | */ | |
375 | #define SK_COPY_THRESHOLD 50 | |
376 | ||
377 | /* number of adapters that can be configured via command line params */ | |
378 | #define SK_MAX_CARD_PARAM 16 | |
379 | ||
380 | ||
381 | /* | |
42d1f039 | 382 | * use those defines for a compile-in version of the driver instead |
7152b1d0 WD |
383 | * of command line parameters |
384 | */ | |
42d1f039 WD |
385 | /* #define LINK_SPEED_A {"Auto", } */ |
386 | /* #define LINK_SPEED_B {"Auto", } */ | |
387 | /* #define AUTO_NEG_A {"Sense", } */ | |
388 | /* #define AUTO_NEG_B {"Sense", } */ | |
389 | /* #define DUP_CAP_A {"Both", } */ | |
390 | /* #define DUP_CAP_B {"Both", } */ | |
391 | /* #define FLOW_CTRL_A {"SymOrRem", } */ | |
392 | /* #define FLOW_CTRL_B {"SymOrRem", } */ | |
393 | /* #define ROLE_A {"Auto", } */ | |
394 | /* #define ROLE_B {"Auto", } */ | |
395 | /* #define PREF_PORT {"A", } */ | |
396 | /* #define RLMT_MODE {"CheckLinkState", } */ | |
7152b1d0 WD |
397 | |
398 | #define DEV_KFREE_SKB(skb) dev_kfree_skb(skb) | |
399 | #define DEV_KFREE_SKB_IRQ(skb) dev_kfree_skb_irq(skb) | |
400 | #define DEV_KFREE_SKB_ANY(skb) dev_kfree_skb_any(skb) | |
401 | ||
402 | /* function prototypes ******************************************************/ | |
403 | static void FreeResources(struct SK_NET_DEVICE *dev); | |
404 | static int SkGeBoardInit(struct SK_NET_DEVICE *dev, SK_AC *pAC); | |
405 | static SK_BOOL BoardAllocMem(SK_AC *pAC); | |
406 | static void BoardFreeMem(SK_AC *pAC); | |
407 | static void BoardInitMem(SK_AC *pAC); | |
408 | static void SetupRing(SK_AC*, void*, uintptr_t, RXD**, RXD**, RXD**, | |
409 | int*, SK_BOOL); | |
410 | ||
411 | #if 0 | |
412 | static void SkGeIsr(int irq, void *dev_id, struct pt_regs *ptregs); | |
413 | static void SkGeIsrOnePort(int irq, void *dev_id, struct pt_regs *ptregs); | |
414 | static int SkGeOpen(struct SK_NET_DEVICE *dev); | |
415 | static int SkGeClose(struct SK_NET_DEVICE *dev); | |
416 | static int SkGeXmit(struct sk_buff *skb, struct SK_NET_DEVICE *dev); | |
417 | static int SkGeSetMacAddr(struct SK_NET_DEVICE *dev, void *p); | |
418 | static void SkGeSetRxMode(struct SK_NET_DEVICE *dev); | |
419 | static struct net_device_stats *SkGeStats(struct SK_NET_DEVICE *dev); | |
420 | static int SkGeIoctl(struct SK_NET_DEVICE *dev, struct ifreq *rq, int cmd); | |
421 | #else | |
422 | void SkGeIsr(int irq, void *dev_id, struct pt_regs *ptregs); | |
423 | void SkGeIsrOnePort(int irq, void *dev_id, struct pt_regs *ptregs); | |
424 | int SkGeOpen(struct SK_NET_DEVICE *dev); | |
425 | int SkGeClose(struct SK_NET_DEVICE *dev); | |
426 | int SkGeXmit(struct sk_buff *skb, struct SK_NET_DEVICE *dev); | |
427 | #endif | |
428 | static void GetConfiguration(SK_AC*); | |
429 | static void ProductStr(SK_AC*); | |
430 | static int XmitFrame(SK_AC*, TX_PORT*, struct sk_buff*); | |
431 | static void FreeTxDescriptors(SK_AC*pAC, TX_PORT*); | |
432 | static void FillRxRing(SK_AC*, RX_PORT*); | |
433 | static SK_BOOL FillRxDescriptor(SK_AC*, RX_PORT*); | |
434 | #if 0 | |
435 | static void ReceiveIrq(SK_AC*, RX_PORT*, SK_BOOL); | |
436 | #else | |
437 | void ReceiveIrq(SK_AC*, RX_PORT*, SK_BOOL); | |
438 | #endif | |
439 | static void ClearAndStartRx(SK_AC*, int); | |
440 | static void ClearTxIrq(SK_AC*, int, int); | |
441 | static void ClearRxRing(SK_AC*, RX_PORT*); | |
442 | static void ClearTxRing(SK_AC*, TX_PORT*); | |
443 | #if 0 | |
444 | static void SetQueueSizes(SK_AC *pAC); | |
445 | ||
446 | static int SkGeChangeMtu(struct SK_NET_DEVICE *dev, int new_mtu); | |
447 | #endif | |
448 | static void PortReInitBmu(SK_AC*, int); | |
449 | #if 0 | |
450 | static int SkGeIocMib(DEV_NET*, unsigned int, int); | |
451 | static int XmitFrameSG(SK_AC*, TX_PORT*, struct sk_buff*); | |
452 | #endif | |
453 | ||
454 | /*Extern */ | |
455 | ||
456 | /* external Proc function */ | |
457 | extern int proc_read( | |
458 | char *buffer, | |
459 | char **buffer_location, | |
460 | off_t offset, | |
461 | int buffer_length, | |
462 | int *eof, | |
463 | void *data); | |
464 | ||
465 | #ifdef DEBUG | |
466 | static void DumpMsg(struct sk_buff*, char*); | |
467 | static void DumpData(char*, int); | |
468 | static void DumpLong(char*, int); | |
469 | #endif | |
470 | void dump_frag( SK_U8 *data, int length); | |
471 | ||
472 | /* global variables *********************************************************/ | |
473 | #if 0 | |
474 | static const char *BootString = BOOT_STRING; | |
475 | #endif | |
476 | struct SK_NET_DEVICE *SkGeRootDev = NULL; | |
477 | static int probed __initdata = 0; | |
478 | ||
479 | /* local variables **********************************************************/ | |
480 | static uintptr_t TxQueueAddr[SK_MAX_MACS][2] = {{0x680, 0x600},{0x780, 0x700}}; | |
481 | static uintptr_t RxQueueAddr[SK_MAX_MACS] = {0x400, 0x480}; | |
482 | ||
483 | ||
484 | /* local variables **********************************************************/ | |
485 | const char SK_Root_Dir_entry[8]; | |
486 | ||
487 | #if 0 | |
488 | static struct proc_dir_entry *pSkRootDir; | |
489 | #endif | |
490 | ||
491 | ||
492 | static struct pci_device_id supported[] = { | |
493 | {PCI_VENDOR_ID_3COM, 0x1700}, | |
494 | {PCI_VENDOR_ID_SYSKONNECT, PCI_DEVICE_ID_SYSKONNECT_GE}, | |
0b8fa03b | 495 | {PCI_VENDOR_ID_SYSKONNECT, PCI_DEVICE_ID_SYSKONNECT_YU}, |
7152b1d0 WD |
496 | {} |
497 | }; | |
498 | ||
499 | ||
500 | /***************************************************************************** | |
501 | * | |
53677ef1 | 502 | * skge_probe - find all SK-98xx adapters |
7152b1d0 WD |
503 | * |
504 | * Description: | |
505 | * This function scans the PCI bus for SK-98xx adapters. Resources for | |
506 | * each adapter are allocated and the adapter is brought into Init 1 | |
507 | * state. | |
508 | * | |
509 | * Returns: | |
510 | * 0, if everything is ok | |
511 | * !=0, on error | |
512 | */ | |
513 | #if 0 | |
514 | static int __init skge_probe (void) | |
515 | #else | |
516 | int skge_probe (struct eth_device ** ret_dev) | |
517 | #endif | |
518 | { | |
519 | #if 0 | |
520 | int proc_root_initialized = 0; | |
521 | #endif | |
522 | int boards_found = 0; | |
523 | #if 0 | |
524 | int vendor_flag = SK_FALSE; | |
525 | #endif | |
526 | SK_AC *pAC; | |
527 | DEV_NET *pNet = NULL; | |
528 | #if 0 | |
529 | struct proc_dir_entry *pProcFile; | |
530 | struct pci_dev *pdev = NULL; | |
531 | unsigned long base_address; | |
532 | #else | |
533 | u32 base_address; | |
534 | #endif | |
535 | struct SK_NET_DEVICE *dev = NULL; | |
536 | #if 0 | |
537 | SK_BOOL DeviceFound = SK_FALSE; | |
538 | #endif | |
539 | SK_BOOL BootStringCount = SK_FALSE; | |
540 | #if 1 | |
541 | pci_dev_t devno; | |
542 | #endif | |
543 | ||
544 | if (probed) | |
545 | return -ENODEV; | |
546 | probed++; | |
547 | ||
548 | if (!pci_present()) /* is PCI support present? */ | |
549 | return -ENODEV; | |
550 | ||
551 | #if 0 | |
552 | while((pdev = pci_find_class(PCI_CLASS_NETWORK_ETHERNET << 8, pdev))) | |
553 | #else | |
554 | while((devno = pci_find_devices (supported, boards_found)) >= 0) | |
555 | #endif | |
556 | { | |
557 | ||
558 | dev = NULL; | |
559 | pNet = NULL; | |
560 | ||
561 | ||
562 | #if 0 | |
563 | SK_PCI_ISCOMPLIANT(vendor_flag, pdev); | |
564 | if (!vendor_flag) | |
565 | continue; | |
566 | #endif | |
567 | ||
42d1f039 WD |
568 | /* if ((pdev->vendor != PCI_VENDOR_ID_SYSKONNECT) && |
569 | ((pdev->device != PCI_DEVICE_ID_SYSKONNECT_GE) || | |
7152b1d0 WD |
570 | (pdev->device != PCI_DEVICE_ID_SYSKONNECT_YU))){ |
571 | continue; | |
572 | } | |
573 | */ | |
574 | #if 0 | |
575 | /* Configure DMA attributes. */ | |
576 | if (pci_set_dma_mask(pdev, (u64) 0xffffffffffffffff) && | |
577 | pci_set_dma_mask(pdev, (u64) 0xffffffff)) | |
578 | continue; | |
579 | #endif | |
580 | ||
581 | ||
582 | #if 0 | |
583 | if ((dev = init_etherdev(dev, sizeof(DEV_NET))) == NULL) { | |
584 | printk(KERN_ERR "Unable to allocate etherdev " | |
585 | "structure!\n"); | |
586 | break; | |
587 | } | |
588 | #else | |
589 | dev = malloc (sizeof *dev); | |
590 | memset(dev, 0, sizeof(*dev)); | |
591 | dev->priv = malloc(sizeof(DEV_NET)); | |
592 | #endif | |
593 | ||
594 | if (dev->priv == NULL) { | |
595 | printk(KERN_ERR "Unable to allocate adapter " | |
596 | "structure!\n"); | |
597 | break; | |
598 | } | |
599 | ||
600 | pNet = dev->priv; | |
601 | pNet->pAC = kmalloc(sizeof(SK_AC), GFP_KERNEL); | |
602 | if (pNet->pAC == NULL){ | |
603 | kfree(dev->priv); | |
604 | printk(KERN_ERR "Unable to allocate adapter " | |
605 | "structure!\n"); | |
606 | break; | |
607 | } | |
608 | ||
609 | /* Print message */ | |
610 | if (!BootStringCount) { | |
611 | /* set display flag to TRUE so that */ | |
612 | /* we only display this string ONCE */ | |
613 | BootStringCount = SK_TRUE; | |
614 | #ifdef SK98_INFO | |
615 | printk("%s\n", BootString); | |
616 | #endif | |
617 | } | |
618 | ||
619 | memset(pNet->pAC, 0, sizeof(SK_AC)); | |
620 | pAC = pNet->pAC; | |
621 | #if 0 | |
622 | pAC->PciDev = pdev; | |
623 | pAC->PciDevId = pdev->device; | |
624 | pAC->dev[0] = dev; | |
625 | pAC->dev[1] = dev; | |
626 | #else | |
627 | pAC->PciDev = devno; | |
628 | ret_dev[0] = pAC->dev[0] = dev; | |
629 | ret_dev[1] = pAC->dev[1] = dev; | |
630 | #endif | |
631 | sprintf(pAC->Name, "SysKonnect SK-98xx"); | |
632 | pAC->CheckQueue = SK_FALSE; | |
633 | ||
634 | pNet->Mtu = 1500; | |
635 | pNet->Up = 0; | |
636 | #if 0 | |
637 | dev->irq = pdev->irq; | |
638 | ||
639 | dev->open = &SkGeOpen; | |
640 | dev->stop = &SkGeClose; | |
641 | dev->hard_start_xmit = &SkGeXmit; | |
642 | dev->get_stats = &SkGeStats; | |
643 | dev->set_multicast_list = &SkGeSetRxMode; | |
644 | dev->set_mac_address = &SkGeSetMacAddr; | |
645 | dev->do_ioctl = &SkGeIoctl; | |
646 | dev->change_mtu = &SkGeChangeMtu; | |
53677ef1 | 647 | dev->flags &= ~IFF_RUNNING; |
7152b1d0 WD |
648 | #endif |
649 | ||
650 | #ifdef SK_ZEROCOPY | |
651 | if (pAC->GIni.GIChipId == CHIP_ID_YUKON) { | |
652 | /* Use only if yukon hardware */ | |
653 | /* SK and ZEROCOPY - fly baby... */ | |
654 | dev->features |= NETIF_F_SG | NETIF_F_IP_CSUM; | |
655 | } | |
656 | #endif | |
657 | ||
658 | #if 0 | |
659 | /* | |
660 | * Dummy value. | |
661 | */ | |
662 | dev->base_addr = 42; | |
663 | pci_set_master(pdev); | |
664 | ||
665 | pci_set_master(pdev); | |
666 | base_address = pci_resource_start (pdev, 0); | |
667 | #else | |
668 | pci_write_config_dword(devno, | |
42d1f039 WD |
669 | PCI_COMMAND, |
670 | PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER); | |
7152b1d0 | 671 | pci_read_config_dword (devno, PCI_BASE_ADDRESS_0, |
42d1f039 | 672 | &base_address); |
7152b1d0 WD |
673 | #endif |
674 | ||
675 | #ifdef SK_BIG_ENDIAN | |
676 | /* | |
677 | * On big endian machines, we use the adapter's aibility of | |
678 | * reading the descriptors as big endian. | |
679 | */ | |
680 | { | |
681 | SK_U32 our2; | |
682 | SkPciReadCfgDWord(pAC, PCI_OUR_REG_2, &our2); | |
683 | our2 |= PCI_REV_DESC; | |
684 | SkPciWriteCfgDWord(pAC, PCI_OUR_REG_2, our2); | |
685 | } | |
686 | #endif | |
687 | ||
688 | /* | |
689 | * Remap the regs into kernel space. | |
690 | */ | |
691 | #if 0 | |
692 | pAC->IoBase = (char*)ioremap(base_address, 0x4000); | |
693 | #else | |
694 | pAC->IoBase = (char*)pci_mem_to_phys(devno, base_address); | |
695 | #endif | |
696 | ||
697 | if (!pAC->IoBase){ | |
698 | printk(KERN_ERR "%s: Unable to map I/O register, " | |
699 | "SK 98xx No. %i will be disabled.\n", | |
700 | dev->name, boards_found); | |
701 | kfree(dev); | |
702 | break; | |
703 | } | |
704 | ||
705 | pAC->Index = boards_found; | |
706 | if (SkGeBoardInit(dev, pAC)) { | |
707 | FreeResources(dev); | |
708 | kfree(dev); | |
709 | continue; | |
710 | } | |
711 | ||
712 | #if 0 | |
713 | memcpy((caddr_t) &dev->dev_addr, | |
714 | (caddr_t) &pAC->Addr.Net[0].CurrentMacAddress, 6); | |
715 | #else | |
716 | memcpy((caddr_t) &dev->enetaddr, | |
717 | (caddr_t) &pAC->Addr.Net[0].CurrentMacAddress, 6); | |
718 | #endif | |
719 | ||
720 | #if 0 | |
721 | /* First adapter... Create proc and print message */ | |
722 | if (!DeviceFound) { | |
723 | DeviceFound = SK_TRUE; | |
724 | SK_MEMCPY(&SK_Root_Dir_entry, BootString, | |
725 | sizeof(SK_Root_Dir_entry) - 1); | |
726 | ||
727 | /*Create proc (directory)*/ | |
728 | if(!proc_root_initialized) { | |
729 | pSkRootDir = create_proc_entry(SK_Root_Dir_entry, | |
730 | S_IFDIR | S_IWUSR | S_IRUGO | S_IXUGO, proc_net); | |
731 | proc_root_initialized = 1; | |
732 | } | |
733 | ||
734 | pSkRootDir->owner = THIS_MODULE; | |
735 | } | |
736 | ||
737 | ||
7152b1d0 WD |
738 | /* Create proc file */ |
739 | pProcFile = create_proc_entry(dev->name, | |
740 | S_IFREG | S_IXUSR | S_IWGRP | S_IROTH, | |
741 | pSkRootDir); | |
742 | ||
42d1f039 | 743 | |
7152b1d0 WD |
744 | pProcFile->read_proc = proc_read; |
745 | pProcFile->write_proc = NULL; | |
746 | pProcFile->nlink = 1; | |
747 | pProcFile->size = sizeof(dev->name + 1); | |
748 | pProcFile->data = (void *)pProcFile; | |
749 | #endif | |
750 | ||
751 | pNet->PortNr = 0; | |
752 | pNet->NetNr = 0; | |
753 | ||
754 | #ifdef SK_ZEROCOPY | |
755 | if (pAC->GIni.GIChipId == CHIP_ID_YUKON) { | |
756 | /* SG and ZEROCOPY - fly baby... */ | |
757 | dev->features |= NETIF_F_SG | NETIF_F_IP_CSUM; | |
758 | } | |
759 | #endif | |
760 | ||
761 | boards_found++; | |
762 | ||
763 | /* More then one port found */ | |
764 | if ((pAC->GIni.GIMacsFound == 2 ) && (pAC->RlmtNets == 2)) { | |
765 | #if 0 | |
766 | if ((dev = init_etherdev(NULL, sizeof(DEV_NET))) == 0) { | |
767 | printk(KERN_ERR "Unable to allocate etherdev " | |
768 | "structure!\n"); | |
769 | break; | |
770 | } | |
771 | #else | |
772 | dev = malloc (sizeof *dev); | |
773 | memset(dev, 0, sizeof(*dev)); | |
774 | dev->priv = malloc(sizeof(DEV_NET)); | |
775 | #endif | |
776 | ||
777 | pAC->dev[1] = dev; | |
778 | pNet = dev->priv; | |
779 | pNet->PortNr = 1; | |
780 | pNet->NetNr = 1; | |
781 | pNet->pAC = pAC; | |
782 | pNet->Mtu = 1500; | |
783 | pNet->Up = 0; | |
784 | ||
785 | #if 0 | |
786 | dev->open = &SkGeOpen; | |
787 | dev->stop = &SkGeClose; | |
788 | dev->hard_start_xmit = &SkGeXmit; | |
789 | dev->get_stats = &SkGeStats; | |
790 | dev->set_multicast_list = &SkGeSetRxMode; | |
791 | dev->set_mac_address = &SkGeSetMacAddr; | |
792 | dev->do_ioctl = &SkGeIoctl; | |
793 | dev->change_mtu = &SkGeChangeMtu; | |
53677ef1 | 794 | dev->flags &= ~IFF_RUNNING; |
7152b1d0 WD |
795 | #endif |
796 | ||
797 | #ifdef SK_ZEROCOPY | |
798 | if (pAC->GIni.GIChipId == CHIP_ID_YUKON) { | |
799 | /* SG and ZEROCOPY - fly baby... */ | |
800 | dev->features |= NETIF_F_SG | NETIF_F_IP_CSUM; | |
801 | } | |
802 | #endif | |
803 | ||
804 | #if 0 | |
805 | pProcFile = create_proc_entry(dev->name, | |
806 | S_IFREG | S_IXUSR | S_IWGRP | S_IROTH, | |
807 | pSkRootDir); | |
808 | ||
42d1f039 | 809 | |
7152b1d0 WD |
810 | pProcFile->read_proc = proc_read; |
811 | pProcFile->write_proc = NULL; | |
812 | pProcFile->nlink = 1; | |
813 | pProcFile->size = sizeof(dev->name + 1); | |
814 | pProcFile->data = (void *)pProcFile; | |
815 | #endif | |
816 | ||
817 | #if 0 | |
818 | memcpy((caddr_t) &dev->dev_addr, | |
819 | (caddr_t) &pAC->Addr.Net[1].CurrentMacAddress, 6); | |
820 | #else | |
821 | memcpy((caddr_t) &dev->enetaddr, | |
822 | (caddr_t) &pAC->Addr.Net[1].CurrentMacAddress, 6); | |
823 | #endif | |
42d1f039 | 824 | |
7152b1d0 WD |
825 | printk("%s: %s\n", dev->name, pAC->DeviceStr); |
826 | printk(" PrefPort:B RlmtMode:Dual Check Link State\n"); | |
827 | ||
828 | } | |
829 | ||
830 | ||
831 | /* Save the hardware revision */ | |
832 | pAC->HWRevision = (((pAC->GIni.GIPciHwRev >> 4) & 0x0F)*10) + | |
833 | (pAC->GIni.GIPciHwRev & 0x0F); | |
834 | ||
835 | /* | |
836 | * This is bollocks, but we need to tell the net-init | |
837 | * code that it shall go for the next device. | |
838 | */ | |
839 | #if 0 | |
840 | #ifndef MODULE | |
841 | dev->base_addr = 0; | |
842 | #endif | |
843 | #endif | |
844 | } | |
845 | ||
846 | /* | |
847 | * If we're at this point we're going through skge_probe() for | |
848 | * the first time. Return success (0) if we've initialized 1 | |
849 | * or more boards. Otherwise, return failure (-ENODEV). | |
850 | */ | |
851 | ||
852 | return boards_found; | |
853 | } /* skge_probe */ | |
854 | ||
855 | ||
856 | /***************************************************************************** | |
857 | * | |
53677ef1 | 858 | * FreeResources - release resources allocated for adapter |
7152b1d0 WD |
859 | * |
860 | * Description: | |
861 | * This function releases the IRQ, unmaps the IO and | |
862 | * frees the desriptor ring. | |
863 | * | |
864 | * Returns: N/A | |
42d1f039 | 865 | * |
7152b1d0 WD |
866 | */ |
867 | static void FreeResources(struct SK_NET_DEVICE *dev) | |
868 | { | |
869 | SK_U32 AllocFlag; | |
870 | DEV_NET *pNet; | |
871 | SK_AC *pAC; | |
872 | ||
873 | if (dev->priv) { | |
874 | pNet = (DEV_NET*) dev->priv; | |
875 | pAC = pNet->pAC; | |
876 | AllocFlag = pAC->AllocFlag; | |
877 | #if 0 | |
878 | if (AllocFlag & SK_ALLOC_IRQ) { | |
879 | free_irq(dev->irq, dev); | |
880 | } | |
881 | if (pAC->IoBase) { | |
882 | iounmap(pAC->IoBase); | |
883 | } | |
884 | #endif | |
885 | if (pAC->pDescrMem) { | |
886 | BoardFreeMem(pAC); | |
887 | } | |
888 | } | |
42d1f039 | 889 | |
7152b1d0 WD |
890 | } /* FreeResources */ |
891 | ||
892 | #if 0 | |
893 | MODULE_AUTHOR("Mirko Lindner <mlindner@syskonnect.de>"); | |
894 | MODULE_DESCRIPTION("SysKonnect SK-NET Gigabit Ethernet SK-98xx driver"); | |
895 | MODULE_LICENSE("GPL"); | |
896 | MODULE_PARM(Speed_A, "1-" __MODULE_STRING(SK_MAX_CARD_PARAM) "s"); | |
897 | MODULE_PARM(Speed_B, "1-" __MODULE_STRING(SK_MAX_CARD_PARAM) "s"); | |
898 | MODULE_PARM(AutoNeg_A, "1-" __MODULE_STRING(SK_MAX_CARD_PARAM) "s"); | |
899 | MODULE_PARM(AutoNeg_B, "1-" __MODULE_STRING(SK_MAX_CARD_PARAM) "s"); | |
900 | MODULE_PARM(DupCap_A, "1-" __MODULE_STRING(SK_MAX_CARD_PARAM) "s"); | |
901 | MODULE_PARM(DupCap_B, "1-" __MODULE_STRING(SK_MAX_CARD_PARAM) "s"); | |
902 | MODULE_PARM(FlowCtrl_A, "1-" __MODULE_STRING(SK_MAX_CARD_PARAM) "s"); | |
903 | MODULE_PARM(FlowCtrl_B, "1-" __MODULE_STRING(SK_MAX_CARD_PARAM) "s"); | |
904 | MODULE_PARM(Role_A, "1-" __MODULE_STRING(SK_MAX_CARD_PARAM) "s"); | |
905 | MODULE_PARM(Role_B, "1-" __MODULE_STRING(SK_MAX_CARD_PARAM) "s"); | |
906 | MODULE_PARM(PrefPort, "1-" __MODULE_STRING(SK_MAX_CARD_PARAM) "s"); | |
907 | MODULE_PARM(RlmtMode, "1-" __MODULE_STRING(SK_MAX_CARD_PARAM) "s"); | |
908 | /* not used, just there because every driver should have them: */ | |
909 | MODULE_PARM(options, "1-" __MODULE_STRING(SK_MAX_CARD_PARAM) "i"); | |
910 | MODULE_PARM(debug, "i"); | |
911 | #endif | |
912 | ||
913 | ||
914 | #ifdef LINK_SPEED_A | |
915 | static char *Speed_A[SK_MAX_CARD_PARAM] = LINK_SPEED_A; | |
916 | #else | |
917 | static char *Speed_A[SK_MAX_CARD_PARAM] = {"", }; | |
918 | #endif | |
919 | ||
920 | #ifdef LINK_SPEED_B | |
921 | static char *Speed_B[SK_MAX_CARD_PARAM] = LINK_SPEED_B; | |
922 | #else | |
923 | static char *Speed_B[SK_MAX_CARD_PARAM] = {"", }; | |
924 | #endif | |
925 | ||
926 | #ifdef AUTO_NEG_A | |
927 | static char *AutoNeg_A[SK_MAX_CARD_PARAM] = AUTO_NEG_A; | |
928 | #else | |
929 | static char *AutoNeg_A[SK_MAX_CARD_PARAM] = {"", }; | |
930 | #endif | |
931 | ||
932 | #ifdef DUP_CAP_A | |
933 | static char *DupCap_A[SK_MAX_CARD_PARAM] = DUP_CAP_A; | |
934 | #else | |
935 | static char *DupCap_A[SK_MAX_CARD_PARAM] = {"", }; | |
936 | #endif | |
937 | ||
938 | #ifdef FLOW_CTRL_A | |
939 | static char *FlowCtrl_A[SK_MAX_CARD_PARAM] = FLOW_CTRL_A; | |
940 | #else | |
941 | static char *FlowCtrl_A[SK_MAX_CARD_PARAM] = {"", }; | |
942 | #endif | |
943 | ||
944 | #ifdef ROLE_A | |
945 | static char *Role_A[SK_MAX_CARD_PARAM] = ROLE_A; | |
946 | #else | |
947 | static char *Role_A[SK_MAX_CARD_PARAM] = {"", }; | |
948 | #endif | |
949 | ||
950 | #ifdef AUTO_NEG_B | |
951 | static char *AutoNeg_B[SK_MAX_CARD_PARAM] = AUTO_NEG_B; | |
952 | #else | |
953 | static char *AutoNeg_B[SK_MAX_CARD_PARAM] = {"", }; | |
954 | #endif | |
955 | ||
956 | #ifdef DUP_CAP_B | |
957 | static char *DupCap_B[SK_MAX_CARD_PARAM] = DUP_CAP_B; | |
958 | #else | |
959 | static char *DupCap_B[SK_MAX_CARD_PARAM] = {"", }; | |
960 | #endif | |
961 | ||
962 | #ifdef FLOW_CTRL_B | |
963 | static char *FlowCtrl_B[SK_MAX_CARD_PARAM] = FLOW_CTRL_B; | |
964 | #else | |
965 | static char *FlowCtrl_B[SK_MAX_CARD_PARAM] = {"", }; | |
966 | #endif | |
967 | ||
968 | #ifdef ROLE_B | |
969 | static char *Role_B[SK_MAX_CARD_PARAM] = ROLE_B; | |
970 | #else | |
971 | static char *Role_B[SK_MAX_CARD_PARAM] = {"", }; | |
972 | #endif | |
973 | ||
974 | #ifdef PREF_PORT | |
975 | static char *PrefPort[SK_MAX_CARD_PARAM] = PREF_PORT; | |
976 | #else | |
977 | static char *PrefPort[SK_MAX_CARD_PARAM] = {"", }; | |
978 | #endif | |
979 | ||
980 | #ifdef RLMT_MODE | |
981 | static char *RlmtMode[SK_MAX_CARD_PARAM] = RLMT_MODE; | |
982 | #else | |
983 | static char *RlmtMode[SK_MAX_CARD_PARAM] = {"", }; | |
984 | #endif | |
985 | ||
986 | #if 0 | |
987 | static int debug = 0; /* not used */ | |
988 | static int options[SK_MAX_CARD_PARAM] = {0, }; /* not used */ | |
989 | ||
990 | ||
991 | /***************************************************************************** | |
992 | * | |
53677ef1 | 993 | * skge_init_module - module initialization function |
7152b1d0 WD |
994 | * |
995 | * Description: | |
996 | * Very simple, only call skge_probe and return approriate result. | |
997 | * | |
998 | * Returns: | |
999 | * 0, if everything is ok | |
1000 | * !=0, on error | |
1001 | */ | |
1002 | static int __init skge_init_module(void) | |
1003 | { | |
1004 | int cards; | |
1005 | SkGeRootDev = NULL; | |
42d1f039 | 1006 | |
7152b1d0 WD |
1007 | /* just to avoid warnings ... */ |
1008 | debug = 0; | |
1009 | options[0] = 0; | |
1010 | ||
1011 | cards = skge_probe(); | |
1012 | if (cards == 0) { | |
1013 | printk("sk98lin: No adapter found.\n"); | |
1014 | } | |
1015 | return cards ? 0 : -ENODEV; | |
1016 | } /* skge_init_module */ | |
1017 | ||
1018 | ||
1019 | /***************************************************************************** | |
1020 | * | |
53677ef1 | 1021 | * skge_cleanup_module - module unload function |
7152b1d0 WD |
1022 | * |
1023 | * Description: | |
1024 | * Disable adapter if it is still running, free resources, | |
1025 | * free device struct. | |
1026 | * | |
1027 | * Returns: N/A | |
1028 | */ | |
1029 | static void __exit skge_cleanup_module(void) | |
1030 | { | |
1031 | DEV_NET *pNet; | |
1032 | SK_AC *pAC; | |
1033 | struct SK_NET_DEVICE *next; | |
1034 | unsigned long Flags; | |
1035 | SK_EVPARA EvPara; | |
1036 | ||
1037 | while (SkGeRootDev) { | |
1038 | pNet = (DEV_NET*) SkGeRootDev->priv; | |
1039 | pAC = pNet->pAC; | |
1040 | next = pAC->Next; | |
1041 | ||
1042 | netif_stop_queue(SkGeRootDev); | |
1043 | SkGeYellowLED(pAC, pAC->IoBase, 0); | |
1044 | ||
1045 | if(pAC->BoardLevel == 2) { | |
1046 | /* board is still alive */ | |
1047 | spin_lock_irqsave(&pAC->SlowPathLock, Flags); | |
1048 | EvPara.Para32[0] = 0; | |
1049 | EvPara.Para32[1] = -1; | |
1050 | SkEventQueue(pAC, SKGE_RLMT, SK_RLMT_STOP, EvPara); | |
1051 | EvPara.Para32[0] = 1; | |
1052 | EvPara.Para32[1] = -1; | |
1053 | SkEventQueue(pAC, SKGE_RLMT, SK_RLMT_STOP, EvPara); | |
1054 | SkEventDispatcher(pAC, pAC->IoBase); | |
1055 | /* disable interrupts */ | |
1056 | SK_OUT32(pAC->IoBase, B0_IMSK, 0); | |
42d1f039 | 1057 | SkGeDeInit(pAC, pAC->IoBase); |
7152b1d0 WD |
1058 | spin_unlock_irqrestore(&pAC->SlowPathLock, Flags); |
1059 | pAC->BoardLevel = 0; | |
1060 | /* We do NOT check here, if IRQ was pending, of course*/ | |
1061 | } | |
1062 | ||
1063 | if(pAC->BoardLevel == 1) { | |
1064 | /* board is still alive */ | |
42d1f039 | 1065 | SkGeDeInit(pAC, pAC->IoBase); |
7152b1d0 WD |
1066 | pAC->BoardLevel = 0; |
1067 | } | |
1068 | ||
1069 | if ((pAC->GIni.GIMacsFound == 2) && pAC->RlmtNets == 2){ | |
1070 | unregister_netdev(pAC->dev[1]); | |
1071 | kfree(pAC->dev[1]); | |
1072 | } | |
1073 | ||
1074 | FreeResources(SkGeRootDev); | |
1075 | ||
1076 | SkGeRootDev->get_stats = NULL; | |
42d1f039 | 1077 | /* |
7152b1d0 WD |
1078 | * otherwise unregister_netdev calls get_stats with |
1079 | * invalid IO ... :-( | |
1080 | */ | |
1081 | unregister_netdev(SkGeRootDev); | |
1082 | kfree(SkGeRootDev); | |
1083 | kfree(pAC); | |
1084 | SkGeRootDev = next; | |
1085 | } | |
1086 | ||
1087 | /* clear proc-dir */ | |
1088 | remove_proc_entry(pSkRootDir->name, proc_net); | |
1089 | ||
1090 | } /* skge_cleanup_module */ | |
1091 | ||
1092 | module_init(skge_init_module); | |
1093 | module_exit(skge_cleanup_module); | |
1094 | #endif | |
1095 | ||
1096 | ||
1097 | /***************************************************************************** | |
1098 | * | |
53677ef1 | 1099 | * SkGeBoardInit - do level 0 and 1 initialization |
7152b1d0 WD |
1100 | * |
1101 | * Description: | |
1102 | * This function prepares the board hardware for running. The desriptor | |
1103 | * ring is set up, the IRQ is allocated and the configuration settings | |
1104 | * are examined. | |
1105 | * | |
1106 | * Returns: | |
1107 | * 0, if everything is ok | |
1108 | * !=0, on error | |
1109 | */ | |
1110 | static int __init SkGeBoardInit(struct SK_NET_DEVICE *dev, SK_AC *pAC) | |
1111 | { | |
1112 | short i; | |
1113 | unsigned long Flags; | |
1114 | char *DescrString = "sk98lin: Driver for Linux"; /* this is given to PNMI */ | |
1115 | char *VerStr = VER_STRING; | |
1116 | #if 0 | |
1117 | int Ret; /* return code of request_irq */ | |
1118 | #endif | |
1119 | SK_BOOL DualNet; | |
1120 | ||
1121 | SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_ENTRY, | |
1122 | ("IoBase: %08lX\n", (unsigned long)pAC->IoBase)); | |
1123 | for (i=0; i<SK_MAX_MACS; i++) { | |
1124 | pAC->TxPort[i][0].HwAddr = pAC->IoBase + TxQueueAddr[i][0]; | |
1125 | pAC->TxPort[i][0].PortIndex = i; | |
1126 | pAC->RxPort[i].HwAddr = pAC->IoBase + RxQueueAddr[i]; | |
1127 | pAC->RxPort[i].PortIndex = i; | |
1128 | } | |
1129 | ||
1130 | /* Initialize the mutexes */ | |
1131 | for (i=0; i<SK_MAX_MACS; i++) { | |
1132 | spin_lock_init(&pAC->TxPort[i][0].TxDesRingLock); | |
1133 | spin_lock_init(&pAC->RxPort[i].RxDesRingLock); | |
1134 | } | |
1135 | spin_lock_init(&pAC->SlowPathLock); | |
1136 | ||
1137 | /* level 0 init common modules here */ | |
42d1f039 | 1138 | |
7152b1d0 WD |
1139 | spin_lock_irqsave(&pAC->SlowPathLock, Flags); |
1140 | /* Does a RESET on board ...*/ | |
1141 | if (SkGeInit(pAC, pAC->IoBase, 0) != 0) { | |
1142 | printk("HWInit (0) failed.\n"); | |
1143 | spin_unlock_irqrestore(&pAC->SlowPathLock, Flags); | |
1144 | return(-EAGAIN); | |
1145 | } | |
1146 | SkI2cInit( pAC, pAC->IoBase, 0); | |
1147 | SkEventInit(pAC, pAC->IoBase, 0); | |
1148 | SkPnmiInit( pAC, pAC->IoBase, 0); | |
1149 | SkAddrInit( pAC, pAC->IoBase, 0); | |
1150 | SkRlmtInit( pAC, pAC->IoBase, 0); | |
1151 | SkTimerInit(pAC, pAC->IoBase, 0); | |
42d1f039 | 1152 | |
7152b1d0 WD |
1153 | pAC->BoardLevel = 0; |
1154 | pAC->RxBufSize = ETH_BUF_SIZE; | |
1155 | ||
1156 | SK_PNMI_SET_DRIVER_DESCR(pAC, DescrString); | |
1157 | SK_PNMI_SET_DRIVER_VER(pAC, VerStr); | |
1158 | ||
1159 | spin_unlock_irqrestore(&pAC->SlowPathLock, Flags); | |
1160 | ||
1161 | /* level 1 init common modules here (HW init) */ | |
1162 | spin_lock_irqsave(&pAC->SlowPathLock, Flags); | |
1163 | if (SkGeInit(pAC, pAC->IoBase, 1) != 0) { | |
1164 | printk("HWInit (1) failed.\n"); | |
1165 | spin_unlock_irqrestore(&pAC->SlowPathLock, Flags); | |
1166 | return(-EAGAIN); | |
1167 | } | |
1168 | SkI2cInit( pAC, pAC->IoBase, 1); | |
1169 | SkEventInit(pAC, pAC->IoBase, 1); | |
1170 | SkPnmiInit( pAC, pAC->IoBase, 1); | |
1171 | SkAddrInit( pAC, pAC->IoBase, 1); | |
1172 | SkRlmtInit( pAC, pAC->IoBase, 1); | |
1173 | SkTimerInit(pAC, pAC->IoBase, 1); | |
1174 | ||
1175 | GetConfiguration(pAC); | |
1176 | if (pAC->RlmtNets == 2) { | |
1177 | pAC->GIni.GIPortUsage = SK_MUL_LINK; | |
1178 | } | |
1179 | ||
1180 | pAC->BoardLevel = 1; | |
1181 | spin_unlock_irqrestore(&pAC->SlowPathLock, Flags); | |
1182 | ||
1183 | #if 0 | |
1184 | if (pAC->GIni.GIMacsFound == 2) { | |
1185 | Ret = request_irq(dev->irq, SkGeIsr, SA_SHIRQ, pAC->Name, dev); | |
1186 | } else if (pAC->GIni.GIMacsFound == 1) { | |
1187 | Ret = request_irq(dev->irq, SkGeIsrOnePort, SA_SHIRQ, | |
1188 | pAC->Name, dev); | |
1189 | } else { | |
1190 | printk(KERN_WARNING "%s: Illegal number of ports: %d\n", | |
1191 | dev->name, pAC->GIni.GIMacsFound); | |
1192 | return -EAGAIN; | |
1193 | } | |
1194 | ||
1195 | if (Ret) { | |
1196 | printk(KERN_WARNING "%s: Requested IRQ %d is busy.\n", | |
1197 | dev->name, dev->irq); | |
1198 | return -EAGAIN; | |
1199 | } | |
1200 | #endif | |
1201 | pAC->AllocFlag |= SK_ALLOC_IRQ; | |
1202 | ||
1203 | /* Alloc memory for this board (Mem for RxD/TxD) : */ | |
1204 | if(!BoardAllocMem(pAC)) { | |
1205 | printk("No memory for descriptor rings.\n"); | |
42d1f039 | 1206 | return(-EAGAIN); |
7152b1d0 WD |
1207 | } |
1208 | ||
1209 | SkCsSetReceiveFlags(pAC, | |
1210 | SKCS_PROTO_IP | SKCS_PROTO_TCP | SKCS_PROTO_UDP, | |
1211 | &pAC->CsOfs1, &pAC->CsOfs2, 0); | |
1212 | pAC->CsOfs = (pAC->CsOfs2 << 16) | pAC->CsOfs1; | |
1213 | ||
1214 | BoardInitMem(pAC); | |
1215 | #if 0 | |
1216 | SetQueueSizes(pAC); | |
1217 | #else | |
1218 | /* tschilling: New common function with minimum size check. */ | |
1219 | DualNet = SK_FALSE; | |
1220 | if (pAC->RlmtNets == 2) { | |
1221 | DualNet = SK_TRUE; | |
1222 | } | |
42d1f039 | 1223 | |
7152b1d0 WD |
1224 | if (SkGeInitAssignRamToQueues( |
1225 | pAC, | |
1226 | pAC->ActivePort, | |
1227 | DualNet)) { | |
1228 | BoardFreeMem(pAC); | |
1229 | printk("SkGeInitAssignRamToQueues failed.\n"); | |
1230 | return(-EAGAIN); | |
1231 | } | |
1232 | #endif | |
1233 | ||
1234 | /* Print adapter specific string from vpd */ | |
1235 | ProductStr(pAC); | |
1236 | #ifdef SK98_INFO | |
1237 | printk("%s: %s\n", dev->name, pAC->DeviceStr); | |
1238 | ||
1239 | /* Print configuration settings */ | |
1240 | printk(" PrefPort:%c RlmtMode:%s\n", | |
1241 | 'A' + pAC->Rlmt.Net[0].Port[pAC->Rlmt.Net[0].PrefPort]->PortNumber, | |
1242 | (pAC->RlmtMode==0) ? "Check Link State" : | |
42d1f039 WD |
1243 | ((pAC->RlmtMode==1) ? "Check Link State" : |
1244 | ((pAC->RlmtMode==3) ? "Check Local Port" : | |
1245 | ((pAC->RlmtMode==7) ? "Check Segmentation" : | |
7152b1d0 WD |
1246 | ((pAC->RlmtMode==17) ? "Dual Check Link State" :"Error"))))); |
1247 | #endif | |
1248 | ||
1249 | SkGeYellowLED(pAC, pAC->IoBase, 1); | |
1250 | ||
1251 | /* | |
1252 | * Register the device here | |
1253 | */ | |
1254 | pAC->Next = SkGeRootDev; | |
1255 | SkGeRootDev = dev; | |
1256 | ||
1257 | return (0); | |
1258 | } /* SkGeBoardInit */ | |
1259 | ||
1260 | ||
1261 | /***************************************************************************** | |
1262 | * | |
53677ef1 | 1263 | * BoardAllocMem - allocate the memory for the descriptor rings |
7152b1d0 WD |
1264 | * |
1265 | * Description: | |
1266 | * This function allocates the memory for all descriptor rings. | |
1267 | * Each ring is aligned for the desriptor alignment and no ring | |
1268 | * has a 4 GByte boundary in it (because the upper 32 bit must | |
1269 | * be constant for all descriptiors in one rings). | |
1270 | * | |
1271 | * Returns: | |
1272 | * SK_TRUE, if all memory could be allocated | |
1273 | * SK_FALSE, if not | |
1274 | */ | |
1275 | static SK_BOOL BoardAllocMem( | |
1276 | SK_AC *pAC) | |
1277 | { | |
1278 | caddr_t pDescrMem; /* pointer to descriptor memory area */ | |
1279 | size_t AllocLength; /* length of complete descriptor area */ | |
1280 | int i; /* loop counter */ | |
1281 | unsigned long BusAddr; | |
1282 | ||
42d1f039 | 1283 | |
7152b1d0 WD |
1284 | /* rings plus one for alignment (do not cross 4 GB boundary) */ |
1285 | /* RX_RING_SIZE is assumed bigger than TX_RING_SIZE */ | |
1286 | #if (BITS_PER_LONG == 32) | |
1287 | AllocLength = (RX_RING_SIZE + TX_RING_SIZE) * pAC->GIni.GIMacsFound + 8; | |
1288 | #else | |
1289 | AllocLength = (RX_RING_SIZE + TX_RING_SIZE) * pAC->GIni.GIMacsFound | |
1290 | + RX_RING_SIZE + 8; | |
1291 | #endif | |
1292 | ||
1293 | pDescrMem = pci_alloc_consistent(pAC->PciDev, AllocLength, | |
1294 | &pAC->pDescrMemDMA); | |
1295 | ||
1296 | if (pDescrMem == NULL) { | |
1297 | return (SK_FALSE); | |
1298 | } | |
1299 | pAC->pDescrMem = pDescrMem; | |
1300 | BusAddr = (unsigned long) pAC->pDescrMemDMA; | |
1301 | ||
1302 | /* Descriptors need 8 byte alignment, and this is ensured | |
1303 | * by pci_alloc_consistent. | |
1304 | */ | |
1305 | for (i=0; i<pAC->GIni.GIMacsFound; i++) { | |
1306 | SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_TX_PROGRESS, | |
1307 | ("TX%d/A: pDescrMem: %lX, PhysDescrMem: %lX\n", | |
1308 | i, (unsigned long) pDescrMem, | |
1309 | BusAddr)); | |
1310 | pAC->TxPort[i][0].pTxDescrRing = pDescrMem; | |
1311 | pAC->TxPort[i][0].VTxDescrRing = BusAddr; | |
1312 | pDescrMem += TX_RING_SIZE; | |
1313 | BusAddr += TX_RING_SIZE; | |
42d1f039 | 1314 | |
7152b1d0 WD |
1315 | SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_TX_PROGRESS, |
1316 | ("RX%d: pDescrMem: %lX, PhysDescrMem: %lX\n", | |
1317 | i, (unsigned long) pDescrMem, | |
1318 | (unsigned long)BusAddr)); | |
1319 | pAC->RxPort[i].pRxDescrRing = pDescrMem; | |
1320 | pAC->RxPort[i].VRxDescrRing = BusAddr; | |
1321 | pDescrMem += RX_RING_SIZE; | |
1322 | BusAddr += RX_RING_SIZE; | |
1323 | } /* for */ | |
42d1f039 | 1324 | |
7152b1d0 WD |
1325 | return (SK_TRUE); |
1326 | } /* BoardAllocMem */ | |
1327 | ||
1328 | ||
1329 | /**************************************************************************** | |
1330 | * | |
1331 | * BoardFreeMem - reverse of BoardAllocMem | |
1332 | * | |
1333 | * Description: | |
1334 | * Free all memory allocated in BoardAllocMem: adapter context, | |
1335 | * descriptor rings, locks. | |
1336 | * | |
1337 | * Returns: N/A | |
1338 | */ | |
1339 | static void BoardFreeMem( | |
1340 | SK_AC *pAC) | |
1341 | { | |
1342 | size_t AllocLength; /* length of complete descriptor area */ | |
1343 | ||
1344 | SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_ENTRY, | |
1345 | ("BoardFreeMem\n")); | |
1346 | #if (BITS_PER_LONG == 32) | |
1347 | AllocLength = (RX_RING_SIZE + TX_RING_SIZE) * pAC->GIni.GIMacsFound + 8; | |
1348 | #else | |
1349 | AllocLength = (RX_RING_SIZE + TX_RING_SIZE) * pAC->GIni.GIMacsFound | |
1350 | + RX_RING_SIZE + 8; | |
1351 | #endif | |
1352 | ||
1353 | pci_free_consistent(pAC->PciDev, AllocLength, | |
1354 | pAC->pDescrMem, pAC->pDescrMemDMA); | |
1355 | pAC->pDescrMem = NULL; | |
1356 | } /* BoardFreeMem */ | |
1357 | ||
1358 | ||
1359 | /***************************************************************************** | |
1360 | * | |
53677ef1 | 1361 | * BoardInitMem - initiate the descriptor rings |
7152b1d0 WD |
1362 | * |
1363 | * Description: | |
1364 | * This function sets the descriptor rings up in memory. | |
1365 | * The adapter is initialized with the descriptor start addresses. | |
1366 | * | |
1367 | * Returns: N/A | |
1368 | */ | |
1369 | static void BoardInitMem( | |
1370 | SK_AC *pAC) /* pointer to adapter context */ | |
1371 | { | |
1372 | int i; /* loop counter */ | |
1373 | int RxDescrSize; /* the size of a rx descriptor rounded up to alignment*/ | |
1374 | int TxDescrSize; /* the size of a tx descriptor rounded up to alignment*/ | |
1375 | ||
1376 | SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_ENTRY, | |
1377 | ("BoardInitMem\n")); | |
1378 | ||
1379 | RxDescrSize = (((sizeof(RXD) - 1) / DESCR_ALIGN) + 1) * DESCR_ALIGN; | |
1380 | pAC->RxDescrPerRing = RX_RING_SIZE / RxDescrSize; | |
1381 | TxDescrSize = (((sizeof(TXD) - 1) / DESCR_ALIGN) + 1) * DESCR_ALIGN; | |
1382 | pAC->TxDescrPerRing = TX_RING_SIZE / RxDescrSize; | |
42d1f039 | 1383 | |
7152b1d0 | 1384 | for (i=0; i<pAC->GIni.GIMacsFound; i++) { |
2d6d9f08 WD |
1385 | TXD **txd_head, **txd_tail, **txd_prev; |
1386 | ||
1387 | txd_head = &pAC->TxPort[i][0].pTxdRingHead; | |
1388 | txd_tail = &pAC->TxPort[i][0].pTxdRingTail; | |
1389 | txd_prev = &pAC->TxPort[i][0].pTxdRingPrev; | |
1390 | ||
7152b1d0 WD |
1391 | SetupRing( |
1392 | pAC, | |
1393 | pAC->TxPort[i][0].pTxDescrRing, | |
1394 | pAC->TxPort[i][0].VTxDescrRing, | |
2d6d9f08 WD |
1395 | (RXD**)txd_head, |
1396 | (RXD**)txd_tail, | |
1397 | (RXD**)txd_prev, | |
7152b1d0 WD |
1398 | &pAC->TxPort[i][0].TxdRingFree, |
1399 | SK_TRUE); | |
1400 | SetupRing( | |
1401 | pAC, | |
1402 | pAC->RxPort[i].pRxDescrRing, | |
1403 | pAC->RxPort[i].VRxDescrRing, | |
1404 | &pAC->RxPort[i].pRxdRingHead, | |
1405 | &pAC->RxPort[i].pRxdRingTail, | |
1406 | &pAC->RxPort[i].pRxdRingPrev, | |
1407 | &pAC->RxPort[i].RxdRingFree, | |
1408 | SK_FALSE); | |
1409 | } | |
1410 | } /* BoardInitMem */ | |
1411 | ||
1412 | ||
1413 | /***************************************************************************** | |
1414 | * | |
53677ef1 | 1415 | * SetupRing - create one descriptor ring |
7152b1d0 WD |
1416 | * |
1417 | * Description: | |
1418 | * This function creates one descriptor ring in the given memory area. | |
1419 | * The head, tail and number of free descriptors in the ring are set. | |
1420 | * | |
1421 | * Returns: | |
1422 | * none | |
1423 | */ | |
1424 | static void SetupRing( | |
1425 | SK_AC *pAC, | |
1426 | void *pMemArea, /* a pointer to the memory area for the ring */ | |
1427 | uintptr_t VMemArea, /* the virtual bus address of the memory area */ | |
1428 | RXD **ppRingHead, /* address where the head should be written */ | |
1429 | RXD **ppRingTail, /* address where the tail should be written */ | |
1430 | RXD **ppRingPrev, /* address where the tail should be written */ | |
1431 | int *pRingFree, /* address where the # of free descr. goes */ | |
1432 | SK_BOOL IsTx) /* flag: is this a tx ring */ | |
1433 | { | |
1434 | int i; /* loop counter */ | |
1435 | int DescrSize; /* the size of a descriptor rounded up to alignment*/ | |
1436 | int DescrNum; /* number of descriptors per ring */ | |
1437 | RXD *pDescr; /* pointer to a descriptor (receive or transmit) */ | |
1438 | RXD *pNextDescr; /* pointer to the next descriptor */ | |
1439 | RXD *pPrevDescr; /* pointer to the previous descriptor */ | |
1440 | uintptr_t VNextDescr; /* the virtual bus address of the next descriptor */ | |
1441 | ||
1442 | if (IsTx == SK_TRUE) { | |
1443 | DescrSize = (((sizeof(TXD) - 1) / DESCR_ALIGN) + 1) * | |
1444 | DESCR_ALIGN; | |
1445 | DescrNum = TX_RING_SIZE / DescrSize; | |
1446 | } else { | |
1447 | DescrSize = (((sizeof(RXD) - 1) / DESCR_ALIGN) + 1) * | |
1448 | DESCR_ALIGN; | |
1449 | DescrNum = RX_RING_SIZE / DescrSize; | |
1450 | } | |
42d1f039 | 1451 | |
7152b1d0 WD |
1452 | SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_TX_PROGRESS, |
1453 | ("Descriptor size: %d Descriptor Number: %d\n", | |
1454 | DescrSize,DescrNum)); | |
42d1f039 | 1455 | |
7152b1d0 WD |
1456 | pDescr = (RXD*) pMemArea; |
1457 | pPrevDescr = NULL; | |
1458 | pNextDescr = (RXD*) (((char*)pDescr) + DescrSize); | |
1459 | VNextDescr = VMemArea + DescrSize; | |
1460 | for(i=0; i<DescrNum; i++) { | |
1461 | /* set the pointers right */ | |
1462 | pDescr->VNextRxd = VNextDescr & 0xffffffffULL; | |
1463 | pDescr->pNextRxd = pNextDescr; | |
1464 | pDescr->TcpSumStarts = pAC->CsOfs; | |
1465 | ||
1466 | /* advance one step */ | |
1467 | pPrevDescr = pDescr; | |
1468 | pDescr = pNextDescr; | |
1469 | pNextDescr = (RXD*) (((char*)pDescr) + DescrSize); | |
1470 | VNextDescr += DescrSize; | |
1471 | } | |
1472 | pPrevDescr->pNextRxd = (RXD*) pMemArea; | |
1473 | pPrevDescr->VNextRxd = VMemArea; | |
1474 | pDescr = (RXD*) pMemArea; | |
1475 | *ppRingHead = (RXD*) pMemArea; | |
1476 | *ppRingTail = *ppRingHead; | |
1477 | *ppRingPrev = pPrevDescr; | |
1478 | *pRingFree = DescrNum; | |
1479 | } /* SetupRing */ | |
1480 | ||
1481 | ||
1482 | /***************************************************************************** | |
1483 | * | |
53677ef1 | 1484 | * PortReInitBmu - re-initiate the descriptor rings for one port |
7152b1d0 WD |
1485 | * |
1486 | * Description: | |
1487 | * This function reinitializes the descriptor rings of one port | |
1488 | * in memory. The port must be stopped before. | |
1489 | * The HW is initialized with the descriptor start addresses. | |
1490 | * | |
1491 | * Returns: | |
1492 | * none | |
1493 | */ | |
1494 | static void PortReInitBmu( | |
1495 | SK_AC *pAC, /* pointer to adapter context */ | |
1496 | int PortIndex) /* index of the port for which to re-init */ | |
1497 | { | |
1498 | SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_ENTRY, | |
1499 | ("PortReInitBmu ")); | |
1500 | ||
1501 | /* set address of first descriptor of ring in BMU */ | |
1502 | SK_OUT32(pAC->IoBase, TxQueueAddr[PortIndex][TX_PRIO_LOW]+ | |
1503 | TX_Q_CUR_DESCR_LOW, | |
1504 | (uint32_t)(((caddr_t) | |
1505 | (pAC->TxPort[PortIndex][TX_PRIO_LOW].pTxdRingHead) - | |
1506 | pAC->TxPort[PortIndex][TX_PRIO_LOW].pTxDescrRing + | |
1507 | pAC->TxPort[PortIndex][TX_PRIO_LOW].VTxDescrRing) & | |
1508 | 0xFFFFFFFF)); | |
1509 | SK_OUT32(pAC->IoBase, TxQueueAddr[PortIndex][TX_PRIO_LOW]+ | |
1510 | TX_Q_DESCR_HIGH, | |
1511 | (uint32_t)(((caddr_t) | |
1512 | (pAC->TxPort[PortIndex][TX_PRIO_LOW].pTxdRingHead) - | |
1513 | pAC->TxPort[PortIndex][TX_PRIO_LOW].pTxDescrRing + | |
1514 | pAC->TxPort[PortIndex][TX_PRIO_LOW].VTxDescrRing) >> 32)); | |
1515 | SK_OUT32(pAC->IoBase, RxQueueAddr[PortIndex]+RX_Q_CUR_DESCR_LOW, | |
1516 | (uint32_t)(((caddr_t)(pAC->RxPort[PortIndex].pRxdRingHead) - | |
1517 | pAC->RxPort[PortIndex].pRxDescrRing + | |
1518 | pAC->RxPort[PortIndex].VRxDescrRing) & 0xFFFFFFFF)); | |
1519 | SK_OUT32(pAC->IoBase, RxQueueAddr[PortIndex]+RX_Q_DESCR_HIGH, | |
1520 | (uint32_t)(((caddr_t)(pAC->RxPort[PortIndex].pRxdRingHead) - | |
1521 | pAC->RxPort[PortIndex].pRxDescrRing + | |
1522 | pAC->RxPort[PortIndex].VRxDescrRing) >> 32)); | |
1523 | } /* PortReInitBmu */ | |
1524 | ||
1525 | ||
1526 | /**************************************************************************** | |
1527 | * | |
1528 | * SkGeIsr - handle adapter interrupts | |
1529 | * | |
1530 | * Description: | |
1531 | * The interrupt routine is called when the network adapter | |
1532 | * generates an interrupt. It may also be called if another device | |
1533 | * shares this interrupt vector with the driver. | |
1534 | * | |
1535 | * Returns: N/A | |
1536 | * | |
1537 | */ | |
1538 | #if 0 | |
1539 | static void SkGeIsr(int irq, void *dev_id, struct pt_regs *ptregs) | |
1540 | #else | |
1541 | void SkGeIsr(int irq, void *dev_id, struct pt_regs *ptregs) | |
1542 | #endif | |
1543 | { | |
1544 | struct SK_NET_DEVICE *dev = (struct SK_NET_DEVICE *)dev_id; | |
1545 | DEV_NET *pNet; | |
1546 | SK_AC *pAC; | |
42d1f039 | 1547 | SK_U32 IntSrc; /* interrupts source register contents */ |
7152b1d0 WD |
1548 | |
1549 | pNet = (DEV_NET*) dev->priv; | |
1550 | pAC = pNet->pAC; | |
42d1f039 | 1551 | |
7152b1d0 WD |
1552 | /* |
1553 | * Check and process if its our interrupt | |
1554 | */ | |
1555 | SK_IN32(pAC->IoBase, B0_SP_ISRC, &IntSrc); | |
1556 | if (IntSrc == 0) { | |
1557 | return; | |
1558 | } | |
1559 | ||
1560 | while (((IntSrc & IRQ_MASK) & ~SPECIAL_IRQS) != 0) { | |
1561 | #if 0 /* software irq currently not used */ | |
1562 | if (IntSrc & IRQ_SW) { | |
1563 | SK_DBG_MSG(NULL, SK_DBGMOD_DRV, | |
1564 | SK_DBGCAT_DRV_INT_SRC, | |
1565 | ("Software IRQ\n")); | |
1566 | } | |
1567 | #endif | |
1568 | if (IntSrc & IRQ_EOF_RX1) { | |
1569 | SK_DBG_MSG(NULL, SK_DBGMOD_DRV, | |
1570 | SK_DBGCAT_DRV_INT_SRC, | |
1571 | ("EOF RX1 IRQ\n")); | |
1572 | ReceiveIrq(pAC, &pAC->RxPort[0], SK_TRUE); | |
1573 | SK_PNMI_CNT_RX_INTR(pAC, 0); | |
1574 | } | |
1575 | if (IntSrc & IRQ_EOF_RX2) { | |
1576 | SK_DBG_MSG(NULL, SK_DBGMOD_DRV, | |
1577 | SK_DBGCAT_DRV_INT_SRC, | |
1578 | ("EOF RX2 IRQ\n")); | |
1579 | ReceiveIrq(pAC, &pAC->RxPort[1], SK_TRUE); | |
1580 | SK_PNMI_CNT_RX_INTR(pAC, 1); | |
1581 | } | |
1582 | #ifdef USE_TX_COMPLETE /* only if tx complete interrupt used */ | |
1583 | if (IntSrc & IRQ_EOF_AS_TX1) { | |
1584 | SK_DBG_MSG(NULL, SK_DBGMOD_DRV, | |
1585 | SK_DBGCAT_DRV_INT_SRC, | |
1586 | ("EOF AS TX1 IRQ\n")); | |
1587 | SK_PNMI_CNT_TX_INTR(pAC, 0); | |
1588 | spin_lock(&pAC->TxPort[0][TX_PRIO_LOW].TxDesRingLock); | |
1589 | FreeTxDescriptors(pAC, &pAC->TxPort[0][TX_PRIO_LOW]); | |
1590 | spin_unlock(&pAC->TxPort[0][TX_PRIO_LOW].TxDesRingLock); | |
1591 | } | |
1592 | if (IntSrc & IRQ_EOF_AS_TX2) { | |
1593 | SK_DBG_MSG(NULL, SK_DBGMOD_DRV, | |
1594 | SK_DBGCAT_DRV_INT_SRC, | |
1595 | ("EOF AS TX2 IRQ\n")); | |
1596 | SK_PNMI_CNT_TX_INTR(pAC, 1); | |
1597 | spin_lock(&pAC->TxPort[1][TX_PRIO_LOW].TxDesRingLock); | |
1598 | FreeTxDescriptors(pAC, &pAC->TxPort[1][TX_PRIO_LOW]); | |
1599 | spin_unlock(&pAC->TxPort[1][TX_PRIO_LOW].TxDesRingLock); | |
1600 | } | |
1601 | #if 0 /* only if sync. queues used */ | |
1602 | if (IntSrc & IRQ_EOF_SY_TX1) { | |
1603 | SK_DBG_MSG(NULL, SK_DBGMOD_DRV, | |
1604 | SK_DBGCAT_DRV_INT_SRC, | |
1605 | ("EOF SY TX1 IRQ\n")); | |
1606 | SK_PNMI_CNT_TX_INTR(pAC, 1); | |
1607 | spin_lock(&pAC->TxPort[0][TX_PRIO_HIGH].TxDesRingLock); | |
1608 | FreeTxDescriptors(pAC, 0, TX_PRIO_HIGH); | |
1609 | spin_unlock(&pAC->TxPort[0][TX_PRIO_HIGH].TxDesRingLock); | |
1610 | ClearTxIrq(pAC, 0, TX_PRIO_HIGH); | |
1611 | } | |
1612 | if (IntSrc & IRQ_EOF_SY_TX2) { | |
1613 | SK_DBG_MSG(NULL, SK_DBGMOD_DRV, | |
1614 | SK_DBGCAT_DRV_INT_SRC, | |
1615 | ("EOF SY TX2 IRQ\n")); | |
1616 | SK_PNMI_CNT_TX_INTR(pAC, 1); | |
1617 | spin_lock(&pAC->TxPort[1][TX_PRIO_HIGH].TxDesRingLock); | |
1618 | FreeTxDescriptors(pAC, 1, TX_PRIO_HIGH); | |
1619 | spin_unlock(&pAC->TxPort[1][TX_PRIO_HIGH].TxDesRingLock); | |
1620 | ClearTxIrq(pAC, 1, TX_PRIO_HIGH); | |
1621 | } | |
1622 | #endif | |
1623 | #endif | |
1624 | ||
1625 | /* do all IO at once */ | |
1626 | if (IntSrc & IRQ_EOF_RX1) | |
1627 | ClearAndStartRx(pAC, 0); | |
1628 | if (IntSrc & IRQ_EOF_RX2) | |
1629 | ClearAndStartRx(pAC, 1); | |
1630 | #ifdef USE_TX_COMPLETE /* only if tx complete interrupt used */ | |
1631 | if (IntSrc & IRQ_EOF_AS_TX1) | |
1632 | ClearTxIrq(pAC, 0, TX_PRIO_LOW); | |
1633 | if (IntSrc & IRQ_EOF_AS_TX2) | |
1634 | ClearTxIrq(pAC, 1, TX_PRIO_LOW); | |
1635 | #endif | |
1636 | SK_IN32(pAC->IoBase, B0_ISRC, &IntSrc); | |
1637 | } /* while (IntSrc & IRQ_MASK != 0) */ | |
1638 | ||
1639 | if ((IntSrc & SPECIAL_IRQS) || pAC->CheckQueue) { | |
1640 | SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_INT_SRC, | |
1641 | ("SPECIAL IRQ DP-Cards => %x\n", IntSrc)); | |
1642 | pAC->CheckQueue = SK_FALSE; | |
1643 | spin_lock(&pAC->SlowPathLock); | |
1644 | if (IntSrc & SPECIAL_IRQS) | |
1645 | SkGeSirqIsr(pAC, pAC->IoBase, IntSrc); | |
1646 | ||
1647 | SkEventDispatcher(pAC, pAC->IoBase); | |
1648 | spin_unlock(&pAC->SlowPathLock); | |
1649 | } | |
1650 | /* | |
42d1f039 | 1651 | * do it all again is case we cleared an interrupt that |
7152b1d0 WD |
1652 | * came in after handling the ring (OUTs may be delayed |
1653 | * in hardware buffers, but are through after IN) | |
1654 | */ | |
1655 | ||
1656 | ReceiveIrq(pAC, &pAC->RxPort[0], SK_TRUE); | |
1657 | ReceiveIrq(pAC, &pAC->RxPort[1], SK_TRUE); | |
1658 | ||
1659 | if (pAC->CheckQueue) { | |
1660 | pAC->CheckQueue = SK_FALSE; | |
1661 | spin_lock(&pAC->SlowPathLock); | |
1662 | SkEventDispatcher(pAC, pAC->IoBase); | |
1663 | spin_unlock(&pAC->SlowPathLock); | |
1664 | } | |
1665 | ||
1666 | ||
1667 | /* IRQ is processed - Enable IRQs again*/ | |
1668 | SK_OUT32(pAC->IoBase, B0_IMSK, IRQ_MASK); | |
1669 | ||
1670 | return; | |
1671 | } /* SkGeIsr */ | |
1672 | ||
1673 | ||
1674 | /**************************************************************************** | |
1675 | * | |
1676 | * SkGeIsrOnePort - handle adapter interrupts for single port adapter | |
1677 | * | |
1678 | * Description: | |
1679 | * The interrupt routine is called when the network adapter | |
1680 | * generates an interrupt. It may also be called if another device | |
1681 | * shares this interrupt vector with the driver. | |
1682 | * This is the same as above, but handles only one port. | |
1683 | * | |
1684 | * Returns: N/A | |
1685 | * | |
1686 | */ | |
1687 | #if 0 | |
1688 | static void SkGeIsrOnePort(int irq, void *dev_id, struct pt_regs *ptregs) | |
1689 | #else | |
1690 | void SkGeIsrOnePort(int irq, void *dev_id, struct pt_regs *ptregs) | |
1691 | #endif | |
1692 | { | |
1693 | struct SK_NET_DEVICE *dev = (struct SK_NET_DEVICE *)dev_id; | |
1694 | DEV_NET *pNet; | |
1695 | SK_AC *pAC; | |
42d1f039 | 1696 | SK_U32 IntSrc; /* interrupts source register contents */ |
7152b1d0 WD |
1697 | |
1698 | pNet = (DEV_NET*) dev->priv; | |
1699 | pAC = pNet->pAC; | |
42d1f039 | 1700 | |
7152b1d0 WD |
1701 | /* |
1702 | * Check and process if its our interrupt | |
1703 | */ | |
1704 | SK_IN32(pAC->IoBase, B0_SP_ISRC, &IntSrc); | |
1705 | if (IntSrc == 0) { | |
1706 | return; | |
1707 | } | |
42d1f039 | 1708 | |
7152b1d0 WD |
1709 | while (((IntSrc & IRQ_MASK) & ~SPECIAL_IRQS) != 0) { |
1710 | #if 0 /* software irq currently not used */ | |
1711 | if (IntSrc & IRQ_SW) { | |
1712 | SK_DBG_MSG(NULL, SK_DBGMOD_DRV, | |
1713 | SK_DBGCAT_DRV_INT_SRC, | |
1714 | ("Software IRQ\n")); | |
1715 | } | |
1716 | #endif | |
1717 | if (IntSrc & IRQ_EOF_RX1) { | |
1718 | SK_DBG_MSG(NULL, SK_DBGMOD_DRV, | |
1719 | SK_DBGCAT_DRV_INT_SRC, | |
1720 | ("EOF RX1 IRQ\n")); | |
1721 | ReceiveIrq(pAC, &pAC->RxPort[0], SK_TRUE); | |
1722 | SK_PNMI_CNT_RX_INTR(pAC, 0); | |
1723 | } | |
1724 | #ifdef USE_TX_COMPLETE /* only if tx complete interrupt used */ | |
1725 | if (IntSrc & IRQ_EOF_AS_TX1) { | |
1726 | SK_DBG_MSG(NULL, SK_DBGMOD_DRV, | |
1727 | SK_DBGCAT_DRV_INT_SRC, | |
1728 | ("EOF AS TX1 IRQ\n")); | |
1729 | SK_PNMI_CNT_TX_INTR(pAC, 0); | |
1730 | spin_lock(&pAC->TxPort[0][TX_PRIO_LOW].TxDesRingLock); | |
1731 | FreeTxDescriptors(pAC, &pAC->TxPort[0][TX_PRIO_LOW]); | |
1732 | spin_unlock(&pAC->TxPort[0][TX_PRIO_LOW].TxDesRingLock); | |
1733 | } | |
1734 | #if 0 /* only if sync. queues used */ | |
1735 | if (IntSrc & IRQ_EOF_SY_TX1) { | |
1736 | SK_DBG_MSG(NULL, SK_DBGMOD_DRV, | |
1737 | SK_DBGCAT_DRV_INT_SRC, | |
1738 | ("EOF SY TX1 IRQ\n")); | |
1739 | SK_PNMI_CNT_TX_INTR(pAC, 0); | |
1740 | spin_lock(&pAC->TxPort[0][TX_PRIO_HIGH].TxDesRingLock); | |
1741 | FreeTxDescriptors(pAC, 0, TX_PRIO_HIGH); | |
1742 | spin_unlock(&pAC->TxPort[0][TX_PRIO_HIGH].TxDesRingLock); | |
1743 | ClearTxIrq(pAC, 0, TX_PRIO_HIGH); | |
1744 | } | |
1745 | #endif | |
1746 | #endif | |
1747 | ||
1748 | /* do all IO at once */ | |
1749 | if (IntSrc & IRQ_EOF_RX1) | |
1750 | ClearAndStartRx(pAC, 0); | |
1751 | #ifdef USE_TX_COMPLETE /* only if tx complete interrupt used */ | |
1752 | if (IntSrc & IRQ_EOF_AS_TX1) | |
1753 | ClearTxIrq(pAC, 0, TX_PRIO_LOW); | |
1754 | #endif | |
1755 | SK_IN32(pAC->IoBase, B0_ISRC, &IntSrc); | |
1756 | } /* while (IntSrc & IRQ_MASK != 0) */ | |
42d1f039 | 1757 | |
7152b1d0 WD |
1758 | if ((IntSrc & SPECIAL_IRQS) || pAC->CheckQueue) { |
1759 | SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_INT_SRC, | |
1760 | ("SPECIAL IRQ SP-Cards => %x\n", IntSrc)); | |
1761 | pAC->CheckQueue = SK_FALSE; | |
1762 | spin_lock(&pAC->SlowPathLock); | |
1763 | if (IntSrc & SPECIAL_IRQS) | |
1764 | SkGeSirqIsr(pAC, pAC->IoBase, IntSrc); | |
1765 | ||
1766 | SkEventDispatcher(pAC, pAC->IoBase); | |
1767 | spin_unlock(&pAC->SlowPathLock); | |
1768 | } | |
1769 | /* | |
42d1f039 | 1770 | * do it all again is case we cleared an interrupt that |
7152b1d0 WD |
1771 | * came in after handling the ring (OUTs may be delayed |
1772 | * in hardware buffers, but are through after IN) | |
1773 | */ | |
1774 | ReceiveIrq(pAC, &pAC->RxPort[0], SK_TRUE); | |
1775 | ||
1776 | /* IRQ is processed - Enable IRQs again*/ | |
1777 | SK_OUT32(pAC->IoBase, B0_IMSK, IRQ_MASK); | |
1778 | ||
1779 | return; | |
1780 | } /* SkGeIsrOnePort */ | |
1781 | ||
1782 | ||
1783 | /**************************************************************************** | |
1784 | * | |
1785 | * SkGeOpen - handle start of initialized adapter | |
1786 | * | |
1787 | * Description: | |
1788 | * This function starts the initialized adapter. | |
1789 | * The board level variable is set and the adapter is | |
1790 | * brought to full functionality. | |
1791 | * The device flags are set for operation. | |
1792 | * Do all necessary level 2 initialization, enable interrupts and | |
1793 | * give start command to RLMT. | |
1794 | * | |
1795 | * Returns: | |
1796 | * 0 on success | |
1797 | * != 0 on error | |
1798 | */ | |
1799 | #if 0 | |
1800 | static int SkGeOpen( | |
1801 | #else | |
1802 | int SkGeOpen( | |
1803 | #endif | |
1804 | struct SK_NET_DEVICE *dev) | |
1805 | { | |
1806 | DEV_NET *pNet; | |
1807 | SK_AC *pAC; | |
1808 | unsigned long Flags; /* for spin lock */ | |
1809 | int i; | |
1810 | SK_EVPARA EvPara; /* an event parameter union */ | |
1811 | ||
1812 | pNet = (DEV_NET*) dev->priv; | |
1813 | pAC = pNet->pAC; | |
42d1f039 | 1814 | |
7152b1d0 WD |
1815 | SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_ENTRY, |
1816 | ("SkGeOpen: pAC=0x%lX:\n", (unsigned long)pAC)); | |
1817 | ||
1818 | if (pAC->BoardLevel == 0) { | |
1819 | /* level 1 init common modules here */ | |
1820 | if (SkGeInit(pAC, pAC->IoBase, 1) != 0) { | |
1821 | printk("%s: HWInit (1) failed.\n", pAC->dev[pNet->PortNr]->name); | |
1822 | return (-1); | |
1823 | } | |
1824 | SkI2cInit (pAC, pAC->IoBase, 1); | |
1825 | SkEventInit (pAC, pAC->IoBase, 1); | |
1826 | SkPnmiInit (pAC, pAC->IoBase, 1); | |
1827 | SkAddrInit (pAC, pAC->IoBase, 1); | |
1828 | SkRlmtInit (pAC, pAC->IoBase, 1); | |
1829 | SkTimerInit (pAC, pAC->IoBase, 1); | |
1830 | pAC->BoardLevel = 1; | |
1831 | } | |
1832 | ||
1833 | if (pAC->BoardLevel != 2) { | |
1834 | /* tschilling: Level 2 init modules here, check return value. */ | |
1835 | if (SkGeInit(pAC, pAC->IoBase, 2) != 0) { | |
1836 | printk("%s: HWInit (2) failed.\n", pAC->dev[pNet->PortNr]->name); | |
1837 | return (-1); | |
1838 | } | |
1839 | SkI2cInit (pAC, pAC->IoBase, 2); | |
1840 | SkEventInit (pAC, pAC->IoBase, 2); | |
1841 | SkPnmiInit (pAC, pAC->IoBase, 2); | |
1842 | SkAddrInit (pAC, pAC->IoBase, 2); | |
1843 | SkRlmtInit (pAC, pAC->IoBase, 2); | |
1844 | SkTimerInit (pAC, pAC->IoBase, 2); | |
1845 | pAC->BoardLevel = 2; | |
1846 | } | |
1847 | ||
1848 | for (i=0; i<pAC->GIni.GIMacsFound; i++) { | |
1849 | /* Enable transmit descriptor polling. */ | |
1850 | SkGePollTxD(pAC, pAC->IoBase, i, SK_TRUE); | |
1851 | FillRxRing(pAC, &pAC->RxPort[i]); | |
1852 | } | |
1853 | SkGeYellowLED(pAC, pAC->IoBase, 1); | |
1854 | ||
1855 | #ifdef USE_INT_MOD | |
1856 | /* moderate only TX complete interrupts (these are not time critical) */ | |
1857 | #define IRQ_MOD_MASK (IRQ_EOF_AS_TX1 | IRQ_EOF_AS_TX2) | |
1858 | { | |
1859 | unsigned long ModBase; | |
1860 | ModBase = 53125000 / INTS_PER_SEC; | |
1861 | SK_OUT32(pAC->IoBase, B2_IRQM_INI, ModBase); | |
1862 | SK_OUT32(pAC->IoBase, B2_IRQM_MSK, IRQ_MOD_MASK); | |
1863 | SK_OUT32(pAC->IoBase, B2_IRQM_CTRL, TIM_START); | |
1864 | } | |
1865 | #endif | |
1866 | ||
1867 | /* enable Interrupts */ | |
1868 | SK_OUT32(pAC->IoBase, B0_IMSK, IRQ_MASK); | |
1869 | SK_OUT32(pAC->IoBase, B0_HWE_IMSK, IRQ_HWE_MASK); | |
1870 | ||
1871 | spin_lock_irqsave(&pAC->SlowPathLock, Flags); | |
1872 | ||
1873 | if ((pAC->RlmtMode != 0) && (pAC->MaxPorts == 0)) { | |
1874 | EvPara.Para32[0] = pAC->RlmtNets; | |
1875 | EvPara.Para32[1] = -1; | |
1876 | SkEventQueue(pAC, SKGE_RLMT, SK_RLMT_SET_NETS, | |
1877 | EvPara); | |
1878 | EvPara.Para32[0] = pAC->RlmtMode; | |
1879 | EvPara.Para32[1] = 0; | |
1880 | SkEventQueue(pAC, SKGE_RLMT, SK_RLMT_MODE_CHANGE, | |
1881 | EvPara); | |
1882 | } | |
1883 | ||
1884 | EvPara.Para32[0] = pNet->NetNr; | |
1885 | EvPara.Para32[1] = -1; | |
1886 | SkEventQueue(pAC, SKGE_RLMT, SK_RLMT_START, EvPara); | |
1887 | SkEventDispatcher(pAC, pAC->IoBase); | |
1888 | spin_unlock_irqrestore(&pAC->SlowPathLock, Flags); | |
1889 | ||
1890 | pAC->MaxPorts++; | |
1891 | pNet->Up = 1; | |
1892 | ||
1893 | MOD_INC_USE_COUNT; | |
1894 | ||
1895 | SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_ENTRY, | |
1896 | ("SkGeOpen suceeded\n")); | |
1897 | ||
1898 | return (0); | |
1899 | } /* SkGeOpen */ | |
1900 | ||
1901 | ||
1902 | /**************************************************************************** | |
1903 | * | |
1904 | * SkGeClose - Stop initialized adapter | |
1905 | * | |
1906 | * Description: | |
1907 | * Close initialized adapter. | |
1908 | * | |
1909 | * Returns: | |
1910 | * 0 - on success | |
1911 | * error code - on error | |
1912 | */ | |
1913 | #if 0 | |
1914 | static int SkGeClose( | |
1915 | #else | |
1916 | int SkGeClose( | |
1917 | #endif | |
1918 | struct SK_NET_DEVICE *dev) | |
1919 | { | |
1920 | DEV_NET *pNet; | |
1921 | SK_AC *pAC; | |
1922 | ||
1923 | unsigned long Flags; /* for spin lock */ | |
1924 | int i; | |
1925 | int PortIdx; | |
1926 | SK_EVPARA EvPara; | |
1927 | ||
1928 | netif_stop_queue(dev); | |
1929 | pNet = (DEV_NET*) dev->priv; | |
1930 | pAC = pNet->pAC; | |
1931 | ||
1932 | if (pAC->RlmtNets == 1) | |
1933 | PortIdx = pAC->ActivePort; | |
1934 | else | |
1935 | PortIdx = pNet->NetNr; | |
1936 | ||
1937 | SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_ENTRY, | |
1938 | ("SkGeClose: pAC=0x%lX ", (unsigned long)pAC)); | |
1939 | ||
42d1f039 | 1940 | /* |
7152b1d0 WD |
1941 | * Clear multicast table, promiscuous mode .... |
1942 | */ | |
1943 | SkAddrMcClear(pAC, pAC->IoBase, PortIdx, 0); | |
1944 | SkAddrPromiscuousChange(pAC, pAC->IoBase, PortIdx, | |
1945 | SK_PROM_MODE_NONE); | |
1946 | ||
1947 | if (pAC->MaxPorts == 1) { | |
1948 | spin_lock_irqsave(&pAC->SlowPathLock, Flags); | |
1949 | /* disable interrupts */ | |
1950 | SK_OUT32(pAC->IoBase, B0_IMSK, 0); | |
1951 | EvPara.Para32[0] = pNet->NetNr; | |
1952 | EvPara.Para32[1] = -1; | |
1953 | SkEventQueue(pAC, SKGE_RLMT, SK_RLMT_STOP, EvPara); | |
1954 | SkEventDispatcher(pAC, pAC->IoBase); | |
1955 | SK_OUT32(pAC->IoBase, B0_IMSK, 0); | |
1956 | /* stop the hardware */ | |
1957 | SkGeDeInit(pAC, pAC->IoBase); | |
1958 | pAC->BoardLevel = 0; | |
1959 | spin_unlock_irqrestore(&pAC->SlowPathLock, Flags); | |
1960 | } else { | |
1961 | ||
1962 | spin_lock_irqsave(&pAC->SlowPathLock, Flags); | |
1963 | EvPara.Para32[0] = pNet->NetNr; | |
1964 | EvPara.Para32[1] = -1; | |
1965 | SkEventQueue(pAC, SKGE_RLMT, SK_RLMT_STOP, EvPara); | |
1966 | SkEventDispatcher(pAC, pAC->IoBase); | |
1967 | spin_unlock_irqrestore(&pAC->SlowPathLock, Flags); | |
42d1f039 | 1968 | |
7152b1d0 WD |
1969 | /* Stop port */ |
1970 | spin_lock_irqsave(&pAC->TxPort[pNet->PortNr] | |
1971 | [TX_PRIO_LOW].TxDesRingLock, Flags); | |
42d1f039 | 1972 | SkGeStopPort(pAC, pAC->IoBase, pNet->PortNr, |
7152b1d0 WD |
1973 | SK_STOP_ALL, SK_HARD_RST); |
1974 | spin_unlock_irqrestore(&pAC->TxPort[pNet->PortNr] | |
1975 | [TX_PRIO_LOW].TxDesRingLock, Flags); | |
1976 | } | |
1977 | ||
1978 | if (pAC->RlmtNets == 1) { | |
1979 | /* clear all descriptor rings */ | |
1980 | for (i=0; i<pAC->GIni.GIMacsFound; i++) { | |
1981 | ReceiveIrq(pAC, &pAC->RxPort[i], SK_TRUE); | |
1982 | ClearRxRing(pAC, &pAC->RxPort[i]); | |
1983 | ClearTxRing(pAC, &pAC->TxPort[i][TX_PRIO_LOW]); | |
1984 | } | |
1985 | } else { | |
1986 | /* clear port descriptor rings */ | |
1987 | ReceiveIrq(pAC, &pAC->RxPort[pNet->PortNr], SK_TRUE); | |
1988 | ClearRxRing(pAC, &pAC->RxPort[pNet->PortNr]); | |
1989 | ClearTxRing(pAC, &pAC->TxPort[pNet->PortNr][TX_PRIO_LOW]); | |
1990 | } | |
1991 | ||
1992 | SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_ENTRY, | |
1993 | ("SkGeClose: done ")); | |
1994 | ||
1995 | pAC->MaxPorts--; | |
1996 | pNet->Up = 0; | |
1997 | MOD_DEC_USE_COUNT; | |
42d1f039 | 1998 | |
7152b1d0 WD |
1999 | return (0); |
2000 | } /* SkGeClose */ | |
2001 | ||
2002 | ||
2003 | /***************************************************************************** | |
2004 | * | |
53677ef1 | 2005 | * SkGeXmit - Linux frame transmit function |
7152b1d0 WD |
2006 | * |
2007 | * Description: | |
2008 | * The system calls this function to send frames onto the wire. | |
2009 | * It puts the frame in the tx descriptor ring. If the ring is | |
2010 | * full then, the 'tbusy' flag is set. | |
2011 | * | |
2012 | * Returns: | |
2013 | * 0, if everything is ok | |
2014 | * !=0, on error | |
2015 | * WARNING: returning 1 in 'tbusy' case caused system crashes (double | |
2016 | * allocated skb's) !!! | |
2017 | */ | |
2018 | #if 0 | |
2019 | static int SkGeXmit(struct sk_buff *skb, struct SK_NET_DEVICE *dev) | |
2020 | #else | |
2021 | int SkGeXmit(struct sk_buff *skb, struct SK_NET_DEVICE *dev) | |
2022 | #endif | |
2023 | { | |
2024 | DEV_NET *pNet; | |
2025 | SK_AC *pAC; | |
2026 | int Rc; /* return code of XmitFrame */ | |
2027 | ||
2028 | pNet = (DEV_NET*) dev->priv; | |
2029 | pAC = pNet->pAC; | |
2030 | ||
2031 | #if 0 | |
42d1f039 | 2032 | if ((!skb_shinfo(skb)->nr_frags) || |
7152b1d0 WD |
2033 | #else |
2034 | if (1 || | |
2035 | #endif | |
2036 | (pAC->GIni.GIChipId == CHIP_ID_GENESIS)) { | |
2037 | /* Don't activate scatter-gather and hardware checksum */ | |
2038 | ||
2039 | if (pAC->RlmtNets == 2) | |
2040 | Rc = XmitFrame( | |
2041 | pAC, | |
2042 | &pAC->TxPort[pNet->PortNr][TX_PRIO_LOW], | |
2043 | skb); | |
2044 | else | |
2045 | Rc = XmitFrame( | |
2046 | pAC, | |
2047 | &pAC->TxPort[pAC->ActivePort][TX_PRIO_LOW], | |
2048 | skb); | |
2049 | } else { | |
2050 | #if 0 | |
2051 | /* scatter-gather and hardware TCP checksumming anabled*/ | |
2052 | if (pAC->RlmtNets == 2) | |
2053 | Rc = XmitFrameSG( | |
2054 | pAC, | |
2055 | &pAC->TxPort[pNet->PortNr][TX_PRIO_LOW], | |
2056 | skb); | |
2057 | else | |
2058 | Rc = XmitFrameSG( | |
2059 | pAC, | |
2060 | &pAC->TxPort[pAC->ActivePort][TX_PRIO_LOW], | |
2061 | skb); | |
2062 | #endif | |
2063 | } | |
2064 | ||
2065 | /* Transmitter out of resources? */ | |
2066 | if (Rc <= 0) { | |
2067 | netif_stop_queue(dev); | |
2068 | } | |
2069 | ||
2070 | /* If not taken, give buffer ownership back to the | |
2071 | * queueing layer. | |
2072 | */ | |
2073 | if (Rc < 0) | |
2074 | return (1); | |
2075 | ||
2076 | #if 0 | |
2077 | dev->trans_start = jiffies; | |
2078 | #endif | |
2079 | return (0); | |
2080 | } /* SkGeXmit */ | |
2081 | ||
2082 | ||
2083 | /***************************************************************************** | |
2084 | * | |
53677ef1 | 2085 | * XmitFrame - fill one socket buffer into the transmit ring |
7152b1d0 WD |
2086 | * |
2087 | * Description: | |
2088 | * This function puts a message into the transmit descriptor ring | |
2089 | * if there is a descriptors left. | |
2090 | * Linux skb's consist of only one continuous buffer. | |
2091 | * The first step locks the ring. It is held locked | |
2092 | * all time to avoid problems with SWITCH_../PORT_RESET. | |
2093 | * Then the descriptoris allocated. | |
2094 | * The second part is linking the buffer to the descriptor. | |
2095 | * At the very last, the Control field of the descriptor | |
2096 | * is made valid for the BMU and a start TX command is given | |
2097 | * if necessary. | |
2098 | * | |
2099 | * Returns: | |
2100 | * > 0 - on succes: the number of bytes in the message | |
2101 | * = 0 - on resource shortage: this frame sent or dropped, now | |
2102 | * the ring is full ( -> set tbusy) | |
2103 | * < 0 - on failure: other problems ( -> return failure to upper layers) | |
2104 | */ | |
2105 | static int XmitFrame( | |
53677ef1 | 2106 | SK_AC *pAC, /* pointer to adapter context */ |
7152b1d0 WD |
2107 | TX_PORT *pTxPort, /* pointer to struct of port to send to */ |
2108 | struct sk_buff *pMessage) /* pointer to send-message */ | |
2109 | { | |
2110 | TXD *pTxd; /* the rxd to fill */ | |
2111 | unsigned long Flags; | |
2112 | SK_U64 PhysAddr; | |
2113 | int BytesSend; | |
2114 | ||
2115 | SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_TX_PROGRESS, | |
2116 | ("X")); | |
2117 | ||
2118 | spin_lock_irqsave(&pTxPort->TxDesRingLock, Flags); | |
2119 | #ifndef USE_TX_COMPLETE | |
2120 | FreeTxDescriptors(pAC, pTxPort); | |
2121 | #endif | |
2122 | if (pTxPort->TxdRingFree == 0) { | |
2123 | /* no enough free descriptors in ring at the moment */ | |
2124 | FreeTxDescriptors(pAC, pTxPort); | |
2125 | if (pTxPort->TxdRingFree == 0) { | |
2126 | spin_unlock_irqrestore(&pTxPort->TxDesRingLock, Flags); | |
2127 | SK_PNMI_CNT_NO_TX_BUF(pAC, pTxPort->PortIndex); | |
2128 | SK_DBG_MSG(NULL, SK_DBGMOD_DRV, | |
2129 | SK_DBGCAT_DRV_TX_PROGRESS, | |
2130 | ("XmitFrame failed\n")); | |
2131 | /* this message can not be sent now */ | |
2132 | /* Because tbusy seems to be set, the message should not be freed here */ | |
2133 | /* It will be used by the scheduler of the ethernet handler */ | |
2134 | return (-1); | |
2135 | } | |
2136 | } | |
2137 | /* advance head counter behind descriptor needed for this frame */ | |
2138 | pTxd = pTxPort->pTxdRingHead; | |
2139 | pTxPort->pTxdRingHead = pTxd->pNextTxd; | |
2140 | pTxPort->TxdRingFree--; | |
2141 | /* the needed descriptor is reserved now */ | |
42d1f039 WD |
2142 | |
2143 | /* | |
7152b1d0 WD |
2144 | * everything allocated ok, so add buffer to descriptor |
2145 | */ | |
2146 | ||
2147 | #ifdef SK_DUMP_TX | |
2148 | DumpMsg(pMessage, "XmitFrame"); | |
2149 | #endif | |
2150 | ||
2151 | /* set up descriptor and CONTROL dword */ | |
2152 | #if 0 | |
2153 | PhysAddr = (SK_U64) pci_map_page(pAC->PciDev, | |
2154 | virt_to_page(pMessage->data), | |
2155 | ((unsigned long) pMessage->data & | |
2156 | ~PAGE_MASK), | |
2157 | pMessage->len, | |
2158 | PCI_DMA_TODEVICE); | |
2159 | #else | |
2160 | PhysAddr = (SK_U64) pci_phys_to_mem(pAC->PciDev, (u32) pMessage->data); | |
2161 | #endif | |
2162 | pTxd->VDataLow = (SK_U32) (PhysAddr & 0xffffffff); | |
2163 | pTxd->VDataHigh = (SK_U32) (PhysAddr >> 32); | |
2164 | pTxd->pMBuf = pMessage; | |
2165 | pTxd->TBControl = TX_CTRL_OWN_BMU | TX_CTRL_STF | | |
2166 | TX_CTRL_CHECK_DEFAULT | TX_CTRL_SOFTWARE | | |
2167 | #ifdef USE_TX_COMPLETE | |
2168 | TX_CTRL_EOF | TX_CTRL_EOF_IRQ | pMessage->len; | |
2169 | #else | |
2170 | TX_CTRL_EOF | pMessage->len; | |
2171 | #endif | |
42d1f039 | 2172 | |
7152b1d0 WD |
2173 | if ((pTxPort->pTxdRingPrev->TBControl & TX_CTRL_OWN_BMU) == 0) { |
2174 | /* previous descriptor already done, so give tx start cmd */ | |
2175 | /* StartTx(pAC, pTxPort->HwAddr); */ | |
2176 | SK_OUT8(pTxPort->HwAddr, TX_Q_CTRL, TX_Q_CTRL_START); | |
2177 | } | |
2178 | pTxPort->pTxdRingPrev = pTxd; | |
42d1f039 WD |
2179 | |
2180 | ||
7152b1d0 WD |
2181 | BytesSend = pMessage->len; |
2182 | spin_unlock_irqrestore(&pTxPort->TxDesRingLock, Flags); | |
2183 | /* after releasing the lock, the skb may be immidiately freed */ | |
2184 | if (pTxPort->TxdRingFree != 0) | |
2185 | return (BytesSend); | |
2186 | else | |
2187 | return (0); | |
2188 | ||
2189 | } /* XmitFrame */ | |
2190 | ||
2191 | /***************************************************************************** | |
2192 | * | |
53677ef1 | 2193 | * XmitFrameSG - fill one socket buffer into the transmit ring |
7152b1d0 WD |
2194 | * (use SG and TCP/UDP hardware checksumming) |
2195 | * | |
2196 | * Description: | |
2197 | * This function puts a message into the transmit descriptor ring | |
2198 | * if there is a descriptors left. | |
2199 | * | |
2200 | * Returns: | |
2201 | * > 0 - on succes: the number of bytes in the message | |
2202 | * = 0 - on resource shortage: this frame sent or dropped, now | |
2203 | * the ring is full ( -> set tbusy) | |
2204 | * < 0 - on failure: other problems ( -> return failure to upper layers) | |
2205 | */ | |
2206 | #if 0 | |
2207 | static int XmitFrameSG( | |
53677ef1 | 2208 | SK_AC *pAC, /* pointer to adapter context */ |
7152b1d0 WD |
2209 | TX_PORT *pTxPort, /* pointer to struct of port to send to */ |
2210 | struct sk_buff *pMessage) /* pointer to send-message */ | |
2211 | { | |
2212 | ||
53677ef1 | 2213 | int i; |
7152b1d0 WD |
2214 | int BytesSend; |
2215 | int hlength; | |
2216 | int protocol; | |
2217 | skb_frag_t *sk_frag; | |
2218 | TXD *pTxd; | |
2219 | TXD *pTxdFst; | |
2220 | TXD *pTxdLst; | |
2221 | SK_U64 PhysAddr; | |
2222 | unsigned long Flags; | |
2223 | ||
2224 | spin_lock_irqsave(&pTxPort->TxDesRingLock, Flags); | |
2225 | #ifndef USE_TX_COMPLETE | |
2226 | FreeTxDescriptors(pAC, pTxPort); | |
2227 | #endif | |
2228 | if ((skb_shinfo(pMessage)->nr_frags +1) > pTxPort->TxdRingFree) { | |
2229 | FreeTxDescriptors(pAC, pTxPort); | |
2230 | if ((skb_shinfo(pMessage)->nr_frags + 1) > pTxPort->TxdRingFree) { | |
2231 | spin_unlock_irqrestore(&pTxPort->TxDesRingLock, Flags); | |
2232 | SK_PNMI_CNT_NO_TX_BUF(pAC, pTxPort->PortIndex); | |
2233 | SK_DBG_MSG(NULL, SK_DBGMOD_DRV, | |
2234 | SK_DBGCAT_DRV_TX_PROGRESS, | |
2235 | ("XmitFrameSG failed - Ring full\n")); | |
2236 | /* this message can not be sent now */ | |
2237 | return(-1); | |
2238 | } | |
2239 | } | |
2240 | ||
2241 | ||
2242 | pTxd = pTxPort->pTxdRingHead; | |
2243 | pTxdFst = pTxd; | |
2244 | pTxdLst = pTxd; | |
2245 | BytesSend = 0; | |
2246 | protocol = 0; | |
2247 | ||
2248 | /* map first fragment (header) */ | |
2249 | PhysAddr = (SK_U64) pci_map_page(pAC->PciDev, | |
2250 | virt_to_page(pMessage->data), | |
2251 | ((unsigned long) pMessage->data & ~PAGE_MASK), | |
2252 | skb_headlen(pMessage), | |
2253 | PCI_DMA_TODEVICE); | |
2254 | ||
2255 | pTxd->VDataLow = (SK_U32) (PhysAddr & 0xffffffff); | |
2256 | pTxd->VDataHigh = (SK_U32) (PhysAddr >> 32); | |
2257 | ||
2258 | /* HW checksum? */ | |
2259 | if (pMessage->ip_summed == CHECKSUM_HW) { | |
2260 | pTxd->TBControl = TX_CTRL_STF | | |
2261 | TX_CTRL_ST_FWD | | |
2262 | skb_headlen(pMessage); | |
2263 | ||
2264 | /* We have to use the opcode for tcp here because the opcode for | |
2265 | udp is not working in the hardware yet (revision 2.0)*/ | |
2266 | protocol = ((SK_U8)pMessage->data[23] & 0xf); | |
2267 | if ((protocol == 17) && (pAC->GIni.GIChipRev != 0)) | |
2268 | pTxd->TBControl |= BMU_UDP_CHECK; | |
2269 | else | |
2270 | pTxd->TBControl |= BMU_TCP_CHECK ; | |
2271 | ||
2272 | hlength = ((SK_U8)pMessage->data[14] & 0xf) * 4; | |
2273 | pTxd->TcpSumOfs = 0; /* PH-Checksum already claculated */ | |
2274 | pTxd->TcpSumSt = 14+hlength+16; | |
2275 | pTxd->TcpSumWr = 14+hlength; | |
42d1f039 | 2276 | |
7152b1d0 | 2277 | } else { |
42d1f039 | 2278 | pTxd->TBControl = TX_CTRL_CHECK_DEFAULT | |
7152b1d0 WD |
2279 | TX_CTRL_SOFTWARE | |
2280 | TX_CTRL_STF | | |
2281 | skb_headlen(pMessage); | |
2282 | } | |
2283 | ||
2284 | pTxd = pTxd->pNextTxd; | |
2285 | pTxPort->TxdRingFree--; | |
2286 | BytesSend += skb_headlen(pMessage); | |
2287 | ||
2288 | ||
2289 | /* Map SG fragments */ | |
2290 | for (i = 0; i < skb_shinfo(pMessage)->nr_frags; i++) { | |
2291 | sk_frag = &skb_shinfo(pMessage)->frags[i]; | |
42d1f039 | 2292 | |
7152b1d0 WD |
2293 | /* we already have the proper value in entry */ |
2294 | PhysAddr = (SK_U64) pci_map_page(pAC->PciDev, | |
2295 | sk_frag->page, | |
2296 | sk_frag->page_offset, | |
2297 | sk_frag->size, | |
2298 | PCI_DMA_TODEVICE); | |
2299 | ||
2300 | pTxd->VDataLow = (SK_U32) (PhysAddr & 0xffffffff); | |
2301 | pTxd->VDataHigh = (SK_U32) (PhysAddr >> 32); | |
2302 | pTxd->pMBuf = pMessage; | |
42d1f039 | 2303 | |
7152b1d0 WD |
2304 | /* HW checksum */ |
2305 | if (pMessage->ip_summed == CHECKSUM_HW) { | |
42d1f039 WD |
2306 | pTxd->TBControl = TX_CTRL_OWN_BMU | |
2307 | TX_CTRL_SOFTWARE | | |
7152b1d0 WD |
2308 | TX_CTRL_ST_FWD; |
2309 | ||
2310 | /* We have to use the opcode for tcp here because the opcode for | |
2311 | udp is not working in the hardware yet (revision 2.0)*/ | |
2312 | if ((protocol == 17) && (pAC->GIni.GIChipRev != 0)) | |
2313 | pTxd->TBControl |= BMU_UDP_CHECK ; | |
2314 | else | |
2315 | pTxd->TBControl |= BMU_TCP_CHECK ; | |
2316 | ||
2317 | } else { | |
2318 | pTxd->TBControl = TX_CTRL_CHECK_DEFAULT | | |
2319 | TX_CTRL_SOFTWARE | | |
2320 | TX_CTRL_OWN_BMU; | |
2321 | } | |
2322 | ||
2323 | /* Last fragment */ | |
2324 | if( (i+1) == skb_shinfo(pMessage)->nr_frags ) { | |
2325 | #ifdef USE_TX_COMPLETE | |
2326 | pTxd->TBControl |= TX_CTRL_EOF | | |
2327 | TX_CTRL_EOF_IRQ | | |
2328 | sk_frag->size; | |
2329 | #else | |
2330 | pTxd->TBControl |= TX_CTRL_EOF | | |
2331 | sk_frag->size; | |
2332 | #endif | |
2333 | pTxdFst->TBControl |= TX_CTRL_OWN_BMU | | |
42d1f039 | 2334 | TX_CTRL_SOFTWARE; |
7152b1d0 WD |
2335 | |
2336 | } else { | |
2337 | pTxd->TBControl |= sk_frag->size; | |
2338 | } | |
2339 | pTxdLst = pTxd; | |
2340 | pTxd = pTxd->pNextTxd; | |
2341 | pTxPort->TxdRingFree--; | |
2342 | BytesSend += sk_frag->size; | |
2343 | } | |
2344 | ||
2345 | if ((pTxPort->pTxdRingPrev->TBControl & TX_CTRL_OWN_BMU) == 0) { | |
2346 | /* previous descriptor already done, so give tx start cmd */ | |
2347 | /* StartTx(pAC, pTxPort->HwAddr); */ | |
2348 | SK_OUT8(pTxPort->HwAddr, TX_Q_CTRL, TX_Q_CTRL_START); | |
2349 | } | |
2350 | ||
2351 | pTxPort->pTxdRingPrev = pTxdLst; | |
2352 | pTxPort->pTxdRingHead = pTxd; | |
2353 | ||
2354 | spin_unlock_irqrestore(&pTxPort->TxDesRingLock, Flags); | |
2355 | ||
2356 | if (pTxPort->TxdRingFree > 0) | |
2357 | return (BytesSend); | |
2358 | else | |
2359 | return (0); | |
2360 | } | |
2361 | #endif | |
2362 | ||
2363 | ||
2364 | void dump_frag( SK_U8 *data, int length) | |
2365 | { | |
42d1f039 | 2366 | int i; |
7152b1d0 | 2367 | |
42d1f039 WD |
2368 | printk("Length: %d\n", length); |
2369 | for( i=0; i < length; i++ ) { | |
2370 | printk(" %02x", (SK_U8)*(data + i) ); | |
2371 | if( !((i+1) % 20) ) | |
2372 | printk("\n"); | |
2373 | } | |
2374 | printk("\n\n"); | |
7152b1d0 WD |
2375 | |
2376 | } | |
2377 | ||
2378 | ||
2379 | /***************************************************************************** | |
2380 | * | |
53677ef1 | 2381 | * FreeTxDescriptors - release descriptors from the descriptor ring |
7152b1d0 WD |
2382 | * |
2383 | * Description: | |
2384 | * This function releases descriptors from a transmit ring if they | |
2385 | * have been sent by the BMU. | |
2386 | * If a descriptors is sent, it can be freed and the message can | |
2387 | * be freed, too. | |
2388 | * The SOFTWARE controllable bit is used to prevent running around a | |
2389 | * completely free ring for ever. If this bit is no set in the | |
2390 | * frame (by XmitFrame), this frame has never been sent or is | |
2391 | * already freed. | |
2392 | * The Tx descriptor ring lock must be held while calling this function !!! | |
2393 | * | |
2394 | * Returns: | |
2395 | * none | |
2396 | */ | |
2397 | static void FreeTxDescriptors( | |
2398 | SK_AC *pAC, /* pointer to the adapter context */ | |
2399 | TX_PORT *pTxPort) /* pointer to destination port structure */ | |
2400 | { | |
2401 | TXD *pTxd; /* pointer to the checked descriptor */ | |
2402 | TXD *pNewTail; /* pointer to 'end' of the ring */ | |
2403 | SK_U32 Control; /* TBControl field of descriptor */ | |
2404 | SK_U64 PhysAddr; /* address of DMA mapping */ | |
2405 | ||
2406 | pNewTail = pTxPort->pTxdRingTail; | |
2407 | pTxd = pNewTail; | |
42d1f039 | 2408 | /* |
7152b1d0 WD |
2409 | * loop forever; exits if TX_CTRL_SOFTWARE bit not set in start frame |
2410 | * or TX_CTRL_OWN_BMU bit set in any frame | |
2411 | */ | |
2412 | while (1) { | |
2413 | Control = pTxd->TBControl; | |
2414 | if ((Control & TX_CTRL_SOFTWARE) == 0) { | |
42d1f039 | 2415 | /* |
7152b1d0 WD |
2416 | * software controllable bit is set in first |
2417 | * fragment when given to BMU. Not set means that | |
42d1f039 | 2418 | * this fragment was never sent or is already |
7152b1d0 WD |
2419 | * freed ( -> ring completely free now). |
2420 | */ | |
2421 | pTxPort->pTxdRingTail = pTxd; | |
2422 | netif_wake_queue(pAC->dev[pTxPort->PortIndex]); | |
2423 | return; | |
2424 | } | |
2425 | if (Control & TX_CTRL_OWN_BMU) { | |
2426 | pTxPort->pTxdRingTail = pTxd; | |
2427 | if (pTxPort->TxdRingFree > 0) { | |
2428 | netif_wake_queue(pAC->dev[pTxPort->PortIndex]); | |
2429 | } | |
2430 | return; | |
2431 | } | |
42d1f039 | 2432 | |
7152b1d0 WD |
2433 | /* release the DMA mapping */ |
2434 | PhysAddr = ((SK_U64) pTxd->VDataHigh) << (SK_U64) 32; | |
2435 | PhysAddr |= (SK_U64) pTxd->VDataLow; | |
2436 | pci_unmap_page(pAC->PciDev, PhysAddr, | |
2437 | pTxd->pMBuf->len, | |
2438 | PCI_DMA_TODEVICE); | |
2439 | ||
2440 | if (Control & TX_CTRL_EOF) | |
2441 | DEV_KFREE_SKB_ANY(pTxd->pMBuf); /* free message */ | |
2442 | ||
2443 | pTxPort->TxdRingFree++; | |
2444 | pTxd->TBControl &= ~TX_CTRL_SOFTWARE; | |
2445 | pTxd = pTxd->pNextTxd; /* point behind fragment with EOF */ | |
2446 | } /* while(forever) */ | |
2447 | } /* FreeTxDescriptors */ | |
2448 | ||
2449 | /***************************************************************************** | |
2450 | * | |
53677ef1 | 2451 | * FillRxRing - fill the receive ring with valid descriptors |
7152b1d0 WD |
2452 | * |
2453 | * Description: | |
2454 | * This function fills the receive ring descriptors with data | |
2455 | * segments and makes them valid for the BMU. | |
2456 | * The active ring is filled completely, if possible. | |
2457 | * The non-active ring is filled only partial to save memory. | |
2458 | * | |
2459 | * Description of rx ring structure: | |
2460 | * head - points to the descriptor which will be used next by the BMU | |
2461 | * tail - points to the next descriptor to give to the BMU | |
42d1f039 | 2462 | * |
7152b1d0 WD |
2463 | * Returns: N/A |
2464 | */ | |
2465 | static void FillRxRing( | |
2466 | SK_AC *pAC, /* pointer to the adapter context */ | |
2467 | RX_PORT *pRxPort) /* ptr to port struct for which the ring | |
2468 | should be filled */ | |
2469 | { | |
2470 | unsigned long Flags; | |
2471 | ||
2472 | spin_lock_irqsave(&pRxPort->RxDesRingLock, Flags); | |
2473 | while (pRxPort->RxdRingFree > pRxPort->RxFillLimit) { | |
2474 | if(!FillRxDescriptor(pAC, pRxPort)) | |
2475 | break; | |
2476 | } | |
2477 | spin_unlock_irqrestore(&pRxPort->RxDesRingLock, Flags); | |
2478 | } /* FillRxRing */ | |
2479 | ||
2480 | ||
2481 | /***************************************************************************** | |
2482 | * | |
53677ef1 | 2483 | * FillRxDescriptor - fill one buffer into the receive ring |
7152b1d0 WD |
2484 | * |
2485 | * Description: | |
2486 | * The function allocates a new receive buffer and | |
2487 | * puts it into the next descriptor. | |
2488 | * | |
2489 | * Returns: | |
2490 | * SK_TRUE - a buffer was added to the ring | |
2491 | * SK_FALSE - a buffer could not be added | |
2492 | */ | |
2493 | static SK_BOOL FillRxDescriptor( | |
2494 | SK_AC *pAC, /* pointer to the adapter context struct */ | |
2495 | RX_PORT *pRxPort) /* ptr to port struct of ring to fill */ | |
2496 | { | |
2497 | struct sk_buff *pMsgBlock; /* pointer to a new message block */ | |
2498 | RXD *pRxd; /* the rxd to fill */ | |
2499 | SK_U16 Length; /* data fragment length */ | |
2500 | SK_U64 PhysAddr; /* physical address of a rx buffer */ | |
2501 | ||
2502 | pMsgBlock = alloc_skb(pAC->RxBufSize, GFP_ATOMIC); | |
2503 | if (pMsgBlock == NULL) { | |
2504 | SK_DBG_MSG(NULL, SK_DBGMOD_DRV, | |
2505 | SK_DBGCAT_DRV_ENTRY, | |
2506 | ("%s: Allocation of rx buffer failed !\n", | |
2507 | pAC->dev[pRxPort->PortIndex]->name)); | |
2508 | SK_PNMI_CNT_NO_RX_BUF(pAC, pRxPort->PortIndex); | |
2509 | return(SK_FALSE); | |
2510 | } | |
2511 | skb_reserve(pMsgBlock, 2); /* to align IP frames */ | |
2512 | /* skb allocated ok, so add buffer */ | |
2513 | pRxd = pRxPort->pRxdRingTail; | |
2514 | pRxPort->pRxdRingTail = pRxd->pNextRxd; | |
2515 | pRxPort->RxdRingFree--; | |
2516 | Length = pAC->RxBufSize; | |
2517 | #if 0 | |
2518 | PhysAddr = (SK_U64) pci_map_page(pAC->PciDev, | |
2519 | virt_to_page(pMsgBlock->data), | |
2520 | ((unsigned long) pMsgBlock->data & | |
2521 | ~PAGE_MASK), | |
2522 | pAC->RxBufSize - 2, | |
2523 | PCI_DMA_FROMDEVICE); | |
2524 | #else | |
2525 | PhysAddr = (SK_U64) pci_phys_to_mem(pAC->PciDev, (u32)pMsgBlock->data); | |
2526 | #endif | |
2527 | pRxd->VDataLow = (SK_U32) (PhysAddr & 0xffffffff); | |
2528 | pRxd->VDataHigh = (SK_U32) (PhysAddr >> 32); | |
2529 | pRxd->pMBuf = pMsgBlock; | |
2530 | pRxd->RBControl = RX_CTRL_OWN_BMU | RX_CTRL_STF | | |
2531 | RX_CTRL_EOF_IRQ | RX_CTRL_CHECK_CSUM | Length; | |
2532 | return (SK_TRUE); | |
2533 | ||
2534 | } /* FillRxDescriptor */ | |
2535 | ||
2536 | ||
2537 | /***************************************************************************** | |
2538 | * | |
53677ef1 | 2539 | * ReQueueRxBuffer - fill one buffer back into the receive ring |
7152b1d0 WD |
2540 | * |
2541 | * Description: | |
2542 | * Fill a given buffer back into the rx ring. The buffer | |
2543 | * has been previously allocated and aligned, and its phys. | |
2544 | * address calculated, so this is no more necessary. | |
2545 | * | |
2546 | * Returns: N/A | |
2547 | */ | |
2548 | static void ReQueueRxBuffer( | |
2549 | SK_AC *pAC, /* pointer to the adapter context struct */ | |
2550 | RX_PORT *pRxPort, /* ptr to port struct of ring to fill */ | |
2551 | struct sk_buff *pMsg, /* pointer to the buffer */ | |
2552 | SK_U32 PhysHigh, /* phys address high dword */ | |
2553 | SK_U32 PhysLow) /* phys address low dword */ | |
2554 | { | |
2555 | RXD *pRxd; /* the rxd to fill */ | |
2556 | SK_U16 Length; /* data fragment length */ | |
2557 | ||
2558 | pRxd = pRxPort->pRxdRingTail; | |
2559 | pRxPort->pRxdRingTail = pRxd->pNextRxd; | |
2560 | pRxPort->RxdRingFree--; | |
2561 | Length = pAC->RxBufSize; | |
2562 | pRxd->VDataLow = PhysLow; | |
2563 | pRxd->VDataHigh = PhysHigh; | |
2564 | pRxd->pMBuf = pMsg; | |
2565 | pRxd->RBControl = RX_CTRL_OWN_BMU | RX_CTRL_STF | | |
2566 | RX_CTRL_EOF_IRQ | RX_CTRL_CHECK_CSUM | Length; | |
2567 | return; | |
2568 | } /* ReQueueRxBuffer */ | |
2569 | ||
2570 | ||
2571 | /***************************************************************************** | |
2572 | * | |
53677ef1 | 2573 | * ReceiveIrq - handle a receive IRQ |
7152b1d0 WD |
2574 | * |
2575 | * Description: | |
2576 | * This function is called when a receive IRQ is set. | |
2577 | * It walks the receive descriptor ring and sends up all | |
2578 | * frames that are complete. | |
2579 | * | |
2580 | * Returns: N/A | |
2581 | */ | |
2582 | #if 0 | |
2583 | static void ReceiveIrq( | |
2584 | #else | |
2585 | void ReceiveIrq( | |
2586 | #endif | |
2587 | SK_AC *pAC, /* pointer to adapter context */ | |
2588 | RX_PORT *pRxPort, /* pointer to receive port struct */ | |
2589 | SK_BOOL SlowPathLock) /* indicates if SlowPathLock is needed */ | |
2590 | { | |
2591 | RXD *pRxd; /* pointer to receive descriptors */ | |
2592 | SK_U32 Control; /* control field of descriptor */ | |
2593 | struct sk_buff *pMsg; /* pointer to message holding frame */ | |
2594 | struct sk_buff *pNewMsg; /* pointer to a new message for copying frame */ | |
2595 | int FrameLength; /* total length of received frame */ | |
2596 | SK_MBUF *pRlmtMbuf; /* ptr to a buffer for giving a frame to rlmt */ | |
42d1f039 | 2597 | SK_EVPARA EvPara; /* an event parameter union */ |
7152b1d0 WD |
2598 | unsigned long Flags; /* for spin lock */ |
2599 | int PortIndex = pRxPort->PortIndex; | |
2600 | unsigned int Offset; | |
2601 | unsigned int NumBytes; | |
2602 | unsigned int ForRlmt; | |
2603 | SK_BOOL IsBc; | |
2604 | SK_BOOL IsMc; | |
53677ef1 | 2605 | SK_BOOL IsBadFrame; /* Bad frame */ |
7152b1d0 WD |
2606 | |
2607 | SK_U32 FrameStat; | |
2608 | unsigned short Csum1; | |
2609 | unsigned short Csum2; | |
2610 | unsigned short Type; | |
2611 | #if 0 | |
2612 | int Result; | |
2613 | #endif | |
2614 | SK_U64 PhysAddr; | |
2615 | ||
42d1f039 | 2616 | rx_start: |
7152b1d0 WD |
2617 | /* do forever; exit if RX_CTRL_OWN_BMU found */ |
2618 | for ( pRxd = pRxPort->pRxdRingHead ; | |
2619 | pRxPort->RxdRingFree < pAC->RxDescrPerRing ; | |
2620 | pRxd = pRxd->pNextRxd, | |
2621 | pRxPort->pRxdRingHead = pRxd, | |
2622 | pRxPort->RxdRingFree ++) { | |
2623 | ||
2624 | /* | |
42d1f039 WD |
2625 | * For a better understanding of this loop |
2626 | * Go through every descriptor beginning at the head | |
7152b1d0 WD |
2627 | * Please note: the ring might be completely received so the OWN bit |
2628 | * set is not a good crirteria to leave that loop. | |
2629 | * Therefore the RingFree counter is used. | |
2630 | * On entry of this loop pRxd is a pointer to the Rxd that needs | |
2631 | * to be checked next. | |
2632 | */ | |
2633 | ||
2634 | Control = pRxd->RBControl; | |
42d1f039 | 2635 | |
7152b1d0 WD |
2636 | /* check if this descriptor is ready */ |
2637 | if ((Control & RX_CTRL_OWN_BMU) != 0) { | |
2638 | /* this descriptor is not yet ready */ | |
2639 | /* This is the usual end of the loop */ | |
2640 | /* We don't need to start the ring again */ | |
2641 | FillRxRing(pAC, pRxPort); | |
2642 | return; | |
2643 | } | |
2644 | ||
2645 | /* get length of frame and check it */ | |
2646 | FrameLength = Control & RX_CTRL_LEN_MASK; | |
2647 | if (FrameLength > pAC->RxBufSize) { | |
2648 | goto rx_failed; | |
2649 | } | |
2650 | ||
2651 | /* check for STF and EOF */ | |
2652 | if ((Control & (RX_CTRL_STF | RX_CTRL_EOF)) != | |
2653 | (RX_CTRL_STF | RX_CTRL_EOF)) { | |
2654 | goto rx_failed; | |
2655 | } | |
2656 | ||
2657 | /* here we have a complete frame in the ring */ | |
2658 | pMsg = pRxd->pMBuf; | |
2659 | ||
2660 | FrameStat = pRxd->FrameStat; | |
2661 | ||
2662 | /* check for frame length mismatch */ | |
2663 | #define XMR_FS_LEN_SHIFT 18 | |
2664 | #define GMR_FS_LEN_SHIFT 16 | |
2665 | if (pAC->GIni.GIChipId == CHIP_ID_GENESIS) { | |
2666 | if (FrameLength != (SK_U32) (FrameStat >> XMR_FS_LEN_SHIFT)) { | |
2667 | SK_DBG_MSG(NULL, SK_DBGMOD_DRV, | |
2668 | SK_DBGCAT_DRV_RX_PROGRESS, | |
2669 | ("skge: Frame length mismatch (%u/%u).\n", | |
2670 | FrameLength, | |
2671 | (SK_U32) (FrameStat >> XMR_FS_LEN_SHIFT))); | |
2672 | goto rx_failed; | |
2673 | } | |
2674 | } | |
2675 | else { | |
2676 | if (FrameLength != (SK_U32) (FrameStat >> GMR_FS_LEN_SHIFT)) { | |
2677 | SK_DBG_MSG(NULL, SK_DBGMOD_DRV, | |
2678 | SK_DBGCAT_DRV_RX_PROGRESS, | |
2679 | ("skge: Frame length mismatch (%u/%u).\n", | |
2680 | FrameLength, | |
2681 | (SK_U32) (FrameStat >> XMR_FS_LEN_SHIFT))); | |
2682 | goto rx_failed; | |
2683 | } | |
2684 | } | |
2685 | ||
2686 | /* Set Rx Status */ | |
2687 | if (pAC->GIni.GIChipId == CHIP_ID_GENESIS) { | |
2688 | IsBc = (FrameStat & XMR_FS_BC) != 0; | |
2689 | IsMc = (FrameStat & XMR_FS_MC) != 0; | |
42d1f039 | 2690 | IsBadFrame = (FrameStat & |
7152b1d0 WD |
2691 | (XMR_FS_ANY_ERR | XMR_FS_2L_VLAN)) != 0; |
2692 | } else { | |
2693 | IsBc = (FrameStat & GMR_FS_BC) != 0; | |
2694 | IsMc = (FrameStat & GMR_FS_MC) != 0; | |
2695 | IsBadFrame = (((FrameStat & GMR_FS_ANY_ERR) != 0) || | |
2696 | ((FrameStat & GMR_FS_RX_OK) == 0)); | |
2697 | } | |
2698 | ||
2699 | SK_DBG_MSG(NULL, SK_DBGMOD_DRV, 0, | |
2700 | ("Received frame of length %d on port %d\n", | |
2701 | FrameLength, PortIndex)); | |
2702 | SK_DBG_MSG(NULL, SK_DBGMOD_DRV, 0, | |
2703 | ("Number of free rx descriptors: %d\n", | |
2704 | pRxPort->RxdRingFree)); | |
2705 | /* DumpMsg(pMsg, "Rx"); */ | |
2706 | ||
2707 | if ((Control & RX_CTRL_STAT_VALID) != RX_CTRL_STAT_VALID || | |
2708 | (IsBadFrame)) { | |
2709 | #if 0 | |
2710 | (FrameStat & (XMR_FS_ANY_ERR | XMR_FS_2L_VLAN)) != 0) { | |
2711 | #endif | |
2712 | /* there is a receive error in this frame */ | |
2713 | SK_DBG_MSG(NULL, SK_DBGMOD_DRV, | |
2714 | SK_DBGCAT_DRV_RX_PROGRESS, | |
2715 | ("skge: Error in received frame, dropped!\n" | |
2716 | "Control: %x\nRxStat: %x\n", | |
2717 | Control, FrameStat)); | |
2718 | ||
2719 | PhysAddr = ((SK_U64) pRxd->VDataHigh) << (SK_U64)32; | |
2720 | PhysAddr |= (SK_U64) pRxd->VDataLow; | |
2721 | pci_dma_sync_single(pAC->PciDev, | |
2722 | (dma_addr_t) PhysAddr, | |
2723 | FrameLength, | |
2724 | PCI_DMA_FROMDEVICE); | |
2725 | ReQueueRxBuffer(pAC, pRxPort, pMsg, | |
2726 | pRxd->VDataHigh, pRxd->VDataLow); | |
2727 | ||
2728 | continue; | |
2729 | } | |
2730 | ||
2731 | /* | |
2732 | * if short frame then copy data to reduce memory waste | |
2733 | */ | |
2734 | if ((FrameLength < SK_COPY_THRESHOLD) && | |
2735 | ((pNewMsg = alloc_skb(FrameLength+2, GFP_ATOMIC)) != NULL)) { | |
2736 | /* | |
2737 | * Short frame detected and allocation successfull | |
2738 | */ | |
2739 | /* use new skb and copy data */ | |
2740 | skb_reserve(pNewMsg, 2); | |
2741 | skb_put(pNewMsg, FrameLength); | |
2742 | PhysAddr = ((SK_U64) pRxd->VDataHigh) << (SK_U64)32; | |
2743 | PhysAddr |= (SK_U64) pRxd->VDataLow; | |
2744 | ||
2745 | pci_dma_sync_single(pAC->PciDev, | |
2746 | (dma_addr_t) PhysAddr, | |
2747 | FrameLength, | |
2748 | PCI_DMA_FROMDEVICE); | |
2749 | eth_copy_and_sum(pNewMsg, pMsg->data, | |
2750 | FrameLength, 0); | |
2751 | ReQueueRxBuffer(pAC, pRxPort, pMsg, | |
2752 | pRxd->VDataHigh, pRxd->VDataLow); | |
2753 | pMsg = pNewMsg; | |
2754 | ||
2755 | } | |
2756 | else { | |
2757 | /* | |
2758 | * if large frame, or SKB allocation failed, pass | |
2759 | * the SKB directly to the networking | |
2760 | */ | |
2761 | ||
2762 | PhysAddr = ((SK_U64) pRxd->VDataHigh) << (SK_U64)32; | |
2763 | PhysAddr |= (SK_U64) pRxd->VDataLow; | |
2764 | ||
2765 | /* release the DMA mapping */ | |
2766 | pci_unmap_single(pAC->PciDev, | |
2767 | PhysAddr, | |
2768 | pAC->RxBufSize - 2, | |
2769 | PCI_DMA_FROMDEVICE); | |
2770 | ||
2771 | /* set length in message */ | |
2772 | skb_put(pMsg, FrameLength); | |
2773 | /* hardware checksum */ | |
2774 | Type = ntohs(*((short*)&pMsg->data[12])); | |
2775 | if (Type == 0x800) { | |
2776 | Csum1=le16_to_cpu(pRxd->TcpSums & 0xffff); | |
2777 | Csum2=le16_to_cpu((pRxd->TcpSums >> 16) & 0xffff); | |
2778 | #if 0 | |
2779 | if ((((Csum1 & 0xfffe) && (Csum2 & 0xfffe)) && | |
2780 | (pAC->GIni.GIChipId == CHIP_ID_GENESIS)) || | |
2781 | (pAC->GIni.GIChipId == CHIP_ID_YUKON)) { | |
2782 | Result = SkCsGetReceiveInfo(pAC, | |
42d1f039 | 2783 | &pMsg->data[14], |
7152b1d0 WD |
2784 | Csum1, Csum2, pRxPort->PortIndex); |
2785 | if (Result == | |
2786 | SKCS_STATUS_IP_FRAGMENT || | |
2787 | Result == | |
2788 | SKCS_STATUS_IP_CSUM_OK || | |
2789 | Result == | |
2790 | SKCS_STATUS_TCP_CSUM_OK || | |
2791 | Result == | |
2792 | SKCS_STATUS_UDP_CSUM_OK) { | |
2793 | pMsg->ip_summed = | |
2794 | CHECKSUM_UNNECESSARY; | |
2795 | } else { | |
2796 | SK_DBG_MSG(NULL, SK_DBGMOD_DRV, | |
2797 | SK_DBGCAT_DRV_RX_PROGRESS, | |
2798 | ("skge: CRC error. Frame dropped!\n")); | |
2799 | goto rx_failed; | |
2800 | } | |
2801 | }/* checksumControl calculation valid */ | |
2802 | #endif | |
2803 | } /* IP frame */ | |
2804 | } /* frame > SK_COPY_TRESHOLD */ | |
42d1f039 | 2805 | |
7152b1d0 WD |
2806 | SK_DBG_MSG(NULL, SK_DBGMOD_DRV, 1,("V")); |
2807 | ForRlmt = SK_RLMT_RX_PROTOCOL; | |
2808 | #if 0 | |
2809 | IsBc = (FrameStat & XMR_FS_BC)==XMR_FS_BC; | |
2810 | #endif | |
2811 | SK_RLMT_PRE_LOOKAHEAD(pAC, PortIndex, FrameLength, | |
2812 | IsBc, &Offset, &NumBytes); | |
2813 | if (NumBytes != 0) { | |
2814 | #if 0 | |
2815 | IsMc = (FrameStat & XMR_FS_MC)==XMR_FS_MC; | |
2816 | #endif | |
42d1f039 | 2817 | SK_RLMT_LOOKAHEAD(pAC, PortIndex, |
7152b1d0 WD |
2818 | &pMsg->data[Offset], |
2819 | IsBc, IsMc, &ForRlmt); | |
2820 | } | |
2821 | if (ForRlmt == SK_RLMT_RX_PROTOCOL) { | |
2822 | SK_DBG_MSG(NULL, SK_DBGMOD_DRV, 1,("W")); | |
2823 | /* send up only frames from active port */ | |
2824 | if ((PortIndex == pAC->ActivePort) || | |
2825 | (pAC->RlmtNets == 2)) { | |
2826 | /* frame for upper layer */ | |
2827 | SK_DBG_MSG(NULL, SK_DBGMOD_DRV, 1,("U")); | |
2828 | #ifdef xDEBUG | |
2829 | DumpMsg(pMsg, "Rx"); | |
2830 | #endif | |
2831 | SK_PNMI_CNT_RX_OCTETS_DELIVERED(pAC, | |
2832 | FrameLength, pRxPort->PortIndex); | |
2833 | ||
2834 | #if 0 | |
2835 | pMsg->dev = pAC->dev[pRxPort->PortIndex]; | |
2836 | pMsg->protocol = eth_type_trans(pMsg, | |
2837 | pAC->dev[pRxPort->PortIndex]); | |
2838 | netif_rx(pMsg); | |
2839 | pAC->dev[pRxPort->PortIndex]->last_rx = jiffies; | |
2840 | #else | |
2841 | NetReceive(pMsg->data, pMsg->len); | |
2842 | dev_kfree_skb_any(pMsg); | |
2843 | #endif | |
2844 | } | |
2845 | else { | |
2846 | /* drop frame */ | |
42d1f039 | 2847 | SK_DBG_MSG(NULL, SK_DBGMOD_DRV, |
7152b1d0 WD |
2848 | SK_DBGCAT_DRV_RX_PROGRESS, |
2849 | ("D")); | |
2850 | DEV_KFREE_SKB(pMsg); | |
2851 | } | |
42d1f039 | 2852 | |
7152b1d0 WD |
2853 | } /* if not for rlmt */ |
2854 | else { | |
2855 | /* packet for rlmt */ | |
42d1f039 | 2856 | SK_DBG_MSG(NULL, SK_DBGMOD_DRV, |
7152b1d0 WD |
2857 | SK_DBGCAT_DRV_RX_PROGRESS, ("R")); |
2858 | pRlmtMbuf = SkDrvAllocRlmtMbuf(pAC, | |
2859 | pAC->IoBase, FrameLength); | |
2860 | if (pRlmtMbuf != NULL) { | |
2861 | pRlmtMbuf->pNext = NULL; | |
2862 | pRlmtMbuf->Length = FrameLength; | |
2863 | pRlmtMbuf->PortIdx = PortIndex; | |
2864 | EvPara.pParaPtr = pRlmtMbuf; | |
2865 | memcpy((char*)(pRlmtMbuf->pData), | |
2866 | (char*)(pMsg->data), | |
2867 | FrameLength); | |
2868 | ||
2869 | /* SlowPathLock needed? */ | |
2870 | if (SlowPathLock == SK_TRUE) { | |
2871 | spin_lock_irqsave(&pAC->SlowPathLock, Flags); | |
2872 | SkEventQueue(pAC, SKGE_RLMT, | |
2873 | SK_RLMT_PACKET_RECEIVED, | |
2874 | EvPara); | |
2875 | pAC->CheckQueue = SK_TRUE; | |
2876 | spin_unlock_irqrestore(&pAC->SlowPathLock, Flags); | |
2877 | } else { | |
2878 | SkEventQueue(pAC, SKGE_RLMT, | |
2879 | SK_RLMT_PACKET_RECEIVED, | |
2880 | EvPara); | |
2881 | pAC->CheckQueue = SK_TRUE; | |
2882 | } | |
2883 | ||
42d1f039 | 2884 | SK_DBG_MSG(NULL, SK_DBGMOD_DRV, |
7152b1d0 WD |
2885 | SK_DBGCAT_DRV_RX_PROGRESS, |
2886 | ("Q")); | |
2887 | } | |
2888 | #if 0 | |
42d1f039 | 2889 | if ((pAC->dev[pRxPort->PortIndex]->flags & |
7152b1d0 | 2890 | (IFF_PROMISC | IFF_ALLMULTI)) != 0 || |
42d1f039 WD |
2891 | (ForRlmt & SK_RLMT_RX_PROTOCOL) == |
2892 | SK_RLMT_RX_PROTOCOL) { | |
7152b1d0 WD |
2893 | pMsg->dev = pAC->dev[pRxPort->PortIndex]; |
2894 | pMsg->protocol = eth_type_trans(pMsg, | |
2895 | pAC->dev[pRxPort->PortIndex]); | |
2896 | netif_rx(pMsg); | |
2897 | pAC->dev[pRxPort->PortIndex]->last_rx = jiffies; | |
2898 | } | |
2899 | #else | |
2900 | if (0) { | |
2901 | } | |
2902 | #endif | |
2903 | else { | |
2904 | DEV_KFREE_SKB(pMsg); | |
2905 | } | |
2906 | ||
2907 | } /* if packet for rlmt */ | |
2908 | } /* for ... scanning the RXD ring */ | |
2909 | ||
2910 | /* RXD ring is empty -> fill and restart */ | |
2911 | FillRxRing(pAC, pRxPort); | |
2912 | /* do not start if called from Close */ | |
2913 | if (pAC->BoardLevel > 0) { | |
2914 | ClearAndStartRx(pAC, PortIndex); | |
2915 | } | |
2916 | return; | |
2917 | ||
2918 | rx_failed: | |
2919 | /* remove error frame */ | |
2920 | SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_ERROR, | |
2921 | ("Schrottdescriptor, length: 0x%x\n", FrameLength)); | |
2922 | ||
2923 | /* release the DMA mapping */ | |
2924 | ||
2925 | PhysAddr = ((SK_U64) pRxd->VDataHigh) << (SK_U64)32; | |
2926 | PhysAddr |= (SK_U64) pRxd->VDataLow; | |
2927 | pci_unmap_page(pAC->PciDev, | |
2928 | PhysAddr, | |
2929 | pAC->RxBufSize - 2, | |
2930 | PCI_DMA_FROMDEVICE); | |
2931 | DEV_KFREE_SKB_IRQ(pRxd->pMBuf); | |
2932 | pRxd->pMBuf = NULL; | |
2933 | pRxPort->RxdRingFree++; | |
2934 | pRxPort->pRxdRingHead = pRxd->pNextRxd; | |
2935 | goto rx_start; | |
2936 | ||
2937 | } /* ReceiveIrq */ | |
2938 | ||
2939 | ||
2940 | /***************************************************************************** | |
2941 | * | |
53677ef1 | 2942 | * ClearAndStartRx - give a start receive command to BMU, clear IRQ |
7152b1d0 WD |
2943 | * |
2944 | * Description: | |
2945 | * This function sends a start command and a clear interrupt | |
2946 | * command for one receive queue to the BMU. | |
2947 | * | |
2948 | * Returns: N/A | |
2949 | * none | |
2950 | */ | |
2951 | static void ClearAndStartRx( | |
2952 | SK_AC *pAC, /* pointer to the adapter context */ | |
2953 | int PortIndex) /* index of the receive port (XMAC) */ | |
2954 | { | |
2955 | SK_OUT8(pAC->IoBase, RxQueueAddr[PortIndex]+RX_Q_CTRL, | |
2956 | RX_Q_CTRL_START | RX_Q_CTRL_CLR_I_EOF); | |
2957 | } /* ClearAndStartRx */ | |
2958 | ||
2959 | ||
2960 | /***************************************************************************** | |
2961 | * | |
53677ef1 | 2962 | * ClearTxIrq - give a clear transmit IRQ command to BMU |
7152b1d0 WD |
2963 | * |
2964 | * Description: | |
2965 | * This function sends a clear tx IRQ command for one | |
2966 | * transmit queue to the BMU. | |
2967 | * | |
2968 | * Returns: N/A | |
2969 | */ | |
2970 | static void ClearTxIrq( | |
2971 | SK_AC *pAC, /* pointer to the adapter context */ | |
2972 | int PortIndex, /* index of the transmit port (XMAC) */ | |
2973 | int Prio) /* priority or normal queue */ | |
2974 | { | |
2975 | SK_OUT8(pAC->IoBase, TxQueueAddr[PortIndex][Prio]+TX_Q_CTRL, | |
2976 | TX_Q_CTRL_CLR_I_EOF); | |
2977 | } /* ClearTxIrq */ | |
2978 | ||
2979 | ||
2980 | /***************************************************************************** | |
2981 | * | |
53677ef1 | 2982 | * ClearRxRing - remove all buffers from the receive ring |
7152b1d0 WD |
2983 | * |
2984 | * Description: | |
2985 | * This function removes all receive buffers from the ring. | |
2986 | * The receive BMU must be stopped before calling this function. | |
2987 | * | |
2988 | * Returns: N/A | |
2989 | */ | |
2990 | static void ClearRxRing( | |
2991 | SK_AC *pAC, /* pointer to adapter context */ | |
2992 | RX_PORT *pRxPort) /* pointer to rx port struct */ | |
2993 | { | |
2994 | RXD *pRxd; /* pointer to the current descriptor */ | |
2995 | unsigned long Flags; | |
2996 | SK_U64 PhysAddr; | |
2997 | ||
2998 | if (pRxPort->RxdRingFree == pAC->RxDescrPerRing) { | |
2999 | return; | |
3000 | } | |
3001 | spin_lock_irqsave(&pRxPort->RxDesRingLock, Flags); | |
3002 | pRxd = pRxPort->pRxdRingHead; | |
3003 | do { | |
3004 | if (pRxd->pMBuf != NULL) { | |
3005 | ||
3006 | PhysAddr = ((SK_U64) pRxd->VDataHigh) << (SK_U64)32; | |
3007 | PhysAddr |= (SK_U64) pRxd->VDataLow; | |
3008 | pci_unmap_page(pAC->PciDev, | |
3009 | PhysAddr, | |
3010 | pAC->RxBufSize - 2, | |
3011 | PCI_DMA_FROMDEVICE); | |
3012 | DEV_KFREE_SKB(pRxd->pMBuf); | |
3013 | pRxd->pMBuf = NULL; | |
3014 | } | |
3015 | pRxd->RBControl &= RX_CTRL_OWN_BMU; | |
3016 | pRxd = pRxd->pNextRxd; | |
3017 | pRxPort->RxdRingFree++; | |
3018 | } while (pRxd != pRxPort->pRxdRingTail); | |
3019 | pRxPort->pRxdRingTail = pRxPort->pRxdRingHead; | |
3020 | spin_unlock_irqrestore(&pRxPort->RxDesRingLock, Flags); | |
3021 | } /* ClearRxRing */ | |
3022 | ||
3023 | ||
3024 | /***************************************************************************** | |
3025 | * | |
3026 | * ClearTxRing - remove all buffers from the transmit ring | |
3027 | * | |
3028 | * Description: | |
3029 | * This function removes all transmit buffers from the ring. | |
3030 | * The transmit BMU must be stopped before calling this function | |
3031 | * and transmitting at the upper level must be disabled. | |
3032 | * The BMU own bit of all descriptors is cleared, the rest is | |
3033 | * done by calling FreeTxDescriptors. | |
3034 | * | |
3035 | * Returns: N/A | |
3036 | */ | |
3037 | static void ClearTxRing( | |
3038 | SK_AC *pAC, /* pointer to adapter context */ | |
3039 | TX_PORT *pTxPort) /* pointer to tx prt struct */ | |
3040 | { | |
3041 | TXD *pTxd; /* pointer to the current descriptor */ | |
3042 | int i; | |
3043 | unsigned long Flags; | |
3044 | ||
3045 | spin_lock_irqsave(&pTxPort->TxDesRingLock, Flags); | |
3046 | pTxd = pTxPort->pTxdRingHead; | |
3047 | for (i=0; i<pAC->TxDescrPerRing; i++) { | |
3048 | pTxd->TBControl &= ~TX_CTRL_OWN_BMU; | |
3049 | pTxd = pTxd->pNextTxd; | |
3050 | } | |
3051 | FreeTxDescriptors(pAC, pTxPort); | |
3052 | spin_unlock_irqrestore(&pTxPort->TxDesRingLock, Flags); | |
3053 | } /* ClearTxRing */ | |
3054 | ||
3055 | ||
3056 | #if 0 | |
3057 | /***************************************************************************** | |
3058 | * | |
53677ef1 | 3059 | * SetQueueSizes - configure the sizes of rx and tx queues |
7152b1d0 WD |
3060 | * |
3061 | * Description: | |
3062 | * This function assigns the sizes for active and passive port | |
3063 | * to the appropriate HWinit structure variables. | |
3064 | * The passive port(s) get standard values, all remaining RAM | |
3065 | * is given to the active port. | |
3066 | * The queue sizes are in kbyte and must be multiple of 8. | |
3067 | * The limits for the number of buffers filled into the rx rings | |
3068 | * is also set in this routine. | |
3069 | * | |
3070 | * Returns: | |
3071 | * none | |
3072 | */ | |
3073 | static void SetQueueSizes( | |
3074 | SK_AC *pAC) /* pointer to the adapter context */ | |
3075 | { | |
3076 | int StandbyRam; /* adapter RAM used for a standby port */ | |
3077 | int RemainingRam; /* adapter RAM available for the active port */ | |
3078 | int RxRam; /* RAM used for the active port receive queue */ | |
3079 | int i; /* loop counter */ | |
3080 | ||
3081 | if (pAC->RlmtNets == 1) { | |
3082 | StandbyRam = SK_RLMT_STANDBY_QRXSIZE + SK_RLMT_STANDBY_QXASIZE + | |
3083 | SK_RLMT_STANDBY_QXSSIZE; | |
42d1f039 | 3084 | RemainingRam = pAC->GIni.GIRamSize - |
7152b1d0 WD |
3085 | (pAC->GIni.GIMacsFound-1) * StandbyRam; |
3086 | for (i=0; i<pAC->GIni.GIMacsFound; i++) { | |
3087 | pAC->GIni.GP[i].PRxQSize = SK_RLMT_STANDBY_QRXSIZE; | |
3088 | pAC->GIni.GP[i].PXSQSize = SK_RLMT_STANDBY_QXSSIZE; | |
3089 | pAC->GIni.GP[i].PXAQSize = SK_RLMT_STANDBY_QXASIZE; | |
3090 | } | |
3091 | RxRam = (RemainingRam * 8 / 10) & ~7; | |
3092 | pAC->GIni.GP[pAC->ActivePort].PRxQSize = RxRam; | |
3093 | pAC->GIni.GP[pAC->ActivePort].PXSQSize = 0; | |
3094 | pAC->GIni.GP[pAC->ActivePort].PXAQSize = | |
3095 | (RemainingRam - RxRam) & ~7; | |
3096 | pAC->RxQueueSize = RxRam; | |
3097 | pAC->TxSQueueSize = 0; | |
3098 | pAC->TxAQueueSize = (RemainingRam - RxRam) & ~7; | |
3099 | SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_ENTRY, | |
3100 | ("queue sizes settings - rx:%d txA:%d txS:%d\n", | |
3101 | pAC->RxQueueSize,pAC->TxAQueueSize, pAC->TxSQueueSize)); | |
3102 | } else { | |
3103 | RemainingRam = pAC->GIni.GIRamSize/pAC->GIni.GIMacsFound; | |
3104 | RxRam = (RemainingRam * 8 / 10) & ~7; | |
3105 | for (i=0; i<pAC->GIni.GIMacsFound; i++) { | |
3106 | pAC->GIni.GP[i].PRxQSize = RxRam; | |
3107 | pAC->GIni.GP[i].PXSQSize = 0; | |
3108 | pAC->GIni.GP[i].PXAQSize = (RemainingRam - RxRam) & ~7; | |
3109 | } | |
42d1f039 | 3110 | |
7152b1d0 WD |
3111 | pAC->RxQueueSize = RxRam; |
3112 | pAC->TxSQueueSize = 0; | |
3113 | pAC->TxAQueueSize = (RemainingRam - RxRam) & ~7; | |
3114 | } | |
3115 | for (i=0; i<SK_MAX_MACS; i++) { | |
3116 | pAC->RxPort[i].RxFillLimit = pAC->RxDescrPerRing; | |
3117 | } | |
3118 | ||
3119 | if (pAC->RlmtNets == 2) { | |
3120 | for (i=0; i<pAC->GIni.GIMacsFound; i++) { | |
3121 | pAC->RxPort[i].RxFillLimit = pAC->RxDescrPerRing - 100; | |
3122 | } | |
3123 | } else { | |
3124 | for (i=0; i<pAC->GIni.GIMacsFound; i++) { | |
3125 | pAC->RxPort[i].RxFillLimit = pAC->RxDescrPerRing - 100; | |
3126 | } | |
3127 | /* | |
3128 | * Do not set the Limit to 0, because this could cause | |
3129 | * wrap around with ReQueue'ed buffers (a buffer could | |
3130 | * be requeued in the same position, made accessable to | |
3131 | * the hardware, and the hardware could change its | |
3132 | * contents! | |
3133 | */ | |
3134 | pAC->RxPort[pAC->ActivePort].RxFillLimit = 1; | |
3135 | } | |
3136 | ||
3137 | #ifdef DEBUG | |
3138 | for (i=0; i<pAC->GIni.GIMacsFound; i++) { | |
3139 | SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_TX_PROGRESS, | |
3140 | ("i: %d, RxQSize: %d, PXSQsize: %d, PXAQSize: %d\n", | |
3141 | i, | |
3142 | pAC->GIni.GP[i].PRxQSize, | |
3143 | pAC->GIni.GP[i].PXSQSize, | |
3144 | pAC->GIni.GP[i].PXAQSize)); | |
3145 | } | |
3146 | #endif | |
3147 | } /* SetQueueSizes */ | |
3148 | ||
3149 | ||
3150 | /***************************************************************************** | |
3151 | * | |
53677ef1 | 3152 | * SkGeSetMacAddr - Set the hardware MAC address |
7152b1d0 WD |
3153 | * |
3154 | * Description: | |
3155 | * This function sets the MAC address used by the adapter. | |
3156 | * | |
3157 | * Returns: | |
3158 | * 0, if everything is ok | |
3159 | * !=0, on error | |
3160 | */ | |
3161 | static int SkGeSetMacAddr(struct SK_NET_DEVICE *dev, void *p) | |
3162 | { | |
3163 | ||
3164 | DEV_NET *pNet = (DEV_NET*) dev->priv; | |
3165 | SK_AC *pAC = pNet->pAC; | |
3166 | ||
3167 | struct sockaddr *addr = p; | |
3168 | unsigned long Flags; | |
42d1f039 | 3169 | |
7152b1d0 WD |
3170 | SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_ENTRY, |
3171 | ("SkGeSetMacAddr starts now...\n")); | |
3172 | if(netif_running(dev)) | |
3173 | return -EBUSY; | |
3174 | ||
3175 | memcpy(dev->dev_addr, addr->sa_data,dev->addr_len); | |
42d1f039 | 3176 | |
7152b1d0 WD |
3177 | spin_lock_irqsave(&pAC->SlowPathLock, Flags); |
3178 | ||
3179 | if (pAC->RlmtNets == 2) | |
3180 | SkAddrOverride(pAC, pAC->IoBase, pNet->NetNr, | |
3181 | (SK_MAC_ADDR*)dev->dev_addr, SK_ADDR_VIRTUAL_ADDRESS); | |
3182 | else | |
3183 | SkAddrOverride(pAC, pAC->IoBase, pAC->ActivePort, | |
3184 | (SK_MAC_ADDR*)dev->dev_addr, SK_ADDR_VIRTUAL_ADDRESS); | |
3185 | ||
42d1f039 | 3186 | |
7152b1d0 WD |
3187 | spin_unlock_irqrestore(&pAC->SlowPathLock, Flags); |
3188 | return 0; | |
3189 | } /* SkGeSetMacAddr */ | |
3190 | #endif | |
3191 | ||
3192 | ||
3193 | /***************************************************************************** | |
3194 | * | |
53677ef1 | 3195 | * SkGeSetRxMode - set receive mode |
7152b1d0 WD |
3196 | * |
3197 | * Description: | |
3198 | * This function sets the receive mode of an adapter. The adapter | |
3199 | * supports promiscuous mode, allmulticast mode and a number of | |
3200 | * multicast addresses. If more multicast addresses the available | |
3201 | * are selected, a hash function in the hardware is used. | |
3202 | * | |
3203 | * Returns: | |
3204 | * 0, if everything is ok | |
3205 | * !=0, on error | |
3206 | */ | |
3207 | #if 0 | |
3208 | static void SkGeSetRxMode(struct SK_NET_DEVICE *dev) | |
3209 | { | |
3210 | ||
3211 | DEV_NET *pNet; | |
3212 | SK_AC *pAC; | |
3213 | ||
3214 | struct dev_mc_list *pMcList; | |
3215 | int i; | |
3216 | int PortIdx; | |
3217 | unsigned long Flags; | |
3218 | ||
3219 | SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_ENTRY, | |
3220 | ("SkGeSetRxMode starts now... ")); | |
3221 | ||
3222 | pNet = (DEV_NET*) dev->priv; | |
3223 | pAC = pNet->pAC; | |
3224 | if (pAC->RlmtNets == 1) | |
3225 | PortIdx = pAC->ActivePort; | |
3226 | else | |
3227 | PortIdx = pNet->NetNr; | |
3228 | ||
3229 | spin_lock_irqsave(&pAC->SlowPathLock, Flags); | |
3230 | if (dev->flags & IFF_PROMISC) { | |
3231 | SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_ENTRY, | |
3232 | ("PROMISCUOUS mode\n")); | |
3233 | SkAddrPromiscuousChange(pAC, pAC->IoBase, PortIdx, | |
3234 | SK_PROM_MODE_LLC); | |
3235 | } else if (dev->flags & IFF_ALLMULTI) { | |
3236 | SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_ENTRY, | |
3237 | ("ALLMULTI mode\n")); | |
3238 | SkAddrPromiscuousChange(pAC, pAC->IoBase, PortIdx, | |
3239 | SK_PROM_MODE_ALL_MC); | |
3240 | } else { | |
3241 | SkAddrPromiscuousChange(pAC, pAC->IoBase, PortIdx, | |
3242 | SK_PROM_MODE_NONE); | |
3243 | SkAddrMcClear(pAC, pAC->IoBase, PortIdx, 0); | |
3244 | ||
3245 | SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_ENTRY, | |
3246 | ("Number of MC entries: %d ", dev->mc_count)); | |
42d1f039 | 3247 | |
7152b1d0 WD |
3248 | pMcList = dev->mc_list; |
3249 | for (i=0; i<dev->mc_count; i++, pMcList = pMcList->next) { | |
3250 | SkAddrMcAdd(pAC, pAC->IoBase, PortIdx, | |
3251 | (SK_MAC_ADDR*)pMcList->dmi_addr, 0); | |
3252 | SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_MCA, | |
3253 | ("%02x:%02x:%02x:%02x:%02x:%02x\n", | |
3254 | pMcList->dmi_addr[0], | |
3255 | pMcList->dmi_addr[1], | |
3256 | pMcList->dmi_addr[2], | |
3257 | pMcList->dmi_addr[3], | |
3258 | pMcList->dmi_addr[4], | |
3259 | pMcList->dmi_addr[5])); | |
3260 | } | |
3261 | SkAddrMcUpdate(pAC, pAC->IoBase, PortIdx); | |
3262 | } | |
3263 | spin_unlock_irqrestore(&pAC->SlowPathLock, Flags); | |
42d1f039 | 3264 | |
7152b1d0 WD |
3265 | return; |
3266 | } /* SkGeSetRxMode */ | |
3267 | ||
3268 | ||
3269 | /***************************************************************************** | |
3270 | * | |
53677ef1 | 3271 | * SkGeChangeMtu - set the MTU to another value |
7152b1d0 WD |
3272 | * |
3273 | * Description: | |
3274 | * This function sets is called whenever the MTU size is changed | |
3275 | * (ifconfig mtu xxx dev ethX). If the MTU is bigger than standard | |
3276 | * ethernet MTU size, long frame support is activated. | |
3277 | * | |
3278 | * Returns: | |
3279 | * 0, if everything is ok | |
3280 | * !=0, on error | |
3281 | */ | |
3282 | static int SkGeChangeMtu(struct SK_NET_DEVICE *dev, int NewMtu) | |
3283 | { | |
3284 | DEV_NET *pNet; | |
3285 | DEV_NET *pOtherNet; | |
3286 | SK_AC *pAC; | |
3287 | unsigned long Flags; | |
3288 | int i; | |
53677ef1 | 3289 | SK_EVPARA EvPara; |
7152b1d0 WD |
3290 | |
3291 | SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_ENTRY, | |
3292 | ("SkGeChangeMtu starts now...\n")); | |
3293 | ||
3294 | pNet = (DEV_NET*) dev->priv; | |
3295 | pAC = pNet->pAC; | |
3296 | ||
3297 | if ((NewMtu < 68) || (NewMtu > SK_JUMBO_MTU)) { | |
3298 | return -EINVAL; | |
3299 | } | |
3300 | ||
3301 | if(pAC->BoardLevel != 2) { | |
3302 | return -EINVAL; | |
3303 | } | |
3304 | ||
3305 | pNet->Mtu = NewMtu; | |
3306 | pOtherNet = (DEV_NET*)pAC->dev[1 - pNet->NetNr]->priv; | |
3307 | if ((pOtherNet->Mtu > 1500) && (NewMtu <= 1500) && (pOtherNet->Up==1)) { | |
3308 | return(0); | |
3309 | } | |
3310 | ||
3311 | EvPara.Para32[0] = pNet->NetNr; | |
3312 | EvPara.Para32[1] = -1; | |
3313 | ||
3314 | pAC->RxBufSize = NewMtu + 32; | |
3315 | dev->mtu = NewMtu; | |
3316 | ||
3317 | SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_ENTRY, | |
3318 | ("New MTU: %d\n", NewMtu)); | |
3319 | ||
3320 | /* prevent reconfiguration while changing the MTU */ | |
3321 | ||
3322 | /* disable interrupts */ | |
3323 | SK_OUT32(pAC->IoBase, B0_IMSK, 0); | |
3324 | spin_lock_irqsave(&pAC->SlowPathLock, Flags); | |
3325 | ||
3326 | /* Found more than one port */ | |
42d1f039 | 3327 | if ((pAC->GIni.GIMacsFound == 2 ) && |
7152b1d0 WD |
3328 | (pAC->RlmtNets == 2)) { |
3329 | /* Stop both ports */ | |
3330 | EvPara.Para32[0] = 0; | |
3331 | SkEventQueue(pAC, SKGE_RLMT, SK_RLMT_STOP, EvPara); | |
3332 | EvPara.Para32[0] = 1; | |
3333 | SkEventQueue(pAC, SKGE_RLMT, SK_RLMT_STOP, EvPara); | |
3334 | } else { | |
3335 | SkEventQueue(pAC, SKGE_RLMT, SK_RLMT_STOP, EvPara); | |
3336 | } | |
3337 | ||
3338 | SkEventDispatcher(pAC, pAC->IoBase); | |
3339 | ||
3340 | for (i=0; i<pAC->GIni.GIMacsFound; i++) { | |
3341 | spin_lock_irqsave( | |
3342 | &pAC->TxPort[i][TX_PRIO_LOW].TxDesRingLock, Flags); | |
3343 | netif_stop_queue(pAC->dev[i]); | |
3344 | ||
3345 | } | |
3346 | ||
42d1f039 | 3347 | /* |
7152b1d0 WD |
3348 | * adjust number of rx buffers allocated |
3349 | */ | |
3350 | if (NewMtu > 1500) { | |
3351 | /* use less rx buffers */ | |
3352 | for (i=0; i<pAC->GIni.GIMacsFound; i++) { | |
3353 | /* Found more than one port */ | |
42d1f039 | 3354 | if ((pAC->GIni.GIMacsFound == 2 ) && |
7152b1d0 | 3355 | (pAC->RlmtNets == 2)) { |
42d1f039 | 3356 | pAC->RxPort[i].RxFillLimit = |
7152b1d0 WD |
3357 | pAC->RxDescrPerRing - 100; |
3358 | } else { | |
3359 | if (i == pAC->ActivePort) | |
3360 | pAC->RxPort[i].RxFillLimit = | |
3361 | pAC->RxDescrPerRing - 100; | |
3362 | else | |
3363 | pAC->RxPort[i].RxFillLimit = | |
3364 | pAC->RxDescrPerRing - 10; | |
3365 | } | |
3366 | } | |
3367 | } | |
3368 | else { | |
3369 | /* use normal amount of rx buffers */ | |
3370 | for (i=0; i<pAC->GIni.GIMacsFound; i++) { | |
3371 | /* Found more than one port */ | |
42d1f039 | 3372 | if ((pAC->GIni.GIMacsFound == 2 ) && |
7152b1d0 WD |
3373 | (pAC->RlmtNets == 2)) { |
3374 | pAC->RxPort[i].RxFillLimit = 1; | |
3375 | } else { | |
3376 | if (i == pAC->ActivePort) | |
3377 | pAC->RxPort[i].RxFillLimit = 1; | |
3378 | else | |
3379 | pAC->RxPort[i].RxFillLimit = | |
3380 | pAC->RxDescrPerRing - 100; | |
3381 | } | |
3382 | } | |
3383 | } | |
7152b1d0 | 3384 | |
42d1f039 WD |
3385 | SkGeDeInit(pAC, pAC->IoBase); |
3386 | ||
3387 | /* | |
7152b1d0 WD |
3388 | * enable/disable hardware support for long frames |
3389 | */ | |
3390 | if (NewMtu > 1500) { | |
42d1f039 | 3391 | /* pAC->JumboActivated = SK_TRUE; /#* is never set back !!! */ |
7152b1d0 WD |
3392 | pAC->GIni.GIPortUsage = SK_JUMBO_LINK; |
3393 | } | |
3394 | else { | |
42d1f039 | 3395 | if ((pAC->GIni.GIMacsFound == 2 ) && |
7152b1d0 WD |
3396 | (pAC->RlmtNets == 2)) { |
3397 | pAC->GIni.GIPortUsage = SK_MUL_LINK; | |
3398 | } else { | |
3399 | pAC->GIni.GIPortUsage = SK_RED_LINK; | |
3400 | } | |
3401 | } | |
3402 | ||
3403 | SkGeInit( pAC, pAC->IoBase, 1); | |
3404 | SkI2cInit( pAC, pAC->IoBase, 1); | |
3405 | SkEventInit(pAC, pAC->IoBase, 1); | |
3406 | SkPnmiInit( pAC, pAC->IoBase, 1); | |
3407 | SkAddrInit( pAC, pAC->IoBase, 1); | |
3408 | SkRlmtInit( pAC, pAC->IoBase, 1); | |
3409 | SkTimerInit(pAC, pAC->IoBase, 1); | |
42d1f039 | 3410 | |
7152b1d0 WD |
3411 | /* |
3412 | * tschilling: | |
3413 | * Speed and others are set back to default in level 1 init! | |
3414 | */ | |
3415 | GetConfiguration(pAC); | |
42d1f039 | 3416 | |
7152b1d0 WD |
3417 | SkGeInit( pAC, pAC->IoBase, 2); |
3418 | SkI2cInit( pAC, pAC->IoBase, 2); | |
3419 | SkEventInit(pAC, pAC->IoBase, 2); | |
3420 | SkPnmiInit( pAC, pAC->IoBase, 2); | |
3421 | SkAddrInit( pAC, pAC->IoBase, 2); | |
3422 | SkRlmtInit( pAC, pAC->IoBase, 2); | |
3423 | SkTimerInit(pAC, pAC->IoBase, 2); | |
3424 | ||
42d1f039 | 3425 | /* |
7152b1d0 WD |
3426 | * clear and reinit the rx rings here |
3427 | */ | |
3428 | for (i=0; i<pAC->GIni.GIMacsFound; i++) { | |
3429 | ReceiveIrq(pAC, &pAC->RxPort[i], SK_TRUE); | |
3430 | ClearRxRing(pAC, &pAC->RxPort[i]); | |
3431 | FillRxRing(pAC, &pAC->RxPort[i]); | |
3432 | ||
3433 | /* Enable transmit descriptor polling. */ | |
3434 | SkGePollTxD(pAC, pAC->IoBase, i, SK_TRUE); | |
3435 | FillRxRing(pAC, &pAC->RxPort[i]); | |
3436 | }; | |
3437 | ||
3438 | SkGeYellowLED(pAC, pAC->IoBase, 1); | |
3439 | ||
3440 | #ifdef USE_INT_MOD | |
3441 | { | |
3442 | unsigned long ModBase; | |
3443 | ModBase = 53125000 / INTS_PER_SEC; | |
3444 | SK_OUT32(pAC->IoBase, B2_IRQM_INI, ModBase); | |
3445 | SK_OUT32(pAC->IoBase, B2_IRQM_MSK, IRQ_MOD_MASK); | |
3446 | SK_OUT32(pAC->IoBase, B2_IRQM_CTRL, TIM_START); | |
3447 | } | |
3448 | #endif | |
3449 | ||
3450 | netif_start_queue(pAC->dev[pNet->PortNr]); | |
3451 | for (i=pAC->GIni.GIMacsFound-1; i>=0; i--) { | |
3452 | spin_unlock(&pAC->TxPort[i][TX_PRIO_LOW].TxDesRingLock); | |
3453 | } | |
3454 | ||
3455 | /* enable Interrupts */ | |
3456 | SK_OUT32(pAC->IoBase, B0_IMSK, IRQ_MASK); | |
3457 | SK_OUT32(pAC->IoBase, B0_HWE_IMSK, IRQ_HWE_MASK); | |
3458 | ||
3459 | SkEventQueue(pAC, SKGE_RLMT, SK_RLMT_START, EvPara); | |
3460 | SkEventDispatcher(pAC, pAC->IoBase); | |
3461 | ||
3462 | /* Found more than one port */ | |
42d1f039 | 3463 | if ((pAC->GIni.GIMacsFound == 2 ) && |
7152b1d0 WD |
3464 | (pAC->RlmtNets == 2)) { |
3465 | /* Start both ports */ | |
3466 | EvPara.Para32[0] = pAC->RlmtNets; | |
3467 | EvPara.Para32[1] = -1; | |
3468 | SkEventQueue(pAC, SKGE_RLMT, SK_RLMT_SET_NETS, | |
3469 | EvPara); | |
42d1f039 WD |
3470 | |
3471 | ||
7152b1d0 WD |
3472 | EvPara.Para32[1] = -1; |
3473 | EvPara.Para32[0] = pNet->PortNr; | |
3474 | SkEventQueue(pAC, SKGE_RLMT, SK_RLMT_START, EvPara); | |
42d1f039 | 3475 | |
7152b1d0 WD |
3476 | if (pOtherNet->Up) { |
3477 | EvPara.Para32[0] = pOtherNet->PortNr; | |
42d1f039 | 3478 | SkEventQueue(pAC, SKGE_RLMT, |
7152b1d0 WD |
3479 | SK_RLMT_START, EvPara); |
3480 | } | |
3481 | } else { | |
3482 | SkEventQueue(pAC, SKGE_RLMT, SK_RLMT_START, EvPara); | |
3483 | } | |
3484 | ||
3485 | SkEventDispatcher(pAC, pAC->IoBase); | |
3486 | spin_unlock_irqrestore(&pAC->SlowPathLock, Flags); | |
42d1f039 | 3487 | |
7152b1d0 WD |
3488 | return 0; |
3489 | } /* SkGeChangeMtu */ | |
3490 | ||
3491 | ||
3492 | /***************************************************************************** | |
3493 | * | |
53677ef1 | 3494 | * SkGeStats - return ethernet device statistics |
7152b1d0 WD |
3495 | * |
3496 | * Description: | |
3497 | * This function return statistic data about the ethernet device | |
3498 | * to the operating system. | |
3499 | * | |
3500 | * Returns: | |
3501 | * pointer to the statistic structure. | |
3502 | */ | |
3503 | static struct net_device_stats *SkGeStats(struct SK_NET_DEVICE *dev) | |
3504 | { | |
3505 | DEV_NET *pNet = (DEV_NET*) dev->priv; | |
3506 | SK_AC *pAC = pNet->pAC; | |
3507 | SK_PNMI_STRUCT_DATA *pPnmiStruct; /* structure for all Pnmi-Data */ | |
3508 | SK_PNMI_STAT *pPnmiStat; /* pointer to virtual XMAC stat. data */ | |
3509 | SK_PNMI_CONF *pPnmiConf; /* pointer to virtual link config. */ | |
3510 | unsigned int Size; /* size of pnmi struct */ | |
3511 | unsigned long Flags; /* for spin lock */ | |
3512 | ||
3513 | SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_ENTRY, | |
3514 | ("SkGeStats starts now...\n")); | |
3515 | pPnmiStruct = &pAC->PnmiStruct; | |
42d1f039 WD |
3516 | memset(pPnmiStruct, 0, sizeof(SK_PNMI_STRUCT_DATA)); |
3517 | spin_lock_irqsave(&pAC->SlowPathLock, Flags); | |
3518 | Size = SK_PNMI_STRUCT_SIZE; | |
7152b1d0 | 3519 | SkPnmiGetStruct(pAC, pAC->IoBase, pPnmiStruct, &Size, pNet->NetNr); |
42d1f039 WD |
3520 | spin_unlock_irqrestore(&pAC->SlowPathLock, Flags); |
3521 | pPnmiStat = &pPnmiStruct->Stat[0]; | |
3522 | pPnmiConf = &pPnmiStruct->Conf[0]; | |
7152b1d0 WD |
3523 | |
3524 | pAC->stats.rx_packets = (SK_U32) pPnmiStruct->RxDeliveredCts & 0xFFFFFFFF; | |
3525 | pAC->stats.tx_packets = (SK_U32) pPnmiStat->StatTxOkCts & 0xFFFFFFFF; | |
3526 | pAC->stats.rx_bytes = (SK_U32) pPnmiStruct->RxOctetsDeliveredCts; | |
3527 | pAC->stats.tx_bytes = (SK_U32) pPnmiStat->StatTxOctetsOkCts; | |
42d1f039 WD |
3528 | |
3529 | if (pNet->Mtu <= 1500) { | |
3530 | pAC->stats.rx_errors = (SK_U32) pPnmiStruct->InErrorsCts & 0xFFFFFFFF; | |
3531 | } else { | |
3532 | pAC->stats.rx_errors = (SK_U32) ((pPnmiStruct->InErrorsCts - | |
3533 | pPnmiStat->StatRxTooLongCts) & 0xFFFFFFFF); | |
7152b1d0 WD |
3534 | } |
3535 | ||
3536 | ||
3537 | if (pAC->GIni.GP[0].PhyType == SK_PHY_XMAC && pAC->HWRevision < 12) | |
3538 | pAC->stats.rx_errors = pAC->stats.rx_errors - pPnmiStat->StatRxShortsCts; | |
3539 | ||
3540 | pAC->stats.tx_errors = (SK_U32) pPnmiStat->StatTxSingleCollisionCts & 0xFFFFFFFF; | |
3541 | pAC->stats.rx_dropped = (SK_U32) pPnmiStruct->RxNoBufCts & 0xFFFFFFFF; | |
3542 | pAC->stats.tx_dropped = (SK_U32) pPnmiStruct->TxNoBufCts & 0xFFFFFFFF; | |
3543 | pAC->stats.multicast = (SK_U32) pPnmiStat->StatRxMulticastOkCts & 0xFFFFFFFF; | |
3544 | pAC->stats.collisions = (SK_U32) pPnmiStat->StatTxSingleCollisionCts & 0xFFFFFFFF; | |
3545 | ||
3546 | /* detailed rx_errors: */ | |
3547 | pAC->stats.rx_length_errors = (SK_U32) pPnmiStat->StatRxRuntCts & 0xFFFFFFFF; | |
3548 | pAC->stats.rx_over_errors = (SK_U32) pPnmiStat->StatRxFifoOverflowCts & 0xFFFFFFFF; | |
3549 | pAC->stats.rx_crc_errors = (SK_U32) pPnmiStat->StatRxFcsCts & 0xFFFFFFFF; | |
3550 | pAC->stats.rx_frame_errors = (SK_U32) pPnmiStat->StatRxFramingCts & 0xFFFFFFFF; | |
3551 | pAC->stats.rx_fifo_errors = (SK_U32) pPnmiStat->StatRxFifoOverflowCts & 0xFFFFFFFF; | |
3552 | pAC->stats.rx_missed_errors = (SK_U32) pPnmiStat->StatRxMissedCts & 0xFFFFFFFF; | |
3553 | ||
3554 | /* detailed tx_errors */ | |
3555 | pAC->stats.tx_aborted_errors = (SK_U32) 0; | |
3556 | pAC->stats.tx_carrier_errors = (SK_U32) pPnmiStat->StatTxCarrierCts & 0xFFFFFFFF; | |
3557 | pAC->stats.tx_fifo_errors = (SK_U32) pPnmiStat->StatTxFifoUnderrunCts & 0xFFFFFFFF; | |
3558 | pAC->stats.tx_heartbeat_errors = (SK_U32) pPnmiStat->StatTxCarrierCts & 0xFFFFFFFF; | |
3559 | pAC->stats.tx_window_errors = (SK_U32) 0; | |
3560 | ||
3561 | return(&pAC->stats); | |
3562 | } /* SkGeStats */ | |
3563 | ||
3564 | ||
3565 | /***************************************************************************** | |
3566 | * | |
53677ef1 | 3567 | * SkGeIoctl - IO-control function |
7152b1d0 WD |
3568 | * |
3569 | * Description: | |
3570 | * This function is called if an ioctl is issued on the device. | |
3571 | * There are three subfunction for reading, writing and test-writing | |
3572 | * the private MIB data structure (usefull for SysKonnect-internal tools). | |
3573 | * | |
3574 | * Returns: | |
3575 | * 0, if everything is ok | |
3576 | * !=0, on error | |
3577 | */ | |
3578 | static int SkGeIoctl(struct SK_NET_DEVICE *dev, struct ifreq *rq, int cmd) | |
3579 | { | |
3580 | DEV_NET *pNet; | |
3581 | SK_AC *pAC; | |
3582 | ||
3583 | SK_GE_IOCTL Ioctl; | |
3584 | unsigned int Err = 0; | |
3585 | int Size; | |
3586 | ||
3587 | SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_ENTRY, | |
3588 | ("SkGeIoctl starts now...\n")); | |
3589 | ||
3590 | pNet = (DEV_NET*) dev->priv; | |
3591 | pAC = pNet->pAC; | |
42d1f039 | 3592 | |
7152b1d0 WD |
3593 | if(copy_from_user(&Ioctl, rq->ifr_data, sizeof(SK_GE_IOCTL))) { |
3594 | return -EFAULT; | |
3595 | } | |
3596 | ||
3597 | switch(cmd) { | |
3598 | case SK_IOCTL_SETMIB: | |
3599 | case SK_IOCTL_PRESETMIB: | |
3600 | if (!capable(CAP_NET_ADMIN)) return -EPERM; | |
42d1f039 WD |
3601 | case SK_IOCTL_GETMIB: |
3602 | if(copy_from_user(&pAC->PnmiStruct, Ioctl.pData, | |
7152b1d0 WD |
3603 | Ioctl.Len<sizeof(pAC->PnmiStruct)? |
3604 | Ioctl.Len : sizeof(pAC->PnmiStruct))) { | |
3605 | return -EFAULT; | |
3606 | } | |
3607 | Size = SkGeIocMib(pNet, Ioctl.Len, cmd); | |
3608 | if(copy_to_user(Ioctl.pData, &pAC->PnmiStruct, | |
3609 | Ioctl.Len<Size? Ioctl.Len : Size)) { | |
3610 | return -EFAULT; | |
3611 | } | |
3612 | Ioctl.Len = Size; | |
3613 | if(copy_to_user(rq->ifr_data, &Ioctl, sizeof(SK_GE_IOCTL))) { | |
3614 | return -EFAULT; | |
3615 | } | |
3616 | break; | |
3617 | default: | |
3618 | Err = -EOPNOTSUPP; | |
3619 | } | |
3620 | return(Err); | |
3621 | } /* SkGeIoctl */ | |
3622 | ||
3623 | ||
3624 | /***************************************************************************** | |
3625 | * | |
53677ef1 | 3626 | * SkGeIocMib - handle a GetMib, SetMib- or PresetMib-ioctl message |
7152b1d0 WD |
3627 | * |
3628 | * Description: | |
3629 | * This function reads/writes the MIB data using PNMI (Private Network | |
3630 | * Management Interface). | |
3631 | * The destination for the data must be provided with the | |
3632 | * ioctl call and is given to the driver in the form of | |
3633 | * a user space address. | |
3634 | * Copying from the user-provided data area into kernel messages | |
3635 | * and back is done by copy_from_user and copy_to_user calls in | |
3636 | * SkGeIoctl. | |
3637 | * | |
3638 | * Returns: | |
3639 | * returned size from PNMI call | |
3640 | */ | |
3641 | static int SkGeIocMib( | |
3642 | DEV_NET *pNet, /* pointer to the adapter context */ | |
3643 | unsigned int Size, /* length of ioctl data */ | |
3644 | int mode) /* flag for set/preset */ | |
3645 | { | |
3646 | unsigned long Flags; /* for spin lock */ | |
3647 | SK_AC *pAC; | |
3648 | ||
3649 | SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_ENTRY, | |
3650 | ("SkGeIocMib starts now...\n")); | |
3651 | pAC = pNet->pAC; | |
3652 | /* access MIB */ | |
3653 | spin_lock_irqsave(&pAC->SlowPathLock, Flags); | |
3654 | switch(mode) { | |
3655 | case SK_IOCTL_GETMIB: | |
3656 | SkPnmiGetStruct(pAC, pAC->IoBase, &pAC->PnmiStruct, &Size, | |
3657 | pNet->NetNr); | |
3658 | break; | |
3659 | case SK_IOCTL_PRESETMIB: | |
3660 | SkPnmiPreSetStruct(pAC, pAC->IoBase, &pAC->PnmiStruct, &Size, | |
3661 | pNet->NetNr); | |
3662 | break; | |
3663 | case SK_IOCTL_SETMIB: | |
3664 | SkPnmiSetStruct(pAC, pAC->IoBase, &pAC->PnmiStruct, &Size, | |
3665 | pNet->NetNr); | |
3666 | break; | |
3667 | default: | |
3668 | break; | |
3669 | } | |
3670 | spin_unlock_irqrestore(&pAC->SlowPathLock, Flags); | |
3671 | SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_ENTRY, | |
3672 | ("MIB data access succeeded\n")); | |
3673 | return (Size); | |
3674 | } /* SkGeIocMib */ | |
3675 | #endif | |
3676 | ||
3677 | ||
3678 | /***************************************************************************** | |
3679 | * | |
53677ef1 | 3680 | * GetConfiguration - read configuration information |
7152b1d0 WD |
3681 | * |
3682 | * Description: | |
3683 | * This function reads per-adapter configuration information from | |
3684 | * the options provided on the command line. | |
3685 | * | |
3686 | * Returns: | |
3687 | * none | |
3688 | */ | |
3689 | static void GetConfiguration( | |
3690 | SK_AC *pAC) /* pointer to the adapter context structure */ | |
3691 | { | |
3692 | SK_I32 Port; /* preferred port */ | |
3693 | int LinkSpeed; /* Link speed */ | |
3694 | int AutoNeg; /* auto negotiation off (0) or on (1) */ | |
3695 | int DuplexCap; /* duplex capabilities (0=both, 1=full, 2=half */ | |
3696 | int MSMode; /* master / slave mode selection */ | |
3697 | SK_BOOL AutoSet; | |
3698 | SK_BOOL DupSet; | |
3699 | /* | |
3700 | * The two parameters AutoNeg. and DuplexCap. map to one configuration | |
3701 | * parameter. The mapping is described by this table: | |
3702 | * DuplexCap -> | both | full | half | | |
3703 | * AutoNeg | | | | | |
3704 | * ----------------------------------------------------------------- | |
3705 | * Off | illegal | Full | Half | | |
3706 | * ----------------------------------------------------------------- | |
3707 | * On | AutoBoth | AutoFull | AutoHalf | | |
3708 | * ----------------------------------------------------------------- | |
3709 | * Sense | AutoSense | AutoSense | AutoSense | | |
3710 | */ | |
42d1f039 WD |
3711 | int Capabilities[3][3] = |
3712 | { { -1, SK_LMODE_FULL, SK_LMODE_HALF}, | |
7152b1d0 WD |
3713 | {SK_LMODE_AUTOBOTH, SK_LMODE_AUTOFULL, SK_LMODE_AUTOHALF}, |
3714 | {SK_LMODE_AUTOSENSE, SK_LMODE_AUTOSENSE, SK_LMODE_AUTOSENSE} }; | |
3715 | #define DC_BOTH 0 | |
3716 | #define DC_FULL 1 | |
3717 | #define DC_HALF 2 | |
3718 | #define AN_OFF 0 | |
3719 | #define AN_ON 1 | |
3720 | #define AN_SENS 2 | |
3721 | ||
3722 | /* settings for port A */ | |
3723 | /* settings link speed */ | |
53677ef1 | 3724 | LinkSpeed = SK_LSPEED_AUTO; /* default: do auto select */ |
7152b1d0 WD |
3725 | if (Speed_A != NULL && pAC->Index<SK_MAX_CARD_PARAM && |
3726 | Speed_A[pAC->Index] != NULL) { | |
3727 | if (strcmp(Speed_A[pAC->Index],"")==0) { | |
3728 | LinkSpeed = SK_LSPEED_AUTO; | |
3729 | } | |
3730 | else if (strcmp(Speed_A[pAC->Index],"Auto")==0) { | |
3731 | LinkSpeed = SK_LSPEED_AUTO; | |
3732 | } | |
3733 | else if (strcmp(Speed_A[pAC->Index],"10")==0) { | |
3734 | LinkSpeed = SK_LSPEED_10MBPS; | |
3735 | } | |
3736 | else if (strcmp(Speed_A[pAC->Index],"100")==0) { | |
3737 | LinkSpeed = SK_LSPEED_100MBPS; | |
3738 | } | |
3739 | else if (strcmp(Speed_A[pAC->Index],"1000")==0) { | |
3740 | LinkSpeed = SK_LSPEED_1000MBPS; | |
3741 | } | |
3742 | else printk("%s: Illegal value for Speed_A\n", | |
3743 | pAC->dev[0]->name); | |
3744 | } | |
3745 | ||
3746 | /* Check speed parameter */ | |
3747 | /* Only copper type adapter and GE V2 cards */ | |
3748 | if (((pAC->GIni.GIChipId != CHIP_ID_YUKON) || | |
3749 | (pAC->GIni.GICopperType != SK_TRUE)) && | |
42d1f039 | 3750 | ((LinkSpeed != SK_LSPEED_AUTO) && |
7152b1d0 WD |
3751 | (LinkSpeed != SK_LSPEED_1000MBPS))) { |
3752 | printk("%s: Illegal value for Speed_A. " | |
3753 | "Not a copper card or GE V2 card\n Using " | |
3754 | "speed 1000\n", pAC->dev[0]->name); | |
3755 | LinkSpeed = SK_LSPEED_1000MBPS; | |
3756 | } | |
3757 | pAC->GIni.GP[0].PLinkSpeed = LinkSpeed; | |
3758 | ||
3759 | /* Autonegotiation */ | |
3760 | AutoNeg = AN_ON; /* tschilling: Default: Autonegotiation on! */ | |
3761 | AutoSet = SK_FALSE; | |
3762 | if (AutoNeg_A != NULL && pAC->Index<SK_MAX_CARD_PARAM && | |
3763 | AutoNeg_A[pAC->Index] != NULL) { | |
3764 | AutoSet = SK_TRUE; | |
3765 | if (strcmp(AutoNeg_A[pAC->Index],"")==0) { | |
3766 | AutoSet = SK_FALSE; | |
3767 | } | |
3768 | else if (strcmp(AutoNeg_A[pAC->Index],"On")==0) { | |
3769 | AutoNeg = AN_ON; | |
3770 | } | |
3771 | else if (strcmp(AutoNeg_A[pAC->Index],"Off")==0) { | |
3772 | AutoNeg = AN_OFF; | |
3773 | } | |
3774 | else if (strcmp(AutoNeg_A[pAC->Index],"Sense")==0) { | |
3775 | AutoNeg = AN_SENS; | |
3776 | } | |
3777 | else printk("%s: Illegal value for AutoNeg_A\n", | |
3778 | pAC->dev[0]->name); | |
3779 | } | |
3780 | ||
3781 | DuplexCap = DC_BOTH; | |
3782 | DupSet = SK_FALSE; | |
3783 | if (DupCap_A != NULL && pAC->Index<SK_MAX_CARD_PARAM && | |
3784 | DupCap_A[pAC->Index] != NULL) { | |
3785 | DupSet = SK_TRUE; | |
3786 | if (strcmp(DupCap_A[pAC->Index],"")==0) { | |
3787 | DupSet = SK_FALSE; | |
3788 | } | |
3789 | else if (strcmp(DupCap_A[pAC->Index],"Both")==0) { | |
3790 | DuplexCap = DC_BOTH; | |
3791 | } | |
3792 | else if (strcmp(DupCap_A[pAC->Index],"Full")==0) { | |
3793 | DuplexCap = DC_FULL; | |
3794 | } | |
3795 | else if (strcmp(DupCap_A[pAC->Index],"Half")==0) { | |
3796 | DuplexCap = DC_HALF; | |
3797 | } | |
3798 | else printk("%s: Illegal value for DupCap_A\n", | |
3799 | pAC->dev[0]->name); | |
3800 | } | |
42d1f039 | 3801 | |
7152b1d0 WD |
3802 | /* check for illegal combinations */ |
3803 | if (AutoSet && AutoNeg==AN_SENS && DupSet) { | |
3804 | printk("%s, Port A: DuplexCapabilities" | |
3805 | " ignored using Sense mode\n", pAC->dev[0]->name); | |
3806 | } | |
3807 | if (AutoSet && AutoNeg==AN_OFF && DupSet && DuplexCap==DC_BOTH){ | |
3808 | printk("%s, Port A: Illegal combination" | |
3809 | " of values AutoNeg. and DuplexCap.\n Using " | |
3810 | "Full Duplex\n", pAC->dev[0]->name); | |
3811 | ||
3812 | DuplexCap = DC_FULL; | |
3813 | } | |
3814 | if (AutoSet && AutoNeg==AN_OFF && !DupSet) { | |
3815 | DuplexCap = DC_FULL; | |
3816 | } | |
42d1f039 | 3817 | |
7152b1d0 WD |
3818 | if (!AutoSet && DupSet) { |
3819 | printk("%s, Port A: Duplex setting not" | |
3820 | " possible in\n default AutoNegotiation mode" | |
3821 | " (Sense).\n Using AutoNegotiation On\n", | |
3822 | pAC->dev[0]->name); | |
3823 | AutoNeg = AN_ON; | |
3824 | } | |
42d1f039 | 3825 | |
7152b1d0 WD |
3826 | /* set the desired mode */ |
3827 | pAC->GIni.GP[0].PLinkModeConf = | |
3828 | Capabilities[AutoNeg][DuplexCap]; | |
42d1f039 | 3829 | |
7152b1d0 WD |
3830 | pAC->GIni.GP[0].PFlowCtrlMode = SK_FLOW_MODE_SYM_OR_REM; |
3831 | if (FlowCtrl_A != NULL && pAC->Index<SK_MAX_CARD_PARAM && | |
3832 | FlowCtrl_A[pAC->Index] != NULL) { | |
3833 | if (strcmp(FlowCtrl_A[pAC->Index],"") == 0) { | |
3834 | } | |
3835 | else if (strcmp(FlowCtrl_A[pAC->Index],"SymOrRem") == 0) { | |
3836 | pAC->GIni.GP[0].PFlowCtrlMode = | |
3837 | SK_FLOW_MODE_SYM_OR_REM; | |
3838 | } | |
3839 | else if (strcmp(FlowCtrl_A[pAC->Index],"Sym")==0) { | |
3840 | pAC->GIni.GP[0].PFlowCtrlMode = | |
3841 | SK_FLOW_MODE_SYMMETRIC; | |
3842 | } | |
3843 | else if (strcmp(FlowCtrl_A[pAC->Index],"LocSend")==0) { | |
3844 | pAC->GIni.GP[0].PFlowCtrlMode = | |
3845 | SK_FLOW_MODE_LOC_SEND; | |
3846 | } | |
3847 | else if (strcmp(FlowCtrl_A[pAC->Index],"None")==0) { | |
3848 | pAC->GIni.GP[0].PFlowCtrlMode = | |
3849 | SK_FLOW_MODE_NONE; | |
3850 | } | |
3851 | else printk("Illegal value for FlowCtrl_A\n"); | |
3852 | } | |
3853 | if (AutoNeg==AN_OFF && pAC->GIni.GP[0].PFlowCtrlMode!= | |
3854 | SK_FLOW_MODE_NONE) { | |
3855 | printk("%s, Port A: FlowControl" | |
3856 | " impossible without AutoNegotiation," | |
3857 | " disabled\n", pAC->dev[0]->name); | |
3858 | pAC->GIni.GP[0].PFlowCtrlMode = SK_FLOW_MODE_NONE; | |
3859 | } | |
3860 | ||
3861 | MSMode = SK_MS_MODE_AUTO; /* default: do auto select */ | |
3862 | if (Role_A != NULL && pAC->Index<SK_MAX_CARD_PARAM && | |
3863 | Role_A[pAC->Index] != NULL) { | |
3864 | if (strcmp(Role_A[pAC->Index],"")==0) { | |
3865 | } | |
3866 | else if (strcmp(Role_A[pAC->Index],"Auto")==0) { | |
3867 | MSMode = SK_MS_MODE_AUTO; | |
3868 | } | |
3869 | else if (strcmp(Role_A[pAC->Index],"Master")==0) { | |
3870 | MSMode = SK_MS_MODE_MASTER; | |
3871 | } | |
3872 | else if (strcmp(Role_A[pAC->Index],"Slave")==0) { | |
3873 | MSMode = SK_MS_MODE_SLAVE; | |
3874 | } | |
3875 | else printk("%s: Illegal value for Role_A\n", | |
3876 | pAC->dev[0]->name); | |
3877 | } | |
3878 | pAC->GIni.GP[0].PMSMode = MSMode; | |
42d1f039 WD |
3879 | |
3880 | ||
7152b1d0 WD |
3881 | /* settings for port B */ |
3882 | /* settings link speed */ | |
53677ef1 | 3883 | LinkSpeed = SK_LSPEED_AUTO; /* default: do auto select */ |
7152b1d0 WD |
3884 | if (Speed_B != NULL && pAC->Index<SK_MAX_CARD_PARAM && |
3885 | Speed_B[pAC->Index] != NULL) { | |
3886 | if (strcmp(Speed_B[pAC->Index],"")==0) { | |
3887 | LinkSpeed = SK_LSPEED_AUTO; | |
3888 | } | |
3889 | else if (strcmp(Speed_B[pAC->Index],"Auto")==0) { | |
3890 | LinkSpeed = SK_LSPEED_AUTO; | |
3891 | } | |
3892 | else if (strcmp(Speed_B[pAC->Index],"10")==0) { | |
3893 | LinkSpeed = SK_LSPEED_10MBPS; | |
3894 | } | |
3895 | else if (strcmp(Speed_B[pAC->Index],"100")==0) { | |
3896 | LinkSpeed = SK_LSPEED_100MBPS; | |
3897 | } | |
3898 | else if (strcmp(Speed_B[pAC->Index],"1000")==0) { | |
3899 | LinkSpeed = SK_LSPEED_1000MBPS; | |
3900 | } | |
3901 | else printk("%s: Illegal value for Speed_B\n", | |
3902 | pAC->dev[1]->name); | |
3903 | } | |
3904 | ||
3905 | /* Check speed parameter */ | |
3906 | /* Only copper type adapter and GE V2 cards */ | |
3907 | if (((pAC->GIni.GIChipId != CHIP_ID_YUKON) || | |
3908 | (pAC->GIni.GICopperType != SK_TRUE)) && | |
42d1f039 | 3909 | ((LinkSpeed != SK_LSPEED_AUTO) && |
7152b1d0 WD |
3910 | (LinkSpeed != SK_LSPEED_1000MBPS))) { |
3911 | printk("%s: Illegal value for Speed_B. " | |
3912 | "Not a copper card or GE V2 card\n Using " | |
3913 | "speed 1000\n", pAC->dev[1]->name); | |
3914 | LinkSpeed = SK_LSPEED_1000MBPS; | |
3915 | } | |
3916 | pAC->GIni.GP[1].PLinkSpeed = LinkSpeed; | |
3917 | ||
3918 | /* Auto negotiation */ | |
3919 | AutoNeg = AN_SENS; /* default: do auto Sense */ | |
3920 | AutoSet = SK_FALSE; | |
3921 | if (AutoNeg_B != NULL && pAC->Index<SK_MAX_CARD_PARAM && | |
3922 | AutoNeg_B[pAC->Index] != NULL) { | |
3923 | AutoSet = SK_TRUE; | |
3924 | if (strcmp(AutoNeg_B[pAC->Index],"")==0) { | |
3925 | AutoSet = SK_FALSE; | |
3926 | } | |
3927 | else if (strcmp(AutoNeg_B[pAC->Index],"On")==0) { | |
3928 | AutoNeg = AN_ON; | |
3929 | } | |
3930 | else if (strcmp(AutoNeg_B[pAC->Index],"Off")==0) { | |
3931 | AutoNeg = AN_OFF; | |
3932 | } | |
3933 | else if (strcmp(AutoNeg_B[pAC->Index],"Sense")==0) { | |
3934 | AutoNeg = AN_SENS; | |
3935 | } | |
3936 | else printk("Illegal value for AutoNeg_B\n"); | |
3937 | } | |
3938 | ||
3939 | DuplexCap = DC_BOTH; | |
3940 | DupSet = SK_FALSE; | |
3941 | if (DupCap_B != NULL && pAC->Index<SK_MAX_CARD_PARAM && | |
3942 | DupCap_B[pAC->Index] != NULL) { | |
3943 | DupSet = SK_TRUE; | |
3944 | if (strcmp(DupCap_B[pAC->Index],"")==0) { | |
3945 | DupSet = SK_FALSE; | |
3946 | } | |
3947 | else if (strcmp(DupCap_B[pAC->Index],"Both")==0) { | |
3948 | DuplexCap = DC_BOTH; | |
3949 | } | |
3950 | else if (strcmp(DupCap_B[pAC->Index],"Full")==0) { | |
3951 | DuplexCap = DC_FULL; | |
3952 | } | |
3953 | else if (strcmp(DupCap_B[pAC->Index],"Half")==0) { | |
3954 | DuplexCap = DC_HALF; | |
3955 | } | |
3956 | else printk("Illegal value for DupCap_B\n"); | |
3957 | } | |
42d1f039 | 3958 | |
7152b1d0 WD |
3959 | /* check for illegal combinations */ |
3960 | if (AutoSet && AutoNeg==AN_SENS && DupSet) { | |
3961 | printk("%s, Port B: DuplexCapabilities" | |
3962 | " ignored using Sense mode\n", pAC->dev[1]->name); | |
3963 | } | |
3964 | if (AutoSet && AutoNeg==AN_OFF && DupSet && DuplexCap==DC_BOTH){ | |
3965 | printk("%s, Port B: Illegal combination" | |
3966 | " of values AutoNeg. and DuplexCap.\n Using " | |
3967 | "Full Duplex\n", pAC->dev[1]->name); | |
3968 | ||
3969 | DuplexCap = DC_FULL; | |
3970 | } | |
3971 | if (AutoSet && AutoNeg==AN_OFF && !DupSet) { | |
3972 | DuplexCap = DC_FULL; | |
3973 | } | |
42d1f039 | 3974 | |
7152b1d0 WD |
3975 | if (!AutoSet && DupSet) { |
3976 | printk("%s, Port B: Duplex setting not" | |
3977 | " possible in\n default AutoNegotiation mode" | |
3978 | " (Sense).\n Using AutoNegotiation On\n", | |
3979 | pAC->dev[1]->name); | |
3980 | AutoNeg = AN_ON; | |
3981 | } | |
3982 | ||
3983 | /* set the desired mode */ | |
3984 | pAC->GIni.GP[1].PLinkModeConf = | |
3985 | Capabilities[AutoNeg][DuplexCap]; | |
3986 | ||
3987 | pAC->GIni.GP[1].PFlowCtrlMode = SK_FLOW_MODE_SYM_OR_REM; | |
3988 | if (FlowCtrl_B != NULL && pAC->Index<SK_MAX_CARD_PARAM && | |
3989 | FlowCtrl_B[pAC->Index] != NULL) { | |
3990 | if (strcmp(FlowCtrl_B[pAC->Index],"") == 0) { | |
3991 | } | |
3992 | else if (strcmp(FlowCtrl_B[pAC->Index],"SymOrRem") == 0) { | |
3993 | pAC->GIni.GP[1].PFlowCtrlMode = | |
3994 | SK_FLOW_MODE_SYM_OR_REM; | |
3995 | } | |
3996 | else if (strcmp(FlowCtrl_B[pAC->Index],"Sym")==0) { | |
3997 | pAC->GIni.GP[1].PFlowCtrlMode = | |
3998 | SK_FLOW_MODE_SYMMETRIC; | |
3999 | } | |
4000 | else if (strcmp(FlowCtrl_B[pAC->Index],"LocSend")==0) { | |
4001 | pAC->GIni.GP[1].PFlowCtrlMode = | |
4002 | SK_FLOW_MODE_LOC_SEND; | |
4003 | } | |
4004 | else if (strcmp(FlowCtrl_B[pAC->Index],"None")==0) { | |
4005 | pAC->GIni.GP[1].PFlowCtrlMode = | |
4006 | SK_FLOW_MODE_NONE; | |
4007 | } | |
4008 | else printk("Illegal value for FlowCtrl_B\n"); | |
4009 | } | |
4010 | if (AutoNeg==AN_OFF && pAC->GIni.GP[1].PFlowCtrlMode!= | |
4011 | SK_FLOW_MODE_NONE) { | |
4012 | printk("%s, Port B: FlowControl" | |
4013 | " impossible without AutoNegotiation," | |
4014 | " disabled\n", pAC->dev[1]->name); | |
4015 | pAC->GIni.GP[1].PFlowCtrlMode = SK_FLOW_MODE_NONE; | |
4016 | } | |
4017 | ||
4018 | MSMode = SK_MS_MODE_AUTO; /* default: do auto select */ | |
4019 | if (Role_B != NULL && pAC->Index<SK_MAX_CARD_PARAM && | |
4020 | Role_B[pAC->Index] != NULL) { | |
4021 | if (strcmp(Role_B[pAC->Index],"")==0) { | |
4022 | } | |
4023 | else if (strcmp(Role_B[pAC->Index],"Auto")==0) { | |
4024 | MSMode = SK_MS_MODE_AUTO; | |
4025 | } | |
4026 | else if (strcmp(Role_B[pAC->Index],"Master")==0) { | |
4027 | MSMode = SK_MS_MODE_MASTER; | |
4028 | } | |
4029 | else if (strcmp(Role_B[pAC->Index],"Slave")==0) { | |
4030 | MSMode = SK_MS_MODE_SLAVE; | |
4031 | } | |
4032 | else printk("%s: Illegal value for Role_B\n", | |
4033 | pAC->dev[1]->name); | |
4034 | } | |
4035 | pAC->GIni.GP[1].PMSMode = MSMode; | |
42d1f039 WD |
4036 | |
4037 | ||
7152b1d0 WD |
4038 | /* settings for both ports */ |
4039 | pAC->ActivePort = 0; | |
4040 | if (PrefPort != NULL && pAC->Index<SK_MAX_CARD_PARAM && | |
4041 | PrefPort[pAC->Index] != NULL) { | |
4042 | if (strcmp(PrefPort[pAC->Index],"") == 0) { /* Auto */ | |
4043 | pAC->ActivePort = 0; | |
4044 | pAC->Rlmt.Net[0].Preference = -1; /* auto */ | |
4045 | pAC->Rlmt.Net[0].PrefPort = 0; | |
4046 | } | |
4047 | else if (strcmp(PrefPort[pAC->Index],"A") == 0) { | |
4048 | /* | |
4049 | * do not set ActivePort here, thus a port | |
4050 | * switch is issued after net up. | |
4051 | */ | |
4052 | Port = 0; | |
4053 | pAC->Rlmt.Net[0].Preference = Port; | |
4054 | pAC->Rlmt.Net[0].PrefPort = Port; | |
4055 | } | |
4056 | else if (strcmp(PrefPort[pAC->Index],"B") == 0) { | |
4057 | /* | |
4058 | * do not set ActivePort here, thus a port | |
4059 | * switch is issued after net up. | |
4060 | */ | |
4061 | Port = 1; | |
4062 | pAC->Rlmt.Net[0].Preference = Port; | |
4063 | pAC->Rlmt.Net[0].PrefPort = Port; | |
4064 | } | |
4065 | else printk("%s: Illegal value for PrefPort\n", | |
4066 | pAC->dev[0]->name); | |
4067 | } | |
4068 | ||
4069 | pAC->RlmtNets = 1; | |
4070 | ||
4071 | if (RlmtMode != NULL && pAC->Index<SK_MAX_CARD_PARAM && | |
4072 | RlmtMode[pAC->Index] != NULL) { | |
4073 | if (strcmp(RlmtMode[pAC->Index], "") == 0) { | |
4074 | pAC->RlmtMode = 0; | |
4075 | } | |
4076 | else if (strcmp(RlmtMode[pAC->Index], "CheckLinkState") == 0) { | |
4077 | pAC->RlmtMode = SK_RLMT_CHECK_LINK; | |
4078 | } | |
4079 | else if (strcmp(RlmtMode[pAC->Index], "CheckLocalPort") == 0) { | |
4080 | pAC->RlmtMode = SK_RLMT_CHECK_LINK | | |
4081 | SK_RLMT_CHECK_LOC_LINK; | |
4082 | } | |
4083 | else if (strcmp(RlmtMode[pAC->Index], "CheckSeg") == 0) { | |
4084 | pAC->RlmtMode = SK_RLMT_CHECK_LINK | | |
42d1f039 | 4085 | SK_RLMT_CHECK_LOC_LINK | |
7152b1d0 WD |
4086 | SK_RLMT_CHECK_SEG; |
4087 | } | |
4088 | else if ((strcmp(RlmtMode[pAC->Index], "DualNet") == 0) && | |
4089 | (pAC->GIni.GIMacsFound == 2)) { | |
4090 | pAC->RlmtMode = SK_RLMT_CHECK_LINK; | |
4091 | pAC->RlmtNets = 2; | |
4092 | } | |
4093 | else { | |
4094 | printk("%s: Illegal value for" | |
4095 | " RlmtMode, using default\n", pAC->dev[0]->name); | |
4096 | pAC->RlmtMode = 0; | |
4097 | } | |
4098 | } | |
4099 | else { | |
4100 | pAC->RlmtMode = 0; | |
4101 | } | |
4102 | } /* GetConfiguration */ | |
4103 | ||
4104 | ||
4105 | /***************************************************************************** | |
4106 | * | |
53677ef1 | 4107 | * ProductStr - return a adapter identification string from vpd |
7152b1d0 WD |
4108 | * |
4109 | * Description: | |
4110 | * This function reads the product name string from the vpd area | |
4111 | * and puts it the field pAC->DeviceString. | |
4112 | * | |
4113 | * Returns: N/A | |
4114 | */ | |
4115 | static void ProductStr( | |
4116 | SK_AC *pAC /* pointer to adapter context */ | |
4117 | ) | |
4118 | { | |
4119 | int StrLen = 80; /* length of the string, defined in SK_AC */ | |
4120 | char Keyword[] = VPD_NAME; /* vpd productname identifier */ | |
4121 | int ReturnCode; /* return code from vpd_read */ | |
4122 | unsigned long Flags; | |
4123 | ||
4124 | spin_lock_irqsave(&pAC->SlowPathLock, Flags); | |
4125 | ReturnCode = VpdRead(pAC, pAC->IoBase, Keyword, pAC->DeviceStr, | |
4126 | &StrLen); | |
4127 | spin_unlock_irqrestore(&pAC->SlowPathLock, Flags); | |
4128 | if (ReturnCode != 0) { | |
4129 | /* there was an error reading the vpd data */ | |
4130 | SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_ERROR, | |
4131 | ("Error reading VPD data: %d\n", ReturnCode)); | |
4132 | pAC->DeviceStr[0] = '\0'; | |
4133 | } | |
4134 | } /* ProductStr */ | |
4135 | ||
4136 | ||
7152b1d0 WD |
4137 | /****************************************************************************/ |
4138 | /* functions for common modules *********************************************/ | |
4139 | /****************************************************************************/ | |
4140 | ||
4141 | ||
4142 | /***************************************************************************** | |
4143 | * | |
4144 | * SkDrvAllocRlmtMbuf - allocate an RLMT mbuf | |
4145 | * | |
4146 | * Description: | |
4147 | * This routine returns an RLMT mbuf or NULL. The RLMT Mbuf structure | |
4148 | * is embedded into a socket buff data area. | |
4149 | * | |
4150 | * Context: | |
4151 | * runtime | |
4152 | * | |
4153 | * Returns: | |
4154 | * NULL or pointer to Mbuf. | |
4155 | */ | |
4156 | SK_MBUF *SkDrvAllocRlmtMbuf( | |
4157 | SK_AC *pAC, /* pointer to adapter context */ | |
4158 | SK_IOC IoC, /* the IO-context */ | |
4159 | unsigned BufferSize) /* size of the requested buffer */ | |
4160 | { | |
4161 | SK_MBUF *pRlmtMbuf; /* pointer to a new rlmt-mbuf structure */ | |
4162 | struct sk_buff *pMsgBlock; /* pointer to a new message block */ | |
4163 | ||
4164 | pMsgBlock = alloc_skb(BufferSize + sizeof(SK_MBUF), GFP_ATOMIC); | |
4165 | if (pMsgBlock == NULL) { | |
4166 | return (NULL); | |
4167 | } | |
4168 | pRlmtMbuf = (SK_MBUF*) pMsgBlock->data; | |
4169 | skb_reserve(pMsgBlock, sizeof(SK_MBUF)); | |
4170 | pRlmtMbuf->pNext = NULL; | |
4171 | pRlmtMbuf->pOs = pMsgBlock; | |
4172 | pRlmtMbuf->pData = pMsgBlock->data; /* Data buffer. */ | |
4173 | pRlmtMbuf->Size = BufferSize; /* Data buffer size. */ | |
4174 | pRlmtMbuf->Length = 0; /* Length of packet (<= Size). */ | |
4175 | return (pRlmtMbuf); | |
4176 | ||
4177 | } /* SkDrvAllocRlmtMbuf */ | |
4178 | ||
4179 | ||
4180 | /***************************************************************************** | |
4181 | * | |
4182 | * SkDrvFreeRlmtMbuf - free an RLMT mbuf | |
4183 | * | |
4184 | * Description: | |
4185 | * This routine frees one or more RLMT mbuf(s). | |
4186 | * | |
4187 | * Context: | |
4188 | * runtime | |
4189 | * | |
4190 | * Returns: | |
4191 | * Nothing | |
4192 | */ | |
4193 | void SkDrvFreeRlmtMbuf( | |
42d1f039 WD |
4194 | SK_AC *pAC, /* pointer to adapter context */ |
4195 | SK_IOC IoC, /* the IO-context */ | |
7152b1d0 WD |
4196 | SK_MBUF *pMbuf) /* size of the requested buffer */ |
4197 | { | |
4198 | SK_MBUF *pFreeMbuf; | |
4199 | SK_MBUF *pNextMbuf; | |
4200 | ||
4201 | pFreeMbuf = pMbuf; | |
4202 | do { | |
4203 | pNextMbuf = pFreeMbuf->pNext; | |
4204 | DEV_KFREE_SKB_ANY(pFreeMbuf->pOs); | |
4205 | pFreeMbuf = pNextMbuf; | |
4206 | } while ( pFreeMbuf != NULL ); | |
4207 | } /* SkDrvFreeRlmtMbuf */ | |
4208 | ||
4209 | ||
4210 | /***************************************************************************** | |
4211 | * | |
4212 | * SkOsGetTime - provide a time value | |
4213 | * | |
4214 | * Description: | |
4215 | * This routine provides a time value. The unit is 1/HZ (defined by Linux). | |
4216 | * It is not used for absolute time, but only for time differences. | |
4217 | * | |
4218 | * | |
4219 | * Returns: | |
4220 | * Time value | |
4221 | */ | |
4222 | SK_U64 SkOsGetTime(SK_AC *pAC) | |
4223 | { | |
4224 | #if 0 | |
4225 | return jiffies; | |
4226 | #else | |
4227 | return get_timer(0); | |
4228 | #endif | |
4229 | } /* SkOsGetTime */ | |
4230 | ||
4231 | ||
4232 | /***************************************************************************** | |
4233 | * | |
4234 | * SkPciReadCfgDWord - read a 32 bit value from pci config space | |
4235 | * | |
4236 | * Description: | |
4237 | * This routine reads a 32 bit value from the pci configuration | |
4238 | * space. | |
4239 | * | |
4240 | * Returns: | |
4241 | * 0 - indicate everything worked ok. | |
4242 | * != 0 - error indication | |
4243 | */ | |
4244 | int SkPciReadCfgDWord( | |
4245 | SK_AC *pAC, /* Adapter Control structure pointer */ | |
4246 | int PciAddr, /* PCI register address */ | |
4247 | SK_U32 *pVal) /* pointer to store the read value */ | |
4248 | { | |
4249 | pci_read_config_dword(pAC->PciDev, PciAddr, pVal); | |
4250 | return(0); | |
4251 | } /* SkPciReadCfgDWord */ | |
4252 | ||
4253 | ||
4254 | /***************************************************************************** | |
4255 | * | |
4256 | * SkPciReadCfgWord - read a 16 bit value from pci config space | |
4257 | * | |
4258 | * Description: | |
4259 | * This routine reads a 16 bit value from the pci configuration | |
4260 | * space. | |
4261 | * | |
4262 | * Returns: | |
4263 | * 0 - indicate everything worked ok. | |
4264 | * != 0 - error indication | |
4265 | */ | |
4266 | int SkPciReadCfgWord( | |
4267 | SK_AC *pAC, /* Adapter Control structure pointer */ | |
4268 | int PciAddr, /* PCI register address */ | |
4269 | SK_U16 *pVal) /* pointer to store the read value */ | |
4270 | { | |
4271 | pci_read_config_word(pAC->PciDev, PciAddr, pVal); | |
4272 | return(0); | |
4273 | } /* SkPciReadCfgWord */ | |
4274 | ||
4275 | ||
4276 | /***************************************************************************** | |
4277 | * | |
4278 | * SkPciReadCfgByte - read a 8 bit value from pci config space | |
4279 | * | |
4280 | * Description: | |
4281 | * This routine reads a 8 bit value from the pci configuration | |
4282 | * space. | |
4283 | * | |
4284 | * Returns: | |
4285 | * 0 - indicate everything worked ok. | |
4286 | * != 0 - error indication | |
4287 | */ | |
4288 | int SkPciReadCfgByte( | |
4289 | SK_AC *pAC, /* Adapter Control structure pointer */ | |
4290 | int PciAddr, /* PCI register address */ | |
4291 | SK_U8 *pVal) /* pointer to store the read value */ | |
4292 | { | |
4293 | pci_read_config_byte(pAC->PciDev, PciAddr, pVal); | |
4294 | return(0); | |
4295 | } /* SkPciReadCfgByte */ | |
4296 | ||
4297 | ||
4298 | /***************************************************************************** | |
4299 | * | |
4300 | * SkPciWriteCfgDWord - write a 32 bit value to pci config space | |
4301 | * | |
4302 | * Description: | |
4303 | * This routine writes a 32 bit value to the pci configuration | |
4304 | * space. | |
4305 | * | |
4306 | * Returns: | |
4307 | * 0 - indicate everything worked ok. | |
4308 | * != 0 - error indication | |
4309 | */ | |
4310 | int SkPciWriteCfgDWord( | |
4311 | SK_AC *pAC, /* Adapter Control structure pointer */ | |
4312 | int PciAddr, /* PCI register address */ | |
4313 | SK_U32 Val) /* pointer to store the read value */ | |
4314 | { | |
4315 | pci_write_config_dword(pAC->PciDev, PciAddr, Val); | |
4316 | return(0); | |
4317 | } /* SkPciWriteCfgDWord */ | |
4318 | ||
4319 | ||
4320 | /***************************************************************************** | |
4321 | * | |
4322 | * SkPciWriteCfgWord - write a 16 bit value to pci config space | |
4323 | * | |
4324 | * Description: | |
4325 | * This routine writes a 16 bit value to the pci configuration | |
4326 | * space. The flag PciConfigUp indicates whether the config space | |
4327 | * is accesible or must be set up first. | |
4328 | * | |
4329 | * Returns: | |
4330 | * 0 - indicate everything worked ok. | |
4331 | * != 0 - error indication | |
4332 | */ | |
4333 | int SkPciWriteCfgWord( | |
4334 | SK_AC *pAC, /* Adapter Control structure pointer */ | |
4335 | int PciAddr, /* PCI register address */ | |
4336 | SK_U16 Val) /* pointer to store the read value */ | |
4337 | { | |
4338 | pci_write_config_word(pAC->PciDev, PciAddr, Val); | |
4339 | return(0); | |
4340 | } /* SkPciWriteCfgWord */ | |
4341 | ||
4342 | ||
4343 | /***************************************************************************** | |
4344 | * | |
4345 | * SkPciWriteCfgWord - write a 8 bit value to pci config space | |
4346 | * | |
4347 | * Description: | |
4348 | * This routine writes a 8 bit value to the pci configuration | |
4349 | * space. The flag PciConfigUp indicates whether the config space | |
4350 | * is accesible or must be set up first. | |
4351 | * | |
4352 | * Returns: | |
4353 | * 0 - indicate everything worked ok. | |
4354 | * != 0 - error indication | |
4355 | */ | |
4356 | int SkPciWriteCfgByte( | |
4357 | SK_AC *pAC, /* Adapter Control structure pointer */ | |
4358 | int PciAddr, /* PCI register address */ | |
4359 | SK_U8 Val) /* pointer to store the read value */ | |
4360 | { | |
4361 | pci_write_config_byte(pAC->PciDev, PciAddr, Val); | |
4362 | return(0); | |
4363 | } /* SkPciWriteCfgByte */ | |
4364 | ||
4365 | ||
4366 | /***************************************************************************** | |
4367 | * | |
4368 | * SkDrvEvent - handle driver events | |
4369 | * | |
4370 | * Description: | |
4371 | * This function handles events from all modules directed to the driver | |
4372 | * | |
4373 | * Context: | |
4374 | * Is called under protection of slow path lock. | |
4375 | * | |
4376 | * Returns: | |
4377 | * 0 if everything ok | |
4378 | * < 0 on error | |
42d1f039 | 4379 | * |
7152b1d0 WD |
4380 | */ |
4381 | int SkDrvEvent( | |
4382 | SK_AC *pAC, /* pointer to adapter context */ | |
4383 | SK_IOC IoC, /* io-context */ | |
4384 | SK_U32 Event, /* event-id */ | |
4385 | SK_EVPARA Param) /* event-parameter */ | |
4386 | { | |
4387 | SK_MBUF *pRlmtMbuf; /* pointer to a rlmt-mbuf structure */ | |
4388 | struct sk_buff *pMsg; /* pointer to a message block */ | |
4389 | int FromPort; /* the port from which we switch away */ | |
4390 | int ToPort; /* the port we switch to */ | |
4391 | SK_EVPARA NewPara; /* parameter for further events */ | |
4392 | #if 0 | |
4393 | int Stat; | |
4394 | #endif | |
4395 | unsigned long Flags; | |
4396 | SK_BOOL DualNet; | |
4397 | ||
4398 | switch (Event) { | |
4399 | case SK_DRV_ADAP_FAIL: | |
4400 | SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_EVENT, | |
4401 | ("ADAPTER FAIL EVENT\n")); | |
4402 | printk("%s: Adapter failed.\n", pAC->dev[0]->name); | |
4403 | /* disable interrupts */ | |
4404 | SK_OUT32(pAC->IoBase, B0_IMSK, 0); | |
4405 | /* cgoos */ | |
4406 | break; | |
4407 | case SK_DRV_PORT_FAIL: | |
4408 | FromPort = Param.Para32[0]; | |
4409 | SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_EVENT, | |
4410 | ("PORT FAIL EVENT, Port: %d\n", FromPort)); | |
4411 | if (FromPort == 0) { | |
4412 | printk("%s: Port A failed.\n", pAC->dev[0]->name); | |
4413 | } else { | |
4414 | printk("%s: Port B failed.\n", pAC->dev[1]->name); | |
4415 | } | |
4416 | /* cgoos */ | |
4417 | break; | |
4418 | case SK_DRV_PORT_RESET: /* SK_U32 PortIdx */ | |
4419 | /* action list 4 */ | |
4420 | FromPort = Param.Para32[0]; | |
4421 | SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_EVENT, | |
4422 | ("PORT RESET EVENT, Port: %d ", FromPort)); | |
4423 | NewPara.Para64 = FromPort; | |
4424 | SkPnmiEvent(pAC, IoC, SK_PNMI_EVT_XMAC_RESET, NewPara); | |
4425 | spin_lock_irqsave( | |
4426 | &pAC->TxPort[FromPort][TX_PRIO_LOW].TxDesRingLock, | |
4427 | Flags); | |
4428 | SkGeStopPort(pAC, IoC, FromPort, SK_STOP_ALL, SK_HARD_RST); | |
4429 | #if 0 | |
4430 | pAC->dev[Param.Para32[0]]->flags &= ~IFF_RUNNING; | |
4431 | #endif | |
4432 | spin_unlock_irqrestore( | |
4433 | &pAC->TxPort[FromPort][TX_PRIO_LOW].TxDesRingLock, | |
4434 | Flags); | |
42d1f039 | 4435 | |
7152b1d0 WD |
4436 | /* clear rx ring from received frames */ |
4437 | ReceiveIrq(pAC, &pAC->RxPort[FromPort], SK_FALSE); | |
42d1f039 | 4438 | |
7152b1d0 WD |
4439 | ClearTxRing(pAC, &pAC->TxPort[FromPort][TX_PRIO_LOW]); |
4440 | spin_lock_irqsave( | |
4441 | &pAC->TxPort[FromPort][TX_PRIO_LOW].TxDesRingLock, | |
4442 | Flags); | |
42d1f039 | 4443 | |
7152b1d0 WD |
4444 | /* tschilling: Handling of return value inserted. */ |
4445 | if (SkGeInitPort(pAC, IoC, FromPort)) { | |
4446 | if (FromPort == 0) { | |
4447 | printk("%s: SkGeInitPort A failed.\n", pAC->dev[0]->name); | |
4448 | } else { | |
4449 | printk("%s: SkGeInitPort B failed.\n", pAC->dev[1]->name); | |
4450 | } | |
4451 | } | |
4452 | SkAddrMcUpdate(pAC,IoC, FromPort); | |
4453 | PortReInitBmu(pAC, FromPort); | |
4454 | SkGePollTxD(pAC, IoC, FromPort, SK_TRUE); | |
4455 | ClearAndStartRx(pAC, FromPort); | |
4456 | spin_unlock_irqrestore( | |
4457 | &pAC->TxPort[FromPort][TX_PRIO_LOW].TxDesRingLock, | |
4458 | Flags); | |
4459 | break; | |
4460 | case SK_DRV_NET_UP: /* SK_U32 PortIdx */ | |
4461 | /* action list 5 */ | |
4462 | FromPort = Param.Para32[0]; | |
4463 | SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_EVENT, | |
4464 | ("NET UP EVENT, Port: %d ", Param.Para32[0])); | |
4465 | #ifdef SK98_INFO | |
4466 | printk("%s: network connection up using" | |
4467 | " port %c\n", pAC->dev[Param.Para32[0]]->name, 'A'+Param.Para32[0]); | |
4468 | ||
4469 | /* tschilling: Values changed according to LinkSpeedUsed. */ | |
4470 | Stat = pAC->GIni.GP[FromPort].PLinkSpeedUsed; | |
4471 | if (Stat == SK_LSPEED_STAT_10MBPS) { | |
4472 | printk(" speed: 10\n"); | |
4473 | } else if (Stat == SK_LSPEED_STAT_100MBPS) { | |
4474 | printk(" speed: 100\n"); | |
4475 | } else if (Stat == SK_LSPEED_STAT_1000MBPS) { | |
4476 | printk(" speed: 1000\n"); | |
4477 | } else { | |
4478 | printk(" speed: unknown\n"); | |
4479 | } | |
4480 | ||
4481 | Stat = pAC->GIni.GP[FromPort].PLinkModeStatus; | |
4482 | if (Stat == SK_LMODE_STAT_AUTOHALF || | |
4483 | Stat == SK_LMODE_STAT_AUTOFULL) { | |
4484 | printk(" autonegotiation: yes\n"); | |
4485 | } | |
4486 | else { | |
4487 | printk(" autonegotiation: no\n"); | |
4488 | } | |
4489 | if (Stat == SK_LMODE_STAT_AUTOHALF || | |
4490 | Stat == SK_LMODE_STAT_HALF) { | |
4491 | printk(" duplex mode: half\n"); | |
4492 | } | |
4493 | else { | |
4494 | printk(" duplex mode: full\n"); | |
4495 | } | |
4496 | Stat = pAC->GIni.GP[FromPort].PFlowCtrlStatus; | |
4497 | if (Stat == SK_FLOW_STAT_REM_SEND ) { | |
4498 | printk(" flowctrl: remote send\n"); | |
4499 | } | |
4500 | else if (Stat == SK_FLOW_STAT_LOC_SEND ){ | |
4501 | printk(" flowctrl: local send\n"); | |
4502 | } | |
4503 | else if (Stat == SK_FLOW_STAT_SYMMETRIC ){ | |
4504 | printk(" flowctrl: symmetric\n"); | |
4505 | } | |
4506 | else { | |
4507 | printk(" flowctrl: none\n"); | |
4508 | } | |
42d1f039 | 4509 | |
7152b1d0 WD |
4510 | /* tschilling: Check against CopperType now. */ |
4511 | if ((pAC->GIni.GICopperType == SK_TRUE) && | |
4512 | (pAC->GIni.GP[FromPort].PLinkSpeedUsed == | |
4513 | SK_LSPEED_STAT_1000MBPS)) { | |
4514 | Stat = pAC->GIni.GP[FromPort].PMSStatus; | |
4515 | if (Stat == SK_MS_STAT_MASTER ) { | |
4516 | printk(" role: master\n"); | |
4517 | } | |
4518 | else if (Stat == SK_MS_STAT_SLAVE ) { | |
4519 | printk(" role: slave\n"); | |
4520 | } | |
4521 | else { | |
4522 | printk(" role: ???\n"); | |
4523 | } | |
4524 | } | |
4525 | ||
4526 | #ifdef SK_ZEROCOPY | |
4527 | if (pAC->GIni.GIChipId == CHIP_ID_YUKON) | |
4528 | printk(" scatter-gather: enabled\n"); | |
4529 | else | |
4530 | printk(" scatter-gather: disabled\n"); | |
4531 | ||
4532 | #else | |
4533 | printk(" scatter-gather: disabled\n"); | |
4534 | #endif | |
4535 | #endif /* SK98_INFO */ | |
42d1f039 WD |
4536 | |
4537 | if ((Param.Para32[0] != pAC->ActivePort) && | |
7152b1d0 WD |
4538 | (pAC->RlmtNets == 1)) { |
4539 | NewPara.Para32[0] = pAC->ActivePort; | |
4540 | NewPara.Para32[1] = Param.Para32[0]; | |
4541 | SkEventQueue(pAC, SKGE_DRV, SK_DRV_SWITCH_INTERN, | |
4542 | NewPara); | |
4543 | } | |
4544 | ||
4545 | /* Inform the world that link protocol is up. */ | |
4546 | #if 0 | |
4547 | pAC->dev[Param.Para32[0]]->flags |= IFF_RUNNING; | |
4548 | #endif | |
4549 | ||
4550 | break; | |
4551 | case SK_DRV_NET_DOWN: /* SK_U32 Reason */ | |
4552 | /* action list 7 */ | |
4553 | SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_EVENT, | |
4554 | ("NET DOWN EVENT ")); | |
4555 | #ifdef SK98_INFO | |
4556 | printk("%s: network connection down\n", pAC->dev[Param.Para32[1]]->name); | |
4557 | #endif | |
4558 | #if 0 | |
4559 | pAC->dev[Param.Para32[1]]->flags &= ~IFF_RUNNING; | |
4560 | #endif | |
4561 | break; | |
4562 | case SK_DRV_SWITCH_HARD: /* SK_U32 FromPortIdx SK_U32 ToPortIdx */ | |
4563 | SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_EVENT, | |
4564 | ("PORT SWITCH HARD ")); | |
4565 | case SK_DRV_SWITCH_SOFT: /* SK_U32 FromPortIdx SK_U32 ToPortIdx */ | |
4566 | /* action list 6 */ | |
4567 | printk("%s: switching to port %c\n", pAC->dev[0]->name, | |
4568 | 'A'+Param.Para32[1]); | |
4569 | case SK_DRV_SWITCH_INTERN: /* SK_U32 FromPortIdx SK_U32 ToPortIdx */ | |
4570 | FromPort = Param.Para32[0]; | |
4571 | ToPort = Param.Para32[1]; | |
4572 | SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_EVENT, | |
4573 | ("PORT SWITCH EVENT, From: %d To: %d (Pref %d) ", | |
4574 | FromPort, ToPort, pAC->Rlmt.Net[0].PrefPort)); | |
4575 | NewPara.Para64 = FromPort; | |
4576 | SkPnmiEvent(pAC, IoC, SK_PNMI_EVT_XMAC_RESET, NewPara); | |
4577 | NewPara.Para64 = ToPort; | |
4578 | SkPnmiEvent(pAC, IoC, SK_PNMI_EVT_XMAC_RESET, NewPara); | |
4579 | spin_lock_irqsave( | |
4580 | &pAC->TxPort[FromPort][TX_PRIO_LOW].TxDesRingLock, | |
4581 | Flags); | |
4582 | spin_lock_irqsave( | |
4583 | &pAC->TxPort[ToPort][TX_PRIO_LOW].TxDesRingLock, Flags); | |
4584 | SkGeStopPort(pAC, IoC, FromPort, SK_STOP_ALL, SK_SOFT_RST); | |
4585 | SkGeStopPort(pAC, IoC, ToPort, SK_STOP_ALL, SK_SOFT_RST); | |
4586 | spin_unlock_irqrestore( | |
4587 | &pAC->TxPort[ToPort][TX_PRIO_LOW].TxDesRingLock, Flags); | |
4588 | spin_unlock_irqrestore( | |
4589 | &pAC->TxPort[FromPort][TX_PRIO_LOW].TxDesRingLock, | |
4590 | Flags); | |
4591 | ||
4592 | ReceiveIrq(pAC, &pAC->RxPort[FromPort], SK_FALSE); /* clears rx ring */ | |
4593 | ReceiveIrq(pAC, &pAC->RxPort[ToPort], SK_FALSE); /* clears rx ring */ | |
42d1f039 | 4594 | |
7152b1d0 WD |
4595 | ClearTxRing(pAC, &pAC->TxPort[FromPort][TX_PRIO_LOW]); |
4596 | ClearTxRing(pAC, &pAC->TxPort[ToPort][TX_PRIO_LOW]); | |
4597 | spin_lock_irqsave( | |
42d1f039 | 4598 | &pAC->TxPort[FromPort][TX_PRIO_LOW].TxDesRingLock, |
7152b1d0 WD |
4599 | Flags); |
4600 | spin_lock_irqsave( | |
4601 | &pAC->TxPort[ToPort][TX_PRIO_LOW].TxDesRingLock, Flags); | |
4602 | pAC->ActivePort = ToPort; | |
4603 | #if 0 | |
4604 | SetQueueSizes(pAC); | |
4605 | #else | |
4606 | /* tschilling: New common function with minimum size check. */ | |
4607 | DualNet = SK_FALSE; | |
4608 | if (pAC->RlmtNets == 2) { | |
4609 | DualNet = SK_TRUE; | |
4610 | } | |
42d1f039 | 4611 | |
7152b1d0 WD |
4612 | if (SkGeInitAssignRamToQueues( |
4613 | pAC, | |
4614 | pAC->ActivePort, | |
4615 | DualNet)) { | |
4616 | spin_unlock_irqrestore( | |
4617 | &pAC->TxPort[ToPort][TX_PRIO_LOW].TxDesRingLock, Flags); | |
4618 | spin_unlock_irqrestore( | |
4619 | &pAC->TxPort[FromPort][TX_PRIO_LOW].TxDesRingLock, | |
4620 | Flags); | |
4621 | printk("SkGeInitAssignRamToQueues failed.\n"); | |
4622 | break; | |
4623 | } | |
4624 | #endif | |
4625 | /* tschilling: Handling of return values inserted. */ | |
4626 | if (SkGeInitPort(pAC, IoC, FromPort) || | |
4627 | SkGeInitPort(pAC, IoC, ToPort)) { | |
4628 | printk("%s: SkGeInitPort failed.\n", pAC->dev[0]->name); | |
4629 | } | |
4630 | if (Event == SK_DRV_SWITCH_SOFT) { | |
4631 | SkMacRxTxEnable(pAC, IoC, FromPort); | |
4632 | } | |
4633 | SkMacRxTxEnable(pAC, IoC, ToPort); | |
4634 | SkAddrSwap(pAC, IoC, FromPort, ToPort); | |
4635 | SkAddrMcUpdate(pAC, IoC, FromPort); | |
4636 | SkAddrMcUpdate(pAC, IoC, ToPort); | |
4637 | PortReInitBmu(pAC, FromPort); | |
4638 | PortReInitBmu(pAC, ToPort); | |
4639 | SkGePollTxD(pAC, IoC, FromPort, SK_TRUE); | |
4640 | SkGePollTxD(pAC, IoC, ToPort, SK_TRUE); | |
4641 | ClearAndStartRx(pAC, FromPort); | |
4642 | ClearAndStartRx(pAC, ToPort); | |
4643 | spin_unlock_irqrestore( | |
4644 | &pAC->TxPort[ToPort][TX_PRIO_LOW].TxDesRingLock, Flags); | |
4645 | spin_unlock_irqrestore( | |
4646 | &pAC->TxPort[FromPort][TX_PRIO_LOW].TxDesRingLock, | |
4647 | Flags); | |
4648 | break; | |
4649 | case SK_DRV_RLMT_SEND: /* SK_MBUF *pMb */ | |
4650 | SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_EVENT, | |
4651 | ("RLS ")); | |
4652 | pRlmtMbuf = (SK_MBUF*) Param.pParaPtr; | |
4653 | pMsg = (struct sk_buff*) pRlmtMbuf->pOs; | |
4654 | skb_put(pMsg, pRlmtMbuf->Length); | |
4655 | if (XmitFrame(pAC, &pAC->TxPort[pRlmtMbuf->PortIdx][TX_PRIO_LOW], | |
4656 | pMsg) < 0) | |
4657 | ||
4658 | DEV_KFREE_SKB_ANY(pMsg); | |
4659 | break; | |
4660 | default: | |
4661 | break; | |
4662 | } | |
4663 | SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_EVENT, | |
4664 | ("END EVENT ")); | |
42d1f039 | 4665 | |
7152b1d0 WD |
4666 | return (0); |
4667 | } /* SkDrvEvent */ | |
4668 | ||
4669 | ||
4670 | /***************************************************************************** | |
4671 | * | |
4672 | * SkErrorLog - log errors | |
4673 | * | |
4674 | * Description: | |
4675 | * This function logs errors to the system buffer and to the console | |
4676 | * | |
4677 | * Returns: | |
4678 | * 0 if everything ok | |
4679 | * < 0 on error | |
42d1f039 | 4680 | * |
7152b1d0 WD |
4681 | */ |
4682 | void SkErrorLog( | |
4683 | SK_AC *pAC, | |
4684 | int ErrClass, | |
4685 | int ErrNum, | |
4686 | char *pErrorMsg) | |
4687 | { | |
4688 | char ClassStr[80]; | |
4689 | ||
4690 | switch (ErrClass) { | |
4691 | case SK_ERRCL_OTHER: | |
4692 | strcpy(ClassStr, "Other error"); | |
4693 | break; | |
4694 | case SK_ERRCL_CONFIG: | |
4695 | strcpy(ClassStr, "Configuration error"); | |
4696 | break; | |
4697 | case SK_ERRCL_INIT: | |
4698 | strcpy(ClassStr, "Initialization error"); | |
4699 | break; | |
4700 | case SK_ERRCL_NORES: | |
4701 | strcpy(ClassStr, "Out of resources error"); | |
4702 | break; | |
4703 | case SK_ERRCL_SW: | |
4704 | strcpy(ClassStr, "internal Software error"); | |
4705 | break; | |
4706 | case SK_ERRCL_HW: | |
4707 | strcpy(ClassStr, "Hardware failure"); | |
4708 | break; | |
4709 | case SK_ERRCL_COMM: | |
4710 | strcpy(ClassStr, "Communication error"); | |
4711 | break; | |
4712 | } | |
4713 | printk(KERN_INFO "%s: -- ERROR --\n Class: %s\n" | |
4714 | " Nr: 0x%x\n Msg: %s\n", pAC->dev[0]->name, | |
4715 | ClassStr, ErrNum, pErrorMsg); | |
4716 | ||
4717 | } /* SkErrorLog */ | |
4718 | ||
4719 | #ifdef DEBUG | |
4720 | /****************************************************************************/ | |
4721 | /* "debug only" section *****************************************************/ | |
4722 | /****************************************************************************/ | |
4723 | ||
4724 | ||
4725 | /***************************************************************************** | |
4726 | * | |
4727 | * DumpMsg - print a frame | |
4728 | * | |
4729 | * Description: | |
4730 | * This function prints frames to the system logfile/to the console. | |
4731 | * | |
4732 | * Returns: N/A | |
42d1f039 | 4733 | * |
7152b1d0 WD |
4734 | */ |
4735 | static void DumpMsg(struct sk_buff *skb, char *str) | |
4736 | { | |
4737 | int msglen; | |
4738 | ||
4739 | if (skb == NULL) { | |
4740 | printk("DumpMsg(): NULL-Message\n"); | |
4741 | return; | |
4742 | } | |
4743 | ||
4744 | if (skb->data == NULL) { | |
4745 | printk("DumpMsg(): Message empty\n"); | |
4746 | return; | |
4747 | } | |
4748 | ||
4749 | msglen = skb->len; | |
4750 | if (msglen > 64) | |
4751 | msglen = 64; | |
4752 | ||
4753 | printk("--- Begin of message from %s , len %d (from %d) ----\n", str, msglen, skb->len); | |
4754 | ||
4755 | DumpData((char *)skb->data, msglen); | |
4756 | ||
4757 | printk("------- End of message ---------\n"); | |
4758 | } /* DumpMsg */ | |
4759 | ||
4760 | ||
7152b1d0 WD |
4761 | /***************************************************************************** |
4762 | * | |
4763 | * DumpData - print a data area | |
4764 | * | |
4765 | * Description: | |
42d1f039 | 4766 | * This function prints a area of data to the system logfile/to the |
7152b1d0 WD |
4767 | * console. |
4768 | * | |
4769 | * Returns: N/A | |
42d1f039 | 4770 | * |
7152b1d0 WD |
4771 | */ |
4772 | static void DumpData(char *p, int size) | |
4773 | { | |
4774 | register int i; | |
4775 | int haddr, addr; | |
4776 | char hex_buffer[180]; | |
4777 | char asc_buffer[180]; | |
4778 | char HEXCHAR[] = "0123456789ABCDEF"; | |
4779 | ||
4780 | addr = 0; | |
4781 | haddr = 0; | |
4782 | hex_buffer[0] = 0; | |
4783 | asc_buffer[0] = 0; | |
4784 | for (i=0; i < size; ) { | |
4785 | if (*p >= '0' && *p <='z') | |
4786 | asc_buffer[addr] = *p; | |
4787 | else | |
4788 | asc_buffer[addr] = '.'; | |
4789 | addr++; | |
4790 | asc_buffer[addr] = 0; | |
4791 | hex_buffer[haddr] = HEXCHAR[(*p & 0xf0) >> 4]; | |
4792 | haddr++; | |
4793 | hex_buffer[haddr] = HEXCHAR[*p & 0x0f]; | |
4794 | haddr++; | |
4795 | hex_buffer[haddr] = ' '; | |
4796 | haddr++; | |
4797 | hex_buffer[haddr] = 0; | |
4798 | p++; | |
4799 | i++; | |
4800 | if (i%16 == 0) { | |
4801 | printk("%s %s\n", hex_buffer, asc_buffer); | |
4802 | addr = 0; | |
4803 | haddr = 0; | |
4804 | } | |
4805 | } | |
4806 | } /* DumpData */ | |
4807 | ||
4808 | ||
4809 | /***************************************************************************** | |
4810 | * | |
4811 | * DumpLong - print a data area as long values | |
4812 | * | |
4813 | * Description: | |
42d1f039 | 4814 | * This function prints a area of data to the system logfile/to the |
7152b1d0 WD |
4815 | * console. |
4816 | * | |
4817 | * Returns: N/A | |
42d1f039 | 4818 | * |
7152b1d0 WD |
4819 | */ |
4820 | static void DumpLong(char *pc, int size) | |
4821 | { | |
4822 | register int i; | |
4823 | int haddr, addr; | |
4824 | char hex_buffer[180]; | |
4825 | char asc_buffer[180]; | |
4826 | char HEXCHAR[] = "0123456789ABCDEF"; | |
4827 | long *p; | |
4828 | int l; | |
4829 | ||
4830 | addr = 0; | |
4831 | haddr = 0; | |
4832 | hex_buffer[0] = 0; | |
4833 | asc_buffer[0] = 0; | |
4834 | p = (long*) pc; | |
4835 | for (i=0; i < size; ) { | |
4836 | l = (long) *p; | |
4837 | hex_buffer[haddr] = HEXCHAR[(l >> 28) & 0xf]; | |
4838 | haddr++; | |
4839 | hex_buffer[haddr] = HEXCHAR[(l >> 24) & 0xf]; | |
4840 | haddr++; | |
4841 | hex_buffer[haddr] = HEXCHAR[(l >> 20) & 0xf]; | |
4842 | haddr++; | |
4843 | hex_buffer[haddr] = HEXCHAR[(l >> 16) & 0xf]; | |
4844 | haddr++; | |
4845 | hex_buffer[haddr] = HEXCHAR[(l >> 12) & 0xf]; | |
4846 | haddr++; | |
4847 | hex_buffer[haddr] = HEXCHAR[(l >> 8) & 0xf]; | |
4848 | haddr++; | |
4849 | hex_buffer[haddr] = HEXCHAR[(l >> 4) & 0xf]; | |
4850 | haddr++; | |
4851 | hex_buffer[haddr] = HEXCHAR[l & 0x0f]; | |
4852 | haddr++; | |
4853 | hex_buffer[haddr] = ' '; | |
4854 | haddr++; | |
4855 | hex_buffer[haddr] = 0; | |
4856 | p++; | |
4857 | i++; | |
4858 | if (i%8 == 0) { | |
4859 | printk("%4x %s\n", (i-8)*4, hex_buffer); | |
4860 | haddr = 0; | |
4861 | } | |
4862 | } | |
4863 | printk("------------------------\n"); | |
4864 | } /* DumpLong */ | |
4865 | ||
4866 | #endif |