blob: 983333bcce12eee34aa82fb7c509c00f4b25cbab [file] [log] [blame]
#include <Copyright.h>
/*******************************************************************************
* gtBrgStu.c
*
* DESCRIPTION:
* API definitions for SID (VTU 802.1s Port State Information Database)
* Translation Unit.
*
* DEPENDENCIES:
*
* FILE REVISION NUMBER:
* $Revision: $
*******************************************************************************/
#include <msApi.h>
#include <gtSem.h>
#include <gtHwCntl.h>
#include <gtDrvSwRegs.h>
/****************************************************************************/
/* Forward function declaration. */
/****************************************************************************/
static GT_STATUS stuOperationPerform
(
IN GT_QD_DEV *dev,
IN GT_STU_OPERATION stuOp,
INOUT GT_U8 *valid,
INOUT GT_STU_ENTRY *stuEntry
);
/*******************************************************************************
* gstuGetEntryCount
*
* DESCRIPTION:
* Gets the current number of valid entries in the STU table
*
* INPUTS:
* None.
*
* OUTPUTS:
* numEntries - number of STU entries.
*
* RETURNS:
* GT_OK - on success
* GT_FAIL - on error
* GT_NOT_SUPPORTED - if current device does not support this feature.
*
* COMMENTS:
* None
*
*******************************************************************************/
GT_STATUS gstuGetEntryCount
(
IN GT_QD_DEV *dev,
OUT GT_U32 *numEntries
)
{
GT_U8 valid;
GT_U32 numOfEntries;
GT_STATUS retVal;
GT_STU_ENTRY entry;
DBG_INFO(("gstuGetEntryCount Called.\n"));
/* check if device supports this feature */
if (!IS_IN_DEV_GROUP(dev,DEV_802_1S_STU))
{
DBG_INFO(("GT_NOT_SUPPORTED\n"));
return GT_NOT_SUPPORTED;
}
entry.sid = 0;
numOfEntries = 0;
while(1)
{
retVal = stuOperationPerform(dev,GET_NEXT_STU_ENTRY,&valid,&entry);
if(retVal != GT_OK)
{
DBG_INFO(("Failed (stuOperationPerform returned GT_FAIL).\n"));
return retVal;
}
if( entry.sid==0x3F )
{
if (valid==1) numOfEntries++;
break;
}
numOfEntries++;
}
*numEntries = numOfEntries;
DBG_INFO(("OK.\n"));
return GT_OK;
}
/*******************************************************************************
* gstuGetEntryFirst
*
* DESCRIPTION:
* Gets first lexicographic entry from the STU.
*
* INPUTS:
* None.
*
* OUTPUTS:
* stuEntry - find the first valid STU entry.
*
* RETURNS:
* GT_OK - on success
* GT_FAIL - on error
* GT_NO_SUCH - table is empty.
* GT_NOT_SUPPORTED - if current device does not support this feature.
*
* COMMENTS:
*
*******************************************************************************/
GT_STATUS gstuGetEntryFirst
(
IN GT_QD_DEV *dev,
OUT GT_STU_ENTRY *stuEntry
)
{
GT_U8 valid;
GT_STATUS retVal;
GT_U8 port;
GT_LPORT lport;
GT_STU_ENTRY entry;
DBG_INFO(("gstuGetEntryFirst Called.\n"));
/* check if device supports this feature */
if (!IS_IN_DEV_GROUP(dev,DEV_802_1S_STU))
{
DBG_INFO(("GT_NOT_SUPPORTED\n"));
return GT_NOT_SUPPORTED;
}
entry.sid = 0;
valid = 0;
retVal = stuOperationPerform(dev,GET_NEXT_STU_ENTRY,&valid, &entry);
if(retVal != GT_OK)
{
DBG_INFO(("Failed (stuOperationPerform returned GT_FAIL).\n"));
return retVal;
}
/* retrieve the value from the operation */
if((entry.sid == 0x3F) && (valid == 0))
return GT_NO_SUCH;
stuEntry->sid = entry.sid;
for(lport=0; lport<dev->numOfPorts; lport++)
{
port = GT_LPORT_2_PORT(lport);
stuEntry->portState[lport]=entry.portState[port];
}
DBG_INFO(("OK.\n"));
return GT_OK;
}
/*******************************************************************************
* gstuGetEntryNext
*
* DESCRIPTION:
* Gets next lexicographic STU entry from the specified SID.
*
* INPUTS:
* stuEntry - the SID to start the search.
*
* OUTPUTS:
* stuEntry - next STU entry.
*
* RETURNS:
* GT_OK - on success.
* GT_FAIL - on error or entry does not exist.
* GT_NO_SUCH - no more entries.
* GT_NOT_SUPPORTED - if current device does not support this feature.
*
* COMMENTS:
*
*******************************************************************************/
GT_STATUS gstuGetEntryNext
(
IN GT_QD_DEV *dev,
INOUT GT_STU_ENTRY *stuEntry
)
{
GT_U8 valid;
GT_STATUS retVal;
GT_U8 port;
GT_LPORT lport;
GT_STU_ENTRY entry;
DBG_INFO(("gstuGetEntryNext Called.\n"));
/* check if device supports this feature */
if (!IS_IN_DEV_GROUP(dev,DEV_802_1S_STU))
{
DBG_INFO(("GT_NOT_SUPPORTED\n"));
return GT_NOT_SUPPORTED;
}
if(stuEntry->sid >= 0x3F)
{
return GT_NO_SUCH;
}
else
{
entry.sid = stuEntry->sid;
}
valid = 0;
retVal = stuOperationPerform(dev,GET_NEXT_STU_ENTRY,&valid, &entry);
if(retVal != GT_OK)
{
DBG_INFO(("Failed (stuOperationPerform returned GT_FAIL).\n"));
return retVal;
}
/* retrieve the value from the operation */
if((entry.sid == 0x3F) && (valid == 0))
return GT_NO_SUCH;
stuEntry->sid = entry.sid;
for(lport=0; lport<dev->numOfPorts; lport++)
{
port = GT_LPORT_2_PORT(lport);
stuEntry->portState[lport]=entry.portState[port];
}
DBG_INFO(("OK.\n"));
return GT_OK;
}
/*******************************************************************************
* gstuFindSidEntry
*
* DESCRIPTION:
* Find STU entry for a specific SID, it will return the entry, if found,
* along with its associated data
*
* INPUTS:
* stuEntry - contains the SID to searche for
*
* OUTPUTS:
* found - GT_TRUE, if the appropriate entry exists.
* stuEntry - the entry parameters.
*
* RETURNS:
* GT_OK - on success.
* GT_FAIL - on error or entry does not exist.
* GT_NO_SUCH - no such entry.
* GT_NOT_SUPPORTED - if current device does not support this feature.
*
* COMMENTS:
* Valid SID is 1 ~ 63.
*
*******************************************************************************/
GT_STATUS gstuFindSidEntry
(
IN GT_QD_DEV *dev,
INOUT GT_STU_ENTRY *stuEntry,
OUT GT_BOOL *found
)
{
GT_U8 valid;
GT_STATUS retVal;
GT_U8 port;
GT_LPORT lport;
GT_STU_ENTRY entry;
DBG_INFO(("gstuFindSidEntry Called.\n"));
/* check if device supports this feature */
if (!IS_IN_DEV_GROUP(dev,DEV_802_1S_STU))
{
DBG_INFO(("GT_NOT_SUPPORTED\n"));
return GT_NOT_SUPPORTED;
}
if((stuEntry->sid == 0) || (stuEntry->sid > 0x3F))
{
DBG_INFO(("GT_BAD_PARAM\n"));
return GT_BAD_PARAM;
}
*found = GT_FALSE;
/* Decrement 1 from sid */
entry.sid = stuEntry->sid-1;
valid = 0; /* valid is not used as input in this operation */
retVal = stuOperationPerform(dev,GET_NEXT_STU_ENTRY,&valid, &entry);
if(retVal != GT_OK)
{
DBG_INFO(("Failed (stuOperationPerform returned GT_FAIL).\n"));
return retVal;
}
/* retrive the value from the operation */
if ((entry.sid != stuEntry->sid) | (valid == 0))
return GT_NO_SUCH;
for(lport=0; lport<dev->numOfPorts; lport++)
{
port = GT_LPORT_2_PORT(lport);
stuEntry->portState[lport]=entry.portState[port];
}
*found = GT_TRUE;
DBG_INFO(("OK.\n"));
return GT_OK;
}
/*******************************************************************************
* gstuAddEntry
*
* DESCRIPTION:
* Creates or update the entry in STU table based on user input.
*
* INPUTS:
* stuEntry - stu entry to insert to the STU.
*
* OUTPUTS:
* None
*
* RETURNS:
* GT_OK - on success
* GT_FAIL - on error
* GT_NOT_SUPPORTED - if current device does not support this feature.
*
* COMMENTS:
* Valid SID is 1 ~ 63.
*
*******************************************************************************/
GT_STATUS gstuAddEntry
(
IN GT_QD_DEV *dev,
IN GT_STU_ENTRY *stuEntry
)
{
GT_U8 valid;
GT_STATUS retVal;
GT_U8 port;
GT_LPORT lport;
GT_STU_ENTRY tmpStuEntry;
GT_BOOL found;
int count = 50000;
GT_STU_ENTRY entry;
DBG_INFO(("gstuAddEntry Called.\n"));
/* check if device supports this feature */
if (!IS_IN_DEV_GROUP(dev,DEV_802_1S_STU))
{
DBG_INFO(("GT_NOT_SUPPORTED\n"));
return GT_NOT_SUPPORTED;
}
if((stuEntry->sid == 0) || (stuEntry->sid > 0x3F))
{
DBG_INFO(("GT_BAD_PARAM\n"));
return GT_BAD_PARAM;
}
entry.sid = stuEntry->sid;
valid = 1; /* for load operation */
for(port=0; port<dev->maxPorts; port++)
{
lport = GT_PORT_2_LPORT(port);
if (lport == GT_INVALID_PORT)
entry.portState[port] = 0;
else
entry.portState[port] = stuEntry->portState[lport];
}
retVal = stuOperationPerform(dev,LOAD_PURGE_STU_ENTRY,&valid, &entry);
if(retVal != GT_OK)
{
DBG_INFO(("Failed (stuOperationPerform returned GT_FAIL).\n"));
return retVal;
}
/* verify that the given entry has been added */
tmpStuEntry.sid = stuEntry->sid;
if((retVal = gstuFindSidEntry(dev,&tmpStuEntry,&found)) != GT_OK)
{
while(count--);
if((retVal = gstuFindSidEntry(dev,&tmpStuEntry,&found)) != GT_OK)
{
DBG_INFO(("Added entry cannot be found\n"));
return retVal;
}
}
if(found == GT_FALSE)
{
DBG_INFO(("Added entry cannot be found\n"));
return GT_FAIL;
}
DBG_INFO(("OK.\n"));
return GT_OK;
}
/*******************************************************************************
* gstuDelEntry
*
* DESCRIPTION:
* Deletes STU entry specified by user.
*
* INPUTS:
* stuEntry - the STU entry to be deleted
*
* OUTPUTS:
* None.
*
* RETURNS:
* GT_OK - on success
* GT_FAIL - on error
* GT_NOT_SUPPORTED - if current device does not support this feature.
*
* COMMENTS:
* Valid SID is 1 ~ 63.
*
*******************************************************************************/
GT_STATUS gstuDelEntry
(
IN GT_QD_DEV *dev,
IN GT_STU_ENTRY *stuEntry
)
{
GT_U8 valid;
GT_STATUS retVal;
GT_STU_ENTRY entry;
DBG_INFO(("gstuDelEntry Called.\n"));
/* check if device supports this feature */
if (!IS_IN_DEV_GROUP(dev,DEV_802_1S_STU))
{
DBG_INFO(("GT_NOT_SUPPORTED\n"));
return GT_NOT_SUPPORTED;
}
if((stuEntry->sid == 0) || (stuEntry->sid > 0x3F))
{
DBG_INFO(("GT_BAD_PARAM\n"));
return GT_BAD_PARAM;
}
entry.sid = stuEntry->sid;
valid = 0; /* for delete operation */
retVal = stuOperationPerform(dev,LOAD_PURGE_STU_ENTRY,&valid, &entry);
if(retVal != GT_OK)
{
DBG_INFO(("Failed (stuOperationPerform returned GT_FAIL).\n"));
return retVal;
}
DBG_INFO(("OK.\n"));
return GT_OK;
}
/****************************************************************************/
/* Internal use functions. */
/****************************************************************************/
static GT_STATUS stuSetSTUData
(
IN GT_QD_DEV *dev,
IN GT_STU_ENTRY *entry
)
{
GT_STATUS retVal; /* Functions return value. */
GT_U16 data1,data2,data3; /* Data to be set into the */
GT_U16 nStuData = 0;
data1 = data2 = data3 = 0;
switch (dev->maxPorts)
{
case 11:
data3 |= (entry->portState[10] & 3) << 10;
/* pass through */
case 10:
data3 |= (entry->portState[9] & 3) << 6;
/* pass through */
case 9:
data3 |= (entry->portState[8] & 3) << 2;
nStuData++;
/* pass through */
case 8:
data2 |= (entry->portState[7] & 3) << 14;
/* pass through */
case 7:
data2 |= (entry->portState[6] & 3) << 10;
/* pass through */
case 6:
data2 |= (entry->portState[5] & 3) << 6;
/* pass through */
case 5:
data2 |= (entry->portState[4] & 3) << 2;
nStuData++;
/* pass through */
case 4:
data1 |= (entry->portState[3] & 3) << 14;
/* pass through */
case 3:
data1 |= (entry->portState[2] & 3) << 10;
/* pass through */
case 2:
data1 |= (entry->portState[1] & 3) << 6;
/* pass through */
case 1:
data1 |= (entry->portState[0] & 3) << 2;
nStuData++;
break;
default:
return GT_FAIL;
}
switch(nStuData)
{
case 3:
retVal = hwWriteGlobalReg(dev,QD_REG_VTU_DATA3_REG,data3);
if(retVal != GT_OK)
{
return retVal;
}
/* pass through */
case 2:
retVal = hwWriteGlobalReg(dev,QD_REG_VTU_DATA2_REG,data2);
if(retVal != GT_OK)
{
return retVal;
}
/* pass through */
case 1:
retVal = hwWriteGlobalReg(dev,QD_REG_VTU_DATA1_REG,data1);
if(retVal != GT_OK)
{
return retVal;
}
break;
default:
return GT_FAIL;
}
return retVal;
}
static GT_STATUS stuGetSTUData
(
IN GT_QD_DEV *dev,
OUT GT_STU_ENTRY *entry
)
{
GT_STATUS retVal; /* Functions return value. */
GT_U16 data1,data2,data3; /* Data to be set into the */
GT_U16 nStuData = 0;
data1 = data2 = data3 = 0;
gtMemSet((void*)entry->portState,0,sizeof(entry->portState));
switch (dev->maxPorts)
{
case 11:
case 10:
case 9:
nStuData = 3;
break;
case 8:
case 7:
case 6:
case 5:
nStuData = 2;
break;
case 4:
case 3:
case 2:
case 1:
nStuData = 1;
break;
default:
return GT_FAIL;
}
switch(nStuData)
{
case 3:
retVal = hwReadGlobalReg(dev,QD_REG_VTU_DATA3_REG,&data3);
if(retVal != GT_OK)
{
return retVal;
}
/* pass through */
case 2:
retVal = hwReadGlobalReg(dev,QD_REG_VTU_DATA2_REG,&data2);
if(retVal != GT_OK)
{
return retVal;
}
/* pass through */
case 1:
retVal = hwReadGlobalReg(dev,QD_REG_VTU_DATA1_REG,&data1);
if(retVal != GT_OK)
{
return retVal;
}
break;
default:
return GT_FAIL;
}
switch (dev->maxPorts)
{
case 11:
entry->portState[10] = (data3 >> 10) & 3 ;
/* pass through */
case 10:
entry->portState[9] = (data3 >> 6) & 3 ;
/* pass through */
case 9:
entry->portState[8] = (data3 >> 2) & 3 ;
/* pass through */
case 8:
entry->portState[7] = (data2 >> 14) & 3 ;
/* pass through */
case 7:
entry->portState[6] = (data2 >> 10) & 3 ;
/* pass through */
case 6:
entry->portState[5] = (data2 >> 6) & 3 ;
/* pass through */
case 5:
entry->portState[4] = (data2 >> 2) & 3 ;
/* pass through */
case 4:
entry->portState[3] = (data1 >> 14) & 3 ;
/* pass through */
case 3:
entry->portState[2] = (data1 >> 10) & 3 ;
/* pass through */
case 2:
entry->portState[1] = (data1 >> 6) & 3 ;
/* pass through */
case 1:
entry->portState[0] = (data1 >> 2) & 3 ;
break;
default:
return GT_FAIL;
}
return GT_OK;
}
/*******************************************************************************
* stuOperationPerform
*
* DESCRIPTION:
* This function is used by all STU control functions, and is responsible
* to write the required operation into the STU registers.
*
* INPUTS:
* stuOp - The STU operation bits to be written into the STU
* operation register.
* sid - sid
* valid - valid bit
* stuData - STU Data with port state information
*
* OUTPUTS:
* sid - sid
* valid - valid bit
* stuData - STU Data with port state information
*
* RETURNS:
* GT_OK on success,
* GT_FAIL otherwise.
*
* COMMENTS:
*
*******************************************************************************/
static GT_STATUS stuOperationPerform
(
IN GT_QD_DEV *dev,
IN GT_STU_OPERATION stuOp,
INOUT GT_U8 *valid,
INOUT GT_STU_ENTRY *entry
)
{
GT_STATUS retVal; /* Functions return value. */
GT_U16 data; /* Data to be set into the */
/* register. */
gtSemTake(dev,dev->vtuRegsSem,OS_WAIT_FOREVER);
/* Wait until the VTU in ready. */
data = 1;
while(data == 1)
{
retVal = hwGetGlobalRegField(dev,QD_REG_VTU_OPERATION,15,1,&data);
if(retVal != GT_OK)
{
gtSemGive(dev,dev->vtuRegsSem);
return retVal;
}
}
/* Set the VTU data register if Load operation is required. */
if (stuOp == LOAD_PURGE_STU_ENTRY)
{
if (*valid == 1)
{
/* set the Port State for all the ports */
retVal = stuSetSTUData(dev,entry);
if(retVal != GT_OK)
{
gtSemGive(dev,dev->vtuRegsSem);
return retVal;
}
/* Set the valid bit (QD_REG_VTU_VID_REG) */
data= *valid << 12 ;
retVal = hwWriteGlobalReg(dev,(GT_U8)(QD_REG_VTU_VID_REG),data);
if(retVal != GT_OK)
{
gtSemGive(dev,dev->vtuRegsSem);
return retVal;
}
}
else
{
/* Clear the valid bit (QD_REG_VTU_VID_REG) */
data= 0 ;
retVal = hwWriteGlobalReg(dev,(GT_U8)(QD_REG_VTU_VID_REG),data);
if(retVal != GT_OK)
{
gtSemGive(dev,dev->vtuRegsSem);
return retVal;
}
}
}
/* Set the SID register (QD_REG_STU_SID_REG) */
data= (entry->sid) & 0x3F;
retVal = hwWriteGlobalReg(dev,(GT_U8)(QD_REG_STU_SID_REG),data);
if(retVal != GT_OK)
{
gtSemGive(dev,dev->vtuRegsSem);
return retVal;
}
/* Start the STU Operation by defining the stuOp and VTUBusy */
data = (1 << 15) | (stuOp << 12);
retVal = hwWriteGlobalReg(dev,QD_REG_VTU_OPERATION,data);
if(retVal != GT_OK)
{
gtSemGive(dev,dev->vtuRegsSem);
return retVal;
}
/* If the operation is a get next operation wait for the response */
if(stuOp == GET_NEXT_STU_ENTRY)
{
/* Wait until the STU in ready. */
data = 1;
while(data == 1)
{
retVal = hwGetGlobalRegField(dev,QD_REG_VTU_OPERATION,15,1,&data);
if(retVal != GT_OK)
{
gtSemGive(dev,dev->vtuRegsSem);
return retVal;
}
}
/****************** get the valid bit *******************/
retVal = hwGetGlobalRegField(dev,QD_REG_VTU_VID_REG,12,1,&data);
if(retVal != GT_OK)
{
gtSemGive(dev,dev->vtuRegsSem);
return retVal;
}
*valid = (GT_U8)data;
/****************** get the sid *******************/
retVal = hwReadGlobalReg(dev,QD_REG_STU_SID_REG,&data);
if(retVal != GT_OK)
{
gtSemGive(dev,dev->vtuRegsSem);
return retVal;
}
/* the sid is bits 0-5 */
entry->sid = data & 0x3F;
if (*valid)
{
/* get the Port State for all the ports */
retVal = stuGetSTUData(dev,entry);
if(retVal != GT_OK)
{
gtSemGive(dev,dev->vtuRegsSem);
return retVal;
}
} /* entry is valid */
} /* end of get next entry */
gtSemGive(dev,dev->vtuRegsSem);
return GT_OK;
}