/* * Copyright 2008-2013 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 FMan dTSEC driver *//***************************************************************************/ #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" #include "fsl_fman_dtsec_mii_acc.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; fman_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 fman_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 = fman_dtsec_get_event(p_DtsecMemMap, (uint32_t)(~(DTSEC_IMASK_MMRDEN | DTSEC_IMASK_MMWREN))); event &= fman_dtsec_get_interrupt_mask(p_DtsecMemMap); fman_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 = fman_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) { if (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) { fman_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 */ fman_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) fman_dtsec_start_tx(p_MemMap); if (mode & e_COMM_MODE_RX) fman_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")); if (enable) p_Dtsec->enTsuErrExeption = TRUE; else p_Dtsec->enTsuErrExeption = FALSE; } 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); fman_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); fman_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 (0 < pauseTime && 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 */ fman_dtsec_set_tx_pause_frames(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); fman_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; fman_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; fman_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 = fman_dtsec_get_stat_counter(p_DtsecMemMap, E_DTSEC_STAT_TR64) + p_Dtsec->internalStatistics.tr64; p_Statistics->eStatPkts65to127 = fman_dtsec_get_stat_counter(p_DtsecMemMap, E_DTSEC_STAT_TR127) + p_Dtsec->internalStatistics.tr127; p_Statistics->eStatPkts128to255 = fman_dtsec_get_stat_counter(p_DtsecMemMap, E_DTSEC_STAT_TR255) + p_Dtsec->internalStatistics.tr255; p_Statistics->eStatPkts256to511 = fman_dtsec_get_stat_counter(p_DtsecMemMap, E_DTSEC_STAT_TR511) + p_Dtsec->internalStatistics.tr511; p_Statistics->eStatPkts512to1023 = fman_dtsec_get_stat_counter(p_DtsecMemMap, E_DTSEC_STAT_TR1K) + p_Dtsec->internalStatistics.tr1k; p_Statistics->eStatPkts1024to1518 = fman_dtsec_get_stat_counter(p_DtsecMemMap, E_DTSEC_STAT_TRMAX) + p_Dtsec->internalStatistics.trmax; p_Statistics->eStatPkts1519to1522 = fman_dtsec_get_stat_counter(p_DtsecMemMap, E_DTSEC_STAT_TRMGV) + p_Dtsec->internalStatistics.trmgv; /* MIB II */ p_Statistics->ifInOctets = fman_dtsec_get_stat_counter(p_DtsecMemMap, E_DTSEC_STAT_RBYT) + p_Dtsec->internalStatistics.rbyt; p_Statistics->ifInPkts = fman_dtsec_get_stat_counter(p_DtsecMemMap, E_DTSEC_STAT_RPKT) + p_Dtsec->internalStatistics.rpkt; p_Statistics->ifInUcastPkts = 0; p_Statistics->ifInMcastPkts = fman_dtsec_get_stat_counter(p_DtsecMemMap, E_DTSEC_STAT_RMCA) + p_Dtsec->internalStatistics.rmca; p_Statistics->ifInBcastPkts = fman_dtsec_get_stat_counter(p_DtsecMemMap, E_DTSEC_STAT_RBCA) + p_Dtsec->internalStatistics.rbca; p_Statistics->ifOutOctets = fman_dtsec_get_stat_counter(p_DtsecMemMap, E_DTSEC_STAT_TBYT) + p_Dtsec->internalStatistics.tbyt; p_Statistics->ifOutPkts = fman_dtsec_get_stat_counter(p_DtsecMemMap, E_DTSEC_STAT_TPKT) + p_Dtsec->internalStatistics.tpkt; p_Statistics->ifOutUcastPkts = 0; p_Statistics->ifOutMcastPkts = fman_dtsec_get_stat_counter(p_DtsecMemMap, E_DTSEC_STAT_TMCA) + p_Dtsec->internalStatistics.tmca; p_Statistics->ifOutBcastPkts = fman_dtsec_get_stat_counter(p_DtsecMemMap, E_DTSEC_STAT_TBCA) + p_Dtsec->internalStatistics.tbca; } p_Statistics->eStatFragments = fman_dtsec_get_stat_counter(p_DtsecMemMap, E_DTSEC_STAT_RFRG) + p_Dtsec->internalStatistics.rfrg; p_Statistics->eStatJabbers = fman_dtsec_get_stat_counter(p_DtsecMemMap, E_DTSEC_STAT_RJBR) + p_Dtsec->internalStatistics.rjbr; p_Statistics->eStatsDropEvents = fman_dtsec_get_stat_counter(p_DtsecMemMap, E_DTSEC_STAT_RDRP) + p_Dtsec->internalStatistics.rdrp; p_Statistics->eStatCRCAlignErrors = fman_dtsec_get_stat_counter(p_DtsecMemMap, E_DTSEC_STAT_RALN) + p_Dtsec->internalStatistics.raln; p_Statistics->eStatUndersizePkts = fman_dtsec_get_stat_counter(p_DtsecMemMap, E_DTSEC_STAT_RUND) + p_Dtsec->internalStatistics.rund; p_Statistics->eStatOversizePkts = fman_dtsec_get_stat_counter(p_DtsecMemMap, E_DTSEC_STAT_ROVR) + p_Dtsec->internalStatistics.rovr; p_Statistics->reStatPause = fman_dtsec_get_stat_counter(p_DtsecMemMap, E_DTSEC_STAT_RXPF) + p_Dtsec->internalStatistics.rxpf; p_Statistics->teStatPause = fman_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 + fman_dtsec_get_stat_counter(p_DtsecMemMap,E_DTSEC_STAT_RFLR) + p_Dtsec->internalStatistics.rflr + fman_dtsec_get_stat_counter(p_DtsecMemMap,E_DTSEC_STAT_RCDE) + p_Dtsec->internalStatistics.rcde + fman_dtsec_get_stat_counter(p_DtsecMemMap,E_DTSEC_STAT_RCSE) + p_Dtsec->internalStatistics.rcse; p_Statistics->ifOutDiscards = fman_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: */ + fman_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); fman_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 */ fman_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 */ fman_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 */ fman_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)((fman_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; } fman_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)((fman_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])) fman_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])) fman_dtsec_set_bucket(p_Dtsec->p_MemMap, bucket, FALSE); } /* address does not exist */ ASSERT_COND(p_HashEntry != NULL); return E_OK; } /* .............................................................................. */ 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); fman_dtsec_set_uc_promisc(p_Dtsec->p_MemMap, newVal); fman_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)fman_dtsec_set_stat_level(p_Dtsec->p_MemMap, (enum dtsec_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 DtsecSetWakeOnLan(t_Handle h_Dtsec, bool en) { t_Dtsec *p_Dtsec = (t_Dtsec *)h_Dtsec; SANITY_CHECK_RETURN_ERROR(p_Dtsec, E_INVALID_STATE); SANITY_CHECK_RETURN_ERROR(!p_Dtsec->p_DtsecDriverParam, E_INVALID_STATE); fman_dtsec_set_wol(p_Dtsec->p_MemMap, en); return E_OK; } /* .............................................................................. */ static t_Error DtsecAdjustLink(t_Handle h_Dtsec, e_EnetSpeed speed, bool fullDuplex) { t_Dtsec *p_Dtsec = (t_Dtsec *)h_Dtsec; int 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 = fman_dtsec_adjust_link(p_Dtsec->p_MemMap, enet_interface, enet_speed, fullDuplex); if (err == -EINVAL) RETURN_ERROR(MAJOR, E_CONFLICT, ("Ethernet interface does not support Half Duplex mode")); return (t_Error)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_SPEED0 | PHY_CR_SPEED1 ); tmpReg16 |= (PHY_CR_ANE | PHY_CR_RESET_AN | PHY_CR_FULLDUPLEX | PHY_CR_SPEED1); 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 = fman_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) fman_dtsec_enable_interrupt(p_Dtsec->p_MemMap, bitMask); else fman_dtsec_disable_interrupt(p_Dtsec->p_MemMap, bitMask); } else { if (!p_Dtsec->ptpTsuEnabled) RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("Exception valid for 1588 only")); if (enable) { p_Dtsec->enTsuErrExeption = TRUE; fman_dtsec_enable_tmr_interrupt(p_Dtsec->p_MemMap); } else { p_Dtsec->enTsuErrExeption = FALSE; fman_dtsec_disable_tmr_interrupt(p_Dtsec->p_MemMap); } } return E_OK; } /*****************************************************************************/ /* 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)fman_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")); } 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 = fman_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); if (err) RETURN_ERROR(MINOR,err, NO_MSG); 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); if (p_Dtsec->p_DtsecDriverParam) { /* Called after config */ XX_Free(p_Dtsec->p_DtsecDriverParam); p_Dtsec->p_DtsecDriverParam = NULL; } else /* Called after init */ FreeInitResources(p_Dtsec); XX_Free(p_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_Resume = NULL; 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_SetWakeOnLan = DtsecSetWakeOnLan; 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_GetFrameSizeCounters = NULL; 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; } /*****************************************************************************/ /* 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; fman_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; }