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