blob: b5b18f6c0fb975b381f94675affc22defb5de6b6 [file] [log] [blame]
/*******************************************************************************
Copyright (C) Marvell International Ltd. and its affiliates
This software file (the "File") is owned and distributed by Marvell
International Ltd. and/or its affiliates ("Marvell") under the following
alternative licensing terms. Once you have made an election to distribute the
File under one of the following license alternatives, please (i) delete this
introductory statement regarding license alternatives, (ii) delete the two
license alternatives that you have not elected to use and (iii) preserve the
Marvell copyright notice above.
********************************************************************************
Marvell Commercial License Option
If you received this File from Marvell and you have entered into a commercial
license agreement (a "Commercial License") with Marvell, the File is licensed
to you under the terms of the applicable Commercial License.
********************************************************************************
Marvell GPL License Option
If you received this File from Marvell, you may opt to use, redistribute and/or
modify this File in accordance with the terms and conditions of the General
Public License Version 2, June 1991 (the "GPL License"), a copy of which is
available along with the File in the license.txt file or by writing to the Free
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 or
on the worldwide web at http://www.gnu.org/licenses/gpl.txt.
THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE IMPLIED
WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE ARE EXPRESSLY
DISCLAIMED. The GPL License provides additional details about this warranty
disclaimer.
********************************************************************************
Marvell BSD License Option
If you received this File from Marvell, you may opt to use, redistribute and/or
modify this File under the following licensing terms.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
* Neither the name of Marvell nor the names of its contributors may be
used to endorse or promote products derived from this software without
specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*******************************************************************************/
#include "mvCommon.h" /* Should be included before mvSysHwConfig */
#include "mvTypes.h"
#include "mv802_3.h"
#include "mvDebug.h"
#include "mvOs.h"
#include "mvPp2Gbe.h"
#include "prs/mvPp2Prs.h"
#include "bm/mvBm.h"
#define MV_PP2_RXQ_FREE -1
#define TX_DISABLE_TIMEOUT_MSEC 1000
#define RX_DISABLE_TIMEOUT_MSEC 1000
#define TX_FIFO_EMPTY_TIMEOUT_MSEC 10000
#define PORT_DISABLE_WAIT_TCLOCKS 5000
/* physical TXQs */
MV_PP2_PHYS_TXQ_CTRL *mvPp2PhysTxqs;
/* aggregated TXQs */
MV_PP2_AGGR_TXQ_CTRL *mvPp2AggrTxqs;
/* physical RXQs */
MV_PP2_PHYS_RXQ_CTRL *mvPp2PhysRxqs;
/* ports control */
MV_PP2_PORT_CTRL **mvPp2PortCtrl;
/* HW data */
MV_PP2_HAL_DATA mvPp2HalData;
/*-------------------------------------------------------------------------------*/
int mvPp2MaxCheck(int value, int limit, char *name)
{
if ((value < 0) || (value >= limit)) {
mvOsPrintf("%s %d is out of range [0..%d]\n",
name ? name : "value", value, (limit - 1));
return 1;
}
return 0;
}
int mvPp2PortCheck(int port)
{
return mvPp2MaxCheck(port, mvPp2HalData.maxPort, "port");
}
int mvPp2TxpCheck(int port, int txp)
{
int txpMax = 1;
if (mvPp2PortCheck(port))
return 1;
if (MV_PP2_IS_PON_PORT(port))
txpMax = mvPp2HalData.maxTcont;
return mvPp2MaxCheck(txp, txpMax, "txp");
}
int mvPp2CpuCheck(int cpu)
{
return mvPp2MaxCheck(cpu, mvPp2HalData.maxCPUs, "cpu");
}
int mvPp2EgressPort(int port, int txp)
{
int egress_port;
if (!MV_PP2_IS_PON_PORT(port))
egress_port = MV_PP2_MAX_TCONT + port + txp;
else
egress_port = txp;
return egress_port;
}
/*-------------------------------------------------------------------------------*/
MV_STATUS mvPp2HalInit(MV_PP2_HAL_DATA *halData)
{
int bytes, i;
MV_STATUS status;
mvPp2HalData = *halData;
bytes = mvPp2HalData.maxPort * sizeof(MV_PP2_PORT_CTRL *);
/* Allocate port data structures */
mvPp2PortCtrl = mvOsMalloc(bytes);
if (mvPp2PortCtrl == NULL) {
mvOsPrintf("%s: Can't allocate %d bytes for %d ports\n", __func__,
mvPp2HalData.maxPort * sizeof(MV_PP2_PORT_CTRL), mvPp2HalData.maxPort);
return MV_OUT_OF_CPU_MEM;
}
mvOsMemset(mvPp2PortCtrl, 0, bytes);
/* Allocate physical TXQs */
status = mvPp2PhysTxqsAlloc();
if (status != MV_OK) {
mvOsPrintf("%s: mvPp2PhysTxqsAlloc failed\n", __func__);
return status;
}
/* Allocate aggregated TXQs */
status = mvPp2AggrTxqsAlloc(mvPp2HalData.maxCPUs);
if (status != MV_OK) {
mvOsPrintf("%s: mvPp2AggrTxqsAlloc failed\n", __func__);
return status;
}
/* Allocate physical RXQs */
status = mvPp2PhysRxqsAlloc();
if (status != MV_OK) {
mvOsPrintf("%s: mvPp2PhysRxqsAlloc failed\n", __func__);
return status;
}
mvBmInit();
/* Rx Fifo Init */
mvPp2RxFifoInit(mvPp2HalData.maxPort);
/* Init all interrupt rxqs groups - each port has 0 rxqs */
for (i = 0; i <= MV_PP2_PON_PORT_ID; i++)
mvPp2GbeIsrRxqGroup(i, 0);
MV_REG_WRITE(ETH_MNG_EXTENDED_GLOBAL_CTRL_REG, 0x27);
/* Allow cache snoop when transmiting packets */
if (mvPp2HalData.iocc)
mvPp2WrReg(MV_PP2_TX_SNOOP_REG, 0x1);
/* Set TX FIFO Threshold to maximum */
MV_REG_WRITE(MV_PP2_TX_FIFO_THRESH_REG, MV_PP2_TX_CSUM_MAX_SIZE);
return MV_OK;
}
/*-------------------------------------------------------------------------------*/
MV_VOID mvPp2HalDestroy(MV_VOID)
{
mvPp2PhysTxqsDestroy();
mvPp2AggrTxqsDestroy();
mvPp2PhysRxqsDestroy();
mvOsFree(mvPp2PortCtrl);
memset(&mvPp2HalData, 0, sizeof(mvPp2HalData));
}
/*******************************************************************************
* mvNetaDefaultsSet - Set defaults to the NETA port
*
* DESCRIPTION:
* This
function sets default values to the NETA port.
* 1) Clears interrupt Cause and Mask registers.
* 2) Clears all MAC tables.
* 3) Sets defaults to all registers.
* 4) Resets RX and TX descriptor rings.
* 5) Resets PHY.
*
* INPUT:
* int portNo - Port number.
*
* RETURN: MV_STATUS
* MV_OK - Success, Others - Failure
* NOTE:
* This function updates all the port configurations except those set
* initialy by the OsGlue by MV_NETA_PORT_INIT.
* This function can be called after portDown to return the port settings
* to defaults.
*******************************************************************************/
MV_STATUS mvPp2DefaultsSet(int port)
{
MV_U32 regVal;
int txp, queue, txPortNum, i;
MV_PP2_PORT_CTRL *pPortCtrl = mvPp2PortHndlGet(port);
if (!MV_PP2_IS_PON_PORT(port))
mvGmacDefaultsSet(port);
/* avoid unused variable compilation warninig */
regVal = 0;
for (txp = 0; txp < pPortCtrl->txpNum; txp++) {
/* Disable Legacy WRR, Disable EJP, Release from reset */
txPortNum = mvPp2EgressPort(port, txp);
mvPp2WrReg(MV_PP2_TXP_SCHED_PORT_INDEX_REG, txPortNum);
mvPp2WrReg(MV_PP2_TXP_SCHED_CMD_1_REG, 0);
/* Close bandwidth for all queues */
for (queue = 0; queue < MV_PP2_MAX_TXQ; queue++)
mvPp2WrReg(MV_PP2_TXQ_SCHED_TOKEN_CNTR_REG(MV_PPV2_TXQ_PHYS(port, txp, queue)), 0);
/* Set refill period to 1 usec, refill tokens and bucket size to maximum */
mvPp2WrReg(MV_PP2_TXP_SCHED_PERIOD_REG, mvPp2HalData.tClk / 1000000);
mvPp2TxpMaxRateSet(port, txp);
}
/* Set MaximumLowLatencyPacketSize value to 256 */
mvPp2WrReg(MV_PP2_RX_CTRL_REG(port), MV_PP2_RX_USE_PSEUDO_FOR_CSUM_MASK |
MV_PP2_RX_LOW_LATENCY_PKT_SIZE_MASK(256));
/* Enable Rx cache snoop */
if (mvPp2HalData.iocc) {
for (i = 0; i < pPortCtrl->rxqNum; i++) {
queue = mvPp2LogicRxqToPhysRxq(port, i);
regVal = mvPp2RdReg(MV_PP2_RXQ_CONFIG_REG(queue));
regVal |= MV_PP2_SNOOP_PKT_SIZE_MASK | MV_PP2_SNOOP_BUF_HDR_MASK;
mvPp2WrReg(MV_PP2_RXQ_CONFIG_REG(queue), regVal);
}
}
/* At default, mask all interrupts to all cpus */
mvPp2GbeCpuInterruptsDisable(port, (1 << mvPp2HalData.maxCPUs) - 1);
return MV_OK;
}
/*-------------------------------------------------------------------------------*/
/* Mapping */
/* Add a mapping prxq <-> (port, lrxq) */
MV_STATUS mvPp2PhysRxqMapAdd(int prxq, int port, int lrxq)
{
MV_PP2_PORT_CTRL *pCtrl;
if (mvPp2PortCheck(port)) {
mvOsPrintf("Bad port number: %d\n", port);
return MV_BAD_PARAM;
}
if (lrxq < 0 || lrxq > MV_PP2_MAX_RXQ) {
mvOsPrintf("Bad logical RXQ number: %d\n", lrxq);
return MV_BAD_PARAM;
}
if (mvPp2PhysRxqs == NULL)
return MV_ERROR;
if (prxq < 0 || prxq >= MV_PP2_RXQ_TOTAL_NUM)
return MV_BAD_PARAM;
if (mvPp2PhysRxqs[prxq].port != MV_PP2_RXQ_FREE || mvPp2PhysRxqs[prxq].logicRxq != MV_PP2_RXQ_FREE)
return MV_BAD_PARAM;
pCtrl = mvPp2PortCtrl[port];
/* map prxq <- (port, lrxq) */
if (pCtrl == NULL || pCtrl->pRxQueue == NULL)
return MV_BAD_PARAM;
if (lrxq < 0 || lrxq >= MV_PP2_MAX_RXQ)
return MV_BAD_PARAM;
if (pCtrl->rxqNum >= MV_PP2_MAX_RXQ)
return MV_FAIL;
pCtrl->pRxQueue[lrxq] = &mvPp2PhysRxqs[prxq];
pCtrl->rxqNum++;
/* map prxq -> (port, lrxq) */
mvPp2PhysRxqs[prxq].port = port;
mvPp2PhysRxqs[prxq].logicRxq = lrxq;
return MV_OK;
}
/* Free the relevant physical rxq */
MV_STATUS mvPp2PhysRxqMapDel(int prxq)
{
int port, lrxq;
if (mvPp2PhysRxqs == NULL)
return MV_ERROR;
if (prxq < 0 || prxq >= MV_PP2_RXQ_TOTAL_NUM)
return MV_BAD_PARAM;
port = mvPp2PhysRxqs[prxq].port;
lrxq = mvPp2PhysRxqs[prxq].logicRxq;
mvPp2PhysRxqs[prxq].port = MV_PP2_RXQ_FREE;
mvPp2PhysRxqs[prxq].logicRxq = MV_PP2_RXQ_FREE;
if (port != MV_PP2_RXQ_FREE && lrxq != MV_PP2_RXQ_FREE &&
mvPp2PortCtrl[port] && mvPp2PortCtrl[port]->pRxQueue[lrxq]) {
mvPp2PortCtrl[port]->pRxQueue[lrxq] = NULL;
mvPp2PortCtrl[port]->rxqNum--;
}
return MV_OK;
}
MV_STATUS mvPp2PortLogicRxqMapDel(int port, int lrxq)
{
MV_PP2_PHYS_RXQ_CTRL *prxqCtrl;
if (mvPp2PortCheck(port)) {
mvOsPrintf("Bad port number: %d\n", port);
return MV_BAD_PARAM;
}
if (lrxq < 0 || lrxq > MV_PP2_MAX_RXQ) {
mvOsPrintf("Bad logical RXQ number: %d\n", lrxq);
return MV_BAD_PARAM;
}
if (mvPp2PhysRxqs == NULL)
return MV_ERROR;
if (mvPp2PortCtrl[port] == NULL || mvPp2PortCtrl[port]->pRxQueue == NULL)
return MV_BAD_PARAM;
prxqCtrl = mvPp2PortCtrl[port]->pRxQueue[lrxq];
mvPp2PortCtrl[port]->pRxQueue[lrxq] = NULL;
if (prxqCtrl) {
prxqCtrl->logicRxq = MV_PP2_RXQ_FREE;
prxqCtrl->port = MV_PP2_RXQ_FREE;
mvPp2PortCtrl[port]->rxqNum--;
}
return MV_OK;
}
/*-------------------------------------------------------------------------------*/
/* General descriptor management */
static void mvPp2DescRingReset(MV_PP2_QUEUE_CTRL *pQueueCtrl)
{
int descrNum = (pQueueCtrl->lastDesc + 1);
char *pDesc = pQueueCtrl->pFirst;
if (pDesc == NULL)
return;
/* reset ring of descriptors */
mvOsMemset(pDesc, 0, (descrNum * MV_PP2_DESC_ALIGNED_SIZE));
mvOsCacheFlush(NULL, pDesc, (descrNum * MV_PP2_DESC_ALIGNED_SIZE));
pQueueCtrl->nextToProc = 0;
}
/* allocate descriptors */
MV_U8 *mvPp2DescrMemoryAlloc(int descSize, MV_ULONG *pPhysAddr, MV_U32 *memHandle)
{
MV_U8 *pVirt;
#ifdef ETH_DESCR_UNCACHED
pVirt = (MV_U8 *)mvOsIoUncachedMalloc(NULL, descSize, pPhysAddr, memHandle);
#else
pVirt = (MV_U8 *)mvOsIoCachedMalloc(NULL, descSize, pPhysAddr, memHandle);
#endif /* ETH_DESCR_UNCACHED */
if (pVirt)
mvOsMemset(pVirt, 0, descSize);
return pVirt;
}
void mvPp2DescrMemoryFree(int descSize, MV_ULONG *pPhysAddr, MV_U8 *pVirt, MV_U32 *memHandle)
{
#ifdef ETH_DESCR_UNCACHED
mvOsIoUncachedFree(NULL, descSize, (MV_ULONG)pPhysAddr, pVirt, (MV_U32)memHandle);
#else
mvOsIoCachedFree(NULL, descSize, (MV_ULONG)pPhysAddr, pVirt, (MV_U32)memHandle);
#endif /* ETH_DESCR_UNCACHED */
}
MV_STATUS mvPp2DescrCreate(MV_PP2_QUEUE_CTRL *qCtrl, int descNum)
{
int descSize;
/* Allocate memory for descriptors */
descSize = ((descNum * MV_PP2_DESC_ALIGNED_SIZE) + MV_PP2_DESC_Q_ALIGN);
qCtrl->descBuf.bufVirtPtr =
mvPp2DescrMemoryAlloc(descSize, &qCtrl->descBuf.bufPhysAddr, &qCtrl->descBuf.memHandle);
qCtrl->descBuf.bufSize = descSize;
qCtrl->descSize = MV_PP2_DESC_ALIGNED_SIZE;
if (qCtrl->descBuf.bufVirtPtr == NULL) {
mvOsPrintf("%s: Can't allocate %d bytes for %d descr\n", __func__, descSize, descNum);
return MV_OUT_OF_CPU_MEM;
}
/* Make sure descriptor address is aligned */
qCtrl->pFirst = (char *)MV_ALIGN_UP((MV_ULONG) qCtrl->descBuf.bufVirtPtr, MV_PP2_DESC_Q_ALIGN);
qCtrl->lastDesc = (descNum - 1);
return MV_OK;
}
/*-------------------------------------------------------------------------------*/
/* RXQ */
/* Allocate and initialize descriptors for RXQ */
MV_PP2_PHYS_RXQ_CTRL *mvPp2RxqInit(int port, int rxq, int descNum)
{
MV_STATUS status;
int prxq;
MV_PP2_PHYS_RXQ_CTRL *pRxq;
MV_PP2_QUEUE_CTRL *qCtrl;
prxq = mvPp2LogicRxqToPhysRxq(port, rxq);
if (prxq < 0) {
mvOsPrintf("bad (port,rxq): (%d, %d), no mapping to physical rxq\n", port, rxq);
return NULL;
}
pRxq = &mvPp2PhysRxqs[prxq];
qCtrl = &pRxq->queueCtrl;
/* Number of descriptors must be multiple of 16 */
if (descNum % 16 != 0) {
mvOsPrintf("Descriptor number %d, must be a multiple of 16\n", descNum);
return NULL;
}
status = mvPp2DescrCreate(qCtrl, descNum);
if (status != MV_OK)
return NULL;
mvPp2DescRingReset(qCtrl);
/* zero occupied and non-occupied counters - direct access */
mvPp2WrReg(MV_PP2_RXQ_STATUS_REG(prxq), 0);
/* Set Rx descriptors queue starting address */
/* indirect access */
mvPp2WrReg(MV_PP2_RXQ_NUM_REG, prxq);
mvPp2WrReg(MV_PP2_RXQ_DESC_ADDR_REG, pp2DescVirtToPhys(qCtrl, (MV_U8 *)qCtrl->pFirst));
mvPp2WrReg(MV_PP2_RXQ_DESC_SIZE_REG, descNum);
mvPp2WrReg(MV_PP2_RXQ_INDEX_REG, 0);
return pRxq;
}
void mvPp2RxqDelete(int port, int rxq)
{
int prxq;
MV_PP2_PHYS_RXQ_CTRL *pRxq;
MV_PP2_QUEUE_CTRL *pQueueCtrl;
MV_BUF_INFO *pDescBuf;
prxq = mvPp2LogicRxqToPhysRxq(port, rxq);
if (prxq < 0) {
mvOsPrintf("bad (port,rxq): (%d, %d), no mapping to physical rxq\n", port, rxq);
return;
}
pRxq = &mvPp2PhysRxqs[prxq];
pQueueCtrl = &pRxq->queueCtrl;
pDescBuf = &pQueueCtrl->descBuf;
mvPp2DescrMemoryFree(pDescBuf->bufSize, (MV_ULONG *)pDescBuf->bufPhysAddr,
pDescBuf->bufVirtPtr, (MV_U32 *)pDescBuf->memHandle);
mvOsMemset(pQueueCtrl, 0, sizeof(*pQueueCtrl));
/* Clear Rx descriptors queue starting address, size and free descr number */
mvPp2WrReg(MV_PP2_RXQ_STATUS_REG(prxq), 0);
mvPp2WrReg(MV_PP2_RXQ_NUM_REG, prxq);
mvPp2WrReg(MV_PP2_RXQ_DESC_ADDR_REG, 0);
mvPp2WrReg(MV_PP2_RXQ_DESC_SIZE_REG, 0);
}
/* Allocate and initialize all physical RXQs.
This function must be called before any use of RXQ */
MV_STATUS mvPp2PhysRxqsAlloc(MV_VOID)
{
int i, bytes;
bytes = MV_PP2_RXQ_TOTAL_NUM * sizeof(MV_PP2_PHYS_RXQ_CTRL);
mvPp2PhysRxqs = mvOsMalloc(bytes);
if (!mvPp2PhysRxqs) {
mvOsPrintf("mvPp2 Can't allocate %d Bytes for %d RXQs controls\n",
bytes, MV_PP2_RXQ_TOTAL_NUM);
return MV_OUT_OF_CPU_MEM;
}
memset(mvPp2PhysRxqs, 0, bytes);
for (i = 0; i < MV_PP2_RXQ_TOTAL_NUM; i++) {
mvPp2PhysRxqs[i].port = MV_PP2_RXQ_FREE;
mvPp2PhysRxqs[i].logicRxq = MV_PP2_RXQ_FREE;
mvPp2PhysRxqs[i].rxq = i;
}
return MV_OK;
}
/* Destroy all physical RXQs */
MV_STATUS mvPp2PhysRxqsDestroy(MV_VOID)
{
mvOsFree(mvPp2PhysRxqs);
return MV_OK;
}
/* Associate <num_rxqs> RXQs for Port number <port>, starting from RXQ number <firstRxq>
Port and physical RXQs must be initialized.
Opperation succeeds only if ALL RXQs can be added to this port - otherwise do nothing */
MV_STATUS mvPp2PortRxqsInit(int port, int firstRxq, int numRxqs)
{
int i;
MV_PP2_PORT_CTRL *pCtrl = mvPp2PortCtrl[port];
if (firstRxq < 0 || firstRxq + numRxqs > MV_PP2_RXQ_TOTAL_NUM) {
mvOsPrintf("%s: Bad RXQ parameters. first RXQ = %d, num of RXQS = %d\n", __func__, firstRxq, numRxqs);
return MV_BAD_PARAM;
}
/* Check resources */
for (i = firstRxq; i < firstRxq + numRxqs; i++) {
if (mvPp2PhysRxqs[i].port != MV_PP2_RXQ_FREE || mvPp2PhysRxqs[i].logicRxq != MV_PP2_RXQ_FREE) {
mvOsPrintf("%s: Failed to init port#%d RXQ#%d: RXQ is already occupied\n", __func__, port, i);
return MV_FAIL;
}
}
/* Allocate logical RXQs */
if (!pCtrl->pRxQueue)
pCtrl->pRxQueue = mvOsMalloc(MV_PP2_MAX_RXQ * sizeof(MV_PP2_PHYS_RXQ_CTRL *));
if (!pCtrl->pRxQueue)
return MV_OUT_OF_CPU_MEM;
mvOsMemset(pCtrl->pRxQueue, 0, (MV_PP2_MAX_RXQ * sizeof(MV_PP2_PHYS_RXQ_CTRL *)));
/* Associate requested RXQs with port */
for (i = firstRxq; i < firstRxq + numRxqs; i++)
mvPp2PhysRxqMapAdd(i, port, i - firstRxq);
return MV_OK;
}
MV_STATUS mvPp2RxqPktsCoalSet(int port, int rxq, MV_U32 pkts)
{
MV_U32 regVal;
int prxq = mvPp2LogicRxqToPhysRxq(port, rxq);
regVal = (pkts << MV_PP2_OCCUPIED_THRESH_OFFSET) & MV_PP2_OCCUPIED_THRESH_MASK;
mvPp2WrReg(MV_PP2_RXQ_NUM_REG, prxq);
mvPp2WrReg(MV_PP2_RXQ_THRESH_REG, regVal);
return MV_OK;
}
int mvPp2RxqPktsCoalGet(int port, int rxq)
{
MV_U32 regVal;
int prxq = mvPp2LogicRxqToPhysRxq(port, rxq);
mvPp2WrReg(MV_PP2_RXQ_NUM_REG, prxq);
regVal = mvPp2RdReg(MV_PP2_RXQ_THRESH_REG);
return (regVal & MV_PP2_OCCUPIED_THRESH_MASK) >> MV_PP2_OCCUPIED_THRESH_OFFSET;
}
void mvPp2RxqReset(int port, int rxq)
{
MV_PP2_PHYS_RXQ_CTRL *pRxq;
int prxq;
prxq = mvPp2LogicRxqToPhysRxq(port, rxq);
pRxq = &mvPp2PhysRxqs[prxq];
mvPp2DescRingReset(&pRxq->queueCtrl);
/* zero occupied and non-occupied counters - direct access */
mvPp2WrReg(MV_PP2_RXQ_STATUS_REG(prxq), 0);
/* zero next descriptor index - indirect access */
mvPp2WrReg(MV_PP2_RXQ_NUM_REG, prxq);
mvPp2WrReg(MV_PP2_RXQ_INDEX_REG, 0);
}
/* Reset all RXQs */
void mvPp2RxReset(int port)
{
MV_PP2_PORT_CTRL *pPortCtrl = mvPp2PortCtrl[port];
int rxq;
for (rxq = 0; rxq < pPortCtrl->rxqNum ; rxq++)
mvPp2RxqReset(port, rxq);
}
/*-------------------------------------------------------------------------------*/
void mvPp2TxqHwfSizeSet(int port, int txp, int txq, int hwfNum)
{
int ptxq = MV_PPV2_TXQ_PHYS(port, txp, txq);
mvPp2WrReg(MV_PP2_TXQ_NUM_REG, ptxq);
mvPp2WrReg(MV_PP2_TXQ_DESC_HWF_SIZE_REG, hwfNum & MV_PP2_TXQ_DESC_HWF_SIZE_MASK);
}
/* TXQ */
/* Allocate and initialize descriptors for TXQ */
MV_PP2_PHYS_TXQ_CTRL *mvPp2TxqInit(int port, int txp, int txq, int descNum, int hwfNum)
{
MV_STATUS status;
MV_U32 regVal;
int desc, descPerTxq, ptxq = MV_PPV2_TXQ_PHYS(port, txp, txq);
MV_PP2_PHYS_TXQ_CTRL *pTxq = &mvPp2PhysTxqs[ptxq];
MV_PP2_QUEUE_CTRL *qCtrl = &pTxq->queueCtrl;
status = mvPp2DescrCreate(qCtrl, descNum);
if (status != MV_OK)
return NULL;
mvPp2DescRingReset(qCtrl);
mvPp2TxqFreeReservedDesc(port, txp, txq);
/* Set Tx descriptors queue starting address */
/* indirect access */
mvPp2WrReg(MV_PP2_TXQ_NUM_REG, ptxq);
mvPp2WrReg(MV_PP2_TXQ_DESC_ADDR_REG, pp2DescVirtToPhys(qCtrl, (MV_U8 *)qCtrl->pFirst));
mvPp2WrReg(MV_PP2_TXQ_DESC_SIZE_REG, descNum & MV_PP2_TXQ_DESC_SIZE_MASK);
mvPp2WrReg(MV_PP2_TXQ_DESC_HWF_SIZE_REG, hwfNum & MV_PP2_TXQ_DESC_HWF_SIZE_MASK);
mvPp2WrReg(MV_PP2_TXQ_INDEX_REG, 0);
/* Sanity check: Pending descriptors counter and sent descriptors counter must be 0 */
/* Pending counter read - indirect access */
regVal = mvPp2RdReg(MV_PP2_TXQ_PENDING_REG);
if (regVal != 0) {
mvOsPrintf("port=%d, txp=%d, txq=%d, ptxq=%d: pending=%u, reserved=%u\n",
port, txp, txq, ptxq,
((regVal & MV_PP2_TXQ_PENDING_MASK) >> MV_PP2_TXQ_PENDING_OFFSET),
((regVal & MV_PP2_TXQ_RESERVED_MASK) >> MV_PP2_TXQ_RESERVED_OFFSET));
}
/* Sent descriptors counter - direct access */
regVal = mvPp2RdReg(MV_PP2_TXQ_SENT_REG(ptxq));
if (regVal != 0) {
mvOsPrintf("port=%d, txp=%d, txq=%d, ptxq=%d, sent=0x%08x - Sent packets\n",
port, txp, txq, ptxq, regVal);
}
/* Calculate base address in prefetch buffer. We reserve 16 descriptors for each existing TXQ */
/* TCONTS for PON port must be continious from 0 to mvPp2HalData.maxTcont */
/* GBE ports assumed to be continious from 0 to (mvPp2HalData.maxPort - 1) */
descPerTxq = 16;
if (MV_PP2_IS_PON_PORT(port))
desc = ptxq * descPerTxq;
else
desc = (mvPp2HalData.maxTcont * MV_PP2_MAX_TXQ * descPerTxq) +
(port * MV_PP2_MAX_TXQ * descPerTxq) + (txq * descPerTxq);
mvPp2WrReg(MV_PP2_TXQ_PREF_BUF_REG, MV_PP2_PREF_BUF_PTR(desc) | MV_PP2_PREF_BUF_SIZE_16 |
MV_PP2_PREF_BUF_THRESH(descPerTxq/2));
mvPp2TxqMaxRateSet(port, txp, txq);
return pTxq;
}
MV_STATUS mvPp2TxqDelete(int port, int txp, int txq)
{
int ptxq = MV_PPV2_TXQ_PHYS(port, txp, txq);
MV_PP2_QUEUE_CTRL *pQueueCtrl = &mvPp2PhysTxqs[ptxq].queueCtrl;
MV_BUF_INFO *pDescBuf = &pQueueCtrl->descBuf;
mvPp2DescrMemoryFree(pDescBuf->bufSize, (MV_ULONG *)pDescBuf->bufPhysAddr,
pDescBuf->bufVirtPtr, (MV_U32 *)pDescBuf->memHandle);
mvOsMemset(pQueueCtrl, 0, sizeof(*pQueueCtrl));
/* Set minimum bandwidth for disabled TXQs */
mvPp2WrReg(MV_PP2_TXQ_SCHED_TOKEN_CNTR_REG(ptxq), 0);
/* Set Tx descriptors queue starting address and size */
mvPp2WrReg(MV_PP2_TXQ_NUM_REG, ptxq);
mvPp2WrReg(MV_PP2_TXQ_DESC_ADDR_REG, 0);
mvPp2WrReg(MV_PP2_TXQ_DESC_SIZE_REG, 0);
mvPp2WrReg(MV_PP2_TXQ_DESC_HWF_SIZE_REG, 0);
return MV_OK;
}
/* Allocate and initialize all physical TXQs.
This function must be called before any use of TXQ */
MV_STATUS mvPp2PhysTxqsAlloc(void)
{
int i, bytes;
/* Alloc one extra element for temporary TXQ */
bytes = (MV_PP2_TXQ_TOTAL_NUM + 1) * sizeof(MV_PP2_PHYS_TXQ_CTRL);
mvPp2PhysTxqs = mvOsMalloc(bytes);
if (!mvPp2PhysTxqs) {
mvOsPrintf("mvPp2 Can't allocate %d Bytes for %d TXQs control\n",
bytes, MV_PP2_TXQ_TOTAL_NUM);
return MV_OUT_OF_CPU_MEM;
}
memset(mvPp2PhysTxqs, 0, bytes);
for (i = 0; i < (MV_PP2_TXQ_TOTAL_NUM + 1); i++)
mvPp2PhysTxqs[i].txq = i;
return MV_OK;
}
/* Destroy all physical TXQs */
MV_VOID mvPp2PhysTxqsDestroy(MV_VOID)
{
mvOsFree(mvPp2PhysTxqs);
}
/* Associate TXQs for this port
Physical TXQS must be initialized (by using mvPp2PhysTxqsAlloc)
Notice that TXQ mapping is predefined */
MV_STATUS mvPp2PortTxqsInit(int port)
{
int txp, txq, ptxq;
MV_PP2_PORT_CTRL *pCtrl = mvPp2PortCtrl[port];
if (!pCtrl->pTxQueue)
pCtrl->pTxQueue = mvOsMalloc(pCtrl->txqNum * pCtrl->txpNum * sizeof(MV_PP2_PHYS_TXQ_CTRL *));
if (!pCtrl->pTxQueue)
return MV_OUT_OF_CPU_MEM;
for (txp = 0; txp < pCtrl->txpNum; txp++) {
for (txq = 0; txq < pCtrl->txqNum; txq++) {
ptxq = MV_PPV2_TXQ_PHYS(port, txp, txq);
pCtrl->pTxQueue[txp * CONFIG_MV_PP2_TXQ + txq] = &mvPp2PhysTxqs[ptxq];
}
}
return MV_OK;
}
/* Allocate and initialize descriptors for Aggr TXQ */
MV_STATUS mvPp2AggrTxqDescInit(MV_PP2_AGGR_TXQ_CTRL *txqCtrl, int descNum, int cpu)
{
MV_STATUS status;
MV_PP2_QUEUE_CTRL *qCtrl = &txqCtrl->queueCtrl;
status = mvPp2DescrCreate(qCtrl, descNum);
if (status != MV_OK)
return status;
mvPp2DescRingReset(qCtrl);
/* Aggr TXQ no reset WA */
qCtrl->nextToProc = mvPp2RdReg(MV_PP2_AGGR_TXQ_INDEX_REG(cpu));
/* Set Tx descriptors queue starting address */
/* indirect access */
mvPp2WrReg(MV_PP2_AGGR_TXQ_DESC_ADDR_REG(cpu), pp2DescVirtToPhys(qCtrl, (MV_U8 *)qCtrl->pFirst));
mvPp2WrReg(MV_PP2_AGGR_TXQ_DESC_SIZE_REG(cpu), descNum & MV_PP2_AGGR_TXQ_DESC_SIZE_MASK);
/* RO - mvPp2WrReg(MV_PP2_AGGR_TXQ_INDEX_REG(cpu), 0); */
return MV_OK;
}
/* Allocate all aggregated TXQs.
This function must be called before any use of aggregated TXQ */
MV_STATUS mvPp2AggrTxqsAlloc(int cpuNum)
{
/* Alloc one extra element for temporary TXQ */
int bytes = cpuNum * sizeof(MV_PP2_PHYS_TXQ_CTRL);
mvPp2AggrTxqs = mvOsMalloc(bytes);
if (!mvPp2AggrTxqs) {
mvOsPrintf("mvPp2 Can't allocate %d Bytes for %d aggr TXQs control\n", bytes, cpuNum);
return MV_OUT_OF_CPU_MEM;
}
memset(mvPp2AggrTxqs, 0, bytes);
return MV_OK;
}
/* release all aggregated TXQs */
MV_VOID mvPp2AggrTxqsDestroy(MV_VOID)
{
mvOsFree(mvPp2AggrTxqs);
}
/* Destroy all aggregated TXQs */
MV_VOID mvPp2AggrTxqDelete(int cpu)
{
MV_PP2_AGGR_TXQ_CTRL *pTxqCtrl = &mvPp2AggrTxqs[cpu];
MV_PP2_QUEUE_CTRL *pQueuCtrl = &pTxqCtrl->queueCtrl;
MV_BUF_INFO *pDescBuf = &pQueuCtrl->descBuf;
mvPp2DescrMemoryFree(pDescBuf->bufSize, (MV_ULONG *)pDescBuf->bufPhysAddr,
pDescBuf->bufVirtPtr, (MV_U32 *)pDescBuf->memHandle);
mvOsMemset(pQueuCtrl, 0, sizeof(*pQueuCtrl));
}
/* Initialize aggregated TXQ */
MV_PP2_AGGR_TXQ_CTRL *mvPp2AggrTxqInit(int cpu, int descNum)
{
MV_STATUS status;
if (!mvPp2AggrTxqs)
return NULL;
/* Number of descriptors must be multiple of 16 */
if (descNum % 16 != 0) {
mvOsPrintf("Descriptor number %d, must be a multiple of 16\n", descNum);
return NULL;
}
mvPp2AggrTxqs[cpu].cpu = cpu;
status = mvPp2AggrTxqDescInit(&mvPp2AggrTxqs[cpu], descNum, cpu);
if (status != MV_OK) {
mvOsPrintf("mvPp2 failed to initialize descriptor ring for aggr TXQ %d\n", cpu);
return NULL;
}
return &mvPp2AggrTxqs[cpu];
}
MV_STATUS mvPp2TxDonePktsCoalSet(int port, int txp, int txq, MV_U32 pkts)
{
MV_U32 regVal;
int ptxq = MV_PPV2_TXQ_PHYS(port, txp, txq);
regVal = (pkts << MV_PP2_TRANSMITTED_THRESH_OFFSET) & MV_PP2_TRANSMITTED_THRESH_MASK;
mvPp2WrReg(MV_PP2_TXQ_NUM_REG, ptxq);
mvPp2WrReg(MV_PP2_TXQ_THRESH_REG, regVal);
return MV_OK;
}
int mvPp2TxDonePktsCoalGet(int port, int txp, int txq)
{
MV_U32 regVal;
int ptxq = MV_PPV2_TXQ_PHYS(port, txp, txq);
mvPp2WrReg(MV_PP2_TXQ_NUM_REG, ptxq);
regVal = mvPp2RdReg(MV_PP2_TXQ_THRESH_REG);
return (regVal & MV_PP2_TRANSMITTED_THRESH_MASK) >> MV_PP2_TRANSMITTED_THRESH_OFFSET;
}
void mvPp2TxqReset(int port, int txp, int txq)
{
int ptxq;
MV_PP2_PHYS_TXQ_CTRL *pTxq;
ptxq = MV_PPV2_TXQ_PHYS(port, txp, txq);
pTxq = &mvPp2PhysTxqs[ptxq];
mvPp2DescRingReset(&pTxq->queueCtrl);
mvPp2WrReg(MV_PP2_TXQ_NUM_REG, ptxq);
mvPp2WrReg(MV_PP2_TXQ_INDEX_REG, 0);
}
/* Reset all TXQs */
void mvPp2TxpReset(int port, int txp)
{
int txq;
MV_PP2_PORT_CTRL *pPortCtrl = mvPp2PortCtrl[port];
for (txq = 0; txq < pPortCtrl->txqNum; txq++)
mvPp2TxqReset(port, txp, txq);
}
/* Allocate and initialize descriptors for temporary TXQ */
MV_STATUS mvPp2TxqTempInit(int descNum, int hwfNum)
{
MV_STATUS status;
int ptxq = MV_PP2_TXQ_TOTAL_NUM;
MV_PP2_PHYS_TXQ_CTRL *pTxq = &mvPp2PhysTxqs[ptxq];
MV_PP2_QUEUE_CTRL *qCtrl = &pTxq->queueCtrl;
status = mvPp2DescrCreate(qCtrl, descNum);
if (status != MV_OK)
return MV_FAIL;
mvPp2DescRingReset(qCtrl);
/* Set Tx descriptors queue starting address */
/* indirect access */
mvPp2WrReg(MV_PP2_TXQ_NUM_REG, ptxq);
mvPp2WrReg(MV_PP2_TXQ_DESC_ADDR_REG, pp2DescVirtToPhys(qCtrl, (MV_U8 *)qCtrl->pFirst));
mvPp2WrReg(MV_PP2_TXQ_DESC_SIZE_REG, descNum & MV_PP2_TXQ_DESC_SIZE_MASK);
mvPp2WrReg(MV_PP2_TXQ_DESC_HWF_SIZE_REG, hwfNum & MV_PP2_TXQ_DESC_HWF_SIZE_MASK);
mvPp2WrReg(MV_PP2_TXQ_INDEX_REG, 0);
mvPp2WrReg(MV_PP2_TXQ_PREF_BUF_REG, MV_PP2_PREF_BUF_PTR(ptxq * 4) | MV_PP2_PREF_BUF_SIZE_4 | MV_PP2_PREF_BUF_THRESH(2));
return MV_OK;
}
void mvPp2TxqTempDelete(void)
{
int ptxq = MV_PP2_TXQ_TOTAL_NUM;
MV_PP2_PHYS_TXQ_CTRL *pTxq = &mvPp2PhysTxqs[ptxq];
MV_PP2_QUEUE_CTRL *qCtrl = &pTxq->queueCtrl;
MV_BUF_INFO *pDescBuf = &qCtrl->descBuf;
mvPp2DescrMemoryFree(pDescBuf->bufSize, (MV_ULONG *)pDescBuf->bufPhysAddr,
pDescBuf->bufVirtPtr, (MV_U32 *)pDescBuf->memHandle);
mvOsMemset(qCtrl, 0, sizeof(*qCtrl));
}
/*-------------------------------------------------------------------------------*/
/* Port */
/* Allocate and initialize port structure
Alocate an initialize TXQs for this port
Associate <numRxqs> RXQs for Port number <port>, starting from RXQ number <firstRxq>
Note: mvPp2PortCtrl must be initialized, i.e. must call mvPp2HalInit before this function */
void *mvPp2PortInit(int port, int firstRxq, int numRxqs, void *osHandle)
{
MV_STATUS status;
MV_PP2_PORT_CTRL *pCtrl;
if (mvPp2PortCheck(port)) {
mvOsPrintf("%s: Bad port number: %d\n", __func__, port);
return NULL;
}
if (!mvPp2PortCtrl) {
mvOsPrintf("%s: Port control is uninitialized\n", __func__);
return NULL;
}
if (!mvPp2PortCtrl[port])
mvPp2PortCtrl[port] = (MV_PP2_PORT_CTRL *)mvOsMalloc(sizeof(MV_PP2_PORT_CTRL));
if (!mvPp2PortCtrl[port]) {
mvOsPrintf("%s: Could not allocate %d bytes for port structure\n", __func__, sizeof(MV_PP2_PORT_CTRL));
return NULL;
}
mvOsMemset(mvPp2PortCtrl[port], 0, sizeof(MV_PP2_PORT_CTRL));
pCtrl = mvPp2PortCtrl[port];
pCtrl->portNo = port;
pCtrl->osHandle = osHandle;
/* associate TXQs to this port */
#ifdef CONFIG_MV_INCLUDE_PON
pCtrl->txpNum = MV_PP2_IS_PON_PORT(port) ? mvPp2HalData.maxTcont : 1;
#else
pCtrl->txpNum = 1;
#endif
pCtrl->txqNum = CONFIG_MV_PP2_TXQ;
status = mvPp2PortTxqsInit(port);
if (status != MV_OK)
return NULL;
/* associate RXQs to this port */
pCtrl->rxqNum = 0;
status = mvPp2PortRxqsInit(port, firstRxq, numRxqs);
if (status != MV_OK)
return NULL;
/* associate interrupt from relevant rxqs group to this port */
status = mvPp2GbeIsrRxqGroup(port, numRxqs);
if (status != MV_OK)
return NULL;
/* Disable port */
mvPp2PortIngressEnable(port, MV_FALSE);
mvPp2PortEgressEnable(port, MV_FALSE);
mvPp2PortEnable(port, MV_FALSE);
mvPp2DefaultsSet(port);
return pCtrl;
}
void mvPp2PortDestroy(int portNo)
{
MV_PP2_PORT_CTRL *pPortCtrl = mvPp2PortHndlGet(portNo);
if (pPortCtrl->pTxQueue)
mvOsFree(pPortCtrl->pTxQueue);
if (pPortCtrl->pRxQueue)
mvOsFree(pPortCtrl->pRxQueue);
if (pPortCtrl)
mvOsFree(pPortCtrl);
mvPp2PortCtrl[portNo] = NULL;
}
/*******************************************************************************
* mvPp2PortEgressEnable
*
* DESCRIPTION:
* Disable fetch descriptors from initialized TXQs
*
* Note: Effects TXQs initialized prior to calling this function.
*
* INPUT:
* int portNo - Port number.
*
* RETURN: MV_STATUS
* MV_OK - Success, Others - Failure.
*
*******************************************************************************/
MV_STATUS mvPp2PortEgressEnable(int port, MV_BOOL en)
{
int txp;
MV_PP2_PORT_CTRL *pPortCtrl = mvPp2PortHndlGet(port);
/* Disable all physical TXQs */
for (txp = 0; txp < pPortCtrl->txpNum; txp++) {
if (en)
mvPp2TxpEnable(port, txp);
else
mvPp2TxpDisable(port, txp);
}
return MV_OK;
}
/*-------------------------------------------------------------------------------*/
MV_STATUS mvPp2PortEnable(int port, MV_BOOL en)
{
if (!MV_PP2_IS_PON_PORT(port)) {
/* Enable port */
if (en)
mvGmacPortEnable(port);
else
mvGmacPortDisable(port);
}
return MV_OK;
}
/*-------------------------------------------------------------------------------*/
/* BM */
MV_STATUS mvPp2BmPoolBufSizeSet(int pool, int bufsize)
{
MV_U32 regVal;
mvBmPoolBufSizeSet(pool, bufsize);
regVal = MV_ALIGN_UP(bufsize, 1 << MV_PP2_POOL_BUF_SIZE_OFFSET);
mvPp2WrReg(MV_PP2_POOL_BUF_SIZE_REG(pool), regVal);
return MV_OK;
}
/*******************************************************************************
* mvPp2PortIngressEnable
*
* DESCRIPTION:
* Enable/Disable receive packets to RXQs for SWF and receive packets to TXQs for HWF.
*
* Note: Effects only Rx and Tx queues initialized prior to calling this function.
*
* INPUT:
* int portNo - Port number.
*
* RETURN: MV_STATUS
* MV_OK - Success, Others - Failure.
*
*******************************************************************************/
MV_STATUS mvPp2PortIngressEnable(int port, MV_BOOL en)
{
int txp, txq, rxq;
MV_PP2_PORT_CTRL *pPortCtrl = mvPp2PortHndlGet(port);
/* Enable all initialized RXQs */
for (rxq = 0; rxq < pPortCtrl->rxqNum ; rxq++) {
if (pPortCtrl->pRxQueue[rxq] != NULL)
mvPp2RxqEnable(port, rxq, en);
}
/* Enable HWF for all initialized TXQs. */
for (txp = 0; txp < pPortCtrl->txpNum; txp++) {
for (txq = 0; txq < pPortCtrl->txqNum; txq++) {
if (pPortCtrl->pTxQueue[txp * pPortCtrl->txqNum + txq] != NULL)
mvPp2HwfTxqEnable(port, txp, txq, en);
}
}
return MV_OK;
}
MV_STATUS mvPp2RxqOffsetSet(int port, int rxq, int offset)
{
MV_U32 regVal;
int prxq = mvPp2LogicRxqToPhysRxq(port, rxq);
if (offset % 32 != 0) {
mvOsPrintf("%s: offset must be in units of 32\n", __func__);
return MV_BAD_PARAM;
}
/* convert offset from bytes to units of 32 bytes */
offset = offset >> 5;
regVal = mvPp2RdReg(MV_PP2_RXQ_CONFIG_REG(prxq));
regVal &= ~MV_PP2_RXQ_PACKET_OFFSET_MASK;
/* Offset is in */
regVal |= ((offset << MV_PP2_RXQ_PACKET_OFFSET_OFFS) & MV_PP2_RXQ_PACKET_OFFSET_MASK);
mvPp2WrReg(MV_PP2_RXQ_CONFIG_REG(prxq), regVal);
return MV_OK;
}
MV_STATUS mvPp2RxqBmLongPoolSet(int port, int rxq, int longPool)
{
MV_U32 regVal = 0;
int prxq = mvPp2LogicRxqToPhysRxq(port, rxq);
regVal = mvPp2RdReg(MV_PP2_RXQ_CONFIG_REG(prxq));
regVal &= ~MV_PP2_RXQ_POOL_LONG_MASK;
regVal |= ((longPool << MV_PP2_RXQ_POOL_LONG_OFFS) & MV_PP2_RXQ_POOL_LONG_MASK);
mvPp2WrReg(MV_PP2_RXQ_CONFIG_REG(prxq), regVal);
/* Update default BM priority rule */
mvBmRxqToQsetLongClean(prxq);
mvBmRxqToQsetLongSet(prxq, mvBmDefaultQsetNumGet(longPool));
return MV_OK;
}
MV_STATUS mvPp2RxqBmShortPoolSet(int port, int rxq, int shortPool)
{
MV_U32 regVal = 0;
int prxq = mvPp2LogicRxqToPhysRxq(port, rxq);
regVal = mvPp2RdReg(MV_PP2_RXQ_CONFIG_REG(prxq));
regVal &= ~MV_PP2_RXQ_POOL_SHORT_MASK;
regVal |= ((shortPool << MV_PP2_RXQ_POOL_SHORT_OFFS) & MV_PP2_RXQ_POOL_SHORT_MASK);
mvPp2WrReg(MV_PP2_RXQ_CONFIG_REG(prxq), regVal);
/* Update default BM priority rule */
mvBmRxqToQsetShortClean(prxq);
mvBmRxqToQsetShortSet(prxq, mvBmDefaultQsetNumGet(shortPool));
return MV_OK;
}
MV_STATUS mvPp2TxqBmShortPoolSet(int port, int txp, int txq, int shortPool)
{
MV_U32 regVal = 0;
int ptxq = MV_PPV2_TXQ_PHYS(port, txp, txq);
regVal = mvPp2RdReg(MV_PP2_HWF_TXQ_CONFIG_REG(ptxq));
regVal &= ~MV_PP2_HWF_TXQ_POOL_SHORT_MASK;
regVal |= ((shortPool << MV_PP2_HWF_TXQ_POOL_SHORT_OFFS) & MV_PP2_HWF_TXQ_POOL_SHORT_MASK);
mvPp2WrReg(MV_PP2_HWF_TXQ_CONFIG_REG(ptxq), regVal);
mvBmTxqToQsetShortClean(ptxq);
mvBmTxqToQsetShortSet(ptxq, mvBmDefaultQsetNumGet(shortPool));
return MV_OK;
}
MV_STATUS mvPp2TxqBmLongPoolSet(int port, int txp, int txq, int longPool)
{
MV_U32 regVal = 0;
int ptxq = MV_PPV2_TXQ_PHYS(port, txp, txq);
regVal = mvPp2RdReg(MV_PP2_HWF_TXQ_CONFIG_REG(ptxq));
regVal &= ~MV_PP2_HWF_TXQ_POOL_LONG_MASK;
regVal |= ((longPool << MV_PP2_HWF_TXQ_POOL_LONG_OFFS) & MV_PP2_HWF_TXQ_POOL_LONG_MASK);
mvPp2WrReg(MV_PP2_HWF_TXQ_CONFIG_REG(ptxq), regVal);
mvBmTxqToQsetLongClean(ptxq);
mvBmTxqToQsetLongSet(ptxq, mvBmDefaultQsetNumGet(longPool));
return MV_OK;
}
/*-------------------------------------------------------------------------------*/
MV_STATUS mvPp2MhSet(int port, MV_TAG_TYPE mh)
{
MV_U32 regVal;
regVal = mvPp2RdReg(MV_PP2_MH_REG(MV_PPV2_PORT_PHYS(port)));
/* Clear relevant fields */
regVal &= ~(MV_PP2_DSA_EN_MASK | MV_PP2_MH_EN_MASK);
switch (mh) {
case MV_TAG_TYPE_NONE:
case MV_TAG_TYPE_VLAN:
break;
case MV_TAG_TYPE_MH:
regVal |= MV_PP2_MH_EN_MASK;
break;
case MV_TAG_TYPE_DSA:
regVal |= MV_PP2_DSA_NON_EXTENDED;
break;
case MV_TAG_TYPE_EDSA:
regVal |= MV_PP2_DSA_EXTENDED;
break;
default:
mvOsPrintf("port=%d: Unexpected MH = %d value\n", port, mh);
return MV_BAD_PARAM;
}
mvPp2WrReg(MV_PP2_MH_REG(MV_PPV2_PORT_PHYS(port)), regVal);
if (mh == MV_TAG_TYPE_MH)
mvGmacPortMhSet(port, 1);
else
mvGmacPortMhSet(port, 0);
return MV_OK;
}
/*-------------------------------------------------------------------------------*/
MV_STATUS mvPp2RxFifoInit(int portNum)
{
int i, port;
for (i = 0; i < portNum; i++) {
port = MV_PPV2_PORT_PHYS(i);
mvPp2WrReg(MV_PP2_RX_DATA_FIFO_SIZE_REG(port), MV_PP2_RX_FIFO_PORT_DATA_SIZE);
mvPp2WrReg(MV_PP2_RX_ATTR_FIFO_SIZE_REG(port), MV_PP2_RX_FIFO_PORT_ATTR_SIZE);
}
mvPp2WrReg(MV_PP2_RX_MIN_PKT_SIZE_REG, MV_PP2_RX_FIFO_PORT_MIN_PKT);
mvPp2WrReg(MV_PP2_RX_FIFO_INIT_REG, 0x1);
return MV_OK;
}
/*-------------------------------------------------------------------------------*/
/*******************************/
/* Interrupts API */
/*******************************/
MV_STATUS mvPp2RxqTimeCoalSet(int port, int rxq, MV_U32 uSec)
{
MV_U32 regVal;
int prxq = mvPp2LogicRxqToPhysRxq(port, rxq);
unsigned int tClkUsec;
tClkUsec = mvPp2HalData.tClk / 1000000;
/* Register contains interrupt time in units of 16 core clock sycles, */
/* therefore shift the result value on 4 bits */
regVal = (((uSec * tClkUsec) >> 4) << MV_PP2_ISR_RX_THRESHOLD_OFFS) & MV_PP2_ISR_RX_THRESHOLD_MASK;
mvPp2WrReg(MV_PP2_ISR_RX_THRESHOLD_REG(prxq), regVal);
return MV_OK;
}
unsigned int mvPp2RxqTimeCoalGet(int port, int rxq)
{
MV_U32 regVal;
int prxq = mvPp2LogicRxqToPhysRxq(port, rxq);
unsigned int res, tClkUsec, uSec;
tClkUsec = mvPp2HalData.tClk / 1000000;
regVal = mvPp2RdReg(MV_PP2_ISR_RX_THRESHOLD_REG(prxq));
/* Register contains interrupt time in units of 16 core clock sycles, */
/* therefore shift the result value on 4 bits */
res = (((regVal & MV_PP2_ISR_RX_THRESHOLD_MASK) >> MV_PP2_ISR_RX_THRESHOLD_OFFS) << 4);
if ((res % tClkUsec) != 0)
uSec = (res / tClkUsec) + 1;
else
uSec = res / tClkUsec;
return uSec;
}
/* unmask the current CPU's rx/tx interrupts *
* - rxq_mask: support rxq to cpu granularity *
* - isTxDoneIsr: if 0 then Tx Done interruptare not unmasked */
MV_STATUS mvPp2GbeIsrRxTxUnmask(int port, MV_U16 rxq_mask, int isTxDoneIsr)
{
if (MV_PP2_IS_PON_PORT(port)) {
mvPp2WrReg(MV_PP2_ISR_PON_RX_TX_MASK_REG,
(MV_PP2_PON_CAUSE_MISC_SUM_MASK |
((isTxDoneIsr) ? MV_PP2_PON_CAUSE_TXP_OCCUP_DESC_ALL_MASK : 0) |
(MV_PP2_PON_CAUSE_RXQ_OCCUP_DESC_ALL_MASK & rxq_mask)));
} else {
mvPp2WrReg(MV_PP2_ISR_RX_TX_MASK_REG(MV_PPV2_PORT_PHYS(port)),
(MV_PP2_CAUSE_MISC_SUM_MASK |
((isTxDoneIsr) ? MV_PP2_CAUSE_TXQ_OCCUP_DESC_ALL_MASK : 0) |
(MV_PP2_CAUSE_RXQ_OCCUP_DESC_ALL_MASK & rxq_mask)));
}
return MV_OK;
}
/* mask the current CPU's rx/tx interrupts */
MV_STATUS mvPp2GbeIsrRxTxMask(int port)
{
if (MV_PP2_IS_PON_PORT(port))
mvPp2WrReg(MV_PP2_ISR_PON_RX_TX_MASK_REG, 0);
else
mvPp2WrReg(MV_PP2_ISR_RX_TX_MASK_REG(MV_PPV2_PORT_PHYS(port)), 0);
return MV_OK;
}
MV_STATUS mvPp2GbeIsrRxqGroup(int port, int rxqNum)
{
if ((rxqNum % 4 != 0) || (rxqNum > MV_PP2_MAX_RXQ)) {
mvOsPrintf("%s: bad number of rxqs - %d. Must be multiple of 4 and less than %d\n",
__func__, rxqNum, MV_PP2_MAX_RXQ);
return MV_BAD_PARAM;
}
mvPp2WrReg(MV_PP2_ISR_RXQ_GROUP_REG(port), rxqNum);
return MV_OK;
}
/*-------------------------------------------------------------------------------*/
/* WRR / EJP configuration routines */
MV_STATUS mvPp2TxpMaxRateSet(int port, int txp)
{
MV_U32 regVal;
int eport;
eport = mvPp2EgressPort(port, txp);
mvPp2WrReg(MV_PP2_TXP_SCHED_PORT_INDEX_REG, eport);
regVal = mvPp2RdReg(MV_PP2_TXP_SCHED_REFILL_REG);
regVal &= ~MV_PP2_TXP_REFILL_PERIOD_ALL_MASK;
regVal |= MV_PP2_TXP_REFILL_PERIOD_MASK(1);
regVal |= MV_PP2_TXP_REFILL_TOKENS_ALL_MASK;
mvPp2WrReg(MV_PP2_TXP_SCHED_REFILL_REG, regVal);
regVal = MV_PP2_TXP_TOKEN_CNTR_MAX;
mvPp2WrReg(MV_PP2_TXP_SCHED_TOKEN_SIZE_REG, regVal);
return MV_OK;
}
MV_STATUS mvPp2TxqMaxRateSet(int port, int txp, int txq)
{
MV_U32 regVal;
int eport;
eport = mvPp2EgressPort(port, txp);
mvPp2WrReg(MV_PP2_TXP_SCHED_PORT_INDEX_REG, eport);
regVal = mvPp2RdReg(MV_PP2_TXQ_SCHED_REFILL_REG(txq));
regVal &= ~MV_PP2_TXQ_REFILL_PERIOD_ALL_MASK;
regVal |= MV_PP2_TXQ_REFILL_PERIOD_MASK(1);
regVal |= MV_PP2_TXQ_REFILL_TOKENS_ALL_MASK;
mvPp2WrReg(MV_PP2_TXQ_SCHED_REFILL_REG(txq), regVal);
regVal = MV_PP2_TXQ_TOKEN_CNTR_MAX;
mvPp2WrReg(MV_PP2_TXQ_SCHED_TOKEN_SIZE_REG(txq), regVal);
return MV_OK;
}
/* Calculate period and tokens accordingly with required rate and accuracy */
MV_STATUS mvPp2RateCalc(int rate, unsigned int accuracy, unsigned int *pPeriod, unsigned int *pTokens)
{
/* Calculate refill tokens and period - rate [Kbps] = tokens [bits] * 1000 / period [usec] */
/* Assume: Tclock [MHz] / BasicRefillNoOfClocks = 1 */
unsigned int period, tokens, calc;
if (rate == 0) {
/* Disable traffic from the port: tokens = 0 */
if (pPeriod != NULL)
*pPeriod = 1000;
if (pTokens != NULL)
*pTokens = 0;
return MV_OK;
}
/* Find values of "period" and "tokens" match "rate" and "accuracy" when period is minimal */
for (period = 1; period <= 1000; period++) {
tokens = 1;
while (MV_TRUE) {
calc = (tokens * 1000) / period;
if (((MV_ABS(calc - rate) * 100) / rate) <= accuracy) {
if (pPeriod != NULL)
*pPeriod = period;
if (pTokens != NULL)
*pTokens = tokens;
return MV_OK;
}
if (calc > rate)
break;
tokens++;
}
}
return MV_FAIL;
}
/* Set bandwidth limitation for TX port
* rate [Kbps] - steady state TX bandwidth limitation
*/
MV_STATUS mvPp2TxpRateSet(int port, int txp, int rate)
{
MV_U32 regVal;
unsigned int tokens, period, txPortNum, accuracy = 0;
MV_STATUS status;
if (mvPp2TxpCheck(port, txp))
return MV_BAD_PARAM;
txPortNum = mvPp2EgressPort(port, txp);
mvPp2WrReg(MV_PP2_TXP_SCHED_PORT_INDEX_REG, txPortNum);
regVal = mvPp2RdReg(MV_PP2_TXP_SCHED_PERIOD_REG);
status = mvPp2RateCalc(rate, accuracy, &period, &tokens);
if (status != MV_OK) {
mvOsPrintf("%s: Can't provide rate of %d [Kbps] with accuracy of %d [%%]\n",
__func__, rate, accuracy);
return status;
}
if (tokens > MV_PP2_TXP_REFILL_TOKENS_MAX)
tokens = MV_PP2_TXP_REFILL_TOKENS_MAX;
if (period > MV_PP2_TXP_REFILL_PERIOD_MAX)
period = MV_PP2_TXP_REFILL_PERIOD_MAX;
regVal = mvPp2RdReg(MV_PP2_TXP_SCHED_REFILL_REG);
regVal &= ~MV_PP2_TXP_REFILL_TOKENS_ALL_MASK ;
regVal |= MV_PP2_TXP_REFILL_TOKENS_MASK(tokens);
regVal &= ~MV_PP2_TXP_REFILL_PERIOD_ALL_MASK;
regVal |= MV_PP2_TXP_REFILL_PERIOD_MASK(period);
mvPp2WrReg(MV_PP2_TXP_SCHED_REFILL_REG, regVal);
return MV_OK;
}
/* Set maximum burst size for TX port
* burst [bytes] - number of bytes to be sent with maximum possible TX rate,
* before TX rate limitation will take place.
*/
MV_STATUS mvPp2TxpBurstSet(int port, int txp, int burst)
{
MV_U32 size, mtu;
int txPortNum;
if (mvPp2TxpCheck(port, txp))
return MV_BAD_PARAM;
txPortNum = mvPp2EgressPort(port, txp);
mvPp2WrReg(MV_PP2_TXP_SCHED_PORT_INDEX_REG, txPortNum);
/* Calulate Token Bucket Size */
size = 8 * burst;
if (size > MV_PP2_TXP_TOKEN_SIZE_MAX)
size = MV_PP2_TXP_TOKEN_SIZE_MAX;
/* Token bucket size must be larger then MTU */
mtu = mvPp2RdReg(MV_PP2_TXP_SCHED_MTU_REG);
if (mtu > size) {
mvOsPrintf("%s Error: Bucket size (%d bytes) < MTU (%d bytes)\n",
__func__, (size / 8), (mtu / 8));
return MV_BAD_PARAM;
}
mvPp2WrReg(MV_PP2_TXP_SCHED_TOKEN_SIZE_REG, size);
return MV_OK;
}
/* Set bandwidth limitation for TXQ
* rate [Kbps] - steady state TX rate limitation
*/
MV_STATUS mvPp2TxqRateSet(int port, int txp, int txq, int rate)
{
MV_U32 regVal;
unsigned int txPortNum, period, tokens, accuracy = 0;
MV_STATUS status;
if (mvPp2TxpCheck(port, txp))
return MV_BAD_PARAM;
if (txq >= MV_PP2_MAX_TXQ)
return MV_BAD_PARAM;
status = mvPp2RateCalc(rate, accuracy, &period, &tokens);
if (status != MV_OK) {
mvOsPrintf("%s: Can't provide rate of %d [Kbps] with accuracy of %d [%%]\n",
__func__, rate, accuracy);
return status;
}
txPortNum = mvPp2EgressPort(port, txp);
mvPp2WrReg(MV_PP2_TXP_SCHED_PORT_INDEX_REG, txPortNum);
if (tokens > MV_PP2_TXQ_REFILL_TOKENS_MAX)
tokens = MV_PP2_TXQ_REFILL_TOKENS_MAX;
if (period > MV_PP2_TXQ_REFILL_PERIOD_MAX)
period = MV_PP2_TXQ_REFILL_PERIOD_MAX;
regVal = mvPp2RdReg(MV_PP2_TXQ_SCHED_REFILL_REG(txq));
regVal &= ~MV_PP2_TXQ_REFILL_TOKENS_ALL_MASK;
regVal |= MV_PP2_TXQ_REFILL_TOKENS_MASK(tokens);
regVal &= ~MV_PP2_TXQ_REFILL_PERIOD_ALL_MASK;
regVal |= MV_PP2_TXQ_REFILL_PERIOD_MASK(period);
mvPp2WrReg(MV_PP2_TXQ_SCHED_REFILL_REG(txq), regVal);
return MV_OK;
}
/* Set maximum burst size for TX port
* burst [bytes] - number of bytes to be sent with maximum possible TX rate,
* before TX bandwidth limitation will take place.
*/
MV_STATUS mvPp2TxqBurstSet(int port, int txp, int txq, int burst)
{
MV_U32 size, mtu;
int txPortNum;
if (mvPp2TxpCheck(port, txp))
return MV_BAD_PARAM;
if (txq >= MV_PP2_MAX_TXQ)
return MV_BAD_PARAM;
txPortNum = mvPp2EgressPort(port, txp);
mvPp2WrReg(MV_PP2_TXP_SCHED_PORT_INDEX_REG, txPortNum);
/* Calulate Tocket Bucket Size */
size = 8 * burst;
if (size > MV_PP2_TXQ_TOKEN_SIZE_MAX)
size = MV_PP2_TXQ_TOKEN_SIZE_MAX;
/* Tocken bucket size must be larger then MTU */
mtu = mvPp2RdReg(MV_PP2_TXP_SCHED_MTU_REG);
if (mtu > size) {
mvOsPrintf("%s Error: Bucket size (%d bytes) < MTU (%d bytes)\n",
__func__, (size / 8), (mtu / 8));
return MV_BAD_PARAM;
}
mvPp2WrReg(MV_PP2_TXQ_SCHED_TOKEN_SIZE_REG(txq), size);
return MV_OK;
}
/* Set TXQ to work in FIX priority mode */
MV_STATUS mvPp2TxqFixPrioSet(int port, int txp, int txq)
{
MV_U32 regVal;
int txPortNum;
if (mvPp2TxpCheck(port, txp))
return MV_BAD_PARAM;
if (txq >= MV_PP2_MAX_TXQ)
return MV_BAD_PARAM;
txPortNum = mvPp2EgressPort(port, txp);
mvPp2WrReg(MV_PP2_TXP_SCHED_PORT_INDEX_REG, txPortNum);
regVal = mvPp2RdReg(MV_PP2_TXP_SCHED_FIXED_PRIO_REG);
regVal |= (1 << txq);
mvPp2WrReg(MV_PP2_TXP_SCHED_FIXED_PRIO_REG, regVal);
return MV_OK;
}
/* Set TXQ to work in WRR mode and set relative weight. */
/* Weight range [1..N] */
MV_STATUS mvPp2TxqWrrPrioSet(int port, int txp, int txq, int weight)
{
MV_U32 regVal, mtu, mtu_aligned, weight_min;
int txPortNum;
if (mvPp2TxpCheck(port, txp))
return MV_BAD_PARAM;
if (txq >= MV_PP2_MAX_TXQ)
return MV_BAD_PARAM;
txPortNum = mvPp2EgressPort(port, txp);
mvPp2WrReg(MV_PP2_TXP_SCHED_PORT_INDEX_REG, txPortNum);
/* Weight * 256 bytes * 8 bits must be larger then MTU [bits] */
mtu = mvPp2RdReg(MV_PP2_TXP_SCHED_MTU_REG);
/* WA for wrong Token bucket update: Set MTU value = 3*real MTU value, now get read MTU*/
mtu /= MV_AMPLIFY_FACTOR_MTU;
mtu /= MV_BIT_NUM_OF_BYTE; /* move to bytes */
mtu_aligned = MV_ALIGN_UP(mtu, MV_WRR_WEIGHT_UNIT);
weight_min = mtu_aligned / MV_WRR_WEIGHT_UNIT;
if ((weight < weight_min) || (weight > MV_PP2_TXQ_WRR_WEIGHT_MAX)) {
mvOsPrintf("%s Error: weight=%d is out of range %d...%d\n",
__func__, weight, weight_min, MV_PP2_TXQ_WRR_WEIGHT_MAX);
return MV_FAIL;
}
regVal = mvPp2RdReg(MV_PP2_TXQ_SCHED_WRR_REG(txq));
regVal &= ~MV_PP2_TXQ_WRR_WEIGHT_ALL_MASK;
regVal |= MV_PP2_TXQ_WRR_WEIGHT_MASK(weight);
mvPp2WrReg(MV_PP2_TXQ_SCHED_WRR_REG(txq), regVal);
regVal = mvPp2RdReg(MV_PP2_TXP_SCHED_FIXED_PRIO_REG);
regVal &= ~(1 << txq);
mvPp2WrReg(MV_PP2_TXP_SCHED_FIXED_PRIO_REG, regVal);
return MV_OK;
}
/* Set minimum number of tockens to start transmit for TX port
* maxTxSize [bytes] - maximum packet size can be sent via this TX port
*/
MV_STATUS mvPp2TxpMaxTxSizeSet(int port, int txp, int maxTxSize)
{
MV_U32 regVal, size, mtu;
int txq, txPortNum;
if (mvPp2TxpCheck(port, txp))
return MV_BAD_PARAM;
mtu = maxTxSize * 8;
if (mtu > MV_PP2_TXP_MTU_MAX)
mtu = MV_PP2_TXP_MTU_MAX;
/* WA for wrong Token bucket update: Set MTU value = 3*real MTU value */
mtu = MV_AMPLIFY_FACTOR_MTU * mtu;
txPortNum = mvPp2EgressPort(port, txp);
mvPp2WrReg(MV_PP2_TXP_SCHED_PORT_INDEX_REG, txPortNum);
/* set MTU */
regVal = mvPp2RdReg(MV_PP2_TXP_SCHED_MTU_REG);
regVal &= ~MV_PP2_TXP_MTU_ALL_MASK;
regVal |= MV_PP2_TXP_MTU_MASK(mtu);
mvPp2WrReg(MV_PP2_TXP_SCHED_MTU_REG, regVal);
/* TXP token size and all TXQs token size must be larger that MTU */
regVal = mvPp2RdReg(MV_PP2_TXP_SCHED_TOKEN_SIZE_REG);
size = regVal & MV_PP2_TXP_TOKEN_SIZE_MAX;
if (size < mtu) {
size = mtu;
regVal &= ~MV_PP2_TXP_TOKEN_SIZE_MAX;
regVal |= size;
mvPp2WrReg(MV_PP2_TXP_SCHED_TOKEN_SIZE_REG, regVal);
}
for (txq = 0; txq < CONFIG_MV_PP2_TXQ; txq++) {
regVal = mvPp2RdReg(MV_PP2_TXQ_SCHED_TOKEN_SIZE_REG(txq));
size = regVal & MV_PP2_TXQ_TOKEN_SIZE_MAX;
if (size < mtu) {
size = mtu;
regVal &= ~MV_PP2_TXQ_TOKEN_SIZE_MAX;
regVal |= size;
mvPp2WrReg(MV_PP2_TXQ_SCHED_TOKEN_SIZE_REG(txq), regVal);
}
}
return MV_OK;
}
/* Disable transmit via physical egress queue - HW doesn't take descriptors from DRAM */
MV_STATUS mvPp2TxpDisable(int port, int txp)
{
MV_U32 regData;
int mDelay;
int txPortNum = mvPp2EgressPort(port, txp);
/* Issue stop command for active channels only */
mvPp2WrReg(MV_PP2_TXP_SCHED_PORT_INDEX_REG, txPortNum);
regData = (mvPp2RdReg(MV_PP2_TXP_SCHED_Q_CMD_REG)) & MV_PP2_TXP_SCHED_ENQ_MASK;
if (regData != 0)
mvPp2WrReg(MV_PP2_TXP_SCHED_Q_CMD_REG, (regData << MV_PP2_TXP_SCHED_DISQ_OFFSET));
/* Wait for all Tx activity to terminate. */
/* for PON, do not wait for TXQ, since for Functional Erratum FE-8309479, PON TXQ could only be flushed
for Ethernet port, not PON port, so TXQ will never be stopped */
if (MV_PP2_IS_PON_PORT(port))
return MV_OK;
mDelay = 0;
do {
if (mDelay >= TX_DISABLE_TIMEOUT_MSEC) {
mvOsPrintf("port=%d, txp=%d: TIMEOUT for TX stopped !!! txQueueCmd - 0x%08x\n",
port, txp, regData);
return MV_TIMEOUT;
}
mvOsDelay(1);
mDelay++;
/* Check port TX Command register that all Tx queues are stopped */
regData = mvPp2RdReg(MV_PP2_TXP_SCHED_Q_CMD_REG);
} while (regData & MV_PP2_TXP_SCHED_ENQ_MASK);
return MV_OK;
}
/* Enable transmit via physical egress queue - HW starts take descriptors from DRAM */
MV_STATUS mvPp2TxpEnable(int port, int txp)
{
MV_PP2_PORT_CTRL *pPortCtrl = mvPp2PortHndlGet(port);
MV_U32 qMap;
int txq, eport = mvPp2EgressPort(port, txp);
/* Enable all initialized TXs. */
qMap = 0;
for (txq = 0; txq < pPortCtrl->txqNum; txq++) {
if (pPortCtrl->pTxQueue[txp * CONFIG_MV_PP2_TXQ + txq] != NULL)
qMap |= (1 << txq);
}
/* Indirect access to register */
mvPp2WrReg(MV_PP2_TXP_SCHED_PORT_INDEX_REG, eport);
mvPp2WrReg(MV_PP2_TXP_SCHED_Q_CMD_REG, qMap);
return MV_OK;
}
/* Functions implemented only for PPv2.1 version (A0 and later) */
MV_STATUS mvPp2RxqEnable(int port, int rxq, MV_BOOL en)
{
MV_U32 regVal;
int prxq = mvPp2LogicRxqToPhysRxq(port, rxq);
regVal = mvPp2RdReg(MV_PP2_RXQ_CONFIG_REG(prxq));
if (en)
regVal &= ~MV_PP2_RXQ_DISABLE_MASK;
else
regVal |= MV_PP2_RXQ_DISABLE_MASK;
mvPp2WrReg(MV_PP2_RXQ_CONFIG_REG(prxq), regVal);
return MV_OK;
}
MV_STATUS mvPp2HwfTxqEnable(int port, int txp, int txq, MV_BOOL en)
{
MV_U32 regVal;
int ptxq = MV_PPV2_TXQ_PHYS(port, txp, txq);
regVal = mvPp2RdReg(MV_PP2_HWF_TXQ_CONFIG_REG(ptxq));
if (en)
regVal &= ~MV_PP2_HWF_TXQ_DISABLE_MASK;
else
regVal |= MV_PP2_HWF_TXQ_DISABLE_MASK;
mvPp2WrReg(MV_PP2_HWF_TXQ_CONFIG_REG(ptxq), regVal);
return MV_OK;
}
MV_BOOL mvPp2DisableCmdInProgress(void)
{
MV_U32 regVal;
regVal = mvPp2RdReg(MV_PP2_RX_STATUS);
regVal &= MV_PP2_DISABLE_IN_PROG_MASK;
return regVal;
}
MV_STATUS mvPp2TxqDrainSet(int port, int txp, int txq, MV_BOOL en)
{
MV_U32 regVal;
int ptxq = MV_PPV2_TXQ_PHYS(port, txp, txq);
mvPp2WrReg(MV_PP2_TXQ_NUM_REG, ptxq);
regVal = mvPp2RdReg(MV_PP2_TXQ_PREF_BUF_REG);
if (en)
regVal |= MV_PP2_HWF_TXQ_DISABLE_MASK;
else
regVal &= ~MV_PP2_HWF_TXQ_DISABLE_MASK;
mvPp2WrReg(MV_PP2_TXQ_PREF_BUF_REG, regVal);
return MV_OK;
}
MV_STATUS mvPp2TxPortFifoFlush(int port, MV_BOOL en)
{
MV_U32 regVal;
/* valid only for ethernet ports (not for xPON) */
if (MV_PP2_IS_PON_PORT(port))
return MV_NOT_SUPPORTED;
regVal = mvPp2RdReg(MV_PP2_TX_PORT_FLUSH_REG);
if (en)
regVal |= MV_PP2_TX_PORT_FLUSH_MASK(port);
else
regVal &= ~MV_PP2_TX_PORT_FLUSH_MASK(port);
mvPp2WrReg(MV_PP2_TX_PORT_FLUSH_REG, regVal);
return MV_OK;
}
/* Function for swithcing SWF to HWF */
/* txq is physical (global) txq in range 0..MV_PP2_TXQ_TOTAL_NUM */
/* txq is physical (global) rxq in range 0..MV_PP2_RXQ_TOTAL_NUM */
MV_STATUS mvPp2FwdSwitchCtrl(MV_U32 flowId, int txq, int rxq, int msec)
{
MV_U32 regVal;
int timeout, max;
/* Check validity of parameters */
if (mvPp2MaxCheck(txq, MV_PP2_TXQ_TOTAL_NUM, "global txq"))
return MV_BAD_PARAM;
if (mvPp2MaxCheck(rxq, MV_PP2_RXQ_TOTAL_NUM, "global rxq"))
return MV_BAD_PARAM;
timeout = MV_PP2_FWD_SWITCH_TIMEOUT_MAX * 1024;
max = timeout / (mvPp2HalData.tClk / 1000);
if (mvPp2MaxCheck(msec, max + 1, "timeout msec"))
return MV_BAD_PARAM;
mvPp2WrReg(MV_PP2_FWD_SWITCH_FLOW_ID_REG, flowId);
timeout = ((mvPp2HalData.tClk / 1000) * msec) / 1024;
regVal = MV_PP2_FWD_SWITCH_TXQ_VAL(txq) | MV_PP2_FWD_SWITCH_RXQ_VAL(rxq) |
MV_PP2_FWD_SWITCH_TIMEOUT_VAL(timeout);
mvPp2WrReg(MV_PP2_FWD_SWITCH_CTRL_REG, regVal);
return MV_OK;
}
int mvPp2FwdSwitchStatus(int *hwState, int *msec)
{
MV_U32 regVal, cycles;
regVal = mvPp2RdReg(MV_PP2_FWD_SWITCH_STATUS_REG);
if (hwState)
*hwState = (regVal & MV_PP2_FWD_SWITCH_STATE_MASK) >> MV_PP2_FWD_SWITCH_STATE_OFFS;
cycles = (regVal & MV_PP2_FWD_SWITCH_TIMER_MASK) >> MV_PP2_FWD_SWITCH_TIMER_OFFS;
cycles *= 1024;
if (msec)
*msec = cycles / (mvPp2HalData.tClk / 1000);
return (regVal & MV_PP2_FWD_SWITCH_STATUS_MASK) >> MV_PP2_FWD_SWITCH_STATUS_OFFS;
}