]> git.kernelconcepts.de Git - karo-tx-uboot.git/blob - drivers/sk98lin/skaddr.c
* Patches by Xianghua Xiao, 15 Oct 2003:
[karo-tx-uboot.git] / drivers / sk98lin / skaddr.c
1 /******************************************************************************
2  *
3  * Name:        skaddr.c
4  * Project:     GEnesis, PCI Gigabit Ethernet Adapter
5  * Version:     $Revision: 1.48 $
6  * Date:        $Date: 2003/02/12 17:09:37 $
7  * Purpose:     Manage Addresses (Multicast and Unicast) and Promiscuous Mode.
8  *
9  ******************************************************************************/
10
11 /******************************************************************************
12  *
13  *      (C)Copyright 1998-2002 SysKonnect GmbH.
14  *
15  *      This program is free software; you can redistribute it and/or modify
16  *      it under the terms of the GNU General Public License as published by
17  *      the Free Software Foundation; either version 2 of the License, or
18  *      (at your option) any later version.
19  *
20  *      The information in this file is provided "AS IS" without warranty.
21  *
22  ******************************************************************************/
23
24 /******************************************************************************
25  *
26  * History:
27  *
28  *      $Log: skaddr.c,v $
29  *      Revision 1.48  2003/02/12 17:09:37  tschilli
30  *      Fix in SkAddrOverride() to set both (physical and logical) MAC addresses
31  *      in case that both addresses are identical.
32  *
33  *      Revision 1.47  2002/09/17 06:31:10  tschilli
34  *      Handling of SK_PROM_MODE_ALL_MC flag in SkAddrGmacMcUpdate()
35  *      and SkAddrGmacPromiscuousChange() fixed.
36  *      Editorial changes.
37  *
38  *      Revision 1.46  2002/08/22 07:55:41  tschilli
39  *      New function SkGmacMcHash() for GMAC multicast hashing algorithm added.
40  *      Editorial changes.
41  *
42  *      Revision 1.45  2002/08/15 12:29:35  tschilli
43  *      SkAddrGmacMcUpdate() and SkAddrGmacPromiscuousChange() changed.
44  *
45  *      Revision 1.44  2002/08/14 12:18:03  rschmidt
46  *      Replaced direct handling of MAC Hashing (XMAC and GMAC)
47  *      with routine SkMacHashing().
48  *      Replaced wrong 3rd para 'i' with 'PortNumber' in SkMacPromiscMode().
49  *
50  *      Revision 1.43  2002/08/13 09:37:43  rschmidt
51  *      Corrected some SK_DBG_MSG outputs.
52  *      Replaced wrong 2nd para pAC with IoC in SkMacPromiscMode().
53  *      Editorial changes.
54  *
55  *      Revision 1.42  2002/08/12 11:24:36  rschmidt
56  *      Remove setting of logical MAC address GM_SRC_ADDR_2 in SkAddrInit().
57  *      Replaced direct handling of MAC Promiscuous Mode (XMAC and GMAC)
58  *      with routine SkMacPromiscMode().
59  *      Editorial changes.
60  *
61  *      Revision 1.41  2002/06/10 13:52:18  tschilli
62  *      Changes for handling YUKON.
63  *      All changes are internally and not visible to the programmer
64  *      using this module.
65  *
66  *      Revision 1.40  2001/02/14 14:04:59  rassmann
67  *      Editorial changes.
68  *
69  *      Revision 1.39  2001/01/30 10:30:04  rassmann
70  *      Editorial changes.
71  *
72  *      Revision 1.38  2001/01/25 16:26:52  rassmann
73  *      Ensured that logical address overrides are done on net's active port.
74  *
75  *      Revision 1.37  2001/01/22 13:41:34  rassmann
76  *      Supporting two nets on dual-port adapters.
77  *
78  *      Revision 1.36  2000/08/07 11:10:39  rassmann
79  *      Editorial changes.
80  *
81  *      Revision 1.35  2000/05/04 09:38:41  rassmann
82  *      Editorial changes.
83  *      Corrected multicast address hashing.
84  *
85  *      Revision 1.34  1999/11/22 13:23:44  cgoos
86  *      Changed license header to GPL.
87  *
88  *      Revision 1.33  1999/05/28 10:56:06  rassmann
89  *      Editorial changes.
90  *
91  *      Revision 1.32  1999/03/31 10:59:20  rassmann
92  *      Returning Success instead of DupAddr if address shall be overridden
93  *      with same value.
94  *
95  *      Revision 1.31  1999/01/14 16:18:17  rassmann
96  *      Corrected multicast initialization.
97  *
98  *      Revision 1.30  1999/01/04 10:30:35  rassmann
99  *      SkAddrOverride only possible after SK_INIT_IO phase.
100  *
101  *      Revision 1.29  1998/12/29 13:13:10  rassmann
102  *      An address override is now preserved in the SK_INIT_IO phase.
103  *      All functions return an int now.
104  *      Extended parameter checking.
105  *
106  *      Revision 1.28  1998/12/01 11:45:53  rassmann
107  *      Code cleanup.
108  *
109  *      Revision 1.27  1998/12/01 09:22:49  rassmann
110  *      SkAddrMcAdd and SkAddrMcUpdate returned SK_MC_FILTERING_INEXACT
111  *      too often.
112  *
113  *      Revision 1.26  1998/11/24 12:39:44  rassmann
114  *      Reserved multicast entry for BPDU address.
115  *      13 multicast entries left for protocol.
116  *
117  *      Revision 1.25  1998/11/17 16:54:23  rassmann
118  *      Using exact match for up to 14 multicast addresses.
119  *      Still receiving all multicasts if more addresses are added.
120  *
121  *      Revision 1.24  1998/11/13 17:24:31  rassmann
122  *      Changed return value of SkAddrOverride to int.
123  *
124  *      Revision 1.23  1998/11/13 16:56:18  rassmann
125  *      Added macro SK_ADDR_COMPARE.
126  *      Changed return type of SkAddrOverride to SK_BOOL.
127  *
128  *      Revision 1.22  1998/11/04 17:06:17  rassmann
129  *      Corrected McUpdate and PromiscuousChange functions.
130  *
131  *      Revision 1.21  1998/10/29 14:34:04  rassmann
132  *      Clearing SK_ADDR struct at startup.
133  *
134  *      Revision 1.20  1998/10/28 18:16:34  rassmann
135  *      Avoiding I/Os before SK_INIT_RUN level.
136  *      Aligning InexactFilter.
137  *
138  *      Revision 1.19  1998/10/28 11:29:28  rassmann
139  *      Programming physical address in SkAddrMcUpdate.
140  *      Corrected programming of exact match entries.
141  *
142  *      Revision 1.18  1998/10/28 10:34:48  rassmann
143  *      Corrected reading of physical addresses.
144  *
145  *      Revision 1.17  1998/10/28 10:26:13  rassmann
146  *      Getting ports' current MAC addresses from EPROM now.
147  *      Added debug output.
148  *
149  *      Revision 1.16  1998/10/27 16:20:12  rassmann
150  *      Reading MAC address byte by byte.
151  *
152  *      Revision 1.15  1998/10/22 11:39:09  rassmann
153  *      Corrected signed/unsigned mismatches.
154  *
155  *      Revision 1.14  1998/10/19 17:12:35  rassmann
156  *      Syntax corrections.
157  *
158  *      Revision 1.13  1998/10/19 17:02:19  rassmann
159  *      Now reading permanent MAC addresses from CRF.
160  *
161  *      Revision 1.12  1998/10/15 15:15:48  rassmann
162  *      Changed Flags Parameters from SK_U8 to int.
163  *      Checked with lint.
164  *
165  *      Revision 1.11  1998/09/24 19:15:12  rassmann
166  *      Code cleanup.
167  *
168  *      Revision 1.10  1998/09/18 20:18:54  rassmann
169  *      Added HW access.
170  *      Implemented swapping.
171  *
172  *      Revision 1.9  1998/09/16 11:32:00  rassmann
173  *      Including skdrv1st.h again. :(
174  *
175  *      Revision 1.8  1998/09/16 11:09:34  rassmann
176  *      Syntax corrections.
177  *
178  *      Revision 1.7  1998/09/14 17:06:34  rassmann
179  *      Minor changes.
180  *
181  *      Revision 1.6  1998/09/07 08:45:41  rassmann
182  *      Syntax corrections.
183  *
184  *      Revision 1.5  1998/09/04 19:40:19  rassmann
185  *      Interface enhancements.
186  *
187  *      Revision 1.4  1998/09/04 12:14:12  rassmann
188  *      Interface cleanup.
189  *
190  *      Revision 1.3  1998/09/02 16:56:40  rassmann
191  *      Updated interface.
192  *
193  *      Revision 1.2  1998/08/27 14:26:09  rassmann
194  *      Updated interface.
195  *
196  *      Revision 1.1  1998/08/21 08:30:22  rassmann
197  *      First public version.
198  *
199  ******************************************************************************/
200
201 /******************************************************************************
202  *
203  * Description:
204  *
205  * This module is intended to manage multicast addresses, address override,
206  * and promiscuous mode on GEnesis and Yukon adapters.
207  *
208  * Address Layout:
209  *      port address:           physical MAC address
210  *      1st exact match:        logical MAC address (GEnesis only)
211  *      2nd exact match:        RLMT multicast (GEnesis only)
212  *      exact match 3-13:       OS-specific multicasts (GEnesis only)
213  *
214  * Include File Hierarchy:
215  *
216  *      "skdrv1st.h"
217  *      "skdrv2nd.h"
218  *
219  ******************************************************************************/
220
221 #include <config.h>
222
223 #ifdef CONFIG_SK98
224
225 #ifndef lint
226 static const char SysKonnectFileId[] =
227         "@(#) $Id: skaddr.c,v 1.48 2003/02/12 17:09:37 tschilli Exp $ (C) SysKonnect.";
228 #endif  /* !defined(lint) */
229
230 #define __SKADDR_C
231
232 #ifdef __cplusplus
233 #error C++ is not yet supported.
234 extern "C" {
235 #endif  /* cplusplus */
236
237 #include "h/skdrv1st.h"
238 #include "h/skdrv2nd.h"
239
240 /* defines ********************************************************************/
241
242
243 #define XMAC_POLY       0xEDB88320UL    /* CRC32-Poly - XMAC: Little Endian */
244 #define GMAC_POLY       0x04C11DB7L     /* CRC16-Poly - GMAC: Little Endian */
245 #define HASH_BITS       6                               /* #bits in hash */
246 #define SK_MC_BIT       0x01
247
248 /* Error numbers and messages. */
249
250 #define SKERR_ADDR_E001         (SK_ERRBASE_ADDR + 0)
251 #define SKERR_ADDR_E001MSG      "Bad Flags."
252 #define SKERR_ADDR_E002         (SKERR_ADDR_E001 + 1)
253 #define SKERR_ADDR_E002MSG      "New Error."
254
255 /* typedefs *******************************************************************/
256
257 /* None. */
258
259 /* global variables ***********************************************************/
260
261 /* 64-bit hash values with all bits set. */
262
263 SK_U16  OnesHash[4] = {0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF};
264
265 /* local variables ************************************************************/
266
267 #ifdef DEBUG
268 static int      Next0[SK_MAX_MACS] = {0, 0};
269 #endif  /* DEBUG */
270
271 /* functions ******************************************************************/
272
273 /******************************************************************************
274  *
275  *      SkAddrInit - initialize data, set state to init
276  *
277  * Description:
278  *
279  *      SK_INIT_DATA
280  *      ============
281  *
282  *      This routine clears the multicast tables and resets promiscuous mode.
283  *      Some entries are reserved for the "logical MAC address", the
284  *      SK-RLMT multicast address, and the BPDU multicast address.
285  *
286  *
287  *      SK_INIT_IO
288  *      ==========
289  *
290  *      All permanent MAC addresses are read from EPROM.
291  *      If the current MAC addresses are not already set in software,
292  *      they are set to the values of the permanent addresses.
293  *      The current addresses are written to the corresponding MAC.
294  *
295  *
296  *      SK_INIT_RUN
297  *      ===========
298  *
299  *      Nothing.
300  *
301  * Context:
302  *      init, pageable
303  *
304  * Returns:
305  *      SK_ADDR_SUCCESS
306  */
307 int     SkAddrInit(
308 SK_AC   *pAC,   /* the adapter context */
309 SK_IOC  IoC,    /* I/O context */
310 int             Level)  /* initialization level */
311 {
312         int                     j;
313         SK_U32          i;
314         SK_U8           *InAddr;
315         SK_U16          *OutAddr;
316         SK_ADDR_PORT    *pAPort;
317
318         switch (Level) {
319         case SK_INIT_DATA:
320                 SK_MEMSET((char *) &pAC->Addr, 0, sizeof(SK_ADDR));
321
322                 for (i = 0; i < SK_MAX_MACS; i++) {
323                         pAPort = &pAC->Addr.Port[i];
324                         pAPort->PromMode = SK_PROM_MODE_NONE;
325
326                         pAPort->FirstExactMatchRlmt = SK_ADDR_FIRST_MATCH_RLMT;
327                         pAPort->FirstExactMatchDrv = SK_ADDR_FIRST_MATCH_DRV;
328                         pAPort->NextExactMatchRlmt = SK_ADDR_FIRST_MATCH_RLMT;
329                         pAPort->NextExactMatchDrv = SK_ADDR_FIRST_MATCH_DRV;
330                 }
331 #ifdef xDEBUG
332                 for (i = 0; i < SK_MAX_MACS; i++) {
333                         if (pAC->Addr.Port[i].NextExactMatchRlmt <
334                                 SK_ADDR_FIRST_MATCH_RLMT) {
335                                 Next0[i] |= 4;
336                         }
337                 }
338 #endif  /* DEBUG */
339                 /* pAC->Addr.InitDone = SK_INIT_DATA; */
340                 break;
341
342         case SK_INIT_IO:
343                 for (i = 0; i < SK_MAX_NETS; i++) {
344                         pAC->Addr.Net[i].ActivePort = pAC->Rlmt.Net[i].ActivePort;
345                 }
346 #ifdef xDEBUG
347                 for (i = 0; i < SK_MAX_MACS; i++) {
348                         if (pAC->Addr.Port[i].NextExactMatchRlmt <
349                                 SK_ADDR_FIRST_MATCH_RLMT) {
350                                 Next0[i] |= 8;
351                         }
352                 }
353 #endif  /* DEBUG */
354
355                 /* Read permanent logical MAC address from Control Register File. */
356                 for (j = 0; j < SK_MAC_ADDR_LEN; j++) {
357                         InAddr = (SK_U8 *) &pAC->Addr.Net[0].PermanentMacAddress.a[j];
358                         SK_IN8(IoC, B2_MAC_1 + j, InAddr);
359                 }
360
361                 if (!pAC->Addr.Net[0].CurrentMacAddressSet) {
362                         /* Set the current logical MAC address to the permanent one. */
363                         pAC->Addr.Net[0].CurrentMacAddress =
364                                 pAC->Addr.Net[0].PermanentMacAddress;
365                         pAC->Addr.Net[0].CurrentMacAddressSet = SK_TRUE;
366                 }
367
368                 /* Set the current logical MAC address. */
369                 pAC->Addr.Port[pAC->Addr.Net[0].ActivePort].Exact[0] =
370                         pAC->Addr.Net[0].CurrentMacAddress;
371 #if SK_MAX_NETS > 1
372                 /* Set logical MAC address for net 2 to (log | 3). */
373                 if (!pAC->Addr.Net[1].CurrentMacAddressSet) {
374                         pAC->Addr.Net[1].PermanentMacAddress =
375                                 pAC->Addr.Net[0].PermanentMacAddress;
376                         pAC->Addr.Net[1].PermanentMacAddress.a[5] |= 3;
377                         /* Set the current logical MAC address to the permanent one. */
378                         pAC->Addr.Net[1].CurrentMacAddress =
379                                 pAC->Addr.Net[1].PermanentMacAddress;
380                         pAC->Addr.Net[1].CurrentMacAddressSet = SK_TRUE;
381                 }
382 #endif  /* SK_MAX_NETS > 1 */
383
384 #ifdef DEBUG
385                 for (i = 0; i < (SK_U32) pAC->GIni.GIMacsFound; i++) {
386                         SK_DBG_MSG(pAC, SK_DBGMOD_ADDR, SK_DBGCAT_INIT,
387                                 ("Permanent MAC Address (Net%d): %02X %02X %02X %02X %02X %02X\n",
388                                         i,
389                                         pAC->Addr.Net[i].PermanentMacAddress.a[0],
390                                         pAC->Addr.Net[i].PermanentMacAddress.a[1],
391                                         pAC->Addr.Net[i].PermanentMacAddress.a[2],
392                                         pAC->Addr.Net[i].PermanentMacAddress.a[3],
393                                         pAC->Addr.Net[i].PermanentMacAddress.a[4],
394                                         pAC->Addr.Net[i].PermanentMacAddress.a[5]))
395
396                         SK_DBG_MSG(pAC, SK_DBGMOD_ADDR, SK_DBGCAT_INIT,
397                                 ("Logical MAC Address (Net%d): %02X %02X %02X %02X %02X %02X\n",
398                                         i,
399                                         pAC->Addr.Net[i].CurrentMacAddress.a[0],
400                                         pAC->Addr.Net[i].CurrentMacAddress.a[1],
401                                         pAC->Addr.Net[i].CurrentMacAddress.a[2],
402                                         pAC->Addr.Net[i].CurrentMacAddress.a[3],
403                                         pAC->Addr.Net[i].CurrentMacAddress.a[4],
404                                         pAC->Addr.Net[i].CurrentMacAddress.a[5]))
405                 }
406 #endif  /* DEBUG */
407
408                 for (i = 0; i < (SK_U32) pAC->GIni.GIMacsFound; i++) {
409                         pAPort = &pAC->Addr.Port[i];
410
411                         /* Read permanent port addresses from Control Register File. */
412                         for (j = 0; j < SK_MAC_ADDR_LEN; j++) {
413                                 InAddr = (SK_U8 *) &pAPort->PermanentMacAddress.a[j];
414                                 SK_IN8(IoC, B2_MAC_2 + 8 * i + j, InAddr);
415                         }
416
417                         if (!pAPort->CurrentMacAddressSet) {
418                                 /*
419                                  * Set the current and previous physical MAC address
420                                  * of this port to its permanent MAC address.
421                                  */
422                                 pAPort->CurrentMacAddress = pAPort->PermanentMacAddress;
423                                 pAPort->PreviousMacAddress = pAPort->PermanentMacAddress;
424                                 pAPort->CurrentMacAddressSet = SK_TRUE;
425                         }
426
427                         /* Set port's current physical MAC address. */
428                         OutAddr = (SK_U16 *) &pAPort->CurrentMacAddress.a[0];
429
430                         if (pAC->GIni.GIChipId == CHIP_ID_GENESIS) {
431                                 XM_OUTADDR(IoC, i, XM_SA, OutAddr);
432                         }
433                         else {
434                                 GM_OUTADDR(IoC, i, GM_SRC_ADDR_1L, OutAddr);
435                         }
436 #ifdef DEBUG
437                         SK_DBG_MSG(pAC, SK_DBGMOD_ADDR, SK_DBGCAT_INIT,
438                                 ("SkAddrInit: Permanent Physical MAC Address: %02X %02X %02X %02X %02X %02X\n",
439                                         pAPort->PermanentMacAddress.a[0],
440                                         pAPort->PermanentMacAddress.a[1],
441                                         pAPort->PermanentMacAddress.a[2],
442                                         pAPort->PermanentMacAddress.a[3],
443                                         pAPort->PermanentMacAddress.a[4],
444                                         pAPort->PermanentMacAddress.a[5]))
445
446                         SK_DBG_MSG(pAC, SK_DBGMOD_ADDR, SK_DBGCAT_INIT,
447                                 ("SkAddrInit: Physical MAC Address: %02X %02X %02X %02X %02X %02X\n",
448                                         pAPort->CurrentMacAddress.a[0],
449                                         pAPort->CurrentMacAddress.a[1],
450                                         pAPort->CurrentMacAddress.a[2],
451                                         pAPort->CurrentMacAddress.a[3],
452                                         pAPort->CurrentMacAddress.a[4],
453                                         pAPort->CurrentMacAddress.a[5]))
454 #endif  /* DEBUG */
455                 }
456                 /* pAC->Addr.InitDone = SK_INIT_IO; */
457                 break;
458
459         case SK_INIT_RUN:
460 #ifdef xDEBUG
461                 for (i = 0; i < SK_MAX_MACS; i++) {
462                         if (pAC->Addr.Port[i].NextExactMatchRlmt <
463                                 SK_ADDR_FIRST_MATCH_RLMT) {
464                                 Next0[i] |= 16;
465                         }
466                 }
467 #endif  /* DEBUG */
468
469                 /* pAC->Addr.InitDone = SK_INIT_RUN; */
470                 break;
471
472         default:        /* error */
473                 break;
474         }
475
476         return (SK_ADDR_SUCCESS);
477
478 }       /* SkAddrInit */
479
480
481 /******************************************************************************
482  *
483  *      SkAddrMcClear - clear the multicast table
484  *
485  * Description:
486  *      This routine clears the multicast table.
487  *
488  *      If not suppressed by Flag SK_MC_SW_ONLY, the hardware is updated
489  *      immediately.
490  *
491  *      It calls either SkAddrXmacMcClear or SkAddrGmacMcClear, according
492  *      to the adapter in use. The real work is done there.
493  *
494  * Context:
495  *      runtime, pageable
496  *      may be called starting with SK_INIT_DATA with flag SK_MC_SW_ONLY
497  *      may be called after SK_INIT_IO without limitation
498  *
499  * Returns:
500  *      SK_ADDR_SUCCESS
501  *      SK_ADDR_ILLEGAL_PORT
502  */
503 int     SkAddrMcClear(
504 SK_AC   *pAC,           /* adapter context */
505 SK_IOC  IoC,            /* I/O context */
506 SK_U32  PortNumber,     /* Index of affected port */
507 int             Flags)          /* permanent/non-perm, sw-only */
508 {
509         int ReturnCode;
510
511         if (PortNumber >= (SK_U32) pAC->GIni.GIMacsFound) {
512                 return (SK_ADDR_ILLEGAL_PORT);
513         }
514
515         if (pAC->GIni.GIChipId == CHIP_ID_GENESIS) {
516                 ReturnCode = SkAddrXmacMcClear(pAC, IoC, PortNumber, Flags);
517         }
518         else {
519                 ReturnCode = SkAddrGmacMcClear(pAC, IoC, PortNumber, Flags);
520         }
521
522         return (ReturnCode);
523
524 }       /* SkAddrMcClear */
525
526
527 /******************************************************************************
528  *
529  *      SkAddrXmacMcClear - clear the multicast table
530  *
531  * Description:
532  *      This routine clears the multicast table
533  *      (either entry 2 or entries 3-16 and InexactFilter) of the given port.
534  *      If not suppressed by Flag SK_MC_SW_ONLY, the hardware is updated
535  *      immediately.
536  *
537  * Context:
538  *      runtime, pageable
539  *      may be called starting with SK_INIT_DATA with flag SK_MC_SW_ONLY
540  *      may be called after SK_INIT_IO without limitation
541  *
542  * Returns:
543  *      SK_ADDR_SUCCESS
544  *      SK_ADDR_ILLEGAL_PORT
545  */
546 int     SkAddrXmacMcClear(
547 SK_AC   *pAC,           /* adapter context */
548 SK_IOC  IoC,            /* I/O context */
549 SK_U32  PortNumber,     /* Index of affected port */
550 int             Flags)          /* permanent/non-perm, sw-only */
551 {
552         int i;
553
554         if (Flags & SK_ADDR_PERMANENT) {        /* permanent => RLMT */
555
556                 /* Clear RLMT multicast addresses. */
557                 pAC->Addr.Port[PortNumber].NextExactMatchRlmt = SK_ADDR_FIRST_MATCH_RLMT;
558         }
559         else {  /* not permanent => DRV */
560
561                 /* Clear InexactFilter */
562                 for (i = 0; i < 8; i++) {
563                         pAC->Addr.Port[PortNumber].InexactFilter.Bytes[i] = 0;
564                 }
565
566                 /* Clear DRV multicast addresses. */
567
568                 pAC->Addr.Port[PortNumber].NextExactMatchDrv = SK_ADDR_FIRST_MATCH_DRV;
569         }
570
571         if (!(Flags & SK_MC_SW_ONLY)) {
572                 (void) SkAddrXmacMcUpdate(pAC, IoC, PortNumber);
573         }
574
575         return (SK_ADDR_SUCCESS);
576
577 }       /* SkAddrXmacMcClear */
578
579
580 /******************************************************************************
581  *
582  *      SkAddrGmacMcClear - clear the multicast table
583  *
584  * Description:
585  *      This routine clears the multicast hashing table (InexactFilter)
586  *      (either the RLMT or the driver bits) of the given port.
587  *
588  *      If not suppressed by Flag SK_MC_SW_ONLY, the hardware is updated
589  *      immediately.
590  *
591  * Context:
592  *      runtime, pageable
593  *      may be called starting with SK_INIT_DATA with flag SK_MC_SW_ONLY
594  *      may be called after SK_INIT_IO without limitation
595  *
596  * Returns:
597  *      SK_ADDR_SUCCESS
598  *      SK_ADDR_ILLEGAL_PORT
599  */
600 int     SkAddrGmacMcClear(
601 SK_AC   *pAC,           /* adapter context */
602 SK_IOC  IoC,            /* I/O context */
603 SK_U32  PortNumber,     /* Index of affected port */
604 int             Flags)          /* permanent/non-perm, sw-only */
605 {
606         int i;
607
608 #ifdef DEBUG
609         SK_DBG_MSG(pAC, SK_DBGMOD_ADDR, SK_DBGCAT_CTRL,
610                 ("GMAC InexactFilter (not cleared): %02X %02X %02X %02X %02X %02X %02X %02X\n",
611                         pAC->Addr.Port[PortNumber].InexactFilter.Bytes[0],
612                         pAC->Addr.Port[PortNumber].InexactFilter.Bytes[1],
613                         pAC->Addr.Port[PortNumber].InexactFilter.Bytes[2],
614                         pAC->Addr.Port[PortNumber].InexactFilter.Bytes[3],
615                         pAC->Addr.Port[PortNumber].InexactFilter.Bytes[4],
616                         pAC->Addr.Port[PortNumber].InexactFilter.Bytes[5],
617                         pAC->Addr.Port[PortNumber].InexactFilter.Bytes[6],
618                         pAC->Addr.Port[PortNumber].InexactFilter.Bytes[7]))
619 #endif  /* DEBUG */
620
621         /* Clear InexactFilter */
622         for (i = 0; i < 8; i++) {
623                 pAC->Addr.Port[PortNumber].InexactFilter.Bytes[i] = 0;
624         }
625
626         if (Flags & SK_ADDR_PERMANENT) {        /* permanent => RLMT */
627
628                 /* Copy DRV bits to InexactFilter. */
629                 for (i = 0; i < 8; i++) {
630                         pAC->Addr.Port[PortNumber].InexactFilter.Bytes[i] |=
631                                 pAC->Addr.Port[PortNumber].InexactDrvFilter.Bytes[i];
632
633                         /* Clear InexactRlmtFilter. */
634                         pAC->Addr.Port[PortNumber].InexactRlmtFilter.Bytes[i] = 0;
635
636                 }
637         }
638         else {  /* not permanent => DRV */
639
640                 /* Copy RLMT bits to InexactFilter. */
641                 for (i = 0; i < 8; i++) {
642                         pAC->Addr.Port[PortNumber].InexactFilter.Bytes[i] |=
643                                 pAC->Addr.Port[PortNumber].InexactRlmtFilter.Bytes[i];
644
645                         /* Clear InexactDrvFilter. */
646                         pAC->Addr.Port[PortNumber].InexactDrvFilter.Bytes[i] = 0;
647                 }
648         }
649
650 #ifdef DEBUG
651         SK_DBG_MSG(pAC, SK_DBGMOD_ADDR, SK_DBGCAT_CTRL,
652                 ("GMAC InexactFilter (cleared): %02X %02X %02X %02X %02X %02X %02X %02X\n",
653                         pAC->Addr.Port[PortNumber].InexactFilter.Bytes[0],
654                         pAC->Addr.Port[PortNumber].InexactFilter.Bytes[1],
655                         pAC->Addr.Port[PortNumber].InexactFilter.Bytes[2],
656                         pAC->Addr.Port[PortNumber].InexactFilter.Bytes[3],
657                         pAC->Addr.Port[PortNumber].InexactFilter.Bytes[4],
658                         pAC->Addr.Port[PortNumber].InexactFilter.Bytes[5],
659                         pAC->Addr.Port[PortNumber].InexactFilter.Bytes[6],
660                         pAC->Addr.Port[PortNumber].InexactFilter.Bytes[7]))
661 #endif  /* DEBUG */
662
663         if (!(Flags & SK_MC_SW_ONLY)) {
664                 (void) SkAddrGmacMcUpdate(pAC, IoC, PortNumber);
665         }
666
667         return (SK_ADDR_SUCCESS);
668
669 }       /* SkAddrGmacMcClear */
670
671 #ifndef SK_ADDR_CHEAT
672
673 /******************************************************************************
674  *
675  *      SkXmacMcHash - hash multicast address
676  *
677  * Description:
678  *      This routine computes the hash value for a multicast address.
679  *      A CRC32 algorithm is used.
680  *
681  * Notes:
682  *      The code was adapted from the XaQti data sheet.
683  *
684  * Context:
685  *      runtime, pageable
686  *
687  * Returns:
688  *      Hash value of multicast address.
689  */
690 SK_U32 SkXmacMcHash(
691 unsigned char *pMc)     /* Multicast address */
692 {
693         SK_U32 Idx;
694         SK_U32 Bit;
695         SK_U32 Data;
696         SK_U32 Crc;
697
698         Crc = 0xFFFFFFFFUL;
699         for (Idx = 0; Idx < SK_MAC_ADDR_LEN; Idx++) {
700                 Data = *pMc++;
701                 for (Bit = 0; Bit < 8; Bit++, Data >>= 1) {
702                         Crc = (Crc >> 1) ^ (((Crc ^ Data) & 1) ? XMAC_POLY : 0);
703                 }
704         }
705
706         return (Crc & ((1 << HASH_BITS) - 1));
707
708 }       /* SkXmacMcHash */
709
710
711 /******************************************************************************
712  *
713  *      SkGmacMcHash - hash multicast address
714  *
715  * Description:
716  *      This routine computes the hash value for a multicast address.
717  *      A CRC16 algorithm is used.
718  *
719  * Notes:
720  *
721  *
722  * Context:
723  *      runtime, pageable
724  *
725  * Returns:
726  *      Hash value of multicast address.
727  */
728 SK_U32 SkGmacMcHash(
729 unsigned char *pMc)     /* Multicast address */
730 {
731         SK_U32 Data;
732         SK_U32 TmpData;
733         SK_U32 Crc;
734         int Byte;
735         int Bit;
736
737         Crc = 0xFFFFFFFFUL;
738         for (Byte = 0; Byte < 6; Byte++) {
739                 /* Get next byte. */
740                 Data = (SK_U32) pMc[Byte];
741
742                 /* Change bit order in byte. */
743                 TmpData = Data;
744                 for (Bit = 0; Bit < 8; Bit++) {
745                         if (TmpData & 1L) {
746                                 Data |=  1L << (7 - Bit);
747                         }
748                         else {
749                                 Data &= ~(1L << (7 - Bit));
750                         }
751                         TmpData >>= 1;
752                 }
753
754                 Crc ^= (Data << 24);
755                 for (Bit = 0; Bit < 8; Bit++) {
756                         if (Crc & 0x80000000) {
757                                 Crc = (Crc << 1) ^ GMAC_POLY;
758                         }
759                         else {
760                                 Crc <<= 1;
761                         }
762                 }
763         }
764
765         return (Crc & ((1 << HASH_BITS) - 1));
766
767 }       /* SkGmacMcHash */
768
769 #endif  /* not SK_ADDR_CHEAT */
770
771 /******************************************************************************
772  *
773  *      SkAddrMcAdd - add a multicast address to a port
774  *
775  * Description:
776  *      This routine enables reception for a given address on the given port.
777  *
778  *      It calls either SkAddrXmacMcAdd or SkAddrGmacMcAdd, according to the
779  *      adapter in use. The real work is done there.
780  *
781  * Notes:
782  *      The return code is only valid for SK_PROM_MODE_NONE.
783  *
784  * Context:
785  *      runtime, pageable
786  *      may be called after SK_INIT_DATA
787  *
788  * Returns:
789  *      SK_MC_FILTERING_EXACT
790  *      SK_MC_FILTERING_INEXACT
791  *      SK_MC_ILLEGAL_ADDRESS
792  *      SK_MC_ILLEGAL_PORT
793  *      SK_MC_RLMT_OVERFLOW
794  */
795 int     SkAddrMcAdd(
796 SK_AC           *pAC,           /* adapter context */
797 SK_IOC          IoC,            /* I/O context */
798 SK_U32          PortNumber,     /* Port Number */
799 SK_MAC_ADDR     *pMc,           /* multicast address to be added */
800 int                     Flags)          /* permanent/non-permanent */
801 {
802         int ReturnCode;
803
804         if (PortNumber >= (SK_U32) pAC->GIni.GIMacsFound) {
805                 return (SK_ADDR_ILLEGAL_PORT);
806         }
807
808         if (pAC->GIni.GIChipId == CHIP_ID_GENESIS) {
809                 ReturnCode = SkAddrXmacMcAdd(pAC, IoC, PortNumber, pMc, Flags);
810         }
811         else {
812                 ReturnCode = SkAddrGmacMcAdd(pAC, IoC, PortNumber, pMc, Flags);
813         }
814
815         return (ReturnCode);
816
817 }       /* SkAddrMcAdd */
818
819
820 /******************************************************************************
821  *
822  *      SkAddrXmacMcAdd - add a multicast address to a port
823  *
824  * Description:
825  *      This routine enables reception for a given address on the given port.
826  *
827  * Notes:
828  *      The return code is only valid for SK_PROM_MODE_NONE.
829  *
830  *      The multicast bit is only checked if there are no free exact match
831  *      entries.
832  *
833  * Context:
834  *      runtime, pageable
835  *      may be called after SK_INIT_DATA
836  *
837  * Returns:
838  *      SK_MC_FILTERING_EXACT
839  *      SK_MC_FILTERING_INEXACT
840  *      SK_MC_ILLEGAL_ADDRESS
841  *      SK_MC_RLMT_OVERFLOW
842  */
843 int     SkAddrXmacMcAdd(
844 SK_AC           *pAC,           /* adapter context */
845 SK_IOC          IoC,            /* I/O context */
846 SK_U32          PortNumber,     /* Port Number */
847 SK_MAC_ADDR     *pMc,           /* multicast address to be added */
848 int             Flags)          /* permanent/non-permanent */
849 {
850         int     i;
851         SK_U8   Inexact;
852 #ifndef SK_ADDR_CHEAT
853         SK_U32 HashBit;
854 #endif  /* !defined(SK_ADDR_CHEAT) */
855
856         if (Flags & SK_ADDR_PERMANENT) {        /* permanent => RLMT */
857 #ifdef xDEBUG
858                 if (pAC->Addr.Port[PortNumber].NextExactMatchRlmt <
859                         SK_ADDR_FIRST_MATCH_RLMT) {
860                         Next0[PortNumber] |= 1;
861                         return (SK_MC_RLMT_OVERFLOW);
862                 }
863 #endif  /* DEBUG */
864
865                 if (pAC->Addr.Port[PortNumber].NextExactMatchRlmt >
866                         SK_ADDR_LAST_MATCH_RLMT) {
867                         return (SK_MC_RLMT_OVERFLOW);
868                 }
869
870                 /* Set a RLMT multicast address. */
871
872                 pAC->Addr.Port[PortNumber].Exact[
873                         pAC->Addr.Port[PortNumber].NextExactMatchRlmt++] = *pMc;
874
875                 return (SK_MC_FILTERING_EXACT);
876         }
877
878 #ifdef xDEBUG
879         if (pAC->Addr.Port[PortNumber].NextExactMatchDrv <
880                 SK_ADDR_FIRST_MATCH_DRV) {
881                         Next0[PortNumber] |= 2;
882                 return (SK_MC_RLMT_OVERFLOW);
883         }
884 #endif  /* DEBUG */
885
886         if (pAC->Addr.Port[PortNumber].NextExactMatchDrv <= SK_ADDR_LAST_MATCH_DRV) {
887
888                 /* Set exact match entry. */
889                 pAC->Addr.Port[PortNumber].Exact[
890                         pAC->Addr.Port[PortNumber].NextExactMatchDrv++] = *pMc;
891
892                 /* Clear InexactFilter */
893                 for (i = 0; i < 8; i++) {
894                         pAC->Addr.Port[PortNumber].InexactFilter.Bytes[i] = 0;
895                 }
896         }
897         else {
898                 if (!(pMc->a[0] & SK_MC_BIT)) {
899                         /* Hashing only possible with multicast addresses. */
900                         return (SK_MC_ILLEGAL_ADDRESS);
901                 }
902 #ifndef SK_ADDR_CHEAT
903                 /* Compute hash value of address. */
904                 HashBit = 63 - SkXmacMcHash(&pMc->a[0]);
905
906                 /* Add bit to InexactFilter. */
907                 pAC->Addr.Port[PortNumber].InexactFilter.Bytes[HashBit / 8] |=
908                         1 << (HashBit % 8);
909 #else   /* SK_ADDR_CHEAT */
910                 /* Set all bits in InexactFilter. */
911                 for (i = 0; i < 8; i++) {
912                         pAC->Addr.Port[PortNumber].InexactFilter.Bytes[i] = 0xFF;
913                 }
914 #endif  /* SK_ADDR_CHEAT */
915         }
916
917         for (Inexact = 0, i = 0; i < 8; i++) {
918                 Inexact |= pAC->Addr.Port[PortNumber].InexactFilter.Bytes[i];
919         }
920
921         if (Inexact == 0 && pAC->Addr.Port[PortNumber].PromMode == 0) {
922                 return (SK_MC_FILTERING_EXACT);
923         }
924         else {
925                 return (SK_MC_FILTERING_INEXACT);
926         }
927
928 }       /* SkAddrXmacMcAdd */
929
930
931 /******************************************************************************
932  *
933  *      SkAddrGmacMcAdd - add a multicast address to a port
934  *
935  * Description:
936  *      This routine enables reception for a given address on the given port.
937  *
938  * Notes:
939  *      The return code is only valid for SK_PROM_MODE_NONE.
940  *
941  * Context:
942  *      runtime, pageable
943  *      may be called after SK_INIT_DATA
944  *
945  * Returns:
946  *      SK_MC_FILTERING_INEXACT
947  *      SK_MC_ILLEGAL_ADDRESS
948  */
949 int     SkAddrGmacMcAdd(
950 SK_AC           *pAC,           /* adapter context */
951 SK_IOC          IoC,            /* I/O context */
952 SK_U32          PortNumber,     /* Port Number */
953 SK_MAC_ADDR     *pMc,           /* multicast address to be added */
954 int             Flags)          /* permanent/non-permanent */
955 {
956         int     i;
957 #ifndef SK_ADDR_CHEAT
958         SK_U32 HashBit;
959 #endif  /* !defined(SK_ADDR_CHEAT) */
960
961         if (!(pMc->a[0] & SK_MC_BIT)) {
962                 /* Hashing only possible with multicast addresses. */
963                 return (SK_MC_ILLEGAL_ADDRESS);
964         }
965
966 #ifndef SK_ADDR_CHEAT
967
968         /* Compute hash value of address. */
969         HashBit = SkGmacMcHash(&pMc->a[0]);
970
971         if (Flags & SK_ADDR_PERMANENT) {        /* permanent => RLMT */
972
973                 /* Add bit to InexactRlmtFilter. */
974                 pAC->Addr.Port[PortNumber].InexactRlmtFilter.Bytes[HashBit / 8] |=
975                         1 << (HashBit % 8);
976
977                 /* Copy bit to InexactFilter. */
978                 for (i = 0; i < 8; i++) {
979                         pAC->Addr.Port[PortNumber].InexactFilter.Bytes[i] |=
980                                 pAC->Addr.Port[PortNumber].InexactRlmtFilter.Bytes[i];
981                 }
982 #ifdef DEBUG
983                 SK_DBG_MSG(pAC, SK_DBGMOD_ADDR, SK_DBGCAT_CTRL,
984                 ("GMAC InexactRlmtFilter: %02X %02X %02X %02X %02X %02X %02X %02X\n",
985                         pAC->Addr.Port[PortNumber].InexactRlmtFilter.Bytes[0],
986                         pAC->Addr.Port[PortNumber].InexactRlmtFilter.Bytes[1],
987                         pAC->Addr.Port[PortNumber].InexactRlmtFilter.Bytes[2],
988                         pAC->Addr.Port[PortNumber].InexactRlmtFilter.Bytes[3],
989                         pAC->Addr.Port[PortNumber].InexactRlmtFilter.Bytes[4],
990                         pAC->Addr.Port[PortNumber].InexactRlmtFilter.Bytes[5],
991                         pAC->Addr.Port[PortNumber].InexactRlmtFilter.Bytes[6],
992                         pAC->Addr.Port[PortNumber].InexactRlmtFilter.Bytes[7]))
993 #endif  /* DEBUG */
994         }
995         else {  /* not permanent => DRV */
996
997                 /* Add bit to InexactDrvFilter. */
998                 pAC->Addr.Port[PortNumber].InexactDrvFilter.Bytes[HashBit / 8] |=
999                         1 << (HashBit % 8);
1000
1001                 /* Copy bit to InexactFilter. */
1002                 for (i = 0; i < 8; i++) {
1003                         pAC->Addr.Port[PortNumber].InexactFilter.Bytes[i] |=
1004                                 pAC->Addr.Port[PortNumber].InexactDrvFilter.Bytes[i];
1005                 }
1006 #ifdef DEBUG
1007                 SK_DBG_MSG(pAC, SK_DBGMOD_ADDR, SK_DBGCAT_CTRL,
1008                 ("GMAC InexactDrvFilter: %02X %02X %02X %02X %02X %02X %02X %02X\n",
1009                         pAC->Addr.Port[PortNumber].InexactDrvFilter.Bytes[0],
1010                         pAC->Addr.Port[PortNumber].InexactDrvFilter.Bytes[1],
1011                         pAC->Addr.Port[PortNumber].InexactDrvFilter.Bytes[2],
1012                         pAC->Addr.Port[PortNumber].InexactDrvFilter.Bytes[3],
1013                         pAC->Addr.Port[PortNumber].InexactDrvFilter.Bytes[4],
1014                         pAC->Addr.Port[PortNumber].InexactDrvFilter.Bytes[5],
1015                         pAC->Addr.Port[PortNumber].InexactDrvFilter.Bytes[6],
1016                         pAC->Addr.Port[PortNumber].InexactDrvFilter.Bytes[7]))
1017 #endif  /* DEBUG */
1018         }
1019
1020 #else   /* SK_ADDR_CHEAT */
1021
1022         /* Set all bits in InexactFilter. */
1023         for (i = 0; i < 8; i++) {
1024                 pAC->Addr.Port[PortNumber].InexactFilter.Bytes[i] = 0xFF;
1025         }
1026 #endif  /* SK_ADDR_CHEAT */
1027
1028         return (SK_MC_FILTERING_INEXACT);
1029
1030 }       /* SkAddrGmacMcAdd */
1031
1032
1033 /******************************************************************************
1034  *
1035  *      SkAddrMcUpdate - update the HW MC address table and set the MAC address
1036  *
1037  * Description:
1038  *      This routine enables reception of the addresses contained in a local
1039  *      table for a given port.
1040  *      It also programs the port's current physical MAC address.
1041  *
1042  *      It calls either SkAddrXmacMcUpdate or SkAddrGmacMcUpdate, according
1043  *      to the adapter in use. The real work is done there.
1044  *
1045  * Notes:
1046  *      The return code is only valid for SK_PROM_MODE_NONE.
1047  *
1048  * Context:
1049  *      runtime, pageable
1050  *      may be called after SK_INIT_IO
1051  *
1052  * Returns:
1053  *      SK_MC_FILTERING_EXACT
1054  *      SK_MC_FILTERING_INEXACT
1055  *      SK_ADDR_ILLEGAL_PORT
1056  */
1057 int     SkAddrMcUpdate(
1058 SK_AC   *pAC,           /* adapter context */
1059 SK_IOC  IoC,            /* I/O context */
1060 SK_U32  PortNumber)     /* Port Number */
1061 {
1062         int ReturnCode;
1063
1064         if (PortNumber >= (SK_U32) pAC->GIni.GIMacsFound) {
1065                 return (SK_ADDR_ILLEGAL_PORT);
1066         }
1067
1068         if (pAC->GIni.GIChipId == CHIP_ID_GENESIS) {
1069                 ReturnCode = SkAddrXmacMcUpdate(pAC, IoC, PortNumber);
1070         }
1071         else {
1072                 ReturnCode = SkAddrGmacMcUpdate(pAC, IoC, PortNumber);
1073         }
1074
1075         return (ReturnCode);
1076
1077 }       /* SkAddrMcUpdate */
1078
1079
1080 /******************************************************************************
1081  *
1082  *      SkAddrXmacMcUpdate - update the HW MC address table and set the MAC address
1083  *
1084  * Description:
1085  *      This routine enables reception of the addresses contained in a local
1086  *      table for a given port.
1087  *      It also programs the port's current physical MAC address.
1088  *
1089  * Notes:
1090  *      The return code is only valid for SK_PROM_MODE_NONE.
1091  *
1092  * Context:
1093  *      runtime, pageable
1094  *      may be called after SK_INIT_IO
1095  *
1096  * Returns:
1097  *      SK_MC_FILTERING_EXACT
1098  *      SK_MC_FILTERING_INEXACT
1099  *      SK_ADDR_ILLEGAL_PORT
1100  */
1101 int     SkAddrXmacMcUpdate(
1102 SK_AC   *pAC,           /* adapter context */
1103 SK_IOC  IoC,            /* I/O context */
1104 SK_U32  PortNumber)     /* Port Number */
1105 {
1106         SK_U32          i;
1107         SK_U8           Inexact;
1108         SK_U16          *OutAddr;
1109         SK_ADDR_PORT    *pAPort;
1110
1111         SK_DBG_MSG(pAC,SK_DBGMOD_ADDR, SK_DBGCAT_CTRL,
1112                 ("SkAddrXmacMcUpdate on Port %u.\n", PortNumber))
1113
1114         pAPort = &pAC->Addr.Port[PortNumber];
1115
1116 #ifdef DEBUG
1117         SK_DBG_MSG(pAC,SK_DBGMOD_ADDR, SK_DBGCAT_CTRL,
1118                 ("Next0 on Port %d: %d\n", PortNumber, Next0[PortNumber]))
1119 #endif  /* DEBUG */
1120
1121         /* Start with 0 to also program the logical MAC address. */
1122         for (i = 0; i < pAPort->NextExactMatchRlmt; i++) {
1123                 /* Set exact match address i on XMAC */
1124                 OutAddr = (SK_U16 *) &pAPort->Exact[i].a[0];
1125                 XM_OUTADDR(IoC, PortNumber, XM_EXM(i), OutAddr);
1126         }
1127
1128         /* Clear other permanent exact match addresses on XMAC */
1129         if (pAPort->NextExactMatchRlmt <= SK_ADDR_LAST_MATCH_RLMT) {
1130
1131                 SkXmClrExactAddr(pAC, IoC, PortNumber, pAPort->NextExactMatchRlmt,
1132                         SK_ADDR_LAST_MATCH_RLMT);
1133         }
1134
1135         for (i = pAPort->FirstExactMatchDrv; i < pAPort->NextExactMatchDrv; i++) {
1136                 OutAddr = (SK_U16 *) &pAPort->Exact[i].a[0];
1137                 XM_OUTADDR(IoC, PortNumber, XM_EXM(i), OutAddr);
1138         }
1139
1140         /* Clear other non-permanent exact match addresses on XMAC */
1141         if (pAPort->NextExactMatchDrv <= SK_ADDR_LAST_MATCH_DRV) {
1142
1143                 SkXmClrExactAddr(pAC, IoC, PortNumber, pAPort->NextExactMatchDrv,
1144                         SK_ADDR_LAST_MATCH_DRV);
1145         }
1146
1147         for (Inexact = 0, i = 0; i < 8; i++) {
1148                 Inexact |= pAPort->InexactFilter.Bytes[i];
1149         }
1150
1151         if (pAPort->PromMode & SK_PROM_MODE_ALL_MC) {
1152
1153                 /* Set all bits in 64-bit hash register. */
1154                 XM_OUTHASH(IoC, PortNumber, XM_HSM, &OnesHash);
1155
1156                 /* Enable Hashing */
1157                 SkMacHashing(pAC, IoC, PortNumber, SK_TRUE);
1158         }
1159         else if (Inexact != 0) {
1160
1161                 /* Set 64-bit hash register to InexactFilter. */
1162                 XM_OUTHASH(IoC, PortNumber, XM_HSM, &pAPort->InexactFilter.Bytes[0]);
1163
1164                 /* Enable Hashing */
1165                 SkMacHashing(pAC, IoC, PortNumber, SK_TRUE);
1166         }
1167         else {
1168                 /* Disable Hashing */
1169                 SkMacHashing(pAC, IoC, PortNumber, SK_FALSE);
1170         }
1171
1172         if (pAPort->PromMode != SK_PROM_MODE_NONE) {
1173                 (void) SkAddrXmacPromiscuousChange(pAC, IoC, PortNumber, pAPort->PromMode);
1174         }
1175
1176         /* Set port's current physical MAC address. */
1177         OutAddr = (SK_U16 *) &pAPort->CurrentMacAddress.a[0];
1178
1179         XM_OUTADDR(IoC, PortNumber, XM_SA, OutAddr);
1180
1181 #ifdef xDEBUG
1182         for (i = 0; i < pAPort->NextExactMatchRlmt; i++) {
1183                 SK_U8           InAddr8[6];
1184                 SK_U16          *InAddr;
1185
1186                 /* Get exact match address i from port PortNumber. */
1187                 InAddr = (SK_U16 *) &InAddr8[0];
1188
1189                 XM_INADDR(IoC, PortNumber, XM_EXM(i), InAddr);
1190
1191                 SK_DBG_MSG(pAC,SK_DBGMOD_ADDR, SK_DBGCAT_CTRL,
1192                         ("SkAddrXmacMcUpdate: MC address %d on Port %u: ",
1193                          "%02x %02x %02x %02x %02x %02x -- %02x %02x %02x %02x %02x %02x\n",
1194                                 i,
1195                                 PortNumber,
1196                                 InAddr8[0],
1197                                 InAddr8[1],
1198                                 InAddr8[2],
1199                                 InAddr8[3],
1200                                 InAddr8[4],
1201                                 InAddr8[5],
1202                                 pAPort->Exact[i].a[0],
1203                                 pAPort->Exact[i].a[1],
1204                                 pAPort->Exact[i].a[2],
1205                                 pAPort->Exact[i].a[3],
1206                                 pAPort->Exact[i].a[4],
1207                                 pAPort->Exact[i].a[5]))
1208         }
1209 #endif  /* DEBUG */
1210
1211         /* Determine return value. */
1212         if (Inexact == 0 && pAPort->PromMode == 0) {
1213                 return (SK_MC_FILTERING_EXACT);
1214         }
1215         else {
1216                 return (SK_MC_FILTERING_INEXACT);
1217         }
1218
1219 }       /* SkAddrXmacMcUpdate */
1220
1221
1222 /******************************************************************************
1223  *
1224  *      SkAddrGmacMcUpdate - update the HW MC address table and set the MAC address
1225  *
1226  * Description:
1227  *      This routine enables reception of the addresses contained in a local
1228  *      table for a given port.
1229  *      It also programs the port's current physical MAC address.
1230  *
1231  * Notes:
1232  *      The return code is only valid for SK_PROM_MODE_NONE.
1233  *
1234  * Context:
1235  *      runtime, pageable
1236  *      may be called after SK_INIT_IO
1237  *
1238  * Returns:
1239  *      SK_MC_FILTERING_EXACT
1240  *      SK_MC_FILTERING_INEXACT
1241  *      SK_ADDR_ILLEGAL_PORT
1242  */
1243 int     SkAddrGmacMcUpdate(
1244 SK_AC   *pAC,           /* adapter context */
1245 SK_IOC  IoC,            /* I/O context */
1246 SK_U32  PortNumber)     /* Port Number */
1247 {
1248         SK_U32          i;
1249         SK_U8           Inexact;
1250         SK_U16          *OutAddr;
1251         SK_ADDR_PORT    *pAPort;
1252
1253         SK_DBG_MSG(pAC,SK_DBGMOD_ADDR, SK_DBGCAT_CTRL,
1254                 ("SkAddrGmacMcUpdate on Port %u.\n", PortNumber))
1255
1256         pAPort = &pAC->Addr.Port[PortNumber];
1257
1258 #ifdef DEBUG
1259         SK_DBG_MSG(pAC,SK_DBGMOD_ADDR, SK_DBGCAT_CTRL,
1260                 ("Next0 on Port %d: %d\n", PortNumber, Next0[PortNumber]))
1261 #endif  /* DEBUG */
1262
1263         for (Inexact = 0, i = 0; i < 8; i++) {
1264                 Inexact |= pAPort->InexactFilter.Bytes[i];
1265         }
1266
1267         /* Set 64-bit hash register to InexactFilter. */
1268         GM_OUTHASH(IoC, PortNumber, GM_MC_ADDR_H1,
1269                 &pAPort->InexactFilter.Bytes[0]);
1270
1271         if (pAPort->PromMode & SK_PROM_MODE_ALL_MC) {
1272
1273                 /* Set all bits in 64-bit hash register. */
1274                 GM_OUTHASH(IoC, PortNumber, GM_MC_ADDR_H1, &OnesHash);
1275
1276                 /* Enable Hashing */
1277                 SkMacHashing(pAC, IoC, PortNumber, SK_TRUE);
1278         }
1279         else {
1280                 /* Enable Hashing. */
1281                 SkMacHashing(pAC, IoC, PortNumber, SK_TRUE);
1282         }
1283
1284         if (pAPort->PromMode != SK_PROM_MODE_NONE) {
1285                 (void) SkAddrGmacPromiscuousChange(pAC, IoC, PortNumber, pAPort->PromMode);
1286         }
1287
1288         /* Set port's current physical MAC address. */
1289         OutAddr = (SK_U16 *) &pAPort->CurrentMacAddress.a[0];
1290         GM_OUTADDR(IoC, PortNumber, GM_SRC_ADDR_1L, OutAddr);
1291
1292         /* Set port's current logical MAC address. */
1293         OutAddr = (SK_U16 *) &pAPort->Exact[0].a[0];
1294         GM_OUTADDR(IoC, PortNumber, GM_SRC_ADDR_2L, OutAddr);
1295
1296 #ifdef DEBUG
1297         SK_DBG_MSG(pAC, SK_DBGMOD_ADDR, SK_DBGCAT_CTRL,
1298                 ("SkAddrGmacMcUpdate: Permanent Physical MAC Address: %02X %02X %02X %02X %02X %02X\n",
1299                         pAPort->Exact[0].a[0],
1300                         pAPort->Exact[0].a[1],
1301                         pAPort->Exact[0].a[2],
1302                         pAPort->Exact[0].a[3],
1303                         pAPort->Exact[0].a[4],
1304                         pAPort->Exact[0].a[5]))
1305
1306         SK_DBG_MSG(pAC, SK_DBGMOD_ADDR, SK_DBGCAT_CTRL,
1307                 ("SkAddrGmacMcUpdate: Physical MAC Address: %02X %02X %02X %02X %02X %02X\n",
1308                         pAPort->CurrentMacAddress.a[0],
1309                         pAPort->CurrentMacAddress.a[1],
1310                         pAPort->CurrentMacAddress.a[2],
1311                         pAPort->CurrentMacAddress.a[3],
1312                         pAPort->CurrentMacAddress.a[4],
1313                         pAPort->CurrentMacAddress.a[5]))
1314 #endif  /* DEBUG */
1315
1316         /* Determine return value. */
1317         if (Inexact == 0 && pAPort->PromMode == 0) {
1318                 return (SK_MC_FILTERING_EXACT);
1319         }
1320         else {
1321                 return (SK_MC_FILTERING_INEXACT);
1322         }
1323
1324 }       /* SkAddrGmacMcUpdate */
1325
1326
1327 /******************************************************************************
1328  *
1329  *      SkAddrOverride - override a port's MAC address
1330  *
1331  * Description:
1332  *      This routine overrides the MAC address of one port.
1333  *
1334  * Context:
1335  *      runtime, pageable
1336  *      may be called after SK_INIT_IO
1337  *
1338  * Returns:
1339  *      SK_ADDR_SUCCESS if successful.
1340  *      SK_ADDR_DUPLICATE_ADDRESS if duplicate MAC address.
1341  *      SK_ADDR_MULTICAST_ADDRESS if multicast or broadcast address.
1342  *      SK_ADDR_TOO_EARLY if SK_INIT_IO was not executed before.
1343  */
1344 int     SkAddrOverride(
1345 SK_AC           *pAC,           /* adapter context */
1346 SK_IOC          IoC,            /* I/O context */
1347 SK_U32          PortNumber,     /* Port Number */
1348 SK_MAC_ADDR     *pNewAddr,      /* new MAC address */
1349 int                     Flags)          /* logical/physical MAC address */
1350 {
1351         SK_EVPARA       Para;
1352         SK_U32          NetNumber;
1353         SK_U32          i;
1354         SK_U16          *OutAddr;
1355
1356         NetNumber = pAC->Rlmt.Port[PortNumber].Net->NetNumber;
1357
1358         if (PortNumber >= (SK_U32) pAC->GIni.GIMacsFound) {
1359                 return (SK_ADDR_ILLEGAL_PORT);
1360         }
1361
1362         if (pNewAddr != NULL && (pNewAddr->a[0] & SK_MC_BIT) != 0) {
1363                 return (SK_ADDR_MULTICAST_ADDRESS);
1364         }
1365
1366         if (!pAC->Addr.Net[NetNumber].CurrentMacAddressSet) {
1367                 return (SK_ADDR_TOO_EARLY);
1368         }
1369
1370         if (Flags & SK_ADDR_SET_LOGICAL) {      /* Activate logical MAC address. */
1371                 /* Parameter *pNewAddr is ignored. */
1372                 for (i = 0; i < (SK_U32) pAC->GIni.GIMacsFound; i++) {
1373                         if (!pAC->Addr.Port[i].CurrentMacAddressSet) {
1374                                 return (SK_ADDR_TOO_EARLY);
1375                         }
1376                 }
1377
1378                 /* Set PortNumber to number of net's active port. */
1379                 PortNumber = pAC->Rlmt.Net[NetNumber].
1380                         Port[pAC->Addr.Net[NetNumber].ActivePort]->PortNumber;
1381
1382                 pAC->Addr.Port[PortNumber].Exact[0] =
1383                         pAC->Addr.Net[NetNumber].CurrentMacAddress;
1384
1385                 /* Write address to first exact match entry of active port. */
1386                 (void) SkAddrMcUpdate(pAC, IoC, PortNumber);
1387         }
1388         else if (Flags & SK_ADDR_CLEAR_LOGICAL) {
1389                 /* Deactivate logical MAC address. */
1390                 /* Parameter *pNewAddr is ignored. */
1391                 for (i = 0; i < (SK_U32) pAC->GIni.GIMacsFound; i++) {
1392                         if (!pAC->Addr.Port[i].CurrentMacAddressSet) {
1393                                 return (SK_ADDR_TOO_EARLY);
1394                         }
1395                 }
1396
1397                 /* Set PortNumber to number of net's active port. */
1398                 PortNumber = pAC->Rlmt.Net[NetNumber].
1399                         Port[pAC->Addr.Net[NetNumber].ActivePort]->PortNumber;
1400
1401                 for (i = 0; i < SK_MAC_ADDR_LEN; i++ ) {
1402                         pAC->Addr.Port[PortNumber].Exact[0].a[i] = 0;
1403                 }
1404
1405                 /* Write address to first exact match entry of active port. */
1406                 (void) SkAddrMcUpdate(pAC, IoC, PortNumber);
1407         }
1408         else if (Flags & SK_ADDR_PHYSICAL_ADDRESS) {    /* Physical MAC address. */
1409                 if (SK_ADDR_EQUAL(pNewAddr->a,
1410                         pAC->Addr.Net[NetNumber].CurrentMacAddress.a)) {
1411                         return (SK_ADDR_DUPLICATE_ADDRESS);
1412                 }
1413
1414                 for (i = 0; i < (SK_U32) pAC->GIni.GIMacsFound; i++) {
1415                         if (!pAC->Addr.Port[i].CurrentMacAddressSet) {
1416                                 return (SK_ADDR_TOO_EARLY);
1417                         }
1418
1419                         if (SK_ADDR_EQUAL(pNewAddr->a,
1420                                 pAC->Addr.Port[i].CurrentMacAddress.a)) {
1421                                 if (i == PortNumber) {
1422                                         return (SK_ADDR_SUCCESS);
1423                                 }
1424                                 else {
1425                                         return (SK_ADDR_DUPLICATE_ADDRESS);
1426                                 }
1427                         }
1428                 }
1429
1430                 pAC->Addr.Port[PortNumber].PreviousMacAddress =
1431                         pAC->Addr.Port[PortNumber].CurrentMacAddress;
1432                 pAC->Addr.Port[PortNumber].CurrentMacAddress = *pNewAddr;
1433
1434                 /* Change port's physical MAC address. */
1435                 OutAddr = (SK_U16 *) pNewAddr;
1436
1437                 if (pAC->GIni.GIChipId == CHIP_ID_GENESIS) {
1438                         XM_OUTADDR(IoC, PortNumber, XM_SA, OutAddr);
1439                 }
1440                 else {
1441                         GM_OUTADDR(IoC, PortNumber, GM_SRC_ADDR_1L, OutAddr);
1442                 }
1443
1444                 /* Report address change to RLMT. */
1445                 Para.Para32[0] = PortNumber;
1446                 Para.Para32[0] = -1;
1447                 SkEventQueue(pAC, SKGE_RLMT, SK_RLMT_PORT_ADDR, Para);
1448         }
1449         else {  /* Logical MAC address. */
1450                 if (SK_ADDR_EQUAL(pNewAddr->a,
1451                         pAC->Addr.Net[NetNumber].CurrentMacAddress.a)) {
1452                         return (SK_ADDR_SUCCESS);
1453                 }
1454
1455                 for (i = 0; i < (SK_U32) pAC->GIni.GIMacsFound; i++) {
1456                         if (!pAC->Addr.Port[i].CurrentMacAddressSet) {
1457                                 return (SK_ADDR_TOO_EARLY);
1458                         }
1459
1460                         if (SK_ADDR_EQUAL(pNewAddr->a,
1461                                 pAC->Addr.Port[i].CurrentMacAddress.a)) {
1462                                 return (SK_ADDR_DUPLICATE_ADDRESS);
1463                         }
1464                 }
1465
1466                 /*
1467                  * In case that the physical and the logical MAC addresses are equal
1468                  * we must also change the physical MAC address here.
1469                  * In this case we have an adapter which initially was programmed with
1470                  * two identical MAC addresses.
1471                  */
1472                 if (SK_ADDR_EQUAL(pAC->Addr.Port[PortNumber].CurrentMacAddress.a,
1473                                 pAC->Addr.Port[PortNumber].Exact[0].a)) {
1474
1475                         pAC->Addr.Port[PortNumber].PreviousMacAddress =
1476                                 pAC->Addr.Port[PortNumber].CurrentMacAddress;
1477                         pAC->Addr.Port[PortNumber].CurrentMacAddress = *pNewAddr;
1478
1479                         /* Report address change to RLMT. */
1480                         Para.Para32[0] = PortNumber;
1481                         Para.Para32[0] = -1;
1482                         SkEventQueue(pAC, SKGE_RLMT, SK_RLMT_PORT_ADDR, Para);
1483                 }
1484
1485                 /* Set PortNumber to number of net's active port. */
1486                 PortNumber = pAC->Rlmt.Net[NetNumber].
1487                         Port[pAC->Addr.Net[NetNumber].ActivePort]->PortNumber;
1488
1489                 pAC->Addr.Net[NetNumber].CurrentMacAddress = *pNewAddr;
1490                 pAC->Addr.Port[PortNumber].Exact[0] = *pNewAddr;
1491 #ifdef DEBUG
1492                 SK_DBG_MSG(pAC,SK_DBGMOD_ADDR, SK_DBGCAT_CTRL,
1493                         ("SkAddrOverride: Permanent MAC Address: %02X %02X %02X %02X %02X %02X\n",
1494                                 pAC->Addr.Net[NetNumber].PermanentMacAddress.a[0],
1495                                 pAC->Addr.Net[NetNumber].PermanentMacAddress.a[1],
1496                                 pAC->Addr.Net[NetNumber].PermanentMacAddress.a[2],
1497                                 pAC->Addr.Net[NetNumber].PermanentMacAddress.a[3],
1498                                 pAC->Addr.Net[NetNumber].PermanentMacAddress.a[4],
1499                                 pAC->Addr.Net[NetNumber].PermanentMacAddress.a[5]))
1500
1501                 SK_DBG_MSG(pAC,SK_DBGMOD_ADDR, SK_DBGCAT_CTRL,
1502                         ("SkAddrOverride: New logical MAC Address: %02X %02X %02X %02X %02X %02X\n",
1503                                 pAC->Addr.Net[NetNumber].CurrentMacAddress.a[0],
1504                                 pAC->Addr.Net[NetNumber].CurrentMacAddress.a[1],
1505                                 pAC->Addr.Net[NetNumber].CurrentMacAddress.a[2],
1506                                 pAC->Addr.Net[NetNumber].CurrentMacAddress.a[3],
1507                                 pAC->Addr.Net[NetNumber].CurrentMacAddress.a[4],
1508                                 pAC->Addr.Net[NetNumber].CurrentMacAddress.a[5]))
1509 #endif  /* DEBUG */
1510
1511         /* Write address to first exact match entry of active port. */
1512                 (void) SkAddrMcUpdate(pAC, IoC, PortNumber);
1513         }
1514
1515         return (SK_ADDR_SUCCESS);
1516
1517 }       /* SkAddrOverride */
1518
1519
1520 /******************************************************************************
1521  *
1522  *      SkAddrPromiscuousChange - set promiscuous mode for given port
1523  *
1524  * Description:
1525  *      This routine manages promiscuous mode:
1526  *      - none
1527  *      - all LLC frames
1528  *      - all MC frames
1529  *
1530  *      It calls either SkAddrXmacPromiscuousChange or
1531  *      SkAddrGmacPromiscuousChange, according to the adapter in use.
1532  *      The real work is done there.
1533  *
1534  * Context:
1535  *      runtime, pageable
1536  *      may be called after SK_INIT_IO
1537  *
1538  * Returns:
1539  *      SK_ADDR_SUCCESS
1540  *      SK_ADDR_ILLEGAL_PORT
1541  */
1542 int     SkAddrPromiscuousChange(
1543 SK_AC   *pAC,                   /* adapter context */
1544 SK_IOC  IoC,                    /* I/O context */
1545 SK_U32  PortNumber,             /* port whose promiscuous mode changes */
1546 int             NewPromMode)    /* new promiscuous mode */
1547 {
1548         int ReturnCode;
1549
1550         if (PortNumber >= (SK_U32) pAC->GIni.GIMacsFound) {
1551                 return (SK_ADDR_ILLEGAL_PORT);
1552         }
1553
1554         if (pAC->GIni.GIChipId == CHIP_ID_GENESIS) {
1555                 ReturnCode = SkAddrXmacPromiscuousChange(pAC, IoC, PortNumber, NewPromMode);
1556         }
1557         else {
1558                 ReturnCode = SkAddrGmacPromiscuousChange(pAC, IoC, PortNumber, NewPromMode);
1559         }
1560
1561         return (ReturnCode);
1562
1563 }       /* SkAddrPromiscuousChange */
1564
1565
1566 /******************************************************************************
1567  *
1568  *      SkAddrXmacPromiscuousChange - set promiscuous mode for given port
1569  *
1570  * Description:
1571  *      This routine manages promiscuous mode:
1572  *      - none
1573  *      - all LLC frames
1574  *      - all MC frames
1575  *
1576  * Context:
1577  *      runtime, pageable
1578  *      may be called after SK_INIT_IO
1579  *
1580  * Returns:
1581  *      SK_ADDR_SUCCESS
1582  *      SK_ADDR_ILLEGAL_PORT
1583  */
1584 int     SkAddrXmacPromiscuousChange(
1585 SK_AC   *pAC,                   /* adapter context */
1586 SK_IOC  IoC,                    /* I/O context */
1587 SK_U32  PortNumber,             /* port whose promiscuous mode changes */
1588 int             NewPromMode)    /* new promiscuous mode */
1589 {
1590         int                     i;
1591         SK_BOOL         InexactModeBit;
1592         SK_U8           Inexact;
1593         SK_U8           HwInexact;
1594         SK_FILTER64     HwInexactFilter;
1595         SK_U16          LoMode;         /* Lower 16 bits of XMAC Mode Register. */
1596         int                     CurPromMode = SK_PROM_MODE_NONE;
1597
1598         /* Read CurPromMode from Hardware. */
1599         XM_IN16(IoC, PortNumber, XM_MODE, &LoMode);
1600
1601         if ((LoMode & XM_MD_ENA_PROM) != 0) {
1602                 /* Promiscuous mode! */
1603                 CurPromMode |= SK_PROM_MODE_LLC;
1604         }
1605
1606         for (Inexact = 0xFF, i = 0; i < 8; i++) {
1607                 Inexact &= pAC->Addr.Port[PortNumber].InexactFilter.Bytes[i];
1608         }
1609         if (Inexact == 0xFF) {
1610                 CurPromMode |= (pAC->Addr.Port[PortNumber].PromMode & SK_PROM_MODE_ALL_MC);
1611         }
1612         else {
1613                 /* Get InexactModeBit (bit XM_MD_ENA_HASH in mode register) */
1614                 XM_IN16(IoC, PortNumber, XM_MODE, &LoMode);
1615
1616                 InexactModeBit = (LoMode & XM_MD_ENA_HASH) != 0;
1617
1618                 /* Read 64-bit hash register from XMAC */
1619                 XM_INHASH(IoC, PortNumber, XM_HSM, &HwInexactFilter.Bytes[0]);
1620
1621                 for (HwInexact = 0xFF, i = 0; i < 8; i++) {
1622                         HwInexact &= HwInexactFilter.Bytes[i];
1623                 }
1624
1625                 if (InexactModeBit && (HwInexact == 0xFF)) {
1626                         CurPromMode |= SK_PROM_MODE_ALL_MC;
1627                 }
1628         }
1629
1630         pAC->Addr.Port[PortNumber].PromMode = NewPromMode;
1631
1632         if (NewPromMode == CurPromMode) {
1633                 return (SK_ADDR_SUCCESS);
1634         }
1635
1636         if ((NewPromMode & SK_PROM_MODE_ALL_MC) &&
1637                 !(CurPromMode & SK_PROM_MODE_ALL_MC)) { /* All MC. */
1638
1639                 /* Set all bits in 64-bit hash register. */
1640                 XM_OUTHASH(IoC, PortNumber, XM_HSM, &OnesHash);
1641
1642                 /* Enable Hashing */
1643                 SkMacHashing(pAC, IoC, PortNumber, SK_TRUE);
1644         }
1645         else if ((CurPromMode & SK_PROM_MODE_ALL_MC) &&
1646                 !(NewPromMode & SK_PROM_MODE_ALL_MC)) { /* Norm MC. */
1647                 for (Inexact = 0, i = 0; i < 8; i++) {
1648                         Inexact |= pAC->Addr.Port[PortNumber].InexactFilter.Bytes[i];
1649                 }
1650                 if (Inexact == 0) {
1651                         /* Disable Hashing */
1652                         SkMacHashing(pAC, IoC, PortNumber, SK_FALSE);
1653                 }
1654                 else {
1655                         /* Set 64-bit hash register to InexactFilter. */
1656                         XM_OUTHASH(IoC, PortNumber, XM_HSM,
1657                                 &pAC->Addr.Port[PortNumber].InexactFilter.Bytes[0]);
1658
1659                         /* Enable Hashing */
1660                         SkMacHashing(pAC, IoC, PortNumber, SK_TRUE);
1661                 }
1662         }
1663
1664         if ((NewPromMode & SK_PROM_MODE_LLC) &&
1665                 !(CurPromMode & SK_PROM_MODE_LLC)) {    /* Prom. LLC */
1666                 /* Set the MAC in Promiscuous Mode */
1667                 SkMacPromiscMode(pAC, IoC, PortNumber, SK_TRUE);
1668         }
1669         else if ((CurPromMode & SK_PROM_MODE_LLC) &&
1670                 !(NewPromMode & SK_PROM_MODE_LLC)) {    /* Norm. LLC. */
1671                 /* Clear Promiscuous Mode */
1672                 SkMacPromiscMode(pAC, IoC, PortNumber, SK_FALSE);
1673         }
1674
1675         return (SK_ADDR_SUCCESS);
1676
1677 }       /* SkAddrXmacPromiscuousChange */
1678
1679
1680 /******************************************************************************
1681  *
1682  *      SkAddrGmacPromiscuousChange - set promiscuous mode for given port
1683  *
1684  * Description:
1685  *      This routine manages promiscuous mode:
1686  *      - none
1687  *      - all LLC frames
1688  *      - all MC frames
1689  *
1690  * Context:
1691  *      runtime, pageable
1692  *      may be called after SK_INIT_IO
1693  *
1694  * Returns:
1695  *      SK_ADDR_SUCCESS
1696  *      SK_ADDR_ILLEGAL_PORT
1697  */
1698 int     SkAddrGmacPromiscuousChange(
1699 SK_AC   *pAC,                   /* adapter context */
1700 SK_IOC  IoC,                    /* I/O context */
1701 SK_U32  PortNumber,             /* port whose promiscuous mode changes */
1702 int             NewPromMode)    /* new promiscuous mode */
1703 {
1704         SK_U16          ReceiveControl; /* GMAC Receive Control Register */
1705         int             CurPromMode = SK_PROM_MODE_NONE;
1706
1707         /* Read CurPromMode from Hardware. */
1708         GM_IN16(IoC, PortNumber, GM_RX_CTRL, &ReceiveControl);
1709
1710         if ((ReceiveControl & (GM_RXCR_UCF_ENA | GM_RXCR_MCF_ENA)) == 0) {
1711                 /* Promiscuous mode! */
1712                 CurPromMode |= SK_PROM_MODE_LLC;
1713         }
1714
1715         if ((ReceiveControl & GM_RXCR_MCF_ENA) == 0) {
1716                 /* All Multicast mode! */
1717                 CurPromMode |= (pAC->Addr.Port[PortNumber].PromMode & SK_PROM_MODE_ALL_MC);
1718         }
1719
1720         pAC->Addr.Port[PortNumber].PromMode = NewPromMode;
1721
1722         if (NewPromMode == CurPromMode) {
1723                 return (SK_ADDR_SUCCESS);
1724         }
1725
1726         if ((NewPromMode & SK_PROM_MODE_ALL_MC) &&
1727                 !(CurPromMode & SK_PROM_MODE_ALL_MC)) { /* All MC */
1728
1729                 /* Set all bits in 64-bit hash register. */
1730                 GM_OUTHASH(IoC, PortNumber, GM_MC_ADDR_H1, &OnesHash);
1731
1732                 /* Enable Hashing */
1733                 SkMacHashing(pAC, IoC, PortNumber, SK_TRUE);
1734         }
1735
1736         if ((CurPromMode & SK_PROM_MODE_ALL_MC) &&
1737                 !(NewPromMode & SK_PROM_MODE_ALL_MC)) { /* Norm. MC */
1738
1739                 /* Set 64-bit hash register to InexactFilter. */
1740                 GM_OUTHASH(IoC, PortNumber, GM_MC_ADDR_H1,
1741                         &pAC->Addr.Port[PortNumber].InexactFilter.Bytes[0]);
1742
1743                 /* Enable Hashing. */
1744                 SkMacHashing(pAC, IoC, PortNumber, SK_TRUE);
1745         }
1746
1747         if ((NewPromMode & SK_PROM_MODE_LLC) &&
1748                 !(CurPromMode & SK_PROM_MODE_LLC)) {    /* Prom. LLC */
1749
1750                 /* Set the MAC to Promiscuous Mode. */
1751                 SkMacPromiscMode(pAC, IoC, PortNumber, SK_TRUE);
1752         }
1753         else if ((CurPromMode & SK_PROM_MODE_LLC) &&
1754                 !(NewPromMode & SK_PROM_MODE_LLC)) {    /* Norm. LLC */
1755
1756                 /* Clear Promiscuous Mode. */
1757                 SkMacPromiscMode(pAC, IoC, PortNumber, SK_FALSE);
1758         }
1759
1760         return (SK_ADDR_SUCCESS);
1761
1762 }       /* SkAddrGmacPromiscuousChange */
1763
1764
1765 /******************************************************************************
1766  *
1767  *      SkAddrSwap - swap address info
1768  *
1769  * Description:
1770  *      This routine swaps address info of two ports.
1771  *
1772  * Context:
1773  *      runtime, pageable
1774  *      may be called after SK_INIT_IO
1775  *
1776  * Returns:
1777  *      SK_ADDR_SUCCESS
1778  *      SK_ADDR_ILLEGAL_PORT
1779  */
1780 int     SkAddrSwap(
1781 SK_AC   *pAC,                   /* adapter context */
1782 SK_IOC  IoC,                    /* I/O context */
1783 SK_U32  FromPortNumber,         /* Port1 Index */
1784 SK_U32  ToPortNumber)           /* Port2 Index */
1785 {
1786         int                     i;
1787         SK_U8           Byte;
1788         SK_MAC_ADDR     MacAddr;
1789         SK_U32          DWord;
1790
1791         if (FromPortNumber >= (SK_U32) pAC->GIni.GIMacsFound) {
1792                 return (SK_ADDR_ILLEGAL_PORT);
1793         }
1794
1795         if (ToPortNumber >= (SK_U32) pAC->GIni.GIMacsFound) {
1796                 return (SK_ADDR_ILLEGAL_PORT);
1797         }
1798
1799         if (pAC->Rlmt.Port[FromPortNumber].Net != pAC->Rlmt.Port[ToPortNumber].Net) {
1800                 return (SK_ADDR_ILLEGAL_PORT);
1801         }
1802
1803         /*
1804          * Swap:
1805          * - Exact Match Entries (GEnesis and Yukon)
1806          *   Yukon uses first entry for the logical MAC
1807          *   address (stored in the second GMAC register).
1808          * - FirstExactMatchRlmt (GEnesis only)
1809          * - NextExactMatchRlmt (GEnesis only)
1810          * - FirstExactMatchDrv (GEnesis only)
1811          * - NextExactMatchDrv (GEnesis only)
1812          * - 64-bit filter (InexactFilter)
1813          * - Promiscuous Mode
1814          * of ports.
1815          */
1816
1817         for (i = 0; i < SK_ADDR_EXACT_MATCHES; i++) {
1818                 MacAddr = pAC->Addr.Port[FromPortNumber].Exact[i];
1819                 pAC->Addr.Port[FromPortNumber].Exact[i] =
1820                         pAC->Addr.Port[ToPortNumber].Exact[i];
1821                 pAC->Addr.Port[ToPortNumber].Exact[i] = MacAddr;
1822         }
1823
1824         for (i = 0; i < 8; i++) {
1825                 Byte = pAC->Addr.Port[FromPortNumber].InexactFilter.Bytes[i];
1826                 pAC->Addr.Port[FromPortNumber].InexactFilter.Bytes[i] =
1827                         pAC->Addr.Port[ToPortNumber].InexactFilter.Bytes[i];
1828                 pAC->Addr.Port[ToPortNumber].InexactFilter.Bytes[i] = Byte;
1829         }
1830
1831         i = pAC->Addr.Port[FromPortNumber].PromMode;
1832         pAC->Addr.Port[FromPortNumber].PromMode = pAC->Addr.Port[ToPortNumber].PromMode;
1833         pAC->Addr.Port[ToPortNumber].PromMode = i;
1834
1835         if (pAC->GIni.GIChipId == CHIP_ID_GENESIS) {
1836                 DWord = pAC->Addr.Port[FromPortNumber].FirstExactMatchRlmt;
1837                 pAC->Addr.Port[FromPortNumber].FirstExactMatchRlmt =
1838                         pAC->Addr.Port[ToPortNumber].FirstExactMatchRlmt;
1839                 pAC->Addr.Port[ToPortNumber].FirstExactMatchRlmt = DWord;
1840
1841                 DWord = pAC->Addr.Port[FromPortNumber].NextExactMatchRlmt;
1842                 pAC->Addr.Port[FromPortNumber].NextExactMatchRlmt =
1843                         pAC->Addr.Port[ToPortNumber].NextExactMatchRlmt;
1844                 pAC->Addr.Port[ToPortNumber].NextExactMatchRlmt = DWord;
1845
1846                 DWord = pAC->Addr.Port[FromPortNumber].FirstExactMatchDrv;
1847                 pAC->Addr.Port[FromPortNumber].FirstExactMatchDrv =
1848                         pAC->Addr.Port[ToPortNumber].FirstExactMatchDrv;
1849                 pAC->Addr.Port[ToPortNumber].FirstExactMatchDrv = DWord;
1850
1851                 DWord = pAC->Addr.Port[FromPortNumber].NextExactMatchDrv;
1852                 pAC->Addr.Port[FromPortNumber].NextExactMatchDrv =
1853                         pAC->Addr.Port[ToPortNumber].NextExactMatchDrv;
1854                 pAC->Addr.Port[ToPortNumber].NextExactMatchDrv = DWord;
1855         }
1856
1857         /* CAUTION: Solution works if only ports of one adapter are in use. */
1858         for (i = 0; (SK_U32) i < pAC->Rlmt.Net[pAC->Rlmt.Port[ToPortNumber].
1859                 Net->NetNumber].NumPorts; i++) {
1860                 if (pAC->Rlmt.Net[pAC->Rlmt.Port[ToPortNumber].Net->NetNumber].
1861                         Port[i]->PortNumber == ToPortNumber) {
1862                         pAC->Addr.Net[pAC->Rlmt.Port[ToPortNumber].Net->NetNumber].
1863                                 ActivePort = i;
1864                         /* 20001207 RA: Was "ToPortNumber;". */
1865                 }
1866         }
1867
1868         (void) SkAddrMcUpdate(pAC, IoC, FromPortNumber);
1869         (void) SkAddrMcUpdate(pAC, IoC, ToPortNumber);
1870
1871         return (SK_ADDR_SUCCESS);
1872
1873 }       /* SkAddrSwap */
1874
1875 #ifdef __cplusplus
1876 }
1877 #endif  /* __cplusplus */
1878
1879 #endif /* CONFIG_SK98 */