/*
 * Copyright (C) 2013 Realtek Semiconductor Corp.
 * All Rights Reserved.
 *
 * This program is the proprietary software of Realtek Semiconductor
 * Corporation and/or its licensors, and only be used, duplicated,
 * modified or distributed under the authorized license from Realtek.
 *
 * ANY USE OF THE SOFTWARE OTHER THAN AS AUTHORIZED UNDER
 * THIS LICENSE OR COPYRIGHT LAW IS PROHIBITED.
 *
 * $Revision: 51993 $
 * $Date: 2014-10-08 19:44:38 +0800 (週三, 08 十月 2014) $
 *
 * Purpose : RTL8367C switch high-level API for RTL8367C
 * Feature : VLAN related functions
 *
 */
#include <rtl8367c_asicdrv_vlan.h>

#ifndef __KERNEL__
#include <string.h>
#else
#include <linux/string.h>
#endif

#if defined(CONFIG_RTL8367C_ASICDRV_TEST)
rtl8367c_vlan4kentrysmi Rtl8370sVirtualVlanTable[RTL8367C_VIDMAX + 1];
#endif

void _rtl8367c_VlanMCStUser2Smi(rtl8367c_vlanconfiguser *pVlanCg, rtl8367c_vlanconfigsmi *pSmiVlanCfg)
{
	pSmiVlanCfg->mbr 		= pVlanCg->mbr;
	pSmiVlanCfg->fid_msti 	= pVlanCg->fid_msti;
	pSmiVlanCfg->evid 		= pVlanCg->evid;
	pSmiVlanCfg->meteridx 	= pVlanCg->meteridx;
	pSmiVlanCfg->envlanpol 	= pVlanCg->envlanpol;
	pSmiVlanCfg->vbpri 		= pVlanCg->vbpri;
	pSmiVlanCfg->vbpen 		= pVlanCg->vbpen;
}

void _rtl8367c_VlanMCStSmi2User(rtl8367c_vlanconfigsmi *pSmiVlanCfg, rtl8367c_vlanconfiguser *pVlanCg)
{
	pVlanCg->mbr			= pSmiVlanCfg->mbr;
	pVlanCg->fid_msti		= pSmiVlanCfg->fid_msti;
	pVlanCg->evid			= pSmiVlanCfg->evid;
    pVlanCg->meteridx		= pSmiVlanCfg->meteridx;
	pVlanCg->envlanpol		= pSmiVlanCfg->envlanpol;
	pVlanCg->vbpri			= pSmiVlanCfg->vbpri;
	pVlanCg->vbpen			= pSmiVlanCfg->vbpen;
}

void _rtl8367c_Vlan4kStUser2Smi(rtl8367c_user_vlan4kentry *pUserVlan4kEntry, rtl8367c_vlan4kentrysmi *pSmiVlan4kEntry)
{
    pSmiVlan4kEntry->mbr        = pUserVlan4kEntry->mbr&0xff;
	pSmiVlan4kEntry->mbr_ext_0_1 	= (pUserVlan4kEntry->mbr >> 8)&0x3;
	pSmiVlan4kEntry->mbr_ext_2= (pUserVlan4kEntry->mbr >> 10)&0x1;
    pSmiVlan4kEntry->untag      = pUserVlan4kEntry->untag&0xff;
	pSmiVlan4kEntry->untagset_ext	=	(pUserVlan4kEntry->untag >> 8)&0x7;
 	pSmiVlan4kEntry->fid_msti   = pUserVlan4kEntry->fid_msti;
 	pSmiVlan4kEntry->vbpen      = pUserVlan4kEntry->vbpen;
	pSmiVlan4kEntry->vbpri      = pUserVlan4kEntry->vbpri;
	pSmiVlan4kEntry->envlanpol  = pUserVlan4kEntry->envlanpol;
	pSmiVlan4kEntry->meteridx   = pUserVlan4kEntry->meteridx & 0x1f;
	pSmiVlan4kEntry->mtr_idx_ext = (pUserVlan4kEntry->meteridx >> 5) & 0x1;
	pSmiVlan4kEntry->ivl_svl	= pUserVlan4kEntry->ivl_svl;

}

void _rtl8367c_Vlan4kStSmi2User(rtl8367c_vlan4kentrysmi *pSmiVlan4kEntry, rtl8367c_user_vlan4kentry *pUserVlan4kEntry)
{
	rtk_uint16 tmp;

	tmp = pSmiVlan4kEntry->mbr_ext_2 & 0x1;
	tmp = (tmp << 2)| pSmiVlan4kEntry->mbr_ext_0_1;
    pUserVlan4kEntry->mbr    	= (tmp << 8) | pSmiVlan4kEntry->mbr;

	tmp = pSmiVlan4kEntry->untagset_ext;
    pUserVlan4kEntry->untag    	= (tmp << 8) | pSmiVlan4kEntry->untag;
 	pUserVlan4kEntry->fid_msti  = pSmiVlan4kEntry->fid_msti;
 	pUserVlan4kEntry->vbpen     = pSmiVlan4kEntry->vbpen;
	pUserVlan4kEntry->vbpri     = pSmiVlan4kEntry->vbpri;
	pUserVlan4kEntry->envlanpol = pSmiVlan4kEntry->envlanpol;

	tmp = pSmiVlan4kEntry->mtr_idx_ext & 0x1;
	pUserVlan4kEntry->meteridx  = (tmp << 5) | pSmiVlan4kEntry->meteridx;
	pUserVlan4kEntry->ivl_svl  	= pSmiVlan4kEntry->ivl_svl;
}
/* Function Name:
 *      rtl8367c_setAsicVlanMemberConfig
 * Description:
 *      Set 32 VLAN member configurations
 * Input:
 *      index 		- VLAN member configuration index (0~31)
 *      pVlanCg - VLAN member configuration
 * Output:
 *      None
 * Return:
 *      RT_ERR_OK 					- Success
 *      RT_ERR_SMI  				- SMI access error
 *      RT_ERR_INPUT  				- Invalid input parameter
 *      RT_ERR_L2_FID  				- Invalid FID
 *      RT_ERR_PORT_MASK  			- Invalid portmask
 *      RT_ERR_FILTER_METER_ID  	- Invalid meter
 *      RT_ERR_QOS_INT_PRIORITY  	- Invalid priority
 *      RT_ERR_VLAN_ENTRY_NOT_FOUND - Invalid VLAN member configuration index
 * Note:
 *      None
 */
ret_t rtl8367c_setAsicVlanMemberConfig(rtk_uint32 index, rtl8367c_vlanconfiguser *pVlanCg)
{
	ret_t  retVal;
	rtk_uint32 regAddr;
	rtk_uint32 regData;
	rtk_uint16 *tableAddr;
    rtk_uint32 page_idx;
    rtl8367c_vlanconfigsmi  smi_vlancfg;

    /* Error Checking  */
	if(index > RTL8367C_CVIDXMAX)
        return RT_ERR_VLAN_ENTRY_NOT_FOUND;

    if(pVlanCg->evid > RTL8367C_EVIDMAX)
        return RT_ERR_INPUT;


    if(pVlanCg->mbr > RTL8367C_PORTMASK)
        return RT_ERR_PORT_MASK;

    if(pVlanCg->fid_msti > RTL8367C_FIDMAX)
        return RT_ERR_L2_FID;

    if(pVlanCg->meteridx > RTL8367C_METERMAX)
        return RT_ERR_FILTER_METER_ID;

    if(pVlanCg->vbpri > RTL8367C_PRIMAX)
        return RT_ERR_QOS_INT_PRIORITY;

    memset(&smi_vlancfg, 0x00, sizeof(rtl8367c_vlanconfigsmi));
    _rtl8367c_VlanMCStUser2Smi(pVlanCg, &smi_vlancfg);
    tableAddr = (rtk_uint16*)&smi_vlancfg;

    for(page_idx = 0; page_idx < 4; page_idx++)  /* 4 pages per VLAN Member Config */
    {
        regAddr = RTL8367C_VLAN_MEMBER_CONFIGURATION_BASE + (index * 4) + page_idx;
    	regData = *tableAddr;

    	retVal = rtl8367c_setAsicReg(regAddr, regData);
    	if(retVal != RT_ERR_OK)
            return retVal;

        tableAddr++;
    }

	return RT_ERR_OK;
}
/* Function Name:
 *      rtl8367c_getAsicVlanMemberConfig
 * Description:
 *      Get 32 VLAN member configurations
 * Input:
 *      index 		- VLAN member configuration index (0~31)
 *      pVlanCg - VLAN member configuration
 * Output:
 *      None
 * Return:
 *      RT_ERR_OK 					- Success
 *      RT_ERR_SMI  				- SMI access error
 *      RT_ERR_INPUT  				- Invalid input parameter
 *      RT_ERR_VLAN_ENTRY_NOT_FOUND - Invalid VLAN member configuration index
 * Note:
 *      None
 */
ret_t rtl8367c_getAsicVlanMemberConfig(rtk_uint32 index, rtl8367c_vlanconfiguser *pVlanCg)
{
    ret_t  retVal;
    rtk_uint32 page_idx;
    rtk_uint32 regAddr;
    rtk_uint32 regData;
    rtk_uint16 *tableAddr;
    rtl8367c_vlanconfigsmi  smi_vlancfg;

    if(index > RTL8367C_CVIDXMAX)
		return RT_ERR_VLAN_ENTRY_NOT_FOUND;

    memset(&smi_vlancfg, 0x00, sizeof(rtl8367c_vlanconfigsmi));
    tableAddr  = (rtk_uint16*)&smi_vlancfg;

    for(page_idx = 0; page_idx < 4; page_idx++)  /* 4 pages per VLAN Member Config */
    {
        regAddr = RTL8367C_VLAN_MEMBER_CONFIGURATION_BASE + (index * 4) + page_idx;

        retVal = rtl8367c_getAsicReg(regAddr, &regData);
        if(retVal != RT_ERR_OK)
            return retVal;

        *tableAddr = (rtk_uint16)regData;
        tableAddr++;
    }

    _rtl8367c_VlanMCStSmi2User(&smi_vlancfg, pVlanCg);
    return RT_ERR_OK;
}
/* Function Name:
 *      rtl8367c_setAsicVlan4kEntry
 * Description:
 *      Set VID mapped entry to 4K VLAN table
 * Input:
 *      pVlan4kEntry - 4K VLAN configuration
 * Output:
 *      None
 * Return:
 *      RT_ERR_OK 					- Success
 *      RT_ERR_SMI  				- SMI access error
 *      RT_ERR_INPUT  				- Invalid input parameter
 *      RT_ERR_L2_FID  				- Invalid FID
 *      RT_ERR_VLAN_VID 			- Invalid VID parameter (0~4095)
 *      RT_ERR_PORT_MASK  			- Invalid portmask
 *      RT_ERR_FILTER_METER_ID  	- Invalid meter
 *      RT_ERR_QOS_INT_PRIORITY  	- Invalid priority
 * Note:
 *      None
 */
ret_t rtl8367c_setAsicVlan4kEntry(rtl8367c_user_vlan4kentry *pVlan4kEntry )
{
    rtl8367c_vlan4kentrysmi vlan_4k_entry;
	rtk_uint32					page_idx;
	rtk_uint16					*tableAddr;
	ret_t 					retVal;
	rtk_uint32 					regData;

    if(pVlan4kEntry->vid > RTL8367C_VIDMAX)
        return RT_ERR_VLAN_VID;

    if(pVlan4kEntry->mbr > RTL8367C_PORTMASK)
        return RT_ERR_PORT_MASK;

    if(pVlan4kEntry->untag > RTL8367C_PORTMASK)
        return RT_ERR_PORT_MASK;

    if(pVlan4kEntry->fid_msti > RTL8367C_FIDMAX)
        return RT_ERR_L2_FID;

    if(pVlan4kEntry->meteridx > RTL8367C_METERMAX)
        return RT_ERR_FILTER_METER_ID;

    if(pVlan4kEntry->vbpri > RTL8367C_PRIMAX)
        return RT_ERR_QOS_INT_PRIORITY;

    memset(&vlan_4k_entry, 0x00, sizeof(rtl8367c_vlan4kentrysmi));
    _rtl8367c_Vlan4kStUser2Smi(pVlan4kEntry, &vlan_4k_entry);

	/* Prepare Data */
	tableAddr = (rtk_uint16 *)&vlan_4k_entry;
	for(page_idx = 0; page_idx < (sizeof(rtl8367c_vlan4kentrysmi) / 2); page_idx++)
	{
		regData = *tableAddr;
		retVal = rtl8367c_setAsicReg(RTL8367C_TABLE_ACCESS_WRDATA_BASE + page_idx, regData);
		if(retVal != RT_ERR_OK)
			return retVal;

		tableAddr++;
	}

	/* Write Address (VLAN_ID) */
	regData = pVlan4kEntry->vid;
	retVal = rtl8367c_setAsicReg(RTL8367C_TABLE_ACCESS_ADDR_REG, regData);
	if(retVal != RT_ERR_OK)
		return retVal;

	/* Write Command */
	retVal = rtl8367c_setAsicRegBits(RTL8367C_TABLE_ACCESS_CTRL_REG, RTL8367C_TABLE_TYPE_MASK | RTL8367C_COMMAND_TYPE_MASK,RTL8367C_TABLE_ACCESS_REG_DATA(TB_OP_WRITE,TB_TARGET_CVLAN));
	if(retVal != RT_ERR_OK)
		return retVal;

#if defined(CONFIG_RTL8367C_ASICDRV_TEST)
    memcpy(&Rtl8370sVirtualVlanTable[pVlan4kEntry->vid], &vlan_4k_entry, sizeof(rtl8367c_vlan4kentrysmi));
#endif

    return RT_ERR_OK;
}
/* Function Name:
 *      rtl8367c_getAsicVlan4kEntry
 * Description:
 *      Get VID mapped entry to 4K VLAN table
 * Input:
 *      pVlan4kEntry - 4K VLAN configuration
 * Output:
 *      None
 * Return:
 *      RT_ERR_OK 				- Success
 *      RT_ERR_SMI  			- SMI access error
 *      RT_ERR_VLAN_VID 		- Invalid VID parameter (0~4095)
 *      RT_ERR_BUSYWAIT_TIMEOUT - LUT is busy at retrieving
 * Note:
 *      None
 */
ret_t rtl8367c_getAsicVlan4kEntry(rtl8367c_user_vlan4kentry *pVlan4kEntry )
{
	rtl8367c_vlan4kentrysmi     vlan_4k_entry;
	rtk_uint32					page_idx;
	rtk_uint16					*tableAddr;
	ret_t 					    retVal;
	rtk_uint32 					regData;
    rtk_uint32                  busyCounter;

    if(pVlan4kEntry->vid > RTL8367C_VIDMAX)
        return RT_ERR_VLAN_VID;

    /* Polling status */
    busyCounter = RTL8367C_VLAN_BUSY_CHECK_NO;
	while(busyCounter)
	{
		retVal = rtl8367c_getAsicRegBit(RTL8367C_TABLE_ACCESS_STATUS_REG, RTL8367C_TABLE_LUT_ADDR_BUSY_FLAG_OFFSET,&regData);
		if(retVal != RT_ERR_OK)
	        return retVal;

		if(regData == 0)
			break;

		busyCounter --;
		if(busyCounter == 0)
			return RT_ERR_BUSYWAIT_TIMEOUT;
	}

	/* Write Address (VLAN_ID) */
	regData = pVlan4kEntry->vid;
	retVal = rtl8367c_setAsicReg(RTL8367C_TABLE_ACCESS_ADDR_REG, regData);
	if(retVal != RT_ERR_OK)
		return retVal;

	/* Read Command */
	retVal = rtl8367c_setAsicRegBits(RTL8367C_TABLE_ACCESS_CTRL_REG, RTL8367C_TABLE_TYPE_MASK | RTL8367C_COMMAND_TYPE_MASK, RTL8367C_TABLE_ACCESS_REG_DATA(TB_OP_READ,TB_TARGET_CVLAN));
	if(retVal != RT_ERR_OK)
		return retVal;

    /* Polling status */
    busyCounter = RTL8367C_VLAN_BUSY_CHECK_NO;
	while(busyCounter)
	{
		retVal = rtl8367c_getAsicRegBit(RTL8367C_TABLE_ACCESS_STATUS_REG, RTL8367C_TABLE_LUT_ADDR_BUSY_FLAG_OFFSET,&regData);
		if(retVal != RT_ERR_OK)
	        return retVal;

		if(regData == 0)
			break;

		busyCounter --;
		if(busyCounter == 0)
			return RT_ERR_BUSYWAIT_TIMEOUT;
	}

	/* Read VLAN data from register */
	tableAddr = (rtk_uint16 *)&vlan_4k_entry;
	for(page_idx = 0; page_idx < (sizeof(rtl8367c_vlan4kentrysmi) / 2); page_idx++)
	{
		retVal = rtl8367c_getAsicReg(RTL8367C_TABLE_ACCESS_RDDATA_BASE + page_idx, &regData);
		if(retVal != RT_ERR_OK)
			return retVal;

		*tableAddr = regData;
		tableAddr++;
	}

	_rtl8367c_Vlan4kStSmi2User(&vlan_4k_entry, pVlan4kEntry);

#if defined(CONFIG_RTL8367C_ASICDRV_TEST)
    _rtl8367c_Vlan4kStSmi2User(&Rtl8370sVirtualVlanTable[pVlan4kEntry->vid], pVlan4kEntry);
#endif

    return RT_ERR_OK;
}
/* Function Name:
 *      rtl8367c_setAsicVlanAccpetFrameType
 * Description:
 *      Set per-port acceptable frame type
 * Input:
 *      port 		- Physical port number (0~10)
 *      frameType 	- The acceptable frame type
 * Output:
 *      None
 * Return:
 *      RT_ERR_OK 						- Success
 *      RT_ERR_SMI  					- SMI access error
 *      RT_ERR_PORT_ID  				- Invalid port number
 *      RT_ERR_VLAN_ACCEPT_FRAME_TYPE  	- Invalid frame type
 * Note:
 *      None
 */
ret_t rtl8367c_setAsicVlanAccpetFrameType(rtk_uint32 port, rtl8367c_accframetype frameType)
{
    if(port > RTL8367C_PORTIDMAX)
        return RT_ERR_PORT_ID;

    if(frameType >= FRAME_TYPE_MAX_BOUND)
        return RT_ERR_VLAN_ACCEPT_FRAME_TYPE;

    return rtl8367c_setAsicRegBits(RTL8367C_VLAN_ACCEPT_FRAME_TYPE_REG(port), RTL8367C_VLAN_ACCEPT_FRAME_TYPE_MASK(port), frameType);
}
/* Function Name:
 *      rtl8367c_getAsicVlanAccpetFrameType
 * Description:
 *      Get per-port acceptable frame type
 * Input:
 *      port 		- Physical port number (0~10)
 *      pFrameType 	- The acceptable frame type
 * Output:
 *      None
 * Return:
 *      RT_ERR_OK 						- Success
 *      RT_ERR_SMI  					- SMI access error
 *      RT_ERR_PORT_ID  				- Invalid port number
 *      RT_ERR_VLAN_ACCEPT_FRAME_TYPE  	- Invalid frame type
 * Note:
 *      None
 */
ret_t rtl8367c_getAsicVlanAccpetFrameType(rtk_uint32 port, rtl8367c_accframetype *pFrameType)
{
    if(port > RTL8367C_PORTIDMAX)
        return RT_ERR_PORT_ID;

    return rtl8367c_getAsicRegBits(RTL8367C_VLAN_ACCEPT_FRAME_TYPE_REG(port), RTL8367C_VLAN_ACCEPT_FRAME_TYPE_MASK(port), pFrameType);
}
/* Function Name:
 *      rtl8367c_setAsicVlanIngressFilter
 * Description:
 *      Set VLAN Ingress Filter
 * Input:
 *      port 		- Physical port number (0~10)
 *      enabled 	- Enable or disable Ingress filter
 * Output:
 *      None
 * Return:
 *      RT_ERR_OK 		- Success
 *      RT_ERR_SMI  	- SMI access error
 *      RT_ERR_PORT_ID  - Invalid port number
 * Note:
 *      None
 */
ret_t rtl8367c_setAsicVlanIngressFilter(rtk_uint32 port, rtk_uint32 enabled)
{
    if(port > RTL8367C_PORTIDMAX)
        return RT_ERR_PORT_ID;

    return rtl8367c_setAsicRegBit(RTL8367C_VLAN_INGRESS_REG, port, enabled);
}
/* Function Name:
 *      rtl8367c_getAsicVlanIngressFilter
 * Description:
 *      Get VLAN Ingress Filter
 * Input:
 *      port 		- Physical port number (0~10)
 *      pEnable 	- Enable or disable Ingress filter
 * Output:
 *      None
 * Return:
 *      RT_ERR_OK 		- Success
 *      RT_ERR_SMI  	- SMI access error
 *      RT_ERR_PORT_ID  - Invalid port number
 * Note:
 *      None
 */
ret_t rtl8367c_getAsicVlanIngressFilter(rtk_uint32 port, rtk_uint32 *pEnable)
{
    if(port > RTL8367C_PORTIDMAX)
        return RT_ERR_PORT_ID;

    return rtl8367c_getAsicRegBit(RTL8367C_VLAN_INGRESS_REG, port, pEnable);
}
/* Function Name:
 *      rtl8367c_setAsicVlanEgressTagMode
 * Description:
 *      Set CVLAN egress tag mode
 * Input:
 *      port 		- Physical port number (0~10)
 *      tagMode 	- The egress tag mode. Including Original mode, Keep tag mode and Priority tag mode
 * Output:
 *      None
 * Return:
 *      RT_ERR_OK 		- Success
 *      RT_ERR_SMI  	- SMI access error
 *      RT_ERR_INPUT  	- Invalid input parameter
 *      RT_ERR_PORT_ID  - Invalid port number
 * Note:
 *      None
 */
ret_t rtl8367c_setAsicVlanEgressTagMode(rtk_uint32 port, rtl8367c_egtagmode tagMode)
{
    if(port > RTL8367C_PORTIDMAX)
        return RT_ERR_PORT_ID;

    if(tagMode >= EG_TAG_MODE_END)
        return RT_ERR_INPUT;

    return rtl8367c_setAsicRegBits(RTL8367C_PORT_MISC_CFG_REG(port), RTL8367C_VLAN_EGRESS_MDOE_MASK, tagMode);
}
/* Function Name:
 *      rtl8367c_getAsicVlanEgressTagMode
 * Description:
 *      Get CVLAN egress tag mode
 * Input:
 *      port 		- Physical port number (0~10)
 *      pTagMode 	- The egress tag mode. Including Original mode, Keep tag mode and Priority tag mode
 * Output:
 *      None
 * Return:
 *      RT_ERR_OK 		- Success
 *      RT_ERR_SMI  	- SMI access error
 *      RT_ERR_PORT_ID  - Invalid port number
 * Note:
 *      None
 */
ret_t rtl8367c_getAsicVlanEgressTagMode(rtk_uint32 port, rtl8367c_egtagmode *pTagMode)
{
    if(port > RTL8367C_PORTIDMAX)
        return RT_ERR_PORT_ID;

    return rtl8367c_getAsicRegBits(RTL8367C_PORT_MISC_CFG_REG(port), RTL8367C_VLAN_EGRESS_MDOE_MASK, pTagMode);
}
/* Function Name:
 *      rtl8367c_setAsicVlanPortBasedVID
 * Description:
 *      Set port based VID which is indexed to 32 VLAN member configurations
 * Input:
 *      port 	- Physical port number (0~10)
 *      index 	- Index to VLAN member configuration
 *      pri 	- 1Q Port based VLAN priority
 * Output:
 *      None
 * Return:
 *      RT_ERR_OK 					- Success
 *      RT_ERR_SMI  				- SMI access error
 *      RT_ERR_PORT_ID  			- Invalid port number
 *      RT_ERR_QOS_INT_PRIORITY  	- Invalid priority
 *      RT_ERR_VLAN_ENTRY_NOT_FOUND - Invalid VLAN member configuration index
 * Note:
 *      None
 */
ret_t rtl8367c_setAsicVlanPortBasedVID(rtk_uint32 port, rtk_uint32 index, rtk_uint32 pri)
{
    rtk_uint32 regAddr, bit_mask;
    ret_t  retVal;

    if(port > RTL8367C_PORTIDMAX)
        return RT_ERR_PORT_ID;

    if(index > RTL8367C_CVIDXMAX)
        return RT_ERR_VLAN_ENTRY_NOT_FOUND;

    if(pri > RTL8367C_PRIMAX)
        return RT_ERR_QOS_INT_PRIORITY;

    regAddr = RTL8367C_VLAN_PVID_CTRL_REG(port);
    bit_mask = RTL8367C_PORT_VIDX_MASK(port);
    retVal = rtl8367c_setAsicRegBits(regAddr, bit_mask, index);
    if(retVal != RT_ERR_OK)
        return retVal;

    regAddr = RTL8367C_VLAN_PORTBASED_PRIORITY_REG(port);
    bit_mask = RTL8367C_VLAN_PORTBASED_PRIORITY_MASK(port);
    retVal = rtl8367c_setAsicRegBits(regAddr, bit_mask, pri);
    if(retVal != RT_ERR_OK)
        return retVal;

    return RT_ERR_OK;
}
/* Function Name:
 *      rtl8367c_getAsicVlanPortBasedVID
 * Description:
 *      Get port based VID which is indexed to 32 VLAN member configurations
 * Input:
 *      port 	- Physical port number (0~10)
 *      pIndex 	- Index to VLAN member configuration
 *      pPri 	- 1Q Port based VLAN priority
 * Output:
 *      None
 * Return:
 *      RT_ERR_OK 		- Success
 *      RT_ERR_SMI  	- SMI access error
 *      RT_ERR_PORT_ID  - Invalid port number
 * Note:
 *      None
 */
ret_t rtl8367c_getAsicVlanPortBasedVID(rtk_uint32 port, rtk_uint32 *pIndex, rtk_uint32 *pPri)
{
    rtk_uint32 regAddr,bit_mask;
    ret_t  retVal;

    if(port > RTL8367C_PORTIDMAX)
        return RT_ERR_PORT_ID;

    regAddr = RTL8367C_VLAN_PVID_CTRL_REG(port);
    bit_mask = RTL8367C_PORT_VIDX_MASK(port);
    retVal = rtl8367c_getAsicRegBits(regAddr, bit_mask, pIndex);
    if(retVal != RT_ERR_OK)
        return retVal;

    regAddr = RTL8367C_VLAN_PORTBASED_PRIORITY_REG(port);
    bit_mask = RTL8367C_VLAN_PORTBASED_PRIORITY_MASK(port);
    retVal = rtl8367c_getAsicRegBits(regAddr, bit_mask, pPri);
    if(retVal != RT_ERR_OK)
        return retVal;

    return RT_ERR_OK;
}
/* Function Name:
 *      rtl8367c_setAsicVlanProtocolBasedGroupData
 * Description:
 *      Set protocol and port based group database
 * Input:
 *      index 		- Index to VLAN member configuration
 *      pPbCfg 	- Protocol and port based group database entry
 * Output:
 *      None
 * Return:
 *      RT_ERR_OK 					- Success
 *      RT_ERR_SMI  				- SMI access error
 *      RT_ERR_INPUT  				- Invalid input parameter
 *      RT_ERR_VLAN_PROTO_AND_PORT  - Invalid protocol base group database index
 * Note:
 *      None
 */
ret_t rtl8367c_setAsicVlanProtocolBasedGroupData(rtk_uint32 index, rtl8367c_protocolgdatacfg *pPbCfg)
{
	rtk_uint32  frameType;
    rtk_uint32  etherType;
	ret_t	retVal;

	/* Error Checking */
	if(index > RTL8367C_PROTOVLAN_GIDX_MAX)
		return RT_ERR_VLAN_PROTO_AND_PORT;

    if(pPbCfg->frameType >= PPVLAN_FRAME_TYPE_END )
		return RT_ERR_INPUT;

	frameType = pPbCfg->frameType;
	etherType = pPbCfg->etherType;

	/* Frame type */
    retVal = rtl8367c_setAsicRegBits(RTL8367C_VLAN_PPB_FRAMETYPE_REG(index), RTL8367C_VLAN_PPB_FRAMETYPE_MASK, frameType);
    if(retVal != RT_ERR_OK)
        return retVal;

	/* Ether type */
	retVal = rtl8367c_setAsicReg(RTL8367C_VLAN_PPB_ETHERTYPR_REG(index), etherType);
    if(retVal != RT_ERR_OK)
        return retVal;

    return RT_ERR_OK;
}
/* Function Name:
 *      rtl8367c_getAsicVlanProtocolBasedGroupData
 * Description:
 *      Get protocol and port based group database
 * Input:
 *      index 		- Index to VLAN member configuration
 *      pPbCfg 	- Protocol and port based group database entry
 * Output:
 *      None
 * Return:
 *      RT_ERR_OK 					- Success
 *      RT_ERR_SMI  				- SMI access error
 *      RT_ERR_INPUT  				- Invalid input parameter
 *      RT_ERR_VLAN_PROTO_AND_PORT  - Invalid protocol base group database index
 * Note:
 *      None
 */
ret_t rtl8367c_getAsicVlanProtocolBasedGroupData(rtk_uint32 index, rtl8367c_protocolgdatacfg *pPbCfg)
{
	rtk_uint32  frameType;
    rtk_uint32  etherType;
	ret_t	retVal;

	/* Error Checking */
	if(index > RTL8367C_PROTOVLAN_GIDX_MAX)
		return RT_ERR_VLAN_PROTO_AND_PORT;

	/* Read Frame type */
    retVal = rtl8367c_getAsicRegBits(RTL8367C_VLAN_PPB_FRAMETYPE_REG(index), RTL8367C_VLAN_PPB_FRAMETYPE_MASK, &frameType);
    if(retVal != RT_ERR_OK)
        return retVal;

	/* Read Ether type */
	retVal = rtl8367c_getAsicReg(RTL8367C_VLAN_PPB_ETHERTYPR_REG(index), &etherType);
    if(retVal != RT_ERR_OK)
        return retVal;


	pPbCfg->frameType = frameType;
	pPbCfg->etherType = etherType;
    return RT_ERR_OK;
}
/* Function Name:
 *      rtl8367c_setAsicVlanPortAndProtocolBased
 * Description:
 *      Set protocol and port based VLAN configuration
 * Input:
 *      port 		- Physical port number (0~10)
 *      index 		- Index of protocol and port based database index
 *      pPpbCfg 	- Protocol and port based VLAN configuration
 * Output:
 *      None
 * Return:
 *      RT_ERR_OK 					- Success
 *      RT_ERR_SMI  				- SMI access error
 *      RT_ERR_INPUT  				- Invalid input parameter
 *      RT_ERR_PORT_ID  			- Invalid port number
 *      RT_ERR_QOS_INT_PRIORITY  	- Invalid priority
 *      RT_ERR_VLAN_PROTO_AND_PORT  - Invalid protocol base group database index
 *      RT_ERR_VLAN_ENTRY_NOT_FOUND - Invalid VLAN member configuration index
 * Note:
 *      None
 */
ret_t rtl8367c_setAsicVlanPortAndProtocolBased(rtk_uint32 port, rtk_uint32 index, rtl8367c_protocolvlancfg *pPpbCfg)
{
	rtk_uint32  reg_addr, bit_mask, bit_value;
	ret_t   retVal;

	/* Error Checking */
	if(port > RTL8367C_PORTIDMAX)
		return RT_ERR_PORT_ID;

	if(index > RTL8367C_PROTOVLAN_GIDX_MAX)
		return RT_ERR_VLAN_PROTO_AND_PORT;

	if( (pPpbCfg->valid != FALSE) && (pPpbCfg->valid != TRUE) )
        return RT_ERR_INPUT;

	if(pPpbCfg->vlan_idx > RTL8367C_CVIDXMAX)
        return RT_ERR_VLAN_ENTRY_NOT_FOUND;

	if(pPpbCfg->priority > RTL8367C_PRIMAX)
        return RT_ERR_QOS_INT_PRIORITY;

	/* Valid bit */
	reg_addr  = RTL8367C_VLAN_PPB_VALID_REG(index);
	bit_mask  = 0x0001 << port;
	bit_value = ((TRUE == pPpbCfg->valid) ? 0x1 : 0x0);
	retVal    = rtl8367c_setAsicRegBits(reg_addr, bit_mask, bit_value);
	if(retVal != RT_ERR_OK)
		return retVal;

	/* Calculate the actual register address for CVLAN index*/
	if(port < 8)
	{
		reg_addr = RTL8367C_VLAN_PPB_CTRL_REG(index, port);
		bit_mask = RTL8367C_VLAN_PPB_CTRL_MASK(port);
		bit_value = pPpbCfg->vlan_idx;
	}
	else{
		reg_addr = RTL8367C_REG_VLAN_PPB0_CTRL4;
		switch(port){
			case 8:
				bit_mask = RTL8367C_VLAN_PPB0_CTRL4_PORT8_INDEX_MASK;
				break;
			case 9:
				bit_mask = RTL8367C_VLAN_PPB0_CTRL4_PORT9_INDEX_MASK;
				break;
			case 10:
				bit_mask = RTL8367C_VLAN_PPB0_CTRL4_PORT10_INDEX_MASK;
				break;
			default:
				bit_mask = RTL8367C_VLAN_PPB0_CTRL4_PORT8_INDEX_MASK;
				break;
		}
		bit_value = pPpbCfg->vlan_idx;
	}
	retVal	= rtl8367c_setAsicRegBits(reg_addr, bit_mask, bit_value);
	if(retVal != RT_ERR_OK)
		return retVal;

	/* write priority */
	reg_addr  = RTL8367C_VLAN_PPB_PRIORITY_ITEM_REG(port, index);
	bit_mask  = RTL8367C_VLAN_PPB_PRIORITY_ITEM_MASK(port);
	bit_value = pPpbCfg->priority;
	retVal    = rtl8367c_setAsicRegBits(reg_addr, bit_mask, bit_value);
	if(retVal != RT_ERR_OK)
		return retVal;

    return RT_ERR_OK;
}
/* Function Name:
 *      rtl8367c_getAsicVlanPortAndProtocolBased
 * Description:
 *      Get protocol and port based VLAN configuration
 * Input:
 *      port 		- Physical port number (0~7)
 *      index 		- Index of protocol and port based database index
 *      pPpbCfg 	- Protocol and port based VLAN configuration
 * Output:
 *      None
 * Return:
 *      RT_ERR_OK 					- Success
 *      RT_ERR_SMI  				- SMI access error
 *      RT_ERR_INPUT  				- Invalid input parameter
 *      RT_ERR_PORT_ID  			- Invalid port number
 *      RT_ERR_VLAN_PROTO_AND_PORT  - Invalid protocol base group database index
 * Note:
 *      None
 */
ret_t rtl8367c_getAsicVlanPortAndProtocolBased(rtk_uint32 port, rtk_uint32 index, rtl8367c_protocolvlancfg *pPpbCfg)
{
	rtk_uint32  reg_addr, bit_mask, bit_value;
	ret_t   retVal;

	/* Error Checking */
	if(port > RTL8367C_PORTIDMAX)
		return RT_ERR_PORT_ID;

	if(index > RTL8367C_PROTOVLAN_GIDX_MAX)
		return RT_ERR_VLAN_PROTO_AND_PORT;

	if(pPpbCfg == NULL)
		return RT_ERR_INPUT;

	/* Valid bit */
	reg_addr  = RTL8367C_VLAN_PPB_VALID_REG(index);
	bit_mask  = 0x0001 << port;
	retVal    = rtl8367c_getAsicRegBits(reg_addr, bit_mask, &bit_value);
	if(retVal != RT_ERR_OK)
		return retVal;

	pPpbCfg->valid = bit_value;

	/* CVLAN index */
	if(port < 8)
	{
		reg_addr = RTL8367C_VLAN_PPB_CTRL_REG(index, port);
		bit_mask = RTL8367C_VLAN_PPB_CTRL_MASK(port);
	}
	else{
		reg_addr = RTL8367C_REG_VLAN_PPB0_CTRL4;
		switch(port){
			case 8:
				bit_mask = RTL8367C_VLAN_PPB0_CTRL4_PORT8_INDEX_MASK;
				break;
			case 9:
				bit_mask = RTL8367C_VLAN_PPB0_CTRL4_PORT9_INDEX_MASK;
				break;
			case 10:
				bit_mask = RTL8367C_VLAN_PPB0_CTRL4_PORT10_INDEX_MASK;
				break;
			default:
				bit_mask = RTL8367C_VLAN_PPB0_CTRL4_PORT8_INDEX_MASK;
				break;
		}
	}
	retVal = rtl8367c_getAsicRegBits(reg_addr, bit_mask, &bit_value);
	if(retVal != RT_ERR_OK)
		return retVal;

	pPpbCfg->vlan_idx = bit_value;


	/* priority */
	reg_addr = RTL8367C_VLAN_PPB_PRIORITY_ITEM_REG(port,index);
	bit_mask = RTL8367C_VLAN_PPB_PRIORITY_ITEM_MASK(port);
	retVal = rtl8367c_getAsicRegBits(reg_addr, bit_mask, &bit_value);
	if(retVal != RT_ERR_OK)
		return retVal;

	pPpbCfg->priority = bit_value;
    return RT_ERR_OK;
}
/* Function Name:
 *      rtl8367c_setAsicVlanFilter
 * Description:
 *      Set enable CVLAN filtering function
 * Input:
 *      enabled - 1: enabled, 0: disabled
 * Output:
 *      None
 * Return:
 *      RT_ERR_OK 		- Success
 *      RT_ERR_SMI  	- SMI access error
 * Note:
 *      None
 */
ret_t rtl8367c_setAsicVlanFilter(rtk_uint32 enabled)
{
    return rtl8367c_setAsicRegBit(RTL8367C_REG_VLAN_CTRL, RTL8367C_VLAN_CTRL_OFFSET, enabled);
}
/* Function Name:
 *      rtl8367c_getAsicVlanFilter
 * Description:
 *      Get enable CVLAN filtering function
 * Input:
 *      pEnabled - 1: enabled, 0: disabled
 * Output:
 *      None
 * Return:
 *      RT_ERR_OK 		- Success
 *      RT_ERR_SMI  	- SMI access error
 * Note:
 *      None
 */
ret_t rtl8367c_getAsicVlanFilter(rtk_uint32* pEnabled)
{
    return rtl8367c_getAsicRegBit(RTL8367C_REG_VLAN_CTRL, RTL8367C_VLAN_CTRL_OFFSET, pEnabled);
}
/* Function Name:
 *      rtl8367c_setAsicVlanUntagDscpPriorityEn
 * Description:
 *      Set enable Dscp to untag 1Q priority
 * Input:
 *      enabled - 1: enabled, 0: disabled
 * Output:
 *      None
 * Return:
 *      RT_ERR_OK 		- Success
 *      RT_ERR_SMI  	- SMI access error
 * Note:
 *      None
 */
ret_t rtl8367c_setAsicVlanUntagDscpPriorityEn(rtk_uint32 enabled)
{
    return rtl8367c_setAsicRegBit(RTL8367C_REG_UNTAG_DSCP_PRI_CFG, RTL8367C_UNTAG_DSCP_PRI_CFG_OFFSET, enabled);
}
/* Function Name:
 *      rtl8367c_getAsicVlanUntagDscpPriorityEn
 * Description:
 *      Get enable Dscp to untag 1Q priority
 * Input:
 *      enabled - 1: enabled, 0: disabled
 * Output:
 *      None
 * Return:
 *      RT_ERR_OK 		- Success
 *      RT_ERR_SMI  	- SMI access error
 * Note:
 *      None
 */
ret_t rtl8367c_getAsicVlanUntagDscpPriorityEn(rtk_uint32* enabled)
{
    return rtl8367c_getAsicRegBit(RTL8367C_REG_UNTAG_DSCP_PRI_CFG, RTL8367C_UNTAG_DSCP_PRI_CFG_OFFSET, enabled);
}
/* Function Name:
 *      rtl8367c_setAsicPortBasedFid
 * Description:
 *      Set port based FID
 * Input:
 *      port 	- Physical port number (0~10)
 *      fid 	- Port based fid
 * Output:
 *      None
 * Return:
 *      RT_ERR_OK 		- Success
 *      RT_ERR_SMI  	- SMI access error
 *      RT_ERR_L2_FID  	- Invalid FID
 *      RT_ERR_PORT_ID  - Invalid port number
 * Note:
 *      None
 */
ret_t rtl8367c_setAsicPortBasedFid(rtk_uint32 port, rtk_uint32 fid)
{
	rtk_uint32  reg_addr;

    if(port > RTL8367C_PORTIDMAX)
        return RT_ERR_PORT_ID;

    if(fid > RTL8367C_FIDMAX)
        return RT_ERR_L2_FID;

	if(port < 8)
    	return rtl8367c_setAsicReg(RTL8367C_PORT_PBFID_REG(port),fid);
	else {
		reg_addr = RTL8367C_REG_PORT8_PBFID + port-8;
    	return rtl8367c_setAsicReg(reg_addr, fid);
	}

}
/* Function Name:
 *      rtl8367c_getAsicPortBasedFid
 * Description:
 *      Get port based FID
 * Input:
 *      port 	- Physical port number (0~7)
 *      pFid 	- Port based fid
 * Output:
 *      None
 * Return:
 *      RT_ERR_OK 		- Success
 *      RT_ERR_SMI  	- SMI access error
 *      RT_ERR_PORT_ID  - Invalid port number
 * Note:
 *      None
 */
ret_t rtl8367c_getAsicPortBasedFid(rtk_uint32 port, rtk_uint32* pFid)
{
	rtk_uint32  reg_addr;

    if(port > RTL8367C_PORTIDMAX)
        return RT_ERR_PORT_ID;

	if(port < 8)
    	return rtl8367c_getAsicReg(RTL8367C_PORT_PBFID_REG(port), pFid);
	else{
		reg_addr = RTL8367C_REG_PORT8_PBFID + port-8;
    	return rtl8367c_getAsicReg(reg_addr, pFid);
	}
}
/* Function Name:
 *      rtl8367c_setAsicPortBasedFidEn
 * Description:
 *      Set port based FID selection enable
 * Input:
 *      port 	- Physical port number (0~10)
 *      enabled - 1: enabled, 0: disabled
 * Output:
 *      None
 * Return:
 *      RT_ERR_OK 		- Success
 *      RT_ERR_SMI  	- SMI access error
 *      RT_ERR_PORT_ID  - Invalid port number
 * Note:
 *      None
 */
ret_t rtl8367c_setAsicPortBasedFidEn(rtk_uint32 port, rtk_uint32 enabled)
{
    if(port > RTL8367C_PORTIDMAX)
        return RT_ERR_PORT_ID;

    return rtl8367c_setAsicRegBit(RTL8367C_REG_PORT_PBFIDEN,port, enabled);
}
/* Function Name:
 *      rtl8367c_getAsicPortBasedFidEn
 * Description:
 *      Get port based FID selection enable
 * Input:
 *      port 	- Physical port number (0~10)
 *      pEnabled - 1: enabled, 0: disabled
 * Output:
 *      None
 * Return:
 *      RT_ERR_OK 		- Success
 *      RT_ERR_SMI  	- SMI access error
 *      RT_ERR_PORT_ID  - Invalid port number
 * Note:
 *      None
 */
ret_t rtl8367c_getAsicPortBasedFidEn(rtk_uint32 port, rtk_uint32* pEnabled)
{
    if(port > RTL8367C_PORTIDMAX)
        return RT_ERR_PORT_ID;

    return rtl8367c_getAsicRegBit(RTL8367C_REG_PORT_PBFIDEN,port, pEnabled);
}
/* Function Name:
 *      rtl8367c_setAsicSpanningTreeStatus
 * Description:
 *      Set spanning tree state per each port
 * Input:
 *      port 	- Physical port number (0~10)
 *      msti 	- Multiple spanning tree instance
 *      state 	- Spanning tree state for msti
 * Output:
 *      None
 * Return:
 *      RT_ERR_OK 			- Success
 *      RT_ERR_SMI  		- SMI access error
 *      RT_ERR_MSTI  		- Invalid msti parameter
 *      RT_ERR_PORT_ID  	- Invalid port number
 *      RT_ERR_MSTP_STATE  	- Invalid port number
 * Note:
 *      None
 */
ret_t rtl8367c_setAsicSpanningTreeStatus(rtk_uint32 port, rtk_uint32 msti, rtk_uint32 state)
{
	rtk_uint32  reg_addr,bits_msk;

    if(port > RTL8367C_PORTIDMAX)
        return RT_ERR_PORT_ID;

    if(msti > RTL8367C_MSTIMAX)
        return RT_ERR_MSTI;

	if(state > STPST_FORWARDING)
		return RT_ERR_MSTP_STATE;

	if(port < 8)
		return rtl8367c_setAsicRegBits(RTL8367C_VLAN_MSTI_REG(msti,port), RTL8367C_VLAN_MSTI_MASK(port),state);
	else{
		reg_addr = RTL8367C_VLAN_MSTI_REG(msti,port);
		switch(port){
			case 8: bits_msk = RTL8367C_VLAN_MSTI0_CTRL1_PORT8_STATE_MASK;break;
			case 9: bits_msk = RTL8367C_VLAN_MSTI0_CTRL1_PORT9_STATE_MASK;break;
			case 10: bits_msk = RTL8367C_VLAN_MSTI0_CTRL1_PORT10_STATE_MASK;break;
		}
		return rtl8367c_setAsicRegBits(reg_addr, bits_msk,state);
	}
}
/* Function Name:
 *      rtl8367c_getAsicSpanningTreeStatus
 * Description:
 *      Set spanning tree state per each port
 * Input:
 *      port 	- Physical port number (0~10)
 *      msti 	- Multiple spanning tree instance
 *      pState 	- Spanning tree state for msti
 * Output:
 *      None
 * Return:
 *      RT_ERR_OK 			- Success
 *      RT_ERR_SMI  		- SMI access error
 *      RT_ERR_MSTI  		- Invalid msti parameter
 *      RT_ERR_PORT_ID  	- Invalid port number
 * Note:
 *      None
 */
ret_t rtl8367c_getAsicSpanningTreeStatus(rtk_uint32 port, rtk_uint32 msti, rtk_uint32* pState)
{
	rtk_uint32  reg_addr,bits_msk;

    if(port > RTL8367C_PORTIDMAX)
        return RT_ERR_PORT_ID;

    if(msti > RTL8367C_MSTIMAX)
        return RT_ERR_MSTI;

	if(port < 8)
		return rtl8367c_getAsicRegBits(RTL8367C_VLAN_MSTI_REG(msti,port), RTL8367C_VLAN_MSTI_MASK(port), pState);
	else{
		reg_addr = RTL8367C_VLAN_MSTI_REG(msti,port);
		switch(port){
			case 8: bits_msk = RTL8367C_VLAN_MSTI0_CTRL1_PORT8_STATE_MASK;break;
			case 9: bits_msk = RTL8367C_VLAN_MSTI0_CTRL1_PORT9_STATE_MASK;break;
			case 10: bits_msk = RTL8367C_VLAN_MSTI0_CTRL1_PORT10_STATE_MASK;break;
		}
		return rtl8367c_getAsicRegBits(reg_addr, bits_msk, pState);
	}

}

/* Function Name:
 *      rtl8367c_setAsicVlanTransparent
 * Description:
 *      Set VLAN transparent
 * Input:
 *      port 		- Physical port number (0~10)
 *      portmask 	- portmask(0~0xFF)
 * Output:
 *      None
 * Return:
 *      RT_ERR_OK 			- Success
 *      RT_ERR_SMI  		- SMI access error
 *      RT_ERR_PORT_MASK  	- Invalid portmask
 *      RT_ERR_PORT_ID  	- Invalid port number
 * Note:
 *      None
 */
ret_t rtl8367c_setAsicVlanTransparent(rtk_uint32 port, rtk_uint32 portmask)
{
    if(port > RTL8367C_PORTIDMAX)
        return RT_ERR_PORT_ID;

    if(portmask > RTL8367C_PORTMASK)
        return RT_ERR_PORT_MASK;

    return rtl8367c_setAsicRegBits(RTL8367C_REG_VLAN_EGRESS_TRANS_CTRL0 + port, RTL8367C_VLAN_EGRESS_TRANS_CTRL0_MASK, portmask);
}

/* Function Name:
 *      rtl8367c_getAsicVlanTransparent
 * Description:
 *      Get VLAN transparent
 * Input:
 *      port 		- Physical port number (0~10)
 * Output:
 *      pPortmask   - Ingress port mask
 * Return:
 *      RT_ERR_OK 			- Success
 *      RT_ERR_SMI  		- SMI access error
 *      RT_ERR_PORT_MASK  	- Invalid portmask
 *      RT_ERR_PORT_ID  	- Invalid port number
 * Note:
 *      None
 */
ret_t rtl8367c_getAsicVlanTransparent(rtk_uint32 port, rtk_uint32 *pPortmask)
{
    if(port > RTL8367C_PORTIDMAX)
        return RT_ERR_PORT_ID;

    return rtl8367c_getAsicRegBits(RTL8367C_REG_VLAN_EGRESS_TRANS_CTRL0 + port, RTL8367C_VLAN_EGRESS_TRANS_CTRL0_MASK, pPortmask);
}

/* Function Name:
 *      rtl8367c_setAsicVlanEgressKeep
 * Description:
 *      Set per egress port VLAN keep mode
 * Input:
 *      port 		- Physical port number (0~10)
 *      portmask 	- portmask(0~0xFF)
 * Output:
 *      None
 * Return:
 *      RT_ERR_OK 			- Success
 *      RT_ERR_SMI  		- SMI access error
 *      RT_ERR_PORT_MASK  	- Invalid portmask
 *      RT_ERR_PORT_ID  	- Invalid port number
 * Note:
 *      None
 */
ret_t rtl8367c_setAsicVlanEgressKeep(rtk_uint32 port, rtk_uint32 portmask)
{
    rtk_uint32 regAddr, bit_mask;
    ret_t  retVal;

    if(port > RTL8367C_PORTIDMAX)
        return RT_ERR_PORT_ID;

    if(portmask > RTL8367C_PORTMASK)
        return RT_ERR_PORT_MASK;

	if(port < 8){
    	retVal = rtl8367c_setAsicRegBits(RTL8367C_REG_VLAN_EGRESS_KEEP_CTRL0 + (port>>1),RTL8367C_PORT0_VLAN_KEEP_MASK_MASK<<((port&1)*8),portmask & 0xff);
		if(retVal != RT_ERR_OK)
			return retVal;
		regAddr = RTL8367C_REG_VLAN_EGRESS_KEEP_CTRL0_EXT + (port>>1);
		bit_mask = RTL8367C_PORT0_VLAN_KEEP_MASK_EXT_MASK;
		bit_mask <<= (port&1)*3;
		retVal = rtl8367c_setAsicRegBits(regAddr, bit_mask, (portmask>>8)&0x7);
		if(retVal != RT_ERR_OK)
			return retVal;
	}
	else{
		switch(port){
			case 8:
				regAddr = RTL8367C_REG_VLAN_EGRESS_KEEP_CTRL4;
				bit_mask = RTL8367C_PORT8_VLAN_KEEP_MASK_MASK;
				retVal = rtl8367c_setAsicRegBits(regAddr, bit_mask, portmask & 0xff);
				if(retVal != RT_ERR_OK)
					return retVal;
				regAddr = RTL8367C_REG_VLAN_EGRESS_KEEP_CTRL4_EXT;
				bit_mask = RTL8367C_PORT8_VLAN_KEEP_MASK_EXT_MASK;
				retVal = rtl8367c_setAsicRegBits(regAddr, bit_mask, (portmask>>8)&0x7);
				if(retVal != RT_ERR_OK)
					return retVal;
				break;

			case 9:
				regAddr = RTL8367C_REG_VLAN_EGRESS_KEEP_CTRL4;
				bit_mask = RTL8367C_PORT9_VLAN_KEEP_MASK_MASK;
				retVal = rtl8367c_setAsicRegBits(regAddr, bit_mask, portmask & 0xff);
				if(retVal != RT_ERR_OK)
					return retVal;
				regAddr = RTL8367C_REG_VLAN_EGRESS_KEEP_CTRL4_EXT;
				bit_mask = RTL8367C_PORT9_VLAN_KEEP_MASK_EXT_MASK;
				retVal = rtl8367c_setAsicRegBits(regAddr, bit_mask, (portmask>>8)&0x7);
				if(retVal != RT_ERR_OK)
					return retVal;
				break;

			case 10:
				regAddr = RTL8367C_REG_VLAN_EGRESS_KEEP_CTRL5;
				bit_mask = RTL8367C_VLAN_EGRESS_KEEP_CTRL5_MASK;
				retVal = rtl8367c_setAsicRegBits(regAddr, bit_mask, portmask & 0xff);
				if(retVal != RT_ERR_OK)
					return retVal;
				regAddr = RTL8367C_REG_VLAN_EGRESS_KEEP_CTRL5_EXT;
				bit_mask = RTL8367C_VLAN_EGRESS_KEEP_CTRL5_EXT_MASK;
				retVal = rtl8367c_setAsicRegBits(regAddr, bit_mask, (portmask>>8)&0x7);
				if(retVal != RT_ERR_OK)
					return retVal;
				break;
		}
	}

	return RT_ERR_OK;
}

/* Function Name:
 *      rtl8367c_getAsicVlanEgressKeep
 * Description:
 *      Get per egress port VLAN keep mode
 * Input:
 *      port 		- Physical port number (0~7)
 *      pPortmask 	- portmask(0~0xFF)
 * Output:
 *      None
 * Return:
 *      RT_ERR_OK 		- Success
 *      RT_ERR_SMI  	- SMI access error
 *      RT_ERR_PORT_ID  - Invalid port number
 * Note:
 *      None
 */
ret_t rtl8367c_getAsicVlanEgressKeep(rtk_uint32 port, rtk_uint32* pPortmask)
{
    rtk_uint32 regAddr, bit_mask, regval_l, regval_h;
    ret_t  retVal;

    if(port > RTL8367C_PORTIDMAX)
        return RT_ERR_PORT_ID;

	if(port < 8){
    	retVal = rtl8367c_getAsicRegBits(RTL8367C_REG_VLAN_EGRESS_KEEP_CTRL0 + (port>>1),RTL8367C_PORT0_VLAN_KEEP_MASK_MASK<<((port&1)*8),&regval_l);
		if(retVal != RT_ERR_OK)
			return retVal;
		regAddr = RTL8367C_REG_VLAN_EGRESS_KEEP_CTRL0_EXT + (port>>1);
		bit_mask = RTL8367C_PORT0_VLAN_KEEP_MASK_EXT_MASK;
		bit_mask <<= (port&1)*3;
		retVal = rtl8367c_getAsicRegBits(regAddr, bit_mask, &regval_h);
		if(retVal != RT_ERR_OK)
			return retVal;
		*pPortmask = (regval_h << 8) | regval_l;
	}
	else{
		switch(port){
			case 8:
				regAddr = RTL8367C_REG_VLAN_EGRESS_KEEP_CTRL4;
				bit_mask = RTL8367C_PORT8_VLAN_KEEP_MASK_MASK;
				retVal = rtl8367c_getAsicRegBits(regAddr, bit_mask, &regval_l);
				if(retVal != RT_ERR_OK)
					return retVal;
				regAddr = RTL8367C_REG_VLAN_EGRESS_KEEP_CTRL4_EXT;
				bit_mask = RTL8367C_PORT8_VLAN_KEEP_MASK_EXT_MASK;
				retVal = rtl8367c_getAsicRegBits(regAddr, bit_mask, &regval_h);
				if(retVal != RT_ERR_OK)
					return retVal;

				*pPortmask = (regval_h << 8) | regval_l;
				break;

			case 9:
				regAddr = RTL8367C_REG_VLAN_EGRESS_KEEP_CTRL4;
				bit_mask = RTL8367C_PORT9_VLAN_KEEP_MASK_MASK;
				retVal = rtl8367c_getAsicRegBits(regAddr, bit_mask, &regval_l);
				if(retVal != RT_ERR_OK)
					return retVal;
				regAddr = RTL8367C_REG_VLAN_EGRESS_KEEP_CTRL4_EXT;
				bit_mask = RTL8367C_PORT9_VLAN_KEEP_MASK_EXT_MASK;
				retVal = rtl8367c_getAsicRegBits(regAddr, bit_mask, &regval_h);
				if(retVal != RT_ERR_OK)
					return retVal;

				*pPortmask = (regval_h << 8) | regval_l;
				break;

			case 10:
				regAddr = RTL8367C_REG_VLAN_EGRESS_KEEP_CTRL5;
				bit_mask = RTL8367C_VLAN_EGRESS_KEEP_CTRL5_MASK;
				retVal = rtl8367c_getAsicRegBits(regAddr, bit_mask, &regval_l);
				if(retVal != RT_ERR_OK)
					return retVal;
				regAddr = RTL8367C_REG_VLAN_EGRESS_KEEP_CTRL5_EXT;
				bit_mask = RTL8367C_VLAN_EGRESS_KEEP_CTRL5_EXT_MASK;
				retVal = rtl8367c_getAsicRegBits(regAddr, bit_mask, &regval_h);
				if(retVal != RT_ERR_OK)
					return retVal;

				*pPortmask = (regval_h << 8) | regval_l;
				break;
		}
	}

	return RT_ERR_OK;
}

/* Function Name:
 *      rtl8367c_setReservedVidAction
 * Description:
 *      Set reserved VID action
 * Input:
 *      vid0Action 		- VID 0 action
 *      vid4095Action 	- VID 4095 action
 * Output:
 *      None
 * Return:
 *      RT_ERR_OK 		- Success
 *      RT_ERR_SMI  	- SMI access error
 *      RT_ERR_INPUT    - Error input
 * Note:
 *      None
 */
ret_t rtl8367c_setReservedVidAction(rtk_uint32 vid0Action, rtk_uint32 vid4095Action)
{
    ret_t   retVal;

    if(vid0Action >= RES_VID_ACT_END)
        return RT_ERR_INPUT;

    if(vid4095Action >= RES_VID_ACT_END)
        return RT_ERR_INPUT;

    if((retVal = rtl8367c_setAsicRegBit(RTL8367C_REG_VLAN_EXT_CTRL, RTL8367C_VLAN_VID0_TYPE_OFFSET, vid0Action)) != RT_ERR_OK)
        return retVal;

    if((retVal = rtl8367c_setAsicRegBit(RTL8367C_REG_VLAN_EXT_CTRL, RTL8367C_VLAN_VID4095_TYPE_OFFSET, vid4095Action)) != RT_ERR_OK)
        return retVal;

    return RT_ERR_OK;
}

/* Function Name:
 *      rtl8367c_getReservedVidAction
 * Description:
 *      Get reserved VID action
 * Input:
 *      pVid0Action 	- VID 0 action
 *      pVid4095Action 	- VID 4095 action
 * Output:
 *      None
 * Return:
 *      RT_ERR_OK 		    - Success
 *      RT_ERR_SMI  	    - SMI access error
 *      RT_ERR_NULL_POINTER - Null pointer
 * Note:
 *      None
 */
ret_t rtl8367c_getReservedVidAction(rtk_uint32 *pVid0Action, rtk_uint32 *pVid4095Action)
{
    ret_t   retVal;

    if(pVid0Action == NULL)
        return RT_ERR_NULL_POINTER;

    if(pVid4095Action == NULL)
        return RT_ERR_NULL_POINTER;

    if((retVal = rtl8367c_getAsicRegBit(RTL8367C_REG_VLAN_EXT_CTRL, RTL8367C_VLAN_VID0_TYPE_OFFSET, pVid0Action)) != RT_ERR_OK)
        return retVal;

    if((retVal = rtl8367c_getAsicRegBit(RTL8367C_REG_VLAN_EXT_CTRL, RTL8367C_VLAN_VID4095_TYPE_OFFSET, pVid4095Action)) != RT_ERR_OK)
        return retVal;

    return RT_ERR_OK;

}

/* Function Name:
 *      rtl8367c_setRealKeepRemarkEn
 * Description:
 *      Set Real Keep Remark
 * Input:
 *      enabled 		- 0: 1P remarking is forbidden at real keep packet, 1: 1P remarking is enabled at real keep packet
 * Output:
 *      None
 * Return:
 *      RT_ERR_OK 		- Success
 *      RT_ERR_SMI  	- SMI access error
 *      RT_ERR_INPUT    - Error input
 * Note:
 *      None
 */
ret_t rtl8367c_setRealKeepRemarkEn(rtk_uint32 enabled)
{
    ret_t   retVal;

    if((retVal = rtl8367c_setAsicRegBit(RTL8367C_REG_VLAN_EXT_CTRL, RTL8367C_VLAN_1P_REMARK_BYPASS_REALKEEP_OFFSET, enabled)) != RT_ERR_OK)
        return retVal;

    return RT_ERR_OK;
}

/* Function Name:
 *      rtl8367c_getRealKeepRemarkEn
 * Description:
 *      Get Real Keep Remark
 * Input:
 *      None
 * Output:
 *      pEnabled 		- 0: 1P remarking is forbidden at real keep packet, 1: 1P remarking is enabled at real keep packet
 * Return:
 *      RT_ERR_OK 		- Success
 *      RT_ERR_SMI  	- SMI access error
 *      RT_ERR_INPUT    - Error input
 * Note:
 *      None
 */
ret_t rtl8367c_getRealKeepRemarkEn(rtk_uint32 *pEnabled)
{
    ret_t   retVal;

    if((retVal = rtl8367c_getAsicRegBit(RTL8367C_REG_VLAN_EXT_CTRL, RTL8367C_VLAN_1P_REMARK_BYPASS_REALKEEP_OFFSET, pEnabled)) != RT_ERR_OK)
        return retVal;

    return RT_ERR_OK;
}

/* Function Name:
 *      rtl8367c_resetVlan
 * Description:
 *      Reset VLAN table
 * Input:
 *      None.
 * Output:
 *      None.
 * Return:
 *      RT_ERR_OK 		- Success
 *      RT_ERR_SMI  	- SMI access error
 * Note:
 *      None
 */
ret_t rtl8367c_resetVlan(void)
{
    ret_t   retVal;

    if((retVal = rtl8367c_setAsicRegBit(RTL8367C_REG_VLAN_EXT_CTRL2, RTL8367C_VLAN_EXT_CTRL2_OFFSET, 1)) != RT_ERR_OK)
        return retVal;

    return RT_ERR_OK;
}

