/*
 * 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$
 * $Date$
 *
 * Purpose : RTL8367C switch high-level API for RTL8367C
 * Feature : VLAN related functions
 *
 */
#include <rtl8367c_asicdrv_vlan.h>

#include <string.h>

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

static void _rtl8367c_VlanMCStUser2Smi(rtl8367c_vlanconfiguser *pVlanCg, rtk_uint16 *pSmiVlanCfg)
{
    pSmiVlanCfg[0] |= pVlanCg->mbr & 0x07FF;

    pSmiVlanCfg[1] |= pVlanCg->fid_msti & 0x000F;

    pSmiVlanCfg[2] |= pVlanCg->vbpen & 0x0001;
    pSmiVlanCfg[2] |= (pVlanCg->vbpri & 0x0007) << 1;
    pSmiVlanCfg[2] |= (pVlanCg->envlanpol & 0x0001) << 4;
    pSmiVlanCfg[2] |= (pVlanCg->meteridx & 0x003F) << 5;

    pSmiVlanCfg[3] |= pVlanCg->evid & 0x1FFF;
}

static void _rtl8367c_VlanMCStSmi2User(rtk_uint16 *pSmiVlanCfg, rtl8367c_vlanconfiguser *pVlanCg)
{
    pVlanCg->mbr            = pSmiVlanCfg[0] & 0x07FF;
    pVlanCg->fid_msti       = pSmiVlanCfg[1] & 0x000F;
    pVlanCg->meteridx       = (pSmiVlanCfg[2] >> 5) & 0x003F;
    pVlanCg->envlanpol      = (pSmiVlanCfg[2] >> 4) & 0x0001;
    pVlanCg->vbpri          = (pSmiVlanCfg[2] >> 1) & 0x0007;
    pVlanCg->vbpen          = pSmiVlanCfg[2] & 0x0001;
    pVlanCg->evid           = pSmiVlanCfg[3] & 0x1FFF;
}

static void _rtl8367c_Vlan4kStUser2Smi(rtl8367c_user_vlan4kentry *pUserVlan4kEntry, rtk_uint16 *pSmiVlan4kEntry)
{
    pSmiVlan4kEntry[0] |= (pUserVlan4kEntry->mbr & 0x00FF);
    pSmiVlan4kEntry[0] |= (pUserVlan4kEntry->untag & 0x00FF) << 8;

    pSmiVlan4kEntry[1] |= (pUserVlan4kEntry->fid_msti & 0x000F);
    pSmiVlan4kEntry[1] |= (pUserVlan4kEntry->vbpen & 0x0001) << 4;
    pSmiVlan4kEntry[1] |= (pUserVlan4kEntry->vbpri & 0x0007) << 5;
    pSmiVlan4kEntry[1] |= (pUserVlan4kEntry->envlanpol & 0x0001) << 8;
    pSmiVlan4kEntry[1] |= (pUserVlan4kEntry->meteridx & 0x001F) << 9;
    pSmiVlan4kEntry[1] |= (pUserVlan4kEntry->ivl_svl & 0x0001) << 14;

    pSmiVlan4kEntry[2] |= ((pUserVlan4kEntry->mbr & 0x0700) >> 8);
    pSmiVlan4kEntry[2] |= ((pUserVlan4kEntry->untag & 0x0700) >> 8) << 3;
    pSmiVlan4kEntry[2] |= ((pUserVlan4kEntry->meteridx & 0x0020) >> 5) << 6;
}


static void _rtl8367c_Vlan4kStSmi2User(rtk_uint16 *pSmiVlan4kEntry, rtl8367c_user_vlan4kentry *pUserVlan4kEntry)
{
    pUserVlan4kEntry->mbr = (pSmiVlan4kEntry[0] & 0x00FF) | ((pSmiVlan4kEntry[2] & 0x0007) << 8);
    pUserVlan4kEntry->untag = ((pSmiVlan4kEntry[0] & 0xFF00) >> 8) | (((pSmiVlan4kEntry[2] & 0x0038) >> 3) << 8);
    pUserVlan4kEntry->fid_msti = pSmiVlan4kEntry[1] & 0x000F;
    pUserVlan4kEntry->vbpen = (pSmiVlan4kEntry[1] & 0x0010) >> 4;
    pUserVlan4kEntry->vbpri = (pSmiVlan4kEntry[1] & 0x00E0) >> 5;
    pUserVlan4kEntry->envlanpol = (pSmiVlan4kEntry[1] & 0x0100) >> 8;
    pUserVlan4kEntry->meteridx = ((pSmiVlan4kEntry[1] & 0x3E00) >> 9) | (((pSmiVlan4kEntry[2] & 0x0040) >> 6) << 5);
    pUserVlan4kEntry->ivl_svl = (pSmiVlan4kEntry[1] & 0x4000) >> 14;
}

/* 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;
    rtk_uint16 smi_vlancfg[RTL8367C_VLAN_MBRCFG_LEN];

    /* 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(rtk_uint16) * RTL8367C_VLAN_MBRCFG_LEN);
    _rtl8367c_VlanMCStUser2Smi(pVlanCg, smi_vlancfg);
    tableAddr = 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;
    rtk_uint16 smi_vlancfg[RTL8367C_VLAN_MBRCFG_LEN];

    if(index > RTL8367C_CVIDXMAX)
        return RT_ERR_VLAN_ENTRY_NOT_FOUND;

    memset(smi_vlancfg, 0x00, sizeof(rtk_uint16) * RTL8367C_VLAN_MBRCFG_LEN);
    tableAddr  = 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 )
{
    rtk_uint16              vlan_4k_entry[RTL8367C_VLAN_4KTABLE_LEN];
    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(rtk_uint16) * RTL8367C_VLAN_4KTABLE_LEN);
    _rtl8367c_Vlan4kStUser2Smi(pVlan4kEntry, vlan_4k_entry);

    /* Prepare Data */
    tableAddr = vlan_4k_entry;
    for(page_idx = 0; page_idx < RTL8367C_VLAN_4KTABLE_LEN; 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], pVlan4kEntry, sizeof(rtl8367c_user_vlan4kentry));
#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 )
{
    rtk_uint16                  vlan_4k_entry[RTL8367C_VLAN_4KTABLE_LEN];
    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 = vlan_4k_entry;
    for(page_idx = 0; page_idx < RTL8367C_VLAN_4KTABLE_LEN; 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)
    memcpy(pVlan4kEntry, &Rtl8370sVirtualVlanTable[pVlan4kEntry->vid], sizeof(rtl8367c_user_vlan4kentry));
#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)
{
    rtk_uint32 regData;
    ret_t  retVal;

    if(port > RTL8367C_PORTIDMAX)
        return RT_ERR_PORT_ID;

    if((retVal = rtl8367c_getAsicRegBits(RTL8367C_VLAN_ACCEPT_FRAME_TYPE_REG(port), RTL8367C_VLAN_ACCEPT_FRAME_TYPE_MASK(port), &regData)) != RT_ERR_OK)
        return retVal;

    *pFrameType = (rtl8367c_accframetype)regData;
    return RT_ERR_OK;
}
/* 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)
{
    rtk_uint32 regData;
    ret_t  retVal;

    if(port > RTL8367C_PORTIDMAX)
        return RT_ERR_PORT_ID;

    if((retVal = rtl8367c_getAsicRegBits(RTL8367C_PORT_MISC_CFG_REG(port), RTL8367C_VLAN_EGRESS_MDOE_MASK, &regData)) != RT_ERR_OK)
        return retVal;

    *pTagMode = (rtl8367c_egtagmode)regData;
    return RT_ERR_OK;
}
/* 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);
    }
    else if(port == 8)
    {
        reg_addr = RTL8367C_REG_VLAN_PPB0_CTRL4;
        bit_mask = RTL8367C_VLAN_PPB0_CTRL4_PORT8_INDEX_MASK;
    }
    else if(port == 9)
    {
        reg_addr = RTL8367C_REG_VLAN_PPB0_CTRL4;
        bit_mask = RTL8367C_VLAN_PPB0_CTRL4_PORT9_INDEX_MASK;
    }
    else if(port == 10)
    {
        reg_addr = RTL8367C_REG_VLAN_PPB0_CTRL4;
        bit_mask = RTL8367C_VLAN_PPB0_CTRL4_PORT10_INDEX_MASK;
    }

    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 if(port == 8)
    {
        reg_addr = RTL8367C_REG_VLAN_PPB0_CTRL4;
        bit_mask = RTL8367C_VLAN_PPB0_CTRL4_PORT8_INDEX_MASK;
    }
    else if(port == 9)
    {
        reg_addr = RTL8367C_REG_VLAN_PPB0_CTRL4;
        bit_mask = RTL8367C_VLAN_PPB0_CTRL4_PORT9_INDEX_MASK;
    }
    else if(port == 10)
    {
        reg_addr = RTL8367C_REG_VLAN_PPB0_CTRL4;
        bit_mask = RTL8367C_VLAN_PPB0_CTRL4_PORT10_INDEX_MASK;
    }

    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;
            default:
                return RT_ERR_PORT_ID;
        }

        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;
            default:
                return RT_ERR_PORT_ID;
        }

        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;
}

