blob: 557df5f1c8c36a7487763bf1e6bb45be60d9caac [file] [log] [blame]
#include <Copyright.h>
/********************************************************************************
* qdSim.c
*
* DESCRIPTION:
* Simulate QuaterDeck Device(88E6052)'s register map. When QuareterDeck API
* try to read/write a bit or bits into QuaterDeck, the simulator will redirect to
* its own memory place and performing the function very close to QuaterDeck.
* For example,
* 1) user can set/reset a certain bit of QuarterDeck registers(Phy,Port,and General registers).
* 2) user can access ATU (flush, load, purge, etc. with max MAC addresses of 32)
* 3) user can manually generate an Interrupt and test the Interrupt routine.
* 4) when user read a register, it will clear a certain register if it's a Self Clear register.
* 5) when user write a register, it will return ERROR if it's read only register.
*
*
* DEPENDENCIES: QuaterDeck (88E6052) Register MAP.
*
* FILE REVISION NUMBER:
*
*******************************************************************************/
#include <msApi.h>
#include <qdSimRegs.h>
#define IS_BROADCAST_ADDR(_addr) \
(((_addr)[0] == 0xFF) && ((_addr)[1] == 0xFF) && \
((_addr)[2] == 0xFF) && ((_addr)[3] == 0xFF) && \
((_addr)[4] == 0xFF) && ((_addr)[5] == 0xFF))
#define IS_GLOBAL_REG(_port) ((int)(_port) == qdSimDev.qdSimGlobalRegBase)
#define IS_PORT_REG(_port) (((int)(_port) >= qdSimDev.qdSimPortBase) && ((int)(_port) < qdSimDev.qdSimPortBase + qdSimDev.qdSimNumOfPorts))
#define IS_PHY_REG(_port) (((int)(_port) >= qdSimDev.qdSimPhyBase) && ((int)(_port) < qdSimDev.qdSimPhyBase + qdSimDev.qdSimNumOfPhys))
typedef struct _QD_SIM_DEV
{
int qdSimUsed;
unsigned int qdSimDevId;
int qdSimNumOfPorts;
int qdSimPortBase;
int qdSimNumOfPhys;
int qdSimPhyBase;
int qdSimGlobalRegBase;
int qdSimPortStatsClear[10];
int qdSimStatsCapturedPort;
int vtuSize;
int atuSize;
} QD_SIM_DEV;
static QD_SIM_DEV qdSimDev = {0};
void qdSimRegsInit();
GT_BOOL qdSimRead (GT_QD_DEV *dev, unsigned int portNumber , unsigned int miiReg, unsigned int* value);
GT_BOOL qdSimWrite(GT_QD_DEV *dev, unsigned int portNumber , unsigned int miiReg, unsigned int value);
/*
* This Array will simulate the QuarterDeck Registers.
* To use it, qdSimRegs has to be initialized with its default values and
* Call qdSimRead and qdSimWrite functions.
*/
#define MAX_SMI_ADDRESS 0x20
#define MAX_REG_ADDRESS 0x20
#define MAX_ATU_ADDRESS 0x800
#define MAX_QD_VTU_ENTRIES 0x40
GT_U16 qdSimRegs[MAX_SMI_ADDRESS][MAX_REG_ADDRESS];
typedef struct _QDSIM_ATU_ENTRY
{
GT_U16 atuData;
GT_U16 DBNum;
GT_U8 atuMac[6];
} QDSIM_ATU_ENTRY;
/*
Since QuarterDeck Simulator supports only fixed size of atu entry,
we are going with array list not dynamic linked list.
*/
typedef struct _QDSIM_ATU_NODE
{
QDSIM_ATU_ENTRY atuEntry;
GT_U32 nextEntry;
} QDSIM_ATU_NODE;
typedef struct _QDSIM_ATU_LIST
{
int atuSize;
GT_U32 head;
} QDSIM_ATU_LIST;
QDSIM_ATU_NODE ATUNode[MAX_ATU_ADDRESS];
QDSIM_ATU_LIST ATUList;
typedef struct _QDSIM_VTU_ENTRY
{
GT_U16 DBNum;
GT_U16 memberTag[10];
GT_U16 vid;
} QDSIM_VTU_ENTRY;
/*
Since QuarterDeck Simulator supports only fixed size of atu entry,
we are going with array list not dynamic linked list.
*/
typedef struct _QDSIM_VTU_NODE
{
QDSIM_VTU_ENTRY vtuEntry;
GT_U32 nextEntry;
} QDSIM_VTU_NODE;
typedef struct _QDSIM_VTU_LIST
{
int vtuSize;
GT_U32 head;
} QDSIM_VTU_LIST;
QDSIM_VTU_NODE VTUNode[MAX_QD_VTU_ENTRIES];
QDSIM_VTU_LIST VTUList;
/*******************************************************************************
* qdMemSet
*
* DESCRIPTION:
* Set a block of memory
*
* INPUTS:
* start - start address of memory block for setting
* simbol - character to store, converted to an unsigned char
* size - size of block to be set
*
* OUTPUTS:
* None
*
* RETURNS:
* Pointer to set memory block
*
* COMMENTS:
* None
*
*******************************************************************************/
void * qdMemSet
(
IN void * start,
IN int symbol,
IN GT_U32 size
)
{
GT_U32 i;
char* buf;
buf = (char*)start;
for(i=0; i<size; i++)
{
*buf++ = (char)symbol;
}
return start;
}
/*******************************************************************************
* qdMemCpy
*
* DESCRIPTION:
* Copies 'size' characters from the object pointed to by 'source' into
* the object pointed to by 'destination'. If copying takes place between
* objects that overlap, the behavior is undefined.
*
* INPUTS:
* destination - destination of copy
* source - source of copy
* size - size of memory to copy
*
* OUTPUTS:
* None
*
* RETURNS:
* Pointer to destination
*
* COMMENTS:
* None
*
*******************************************************************************/
void * qdMemCpy
(
IN void * destination,
IN const void * source,
IN GT_U32 size
)
{
GT_U32 i;
char* buf;
char* src;
buf = (char*)destination;
src = (char*)source;
for(i=0; i<size; i++)
{
*buf++ = *src++;
}
return destination;
}
/*******************************************************************************
* qdMemCmp
*
* DESCRIPTION:
* Compares given memories.
*
* INPUTS:
* src1 - source 1
* src2 - source 2
* size - size of memory to copy
*
* OUTPUTS:
* None
*
* RETURNS:
* 0, if equal.
* negative number, if src1 < src2.
* positive number, if src1 > src2.
*
* COMMENTS:
* None
*
*******************************************************************************/
int qdMemCmp
(
IN char src1[],
IN char src2[],
IN GT_U32 size
)
{
GT_U32 i;
int value;
for(i=0; i<size; i++)
{
if((value = (int)(src1[i] - src2[i])) != 0)
return value;
}
return 0;
}
/*
Compare the given ethernet addresses.
0, if they are equal.
Negative int, if mac2 is bigger than mac1.
Positive int, if mac1 is bigger than mac2.
*/
int cmpEtherMac(unsigned char* mac1, unsigned char* mac2)
{
int i, tmp;
for(i=0; i<6; i++)
{
if((tmp = mac1[i] - mac2[i]) != 0)
return tmp;
}
return 0;
}
/*
entry index, if found.
MAX_ATU_ADDRESS, otherwise.
*/
int qdSimATUFindNext(QDSIM_ATU_ENTRY* entry)
{
int i;
int node = ATUList.head;
if (IS_BROADCAST_ADDR(entry->atuMac))
{
if(ATUList.atuSize != 0)
{
if (ATUNode[node].atuEntry.DBNum == entry->DBNum)
return node;
else
{
for(i=0; i<ATUList.atuSize; i++)
{
if(ATUNode[node].atuEntry.DBNum == entry->DBNum)
return node;
node = ATUNode[node].nextEntry;
}
}
}
return MAX_ATU_ADDRESS;
}
for(i=0; i<ATUList.atuSize; i++)
{
if(cmpEtherMac(ATUNode[node].atuEntry.atuMac,entry->atuMac) > 0)
{
if(ATUNode[node].atuEntry.DBNum == entry->DBNum)
break;
}
node = ATUNode[node].nextEntry;
}
if (i == ATUList.atuSize)
return MAX_ATU_ADDRESS;
return node;
}
/*
Return 1, if added successfully.
Return 0, otherwise.
*/
GT_BOOL qdSimATUAdd(QDSIM_ATU_ENTRY* entry)
{
int i, freeNode, preNode, node;
preNode = node = ATUList.head;
if (ATUList.atuSize >= MAX_ATU_ADDRESS)
return GT_FALSE;
/* find a free entry from our global memory. */
for(i=0; i<MAX_ATU_ADDRESS; i++)
{
if(ATUNode[i].nextEntry == MAX_ATU_ADDRESS)
break;
}
if (i==MAX_ATU_ADDRESS)
{
return GT_FALSE;
}
freeNode = i;
/* find the smallest entry which is bigger than the given entry */
for(i=0; i<ATUList.atuSize; i++)
{
if(cmpEtherMac(ATUNode[node].atuEntry.atuMac,entry->atuMac) >= 0)
break;
preNode = node;
node = ATUNode[node].nextEntry;
}
/* if the same Mac address is in the list and dbnum is identical, then just update and return. */
if (i != ATUList.atuSize)
if(cmpEtherMac(ATUNode[node].atuEntry.atuMac,entry->atuMac) == 0)
{
if(ATUNode[node].atuEntry.DBNum == entry->DBNum)
{
ATUNode[node].atuEntry.atuData = entry->atuData;
return GT_TRUE;
}
}
qdMemCpy(ATUNode[freeNode].atuEntry.atuMac, entry->atuMac, 6);
ATUNode[freeNode].atuEntry.atuData = entry->atuData;
ATUNode[freeNode].atuEntry.DBNum = entry->DBNum;
/* Add it to head */
if (i == 0)
{
ATUNode[freeNode].nextEntry = ATUList.head;
ATUList.head = freeNode;
}
/* Add it to tail */
else if (i == ATUList.atuSize)
{
ATUNode[preNode].nextEntry = freeNode;
ATUNode[freeNode].nextEntry = ATUList.head;
}
/* Add it in the middle of the list */
else
{
ATUNode[freeNode].nextEntry = ATUNode[preNode].nextEntry;
ATUNode[preNode].nextEntry = freeNode;
}
ATUList.atuSize++;
return GT_TRUE;
}
/*
Return 1, if added successfully.
Return 0, otherwise.
*/
GT_BOOL qdSimATUDel(QDSIM_ATU_ENTRY* entry)
{
int i, preNode, node;
preNode = node = ATUList.head;
/* find the entry */
for(i=0; i<ATUList.atuSize; i++)
{
if(cmpEtherMac(ATUNode[node].atuEntry.atuMac,entry->atuMac) == 0)
{
if(ATUNode[node].atuEntry.DBNum == entry->DBNum)
break;
}
preNode = node;
node = ATUNode[node].nextEntry;
}
if (i == ATUList.atuSize)
{
/* cannot find the given entry to be deleted. */
return GT_FALSE;
}
/* Delete it from head */
if (i == 0)
{
ATUList.head = ATUNode[node].nextEntry;
}
/* Delete it in the middle of the list */
else if (i != ATUList.atuSize-1)
{
ATUNode[preNode].nextEntry = ATUNode[node].nextEntry;
}
ATUList.atuSize--;
ATUNode[node].nextEntry = MAX_ATU_ADDRESS;
return GT_TRUE;
}
GT_BOOL qdSimATUFlushUnlockedEntry()
{
int i;
for (i=0; i<MAX_ATU_ADDRESS; i++)
{
if(((ATUNode[i].atuEntry.atuData & 0xF) != 0xF) &&
(!(ATUNode[i].atuEntry.atuMac[0] & 1)) &&
(ATUNode[i].nextEntry != MAX_ATU_ADDRESS))
{
qdSimATUDel(&ATUNode[i].atuEntry);
}
}
return GT_TRUE;
}
GT_BOOL qdSimATUFlushInDB(int dbNum)
{
int i;
for (i=0; i<MAX_ATU_ADDRESS; i++)
{
if(ATUNode[i].atuEntry.DBNum != dbNum)
continue;
qdSimATUDel(&ATUNode[i].atuEntry);
}
return GT_TRUE;
}
GT_BOOL qdSimATUFlushUnlockedInDB(int dbNum)
{
int i;
for (i=0; i<MAX_ATU_ADDRESS; i++)
{
if(ATUNode[i].atuEntry.DBNum != dbNum)
continue;
if(((ATUNode[i].atuEntry.atuData & 0xF) != 0xF) &&
(!(ATUNode[i].atuEntry.atuMac[0] & 1)) &&
(ATUNode[i].nextEntry != MAX_ATU_ADDRESS))
{
qdSimATUDel(&ATUNode[i].atuEntry);
}
}
return GT_TRUE;
}
void qdSimATUInit()
{
int i;
qdMemSet((char*)ATUNode, 0, sizeof(ATUNode));
/* MAX_ATU_ADDRESS means entry i is free, otherwise, it's not free */
for (i=0; i<MAX_ATU_ADDRESS; i++)
ATUNode[i].nextEntry = MAX_ATU_ADDRESS;
ATUList.atuSize = 0;
ATUList.head = 0;
}
void qdSimGetATUInfo(QDSIM_ATU_ENTRY* entry)
{
entry->atuData = qdSimRegs[qdSimDev.qdSimGlobalRegBase][12];
entry->atuMac[0] = (qdSimRegs[qdSimDev.qdSimGlobalRegBase][13] >> 8) & 0xFF;
entry->atuMac[1] = qdSimRegs[qdSimDev.qdSimGlobalRegBase][13] & 0xFF;
entry->atuMac[2] = (qdSimRegs[qdSimDev.qdSimGlobalRegBase][14] >> 8) & 0xFF;
entry->atuMac[3] = qdSimRegs[qdSimDev.qdSimGlobalRegBase][14] & 0xFF;
entry->atuMac[4] = (qdSimRegs[qdSimDev.qdSimGlobalRegBase][15] >> 8) & 0xFF;
entry->atuMac[5] = qdSimRegs[qdSimDev.qdSimGlobalRegBase][15] & 0xFF;
entry->DBNum = qdSimRegs[qdSimDev.qdSimGlobalRegBase][11] & 0xF;
return;
}
void qdSimSetATUInfo(QDSIM_ATU_ENTRY* entry)
{
qdSimRegs[qdSimDev.qdSimGlobalRegBase][12] = entry->atuData;
qdSimRegs[qdSimDev.qdSimGlobalRegBase][13] = (entry->atuMac[0]<<8) | entry->atuMac[1];
qdSimRegs[qdSimDev.qdSimGlobalRegBase][14] = (entry->atuMac[2]<<8) | entry->atuMac[3];
qdSimRegs[qdSimDev.qdSimGlobalRegBase][15] = (entry->atuMac[4]<<8) | entry->atuMac[5];
qdSimRegs[qdSimDev.qdSimGlobalRegBase][11] &= ~0xF;
qdSimRegs[qdSimDev.qdSimGlobalRegBase][11] |= (entry->DBNum & 0xF);
return;
}
void qdSimReSetATUInfo()
{
qdSimRegs[qdSimDev.qdSimGlobalRegBase][11] &= ~0xF;
qdSimRegs[qdSimDev.qdSimGlobalRegBase][12] = 0;
qdSimRegs[qdSimDev.qdSimGlobalRegBase][13] = 0xFFFF;
qdSimRegs[qdSimDev.qdSimGlobalRegBase][14] = 0xFFFF;
qdSimRegs[qdSimDev.qdSimGlobalRegBase][15] = 0xFFFF;
return;
}
GT_BOOL qdSimATUOperation(unsigned int value)
{
QDSIM_ATU_ENTRY entry;
int index;
switch((value & 0x7000) >> 12)
{
case 1:
/* Flush ALL */
qdSimATUInit();
break;
case 2:
/* Flush all unlocked entries */
return qdSimATUFlushUnlockedEntry();
case 3:
/* Load or Purge entry */
qdSimGetATUInfo(&entry);
if(entry.atuData & 0xF)
return qdSimATUAdd(&entry);
else
return qdSimATUDel(&entry);
break;
case 4:
/* Get Next Entry */
qdSimGetATUInfo(&entry);
index = qdSimATUFindNext(&entry);
if (index == MAX_ATU_ADDRESS)
{
qdSimReSetATUInfo();
return GT_TRUE;
}
else
{
qdSimSetATUInfo(&ATUNode[index].atuEntry);
return GT_TRUE;
}
break;
case 5:
/* Flush ALL in a DBNum */
return qdSimATUFlushInDB(value & 0xF);
break;
case 6:
/* Flush all unlocked entries */
return qdSimATUFlushUnlockedInDB(value & 0xF);
default:
break;
}
return GT_TRUE;
}
/*
VTU Related Routines
*/
/*
entry index, if found.
MAX_QD_VTU_ENTRIES, otherwise.
*/
int qdSimVTUFindNext(QDSIM_VTU_ENTRY* entry)
{
int i;
int node = VTUList.head;
if (entry->vid == 0xFFF)
{
if(VTUList.vtuSize != 0)
return node;
else
return MAX_QD_VTU_ENTRIES;
}
for(i=0; i<VTUList.vtuSize; i++)
{
if(VTUNode[node].vtuEntry.vid > entry->vid)
break;
node = VTUNode[node].nextEntry;
}
if (i == VTUList.vtuSize)
return MAX_QD_VTU_ENTRIES;
return node;
}
/*
Return 1, if added successfully.
Return 0, otherwise.
*/
GT_BOOL qdSimVTUAdd(QDSIM_VTU_ENTRY* entry)
{
int i, freeNode, preNode, node;
preNode = node = VTUList.head;
if (VTUList.vtuSize >= qdSimDev.vtuSize)
return GT_FALSE;
/* find a free entry from our global memory. */
for(i=0; i<MAX_QD_VTU_ENTRIES; i++)
{
if(VTUNode[i].nextEntry == MAX_QD_VTU_ENTRIES)
break;
}
if (i==MAX_QD_VTU_ENTRIES)
{
return GT_FALSE;
}
freeNode = i;
/* find the smallest entry which is bigger than the given entry */
for(i=0; i<VTUList.vtuSize; i++)
{
if(VTUNode[node].vtuEntry.vid >= entry->vid)
break;
preNode = node;
node = VTUNode[node].nextEntry;
}
/* if the same vid is in the list, then just update and return. */
if (i != VTUList.vtuSize)
if(VTUNode[node].vtuEntry.vid == entry->vid)
{
qdMemCpy(&VTUNode[node].vtuEntry, entry, sizeof(QDSIM_VTU_ENTRY));
return GT_TRUE;
}
qdMemCpy(&VTUNode[freeNode].vtuEntry, entry, sizeof(QDSIM_VTU_ENTRY));
/* Add it to head */
if (i == 0)
{
VTUNode[freeNode].nextEntry = VTUList.head;
VTUList.head = freeNode;
}
/* Add it to tail */
else if (i == VTUList.vtuSize)
{
VTUNode[preNode].nextEntry = freeNode;
VTUNode[freeNode].nextEntry = VTUList.head;
}
/* Add it in the middle of the list */
else
{
VTUNode[freeNode].nextEntry = VTUNode[preNode].nextEntry;
VTUNode[preNode].nextEntry = freeNode;
}
VTUList.vtuSize++;
return GT_TRUE;
}
/*
Return 1, if added successfully.
Return 0, otherwise.
*/
GT_BOOL qdSimVTUDel(QDSIM_VTU_ENTRY* entry)
{
int i, preNode, node;
preNode = node = VTUList.head;
/* find the entry */
for(i=0; i<VTUList.vtuSize; i++)
{
if(VTUNode[node].vtuEntry.vid == entry->vid)
break;
preNode = node;
node = VTUNode[node].nextEntry;
}
if (i == VTUList.vtuSize)
{
/* cannot find the given entry to be deleted. */
return GT_FALSE;
}
/* Delete it from head */
if (i == 0)
{
VTUList.head = VTUNode[node].nextEntry;
}
/* Delete it in the middle of the list */
else if (i != VTUList.vtuSize-1)
{
VTUNode[preNode].nextEntry = VTUNode[node].nextEntry;
}
VTUList.vtuSize--;
VTUNode[node].nextEntry = MAX_QD_VTU_ENTRIES;
return GT_TRUE;
}
/*
Return 1, if added successfully.
Return 0, otherwise.
*/
GT_BOOL qdSimVTUUpdate(QDSIM_VTU_ENTRY* entry)
{
int i;
int node = VTUList.head;
/* find the entry */
for(i=0; i<VTUList.vtuSize; i++)
{
if(VTUNode[node].vtuEntry.vid == entry->vid)
break;
node = VTUNode[node].nextEntry;
}
if (i == VTUList.vtuSize)
{
/* cannot find the given entry to be deleted. */
return GT_FALSE;
}
/* Update the found entry */
qdMemCpy(&VTUNode[node].vtuEntry, entry, sizeof(QDSIM_VTU_ENTRY));
return GT_TRUE;
}
void qdSimVTUInit()
{
int i;
qdMemSet((char*)VTUNode, 0, sizeof(VTUNode));
/* MAX_ATU_ADDRESS means entry i is free, otherwise, it's not free */
for (i=0; i<MAX_QD_VTU_ENTRIES; i++)
VTUNode[i].nextEntry = MAX_QD_VTU_ENTRIES;
VTUList.vtuSize = 0;
VTUList.head = 0;
}
void qdSimGetVTUInfo(QDSIM_VTU_ENTRY* entry)
{
entry->DBNum = qdSimRegs[qdSimDev.qdSimGlobalRegBase][5] & 0xF;
entry->vid = qdSimRegs[qdSimDev.qdSimGlobalRegBase][6] & 0x1FFF;
entry->memberTag[0] = qdSimRegs[qdSimDev.qdSimGlobalRegBase][7] & 0x3;
entry->memberTag[1] = (qdSimRegs[qdSimDev.qdSimGlobalRegBase][7] >> 4) & 0x3;
entry->memberTag[2] = (qdSimRegs[qdSimDev.qdSimGlobalRegBase][7] >> 8) & 0x3;
entry->memberTag[3] = (qdSimRegs[qdSimDev.qdSimGlobalRegBase][7] >> 12) & 0x3;
entry->memberTag[4] = qdSimRegs[qdSimDev.qdSimGlobalRegBase][8] & 0x3;
entry->memberTag[5] = (qdSimRegs[qdSimDev.qdSimGlobalRegBase][8] >> 4) & 0x3;
entry->memberTag[6] = (qdSimRegs[qdSimDev.qdSimGlobalRegBase][8] >> 8) & 0x3;
entry->memberTag[7] = (qdSimRegs[qdSimDev.qdSimGlobalRegBase][8] >> 12) & 0x3;
entry->memberTag[8] = qdSimRegs[qdSimDev.qdSimGlobalRegBase][9] & 0x3;
entry->memberTag[9] = (qdSimRegs[qdSimDev.qdSimGlobalRegBase][9] >> 4) & 0x3;
return;
}
void qdSimSetVTUInfo(QDSIM_VTU_ENTRY* entry)
{
qdSimRegs[qdSimDev.qdSimGlobalRegBase][5] |= entry->DBNum;
qdSimRegs[qdSimDev.qdSimGlobalRegBase][6] = (entry->vid & 0xFFF) | 0x1000;
qdSimRegs[qdSimDev.qdSimGlobalRegBase][7] = entry->memberTag[0] |
(entry->memberTag[1] << 4) |
(entry->memberTag[2] << 8) |
(entry->memberTag[3] << 12);
qdSimRegs[qdSimDev.qdSimGlobalRegBase][8] = entry->memberTag[4] |
(entry->memberTag[5] << 4) |
(entry->memberTag[6] << 8) |
(entry->memberTag[7] << 12);
qdSimRegs[qdSimDev.qdSimGlobalRegBase][9] = entry->memberTag[8] |
(entry->memberTag[9] << 4);
return;
}
void qdSimReSetVTUInfo()
{
qdSimRegs[qdSimDev.qdSimGlobalRegBase][6] = 0xFFF;
return;
}
void qdSimVTUGetViolation()
{
qdSimRegs[qdSimDev.qdSimGlobalRegBase][5] &= ~0xFFF;
qdSimRegs[qdSimDev.qdSimGlobalRegBase][5] |= 1; /* assume port 1 causes the violation */
qdSimRegs[qdSimDev.qdSimGlobalRegBase][6] = 1; /* assume vid 1 causes the violation */
}
void qdSimVTUResetBusy()
{
qdSimRegs[qdSimDev.qdSimGlobalRegBase][5] &= ~0x8000;
return;
}
GT_BOOL qdSimVTUOperation(unsigned int value)
{
QDSIM_VTU_ENTRY entry;
int index;
if(!(value & 0x8000))
return GT_FALSE;
qdSimVTUResetBusy();
switch((value & 0x7000) >> 12)
{
case 1:
/* Flush ALL */
qdSimVTUInit();
break;
case 3:
/* Load or Purge entry */
qdSimGetVTUInfo(&entry);
if(entry.vid & 0x1000)
{
entry.vid &= ~0x1000;
return qdSimVTUAdd(&entry);
}
else
return qdSimVTUDel(&entry);
break;
case 4:
/* Get Next Entry */
qdSimGetVTUInfo(&entry);
entry.vid &= ~0x1000;
index = qdSimVTUFindNext(&entry);
if (index == MAX_QD_VTU_ENTRIES)
{
qdSimReSetVTUInfo();
return GT_TRUE;
}
else
{
qdSimSetVTUInfo(&VTUNode[index].vtuEntry);
return GT_TRUE;
}
break;
case 7:
qdSimVTUGetViolation();
break;
default:
break;
}
return GT_TRUE;
}
void qdSimStatsInit()
{
int i;
for(i=0; i<qdSimDev.qdSimNumOfPorts; i++)
qdSimDev.qdSimPortStatsClear[i] = 0;
}
GT_BOOL qdSimStatsOperation(unsigned int value)
{
int i;
if(!(value & 0x8000))
return GT_FALSE;
qdSimRegs[qdSimDev.qdSimGlobalRegBase][29] &= ~0x8000;
switch((value & 0x7000) >> 12)
{
case 1:
/* Flush ALL */
for(i=0; i<qdSimDev.qdSimNumOfPorts; i++)
qdSimDev.qdSimPortStatsClear[i] = 1;
break;
case 2:
/* Flush a port */
if ((value & 0x3F) >= (unsigned int)qdSimDev.qdSimNumOfPorts)
return GT_FALSE;
qdSimDev.qdSimPortStatsClear[value & 0x3F] = 1;
break;
case 4:
/* Read a counter */
if(qdSimDev.qdSimPortStatsClear[qdSimDev.qdSimStatsCapturedPort] == 1)
{
qdSimRegs[qdSimDev.qdSimGlobalRegBase][30] = 0;
qdSimRegs[qdSimDev.qdSimGlobalRegBase][31] = 0;
}
else
{
qdSimRegs[qdSimDev.qdSimGlobalRegBase][30] = qdSimDev.qdSimStatsCapturedPort;
qdSimRegs[qdSimDev.qdSimGlobalRegBase][31] = value & 0x3F;
}
break;
case 5:
if ((value & 0x3F) >= (unsigned int)qdSimDev.qdSimNumOfPorts)
return GT_FALSE;
qdSimDev.qdSimStatsCapturedPort = value & 0x3F;
break;
default:
return GT_FALSE;
}
return GT_TRUE;
}
#define QD_PHY_CONTROL_RW (QD_PHY_RESET|QD_PHY_LOOPBACK|QD_PHY_SPEED|QD_PHY_AUTONEGO|QD_PHY_POWER|QD_PHY_RESTART_AUTONEGO|QD_PHY_DUPLEX)
#define QD_PHY_CONTROL_RO (~QD_PHY_CONTROL_RW)
GT_BOOL qdSimPhyControl(unsigned int portNumber , unsigned int miiReg, unsigned int value)
{
/* reset all the Read Only bits. */
value &= QD_PHY_CONTROL_RW;
/* If powerDown is set, add Reset and Restart Auto bits. */
if(value & QD_PHY_POWER)
{
value |= (QD_PHY_RESET|QD_PHY_RESTART_AUTONEGO);
qdSimRegs[portNumber][miiReg] = (GT_U16)value;
return GT_TRUE;
}
/* If Power Down was set, clear Reset and Restart Auto bits. */
if(qdSimRegs[portNumber][miiReg] & QD_PHY_POWER)
{
value &= ~(QD_PHY_RESET|QD_PHY_RESTART_AUTONEGO);
qdSimRegs[portNumber][miiReg] = (GT_U16)value;
return GT_TRUE;
}
/* If Reset or Restart Auto set, replace with current value and clear Reset/Restart Auto. */
if (value & (QD_PHY_RESET|QD_PHY_RESTART_AUTONEGO))
{
value &= ~(QD_PHY_RESET|QD_PHY_RESTART_AUTONEGO);
qdSimRegs[portNumber][miiReg] = (GT_U16)value;
return GT_TRUE;
}
else
{
value &= ~(QD_PHY_SPEED|QD_PHY_AUTONEGO|QD_PHY_DUPLEX);
qdSimRegs[portNumber][miiReg] &= (QD_PHY_SPEED|QD_PHY_AUTONEGO|QD_PHY_DUPLEX);
qdSimRegs[portNumber][miiReg] |= (GT_U16)value;
return GT_TRUE;
}
return GT_TRUE;
}
void qdSimRegsInit_6021()
{
qdSimRegs[qdSimDev.qdSimGlobalRegBase][5] = 0; /* VTU Operation Register */
qdSimRegs[qdSimDev.qdSimGlobalRegBase][6] = 0; /* VTU VID Register */
qdSimRegs[qdSimDev.qdSimGlobalRegBase][7] = 0; /* VTU Data Register */
qdSimRegs[qdSimDev.qdSimGlobalRegBase][29] = 0; /* Stats Operation Register */
qdSimRegs[qdSimDev.qdSimGlobalRegBase][30] = 0; /* Stats Counter Register Bytes 3,2 */
qdSimRegs[qdSimDev.qdSimGlobalRegBase][31] = 0; /* Stats Counter Register Bytes 1,0 */
}
void qdSimRegsInit_6063()
{
qdSimRegs[qdSimDev.qdSimGlobalRegBase][5] = 0; /* VTU Operation Register */
qdSimRegs[qdSimDev.qdSimGlobalRegBase][6] = 0; /* VTU VID Register */
qdSimRegs[qdSimDev.qdSimGlobalRegBase][7] = 0; /* VTU Data Register */
qdSimRegs[qdSimDev.qdSimGlobalRegBase][8] = 0; /* VTU Data Register */
qdSimRegs[qdSimDev.qdSimGlobalRegBase][29] = 0; /* Stats Operation Register */
qdSimRegs[qdSimDev.qdSimGlobalRegBase][30] = 0; /* Stats Counter Register Bytes 3,2 */
qdSimRegs[qdSimDev.qdSimGlobalRegBase][31] = 0; /* Stats Counter Register Bytes 1,0 */
}
void qdSimRegsInit_6083()
{
qdSimRegs[qdSimDev.qdSimGlobalRegBase][5] = 0; /* VTU Operation Register */
qdSimRegs[qdSimDev.qdSimGlobalRegBase][6] = 0; /* VTU VID Register */
qdSimRegs[qdSimDev.qdSimGlobalRegBase][7] = 0; /* VTU Data Register */
qdSimRegs[qdSimDev.qdSimGlobalRegBase][8] = 0; /* VTU Data Register */
qdSimRegs[qdSimDev.qdSimGlobalRegBase][9] = 0; /* VTU Data Register */
qdSimRegs[qdSimDev.qdSimGlobalRegBase][29] = 0; /* Stats Operation Register */
qdSimRegs[qdSimDev.qdSimGlobalRegBase][30] = 0; /* Stats Counter Register Bytes 3,2 */
qdSimRegs[qdSimDev.qdSimGlobalRegBase][31] = 0; /* Stats Counter Register Bytes 1,0 */
}
void qdSimRegsInit()
{
int i;
qdMemSet(qdSimRegs, 0xff, sizeof(qdSimRegs));
/*
PHY Registers Setup
*/
for(i=0; i<qdSimDev.qdSimNumOfPhys; i++)
{
qdSimRegs[i][0] = 0x3100; /* PHY Control */
qdSimRegs[i][1] = 0x7849; /* PHY Status */
qdSimRegs[i][2] = 0x0141; /* PHY Id 1 */
qdSimRegs[i][3] = 0x0c1f; /* PHY Id 2 */
qdSimRegs[i][4] = 0x01e1; /* AutoNego Ad */
qdSimRegs[i][5] = 0; /* Partner Ability */
qdSimRegs[i][6] = 4; /* AutoNego Expansion */
qdSimRegs[i][7] = 0x2001; /* Next Page Transmit */
qdSimRegs[i][8] = 0; /* Link Partner Next Page */
qdSimRegs[i][16] = 0x130; /* Phy Specific Control */
qdSimRegs[i][17] = 0x40; /* Phy Specific Status */
qdSimRegs[i][18] = 0; /* Phy Interrupt Enable */
qdSimRegs[i][19] = 0x40; /* Phy Interrupt Status */
qdSimRegs[i][20] = 0; /* Interrupt Port Summary */
qdSimRegs[i][21] = 0; /* Receive Error Counter */
qdSimRegs[i][22] = 0xa34; /* LED Parallel Select */
qdSimRegs[i][23] = 0x3fc; /* LED Stream Select */
qdSimRegs[i][24] = 0x42bf; /* LED Control */
}
/*
Port Registers Setup
*/
for(i=qdSimDev.qdSimPortBase; i<qdSimDev.qdSimNumOfPorts+qdSimDev.qdSimPortBase; i++)
{
qdSimRegs[i][0] = 0x800; /* Port Status */
qdSimRegs[i][3] = (GT_U16)qdSimDev.qdSimDevId << 4; /* Switch ID */
qdSimRegs[i][4] = 0x7f; /* Port Control */
qdSimRegs[i][6] = 0x7f & (~(1 << (i-8))); /* Port Based Vlan Map */
qdSimRegs[i][7] = 1; /* Default Port Vlan ID & Priority */
qdSimRegs[i][16] = 0; /* Rx Frame Counter */
qdSimRegs[i][17] = 0; /* Tx Frame Counter */
}
/*
Global Registers Setup
*/
qdSimRegs[qdSimDev.qdSimGlobalRegBase][0] = 0x3c01; /* Global Status */
qdSimRegs[qdSimDev.qdSimGlobalRegBase][1] = 0; /* Switch Mac Addr 0 ~ 1 byte */
qdSimRegs[qdSimDev.qdSimGlobalRegBase][2] = 0; /* Switch Mac Addr 2 ~ 3 byte */
qdSimRegs[qdSimDev.qdSimGlobalRegBase][3] = 0; /* Switch Mac Addr 4 ~ 5 byte */
qdSimRegs[qdSimDev.qdSimGlobalRegBase][4] = 0x81; /* Global Control */
qdSimRegs[qdSimDev.qdSimGlobalRegBase][10] = 0x1130; /* ATU Control */
qdSimRegs[qdSimDev.qdSimGlobalRegBase][11] = 0; /* ATU Operation */
qdSimRegs[qdSimDev.qdSimGlobalRegBase][12] = 0; /* ATU Data */
qdSimRegs[qdSimDev.qdSimGlobalRegBase][13] = 0; /* ATU Mac Addr 0 ~ 1 byte */
qdSimRegs[qdSimDev.qdSimGlobalRegBase][14] = 0; /* ATU Mac Addr 2 ~ 3 byte */
qdSimRegs[qdSimDev.qdSimGlobalRegBase][15] = 0; /* ATU Mac Addr 4 ~ 5 byte */
qdSimRegs[qdSimDev.qdSimGlobalRegBase][16] = 0; /* IP-PRI Mapping */
qdSimRegs[qdSimDev.qdSimGlobalRegBase][17] = 0; /* IP-PRI Mapping */
qdSimRegs[qdSimDev.qdSimGlobalRegBase][18] = 0x5555; /* IP-PRI Mapping */
qdSimRegs[qdSimDev.qdSimGlobalRegBase][19] = 0x5555; /* IP-PRI Mapping */
qdSimRegs[qdSimDev.qdSimGlobalRegBase][20] = 0xaaaa; /* IP-PRI Mapping */
qdSimRegs[qdSimDev.qdSimGlobalRegBase][21] = 0xaaaa; /* IP-PRI Mapping */
qdSimRegs[qdSimDev.qdSimGlobalRegBase][22] = 0xffff; /* IP-PRI Mapping */
qdSimRegs[qdSimDev.qdSimGlobalRegBase][23] = 0xffff; /* IP-PRI Mapping */
qdSimRegs[qdSimDev.qdSimGlobalRegBase][24] = 0xfa41; /* IEEE-PRI Mapping */
switch(qdSimDev.qdSimDevId)
{
case GT_88E6021:
qdSimRegsInit_6021();
break;
case GT_88E6063:
case GT_FF_HG:
case GT_FF_EG:
case GT_FH_VPN:
qdSimRegsInit_6063();
break;
case GT_88E6083:
qdSimRegsInit_6083();
break;
default:
break;
}
}
GT_BOOL qdSimRead_6052(unsigned int portNumber , unsigned int miiReg, unsigned int* value)
{
*value = (unsigned int) qdSimRegs[portNumber][miiReg];
if (IS_GLOBAL_REG(portNumber)) /* Global register */
{
switch(miiReg)
{
case QD_REG_GLOBAL_STATUS:
qdSimRegs[portNumber][miiReg] &= ~0xF;
if(qdSimRegs[0][QD_PHY_INT_PORT_SUMMARY_REG])
qdSimRegs[portNumber][miiReg] |= 0x2;
break;
case QD_REG_MACADDR_01:
case QD_REG_MACADDR_23:
case QD_REG_MACADDR_45:
case QD_REG_GLOBAL_CONTROL:
case QD_REG_ATU_CONTROL:
case QD_REG_ATU_OPERATION:
case QD_REG_ATU_DATA_REG:
case QD_REG_ATU_MAC_01:
case QD_REG_ATU_MAC_23:
case QD_REG_ATU_MAC_45:
case QD_REG_IP_PRI_REG0:
case QD_REG_IP_PRI_REG1:
case QD_REG_IP_PRI_REG2:
case QD_REG_IP_PRI_REG3:
case QD_REG_IP_PRI_REG4:
case QD_REG_IP_PRI_REG5:
case QD_REG_IP_PRI_REG6:
case QD_REG_IP_PRI_REG7:
case QD_REG_IEEE_PRI:
break;
}
}
else if(IS_PORT_REG(portNumber)) /* Port registers */
{
switch(miiReg)
{
case QD_REG_PORT_STATUS:
case QD_REG_SWITCH_ID:
case QD_REG_PORT_CONTROL:
case QD_REG_PORT_VLAN_MAP:
case QD_REG_PVID:
case QD_REG_RXCOUNTER:
case QD_REG_TXCOUNTER:
break;
}
}
else if(IS_PHY_REG(portNumber)) /* phy registers */
{
switch(miiReg)
{
case QD_PHY_CONTROL_REG:
break;
case QD_PHY_INT_ENABLE_REG:
break;
case QD_PHY_INT_STATUS_REG:
qdSimRegs[portNumber][miiReg] = 0;
qdSimRegs[0][QD_PHY_INT_PORT_SUMMARY_REG] &= ~(1<<portNumber);
break;
case QD_PHY_INT_PORT_SUMMARY_REG:
*value = (unsigned int) qdSimRegs[0][miiReg];
break;
}
}
return GT_TRUE;
}
GT_BOOL qdSimRead_6021(unsigned int portNumber , unsigned int miiReg, unsigned int* value)
{
*value = (unsigned int) qdSimRegs[portNumber][miiReg];
if (IS_GLOBAL_REG(portNumber)) /* Global register */
{
switch(miiReg)
{
case QD_REG_GLOBAL_STATUS:
qdSimRegs[portNumber][miiReg] &= ~0x7F;
if(qdSimRegs[0][QD_PHY_INT_PORT_SUMMARY_REG])
qdSimRegs[portNumber][miiReg] |= 0x2;
break;
case QD_REG_MACADDR_01:
case QD_REG_MACADDR_23:
case QD_REG_MACADDR_45:
case QD_REG_VTU_OPERATION:
case QD_REG_VTU_VID_REG:
case QD_REG_VTU_DATA1_REG:
case QD_REG_VTU_DATA2_REG:
case QD_REG_GLOBAL_CONTROL:
case QD_REG_ATU_CONTROL:
case QD_REG_ATU_OPERATION:
case QD_REG_ATU_DATA_REG:
case QD_REG_ATU_MAC_01:
case QD_REG_ATU_MAC_23:
case QD_REG_ATU_MAC_45:
case QD_REG_IP_PRI_REG0:
case QD_REG_IP_PRI_REG1:
case QD_REG_IP_PRI_REG2:
case QD_REG_IP_PRI_REG3:
case QD_REG_IP_PRI_REG4:
case QD_REG_IP_PRI_REG5:
case QD_REG_IP_PRI_REG6:
case QD_REG_IP_PRI_REG7:
case QD_REG_IEEE_PRI:
case QD_REG_STATS_OPERATION:
case QD_REG_STATS_COUNTER3_2:
case QD_REG_STATS_COUNTER1_0:
break;
}
}
else if(IS_PORT_REG(portNumber)) /* Port registers */
{
switch(miiReg)
{
case QD_REG_PORT_STATUS:
case QD_REG_SWITCH_ID:
case QD_REG_PORT_CONTROL:
case QD_REG_PORT_VLAN_MAP:
case QD_REG_PVID:
case QD_REG_RATE_CTRL:
case QD_REG_PAV:
case QD_REG_RXCOUNTER:
case QD_REG_TXCOUNTER:
case QD_REG_Q_COUNTER:
break;
}
}
else if(IS_PHY_REG(portNumber)) /* phy registers */
{
switch(miiReg)
{
case QD_PHY_CONTROL_REG:
break;
case QD_PHY_INT_ENABLE_REG:
break;
case QD_PHY_INT_STATUS_REG:
qdSimRegs[portNumber][miiReg] = 0;
qdSimRegs[0][QD_PHY_INT_PORT_SUMMARY_REG] &= ~(1<<portNumber);
break;
case QD_PHY_INT_PORT_SUMMARY_REG:
*value = (unsigned int) qdSimRegs[0][miiReg];
break;
}
}
return GT_TRUE;
}
GT_BOOL qdSimRead_6063(unsigned int portNumber , unsigned int miiReg, unsigned int* value)
{
*value = (unsigned int) qdSimRegs[portNumber][miiReg];
if (IS_GLOBAL_REG(portNumber)) /* Global register */
{
switch(miiReg)
{
case QD_REG_GLOBAL_STATUS:
qdSimRegs[portNumber][miiReg] &= ~0x7F;
if(qdSimRegs[0][QD_PHY_INT_PORT_SUMMARY_REG])
qdSimRegs[portNumber][miiReg] |= 0x2;
break;
case QD_REG_MACADDR_01:
case QD_REG_MACADDR_23:
case QD_REG_MACADDR_45:
case QD_REG_VTU_OPERATION:
case QD_REG_VTU_VID_REG:
case QD_REG_VTU_DATA1_REG:
case QD_REG_VTU_DATA2_REG:
case QD_REG_GLOBAL_CONTROL:
case QD_REG_ATU_CONTROL:
case QD_REG_ATU_OPERATION:
case QD_REG_ATU_DATA_REG:
case QD_REG_ATU_MAC_01:
case QD_REG_ATU_MAC_23:
case QD_REG_ATU_MAC_45:
case QD_REG_IP_PRI_REG0:
case QD_REG_IP_PRI_REG1:
case QD_REG_IP_PRI_REG2:
case QD_REG_IP_PRI_REG3:
case QD_REG_IP_PRI_REG4:
case QD_REG_IP_PRI_REG5:
case QD_REG_IP_PRI_REG6:
case QD_REG_IP_PRI_REG7:
case QD_REG_IEEE_PRI:
case QD_REG_STATS_OPERATION:
case QD_REG_STATS_COUNTER3_2:
case QD_REG_STATS_COUNTER1_0:
break;
}
}
else if(IS_PORT_REG(portNumber)) /* Port registers */
{
switch(miiReg)
{
case QD_REG_PORT_STATUS:
case QD_REG_SWITCH_ID:
case QD_REG_PORT_CONTROL:
case QD_REG_PORT_VLAN_MAP:
case QD_REG_PVID:
case QD_REG_RATE_CTRL:
case QD_REG_PAV:
case QD_REG_RXCOUNTER:
case QD_REG_TXCOUNTER:
case QD_REG_Q_COUNTER:
break;
}
}
else if(IS_PHY_REG(portNumber)) /* phy registers */
{
switch(miiReg)
{
case QD_PHY_CONTROL_REG:
break;
case QD_PHY_INT_ENABLE_REG:
break;
case QD_PHY_INT_STATUS_REG:
qdSimRegs[portNumber][miiReg] = 0;
qdSimRegs[0][QD_PHY_INT_PORT_SUMMARY_REG] &= ~(1<<portNumber);
break;
case QD_PHY_INT_PORT_SUMMARY_REG:
*value = (unsigned int) qdSimRegs[0][miiReg];
break;
}
}
return GT_TRUE;
}
GT_BOOL qdSimRead_6083(unsigned int portNumber , unsigned int miiReg, unsigned int* value)
{
*value = (unsigned int) qdSimRegs[portNumber][miiReg];
if (IS_GLOBAL_REG(portNumber)) /* Global register */
{
switch(miiReg)
{
case QD_REG_GLOBAL_STATUS:
qdSimRegs[portNumber][miiReg] &= ~0x7F;
if(qdSimRegs[0][QD_PHY_INT_PORT_SUMMARY_REG])
qdSimRegs[portNumber][miiReg] |= 0x2;
break;
case QD_REG_MACADDR_01:
case QD_REG_MACADDR_23:
case QD_REG_MACADDR_45:
case QD_REG_VTU_OPERATION:
case QD_REG_VTU_VID_REG:
case QD_REG_VTU_DATA1_REG:
case QD_REG_VTU_DATA2_REG:
case QD_REG_GLOBAL_CONTROL:
case QD_REG_ATU_CONTROL:
case QD_REG_ATU_OPERATION:
case QD_REG_ATU_DATA_REG:
case QD_REG_ATU_MAC_01:
case QD_REG_ATU_MAC_23:
case QD_REG_ATU_MAC_45:
case QD_REG_IP_PRI_REG0:
case QD_REG_IP_PRI_REG1:
case QD_REG_IP_PRI_REG2:
case QD_REG_IP_PRI_REG3:
case QD_REG_IP_PRI_REG4:
case QD_REG_IP_PRI_REG5:
case QD_REG_IP_PRI_REG6:
case QD_REG_IP_PRI_REG7:
case QD_REG_IEEE_PRI:
case QD_REG_STATS_OPERATION:
case QD_REG_STATS_COUNTER3_2:
case QD_REG_STATS_COUNTER1_0:
break;
}
}
else if(IS_PORT_REG(portNumber)) /* Port registers */
{
switch(miiReg)
{
case QD_REG_PORT_STATUS:
case QD_REG_SWITCH_ID:
case QD_REG_PORT_CONTROL:
case QD_REG_PORT_VLAN_MAP:
case QD_REG_PVID:
case QD_REG_RATE_CTRL:
case QD_REG_PAV:
case QD_REG_RXCOUNTER:
case QD_REG_TXCOUNTER:
case QD_REG_Q_COUNTER:
break;
}
}
else if(IS_PHY_REG(portNumber)) /* phy registers */
{
switch(miiReg)
{
case QD_PHY_CONTROL_REG:
break;
case QD_PHY_INT_ENABLE_REG:
break;
case QD_PHY_INT_STATUS_REG:
qdSimRegs[portNumber][miiReg] = 0;
qdSimRegs[0][QD_PHY_INT_PORT_SUMMARY_REG] &= ~(1<<portNumber);
break;
case QD_PHY_INT_PORT_SUMMARY_REG:
*value = (unsigned int) qdSimRegs[0][miiReg];
break;
}
}
return GT_TRUE;
}
GT_BOOL qdSimRead (GT_QD_DEV *dev,unsigned int portNumber , unsigned int miiReg, unsigned int* value)
{
if (portNumber >= MAX_SMI_ADDRESS)
portNumber -= MAX_SMI_ADDRESS;
if ((portNumber >= MAX_SMI_ADDRESS) || (miiReg >= MAX_REG_ADDRESS))
return GT_FALSE;
switch(qdSimDev.qdSimDevId)
{
case GT_88E6051:
case GT_88E6052:
return qdSimRead_6052(portNumber, miiReg, value);
case GT_88E6021:
return qdSimRead_6021(portNumber, miiReg, value);
case GT_88E6063:
case GT_FF_HG:
case GT_FF_EG:
case GT_FH_VPN:
return qdSimRead_6063(portNumber, miiReg, value);
case GT_88E6083:
return qdSimRead_6083(portNumber, miiReg, value);
default:
break;
}
return GT_TRUE;
}
GT_BOOL qdSimWrite_6052 (unsigned int portNumber , unsigned int miiReg, unsigned int value)
{
GT_BOOL status;
if (IS_GLOBAL_REG(portNumber)) /* Global register */
{
switch(miiReg)
{
case QD_REG_GLOBAL_STATUS:
/* readonly register */
return GT_FALSE;
case QD_REG_MACADDR_01:
case QD_REG_MACADDR_23:
case QD_REG_MACADDR_45:
break;
case QD_REG_GLOBAL_CONTROL:
if(value & 0x200)
{
/* Reload EEPROM values */
qdSimRegsInit();
qdSimRegs[portNumber][QD_REG_GLOBAL_STATUS] |= 0x1;
return GT_TRUE;
}
break;
case QD_REG_ATU_CONTROL:
value &= ~0x8000;
break;
case QD_REG_ATU_OPERATION:
status = qdSimATUOperation(value);
return status;
case QD_REG_ATU_DATA_REG:
case QD_REG_ATU_MAC_01:
case QD_REG_ATU_MAC_23:
case QD_REG_ATU_MAC_45:
case QD_REG_IP_PRI_REG0:
case QD_REG_IP_PRI_REG1:
case QD_REG_IP_PRI_REG2:
case QD_REG_IP_PRI_REG3:
case QD_REG_IP_PRI_REG4:
case QD_REG_IP_PRI_REG5:
case QD_REG_IP_PRI_REG6:
case QD_REG_IP_PRI_REG7:
case QD_REG_IEEE_PRI:
break;
default:
return GT_FALSE;
}
}
else if(IS_PORT_REG(portNumber)) /* Port registers */
{
switch(miiReg)
{
case QD_REG_PORT_STATUS:
case QD_REG_SWITCH_ID:
/* readonly registers */
return GT_FALSE;
case QD_REG_PORT_CONTROL:
case QD_REG_PORT_VLAN_MAP:
case QD_REG_PVID:
break;
case QD_REG_RXCOUNTER:
case QD_REG_TXCOUNTER:
/* readonly registers */
return GT_FALSE;
default:
return GT_FALSE;
}
}
else if(IS_PHY_REG(portNumber)) /* phy registers */
{
switch(miiReg)
{
case QD_PHY_CONTROL_REG:
return qdSimPhyControl(portNumber,miiReg,value);
case QD_PHY_INT_ENABLE_REG:
case QD_PHY_AUTONEGO_AD_REG:
case QD_PHY_NEXTPAGE_TX_REG:
case QD_PHY_SPEC_CONTROL_REG:
break;
case QD_PHY_INT_STATUS_REG:
case QD_PHY_INT_PORT_SUMMARY_REG:
return GT_FALSE;
default:
return GT_FALSE;
}
}
else
return GT_FALSE;
qdSimRegs[portNumber][miiReg] = (GT_U16)value;
return GT_TRUE;
}
GT_BOOL qdSimWrite_6021 (unsigned int portNumber , unsigned int miiReg, unsigned int value)
{
GT_BOOL status;
if (IS_GLOBAL_REG(portNumber)) /* Global register */
{
switch(miiReg)
{
case QD_REG_GLOBAL_STATUS:
/* readonly register */
return GT_FALSE;
case QD_REG_MACADDR_01:
case QD_REG_MACADDR_23:
case QD_REG_MACADDR_45:
break;
case QD_REG_VTU_OPERATION:
qdSimRegs[qdSimDev.qdSimGlobalRegBase][5] &= ~0xF;
qdSimRegs[qdSimDev.qdSimGlobalRegBase][5] |= (value & 0xF);
status = qdSimVTUOperation(value);
return status;
case QD_REG_VTU_VID_REG:
case QD_REG_VTU_DATA1_REG:
case QD_REG_VTU_DATA2_REG:
break;
case QD_REG_GLOBAL_CONTROL:
if(value & 0x200)
{
/* Reload EEPROM values */
qdSimRegsInit();
qdSimRegs[portNumber][QD_REG_GLOBAL_STATUS] |= 0x1;
return GT_TRUE;
}
break;
case QD_REG_ATU_CONTROL:
value &= ~0x8000;
break;
case QD_REG_ATU_OPERATION:
qdSimRegs[qdSimDev.qdSimGlobalRegBase][11] &= ~0xF;
qdSimRegs[qdSimDev.qdSimGlobalRegBase][11] |= (value & 0xF);
status = qdSimATUOperation(value);
return status;
case QD_REG_ATU_DATA_REG:
case QD_REG_ATU_MAC_01:
case QD_REG_ATU_MAC_23:
case QD_REG_ATU_MAC_45:
case QD_REG_IP_PRI_REG0:
case QD_REG_IP_PRI_REG1:
case QD_REG_IP_PRI_REG2:
case QD_REG_IP_PRI_REG3:
case QD_REG_IP_PRI_REG4:
case QD_REG_IP_PRI_REG5:
case QD_REG_IP_PRI_REG6:
case QD_REG_IP_PRI_REG7:
case QD_REG_IEEE_PRI:
break;
case QD_REG_STATS_OPERATION:
status = qdSimStatsOperation(value);
return status;
case QD_REG_STATS_COUNTER3_2:
case QD_REG_STATS_COUNTER1_0:
return GT_FALSE;
default:
return GT_FALSE;
}
}
else if(IS_PORT_REG(portNumber)) /* Port registers */
{
switch(miiReg)
{
case QD_REG_PORT_STATUS:
if(portNumber > 9)
{
qdSimRegs[portNumber][miiReg] &= ~QD_PORT_STATUS_DUPLEX;
qdSimRegs[portNumber][miiReg] |= (value & QD_PORT_STATUS_DUPLEX);
return GT_TRUE;
}
case QD_REG_SWITCH_ID:
/* readonly registers */
return GT_FALSE;
case QD_REG_PORT_CONTROL:
case QD_REG_PORT_VLAN_MAP:
case QD_REG_PVID:
break;
case QD_REG_RATE_CTRL:
case QD_REG_PAV:
case QD_REG_RXCOUNTER:
case QD_REG_TXCOUNTER:
/* readonly registers */
return GT_FALSE;
case QD_REG_Q_COUNTER:
return GT_FALSE;
default:
return GT_FALSE;
}
}
else if(IS_PHY_REG(portNumber)) /* phy registers */
{
switch(miiReg)
{
case QD_PHY_CONTROL_REG:
return qdSimPhyControl(portNumber,miiReg,value);
case QD_PHY_INT_ENABLE_REG:
case QD_PHY_AUTONEGO_AD_REG:
case QD_PHY_NEXTPAGE_TX_REG:
case QD_PHY_SPEC_CONTROL_REG:
break;
case QD_PHY_INT_STATUS_REG:
case QD_PHY_INT_PORT_SUMMARY_REG:
return GT_FALSE;
default:
return GT_FALSE;
}
}
else
return GT_FALSE;
qdSimRegs[portNumber][miiReg] = (GT_U16)value;
return GT_TRUE;
}
GT_BOOL qdSimWrite_6063 (unsigned int portNumber , unsigned int miiReg, unsigned int value)
{
GT_BOOL status;
if (IS_GLOBAL_REG(portNumber)) /* Global register */
{
switch(miiReg)
{
case QD_REG_GLOBAL_STATUS:
/* readonly register */
return GT_FALSE;
case QD_REG_MACADDR_01:
case QD_REG_MACADDR_23:
case QD_REG_MACADDR_45:
break;
case QD_REG_VTU_OPERATION:
qdSimRegs[qdSimDev.qdSimGlobalRegBase][5] &= ~0xF;
qdSimRegs[qdSimDev.qdSimGlobalRegBase][5] |= (value & 0xF);
status = qdSimVTUOperation(value);
return status;
case QD_REG_VTU_VID_REG:
case QD_REG_VTU_DATA1_REG:
case QD_REG_VTU_DATA2_REG:
break;
case QD_REG_GLOBAL_CONTROL:
if(value & 0x200)
{
/* Reload EEPROM values */
qdSimRegsInit();
qdSimRegs[portNumber][QD_REG_GLOBAL_STATUS] |= 0x1;
return GT_TRUE;
}
break;
case QD_REG_ATU_CONTROL:
value &= ~0x8000;
break;
case QD_REG_ATU_OPERATION:
qdSimRegs[qdSimDev.qdSimGlobalRegBase][11] &= ~0xF;
qdSimRegs[qdSimDev.qdSimGlobalRegBase][11] |= (value & 0xF);
status = qdSimATUOperation(value);
return status;
case QD_REG_ATU_DATA_REG:
case QD_REG_ATU_MAC_01:
case QD_REG_ATU_MAC_23:
case QD_REG_ATU_MAC_45:
case QD_REG_IP_PRI_REG0:
case QD_REG_IP_PRI_REG1:
case QD_REG_IP_PRI_REG2:
case QD_REG_IP_PRI_REG3:
case QD_REG_IP_PRI_REG4:
case QD_REG_IP_PRI_REG5:
case QD_REG_IP_PRI_REG6:
case QD_REG_IP_PRI_REG7:
case QD_REG_IEEE_PRI:
break;
case QD_REG_STATS_OPERATION:
status = qdSimStatsOperation(value);
return status;
case QD_REG_STATS_COUNTER3_2:
case QD_REG_STATS_COUNTER1_0:
return GT_FALSE;
default:
return GT_FALSE;
}
}
else if(IS_PORT_REG(portNumber)) /* Port registers */
{
switch(miiReg)
{
case QD_REG_PORT_STATUS:
if(portNumber > 12)
{
qdSimRegs[portNumber][miiReg] &= ~QD_PORT_STATUS_DUPLEX;
qdSimRegs[portNumber][miiReg] |= (value & QD_PORT_STATUS_DUPLEX);
return GT_TRUE;
}
case QD_REG_SWITCH_ID:
/* readonly registers */
return GT_FALSE;
case QD_REG_PORT_CONTROL:
case QD_REG_PORT_VLAN_MAP:
case QD_REG_PVID:
case QD_REG_RATE_CTRL:
case QD_REG_PAV:
break;
case QD_REG_RXCOUNTER:
case QD_REG_TXCOUNTER:
/* readonly registers */
return GT_FALSE;
case QD_REG_Q_COUNTER:
return GT_FALSE;
default:
return GT_FALSE;
}
}
else if(IS_PHY_REG(portNumber)) /* phy registers */
{
switch(miiReg)
{
case QD_PHY_CONTROL_REG:
return qdSimPhyControl(portNumber,miiReg,value);
case QD_PHY_INT_ENABLE_REG:
case QD_PHY_AUTONEGO_AD_REG:
case QD_PHY_NEXTPAGE_TX_REG:
case QD_PHY_SPEC_CONTROL_REG:
break;
case QD_PHY_INT_STATUS_REG:
case QD_PHY_INT_PORT_SUMMARY_REG:
return GT_FALSE;
default:
return GT_FALSE;
}
}
else
return GT_FALSE;
qdSimRegs[portNumber][miiReg] = (GT_U16)value;
return GT_TRUE;
}
GT_BOOL qdSimWrite_6083 (unsigned int portNumber , unsigned int miiReg, unsigned int value)
{
GT_BOOL status;
if (IS_GLOBAL_REG(portNumber)) /* Global register */
{
switch(miiReg)
{
case QD_REG_GLOBAL_STATUS:
/* readonly register */
return GT_FALSE;
case QD_REG_MACADDR_01:
case QD_REG_MACADDR_23:
case QD_REG_MACADDR_45:
break;
case QD_REG_VTU_OPERATION:
qdSimRegs[qdSimDev.qdSimGlobalRegBase][5] &= ~0xF;
qdSimRegs[qdSimDev.qdSimGlobalRegBase][5] |= (value & 0xF);
status = qdSimVTUOperation(value);
return status;
case QD_REG_VTU_VID_REG:
case QD_REG_VTU_DATA1_REG:
case QD_REG_VTU_DATA2_REG:
case QD_REG_VTU_DATA3_REG:
break;
case QD_REG_GLOBAL_CONTROL:
if(value & 0x200)
{
/* Reload EEPROM values */
qdSimRegsInit();
qdSimRegs[portNumber][QD_REG_GLOBAL_STATUS] |= 0x1;
return GT_TRUE;
}
break;
case QD_REG_ATU_CONTROL:
value &= ~0x8000;
break;
case QD_REG_ATU_OPERATION:
qdSimRegs[qdSimDev.qdSimGlobalRegBase][11] &= ~0xF;
qdSimRegs[qdSimDev.qdSimGlobalRegBase][11] |= (value & 0xF);
status = qdSimATUOperation(value);
return status;
case QD_REG_ATU_DATA_REG:
case QD_REG_ATU_MAC_01:
case QD_REG_ATU_MAC_23:
case QD_REG_ATU_MAC_45:
case QD_REG_IP_PRI_REG0:
case QD_REG_IP_PRI_REG1:
case QD_REG_IP_PRI_REG2:
case QD_REG_IP_PRI_REG3:
case QD_REG_IP_PRI_REG4:
case QD_REG_IP_PRI_REG5:
case QD_REG_IP_PRI_REG6:
case QD_REG_IP_PRI_REG7:
case QD_REG_IEEE_PRI:
break;
case QD_REG_STATS_OPERATION:
status = qdSimStatsOperation(value);
return status;
case QD_REG_STATS_COUNTER3_2:
case QD_REG_STATS_COUNTER1_0:
return GT_FALSE;
default:
return GT_FALSE;
}
}
else if(IS_PORT_REG(portNumber)) /* Port registers */
{
switch(miiReg)
{
case QD_REG_PORT_STATUS:
if(portNumber > 12)
{
qdSimRegs[portNumber][miiReg] &= ~QD_PORT_STATUS_DUPLEX;
qdSimRegs[portNumber][miiReg] |= (value & QD_PORT_STATUS_DUPLEX);
return GT_TRUE;
}
case QD_REG_SWITCH_ID:
/* readonly registers */
return GT_FALSE;
case QD_REG_PORT_CONTROL:
case QD_REG_PORT_VLAN_MAP:
case QD_REG_PVID:
case QD_REG_RATE_CTRL:
case QD_REG_PAV:
break;
case QD_REG_RXCOUNTER:
case QD_REG_TXCOUNTER:
/* readonly registers */
return GT_FALSE;
case QD_REG_Q_COUNTER:
return GT_FALSE;
default:
return GT_FALSE;
}
}
else if(IS_PHY_REG(portNumber)) /* phy registers */
{
switch(miiReg)
{
case QD_PHY_CONTROL_REG:
return qdSimPhyControl(portNumber,miiReg,value);
case QD_PHY_INT_ENABLE_REG:
case QD_PHY_AUTONEGO_AD_REG:
case QD_PHY_NEXTPAGE_TX_REG:
case QD_PHY_SPEC_CONTROL_REG:
break;
case QD_PHY_INT_STATUS_REG:
case QD_PHY_INT_PORT_SUMMARY_REG:
return GT_FALSE;
default:
return GT_FALSE;
}
}
else
return GT_FALSE;
qdSimRegs[portNumber][miiReg] = (GT_U16)value;
return GT_TRUE;
}
GT_BOOL qdSimWrite (GT_QD_DEV *dev,unsigned int portNumber , unsigned int miiReg, unsigned int value)
{
if (portNumber >= MAX_SMI_ADDRESS)
portNumber -= MAX_SMI_ADDRESS;
if ((portNumber >= MAX_SMI_ADDRESS) || (miiReg >= MAX_REG_ADDRESS))
return GT_FALSE;
switch(qdSimDev.qdSimDevId)
{
case GT_88E6051:
case GT_88E6052:
return qdSimWrite_6052(portNumber, miiReg, value);
case GT_88E6021:
return qdSimWrite_6021(portNumber, miiReg, value);
case GT_88E6063:
case GT_FF_HG:
case GT_FF_EG:
case GT_FH_VPN:
return qdSimWrite_6063(portNumber, miiReg, value);
case GT_88E6083:
return qdSimWrite_6083(portNumber, miiReg, value);
default:
break;
}
return GT_TRUE;
}
GT_STATUS qdSimSetPhyInt(unsigned int portNumber, unsigned short u16Data)
{
if(!qdSimDev.qdSimUsed)
return GT_FAIL;
qdSimRegs[portNumber][QD_PHY_INT_STATUS_REG] = u16Data;
if(u16Data)
qdSimRegs[0][QD_PHY_INT_PORT_SUMMARY_REG] |= (1<<portNumber);
else
qdSimRegs[0][QD_PHY_INT_PORT_SUMMARY_REG] &= ~(1<<portNumber);
qdSimRegs[MAX_SMI_ADDRESS-1][QD_REG_GLOBAL_STATUS] |= 0x2;
return GT_OK;
}
GT_STATUS qdSimSetGlobalInt(unsigned short u16Data)
{
if(!qdSimDev.qdSimUsed)
return GT_FAIL;
qdSimRegs[MAX_SMI_ADDRESS-1][QD_REG_GLOBAL_STATUS] |= (u16Data & 0xF);
return GT_OK;
}
void qdSimInit(GT_DEVICE devId, int baseAddr)
{
qdSimDev.qdSimUsed = 1;
qdSimDev.qdSimDevId = devId;
qdSimDev.vtuSize = 0;
qdSimDev.qdSimPhyBase = baseAddr;
qdSimDev.qdSimPortBase = baseAddr + 0x8;
qdSimDev.qdSimGlobalRegBase = baseAddr + 0xF;
switch(devId)
{
case GT_88E6021:
qdSimDev.vtuSize = 16;
qdSimDev.qdSimNumOfPhys = 2;
qdSimDev.qdSimNumOfPorts = 3;
break;
case GT_88E6051:
qdSimDev.qdSimNumOfPhys = 5;
qdSimDev.qdSimNumOfPorts = 6;
break;
case GT_88E6063:
case GT_FH_VPN:
qdSimDev.vtuSize = 64;
case GT_88E6052:
case GT_FF_HG:
case GT_FF_EG:
qdSimDev.qdSimNumOfPhys = 5;
qdSimDev.qdSimNumOfPorts = 7;
break;
case GT_88E6083:
qdSimDev.vtuSize = 64;
qdSimDev.qdSimNumOfPhys = 8;
qdSimDev.qdSimNumOfPorts = 10;
qdSimDev.qdSimPhyBase = 0;
qdSimDev.qdSimPortBase = 0x10;
qdSimDev.qdSimGlobalRegBase = 0x1b;
break;
default:
qdSimDev.vtuSize = 64;
qdSimDev.qdSimDevId = GT_88E6063;
qdSimDev.qdSimNumOfPhys = 5;
qdSimDev.qdSimNumOfPorts = 7;
break;
}
qdSimATUInit();
qdSimVTUInit();
qdSimRegsInit();
return;
}