diff options
author | Mandy Lavi <mandy.lavi@freescale.com> | 2013-03-24 16:40:18 (GMT) |
---|---|---|
committer | Fleming Andrew-AFLEMING <AFLEMING@freescale.com> | 2013-04-08 23:07:26 (GMT) |
commit | 3cc514986cb4e457458cc826288b6c2107c97907 (patch) | |
tree | 2985e48afc5dd20f44d51ef6aafdae917ce2698f /drivers/net/ethernet/freescale/fman/Peripherals/FM/MAC | |
parent | 5767d52cec831b0e2927d34e91acd738cc1cb0ef (diff) | |
download | linux-fsl-qoriq-3cc514986cb4e457458cc826288b6c2107c97907.tar.xz |
fmd: fmd19 integration
Add fmd19 codebase, plus a minimal set of sources from dpaa-eth,
necessary for bare compilation
Change-Id: I390df8717671204e3d98a987135393bef4534e95
Signed-off-by: Mandy Lavi <mandy.lavi@freescale.com>
Signed-off-by: Bogdan Hamciuc <bogdan.hamciuc@freescale.com>
Reviewed-on: http://git.am.freescale.net:8181/1029
Reviewed-by: Fleming Andrew-AFLEMING <AFLEMING@freescale.com>
Tested-by: Fleming Andrew-AFLEMING <AFLEMING@freescale.com>
Diffstat (limited to 'drivers/net/ethernet/freescale/fman/Peripherals/FM/MAC')
22 files changed, 7637 insertions, 0 deletions
diff --git a/drivers/net/ethernet/freescale/fman/Peripherals/FM/MAC/Makefile b/drivers/net/ethernet/freescale/fman/Peripherals/FM/MAC/Makefile new file mode 100644 index 0000000..a018ab2 --- /dev/null +++ b/drivers/net/ethernet/freescale/fman/Peripherals/FM/MAC/Makefile @@ -0,0 +1,21 @@ +# +# Makefile for the Freescale Ethernet controllers +# +EXTRA_CFLAGS += -DVERSION=\"\" +# +#Include netcomm SW specific definitions +include $(srctree)/drivers/net/ethernet/freescale/fman/ncsw_config.mk + +NCSW_FM_INC = $(srctree)/drivers/net/ethernet/freescale/fman/Peripherals/FM/inc + +EXTRA_CFLAGS += -I$(NCSW_FM_INC) + +obj-y += fsl-ncsw-MAC.o + +fsl-ncsw-MAC-objs := dtsec.o dtsec_mii_acc.o fm_mac.o tgec.o tgec_mii_acc.o \ + fman_dtsec.o fman_dtsec_mii_acc.o fman_memac.o \ + fman_tgec.o fman_crc32.o + +ifeq ($(CONFIG_FMAN_T4240),y) +fsl-ncsw-MAC-objs += memac.o memac_mii_acc.o +endif diff --git a/drivers/net/ethernet/freescale/fman/Peripherals/FM/MAC/dtsec.c b/drivers/net/ethernet/freescale/fman/Peripherals/FM/MAC/dtsec.c new file mode 100644 index 0000000..e4cb509 --- /dev/null +++ b/drivers/net/ethernet/freescale/fman/Peripherals/FM/MAC/dtsec.c @@ -0,0 +1,1513 @@ +/* + * Copyright 2008-2012 Freescale Semiconductor Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Freescale Semiconductor nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + +/****************************************************************************** + @File dtsec.c + + @Description FM dTSEC ... +*//***************************************************************************/ + +#include "std_ext.h" +#include "error_ext.h" +#include "string_ext.h" +#include "xx_ext.h" +#include "endian_ext.h" +#include "debug_ext.h" +#include "crc_mac_addr_ext.h" + +#include "fm_common.h" +#include "dtsec.h" +#include "fsl_fman_dtsec.h" + + +/*****************************************************************************/ +/* Internal routines */ +/*****************************************************************************/ + +static t_Error CheckInitParameters(t_Dtsec *p_Dtsec) +{ + if (ENET_SPEED_FROM_MODE(p_Dtsec->enetMode) >= e_ENET_SPEED_10000) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("Ethernet 1G MAC driver only supports 1G or lower speeds")); + if (p_Dtsec->macId >= FM_MAX_NUM_OF_1G_MACS) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("macId can not be greater than the number of 1G MACs")); + if (p_Dtsec->addr == 0) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("Ethernet MAC Must have a valid MAC Address")); + if ((ENET_SPEED_FROM_MODE(p_Dtsec->enetMode) >= e_ENET_SPEED_1000) && + p_Dtsec->p_DtsecDriverParam->halfdup_on) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("Ethernet MAC 1G can't work in half duplex")); + if (p_Dtsec->p_DtsecDriverParam->halfdup_on && (p_Dtsec->p_DtsecDriverParam)->loopback) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("LoopBack is not supported in halfDuplex mode")); +#ifdef FM_RX_PREAM_4_ERRATA_DTSEC_A001 + if (p_Dtsec->fmMacControllerDriver.fmRevInfo.majorRev <= 6) /* fixed for rev3 */ + if (p_Dtsec->p_DtsecDriverParam->rx_preamble) + RETURN_ERROR(MAJOR, E_NOT_SUPPORTED, ("preambleRxEn")); +#endif /* FM_RX_PREAM_4_ERRATA_DTSEC_A001 */ + if (((p_Dtsec->p_DtsecDriverParam)->tx_preamble || (p_Dtsec->p_DtsecDriverParam)->rx_preamble) &&( (p_Dtsec->p_DtsecDriverParam)->preamble_len != 0x7)) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("Preamble length should be 0x7 bytes")); + if ((p_Dtsec->p_DtsecDriverParam)->halfdup_on && + (p_Dtsec->p_DtsecDriverParam->tx_time_stamp_en || p_Dtsec->p_DtsecDriverParam->rx_time_stamp_en)) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("dTSEC in half duplex mode has to be with 1588 timeStamping diable")); + if ((p_Dtsec->p_DtsecDriverParam)->rx_flow && (p_Dtsec->p_DtsecDriverParam)->rx_ctrl_acc ) + RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Receive control frame are not passed to the system memory so it can not be accept ")); + if ((p_Dtsec->p_DtsecDriverParam)->rx_prepend > MAX_PACKET_ALIGNMENT) + RETURN_ERROR(MAJOR, E_INVALID_STATE, ("packetAlignmentPadding can't be greater than %d ",MAX_PACKET_ALIGNMENT )); + if (((p_Dtsec->p_DtsecDriverParam)->non_back_to_back_ipg1 > MAX_INTER_PACKET_GAP) || + ((p_Dtsec->p_DtsecDriverParam)->non_back_to_back_ipg2 > MAX_INTER_PACKET_GAP) || + ((p_Dtsec->p_DtsecDriverParam)->back_to_back_ipg > MAX_INTER_PACKET_GAP)) + RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Inter packet gap can't be greater than %d ",MAX_INTER_PACKET_GAP )); + if ((p_Dtsec->p_DtsecDriverParam)->halfdup_alt_backoff_val > MAX_INTER_PALTERNATE_BEB) + RETURN_ERROR(MAJOR, E_INVALID_STATE, ("alternateBackoffVal can't be greater than %d ",MAX_INTER_PALTERNATE_BEB )); + if ((p_Dtsec->p_DtsecDriverParam)->halfdup_retransmit > MAX_RETRANSMISSION) + RETURN_ERROR(MAJOR, E_INVALID_STATE, ("maxRetransmission can't be greater than %d ",MAX_RETRANSMISSION )); + if ((p_Dtsec->p_DtsecDriverParam)->halfdup_coll_window > MAX_COLLISION_WINDOW) + RETURN_ERROR(MAJOR, E_INVALID_STATE, ("collisionWindow can't be greater than %d ",MAX_COLLISION_WINDOW )); + + /* If Auto negotiation process is disabled, need to */ + /* Set up the PHY using the MII Management Interface */ + if (p_Dtsec->p_DtsecDriverParam->tbipa > MAX_PHYS) + RETURN_ERROR(MAJOR, E_NOT_IN_RANGE, ("PHY address (should be 0-%d)", MAX_PHYS)); + if (!p_Dtsec->f_Exception) + RETURN_ERROR(MAJOR, E_INVALID_HANDLE, ("uninitialized f_Exception")); + if (!p_Dtsec->f_Event) + RETURN_ERROR(MAJOR, E_INVALID_HANDLE, ("uninitialized f_Event")); + +#ifdef FM_LEN_CHECK_ERRATA_FMAN_SW002 + if (p_Dtsec->p_DtsecDriverParam->rx_len_check) + RETURN_ERROR(MINOR, E_NOT_SUPPORTED, ("LengthCheck!")); +#endif /* FM_LEN_CHECK_ERRATA_FMAN_SW002 */ + + return E_OK; +} + +/* ......................................................................... */ + +static uint32_t GetMacAddrHashCode(uint64_t ethAddr) +{ + uint32_t crc; + + /* CRC calculation */ + GET_MAC_ADDR_CRC(ethAddr, crc); + + crc = GetMirror32(crc); + + return crc; +} + +/* ......................................................................... */ + +static void UpdateStatistics(t_Dtsec *p_Dtsec) +{ + uint32_t car1, car2; + + dtsec_get_clear_carry_regs(p_Dtsec->p_MemMap, &car1, &car2); + + if (car1) + { + if (car1 & CAR1_TR64) + p_Dtsec->internalStatistics.tr64 += VAL22BIT; + if (car1 & CAR1_TR127) + p_Dtsec->internalStatistics.tr127 += VAL22BIT; + if (car1 & CAR1_TR255) + p_Dtsec->internalStatistics.tr255 += VAL22BIT; + if (car1 & CAR1_TR511) + p_Dtsec->internalStatistics.tr511 += VAL22BIT; + if (car1 & CAR1_TRK1) + p_Dtsec->internalStatistics.tr1k += VAL22BIT; + if (car1 & CAR1_TRMAX) + p_Dtsec->internalStatistics.trmax += VAL22BIT; + if (car1 & CAR1_TRMGV) + p_Dtsec->internalStatistics.trmgv += VAL22BIT; + if (car1 & CAR1_RBYT) + p_Dtsec->internalStatistics.rbyt += (uint64_t)VAL32BIT; + if (car1 & CAR1_RPKT) + p_Dtsec->internalStatistics.rpkt += VAL22BIT; + if (car1 & CAR1_RMCA) + p_Dtsec->internalStatistics.rmca += VAL22BIT; + if (car1 & CAR1_RBCA) + p_Dtsec->internalStatistics.rbca += VAL22BIT; + if (car1 & CAR1_RXPF) + p_Dtsec->internalStatistics.rxpf += VAL16BIT; + if (car1 & CAR1_RALN) + p_Dtsec->internalStatistics.raln += VAL16BIT; + if (car1 & CAR1_RFLR) + p_Dtsec->internalStatistics.rflr += VAL16BIT; + if (car1 & CAR1_RCDE) + p_Dtsec->internalStatistics.rcde += VAL16BIT; + if (car1 & CAR1_RCSE) + p_Dtsec->internalStatistics.rcse += VAL16BIT; + if (car1 & CAR1_RUND) + p_Dtsec->internalStatistics.rund += VAL16BIT; + if (car1 & CAR1_ROVR) + p_Dtsec->internalStatistics.rovr += VAL16BIT; + if (car1 & CAR1_RFRG) + p_Dtsec->internalStatistics.rfrg += VAL16BIT; + if (car1 & CAR1_RJBR) + p_Dtsec->internalStatistics.rjbr += VAL16BIT; + if (car1 & CAR1_RDRP) + p_Dtsec->internalStatistics.rdrp += VAL16BIT; + } + if (car2) + { + if (car2 & CAR2_TFCS) + p_Dtsec->internalStatistics.tfcs += VAL12BIT; + if (car2 & CAR2_TBYT) + p_Dtsec->internalStatistics.tbyt += (uint64_t)VAL32BIT; + if (car2 & CAR2_TPKT) + p_Dtsec->internalStatistics.tpkt += VAL22BIT; + if (car2 & CAR2_TMCA) + p_Dtsec->internalStatistics.tmca += VAL22BIT; + if (car2 & CAR2_TBCA) + p_Dtsec->internalStatistics.tbca += VAL22BIT; + if (car2 & CAR2_TXPF) + p_Dtsec->internalStatistics.txpf += VAL16BIT; + if (car2 & CAR2_TDRP) + p_Dtsec->internalStatistics.tdrp += VAL16BIT; + } +} + +/* .............................................................................. */ + +static uint16_t DtsecGetMaxFrameLength(t_Handle h_Dtsec) +{ + t_Dtsec *p_Dtsec = (t_Dtsec *)h_Dtsec; + + SANITY_CHECK_RETURN_VALUE(p_Dtsec, E_INVALID_HANDLE, 0); + SANITY_CHECK_RETURN_VALUE(!p_Dtsec->p_DtsecDriverParam, E_INVALID_STATE, 0); + + return dtsec_get_max_frame_len(p_Dtsec->p_MemMap); +} + +/* .............................................................................. */ + +static void DtsecIsr(t_Handle h_Dtsec) +{ + t_Dtsec *p_Dtsec = (t_Dtsec *)h_Dtsec; + uint32_t event; + struct dtsec_regs *p_DtsecMemMap = p_Dtsec->p_MemMap; + + /* do not handle MDIO events */ + event = dtsec_get_event(p_DtsecMemMap, (uint32_t)(~(DTSEC_IMASK_MMRDEN | DTSEC_IMASK_MMWREN))); + + event &= dtsec_get_interrupt_mask(p_DtsecMemMap); + + dtsec_ack_event(p_DtsecMemMap, event); + + if (event & DTSEC_IMASK_BREN) + p_Dtsec->f_Exception(p_Dtsec->h_App, e_FM_MAC_EX_1G_BAB_RX); + if (event & DTSEC_IMASK_RXCEN) + p_Dtsec->f_Exception(p_Dtsec->h_App, e_FM_MAC_EX_1G_RX_CTL); + if (event & DTSEC_IMASK_MSROEN) + UpdateStatistics(p_Dtsec); + if (event & DTSEC_IMASK_GTSCEN) + p_Dtsec->f_Exception(p_Dtsec->h_App, e_FM_MAC_EX_1G_GRATEFUL_TX_STP_COMPLET); + if (event & DTSEC_IMASK_BTEN) + p_Dtsec->f_Exception(p_Dtsec->h_App, e_FM_MAC_EX_1G_BAB_TX); + if (event & DTSEC_IMASK_TXCEN) + p_Dtsec->f_Exception(p_Dtsec->h_App, e_FM_MAC_EX_1G_TX_CTL); + if (event & DTSEC_IMASK_TXEEN) + p_Dtsec->f_Exception(p_Dtsec->h_App, e_FM_MAC_EX_1G_TX_ERR); + if (event & DTSEC_IMASK_LCEN) + p_Dtsec->f_Exception(p_Dtsec->h_App, e_FM_MAC_EX_1G_LATE_COL); + if (event & DTSEC_IMASK_CRLEN) + p_Dtsec->f_Exception(p_Dtsec->h_App, e_FM_MAC_EX_1G_COL_RET_LMT); + if (event & DTSEC_IMASK_XFUNEN) + { +#ifdef FM_TX_LOCKUP_ERRATA_DTSEC6 + if (p_Dtsec->fmMacControllerDriver.fmRevInfo.majorRev == 2) + { + uint32_t tpkt1, tmpReg1, tpkt2, tmpReg2, i; + /* a. Write 0x00E0_0C00 to DTSEC_ID */ + /* This is a read only regidter */ + + /* b. Read and save the value of TPKT */ + tpkt1 = GET_UINT32(p_DtsecMemMap->tpkt); + + /* c. Read the register at dTSEC address offset 0x32C */ + tmpReg1 = GET_UINT32(*(uint32_t*)((uint8_t*)p_DtsecMemMap + 0x32c)); + + /* d. Compare bits [9:15] to bits [25:31] of the register at address offset 0x32C. */ + if ((tmpReg1 & 0x007F0000) != (tmpReg1 & 0x0000007F)) + { + /* If they are not equal, save the value of this register and wait for at least + * MAXFRM*16 ns */ + XX_UDelay((uint32_t)(MIN(DtsecGetMaxFrameLength(p_Dtsec)*16/1000, 1))); + } + + /* e. Read and save TPKT again and read the register at dTSEC address offset + 0x32C again*/ + tpkt2 = GET_UINT32(p_DtsecMemMap->tpkt); + tmpReg2 = GET_UINT32(*(uint32_t*)((uint8_t*)p_DtsecMemMap + 0x32c)); + + /* f. Compare the value of TPKT saved in step b to value read in step e. Also + compare bits [9:15] of the register at offset 0x32C saved in step d to the value + of bits [9:15] saved in step e. If the two registers values are unchanged, then + the transmit portion of the dTSEC controller is locked up and the user should + proceed to the recover sequence. */ + if ((tpkt1 == tpkt2) && ((tmpReg1 & 0x007F0000) == (tmpReg2 & 0x007F0000))) + { + /* recover sequence */ + + /* a.Write a 1 to RCTRL[GRS]*/ + + WRITE_UINT32(p_DtsecMemMap->rctrl, GET_UINT32(p_DtsecMemMap->rctrl) | RCTRL_GRS); + + /* b.Wait until IEVENT[GRSC]=1, or at least 100 us has elapsed. */ + for (i = 0 ; i < 100 ; i++ ) + { + if (GET_UINT32(p_DtsecMemMap->ievent) & DTSEC_IMASK_GRSCEN) + break; + XX_UDelay(1); + } + if (GET_UINT32(p_DtsecMemMap->ievent) & DTSEC_IMASK_GRSCEN) + WRITE_UINT32(p_DtsecMemMap->ievent, DTSEC_IMASK_GRSCEN); + else + DBG(INFO,("Rx lockup due to dTSEC Tx lockup")); + + /* c.Write a 1 to bit n of FM_RSTC (offset 0x0CC of FPM)*/ + FmResetMac(p_Dtsec->fmMacControllerDriver.h_Fm, e_FM_MAC_1G, p_Dtsec->fmMacControllerDriver.macId); + + /* d.Wait 4 Tx clocks (32 ns) */ + XX_UDelay(1); + + /* e.Write a 0 to bit n of FM_RSTC. */ + /* cleared by FMAN */ + } + } +#endif /* FM_TX_LOCKUP_ERRATA_DTSEC6 */ + + p_Dtsec->f_Exception(p_Dtsec->h_App, e_FM_MAC_EX_1G_TX_FIFO_UNDRN); + } + if (event & DTSEC_IMASK_MAGEN) + p_Dtsec->f_Exception(p_Dtsec->h_App, e_FM_MAC_EX_1G_MAG_PCKT); + if (event & DTSEC_IMASK_GRSCEN) + p_Dtsec->f_Exception(p_Dtsec->h_App, e_FM_MAC_EX_1G_GRATEFUL_RX_STP_COMPLET); + if (event & DTSEC_IMASK_TDPEEN) + p_Dtsec->f_Exception(p_Dtsec->h_App, e_FM_MAC_EX_1G_TX_DATA_ERR); + if (event & DTSEC_IMASK_RDPEEN) + p_Dtsec->f_Exception(p_Dtsec->h_App, e_FM_MAC_EX_1G_RX_DATA_ERR); + + /* - masked interrupts */ + ASSERT_COND(!(event & DTSEC_IMASK_ABRTEN)); + ASSERT_COND(!(event & DTSEC_IMASK_IFERREN)); +} + +static void DtsecMdioIsr(t_Handle h_Dtsec) +{ + t_Dtsec *p_Dtsec = (t_Dtsec *)h_Dtsec; + uint32_t event; + struct dtsec_regs *p_DtsecMemMap = p_Dtsec->p_MemMap; + + event = GET_UINT32(p_DtsecMemMap->ievent); + /* handle only MDIO events */ + event &= (DTSEC_IMASK_MMRDEN | DTSEC_IMASK_MMWREN); + if (event) + { + event &= GET_UINT32(p_DtsecMemMap->imask); + + WRITE_UINT32(p_DtsecMemMap->ievent, event); + + if (event & DTSEC_IMASK_MMRDEN) + p_Dtsec->f_Event(p_Dtsec->h_App, e_FM_MAC_EX_1G_MII_MNG_RD_COMPLET); + if (event & DTSEC_IMASK_MMWREN) + p_Dtsec->f_Event(p_Dtsec->h_App, e_FM_MAC_EX_1G_MII_MNG_WR_COMPLET); + } +} + +static void Dtsec1588Isr(t_Handle h_Dtsec) +{ + t_Dtsec *p_Dtsec = (t_Dtsec *)h_Dtsec; + uint32_t event; + struct dtsec_regs *p_DtsecMemMap = p_Dtsec->p_MemMap; + + if (p_Dtsec->ptpTsuEnabled) + { + event = dtsec_check_and_clear_tmr_event(p_DtsecMemMap); + + if (event) + { + ASSERT_COND(event & TMR_PEVENT_TSRE); + p_Dtsec->f_Exception(p_Dtsec->h_App, e_FM_MAC_EX_1G_1588_TS_RX_ERR); + } + } +} + +/* ........................................................................... */ + +static void FreeInitResources(t_Dtsec *p_Dtsec) +{ + /*TODO - need to ask why with mdioIrq != 0*/ + if ((p_Dtsec->mdioIrq != 0) && (p_Dtsec->mdioIrq != NO_IRQ)) + { + XX_DisableIntr(p_Dtsec->mdioIrq); + XX_FreeIntr(p_Dtsec->mdioIrq); + } + FmUnregisterIntr(p_Dtsec->fmMacControllerDriver.h_Fm, e_FM_MOD_1G_MAC, p_Dtsec->macId, e_FM_INTR_TYPE_ERR); + FmUnregisterIntr(p_Dtsec->fmMacControllerDriver.h_Fm, e_FM_MOD_1G_MAC, p_Dtsec->macId, e_FM_INTR_TYPE_NORMAL); + + /* release the driver's group hash table */ + FreeHashTable(p_Dtsec->p_MulticastAddrHash); + p_Dtsec->p_MulticastAddrHash = NULL; + + /* release the driver's individual hash table */ + FreeHashTable(p_Dtsec->p_UnicastAddrHash); + p_Dtsec->p_UnicastAddrHash = NULL; +} + +/* ........................................................................... */ + +static t_Error GracefulStop(t_Dtsec *p_Dtsec, e_CommMode mode) +{ + struct dtsec_regs *p_MemMap; + + ASSERT_COND(p_Dtsec); + + p_MemMap = p_Dtsec->p_MemMap; + ASSERT_COND(p_MemMap); + + /* Assert the graceful transmit stop bit */ + if (mode & e_COMM_MODE_RX) + { + dtsec_stop_rx(p_MemMap); + +#ifdef FM_GRS_ERRATA_DTSEC_A002 + if (p_Dtsec->fmMacControllerDriver.fmRevInfo.majorRev == 2) + XX_UDelay(100); +#else /* FM_GRS_ERRATA_DTSEC_A002 */ +#ifdef FM_GTS_AFTER_DROPPED_FRAME_ERRATA_DTSEC_A004839 + XX_UDelay(10); +#endif /* FM_GTS_AFTER_DROPPED_FRAME_ERRATA_DTSEC_A004839 */ +#endif /* FM_GRS_ERRATA_DTSEC_A002 */ + } + + if (mode & e_COMM_MODE_TX) +#if defined(FM_GTS_ERRATA_DTSEC_A004) || defined(FM_GTS_AFTER_MAC_ABORTED_FRAME_ERRATA_DTSEC_A0012) + if (p_Dtsec->fmMacControllerDriver.fmRevInfo.majorRev == 2) + DBG(INFO, ("GTS not supported due to DTSEC_A004 errata.")); +#else /* not defined(FM_GTS_ERRATA_DTSEC_A004) ||... */ +#ifdef FM_GTS_UNDERRUN_ERRATA_DTSEC_A0014 + DBG(INFO, ("GTS not supported due to DTSEC_A0014 errata.")); +#else /* FM_GTS_UNDERRUN_ERRATA_DTSEC_A0014 */ + dtsec_stop_tx(p_MemMap); +#endif /* FM_GTS_UNDERRUN_ERRATA_DTSEC_A0014 */ +#endif /* defined(FM_GTS_ERRATA_DTSEC_A004) ||... */ + + return E_OK; +} + +/* .............................................................................. */ + +static t_Error GracefulRestart(t_Dtsec *p_Dtsec, e_CommMode mode) +{ + struct dtsec_regs *p_MemMap; + + ASSERT_COND(p_Dtsec); + p_MemMap = p_Dtsec->p_MemMap; + ASSERT_COND(p_MemMap); + + /* clear the graceful receive stop bit */ + if (mode & e_COMM_MODE_TX) + dtsec_start_tx(p_MemMap); + + if (mode & e_COMM_MODE_RX) + dtsec_start_rx(p_MemMap); + + return E_OK; +} + + +/*****************************************************************************/ +/* dTSEC Configs modification functions */ +/*****************************************************************************/ + + +/* .............................................................................. */ + +static t_Error DtsecConfigLoopback(t_Handle h_Dtsec, bool newVal) +{ + + t_Dtsec *p_Dtsec = (t_Dtsec *)h_Dtsec; + + SANITY_CHECK_RETURN_ERROR(p_Dtsec, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_Dtsec->p_DtsecDriverParam, E_INVALID_STATE); + + p_Dtsec->p_DtsecDriverParam->loopback = newVal; + + return E_OK; +} + +/* .............................................................................. */ + +static t_Error DtsecConfigMaxFrameLength(t_Handle h_Dtsec, uint16_t newVal) +{ + t_Dtsec *p_Dtsec = (t_Dtsec *)h_Dtsec; + + SANITY_CHECK_RETURN_ERROR(p_Dtsec, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_Dtsec->p_DtsecDriverParam, E_INVALID_STATE); + + p_Dtsec->p_DtsecDriverParam->maximum_frame = newVal; + + return E_OK; +} + +/* .............................................................................. */ + +static t_Error DtsecConfigPadAndCrc(t_Handle h_Dtsec, bool newVal) +{ + t_Dtsec *p_Dtsec = (t_Dtsec *)h_Dtsec; + + SANITY_CHECK_RETURN_ERROR(p_Dtsec, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_Dtsec->p_DtsecDriverParam, E_INVALID_STATE); + + p_Dtsec->p_DtsecDriverParam->tx_pad_crc = newVal; + + return E_OK; +} + +/* .............................................................................. */ + +static t_Error DtsecConfigHalfDuplex(t_Handle h_Dtsec, bool newVal) +{ + t_Dtsec *p_Dtsec = (t_Dtsec *)h_Dtsec; + + SANITY_CHECK_RETURN_ERROR(p_Dtsec, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_Dtsec->p_DtsecDriverParam, E_INVALID_STATE); + + p_Dtsec->p_DtsecDriverParam->halfdup_on = newVal; + + return E_OK; +} + +/* .............................................................................. */ + +static t_Error DtsecConfigTbiPhyAddr(t_Handle h_Dtsec, uint8_t newVal) +{ + t_Dtsec *p_Dtsec = (t_Dtsec *)h_Dtsec; + + SANITY_CHECK_RETURN_ERROR(p_Dtsec, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_Dtsec->p_DtsecDriverParam, E_INVALID_STATE); + + p_Dtsec->p_DtsecDriverParam->tbi_phy_addr = newVal; + + return E_OK; +} + +/* .............................................................................. */ + +static t_Error DtsecConfigLengthCheck(t_Handle h_Dtsec, bool newVal) +{ + t_Dtsec *p_Dtsec = (t_Dtsec *)h_Dtsec; + + SANITY_CHECK_RETURN_ERROR(p_Dtsec, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_Dtsec->p_DtsecDriverParam, E_INVALID_STATE); + + p_Dtsec->p_DtsecDriverParam->rx_len_check = newVal; + + return E_OK; +} + +static t_Error DtsecConfigException(t_Handle h_Dtsec, e_FmMacExceptions exception, bool enable) +{ + t_Dtsec *p_Dtsec = (t_Dtsec *)h_Dtsec; + uint32_t bitMask = 0; + + SANITY_CHECK_RETURN_ERROR(p_Dtsec, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_Dtsec->p_DtsecDriverParam, E_INVALID_STATE); + + if (exception != e_FM_MAC_EX_1G_1588_TS_RX_ERR) + { + GET_EXCEPTION_FLAG(bitMask, exception); + if (bitMask) + { + if (enable) + p_Dtsec->exceptions |= bitMask; + else + p_Dtsec->exceptions &= ~bitMask; + } + else + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("Undefined exception")); + } + else + { + if (!p_Dtsec->ptpTsuEnabled) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("Exception valid for 1588 only")); + switch (exception){ + case (e_FM_MAC_EX_1G_1588_TS_RX_ERR): + if (enable) + p_Dtsec->enTsuErrExeption = TRUE; + else + p_Dtsec->enTsuErrExeption = FALSE; + break; + default: + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("Undefined exception")); + } + } + return E_OK; +} +/*****************************************************************************/ +/* dTSEC Run Time API functions */ +/*****************************************************************************/ + +/* .............................................................................. */ + +static t_Error DtsecEnable(t_Handle h_Dtsec, e_CommMode mode) +{ + t_Dtsec *p_Dtsec = (t_Dtsec *)h_Dtsec; + + SANITY_CHECK_RETURN_ERROR(p_Dtsec, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(!p_Dtsec->p_DtsecDriverParam, E_INVALID_STATE); + + dtsec_enable(p_Dtsec->p_MemMap, + (bool)!!(mode & e_COMM_MODE_RX), + (bool)!!(mode & e_COMM_MODE_TX)); + + GracefulRestart(p_Dtsec, mode); + + return E_OK; +} + +/* .............................................................................. */ + +static t_Error DtsecDisable (t_Handle h_Dtsec, e_CommMode mode) +{ + t_Dtsec *p_Dtsec = (t_Dtsec *)h_Dtsec; + + SANITY_CHECK_RETURN_ERROR(p_Dtsec, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(!p_Dtsec->p_DtsecDriverParam, E_INVALID_STATE); + + GracefulStop(p_Dtsec, mode); + + dtsec_disable(p_Dtsec->p_MemMap, + (bool)!!(mode & e_COMM_MODE_RX), + (bool)!!(mode & e_COMM_MODE_TX)); + + return E_OK; +} + +/* .............................................................................. */ + +static t_Error DtsecSetTxPauseFrames(t_Handle h_Dtsec, + uint8_t priority, + uint16_t pauseTime, + uint16_t threshTime) +{ + t_Dtsec *p_Dtsec = (t_Dtsec *)h_Dtsec; + + UNUSED(priority);UNUSED(threshTime); + + SANITY_CHECK_RETURN_ERROR(p_Dtsec, E_INVALID_STATE); + SANITY_CHECK_RETURN_ERROR(!p_Dtsec->p_DtsecDriverParam, E_INVALID_STATE); + +#ifdef FM_BAD_TX_TS_IN_B_2_B_ERRATA_DTSEC_A003 + if (p_Dtsec->fmMacControllerDriver.fmRevInfo.majorRev == 2) + if (pauseTime <= 320) + RETURN_ERROR(MINOR, E_INVALID_VALUE, + ("This pause-time value of %d is illegal due to errata dTSEC-A003!" + " value should be greater than 320.")); +#endif /* FM_BAD_TX_TS_IN_B_2_B_ERRATA_DTSEC_A003 */ + + dtsec_set_tx_pause_time(p_Dtsec->p_MemMap, pauseTime); + return E_OK; +} + +/* .............................................................................. */ +/* backward compatibility. will be removed in the future. */ +static t_Error DtsecTxMacPause(t_Handle h_Dtsec, uint16_t pauseTime) +{ + return DtsecSetTxPauseFrames(h_Dtsec, 0, pauseTime, 0); +} + +/* .............................................................................. */ + +static t_Error DtsecRxIgnoreMacPause(t_Handle h_Dtsec, bool en) +{ + t_Dtsec *p_Dtsec = (t_Dtsec *)h_Dtsec; + bool accept_pause = !en; + + SANITY_CHECK_RETURN_ERROR(p_Dtsec, E_INVALID_STATE); + SANITY_CHECK_RETURN_ERROR(!p_Dtsec->p_DtsecDriverParam, E_INVALID_STATE); + + dtsec_handle_rx_pause(p_Dtsec->p_MemMap, accept_pause); + + return E_OK; +} + +/* .............................................................................. */ + +static t_Error DtsecEnable1588TimeStamp(t_Handle h_Dtsec) +{ + t_Dtsec *p_Dtsec = (t_Dtsec *)h_Dtsec; + + SANITY_CHECK_RETURN_ERROR(p_Dtsec, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(!p_Dtsec->p_DtsecDriverParam, E_INVALID_STATE); + + p_Dtsec->ptpTsuEnabled = TRUE; + dtsec_set_ts(p_Dtsec->p_MemMap, TRUE); + + return E_OK; +} + +/* .............................................................................. */ + +static t_Error DtsecDisable1588TimeStamp(t_Handle h_Dtsec) +{ + t_Dtsec *p_Dtsec = (t_Dtsec *)h_Dtsec; + + SANITY_CHECK_RETURN_ERROR(p_Dtsec, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(!p_Dtsec->p_DtsecDriverParam, E_INVALID_STATE); + + p_Dtsec->ptpTsuEnabled = FALSE; + dtsec_set_ts(p_Dtsec->p_MemMap, FALSE); + + return E_OK; +} + +/* .............................................................................. */ + +static t_Error DtsecGetStatistics(t_Handle h_Dtsec, t_FmMacStatistics *p_Statistics) +{ + t_Dtsec *p_Dtsec = (t_Dtsec *)h_Dtsec; + struct dtsec_regs *p_DtsecMemMap; + + SANITY_CHECK_RETURN_ERROR(p_Dtsec, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(!p_Dtsec->p_DtsecDriverParam, E_INVALID_STATE); + SANITY_CHECK_RETURN_ERROR(p_Statistics, E_NULL_POINTER); + + p_DtsecMemMap = p_Dtsec->p_MemMap; + + if (p_Dtsec->statisticsLevel == e_FM_MAC_NONE_STATISTICS) + RETURN_ERROR(MINOR, E_INVALID_STATE, ("Statistics disabled")); + + memset(p_Statistics, 0xff, sizeof(t_FmMacStatistics)); + + if (p_Dtsec->statisticsLevel == e_FM_MAC_FULL_STATISTICS) + { + p_Statistics->eStatPkts64 = dtsec_get_stat_counter(p_DtsecMemMap, E_DTSEC_STAT_TR64) + + p_Dtsec->internalStatistics.tr64; + p_Statistics->eStatPkts65to127 = dtsec_get_stat_counter(p_DtsecMemMap, E_DTSEC_STAT_TR127) + + p_Dtsec->internalStatistics.tr127; + p_Statistics->eStatPkts128to255 = dtsec_get_stat_counter(p_DtsecMemMap, E_DTSEC_STAT_TR255) + + p_Dtsec->internalStatistics.tr255; + p_Statistics->eStatPkts256to511 = dtsec_get_stat_counter(p_DtsecMemMap, E_DTSEC_STAT_TR511) + + p_Dtsec->internalStatistics.tr511; + p_Statistics->eStatPkts512to1023 = dtsec_get_stat_counter(p_DtsecMemMap, E_DTSEC_STAT_TR1K) + + p_Dtsec->internalStatistics.tr1k; + p_Statistics->eStatPkts1024to1518 = dtsec_get_stat_counter(p_DtsecMemMap, E_DTSEC_STAT_TRMAX) + + p_Dtsec->internalStatistics.trmax; + p_Statistics->eStatPkts1519to1522 = dtsec_get_stat_counter(p_DtsecMemMap, E_DTSEC_STAT_TRMGV) + + p_Dtsec->internalStatistics.trmgv; + + /* MIB II */ + p_Statistics->ifInOctets = dtsec_get_stat_counter(p_DtsecMemMap, E_DTSEC_STAT_RBYT) + + p_Dtsec->internalStatistics.rbyt; + p_Statistics->ifInPkts = dtsec_get_stat_counter(p_DtsecMemMap, E_DTSEC_STAT_RPKT) + + p_Dtsec->internalStatistics.rpkt; + p_Statistics->ifInUcastPkts = 0; + p_Statistics->ifInMcastPkts = dtsec_get_stat_counter(p_DtsecMemMap, E_DTSEC_STAT_RMCA) + + p_Dtsec->internalStatistics.rmca; + p_Statistics->ifInBcastPkts = dtsec_get_stat_counter(p_DtsecMemMap, E_DTSEC_STAT_RBCA) + + p_Dtsec->internalStatistics.rbca; + p_Statistics->ifOutOctets = dtsec_get_stat_counter(p_DtsecMemMap, E_DTSEC_STAT_TBYT) + + p_Dtsec->internalStatistics.tbyt; + p_Statistics->ifOutPkts = dtsec_get_stat_counter(p_DtsecMemMap, E_DTSEC_STAT_TPKT) + + p_Dtsec->internalStatistics.tpkt; + p_Statistics->ifOutUcastPkts = 0; + p_Statistics->ifOutMcastPkts = dtsec_get_stat_counter(p_DtsecMemMap, E_DTSEC_STAT_TMCA) + + p_Dtsec->internalStatistics.tmca; + p_Statistics->ifOutBcastPkts = dtsec_get_stat_counter(p_DtsecMemMap, E_DTSEC_STAT_TBCA) + + p_Dtsec->internalStatistics.tbca; + } + + p_Statistics->eStatFragments = dtsec_get_stat_counter(p_DtsecMemMap, E_DTSEC_STAT_RFRG) + + p_Dtsec->internalStatistics.rfrg; + p_Statistics->eStatJabbers = dtsec_get_stat_counter(p_DtsecMemMap, E_DTSEC_STAT_RJBR) + + p_Dtsec->internalStatistics.rjbr; + p_Statistics->eStatsDropEvents = dtsec_get_stat_counter(p_DtsecMemMap, E_DTSEC_STAT_RDRP) + + p_Dtsec->internalStatistics.rdrp; + p_Statistics->eStatCRCAlignErrors = dtsec_get_stat_counter(p_DtsecMemMap, E_DTSEC_STAT_RALN) + + p_Dtsec->internalStatistics.raln; + p_Statistics->eStatUndersizePkts = dtsec_get_stat_counter(p_DtsecMemMap, E_DTSEC_STAT_RUND) + + p_Dtsec->internalStatistics.rund; + p_Statistics->eStatOversizePkts = dtsec_get_stat_counter(p_DtsecMemMap, E_DTSEC_STAT_ROVR) + + p_Dtsec->internalStatistics.rovr; + p_Statistics->reStatPause = dtsec_get_stat_counter(p_DtsecMemMap, E_DTSEC_STAT_RXPF) + + p_Dtsec->internalStatistics.rxpf; + p_Statistics->teStatPause = dtsec_get_stat_counter(p_DtsecMemMap, E_DTSEC_STAT_TXPF) + + p_Dtsec->internalStatistics.txpf; + p_Statistics->ifInDiscards = p_Statistics->eStatsDropEvents; + p_Statistics->ifInErrors = p_Statistics->eStatsDropEvents + p_Statistics->eStatCRCAlignErrors + + dtsec_get_stat_counter(p_DtsecMemMap,E_DTSEC_STAT_RFLR) + p_Dtsec->internalStatistics.rflr + + dtsec_get_stat_counter(p_DtsecMemMap,E_DTSEC_STAT_RCDE) + p_Dtsec->internalStatistics.rcde + + dtsec_get_stat_counter(p_DtsecMemMap,E_DTSEC_STAT_RCSE) + p_Dtsec->internalStatistics.rcse; + + p_Statistics->ifOutDiscards = dtsec_get_stat_counter(p_DtsecMemMap, E_DTSEC_STAT_TDRP) + + p_Dtsec->internalStatistics.tdrp; + p_Statistics->ifOutErrors = p_Statistics->ifOutDiscards /**< Number of frames transmitted with error: */ + + dtsec_get_stat_counter(p_DtsecMemMap,E_DTSEC_STAT_TFCS) + + p_Dtsec->internalStatistics.tfcs; + + return E_OK; +} + +/* .............................................................................. */ + +static t_Error DtsecModifyMacAddress (t_Handle h_Dtsec, t_EnetAddr *p_EnetAddr) +{ + t_Dtsec *p_Dtsec = (t_Dtsec *)h_Dtsec; + + SANITY_CHECK_RETURN_ERROR(p_Dtsec, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(!p_Dtsec->p_DtsecDriverParam, E_INVALID_STATE); + + /* Initialize MAC Station Address registers (1 & 2) */ + /* Station address have to be swapped (big endian to little endian */ + p_Dtsec->addr = ENET_ADDR_TO_UINT64(*p_EnetAddr); + dtsec_set_mac_address(p_Dtsec->p_MemMap, (uint8_t *)(*p_EnetAddr)); + + return E_OK; +} + +/* .............................................................................. */ + +static t_Error DtsecResetCounters (t_Handle h_Dtsec) +{ + t_Dtsec *p_Dtsec = (t_Dtsec *)h_Dtsec; + + SANITY_CHECK_RETURN_ERROR(p_Dtsec, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(!p_Dtsec->p_DtsecDriverParam, E_INVALID_STATE); + + /* clear HW counters */ + dtsec_reset_stat(p_Dtsec->p_MemMap); + + /* clear SW counters holding carries */ + memset(&p_Dtsec->internalStatistics, 0, sizeof(t_InternalStatistics)); + + return E_OK; +} + +/* .............................................................................. */ + +static t_Error DtsecAddExactMatchMacAddress(t_Handle h_Dtsec, t_EnetAddr *p_EthAddr) +{ + t_Dtsec *p_Dtsec = (t_Dtsec *) h_Dtsec; + uint64_t ethAddr; + uint8_t paddrNum; + + SANITY_CHECK_RETURN_ERROR(p_Dtsec, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(!p_Dtsec->p_DtsecDriverParam, E_INVALID_STATE); + + ethAddr = ENET_ADDR_TO_UINT64(*p_EthAddr); + + if (ethAddr & GROUP_ADDRESS) + /* Multicast address has no effect in PADDR */ + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("Multicast address")); + + /* Make sure no PADDR contains this address */ + for (paddrNum = 0; paddrNum < DTSEC_NUM_OF_PADDRS; paddrNum++) + if (p_Dtsec->indAddrRegUsed[paddrNum]) + if (p_Dtsec->paddr[paddrNum] == ethAddr) + RETURN_ERROR(MAJOR, E_ALREADY_EXISTS, NO_MSG); + + /* Find first unused PADDR */ + for (paddrNum = 0; paddrNum < DTSEC_NUM_OF_PADDRS; paddrNum++) + if (!(p_Dtsec->indAddrRegUsed[paddrNum])) + { + /* mark this PADDR as used */ + p_Dtsec->indAddrRegUsed[paddrNum] = TRUE; + /* store address */ + p_Dtsec->paddr[paddrNum] = ethAddr; + + /* put in hardware */ + dtsec_add_addr_in_paddr(p_Dtsec->p_MemMap, (uint64_t)PTR_TO_UINT(ðAddr), paddrNum); + p_Dtsec->numOfIndAddrInRegs++; + + return E_OK; + } + + /* No free PADDR */ + RETURN_ERROR(MAJOR, E_FULL, NO_MSG); +} + +/* .............................................................................. */ + +static t_Error DtsecDelExactMatchMacAddress(t_Handle h_Dtsec, t_EnetAddr *p_EthAddr) +{ + t_Dtsec *p_Dtsec = (t_Dtsec *) h_Dtsec; + uint64_t ethAddr; + uint8_t paddrNum; + + SANITY_CHECK_RETURN_ERROR(p_Dtsec, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(!p_Dtsec->p_DtsecDriverParam, E_INVALID_STATE); + + ethAddr = ENET_ADDR_TO_UINT64(*p_EthAddr); + + /* Find used PADDR containing this address */ + for (paddrNum = 0; paddrNum < DTSEC_NUM_OF_PADDRS; paddrNum++) + { + if ((p_Dtsec->indAddrRegUsed[paddrNum]) && + (p_Dtsec->paddr[paddrNum] == ethAddr)) + { + /* mark this PADDR as not used */ + p_Dtsec->indAddrRegUsed[paddrNum] = FALSE; + /* clear in hardware */ + dtsec_clear_addr_in_paddr(p_Dtsec->p_MemMap, paddrNum); + p_Dtsec->numOfIndAddrInRegs--; + + return E_OK; + } + } + + RETURN_ERROR(MAJOR, E_NOT_FOUND, NO_MSG); +} + +/* .............................................................................. */ + +static t_Error DtsecAddHashMacAddress(t_Handle h_Dtsec, t_EnetAddr *p_EthAddr) +{ + t_Dtsec *p_Dtsec = (t_Dtsec *)h_Dtsec; + t_EthHashEntry *p_HashEntry; + uint64_t ethAddr; + int32_t bucket; + uint32_t crc; + bool mcast, ghtx; + + SANITY_CHECK_RETURN_ERROR(p_Dtsec, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(!p_Dtsec->p_DtsecDriverParam, E_INVALID_STATE); + + ethAddr = ENET_ADDR_TO_UINT64(*p_EthAddr); + + ghtx = (bool)((dtsec_get_rctrl(p_Dtsec->p_MemMap) & RCTRL_GHTX) ? TRUE : FALSE); + mcast = (bool)((ethAddr & MAC_GROUP_ADDRESS) ? TRUE : FALSE); + + if (ghtx && !mcast) /* Cannot handle unicast mac addr when GHTX is on */ + RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Could not compute hash bucket")); + + crc = GetMacAddrHashCode(ethAddr); + + /* considering the 9 highest order bits in crc H[8:0]: + * if ghtx = 0 H[8:6] (highest order 3 bits) identify the hash register + * and H[5:1] (next 5 bits) identify the hash bit + * if ghts = 1 H[8:5] (highest order 4 bits) identify the hash register + * and H[4:0] (next 5 bits) identify the hash bit. + * + * In bucket index output the low 5 bits identify the hash register bit, + * while the higher 4 bits identify the hash register + */ + + if (ghtx) + bucket = (int32_t)((crc >> 23) & 0x1ff); + else { + bucket = (int32_t)((crc >> 24) & 0xff); + /* if !ghtx and mcast the bit must be set in gaddr instead of igaddr. */ + if (mcast) + bucket += 0x100; + } + + dtsec_set_bucket(p_Dtsec->p_MemMap, bucket, TRUE); + + /* Create element to be added to the driver hash table */ + p_HashEntry = (t_EthHashEntry *)XX_Malloc(sizeof(t_EthHashEntry)); + p_HashEntry->addr = ethAddr; + INIT_LIST(&p_HashEntry->node); + + if (ethAddr & MAC_GROUP_ADDRESS) + /* Group Address */ + LIST_AddToTail(&(p_HashEntry->node), &(p_Dtsec->p_MulticastAddrHash->p_Lsts[bucket])); + else + LIST_AddToTail(&(p_HashEntry->node), &(p_Dtsec->p_UnicastAddrHash->p_Lsts[bucket])); + + return E_OK; +} + +/* .............................................................................. */ + +static t_Error DtsecDelHashMacAddress(t_Handle h_Dtsec, t_EnetAddr *p_EthAddr) +{ + t_Dtsec *p_Dtsec = (t_Dtsec *)h_Dtsec; + t_List *p_Pos; + t_EthHashEntry *p_HashEntry = NULL; + uint64_t ethAddr; + int32_t bucket; + uint32_t crc; + bool mcast, ghtx; + + SANITY_CHECK_RETURN_ERROR(p_Dtsec, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(!p_Dtsec->p_DtsecDriverParam, E_INVALID_STATE); + + ethAddr = ENET_ADDR_TO_UINT64(*p_EthAddr); + + ghtx = (bool)((dtsec_get_rctrl(p_Dtsec->p_MemMap) & RCTRL_GHTX) ? TRUE : FALSE); + mcast = (bool)((ethAddr & MAC_GROUP_ADDRESS) ? TRUE : FALSE); + + if (ghtx && !mcast) /* Cannot handle unicast mac addr when GHTX is on */ + RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Could not compute hash bucket")); + + crc = GetMacAddrHashCode(ethAddr); + + if (ghtx) + bucket = (int32_t)((crc >> 23) & 0x1ff); + else { + bucket = (int32_t)((crc >> 24) & 0xff); + /* if !ghtx and mcast the bit must be set in gaddr instead of igaddr. */ + if (mcast) + bucket += 0x100; + } + + if (ethAddr & MAC_GROUP_ADDRESS) + { + /* Group Address */ + LIST_FOR_EACH(p_Pos, &(p_Dtsec->p_MulticastAddrHash->p_Lsts[bucket])) + { + p_HashEntry = ETH_HASH_ENTRY_OBJ(p_Pos); + if (p_HashEntry->addr == ethAddr) + { + LIST_DelAndInit(&p_HashEntry->node); + XX_Free(p_HashEntry); + break; + } + } + if (LIST_IsEmpty(&p_Dtsec->p_MulticastAddrHash->p_Lsts[bucket])) + dtsec_set_bucket(p_Dtsec->p_MemMap, bucket, FALSE); + } + else + { + /* Individual Address */ + LIST_FOR_EACH(p_Pos, &(p_Dtsec->p_UnicastAddrHash->p_Lsts[bucket])) + { + p_HashEntry = ETH_HASH_ENTRY_OBJ(p_Pos); + if (p_HashEntry->addr == ethAddr) + { + LIST_DelAndInit(&p_HashEntry->node); + XX_Free(p_HashEntry); + break; + } + } + if (LIST_IsEmpty(&p_Dtsec->p_UnicastAddrHash->p_Lsts[bucket])) + dtsec_set_bucket(p_Dtsec->p_MemMap, bucket, FALSE); + } + + /* address does not exist */ + ASSERT_COND(p_HashEntry != NULL); + + return E_OK; +} + +void DtsecRestartTbiAN(t_Handle h_Dtsec) +{ + t_Dtsec *p_Dtsec = (t_Dtsec *)h_Dtsec; + + if (!p_Dtsec) + return; + + DTSEC_MII_WritePhyReg(p_Dtsec, p_Dtsec->tbi_phy_addr, 0, + PHY_CR_ANE | PHY_CR_RESET_AN | PHY_CR_FULLDUPLEX | PHY_CR_SPEED1); +} + +/* .............................................................................. */ + +static t_Error DtsecSetPromiscuous(t_Handle h_Dtsec, bool newVal) +{ + t_Dtsec *p_Dtsec = (t_Dtsec *)h_Dtsec; + + SANITY_CHECK_RETURN_ERROR(p_Dtsec, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(!p_Dtsec->p_DtsecDriverParam, E_INVALID_STATE); + + dtsec_set_uc_promisc(p_Dtsec->p_MemMap, newVal); + dtsec_set_mc_promisc(p_Dtsec->p_MemMap, newVal); + + return E_OK; +} + +/* .............................................................................. */ + +static t_Error DtsecSetStatistics(t_Handle h_Dtsec, e_FmMacStatisticsLevel statisticsLevel) +{ + t_Dtsec *p_Dtsec = (t_Dtsec *)h_Dtsec; + t_Error err; + + SANITY_CHECK_RETURN_ERROR(p_Dtsec, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(!p_Dtsec->p_DtsecDriverParam, E_INVALID_STATE); + + p_Dtsec->statisticsLevel = statisticsLevel; + + err = (t_Error)dtsec_set_stat_level(p_Dtsec->p_MemMap, + (enum mac_stat_level)statisticsLevel); + if (err != E_OK) + return err; + + switch (statisticsLevel) + { + case (e_FM_MAC_NONE_STATISTICS): + p_Dtsec->exceptions &= ~DTSEC_IMASK_MSROEN; + break; + case (e_FM_MAC_PARTIAL_STATISTICS): + p_Dtsec->exceptions |= DTSEC_IMASK_MSROEN; + break; + case (e_FM_MAC_FULL_STATISTICS): + p_Dtsec->exceptions |= DTSEC_IMASK_MSROEN; + break; + default: + RETURN_ERROR(MINOR, E_INVALID_SELECTION, NO_MSG); + } + + return E_OK; +} + +/* .............................................................................. */ + +static t_Error DtsecAdjustLink(t_Handle h_Dtsec, e_EnetSpeed speed, bool fullDuplex) +{ + t_Dtsec *p_Dtsec = (t_Dtsec *)h_Dtsec; + t_Error err; + enum enet_interface enet_interface; + enum enet_speed enet_speed; + + SANITY_CHECK_RETURN_ERROR(p_Dtsec, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(!p_Dtsec->p_DtsecDriverParam, E_INVALID_STATE); + + p_Dtsec->enetMode = MAKE_ENET_MODE(ENET_INTERFACE_FROM_MODE(p_Dtsec->enetMode), speed); + enet_interface = (enum enet_interface) ENET_INTERFACE_FROM_MODE(p_Dtsec->enetMode); + enet_speed = (enum enet_speed) ENET_SPEED_FROM_MODE(p_Dtsec->enetMode); + p_Dtsec->halfDuplex = !fullDuplex; + + err = (t_Error)dtsec_adjust_link(p_Dtsec->p_MemMap, enet_interface, enet_speed, fullDuplex); + + if (err == E_CONFLICT) + RETURN_ERROR(MAJOR, E_CONFLICT, ("Ethernet interface does not support Half Duplex mode")); + + return err; +} + +/* .............................................................................. */ + +static t_Error DtsecRestartAutoneg(t_Handle h_Dtsec) +{ + t_Dtsec *p_Dtsec = (t_Dtsec *)h_Dtsec; + uint16_t tmpReg16; + + SANITY_CHECK_RETURN_ERROR(p_Dtsec, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(!p_Dtsec->p_DtsecDriverParam, E_INVALID_STATE); + + DTSEC_MII_ReadPhyReg(p_Dtsec, p_Dtsec->tbi_phy_addr, 0, &tmpReg16); + tmpReg16 |= (PHY_CR_RESET_AN); + DTSEC_MII_WritePhyReg(p_Dtsec, p_Dtsec->tbi_phy_addr, 0, tmpReg16); + + return E_OK; +} + +/*************************************************************************************/ +/* .............................................................................. */ + +static t_Error DtsecGetId(t_Handle h_Dtsec, uint32_t *macId) +{ + t_Dtsec *p_Dtsec = (t_Dtsec *)h_Dtsec; + + SANITY_CHECK_RETURN_ERROR(p_Dtsec, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(!p_Dtsec->p_DtsecDriverParam, E_INVALID_STATE); + + *macId = p_Dtsec->macId; + + return E_OK; +} + +/* .............................................................................. */ + +static t_Error DtsecGetVersion(t_Handle h_Dtsec, uint32_t *macVersion) +{ + t_Dtsec *p_Dtsec = (t_Dtsec *)h_Dtsec; + + SANITY_CHECK_RETURN_ERROR(p_Dtsec, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(!p_Dtsec->p_DtsecDriverParam, E_INVALID_STATE); + + *macVersion = dtsec_get_revision(p_Dtsec->p_MemMap); + + return E_OK; +} + +/* .............................................................................. */ + +static t_Error DtsecSetException(t_Handle h_Dtsec, e_FmMacExceptions exception, bool enable) +{ + t_Dtsec *p_Dtsec = (t_Dtsec *)h_Dtsec; + uint32_t bitMask = 0; + + SANITY_CHECK_RETURN_ERROR(p_Dtsec, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(!p_Dtsec->p_DtsecDriverParam, E_INVALID_STATE); + + if (exception != e_FM_MAC_EX_1G_1588_TS_RX_ERR) + { + GET_EXCEPTION_FLAG(bitMask, exception); + if (bitMask) + { + if (enable) + p_Dtsec->exceptions |= bitMask; + else + p_Dtsec->exceptions &= ~bitMask; + } + else + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("Undefined exception")); + + if (enable) + dtsec_enable_interrupt(p_Dtsec->p_MemMap, bitMask); + else + dtsec_disable_interrupt(p_Dtsec->p_MemMap, bitMask); + } + else + { + if (!p_Dtsec->ptpTsuEnabled) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("Exception valid for 1588 only")); + switch (exception) + { + case (e_FM_MAC_EX_1G_1588_TS_RX_ERR): + if (enable) + { + p_Dtsec->enTsuErrExeption = TRUE; + dtsec_enable_tmr_interrupt(p_Dtsec->p_MemMap); + } else { + p_Dtsec->enTsuErrExeption = FALSE; + dtsec_disable_tmr_interrupt(p_Dtsec->p_MemMap); + } + break; + default: + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("Undefined exception")); + } + } + + return E_OK; +} + + + +/* ........................................................................... */ + +#if (defined(DEBUG_ERRORS) && (DEBUG_ERRORS > 0)) +static t_Error DtsecDumpRegs(t_Handle h_Dtsec) +{ + t_Dtsec *p_Dtsec = (t_Dtsec *)h_Dtsec; + int i = 0; + + DECLARE_DUMP; + + if (p_Dtsec->p_MemMap) + { + + DUMP_TITLE(p_Dtsec->p_MemMap, ("dTSEC %d: ", p_Dtsec->macId)); + DUMP_VAR(p_Dtsec->p_MemMap, tsec_id); + DUMP_VAR(p_Dtsec->p_MemMap, tsec_id2); + DUMP_VAR(p_Dtsec->p_MemMap, ievent); + DUMP_VAR(p_Dtsec->p_MemMap, imask); + DUMP_VAR(p_Dtsec->p_MemMap, ecntrl); + DUMP_VAR(p_Dtsec->p_MemMap, ptv); + DUMP_VAR(p_Dtsec->p_MemMap, tmr_ctrl); + DUMP_VAR(p_Dtsec->p_MemMap, tmr_pevent); + DUMP_VAR(p_Dtsec->p_MemMap, tmr_pemask); + DUMP_VAR(p_Dtsec->p_MemMap, tctrl); + DUMP_VAR(p_Dtsec->p_MemMap, rctrl); + DUMP_VAR(p_Dtsec->p_MemMap, maccfg1); + DUMP_VAR(p_Dtsec->p_MemMap, maccfg2); + DUMP_VAR(p_Dtsec->p_MemMap, ipgifg); + DUMP_VAR(p_Dtsec->p_MemMap, hafdup); + DUMP_VAR(p_Dtsec->p_MemMap, maxfrm); + + DUMP_VAR(p_Dtsec->p_MemMap, macstnaddr1); + DUMP_VAR(p_Dtsec->p_MemMap, macstnaddr2); + + DUMP_SUBSTRUCT_ARRAY(i, 8) + { + DUMP_VAR(p_Dtsec->p_MemMap, macaddr[i].exact_match1); + DUMP_VAR(p_Dtsec->p_MemMap, macaddr[i].exact_match2); + } + DUMP_VAR(p_Dtsec->p_MemMap, car1); + DUMP_VAR(p_Dtsec->p_MemMap, car2); + } + + return E_OK; +} +#endif /* (defined(DEBUG_ERRORS) && ... */ + + +/*****************************************************************************/ +/* dTSEC Init & Free API */ +/*****************************************************************************/ + +/* .............................................................................. */ + +static t_Error DtsecInit(t_Handle h_Dtsec) +{ + t_Dtsec *p_Dtsec = (t_Dtsec *)h_Dtsec; + struct dtsec_cfg *p_DtsecDriverParam; + t_Error err; + uint16_t maxFrmLn; + enum enet_interface enet_interface; + enum enet_speed enet_speed; + t_EnetAddr ethAddr; + + SANITY_CHECK_RETURN_ERROR(p_Dtsec, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_Dtsec->p_DtsecDriverParam, E_INVALID_STATE); + SANITY_CHECK_RETURN_ERROR(p_Dtsec->fmMacControllerDriver.h_Fm, E_INVALID_HANDLE); + + FM_GetRevision(p_Dtsec->fmMacControllerDriver.h_Fm, &p_Dtsec->fmMacControllerDriver.fmRevInfo); + CHECK_INIT_PARAMETERS(p_Dtsec, CheckInitParameters); + + p_DtsecDriverParam = p_Dtsec->p_DtsecDriverParam; + p_Dtsec->halfDuplex = p_DtsecDriverParam->halfdup_on; + + enet_interface = (enum enet_interface)ENET_INTERFACE_FROM_MODE(p_Dtsec->enetMode); + enet_speed = (enum enet_speed)ENET_SPEED_FROM_MODE(p_Dtsec->enetMode); + MAKE_ENET_ADDR_FROM_UINT64(p_Dtsec->addr, ethAddr); + + err = (t_Error)dtsec_init(p_Dtsec->p_MemMap, + p_DtsecDriverParam, + enet_interface, + enet_speed, + (uint8_t*)ethAddr, + p_Dtsec->fmMacControllerDriver.fmRevInfo.majorRev, + p_Dtsec->fmMacControllerDriver.fmRevInfo.minorRev, + p_Dtsec->exceptions); + if (err) + { + FreeInitResources(p_Dtsec); + RETURN_ERROR(MAJOR, err, ("This DTSEC version does not support the required i/f mode")); + } + + DTSEC_MII_Init(h_Dtsec); + + if (ENET_INTERFACE_FROM_MODE(p_Dtsec->enetMode) == e_ENET_IF_SGMII) + { + uint16_t tmpReg16; + + /* Configure the TBI PHY Control Register */ + tmpReg16 = PHY_TBICON_CLK_SEL | PHY_TBICON_SRESET; + DTSEC_MII_WritePhyReg(p_Dtsec, (uint8_t)p_DtsecDriverParam->tbipa, 17, tmpReg16); + + tmpReg16 = PHY_TBICON_CLK_SEL; + DTSEC_MII_WritePhyReg(p_Dtsec, (uint8_t)p_DtsecDriverParam->tbipa, 17, tmpReg16); + + tmpReg16 = (PHY_CR_PHY_RESET | PHY_CR_ANE | PHY_CR_FULLDUPLEX | PHY_CR_SPEED1); + DTSEC_MII_WritePhyReg(p_Dtsec, (uint8_t)p_DtsecDriverParam->tbipa, 0, tmpReg16); + + if (p_Dtsec->enetMode & ENET_IF_SGMII_BASEX) + tmpReg16 = PHY_TBIANA_1000X; + else + tmpReg16 = PHY_TBIANA_SGMII; + DTSEC_MII_WritePhyReg(p_Dtsec, (uint8_t)p_DtsecDriverParam->tbipa, 4, tmpReg16); + + tmpReg16 = (PHY_CR_ANE | PHY_CR_RESET_AN | PHY_CR_FULLDUPLEX | PHY_CR_SPEED1); + + DTSEC_MII_WritePhyReg(p_Dtsec, (uint8_t)p_DtsecDriverParam->tbipa, 0, tmpReg16); + } + + /* Max Frame Length */ + maxFrmLn = dtsec_get_max_frame_len(p_Dtsec->p_MemMap); + err = FmSetMacMaxFrame(p_Dtsec->fmMacControllerDriver.h_Fm, e_FM_MAC_1G, + p_Dtsec->fmMacControllerDriver.macId, maxFrmLn); + + p_Dtsec->p_MulticastAddrHash = AllocHashTable(EXTENDED_HASH_TABLE_SIZE); + if (!p_Dtsec->p_MulticastAddrHash) { + FreeInitResources(p_Dtsec); + RETURN_ERROR(MAJOR, E_NO_MEMORY, ("MC hash table is FAILED")); + } + + p_Dtsec->p_UnicastAddrHash = AllocHashTable(HASH_TABLE_SIZE); + if (!p_Dtsec->p_UnicastAddrHash) + { + FreeInitResources(p_Dtsec); + RETURN_ERROR(MAJOR, E_NO_MEMORY, ("UC hash table is FAILED")); + } + + /* register err intr handler for dtsec to FPM (err)*/ + FmRegisterIntr(p_Dtsec->fmMacControllerDriver.h_Fm, + e_FM_MOD_1G_MAC, + p_Dtsec->macId, + e_FM_INTR_TYPE_ERR, + DtsecIsr, + p_Dtsec); + /* register 1588 intr handler for TMR to FPM (normal)*/ + FmRegisterIntr(p_Dtsec->fmMacControllerDriver.h_Fm, + e_FM_MOD_1G_MAC, + p_Dtsec->macId, + e_FM_INTR_TYPE_NORMAL, + Dtsec1588Isr, + p_Dtsec); + /* register normal intr handler for dtsec to main interrupt controller. */ + if (p_Dtsec->mdioIrq != NO_IRQ) + { + XX_SetIntr(p_Dtsec->mdioIrq, DtsecMdioIsr, p_Dtsec); + XX_EnableIntr(p_Dtsec->mdioIrq); + } + + XX_Free(p_DtsecDriverParam); + p_Dtsec->p_DtsecDriverParam = NULL; + + err = DtsecSetStatistics(h_Dtsec, e_FM_MAC_FULL_STATISTICS); + if (err) + { + FreeInitResources(p_Dtsec); + RETURN_ERROR(MAJOR, err, ("Undefined statistics level")); + } + + return E_OK; +} + +/* ........................................................................... */ + +static t_Error DtsecFree(t_Handle h_Dtsec) +{ + t_Dtsec *p_Dtsec = (t_Dtsec *)h_Dtsec; + + SANITY_CHECK_RETURN_ERROR(p_Dtsec, E_INVALID_HANDLE); + + FreeInitResources(p_Dtsec); + + if (p_Dtsec->p_DtsecDriverParam) + { + XX_Free(p_Dtsec->p_DtsecDriverParam); + p_Dtsec->p_DtsecDriverParam = NULL; + } + XX_Free (h_Dtsec); + + return E_OK; +} + +/* .............................................................................. */ + +static void InitFmMacControllerDriver(t_FmMacControllerDriver *p_FmMacControllerDriver) +{ + p_FmMacControllerDriver->f_FM_MAC_Init = DtsecInit; + p_FmMacControllerDriver->f_FM_MAC_Free = DtsecFree; + + p_FmMacControllerDriver->f_FM_MAC_SetStatistics = DtsecSetStatistics; + p_FmMacControllerDriver->f_FM_MAC_ConfigLoopback = DtsecConfigLoopback; + p_FmMacControllerDriver->f_FM_MAC_ConfigMaxFrameLength = DtsecConfigMaxFrameLength; + + p_FmMacControllerDriver->f_FM_MAC_ConfigWan = NULL; /* Not supported on dTSEC */ + + p_FmMacControllerDriver->f_FM_MAC_ConfigPadAndCrc = DtsecConfigPadAndCrc; + p_FmMacControllerDriver->f_FM_MAC_ConfigHalfDuplex = DtsecConfigHalfDuplex; + p_FmMacControllerDriver->f_FM_MAC_ConfigLengthCheck = DtsecConfigLengthCheck; + p_FmMacControllerDriver->f_FM_MAC_ConfigTbiPhyAddr = DtsecConfigTbiPhyAddr; + p_FmMacControllerDriver->f_FM_MAC_ConfigException = DtsecConfigException; + p_FmMacControllerDriver->f_FM_MAC_ConfigResetOnInit = NULL; + + p_FmMacControllerDriver->f_FM_MAC_Enable = DtsecEnable; + p_FmMacControllerDriver->f_FM_MAC_Disable = DtsecDisable; + + p_FmMacControllerDriver->f_FM_MAC_SetException = DtsecSetException; + + p_FmMacControllerDriver->f_FM_MAC_SetPromiscuous = DtsecSetPromiscuous; + p_FmMacControllerDriver->f_FM_MAC_AdjustLink = DtsecAdjustLink; + p_FmMacControllerDriver->f_FM_MAC_RestartAutoneg = DtsecRestartAutoneg; + + p_FmMacControllerDriver->f_FM_MAC_Enable1588TimeStamp = DtsecEnable1588TimeStamp; + p_FmMacControllerDriver->f_FM_MAC_Disable1588TimeStamp = DtsecDisable1588TimeStamp; + + p_FmMacControllerDriver->f_FM_MAC_SetTxAutoPauseFrames = DtsecTxMacPause; + p_FmMacControllerDriver->f_FM_MAC_SetTxPauseFrames = DtsecSetTxPauseFrames; + p_FmMacControllerDriver->f_FM_MAC_SetRxIgnorePauseFrames = DtsecRxIgnoreMacPause; + + p_FmMacControllerDriver->f_FM_MAC_ResetCounters = DtsecResetCounters; + p_FmMacControllerDriver->f_FM_MAC_GetStatistics = DtsecGetStatistics; + + p_FmMacControllerDriver->f_FM_MAC_ModifyMacAddr = DtsecModifyMacAddress; + p_FmMacControllerDriver->f_FM_MAC_AddHashMacAddr = DtsecAddHashMacAddress; + p_FmMacControllerDriver->f_FM_MAC_RemoveHashMacAddr = DtsecDelHashMacAddress; + p_FmMacControllerDriver->f_FM_MAC_AddExactMatchMacAddr = DtsecAddExactMatchMacAddress; + p_FmMacControllerDriver->f_FM_MAC_RemovelExactMatchMacAddr = DtsecDelExactMatchMacAddress; + p_FmMacControllerDriver->f_FM_MAC_GetId = DtsecGetId; + p_FmMacControllerDriver->f_FM_MAC_GetVersion = DtsecGetVersion; + p_FmMacControllerDriver->f_FM_MAC_GetMaxFrameLength = DtsecGetMaxFrameLength; + + p_FmMacControllerDriver->f_FM_MAC_MII_WritePhyReg = DTSEC_MII_WritePhyReg; + p_FmMacControllerDriver->f_FM_MAC_MII_ReadPhyReg = DTSEC_MII_ReadPhyReg; + +#if (defined(DEBUG_ERRORS) && (DEBUG_ERRORS > 0)) + p_FmMacControllerDriver->f_FM_MAC_DumpRegs = DtsecDumpRegs; +#endif /* (defined(DEBUG_ERRORS) && ... */ +} + + +/*****************************************************************************/ +/* dTSEC Config Main Entry */ +/*****************************************************************************/ + +/* .............................................................................. */ + +t_Handle DTSEC_Config(t_FmMacParams *p_FmMacParam) +{ + t_Dtsec *p_Dtsec; + struct dtsec_cfg *p_DtsecDriverParam; + uintptr_t baseAddr; + + SANITY_CHECK_RETURN_VALUE(p_FmMacParam, E_NULL_POINTER, NULL); + + baseAddr = p_FmMacParam->baseAddr; + + /* allocate memory for the UCC GETH data structure. */ + p_Dtsec = (t_Dtsec *)XX_Malloc(sizeof(t_Dtsec)); + if (!p_Dtsec) + { + REPORT_ERROR(MAJOR, E_NO_MEMORY, ("dTSEC driver structure")); + return NULL; + } + memset(p_Dtsec, 0, sizeof(t_Dtsec)); + InitFmMacControllerDriver(&p_Dtsec->fmMacControllerDriver); + + /* allocate memory for the dTSEC driver parameters data structure. */ + p_DtsecDriverParam = (struct dtsec_cfg *) XX_Malloc(sizeof(struct dtsec_cfg)); + if (!p_DtsecDriverParam) + { + XX_Free(p_Dtsec); + REPORT_ERROR(MAJOR, E_NO_MEMORY, ("dTSEC driver parameters")); + return NULL; + } + memset(p_DtsecDriverParam, 0, sizeof(struct dtsec_cfg)); + + /* Plant parameter structure pointer */ + p_Dtsec->p_DtsecDriverParam = p_DtsecDriverParam; + + dtsec_defconfig(p_DtsecDriverParam); + + p_Dtsec->p_MemMap = (struct dtsec_regs *)UINT_TO_PTR(baseAddr); + p_Dtsec->p_MiiMemMap = (struct dtsec_mii_reg *)UINT_TO_PTR(baseAddr + DTSEC_TO_MII_OFFSET); + p_Dtsec->addr = ENET_ADDR_TO_UINT64(p_FmMacParam->addr); + p_Dtsec->enetMode = p_FmMacParam->enetMode; + p_Dtsec->macId = p_FmMacParam->macId; + p_Dtsec->exceptions = DEFAULT_exceptions; + p_Dtsec->mdioIrq = p_FmMacParam->mdioIrq; + p_Dtsec->f_Exception = p_FmMacParam->f_Exception; + p_Dtsec->f_Event = p_FmMacParam->f_Event; + p_Dtsec->h_App = p_FmMacParam->h_App; + p_Dtsec->ptpTsuEnabled = p_Dtsec->p_DtsecDriverParam->ptp_tsu_en; + p_Dtsec->enTsuErrExeption = p_Dtsec->p_DtsecDriverParam->ptp_exception_en; + p_Dtsec->tbi_phy_addr = p_Dtsec->p_DtsecDriverParam->tbi_phy_addr; + + return p_Dtsec; +} diff --git a/drivers/net/ethernet/freescale/fman/Peripherals/FM/MAC/dtsec.h b/drivers/net/ethernet/freescale/fman/Peripherals/FM/MAC/dtsec.h new file mode 100644 index 0000000..01296dd --- /dev/null +++ b/drivers/net/ethernet/freescale/fman/Peripherals/FM/MAC/dtsec.h @@ -0,0 +1,245 @@ +/* + * Copyright 2008-2012 Freescale Semiconductor Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Freescale Semiconductor nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + +/****************************************************************************** + @File dtsec.h + + @Description FM dTSEC ... +*//***************************************************************************/ +#ifndef __DTSEC_H +#define __DTSEC_H + +#include "std_ext.h" +#include "error_ext.h" +#include "list_ext.h" +#include "enet_ext.h" + +#include "dtsec_mii_acc.h" +#include "fm_mac.h" + + +#define DEFAULT_exceptions \ + ((uint32_t)(DTSEC_IMASK_BREN | \ + DTSEC_IMASK_RXCEN | \ + DTSEC_IMASK_BTEN | \ + DTSEC_IMASK_TXCEN | \ + DTSEC_IMASK_TXEEN | \ + DTSEC_IMASK_ABRTEN | \ + DTSEC_IMASK_LCEN | \ + DTSEC_IMASK_CRLEN | \ + DTSEC_IMASK_XFUNEN | \ + DTSEC_IMASK_IFERREN | \ + DTSEC_IMASK_MAGEN | \ + DTSEC_IMASK_TDPEEN | \ + DTSEC_IMASK_RDPEEN)) + +#define GET_EXCEPTION_FLAG(bitMask, exception) switch (exception){ \ + case e_FM_MAC_EX_1G_BAB_RX: \ + bitMask = DTSEC_IMASK_BREN; break; \ + case e_FM_MAC_EX_1G_RX_CTL: \ + bitMask = DTSEC_IMASK_RXCEN; break; \ + case e_FM_MAC_EX_1G_GRATEFUL_TX_STP_COMPLET: \ + bitMask = DTSEC_IMASK_GTSCEN ; break; \ + case e_FM_MAC_EX_1G_BAB_TX: \ + bitMask = DTSEC_IMASK_BTEN ; break; \ + case e_FM_MAC_EX_1G_TX_CTL: \ + bitMask = DTSEC_IMASK_TXCEN ; break; \ + case e_FM_MAC_EX_1G_TX_ERR: \ + bitMask = DTSEC_IMASK_TXEEN ; break; \ + case e_FM_MAC_EX_1G_LATE_COL: \ + bitMask = DTSEC_IMASK_LCEN ; break; \ + case e_FM_MAC_EX_1G_COL_RET_LMT: \ + bitMask = DTSEC_IMASK_CRLEN ; break; \ + case e_FM_MAC_EX_1G_TX_FIFO_UNDRN: \ + bitMask = DTSEC_IMASK_XFUNEN ; break; \ + case e_FM_MAC_EX_1G_MAG_PCKT: \ + bitMask = DTSEC_IMASK_MAGEN ; break; \ + case e_FM_MAC_EX_1G_MII_MNG_RD_COMPLET: \ + bitMask = DTSEC_IMASK_MMRDEN; break; \ + case e_FM_MAC_EX_1G_MII_MNG_WR_COMPLET: \ + bitMask = DTSEC_IMASK_MMWREN ; break; \ + case e_FM_MAC_EX_1G_GRATEFUL_RX_STP_COMPLET: \ + bitMask = DTSEC_IMASK_GRSCEN; break; \ + case e_FM_MAC_EX_1G_TX_DATA_ERR: \ + bitMask = DTSEC_IMASK_TDPEEN; break; \ + case e_FM_MAC_EX_1G_RX_MIB_CNT_OVFL: \ + bitMask = DTSEC_IMASK_MSROEN ; break; \ + default: bitMask = 0;break;} + + +#define MAX_PACKET_ALIGNMENT 31 +#define MAX_INTER_PACKET_GAP 0x7f +#define MAX_INTER_PALTERNATE_BEB 0x0f +#define MAX_RETRANSMISSION 0x0f +#define MAX_COLLISION_WINDOW 0x03ff + + +/********************* From mac ext ******************************************/ +typedef uint32_t t_ErrorDisable; + +#define ERROR_DISABLE_TRANSMIT 0x00400000 +#define ERROR_DISABLE_LATE_COLLISION 0x00040000 +#define ERROR_DISABLE_COLLISION_RETRY_LIMIT 0x00020000 +#define ERROR_DISABLE_TxFIFO_UNDERRUN 0x00010000 +#define ERROR_DISABLE_TxABORT 0x00008000 +#define ERROR_DISABLE_INTERFACE 0x00004000 +#define ERROR_DISABLE_TxDATA_PARITY 0x00000002 +#define ERROR_DISABLE_RxDATA_PARITY 0x00000001 + +/*****************************************************************************/ +#define DTSEC_NUM_OF_PADDRS 15 /* number of pattern match registers (entries) */ + +#define GROUP_ADDRESS 0x0000010000000000LL /* Group address bit indication */ + +#define HASH_TABLE_SIZE 256 /* Hash table size (= 32 bits * 8 regs) */ + +#define HASH_TABLE_SIZE 256 /* Hash table size (32 bits * 8 regs) */ +#define EXTENDED_HASH_TABLE_SIZE 512 /* Extended Hash table size (32 bits * 16 regs) */ + +#define DTSEC_TO_MII_OFFSET 0x1000 /* number of pattern match registers (entries) */ + +#define MAX_PHYS 32 /* maximum number of phys */ + +#define VAL32BIT 0x100000000LL +#define VAL22BIT 0x00400000 +#define VAL16BIT 0x00010000 +#define VAL12BIT 0x00001000 + +/* PHY Control Register */ +#define PHY_CR_PHY_RESET 0x8000 +#define PHY_CR_LOOPBACK 0x4000 +#define PHY_CR_SPEED0 0x2000 +#define PHY_CR_ANE 0x1000 +#define PHY_CR_RESET_AN 0x0200 +#define PHY_CR_FULLDUPLEX 0x0100 +#define PHY_CR_SPEED1 0x0040 + +#define PHY_TBICON_SRESET 0x8000 +#define PHY_TBICON_CLK_SEL 0x0020 + +#define PHY_TBIANA_SGMII 0x4001 +#define PHY_TBIANA_1000X 0x01a0 + + +/* CAR1/2 bits */ +#define CAR1_TR64 0x80000000 +#define CAR1_TR127 0x40000000 +#define CAR1_TR255 0x20000000 +#define CAR1_TR511 0x10000000 +#define CAR1_TRK1 0x08000000 +#define CAR1_TRMAX 0x04000000 +#define CAR1_TRMGV 0x02000000 + +#define CAR1_RBYT 0x00010000 +#define CAR1_RPKT 0x00008000 +#define CAR1_RMCA 0x00002000 +#define CAR1_RBCA 0x00001000 +#define CAR1_RXPF 0x00000400 +#define CAR1_RALN 0x00000100 +#define CAR1_RFLR 0x00000080 +#define CAR1_RCDE 0x00000040 +#define CAR1_RCSE 0x00000020 +#define CAR1_RUND 0x00000010 +#define CAR1_ROVR 0x00000008 +#define CAR1_RFRG 0x00000004 +#define CAR1_RJBR 0x00000002 +#define CAR1_RDRP 0x00000001 + +#define CAR2_TFCS 0x00040000 +#define CAR2_TBYT 0x00002000 +#define CAR2_TPKT 0x00001000 +#define CAR2_TMCA 0x00000800 +#define CAR2_TBCA 0x00000400 +#define CAR2_TXPF 0x00000200 +#define CAR2_TDRP 0x00000001 + +typedef struct t_InternalStatistics +{ + uint64_t tr64; + uint64_t tr127; + uint64_t tr255; + uint64_t tr511; + uint64_t tr1k; + uint64_t trmax; + uint64_t trmgv; + uint64_t rfrg; + uint64_t rjbr; + uint64_t rdrp; + uint64_t raln; + uint64_t rund; + uint64_t rovr; + uint64_t rxpf; + uint64_t txpf; + uint64_t rbyt; + uint64_t rpkt; + uint64_t rmca; + uint64_t rbca; + uint64_t rflr; + uint64_t rcde; + uint64_t rcse; + uint64_t tbyt; + uint64_t tpkt; + uint64_t tmca; + uint64_t tbca; + uint64_t tdrp; + uint64_t tfcs; +} t_InternalStatistics; + +typedef struct { + t_FmMacControllerDriver fmMacControllerDriver; + t_Handle h_App; /**< Handle to the upper layer application */ + struct dtsec_regs *p_MemMap; /**< pointer to dTSEC memory mapped registers. */ + struct dtsec_mii_reg *p_MiiMemMap; /**< pointer to dTSEC MII memory mapped registers. */ + uint64_t addr; /**< MAC address of device; */ + e_EnetMode enetMode; /**< Ethernet physical interface */ + t_FmMacExceptionCallback *f_Exception; + int mdioIrq; + t_FmMacExceptionCallback *f_Event; + bool indAddrRegUsed[DTSEC_NUM_OF_PADDRS]; /**< Whether a particular individual address recognition register is being used */ + uint64_t paddr[DTSEC_NUM_OF_PADDRS]; /**< MAC address for particular individual address recognition register */ + uint8_t numOfIndAddrInRegs; /**< Number of individual addresses in registers for this station. */ + bool halfDuplex; + t_InternalStatistics internalStatistics; + t_EthHash *p_MulticastAddrHash; /* pointer to driver's global address hash table */ + t_EthHash *p_UnicastAddrHash; /* pointer to driver's individual address hash table */ + uint8_t macId; + uint8_t tbi_phy_addr; + uint32_t exceptions; + bool ptpTsuEnabled; + bool enTsuErrExeption; + e_FmMacStatisticsLevel statisticsLevel; + struct dtsec_cfg *p_DtsecDriverParam; +} t_Dtsec; + + +#endif /* __DTSEC_H */ diff --git a/drivers/net/ethernet/freescale/fman/Peripherals/FM/MAC/dtsec_mii_acc.c b/drivers/net/ethernet/freescale/fman/Peripherals/FM/MAC/dtsec_mii_acc.c new file mode 100644 index 0000000..371e1f9 --- /dev/null +++ b/drivers/net/ethernet/freescale/fman/Peripherals/FM/MAC/dtsec_mii_acc.c @@ -0,0 +1,109 @@ +/* + * Copyright 2008-2012 Freescale Semiconductor Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Freescale Semiconductor nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + +/****************************************************************************** + @File dtsec_mii_acc.c + + @Description FM dtsec MII register access MAC ... +*//***************************************************************************/ + +#include "error_ext.h" +#include "std_ext.h" +#include "fm_mac.h" +#include "dtsec.h" +#include "fsl_fman_dtsec_mii_acc.h" + + +/*****************************************************************************/ +t_Error DTSEC_MII_WritePhyReg(t_Handle h_Dtsec, + uint8_t phyAddr, + uint8_t reg, + uint16_t data) +{ + t_Dtsec *p_Dtsec = (t_Dtsec *)h_Dtsec; + struct dtsec_mii_reg *miiregs; + t_Error err; + + SANITY_CHECK_RETURN_ERROR(p_Dtsec, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_Dtsec->p_MiiMemMap, E_INVALID_HANDLE); + + miiregs = p_Dtsec->p_MiiMemMap; + + err = (t_Error)dtsec_mii_write_reg(miiregs, phyAddr, reg, data); + + return err; +} + +/*****************************************************************************/ +t_Error DTSEC_MII_ReadPhyReg(t_Handle h_Dtsec, + uint8_t phyAddr, + uint8_t reg, + uint16_t *p_Data) +{ + t_Dtsec *p_Dtsec = (t_Dtsec *)h_Dtsec; + struct dtsec_mii_reg *miiregs; + t_Error err; + + SANITY_CHECK_RETURN_ERROR(p_Dtsec, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_Dtsec->p_MiiMemMap, E_INVALID_HANDLE); + + miiregs = p_Dtsec->p_MiiMemMap; + + err = (t_Error)dtsec_mii_read_reg(miiregs, phyAddr, reg, p_Data); + + if (*p_Data == 0xffff) + RETURN_ERROR(MINOR, E_NO_DEVICE, + ("Read wrong data (0xffff): phyAddr 0x%x, reg 0x%x", + phyAddr, reg)); + if (err) + RETURN_ERROR(MINOR, err, NO_MSG); + + return err; +} + +t_Error DTSEC_MII_Init(t_Handle h_Dtsec) +{ + t_Dtsec *p_Dtsec = (t_Dtsec *)h_Dtsec; + struct dtsec_mii_reg *miiregs; + uint16_t dtsec_freq; + + SANITY_CHECK_RETURN_ERROR(p_Dtsec, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_Dtsec->p_MiiMemMap, E_INVALID_HANDLE); + + miiregs = p_Dtsec->p_MiiMemMap; + dtsec_freq = (uint16_t)(p_Dtsec->fmMacControllerDriver.clkFreq >> 1); + + dtsec_mii_init(miiregs, dtsec_freq); + + return E_OK; +} diff --git a/drivers/net/ethernet/freescale/fman/Peripherals/FM/MAC/dtsec_mii_acc.h b/drivers/net/ethernet/freescale/fman/Peripherals/FM/MAC/dtsec_mii_acc.h new file mode 100644 index 0000000..d5dd39a --- /dev/null +++ b/drivers/net/ethernet/freescale/fman/Peripherals/FM/MAC/dtsec_mii_acc.h @@ -0,0 +1,45 @@ +/* + * Copyright 2008-2012 Freescale Semiconductor Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Freescale Semiconductor nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + +#ifndef __DTSEC_MII_ACC_H +#define __DTSEC_MII_ACC_H + +#include "std_ext.h" + + +t_Error DTSEC_MII_WritePhyReg(t_Handle h_Dtsec, uint8_t phyAddr, uint8_t reg, uint16_t data); +t_Error DTSEC_MII_ReadPhyReg(t_Handle h_Dtsec, uint8_t phyAddr, uint8_t reg, uint16_t *p_Data); +t_Error DTSEC_MII_Init(t_Handle h_Dtsec); + + +#endif /* __DTSEC_MII_ACC_H */ diff --git a/drivers/net/ethernet/freescale/fman/Peripherals/FM/MAC/fm_mac.c b/drivers/net/ethernet/freescale/fman/Peripherals/FM/MAC/fm_mac.c new file mode 100644 index 0000000..e2deaa2 --- /dev/null +++ b/drivers/net/ethernet/freescale/fman/Peripherals/FM/MAC/fm_mac.c @@ -0,0 +1,628 @@ +/* + * Copyright 2008-2012 Freescale Semiconductor Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Freescale Semiconductor nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + +/****************************************************************************** + @File fm_mac.c + + @Description FM MAC ... +*//***************************************************************************/ +#include "std_ext.h" +#include "string_ext.h" +#include "sprint_ext.h" +#include "error_ext.h" +#include "fm_ext.h" + +#include "fm_common.h" +#include "fm_mac.h" + + +/* ......................................................................... */ + +t_Handle FM_MAC_Config (t_FmMacParams *p_FmMacParam) +{ + t_FmMacControllerDriver *p_FmMacControllerDriver; + + SANITY_CHECK_RETURN_VALUE(p_FmMacParam, E_INVALID_HANDLE, NULL); + +#if (DPAA_VERSION == 10) + if (ENET_SPEED_FROM_MODE(p_FmMacParam->enetMode) < e_ENET_SPEED_10000) + p_FmMacControllerDriver = (t_FmMacControllerDriver *)DTSEC_Config(p_FmMacParam); + else +#if FM_MAX_NUM_OF_10G_MACS > 0 + p_FmMacControllerDriver = (t_FmMacControllerDriver *)TGEC_Config(p_FmMacParam); +#else + p_FmMacControllerDriver = NULL; +#endif /* FM_MAX_NUM_OF_10G_MACS > 0 */ +#else + p_FmMacControllerDriver = (t_FmMacControllerDriver *)MEMAC_Config(p_FmMacParam); +#endif /* (DPAA_VERSION == 10) */ + + if (!p_FmMacControllerDriver) + return NULL; + + p_FmMacControllerDriver->h_Fm = p_FmMacParam->h_Fm; + p_FmMacControllerDriver->enetMode = p_FmMacParam->enetMode; + p_FmMacControllerDriver->macId = p_FmMacParam->macId; + p_FmMacControllerDriver->resetOnInit = DEFAULT_resetOnInit; + + if ((p_FmMacControllerDriver->clkFreq = FmGetClockFreq(p_FmMacControllerDriver->h_Fm)) == 0) + { + REPORT_ERROR(MAJOR, E_INVALID_STATE, ("Can't get clock for MAC!")); + return NULL; + } + + return (t_Handle)p_FmMacControllerDriver; +} + +/* ......................................................................... */ + +t_Error FM_MAC_Init (t_Handle h_FmMac) +{ + t_FmMacControllerDriver *p_FmMacControllerDriver = (t_FmMacControllerDriver *)h_FmMac; + + SANITY_CHECK_RETURN_ERROR(p_FmMacControllerDriver, E_INVALID_HANDLE); + + if (p_FmMacControllerDriver->resetOnInit && + !p_FmMacControllerDriver->f_FM_MAC_ConfigResetOnInit && + (FmResetMac(p_FmMacControllerDriver->h_Fm, + ((ENET_INTERFACE_FROM_MODE(p_FmMacControllerDriver->enetMode) == e_ENET_IF_XGMII) ? + e_FM_MAC_10G : e_FM_MAC_1G), + p_FmMacControllerDriver->macId) != E_OK)) + RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Can't reset MAC!")); + + if (p_FmMacControllerDriver->f_FM_MAC_Init) + return p_FmMacControllerDriver->f_FM_MAC_Init(h_FmMac); + RETURN_ERROR(MINOR, E_NOT_SUPPORTED, NO_MSG); +} + +/* ......................................................................... */ + +t_Error FM_MAC_Free (t_Handle h_FmMac) +{ + t_FmMacControllerDriver *p_FmMacControllerDriver = (t_FmMacControllerDriver *)h_FmMac; + + SANITY_CHECK_RETURN_ERROR(p_FmMacControllerDriver, E_INVALID_HANDLE); + + if (p_FmMacControllerDriver->f_FM_MAC_Free) + return p_FmMacControllerDriver->f_FM_MAC_Free(h_FmMac); + + RETURN_ERROR(MINOR, E_NOT_SUPPORTED, NO_MSG); +} + +/* ......................................................................... */ + +t_Error FM_MAC_ConfigResetOnInit (t_Handle h_FmMac, bool enable) +{ + t_FmMacControllerDriver *p_FmMacControllerDriver = (t_FmMacControllerDriver *)h_FmMac; + + SANITY_CHECK_RETURN_ERROR(p_FmMacControllerDriver, E_INVALID_HANDLE); + + if (p_FmMacControllerDriver->f_FM_MAC_ConfigResetOnInit) + return p_FmMacControllerDriver->f_FM_MAC_ConfigResetOnInit(h_FmMac, enable); + + p_FmMacControllerDriver->resetOnInit = enable; + + return E_OK; +} + +/* ......................................................................... */ + +t_Error FM_MAC_ConfigLoopback (t_Handle h_FmMac, bool newVal) +{ + t_FmMacControllerDriver *p_FmMacControllerDriver = (t_FmMacControllerDriver *)h_FmMac; + + SANITY_CHECK_RETURN_ERROR(p_FmMacControllerDriver, E_INVALID_HANDLE); + + if (p_FmMacControllerDriver->f_FM_MAC_ConfigLoopback) + return p_FmMacControllerDriver->f_FM_MAC_ConfigLoopback(h_FmMac, newVal); + + RETURN_ERROR(MINOR, E_NOT_SUPPORTED, NO_MSG); +} + +/* ......................................................................... */ + +t_Error FM_MAC_ConfigMaxFrameLength (t_Handle h_FmMac, uint16_t newVal) +{ + t_FmMacControllerDriver *p_FmMacControllerDriver = (t_FmMacControllerDriver *)h_FmMac; + + SANITY_CHECK_RETURN_ERROR(p_FmMacControllerDriver, E_INVALID_HANDLE); + + if (p_FmMacControllerDriver->f_FM_MAC_ConfigMaxFrameLength) + return p_FmMacControllerDriver->f_FM_MAC_ConfigMaxFrameLength(h_FmMac, newVal); + RETURN_ERROR(MINOR, E_NOT_SUPPORTED, NO_MSG); +} + +/* ......................................................................... */ + +t_Error FM_MAC_ConfigWan (t_Handle h_FmMac, bool flag) +{ + t_FmMacControllerDriver *p_FmMacControllerDriver = (t_FmMacControllerDriver *)h_FmMac; + + SANITY_CHECK_RETURN_ERROR(p_FmMacControllerDriver, E_INVALID_HANDLE); + + if (p_FmMacControllerDriver->f_FM_MAC_ConfigWan) + return p_FmMacControllerDriver->f_FM_MAC_ConfigWan(h_FmMac, flag); + + RETURN_ERROR(MINOR, E_NOT_SUPPORTED, NO_MSG); +} + +/* ......................................................................... */ + +t_Error FM_MAC_ConfigPadAndCrc (t_Handle h_FmMac, bool newVal) +{ + t_FmMacControllerDriver *p_FmMacControllerDriver = (t_FmMacControllerDriver *)h_FmMac; + + SANITY_CHECK_RETURN_ERROR(p_FmMacControllerDriver, E_INVALID_HANDLE); + + if (p_FmMacControllerDriver->f_FM_MAC_ConfigPadAndCrc) + return p_FmMacControllerDriver->f_FM_MAC_ConfigPadAndCrc(h_FmMac, newVal); + + RETURN_ERROR(MINOR, E_NOT_SUPPORTED, NO_MSG); +} + +/* ......................................................................... */ + +t_Error FM_MAC_ConfigHalfDuplex (t_Handle h_FmMac, bool newVal) +{ + t_FmMacControllerDriver *p_FmMacControllerDriver = (t_FmMacControllerDriver *)h_FmMac; + + SANITY_CHECK_RETURN_ERROR(p_FmMacControllerDriver, E_INVALID_HANDLE); + + if (p_FmMacControllerDriver->f_FM_MAC_ConfigHalfDuplex) + return p_FmMacControllerDriver->f_FM_MAC_ConfigHalfDuplex(h_FmMac,newVal); + + RETURN_ERROR(MINOR, E_NOT_SUPPORTED, NO_MSG); +} + +/* ......................................................................... */ + +t_Error FM_MAC_ConfigTbiPhyAddr (t_Handle h_FmMac, uint8_t newVal) +{ + t_FmMacControllerDriver *p_FmMacControllerDriver = (t_FmMacControllerDriver *)h_FmMac; + + SANITY_CHECK_RETURN_ERROR(p_FmMacControllerDriver, E_INVALID_HANDLE); + + if (p_FmMacControllerDriver->f_FM_MAC_ConfigTbiPhyAddr) + return p_FmMacControllerDriver->f_FM_MAC_ConfigTbiPhyAddr(h_FmMac,newVal); + + RETURN_ERROR(MINOR, E_NOT_SUPPORTED, NO_MSG); +} + +/* ......................................................................... */ + +t_Error FM_MAC_ConfigLengthCheck (t_Handle h_FmMac, bool newVal) +{ + t_FmMacControllerDriver *p_FmMacControllerDriver = (t_FmMacControllerDriver *)h_FmMac; + + SANITY_CHECK_RETURN_ERROR(p_FmMacControllerDriver, E_INVALID_HANDLE); + + if (p_FmMacControllerDriver->f_FM_MAC_ConfigLengthCheck) + return p_FmMacControllerDriver->f_FM_MAC_ConfigLengthCheck(h_FmMac,newVal); + + RETURN_ERROR(MINOR, E_NOT_SUPPORTED, NO_MSG); +} + +/* ......................................................................... */ + +t_Error FM_MAC_ConfigException (t_Handle h_FmMac, e_FmMacExceptions ex, bool enable) +{ + t_FmMacControllerDriver *p_FmMacControllerDriver = (t_FmMacControllerDriver *)h_FmMac; + + SANITY_CHECK_RETURN_ERROR(p_FmMacControllerDriver, E_INVALID_HANDLE); + + if (p_FmMacControllerDriver->f_FM_MAC_ConfigException) + return p_FmMacControllerDriver->f_FM_MAC_ConfigException(h_FmMac, ex, enable); + + RETURN_ERROR(MINOR, E_NOT_SUPPORTED, NO_MSG); +} + +#ifdef FM_TX_ECC_FRMS_ERRATA_10GMAC_A004 +/* ......................................................................... */ + +t_Error FM_MAC_ConfigSkipFman11Workaround (t_Handle h_FmMac) +{ + t_FmMacControllerDriver *p_FmMacControllerDriver = (t_FmMacControllerDriver *)h_FmMac; + + SANITY_CHECK_RETURN_ERROR(p_FmMacControllerDriver, E_INVALID_HANDLE); + + if (p_FmMacControllerDriver->f_FM_MAC_ConfigSkipFman11Workaround) + return p_FmMacControllerDriver->f_FM_MAC_ConfigSkipFman11Workaround(h_FmMac); + + RETURN_ERROR(MINOR, E_NOT_SUPPORTED, NO_MSG); +} +#endif /* FM_TX_ECC_FRMS_ERRATA_10GMAC_A004 */ + + +/*****************************************************************************/ +/* Run Time Control */ +/*****************************************************************************/ + +/* ......................................................................... */ + +t_Error FM_MAC_Enable (t_Handle h_FmMac, e_CommMode mode) +{ + t_FmMacControllerDriver *p_FmMacControllerDriver = (t_FmMacControllerDriver *)h_FmMac; + + SANITY_CHECK_RETURN_ERROR(p_FmMacControllerDriver, E_INVALID_HANDLE); + + if (p_FmMacControllerDriver->f_FM_MAC_Enable) + return p_FmMacControllerDriver->f_FM_MAC_Enable(h_FmMac, mode); + + RETURN_ERROR(MINOR, E_NOT_SUPPORTED, NO_MSG); +} + +/* ......................................................................... */ + +t_Error FM_MAC_Disable (t_Handle h_FmMac, e_CommMode mode) +{ + t_FmMacControllerDriver *p_FmMacControllerDriver = (t_FmMacControllerDriver *)h_FmMac; + + SANITY_CHECK_RETURN_ERROR(p_FmMacControllerDriver, E_INVALID_HANDLE); + + if (p_FmMacControllerDriver->f_FM_MAC_Disable) + return p_FmMacControllerDriver->f_FM_MAC_Disable(h_FmMac, mode); + + RETURN_ERROR(MINOR, E_NOT_SUPPORTED, NO_MSG); +} + +/* ......................................................................... */ + +t_Error FM_MAC_Enable1588TimeStamp (t_Handle h_FmMac) +{ + t_FmMacControllerDriver *p_FmMacControllerDriver = (t_FmMacControllerDriver *)h_FmMac; + + SANITY_CHECK_RETURN_ERROR(p_FmMacControllerDriver, E_INVALID_HANDLE); + + if (p_FmMacControllerDriver->f_FM_MAC_Enable1588TimeStamp) + return p_FmMacControllerDriver->f_FM_MAC_Enable1588TimeStamp(h_FmMac); + + RETURN_ERROR(MINOR, E_NOT_SUPPORTED, NO_MSG); +} + +/* ......................................................................... */ + +t_Error FM_MAC_Disable1588TimeStamp (t_Handle h_FmMac) +{ + t_FmMacControllerDriver *p_FmMacControllerDriver = (t_FmMacControllerDriver *)h_FmMac; + + SANITY_CHECK_RETURN_ERROR(p_FmMacControllerDriver, E_INVALID_HANDLE); + + if (p_FmMacControllerDriver->f_FM_MAC_Disable1588TimeStamp) + return p_FmMacControllerDriver->f_FM_MAC_Disable1588TimeStamp(h_FmMac); + + RETURN_ERROR(MINOR, E_NOT_SUPPORTED, NO_MSG); +} + +/* ......................................................................... */ + +t_Error FM_MAC_SetTxAutoPauseFrames(t_Handle h_FmMac, + uint16_t pauseTime) +{ + t_FmMacControllerDriver *p_FmMacControllerDriver = (t_FmMacControllerDriver *)h_FmMac; + + SANITY_CHECK_RETURN_ERROR(p_FmMacControllerDriver, E_INVALID_HANDLE); + + if (p_FmMacControllerDriver->f_FM_MAC_SetTxAutoPauseFrames) + return p_FmMacControllerDriver->f_FM_MAC_SetTxAutoPauseFrames(h_FmMac, + pauseTime); + + RETURN_ERROR(MINOR, E_NOT_SUPPORTED, NO_MSG); +} + +/* ......................................................................... */ + +t_Error FM_MAC_SetTxPauseFrames(t_Handle h_FmMac, + uint8_t priority, + uint16_t pauseTime, + uint16_t threshTime) +{ + t_FmMacControllerDriver *p_FmMacControllerDriver = (t_FmMacControllerDriver *)h_FmMac; + + SANITY_CHECK_RETURN_ERROR(p_FmMacControllerDriver, E_INVALID_HANDLE); + + if (p_FmMacControllerDriver->f_FM_MAC_SetTxPauseFrames) + return p_FmMacControllerDriver->f_FM_MAC_SetTxPauseFrames(h_FmMac, + priority, + pauseTime, + threshTime); + + RETURN_ERROR(MINOR, E_NOT_SUPPORTED, NO_MSG); +} + +/* ......................................................................... */ + +t_Error FM_MAC_SetRxIgnorePauseFrames (t_Handle h_FmMac, bool en) +{ + t_FmMacControllerDriver *p_FmMacControllerDriver = (t_FmMacControllerDriver *)h_FmMac; + + SANITY_CHECK_RETURN_ERROR(p_FmMacControllerDriver, E_INVALID_HANDLE); + + if (p_FmMacControllerDriver->f_FM_MAC_SetRxIgnorePauseFrames) + return p_FmMacControllerDriver->f_FM_MAC_SetRxIgnorePauseFrames(h_FmMac, en); + + RETURN_ERROR(MINOR, E_NOT_SUPPORTED, NO_MSG); +} + +/* ......................................................................... */ + +t_Error FM_MAC_ResetCounters (t_Handle h_FmMac) +{ + t_FmMacControllerDriver *p_FmMacControllerDriver = (t_FmMacControllerDriver *)h_FmMac; + + SANITY_CHECK_RETURN_ERROR(p_FmMacControllerDriver, E_INVALID_HANDLE); + + if (p_FmMacControllerDriver->f_FM_MAC_ResetCounters) + return p_FmMacControllerDriver->f_FM_MAC_ResetCounters(h_FmMac); + + RETURN_ERROR(MINOR, E_NOT_SUPPORTED, NO_MSG); +} + +/* ......................................................................... */ + +t_Error FM_MAC_SetException(t_Handle h_FmMac, e_FmMacExceptions ex, bool enable) +{ + t_FmMacControllerDriver *p_FmMacControllerDriver = (t_FmMacControllerDriver *)h_FmMac; + + SANITY_CHECK_RETURN_ERROR(p_FmMacControllerDriver, E_INVALID_HANDLE); + + if (p_FmMacControllerDriver->f_FM_MAC_SetException) + return p_FmMacControllerDriver->f_FM_MAC_SetException(h_FmMac, ex, enable); + + RETURN_ERROR(MINOR, E_NOT_SUPPORTED, NO_MSG); +} + +/* ......................................................................... */ + +t_Error FM_MAC_SetStatistics (t_Handle h_FmMac, e_FmMacStatisticsLevel statisticsLevel) +{ + t_FmMacControllerDriver *p_FmMacControllerDriver = (t_FmMacControllerDriver *)h_FmMac; + + SANITY_CHECK_RETURN_ERROR(p_FmMacControllerDriver, E_INVALID_HANDLE); + + if (p_FmMacControllerDriver->f_FM_MAC_SetStatistics) + return p_FmMacControllerDriver->f_FM_MAC_SetStatistics(h_FmMac, statisticsLevel); + + RETURN_ERROR(MINOR, E_NOT_SUPPORTED, NO_MSG); +} + +/* ......................................................................... */ + +t_Error FM_MAC_GetStatistics (t_Handle h_FmMac, t_FmMacStatistics *p_Statistics) +{ + t_FmMacControllerDriver *p_FmMacControllerDriver = (t_FmMacControllerDriver *)h_FmMac; + + SANITY_CHECK_RETURN_ERROR(p_FmMacControllerDriver, E_INVALID_HANDLE); + + if (p_FmMacControllerDriver->f_FM_MAC_GetStatistics) + return p_FmMacControllerDriver->f_FM_MAC_GetStatistics(h_FmMac, p_Statistics); + + RETURN_ERROR(MINOR, E_NOT_SUPPORTED, NO_MSG); +} + +/* ......................................................................... */ + +t_Error FM_MAC_ModifyMacAddr (t_Handle h_FmMac, t_EnetAddr *p_EnetAddr) +{ + t_FmMacControllerDriver *p_FmMacControllerDriver = (t_FmMacControllerDriver *)h_FmMac; + + SANITY_CHECK_RETURN_ERROR(p_FmMacControllerDriver, E_INVALID_HANDLE); + + if (p_FmMacControllerDriver->f_FM_MAC_ModifyMacAddr) + return p_FmMacControllerDriver->f_FM_MAC_ModifyMacAddr(h_FmMac, p_EnetAddr); + + RETURN_ERROR(MINOR, E_NOT_SUPPORTED, NO_MSG); +} + +/* ......................................................................... */ + +t_Error FM_MAC_AddHashMacAddr (t_Handle h_FmMac, t_EnetAddr *p_EnetAddr) +{ + t_FmMacControllerDriver *p_FmMacControllerDriver = (t_FmMacControllerDriver *)h_FmMac; + + SANITY_CHECK_RETURN_ERROR(p_FmMacControllerDriver, E_INVALID_HANDLE); + + if (p_FmMacControllerDriver->f_FM_MAC_AddHashMacAddr) + return p_FmMacControllerDriver->f_FM_MAC_AddHashMacAddr(h_FmMac, p_EnetAddr); + + RETURN_ERROR(MINOR, E_NOT_SUPPORTED, NO_MSG); +} + +/* ......................................................................... */ + +t_Error FM_MAC_RemoveHashMacAddr (t_Handle h_FmMac, t_EnetAddr *p_EnetAddr) +{ + t_FmMacControllerDriver *p_FmMacControllerDriver = (t_FmMacControllerDriver *)h_FmMac; + + SANITY_CHECK_RETURN_ERROR(p_FmMacControllerDriver, E_INVALID_HANDLE); + + if (p_FmMacControllerDriver->f_FM_MAC_RemoveHashMacAddr) + return p_FmMacControllerDriver->f_FM_MAC_RemoveHashMacAddr(h_FmMac, p_EnetAddr); + + RETURN_ERROR(MINOR, E_NOT_SUPPORTED, NO_MSG); +} + +/* ......................................................................... */ + +t_Error FM_MAC_AddExactMatchMacAddr (t_Handle h_FmMac, t_EnetAddr *p_EnetAddr) +{ + t_FmMacControllerDriver *p_FmMacControllerDriver = (t_FmMacControllerDriver *)h_FmMac; + + SANITY_CHECK_RETURN_ERROR(p_FmMacControllerDriver, E_INVALID_HANDLE); + + if (p_FmMacControllerDriver->f_FM_MAC_AddExactMatchMacAddr) + return p_FmMacControllerDriver->f_FM_MAC_AddExactMatchMacAddr(h_FmMac, p_EnetAddr); + + RETURN_ERROR(MINOR, E_NOT_SUPPORTED, NO_MSG); +} + +/* ......................................................................... */ + +t_Error FM_MAC_RemovelExactMatchMacAddr (t_Handle h_FmMac, t_EnetAddr *p_EnetAddr) +{ + t_FmMacControllerDriver *p_FmMacControllerDriver = (t_FmMacControllerDriver *)h_FmMac; + + SANITY_CHECK_RETURN_ERROR(p_FmMacControllerDriver, E_INVALID_HANDLE); + + if (p_FmMacControllerDriver->f_FM_MAC_RemovelExactMatchMacAddr) + return p_FmMacControllerDriver->f_FM_MAC_RemovelExactMatchMacAddr(h_FmMac, p_EnetAddr); + + RETURN_ERROR(MINOR, E_NOT_SUPPORTED, NO_MSG); +} + +/* ......................................................................... */ + +t_Error FM_MAC_GetVesrion (t_Handle h_FmMac, uint32_t *macVresion) +{ + t_FmMacControllerDriver *p_FmMacControllerDriver = (t_FmMacControllerDriver *)h_FmMac; + + SANITY_CHECK_RETURN_ERROR(p_FmMacControllerDriver, E_INVALID_HANDLE); + + if (p_FmMacControllerDriver->f_FM_MAC_GetVersion) + return p_FmMacControllerDriver->f_FM_MAC_GetVersion(h_FmMac, macVresion); + + RETURN_ERROR(MINOR, E_NOT_SUPPORTED, NO_MSG); + +} + +/* ......................................................................... */ + +t_Error FM_MAC_GetId (t_Handle h_FmMac, uint32_t *macId) +{ + t_FmMacControllerDriver *p_FmMacControllerDriver = (t_FmMacControllerDriver *)h_FmMac; + + SANITY_CHECK_RETURN_ERROR(p_FmMacControllerDriver, E_INVALID_HANDLE); + + if (p_FmMacControllerDriver->f_FM_MAC_GetId) + return p_FmMacControllerDriver->f_FM_MAC_GetId(h_FmMac, macId); + + RETURN_ERROR(MINOR, E_NOT_SUPPORTED, NO_MSG); +} + +/* ......................................................................... */ + +t_Error FM_MAC_SetPromiscuous (t_Handle h_FmMac, bool newVal) +{ + t_FmMacControllerDriver *p_FmMacControllerDriver = (t_FmMacControllerDriver *)h_FmMac; + + SANITY_CHECK_RETURN_ERROR(p_FmMacControllerDriver, E_INVALID_HANDLE); + + if (p_FmMacControllerDriver->f_FM_MAC_SetPromiscuous) + return p_FmMacControllerDriver->f_FM_MAC_SetPromiscuous(h_FmMac, newVal); + + RETURN_ERROR(MINOR, E_NOT_SUPPORTED, NO_MSG); +} + +/* ......................................................................... */ + +t_Error FM_MAC_AdjustLink(t_Handle h_FmMac, e_EnetSpeed speed, bool fullDuplex) +{ + t_FmMacControllerDriver *p_FmMacControllerDriver = (t_FmMacControllerDriver *)h_FmMac; + + SANITY_CHECK_RETURN_ERROR(p_FmMacControllerDriver, E_INVALID_HANDLE); + + if (p_FmMacControllerDriver->f_FM_MAC_AdjustLink) + return p_FmMacControllerDriver->f_FM_MAC_AdjustLink(h_FmMac, speed, fullDuplex); + + RETURN_ERROR(MINOR, E_NOT_SUPPORTED, NO_MSG); +} + +/* ......................................................................... */ + +t_Error FM_MAC_RestartAutoneg(t_Handle h_FmMac) +{ + t_FmMacControllerDriver *p_FmMacControllerDriver = (t_FmMacControllerDriver *)h_FmMac; + + SANITY_CHECK_RETURN_ERROR(p_FmMacControllerDriver, E_INVALID_HANDLE); + + if (p_FmMacControllerDriver->f_FM_MAC_RestartAutoneg) + return p_FmMacControllerDriver->f_FM_MAC_RestartAutoneg(h_FmMac); + + RETURN_ERROR(MINOR, E_NOT_SUPPORTED, NO_MSG); +} + +/* ......................................................................... */ + +t_Error FM_MAC_MII_WritePhyReg (t_Handle h_FmMac, uint8_t phyAddr, uint8_t reg, uint16_t data) +{ + t_FmMacControllerDriver *p_FmMacControllerDriver = (t_FmMacControllerDriver *)h_FmMac; + + SANITY_CHECK_RETURN_ERROR(p_FmMacControllerDriver, E_INVALID_HANDLE); + + if (p_FmMacControllerDriver->f_FM_MAC_MII_WritePhyReg) + return p_FmMacControllerDriver->f_FM_MAC_MII_WritePhyReg(h_FmMac, phyAddr, reg, data); + + RETURN_ERROR(MINOR, E_NOT_SUPPORTED, NO_MSG); +} + +/* ......................................................................... */ + +t_Error FM_MAC_MII_ReadPhyReg(t_Handle h_FmMac, uint8_t phyAddr, uint8_t reg, uint16_t *p_Data) +{ + t_FmMacControllerDriver *p_FmMacControllerDriver = (t_FmMacControllerDriver *)h_FmMac; + + SANITY_CHECK_RETURN_ERROR(p_FmMacControllerDriver, E_INVALID_HANDLE); + + if (p_FmMacControllerDriver->f_FM_MAC_MII_ReadPhyReg) + return p_FmMacControllerDriver->f_FM_MAC_MII_ReadPhyReg(h_FmMac, phyAddr, reg, p_Data); + + RETURN_ERROR(MINOR, E_NOT_SUPPORTED, NO_MSG); +} + +/* ......................................................................... */ + +uint16_t FM_MAC_GetMaxFrameLength(t_Handle h_FmMac) +{ + t_FmMacControllerDriver *p_FmMacControllerDriver = (t_FmMacControllerDriver *)h_FmMac; + + SANITY_CHECK_RETURN_VALUE(p_FmMacControllerDriver, E_INVALID_HANDLE, 0); + + if (p_FmMacControllerDriver->f_FM_MAC_GetMaxFrameLength) + return p_FmMacControllerDriver->f_FM_MAC_GetMaxFrameLength(h_FmMac); + + REPORT_ERROR(MINOR, E_NOT_SUPPORTED, NO_MSG); + return 0; +} + +#if (defined(DEBUG_ERRORS) && (DEBUG_ERRORS > 0)) +/*****************************************************************************/ +t_Error FM_MAC_DumpRegs(t_Handle h_FmMac) +{ + t_FmMacControllerDriver *p_FmMacControllerDriver = (t_FmMacControllerDriver *)h_FmMac; + + SANITY_CHECK_RETURN_ERROR(p_FmMacControllerDriver, E_INVALID_HANDLE); + + if (p_FmMacControllerDriver->f_FM_MAC_DumpRegs) + return p_FmMacControllerDriver->f_FM_MAC_DumpRegs(h_FmMac); + RETURN_ERROR(MINOR, E_NOT_SUPPORTED, NO_MSG); +} +#endif /* (defined(DEBUG_ERRORS) && ... */ diff --git a/drivers/net/ethernet/freescale/fman/Peripherals/FM/MAC/fm_mac.h b/drivers/net/ethernet/freescale/fman/Peripherals/FM/MAC/fm_mac.h new file mode 100644 index 0000000..94f7b09 --- /dev/null +++ b/drivers/net/ethernet/freescale/fman/Peripherals/FM/MAC/fm_mac.h @@ -0,0 +1,222 @@ +/* + * Copyright 2008-2012 Freescale Semiconductor Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Freescale Semiconductor nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + +/****************************************************************************** + @File fm_mac.h + + @Description FM MAC ... +*//***************************************************************************/ +#ifndef __FM_MAC_H +#define __FM_MAC_H + +#include "std_ext.h" +#include "error_ext.h" +#include "list_ext.h" +#include "fm_mac_ext.h" +#include "fm_common.h" + + +#define __ERR_MODULE__ MODULE_FM_MAC + +/**************************************************************************//** + @Description defaults +*//***************************************************************************/ + + +#define DEFAULT_halfDuplex FALSE +#define DEFAULT_padAndCrcEnable TRUE +#define DEFAULT_resetOnInit FALSE + + +typedef struct { + uint64_t addr; /* Ethernet Address */ + t_List node; +} t_EthHashEntry; +#define ETH_HASH_ENTRY_OBJ(ptr) LIST_OBJECT(ptr, t_EthHashEntry, node) + +typedef struct { + uint16_t size; + t_List *p_Lsts; +} t_EthHash; + +typedef struct { + t_Error (*f_FM_MAC_Init) (t_Handle h_FmMac); + t_Error (*f_FM_MAC_Free) (t_Handle h_FmMac); + + t_Error (*f_FM_MAC_SetStatistics) (t_Handle h_FmMac, e_FmMacStatisticsLevel statisticsLevel); + t_Error (*f_FM_MAC_ConfigLoopback) (t_Handle h_FmMac, bool newVal); + t_Error (*f_FM_MAC_ConfigMaxFrameLength) (t_Handle h_FmMac, uint16_t newVal); + t_Error (*f_FM_MAC_ConfigWan) (t_Handle h_FmMac, bool flag); + t_Error (*f_FM_MAC_ConfigPadAndCrc) (t_Handle h_FmMac, bool newVal); + t_Error (*f_FM_MAC_ConfigHalfDuplex) (t_Handle h_FmMac, bool newVal); + t_Error (*f_FM_MAC_ConfigLengthCheck) (t_Handle h_FmMac, bool newVal); + t_Error (*f_FM_MAC_ConfigTbiPhyAddr) (t_Handle h_FmMac, uint8_t newVal); + t_Error (*f_FM_MAC_ConfigException) (t_Handle h_FmMac, e_FmMacExceptions, bool enable); + t_Error (*f_FM_MAC_ConfigResetOnInit) (t_Handle h_FmMac, bool enable); +#ifdef FM_TX_ECC_FRMS_ERRATA_10GMAC_A004 + t_Error (*f_FM_MAC_ConfigSkipFman11Workaround) (t_Handle h_FmMac); +#endif /* FM_TX_ECC_FRMS_ERRATA_10GMAC_A004 */ + + t_Error (*f_FM_MAC_SetException) (t_Handle h_FmMac, e_FmMacExceptions ex, bool enable); + + t_Error (*f_FM_MAC_Enable) (t_Handle h_FmMac, e_CommMode mode); + t_Error (*f_FM_MAC_Disable) (t_Handle h_FmMac, e_CommMode mode); + t_Error (*f_FM_MAC_Enable1588TimeStamp) (t_Handle h_FmMac); + t_Error (*f_FM_MAC_Disable1588TimeStamp) (t_Handle h_FmMac); + t_Error (*f_FM_MAC_Reset) (t_Handle h_FmMac, bool wait); + + t_Error (*f_FM_MAC_SetTxAutoPauseFrames) (t_Handle h_FmMac, + uint16_t pauseTime); + t_Error (*f_FM_MAC_SetTxPauseFrames) (t_Handle h_FmMac, + uint8_t priority, + uint16_t pauseTime, + uint16_t threshTime); + t_Error (*f_FM_MAC_SetRxIgnorePauseFrames) (t_Handle h_FmMac, bool en); + + t_Error (*f_FM_MAC_ResetCounters) (t_Handle h_FmMac); + t_Error (*f_FM_MAC_GetStatistics) (t_Handle h_FmMac, t_FmMacStatistics *p_Statistics); + + t_Error (*f_FM_MAC_ModifyMacAddr) (t_Handle h_FmMac, t_EnetAddr *p_EnetAddr); + t_Error (*f_FM_MAC_AddHashMacAddr) (t_Handle h_FmMac, t_EnetAddr *p_EnetAddr); + t_Error (*f_FM_MAC_RemoveHashMacAddr) (t_Handle h_FmMac, t_EnetAddr *p_EnetAddr); + t_Error (*f_FM_MAC_AddExactMatchMacAddr) (t_Handle h_FmMac, t_EnetAddr *p_EnetAddr); + t_Error (*f_FM_MAC_RemovelExactMatchMacAddr) (t_Handle h_FmMac, t_EnetAddr *p_EnetAddr); + + t_Error (*f_FM_MAC_SetPromiscuous) (t_Handle h_FmMac, bool newVal); + t_Error (*f_FM_MAC_AdjustLink) (t_Handle h_FmMac, e_EnetSpeed speed, bool fullDuplex); + t_Error (*f_FM_MAC_RestartAutoneg) (t_Handle h_FmMac); + + t_Error (*f_FM_MAC_GetId) (t_Handle h_FmMac, uint32_t *macId); + + t_Error (*f_FM_MAC_GetVersion) (t_Handle h_FmMac, uint32_t *macVersion); + + uint16_t (*f_FM_MAC_GetMaxFrameLength) (t_Handle h_FmMac); + + t_Error (*f_FM_MAC_MII_WritePhyReg)(t_Handle h_FmMac, uint8_t phyAddr, uint8_t reg, uint16_t data); + t_Error (*f_FM_MAC_MII_ReadPhyReg)(t_Handle h_FmMac, uint8_t phyAddr, uint8_t reg, uint16_t *p_Data); + +#if (defined(DEBUG_ERRORS) && (DEBUG_ERRORS > 0)) + t_Error (*f_FM_MAC_DumpRegs) (t_Handle h_FmMac); +#endif /* (defined(DEBUG_ERRORS) && ... */ + + t_Handle h_Fm; + t_FmRevisionInfo fmRevInfo; + e_EnetMode enetMode; + uint8_t macId; + bool resetOnInit; + uint16_t clkFreq; +} t_FmMacControllerDriver; + + +#if (DPAA_VERSION == 10) +t_Handle DTSEC_Config(t_FmMacParams *p_FmMacParam); +t_Handle TGEC_Config(t_FmMacParams *p_FmMacParams); +#else +t_Handle MEMAC_Config(t_FmMacParams *p_FmMacParam); +#endif /* (DPAA_VERSION == 10) */ +uint16_t FM_MAC_GetMaxFrameLength(t_Handle FmMac); + + +/* ........................................................................... */ + +static __inline__ t_EthHashEntry *DequeueAddrFromHashEntry(t_List *p_AddrLst) +{ + t_EthHashEntry *p_HashEntry = NULL; + if (!LIST_IsEmpty(p_AddrLst)) + { + p_HashEntry = ETH_HASH_ENTRY_OBJ(p_AddrLst->p_Next); + LIST_DelAndInit(&p_HashEntry->node); + } + return p_HashEntry; +} + +/* ........................................................................... */ + +static __inline__ void FreeHashTable(t_EthHash *p_Hash) +{ + t_EthHashEntry *p_HashEntry; + int i = 0; + + if (p_Hash) + { + if (p_Hash->p_Lsts) + { + for (i=0; i<p_Hash->size; i++) + { + p_HashEntry = DequeueAddrFromHashEntry(&p_Hash->p_Lsts[i]); + while (p_HashEntry) + { + XX_Free(p_HashEntry); + p_HashEntry = DequeueAddrFromHashEntry(&p_Hash->p_Lsts[i]); + } + } + + XX_Free(p_Hash->p_Lsts); + } + + XX_Free(p_Hash); + } +} + +/* ........................................................................... */ + +static __inline__ t_EthHash * AllocHashTable(uint16_t size) +{ + uint32_t i; + t_EthHash *p_Hash; + + /* Allocate address hash table */ + p_Hash = (t_EthHash *)XX_Malloc(size*sizeof(t_EthHash *)); + if (!p_Hash) + { + REPORT_ERROR(MAJOR, E_NO_MEMORY, ("Address hash table")); + return NULL; + } + p_Hash->size = size; + + p_Hash->p_Lsts = (t_List *)XX_Malloc(p_Hash->size*sizeof(t_List)); + if (!p_Hash->p_Lsts) + { + REPORT_ERROR(MAJOR, E_NO_MEMORY, ("Address hash table")); + XX_Free(p_Hash); + return NULL; + } + + for (i=0 ; i<p_Hash->size; i++) + INIT_LIST(&p_Hash->p_Lsts[i]); + + return p_Hash; +} + + +#endif /* __FM_MAC_H */ diff --git a/drivers/net/ethernet/freescale/fman/Peripherals/FM/MAC/fman_crc32.c b/drivers/net/ethernet/freescale/fman/Peripherals/FM/MAC/fman_crc32.c new file mode 100644 index 0000000..b6a4ca2 --- /dev/null +++ b/drivers/net/ethernet/freescale/fman/Peripherals/FM/MAC/fman_crc32.c @@ -0,0 +1,119 @@ +/* + * Copyright 2008-2012 Freescale Semiconductor Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Freescale Semiconductor nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + +#include "fman_crc32.h" +#include "common/general.h" + + +/* precomputed CRC values for address hashing */ +static const uint32_t crc_tbl[256] = { + 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f, + 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, + 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2, + 0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, + 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9, + 0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172, + 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c, + 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59, + 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, + 0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, + 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106, + 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433, + 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, + 0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, + 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950, + 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65, + 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7, + 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, + 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa, + 0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f, + 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81, + 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, + 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84, + 0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, + 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, + 0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc, + 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e, + 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b, + 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, + 0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, + 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28, + 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d, + 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f, + 0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, + 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242, + 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777, + 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69, + 0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, + 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc, + 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9, + 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693, + 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, + 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d +}; + +/* Get the mirrored value of a byte size number. (0x11010011 --> 0x11001011) */ +static inline uint8_t get_mirror8(uint8_t n) +{ + uint8_t mirror[16] = { + 0x00, 0x08, 0x04, 0x0c, 0x02, 0x0a, 0x06, 0x0e, + 0x01, 0x09, 0x05, 0x0d, 0x03, 0x0b, 0x07, 0x0f + }; + return (uint8_t)(((mirror[n & 0x0f] << 4) | (mirror[n >> 4]))); +} + +static inline uint32_t get_mirror32(uint32_t n) +{ + return ((uint32_t)get_mirror8((uint8_t)(n))<<24) | + ((uint32_t)get_mirror8((uint8_t)(n>>8))<<16) | + ((uint32_t)get_mirror8((uint8_t)(n>>16))<<8) | + ((uint32_t)get_mirror8((uint8_t)(n>>24))); +} + +uint32_t get_mac_addr_crc(uint64_t _addr) +{ + uint32_t i; + uint8_t data; + uint32_t crc; + + /* CRC calculation */ + crc = 0xffffffff; + for (i = 0; i < 6; i++) { + data = (uint8_t)(_addr >> ((5-i)*8)); + crc = crc ^ data; + crc = crc_tbl[crc&0xff] ^ (crc>>8); + } + + crc = get_mirror32(crc); + return crc; +} diff --git a/drivers/net/ethernet/freescale/fman/Peripherals/FM/MAC/fman_crc32.h b/drivers/net/ethernet/freescale/fman/Peripherals/FM/MAC/fman_crc32.h new file mode 100644 index 0000000..6e32fdc --- /dev/null +++ b/drivers/net/ethernet/freescale/fman/Peripherals/FM/MAC/fman_crc32.h @@ -0,0 +1,43 @@ +/* + * Copyright 2008-2012 Freescale Semiconductor Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Freescale Semiconductor nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + +#ifndef __FMAN_CRC32_H +#define __FMAN_CRC32_H + +#include "common/general.h" + + +uint32_t get_mac_addr_crc(uint64_t _addr); + + +#endif /* __FMAN_CRC32_H */ diff --git a/drivers/net/ethernet/freescale/fman/Peripherals/FM/MAC/fman_dtsec.c b/drivers/net/ethernet/freescale/fman/Peripherals/FM/MAC/fman_dtsec.c new file mode 100644 index 0000000..2ba8554 --- /dev/null +++ b/drivers/net/ethernet/freescale/fman/Peripherals/FM/MAC/fman_dtsec.c @@ -0,0 +1,818 @@ +/* + * Copyright 2008-2012 Freescale Semiconductor Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Freescale Semiconductor nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + +#include "fsl_fman_dtsec.h" + + +void dtsec_stop_rx(struct dtsec_regs *regs) +{ + /* Assert the graceful stop bit */ + iowrite32be(ioread32be(®s->rctrl) | RCTRL_GRS, ®s->rctrl); +} + +void dtsec_stop_tx(struct dtsec_regs *regs) +{ + /* Assert the graceful stop bit */ + iowrite32be(ioread32be(®s->tctrl) | DTSEC_TCTRL_GTS, ®s->tctrl); +} + +void dtsec_start_tx(struct dtsec_regs *regs) +{ + /* clear the graceful stop bit */ + iowrite32be(ioread32be(®s->tctrl) & ~DTSEC_TCTRL_GTS, ®s->tctrl); +} + +void dtsec_start_rx(struct dtsec_regs *regs) +{ + /* clear the graceful stop bit */ + iowrite32be(ioread32be(®s->rctrl) & ~RCTRL_GRS, ®s->rctrl); +} + +void dtsec_defconfig(struct dtsec_cfg *cfg) +{ + cfg->halfdup_on = DEFAULT_HALFDUP_ON; + cfg->halfdup_retransmit = DEFAULT_HALFDUP_RETRANSMIT; + cfg->halfdup_coll_window = DEFAULT_HALFDUP_COLL_WINDOW; + cfg->halfdup_excess_defer = DEFAULT_HALFDUP_EXCESS_DEFER; + cfg->halfdup_no_backoff = DEFAULT_HALFDUP_NO_BACKOFF; + cfg->halfdup_bp_no_backoff = DEFAULT_HALFDUP_BP_NO_BACKOFF; + cfg->halfdup_alt_backoff_val = DEFAULT_HALFDUP_ALT_BACKOFF_VAL; + cfg->halfdup_alt_backoff_en = DEFAULT_HALFDUP_ALT_BACKOFF_EN; + cfg->rx_drop_bcast = DEFAULT_RX_DROP_BCAST; + cfg->rx_short_frm = DEFAULT_RX_SHORT_FRM; + cfg->rx_len_check = DEFAULT_RX_LEN_CHECK; + cfg->tx_pad_crc = DEFAULT_TX_PAD_CRC; + cfg->tx_crc = DEFAULT_TX_CRC; + cfg->rx_ctrl_acc = DEFAULT_RX_CTRL_ACC; + cfg->tx_pause_time = DEFAULT_TX_PAUSE_TIME; + cfg->tbipa = DEFAULT_TBIPA; /* PHY address 0 is reserved (DPAA RM)*/ + cfg->rx_prepend = DEFAULT_RX_PREPEND; + cfg->ptp_tsu_en = DEFAULT_PTP_TSU_EN; + cfg->ptp_exception_en = DEFAULT_PTP_EXCEPTION_EN; + cfg->preamble_len = DEFAULT_PREAMBLE_LEN; + cfg->rx_preamble = DEFAULT_RX_PREAMBLE; + cfg->tx_preamble = DEFAULT_TX_PREAMBLE; + cfg->loopback = DEFAULT_LOOPBACK; + cfg->rx_time_stamp_en = DEFAULT_RX_TIME_STAMP_EN; + cfg->tx_time_stamp_en = DEFAULT_TX_TIME_STAMP_EN; + cfg->rx_flow = DEFAULT_RX_FLOW; + cfg->tx_flow = DEFAULT_TX_FLOW; + cfg->rx_group_hash_exd = DEFAULT_RX_GROUP_HASH_EXD; + cfg->tx_pause_time_extd = DEFAULT_TX_PAUSE_TIME_EXTD; + cfg->rx_promisc = DEFAULT_RX_PROMISC; + cfg->non_back_to_back_ipg1 = DEFAULT_NON_BACK_TO_BACK_IPG1; + cfg->non_back_to_back_ipg2 = DEFAULT_NON_BACK_TO_BACK_IPG2; + cfg->min_ifg_enforcement = DEFAULT_MIN_IFG_ENFORCEMENT; + cfg->back_to_back_ipg = DEFAULT_BACK_TO_BACK_IPG; + cfg->maximum_frame = DEFAULT_MAXIMUM_FRAME; + cfg->tbi_phy_addr = DEFAULT_TBI_PHY_ADDR; +} + +int dtsec_init(struct dtsec_regs *regs, struct dtsec_cfg *cfg, + enum enet_interface iface_mode, + enum enet_speed iface_speed, + uint8_t *macaddr, + uint8_t fm_rev_maj, + uint8_t fm_rev_min, + uint32_t exception_mask) +{ + bool is_rgmii = FALSE; + bool is_sgmii = FALSE; + bool is_qsgmii = FALSE; + int i; + uint32_t tmp; + +UNUSED(fm_rev_maj);UNUSED(fm_rev_min); + + /* let's start with a soft reset */ + iowrite32be(MACCFG1_SOFT_RESET, ®s->maccfg1); + iowrite32be(0, ®s->maccfg1); + + /*************dtsec_id2******************/ + tmp = ioread32be(®s->tsec_id2); + + /* check RGMII support */ + if (iface_mode == E_ENET_IF_RGMII || + iface_mode == E_ENET_IF_RMII) + if (tmp & DTSEC_ID2_INT_REDUCED_OFF) + return -EINVAL; + + if (iface_mode == E_ENET_IF_SGMII || + iface_mode == E_ENET_IF_MII) + if (tmp & DTSEC_ID2_INT_REDUCED_OFF) + return -EINVAL; + + /***************ECNTRL************************/ + + is_rgmii = (bool)((iface_mode == E_ENET_IF_RGMII) ? TRUE : FALSE); + is_sgmii = (bool)((iface_mode == E_ENET_IF_SGMII) ? TRUE : FALSE); + is_qsgmii = (bool)((iface_mode == E_ENET_IF_QSGMII) ? TRUE : FALSE); + + tmp = 0; + if (is_rgmii || iface_mode == E_ENET_IF_GMII) + tmp |= DTSEC_ECNTRL_GMIIM; + if (is_sgmii) + tmp |= (DTSEC_ECNTRL_SGMIIM | DTSEC_ECNTRL_TBIM); + if (is_qsgmii) + tmp |= (DTSEC_ECNTRL_SGMIIM | DTSEC_ECNTRL_TBIM | + DTSEC_ECNTRL_QSGMIIM); + if (is_rgmii) + tmp |= DTSEC_ECNTRL_RPM; + if (iface_speed == E_ENET_SPEED_100) + tmp |= DTSEC_ECNTRL_R100M; + + iowrite32be(tmp, ®s->ecntrl); + /***************ECNTRL************************/ + + /***************TCTRL************************/ + tmp = 0; + if (cfg->halfdup_on) + tmp |= DTSEC_TCTRL_THDF; + if (cfg->tx_time_stamp_en) + tmp |= DTSEC_TCTRL_TTSE; + + iowrite32be(tmp, ®s->tctrl); + + /***************TCTRL************************/ + + /***************PTV************************/ + tmp = 0; + +#ifdef FM_SHORT_PAUSE_TIME_ERRATA_DTSEC1 + if ((fm_rev_maj == 1) && (fm_rev_min == 0)) + cfg->tx_pause_time += 2; +#endif /* FM_SHORT_PAUSE_TIME_ERRATA_DTSEC1 */ + + if (cfg->tx_pause_time) + tmp |= cfg->tx_pause_time; + if (cfg->tx_pause_time_extd) + tmp |= cfg->tx_pause_time_extd << PTV_PTE_OFST; + iowrite32be(tmp, ®s->ptv); + + /***************RCTRL************************/ + tmp = 0; + tmp |= ((uint32_t)(cfg->rx_prepend & 0x0000001f)) << 16; + if (cfg->rx_ctrl_acc) + tmp |= RCTRL_CFA; + if (cfg->rx_group_hash_exd) + tmp |= RCTRL_GHTX; + if (cfg->rx_time_stamp_en) + tmp |= RCTRL_RTSE; + if (cfg->rx_drop_bcast) + tmp |= RCTRL_BC_REJ; + if (cfg->rx_short_frm) + tmp |= RCTRL_RSF; + if (cfg->rx_promisc) + tmp |= RCTRL_PROM; + + iowrite32be(tmp, ®s->rctrl); + /***************RCTRL************************/ + + /* + * Assign a Phy Address to the TBI (TBIPA). + * Done also in cases where TBI is not selected to avoid conflict with + * the external PHY's Physical address + */ + iowrite32be(cfg->tbipa, ®s->tbipa); + + /***************TMR_CTL************************/ + iowrite32be(0, ®s->tmr_ctrl); + + if (cfg->ptp_tsu_en) { + tmp = 0; + tmp |= TMR_PEVENT_TSRE; + iowrite32be(tmp, ®s->tmr_pevent); + + if (cfg->ptp_exception_en) { + tmp = 0; + tmp |= TMR_PEMASK_TSREEN; + iowrite32be(tmp, ®s->tmr_pemask); + } + } + + /***************MACCFG1***********************/ + tmp = 0; + if (cfg->loopback) + tmp |= MACCFG1_LOOPBACK; + if (cfg->rx_flow) + tmp |= MACCFG1_RX_FLOW; + if (cfg->tx_flow) + tmp |= MACCFG1_TX_FLOW; + iowrite32be(tmp, ®s->maccfg1); + + /***************MACCFG1***********************/ + + /***************MACCFG2***********************/ + tmp = 0; + + if (iface_speed < E_ENET_SPEED_1000) + tmp |= MACCFG2_NIBBLE_MODE; + else if (iface_speed == E_ENET_SPEED_1000) + tmp |= MACCFG2_BYTE_MODE; + + tmp |= ((uint32_t) cfg->preamble_len & 0x0000000f) + << PREAMBLE_LENGTH_SHIFT; + + if (cfg->rx_preamble) + tmp |= MACCFG2_PRE_AM_Rx_EN; + if (cfg->tx_preamble) + tmp |= MACCFG2_PRE_AM_Tx_EN; + if (cfg->rx_len_check) + tmp |= MACCFG2_LENGTH_CHECK; + if (cfg->tx_pad_crc) + tmp |= MACCFG2_PAD_CRC_EN; + if (cfg->tx_crc) + tmp |= MACCFG2_CRC_EN; + if (!cfg->halfdup_on) + tmp |= MACCFG2_FULL_DUPLEX; + iowrite32be(tmp, ®s->maccfg2); + + /***************MACCFG2***********************/ + + /***************IPGIFG************************/ + tmp = 0; + tmp = (((cfg->non_back_to_back_ipg1 << + IPGIFG_NON_BACK_TO_BACK_IPG_1_SHIFT) + & IPGIFG_NON_BACK_TO_BACK_IPG_1) + | ((cfg->non_back_to_back_ipg2 << + IPGIFG_NON_BACK_TO_BACK_IPG_2_SHIFT) + & IPGIFG_NON_BACK_TO_BACK_IPG_2) + | ((cfg->min_ifg_enforcement << + IPGIFG_MIN_IFG_ENFORCEMENT_SHIFT) + & IPGIFG_MIN_IFG_ENFORCEMENT) + | (cfg->back_to_back_ipg & IPGIFG_BACK_TO_BACK_IPG)); + iowrite32be(tmp, ®s->ipgifg); + + /***************IPGIFG************************/ + + /***************HAFDUP************************/ + tmp = 0; + + if (cfg->halfdup_alt_backoff_en) + tmp = (uint32_t)(HAFDUP_ALT_BEB | + ((cfg->halfdup_alt_backoff_val & 0x0000000f) + << HAFDUP_ALTERNATE_BEB_TRUNCATION_SHIFT)); + if (cfg->halfdup_bp_no_backoff) + tmp |= HAFDUP_BP_NO_BACKOFF; + if (cfg->halfdup_no_backoff) + tmp |= HAFDUP_NO_BACKOFF; + if (cfg->halfdup_excess_defer) + tmp |= HAFDUP_EXCESS_DEFER; + tmp |= ((cfg->halfdup_retransmit << HAFDUP_RETRANSMISSION_MAX_SHIFT) + & HAFDUP_RETRANSMISSION_MAX); + tmp |= (cfg->halfdup_coll_window & HAFDUP_COLLISION_WINDOW); + + iowrite32be(tmp, ®s->hafdup); + /***************HAFDUP************************/ + + /***************MAXFRM************************/ + /* Initialize MAXFRM */ + iowrite32be(cfg->maximum_frame, ®s->maxfrm); + + /***************MAXFRM************************/ + + /***************CAM1************************/ + iowrite32be(0xffffffff, ®s->cam1); + iowrite32be(0xffffffff, ®s->cam2); + + /***************IMASK************************/ + iowrite32be(exception_mask, ®s->imask); + /***************IMASK************************/ + + /***************IEVENT************************/ + iowrite32be(0xffffffff, ®s->ievent); + + /***************MACSTNADDR1/2*****************/ + + tmp = (uint32_t)((macaddr[5] << 24) | + (macaddr[4] << 16) | + (macaddr[3] << 8) | + macaddr[2]); + iowrite32be(tmp, ®s->macstnaddr1); + + tmp = (uint32_t)((macaddr[1] << 24) | + (macaddr[0] << 16)); + iowrite32be(tmp, ®s->macstnaddr2); + + /***************MACSTNADDR1/2*****************/ + + /*****************HASH************************/ + for (i = 0; i < NUM_OF_HASH_REGS ; i++) { + /* Initialize IADDRx */ + iowrite32be(0, ®s->igaddr[i]); + /* Initialize GADDRx */ + iowrite32be(0, ®s->gaddr[i]); + } + + dtsec_reset_stat(regs); + + return 0; +} + +uint16_t dtsec_get_max_frame_len(struct dtsec_regs *regs) +{ + return (uint16_t)ioread32be(®s->maxfrm); +} + +void dtsec_set_max_frame_len(struct dtsec_regs *regs, uint16_t length) +{ + iowrite32be(length, ®s->maxfrm); +} + +void dtsec_set_mac_address(struct dtsec_regs *regs, uint8_t *adr) +{ + uint32_t tmp; + + tmp = (uint32_t)((adr[5] << 24) | + (adr[4] << 16) | + (adr[3] << 8) | + adr[2]); + iowrite32be(tmp, ®s->macstnaddr1); + + tmp = (uint32_t)((adr[1] << 24) | + (adr[0] << 16)); + iowrite32be(tmp, ®s->macstnaddr2); +} + +void dtsec_get_mac_address(struct dtsec_regs *regs, uint8_t *macaddr) +{ + uint32_t tmp1, tmp2; + + tmp1 = ioread32be(®s->macstnaddr1); + tmp2 = ioread32be(®s->macstnaddr2); + + macaddr[0] = (uint8_t)((tmp2 & 0x00ff0000) >> 16); + macaddr[1] = (uint8_t)((tmp2 & 0xff000000) >> 24); + macaddr[2] = (uint8_t)(tmp1 & 0x000000ff); + macaddr[3] = (uint8_t)((tmp1 & 0x0000ff00) >> 8); + macaddr[4] = (uint8_t)((tmp1 & 0x00ff0000) >> 16); + macaddr[5] = (uint8_t)((tmp1 & 0xff000000) >> 24); +} + +void dtsec_set_bucket(struct dtsec_regs *regs, int bucket, bool enable) +{ + int reg_idx = (bucket >> 5) & 0xf; + int bit_idx = bucket & 0x1f; + uint32_t bit_mask = 0x80000000 >> bit_idx; + uint32_t *reg; + + if (reg_idx > 7) + reg = ®s->gaddr[reg_idx-8]; + else + reg = ®s->igaddr[reg_idx]; + + if (enable) + iowrite32be(ioread32be(reg) | bit_mask, reg); + else + iowrite32be(ioread32be(reg) & (~bit_mask), reg); +} + +void dtsec_reset_filter_table(struct dtsec_regs *regs, bool mcast, bool ucast) +{ + int i; + bool ghtx; + + ghtx = (bool)((ioread32be(®s->rctrl) & RCTRL_GHTX) ? TRUE : FALSE); + + if (ucast || (ghtx && mcast)) { + for (i = 0; i < NUM_OF_HASH_REGS; i++) + iowrite32be(0, ®s->igaddr[i]); + } + if (mcast) { + for (i = 0; i < NUM_OF_HASH_REGS; i++) + iowrite32be(0, ®s->gaddr[i]); + } +} + +int dtsec_set_tbi_phy_addr(struct dtsec_regs *regs, + uint8_t addr) +{ + if (addr > 0 && addr < 32) + iowrite32be(addr, ®s->tbipa); + else + return -EINVAL; + + return 0; +} + +int dtsec_adjust_link(struct dtsec_regs *regs, + enum enet_interface iface_mode, + enum enet_speed speed, bool full_dx) +{ + uint32_t tmp; + + if ((speed == E_ENET_SPEED_1000) && !full_dx) + return -EINVAL; + + tmp = ioread32be(®s->maccfg2); + if (!full_dx) + tmp &= ~MACCFG2_FULL_DUPLEX; + else + tmp |= MACCFG2_FULL_DUPLEX; + + tmp &= ~(MACCFG2_NIBBLE_MODE | MACCFG2_BYTE_MODE); + if (speed < E_ENET_SPEED_1000) + tmp |= MACCFG2_NIBBLE_MODE; + else if (speed == E_ENET_SPEED_1000) + tmp |= MACCFG2_BYTE_MODE; + iowrite32be(tmp, ®s->maccfg2); + + tmp = ioread32be(®s->ecntrl); + if (speed == E_ENET_SPEED_100) + tmp |= DTSEC_ECNTRL_R100M; + else + tmp &= ~DTSEC_ECNTRL_R100M; + iowrite32be(tmp, ®s->ecntrl); + + return 0; +} + +void dtsec_set_uc_promisc(struct dtsec_regs *regs, bool enable) +{ + uint32_t tmp; + + tmp = ioread32be(®s->rctrl); + + if (enable) + tmp |= RCTRL_UPROM; + else + tmp &= ~RCTRL_UPROM; + + iowrite32be(tmp, ®s->rctrl); +} + +void dtsec_set_mc_promisc(struct dtsec_regs *regs, bool enable) +{ + uint32_t tmp; + + tmp = ioread32be(®s->rctrl); + + if (enable) + tmp |= RCTRL_MPROM; + else + tmp &= ~RCTRL_MPROM; + + iowrite32be(tmp, ®s->rctrl); +} + +bool dtsec_get_clear_carry_regs(struct dtsec_regs *regs, + uint32_t *car1, uint32_t *car2) +{ + /* read carry registers */ + *car1 = ioread32be(®s->car1); + *car2 = ioread32be(®s->car2); + /* clear carry registers */ + if (*car1) + iowrite32be(*car1, ®s->car1); + if (*car2) + iowrite32be(*car2, ®s->car2); + + return (bool)((*car1 | *car2) ? TRUE : FALSE); +} + + +void dtsec_reset_stat(struct dtsec_regs *regs) +{ + /* clear HW counters */ + iowrite32be(ioread32be(®s->ecntrl) | + DTSEC_ECNTRL_CLRCNT, ®s->ecntrl); +} + +int dtsec_set_stat_level(struct dtsec_regs *regs, enum mac_stat_level level) +{ + switch (level) { + case E_MAC_STAT_NONE: + iowrite32be(0xffffffff, ®s->cam1); + iowrite32be(0xffffffff, ®s->cam2); + iowrite32be(ioread32be(®s->ecntrl) & ~DTSEC_ECNTRL_STEN, + ®s->ecntrl); + iowrite32be(ioread32be(®s->imask) & ~DTSEC_IMASK_MSROEN, + ®s->imask); + break; + case E_MAC_STAT_PARTIAL: + iowrite32be(CAM1_ERRORS_ONLY, ®s->cam1); + iowrite32be(CAM2_ERRORS_ONLY, ®s->cam2); + iowrite32be(ioread32be(®s->ecntrl) | DTSEC_ECNTRL_STEN, + ®s->ecntrl); + iowrite32be(ioread32be(®s->imask) | DTSEC_IMASK_MSROEN, + ®s->imask); + break; + case E_MAC_STAT_MIB_GRP1: + iowrite32be((uint32_t)~CAM1_MIB_GRP_1, ®s->cam1); + iowrite32be((uint32_t)~CAM2_MIB_GRP_1, ®s->cam2); + iowrite32be(ioread32be(®s->ecntrl) | DTSEC_ECNTRL_STEN, + ®s->ecntrl); + iowrite32be(ioread32be(®s->imask) | DTSEC_IMASK_MSROEN, + ®s->imask); + break; + case E_MAC_STAT_FULL: + iowrite32be(0, ®s->cam1); + iowrite32be(0, ®s->cam2); + iowrite32be(ioread32be(®s->ecntrl) | DTSEC_ECNTRL_STEN, + ®s->ecntrl); + iowrite32be(ioread32be(®s->imask) | DTSEC_IMASK_MSROEN, + ®s->imask); + break; + default: + return -EINVAL; + } + + return 0; +} + +void dtsec_set_ts(struct dtsec_regs *regs, bool en) +{ + if (en) { + iowrite32be(ioread32be(®s->rctrl) | RCTRL_RTSE, + ®s->rctrl); + iowrite32be(ioread32be(®s->tctrl) | DTSEC_TCTRL_TTSE, + ®s->tctrl); + } else { + iowrite32be(ioread32be(®s->rctrl) & ~RCTRL_RTSE, + ®s->rctrl); + iowrite32be(ioread32be(®s->tctrl) & ~DTSEC_TCTRL_TTSE, + ®s->tctrl); + } +} + +void dtsec_enable(struct dtsec_regs *regs, bool apply_rx, bool apply_tx) +{ + uint32_t tmp; + + tmp = ioread32be(®s->maccfg1); + + if (apply_rx) + tmp |= MACCFG1_RX_EN ; + + if (apply_tx) + tmp |= MACCFG1_TX_EN ; + + iowrite32be(tmp, ®s->maccfg1); +} + +void dtsec_clear_addr_in_paddr(struct dtsec_regs *regs, uint8_t paddr_num) +{ + iowrite32be(0, ®s->macaddr[paddr_num].exact_match1); + iowrite32be(0, ®s->macaddr[paddr_num].exact_match2); +} + +void dtsec_add_addr_in_paddr(struct dtsec_regs *regs, + uint64_t addr, + uint8_t paddr_num) +{ + uint32_t tmp; + + tmp = (uint32_t)(addr); + /* swap */ + tmp = (((tmp & 0x000000FF) << 24) | + ((tmp & 0x0000FF00) << 8) | + ((tmp & 0x00FF0000) >> 8) | + ((tmp & 0xFF000000) >> 24)); + iowrite32be(tmp, ®s->macaddr[paddr_num].exact_match1); + + tmp = (uint32_t)(addr>>32); + /* swap */ + tmp = (((tmp & 0x000000FF) << 24) | + ((tmp & 0x0000FF00) << 8) | + ((tmp & 0x00FF0000) >> 8) | + ((tmp & 0xFF000000) >> 24)); + iowrite32be(tmp, ®s->macaddr[paddr_num].exact_match2); +} + +void dtsec_disable(struct dtsec_regs *regs, bool apply_rx, bool apply_tx) +{ + uint32_t tmp; + + tmp = ioread32be(®s->maccfg1); + + if (apply_rx) + tmp &= ~MACCFG1_RX_EN; + + if (apply_tx) + tmp &= ~MACCFG1_TX_EN; + + iowrite32be(tmp, ®s->maccfg1); +} + +void dtsec_set_tx_pause_time(struct dtsec_regs *regs, uint16_t time) +{ + uint32_t ptv = 0; + + /* fixme: don't enable tx pause for half-duplex */ + + if (time) { + ptv = ioread32be(®s->ptv); + ptv &= 0xffff0000; + ptv |= time & 0x0000ffff; + iowrite32be(ptv, ®s->ptv); + + /* trigger the transmission of a flow-control pause frame */ + iowrite32be(ioread32be(®s->maccfg1) | MACCFG1_TX_FLOW, + ®s->maccfg1); + } else + iowrite32be(ioread32be(®s->maccfg1) & ~MACCFG1_TX_FLOW, + ®s->maccfg1); +} + +void dtsec_handle_rx_pause(struct dtsec_regs *regs, bool en) +{ + uint32_t tmp; + + /* todo: check if mac is set to full-duplex */ + + tmp = ioread32be(®s->maccfg1); + if (en) + tmp |= MACCFG1_RX_FLOW; + else + tmp &= ~MACCFG1_RX_FLOW; + iowrite32be(tmp, ®s->maccfg1); +} + +uint32_t dtsec_get_rctrl(struct dtsec_regs *regs) +{ + return ioread32be(®s->rctrl); +} + +uint32_t dtsec_get_revision(struct dtsec_regs *regs) +{ + return ioread32be(®s->tsec_id); +} + +uint32_t dtsec_get_event(struct dtsec_regs *regs, uint32_t ev_mask) +{ + return ioread32be(®s->ievent) & ev_mask; +} + +void dtsec_ack_event(struct dtsec_regs *regs, uint32_t ev_mask) +{ + iowrite32be(ev_mask, ®s->ievent); +} + +uint32_t dtsec_get_interrupt_mask(struct dtsec_regs *regs) +{ + return ioread32be(®s->imask); +} + +uint32_t dtsec_check_and_clear_tmr_event(struct dtsec_regs *regs) +{ + uint32_t event; + + event = ioread32be(®s->tmr_pevent); + event &= ioread32be(®s->tmr_pemask); + + if (event) + iowrite32be(event, ®s->tmr_pevent); + return event; +} + +void dtsec_enable_tmr_interrupt(struct dtsec_regs *regs) +{ + iowrite32be(ioread32be(®s->tmr_pemask) | TMR_PEMASK_TSREEN, + ®s->tmr_pemask); +} + +void dtsec_disable_tmr_interrupt(struct dtsec_regs *regs) +{ + iowrite32be(ioread32be(®s->tmr_pemask) & ~TMR_PEMASK_TSREEN, + ®s->tmr_pemask); +} + +void dtsec_enable_interrupt(struct dtsec_regs *regs, uint32_t ev_mask) +{ + iowrite32be(ioread32be(®s->imask) | ev_mask, ®s->imask); +} + +void dtsec_disable_interrupt(struct dtsec_regs *regs, uint32_t ev_mask) +{ + iowrite32be(ioread32be(®s->imask) & ~ev_mask, ®s->imask); +} + +uint32_t dtsec_get_stat_counter(struct dtsec_regs *regs, + enum dtsec_stat_counters reg_name) +{ + uint32_t ret_val; + + switch (reg_name) { + case E_DTSEC_STAT_TR64: + ret_val = ioread32be(®s->tr64); + break; + case E_DTSEC_STAT_TR127: + ret_val = ioread32be(®s->tr127); + break; + case E_DTSEC_STAT_TR255: + ret_val = ioread32be(®s->tr255); + break; + case E_DTSEC_STAT_TR511: + ret_val = ioread32be(®s->tr511); + break; + case E_DTSEC_STAT_TR1K: + ret_val = ioread32be(®s->tr1k); + break; + case E_DTSEC_STAT_TRMAX: + ret_val = ioread32be(®s->trmax); + break; + case E_DTSEC_STAT_TRMGV: + ret_val = ioread32be(®s->trmgv); + break; + case E_DTSEC_STAT_RBYT: + ret_val = ioread32be(®s->rbyt); + break; + case E_DTSEC_STAT_RPKT: + ret_val = ioread32be(®s->rpkt); + break; + case E_DTSEC_STAT_RMCA: + ret_val = ioread32be(®s->rmca); + break; + case E_DTSEC_STAT_RBCA: + ret_val = ioread32be(®s->rbca); + break; + case E_DTSEC_STAT_RXPF: + ret_val = ioread32be(®s->rxpf); + break; + case E_DTSEC_STAT_RALN: + ret_val = ioread32be(®s->raln); + break; + case E_DTSEC_STAT_RFLR: + ret_val = ioread32be(®s->rflr); + break; + case E_DTSEC_STAT_RCDE: + ret_val = ioread32be(®s->rcde); + break; + case E_DTSEC_STAT_RCSE: + ret_val = ioread32be(®s->rcse); + break; + case E_DTSEC_STAT_RUND: + ret_val = ioread32be(®s->rund); + break; + case E_DTSEC_STAT_ROVR: + ret_val = ioread32be(®s->rovr); + break; + case E_DTSEC_STAT_RFRG: + ret_val = ioread32be(®s->rfrg); + break; + case E_DTSEC_STAT_RJBR: + ret_val = ioread32be(®s->rjbr); + break; + case E_DTSEC_STAT_RDRP: + ret_val = ioread32be(®s->rdrp); + break; + case E_DTSEC_STAT_TFCS: + ret_val = ioread32be(®s->tfcs); + break; + case E_DTSEC_STAT_TBYT: + ret_val = ioread32be(®s->tbyt); + break; + case E_DTSEC_STAT_TPKT: + ret_val = ioread32be(®s->tpkt); + break; + case E_DTSEC_STAT_TMCA: + ret_val = ioread32be(®s->tmca); + break; + case E_DTSEC_STAT_TBCA: + ret_val = ioread32be(®s->tbca); + break; + case E_DTSEC_STAT_TXPF: + ret_val = ioread32be(®s->txpf); + break; + case E_DTSEC_STAT_TNCL: + ret_val = ioread32be(®s->tncl); + break; + case E_DTSEC_STAT_TDRP: + ret_val = ioread32be(®s->tdrp); + break; + default: + ret_val = 0; + } + + return ret_val; +} diff --git a/drivers/net/ethernet/freescale/fman/Peripherals/FM/MAC/fman_dtsec_mii_acc.c b/drivers/net/ethernet/freescale/fman/Peripherals/FM/MAC/fman_dtsec_mii_acc.c new file mode 100644 index 0000000..b1b7bae --- /dev/null +++ b/drivers/net/ethernet/freescale/fman/Peripherals/FM/MAC/fman_dtsec_mii_acc.c @@ -0,0 +1,149 @@ +/* + * Copyright 2008-2012 Freescale Semiconductor Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Freescale Semiconductor nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + +#include "common/general.h" +#include "fsl_fman_dtsec_mii_acc.h" + + +/** + * dtsec_mii_get_div() - calculates the value of the dtsec mii divider + * @dtsec_freq: dtsec clock frequency (in Mhz) + * + * This function calculates the dtsec mii clock divider that determines + * the MII MDC clock. MII MDC clock can work in the range of 2.5 to 12.5 Mhz. + * The output of this function is the value of MIIMCFG[MgmtClk] which + * implicitly determines the divider value. + * Note: the dTSEC system clock is equal to 1/2 of the FMan clock. + * + * The table below which reflects dtsec_mii_get_div() functionality + * shows the relations among dtsec_freq, MgmtClk, actual divider + * and the MII frequency: + * + * dtsec freq MgmtClk div MII freq + * [80..159] 0 (1/4)(1/8) [2.5 to 5.0] + * [160..319] 1 (1/4)(1/8) [5.0 to 10.0] + * [320..479] 2 (1/6)(1/8) [6.7 to 10.0] + * [480..639] 3 (1/8)(1/8) [7.5 to 10.0] + * [640..799] 4 (1/10)(1/8) [8.0 to 10.0] + * [800..959] 5 (1/14)(1/8) [7.1 to 8.5] + * [960..1119] 6 (1/20)(1/8) [6.0 to 7.0] + * [1120..1279] 7 (1/28)(1/8) [5.0 to 5.7] + * [1280..2800] 7 (1/28)(1/8) [5.7 to 12.5] + * + * Returns: the MIIMCFG[MgmtClk] appropriate value + */ + +static uint8_t dtsec_mii_get_div(uint16_t dtsec_freq) +{ + uint16_t mgmt_clk = (uint16_t)(dtsec_freq / 160); + + if (mgmt_clk > 7) + mgmt_clk = 7; + + return (uint8_t)mgmt_clk; +} + +void dtsec_mii_reset(struct dtsec_mii_reg *regs) +{ + /* Reset the management interface */ + iowrite32be(ioread32be(®s->miimcfg) | MIIMCFG_RESET_MGMT, + ®s->miimcfg); + iowrite32be(ioread32be(®s->miimcfg) & ~MIIMCFG_RESET_MGMT, + ®s->miimcfg); +} + +void dtsec_mii_init(struct dtsec_mii_reg *regs, uint16_t dtsec_freq) +{ + /* Setup the MII Mgmt clock speed */ + iowrite32be((uint32_t)dtsec_mii_get_div(dtsec_freq), ®s->miimcfg); +} + +int dtsec_mii_write_reg(struct dtsec_mii_reg *regs, uint8_t addr, + uint8_t reg, uint16_t data) +{ + uint32_t tmp; + + /* Stop the MII management read cycle */ + iowrite32be(0, ®s->miimcom); + /* Dummy read to make sure MIIMCOM is written */ + tmp = ioread32be(®s->miimcom); + + /* Setting up MII Management Address Register */ + tmp = (uint32_t)((addr << MIIMADD_PHY_ADDR_SHIFT) | reg); + iowrite32be(tmp, ®s->miimadd); + + /* Setting up MII Management Control Register with data */ + iowrite32be((uint32_t)data, ®s->miimcon); + /* Dummy read to make sure MIIMCON is written */ + tmp = ioread32be(®s->miimcon); + + /* Wait untill MII management write is complete */ + /* todo: a timeout could be useful here */ + while ((ioread32be(®s->miimind)) & MIIMIND_BUSY) + /* busy wait */; + + return 0; +} + +int dtsec_mii_read_reg(struct dtsec_mii_reg *regs, uint8_t addr, + uint8_t reg, uint16_t *data) +{ + uint32_t tmp; + + /* Setting up the MII Management Address Register */ + tmp = (uint32_t)((addr << MIIMADD_PHY_ADDR_SHIFT) | reg); + iowrite32be(tmp, ®s->miimadd); + + /* Perform an MII management read cycle */ + iowrite32be(MIIMCOM_READ_CYCLE, ®s->miimcom); + /* Dummy read to make sure MIIMCOM is written */ + tmp = ioread32be(®s->miimcom); + + /* Wait until MII management read is complete */ + /* todo: a timeout could be useful here */ + while ((ioread32be(®s->miimind)) & MIIMIND_BUSY) + /* busy wait */; + + /* Read MII management status */ + *data = (uint16_t)ioread32be(®s->miimstat); + + iowrite32be(0, ®s->miimcom); + /* Dummy read to make sure MIIMCOM is written */ + tmp = ioread32be(®s->miimcom); + + if (*data == 0xffff) + return -ENXIO; + + return 0; +} + diff --git a/drivers/net/ethernet/freescale/fman/Peripherals/FM/MAC/fman_memac.c b/drivers/net/ethernet/freescale/fman/Peripherals/FM/MAC/fman_memac.c new file mode 100644 index 0000000..a63d06a --- /dev/null +++ b/drivers/net/ethernet/freescale/fman/Peripherals/FM/MAC/fman_memac.c @@ -0,0 +1,427 @@ +/* + * Copyright 2008-2012 Freescale Semiconductor Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Freescale Semiconductor nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + +#include "fsl_fman_memac.h" + + +uint32_t memac_get_event(struct memac_regs *regs, uint32_t ev_mask) +{ + return ioread32be(®s->ievent) & ev_mask; +} + +uint32_t memac_get_interrupt_mask(struct memac_regs *regs) +{ + return ioread32be(®s->imask); +} + +void memac_ack_event(struct memac_regs *regs, uint32_t ev_mask) +{ + iowrite32be(ev_mask, ®s->ievent); +} + +void memac_set_promiscuous(struct memac_regs *regs, bool val) +{ + uint32_t tmp; + + tmp = ioread32be(®s->command_config); + + if (val) + tmp |= CMD_CFG_PROMIS_EN; + else + tmp &= ~CMD_CFG_PROMIS_EN; + + iowrite32be(tmp, ®s->command_config); +} + +void memac_hardware_clear_addr_in_paddr(struct memac_regs *regs, + uint8_t paddr_num) +{ + if (paddr_num == 0) { + iowrite32be(0, ®s->mac_addr0.mac_addr_l); + iowrite32be(0, ®s->mac_addr0.mac_addr_u); + } else { + iowrite32be(0x0, ®s->mac_addr[paddr_num - 1].mac_addr_l); + iowrite32be(0x0, ®s->mac_addr[paddr_num - 1].mac_addr_u); + } +} + +void memac_hardware_add_addr_in_paddr(struct memac_regs *regs, + uint8_t *adr, + uint8_t paddr_num) +{ + uint32_t tmp0, tmp1; + + tmp0 = (uint32_t)(adr[0] | + adr[1] << 8 | + adr[2] << 16 | + adr[3] << 24); + tmp1 = (uint32_t)(adr[4] | adr[5] << 8); + + if (paddr_num == 0) { + iowrite32be(tmp0, ®s->mac_addr0.mac_addr_l); + iowrite32be(tmp1, ®s->mac_addr0.mac_addr_u); + } else { + iowrite32be(tmp0, ®s->mac_addr[paddr_num-1].mac_addr_l); + iowrite32be(tmp1, ®s->mac_addr[paddr_num-1].mac_addr_u); + } +} + +void memac_enable(struct memac_regs *regs, bool apply_rx, bool apply_tx) +{ + uint32_t tmp; + + tmp = ioread32be(®s->command_config); + + if (apply_rx) + tmp |= CMD_CFG_RX_EN; + + if (apply_tx) + tmp |= CMD_CFG_TX_EN; + + iowrite32be(tmp, ®s->command_config); +} + +void memac_disable(struct memac_regs *regs, bool apply_rx, bool apply_tx) +{ + uint32_t tmp; + + tmp = ioread32be(®s->command_config); + + if (apply_rx) + tmp &= ~CMD_CFG_RX_EN; + + if (apply_tx) + tmp &= ~CMD_CFG_TX_EN; + + iowrite32be(tmp, ®s->command_config); +} + +void memac_reset_counter(struct memac_regs *regs) +{ + uint32_t tmp; + + tmp = ioread32be(®s->statn_config); + + tmp |= STATS_CFG_CLR; + + iowrite32be(tmp, ®s->statn_config); + + while (ioread32be(®s->statn_config) & STATS_CFG_CLR); +} + +void memac_reset(struct memac_regs *regs) +{ + uint32_t tmp; + + tmp = ioread32be(®s->command_config); + + tmp |= CMD_CFG_SW_RESET; + + iowrite32be(tmp, ®s->command_config); + + while (ioread32be(®s->command_config) & CMD_CFG_SW_RESET); +} + +void memac_init(struct memac_regs *regs, + struct memac_cfg *cfg, + enum enet_interface enet_interface, + enum enet_speed enet_speed, + uint32_t exceptions) +{ + uint32_t tmp; + + /* Config */ + tmp = 0; + if (cfg->wan_mode_enable) + tmp |= CMD_CFG_WAN_MODE; + if (cfg->promiscuous_mode_enable) + tmp |= CMD_CFG_PROMIS_EN; + if (cfg->pause_forward_enable) + tmp |= CMD_CFG_PAUSE_FWD; + if (cfg->pause_ignore) + tmp |= CMD_CFG_PAUSE_IGNORE; + if (cfg->tx_addr_ins_enable) + tmp |= CMD_CFG_TX_ADDR_INS; + if (cfg->loopback_enable) + tmp |= CMD_CFG_LOOPBACK_EN; + if (cfg->cmd_frame_enable) + tmp |= CMD_CFG_CNT_FRM_EN; + if (cfg->send_idle_enable) + tmp |= CMD_CFG_SEND_IDLE; + if (cfg->no_length_check_enable) + tmp |= CMD_CFG_NO_LEN_CHK; + if (cfg->rx_sfd_any) + tmp |= CMD_CFG_SFD_ANY; + if (cfg->pad_enable) + tmp |= CMD_CFG_TX_PAD_EN; + + tmp |= CMD_CFG_CRC_FWD; + + iowrite32be(tmp, ®s->command_config); + + /* Max Frame Length */ + iowrite32be((uint32_t)cfg->max_frame_length, ®s->maxfrm); + + /* Pause Time */ + iowrite32be(cfg->pause_quanta, ®s->pause_quanta[0]); + iowrite32be(0, ®s->pause_thresh[0]); + + /* interrupts */ + iowrite32be(MEMAC_EVENTS_MASK, ®s->ievent); + iowrite32be(exceptions, ®s->imask); + + /* IF_MODE */ + tmp = 0; + switch (enet_interface) { + case E_ENET_IF_XGMII: + case E_ENET_IF_XFI: + tmp |= IF_MODE_XGMII; + break; + default: + tmp |= IF_MODE_GMII; + if (enet_interface == E_ENET_IF_RGMII) + tmp |= IF_MODE_RGMII | IF_MODE_RGMII_AUTO; + } + iowrite32be(tmp, ®s->if_mode); +} + +void memac_set_exception(struct memac_regs *regs, uint32_t val, bool enable) +{ + uint32_t tmp; + + tmp = ioread32be(®s->imask); + if (enable) + tmp |= val; + else + tmp &= ~val; + + iowrite32be(tmp, ®s->imask); +} + +void memac_set_hash_table(struct memac_regs *regs, uint32_t val) +{ + iowrite32be(val, ®s->hashtable_ctrl); +} + +uint16_t memac_get_max_frame_length(struct memac_regs *regs) +{ + uint32_t tmp; + + tmp = ioread32be(®s->maxfrm); + + return(uint16_t)tmp; +} + + +void memac_set_tx_pause_frames(struct memac_regs *regs, + uint8_t priority, + uint16_t pause_time, + uint16_t thresh_time) +{ + uint32_t tmp; + + tmp = ioread32be(®s->command_config); + if (priority == 0xff) { + tmp &= ~CMD_CFG_PFC_MODE; + priority = 0; + } + else + tmp |= CMD_CFG_PFC_MODE; + + iowrite32be(tmp, ®s->command_config); + + tmp = ioread32be(®s->pause_quanta[priority / 2]); + if (priority % 2) + tmp &= 0x0000FFFF; + else + tmp &= 0xFFFF0000; + tmp |= ((uint32_t)pause_time << (16 * (priority % 2))); + iowrite32be(tmp, ®s->pause_quanta[priority / 2]); + + tmp = ioread32be(®s->pause_thresh[priority / 2]); + if (priority % 2) + tmp &= 0x0000FFFF; + else + tmp &= 0xFFFF0000; + tmp |= ((uint32_t)thresh_time<<(16 * (priority % 2))); + iowrite32be(tmp, ®s->pause_thresh[priority / 2]); +} + +void memac_set_rx_ignore_pause_frames(struct memac_regs *regs,bool enable) +{ + uint32_t tmp; + + tmp = ioread32be(®s->command_config); + if (enable) + tmp |= CMD_CFG_PAUSE_IGNORE; + else + tmp &= ~CMD_CFG_PAUSE_IGNORE; + + iowrite32be(tmp, ®s->command_config); +} + +void memac_set_loopback(struct memac_regs *regs, bool enable) +{ + uint32_t tmp; + + tmp = ioread32be(®s->command_config); + + if (enable) + tmp |= CMD_CFG_LOOPBACK_EN; + else + tmp &= ~CMD_CFG_LOOPBACK_EN; + + iowrite32be(tmp, ®s->command_config); +} + + +#define GET_MEMAC_CNTR_64(bn) \ + (ioread32be(®s->bn ## _l) | \ + ((uint64_t)ioread32be(®s->bn ## _u) << 32)) + +uint64_t memac_get_counter(struct memac_regs *regs, + enum memac_counters reg_name) +{ + uint64_t ret_val; + + switch (reg_name) { + case E_MEMAC_COUNTER_R64: + ret_val = GET_MEMAC_CNTR_64(r64); + break; + case E_MEMAC_COUNTER_R127: + ret_val = GET_MEMAC_CNTR_64(r127); + break; + case E_MEMAC_COUNTER_R255: + ret_val = GET_MEMAC_CNTR_64(r255); + break; + case E_MEMAC_COUNTER_R511: + ret_val = GET_MEMAC_CNTR_64(r511); + break; + case E_MEMAC_COUNTER_R1023: + ret_val = GET_MEMAC_CNTR_64(r1023); + break; + case E_MEMAC_COUNTER_R1518: + ret_val = GET_MEMAC_CNTR_64(r1518); + break; + case E_MEMAC_COUNTER_R1519X: + ret_val = GET_MEMAC_CNTR_64(r1519x); + break; + case E_MEMAC_COUNTER_RFRG: + ret_val = GET_MEMAC_CNTR_64(rfrg); + break; + case E_MEMAC_COUNTER_RJBR: + ret_val = GET_MEMAC_CNTR_64(rjbr); + break; + case E_MEMAC_COUNTER_RDRP: + ret_val = GET_MEMAC_CNTR_64(rdrp); + break; + case E_MEMAC_COUNTER_RALN: + ret_val = GET_MEMAC_CNTR_64(raln); + break; + case E_MEMAC_COUNTER_TUND: + ret_val = GET_MEMAC_CNTR_64(tund); + break; + case E_MEMAC_COUNTER_ROVR: + ret_val = GET_MEMAC_CNTR_64(rovr); + break; + case E_MEMAC_COUNTER_RXPF: + ret_val = GET_MEMAC_CNTR_64(rxpf); + break; + case E_MEMAC_COUNTER_TXPF: + ret_val = GET_MEMAC_CNTR_64(txpf); + break; + case E_MEMAC_COUNTER_ROCT: + ret_val = GET_MEMAC_CNTR_64(roct); + break; + case E_MEMAC_COUNTER_RMCA: + ret_val = GET_MEMAC_CNTR_64(rmca); + break; + case E_MEMAC_COUNTER_RBCA: + ret_val = GET_MEMAC_CNTR_64(rbca); + break; + case E_MEMAC_COUNTER_RPKT: + ret_val = GET_MEMAC_CNTR_64(rpkt); + break; + case E_MEMAC_COUNTER_RUCA: + ret_val = GET_MEMAC_CNTR_64(ruca); + break; + case E_MEMAC_COUNTER_RERR: + ret_val = GET_MEMAC_CNTR_64(rerr); + break; + case E_MEMAC_COUNTER_TOCT: + ret_val = GET_MEMAC_CNTR_64(toct); + break; + case E_MEMAC_COUNTER_TMCA: + ret_val = GET_MEMAC_CNTR_64(tmca); + break; + case E_MEMAC_COUNTER_TBCA: + ret_val = GET_MEMAC_CNTR_64(tbca); + break; + case E_MEMAC_COUNTER_TUCA: + ret_val = GET_MEMAC_CNTR_64(tuca); + break; + case E_MEMAC_COUNTER_TERR: + ret_val = GET_MEMAC_CNTR_64(terr); + break; + default: + ret_val = 0; + } + + return ret_val; +} + +void memac_defconfig(struct memac_cfg *cfg) +{ + cfg->reset_on_init = FALSE; + cfg->wan_mode_enable = FALSE; + cfg->promiscuous_mode_enable = FALSE; + cfg->pause_forward_enable = FALSE; + cfg->pause_ignore = FALSE; + cfg->tx_addr_ins_enable = FALSE; + cfg->loopback_enable = FALSE; + cfg->cmd_frame_enable = FALSE; + cfg->rx_error_discard = FALSE; + cfg->send_idle_enable = FALSE; + cfg->no_length_check_enable = TRUE; + cfg->lgth_check_nostdr = FALSE; + cfg->time_stamp_enable = FALSE; + cfg->tx_ipg_length = DEFAULT_TX_IPG_LENGTH; + cfg->max_frame_length = DEFAULT_FRAME_LENGTH; + cfg->pause_quanta = DEFAULT_PAUSE_QUANTA; + cfg->pad_enable = TRUE; + cfg->phy_tx_ena_on = FALSE; + cfg->rx_sfd_any = FALSE; + cfg->rx_pbl_fwd = FALSE; + cfg->tx_pbl_fwd = FALSE; + cfg->debug_mode = FALSE; +} diff --git a/drivers/net/ethernet/freescale/fman/Peripherals/FM/MAC/fman_tgec.c b/drivers/net/ethernet/freescale/fman/Peripherals/FM/MAC/fman_tgec.c new file mode 100644 index 0000000..fa80a36 --- /dev/null +++ b/drivers/net/ethernet/freescale/fman/Peripherals/FM/MAC/fman_tgec.c @@ -0,0 +1,355 @@ +/* + * Copyright 2008-2012 Freescale Semiconductor Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Freescale Semiconductor nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + +#include "fsl_fman_tgec.h" + + +void tgec_set_mac_address(struct tgec_regs *regs, uint8_t *adr) +{ + uint32_t tmp0, tmp1; + + tmp0 = (uint32_t)(adr[0] | + adr[1] << 8 | + adr[2] << 16 | + adr[3] << 24); + tmp1 = (uint32_t)(adr[4] | adr[5] << 8); + iowrite32be(tmp0, ®s->mac_addr_0); + iowrite32be(tmp1, ®s->mac_addr_1); +} + +void tgec_reset_stat(struct tgec_regs *regs) +{ + uint32_t tmp; + + tmp = ioread32be(®s->command_config); + + tmp |= CMD_CFG_STAT_CLR; + + iowrite32be(tmp, ®s->command_config); + + while (ioread32be(®s->command_config) & CMD_CFG_STAT_CLR); +} + +#define GET_TGEC_CNTR_64(bn) \ + (((uint64_t)ioread32be(®s->bn ## _u) << 32) | \ + ioread32be(®s->bn ## _l)) + +uint64_t tgec_get_counter(struct tgec_regs *regs, enum tgec_counters reg_name) +{ + uint64_t ret_val; + + switch (reg_name) { + case E_TGEC_COUNTER_R64: + ret_val = GET_TGEC_CNTR_64(r64); + break; + case E_TGEC_COUNTER_R127: + ret_val = GET_TGEC_CNTR_64(r127); + break; + case E_TGEC_COUNTER_R255: + ret_val = GET_TGEC_CNTR_64(r255); + break; + case E_TGEC_COUNTER_R511: + ret_val = GET_TGEC_CNTR_64(r511); + break; + case E_TGEC_COUNTER_R1023: + ret_val = GET_TGEC_CNTR_64(r1023); + break; + case E_TGEC_COUNTER_R1518: + ret_val = GET_TGEC_CNTR_64(r1518); + break; + case E_TGEC_COUNTER_R1519X: + ret_val = GET_TGEC_CNTR_64(r1519x); + break; + case E_TGEC_COUNTER_TRFRG: + ret_val = GET_TGEC_CNTR_64(trfrg); + break; + case E_TGEC_COUNTER_TRJBR: + ret_val = GET_TGEC_CNTR_64(trjbr); + break; + case E_TGEC_COUNTER_RDRP: + ret_val = GET_TGEC_CNTR_64(rdrp); + break; + case E_TGEC_COUNTER_RALN: + ret_val = GET_TGEC_CNTR_64(raln); + break; + case E_TGEC_COUNTER_TRUND: + ret_val = GET_TGEC_CNTR_64(trund); + break; + case E_TGEC_COUNTER_TROVR: + ret_val = GET_TGEC_CNTR_64(trovr); + break; + case E_TGEC_COUNTER_RXPF: + ret_val = GET_TGEC_CNTR_64(rxpf); + break; + case E_TGEC_COUNTER_TXPF: + ret_val = GET_TGEC_CNTR_64(txpf); + break; + case E_TGEC_COUNTER_ROCT: + ret_val = GET_TGEC_CNTR_64(roct); + break; + case E_TGEC_COUNTER_RMCA: + ret_val = GET_TGEC_CNTR_64(rmca); + break; + case E_TGEC_COUNTER_RBCA: + ret_val = GET_TGEC_CNTR_64(rbca); + break; + case E_TGEC_COUNTER_RPKT: + ret_val = GET_TGEC_CNTR_64(rpkt); + break; + case E_TGEC_COUNTER_RUCA: + ret_val = GET_TGEC_CNTR_64(ruca); + break; + case E_TGEC_COUNTER_RERR: + ret_val = GET_TGEC_CNTR_64(rerr); + break; + case E_TGEC_COUNTER_TOCT: + ret_val = GET_TGEC_CNTR_64(toct); + break; + case E_TGEC_COUNTER_TMCA: + ret_val = GET_TGEC_CNTR_64(tmca); + break; + case E_TGEC_COUNTER_TBCA: + ret_val = GET_TGEC_CNTR_64(tbca); + break; + case E_TGEC_COUNTER_TUCA: + ret_val = GET_TGEC_CNTR_64(tuca); + break; + case E_TGEC_COUNTER_TERR: + ret_val = GET_TGEC_CNTR_64(terr); + break; + default: + ret_val = 0; + } + + return ret_val; +} + +void tgec_enable(struct tgec_regs *regs, bool apply_rx, bool apply_tx) +{ + uint32_t tmp; + + tmp = ioread32be(®s->command_config); + if (apply_rx) + tmp |= CMD_CFG_RX_EN; + if (apply_tx) + tmp |= CMD_CFG_TX_EN; + iowrite32be(tmp, ®s->command_config); +} + +void tgec_disable(struct tgec_regs *regs, bool apply_rx, bool apply_tx) +{ + uint32_t tmp_reg_32; + + tmp_reg_32 = ioread32be(®s->command_config); + if (apply_rx) + tmp_reg_32 &= ~CMD_CFG_RX_EN; + if (apply_tx) + tmp_reg_32 &= ~CMD_CFG_TX_EN; + iowrite32be(tmp_reg_32, ®s->command_config); +} + +void tgec_set_promiscuous(struct tgec_regs *regs, bool val) +{ + uint32_t tmp; + + tmp = ioread32be(®s->command_config); + + if (val) + tmp |= CMD_CFG_PROMIS_EN; + else + tmp &= ~CMD_CFG_PROMIS_EN; + + iowrite32be(tmp, ®s->command_config); +} + +void tgec_set_hash_table(struct tgec_regs *regs, uint32_t value) +{ + iowrite32be(value, ®s->hashtable_ctrl); +} + +void tgec_tx_mac_pause(struct tgec_regs *regs, uint16_t pause_time) +{ + iowrite32be((uint32_t)pause_time, ®s->pause_quant); +} + +void tgec_rx_ignore_mac_pause(struct tgec_regs *regs, bool en) +{ + uint32_t tmp; + + tmp = ioread32be(®s->command_config); + if (en) + tmp |= CMD_CFG_PAUSE_IGNORE; + else + tmp &= ~CMD_CFG_PAUSE_IGNORE; + iowrite32be(tmp, ®s->command_config); +} + +void tgec_enable_1588_time_stamp(struct tgec_regs *regs, bool en) +{ + uint32_t tmp; + + tmp = ioread32be(®s->command_config); + if (en) + tmp |= CMD_CFG_EN_TIMESTAMP; + else + tmp &= ~CMD_CFG_EN_TIMESTAMP; + iowrite32be(tmp, ®s->command_config); +} + +uint32_t tgec_get_event(struct tgec_regs *regs, uint32_t ev_mask) +{ + return ioread32be(®s->ievent) & ev_mask; +} + +void tgec_ack_event(struct tgec_regs *regs, uint32_t ev_mask) +{ + iowrite32be(ev_mask, ®s->ievent); +} + +uint32_t tgec_get_interrupt_mask(struct tgec_regs *regs) +{ + return ioread32be(®s->imask); +} + +void tgec_add_addr_in_paddr(struct tgec_regs *regs, uint8_t *adr) +{ + uint32_t tmp0, tmp1; + + tmp0 = (uint32_t)(adr[0] | + adr[1] << 8 | + adr[2] << 16 | + adr[3] << 24); + tmp1 = (uint32_t)(adr[4] | adr[5] << 8); + iowrite32be(tmp0, ®s->mac_addr_2); + iowrite32be(tmp1, ®s->mac_addr_3); +} + +void tgec_clear_addr_in_paddr(struct tgec_regs *regs) +{ + iowrite32be(0, ®s->mac_addr_2); + iowrite32be(0, ®s->mac_addr_3); +} + +uint32_t tgec_get_revision(struct tgec_regs *regs) +{ + return ioread32be(®s->tgec_id); +} + +void tgec_enable_interrupt(struct tgec_regs *regs, uint32_t ev_mask) +{ + iowrite32be(ioread32be(®s->imask) | ev_mask, ®s->imask); +} + +void tgec_disable_interrupt(struct tgec_regs *regs, uint32_t ev_mask) +{ + iowrite32be(ioread32be(®s->imask) & ~ev_mask, ®s->imask); +} + +uint16_t tgec_get_max_frame_len(struct tgec_regs *regs) +{ + return (uint16_t) ioread32be(®s->maxfrm); +} + +void tgec_defconfig(struct tgec_cfg *cfg) +{ + cfg->wan_mode_enable = DEFAULT_WAN_MODE_ENABLE; + cfg->promiscuous_mode_enable = DEFAULT_PROMISCUOUS_MODE_ENABLE; + cfg->pause_forward_enable = DEFAULT_PAUSE_FORWARD_ENABLE; + cfg->pause_ignore = DEFAULT_PAUSE_IGNORE; + cfg->tx_addr_ins_enable = DEFAULT_TX_ADDR_INS_ENABLE; + cfg->loopback_enable = DEFAULT_LOOPBACK_ENABLE; + cfg->cmd_frame_enable = DEFAULT_CMD_FRAME_ENABLE; + cfg->rx_error_discard = DEFAULT_RX_ERROR_DISCARD; + cfg->send_idle_enable = DEFAULT_SEND_IDLE_ENABLE; + cfg->no_length_check_enable = DEFAULT_NO_LENGTH_CHECK_ENABLE; + cfg->lgth_check_nostdr = DEFAULT_LGTH_CHECK_NOSTDR; + cfg->time_stamp_enable = DEFAULT_TIME_STAMP_ENABLE; + cfg->tx_ipg_length = DEFAULT_TX_IPG_LENGTH; + cfg->max_frame_length = DEFAULT_MAX_FRAME_LENGTH; + cfg->pause_quant = DEFAULT_PAUSE_QUANT; +#ifdef FM_TX_ECC_FRMS_ERRATA_10GMAC_A004 + cfg->skip_fman11_workaround = FALSE; +#endif /* FM_TX_ECC_FRMS_ERRATA_10GMAC_A004 */ +} + +int tgec_init(struct tgec_regs *regs, struct tgec_cfg *cfg, + uint32_t exception_mask) +{ + uint32_t tmp; + + /* Config */ + tmp = 0x40; /* CRC forward */ + if (cfg->wan_mode_enable) + tmp |= CMD_CFG_WAN_MODE; + if (cfg->promiscuous_mode_enable) + tmp |= CMD_CFG_PROMIS_EN; + if (cfg->pause_forward_enable) + tmp |= CMD_CFG_PAUSE_FWD; + if (cfg->pause_ignore) + tmp |= CMD_CFG_PAUSE_IGNORE; + if (cfg->tx_addr_ins_enable) + tmp |= CMD_CFG_TX_ADDR_INS; + if (cfg->loopback_enable) + tmp |= CMD_CFG_LOOPBACK_EN; + if (cfg->cmd_frame_enable) + tmp |= CMD_CFG_CMD_FRM_EN; + if (cfg->rx_error_discard) + tmp |= CMD_CFG_RX_ER_DISC; + if (cfg->send_idle_enable) + tmp |= CMD_CFG_SEND_IDLE; + if (cfg->no_length_check_enable) + tmp |= CMD_CFG_NO_LEN_CHK; + if (cfg->time_stamp_enable) + tmp |= CMD_CFG_EN_TIMESTAMP; + iowrite32be(tmp, ®s->command_config); + /* Max Frame Length */ + iowrite32be((uint32_t)cfg->max_frame_length, ®s->maxfrm); + /* Pause Time */ + iowrite32be(cfg->pause_quant, ®s->pause_quant); + + /* clear all pending events and set-up interrupts */ + tgec_ack_event(regs, 0xffffffff); + tgec_enable_interrupt(regs, exception_mask); + return 0; +} + +void tgec_fm_tx_fifo_corruption_errata_10gmac_a007(struct tgec_regs *regs) +{ + uint32_t tmp; + + /* restore the default tx ipg Length */ + tmp = (ioread32be(®s->tx_ipg_len) & ~TX_IPG_LENGTH_MASK) | 12; + + iowrite32be(tmp, ®s->tx_ipg_len); + +} diff --git a/drivers/net/ethernet/freescale/fman/Peripherals/FM/MAC/fsl_fman_dtsec_mii_acc.h b/drivers/net/ethernet/freescale/fman/Peripherals/FM/MAC/fsl_fman_dtsec_mii_acc.h new file mode 100644 index 0000000..2d74b6a --- /dev/null +++ b/drivers/net/ethernet/freescale/fman/Peripherals/FM/MAC/fsl_fman_dtsec_mii_acc.h @@ -0,0 +1,102 @@ +/* + * Copyright 2008-2012 Freescale Semiconductor Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Freescale Semiconductor nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + +#ifndef __FSL_FMAN_DTSEC_MII_ACC_H +#define __FSL_FMAN_DTSEC_MII_ACC_H + +#include "common/general.h" + + +/* MII Management Configuration Register */ +#define MIIMCFG_RESET_MGMT 0x80000000 +#define MIIMCFG_MGNTCLK_MASK 0x00000007 +#define MIIMCFG_MGNTCLK_SHIFT 0 + +/* MII Management Command Register */ +#define MIIMCOM_SCAN_CYCLE 0x00000002 +#define MIIMCOM_READ_CYCLE 0x00000001 + +/* MII Management Address Register */ +#define MIIMADD_PHY_ADDR_SHIFT 8 +#define MIIMADD_PHY_ADDR_MASK 0x00001f00 + +#define MIIMADD_REG_ADDR_SHIFT 0 +#define MIIMADD_REG_ADDR_MASK 0x0000001f + +/* MII Management Indicator Register */ +#define MIIMIND_BUSY 0x00000001 + + +/* PHY Control Register */ +#define PHY_CR_LOOPBACK 0x4000 +#define PHY_CR_SPEED0 0x2000 +#define PHY_CR_ANE 0x1000 +#define PHY_CR_FULLDUPLEX 0x0100 +#define PHY_CR_SPEED1 0x0040 + +#define PHY_TBICON_SRESET 0x8000 +#define PHY_TBICON_SPEED2 0x0020 + +/* register map */ + +/* MII Configuration Control Memory Map Registers */ +struct dtsec_mii_reg { + uint32_t reserved1[72]; + uint32_t miimcfg; /* MII Mgmt:configuration */ + uint32_t miimcom; /* MII Mgmt:command */ + uint32_t miimadd; /* MII Mgmt:address */ + uint32_t miimcon; /* MII Mgmt:control 3 */ + uint32_t miimstat; /* MII Mgmt:status */ + uint32_t miimind; /* MII Mgmt:indicators */ +}; + +/* dTSEC MII API */ + +/* functions to access the mii registers for phy configuration. + * this functionality may not be available for all dtsecs in the system. + * consult the reference manual for details */ +void dtsec_mii_reset(struct dtsec_mii_reg *regs); +/* frequency is in MHz. + * note that dtsec clock is 1/2 of fman clock */ +void dtsec_mii_init(struct dtsec_mii_reg *regs, uint16_t dtsec_freq); +int dtsec_mii_write_reg(struct dtsec_mii_reg *regs, + uint8_t addr, + uint8_t reg, + uint16_t data); + +int dtsec_mii_read_reg(struct dtsec_mii_reg *regs, + uint8_t addr, + uint8_t reg, + uint16_t *data); + +#endif /* __FSL_FMAN_DTSEC_MII_ACC_H */ diff --git a/drivers/net/ethernet/freescale/fman/Peripherals/FM/MAC/memac.c b/drivers/net/ethernet/freescale/fman/Peripherals/FM/MAC/memac.c new file mode 100644 index 0000000..6e5440d --- /dev/null +++ b/drivers/net/ethernet/freescale/fman/Peripherals/FM/MAC/memac.c @@ -0,0 +1,1036 @@ +/* + * Copyright 2008-2012 Freescale Semiconductor Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Freescale Semiconductor nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + +/****************************************************************************** + @File memac.c + + @Description FM mEMAC driver +*//***************************************************************************/ + +#include "std_ext.h" +#include "string_ext.h" +#include "error_ext.h" +#include "xx_ext.h" +#include "endian_ext.h" +#include "debug_ext.h" + +#include "fm_common.h" +#include "memac.h" + + +/*****************************************************************************/ +/* Internal routines */ +/*****************************************************************************/ + +/* ......................................................................... */ + +static uint32_t GetMacAddrHashCode(uint64_t ethAddr) +{ + uint64_t mask1, mask2; + uint32_t xor = 0; + uint8_t i, j; + + for (i=0; i < 6; i++) + { + mask1 = ethAddr & (uint64_t)0x01; + ethAddr >>= 1; + + for (j=0; j < 7; j++) + { + mask2 = ethAddr & (uint64_t)0x01; + mask1 ^= mask2; + ethAddr >>= 1; + } + xor |= (mask1 << (5-i)); + } + + return xor; +} + + +/* ......................................................................... */ + +static void SetupSgmiiInternalPhy(t_Memac *p_Memac, uint8_t phyAddr) +{ + uint16_t tmpReg16; + + /* SGMII mode + AN enable */ + tmpReg16 = PHY_SGMII_IF_MODE_AN | PHY_SGMII_IF_MODE_SGMII; + MEMAC_MII_WritePhyReg(p_Memac, phyAddr, 0x14, tmpReg16); + + /* Device ability according to SGMII specification */ + tmpReg16 = PHY_SGMII_DEV_ABILITY_SGMII; + MEMAC_MII_WritePhyReg(p_Memac, phyAddr, 0x4, tmpReg16); + + /* Adjust link timer for SGMII - + According to Cisco SGMII specification the timer should be 1.6 ms. + The link_timer register is configured in units of the clock. + - When running as 1G SGMII, Serdes clock is 125 MHz, so + unit = 1 / (125*10^6 Hz) = 8 ns. + 1.6 ms in units of 8 ns = 1.6ms / 8ns = 2 * 10^5 = 0x30d40 + - When running as 2.5G SGMII, Serdes clock is 312.5 MHz, so + unit = 1 / (312.5*10^6 Hz) = 3.2 ns. + 1.6 ms in units of 3.2 ns = 1.6ms / 3.2ns = 5 * 10^5 = 0x7a120. + Since link_timer value of 1G SGMII will be too short for 2.5 SGMII, + we always set up here a value of 2.5 SGMII. */ + MEMAC_MII_WritePhyReg(p_Memac, phyAddr, 0x13, 0x0007); + MEMAC_MII_WritePhyReg(p_Memac, phyAddr, 0x12, 0xa120); + + /* Restart AN */ + tmpReg16 = PHY_SGMII_CR_DEF_VAL | PHY_SGMII_CR_RESET_AN; + MEMAC_MII_WritePhyReg(p_Memac, phyAddr, 0x0, tmpReg16); +} + +/* ......................................................................... */ + +static void SetupSgmiiInternalPhyBaseX(t_Memac *p_Memac, uint8_t phyAddr) +{ + uint16_t tmpReg16; + + /* 1000BaseX mode */ + tmpReg16 = PHY_SGMII_IF_MODE_1000X; + MEMAC_MII_WritePhyReg(p_Memac, phyAddr, 0x14, tmpReg16); + + /* AN Device capability */ + tmpReg16 = PHY_SGMII_DEV_ABILITY_1000X; + MEMAC_MII_WritePhyReg(p_Memac, phyAddr, 0x4, tmpReg16); + + /* Adjust link timer for SGMII - + For Serdes 1000BaseX auto-negotiation the timer should be 10 ms. + The link_timer register is configured in units of the clock. + - When running as 1G SGMII, Serdes clock is 125 MHz, so + unit = 1 / (125*10^6 Hz) = 8 ns. + 10 ms in units of 8 ns = 10ms / 8ns = 1250000 = 0x1312d0 + - When running as 2.5G SGMII, Serdes clock is 312.5 MHz, so + unit = 1 / (312.5*10^6 Hz) = 3.2 ns. + 10 ms in units of 3.2 ns = 10ms / 3.2ns = 3125000 = 0x2faf08. + Since link_timer value of 1G SGMII will be too short for 2.5 SGMII, + we always set up here a value of 2.5 SGMII. */ + MEMAC_MII_WritePhyReg(p_Memac, phyAddr, 0x13, 0x002f); + MEMAC_MII_WritePhyReg(p_Memac, phyAddr, 0x12, 0xaf08); + + /* Restart AN */ + tmpReg16 = PHY_SGMII_CR_DEF_VAL | PHY_SGMII_CR_RESET_AN; + MEMAC_MII_WritePhyReg(p_Memac, phyAddr, 0x0, tmpReg16); +} + +/* ......................................................................... */ + +static t_Error CheckInitParameters(t_Memac *p_Memac) +{ + e_FmMacType portType; + + portType = ((ENET_SPEED_FROM_MODE(p_Memac->enetMode) < e_ENET_SPEED_10000) ? e_FM_MAC_1G : e_FM_MAC_10G); + +#if (FM_MAX_NUM_OF_10G_MACS > 0) + if ((portType == e_FM_MAC_10G) && (p_Memac->macId >= FM_MAX_NUM_OF_10G_MACS)) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("10G MAC ID must be less than %d", FM_MAX_NUM_OF_10G_MACS)); +#endif /* (FM_MAX_NUM_OF_10G_MACS > 0) */ + + if ((portType == e_FM_MAC_1G) && (p_Memac->macId >= FM_MAX_NUM_OF_1G_MACS)) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("1G MAC ID must be less than %d", FM_MAX_NUM_OF_1G_MACS)); + if (p_Memac->addr == 0) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("Ethernet MAC must have a valid MAC address")); + if (!p_Memac->f_Exception) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("Uninitialized f_Exception")); + if (!p_Memac->f_Event) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("Uninitialized f_Event")); +#ifdef FM_LEN_CHECK_ERRATA_FMAN_SW002 + if (!p_Memac->p_MemacDriverParam->no_length_check_enable) + RETURN_ERROR(MINOR, E_NOT_SUPPORTED, ("LengthCheck!")); +#endif /* FM_LEN_CHECK_ERRATA_FMAN_SW002 */ + + return E_OK; +} + +/* ........................................................................... */ + +static void MemacErrException(t_Handle h_Memac) +{ + t_Memac *p_Memac = (t_Memac *)h_Memac; + struct memac_regs *regs = p_Memac->p_MemMap; + uint32_t event, imsk; + + event = memac_get_event(regs, 0xffffffff); + + /* + * Apparently the imask bits are shifted by 16 bits offset from + * their corresponding bits in the ievent - hence the >> 16 + */ + imsk = memac_get_interrupt_mask(regs) >> 16;; + + /* + * Extract all event bits plus the pending interrupts according to + * their imask + */ + event = (event & ~(MEMAC_ALL_IMASKS >> 16)) | (event & imsk); + + /* Ignoring the status bits */ + event = event & ~(MEMAC_IEVNT_RX_EMPTY | + MEMAC_IEVNT_TX_EMPTY | + MEMAC_IEVNT_RX_LOWP | + MEMAC_IEVNT_PHY_LOS); + + memac_ack_event(regs, event); + + if (event & MEMAC_IEVNT_RX_FIFO_OVFL) + p_Memac->f_Exception(p_Memac->h_App, e_FM_MAC_EX_10G_RX_FIFO_OVFL); + if (event & MEMAC_IEVNT_TX_FIFO_UNFL) + p_Memac->f_Exception(p_Memac->h_App, e_FM_MAC_EX_10G_TX_FIFO_UNFL); + if (event & MEMAC_IEVNT_TX_FIFO_OVFL) + p_Memac->f_Exception(p_Memac->h_App, e_FM_MAC_EX_10G_TX_FIFO_OVFL); + if (event & MEMAC_IEVNT_TX_ECC_ER) + p_Memac->f_Exception(p_Memac->h_App, e_FM_MAC_EX_10G_1TX_ECC_ER); + if (event & MEMAC_IEVNT_RX_ECC_ER) + p_Memac->f_Exception(p_Memac->h_App, e_FM_MAC_EX_10G_RX_ECC_ER); + if (event & MEMAC_IEVNT_REM_FAULT) + p_Memac->f_Exception(p_Memac->h_App, e_FM_MAC_EX_10G_REM_FAULT); + if (event & MEMAC_IEVNT_LOC_FAULT) + p_Memac->f_Exception(p_Memac->h_App, e_FM_MAC_EX_10G_LOC_FAULT); +} + + +/* ......................................................................... */ + +static void FreeInitResources(t_Memac *p_Memac) +{ + e_FmMacType portType; + + portType = + ((ENET_SPEED_FROM_MODE(p_Memac->enetMode) < e_ENET_SPEED_10000) ? e_FM_MAC_1G : e_FM_MAC_10G); + + if (portType == e_FM_MAC_10G) + FmUnregisterIntr(p_Memac->fmMacControllerDriver.h_Fm, e_FM_MOD_10G_MAC, p_Memac->macId, e_FM_INTR_TYPE_ERR); + else + FmUnregisterIntr(p_Memac->fmMacControllerDriver.h_Fm, e_FM_MOD_1G_MAC, p_Memac->macId, e_FM_INTR_TYPE_ERR); + + /* release the driver's group hash table */ + FreeHashTable(p_Memac->p_MulticastAddrHash); + p_Memac->p_MulticastAddrHash = NULL; + + /* release the driver's individual hash table */ + FreeHashTable(p_Memac->p_UnicastAddrHash); + p_Memac->p_UnicastAddrHash = NULL; +} + + +/*****************************************************************************/ +/* mEMAC API routines */ +/*****************************************************************************/ + +/* ......................................................................... */ + +static t_Error MemacEnable(t_Handle h_Memac, e_CommMode mode) +{ + t_Memac *p_Memac = (t_Memac *)h_Memac; + + SANITY_CHECK_RETURN_ERROR(p_Memac, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(!p_Memac->p_MemacDriverParam, E_INVALID_STATE); + + memac_enable(p_Memac->p_MemMap, (mode & e_COMM_MODE_RX), (mode & e_COMM_MODE_TX)); + + return E_OK; +} + +/* ......................................................................... */ + +static t_Error MemacDisable (t_Handle h_Memac, e_CommMode mode) +{ + t_Memac *p_Memac = (t_Memac *)h_Memac; + + SANITY_CHECK_RETURN_ERROR(p_Memac, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(!p_Memac->p_MemacDriverParam, E_INVALID_STATE); + + memac_disable(p_Memac->p_MemMap, (mode & e_COMM_MODE_RX), (mode & e_COMM_MODE_TX)); + + return E_OK; +} + +/* ......................................................................... */ + +static t_Error MemacSetPromiscuous(t_Handle h_Memac, bool newVal) +{ + t_Memac *p_Memac = (t_Memac *)h_Memac; + + SANITY_CHECK_RETURN_ERROR(p_Memac, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(!p_Memac->p_MemacDriverParam, E_INVALID_STATE); + + memac_set_promiscuous(p_Memac->p_MemMap, newVal); + + return E_OK; +} + +/* .............................................................................. */ + +static t_Error MemacAdjustLink(t_Handle h_Memac, e_EnetSpeed speed, bool fullDuplex) +{ + t_Memac *p_Memac = (t_Memac *)h_Memac; + + SANITY_CHECK_RETURN_ERROR(p_Memac, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(!p_Memac->p_MemacDriverParam, E_INVALID_STATE); +UNUSED(p_Memac); +DBG(WARNING, ("mEMAC works in automatic-mode; therefore, adjust-link is not needed!")); + + return E_OK; +} + + +/*****************************************************************************/ +/* Memac Configs modification functions */ +/*****************************************************************************/ + +/* ......................................................................... */ + +static t_Error MemacConfigLoopback(t_Handle h_Memac, bool newVal) +{ + t_Memac *p_Memac = (t_Memac *)h_Memac; + + SANITY_CHECK_RETURN_ERROR(p_Memac, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_Memac->p_MemacDriverParam, E_INVALID_STATE); + + p_Memac->p_MemacDriverParam->loopback_enable = newVal; + + return E_OK; +} + +/* ......................................................................... */ + +static t_Error MemacConfigWan(t_Handle h_Memac, bool newVal) +{ + t_Memac *p_Memac = (t_Memac *)h_Memac; + + SANITY_CHECK_RETURN_ERROR(p_Memac, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_Memac->p_MemacDriverParam, E_INVALID_STATE); + + p_Memac->p_MemacDriverParam->wan_mode_enable = newVal; + + return E_OK; +} + +/* ......................................................................... */ + +static t_Error MemacConfigMaxFrameLength(t_Handle h_Memac, uint16_t newVal) +{ + t_Memac *p_Memac = (t_Memac *)h_Memac; + + SANITY_CHECK_RETURN_ERROR(p_Memac, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_Memac->p_MemacDriverParam, E_INVALID_STATE); + + p_Memac->p_MemacDriverParam->max_frame_length = newVal; + + return E_OK; +} + +/* ......................................................................... */ + +static t_Error MemacConfigPad(t_Handle h_Memac, bool newVal) +{ + t_Memac *p_Memac = (t_Memac *)h_Memac; + + SANITY_CHECK_RETURN_ERROR(p_Memac, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_Memac->p_MemacDriverParam, E_INVALID_STATE); + + p_Memac->p_MemacDriverParam->pad_enable = newVal; + + return E_OK; +} + +/* ......................................................................... */ + +static t_Error MemacConfigLengthCheck(t_Handle h_Memac, bool newVal) +{ + t_Memac *p_Memac = (t_Memac *)h_Memac; + + SANITY_CHECK_RETURN_ERROR(p_Memac, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_Memac->p_MemacDriverParam, E_INVALID_STATE); + + p_Memac->p_MemacDriverParam->no_length_check_enable = !newVal; + + return E_OK; +} + +/* ......................................................................... */ + +static t_Error MemacConfigException(t_Handle h_Memac, e_FmMacExceptions exception, bool enable) +{ + t_Memac *p_Memac = (t_Memac *)h_Memac; + uint32_t bitMask = 0; + + SANITY_CHECK_RETURN_ERROR(p_Memac, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_Memac->p_MemacDriverParam, E_INVALID_STATE); + + GET_EXCEPTION_FLAG(bitMask, exception); + if (bitMask) + { + if (enable) + p_Memac->exceptions |= bitMask; + else + p_Memac->exceptions &= ~bitMask; + } + else + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("Undefined exception")); + + return E_OK; +} + +/* ......................................................................... */ + +static t_Error MemacConfigResetOnInit(t_Handle h_Memac, bool enable) +{ + t_Memac *p_Memac = (t_Memac *)h_Memac; + + SANITY_CHECK_RETURN_ERROR(p_Memac, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_Memac->p_MemacDriverParam, E_INVALID_STATE); + + p_Memac->p_MemacDriverParam->reset_on_init = enable; + + return E_OK; +} + + +/*****************************************************************************/ +/* Memac Run Time API functions */ +/*****************************************************************************/ + +/* ......................................................................... */ + +static t_Error MemacSetTxPauseFrames(t_Handle h_Memac, + uint8_t priority, + uint16_t pauseTime, + uint16_t threshTime) +{ + t_Memac *p_Memac = (t_Memac *)h_Memac; + + SANITY_CHECK_RETURN_ERROR(p_Memac, E_INVALID_STATE); + SANITY_CHECK_RETURN_ERROR(!p_Memac->p_MemacDriverParam, E_INVALID_STATE); + + memac_set_tx_pause_frames(p_Memac->p_MemMap, priority, pauseTime, threshTime); + + return E_OK; +} + +/* ......................................................................... */ + +static t_Error MemacSetTxAutoPauseFrames(t_Handle h_Memac, + uint16_t pauseTime) +{ + return MemacSetTxPauseFrames(h_Memac, FM_MAC_NO_PFC, pauseTime, 0); +} + +/* ......................................................................... */ + +static t_Error MemacSetRxIgnorePauseFrames(t_Handle h_Memac, bool en) +{ + t_Memac *p_Memac = (t_Memac *)h_Memac; + + SANITY_CHECK_RETURN_ERROR(p_Memac, E_INVALID_STATE); + SANITY_CHECK_RETURN_ERROR(!p_Memac->p_MemacDriverParam, E_INVALID_STATE); + + memac_set_rx_ignore_pause_frames(p_Memac->p_MemMap, en); + + return E_OK; +} + +/* .............................................................................. */ + +static t_Error MemacEnable1588TimeStamp(t_Handle h_Memac) +{ + t_Memac *p_Memac = (t_Memac *)h_Memac; + + SANITY_CHECK_RETURN_ERROR(p_Memac, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(!p_Memac->p_MemacDriverParam, E_INVALID_STATE); +UNUSED(p_Memac); +DBG(WARNING, ("mEMAC has 1588 always enabled!")); + + return E_OK; +} + +/* Counters handling */ +/* ......................................................................... */ + +static t_Error MemacGetStatistics(t_Handle h_Memac, t_FmMacStatistics *p_Statistics) +{ + t_Memac *p_Memac = (t_Memac *)h_Memac; + + SANITY_CHECK_RETURN_ERROR(p_Memac, E_NULL_POINTER); + SANITY_CHECK_RETURN_ERROR(!p_Memac->p_MemacDriverParam, E_INVALID_STATE); + SANITY_CHECK_RETURN_ERROR(p_Statistics, E_NULL_POINTER); + + p_Statistics->eStatPkts64 = memac_get_counter(p_Memac->p_MemMap, E_MEMAC_COUNTER_R64); + p_Statistics->eStatPkts65to127 = memac_get_counter(p_Memac->p_MemMap, E_MEMAC_COUNTER_R127); + p_Statistics->eStatPkts128to255 = memac_get_counter(p_Memac->p_MemMap, E_MEMAC_COUNTER_R255); + p_Statistics->eStatPkts256to511 = memac_get_counter(p_Memac->p_MemMap, E_MEMAC_COUNTER_R511); + p_Statistics->eStatPkts512to1023 = memac_get_counter(p_Memac->p_MemMap, E_MEMAC_COUNTER_R1023); + p_Statistics->eStatPkts1024to1518 = memac_get_counter(p_Memac->p_MemMap, E_MEMAC_COUNTER_R1518); + p_Statistics->eStatPkts1519to1522 = memac_get_counter(p_Memac->p_MemMap, E_MEMAC_COUNTER_R1519X); +/* */ + p_Statistics->eStatFragments = memac_get_counter(p_Memac->p_MemMap, E_MEMAC_COUNTER_RFRG); + p_Statistics->eStatJabbers = memac_get_counter(p_Memac->p_MemMap, E_MEMAC_COUNTER_RJBR); + + p_Statistics->eStatsDropEvents = memac_get_counter(p_Memac->p_MemMap, E_MEMAC_COUNTER_RDRP); + p_Statistics->eStatCRCAlignErrors = memac_get_counter(p_Memac->p_MemMap, E_MEMAC_COUNTER_RALN); + + p_Statistics->eStatUndersizePkts = memac_get_counter(p_Memac->p_MemMap, E_MEMAC_COUNTER_TUND); + p_Statistics->eStatOversizePkts = memac_get_counter(p_Memac->p_MemMap, E_MEMAC_COUNTER_ROVR); +/* Pause */ + p_Statistics->reStatPause = memac_get_counter(p_Memac->p_MemMap, E_MEMAC_COUNTER_RXPF); + p_Statistics->teStatPause = memac_get_counter(p_Memac->p_MemMap, E_MEMAC_COUNTER_TXPF); + +/* MIB II */ + p_Statistics->ifInOctets = memac_get_counter(p_Memac->p_MemMap, E_MEMAC_COUNTER_ROCT); + p_Statistics->ifInUcastPkts = memac_get_counter(p_Memac->p_MemMap, E_MEMAC_COUNTER_RUCA); + p_Statistics->ifInMcastPkts = memac_get_counter(p_Memac->p_MemMap, E_MEMAC_COUNTER_RMCA); + p_Statistics->ifInBcastPkts = memac_get_counter(p_Memac->p_MemMap, E_MEMAC_COUNTER_RBCA); + p_Statistics->ifInPkts = p_Statistics->ifInUcastPkts + + p_Statistics->ifInMcastPkts + + p_Statistics->ifInBcastPkts; + p_Statistics->ifInDiscards = 0; + p_Statistics->ifInErrors = memac_get_counter(p_Memac->p_MemMap, E_MEMAC_COUNTER_RERR); + + p_Statistics->ifOutOctets = memac_get_counter(p_Memac->p_MemMap, E_MEMAC_COUNTER_TOCT); + p_Statistics->ifOutUcastPkts = memac_get_counter(p_Memac->p_MemMap, E_MEMAC_COUNTER_TUCA); + p_Statistics->ifOutMcastPkts = memac_get_counter(p_Memac->p_MemMap, E_MEMAC_COUNTER_TMCA); + p_Statistics->ifOutBcastPkts = memac_get_counter(p_Memac->p_MemMap, E_MEMAC_COUNTER_TBCA); + p_Statistics->ifOutPkts = p_Statistics->ifOutUcastPkts + + p_Statistics->ifOutMcastPkts + + p_Statistics->ifOutBcastPkts; + p_Statistics->ifOutDiscards = 0; + p_Statistics->ifOutErrors = memac_get_counter(p_Memac->p_MemMap, E_MEMAC_COUNTER_TERR); + + return E_OK; +} + +/* ......................................................................... */ + +static t_Error MemacModifyMacAddress (t_Handle h_Memac, t_EnetAddr *p_EnetAddr) +{ + t_Memac *p_Memac = (t_Memac *)h_Memac; + + SANITY_CHECK_RETURN_ERROR(p_Memac, E_NULL_POINTER); + SANITY_CHECK_RETURN_ERROR(!p_Memac->p_MemacDriverParam, E_INVALID_STATE); + + memac_hardware_add_addr_in_paddr(p_Memac->p_MemMap, (uint8_t *)(*p_EnetAddr), 0); + + return E_OK; +} + +/* ......................................................................... */ + +static t_Error MemacResetCounters (t_Handle h_Memac) +{ + t_Memac *p_Memac = (t_Memac *)h_Memac; + + SANITY_CHECK_RETURN_ERROR(p_Memac, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(!p_Memac->p_MemacDriverParam, E_INVALID_STATE); + + memac_reset_counter(p_Memac->p_MemMap); + + return E_OK; +} + +/* ......................................................................... */ + +static t_Error MemacAddExactMatchMacAddress(t_Handle h_Memac, t_EnetAddr *p_EthAddr) +{ + t_Memac *p_Memac = (t_Memac *) h_Memac; + uint64_t ethAddr; + uint8_t paddrNum; + + SANITY_CHECK_RETURN_ERROR(p_Memac, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(!p_Memac->p_MemacDriverParam, E_INVALID_STATE); + + ethAddr = ENET_ADDR_TO_UINT64(*p_EthAddr); + + if (ethAddr & GROUP_ADDRESS) + /* Multicast address has no effect in PADDR */ + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("Multicast address")); + + /* Make sure no PADDR contains this address */ + for (paddrNum = 0; paddrNum < MEMAC_NUM_OF_PADDRS; paddrNum++) + if (p_Memac->indAddrRegUsed[paddrNum]) + if (p_Memac->paddr[paddrNum] == ethAddr) + RETURN_ERROR(MAJOR, E_ALREADY_EXISTS, NO_MSG); + + /* Find first unused PADDR */ + for (paddrNum = 0; paddrNum < MEMAC_NUM_OF_PADDRS; paddrNum++) + if (!(p_Memac->indAddrRegUsed[paddrNum])) + { + /* mark this PADDR as used */ + p_Memac->indAddrRegUsed[paddrNum] = TRUE; + /* store address */ + p_Memac->paddr[paddrNum] = ethAddr; + + /* put in hardware */ + memac_hardware_add_addr_in_paddr(p_Memac->p_MemMap, (uint8_t*)(*p_EthAddr), paddrNum); + p_Memac->numOfIndAddrInRegs++; + + return E_OK; + } + + /* No free PADDR */ + RETURN_ERROR(MAJOR, E_FULL, NO_MSG); +} + +/* ......................................................................... */ + +static t_Error MemacDelExactMatchMacAddress(t_Handle h_Memac, t_EnetAddr *p_EthAddr) +{ + t_Memac *p_Memac = (t_Memac *) h_Memac; + uint64_t ethAddr; + uint8_t paddrNum; + + SANITY_CHECK_RETURN_ERROR(p_Memac, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(!p_Memac->p_MemacDriverParam, E_INVALID_STATE); + + ethAddr = ENET_ADDR_TO_UINT64(*p_EthAddr); + + /* Find used PADDR containing this address */ + for (paddrNum = 0; paddrNum < MEMAC_NUM_OF_PADDRS; paddrNum++) + { + if ((p_Memac->indAddrRegUsed[paddrNum]) && + (p_Memac->paddr[paddrNum] == ethAddr)) + { + /* mark this PADDR as not used */ + p_Memac->indAddrRegUsed[paddrNum] = FALSE; + /* clear in hardware */ + memac_hardware_clear_addr_in_paddr(p_Memac->p_MemMap, paddrNum); + p_Memac->numOfIndAddrInRegs--; + + return E_OK; + } + } + + RETURN_ERROR(MAJOR, E_NOT_FOUND, NO_MSG); +} + +/* ......................................................................... */ + +static t_Error MemacAddHashMacAddress(t_Handle h_Memac, t_EnetAddr *p_EthAddr) +{ + t_Memac *p_Memac = (t_Memac *)h_Memac; + t_EthHashEntry *p_HashEntry; + uint32_t hash; + uint64_t ethAddr; + + SANITY_CHECK_RETURN_ERROR(p_Memac, E_NULL_POINTER); + SANITY_CHECK_RETURN_ERROR(!p_Memac->p_MemacDriverParam, E_INVALID_STATE); + + ethAddr = ENET_ADDR_TO_UINT64(*p_EthAddr); + + if (!(ethAddr & GROUP_ADDRESS)) + /* Unicast addresses not supported in hash */ + RETURN_ERROR(MAJOR, E_NOT_SUPPORTED, ("Unicast Address")); + + hash = GetMacAddrHashCode(ethAddr) & HASH_CTRL_ADDR_MASK; + + /* Create element to be added to the driver hash table */ + p_HashEntry = (t_EthHashEntry *)XX_Malloc(sizeof(t_EthHashEntry)); + p_HashEntry->addr = ethAddr; + INIT_LIST(&p_HashEntry->node); + + LIST_AddToTail(&(p_HashEntry->node), &(p_Memac->p_MulticastAddrHash->p_Lsts[hash])); + memac_set_hash_table(p_Memac->p_MemMap, (hash | HASH_CTRL_MCAST_EN)); + + return E_OK; +} + +/* ......................................................................... */ + +static t_Error MemacDelHashMacAddress(t_Handle h_Memac, t_EnetAddr *p_EthAddr) +{ + t_Memac *p_Memac = (t_Memac *)h_Memac; + t_EthHashEntry *p_HashEntry = NULL; + t_List *p_Pos; + uint32_t hash; + uint64_t ethAddr; + + SANITY_CHECK_RETURN_ERROR(p_Memac, E_NULL_POINTER); + SANITY_CHECK_RETURN_ERROR(!p_Memac->p_MemacDriverParam, E_INVALID_STATE); + + ethAddr = ENET_ADDR_TO_UINT64(*p_EthAddr); + + hash = GetMacAddrHashCode(ethAddr) & HASH_CTRL_ADDR_MASK; + + LIST_FOR_EACH(p_Pos, &(p_Memac->p_MulticastAddrHash->p_Lsts[hash])) + { + p_HashEntry = ETH_HASH_ENTRY_OBJ(p_Pos); + if (p_HashEntry->addr == ethAddr) + { + LIST_DelAndInit(&p_HashEntry->node); + XX_Free(p_HashEntry); + break; + } + } + if (LIST_IsEmpty(&p_Memac->p_MulticastAddrHash->p_Lsts[hash])) + memac_set_hash_table(p_Memac->p_MemMap, (hash & ~HASH_CTRL_MCAST_EN)); + + return E_OK; +} + + +/* ......................................................................... */ + +static t_Error MemacSetException(t_Handle h_Memac, e_FmMacExceptions exception, bool enable) +{ + t_Memac *p_Memac = (t_Memac *)h_Memac; + uint32_t bitMask = 0; + + SANITY_CHECK_RETURN_ERROR(p_Memac, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(!p_Memac->p_MemacDriverParam, E_INVALID_STATE); + + GET_EXCEPTION_FLAG(bitMask, exception); + if (bitMask) + { + if (enable) + p_Memac->exceptions |= bitMask; + else + p_Memac->exceptions &= ~bitMask; + } + else + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("Undefined exception")); + + memac_set_exception(p_Memac->p_MemMap, bitMask, enable); + + return E_OK; +} + +/* ......................................................................... */ + +static uint16_t MemacGetMaxFrameLength(t_Handle h_Memac) +{ + t_Memac *p_Memac = (t_Memac *)h_Memac; + + SANITY_CHECK_RETURN_VALUE(p_Memac, E_INVALID_HANDLE, 0); + SANITY_CHECK_RETURN_VALUE(!p_Memac->p_MemacDriverParam, E_INVALID_STATE, 0); + + return memac_get_max_frame_length(p_Memac->p_MemMap); +} + +/* ......................................................................... */ + +#if (defined(DEBUG_ERRORS) && (DEBUG_ERRORS > 0)) +static t_Error MemacDumpRegs(t_Handle h_Memac) +{ + t_Memac *p_Memac = (t_Memac *)h_Memac; + int i = 0; + + DECLARE_DUMP; + + if (p_Memac->p_MemMap) + { + DUMP_TITLE(p_Memac->p_MemMap, ("mEMAC %d: ", p_Memac->macId)); + DUMP_VAR(p_Memac->p_MemMap, command_config); + DUMP_VAR(p_Memac->p_MemMap, mac_addr0.mac_addr_l); + DUMP_VAR(p_Memac->p_MemMap, mac_addr0.mac_addr_u); + DUMP_VAR(p_Memac->p_MemMap, maxfrm); + DUMP_VAR(p_Memac->p_MemMap, hashtable_ctrl); + DUMP_VAR(p_Memac->p_MemMap, ievent); + DUMP_VAR(p_Memac->p_MemMap, tx_ipg_length); + DUMP_VAR(p_Memac->p_MemMap, imask); + + DUMP_SUBSTRUCT_ARRAY(i, 4) + { + DUMP_VAR(p_Memac->p_MemMap, pause_quanta[i]); + } + DUMP_SUBSTRUCT_ARRAY(i, 4) + { + DUMP_VAR(p_Memac->p_MemMap, pause_thresh[i]); + } + + DUMP_VAR(p_Memac->p_MemMap, rx_pause_status); + + DUMP_SUBSTRUCT_ARRAY(i, MEMAC_NUM_OF_PADDRS) + { + DUMP_VAR(p_Memac->p_MemMap, mac_addr[i].mac_addr_l); + DUMP_VAR(p_Memac->p_MemMap, mac_addr[i].mac_addr_u); + } + + DUMP_VAR(p_Memac->p_MemMap, lpwake_timer); + DUMP_VAR(p_Memac->p_MemMap, sleep_timer); + DUMP_VAR(p_Memac->p_MemMap, statn_config); + DUMP_VAR(p_Memac->p_MemMap, if_mode); + DUMP_VAR(p_Memac->p_MemMap, if_status); + DUMP_VAR(p_Memac->p_MemMap, hg_config); + DUMP_VAR(p_Memac->p_MemMap, hg_pause_quanta); + DUMP_VAR(p_Memac->p_MemMap, hg_pause_thresh); + DUMP_VAR(p_Memac->p_MemMap, hgrx_pause_status); + DUMP_VAR(p_Memac->p_MemMap, hg_fifos_status); + DUMP_VAR(p_Memac->p_MemMap, rhm); + DUMP_VAR(p_Memac->p_MemMap, thm); + } + + return E_OK; +} +#endif /* (defined(DEBUG_ERRORS) && ... */ + + +/*****************************************************************************/ +/* mEMAC Init & Free API */ +/*****************************************************************************/ + +/* ......................................................................... */ + +static t_Error MemacInit(t_Handle h_Memac) +{ + t_Memac *p_Memac = (t_Memac *)h_Memac; + struct memac_cfg *p_MemacDriverParam; + enum enet_interface enet_interface; + enum enet_speed enet_speed; + uint8_t i, phyAddr; + t_EnetAddr ethAddr; + e_FmMacType portType; + t_Error err; + + SANITY_CHECK_RETURN_ERROR(p_Memac, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_Memac->p_MemacDriverParam, E_INVALID_STATE); + SANITY_CHECK_RETURN_ERROR(p_Memac->fmMacControllerDriver.h_Fm, E_INVALID_HANDLE); + + /* not needed! */ + /*FM_GetRevision(p_Memac->fmMacControllerDriver.h_Fm, &p_Memac->fmMacControllerDriver.fmRevInfo);*/ + + CHECK_INIT_PARAMETERS(p_Memac, CheckInitParameters); + + p_MemacDriverParam = p_Memac->p_MemacDriverParam; + + portType = + ((ENET_SPEED_FROM_MODE(p_Memac->enetMode) < e_ENET_SPEED_10000) ? e_FM_MAC_1G : e_FM_MAC_10G); + + /* First, reset the MAC if desired. */ + if (p_MemacDriverParam->reset_on_init) + memac_reset(p_Memac->p_MemMap); + + /* MAC Address */ + MAKE_ENET_ADDR_FROM_UINT64(p_Memac->addr, ethAddr); + memac_hardware_add_addr_in_paddr(p_Memac->p_MemMap, (uint8_t*)ethAddr, 0); + + enet_interface = (enum enet_interface) ENET_INTERFACE_FROM_MODE(p_Memac->enetMode); + enet_speed = (enum enet_speed) ENET_SPEED_FROM_MODE(p_Memac->enetMode); + + memac_init(p_Memac->p_MemMap, + p_Memac->p_MemacDriverParam, + enet_interface, + enet_speed, + p_Memac->exceptions); + + if (ENET_INTERFACE_FROM_MODE(p_Memac->enetMode) == e_ENET_IF_SGMII) + { + /* Configure internal SGMII PHY */ + if (p_Memac->enetMode & ENET_IF_SGMII_BASEX) + SetupSgmiiInternalPhyBaseX(p_Memac, PHY_MDIO_ADDR); + else + SetupSgmiiInternalPhy(p_Memac, PHY_MDIO_ADDR); + } + else if (ENET_INTERFACE_FROM_MODE(p_Memac->enetMode) == e_ENET_IF_QSGMII) + { + /* Configure 4 internal SGMII PHYs */ + for (i = 0; i < 4; i++) + { + /* QSGMII PHY address occupies 3 upper bits of 5-bit + phyAddress; the lower 2 bits are used to extend + register address space and access each one of 4 + ports inside QSGMII. */ + phyAddr = (uint8_t)((PHY_MDIO_ADDR << 2) | i); + if (p_Memac->enetMode & ENET_IF_SGMII_BASEX) + SetupSgmiiInternalPhyBaseX(p_Memac, phyAddr); + else + SetupSgmiiInternalPhy(p_Memac, phyAddr); + } + } + + /* Max Frame Length */ + err = FmSetMacMaxFrame(p_Memac->fmMacControllerDriver.h_Fm, + portType, + p_Memac->fmMacControllerDriver.macId, + p_MemacDriverParam->max_frame_length); + if (err) + RETURN_ERROR(MAJOR, err, ("settings Mac max frame length is FAILED")); + + p_Memac->p_MulticastAddrHash = AllocHashTable(HASH_TABLE_SIZE); + if (!p_Memac->p_MulticastAddrHash) + { + FreeInitResources(p_Memac); + RETURN_ERROR(MAJOR, E_NO_MEMORY, ("allocation hash table is FAILED")); + } + + p_Memac->p_UnicastAddrHash = AllocHashTable(HASH_TABLE_SIZE); + if (!p_Memac->p_UnicastAddrHash) + { + FreeInitResources(p_Memac); + RETURN_ERROR(MAJOR, E_NO_MEMORY, ("allocation hash table is FAILED")); + } + + FmRegisterIntr(p_Memac->fmMacControllerDriver.h_Fm, + (portType == e_FM_MAC_10G) ? e_FM_MOD_10G_MAC : e_FM_MOD_1G_MAC, + p_Memac->macId, + e_FM_INTR_TYPE_ERR, + MemacErrException, + p_Memac); + + + XX_Free(p_MemacDriverParam); + p_Memac->p_MemacDriverParam = NULL; + + return E_OK; +} + +/* ......................................................................... */ + +static t_Error MemacFree(t_Handle h_Memac) +{ + t_Memac *p_Memac = (t_Memac *)h_Memac; + + SANITY_CHECK_RETURN_ERROR(p_Memac, E_INVALID_HANDLE); + + FreeInitResources(p_Memac); + + if (p_Memac->p_MemacDriverParam) + { + XX_Free(p_Memac->p_MemacDriverParam); + p_Memac->p_MemacDriverParam = NULL; + } + XX_Free(p_Memac); + + return E_OK; +} + +/* ......................................................................... */ + +static void InitFmMacControllerDriver(t_FmMacControllerDriver *p_FmMacControllerDriver) +{ + p_FmMacControllerDriver->f_FM_MAC_Init = MemacInit; + p_FmMacControllerDriver->f_FM_MAC_Free = MemacFree; + + p_FmMacControllerDriver->f_FM_MAC_SetStatistics = NULL; + p_FmMacControllerDriver->f_FM_MAC_ConfigLoopback = MemacConfigLoopback; + p_FmMacControllerDriver->f_FM_MAC_ConfigMaxFrameLength = MemacConfigMaxFrameLength; + + p_FmMacControllerDriver->f_FM_MAC_ConfigWan = MemacConfigWan; + + p_FmMacControllerDriver->f_FM_MAC_ConfigPadAndCrc = MemacConfigPad; + p_FmMacControllerDriver->f_FM_MAC_ConfigHalfDuplex = NULL; /* half-duplex is detected automatically */ + p_FmMacControllerDriver->f_FM_MAC_ConfigLengthCheck = MemacConfigLengthCheck; + + p_FmMacControllerDriver->f_FM_MAC_ConfigException = MemacConfigException; + p_FmMacControllerDriver->f_FM_MAC_ConfigResetOnInit = MemacConfigResetOnInit; + + p_FmMacControllerDriver->f_FM_MAC_SetException = MemacSetException; + + p_FmMacControllerDriver->f_FM_MAC_Enable1588TimeStamp = MemacEnable1588TimeStamp; /* always enabled */ + p_FmMacControllerDriver->f_FM_MAC_Disable1588TimeStamp = NULL; + + p_FmMacControllerDriver->f_FM_MAC_SetPromiscuous = MemacSetPromiscuous; + p_FmMacControllerDriver->f_FM_MAC_AdjustLink = MemacAdjustLink; + p_FmMacControllerDriver->f_FM_MAC_RestartAutoneg = NULL; + + p_FmMacControllerDriver->f_FM_MAC_Enable = MemacEnable; + p_FmMacControllerDriver->f_FM_MAC_Disable = MemacDisable; + + p_FmMacControllerDriver->f_FM_MAC_SetTxAutoPauseFrames = MemacSetTxAutoPauseFrames; + p_FmMacControllerDriver->f_FM_MAC_SetTxPauseFrames = MemacSetTxPauseFrames; + p_FmMacControllerDriver->f_FM_MAC_SetRxIgnorePauseFrames = MemacSetRxIgnorePauseFrames; + + p_FmMacControllerDriver->f_FM_MAC_ResetCounters = MemacResetCounters; + p_FmMacControllerDriver->f_FM_MAC_GetStatistics = MemacGetStatistics; + + p_FmMacControllerDriver->f_FM_MAC_ModifyMacAddr = MemacModifyMacAddress; + p_FmMacControllerDriver->f_FM_MAC_AddHashMacAddr = MemacAddHashMacAddress; + p_FmMacControllerDriver->f_FM_MAC_RemoveHashMacAddr = MemacDelHashMacAddress; + p_FmMacControllerDriver->f_FM_MAC_AddExactMatchMacAddr = MemacAddExactMatchMacAddress; + p_FmMacControllerDriver->f_FM_MAC_RemovelExactMatchMacAddr = MemacDelExactMatchMacAddress; + p_FmMacControllerDriver->f_FM_MAC_GetId = NULL; + p_FmMacControllerDriver->f_FM_MAC_GetVersion = NULL; + p_FmMacControllerDriver->f_FM_MAC_GetMaxFrameLength = MemacGetMaxFrameLength; + + p_FmMacControllerDriver->f_FM_MAC_MII_WritePhyReg = MEMAC_MII_WritePhyReg; + p_FmMacControllerDriver->f_FM_MAC_MII_ReadPhyReg = MEMAC_MII_ReadPhyReg; + +#if (defined(DEBUG_ERRORS) && (DEBUG_ERRORS > 0)) + p_FmMacControllerDriver->f_FM_MAC_DumpRegs = MemacDumpRegs; +#endif /* (defined(DEBUG_ERRORS) && ... */ +} + + +/*****************************************************************************/ +/* mEMAC Config Main Entry */ +/*****************************************************************************/ + +/* ......................................................................... */ + +t_Handle MEMAC_Config(t_FmMacParams *p_FmMacParam) +{ + t_Memac *p_Memac; + struct memac_cfg *p_MemacDriverParam; + uintptr_t baseAddr; + + SANITY_CHECK_RETURN_VALUE(p_FmMacParam, E_NULL_POINTER, NULL); + + baseAddr = p_FmMacParam->baseAddr; + /* Allocate memory for the mEMAC data structure */ + p_Memac = (t_Memac *)XX_Malloc(sizeof(t_Memac)); + if (!p_Memac) + { + REPORT_ERROR(MAJOR, E_NO_MEMORY, ("mEMAC driver structure")); + return NULL; + } + memset(p_Memac, 0, sizeof(t_Memac)); + InitFmMacControllerDriver(&p_Memac->fmMacControllerDriver); + + /* Allocate memory for the mEMAC driver parameters data structure */ + p_MemacDriverParam = (struct memac_cfg *) XX_Malloc(sizeof(struct memac_cfg)); + if (!p_MemacDriverParam) + { + REPORT_ERROR(MAJOR, E_NO_MEMORY, ("mEMAC driver parameters")); + MemacFree(p_Memac); + return NULL; + } + memset(p_MemacDriverParam, 0, sizeof(struct memac_cfg)); + + /* Plant parameter structure pointer */ + p_Memac->p_MemacDriverParam = p_MemacDriverParam; + + memac_defconfig(p_MemacDriverParam); + + p_Memac->addr = ENET_ADDR_TO_UINT64(p_FmMacParam->addr); + + p_Memac->p_MemMap = (struct memac_regs *)UINT_TO_PTR(baseAddr); + p_Memac->p_MiiMemMap = (t_MemacMiiAccessMemMap *)UINT_TO_PTR(baseAddr + MEMAC_TO_MII_OFFSET); + + p_Memac->enetMode = p_FmMacParam->enetMode; + p_Memac->macId = p_FmMacParam->macId; + p_Memac->exceptions = MEMAC_default_exceptions; + p_Memac->f_Exception = p_FmMacParam->f_Exception; + p_Memac->f_Event = p_FmMacParam->f_Event; + p_Memac->h_App = p_FmMacParam->h_App; + + return p_Memac; +} diff --git a/drivers/net/ethernet/freescale/fman/Peripherals/FM/MAC/memac.h b/drivers/net/ethernet/freescale/fman/Peripherals/FM/MAC/memac.h new file mode 100644 index 0000000..e1c4c53 --- /dev/null +++ b/drivers/net/ethernet/freescale/fman/Peripherals/FM/MAC/memac.h @@ -0,0 +1,104 @@ +/* + * Copyright 2008-2012 Freescale Semiconductor Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Freescale Semiconductor nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + +/****************************************************************************** + @File memac.h + + @Description FM Multirate Ethernet MAC (mEMAC) +*//***************************************************************************/ +#ifndef __MEMAC_H +#define __MEMAC_H + +#include "std_ext.h" +#include "error_ext.h" +#include "list_ext.h" + +#include "memac_mii_acc.h" +#include "fm_mac.h" +#include "fsl_fman_memac.h" + + +#define MEMAC_default_exceptions ((uint32_t)(MEMAC_IMASK_TECC_ER | MEMAC_IMASK_RECC_ER)) + +#define GET_EXCEPTION_FLAG(bitMask, exception) switch (exception){ \ + case e_FM_MAC_EX_10G_1TX_ECC_ER: \ + bitMask = MEMAC_IMASK_TECC_ER; break; \ + case e_FM_MAC_EX_10G_RX_ECC_ER: \ + bitMask = MEMAC_IMASK_RECC_ER; break; \ + default: bitMask = 0;break;} + + +typedef struct +{ + t_FmMacControllerDriver fmMacControllerDriver; /**< Upper Mac control block */ + t_Handle h_App; /**< Handle to the upper layer application */ + struct memac_regs *p_MemMap; /**< Pointer to MAC memory mapped registers */ + t_MemacMiiAccessMemMap *p_MiiMemMap; /**< Pointer to MII memory mapped registers */ + uint64_t addr; /**< MAC address of device */ + e_EnetMode enetMode; /**< Ethernet physical interface */ + t_FmMacExceptionCallback *f_Exception; + int mdioIrq; + t_FmMacExceptionCallback *f_Event; + bool indAddrRegUsed[MEMAC_NUM_OF_PADDRS]; /**< Whether a particular individual address recognition register is being used */ + uint64_t paddr[MEMAC_NUM_OF_PADDRS]; /**< MAC address for particular individual address recognition register */ + uint8_t numOfIndAddrInRegs; /**< Number of individual addresses in registers for this station. */ + t_EthHash *p_MulticastAddrHash; /**< Pointer to driver's global address hash table */ + t_EthHash *p_UnicastAddrHash; /**< Pointer to driver's individual address hash table */ + bool debugMode; + uint8_t macId; + uint32_t exceptions; + struct memac_cfg *p_MemacDriverParam; +} t_Memac; + + +/* Internal PHY access */ +#define PHY_MDIO_ADDR 0 + +/* Internal PHY Registers - SGMII */ +#define PHY_SGMII_CR_PHY_RESET 0x8000 +#define PHY_SGMII_CR_RESET_AN 0x0200 +#define PHY_SGMII_CR_DEF_VAL 0x1140 +#define PHY_SGMII_DEV_ABILITY_SGMII 0x4001 +#define PHY_SGMII_DEV_ABILITY_1000X 0x01A0 +#define PHY_SGMII_IF_MODE_AN 0x0002 +#define PHY_SGMII_IF_MODE_SGMII 0x0001 +#define PHY_SGMII_IF_MODE_1000X 0x0000 + + +#define MEMAC_TO_MII_OFFSET 0x030 /* Offset from the MEM map to the MDIO mem map */ + +t_Error MEMAC_MII_WritePhyReg(t_Handle h_Memac, uint8_t phyAddr, uint8_t reg, uint16_t data); +t_Error MEMAC_MII_ReadPhyReg(t_Handle h_Memac, uint8_t phyAddr, uint8_t reg, uint16_t *p_Data); + + +#endif /* __MEMAC_H */ diff --git a/drivers/net/ethernet/freescale/fman/Peripherals/FM/MAC/memac_mii_acc.c b/drivers/net/ethernet/freescale/fman/Peripherals/FM/MAC/memac_mii_acc.c new file mode 100644 index 0000000..be5b867 --- /dev/null +++ b/drivers/net/ethernet/freescale/fman/Peripherals/FM/MAC/memac_mii_acc.c @@ -0,0 +1,240 @@ +/* + * Copyright 2008-2012 Freescale Semiconductor Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Freescale Semiconductor nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + +#include "error_ext.h" +#include "std_ext.h" +#include "fm_mac.h" +#include "memac.h" +#include "xx_ext.h" + +#include "fm_common.h" + + +static void WritePhyReg10G(t_MemacMiiAccessMemMap *p_MiiAccess, + uint8_t phyAddr, + uint8_t reg, + uint16_t data) +{ + uint32_t tmpReg; + + tmpReg = GET_UINT32(p_MiiAccess->mdio_cfg); + /* Leave only MDIO_CLK_DIV bits set on */ + tmpReg &= MDIO_CFG_CLK_DIV_MASK; + /* Set maximum MDIO_HOLD value to allow phy to see + change of data signal */ + tmpReg |= MDIO_CFG_HOLD_MASK; + /* Add 10G interface mode */ + tmpReg |= MDIO_CFG_ENC45; + WRITE_UINT32(p_MiiAccess->mdio_cfg, tmpReg); + + /* Wait for command completion */ + while ((GET_UINT32(p_MiiAccess->mdio_cfg)) & MDIO_CFG_BSY) + XX_UDelay(1); + + /* Specify phy and register to be accessed */ + WRITE_UINT32(p_MiiAccess->mdio_ctrl, phyAddr); + WRITE_UINT32(p_MiiAccess->mdio_addr, reg); + CORE_MemoryBarrier(); + + while ((GET_UINT32(p_MiiAccess->mdio_cfg)) & MDIO_CFG_BSY) + XX_UDelay(1); + + /* Write data */ + WRITE_UINT32(p_MiiAccess->mdio_data, data); + CORE_MemoryBarrier(); + + /* Wait for write transaction end */ + while ((GET_UINT32(p_MiiAccess->mdio_data)) & MDIO_DATA_BSY) + XX_UDelay(1); +} + +static uint32_t ReadPhyReg10G(t_MemacMiiAccessMemMap *p_MiiAccess, + uint8_t phyAddr, + uint8_t reg, + uint16_t *p_Data) +{ + uint32_t tmpReg; + + tmpReg = GET_UINT32(p_MiiAccess->mdio_cfg); + /* Leave only MDIO_CLK_DIV bits set on */ + tmpReg &= MDIO_CFG_CLK_DIV_MASK; + /* Set maximum MDIO_HOLD value to allow phy to see + change of data signal */ + tmpReg |= MDIO_CFG_HOLD_MASK; + /* Add 10G interface mode */ + tmpReg |= MDIO_CFG_ENC45; + WRITE_UINT32(p_MiiAccess->mdio_cfg, tmpReg); + + /* Wait for command completion */ + while ((GET_UINT32(p_MiiAccess->mdio_cfg)) & MDIO_CFG_BSY) + XX_UDelay(1); + + /* Specify phy and register to be accessed */ + WRITE_UINT32(p_MiiAccess->mdio_ctrl, phyAddr); + WRITE_UINT32(p_MiiAccess->mdio_addr, reg); + CORE_MemoryBarrier(); + + while ((GET_UINT32(p_MiiAccess->mdio_cfg)) & MDIO_CFG_BSY) + XX_UDelay(1); + + /* Read cycle */ + tmpReg = phyAddr; + tmpReg |= MDIO_CTL_READ; + WRITE_UINT32(p_MiiAccess->mdio_ctrl, tmpReg); + CORE_MemoryBarrier(); + + /* Wait for data to be available */ + while ((GET_UINT32(p_MiiAccess->mdio_data)) & MDIO_DATA_BSY) + XX_UDelay(1); + + *p_Data = (uint16_t)GET_UINT32(p_MiiAccess->mdio_data); + + /* Check if there was an error */ + return GET_UINT32(p_MiiAccess->mdio_cfg); +} + +static void WritePhyReg1G(t_MemacMiiAccessMemMap *p_MiiAccess, + uint8_t phyAddr, + uint8_t reg, + uint16_t data) +{ + uint32_t tmpReg; + + /* Leave only MDIO_CLK_DIV and MDIO_HOLD bits set on */ + tmpReg = GET_UINT32(p_MiiAccess->mdio_cfg); + tmpReg &= (MDIO_CFG_CLK_DIV_MASK | MDIO_CFG_HOLD_MASK); + WRITE_UINT32(p_MiiAccess->mdio_cfg, tmpReg); + + /* Wait for command completion */ + while ((GET_UINT32(p_MiiAccess->mdio_cfg)) & MDIO_CFG_BSY) + XX_UDelay(1); + + /* Write transaction */ + tmpReg = (phyAddr << MDIO_CTL_PHY_ADDR_SHIFT); + tmpReg |= reg; + WRITE_UINT32(p_MiiAccess->mdio_ctrl, tmpReg); + + while ((GET_UINT32(p_MiiAccess->mdio_cfg)) & MDIO_CFG_BSY) + XX_UDelay(1); + + WRITE_UINT32(p_MiiAccess->mdio_data, data); + + CORE_MemoryBarrier(); + + /* Wait for write transaction to end */ + while ((GET_UINT32(p_MiiAccess->mdio_data)) & MDIO_DATA_BSY) + XX_UDelay(1); +} + +static uint32_t ReadPhyReg1G(t_MemacMiiAccessMemMap *p_MiiAccess, + uint8_t phyAddr, + uint8_t reg, + uint16_t *p_Data) +{ + uint32_t tmpReg; + + /* Leave only MDIO_CLK_DIV and MDIO_HOLD bits set on */ + tmpReg = GET_UINT32(p_MiiAccess->mdio_cfg); + tmpReg &= (MDIO_CFG_CLK_DIV_MASK | MDIO_CFG_HOLD_MASK); + WRITE_UINT32(p_MiiAccess->mdio_cfg, tmpReg); + + /* Wait for command completion */ + while ((GET_UINT32(p_MiiAccess->mdio_cfg)) & MDIO_CFG_BSY) + XX_UDelay(1); + + /* Read transaction */ + tmpReg = (phyAddr << MDIO_CTL_PHY_ADDR_SHIFT); + tmpReg |= reg; + tmpReg |= MDIO_CTL_READ; + WRITE_UINT32(p_MiiAccess->mdio_ctrl, tmpReg); + + while ((GET_UINT32(p_MiiAccess->mdio_cfg)) & MDIO_CFG_BSY) + XX_UDelay(1); + + /* Wait for data to be available */ + while ((GET_UINT32(p_MiiAccess->mdio_data)) & MDIO_DATA_BSY) + XX_UDelay(1); + + *p_Data = (uint16_t)GET_UINT32(p_MiiAccess->mdio_data); + + /* Check error */ + return GET_UINT32(p_MiiAccess->mdio_cfg); +} + +/*****************************************************************************/ +t_Error MEMAC_MII_WritePhyReg(t_Handle h_Memac, + uint8_t phyAddr, + uint8_t reg, + uint16_t data) +{ + t_Memac *p_Memac = (t_Memac *)h_Memac; + + SANITY_CHECK_RETURN_ERROR(p_Memac, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_Memac->p_MiiMemMap, E_INVALID_HANDLE); + + /* Figure out interface type - 10G vs 1G. + In 10G interface both phyAddr and devAddr present. */ + if (ENET_SPEED_FROM_MODE(p_Memac->enetMode) == e_ENET_SPEED_10000) + WritePhyReg10G(p_Memac->p_MiiMemMap, phyAddr, reg, data); + else + WritePhyReg1G(p_Memac->p_MiiMemMap, phyAddr, reg, data); + + return E_OK; +} + +/*****************************************************************************/ +t_Error MEMAC_MII_ReadPhyReg(t_Handle h_Memac, + uint8_t phyAddr, + uint8_t reg, + uint16_t *p_Data) +{ + t_Memac *p_Memac = (t_Memac *)h_Memac; + uint32_t ans; + + SANITY_CHECK_RETURN_ERROR(p_Memac, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_Memac->p_MiiMemMap, E_INVALID_HANDLE); + + /* Figure out interface type - 10G vs 1G. + In 10G interface both phyAddr and devAddr present. */ + if (ENET_SPEED_FROM_MODE(p_Memac->enetMode) == e_ENET_SPEED_10000) + ans = ReadPhyReg10G(p_Memac->p_MiiMemMap, phyAddr, reg, p_Data); + else + ans = ReadPhyReg1G(p_Memac->p_MiiMemMap, phyAddr, reg, p_Data); + + if (ans & MDIO_CFG_READ_ERR) + RETURN_ERROR(MINOR, E_INVALID_VALUE, + ("Read Error: phyAddr 0x%x, dev 0x%x, reg 0x%x, cfgReg 0x%x", + ((phyAddr & 0xe0) >> 5), (phyAddr & 0x1f), reg, ans)); + + return E_OK; +} diff --git a/drivers/net/ethernet/freescale/fman/Peripherals/FM/MAC/memac_mii_acc.h b/drivers/net/ethernet/freescale/fman/Peripherals/FM/MAC/memac_mii_acc.h new file mode 100644 index 0000000..dab4360 --- /dev/null +++ b/drivers/net/ethernet/freescale/fman/Peripherals/FM/MAC/memac_mii_acc.h @@ -0,0 +1,73 @@ +/* + * Copyright 2008-2012 Freescale Semiconductor Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Freescale Semiconductor nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + +#ifndef __MEMAC_MII_ACC_H +#define __MEMAC_MII_ACC_H + +#include "std_ext.h" + + +/* MII Management Registers */ +#define MDIO_CFG_CLK_DIV_MASK 0x0000ff80 +#define MDIO_CFG_CLK_DIV_SHIFT 7 +#define MDIO_CFG_HOLD_MASK 0x0000001c +#define MDIO_CFG_ENC45 0x00000040 +#define MDIO_CFG_READ_ERR 0x00000002 +#define MDIO_CFG_BSY 0x00000001 + +#define MDIO_CTL_PHY_ADDR_SHIFT 5 +#define MDIO_CTL_READ 0x00008000 + +#define MDIO_DATA_BSY 0x80000000 + +#if defined(__MWERKS__) && !defined(__GNUC__) +#pragma pack(push,1) +#endif /* defined(__MWERKS__) && ... */ + +/*----------------------------------------------------*/ +/* MII Configuration Control Memory Map Registers */ +/*----------------------------------------------------*/ +typedef _Packed struct t_MemacMiiAccessMemMap +{ + volatile uint32_t mdio_cfg; /* 0x030 */ + volatile uint32_t mdio_ctrl; /* 0x034 */ + volatile uint32_t mdio_data; /* 0x038 */ + volatile uint32_t mdio_addr; /* 0x03c */ +} _PackedType t_MemacMiiAccessMemMap ; + +#if defined(__MWERKS__) && !defined(__GNUC__) +#pragma pack(pop) +#endif /* defined(__MWERKS__) && ... */ + + +#endif /* __MEMAC_MII_ACC_H */ diff --git a/drivers/net/ethernet/freescale/fman/Peripherals/FM/MAC/tgec.c b/drivers/net/ethernet/freescale/fman/Peripherals/FM/MAC/tgec.c new file mode 100644 index 0000000..522d64b --- /dev/null +++ b/drivers/net/ethernet/freescale/fman/Peripherals/FM/MAC/tgec.c @@ -0,0 +1,1018 @@ +/* + * Copyright 2008-2012 Freescale Semiconductor Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Freescale Semiconductor nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + +/****************************************************************************** + @File tgec.c + + @Description FM 10G MAC ... +*//***************************************************************************/ + +#include "std_ext.h" +#include "string_ext.h" +#include "error_ext.h" +#include "xx_ext.h" +#include "endian_ext.h" +#include "debug_ext.h" +#include "crc_mac_addr_ext.h" + +#include "fm_common.h" +#include "fsl_fman_tgec.h" +#include "tgec.h" + + +/*****************************************************************************/ +/* Internal routines */ +/*****************************************************************************/ + +static t_Error CheckInitParameters(t_Tgec *p_Tgec) +{ + if (ENET_SPEED_FROM_MODE(p_Tgec->enetMode) < e_ENET_SPEED_10000) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("Ethernet 10G MAC driver only support 10G speed")); +#if (FM_MAX_NUM_OF_10G_MACS > 0) + if (p_Tgec->macId >= FM_MAX_NUM_OF_10G_MACS) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("macId of 10G can not be greater than 0")); +#endif /* (FM_MAX_NUM_OF_10G_MACS > 0) */ + + if (p_Tgec->addr == 0) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("Ethernet 10G MAC Must have a valid MAC Address")); + if (!p_Tgec->f_Exception) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("uninitialized f_Exception")); + if (!p_Tgec->f_Event) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("uninitialized f_Event")); +#ifdef FM_LEN_CHECK_ERRATA_FMAN_SW002 + if (!p_Tgec->p_TgecDriverParam->no_length_check_enable) + RETURN_ERROR(MINOR, E_NOT_SUPPORTED, ("LengthCheck!")); +#endif /* FM_LEN_CHECK_ERRATA_FMAN_SW002 */ + return E_OK; +} + +/* ......................................................................... */ + +static uint32_t GetMacAddrHashCode(uint64_t ethAddr) +{ + uint32_t crc; + + /* CRC calculation */ + GET_MAC_ADDR_CRC(ethAddr, crc); + + crc = GetMirror32(crc); + + return crc; +} + +/* ......................................................................... */ + +static void TgecErrException(t_Handle h_Tgec) +{ + t_Tgec *p_Tgec = (t_Tgec *)h_Tgec; + uint32_t event; + struct tgec_regs *p_TgecMemMap = p_Tgec->p_MemMap; + + /* do not handle MDIO events */ + event = tgec_get_event(p_TgecMemMap, ~(TGEC_IMASK_MDIO_SCAN_EVENT | TGEC_IMASK_MDIO_CMD_CMPL)); + event &= tgec_get_interrupt_mask(p_TgecMemMap); + + tgec_ack_event(p_TgecMemMap, event); + + if (event & TGEC_IMASK_REM_FAULT) + p_Tgec->f_Exception(p_Tgec->h_App, e_FM_MAC_EX_10G_REM_FAULT); + if (event & TGEC_IMASK_LOC_FAULT) + p_Tgec->f_Exception(p_Tgec->h_App, e_FM_MAC_EX_10G_LOC_FAULT); + if (event & TGEC_IMASK_TX_ECC_ER) + p_Tgec->f_Exception(p_Tgec->h_App, e_FM_MAC_EX_10G_1TX_ECC_ER); + if (event & TGEC_IMASK_TX_FIFO_UNFL) + p_Tgec->f_Exception(p_Tgec->h_App, e_FM_MAC_EX_10G_TX_FIFO_UNFL); + if (event & TGEC_IMASK_TX_FIFO_OVFL) + p_Tgec->f_Exception(p_Tgec->h_App, e_FM_MAC_EX_10G_TX_FIFO_OVFL); + if (event & TGEC_IMASK_TX_ER) + p_Tgec->f_Exception(p_Tgec->h_App, e_FM_MAC_EX_10G_TX_ER); + if (event & TGEC_IMASK_RX_FIFO_OVFL) + p_Tgec->f_Exception(p_Tgec->h_App, e_FM_MAC_EX_10G_RX_FIFO_OVFL); + if (event & TGEC_IMASK_RX_ECC_ER) + p_Tgec->f_Exception(p_Tgec->h_App, e_FM_MAC_EX_10G_RX_ECC_ER); + if (event & TGEC_IMASK_RX_JAB_FRM) + p_Tgec->f_Exception(p_Tgec->h_App, e_FM_MAC_EX_10G_RX_JAB_FRM); + if (event & TGEC_IMASK_RX_OVRSZ_FRM) + p_Tgec->f_Exception(p_Tgec->h_App, e_FM_MAC_EX_10G_RX_OVRSZ_FRM); + if (event & TGEC_IMASK_RX_RUNT_FRM) + p_Tgec->f_Exception(p_Tgec->h_App, e_FM_MAC_EX_10G_RX_RUNT_FRM); + if (event & TGEC_IMASK_RX_FRAG_FRM) + p_Tgec->f_Exception(p_Tgec->h_App, e_FM_MAC_EX_10G_RX_FRAG_FRM); + if (event & TGEC_IMASK_RX_LEN_ER) + p_Tgec->f_Exception(p_Tgec->h_App, e_FM_MAC_EX_10G_RX_LEN_ER); + if (event & TGEC_IMASK_RX_CRC_ER) + p_Tgec->f_Exception(p_Tgec->h_App, e_FM_MAC_EX_10G_RX_CRC_ER); + if (event & TGEC_IMASK_RX_ALIGN_ER) + p_Tgec->f_Exception(p_Tgec->h_App, e_FM_MAC_EX_10G_RX_ALIGN_ER); +} + +/* ......................................................................... */ + +static void TgecException(t_Handle h_Tgec) +{ + t_Tgec *p_Tgec = (t_Tgec *)h_Tgec; + uint32_t event; + struct tgec_regs *p_TgecMemMap = p_Tgec->p_MemMap; + + /* handle only MDIO events */ + event = tgec_get_event(p_TgecMemMap, (TGEC_IMASK_MDIO_SCAN_EVENT | TGEC_IMASK_MDIO_CMD_CMPL)); + event &= tgec_get_interrupt_mask(p_TgecMemMap); + + tgec_ack_event(p_TgecMemMap, event); + + if (event & TGEC_IMASK_MDIO_SCAN_EVENT) + p_Tgec->f_Event(p_Tgec->h_App, e_FM_MAC_EX_10G_MDIO_SCAN_EVENTMDIO); + if (event & TGEC_IMASK_MDIO_CMD_CMPL) + p_Tgec->f_Event(p_Tgec->h_App, e_FM_MAC_EX_10G_MDIO_CMD_CMPL); +} + +/* ......................................................................... */ + +static void FreeInitResources(t_Tgec *p_Tgec) +{ + if ((p_Tgec->mdioIrq != 0) && (p_Tgec->mdioIrq != NO_IRQ)) + { + XX_DisableIntr(p_Tgec->mdioIrq); + XX_FreeIntr(p_Tgec->mdioIrq); + } + else if (p_Tgec->mdioIrq == 0) + REPORT_ERROR(MINOR, E_NOT_SUPPORTED, NO_MSG); + FmUnregisterIntr(p_Tgec->fmMacControllerDriver.h_Fm, e_FM_MOD_10G_MAC, p_Tgec->macId, e_FM_INTR_TYPE_ERR); + + /* release the driver's group hash table */ + FreeHashTable(p_Tgec->p_MulticastAddrHash); + p_Tgec->p_MulticastAddrHash = NULL; + + /* release the driver's individual hash table */ + FreeHashTable(p_Tgec->p_UnicastAddrHash); + p_Tgec->p_UnicastAddrHash = NULL; +} + + +/*****************************************************************************/ +/* 10G MAC API routines */ +/*****************************************************************************/ + +/* ......................................................................... */ + +static t_Error TgecEnable(t_Handle h_Tgec, e_CommMode mode) +{ + t_Tgec *p_Tgec = (t_Tgec *)h_Tgec; + + SANITY_CHECK_RETURN_ERROR(p_Tgec, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(!p_Tgec->p_TgecDriverParam, E_INVALID_STATE); + + tgec_enable(p_Tgec->p_MemMap, (mode & e_COMM_MODE_RX), (mode & e_COMM_MODE_TX)); + + return E_OK; +} + +/* ......................................................................... */ + +static t_Error TgecDisable (t_Handle h_Tgec, e_CommMode mode) +{ + t_Tgec *p_Tgec = (t_Tgec *)h_Tgec; + + SANITY_CHECK_RETURN_ERROR(p_Tgec, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(!p_Tgec->p_TgecDriverParam, E_INVALID_STATE); + + tgec_disable(p_Tgec->p_MemMap, (mode & e_COMM_MODE_RX), (mode & e_COMM_MODE_TX)); + + return E_OK; +} + +/* ......................................................................... */ + +static t_Error TgecSetPromiscuous(t_Handle h_Tgec, bool newVal) +{ + t_Tgec *p_Tgec = (t_Tgec *)h_Tgec; + + SANITY_CHECK_RETURN_ERROR(p_Tgec, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(!p_Tgec->p_TgecDriverParam, E_INVALID_STATE); + + tgec_set_promiscuous(p_Tgec->p_MemMap, newVal); + + return E_OK; +} + + +/*****************************************************************************/ +/* Tgec Configs modification functions */ +/*****************************************************************************/ + +/* ......................................................................... */ + +static t_Error TgecConfigLoopback(t_Handle h_Tgec, bool newVal) +{ + t_Tgec *p_Tgec = (t_Tgec *)h_Tgec; + + SANITY_CHECK_RETURN_ERROR(p_Tgec, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_Tgec->p_TgecDriverParam, E_INVALID_STATE); + + p_Tgec->p_TgecDriverParam->loopback_enable = newVal; + + return E_OK; +} + +/* ......................................................................... */ + +static t_Error TgecConfigWan(t_Handle h_Tgec, bool newVal) +{ + t_Tgec *p_Tgec = (t_Tgec *)h_Tgec; + + SANITY_CHECK_RETURN_ERROR(p_Tgec, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_Tgec->p_TgecDriverParam, E_INVALID_STATE); + + p_Tgec->p_TgecDriverParam->wan_mode_enable = newVal; + + return E_OK; +} + +/* ......................................................................... */ + +static t_Error TgecConfigMaxFrameLength(t_Handle h_Tgec, uint16_t newVal) +{ + t_Tgec *p_Tgec = (t_Tgec *)h_Tgec; + + SANITY_CHECK_RETURN_ERROR(p_Tgec, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_Tgec->p_TgecDriverParam, E_INVALID_STATE); + + p_Tgec->p_TgecDriverParam->max_frame_length = newVal; + + return E_OK; +} + +/* ......................................................................... */ + +static t_Error TgecConfigLengthCheck(t_Handle h_Tgec, bool newVal) +{ + t_Tgec *p_Tgec = (t_Tgec *)h_Tgec; + + UNUSED(newVal); + + SANITY_CHECK_RETURN_ERROR(p_Tgec, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_Tgec->p_TgecDriverParam, E_INVALID_STATE); + + p_Tgec->p_TgecDriverParam->no_length_check_enable = !newVal; + + return E_OK; +} + +/* ......................................................................... */ + +static t_Error TgecConfigException(t_Handle h_Tgec, e_FmMacExceptions exception, bool enable) +{ + t_Tgec *p_Tgec = (t_Tgec *)h_Tgec; + uint32_t bitMask = 0; + + SANITY_CHECK_RETURN_ERROR(p_Tgec, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_Tgec->p_TgecDriverParam, E_INVALID_STATE); + + GET_EXCEPTION_FLAG(bitMask, exception); + if (bitMask) + { + if (enable) + p_Tgec->exceptions |= bitMask; + else + p_Tgec->exceptions &= ~bitMask; + } + else + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("Undefined exception")); + + return E_OK; +} + +#ifdef FM_TX_ECC_FRMS_ERRATA_10GMAC_A004 +/* ......................................................................... */ + +static t_Error TgecConfigSkipFman11Workaround(t_Handle h_Tgec) +{ + t_Tgec *p_Tgec = (t_Tgec *)h_Tgec; + + SANITY_CHECK_RETURN_ERROR(p_Tgec, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_Tgec->p_TgecDriverParam, E_INVALID_STATE); + + p_Tgec->p_TgecDriverParam->skip_fman11_workaround = TRUE; + + return E_OK; +} +#endif /* FM_TX_ECC_FRMS_ERRATA_10GMAC_A004 */ + + +/*****************************************************************************/ +/* Tgec Run Time API functions */ +/*****************************************************************************/ + +/* ......................................................................... */ +/* backward compatibility. will be removed in the future. */ +static t_Error TgecTxMacPause(t_Handle h_Tgec, uint16_t pauseTime) +{ + t_Tgec *p_Tgec = (t_Tgec *)h_Tgec; + + SANITY_CHECK_RETURN_ERROR(p_Tgec, E_INVALID_STATE); + SANITY_CHECK_RETURN_ERROR(!p_Tgec->p_TgecDriverParam, E_INVALID_STATE); + tgec_tx_mac_pause(p_Tgec->p_MemMap, pauseTime); + + + return E_OK; +} + +/* ......................................................................... */ + +static t_Error TgecSetTxPauseFrames(t_Handle h_Tgec, + uint8_t priority, + uint16_t pauseTime, + uint16_t threshTime) +{ + t_Tgec *p_Tgec = (t_Tgec *)h_Tgec; + + SANITY_CHECK_RETURN_ERROR(p_Tgec, E_INVALID_STATE); + SANITY_CHECK_RETURN_ERROR(!p_Tgec->p_TgecDriverParam, E_INVALID_STATE); + + UNUSED(priority); UNUSED(threshTime); + + tgec_tx_mac_pause(p_Tgec->p_MemMap, pauseTime); + + return E_OK; +} + +/* ......................................................................... */ + +static t_Error TgecRxIgnoreMacPause(t_Handle h_Tgec, bool en) +{ + t_Tgec *p_Tgec = (t_Tgec *)h_Tgec; + + SANITY_CHECK_RETURN_ERROR(p_Tgec, E_INVALID_STATE); + SANITY_CHECK_RETURN_ERROR(!p_Tgec->p_TgecDriverParam, E_INVALID_STATE); + + tgec_rx_ignore_mac_pause(p_Tgec->p_MemMap, en); + + return E_OK; +} + +/* ......................................................................... */ + +static t_Error TgecGetStatistics(t_Handle h_Tgec, t_FmMacStatistics *p_Statistics) +{ + t_Tgec *p_Tgec = (t_Tgec *)h_Tgec; + struct tgec_regs *p_TgecMemMap; + + SANITY_CHECK_RETURN_ERROR(p_Tgec, E_NULL_POINTER); + SANITY_CHECK_RETURN_ERROR(!p_Tgec->p_TgecDriverParam, E_INVALID_STATE); + SANITY_CHECK_RETURN_ERROR(p_Statistics, E_NULL_POINTER); + + p_TgecMemMap = p_Tgec->p_MemMap; + + p_Statistics->eStatPkts64 = tgec_get_counter(p_TgecMemMap, E_TGEC_COUNTER_R64); + p_Statistics->eStatPkts65to127 = tgec_get_counter(p_TgecMemMap, E_TGEC_COUNTER_R127); + p_Statistics->eStatPkts128to255 = tgec_get_counter(p_TgecMemMap, E_TGEC_COUNTER_R255); + p_Statistics->eStatPkts256to511 = tgec_get_counter(p_TgecMemMap, E_TGEC_COUNTER_R511); + p_Statistics->eStatPkts512to1023 = tgec_get_counter(p_TgecMemMap, E_TGEC_COUNTER_R1023); + p_Statistics->eStatPkts1024to1518 = tgec_get_counter(p_TgecMemMap, E_TGEC_COUNTER_R1518); + p_Statistics->eStatPkts1519to1522 = tgec_get_counter(p_TgecMemMap, E_TGEC_COUNTER_R1519X); +/* */ + p_Statistics->eStatFragments = tgec_get_counter(p_TgecMemMap, E_TGEC_COUNTER_TRFRG); + p_Statistics->eStatJabbers = tgec_get_counter(p_TgecMemMap, E_TGEC_COUNTER_TRJBR); + + p_Statistics->eStatsDropEvents = tgec_get_counter(p_TgecMemMap, E_TGEC_COUNTER_RDRP); + p_Statistics->eStatCRCAlignErrors = tgec_get_counter(p_TgecMemMap, E_TGEC_COUNTER_RALN); + + p_Statistics->eStatUndersizePkts = tgec_get_counter(p_TgecMemMap, E_TGEC_COUNTER_TRUND); + p_Statistics->eStatOversizePkts = tgec_get_counter(p_TgecMemMap, E_TGEC_COUNTER_TROVR); +/* Pause */ + p_Statistics->reStatPause = tgec_get_counter(p_TgecMemMap, E_TGEC_COUNTER_RXPF); + p_Statistics->teStatPause = tgec_get_counter(p_TgecMemMap, E_TGEC_COUNTER_TXPF); + +/* MIB II */ + p_Statistics->ifInOctets = tgec_get_counter(p_TgecMemMap, E_TGEC_COUNTER_ROCT); + p_Statistics->ifInUcastPkts = tgec_get_counter(p_TgecMemMap, E_TGEC_COUNTER_RUCA); + p_Statistics->ifInMcastPkts = tgec_get_counter(p_TgecMemMap, E_TGEC_COUNTER_RMCA); + p_Statistics->ifInBcastPkts = tgec_get_counter(p_TgecMemMap, E_TGEC_COUNTER_RBCA); + p_Statistics->ifInPkts = p_Statistics->ifInUcastPkts + + p_Statistics->ifInMcastPkts + + p_Statistics->ifInBcastPkts; + p_Statistics->ifInDiscards = 0; + p_Statistics->ifInErrors = tgec_get_counter(p_TgecMemMap, E_TGEC_COUNTER_RERR); + + p_Statistics->ifOutOctets = tgec_get_counter(p_TgecMemMap, E_TGEC_COUNTER_TOCT); + p_Statistics->ifOutUcastPkts = tgec_get_counter(p_TgecMemMap, E_TGEC_COUNTER_TUCA); + p_Statistics->ifOutMcastPkts = tgec_get_counter(p_TgecMemMap, E_TGEC_COUNTER_TMCA); + p_Statistics->ifOutBcastPkts = tgec_get_counter(p_TgecMemMap, E_TGEC_COUNTER_TBCA); + p_Statistics->ifOutPkts = p_Statistics->ifOutUcastPkts + + p_Statistics->ifOutMcastPkts + + p_Statistics->ifOutBcastPkts; + p_Statistics->ifOutDiscards = 0; + p_Statistics->ifOutErrors = tgec_get_counter(p_TgecMemMap, E_TGEC_COUNTER_TERR); + + return E_OK; +} + +/* ......................................................................... */ + +static t_Error TgecEnable1588TimeStamp(t_Handle h_Tgec) +{ + t_Tgec *p_Tgec = (t_Tgec *)h_Tgec; + + SANITY_CHECK_RETURN_ERROR(p_Tgec, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(!p_Tgec->p_TgecDriverParam, E_INVALID_STATE); + + tgec_enable_1588_time_stamp(p_Tgec->p_MemMap, 1); + + return E_OK; +} + +/* ......................................................................... */ + +static t_Error TgecDisable1588TimeStamp(t_Handle h_Tgec) +{ + t_Tgec *p_Tgec = (t_Tgec *)h_Tgec; + + SANITY_CHECK_RETURN_ERROR(p_Tgec, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(!p_Tgec->p_TgecDriverParam, E_INVALID_STATE); + + tgec_enable_1588_time_stamp(p_Tgec->p_MemMap, 0); + + return E_OK; +} + +/* ......................................................................... */ + +static t_Error TgecModifyMacAddress (t_Handle h_Tgec, t_EnetAddr *p_EnetAddr) +{ + t_Tgec *p_Tgec = (t_Tgec *)h_Tgec; + + SANITY_CHECK_RETURN_ERROR(p_Tgec, E_NULL_POINTER); + SANITY_CHECK_RETURN_ERROR(!p_Tgec->p_TgecDriverParam, E_INVALID_STATE); + + p_Tgec->addr = ENET_ADDR_TO_UINT64(*p_EnetAddr); + tgec_set_mac_address(p_Tgec->p_MemMap, (uint8_t *)(*p_EnetAddr)); + + return E_OK; +} + +/* ......................................................................... */ + +static t_Error TgecResetCounters (t_Handle h_Tgec) +{ + t_Tgec *p_Tgec = (t_Tgec *)h_Tgec; + + SANITY_CHECK_RETURN_ERROR(p_Tgec, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(!p_Tgec->p_TgecDriverParam, E_INVALID_STATE); + + tgec_reset_stat(p_Tgec->p_MemMap); + + return E_OK; +} + +/* ......................................................................... */ + +static t_Error TgecAddExactMatchMacAddress(t_Handle h_Tgec, t_EnetAddr *p_EthAddr) +{ + t_Tgec *p_Tgec = (t_Tgec *) h_Tgec; + uint64_t ethAddr; + uint8_t paddrNum; + + SANITY_CHECK_RETURN_ERROR(p_Tgec, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(!p_Tgec->p_TgecDriverParam, E_INVALID_STATE); + + ethAddr = ENET_ADDR_TO_UINT64(*p_EthAddr); + + if (ethAddr & GROUP_ADDRESS) + /* Multicast address has no effect in PADDR */ + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("Multicast address")); + + /* Make sure no PADDR contains this address */ + for (paddrNum = 0; paddrNum < TGEC_NUM_OF_PADDRS; paddrNum++) + if (p_Tgec->indAddrRegUsed[paddrNum]) + if (p_Tgec->paddr[paddrNum] == ethAddr) + RETURN_ERROR(MAJOR, E_ALREADY_EXISTS, NO_MSG); + + /* Find first unused PADDR */ + for (paddrNum = 0; paddrNum < TGEC_NUM_OF_PADDRS; paddrNum++) + { + if (!(p_Tgec->indAddrRegUsed[paddrNum])) + { + /* mark this PADDR as used */ + p_Tgec->indAddrRegUsed[paddrNum] = TRUE; + /* store address */ + p_Tgec->paddr[paddrNum] = ethAddr; + + /* put in hardware */ + tgec_add_addr_in_paddr(p_Tgec->p_MemMap, (uint8_t*)(*p_EthAddr)/* , paddrNum */); + p_Tgec->numOfIndAddrInRegs++; + + return E_OK; + } + } + + /* No free PADDR */ + RETURN_ERROR(MAJOR, E_FULL, NO_MSG); +} + +/* ......................................................................... */ + +static t_Error TgecDelExactMatchMacAddress(t_Handle h_Tgec, t_EnetAddr *p_EthAddr) +{ + t_Tgec *p_Tgec = (t_Tgec *) h_Tgec; + uint64_t ethAddr; + uint8_t paddrNum; + + SANITY_CHECK_RETURN_ERROR(p_Tgec, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(!p_Tgec->p_TgecDriverParam, E_INVALID_STATE); + + ethAddr = ENET_ADDR_TO_UINT64(*p_EthAddr); + + /* Find used PADDR containing this address */ + for (paddrNum = 0; paddrNum < TGEC_NUM_OF_PADDRS; paddrNum++) + { + if ((p_Tgec->indAddrRegUsed[paddrNum]) && + (p_Tgec->paddr[paddrNum] == ethAddr)) + { + /* mark this PADDR as not used */ + p_Tgec->indAddrRegUsed[paddrNum] = FALSE; + /* clear in hardware */ + tgec_clear_addr_in_paddr(p_Tgec->p_MemMap /*, paddrNum */); + p_Tgec->numOfIndAddrInRegs--; + + return E_OK; + } + } + + RETURN_ERROR(MAJOR, E_NOT_FOUND, NO_MSG); +} + +/* ......................................................................... */ + +static t_Error TgecAddHashMacAddress(t_Handle h_Tgec, t_EnetAddr *p_EthAddr) +{ + t_Tgec *p_Tgec = (t_Tgec *)h_Tgec; + t_EthHashEntry *p_HashEntry; + uint32_t crc; + uint32_t hash; + uint64_t ethAddr; + + SANITY_CHECK_RETURN_ERROR(p_Tgec, E_NULL_POINTER); + SANITY_CHECK_RETURN_ERROR(!p_Tgec->p_TgecDriverParam, E_INVALID_STATE); + + ethAddr = ENET_ADDR_TO_UINT64(*p_EthAddr); + + if (!(ethAddr & GROUP_ADDRESS)) + /* Unicast addresses not supported in hash */ + RETURN_ERROR(MAJOR, E_NOT_SUPPORTED, ("Unicast Address")); + + /* CRC calculation */ + crc = GetMacAddrHashCode(ethAddr); + + hash = (crc >> TGEC_HASH_MCAST_SHIFT) & TGEC_HASH_ADR_MSK; /* Take 9 MSB bits */ + + /* Create element to be added to the driver hash table */ + p_HashEntry = (t_EthHashEntry *)XX_Malloc(sizeof(t_EthHashEntry)); + p_HashEntry->addr = ethAddr; + INIT_LIST(&p_HashEntry->node); + + LIST_AddToTail(&(p_HashEntry->node), &(p_Tgec->p_MulticastAddrHash->p_Lsts[hash])); + tgec_set_hash_table(p_Tgec->p_MemMap, (hash | TGEC_HASH_MCAST_EN)); + + return E_OK; +} + +/* ......................................................................... */ + +static t_Error TgecDelHashMacAddress(t_Handle h_Tgec, t_EnetAddr *p_EthAddr) +{ + t_Tgec *p_Tgec = (t_Tgec *)h_Tgec; + t_EthHashEntry *p_HashEntry = NULL; + t_List *p_Pos; + uint32_t crc; + uint32_t hash; + uint64_t ethAddr; + + SANITY_CHECK_RETURN_ERROR(p_Tgec, E_NULL_POINTER); + SANITY_CHECK_RETURN_ERROR(!p_Tgec->p_TgecDriverParam, E_INVALID_STATE); + + ethAddr = ((*(uint64_t *)p_EthAddr) >> 16); + + /* CRC calculation */ + crc = GetMacAddrHashCode(ethAddr); + + hash = (crc >> TGEC_HASH_MCAST_SHIFT) & TGEC_HASH_ADR_MSK; /* Take 9 MSB bits */ + + LIST_FOR_EACH(p_Pos, &(p_Tgec->p_MulticastAddrHash->p_Lsts[hash])) + { + p_HashEntry = ETH_HASH_ENTRY_OBJ(p_Pos); + if (p_HashEntry->addr == ethAddr) + { + LIST_DelAndInit(&p_HashEntry->node); + XX_Free(p_HashEntry); + break; + } + } + if (LIST_IsEmpty(&p_Tgec->p_MulticastAddrHash->p_Lsts[hash])) + tgec_set_hash_table(p_Tgec->p_MemMap, (hash & ~TGEC_HASH_MCAST_EN)); + + return E_OK; +} + +/* ......................................................................... */ + +static t_Error TgecGetId(t_Handle h_Tgec, uint32_t *macId) +{ + t_Tgec *p_Tgec = (t_Tgec *)h_Tgec; + + SANITY_CHECK_RETURN_ERROR(p_Tgec, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(!p_Tgec->p_TgecDriverParam, E_INVALID_STATE); + + UNUSED(p_Tgec); + UNUSED(macId); + RETURN_ERROR(MINOR, E_NOT_SUPPORTED, ("TgecGetId Not Supported")); +} + +/* ......................................................................... */ + +static t_Error TgecGetVersion(t_Handle h_Tgec, uint32_t *macVersion) +{ + t_Tgec *p_Tgec = (t_Tgec *)h_Tgec; + + SANITY_CHECK_RETURN_ERROR(p_Tgec, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(!p_Tgec->p_TgecDriverParam, E_INVALID_STATE); + + *macVersion = tgec_get_revision(p_Tgec->p_MemMap); + + return E_OK; +} + +/* ......................................................................... */ + +static t_Error TgecSetExcpetion(t_Handle h_Tgec, e_FmMacExceptions exception, bool enable) +{ + t_Tgec *p_Tgec = (t_Tgec *)h_Tgec; + uint32_t bitMask = 0; + + SANITY_CHECK_RETURN_ERROR(p_Tgec, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(!p_Tgec->p_TgecDriverParam, E_INVALID_STATE); + + GET_EXCEPTION_FLAG(bitMask, exception); + if (bitMask) + { + if (enable) + p_Tgec->exceptions |= bitMask; + else + p_Tgec->exceptions &= ~bitMask; + } + else + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("Undefined exception")); + + if (enable) + tgec_enable_interrupt(p_Tgec->p_MemMap, bitMask); + else + tgec_disable_interrupt(p_Tgec->p_MemMap, bitMask); + + return E_OK; +} + +/* ......................................................................... */ + +static uint16_t TgecGetMaxFrameLength(t_Handle h_Tgec) +{ + t_Tgec *p_Tgec = (t_Tgec *)h_Tgec; + + SANITY_CHECK_RETURN_VALUE(p_Tgec, E_INVALID_HANDLE, 0); + SANITY_CHECK_RETURN_VALUE(!p_Tgec->p_TgecDriverParam, E_INVALID_STATE, 0); + + return tgec_get_max_frame_len(p_Tgec->p_MemMap); +} + +/* ......................................................................... */ + +#ifdef FM_TX_ECC_FRMS_ERRATA_10GMAC_A004 +static t_Error TgecTxEccWorkaround(t_Tgec *p_Tgec) +{ + t_Error err; + +#if defined(DEBUG_ERRORS) && (DEBUG_ERRORS > 0) + XX_Print("Applying 10G TX ECC workaround (10GMAC-A004) ... "); +#endif /* (DEBUG_ERRORS > 0) */ + /* enable and set promiscuous */ + tgec_enable(p_Tgec->p_MemMap, TRUE, TRUE); + tgec_set_promiscuous(p_Tgec->p_MemMap, TRUE); + err = Fm10GTxEccWorkaround(p_Tgec->fmMacControllerDriver.h_Fm, p_Tgec->macId); + /* disable */ + tgec_set_promiscuous(p_Tgec->p_MemMap, FALSE); + tgec_enable(p_Tgec->p_MemMap, FALSE, FALSE); +#if defined(DEBUG_ERRORS) && (DEBUG_ERRORS > 0) + if (err) + XX_Print("FAILED!\n"); + else + XX_Print("done.\n"); +#endif /* (DEBUG_ERRORS > 0) */ + tgec_reset_stat(p_Tgec->p_MemMap); + + return err; +} +#endif /* FM_TX_ECC_FRMS_ERRATA_10GMAC_A004 */ + +/* ......................................................................... */ + +#if (defined(DEBUG_ERRORS) && (DEBUG_ERRORS > 0)) +static t_Error TgecDumpRegs(t_Handle h_Tgec) +{ + t_Tgec *p_Tgec = (t_Tgec *)h_Tgec; + + DECLARE_DUMP; + + if (p_Tgec->p_MemMap) + { + DUMP_TITLE(p_Tgec->p_MemMap, ("10G MAC %d: ", p_Tgec->macId)); + DUMP_VAR(p_Tgec->p_MemMap, tgec_id); + DUMP_VAR(p_Tgec->p_MemMap, command_config); + DUMP_VAR(p_Tgec->p_MemMap, mac_addr_0); + DUMP_VAR(p_Tgec->p_MemMap, mac_addr_1); + DUMP_VAR(p_Tgec->p_MemMap, maxfrm); + DUMP_VAR(p_Tgec->p_MemMap, pause_quant); + DUMP_VAR(p_Tgec->p_MemMap, rx_fifo_sections); + DUMP_VAR(p_Tgec->p_MemMap, tx_fifo_sections); + DUMP_VAR(p_Tgec->p_MemMap, rx_fifo_almost_f_e); + DUMP_VAR(p_Tgec->p_MemMap, tx_fifo_almost_f_e); + DUMP_VAR(p_Tgec->p_MemMap, hashtable_ctrl); + DUMP_VAR(p_Tgec->p_MemMap, mdio_cfg_status); + DUMP_VAR(p_Tgec->p_MemMap, mdio_command); + DUMP_VAR(p_Tgec->p_MemMap, mdio_data); + DUMP_VAR(p_Tgec->p_MemMap, mdio_regaddr); + DUMP_VAR(p_Tgec->p_MemMap, status); + DUMP_VAR(p_Tgec->p_MemMap, tx_ipg_len); + DUMP_VAR(p_Tgec->p_MemMap, mac_addr_2); + DUMP_VAR(p_Tgec->p_MemMap, mac_addr_3); + DUMP_VAR(p_Tgec->p_MemMap, rx_fifo_ptr_rd); + DUMP_VAR(p_Tgec->p_MemMap, rx_fifo_ptr_wr); + DUMP_VAR(p_Tgec->p_MemMap, tx_fifo_ptr_rd); + DUMP_VAR(p_Tgec->p_MemMap, tx_fifo_ptr_wr); + DUMP_VAR(p_Tgec->p_MemMap, imask); + DUMP_VAR(p_Tgec->p_MemMap, ievent); + } + + return E_OK; +} +#endif /* (defined(DEBUG_ERRORS) && ... */ + + +/*****************************************************************************/ +/* FM Init & Free API */ +/*****************************************************************************/ + +/* ......................................................................... */ + +static t_Error TgecInit(t_Handle h_Tgec) +{ + t_Tgec *p_Tgec = (t_Tgec *)h_Tgec; + struct tgec_cfg *p_TgecDriverParam; + t_EnetAddr ethAddr; + t_Error err; + + SANITY_CHECK_RETURN_ERROR(p_Tgec, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_Tgec->p_TgecDriverParam, E_INVALID_STATE); + SANITY_CHECK_RETURN_ERROR(p_Tgec->fmMacControllerDriver.h_Fm, E_INVALID_HANDLE); + + FM_GetRevision(p_Tgec->fmMacControllerDriver.h_Fm, &p_Tgec->fmMacControllerDriver.fmRevInfo); + CHECK_INIT_PARAMETERS(p_Tgec, CheckInitParameters); + + p_TgecDriverParam = p_Tgec->p_TgecDriverParam; + + MAKE_ENET_ADDR_FROM_UINT64(p_Tgec->addr, ethAddr); + tgec_set_mac_address(p_Tgec->p_MemMap, (uint8_t *)ethAddr); + + /* interrupts */ +#ifdef FM_10G_REM_N_LCL_FLT_EX_10GMAC_ERRATA_SW005 + { + if (p_Tgec->fmMacControllerDriver.fmRevInfo.majorRev <=2) + p_Tgec->exceptions &= ~(TGEC_IMASK_REM_FAULT | TGEC_IMASK_LOC_FAULT); + } +#endif /* FM_10G_REM_N_LCL_FLT_EX_10GMAC_ERRATA_SW005 */ + +#ifdef FM_TX_ECC_FRMS_ERRATA_10GMAC_A004 + if (p_Tgec->fmMacControllerDriver.fmRevInfo.majorRev <= 6 /*fixed for rev3 */) + { + if (!p_Tgec->p_TgecDriverParam->skip_fman11_workaround && + ((err = TgecTxEccWorkaround(p_Tgec)) != E_OK)) + { + FreeInitResources(p_Tgec); + REPORT_ERROR(MINOR, err, ("TgecTxEccWorkaround FAILED")); + } + } +#endif /* FM_TX_ECC_FRMS_ERRATA_10GMAC_A004 */ + + err = tgec_init(p_Tgec->p_MemMap, p_TgecDriverParam, p_Tgec->exceptions); + if (err) + { + FreeInitResources(p_Tgec); + RETURN_ERROR(MAJOR, err, ("This TGEC version does not support the required i/f mode")); + } + + /* Max Frame Length */ + err = FmSetMacMaxFrame(p_Tgec->fmMacControllerDriver.h_Fm, + e_FM_MAC_10G, + p_Tgec->fmMacControllerDriver.macId, + p_TgecDriverParam->max_frame_length); + /* we consider having no IPC a non crasher... */ + +#ifdef FM_TX_FIFO_CORRUPTION_ERRATA_10GMAC_A007 + if (p_Tgec->fmMacControllerDriver.fmRevInfo.majorRev == 2) + tgec_fm_tx_fifo_corruption_errata_10gmac_a007(p_Tgec->p_MemMap); +#endif /* FM_TX_FIFO_CORRUPTION_ERRATA_10GMAC_A007 */ + + p_Tgec->p_MulticastAddrHash = AllocHashTable(HASH_TABLE_SIZE); + if (!p_Tgec->p_MulticastAddrHash) + { + FreeInitResources(p_Tgec); + RETURN_ERROR(MAJOR, E_NO_MEMORY, ("allocation hash table is FAILED")); + } + + p_Tgec->p_UnicastAddrHash = AllocHashTable(HASH_TABLE_SIZE); + if (!p_Tgec->p_UnicastAddrHash) + { + FreeInitResources(p_Tgec); + RETURN_ERROR(MAJOR, E_NO_MEMORY, ("allocation hash table is FAILED")); + } + + FmRegisterIntr(p_Tgec->fmMacControllerDriver.h_Fm, + e_FM_MOD_10G_MAC, + p_Tgec->macId, + e_FM_INTR_TYPE_ERR, + TgecErrException, + p_Tgec); + if ((p_Tgec->mdioIrq != 0) && (p_Tgec->mdioIrq != NO_IRQ)) + { + XX_SetIntr(p_Tgec->mdioIrq, TgecException, p_Tgec); + XX_EnableIntr(p_Tgec->mdioIrq); + } + else if (p_Tgec->mdioIrq == 0) + REPORT_ERROR(MINOR, E_NOT_SUPPORTED, (NO_MSG)); + + XX_Free(p_TgecDriverParam); + p_Tgec->p_TgecDriverParam = NULL; + + return E_OK; +} + +/* ......................................................................... */ + +static t_Error TgecFree(t_Handle h_Tgec) +{ + t_Tgec *p_Tgec = (t_Tgec *)h_Tgec; + + SANITY_CHECK_RETURN_ERROR(p_Tgec, E_INVALID_HANDLE); + + FreeInitResources(p_Tgec); + + if (p_Tgec->p_TgecDriverParam) + { + XX_Free(p_Tgec->p_TgecDriverParam); + p_Tgec->p_TgecDriverParam = NULL; + } + XX_Free (p_Tgec); + + return E_OK; +} + +/* ......................................................................... */ + +static void InitFmMacControllerDriver(t_FmMacControllerDriver *p_FmMacControllerDriver) +{ + p_FmMacControllerDriver->f_FM_MAC_Init = TgecInit; + p_FmMacControllerDriver->f_FM_MAC_Free = TgecFree; + + p_FmMacControllerDriver->f_FM_MAC_SetStatistics = NULL; + p_FmMacControllerDriver->f_FM_MAC_ConfigLoopback = TgecConfigLoopback; + p_FmMacControllerDriver->f_FM_MAC_ConfigMaxFrameLength = TgecConfigMaxFrameLength; + + p_FmMacControllerDriver->f_FM_MAC_ConfigWan = TgecConfigWan; + + p_FmMacControllerDriver->f_FM_MAC_ConfigPadAndCrc = NULL; /* TGEC always works with pad+crc */ + p_FmMacControllerDriver->f_FM_MAC_ConfigHalfDuplex = NULL; /* half-duplex is not supported in xgec */ + p_FmMacControllerDriver->f_FM_MAC_ConfigLengthCheck = TgecConfigLengthCheck; + p_FmMacControllerDriver->f_FM_MAC_ConfigException = TgecConfigException; + p_FmMacControllerDriver->f_FM_MAC_ConfigResetOnInit = NULL; + +#ifdef FM_TX_ECC_FRMS_ERRATA_10GMAC_A004 + p_FmMacControllerDriver->f_FM_MAC_ConfigSkipFman11Workaround= TgecConfigSkipFman11Workaround; +#endif /* FM_TX_ECC_FRMS_ERRATA_10GMAC_A004 */ + + p_FmMacControllerDriver->f_FM_MAC_SetException = TgecSetExcpetion; + + p_FmMacControllerDriver->f_FM_MAC_Enable1588TimeStamp = TgecEnable1588TimeStamp; + p_FmMacControllerDriver->f_FM_MAC_Disable1588TimeStamp = TgecDisable1588TimeStamp; + + p_FmMacControllerDriver->f_FM_MAC_SetPromiscuous = TgecSetPromiscuous; + p_FmMacControllerDriver->f_FM_MAC_AdjustLink = NULL; + p_FmMacControllerDriver->f_FM_MAC_RestartAutoneg = NULL; + + p_FmMacControllerDriver->f_FM_MAC_Enable = TgecEnable; + p_FmMacControllerDriver->f_FM_MAC_Disable = TgecDisable; + + p_FmMacControllerDriver->f_FM_MAC_SetTxAutoPauseFrames = TgecTxMacPause; + p_FmMacControllerDriver->f_FM_MAC_SetTxPauseFrames = TgecSetTxPauseFrames; + p_FmMacControllerDriver->f_FM_MAC_SetRxIgnorePauseFrames = TgecRxIgnoreMacPause; + + p_FmMacControllerDriver->f_FM_MAC_ResetCounters = TgecResetCounters; + p_FmMacControllerDriver->f_FM_MAC_GetStatistics = TgecGetStatistics; + + p_FmMacControllerDriver->f_FM_MAC_ModifyMacAddr = TgecModifyMacAddress; + p_FmMacControllerDriver->f_FM_MAC_AddHashMacAddr = TgecAddHashMacAddress; + p_FmMacControllerDriver->f_FM_MAC_RemoveHashMacAddr = TgecDelHashMacAddress; + p_FmMacControllerDriver->f_FM_MAC_AddExactMatchMacAddr = TgecAddExactMatchMacAddress; + p_FmMacControllerDriver->f_FM_MAC_RemovelExactMatchMacAddr = TgecDelExactMatchMacAddress; + p_FmMacControllerDriver->f_FM_MAC_GetId = TgecGetId; + p_FmMacControllerDriver->f_FM_MAC_GetVersion = TgecGetVersion; + p_FmMacControllerDriver->f_FM_MAC_GetMaxFrameLength = TgecGetMaxFrameLength; + + p_FmMacControllerDriver->f_FM_MAC_MII_WritePhyReg = TGEC_MII_WritePhyReg; + p_FmMacControllerDriver->f_FM_MAC_MII_ReadPhyReg = TGEC_MII_ReadPhyReg; + +#if (defined(DEBUG_ERRORS) && (DEBUG_ERRORS > 0)) + p_FmMacControllerDriver->f_FM_MAC_DumpRegs = TgecDumpRegs; +#endif /* (defined(DEBUG_ERRORS) && ... */ +} + + +/*****************************************************************************/ +/* Tgec Config Main Entry */ +/*****************************************************************************/ + +/* ......................................................................... */ + +t_Handle TGEC_Config(t_FmMacParams *p_FmMacParam) +{ + t_Tgec *p_Tgec; + struct tgec_cfg *p_TgecDriverParam; + uintptr_t baseAddr; + + SANITY_CHECK_RETURN_VALUE(p_FmMacParam, E_NULL_POINTER, NULL); + + baseAddr = p_FmMacParam->baseAddr; + /* allocate memory for the UCC GETH data structure. */ + p_Tgec = (t_Tgec *)XX_Malloc(sizeof(t_Tgec)); + if (!p_Tgec) + { + REPORT_ERROR(MAJOR, E_NO_MEMORY, ("10G MAC driver structure")); + return NULL; + } + memset(p_Tgec, 0, sizeof(t_Tgec)); + InitFmMacControllerDriver(&p_Tgec->fmMacControllerDriver); + + /* allocate memory for the 10G MAC driver parameters data structure. */ + p_TgecDriverParam = (struct tgec_cfg *) XX_Malloc(sizeof(struct tgec_cfg)); + if (!p_TgecDriverParam) + { + REPORT_ERROR(MAJOR, E_NO_MEMORY, ("10G MAC driver parameters")); + TgecFree(p_Tgec); + return NULL; + } + memset(p_TgecDriverParam, 0, sizeof(struct tgec_cfg)); + + /* Plant parameter structure pointer */ + p_Tgec->p_TgecDriverParam = p_TgecDriverParam; + + tgec_defconfig(p_TgecDriverParam); + + p_Tgec->p_MemMap = (struct tgec_regs *)UINT_TO_PTR(baseAddr); + p_Tgec->p_MiiMemMap = (t_TgecMiiAccessMemMap *)UINT_TO_PTR(baseAddr + TGEC_TO_MII_OFFSET); + p_Tgec->addr = ENET_ADDR_TO_UINT64(p_FmMacParam->addr); + p_Tgec->enetMode = p_FmMacParam->enetMode; + p_Tgec->macId = p_FmMacParam->macId; + p_Tgec->exceptions = DEFAULT_exceptions; + p_Tgec->mdioIrq = p_FmMacParam->mdioIrq; + p_Tgec->f_Exception = p_FmMacParam->f_Exception; + p_Tgec->f_Event = p_FmMacParam->f_Event; + p_Tgec->h_App = p_FmMacParam->h_App; + + return p_Tgec; +} diff --git a/drivers/net/ethernet/freescale/fman/Peripherals/FM/MAC/tgec.h b/drivers/net/ethernet/freescale/fman/Peripherals/FM/MAC/tgec.h new file mode 100644 index 0000000..2aa3923 --- /dev/null +++ b/drivers/net/ethernet/freescale/fman/Peripherals/FM/MAC/tgec.h @@ -0,0 +1,151 @@ +/* + * Copyright 2008-2012 Freescale Semiconductor Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Freescale Semiconductor nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + +/****************************************************************************** + @File tgec.h + + @Description FM 10G MAC ... +*//***************************************************************************/ +#ifndef __TGEC_H +#define __TGEC_H + +#include "std_ext.h" +#include "error_ext.h" +#include "list_ext.h" +#include "enet_ext.h" + +#include "tgec_mii_acc.h" +#include "fm_mac.h" + + +#define DEFAULT_exceptions \ + ((uint32_t)(TGEC_IMASK_MDIO_SCAN_EVENT | \ + TGEC_IMASK_REM_FAULT | \ + TGEC_IMASK_LOC_FAULT | \ + TGEC_IMASK_TX_ECC_ER | \ + TGEC_IMASK_TX_FIFO_UNFL | \ + TGEC_IMASK_TX_FIFO_OVFL | \ + TGEC_IMASK_TX_ER | \ + TGEC_IMASK_RX_FIFO_OVFL | \ + TGEC_IMASK_RX_ECC_ER | \ + TGEC_IMASK_RX_JAB_FRM | \ + TGEC_IMASK_RX_OVRSZ_FRM | \ + TGEC_IMASK_RX_RUNT_FRM | \ + TGEC_IMASK_RX_FRAG_FRM | \ + TGEC_IMASK_RX_CRC_ER | \ + TGEC_IMASK_RX_ALIGN_ER)) + +#define GET_EXCEPTION_FLAG(bitMask, exception) switch (exception){ \ + case e_FM_MAC_EX_10G_MDIO_SCAN_EVENTMDIO: \ + bitMask = TGEC_IMASK_MDIO_SCAN_EVENT ; break; \ + case e_FM_MAC_EX_10G_MDIO_CMD_CMPL: \ + bitMask = TGEC_IMASK_MDIO_CMD_CMPL ; break; \ + case e_FM_MAC_EX_10G_REM_FAULT: \ + bitMask = TGEC_IMASK_REM_FAULT ; break; \ + case e_FM_MAC_EX_10G_LOC_FAULT: \ + bitMask = TGEC_IMASK_LOC_FAULT ; break; \ + case e_FM_MAC_EX_10G_1TX_ECC_ER: \ + bitMask = TGEC_IMASK_TX_ECC_ER ; break; \ + case e_FM_MAC_EX_10G_TX_FIFO_UNFL: \ + bitMask = TGEC_IMASK_TX_FIFO_UNFL ; break; \ + case e_FM_MAC_EX_10G_TX_FIFO_OVFL: \ + bitMask = TGEC_IMASK_TX_FIFO_OVFL ; break; \ + case e_FM_MAC_EX_10G_TX_ER: \ + bitMask = TGEC_IMASK_TX_ER ; break; \ + case e_FM_MAC_EX_10G_RX_FIFO_OVFL: \ + bitMask = TGEC_IMASK_RX_FIFO_OVFL ; break; \ + case e_FM_MAC_EX_10G_RX_ECC_ER: \ + bitMask = TGEC_IMASK_RX_ECC_ER ; break; \ + case e_FM_MAC_EX_10G_RX_JAB_FRM: \ + bitMask = TGEC_IMASK_RX_JAB_FRM ; break; \ + case e_FM_MAC_EX_10G_RX_OVRSZ_FRM: \ + bitMask = TGEC_IMASK_RX_OVRSZ_FRM ; break; \ + case e_FM_MAC_EX_10G_RX_RUNT_FRM: \ + bitMask = TGEC_IMASK_RX_RUNT_FRM ; break; \ + case e_FM_MAC_EX_10G_RX_FRAG_FRM: \ + bitMask = TGEC_IMASK_RX_FRAG_FRM ; break; \ + case e_FM_MAC_EX_10G_RX_LEN_ER: \ + bitMask = TGEC_IMASK_RX_LEN_ER ; break; \ + case e_FM_MAC_EX_10G_RX_CRC_ER: \ + bitMask = TGEC_IMASK_RX_CRC_ER ; break; \ + case e_FM_MAC_EX_10G_RX_ALIGN_ER: \ + bitMask = TGEC_IMASK_RX_ALIGN_ER ; break; \ + default: bitMask = 0;break;} + +#define MAX_PACKET_ALIGNMENT 31 +#define MAX_INTER_PACKET_GAP 0x7f +#define MAX_INTER_PALTERNATE_BEB 0x0f +#define MAX_RETRANSMISSION 0x0f +#define MAX_COLLISION_WINDOW 0x03ff + +#define TGEC_NUM_OF_PADDRS 1 /* number of pattern match registers (entries) */ + +#define GROUP_ADDRESS 0x0000010000000000LL /* Group address bit indication */ + +#define HASH_TABLE_SIZE 512 /* Hash table size (= 32 bits * 8 regs) */ + +#define TGEC_TO_MII_OFFSET 0x1030 /* Offset from the MEM map to the MDIO mem map */ + +/* 10-gigabit Ethernet MAC Controller ID (10GEC_ID) */ +#define TGEC_ID_ID 0xffff0000 +#define TGEC_ID_MAC_VERSION 0x0000FF00 +#define TGEC_ID_MAC_REV 0x000000ff + + +typedef struct { + t_FmMacControllerDriver fmMacControllerDriver; /**< Upper Mac control block */ + t_Handle h_App; /**< Handle to the upper layer application */ + struct tgec_regs *p_MemMap; /**< pointer to 10G memory mapped registers. */ + t_TgecMiiAccessMemMap *p_MiiMemMap; /**< pointer to MII memory mapped registers. */ + uint64_t addr; /**< MAC address of device; */ + e_EnetMode enetMode; /**< Ethernet physical interface */ + t_FmMacExceptionCallback *f_Exception; + int mdioIrq; + t_FmMacExceptionCallback *f_Event; + bool indAddrRegUsed[TGEC_NUM_OF_PADDRS]; /**< Whether a particular individual address recognition register is being used */ + uint64_t paddr[TGEC_NUM_OF_PADDRS]; /**< MAC address for particular individual address recognition register */ + uint8_t numOfIndAddrInRegs; /**< Number of individual addresses in registers for this station. */ + t_EthHash *p_MulticastAddrHash; /**< pointer to driver's global address hash table */ + t_EthHash *p_UnicastAddrHash; /**< pointer to driver's individual address hash table */ + bool debugMode; + uint8_t macId; + uint32_t exceptions; + struct tgec_cfg *p_TgecDriverParam; +} t_Tgec; + + +t_Error TGEC_MII_WritePhyReg(t_Handle h_Tgec, uint8_t phyAddr, uint8_t reg, uint16_t data); +t_Error TGEC_MII_ReadPhyReg(t_Handle h_Tgec, uint8_t phyAddr, uint8_t reg, uint16_t *p_Data); + + +#endif /* __TGEC_H */ diff --git a/drivers/net/ethernet/freescale/fman/Peripherals/FM/MAC/tgec_mii_acc.c b/drivers/net/ethernet/freescale/fman/Peripherals/FM/MAC/tgec_mii_acc.c new file mode 100644 index 0000000..e0fafd1 --- /dev/null +++ b/drivers/net/ethernet/freescale/fman/Peripherals/FM/MAC/tgec_mii_acc.c @@ -0,0 +1,139 @@ +/* + * Copyright 2008-2012 Freescale Semiconductor Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Freescale Semiconductor nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + + +#include "error_ext.h" +#include "std_ext.h" +#include "fm_mac.h" +#include "tgec.h" +#include "xx_ext.h" + +#include "fm_common.h" + + +/*****************************************************************************/ +t_Error TGEC_MII_WritePhyReg(t_Handle h_Tgec, + uint8_t phyAddr, + uint8_t reg, + uint16_t data) +{ + t_Tgec *p_Tgec = (t_Tgec *)h_Tgec; + t_TgecMiiAccessMemMap *p_MiiAccess; + uint32_t cfgStatusReg; + + SANITY_CHECK_RETURN_ERROR(p_Tgec, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_Tgec->p_MiiMemMap, E_INVALID_HANDLE); + + p_MiiAccess = p_Tgec->p_MiiMemMap; + + /* Configure MII */ + cfgStatusReg = GET_UINT32(p_MiiAccess->mdio_cfg_status); + cfgStatusReg &= ~MIIMCOM_DIV_MASK; + /* (one half of fm clock => 2.5Mhz) */ + cfgStatusReg |=((((p_Tgec->fmMacControllerDriver.clkFreq*10)/2)/25) << MIIMCOM_DIV_SHIFT); + WRITE_UINT32(p_MiiAccess->mdio_cfg_status, cfgStatusReg); + + while ((GET_UINT32(p_MiiAccess->mdio_cfg_status)) & MIIMIND_BUSY) + XX_UDelay (1); + + WRITE_UINT32(p_MiiAccess->mdio_command, phyAddr); + + WRITE_UINT32(p_MiiAccess->mdio_regaddr, reg); + + CORE_MemoryBarrier(); + + while ((GET_UINT32(p_MiiAccess->mdio_cfg_status)) & MIIMIND_BUSY) + XX_UDelay (1); + + WRITE_UINT32(p_MiiAccess->mdio_data, data); + + CORE_MemoryBarrier(); + + while ((GET_UINT32(p_MiiAccess->mdio_data)) & MIIDATA_BUSY) + XX_UDelay (1); + + return E_OK; +} + +/*****************************************************************************/ +t_Error TGEC_MII_ReadPhyReg(t_Handle h_Tgec, + uint8_t phyAddr, + uint8_t reg, + uint16_t *p_Data) +{ + t_Tgec *p_Tgec = (t_Tgec *)h_Tgec; + t_TgecMiiAccessMemMap *p_MiiAccess; + uint32_t cfgStatusReg; + + SANITY_CHECK_RETURN_ERROR(p_Tgec, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_Tgec->p_MiiMemMap, E_INVALID_HANDLE); + + p_MiiAccess = p_Tgec->p_MiiMemMap; + + /* Configure MII */ + cfgStatusReg = GET_UINT32(p_MiiAccess->mdio_cfg_status); + cfgStatusReg &= ~MIIMCOM_DIV_MASK; + /* (one half of fm clock => 2.5Mhz) */ + cfgStatusReg |=((((p_Tgec->fmMacControllerDriver.clkFreq*10)/2)/25) << MIIMCOM_DIV_SHIFT); + WRITE_UINT32(p_MiiAccess->mdio_cfg_status, cfgStatusReg); + + while ((GET_UINT32(p_MiiAccess->mdio_cfg_status)) & MIIMIND_BUSY) + XX_UDelay (1); + + WRITE_UINT32(p_MiiAccess->mdio_command, phyAddr); + + WRITE_UINT32(p_MiiAccess->mdio_regaddr, reg); + + CORE_MemoryBarrier(); + + while ((GET_UINT32(p_MiiAccess->mdio_cfg_status)) & MIIMIND_BUSY) + XX_UDelay (1); + + WRITE_UINT32(p_MiiAccess->mdio_command, (uint32_t)(phyAddr | MIIMCOM_READ_CYCLE)); + + CORE_MemoryBarrier(); + + while ((GET_UINT32(p_MiiAccess->mdio_data)) & MIIDATA_BUSY) + XX_UDelay (1); + + *p_Data = (uint16_t)GET_UINT32(p_MiiAccess->mdio_data); + + cfgStatusReg = GET_UINT32(p_MiiAccess->mdio_cfg_status); + + if (cfgStatusReg & MIIMIND_READ_ERROR) + RETURN_ERROR(MINOR, E_INVALID_VALUE, + ("Read Error: phyAddr 0x%x, dev 0x%x, reg 0x%x, cfgStatusReg 0x%x", + ((phyAddr & 0xe0)>>5), (phyAddr & 0x1f), reg, cfgStatusReg)); + + return E_OK; +} diff --git a/drivers/net/ethernet/freescale/fman/Peripherals/FM/MAC/tgec_mii_acc.h b/drivers/net/ethernet/freescale/fman/Peripherals/FM/MAC/tgec_mii_acc.h new file mode 100644 index 0000000..645cdde --- /dev/null +++ b/drivers/net/ethernet/freescale/fman/Peripherals/FM/MAC/tgec_mii_acc.h @@ -0,0 +1,80 @@ +/* + * Copyright 2008-2012 Freescale Semiconductor Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Freescale Semiconductor nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + +#ifndef __TGEC_MII_ACC_H +#define __TGEC_MII_ACC_H + +#include "std_ext.h" + + +/* MII Management Command Register */ +#define MIIMCOM_READ_POST_INCREMENT 0x00004000 +#define MIIMCOM_READ_CYCLE 0x00008000 +#define MIIMCOM_SCAN_CYCLE 0x00000800 +#define MIIMCOM_PREAMBLE_DISABLE 0x00000400 + +#define MIIMCOM_MDIO_HOLD_1_REG_CLK 0 +#define MIIMCOM_MDIO_HOLD_2_REG_CLK 1 +#define MIIMCOM_MDIO_HOLD_3_REG_CLK 2 +#define MIIMCOM_MDIO_HOLD_4_REG_CLK 3 + +#define MIIMCOM_DIV_MASK 0x0000ff00 +#define MIIMCOM_DIV_SHIFT 8 + +/* MII Management Indicator Register */ +#define MIIMIND_BUSY 0x00000001 +#define MIIMIND_READ_ERROR 0x00000002 + +#define MIIDATA_BUSY 0x80000000 + +#if defined(__MWERKS__) && !defined(__GNUC__) +#pragma pack(push,1) +#endif /* defined(__MWERKS__) && ... */ + +/*----------------------------------------------------*/ +/* MII Configuration Control Memory Map Registers */ +/*----------------------------------------------------*/ +typedef _Packed struct t_TgecMiiAccessMemMap +{ + volatile uint32_t mdio_cfg_status; /* 0x030 */ + volatile uint32_t mdio_command; /* 0x034 */ + volatile uint32_t mdio_data; /* 0x038 */ + volatile uint32_t mdio_regaddr; /* 0x03c */ +} _PackedType t_TgecMiiAccessMemMap ; + +#if defined(__MWERKS__) && !defined(__GNUC__) +#pragma pack(pop) +#endif /* defined(__MWERKS__) && ... */ + + +#endif /* __TGEC_MII_ACC_H */ |