/******************************************************************************* Copyright (C) Marvell International Ltd. and its affiliates This software file (the "File") is owned and distributed by Marvell International Ltd. and/or its affiliates ("Marvell") under the following alternative licensing terms. Once you have made an election to distribute the File under one of the following license alternatives, please (i) delete this introductory statement regarding license alternatives, (ii) delete the two license alternatives that you have not elected to use and (iii) preserve the Marvell copyright notice above. ******************************************************************************** Marvell Commercial License Option If you received this File from Marvell and you have entered into a commercial license agreement (a "Commercial License") with Marvell, the File is licensed to you under the terms of the applicable Commercial License. ******************************************************************************** Marvell GPL License Option If you received this File from Marvell, you may opt to use, redistribute and/or modify this File in accordance with the terms and conditions of the General Public License Version 2, June 1991 (the "GPL License"), a copy of which is available along with the File in the license.txt file or by writing to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 or on the worldwide web at http://www.gnu.org/licenses/gpl.txt. THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE ARE EXPRESSLY DISCLAIMED. The GPL License provides additional details about this warranty disclaimer. ******************************************************************************** Marvell BSD License Option If you received this File from Marvell, you may opt to use, redistribute and/or modify this File under the following licensing terms. 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 Marvell nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 THE COPYRIGHT OWNER OR CONTRIBUTORS 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 "mvTsu.h" #include "ctrlEnv/mvCtrlEnvLib.h" /********************************/ /* Local enums and structures */ /********************************/ #define TSU_MIN_PKT_SIZE 188 #define TSU_MAX_PKT_SIZE 256 #define TSU_NUM_CLOCK_DIVIDERS 6 typedef struct { MV_U32 aggrMode; MV_U16 pktSize; MV_TSU_PORT_DIRECTION portDir; MV_ULONG descPhyAddr; MV_U32 *descVirtAddr; MV_U32 descMemHandle; MV_U32 numTsDesc; MV_U32 numDoneQEntry; MV_U32 aggrNumPckts; MV_U32 *tsDataBuff; MV_U32 *tsDoneBuff; MV_U32 dataBlockSize; MV_U32 dataReadIdx; MV_U32 statReadIdx; MV_U32 cpuRollBit; MV_U32 descSize; MV_U32 queueMask; MV_U32 queueDescSize; MV_BOOL enableTimer; }MV_TSU_PORT_CTRL; typedef struct { MV_U32 numActPorts; MV_TSU_PORTS_MODE mode; MV_TSU_CORE_CLOCK coreClock; void *osHandle; }MV_TSU_CTRL; /********************************/ /* Local Macros */ /********************************/ #define TS_SIGNAL_PARAMS_CONFIG(cfg,usedMask,polMask,reg) \ { \ if(cfg != TSU_SIGNAL_KEEP_DEF) \ { \ reg &= ~(usedMask | polMask); \ if(cfg != TSU_SIGNAL_DIS) \ { \ reg |= usedMask; \ if(cfg == TSU_SIGNAL_EN_ACT_HIGH) \ reg |= polMask; \ } \ } \ } #define TS_SIGNAL_PARAMS_GET(cfg,usedMask,polMask,reg) \ { \ if(reg & usedMask) \ { \ if(reg & polMask) \ cfg = TSU_SIGNAL_EN_ACT_HIGH; \ else \ cfg = TSU_SIGNAL_EN_ACT_LOW; \ } \ else \ { \ cfg = TSU_SIGNAL_DIS; \ } \ } #define TSU_SET_DESC_BUFF_PTR(desc,addr) (*(MV_U32*)desc) = addr #define TSU_SET_OUT_DESC_TMSTMP(desc,tms,err) \ (*((MV_U32*)desc + 1)) = (tms | (err << 28)) #define TSU_BUFF_HNDL(d, s) (MV_U32) ((d & 0xFFFF) | ((s & 0xFFFF) << 16)) #define TSU_BUFF_HNDL_2_DATA_IDX(h) (MV_U32)(h & 0xFFFF) #define TSU_BUFF_HNDL_2_STAT_IDX(h) (MV_U32)((h >> 16) & 0xFFFF) /********************************/ /* Control variables. */ /********************************/ MV_U32 mvTsuCoreClock2Val[] = { 83 * _1M, /* TSU_CORE_CLK_83_MHZ */ 71 * _1M, /* TSU_CORE_CLK_71_MHZ */ 91 * _1M, /* TSU_CORE_CLK_91_MHZ */ 100 * _1M /* TSU_CORE_CLK_100_MHZ */ }; MV_TSU_CTRL mvTsuCtrl; MV_TSU_PORT_CTRL mvTsuPortCtrl[MV_TSU_NUM_PORTS]; /********************************/ /* Forward functions declaration*/ /********************************/ inline static MV_STATUS mvTsuOperationModeSet(MV_U8 port, MV_BOOL enable); static MV_STATUS mvTsuReadyBuffCountGet(MV_U8 port, MV_U32 *numBlocks, MV_U32 *numBuffers); static MV_STATUS mvTsuPortEnable(MV_U8 port,MV_BOOL enable); /********************************/ /* Functions Implementation */ /********************************/ /******************************************************************************* * mvTsuHalInit * * DESCRIPTION: * Initialize the TSU unit, and get unit out of reset. * * INPUT: * coreClock - The core clock at which the TSU should operate. * mode - The mode on configure the unit into (serial/parallel). * osHandle - Memory handle used for memory allocations. * OUTPUT: * None. * RETURN: * MV_OK - on success, * *******************************************************************************/ MV_STATUS mvTsuHalInit(MV_TSU_CORE_CLOCK coreClock, MV_TSU_PORTS_MODE mode, void *osHandle) { MV_U32 reg; MV_U32 port; /* Setup the core clock. */ reg = MV_REG_READ(MV_TSU_MODES_REG); reg &= TSU_MODES_TSCK_MASK; reg |= (coreClock << TSU_MODES_TSCK_OFF); /* Configure the mode */ reg &= ~TSU_MODES_PAR_MODE_MASK; if(mode == TSU_MODE_SERIAL) { reg |= TSU_MODES_PAR_MODE_SER; mvTsuCtrl.numActPorts = 2; } else { reg |= TSU_MODES_PAR_MODE_PAR; mvTsuCtrl.numActPorts = 1; } MV_REG_WRITE(MV_TSU_MODES_REG,reg); /* Get ports out of reset. */ for(port = 0; port < MV_TSU_NUM_PORTS; port++) mvTsuPortReset(port); /* Setup control veraibles. */ mvTsuCtrl.coreClock = coreClock; mvTsuCtrl.osHandle = osHandle; mvTsuCtrl.mode = mode; return MV_OK; } /******************************************************************************* * mvTsuShutdown * * DESCRIPTION: * Shutdown the TS unit, and put into reset state. * * INPUT: * None. * OUTPUT: * None. * RETURN: * MV_OK - on success, * *******************************************************************************/ MV_STATUS mvTsuShutdown(void) { //... // Check if it's possible to put the module back into reset mode. return MV_NOT_IMPLEMENTED; } /******************************************************************************* * mvTsuPortReset * * DESCRIPTION: * Perform a SW reset on a given port. * * INPUT: * port - The port number to reset. * OUTPUT: * None. * RETURN: * MV_OK - On success, * MV_BAD_VALUE - Bad port configuration option. * MV_BAD_SIZE - Illegal number of ports. * *******************************************************************************/ MV_STATUS mvTsuPortReset(MV_U8 port) { MV_U32 reg; /* Check the correctness of parameters. */ if(port >= MV_TSU_NUM_PORTS) return MV_BAD_SIZE; /* First, set in reset mode, then get out of reset. */ reg = MV_REG_READ(MV_TSU_CONFIG_REG(port)); reg &= ~TSU_CFG_RESET_MASK; reg |= TSU_CFG_RESET_SET; MV_REG_WRITE(MV_TSU_CONFIG_REG(port),reg); reg &= ~TSU_CFG_RESET_MASK; reg |= TSU_CFG_RESET_CLEAR; MV_REG_WRITE(MV_TSU_CONFIG_REG(port),reg); return MV_OK; } /******************************************************************************* * mvTsuPortInit * * DESCRIPTION: * Initialize the TSU ports. * * INPUT: * port - The port number to configure. * portCfg - Port configurations parameters. * OUTPUT: * None. * RETURN: * MV_OK - On success, * MV_BAD_VALUE - Bad port configuration option. * MV_BAD_SIZE - Illegal number of ports. * *******************************************************************************/ MV_STATUS mvTsuPortInit(MV_U8 port, MV_TSU_PORT_CONFIG *portCfg) { MV_U32 reg; /* Check the correctness of parameters. */ if(((mvTsuCtrl.mode == TSU_MODE_SERIAL) && (port >= MV_TSU_NUM_PORTS))|| ((mvTsuCtrl.mode == TSU_MODE_PARALLEL) && (port >= 1))) return MV_BAD_SIZE; if((portCfg->pktSize < TSU_MIN_PKT_SIZE) || (portCfg->pktSize > TSU_MAX_PKT_SIZE)) return MV_BAD_VALUE; /* configure the port parameters */ /* Disable operation mode. */ mvTsuOperationModeSet(port,MV_FALSE); reg = MV_REG_READ(MV_TSU_CONFIG_REG(port)); /* Setup packet size. */ reg &= ~TSU_CFG_PKT_SIZE_MASK; reg |= (((portCfg->pktSize - 1) & 0xFF) << TSU_CFG_PKT_SIZE_OFFS); /* Setup data direction. */ reg &= ~TSU_CFG_DATA_DIR_MASK; if(portCfg->portDir == TSU_PORT_INPUT) reg |= TSU_CFG_DATA_DIR_IN; else reg |= TSU_CFG_DATA_DIR_OUT; /* Setup serial / parallel mode. */ reg &= ~TSU_CFG_DATA_MODE_MASK; if(mvTsuCtrl.mode == TSU_MODE_SERIAL) reg |= TSU_CFG_DATA_MODE_SER; else reg |= TSU_CFG_DATA_MODE_PAR; MV_REG_WRITE(MV_TSU_CONFIG_REG(port),reg); /* Setup DMA packet size. */ reg = MV_REG_READ(MV_TSU_DMA_PARAMS_REG(port)); reg &= ~TSU_DMAP_DMA_LEN_MASK; reg |= portCfg->pktSize; MV_REG_WRITE(MV_TSU_DMA_PARAMS_REG(port),reg); /* Setup timestamp auto adjust. */ if(portCfg->portDir == TSU_PORT_OUTPUT) { reg = MV_REG_READ(MV_TSU_TIMESTAMP_CTRL_REG(port)); reg &= ~TSU_TMS_CTRL_AUTO_ADJ_MASK; reg |= TSU_TMS_CTRL_AUTO_ADJ_ON; MV_REG_WRITE(MV_TSU_TIMESTAMP_CTRL_REG(port),reg); } /* Enable operation mode. */ mvTsuOperationModeSet(port,MV_TRUE); /* Update global control vars. */ mvTsuPortCtrl[port].pktSize = portCfg->pktSize; mvTsuPortCtrl[port].portDir = portCfg->portDir; MV_REG_BIT_SET(MV_TSU_CONFIG_REG(port),(1 << 17)); return MV_OK; } /******************************************************************************* * mvTsuPortSignalCfgSet * * DESCRIPTION: * Configure port signals parameters. * * INPUT: * port - The port to configure. * signalCfg - Signal configuration options. * serialflags - Serial signal configuration options (valid only if the * port is working in serial mode). * OUTPUT: * None. * RETURN: * MV_OK - On success, * MV_BAD_VALUE - Bad port configuration option. * MV_BAD_SIZE - Illegal number of ports. * *******************************************************************************/ MV_STATUS mvTsuPortSignalCfgSet(MV_U8 port, MV_TSU_SIGNAL_CONFIG *signalCfg, MV_U32 serialFlags) { MV_U32 reg; if(port >= MV_TSU_NUM_PORTS) return MV_OUT_OF_RANGE; /* Disable operation mode. */ mvTsuOperationModeSet(port,MV_FALSE); reg = MV_REG_READ(MV_TSU_CONFIG_REG(port)); /* Setup signal related options. */ TS_SIGNAL_PARAMS_CONFIG(signalCfg->tsSync, TSU_CFG_SYNC_USED_MASK, TSU_CFG_SYNC_POL_MASK,reg); TS_SIGNAL_PARAMS_CONFIG(signalCfg->tsValid, TSU_CFG_VAL_USED_MASK, TSU_CFG_VAL_POL_MASK,reg); TS_SIGNAL_PARAMS_CONFIG(signalCfg->tsError, TSU_CFG_ERR_USED_MASK, TSU_CFG_ERR_POL_MASK,reg); if(signalCfg->tsDataEdge != TSU_SIGNAL_EDGE_KEEP_DEF) { if(signalCfg->tsDataEdge == TSU_SIGNAL_EDGE_FALL) reg |= TSU_CFG_TX_EDGE_MASK; else reg &= ~TSU_CFG_TX_EDGE_MASK; } /* Setup serial mode related configurations. */ if(mvTsuCtrl.mode == TSU_MODE_SERIAL) { if(serialFlags & MV_TSU_SER_DATA_ORDER_MASK) { reg &= ~TSU_CFG_DATA_ORD_MASK; if(serialFlags & MV_TSU_SER_DATA_ORDER_MSB) reg |= TSU_CFG_DATA_ORD_MSB; else if(serialFlags & MV_TSU_SER_DATA_ORDER_LSB) reg |= TSU_CFG_DATA_ORD_LSB; } if(serialFlags & MV_TSU_SER_SYNC_ACT_LEN_MASK) { reg &= ~TSU_CFG_TS_SYNC_MASK; if(serialFlags & MV_TSU_SER_SYNC_ACT_1_BIT) reg |= TSU_CFG_TS_SYNC_1BIT; else if(serialFlags & MV_TSU_SER_SYNC_ACT_8_BIT) reg |= TSU_CFG_TS_SYNC_8BIT; } if(serialFlags & MV_TSU_SER_TX_CLK_MODE_MASK) { reg &= ~TSU_CFG_CLK_MODE_MASK; if(serialFlags & MV_TSU_SER_TX_CLK_MODE_GAPPED) reg |= TSU_CFG_CLK_MODE_GAPPED; else if(serialFlags & MV_TSU_SER_TX_CLK_MODE_CONT) reg |= TSU_CFG_CLK_MODE_CONT; } } MV_REG_WRITE(MV_TSU_CONFIG_REG(port),reg); /* Enable operation mode. */ mvTsuOperationModeSet(port,MV_TRUE); return MV_OK; } /******************************************************************************* * mvTsuPortSignalCfgGet * * DESCRIPTION: * Get port signals parameters. * * INPUT: * port - The port to configure. * OUTPUT: * signalCfg - Signal configuration options. * serialflags - Serial signal configuration options (valid only if the * port is working in serial mode). * RETURN: * MV_OK - On success, * MV_OUT_OF_RANGE - Illegal port number. * MV_BAD_PARAM - Bad pointers. * *******************************************************************************/ MV_STATUS mvTsuPortSignalCfgGet(MV_U8 port, MV_TSU_SIGNAL_CONFIG *signalCfg, MV_U32* serialFlags) { MV_U32 reg; if(port >= MV_TSU_NUM_PORTS) return MV_OUT_OF_RANGE; if((signalCfg == NULL) || ( (mvTsuCtrl.mode == TSU_MODE_SERIAL) && (serialFlags == NULL))) return MV_BAD_PARAM; reg = MV_REG_READ(MV_TSU_CONFIG_REG(port)); /* Setup signal related options. */ TS_SIGNAL_PARAMS_GET(signalCfg->tsSync,TSU_CFG_SYNC_USED_MASK, TSU_CFG_SYNC_POL_MASK,reg); TS_SIGNAL_PARAMS_GET(signalCfg->tsValid,TSU_CFG_VAL_USED_MASK, TSU_CFG_VAL_POL_MASK,reg); TS_SIGNAL_PARAMS_GET(signalCfg->tsError,TSU_CFG_ERR_USED_MASK, TSU_CFG_ERR_POL_MASK,reg); if(reg & TSU_CFG_TX_EDGE_MASK) signalCfg->tsDataEdge = TSU_SIGNAL_EDGE_FALL; else signalCfg->tsDataEdge = TSU_SIGNAL_EDGE_RISE; /* Setup serial mode related configurations. */ if(mvTsuCtrl.mode == TSU_MODE_SERIAL) { *serialFlags = 0; if((reg & TSU_CFG_DATA_ORD_MASK) == TSU_CFG_DATA_ORD_LSB) *serialFlags |= MV_TSU_SER_DATA_ORDER_LSB; else *serialFlags |= MV_TSU_SER_DATA_ORDER_MSB; if((reg & TSU_CFG_TS_SYNC_MASK) == TSU_CFG_TS_SYNC_1BIT) *serialFlags |= MV_TSU_SER_SYNC_ACT_1_BIT; else *serialFlags |= MV_TSU_SER_SYNC_ACT_8_BIT; if((reg & TSU_CFG_CLK_MODE_MASK) == MV_TSU_SER_TX_CLK_MODE_GAPPED) *serialFlags |= TSU_CFG_CLK_MODE_GAPPED; else *serialFlags |= TSU_CFG_CLK_MODE_CONT; } return MV_OK; } /******************************************************************************* * mvTsuStatusGet * * DESCRIPTION: * Get the TSU port status for a given port. * * INPUT: * port - The port number to configure. * OUTPUT: * status - Bitmask representing the TSU port status (a bitwise or * between the MV_TSU_STATUS_* macros. * RETURN: * MV_OK - On success, * MV_OUT_OF_RANGE - Unsupported port number. * *******************************************************************************/ MV_STATUS mvTsuStatusGet(MV_U8 port, MV_U32 *status) { MV_U32 reg; if(port >= mvTsuCtrl.numActPorts) { return MV_OUT_OF_RANGE; } reg = MV_REG_READ(MV_TSU_STATUS_REG(port)); reg &= TSU_STATUS_MASK; *status = 0; if(reg & TSU_STATUS_IF_ERR) *status |= MV_TSU_STATUS_TSIF_ERROR; if(reg & TSU_STATUS_FIFO_OVFL_ERR) *status |= MV_TSU_STATUS_OVFL_ERROR; if(reg & TSU_STATUS_CONN_ERR) *status |= MV_TSU_STATUS_CONN_ERROR; return MV_OK; } /******************************************************************************* * mvTsuBuffersInit * * DESCRIPTION: * Initialize the TSU unit buffers. * This function is used to initialize both Rx or Tx buffers according to * the port mode configured in mvTsuPortsInit(). * * INPUT: * port - The port number to configure. * buffInfo- TSU buffer information. * OUTPUT: * None. * RETURN: * MV_OK - On success, * MV_OUT_OF_RANGE - Unsupported port number. * MV_BAD_PARAM - Bad buffer configuration options. * MV_NOT_ALIGNED - Bad data buffer alignemed. * *******************************************************************************/ MV_STATUS mvTsuBuffersInit(MV_U8 port, MV_TSU_BUFF_INFO *buffInfo) { MV_U32 reg; MV_U32 descSize; MV_U32 i; MV_U8 *tsDataBuff; MV_U32 *descEntry; MV_U32 phyAddr; if(port >= mvTsuCtrl.numActPorts) return MV_OUT_OF_RANGE; if( ( (buffInfo->aggrMode != MV_TSU_AGGR_MODE_DISABLED) && ( (buffInfo->aggrMode2TmstmpOff > 0xF ) || (buffInfo->aggrMode2TmstmpOff < 4 ) || (buffInfo->aggrNumPackets <= 1) || (buffInfo->numDoneQEntry < buffInfo->aggrNumPackets) ) ) || (!MV_IS_POWER_OF_2(buffInfo->numTsDesc) ) || (!MV_IS_POWER_OF_2(buffInfo->numDoneQEntry) ) || (buffInfo->numTsDesc == 0) || (buffInfo->numDoneQEntry == 0) || (buffInfo->numDoneQEntry > MV_TSU_MAX_DONEQ_LEN) || ( (mvTsuPortCtrl[port].portDir == TSU_PORT_INPUT) && (buffInfo->numTsDesc > MV_TSU_MAX_IN_QUEUE_LEN) ) || ( (mvTsuPortCtrl[port].portDir == TSU_PORT_OUTPUT) && (buffInfo->numTsDesc > MV_TSU_MAX_OUT_QUEUE_LEN) ) ) { return MV_BAD_PARAM; } /* Check buffer alignment. */ if( ( (buffInfo->aggrMode == MV_TSU_AGGR_MODE_2) && (((buffInfo->tsDataBuffPhys + buffInfo->aggrMode2TmstmpOff) & (TSU_DMA_ALIGN - 1)) != 0) ) || ( (buffInfo->aggrMode == MV_TSU_AGGR_MODE_DISABLED) && (buffInfo->tsDataBuffPhys & (TSU_DMA_ALIGN - 1)) != 0 ) ) { return MV_NOT_ALIGNED; } /* Disable operation mode. */ mvTsuOperationModeSet(port,MV_FALSE); /* Setup aggregation mode. */ reg = MV_REG_READ(MV_TSU_AGGREGATION_CTRL_REG(port)); reg &= ~TSU_AGGR_ENABLE_MASK; if(buffInfo->aggrMode == MV_TSU_AGGR_MODE_DISABLED) { reg |= TSU_AGGR_DISABLE; mvTsuPortCtrl[port].aggrNumPckts = 1; } else { reg |= TSU_AGGR_ENABLE; reg &= ~TSU_AGGR_TMSTMP_OFF_MASK; if(buffInfo->aggrMode == MV_TSU_AGGR_MODE_2) { reg |= (buffInfo->aggrMode2TmstmpOff << TSU_AGGR_TMSTMP_OFF_OFFS); reg &= ~TSU_AGGR_TMSTMP_MODE_MASK; reg |= TSU_AGGR_TMSTMP_TO_PCKT; } reg &= ~TSU_AGGR_PCKT_NUM_MASK; reg |= (buffInfo->aggrNumPackets << TSU_AGGR_PCKT_NUM_OFFS); MV_REG_WRITE(MV_TSU_AGGREGATION_CTRL_REG(port),reg); mvTsuPortCtrl[port].aggrNumPckts = buffInfo->aggrNumPackets; } mvTsuPortCtrl[port].aggrMode = buffInfo->aggrMode; if(mvTsuPortCtrl[port].portDir == TSU_PORT_INPUT) { descSize = TSU_INPUT_DESC_ENTRY_SIZE; mvTsuPortCtrl[port].queueDescSize = 4; } else { descSize = TSU_OUTPUT_DESC_ENTRY_SIZE(buffInfo->aggrMode); mvTsuPortCtrl[port].queueDescSize = 8; } /* Initialize descriptor data. */ mvTsuPortCtrl[port].descVirtAddr = mvOsIoUncachedMalloc( mvTsuCtrl.osHandle,descSize * buffInfo->numTsDesc, &(mvTsuPortCtrl[port].descPhyAddr), &(mvTsuPortCtrl[port].descMemHandle)); /* Initialize the descriptors list with buffer pointers. */ descEntry = (MV_U32*)mvTsuPortCtrl[port].descVirtAddr; tsDataBuff = (MV_U8*)buffInfo->tsDataBuff; phyAddr = buffInfo->tsDataBuffPhys; for(i = 0; i < buffInfo->numTsDesc; i++) { TSU_SET_DESC_BUFF_PTR(descEntry,phyAddr); descEntry += (descSize >> 2); tsDataBuff += buffInfo->dataBlockSize; phyAddr += buffInfo->dataBlockSize; } mvTsuPortCtrl[port].queueMask = ~(0xFFFFFFFF << mvLog2(buffInfo->numTsDesc * descSize)); if(mvTsuPortCtrl[port].portDir == TSU_PORT_INPUT) mvTsuPortCtrl[port].cpuRollBit = mvTsuPortCtrl[port].queueMask + 1; else mvTsuPortCtrl[port].cpuRollBit = 0; /* Write the read / write pointers for data & status buffers. */ /* Desc start pointer. */ phyAddr = mvTsuPortCtrl[port].descPhyAddr; MV_REG_WRITE(MV_TSU_DESC_QUEUE_BASE_REG(port),phyAddr); /* Desc read pointer. */ MV_REG_WRITE(MV_TSU_DESC_QUEUE_READ_PTR_REG(port), 0 << TSU_DESC_READ_PTR_OFFS); /* Desc write pointer. */ MV_REG_WRITE(MV_TSU_DESC_QUEUE_WRITE_PTR_REG(port), mvTsuPortCtrl[port].cpuRollBit); /* Done start pointer. */ phyAddr = buffInfo->tsDoneBuffPhys; MV_REG_WRITE(MV_TSU_DONE_QUEUE_BASE_REG(port),phyAddr); /* Done read pointer. */ MV_REG_WRITE(MV_TSU_DONE_QUEUE_READ_PTR_REG(port), 0 << TSU_DONE_READ_PTR_OFFS); /* Done write pointer. */ MV_REG_WRITE(MV_TSU_DONE_QUEUE_WRITE_PTR_REG(port), mvTsuPortCtrl[port].cpuRollBit);//0 << TSU_DONE_WRITE_PTR_OFFS); /* Done & Data queues size. */ reg = MV_REG_READ(MV_TSU_DMA_PARAMS_REG(port)); reg &= ~(TSU_DMAP_DESC_Q_SIZE_MASK | TSU_DMAP_DONE_Q_SIZE_MASK); i = mvLog2((buffInfo->numTsDesc * descSize) >> 2); reg |= (i << TSU_DMAP_DESC_Q_SIZE_OFFS); i = mvLog2((buffInfo->numDoneQEntry * TSU_DONE_STATUS_ENTRY_SIZE) >> 2); reg |= (i << TSU_DMAP_DONE_Q_SIZE_OFFS); MV_REG_WRITE(MV_TSU_DMA_PARAMS_REG(port),reg); mvTsuPortCtrl[port].descSize = descSize; mvTsuPortCtrl[port].numTsDesc = buffInfo->numTsDesc; mvTsuPortCtrl[port].numDoneQEntry = buffInfo->numDoneQEntry; mvTsuPortCtrl[port].tsDataBuff = buffInfo->tsDataBuff; mvTsuPortCtrl[port].tsDoneBuff = buffInfo->tsDoneBuff; mvTsuPortCtrl[port].dataBlockSize = buffInfo->dataBlockSize; mvTsuPortCtrl[port].dataReadIdx = 0; mvTsuPortCtrl[port].statReadIdx = 0; mvTsuPortCtrl[port].enableTimer = MV_FALSE; mvTsuPortEnable(port,MV_TRUE); /* Enable operation mode. */ mvTsuOperationModeSet(port,MV_TRUE); return MV_OK; } /******************************************************************************* * mvTsuPortShutdown * * DESCRIPTION: * Shutdown the port, this will release any previously allocated port * memory, and set the port to disable state. * * INPUT: * port - The port number to shutdown. * OUTPUT: * None. * RETURN: * MV_OK - On success, * MV_OUT_OF_RANGE - Unsupported port number. * MV_BAD_PARAM - Bad buffer configuration options. * *******************************************************************************/ MV_STATUS mvTsuPortShutdown(MV_U8 port) { MV_TSU_PORT_CTRL *portCtrl; if(port >= mvTsuCtrl.numActPorts) return MV_OUT_OF_RANGE; /* Disable operation mode. */ mvTsuOperationModeSet(port,MV_FALSE); /* Disable the port. */ mvTsuPortEnable(port,MV_FALSE); /* Free descriptors buffer. */ portCtrl = &mvTsuPortCtrl[port]; mvOsIoUncachedFree(mvTsuCtrl.osHandle, portCtrl->descSize * portCtrl->numTsDesc, portCtrl->descPhyAddr,portCtrl->descVirtAddr, portCtrl->descMemHandle); return MV_OK; } /******************************************************************************* * mvTsuDmaWatermarkSet * * DESCRIPTION: * Set the watermark for starting a DMA transfer from / to the TSU * internal FIFO to the CPU memory. * * INPUT: * port - The port number to configure. * watermark - The watermark to configure (in DWORD units). * For Rx: Number of data DWORDS in FIFO to start DMA. * For Tx: Number of free DWORDS in FIFO to start DMA. * OUTPUT: * None. * RETURN: * MV_OK - On success, * MV_OUT_OF_RANGE - Unsupported port number. * MV_BAD_PARAM - Bad watermark value.. * *******************************************************************************/ MV_STATUS mvTsuDmaWatermarkSet(MV_U8 port, MV_U32 watermark) { MV_U32 reg; if(port >= mvTsuCtrl.numActPorts) return MV_OUT_OF_RANGE; if(watermark > TSU_DMAP_DATA_WTRMK_MAX) return MV_BAD_PARAM; /* Disable operation mode. */ mvTsuOperationModeSet(port,MV_FALSE); reg = MV_REG_READ(MV_TSU_DMA_PARAMS_REG(port)); reg &= ~TSU_DMAP_DATA_WTRMK_MASK; reg |= (watermark << TSU_DMAP_DATA_WTRMK_OFFS); MV_REG_WRITE(MV_TSU_DMA_PARAMS_REG(port),reg); /* Enable operation mode. */ mvTsuOperationModeSet(port,MV_TRUE); return MV_OK; } /******************************************************************************* * mvTsuAggrMode1TmsOnPcktEn * * DESCRIPTION: * Set the TSU unit to add the timestamp to the packet buffer when working * in aggregation mode-1. * * INPUT: * port - The port number to configure. * enable - When True, enables the placement of timestamp data in the * packet buffer. * When False, the timestamp is placed in the Done-Queue. * OUTPUT: * None. * RETURN: * MV_OK - On success, * MV_OUT_OF_RANGE - Unsupported port number. * *******************************************************************************/ MV_STATUS mvTsuAggrMode1TmsOnPcktEn(MV_U8 port, MV_BOOL enable) { MV_U32 reg; if(port >= mvTsuCtrl.numActPorts) return MV_OUT_OF_RANGE; /* Disable operation mode. */ mvTsuOperationModeSet(port,MV_FALSE); reg = MV_REG_READ(MV_TSU_AGGREGATION_CTRL_REG(port)); reg &= ~TSU_AGGR_TMSTMP_MODE_MASK; if(enable == MV_TRUE) reg |= TSU_AGGR_TMSTMP_TO_PCKT; else reg |= TSU_AGGR_TMSTMP_TO_DONE_Q; MV_REG_WRITE(MV_TSU_AGGREGATION_CTRL_REG(port),reg); /* Enable operation mode. */ mvTsuOperationModeSet(port,MV_TRUE); return MV_OK; } /********************************/ /* Rx related APIs */ /********************************/ /******************************************************************************* * mvTsuRxSyncDetectionSet * * DESCRIPTION: * Set TS synchronization parameters for Rx data. * * INPUT: * port - The port number to configure. * syncDetect - Number of TS sync matches to lock signal. * syncLoss - Number of TS sync losses to unlock signal. * OUTPUT: * None. * RETURN: * MV_OK - On success, * MV_OUT_OF_RANGE - Unsupported port number. * MV_BAD_PARAM - Bad sync values configuration. * *******************************************************************************/ MV_STATUS mvTsuRxSyncDetectionSet(MV_U8 port, MV_U8 syncDetect, MV_U8 syncLoss) { MV_U32 reg; MV_U8 maxVal; if(port >= MV_TSU_NUM_PORTS) return MV_OUT_OF_RANGE; maxVal = TSU_SYNC_LOSS_CNT_MASK >> TSU_SYNC_LOSS_CNT_OFFS; if((syncDetect > maxVal) || (syncLoss > maxVal)) return MV_BAD_PARAM; /* Disable operation mode. */ mvTsuOperationModeSet(port,MV_FALSE); reg = MV_REG_READ(MV_TSU_SYNCBYTE_DETECT_REG(port)); reg &= ~(TSU_SYNC_LOSS_CNT_MASK | TSU_SYNC_DETECT_CNT_MASK); reg |= ((syncDetect << TSU_SYNC_DETECT_CNT_OFFS) | (syncLoss << TSU_SYNC_LOSS_CNT_OFFS)); MV_REG_WRITE(MV_TSU_SYNCBYTE_DETECT_REG(port),reg); /* Enable operation mode. */ mvTsuOperationModeSet(port,MV_TRUE); return MV_OK; } /******************************************************************************* * mvTsuRxSyncDetectionGet * * DESCRIPTION: * Get TS synchronization parameters for Rx data. * * INPUT: * port - The port number. * OUTPUT: * syncDetect - Number of TS sync matches to lock signal. * syncLoss - Number of TS sync losses to unlock signal. * RETURN: * MV_OK - On success, * MV_OUT_OF_RANGE - Unsupported port number. * MV_BAD_PARAM - Bad pointers. * *******************************************************************************/ MV_STATUS mvTsuRxSyncDetectionGet(MV_U8 port, MV_U8 *syncDetect, MV_U8 *syncLoss) { MV_U32 reg; if(port >= MV_TSU_NUM_PORTS) return MV_OUT_OF_RANGE; if((syncDetect == NULL) || (syncLoss == NULL)) return MV_BAD_PARAM; reg = MV_REG_READ(MV_TSU_SYNCBYTE_DETECT_REG(port)); *syncDetect = (reg & TSU_SYNC_DETECT_CNT_MASK) >> TSU_SYNC_DETECT_CNT_OFFS; *syncLoss = (reg & TSU_SYNC_LOSS_CNT_MASK) >> TSU_SYNC_LOSS_CNT_OFFS; return MV_OK; } /******************************************************************************* * mvTsuRxFullBuffCountGet * * DESCRIPTION: * Get number of Rx packets ready for CPU processing. * * INPUT: * port - TSU port number. * OUTPUT: * numBlocks - Number of data blocks ready for CPU processing * (already have data for processing). * numBuffers - Number of buffers ready for CPU processing (already * have data for processing). * In non-aggreagtion mode numBlocks == numBuffers. * RETURN: * MV_OK - On success, * MV_OUT_OF_RANGE - Unsupported port number. * MV_NOT_SUPPORTED- If the port is not configured in input mode. * *******************************************************************************/ MV_STATUS mvTsuRxFullBuffCountGet(MV_U8 port, MV_U32 *numBlocks, MV_U32 *numBuffers) { if(port >= mvTsuCtrl.numActPorts) return MV_OUT_OF_RANGE; if(mvTsuPortCtrl[port].portDir != TSU_PORT_INPUT) return MV_NOT_SUPPORTED; return mvTsuReadyBuffCountGet(port,numBlocks,numBuffers); } /******************************************************************************* * mvTsuRxNextBuffGet * * DESCRIPTION: * Get a pointer to the next available Rx data & status buffers from the Rx * queue. * * INPUT: * port - TSU port number. * dataBuff - Pointer to return the address of the next data buffer. * statBuff - Pointer to return the address of the next status * buffer. * OUTPUT: * buffsHandle - A handle returned to the user to be used when freeing * the buffers in mvTsuRxBuffFree(). * RETURN: * MV_OK - On success, * MV_OUT_OF_RANGE - Unsupported port number. * MV_BAD_PARAM - Bad parameters. * MV_NOT_SUPPORTED- Functionality not supported by the port configuration. * MV_NO_MORE - No Rx data is available for copy. * NOTE: * When working in Aggregation mode, the buffer will point to the * beggining of the aggregation buffer and not to a single packet inside * the buffer. * *******************************************************************************/ MV_STATUS mvTsuRxNextBuffGet(MV_U8 port,MV_U32 **dataBuff, MV_U32 **statBuff, MV_U32 *buffsHandle) { MV_TSU_PORT_CTRL *portCtrl; MV_U32 numBlocks; if(port >= mvTsuCtrl.numActPorts) return MV_OUT_OF_RANGE; if(mvTsuPortCtrl[port].portDir != TSU_PORT_INPUT) return MV_NOT_SUPPORTED; if((dataBuff == NULL) || (statBuff == NULL) || (buffsHandle == NULL)) return MV_BAD_PARAM; mvTsuReadyBuffCountGet(port,&numBlocks,NULL); if(numBlocks <= 2) return MV_NO_MORE; portCtrl = &mvTsuPortCtrl[port]; /* Get read pointer. */ *dataBuff = (MV_U32*)(((MV_U32)portCtrl->tsDataBuff) + (portCtrl->dataBlockSize * portCtrl->dataReadIdx)); *statBuff = (MV_U32*)(((MV_U32)portCtrl->tsDoneBuff) + (TSU_DONE_STATUS_ENTRY_SIZE * portCtrl->statReadIdx)); *buffsHandle = TSU_BUFF_HNDL(portCtrl->dataReadIdx, portCtrl->statReadIdx); return MV_OK; } /******************************************************************************* * mvTsuRxTimestampCntEn * * DESCRIPTION: * Enable / Disable the timestamp counter for Rx direction. * * INPUT: * port - TSU port number. * enable - MV_TRUE to enable the timestamp counter. * OUTPUT: * None. * RETURN: * MV_OK - On success, * MV_OUT_OF_RANGE - Unsupported port number. * MV_BAD_PARAM - Bad parameters. * NOTE: * *******************************************************************************/ MV_STATUS mvTsuRxTimestampCntEn(MV_U8 port,MV_BOOL enable) { MV_U32 reg; if(port >= mvTsuCtrl.numActPorts) return MV_OUT_OF_RANGE; if(mvTsuPortCtrl[port].portDir != TSU_PORT_INPUT) return MV_NOT_SUPPORTED; reg = MV_REG_READ(MV_TSU_TIMESTAMP_CTRL_REG(port)); reg &= ~TSU_TMS_CTRL_TIMER_MASK; if(enable == MV_TRUE) reg |= TSU_TMS_CTRL_TIMER_EN; else reg |= TSU_TMS_CTRL_TIMER_DIS; MV_REG_WRITE(MV_TSU_TIMESTAMP_CTRL_REG(port),reg); return MV_OK; } /******************************************************************************* * mvTsuRxBuffFree * * DESCRIPTION: * Mark a given set of buffers to be free (ready for new data Rx). * * INPUT: * port - TSU port number. * dataBuff - Pointer to the start of data buffer to return. * statBuff - Pointer to the start of status buffer to return. * buffsHandle - The buffers handle as returned by mvTsuRxNextBuffGet() * OUTPUT: * None. * RETURN: * MV_OK - On success, * MV_OUT_OF_RANGE - Unsupported port number. * MV_NO_MORE - No Rx data is available for copy. * MV_BAD_PARAM - Bad parameters. * MV_BAD_STATE - Bad buffer free order, attempting to free a buffer * before all previous buffers where freed. * NOTE: * When working in Aggregation mode, the buffer will point to the * beggining of the aggregation buffer and not to a single packet inside * the buffer. * *******************************************************************************/ MV_STATUS mvTsuRxBuffFree(MV_U8 port,MV_U32 *dataBuff, MV_U32 *statBuff, MV_U32 buffsHandle) { MV_TSU_PORT_CTRL *portCtrl; MV_U32 ptr; if(port >= mvTsuCtrl.numActPorts) return MV_OUT_OF_RANGE; if(mvTsuPortCtrl[port].portDir != TSU_PORT_INPUT) return MV_NOT_SUPPORTED; if((dataBuff == NULL) || (statBuff == NULL)) return MV_BAD_PARAM; portCtrl = &mvTsuPortCtrl[port]; if(buffsHandle != TSU_BUFF_HNDL(portCtrl->dataReadIdx,portCtrl->statReadIdx)){ mvOsPrintf("Bad state..........................\n"); return MV_BAD_STATE; } portCtrl->dataReadIdx = (portCtrl->dataReadIdx + 1) & (portCtrl->numTsDesc - 1); if(portCtrl->dataReadIdx == 0) portCtrl->cpuRollBit ^= (portCtrl->queueMask + 1); portCtrl->statReadIdx = ((portCtrl->statReadIdx + portCtrl->aggrNumPckts) & (portCtrl->numDoneQEntry - 1)); /* Update the desc queue write pointer. */ ptr = (portCtrl->dataReadIdx << 2) | portCtrl->cpuRollBit; MV_REG_WRITE(MV_TSU_DESC_QUEUE_WRITE_PTR_REG(port),ptr); return MV_OK; } /******************************************************************************* * mvTsuRxFlushErrorPackets * * DESCRIPTION: * Enable / Disable flushing of received erroneous packets. * * INPUT: * port - TSU port number. * enableFlush - MV_TRUE to flush recieved erroneous packets. * MV_FALSE to copy erroneous packets to Rx buffers. * OUTPUT: * None. * RETURN: * MV_OK - On success, * MV_OUT_OF_RANGE - Unsupported port number. * *******************************************************************************/ MV_STATUS mvTsuRxFlushErrorPackets(MV_U8 port, MV_BOOL enableFlush) { MV_U32 reg; if(port >= mvTsuCtrl.numActPorts) return MV_OUT_OF_RANGE; /* Disable operation mode. */ mvTsuOperationModeSet(port,MV_FALSE); reg = MV_REG_READ(MV_TSU_AGGREGATION_CTRL_REG(port)); reg &= ~TSU_AGGR_FLUSH_ERR_MASK; if(enableFlush == MV_TRUE) reg |= TSU_AGGR_FLUSH_ERR_ENABLE; else reg |= TSU_AGGR_FLUSH_ERR_DISABLE; MV_REG_WRITE(MV_TSU_AGGREGATION_CTRL_REG(port),reg); /* Enable operation mode. */ mvTsuOperationModeSet(port,MV_TRUE); return MV_OK; } /********************************/ /* Tx related APIs */ /********************************/ /******************************************************************************* * mvTsuTxClockFreqSet * * DESCRIPTION: * Configure the transmit clock frequency and parameters. * * INPUT: * port - TSU port number. * freq - The frequency to configure in Hz. * autoAdjust - Whether to adjust the Tx frequency according to the * next packet timestamp. * OUTPUT: * None. * RETURN: * MV_OK - On success, * MV_OUT_OF_RANGE - Unsupported port number. * MV_BAD_VALUE - Bad Tx frequency value. * *******************************************************************************/ MV_STATUS mvTsuTxClockFreqSet(MV_U8 port, MV_U32 freq, MV_BOOL autoAdjust) { MV_U32 reg; MV_U32 clockVal; MV_U32 divider; if(port >= mvTsuCtrl.numActPorts) return MV_OUT_OF_RANGE; clockVal = mvTsuCoreClock2Val[mvTsuCtrl.coreClock]; if(freq > clockVal) return MV_BAD_VALUE; /* Disable operation mode. */ mvTsuOperationModeSet(port,MV_FALSE); /* Find the correct divider that satisfies: freq <= (core_clock / div)*/ divider = TSU_NUM_CLOCK_DIVIDERS - 1; while(divider != 0) { if(freq <= (clockVal >> divider)) break; divider--; } /* Now, bestDev holds the best divider value. */ reg = MV_REG_READ(MV_TSU_CONFIG_REG(port)); reg &= ~(TSU_CFG_OUT_CLOCK_MASK | TSU_CFG_FREQ_MODE_MASK); switch(divider) { case(0): /* 1 */ reg |= (1 << TSU_CFG_FREQ_MODE_OFFS); /* Fall through */ case(3): /* 8 */ reg |= TSU_CFG_OUT_CLOCK_1_8; break; case(1): /* 2 */ reg |= (1 << TSU_CFG_FREQ_MODE_OFFS); /* Fall through */ case(4): /* 16 */ reg |= TSU_CFG_OUT_CLOCK_2_16; break; case(2): /* 4 */ reg |= (1 << TSU_CFG_FREQ_MODE_OFFS); /* Fall through */ case(5): /* 32 */ reg |= TSU_CFG_OUT_CLOCK_4_32; break; default: break; } MV_REG_WRITE(MV_TSU_CONFIG_REG(port),reg); /* Setup auto adjust. */ reg = MV_REG_READ(MV_TSU_TIMESTAMP_CTRL_REG(port)); reg &= ~TSU_TMS_CTRL_AUTO_ADJ_MASK; if(autoAdjust == MV_TRUE) reg |= TSU_TMS_CTRL_AUTO_ADJ_ON; else reg |= TSU_TMS_CTRL_AUTO_ADJ_OFF; MV_REG_WRITE(MV_TSU_TIMESTAMP_CTRL_REG(port),reg); /* Enable operation mode. */ mvTsuOperationModeSet(port,MV_TRUE); return MV_OK; } /******************************************************************************* * mvTsuTxFreeBuffCountGet * * DESCRIPTION: * Get the number of free packets ready to be transmitted in the TX * descriptor list. * * INPUT: * port - TSU port number. * OUTPUT: * numBlocks - Number of data blocks ready for CPU processing * (does not have data for transmit). * numBuffers - Number of buffers ready for CPU processing (does not * have data for transmit). * In non-aggreagtion mode numBlocks == numBuffers. * RETURN: * MV_OK - On success, * MV_OUT_OF_RANGE - Unsupported port number. * MV_NOT_SUPPORTED- If the port is not configured in output mode. * *******************************************************************************/ MV_STATUS mvTsuTxFreeBuffCountGet(MV_U8 port, MV_U32 *numBlocks, MV_U32 *numBuffers) { if(port >= mvTsuCtrl.numActPorts) return MV_OUT_OF_RANGE; if(mvTsuPortCtrl[port].portDir != TSU_PORT_OUTPUT) return MV_NOT_SUPPORTED; return mvTsuReadyBuffCountGet(port,numBlocks,numBuffers); } /******************************************************************************* * mvTsuRxNextBuffGet * * DESCRIPTION: * Get a pointer to the next available Tx data & status buffers from the Tx * queue. * * INPUT: * port - TSU port number. * dataBuff - Pointer to return the address of the next data buffer. * statBuff - Pointer to return the address of the next status * buffer. * OUTPUT: * buffsHandle - A handle returned to the user to be used when freeing * the buffers in mvTsuTxBuffPut(). * RETURN: * MV_OK - On success, * MV_OUT_OF_RANGE - Unsupported port number. * MV_BAD_PARAM - Bad parameters. * MV_NOT_SUPPORTED- Functionality not supported by the port configuration. * MV_NO_MORE - No free Tx data is available. * NOTE: * When working in Aggregation mode, the buffer will point to the * beggining of the aggregation buffer and not to a single packet inside * the buffer. * *******************************************************************************/ MV_STATUS mvTsuTxNextBuffGet(MV_U8 port,MV_U32 **dataBuff,MV_U32 *buffsHandle) { MV_TSU_PORT_CTRL *portCtrl; MV_U32 numBlocks; if(port >= mvTsuCtrl.numActPorts) return MV_OUT_OF_RANGE; if(mvTsuPortCtrl[port].portDir != TSU_PORT_OUTPUT) return MV_NOT_SUPPORTED; if((dataBuff == NULL) || (buffsHandle == NULL)) return MV_BAD_PARAM; mvTsuTxFreeBuffCountGet(port,&numBlocks,NULL); if(numBlocks <= 2) return MV_NO_MORE; // if(numBlocks == 0) // return MV_NO_MORE; portCtrl = &mvTsuPortCtrl[port]; if(dataBuff != NULL) { *dataBuff = (MV_U32*)(((MV_U32)portCtrl->tsDataBuff) + (portCtrl->dataBlockSize * portCtrl->dataReadIdx)); *buffsHandle = TSU_BUFF_HNDL(portCtrl->dataReadIdx,portCtrl->statReadIdx); } return MV_OK; } /******************************************************************************* * mvTsuTxBuffPut * * DESCRIPTION: * Mark a given set of buffers to be ready for transmission. * * INPUT: * port - TSU port number. * dataBuff - Pointer to the start of data buffer to put. * tmsValue - The timestamp to associate with the buffer. * This parameter is applicable only when working in * non-aggregation mode. * tsErr - Indicates if the TS packet should be sent as an * erroneous packet. * This parameter is applicable only when working in * non-aggregation mode. * buffsHandle - The buffer handle as returned by mvTsuTxNextBuffGet() * OUTPUT: * None. * RETURN: * MV_OK - On success, * MV_OUT_OF_RANGE - Unsupported port number. * MV_BAD_PARAM - Bad function parameters. * NOTE: * When working in Aggregation mode, the buffer will point to the * beggining of the aggregation buffer and not to a single packet inside * the buffer. * *******************************************************************************/ MV_STATUS mvTsuTxBuffPut(MV_U8 port, MV_U32 *dataBuff, MV_U32 tmsValue, MV_BOOL tsErr, MV_U32 buffsHandle) { MV_TSU_PORT_CTRL *portCtrl; MV_U32 *descEntry; MV_U32 ptr; MV_U32 reg; if(port >= mvTsuCtrl.numActPorts) return MV_OUT_OF_RANGE; if(mvTsuPortCtrl[port].portDir != TSU_PORT_OUTPUT) return MV_NOT_SUPPORTED; if(dataBuff == NULL) return MV_BAD_PARAM; portCtrl = &mvTsuPortCtrl[port]; if(TSU_BUFF_HNDL_2_DATA_IDX(buffsHandle) != portCtrl->dataReadIdx) return MV_BAD_STATE; if(portCtrl->aggrMode == MV_TSU_AGGR_MODE_DISABLED) { /* Write the timestamp value. */ descEntry = (MV_U32*)(((MV_U32)portCtrl->descVirtAddr) + (portCtrl->dataReadIdx << 3)); TSU_SET_OUT_DESC_TMSTMP(descEntry,tmsValue,tsErr); } portCtrl->dataReadIdx = (portCtrl->dataReadIdx + 1) & (portCtrl->numTsDesc - 1); if(portCtrl->dataReadIdx == 0) portCtrl->cpuRollBit ^= (portCtrl->queueMask + 1); /* Update the desc queue write pointer. */ ptr = (portCtrl->dataReadIdx << 3) | portCtrl->cpuRollBit; MV_REG_WRITE(MV_TSU_DESC_QUEUE_WRITE_PTR_REG(port),ptr); if(portCtrl->enableTimer) { /* Enable the timestamp counter. */ reg = MV_REG_READ(MV_TSU_TIMESTAMP_CTRL_REG(port)); reg &= ~TSU_TMS_CTRL_TIMER_MASK; reg |= TSU_TMS_CTRL_TIMER_EN; MV_REG_WRITE(MV_TSU_TIMESTAMP_CTRL_REG(port),reg); portCtrl->enableTimer = MV_FALSE; } return MV_OK; } /******************************************************************************* * mvTsuTxStatusGet * * DESCRIPTION: * Get the next TX done buffer from the TX done queue. * * INPUT: * port - TSU port number. * doneBuff - Pointer to return the address of the next done buffer. * buffsHandle - The buffer handle as returned by mvTsuTxNextBuffGet() * OUTPUT: * numBuffs - Number of returned buffers. * RETURN: * MV_OK - On success, * MV_OUT_OF_RANGE - Unsupported port number. * MV_NO_MORE - No free Tx buffers are avilable. * NOTE: * *******************************************************************************/ MV_STATUS mvTsuTxStatusGet(MV_U8 port, MV_U32 **doneBuff, MV_U32 buffsHandle) { MV_TSU_PORT_CTRL *portCtrl; if(port >= mvTsuCtrl.numActPorts) return MV_OUT_OF_RANGE; if(mvTsuPortCtrl[port].portDir != TSU_PORT_OUTPUT) return MV_NOT_SUPPORTED; if(doneBuff == NULL) return MV_BAD_PARAM; portCtrl = &mvTsuPortCtrl[port]; if(TSU_BUFF_HNDL_2_STAT_IDX(buffsHandle) != portCtrl->statReadIdx) return MV_BAD_STATE; *doneBuff = (MV_U32*)(portCtrl->tsDoneBuff + portCtrl->statReadIdx); portCtrl->statReadIdx = ((portCtrl->statReadIdx + portCtrl->aggrNumPckts)& (portCtrl->numDoneQEntry - 1)); return MV_OK; } /******************************************************************************* * mvTsuTxInitTimeStampSet * * DESCRIPTION: * Set the initial timestamp value for TX operations. * This function must be called before each transmit session. * * INPUT: * port - TSU port number. * enableTmstmp - Enable the timestamp mechanism for packet transmit. * When false, the TSU will transmit packets back-to-back * initTimestamp - (Valid only if enableTs == MV_TRUE) * The initial timestamp to set. * OUTPUT: * None. * RETURN: * MV_OK - On success, * MV_OUT_OF_RANGE - Unsupported port number. * MV_BAD_PARAM - Bad timestamp value. * *******************************************************************************/ MV_STATUS mvTsuTxInitTimeStampSet(MV_U8 port, MV_BOOL enableTmstmp, MV_U32 initTimestamp) { MV_U32 reg; MV_U32 tsReg; if(port >= mvTsuCtrl.numActPorts) return MV_OUT_OF_RANGE; if(mvTsuPortCtrl[port].portDir != TSU_PORT_OUTPUT) return MV_NOT_SUPPORTED; /* Disable operation mode. */ mvTsuOperationModeSet(port,MV_FALSE); reg = MV_REG_READ(MV_TSU_TIMESTAMP_CTRL_REG(port)); if(enableTmstmp == MV_TRUE) { /* Setup timestamp initial value. */ tsReg = MV_REG_READ(MV_TSU_TIMESTAMP_REG(port)); tsReg &= ~TSU_TMSTMP_TIMESTAMP_MASK; tsReg |= (initTimestamp & (TSU_TMSTMP_TIMESTAMP_MASK >> TSU_TMSTMP_TIMESTAMP_OFFS)); MV_REG_WRITE(MV_TSU_TIMESTAMP_REG(port),tsReg); /* Trigger the TSU to read the timestamp. */ reg |= (1 << TSU_TMS_CTRL_READ_TIMER_OFFS); } /* Disable the timestamp counter (Will be enabled on */ /* the first packet Tx */ reg &= ~TSU_TMS_CTRL_TIMER_MASK; reg |= TSU_TMS_CTRL_TIMER_DIS; MV_REG_WRITE(MV_TSU_TIMESTAMP_CTRL_REG(port),reg); mvTsuPortCtrl[port].enableTimer = enableTmstmp; /* Enable operation mode. */ mvTsuOperationModeSet(port,MV_TRUE); return MV_OK; } /******************************************************************************* * mvTsuTxDone * * DESCRIPTION: * Inform the TS unit that the current transmission session is over. * This will stop the internal timestamp counters held by the unit. * * INPUT: * port - TSU port number. * OUTPUT: * None. * RETURN: * MV_OK - On success, * MV_OUT_OF_RANGE - Unsupported port number. * *******************************************************************************/ MV_STATUS mvTsuTxDone(MV_U8 port) { MV_U32 reg; if(port >= mvTsuCtrl.numActPorts) return MV_OUT_OF_RANGE; if(mvTsuPortCtrl[port].portDir != TSU_PORT_OUTPUT) return MV_NOT_SUPPORTED; /* Disable operation mode. */ mvTsuOperationModeSet(port,MV_FALSE); reg = MV_REG_READ(MV_TSU_TIMESTAMP_CTRL_REG(port)); /* Disable the timestamp counter. */ reg &= ~TSU_TMS_CTRL_TIMER_MASK; reg |= TSU_TMS_CTRL_TIMER_DIS; MV_REG_WRITE(MV_TSU_TIMESTAMP_CTRL_REG(port),reg); /* Enable operation mode. */ mvTsuOperationModeSet(port,MV_TRUE); return MV_OK; } /******************************************************************************* * mvTsuOperationModeSet * * DESCRIPTION: * Set the given TS port into operaion mode. * * INPUT: * port - TSU port number. * enable - MV_TRUE: enable operation mode. * MV_FALSE: disable operation mode. * OUTPUT: * None. * RETURN: * MV_OK - On success, * MV_OUT_OF_RANGE - Unsupported port number. * *******************************************************************************/ inline static MV_STATUS mvTsuOperationModeSet(MV_U8 port, MV_BOOL enable) { MV_U32 reg; reg = MV_REG_READ(MV_TSU_CONFIG_REG(port)); reg &= ~TSU_CFG_OPER_MASK; if(enable) reg |= TSU_CFG_OPER_ENABLE; else reg |= TSU_CFG_OPER_DISABLE; MV_REG_WRITE(MV_TSU_CONFIG_REG(port),reg); return MV_OK; } /******************************************************************************* * mvTsuReadyBuffCountGet * * DESCRIPTION: * Get number of packets ready for CPU processing. * In Rx direction, this is the number of packets ready to be rpocessed by * CPU. For Tx direction, this is the number of free buffers ready for data * transmission. * * INPUT: * port - TSU port number. * OUTPUT: * numBlocks - Number of data blocks ready for CPU processing * (already have data for processing). * numBuffers - Number of buffers ready for CPU processing (already * have data for processing). * In non-aggreagtion mode numBlocks == numBuffers. * RETURN: * MV_OK - On success, * MV_OUT_OF_RANGE - Unsupported port number. * *******************************************************************************/ static MV_STATUS mvTsuReadyBuffCountGet(MV_U8 port, MV_U32 *numBlocks, MV_U32 *numBuffers) { MV_U32 cpuPtr; MV_U32 tsuPtr; MV_U32 result = 0; MV_U32 tsuRollBit; MV_TSU_PORT_CTRL *portCtrl = &mvTsuPortCtrl[port]; /* Get CPU pointer. */ cpuPtr = portCtrl->dataReadIdx; /* Get TSU pointer. */ tsuPtr = MV_REG_READ(MV_TSU_DESC_QUEUE_READ_PTR_REG(port)); tsuRollBit = tsuPtr & (portCtrl->queueMask + 1); tsuPtr &= portCtrl->queueMask; tsuPtr /= portCtrl->queueDescSize; if(tsuPtr > cpuPtr) { result = tsuPtr - cpuPtr; } else if(tsuPtr < cpuPtr) { result = tsuPtr + portCtrl->numTsDesc - cpuPtr; } else if( (tsuPtr == cpuPtr) && (portCtrl->cpuRollBit == tsuRollBit) ) { result = portCtrl->numTsDesc; } if(numBuffers) *numBuffers = result * portCtrl->aggrNumPckts; if(numBlocks) *numBlocks = result; return MV_OK; } /******************************************************************************* * mvTsuPortEnable * * DESCRIPTION: * Enable port for receiving & transmitting data after it has been * configured. * * INPUT: * port - The port number to configure. * enable - MV_TRUE to enable port. * MV_FALSE to disable it. * OUTPUT: * None. * RETURN: * MV_OK - On success, * MV_OUT_OF_RANGE - Unsupported port number. * *******************************************************************************/ static MV_STATUS mvTsuPortEnable(MV_U8 port,MV_BOOL enable) { MV_U32 reg; if(port >= mvTsuCtrl.numActPorts) return MV_OUT_OF_RANGE; if(enable == MV_TRUE) reg = 0xFFFFFFFF; else reg = 0x04040404; reg = MV_REG_WRITE(MV_TSU_ENABLE_ACCESS_REG(port),reg); return MV_OK; }