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