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