diff options
Diffstat (limited to 'drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Port')
6 files changed, 10265 insertions, 0 deletions
diff --git a/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Port/Makefile b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Port/Makefile new file mode 100644 index 0000000..7d928e0 --- /dev/null +++ b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Port/Makefile @@ -0,0 +1,15 @@ +# +# Makefile for the Freescale Ethernet controllers +# +ccflags-y += -DVERSION=\"\" +# +#Include netcomm SW specific definitions +include $(srctree)/drivers/net/ethernet/freescale/sdk_fman/ncsw_config.mk + +NCSW_FM_INC = $(srctree)/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/inc + +ccflags-y += -I$(NCSW_FM_INC) + +obj-y += fsl-ncsw-Pcd.o + +fsl-ncsw-Pcd-objs := fm_port.o fm_port_im.o fman_port.o diff --git a/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Port/fm_port.c b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Port/fm_port.c new file mode 100644 index 0000000..ec6e0ed --- /dev/null +++ b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Port/fm_port.c @@ -0,0 +1,6436 @@ +/* + * Copyright 2008-2012 Freescale Semiconductor Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Freescale Semiconductor nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + +/****************************************************************************** + @File fm_port.c + + @Description FM driver routines implementation. + *//***************************************************************************/ +#include "error_ext.h" +#include "std_ext.h" +#include "string_ext.h" +#include "sprint_ext.h" +#include "debug_ext.h" +#include "fm_muram_ext.h" + +#include "fman_common.h" +#include "fm_port.h" +#include "fm_port_dsar.h" +#include "common/general.h" + +/****************************************/ +/* static functions */ +/****************************************/ +static t_Error FmPortConfigAutoResForDeepSleepSupport1(t_FmPort *p_FmPort); + +static t_Error CheckInitParameters(t_FmPort *p_FmPort) +{ + t_FmPortDriverParam *p_Params = p_FmPort->p_FmPortDriverParam; + struct fman_port_cfg *p_DfltConfig = &p_Params->dfltCfg; + t_Error ans = E_OK; + uint32_t unusedMask; + + if (p_FmPort->imEn) + { + if (p_FmPort->portType == e_FM_PORT_TYPE_RX_10G) + if (p_FmPort->p_FmPortDriverParam->dfltCfg.tx_fifo_deq_pipeline_depth + > 2) + RETURN_ERROR( + MAJOR, + E_INVALID_VALUE, + ("fifoDeqPipelineDepth for IM 10G can't be larger than 2")); + + if ((ans = FmPortImCheckInitParameters(p_FmPort)) != E_OK) + return ERROR_CODE(ans); + } + else + { + /****************************************/ + /* Rx only */ + /****************************************/ + if ((p_FmPort->portType == e_FM_PORT_TYPE_RX) + || (p_FmPort->portType == e_FM_PORT_TYPE_RX_10G)) + { + /* external buffer pools */ + if (!p_Params->extBufPools.numOfPoolsUsed) + RETURN_ERROR( + MAJOR, + E_INVALID_VALUE, + ("extBufPools.numOfPoolsUsed=0. At least one buffer pool must be defined")); + + if (FmSpCheckBufPoolsParams(&p_Params->extBufPools, + p_Params->p_BackupBmPools, + &p_Params->bufPoolDepletion) != E_OK) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, NO_MSG); + + /* Check that part of IC that needs copying is small enough to enter start margin */ + if (p_Params->intContext.size + && (p_Params->intContext.size + + p_Params->intContext.extBufOffset + > p_Params->bufMargins.startMargins)) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, + ("intContext.size is larger than start margins")); + + if ((p_Params->liodnOffset != (uint16_t)DPAA_LIODN_DONT_OVERRIDE) + && (p_Params->liodnOffset & ~FM_LIODN_OFFSET_MASK)) + RETURN_ERROR( + MAJOR, + E_INVALID_VALUE, + ("liodnOffset is larger than %d", FM_LIODN_OFFSET_MASK+1)); + +#ifdef FM_NO_BACKUP_POOLS + if ((p_FmPort->fmRevInfo.majorRev != 4) && (p_FmPort->fmRevInfo.majorRev < 6)) + if (p_FmPort->p_FmPortDriverParam->p_BackupBmPools) + RETURN_ERROR(MAJOR, E_NOT_SUPPORTED, ("BackupBmPools")); +#endif /* FM_NO_BACKUP_POOLS */ + } + + /****************************************/ + /* Non Rx ports */ + /****************************************/ + else + { + if (p_Params->deqSubPortal >= FM_MAX_NUM_OF_SUB_PORTALS) + RETURN_ERROR( + MAJOR, + E_INVALID_VALUE, + (" deqSubPortal has to be in the range of 0 - %d", FM_MAX_NUM_OF_SUB_PORTALS)); + + /* to protect HW internal-context from overwrite */ + if ((p_Params->intContext.size) + && (p_Params->intContext.intContextOffset + < MIN_TX_INT_OFFSET)) + RETURN_ERROR( + MAJOR, + E_INVALID_VALUE, + ("non-Rx intContext.intContextOffset can't be smaller than %d", MIN_TX_INT_OFFSET)); + + if ((p_FmPort->portType == e_FM_PORT_TYPE_TX) + || (p_FmPort->portType == e_FM_PORT_TYPE_TX_10G) + /* in O/H DEFAULT_notSupported indicates that it is not supported and should not be checked */ + || (p_FmPort->p_FmPortDriverParam->dfltCfg.tx_fifo_deq_pipeline_depth + != DEFAULT_notSupported)) + { + /* Check that not larger than 8 */ + if ((!p_FmPort->p_FmPortDriverParam->dfltCfg.tx_fifo_deq_pipeline_depth) + || (p_FmPort->p_FmPortDriverParam->dfltCfg.tx_fifo_deq_pipeline_depth + > MAX_FIFO_PIPELINE_DEPTH)) + RETURN_ERROR( + MAJOR, + E_INVALID_VALUE, + ("fifoDeqPipelineDepth can't be larger than %d", MAX_FIFO_PIPELINE_DEPTH)); + } + } + + /****************************************/ + /* Rx Or Offline Parsing */ + /****************************************/ + if ((p_FmPort->portType == e_FM_PORT_TYPE_RX) + || (p_FmPort->portType == e_FM_PORT_TYPE_RX_10G) + || (p_FmPort->portType == e_FM_PORT_TYPE_OH_OFFLINE_PARSING)) + { + if (!p_Params->dfltFqid) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, + ("dfltFqid must be between 1 and 2^24-1")); +#if defined(FM_CAPWAP_SUPPORT) && defined(FM_LOCKUP_ALIGNMENT_ERRATA_FMAN_SW004) + if (p_FmPort->p_FmPortDriverParam->bufferPrefixContent.manipExtraSpace % 16) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("bufferPrefixContent.manipExtraSpace has to be devidable by 16")); +#endif /* defined(FM_CAPWAP_SUPPORT) && ... */ + } + + /****************************************/ + /* All ports */ + /****************************************/ + /* common BMI registers values */ + /* Check that Queue Id is not larger than 2^24, and is not 0 */ + if ((p_Params->errFqid & ~0x00FFFFFF) || !p_Params->errFqid) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, + ("errFqid must be between 1 and 2^24-1")); + if (p_Params->dfltFqid & ~0x00FFFFFF) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, + ("dfltFqid must be between 1 and 2^24-1")); + } + + /****************************************/ + /* Rx only */ + /****************************************/ + if ((p_FmPort->portType == e_FM_PORT_TYPE_RX) + || (p_FmPort->portType == e_FM_PORT_TYPE_RX_10G)) + { + if (p_DfltConfig->rx_pri_elevation % BMI_FIFO_UNITS) + RETURN_ERROR( + MAJOR, + E_INVALID_VALUE, + ("rxFifoPriElevationLevel has to be divisible by %d", BMI_FIFO_UNITS)); + if ((p_DfltConfig->rx_pri_elevation < BMI_FIFO_UNITS) + || (p_DfltConfig->rx_pri_elevation > MAX_PORT_FIFO_SIZE)) + RETURN_ERROR( + MAJOR, + E_INVALID_VALUE, + ("rxFifoPriElevationLevel has to be in the range of 256 - %d", MAX_PORT_FIFO_SIZE)); + if (p_DfltConfig->rx_fifo_thr % BMI_FIFO_UNITS) + RETURN_ERROR( + MAJOR, + E_INVALID_VALUE, + ("rxFifoThreshold has to be divisible by %d", BMI_FIFO_UNITS)); + if ((p_DfltConfig->rx_fifo_thr < BMI_FIFO_UNITS) + || (p_DfltConfig->rx_fifo_thr > MAX_PORT_FIFO_SIZE)) + RETURN_ERROR( + MAJOR, + E_INVALID_VALUE, + ("rxFifoThreshold has to be in the range of 256 - %d", MAX_PORT_FIFO_SIZE)); + + /* Check that not larger than 16 */ + if (p_DfltConfig->rx_cut_end_bytes > FRAME_END_DATA_SIZE) + RETURN_ERROR( + MAJOR, + E_INVALID_VALUE, + ("cutBytesFromEnd can't be larger than %d", FRAME_END_DATA_SIZE)); + + if (FmSpCheckBufMargins(&p_Params->bufMargins) != E_OK) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, NO_MSG); + + /* extra FIFO size (allowed only to Rx ports) */ + if (p_Params->setSizeOfFifo + && (p_FmPort->fifoBufs.extra % BMI_FIFO_UNITS)) + RETURN_ERROR( + MAJOR, + E_INVALID_VALUE, + ("fifoBufs.extra has to be divisible by %d", BMI_FIFO_UNITS)); + + if (p_Params->bufPoolDepletion.poolsGrpModeEnable + && !p_Params->bufPoolDepletion.numOfPools) + RETURN_ERROR( + MAJOR, + E_INVALID_VALUE, + ("bufPoolDepletion.numOfPools can not be 0 when poolsGrpModeEnable=TRUE")); +#ifdef FM_CSI_CFED_LIMIT + if (p_FmPort->fmRevInfo.majorRev == 4) + { + /* Check that not larger than 16 */ + if (p_DfltConfig->rx_cut_end_bytes + p_DfltConfig->checksum_bytes_ignore > FRAME_END_DATA_SIZE) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("cheksumLastBytesIgnore + cutBytesFromEnd can't be larger than %d", FRAME_END_DATA_SIZE)); + } +#endif /* FM_CSI_CFED_LIMIT */ + } + + /****************************************/ + /* Non Rx ports */ + /****************************************/ + /* extra FIFO size (allowed only to Rx ports) */ + else + if (p_FmPort->fifoBufs.extra) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, + (" No fifoBufs.extra for non Rx ports")); + + /****************************************/ + /* Tx only */ + /****************************************/ + if ((p_FmPort->portType == e_FM_PORT_TYPE_TX) + || (p_FmPort->portType == e_FM_PORT_TYPE_TX_10G)) + { + if (p_DfltConfig->tx_fifo_min_level % BMI_FIFO_UNITS) + RETURN_ERROR( + MAJOR, + E_INVALID_VALUE, + ("txFifoMinFillLevel has to be divisible by %d", BMI_FIFO_UNITS)); + if (p_DfltConfig->tx_fifo_min_level > (MAX_PORT_FIFO_SIZE - 256)) + RETURN_ERROR( + MAJOR, + E_INVALID_VALUE, + ("txFifoMinFillLevel has to be in the range of 0 - %d", (MAX_PORT_FIFO_SIZE - 256))); + if (p_DfltConfig->tx_fifo_low_comf_level % BMI_FIFO_UNITS) + RETURN_ERROR( + MAJOR, + E_INVALID_VALUE, + ("txFifoLowComfLevel has to be divisible by %d", BMI_FIFO_UNITS)); + if ((p_DfltConfig->tx_fifo_low_comf_level < BMI_FIFO_UNITS) + || (p_DfltConfig->tx_fifo_low_comf_level > MAX_PORT_FIFO_SIZE)) + RETURN_ERROR( + MAJOR, + E_INVALID_VALUE, + ("txFifoLowComfLevel has to be in the range of 256 - %d", MAX_PORT_FIFO_SIZE)); + + if (p_FmPort->portType == e_FM_PORT_TYPE_TX) + if (p_FmPort->p_FmPortDriverParam->dfltCfg.tx_fifo_deq_pipeline_depth + > 2) + RETURN_ERROR( + MAJOR, E_INVALID_VALUE, + ("fifoDeqPipelineDepth for 1G can't be larger than 2")); + } + + /****************************************/ + /* Non Tx Ports */ + /****************************************/ + /* If discard override was selected , no frames may be discarded. */ + else + if (p_DfltConfig->discard_override && p_Params->errorsToDiscard) + RETURN_ERROR( + MAJOR, + E_CONFLICT, + ("errorsToDiscard is not empty, but frmDiscardOverride selected (all discarded frames to be enqueued to error queue).")); + + /****************************************/ + /* Rx and Offline parsing */ + /****************************************/ + if ((p_FmPort->portType == e_FM_PORT_TYPE_RX) + || (p_FmPort->portType == e_FM_PORT_TYPE_RX_10G) + || (p_FmPort->portType == e_FM_PORT_TYPE_OH_OFFLINE_PARSING)) + { + if (p_FmPort->portType == e_FM_PORT_TYPE_OH_OFFLINE_PARSING) + unusedMask = BMI_STATUS_OP_MASK_UNUSED; + else + unusedMask = BMI_STATUS_RX_MASK_UNUSED; + + /* Check that no common bits with BMI_STATUS_MASK_UNUSED */ + if (p_Params->errorsToDiscard & unusedMask) + RETURN_ERROR(MAJOR, E_INVALID_SELECTION, + ("errorsToDiscard contains undefined bits")); + } + + /****************************************/ + /* Offline Ports */ + /****************************************/ +#ifdef FM_OP_OPEN_DMA_MIN_LIMIT + if ((p_FmPort->fmRevInfo.majorRev >= 6) + && (p_FmPort->portType == e_FM_PORT_TYPE_OH_OFFLINE_PARSING) + && p_Params->setNumOfOpenDmas + && (p_FmPort->openDmas.num < MIN_NUM_OF_OP_DMAS)) + RETURN_ERROR( + MAJOR, + E_INVALID_VALUE, + ("For Offline port, openDmas.num can't be smaller than %d", MIN_NUM_OF_OP_DMAS)); +#endif /* FM_OP_OPEN_DMA_MIN_LIMIT */ + + /****************************************/ + /* Offline & HC Ports */ + /****************************************/ + if ((p_FmPort->portType == e_FM_PORT_TYPE_OH_OFFLINE_PARSING) + || (p_FmPort->portType == e_FM_PORT_TYPE_OH_HOST_COMMAND)) + { +#ifndef FM_FRAME_END_PARAMS_FOR_OP + if ((p_FmPort->fmRevInfo.majorRev < 6) && + (p_FmPort->p_FmPortDriverParam->cheksumLastBytesIgnore != DEFAULT_notSupported)) + /* this is an indication that user called config for this mode which is not supported in this integration */ + RETURN_ERROR(MAJOR, E_NOT_SUPPORTED, ("cheksumLastBytesIgnore is available for Rx & Tx ports only")); +#endif /* !FM_FRAME_END_PARAMS_FOR_OP */ + +#ifndef FM_DEQ_PIPELINE_PARAMS_FOR_OP + if ((!((p_FmPort->fmRevInfo.majorRev == 4) || + (p_FmPort->fmRevInfo.majorRev >= 6))) && + (p_FmPort->p_FmPortDriverParam->dfltCfg.tx_fifo_deq_pipeline_depth != DEFAULT_notSupported)) + /* this is an indication that user called config for this mode which is not supported in this integration */ + RETURN_ERROR(MAJOR, E_INVALID_OPERATION, ("fifoDeqPipelineDepth is available for Tx ports only")); +#endif /* !FM_DEQ_PIPELINE_PARAMS_FOR_OP */ + } + + /****************************************/ + /* All ports */ + /****************************************/ + /* Check that not larger than 16 */ + if ((p_Params->cheksumLastBytesIgnore > FRAME_END_DATA_SIZE) + && ((p_Params->cheksumLastBytesIgnore != DEFAULT_notSupported))) + RETURN_ERROR( + MAJOR, + E_INVALID_VALUE, + ("cheksumLastBytesIgnore can't be larger than %d", FRAME_END_DATA_SIZE)); + + if (FmSpCheckIntContextParams(&p_Params->intContext) != E_OK) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, NO_MSG); + + /* common BMI registers values */ + if (p_Params->setNumOfTasks + && ((!p_FmPort->tasks.num) + || (p_FmPort->tasks.num > MAX_NUM_OF_TASKS))) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, + ("tasks.num can't be larger than %d", MAX_NUM_OF_TASKS)); + if (p_Params->setNumOfTasks + && (p_FmPort->tasks.extra > MAX_NUM_OF_EXTRA_TASKS)) + RETURN_ERROR( + MAJOR, + E_INVALID_VALUE, + ("tasks.extra can't be larger than %d", MAX_NUM_OF_EXTRA_TASKS)); + if (p_Params->setNumOfOpenDmas + && ((!p_FmPort->openDmas.num) + || (p_FmPort->openDmas.num > MAX_NUM_OF_DMAS))) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, + ("openDmas.num can't be larger than %d", MAX_NUM_OF_DMAS)); + if (p_Params->setNumOfOpenDmas + && (p_FmPort->openDmas.extra > MAX_NUM_OF_EXTRA_DMAS)) + RETURN_ERROR( + MAJOR, + E_INVALID_VALUE, + ("openDmas.extra can't be larger than %d", MAX_NUM_OF_EXTRA_DMAS)); + if (p_Params->setSizeOfFifo + && (!p_FmPort->fifoBufs.num + || (p_FmPort->fifoBufs.num > MAX_PORT_FIFO_SIZE))) + RETURN_ERROR( + MAJOR, + E_INVALID_VALUE, + ("fifoBufs.num has to be in the range of 256 - %d", MAX_PORT_FIFO_SIZE)); + if (p_Params->setSizeOfFifo && (p_FmPort->fifoBufs.num % BMI_FIFO_UNITS)) + RETURN_ERROR( + MAJOR, E_INVALID_VALUE, + ("fifoBufs.num has to be divisible by %d", BMI_FIFO_UNITS)); + +#ifdef FM_QMI_NO_DEQ_OPTIONS_SUPPORT + if (p_FmPort->fmRevInfo.majorRev == 4) + if (p_FmPort->p_FmPortDriverParam->deqPrefetchOption != DEFAULT_notSupported) + /* this is an indication that user called config for this mode which is not supported in this integration */ + RETURN_ERROR(MAJOR, E_INVALID_OPERATION, ("deqPrefetchOption")); +#endif /* FM_QMI_NO_DEQ_OPTIONS_SUPPORT */ + + return E_OK; +} + +static t_Error VerifySizeOfFifo(t_FmPort *p_FmPort) +{ + uint32_t minFifoSizeRequired = 0, optFifoSizeForB2B = 0; + + /*************************/ + /* TX PORTS */ + /*************************/ + if ((p_FmPort->portType == e_FM_PORT_TYPE_TX) + || (p_FmPort->portType == e_FM_PORT_TYPE_TX_10G)) + { + minFifoSizeRequired = + (uint32_t)(ROUND_UP(p_FmPort->maxFrameLength, BMI_FIFO_UNITS) + + (3 * BMI_FIFO_UNITS)); + if (!p_FmPort->imEn) + minFifoSizeRequired += + p_FmPort->p_FmPortDriverParam->dfltCfg.tx_fifo_deq_pipeline_depth + * BMI_FIFO_UNITS; + + optFifoSizeForB2B = minFifoSizeRequired; + + /* Add some margin for back-to-back capability to improve performance, + allows the hardware to pipeline new frame dma while the previous + frame not yet transmitted. */ + if (p_FmPort->portType == e_FM_PORT_TYPE_TX_10G) + optFifoSizeForB2B += 3 * BMI_FIFO_UNITS; + else + optFifoSizeForB2B += 2 * BMI_FIFO_UNITS; + } + + /*************************/ + /* RX IM PORTS */ + /*************************/ + else + if (((p_FmPort->portType == e_FM_PORT_TYPE_RX) + || (p_FmPort->portType == e_FM_PORT_TYPE_RX_10G)) + && p_FmPort->imEn) + { + optFifoSizeForB2B = + minFifoSizeRequired = + (uint32_t)(ROUND_UP(p_FmPort->maxFrameLength, BMI_FIFO_UNITS) + + (4 * BMI_FIFO_UNITS)); + } + + /*************************/ + /* RX non-IM PORTS */ + /*************************/ + else + if (((p_FmPort->portType == e_FM_PORT_TYPE_RX) + || (p_FmPort->portType == e_FM_PORT_TYPE_RX_10G)) + && !p_FmPort->imEn) + { + if (p_FmPort->fmRevInfo.majorRev == 4) + { + if (p_FmPort->rxPoolsParams.numOfPools == 1) + minFifoSizeRequired = 8 * BMI_FIFO_UNITS; + else + minFifoSizeRequired = + (uint32_t)(ROUND_UP(p_FmPort->rxPoolsParams.secondLargestBufSize, BMI_FIFO_UNITS) + + (7 * BMI_FIFO_UNITS)); + } + else + { +#if (DPAA_VERSION >= 11) + minFifoSizeRequired = + (uint32_t)(ROUND_UP(p_FmPort->maxFrameLength, BMI_FIFO_UNITS) + + (5 * BMI_FIFO_UNITS)); + /* 4 according to spec + 1 for FOF>0 */ +#else + minFifoSizeRequired = (uint32_t) + (ROUND_UP(MIN(p_FmPort->maxFrameLength, p_FmPort->rxPoolsParams.largestBufSize), BMI_FIFO_UNITS) + + (7*BMI_FIFO_UNITS)); +#endif /* (DPAA_VERSION >= 11) */ + } + + optFifoSizeForB2B = minFifoSizeRequired; + + /* Add some margin for back-to-back capability to improve performance, + allows the hardware to pipeline new frame dma while the previous + frame not yet transmitted. */ + if (p_FmPort->portType == e_FM_PORT_TYPE_RX_10G) + optFifoSizeForB2B += 8 * BMI_FIFO_UNITS; + else + optFifoSizeForB2B += 3 * BMI_FIFO_UNITS; + } + + /* For O/H ports, check fifo size and update if necessary */ + else + if ((p_FmPort->portType == e_FM_PORT_TYPE_OH_OFFLINE_PARSING) + || (p_FmPort->portType == e_FM_PORT_TYPE_OH_HOST_COMMAND)) + { +#if (DPAA_VERSION >= 11) + optFifoSizeForB2B = + minFifoSizeRequired = + (uint32_t)(ROUND_UP(p_FmPort->maxFrameLength, BMI_FIFO_UNITS) + + ((p_FmPort->p_FmPortDriverParam->dfltCfg.tx_fifo_deq_pipeline_depth + + 5) * BMI_FIFO_UNITS)); + /* 4 according to spec + 1 for FOF>0 */ +#else + optFifoSizeForB2B = minFifoSizeRequired = (uint32_t)((p_FmPort->tasks.num + 2) * BMI_FIFO_UNITS); +#endif /* (DPAA_VERSION >= 11) */ + } + + ASSERT_COND(minFifoSizeRequired > 0); + ASSERT_COND(optFifoSizeForB2B >= minFifoSizeRequired); + + /* Verify the size */ + if (p_FmPort->fifoBufs.num < minFifoSizeRequired) + DBG(INFO, + ("FIFO size is %d and should be enlarged to %d bytes",p_FmPort->fifoBufs.num, minFifoSizeRequired)); + else if (p_FmPort->fifoBufs.num < optFifoSizeForB2B) + DBG(INFO, + ("For back-to-back frames processing, FIFO size is %d and needs to enlarge to %d bytes", p_FmPort->fifoBufs.num, optFifoSizeForB2B)); + + return E_OK; +} + +static void FmPortDriverParamFree(t_FmPort *p_FmPort) +{ + if (p_FmPort->p_FmPortDriverParam) + { + XX_Free(p_FmPort->p_FmPortDriverParam); + p_FmPort->p_FmPortDriverParam = NULL; + } +} + +static t_Error SetExtBufferPools(t_FmPort *p_FmPort) +{ + t_FmExtPools *p_ExtBufPools = &p_FmPort->p_FmPortDriverParam->extBufPools; + t_FmBufPoolDepletion *p_BufPoolDepletion = + &p_FmPort->p_FmPortDriverParam->bufPoolDepletion; + uint8_t orderedArray[FM_PORT_MAX_NUM_OF_EXT_POOLS]; + uint16_t sizesArray[BM_MAX_NUM_OF_POOLS]; + int i = 0, j = 0, err; + struct fman_port_bpools bpools; + + memset(&orderedArray, 0, sizeof(uint8_t) * FM_PORT_MAX_NUM_OF_EXT_POOLS); + memset(&sizesArray, 0, sizeof(uint16_t) * BM_MAX_NUM_OF_POOLS); + memcpy(&p_FmPort->extBufPools, p_ExtBufPools, sizeof(t_FmExtPools)); + + FmSpSetBufPoolsInAscOrderOfBufSizes(p_ExtBufPools, orderedArray, + sizesArray); + + /* Prepare flibs bpools structure */ + memset(&bpools, 0, sizeof(struct fman_port_bpools)); + bpools.count = p_ExtBufPools->numOfPoolsUsed; + bpools.counters_enable = TRUE; + for (i = 0; i < p_ExtBufPools->numOfPoolsUsed; i++) + { + bpools.bpool[i].bpid = orderedArray[i]; + bpools.bpool[i].size = sizesArray[orderedArray[i]]; + /* functionality available only for some derivatives (limited by config) */ + if (p_FmPort->p_FmPortDriverParam->p_BackupBmPools) + for (j = 0; + j + < p_FmPort->p_FmPortDriverParam->p_BackupBmPools->numOfBackupPools; + j++) + if (orderedArray[i] + == p_FmPort->p_FmPortDriverParam->p_BackupBmPools->poolIds[j]) + { + bpools.bpool[i].is_backup = TRUE; + break; + } + } + + /* save pools parameters for later use */ + p_FmPort->rxPoolsParams.numOfPools = p_ExtBufPools->numOfPoolsUsed; + p_FmPort->rxPoolsParams.largestBufSize = + sizesArray[orderedArray[p_ExtBufPools->numOfPoolsUsed - 1]]; + p_FmPort->rxPoolsParams.secondLargestBufSize = + sizesArray[orderedArray[p_ExtBufPools->numOfPoolsUsed - 2]]; + + /* FMBM_RMPD reg. - pool depletion */ + if (p_BufPoolDepletion->poolsGrpModeEnable) + { + bpools.grp_bp_depleted_num = p_BufPoolDepletion->numOfPools; + for (i = 0; i < BM_MAX_NUM_OF_POOLS; i++) + { + if (p_BufPoolDepletion->poolsToConsider[i]) + { + for (j = 0; j < p_ExtBufPools->numOfPoolsUsed; j++) + { + if (i == orderedArray[j]) + { + bpools.bpool[j].grp_bp_depleted = TRUE; + break; + } + } + } + } + } + + if (p_BufPoolDepletion->singlePoolModeEnable) + { + for (i = 0; i < BM_MAX_NUM_OF_POOLS; i++) + { + if (p_BufPoolDepletion->poolsToConsiderForSingleMode[i]) + { + for (j = 0; j < p_ExtBufPools->numOfPoolsUsed; j++) + { + if (i == orderedArray[j]) + { + bpools.bpool[j].single_bp_depleted = TRUE; + break; + } + } + } + } + } + +#if (DPAA_VERSION >= 11) + /* fill QbbPEV */ + if (p_BufPoolDepletion->poolsGrpModeEnable + || p_BufPoolDepletion->singlePoolModeEnable) + { + for (i = 0; i < FM_MAX_NUM_OF_PFC_PRIORITIES; i++) + { + if (p_BufPoolDepletion->pfcPrioritiesEn[i] == TRUE) + { + bpools.bpool[i].pfc_priorities_en = TRUE; + } + } + } +#endif /* (DPAA_VERSION >= 11) */ + + /* Issue flibs function */ + err = fman_port_set_bpools(&p_FmPort->port, &bpools); + if (err != 0) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("fman_port_set_bpools")); + + if (p_FmPort->p_FmPortDriverParam->p_BackupBmPools) + XX_Free(p_FmPort->p_FmPortDriverParam->p_BackupBmPools); + + return E_OK; +} + +static t_Error ClearPerfCnts(t_FmPort *p_FmPort) +{ + if (p_FmPort->portType != e_FM_PORT_TYPE_OH_OFFLINE_PARSING) + FM_PORT_ModifyCounter(p_FmPort, e_FM_PORT_COUNTERS_QUEUE_UTIL, 0); + FM_PORT_ModifyCounter(p_FmPort, e_FM_PORT_COUNTERS_TASK_UTIL, 0); + FM_PORT_ModifyCounter(p_FmPort, e_FM_PORT_COUNTERS_DMA_UTIL, 0); + FM_PORT_ModifyCounter(p_FmPort, e_FM_PORT_COUNTERS_FIFO_UTIL, 0); + return E_OK; +} + +static t_Error InitLowLevelDriver(t_FmPort *p_FmPort) +{ + t_FmPortDriverParam *p_DriverParams = p_FmPort->p_FmPortDriverParam; + struct fman_port_params portParams; + uint32_t tmpVal; + t_Error err; + + /* Set up flibs parameters and issue init function */ + + memset(&portParams, 0, sizeof(struct fman_port_params)); + portParams.discard_mask = p_DriverParams->errorsToDiscard; + portParams.dflt_fqid = p_DriverParams->dfltFqid; + portParams.err_fqid = p_DriverParams->errFqid; + portParams.deq_sp = p_DriverParams->deqSubPortal; + portParams.dont_release_buf = p_DriverParams->dontReleaseBuf; + switch (p_FmPort->portType) + { + case (e_FM_PORT_TYPE_RX_10G): + case (e_FM_PORT_TYPE_RX): + portParams.err_mask = (RX_ERRS_TO_ENQ & ~portParams.discard_mask); + if (!p_FmPort->imEn) + { + if (p_DriverParams->forwardReuseIntContext) + p_DriverParams->dfltCfg.rx_fd_bits = + (uint8_t)(BMI_PORT_RFNE_FRWD_RPD >> 24); + } + break; + + case (e_FM_PORT_TYPE_OH_OFFLINE_PARSING): + portParams.err_mask = (OP_ERRS_TO_ENQ & ~portParams.discard_mask); + break; + break; + + default: + break; + } + + tmpVal = + (uint32_t)( + (p_FmPort->internalBufferOffset % OFFSET_UNITS) ? (p_FmPort->internalBufferOffset + / OFFSET_UNITS + 1) : + (p_FmPort->internalBufferOffset / OFFSET_UNITS)); + p_FmPort->internalBufferOffset = (uint8_t)(tmpVal * OFFSET_UNITS); + p_DriverParams->dfltCfg.int_buf_start_margin = + p_FmPort->internalBufferOffset; + + p_DriverParams->dfltCfg.ext_buf_start_margin = + p_DriverParams->bufMargins.startMargins; + p_DriverParams->dfltCfg.ext_buf_end_margin = + p_DriverParams->bufMargins.endMargins; + + p_DriverParams->dfltCfg.ic_ext_offset = + p_DriverParams->intContext.extBufOffset; + p_DriverParams->dfltCfg.ic_int_offset = + p_DriverParams->intContext.intContextOffset; + p_DriverParams->dfltCfg.ic_size = p_DriverParams->intContext.size; + + p_DriverParams->dfltCfg.stats_counters_enable = TRUE; + p_DriverParams->dfltCfg.perf_counters_enable = TRUE; + p_DriverParams->dfltCfg.queue_counters_enable = TRUE; + + p_DriverParams->dfltCfg.perf_cnt_params.task_val = + (uint8_t)p_FmPort->tasks.num; + if (p_FmPort->portType == e_FM_PORT_TYPE_OH_OFFLINE_PARSING || + p_FmPort->portType == e_FM_PORT_TYPE_OH_HOST_COMMAND)p_DriverParams->dfltCfg.perf_cnt_params.queue_val = 0; + else + p_DriverParams->dfltCfg.perf_cnt_params.queue_val = 1; + p_DriverParams->dfltCfg.perf_cnt_params.dma_val = + (uint8_t)p_FmPort->openDmas.num; + p_DriverParams->dfltCfg.perf_cnt_params.fifo_val = p_FmPort->fifoBufs.num; + + if (0 + != fman_port_init(&p_FmPort->port, &p_DriverParams->dfltCfg, + &portParams)) + RETURN_ERROR(MAJOR, E_NO_DEVICE, ("fman_port_init")); + + if (p_FmPort->imEn && ((err = FmPortImInit(p_FmPort)) != E_OK)) + RETURN_ERROR(MAJOR, err, NO_MSG); + else + { + // from QMIInit + if ((p_FmPort->portType != e_FM_PORT_TYPE_RX_10G) + && (p_FmPort->portType != e_FM_PORT_TYPE_RX)) + { + if (p_DriverParams->deqPrefetchOption == e_FM_PORT_DEQ_NO_PREFETCH) + FmSetPortPreFetchConfiguration(p_FmPort->h_Fm, p_FmPort->portId, + FALSE); + else + FmSetPortPreFetchConfiguration(p_FmPort->h_Fm, p_FmPort->portId, + TRUE); + } + } + /* The code bellow is a trick so the FM will not release the buffer + to BM nor will try to enqueue the frame to QM */ + if (((p_FmPort->portType == e_FM_PORT_TYPE_TX_10G) + || (p_FmPort->portType == e_FM_PORT_TYPE_TX)) && (!p_FmPort->imEn)) + { + if (!p_DriverParams->dfltFqid && p_DriverParams->dontReleaseBuf) + { + /* override fmbm_tcfqid 0 with a false non-0 value. This will force FM to + * act according to tfene. Otherwise, if fmbm_tcfqid is 0 the FM will release + * buffers to BM regardless of fmbm_tfene + */ + WRITE_UINT32(p_FmPort->port.bmi_regs->tx.fmbm_tcfqid, 0xFFFFFF); + WRITE_UINT32(p_FmPort->port.bmi_regs->tx.fmbm_tfene, + NIA_ENG_BMI | NIA_BMI_AC_TX_RELEASE); + } + } + + return E_OK; +} + +static bool CheckRxBmiCounter(t_FmPort *p_FmPort, e_FmPortCounters counter) +{ + UNUSED(p_FmPort); + + switch (counter) + { + case (e_FM_PORT_COUNTERS_CYCLE): + case (e_FM_PORT_COUNTERS_TASK_UTIL): + case (e_FM_PORT_COUNTERS_QUEUE_UTIL): + case (e_FM_PORT_COUNTERS_DMA_UTIL): + case (e_FM_PORT_COUNTERS_FIFO_UTIL): + case (e_FM_PORT_COUNTERS_RX_PAUSE_ACTIVATION): + case (e_FM_PORT_COUNTERS_FRAME): + case (e_FM_PORT_COUNTERS_DISCARD_FRAME): + case (e_FM_PORT_COUNTERS_RX_BAD_FRAME): + case (e_FM_PORT_COUNTERS_RX_LARGE_FRAME): + case (e_FM_PORT_COUNTERS_RX_FILTER_FRAME): + case (e_FM_PORT_COUNTERS_RX_LIST_DMA_ERR): + case (e_FM_PORT_COUNTERS_RX_OUT_OF_BUFFERS_DISCARD): + case (e_FM_PORT_COUNTERS_DEALLOC_BUF): + case (e_FM_PORT_COUNTERS_PREPARE_TO_ENQUEUE_COUNTER): + return TRUE; + default: + return FALSE; + } +} + +static bool CheckTxBmiCounter(t_FmPort *p_FmPort, e_FmPortCounters counter) +{ + UNUSED(p_FmPort); + + switch (counter) + { + case (e_FM_PORT_COUNTERS_CYCLE): + case (e_FM_PORT_COUNTERS_TASK_UTIL): + case (e_FM_PORT_COUNTERS_QUEUE_UTIL): + case (e_FM_PORT_COUNTERS_DMA_UTIL): + case (e_FM_PORT_COUNTERS_FIFO_UTIL): + case (e_FM_PORT_COUNTERS_FRAME): + case (e_FM_PORT_COUNTERS_DISCARD_FRAME): + case (e_FM_PORT_COUNTERS_LENGTH_ERR): + case (e_FM_PORT_COUNTERS_UNSUPPRTED_FORMAT): + case (e_FM_PORT_COUNTERS_DEALLOC_BUF): + return TRUE; + default: + return FALSE; + } +} + +static bool CheckOhBmiCounter(t_FmPort *p_FmPort, e_FmPortCounters counter) +{ + switch (counter) + { + case (e_FM_PORT_COUNTERS_CYCLE): + case (e_FM_PORT_COUNTERS_TASK_UTIL): + case (e_FM_PORT_COUNTERS_DMA_UTIL): + case (e_FM_PORT_COUNTERS_FIFO_UTIL): + case (e_FM_PORT_COUNTERS_FRAME): + case (e_FM_PORT_COUNTERS_DISCARD_FRAME): + case (e_FM_PORT_COUNTERS_RX_LIST_DMA_ERR): + case (e_FM_PORT_COUNTERS_WRED_DISCARD): + case (e_FM_PORT_COUNTERS_LENGTH_ERR): + case (e_FM_PORT_COUNTERS_UNSUPPRTED_FORMAT): + case (e_FM_PORT_COUNTERS_DEALLOC_BUF): + return TRUE; + case (e_FM_PORT_COUNTERS_RX_FILTER_FRAME): + if (p_FmPort->portType == e_FM_PORT_TYPE_OH_HOST_COMMAND) + return FALSE; + else + return TRUE; + default: + return FALSE; + } +} + +static t_Error BmiPortCheckAndGetCounterType( + t_FmPort *p_FmPort, e_FmPortCounters counter, + enum fman_port_stats_counters *p_StatsType, + enum fman_port_perf_counters *p_PerfType, bool *p_IsStats) +{ + volatile uint32_t *p_Reg; + bool isValid; + + switch (p_FmPort->portType) + { + case (e_FM_PORT_TYPE_RX_10G): + case (e_FM_PORT_TYPE_RX): + p_Reg = &p_FmPort->port.bmi_regs->rx.fmbm_rstc; + isValid = CheckRxBmiCounter(p_FmPort, counter); + break; + case (e_FM_PORT_TYPE_TX_10G): + case (e_FM_PORT_TYPE_TX): + p_Reg = &p_FmPort->port.bmi_regs->tx.fmbm_tstc; + isValid = CheckTxBmiCounter(p_FmPort, counter); + break; + case (e_FM_PORT_TYPE_OH_OFFLINE_PARSING): + case (e_FM_PORT_TYPE_OH_HOST_COMMAND): + p_Reg = &p_FmPort->port.bmi_regs->oh.fmbm_ostc; + isValid = CheckOhBmiCounter(p_FmPort, counter); + break; + default: + RETURN_ERROR(MINOR, E_INVALID_STATE, ("Unsupported port type")); + } + + if (!isValid) + RETURN_ERROR(MINOR, E_INVALID_STATE, + ("Requested counter is not available for this port type")); + + /* check that counters are enabled */ + switch (counter) + { + case (e_FM_PORT_COUNTERS_CYCLE): + case (e_FM_PORT_COUNTERS_TASK_UTIL): + case (e_FM_PORT_COUNTERS_QUEUE_UTIL): + case (e_FM_PORT_COUNTERS_DMA_UTIL): + case (e_FM_PORT_COUNTERS_FIFO_UTIL): + case (e_FM_PORT_COUNTERS_RX_PAUSE_ACTIVATION): + /* performance counters - may be read when disabled */ + *p_IsStats = FALSE; + break; + case (e_FM_PORT_COUNTERS_FRAME): + case (e_FM_PORT_COUNTERS_DISCARD_FRAME): + case (e_FM_PORT_COUNTERS_DEALLOC_BUF): + case (e_FM_PORT_COUNTERS_RX_BAD_FRAME): + case (e_FM_PORT_COUNTERS_RX_LARGE_FRAME): + case (e_FM_PORT_COUNTERS_RX_FILTER_FRAME): + case (e_FM_PORT_COUNTERS_RX_LIST_DMA_ERR): + case (e_FM_PORT_COUNTERS_RX_OUT_OF_BUFFERS_DISCARD): + case (e_FM_PORT_COUNTERS_LENGTH_ERR): + case (e_FM_PORT_COUNTERS_UNSUPPRTED_FORMAT): + case (e_FM_PORT_COUNTERS_WRED_DISCARD): + *p_IsStats = TRUE; + if (!(GET_UINT32(*p_Reg) & BMI_COUNTERS_EN)) + RETURN_ERROR(MINOR, E_INVALID_STATE, + ("Requested counter was not enabled")); + break; + default: + break; + } + + /* Set counter */ + switch (counter) + { + case (e_FM_PORT_COUNTERS_CYCLE): + *p_PerfType = E_FMAN_PORT_PERF_CNT_CYCLE; + break; + case (e_FM_PORT_COUNTERS_TASK_UTIL): + *p_PerfType = E_FMAN_PORT_PERF_CNT_TASK_UTIL; + break; + case (e_FM_PORT_COUNTERS_QUEUE_UTIL): + *p_PerfType = E_FMAN_PORT_PERF_CNT_QUEUE_UTIL; + break; + case (e_FM_PORT_COUNTERS_DMA_UTIL): + *p_PerfType = E_FMAN_PORT_PERF_CNT_DMA_UTIL; + break; + case (e_FM_PORT_COUNTERS_FIFO_UTIL): + *p_PerfType = E_FMAN_PORT_PERF_CNT_FIFO_UTIL; + break; + case (e_FM_PORT_COUNTERS_RX_PAUSE_ACTIVATION): + *p_PerfType = E_FMAN_PORT_PERF_CNT_RX_PAUSE; + break; + case (e_FM_PORT_COUNTERS_FRAME): + *p_StatsType = E_FMAN_PORT_STATS_CNT_FRAME; + break; + case (e_FM_PORT_COUNTERS_DISCARD_FRAME): + *p_StatsType = E_FMAN_PORT_STATS_CNT_DISCARD; + break; + case (e_FM_PORT_COUNTERS_DEALLOC_BUF): + *p_StatsType = E_FMAN_PORT_STATS_CNT_DEALLOC_BUF; + break; + case (e_FM_PORT_COUNTERS_RX_BAD_FRAME): + *p_StatsType = E_FMAN_PORT_STATS_CNT_RX_BAD_FRAME; + break; + case (e_FM_PORT_COUNTERS_RX_LARGE_FRAME): + *p_StatsType = E_FMAN_PORT_STATS_CNT_RX_LARGE_FRAME; + break; + case (e_FM_PORT_COUNTERS_RX_OUT_OF_BUFFERS_DISCARD): + *p_StatsType = E_FMAN_PORT_STATS_CNT_RX_OUT_OF_BUF; + break; + case (e_FM_PORT_COUNTERS_RX_FILTER_FRAME): + *p_StatsType = E_FMAN_PORT_STATS_CNT_FILTERED_FRAME; + break; + case (e_FM_PORT_COUNTERS_RX_LIST_DMA_ERR): + *p_StatsType = E_FMAN_PORT_STATS_CNT_DMA_ERR; + break; + case (e_FM_PORT_COUNTERS_WRED_DISCARD): + *p_StatsType = E_FMAN_PORT_STATS_CNT_WRED_DISCARD; + break; + case (e_FM_PORT_COUNTERS_LENGTH_ERR): + *p_StatsType = E_FMAN_PORT_STATS_CNT_LEN_ERR; + break; + case (e_FM_PORT_COUNTERS_UNSUPPRTED_FORMAT): + *p_StatsType = E_FMAN_PORT_STATS_CNT_UNSUPPORTED_FORMAT; + break; + default: + break; + } + + return E_OK; +} + +static t_Error AdditionalPrsParams(t_FmPort *p_FmPort, + t_FmPcdPrsAdditionalHdrParams *p_HdrParams, + uint32_t *p_SoftSeqAttachReg) +{ + uint8_t hdrNum, Ipv4HdrNum; + u_FmPcdHdrPrsOpts *p_prsOpts; + uint32_t tmpReg = *p_SoftSeqAttachReg, tmpPrsOffset; + + if (IS_PRIVATE_HEADER(p_HdrParams->hdr) + || IS_SPECIAL_HEADER(p_HdrParams->hdr)) + RETURN_ERROR( + MAJOR, E_NOT_SUPPORTED, + ("No additional parameters for private or special headers.")); + + if (p_HdrParams->errDisable) + tmpReg |= PRS_HDR_ERROR_DIS; + + /* Set parser options */ + if (p_HdrParams->usePrsOpts) + { + p_prsOpts = &p_HdrParams->prsOpts; + switch (p_HdrParams->hdr) + { + case (HEADER_TYPE_MPLS): + if (p_prsOpts->mplsPrsOptions.labelInterpretationEnable) + tmpReg |= PRS_HDR_MPLS_LBL_INTER_EN; + hdrNum = GetPrsHdrNum(p_prsOpts->mplsPrsOptions.nextParse); + if (hdrNum == ILLEGAL_HDR_NUM) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, NO_MSG); + Ipv4HdrNum = GetPrsHdrNum(HEADER_TYPE_IPv4); + if (hdrNum < Ipv4HdrNum) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, + ("Header must be equal or higher than IPv4")); + tmpReg |= ((uint32_t)hdrNum * PRS_HDR_ENTRY_SIZE) + << PRS_HDR_MPLS_NEXT_HDR_SHIFT; + break; + case (HEADER_TYPE_PPPoE): + if (p_prsOpts->pppoePrsOptions.enableMTUCheck) + tmpReg |= PRS_HDR_PPPOE_MTU_CHECK_EN; + break; + case (HEADER_TYPE_IPv6): + if (p_prsOpts->ipv6PrsOptions.routingHdrEnable) + tmpReg |= PRS_HDR_IPV6_ROUTE_HDR_EN; + break; + case (HEADER_TYPE_TCP): + if (p_prsOpts->tcpPrsOptions.padIgnoreChecksum) + tmpReg |= PRS_HDR_TCP_PAD_REMOVAL; + else + tmpReg &= ~PRS_HDR_TCP_PAD_REMOVAL; + break; + case (HEADER_TYPE_UDP): + if (p_prsOpts->udpPrsOptions.padIgnoreChecksum) + tmpReg |= PRS_HDR_UDP_PAD_REMOVAL; + else + tmpReg &= ~PRS_HDR_UDP_PAD_REMOVAL; + break; + default: + RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Invalid header")); + } + } + + /* set software parsing (address is divided in 2 since parser uses 2 byte access. */ + if (p_HdrParams->swPrsEnable) + { + tmpPrsOffset = FmPcdGetSwPrsOffset(p_FmPort->h_FmPcd, p_HdrParams->hdr, + p_HdrParams->indexPerHdr); + if (tmpPrsOffset == ILLEGAL_BASE) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, NO_MSG); + tmpReg |= (PRS_HDR_SW_PRS_EN | tmpPrsOffset); + } + *p_SoftSeqAttachReg = tmpReg; + + return E_OK; +} + +static uint32_t GetPortSchemeBindParams( + t_Handle h_FmPort, t_FmPcdKgInterModuleBindPortToSchemes *p_SchemeBind) +{ + t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; + uint32_t walking1Mask = 0x80000000, tmp; + uint8_t idx = 0; + + p_SchemeBind->netEnvId = p_FmPort->netEnvId; + p_SchemeBind->hardwarePortId = p_FmPort->hardwarePortId; + p_SchemeBind->useClsPlan = p_FmPort->useClsPlan; + p_SchemeBind->numOfSchemes = 0; + tmp = p_FmPort->schemesPerPortVector; + if (tmp) + { + while (tmp) + { + if (tmp & walking1Mask) + { + p_SchemeBind->schemesIds[p_SchemeBind->numOfSchemes] = idx; + p_SchemeBind->numOfSchemes++; + tmp &= ~walking1Mask; + } + walking1Mask >>= 1; + idx++; + } + } + + return tmp; +} + +static void FmPortCheckNApplyMacsec(t_Handle h_FmPort) +{ + t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; + volatile uint32_t *p_BmiCfgReg = NULL; + uint32_t macsecEn = BMI_PORT_CFG_EN_MACSEC; + uint32_t lcv, walking1Mask = 0x80000000; + uint8_t cnt = 0; + + ASSERT_COND(p_FmPort); + ASSERT_COND(p_FmPort->h_FmPcd); + ASSERT_COND(!p_FmPort->p_FmPortDriverParam); + + if ((p_FmPort->portType != e_FM_PORT_TYPE_RX_10G) + && (p_FmPort->portType != e_FM_PORT_TYPE_RX)) + return; + + p_BmiCfgReg = &p_FmPort->port.bmi_regs->rx.fmbm_rcfg; + /* get LCV for MACSEC */ + if ((lcv = FmPcdGetMacsecLcv(p_FmPort->h_FmPcd, p_FmPort->netEnvId)) + != 0) + { + while (!(lcv & walking1Mask)) + { + cnt++; + walking1Mask >>= 1; + } + + macsecEn |= (uint32_t)cnt << BMI_PORT_CFG_MS_SEL_SHIFT; + WRITE_UINT32(*p_BmiCfgReg, GET_UINT32(*p_BmiCfgReg) | macsecEn); + } +} + +static t_Error SetPcd(t_FmPort *p_FmPort, t_FmPortPcdParams *p_PcdParams) +{ + t_Error err = E_OK; + uint32_t tmpReg; + volatile uint32_t *p_BmiNia = NULL; + volatile uint32_t *p_BmiPrsNia = NULL; + volatile uint32_t *p_BmiPrsStartOffset = NULL; + volatile uint32_t *p_BmiInitPrsResult = NULL; + volatile uint32_t *p_BmiCcBase = NULL; + uint16_t hdrNum, L3HdrNum, greHdrNum; + int i; + bool isEmptyClsPlanGrp; + uint32_t tmpHxs[FM_PCD_PRS_NUM_OF_HDRS]; + uint16_t absoluteProfileId; + uint8_t physicalSchemeId; + uint32_t ccTreePhysOffset; + t_FmPcdKgInterModuleBindPortToSchemes schemeBind; + uint32_t initialSwPrs = 0; + + ASSERT_COND(p_FmPort); + SANITY_CHECK_RETURN_ERROR(!p_FmPort->p_FmPortDriverParam, E_INVALID_STATE); + + if (p_FmPort->imEn) + RETURN_ERROR(MAJOR, E_INVALID_OPERATION, + ("available for non-independant mode ports only")); + + if ((p_FmPort->portType != e_FM_PORT_TYPE_RX_10G) + && (p_FmPort->portType != e_FM_PORT_TYPE_RX) + && (p_FmPort->portType != e_FM_PORT_TYPE_OH_OFFLINE_PARSING)) + RETURN_ERROR(MAJOR, E_INVALID_OPERATION, + ("available for Rx and offline parsing ports only")); + + p_FmPort->netEnvId = FmPcdGetNetEnvId(p_PcdParams->h_NetEnv); + + p_FmPort->pcdEngines = 0; + + /* initialize p_FmPort->pcdEngines field in port's structure */ + switch (p_PcdParams->pcdSupport) + { + case (e_FM_PORT_PCD_SUPPORT_NONE): + RETURN_ERROR( + MAJOR, + E_INVALID_STATE, + ("No PCD configuration required if e_FM_PORT_PCD_SUPPORT_NONE selected")); + case (e_FM_PORT_PCD_SUPPORT_PRS_ONLY): + p_FmPort->pcdEngines |= FM_PCD_PRS; + break; + case (e_FM_PORT_PCD_SUPPORT_PLCR_ONLY): + p_FmPort->pcdEngines |= FM_PCD_PLCR; + break; + case (e_FM_PORT_PCD_SUPPORT_PRS_AND_PLCR): + p_FmPort->pcdEngines |= FM_PCD_PRS; + p_FmPort->pcdEngines |= FM_PCD_PLCR; + break; + case (e_FM_PORT_PCD_SUPPORT_PRS_AND_KG): + p_FmPort->pcdEngines |= FM_PCD_PRS; + p_FmPort->pcdEngines |= FM_PCD_KG; + break; + case (e_FM_PORT_PCD_SUPPORT_PRS_AND_KG_AND_CC): + p_FmPort->pcdEngines |= FM_PCD_PRS; + p_FmPort->pcdEngines |= FM_PCD_CC; + p_FmPort->pcdEngines |= FM_PCD_KG; + break; + case (e_FM_PORT_PCD_SUPPORT_PRS_AND_KG_AND_CC_AND_PLCR): + p_FmPort->pcdEngines |= FM_PCD_PRS; + p_FmPort->pcdEngines |= FM_PCD_KG; + p_FmPort->pcdEngines |= FM_PCD_CC; + p_FmPort->pcdEngines |= FM_PCD_PLCR; + break; + case (e_FM_PORT_PCD_SUPPORT_PRS_AND_CC): + p_FmPort->pcdEngines |= FM_PCD_PRS; + p_FmPort->pcdEngines |= FM_PCD_CC; + break; + case (e_FM_PORT_PCD_SUPPORT_PRS_AND_CC_AND_PLCR): + p_FmPort->pcdEngines |= FM_PCD_PRS; + p_FmPort->pcdEngines |= FM_PCD_CC; + p_FmPort->pcdEngines |= FM_PCD_PLCR; + break; + case (e_FM_PORT_PCD_SUPPORT_PRS_AND_KG_AND_PLCR): + p_FmPort->pcdEngines |= FM_PCD_PRS; + p_FmPort->pcdEngines |= FM_PCD_KG; + p_FmPort->pcdEngines |= FM_PCD_PLCR; + break; + case (e_FM_PORT_PCD_SUPPORT_CC_ONLY): + p_FmPort->pcdEngines |= FM_PCD_CC; + break; +#ifdef FM_CAPWAP_SUPPORT + case (e_FM_PORT_PCD_SUPPORT_CC_AND_KG): + p_FmPort->pcdEngines |= FM_PCD_CC; + p_FmPort->pcdEngines |= FM_PCD_KG; + break; + case (e_FM_PORT_PCD_SUPPORT_CC_AND_KG_AND_PLCR): + p_FmPort->pcdEngines |= FM_PCD_CC; + p_FmPort->pcdEngines |= FM_PCD_KG; + p_FmPort->pcdEngines |= FM_PCD_PLCR; + break; +#endif /* FM_CAPWAP_SUPPORT */ + + default: + RETURN_ERROR(MAJOR, E_INVALID_STATE, ("invalid pcdSupport")); + } + + if ((p_FmPort->pcdEngines & FM_PCD_PRS) + && (p_PcdParams->p_PrsParams->numOfHdrsWithAdditionalParams + > FM_PCD_PRS_NUM_OF_HDRS)) + RETURN_ERROR( + MAJOR, + E_INVALID_VALUE, + ("Port parser numOfHdrsWithAdditionalParams may not exceed %d", FM_PCD_PRS_NUM_OF_HDRS)); + + /* check that parameters exist for each and only each defined engine */ + if ((!!(p_FmPort->pcdEngines & FM_PCD_PRS) != !!p_PcdParams->p_PrsParams) + || (!!(p_FmPort->pcdEngines & FM_PCD_KG) + != !!p_PcdParams->p_KgParams) + || (!!(p_FmPort->pcdEngines & FM_PCD_CC) + != !!p_PcdParams->p_CcParams)) + RETURN_ERROR( + MAJOR, + E_INVALID_STATE, + ("PCD initialization structure is not consistent with pcdSupport")); + + /* get PCD registers pointers */ + switch (p_FmPort->portType) + { + case (e_FM_PORT_TYPE_RX_10G): + case (e_FM_PORT_TYPE_RX): + p_BmiNia = &p_FmPort->port.bmi_regs->rx.fmbm_rfne; + p_BmiPrsNia = &p_FmPort->port.bmi_regs->rx.fmbm_rfpne; + p_BmiPrsStartOffset = &p_FmPort->port.bmi_regs->rx.fmbm_rpso; + p_BmiInitPrsResult = &p_FmPort->port.bmi_regs->rx.fmbm_rprai[0]; + p_BmiCcBase = &p_FmPort->port.bmi_regs->rx.fmbm_rccb; + break; + case (e_FM_PORT_TYPE_OH_OFFLINE_PARSING): + p_BmiNia = &p_FmPort->port.bmi_regs->oh.fmbm_ofne; + p_BmiPrsNia = &p_FmPort->port.bmi_regs->oh.fmbm_ofpne; + p_BmiPrsStartOffset = &p_FmPort->port.bmi_regs->oh.fmbm_opso; + p_BmiInitPrsResult = &p_FmPort->port.bmi_regs->oh.fmbm_oprai[0]; + p_BmiCcBase = &p_FmPort->port.bmi_regs->oh.fmbm_occb; + break; + default: + RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Invalid port type")); + } + + /* set PCD port parameter */ + if (p_FmPort->pcdEngines & FM_PCD_CC) + { + err = FmPcdCcBindTree(p_FmPort->h_FmPcd, p_PcdParams, + p_PcdParams->p_CcParams->h_CcTree, + &ccTreePhysOffset, p_FmPort); + if (err) + RETURN_ERROR(MAJOR, err, NO_MSG); + + WRITE_UINT32(*p_BmiCcBase, ccTreePhysOffset); + p_FmPort->ccTreeId = p_PcdParams->p_CcParams->h_CcTree; + } + + if (p_FmPort->pcdEngines & FM_PCD_KG) + { + if (p_PcdParams->p_KgParams->numOfSchemes == 0) + RETURN_ERROR( + MAJOR, + E_INVALID_VALUE, + ("For ports using Keygen, at least one scheme must be bound. ")); + + err = FmPcdKgSetOrBindToClsPlanGrp(p_FmPort->h_FmPcd, + p_FmPort->hardwarePortId, + p_FmPort->netEnvId, + p_FmPort->optArray, + &p_FmPort->clsPlanGrpId, + &isEmptyClsPlanGrp); + if (err) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, + ("FmPcdKgSetOrBindToClsPlanGrp failed. ")); + + p_FmPort->useClsPlan = !isEmptyClsPlanGrp; + + schemeBind.netEnvId = p_FmPort->netEnvId; + schemeBind.hardwarePortId = p_FmPort->hardwarePortId; + schemeBind.numOfSchemes = p_PcdParams->p_KgParams->numOfSchemes; + schemeBind.useClsPlan = p_FmPort->useClsPlan; + + /* for each scheme */ + for (i = 0; i < p_PcdParams->p_KgParams->numOfSchemes; i++) + { + ASSERT_COND(p_PcdParams->p_KgParams->h_Schemes[i]); + physicalSchemeId = FmPcdKgGetSchemeId( + p_PcdParams->p_KgParams->h_Schemes[i]); + schemeBind.schemesIds[i] = physicalSchemeId; + /* build vector */ + p_FmPort->schemesPerPortVector |= 1 + << (31 - (uint32_t)physicalSchemeId); +#if (DPAA_VERSION >= 11) + /*because of the state that VSPE is defined per port - all PCD path should be according to this requirement + if !VSPE - in port, for relevant scheme VSPE can not be set*/ + if (!p_FmPort->vspe + && FmPcdKgGetVspe((p_PcdParams->p_KgParams->h_Schemes[i]))) + RETURN_ERROR(MAJOR, E_INVALID_STATE, + ("VSPE is not at port level")); +#endif /* (DPAA_VERSION >= 11) */ + } + + err = FmPcdKgBindPortToSchemes(p_FmPort->h_FmPcd, &schemeBind); + if (err) + RETURN_ERROR(MAJOR, err, NO_MSG); + } + + /***************************/ + /* configure NIA after BMI */ + /***************************/ + /* rfne may contain FDCS bits, so first we read them. */ + p_FmPort->savedBmiNia = GET_UINT32(*p_BmiNia) & BMI_RFNE_FDCS_MASK; + + /* If policer is used directly after BMI or PRS */ + if ((p_FmPort->pcdEngines & FM_PCD_PLCR) + && ((p_PcdParams->pcdSupport == e_FM_PORT_PCD_SUPPORT_PLCR_ONLY) + || (p_PcdParams->pcdSupport + == e_FM_PORT_PCD_SUPPORT_PRS_AND_PLCR))) + { + if (!p_PcdParams->p_PlcrParams->h_Profile) + RETURN_ERROR(MAJOR, E_INVALID_STATE, + ("Profile should be initialized")); + + absoluteProfileId = (uint16_t)FmPcdPlcrProfileGetAbsoluteId( + p_PcdParams->p_PlcrParams->h_Profile); + + if (!FmPcdPlcrIsProfileValid(p_FmPort->h_FmPcd, absoluteProfileId)) + RETURN_ERROR(MAJOR, E_INVALID_STATE, + ("Private port profile not valid.")); + + tmpReg = (uint32_t)(absoluteProfileId | NIA_PLCR_ABSOLUTE); + + if (p_FmPort->pcdEngines & FM_PCD_PRS) /* e_FM_PCD_SUPPORT_PRS_AND_PLCR */ + /* update BMI HPNIA */ + WRITE_UINT32(*p_BmiPrsNia, (uint32_t)(NIA_ENG_PLCR | tmpReg)); + else + /* e_FM_PCD_SUPPORT_PLCR_ONLY */ + /* update BMI NIA */ + p_FmPort->savedBmiNia |= (uint32_t)(NIA_ENG_PLCR); + } + + /* if CC is used directly after BMI */ + if ((p_PcdParams->pcdSupport == e_FM_PORT_PCD_SUPPORT_CC_ONLY) +#ifdef FM_CAPWAP_SUPPORT + || (p_PcdParams->pcdSupport == e_FM_PORT_PCD_SUPPORT_CC_AND_KG) + || (p_PcdParams->pcdSupport == e_FM_PORT_PCD_SUPPORT_CC_AND_KG_AND_PLCR) +#endif /* FM_CAPWAP_SUPPORT */ + ) + { + if (p_FmPort->portType != e_FM_PORT_TYPE_OH_OFFLINE_PARSING) + RETURN_ERROR( + MAJOR, + E_INVALID_OPERATION, + ("e_FM_PORT_PCD_SUPPORT_CC_xx available for offline parsing ports only")); + p_FmPort->savedBmiNia |= (uint32_t)(NIA_ENG_FM_CTL | NIA_FM_CTL_AC_CC); + /* check that prs start offset == RIM[FOF] */ + } + + if (p_FmPort->pcdEngines & FM_PCD_PRS) + { + ASSERT_COND(p_PcdParams->p_PrsParams); +#if (DPAA_VERSION >= 11) + if (p_PcdParams->p_PrsParams->firstPrsHdr == HEADER_TYPE_CAPWAP) + hdrNum = OFFLOAD_SW_PATCH_CAPWAP_LABEL; + else + { +#endif /* (DPAA_VERSION >= 11) */ + /* if PRS is used it is always first */ + hdrNum = GetPrsHdrNum(p_PcdParams->p_PrsParams->firstPrsHdr); + if (hdrNum == ILLEGAL_HDR_NUM) + RETURN_ERROR(MAJOR, E_NOT_SUPPORTED, ("Unsupported header.")); +#if (DPAA_VERSION >= 11) + } +#endif /* (DPAA_VERSION >= 11) */ + p_FmPort->savedBmiNia |= (uint32_t)(NIA_ENG_PRS | (uint32_t)(hdrNum)); + /* set after parser NIA */ + tmpReg = 0; + switch (p_PcdParams->pcdSupport) + { + case (e_FM_PORT_PCD_SUPPORT_PRS_ONLY): + WRITE_UINT32(*p_BmiPrsNia, + GET_NIA_BMI_AC_ENQ_FRAME(p_FmPort->h_FmPcd)); + break; + case (e_FM_PORT_PCD_SUPPORT_PRS_AND_KG_AND_CC): + case (e_FM_PORT_PCD_SUPPORT_PRS_AND_KG_AND_CC_AND_PLCR): + tmpReg = NIA_KG_CC_EN; + case (e_FM_PORT_PCD_SUPPORT_PRS_AND_KG): + case (e_FM_PORT_PCD_SUPPORT_PRS_AND_KG_AND_PLCR): + if (p_PcdParams->p_KgParams->directScheme) + { + physicalSchemeId = FmPcdKgGetSchemeId( + p_PcdParams->p_KgParams->h_DirectScheme); + /* check that this scheme was bound to this port */ + for (i = 0; i < p_PcdParams->p_KgParams->numOfSchemes; i++) + if (p_PcdParams->p_KgParams->h_DirectScheme + == p_PcdParams->p_KgParams->h_Schemes[i]) + break; + if (i == p_PcdParams->p_KgParams->numOfSchemes) + RETURN_ERROR( + MAJOR, + E_INVALID_VALUE, + ("Direct scheme is not one of the port selected schemes.")); + tmpReg |= (uint32_t)(NIA_KG_DIRECT | physicalSchemeId); + } + WRITE_UINT32(*p_BmiPrsNia, NIA_ENG_KG | tmpReg); + break; + case (e_FM_PORT_PCD_SUPPORT_PRS_AND_CC): + case (e_FM_PORT_PCD_SUPPORT_PRS_AND_CC_AND_PLCR): + WRITE_UINT32(*p_BmiPrsNia, + (uint32_t)(NIA_ENG_FM_CTL | NIA_FM_CTL_AC_CC)); + break; + case (e_FM_PORT_PCD_SUPPORT_PRS_AND_PLCR): + break; + default: + RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Invalid PCD support")); + } + + /* set start parsing offset */ + WRITE_UINT32(*p_BmiPrsStartOffset, + p_PcdParams->p_PrsParams->parsingOffset); + + /************************************/ + /* Parser port parameters */ + /************************************/ + /* stop before configuring */ + WRITE_UINT32(p_FmPort->p_FmPortPrsRegs->pcac, PRS_CAC_STOP); + /* wait for parser to be in idle state */ + while (GET_UINT32(p_FmPort->p_FmPortPrsRegs->pcac) & PRS_CAC_ACTIVE) + ; + + /* set soft seq attachment register */ + memset(tmpHxs, 0, FM_PCD_PRS_NUM_OF_HDRS * sizeof(uint32_t)); + + /* set protocol options */ + for (i = 0; p_FmPort->optArray[i]; i++) + switch (p_FmPort->optArray[i]) + { + case (ETH_BROADCAST): + hdrNum = GetPrsHdrNum(HEADER_TYPE_ETH); + tmpHxs[hdrNum] |= (i + 1) << PRS_HDR_ETH_BC_SHIFT; + break; + case (ETH_MULTICAST): + hdrNum = GetPrsHdrNum(HEADER_TYPE_ETH); + tmpHxs[hdrNum] |= (i + 1) << PRS_HDR_ETH_MC_SHIFT; + break; + case (VLAN_STACKED): + hdrNum = GetPrsHdrNum(HEADER_TYPE_VLAN); + tmpHxs[hdrNum] |= (i + 1) << PRS_HDR_VLAN_STACKED_SHIFT; + break; + case (MPLS_STACKED): + hdrNum = GetPrsHdrNum(HEADER_TYPE_MPLS); + tmpHxs[hdrNum] |= (i + 1) << PRS_HDR_MPLS_STACKED_SHIFT; + break; + case (IPV4_BROADCAST_1): + hdrNum = GetPrsHdrNum(HEADER_TYPE_IPv4); + tmpHxs[hdrNum] |= (i + 1) << PRS_HDR_IPV4_1_BC_SHIFT; + break; + case (IPV4_MULTICAST_1): + hdrNum = GetPrsHdrNum(HEADER_TYPE_IPv4); + tmpHxs[hdrNum] |= (i + 1) << PRS_HDR_IPV4_1_MC_SHIFT; + break; + case (IPV4_UNICAST_2): + hdrNum = GetPrsHdrNum(HEADER_TYPE_IPv4); + tmpHxs[hdrNum] |= (i + 1) << PRS_HDR_IPV4_2_UC_SHIFT; + break; + case (IPV4_MULTICAST_BROADCAST_2): + hdrNum = GetPrsHdrNum(HEADER_TYPE_IPv4); + tmpHxs[hdrNum] |= (i + 1) << PRS_HDR_IPV4_2_MC_BC_SHIFT; + break; + case (IPV6_MULTICAST_1): + hdrNum = GetPrsHdrNum(HEADER_TYPE_IPv6); + tmpHxs[hdrNum] |= (i + 1) << PRS_HDR_IPV6_1_MC_SHIFT; + break; + case (IPV6_UNICAST_2): + hdrNum = GetPrsHdrNum(HEADER_TYPE_IPv6); + tmpHxs[hdrNum] |= (i + 1) << PRS_HDR_IPV6_2_UC_SHIFT; + break; + case (IPV6_MULTICAST_2): + hdrNum = GetPrsHdrNum(HEADER_TYPE_IPv6); + tmpHxs[hdrNum] |= (i + 1) << PRS_HDR_IPV6_2_MC_SHIFT; + break; + } + + if (FmPcdNetEnvIsHdrExist(p_FmPort->h_FmPcd, p_FmPort->netEnvId, + HEADER_TYPE_UDP_ENCAP_ESP)) + { + if (p_PcdParams->p_PrsParams->numOfHdrsWithAdditionalParams == FM_PCD_PRS_NUM_OF_HDRS) + RETURN_ERROR( + MINOR, E_INVALID_VALUE, + ("If HEADER_TYPE_UDP_ENCAP_ESP is used, numOfHdrsWithAdditionalParams may be up to FM_PCD_PRS_NUM_OF_HDRS - 1")); + + p_PcdParams->p_PrsParams->additionalParams[p_PcdParams->p_PrsParams->numOfHdrsWithAdditionalParams].hdr = + HEADER_TYPE_UDP; + p_PcdParams->p_PrsParams->additionalParams[p_PcdParams->p_PrsParams->numOfHdrsWithAdditionalParams].swPrsEnable = + TRUE; + p_PcdParams->p_PrsParams->numOfHdrsWithAdditionalParams++; + } + + /* set MPLS default next header - HW reset workaround */ + hdrNum = GetPrsHdrNum(HEADER_TYPE_MPLS); + tmpHxs[hdrNum] |= PRS_HDR_MPLS_LBL_INTER_EN; + L3HdrNum = GetPrsHdrNum(HEADER_TYPE_USER_DEFINED_L3); + tmpHxs[hdrNum] |= (uint32_t)L3HdrNum << PRS_HDR_MPLS_NEXT_HDR_SHIFT; + + /* for GRE, disable errors */ + greHdrNum = GetPrsHdrNum(HEADER_TYPE_GRE); + tmpHxs[greHdrNum] |= PRS_HDR_ERROR_DIS; + + /* For UDP remove PAD from L4 checksum calculation */ + hdrNum = GetPrsHdrNum(HEADER_TYPE_UDP); + tmpHxs[hdrNum] |= PRS_HDR_UDP_PAD_REMOVAL; + /* For TCP remove PAD from L4 checksum calculation */ + hdrNum = GetPrsHdrNum(HEADER_TYPE_TCP); + tmpHxs[hdrNum] |= PRS_HDR_TCP_PAD_REMOVAL; + + /* config additional params for specific headers */ + for (i = 0; i < p_PcdParams->p_PrsParams->numOfHdrsWithAdditionalParams; + i++) + { + /* case for using sw parser as the initial NIA address, before + * HW parsing + */ + if ((p_PcdParams->p_PrsParams->additionalParams[i].hdr == HEADER_TYPE_NONE) && + p_PcdParams->p_PrsParams->additionalParams[i].swPrsEnable) + { + initialSwPrs = FmPcdGetSwPrsOffset(p_FmPort->h_FmPcd, HEADER_TYPE_NONE, + p_PcdParams->p_PrsParams->additionalParams[i].indexPerHdr); + if (initialSwPrs == ILLEGAL_BASE) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, NO_MSG); + + /* clear parser first HXS */ + p_FmPort->savedBmiNia &= ~BMI_RFNE_HXS_MASK; /* 0x000000FF */ + /* rewrite with soft parser start */ + p_FmPort->savedBmiNia |= initialSwPrs; + continue; + } + + hdrNum = + GetPrsHdrNum(p_PcdParams->p_PrsParams->additionalParams[i].hdr); + if (hdrNum == ILLEGAL_HDR_NUM) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, NO_MSG); + if (hdrNum == NO_HDR_NUM) + RETURN_ERROR( + MAJOR, E_INVALID_VALUE, + ("Private headers may not use additional parameters")); + + err = AdditionalPrsParams( + p_FmPort, &p_PcdParams->p_PrsParams->additionalParams[i], + &tmpHxs[hdrNum]); + if (err) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, NO_MSG); + } + + /* Check if ip-reassembly port - need to link sw-parser code */ + if (p_FmPort->h_IpReassemblyManip) + { + /* link to sw parser code for IP Frag - only if no other code is applied. */ + hdrNum = GetPrsHdrNum(HEADER_TYPE_IPv4); + if (!(tmpHxs[hdrNum] & PRS_HDR_SW_PRS_EN)) + tmpHxs[hdrNum] |= (PRS_HDR_SW_PRS_EN | OFFLOAD_SW_PATCH_IPv4_IPR_LABEL); + hdrNum = GetPrsHdrNum(HEADER_TYPE_IPv6); + if (!(tmpHxs[hdrNum] & PRS_HDR_SW_PRS_EN)) + tmpHxs[hdrNum] |= (PRS_HDR_SW_PRS_EN | OFFLOAD_SW_PATCH_IPv6_IPR_LABEL); + } else { + if (FmPcdNetEnvIsHdrExist(p_FmPort->h_FmPcd, p_FmPort->netEnvId, HEADER_TYPE_UDP_LITE)) + { + hdrNum = GetPrsHdrNum(HEADER_TYPE_IPv6); + if (!(tmpHxs[hdrNum] & PRS_HDR_SW_PRS_EN)) + tmpHxs[hdrNum] |= (PRS_HDR_SW_PRS_EN | OFFLOAD_SW_PATCH_IPv6_IPF_LABEL); + } else if ((FmPcdIsAdvancedOffloadSupported(p_FmPort->h_FmPcd) + && (p_FmPort->portType == e_FM_PORT_TYPE_OH_OFFLINE_PARSING))) + { + hdrNum = GetPrsHdrNum(HEADER_TYPE_IPv6); + if (!(tmpHxs[hdrNum] & PRS_HDR_SW_PRS_EN)) + tmpHxs[hdrNum] |= (PRS_HDR_SW_PRS_EN | OFFLOAD_SW_PATCH_IPv6_IPF_LABEL); + } + } + +#if ((DPAA_VERSION == 10) && defined(FM_CAPWAP_SUPPORT)) + if (FmPcdNetEnvIsHdrExist(p_FmPort->h_FmPcd, p_FmPort->netEnvId, + HEADER_TYPE_UDP_LITE)) + { + /* link to sw parser code for udp lite - only if no other code is applied. */ + hdrNum = GetPrsHdrNum(HEADER_TYPE_IPv6); + if (!(tmpHxs[hdrNum] & PRS_HDR_SW_PRS_EN)) + tmpHxs[hdrNum] |= (PRS_HDR_SW_PRS_EN | UDP_LITE_SW_PATCH_LABEL); + } +#endif /* ((DPAA_VERSION == 10) && defined(FM_CAPWAP_SUPPORT)) */ + for (i = 0; i < FM_PCD_PRS_NUM_OF_HDRS; i++) + { + /* For all header set LCV as taken from netEnv*/ + WRITE_UINT32( + p_FmPort->p_FmPortPrsRegs->hdrs[i].lcv, + FmPcdGetLcv(p_FmPort->h_FmPcd, p_FmPort->netEnvId, (uint8_t)i)); + /* set HXS register according to default+Additional params+protocol options */ + WRITE_UINT32(p_FmPort->p_FmPortPrsRegs->hdrs[i].softSeqAttach, + tmpHxs[i]); + } + + /* set tpid. */ + tmpReg = PRS_TPID_DFLT; + if (p_PcdParams->p_PrsParams->setVlanTpid1) + { + tmpReg &= PRS_TPID2_MASK; + tmpReg |= (uint32_t)p_PcdParams->p_PrsParams->vlanTpid1 + << PRS_PCTPID_SHIFT; + } + if (p_PcdParams->p_PrsParams->setVlanTpid2) + { + tmpReg &= PRS_TPID1_MASK; + tmpReg |= (uint32_t)p_PcdParams->p_PrsParams->vlanTpid2; + }WRITE_UINT32(p_FmPort->p_FmPortPrsRegs->pctpid, tmpReg); + + /* enable parser */ + WRITE_UINT32(p_FmPort->p_FmPortPrsRegs->pcac, 0); + + if (p_PcdParams->p_PrsParams->prsResultPrivateInfo) + p_FmPort->privateInfo = + p_PcdParams->p_PrsParams->prsResultPrivateInfo; + + } /* end parser */ + else { + if (FmPcdIsAdvancedOffloadSupported(p_FmPort->h_FmPcd) + && (p_FmPort->portType == e_FM_PORT_TYPE_OH_OFFLINE_PARSING)) + { + hdrNum = GetPrsHdrNum(HEADER_TYPE_IPv6); + WRITE_UINT32(p_FmPort->p_FmPortPrsRegs->hdrs[hdrNum].softSeqAttach, + (PRS_HDR_SW_PRS_EN | OFFLOAD_SW_PATCH_IPv6_IPF_LABEL)); + } + + WRITE_UINT32(*p_BmiPrsStartOffset, 0); + + p_FmPort->privateInfo = 0; + } + + FmPortCheckNApplyMacsec(p_FmPort); + + WRITE_UINT32( + *p_BmiPrsStartOffset, + GET_UINT32(*p_BmiPrsStartOffset) + p_FmPort->internalBufferOffset); + + /* set initial parser result - used for all engines */ + for (i = 0; i < FM_PORT_PRS_RESULT_NUM_OF_WORDS; i++) + { + if (!i) + WRITE_UINT32( + *(p_BmiInitPrsResult), + (uint32_t)(((uint32_t)p_FmPort->privateInfo << BMI_PR_PORTID_SHIFT) | BMI_PRS_RESULT_HIGH)); + else + { + if (i < FM_PORT_PRS_RESULT_NUM_OF_WORDS / 2) + WRITE_UINT32(*(p_BmiInitPrsResult+i), BMI_PRS_RESULT_HIGH); + else + WRITE_UINT32(*(p_BmiInitPrsResult+i), BMI_PRS_RESULT_LOW); + } + } + + return E_OK; +} + +static t_Error DeletePcd(t_FmPort *p_FmPort) +{ + t_Error err = E_OK; + volatile uint32_t *p_BmiNia = NULL; + volatile uint32_t *p_BmiPrsStartOffset = NULL; + + ASSERT_COND(p_FmPort); + SANITY_CHECK_RETURN_ERROR(!p_FmPort->p_FmPortDriverParam, E_INVALID_STATE); + + if (p_FmPort->imEn) + RETURN_ERROR(MAJOR, E_INVALID_OPERATION, + ("available for non-independant mode ports only")); + + if ((p_FmPort->portType != e_FM_PORT_TYPE_RX_10G) + && (p_FmPort->portType != e_FM_PORT_TYPE_RX) + && (p_FmPort->portType != e_FM_PORT_TYPE_OH_OFFLINE_PARSING)) + RETURN_ERROR( MAJOR, E_INVALID_OPERATION, + ("available for Rx and offline parsing ports only")); + + if (!p_FmPort->pcdEngines) + RETURN_ERROR(MAJOR, E_INVALID_OPERATION, ("called for non PCD port")); + + /* get PCD registers pointers */ + switch (p_FmPort->portType) + { + case (e_FM_PORT_TYPE_RX_10G): + case (e_FM_PORT_TYPE_RX): + p_BmiNia = &p_FmPort->port.bmi_regs->rx.fmbm_rfne; + p_BmiPrsStartOffset = &p_FmPort->port.bmi_regs->rx.fmbm_rpso; + break; + case (e_FM_PORT_TYPE_OH_OFFLINE_PARSING): + p_BmiNia = &p_FmPort->port.bmi_regs->oh.fmbm_ofne; + p_BmiPrsStartOffset = &p_FmPort->port.bmi_regs->oh.fmbm_opso; + break; + default: + RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Invalid port type")); + } + + if ((GET_UINT32(*p_BmiNia) & GET_NO_PCD_NIA_BMI_AC_ENQ_FRAME()) + != GET_NO_PCD_NIA_BMI_AC_ENQ_FRAME()) + RETURN_ERROR(MAJOR, E_INVALID_OPERATION, + ("port has to be detached previousely")); + + WRITE_UINT32(*p_BmiPrsStartOffset, 0); + + /* "cut" PCD out of the port's flow - go to BMI */ + /* WRITE_UINT32(*p_BmiNia, (p_FmPort->savedBmiNia & BMI_RFNE_FDCS_MASK) | (NIA_ENG_BMI | NIA_BMI_AC_ENQ_FRAME)); */ + + if (p_FmPort->pcdEngines & FM_PCD_PRS) + { + /* stop parser */ + WRITE_UINT32(p_FmPort->p_FmPortPrsRegs->pcac, PRS_CAC_STOP); + /* wait for parser to be in idle state */ + while (GET_UINT32(p_FmPort->p_FmPortPrsRegs->pcac) & PRS_CAC_ACTIVE) + ; + } + + if (p_FmPort->pcdEngines & FM_PCD_KG) + { + t_FmPcdKgInterModuleBindPortToSchemes schemeBind; + + /* unbind all schemes */ + p_FmPort->schemesPerPortVector = GetPortSchemeBindParams(p_FmPort, + &schemeBind); + + err = FmPcdKgUnbindPortToSchemes(p_FmPort->h_FmPcd, &schemeBind); + if (err) + RETURN_ERROR(MAJOR, err, NO_MSG); + + err = FmPcdKgDeleteOrUnbindPortToClsPlanGrp(p_FmPort->h_FmPcd, + p_FmPort->hardwarePortId, + p_FmPort->clsPlanGrpId); + if (err) + RETURN_ERROR(MAJOR, err, NO_MSG); + p_FmPort->useClsPlan = FALSE; + } + + if (p_FmPort->pcdEngines & FM_PCD_CC) + { + /* unbind - we need to get the treeId too */ + err = FmPcdCcUnbindTree(p_FmPort->h_FmPcd, p_FmPort->ccTreeId); + if (err) + RETURN_ERROR(MAJOR, err, NO_MSG); + } + + p_FmPort->pcdEngines = 0; + + return E_OK; +} + +static t_Error AttachPCD(t_FmPort *p_FmPort) +{ + volatile uint32_t *p_BmiNia = NULL; + + ASSERT_COND(p_FmPort); + + /* get PCD registers pointers */ + if (p_FmPort->portType == e_FM_PORT_TYPE_OH_OFFLINE_PARSING) + p_BmiNia = &p_FmPort->port.bmi_regs->oh.fmbm_ofne; + else + p_BmiNia = &p_FmPort->port.bmi_regs->rx.fmbm_rfne; + + /* check that current NIA is BMI to BMI */ + if ((GET_UINT32(*p_BmiNia) & ~BMI_RFNE_FDCS_MASK) + != GET_NO_PCD_NIA_BMI_AC_ENQ_FRAME()) + RETURN_ERROR( MAJOR, E_INVALID_OPERATION, + ("may be called only for ports in BMI-to-BMI state.")); + + if (p_FmPort->requiredAction & UPDATE_FMFP_PRC_WITH_ONE_RISC_ONLY) + if (FmSetNumOfRiscsPerPort(p_FmPort->h_Fm, p_FmPort->hardwarePortId, 1, + p_FmPort->orFmanCtrl) != E_OK) + RETURN_ERROR(MAJOR, E_INVALID_STATE, NO_MSG); + + if (p_FmPort->requiredAction & UPDATE_NIA_CMNE) + { + if (p_FmPort->portType == e_FM_PORT_TYPE_OH_OFFLINE_PARSING) + WRITE_UINT32(p_FmPort->port.bmi_regs->oh.fmbm_ocmne, + p_FmPort->savedBmiCmne); + else + WRITE_UINT32(p_FmPort->port.bmi_regs->rx.fmbm_rcmne, + p_FmPort->savedBmiCmne); + } + + if (p_FmPort->requiredAction & UPDATE_NIA_PNEN) + WRITE_UINT32(p_FmPort->p_FmPortQmiRegs->fmqm_pnen, + p_FmPort->savedQmiPnen); + + if (p_FmPort->requiredAction & UPDATE_NIA_FENE) + { + if (p_FmPort->portType == e_FM_PORT_TYPE_OH_OFFLINE_PARSING) + WRITE_UINT32(p_FmPort->port.bmi_regs->oh.fmbm_ofene, + p_FmPort->savedBmiFene); + else + WRITE_UINT32(p_FmPort->port.bmi_regs->rx.fmbm_rfene, + p_FmPort->savedBmiFene); + } + + if (p_FmPort->requiredAction & UPDATE_NIA_FPNE) + { + if (p_FmPort->portType == e_FM_PORT_TYPE_OH_OFFLINE_PARSING) + WRITE_UINT32(p_FmPort->port.bmi_regs->oh.fmbm_ofpne, + p_FmPort->savedBmiFpne); + else + WRITE_UINT32(p_FmPort->port.bmi_regs->rx.fmbm_rfpne, + p_FmPort->savedBmiFpne); + } + + if (p_FmPort->requiredAction & UPDATE_OFP_DPTE) + { + ASSERT_COND(p_FmPort->portType == e_FM_PORT_TYPE_OH_OFFLINE_PARSING); + + WRITE_UINT32(p_FmPort->port.bmi_regs->oh.fmbm_ofp, + p_FmPort->savedBmiOfp); + } + + WRITE_UINT32(*p_BmiNia, p_FmPort->savedBmiNia); + + if (p_FmPort->requiredAction & UPDATE_NIA_PNDN) + { + p_FmPort->origNonRxQmiRegsPndn = + GET_UINT32(p_FmPort->port.qmi_regs->fmqm_pndn); + WRITE_UINT32(p_FmPort->port.qmi_regs->fmqm_pndn, + p_FmPort->savedNonRxQmiRegsPndn); + } + + return E_OK; +} + +static t_Error DetachPCD(t_FmPort *p_FmPort) +{ + volatile uint32_t *p_BmiNia = NULL; + + ASSERT_COND(p_FmPort); + + /* get PCD registers pointers */ + if (p_FmPort->requiredAction & UPDATE_NIA_PNDN) + WRITE_UINT32(p_FmPort->port.qmi_regs->fmqm_pndn, + p_FmPort->origNonRxQmiRegsPndn); + + if (p_FmPort->portType == e_FM_PORT_TYPE_OH_OFFLINE_PARSING) + p_BmiNia = &p_FmPort->port.bmi_regs->oh.fmbm_ofne; + else + p_BmiNia = &p_FmPort->port.bmi_regs->rx.fmbm_rfne; + + WRITE_UINT32( + *p_BmiNia, + (p_FmPort->savedBmiNia & BMI_RFNE_FDCS_MASK) | GET_NO_PCD_NIA_BMI_AC_ENQ_FRAME()); + + if (FmPcdGetHcHandle(p_FmPort->h_FmPcd)) + FmPcdHcSync(p_FmPort->h_FmPcd); + + if (p_FmPort->requiredAction & UPDATE_NIA_FENE) + { + if (p_FmPort->portType == e_FM_PORT_TYPE_OH_OFFLINE_PARSING) + WRITE_UINT32(p_FmPort->port.bmi_regs->oh.fmbm_ofene, + NIA_ENG_QMI_ENQ | NIA_ORDER_RESTOR); + else + WRITE_UINT32(p_FmPort->port.bmi_regs->rx.fmbm_rfene, + NIA_ENG_QMI_ENQ | NIA_ORDER_RESTOR); + } + + if (p_FmPort->requiredAction & UPDATE_NIA_PNEN) + WRITE_UINT32(p_FmPort->port.qmi_regs->fmqm_pnen, + NIA_ENG_BMI | NIA_BMI_AC_RELEASE); + + if (p_FmPort->requiredAction & UPDATE_FMFP_PRC_WITH_ONE_RISC_ONLY) + if (FmSetNumOfRiscsPerPort(p_FmPort->h_Fm, p_FmPort->hardwarePortId, 2, + p_FmPort->orFmanCtrl) != E_OK) + RETURN_ERROR(MAJOR, E_INVALID_STATE, NO_MSG); + + p_FmPort->requiredAction = 0; + + return E_OK; +} + +/*****************************************************************************/ +/* Inter-module API routines */ +/*****************************************************************************/ +void FmPortSetMacsecCmd(t_Handle h_FmPort, uint8_t dfltSci) +{ + t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; + volatile uint32_t *p_BmiCfgReg = NULL; + uint32_t tmpReg; + + SANITY_CHECK_RETURN(p_FmPort, E_INVALID_HANDLE); + SANITY_CHECK_RETURN(p_FmPort->p_FmPortDriverParam, E_INVALID_STATE); + + if ((p_FmPort->portType != e_FM_PORT_TYPE_TX_10G) + && (p_FmPort->portType != e_FM_PORT_TYPE_TX)) + { + REPORT_ERROR(MAJOR, E_INVALID_OPERATION, ("The routine is relevant for Tx ports only")); + return; + } + + p_BmiCfgReg = &p_FmPort->port.bmi_regs->tx.fmbm_tfca; + tmpReg = GET_UINT32(*p_BmiCfgReg) & ~BMI_CMD_ATTR_MACCMD_MASK; + tmpReg |= BMI_CMD_ATTR_MACCMD_SECURED; + tmpReg |= (((uint32_t)dfltSci << BMI_CMD_ATTR_MACCMD_SC_SHIFT) + & BMI_CMD_ATTR_MACCMD_SC_MASK); + + WRITE_UINT32(*p_BmiCfgReg, tmpReg); +} + +uint8_t FmPortGetNetEnvId(t_Handle h_FmPort) +{ + return ((t_FmPort*)h_FmPort)->netEnvId; +} + +uint8_t FmPortGetHardwarePortId(t_Handle h_FmPort) +{ + return ((t_FmPort*)h_FmPort)->hardwarePortId; +} + +uint32_t FmPortGetPcdEngines(t_Handle h_FmPort) +{ + return ((t_FmPort*)h_FmPort)->pcdEngines; +} + +#if (DPAA_VERSION >= 11) +t_Error FmPortSetGprFunc(t_Handle h_FmPort, e_FmPortGprFuncType gprFunc, + void **p_Value) +{ + t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; + uint32_t muramPageOffset; + + ASSERT_COND(p_FmPort); + ASSERT_COND(p_Value); + + if (p_FmPort->gprFunc != e_FM_PORT_GPR_EMPTY) + { + if (p_FmPort->gprFunc != gprFunc) + RETURN_ERROR(MAJOR, E_INVALID_STATE, + ("gpr was assigned with different func")); + } + else + { + switch (gprFunc) + { + case (e_FM_PORT_GPR_MURAM_PAGE): + p_FmPort->p_ParamsPage = FM_MURAM_AllocMem(p_FmPort->h_FmMuram, + 256, 8); + if (!p_FmPort->p_ParamsPage) + RETURN_ERROR(MAJOR, E_NO_MEMORY, ("MURAM alloc for page")); + + IOMemSet32(p_FmPort->p_ParamsPage, 0, 256); + muramPageOffset = + (uint32_t)(XX_VirtToPhys(p_FmPort->p_ParamsPage) + - p_FmPort->fmMuramPhysBaseAddr); + switch (p_FmPort->portType) + { + case (e_FM_PORT_TYPE_RX_10G): + case (e_FM_PORT_TYPE_RX): + WRITE_UINT32( + p_FmPort->p_FmPortBmiRegs->rxPortBmiRegs.fmbm_rgpr, + muramPageOffset); + break; + case (e_FM_PORT_TYPE_OH_OFFLINE_PARSING): + WRITE_UINT32( + p_FmPort->p_FmPortBmiRegs->ohPortBmiRegs.fmbm_ogpr, + muramPageOffset); + break; + default: + RETURN_ERROR(MAJOR, E_INVALID_STATE, + ("Invalid port type")); + } + break; + default: + RETURN_ERROR(MAJOR, E_INVALID_SELECTION, NO_MSG); + } + p_FmPort->gprFunc = gprFunc; + } + + switch (p_FmPort->gprFunc) + { + case (e_FM_PORT_GPR_MURAM_PAGE): + *p_Value = p_FmPort->p_ParamsPage; + break; + default: + RETURN_ERROR(MAJOR, E_INVALID_SELECTION, NO_MSG); + } + + return E_OK; +} +#endif /* (DPAA_VERSION >= 11) */ + +t_Error FmPortGetSetCcParams(t_Handle h_FmPort, + t_FmPortGetSetCcParams *p_CcParams) +{ + t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; + int tmpInt; + volatile uint32_t *p_BmiPrsStartOffset = NULL; + + /* this function called from Cc for pass and receive parameters port params between CC and PORT*/ + + if ((p_CcParams->getCcParams.type & OFFSET_OF_PR) + && (p_FmPort->bufferOffsets.prsResultOffset != ILLEGAL_BASE)) + { + p_CcParams->getCcParams.prOffset = + (uint8_t)p_FmPort->bufferOffsets.prsResultOffset; + p_CcParams->getCcParams.type &= ~OFFSET_OF_PR; + } + if (p_CcParams->getCcParams.type & HW_PORT_ID) + { + p_CcParams->getCcParams.hardwarePortId = + (uint8_t)p_FmPort->hardwarePortId; + p_CcParams->getCcParams.type &= ~HW_PORT_ID; + } + if ((p_CcParams->getCcParams.type & OFFSET_OF_DATA) + && (p_FmPort->bufferOffsets.dataOffset != ILLEGAL_BASE)) + { + p_CcParams->getCcParams.dataOffset = + (uint16_t)p_FmPort->bufferOffsets.dataOffset; + p_CcParams->getCcParams.type &= ~OFFSET_OF_DATA; + } + if (p_CcParams->getCcParams.type & NUM_OF_TASKS) + { + p_CcParams->getCcParams.numOfTasks = (uint8_t)p_FmPort->tasks.num; + p_CcParams->getCcParams.type &= ~NUM_OF_TASKS; + } + if (p_CcParams->getCcParams.type & NUM_OF_EXTRA_TASKS) + { + p_CcParams->getCcParams.numOfExtraTasks = + (uint8_t)p_FmPort->tasks.extra; + p_CcParams->getCcParams.type &= ~NUM_OF_EXTRA_TASKS; + } + if (p_CcParams->getCcParams.type & FM_REV) + { + p_CcParams->getCcParams.revInfo.majorRev = p_FmPort->fmRevInfo.majorRev; + p_CcParams->getCcParams.revInfo.minorRev = p_FmPort->fmRevInfo.minorRev; + p_CcParams->getCcParams.type &= ~FM_REV; + } + if (p_CcParams->getCcParams.type & DISCARD_MASK) + { + if (p_FmPort->portType == e_FM_PORT_TYPE_OH_OFFLINE_PARSING) + p_CcParams->getCcParams.discardMask = + GET_UINT32(p_FmPort->p_FmPortBmiRegs->ohPortBmiRegs.fmbm_ofsdm); + else + p_CcParams->getCcParams.discardMask = + GET_UINT32(p_FmPort->p_FmPortBmiRegs->rxPortBmiRegs.fmbm_rfsdm); + p_CcParams->getCcParams.type &= ~DISCARD_MASK; + } + if (p_CcParams->getCcParams.type & MANIP_EXTRA_SPACE) + { + p_CcParams->getCcParams.internalBufferOffset = + p_FmPort->internalBufferOffset; + p_CcParams->getCcParams.type &= ~MANIP_EXTRA_SPACE; + } + if (p_CcParams->getCcParams.type & GET_NIA_FPNE) + { + if (p_FmPort->portType == e_FM_PORT_TYPE_OH_OFFLINE_PARSING) + p_CcParams->getCcParams.nia = + GET_UINT32(p_FmPort->port.bmi_regs->oh.fmbm_ofpne); + else + p_CcParams->getCcParams.nia = + GET_UINT32(p_FmPort->port.bmi_regs->rx.fmbm_rfpne); + p_CcParams->getCcParams.type &= ~GET_NIA_FPNE; + } + if (p_CcParams->getCcParams.type & GET_NIA_PNDN) + { + if (p_FmPort->portType != e_FM_PORT_TYPE_OH_OFFLINE_PARSING) + RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Invalid port type")); + p_CcParams->getCcParams.nia = + GET_UINT32(p_FmPort->p_FmPortQmiRegs->nonRxQmiRegs.fmqm_pndn); + p_CcParams->getCcParams.type &= ~GET_NIA_PNDN; + } + + if ((p_CcParams->setCcParams.type & UPDATE_FMFP_PRC_WITH_ONE_RISC_ONLY) + && !(p_FmPort->requiredAction & UPDATE_FMFP_PRC_WITH_ONE_RISC_ONLY)) + { + p_FmPort->requiredAction |= UPDATE_FMFP_PRC_WITH_ONE_RISC_ONLY; + p_FmPort->orFmanCtrl = p_CcParams->setCcParams.orFmanCtrl; + } + + if ((p_CcParams->setCcParams.type & UPDATE_NIA_PNEN) + && !(p_FmPort->requiredAction & UPDATE_NIA_PNEN)) + { + p_FmPort->savedQmiPnen = p_CcParams->setCcParams.nia; + p_FmPort->requiredAction |= UPDATE_NIA_PNEN; + } + else + if (p_CcParams->setCcParams.type & UPDATE_NIA_PNEN) + { + if (p_FmPort->savedQmiPnen != p_CcParams->setCcParams.nia) + RETURN_ERROR(MAJOR, E_INVALID_STATE, + ("PNEN was defined previously different")); + } + + if ((p_CcParams->setCcParams.type & UPDATE_NIA_PNDN) + && !(p_FmPort->requiredAction & UPDATE_NIA_PNDN)) + { + p_FmPort->savedNonRxQmiRegsPndn = p_CcParams->setCcParams.nia; + p_FmPort->requiredAction |= UPDATE_NIA_PNDN; + } + else + if (p_CcParams->setCcParams.type & UPDATE_NIA_PNDN) + { + if (p_FmPort->savedNonRxQmiRegsPndn != p_CcParams->setCcParams.nia) + RETURN_ERROR(MAJOR, E_INVALID_STATE, + ("PNDN was defined previously different")); + } + + if ((p_CcParams->setCcParams.type & UPDATE_NIA_FENE) + && (p_CcParams->setCcParams.overwrite + || !(p_FmPort->requiredAction & UPDATE_NIA_FENE))) + { + p_FmPort->savedBmiFene = p_CcParams->setCcParams.nia; + p_FmPort->requiredAction |= UPDATE_NIA_FENE; + } + else + if (p_CcParams->setCcParams.type & UPDATE_NIA_FENE) + { + if (p_FmPort->savedBmiFene != p_CcParams->setCcParams.nia) + RETURN_ERROR( MAJOR, E_INVALID_STATE, + ("xFENE was defined previously different")); + } + + if ((p_CcParams->setCcParams.type & UPDATE_NIA_FPNE) + && !(p_FmPort->requiredAction & UPDATE_NIA_FPNE)) + { + p_FmPort->savedBmiFpne = p_CcParams->setCcParams.nia; + p_FmPort->requiredAction |= UPDATE_NIA_FPNE; + } + else + if (p_CcParams->setCcParams.type & UPDATE_NIA_FPNE) + { + if (p_FmPort->savedBmiFpne != p_CcParams->setCcParams.nia) + RETURN_ERROR( MAJOR, E_INVALID_STATE, + ("xFPNE was defined previously different")); + } + + if ((p_CcParams->setCcParams.type & UPDATE_NIA_CMNE) + && !(p_FmPort->requiredAction & UPDATE_NIA_CMNE)) + { + p_FmPort->savedBmiCmne = p_CcParams->setCcParams.nia; + p_FmPort->requiredAction |= UPDATE_NIA_CMNE; + } + else + if (p_CcParams->setCcParams.type & UPDATE_NIA_CMNE) + { + if (p_FmPort->savedBmiCmne != p_CcParams->setCcParams.nia) + RETURN_ERROR( MAJOR, E_INVALID_STATE, + ("xCMNE was defined previously different")); + } + + if ((p_CcParams->setCcParams.type & UPDATE_PSO) + && !(p_FmPort->requiredAction & UPDATE_PSO)) + { + /* get PCD registers pointers */ + switch (p_FmPort->portType) + { + case (e_FM_PORT_TYPE_RX_10G): + case (e_FM_PORT_TYPE_RX): + p_BmiPrsStartOffset = &p_FmPort->port.bmi_regs->rx.fmbm_rpso; + break; + case (e_FM_PORT_TYPE_OH_OFFLINE_PARSING): + p_BmiPrsStartOffset = &p_FmPort->port.bmi_regs->oh.fmbm_opso; + break; + default: + RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Invalid port type")); + } + + /* set start parsing offset */ + tmpInt = (int)GET_UINT32(*p_BmiPrsStartOffset) + + p_CcParams->setCcParams.psoSize; + if (tmpInt > 0) + WRITE_UINT32(*p_BmiPrsStartOffset, (uint32_t)tmpInt); + + p_FmPort->requiredAction |= UPDATE_PSO; + p_FmPort->savedPrsStartOffset = p_CcParams->setCcParams.psoSize; + } + else + if (p_CcParams->setCcParams.type & UPDATE_PSO) + { + if (p_FmPort->savedPrsStartOffset + != p_CcParams->setCcParams.psoSize) + RETURN_ERROR( + MAJOR, + E_INVALID_STATE, + ("parser start offset was defoned previousley different")); + } + + if ((p_CcParams->setCcParams.type & UPDATE_OFP_DPTE) + && !(p_FmPort->requiredAction & UPDATE_OFP_DPTE)) + { + if (p_FmPort->portType != e_FM_PORT_TYPE_OH_OFFLINE_PARSING) + RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Invalid port type")); + p_FmPort->savedBmiOfp = GET_UINT32(p_FmPort->port.bmi_regs->oh.fmbm_ofp); + p_FmPort->savedBmiOfp &= ~BMI_FIFO_PIPELINE_DEPTH_MASK; + p_FmPort->savedBmiOfp |= p_CcParams->setCcParams.ofpDpde + << BMI_FIFO_PIPELINE_DEPTH_SHIFT; + p_FmPort->requiredAction |= UPDATE_OFP_DPTE; + } + + return E_OK; +} +/*********************** End of inter-module routines ************************/ + +/****************************************/ +/* API Init unit functions */ +/****************************************/ + +t_Handle FM_PORT_Config(t_FmPortParams *p_FmPortParams) +{ + t_FmPort *p_FmPort; + uintptr_t baseAddr = p_FmPortParams->baseAddr; + uint32_t tmpReg; + + /* Allocate FM structure */ + p_FmPort = (t_FmPort *)XX_Malloc(sizeof(t_FmPort)); + if (!p_FmPort) + { + REPORT_ERROR(MAJOR, E_NO_MEMORY, ("FM Port driver structure")); + return NULL; + } + memset(p_FmPort, 0, sizeof(t_FmPort)); + + /* Allocate the FM driver's parameters structure */ + p_FmPort->p_FmPortDriverParam = (t_FmPortDriverParam *)XX_Malloc( + sizeof(t_FmPortDriverParam)); + if (!p_FmPort->p_FmPortDriverParam) + { + XX_Free(p_FmPort); + REPORT_ERROR(MAJOR, E_NO_MEMORY, ("FM Port driver parameters")); + return NULL; + } + memset(p_FmPort->p_FmPortDriverParam, 0, sizeof(t_FmPortDriverParam)); + + /* Initialize FM port parameters which will be kept by the driver */ + p_FmPort->portType = p_FmPortParams->portType; + p_FmPort->portId = p_FmPortParams->portId; + p_FmPort->pcdEngines = FM_PCD_NONE; + p_FmPort->f_Exception = p_FmPortParams->f_Exception; + p_FmPort->h_App = p_FmPortParams->h_App; + p_FmPort->h_Fm = p_FmPortParams->h_Fm; + + /* get FM revision */ + FM_GetRevision(p_FmPort->h_Fm, &p_FmPort->fmRevInfo); + + /* calculate global portId number */ + p_FmPort->hardwarePortId = SwPortIdToHwPortId(p_FmPort->portType, + p_FmPortParams->portId, + p_FmPort->fmRevInfo.majorRev, + p_FmPort->fmRevInfo.minorRev); + + if (p_FmPort->fmRevInfo.majorRev >= 6) + { + if ((p_FmPort->portType == e_FM_PORT_TYPE_OH_HOST_COMMAND) + && (p_FmPortParams->portId != FM_OH_PORT_ID)) + DBG(WARNING, + ("Port ID %d is recommended for HC port. Overwriting HW defaults to be suitable for HC.", + FM_OH_PORT_ID)); + + if ((p_FmPort->portType == e_FM_PORT_TYPE_OH_OFFLINE_PARSING) + && (p_FmPortParams->portId == FM_OH_PORT_ID)) + DBG(WARNING, ("Use non-zero portId for OP port due to insufficient resources on portId 0.")); + } + + /* Set up FM port parameters for initialization phase only */ + + /* First, fill in flibs struct */ + fman_port_defconfig(&p_FmPort->p_FmPortDriverParam->dfltCfg, + (enum fman_port_type)p_FmPort->portType); + /* Overwrite some integration specific parameters */ + p_FmPort->p_FmPortDriverParam->dfltCfg.rx_pri_elevation = + DEFAULT_PORT_rxFifoPriElevationLevel; + p_FmPort->p_FmPortDriverParam->dfltCfg.rx_fifo_thr = + DEFAULT_PORT_rxFifoThreshold; + +#if defined(FM_OP_NO_VSP_NO_RELEASE_ERRATA_FMAN_A006675) || defined(FM_ERROR_VSP_NO_MATCH_SW006) + p_FmPort->p_FmPortDriverParam->dfltCfg.errata_A006675 = TRUE; +#else + p_FmPort->p_FmPortDriverParam->dfltCfg.errata_A006675 = FALSE; +#endif + if ((p_FmPort->fmRevInfo.majorRev == 6) + && (p_FmPort->fmRevInfo.minorRev == 0)) + p_FmPort->p_FmPortDriverParam->dfltCfg.errata_A006320 = TRUE; + else + p_FmPort->p_FmPortDriverParam->dfltCfg.errata_A006320 = FALSE; + + /* Excessive Threshold register - exists for pre-FMv3 chips only */ + if (p_FmPort->fmRevInfo.majorRev < 6) + { +#ifdef FM_NO_RESTRICT_ON_ACCESS_RSRC + p_FmPort->p_FmPortDriverParam->dfltCfg.excessive_threshold_register = + TRUE; +#endif + p_FmPort->p_FmPortDriverParam->dfltCfg.fmbm_rebm_has_sgd = FALSE; + p_FmPort->p_FmPortDriverParam->dfltCfg.fmbm_tfne_has_features = FALSE; + } + else + { + p_FmPort->p_FmPortDriverParam->dfltCfg.excessive_threshold_register = + FALSE; + p_FmPort->p_FmPortDriverParam->dfltCfg.fmbm_rebm_has_sgd = TRUE; + p_FmPort->p_FmPortDriverParam->dfltCfg.fmbm_tfne_has_features = TRUE; + } + if (p_FmPort->fmRevInfo.majorRev == 4) + p_FmPort->p_FmPortDriverParam->dfltCfg.qmi_deq_options_support = FALSE; + else + p_FmPort->p_FmPortDriverParam->dfltCfg.qmi_deq_options_support = TRUE; + + /* Continue with other parameters */ + p_FmPort->p_FmPortDriverParam->baseAddr = baseAddr; + /* set memory map pointers */ + p_FmPort->p_FmPortQmiRegs = + (t_FmPortQmiRegs *)UINT_TO_PTR(baseAddr + QMI_PORT_REGS_OFFSET); + p_FmPort->p_FmPortBmiRegs = + (u_FmPortBmiRegs *)UINT_TO_PTR(baseAddr + BMI_PORT_REGS_OFFSET); + p_FmPort->p_FmPortPrsRegs = + (t_FmPortPrsRegs *)UINT_TO_PTR(baseAddr + PRS_PORT_REGS_OFFSET); + + p_FmPort->p_FmPortDriverParam->bufferPrefixContent.privDataSize = + DEFAULT_PORT_bufferPrefixContent_privDataSize; + p_FmPort->p_FmPortDriverParam->bufferPrefixContent.passPrsResult = + DEFAULT_PORT_bufferPrefixContent_passPrsResult; + p_FmPort->p_FmPortDriverParam->bufferPrefixContent.passTimeStamp = + DEFAULT_PORT_bufferPrefixContent_passTimeStamp; + p_FmPort->p_FmPortDriverParam->bufferPrefixContent.passAllOtherPCDInfo = + DEFAULT_PORT_bufferPrefixContent_passTimeStamp; + p_FmPort->p_FmPortDriverParam->bufferPrefixContent.dataAlign = + DEFAULT_PORT_bufferPrefixContent_dataAlign; + /* p_FmPort->p_FmPortDriverParam->dmaSwapData = (e_FmDmaSwapOption)DEFAULT_PORT_dmaSwapData; + p_FmPort->p_FmPortDriverParam->dmaIntContextCacheAttr = (e_FmDmaCacheOption)DEFAULT_PORT_dmaIntContextCacheAttr; + p_FmPort->p_FmPortDriverParam->dmaHeaderCacheAttr = (e_FmDmaCacheOption)DEFAULT_PORT_dmaHeaderCacheAttr; + p_FmPort->p_FmPortDriverParam->dmaScatterGatherCacheAttr = (e_FmDmaCacheOption)DEFAULT_PORT_dmaScatterGatherCacheAttr; + p_FmPort->p_FmPortDriverParam->dmaWriteOptimize = DEFAULT_PORT_dmaWriteOptimize; + */ + p_FmPort->p_FmPortDriverParam->liodnBase = p_FmPortParams->liodnBase; + p_FmPort->p_FmPortDriverParam->cheksumLastBytesIgnore = + DEFAULT_PORT_cheksumLastBytesIgnore; + + p_FmPort->maxFrameLength = DEFAULT_PORT_maxFrameLength; + /* resource distribution. */ + p_FmPort->fifoBufs.num = DEFAULT_PORT_numOfFifoBufs(p_FmPort->portType) + * BMI_FIFO_UNITS; + p_FmPort->fifoBufs.extra = DEFAULT_PORT_extraNumOfFifoBufs + * BMI_FIFO_UNITS; + p_FmPort->openDmas.num = DEFAULT_PORT_numOfOpenDmas(p_FmPort->portType); + p_FmPort->openDmas.extra = + DEFAULT_PORT_extraNumOfOpenDmas(p_FmPort->portType); + p_FmPort->tasks.num = DEFAULT_PORT_numOfTasks(p_FmPort->portType); + p_FmPort->tasks.extra = DEFAULT_PORT_extraNumOfTasks(p_FmPort->portType); + + +#ifdef FM_HEAVY_TRAFFIC_SEQUENCER_HANG_ERRATA_FMAN_A006981 + if ((p_FmPort->fmRevInfo.majorRev == 6) + && (p_FmPort->fmRevInfo.minorRev == 0) + && ((p_FmPort->portType == e_FM_PORT_TYPE_OH_OFFLINE_PARSING) + || (p_FmPort->portType == e_FM_PORT_TYPE_TX))) + { + p_FmPort->openDmas.num = 16; + p_FmPort->openDmas.extra = 0; + } +#endif /* FM_HEAVY_TRAFFIC_SEQUENCER_HANG_ERRATA_FMAN_A006981 */ + + /* Port type specific initialization: */ + switch (p_FmPort->portType) + { + case (e_FM_PORT_TYPE_RX): + case (e_FM_PORT_TYPE_RX_10G): + /* Initialize FM port parameters for initialization phase only */ + p_FmPort->p_FmPortDriverParam->cutBytesFromEnd = + DEFAULT_PORT_cutBytesFromEnd; + p_FmPort->p_FmPortDriverParam->enBufPoolDepletion = FALSE; + p_FmPort->p_FmPortDriverParam->frmDiscardOverride = + DEFAULT_PORT_frmDiscardOverride; + + tmpReg = + GET_UINT32(p_FmPort->p_FmPortBmiRegs->rxPortBmiRegs.fmbm_rfp); + p_FmPort->p_FmPortDriverParam->rxFifoPriElevationLevel = + (((tmpReg & BMI_RX_FIFO_PRI_ELEVATION_MASK) + >> BMI_RX_FIFO_PRI_ELEVATION_SHIFT) + 1) + * BMI_FIFO_UNITS; + p_FmPort->p_FmPortDriverParam->rxFifoThreshold = (((tmpReg + & BMI_RX_FIFO_THRESHOLD_MASK) + >> BMI_RX_FIFO_THRESHOLD_SHIFT) + 1) * BMI_FIFO_UNITS; + + p_FmPort->p_FmPortDriverParam->bufMargins.endMargins = + DEFAULT_PORT_BufMargins_endMargins; + p_FmPort->p_FmPortDriverParam->errorsToDiscard = + DEFAULT_PORT_errorsToDiscard; + p_FmPort->p_FmPortDriverParam->forwardReuseIntContext = + DEFAULT_PORT_forwardIntContextReuse; +#if (DPAA_VERSION >= 11) + p_FmPort->p_FmPortDriverParam->noScatherGather = + DEFAULT_PORT_noScatherGather; +#endif /* (DPAA_VERSION >= 11) */ + break; + + case (e_FM_PORT_TYPE_TX): + p_FmPort->p_FmPortDriverParam->dontReleaseBuf = FALSE; +#ifdef FM_WRONG_RESET_VALUES_ERRATA_FMAN_A005127 + tmpReg = 0x00001013; + WRITE_UINT32( p_FmPort->p_FmPortBmiRegs->txPortBmiRegs.fmbm_tfp, + tmpReg); +#endif /* FM_WRONG_RESET_VALUES_ERRATA_FMAN_A005127 */ + case (e_FM_PORT_TYPE_TX_10G): + tmpReg = + GET_UINT32(p_FmPort->p_FmPortBmiRegs->txPortBmiRegs.fmbm_tfp); + p_FmPort->p_FmPortDriverParam->txFifoMinFillLevel = ((tmpReg + & BMI_TX_FIFO_MIN_FILL_MASK) + >> BMI_TX_FIFO_MIN_FILL_SHIFT) * BMI_FIFO_UNITS; + p_FmPort->p_FmPortDriverParam->dfltCfg.tx_fifo_deq_pipeline_depth = + (uint8_t)(((tmpReg & BMI_FIFO_PIPELINE_DEPTH_MASK) + >> BMI_FIFO_PIPELINE_DEPTH_SHIFT) + 1); + p_FmPort->p_FmPortDriverParam->txFifoLowComfLevel = (((tmpReg + & BMI_TX_LOW_COMF_MASK) >> BMI_TX_LOW_COMF_SHIFT) + 1) + * BMI_FIFO_UNITS; + + p_FmPort->p_FmPortDriverParam->deqType = DEFAULT_PORT_deqType; + p_FmPort->p_FmPortDriverParam->deqPrefetchOption = + DEFAULT_PORT_deqPrefetchOption; + p_FmPort->p_FmPortDriverParam->deqHighPriority = + (bool)((p_FmPort->portType == e_FM_PORT_TYPE_TX) ? DEFAULT_PORT_deqHighPriority_1G : + DEFAULT_PORT_deqHighPriority_10G); + p_FmPort->p_FmPortDriverParam->deqByteCnt = + (uint16_t)( + (p_FmPort->portType == e_FM_PORT_TYPE_TX) ? DEFAULT_PORT_deqByteCnt_1G : + DEFAULT_PORT_deqByteCnt_10G); + break; + case (e_FM_PORT_TYPE_OH_OFFLINE_PARSING): + p_FmPort->p_FmPortDriverParam->errorsToDiscard = + DEFAULT_PORT_errorsToDiscard; +#if (DPAA_VERSION >= 11) + p_FmPort->p_FmPortDriverParam->noScatherGather = + DEFAULT_PORT_noScatherGather; +#endif /* (DPAA_VERSION >= 11) */ + case (e_FM_PORT_TYPE_OH_HOST_COMMAND): + p_FmPort->p_FmPortDriverParam->deqPrefetchOption = + DEFAULT_PORT_deqPrefetchOption_HC; + p_FmPort->p_FmPortDriverParam->deqHighPriority = + DEFAULT_PORT_deqHighPriority_1G; + p_FmPort->p_FmPortDriverParam->deqType = DEFAULT_PORT_deqType; + p_FmPort->p_FmPortDriverParam->deqByteCnt = + DEFAULT_PORT_deqByteCnt_1G; + + tmpReg = + GET_UINT32(p_FmPort->p_FmPortBmiRegs->ohPortBmiRegs.fmbm_ofp); + p_FmPort->p_FmPortDriverParam->dfltCfg.tx_fifo_deq_pipeline_depth = + (uint8_t)(((tmpReg & BMI_FIFO_PIPELINE_DEPTH_MASK) + >> BMI_FIFO_PIPELINE_DEPTH_SHIFT) + 1); + if ((p_FmPort->portType == e_FM_PORT_TYPE_OH_HOST_COMMAND) + && (p_FmPortParams->portId != FM_OH_PORT_ID)) + { + /* Overwrite HC defaults */ + p_FmPort->p_FmPortDriverParam->dfltCfg.tx_fifo_deq_pipeline_depth = + DEFAULT_PORT_fifoDeqPipelineDepth_OH; + } + +#ifndef FM_FRAME_END_PARAMS_FOR_OP + if (p_FmPort->fmRevInfo.majorRev < 6) + p_FmPort->p_FmPortDriverParam->cheksumLastBytesIgnore = DEFAULT_notSupported; +#endif /* !FM_FRAME_END_PARAMS_FOR_OP */ + +#ifndef FM_DEQ_PIPELINE_PARAMS_FOR_OP + if (!((p_FmPort->fmRevInfo.majorRev == 4) || + (p_FmPort->fmRevInfo.majorRev >= 6))) + p_FmPort->p_FmPortDriverParam->dfltCfg.tx_fifo_deq_pipeline_depth = DEFAULT_notSupported; +#endif /* !FM_DEQ_PIPELINE_PARAMS_FOR_OP */ + break; + + default: + XX_Free(p_FmPort->p_FmPortDriverParam); + XX_Free(p_FmPort); + REPORT_ERROR(MAJOR, E_INVALID_STATE, ("Invalid port type")); + return NULL; + } +#ifdef FM_QMI_NO_DEQ_OPTIONS_SUPPORT + if (p_FmPort->fmRevInfo.majorRev == 4) + p_FmPort->p_FmPortDriverParam->deqPrefetchOption = (e_FmPortDeqPrefetchOption)DEFAULT_notSupported; +#endif /* FM_QMI_NO_DEQ_OPTIONS_SUPPORT */ + + p_FmPort->imEn = p_FmPortParams->independentModeEnable; + + if (p_FmPort->imEn) + { + if ((p_FmPort->portType == e_FM_PORT_TYPE_TX) + || (p_FmPort->portType == e_FM_PORT_TYPE_TX_10G)) + p_FmPort->p_FmPortDriverParam->dfltCfg.tx_fifo_deq_pipeline_depth = + DEFAULT_PORT_fifoDeqPipelineDepth_IM; + FmPortConfigIM(p_FmPort, p_FmPortParams); + } + else + { + switch (p_FmPort->portType) + { + case (e_FM_PORT_TYPE_RX): + case (e_FM_PORT_TYPE_RX_10G): + /* Initialize FM port parameters for initialization phase only */ + memcpy(&p_FmPort->p_FmPortDriverParam->extBufPools, + &p_FmPortParams->specificParams.rxParams.extBufPools, + sizeof(t_FmExtPools)); + p_FmPort->p_FmPortDriverParam->errFqid = + p_FmPortParams->specificParams.rxParams.errFqid; + p_FmPort->p_FmPortDriverParam->dfltFqid = + p_FmPortParams->specificParams.rxParams.dfltFqid; + p_FmPort->p_FmPortDriverParam->liodnOffset = + p_FmPortParams->specificParams.rxParams.liodnOffset; + break; + case (e_FM_PORT_TYPE_OH_OFFLINE_PARSING): + case (e_FM_PORT_TYPE_TX): + case (e_FM_PORT_TYPE_TX_10G): + case (e_FM_PORT_TYPE_OH_HOST_COMMAND): + p_FmPort->p_FmPortDriverParam->errFqid = + p_FmPortParams->specificParams.nonRxParams.errFqid; + p_FmPort->p_FmPortDriverParam->deqSubPortal = + (uint8_t)(p_FmPortParams->specificParams.nonRxParams.qmChannel + & QMI_DEQ_CFG_SUBPORTAL_MASK); + p_FmPort->p_FmPortDriverParam->dfltFqid = + p_FmPortParams->specificParams.nonRxParams.dfltFqid; + break; + default: + XX_Free(p_FmPort->p_FmPortDriverParam); + XX_Free(p_FmPort); + REPORT_ERROR(MAJOR, E_INVALID_STATE, ("Invalid port type")); + return NULL; + } + } + + memset(p_FmPort->name, 0, (sizeof(char)) * MODULE_NAME_SIZE); + if (Sprint( + p_FmPort->name, + "FM-%d-port-%s-%d", + FmGetId(p_FmPort->h_Fm), + ((p_FmPort->portType == e_FM_PORT_TYPE_OH_OFFLINE_PARSING + || (p_FmPort->portType == e_FM_PORT_TYPE_OH_HOST_COMMAND)) ? "OH" : + (p_FmPort->portType == e_FM_PORT_TYPE_RX ? "1g-RX" : + (p_FmPort->portType == e_FM_PORT_TYPE_TX ? "1g-TX" : + (p_FmPort->portType + == e_FM_PORT_TYPE_RX_10G ? "10g-RX" : + "10g-TX")))), + p_FmPort->portId) == 0) + { + XX_Free(p_FmPort->p_FmPortDriverParam); + XX_Free(p_FmPort); + REPORT_ERROR(MAJOR, E_INVALID_STATE, ("Sprint failed")); + return NULL; + } + + p_FmPort->h_Spinlock = XX_InitSpinlock(); + if (!p_FmPort->h_Spinlock) + { + XX_Free(p_FmPort->p_FmPortDriverParam); + XX_Free(p_FmPort); + REPORT_ERROR(MAJOR, E_INVALID_STATE, ("Sprint failed")); + return NULL; + } + + return p_FmPort; +} + +t_FmPort *rx_port = 0; +t_FmPort *tx_port = 0; + +/**************************************************************************//** + @Function FM_PORT_Init + + @Description Initializes the FM module + + @Param[in] h_FmPort - FM module descriptor + + @Return E_OK on success; Error code otherwise. + *//***************************************************************************/ +t_Error FM_PORT_Init(t_Handle h_FmPort) +{ + t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; + t_FmPortDriverParam *p_DriverParams; + t_Error errCode; + t_FmInterModulePortInitParams fmParams; + t_FmRevisionInfo revInfo; + + SANITY_CHECK_RETURN_ERROR(h_FmPort, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_FmPort->p_FmPortDriverParam, E_INVALID_HANDLE); + + errCode = FmSpBuildBufferStructure( + &p_FmPort->p_FmPortDriverParam->intContext, + &p_FmPort->p_FmPortDriverParam->bufferPrefixContent, + &p_FmPort->p_FmPortDriverParam->bufMargins, + &p_FmPort->bufferOffsets, &p_FmPort->internalBufferOffset); + if (errCode != E_OK) + RETURN_ERROR(MAJOR, errCode, NO_MSG); +#ifdef FM_HEAVY_TRAFFIC_HANG_ERRATA_FMAN_A005669 + if ((p_FmPort->p_FmPortDriverParam->bcbWorkaround) && + (p_FmPort->portType == e_FM_PORT_TYPE_RX)) + { + p_FmPort->p_FmPortDriverParam->errorsToDiscard |= FM_PORT_FRM_ERR_PHYSICAL; + if (!p_FmPort->fifoBufs.num) + p_FmPort->fifoBufs.num = DEFAULT_PORT_numOfFifoBufs(p_FmPort->portType)*BMI_FIFO_UNITS; + p_FmPort->fifoBufs.num += 4*KILOBYTE; + } +#endif /* FM_HEAVY_TRAFFIC_HANG_ERRATA_FMAN_A005669 */ + + CHECK_INIT_PARAMETERS(p_FmPort, CheckInitParameters); + + p_DriverParams = p_FmPort->p_FmPortDriverParam; + + /* Set up flibs port structure */ + memset(&p_FmPort->port, 0, sizeof(struct fman_port)); + p_FmPort->port.type = (enum fman_port_type)p_FmPort->portType; + FM_GetRevision(p_FmPort->h_Fm, &revInfo); + p_FmPort->port.fm_rev_maj = revInfo.majorRev; + p_FmPort->port.fm_rev_min = revInfo.minorRev; + p_FmPort->port.bmi_regs = + (union fman_port_bmi_regs *)UINT_TO_PTR(p_DriverParams->baseAddr + BMI_PORT_REGS_OFFSET); + p_FmPort->port.qmi_regs = + (struct fman_port_qmi_regs *)UINT_TO_PTR(p_DriverParams->baseAddr + QMI_PORT_REGS_OFFSET); + p_FmPort->port.ext_pools_num = (uint8_t)((revInfo.majorRev == 4) ? 4 : 8); + p_FmPort->port.im_en = p_FmPort->imEn; + p_FmPort->p_FmPortPrsRegs = + (t_FmPortPrsRegs *)UINT_TO_PTR(p_DriverParams->baseAddr + PRS_PORT_REGS_OFFSET); + + if (((p_FmPort->portType == e_FM_PORT_TYPE_RX_10G) + || (p_FmPort->portType == e_FM_PORT_TYPE_RX)) && !p_FmPort->imEn) + { + /* Call the external Buffer routine which also checks fifo + size and updates it if necessary */ + /* define external buffer pools and pool depletion*/ + errCode = SetExtBufferPools(p_FmPort); + if (errCode) + RETURN_ERROR(MAJOR, errCode, NO_MSG); + /* check if the largest external buffer pool is large enough */ + if (p_DriverParams->bufMargins.startMargins + MIN_EXT_BUF_SIZE + + p_DriverParams->bufMargins.endMargins + > p_FmPort->rxPoolsParams.largestBufSize) + RETURN_ERROR( + MAJOR, + E_INVALID_VALUE, + ("bufMargins.startMargins (%d) + minimum buf size (64) + bufMargins.endMargins (%d) is larger than maximum external buffer size (%d)", p_DriverParams->bufMargins.startMargins, p_DriverParams->bufMargins.endMargins, p_FmPort->rxPoolsParams.largestBufSize)); + } + if (p_FmPort->portType == e_FM_PORT_TYPE_OH_OFFLINE_PARSING) + { + { +#ifdef FM_NO_OP_OBSERVED_POOLS + t_FmRevisionInfo revInfo; + + FM_GetRevision(p_FmPort->h_Fm, &revInfo); + if ((revInfo.majorRev == 4) && (p_DriverParams->enBufPoolDepletion)) +#endif /* FM_NO_OP_OBSERVED_POOLS */ + { + /* define external buffer pools */ + errCode = SetExtBufferPools(p_FmPort); + if (errCode) + RETURN_ERROR(MAJOR, errCode, NO_MSG); + } + } + } + + /************************************************************/ + /* Call FM module routine for communicating parameters */ + /************************************************************/ + memset(&fmParams, 0, sizeof(fmParams)); + fmParams.hardwarePortId = p_FmPort->hardwarePortId; + fmParams.portType = (e_FmPortType)p_FmPort->portType; + fmParams.numOfTasks = (uint8_t)p_FmPort->tasks.num; + fmParams.numOfExtraTasks = (uint8_t)p_FmPort->tasks.extra; + fmParams.numOfOpenDmas = (uint8_t)p_FmPort->openDmas.num; + fmParams.numOfExtraOpenDmas = (uint8_t)p_FmPort->openDmas.extra; + + if (p_FmPort->fifoBufs.num) + { + errCode = VerifySizeOfFifo(p_FmPort); + if (errCode != E_OK) + RETURN_ERROR(MAJOR, errCode, NO_MSG); + } + fmParams.sizeOfFifo = p_FmPort->fifoBufs.num; + fmParams.extraSizeOfFifo = p_FmPort->fifoBufs.extra; + fmParams.independentMode = p_FmPort->imEn; + fmParams.liodnOffset = p_DriverParams->liodnOffset; + fmParams.liodnBase = p_DriverParams->liodnBase; + fmParams.deqPipelineDepth = + p_FmPort->p_FmPortDriverParam->dfltCfg.tx_fifo_deq_pipeline_depth; + fmParams.maxFrameLength = p_FmPort->maxFrameLength; +#ifndef FM_DEQ_PIPELINE_PARAMS_FOR_OP + if ((p_FmPort->portType == e_FM_PORT_TYPE_OH_OFFLINE_PARSING) || + (p_FmPort->portType == e_FM_PORT_TYPE_OH_HOST_COMMAND)) + { + if (!((p_FmPort->fmRevInfo.majorRev == 4) || + (p_FmPort->fmRevInfo.majorRev >= 6))) + /* HC ports do not have fifoDeqPipelineDepth, but it is needed only + * for deq threshold calculation. + */ + fmParams.deqPipelineDepth = 2; + } +#endif /* !FM_DEQ_PIPELINE_PARAMS_FOR_OP */ + + errCode = FmGetSetPortParams(p_FmPort->h_Fm, &fmParams); + if (errCode) + RETURN_ERROR(MAJOR, errCode, NO_MSG); + + /* get params for use in init */ + p_FmPort->fmMuramPhysBaseAddr = + (uint64_t)((uint64_t)(fmParams.fmMuramPhysBaseAddr.low) + | ((uint64_t)(fmParams.fmMuramPhysBaseAddr.high) << 32)); + p_FmPort->h_FmMuram = FmGetMuramHandle(p_FmPort->h_Fm); + + errCode = InitLowLevelDriver(p_FmPort); + if (errCode != E_OK) + RETURN_ERROR(MAJOR, errCode, NO_MSG); + + FmPortDriverParamFree(p_FmPort); + +#if (DPAA_VERSION >= 11) + if ((p_FmPort->portType == e_FM_PORT_TYPE_RX_10G) + || (p_FmPort->portType == e_FM_PORT_TYPE_RX) + || (p_FmPort->portType == e_FM_PORT_TYPE_OH_OFFLINE_PARSING)) + { + t_FmPcdCtrlParamsPage *p_ParamsPage; + + FmPortSetGprFunc(p_FmPort, e_FM_PORT_GPR_MURAM_PAGE, + (void**)&p_ParamsPage); + ASSERT_COND(p_ParamsPage); + + WRITE_UINT32(p_ParamsPage->misc, FM_CTL_PARAMS_PAGE_ALWAYS_ON); +#ifdef FM_OP_NO_VSP_NO_RELEASE_ERRATA_FMAN_A006675 + if (p_FmPort->portType == e_FM_PORT_TYPE_OH_OFFLINE_PARSING) + { + WRITE_UINT32( + p_ParamsPage->misc, + (GET_UINT32(p_ParamsPage->misc) | FM_CTL_PARAMS_PAGE_OP_FIX_EN)); + WRITE_UINT32( + p_ParamsPage->discardMask, + GET_UINT32(p_FmPort->p_FmPortBmiRegs->ohPortBmiRegs.fmbm_ofsdm)); + } +#endif /* FM_OP_NO_VSP_NO_RELEASE_ERRATA_FMAN_A006675 */ +#ifdef FM_ERROR_VSP_NO_MATCH_SW006 + if (p_FmPort->portType == e_FM_PORT_TYPE_OH_OFFLINE_PARSING) + WRITE_UINT32( + p_ParamsPage->errorsDiscardMask, + (GET_UINT32(p_FmPort->p_FmPortBmiRegs->ohPortBmiRegs.fmbm_ofsdm) | GET_UINT32(p_FmPort->p_FmPortBmiRegs->ohPortBmiRegs.fmbm_ofsem))); + else + WRITE_UINT32( + p_ParamsPage->errorsDiscardMask, + (GET_UINT32(p_FmPort->p_FmPortBmiRegs->rxPortBmiRegs.fmbm_rfsdm) | GET_UINT32(p_FmPort->p_FmPortBmiRegs->rxPortBmiRegs.fmbm_rfsem))); +#endif /* FM_ERROR_VSP_NO_MATCH_SW006 */ + } +#endif /* (DPAA_VERSION >= 11) */ + + if (p_FmPort->deepSleepVars.autoResMaxSizes) + FmPortConfigAutoResForDeepSleepSupport1(p_FmPort); + return E_OK; +} + +/**************************************************************************//** + @Function FM_PORT_Free + + @Description Frees all resources that were assigned to FM module. + + Calling this routine invalidates the descriptor. + + @Param[in] h_FmPort - FM module descriptor + + @Return E_OK on success; Error code otherwise. + *//***************************************************************************/ +t_Error FM_PORT_Free(t_Handle h_FmPort) +{ + t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; + t_FmInterModulePortFreeParams fmParams; + + SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE); + + if (p_FmPort->pcdEngines) + RETURN_ERROR( + MAJOR, + E_INVALID_STATE, + ("Trying to free a port with PCD. FM_PORT_DeletePCD must be called first.")); + + if (p_FmPort->enabled) + { + if (FM_PORT_Disable(p_FmPort) != E_OK) + RETURN_ERROR(MAJOR, E_INVALID_STATE, ("FM_PORT_Disable FAILED")); + } + + if (p_FmPort->imEn) + FmPortImFree(p_FmPort); + + FmPortDriverParamFree(p_FmPort); + + memset(&fmParams, 0, sizeof(fmParams)); + fmParams.hardwarePortId = p_FmPort->hardwarePortId; + fmParams.portType = (e_FmPortType)p_FmPort->portType; + fmParams.deqPipelineDepth = + p_FmPort->p_FmPortDriverParam->dfltCfg.tx_fifo_deq_pipeline_depth; + + FmFreePortParams(p_FmPort->h_Fm, &fmParams); + +#if (DPAA_VERSION >= 11) + if (FmVSPFreeForPort(p_FmPort->h_Fm, p_FmPort->portType, p_FmPort->portId) + != E_OK) + RETURN_ERROR(MAJOR, E_INVALID_STATE, ("VSP free of port FAILED")); + + if (p_FmPort->p_ParamsPage) + FM_MURAM_FreeMem(p_FmPort->h_FmMuram, p_FmPort->p_ParamsPage); +#endif /* (DPAA_VERSION >= 11) */ + + if (p_FmPort->h_Spinlock) + XX_FreeSpinlock(p_FmPort->h_Spinlock); + + XX_Free(p_FmPort); + + return E_OK; +} + +/*************************************************/ +/* API Advanced Init unit functions */ +/*************************************************/ + +t_Error FM_PORT_ConfigNumOfOpenDmas(t_Handle h_FmPort, t_FmPortRsrc *p_OpenDmas) +{ + t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; + + SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_FmPort->p_FmPortDriverParam, E_INVALID_HANDLE); + + p_FmPort->p_FmPortDriverParam->setNumOfOpenDmas = TRUE; + memcpy(&p_FmPort->openDmas, p_OpenDmas, sizeof(t_FmPortRsrc)); + + return E_OK; +} + +t_Error FM_PORT_ConfigNumOfTasks(t_Handle h_FmPort, t_FmPortRsrc *p_NumOfTasks) +{ + t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; + + SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_FmPort->p_FmPortDriverParam, E_INVALID_HANDLE); + + memcpy(&p_FmPort->tasks, p_NumOfTasks, sizeof(t_FmPortRsrc)); + p_FmPort->p_FmPortDriverParam->setNumOfTasks = TRUE; + return E_OK; +} + +t_Error FM_PORT_ConfigSizeOfFifo(t_Handle h_FmPort, t_FmPortRsrc *p_SizeOfFifo) +{ + t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; + + SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_FmPort->p_FmPortDriverParam, E_INVALID_HANDLE); + + p_FmPort->p_FmPortDriverParam->setSizeOfFifo = TRUE; + memcpy(&p_FmPort->fifoBufs, p_SizeOfFifo, sizeof(t_FmPortRsrc)); + + return E_OK; +} + +t_Error FM_PORT_ConfigDeqHighPriority(t_Handle h_FmPort, bool highPri) +{ + t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; + + SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_FmPort->p_FmPortDriverParam, E_INVALID_HANDLE); + if ((p_FmPort->portType == e_FM_PORT_TYPE_RX_10G) + || (p_FmPort->portType == e_FM_PORT_TYPE_RX)) + RETURN_ERROR(MAJOR, E_NO_MEMORY, ("not available for Rx ports")); + + p_FmPort->p_FmPortDriverParam->dfltCfg.deq_high_pri = highPri; + + return E_OK; +} + +t_Error FM_PORT_ConfigDeqType(t_Handle h_FmPort, e_FmPortDeqType deqType) +{ + t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; + + SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_FmPort->p_FmPortDriverParam, E_INVALID_HANDLE); + if ((p_FmPort->portType == e_FM_PORT_TYPE_RX_10G) + || (p_FmPort->portType == e_FM_PORT_TYPE_RX)) + RETURN_ERROR(MAJOR, E_INVALID_OPERATION, + ("not available for Rx ports")); + + p_FmPort->p_FmPortDriverParam->dfltCfg.deq_type = + (enum fman_port_deq_type)deqType; + + return E_OK; +} + +t_Error FM_PORT_ConfigDeqPrefetchOption( + t_Handle h_FmPort, e_FmPortDeqPrefetchOption deqPrefetchOption) +{ + t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; + + SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_FmPort->p_FmPortDriverParam, E_INVALID_HANDLE); + if ((p_FmPort->portType == e_FM_PORT_TYPE_RX_10G) + || (p_FmPort->portType == e_FM_PORT_TYPE_RX)) + RETURN_ERROR(MAJOR, E_INVALID_OPERATION, + ("not available for Rx ports")); + p_FmPort->p_FmPortDriverParam->dfltCfg.deq_prefetch_opt = + (enum fman_port_deq_prefetch)deqPrefetchOption; + + return E_OK; +} + +t_Error FM_PORT_ConfigBackupPools(t_Handle h_FmPort, + t_FmBackupBmPools *p_BackupBmPools) +{ + t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; + + SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_FmPort->p_FmPortDriverParam, E_INVALID_HANDLE); + if ((p_FmPort->portType != e_FM_PORT_TYPE_RX_10G) + && (p_FmPort->portType != e_FM_PORT_TYPE_RX)) + RETURN_ERROR(MAJOR, E_INVALID_OPERATION, + ("available for Rx ports only")); + + p_FmPort->p_FmPortDriverParam->p_BackupBmPools = + (t_FmBackupBmPools *)XX_Malloc(sizeof(t_FmBackupBmPools)); + if (!p_FmPort->p_FmPortDriverParam->p_BackupBmPools) + RETURN_ERROR(MAJOR, E_NO_MEMORY, ("p_BackupBmPools allocation failed")); + memcpy(p_FmPort->p_FmPortDriverParam->p_BackupBmPools, p_BackupBmPools, + sizeof(t_FmBackupBmPools)); + + return E_OK; +} + +t_Error FM_PORT_ConfigDeqByteCnt(t_Handle h_FmPort, uint16_t deqByteCnt) +{ + t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; + + SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_FmPort->p_FmPortDriverParam, E_INVALID_HANDLE); + if ((p_FmPort->portType == e_FM_PORT_TYPE_RX_10G) + || (p_FmPort->portType == e_FM_PORT_TYPE_RX)) + RETURN_ERROR(MAJOR, E_INVALID_OPERATION, + ("not available for Rx ports")); + + p_FmPort->p_FmPortDriverParam->dfltCfg.deq_byte_cnt = deqByteCnt; + + return E_OK; +} + +t_Error FM_PORT_ConfigBufferPrefixContent( + t_Handle h_FmPort, t_FmBufferPrefixContent *p_FmBufferPrefixContent) +{ + t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; + + SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_FmPort->p_FmPortDriverParam, E_INVALID_HANDLE); + + memcpy(&p_FmPort->p_FmPortDriverParam->bufferPrefixContent, + p_FmBufferPrefixContent, sizeof(t_FmBufferPrefixContent)); + /* if dataAlign was not initialized by user, we return to driver's default */ + if (!p_FmPort->p_FmPortDriverParam->bufferPrefixContent.dataAlign) + p_FmPort->p_FmPortDriverParam->bufferPrefixContent.dataAlign = + DEFAULT_PORT_bufferPrefixContent_dataAlign; + + return E_OK; +} + +t_Error FM_PORT_ConfigCheksumLastBytesIgnore(t_Handle h_FmPort, + uint8_t checksumLastBytesIgnore) +{ + t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; + + SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_FmPort->p_FmPortDriverParam, E_INVALID_HANDLE); + + p_FmPort->p_FmPortDriverParam->dfltCfg.checksum_bytes_ignore = + checksumLastBytesIgnore; + + return E_OK; +} + +t_Error FM_PORT_ConfigCutBytesFromEnd(t_Handle h_FmPort, + uint8_t cutBytesFromEnd) +{ + t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; + + SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_FmPort->p_FmPortDriverParam, E_INVALID_HANDLE); + if ((p_FmPort->portType != e_FM_PORT_TYPE_RX_10G) + && (p_FmPort->portType != e_FM_PORT_TYPE_RX)) + RETURN_ERROR(MAJOR, E_INVALID_OPERATION, + ("available for Rx ports only")); + + p_FmPort->p_FmPortDriverParam->dfltCfg.rx_cut_end_bytes = cutBytesFromEnd; + + return E_OK; +} + +t_Error FM_PORT_ConfigPoolDepletion(t_Handle h_FmPort, + t_FmBufPoolDepletion *p_BufPoolDepletion) +{ + t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; + + SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_FmPort->p_FmPortDriverParam, E_INVALID_HANDLE); + if ((p_FmPort->portType != e_FM_PORT_TYPE_RX_10G) + && (p_FmPort->portType != e_FM_PORT_TYPE_RX)) + RETURN_ERROR(MAJOR, E_INVALID_OPERATION, + ("available for Rx ports only")); + + p_FmPort->p_FmPortDriverParam->enBufPoolDepletion = TRUE; + memcpy(&p_FmPort->p_FmPortDriverParam->bufPoolDepletion, p_BufPoolDepletion, + sizeof(t_FmBufPoolDepletion)); + + return E_OK; +} + +t_Error FM_PORT_ConfigObservedPoolDepletion( + t_Handle h_FmPort, + t_FmPortObservedBufPoolDepletion *p_FmPortObservedBufPoolDepletion) +{ + t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; + + SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_FmPort->p_FmPortDriverParam, E_INVALID_HANDLE); + if (p_FmPort->portType != e_FM_PORT_TYPE_OH_OFFLINE_PARSING) + RETURN_ERROR(MAJOR, E_INVALID_OPERATION, + ("available for OP ports only")); + + p_FmPort->p_FmPortDriverParam->enBufPoolDepletion = TRUE; + memcpy(&p_FmPort->p_FmPortDriverParam->bufPoolDepletion, + &p_FmPortObservedBufPoolDepletion->poolDepletionParams, + sizeof(t_FmBufPoolDepletion)); + memcpy(&p_FmPort->p_FmPortDriverParam->extBufPools, + &p_FmPortObservedBufPoolDepletion->poolsParams, + sizeof(t_FmExtPools)); + + return E_OK; +} + +t_Error FM_PORT_ConfigExtBufPools(t_Handle h_FmPort, t_FmExtPools *p_FmExtPools) +{ + t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; + + SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_FmPort->p_FmPortDriverParam, E_INVALID_HANDLE); + + if (p_FmPort->portType != e_FM_PORT_TYPE_OH_OFFLINE_PARSING) + RETURN_ERROR(MAJOR, E_INVALID_OPERATION, + ("available for OP ports only")); + + memcpy(&p_FmPort->p_FmPortDriverParam->extBufPools, p_FmExtPools, + sizeof(t_FmExtPools)); + + return E_OK; +} + +t_Error FM_PORT_ConfigDontReleaseTxBufToBM(t_Handle h_FmPort) +{ + t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; + + SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_FmPort->p_FmPortDriverParam, E_INVALID_HANDLE); + if ((p_FmPort->portType != e_FM_PORT_TYPE_TX_10G) + && (p_FmPort->portType != e_FM_PORT_TYPE_TX)) + RETURN_ERROR(MAJOR, E_INVALID_OPERATION, + ("available for Tx ports only")); + + p_FmPort->p_FmPortDriverParam->dontReleaseBuf = TRUE; + + return E_OK; +} + +t_Error FM_PORT_ConfigDfltColor(t_Handle h_FmPort, e_FmPortColor color) +{ + t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; + + SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_FmPort->p_FmPortDriverParam, E_INVALID_HANDLE); + p_FmPort->p_FmPortDriverParam->dfltCfg.color = (enum fman_port_color)color; + + return E_OK; +} + +t_Error FM_PORT_ConfigSyncReq(t_Handle h_FmPort, bool syncReq) +{ + t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; + + SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_FmPort->p_FmPortDriverParam, E_INVALID_HANDLE); + + if ((p_FmPort->portType == e_FM_PORT_TYPE_TX_10G) + || (p_FmPort->portType == e_FM_PORT_TYPE_TX)) + RETURN_ERROR(MAJOR, E_INVALID_OPERATION, + ("Not available for Tx ports")); + + p_FmPort->p_FmPortDriverParam->dfltCfg.sync_req = syncReq; + + return E_OK; +} + +t_Error FM_PORT_ConfigFrmDiscardOverride(t_Handle h_FmPort, bool override) +{ + t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; + + SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_FmPort->p_FmPortDriverParam, E_INVALID_HANDLE); + if ((p_FmPort->portType == e_FM_PORT_TYPE_TX_10G) + || (p_FmPort->portType == e_FM_PORT_TYPE_TX)) + RETURN_ERROR(MAJOR, E_INVALID_OPERATION, + ("Not available for Tx ports")); + + p_FmPort->p_FmPortDriverParam->dfltCfg.discard_override = override; + + return E_OK; +} + +t_Error FM_PORT_ConfigErrorsToDiscard(t_Handle h_FmPort, + fmPortFrameErrSelect_t errs) +{ + t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; + + SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_FmPort->p_FmPortDriverParam, E_INVALID_HANDLE); + if ((p_FmPort->portType != e_FM_PORT_TYPE_RX_10G) + && (p_FmPort->portType != e_FM_PORT_TYPE_RX) + && (p_FmPort->portType != e_FM_PORT_TYPE_OH_OFFLINE_PARSING)) + RETURN_ERROR( MAJOR, E_INVALID_OPERATION, + ("available for Rx and offline parsing ports only")); + + p_FmPort->p_FmPortDriverParam->errorsToDiscard = errs; + + return E_OK; +} + +t_Error FM_PORT_ConfigDmaSwapData(t_Handle h_FmPort, e_FmDmaSwapOption swapData) +{ + t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; + + SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_FmPort->p_FmPortDriverParam, E_INVALID_HANDLE); + + p_FmPort->p_FmPortDriverParam->dfltCfg.dma_swap_data = + (enum fman_port_dma_swap)swapData; + + return E_OK; +} + +t_Error FM_PORT_ConfigDmaIcCacheAttr(t_Handle h_FmPort, + e_FmDmaCacheOption intContextCacheAttr) +{ + t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; + + SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_FmPort->p_FmPortDriverParam, E_INVALID_HANDLE); + + p_FmPort->p_FmPortDriverParam->dfltCfg.dma_ic_stash_on = + (bool)(intContextCacheAttr == e_FM_DMA_STASH); + + return E_OK; +} + +t_Error FM_PORT_ConfigDmaHdrAttr(t_Handle h_FmPort, + e_FmDmaCacheOption headerCacheAttr) +{ + t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; + + SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_FmPort->p_FmPortDriverParam, E_INVALID_HANDLE); + + p_FmPort->p_FmPortDriverParam->dfltCfg.dma_header_stash_on = + (bool)(headerCacheAttr == e_FM_DMA_STASH); + + return E_OK; +} + +t_Error FM_PORT_ConfigDmaScatterGatherAttr( + t_Handle h_FmPort, e_FmDmaCacheOption scatterGatherCacheAttr) +{ + t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; + + SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_FmPort->p_FmPortDriverParam, E_INVALID_HANDLE); + + p_FmPort->p_FmPortDriverParam->dfltCfg.dma_sg_stash_on = + (bool)(scatterGatherCacheAttr == e_FM_DMA_STASH); + + return E_OK; +} + +t_Error FM_PORT_ConfigDmaWriteOptimize(t_Handle h_FmPort, bool optimize) +{ + t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; + + SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_FmPort->p_FmPortDriverParam, E_INVALID_HANDLE); + + if ((p_FmPort->portType == e_FM_PORT_TYPE_TX_10G) + || (p_FmPort->portType == e_FM_PORT_TYPE_TX)) + RETURN_ERROR(MAJOR, E_INVALID_OPERATION, + ("Not available for Tx ports")); + + p_FmPort->p_FmPortDriverParam->dfltCfg.dma_write_optimize = optimize; + + return E_OK; +} + +#if (DPAA_VERSION >= 11) +t_Error FM_PORT_ConfigNoScatherGather(t_Handle h_FmPort, bool noScatherGather) +{ + t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; + + UNUSED(noScatherGather); + UNUSED(p_FmPort); + + SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_FmPort->p_FmPortDriverParam, E_INVALID_HANDLE); + + p_FmPort->p_FmPortDriverParam->noScatherGather = noScatherGather; + + return E_OK; +} +#endif /* (DPAA_VERSION >= 11) */ + +t_Error FM_PORT_ConfigForwardReuseIntContext(t_Handle h_FmPort, + bool forwardReuse) +{ + t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; + + SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_FmPort->p_FmPortDriverParam, E_INVALID_HANDLE); + + if ((p_FmPort->portType != e_FM_PORT_TYPE_RX_10G) + && (p_FmPort->portType != e_FM_PORT_TYPE_RX)) + RETURN_ERROR(MAJOR, E_INVALID_OPERATION, + ("available for Rx ports only")); + + p_FmPort->p_FmPortDriverParam->forwardReuseIntContext = forwardReuse; + + return E_OK; +} + +t_Error FM_PORT_ConfigMaxFrameLength(t_Handle h_FmPort, uint16_t length) +{ + t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; + + SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_FmPort->p_FmPortDriverParam, E_INVALID_HANDLE); + + p_FmPort->maxFrameLength = length; + + return E_OK; +} + +#ifdef FM_HEAVY_TRAFFIC_HANG_ERRATA_FMAN_A005669 +t_Error FM_PORT_ConfigBCBWorkaround(t_Handle h_FmPort) +{ + t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; + + SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_FmPort->p_FmPortDriverParam, E_INVALID_HANDLE); + + p_FmPort->p_FmPortDriverParam->bcbWorkaround = TRUE; + + return E_OK; +} +#endif /* FM_HEAVY_TRAFFIC_HANG_ERRATA_FMAN_A005669 */ + +/****************************************************/ +/* Hidden-DEBUG Only API */ +/****************************************************/ + +t_Error FM_PORT_ConfigTxFifoMinFillLevel(t_Handle h_FmPort, + uint32_t minFillLevel) +{ + t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; + + SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_FmPort->p_FmPortDriverParam, E_INVALID_HANDLE); + if ((p_FmPort->portType != e_FM_PORT_TYPE_TX_10G) + && (p_FmPort->portType != e_FM_PORT_TYPE_TX)) + RETURN_ERROR(MAJOR, E_INVALID_OPERATION, + ("available for Tx ports only")); + + p_FmPort->p_FmPortDriverParam->dfltCfg.tx_fifo_min_level = minFillLevel; + + return E_OK; +} + +t_Error FM_PORT_ConfigFifoDeqPipelineDepth(t_Handle h_FmPort, + uint8_t deqPipelineDepth) +{ + t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; + + SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_FmPort->p_FmPortDriverParam, E_INVALID_HANDLE); + + if ((p_FmPort->portType == e_FM_PORT_TYPE_RX_10G) + || (p_FmPort->portType == e_FM_PORT_TYPE_RX)) + RETURN_ERROR(MAJOR, E_INVALID_OPERATION, + ("Not available for Rx ports")); + + if (p_FmPort->imEn) + RETURN_ERROR(MAJOR, E_INVALID_OPERATION, + ("Not available for IM ports!")); + + p_FmPort->p_FmPortDriverParam->dfltCfg.tx_fifo_deq_pipeline_depth = + deqPipelineDepth; + + return E_OK; +} + +t_Error FM_PORT_ConfigTxFifoLowComfLevel(t_Handle h_FmPort, + uint32_t fifoLowComfLevel) +{ + t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; + + SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_FmPort->p_FmPortDriverParam, E_INVALID_HANDLE); + if ((p_FmPort->portType != e_FM_PORT_TYPE_TX_10G) + && (p_FmPort->portType != e_FM_PORT_TYPE_TX)) + RETURN_ERROR(MAJOR, E_INVALID_OPERATION, + ("available for Tx ports only")); + + p_FmPort->p_FmPortDriverParam->dfltCfg.tx_fifo_low_comf_level = + fifoLowComfLevel; + + return E_OK; +} + +t_Error FM_PORT_ConfigRxFifoThreshold(t_Handle h_FmPort, uint32_t fifoThreshold) +{ + t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; + + SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_FmPort->p_FmPortDriverParam, E_INVALID_HANDLE); + if ((p_FmPort->portType != e_FM_PORT_TYPE_RX_10G) + && (p_FmPort->portType != e_FM_PORT_TYPE_RX)) + RETURN_ERROR(MAJOR, E_INVALID_OPERATION, + ("available for Rx ports only")); + + p_FmPort->p_FmPortDriverParam->dfltCfg.rx_fifo_thr = fifoThreshold; + + return E_OK; +} + +t_Error FM_PORT_ConfigRxFifoPriElevationLevel(t_Handle h_FmPort, + uint32_t priElevationLevel) +{ + t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; + + SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_FmPort->p_FmPortDriverParam, E_INVALID_HANDLE); + if ((p_FmPort->portType != e_FM_PORT_TYPE_RX_10G) + && (p_FmPort->portType != e_FM_PORT_TYPE_RX)) + RETURN_ERROR(MAJOR, E_INVALID_OPERATION, + ("available for Rx ports only")); + + p_FmPort->p_FmPortDriverParam->dfltCfg.rx_pri_elevation = priElevationLevel; + + return E_OK; +} +/****************************************************/ +/* API Run-time Control unit functions */ +/****************************************************/ + +t_Error FM_PORT_SetNumOfOpenDmas(t_Handle h_FmPort, + t_FmPortRsrc *p_NumOfOpenDmas) +{ + t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; + t_Error err; + + SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(!p_FmPort->p_FmPortDriverParam, E_INVALID_HANDLE); + + if ((!p_NumOfOpenDmas->num) || (p_NumOfOpenDmas->num > MAX_NUM_OF_DMAS)) + RETURN_ERROR( MAJOR, E_INVALID_VALUE, + ("openDmas-num can't be larger than %d", MAX_NUM_OF_DMAS)); + if (p_NumOfOpenDmas->extra > MAX_NUM_OF_EXTRA_DMAS) + RETURN_ERROR( + MAJOR, + E_INVALID_VALUE, + ("openDmas-extra can't be larger than %d", MAX_NUM_OF_EXTRA_DMAS)); + err = FmSetNumOfOpenDmas(p_FmPort->h_Fm, p_FmPort->hardwarePortId, + (uint8_t*)&p_NumOfOpenDmas->num, + (uint8_t*)&p_NumOfOpenDmas->extra, FALSE); + if (err) + RETURN_ERROR(MAJOR, err, NO_MSG); + + memcpy(&p_FmPort->openDmas, p_NumOfOpenDmas, sizeof(t_FmPortRsrc)); + + return E_OK; +} + +t_Error FM_PORT_SetNumOfTasks(t_Handle h_FmPort, t_FmPortRsrc *p_NumOfTasks) +{ + t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; + t_Error err; + + SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(!p_FmPort->p_FmPortDriverParam, E_INVALID_HANDLE); + + /* only driver uses host command port, so ASSERT rather than RETURN_ERROR */ + ASSERT_COND(p_FmPort->portType != e_FM_PORT_TYPE_OH_HOST_COMMAND); + + if ((!p_NumOfTasks->num) || (p_NumOfTasks->num > MAX_NUM_OF_TASKS)) + RETURN_ERROR( + MAJOR, E_INVALID_VALUE, + ("NumOfTasks-num can't be larger than %d", MAX_NUM_OF_TASKS)); + if (p_NumOfTasks->extra > MAX_NUM_OF_EXTRA_TASKS) + RETURN_ERROR( + MAJOR, + E_INVALID_VALUE, + ("NumOfTasks-extra can't be larger than %d", MAX_NUM_OF_EXTRA_TASKS)); + + err = FmSetNumOfTasks(p_FmPort->h_Fm, p_FmPort->hardwarePortId, + (uint8_t*)&p_NumOfTasks->num, + (uint8_t*)&p_NumOfTasks->extra, FALSE); + if (err) + RETURN_ERROR(MAJOR, err, NO_MSG); + + /* update driver's struct */ + memcpy(&p_FmPort->tasks, p_NumOfTasks, sizeof(t_FmPortRsrc)); + return E_OK; +} + +t_Error FM_PORT_SetSizeOfFifo(t_Handle h_FmPort, t_FmPortRsrc *p_SizeOfFifo) +{ + t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; + t_Error err; + + SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(!p_FmPort->p_FmPortDriverParam, E_INVALID_HANDLE); + + if (!p_SizeOfFifo->num || (p_SizeOfFifo->num > MAX_PORT_FIFO_SIZE)) + RETURN_ERROR( + MAJOR, + E_INVALID_VALUE, + ("SizeOfFifo-num has to be in the range of 256 - %d", MAX_PORT_FIFO_SIZE)); + if (p_SizeOfFifo->num % BMI_FIFO_UNITS) + RETURN_ERROR( + MAJOR, E_INVALID_VALUE, + ("SizeOfFifo-num has to be divisible by %d", BMI_FIFO_UNITS)); + if ((p_FmPort->portType == e_FM_PORT_TYPE_RX) + || (p_FmPort->portType == e_FM_PORT_TYPE_RX_10G)) + { + /* extra FIFO size (allowed only to Rx ports) */ + if (p_SizeOfFifo->extra % BMI_FIFO_UNITS) + RETURN_ERROR( + MAJOR, + E_INVALID_VALUE, + ("SizeOfFifo-extra has to be divisible by %d", BMI_FIFO_UNITS)); + } + else + if (p_SizeOfFifo->extra) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, + (" No SizeOfFifo-extra for non Rx ports")); + + memcpy(&p_FmPort->fifoBufs, p_SizeOfFifo, sizeof(t_FmPortRsrc)); + + /* we do not change user's parameter */ + err = VerifySizeOfFifo(p_FmPort); + if (err) + RETURN_ERROR(MAJOR, err, NO_MSG); + + err = FmSetSizeOfFifo(p_FmPort->h_Fm, p_FmPort->hardwarePortId, + &p_SizeOfFifo->num, &p_SizeOfFifo->extra, FALSE); + if (err) + RETURN_ERROR(MAJOR, err, NO_MSG); + + return E_OK; +} + +uint32_t FM_PORT_GetBufferDataOffset(t_Handle h_FmPort) +{ + t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; + + SANITY_CHECK_RETURN_VALUE(p_FmPort, E_INVALID_HANDLE, 0); + SANITY_CHECK_RETURN_VALUE(!p_FmPort->p_FmPortDriverParam, E_INVALID_STATE, + 0); + + return p_FmPort->bufferOffsets.dataOffset; +} + +uint8_t * FM_PORT_GetBufferICInfo(t_Handle h_FmPort, char *p_Data) +{ + t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; + + SANITY_CHECK_RETURN_VALUE(p_FmPort, E_INVALID_HANDLE, NULL); + SANITY_CHECK_RETURN_VALUE(!p_FmPort->p_FmPortDriverParam, E_INVALID_STATE, + NULL); + + if (p_FmPort->bufferOffsets.pcdInfoOffset == ILLEGAL_BASE) + return NULL; + + return (uint8_t *)PTR_MOVE(p_Data, p_FmPort->bufferOffsets.pcdInfoOffset); +} + +t_FmPrsResult * FM_PORT_GetBufferPrsResult(t_Handle h_FmPort, char *p_Data) +{ + t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; + + SANITY_CHECK_RETURN_VALUE(p_FmPort, E_INVALID_HANDLE, NULL); + SANITY_CHECK_RETURN_VALUE(!p_FmPort->p_FmPortDriverParam, E_INVALID_STATE, + NULL); + + if (p_FmPort->bufferOffsets.prsResultOffset == ILLEGAL_BASE) + return NULL; + + return (t_FmPrsResult *)PTR_MOVE(p_Data, p_FmPort->bufferOffsets.prsResultOffset); +} + +uint64_t * FM_PORT_GetBufferTimeStamp(t_Handle h_FmPort, char *p_Data) +{ + t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; + + SANITY_CHECK_RETURN_VALUE(p_FmPort, E_INVALID_HANDLE, NULL); + SANITY_CHECK_RETURN_VALUE(!p_FmPort->p_FmPortDriverParam, E_INVALID_STATE, + NULL); + + if (p_FmPort->bufferOffsets.timeStampOffset == ILLEGAL_BASE) + return NULL; + + return (uint64_t *)PTR_MOVE(p_Data, p_FmPort->bufferOffsets.timeStampOffset); +} + +uint8_t * FM_PORT_GetBufferHashResult(t_Handle h_FmPort, char *p_Data) +{ + t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; + + SANITY_CHECK_RETURN_VALUE(p_FmPort, E_INVALID_HANDLE, NULL); + SANITY_CHECK_RETURN_VALUE(!p_FmPort->p_FmPortDriverParam, E_INVALID_STATE, + NULL); + + if (p_FmPort->bufferOffsets.hashResultOffset == ILLEGAL_BASE) + return NULL; + + return (uint8_t *)PTR_MOVE(p_Data, p_FmPort->bufferOffsets.hashResultOffset); +} + +t_Error FM_PORT_Disable(t_Handle h_FmPort) +{ + t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; + int err; + + SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(!p_FmPort->p_FmPortDriverParam, E_INVALID_STATE); + + if (p_FmPort->imEn) + FmPortImDisable(p_FmPort); + + err = fman_port_disable(&p_FmPort->port); + if (err == -EBUSY) + { + DBG(WARNING, ("%s: BMI or QMI is Busy. Port forced down", + p_FmPort->name)); + } + else + if (err != 0) + { + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("fman_port_disable")); + } + + p_FmPort->enabled = FALSE; + + return E_OK; +} + +t_Error FM_PORT_Enable(t_Handle h_FmPort) +{ + t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; + int err; + + SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(!p_FmPort->p_FmPortDriverParam, E_INVALID_STATE); + + /* Used by FM_PORT_Free routine as indication + if to disable port. Thus set it to TRUE prior + to enabling itself. This way if part of enable + process fails there will be still things + to disable during Free. For example, if BMI + enable succeeded but QMI failed, still BMI + needs to be disabled by Free. */ + p_FmPort->enabled = TRUE; + + if (p_FmPort->imEn) + FmPortImEnable(p_FmPort); + + err = fman_port_enable(&p_FmPort->port); + if (err != 0) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("fman_port_enable")); + + return E_OK; +} + +t_Error FM_PORT_SetRateLimit(t_Handle h_FmPort, t_FmPortRateLimit *p_RateLimit) +{ + t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; + uint8_t factor, countUnitBit; + uint16_t baseGran; + struct fman_port_rate_limiter params; + int err; + + SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(!p_FmPort->p_FmPortDriverParam, E_INVALID_HANDLE); + + switch (p_FmPort->portType) + { + case (e_FM_PORT_TYPE_TX_10G): + case (e_FM_PORT_TYPE_TX): + baseGran = BMI_RATE_LIMIT_GRAN_TX; + break; + case (e_FM_PORT_TYPE_OH_OFFLINE_PARSING): + baseGran = BMI_RATE_LIMIT_GRAN_OP; + break; + default: + RETURN_ERROR( MAJOR, E_INVALID_OPERATION, + ("available for Tx and Offline parsing ports only")); + } + + countUnitBit = (uint8_t)FmGetTimeStampScale(p_FmPort->h_Fm); /* TimeStamp per nano seconds units */ + /* normally, we use 1 usec as the reference count */ + factor = 1; + /* if ratelimit is too small for a 1usec factor, multiply the factor */ + while (p_RateLimit->rateLimit < baseGran / factor) + { + if (countUnitBit == 31) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("Rate limit is too small")); + + countUnitBit++; + factor <<= 1; + } + /* if ratelimit is too large for a 1usec factor, it is also larger than max rate*/ + if (p_RateLimit->rateLimit + > ((uint32_t)baseGran * (1 << 10) * (uint32_t)factor)) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("Rate limit is too large")); + + if (!p_RateLimit->maxBurstSize + || (p_RateLimit->maxBurstSize > BMI_RATE_LIMIT_MAX_BURST_SIZE)) + RETURN_ERROR( + MAJOR, + E_INVALID_VALUE, + ("maxBurstSize must be between 1K and %dk", BMI_RATE_LIMIT_MAX_BURST_SIZE)); + + params.count_1micro_bit = (uint8_t)FmGetTimeStampScale(p_FmPort->h_Fm); + params.high_burst_size_gran = FALSE; + params.burst_size = p_RateLimit->maxBurstSize; + params.rate = p_RateLimit->rateLimit; + params.rate_factor = E_FMAN_PORT_RATE_DOWN_NONE; + + if (p_FmPort->portType == e_FM_PORT_TYPE_OH_OFFLINE_PARSING) + { +#ifndef FM_NO_ADVANCED_RATE_LIMITER + + if ((p_FmPort->fmRevInfo.majorRev == 4) + || (p_FmPort->fmRevInfo.majorRev >= 6)) + { + params.high_burst_size_gran = TRUE; + } + else +#endif /* ! FM_NO_ADVANCED_RATE_LIMITER */ + { + if (p_RateLimit->rateLimitDivider + != e_FM_PORT_DUAL_RATE_LIMITER_NONE) + RETURN_ERROR(MAJOR, E_NOT_SUPPORTED, + ("FM_PORT_ConfigDualRateLimitScaleDown")); + + if (p_RateLimit->maxBurstSize % 1000) + { + p_RateLimit->maxBurstSize = + (uint16_t)((p_RateLimit->maxBurstSize / 1000) + 1); + DBG(WARNING, ("rateLimit.maxBurstSize rounded up to %d", (p_RateLimit->maxBurstSize/1000+1)*1000)); + } + else + p_RateLimit->maxBurstSize = (uint16_t)(p_RateLimit->maxBurstSize + / 1000); + } + params.rate_factor = + (enum fman_port_rate_limiter_scale_down)p_RateLimit->rateLimitDivider; + params.burst_size = p_RateLimit->maxBurstSize; + } + + err = fman_port_set_rate_limiter(&p_FmPort->port, ¶ms); + if (err != 0) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("fman_port_set_rate_limiter")); + + return E_OK; +} + +t_Error FM_PORT_DeleteRateLimit(t_Handle h_FmPort) +{ + t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; + int err; + + SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(!p_FmPort->p_FmPortDriverParam, E_INVALID_HANDLE); + + if ((p_FmPort->portType == e_FM_PORT_TYPE_RX_10G) + || (p_FmPort->portType == e_FM_PORT_TYPE_RX) + || (p_FmPort->portType == e_FM_PORT_TYPE_OH_HOST_COMMAND)) + RETURN_ERROR( MAJOR, E_INVALID_OPERATION, + ("available for Tx and Offline parsing ports only")); + + err = fman_port_delete_rate_limiter(&p_FmPort->port); + if (err != 0) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("fman_port_set_rate_limiter")); + return E_OK; +} + +t_Error FM_PORT_SetPfcPrioritiesMappingToQmanWQ(t_Handle h_FmPort, uint8_t prio, + uint8_t wq) +{ + t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; + uint32_t tmpReg; + uint32_t wqTmpReg; + + SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(!p_FmPort->p_FmPortDriverParam, E_INVALID_STATE); + + if ((p_FmPort->portType != e_FM_PORT_TYPE_TX) + && (p_FmPort->portType != e_FM_PORT_TYPE_TX_10G)) + RETURN_ERROR(MAJOR, E_INVALID_OPERATION, + ("PFC mapping is available for Tx ports only")); + + if (prio > 7) + RETURN_ERROR(MAJOR, E_NOT_IN_RANGE, + ("PFC priority (%d) is out of range (0-7)", prio)); + if (wq > 7) + RETURN_ERROR(MAJOR, E_NOT_IN_RANGE, + ("WQ (%d) is out of range (0-7)", wq)); + + tmpReg = GET_UINT32(p_FmPort->p_FmPortBmiRegs->txPortBmiRegs.fmbm_tpfcm[0]); + tmpReg &= ~(0xf << ((7 - prio) * 4)); + wqTmpReg = ((uint32_t)wq << ((7 - prio) * 4)); + tmpReg |= wqTmpReg; + + WRITE_UINT32(p_FmPort->p_FmPortBmiRegs->txPortBmiRegs.fmbm_tpfcm[0], + tmpReg); + + return E_OK; +} + +t_Error FM_PORT_SetFrameQueueCounters(t_Handle h_FmPort, bool enable) +{ + t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; + + SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(!p_FmPort->p_FmPortDriverParam, E_INVALID_STATE); + + fman_port_set_queue_cnt_mode(&p_FmPort->port, enable); + + return E_OK; +} + +t_Error FM_PORT_SetPerformanceCounters(t_Handle h_FmPort, bool enable) +{ + t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; + int err; + + SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(!p_FmPort->p_FmPortDriverParam, E_INVALID_STATE); + + err = fman_port_set_perf_cnt_mode(&p_FmPort->port, enable); + if (err != 0) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("fman_port_set_perf_cnt_mode")); + return E_OK; +} + +t_Error FM_PORT_SetPerformanceCountersParams( + t_Handle h_FmPort, t_FmPortPerformanceCnt *p_FmPortPerformanceCnt) +{ + t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; + struct fman_port_perf_cnt_params params; + int err; + + SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE); + + /* check parameters */ + if (!p_FmPortPerformanceCnt->taskCompVal + || (p_FmPortPerformanceCnt->taskCompVal > p_FmPort->tasks.num)) + RETURN_ERROR( + MAJOR, + E_INVALID_VALUE, + ("taskCompVal (%d) has to be in the range of 1 - %d (current value)!", p_FmPortPerformanceCnt->taskCompVal, p_FmPort->tasks.num)); + if (!p_FmPortPerformanceCnt->dmaCompVal + || (p_FmPortPerformanceCnt->dmaCompVal > p_FmPort->openDmas.num)) + RETURN_ERROR( + MAJOR, + E_INVALID_VALUE, + ("dmaCompVal (%d) has to be in the range of 1 - %d (current value)!", p_FmPortPerformanceCnt->dmaCompVal, p_FmPort->openDmas.num)); + if (!p_FmPortPerformanceCnt->fifoCompVal + || (p_FmPortPerformanceCnt->fifoCompVal > p_FmPort->fifoBufs.num)) + RETURN_ERROR( + MAJOR, + E_INVALID_VALUE, + ("fifoCompVal (%d) has to be in the range of 256 - %d (current value)!", p_FmPortPerformanceCnt->fifoCompVal, p_FmPort->fifoBufs.num)); + if (p_FmPortPerformanceCnt->fifoCompVal % BMI_FIFO_UNITS) + RETURN_ERROR( + MAJOR, + E_INVALID_VALUE, + ("fifoCompVal (%d) has to be divisible by %d", p_FmPortPerformanceCnt->fifoCompVal, BMI_FIFO_UNITS)); + + switch (p_FmPort->portType) + { + case (e_FM_PORT_TYPE_RX_10G): + case (e_FM_PORT_TYPE_RX): + if (!p_FmPortPerformanceCnt->queueCompVal + || (p_FmPortPerformanceCnt->queueCompVal + > MAX_PERFORMANCE_RX_QUEUE_COMP)) + RETURN_ERROR( + MAJOR, + E_INVALID_VALUE, + ("performanceCnt.queueCompVal for Rx has to be in the range of 1 - %d", MAX_PERFORMANCE_RX_QUEUE_COMP)); + break; + case (e_FM_PORT_TYPE_TX_10G): + case (e_FM_PORT_TYPE_TX): + if (!p_FmPortPerformanceCnt->queueCompVal + || (p_FmPortPerformanceCnt->queueCompVal + > MAX_PERFORMANCE_TX_QUEUE_COMP)) + RETURN_ERROR( + MAJOR, + E_INVALID_VALUE, + ("performanceCnt.queueCompVal for Tx has to be in the range of 1 - %d", MAX_PERFORMANCE_TX_QUEUE_COMP)); + break; + case (e_FM_PORT_TYPE_OH_OFFLINE_PARSING): + case (e_FM_PORT_TYPE_OH_HOST_COMMAND): + if (p_FmPortPerformanceCnt->queueCompVal) + RETURN_ERROR( + MAJOR, + E_INVALID_VALUE, + ("performanceCnt.queueCompVal is not relevant for H/O ports.")); + break; + default: + RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Invalid port type")); + } + + params.task_val = p_FmPortPerformanceCnt->taskCompVal; + params.queue_val = p_FmPortPerformanceCnt->queueCompVal; + params.dma_val = p_FmPortPerformanceCnt->dmaCompVal; + params.fifo_val = p_FmPortPerformanceCnt->fifoCompVal; + + err = fman_port_set_perf_cnt_params(&p_FmPort->port, ¶ms); + if (err != 0) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("fman_port_set_perf_cnt_params")); + + return E_OK; +} + +t_Error FM_PORT_AnalyzePerformanceParams(t_Handle h_FmPort) +{ + t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; + t_FmPortPerformanceCnt currParams, savedParams; + t_Error err; + bool underTest, failed = FALSE; + + SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE); + + XX_Print("Analyzing Performance parameters for port (type %d, id%d)\n", + p_FmPort->portType, p_FmPort->portId); + + currParams.taskCompVal = (uint8_t)p_FmPort->tasks.num; + if ((p_FmPort->portType == e_FM_PORT_TYPE_OH_OFFLINE_PARSING) + || (p_FmPort->portType == e_FM_PORT_TYPE_OH_HOST_COMMAND)) + currParams.queueCompVal = 0; + else + currParams.queueCompVal = 1; + currParams.dmaCompVal = (uint8_t)p_FmPort->openDmas.num; + currParams.fifoCompVal = p_FmPort->fifoBufs.num; + + FM_PORT_SetPerformanceCounters(p_FmPort, FALSE); + ClearPerfCnts(p_FmPort); + if ((err = FM_PORT_SetPerformanceCountersParams(p_FmPort, &currParams)) + != E_OK) + RETURN_ERROR(MAJOR, err, NO_MSG); + FM_PORT_SetPerformanceCounters(p_FmPort, TRUE); + XX_UDelay(1000000); + FM_PORT_SetPerformanceCounters(p_FmPort, FALSE); + if (FM_PORT_GetCounter(p_FmPort, e_FM_PORT_COUNTERS_TASK_UTIL)) + { + XX_Print( + "Max num of defined port tasks (%d) utilized - Please enlarge\n", + p_FmPort->tasks.num); + failed = TRUE; + } + if (FM_PORT_GetCounter(p_FmPort, e_FM_PORT_COUNTERS_DMA_UTIL)) + { + XX_Print( + "Max num of defined port openDmas (%d) utilized - Please enlarge\n", + p_FmPort->openDmas.num); + failed = TRUE; + } + if (FM_PORT_GetCounter(p_FmPort, e_FM_PORT_COUNTERS_FIFO_UTIL)) + { + XX_Print( + "Max size of defined port fifo (%d) utilized - Please enlarge\n", + p_FmPort->fifoBufs.num); + failed = TRUE; + } + if (failed) + RETURN_ERROR(MAJOR, E_INVALID_STATE, NO_MSG); + + memset(&savedParams, 0, sizeof(savedParams)); + while (TRUE) + { + underTest = FALSE; + if ((currParams.taskCompVal != 1) && !savedParams.taskCompVal) + { + currParams.taskCompVal--; + underTest = TRUE; + } + if ((currParams.dmaCompVal != 1) && !savedParams.dmaCompVal) + { + currParams.dmaCompVal--; + underTest = TRUE; + } + if ((currParams.fifoCompVal != BMI_FIFO_UNITS) + && !savedParams.fifoCompVal) + { + currParams.fifoCompVal -= BMI_FIFO_UNITS; + underTest = TRUE; + } + if (!underTest) + break; + + ClearPerfCnts(p_FmPort); + if ((err = FM_PORT_SetPerformanceCountersParams(p_FmPort, &currParams)) + != E_OK) + RETURN_ERROR(MAJOR, err, NO_MSG); + FM_PORT_SetPerformanceCounters(p_FmPort, TRUE); + XX_UDelay(1000000); + FM_PORT_SetPerformanceCounters(p_FmPort, FALSE); + + if (!savedParams.taskCompVal + && FM_PORT_GetCounter(p_FmPort, e_FM_PORT_COUNTERS_TASK_UTIL)) + savedParams.taskCompVal = (uint8_t)(currParams.taskCompVal + 2); + if (!savedParams.dmaCompVal + && FM_PORT_GetCounter(p_FmPort, e_FM_PORT_COUNTERS_DMA_UTIL)) + savedParams.dmaCompVal = (uint8_t)(currParams.dmaCompVal + 2); + if (!savedParams.fifoCompVal + && FM_PORT_GetCounter(p_FmPort, e_FM_PORT_COUNTERS_FIFO_UTIL)) + savedParams.fifoCompVal = currParams.fifoCompVal + + (2 * BMI_FIFO_UNITS); + } + + XX_Print("best vals: tasks %d, dmas %d, fifos %d\n", + savedParams.taskCompVal, savedParams.dmaCompVal, + savedParams.fifoCompVal); + return E_OK; +} + +t_Error FM_PORT_SetStatisticsCounters(t_Handle h_FmPort, bool enable) +{ + t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; + int err; + + SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(!p_FmPort->p_FmPortDriverParam, E_INVALID_STATE); + + err = fman_port_set_stats_cnt_mode(&p_FmPort->port, enable); + if (err != 0) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("fman_port_set_stats_cnt_mode")); + return E_OK; +} + +t_Error FM_PORT_SetErrorsRoute(t_Handle h_FmPort, fmPortFrameErrSelect_t errs) +{ + t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; + volatile uint32_t *p_ErrDiscard = NULL; + int err; + + UNUSED(p_ErrDiscard); + err = fman_port_set_err_mask(&p_FmPort->port, (uint32_t)errs); + if (err != 0) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("fman_port_set_err_mask")); + +#ifdef FM_ERROR_VSP_NO_MATCH_SW006 + if (p_FmPort->fmRevInfo.majorRev >= 6) + { + t_FmPcdCtrlParamsPage *p_ParamsPage; + + FmPortSetGprFunc(p_FmPort, e_FM_PORT_GPR_MURAM_PAGE, + (void**)&p_ParamsPage); + ASSERT_COND(p_ParamsPage); + switch (p_FmPort->portType) + { + case (e_FM_PORT_TYPE_RX_10G): + case (e_FM_PORT_TYPE_RX): + p_ErrDiscard = + &p_FmPort->p_FmPortBmiRegs->rxPortBmiRegs.fmbm_rfsdm; + break; + case (e_FM_PORT_TYPE_OH_OFFLINE_PARSING): + p_ErrDiscard = + &p_FmPort->p_FmPortBmiRegs->ohPortBmiRegs.fmbm_ofsdm; + break; + default: + RETURN_ERROR( + MAJOR, E_INVALID_OPERATION, + ("available for Rx and offline parsing ports only")); + } + WRITE_UINT32(p_ParamsPage->errorsDiscardMask, + GET_UINT32(*p_ErrDiscard) | errs); + } +#endif /* FM_ERROR_VSP_NO_MATCH_SW006 */ + + return E_OK; +} + +t_Error FM_PORT_SetAllocBufCounter(t_Handle h_FmPort, uint8_t poolId, + bool enable) +{ + t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; + int err; + + SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(poolId<BM_MAX_NUM_OF_POOLS, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(!p_FmPort->p_FmPortDriverParam, E_INVALID_STATE); + + if ((p_FmPort->portType != e_FM_PORT_TYPE_RX_10G) + && (p_FmPort->portType != e_FM_PORT_TYPE_RX)) + RETURN_ERROR(MAJOR, E_INVALID_OPERATION, + ("available for Rx ports only")); + + err = fman_port_set_bpool_cnt_mode(&p_FmPort->port, poolId, enable); + if (err != 0) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("fman_port_set_bpool_cnt_mode")); + return E_OK; +} + +t_Error FM_PORT_GetBmiCounters(t_Handle h_FmPort, t_FmPortBmiStats *p_BmiStats) +{ + t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; + + if ((p_FmPort->portType == e_FM_PORT_TYPE_RX) + || (p_FmPort->portType == e_FM_PORT_TYPE_RX_10G)){ + p_BmiStats->cntCycle = + FM_PORT_GetCounter(h_FmPort, e_FM_PORT_COUNTERS_CYCLE); + /* fmbm_rccn */ + p_BmiStats->cntTaskUtil = + FM_PORT_GetCounter(h_FmPort, e_FM_PORT_COUNTERS_TASK_UTIL); + /* fmbm_rtuc */ + p_BmiStats->cntQueueUtil = + FM_PORT_GetCounter(h_FmPort, e_FM_PORT_COUNTERS_QUEUE_UTIL); + /* fmbm_rrquc */ + p_BmiStats->cntDmaUtil = + FM_PORT_GetCounter(h_FmPort, e_FM_PORT_COUNTERS_DMA_UTIL); + /* fmbm_rduc */ + p_BmiStats->cntFifoUtil = + FM_PORT_GetCounter(h_FmPort, e_FM_PORT_COUNTERS_FIFO_UTIL); + /* fmbm_rfuc */ + p_BmiStats->cntRxPauseActivation = + FM_PORT_GetCounter(h_FmPort, e_FM_PORT_COUNTERS_RX_PAUSE_ACTIVATION); + /* fmbm_rpac */ + p_BmiStats->cntFrame = + FM_PORT_GetCounter(h_FmPort, e_FM_PORT_COUNTERS_FRAME); + /* fmbm_rfrc */ + p_BmiStats->cntDiscardFrame = + FM_PORT_GetCounter(h_FmPort, e_FM_PORT_COUNTERS_DISCARD_FRAME); + /* fmbm_rfdc */ + p_BmiStats->cntDeallocBuf = + FM_PORT_GetCounter(h_FmPort, e_FM_PORT_COUNTERS_DEALLOC_BUF); + /* fmbm_rbdc */ + p_BmiStats->cntRxBadFrame = + FM_PORT_GetCounter(h_FmPort, e_FM_PORT_COUNTERS_RX_BAD_FRAME); + /* fmbm_rfbc */ + p_BmiStats->cntRxLargeFrame = + FM_PORT_GetCounter(h_FmPort, e_FM_PORT_COUNTERS_RX_LARGE_FRAME); + /* fmbm_rlfc */ + p_BmiStats->cntRxFilterFrame = + FM_PORT_GetCounter(h_FmPort, e_FM_PORT_COUNTERS_RX_FILTER_FRAME); + /* fmbm_rffc */ + p_BmiStats->cntRxListDmaErr = + FM_PORT_GetCounter(h_FmPort, e_FM_PORT_COUNTERS_RX_LIST_DMA_ERR); + /* fmbm_rfldec */ + p_BmiStats->cntRxOutOfBuffersDiscard = + FM_PORT_GetCounter(h_FmPort, e_FM_PORT_COUNTERS_RX_OUT_OF_BUFFERS_DISCARD); + /* fmbm_rodc */ + p_BmiStats->cntWredDiscard = 0; + p_BmiStats->cntLengthErr = 0; + p_BmiStats->cntUnsupportedFormat = 0; + } + else if ((p_FmPort->portType == e_FM_PORT_TYPE_TX) + || (p_FmPort->portType == e_FM_PORT_TYPE_TX_10G)){ + p_BmiStats->cntCycle = + FM_PORT_GetCounter(h_FmPort, e_FM_PORT_COUNTERS_CYCLE); + /* fmbm_tccn */ + p_BmiStats->cntTaskUtil = + FM_PORT_GetCounter(h_FmPort, e_FM_PORT_COUNTERS_TASK_UTIL); + /* fmbm_ttuc */ + p_BmiStats->cntQueueUtil = + FM_PORT_GetCounter(h_FmPort, e_FM_PORT_COUNTERS_QUEUE_UTIL); + /* fmbm_ttcquc */ + p_BmiStats->cntDmaUtil = + FM_PORT_GetCounter(h_FmPort, e_FM_PORT_COUNTERS_DMA_UTIL); + /* fmbm_tduc */ + p_BmiStats->cntFifoUtil = + FM_PORT_GetCounter(h_FmPort, e_FM_PORT_COUNTERS_FIFO_UTIL); + /* fmbm_tfuc */ + p_BmiStats->cntRxPauseActivation = 0; + p_BmiStats->cntFrame = + FM_PORT_GetCounter(h_FmPort, e_FM_PORT_COUNTERS_FRAME); + /* fmbm_tfrc */ + p_BmiStats->cntDiscardFrame = + FM_PORT_GetCounter(h_FmPort, e_FM_PORT_COUNTERS_DISCARD_FRAME); + /* fmbm_tfdc */ + p_BmiStats->cntDeallocBuf = + FM_PORT_GetCounter(h_FmPort, e_FM_PORT_COUNTERS_DEALLOC_BUF); + /* fmbm_tbdc */ + p_BmiStats->cntRxBadFrame = 0; + p_BmiStats->cntRxLargeFrame = 0; + p_BmiStats->cntRxFilterFrame = 0; + p_BmiStats->cntRxListDmaErr = 0; + p_BmiStats->cntRxOutOfBuffersDiscard = 0; + p_BmiStats->cntWredDiscard = 0; + p_BmiStats->cntLengthErr = + FM_PORT_GetCounter(h_FmPort, e_FM_PORT_COUNTERS_LENGTH_ERR); + /* fmbm_tfledc */ + p_BmiStats->cntUnsupportedFormat = + FM_PORT_GetCounter(h_FmPort, e_FM_PORT_COUNTERS_UNSUPPRTED_FORMAT); + /* fmbm_tfufdc */ + } + else if (p_FmPort->portType == e_FM_PORT_TYPE_OH_OFFLINE_PARSING) { + p_BmiStats->cntCycle = + FM_PORT_GetCounter(h_FmPort, e_FM_PORT_COUNTERS_CYCLE); + /* fmbm_occn */ + p_BmiStats->cntTaskUtil = + FM_PORT_GetCounter(h_FmPort, e_FM_PORT_COUNTERS_TASK_UTIL); + /* fmbm_otuc */ + p_BmiStats->cntQueueUtil = 0; + p_BmiStats->cntDmaUtil = + FM_PORT_GetCounter(h_FmPort, e_FM_PORT_COUNTERS_DMA_UTIL); + /* fmbm_oduc */ + p_BmiStats->cntFifoUtil = + FM_PORT_GetCounter(h_FmPort, e_FM_PORT_COUNTERS_FIFO_UTIL); + /* fmbm_ofuc*/ + p_BmiStats->cntRxPauseActivation = 0; + p_BmiStats->cntFrame = + FM_PORT_GetCounter(h_FmPort, e_FM_PORT_COUNTERS_FRAME); + /* fmbm_ofrc */ + p_BmiStats->cntDiscardFrame = + FM_PORT_GetCounter(h_FmPort, e_FM_PORT_COUNTERS_DISCARD_FRAME); + /* fmbm_ofdc */ + p_BmiStats->cntDeallocBuf = + FM_PORT_GetCounter(h_FmPort, e_FM_PORT_COUNTERS_DEALLOC_BUF); + /* fmbm_obdc*/ + p_BmiStats->cntRxBadFrame = 0; + p_BmiStats->cntRxLargeFrame = 0; + p_BmiStats->cntRxFilterFrame = + FM_PORT_GetCounter(h_FmPort, e_FM_PORT_COUNTERS_RX_FILTER_FRAME); + /* fmbm_offc */ + p_BmiStats->cntRxListDmaErr = + FM_PORT_GetCounter(h_FmPort, e_FM_PORT_COUNTERS_RX_LIST_DMA_ERR); + /* fmbm_ofldec */ + p_BmiStats->cntRxOutOfBuffersDiscard = + FM_PORT_GetCounter(h_FmPort, e_FM_PORT_COUNTERS_RX_OUT_OF_BUFFERS_DISCARD); + /* fmbm_rodc */ + p_BmiStats->cntWredDiscard = + FM_PORT_GetCounter(h_FmPort, e_FM_PORT_COUNTERS_WRED_DISCARD); + /* fmbm_ofwdc */ + p_BmiStats->cntLengthErr = + FM_PORT_GetCounter(h_FmPort, e_FM_PORT_COUNTERS_LENGTH_ERR); + /* fmbm_ofledc */ + p_BmiStats->cntUnsupportedFormat = + FM_PORT_GetCounter(h_FmPort, e_FM_PORT_COUNTERS_UNSUPPRTED_FORMAT); + /* fmbm_ofufdc */ + } + return E_OK; +} + +uint32_t FM_PORT_GetCounter(t_Handle h_FmPort, e_FmPortCounters counter) +{ + t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; + bool bmiCounter = FALSE; + enum fman_port_stats_counters statsType; + enum fman_port_perf_counters perfType; + enum fman_port_qmi_counters queueType; + bool isStats; + t_Error errCode; + + SANITY_CHECK_RETURN_VALUE(p_FmPort, E_INVALID_HANDLE, 0); + SANITY_CHECK_RETURN_ERROR(!p_FmPort->p_FmPortDriverParam, E_INVALID_STATE); + + switch (counter) + { + case (e_FM_PORT_COUNTERS_DEQ_TOTAL): + case (e_FM_PORT_COUNTERS_DEQ_FROM_DEFAULT): + case (e_FM_PORT_COUNTERS_DEQ_CONFIRM): + /* check that counter is available for the port type */ + if ((p_FmPort->portType == e_FM_PORT_TYPE_RX) + || (p_FmPort->portType == e_FM_PORT_TYPE_RX_10G)) + { + REPORT_ERROR(MINOR, E_INVALID_STATE, + ("Requested counter is not available for Rx ports")); + return 0; + } + bmiCounter = FALSE; + break; + case (e_FM_PORT_COUNTERS_ENQ_TOTAL): + bmiCounter = FALSE; + break; + default: /* BMI counters (or error - will be checked in BMI routine )*/ + bmiCounter = TRUE; + break; + } + + if (bmiCounter) + { + errCode = BmiPortCheckAndGetCounterType(p_FmPort, counter, &statsType, + &perfType, &isStats); + if (errCode != E_OK) + { + REPORT_ERROR(MINOR, errCode, NO_MSG); + return 0; + } + if (isStats) + return fman_port_get_stats_counter(&p_FmPort->port, statsType); + else + return fman_port_get_perf_counter(&p_FmPort->port, perfType); + } + else /* QMI counter */ + { + /* check that counters are enabled */ + if (!(GET_UINT32(p_FmPort->port.qmi_regs->fmqm_pnc) + & QMI_PORT_CFG_EN_COUNTERS)) + + { + REPORT_ERROR(MINOR, E_INVALID_STATE, ("Requested counter was not enabled")); + return 0; + } + + /* Set counter */ + switch (counter) + { + case (e_FM_PORT_COUNTERS_ENQ_TOTAL): + queueType = E_FMAN_PORT_ENQ_TOTAL; + break; + case (e_FM_PORT_COUNTERS_DEQ_TOTAL): + queueType = E_FMAN_PORT_DEQ_TOTAL; + break; + case (e_FM_PORT_COUNTERS_DEQ_FROM_DEFAULT): + queueType = E_FMAN_PORT_DEQ_FROM_DFLT; + break; + case (e_FM_PORT_COUNTERS_DEQ_CONFIRM): + queueType = E_FMAN_PORT_DEQ_CONFIRM; + break; + default: + REPORT_ERROR(MINOR, E_INVALID_STATE, ("Requested counter is not available")); + return 0; + } + + return fman_port_get_qmi_counter(&p_FmPort->port, queueType); + } + + return 0; +} + +t_Error FM_PORT_ModifyCounter(t_Handle h_FmPort, e_FmPortCounters counter, + uint32_t value) +{ + t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; + bool bmiCounter = FALSE; + enum fman_port_stats_counters statsType; + enum fman_port_perf_counters perfType; + enum fman_port_qmi_counters queueType; + bool isStats; + t_Error errCode; + + SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(!p_FmPort->p_FmPortDriverParam, E_INVALID_STATE); + + switch (counter) + { + case (e_FM_PORT_COUNTERS_DEQ_TOTAL): + case (e_FM_PORT_COUNTERS_DEQ_FROM_DEFAULT): + case (e_FM_PORT_COUNTERS_DEQ_CONFIRM): + /* check that counter is available for the port type */ + if ((p_FmPort->portType == e_FM_PORT_TYPE_RX) + || (p_FmPort->portType == e_FM_PORT_TYPE_RX_10G)) + RETURN_ERROR( + MINOR, E_INVALID_STATE, + ("Requested counter is not available for Rx ports")); + case (e_FM_PORT_COUNTERS_ENQ_TOTAL): + bmiCounter = FALSE; + break; + default: /* BMI counters (or error - will be checked in BMI routine )*/ + bmiCounter = TRUE; + break; + } + + if (bmiCounter) + { + errCode = BmiPortCheckAndGetCounterType(p_FmPort, counter, &statsType, + &perfType, &isStats); + if (errCode != E_OK) + { + RETURN_ERROR(MINOR, errCode, NO_MSG); + } + if (isStats) + fman_port_set_stats_counter(&p_FmPort->port, statsType, value); + else + fman_port_set_perf_counter(&p_FmPort->port, perfType, value); + } + else /* QMI counter */ + { + /* check that counters are enabled */ + if (!(GET_UINT32(p_FmPort->port.qmi_regs->fmqm_pnc) + & QMI_PORT_CFG_EN_COUNTERS)) + { + RETURN_ERROR(MINOR, E_INVALID_STATE, + ("Requested counter was not enabled")); + } + + /* Set counter */ + switch (counter) + { + case (e_FM_PORT_COUNTERS_ENQ_TOTAL): + queueType = E_FMAN_PORT_ENQ_TOTAL; + break; + case (e_FM_PORT_COUNTERS_DEQ_TOTAL): + queueType = E_FMAN_PORT_DEQ_TOTAL; + break; + case (e_FM_PORT_COUNTERS_DEQ_FROM_DEFAULT): + queueType = E_FMAN_PORT_DEQ_FROM_DFLT; + break; + case (e_FM_PORT_COUNTERS_DEQ_CONFIRM): + queueType = E_FMAN_PORT_DEQ_CONFIRM; + break; + default: + RETURN_ERROR(MAJOR, E_INVALID_STATE, + ("Requested counter is not available")); + } + + fman_port_set_qmi_counter(&p_FmPort->port, queueType, value); + } + + return E_OK; +} + +uint32_t FM_PORT_GetAllocBufCounter(t_Handle h_FmPort, uint8_t poolId) +{ + t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; + + SANITY_CHECK_RETURN_VALUE(p_FmPort, E_INVALID_HANDLE, 0); + SANITY_CHECK_RETURN_ERROR(!p_FmPort->p_FmPortDriverParam, E_INVALID_STATE); + + if ((p_FmPort->portType != e_FM_PORT_TYPE_RX) + && (p_FmPort->portType == e_FM_PORT_TYPE_RX_10G)) + { + REPORT_ERROR(MINOR, E_INVALID_STATE, ("Requested counter is not available for non-Rx ports")); + return 0; + } + return fman_port_get_bpool_counter(&p_FmPort->port, poolId); +} + +t_Error FM_PORT_ModifyAllocBufCounter(t_Handle h_FmPort, uint8_t poolId, + uint32_t value) +{ + t_FmPort *p_FmPort = (t_FmPort *)h_FmPort; + + SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(!p_FmPort->p_FmPortDriverParam, E_INVALID_STATE); + + if ((p_FmPort->portType != e_FM_PORT_TYPE_RX) + && (p_FmPort->portType == e_FM_PORT_TYPE_RX_10G)) + RETURN_ERROR( MINOR, E_INVALID_STATE, + ("Requested counter is not available for non-Rx ports")); + + fman_port_set_bpool_counter(&p_FmPort->port, poolId, value); + return E_OK; +} +bool FM_PORT_IsStalled(t_Handle h_FmPort) +{ + t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; + t_Error err; + bool isStalled; + + SANITY_CHECK_RETURN_VALUE(p_FmPort, E_INVALID_HANDLE, FALSE); + SANITY_CHECK_RETURN_VALUE(!p_FmPort->p_FmPortDriverParam, E_INVALID_STATE, + FALSE); + + err = FmIsPortStalled(p_FmPort->h_Fm, p_FmPort->hardwarePortId, &isStalled); + if (err != E_OK) + { + REPORT_ERROR(MAJOR, err, NO_MSG); + return TRUE; + } + return isStalled; +} + +t_Error FM_PORT_ReleaseStalled(t_Handle h_FmPort) +{ + t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; + + SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(!p_FmPort->p_FmPortDriverParam, E_INVALID_STATE); + + return FmResumeStalledPort(p_FmPort->h_Fm, p_FmPort->hardwarePortId); +} + +t_Error FM_PORT_SetRxL4ChecksumVerify(t_Handle h_FmPort, bool l4Checksum) +{ + t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; + int err; + + SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(!p_FmPort->p_FmPortDriverParam, E_INVALID_STATE); + + if ((p_FmPort->portType != e_FM_PORT_TYPE_RX_10G) + && (p_FmPort->portType != e_FM_PORT_TYPE_RX)) + RETURN_ERROR(MAJOR, E_INVALID_OPERATION, + ("available for Rx ports only")); + + if (l4Checksum) + err = fman_port_modify_rx_fd_bits( + &p_FmPort->port, (uint8_t)(BMI_PORT_RFNE_FRWD_DCL4C >> 24), + TRUE); + else + err = fman_port_modify_rx_fd_bits( + &p_FmPort->port, (uint8_t)(BMI_PORT_RFNE_FRWD_DCL4C >> 24), + FALSE); + if (err != 0) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("fman_port_modify_rx_fd_bits")); + + return E_OK; +} + +/*****************************************************************************/ +/* API Run-time PCD Control unit functions */ +/*****************************************************************************/ + +#if (DPAA_VERSION >= 11) +t_Error FM_PORT_VSPAlloc(t_Handle h_FmPort, t_FmPortVSPAllocParams *p_VSPParams) +{ + t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; + t_Error err = E_OK; + volatile uint32_t *p_BmiStorageProfileId = NULL, *p_BmiVspe = NULL; + uint32_t tmpReg = 0, tmp = 0; + uint16_t hwStoragePrflId; + + SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_FmPort->h_Fm, E_INVALID_HANDLE); + /*for numOfProfiles = 0 don't call this function*/ + SANITY_CHECK_RETURN_ERROR(p_VSPParams->numOfProfiles, E_INVALID_VALUE); + /*dfltRelativeId should be in the range of numOfProfiles*/ + SANITY_CHECK_RETURN_ERROR( + p_VSPParams->dfltRelativeId < p_VSPParams->numOfProfiles, + E_INVALID_VALUE); + /*p_FmPort should be from Rx type or OP*/ + SANITY_CHECK_RETURN_ERROR( + ((p_FmPort->portType == e_FM_PORT_TYPE_RX_10G) || (p_FmPort->portType == e_FM_PORT_TYPE_RX) || (p_FmPort->portType == e_FM_PORT_TYPE_OH_OFFLINE_PARSING)), + E_INVALID_VALUE); + /*port should be disabled*/ + SANITY_CHECK_RETURN_ERROR(!p_FmPort->enabled, E_INVALID_STATE); + /*if its called for Rx port relevant Tx Port should be passed (initialized) too and it should be disabled*/ + SANITY_CHECK_RETURN_ERROR( + ((p_VSPParams->h_FmTxPort && !((t_FmPort *)(p_VSPParams->h_FmTxPort))->enabled) || (p_FmPort->portType == e_FM_PORT_TYPE_OH_OFFLINE_PARSING)), + E_INVALID_VALUE); + /*should be called before SetPCD - this port should be without PCD*/ + SANITY_CHECK_RETURN_ERROR(!p_FmPort->pcdEngines, E_INVALID_STATE); + + /*alloc window of VSPs for this port*/ + err = FmVSPAllocForPort(p_FmPort->h_Fm, p_FmPort->portType, + p_FmPort->portId, p_VSPParams->numOfProfiles); + if (err != E_OK) + RETURN_ERROR(MAJOR, err, NO_MSG); + + /*get absolute VSP ID for dfltRelative*/ + err = FmVSPGetAbsoluteProfileId(p_FmPort->h_Fm, p_FmPort->portType, + p_FmPort->portId, + p_VSPParams->dfltRelativeId, + &hwStoragePrflId); + if (err != E_OK) + RETURN_ERROR(MAJOR, err, NO_MSG); + + /*fill relevant registers for p_FmPort and relative TxPort in the case p_FmPort from Rx type*/ + switch (p_FmPort->portType) + { + case (e_FM_PORT_TYPE_RX_10G): + case (e_FM_PORT_TYPE_RX): + p_BmiStorageProfileId = + &(((t_FmPort *)(p_VSPParams->h_FmTxPort))->p_FmPortBmiRegs->txPortBmiRegs.fmbm_tcfqid); + p_BmiVspe = + &(((t_FmPort *)(p_VSPParams->h_FmTxPort))->p_FmPortBmiRegs->txPortBmiRegs.fmbm_tfne); + + tmpReg = GET_UINT32(*p_BmiStorageProfileId) & ~BMI_SP_ID_MASK; + tmpReg |= (uint32_t)hwStoragePrflId << BMI_SP_ID_SHIFT; + WRITE_UINT32(*p_BmiStorageProfileId, tmpReg); + + tmpReg = GET_UINT32(*p_BmiVspe); + WRITE_UINT32(*p_BmiVspe, tmpReg | BMI_SP_EN); + + p_BmiStorageProfileId = + &p_FmPort->p_FmPortBmiRegs->rxPortBmiRegs.fmbm_rfqid; + p_BmiVspe = &p_FmPort->p_FmPortBmiRegs->rxPortBmiRegs.fmbm_rpp; + hwStoragePrflId = p_VSPParams->dfltRelativeId; + break; + + case (e_FM_PORT_TYPE_OH_OFFLINE_PARSING): + tmpReg = NIA_ENG_BMI | NIA_BMI_AC_FETCH_ALL_FRAME; + WRITE_UINT32( p_FmPort->p_FmPortQmiRegs->nonRxQmiRegs.fmqm_pndn, + tmpReg); + + p_BmiStorageProfileId = + &p_FmPort->p_FmPortBmiRegs->ohPortBmiRegs.fmbm_ofqid; + p_BmiVspe = &p_FmPort->p_FmPortBmiRegs->ohPortBmiRegs.fmbm_opp; + tmp |= BMI_EBD_EN; + break; + + default: + RETURN_ERROR( MAJOR, E_INVALID_OPERATION, + ("available for Rx and offline parsing ports only")); + } + + p_FmPort->vspe = TRUE; + p_FmPort->dfltRelativeId = p_VSPParams->dfltRelativeId; + + tmpReg = GET_UINT32(*p_BmiStorageProfileId) & ~BMI_SP_ID_MASK; + tmpReg |= (uint32_t)hwStoragePrflId << BMI_SP_ID_SHIFT; + WRITE_UINT32(*p_BmiStorageProfileId, tmpReg); + + tmpReg = GET_UINT32(*p_BmiVspe); + WRITE_UINT32(*p_BmiVspe, tmpReg | BMI_SP_EN | tmp); + return E_OK; +} +#endif /* (DPAA_VERSION >= 11) */ + +t_Error FM_PORT_PcdPlcrAllocProfiles(t_Handle h_FmPort, uint16_t numOfProfiles) +{ + t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; + t_Error err = E_OK; + + p_FmPort->h_FmPcd = FmGetPcdHandle(p_FmPort->h_Fm); + ASSERT_COND(p_FmPort->h_FmPcd); + + if (!TRY_LOCK(p_FmPort->h_Spinlock, &p_FmPort->lock)) + { + DBG(TRACE, ("FM Port Try Lock - BUSY")); + return ERROR_CODE(E_BUSY); + } + + if (numOfProfiles) + { + err = FmPcdPlcrAllocProfiles(p_FmPort->h_FmPcd, + p_FmPort->hardwarePortId, numOfProfiles); + if (err) + RETURN_ERROR(MAJOR, err, NO_MSG); + } + /* set the port handle within the PCD policer, even if no profiles defined */ + FmPcdPortRegister(p_FmPort->h_FmPcd, h_FmPort, p_FmPort->hardwarePortId); + + RELEASE_LOCK(p_FmPort->lock); + + return E_OK; +} + +t_Error FM_PORT_PcdPlcrFreeProfiles(t_Handle h_FmPort) +{ + t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; + t_Error err = E_OK; + + if (!TRY_LOCK(p_FmPort->h_Spinlock, &p_FmPort->lock)) + { + DBG(TRACE, ("FM Port Try Lock - BUSY")); + return ERROR_CODE(E_BUSY); + } + + err = FmPcdPlcrFreeProfiles(p_FmPort->h_FmPcd, p_FmPort->hardwarePortId); + + RELEASE_LOCK(p_FmPort->lock); + + if (err) + RETURN_ERROR(MAJOR, err, NO_MSG); + + return E_OK; +} + +t_Error FM_PORT_PcdKgModifyInitialScheme(t_Handle h_FmPort, + t_FmPcdKgSchemeSelect *p_FmPcdKgScheme) +{ + t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; + volatile uint32_t *p_BmiHpnia = NULL; + uint32_t tmpReg; + uint8_t relativeSchemeId; + uint8_t physicalSchemeId; + + SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(!p_FmPort->p_FmPortDriverParam, E_INVALID_STATE); + SANITY_CHECK_RETURN_ERROR(p_FmPort->pcdEngines & FM_PCD_KG, + E_INVALID_STATE); + + tmpReg = (uint32_t)((p_FmPort->pcdEngines & FM_PCD_CC) ? NIA_KG_CC_EN : 0); + switch (p_FmPort->portType) + { + case (e_FM_PORT_TYPE_RX_10G): + case (e_FM_PORT_TYPE_RX): + p_BmiHpnia = &p_FmPort->port.bmi_regs->rx.fmbm_rfpne; + break; + case (e_FM_PORT_TYPE_OH_OFFLINE_PARSING): + p_BmiHpnia = &p_FmPort->port.bmi_regs->oh.fmbm_ofpne; + break; + default: + RETURN_ERROR( MAJOR, E_INVALID_OPERATION, + ("available for Rx and offline parsing ports only")); + } + + if (!TRY_LOCK(p_FmPort->h_Spinlock, &p_FmPort->lock)) + { + DBG(TRACE, ("FM Port Try Lock - BUSY")); + return ERROR_CODE(E_BUSY); + } + + /* if we want to change to direct scheme, we need to check that this scheme is valid */ + if (p_FmPcdKgScheme->direct) + { + physicalSchemeId = FmPcdKgGetSchemeId(p_FmPcdKgScheme->h_DirectScheme); + /* check that this scheme is bound to this port */ + if (!(p_FmPort->schemesPerPortVector + & (uint32_t)(1 << (31 - (uint32_t)physicalSchemeId)))) + { + RELEASE_LOCK(p_FmPort->lock); + RETURN_ERROR( + MAJOR, E_INVALID_STATE, + ("called with a scheme that is not bound to this port")); + } + + relativeSchemeId = FmPcdKgGetRelativeSchemeId(p_FmPort->h_FmPcd, + physicalSchemeId); + if (relativeSchemeId >= FM_PCD_KG_NUM_OF_SCHEMES) + { + RELEASE_LOCK(p_FmPort->lock); + RETURN_ERROR(MAJOR, E_NOT_IN_RANGE, + ("called with invalid Scheme ")); + } + + if (!FmPcdKgIsSchemeValidSw(p_FmPcdKgScheme->h_DirectScheme)) + { + RELEASE_LOCK(p_FmPort->lock); + RETURN_ERROR(MAJOR, E_INVALID_STATE, + ("called with uninitialized Scheme ")); + } + + WRITE_UINT32( + *p_BmiHpnia, + NIA_ENG_KG | tmpReg | NIA_KG_DIRECT | (uint32_t)physicalSchemeId); + } + else + /* change to indirect scheme */ + WRITE_UINT32(*p_BmiHpnia, NIA_ENG_KG | tmpReg); + RELEASE_LOCK(p_FmPort->lock); + + return E_OK; +} + +t_Error FM_PORT_PcdPlcrModifyInitialProfile(t_Handle h_FmPort, + t_Handle h_Profile) +{ + t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; + volatile uint32_t *p_BmiNia; + volatile uint32_t *p_BmiHpnia; + uint32_t tmpReg; + uint16_t absoluteProfileId = FmPcdPlcrProfileGetAbsoluteId(h_Profile); + + SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(!p_FmPort->p_FmPortDriverParam, E_INVALID_STATE); + SANITY_CHECK_RETURN_ERROR(p_FmPort->pcdEngines & FM_PCD_PLCR, + E_INVALID_STATE); + + /* check relevance of this routine - only when policer is used + directly after BMI or Parser */ + if ((p_FmPort->pcdEngines & FM_PCD_KG) + || (p_FmPort->pcdEngines & FM_PCD_CC)) + RETURN_ERROR( + MAJOR, + E_INVALID_STATE, + ("relevant only when PCD support mode is e_FM_PCD_SUPPORT_PLCR_ONLY or e_FM_PCD_SUPPORT_PRS_AND_PLCR")); + + switch (p_FmPort->portType) + { + case (e_FM_PORT_TYPE_RX_10G): + case (e_FM_PORT_TYPE_RX): + p_BmiNia = &p_FmPort->port.bmi_regs->rx.fmbm_rfne; + p_BmiHpnia = &p_FmPort->port.bmi_regs->rx.fmbm_rfpne; + tmpReg = GET_UINT32(*p_BmiNia) & BMI_RFNE_FDCS_MASK; + break; + case (e_FM_PORT_TYPE_OH_OFFLINE_PARSING): + p_BmiNia = &p_FmPort->port.bmi_regs->oh.fmbm_ofne; + p_BmiHpnia = &p_FmPort->port.bmi_regs->oh.fmbm_ofpne; + tmpReg = 0; + break; + default: + RETURN_ERROR( MAJOR, E_INVALID_OPERATION, + ("available for Rx and offline parsing ports only")); + } + + if (!TRY_LOCK(p_FmPort->h_Spinlock, &p_FmPort->lock)) + { + DBG(TRACE, ("FM Port Try Lock - BUSY")); + return ERROR_CODE(E_BUSY); + } + + if (!FmPcdPlcrIsProfileValid(p_FmPort->h_FmPcd, absoluteProfileId)) + { + RELEASE_LOCK(p_FmPort->lock); + RETURN_ERROR(MAJOR, E_INVALID_OPERATION, ("Invalid profile")); + } + + tmpReg |= (uint32_t)(NIA_ENG_PLCR | NIA_PLCR_ABSOLUTE | absoluteProfileId); + + if (p_FmPort->pcdEngines & FM_PCD_PRS) /* e_FM_PCD_SUPPORT_PRS_AND_PLCR */ + { + /* update BMI HPNIA */ + WRITE_UINT32(*p_BmiHpnia, tmpReg); + } + else /* e_FM_PCD_SUPPORT_PLCR_ONLY */ + { + /* rfne may contain FDCS bits, so first we read them. */ + tmpReg |= (GET_UINT32(*p_BmiNia) & BMI_RFNE_FDCS_MASK); + /* update BMI NIA */ + WRITE_UINT32(*p_BmiNia, tmpReg); + }RELEASE_LOCK(p_FmPort->lock); + + return E_OK; +} + +t_Error FM_PORT_PcdCcModifyTree(t_Handle h_FmPort, t_Handle h_CcTree) +{ + t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; + t_Error err = E_OK; + volatile uint32_t *p_BmiCcBase = NULL; + volatile uint32_t *p_BmiNia = NULL; + uint32_t ccTreePhysOffset; + + SANITY_CHECK_RETURN_ERROR(h_FmPort, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(h_CcTree, E_INVALID_HANDLE); + + if (p_FmPort->imEn) + RETURN_ERROR(MAJOR, E_INVALID_OPERATION, + ("available for non-independent mode ports only")); + + /* get PCD registers pointers */ + switch (p_FmPort->portType) + { + case (e_FM_PORT_TYPE_RX_10G): + case (e_FM_PORT_TYPE_RX): + p_BmiNia = &p_FmPort->port.bmi_regs->rx.fmbm_rfne; + break; + case (e_FM_PORT_TYPE_OH_OFFLINE_PARSING): + p_BmiNia = &p_FmPort->port.bmi_regs->oh.fmbm_ofne; + break; + default: + RETURN_ERROR( MAJOR, E_INVALID_OPERATION, + ("available for Rx and offline parsing ports only")); + } + + /* check that current NIA is BMI to BMI */ + if ((GET_UINT32(*p_BmiNia) & ~BMI_RFNE_FDCS_MASK) + != GET_NIA_BMI_AC_ENQ_FRAME(p_FmPort->h_FmPcd)) + RETURN_ERROR( MAJOR, E_INVALID_OPERATION, + ("may be called only for ports in BMI-to-BMI state.")); + + if (p_FmPort->pcdEngines & FM_PCD_CC) + { + if (p_FmPort->h_IpReassemblyManip) + { + err = FmPcdCcTreeAddIPR(p_FmPort->h_FmPcd, h_CcTree, NULL, + p_FmPort->h_IpReassemblyManip, FALSE); + if (err != E_OK) + { + RETURN_ERROR(MAJOR, err, NO_MSG); + } + } + else + if (p_FmPort->h_CapwapReassemblyManip) + { + err = FmPcdCcTreeAddCPR(p_FmPort->h_FmPcd, h_CcTree, NULL, + p_FmPort->h_CapwapReassemblyManip, + FALSE); + if (err != E_OK) + { + RETURN_ERROR(MAJOR, err, NO_MSG); + } + } + switch (p_FmPort->portType) + { + case (e_FM_PORT_TYPE_RX_10G): + case (e_FM_PORT_TYPE_RX): + p_BmiCcBase = &p_FmPort->port.bmi_regs->rx.fmbm_rccb; + break; + case (e_FM_PORT_TYPE_OH_OFFLINE_PARSING): + p_BmiCcBase = &p_FmPort->port.bmi_regs->oh.fmbm_occb; + break; + default: + RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Invalid port type")); + } + + if (!TRY_LOCK(p_FmPort->h_Spinlock, &p_FmPort->lock)) + { + DBG(TRACE, ("FM Port Try Lock - BUSY")); + return ERROR_CODE(E_BUSY); + } + err = FmPcdCcBindTree(p_FmPort->h_FmPcd, NULL, h_CcTree, + &ccTreePhysOffset, h_FmPort); + if (err) + { + RELEASE_LOCK(p_FmPort->lock); + RETURN_ERROR(MAJOR, err, NO_MSG); + }WRITE_UINT32(*p_BmiCcBase, ccTreePhysOffset); + + p_FmPort->ccTreeId = h_CcTree; + RELEASE_LOCK(p_FmPort->lock); + } + else + RETURN_ERROR( MAJOR, E_INVALID_STATE, + ("Coarse Classification not defined for this port.")); + + return E_OK; +} + +t_Error FM_PORT_AttachPCD(t_Handle h_FmPort) +{ + t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; + t_Error err = E_OK; + + SANITY_CHECK_RETURN_ERROR(h_FmPort, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(!p_FmPort->p_FmPortDriverParam, E_INVALID_STATE); + + if (p_FmPort->imEn) + RETURN_ERROR(MAJOR, E_INVALID_OPERATION, + ("available for non-independent mode ports only")); + + if ((p_FmPort->portType != e_FM_PORT_TYPE_RX_10G) + && (p_FmPort->portType != e_FM_PORT_TYPE_RX) + && (p_FmPort->portType != e_FM_PORT_TYPE_OH_OFFLINE_PARSING)) + RETURN_ERROR( MAJOR, E_INVALID_OPERATION, + ("available for Rx and offline parsing ports only")); + + if (!TRY_LOCK(p_FmPort->h_Spinlock, &p_FmPort->lock)) + { + DBG(TRACE, ("FM Port Try Lock - BUSY")); + return ERROR_CODE(E_BUSY); + } + + if (p_FmPort->h_ReassemblyTree) + p_FmPort->pcdEngines |= FM_PCD_CC; + + err = AttachPCD(h_FmPort); + RELEASE_LOCK(p_FmPort->lock); + + return err; +} + +t_Error FM_PORT_DetachPCD(t_Handle h_FmPort) +{ + t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; + t_Error err = E_OK; + + SANITY_CHECK_RETURN_ERROR(h_FmPort, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(!p_FmPort->p_FmPortDriverParam, E_INVALID_STATE); + + if (p_FmPort->imEn) + RETURN_ERROR(MAJOR, E_INVALID_OPERATION, + ("available for non-independent mode ports only")); + + if ((p_FmPort->portType != e_FM_PORT_TYPE_RX_10G) + && (p_FmPort->portType != e_FM_PORT_TYPE_RX) + && (p_FmPort->portType != e_FM_PORT_TYPE_OH_OFFLINE_PARSING)) + RETURN_ERROR( MAJOR, E_INVALID_OPERATION, + ("available for Rx and offline parsing ports only")); + + if (!TRY_LOCK(p_FmPort->h_Spinlock, &p_FmPort->lock)) + { + DBG(TRACE, ("FM Port Try Lock - BUSY")); + return ERROR_CODE(E_BUSY); + } + + err = DetachPCD(h_FmPort); + if (err != E_OK) + { + RELEASE_LOCK(p_FmPort->lock); + RETURN_ERROR(MAJOR, err, NO_MSG); + } + + if (p_FmPort->h_ReassemblyTree) + p_FmPort->pcdEngines &= ~FM_PCD_CC; + RELEASE_LOCK(p_FmPort->lock); + + return E_OK; +} + +t_Error FM_PORT_SetPCD(t_Handle h_FmPort, t_FmPortPcdParams *p_PcdParam) +{ + t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; + t_Error err = E_OK; + t_FmPortPcdParams modifiedPcdParams, *p_PcdParams; + t_FmPcdCcTreeParams *p_FmPcdCcTreeParams; + t_FmPortPcdCcParams fmPortPcdCcParams; + t_FmPortGetSetCcParams fmPortGetSetCcParams; + + SANITY_CHECK_RETURN_ERROR(h_FmPort, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_PcdParam, E_NULL_POINTER); + SANITY_CHECK_RETURN_ERROR(!p_FmPort->p_FmPortDriverParam, E_INVALID_STATE); + + if (p_FmPort->imEn) + RETURN_ERROR(MAJOR, E_INVALID_OPERATION, + ("available for non-independent mode ports only")); + + if ((p_FmPort->portType != e_FM_PORT_TYPE_RX_10G) + && (p_FmPort->portType != e_FM_PORT_TYPE_RX) + && (p_FmPort->portType != e_FM_PORT_TYPE_OH_OFFLINE_PARSING)) + RETURN_ERROR( MAJOR, E_INVALID_OPERATION, + ("available for Rx and offline parsing ports only")); + + if (!TRY_LOCK(p_FmPort->h_Spinlock, &p_FmPort->lock)) + { + DBG(TRACE, ("FM Port Try Lock - BUSY")); + return ERROR_CODE(E_BUSY); + } + + p_FmPort->h_FmPcd = FmGetPcdHandle(p_FmPort->h_Fm); + ASSERT_COND(p_FmPort->h_FmPcd); + + if (p_PcdParam->p_CcParams && !p_PcdParam->p_CcParams->h_CcTree) + RETURN_ERROR(MAJOR, E_INVALID_HANDLE, + ("Tree handle must be given if CC is required")); + + memcpy(&modifiedPcdParams, p_PcdParam, sizeof(t_FmPortPcdParams)); + p_PcdParams = &modifiedPcdParams; + if ((p_PcdParams->h_IpReassemblyManip) +#if (DPAA_VERSION >= 11) + || (p_PcdParams->h_CapwapReassemblyManip) +#endif /* (DPAA_VERSION >= 11) */ + ) + { + if ((p_PcdParams->pcdSupport != e_FM_PORT_PCD_SUPPORT_PRS_AND_KG) + && (p_PcdParams->pcdSupport + != e_FM_PORT_PCD_SUPPORT_PRS_AND_KG_AND_CC) + && (p_PcdParams->pcdSupport + != e_FM_PORT_PCD_SUPPORT_PRS_AND_KG_AND_CC_AND_PLCR) + && (p_PcdParams->pcdSupport + != e_FM_PORT_PCD_SUPPORT_PRS_AND_KG_AND_PLCR)) + { + RELEASE_LOCK(p_FmPort->lock); + RETURN_ERROR( MAJOR, E_INVALID_STATE, + ("pcdSupport must have KG for supporting Reassembly")); + } + p_FmPort->h_IpReassemblyManip = p_PcdParams->h_IpReassemblyManip; +#if (DPAA_VERSION >= 11) + if ((p_PcdParams->h_IpReassemblyManip) + && (p_PcdParams->h_CapwapReassemblyManip)) + RETURN_ERROR(MAJOR, E_INVALID_STATE, + ("Either IP-R or CAPWAP-R is allowed")); + if ((p_PcdParams->h_CapwapReassemblyManip) + && (p_FmPort->portType != e_FM_PORT_TYPE_OH_OFFLINE_PARSING)) + RETURN_ERROR(MAJOR, E_INVALID_STATE, + ("CAPWAP-R is allowed only on offline-port")); + if (p_PcdParams->h_CapwapReassemblyManip) + p_FmPort->h_CapwapReassemblyManip = + p_PcdParams->h_CapwapReassemblyManip; +#endif /* (DPAA_VERSION >= 11) */ + + if (!p_PcdParams->p_CcParams) + { + if (!((p_PcdParams->pcdSupport == e_FM_PORT_PCD_SUPPORT_PRS_AND_KG) + || (p_PcdParams->pcdSupport + == e_FM_PORT_PCD_SUPPORT_PRS_AND_KG_AND_PLCR))) + { + RELEASE_LOCK(p_FmPort->lock); + RETURN_ERROR( + MAJOR, + E_INVALID_STATE, + ("PCD initialization structure is not consistent with pcdSupport")); + } + + /* No user-tree, need to build internal tree */ + p_FmPcdCcTreeParams = (t_FmPcdCcTreeParams*)XX_Malloc( + sizeof(t_FmPcdCcTreeParams)); + if (!p_FmPcdCcTreeParams) + RETURN_ERROR(MAJOR, E_NO_MEMORY, ("p_FmPcdCcTreeParams")); + memset(p_FmPcdCcTreeParams, 0, sizeof(t_FmPcdCcTreeParams)); + p_FmPcdCcTreeParams->h_NetEnv = p_PcdParams->h_NetEnv; + p_FmPort->h_ReassemblyTree = FM_PCD_CcRootBuild( + p_FmPort->h_FmPcd, p_FmPcdCcTreeParams); + + if (!p_FmPort->h_ReassemblyTree) + { + RELEASE_LOCK(p_FmPort->lock); + XX_Free(p_FmPcdCcTreeParams); + RETURN_ERROR( MAJOR, E_INVALID_HANDLE, + ("FM_PCD_CcBuildTree for Reassembly failed")); + } + if (p_PcdParams->pcdSupport == e_FM_PORT_PCD_SUPPORT_PRS_AND_KG) + p_PcdParams->pcdSupport = + e_FM_PORT_PCD_SUPPORT_PRS_AND_KG_AND_CC; + else + p_PcdParams->pcdSupport = + e_FM_PORT_PCD_SUPPORT_PRS_AND_KG_AND_CC_AND_PLCR; + + memset(&fmPortPcdCcParams, 0, sizeof(t_FmPortPcdCcParams)); + fmPortPcdCcParams.h_CcTree = p_FmPort->h_ReassemblyTree; + p_PcdParams->p_CcParams = &fmPortPcdCcParams; + XX_Free(p_FmPcdCcTreeParams); + } + + if (p_FmPort->h_IpReassemblyManip) + err = FmPcdCcTreeAddIPR(p_FmPort->h_FmPcd, + p_PcdParams->p_CcParams->h_CcTree, + p_PcdParams->h_NetEnv, + p_FmPort->h_IpReassemblyManip, TRUE); +#if (DPAA_VERSION >= 11) + else + if (p_FmPort->h_CapwapReassemblyManip) + err = FmPcdCcTreeAddCPR(p_FmPort->h_FmPcd, + p_PcdParams->p_CcParams->h_CcTree, + p_PcdParams->h_NetEnv, + p_FmPort->h_CapwapReassemblyManip, + TRUE); +#endif /* (DPAA_VERSION >= 11) */ + + if (err != E_OK) + { + if (p_FmPort->h_ReassemblyTree) + { + FM_PCD_CcRootDelete(p_FmPort->h_ReassemblyTree); + p_FmPort->h_ReassemblyTree = NULL; + }RELEASE_LOCK(p_FmPort->lock); + RETURN_ERROR(MAJOR, err, NO_MSG); + } + } + + if (!FmPcdLockTryLockAll(p_FmPort->h_FmPcd)) + { + if (p_FmPort->h_ReassemblyTree) + { + FM_PCD_CcRootDelete(p_FmPort->h_ReassemblyTree); + p_FmPort->h_ReassemblyTree = NULL; + }RELEASE_LOCK(p_FmPort->lock); + DBG(TRACE, ("Try LockAll - BUSY")); + return ERROR_CODE(E_BUSY); + } + + err = SetPcd(h_FmPort, p_PcdParams); + if (err) + { + if (p_FmPort->h_ReassemblyTree) + { + FM_PCD_CcRootDelete(p_FmPort->h_ReassemblyTree); + p_FmPort->h_ReassemblyTree = NULL; + } + FmPcdLockUnlockAll(p_FmPort->h_FmPcd); + RELEASE_LOCK(p_FmPort->lock); + RETURN_ERROR(MAJOR, err, NO_MSG); + } + + if ((p_FmPort->pcdEngines & FM_PCD_PRS) + && (p_PcdParams->p_PrsParams->includeInPrsStatistics)) + { + err = FmPcdPrsIncludePortInStatistics(p_FmPort->h_FmPcd, + p_FmPort->hardwarePortId, TRUE); + if (err) + { + DeletePcd(p_FmPort); + if (p_FmPort->h_ReassemblyTree) + { + FM_PCD_CcRootDelete(p_FmPort->h_ReassemblyTree); + p_FmPort->h_ReassemblyTree = NULL; + } + FmPcdLockUnlockAll(p_FmPort->h_FmPcd); + RELEASE_LOCK(p_FmPort->lock); + RETURN_ERROR(MAJOR, err, NO_MSG); + } + p_FmPort->includeInPrsStatistics = TRUE; + } + + FmPcdIncNetEnvOwners(p_FmPort->h_FmPcd, p_FmPort->netEnvId); + + if (FmPcdIsAdvancedOffloadSupported(p_FmPort->h_FmPcd)) + { + memset(&fmPortGetSetCcParams, 0, sizeof(t_FmPortGetSetCcParams)); + + if (p_FmPort->portType == e_FM_PORT_TYPE_OH_OFFLINE_PARSING) + { +#ifdef FM_KG_ERASE_FLOW_ID_ERRATA_FMAN_SW004 + if ((p_FmPort->fmRevInfo.majorRev < 6) && + (p_FmPort->pcdEngines & FM_PCD_KG)) + { + int i; + for (i = 0; i<p_PcdParams->p_KgParams->numOfSchemes; i++) + /* The following function must be locked */ + FmPcdKgCcGetSetParams(p_FmPort->h_FmPcd, + p_PcdParams->p_KgParams->h_Schemes[i], + UPDATE_KG_NIA_CC_WA, + 0); + } +#endif /* FM_KG_ERASE_FLOW_ID_ERRATA_FMAN_SW004 */ + +#if (DPAA_VERSION >= 11) + { + t_FmPcdCtrlParamsPage *p_ParamsPage; + + FmPortSetGprFunc(p_FmPort, e_FM_PORT_GPR_MURAM_PAGE, + (void**)&p_ParamsPage); + ASSERT_COND(p_ParamsPage); + WRITE_UINT32(p_ParamsPage->postBmiFetchNia, + p_FmPort->savedBmiNia); + } +#endif /* (DPAA_VERSION >= 11) */ + + /* Set post-bmi-fetch nia */ + p_FmPort->savedBmiNia &= BMI_RFNE_FDCS_MASK; + p_FmPort->savedBmiNia |= (NIA_FM_CTL_AC_POST_BMI_FETCH + | NIA_ENG_FM_CTL); + + /* Set pre-bmi-fetch nia */ + fmPortGetSetCcParams.setCcParams.type = UPDATE_NIA_PNDN; +#if (DPAA_VERSION >= 11) + fmPortGetSetCcParams.setCcParams.nia = + (NIA_FM_CTL_AC_PRE_BMI_FETCH_FULL_FRAME | NIA_ENG_FM_CTL); +#else + fmPortGetSetCcParams.setCcParams.nia = (NIA_FM_CTL_AC_PRE_BMI_FETCH_HEADER | NIA_ENG_FM_CTL); +#endif /* (DPAA_VERSION >= 11) */ + if ((err = FmPortGetSetCcParams(p_FmPort, &fmPortGetSetCcParams)) + != E_OK) + { + DeletePcd(p_FmPort); + if (p_FmPort->h_ReassemblyTree) + { + FM_PCD_CcRootDelete(p_FmPort->h_ReassemblyTree); + p_FmPort->h_ReassemblyTree = NULL; + } + FmPcdLockUnlockAll(p_FmPort->h_FmPcd); + RELEASE_LOCK(p_FmPort->lock); + RETURN_ERROR(MAJOR, err, NO_MSG); + } + } + + FmPcdLockUnlockAll(p_FmPort->h_FmPcd); + + /* Set pop-to-next-step nia */ +#if (DPAA_VERSION == 10) + if (p_FmPort->fmRevInfo.majorRev < 6) + { + fmPortGetSetCcParams.setCcParams.type = UPDATE_NIA_PNEN; + fmPortGetSetCcParams.setCcParams.nia = NIA_FM_CTL_AC_POP_TO_N_STEP | NIA_ENG_FM_CTL; + } + else + { +#endif /* (DPAA_VERSION == 10) */ + fmPortGetSetCcParams.getCcParams.type = GET_NIA_FPNE; +#if (DPAA_VERSION == 10) + } +#endif /* (DPAA_VERSION == 10) */ + if ((err = FmPortGetSetCcParams(h_FmPort, &fmPortGetSetCcParams)) + != E_OK) + { + DeletePcd(p_FmPort); + if (p_FmPort->h_ReassemblyTree) + { + FM_PCD_CcRootDelete(p_FmPort->h_ReassemblyTree); + p_FmPort->h_ReassemblyTree = NULL; + }RELEASE_LOCK(p_FmPort->lock); + RETURN_ERROR(MAJOR, err, NO_MSG); + } + + /* Set post-bmi-prepare-to-enq nia */ + fmPortGetSetCcParams.setCcParams.type = UPDATE_NIA_FENE; + fmPortGetSetCcParams.setCcParams.nia = (NIA_FM_CTL_AC_POST_BMI_ENQ + | NIA_ENG_FM_CTL); + if ((err = FmPortGetSetCcParams(h_FmPort, &fmPortGetSetCcParams)) + != E_OK) + { + DeletePcd(p_FmPort); + if (p_FmPort->h_ReassemblyTree) + { + FM_PCD_CcRootDelete(p_FmPort->h_ReassemblyTree); + p_FmPort->h_ReassemblyTree = NULL; + }RELEASE_LOCK(p_FmPort->lock); + RETURN_ERROR(MAJOR, err, NO_MSG); + } + + if ((p_FmPort->h_IpReassemblyManip) + || (p_FmPort->h_CapwapReassemblyManip)) + { +#if (DPAA_VERSION == 10) + if (p_FmPort->fmRevInfo.majorRev < 6) + { + /* Overwrite post-bmi-prepare-to-enq nia */ + fmPortGetSetCcParams.setCcParams.type = UPDATE_NIA_FENE; + fmPortGetSetCcParams.setCcParams.nia = (NIA_FM_CTL_AC_POST_BMI_ENQ_ORR | NIA_ENG_FM_CTL | NIA_ORDER_RESTOR); + fmPortGetSetCcParams.setCcParams.overwrite = TRUE; + } + else + { +#endif /* (DPAA_VERSION == 10) */ + /* Set the ORR bit (for order-restoration) */ + fmPortGetSetCcParams.setCcParams.type = UPDATE_NIA_FPNE; + fmPortGetSetCcParams.setCcParams.nia = + fmPortGetSetCcParams.getCcParams.nia | NIA_ORDER_RESTOR; +#if (DPAA_VERSION == 10) + } +#endif /* (DPAA_VERSION == 10) */ + if ((err = FmPortGetSetCcParams(h_FmPort, &fmPortGetSetCcParams)) + != E_OK) + { + DeletePcd(p_FmPort); + if (p_FmPort->h_ReassemblyTree) + { + FM_PCD_CcRootDelete(p_FmPort->h_ReassemblyTree); + p_FmPort->h_ReassemblyTree = NULL; + }RELEASE_LOCK(p_FmPort->lock); + RETURN_ERROR(MAJOR, err, NO_MSG); + } + } + } + else + FmPcdLockUnlockAll(p_FmPort->h_FmPcd); + +#if (DPAA_VERSION >= 11) + { + t_FmPcdCtrlParamsPage *p_ParamsPage; + + memset(&fmPortGetSetCcParams, 0, sizeof(t_FmPortGetSetCcParams)); + + fmPortGetSetCcParams.setCcParams.type = UPDATE_NIA_CMNE; + if (FmPcdIsAdvancedOffloadSupported(p_FmPort->h_FmPcd)) + fmPortGetSetCcParams.setCcParams.nia = NIA_FM_CTL_AC_POP_TO_N_STEP + | NIA_ENG_FM_CTL; + else + fmPortGetSetCcParams.setCcParams.nia = + NIA_FM_CTL_AC_NO_IPACC_POP_TO_N_STEP | NIA_ENG_FM_CTL; + if ((err = FmPortGetSetCcParams(h_FmPort, &fmPortGetSetCcParams)) + != E_OK) + { + DeletePcd(p_FmPort); + if (p_FmPort->h_ReassemblyTree) + { + FM_PCD_CcRootDelete(p_FmPort->h_ReassemblyTree); + p_FmPort->h_ReassemblyTree = NULL; + }RELEASE_LOCK(p_FmPort->lock); + RETURN_ERROR(MAJOR, err, NO_MSG); + } + + FmPortSetGprFunc(p_FmPort, e_FM_PORT_GPR_MURAM_PAGE, + (void**)&p_ParamsPage); + ASSERT_COND(p_ParamsPage); + + if (FmPcdIsAdvancedOffloadSupported(p_FmPort->h_FmPcd)) + WRITE_UINT32( + p_ParamsPage->misc, + GET_UINT32(p_ParamsPage->misc) | FM_CTL_PARAMS_PAGE_OFFLOAD_SUPPORT_EN); + + if ((p_FmPort->h_IpReassemblyManip) + || (p_FmPort->h_CapwapReassemblyManip)) + { + if (p_FmPort->portType == e_FM_PORT_TYPE_OH_OFFLINE_PARSING) + WRITE_UINT32( + p_ParamsPage->discardMask, + GET_UINT32(p_FmPort->p_FmPortBmiRegs->ohPortBmiRegs.fmbm_ofsdm)); + else + WRITE_UINT32( + p_ParamsPage->discardMask, + GET_UINT32(p_FmPort->p_FmPortBmiRegs->rxPortBmiRegs.fmbm_rfsdm)); + } +#ifdef FM_ERROR_VSP_NO_MATCH_SW006 + if (p_FmPort->vspe) + WRITE_UINT32( + p_ParamsPage->misc, + GET_UINT32(p_ParamsPage->misc) | (p_FmPort->dfltRelativeId & FM_CTL_PARAMS_PAGE_ERROR_VSP_MASK)); +#endif /* FM_ERROR_VSP_NO_MATCH_SW006 */ + } +#endif /* (DPAA_VERSION >= 11) */ + + err = AttachPCD(h_FmPort); + if (err) + { + DeletePcd(p_FmPort); + if (p_FmPort->h_ReassemblyTree) + { + FM_PCD_CcRootDelete(p_FmPort->h_ReassemblyTree); + p_FmPort->h_ReassemblyTree = NULL; + }RELEASE_LOCK(p_FmPort->lock); + RETURN_ERROR(MAJOR, err, NO_MSG); + } + + RELEASE_LOCK(p_FmPort->lock); + + return err; +} + +t_Error FM_PORT_DeletePCD(t_Handle h_FmPort) +{ + t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; + t_Error err = E_OK; + + SANITY_CHECK_RETURN_ERROR(h_FmPort, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(!p_FmPort->p_FmPortDriverParam, E_INVALID_STATE); + + if (p_FmPort->imEn) + RETURN_ERROR(MAJOR, E_INVALID_OPERATION, + ("available for non-independant mode ports only")); + + if ((p_FmPort->portType != e_FM_PORT_TYPE_RX_10G) + && (p_FmPort->portType != e_FM_PORT_TYPE_RX) + && (p_FmPort->portType != e_FM_PORT_TYPE_OH_OFFLINE_PARSING)) + RETURN_ERROR( MAJOR, E_INVALID_OPERATION, + ("available for Rx and offline parsing ports only")); + + if (!TRY_LOCK(p_FmPort->h_Spinlock, &p_FmPort->lock)) + { + DBG(TRACE, ("FM Port Try Lock - BUSY")); + return ERROR_CODE(E_BUSY); + } + + err = DetachPCD(h_FmPort); + if (err) + { + RELEASE_LOCK(p_FmPort->lock); + RETURN_ERROR(MAJOR, err, NO_MSG); + } + + FmPcdDecNetEnvOwners(p_FmPort->h_FmPcd, p_FmPort->netEnvId); + + /* we do it anyway, instead of checking if included */ + if ((p_FmPort->pcdEngines & FM_PCD_PRS) && p_FmPort->includeInPrsStatistics) + { + FmPcdPrsIncludePortInStatistics(p_FmPort->h_FmPcd, + p_FmPort->hardwarePortId, FALSE); + p_FmPort->includeInPrsStatistics = FALSE; + } + + if (!FmPcdLockTryLockAll(p_FmPort->h_FmPcd)) + { + RELEASE_LOCK(p_FmPort->lock); + DBG(TRACE, ("Try LockAll - BUSY")); + return ERROR_CODE(E_BUSY); + } + + err = DeletePcd(h_FmPort); + FmPcdLockUnlockAll(p_FmPort->h_FmPcd); + if (err) + { + RELEASE_LOCK(p_FmPort->lock); + RETURN_ERROR(MAJOR, err, NO_MSG); + } + + if (p_FmPort->h_ReassemblyTree) + { + err = FM_PCD_CcRootDelete(p_FmPort->h_ReassemblyTree); + if (err) + { + RELEASE_LOCK(p_FmPort->lock); + RETURN_ERROR(MAJOR, err, NO_MSG); + } + p_FmPort->h_ReassemblyTree = NULL; + }RELEASE_LOCK(p_FmPort->lock); + + return err; +} + +t_Error FM_PORT_PcdKgBindSchemes(t_Handle h_FmPort, + t_FmPcdPortSchemesParams *p_PortScheme) +{ + t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; + t_FmPcdKgInterModuleBindPortToSchemes schemeBind; + t_Error err = E_OK; + uint32_t tmpScmVec = 0; + int i; + + SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(!p_FmPort->p_FmPortDriverParam, E_INVALID_STATE); + SANITY_CHECK_RETURN_ERROR(p_FmPort->pcdEngines & FM_PCD_KG, + E_INVALID_STATE); + + schemeBind.netEnvId = p_FmPort->netEnvId; + schemeBind.hardwarePortId = p_FmPort->hardwarePortId; + schemeBind.numOfSchemes = p_PortScheme->numOfSchemes; + schemeBind.useClsPlan = p_FmPort->useClsPlan; + for (i = 0; i < schemeBind.numOfSchemes; i++) + { + schemeBind.schemesIds[i] = FmPcdKgGetSchemeId( + p_PortScheme->h_Schemes[i]); + /* build vector */ + tmpScmVec |= 1 << (31 - (uint32_t)schemeBind.schemesIds[i]); + } + + if (!TRY_LOCK(p_FmPort->h_Spinlock, &p_FmPort->lock)) + { + DBG(TRACE, ("FM Port Try Lock - BUSY")); + return ERROR_CODE(E_BUSY); + } + + err = FmPcdKgBindPortToSchemes(p_FmPort->h_FmPcd, &schemeBind); + if (err == E_OK) + p_FmPort->schemesPerPortVector |= tmpScmVec; + +#ifdef FM_KG_ERASE_FLOW_ID_ERRATA_FMAN_SW004 + if ((FmPcdIsAdvancedOffloadSupported(p_FmPort->h_FmPcd)) && + (p_FmPort->portType == e_FM_PORT_TYPE_OH_OFFLINE_PARSING) && + (p_FmPort->fmRevInfo.majorRev < 6)) + { + for (i=0; i<p_PortScheme->numOfSchemes; i++) + FmPcdKgCcGetSetParams(p_FmPort->h_FmPcd, p_PortScheme->h_Schemes[i], UPDATE_KG_NIA_CC_WA, 0); + } +#endif /* FM_KG_ERASE_FLOW_ID_ERRATA_FMAN_SW004 */ + + RELEASE_LOCK(p_FmPort->lock); + + return err; +} + +t_Error FM_PORT_PcdKgUnbindSchemes(t_Handle h_FmPort, + t_FmPcdPortSchemesParams *p_PortScheme) +{ + t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; + t_FmPcdKgInterModuleBindPortToSchemes schemeBind; + t_Error err = E_OK; + uint32_t tmpScmVec = 0; + int i; + + SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(!p_FmPort->p_FmPortDriverParam, E_INVALID_STATE); + SANITY_CHECK_RETURN_ERROR(p_FmPort->pcdEngines & FM_PCD_KG, + E_INVALID_STATE); + + schemeBind.netEnvId = p_FmPort->netEnvId; + schemeBind.hardwarePortId = p_FmPort->hardwarePortId; + schemeBind.numOfSchemes = p_PortScheme->numOfSchemes; + for (i = 0; i < schemeBind.numOfSchemes; i++) + { + schemeBind.schemesIds[i] = FmPcdKgGetSchemeId( + p_PortScheme->h_Schemes[i]); + /* build vector */ + tmpScmVec |= 1 << (31 - (uint32_t)schemeBind.schemesIds[i]); + } + + if (!TRY_LOCK(p_FmPort->h_Spinlock, &p_FmPort->lock)) + { + DBG(TRACE, ("FM Port Try Lock - BUSY")); + return ERROR_CODE(E_BUSY); + } + + err = FmPcdKgUnbindPortToSchemes(p_FmPort->h_FmPcd, &schemeBind); + if (err == E_OK) + p_FmPort->schemesPerPortVector &= ~tmpScmVec; + RELEASE_LOCK(p_FmPort->lock); + + return err; +} + +t_Error FM_PORT_AddCongestionGrps(t_Handle h_FmPort, + t_FmPortCongestionGrps *p_CongestionGrps) +{ + t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; + uint8_t priorityTmpArray[FM_PORT_NUM_OF_CONGESTION_GRPS]; + uint8_t mod, index; + uint32_t i, grpsMap[FMAN_PORT_CG_MAP_NUM]; + int err; +#if (DPAA_VERSION >= 11) + int j; +#endif /* (DPAA_VERSION >= 11) */ + + SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE); + + /* un-necessary check of the indexes; probably will be needed in the future when there + will be more CGs available .... + for (i=0; i<p_CongestionGrps->numOfCongestionGrpsToConsider; i++) + if (p_CongestionGrps->congestionGrpsToConsider[i] >= FM_PORT_NUM_OF_CONGESTION_GRPS) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("CG id!")); + */ + +#ifdef FM_NO_OP_OBSERVED_CGS + if ((p_FmPort->fmRevInfo.majorRev != 4) && + (p_FmPort->fmRevInfo.majorRev < 6)) + { + if ((p_FmPort->portType != e_FM_PORT_TYPE_RX_10G) && + (p_FmPort->portType != e_FM_PORT_TYPE_RX)) + RETURN_ERROR(MAJOR, E_NOT_SUPPORTED, ("Available for Rx ports only")); + } + else +#endif /* FM_NO_OP_OBSERVED_CGS */ + if ((p_FmPort->portType != e_FM_PORT_TYPE_RX_10G) + && (p_FmPort->portType != e_FM_PORT_TYPE_RX) + && (p_FmPort->portType != e_FM_PORT_TYPE_OH_OFFLINE_PARSING)) + RETURN_ERROR(MAJOR, E_NOT_SUPPORTED, + ("Available for Rx & OP ports only")); + + /* Prepare groups map array */ + memset(grpsMap, 0, FMAN_PORT_CG_MAP_NUM * sizeof(uint32_t)); + for (i = 0; i < p_CongestionGrps->numOfCongestionGrpsToConsider; i++) + { + index = (uint8_t)(p_CongestionGrps->congestionGrpsToConsider[i] / 32); + mod = (uint8_t)(p_CongestionGrps->congestionGrpsToConsider[i] % 32); + if (p_FmPort->fmRevInfo.majorRev != 4) + grpsMap[7 - index] |= (uint32_t)(1 << mod); + else + grpsMap[0] |= (uint32_t)(1 << mod); + } + + memset(&priorityTmpArray, 0, + FM_PORT_NUM_OF_CONGESTION_GRPS * sizeof(uint8_t)); + + for (i = 0; i < p_CongestionGrps->numOfCongestionGrpsToConsider; i++) + { +#if (DPAA_VERSION >= 11) + for (j = 0; j < FM_MAX_NUM_OF_PFC_PRIORITIES; j++) + if (p_CongestionGrps->pfcPrioritiesEn[i][j]) + priorityTmpArray[p_CongestionGrps->congestionGrpsToConsider[i]] |= + (0x01 << (FM_MAX_NUM_OF_PFC_PRIORITIES - j - 1)); +#endif /* (DPAA_VERSION >= 11) */ + } + +#if (DPAA_VERSION >= 11) + for (i = 0; i < FM_PORT_NUM_OF_CONGESTION_GRPS; i++) + { + err = FmSetCongestionGroupPFCpriority(p_FmPort->h_Fm, i, + priorityTmpArray[i]); + if (err) + return err; + } +#endif /* (DPAA_VERSION >= 11) */ + + err = fman_port_add_congestion_grps(&p_FmPort->port, grpsMap); + if (err != 0) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("fman_port_add_congestion_grps")); + + return E_OK; +} + +t_Error FM_PORT_RemoveCongestionGrps(t_Handle h_FmPort, + t_FmPortCongestionGrps *p_CongestionGrps) +{ + t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; + uint8_t mod, index; + uint32_t i, grpsMap[FMAN_PORT_CG_MAP_NUM]; + int err; + + SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE); + + { +#ifdef FM_NO_OP_OBSERVED_CGS + t_FmRevisionInfo revInfo; + + FM_GetRevision(p_FmPort->h_Fm, &revInfo); + if (revInfo.majorRev != 4) + { + if ((p_FmPort->portType != e_FM_PORT_TYPE_RX_10G) && + (p_FmPort->portType != e_FM_PORT_TYPE_RX)) + RETURN_ERROR(MAJOR, E_NOT_SUPPORTED, ("Available for Rx ports only")); + } + else +#endif /* FM_NO_OP_OBSERVED_CGS */ + if ((p_FmPort->portType != e_FM_PORT_TYPE_RX_10G) + && (p_FmPort->portType != e_FM_PORT_TYPE_RX) + && (p_FmPort->portType != e_FM_PORT_TYPE_OH_OFFLINE_PARSING)) + RETURN_ERROR(MAJOR, E_NOT_SUPPORTED, + ("Available for Rx & OP ports only")); + } + + /* Prepare groups map array */ + memset(grpsMap, 0, FMAN_PORT_CG_MAP_NUM * sizeof(uint32_t)); + for (i = 0; i < p_CongestionGrps->numOfCongestionGrpsToConsider; i++) + { + index = (uint8_t)(p_CongestionGrps->congestionGrpsToConsider[i] / 32); + mod = (uint8_t)(p_CongestionGrps->congestionGrpsToConsider[i] % 32); + if (p_FmPort->fmRevInfo.majorRev != 4) + grpsMap[7 - index] |= (uint32_t)(1 << mod); + else + grpsMap[0] |= (uint32_t)(1 << mod); + } + +#if (DPAA_VERSION >= 11) + for (i = 0; i < p_CongestionGrps->numOfCongestionGrpsToConsider; i++) + { + t_Error err = FmSetCongestionGroupPFCpriority( + p_FmPort->h_Fm, p_CongestionGrps->congestionGrpsToConsider[i], + 0); + if (err) + return err; + } +#endif /* (DPAA_VERSION >= 11) */ + + err = fman_port_remove_congestion_grps(&p_FmPort->port, grpsMap); + if (err != 0) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, + ("fman_port_remove_congestion_grps")); + return E_OK; +} + +#if (DPAA_VERSION >= 11) +t_Error FM_PORT_GetIPv4OptionsCount(t_Handle h_FmPort, + uint32_t *p_Ipv4OptionsCount) +{ + t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; + + SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR( + (p_FmPort->portType == e_FM_PORT_TYPE_OH_OFFLINE_PARSING), + E_INVALID_VALUE); + SANITY_CHECK_RETURN_ERROR(p_FmPort->p_ParamsPage, E_INVALID_STATE); + SANITY_CHECK_RETURN_ERROR(p_Ipv4OptionsCount, E_NULL_POINTER); + + *p_Ipv4OptionsCount = GET_UINT32(p_FmPort->p_ParamsPage->ipfOptionsCounter); + + return E_OK; +} +#endif /* (DPAA_VERSION >= 11) */ + +t_Error FM_PORT_ConfigDsarSupport(t_Handle h_FmPortRx, + t_FmPortDsarTablesSizes *params) +{ + t_FmPort *p_FmPort = (t_FmPort *)h_FmPortRx; + p_FmPort->deepSleepVars.autoResMaxSizes = XX_Malloc( + sizeof(struct t_FmPortDsarTablesSizes)); + memcpy(p_FmPort->deepSleepVars.autoResMaxSizes, params, + sizeof(struct t_FmPortDsarTablesSizes)); + return E_OK; +} + +static t_Error FmPortConfigAutoResForDeepSleepSupport1(t_FmPort *p_FmPort) +{ + uint32_t *param_page; + t_FmPortDsarTablesSizes *params = p_FmPort->deepSleepVars.autoResMaxSizes; + t_ArCommonDesc *ArCommonDescPtr; + uint32_t size = sizeof(t_ArCommonDesc); + // ARP + // should put here if (params->max_num_of_arp_entries)? + size = ROUND_UP(size,4); + size += sizeof(t_DsarArpDescriptor); + size += sizeof(t_DsarArpBindingEntry) * params->maxNumOfArpEntries; + size += sizeof(t_DsarArpStatistics); + //ICMPV4 + size = ROUND_UP(size,4); + size += sizeof(t_DsarIcmpV4Descriptor); + size += sizeof(t_DsarIcmpV4BindingEntry) * params->maxNumOfEchoIpv4Entries; + size += sizeof(t_DsarIcmpV4Statistics); + //ICMPV6 + size = ROUND_UP(size,4); + size += sizeof(t_DsarIcmpV6Descriptor); + size += sizeof(t_DsarIcmpV6BindingEntry) * params->maxNumOfEchoIpv6Entries; + size += sizeof(t_DsarIcmpV6Statistics); + //ND + size = ROUND_UP(size,4); + size += sizeof(t_DsarNdDescriptor); + size += sizeof(t_DsarIcmpV6BindingEntry) * params->maxNumOfNdpEntries; + size += sizeof(t_DsarIcmpV6Statistics); + //SNMP + size = ROUND_UP(size,4); + size += sizeof(t_DsarSnmpDescriptor); + size += sizeof(t_DsarSnmpIpv4AddrTblEntry) + * params->maxNumOfSnmpIPV4Entries; + size += sizeof(t_DsarSnmpIpv6AddrTblEntry) + * params->maxNumOfSnmpIPV6Entries; + size += sizeof(t_OidsTblEntry) * params->maxNumOfSnmpOidEntries; + size += params->maxNumOfSnmpOidChar; + size += sizeof(t_DsarIcmpV6Statistics); + //filters + size = ROUND_UP(size,4); + size += params->maxNumOfIpProtFiltering; + size = ROUND_UP(size,4); + size += params->maxNumOfUdpPortFiltering * sizeof(t_PortTblEntry); + size = ROUND_UP(size,4); + size += params->maxNumOfTcpPortFiltering * sizeof(t_PortTblEntry); + + // add here for more protocols + + // statistics + size = ROUND_UP(size,4); + size += sizeof(t_ArStatistics); + + ArCommonDescPtr = FM_MURAM_AllocMem(p_FmPort->h_FmMuram, size, 0x10); + + param_page = + XX_PhysToVirt( + p_FmPort->fmMuramPhysBaseAddr + + GET_UINT32(p_FmPort->p_FmPortBmiRegs->rxPortBmiRegs.fmbm_rgpr)); + WRITE_UINT32( + *param_page, + (uint32_t)(XX_VirtToPhys(ArCommonDescPtr) - p_FmPort->fmMuramPhysBaseAddr)); + return E_OK; +} + +t_FmPortDsarTablesSizes* FM_PORT_GetDsarTablesMaxSizes(t_Handle h_FmPortRx) +{ + t_FmPort *p_FmPort = (t_FmPort *)h_FmPortRx; + return p_FmPort->deepSleepVars.autoResMaxSizes; +} + +struct arOffsets +{ + uint32_t arp; + uint32_t nd; + uint32_t icmpv4; + uint32_t icmpv6; + uint32_t snmp; + uint32_t stats; + uint32_t filtIp; + uint32_t filtUdp; + uint32_t filtTcp; +}; + +static uint32_t AR_ComputeOffsets(struct arOffsets* of, + struct t_FmPortDsarParams *params, + t_FmPort *p_FmPort) +{ + uint32_t size = sizeof(t_ArCommonDesc); + // ARP + if (params->p_AutoResArpInfo) + { + size = ROUND_UP(size,4); + of->arp = size; + size += sizeof(t_DsarArpDescriptor); + size += sizeof(t_DsarArpBindingEntry) + * params->p_AutoResArpInfo->tableSize; + size += sizeof(t_DsarArpStatistics); + } + // ICMPV4 + if (params->p_AutoResEchoIpv4Info) + { + size = ROUND_UP(size,4); + of->icmpv4 = size; + size += sizeof(t_DsarIcmpV4Descriptor); + size += sizeof(t_DsarIcmpV4BindingEntry) + * params->p_AutoResEchoIpv4Info->tableSize; + size += sizeof(t_DsarIcmpV4Statistics); + } + // ICMPV6 + if (params->p_AutoResEchoIpv6Info) + { + size = ROUND_UP(size,4); + of->icmpv6 = size; + size += sizeof(t_DsarIcmpV6Descriptor); + size += sizeof(t_DsarIcmpV6BindingEntry) + * params->p_AutoResEchoIpv6Info->tableSize; + size += sizeof(t_DsarIcmpV6Statistics); + } + // ND + if (params->p_AutoResNdpInfo) + { + size = ROUND_UP(size,4); + of->nd = size; + size += sizeof(t_DsarNdDescriptor); + size += sizeof(t_DsarIcmpV6BindingEntry) + * (params->p_AutoResNdpInfo->tableSizeAssigned + + params->p_AutoResNdpInfo->tableSizeTmp); + size += sizeof(t_DsarIcmpV6Statistics); + } + // SNMP + if (params->p_AutoResSnmpInfo) + { + size = ROUND_UP(size,4); + of->snmp = size; + size += sizeof(t_DsarSnmpDescriptor); + size += sizeof(t_DsarSnmpIpv4AddrTblEntry) + * params->p_AutoResSnmpInfo->numOfIpv4Addresses; + size += sizeof(t_DsarSnmpIpv6AddrTblEntry) + * params->p_AutoResSnmpInfo->numOfIpv6Addresses; + size += sizeof(t_OidsTblEntry) * params->p_AutoResSnmpInfo->oidsTblSize; + size += p_FmPort->deepSleepVars.autoResMaxSizes->maxNumOfSnmpOidChar; + size += sizeof(t_DsarIcmpV6Statistics); + } + //filters + size = ROUND_UP(size,4); + if (params->p_AutoResFilteringInfo) + { + of->filtIp = size; + size += params->p_AutoResFilteringInfo->ipProtTableSize; + size = ROUND_UP(size,4); + of->filtUdp = size; + size += params->p_AutoResFilteringInfo->udpPortsTableSize + * sizeof(t_PortTblEntry); + size = ROUND_UP(size,4); + of->filtTcp = size; + size += params->p_AutoResFilteringInfo->tcpPortsTableSize + * sizeof(t_PortTblEntry); + } + // add here for more protocols + // statistics + size = ROUND_UP(size,4); + of->stats = size; + size += sizeof(t_ArStatistics); + return size; +} + +uint32_t* ARDesc; +void PrsEnable(t_Handle p_FmPcd); +void PrsDisable(t_Handle p_FmPcd); +int PrsIsEnabled(t_Handle p_FmPcd); +t_Handle FM_PCD_GetHcPort(t_Handle h_FmPcd); + +static t_Error DsarCheckParams(t_FmPortDsarParams *params, + t_FmPortDsarTablesSizes *sizes) +{ + bool macInit = FALSE; + uint8_t mac[6]; + int i = 0; + + // check table sizes + if (params->p_AutoResArpInfo + && sizes->maxNumOfArpEntries < params->p_AutoResArpInfo->tableSize) + RETURN_ERROR( + MAJOR, E_INVALID_VALUE, + ("DSAR: Arp table size exceeds the configured maximum size.")); + if (params->p_AutoResEchoIpv4Info + && sizes->maxNumOfEchoIpv4Entries + < params->p_AutoResEchoIpv4Info->tableSize) + RETURN_ERROR( + MAJOR, + E_INVALID_VALUE, + ("DSAR: EchoIpv4 table size exceeds the configured maximum size.")); + if (params->p_AutoResNdpInfo + && sizes->maxNumOfNdpEntries + < params->p_AutoResNdpInfo->tableSizeAssigned + + params->p_AutoResNdpInfo->tableSizeTmp) + RETURN_ERROR( + MAJOR, E_INVALID_VALUE, + ("DSAR: NDP table size exceeds the configured maximum size.")); + if (params->p_AutoResEchoIpv6Info + && sizes->maxNumOfEchoIpv6Entries + < params->p_AutoResEchoIpv6Info->tableSize) + RETURN_ERROR( + MAJOR, + E_INVALID_VALUE, + ("DSAR: EchoIpv6 table size exceeds the configured maximum size.")); + if (params->p_AutoResSnmpInfo + && sizes->maxNumOfSnmpOidEntries + < params->p_AutoResSnmpInfo->oidsTblSize) + RETURN_ERROR( + MAJOR, + E_INVALID_VALUE, + ("DSAR: Snmp Oid table size exceeds the configured maximum size.")); + if (params->p_AutoResSnmpInfo + && sizes->maxNumOfSnmpIPV4Entries + < params->p_AutoResSnmpInfo->numOfIpv4Addresses) + RETURN_ERROR( + MAJOR, + E_INVALID_VALUE, + ("DSAR: Snmp ipv4 table size exceeds the configured maximum size.")); + if (params->p_AutoResSnmpInfo + && sizes->maxNumOfSnmpIPV6Entries + < params->p_AutoResSnmpInfo->numOfIpv6Addresses) + RETURN_ERROR( + MAJOR, + E_INVALID_VALUE, + ("DSAR: Snmp ipv6 table size exceeds the configured maximum size.")); + if (params->p_AutoResFilteringInfo) + { + if (sizes->maxNumOfIpProtFiltering + < params->p_AutoResFilteringInfo->ipProtTableSize) + RETURN_ERROR( + MAJOR, + E_INVALID_VALUE, + ("DSAR: ip filter table size exceeds the configured maximum size.")); + if (sizes->maxNumOfTcpPortFiltering + < params->p_AutoResFilteringInfo->udpPortsTableSize) + RETURN_ERROR( + MAJOR, + E_INVALID_VALUE, + ("DSAR: udp filter table size exceeds the configured maximum size.")); + if (sizes->maxNumOfUdpPortFiltering + < params->p_AutoResFilteringInfo->tcpPortsTableSize) + RETURN_ERROR( + MAJOR, + E_INVALID_VALUE, + ("DSAR: tcp filter table size exceeds the configured maximum size.")); + } + /* check only 1 MAC address is configured (this is what ucode currently supports) */ + if (params->p_AutoResArpInfo && params->p_AutoResArpInfo->tableSize) + { + memcpy(mac, params->p_AutoResArpInfo->p_AutoResTable[0].mac, 6); + i = 1; + macInit = TRUE; + + for (; i < params->p_AutoResArpInfo->tableSize; i++) + if (memcmp(mac, params->p_AutoResArpInfo->p_AutoResTable[i].mac, 6)) + RETURN_ERROR( + MAJOR, E_INVALID_VALUE, + ("DSAR: Only 1 mac address is currently supported.")); + } + if (params->p_AutoResEchoIpv4Info + && params->p_AutoResEchoIpv4Info->tableSize) + { + i = 0; + if (!macInit) + { + memcpy(mac, params->p_AutoResEchoIpv4Info->p_AutoResTable[0].mac, + 6); + i = 1; + macInit = TRUE; + } + for (; i < params->p_AutoResEchoIpv4Info->tableSize; i++) + if (memcmp(mac, + params->p_AutoResEchoIpv4Info->p_AutoResTable[i].mac, 6)) + RETURN_ERROR( + MAJOR, E_INVALID_VALUE, + ("DSAR: Only 1 mac address is currently supported.")); + } + if (params->p_AutoResEchoIpv6Info + && params->p_AutoResEchoIpv6Info->tableSize) + { + i = 0; + if (!macInit) + { + memcpy(mac, params->p_AutoResEchoIpv6Info->p_AutoResTable[0].mac, + 6); + i = 1; + macInit = TRUE; + } + for (; i < params->p_AutoResEchoIpv6Info->tableSize; i++) + if (memcmp(mac, + params->p_AutoResEchoIpv6Info->p_AutoResTable[i].mac, 6)) + RETURN_ERROR( + MAJOR, E_INVALID_VALUE, + ("DSAR: Only 1 mac address is currently supported.")); + } + if (params->p_AutoResNdpInfo && params->p_AutoResNdpInfo->tableSizeAssigned) + { + i = 0; + if (!macInit) + { + memcpy(mac, params->p_AutoResNdpInfo->p_AutoResTableAssigned[0].mac, + 6); + i = 1; + macInit = TRUE; + } + for (; i < params->p_AutoResNdpInfo->tableSizeAssigned; i++) + if (memcmp(mac, + params->p_AutoResNdpInfo->p_AutoResTableAssigned[i].mac, + 6)) + RETURN_ERROR( + MAJOR, E_INVALID_VALUE, + ("DSAR: Only 1 mac address is currently supported.")); + } + if (params->p_AutoResNdpInfo && params->p_AutoResNdpInfo->tableSizeTmp) + { + i = 0; + if (!macInit) + { + memcpy(mac, params->p_AutoResNdpInfo->p_AutoResTableTmp[0].mac, 6); + i = 1; + } + for (; i < params->p_AutoResNdpInfo->tableSizeTmp; i++) + if (memcmp(mac, params->p_AutoResNdpInfo->p_AutoResTableTmp[i].mac, + 6)) + RETURN_ERROR( + MAJOR, E_INVALID_VALUE, + ("DSAR: Only 1 mac address is currently supported.")); + } + return E_OK; +} + +static int GetBERLen(uint8_t* buf) +{ + if (*buf & 0x80) + { + if ((*buf & 0x7F) == 1) + return buf[1]; + else + return *(uint16_t*)&buf[1]; // assuming max len is 2 + } + else + return buf[0]; +} +#define TOTAL_BER_LEN(len) (len < 128) ? len + 2 : len + 3 + +#define SCFG_FMCLKDPSLPCR_ADDR 0xFFE0FC00C +#define SCFG_FMCLKDPSLPCR_DS_VAL 0x08402000 +#define SCFG_FMCLKDPSLPCR_NORMAL_VAL 0x00402000 +static int fm_soc_suspend(void) +{ + uint32_t *fmclk, tmp32; + fmclk = ioremap(SCFG_FMCLKDPSLPCR_ADDR, 4); + tmp32 = GET_UINT32(*fmclk); + WRITE_UINT32(*fmclk, SCFG_FMCLKDPSLPCR_DS_VAL); + tmp32 = GET_UINT32(*fmclk); + iounmap(fmclk); + return 0; +} + +void fm_clk_down(void) +{ + uint32_t *fmclk, tmp32; + fmclk = ioremap(SCFG_FMCLKDPSLPCR_ADDR, 4); + tmp32 = GET_UINT32(*fmclk); + WRITE_UINT32(*fmclk, SCFG_FMCLKDPSLPCR_DS_VAL | 0x40000000); + tmp32 = GET_UINT32(*fmclk); + iounmap(fmclk); +} + +t_Error FM_PORT_EnterDsar(t_Handle h_FmPortRx, t_FmPortDsarParams *params) +{ + int i, j; + t_Error err; + uint32_t nia; + t_FmPort *p_FmPort = (t_FmPort *)h_FmPortRx; + t_FmPort *p_FmPortTx = (t_FmPort *)params->h_FmPortTx; + t_DsarArpDescriptor *ArpDescriptor; + t_DsarIcmpV4Descriptor* ICMPV4Descriptor; + t_DsarIcmpV6Descriptor* ICMPV6Descriptor; + t_DsarNdDescriptor* NDDescriptor; + + uint64_t fmMuramVirtBaseAddr = (uint64_t)PTR_TO_UINT(XX_PhysToVirt(p_FmPort->fmMuramPhysBaseAddr)); + uint32_t *param_page = XX_PhysToVirt(p_FmPort->fmMuramPhysBaseAddr + GET_UINT32(p_FmPort->p_FmPortBmiRegs->rxPortBmiRegs.fmbm_rgpr)); + t_ArCommonDesc *ArCommonDescPtr = (t_ArCommonDesc*)(XX_PhysToVirt(p_FmPort->fmMuramPhysBaseAddr + GET_UINT32(*param_page))); + struct arOffsets* of; + uint8_t tmp = 0; + t_FmGetSetParams fmGetSetParams; + memset(&fmGetSetParams, 0, sizeof (t_FmGetSetParams)); + fmGetSetParams.setParams.type = UPDATE_FPM_BRKC_SLP; + fmGetSetParams.setParams.sleep = 1; + + err = DsarCheckParams(params, p_FmPort->deepSleepVars.autoResMaxSizes); + if (err != E_OK) + return err; + + p_FmPort->deepSleepVars.autoResOffsets = XX_Malloc(sizeof(struct arOffsets)); + of = (struct arOffsets *)p_FmPort->deepSleepVars.autoResOffsets; + IOMemSet32(ArCommonDescPtr, 0, AR_ComputeOffsets(of, params, p_FmPort)); + + // common + WRITE_UINT8(ArCommonDescPtr->arTxPort, p_FmPortTx->hardwarePortId); + nia = GET_UINT32(p_FmPort->p_FmPortBmiRegs->rxPortBmiRegs.fmbm_rfne); // bmi nia + if ((nia & 0x007C0000) == 0x00440000) // bmi nia is parser + WRITE_UINT32(ArCommonDescPtr->activeHPNIA, GET_UINT32(p_FmPort->p_FmPortBmiRegs->rxPortBmiRegs.fmbm_rfpne)); + else + WRITE_UINT32(ArCommonDescPtr->activeHPNIA, nia); + WRITE_UINT16(ArCommonDescPtr->snmpPort, 161); + + // ARP + if (params->p_AutoResArpInfo) + { + t_DsarArpBindingEntry* arp_bindings; + ArpDescriptor = (t_DsarArpDescriptor*)(PTR_TO_UINT(ArCommonDescPtr) + of->arp); + WRITE_UINT32(ArCommonDescPtr->p_ArpDescriptor, PTR_TO_UINT(ArpDescriptor) - fmMuramVirtBaseAddr); + arp_bindings = (t_DsarArpBindingEntry*)(PTR_TO_UINT(ArpDescriptor) + sizeof(t_DsarArpDescriptor)); + if (params->p_AutoResArpInfo->enableConflictDetection) + WRITE_UINT16(ArpDescriptor->control, 1); + else + WRITE_UINT16(ArpDescriptor->control, 0); + if (params->p_AutoResArpInfo->tableSize) + { + t_FmPortDsarArpEntry* arp_entry = params->p_AutoResArpInfo->p_AutoResTable; + WRITE_UINT16(*(uint16_t*)&ArCommonDescPtr->macStationAddr[0], *(uint16_t*)&arp_entry[0].mac[0]); + WRITE_UINT32(*(uint32_t*)&ArCommonDescPtr->macStationAddr[2], *(uint32_t*)&arp_entry[0].mac[2]); + WRITE_UINT16(ArpDescriptor->numOfBindings, params->p_AutoResArpInfo->tableSize); + + for (i = 0; i < params->p_AutoResArpInfo->tableSize; i++) + { + WRITE_UINT32(arp_bindings[i].ipv4Addr, arp_entry[i].ipAddress); + if (arp_entry[i].isVlan) + WRITE_UINT16(arp_bindings[i].vlanId, arp_entry[i].vid & 0xFFF); + } + WRITE_UINT32(ArpDescriptor->p_Bindings, PTR_TO_UINT(arp_bindings) - fmMuramVirtBaseAddr); + } + WRITE_UINT32(ArpDescriptor->p_Statistics, PTR_TO_UINT(arp_bindings) + + sizeof(t_DsarArpBindingEntry) * params->p_AutoResArpInfo->tableSize - fmMuramVirtBaseAddr); + } + + // ICMPV4 + if (params->p_AutoResEchoIpv4Info) + { + t_DsarIcmpV4BindingEntry* icmpv4_bindings; + ICMPV4Descriptor = (t_DsarIcmpV4Descriptor*)(PTR_TO_UINT(ArCommonDescPtr) + of->icmpv4); + WRITE_UINT32(ArCommonDescPtr->p_IcmpV4Descriptor, PTR_TO_UINT(ICMPV4Descriptor) - fmMuramVirtBaseAddr); + icmpv4_bindings = (t_DsarIcmpV4BindingEntry*)(PTR_TO_UINT(ICMPV4Descriptor) + sizeof(t_DsarIcmpV4Descriptor)); + WRITE_UINT16(ICMPV4Descriptor->control, 0); + if (params->p_AutoResEchoIpv4Info->tableSize) + { + t_FmPortDsarArpEntry* arp_entry = params->p_AutoResEchoIpv4Info->p_AutoResTable; + WRITE_UINT16(*(uint16_t*)&ArCommonDescPtr->macStationAddr[0], *(uint16_t*)&arp_entry[0].mac[0]); + WRITE_UINT32(*(uint32_t*)&ArCommonDescPtr->macStationAddr[2], *(uint32_t*)&arp_entry[0].mac[2]); + WRITE_UINT16(ICMPV4Descriptor->numOfBindings, params->p_AutoResEchoIpv4Info->tableSize); + + for (i = 0; i < params->p_AutoResEchoIpv4Info->tableSize; i++) + { + WRITE_UINT32(icmpv4_bindings[i].ipv4Addr, arp_entry[i].ipAddress); + if (arp_entry[i].isVlan) + WRITE_UINT16(icmpv4_bindings[i].vlanId, arp_entry[i].vid & 0xFFF); + } + WRITE_UINT32(ICMPV4Descriptor->p_Bindings, PTR_TO_UINT(icmpv4_bindings) - fmMuramVirtBaseAddr); + } + WRITE_UINT32(ICMPV4Descriptor->p_Statistics, PTR_TO_UINT(icmpv4_bindings) + + sizeof(t_DsarIcmpV4BindingEntry) * params->p_AutoResEchoIpv4Info->tableSize - fmMuramVirtBaseAddr); + } + + // ICMPV6 + if (params->p_AutoResEchoIpv6Info) + { + t_DsarIcmpV6BindingEntry* icmpv6_bindings; + ICMPV6Descriptor = (t_DsarIcmpV6Descriptor*)(PTR_TO_UINT(ArCommonDescPtr) + of->icmpv6); + WRITE_UINT32(ArCommonDescPtr->p_IcmpV6Descriptor, PTR_TO_UINT(ICMPV6Descriptor) - fmMuramVirtBaseAddr); + icmpv6_bindings = (t_DsarIcmpV6BindingEntry*)(PTR_TO_UINT(ICMPV6Descriptor) + sizeof(t_DsarIcmpV6Descriptor)); + WRITE_UINT16(ICMPV6Descriptor->control, 0); + if (params->p_AutoResEchoIpv6Info->tableSize) + { + t_FmPortDsarNdpEntry* ndp_entry = params->p_AutoResEchoIpv6Info->p_AutoResTable; + WRITE_UINT16(*(uint16_t*)&ArCommonDescPtr->macStationAddr[0], *(uint16_t*)&ndp_entry[0].mac[0]); + WRITE_UINT32(*(uint32_t*)&ArCommonDescPtr->macStationAddr[2], *(uint32_t*)&ndp_entry[0].mac[2]); + WRITE_UINT16(ICMPV6Descriptor->numOfBindings, params->p_AutoResEchoIpv6Info->tableSize); + + for (i = 0; i < params->p_AutoResEchoIpv6Info->tableSize; i++) + { + for (j = 0; j < 4; j++) + WRITE_UINT32(icmpv6_bindings[i].ipv6Addr[j], ndp_entry[i].ipAddress[j]); + if (ndp_entry[i].isVlan) + WRITE_UINT16(*(uint16_t*)&icmpv6_bindings[i].ipv6Addr[4], ndp_entry[i].vid & 0xFFF); // writing vlan + } + WRITE_UINT32(ICMPV6Descriptor->p_Bindings, PTR_TO_UINT(icmpv6_bindings) - fmMuramVirtBaseAddr); + } + WRITE_UINT32(ICMPV6Descriptor->p_Statistics, PTR_TO_UINT(icmpv6_bindings) + + sizeof(t_DsarIcmpV6BindingEntry) * params->p_AutoResEchoIpv6Info->tableSize - fmMuramVirtBaseAddr); + } + + // ND + if (params->p_AutoResNdpInfo) + { + t_DsarIcmpV6BindingEntry* icmpv6_bindings; + NDDescriptor = (t_DsarNdDescriptor*)(PTR_TO_UINT(ArCommonDescPtr) + of->nd); + WRITE_UINT32(ArCommonDescPtr->p_NdDescriptor, PTR_TO_UINT(NDDescriptor) - fmMuramVirtBaseAddr); + icmpv6_bindings = (t_DsarIcmpV6BindingEntry*)(PTR_TO_UINT(NDDescriptor) + sizeof(t_DsarNdDescriptor)); + if (params->p_AutoResNdpInfo->enableConflictDetection) + WRITE_UINT16(NDDescriptor->control, 1); + else + WRITE_UINT16(NDDescriptor->control, 0); + if (params->p_AutoResNdpInfo->tableSizeAssigned + params->p_AutoResNdpInfo->tableSizeTmp) + { + t_FmPortDsarNdpEntry* ndp_entry = params->p_AutoResNdpInfo->p_AutoResTableAssigned; + WRITE_UINT16(*(uint16_t*)&ArCommonDescPtr->macStationAddr[0], *(uint16_t*)&ndp_entry[0].mac[0]); + WRITE_UINT32(*(uint32_t*)&ArCommonDescPtr->macStationAddr[2], *(uint32_t*)&ndp_entry[0].mac[2]); + WRITE_UINT16(NDDescriptor->numOfBindings, params->p_AutoResNdpInfo->tableSizeAssigned + + params->p_AutoResNdpInfo->tableSizeTmp); + + for (i = 0; i < params->p_AutoResNdpInfo->tableSizeAssigned; i++) + { + for (j = 0; j < 4; j++) + WRITE_UINT32(icmpv6_bindings[i].ipv6Addr[j], ndp_entry[i].ipAddress[j]); + if (ndp_entry[i].isVlan) + WRITE_UINT16(*(uint16_t*)&icmpv6_bindings[i].ipv6Addr[4], ndp_entry[i].vid & 0xFFF); // writing vlan + } + ndp_entry = params->p_AutoResNdpInfo->p_AutoResTableTmp; + for (i = 0; i < params->p_AutoResNdpInfo->tableSizeTmp; i++) + { + for (j = 0; j < 4; j++) + WRITE_UINT32(icmpv6_bindings[i + params->p_AutoResNdpInfo->tableSizeAssigned].ipv6Addr[j], ndp_entry[i].ipAddress[j]); + if (ndp_entry[i].isVlan) + WRITE_UINT16(*(uint16_t*)&icmpv6_bindings[i + params->p_AutoResNdpInfo->tableSizeAssigned].ipv6Addr[4], ndp_entry[i].vid & 0xFFF); // writing vlan + } + WRITE_UINT32(NDDescriptor->p_Bindings, PTR_TO_UINT(icmpv6_bindings) - fmMuramVirtBaseAddr); + } + WRITE_UINT32(NDDescriptor->p_Statistics, PTR_TO_UINT(icmpv6_bindings) + sizeof(t_DsarIcmpV6BindingEntry) + * (params->p_AutoResNdpInfo->tableSizeAssigned + params->p_AutoResNdpInfo->tableSizeTmp) + - fmMuramVirtBaseAddr); + WRITE_UINT32(NDDescriptor->solicitedAddr, 0xFFFFFFFF); + } + + // SNMP + if (params->p_AutoResSnmpInfo) + { + t_FmPortDsarSnmpInfo *snmpSrc = params->p_AutoResSnmpInfo; + t_DsarSnmpIpv4AddrTblEntry* snmpIpv4Addr; + t_DsarSnmpIpv6AddrTblEntry* snmpIpv6Addr; + t_OidsTblEntry* snmpOid; + uint8_t *charPointer; + int len; + t_DsarSnmpDescriptor* SnmpDescriptor = (t_DsarSnmpDescriptor*)(PTR_TO_UINT(ArCommonDescPtr) + of->snmp); + WRITE_UINT32(ArCommonDescPtr->p_SnmpDescriptor, PTR_TO_UINT(SnmpDescriptor) - fmMuramVirtBaseAddr); + WRITE_UINT16(SnmpDescriptor->control, snmpSrc->control); + WRITE_UINT16(SnmpDescriptor->maxSnmpMsgLength, snmpSrc->maxSnmpMsgLength); + snmpIpv4Addr = (t_DsarSnmpIpv4AddrTblEntry*)(PTR_TO_UINT(SnmpDescriptor) + sizeof(t_DsarSnmpDescriptor)); + if (snmpSrc->numOfIpv4Addresses) + { + t_FmPortDsarSnmpIpv4AddrTblEntry* snmpIpv4AddrSrc = snmpSrc->p_Ipv4AddrTbl; + WRITE_UINT16(SnmpDescriptor->numOfIpv4Addresses, snmpSrc->numOfIpv4Addresses); + for (i = 0; i < snmpSrc->numOfIpv4Addresses; i++) + { + WRITE_UINT32(snmpIpv4Addr[i].ipv4Addr, snmpIpv4AddrSrc[i].ipv4Addr); + if (snmpIpv4AddrSrc[i].isVlan) + WRITE_UINT16(snmpIpv4Addr[i].vlanId, snmpIpv4AddrSrc[i].vid & 0xFFF); + } + WRITE_UINT32(SnmpDescriptor->p_Ipv4AddrTbl, PTR_TO_UINT(snmpIpv4Addr) - fmMuramVirtBaseAddr); + } + snmpIpv6Addr = (t_DsarSnmpIpv6AddrTblEntry*)(PTR_TO_UINT(snmpIpv4Addr) + + sizeof(t_DsarSnmpIpv4AddrTblEntry) * snmpSrc->numOfIpv4Addresses); + if (snmpSrc->numOfIpv6Addresses) + { + t_FmPortDsarSnmpIpv6AddrTblEntry* snmpIpv6AddrSrc = snmpSrc->p_Ipv6AddrTbl; + WRITE_UINT16(SnmpDescriptor->numOfIpv6Addresses, snmpSrc->numOfIpv6Addresses); + for (i = 0; i < snmpSrc->numOfIpv6Addresses; i++) + { + for (j = 0; j < 4; j++) + WRITE_UINT32(snmpIpv6Addr[i].ipv6Addr[j], snmpIpv6AddrSrc[i].ipv6Addr[j]); + if (snmpIpv6AddrSrc[i].isVlan) + WRITE_UINT16(snmpIpv6Addr[i].vlanId, snmpIpv6AddrSrc[i].vid & 0xFFF); + } + WRITE_UINT32(SnmpDescriptor->p_Ipv6AddrTbl, PTR_TO_UINT(snmpIpv6Addr) - fmMuramVirtBaseAddr); + } + snmpOid = (t_OidsTblEntry*)(PTR_TO_UINT(snmpIpv6Addr) + + sizeof(t_DsarSnmpIpv6AddrTblEntry) * snmpSrc->numOfIpv6Addresses); + charPointer = (uint8_t*)(PTR_TO_UINT(snmpOid) + + sizeof(t_OidsTblEntry) * snmpSrc->oidsTblSize); + len = TOTAL_BER_LEN(GetBERLen(&snmpSrc->p_RdOnlyCommunityStr[1])); + Mem2IOCpy32(charPointer, snmpSrc->p_RdOnlyCommunityStr, len); + WRITE_UINT32(SnmpDescriptor->p_RdOnlyCommunityStr, PTR_TO_UINT(charPointer) - fmMuramVirtBaseAddr); + charPointer += len; + len = TOTAL_BER_LEN(GetBERLen(&snmpSrc->p_RdWrCommunityStr[1])); + Mem2IOCpy32(charPointer, snmpSrc->p_RdWrCommunityStr, len); + WRITE_UINT32(SnmpDescriptor->p_RdWrCommunityStr, PTR_TO_UINT(charPointer) - fmMuramVirtBaseAddr); + charPointer += len; + WRITE_UINT32(SnmpDescriptor->oidsTblSize, snmpSrc->oidsTblSize); + WRITE_UINT32(SnmpDescriptor->p_OidsTbl, PTR_TO_UINT(snmpOid) - fmMuramVirtBaseAddr); + for (i = 0; i < snmpSrc->oidsTblSize; i++) + { + WRITE_UINT16(snmpOid->oidSize, snmpSrc->p_OidsTbl[i].oidSize); + WRITE_UINT16(snmpOid->resSize, snmpSrc->p_OidsTbl[i].resSize); + Mem2IOCpy32(charPointer, snmpSrc->p_OidsTbl[i].oidVal, snmpSrc->p_OidsTbl[i].oidSize); + WRITE_UINT32(snmpOid->p_Oid, PTR_TO_UINT(charPointer) - fmMuramVirtBaseAddr); + charPointer += snmpSrc->p_OidsTbl[i].oidSize; + if (snmpSrc->p_OidsTbl[i].resSize <= 4) + WRITE_UINT32(snmpOid->resValOrPtr, *snmpSrc->p_OidsTbl[i].resVal); + else + { + Mem2IOCpy32(charPointer, snmpSrc->p_OidsTbl[i].resVal, snmpSrc->p_OidsTbl[i].resSize); + WRITE_UINT32(snmpOid->resValOrPtr, PTR_TO_UINT(charPointer) - fmMuramVirtBaseAddr); + charPointer += snmpSrc->p_OidsTbl[i].resSize; + } + snmpOid++; + } + charPointer = UINT_TO_PTR(ROUND_UP(PTR_TO_UINT(charPointer),4)); + WRITE_UINT32(SnmpDescriptor->p_Statistics, PTR_TO_UINT(charPointer) - fmMuramVirtBaseAddr); + } + + // filtering + if (params->p_AutoResFilteringInfo) + { + if (params->p_AutoResFilteringInfo->ipProtPassOnHit) + tmp |= IP_PROT_TBL_PASS_MASK; + if (params->p_AutoResFilteringInfo->udpPortPassOnHit) + tmp |= UDP_PORT_TBL_PASS_MASK; + if (params->p_AutoResFilteringInfo->tcpPortPassOnHit) + tmp |= TCP_PORT_TBL_PASS_MASK; + WRITE_UINT8(ArCommonDescPtr->filterControl, tmp); + WRITE_UINT16(ArCommonDescPtr->tcpControlPass, params->p_AutoResFilteringInfo->tcpFlagsMask); + + // ip filtering + if (params->p_AutoResFilteringInfo->ipProtTableSize) + { + uint8_t* ip_tbl = (uint8_t*)(PTR_TO_UINT(ArCommonDescPtr) + of->filtIp); + WRITE_UINT8(ArCommonDescPtr->ipProtocolTblSize, params->p_AutoResFilteringInfo->ipProtTableSize); + for (i = 0; i < params->p_AutoResFilteringInfo->ipProtTableSize; i++) + WRITE_UINT8(ip_tbl[i], params->p_AutoResFilteringInfo->p_IpProtTablePtr[i]); + WRITE_UINT32(ArCommonDescPtr->p_IpProtocolFiltTbl, PTR_TO_UINT(ip_tbl) - fmMuramVirtBaseAddr); + } + + // udp filtering + if (params->p_AutoResFilteringInfo->udpPortsTableSize) + { + t_PortTblEntry* udp_tbl = (t_PortTblEntry*)(PTR_TO_UINT(ArCommonDescPtr) + of->filtUdp); + WRITE_UINT8(ArCommonDescPtr->udpPortTblSize, params->p_AutoResFilteringInfo->udpPortsTableSize); + for (i = 0; i < params->p_AutoResFilteringInfo->udpPortsTableSize; i++) + { + WRITE_UINT32(udp_tbl[i].Ports, + (params->p_AutoResFilteringInfo->p_UdpPortsTablePtr[i].srcPort << 16) + + params->p_AutoResFilteringInfo->p_UdpPortsTablePtr[i].dstPort); + WRITE_UINT32(udp_tbl[i].PortsMask, + (params->p_AutoResFilteringInfo->p_UdpPortsTablePtr[i].srcPortMask << 16) + + params->p_AutoResFilteringInfo->p_UdpPortsTablePtr[i].dstPortMask); + } + WRITE_UINT32(ArCommonDescPtr->p_UdpPortFiltTbl, PTR_TO_UINT(udp_tbl) - fmMuramVirtBaseAddr); + } + + // tcp filtering + if (params->p_AutoResFilteringInfo->tcpPortsTableSize) + { + t_PortTblEntry* tcp_tbl = (t_PortTblEntry*)(PTR_TO_UINT(ArCommonDescPtr) + of->filtTcp); + WRITE_UINT8(ArCommonDescPtr->tcpPortTblSize, params->p_AutoResFilteringInfo->tcpPortsTableSize); + for (i = 0; i < params->p_AutoResFilteringInfo->tcpPortsTableSize; i++) + { + WRITE_UINT32(tcp_tbl[i].Ports, + (params->p_AutoResFilteringInfo->p_TcpPortsTablePtr[i].srcPort << 16) + + params->p_AutoResFilteringInfo->p_TcpPortsTablePtr[i].dstPort); + WRITE_UINT32(tcp_tbl[i].PortsMask, + (params->p_AutoResFilteringInfo->p_TcpPortsTablePtr[i].srcPortMask << 16) + + params->p_AutoResFilteringInfo->p_TcpPortsTablePtr[i].dstPortMask); + } + WRITE_UINT32(ArCommonDescPtr->p_TcpPortFiltTbl, PTR_TO_UINT(tcp_tbl) - fmMuramVirtBaseAddr); + } + } + // common stats + WRITE_UINT32(ArCommonDescPtr->p_ArStats, PTR_TO_UINT(ArCommonDescPtr) + of->stats - fmMuramVirtBaseAddr); + + // get into Deep Sleep sequence: + + // Ensures that FMan do not enter the idle state. This is done by programing + // FMDPSLPCR[FM_STOP] to one. + fm_soc_suspend(); + + ARDesc = UINT_TO_PTR(XX_VirtToPhys(ArCommonDescPtr)); + return E_OK; + +} + +void FM_ChangeClock(t_Handle h_Fm, int hardwarePortId); +t_Error FM_PORT_EnterDsarFinal(t_Handle h_DsarRxPort, t_Handle h_DsarTxPort) +{ + t_FmGetSetParams fmGetSetParams; + t_FmPort *p_FmPort = (t_FmPort *)h_DsarRxPort; + t_FmPort *p_FmPortTx = (t_FmPort *)h_DsarTxPort; + t_Handle *h_FmPcd = FmGetPcd(p_FmPort->h_Fm); + t_FmPort *p_FmPortHc = FM_PCD_GetHcPort(h_FmPcd); + memset(&fmGetSetParams, 0, sizeof (t_FmGetSetParams)); + fmGetSetParams.setParams.type = UPDATE_FM_CLD; + FmGetSetParams(p_FmPort->h_Fm, &fmGetSetParams); + + /* Issue graceful stop to HC port */ + FM_PORT_Disable(p_FmPortHc); + + // config tx port + p_FmPort->deepSleepVars.fmbm_tcfg = GET_UINT32(p_FmPortTx->p_FmPortBmiRegs->txPortBmiRegs.fmbm_tcfg); + WRITE_UINT32(p_FmPortTx->p_FmPortBmiRegs->txPortBmiRegs.fmbm_tcfg, GET_UINT32(p_FmPortTx->p_FmPortBmiRegs->txPortBmiRegs.fmbm_tcfg) | BMI_PORT_CFG_IM | BMI_PORT_CFG_EN); + // ???? + p_FmPort->deepSleepVars.fmbm_tcmne = GET_UINT32(p_FmPortTx->p_FmPortBmiRegs->txPortBmiRegs.fmbm_tcmne); + WRITE_UINT32(p_FmPortTx->p_FmPortBmiRegs->txPortBmiRegs.fmbm_tcmne, 0xE); + // Stage 7:echo + p_FmPort->deepSleepVars.fmbm_rfpne = GET_UINT32(p_FmPort->p_FmPortBmiRegs->rxPortBmiRegs.fmbm_rfpne); + WRITE_UINT32(p_FmPort->p_FmPortBmiRegs->rxPortBmiRegs.fmbm_rfpne, 0x2E); + if (!PrsIsEnabled(h_FmPcd)) + { + p_FmPort->deepSleepVars.dsarEnabledParser = TRUE; + PrsEnable(h_FmPcd); + } + else + p_FmPort->deepSleepVars.dsarEnabledParser = FALSE; + + p_FmPort->deepSleepVars.fmbm_rfne = GET_UINT32(p_FmPort->p_FmPortBmiRegs->rxPortBmiRegs.fmbm_rfne); + WRITE_UINT32(p_FmPort->p_FmPortBmiRegs->rxPortBmiRegs.fmbm_rfne, 0x440000); + + // save rcfg for restoring: accumulate mode is changed by ucode + p_FmPort->deepSleepVars.fmbm_rcfg = GET_UINT32(p_FmPort->port.bmi_regs->rx.fmbm_rcfg); + WRITE_UINT32(p_FmPort->port.bmi_regs->rx.fmbm_rcfg, p_FmPort->deepSleepVars.fmbm_rcfg | BMI_PORT_CFG_AM); + memset(&fmGetSetParams, 0, sizeof (t_FmGetSetParams)); + fmGetSetParams.setParams.type = UPDATE_FPM_BRKC_SLP; + fmGetSetParams.setParams.sleep = 1; + FmGetSetParams(p_FmPort->h_Fm, &fmGetSetParams); + +// ***** issue external request sync command + memset(&fmGetSetParams, 0, sizeof (t_FmGetSetParams)); + fmGetSetParams.setParams.type = UPDATE_FPM_EXTC; + FmGetSetParams(p_FmPort->h_Fm, &fmGetSetParams); + // get + memset(&fmGetSetParams, 0, sizeof (t_FmGetSetParams)); + fmGetSetParams.getParams.type = GET_FMFP_EXTC; + FmGetSetParams(p_FmPort->h_Fm, &fmGetSetParams); + if (fmGetSetParams.getParams.fmfp_extc != 0) + { + // clear + memset(&fmGetSetParams, 0, sizeof (t_FmGetSetParams)); + fmGetSetParams.setParams.type = UPDATE_FPM_EXTC_CLEAR; + FmGetSetParams(p_FmPort->h_Fm, &fmGetSetParams); +} + + memset(&fmGetSetParams, 0, sizeof (t_FmGetSetParams)); + fmGetSetParams.getParams.type = GET_FMFP_EXTC | GET_FM_NPI; + do + { + FmGetSetParams(p_FmPort->h_Fm, &fmGetSetParams); + } while (fmGetSetParams.getParams.fmfp_extc != 0 && fmGetSetParams.getParams.fm_npi == 0); + if (fmGetSetParams.getParams.fm_npi != 0) + XX_Print("FM: Sync did not finish\n"); + + // check that all stoped + memset(&fmGetSetParams, 0, sizeof (t_FmGetSetParams)); + fmGetSetParams.getParams.type = GET_FMQM_GS | GET_FM_NPI; + FmGetSetParams(p_FmPort->h_Fm, &fmGetSetParams); + while (fmGetSetParams.getParams.fmqm_gs & 0xF0000000) + FmGetSetParams(p_FmPort->h_Fm, &fmGetSetParams); + if (fmGetSetParams.getParams.fmqm_gs == 0 && fmGetSetParams.getParams.fm_npi == 0) + XX_Print("FM: Sleeping\n"); +// FM_ChangeClock(p_FmPort->h_Fm, p_FmPort->hardwarePortId); + + return E_OK; +} + +EXPORT_SYMBOL(FM_PORT_EnterDsarFinal); + +void FM_PORT_Dsar_DumpRegs() +{ + uint32_t* hh = XX_PhysToVirt(PTR_TO_UINT(ARDesc)); + DUMP_MEMORY(hh, 0x220); +} + +void FM_PORT_ExitDsar(t_Handle h_FmPortRx, t_Handle h_FmPortTx) +{ + t_FmPort *p_FmPort = (t_FmPort *)h_FmPortRx; + t_FmPort *p_FmPortTx = (t_FmPort *)h_FmPortTx; + t_Handle *h_FmPcd = FmGetPcd(p_FmPort->h_Fm); + t_FmPort *p_FmPortHc = FM_PCD_GetHcPort(h_FmPcd); + t_FmGetSetParams fmGetSetParams; + memset(&fmGetSetParams, 0, sizeof (t_FmGetSetParams)); + fmGetSetParams.setParams.type = UPDATE_FPM_BRKC_SLP; + fmGetSetParams.setParams.sleep = 0; + if (p_FmPort->deepSleepVars.autoResOffsets) + { + XX_Free(p_FmPort->deepSleepVars.autoResOffsets); + p_FmPort->deepSleepVars.autoResOffsets = 0; + } + + if (p_FmPort->deepSleepVars.dsarEnabledParser) + PrsDisable(FmGetPcd(p_FmPort->h_Fm)); + WRITE_UINT32(p_FmPort->p_FmPortBmiRegs->rxPortBmiRegs.fmbm_rfpne, p_FmPort->deepSleepVars.fmbm_rfpne); + WRITE_UINT32(p_FmPort->p_FmPortBmiRegs->rxPortBmiRegs.fmbm_rfne, p_FmPort->deepSleepVars.fmbm_rfne); + WRITE_UINT32(p_FmPort->p_FmPortBmiRegs->rxPortBmiRegs.fmbm_rcfg, p_FmPort->deepSleepVars.fmbm_rcfg); + FmGetSetParams(p_FmPort->h_Fm, &fmGetSetParams); + WRITE_UINT32(p_FmPortTx->p_FmPortBmiRegs->txPortBmiRegs.fmbm_tcmne, p_FmPort->deepSleepVars.fmbm_tcmne); + WRITE_UINT32(p_FmPortTx->p_FmPortBmiRegs->txPortBmiRegs.fmbm_tcfg, p_FmPort->deepSleepVars.fmbm_tcfg); + FM_PORT_Enable(p_FmPortHc); +} + +bool FM_PORT_IsInDsar(t_Handle h_FmPort) +{ + t_FmPort *p_FmPort = (t_FmPort *)h_FmPort; + return PTR_TO_UINT(p_FmPort->deepSleepVars.autoResOffsets); +} + +t_Error FM_PORT_GetDsarStats(t_Handle h_FmPortRx, t_FmPortDsarStats *stats) +{ + t_FmPort *p_FmPort = (t_FmPort *)h_FmPortRx; + struct arOffsets *of = (struct arOffsets*)p_FmPort->deepSleepVars.autoResOffsets; + uint8_t* fmMuramVirtBaseAddr = XX_PhysToVirt(p_FmPort->fmMuramPhysBaseAddr); + uint32_t *param_page = XX_PhysToVirt(p_FmPort->fmMuramPhysBaseAddr + GET_UINT32(p_FmPort->p_FmPortBmiRegs->rxPortBmiRegs.fmbm_rgpr)); + t_ArCommonDesc *ArCommonDescPtr = (t_ArCommonDesc*)(XX_PhysToVirt(p_FmPort->fmMuramPhysBaseAddr + GET_UINT32(*param_page))); + t_DsarArpDescriptor *ArpDescriptor = (t_DsarArpDescriptor*)(PTR_TO_UINT(ArCommonDescPtr) + of->arp); + t_DsarArpStatistics* arp_stats = (t_DsarArpStatistics*)(PTR_TO_UINT(ArpDescriptor->p_Statistics) + fmMuramVirtBaseAddr); + t_DsarIcmpV4Descriptor* ICMPV4Descriptor = (t_DsarIcmpV4Descriptor*)(PTR_TO_UINT(ArCommonDescPtr) + of->icmpv4); + t_DsarIcmpV4Statistics* icmpv4_stats = (t_DsarIcmpV4Statistics*)(PTR_TO_UINT(ICMPV4Descriptor->p_Statistics) + fmMuramVirtBaseAddr); + t_DsarNdDescriptor* NDDescriptor = (t_DsarNdDescriptor*)(PTR_TO_UINT(ArCommonDescPtr) + of->nd); + t_NdStatistics* nd_stats = (t_NdStatistics*)(PTR_TO_UINT(NDDescriptor->p_Statistics) + fmMuramVirtBaseAddr); + t_DsarIcmpV6Descriptor* ICMPV6Descriptor = (t_DsarIcmpV6Descriptor*)(PTR_TO_UINT(ArCommonDescPtr) + of->icmpv6); + t_DsarIcmpV6Statistics* icmpv6_stats = (t_DsarIcmpV6Statistics*)(PTR_TO_UINT(ICMPV6Descriptor->p_Statistics) + fmMuramVirtBaseAddr); + t_DsarSnmpDescriptor* SnmpDescriptor = (t_DsarSnmpDescriptor*)(PTR_TO_UINT(ArCommonDescPtr) + of->snmp); + t_DsarSnmpStatistics* snmp_stats = (t_DsarSnmpStatistics*)(PTR_TO_UINT(SnmpDescriptor->p_Statistics) + fmMuramVirtBaseAddr); + stats->arpArCnt = arp_stats->arCnt; + stats->echoIcmpv4ArCnt = icmpv4_stats->arCnt; + stats->ndpArCnt = nd_stats->arCnt; + stats->echoIcmpv6ArCnt = icmpv6_stats->arCnt; + stats->snmpGetCnt = snmp_stats->snmpGetReqCnt; + stats->snmpGetNextCnt = snmp_stats->snmpGetNextReqCnt; + return E_OK; +} diff --git a/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Port/fm_port.h b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Port/fm_port.h new file mode 100644 index 0000000..85986f5 --- /dev/null +++ b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Port/fm_port.h @@ -0,0 +1,999 @@ +/* + * Copyright 2008-2012 Freescale Semiconductor Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Freescale Semiconductor nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + +/****************************************************************************** + @File fm_port.h + + @Description FM Port internal structures and definitions. +*//***************************************************************************/ +#ifndef __FM_PORT_H +#define __FM_PORT_H + +#include "error_ext.h" +#include "std_ext.h" +#include "fm_port_ext.h" + +#include "fm_common.h" +#include "fm_sp_common.h" +#include "fsl_fman_sp.h" +#include "fm_port_ext.h" +#include "fsl_fman_port.h" + +#define __ERR_MODULE__ MODULE_FM_PORT + + +#define MIN_EXT_BUF_SIZE 64 +#define DATA_ALIGNMENT 64 +#define MAX_LIODN_OFFSET 64 +#define MAX_PORT_FIFO_SIZE MIN(BMI_MAX_FIFO_SIZE, 1024*BMI_FIFO_UNITS) + +/**************************************************************************//** + @Description Memory Map defines +*//***************************************************************************/ +#define BMI_PORT_REGS_OFFSET 0 +#define QMI_PORT_REGS_OFFSET 0x400 +#define PRS_PORT_REGS_OFFSET 0x800 + +/**************************************************************************//** + @Description defaults +*//***************************************************************************/ +#define DEFAULT_PORT_deqHighPriority_1G FALSE +#define DEFAULT_PORT_deqHighPriority_10G TRUE +#define DEFAULT_PORT_deqType e_FM_PORT_DEQ_TYPE1 +#define DEFAULT_PORT_deqPrefetchOption e_FM_PORT_DEQ_FULL_PREFETCH +#define DEFAULT_PORT_deqPrefetchOption_HC e_FM_PORT_DEQ_NO_PREFETCH +#define DEFAULT_PORT_deqByteCnt_10G 0x1400 +#define DEFAULT_PORT_deqByteCnt_1G 0x400 +#define DEFAULT_PORT_bufferPrefixContent_privDataSize DEFAULT_FM_SP_bufferPrefixContent_privDataSize +#define DEFAULT_PORT_bufferPrefixContent_passPrsResult DEFAULT_FM_SP_bufferPrefixContent_passPrsResult +#define DEFAULT_PORT_bufferPrefixContent_passTimeStamp DEFAULT_FM_SP_bufferPrefixContent_passTimeStamp +#define DEFAULT_PORT_bufferPrefixContent_allOtherPCDInfo DEFAULT_FM_SP_bufferPrefixContent_allOtherPCDInfo +#define DEFAULT_PORT_bufferPrefixContent_dataAlign DEFAULT_FM_SP_bufferPrefixContent_dataAlign +#define DEFAULT_PORT_cheksumLastBytesIgnore 0 +#define DEFAULT_PORT_cutBytesFromEnd 4 +#define DEFAULT_PORT_fifoDeqPipelineDepth_IM 2 + +#define DEFAULT_PORT_frmDiscardOverride FALSE + +#define DEFAULT_PORT_dmaSwapData (e_FmDmaSwapOption)DEFAULT_FMAN_SP_DMA_SWAP_DATA +#define DEFAULT_PORT_dmaIntContextCacheAttr (e_FmDmaCacheOption)DEFAULT_FMAN_SP_DMA_INT_CONTEXT_CACHE_ATTR +#define DEFAULT_PORT_dmaHeaderCacheAttr (e_FmDmaCacheOption)DEFAULT_FMAN_SP_DMA_HEADER_CACHE_ATTR +#define DEFAULT_PORT_dmaScatterGatherCacheAttr (e_FmDmaCacheOption)DEFAULT_FMAN_SP_DMA_SCATTER_GATHER_CACHE_ATTR +#define DEFAULT_PORT_dmaWriteOptimize DEFAULT_FMAN_SP_DMA_WRITE_OPTIMIZE + +#define DEFAULT_PORT_noScatherGather DEFAULT_FMAN_SP_NO_SCATTER_GATHER +#define DEFAULT_PORT_forwardIntContextReuse FALSE +#define DEFAULT_PORT_BufMargins_startMargins 32 +#define DEFAULT_PORT_BufMargins_endMargins 0 +#define DEFAULT_PORT_syncReq TRUE +#define DEFAULT_PORT_syncReqForHc FALSE +#define DEFAULT_PORT_color e_FM_PORT_COLOR_GREEN +#define DEFAULT_PORT_errorsToDiscard FM_PORT_FRM_ERR_CLS_DISCARD +/* #define DEFAULT_PORT_dualRateLimitScaleDown e_FM_PORT_DUAL_RATE_LIMITER_NONE */ +/* #define DEFAULT_PORT_rateLimitBurstSizeHighGranularity FALSE */ +#define DEFAULT_PORT_exception IM_EV_BSY +#define DEFAULT_PORT_maxFrameLength 9600 + +#define DEFAULT_notSupported 0xff + +#if (DPAA_VERSION < 11) +#define DEFAULT_PORT_rxFifoPriElevationLevel MAX_PORT_FIFO_SIZE +#define DEFAULT_PORT_rxFifoThreshold (MAX_PORT_FIFO_SIZE*3/4) + +#define DEFAULT_PORT_txFifoMinFillLevel 0 +#define DEFAULT_PORT_txFifoLowComfLevel (5*KILOBYTE) +#define DEFAULT_PORT_fifoDeqPipelineDepth_1G 1 +#define DEFAULT_PORT_fifoDeqPipelineDepth_10G 4 + +#define DEFAULT_PORT_fifoDeqPipelineDepth_OH 2 + +/* Host command port MUST NOT be changed to more than 1 !!! */ +#define DEFAULT_PORT_numOfTasks(type) \ + (uint32_t)((((type) == e_FM_PORT_TYPE_RX_10G) || \ + ((type) == e_FM_PORT_TYPE_TX_10G)) ? 16 : \ + ((((type) == e_FM_PORT_TYPE_RX) || \ + ((type) == e_FM_PORT_TYPE_TX) || \ + ((type) == e_FM_PORT_TYPE_OH_OFFLINE_PARSING)) ? 3 : 1)) + +#define DEFAULT_PORT_extraNumOfTasks(type) \ + (uint32_t)(((type) == e_FM_PORT_TYPE_RX_10G) ? 8 : \ + (((type) == e_FM_PORT_TYPE_RX) ? 2 : 0)) + +#define DEFAULT_PORT_numOfOpenDmas(type) \ + (uint32_t)((((type) == e_FM_PORT_TYPE_TX_10G) || \ + ((type) == e_FM_PORT_TYPE_RX_10G)) ? 8 : 1 ) + +#define DEFAULT_PORT_extraNumOfOpenDmas(type) \ + (uint32_t)(((type) == e_FM_PORT_TYPE_RX_10G) ? 8 : \ + (((type) == e_FM_PORT_TYPE_RX) ? 1 : 0)) + +#define DEFAULT_PORT_numOfFifoBufs(type) \ + (uint32_t)((((type) == e_FM_PORT_TYPE_RX_10G) || \ + ((type) == e_FM_PORT_TYPE_TX_10G)) ? 48 : \ + ((type) == e_FM_PORT_TYPE_RX) ? 45 : \ + ((type) == e_FM_PORT_TYPE_TX) ? 44 : 8) + +#define DEFAULT_PORT_extraNumOfFifoBufs 0 + +#else /* (DPAA_VERSION < 11) */ +/* Defaults are registers' reset values */ +#define DEFAULT_PORT_rxFifoPriElevationLevel MAX_PORT_FIFO_SIZE +#define DEFAULT_PORT_rxFifoThreshold MAX_PORT_FIFO_SIZE + +#define DEFAULT_PORT_txFifoMinFillLevel 0 +#define DEFAULT_PORT_txFifoLowComfLevel (5 * KILOBYTE) +#define DEFAULT_PORT_fifoDeqPipelineDepth_1G 2 +#define DEFAULT_PORT_fifoDeqPipelineDepth_10G 4 + +#define DEFAULT_PORT_fifoDeqPipelineDepth_OH 2 + +#define DEFAULT_PORT_numOfTasks(type) \ + (uint32_t)((((type) == e_FM_PORT_TYPE_RX_10G) || \ + ((type) == e_FM_PORT_TYPE_TX_10G)) ? 14 : \ + (((type) == e_FM_PORT_TYPE_RX) || \ + ((type) == e_FM_PORT_TYPE_TX)) ? 4 : \ + ((type) == e_FM_PORT_TYPE_OH_OFFLINE_PARSING) ? 6 : 1) + +#define DEFAULT_PORT_extraNumOfTasks(type) 0 + +#define DEFAULT_PORT_numOfOpenDmas(type) \ + (uint32_t)(((type) == e_FM_PORT_TYPE_RX_10G) ? 8 : \ + ((type) == e_FM_PORT_TYPE_TX_10G) ? 12 : \ + ((type) == e_FM_PORT_TYPE_RX) ? 2 : \ + ((type) == e_FM_PORT_TYPE_TX) ? 3 : \ + ((type) == e_FM_PORT_TYPE_OH_HOST_COMMAND) ? 2 : 4) + +#define DEFAULT_PORT_extraNumOfOpenDmas(type) 0 + +#define DEFAULT_PORT_numOfFifoBufs(type) \ + (uint32_t) (((type) == e_FM_PORT_TYPE_RX_10G) ? 96 : \ + ((type) == e_FM_PORT_TYPE_TX_10G) ? 64 : \ + ((type) == e_FM_PORT_TYPE_OH_HOST_COMMAND) ? 10 : 50) + +#define DEFAULT_PORT_extraNumOfFifoBufs 0 + +#endif /* (DPAA_VERSION < 11) */ + +#define DEFAULT_PORT_txBdRingLength 16 +#define DEFAULT_PORT_rxBdRingLength 128 +#define DEFAULT_PORT_ImfwExtStructsMemId 0 +#define DEFAULT_PORT_ImfwExtStructsMemAttr MEMORY_ATTR_CACHEABLE + +#define FM_PORT_CG_REG_NUM(_cgId) (((FM_PORT_NUM_OF_CONGESTION_GRPS/32)-1)-_cgId/32) + +/**************************************************************************//** + @Collection PCD Engines +*//***************************************************************************/ +typedef uint32_t fmPcdEngines_t; /**< options as defined below: */ + +#define FM_PCD_NONE 0 /**< No PCD Engine indicated */ +#define FM_PCD_PRS 0x80000000 /**< Parser indicated */ +#define FM_PCD_KG 0x40000000 /**< Keygen indicated */ +#define FM_PCD_CC 0x20000000 /**< Coarse classification indicated */ +#define FM_PCD_PLCR 0x10000000 /**< Policer indicated */ +#define FM_PCD_MANIP 0x08000000 /**< Manipulation indicated */ +/* @} */ + +#define FM_PORT_MAX_NUM_OF_EXT_POOLS_ALL_INTEGRATIONS 8 +#define FM_PORT_MAX_NUM_OF_CONGESTION_GRPS_ALL_INTEGRATIONS 256 +#define FM_PORT_CG_REG_NUM(_cgId) (((FM_PORT_NUM_OF_CONGESTION_GRPS/32)-1)-_cgId/32) + +#define FM_OH_PORT_ID 0 + +/***********************************************************************/ +/* SW parser OFFLOAD labels (offsets) */ +/***********************************************************************/ +#if (DPAA_VERSION == 10) +#define OFFLOAD_SW_PATCH_IPv4_IPR_LABEL 0x300 +#define OFFLOAD_SW_PATCH_IPv6_IPR_LABEL 0x325 +#define OFFLOAD_SW_PATCH_IPv6_IPF_LABEL 0x325 +#else +#define OFFLOAD_SW_PATCH_IPv4_IPR_LABEL 0x100 +/* Will be used for: + * 1. identify fragments + * 2. udp-lite + */ +#define OFFLOAD_SW_PATCH_IPv6_IPR_LABEL 0x146 +/* Will be used for: + * 1. will identify the fragmentable area + * 2. udp-lite + */ +#define OFFLOAD_SW_PATCH_IPv6_IPF_LABEL 0x261 +#define OFFLOAD_SW_PATCH_CAPWAP_LABEL 0x38d +#endif /* (DPAA_VERSION == 10) */ + +#if ((DPAA_VERSION == 10) && defined(FM_CAPWAP_SUPPORT)) +#define UDP_LITE_SW_PATCH_LABEL 0x2E0 +#endif /* ((DPAA_VERSION == 10) && defined(FM_CAPWAP_SUPPORT)) */ + + +/**************************************************************************//** + @Description Memory Mapped Registers +*//***************************************************************************/ + +#if defined(__MWERKS__) && !defined(__GNUC__) +#pragma pack(push,1) +#endif /* defined(__MWERKS__) && ... */ + +typedef struct +{ + volatile uint32_t fmbm_rcfg; /**< Rx Configuration */ + volatile uint32_t fmbm_rst; /**< Rx Status */ + volatile uint32_t fmbm_rda; /**< Rx DMA attributes*/ + volatile uint32_t fmbm_rfp; /**< Rx FIFO Parameters*/ + volatile uint32_t fmbm_rfed; /**< Rx Frame End Data*/ + volatile uint32_t fmbm_ricp; /**< Rx Internal Context Parameters*/ + volatile uint32_t fmbm_rim; /**< Rx Internal Buffer Margins*/ + volatile uint32_t fmbm_rebm; /**< Rx External Buffer Margins*/ + volatile uint32_t fmbm_rfne; /**< Rx Frame Next Engine*/ + volatile uint32_t fmbm_rfca; /**< Rx Frame Command Attributes.*/ + volatile uint32_t fmbm_rfpne; /**< Rx Frame Parser Next Engine*/ + volatile uint32_t fmbm_rpso; /**< Rx Parse Start Offset*/ + volatile uint32_t fmbm_rpp; /**< Rx Policer Profile */ + volatile uint32_t fmbm_rccb; /**< Rx Coarse Classification Base */ + volatile uint32_t fmbm_reth; /**< Rx Excessive Threshold */ + volatile uint32_t reserved1[0x01];/**< (0x03C) */ + volatile uint32_t fmbm_rprai[FM_PORT_PRS_RESULT_NUM_OF_WORDS]; + /**< Rx Parse Results Array Initialization*/ + volatile uint32_t fmbm_rfqid; /**< Rx Frame Queue ID*/ + volatile uint32_t fmbm_refqid; /**< Rx Error Frame Queue ID*/ + volatile uint32_t fmbm_rfsdm; /**< Rx Frame Status Discard Mask*/ + volatile uint32_t fmbm_rfsem; /**< Rx Frame Status Error Mask*/ + volatile uint32_t fmbm_rfene; /**< Rx Frame Enqueue Next Engine */ + volatile uint32_t reserved2[0x02];/**< (0x074-0x078) */ + volatile uint32_t fmbm_rcmne; /**< Rx Frame Continuous Mode Next Engine */ + volatile uint32_t reserved3[0x20];/**< (0x080 0x0FF) */ + volatile uint32_t fmbm_ebmpi[FM_PORT_MAX_NUM_OF_EXT_POOLS_ALL_INTEGRATIONS]; + /**< Buffer Manager pool Information-*/ + volatile uint32_t fmbm_acnt[FM_PORT_MAX_NUM_OF_EXT_POOLS_ALL_INTEGRATIONS]; + /**< Allocate Counter-*/ + volatile uint32_t reserved4[0x08]; + /**< 0x130/0x140 - 0x15F reserved -*/ + volatile uint32_t fmbm_rcgm[FM_PORT_MAX_NUM_OF_CONGESTION_GRPS_ALL_INTEGRATIONS/32]; + /**< Congestion Group Map*/ + volatile uint32_t fmbm_rmpd; /**< BM Pool Depletion */ + volatile uint32_t reserved5[0x1F];/**< (0x184 0x1FF) */ + volatile uint32_t fmbm_rstc; /**< Rx Statistics Counters*/ + volatile uint32_t fmbm_rfrc; /**< Rx Frame Counter*/ + volatile uint32_t fmbm_rfbc; /**< Rx Bad Frames Counter*/ + volatile uint32_t fmbm_rlfc; /**< Rx Large Frames Counter*/ + volatile uint32_t fmbm_rffc; /**< Rx Filter Frames Counter*/ + volatile uint32_t fmbm_rfcd; /**< Rx Frame Discard Counter*/ + volatile uint32_t fmbm_rfldec; /**< Rx Frames List DMA Error Counter*/ + volatile uint32_t fmbm_rodc; /**< Rx Out of Buffers Discard Counter-*/ + volatile uint32_t fmbm_rbdc; /**< Rx Buffers Deallocate Counter-*/ + volatile uint32_t fmbm_rpec; /**< Rx RX Prepare to enqueue Counter-*/ + volatile uint32_t reserved6[0x16];/**< (0x228 0x27F) */ + volatile uint32_t fmbm_rpc; /**< Rx Performance Counters*/ + volatile uint32_t fmbm_rpcp; /**< Rx Performance Count Parameters*/ + volatile uint32_t fmbm_rccn; /**< Rx Cycle Counter*/ + volatile uint32_t fmbm_rtuc; /**< Rx Tasks Utilization Counter*/ + volatile uint32_t fmbm_rrquc; /**< Rx Receive Queue Utilization Counter*/ + volatile uint32_t fmbm_rduc; /**< Rx DMA Utilization Counter*/ + volatile uint32_t fmbm_rfuc; /**< Rx FIFO Utilization Counter*/ + volatile uint32_t fmbm_rpac; /**< Rx Pause Activation Counter*/ + volatile uint32_t reserved7[0x18];/**< (0x2A0-0x2FF) */ + volatile uint32_t fmbm_rdcfg[0x3];/**< Rx Debug-*/ + volatile uint32_t fmbm_rgpr; /**< Rx General Purpose Register. */ + volatile uint32_t reserved8[0x3a];/**< (0x310-0x3FF) */ +} t_FmPortRxBmiRegs; + +typedef struct +{ + volatile uint32_t fmbm_tcfg; /**< Tx Configuration */ + volatile uint32_t fmbm_tst; /**< Tx Status */ + volatile uint32_t fmbm_tda; /**< Tx DMA attributes */ + volatile uint32_t fmbm_tfp; /**< Tx FIFO Parameters */ + volatile uint32_t fmbm_tfed; /**< Tx Frame End Data */ + volatile uint32_t fmbm_ticp; /**< Tx Internal Context Parameters */ + volatile uint32_t fmbm_tfdne; /**< Tx Frame Dequeue Next Engine. */ + volatile uint32_t fmbm_tfca; /**< Tx Frame Command attribute. */ + volatile uint32_t fmbm_tcfqid; /**< Tx Confirmation Frame Queue ID. */ + volatile uint32_t fmbm_tfeqid; /**< Tx Frame Error Queue ID */ + volatile uint32_t fmbm_tfene; /**< Tx Frame Enqueue Next Engine */ + volatile uint32_t fmbm_trlmts; /**< Tx Rate Limiter Scale */ + volatile uint32_t fmbm_trlmt; /**< Tx Rate Limiter */ + volatile uint32_t fmbm_tccb; /**< Tx Coarse Classification Base */ + volatile uint32_t reserved0[0x0e];/**< (0x038-0x070) */ + volatile uint32_t fmbm_tfne; /**< Tx Frame Next Engine */ + volatile uint32_t fmbm_tpfcm[0x02];/**< Tx Priority based Flow Control (PFC) Mapping */ + volatile uint32_t fmbm_tcmne; /**< Tx Frame Continuous Mode Next Engine */ + volatile uint32_t reserved2[0x60];/**< (0x080-0x200) */ + volatile uint32_t fmbm_tstc; /**< Tx Statistics Counters */ + volatile uint32_t fmbm_tfrc; /**< Tx Frame Counter */ + volatile uint32_t fmbm_tfdc; /**< Tx Frames Discard Counter */ + volatile uint32_t fmbm_tfledc; /**< Tx Frame Length error discard counter */ + volatile uint32_t fmbm_tfufdc; /**< Tx Frame unsupported format discard Counter */ + volatile uint32_t fmbm_tbdc; /**< Tx Buffers Deallocate Counter */ + volatile uint32_t reserved3[0x1A];/**< (0x218-0x280) */ + volatile uint32_t fmbm_tpc; /**< Tx Performance Counters*/ + volatile uint32_t fmbm_tpcp; /**< Tx Performance Count Parameters*/ + volatile uint32_t fmbm_tccn; /**< Tx Cycle Counter*/ + volatile uint32_t fmbm_ttuc; /**< Tx Tasks Utilization Counter*/ + volatile uint32_t fmbm_ttcquc; /**< Tx Transmit Confirm Queue Utilization Counter*/ + volatile uint32_t fmbm_tduc; /**< Tx DMA Utilization Counter*/ + volatile uint32_t fmbm_tfuc; /**< Tx FIFO Utilization Counter*/ + volatile uint32_t reserved4[16]; /**< (0x29C-0x2FF) */ + volatile uint32_t fmbm_tdcfg[0x3];/**< Tx Debug-*/ + volatile uint32_t fmbm_tgpr; /**< O/H General Purpose Register */ + volatile uint32_t reserved5[0x3a];/**< (0x310-0x3FF) */ +} t_FmPortTxBmiRegs; + +typedef struct +{ + volatile uint32_t fmbm_ocfg; /**< O/H Configuration */ + volatile uint32_t fmbm_ost; /**< O/H Status */ + volatile uint32_t fmbm_oda; /**< O/H DMA attributes */ + volatile uint32_t fmbm_oicp; /**< O/H Internal Context Parameters */ + volatile uint32_t fmbm_ofdne; /**< O/H Frame Dequeue Next Engine */ + volatile uint32_t fmbm_ofne; /**< O/H Frame Next Engine */ + volatile uint32_t fmbm_ofca; /**< O/H Frame Command Attributes. */ + volatile uint32_t fmbm_ofpne; /**< O/H Frame Parser Next Engine */ + volatile uint32_t fmbm_opso; /**< O/H Parse Start Offset */ + volatile uint32_t fmbm_opp; /**< O/H Policer Profile */ + volatile uint32_t fmbm_occb; /**< O/H Coarse Classification base */ + volatile uint32_t fmbm_oim; /**< O/H Internal margins*/ + volatile uint32_t fmbm_ofp; /**< O/H Fifo Parameters*/ + volatile uint32_t fmbm_ofed; /**< O/H Frame End Data*/ + volatile uint32_t reserved0[2]; /**< (0x038 - 0x03F) */ + volatile uint32_t fmbm_oprai[FM_PORT_PRS_RESULT_NUM_OF_WORDS]; + /**< O/H Parse Results Array Initialization */ + volatile uint32_t fmbm_ofqid; /**< O/H Frame Queue ID */ + volatile uint32_t fmbm_oefqid; /**< O/H Error Frame Queue ID */ + volatile uint32_t fmbm_ofsdm; /**< O/H Frame Status Discard Mask */ + volatile uint32_t fmbm_ofsem; /**< O/H Frame Status Error Mask */ + volatile uint32_t fmbm_ofene; /**< O/H Frame Enqueue Next Engine */ + volatile uint32_t fmbm_orlmts; /**< O/H Rate Limiter Scale */ + volatile uint32_t fmbm_orlmt; /**< O/H Rate Limiter */ + volatile uint32_t fmbm_ocmne; /**< O/H Continuous Mode Next Engine */ + volatile uint32_t reserved1[0x20];/**< (0x080 - 0x0FF) */ + volatile uint32_t fmbm_oebmpi[2]; /**< Buffer Manager Observed Pool Information */ + volatile uint32_t reserved2[0x16];/**< (0x108 - 0x15F) */ + volatile uint32_t fmbm_ocgm; /**< Observed Congestion Group Map */ + volatile uint32_t reserved3[0x7]; /**< (0x164 - 0x17F) */ + volatile uint32_t fmbm_ompd; /**< Observed BMan Pool Depletion */ + volatile uint32_t reserved4[0x1F];/**< (0x184 - 0x1FF) */ + volatile uint32_t fmbm_ostc; /**< O/H Statistics Counters */ + volatile uint32_t fmbm_ofrc; /**< O/H Frame Counter */ + volatile uint32_t fmbm_ofdc; /**< O/H Frames Discard Counter */ + volatile uint32_t fmbm_ofledc; /**< O/H Frames Length Error Discard Counter */ + volatile uint32_t fmbm_ofufdc; /**< O/H Frames Unsupported Format Discard Counter */ + volatile uint32_t fmbm_offc; /**< O/H Filter Frames Counter */ + volatile uint32_t fmbm_ofwdc; /**< - Rx Frames WRED Discard Counter */ + volatile uint32_t fmbm_ofldec; /**< O/H Frames List DMA Error Counter */ + volatile uint32_t fmbm_obdc; /**< O/H Buffers Deallocate Counter */ + volatile uint32_t fmbm_oodc; /**< O/H Out of Buffers Discard Counter */ + volatile uint32_t fmbm_opec; /**< O/H Prepare to enqueue Counter */ + volatile uint32_t reserved5[0x15];/**< ( - 0x27F) */ + volatile uint32_t fmbm_opc; /**< O/H Performance Counters */ + volatile uint32_t fmbm_opcp; /**< O/H Performance Count Parameters */ + volatile uint32_t fmbm_occn; /**< O/H Cycle Counter */ + volatile uint32_t fmbm_otuc; /**< O/H Tasks Utilization Counter */ + volatile uint32_t fmbm_oduc; /**< O/H DMA Utilization Counter */ + volatile uint32_t fmbm_ofuc; /**< O/H FIFO Utilization Counter */ + volatile uint32_t reserved6[26]; /**< (0x298-0x2FF) */ + volatile uint32_t fmbm_odcfg[0x3];/**< O/H Debug (only 1 in P1023) */ + volatile uint32_t fmbm_ogpr; /**< O/H General Purpose Register. */ + volatile uint32_t reserved7[0x3a];/**< (0x310 0x3FF) */ +} t_FmPortOhBmiRegs; + +typedef union +{ + t_FmPortRxBmiRegs rxPortBmiRegs; + t_FmPortTxBmiRegs txPortBmiRegs; + t_FmPortOhBmiRegs ohPortBmiRegs; +} u_FmPortBmiRegs; + +typedef struct +{ + volatile uint32_t reserved1[2]; /**< 0xn024 - 0x02B */ + volatile uint32_t fmqm_pndn; /**< PortID n Dequeue NIA Register */ + volatile uint32_t fmqm_pndc; /**< PortID n Dequeue Config Register */ + volatile uint32_t fmqm_pndtfc; /**< PortID n Dequeue Total Frame Counter */ + volatile uint32_t fmqm_pndfdc; /**< PortID n Dequeue FQID from Default Counter */ + volatile uint32_t fmqm_pndcc; /**< PortID n Dequeue Confirm Counter */ +} t_FmPortNonRxQmiRegs; + +typedef struct +{ + volatile uint32_t fmqm_pnc; /**< PortID n Configuration Register */ + volatile uint32_t fmqm_pns; /**< PortID n Status Register */ + volatile uint32_t fmqm_pnts; /**< PortID n Task Status Register */ + volatile uint32_t reserved0[4]; /**< 0xn00C - 0xn01B */ + volatile uint32_t fmqm_pnen; /**< PortID n Enqueue NIA Register */ + volatile uint32_t fmqm_pnetfc; /**< PortID n Enqueue Total Frame Counter */ + t_FmPortNonRxQmiRegs nonRxQmiRegs; /**< Registers for Tx Hc & Op ports */ +} t_FmPortQmiRegs; + +typedef struct +{ + struct + { + volatile uint32_t softSeqAttach; /**< Soft Sequence Attachment */ + volatile uint32_t lcv; /**< Line-up Enable Confirmation Mask */ + } hdrs[FM_PCD_PRS_NUM_OF_HDRS]; + volatile uint32_t reserved0[0xde]; + volatile uint32_t pcac; /**< Parse Internal Memory Configuration Access Control Register */ + volatile uint32_t pctpid; /**< Parse Internal Memory Configured TPID Register */ +} t_FmPortPrsRegs; + +/**************************************************************************//* + @Description Basic buffer descriptor (BD) structure +*//***************************************************************************/ +typedef _Packed struct +{ + volatile uint16_t status; + volatile uint16_t length; + volatile uint8_t reserved0[0x6]; + volatile uint8_t reserved1[0x1]; + volatile t_FmPhysAddr buff; +} _PackedType t_FmImBd; + +typedef _Packed struct +{ + volatile uint16_t gen; /**< tbd */ + volatile uint8_t reserved0[0x1]; + volatile t_FmPhysAddr bdRingBase; /**< tbd */ + volatile uint16_t bdRingSize; /**< tbd */ + volatile uint16_t offsetIn; /**< tbd */ + volatile uint16_t offsetOut; /**< tbd */ + volatile uint8_t reserved1[0x12]; /**< 0x0e - 0x1f */ +} _PackedType t_FmPortImQd; + +typedef _Packed struct +{ + volatile uint32_t mode; /**< Mode register */ + volatile uint32_t rxQdPtr; /**< tbd */ + volatile uint32_t txQdPtr; /**< tbd */ + volatile uint16_t mrblr; /**< tbd */ + volatile uint16_t rxQdBsyCnt; /**< tbd */ + volatile uint8_t reserved0[0x10]; /**< 0x10 - 0x1f */ + t_FmPortImQd rxQd; + t_FmPortImQd txQd; + volatile uint8_t reserved1[0xa0]; /**< 0x60 - 0xff */ +} _PackedType t_FmPortImPram; + +#if defined(__MWERKS__) && !defined(__GNUC__) +#pragma pack(pop) +#endif /* defined(__MWERKS__) && ... */ + + +/**************************************************************************//** + @Description Registers bit fields +*//***************************************************************************/ + +/**************************************************************************//** + @Description BMI defines +*//***************************************************************************/ +#if (DPAA_VERSION >= 11) +#define BMI_SP_ID_MASK 0xff000000 +#define BMI_SP_ID_SHIFT 24 +#define BMI_SP_EN 0x01000000 +#endif /* (DPAA_VERSION >= 11) */ + +#define BMI_PORT_CFG_EN 0x80000000 +#define BMI_PORT_CFG_EN_MACSEC 0x00800000 +#define BMI_PORT_CFG_FDOVR 0x02000000 +#define BMI_PORT_CFG_IM 0x01000000 +#define BMI_PORT_CFG_AM 0x00000040 +#define BMI_PORT_STATUS_BSY 0x80000000 +#define BMI_COUNTERS_EN 0x80000000 + +#define BMI_PORT_RFNE_FRWD_DCL4C 0x10000000 +#define BMI_PORT_RFNE_FRWD_RPD 0x40000000 +#define BMI_RFNE_FDCS_MASK 0xFF000000 +#define BMI_RFNE_HXS_MASK 0x000000FF + +#define BMI_CMD_MR_LEAC 0x00200000 +#define BMI_CMD_MR_SLEAC 0x00100000 +#define BMI_CMD_MR_MA 0x00080000 +#define BMI_CMD_MR_DEAS 0x00040000 +#define BMI_CMD_RX_MR_DEF (BMI_CMD_MR_LEAC | \ + BMI_CMD_MR_SLEAC | \ + BMI_CMD_MR_MA | \ + BMI_CMD_MR_DEAS) +#define BMI_CMD_ATTR_ORDER 0x80000000 +#define BMI_CMD_ATTR_SYNC 0x02000000 +#define BMI_CMD_ATTR_MODE_MISS_ALLIGN_ADDR_EN 0x00080000 +#define BMI_CMD_ATTR_MACCMD_MASK 0x0000ff00 +#define BMI_CMD_ATTR_MACCMD_OVERRIDE 0x00008000 +#define BMI_CMD_ATTR_MACCMD_SECURED 0x00001000 +#define BMI_CMD_ATTR_MACCMD_SC_MASK 0x00000f00 + +#define BMI_EXT_BUF_POOL_ID_MASK 0x003F0000 +#define BMI_STATUS_RX_MASK_UNUSED (uint32_t)(~(FM_PORT_FRM_ERR_DMA | \ + FM_PORT_FRM_ERR_PHYSICAL | \ + FM_PORT_FRM_ERR_SIZE | \ + FM_PORT_FRM_ERR_CLS_DISCARD | \ + FM_PORT_FRM_ERR_EXTRACTION | \ + FM_PORT_FRM_ERR_NO_SCHEME | \ + FM_PORT_FRM_ERR_COLOR_RED | \ + FM_PORT_FRM_ERR_COLOR_YELLOW | \ + FM_PORT_FRM_ERR_ILL_PLCR | \ + FM_PORT_FRM_ERR_PLCR_FRAME_LEN | \ + FM_PORT_FRM_ERR_PRS_TIMEOUT | \ + FM_PORT_FRM_ERR_PRS_ILL_INSTRUCT | \ + FM_PORT_FRM_ERR_BLOCK_LIMIT_EXCEEDED | \ + FM_PORT_FRM_ERR_PRS_HDR_ERR | \ + FM_PORT_FRM_ERR_IPRE | \ + FM_PORT_FRM_ERR_IPR_NCSP | \ + FM_PORT_FRM_ERR_KEYSIZE_OVERFLOW)) + +#define BMI_STATUS_OP_MASK_UNUSED (uint32_t)(BMI_STATUS_RX_MASK_UNUSED & \ + ~(FM_PORT_FRM_ERR_LENGTH | \ + FM_PORT_FRM_ERR_NON_FM | \ + FM_PORT_FRM_ERR_UNSUPPORTED_FORMAT)) + +#define BMI_RATE_LIMIT_EN 0x80000000 +#define BMI_RATE_LIMIT_BURST_SIZE_GRAN 0x80000000 +#define BMI_RATE_LIMIT_SCALE_BY_2 0x00000001 +#define BMI_RATE_LIMIT_SCALE_BY_4 0x00000002 +#define BMI_RATE_LIMIT_SCALE_BY_8 0x00000003 + +#define BMI_RX_FIFO_THRESHOLD_BC 0x80000000 + +#define BMI_PRS_RESULT_HIGH 0x00000000 +#define BMI_PRS_RESULT_LOW 0xFFFFFFFF + + +#define RX_ERRS_TO_ENQ (FM_PORT_FRM_ERR_DMA | \ + FM_PORT_FRM_ERR_PHYSICAL | \ + FM_PORT_FRM_ERR_SIZE | \ + FM_PORT_FRM_ERR_EXTRACTION | \ + FM_PORT_FRM_ERR_NO_SCHEME | \ + FM_PORT_FRM_ERR_ILL_PLCR | \ + FM_PORT_FRM_ERR_PLCR_FRAME_LEN | \ + FM_PORT_FRM_ERR_PRS_TIMEOUT | \ + FM_PORT_FRM_ERR_PRS_ILL_INSTRUCT | \ + FM_PORT_FRM_ERR_BLOCK_LIMIT_EXCEEDED | \ + FM_PORT_FRM_ERR_PRS_HDR_ERR | \ + FM_PORT_FRM_ERR_KEYSIZE_OVERFLOW | \ + FM_PORT_FRM_ERR_IPRE) + +#define OP_ERRS_TO_ENQ (RX_ERRS_TO_ENQ | \ + FM_PORT_FRM_ERR_LENGTH | \ + FM_PORT_FRM_ERR_NON_FM | \ + FM_PORT_FRM_ERR_UNSUPPORTED_FORMAT) + + +#define BMI_RX_FIFO_PRI_ELEVATION_MASK 0x03FF0000 +#define BMI_RX_FIFO_THRESHOLD_MASK 0x000003FF +#define BMI_TX_FIFO_MIN_FILL_MASK 0x03FF0000 +#define BMI_FIFO_PIPELINE_DEPTH_MASK 0x0000F000 +#define BMI_TX_LOW_COMF_MASK 0x000003FF + +/* shifts */ +#define BMI_PORT_CFG_MS_SEL_SHIFT 16 +#define BMI_DMA_ATTR_IC_CACHE_SHIFT FMAN_SP_DMA_ATTR_IC_CACHE_SHIFT +#define BMI_DMA_ATTR_HDR_CACHE_SHIFT FMAN_SP_DMA_ATTR_HDR_CACHE_SHIFT +#define BMI_DMA_ATTR_SG_CACHE_SHIFT FMAN_SP_DMA_ATTR_SG_CACHE_SHIFT + +#define BMI_IM_FOF_SHIFT 28 +#define BMI_PR_PORTID_SHIFT 24 + +#define BMI_RX_FIFO_PRI_ELEVATION_SHIFT 16 +#define BMI_RX_FIFO_THRESHOLD_SHIFT 0 + +#define BMI_RX_FRAME_END_CS_IGNORE_SHIFT 24 +#define BMI_RX_FRAME_END_CUT_SHIFT 16 + +#define BMI_IC_SIZE_SHIFT FMAN_SP_IC_SIZE_SHIFT + +#define BMI_INT_BUF_MARG_SHIFT 28 + +#define BMI_EXT_BUF_MARG_END_SHIFT FMAN_SP_EXT_BUF_MARG_END_SHIFT + +#define BMI_CMD_ATTR_COLOR_SHIFT 26 +#define BMI_CMD_ATTR_COM_MODE_SHIFT 16 +#define BMI_CMD_ATTR_MACCMD_SHIFT 8 +#define BMI_CMD_ATTR_MACCMD_OVERRIDE_SHIFT 15 +#define BMI_CMD_ATTR_MACCMD_SECURED_SHIFT 12 +#define BMI_CMD_ATTR_MACCMD_SC_SHIFT 8 + +#define BMI_POOL_DEP_NUM_OF_POOLS_VECTOR_SHIFT 24 + +#define BMI_TX_FIFO_MIN_FILL_SHIFT 16 +#define BMI_TX_LOW_COMF_SHIFT 0 + +#define BMI_PERFORMANCE_TASK_COMP_SHIFT 24 +#define BMI_PERFORMANCE_PORT_COMP_SHIFT 16 +#define BMI_PERFORMANCE_DMA_COMP_SHIFT 12 +#define BMI_PERFORMANCE_FIFO_COMP_SHIFT 0 + +#define BMI_MAX_BURST_SHIFT 16 +#define BMI_COUNT_RATE_UNIT_SHIFT 16 + +/* sizes */ +#define FRAME_END_DATA_SIZE 16 +#define FRAME_OFFSET_UNITS 16 +#define MIN_TX_INT_OFFSET 16 +#define MAX_FRAME_OFFSET 64 +#define MAX_FIFO_PIPELINE_DEPTH 8 +#define MAX_PERFORMANCE_TASK_COMP 64 +#define MAX_PERFORMANCE_TX_QUEUE_COMP 8 +#define MAX_PERFORMANCE_RX_QUEUE_COMP 64 +#define MAX_PERFORMANCE_DMA_COMP 16 +#define MAX_NUM_OF_TASKS 64 +#define MAX_NUM_OF_EXTRA_TASKS 8 +#define MAX_NUM_OF_DMAS 16 +#define MAX_NUM_OF_EXTRA_DMAS 8 +#define MAX_BURST_SIZE 1024 +#define MIN_NUM_OF_OP_DMAS 2 + + +/**************************************************************************//** + @Description QMI defines +*//***************************************************************************/ +/* masks */ +#define QMI_PORT_CFG_EN 0x80000000 +#define QMI_PORT_CFG_EN_COUNTERS 0x10000000 +#define QMI_PORT_STATUS_DEQ_TNUM_BSY 0x80000000 +#define QMI_PORT_STATUS_DEQ_FD_BSY 0x20000000 + +#define QMI_DEQ_CFG_PREFETCH_NO_TNUM 0x02000000 +#define QMI_DEQ_CFG_PREFETCH_WAITING_TNUM 0 +#define QMI_DEQ_CFG_PREFETCH_1_FRAME 0 +#define QMI_DEQ_CFG_PREFETCH_3_FRAMES 0x01000000 + +#define QMI_DEQ_CFG_PRI 0x80000000 +#define QMI_DEQ_CFG_TYPE1 0x10000000 +#define QMI_DEQ_CFG_TYPE2 0x20000000 +#define QMI_DEQ_CFG_TYPE3 0x30000000 + +#define QMI_DEQ_CFG_SUBPORTAL_MASK 0x1f +#define QMI_DEQ_CFG_SUBPORTAL_SHIFT 20 + +/**************************************************************************//** + @Description PARSER defines +*//***************************************************************************/ +/* masks */ +#define PRS_HDR_ERROR_DIS 0x00000800 +#define PRS_HDR_SW_PRS_EN 0x00000400 +#define PRS_CP_OFFSET_MASK 0x0000000F +#define PRS_TPID1_MASK 0xFFFF0000 +#define PRS_TPID2_MASK 0x0000FFFF +#define PRS_TPID_DFLT 0x91009100 + +#define PRS_HDR_MPLS_LBL_INTER_EN 0x00200000 +#define PRS_HDR_IPV6_ROUTE_HDR_EN 0x00008000 +#define PRS_HDR_PPPOE_MTU_CHECK_EN 0x80000000 +#define PRS_HDR_UDP_PAD_REMOVAL 0x80000000 +#define PRS_HDR_TCP_PAD_REMOVAL 0x80000000 +#define PRS_CAC_STOP 0x00000001 +#define PRS_CAC_ACTIVE 0x00000100 + +/* shifts */ +#define PRS_PCTPID_SHIFT 16 +#define PRS_HDR_MPLS_NEXT_HDR_SHIFT 22 +#define PRS_HDR_ETH_BC_SHIFT 28 +#define PRS_HDR_ETH_MC_SHIFT 24 +#define PRS_HDR_VLAN_STACKED_SHIFT 16 +#define PRS_HDR_MPLS_STACKED_SHIFT 16 +#define PRS_HDR_IPV4_1_BC_SHIFT 28 +#define PRS_HDR_IPV4_1_MC_SHIFT 24 +#define PRS_HDR_IPV4_2_UC_SHIFT 20 +#define PRS_HDR_IPV4_2_MC_BC_SHIFT 16 +#define PRS_HDR_IPV6_1_MC_SHIFT 24 +#define PRS_HDR_IPV6_2_UC_SHIFT 20 +#define PRS_HDR_IPV6_2_MC_SHIFT 16 + +#define PRS_HDR_ETH_BC_MASK 0x0fffffff +#define PRS_HDR_ETH_MC_MASK 0xf0ffffff +#define PRS_HDR_VLAN_STACKED_MASK 0xfff0ffff +#define PRS_HDR_MPLS_STACKED_MASK 0xfff0ffff +#define PRS_HDR_IPV4_1_BC_MASK 0x0fffffff +#define PRS_HDR_IPV4_1_MC_MASK 0xf0ffffff +#define PRS_HDR_IPV4_2_UC_MASK 0xff0fffff +#define PRS_HDR_IPV4_2_MC_BC_MASK 0xfff0ffff +#define PRS_HDR_IPV6_1_MC_MASK 0xf0ffffff +#define PRS_HDR_IPV6_2_UC_MASK 0xff0fffff +#define PRS_HDR_IPV6_2_MC_MASK 0xfff0ffff + +/* others */ +#define PRS_HDR_ENTRY_SIZE 8 +#define DEFAULT_CLS_PLAN_VECTOR 0xFFFFFFFF + +#define IPSEC_SW_PATCH_START 0x20 +#define SCTP_SW_PATCH_START 0x4D +#define DCCP_SW_PATCH_START 0x41 + +/**************************************************************************//** + @Description IM defines +*//***************************************************************************/ +#define BD_R_E 0x80000000 +#define BD_L 0x08000000 + +#define BD_RX_CRE 0x00080000 +#define BD_RX_FTL 0x00040000 +#define BD_RX_FTS 0x00020000 +#define BD_RX_OV 0x00010000 + +#define BD_RX_ERRORS (BD_RX_CRE | BD_RX_FTL | BD_RX_FTS | BD_RX_OV) + +#define FM_IM_SIZEOF_BD sizeof(t_FmImBd) + +#define BD_STATUS_MASK 0xffff0000 +#define BD_LENGTH_MASK 0x0000ffff + +#define BD_STATUS_AND_LENGTH_SET(bd, val) WRITE_UINT32(*(volatile uint32_t*)(bd), (val)) + +#define BD_STATUS_AND_LENGTH(bd) GET_UINT32(*(volatile uint32_t*)(bd)) + +#define BD_GET(id) &p_FmPort->im.p_BdRing[id] + +#define IM_ILEGAL_BD_ID 0xffff + +/* others */ +#define IM_PRAM_ALIGN 0x100 + +/* masks */ +#define IM_MODE_GBL 0x20000000 +#define IM_MODE_BO_MASK 0x18000000 +#define IM_MODE_BO_SHIFT 3 +#define IM_MODE_GRC_STP 0x00800000 + +#define IM_MODE_SET_BO(val) (uint32_t)((val << (31-IM_MODE_BO_SHIFT)) & IM_MODE_BO_MASK) + +#define IM_RXQD_BSYINTM 0x0008 +#define IM_RXQD_RXFINTM 0x0010 +#define IM_RXQD_FPMEVT_SEL_MASK 0x0003 + +#define IM_EV_BSY 0x40000000 +#define IM_EV_RX 0x80000000 + + +/**************************************************************************//** + @Description Additional defines +*//***************************************************************************/ + +typedef struct { + t_Handle h_FmMuram; + t_FmPortImPram *p_FmPortImPram; + uint8_t fwExtStructsMemId; + uint32_t fwExtStructsMemAttr; + uint16_t bdRingSize; + t_FmImBd *p_BdRing; + t_Handle *p_BdShadow; + uint16_t currBdId; + uint16_t firstBdOfFrameId; + + /* Rx port parameters */ + uint8_t dataMemId; /**< Memory partition ID for data buffers */ + uint32_t dataMemAttributes; /**< Memory attributes for data buffers */ + t_BufferPoolInfo rxPool; + uint16_t mrblr; + uint16_t rxFrameAccumLength; + t_FmPortImRxStoreCallback *f_RxStore; + + /* Tx port parameters */ + uint32_t txFirstBdStatus; + t_FmPortImTxConfCallback *f_TxConf; +} t_FmMacIm; + + +typedef struct { + struct fman_port_cfg dfltCfg; + uint32_t dfltFqid; + uint32_t confFqid; + uint32_t errFqid; + uintptr_t baseAddr; + uint8_t deqSubPortal; + bool deqHighPriority; + e_FmPortDeqType deqType; + e_FmPortDeqPrefetchOption deqPrefetchOption; + uint16_t deqByteCnt; + uint8_t cheksumLastBytesIgnore; + uint8_t cutBytesFromEnd; + t_FmBufPoolDepletion bufPoolDepletion; + uint8_t pipelineDepth; + uint16_t fifoLowComfLevel; + bool frmDiscardOverride; + bool enRateLimit; + t_FmPortRateLimit rateLimit; + e_FmPortDualRateLimiterScaleDown rateLimitDivider; + bool enBufPoolDepletion; + uint16_t liodnOffset; + uint16_t liodnBase; + t_FmExtPools extBufPools; + e_FmDmaSwapOption dmaSwapData; + e_FmDmaCacheOption dmaIntContextCacheAttr; + e_FmDmaCacheOption dmaHeaderCacheAttr; + e_FmDmaCacheOption dmaScatterGatherCacheAttr; + bool dmaReadOptimize; + bool dmaWriteOptimize; + uint32_t txFifoMinFillLevel; + uint32_t txFifoLowComfLevel; + uint32_t rxFifoPriElevationLevel; + uint32_t rxFifoThreshold; + t_FmSpBufMargins bufMargins; + t_FmSpIntContextDataCopy intContext; + bool syncReq; + e_FmPortColor color; + fmPortFrameErrSelect_t errorsToDiscard; + fmPortFrameErrSelect_t errorsToEnq; + bool forwardReuseIntContext; + t_FmBufferPrefixContent bufferPrefixContent; + t_FmBackupBmPools *p_BackupBmPools; + bool dontReleaseBuf; + bool setNumOfTasks; + bool setNumOfOpenDmas; + bool setSizeOfFifo; +#if (DPAA_VERSION >= 11) + bool noScatherGather; +#endif /* (DPAA_VERSION >= 11) */ + +#ifdef FM_HEAVY_TRAFFIC_HANG_ERRATA_FMAN_A005669 + bool bcbWorkaround; +#endif /* FM_HEAVY_TRAFFIC_HANG_ERRATA_FMAN_A005669 */ +} t_FmPortDriverParam; + + +typedef struct t_FmPortRxPoolsParams +{ + uint8_t numOfPools; + uint16_t secondLargestBufSize; + uint16_t largestBufSize; +} t_FmPortRxPoolsParams; + +typedef struct t_FmPortDsarVars { + t_Handle *autoResOffsets; + t_FmPortDsarTablesSizes *autoResMaxSizes; + uint32_t fmbm_tcfg; + uint32_t fmbm_tcmne; + uint32_t fmbm_rfne; + uint32_t fmbm_rfpne; + uint32_t fmbm_rcfg; + bool dsarEnabledParser; +} t_FmPortDsarVars; +typedef struct { + struct fman_port port; + t_Handle h_Fm; + t_Handle h_FmPcd; + t_Handle h_FmMuram; + t_FmRevisionInfo fmRevInfo; + uint8_t portId; + e_FmPortType portType; + int enabled; + char name[MODULE_NAME_SIZE]; + uint8_t hardwarePortId; + uint16_t fmClkFreq; + t_FmPortQmiRegs *p_FmPortQmiRegs; + u_FmPortBmiRegs *p_FmPortBmiRegs; + t_FmPortPrsRegs *p_FmPortPrsRegs; + fmPcdEngines_t pcdEngines; + uint32_t savedBmiNia; + uint8_t netEnvId; + uint32_t optArray[FM_PCD_MAX_NUM_OF_OPTIONS(FM_PCD_MAX_NUM_OF_CLS_PLANS)]; + uint32_t lcvs[FM_PCD_PRS_NUM_OF_HDRS]; + uint8_t privateInfo; + uint32_t schemesPerPortVector; + bool useClsPlan; + uint8_t clsPlanGrpId; + t_Handle ccTreeId; + t_Handle completeArg; + void (*f_Complete)(t_Handle arg); + t_FmSpBufferOffsets bufferOffsets; + /* Independent-Mode parameters support */ + bool imEn; + t_FmMacIm im; + volatile bool lock; + t_Handle h_Spinlock; + t_FmPortExceptionCallback *f_Exception; + t_Handle h_App; + uint8_t internalBufferOffset; + uint8_t fmanCtrlEventId; + uint32_t exceptions; + bool polling; + t_FmExtPools extBufPools; + uint32_t requiredAction; + uint32_t savedQmiPnen; + uint32_t savedBmiFene; + uint32_t savedBmiFpne; + uint32_t savedBmiCmne; + uint32_t savedBmiOfp; + uint32_t savedNonRxQmiRegsPndn; + uint32_t origNonRxQmiRegsPndn; + int savedPrsStartOffset; + bool includeInPrsStatistics; + uint16_t maxFrameLength; + t_FmFmanCtrl orFmanCtrl; + t_FmPortRsrc openDmas; + t_FmPortRsrc tasks; + t_FmPortRsrc fifoBufs; + t_FmPortRxPoolsParams rxPoolsParams; +// bool explicitUserSizeOfFifo; + t_Handle h_IpReassemblyManip; + t_Handle h_CapwapReassemblyManip; + t_Handle h_ReassemblyTree; + uint64_t fmMuramPhysBaseAddr; +#if (DPAA_VERSION >= 11) + bool vspe; + uint8_t dfltRelativeId; + e_FmPortGprFuncType gprFunc; + t_FmPcdCtrlParamsPage *p_ParamsPage; +#endif /* (DPAA_VERSION >= 11) */ + t_FmPortDsarVars deepSleepVars; + t_FmPortDriverParam *p_FmPortDriverParam; +} t_FmPort; + + +void FmPortConfigIM (t_FmPort *p_FmPort, t_FmPortParams *p_FmPortParams); +t_Error FmPortImCheckInitParameters(t_FmPort *p_FmPort); + +t_Error FmPortImInit(t_FmPort *p_FmPort); +void FmPortImFree(t_FmPort *p_FmPort); + +t_Error FmPortImEnable (t_FmPort *p_FmPort); +t_Error FmPortImDisable (t_FmPort *p_FmPort); +t_Error FmPortImRx (t_FmPort *p_FmPort); + +void FmPortSetMacsecLcv(t_Handle h_FmPort); +void FmPortSetMacsecCmd(t_Handle h_FmPort, uint8_t dfltSci); + + +t_Error FM_PORT_SetNumOfOpenDmas(t_Handle h_FmPort, t_FmPortRsrc *p_NumOfOpenDmas); +t_Error FM_PORT_SetNumOfTasks(t_Handle h_FmPort, t_FmPortRsrc *p_NumOfTasks); +t_Error FM_PORT_SetSizeOfFifo(t_Handle h_FmPort, t_FmPortRsrc *p_SizeOfFifo); + +static __inline__ uint8_t * BdBufferGet (t_PhysToVirt *f_PhysToVirt, t_FmImBd *p_Bd) +{ + uint64_t physAddr = (uint64_t)((uint64_t)GET_UINT8(p_Bd->buff.high) << 32); + physAddr |= GET_UINT32(p_Bd->buff.low); + + return (uint8_t *)f_PhysToVirt((physAddress_t)(physAddr)); +} + +static __inline__ void SET_ADDR(volatile t_FmPhysAddr *fmPhysAddr, uint64_t value) +{ + WRITE_UINT8(fmPhysAddr->high,(uint8_t)((value & 0x000000ff00000000LL) >> 32)); + WRITE_UINT32(fmPhysAddr->low,(uint32_t)value); +} + +static __inline__ void BdBufferSet(t_VirtToPhys *f_VirtToPhys, t_FmImBd *p_Bd, uint8_t *p_Buffer) +{ + uint64_t physAddr = (uint64_t)(f_VirtToPhys(p_Buffer)); + SET_ADDR(&p_Bd->buff, physAddr); +} + +static __inline__ uint16_t GetNextBdId(t_FmPort *p_FmPort, uint16_t id) +{ + if (id < p_FmPort->im.bdRingSize-1) + return (uint16_t)(id+1); + else + return 0; +} + +void FM_PORT_Dsar_DumpRegs(void); + + +#endif /* __FM_PORT_H */ diff --git a/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Port/fm_port_dsar.h b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Port/fm_port_dsar.h new file mode 100755 index 0000000..95619ef --- /dev/null +++ b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Port/fm_port_dsar.h @@ -0,0 +1,494 @@ +/* + * Copyright 2008-2012 Freescale Semiconductor Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Freescale Semiconductor nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/**************************************************************************//** + @File fm_port_dsar.h + + @Description Deep Sleep Auto Response project - common module header file. + + Author - Eyal Harari + + @Cautions See the FMan Controller spec and design document for more information. +*//***************************************************************************/ + +#ifndef __FM_PORT_DSAR_H_ +#define __FM_PORT_DSAR_H_ + +#define DSAR_GETSER_MASK 0xFF0000FF + +#if defined(__MWERKS__) && !defined(__GNUC__) +#pragma pack(push,1) +#endif /* defined(__MWERKS__) && ... */ + +/**************************************************************************//** + @Description Deep Sleep Auto Response VLAN-IPv4 Binding Table (for ARP/ICMPv4) + Refer to the FMan Controller spec for more details. +*//***************************************************************************/ +typedef _Packed struct +{ + uint32_t ipv4Addr; /*!< 32 bit IPv4 Address. */ + uint16_t vlanId; /*!< 12 bits VLAN ID. The 4 left-most bits should be cleared */ + /*!< This field should be 0x0000 for an entry with no VLAN tag or a null VLAN ID. */ + uint16_t reserved; +} _PackedType t_DsarArpBindingEntry; + +/**************************************************************************//** + @Description Deep Sleep Auto Response Address Resolution Protocol Statistics Descriptor + Refer to the FMan Controller spec for more details. + 0x00 INVAL_CNT Invalid ARP IPv4-Ethernet counter + 0x04 ECHO_CNT Echo counter + 0x08 CD_CNT Conflict Detection counter + 0x0C AR_CNT Auto-Response counter + 0x10 RATM_CNT Replies Addressed To Me counter + 0x14 UKOP_CNT Unknown Operation counter + 0x18 NMTP_CNT Not my TPA counter + 0x1C NMVLAN_CNT Not My VLAN counter +*//***************************************************************************/ +typedef _Packed struct +{ + uint32_t invalCnt; /**< Invalid ARP IPv4-Ethernet counter. */ + uint32_t echoCnt; /**< Echo counter. */ + uint32_t cdCnt; /**< Conflict Detection counter. */ + uint32_t arCnt; /**< Auto-Response counter. */ + uint32_t ratmCnt; /**< Replies Addressed To Me counter. */ + uint32_t ukopCnt; /**< Unknown Operation counter. */ + uint32_t nmtpCnt; /**< Not my TPA counter. */ + uint32_t nmVlanCnt; /**< Not My VLAN counter */ +} _PackedType t_DsarArpStatistics; + + +/**************************************************************************//** + @Description Deep Sleep Auto Response Address Resolution Protocol Descriptor + 0x0 0-15 Control bits [0-15]. Bit 15 = CDEN. + 0x2 0-15 NumOfBindings Number of entries in the binding list. + 0x4 0-15 BindingsPointer Bindings Pointer. This points to an IPv4-MAC Addresses Bindings list. + 0x6 0-15 + 0x8 0-15 StatisticsPointer Statistics Pointer. This field points to the ARP Descriptors statistics data structure. + 0xA 0-15 + 0xC 0-15 Reserved Reserved. Must be cleared. + 0xE 015 + +*//***************************************************************************/ +typedef _Packed struct +{ + uint16_t control; /** Control bits [0-15]. Bit 15 = CDEN */ + uint16_t numOfBindings; /**< Number of VLAN-IPv4 */ + uint32_t p_Bindings; /**< VLAN-IPv4 Bindings table pointer. */ + uint32_t p_Statistics; /**< Statistics Data Structure pointer. */ + uint32_t reserved1; /**< Reserved. */ +} _PackedType t_DsarArpDescriptor; + + +/**************************************************************************//** + @Description Deep Sleep Auto Response VLAN-IPv4 Binding Table (for ARP/ICMPv4) + Refer to the FMan Controller spec for more details. +*//***************************************************************************/ +typedef _Packed struct +{ + uint32_t ipv4Addr; /*!< 32 bit IPv4 Address. */ + uint16_t vlanId; /*!< 12 bits VLAN ID. The 4 left-most bits should be cleared */ + /*!< This field should be 0x0000 for an entry with no VLAN tag or a null VLAN ID. */ + uint16_t reserved; +} _PackedType t_DsarIcmpV4BindingEntry; + +/**************************************************************************//** + @Description Deep Sleep Auto Response ICMPv4 Statistics Descriptor + Refer to the FMan Controller spec for more details. + 0x00 INVAL_CNT Invalid ICMPv4 header counter + 0x04 NMVLAN_CNT Not My VLAN counter + 0x08 NMIP_CNT Not My IP counter + 0x0C AR_CNT Auto-Response counter + 0x10 CSERR_CNT Checksum Error counter + 0x14 Reserved Reserved + 0x18 Reserved Reserved + 0x1C Reserved Reserved + +*//***************************************************************************/ +typedef _Packed struct +{ + uint32_t invalCnt; /**< Invalid ICMPv4 Echo counter. */ + uint32_t nmVlanCnt; /**< Not My VLAN counter */ + uint32_t nmIpCnt; /**< Not My IP counter */ + uint32_t arCnt; /**< Auto-Response counter */ + uint32_t cserrCnt; /**< Checksum Error counter */ + uint32_t reserved0; /**< Reserved */ + uint32_t reserved1; /**< Reserved */ + uint32_t reserved2; /**< Reserved */ +} _PackedType t_DsarIcmpV4Statistics; + + + +/**************************************************************************//** + @Description Deep Sleep Auto Response ICMPv4 Descriptor + 0x0 0-15 Control bits [0-15] + 0x2 0-15 NumOfBindings Number of entries in the binding list. + 0x4 0-15 BindingsPointer Bindings Pointer. This points to an VLAN-IPv4 Addresses Bindings list. + 0x6 0-15 + 0x8 0-15 StatisticsPointer Statistics Pointer. This field points to the ICMPv4 statistics data structure. + 0xA 0-15 + 0xC 0-15 Reserved Reserved. Must be cleared. + 0xE 015 + +*//***************************************************************************/ +typedef _Packed struct +{ + uint16_t control; /** Control bits [0-15]. */ + uint16_t numOfBindings; /**< Number of VLAN-IPv4 */ + uint32_t p_Bindings; /**< VLAN-IPv4 Bindings table pointer. */ + uint32_t p_Statistics; /**< Statistics Data Structure pointer. */ + uint32_t reserved1; /**< Reserved. */ +} _PackedType t_DsarIcmpV4Descriptor; + +/**************************************************************************//** + @Description Deep Sleep Auto Response VLAN-IPv4 Binding Table (for ARP/ICMPv4) + The 4 left-most bits (15:12) of the VlanId parameter are control flags. + Flags[3:1] (VlanId[15:13]): Reserved, should be cleared. + Flags[0] (VlanId[12]): Temporary address. + • 0 - Assigned IP address. + • 1- Temporary (tentative) IP address. + Refer to the FMan Controller spec for more details. +*//***************************************************************************/ +typedef _Packed struct +{ + uint32_t ipv6Addr[4]; /*!< 3 * 32 bit IPv4 Address. */ + uint16_t resFlags:4; /*!< reserved flags. should be cleared */ + uint16_t vlanId:12; /*!< 12 bits VLAN ID. */ + /*!< This field should be 0x000 for an entry with no VLAN tag or a null VLAN ID. */ + uint16_t reserved; +} _PackedType t_DsarIcmpV6BindingEntry; + +/**************************************************************************//** + @Description Deep Sleep Auto Response ICMPv4 Statistics Descriptor + Refer to the FMan Controller spec for more details. + 0x00 INVAL_CNT Invalid ICMPv4 header counter + 0x04 NMVLAN_CNT Not My VLAN counter + 0x08 NMIP_CNT Not My IP counter + 0x0C AR_CNT Auto-Response counter + 0x10 CSERR_CNT Checksum Error counter + 0x14 MCAST_CNT Multicast counter + 0x18 Reserved Reserved + 0x1C Reserved Reserved + +*//***************************************************************************/ +typedef _Packed struct +{ + uint32_t invalCnt; /**< Invalid ICMPv4 Echo counter. */ + uint32_t nmVlanCnt; /**< Not My VLAN counter */ + uint32_t nmIpCnt; /**< Not My IP counter */ + uint32_t arCnt; /**< Auto-Response counter */ + uint32_t reserved1; /**< Reserved */ + uint32_t reserved2; /**< Reserved */ + uint32_t reserved3; /**< Reserved */ + uint32_t reserved4; /**< Reserved */ +} _PackedType t_DsarIcmpV6Statistics; + +/**************************************************************************//** + @Description Deep Sleep Auto Response Neighbor Discovery Statistics Descriptor + 0x00 INVAL_CNT Invalid Neighbor Discovery message counter + 0x04 NMVLAN_CNT Not My VLAN counter + 0x08 NMIP_CNT Not My IP counter + 0x0C AR_CNT Auto-Response counter + 0x10 CSERR_CNT Checksum Error counter + 0x14 USADVERT_CNT Unsolicited Neighbor Advertisements counter + 0x18 NMMCAST_CNT Not My Multicast group counter + 0x1C NSLLA_CNT No Source Link-Layer Address counter. Indicates that there was a match on a Target + Address of a packet that its source IP address is a unicast address, but the ICMPv6 + Source Link-layer Address option is omitted +*//***************************************************************************/ +typedef _Packed struct +{ + uint32_t invalCnt; /**< Invalid ICMPv4 Echo counter. */ + uint32_t nmVlanCnt; /**< Not My VLAN counter */ + uint32_t nmIpCnt; /**< Not My IP counter */ + uint32_t arCnt; /**< Auto-Response counter */ + uint32_t reserved1; /**< Reserved */ + uint32_t usadvertCnt; /**< Unsolicited Neighbor Advertisements counter */ + uint32_t nmmcastCnt; /**< Not My Multicast group counter */ + uint32_t nsllaCnt; /**< No Source Link-Layer Address counter */ +} _PackedType t_NdStatistics; + +/**************************************************************************//** + @Description Deep Sleep Auto Response ICMPv6 Descriptor + 0x0 0-15 Control bits [0-15] + 0x2 0-15 NumOfBindings Number of entries in the binding list. + 0x4 0-15 BindingsPointer Bindings Pointer. This points to an VLAN-IPv4 Addresses Bindings list. + 0x6 0-15 + 0x8 0-15 StatisticsPointer Statistics Pointer. This field points to the ICMPv4 statistics data structure. + 0xA 0-15 + 0xC 0-15 Reserved Reserved. Must be cleared. + 0xE 015 + +*//***************************************************************************/ +typedef _Packed struct +{ + uint16_t control; /** Control bits [0-15]. */ + uint16_t numOfBindings; /**< Number of VLAN-IPv6 */ + uint32_t p_Bindings; /**< VLAN-IPv4 Bindings table pointer. */ + uint32_t p_Statistics; /**< Statistics Data Structure pointer. */ + uint32_t reserved1; /**< Reserved. */ +} _PackedType t_DsarIcmpV6Descriptor; + + +/**************************************************************************//** + @Description Internet Control Message Protocol (ICMPv6) Echo message header + The fields names are taken from RFC 4443. +*//***************************************************************************/ +/* 0 1 2 3 */ +/* 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 */ +/* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ */ +/* | Type | Code | Checksum | */ +/* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ */ +/* | Identifier | Sequence Number | */ +/* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ */ +/* | Data ... */ +/* +-+-+-+-+- */ +typedef _Packed struct +{ + uint8_t type; + uint8_t code; + uint16_t checksum; + uint16_t identifier; + uint16_t sequenceNumber; +} _PackedType t_IcmpV6EchoHdr; + +/**************************************************************************//** + @Description Internet Control Message Protocol (ICMPv6) + Neighbor Solicitation/Advertisement header + The fields names are taken from RFC 4861. + The R/S/O fields are valid for Neighbor Advertisement only +*//***************************************************************************/ +/* 0 1 2 3 + * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Type | Code | Checksum | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * |R|S|O| Reserved | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | | + * + + + * | | + * + Target Address + + * | | + * + + + * | | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Options ... + * +-+-+-+-+-+-+-+-+-+-+-+- + * + * Options Format: + * 0 1 2 3 + * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Type | Length | Link-Layer Address ... | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Link-Layer Address | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +*/ +typedef _Packed struct +{ + uint8_t type; + uint8_t code; + uint16_t checksum; + uint32_t router:1; + uint32_t solicited:1; + uint32_t override:1; + uint32_t reserved:29; + uint32_t targetAddr[4]; + uint8_t optionType; + uint8_t optionLength; + uint8_t linkLayerAddr[6]; +} _PackedType t_IcmpV6NdHdr; + +/**************************************************************************//** + @Description Deep Sleep Auto Response ICMPv6 Descriptor + 0x0 0-15 Control bits [0-15] + 0x2 0-15 NumOfBindings Number of entries in the binding list. + 0x4 0-15 BindingsPointer Bindings Pointer. This points to an VLAN-IPv4 Addresses Bindings list. + 0x6 0-15 + 0x8 0-15 StatisticsPointer Statistics Pointer. This field points to the ICMPv4 statistics data structure. + 0xA 0-15 + 0xC 0-15 Reserved Reserved. Must be cleared. + 0xE 015 + +*//***************************************************************************/ +typedef _Packed struct +{ + uint16_t control; /** Control bits [0-15]. */ + uint16_t numOfBindings; /**< Number of VLAN-IPv6 */ + uint32_t p_Bindings; /**< VLAN-IPv4 Bindings table pointer. */ + uint32_t p_Statistics; /**< Statistics Data Structure pointer. */ + uint32_t solicitedAddr; /**< Solicited Node Multicast Group Address */ +} _PackedType t_DsarNdDescriptor; + +/**************************************************************************//** +@Description Deep Sleep Auto Response SNMP OIDs table entry + +*//***************************************************************************/ +typedef struct { + uint16_t oidSize; /**< Size in octets of the OID. */ + uint16_t resSize; /**< Size in octets of the value that is attached to the OID. */ + uint32_t p_Oid; /**< Pointer to the OID. OID is encoded in BER but type and length are excluded. */ + uint32_t resValOrPtr; /**< Value (for up to 4 octets) or pointer to the Value. Encoded in BER. */ + uint32_t reserved; +} t_OidsTblEntry; + +/**************************************************************************//** + @Description Deep Sleep Auto Response SNMP IPv4 Addresses Table Entry + Refer to the FMan Controller spec for more details. +*//***************************************************************************/ +typedef struct +{ + uint32_t ipv4Addr; /*!< 32 bit IPv4 Address. */ + uint16_t vlanId; /*!< 12 bits VLAN ID. The 4 left-most bits should be cleared */ + /*!< This field should be 0x0000 for an entry with no VLAN tag or a null VLAN ID. */ + uint16_t reserved; +} t_DsarSnmpIpv4AddrTblEntry; + +/**************************************************************************//** + @Description Deep Sleep Auto Response SNMP IPv6 Addresses Table Entry + Refer to the FMan Controller spec for more details. +*//***************************************************************************/ +#pragma pack(push,1) +typedef struct +{ + uint32_t ipv6Addr[4]; /*!< 4 * 32 bit IPv6 Address. */ + uint16_t vlanId; /*!< 12 bits VLAN ID. The 4 left-most bits should be cleared */ + /*!< This field should be 0x0000 for an entry with no VLAN tag or a null VLAN ID. */ + uint16_t reserved; +} t_DsarSnmpIpv6AddrTblEntry; +#pragma pack(pop) + +/**************************************************************************//** +@Description Deep Sleep Auto Response SNMP statistics table + +*//***************************************************************************/ +typedef struct { + uint32_t snmpErrCnt; /**< Counts SNMP errors (wrong version, BER encoding, format). */ + uint32_t snmpCommunityErrCnt; /**< Counts messages that were dropped due to insufficient permission. */ + uint32_t snmpTotalDiscardCnt; /**< Counts any message that was dropped. */ + uint32_t snmpGetReqCnt; /**< Counts the number of get-request messages */ + uint32_t snmpGetNextReqCnt; /**< Counts the number of get-next-request messages */ +} t_DsarSnmpStatistics; + +/**************************************************************************//** + @Description Deep Sleep Auto Response SNMP Descriptor + +*//***************************************************************************/ +typedef struct +{ + uint16_t control; /**< Control bits [0-15]. */ + uint16_t maxSnmpMsgLength; /**< Maximal allowed SNMP message length. */ + uint16_t numOfIpv4Addresses; /**< Number of entries in IPv4 addresses table. */ + uint16_t numOfIpv6Addresses; /**< Number of entries in IPv6 addresses table. */ + uint32_t p_Ipv4AddrTbl; /**< Pointer to IPv4 addresses table. */ + uint32_t p_Ipv6AddrTbl; /**< Pointer to IPv6 addresses table. */ + uint32_t p_RdOnlyCommunityStr; /**< Pointer to the Read Only Community String. */ + uint32_t p_RdWrCommunityStr; /**< Pointer to the Read Write Community String. */ + uint32_t p_OidsTbl; /**< Pointer to OIDs table. */ + uint32_t oidsTblSize; /**< Number of entries in OIDs table. */ + uint32_t p_Statistics; /**< Pointer to SNMP statistics table. */ +} t_DsarSnmpDescriptor; + +/**************************************************************************//** +@Description Deep Sleep Auto Response (Common) Statistics + +*//***************************************************************************/ +typedef _Packed struct { + uint32_t dsarDiscarded; + uint32_t dsarErrDiscarded; + uint32_t dsarFragDiscarded; + uint32_t dsarTunnelDiscarded; + uint32_t dsarArpDiscarded; + uint32_t dsarIpDiscarded; + uint32_t dsarTcpDiscarded; + uint32_t dsarUdpDiscarded; + uint32_t dsarIcmpV6ChecksumErr; /* ICMPv6 Checksum Error counter */ + uint32_t dsarIcmpV6OtherType; /* ICMPv6 'Other' type (not Echo or Neighbor Solicitaion/Advertisement counter */ + uint32_t dsarIcmpV4OtherType; /* ICMPv4 'Other' type (not Echo) counter */ +} _PackedType t_ArStatistics; + + +/**************************************************************************//** +@Description Deep Sleep Auto Response TCP/UDP port filter table entry + +*//***************************************************************************/ +typedef _Packed struct { + uint32_t Ports; + uint32_t PortsMask; +} _PackedType t_PortTblEntry; + + + +/**************************************************************************//** +@Description Deep Sleep Auto Response Common Parameters Descriptor + +*//***************************************************************************/ +typedef _Packed struct { + uint8_t arTxPort; /* 0x00 0-7 Auto Response Transmit Port number */ + uint8_t controlBits; /* 0x00 8-15 Auto Response control bits */ + uint16_t res1; /* 0x00 16-31 Reserved */ + uint32_t activeHPNIA; /* 0x04 0-31 Active mode Hardware Parser NIA */ + uint16_t snmpPort; /* 0x08 0-15 SNMP Port. */ + uint8_t macStationAddr[6]; /* 0x08 16-31 and 0x0C 0-31 MAC Station Address */ + uint8_t res2; /* 0x10 0-7 Reserved */ + uint8_t filterControl; /* 0x10 8-15 Filtering Control Bits. */ + uint16_t tcpControlPass; /* 0x10 16-31 TCP control pass flags */ + uint8_t ipProtocolTblSize; /* 0x14 0-7 IP Protocol Table Size. */ + uint8_t udpPortTblSize; /* 0x14 8-15 UDP Port Table Size. */ + uint8_t tcpPortTblSize; /* 0x14 16-23 TCP Port Table Size. */ + uint8_t res3; /* 0x14 24-31 Reserved */ + uint32_t p_IpProtocolFiltTbl; /* 0x18 0-31 Pointer to IP Protocol Filter Table */ + uint32_t p_UdpPortFiltTbl; /* 0x1C 0-31 Pointer to UDP Port Filter Table */ + uint32_t p_TcpPortFiltTbl; /* 0x20 0-31 Pointer to TCP Port Filter Table */ + uint32_t res4; /* 0x24 Reserved */ + uint32_t p_ArpDescriptor; /* 0x28 0-31 ARP Descriptor Pointer. */ + uint32_t p_NdDescriptor; /* 0x2C 0-31 Neighbor Discovery Descriptor. */ + uint32_t p_IcmpV4Descriptor; /* 0x30 0-31 ICMPv4 Descriptor pointer. */ + uint32_t p_IcmpV6Descriptor; /* 0x34 0-31 ICMPv6 Descriptor pointer. */ + uint32_t p_SnmpDescriptor; /* 0x38 0-31 SNMP Descriptor pointer. */ + uint32_t p_ArStats; /* 0x3C 0-31 Pointer to Auto Response Statistics */ +} _PackedType t_ArCommonDesc; + +#if defined(__MWERKS__) && !defined(__GNUC__) +#pragma pack(pop) +#endif /* defined(__MWERKS__) && ... */ + +/* t_ArCommonDesc.filterControl bits */ +#define IP_PROT_TBL_PASS_MASK 0x08 +#define UDP_PORT_TBL_PASS_MASK 0x04 +#define TCP_PORT_TBL_PASS_MASK 0x02 + +/* Offset of TCF flags within TCP packet */ +#define TCP_FLAGS_OFFSET 12 + + +#endif /* __FM_PORT_DSAR_H_ */ diff --git a/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Port/fm_port_im.c b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Port/fm_port_im.c new file mode 100644 index 0000000..8de8f5f --- /dev/null +++ b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Port/fm_port_im.c @@ -0,0 +1,753 @@ +/* + * Copyright 2008-2012 Freescale Semiconductor Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Freescale Semiconductor nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + +/****************************************************************************** + @File fm_port_im.c + + @Description FM Port Independent-Mode ... +*//***************************************************************************/ +#include "std_ext.h" +#include "string_ext.h" +#include "error_ext.h" +#include "memcpy_ext.h" +#include "fm_muram_ext.h" + +#include "fm_port.h" + + +#define TX_CONF_STATUS_UNSENT 0x1 + + +typedef enum e_TxConfType +{ + e_TX_CONF_TYPE_CHECK = 0 /**< check if all the buffers were touched by the muxator, no confirmation callback */ + ,e_TX_CONF_TYPE_CALLBACK = 1 /**< confirm to user all the available sent buffers */ + ,e_TX_CONF_TYPE_FLUSH = 3 /**< confirm all buffers plus the unsent one with an appropriate status */ +} e_TxConfType; + + +static void ImException(t_Handle h_FmPort, uint32_t event) +{ + t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; + + ASSERT_COND(((event & (IM_EV_RX | IM_EV_BSY)) && FmIsMaster(p_FmPort->h_Fm)) || + !FmIsMaster(p_FmPort->h_Fm)); + + if (event & IM_EV_RX) + FmPortImRx(p_FmPort); + if ((event & IM_EV_BSY) && p_FmPort->f_Exception) + p_FmPort->f_Exception(p_FmPort->h_App, e_FM_PORT_EXCEPTION_IM_BUSY); +} + + +static t_Error TxConf(t_FmPort *p_FmPort, e_TxConfType confType) +{ + t_Error retVal = E_BUSY; + uint32_t bdStatus; + uint16_t savedStartBdId, confBdId; + + ASSERT_COND(p_FmPort); + + /* + if (confType==e_TX_CONF_TYPE_CHECK) + return (WfqEntryIsQueueEmpty(p_FmPort->im.h_WfqEntry) ? E_OK : E_BUSY); + */ + + confBdId = savedStartBdId = p_FmPort->im.currBdId; + bdStatus = BD_STATUS_AND_LENGTH(BD_GET(confBdId)); + + /* If R bit is set, we don't enter, or we break. + we run till we get to R, or complete the loop */ + while ((!(bdStatus & BD_R_E) || (confType == e_TX_CONF_TYPE_FLUSH)) && (retVal != E_OK)) + { + if (confType & e_TX_CONF_TYPE_CALLBACK) /* if it is confirmation with user callbacks */ + BD_STATUS_AND_LENGTH_SET(BD_GET(confBdId), 0); + + /* case 1: R bit is 0 and Length is set -> confirm! */ + if ((confType & e_TX_CONF_TYPE_CALLBACK) && (bdStatus & BD_LENGTH_MASK)) + { + if (p_FmPort->im.f_TxConf) + { + if ((confType == e_TX_CONF_TYPE_FLUSH) && (bdStatus & BD_R_E)) + p_FmPort->im.f_TxConf(p_FmPort->h_App, + BdBufferGet(XX_PhysToVirt, BD_GET(confBdId)), + TX_CONF_STATUS_UNSENT, + p_FmPort->im.p_BdShadow[confBdId]); + else + p_FmPort->im.f_TxConf(p_FmPort->h_App, + BdBufferGet(XX_PhysToVirt, BD_GET(confBdId)), + 0, + p_FmPort->im.p_BdShadow[confBdId]); + } + } + /* case 2: R bit is 0 and Length is 0 -> not used yet, nop! */ + + confBdId = GetNextBdId(p_FmPort, confBdId); + if (confBdId == savedStartBdId) + retVal = E_OK; + bdStatus = BD_STATUS_AND_LENGTH(BD_GET(confBdId)); + } + + return retVal; +} + +t_Error FmPortImEnable(t_FmPort *p_FmPort) +{ + uint32_t tmpReg = GET_UINT32(p_FmPort->im.p_FmPortImPram->mode); + WRITE_UINT32(p_FmPort->im.p_FmPortImPram->mode, (uint32_t)(tmpReg & ~IM_MODE_GRC_STP)); + return E_OK; +} + +t_Error FmPortImDisable(t_FmPort *p_FmPort) +{ + uint32_t tmpReg = GET_UINT32(p_FmPort->im.p_FmPortImPram->mode); + WRITE_UINT32(p_FmPort->im.p_FmPortImPram->mode, (uint32_t)(tmpReg | IM_MODE_GRC_STP)); + return E_OK; +} + +t_Error FmPortImRx(t_FmPort *p_FmPort) +{ + t_Handle h_CurrUserPriv, h_NewUserPriv; + uint32_t bdStatus; + volatile uint8_t buffPos; + uint16_t length; + uint16_t errors; + uint8_t *p_CurData, *p_Data; + uint32_t flags; + + ASSERT_COND(p_FmPort); + + flags = XX_LockIntrSpinlock(p_FmPort->h_Spinlock); + if (p_FmPort->lock) + { + XX_UnlockIntrSpinlock(p_FmPort->h_Spinlock, flags); + return E_OK; + } + p_FmPort->lock = TRUE; + XX_UnlockIntrSpinlock(p_FmPort->h_Spinlock, flags); + + bdStatus = BD_STATUS_AND_LENGTH(BD_GET(p_FmPort->im.currBdId)); + + while (!(bdStatus & BD_R_E)) /* while there is data in the Rx BD */ + { + if ((p_Data = p_FmPort->im.rxPool.f_GetBuf(p_FmPort->im.rxPool.h_BufferPool, &h_NewUserPriv)) == NULL) + { + p_FmPort->lock = FALSE; + RETURN_ERROR(MAJOR, E_NOT_AVAILABLE, ("Data buffer")); + } + + if (p_FmPort->im.firstBdOfFrameId == IM_ILEGAL_BD_ID) + p_FmPort->im.firstBdOfFrameId = p_FmPort->im.currBdId; + + p_CurData = BdBufferGet(p_FmPort->im.rxPool.f_PhysToVirt, BD_GET(p_FmPort->im.currBdId)); + h_CurrUserPriv = p_FmPort->im.p_BdShadow[p_FmPort->im.currBdId]; + length = (uint16_t)((bdStatus & BD_L) ? + ((bdStatus & BD_LENGTH_MASK) - p_FmPort->im.rxFrameAccumLength): + (bdStatus & BD_LENGTH_MASK)); + p_FmPort->im.rxFrameAccumLength += length; + + /* determine whether buffer is first, last, first and last (single */ + /* buffer frame) or middle (not first and not last) */ + buffPos = (uint8_t)((p_FmPort->im.currBdId == p_FmPort->im.firstBdOfFrameId) ? + ((bdStatus & BD_L) ? SINGLE_BUF : FIRST_BUF) : + ((bdStatus & BD_L) ? LAST_BUF : MIDDLE_BUF)); + + if (bdStatus & BD_L) + { + p_FmPort->im.rxFrameAccumLength = 0; + p_FmPort->im.firstBdOfFrameId = IM_ILEGAL_BD_ID; + } + + BdBufferSet(p_FmPort->im.rxPool.f_VirtToPhys, BD_GET(p_FmPort->im.currBdId), p_Data); + + BD_STATUS_AND_LENGTH_SET(BD_GET(p_FmPort->im.currBdId), BD_R_E); + + errors = (uint16_t)((bdStatus & BD_RX_ERRORS) >> 16); + p_FmPort->im.p_BdShadow[p_FmPort->im.currBdId] = h_NewUserPriv; + + p_FmPort->im.currBdId = GetNextBdId(p_FmPort, p_FmPort->im.currBdId); + WRITE_UINT16(p_FmPort->im.p_FmPortImPram->rxQd.offsetOut, (uint16_t)(p_FmPort->im.currBdId<<4)); + /* Pass the buffer if one of the conditions is true: + - There are no errors + - This is a part of a larger frame ( the application has already received some buffers ) */ + if ((buffPos != SINGLE_BUF) || !errors) + { + if (p_FmPort->im.f_RxStore(p_FmPort->h_App, + p_CurData, + length, + errors, + buffPos, + h_CurrUserPriv) == e_RX_STORE_RESPONSE_PAUSE) + break; + } + else if (p_FmPort->im.rxPool.f_PutBuf(p_FmPort->im.rxPool.h_BufferPool, + p_CurData, + h_CurrUserPriv)) + { + p_FmPort->lock = FALSE; + RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Failed freeing data buffer")); + } + + bdStatus = BD_STATUS_AND_LENGTH(BD_GET(p_FmPort->im.currBdId)); + } + p_FmPort->lock = FALSE; + return E_OK; +} + +void FmPortConfigIM (t_FmPort *p_FmPort, t_FmPortParams *p_FmPortParams) +{ + ASSERT_COND(p_FmPort); + + SANITY_CHECK_RETURN(p_FmPort->p_FmPortDriverParam, E_INVALID_HANDLE); + + p_FmPort->im.h_FmMuram = p_FmPortParams->specificParams.imRxTxParams.h_FmMuram; + p_FmPort->p_FmPortDriverParam->liodnOffset = p_FmPortParams->specificParams.imRxTxParams.liodnOffset; + p_FmPort->im.dataMemId = p_FmPortParams->specificParams.imRxTxParams.dataMemId; + p_FmPort->im.dataMemAttributes = p_FmPortParams->specificParams.imRxTxParams.dataMemAttributes; + + p_FmPort->im.fwExtStructsMemId = DEFAULT_PORT_ImfwExtStructsMemId; + p_FmPort->im.fwExtStructsMemAttr = DEFAULT_PORT_ImfwExtStructsMemAttr; + + if ((p_FmPort->portType == e_FM_PORT_TYPE_RX) || + (p_FmPort->portType == e_FM_PORT_TYPE_RX_10G)) + { + p_FmPort->im.rxPool.h_BufferPool = p_FmPortParams->specificParams.imRxTxParams.rxPoolParams.h_BufferPool; + p_FmPort->im.rxPool.f_GetBuf = p_FmPortParams->specificParams.imRxTxParams.rxPoolParams.f_GetBuf; + p_FmPort->im.rxPool.f_PutBuf = p_FmPortParams->specificParams.imRxTxParams.rxPoolParams.f_PutBuf; + p_FmPort->im.rxPool.bufferSize = p_FmPortParams->specificParams.imRxTxParams.rxPoolParams.bufferSize; + p_FmPort->im.rxPool.f_PhysToVirt = p_FmPortParams->specificParams.imRxTxParams.rxPoolParams.f_PhysToVirt; + if (!p_FmPort->im.rxPool.f_PhysToVirt) + p_FmPort->im.rxPool.f_PhysToVirt = XX_PhysToVirt; + p_FmPort->im.rxPool.f_VirtToPhys = p_FmPortParams->specificParams.imRxTxParams.rxPoolParams.f_VirtToPhys; + if (!p_FmPort->im.rxPool.f_VirtToPhys) + p_FmPort->im.rxPool.f_VirtToPhys = XX_VirtToPhys; + p_FmPort->im.f_RxStore = p_FmPortParams->specificParams.imRxTxParams.f_RxStore; + + p_FmPort->im.mrblr = 0x8000; + while (p_FmPort->im.mrblr) + { + if (p_FmPort->im.rxPool.bufferSize & p_FmPort->im.mrblr) + break; + p_FmPort->im.mrblr >>= 1; + } + if (p_FmPort->im.mrblr != p_FmPort->im.rxPool.bufferSize) + DBG(WARNING, ("Max-Rx-Buffer-Length set to %d", p_FmPort->im.mrblr)); + p_FmPort->im.bdRingSize = DEFAULT_PORT_rxBdRingLength; + p_FmPort->exceptions = DEFAULT_PORT_exception; + if (FmIsMaster(p_FmPort->h_Fm)) + p_FmPort->polling = FALSE; + else + p_FmPort->polling = TRUE; + p_FmPort->fmanCtrlEventId = (uint8_t)NO_IRQ; + } + else + { + p_FmPort->im.f_TxConf = p_FmPortParams->specificParams.imRxTxParams.f_TxConf; + + p_FmPort->im.bdRingSize = DEFAULT_PORT_txBdRingLength; + } +} + +t_Error FmPortImCheckInitParameters(t_FmPort *p_FmPort) +{ + if ((p_FmPort->portType != e_FM_PORT_TYPE_RX) && + (p_FmPort->portType != e_FM_PORT_TYPE_RX_10G) && + (p_FmPort->portType != e_FM_PORT_TYPE_TX) && + (p_FmPort->portType != e_FM_PORT_TYPE_TX_10G)) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, NO_MSG); + + if ((p_FmPort->portType == e_FM_PORT_TYPE_RX) || + (p_FmPort->portType == e_FM_PORT_TYPE_RX_10G)) + { + if (!POWER_OF_2(p_FmPort->im.mrblr)) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("max Rx buffer length must be power of 2!!!")); + if (p_FmPort->im.mrblr < 256) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("max Rx buffer length must at least 256!!!")); + if (p_FmPort->p_FmPortDriverParam->liodnOffset & ~FM_LIODN_OFFSET_MASK) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("liodnOffset is larger than %d", FM_LIODN_OFFSET_MASK+1)); + } + + return E_OK; +} + +t_Error FmPortImInit(t_FmPort *p_FmPort) +{ + t_FmImBd *p_Bd=NULL; + t_Handle h_BufContext; + uint64_t tmpPhysBase; + uint16_t log2Num; + uint8_t *p_Data/*, *p_Tmp*/; + int i; + t_Error err; + uint16_t tmpReg16; + uint32_t tmpReg32; + + ASSERT_COND(p_FmPort); + + p_FmPort->im.p_FmPortImPram = + (t_FmPortImPram *)FM_MURAM_AllocMem(p_FmPort->im.h_FmMuram, sizeof(t_FmPortImPram), IM_PRAM_ALIGN); + if (!p_FmPort->im.p_FmPortImPram) + RETURN_ERROR(MAJOR, E_NO_MEMORY, ("Independent-Mode Parameter-RAM!!!")); + WRITE_BLOCK(p_FmPort->im.p_FmPortImPram, 0, sizeof(t_FmPortImPram)); + + if ((p_FmPort->portType == e_FM_PORT_TYPE_RX) || + (p_FmPort->portType == e_FM_PORT_TYPE_RX_10G)) + { + p_FmPort->im.p_BdRing = + (t_FmImBd *)XX_MallocSmart((uint32_t)(sizeof(t_FmImBd)*p_FmPort->im.bdRingSize), + p_FmPort->im.fwExtStructsMemId, + 4); + if (!p_FmPort->im.p_BdRing) + RETURN_ERROR(MAJOR, E_NO_MEMORY, ("Independent-Mode Rx BD ring!!!")); + IOMemSet32(p_FmPort->im.p_BdRing, 0, (uint32_t)(sizeof(t_FmImBd)*p_FmPort->im.bdRingSize)); + + p_FmPort->im.p_BdShadow = (t_Handle *)XX_Malloc((uint32_t)(sizeof(t_Handle)*p_FmPort->im.bdRingSize)); + if (!p_FmPort->im.p_BdShadow) + RETURN_ERROR(MAJOR, E_NO_MEMORY, ("Independent-Mode Rx BD shadow!!!")); + memset(p_FmPort->im.p_BdShadow, 0, (uint32_t)(sizeof(t_Handle)*p_FmPort->im.bdRingSize)); + + /* Initialize the Rx-BD ring */ + for (i=0; i<p_FmPort->im.bdRingSize; i++) + { + p_Bd = BD_GET(i); + BD_STATUS_AND_LENGTH_SET (p_Bd, BD_R_E); + + if ((p_Data = p_FmPort->im.rxPool.f_GetBuf(p_FmPort->im.rxPool.h_BufferPool, &h_BufContext)) == NULL) + RETURN_ERROR(MAJOR, E_NOT_AVAILABLE, ("Data buffer")); + BdBufferSet(p_FmPort->im.rxPool.f_VirtToPhys, p_Bd, p_Data); + p_FmPort->im.p_BdShadow[i] = h_BufContext; + } + + if ((p_FmPort->im.dataMemAttributes & MEMORY_ATTR_CACHEABLE) || + (p_FmPort->im.fwExtStructsMemAttr & MEMORY_ATTR_CACHEABLE)) + WRITE_UINT32(p_FmPort->im.p_FmPortImPram->mode, IM_MODE_GBL | IM_MODE_SET_BO(2)); + else + WRITE_UINT32(p_FmPort->im.p_FmPortImPram->mode, IM_MODE_SET_BO(2)); + + WRITE_UINT32(p_FmPort->im.p_FmPortImPram->rxQdPtr, + (uint32_t)((uint64_t)(XX_VirtToPhys(p_FmPort->im.p_FmPortImPram)) - + p_FmPort->fmMuramPhysBaseAddr + 0x20)); + + LOG2((uint64_t)p_FmPort->im.mrblr, log2Num); + WRITE_UINT16(p_FmPort->im.p_FmPortImPram->mrblr, log2Num); + + /* Initialize Rx QD */ + tmpPhysBase = (uint64_t)(XX_VirtToPhys(p_FmPort->im.p_BdRing)); + SET_ADDR(&p_FmPort->im.p_FmPortImPram->rxQd.bdRingBase, tmpPhysBase); + WRITE_UINT16(p_FmPort->im.p_FmPortImPram->rxQd.bdRingSize, (uint16_t)(sizeof(t_FmImBd)*p_FmPort->im.bdRingSize)); + + /* Update the IM PRAM address in the BMI */ + WRITE_UINT32(p_FmPort->p_FmPortBmiRegs->rxPortBmiRegs.fmbm_rfqid, + (uint32_t)((uint64_t)(XX_VirtToPhys(p_FmPort->im.p_FmPortImPram)) - + p_FmPort->fmMuramPhysBaseAddr)); + if (!p_FmPort->polling || p_FmPort->exceptions) + { + /* Allocate, configure and register interrupts */ + err = FmAllocFmanCtrlEventReg(p_FmPort->h_Fm, &p_FmPort->fmanCtrlEventId); + if (err) + RETURN_ERROR(MAJOR, err, NO_MSG); + + ASSERT_COND(!(p_FmPort->fmanCtrlEventId & ~IM_RXQD_FPMEVT_SEL_MASK)); + tmpReg16 = (uint16_t)(p_FmPort->fmanCtrlEventId & IM_RXQD_FPMEVT_SEL_MASK); + tmpReg32 = 0; + + if (p_FmPort->exceptions & IM_EV_BSY) + { + tmpReg16 |= IM_RXQD_BSYINTM; + tmpReg32 |= IM_EV_BSY; + } + if (!p_FmPort->polling) + { + tmpReg16 |= IM_RXQD_RXFINTM; + tmpReg32 |= IM_EV_RX; + } + WRITE_UINT16(p_FmPort->im.p_FmPortImPram->rxQd.gen, tmpReg16); + + FmRegisterFmanCtrlIntr(p_FmPort->h_Fm, p_FmPort->fmanCtrlEventId, ImException , (t_Handle)p_FmPort); + + FmSetFmanCtrlIntr(p_FmPort->h_Fm, p_FmPort->fmanCtrlEventId, tmpReg32); + } + else + p_FmPort->fmanCtrlEventId = (uint8_t)NO_IRQ; + } + else + { + p_FmPort->im.p_BdRing = (t_FmImBd *)XX_MallocSmart((uint32_t)(sizeof(t_FmImBd)*p_FmPort->im.bdRingSize), p_FmPort->im.fwExtStructsMemId, 4); + if (!p_FmPort->im.p_BdRing) + RETURN_ERROR(MAJOR, E_NO_MEMORY, ("Independent-Mode Tx BD ring!!!")); + IOMemSet32(p_FmPort->im.p_BdRing, 0, (uint32_t)(sizeof(t_FmImBd)*p_FmPort->im.bdRingSize)); + + p_FmPort->im.p_BdShadow = (t_Handle *)XX_Malloc((uint32_t)(sizeof(t_Handle)*p_FmPort->im.bdRingSize)); + if (!p_FmPort->im.p_BdShadow) + RETURN_ERROR(MAJOR, E_NO_MEMORY, ("Independent-Mode Rx BD shadow!!!")); + memset(p_FmPort->im.p_BdShadow, 0, (uint32_t)(sizeof(t_Handle)*p_FmPort->im.bdRingSize)); + p_FmPort->im.firstBdOfFrameId = IM_ILEGAL_BD_ID; + + if ((p_FmPort->im.dataMemAttributes & MEMORY_ATTR_CACHEABLE) || + (p_FmPort->im.fwExtStructsMemAttr & MEMORY_ATTR_CACHEABLE)) + WRITE_UINT32(p_FmPort->im.p_FmPortImPram->mode, IM_MODE_GBL | IM_MODE_SET_BO(2)); + else + WRITE_UINT32(p_FmPort->im.p_FmPortImPram->mode, IM_MODE_SET_BO(2)); + + WRITE_UINT32(p_FmPort->im.p_FmPortImPram->txQdPtr, + (uint32_t)((uint64_t)(XX_VirtToPhys(p_FmPort->im.p_FmPortImPram)) - + p_FmPort->fmMuramPhysBaseAddr + 0x40)); + + /* Initialize Tx QD */ + tmpPhysBase = (uint64_t)(XX_VirtToPhys(p_FmPort->im.p_BdRing)); + SET_ADDR(&p_FmPort->im.p_FmPortImPram->txQd.bdRingBase, tmpPhysBase); + WRITE_UINT16(p_FmPort->im.p_FmPortImPram->txQd.bdRingSize, (uint16_t)(sizeof(t_FmImBd)*p_FmPort->im.bdRingSize)); + + /* Update the IM PRAM address in the BMI */ + WRITE_UINT32(p_FmPort->p_FmPortBmiRegs->txPortBmiRegs.fmbm_tcfqid, + (uint32_t)((uint64_t)(XX_VirtToPhys(p_FmPort->im.p_FmPortImPram)) - + p_FmPort->fmMuramPhysBaseAddr)); + } + + + return E_OK; +} + +void FmPortImFree(t_FmPort *p_FmPort) +{ + uint32_t bdStatus; + uint8_t *p_CurData; + + ASSERT_COND(p_FmPort); + ASSERT_COND(p_FmPort->im.p_FmPortImPram); + + if ((p_FmPort->portType == e_FM_PORT_TYPE_RX) || + (p_FmPort->portType == e_FM_PORT_TYPE_RX_10G)) + { + if (!p_FmPort->polling || p_FmPort->exceptions) + { + /* Deallocate and unregister interrupts */ + FmSetFmanCtrlIntr(p_FmPort->h_Fm, p_FmPort->fmanCtrlEventId, 0); + + FmFreeFmanCtrlEventReg(p_FmPort->h_Fm, p_FmPort->fmanCtrlEventId); + + WRITE_UINT16(p_FmPort->im.p_FmPortImPram->rxQd.gen, 0); + + FmUnregisterFmanCtrlIntr(p_FmPort->h_Fm, p_FmPort->fmanCtrlEventId); + } + /* Try first clean what has received */ + FmPortImRx(p_FmPort); + + /* Now, get rid of the the empty buffer! */ + bdStatus = BD_STATUS_AND_LENGTH(BD_GET(p_FmPort->im.currBdId)); + + while (bdStatus & BD_R_E) /* while there is data in the Rx BD */ + { + p_CurData = BdBufferGet(p_FmPort->im.rxPool.f_PhysToVirt, BD_GET(p_FmPort->im.currBdId)); + + BdBufferSet(p_FmPort->im.rxPool.f_VirtToPhys, BD_GET(p_FmPort->im.currBdId), NULL); + BD_STATUS_AND_LENGTH_SET(BD_GET(p_FmPort->im.currBdId), 0); + + p_FmPort->im.rxPool.f_PutBuf(p_FmPort->im.rxPool.h_BufferPool, + p_CurData, + p_FmPort->im.p_BdShadow[p_FmPort->im.currBdId]); + + p_FmPort->im.currBdId = GetNextBdId(p_FmPort, p_FmPort->im.currBdId); + bdStatus = BD_STATUS_AND_LENGTH(BD_GET(p_FmPort->im.currBdId)); + } + } + else + TxConf(p_FmPort, e_TX_CONF_TYPE_FLUSH); + + FM_MURAM_FreeMem(p_FmPort->im.h_FmMuram, p_FmPort->im.p_FmPortImPram); + + if (p_FmPort->im.p_BdShadow) + XX_Free(p_FmPort->im.p_BdShadow); + + if (p_FmPort->im.p_BdRing) + XX_FreeSmart(p_FmPort->im.p_BdRing); +} + + +t_Error FM_PORT_ConfigIMMaxRxBufLength(t_Handle h_FmPort, uint16_t newVal) +{ + t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; + + SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_FmPort->imEn, E_INVALID_STATE); + SANITY_CHECK_RETURN_ERROR(p_FmPort->p_FmPortDriverParam, E_INVALID_HANDLE); + + p_FmPort->im.mrblr = newVal; + + return E_OK; +} + +t_Error FM_PORT_ConfigIMRxBdRingLength(t_Handle h_FmPort, uint16_t newVal) +{ + t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; + + SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_FmPort->imEn, E_INVALID_STATE); + SANITY_CHECK_RETURN_ERROR(p_FmPort->p_FmPortDriverParam, E_INVALID_HANDLE); + + p_FmPort->im.bdRingSize = newVal; + + return E_OK; +} + +t_Error FM_PORT_ConfigIMTxBdRingLength(t_Handle h_FmPort, uint16_t newVal) +{ + t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; + + SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_FmPort->imEn, E_INVALID_STATE); + SANITY_CHECK_RETURN_ERROR(p_FmPort->p_FmPortDriverParam, E_INVALID_HANDLE); + + p_FmPort->im.bdRingSize = newVal; + + return E_OK; +} + +t_Error FM_PORT_ConfigIMFmanCtrlExternalStructsMemory(t_Handle h_FmPort, + uint8_t memId, + uint32_t memAttributes) +{ + t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; + + SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_FmPort->imEn, E_INVALID_STATE); + SANITY_CHECK_RETURN_ERROR(p_FmPort->p_FmPortDriverParam, E_INVALID_HANDLE); + + p_FmPort->im.fwExtStructsMemId = memId; + p_FmPort->im.fwExtStructsMemAttr = memAttributes; + + return E_OK; +} + +t_Error FM_PORT_ConfigIMPolling(t_Handle h_FmPort) +{ + t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; + + SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_FmPort->imEn, E_INVALID_STATE); + SANITY_CHECK_RETURN_ERROR(p_FmPort->p_FmPortDriverParam, E_INVALID_HANDLE); + + if ((p_FmPort->portType != e_FM_PORT_TYPE_RX_10G) && (p_FmPort->portType != e_FM_PORT_TYPE_RX)) + RETURN_ERROR(MAJOR, E_INVALID_OPERATION, ("Available for Rx ports only")); + + if (!FmIsMaster(p_FmPort->h_Fm)) + RETURN_ERROR(MAJOR, E_INVALID_OPERATION, ("Available on master-partition only;" + "in guest-partitions, IM is always in polling!")); + + p_FmPort->polling = TRUE; + + return E_OK; +} + +t_Error FM_PORT_SetIMExceptions(t_Handle h_FmPort, e_FmPortExceptions exception, bool enable) +{ + t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; + t_Error err; + uint16_t tmpReg16; + uint32_t tmpReg32; + + SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_FmPort->imEn, E_INVALID_STATE); + SANITY_CHECK_RETURN_ERROR(!p_FmPort->p_FmPortDriverParam, E_INVALID_HANDLE); + + if (exception == e_FM_PORT_EXCEPTION_IM_BUSY) + { + if (enable) + { + p_FmPort->exceptions |= IM_EV_BSY; + if (p_FmPort->fmanCtrlEventId == (uint8_t)NO_IRQ) + { + /* Allocate, configure and register interrupts */ + err = FmAllocFmanCtrlEventReg(p_FmPort->h_Fm, &p_FmPort->fmanCtrlEventId); + if (err) + RETURN_ERROR(MAJOR, err, NO_MSG); + ASSERT_COND(!(p_FmPort->fmanCtrlEventId & ~IM_RXQD_FPMEVT_SEL_MASK)); + + FmRegisterFmanCtrlIntr(p_FmPort->h_Fm, p_FmPort->fmanCtrlEventId, ImException, (t_Handle)p_FmPort); + tmpReg16 = (uint16_t)((p_FmPort->fmanCtrlEventId & IM_RXQD_FPMEVT_SEL_MASK) | IM_RXQD_BSYINTM); + tmpReg32 = IM_EV_BSY; + } + else + { + tmpReg16 = (uint16_t)(GET_UINT16(p_FmPort->im.p_FmPortImPram->rxQd.gen) | IM_RXQD_BSYINTM); + tmpReg32 = FmGetFmanCtrlIntr(p_FmPort->h_Fm, p_FmPort->fmanCtrlEventId) | IM_EV_BSY; + } + + WRITE_UINT16(p_FmPort->im.p_FmPortImPram->rxQd.gen, tmpReg16); + FmSetFmanCtrlIntr(p_FmPort->h_Fm, p_FmPort->fmanCtrlEventId, tmpReg32); + } + else + { + p_FmPort->exceptions &= ~IM_EV_BSY; + if (!p_FmPort->exceptions && p_FmPort->polling) + { + FmFreeFmanCtrlEventReg(p_FmPort->h_Fm, p_FmPort->fmanCtrlEventId); + FmUnregisterFmanCtrlIntr(p_FmPort->h_Fm, p_FmPort->fmanCtrlEventId); + FmSetFmanCtrlIntr(p_FmPort->h_Fm, p_FmPort->fmanCtrlEventId, 0); + WRITE_UINT16(p_FmPort->im.p_FmPortImPram->rxQd.gen, 0); + p_FmPort->fmanCtrlEventId = (uint8_t)NO_IRQ; + } + else + { + tmpReg16 = (uint16_t)(GET_UINT16(p_FmPort->im.p_FmPortImPram->rxQd.gen) & ~IM_RXQD_BSYINTM); + WRITE_UINT16(p_FmPort->im.p_FmPortImPram->rxQd.gen, tmpReg16); + tmpReg32 = FmGetFmanCtrlIntr(p_FmPort->h_Fm, p_FmPort->fmanCtrlEventId) & ~IM_EV_BSY; + FmSetFmanCtrlIntr(p_FmPort->h_Fm, p_FmPort->fmanCtrlEventId, tmpReg32); + } + } + } + else + RETURN_ERROR(MINOR, E_INVALID_SELECTION, ("Invalid exception.")); + + return E_OK; +} + +t_Error FM_PORT_ImTx( t_Handle h_FmPort, + uint8_t *p_Data, + uint16_t length, + bool lastBuffer, + t_Handle h_BufContext) +{ + t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; + uint16_t nextBdId; + uint32_t bdStatus, nextBdStatus; + bool firstBuffer; + + SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_FmPort->imEn, E_INVALID_STATE); + SANITY_CHECK_RETURN_ERROR(!p_FmPort->p_FmPortDriverParam, E_INVALID_HANDLE); + + bdStatus = BD_STATUS_AND_LENGTH(BD_GET(p_FmPort->im.currBdId)); + nextBdId = GetNextBdId(p_FmPort, p_FmPort->im.currBdId); + nextBdStatus = BD_STATUS_AND_LENGTH(BD_GET(nextBdId)); + + if (!(bdStatus & BD_R_E) && !(nextBdStatus & BD_R_E)) + { + /* Confirm the current BD - BD is available */ + if ((bdStatus & BD_LENGTH_MASK) && (p_FmPort->im.f_TxConf)) + p_FmPort->im.f_TxConf (p_FmPort->h_App, + BdBufferGet(XX_PhysToVirt, BD_GET(p_FmPort->im.currBdId)), + 0, + p_FmPort->im.p_BdShadow[p_FmPort->im.currBdId]); + + bdStatus = length; + + /* if this is the first BD of a frame */ + if (p_FmPort->im.firstBdOfFrameId == IM_ILEGAL_BD_ID) + { + firstBuffer = TRUE; + p_FmPort->im.txFirstBdStatus = (bdStatus | BD_R_E); + + if (!lastBuffer) + p_FmPort->im.firstBdOfFrameId = p_FmPort->im.currBdId; + } + else + firstBuffer = FALSE; + + BdBufferSet(XX_VirtToPhys, BD_GET(p_FmPort->im.currBdId), p_Data); + p_FmPort->im.p_BdShadow[p_FmPort->im.currBdId] = h_BufContext; + + /* deal with last */ + if (lastBuffer) + { + /* if single buffer frame */ + if (firstBuffer) + BD_STATUS_AND_LENGTH_SET(BD_GET(p_FmPort->im.currBdId), p_FmPort->im.txFirstBdStatus | BD_L); + else + { + /* Set the last BD of the frame */ + BD_STATUS_AND_LENGTH_SET (BD_GET(p_FmPort->im.currBdId), (bdStatus | BD_R_E | BD_L)); + /* Set the first BD of the frame */ + BD_STATUS_AND_LENGTH_SET(BD_GET(p_FmPort->im.firstBdOfFrameId), p_FmPort->im.txFirstBdStatus); + p_FmPort->im.firstBdOfFrameId = IM_ILEGAL_BD_ID; + } + WRITE_UINT16(p_FmPort->im.p_FmPortImPram->txQd.offsetIn, (uint16_t)(GetNextBdId(p_FmPort, p_FmPort->im.currBdId)<<4)); + } + else if (!firstBuffer) /* mid frame buffer */ + BD_STATUS_AND_LENGTH_SET (BD_GET(p_FmPort->im.currBdId), bdStatus | BD_R_E); + + p_FmPort->im.currBdId = GetNextBdId(p_FmPort, p_FmPort->im.currBdId); + } + else + { + /* Discard current frame. Return error. */ + if (p_FmPort->im.firstBdOfFrameId != IM_ILEGAL_BD_ID) + { + /* Error: No free BD */ + /* Response: Discard current frame. Return error. */ + uint16_t cleanBdId = p_FmPort->im.firstBdOfFrameId; + + ASSERT_COND(p_FmPort->im.firstBdOfFrameId != p_FmPort->im.currBdId); + + /* Since firstInFrame is not NULL, one buffer at least has already been + inserted into the BD ring. Using do-while covers the situation of a + frame spanned throughout the whole Tx BD ring (p_CleanBd is incremented + prior to testing whether or not it's equal to TxBd). */ + do + { + BD_STATUS_AND_LENGTH_SET(BD_GET(cleanBdId), 0); + /* Advance BD pointer */ + cleanBdId = GetNextBdId(p_FmPort, cleanBdId); + } while (cleanBdId != p_FmPort->im.currBdId); + + p_FmPort->im.currBdId = cleanBdId; + p_FmPort->im.firstBdOfFrameId = IM_ILEGAL_BD_ID; + } + + return ERROR_CODE(E_FULL); + } + + return E_OK; +} + +void FM_PORT_ImTxConf(t_Handle h_FmPort) +{ + t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; + + SANITY_CHECK_RETURN(p_FmPort, E_INVALID_HANDLE); + SANITY_CHECK_RETURN(p_FmPort->imEn, E_INVALID_STATE); + SANITY_CHECK_RETURN(!p_FmPort->p_FmPortDriverParam, E_INVALID_HANDLE); + + TxConf(p_FmPort, e_TX_CONF_TYPE_CALLBACK); +} + +t_Error FM_PORT_ImRx(t_Handle h_FmPort) +{ + t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; + + SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_FmPort->imEn, E_INVALID_STATE); + SANITY_CHECK_RETURN_ERROR(!p_FmPort->p_FmPortDriverParam, E_INVALID_HANDLE); + + return FmPortImRx(p_FmPort); +} diff --git a/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Port/fman_port.c b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Port/fman_port.c new file mode 100755 index 0000000..60acbf3 --- /dev/null +++ b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Port/fman_port.c @@ -0,0 +1,1568 @@ +/* + * Copyright 2008-2012 Freescale Semiconductor Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Freescale Semiconductor nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + +#include "common/general.h" + +#include "fman_common.h" +#include "fsl_fman_port.h" + + +/* problem Eyal: the following should not be here*/ +#define NIA_FM_CTL_AC_NO_IPACC_PRE_BMI_ENQ_FRAME 0x00000028 + +static uint32_t get_no_pcd_nia_bmi_ac_enc_frame(struct fman_port_cfg *cfg) +{ + if (cfg->errata_A006675) + return NIA_ENG_FM_CTL | + NIA_FM_CTL_AC_NO_IPACC_PRE_BMI_ENQ_FRAME; + else + return NIA_ENG_BMI | NIA_BMI_AC_ENQ_FRAME; +} + +static int init_bmi_rx(struct fman_port *port, + struct fman_port_cfg *cfg, + struct fman_port_params *params) +{ + struct fman_port_rx_bmi_regs *regs = &port->bmi_regs->rx; + uint32_t tmp; + + /* Rx Configuration register */ + tmp = 0; + if (port->im_en) + tmp |= BMI_PORT_CFG_IM; + else if (cfg->discard_override) + tmp |= BMI_PORT_CFG_FDOVR; + iowrite32be(tmp, ®s->fmbm_rcfg); + + /* DMA attributes */ + tmp = (uint32_t)cfg->dma_swap_data << BMI_DMA_ATTR_SWP_SHIFT; + if (cfg->dma_ic_stash_on) + tmp |= BMI_DMA_ATTR_IC_STASH_ON; + if (cfg->dma_header_stash_on) + tmp |= BMI_DMA_ATTR_HDR_STASH_ON; + if (cfg->dma_sg_stash_on) + tmp |= BMI_DMA_ATTR_SG_STASH_ON; + if (cfg->dma_write_optimize) + tmp |= BMI_DMA_ATTR_WRITE_OPTIMIZE; + iowrite32be(tmp, ®s->fmbm_rda); + + /* Rx FIFO parameters */ + tmp = (cfg->rx_pri_elevation / FMAN_PORT_BMI_FIFO_UNITS - 1) << + BMI_RX_FIFO_PRI_ELEVATION_SHIFT; + tmp |= cfg->rx_fifo_thr / FMAN_PORT_BMI_FIFO_UNITS - 1; + iowrite32be(tmp, ®s->fmbm_rfp); + + if (cfg->excessive_threshold_register) + /* always allow access to the extra resources */ + iowrite32be(BMI_RX_FIFO_THRESHOLD_ETHE, ®s->fmbm_reth); + + /* Frame end data */ + tmp = (uint32_t)cfg->checksum_bytes_ignore << + BMI_RX_FRAME_END_CS_IGNORE_SHIFT; + tmp |= (uint32_t)cfg->rx_cut_end_bytes << + BMI_RX_FRAME_END_CUT_SHIFT; + if (cfg->errata_A006320) + tmp &= 0xffe0ffff; + iowrite32be(tmp, ®s->fmbm_rfed); + + /* Internal context parameters */ + tmp = ((uint32_t)cfg->ic_ext_offset / FMAN_PORT_IC_OFFSET_UNITS) << + BMI_IC_TO_EXT_SHIFT; + tmp |= ((uint32_t)cfg->ic_int_offset / FMAN_PORT_IC_OFFSET_UNITS) << + BMI_IC_FROM_INT_SHIFT; + tmp |= cfg->ic_size / FMAN_PORT_IC_OFFSET_UNITS; + iowrite32be(tmp, ®s->fmbm_ricp); + + /* Internal buffer offset */ + tmp = ((uint32_t)cfg->int_buf_start_margin / FMAN_PORT_IC_OFFSET_UNITS) + << BMI_INT_BUF_MARG_SHIFT; + iowrite32be(tmp, ®s->fmbm_rim); + + /* External buffer margins */ + if (!port->im_en) + { + tmp = (uint32_t)cfg->ext_buf_start_margin << + BMI_EXT_BUF_MARG_START_SHIFT; + tmp |= (uint32_t)cfg->ext_buf_end_margin; + if (cfg->fmbm_rebm_has_sgd && cfg->no_scatter_gather) + tmp |= BMI_SG_DISABLE; + iowrite32be(tmp, ®s->fmbm_rebm); + } + + /* Frame attributes */ + tmp = BMI_CMD_RX_MR_DEF; + if (!port->im_en) + { + tmp |= BMI_CMD_ATTR_ORDER; + tmp |= (uint32_t)cfg->color << BMI_CMD_ATTR_COLOR_SHIFT; + if (cfg->sync_req) + tmp |= BMI_CMD_ATTR_SYNC; + } + iowrite32be(tmp, ®s->fmbm_rfca); + + /* NIA */ + if (port->im_en) + tmp = NIA_ENG_FM_CTL | NIA_FM_CTL_AC_IND_MODE_RX; + else + { + tmp = (uint32_t)cfg->rx_fd_bits << BMI_NEXT_ENG_FD_BITS_SHIFT; + tmp |= get_no_pcd_nia_bmi_ac_enc_frame(cfg); + } + iowrite32be(tmp, ®s->fmbm_rfne); + + /* Enqueue NIA */ + iowrite32be(NIA_ENG_QMI_ENQ | NIA_ORDER_RESTOR, ®s->fmbm_rfene); + + /* Default/error queues */ + if (!port->im_en) + { + iowrite32be((params->dflt_fqid & 0x00FFFFFF), ®s->fmbm_rfqid); + iowrite32be((params->err_fqid & 0x00FFFFFF), ®s->fmbm_refqid); + } + + /* Discard/error masks */ + iowrite32be(params->discard_mask, ®s->fmbm_rfsdm); + iowrite32be(params->err_mask, ®s->fmbm_rfsem); + + /* Statistics counters */ + tmp = 0; + if (cfg->stats_counters_enable) + tmp = BMI_COUNTERS_EN; + iowrite32be(tmp, ®s->fmbm_rstc); + + /* Performance counters */ + fman_port_set_perf_cnt_params(port, &cfg->perf_cnt_params); + tmp = 0; + if (cfg->perf_counters_enable) + tmp = BMI_COUNTERS_EN; + iowrite32be(tmp, ®s->fmbm_rpc); + + return 0; +} + +static int init_bmi_tx(struct fman_port *port, + struct fman_port_cfg *cfg, + struct fman_port_params *params) +{ + struct fman_port_tx_bmi_regs *regs = &port->bmi_regs->tx; + uint32_t tmp; + + /* Tx Configuration register */ + tmp = 0; + if (port->im_en) + tmp |= BMI_PORT_CFG_IM; + iowrite32be(tmp, ®s->fmbm_tcfg); + + /* DMA attributes */ + tmp = (uint32_t)cfg->dma_swap_data << BMI_DMA_ATTR_SWP_SHIFT; + if (cfg->dma_ic_stash_on) + tmp |= BMI_DMA_ATTR_IC_STASH_ON; + if (cfg->dma_header_stash_on) + tmp |= BMI_DMA_ATTR_HDR_STASH_ON; + if (cfg->dma_sg_stash_on) + tmp |= BMI_DMA_ATTR_SG_STASH_ON; + iowrite32be(tmp, ®s->fmbm_tda); + + /* Tx FIFO parameters */ + tmp = (cfg->tx_fifo_min_level / FMAN_PORT_BMI_FIFO_UNITS) << + BMI_TX_FIFO_MIN_FILL_SHIFT; + tmp |= ((uint32_t)cfg->tx_fifo_deq_pipeline_depth - 1) << + BMI_FIFO_PIPELINE_DEPTH_SHIFT; + tmp |= (uint32_t)(cfg->tx_fifo_low_comf_level / + FMAN_PORT_BMI_FIFO_UNITS - 1); + iowrite32be(tmp, ®s->fmbm_tfp); + + /* Frame end data */ + tmp = (uint32_t)cfg->checksum_bytes_ignore << + BMI_FRAME_END_CS_IGNORE_SHIFT; + iowrite32be(tmp, ®s->fmbm_tfed); + + /* Internal context parameters */ + if (!port->im_en) + { + tmp = ((uint32_t)cfg->ic_ext_offset / FMAN_PORT_IC_OFFSET_UNITS) << + BMI_IC_TO_EXT_SHIFT; + tmp |= ((uint32_t)cfg->ic_int_offset / FMAN_PORT_IC_OFFSET_UNITS) << + BMI_IC_FROM_INT_SHIFT; + tmp |= cfg->ic_size / FMAN_PORT_IC_OFFSET_UNITS; + iowrite32be(tmp, ®s->fmbm_ticp); + } + /* Frame attributes */ + tmp = BMI_CMD_TX_MR_DEF; + if (port->im_en) + tmp |= BMI_CMD_MR_DEAS; + else + { + tmp |= BMI_CMD_ATTR_ORDER; + tmp |= (uint32_t)cfg->color << BMI_CMD_ATTR_COLOR_SHIFT; + } + iowrite32be(tmp, ®s->fmbm_tfca); + + /* Dequeue NIA + enqueue NIA */ + if (port->im_en) + { + iowrite32be(NIA_ENG_FM_CTL | NIA_FM_CTL_AC_IND_MODE_TX, ®s->fmbm_tfdne); + iowrite32be(NIA_ENG_FM_CTL | NIA_FM_CTL_AC_IND_MODE_TX, ®s->fmbm_tfene); + } + else + { + iowrite32be(NIA_ENG_QMI_DEQ, ®s->fmbm_tfdne); + iowrite32be(NIA_ENG_QMI_ENQ | NIA_ORDER_RESTOR, ®s->fmbm_tfene); + if (cfg->fmbm_tfne_has_features) + iowrite32be(!params->dflt_fqid ? + BMI_EBD_EN | NIA_BMI_AC_FETCH_ALL_FRAME : + NIA_BMI_AC_FETCH_ALL_FRAME, ®s->fmbm_tfne); + if (!params->dflt_fqid && params->dont_release_buf) + { + iowrite32be(0x00FFFFFF, ®s->fmbm_tcfqid); + iowrite32be(NIA_ENG_BMI | NIA_BMI_AC_TX_RELEASE, ®s->fmbm_tfene); + if (cfg->fmbm_tfne_has_features) + iowrite32be(ioread32be(®s->fmbm_tfne) & ~BMI_EBD_EN, ®s->fmbm_tfne); + } + } + + /* Confirmation/error queues */ + if (!port->im_en) + { + if (params->dflt_fqid || !params->dont_release_buf) + iowrite32be(params->dflt_fqid & 0x00FFFFFF, ®s->fmbm_tcfqid); + iowrite32be((params->err_fqid & 0x00FFFFFF), ®s->fmbm_tefqid); + } + /* Statistics counters */ + tmp = 0; + if (cfg->stats_counters_enable) + tmp = BMI_COUNTERS_EN; + iowrite32be(tmp, ®s->fmbm_tstc); + + /* Performance counters */ + fman_port_set_perf_cnt_params(port, &cfg->perf_cnt_params); + tmp = 0; + if (cfg->perf_counters_enable) + tmp = BMI_COUNTERS_EN; + iowrite32be(tmp, ®s->fmbm_tpc); + + return 0; +} + +static int init_bmi_oh(struct fman_port *port, + struct fman_port_cfg *cfg, + struct fman_port_params *params) +{ + struct fman_port_oh_bmi_regs *regs = &port->bmi_regs->oh; + uint32_t tmp; + + /* OP Configuration register */ + tmp = 0; + if (cfg->discard_override) + tmp |= BMI_PORT_CFG_FDOVR; + iowrite32be(tmp, ®s->fmbm_ocfg); + + /* DMA attributes */ + tmp = (uint32_t)cfg->dma_swap_data << BMI_DMA_ATTR_SWP_SHIFT; + if (cfg->dma_ic_stash_on) + tmp |= BMI_DMA_ATTR_IC_STASH_ON; + if (cfg->dma_header_stash_on) + tmp |= BMI_DMA_ATTR_HDR_STASH_ON; + if (cfg->dma_sg_stash_on) + tmp |= BMI_DMA_ATTR_SG_STASH_ON; + if (cfg->dma_write_optimize) + tmp |= BMI_DMA_ATTR_WRITE_OPTIMIZE; + iowrite32be(tmp, ®s->fmbm_oda); + + /* Tx FIFO parameters */ + tmp = ((uint32_t)cfg->tx_fifo_deq_pipeline_depth - 1) << + BMI_FIFO_PIPELINE_DEPTH_SHIFT; + iowrite32be(tmp, ®s->fmbm_ofp); + + /* Internal context parameters */ + tmp = ((uint32_t)cfg->ic_ext_offset / FMAN_PORT_IC_OFFSET_UNITS) << + BMI_IC_TO_EXT_SHIFT; + tmp |= ((uint32_t)cfg->ic_int_offset / FMAN_PORT_IC_OFFSET_UNITS) << + BMI_IC_FROM_INT_SHIFT; + tmp |= cfg->ic_size / FMAN_PORT_IC_OFFSET_UNITS; + iowrite32be(tmp, ®s->fmbm_oicp); + + /* Frame attributes */ + tmp = BMI_CMD_OP_MR_DEF; + tmp |= (uint32_t)cfg->color << BMI_CMD_ATTR_COLOR_SHIFT; + if (cfg->sync_req) + tmp |= BMI_CMD_ATTR_SYNC; + if (port->type == E_FMAN_PORT_TYPE_OP) + tmp |= BMI_CMD_ATTR_ORDER; + iowrite32be(tmp, ®s->fmbm_ofca); + + /* Internal buffer offset */ + tmp = ((uint32_t)cfg->int_buf_start_margin / FMAN_PORT_IC_OFFSET_UNITS) + << BMI_INT_BUF_MARG_SHIFT; + iowrite32be(tmp, ®s->fmbm_oim); + + /* Dequeue NIA */ + iowrite32be(NIA_ENG_QMI_DEQ, ®s->fmbm_ofdne); + + /* NIA and Enqueue NIA */ + if (port->type == E_FMAN_PORT_TYPE_HC) { + iowrite32be(NIA_ENG_FM_CTL | NIA_FM_CTL_AC_HC, + ®s->fmbm_ofne); + iowrite32be(NIA_ENG_QMI_ENQ, ®s->fmbm_ofene); + } else { + iowrite32be(get_no_pcd_nia_bmi_ac_enc_frame(cfg), + ®s->fmbm_ofne); + iowrite32be(NIA_ENG_QMI_ENQ | NIA_ORDER_RESTOR, + ®s->fmbm_ofene); + } + + /* Default/error queues */ + iowrite32be((params->dflt_fqid & 0x00FFFFFF), ®s->fmbm_ofqid); + iowrite32be((params->err_fqid & 0x00FFFFFF), ®s->fmbm_oefqid); + + /* Discard/error masks */ + if (port->type == E_FMAN_PORT_TYPE_OP) { + iowrite32be(params->discard_mask, ®s->fmbm_ofsdm); + iowrite32be(params->err_mask, ®s->fmbm_ofsem); + } + + /* Statistics counters */ + tmp = 0; + if (cfg->stats_counters_enable) + tmp = BMI_COUNTERS_EN; + iowrite32be(tmp, ®s->fmbm_ostc); + + /* Performance counters */ + fman_port_set_perf_cnt_params(port, &cfg->perf_cnt_params); + tmp = 0; + if (cfg->perf_counters_enable) + tmp = BMI_COUNTERS_EN; + iowrite32be(tmp, ®s->fmbm_opc); + + return 0; +} + +static int init_qmi(struct fman_port *port, + struct fman_port_cfg *cfg, + struct fman_port_params *params) +{ + struct fman_port_qmi_regs *regs = port->qmi_regs; + uint32_t tmp; + + tmp = 0; + if (cfg->queue_counters_enable) + tmp |= QMI_PORT_CFG_EN_COUNTERS; + iowrite32be(tmp, ®s->fmqm_pnc); + + /* Rx port configuration */ + if ((port->type == E_FMAN_PORT_TYPE_RX) || + (port->type == E_FMAN_PORT_TYPE_RX_10G)) { + /* Enqueue NIA */ + iowrite32be(NIA_ENG_BMI | NIA_BMI_AC_RELEASE, ®s->fmqm_pnen); + return 0; + } + + /* Continue with Tx and O/H port configuration */ + if ((port->type == E_FMAN_PORT_TYPE_TX) || + (port->type == E_FMAN_PORT_TYPE_TX_10G)) { + /* Enqueue NIA */ + iowrite32be(NIA_ENG_BMI | NIA_BMI_AC_TX_RELEASE, + ®s->fmqm_pnen); + /* Dequeue NIA */ + iowrite32be(NIA_ENG_BMI | NIA_BMI_AC_TX, ®s->fmqm_pndn); + } else { + /* Enqueue NIA */ + iowrite32be(NIA_ENG_BMI | NIA_BMI_AC_RELEASE, ®s->fmqm_pnen); + /* Dequeue NIA */ + iowrite32be(NIA_ENG_BMI | NIA_BMI_AC_FETCH, ®s->fmqm_pndn); + } + + /* Dequeue Configuration register */ + tmp = 0; + if (cfg->deq_high_pri) + tmp |= QMI_DEQ_CFG_PRI; + + switch (cfg->deq_type) { + case E_FMAN_PORT_DEQ_BY_PRI: + tmp |= QMI_DEQ_CFG_TYPE1; + break; + case E_FMAN_PORT_DEQ_ACTIVE_FQ: + tmp |= QMI_DEQ_CFG_TYPE2; + break; + case E_FMAN_PORT_DEQ_ACTIVE_FQ_NO_ICS: + tmp |= QMI_DEQ_CFG_TYPE3; + break; + default: + return -EINVAL; + } + + if (cfg->qmi_deq_options_support) { + if ((port->type == E_FMAN_PORT_TYPE_HC) && + (cfg->deq_prefetch_opt != E_FMAN_PORT_DEQ_NO_PREFETCH)) + return -EINVAL; + + switch (cfg->deq_prefetch_opt) { + case E_FMAN_PORT_DEQ_NO_PREFETCH: + break; + case E_FMAN_PORT_DEQ_PART_PREFETCH: + tmp |= QMI_DEQ_CFG_PREFETCH_PARTIAL; + break; + case E_FMAN_PORT_DEQ_FULL_PREFETCH: + tmp |= QMI_DEQ_CFG_PREFETCH_FULL; + break; + default: + return -EINVAL; + } + } + tmp |= (uint32_t)(params->deq_sp & QMI_DEQ_CFG_SP_MASK) << + QMI_DEQ_CFG_SP_SHIFT; + tmp |= cfg->deq_byte_cnt; + iowrite32be(tmp, ®s->fmqm_pndc); + + return 0; +} + +static void get_rx_stats_reg(struct fman_port *port, + enum fman_port_stats_counters counter, + uint32_t **stats_reg) +{ + struct fman_port_rx_bmi_regs *regs = &port->bmi_regs->rx; + + switch (counter) { + case E_FMAN_PORT_STATS_CNT_FRAME: + *stats_reg = ®s->fmbm_rfrc; + break; + case E_FMAN_PORT_STATS_CNT_DISCARD: + *stats_reg = ®s->fmbm_rfdc; + break; + case E_FMAN_PORT_STATS_CNT_DEALLOC_BUF: + *stats_reg = ®s->fmbm_rbdc; + break; + case E_FMAN_PORT_STATS_CNT_RX_BAD_FRAME: + *stats_reg = ®s->fmbm_rfbc; + break; + case E_FMAN_PORT_STATS_CNT_RX_LARGE_FRAME: + *stats_reg = ®s->fmbm_rlfc; + break; + case E_FMAN_PORT_STATS_CNT_RX_OUT_OF_BUF: + *stats_reg = ®s->fmbm_rodc; + break; + case E_FMAN_PORT_STATS_CNT_FILTERED_FRAME: + *stats_reg = ®s->fmbm_rffc; + break; + case E_FMAN_PORT_STATS_CNT_DMA_ERR: + *stats_reg = ®s->fmbm_rfldec; + break; + default: + *stats_reg = NULL; + } +} + +static void get_tx_stats_reg(struct fman_port *port, + enum fman_port_stats_counters counter, + uint32_t **stats_reg) +{ + struct fman_port_tx_bmi_regs *regs = &port->bmi_regs->tx; + + switch (counter) { + case E_FMAN_PORT_STATS_CNT_FRAME: + *stats_reg = ®s->fmbm_tfrc; + break; + case E_FMAN_PORT_STATS_CNT_DISCARD: + *stats_reg = ®s->fmbm_tfdc; + break; + case E_FMAN_PORT_STATS_CNT_DEALLOC_BUF: + *stats_reg = ®s->fmbm_tbdc; + break; + case E_FMAN_PORT_STATS_CNT_LEN_ERR: + *stats_reg = ®s->fmbm_tfledc; + break; + case E_FMAN_PORT_STATS_CNT_UNSUPPORTED_FORMAT: + *stats_reg = ®s->fmbm_tfufdc; + break; + default: + *stats_reg = NULL; + } +} + +static void get_oh_stats_reg(struct fman_port *port, + enum fman_port_stats_counters counter, + uint32_t **stats_reg) +{ + struct fman_port_oh_bmi_regs *regs = &port->bmi_regs->oh; + + switch (counter) { + case E_FMAN_PORT_STATS_CNT_FRAME: + *stats_reg = ®s->fmbm_ofrc; + break; + case E_FMAN_PORT_STATS_CNT_DISCARD: + *stats_reg = ®s->fmbm_ofdc; + break; + case E_FMAN_PORT_STATS_CNT_DEALLOC_BUF: + *stats_reg = ®s->fmbm_obdc; + break; + case E_FMAN_PORT_STATS_CNT_FILTERED_FRAME: + *stats_reg = ®s->fmbm_offc; + break; + case E_FMAN_PORT_STATS_CNT_DMA_ERR: + *stats_reg = ®s->fmbm_ofldec; + break; + case E_FMAN_PORT_STATS_CNT_LEN_ERR: + *stats_reg = ®s->fmbm_ofledc; + break; + case E_FMAN_PORT_STATS_CNT_UNSUPPORTED_FORMAT: + *stats_reg = ®s->fmbm_ofufdc; + break; + case E_FMAN_PORT_STATS_CNT_WRED_DISCARD: + *stats_reg = ®s->fmbm_ofwdc; + break; + default: + *stats_reg = NULL; + } +} + +static void get_rx_perf_reg(struct fman_port *port, + enum fman_port_perf_counters counter, + uint32_t **perf_reg) +{ + struct fman_port_rx_bmi_regs *regs = &port->bmi_regs->rx; + + switch (counter) { + case E_FMAN_PORT_PERF_CNT_CYCLE: + *perf_reg = ®s->fmbm_rccn; + break; + case E_FMAN_PORT_PERF_CNT_TASK_UTIL: + *perf_reg = ®s->fmbm_rtuc; + break; + case E_FMAN_PORT_PERF_CNT_QUEUE_UTIL: + *perf_reg = ®s->fmbm_rrquc; + break; + case E_FMAN_PORT_PERF_CNT_DMA_UTIL: + *perf_reg = ®s->fmbm_rduc; + break; + case E_FMAN_PORT_PERF_CNT_FIFO_UTIL: + *perf_reg = ®s->fmbm_rfuc; + break; + case E_FMAN_PORT_PERF_CNT_RX_PAUSE: + *perf_reg = ®s->fmbm_rpac; + break; + default: + *perf_reg = NULL; + } +} + +static void get_tx_perf_reg(struct fman_port *port, + enum fman_port_perf_counters counter, + uint32_t **perf_reg) +{ + struct fman_port_tx_bmi_regs *regs = &port->bmi_regs->tx; + + switch (counter) { + case E_FMAN_PORT_PERF_CNT_CYCLE: + *perf_reg = ®s->fmbm_tccn; + break; + case E_FMAN_PORT_PERF_CNT_TASK_UTIL: + *perf_reg = ®s->fmbm_ttuc; + break; + case E_FMAN_PORT_PERF_CNT_QUEUE_UTIL: + *perf_reg = ®s->fmbm_ttcquc; + break; + case E_FMAN_PORT_PERF_CNT_DMA_UTIL: + *perf_reg = ®s->fmbm_tduc; + break; + case E_FMAN_PORT_PERF_CNT_FIFO_UTIL: + *perf_reg = ®s->fmbm_tfuc; + break; + default: + *perf_reg = NULL; + } +} + +static void get_oh_perf_reg(struct fman_port *port, + enum fman_port_perf_counters counter, + uint32_t **perf_reg) +{ + struct fman_port_oh_bmi_regs *regs = &port->bmi_regs->oh; + + switch (counter) { + case E_FMAN_PORT_PERF_CNT_CYCLE: + *perf_reg = ®s->fmbm_occn; + break; + case E_FMAN_PORT_PERF_CNT_TASK_UTIL: + *perf_reg = ®s->fmbm_otuc; + break; + case E_FMAN_PORT_PERF_CNT_DMA_UTIL: + *perf_reg = ®s->fmbm_oduc; + break; + case E_FMAN_PORT_PERF_CNT_FIFO_UTIL: + *perf_reg = ®s->fmbm_ofuc; + break; + default: + *perf_reg = NULL; + } +} + +static void get_qmi_counter_reg(struct fman_port *port, + enum fman_port_qmi_counters counter, + uint32_t **queue_reg) +{ + struct fman_port_qmi_regs *regs = port->qmi_regs; + + switch (counter) { + case E_FMAN_PORT_ENQ_TOTAL: + *queue_reg = ®s->fmqm_pnetfc; + break; + case E_FMAN_PORT_DEQ_TOTAL: + if ((port->type == E_FMAN_PORT_TYPE_RX) || + (port->type == E_FMAN_PORT_TYPE_RX_10G)) + /* Counter not available for Rx ports */ + *queue_reg = NULL; + else + *queue_reg = ®s->fmqm_pndtfc; + break; + case E_FMAN_PORT_DEQ_FROM_DFLT: + if ((port->type == E_FMAN_PORT_TYPE_RX) || + (port->type == E_FMAN_PORT_TYPE_RX_10G)) + /* Counter not available for Rx ports */ + *queue_reg = NULL; + else + *queue_reg = ®s->fmqm_pndfdc; + break; + case E_FMAN_PORT_DEQ_CONFIRM: + if ((port->type == E_FMAN_PORT_TYPE_RX) || + (port->type == E_FMAN_PORT_TYPE_RX_10G)) + /* Counter not available for Rx ports */ + *queue_reg = NULL; + else + *queue_reg = ®s->fmqm_pndcc; + break; + default: + *queue_reg = NULL; + } +} + +void fman_port_defconfig(struct fman_port_cfg *cfg, enum fman_port_type type) +{ + cfg->dma_swap_data = E_FMAN_PORT_DMA_NO_SWAP; + cfg->dma_ic_stash_on = FALSE; + cfg->dma_header_stash_on = FALSE; + cfg->dma_sg_stash_on = FALSE; + cfg->dma_write_optimize = TRUE; + cfg->color = E_FMAN_PORT_COLOR_GREEN; + cfg->discard_override = FALSE; + cfg->checksum_bytes_ignore = 0; + cfg->rx_cut_end_bytes = 4; + cfg->rx_pri_elevation = ((0x3FF + 1) * FMAN_PORT_BMI_FIFO_UNITS); + cfg->rx_fifo_thr = ((0x3FF + 1) * FMAN_PORT_BMI_FIFO_UNITS); + cfg->rx_fd_bits = 0; + cfg->ic_ext_offset = 0; + cfg->ic_int_offset = 0; + cfg->ic_size = 0; + cfg->int_buf_start_margin = 0; + cfg->ext_buf_start_margin = 0; + cfg->ext_buf_end_margin = 0; + cfg->tx_fifo_min_level = 0; + cfg->tx_fifo_low_comf_level = (5 * KILOBYTE); + cfg->stats_counters_enable = TRUE; + cfg->perf_counters_enable = TRUE; + cfg->deq_type = E_FMAN_PORT_DEQ_BY_PRI; + + if (type == E_FMAN_PORT_TYPE_HC) { + cfg->sync_req = FALSE; + cfg->deq_prefetch_opt = E_FMAN_PORT_DEQ_NO_PREFETCH; + } else { + cfg->sync_req = TRUE; + cfg->deq_prefetch_opt = E_FMAN_PORT_DEQ_FULL_PREFETCH; + } + + if (type == E_FMAN_PORT_TYPE_TX_10G) { + cfg->tx_fifo_deq_pipeline_depth = 4; + cfg->deq_high_pri = TRUE; + cfg->deq_byte_cnt = 0x1400; + } else { + if ((type == E_FMAN_PORT_TYPE_HC) || + (type == E_FMAN_PORT_TYPE_OP)) + cfg->tx_fifo_deq_pipeline_depth = 2; + else + cfg->tx_fifo_deq_pipeline_depth = 1; + + cfg->deq_high_pri = FALSE; + cfg->deq_byte_cnt = 0x400; + } + cfg->no_scatter_gather = DEFAULT_FMAN_SP_NO_SCATTER_GATHER; +} + +static uint8_t fman_port_find_bpool(struct fman_port *port, uint8_t bpid) +{ + uint32_t *bp_reg, tmp; + uint8_t i, id; + + /* Find the pool */ + bp_reg = port->bmi_regs->rx.fmbm_ebmpi; + for (i = 0; + (i < port->ext_pools_num && (i < FMAN_PORT_MAX_EXT_POOLS_NUM)); + i++) { + tmp = ioread32be(&bp_reg[i]); + id = (uint8_t)((tmp & BMI_EXT_BUF_POOL_ID_MASK) >> + BMI_EXT_BUF_POOL_ID_SHIFT); + + if (id == bpid) + break; + } + + return i; +} + +int fman_port_init(struct fman_port *port, + struct fman_port_cfg *cfg, + struct fman_port_params *params) +{ + int err; + + /* Init BMI registers */ + switch (port->type) { + case E_FMAN_PORT_TYPE_RX: + case E_FMAN_PORT_TYPE_RX_10G: + err = init_bmi_rx(port, cfg, params); + break; + case E_FMAN_PORT_TYPE_TX: + case E_FMAN_PORT_TYPE_TX_10G: + err = init_bmi_tx(port, cfg, params); + break; + case E_FMAN_PORT_TYPE_OP: + case E_FMAN_PORT_TYPE_HC: + err = init_bmi_oh(port, cfg, params); + break; + default: + return -EINVAL; + } + + if (err) + return err; + + /* Init QMI registers */ + if (!port->im_en) + { + err = init_qmi(port, cfg, params); + return err; + } + return 0; +} + +int fman_port_enable(struct fman_port *port) +{ + uint32_t *bmi_cfg_reg, tmp; + bool rx_port; + + switch (port->type) { + case E_FMAN_PORT_TYPE_RX: + case E_FMAN_PORT_TYPE_RX_10G: + bmi_cfg_reg = &port->bmi_regs->rx.fmbm_rcfg; + rx_port = TRUE; + break; + case E_FMAN_PORT_TYPE_TX: + case E_FMAN_PORT_TYPE_TX_10G: + bmi_cfg_reg = &port->bmi_regs->tx.fmbm_tcfg; + rx_port = FALSE; + break; + case E_FMAN_PORT_TYPE_OP: + case E_FMAN_PORT_TYPE_HC: + bmi_cfg_reg = &port->bmi_regs->oh.fmbm_ocfg; + rx_port = FALSE; + break; + default: + return -EINVAL; + } + + /* Enable QMI */ + if (!rx_port) { + tmp = ioread32be(&port->qmi_regs->fmqm_pnc) | QMI_PORT_CFG_EN; + iowrite32be(tmp, &port->qmi_regs->fmqm_pnc); + } + + /* Enable BMI */ + tmp = ioread32be(bmi_cfg_reg) | BMI_PORT_CFG_EN; + iowrite32be(tmp, bmi_cfg_reg); + + return 0; +} + +int fman_port_disable(const struct fman_port *port) +{ + uint32_t *bmi_cfg_reg, *bmi_status_reg, tmp; + bool rx_port, failure = FALSE; + int count; + + switch (port->type) { + case E_FMAN_PORT_TYPE_RX: + case E_FMAN_PORT_TYPE_RX_10G: + bmi_cfg_reg = &port->bmi_regs->rx.fmbm_rcfg; + bmi_status_reg = &port->bmi_regs->rx.fmbm_rst; + rx_port = TRUE; + break; + case E_FMAN_PORT_TYPE_TX: + case E_FMAN_PORT_TYPE_TX_10G: + bmi_cfg_reg = &port->bmi_regs->tx.fmbm_tcfg; + bmi_status_reg = &port->bmi_regs->tx.fmbm_tst; + rx_port = FALSE; + break; + case E_FMAN_PORT_TYPE_OP: + case E_FMAN_PORT_TYPE_HC: + bmi_cfg_reg = &port->bmi_regs->oh.fmbm_ocfg; + bmi_status_reg = &port->bmi_regs->oh.fmbm_ost; + rx_port = FALSE; + break; + default: + return -EINVAL; + } + + /* Disable QMI */ + if (!rx_port) { + tmp = ioread32be(&port->qmi_regs->fmqm_pnc) & ~QMI_PORT_CFG_EN; + iowrite32be(tmp, &port->qmi_regs->fmqm_pnc); + + /* Wait for QMI to finish FD handling */ + count = 100; + do { + udelay(10); + tmp = ioread32be(&port->qmi_regs->fmqm_pns); + } while ((tmp & QMI_PORT_STATUS_DEQ_FD_BSY) && --count); + + if (count == 0) + { + /* Timeout */ + failure = TRUE; + } + } + + /* Disable BMI */ + tmp = ioread32be(bmi_cfg_reg) & ~BMI_PORT_CFG_EN; + iowrite32be(tmp, bmi_cfg_reg); + + /* Wait for graceful stop end */ + count = 500; + do { + udelay(10); + tmp = ioread32be(bmi_status_reg); + } while ((tmp & BMI_PORT_STATUS_BSY) && --count); + + if (count == 0) + { + /* Timeout */ + failure = TRUE; + } + + if (failure) + return -EBUSY; + + return 0; +} + +int fman_port_set_bpools(const struct fman_port *port, + const struct fman_port_bpools *bp) +{ + uint32_t tmp, *bp_reg, *bp_depl_reg; + uint8_t i, max_bp_num; + bool grp_depl_used = FALSE, rx_port; + + switch (port->type) { + case E_FMAN_PORT_TYPE_RX: + case E_FMAN_PORT_TYPE_RX_10G: + max_bp_num = port->ext_pools_num; + rx_port = TRUE; + bp_reg = port->bmi_regs->rx.fmbm_ebmpi; + bp_depl_reg = &port->bmi_regs->rx.fmbm_mpd; + break; + case E_FMAN_PORT_TYPE_OP: + if (port->fm_rev_maj != 4) + return -EINVAL; + max_bp_num = FMAN_PORT_OBS_EXT_POOLS_NUM; + rx_port = FALSE; + bp_reg = port->bmi_regs->oh.fmbm_oebmpi; + bp_depl_reg = &port->bmi_regs->oh.fmbm_ompd; + break; + default: + return -EINVAL; + } + + if (rx_port) { + /* Check buffers are provided in ascending order */ + for (i = 0; + (i < (bp->count-1) && (i < FMAN_PORT_MAX_EXT_POOLS_NUM - 1)); + i++) { + if (bp->bpool[i].size > bp->bpool[i+1].size) + return -EINVAL; + } + } + + /* Set up external buffers pools */ + for (i = 0; i < bp->count; i++) { + tmp = BMI_EXT_BUF_POOL_VALID; + tmp |= ((uint32_t)bp->bpool[i].bpid << + BMI_EXT_BUF_POOL_ID_SHIFT) & BMI_EXT_BUF_POOL_ID_MASK; + + if (rx_port) { + if (bp->counters_enable) + tmp |= BMI_EXT_BUF_POOL_EN_COUNTER; + + if (bp->bpool[i].is_backup) + tmp |= BMI_EXT_BUF_POOL_BACKUP; + + tmp |= (uint32_t)bp->bpool[i].size; + } + + iowrite32be(tmp, &bp_reg[i]); + } + + /* Clear unused pools */ + for (i = bp->count; i < max_bp_num; i++) + iowrite32be(0, &bp_reg[i]); + + /* Pools depletion */ + tmp = 0; + for (i = 0; i < FMAN_PORT_MAX_EXT_POOLS_NUM; i++) { + if (bp->bpool[i].grp_bp_depleted) { + grp_depl_used = TRUE; + tmp |= 0x80000000 >> i; + } + + if (bp->bpool[i].single_bp_depleted) + tmp |= 0x80 >> i; + + if (bp->bpool[i].pfc_priorities_en) + tmp |= 0x0100 << i; + } + + if (grp_depl_used) + tmp |= ((uint32_t)bp->grp_bp_depleted_num - 1) << + BMI_POOL_DEP_NUM_OF_POOLS_SHIFT; + + iowrite32be(tmp, bp_depl_reg); + return 0; +} + +int fman_port_set_rate_limiter(struct fman_port *port, + struct fman_port_rate_limiter *rate_limiter) +{ + uint32_t *rate_limit_reg, *rate_limit_scale_reg; + uint32_t granularity, tmp; + uint8_t usec_bit, factor; + + switch (port->type) { + case E_FMAN_PORT_TYPE_TX: + case E_FMAN_PORT_TYPE_TX_10G: + rate_limit_reg = &port->bmi_regs->tx.fmbm_trlmt; + rate_limit_scale_reg = &port->bmi_regs->tx.fmbm_trlmts; + granularity = BMI_RATE_LIMIT_GRAN_TX; + break; + case E_FMAN_PORT_TYPE_OP: + rate_limit_reg = &port->bmi_regs->oh.fmbm_orlmt; + rate_limit_scale_reg = &port->bmi_regs->oh.fmbm_orlmts; + granularity = BMI_RATE_LIMIT_GRAN_OP; + break; + default: + return -EINVAL; + } + + /* Factor is per 1 usec count */ + factor = 1; + usec_bit = rate_limiter->count_1micro_bit; + + /* If rate limit is too small for an 1usec factor, adjust timestamp + * scale and multiply the factor */ + while (rate_limiter->rate < (granularity / factor)) { + if (usec_bit == 31) + /* Can't configure rate limiter - rate is too small */ + return -EINVAL; + + usec_bit++; + factor <<= 1; + } + + /* Figure out register value. The "while" above quarantees that + * (rate_limiter->rate * factor / granularity) >= 1 */ + tmp = (uint32_t)(rate_limiter->rate * factor / granularity - 1); + + /* Check rate limit isn't too large */ + if (tmp >= BMI_RATE_LIMIT_MAX_RATE_IN_GRAN_UNITS) + return -EINVAL; + + /* Check burst size is in allowed range */ + if ((rate_limiter->burst_size == 0) || + (rate_limiter->burst_size > + BMI_RATE_LIMIT_MAX_BURST_SIZE)) + return -EINVAL; + + tmp |= (uint32_t)(rate_limiter->burst_size - 1) << + BMI_RATE_LIMIT_MAX_BURST_SHIFT; + + if ((port->type == E_FMAN_PORT_TYPE_OP) && + (port->fm_rev_maj == 4)) { + if (rate_limiter->high_burst_size_gran) + tmp |= BMI_RATE_LIMIT_HIGH_BURST_SIZE_GRAN; + } + + iowrite32be(tmp, rate_limit_reg); + + /* Set up rate limiter scale register */ + tmp = BMI_RATE_LIMIT_SCALE_EN; + tmp |= (31 - (uint32_t)usec_bit) << BMI_RATE_LIMIT_SCALE_TSBS_SHIFT; + + if ((port->type == E_FMAN_PORT_TYPE_OP) && + (port->fm_rev_maj == 4)) + tmp |= rate_limiter->rate_factor; + + iowrite32be(tmp, rate_limit_scale_reg); + + return 0; +} + +int fman_port_delete_rate_limiter(struct fman_port *port) +{ + uint32_t *rate_limit_scale_reg; + + switch (port->type) { + case E_FMAN_PORT_TYPE_TX: + case E_FMAN_PORT_TYPE_TX_10G: + rate_limit_scale_reg = &port->bmi_regs->tx.fmbm_trlmts; + break; + case E_FMAN_PORT_TYPE_OP: + rate_limit_scale_reg = &port->bmi_regs->oh.fmbm_orlmts; + break; + default: + return -EINVAL; + } + + iowrite32be(0, rate_limit_scale_reg); + return 0; +} + +int fman_port_set_err_mask(struct fman_port *port, uint32_t err_mask) +{ + uint32_t *err_mask_reg; + + /* Obtain register address */ + switch (port->type) { + case E_FMAN_PORT_TYPE_RX: + case E_FMAN_PORT_TYPE_RX_10G: + err_mask_reg = &port->bmi_regs->rx.fmbm_rfsem; + break; + case E_FMAN_PORT_TYPE_OP: + err_mask_reg = &port->bmi_regs->oh.fmbm_ofsem; + break; + default: + return -EINVAL; + } + + iowrite32be(err_mask, err_mask_reg); + return 0; +} + +int fman_port_set_discard_mask(struct fman_port *port, uint32_t discard_mask) +{ + uint32_t *discard_mask_reg; + + /* Obtain register address */ + switch (port->type) { + case E_FMAN_PORT_TYPE_RX: + case E_FMAN_PORT_TYPE_RX_10G: + discard_mask_reg = &port->bmi_regs->rx.fmbm_rfsdm; + break; + case E_FMAN_PORT_TYPE_OP: + discard_mask_reg = &port->bmi_regs->oh.fmbm_ofsdm; + break; + default: + return -EINVAL; + } + + iowrite32be(discard_mask, discard_mask_reg); + return 0; +} + +int fman_port_modify_rx_fd_bits(struct fman_port *port, + uint8_t rx_fd_bits, + bool add) +{ + uint32_t tmp; + + switch (port->type) { + case E_FMAN_PORT_TYPE_RX: + case E_FMAN_PORT_TYPE_RX_10G: + break; + default: + return -EINVAL; + } + + tmp = ioread32be(&port->bmi_regs->rx.fmbm_rfne); + + if (add) + tmp |= (uint32_t)rx_fd_bits << BMI_NEXT_ENG_FD_BITS_SHIFT; + else + tmp &= ~((uint32_t)rx_fd_bits << BMI_NEXT_ENG_FD_BITS_SHIFT); + + iowrite32be(tmp, &port->bmi_regs->rx.fmbm_rfne); + return 0; +} + +int fman_port_set_perf_cnt_params(struct fman_port *port, + struct fman_port_perf_cnt_params *params) +{ + uint32_t *pcp_reg, tmp; + + /* Obtain register address and check parameters are in range */ + switch (port->type) { + case E_FMAN_PORT_TYPE_RX: + case E_FMAN_PORT_TYPE_RX_10G: + pcp_reg = &port->bmi_regs->rx.fmbm_rpcp; + if ((params->queue_val == 0) || + (params->queue_val > MAX_PERFORMANCE_RX_QUEUE_COMP)) + return -EINVAL; + break; + case E_FMAN_PORT_TYPE_TX: + case E_FMAN_PORT_TYPE_TX_10G: + pcp_reg = &port->bmi_regs->tx.fmbm_tpcp; + if ((params->queue_val == 0) || + (params->queue_val > MAX_PERFORMANCE_TX_QUEUE_COMP)) + return -EINVAL; + break; + case E_FMAN_PORT_TYPE_OP: + case E_FMAN_PORT_TYPE_HC: + pcp_reg = &port->bmi_regs->oh.fmbm_opcp; + if (params->queue_val != 0) + return -EINVAL; + break; + default: + return -EINVAL; + } + + if ((params->task_val == 0) || + (params->task_val > MAX_PERFORMANCE_TASK_COMP)) + return -EINVAL; + if ((params->dma_val == 0) || + (params->dma_val > MAX_PERFORMANCE_DMA_COMP)) + return -EINVAL; + if ((params->fifo_val == 0) || + ((params->fifo_val / FMAN_PORT_BMI_FIFO_UNITS) > + MAX_PERFORMANCE_FIFO_COMP)) + return -EINVAL; + tmp = (uint32_t)(params->task_val - 1) << + BMI_PERFORMANCE_TASK_COMP_SHIFT; + tmp |= (uint32_t)(params->dma_val - 1) << + BMI_PERFORMANCE_DMA_COMP_SHIFT; + tmp |= (uint32_t)(params->fifo_val / FMAN_PORT_BMI_FIFO_UNITS - 1); + + switch (port->type) { + case E_FMAN_PORT_TYPE_RX: + case E_FMAN_PORT_TYPE_RX_10G: + case E_FMAN_PORT_TYPE_TX: + case E_FMAN_PORT_TYPE_TX_10G: + tmp |= (uint32_t)(params->queue_val - 1) << + BMI_PERFORMANCE_QUEUE_COMP_SHIFT; + break; + default: + break; + } + + + iowrite32be(tmp, pcp_reg); + return 0; +} + +int fman_port_set_stats_cnt_mode(struct fman_port *port, bool enable) +{ + uint32_t *stats_reg, tmp; + + switch (port->type) { + case E_FMAN_PORT_TYPE_RX: + case E_FMAN_PORT_TYPE_RX_10G: + stats_reg = &port->bmi_regs->rx.fmbm_rstc; + break; + case E_FMAN_PORT_TYPE_TX: + case E_FMAN_PORT_TYPE_TX_10G: + stats_reg = &port->bmi_regs->tx.fmbm_tstc; + break; + case E_FMAN_PORT_TYPE_OP: + case E_FMAN_PORT_TYPE_HC: + stats_reg = &port->bmi_regs->oh.fmbm_ostc; + break; + default: + return -EINVAL; + } + + tmp = ioread32be(stats_reg); + + if (enable) + tmp |= BMI_COUNTERS_EN; + else + tmp &= ~BMI_COUNTERS_EN; + + iowrite32be(tmp, stats_reg); + return 0; +} + +int fman_port_set_perf_cnt_mode(struct fman_port *port, bool enable) +{ + uint32_t *stats_reg, tmp; + + switch (port->type) { + case E_FMAN_PORT_TYPE_RX: + case E_FMAN_PORT_TYPE_RX_10G: + stats_reg = &port->bmi_regs->rx.fmbm_rpc; + break; + case E_FMAN_PORT_TYPE_TX: + case E_FMAN_PORT_TYPE_TX_10G: + stats_reg = &port->bmi_regs->tx.fmbm_tpc; + break; + case E_FMAN_PORT_TYPE_OP: + case E_FMAN_PORT_TYPE_HC: + stats_reg = &port->bmi_regs->oh.fmbm_opc; + break; + default: + return -EINVAL; + } + + tmp = ioread32be(stats_reg); + + if (enable) + tmp |= BMI_COUNTERS_EN; + else + tmp &= ~BMI_COUNTERS_EN; + + iowrite32be(tmp, stats_reg); + return 0; +} + +int fman_port_set_queue_cnt_mode(struct fman_port *port, bool enable) +{ + uint32_t tmp; + + tmp = ioread32be(&port->qmi_regs->fmqm_pnc); + + if (enable) + tmp |= QMI_PORT_CFG_EN_COUNTERS; + else + tmp &= ~QMI_PORT_CFG_EN_COUNTERS; + + iowrite32be(tmp, &port->qmi_regs->fmqm_pnc); + return 0; +} + +int fman_port_set_bpool_cnt_mode(struct fman_port *port, + uint8_t bpid, + bool enable) +{ + uint8_t index; + uint32_t tmp; + + switch (port->type) { + case E_FMAN_PORT_TYPE_RX: + case E_FMAN_PORT_TYPE_RX_10G: + break; + default: + return -EINVAL; + } + + /* Find the pool */ + index = fman_port_find_bpool(port, bpid); + if (index == port->ext_pools_num || index == FMAN_PORT_MAX_EXT_POOLS_NUM) + /* Not found */ + return -EINVAL; + + tmp = ioread32be(&port->bmi_regs->rx.fmbm_ebmpi[index]); + + if (enable) + tmp |= BMI_EXT_BUF_POOL_EN_COUNTER; + else + tmp &= ~BMI_EXT_BUF_POOL_EN_COUNTER; + + iowrite32be(tmp, &port->bmi_regs->rx.fmbm_ebmpi[index]); + return 0; +} + +uint32_t fman_port_get_stats_counter(struct fman_port *port, + enum fman_port_stats_counters counter) +{ + uint32_t *stats_reg, ret_val; + + switch (port->type) { + case E_FMAN_PORT_TYPE_RX: + case E_FMAN_PORT_TYPE_RX_10G: + get_rx_stats_reg(port, counter, &stats_reg); + break; + case E_FMAN_PORT_TYPE_TX: + case E_FMAN_PORT_TYPE_TX_10G: + get_tx_stats_reg(port, counter, &stats_reg); + break; + case E_FMAN_PORT_TYPE_OP: + case E_FMAN_PORT_TYPE_HC: + get_oh_stats_reg(port, counter, &stats_reg); + break; + default: + stats_reg = NULL; + } + + if (stats_reg == NULL) + return 0; + + ret_val = ioread32be(stats_reg); + return ret_val; +} + +void fman_port_set_stats_counter(struct fman_port *port, + enum fman_port_stats_counters counter, + uint32_t value) +{ + uint32_t *stats_reg; + + switch (port->type) { + case E_FMAN_PORT_TYPE_RX: + case E_FMAN_PORT_TYPE_RX_10G: + get_rx_stats_reg(port, counter, &stats_reg); + break; + case E_FMAN_PORT_TYPE_TX: + case E_FMAN_PORT_TYPE_TX_10G: + get_tx_stats_reg(port, counter, &stats_reg); + break; + case E_FMAN_PORT_TYPE_OP: + case E_FMAN_PORT_TYPE_HC: + get_oh_stats_reg(port, counter, &stats_reg); + break; + default: + stats_reg = NULL; + } + + if (stats_reg == NULL) + return; + + iowrite32be(value, stats_reg); +} + +uint32_t fman_port_get_perf_counter(struct fman_port *port, + enum fman_port_perf_counters counter) +{ + uint32_t *perf_reg, ret_val; + + switch (port->type) { + case E_FMAN_PORT_TYPE_RX: + case E_FMAN_PORT_TYPE_RX_10G: + get_rx_perf_reg(port, counter, &perf_reg); + break; + case E_FMAN_PORT_TYPE_TX: + case E_FMAN_PORT_TYPE_TX_10G: + get_tx_perf_reg(port, counter, &perf_reg); + break; + case E_FMAN_PORT_TYPE_OP: + case E_FMAN_PORT_TYPE_HC: + get_oh_perf_reg(port, counter, &perf_reg); + break; + default: + perf_reg = NULL; + } + + if (perf_reg == NULL) + return 0; + + ret_val = ioread32be(perf_reg); + return ret_val; +} + +void fman_port_set_perf_counter(struct fman_port *port, + enum fman_port_perf_counters counter, + uint32_t value) +{ + uint32_t *perf_reg; + + switch (port->type) { + case E_FMAN_PORT_TYPE_RX: + case E_FMAN_PORT_TYPE_RX_10G: + get_rx_perf_reg(port, counter, &perf_reg); + break; + case E_FMAN_PORT_TYPE_TX: + case E_FMAN_PORT_TYPE_TX_10G: + get_tx_perf_reg(port, counter, &perf_reg); + break; + case E_FMAN_PORT_TYPE_OP: + case E_FMAN_PORT_TYPE_HC: + get_oh_perf_reg(port, counter, &perf_reg); + break; + default: + perf_reg = NULL; + } + + if (perf_reg == NULL) + return; + + iowrite32be(value, perf_reg); +} + +uint32_t fman_port_get_qmi_counter(struct fman_port *port, + enum fman_port_qmi_counters counter) +{ + uint32_t *queue_reg, ret_val; + + get_qmi_counter_reg(port, counter, &queue_reg); + + if (queue_reg == NULL) + return 0; + + ret_val = ioread32be(queue_reg); + return ret_val; +} + +void fman_port_set_qmi_counter(struct fman_port *port, + enum fman_port_qmi_counters counter, + uint32_t value) +{ + uint32_t *queue_reg; + + get_qmi_counter_reg(port, counter, &queue_reg); + + if (queue_reg == NULL) + return; + + iowrite32be(value, queue_reg); +} + +uint32_t fman_port_get_bpool_counter(struct fman_port *port, uint8_t bpid) +{ + uint8_t index; + uint32_t ret_val; + + switch (port->type) { + case E_FMAN_PORT_TYPE_RX: + case E_FMAN_PORT_TYPE_RX_10G: + break; + default: + return 0; + } + + /* Find the pool */ + index = fman_port_find_bpool(port, bpid); + if (index == port->ext_pools_num || index == FMAN_PORT_MAX_EXT_POOLS_NUM) + /* Not found */ + return 0; + + ret_val = ioread32be(&port->bmi_regs->rx.fmbm_acnt[index]); + return ret_val; +} + +void fman_port_set_bpool_counter(struct fman_port *port, + uint8_t bpid, + uint32_t value) +{ + uint8_t index; + + switch (port->type) { + case E_FMAN_PORT_TYPE_RX: + case E_FMAN_PORT_TYPE_RX_10G: + break; + default: + return; + } + + /* Find the pool */ + index = fman_port_find_bpool(port, bpid); + if (index == port->ext_pools_num || index == FMAN_PORT_MAX_EXT_POOLS_NUM) + /* Not found */ + return; + + iowrite32be(value, &port->bmi_regs->rx.fmbm_acnt[index]); +} + +int fman_port_add_congestion_grps(struct fman_port *port, + uint32_t grps_map[FMAN_PORT_CG_MAP_NUM]) +{ + int i; + uint32_t tmp, *grp_map_reg; + uint8_t max_grp_map_num; + + switch (port->type) { + case E_FMAN_PORT_TYPE_RX: + case E_FMAN_PORT_TYPE_RX_10G: + if (port->fm_rev_maj == 4) + max_grp_map_num = 1; + else + max_grp_map_num = FMAN_PORT_CG_MAP_NUM; + grp_map_reg = port->bmi_regs->rx.fmbm_rcgm; + break; + case E_FMAN_PORT_TYPE_OP: + max_grp_map_num = 1; + if (port->fm_rev_maj != 4) + return -EINVAL; + grp_map_reg = port->bmi_regs->oh.fmbm_ocgm; + break; + default: + return -EINVAL; + } + + for (i = (max_grp_map_num - 1); i >= 0; i--) { + if (grps_map[i] == 0) + continue; + tmp = ioread32be(&grp_map_reg[i]); + tmp |= grps_map[i]; + iowrite32be(tmp, &grp_map_reg[i]); + } + + return 0; +} + +int fman_port_remove_congestion_grps(struct fman_port *port, + uint32_t grps_map[FMAN_PORT_CG_MAP_NUM]) +{ + int i; + uint32_t tmp, *grp_map_reg; + uint8_t max_grp_map_num; + + switch (port->type) { + case E_FMAN_PORT_TYPE_RX: + case E_FMAN_PORT_TYPE_RX_10G: + if (port->fm_rev_maj == 4) + max_grp_map_num = 1; + else + max_grp_map_num = FMAN_PORT_CG_MAP_NUM; + grp_map_reg = port->bmi_regs->rx.fmbm_rcgm; + break; + case E_FMAN_PORT_TYPE_OP: + max_grp_map_num = 1; + if (port->fm_rev_maj != 4) + return -EINVAL; + grp_map_reg = port->bmi_regs->oh.fmbm_ocgm; + break; + default: + return -EINVAL; + } + + for (i = (max_grp_map_num - 1); i >= 0; i--) { + if (grps_map[i] == 0) + continue; + tmp = ioread32be(&grp_map_reg[i]); + tmp &= ~grps_map[i]; + iowrite32be(tmp, &grp_map_reg[i]); + } + return 0; +} |