/****************************************************************************** * * Name: skaddr.c * Project: GEnesis, PCI Gigabit Ethernet Adapter * Version: $Revision: 1.48 $ * Date: $Date: 2003/02/12 17:09:37 $ * Purpose: Manage Addresses (Multicast and Unicast) and Promiscuous Mode. * ******************************************************************************/ /****************************************************************************** * * (C)Copyright 1998-2002 SysKonnect GmbH. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * The information in this file is provided "AS IS" without warranty. * ******************************************************************************/ /****************************************************************************** * * History: * * $Log: skaddr.c,v $ * Revision 1.48 2003/02/12 17:09:37 tschilli * Fix in SkAddrOverride() to set both (physical and logical) MAC addresses * in case that both addresses are identical. * * Revision 1.47 2002/09/17 06:31:10 tschilli * Handling of SK_PROM_MODE_ALL_MC flag in SkAddrGmacMcUpdate() * and SkAddrGmacPromiscuousChange() fixed. * Editorial changes. * * Revision 1.46 2002/08/22 07:55:41 tschilli * New function SkGmacMcHash() for GMAC multicast hashing algorithm added. * Editorial changes. * * Revision 1.45 2002/08/15 12:29:35 tschilli * SkAddrGmacMcUpdate() and SkAddrGmacPromiscuousChange() changed. * * Revision 1.44 2002/08/14 12:18:03 rschmidt * Replaced direct handling of MAC Hashing (XMAC and GMAC) * with routine SkMacHashing(). * Replaced wrong 3rd para 'i' with 'PortNumber' in SkMacPromiscMode(). * * Revision 1.43 2002/08/13 09:37:43 rschmidt * Corrected some SK_DBG_MSG outputs. * Replaced wrong 2nd para pAC with IoC in SkMacPromiscMode(). * Editorial changes. * * Revision 1.42 2002/08/12 11:24:36 rschmidt * Remove setting of logical MAC address GM_SRC_ADDR_2 in SkAddrInit(). * Replaced direct handling of MAC Promiscuous Mode (XMAC and GMAC) * with routine SkMacPromiscMode(). * Editorial changes. * * Revision 1.41 2002/06/10 13:52:18 tschilli * Changes for handling YUKON. * All changes are internally and not visible to the programmer * using this module. * * Revision 1.40 2001/02/14 14:04:59 rassmann * Editorial changes. * * Revision 1.39 2001/01/30 10:30:04 rassmann * Editorial changes. * * Revision 1.38 2001/01/25 16:26:52 rassmann * Ensured that logical address overrides are done on net's active port. * * Revision 1.37 2001/01/22 13:41:34 rassmann * Supporting two nets on dual-port adapters. * * Revision 1.36 2000/08/07 11:10:39 rassmann * Editorial changes. * * Revision 1.35 2000/05/04 09:38:41 rassmann * Editorial changes. * Corrected multicast address hashing. * * Revision 1.34 1999/11/22 13:23:44 cgoos * Changed license header to GPL. * * Revision 1.33 1999/05/28 10:56:06 rassmann * Editorial changes. * * Revision 1.32 1999/03/31 10:59:20 rassmann * Returning Success instead of DupAddr if address shall be overridden * with same value. * * Revision 1.31 1999/01/14 16:18:17 rassmann * Corrected multicast initialization. * * Revision 1.30 1999/01/04 10:30:35 rassmann * SkAddrOverride only possible after SK_INIT_IO phase. * * Revision 1.29 1998/12/29 13:13:10 rassmann * An address override is now preserved in the SK_INIT_IO phase. * All functions return an int now. * Extended parameter checking. * * Revision 1.28 1998/12/01 11:45:53 rassmann * Code cleanup. * * Revision 1.27 1998/12/01 09:22:49 rassmann * SkAddrMcAdd and SkAddrMcUpdate returned SK_MC_FILTERING_INEXACT * too often. * * Revision 1.26 1998/11/24 12:39:44 rassmann * Reserved multicast entry for BPDU address. * 13 multicast entries left for protocol. * * Revision 1.25 1998/11/17 16:54:23 rassmann * Using exact match for up to 14 multicast addresses. * Still receiving all multicasts if more addresses are added. * * Revision 1.24 1998/11/13 17:24:31 rassmann * Changed return value of SkAddrOverride to int. * * Revision 1.23 1998/11/13 16:56:18 rassmann * Added macro SK_ADDR_COMPARE. * Changed return type of SkAddrOverride to SK_BOOL. * * Revision 1.22 1998/11/04 17:06:17 rassmann * Corrected McUpdate and PromiscuousChange functions. * * Revision 1.21 1998/10/29 14:34:04 rassmann * Clearing SK_ADDR struct at startup. * * Revision 1.20 1998/10/28 18:16:34 rassmann * Avoiding I/Os before SK_INIT_RUN level. * Aligning InexactFilter. * * Revision 1.19 1998/10/28 11:29:28 rassmann * Programming physical address in SkAddrMcUpdate. * Corrected programming of exact match entries. * * Revision 1.18 1998/10/28 10:34:48 rassmann * Corrected reading of physical addresses. * * Revision 1.17 1998/10/28 10:26:13 rassmann * Getting ports' current MAC addresses from EPROM now. * Added debug output. * * Revision 1.16 1998/10/27 16:20:12 rassmann * Reading MAC address byte by byte. * * Revision 1.15 1998/10/22 11:39:09 rassmann * Corrected signed/unsigned mismatches. * * Revision 1.14 1998/10/19 17:12:35 rassmann * Syntax corrections. * * Revision 1.13 1998/10/19 17:02:19 rassmann * Now reading permanent MAC addresses from CRF. * * Revision 1.12 1998/10/15 15:15:48 rassmann * Changed Flags Parameters from SK_U8 to int. * Checked with lint. * * Revision 1.11 1998/09/24 19:15:12 rassmann * Code cleanup. * * Revision 1.10 1998/09/18 20:18:54 rassmann * Added HW access. * Implemented swapping. * * Revision 1.9 1998/09/16 11:32:00 rassmann * Including skdrv1st.h again. :( * * Revision 1.8 1998/09/16 11:09:34 rassmann * Syntax corrections. * * Revision 1.7 1998/09/14 17:06:34 rassmann * Minor changes. * * Revision 1.6 1998/09/07 08:45:41 rassmann * Syntax corrections. * * Revision 1.5 1998/09/04 19:40:19 rassmann * Interface enhancements. * * Revision 1.4 1998/09/04 12:14:12 rassmann * Interface cleanup. * * Revision 1.3 1998/09/02 16:56:40 rassmann * Updated interface. * * Revision 1.2 1998/08/27 14:26:09 rassmann * Updated interface. * * Revision 1.1 1998/08/21 08:30:22 rassmann * First public version. * ******************************************************************************/ /****************************************************************************** * * Description: * * This module is intended to manage multicast addresses, address override, * and promiscuous mode on GEnesis and Yukon adapters. * * Address Layout: * port address: physical MAC address * 1st exact match: logical MAC address (GEnesis only) * 2nd exact match: RLMT multicast (GEnesis only) * exact match 3-13: OS-specific multicasts (GEnesis only) * * Include File Hierarchy: * * "skdrv1st.h" * "skdrv2nd.h" * ******************************************************************************/ #include #ifdef CONFIG_SK98 #ifndef lint static const char SysKonnectFileId[] = "@(#) $Id: skaddr.c,v 1.48 2003/02/12 17:09:37 tschilli Exp $ (C) SysKonnect."; #endif /* !defined(lint) */ #define __SKADDR_C #ifdef __cplusplus #error C++ is not yet supported. extern "C" { #endif /* cplusplus */ #include "h/skdrv1st.h" #include "h/skdrv2nd.h" /* defines ********************************************************************/ #define XMAC_POLY 0xEDB88320UL /* CRC32-Poly - XMAC: Little Endian */ #define GMAC_POLY 0x04C11DB7L /* CRC16-Poly - GMAC: Little Endian */ #define HASH_BITS 6 /* #bits in hash */ #define SK_MC_BIT 0x01 /* Error numbers and messages. */ #define SKERR_ADDR_E001 (SK_ERRBASE_ADDR + 0) #define SKERR_ADDR_E001MSG "Bad Flags." #define SKERR_ADDR_E002 (SKERR_ADDR_E001 + 1) #define SKERR_ADDR_E002MSG "New Error." /* typedefs *******************************************************************/ /* None. */ /* global variables ***********************************************************/ /* 64-bit hash values with all bits set. */ SK_U16 OnesHash[4] = {0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF}; /* local variables ************************************************************/ #ifdef DEBUG static int Next0[SK_MAX_MACS] = {0, 0}; #endif /* DEBUG */ /* functions ******************************************************************/ /****************************************************************************** * * SkAddrInit - initialize data, set state to init * * Description: * * SK_INIT_DATA * ============ * * This routine clears the multicast tables and resets promiscuous mode. * Some entries are reserved for the "logical MAC address", the * SK-RLMT multicast address, and the BPDU multicast address. * * * SK_INIT_IO * ========== * * All permanent MAC addresses are read from EPROM. * If the current MAC addresses are not already set in software, * they are set to the values of the permanent addresses. * The current addresses are written to the corresponding MAC. * * * SK_INIT_RUN * =========== * * Nothing. * * Context: * init, pageable * * Returns: * SK_ADDR_SUCCESS */ int SkAddrInit( SK_AC *pAC, /* the adapter context */ SK_IOC IoC, /* I/O context */ int Level) /* initialization level */ { int j; SK_U32 i; SK_U8 *InAddr; SK_U16 *OutAddr; SK_ADDR_PORT *pAPort; switch (Level) { case SK_INIT_DATA: SK_MEMSET((char *) &pAC->Addr, 0, sizeof(SK_ADDR)); for (i = 0; i < SK_MAX_MACS; i++) { pAPort = &pAC->Addr.Port[i]; pAPort->PromMode = SK_PROM_MODE_NONE; pAPort->FirstExactMatchRlmt = SK_ADDR_FIRST_MATCH_RLMT; pAPort->FirstExactMatchDrv = SK_ADDR_FIRST_MATCH_DRV; pAPort->NextExactMatchRlmt = SK_ADDR_FIRST_MATCH_RLMT; pAPort->NextExactMatchDrv = SK_ADDR_FIRST_MATCH_DRV; } #ifdef xDEBUG for (i = 0; i < SK_MAX_MACS; i++) { if (pAC->Addr.Port[i].NextExactMatchRlmt < SK_ADDR_FIRST_MATCH_RLMT) { Next0[i] |= 4; } } #endif /* DEBUG */ /* pAC->Addr.InitDone = SK_INIT_DATA; */ break; case SK_INIT_IO: for (i = 0; i < SK_MAX_NETS; i++) { pAC->Addr.Net[i].ActivePort = pAC->Rlmt.Net[i].ActivePort; } #ifdef xDEBUG for (i = 0; i < SK_MAX_MACS; i++) { if (pAC->Addr.Port[i].NextExactMatchRlmt < SK_ADDR_FIRST_MATCH_RLMT) { Next0[i] |= 8; } } #endif /* DEBUG */ /* Read permanent logical MAC address from Control Register File. */ for (j = 0; j < SK_MAC_ADDR_LEN; j++) { InAddr = (SK_U8 *) &pAC->Addr.Net[0].PermanentMacAddress.a[j]; SK_IN8(IoC, B2_MAC_1 + j, InAddr); } if (!pAC->Addr.Net[0].CurrentMacAddressSet) { /* Set the current logical MAC address to the permanent one. */ pAC->Addr.Net[0].CurrentMacAddress = pAC->Addr.Net[0].PermanentMacAddress; pAC->Addr.Net[0].CurrentMacAddressSet = SK_TRUE; } /* Set the current logical MAC address. */ pAC->Addr.Port[pAC->Addr.Net[0].ActivePort].Exact[0] = pAC->Addr.Net[0].CurrentMacAddress; #if SK_MAX_NETS > 1 /* Set logical MAC address for net 2 to (log | 3). */ if (!pAC->Addr.Net[1].CurrentMacAddressSet) { pAC->Addr.Net[1].PermanentMacAddress = pAC->Addr.Net[0].PermanentMacAddress; pAC->Addr.Net[1].PermanentMacAddress.a[5] |= 3; /* Set the current logical MAC address to the permanent one. */ pAC->Addr.Net[1].CurrentMacAddress = pAC->Addr.Net[1].PermanentMacAddress; pAC->Addr.Net[1].CurrentMacAddressSet = SK_TRUE; } #endif /* SK_MAX_NETS > 1 */ #ifdef DEBUG for (i = 0; i < (SK_U32) pAC->GIni.GIMacsFound; i++) { SK_DBG_MSG(pAC, SK_DBGMOD_ADDR, SK_DBGCAT_INIT, ("Permanent MAC Address (Net%d): %02X %02X %02X %02X %02X %02X\n", i, pAC->Addr.Net[i].PermanentMacAddress.a[0], pAC->Addr.Net[i].PermanentMacAddress.a[1], pAC->Addr.Net[i].PermanentMacAddress.a[2], pAC->Addr.Net[i].PermanentMacAddress.a[3], pAC->Addr.Net[i].PermanentMacAddress.a[4], pAC->Addr.Net[i].PermanentMacAddress.a[5])) SK_DBG_MSG(pAC, SK_DBGMOD_ADDR, SK_DBGCAT_INIT, ("Logical MAC Address (Net%d): %02X %02X %02X %02X %02X %02X\n", i, pAC->Addr.Net[i].CurrentMacAddress.a[0], pAC->Addr.Net[i].CurrentMacAddress.a[1], pAC->Addr.Net[i].CurrentMacAddress.a[2], pAC->Addr.Net[i].CurrentMacAddress.a[3], pAC->Addr.Net[i].CurrentMacAddress.a[4], pAC->Addr.Net[i].CurrentMacAddress.a[5])) } #endif /* DEBUG */ for (i = 0; i < (SK_U32) pAC->GIni.GIMacsFound; i++) { pAPort = &pAC->Addr.Port[i]; /* Read permanent port addresses from Control Register File. */ for (j = 0; j < SK_MAC_ADDR_LEN; j++) { InAddr = (SK_U8 *) &pAPort->PermanentMacAddress.a[j]; SK_IN8(IoC, B2_MAC_2 + 8 * i + j, InAddr); } if (!pAPort->CurrentMacAddressSet) { /* * Set the current and previous physical MAC address * of this port to its permanent MAC address. */ pAPort->CurrentMacAddress = pAPort->PermanentMacAddress; pAPort->PreviousMacAddress = pAPort->PermanentMacAddress; pAPort->CurrentMacAddressSet = SK_TRUE; } /* Set port's current physical MAC address. */ OutAddr = (SK_U16 *) &pAPort->CurrentMacAddress.a[0]; if (pAC->GIni.GIChipId == CHIP_ID_GENESIS) { XM_OUTADDR(IoC, i, XM_SA, OutAddr); } else { GM_OUTADDR(IoC, i, GM_SRC_ADDR_1L, OutAddr); } #ifdef DEBUG SK_DBG_MSG(pAC, SK_DBGMOD_ADDR, SK_DBGCAT_INIT, ("SkAddrInit: Permanent Physical MAC Address: %02X %02X %02X %02X %02X %02X\n", pAPort->PermanentMacAddress.a[0], pAPort->PermanentMacAddress.a[1], pAPort->PermanentMacAddress.a[2], pAPort->PermanentMacAddress.a[3], pAPort->PermanentMacAddress.a[4], pAPort->PermanentMacAddress.a[5])) SK_DBG_MSG(pAC, SK_DBGMOD_ADDR, SK_DBGCAT_INIT, ("SkAddrInit: Physical MAC Address: %02X %02X %02X %02X %02X %02X\n", pAPort->CurrentMacAddress.a[0], pAPort->CurrentMacAddress.a[1], pAPort->CurrentMacAddress.a[2], pAPort->CurrentMacAddress.a[3], pAPort->CurrentMacAddress.a[4], pAPort->CurrentMacAddress.a[5])) #endif /* DEBUG */ } /* pAC->Addr.InitDone = SK_INIT_IO; */ break; case SK_INIT_RUN: #ifdef xDEBUG for (i = 0; i < SK_MAX_MACS; i++) { if (pAC->Addr.Port[i].NextExactMatchRlmt < SK_ADDR_FIRST_MATCH_RLMT) { Next0[i] |= 16; } } #endif /* DEBUG */ /* pAC->Addr.InitDone = SK_INIT_RUN; */ break; default: /* error */ break; } return (SK_ADDR_SUCCESS); } /* SkAddrInit */ /****************************************************************************** * * SkAddrMcClear - clear the multicast table * * Description: * This routine clears the multicast table. * * If not suppressed by Flag SK_MC_SW_ONLY, the hardware is updated * immediately. * * It calls either SkAddrXmacMcClear or SkAddrGmacMcClear, according * to the adapter in use. The real work is done there. * * Context: * runtime, pageable * may be called starting with SK_INIT_DATA with flag SK_MC_SW_ONLY * may be called after SK_INIT_IO without limitation * * Returns: * SK_ADDR_SUCCESS * SK_ADDR_ILLEGAL_PORT */ int SkAddrMcClear( SK_AC *pAC, /* adapter context */ SK_IOC IoC, /* I/O context */ SK_U32 PortNumber, /* Index of affected port */ int Flags) /* permanent/non-perm, sw-only */ { int ReturnCode; if (PortNumber >= (SK_U32) pAC->GIni.GIMacsFound) { return (SK_ADDR_ILLEGAL_PORT); } if (pAC->GIni.GIChipId == CHIP_ID_GENESIS) { ReturnCode = SkAddrXmacMcClear(pAC, IoC, PortNumber, Flags); } else { ReturnCode = SkAddrGmacMcClear(pAC, IoC, PortNumber, Flags); } return (ReturnCode); } /* SkAddrMcClear */ /****************************************************************************** * * SkAddrXmacMcClear - clear the multicast table * * Description: * This routine clears the multicast table * (either entry 2 or entries 3-16 and InexactFilter) of the given port. * If not suppressed by Flag SK_MC_SW_ONLY, the hardware is updated * immediately. * * Context: * runtime, pageable * may be called starting with SK_INIT_DATA with flag SK_MC_SW_ONLY * may be called after SK_INIT_IO without limitation * * Returns: * SK_ADDR_SUCCESS * SK_ADDR_ILLEGAL_PORT */ int SkAddrXmacMcClear( SK_AC *pAC, /* adapter context */ SK_IOC IoC, /* I/O context */ SK_U32 PortNumber, /* Index of affected port */ int Flags) /* permanent/non-perm, sw-only */ { int i; if (Flags & SK_ADDR_PERMANENT) { /* permanent => RLMT */ /* Clear RLMT multicast addresses. */ pAC->Addr.Port[PortNumber].NextExactMatchRlmt = SK_ADDR_FIRST_MATCH_RLMT; } else { /* not permanent => DRV */ /* Clear InexactFilter */ for (i = 0; i < 8; i++) { pAC->Addr.Port[PortNumber].InexactFilter.Bytes[i] = 0; } /* Clear DRV multicast addresses. */ pAC->Addr.Port[PortNumber].NextExactMatchDrv = SK_ADDR_FIRST_MATCH_DRV; } if (!(Flags & SK_MC_SW_ONLY)) { (void) SkAddrXmacMcUpdate(pAC, IoC, PortNumber); } return (SK_ADDR_SUCCESS); } /* SkAddrXmacMcClear */ /****************************************************************************** * * SkAddrGmacMcClear - clear the multicast table * * Description: * This routine clears the multicast hashing table (InexactFilter) * (either the RLMT or the driver bits) of the given port. * * If not suppressed by Flag SK_MC_SW_ONLY, the hardware is updated * immediately. * * Context: * runtime, pageable * may be called starting with SK_INIT_DATA with flag SK_MC_SW_ONLY * may be called after SK_INIT_IO without limitation * * Returns: * SK_ADDR_SUCCESS * SK_ADDR_ILLEGAL_PORT */ int SkAddrGmacMcClear( SK_AC *pAC, /* adapter context */ SK_IOC IoC, /* I/O context */ SK_U32 PortNumber, /* Index of affected port */ int Flags) /* permanent/non-perm, sw-only */ { int i; #ifdef DEBUG SK_DBG_MSG(pAC, SK_DBGMOD_ADDR, SK_DBGCAT_CTRL, ("GMAC InexactFilter (not cleared): %02X %02X %02X %02X %02X %02X %02X %02X\n", pAC->Addr.Port[PortNumber].InexactFilter.Bytes[0], pAC->Addr.Port[PortNumber].InexactFilter.Bytes[1], pAC->Addr.Port[PortNumber].InexactFilter.Bytes[2], pAC->Addr.Port[PortNumber].InexactFilter.Bytes[3], pAC->Addr.Port[PortNumber].InexactFilter.Bytes[4], pAC->Addr.Port[PortNumber].InexactFilter.Bytes[5], pAC->Addr.Port[PortNumber].InexactFilter.Bytes[6], pAC->Addr.Port[PortNumber].InexactFilter.Bytes[7])) #endif /* DEBUG */ /* Clear InexactFilter */ for (i = 0; i < 8; i++) { pAC->Addr.Port[PortNumber].InexactFilter.Bytes[i] = 0; } if (Flags & SK_ADDR_PERMANENT) { /* permanent => RLMT */ /* Copy DRV bits to InexactFilter. */ for (i = 0; i < 8; i++) { pAC->Addr.Port[PortNumber].InexactFilter.Bytes[i] |= pAC->Addr.Port[PortNumber].InexactDrvFilter.Bytes[i]; /* Clear InexactRlmtFilter. */ pAC->Addr.Port[PortNumber].InexactRlmtFilter.Bytes[i] = 0; } } else { /* not permanent => DRV */ /* Copy RLMT bits to InexactFilter. */ for (i = 0; i < 8; i++) { pAC->Addr.Port[PortNumber].InexactFilter.Bytes[i] |= pAC->Addr.Port[PortNumber].InexactRlmtFilter.Bytes[i]; /* Clear InexactDrvFilter. */ pAC->Addr.Port[PortNumber].InexactDrvFilter.Bytes[i] = 0; } } #ifdef DEBUG SK_DBG_MSG(pAC, SK_DBGMOD_ADDR, SK_DBGCAT_CTRL, ("GMAC InexactFilter (cleared): %02X %02X %02X %02X %02X %02X %02X %02X\n", pAC->Addr.Port[PortNumber].InexactFilter.Bytes[0], pAC->Addr.Port[PortNumber].InexactFilter.Bytes[1], pAC->Addr.Port[PortNumber].InexactFilter.Bytes[2], pAC->Addr.Port[PortNumber].InexactFilter.Bytes[3], pAC->Addr.Port[PortNumber].InexactFilter.Bytes[4], pAC->Addr.Port[PortNumber].InexactFilter.Bytes[5], pAC->Addr.Port[PortNumber].InexactFilter.Bytes[6], pAC->Addr.Port[PortNumber].InexactFilter.Bytes[7])) #endif /* DEBUG */ if (!(Flags & SK_MC_SW_ONLY)) { (void) SkAddrGmacMcUpdate(pAC, IoC, PortNumber); } return (SK_ADDR_SUCCESS); } /* SkAddrGmacMcClear */ #ifndef SK_ADDR_CHEAT /****************************************************************************** * * SkXmacMcHash - hash multicast address * * Description: * This routine computes the hash value for a multicast address. * A CRC32 algorithm is used. * * Notes: * The code was adapted from the XaQti data sheet. * * Context: * runtime, pageable * * Returns: * Hash value of multicast address. */ SK_U32 SkXmacMcHash( unsigned char *pMc) /* Multicast address */ { SK_U32 Idx; SK_U32 Bit; SK_U32 Data; SK_U32 Crc; Crc = 0xFFFFFFFFUL; for (Idx = 0; Idx < SK_MAC_ADDR_LEN; Idx++) { Data = *pMc++; for (Bit = 0; Bit < 8; Bit++, Data >>= 1) { Crc = (Crc >> 1) ^ (((Crc ^ Data) & 1) ? XMAC_POLY : 0); } } return (Crc & ((1 << HASH_BITS) - 1)); } /* SkXmacMcHash */ /****************************************************************************** * * SkGmacMcHash - hash multicast address * * Description: * This routine computes the hash value for a multicast address. * A CRC16 algorithm is used. * * Notes: * * * Context: * runtime, pageable * * Returns: * Hash value of multicast address. */ SK_U32 SkGmacMcHash( unsigned char *pMc) /* Multicast address */ { SK_U32 Data; SK_U32 TmpData; SK_U32 Crc; int Byte; int Bit; Crc = 0xFFFFFFFFUL; for (Byte = 0; Byte < 6; Byte++) { /* Get next byte. */ Data = (SK_U32) pMc[Byte]; /* Change bit order in byte. */ TmpData = Data; for (Bit = 0; Bit < 8; Bit++) { if (TmpData & 1L) { Data |= 1L << (7 - Bit); } else { Data &= ~(1L << (7 - Bit)); } TmpData >>= 1; } Crc ^= (Data << 24); for (Bit = 0; Bit < 8; Bit++) { if (Crc & 0x80000000) { Crc = (Crc << 1) ^ GMAC_POLY; } else { Crc <<= 1; } } } return (Crc & ((1 << HASH_BITS) - 1)); } /* SkGmacMcHash */ #endif /* not SK_ADDR_CHEAT */ /****************************************************************************** * * SkAddrMcAdd - add a multicast address to a port * * Description: * This routine enables reception for a given address on the given port. * * It calls either SkAddrXmacMcAdd or SkAddrGmacMcAdd, according to the * adapter in use. The real work is done there. * * Notes: * The return code is only valid for SK_PROM_MODE_NONE. * * Context: * runtime, pageable * may be called after SK_INIT_DATA * * Returns: * SK_MC_FILTERING_EXACT * SK_MC_FILTERING_INEXACT * SK_MC_ILLEGAL_ADDRESS * SK_MC_ILLEGAL_PORT * SK_MC_RLMT_OVERFLOW */ int SkAddrMcAdd( SK_AC *pAC, /* adapter context */ SK_IOC IoC, /* I/O context */ SK_U32 PortNumber, /* Port Number */ SK_MAC_ADDR *pMc, /* multicast address to be added */ int Flags) /* permanent/non-permanent */ { int ReturnCode; if (PortNumber >= (SK_U32) pAC->GIni.GIMacsFound) { return (SK_ADDR_ILLEGAL_PORT); } if (pAC->GIni.GIChipId == CHIP_ID_GENESIS) { ReturnCode = SkAddrXmacMcAdd(pAC, IoC, PortNumber, pMc, Flags); } else { ReturnCode = SkAddrGmacMcAdd(pAC, IoC, PortNumber, pMc, Flags); } return (ReturnCode); } /* SkAddrMcAdd */ /****************************************************************************** * * SkAddrXmacMcAdd - add a multicast address to a port * * Description: * This routine enables reception for a given address on the given port. * * Notes: * The return code is only valid for SK_PROM_MODE_NONE. * * The multicast bit is only checked if there are no free exact match * entries. * * Context: * runtime, pageable * may be called after SK_INIT_DATA * * Returns: * SK_MC_FILTERING_EXACT * SK_MC_FILTERING_INEXACT * SK_MC_ILLEGAL_ADDRESS * SK_MC_RLMT_OVERFLOW */ int SkAddrXmacMcAdd( SK_AC *pAC, /* adapter context */ SK_IOC IoC, /* I/O context */ SK_U32 PortNumber, /* Port Number */ SK_MAC_ADDR *pMc, /* multicast address to be added */ int Flags) /* permanent/non-permanent */ { int i; SK_U8 Inexact; #ifndef SK_ADDR_CHEAT SK_U32 HashBit; #endif /* !defined(SK_ADDR_CHEAT) */ if (Flags & SK_ADDR_PERMANENT) { /* permanent => RLMT */ #ifdef xDEBUG if (pAC->Addr.Port[PortNumber].NextExactMatchRlmt < SK_ADDR_FIRST_MATCH_RLMT) { Next0[PortNumber] |= 1; return (SK_MC_RLMT_OVERFLOW); } #endif /* DEBUG */ if (pAC->Addr.Port[PortNumber].NextExactMatchRlmt > SK_ADDR_LAST_MATCH_RLMT) { return (SK_MC_RLMT_OVERFLOW); } /* Set a RLMT multicast address. */ pAC->Addr.Port[PortNumber].Exact[ pAC->Addr.Port[PortNumber].NextExactMatchRlmt++] = *pMc; return (SK_MC_FILTERING_EXACT); } #ifdef xDEBUG if (pAC->Addr.Port[PortNumber].NextExactMatchDrv < SK_ADDR_FIRST_MATCH_DRV) { Next0[PortNumber] |= 2; return (SK_MC_RLMT_OVERFLOW); } #endif /* DEBUG */ if (pAC->Addr.Port[PortNumber].NextExactMatchDrv <= SK_ADDR_LAST_MATCH_DRV) { /* Set exact match entry. */ pAC->Addr.Port[PortNumber].Exact[ pAC->Addr.Port[PortNumber].NextExactMatchDrv++] = *pMc; /* Clear InexactFilter */ for (i = 0; i < 8; i++) { pAC->Addr.Port[PortNumber].InexactFilter.Bytes[i] = 0; } } else { if (!(pMc->a[0] & SK_MC_BIT)) { /* Hashing only possible with multicast addresses. */ return (SK_MC_ILLEGAL_ADDRESS); } #ifndef SK_ADDR_CHEAT /* Compute hash value of address. */ HashBit = 63 - SkXmacMcHash(&pMc->a[0]); /* Add bit to InexactFilter. */ pAC->Addr.Port[PortNumber].InexactFilter.Bytes[HashBit / 8] |= 1 << (HashBit % 8); #else /* SK_ADDR_CHEAT */ /* Set all bits in InexactFilter. */ for (i = 0; i < 8; i++) { pAC->Addr.Port[PortNumber].InexactFilter.Bytes[i] = 0xFF; } #endif /* SK_ADDR_CHEAT */ } for (Inexact = 0, i = 0; i < 8; i++) { Inexact |= pAC->Addr.Port[PortNumber].InexactFilter.Bytes[i]; } if (Inexact == 0 && pAC->Addr.Port[PortNumber].PromMode == 0) { return (SK_MC_FILTERING_EXACT); } else { return (SK_MC_FILTERING_INEXACT); } } /* SkAddrXmacMcAdd */ /****************************************************************************** * * SkAddrGmacMcAdd - add a multicast address to a port * * Description: * This routine enables reception for a given address on the given port. * * Notes: * The return code is only valid for SK_PROM_MODE_NONE. * * Context: * runtime, pageable * may be called after SK_INIT_DATA * * Returns: * SK_MC_FILTERING_INEXACT * SK_MC_ILLEGAL_ADDRESS */ int SkAddrGmacMcAdd( SK_AC *pAC, /* adapter context */ SK_IOC IoC, /* I/O context */ SK_U32 PortNumber, /* Port Number */ SK_MAC_ADDR *pMc, /* multicast address to be added */ int Flags) /* permanent/non-permanent */ { int i; #ifndef SK_ADDR_CHEAT SK_U32 HashBit; #endif /* !defined(SK_ADDR_CHEAT) */ if (!(pMc->a[0] & SK_MC_BIT)) { /* Hashing only possible with multicast addresses. */ return (SK_MC_ILLEGAL_ADDRESS); } #ifndef SK_ADDR_CHEAT /* Compute hash value of address. */ HashBit = SkGmacMcHash(&pMc->a[0]); if (Flags & SK_ADDR_PERMANENT) { /* permanent => RLMT */ /* Add bit to InexactRlmtFilter. */ pAC->Addr.Port[PortNumber].InexactRlmtFilter.Bytes[HashBit / 8] |= 1 << (HashBit % 8); /* Copy bit to InexactFilter. */ for (i = 0; i < 8; i++) { pAC->Addr.Port[PortNumber].InexactFilter.Bytes[i] |= pAC->Addr.Port[PortNumber].InexactRlmtFilter.Bytes[i]; } #ifdef DEBUG SK_DBG_MSG(pAC, SK_DBGMOD_ADDR, SK_DBGCAT_CTRL, ("GMAC InexactRlmtFilter: %02X %02X %02X %02X %02X %02X %02X %02X\n", pAC->Addr.Port[PortNumber].InexactRlmtFilter.Bytes[0], pAC->Addr.Port[PortNumber].InexactRlmtFilter.Bytes[1], pAC->Addr.Port[PortNumber].InexactRlmtFilter.Bytes[2], pAC->Addr.Port[PortNumber].InexactRlmtFilter.Bytes[3], pAC->Addr.Port[PortNumber].InexactRlmtFilter.Bytes[4], pAC->Addr.Port[PortNumber].InexactRlmtFilter.Bytes[5], pAC->Addr.Port[PortNumber].InexactRlmtFilter.Bytes[6], pAC->Addr.Port[PortNumber].InexactRlmtFilter.Bytes[7])) #endif /* DEBUG */ } else { /* not permanent => DRV */ /* Add bit to InexactDrvFilter. */ pAC->Addr.Port[PortNumber].InexactDrvFilter.Bytes[HashBit / 8] |= 1 << (HashBit % 8); /* Copy bit to InexactFilter. */ for (i = 0; i < 8; i++) { pAC->Addr.Port[PortNumber].InexactFilter.Bytes[i] |= pAC->Addr.Port[PortNumber].InexactDrvFilter.Bytes[i]; } #ifdef DEBUG SK_DBG_MSG(pAC, SK_DBGMOD_ADDR, SK_DBGCAT_CTRL, ("GMAC InexactDrvFilter: %02X %02X %02X %02X %02X %02X %02X %02X\n", pAC->Addr.Port[PortNumber].InexactDrvFilter.Bytes[0], pAC->Addr.Port[PortNumber].InexactDrvFilter.Bytes[1], pAC->Addr.Port[PortNumber].InexactDrvFilter.Bytes[2], pAC->Addr.Port[PortNumber].InexactDrvFilter.Bytes[3], pAC->Addr.Port[PortNumber].InexactDrvFilter.Bytes[4], pAC->Addr.Port[PortNumber].InexactDrvFilter.Bytes[5], pAC->Addr.Port[PortNumber].InexactDrvFilter.Bytes[6], pAC->Addr.Port[PortNumber].InexactDrvFilter.Bytes[7])) #endif /* DEBUG */ } #else /* SK_ADDR_CHEAT */ /* Set all bits in InexactFilter. */ for (i = 0; i < 8; i++) { pAC->Addr.Port[PortNumber].InexactFilter.Bytes[i] = 0xFF; } #endif /* SK_ADDR_CHEAT */ return (SK_MC_FILTERING_INEXACT); } /* SkAddrGmacMcAdd */ /****************************************************************************** * * SkAddrMcUpdate - update the HW MC address table and set the MAC address * * Description: * This routine enables reception of the addresses contained in a local * table for a given port. * It also programs the port's current physical MAC address. * * It calls either SkAddrXmacMcUpdate or SkAddrGmacMcUpdate, according * to the adapter in use. The real work is done there. * * Notes: * The return code is only valid for SK_PROM_MODE_NONE. * * Context: * runtime, pageable * may be called after SK_INIT_IO * * Returns: * SK_MC_FILTERING_EXACT * SK_MC_FILTERING_INEXACT * SK_ADDR_ILLEGAL_PORT */ int SkAddrMcUpdate( SK_AC *pAC, /* adapter context */ SK_IOC IoC, /* I/O context */ SK_U32 PortNumber) /* Port Number */ { int ReturnCode; if (PortNumber >= (SK_U32) pAC->GIni.GIMacsFound) { return (SK_ADDR_ILLEGAL_PORT); } if (pAC->GIni.GIChipId == CHIP_ID_GENESIS) { ReturnCode = SkAddrXmacMcUpdate(pAC, IoC, PortNumber); } else { ReturnCode = SkAddrGmacMcUpdate(pAC, IoC, PortNumber); } return (ReturnCode); } /* SkAddrMcUpdate */ /****************************************************************************** * * SkAddrXmacMcUpdate - update the HW MC address table and set the MAC address * * Description: * This routine enables reception of the addresses contained in a local * table for a given port. * It also programs the port's current physical MAC address. * * Notes: * The return code is only valid for SK_PROM_MODE_NONE. * * Context: * runtime, pageable * may be called after SK_INIT_IO * * Returns: * SK_MC_FILTERING_EXACT * SK_MC_FILTERING_INEXACT * SK_ADDR_ILLEGAL_PORT */ int SkAddrXmacMcUpdate( SK_AC *pAC, /* adapter context */ SK_IOC IoC, /* I/O context */ SK_U32 PortNumber) /* Port Number */ { SK_U32 i; SK_U8 Inexact; SK_U16 *OutAddr; SK_ADDR_PORT *pAPort; SK_DBG_MSG(pAC,SK_DBGMOD_ADDR, SK_DBGCAT_CTRL, ("SkAddrXmacMcUpdate on Port %u.\n", PortNumber)) pAPort = &pAC->Addr.Port[PortNumber]; #ifdef DEBUG SK_DBG_MSG(pAC,SK_DBGMOD_ADDR, SK_DBGCAT_CTRL, ("Next0 on Port %d: %d\n", PortNumber, Next0[PortNumber])) #endif /* DEBUG */ /* Start with 0 to also program the logical MAC address. */ for (i = 0; i < pAPort->NextExactMatchRlmt; i++) { /* Set exact match address i on XMAC */ OutAddr = (SK_U16 *) &pAPort->Exact[i].a[0]; XM_OUTADDR(IoC, PortNumber, XM_EXM(i), OutAddr); } /* Clear other permanent exact match addresses on XMAC */ if (pAPort->NextExactMatchRlmt <= SK_ADDR_LAST_MATCH_RLMT) { SkXmClrExactAddr(pAC, IoC, PortNumber, pAPort->NextExactMatchRlmt, SK_ADDR_LAST_MATCH_RLMT); } for (i = pAPort->FirstExactMatchDrv; i < pAPort->NextExactMatchDrv; i++) { OutAddr = (SK_U16 *) &pAPort->Exact[i].a[0]; XM_OUTADDR(IoC, PortNumber, XM_EXM(i), OutAddr); } /* Clear other non-permanent exact match addresses on XMAC */ if (pAPort->NextExactMatchDrv <= SK_ADDR_LAST_MATCH_DRV) { SkXmClrExactAddr(pAC, IoC, PortNumber, pAPort->NextExactMatchDrv, SK_ADDR_LAST_MATCH_DRV); } for (Inexact = 0, i = 0; i < 8; i++) { Inexact |= pAPort->InexactFilter.Bytes[i]; } if (pAPort->PromMode & SK_PROM_MODE_ALL_MC) { /* Set all bits in 64-bit hash register. */ XM_OUTHASH(IoC, PortNumber, XM_HSM, &OnesHash); /* Enable Hashing */ SkMacHashing(pAC, IoC, PortNumber, SK_TRUE); } else if (Inexact != 0) { /* Set 64-bit hash register to InexactFilter. */ XM_OUTHASH(IoC, PortNumber, XM_HSM, &pAPort->InexactFilter.Bytes[0]); /* Enable Hashing */ SkMacHashing(pAC, IoC, PortNumber, SK_TRUE); } else { /* Disable Hashing */ SkMacHashing(pAC, IoC, PortNumber, SK_FALSE); } if (pAPort->PromMode != SK_PROM_MODE_NONE) { (void) SkAddrXmacPromiscuousChange(pAC, IoC, PortNumber, pAPort->PromMode); } /* Set port's current physical MAC address. */ OutAddr = (SK_U16 *) &pAPort->CurrentMacAddress.a[0]; XM_OUTADDR(IoC, PortNumber, XM_SA, OutAddr); #ifdef xDEBUG for (i = 0; i < pAPort->NextExactMatchRlmt; i++) { SK_U8 InAddr8[6]; SK_U16 *InAddr; /* Get exact match address i from port PortNumber. */ InAddr = (SK_U16 *) &InAddr8[0]; XM_INADDR(IoC, PortNumber, XM_EXM(i), InAddr); SK_DBG_MSG(pAC,SK_DBGMOD_ADDR, SK_DBGCAT_CTRL, ("SkAddrXmacMcUpdate: MC address %d on Port %u: ", "%02x %02x %02x %02x %02x %02x -- %02x %02x %02x %02x %02x %02x\n", i, PortNumber, InAddr8[0], InAddr8[1], InAddr8[2], InAddr8[3], InAddr8[4], InAddr8[5], pAPort->Exact[i].a[0], pAPort->Exact[i].a[1], pAPort->Exact[i].a[2], pAPort->Exact[i].a[3], pAPort->Exact[i].a[4], pAPort->Exact[i].a[5])) } #endif /* DEBUG */ /* Determine return value. */ if (Inexact == 0 && pAPort->PromMode == 0) { return (SK_MC_FILTERING_EXACT); } else { return (SK_MC_FILTERING_INEXACT); } } /* SkAddrXmacMcUpdate */ /****************************************************************************** * * SkAddrGmacMcUpdate - update the HW MC address table and set the MAC address * * Description: * This routine enables reception of the addresses contained in a local * table for a given port. * It also programs the port's current physical MAC address. * * Notes: * The return code is only valid for SK_PROM_MODE_NONE. * * Context: * runtime, pageable * may be called after SK_INIT_IO * * Returns: * SK_MC_FILTERING_EXACT * SK_MC_FILTERING_INEXACT * SK_ADDR_ILLEGAL_PORT */ int SkAddrGmacMcUpdate( SK_AC *pAC, /* adapter context */ SK_IOC IoC, /* I/O context */ SK_U32 PortNumber) /* Port Number */ { SK_U32 i; SK_U8 Inexact; SK_U16 *OutAddr; SK_ADDR_PORT *pAPort; SK_DBG_MSG(pAC,SK_DBGMOD_ADDR, SK_DBGCAT_CTRL, ("SkAddrGmacMcUpdate on Port %u.\n", PortNumber)) pAPort = &pAC->Addr.Port[PortNumber]; #ifdef DEBUG SK_DBG_MSG(pAC,SK_DBGMOD_ADDR, SK_DBGCAT_CTRL, ("Next0 on Port %d: %d\n", PortNumber, Next0[PortNumber])) #endif /* DEBUG */ for (Inexact = 0, i = 0; i < 8; i++) { Inexact |= pAPort->InexactFilter.Bytes[i]; } /* Set 64-bit hash register to InexactFilter. */ GM_OUTHASH(IoC, PortNumber, GM_MC_ADDR_H1, &pAPort->InexactFilter.Bytes[0]); if (pAPort->PromMode & SK_PROM_MODE_ALL_MC) { /* Set all bits in 64-bit hash register. */ GM_OUTHASH(IoC, PortNumber, GM_MC_ADDR_H1, &OnesHash); /* Enable Hashing */ SkMacHashing(pAC, IoC, PortNumber, SK_TRUE); } else { /* Enable Hashing. */ SkMacHashing(pAC, IoC, PortNumber, SK_TRUE); } if (pAPort->PromMode != SK_PROM_MODE_NONE) { (void) SkAddrGmacPromiscuousChange(pAC, IoC, PortNumber, pAPort->PromMode); } /* Set port's current physical MAC address. */ OutAddr = (SK_U16 *) &pAPort->CurrentMacAddress.a[0]; GM_OUTADDR(IoC, PortNumber, GM_SRC_ADDR_1L, OutAddr); /* Set port's current logical MAC address. */ OutAddr = (SK_U16 *) &pAPort->Exact[0].a[0]; GM_OUTADDR(IoC, PortNumber, GM_SRC_ADDR_2L, OutAddr); #ifdef DEBUG SK_DBG_MSG(pAC, SK_DBGMOD_ADDR, SK_DBGCAT_CTRL, ("SkAddrGmacMcUpdate: Permanent Physical MAC Address: %02X %02X %02X %02X %02X %02X\n", pAPort->Exact[0].a[0], pAPort->Exact[0].a[1], pAPort->Exact[0].a[2], pAPort->Exact[0].a[3], pAPort->Exact[0].a[4], pAPort->Exact[0].a[5])) SK_DBG_MSG(pAC, SK_DBGMOD_ADDR, SK_DBGCAT_CTRL, ("SkAddrGmacMcUpdate: Physical MAC Address: %02X %02X %02X %02X %02X %02X\n", pAPort->CurrentMacAddress.a[0], pAPort->CurrentMacAddress.a[1], pAPort->CurrentMacAddress.a[2], pAPort->CurrentMacAddress.a[3], pAPort->CurrentMacAddress.a[4], pAPort->CurrentMacAddress.a[5])) #endif /* DEBUG */ /* Determine return value. */ if (Inexact == 0 && pAPort->PromMode == 0) { return (SK_MC_FILTERING_EXACT); } else { return (SK_MC_FILTERING_INEXACT); } } /* SkAddrGmacMcUpdate */ /****************************************************************************** * * SkAddrOverride - override a port's MAC address * * Description: * This routine overrides the MAC address of one port. * * Context: * runtime, pageable * may be called after SK_INIT_IO * * Returns: * SK_ADDR_SUCCESS if successful. * SK_ADDR_DUPLICATE_ADDRESS if duplicate MAC address. * SK_ADDR_MULTICAST_ADDRESS if multicast or broadcast address. * SK_ADDR_TOO_EARLY if SK_INIT_IO was not executed before. */ int SkAddrOverride( SK_AC *pAC, /* adapter context */ SK_IOC IoC, /* I/O context */ SK_U32 PortNumber, /* Port Number */ SK_MAC_ADDR *pNewAddr, /* new MAC address */ int Flags) /* logical/physical MAC address */ { SK_EVPARA Para; SK_U32 NetNumber; SK_U32 i; SK_U16 *OutAddr; NetNumber = pAC->Rlmt.Port[PortNumber].Net->NetNumber; if (PortNumber >= (SK_U32) pAC->GIni.GIMacsFound) { return (SK_ADDR_ILLEGAL_PORT); } if (pNewAddr != NULL && (pNewAddr->a[0] & SK_MC_BIT) != 0) { return (SK_ADDR_MULTICAST_ADDRESS); } if (!pAC->Addr.Net[NetNumber].CurrentMacAddressSet) { return (SK_ADDR_TOO_EARLY); } if (Flags & SK_ADDR_SET_LOGICAL) { /* Activate logical MAC address. */ /* Parameter *pNewAddr is ignored. */ for (i = 0; i < (SK_U32) pAC->GIni.GIMacsFound; i++) { if (!pAC->Addr.Port[i].CurrentMacAddressSet) { return (SK_ADDR_TOO_EARLY); } } /* Set PortNumber to number of net's active port. */ PortNumber = pAC->Rlmt.Net[NetNumber]. Port[pAC->Addr.Net[NetNumber].ActivePort]->PortNumber; pAC->Addr.Port[PortNumber].Exact[0] = pAC->Addr.Net[NetNumber].CurrentMacAddress; /* Write address to first exact match entry of active port. */ (void) SkAddrMcUpdate(pAC, IoC, PortNumber); } else if (Flags & SK_ADDR_CLEAR_LOGICAL) { /* Deactivate logical MAC address. */ /* Parameter *pNewAddr is ignored. */ for (i = 0; i < (SK_U32) pAC->GIni.GIMacsFound; i++) { if (!pAC->Addr.Port[i].CurrentMacAddressSet) { return (SK_ADDR_TOO_EARLY); } } /* Set PortNumber to number of net's active port. */ PortNumber = pAC->Rlmt.Net[NetNumber]. Port[pAC->Addr.Net[NetNumber].ActivePort]->PortNumber; for (i = 0; i < SK_MAC_ADDR_LEN; i++ ) { pAC->Addr.Port[PortNumber].Exact[0].a[i] = 0; } /* Write address to first exact match entry of active port. */ (void) SkAddrMcUpdate(pAC, IoC, PortNumber); } else if (Flags & SK_ADDR_PHYSICAL_ADDRESS) { /* Physical MAC address. */ if (SK_ADDR_EQUAL(pNewAddr->a, pAC->Addr.Net[NetNumber].CurrentMacAddress.a)) { return (SK_ADDR_DUPLICATE_ADDRESS); } for (i = 0; i < (SK_U32) pAC->GIni.GIMacsFound; i++) { if (!pAC->Addr.Port[i].CurrentMacAddressSet) { return (SK_ADDR_TOO_EARLY); } if (SK_ADDR_EQUAL(pNewAddr->a, pAC->Addr.Port[i].CurrentMacAddress.a)) { if (i == PortNumber) { return (SK_ADDR_SUCCESS); } else { return (SK_ADDR_DUPLICATE_ADDRESS); } } } pAC->Addr.Port[PortNumber].PreviousMacAddress = pAC->Addr.Port[PortNumber].CurrentMacAddress; pAC->Addr.Port[PortNumber].CurrentMacAddress = *pNewAddr; /* Change port's physical MAC address. */ OutAddr = (SK_U16 *) pNewAddr; if (pAC->GIni.GIChipId == CHIP_ID_GENESIS) { XM_OUTADDR(IoC, PortNumber, XM_SA, OutAddr); } else { GM_OUTADDR(IoC, PortNumber, GM_SRC_ADDR_1L, OutAddr); } /* Report address change to RLMT. */ Para.Para32[0] = PortNumber; Para.Para32[0] = -1; SkEventQueue(pAC, SKGE_RLMT, SK_RLMT_PORT_ADDR, Para); } else { /* Logical MAC address. */ if (SK_ADDR_EQUAL(pNewAddr->a, pAC->Addr.Net[NetNumber].CurrentMacAddress.a)) { return (SK_ADDR_SUCCESS); } for (i = 0; i < (SK_U32) pAC->GIni.GIMacsFound; i++) { if (!pAC->Addr.Port[i].CurrentMacAddressSet) { return (SK_ADDR_TOO_EARLY); } if (SK_ADDR_EQUAL(pNewAddr->a, pAC->Addr.Port[i].CurrentMacAddress.a)) { return (SK_ADDR_DUPLICATE_ADDRESS); } } /* * In case that the physical and the logical MAC addresses are equal * we must also change the physical MAC address here. * In this case we have an adapter which initially was programmed with * two identical MAC addresses. */ if (SK_ADDR_EQUAL(pAC->Addr.Port[PortNumber].CurrentMacAddress.a, pAC->Addr.Port[PortNumber].Exact[0].a)) { pAC->Addr.Port[PortNumber].PreviousMacAddress = pAC->Addr.Port[PortNumber].CurrentMacAddress; pAC->Addr.Port[PortNumber].CurrentMacAddress = *pNewAddr; /* Report address change to RLMT. */ Para.Para32[0] = PortNumber; Para.Para32[0] = -1; SkEventQueue(pAC, SKGE_RLMT, SK_RLMT_PORT_ADDR, Para); } /* Set PortNumber to number of net's active port. */ PortNumber = pAC->Rlmt.Net[NetNumber]. Port[pAC->Addr.Net[NetNumber].ActivePort]->PortNumber; pAC->Addr.Net[NetNumber].CurrentMacAddress = *pNewAddr; pAC->Addr.Port[PortNumber].Exact[0] = *pNewAddr; #ifdef DEBUG SK_DBG_MSG(pAC,SK_DBGMOD_ADDR, SK_DBGCAT_CTRL, ("SkAddrOverride: Permanent MAC Address: %02X %02X %02X %02X %02X %02X\n", pAC->Addr.Net[NetNumber].PermanentMacAddress.a[0], pAC->Addr.Net[NetNumber].PermanentMacAddress.a[1], pAC->Addr.Net[NetNumber].PermanentMacAddress.a[2], pAC->Addr.Net[NetNumber].PermanentMacAddress.a[3], pAC->Addr.Net[NetNumber].PermanentMacAddress.a[4], pAC->Addr.Net[NetNumber].PermanentMacAddress.a[5])) SK_DBG_MSG(pAC,SK_DBGMOD_ADDR, SK_DBGCAT_CTRL, ("SkAddrOverride: New logical MAC Address: %02X %02X %02X %02X %02X %02X\n", pAC->Addr.Net[NetNumber].CurrentMacAddress.a[0], pAC->Addr.Net[NetNumber].CurrentMacAddress.a[1], pAC->Addr.Net[NetNumber].CurrentMacAddress.a[2], pAC->Addr.Net[NetNumber].CurrentMacAddress.a[3], pAC->Addr.Net[NetNumber].CurrentMacAddress.a[4], pAC->Addr.Net[NetNumber].CurrentMacAddress.a[5])) #endif /* DEBUG */ /* Write address to first exact match entry of active port. */ (void) SkAddrMcUpdate(pAC, IoC, PortNumber); } return (SK_ADDR_SUCCESS); } /* SkAddrOverride */ /****************************************************************************** * * SkAddrPromiscuousChange - set promiscuous mode for given port * * Description: * This routine manages promiscuous mode: * - none * - all LLC frames * - all MC frames * * It calls either SkAddrXmacPromiscuousChange or * SkAddrGmacPromiscuousChange, according to the adapter in use. * The real work is done there. * * Context: * runtime, pageable * may be called after SK_INIT_IO * * Returns: * SK_ADDR_SUCCESS * SK_ADDR_ILLEGAL_PORT */ int SkAddrPromiscuousChange( SK_AC *pAC, /* adapter context */ SK_IOC IoC, /* I/O context */ SK_U32 PortNumber, /* port whose promiscuous mode changes */ int NewPromMode) /* new promiscuous mode */ { int ReturnCode; if (PortNumber >= (SK_U32) pAC->GIni.GIMacsFound) { return (SK_ADDR_ILLEGAL_PORT); } if (pAC->GIni.GIChipId == CHIP_ID_GENESIS) { ReturnCode = SkAddrXmacPromiscuousChange(pAC, IoC, PortNumber, NewPromMode); } else { ReturnCode = SkAddrGmacPromiscuousChange(pAC, IoC, PortNumber, NewPromMode); } return (ReturnCode); } /* SkAddrPromiscuousChange */ /****************************************************************************** * * SkAddrXmacPromiscuousChange - set promiscuous mode for given port * * Description: * This routine manages promiscuous mode: * - none * - all LLC frames * - all MC frames * * Context: * runtime, pageable * may be called after SK_INIT_IO * * Returns: * SK_ADDR_SUCCESS * SK_ADDR_ILLEGAL_PORT */ int SkAddrXmacPromiscuousChange( SK_AC *pAC, /* adapter context */ SK_IOC IoC, /* I/O context */ SK_U32 PortNumber, /* port whose promiscuous mode changes */ int NewPromMode) /* new promiscuous mode */ { int i; SK_BOOL InexactModeBit; SK_U8 Inexact; SK_U8 HwInexact; SK_FILTER64 HwInexactFilter; SK_U16 LoMode; /* Lower 16 bits of XMAC Mode Register. */ int CurPromMode = SK_PROM_MODE_NONE; /* Read CurPromMode from Hardware. */ XM_IN16(IoC, PortNumber, XM_MODE, &LoMode); if ((LoMode & XM_MD_ENA_PROM) != 0) { /* Promiscuous mode! */ CurPromMode |= SK_PROM_MODE_LLC; } for (Inexact = 0xFF, i = 0; i < 8; i++) { Inexact &= pAC->Addr.Port[PortNumber].InexactFilter.Bytes[i]; } if (Inexact == 0xFF) { CurPromMode |= (pAC->Addr.Port[PortNumber].PromMode & SK_PROM_MODE_ALL_MC); } else { /* Get InexactModeBit (bit XM_MD_ENA_HASH in mode register) */ XM_IN16(IoC, PortNumber, XM_MODE, &LoMode); InexactModeBit = (LoMode & XM_MD_ENA_HASH) != 0; /* Read 64-bit hash register from XMAC */ XM_INHASH(IoC, PortNumber, XM_HSM, &HwInexactFilter.Bytes[0]); for (HwInexact = 0xFF, i = 0; i < 8; i++) { HwInexact &= HwInexactFilter.Bytes[i]; } if (InexactModeBit && (HwInexact == 0xFF)) { CurPromMode |= SK_PROM_MODE_ALL_MC; } } pAC->Addr.Port[PortNumber].PromMode = NewPromMode; if (NewPromMode == CurPromMode) { return (SK_ADDR_SUCCESS); } if ((NewPromMode & SK_PROM_MODE_ALL_MC) && !(CurPromMode & SK_PROM_MODE_ALL_MC)) { /* All MC. */ /* Set all bits in 64-bit hash register. */ XM_OUTHASH(IoC, PortNumber, XM_HSM, &OnesHash); /* Enable Hashing */ SkMacHashing(pAC, IoC, PortNumber, SK_TRUE); } else if ((CurPromMode & SK_PROM_MODE_ALL_MC) && !(NewPromMode & SK_PROM_MODE_ALL_MC)) { /* Norm MC. */ for (Inexact = 0, i = 0; i < 8; i++) { Inexact |= pAC->Addr.Port[PortNumber].InexactFilter.Bytes[i]; } if (Inexact == 0) { /* Disable Hashing */ SkMacHashing(pAC, IoC, PortNumber, SK_FALSE); } else { /* Set 64-bit hash register to InexactFilter. */ XM_OUTHASH(IoC, PortNumber, XM_HSM, &pAC->Addr.Port[PortNumber].InexactFilter.Bytes[0]); /* Enable Hashing */ SkMacHashing(pAC, IoC, PortNumber, SK_TRUE); } } if ((NewPromMode & SK_PROM_MODE_LLC) && !(CurPromMode & SK_PROM_MODE_LLC)) { /* Prom. LLC */ /* Set the MAC in Promiscuous Mode */ SkMacPromiscMode(pAC, IoC, PortNumber, SK_TRUE); } else if ((CurPromMode & SK_PROM_MODE_LLC) && !(NewPromMode & SK_PROM_MODE_LLC)) { /* Norm. LLC. */ /* Clear Promiscuous Mode */ SkMacPromiscMode(pAC, IoC, PortNumber, SK_FALSE); } return (SK_ADDR_SUCCESS); } /* SkAddrXmacPromiscuousChange */ /****************************************************************************** * * SkAddrGmacPromiscuousChange - set promiscuous mode for given port * * Description: * This routine manages promiscuous mode: * - none * - all LLC frames * - all MC frames * * Context: * runtime, pageable * may be called after SK_INIT_IO * * Returns: * SK_ADDR_SUCCESS * SK_ADDR_ILLEGAL_PORT */ int SkAddrGmacPromiscuousChange( SK_AC *pAC, /* adapter context */ SK_IOC IoC, /* I/O context */ SK_U32 PortNumber, /* port whose promiscuous mode changes */ int NewPromMode) /* new promiscuous mode */ { SK_U16 ReceiveControl; /* GMAC Receive Control Register */ int CurPromMode = SK_PROM_MODE_NONE; /* Read CurPromMode from Hardware. */ GM_IN16(IoC, PortNumber, GM_RX_CTRL, &ReceiveControl); if ((ReceiveControl & (GM_RXCR_UCF_ENA | GM_RXCR_MCF_ENA)) == 0) { /* Promiscuous mode! */ CurPromMode |= SK_PROM_MODE_LLC; } if ((ReceiveControl & GM_RXCR_MCF_ENA) == 0) { /* All Multicast mode! */ CurPromMode |= (pAC->Addr.Port[PortNumber].PromMode & SK_PROM_MODE_ALL_MC); } pAC->Addr.Port[PortNumber].PromMode = NewPromMode; if (NewPromMode == CurPromMode) { return (SK_ADDR_SUCCESS); } if ((NewPromMode & SK_PROM_MODE_ALL_MC) && !(CurPromMode & SK_PROM_MODE_ALL_MC)) { /* All MC */ /* Set all bits in 64-bit hash register. */ GM_OUTHASH(IoC, PortNumber, GM_MC_ADDR_H1, &OnesHash); /* Enable Hashing */ SkMacHashing(pAC, IoC, PortNumber, SK_TRUE); } if ((CurPromMode & SK_PROM_MODE_ALL_MC) && !(NewPromMode & SK_PROM_MODE_ALL_MC)) { /* Norm. MC */ /* Set 64-bit hash register to InexactFilter. */ GM_OUTHASH(IoC, PortNumber, GM_MC_ADDR_H1, &pAC->Addr.Port[PortNumber].InexactFilter.Bytes[0]); /* Enable Hashing. */ SkMacHashing(pAC, IoC, PortNumber, SK_TRUE); } if ((NewPromMode & SK_PROM_MODE_LLC) && !(CurPromMode & SK_PROM_MODE_LLC)) { /* Prom. LLC */ /* Set the MAC to Promiscuous Mode. */ SkMacPromiscMode(pAC, IoC, PortNumber, SK_TRUE); } else if ((CurPromMode & SK_PROM_MODE_LLC) && !(NewPromMode & SK_PROM_MODE_LLC)) { /* Norm. LLC */ /* Clear Promiscuous Mode. */ SkMacPromiscMode(pAC, IoC, PortNumber, SK_FALSE); } return (SK_ADDR_SUCCESS); } /* SkAddrGmacPromiscuousChange */ /****************************************************************************** * * SkAddrSwap - swap address info * * Description: * This routine swaps address info of two ports. * * Context: * runtime, pageable * may be called after SK_INIT_IO * * Returns: * SK_ADDR_SUCCESS * SK_ADDR_ILLEGAL_PORT */ int SkAddrSwap( SK_AC *pAC, /* adapter context */ SK_IOC IoC, /* I/O context */ SK_U32 FromPortNumber, /* Port1 Index */ SK_U32 ToPortNumber) /* Port2 Index */ { int i; SK_U8 Byte; SK_MAC_ADDR MacAddr; SK_U32 DWord; if (FromPortNumber >= (SK_U32) pAC->GIni.GIMacsFound) { return (SK_ADDR_ILLEGAL_PORT); } if (ToPortNumber >= (SK_U32) pAC->GIni.GIMacsFound) { return (SK_ADDR_ILLEGAL_PORT); } if (pAC->Rlmt.Port[FromPortNumber].Net != pAC->Rlmt.Port[ToPortNumber].Net) { return (SK_ADDR_ILLEGAL_PORT); } /* * Swap: * - Exact Match Entries (GEnesis and Yukon) * Yukon uses first entry for the logical MAC * address (stored in the second GMAC register). * - FirstExactMatchRlmt (GEnesis only) * - NextExactMatchRlmt (GEnesis only) * - FirstExactMatchDrv (GEnesis only) * - NextExactMatchDrv (GEnesis only) * - 64-bit filter (InexactFilter) * - Promiscuous Mode * of ports. */ for (i = 0; i < SK_ADDR_EXACT_MATCHES; i++) { MacAddr = pAC->Addr.Port[FromPortNumber].Exact[i]; pAC->Addr.Port[FromPortNumber].Exact[i] = pAC->Addr.Port[ToPortNumber].Exact[i]; pAC->Addr.Port[ToPortNumber].Exact[i] = MacAddr; } for (i = 0; i < 8; i++) { Byte = pAC->Addr.Port[FromPortNumber].InexactFilter.Bytes[i]; pAC->Addr.Port[FromPortNumber].InexactFilter.Bytes[i] = pAC->Addr.Port[ToPortNumber].InexactFilter.Bytes[i]; pAC->Addr.Port[ToPortNumber].InexactFilter.Bytes[i] = Byte; } i = pAC->Addr.Port[FromPortNumber].PromMode; pAC->Addr.Port[FromPortNumber].PromMode = pAC->Addr.Port[ToPortNumber].PromMode; pAC->Addr.Port[ToPortNumber].PromMode = i; if (pAC->GIni.GIChipId == CHIP_ID_GENESIS) { DWord = pAC->Addr.Port[FromPortNumber].FirstExactMatchRlmt; pAC->Addr.Port[FromPortNumber].FirstExactMatchRlmt = pAC->Addr.Port[ToPortNumber].FirstExactMatchRlmt; pAC->Addr.Port[ToPortNumber].FirstExactMatchRlmt = DWord; DWord = pAC->Addr.Port[FromPortNumber].NextExactMatchRlmt; pAC->Addr.Port[FromPortNumber].NextExactMatchRlmt = pAC->Addr.Port[ToPortNumber].NextExactMatchRlmt; pAC->Addr.Port[ToPortNumber].NextExactMatchRlmt = DWord; DWord = pAC->Addr.Port[FromPortNumber].FirstExactMatchDrv; pAC->Addr.Port[FromPortNumber].FirstExactMatchDrv = pAC->Addr.Port[ToPortNumber].FirstExactMatchDrv; pAC->Addr.Port[ToPortNumber].FirstExactMatchDrv = DWord; DWord = pAC->Addr.Port[FromPortNumber].NextExactMatchDrv; pAC->Addr.Port[FromPortNumber].NextExactMatchDrv = pAC->Addr.Port[ToPortNumber].NextExactMatchDrv; pAC->Addr.Port[ToPortNumber].NextExactMatchDrv = DWord; } /* CAUTION: Solution works if only ports of one adapter are in use. */ for (i = 0; (SK_U32) i < pAC->Rlmt.Net[pAC->Rlmt.Port[ToPortNumber]. Net->NetNumber].NumPorts; i++) { if (pAC->Rlmt.Net[pAC->Rlmt.Port[ToPortNumber].Net->NetNumber]. Port[i]->PortNumber == ToPortNumber) { pAC->Addr.Net[pAC->Rlmt.Port[ToPortNumber].Net->NetNumber]. ActivePort = i; /* 20001207 RA: Was "ToPortNumber;". */ } } (void) SkAddrMcUpdate(pAC, IoC, FromPortNumber); (void) SkAddrMcUpdate(pAC, IoC, ToPortNumber); return (SK_ADDR_SUCCESS); } /* SkAddrSwap */ #ifdef __cplusplus } #endif /* __cplusplus */ #endif /* CONFIG_SK98 */