[rdkb][common][bsp][Refactor and sync kernel from openwrt]

[Description]
9627c280 [CRITICAL][kernel][mt7988][eth][Fix issue of PSE hanging when the internal 2.5G PHY connection is disconnected]
ef2c790d [openwrt][common][config][Add AN8855 dsa and gsw config in alphabetical order]
97f46542 [MAC80211][hnat][Improve ETH to ETH performace in an unbalanced PHY rate test for mt7981/7986]
ab061242 [openwrt][common][bsp][Add support to reset boot count of dual image booting]
dff562ec [openwrt][common][bsp][Refactor dual image related patches]
4041ddc5 [CRITICAL][kernel][mt7988][eth][Increase CDM2 guard band settings to 4KB]
d8bd64af [kernel][mt7981][eth][Fix issue of GMAC RX hanging when internal GPHY connect to a legacy 10M/Half hub]
f8e2de72 [CRITICAL][kernel][mt7988][eth][Fix issue of transmitting abnormal data for SGMII]
84c34a72 [openwrt][mt7988][crypto][Fix 3 PPE issue for IPSec]
2f5b874e [MAC80211][hnat][Fix issue of multiple PPEs unbind for ETH in mt7981/7986]
15456702 [openwrt][common][network][Upgrade lldpd from 1.0.17 release 2 to release 3]
3d01da2e [openwrt][common][app][Fix switch cmd netlink issue on mt7988]
8d49660c [kernel][common][dts][Fix the mt7981 with an8855 syntax error dts]
88339b3b [kernel][common][hnat][Fix HNAT BIND issue with entry index 0x3fff]
9c805693 [openwrt][common][app][Add an8855 switch command support]
4cadd12b [openwrt][common][app][Refactor switch command to support switches with different design]
ba8a98e4 [kernel][common][net][Add AN8855 dsa and gsw driver]
6adb18b9 [kernel][common][hnat][Add PPE config to compare source PSE port as hit condition]
99170889 [kernel][common][eth][Add the new firmware for Aquantia AQR113C and CUX3410]
f634629e [kernel][mt7988][eth][macsec: Remove CK_TOP_NETSYS_TOPS_400M_SEL since it's not relevant]
f868325b [kernel][common][eth][Add Aquantia CUX3410 support]
6f2ddbf0 [openwrt][mt7988][tops][fix 3 PPE feature issue]
ff49cc9f [kernel][common][Refactor network backport patch path]
2c9fda11 [kernel][mtd/spi/nmbm/phy/][Change pending-5.4 & backport-5.4 files to correct folder]

[Release-log]

Change-Id: I793a18f2f96f185687080a0fb6b55379995b0398
diff --git a/recipes-devtools/switch/files/src/Makefile b/recipes-devtools/switch/files/src/Makefile
index 81ae127..1d88a8c 100644
--- a/recipes-devtools/switch/files/src/Makefile
+++ b/recipes-devtools/switch/files/src/Makefile
@@ -1,6 +1,10 @@
 EXEC = switch
 
 SRC=switch_fun.c switch_753x.c switch_ioctl.c switch_netlink.c
+SRC+=switch_fun_an8855.c an8855_sdk/api/src/*.c
+
+CFLAGS+=-I./an8855_sdk/api/inc
+CFLAGS+=-DCOMPAT_MODE
 
 all: $(EXEC)
 
diff --git a/recipes-devtools/switch/files/src/an8855_sdk/api/inc/air.h b/recipes-devtools/switch/files/src/an8855_sdk/api/inc/air.h
new file mode 100644
index 0000000..c62174f
--- /dev/null
+++ b/recipes-devtools/switch/files/src/an8855_sdk/api/inc/air.h
@@ -0,0 +1,216 @@
+/* FILE NAME:   air.h

+ * PURPOSE:

+ *      Define the initialization in AIR SDK.

+ * NOTES:

+ */

+

+#ifndef AIR_H

+#define AIR_H

+

+/* INCLUDE FILE DECLARATIONS

+ */

+#include <stdio.h>

+#include <string.h>

+#include "air_types.h"

+#include "air_error.h"

+#include "air_reg.h"

+#include "air_aml.h"

+#include "air_port.h"

+#include "air_vlan.h"

+#include "air_lag.h"

+#include "air_l2.h"

+#include "air_stp.h"

+#include "air_mirror.h"

+#include "air_mib.h"

+#include "air_diag.h"

+#include "air_led.h"

+#include "air_cmd.h"

+#include "air_qos.h"

+#include "air_switch.h"

+#include "air_ver.h"

+#include "air_sec.h"

+#include "air_acl.h"

+#include "air_sptag.h"

+

+/* NAMING CONSTANT DECLARATIONS

+ */

+

+/* MACRO FUNCTION DECLARATIONS

+ */

+#define AIR_CHECK_PTR(__ptr__) do                                          \

+{                                                                           \

+    if (NULL == (__ptr__))                                                  \

+    {                                                                       \

+        return  AIR_E_BAD_PARAMETER;                                       \

+    }                                                                       \

+} while (0)

+

+#define AIR_PARAM_CHK(expr, errCode) do                                    \

+{                                                                           \

+    if ((I32_T)(expr))                                                      \

+    {                                                                       \

+        return errCode;                                                     \

+    }                                                                       \

+} while (0)

+

+#define AIR_PRINT(fmt,...) do                                              \

+{                                                                           \

+    if (_ext_printf)                                                        \

+    {                                                                       \

+        _ext_printf(fmt, ##__VA_ARGS__);                                    \

+    }                                                                       \

+}while (0)

+

+#define AIR_UDELAY(us) do                                                  \

+{                                                                           \

+    if (_ext_udelay)                                                        \

+    {                                                                       \

+        _ext_udelay(us);                                                    \

+    }                                                                       \

+}while (0)

+

+#define AIR_MALLOC(size) (_ext_malloc ? _ext_malloc(size) : NULL)

+

+#define AIR_FREE(ptr) do                                                   \

+    {                                                                       \

+        if (ptr && _ext_free)                                               \

+        {                                                                   \

+            _ext_free(ptr);                                                 \

+        }                                                                   \

+    }while (0)

+

+#ifndef BIT

+#define BIT(nr) (1UL << (nr))

+#endif	/* End of BIT */

+

+/* bits range: for example BITS(16,23) = 0xFF0000*/

+#ifndef BITS

+#define BITS(m, n)   (~(BIT(m) - 1) & ((BIT(n) - 1) | BIT(n)))

+#endif	/* End of BITS */

+

+/* bits range: for example BITS_RANGE(16,4) = 0x0F0000*/

+#ifndef BITS_RANGE

+#define BITS_RANGE(offset, range)   BITS(offset, ((offset)+(range)-1))

+#endif	/* End of BITS_RANGE */

+

+/* bits offset right: for example BITS_OFF_R(0x1234, 8, 4) = 0x2 */

+#ifndef BITS_OFF_R

+#define BITS_OFF_R(val, offset, range)   ((val >> offset) & (BIT(range) - 1))

+#endif	/* End of BITS_OFF_R */

+

+/* bits offset left: for example BITS_OFF_L(0x1234, 8, 4) = 0x400 */

+#ifndef BITS_OFF_L

+#define BITS_OFF_L(val, offset, range)   ((val & (BIT(range) - 1)) << offset)

+#endif	/* End of BITS_OFF_L */

+

+#ifndef MAX

+#define MAX(a, b)   (((a)>(b))?(a):(b))

+#endif	/* End of MAX */

+

+#ifndef MIN

+#define MIN(a, b)   (((a)<(b))?(a):(b))

+#endif	/* End of MIN */

+

+/* DATA TYPE DECLARATIONS

+ */

+typedef AIR_ERROR_NO_T

+(*AIR_PRINTF)(

+    C8_T* fmt,

+    ...);

+

+typedef void

+(*AIR_UDELAY)(

+    UI32_T us);

+

+typedef void*

+(*AIR_MALLOC)(

+    UI32_T size);

+

+typedef void

+(*AIR_FREE)(

+    void *ptr);

+

+typedef struct

+{

+    AML_DEV_ACCESS_T    dev_access;

+    AIR_PRINTF         printf;

+    AIR_UDELAY         udelay;

+    AIR_MALLOC         malloc;

+    AIR_FREE           free;

+}AIR_INIT_PARAM_T;

+

+/* EXPORTED SUBPROGRAM SPECIFICATIONS

+ */

+extern AIR_PRINTF _ext_printf;

+extern AIR_UDELAY _ext_udelay;

+extern AIR_MALLOC _ext_malloc;

+extern AIR_FREE   _ext_free;

+

+

+/* FUNCTION NAME:   air_init

+ * PURPOSE:

+ *      This API is used to initialize the SDK.

+ *

+ * INPUT:

+ *      unit            --  The device unit

+ *      ptr_init_param  --  The sdk callback functions.

+ *

+ * OUTPUT:

+ *      None

+ *

+ * RETURN:

+ *      AIR_E_OK

+ *      AIR_E_OTHERS

+ *

+ * NOTES:

+ *      None

+ */

+AIR_ERROR_NO_T

+air_init(

+    const UI32_T unit,

+    AIR_INIT_PARAM_T *ptr_init_param);

+

+/* FUNCTION NAME:   air_hw_reset

+ * PURPOSE:

+ *      This API is used to reset hardware.

+ *

+ * INPUT:

+ *      unit            --  The device unit

+ *

+ * OUTPUT:

+ *      None

+ *

+ * RETURN:

+ *      AIR_E_OK

+ *      AIR_E_OTHERS

+ *

+ * NOTES:

+ *      None

+ */

+AIR_ERROR_NO_T

+air_hw_reset(

+    const UI32_T unit);

+

+/* FUNCTION NAME:   air_set_gpio_pin_mux

+ * PURPOSE:

+ *      This API is used to set gpio pin mux.

+ *

+ * INPUT:

+ *      unit            --  The device unit

+ *

+ * OUTPUT:

+ *      None

+ *

+ * RETURN:

+ *      AIR_E_OK

+ *      AIR_E_OTHERS

+ *

+ * NOTES:

+ *      None

+ */

+AIR_ERROR_NO_T

+air_set_gpio_pin_mux(

+    const UI32_T unit);

+

+#endif  /* AIR_H */

+

diff --git a/recipes-devtools/switch/files/src/an8855_sdk/api/inc/air_acl.h b/recipes-devtools/switch/files/src/an8855_sdk/api/inc/air_acl.h
new file mode 100644
index 0000000..f4ea6c9
--- /dev/null
+++ b/recipes-devtools/switch/files/src/an8855_sdk/api/inc/air_acl.h
@@ -0,0 +1,1245 @@
+/* FILE NAME: air_acl.h
+ * PURPOSE:
+ *      Define the ACL function in AIR SDK.
+ *
+ * NOTES:
+ *      None
+ */
+
+#ifndef AIR_ACL_H
+#define AIR_ACL_H
+
+/* INCLUDE FILE DECLARATIONS
+*/
+
+/* NAMING CONSTANT DECLARATIONS
+*/
+#define ACL_MAX_BUSY_TIME            (20)
+#define ACL_MAX_RULE_NUM             (128)
+#define ACL_MAX_ACTION_NUM           (128)
+#define ACL_MAX_TRTCM_NUM            (32)
+#define ACL_MAX_MIB_NUM              (64)
+#define ACL_MAX_UDF_NUM              (16)
+#define ACL_MAX_METER_NUM            (32)
+#define ACL_MAX_MIR_SESSION_NUM      (2)
+#define ACL_MAX_TOKEN_NUM            (0xffff)
+#define ACL_MAX_VLAN_NUM             (4096)
+#define ACL_MAX_DROP_PCD_NUM         (8)
+#define ACL_MAX_CLASS_SLR_NUM        (8)
+#define ACL_MAX_ATTACK_RATE_NUM      (96)
+#define ACL_MAX_WORD_OFST_NUM        (128)
+#define ACL_MAX_CMP_PAT_NUM          (0xffff)
+#define ACL_MAX_CMP_BIT_NUM          (0xffff)
+#define ACL_MAX_CBS_NUM              (0xffff)
+#define ACL_MAX_CIR_NUM              (0xffff)
+#define ACL_MAX_PBS_NUM              (0xffff)
+#define ACL_MAX_PIR_NUM              (0xffff)
+
+#define ACL_EN_MASK                  (0x1)
+#define ACL_MEM_CFG_DONE_OFFSET      (31)
+#define ACL_MEM_CFG_RULE_ID_OFFSET   (16)
+#define ACL_MEM_CFG_TCAM_CELL_OFFSET (12)
+#define ACL_MEM_CFG_DATA_BN_OFFSET   (8)
+#define ACL_MEM_CFG_MEM_SEL_OFFSET   (4)
+#define ACL_MEM_CFG_FUNC_SEL_OFFSET  (1)
+#define ACL_MEM_CFG_EN               (1)
+
+#define ACL_MIB_SEL_OFFSET           (4)
+#define ACL_MIB_CLEAR                (1)
+#define ACL_MIB_SEL_MASK             (0x3f)
+#define ACL_TRTCM_EN_OFFSET          (31)
+#define ACL_TRTCM_BUSY_OFFSET        (31)
+#define ACL_TRTCM_WRITE              (1U << 27)
+#define ACL_TRTCM_READ               (0U << 27)
+#define ACL_TRTCM_ID_OFFSET          (0)
+#define ACL_TRTCM_ID_MASK            (0x1f)
+#define ACL_TRTCM_CBS_MASK           (0xffff)
+#define ACL_TRTCM_EBS_MASK           (0xffff)
+#define ACL_TRTCM_CIR_MASK           (0xffff)
+#define ACL_TRTCM_EIR_MASK           (0xffff)
+#define ACL_RATE_BUSY_OFFSET         (31)
+#define ACL_RATE_WRITE               (1U << 30)
+#define ACL_RATE_READ                (0U << 30)
+#define ACL_RATE_ID_OFFSET           (20)
+#define ACL_RATE_ID_MASK             (0x1f)
+#define ACL_RATE_EN_OFFSET           (19)
+#define ACL_RATE_EN                  (1U << 19)
+#define ACL_RATE_DIS                 (0U << 19)
+#define ACL_RATE_TOKEN_MASK          (0xffff)
+
+/*ACL rule field offset and width*/
+#define RULE_TYPE0_OFFSET            (0)
+#define DMAC_OFFSET                  (1)
+#define SMAC_OFFSET                  (49)
+#define STAG_OFFSET                  (97)
+#define CTAG_OFFSET                  (113)
+#define ETYPE_OFFSET                 (129)
+#define DIP_OFFSET                   (145)
+#define SIP_OFFSET                   (177)
+#define DSCP_OFFSET                  (209)
+#define PROTOCOL_OFFSET              (217)
+#define DPORT_OFFSET                 (225)
+#define SPORT_OFFSET                 (241)
+#define UDF_OFFSET                   (257)
+#define FIELDMAP_OFFSET              (273)
+#define IS_IPV6_OFFSET               (286)
+#define PORTMAP_OFFSET               (287)
+
+#define RULE_TYPE1_OFFSET            (0)
+#define DIP_IPV6_OFFSET              (1)
+#define SIP_IPV6_OFFSET              (97)
+#define FLOW_LABEL_OFFSET            (193)
+
+#define RULE_TYPE0_WIDTH            (1)
+#define DMAC_WIDTH                  (8)
+#define SMAC_WIDTH                  (8)
+#define STAG_WIDTH                  (16)
+#define CTAG_WIDTH                  (16)
+#define ETYPE_WIDTH                 (16)
+#define DIP_WIDTH                   (32)
+#define SIP_WIDTH                   (32)
+#define DSCP_WIDTH                  (8)
+#define PROTOCOL_WIDTH              (8)
+#define DPORT_WIDTH                 (16)
+#define SPORT_WIDTH                 (16)
+#define UDF_WIDTH                   (16)
+#define FIELDMAP_WIDTH              (13)
+#define IS_IPV6_WIDTH               (1)
+#define PORTMAP_WIDTH               (7)
+
+#define RULE_TYPE1_WIDTH            (1)
+#define DIP_IPV6_WIDTH              (32)
+#define SIP_IPV6_WIDTH              (32)
+#define FLOW_LABEL_WIDTH            (20)
+
+/*ACL action offset and width*/
+#define ACL_VLAN_VID_OFFSET         (0)
+#define ACL_VLAN_HIT_OFFSET         (12)
+#define ACL_CLASS_IDX_OFFSET        (13)
+#define ACL_TCM_OFFSET              (18)
+#define ACL_TCM_SEL_OFFSET          (20)
+#define ACL_DROP_PCD_G_OFFSET       (21)
+#define ACL_DROP_PCD_Y_OFFSET       (24)
+#define ACL_DROP_PCD_R_OFFSET       (27)
+#define CLASS_SLR_OFFSET            (30)
+#define CLASS_SLR_SEL_OFFSET        (33)
+#define DROP_PCD_SEL_OFFSET         (34)
+#define TRTCM_EN_OFFSET             (35)
+#define ACL_MANG_OFFSET             (36)
+#define LKY_VLAN_OFFSET             (37)
+#define LKY_VLAN_EN_OFFSET          (38)
+#define EG_TAG_OFFSET               (39)
+#define EG_TAG_EN_OFFSET            (42)
+#define PRI_USER_OFFSET             (43)
+#define PRI_USER_EN_OFFSET          (46)
+#define MIRROR_OFFSET               (47)
+#define FW_PORT_OFFSET              (49)
+#define PORT_FW_EN_OFFSET           (52)
+#define RATE_INDEX_OFFSET           (53)
+#define RATE_EN_OFFSET              (58)
+#define ATTACK_RATE_ID_OFFSET       (59)
+#define ATTACK_RATE_EN_OFFSET       (66)
+#define ACL_MIB_ID_OFFSET           (67)
+#define ACL_MIB_EN_OFFSET           (73)
+#define VLAN_PORT_SWAP_OFFSET       (74)
+#define DST_PORT_SWAP_OFFSET        (75)
+#define BPDU_OFFSET                 (76)
+#define PORT_OFFSET                 (77)
+#define PORT_FORCE_OFFSET           (84)
+
+#define ACL_VLAN_VID_WIDTH          (12)
+#define ACL_VLAN_HIT_WIDTH          (1)
+#define ACL_CLASS_IDX_WIDTH         (5)
+#define ACL_TCM_WIDTH               (2)
+#define ACL_TCM_SEL_WIDTH           (1)
+#define ACL_DROP_PCD_G_WIDTH        (3)
+#define ACL_DROP_PCD_Y_WIDTH        (3)
+#define ACL_DROP_PCD_R_WIDTH        (3)
+#define CLASS_SLR_WIDTH             (3)
+#define CLASS_SLR_SEL_WIDTH         (1)
+#define DROP_PCD_SEL_WIDTH          (1)
+#define TRTCM_EN_WIDTH              (1)
+#define ACL_MANG_WIDTH              (1)
+#define LKY_VLAN_WIDTH              (1)
+#define LKY_VLAN_EN_WIDTH           (1)
+#define EG_TAG_WIDTH                (3)
+#define EG_TAG_EN_WIDTH             (1)
+#define PRI_USER_WIDTH              (3)
+#define PRI_USER_EN_WIDTH           (1)
+#define MIRROR_WIDTH                (2)
+#define FW_PORT_WIDTH               (3)
+#define PORT_FW_EN_WIDTH            (1)
+#define RATE_INDEX_WIDTH            (5)
+#define RATE_EN_WIDTH               (1)
+#define ATTACK_RATE_ID_WIDTH        (7)
+#define ATTACK_RATE_EN_WIDTH        (1)
+#define ACL_MIB_ID_WIDTH            (6)
+#define ACL_MIB_EN_WIDTH            (1)
+#define VLAN_PORT_SWAP_WIDTH        (1)
+#define DST_PORT_SWAP_WIDTH         (1)
+#define BPDU_WIDTH                  (1)
+#define PORT_WIDTH                  (7)
+#define PORT_FORCE_WIDTH            (1)
+
+/*ACL UDF table offset and width*/
+#define UDF_RULE_EN_OFFSET          (0)
+#define UDF_PKT_TYPE_OFFSET         (1)
+#define WORD_OFST_OFFSET            (4)
+#define CMP_SEL_OFFSET              (11)
+#define CMP_PAT_OFFSET              (32)
+#define CMP_MASK_OFFSET             (48)
+#define PORT_BITMAP_OFFSET          (64)
+
+#define UDF_RULE_EN_WIDTH           (1)
+#define UDF_PKT_TYPE_WIDTH          (3)
+#define WORD_OFST_WIDTH             (7)
+#define CMP_SEL_WIDTH               (1)
+#define CMP_PAT_WIDTH               (16)
+#define CMP_MASK_WIDTH              (16)
+#define PORT_BITMAP_WIDTH           (29)
+
+#define ACL_UDF_ACC_OFFSET          (31)
+#define ACL_UDF_READ_MASK           (0x0)
+#define ACL_UDF_WRITE_MASK          (0x1)
+#define ACL_UDF_CLEAR_MASK          (0x2)
+#define ACL_UDF_CMD_OFFSET          (28)
+#define ACL_UDF_READ                (ACL_UDF_READ_MASK << ACL_UDF_CMD_OFFSET)
+#define ACL_UDF_WRITE               (ACL_UDF_WRITE_MASK << ACL_UDF_CMD_OFFSET)
+#define ACL_UDF_CLEAR               (ACL_UDF_CLEAR_MASK << ACL_UDF_CMD_OFFSET)
+#define ACL_UDF_ADDR_MASK           (0xf)
+
+#define DPCR_HIGH_THRSH_OFFSET      (11)
+#define DPCR_PBB_OFFSET             (22)
+#define DPCR_LOW_THRSH_WIDTH        (11)
+#define DPCR_LOW_THRSH_MASK         (0x7ff)
+#define DPCR_HIGH_THRSH_WIDTH       (11)
+#define DPCR_HIGH_THRSH_MASK        (0x7ff)
+#define DPCR_PBB_WIDTH              (10)
+#define DPCR_PBB_MASK               (0x3ff)
+#define DP_MFRM_EX_OFFSET           (24)
+
+/* MACRO FUNCTION DECLARATIONS
+*/
+
+/* DATA TYPE DECLARATIONS
+*/
+typedef enum
+{
+    AIR_ACL_RULE_OFS_FMT_MAC_HEADER = 0,
+    AIR_ACL_RULE_OFS_FMT_L2_PAYLOAD,
+    AIR_ACL_RULE_OFS_FMT_IPV4_HEADER,
+    AIR_ACL_RULE_OFS_FMT_IPV6_HEADER,
+    AIR_ACL_RULE_OFS_FMT_L3_PAYLOAD,
+    AIR_ACL_RULE_OFS_FMT_TCP_HEADER,
+    AIR_ACL_RULE_OFS_FMT_UDP_HEADER,
+    AIR_ACL_RULE_OFS_FMT_L4_PAYLOAD,
+    AIR_ACL_RULE_OFS_FMT_LAST
+} AIR_ACL_RULE_OFS_FMT_T;
+
+typedef enum
+{
+    AIR_ACL_RULE_CMP_SEL_PATTERN,          /* Pattern hit by data pattern and bit mask */
+    AIR_ACL_RULE_CMP_SEL_THRESHOLD,        /* Pattern hit by low and high threshold */
+    AIR_ACL_RULE_CMP_SEL_LAST
+}AIR_ACL_RULE_CMP_SEL_T;
+
+typedef enum
+{
+    AIR_ACL_ACT_FWD_DIS,             /* Don't change forwarding behaviour by ACL */
+    AIR_ACL_ACT_FWD_CPU_EX = 4,      /* Forward by system default & CPU port is excluded */
+    AIR_ACL_ACT_FWD_CPU_IN,          /* Forward by system default & CPU port is included */
+    AIR_ACL_ACT_FWD_CPU,             /* Forward to CPU port only */
+    AIR_ACL_ACT_FWD_DROP,            /* Frame dropped */
+    AIR_ACL_ACT_FWD_LAST
+}AIR_ACL_ACT_FWD_T;
+
+typedef enum
+{
+    AIR_ACL_ACT_EGTAG_DIS,
+    AIR_ACL_ACT_EGTAG_CONSISTENT,
+    AIR_ACL_ACT_EGTAG_UNTAG = 4,
+    AIR_ACL_ACT_EGTAG_SWAP,
+    AIR_ACL_ACT_EGTAG_TAG,
+    AIR_ACL_ACT_EGTAG_STACK,
+    AIR_ACL_ACT_EGTAG_LAST
+}AIR_ACL_ACT_EGTAG_T;
+
+typedef enum
+{
+    AIR_ACL_ACT_USR_TCM_DEFAULT,         /* Normal packets, don't work based on color */
+    AIR_ACL_ACT_USR_TCM_GREEN,           /* Green */
+    AIR_ACL_ACT_USR_TCM_YELLOW,          /* Yellow */
+    AIR_ACL_ACT_USR_TCM_RED,             /* Red */
+    AIR_ACL_ACT_USR_TCM_LAST
+}AIR_ACL_ACT_USR_TCM_T;
+
+typedef enum
+{
+    AIR_ACL_DP_COLOR_GREEN,
+    AIR_ACL_DP_COLOR_YELLOW,
+    AIR_ACL_DP_COLOR_RED,
+    AIR_ACL_DP_COLOR_LAST
+}AIR_ACL_DP_COLOR_T;
+
+typedef enum
+{
+    AIR_ACL_RULE_TYPE_0,
+    AIR_ACL_RULE_TYPE_1,
+    AIR_ACL_RULE_TYPE_LAST
+}AIR_ACL_RULE_TYPE_T;
+
+typedef enum
+{
+    AIR_ACL_RULE_T_CELL,
+    AIR_ACL_RULE_C_CELL,
+    AIR_ACL_RULE_TCAM_LAST
+}AIR_ACL_RULE_TCAM_T;
+
+typedef enum
+{
+    AIR_ACL_MEM_SEL_RULE,
+    AIR_ACL_MEM_SEL_ACTION,
+    AIR_ACL_MEM_SEL_LAST
+}AIR_ACL_MEM_SEL_T;
+
+typedef enum
+{
+    AIR_ACL_MEM_FUNC_READ = 0,
+    AIR_ACL_MEM_FUNC_WRITE,
+    AIR_ACL_MEM_FUNC_CLEAR,
+    AIR_ACL_MEM_FUNC_CONFIG_READ = 4,
+    AIR_ACL_MEM_FUNC_CONFIG_WRITE,
+    AIR_ACL_MEM_FUNC_LAST
+}AIR_ACL_MEM_FUNC_T;
+
+typedef enum
+{
+    AIR_ACL_RULE_CONFIG_ENABLE,
+    AIR_ACL_RULE_CONFIG_END,
+    AIR_ACL_RULE_CONFIG_REVERSE,
+    AIR_ACL_RULE_CONFIG_LAST
+}AIR_ACL_RULE_CONFIG_T;
+
+typedef enum
+{
+    AIR_ACL_CHECK_ACL,
+    AIR_ACL_CHECK_UDF,
+    AIR_ACL_CHECK_TRTCM,
+    AIR_ACL_CHECK_METER,
+    AIR_ACL_CHECK_TYPE_LAST
+}AIR_ACL_CHECK_TYPE_T;
+
+typedef enum
+{
+    AIR_ACL_DMAC,
+    AIR_ACL_SMAC,
+    AIR_ACL_STAG,
+    AIR_ACL_CTAG,
+    AIR_ACL_ETYPE,
+    AIR_ACL_DIP,
+    AIR_ACL_SIP,
+    AIR_ACL_DSCP,
+    AIR_ACL_PROTOCOL,
+    AIR_ACL_DPORT,
+    AIR_ACL_SPORT,
+    AIR_ACL_UDF,
+    AIR_ACL_FLOW_LABEL,
+    AIR_ACL_FIELD_TYPE_LAST
+}AIR_ACL_FIELD_TYPE_T;
+
+typedef struct AIR_ACL_FIELD_S
+{
+    UI8_T dmac[6];
+    UI8_T smac[6];
+    UI16_T stag;
+    UI16_T ctag;
+    UI16_T etype;
+    UI32_T dip[4];
+    UI32_T sip[4];
+    UI8_T dscp;
+    UI8_T protocol;
+    UI32_T flow_label;
+    UI16_T dport;
+    UI16_T sport;
+    UI16_T udf;
+    BOOL_T isipv6;
+    UI16_T fieldmap;
+    UI32_T portmap;
+} AIR_ACL_FIELD_T;
+
+typedef struct AIR_ACL_CTRL_S
+{
+    BOOL_T rule_en;
+    BOOL_T reverse;
+    BOOL_T end;
+}AIR_ACL_CTRL_T;
+
+typedef struct AIR_ACL_RULE_S
+{
+    AIR_ACL_FIELD_T key;
+    AIR_ACL_FIELD_T mask;
+    AIR_ACL_CTRL_T ctrl;
+} AIR_ACL_RULE_T;
+
+typedef struct AIR_ACL_UDF_RULE_S
+{
+    BOOL_T valid;                           /* Valid bit */
+    AIR_ACL_RULE_OFS_FMT_T offset_format;   /* Format Type for Word Offset Range */
+    UI32_T offset;                          /* Word Offset */
+    UI32_T portmap;                         /* Physical Source Port Bit-map */
+    AIR_ACL_RULE_CMP_SEL_T cmp_sel;         /* Comparison mode selection */
+    UI16_T pattern;                         /* Comparison Pattern when cmp_sel=AIR_ACL_RULE_CMP_SEL_PATTERN */
+    UI16_T mask;                            /* Comparison Pattern Mask when cmp_sel=AIR_ACL_RULE_CMP_SEL_PATTERN */
+    UI16_T low_threshold;                   /* Low Threshold when cmp_sel=AIR_ACL_RULE_CMP_SEL_THRESHOLD */
+    UI16_T high_threshold;                  /* High Threshold when cmp_sel=AIR_ACL_RULE_CMP_SEL_THRESHOLD */
+}AIR_ACL_UDF_RULE_T;
+
+typedef struct AIR_ACL_ACT_TRTCM_S
+{
+    BOOL_T cls_slr_sel;                     /* FALSE: Select original class selector value
+                                               TRUE:  Select ACL control table defined class selector value */
+    UI8_T cls_slr;                          /* User defined class selector */
+    BOOL_T drop_pcd_sel;                    /* FALSE: Select original drop precedence value
+                                               TRUE:  Select ACL control table defined drop precedence value */
+    UI8_T drop_pcd_r;                       /* User defined drop precedence for red packets */
+    UI8_T drop_pcd_y;                       /* User defined drop precedence for yellow packets */
+    UI8_T drop_pcd_g;                       /* User defined drop precedence for green packets */
+    BOOL_T tcm_sel;                         /* FALSE: Select user defined color value
+                                               TRUE:  Select color remark by trtcm table */
+    AIR_ACL_ACT_USR_TCM_T usr_tcm;          /* User defined color remark */
+    UI8_T tcm_idx;                          /* Index for the 32-entries trtcm table */
+}AIR_ACL_ACT_TRTCM_T;
+
+typedef struct AIR_ACL_ACTION_S
+{
+    BOOL_T port_en;
+    BOOL_T dest_port_sel;               /* Swap destination port member by portmap when port_en=1 */
+    BOOL_T vlan_port_sel;               /* Swap VLAN port member by portmap when port_en=1 */
+    UI32_T portmap;
+
+    BOOL_T cnt_en;
+    UI32_T cnt_idx;                     /* Counter index */
+
+    BOOL_T attack_en;
+    UI32_T attack_idx;                  /* Attack rate index */
+
+    BOOL_T rate_en;
+    UI32_T rate_idx;                    /* Index of meter table */
+
+    BOOL_T vlan_en;
+    UI32_T vlan_idx;                    /* Vid from ACL */
+
+    UI8_T mirrormap;                    /* mirror session bitmap */
+
+    BOOL_T pri_user_en;
+    UI8_T pri_user;                     /* User Priority from ACL */
+
+    BOOL_T lyvlan_en;
+    BOOL_T lyvlan;                      /* Leaky VLAN */
+
+    BOOL_T mang;                        /* Management frame attribute */
+
+    BOOL_T bpdu;                        /* BPDU frame attribute */
+
+    BOOL_T fwd_en;
+    AIR_ACL_ACT_FWD_T fwd;              /* Frame TO_CPU Forwarding */
+
+    BOOL_T egtag_en;
+    AIR_ACL_ACT_EGTAG_T egtag;          /* Egress tag control */
+
+    BOOL_T trtcm_en;
+    AIR_ACL_ACT_TRTCM_T trtcm;          /* TRTCM control */
+
+}AIR_ACL_ACTION_T;
+
+typedef struct AIR_ACL_TRTCM_S
+{
+    UI16_T cir;                             /* Committed information rate (unit: 64Kbps) */
+    UI16_T pir;                             /* Peak information rate (unit: 64Kbps) */
+    UI16_T cbs;                             /* Committed burst size (unit: byte) */
+    UI16_T pbs;                             /* Peak burst size (unit: byte) */
+}AIR_ACL_TRTCM_T;
+
+/* EXPORTED SUBPROGRAM SPECIFICATIONS
+*/
+/* FUNCTION NAME: air_acl_setRuleCtrl
+ * PURPOSE:
+ *      Set ACL rule control.
+ *
+ * INPUT:
+ *      unit            --  Device ID
+ *      rule_idx        --  Index of ACL rule entry
+ *      ptr_rule        --  Structure of ACL rule control
+ *
+ * OUTPUT:
+ *      None
+ *
+ * RETURN:
+ *      AIR_E_OK
+ *      AIR_E_BAD_PARAMETER
+ *      AIR_E_TIMEOUT
+ *
+ * NOTES:
+ *      None
+ */
+AIR_ERROR_NO_T
+air_acl_setRuleCtrl(
+    const UI32_T unit,
+    const UI32_T rule_idx,
+    AIR_ACL_CTRL_T *ptr_ctrl);
+
+/* FUNCTION NAME: air_acl_getRuleCtrl
+ * PURPOSE:
+ *      Get ACL rule control.
+ *
+ * INPUT:
+ *      unit            --  Device ID
+ *      rule_idx        --  Index of ACL rule entry
+ *
+ * OUTPUT:
+ *      ptr_ctrl        --  Structure of ACL rule control
+ *
+ * RETURN:
+ *      AIR_E_OK
+ *      AIR_E_BAD_PARAMETER
+ *      AIR_E_TIMEOUT
+ *
+ * NOTES:
+ *      None
+ */
+AIR_ERROR_NO_T
+air_acl_getRuleCtrl(
+    const UI32_T unit,
+    const UI32_T rule_idx,
+    AIR_ACL_CTRL_T *ptr_ctrl);
+
+/* FUNCTION NAME: air_acl_setRule
+ * PURPOSE:
+ *      Set ACL rule entry.
+ *
+ * INPUT:
+ *      unit            --  Device ID
+ *      rule_idx        --  Index of ACL rule entry
+ *      rule            --  Structure of ACL rule entry
+ *
+ * OUTPUT:
+ *      None
+ *
+ * RETURN:
+ *      AIR_E_OK
+ *      AIR_E_BAD_PARAMETER
+ *      AIR_E_TIMEOUT
+ *
+ * NOTES:
+ *      None
+ */
+AIR_ERROR_NO_T
+air_acl_setRule(
+    const UI32_T unit,
+    const UI32_T rule_idx,
+    AIR_ACL_RULE_T *rule);
+
+/* FUNCTION NAME: air_acl_delRule
+ * PURPOSE:
+ *      Delete an ACL rule entry.
+ *
+ * INPUT:
+ *      unit            --  Device ID
+ *      rule_idx        --  Index of ACL rule entry
+ *
+ * OUTPUT:
+ *      None
+ *
+ * RETURN:
+ *      AIR_E_OK
+ *      AIR_E_BAD_PARAMETER
+ *      AIR_E_TIMEOUT
+ *
+ * NOTES:
+ *      None
+ */
+AIR_ERROR_NO_T
+air_acl_delRule(
+    const UI32_T unit,
+    const UI32_T rule_idx);
+
+/* FUNCTION NAME: air_acl_clearRule
+ * PURPOSE:
+ *      Clear all ACL rule entries.
+ *
+ * INPUT:
+ *      unit            --  Device ID
+ *
+ * OUTPUT:
+ *      None
+ *
+ * RETURN:
+ *      AIR_E_OK
+ *      AIR_E_BAD_PARAMETER
+ *      AIR_E_TIMEOUT
+ *
+ * NOTES:
+ *      None
+ */
+AIR_ERROR_NO_T
+air_acl_clearRule(
+    const UI32_T unit);
+
+/* FUNCTION NAME: air_acl_getRule
+ * PURPOSE:
+ *      Get ACL rule entry.
+ *
+ * INPUT:
+ *      unit            --  Device ID
+ *      rule_idx        --  Index of ACL rule entry
+ *
+ * OUTPUT:
+ *      ptr_rule        --  Structure of ACL rule entry
+ *
+ * RETURN:
+ *      AIR_E_OK
+ *      AIR_E_BAD_PARAMETER
+ *      AIR_E_TIMEOUT
+ *
+ * NOTES:
+ *      None
+ */
+AIR_ERROR_NO_T
+air_acl_getRule(
+    const UI32_T unit,
+    const UI32_T rule_idx,
+    AIR_ACL_RULE_T *ptr_rule);
+
+/* FUNCTION NAME: air_acl_setAction
+ * PURPOSE:
+ *      Set an ACL action entry.
+ *
+ * INPUT:
+ *      unit            --  Device ID
+ *      act_idx         --  Index of ACL action entry
+ *      act             --  Structure of ACL action entry
+ *
+ * OUTPUT:
+ *      None
+ *
+ * RETURN:
+ *      AIR_E_OK
+ *      AIR_E_BAD_PARAMETER
+ *      AIR_E_NOT_SUPPORT
+ *      AIR_E_TIMEOUT
+ *
+ * NOTES:
+ *      None
+ */
+AIR_ERROR_NO_T
+air_acl_setAction(
+    const UI32_T unit,
+    const UI32_T act_idx,
+    const AIR_ACL_ACTION_T act);
+
+/* FUNCTION NAME: air_acl_delAction
+ * PURPOSE:
+ *      Delete an ACL action entry with specific index
+ *
+ * INPUT:
+ *      unit            --  Device ID
+ *      act_idx         --  Index of ACL action entry
+ *
+ * OUTPUT:
+ *      None
+ *
+ * RETURN:
+ *      AIR_E_OK
+ *      AIR_E_BAD_PARAMETER
+ *      AIR_E_ENTRY_NOT_FOUND
+ *      AIR_E_TIMEOUT
+ *
+ * NOTES:
+ *      None
+ */
+AIR_ERROR_NO_T
+air_acl_delAction(
+    const UI32_T unit,
+    const UI32_T act_idx);
+
+/* FUNCTION NAME: air_acl_clearAction
+ * PURPOSE:
+ *      Clear all ACL action entries.
+ *
+ * INPUT:
+ *      unit            --  Device ID
+ *
+ * OUTPUT:
+ *      None
+ *
+ * RETURN:
+ *      AIR_E_OK
+ *      AIR_E_BAD_PARAMETER
+ *      AIR_E_TIMEOUT
+ *
+ * NOTES:
+ *      None
+ */
+AIR_ERROR_NO_T
+air_acl_clearAction(
+    const UI32_T unit);
+
+/* FUNCTION NAME: air_acl_getAction
+ * PURPOSE:
+ *      Get an ACL action entry with speficic index.
+ *
+ * INPUT:
+ *      unit            --  Device ID
+ *      act_idx         --  Index of ACL action entry
+ *
+ * OUTPUT:
+ *      ptr_act         --  Structure of ACL action entry
+ *
+ * RETURN:
+ *      AIR_E_OK
+ *      AIR_E_BAD_PARAMETER
+ *      AIR_E_ENTRY_NOT_FOUND
+ *      AIR_E_TIMEOUT
+ *
+ * NOTES:
+ *      None
+ */
+AIR_ERROR_NO_T
+air_acl_getAction(
+    const UI32_T unit,
+    const UI32_T act_idx,
+    AIR_ACL_ACTION_T *ptr_act);
+
+/* FUNCTION NAME: air_acl_setTrtcm
+ * PURPOSE:
+ *      Set a trTCM entry with the specific index.
+ *
+ * INPUT:
+ *      unit            --  Device ID
+ *      tcm_idx         --  Index of trTCM entry
+ *      tcm             --  Structure of trTCM entry
+ *
+ * OUTPUT:
+ *      None
+ *
+ * RETURN:
+ *      AIR_E_OK
+ *      AIR_E_BAD_PARAMETER
+ *      AIR_E_TIMEOUT
+ *
+ * NOTES:
+ *      Index 0 ~ 31 can be selected in tcm_idx.
+ */
+AIR_ERROR_NO_T
+air_acl_setTrtcm(
+    const UI32_T unit,
+    const UI32_T tcm_idx,
+    const AIR_ACL_TRTCM_T tcm);
+
+/* FUNCTION NAME: air_acl_delTrtcm
+ * PURPOSE:
+ *      Delete an ACL trTCM entry.
+ *
+ * INPUT:
+ *      unit            --  Device ID
+ *      trtcm_idx       --  Index of ACL trTCM entry
+ *
+ * OUTPUT:
+ *      None
+ *
+ * RETURN:
+ *      AIR_E_OK
+ *      AIR_E_BAD_PARAMETER
+ *      AIR_E_TIMEOUT
+ *
+ * NOTES:
+ *      Index 0 ~ 31 can be selected in tcm_idx.
+ */
+AIR_ERROR_NO_T
+air_acl_delTrtcm(
+    const UI32_T unit,
+    const UI32_T trtcm_idx);
+
+/* FUNCTION NAME: air_acl_clearTrtcm
+ * PURPOSE:
+ *      Clear all ACL trTCM entries.
+ *
+ * INPUT:
+ *      unit            --  Device ID
+ *
+ * OUTPUT:
+ *      None
+ *
+ * RETURN:
+ *      AIR_E_OK
+ *      AIR_E_BAD_PARAMETER
+ *      AIR_E_TIMEOUT
+ *
+ * NOTES:
+ *      None
+ */
+AIR_ERROR_NO_T
+air_acl_clearTrtcm(
+    const UI32_T unit);
+
+/* FUNCTION NAME: air_acl_getTrtcm
+ * PURPOSE:
+ *      Get a trTCM entry with the specific index.
+ *
+ * INPUT:
+ *      unit            --  Device ID
+ *      tcm_idx         --  Index of trTCM entry
+ *
+ * OUTPUT:
+ *      ptr_tcm         --  Structure of trTCM entry
+ *
+ * RETURN:
+ *      AIR_E_OK
+ *      AIR_E_BAD_PARAMETER
+ *      AIR_E_TIMEOUT
+ *
+ * NOTES:
+ *      Index 0 ~ 31 can be selected in tcm_idx.
+ */
+AIR_ERROR_NO_T
+air_acl_getTrtcm(
+    const UI32_T unit,
+    const UI32_T tcm_idx,
+    AIR_ACL_TRTCM_T *ptr_tcm);
+
+/* FUNCTION NAME: air_acl_setTrtcmEnable
+ * PURPOSE:
+ *      Set trTCM enable so the meter table will be updated based on PIR and CIR.
+ *      The color marker will also be enabled when ACL is hit.
+ *
+ * INPUT:
+ *      unit            --  Device ID
+ *      state           --  FALSE:Disable
+ *                          TRUE: Enable
+ *
+ * OUTPUT:
+ *      None
+ *
+ * RETURN:
+ *      AIR_E_OK
+ *      AIR_E_BAD_PARAMETER
+ *
+ * NOTES:
+ *      None
+ */
+AIR_ERROR_NO_T
+air_acl_setTrtcmEnable(
+    const UI32_T unit,
+    const BOOL_T state);
+
+/* FUNCTION NAME: air_acl_getTrtcm
+ * PURPOSE:
+ *      Get a trTCM enable state.
+ *
+ * INPUT:
+ *      unit            --  Device ID
+ *
+ * OUTPUT:
+ *      ptr_state       --  FALSE:Disable
+ *                          TRUE: Enable
+ *
+ * RETURN:
+ *      AIR_E_OK
+ *      AIR_E_BAD_PARAMETER
+ *
+ * NOTES:
+ *      None
+ */
+AIR_ERROR_NO_T
+air_acl_getTrtcmEnable(
+    const UI32_T unit,
+    BOOL_T *const ptr_state);
+
+/* FUNCTION NAME: air_acl_setPortEnable
+ * PURPOSE:
+ *      Set ACL state for a specific port.
+ *
+ * INPUT:
+ *      unit            --  Device ID
+ *      port            --  Index of port number
+ *      state           --  FALSE:Disable
+ *                          TRUE: Enable
+ * OUTPUT:
+ *      None
+ *
+ * RETURN:
+ *      AIR_E_OK
+ *      AIR_E_BAD_PARAMETER
+ *
+ * NOTES:
+ *      None
+ */
+AIR_ERROR_NO_T
+air_acl_setPortEnable(
+    const UI32_T unit,
+    const UI32_T port,
+    const BOOL_T state);
+
+/* FUNCTION NAME: air_acl_getPortEnable
+ * PURPOSE:
+ *      Get ACL state for a specific port.
+ *
+ * INPUT:
+ *      unit            --  Device ID
+ *      port            --  Index of port number
+ *
+ * OUTPUT:
+ *      ptr_state       --  FALSE:Disable
+ *                          TRUE: Enable
+ * RETURN:
+ *      AIR_E_OK
+ *      AIR_E_BAD_PARAMETER
+ *
+ * NOTES:
+ *      None
+ */
+AIR_ERROR_NO_T
+air_acl_getPortEnable(
+    const UI32_T unit,
+    const UI32_T port,
+    UI32_T *ptr_state);
+
+/* FUNCTION NAME: air_acl_setDropEnable
+ * PURPOSE:
+ *      Set ACL drop precedence state
+ *
+ * INPUT:
+ *      unit            --  Device ID
+ *      port            --  Index of port number
+ *      state           --  FALSE:Disable
+ *                          TRUE: Enable
+ * OUTPUT:
+ *      None
+ *
+ * RETURN:
+ *      AIR_E_OK
+ *      AIR_E_BAD_PARAMETER
+ *
+ * NOTES:
+ *      None
+ */
+AIR_ERROR_NO_T
+air_acl_setDropEnable(
+    const UI32_T unit,
+    const UI32_T port,
+    const BOOL_T state);
+
+/* FUNCTION NAME: air_acl_getDropEnable
+ * PURPOSE:
+ *      Get ACL drop precedence state
+ *
+ * INPUT:
+ *      unit            --  Device ID
+ *      port            --  Index of port number
+ *
+ * OUTPUT:
+ *      ptr_state       --  FALSE:Disable
+ *                          TRUE: Enable
+ * RETURN:
+ *      AIR_E_OK
+ *      AIR_E_BAD_PARAMETER
+ *
+ * NOTES:
+ *      None
+ */
+AIR_ERROR_NO_T
+air_acl_getDropEnable(
+    const UI32_T unit,
+    const UI32_T port,
+    BOOL_T *ptr_state);
+
+/* FUNCTION NAME: air_acl_setDropThreshold
+ * PURPOSE:
+ *      Set ACL drop threshold.
+ *
+ * INPUT:
+ *      unit            --  Device ID
+ *      port            --  Index of port number
+ *      color           --  AIR_ACL_DP_COLOR_YELLOW: Yellow
+ *                          AIR_ACL_DP_COLOR_RED   : Red
+ *      queue           --  Output queue number
+ *      high            --  High threshold
+ *      low             --  Low threshold
+ *
+ * OUTPUT:
+ *      None
+ *
+ * RETURN:
+ *      AIR_E_OK
+ *      AIR_E_BAD_PARAMETER
+ *
+ * NOTES:
+ *      Key parameter include port, color, queue.
+ */
+AIR_ERROR_NO_T
+air_acl_setDropThreshold(
+    const UI32_T unit,
+    const UI32_T port,
+    const AIR_ACL_DP_COLOR_T color,
+    const UI8_T queue,
+    const UI32_T high,
+    const UI32_T low);
+
+/* FUNCTION NAME: air_acl_getDropThreshold
+ * PURPOSE:
+ *      Get ACL drop threshold.
+ *
+ * INPUT:
+ *      unit            --  Device ID
+ *      port            --  Index of port number
+ *      color           --  AIR_ACL_DP_COLOR_YELLOW: Yellow
+ *                          AIR_ACL_DP_COLOR_RED   : Red
+ *      queue           --  Output queue number
+ *
+ * OUTPUT:
+ *      ptr_high        --  High threshold
+ *      ptr_low         --  Low threshold
+ *
+ * RETURN:
+ *      AIR_E_OK
+ *      AIR_E_BAD_PARAMETER
+ *
+ * NOTES:
+ *      Key parameter include port, color, queue.
+ */
+AIR_ERROR_NO_T
+air_acl_getDropThreshold(
+    const UI32_T unit,
+    const UI32_T port,
+    const AIR_ACL_DP_COLOR_T color,
+    const UI8_T queue,
+    UI32_T *ptr_high,
+    UI32_T *ptr_low);
+
+/* FUNCTION NAME: air_acl_setDropProbability
+ * PURPOSE:
+ *      Set ACL drop probability.
+ *
+ * INPUT:
+ *      unit            --  Device ID
+ *      port            --  Index of port number
+ *      color           --  AIR_ACL_DP_COLOR_YELLOW: Yellow
+ *                          AIR_ACL_DP_COLOR_RED   : Red
+ *      queue           --  Output queue number
+ *      probability     --  Drop probability (value:0 ~ 1023, unit:1/1023; eg: value-102 = 10% )
+ *
+ * OUTPUT:
+ *      None
+ *
+ * RETURN:
+ *      AIR_E_OK
+ *      AIR_E_BAD_PARAMETER
+ *
+ * NOTES:
+ *      Key parameter include port, color, queue.
+ */
+AIR_ERROR_NO_T
+air_acl_setDropProbability(
+    const UI32_T unit,
+    const UI32_T port,
+    const AIR_ACL_DP_COLOR_T color,
+    const UI8_T queue,
+    const UI32_T probability);
+
+/* FUNCTION NAME: air_acl_getDropProbability
+ * PURPOSE:
+ *      Get ACL drop probability.
+ *
+ * INPUT:
+ *      unit            --  Device ID
+ *      port            --  Index of port number
+ *      color           --  AIR_ACL_DP_COLOR_YELLOW: Yellow
+ *                          AIR_ACL_DP_COLOR_RED   : Red
+ *      queue           --  Output queue number
+ *
+ * OUTPUT:
+ *      ptr_probability --  Drop probability (value:0 ~ 1023, unit:1/1023; eg: value-102 = 10% )
+ *
+ * RETURN:
+ *      AIR_E_OK
+ *      AIR_E_BAD_PARAMETER
+ *
+ * NOTES:
+ *      Key parameter include port, color, queue.
+ */
+AIR_ERROR_NO_T
+air_acl_getDropProbability(
+    const UI32_T unit,
+    const UI32_T port,
+    const AIR_ACL_DP_COLOR_T color,
+    const UI8_T queue,
+    UI32_T *ptr_probability);
+
+/* FUNCTION NAME:
+ *      air_acl_setGlobalState
+ * PURPOSE:
+ *      Set the ACL global enable state.
+ * INPUT:
+ *      unit        -- Device ID
+ *      state       -- Enable state of ACL
+ * OUTPUT:
+ *      None
+ * RETURN:
+ *      AIR_E_OK
+ *      AIR_E_BAD_PARAMETER
+ * NOTES:
+ *      None
+ */
+AIR_ERROR_NO_T
+air_acl_setGlobalState(
+    const UI32_T        unit,
+    const BOOL_T        state);
+
+/* FUNCTION NAME:
+ *      air_acl_getGlobalState
+ * PURPOSE:
+ *      Get the ACL global enable state.
+ * INPUT:
+ *      unit             -- Device ID
+ * OUTPUT:
+ *      ptr_state        -- Enable state
+ * RETURN:
+ *      AIR_E_OK
+ *      AIR_E_BAD_PARAMETER
+ * NOTES:
+ *      None
+ */
+AIR_ERROR_NO_T
+air_acl_getGlobalState(
+    const UI32_T         unit,
+    BOOL_T               *ptr_state);
+
+/* FUNCTION NAME:
+ *      air_acl_setUdfRule
+ * PURPOSE:
+ *      Set ACL UDF rule of specified entry index.
+ * INPUT:
+ *      unit             -- Device ID
+ *      rule_idx         -- ACLUDF table entry index
+ *      udf_rule         -- Structure of ACL UDF rule entry
+ * OUTPUT:
+ *      None
+ * RETURN:
+ *      AIR_E_OK
+ *      AIR_E_BAD_PARAMETER
+ * NOTES:
+ *      None
+ */
+AIR_ERROR_NO_T
+air_acl_setUdfRule(
+    const UI32_T                unit,
+    const UI32_T                rule_idx,
+    AIR_ACL_UDF_RULE_T          udf_rule);
+
+/* FUNCTION NAME:
+ *      air_acl_getUdfRule
+ * PURPOSE:
+ *      Get ACL UDF rule of specified entry index.
+ * INPUT:
+ *      unit             -- Device ID
+ *      rule_idx         -- ACLUDF table entry index
+ * OUTPUT:
+ *      ptr_udf_rule     -- Structure of ACL UDF rule entry
+ * RETURN:
+ *      AIR_E_OK
+ *      AIR_E_BAD_PARAMETER
+ * NOTES:
+ *      None
+ */
+AIR_ERROR_NO_T
+air_acl_getUdfRule(
+    const UI32_T                unit,
+    const UI8_T                 rule_idx,
+    AIR_ACL_UDF_RULE_T          *ptr_udf_rule);
+
+/* FUNCTION NAME:
+ *      air_acl_delUdfRule
+ * PURPOSE:
+ *      Delete ACL UDF rule of specified entry index.
+ * INPUT:
+ *      unit             -- Device ID
+ *      rule_idx         -- ACLUDF table entry index
+ * OUTPUT:
+ *      None
+ * RETURN:
+ *      AIR_E_OK
+ *      AIR_E_BAD_PARAMETER
+ * NOTES:
+ *      None
+ */
+AIR_ERROR_NO_T
+air_acl_delUdfRule(
+    const UI32_T      unit,
+    const UI8_T       rule_idx);
+
+/* FUNCTION NAME:
+ *      air_acl_clearUdfRule
+ * PURPOSE:
+ *      Clear acl all udf rule.
+ * INPUT:
+ *      unit             -- Device ID
+ * OUTPUT:
+ *      None
+ * RETURN:
+ *      AIR_E_OK
+ *      AIR_E_BAD_PARAMETER
+ * NOTES:
+ *      None
+ */
+AIR_ERROR_NO_T
+air_acl_clearUdfRule(
+    const UI32_T    unit);
+
+/* FUNCTION NAME:
+ *      air_acl_setMeterTable
+ * PURPOSE:
+ *      Set flow ingress rate limit by meter table.
+ * INPUT:
+ *      unit                -- Device ID
+ *      meter_id            -- Meter id
+ *      enable              -- Meter enable state
+ *      rate                -- Ratelimit(unit:64kbps)
+ * OUTPUT:
+ *      None
+ * RETURN:
+ *      AIR_E_OK
+ *      AIR_E_BAD_PARAMETER
+ * NOTES:
+ *      None
+ */
+AIR_ERROR_NO_T
+air_acl_setMeterTable(
+    const UI32_T            unit,
+    const UI32_T            meter_id,
+    const BOOL_T            enable,
+    const UI32_T            rate);
+
+/* FUNCTION NAME:
+ *      air_acl_getMeterTable
+ * PURPOSE:
+ *      Get meter table configuration.
+ * INPUT:
+ *      unit                -- Device ID
+ *      meter_id            -- Meter id
+ * OUTPUT:
+ *      ptr_enable          -- Meter enable state
+ *      ptr_rate            -- Ratelimit(unit:64kbps)
+ * RETURN:
+ *      AIR_E_OK
+ *      AIR_E_BAD_PARAMETER
+ * NOTES:
+ *      None
+ */
+AIR_ERROR_NO_T
+air_acl_getMeterTable(
+    const UI32_T            unit,
+    const UI32_T            meter_id,
+    BOOL_T                  *ptr_enable,
+    UI32_T                  *ptr_rate);
+
+#endif /* End of AIR_ACL_H */
diff --git a/recipes-devtools/switch/files/src/an8855_sdk/api/inc/air_aml.h b/recipes-devtools/switch/files/src/an8855_sdk/api/inc/air_aml.h
new file mode 100644
index 0000000..49a38b6
--- /dev/null
+++ b/recipes-devtools/switch/files/src/an8855_sdk/api/inc/air_aml.h
@@ -0,0 +1,214 @@
+/* FILE NAME:   air_aml.h

+ * PURPOSE:

+ *      Define the access management layer function in AIR SDK.

+ * NOTES:

+ */

+

+#ifndef AIR_AML_H

+#define AIR_AML_H

+

+/* INCLUDE FILE DECLARATIONS

+ */

+

+/* NAMING CONSTANT DECLARATIONS

+ */

+

+/* MACRO FUNCTION DECLARATIONS

+ */

+

+/* DATA TYPE DECLARATIONS

+ */

+typedef AIR_ERROR_NO_T

+(*AML_DEV_READ_FUNC_T)(

+    const UI32_T    unit,

+    const UI32_T    addr_offset,

+    UI32_T          *ptr_data);

+

+typedef AIR_ERROR_NO_T

+(*AML_DEV_WRITE_FUNC_T)(

+    const UI32_T    unit,

+    const UI32_T    addr_offset,

+    const UI32_T    data);

+

+typedef AIR_ERROR_NO_T

+(*AML_DEV_PHY_READ_FUNC_T)(

+    const UI32_T    unit,

+    const UI32_T    port_id,

+    const UI32_T    addr_offset,

+    UI32_T          *ptr_data);

+

+typedef AIR_ERROR_NO_T

+(*AML_DEV_PHY_WRITE_FUNC_T)(

+    const UI32_T    unit,

+    const UI32_T    port_id,

+    const UI32_T    addr_offset,

+    const UI32_T    data);

+

+typedef AIR_ERROR_NO_T

+(*AML_DEV_PHY_READ_CL45_FUNC_T)(

+    const UI32_T    unit,

+    const UI32_T    port_id,

+    const UI32_T    dev_type,

+    const UI32_T    addr_offset,

+    UI32_T          *ptr_data);

+

+typedef AIR_ERROR_NO_T

+(*AML_DEV_PHY_WRITE_CL45_FUNC_T)(

+    const UI32_T    unit,

+    const UI32_T    port_id,

+    const UI32_T    dev_type,

+    const UI32_T    addr_offset,

+    const UI32_T    data);

+

+/* To read or write the HW-intf registers. */

+typedef struct

+{

+    AML_DEV_READ_FUNC_T             read_callback;

+    AML_DEV_WRITE_FUNC_T            write_callback;

+    AML_DEV_PHY_READ_FUNC_T         phy_read_callback;

+    AML_DEV_PHY_WRITE_FUNC_T        phy_write_callback;

+    AML_DEV_PHY_READ_CL45_FUNC_T    phy_cl45_read_callback;

+    AML_DEV_PHY_WRITE_CL45_FUNC_T   phy_cl45_write_callback;

+}AML_DEV_ACCESS_T;

+

+/* EXPORTED SUBPROGRAM SPECIFICATIONS

+ */

+extern AML_DEV_ACCESS_T _ext_dev_access;

+

+/* FUNCTION NAME:   aml_readReg

+ * PURPOSE:

+ *      To read data from the register of the specified chip unit.

+ * INPUT:

+ *      unit        -- the device unit

+ *      addr_offset -- the address of register

+ * OUTPUT:

+ *      ptr_data    -- pointer for the register data

+ * RETURN:

+ *      NPS_E_OK     -- Successfully read the data.

+ *      NPS_E_OTHERS -- Failed to read the data.

+ * NOTES:

+ *      none

+ */

+AIR_ERROR_NO_T

+aml_readReg(

+    const UI32_T    unit,

+    const UI32_T    addr_offset,

+    UI32_T          *ptr_data);

+

+/* FUNCTION NAME:   aml_writeReg

+ * PURPOSE:

+ *      To write data to the register of the specified chip unit.

+ * INPUT:

+ *      unit        -- the device unit

+ *      addr_offset -- the address of register

+ *      data        -- written data

+ * OUTPUT:

+ *      none

+ * RETURN:

+ *      NPS_E_OK     -- Successfully write the data.

+ *      NPS_E_OTHERS -- Failed to write the data.

+ * NOTES:

+ *      none

+ */

+AIR_ERROR_NO_T

+aml_writeReg(

+    const UI32_T    unit,

+    const UI32_T    addr_offset,

+    const UI32_T    data);

+

+/* FUNCTION NAME:   aml_readPhyReg

+ * PURPOSE:

+ *      To read data from the phy register of the specified chip unit in Clause22.

+ * INPUT:

+ *      unit        -- the device unit

+ *      port_id     -- physical port number

+ *      addr_offset -- the address of phy register

+ * OUTPUT:

+ *      ptr_data    -- pointer for the register data

+ * RETURN:

+ *      NPS_E_OK     -- Successfully read the data.

+ *      NPS_E_OTHERS -- Failed to read the data.

+ * NOTES:

+ *      none

+ */

+AIR_ERROR_NO_T

+aml_readPhyReg(

+    const UI32_T    unit,

+    const UI32_T    port_id,

+    const UI32_T    addr_offset,

+    UI32_T          *ptr_data);

+

+/* FUNCTION NAME:   aml_writePhyReg

+ * PURPOSE:

+ *      To write data to the phy register of the specified chip unit in Clause22.

+ * INPUT:

+ *      unit        -- the device unit

+ *      port_id     -- physical port number

+ *      addr_offset -- the address of phy register

+ *      data        -- written data

+ * OUTPUT:

+ *      none

+ * RETURN:

+ *      NPS_E_OK     -- Successfully write the data.

+ *      NPS_E_OTHERS -- Failed to write the data.

+ * NOTES:

+ *      none

+ */

+AIR_ERROR_NO_T

+aml_writePhyReg(

+    const UI32_T    unit,

+    const UI32_T    port_id,

+    const UI32_T    addr_offset,

+    const UI32_T    ptr_data);

+

+/* FUNCTION NAME:   aml_readPhyRegCL45

+ * PURPOSE:

+ *      To read data from the phy register of the specified chip unit in Clause45.

+ * INPUT:

+ *      unit        -- the device unit

+ *      port_id     -- physical port number

+ *      dev_type    -- phy register type

+ *      addr_offset -- the address of phy register

+ * OUTPUT:

+ *      ptr_data    -- pointer for the register data

+ * RETURN:

+ *      NPS_E_OK     -- Successfully read the data.

+ *      NPS_E_OTHERS -- Failed to read the data.

+ * NOTES:

+ *      none

+ */

+AIR_ERROR_NO_T

+aml_readPhyRegCL45(

+    const UI32_T    unit,

+    const UI32_T    port_id,

+    const UI32_T    dev_type,

+    const UI32_T    addr_offset,

+    UI32_T          *ptr_data);

+

+/* FUNCTION NAME:   aml_writePhyRegCL45

+ * PURPOSE:

+ *      To write data to the phy register of the specified chip unit in Clause45.

+ * INPUT:

+ *      unit        -- the device unit

+ *      port_id     -- physical port number

+ *      dev_type    -- phy register offset

+ *      addr_offset -- the address of phy register

+ *      data        -- written data

+ * OUTPUT:

+ *      none

+ * RETURN:

+ *      NPS_E_OK     -- Successfully write the data.

+ *      NPS_E_OTHERS -- Failed to write the data.

+ * NOTES:

+ *      none

+ */

+AIR_ERROR_NO_T

+aml_writePhyRegCL45(

+    const UI32_T    unit,

+    const UI32_T    port_id,

+    const UI32_T    dev_type,

+    const UI32_T    addr_offset,

+    const UI32_T    data);

+

+#endif  /* AIR_AML_H */

+

diff --git a/recipes-devtools/switch/files/src/an8855_sdk/api/inc/air_cmd.h b/recipes-devtools/switch/files/src/an8855_sdk/api/inc/air_cmd.h
new file mode 100644
index 0000000..071d063
--- /dev/null
+++ b/recipes-devtools/switch/files/src/an8855_sdk/api/inc/air_cmd.h
@@ -0,0 +1,50 @@
+/* FILE NAME:   air_cmd.h

+ * PURPOSE:

+ *      Define the command line function in AIR SDK.

+ * NOTES:

+ */

+

+#ifndef AIR_CMD_H

+#define AIR_CMD_H

+

+/* INCLUDE FILE DECLARATIONS

+ */

+

+/* NAMING CONSTANT DECLARATIONS

+ */

+

+/* MACRO FUNCTION DECLARATIONS

+ */

+

+/* DATA TYPE DECLARATIONS

+ */

+

+/* EXPORTED SUBPROGRAM SPECIFICATIONS

+ */

+/* FUNCTION NAME:   air_parse_cmd

+ * PURPOSE:

+ *      This function is used process diagnostic cmd

+ * INPUT:

+ *      argc         -- parameter number

+ *      argv         -- parameter strings

+ * OUTPUT:

+ *      None

+ * RETURN:

+ *      NPS_E_OK     -- Successfully read the data.

+ *      NPS_E_OTHERS -- Failed to read the data.

+ * NOTES:

+ *

+ */

+AIR_ERROR_NO_T

+air_parse_cmd(

+    const UI32_T argc,

+    const C8_T **argv);

+

+UI32_T

+_strtoul(

+    const C8_T *cp,

+    C8_T **endp,

+    UI32_T base);

+

+#endif  /* AIR_CMD_H */

+

diff --git a/recipes-devtools/switch/files/src/an8855_sdk/api/inc/air_diag.h b/recipes-devtools/switch/files/src/an8855_sdk/api/inc/air_diag.h
new file mode 100644
index 0000000..60fe4f3
--- /dev/null
+++ b/recipes-devtools/switch/files/src/an8855_sdk/api/inc/air_diag.h
@@ -0,0 +1,87 @@
+/* FILE NAME: air_diag.h
+ * PURPOSE:
+ *      Define the diagnostic function in AIR SDK.
+ *
+ * NOTES:
+ *      None
+ */
+
+#ifndef AIR_DIAG_H
+#define AIR_DIAG_H
+
+/* INCLUDE FILE DECLARATIONS
+*/
+
+/* NAMING CONSTANT DECLARATIONS
+*/
+typedef enum
+{
+    AIR_DIAG_TXCOMPLY_MODE_10M_NLP,
+    AIR_DIAG_TXCOMPLY_MODE_10M_RANDOM,
+    AIR_DIAG_TXCOMPLY_MODE_10M_SINE,
+    AIR_DIAG_TXCOMPLY_MODE_100M_PAIR_A,
+    AIR_DIAG_TXCOMPLY_MODE_100M_PAIR_B,
+    AIR_DIAG_TXCOMPLY_MODE_1000M_TM1,
+    AIR_DIAG_TXCOMPLY_MODE_1000M_TM2,
+    AIR_DIAG_TXCOMPLY_MODE_1000M_TM3,
+    AIR_DIAG_TXCOMPLY_MODE_1000M_TM4,
+    AIR_DIAG_TXCOMPLY_MODE_LAST
+}AIR_DIAG_TXCOMPLY_MODE_T;
+
+/* MACRO FUNCTION DECLARATIONS
+*/
+
+/* DATA TYPE DECLARATIONS
+*/
+
+/* EXPORTED SUBPROGRAM SPECIFICATIONS
+*/
+/* FUNCTION NAME: air_diag_setTxComplyMode
+ * PURPOSE:
+ *      Set Ethernet TX Compliance mode.
+ *
+ * INPUT:
+ *      unit            --  Device ID
+ *      port            --  Index of port number
+ *      mode            --  Testing mode of Ethernet TX Compliance
+ *
+ * OUTPUT:
+ *      None
+ *
+ * RETURN:
+ *      AIR_E_OK
+ *      AIR_E_BAD_PARAMETER
+ *
+ * NOTES:
+ */
+AIR_ERROR_NO_T
+air_diag_setTxComplyMode(
+    const UI32_T unit,
+    const UI8_T port,
+    const AIR_DIAG_TXCOMPLY_MODE_T mode);
+
+/* FUNCTION NAME: air_diag_getTxComplyMode
+ * PURPOSE:
+ *      Get Ethernet TX Compliance mode.
+ *
+ * INPUT:
+ *      unit            --  Device ID
+ *      port            --  Index of port number
+ *
+ * OUTPUT:
+ *      ptr_mode        --  Testing mode of Ethernet TX Compliance
+ *
+ * RETURN:
+ *      AIR_E_OK
+ *      AIR_E_BAD_PARAMETER
+ *      AIR_E_OTHERS
+ *
+ * NOTES:
+ */
+AIR_ERROR_NO_T
+air_diag_getTxComplyMode(
+    const UI32_T unit,
+    const UI8_T port,
+    AIR_DIAG_TXCOMPLY_MODE_T *ptr_mode);
+
+#endif /* End of AIR_DIAG_H */
diff --git a/recipes-devtools/switch/files/src/an8855_sdk/api/inc/air_error.h b/recipes-devtools/switch/files/src/an8855_sdk/api/inc/air_error.h
new file mode 100644
index 0000000..836d400
--- /dev/null
+++ b/recipes-devtools/switch/files/src/an8855_sdk/api/inc/air_error.h
@@ -0,0 +1,56 @@
+/* FILE NAME:   air_error.h

+ * PURPOSE:

+ *      Define the error code in AIR SDK.

+ * NOTES:

+ */

+

+#ifndef AIR_ERROR_H

+#define AIR_ERROR_H

+

+/* INCLUDE FILE DECLARATIONS

+ */

+

+/* NAMING CONSTANT DECLARATIONS

+ */

+

+/* MACRO FUNCTION DECLARATIONS

+ */

+

+/* DATA TYPE DECLARATIONS

+ */

+typedef enum

+{

+    AIR_E_OK = 0,              /* Ok and no error */

+    AIR_E_OTHERS,              /* Operation is unsuccessful */

+    AIR_E_BAD_PARAMETER,       /* Parameter is wrong */

+    AIR_E_TABLE_FULL,          /* Table is full */

+    AIR_E_ENTRY_NOT_FOUND,     /* Entry is not found */

+    AIR_E_ENTRY_EXISTS,        /* Entry already exists */

+    AIR_E_NOT_SUPPORT,         /* Feature is not supported */

+    AIR_E_TIMEOUT,             /* Time out error */

+    AIR_E_LAST

+} AIR_ERROR_NO_T;

+

+/* EXPORTED SUBPROGRAM SPECIFICATIONS

+ */

+/* FUNCTION NAME:   air_error_getString

+ * PURPOSE:

+ *      To obtain the error string of the specified error code

+ *

+ * INPUT:

+ *      cause  -- The specified error code

+ * OUTPUT:

+ *      None

+ * RETURN:

+ *      Pointer to the target error string

+ *

+ * NOTES:

+ *

+ *

+ */

+C8_T *

+air_error_getString(

+    const AIR_ERROR_NO_T cause );

+

+#endif  /* AIR_ERROR_H */

+

diff --git a/recipes-devtools/switch/files/src/an8855_sdk/api/inc/air_l2.h b/recipes-devtools/switch/files/src/an8855_sdk/api/inc/air_l2.h
new file mode 100644
index 0000000..1e77305
--- /dev/null
+++ b/recipes-devtools/switch/files/src/an8855_sdk/api/inc/air_l2.h
@@ -0,0 +1,323 @@
+/* FILE NAME: air_l2.h
+* PURPOSE:
+*       Define the layer 2 functions in AIR SDK.
+*
+* NOTES:
+*       None
+*/
+
+#ifndef AIR_L2_H
+#define AIR_L2_H
+
+/* INCLUDE FILE DECLARATIONS
+*/
+
+/* NAMING CONSTANT DECLARATIONS
+*/
+#define AIR_L2_MAC_MAX_AGE_OUT_TIME (1000000)
+
+#define AIR_L2_MAX_BUSY_TIME    (200)
+#define AIR_L2_MAX_AGE_CNT      (BITS(0, (AAC_AGE_CNT_LENGTH - 1)))
+#define AIR_L2_MAX_AGE_UNIT     (BITS(0, (AAC_AGE_UNIT_LENGTH - 1)))
+#define AIR_L2_MAC_SET_NUM      (4)
+#define AIR_L2_MAX_SIZE         (512)
+
+/* Field for MAC Address Table */
+/* Field for MAC entry forward control when hit source MAC */
+typedef enum
+{
+    AIR_L2_FWD_CTRL_DEFAULT,
+    AIR_L2_FWD_CTRL_CPU_INCLUDE,
+    AIR_L2_FWD_CTRL_CPU_EXCLUDE,
+    AIR_L2_FWD_CTRL_CPU_ONLY,
+    AIR_L2_FWD_CTRL_DROP,
+    AIR_L2_FWD_CTRL_LAST
+} AIR_L2_FWD_CTRL_T;
+/* MACRO FUNCTION DECLARATIONS
+*/
+
+/* DATA TYPE DECLARATIONS
+*/
+/* Entry structure of MAC table */
+typedef struct AIR_MAC_ENTRY_S
+{
+    /* L2 MAC entry keys */
+    /* MAC Address */
+    AIR_MAC_T mac;
+
+    /* Customer VID (12bits) */
+    UI16_T cvid;
+
+    /* Filter ID */
+    UI16_T fid;
+
+    /* l2 mac entry attributes */
+#define AIR_L2_MAC_ENTRY_FLAGS_IVL     (1U << 0)
+#define AIR_L2_MAC_ENTRY_FLAGS_STATIC  (1U << 1)
+#define AIR_L2_MAC_ENTRY_FLAGS_UNAUTH  (1U << 2)
+    UI32_T flags;
+
+    /* Destination Port Map */
+    AIR_PORT_BITMAP_T port_bitmap;
+
+    /* Source MAC address hit forward control */
+    AIR_L2_FWD_CTRL_T sa_fwd;
+
+    /* Age Timer only for getting information */
+    UI32_T timer;
+} AIR_MAC_ENTRY_T;
+
+/* FUNCTION NAME: air_l2_addMacAddr
+ * PURPOSE:
+ *      Add or set a L2 unicast MAC address entry.
+ *      If the address entry doesn't exist, it will add the entry.
+ *      If the address entry already exists, it will set the entry
+ *      with user input value.
+ *
+ * INPUT:
+ *      unit            --  Device ID
+ *      ptr_mac_entry   --  Structure of MAC Address table
+ *
+ * OUTPUT:
+ *      None
+ *
+ * RETURN:
+ *      AIR_E_OK
+ *      AIR_E_BAD_PARAMETER
+ *      AIR_E_TABLE_FULL
+ *      AIR_E_TIMEOUT
+ *
+ * NOTES:
+ *      None
+ */
+AIR_ERROR_NO_T
+air_l2_addMacAddr(
+    const UI32_T unit,
+    const AIR_MAC_ENTRY_T   *ptr_mac_entry);
+
+/* FUNCTION NAME: air_l2_delMacAddr
+ * PURPOSE:
+ *      Delete a L2 unicast MAC address entry.
+ *
+ * INPUT:
+ *      unit            --  Device ID
+ *      ptr_mac_entry   --  The structure of MAC Address table
+ *
+ * OUTPUT:
+ *      None
+ *
+ * RETURN:
+ *      AIR_E_OK
+ *      AIR_E_BAD_PARAMETER
+ *
+ * NOTES:
+ *      None
+ */
+AIR_ERROR_NO_T
+air_l2_delMacAddr(
+    const UI32_T unit,
+    const AIR_MAC_ENTRY_T   *ptr_mac_entry);
+
+/* FUNCTION NAME:  air_l2_getMacAddr
+ * PURPOSE:
+ *      Get a L2 unicast MAC address entry.
+ *
+ * INPUT:
+ *      unit            --  Device ID
+ *      ptr_mac_entry   --  The structure of MAC Address table
+ *
+ * OUTPUT:
+ *      ptr_count                -- The number of returned MAC entries
+ *      ptr_mac_entry            -- Structure of MAC Address table for
+ *                                  searching result.
+ *                                  The size of ptr_mac_entry depends
+ *                                  on the maximun number of bank.
+ *                                  The memory size should greater than
+ *                                  ((# of Bank) * (Size of entry
+ *                                  structure))
+ *                                  AIR_MAC_ENTRY_T
+ * RETURN:
+ *      AIR_E_OK                 -- Operation success.
+ *      AIR_E_BAD_PARAMETER      -- Parameter is wrong.
+ *      AIR_E_TIMEOUT            -- Timeout error.
+ *      AIR_E_ENTRY_NOT_FOUND    -- Entry is not found.
+ * NOTES:
+ *      If the parameter:mac in input argument ptr_mac_entry[0] is
+ *      empty. It means to search the first valid MAC address entry
+ *      in MAC address table. Otherwise, to search the specific MAC
+ *      address entry in input argument ptr_mac_entry[0].
+ *      Input argument ptr_mac_entry[0] needs include mac, ivl and
+ *      (fid or cvid) depends on ivl.
+ *      If argument ivl is TRUE, cvid is necessary, or fid is.
+ */
+AIR_ERROR_NO_T
+air_l2_getMacAddr(
+    const UI32_T unit,
+    UI8_T           *ptr_count,
+    AIR_MAC_ENTRY_T *ptr_mac_entry);
+
+/* FUNCTION NAME: hal_sco_l2_getMacBucketSize
+ * PURPOSE:
+ *      Get the bucket size of one MAC address set when searching L2 table.
+ *
+ * INPUT:
+ *      unit            --  Device ID
+ *
+ * OUTPUT:
+ *      ptr_size        --  The bucket size
+ *
+ * RETURN:
+ *      AIR_E_OK
+ *      AIR_E_BAD_PARAMETER
+ *
+ * NOTES:
+ *      None
+ */
+AIR_ERROR_NO_T
+air_l2_getMacBucketSize(
+    const UI32_T    unit,
+    UI32_T          *ptr_size);
+
+
+/* FUNCTION NAME: air_l2_getNextMacAddr
+ * PURPOSE:
+ *      Get the next L2 unicast MAC address entry.
+ *
+ * INPUT:
+ *      unit            --  Device ID
+ *      ptr_mac_entry   --  The structure of MAC Address table
+ *
+ * OUTPUT:
+ *      ptr_count       --  The number of returned MAC entries
+ *      ptr_mac_entry   --  Structure of MAC Address table for searching result.
+ *                          The size of ptr_mac_entry depends on the max. number of bank.
+ *                          The memory size should greater than ((# of Bank) * (Table size))
+ * RETURN:
+ *      AIR_E_OK
+ *      AIR_E_BAD_PARAMETER
+ *      AIR_E_TIMEOUT
+ *      AIR_E_ENTRY_NOT_FOUND
+ * NOTES:
+ *      If the parameter:mac in input argument ptr_mac_entry[0] is empty.
+ *      It means to search the next valid MAC address entries of last searching result.
+ *      Otherwise, to search the next valid MAC address entry of the specific MAC address
+ *      entry in input argument ptr_mac_entry[0].
+ *      Input argument ptr_mac_entry[0] needs include mac, ivl and (fid or cvid) depends on ivl.
+ *      If argument ivl is TRUE, cvid is necessary, or fid is.
+ */
+AIR_ERROR_NO_T
+air_l2_getNextMacAddr(
+    const UI32_T unit,
+    UI8_T           *ptr_count,
+    AIR_MAC_ENTRY_T *ptr_mac_entry);
+
+/* FUNCTION NAME: air_l2_clearMacAddr
+ * PURPOSE:
+ *      Clear all L2 unicast MAC address entry.
+ *
+ * INPUT:
+ *      unit            --  Device ID
+ *
+ * OUTPUT:
+ *      None
+ *
+ * RETURN:
+ *      AIR_E_OK
+ *      AIR_E_BAD_PARAMETER
+ *
+ * NOTES:
+ *      None
+ */
+AIR_ERROR_NO_T
+air_l2_clearMacAddr(
+    const UI32_T unit);
+
+/* FUNCTION NAME:   air_l2_setMacAddrAgeOut
+ * PURPOSE:
+ *      Set the age out time of L2 MAC address entries.
+ * INPUT:
+ *      unit                     -- Device ID
+ *      age_time                 -- Age out time (second)
+ *                                  (1..AIR_L2_MAC_MAX_AGE_OUT_TIME)
+ * OUTPUT:
+ *      None
+ * RETURN:
+ *      AIR_E_OK                 -- Operation success.
+ *      AIR_E_BAD_PARAMETER      -- Parameter is wrong.
+ * NOTES:
+ *      None
+ */
+
+AIR_ERROR_NO_T
+air_l2_setMacAddrAgeOut(
+    const UI32_T    unit,
+    const UI32_T    age_time);
+
+/* FUNCTION NAME:   air_l2_getMacAddrAgeOut
+ * PURPOSE:
+ *      Get the age out time of unicast MAC address.
+ * INPUT:
+ *      unit                     -- Device ID
+ * OUTPUT:
+ *      ptr_age_time             -- age out time
+ * RETURN:
+ *      AIR_E_OK                 -- Operation success.
+ *      AIR_E_BAD_PARAMETER      -- Parameter is wrong.
+ * NOTES:
+ *      None
+ */
+AIR_ERROR_NO_T
+air_l2_getMacAddrAgeOut(
+    const UI32_T    unit,
+    UI32_T          *ptr_age_time);
+
+/* FUNCTION NAME: air_l2_setAgeEnable
+ * PURPOSE:
+ *      Set aging state for a specific port.
+ *
+ * INPUT:
+ *      unit            --  Device ID
+ *      port            --  Index of port number
+ *      state           --  FALSE:Disable
+ *                          TRUE: Enable
+ * OUTPUT:
+ *      None
+ *
+ * RETURN:
+ *      AIR_E_OK
+ *      AIR_E_BAD_PARAMETER
+ *
+ * NOTES:
+ *      None
+ */
+AIR_ERROR_NO_T
+air_l2_setAgeEnable(
+    const UI32_T unit,
+    const UI32_T port,
+    const BOOL_T state);
+
+/* FUNCTION NAME: air_l2_getAgeEnable
+ * PURPOSE:
+ *      Get age state for a specific port.
+ *
+ * INPUT:
+ *      unit            --  Device ID
+ *      port            --  Index of port number
+ *
+ * OUTPUT:
+ *      ptr_state       --  FALSE:Disable
+ *                          TRUE: Enable
+ * RETURN:
+ *      AIR_E_OK
+ *      AIR_E_BAD_PARAMETER
+ *
+ * NOTES:
+ *      None
+ */
+AIR_ERROR_NO_T
+air_l2_getAgeEnable(
+    const UI32_T unit,
+    const UI32_T port,
+    UI32_T *ptr_state);
+
+#endif /* End of AIR_L2_H */
diff --git a/recipes-devtools/switch/files/src/an8855_sdk/api/inc/air_lag.h b/recipes-devtools/switch/files/src/an8855_sdk/api/inc/air_lag.h
new file mode 100644
index 0000000..7ab0132
--- /dev/null
+++ b/recipes-devtools/switch/files/src/an8855_sdk/api/inc/air_lag.h
@@ -0,0 +1,330 @@
+/* FILE NAME:  air_lag.h
+ * PURPOSE:
+ *      Define the Link Agrregation function in AIR SDK.
+ *
+ * NOTES:
+ *      None
+ */
+
+#ifndef AIR_LAG_H
+#define AIR_LAG_H
+
+/* INCLUDE FILE DECLARATIONS
+*/
+
+/* NAMING CONSTANT DECLARATIONS
+*/
+#define AIR_LAG_MAX_MEM_NUM       (4)
+#define AIR_LAG_MAX_PTG_NUM       (2)
+
+#define AIR_LAG_MAX_SA_LRN_NUM     BITS(0,12)
+#define AIR_GRP_PORT(p,n)         (((p) & BITS(0,4)) << (n * 8))
+#define AIR_LAG_MAX_BUSY_TIME      (20)
+
+
+
+/* MACRO FUNCTION DECLARATIONS
+*/
+
+/* DATA TYPE DECLARATIONS
+*/
+typedef struct AIR_LAG_PTGINFO_S
+{
+    UI32_T csr_gp_enable[4];
+    UI32_T csr_gp_port[4];
+}AIR_LAG_PTGINFO_T;
+
+
+typedef struct AIR_LAG_DISTINFO_S
+{
+    UI32_T sp:1;
+    UI32_T sa:1;
+    UI32_T da:1;
+    UI32_T sip:1;
+    UI32_T dip:1;
+    UI32_T sport:1;
+    UI32_T dport:1;
+    UI32_T reverse:25;
+}AIR_LAG_DISTINFO_T;
+
+/* EXPORTED SUBPROGRAM SPECIFICATIONS
+*/
+/* FUNCTION NAME: air_lag_setMember
+ * PURPOSE:
+ *      Set LAG member(s) for a specific LAG port.
+ *
+ * INPUT:
+ *      unit            --  Device ID
+ *      ptg_index       --  Port trunk index
+ *      mem_index       --  Member index
+ *      mem_en          --  enable Member
+ *      port_index      --  Member port
+ *
+ * OUTPUT:
+ *      None
+ *
+ * RETURN:
+ *      AIR_E_OK
+ *      AIR_E_BAD_PARAMETER
+ *
+ * NOTES:
+ *      None
+ */
+AIR_ERROR_NO_T
+air_lag_setMember(
+    const UI32_T        unit,
+    const UI32_T        ptg_index,
+    const UI32_T        mem_index,
+    const UI32_T        mem_en,
+    const UI32_T        port_index);
+
+
+/* FUNCTION NAME: air_lag_getMember
+ * PURPOSE:
+ *      Get LAG member count.
+ *
+ * INPUT:
+ *      unit            --  Device ID
+ *      ptg_index       --  Port trunk index
+ *
+ * OUTPUT:
+ *      member      --  Member ports of  one port trunk
+ *
+ * RETURN:
+ *      AIR_E_OK
+ *      AIR_E_BAD_PARAMETER
+ *
+ * NOTES:
+ *      None
+ */
+AIR_ERROR_NO_T
+air_lag_getMember(
+    const UI32_T unit,
+    const UI32_T ptg_index,
+    AIR_LAG_PTGINFO_T * member);
+
+/* FUNCTION NAME: air_lag_set_ptgc_state
+ * PURPOSE:
+ *     set port trunk group control state.
+ *
+ * INPUT:
+ *      unit            --  Device ID
+ *      ptgc_enable     --  enabble or disable port trunk function
+ *
+ * OUTPUT:
+ *      none
+ *
+ * RETURN:
+ *      AIR_E_OK
+ *      AIR_E_BAD_PARAMETER
+ *
+ * NOTES:
+ *      None
+ */
+AIR_ERROR_NO_T
+air_lag_set_ptgc_state(
+    const UI32_T unit,
+    const BOOL_T ptgc_enable);
+
+/* FUNCTION NAME: air_lag_get_ptgc_state
+ * PURPOSE:
+ *      Get port trunk group control state.
+ *
+ * INPUT:
+ *      unit            --  Device ID
+ *
+ * OUTPUT:
+ *      ptr_state        --  port trunk fucntion is enable or disable
+ *
+ * RETURN:
+ *      AIR_E_OK
+ *      AIR_E_BAD_PARAMETER
+ *
+ * NOTES:
+ *      None
+ */
+AIR_ERROR_NO_T
+air_lag_get_ptgc_state(
+    const UI32_T unit,
+    UI32_T *ptr_state);
+
+
+/* FUNCTION NAME: air_lag_setDstInfo
+ * PURPOSE:
+ *      Set information for the packet distribution.
+ *
+ * INPUT:
+ *      unit            --  Device ID
+ *      dstInfo         --  Infomation selection of packet distribution
+ *
+ * OUTPUT:
+ *      None
+ *
+ * RETURN:
+ *      AIR_E_OK
+ *      AIR_E_BAD_PARAMETER
+ *      AIR_E_TIMEOUT
+ *
+ * NOTES:
+ *      None
+ */
+AIR_ERROR_NO_T
+air_lag_setDstInfo(
+    const UI32_T unit,
+    const AIR_LAG_DISTINFO_T dstInfo);
+
+/* FUNCTION NAME: air_lag_getDstInfo
+ * PURPOSE:
+ *      Set port trunk hashtype.
+ *
+ * INPUT:
+ *      unit            --  Device ID
+ *
+ * OUTPUT:
+ *      ptr_dstInfo     --  Infomation selection of packet distribution
+ *
+ * RETURN:
+ *      AIR_E_OK
+ *      AIR_E_BAD_PARAMETER
+ *      AIR_E_TIMEOUT
+ *
+ * NOTES:
+ *      None
+ */
+AIR_ERROR_NO_T
+air_lag_getDstInfo(
+    const UI32_T unit,
+    AIR_LAG_DISTINFO_T *ptr_dstInfo);
+
+
+/* FUNCTION NAME: air_lag_setState
+ * PURPOSE:
+ *      Set the enable/disable for a specific LAG port.
+ *
+ * INPUT:
+ *      unit            --  Device ID
+ *      hashtype        --  crc32msb/crc32lsb/crc16/xor4
+ * OUTPUT:
+ *      None
+ *
+ * RETURN:
+ *      AIR_E_OK
+ *      AIR_E_BAD_PARAMETER
+ *
+ * NOTES:
+ *      None
+ */
+AIR_ERROR_NO_T
+air_lag_sethashtype(
+    const UI32_T unit,
+    const UI32_T hashtype);
+
+/* FUNCTION NAME: air_lag_getState
+ * PURPOSE:
+ *      Get port trunk hashtype.
+ *
+ * INPUT:
+ *      unit            --  Device ID
+ *
+ * OUTPUT:
+ *      hashtype        --  crc32msb/crc32lsb/crc16/xor4
+ * RETURN:
+ *      AIR_E_OK
+ *      AIR_E_BAD_PARAMETER
+ *
+ * NOTES:
+ *      None
+ */
+AIR_ERROR_NO_T
+air_lag_gethashtype(
+    const UI32_T unit,
+    UI32_T *hashtype);
+
+/* FUNCTION NAME: air_lag_setSpSel
+ * PURPOSE:
+ *      Set the enable/disable for selection source port composition.
+ *
+ * INPUT:
+ *      unit            --  Device ID
+ *      enable          --  enable or disable source port compare
+ * OUTPUT:
+ *      None
+ *
+ * RETURN:
+ *      AIR_E_OK
+ *      AIR_E_BAD_PARAMETER
+ *
+ * NOTES:
+ *      None
+ */
+AIR_ERROR_NO_T
+air_lag_setSpSel(
+    const UI32_T unit,
+    const BOOL_T spsel_enable);
+
+/* FUNCTION NAME: air_lag_getSpSel
+ * PURPOSE:
+ *      Get selection source port composition.
+ *
+ * INPUT:
+ *      unit            --  Device ID
+ *
+ * OUTPUT:
+ *      ptr_state       --  source port compare is enable or disable
+ * RETURN:
+ *      AIR_E_OK
+ *      AIR_E_BAD_PARAMETER
+ *
+ * NOTES:
+ *      None
+ */
+AIR_ERROR_NO_T
+air_lag_getSpSel(
+    const UI32_T unit,
+    UI32_T *ptr_state);
+
+/* FUNCTION NAME: air_lag_setPTSeed
+ * PURPOSE:
+ *      Set the enable/disable for a specific LAG port.
+ *
+ * INPUT:
+ *      unit            --  Device ID
+ *      ptseed          --  port trunk rand seed
+ * OUTPUT:
+ *      None
+ *
+ * RETURN:
+ *      AIR_E_OK
+ *      AIR_E_BAD_PARAMETER
+ *
+ * NOTES:
+ *      None
+ */
+AIR_ERROR_NO_T
+air_lag_setPTSeed(
+    const UI32_T unit,
+    const UI32_T ptseed);
+
+/* FUNCTION NAME: air_lag_getPTSeed
+ * PURPOSE:
+ *      Get port trunk hashtype.
+ *
+ * INPUT:
+ *      unit            --  Device ID
+ *
+ * OUTPUT:
+ *      ptseed          --  port trunk rand seed
+ * RETURN:
+ *      AIR_E_OK
+ *      AIR_E_BAD_PARAMETER
+ *
+ * NOTES:
+ *      None
+ */
+AIR_ERROR_NO_T
+air_lag_getPTSeed(
+    const UI32_T unit,
+    UI32_T *ptseed);
+
+
+#endif /* End of AIR_LAG_H */
diff --git a/recipes-devtools/switch/files/src/an8855_sdk/api/inc/air_led.h b/recipes-devtools/switch/files/src/an8855_sdk/api/inc/air_led.h
new file mode 100644
index 0000000..6419453
--- /dev/null
+++ b/recipes-devtools/switch/files/src/an8855_sdk/api/inc/air_led.h
@@ -0,0 +1,299 @@
+/* FILE NAME: air_led.h
+ * PURPOSE:
+ * 1. Define information for air_led.c
+ * NOTES:
+ */
+
+#ifndef AIR_LED_H
+#define AIR_LED_H
+
+/* INCLUDE FILE DECLARATIONS
+*/
+
+/* NAMING CONSTANT DECLARATIONS
+*/
+
+#define MAX_NUM_LED_ENTITY          2
+#define UNIT_LED_BLINK_DURATION     1024
+
+typedef enum
+{
+    AIR_LED_MODE_DISABLE,      /* ALL LED outputs ard disabled */
+    AIR_LED_MODE_2LED_MODE0,   /* 2 LED pins are enabled. Active high.
+                                   LED 0: Link.
+                                   LED 1: Activity. */
+    AIR_LED_MODE_2LED_MODE1,   /* 2 LED pins are enabled. Active high.
+                                   LED 0: Link 1000 Activity.
+                                   LED 1: Link 100 Activity. */
+    AIR_LED_MODE_2LED_MODE2,   /* 2 LED pins are enabled. Active high.
+                                   LED 0: Link 1000 Activity.
+                                   LED 1: Link 10/100 Activity. */
+    AIR_LED_MODE_USER_DEFINE,  /* LED functions of each pin are user-defined */
+    AIR_LED_MODE_LAST
+}AIR_LED_MODE_T;
+
+typedef enum
+{
+    AIR_LED_BLK_DUR_32M,           /* Blink duration: 32 ms */
+    AIR_LED_BLK_DUR_64M,           /* Blink duration: 64 ms */
+    AIR_LED_BLK_DUR_128M,          /* Blink duration: 128 ms */
+    AIR_LED_BLK_DUR_256M,          /* Blink duration: 256 ms */
+    AIR_LED_BLK_DUR_512M,          /* Blink duration: 512 ms */
+    AIR_LED_BLK_DUR_1024M,         /* Blink duration: 1024 ms */
+    AIR_LED_BLK_DUR_LAST
+}AIR_LED_BLK_DUR_T;
+
+/* MACRO FUNCTION DECLARATIONS
+*/
+
+/* DATA TYPE DECLARATIONS
+*/
+typedef struct AIR_LED_ON_EVT_S
+{
+    BOOL_T link_1000m;     /* Link 1000M */
+    BOOL_T link_100m;      /* Link 100M */
+    BOOL_T link_10m;       /* Link 10M */
+    BOOL_T link_dn;        /* Link Down */
+    BOOL_T fdx;            /* Full Duplex */
+    BOOL_T hdx;            /* Half Duplex */
+    BOOL_T force;          /* Force on (logic 1) */
+}AIR_LED_ON_EVT_T;
+
+typedef struct AIR_LED_BLK_EVT_S
+{
+    BOOL_T tx_act_1000m;  /* 1000Mbps TX Activity */
+    BOOL_T rx_act_1000m;  /* 1000Mbps RX Activity */
+    BOOL_T tx_act_100m;   /* 100Mbps TX Activity */
+    BOOL_T rx_act_100m;   /* 100Mbps RX Activity */
+    BOOL_T tx_act_10m;    /* 10Mbps TX Activity */
+    BOOL_T rx_act_10m;    /* 10Mbps RX Activity */
+    BOOL_T cls;           /* Collision */
+    BOOL_T rx_crc;        /* Rx CRC Error */
+    BOOL_T rx_idle;       /* Rx Idle Error */
+    BOOL_T force;         /* Force blinks (logic 1) */
+}AIR_LED_BLK_EVT_T;
+
+/* EXPORTED SUBPROGRAM SPECIFICATIONS
+*/
+/* FUNCTION NAME: air_led_setMode
+ * PURPOSE:
+ *      Set the LED processing mode for a specific port.
+ *
+ * INPUT:
+ *      unit            --  Device ID
+ *      port            --  Index of port number
+ *      mode            --  Setting mode of LED
+ *
+ * OUTPUT:
+ *      None
+ *
+ * RETURN:
+ *      AIR_E_OK
+ *      AIR_E_BAD_PARAMETER
+ *
+ * NOTES:
+ *      The LED control register is shared with all port on AN8855.
+ *      Setting LED on any one port will also set to each other ports.
+ */
+AIR_ERROR_NO_T
+air_led_setMode(
+    const UI32_T unit,
+    const UI8_T port,
+    const AIR_LED_MODE_T mode);
+
+/* FUNCTION NAME:air_led_getMode
+ * PURPOSE:
+ *      Get the LED processing mode for a specific port.
+ *
+ * INPUT:
+ *      unit            --  Device ID
+ *      port            --  Index of port number
+ *
+ * OUTPUT:
+ *      ptr_mode        --  Setting mode of LED
+ *
+ * RETURN:
+ *      AIR_E_OK
+ *      AIR_E_OTHERS
+ *      AIR_E_BAD_PARAMETER
+ *
+ * NOTES:
+ *      None
+ */
+AIR_ERROR_NO_T
+air_led_getMode(
+    const UI32_T unit,
+    const UI8_T port,
+    AIR_LED_MODE_T *ptr_mode);
+
+/* FUNCTION NAME: air_led_setState
+ * PURPOSE:
+ *      Set the enable state for a specific LED.
+ *
+ * INPUT:
+ *      unit            --  Device ID
+ *      port            --  Index of port number
+ *      entity          --  Entity of LED
+ *      state           --  TRUE: Enable
+ *                          FALSE: Disable
+ * OUTPUT:
+ *      None
+ *
+ * RETURN:
+ *      AIR_E_OK
+ *      AIR_E_BAD_PARAMETER
+ *
+ * NOTES:
+ *      The LED control register is shared with all port on AN8855.
+ *      Setting LED on any one port will also set to each other ports.
+ */
+AIR_ERROR_NO_T
+air_led_setState(
+    const UI32_T unit,
+    const UI8_T port,
+    const UI8_T entity,
+    const BOOL_T state);
+
+/* FUNCTION NAME: air_led_getState
+ * PURPOSE:
+ *      Get the enable state for a specific LED.
+ *
+ * INPUT:
+ *      unit            --  Device ID
+ *      port            --  Index of port number
+ *      entity          --  Entity of LED
+ *
+ * OUTPUT:
+ *      ptr_state       --  TRUE: Enable
+ *                          FALSE: Disable
+ * RETURN:
+ *      AIR_E_OK
+ *      AIR_E_BAD_PARAMETER
+ *
+ * NOTES:
+ *      None
+ */
+AIR_ERROR_NO_T
+air_led_getState(
+    const UI32_T unit,
+    const UI8_T port,
+    const UI8_T entity,
+    BOOL_T *ptr_state);
+
+/* FUNCTION NAME: air_led_setUsrDef
+ * PURPOSE:
+ *      Set the user-defined configuration of a speficic LED.
+ *      It only work when air_led_setState() set to AIR_LED_MODE_USER_DEFINE.
+ *
+ * INPUT:
+ *      unit            --  Device ID
+ *      port            --  Index of port number
+ *      entity          --  Entity of LED
+ *      polar           --  LOW: Active low
+ *                          HIGH: Active high
+ *      on_evt          --  AIR_LED_ON_EVT_T
+ *                          LED turns on if any event is detected
+ *      blk_evt         --  AIR_LED_BLK_EVT_T
+ *                          LED blinks blink if any event is detected
+ * OUTPUT:
+ *      None
+ *
+ * RETURN:
+ *      AIR_E_OK
+ *      AIR_E_BAD_PARAMETER
+ *
+ * NOTES:
+ *      The LED control register is shared with all port on AN8855.
+ *      Setting LED on any one port will also set to each other ports.
+ */
+AIR_ERROR_NO_T
+air_led_setUsrDef(
+    const UI32_T unit,
+    const UI8_T port,
+    const UI8_T entity,
+    const BOOL_T polar,
+    const AIR_LED_ON_EVT_T on_evt,
+    const AIR_LED_BLK_EVT_T blk_evt);
+
+/* FUNCTION NAME: air_led_getUsrDef
+ * PURPOSE:
+ *      Get the user-defined configuration of a speficic LED.
+ *
+ * INPUT:
+ *      unit            --  Device ID
+ *      port            --  Index of port number
+ *      entity          --  Entity of LED
+ * OUTPUT:
+ *      ptr_polar       --  LOW: Active low
+ *                          HIGH: Active high
+ *      ptr_on_evt      --  AIR_LED_ON_EVT_T
+ *                          LED turns on if any event is detected
+ *      ptr_blk_evt     --  AIR_LED_BLK_EVT_T
+ *                          LED blinks if any event is detected
+ * RETURN:
+ *      AIR_E_OK
+ *      AIR_E_BAD_PARAMETER
+ *
+ * NOTES:
+ *      None
+ */
+AIR_ERROR_NO_T
+air_led_getUsrDef(
+    const UI32_T unit,
+    const UI8_T port,
+    const UI8_T entity,
+    BOOL_T *ptr_polar,
+    AIR_LED_ON_EVT_T *ptr_on_evt,
+    AIR_LED_BLK_EVT_T *ptr_blk_evt);
+
+/* FUNCTION NAME: air_led_setBlkTime
+ * PURPOSE:
+ *      Set the Blinking duration of a speficic LED.
+ *      It only work when air_led_setState() set to AIR_LED_MODE_USER_DEFINE.
+ *
+ * INPUT:
+ *      unit            --  Device ID
+ *      port            --  Index of port number
+ *      dur             --  Blink duration
+ *
+ * OUTPUT:
+ *      None
+ *
+ * RETURN:
+ *      AIR_E_OK
+ *      AIR_E_BAD_PARAMETER
+ *
+ * NOTES:
+ *      The LED control register is shared with all port on AN8855.
+ *      Setting LED on any one port will also set to each other ports.
+ */
+AIR_ERROR_NO_T
+air_led_setBlkTime(
+    const UI32_T unit,
+    const UI8_T port,
+    const AIR_LED_BLK_DUR_T dur);
+
+/* FUNCTION NAME: air_led_getBlkTime
+ * PURPOSE:
+ *      Get the Blinking duration of a speficic LED.
+ * INPUT:
+ *      unit            --  Device ID
+ *      port            --  Index of port number
+ *
+ * OUTPUT:
+ *      ptr_dur         --  Blink duration
+ *
+ * RETURN:
+ *      AIR_E_OK
+ *      AIR_E_BAD_PARAMETER
+ *
+ * NOTES:
+ *      None
+ */
+AIR_ERROR_NO_T
+air_led_getBlkTime(
+    const UI32_T unit,
+    const UI8_T port,
+    AIR_LED_BLK_DUR_T *ptr_dur);
+
+#endif /* End of AIR_LED_H */
diff --git a/recipes-devtools/switch/files/src/an8855_sdk/api/inc/air_mib.h b/recipes-devtools/switch/files/src/an8855_sdk/api/inc/air_mib.h
new file mode 100644
index 0000000..6ce0323
--- /dev/null
+++ b/recipes-devtools/switch/files/src/an8855_sdk/api/inc/air_mib.h
@@ -0,0 +1,250 @@
+/* FILE NAME: air_mib.h
+ * PURPOSE:
+ *      Define the MIB counter function in AIR SDK.
+ *
+ * NOTES:
+ *      None
+ */
+
+#ifndef AIR_MIB_H
+#define AIR_MIB_H
+
+/* INCLUDE FILE DECLARATIONS
+*/
+#define MIB_ALL_ITEM    0xFFFFFFFF
+#define AIR_MIB_MAX_ACL_EVENT_NUM      (64)
+#define CSR_ACL_MIB_SEL_OFFSET          (4)
+
+/* NAMING CONSTANT DECLARATIONS
+*/
+typedef struct AIR_MIB_CNT_TX_S
+{
+    UI32_T TDPC;      /* TX Drop Packet */
+    UI32_T TCRC;      /* TX CRC Packet */
+    UI32_T TUPC;      /* TX Unicast Packet */
+    UI32_T TMPC;      /* TX Multicast Packet */
+    UI32_T TBPC;      /* TX Broadcast Packet */
+    UI32_T TCEC;      /* TX Collision Event Count */
+    UI32_T TSCEC;     /* TX Single Collision Event Count */
+    UI32_T TMCEC;     /* TX Multiple Conllision Event Count */
+    UI32_T TDEC;      /* TX Deferred Event Count */
+    UI32_T TLCEC;     /* TX Late Collision Event Count */
+    UI32_T TXCEC;     /* TX Excessive Collision Event Count */
+    UI32_T TPPC;      /* TX Pause Packet */
+    UI32_T TL64PC;    /* TX Packet Length 64 bytes */
+    UI32_T TL65PC;    /* TX Packet Length 65 ~ 127 bytes */
+    UI32_T TL128PC;   /* TX Packet Length 128 ~ 255 bytes */
+    UI32_T TL256PC;   /* TX Packet Length 256 ~ 511 bytes */
+    UI32_T TL512PC;   /* TX Packet Length 512 ~ 1023 bytes */
+    UI32_T TL1024PC;  /* TX Packet Length 1024 ~ 1518 bytes */
+    UI32_T TL1519PC;  /* TX Packet Length 1519 ~ max bytes */
+    UI32_T TODPC;     /* TX Oversize Drop Packet */
+    UI64_T TOC;       /* TX Octets good or bad packtes determined by TX_OCT_CNT_GOOD or TX_OCT_CNT_BAD(64 bit-width)*/
+    UI64_T TOC2;      /* TX Octets bad packets (64 bit-width)*/
+}AIR_MIB_CNT_TX_T;
+
+typedef struct AIR_MIB_CNT_RX_S
+{
+    UI32_T RDPC;      /* RX Drop Packet */
+    UI32_T RFPC;      /* RX filtering Packet */
+    UI32_T RUPC;      /* RX Unicast Packet */
+    UI32_T RMPC;      /* RX Multicast Packet */
+    UI32_T RBPC;      /* RX Broadcast Packet */
+    UI32_T RAEPC;     /* RX Alignment Error Packet */
+    UI32_T RCEPC;     /* RX CRC Packet */
+    UI32_T RUSPC;     /* RX Undersize Packet */
+    UI32_T RFEPC;     /* RX Fragment Error Packet */
+    UI32_T ROSPC;     /* RX Oversize Packet */
+    UI32_T RJEPC;     /* RX Jabber Error Packet */
+    UI32_T RPPC;      /* RX Pause Packet */
+    UI32_T RL64PC;    /* RX Packet Length 64 bytes */
+    UI32_T RL65PC;    /* RX Packet Length 65 ~ 127 bytes */
+    UI32_T RL128PC;   /* RX Packet Length 128 ~ 255 bytes */
+    UI32_T RL256PC;   /* RX Packet Length 256 ~ 511 bytes */
+    UI32_T RL512PC;   /* RX Packet Length 512 ~ 1023 bytes */
+    UI32_T RL1024PC;  /* RX Packet Length 1024 ~ 1518 bytes */
+    UI32_T RL1519PC;  /* RX Packet Length 1519 ~ max bytes */
+    UI32_T RCDPC;     /* RX_CTRL Drop Packet */
+    UI32_T RIDPC;     /* RX Ingress Drop Packet */
+    UI32_T RADPC;     /* RX ARL Drop Packet */
+    UI32_T FCDPC;     /* FLow Control Drop Packet */
+    UI32_T WRDPC;     /* WRED Drop Packtet */
+    UI32_T MRDPC;     /* Mirror Drop Packet */
+    UI32_T SFSPC;     /* RX  sFlow Sampling Packet */
+    UI32_T SFTPC;     /* Rx sFlow Total Packet */
+    UI32_T RXC_DPC;   /* Port Control Drop Packet */
+    UI64_T ROC;       /* RX Octets good or bad packtes determined by TX_OCT_CNT_GOOD or TX_OCT_CNT_BAD (64 bit-width)*/
+    UI64_T ROC2;      /* RX Octets bad packets (64 bit-width)*/
+
+}AIR_MIB_CNT_RX_T;
+
+/* MACRO FUNCTION DECLARATIONS
+*/
+
+/* DATA TYPE DECLARATIONS
+*/
+
+/* EXPORTED SUBPROGRAM SPECIFICATIONS
+*/
+/* FUNCTION NAME: air_mib_setEnable
+ * PURPOSE:
+ *      Enable or Disable mib count fucntion.
+ *
+ * INPUT:
+ *      unit           --   Device ID
+ *      mib_en         --   enable or disable mib_en
+ *
+ * OUTPUT:
+ *      None
+ *
+ * RETURN:
+ *      AIR_E_OK
+ *      AIR_E_BAD_PARAMETER
+ *
+ * NOTES:
+ *      None
+ */
+AIR_ERROR_NO_T
+air_mib_setEnable(
+    const UI32_T unit,
+    const BOOL_T mib_en);
+/* FUNCTION NAME: air_mib_getEnable
+ * PURPOSE:
+ *      Enable or Disable mib count fucntion.
+ *
+ * INPUT:
+ *      unit           --   Device ID
+ *
+ * OUTPUT:
+ *      mib_en         --   enable or disable mib_en
+
+ *
+ * RETURN:
+ *      AIR_E_OK
+ *      AIR_E_BAD_PARAMETER
+ *
+ * NOTES:
+ *      None
+ */
+AIR_ERROR_NO_T
+air_mib_getEnable(
+    const UI32_T unit,
+    BOOL_T *mib_en);
+
+/* FUNCTION NAME: air_mib_clear
+ * PURPOSE:
+ *      Clear all counters of all MIB counters.
+ *
+ * INPUT:
+ *      unit            --  Device ID
+ *
+ * OUTPUT:
+ *      None
+ *
+ * RETURN:
+ *      AIR_E_OK
+ *      AIR_E_BAD_PARAMETER
+ *
+ * NOTES:
+ *      None
+ */
+AIR_ERROR_NO_T
+air_mib_clear(
+    const UI32_T unit);
+
+/* FUNCTION NAME: air_mib_clear_by_port
+ * PURPOSE:
+ *      Clear all counters of all MIB counters.
+ *
+ * INPUT:
+ *      unit            --  Device ID
+ *      port            --  clear port number
+ *
+ * OUTPUT:
+ *      None
+ *
+ * RETURN:
+ *      AIR_E_OK
+ *      AIR_E_BAD_PARAMETER
+ *
+ * NOTES:
+ *      None
+ */
+AIR_ERROR_NO_T
+air_mib_clear_by_port(
+    const UI32_T unit,
+    const UI32_T port);
+
+/* FUNCTION NAME: air_mib_clearAclEvent
+ * PURPOSE:
+ *      Clear all counters of ACL event
+ *
+ * INPUT:
+ *      unit            --  Device ID
+ *
+ * OUTPUT:
+ *      None
+ *
+ * RETURN:
+ *      AIR_E_OK
+ *      AIR_E_BAD_PARAMETER
+ *
+ * NOTES:
+ *      None
+ */
+
+/* FUNCTION NAME: air_mib_get
+ * PURPOSE:
+ *      Get the structure of MIB counter for a specific port.
+ *
+ * INPUT:
+ *      unit            --  Device ID
+ *      port            --  Index of port number
+ *
+ * OUTPUT:
+ *      ptr_rx_mib      --  MIB Counters of Rx Event
+ *      ptr_tx_mib      --  MIB Counters of Tx Event
+ *
+ * RETURN:
+ *      AIR_E_OK
+ *      AIR_E_BAD_PARAMETER
+ *
+ * NOTES:
+ *      None
+ */
+AIR_ERROR_NO_T
+air_mib_get(
+    const UI32_T unit,
+    const UI32_T port,
+    AIR_MIB_CNT_RX_T *ptr_rx_mib,
+    AIR_MIB_CNT_TX_T *ptr_tx_mib);
+
+AIR_ERROR_NO_T
+air_mib_clearAclEvent(
+    const UI32_T unit);
+
+/* FUNCTION NAME: air_mib_getAclEvent
+ * PURPOSE:
+ *      Get the total number of ACL event occurred.
+ *
+ * INPUT:
+ *      unit            --  Device ID
+ *      idx             --  Index of ACL event
+ *
+ * OUTPUT:
+ *      ptr_cnt         --  The total number of ACL event occured
+ *
+ * RETURN:
+ *      AIR_E_OK
+ *      AIR_E_BAD_PARAMETER
+ *
+ * NOTES:
+ *      None
+ */
+AIR_ERROR_NO_T
+air_mib_getAclEvent(
+    const UI32_T unit,
+    const UI32_T idx,
+    UI32_T *ptr_cnt);
+
+#endif /* End of AIR_MIB_H */
diff --git a/recipes-devtools/switch/files/src/an8855_sdk/api/inc/air_mirror.h b/recipes-devtools/switch/files/src/an8855_sdk/api/inc/air_mirror.h
new file mode 100644
index 0000000..2bef998
--- /dev/null
+++ b/recipes-devtools/switch/files/src/an8855_sdk/api/inc/air_mirror.h
@@ -0,0 +1,202 @@
+/* FILE NAME: air_mirror.h
+ * PURPOSE:
+ *      Define the port mirror function in AIR SDK.
+ *
+ * NOTES:
+ *      None
+ */
+
+#ifndef AIR_MIRROR_H
+#define AIR_MIRROR_H
+
+/* INCLUDE FILE DECLARATIONS
+*/
+
+/* NAMING CONSTANT DECLARATIONS
+*/
+#define AIR_MAX_MIRROR_SESSION  (2)
+/* MACRO FUNCTION DECLARATIONS
+*/
+
+/* DATA TYPE DECLARATIONS
+*/
+
+/* mirror session */
+typedef struct AIR_MIR_SESSION_S
+{
+#define AIR_MIR_SESSION_FLAGS_ENABLE            (1U << 0)
+#define AIR_MIR_SESSION_FLAGS_DIR_TX            (1U << 1)
+#define AIR_MIR_SESSION_FLAGS_DIR_RX            (1U << 2)
+#define AIR_MIR_SESSION_FLAGS_TX_TAG_OBEY_CFG   (1U << 3)
+
+    /* flags refer to AIR_MIR_SESSION_FLAGS_XXX */
+    UI32_T                              flags;
+    UI32_T                              dst_port;
+    UI32_T                              src_port;
+} AIR_MIR_SESSION_T;
+
+/* EXPORTED SUBPROGRAM SPECIFICATIONS
+*/
+/* FUNCTION NAME: air_mir_addSession
+* PURPOSE:
+*      This API is used to add or set a mirror session.
+* INPUT:
+*      unit        --   Device unit number
+*      session_id  --   The session information
+*      ptr_session --   The session information
+* OUTPUT:
+*       None
+*
+* RETURN:
+*       AIR_E_OK
+*       AIR_E_BAD_PARAMETER
+*
+* NOTES:
+*       None
+*/
+AIR_ERROR_NO_T
+air_mir_addSession(
+    const UI32_T unit,
+    const UI32_T session_id,
+    const AIR_MIR_SESSION_T *ptr_session);
+
+/* FUNCTION NAME: air_mir_delSession
+* PURPOSE:
+*      This API is used to delete a mirror session.
+* INPUT:
+*      unit        --   Device unit number
+*      session_id  --   The session information
+* OUTPUT:
+*       None
+*
+* RETURN:
+*       AIR_E_OK
+*       AIR_E_BAD_PARAMETER
+*
+* NOTES:
+*       None
+*/
+AIR_ERROR_NO_T
+air_mir_delSession(
+    const UI32_T unit,
+    const UI32_T session_id);
+
+
+/* FUNCTION NAME: air_mir_getSession
+* PURPOSE:
+*      This API is used to get mirror session information.
+* INPUT:
+*      unit         --  Device unit number
+*      session_id   --   The session information
+* OUTPUT:
+*      ptr_session  --  The information of this session to be obtained
+* RETURN:
+*       AIR_E_OK
+*       AIR_E_BAD_PARAMETER
+*
+* NOTES:
+*       None
+*/
+AIR_ERROR_NO_T
+air_mir_getSession(
+    const UI32_T unit,
+    const UI32_T session_id,
+    AIR_MIR_SESSION_T *ptr_session);
+
+
+/* FUNCTION NAME: air_mir_setSessionAdminMode
+* PURPOSE:
+*      This API is used to set mirror session state
+* INPUT:
+*      unit         --  Device unit number
+*      session_id   --  mirror session id
+*      state        --  FALSE: disable
+*                       TRUE:  enable
+* OUTPUT:
+*      None
+* RETURN:
+*       AIR_E_OK
+*       AIR_E_BAD_PARAMETER
+*
+* NOTES:
+*       None
+*/
+AIR_ERROR_NO_T
+air_mir_setSessionAdminMode(
+    const UI32_T unit,
+    const UI32_T session_id,
+    const BOOL_T state);
+
+
+/* FUNCTION NAME: air_mir_getSessionAdminMode
+* PURPOSE:
+*      This API is used to get mirror session state
+* INPUT:
+*      unit         --  Device unit number
+*      session_id   --  mirror session id
+* OUTPUT:
+*      state        --  FALSE: disable
+*                       TRUE:  enable
+* RETURN:
+*       AIR_E_OK
+*       AIR_E_BAD_PARAMETER
+*
+* NOTES:
+*       None
+*/
+AIR_ERROR_NO_T
+air_mir_getSessionAdminMode(
+    const UI32_T unit,
+    const UI32_T session_id,
+    BOOL_T *state);
+
+
+/* EXPORTED SUBPROGRAM SPECIFICATIONS
+*/
+/* FUNCTION NAME: air_mir_setMirrorPort
+* PURPOSE:
+*      This API is used to set mirror port mirroring type
+* INPUT:
+*      unit        --   Device unit number
+*      session_id  --  mirror session id
+*      ptr_session --   The session information
+* OUTPUT:
+*       None
+*
+* RETURN:
+*       AIR_E_OK
+*       AIR_E_BAD_PARAMETER
+*
+* NOTES:
+*       None
+*/
+AIR_ERROR_NO_T
+air_mir_setMirrorPort(
+    const UI32_T unit,
+    const UI32_T session_id,
+    const AIR_MIR_SESSION_T *ptr_session);
+
+
+/* FUNCTION NAME: air_mir_getMirrorPort
+* PURPOSE:
+*      This API is used to get mirror port mirroring type
+* INPUT:
+*      unit         --  Device unit number
+*      session_id   --  mirror session id
+* OUTPUT:
+*      ptr_session  --  The information of this session to be obtained
+* RETURN:
+*       AIR_E_OK
+*       AIR_E_BAD_PARAMETER
+*
+* NOTES:
+*       None
+*/
+AIR_ERROR_NO_T
+air_mir_getMirrorPort(
+    const UI32_T unit,
+    const UI32_T session_id,
+    AIR_MIR_SESSION_T *ptr_session);
+
+
+#endif /* End of AIR_MIRROR_H */
diff --git a/recipes-devtools/switch/files/src/an8855_sdk/api/inc/air_port.h b/recipes-devtools/switch/files/src/an8855_sdk/api/inc/air_port.h
new file mode 100644
index 0000000..a8745eb
--- /dev/null
+++ b/recipes-devtools/switch/files/src/an8855_sdk/api/inc/air_port.h
@@ -0,0 +1,963 @@
+/* FILE NAME:   air_port.h

+ * PURPOSE:

+ *      Define port function in AIR SDK.

+ *

+ * NOTES:

+ *      None

+ */

+

+#ifndef AIR_PORT_H

+#define AIR_PORT_H

+

+/* INCLUDE FILE DECLARATIONS

+ */

+

+/* NAMING CONSTANT DECLARATIONS

+ */

+#define AIR_MAX_NUM_OF_UNIT            (1)

+#define AIR_DST_DEFAULT_PORT           (31)

+#define AIR_PORT_TX                    (0x00)

+#define AIR_PORT_RX                    (0x01)

+#define AIR_MAX_NUM_OF_PORTS           (7)

+#define AIR_MAX_NUM_OF_GIGA_PORTS      (5)

+#define AIR_SGMII_PORT_OFFSET_BEGIN    (5)

+#define AIR_SGMII_PORT_OFFSET_END      (6)

+#define AIR_ALL_PORT_BITMAP            (0x7F)

+

+/* Definition of Power Saving mode */

+#define AIR_PORT_PS_LINKSTATUS         (0x1 << 0)

+#define AIR_PORT_PS_EEE                (0x1 << 1)

+#define AIR_PORT_PS_MASK               (0x3)

+

+/* MACRO FUNCTION DECLARATIONS

+ */

+

+/* DATA TYPE DECLARATIONS

+ */

+/* AIR_PORT_BITMAP_T is the data type for physical port bitmap. */

+#define AIR_BITMAP_SIZE(bit_num)                    ((((bit_num) - 1) / AIR_MAX_NUM_OF_PORTS) + 1)

+#define AIR_PORT_BITMAP_SIZE           AIR_BITMAP_SIZE(AIR_MAX_NUM_OF_PORTS)

+typedef UI32_T   AIR_PORT_BITMAP_T[AIR_PORT_BITMAP_SIZE];

+

+#define AIR_INVALID_ID      (0xFFFFFFFF)

+#define AIR_PORT_INVALID    (AIR_INVALID_ID)

+

+/* Definition of SGMII mode */

+typedef enum

+{

+    AIR_PORT_SGMII_MODE_AN,

+    AIR_PORT_SGMII_MODE_FORCE,

+    AIR_PORT_SGMII_MODE_LAST

+}AIR_PORT_SGMII_MODE_T;

+

+/* Definition of port speed */

+typedef enum

+{

+    AIR_PORT_SPEED_10M,

+    AIR_PORT_SPEED_100M,

+    AIR_PORT_SPEED_1000M,

+    AIR_PORT_SPEED_2500M,

+    AIR_PORT_SPEED_LAST

+}AIR_PORT_SPEED_T;

+

+typedef enum

+{

+    AIR_PORT_DUPLEX_HALF,

+    AIR_PORT_DUPLEX_FULL,

+    AIR_PORT_DUPLEX_LAST

+}AIR_PORT_DUPLEX_T;

+

+typedef enum

+{

+    AIR_PORT_LINK_DOWN,

+    AIR_PORT_LINK_UP,

+    AIR_PORT_LINK_LAST

+}AIR_PORT_LINK_T;

+

+/* Definition of Smart speed down will occur after AN failed how many times */

+typedef enum

+{

+    AIR_PORT_SSD_2T,

+    AIR_PORT_SSD_3T,

+    AIR_PORT_SSD_4T,

+    AIR_PORT_SSD_5T,

+    AIR_PORT_SSD_LAST

+}AIR_PORT_SSD_T;

+

+typedef enum

+{

+    AIR_PORT_VLAN_MODE_PORT_MATRIX = 0,    /* Port matrix mode  */

+    AIR_PORT_VLAN_MODE_FALLBACK,           /* Fallback mode  */

+    AIR_PORT_VLAN_MODE_CHECK,              /* Check mode  */

+    AIR_PORT_VLAN_MODE_SECURITY,           /* Security mode  */

+    AIR_PORT_VLAN_MODE_LAST

+} AIR_PORT_VLAN_MODE_T;

+

+/* Definition of AN Advertisement Register */

+typedef struct AIR_AN_ADV_S

+{

+    BOOL_T advCap10HDX;         /* Advertises 10 BASE-T HDX */

+    BOOL_T advCap10FDX;         /* Advertises 10 BASE-T FDX */

+    BOOL_T advCap100HDX;        /* Advertises 100 BASE-T HDX */

+    BOOL_T advCap100FDX;        /* Advertises 100 BASE-T FDX */

+    BOOL_T advCap1000FDX;       /* Advertises 1000 BASE-T FDX */

+    BOOL_T advPause;            /* Advertieses Asynchronous Pause */

+}AIR_AN_ADV_T;

+

+/* Definition of Link Status of a specific port */

+typedef struct AIR_PORT_STATUS_S

+{

+    BOOL_T link;

+    BOOL_T duplex;

+    UI32_T speed;

+}AIR_PORT_STATUS_T;

+

+/* EXPORTED SUBPROGRAM SPECIFICATIONS

+ */

+/* FUNCTION NAME: air_port_setPortMatrix

+ * PURPOSE:

+ *      Set port matrix from the specified device.

+ *

+ * INPUT:

+ *      unit            --  Unit id

+ *      port            --  Port id

+ *      port_bitmap     --  Matrix port bitmap

+ *

+ * OUTPUT:

+ *      None

+ *

+ * RETURN:

+ *      AIR_E_OK

+ *      AIR_E_OTHERS

+ *      AIR_E_BAD_PARAMETER

+ *

+ * NOTES:

+ *      none

+ */

+AIR_ERROR_NO_T

+air_port_setPortMatrix(

+    const UI32_T    unit,

+    const UI32_T    port,

+    const UI32_T    port_bitmap);

+

+/* FUNCTION NAME: air_port_getPortMatrix

+ * PURPOSE:

+ *      Get port matrix from the specified device.

+ *

+ * INPUT:

+ *      unit            --  Unit id

+ *      port            --  Port id

+ *

+ * OUTPUT:

+ *      p_port_bitmap   --  Matrix port bitmap

+ *

+ * RETURN:

+ *      AIR_E_OK

+ *      AIR_E_OTHERS

+ *      AIR_E_BAD_PARAMETER

+ *

+ * NOTES:

+ *      none

+ */

+AIR_ERROR_NO_T

+air_port_getPortMatrix(

+    const UI32_T    unit,

+    const UI32_T    port,

+    UI32_T          *p_port_bitmap);

+

+/* FUNCTION NAME: air_port_setVlanMode

+ * PURPOSE:

+ *      Set port-based vlan mechanism from the specified device.

+ *

+ * INPUT:

+ *      unit            --  Unit id

+ *      port            --  Port id

+ *      mode            --  Port vlan mode

+ *

+ * OUTPUT:

+ *      None

+ *

+ * RETURN:

+ *      AIR_E_OK

+ *      AIR_E_OTHERS

+ *      AIR_E_BAD_PARAMETER

+ *

+ * NOTES:

+ *      none

+ */

+AIR_ERROR_NO_T

+air_port_setVlanMode(

+    const UI32_T    unit,

+    const UI32_T    port,

+    const AIR_PORT_VLAN_MODE_T mode);

+

+/* FUNCTION NAME: air_port_getVlanMode

+ * PURPOSE:

+ *      Get port-based vlan mechanism from the specified device.

+ *

+ * INPUT:

+ *      unit            --  Unit id

+ *      port            --  Port id

+ *

+ * OUTPUT:

+ *      p_mode          --  Port vlan mode

+ *

+ * RETURN:

+ *      AIR_E_OK

+ *      AIR_E_OTHERS

+ *      AIR_E_BAD_PARAMETER

+ *

+ * NOTES:

+ *      none

+ */

+AIR_ERROR_NO_T

+air_port_getVlanMode(

+    const UI32_T    unit,

+    const UI32_T    port,

+    AIR_PORT_VLAN_MODE_T *p_mode);

+

+/* FUNCTION NAME: air_port_setAnMode

+ * PURPOSE:

+ *      Set the auto-negotiation mode for a specific port.(Auto or Forced)

+ *

+ * INPUT:

+ *      unit            --  Device ID

+ *      port            --  Index of port number

+ *      state           --  FALSE:Disable

+ *                          TRUE: Enable

+ * OUTPUT:

+ *      None

+ *

+ * RETURN:

+ *      AIR_E_OK

+ *      AIR_E_BAD_PARAMETER

+ *

+ * NOTES:

+ *      None

+ */

+AIR_ERROR_NO_T

+air_port_setAnMode(

+    const UI32_T unit,

+    const UI32_T port,

+    const BOOL_T state);

+

+/* FUNCTION NAME: air_port_getAnMode

+ * PURPOSE:

+ *      Get the auto-negotiation mode for a specific port.

+ *

+ * INPUT:

+ *      unit            --  Device ID

+ *      port            --  Index of port number

+ *

+ * OUTPUT:

+ *      state           --  FALSE:Disable

+ *                          TRUE: Enable

+ * RETURN:

+ *      AIR_E_OK

+ *      AIR_E_BAD_PARAMETER

+ *

+ * NOTES:

+ *      None

+ */

+AIR_ERROR_NO_T

+air_port_getAnMode(

+    const UI32_T unit,

+    const UI32_T port,

+    BOOL_T *ptr_state);

+

+/* FUNCTION NAME: air_port_setLocalAdvAbility

+ * PURPOSE:

+ *      Set the auto-negotiation advertisement for a

+ *      specific port.

+ *

+ * INPUT:

+ *      unit            --  Device ID

+ *      port            --  Index of port number

+ *      adv             --  AN advertisement setting

+ *

+ * OUTPUT:

+ *      None

+ *

+ * RETURN:

+ *      AIR_E_OK

+ *      AIR_E_BAD_PARAMETER

+ *

+ * NOTES:

+ *      None

+ */

+AIR_ERROR_NO_T

+air_port_setLocalAdvAbility(

+    const UI32_T unit,

+    const UI32_T port,

+    const AIR_AN_ADV_T adv);

+

+/* FUNCTION NAME: air_port_getLocalAdvAbility

+ * PURPOSE:

+ *      Get the auto-negotiation advertisement for a

+ *      specific port.

+ *

+ * INPUT:

+ *      unit            --  Device ID

+ *      port            --  Index of port number

+ *

+ * OUTPUT:

+ *      ptr_adv         --  AN advertisement setting

+ *

+ * RETURN:

+ *      AIR_E_OK

+ *      AIR_E_BAD_PARAMETER

+ *

+ * NOTES:

+ *      None

+ */

+AIR_ERROR_NO_T

+air_port_getLocalAdvAbility(

+    const UI32_T unit,

+    const UI32_T port,

+    AIR_AN_ADV_T *ptr_adv);

+

+/* FUNCTION NAME: air_port_getRemoteAdvAbility

+ * PURPOSE:

+ *      Get the auto-negotiation remote advertisement for a

+ *      specific port.

+ *

+ * INPUT:

+ *      unit            --  Device ID

+ *      port            --  Index of port number

+ *

+ * OUTPUT:

+ *      ptr_lp_adv      --  AN advertisement of link partner

+ *

+ * RETURN:

+ *      AIR_E_OK

+ *      AIR_E_BAD_PARAMETER

+ *

+ * NOTES:

+ *      None

+ */

+AIR_ERROR_NO_T

+air_port_getRemoteAdvAbility(

+    const UI32_T unit,

+    const UI32_T port,

+    AIR_AN_ADV_T *ptr_lp_adv);

+

+/* FUNCTION NAME: air_port_setSpeed

+ * PURPOSE:

+ *      Set the speed for a specific port.

+ *      This setting is used on force mode only.

+ *

+ * INPUT:

+ *      unit            --  Device ID

+ *      port            --  Index of port number

+ *      speed           --  AIR_PORT_SPEED_10M:  10Mbps

+ *                          AIR_PORT_SPEED_100M: 100Mbps

+ *                          AIR_PORT_SPEED_1000M:1Gbps

+ *                          AIR_PORT_SPEED_2500M:2.5Gbps (Port5, Port6)

+ * OUTPUT:

+ *      None

+ *

+ * RETURN:

+ *      AIR_E_OK

+ *      AIR_E_BAD_PARAMETER

+ *

+ * NOTES:

+ *      None

+ */

+AIR_ERROR_NO_T

+air_port_setSpeed(

+    const UI32_T unit,

+    const UI32_T port,

+    const UI32_T speed);

+

+/* FUNCTION NAME: air_port_getSpeed

+ * PURPOSE:

+ *      Get the speed for a specific port.

+ *

+ * INPUT:

+ *      unit            --  Device ID

+ *      port            --  Index of port number

+ *

+ * OUTPUT:

+ *      ptr_speed       --  AIR_PORT_SPEED_10M:  10Mbps

+ *                          AIR_PORT_SPEED_100M: 100Mbps

+ *                          AIR_PORT_SPEED_1000M:1Gbps

+ * RETURN:

+ *      AIR_E_OK

+ *      AIR_E_BAD_PARAMETER

+ *

+ * NOTES:

+ *      None

+ */

+AIR_ERROR_NO_T

+air_port_getSpeed(

+    const UI32_T unit,

+    const UI32_T port,

+    UI32_T *ptr_speed);

+

+/* FUNCTION NAME: air_port_setDuplex

+ * PURPOSE:

+ *      Get the duplex for a specific port.

+ *      This setting is used on force mode only.

+ *

+ * INPUT:

+ *      unit            --  Device ID

+ *      port            --  Index of port number

+ *      duplex          --  AIR_PORT_DUPLEX_HALF

+ *                          AIR_PORT_DUPLEX_FULL

+ * OUTPUT:

+ *      None

+ *

+ * RETURN:

+ *      AIR_E_OK

+ *      AIR_E_BAD_PARAMETER

+ *

+ * NOTES:

+ *      None

+ */

+AIR_ERROR_NO_T

+air_port_setDuplex(

+    const UI32_T unit,

+    const UI32_T port,

+    const BOOL_T duplex);

+

+/* FUNCTION NAME: air_port_getDuplex

+ * PURPOSE:

+ *      Get the duplex for a specific port.

+ *

+ * INPUT:

+ *      unit            --  Device ID

+ *      port            --  Index of port number

+ *

+ * OUTPUT:

+ *      ptr_duplex      --  AIR_PORT_DUPLEX_HALF

+ *                          AIR_PORT_DUPLEX_FULL

+ * RETURN:

+ *      AIR_E_OK

+ *      AIR_E_BAD_PARAMETER

+ *

+ * NOTES:

+ *      None

+ */

+AIR_ERROR_NO_T

+air_port_getDuplex(

+    const UI32_T unit,

+    const UI32_T port,

+    BOOL_T *ptr_duplex);

+

+/* FUNCTION NAME: air_port_getLink

+ * PURPOSE:

+ *      Get the physical link status for a specific port.

+ *

+ * INPUT:

+ *      unit            --  Device ID

+ *      port            --  Index of port number

+ *

+ * OUTPUT:

+ *      ptr_ps          --  AIR_PORT_STATUS_T

+ *

+ * RETURN:

+ *      AIR_E_OK

+ *      AIR_E_BAD_PARAMETER

+ *

+ * NOTES:

+ *      None

+ */

+AIR_ERROR_NO_T

+air_port_getLink(

+    const UI32_T unit,

+    const UI32_T port,

+    AIR_PORT_STATUS_T *ptr_ps);

+

+/* FUNCTION NAME: air_port_setBckPres

+ * PURPOSE:

+ *      Set the back pressure configuration for a specific port.

+ *

+ * INPUT:

+ *      unit            --  Device ID

+ *      port            --  Index of port number

+ *      bckPres         --  FALSE:Disable

+ *                          TRUE: Enable

+ * OUTPUT:

+ *      None

+ *

+ * RETURN:

+ *      AIR_E_OK

+ *      AIR_E_BAD_PARAMETER

+ *

+ * NOTES:

+ *      None

+ */

+AIR_ERROR_NO_T

+air_port_setBckPres(

+    const UI32_T unit,

+    const UI32_T port,

+    const BOOL_T bckPres);

+

+/* FUNCTION NAME: air_port_getBckPres

+ * PURPOSE:

+ *      Get the back pressure configuration for a specific port.

+ *

+ * INPUT:

+ *      unit            --  Device ID

+ *      port            --  Index of port number

+ *

+ * OUTPUT:

+ *      ptr_bckPres     --  FALSE:Disable

+ *                          TRUE: Enable

+ * RETURN:

+ *      AIR_E_OK

+ *      AIR_E_BAD_PARAMETER

+ *

+ * NOTES:

+ *      None

+ */

+AIR_ERROR_NO_T

+air_port_getBckPres(

+    const UI32_T unit,

+    const UI32_T port,

+    BOOL_T *ptr_bckPres);

+

+/* FUNCTION NAME: air_port_setFlowCtrl

+ * PURPOSE:

+ *      Set the flow control configuration for specific port.

+ *

+ * INPUT:

+ *      unit            --  Select device ID

+ *      port            --  Select port number (0 - 6)

+ *      dir             --  Directions of AIR_PORT_TX or AIR_PORT_RX

+ *      fc_en           --  TRUE: Enable select port flow control

+ *                          FALSE:Disable select port flow control

+ * OUTPUT:

+ *      None

+ *

+ * RETURN:

+ *      AIR_E_OK

+ *      AIR_E_BAD_PARAMETER

+ *

+ * NOTES:

+ *      None

+ */

+AIR_ERROR_NO_T

+air_port_setFlowCtrl(

+    const UI32_T unit,

+    const UI32_T port,

+    const BOOL_T dir,

+    const BOOL_T fc_en);

+

+/* FUNCTION NAME: air_port_getFlowCtrl

+ * PURPOSE:

+ *      Get the flow control configuration for specific port.

+ *

+ * INPUT:

+ *      unit            --  Select device ID

+ *      port            --  Select port number (0..6)

+ *      dir             --  AIR_PORT_TX

+ *                          AIR_PORT_RX

+ * OUTPUT:

+ *      ptr_fc_en       --  FALSE: Port flow control disable

+ *                          TRUE: Port flow control enable

+ * RETURN:

+ *      AIR_E_OK

+ *      AIR_E_BAD_PARAMETER

+ *

+ * NOTES:

+ *      None

+ */

+AIR_ERROR_NO_T

+air_port_getFlowCtrl(

+    const UI32_T unit,

+    const UI32_T port,

+    const BOOL_T dir,

+    BOOL_T *ptr_fc_en);

+

+/* FUNCTION NAME: air_port_setJumbo

+ * PURPOSE:

+ *      Set accepting jumbo frmes with specificied size.

+ *

+ * INPUT:

+ *      unit            --  Select device ID

+ *      pkt_len         --  Select max packet length

+ *                          RX_PKT_LEN_1518

+ *                          RX_PKT_LEN_1536

+ *                          RX_PKT_LEN_1552

+ *                          RX_PKT_LEN_MAX_JUMBO

+ *      frame_len       --  Select max lenght of jumbo frames

+ *                          Range : 2 - 15

+ *                          Units : K Bytes

+ * OUTPUT:

+ *      None

+ *

+ * RETURN:

+ *      AIR_E_OK

+ *      AIR_E_BAD_PARAMETER

+ *

+ * NOTES:

+ *      None

+ */

+AIR_ERROR_NO_T

+air_port_setJumbo(

+    const UI32_T unit,

+    const UI32_T pkt_len,

+    const UI32_T frame_len);

+

+/* FUNCTION NAME: air_port_getJumbo

+ * PURPOSE:

+ *      Get accepting jumbo frmes with specificied size.

+ *

+ * INPUT:

+ *      unit            --  Select device ID

+ *

+ * OUTPUT:

+ *      ptr_pkt_len     --  Select max packet length

+ *                          RX_PKT_LEN_1518

+ *                          RX_PKT_LEN_1536

+ *                          RX_PKT_LEN_1552

+ *                          RX_PKT_LEN_MAX_JUMBO

+ *      ptr_frame_len   --  Select max lenght of jumbo frames

+ *                          Range : 2 - 15

+ *                          Units : K Bytes

+ * RETURN:

+ *      AIR_E_OK

+ *      AIR_E_BAD_PARAMETER

+ *

+ * NOTES:

+ *      None

+ */

+AIR_ERROR_NO_T

+air_port_getJumbo(

+    const UI32_T unit,

+    UI32_T *ptr_pkt_len,

+    UI32_T *ptr_frame_len);

+

+

+/* FUNCTION NAME: air_port_setPsMode

+ * PURPOSE:

+ *      Set the power saving mode for a specific port.

+ *

+ * INPUT:

+ *      unit            --  Device ID

+ *      port            --  Index of port number

+ *      mode            --  Bit-map:

+ *                          AIR_PORT_PS_LINKSTATUS

+ *                          AIR_PORT_PS_EEE

+ *                          FALSE: Disable / TRUE: Enable

+ * OUTPUT:

+ *      None

+ *

+ * RETURN:

+ *      AIR_E_OK

+ *      AIR_E_BAD_PARAMETER

+ *

+ * NOTES:

+ *      None

+ */

+AIR_ERROR_NO_T

+air_port_setPsMode(

+    const UI32_T unit,

+    const UI32_T port,

+    const UI32_T mode);

+

+/* FUNCTION NAME: air_port_getPsMode

+ * PURPOSE:

+ *      Get the power saving mode for a specific port.

+ *

+ * INPUT:

+ *      unit            --  Device ID

+ *      port            --  Index of port number

+ * OUTPUT:

+ *      ptr_mode        --  Bit-map:

+ *                          AIR_PORT_PS_LINKSTATUS

+ *                          AIR_PORT_PS_EEE

+ *                          FALSE: Disable / TRUE: Enable

+ * RETURN:

+ *      AIR_E_OK

+ *      AIR_E_BAD_PARAMETER

+ *

+ * NOTES:

+ *      None

+ */

+AIR_ERROR_NO_T

+air_port_getPsMode(

+    const UI32_T unit,

+    const UI32_T port,

+    UI32_T *ptr_mode);

+

+/* FUNCTION NAME: air_port_setSmtSpdDwn

+ * PURPOSE:

+ *      Set Smart speed down feature for a specific port.

+ *

+ * INPUT:

+ *      unit            --  Device ID

+ *      port            --  Index of port number

+ *      state           --  FALSE:Disable

+ *                          TRUE: Enable

+ *      time            --  AIR_PORT_SSD_2T

+ *                          AIR_PORT_SSD_3T

+ *                          AIR_PORT_SSD_4T

+ *                          AIR_PORT_SSD_5T

+ * OUTPUT:

+ *      None

+ *

+ * RETURN:

+ *      AIR_E_OK

+ *      AIR_E_BAD_PARAMETER

+ *

+ * NOTES:

+ *      None

+ */

+AIR_ERROR_NO_T

+air_port_setSmtSpdDwn(

+    const UI32_T unit,

+    const UI32_T port,

+    const BOOL_T state,

+    const UI32_T time);

+

+/* FUNCTION NAME: air_port_getSmtSpdDwn

+ * PURPOSE:

+ *      Get Smart speed down feature for a specific port.

+ *

+ * INPUT:

+ *      unit            --  Device ID

+ *      port            --  Index of port number

+ *

+ * OUTPUT:

+ *      ptr_state       --  FALSE:Disable

+ *                          TRUE: Enable

+ *      ptr_time        --  AIR_PORT_SSD_2T

+ *                          AIR_PORT_SSD_3T

+ *                          AIR_PORT_SSD_4T

+ *                          AIR_PORT_SSD_5T

+ * RETURN:

+ *      AIR_E_OK

+ *      AIR_E_BAD_PARAMETER

+ *

+ * NOTES:

+ *      None

+ */

+AIR_ERROR_NO_T

+air_port_getSmtSpdDwn(

+    const UI32_T unit,

+    const UI32_T port,

+    UI32_T *ptr_state,

+    UI32_T *ptr_time);

+

+/* FUNCTION NAME: air_port_setEnable

+ * PURPOSE:

+ *      Set powerdown state for a specific port.

+ *

+ * INPUT:

+ *      unit            --  Device ID

+ *      port            --  Index of port number

+ *      state           --  FALSE:Disable

+ *                          TRUE: Enable

+ * OUTPUT:

+ *      None

+ *

+ * RETURN:

+ *      AIR_E_OK

+ *      AIR_E_BAD_PARAMETER

+ *

+ * NOTES:

+ *      None

+ */

+AIR_ERROR_NO_T

+air_port_setEnable(

+    const UI32_T unit,

+    const UI32_T port,

+    const BOOL_T state);

+

+/* FUNCTION NAME: air_port_getEnable

+ * PURPOSE:

+ *      Get powerdown state for a specific port.

+ *

+ * INPUT:

+ *      unit            --  Device ID

+ *      port            --  Index of port number

+ *

+ * OUTPUT:

+ *      ptr_state       --  FALSE:Disable

+ *                          TRUE: Enable

+ * RETURN:

+ *      AIR_E_OK

+ *      AIR_E_BAD_PARAMETER

+ *

+ * NOTES:

+ *      None

+ */

+AIR_ERROR_NO_T

+air_port_getEnable(

+    const UI32_T unit,

+    const UI32_T port,

+    UI32_T *ptr_state);

+

+/* FUNCTION NAME: air_port_setSpTag

+ * PURPOSE:

+ *      Set special tag state of a specific port.

+ *

+ * INPUT:

+ *      unit            --  Device ID

+ *      port            --  Index of port number

+ *      sptag_en        --  TRUE:  Enable special tag

+ *                          FALSE: Disable special tag

+ * OUTPUT:

+ *        None

+ *

+ * RETURN:

+ *        AIR_E_OK

+ *        AIR_E_BAD_PARAMETER

+ *

+ * NOTES:

+ *      None

+ */

+AIR_ERROR_NO_T

+air_port_setSpTag(

+    const UI32_T unit,

+    const UI32_T port,

+    const BOOL_T sptag_en);

+

+/* FUNCTION NAME: air_port_getSpTag

+ * PURPOSE:

+ *      Get special tag state of a specific port.

+ *

+ * INPUT:

+ *      unit            --  Device ID

+ *      port            --  Index of port number

+ * OUTPUT:

+ *      ptr_sptag_en    --  TRUE:  Special tag enable

+ *                          FALSE: Special tag disable

+ *

+ * RETURN:

+ *        AIR_E_OK

+ *        AIR_E_BAD_PARAMETER

+ *

+ * NOTES:

+ *      None

+ */

+AIR_ERROR_NO_T

+air_port_getSpTag(

+    const UI32_T unit,

+    const UI32_T port,

+    BOOL_T *ptr_sptag_en);

+

+/* FUNCTION NAME: air_port_set5GBaseRModeEnable

+ * PURPOSE:

+ *      Set the port5 5GBase-R mode enable

+ *

+ * INPUT:

+ *      unit            --  Device ID

+ *

+ * OUTPUT:

+ *      None

+ *

+ * RETURN:

+ *      AIR_E_OK

+ *      AIR_E_BAD_PARAMETER

+ *

+ * NOTES:

+ *      None

+ */

+AIR_ERROR_NO_T

+air_port_set5GBaseRModeEn(

+    const UI32_T unit);

+

+/* FUNCTION NAME: air_port_setHsgmiiModeEnable

+ * PURPOSE:

+ *      Set the port5 HSGMII mode enable

+ *

+ * INPUT:

+ *      unit            --  Device ID

+ *

+ * OUTPUT:

+ *      None

+ *

+ * RETURN:

+ *      AIR_E_OK

+ *      AIR_E_BAD_PARAMETER

+ *

+ * NOTES:

+ *      None

+ */

+AIR_ERROR_NO_T

+air_port_setHsgmiiModeEn(

+    const UI32_T unit);

+

+/* FUNCTION NAME: air_port_setSgmiiMode

+ * PURPOSE:

+ *      Set the port5 SGMII mode for AN or force

+ *

+ * INPUT:

+ *      unit            --  Device ID

+ *      mode            --  AIR_PORT_SGMII_MODE_AN

+ *                          AIR_PORT_SGMII_MODE_FORCE

+ *      speed           --  AIR_PORT_SPEED_10M:   10Mbps

+ *                          AIR_PORT_SPEED_100M:  100Mbps

+ *                          AIR_PORT_SPEED_1000M: 1Gbps

+ *

+ * OUTPUT:

+ *      None

+ *

+ * RETURN:

+ *      AIR_E_OK

+ *      AIR_E_BAD_PARAMETER

+ *

+ * NOTES:

+ *      None

+ */

+AIR_ERROR_NO_T

+air_port_setSgmiiMode(

+    const UI32_T unit,

+    const UI32_T mode,

+    const UI32_T speed);

+

+

+/* FUNCTION NAME: air_port_setRmiiMode

+ * PURPOSE:

+ *      Set the port5 RMII mode for 100Mbps or 10Mbps

+ *

+ * INPUT:

+ *      unit            --  Device ID

+ *      speed           --  AIR_PORT_SPEED_10M:  10Mbps

+ *                          AIR_PORT_SPEED_100M: 100Mbps

+ *

+ * OUTPUT:

+ *      None

+ *

+ * RETURN:

+ *      AIR_E_OK

+ *      AIR_E_BAD_PARAMETER

+ *

+ * NOTES:

+ *      None

+ */

+AIR_ERROR_NO_T

+air_port_setRmiiMode(

+    const UI32_T unit,

+    const UI32_T speed);

+

+/* FUNCTION NAME: air_port_setRgmiiMode

+ * PURPOSE:

+ *      Set the port5 RGMII mode for 1Gbps or 100Mbps or 10Mbps

+ *

+ * INPUT:

+ *      unit            --  Device ID

+ *      speed           --  AIR_PORT_SPEED_10M:   10Mbps

+ *                          AIR_PORT_SPEED_100M:  100Mbps

+ *                          AIR_PORT_SPEED_1000M: 1Gbps

+ *

+ * OUTPUT:

+ *      None

+ *

+ * RETURN:

+ *      AIR_E_OK

+ *      AIR_E_BAD_PARAMETER

+ *

+ * NOTES:

+ *      None

+ */

+AIR_ERROR_NO_T

+air_port_setRgmiiMode(

+    const UI32_T unit,

+    const UI32_T speed);

+

+#endif  /* AIR_PORT_H */

+

diff --git a/recipes-devtools/switch/files/src/an8855_sdk/api/inc/air_qos.h b/recipes-devtools/switch/files/src/an8855_sdk/api/inc/air_qos.h
new file mode 100644
index 0000000..e1eaf3a
--- /dev/null
+++ b/recipes-devtools/switch/files/src/an8855_sdk/api/inc/air_qos.h
@@ -0,0 +1,590 @@
+/* FILE NAME: air_qos.h
+* PURPOSE:
+ *      Define the Quailty of Service function in AIR SDK.
+*
+* NOTES:
+*       None
+*/
+
+#ifndef AIR_QOS_H
+#define AIR_QOS_H
+
+/* INCLUDE FILE DECLARATIONS
+*/
+
+/* NAMING CONSTANT DECLARATIONS
+*/
+#define AIR_QOS_MAX_TOKEN               (128)
+#define AIR_QOS_MAX_CIR                 (80001)
+#define AIR_QOS_TOKEN_PERIOD_1_4MS      (5)
+#define AIR_QOS_TOKEN_PERIOD_4MS        (9)
+#define AIR_QOS_L1_RATE_LIMIT           (0x18)
+#define AIR_QOS_L2_RATE_LIMIT           (0x04)
+#define AIR_QOS_QUEUE_PIM_WIDTH         (3)
+#define AIR_QOS_QUEUE_PIM_MASK          (7)
+#define AIR_QOS_QUEUE_DEFAULT_VAL       (0x222227)
+#define AIR_QOS_QUEUE_TRUST_HIGH_WEIGHT (6)
+#define AIR_QOS_QUEUE_TRUST_MID_WEIGHT  (5)
+#define AIR_QOS_QUEUE_TRUST_LOW_WEIGHT  (4)
+#define AIR_QOS_SHAPER_RATE_MAX_EXP     (4)
+#define AIR_QOS_SHAPER_RATE_MAX_MAN     (0x1ffff)
+#define AIR_QOS_SHAPER_RATE_MIN_WEIGHT  (1)
+#define AIR_QOS_SHAPER_RATE_MAX_WEIGHT  (128)
+#define AIR_QOS_QUEUE_0                 (0)
+#define AIR_QOS_QUEUE_1                 (1)
+#define AIR_QOS_QUEUE_2                 (2)
+#define AIR_QOS_QUEUE_3                 (3)
+#define AIR_QOS_QUEUE_4                 (4)
+#define AIR_QOS_QUEUE_5                 (5)
+#define AIR_QOS_QUEUE_6                 (6)
+#define AIR_QOS_QUEUE_7                 (7)
+#define AIR_QOS_MIN_TRAFFIC_ARBITRATION_SCHEME_SP                (1)
+#define AIR_QOS_MIN_TRAFFIC_ARBITRATION_SCHEME_WRR               (0)
+#define AIR_QOS_MAX_TRAFFIC_ARBITRATION_SCHEME_SP                (1)
+#define AIR_QOS_MAX_TRAFFIC_ARBITRATION_SCHEME_WFQ               (0)
+#define AIR_QOS_MAX_EXCESS_SP                                    (1)
+#define AIR_QOS_MAX_EXCESS_DROP                                  (0)
+#define AIR_QOS_QUEUE_MAX_NUM           (8)
+#define AIR_QOS_QUEUE_DSCP_MAX_NUM      (64)
+#define AIR_MAX_NUM_OF_QUEUE            (8) /*need to be replaced by AIR_QOS_QUEUE_MAX_NUM*/
+
+#define AIR_QOS_SHAPER_NOSETTING      (0xffffffff)
+#define AIR_QOS_SHAPER_RATE_MIN_WEIGHT  (1)
+#define AIR_QOS_SHAPER_RATE_MAX_WEIGHT  (128)
+
+/* MACRO FUNCTION DECLARATIONS
+*/
+
+/* DATA TYPE DECLARATIONS
+*/
+typedef enum
+{
+    AIR_QOS_SCH_MODE_SP,
+    AIR_QOS_SCH_MODE_WRR,
+    AIR_QOS_SCH_MODE_WFQ,
+    AIR_QOS_SCH_MODE_LAST,
+} AIR_QOS_SCH_MODE_T;
+
+typedef union AIR_QOS_SHAPER_MIN_S
+{
+    struct
+    {
+        UI32_T   min_rate_man      :17;
+        UI32_T   min_reserve       :2;
+        UI32_T   min_rate_en       :1;
+        UI32_T   min_rate_exp      :4;
+        UI32_T   min_weight        :7;
+        UI32_T   min_sp_wrr_q      :1;
+    }raw;
+    UI32_T byte;
+}AIR_QOS_SHAPER_MIN_T;
+
+typedef union AIR_QOS_SHAPER_MAX_S
+{
+    struct
+    {
+        UI32_T   max_rate_man      :17;
+        UI32_T   max_reserve       :1;
+        UI32_T   max_excess_en     :1;
+        UI32_T   max_rate_en       :1;
+        UI32_T   max_rate_exp      :4;
+        UI32_T   max_weight        :7;
+        UI32_T   max_sp_wfq_q      :1;
+    }raw;
+    UI32_T byte;
+}AIR_QOS_SHAPER_MAX_T;
+
+typedef enum
+{
+    /* The packet priority is based on port's priority. */
+    AIR_QOS_TRUST_MODE_PORT,
+
+    /*
+    * The precedence of packet priority is based on 802.1p,
+    * then port's priority.
+    */
+    AIR_QOS_TRUST_MODE_1P_PORT,
+
+    /*
+    * The precedence of packet priority is based on DSCP,
+    * then port's priority.
+    */
+    AIR_QOS_TRUST_MODE_DSCP_PORT,
+
+    /*
+    * The precedence of packet priority is based on DSCP, 802.1p,
+    * then port's priority.
+    */
+    AIR_QOS_TRUST_MODE_DSCP_1P_PORT,
+    AIR_QOS_TRUST_MODE_LAST
+} AIR_QOS_TRUST_MODE_T;
+
+typedef union AIR_QOS_QUEUE_UPW_S
+{
+    struct
+    {
+        UI32_T csr_acl_weight   :3;
+        UI32_T                  :1;
+        UI32_T csr_stag_weight  :3;/*Not use yet*/
+        UI32_T                  :1;
+        UI32_T csr_1p_weight    :3;
+        UI32_T                  :1;
+        UI32_T csr_dscp_weight  :3;
+        UI32_T                  :1;
+        UI32_T csr_port_weight  :3;
+        UI32_T                  :1;
+        UI32_T csr_arl_weight   :3;
+        UI32_T                  :9;
+    }raw;
+    UI32_T byte;
+}AIR_QOS_QUEUE_UPW_T;
+
+typedef union AIR_QOS_QUEUE_PEM_S
+{
+    struct
+    {
+        UI32_T csr_dscp_pri_l     :6;/*Not use yet*/
+        UI32_T csr_que_lan_l      :2;/*Not use yet*/
+        UI32_T csr_que_cpu_l      :3;
+        UI32_T csr_tag_pri_l      :3;/*Not use yet*/
+        UI32_T                    :2;
+        UI32_T csr_dscp_pri_h     :6;/*Not use yet*/
+        UI32_T csr_que_lan_h      :2;/*Not use yet*/
+        UI32_T csr_que_cpu_h      :3;
+        UI32_T csr_tag_pri_h      :3;/*Not use yet*/
+        UI32_T                    :2;
+    }raw;
+    UI32_T byte;
+}AIR_QOS_QUEUE_PEM_T;
+
+typedef enum
+{
+    AIR_QOS_RATE_DIR_INGRESS,
+    AIR_QOS_RATE_DIR_EGRESS,
+    AIR_QOS_RATE_DIR_LAST
+} AIR_QOS_RATE_DIR_T;
+
+typedef struct AIR_RATE_LIMIT_S
+{
+#define AIR_QOS_RATE_LIMIT_CFG_FLAGS_ENABLE_INGRESS     (1U << 0)
+#define AIR_QOS_RATE_LIMIT_CFG_FLAGS_ENABLE_EGRESS      (1U << 1)
+    UI32_T flags;
+
+    /*
+    * The limit cover up to 2.5G
+    * Rate = CIR * 32kbps
+    * Range = 0..80000
+    */
+    UI32_T ingress_cir;
+    UI32_T egress_cir;
+
+    /*
+    * Bucket = Max{(CBS * 512), (CIR * 2500)} Bytes
+    * Range: 0..127
+    */
+    UI32_T ingress_cbs;
+    UI32_T egress_cbs;
+} AIR_QOS_RATE_LIMIT_CFG_T;
+
+
+/* EXPORTED SUBPROGRAM SPECIFICATIONS
+*/
+
+/* FUNCTION NAME:   air_qos_setScheduleAlgo
+ * PURPOSE:
+ *      Set schedule mode of a port queue.
+ * INPUT:
+ *      unit                 -- Device unit number
+ *      port                 -- Port id
+ *      queue                -- Queue id
+ *      sch_mode             -- AIR_QOS_SCH_MODE_T
+ *      weight               -- weight for WRR/WFQ
+ * OUTPUT:
+ *      None
+ * RETURN:
+ *      AIR_E_OK             -- Operation success.
+ *      AIR_E_BAD_PARAMETER  -- Parameter is wrong.
+ * NOTES:
+ *      Weight default value is 1, only for WRR/WFQ mode
+ */
+AIR_ERROR_NO_T
+air_qos_setScheduleAlgo(
+    const UI32_T unit,
+    const UI32_T port,
+    const UI32_T                queue,
+    const AIR_QOS_SCH_MODE_T    sch_mode,
+    const UI32_T                weight);
+
+
+/* FUNCTION NAME: air_qos_getScheduleAlgo
+ * PURPOSE:
+ *      Get schedule mode of a port queue.
+ *
+ * INPUT:
+ *      unit            --  Select device ID
+ *      port            --  Port id
+ *      queue           --  Queue id
+ * OUTPUT:
+ *      ptr_sch_mode    --  AIR_QOS_SCH_MODE_T
+ *      ptr_weight      --  weight for WRR/WFQ
+ * RETURN:
+ *      AIR_E_OK
+ *      AIR_E_BAD_PARAMETER
+ *
+ * NOTES:
+ *     None
+ */
+AIR_ERROR_NO_T
+air_qos_getScheduleAlgo(
+    const UI32_T          unit,
+    const UI32_T          port,
+    const UI32_T          queue,
+    AIR_QOS_SCH_MODE_T    *ptr_sch_mode,
+    UI32_T                *ptr_weight);
+
+/* FUNCTION NAME:   air_qos_setTrustMode
+ * PURPOSE:
+ *      Set qos trust mode value.
+ * INPUT:
+ *      unit                 -- Device unit number
+ *      port                  -.Select port number
+ *      mode                 -- Qos support mode
+ *                              AIR_QOS_TRUST_MODE_T
+ * OUTPUT:
+ *      None
+ * RETURN:
+ *      AIR_E_OK             -- Operation success.
+ *      AIR_E_BAD_PARAMETER  -- Parameter is wrong.
+ * NOTES:
+ *      None
+ */
+
+AIR_ERROR_NO_T
+air_qos_setTrustMode(
+    const UI32_T                    unit,
+    const UI32_T                    port,
+    const AIR_QOS_TRUST_MODE_T      mode);
+
+
+/* FUNCTION NAME: air_qos_getTrustMode
+ * PURPOSE:
+ *      Get qos trust mode value.
+ *
+ * INPUT:
+ *      unit            --  Select device ID
+ *      port              -.Select port number
+ * OUTPUT:
+ *      ptr_weight      --  All Qos weight value
+ * RETURN:
+ *      AIR_E_OK
+ *      AIR_E_BAD_PARAMETER
+ *
+ * NOTES:
+ *      None
+ */
+AIR_ERROR_NO_T
+air_qos_getTrustMode(
+    const UI32_T unit,
+    const UI32_T port,
+    AIR_QOS_TRUST_MODE_T *const ptr_mode);
+
+/* FUNCTION NAME: air_qos_setPri2Queue
+ * PURPOSE:
+ *      Set per port priority to out queue.
+ *
+ * INPUT:
+ *      unit            --  Select device ID
+ *      pri             --  Qos pri value
+ *      queue           --  Qos Queue value
+ *
+ * OUTPUT:
+ *      None
+ *
+ * RETURN:
+ *      AIR_E_OK
+ *      AIR_E_BAD_PARAMETER
+ *
+ * NOTES:
+ *      None
+ */
+AIR_ERROR_NO_T
+air_qos_setPri2Queue(
+    const UI32_T unit,
+    const UI32_T pri,
+    const UI32_T queue);
+
+/* FUNCTION NAME: air_qos_getPri2Queue
+ * PURPOSE:
+ *      Get per port priority to out queue.
+ *
+ * INPUT:
+ *      unit            --  Select device ID
+ *      pri             --  Qos pri value
+ *
+ * OUTPUT:
+ *      ptr_queue       --  Select out queue (0..7)
+ *
+ * RETURN:
+ *      AIR_E_OK
+ *      AIR_E_BAD_PARAMETER
+ *
+ * NOTES:
+ *      None
+ */
+AIR_ERROR_NO_T
+air_qos_getPri2Queue(
+    const UI32_T unit,
+    const UI32_T pri,
+    UI32_T *const ptr_queue);
+
+/* FUNCTION NAME: air_qos_setDscp2Pri
+ * PURPOSE:
+ *      Set DSCP mapping to priority.
+ *
+ * INPUT:
+ *      unit            --  Select device ID
+ *      dscp            --  Select DSCP value (0..63)
+ *      priority        --  Select priority (0..7)
+ *
+ * OUTPUT:
+ *      None
+ *
+ * RETURN:
+ *      AIR_E_OK
+ *      AIR_E_BAD_PARAMETER
+ *
+ * NOTES:
+ *      None
+ */
+AIR_ERROR_NO_T
+air_qos_setDscp2Pri(
+    const UI32_T unit,
+    const UI32_T dscp,
+    const UI32_T pri);
+
+/* FUNCTION NAME: air_qos_getDscp2Pri
+ * PURPOSE:
+ *      Get DSCP mapping priority.
+ *
+ * INPUT:
+ *      unit            --  Select device ID
+ *      dscp            --  Select DSCP value (0..63)
+ *
+ * OUTPUT:
+ *      ptr_pri         --  Priority value (0..7)
+ *
+ * RETURN:
+ *      AIR_E_OK
+ *      AIR_E_BAD_PARAMETER
+ *
+ * NOTES:
+ *      None
+ */
+AIR_ERROR_NO_T
+air_qos_getDscp2Pri(
+    const UI32_T unit,
+    const UI32_T dscp,
+    UI32_T * const ptr_pri);
+
+/* FUNCTION NAME: air_qos_setRateLimitEnable
+ * PURPOSE:
+ *      Enable or disable port rate limit.
+ *
+ * INPUT:
+ *      unit            --  Select device ID
+ *      port            --  Select port number (0..6)
+ *      dir             --  AIR_QOS_RATE_DIR_INGRESS
+ *                          AIR_QOS_RATE_DIR_EGRESS
+ *      rate_en         --  TRUE: eanble rate limit
+ *                          FALSE: disable rate limit
+ * OUTPUT:
+ *      None
+ *
+ * RETURN:
+ *      AIR_E_OK
+ *      AIR_E_BAD_PARAMETER
+ *
+ * NOTES:
+ *      None
+ */
+AIR_ERROR_NO_T
+air_qos_setRateLimitEnable(
+    const UI32_T unit,
+    const UI32_T port,
+    const AIR_QOS_RATE_DIR_T dir,
+    const BOOL_T enable);
+
+/* FUNCTION NAME: air_qos_getRateLimitEnable
+ * PURPOSE:
+ *      Get port rate limit state.
+ *
+ * INPUT:
+ *      unit            --  Select device ID
+ *      port            --  Select port number (0..6)
+ *      dir              -- AIR_QOS_RATE_DIR_T
+ * OUTPUT:
+ *      ptr_enable        --  TRUE: eanble rate limit
+ *                          FALSE: disable rate limit
+ * RETURN:
+ *      AIR_E_OK
+ *      AIR_E_BAD_PARAMETER
+ *
+ * NOTES:
+ *      None
+ */
+AIR_ERROR_NO_T
+air_qos_getRateLimitEnable(
+    const UI32_T                unit,
+    const UI32_T                port,
+    const AIR_QOS_RATE_DIR_T    dir,
+    BOOL_T                      *ptr_enable);
+
+/* FUNCTION NAME: air_qos_setRateLimit
+ * PURPOSE:
+ *      Set per port rate limit.
+ *
+ * INPUT:
+ *      unit            --  Select device ID
+ *      port            --  Select port number
+ *      ptr_cfg         --  AIR_QOS_RATE_LIMIT_CFG_T
+ *
+ * OUTPUT:
+ *      None
+ *
+ * RETURN:
+ *      AIR_E_OK
+ *      AIR_E_BAD_PARAMETER
+ *
+ * NOTES:
+ *      None
+ */
+AIR_ERROR_NO_T
+air_qos_setRateLimit(
+    const UI32_T unit,
+    const UI32_T port,
+    AIR_QOS_RATE_LIMIT_CFG_T    *ptr_cfg);
+
+/* FUNCTION NAME: air_qos_getRateLimit
+ * PURPOSE:
+ *      Get per port rate limit.
+ *
+ * INPUT:
+ *      unit            --  Select device ID
+ *      port            --  Select port number
+ *
+ * OUTPUT:
+ *      ptr_cfg          --  AIR_QOS_RATE_LIMIT_CFG_T
+ *
+ * RETURN:
+ *      AIR_E_OK
+ *      AIR_E_BAD_PARAMETER
+ *
+ * NOTES:
+ *      None
+ */
+AIR_ERROR_NO_T
+air_qos_getRateLimit(
+    const UI32_T unit,
+    const UI32_T port,
+    AIR_QOS_RATE_LIMIT_CFG_T *ptr_cfg);
+
+/* FUNCTION NAME: air_qos_setPortPriority
+ * PURPOSE:
+ *      Get poer port based priority.
+ *
+ * INPUT:
+ *      unit            --  Select device ID
+ *      port            --  Select port number
+ *      priority        --  Select port priority
+ *
+ * OUTPUT:
+ *      None
+ *
+ * RETURN:
+ *      AIR_E_OK
+ *      AIR_E_BAD_PARAMETER
+ *
+ * NOTES:
+ *      None
+ */
+AIR_ERROR_NO_T
+air_qos_setPortPriority(
+    const UI32_T unit,
+    const UI32_T port,
+    const UI32_T priority);
+
+/* FUNCTION NAME: air_qos_getPortPriority
+ * PURPOSE:
+ *      Set per port based priority.
+ *
+ * INPUT:
+ *      unit            --  Select device ID
+ *      port            --  Select port number
+ *
+ * OUTPUT:
+ *      ptr_pri         --  Get port based priority
+ *
+ * RETURN:
+ *      AIR_E_OK
+ *      AIR_E_BAD_PARAMETER
+ *
+ * NOTES:
+ *      None
+ */
+AIR_ERROR_NO_T
+air_qos_getPortPriority(
+    const UI32_T unit,
+    const UI32_T port,
+    UI32_T *ptr_pri);
+
+/* FUNCTION NAME: air_qos_setRateLimitExMngFrm
+ * PURPOSE:
+ *      Set rate limit control exclude/include management frames.
+ *
+ * INPUT:
+ *      unit            --  Select device ID
+ *      dir             --  AIR_RATE_DIR_INGRESS
+ *                          AIR_RATE_DIR_EGRESS
+ *      exclude         --  TRUE: Exclude management frame
+ *                          FALSE:Include management frame
+ * OUTPUT:
+ *      None
+ *
+ * RETURN:
+ *      AIR_E_OK
+ *      AIR_E_BAD_PARAMETER
+ *
+ * NOTES:
+ *      None
+ */
+AIR_ERROR_NO_T
+air_qos_setRateLimitExMngFrm(
+    const UI32_T unit,
+    const AIR_QOS_RATE_DIR_T dir,
+    const BOOL_T exclude);
+
+/* FUNCTION NAME: air_qos_getRateLimitExMngFrm
+ * PURPOSE:
+ *      Get rate limit control exclude/include management frames.
+ *
+ * INPUT:
+ *      unit            --  Select device ID
+ *      dir             --  AIR_RATE_DIR_INGRESS
+ *                          AIR_RATE_DIR_EGRESS
+ * OUTPUT:
+ *      ptr_exclude     --  TRUE: Exclude management frame
+ *                          FALSE:Include management frame
+ * RETURN:
+ *      AIR_E_OK
+ *      AIR_E_BAD_PARAMETER
+ *
+ * NOTES:
+ *      None
+ */
+AIR_ERROR_NO_T
+air_qos_getRateLimitExMngFrm(
+    const UI32_T unit,
+    const AIR_QOS_RATE_DIR_T dir,
+    BOOL_T *ptr_exclude);
+
+#endif /* End of AIR_QOS_H */
diff --git a/recipes-devtools/switch/files/src/an8855_sdk/api/inc/air_reg.h b/recipes-devtools/switch/files/src/an8855_sdk/api/inc/air_reg.h
new file mode 100644
index 0000000..90fb8ac
--- /dev/null
+++ b/recipes-devtools/switch/files/src/an8855_sdk/api/inc/air_reg.h
@@ -0,0 +1,1233 @@
+/* FILE NAME:   air_reg.h
+* PURPOSE:
+*      Define the chip registers in AIR SDK.
+* NOTES:
+*/
+
+#ifndef AIR_REG_H
+#define AIR_REG_H
+
+/* INCLUDE FILE DECLARATIONS
+*/
+
+/* NAMING CONSTANT DECLARATIONS
+*/
+#define PORT_CTRL_PORT_OFFSET               (0x200)
+
+/* SYS SCU */
+#define RST_CTRL1                           (0x100050c0)
+#define SYS_SW_RST_OFFT                     (31)
+
+/* ARL Register Base */
+#define REG_ARL_BASE_ADDRESS                (0x10200000)
+
+#define AGC                                 (0x000C)
+/* fields of AGC */
+#define AGC_TICK_SEL                        (0x1 << 30)
+
+#define MFC                                 (REG_ARL_BASE_ADDRESS + 0x0010)
+/* fields of MFC */
+
+
+#define VTCR_ADDR                           (0x0090)
+#define VTCR_VID_OFFT                       (0)
+#define VTCR_VID_LENG                       (12)
+#define VTCR_VID_RELMASK                    (0x00000FFF)
+#define VTCR_VID_MASK                       (VTCR_VID_RELMASK << VTCR_VID_OFFT)
+#define VTCR_FUNC_OFFT                      (12)
+#define VTCR_FUNC_LENG                      (4)
+#define VTCR_FUNC_RELMASK                   (0x0000000F)
+#define VTCR_FUNC_MASK                      (VTCR_FUNC_RELMASK << VTCR_FUNC_OFFT)
+#define VTCR_FUNC_READ_ACL_RULE             (0x4 << VTCR_FUNC_OFFT)
+#define VTCR_FUNC_WRITE_ACL_RULE            (0x5 << VTCR_FUNC_OFFT)
+#define VTCR_FUNC_READ_TRTCM                (0x6 << VTCR_FUNC_OFFT)
+#define VTCR_FUNC_WRITE_TRTCM               (0x7 << VTCR_FUNC_OFFT)
+#define VTCR_FUNC_READ_ACL_MASK             (0x8 << VTCR_FUNC_OFFT)
+#define VTCR_FUNC_WRITE_ACL_MASK            (0x9 << VTCR_FUNC_OFFT)
+#define VTCR_FUNC_READ_ACL_RULE_CTRL        (0xA << VTCR_FUNC_OFFT)
+#define VTCR_FUNC_WRITE_ACL_RULE_CTRL       (0xB << VTCR_FUNC_OFFT)
+#define VTCR_FUNC_READ_ACL_RATE_CTRL        (0xC << VTCR_FUNC_OFFT)
+#define VTCR_FUNC_WRITE_ACL_RATE_CTRL       (0xD << VTCR_FUNC_OFFT)
+#define VTCR_IDX_INVLD_OFFT                 (16)
+#define VTCR_IDX_INVLD_RELMASK              (0x00000001)
+#define VTCR_IDX_INVLD_MASK                 (VTCR_IDX_INVLD_RELMASK << VTCR_IDX_INVLD_OFFT)
+#define VTCR_BUSY_OFFT                      (31)
+#define VTCR_BUSY_LENG                      (1)
+#define VTCR_BUSY_RELMASK                   (0x00000001)
+#define VTCR_BUSY_MASK                      (VTCR_BUSY_RELMASK << VTCR_BUSY_OFFT)
+
+#define PIM_DSCP(d)                         (0x0058 + (4 * (d / 10)))
+
+#define UNUF                                (0x102000B4)
+#define UNMF                                (0x102000B8)
+#define BCF                                 (0x102000BC)
+#define QRYP                                (0x102000D8)
+
+#define VAWD1_ADDR                          (0x0094)
+#define VAWD2_ADDR                          (0x0098)
+#define VAWD3_ADDR                          (0x00E0)
+#define VAWD4_ADDR                          (0x00E4)
+#define VAWD5_ADDR                          (0x00E8)
+#define VAWD6_ADDR                          (0x00EC)
+#define VAWD7_ADDR                          (0x00F0)
+#define VAWD8_ADDR                          (0x00F4)
+#define VAWD_ADDR(n)                        ((n<2)?(VAWD1_ADDR+(0x4*n)):(VAWD3_ADDR+(0x4*(n-2))))
+
+#define SCH_CTRL_BASE                       (0x1000)
+#define SCH_CTRL_PORT_OFFSET                (0x100)
+#define MMSCR(p)                            (SCH_CTRL_BASE + (p * SCH_CTRL_PORT_OFFSET) + 0x90)
+#define MMSCR0(p, q)                        (SCH_CTRL_BASE + (p * SCH_CTRL_PORT_OFFSET) + (8 * q))
+#define MMSCR1(p, q)                        (SCH_CTRL_BASE + (p * SCH_CTRL_PORT_OFFSET) + (8 * q) + 0x04)
+#define MMSCR2(p, q)                        (SCH_CTRL_BASE + (p * SCH_CTRL_PORT_OFFSET) + (8 * q) + 0x50)
+#define MMSCR3(p, q)                        (SCH_CTRL_BASE + (p * SCH_CTRL_PORT_OFFSET) + (8 * q) + 0x54)
+
+/* fields of GERLCR */
+#define EGC_MFRM_EX_OFFSET                  (9)
+#define EGC_MFRM_EX_LENGTH                  (1)
+
+#define BMU_CTRL_BASE                       (0x1800)
+#define BMU_CTRL_PORT_OFFSET                (0x100)
+
+/* fields of MMDPR */
+#define MMDPR_BASE                          (BMU_CTRL_BASE + 0xC)
+#define MMDPR_PORT_OFFSET                   (0x100)
+#define MMDPR_COLOR_OFFSET                  (0x20)
+#define MMDPR_QUEUE_OFFSET                  (0x4)
+#define MMDPR(p,c,q)                        (MMDPR_BASE + (p * MMDPR_PORT_OFFSET) + (c * MMDPR_COLOR_OFFSET) + (q * MMDPR_QUEUE_OFFSET))
+#define MMDPR_EN                            (1 << 31)
+#define MMDPR_PR_OFFSET                     (24)
+#define MMDPR_PR_LENGTH                     (3)
+#define MMDPR_HT_OFFSET                     (12)
+#define MMDPR_HT_LENGTH                     (9)
+#define MMDPR_LT_OFFSET                     (0)
+#define MMDPR_LT_LENGTH                     (9)
+
+/* fields of GIRLCR */
+#define IGC_MFRM_EX_OFFSET                  (9)
+#define IGC_MFRM_EX_LENGTH                  (1)
+
+#define PORT_CTRL_BASE                      (0x10208000)
+#define PORT_CTRL_REG(p, r)                 (PORT_CTRL_BASE + (p) * PORT_CTRL_PORT_OFFSET + (r))
+
+#define PORTMATRIX(p)                       PORT_CTRL_REG(p, 0x44)
+
+#define PCR(p)                              PORT_CTRL_REG(p, 0x04)
+#define PCR_PORT_VLAN_OFFT                  (0)
+#define PCR_PORT_VLAN_LENG                  (2)
+#define PCR_PORT_VLAN_RELMASK               (0x00000003)
+#define PCR_PORT_VLAN_MASK                  (PCR_PORT_VLAN_RELMASK << PCR_PORT_VLAN_OFFT)
+#define PCR_PORT_RX_MIR_OFFT                (16)
+#define PCR_PORT_RX_MIR_LENG                (2)
+#define PCR_PORT_TX_MIR_OFFT                (20)
+#define PCR_PORT_TX_MIR_LENG                (2)
+#define PCR_PORT_PRI_OFFT                   (24)
+#define PCR_PORT_PRI_LENG                   (3)
+#define PCR_PORT_PRI_RELMASK                (0x00000007)
+#define PCR_PORT_PRI_MASK                   (PCR_PORT_PRI_RELMASK << PCR_PORT_PRI_OFFT)
+#define PCR_PORT_ACL_MIS_FWD_OFFT           (4)
+#define PCR_PORT_ACL_MIS_FWD_LENG           (3)
+#define PCR_PORT_ACL_MIS_FWD_RELMASK        (0x00000007)
+#define PCR_PORT_ACL_MIS_FWD_MASK           (PCR_PORT_ACL_MIS_FWD_RELMASK << PCR_PORT_ACL_MIS_FWD_OFFT)
+#define PCR_EG_TAG_OFFT                     (28)
+#define PCR_EG_TAG_LENG                     (2)
+#define PCR_EG_TAG_RELMASK                  (0x00000003)
+#define PCR_EG_TAG_MASK                     (PCR_EG_TAG_RELMASK << PCR_EG_TAG_OFFT)
+#define PCR_RMK_DSCP_EN                     (0x1000)
+#define PCR_RMK_1Q_EN                       (0x0800)
+
+#define PVC(p)                              PORT_CTRL_REG(p, 0x10)
+#define PVC_ACC_FRM_OFFT                    (0)
+#define PVC_ACC_FRM_LENG                    (2)
+#define PVC_ACC_FRM_RELMASK                 (0x00000003)
+#define PVC_ACC_FRM_MASK                    (PVC_ACC_FRM_RELMASK << PVC_ACC_FRM_OFFT)
+#define PVC_UC_LKYV_EN_OFFT                 (2)
+#define PVC_UC_LKYV_EN_LENG                 (1)
+#define PVC_UC_LKYV_EN_RELMASK              (0x00000001)
+#define PVC_UC_LKYV_EN_MASK                 (PVC_UC_LKYV_EN_RELMASK << PVC_UC_LKYV_EN_OFFT)
+#define PVC_MC_LKYV_EN_OFFT                 (3)
+#define PVC_MC_LKYV_EN_LENG                 (1)
+#define PVC_MC_LKYV_EN_RELMASK              (0x00000001)
+#define PVC_MC_LKYV_EN_MASK                 (PVC_MC_LKYV_EN_RELMASK << PVC_MC_LKYV_EN_OFFT)
+#define PVC_BC_LKYV_EN_OFFT                 (4)
+#define PVC_BC_LKYV_EN_LENG                 (1)
+#define PVC_BC_LKYV_EN_RELMASK              (0x00000001)
+#define PVC_BC_LKYV_EN_MASK                 (PVC_BC_LKYV_EN_RELMASK << PVC_BC_LKYV_EN_OFFT)
+#define PVC_SPTAG_EN_OFFT                   (5)
+#define PVC_SPTAG_EN_LENG                   (1)
+#define PVC_SPTAG_EN_RELMASK                (0x00000001)
+#define PVC_SPTAG_EN_MASK                   (PVC_SPTAG_EN_RELMASK << PVC_SPTAG_EN_OFFT)
+#define PVC_VLAN_ATTR_OFFT                  (6)
+#define PVC_VLAN_ATTR_LENG                  (2)
+#define PVC_VLAN_ATTR_RELMASK               (0x00000003)
+#define PVC_VLAN_ATTR_MASK                  (PVC_VLAN_ATTR_RELMASK << PVC_VLAN_ATTR_OFFT)
+#define PVC_EG_TAG_OFFT                     (8)
+#define PVC_EG_TAG_LENG                     (3)
+#define PVC_EG_TAG_RELMASK                  (0x00000007)
+#define PVC_EG_TAG_MASK                     (PVC_EG_TAG_RELMASK << PVC_EG_TAG_OFFT)
+#define PVC_SPTAG_MODE_OFFT                 (11)
+#define PVC_SPTAG_MODE_LENG                 (1)
+#define PVC_STAG_VPID_OFFT                  (16)
+#define PVC_STAG_VPID_LENG                  (16)
+#define PVC_STAG_VPID_RELMASK               (0x0000FFFF)
+#define PVC_STAG_VPID_MASK                  (PVC_STAG_VPID_RELMASK << PVC_STAG_VPID_OFFT)
+
+#define PPBV1(p)                            PORT_CTRL_REG(p, 0x14)
+#define PPBV1_G0_PORT_VID_OFFT              (0)
+#define PPBV1_G0_PORT_VID_LENG              (12)
+#define PPBV1_G0_PORT_VID_RELMASK           (0x00000FFF)
+#define PPBV1_G0_PORT_VID_MASK              (PPBV1_G0_PORT_VID_RELMASK << PPBV1_G0_PORT_VID_OFFT)
+
+#define PVID(p)                             PORT_CTRL_REG(p, 0x48)
+#define PVID_PCVID_OFFT                     (0)
+#define PVID_PCVID_LENG                     (12)
+#define PVID_PCVID_RELMASK                  (0x00000FFF)
+#define PVID_PCVID_MASK                     (PVID_PCVID_RELMASK << PVID_PCVID_OFFT)
+
+#define BSR(p)                              PORT_CTRL_REG(p, 0x50)
+#define BSR1(p)                             PORT_CTRL_REG(p, 0x54)
+#define BSR_EXT1(p)                         PORT_CTRL_REG(p, 0x58)
+#define BSR1_EXT1(p)                        PORT_CTRL_REG(p, 0x5C)
+#define BSR_EXT2(p)                         PORT_CTRL_REG(p, 0x60)
+#define BSR1_EXT2(p)                        PORT_CTRL_REG(p, 0x64)
+#define BSR_EXT3(p)                         PORT_CTRL_REG(p, 0x68)
+#define BSR1_EXT3(p)                        PORT_CTRL_REG(p, 0x6C)
+#define BSR_STORM_COUNT_MSK                 (0xFF)
+#define BSR_STORM_UNIT_MSK                  (7)
+#define BSR_STORM_UNIT_OFFT                 (8)
+#define BSR_STORM_RATE_BASED                (0x1)
+#define BSR_STORM_DROP_EN                   (0x10)
+#define BSR_STORM_BCST_EN                   (0x2)
+#define BSR_STORM_MCST_EN                   (0x4)
+#define BSR_STORM_UCST_EN                   (0x8)
+#define BSR1_10M_COUNT_OFFT                 (0)
+#define BSR1_100M_COUNT_OFFT                (8)
+#define BSR1_1000M_COUNT_OFFT               (16)
+#define BSR1_2500M_COUNT_OFFT               (24)
+
+#define PEM(p, q)                           (PORT_CTRL_REG(p, (0x44 + (4 * (q/2)))))
+
+#define PORT_MAC_CTRL_BASE                  (0x10210000)
+#define PORT_MAC_CTRL_PORT_OFFSET           (0x200)
+#define PORT_MAC_CTRL_REG(p, r)             (PORT_MAC_CTRL_BASE + (p) * PORT_MAC_CTRL_PORT_OFFSET + (r))
+
+#define PMCR(p)                             PORT_MAC_CTRL_REG(p, 0x00)
+
+#define ARL_CTRL_BASE                       (0x0000)
+#define CFC                                 (0x0004)
+/* fields of CFC */
+#define CFC_MIRROR_EN_OFFSET                (19)
+#define CFC_MIRROR_EN_LEN                   (1)
+#define CFC_MIRROR_PORT_OFFSET              (16)
+#define CFC_MIRROR_PORT_LEN                 (3)
+#define MFC_CPU_PORT_OFFSET                 (8)
+#define MFC_CPU_PORT_LENGTH                 (5)
+#define MFC_CPU_EN_OFFSET                   (15)
+#define MFC_CPU_EN_LENGTH                   (1)
+
+
+#define ISC                                 (0x0018)
+#define TSRA1                               (0x0084)
+#define TSRA2                               (0x0088)
+#define ATRD                                (0x008C)
+#define CPGC                                (0x00B0)
+
+#define PSC(p)                              PORT_CTRL_REG(p, 0xC)
+#define PSC_DIS_LRN_OFFSET                  (4)
+#define PSC_DIS_LRN_LENGTH                  (1)
+#define PSC_SA_CNT_EN_OFFSET                (5)
+#define PSC_SA_CNT_EN_LENGTH                (1)
+#define PSC_SA_CNT_LMT_OFFSET               (8)
+#define PSC_SA_CNT_LMT_LENGTH               (12)
+#define PSC_SA_CNT_LMT_REALMASK             (0x00000FFF)
+#define PSC_SA_CNT_LMT_MASK                 (PSC_SA_CNT_LMT_REALMASK << PSC_SA_CNT_LMT_OFFSET)
+#define PSC_SA_CNT_LMT_MAX                  (0x800)
+
+/* fields of CPGC */
+#define COL_EN                              (0x01)
+#define COL_CLK_EN                          (0x02)
+
+#define CKGCR                               (0x10213E1C)
+#define CKG_LNKDN_GLB_STOP                  (0x01)
+#define CKG_LNKDN_PORT_STOP                 (0x02)
+
+/* fields of TRTCM*/
+#define TRTCM                               (ARL_CTRL_BASE + 0x009C)
+#define TRTCM_EN                            (1 << 31)
+
+#define ARL_TRUNK_BASE                      (0x10200000)
+#define PTC                                 (ARL_TRUNK_BASE + 0x400)
+#define PTSEED                              (ARL_TRUNK_BASE + 0x404)
+#define PTGC                                (ARL_TRUNK_BASE + 0x408)
+#define PTG(g)                              (ARL_TRUNK_BASE + 0x40C + ((g) * 0x8 ))
+#define PTGRSTS                             (ARL_TRUNK_BASE + 0x44C)
+
+#define MIR                                 (REG_ARL_BASE_ADDRESS + (0xCC))
+/* fields of MIR */
+#define MIR_MIRROR_BASE_OFFSER              (8)
+#define MIR_MIRROR_EN_OFFSER(p)             ((p) * MIR_MIRROR_BASE_OFFSER + 0x07)
+#define MIR_MIRROR_EN_LEN                   (1)
+#define MIR_MIRROR_PORT_OFFSER(p)           ((p) * MIR_MIRROR_BASE_OFFSER + 0x00)
+#define MIR_MIRROR_PORT_LEN                 (5)
+#define MIR_MIRROR_TAG_TX_EN_OFFSER(p)      ((p) * MIR_MIRROR_BASE_OFFSER + 0x06)
+#define MIR_MIRROR_TAG_TX_EN_LEN            (1)
+
+/* fields of ATA1 */
+#define ATA1                                (REG_ARL_BASE_ADDRESS + 0x0304)
+#define ATA1_MAC_ADDR_MSB_OFFSET            (0)
+#define ATA1_MAC_ADDR_MSB_LENGTH            (32)
+//#define ATA1_SAT_ADDR_OFFSET                (0)
+//#define ATA1_SAT_ADDR_LENGTH                (11)
+//#define ATA1_SAT_BANK_OFFSET                (16)
+//#define ATA1_SAT_BANK_LENGTH                (4)
+
+/* fields of ATA2 */
+#define ATA2                                (REG_ARL_BASE_ADDRESS + 0x0308)
+#define ATA2_MAC_AGETIME_OFFSET             (0)
+#define ATA2_MAC_AGETIME_LENGTH             (9)
+#define ATA2_MAC_LIFETIME_OFFSET            (9)
+#define ATA2_MAC_LIFETIME_LENGTH            (1)
+#define ATA2_MAC_UNAUTH_OFFSET              (10)
+#define ATA2_MAC_UNAUTH_LENGTH              (1)
+#define ATA2_MAC_ADDR_LSB_OFFSET            (16)
+#define ATA2_MAC_ADDR_LSB_LENGTH            (16)
+
+/* fields of ATWD */
+#define ATWD                                (REG_ARL_BASE_ADDRESS + 0x0324)
+#define ATWD_MAC_LIVE_OFFSET                (0)
+#define ATWD_MAC_LIVE_LENGTH                (1)
+#define ATWD_MAC_LEAK_OFFSET                (1)
+#define ATWD_MAC_LEAK_LENGTH                (1)
+#define ATWD_MAC_UPRI_OFFSET                (2)
+#define ATWD_MAC_UPRI_LENGTH                (3)
+#define ATWD_MAC_FWD_OFFSET                 (5)
+#define ATWD_MAC_FWD_LENGTH                 (3)
+#define ATWD_MAC_MIR_OFFSET                 (8)
+#define ATWD_MAC_MIR_LENGTH                 (2)
+#define ATWD_MAC_ETAG_OFFSET                (12)
+#define ATWD_MAC_ETAG_LENGTH                (3)
+#define ATWD_MAC_IVL_OFFSET                 (15)
+#define ATWD_MAC_IVL_LENGTH                 (1)
+#define ATWD_MAC_VID_OFFSET                 (16)
+#define ATWD_MAC_VID_LENGTH                 (12)
+#define ATWD_MAC_FID_OFFSET                 (28)
+#define ATWD_MAC_FID_LENGTH                 (4)
+
+/* fields of ATWD2 */
+#define ATWD2                               (REG_ARL_BASE_ADDRESS + 0x0328)
+#define ATWD2_MAC_PORT_OFFSET               (0)
+#define ATWD2_MAC_PORT_LENGTH               (8)
+
+/* fields of ATC */
+#define ATC                                 (REG_ARL_BASE_ADDRESS + 0x0300)
+#define ATC_MAC_OFFSET                      (0)
+#define ATC_MAC_LENGTH                      (3)
+#define ATC_SAT_OFFSET                      (4)
+#define ATC_SAT_LENGTH                      (2)
+#define ATC_MAT_OFFSET                      (7)
+#define ATC_MAT_LENGTH                      (5)
+#define ATC_ENTRY_HIT_OFFSET                (12)
+#define ATC_ENTRY_HIT_LENGTH                (4)
+#define ATC_ADDR_OFFSET                     (16)
+#define ATC_ADDR_LENGTH                     (9)
+#define ATC_SINGLE_HIT_OFFSET               (30)
+#define ATC_SINGLE_HIT_LENGTH               (1)
+#define ATC_BUSY_OFFSET                     (31)
+#define ATC_BUSY_LENGTH                     (1)
+
+typedef enum {
+    _ATC_CMD_READ = 0,
+    _ATC_CMD_WRITE,
+    _ATC_CMD_CLEAN,
+    _ATC_CMD_SEARCH = 4,
+    _ATC_CMD_SEARCH_NEXT,
+    _ATC_CMD_LAST
+}_ATC_CMD_T;
+
+#define ATC_CMD_READ                        (_ATC_CMD_READ << ATC_MAC_OFFSET)
+#define ATC_CMD_WRITE                       (_ATC_CMD_WRITE << ATC_MAC_OFFSET)
+#define ATC_CMD_CLEAN                       (_ATC_CMD_CLEAN << ATC_MAC_OFFSET)
+#define ATC_CMD_SEARCH                      (_ATC_CMD_SEARCH << ATC_MAC_OFFSET)
+#define ATC_CMD_SEARCH_NEXT                 (_ATC_CMD_SEARCH_NEXT << ATC_MAC_OFFSET)
+
+typedef enum {
+    _ATC_SAT_MAC = 0,
+    _ATC_SAT_DIP,
+    _ATC_SAT_SIP,
+    _ATC_SAT_ADDR,
+    _ATC_SAT_LAST
+}_ATC_SAT_T;
+
+#define ATC_SAT_MAC                         (_ATC_SAT_MAC << ATC_SAT_OFFSET)
+#define ATC_SAT_DIP                         (_ATC_SAT_DIP << ATC_SAT_OFFSET)
+#define ATC_SAT_SIP                         (_ATC_SAT_SIP << ATC_SAT_OFFSET)
+#define ATC_SAT_ADDR                        (_ATC_SAT_ADDR << ATC_SAT_OFFSET)
+
+typedef enum {
+    _ATC_MAT_ALL = 0,
+    _ATC_MAT_MAC,
+    _ATC_MAT_DYNAMIC_MAC,
+    _ATC_MAT_STATIC_MAC,
+    _ATC_MAT_DIP,
+    _ATC_MAT_DIPV4,
+    _ATC_MAT_DIPV6,
+    _ATC_MAT_SIP,
+    _ATC_MAT_SIPV4,
+    _ATC_MAT_SIPV6,
+    _ATC_MAT_MAC_BY_VID,
+    _ATC_MAT_MAC_BY_FID,
+    _ATC_MAT_MAC_BY_PORT,
+    _ATC_MAT_SIP_BY_DIPV4,
+    _ATC_MAT_SIP_BY_SIPV4,
+    _ATC_MAT_SIP_BY_DIPV6,
+    _ATC_MAT_SIP_BY_SIPV6,
+    _ATC_MAT_LAST
+}_ATC_MAT_T;
+
+#define ATC_MAT_ALL                         (_ATC_MAT_ALL << ATC_MAT_OFFSET)
+#define ATC_MAT_MAC                         (_ATC_MAT_MAC << ATC_MAT_OFFSET)
+#define ATC_MAT_DYNAMIC_MAC                 (_ATC_MAT_DYNAMIC_MAC << ATC_MAT_OFFSET)
+#define ATC_MAT_STATIC_MAC                  (_ATC_MAT_STATIC_MAC << ATC_MAT_OFFSET)
+#define ATC_MAT_DIP                         (_ATC_MAT_DIP << ATC_MAT_OFFSET)
+#define ATC_MAT_DIPV4                       (_ATC_MAT_DIPV4 << ATC_MAT_OFFSET)
+#define ATC_MAT_DIPV6                       (_ATC_MAT_DIPV6 << ATC_MAT_OFFSET)
+#define ATC_MAT_SIP                         (_ATC_MAT_SIP << ATC_MAT_OFFSET)
+#define ATC_MAT_SIPV4                       (_ATC_MAT_SIPV4 << ATC_MAT_OFFSET)
+#define ATC_MAT_SIPV6                       (_ATC_MAT_SIPV6 << ATC_MAT_OFFSET)
+#define ATC_MAT_MAC_BY_VID                  (_ATC_MAT_MAC_BY_VID << ATC_MAT_OFFSET)
+#define ATC_MAT_MAC_BY_FID                  (_ATC_MAT_MAC_BY_FID << ATC_MAT_OFFSET)
+#define ATC_MAT_MAC_BY_PORT                 (_ATC_MAT_MAC_BY_PORT << ATC_MAT_OFFSET)
+#define ATC_MAT_SIP_BY_DIPV4                (_ATC_MAT_SIP_BY_DIPV4 << ATC_MAT_OFFSET)
+#define ATC_MAT_SIP_BY_SIPV4                (_ATC_MAT_SIP_BY_SIPV4 << ATC_MAT_OFFSET)
+#define ATC_MAT_SIP_BY_DIPV6                (_ATC_MAT_SIP_BY_DIPV6 << ATC_MAT_OFFSET)
+#define ATC_MAT_SIP_BY_SIPV6                (_ATC_MAT_SIP_BY_SIPV6 << ATC_MAT_OFFSET)
+
+#define ATC_START_BUSY                      (0x01 << ATC_BUSY_OFFSET)
+
+/* fields of AAC*/
+#define AAC                                 (REG_ARL_BASE_ADDRESS + 0x00A0)
+#define AAC_AGE_UNIT_OFFSET                 (0)
+#define AAC_AGE_UNIT_LENGTH                 (11)
+#define AAC_AGE_CNT_OFFSET                  (12)
+#define AAC_AGE_CNT_LENGTH                  (9)
+#define AAC_AUTO_FLUSH_OFFSET               (28)
+#define AAC_AUTO_FLUSH_LENGTH               (1)
+
+#define AGDIS                               (REG_ARL_BASE_ADDRESS + 0x00C0)
+
+/* fields of ATWDS */
+#define ATRDS                               (REG_ARL_BASE_ADDRESS + 0x0330)
+#define ATRD0_MAC_SEL_OFFSET                (0)
+#define ATRD0_MAC_SEL_LENGTH                (2)
+
+/* fields of ATRD0 */
+#define ATRD0                               (REG_ARL_BASE_ADDRESS + 0x0334)
+//need to verify 32'b 0
+#define ATRD0_MAC_LIVE_OFFSET               (0)
+#define ATRD0_MAC_LIVE_LENGTH               (1)
+#define ATRD0_MAC_LIFETIME_OFFSET           (1)
+#define ATRD0_MAC_LIFETIME_LENGTH           (2)
+#define ATRD0_MAC_TYPE_OFFSET               (3)
+#define ATRD0_MAC_TYPE_LENGTH               (2)
+#define ATRD0_MAC_LEAK_OFFSET               (5)
+#define ATRD0_MAC_LEAK_LENGTH               (1)
+#define ATRD0_MAC_UPRI_OFFSET               (6)
+#define ATRD0_MAC_UPRI_LENGTH               (3)
+#define ATRD0_MAC_IVL_OFFSET                (9)
+#define ATRD0_MAC_IVL_LENGTH                (1)
+#define ATRD0_MAC_VID_OFFSET                (10)
+#define ATRD0_MAC_VID_LENGTH                (12)
+#define ATRD0_MAC_ETAG_OFFSET               (22)
+#define ATRD0_MAC_ETAG_LENGTH               (3)
+#define ATRD0_MAC_FID_OFFSET                (25)
+#define ATRD0_MAC_FID_LENGTH                (4)
+#define ATRD1_MAC_UNAUTH_OFFSET             (31)
+#define ATRD1_MAC_UNAUTH_LENGTH             (1)
+
+/* fields of ATRD1 */
+#define ATRD1                               (REG_ARL_BASE_ADDRESS + 0x0338)
+//need to verify 32'b 0
+#define ATRD1_MAC_FWD_OFFSET                (0)
+#define ATRD1_MAC_FWD_LENGTH                (3)
+#define ATRD1_MAC_AGETIME_OFFSET            (3)
+#define ATRD1_MAC_AGETIME_LENGTH            (9)
+#define ATRD1_MAC_MIR_OFFSET                (12)
+#define ATRD1_MAC_MIR_LENGTH                (4)
+#define ATRD1_MAC_ADDR_LSB_OFFSET           (16)
+#define ATRD1_MAC_ADDR_LSB_LENGTH           (16)
+
+/* fields of ATRD2 */
+#define ATRD2                               (REG_ARL_BASE_ADDRESS + 0x033C)
+#define ATRD2_MAC_ADDR_MSB_OFFSET           (0)
+#define ATRD2_MAC_ADDR_MSB_LENGTH           (32)
+
+/* fields of ATRD3 */
+#define ATRD3                               (REG_ARL_BASE_ADDRESS + 0x0340)
+//need to verify 32'b 0
+#define ATRD3_MAC_PORT_OFFSET               (0)
+#define ATRD3_MAC_PORT_LENGTH               (8)
+
+#define REG_SCH_PORT_ADDRESS           (REG_ARL_BASE_ADDRESS + 0xc000)
+#define MMSCR0_Q0(p)                   (REG_SCH_PORT_ADDRESS + PORT_CTRL_PORT_OFFSET * (p))
+#define MMSCR1_Q0(p)                   (REG_SCH_PORT_ADDRESS + PORT_CTRL_PORT_OFFSET * (p) + 0x4)
+#define MMSCR0_Q1(p)                   (REG_SCH_PORT_ADDRESS + PORT_CTRL_PORT_OFFSET * (p) + 0x8)
+#define MMSCR1_Q1(p)                   (REG_SCH_PORT_ADDRESS + PORT_CTRL_PORT_OFFSET * (p) + 0xc)
+#define MMSCR0_Q2(p)                   (REG_SCH_PORT_ADDRESS + PORT_CTRL_PORT_OFFSET * (p) + 0x10)
+#define MMSCR1_Q2(p)                   (REG_SCH_PORT_ADDRESS + PORT_CTRL_PORT_OFFSET * (p) + 0x14)
+#define MMSCR0_Q3(p)                   (REG_SCH_PORT_ADDRESS + PORT_CTRL_PORT_OFFSET * (p) + 0x18)
+#define MMSCR1_Q3(p)                   (REG_SCH_PORT_ADDRESS + PORT_CTRL_PORT_OFFSET * (p) + 0x1c)
+#define MMSCR0_Q4(p)                   (REG_SCH_PORT_ADDRESS + PORT_CTRL_PORT_OFFSET * (p) + 0x20)
+#define MMSCR1_Q4(p)                   (REG_SCH_PORT_ADDRESS + PORT_CTRL_PORT_OFFSET * (p) + 0x24)
+#define MMSCR0_Q5(p)                   (REG_SCH_PORT_ADDRESS + PORT_CTRL_PORT_OFFSET * (p) + 0x28)
+#define MMSCR1_Q5(p)                   (REG_SCH_PORT_ADDRESS + PORT_CTRL_PORT_OFFSET * (p) + 0x2c)
+#define MMSCR0_Q6(p)                   (REG_SCH_PORT_ADDRESS + PORT_CTRL_PORT_OFFSET * (p) + 0x30)
+#define MMSCR1_Q6(p)                   (REG_SCH_PORT_ADDRESS + PORT_CTRL_PORT_OFFSET * (p) + 0x34)
+#define MMSCR0_Q7(p)                   (REG_SCH_PORT_ADDRESS + PORT_CTRL_PORT_OFFSET * (p) + 0x38)
+#define MMSCR1_Q7(p)                   (REG_SCH_PORT_ADDRESS + PORT_CTRL_PORT_OFFSET * (p) + 0x3c)
+
+#define PUPW(p)                             PORT_CTRL_REG(p, 0x30)
+
+#define PEM1                                (REG_ARL_BASE_ADDRESS + 0x0048)
+#define PEM2                                (REG_ARL_BASE_ADDRESS + 0x004c)
+#define PEM3                                (REG_ARL_BASE_ADDRESS + 0x0050)
+#define PEM4                                (REG_ARL_BASE_ADDRESS + 0x0054)
+
+#define PIM1                                (REG_ARL_BASE_ADDRESS + 0x0058)
+#define PIM2                                (REG_ARL_BASE_ADDRESS + 0x005c)
+#define PIM3                                (REG_ARL_BASE_ADDRESS + 0x0060)
+#define PIM4                                (REG_ARL_BASE_ADDRESS + 0x0064)
+#define PIM5                                (REG_ARL_BASE_ADDRESS + 0x0068)
+#define PIM6                                (REG_ARL_BASE_ADDRESS + 0x006c)
+#define PIM7                                (REG_ARL_BASE_ADDRESS + 0x0070)
+
+/* fields of ingress and egress rate control */
+#define IRLCR(p)                            (REG_ARL_BASE_ADDRESS + (p * PORT_CTRL_PORT_OFFSET) + 0x4000)
+#define ERLCR(p)                            (REG_ARL_BASE_ADDRESS + (p * PORT_CTRL_PORT_OFFSET) + 0xC040)
+#define REG_RATE_CIR_OFFT                   (0)
+#define REG_RATE_CIR_LENG                   (17)
+#define REG_TB_EN_OFFT                      (19)
+#define REG_RATE_TB_OFFT                    (20)
+#define REG_RATE_TB_LENG                    (4)
+#define REG_RATE_CBS_OFFT                   (24)
+#define REG_RATE_CBS_LENG                   (7)
+#define REG_RATE_EN_OFFT                    (31)
+
+/* fields of global ingress and egress rate control */
+#define GIRLCR                              (REG_ARL_BASE_ADDRESS + 0x7E24)
+#define GERLCR                              (REG_ARL_BASE_ADDRESS + 0xFE00)
+#define REG_IPG_BYTE_OFFT                   (0)
+#define REG_IPG_BYTE_LENG                   (8)
+#define REG_MFRM_EX_OFFT                    (9)
+#define REG_MFRM_EX_LENG                    (1)
+#define SFLOW_MFRM_EX_OFFT                  (25)
+#define SFLOW_MFRM_EX_LENG                  (1)
+#define L1_RATE_IPG_BYTE_CNT                (0x18)
+#define L2_RATE_IPG_BYTE_CNT                (0x04)
+
+
+/* fields of PTC */
+#define PTC_INFO_SEL_SP                     (1 << 0)
+#define PTC_INFO_SEL_SA                     (1 << 1)
+#define PTC_INFO_SEL_DA                     (1 << 2)
+#define PTC_INFO_SEL_SIP                    (1 << 3)
+#define PTC_INFO_SEL_DIP                    (1 << 4)
+#define PTC_INFO_SEL_SPORT                  (1 << 5)
+#define PTC_INFO_SEL_DPORT                  (1 << 6)
+
+#define SSC(p)                              PORT_CTRL_REG(p, 0x00)
+#define PIC(p)                              PORT_CTRL_REG(p, 0x08)
+
+/* fields of IGMP SNOOPING */
+#define IGMP_HW_GQUERY                      1
+#define IGMP_HW_SQUERY                      (1 << 2)
+#define IGMP_HW_JOIN                        (1 << 4)
+#define IGMPV3_HW_JOIN                      (1 << 6)
+#define DMAC_01005E                         (1 << 8)
+#define DMAC_3333XX                         (1 << 9)
+#define MCAST_DIP                           (1 << 10)
+#define IGMP_HW_LEAVE                       (1 << 12)
+#define IGMP_AUTO_DOWNGRADE                 (1 << 20)
+#define IGMP_AUTO_ROUTER                    (1 << 18)
+#define IGMP_ROBUSTNESS_OFFSET              16
+#define IGMP_QUERYINTERVAL_OFFSET           8
+
+/* fields of MLD SNOOPING */
+#define MLD_HW_GQUERY                       (1 << 1)
+#define MLD_HW_SQUERY                       (1 << 3)
+#define MLD_HW_JOIN                         (1 << 5)
+#define MLDV2_HW_JOIN                       (1 << 7)
+#define MLD_HW_LEAVE                        (1 << 13)
+#define MLD_AUTO_ROUTER                     (1 << 19)
+
+#define PMSR(p)                             PORT_MAC_CTRL_REG(p, 0x10)
+
+/* fields of loop detect */
+#define LPDET_CTRL                          0x30C0
+#define LPDET_OFFSET                        24
+#define LPDET_TRIGGER_OFFSET                23
+#define LPDET_TRIGGER_PERIODICAL            1
+#define LPDET_TRIGGER_BROADCAST             0
+
+/* Port debug count register */
+#define DBG_CNT_BASE                        0x3018
+#define DBG_CNT_PORT_BASE                   0x100
+#define DBG_CNT(p)                          (DBG_CNT_BASE + (p) * DBG_CNT_PORT_BASE)
+#define DIS_CLR                             (1 << 31)
+
+#define PFC_STS(p)                          PORT_MAC_CTRL_REG(p, 0x24)
+#define PFC_CTRL                            (PORT_MAC_CTRL_BASE + 0xB0)
+#define PFC_EN(p)                           (1 << p)
+#define PFC_SYN_EN(p)                       (0x80 << p)
+
+#define GMACCR                              (PORT_MAC_CTRL_BASE + 0x3e00)
+#define MTCC_LMT_S                          8
+#define MAX_RX_JUMBO_S                      4
+
+/* Values of MAX_RX_PKT_LEN */
+#define RX_PKT_LEN_1518                     (0)
+#define RX_PKT_LEN_1536                     (1)
+#define RX_PKT_LEN_1522                     (2)
+#define RX_PKT_LEN_MAX_JUMBO                (3)
+
+/* Fields of PMCR */
+#define FORCE_MODE                          (1 << 31)
+#define IPG_CFG_S                           (20)
+#define IPG_CFG_M                           (0x300000)
+#define EXT_PHY                             (1 << 19)
+#define MAC_MODE                            (1 << 18)
+#define MAC_TX_EN                           (1 << 16)
+#define MAC_RX_EN                           (1 << 15)
+#define MAC_PRE                             (1 << 14)
+#define BKOFF_EN                            (1 << 12)
+#define BACKPR_EN                           (1 << 11)
+#define FORCE_EEE1G                         (1 << 7)
+#define FORCE_EEE100                        (1 << 6)
+#define FORCE_RX_FC                         (1 << 5)
+#define FORCE_TX_FC                         (1 << 4)
+#define FORCE_SPD_S                         (28)
+#define FORCE_SPD_M                         (0x70000000)
+#define FORCE_DPX                           (1 << 25)
+#define FORCE_LINK                          (1 << 24)
+
+/* Fields of PMSR */
+#define EEE1G_STS                           (1 << 7)
+#define EEE100_STS                          (1 << 6)
+#define RX_FC_STS                           (1 << 5)
+#define TX_FC_STS                           (1 << 4)
+#define MAC_SPD_STS_S                       (28)
+#define MAC_SPD_STS_M                       (0x70000000)
+#define MAC_DPX_STS                         (1 << 25)
+#define MAC_LNK_STS                         (1 << 24)
+
+/* Values of MAC_SPD_STS */
+#define MAC_SPD_10                          0
+#define MAC_SPD_100                         1
+#define MAC_SPD_1000                        2
+#define MAC_SPD_2500                        3
+
+/* Values of IPG_CFG */
+#define IPG_96BIT                           0
+#define IPG_96BIT_WITH_SHORT_IPG            1
+#define IPG_64BIT                           2
+
+/* Register of MIB Base address */
+#define MAC_GLOBAL_REG_BASE                 0x10213E00
+#define ARL_ACL_ATK_REG_BASE                0x10200000
+
+#define MIB_BASE                            0x10214000
+#define MIB_PORT_OFFSET                     0x0200
+#define MIB_ACL_EVENT_OFFSET                0x0F00
+#define MIB_TDPC(p)                         (MIB_BASE + (p) * MIB_PORT_OFFSET + 0x00)
+#define MIB_TCRC(p)                         (MIB_BASE + (p) * MIB_PORT_OFFSET + 0x04)
+#define MIB_TUPC(p)                         (MIB_BASE + (p) * MIB_PORT_OFFSET + 0x08)
+#define MIB_TMPC(p)                         (MIB_BASE + (p) * MIB_PORT_OFFSET + 0x0C)
+#define MIB_TBPC(p)                         (MIB_BASE + (p) * MIB_PORT_OFFSET + 0x10)
+#define MIB_TCEC(p)                         (MIB_BASE + (p) * MIB_PORT_OFFSET + 0x14)
+#define MIB_TSCEC(p)                        (MIB_BASE + (p) * MIB_PORT_OFFSET + 0x18)
+#define MIB_TMCEC(p)                        (MIB_BASE + (p) * MIB_PORT_OFFSET + 0x1C)
+#define MIB_TDEC(p)                         (MIB_BASE + (p) * MIB_PORT_OFFSET + 0x20)
+#define MIB_TLCEC(p)                        (MIB_BASE + (p) * MIB_PORT_OFFSET + 0x24)
+#define MIB_TXCEC(p)                        (MIB_BASE + (p) * MIB_PORT_OFFSET + 0x28)
+#define MIB_TPPC(p)                         (MIB_BASE + (p) * MIB_PORT_OFFSET + 0x2C)
+#define MIB_TL64PC(p)                       (MIB_BASE + (p) * MIB_PORT_OFFSET + 0x30)
+#define MIB_TL65PC(p)                       (MIB_BASE + (p) * MIB_PORT_OFFSET + 0x34)
+#define MIB_TL128PC(p)                      (MIB_BASE + (p) * MIB_PORT_OFFSET + 0x38)
+#define MIB_TL256PC(p)                      (MIB_BASE + (p) * MIB_PORT_OFFSET + 0x3C)
+#define MIB_TL512PC(p)                      (MIB_BASE + (p) * MIB_PORT_OFFSET + 0x40)
+#define MIB_TL1024PC(p)                     (MIB_BASE + (p) * MIB_PORT_OFFSET + 0x44)
+#define MIB_TL1519PC(p)                     (MIB_BASE + (p) * MIB_PORT_OFFSET + 0x48)
+
+#define MIB_TOCL(p)                         (MIB_BASE + (p) * MIB_PORT_OFFSET + 0x4C)
+#define MIB_TOCH(p)                         (MIB_BASE + (p) * MIB_PORT_OFFSET + 0x50)
+#define MIB_TODPC(p)                        (MIB_BASE + (p) * MIB_PORT_OFFSET + 0x54)
+#define MIB_TOCL2(p)                        (MIB_BASE + (p) * MIB_PORT_OFFSET + 0x58)
+#define MIB_TOCH2(p)                        (MIB_BASE + (p) * MIB_PORT_OFFSET + 0x5C)
+
+
+
+#define MIB_RDPC(p)                         (MIB_BASE + (p) * MIB_PORT_OFFSET + 0x80)
+#define MIB_RFPC(p)                         (MIB_BASE + (p) * MIB_PORT_OFFSET + 0x84)
+#define MIB_RUPC(p)                         (MIB_BASE + (p) * MIB_PORT_OFFSET + 0x88)
+#define MIB_RMPC(p)                         (MIB_BASE + (p) * MIB_PORT_OFFSET + 0x8C)
+#define MIB_RBPC(p)                         (MIB_BASE + (p) * MIB_PORT_OFFSET + 0x90)
+#define MIB_RAEPC(p)                        (MIB_BASE + (p) * MIB_PORT_OFFSET + 0x94)
+#define MIB_RCEPC(p)                        (MIB_BASE + (p) * MIB_PORT_OFFSET + 0x98)
+#define MIB_RUSPC(p)                        (MIB_BASE + (p) * MIB_PORT_OFFSET + 0x9C)
+#define MIB_RFEPC(p)                        (MIB_BASE + (p) * MIB_PORT_OFFSET + 0xA0)
+#define MIB_ROSPC(p)                        (MIB_BASE + (p) * MIB_PORT_OFFSET + 0xA4)
+#define MIB_RJEPC(p)                        (MIB_BASE + (p) * MIB_PORT_OFFSET + 0xA8)
+#define MIB_RPPC(p)                         (MIB_BASE + (p) * MIB_PORT_OFFSET + 0xAC)
+#define MIB_RL64PC(p)                       (MIB_BASE + (p) * MIB_PORT_OFFSET + 0xB0)
+#define MIB_RL65PC(p)                       (MIB_BASE + (p) * MIB_PORT_OFFSET + 0xB4)
+#define MIB_RL128PC(p)                      (MIB_BASE + (p) * MIB_PORT_OFFSET + 0xB8)
+#define MIB_RL256PC(p)                      (MIB_BASE + (p) * MIB_PORT_OFFSET + 0xBC)
+#define MIB_RL512PC(p)                      (MIB_BASE + (p) * MIB_PORT_OFFSET + 0xC0)
+#define MIB_RL1024PC(p)                     (MIB_BASE + (p) * MIB_PORT_OFFSET + 0xC4)
+#define MIB_RL1519PC(p)                     (MIB_BASE + (p) * MIB_PORT_OFFSET + 0xC8)
+
+#define MIB_ROCL(p)                         (MIB_BASE + (p) * MIB_PORT_OFFSET + 0xCC)
+#define MIB_ROCH(p)                         (MIB_BASE + (p) * MIB_PORT_OFFSET + 0xD0)
+#define MIB_RCDPC(p)                        (MIB_BASE + (p) * MIB_PORT_OFFSET + 0xD4)
+#define MIB_RIDPC(p)                        (MIB_BASE + (p) * MIB_PORT_OFFSET + 0xD8)
+#define MIB_RADPC(p)                        (MIB_BASE + (p) * MIB_PORT_OFFSET + 0xDC)
+#define MIB_FCDPC(p)                        (MIB_BASE + (p) * MIB_PORT_OFFSET + 0xE0)
+#define MIB_WRDPC(p)                        (MIB_BASE + (p) * MIB_PORT_OFFSET + 0xE4)
+#define MIB_MRDPC(p)                        (MIB_BASE + (p) * MIB_PORT_OFFSET + 0xE8)
+#define MIB_ROCL2(p)                        (MIB_BASE + (p) * MIB_PORT_OFFSET + 0xEC)
+#define MIB_ROCH2(p)                        (MIB_BASE + (p) * MIB_PORT_OFFSET + 0xF0)
+#define MIB_SFSPC(p)                        (MIB_BASE + (p) * MIB_PORT_OFFSET + 0xF4)
+#define MIB_SFTPC(p)                        (MIB_BASE + (p) * MIB_PORT_OFFSET + 0xF8)
+#define MIB_RXC_DPC(p)                      (MIB_BASE + (p) * MIB_PORT_OFFSET + 0xFC)
+
+
+#define MIB_TMIB_HF_STS(p)                  (MIB_BASE + (p) * MIB_PORT_OFFSET + 0x7C)
+#define MIB_RMIB_HF_STS(p)                  (MIB_BASE + (p) * MIB_PORT_OFFSET + 0x100)
+
+#define ACL_MIB_CNT_CFG                     (ARL_ACL_ATK_REG_BASE + 0x534)
+#define ACL_MIB_CNT                         (ARL_ACL_ATK_REG_BASE + 0x538)
+
+
+#define MIB_CCR                             (MAC_GLOBAL_REG_BASE + 0x0030)
+#define MIB_PCLR                            (MAC_GLOBAL_REG_BASE + 0x0034)
+#define MIB_CCR_MIB_ENABLE_OFFSET           (31)
+#define MIB_CCR_MIB_ENABLE_LENGTH            (1)
+#define MIB_CCR_MIB_ENABLE                  (1 << 31)
+#define MIB_CCR_RX_OCT_CNT_GOOD             (1 << 7)
+#define MIB_CCR_RX_OCT_CNT_BAD              (1 << 6)
+#define MIB_CCR_TX_OCT_CNT_GOOD             (1 << 5)
+#define MIB_CCR_TX_OCT_CNT_BAD              (1 << 4)
+
+#define CSR_ACL_MIB_CLEAR                   (1 << 0)
+
+#define SGMII_REG_BASE                      0x5000
+#define SGMII_REG_PORT_BASE                 0x1000
+#define SGMII_REG(p, r)                     (SGMII_REG_BASE + (p) * SGMII_REG_PORT_BASE + (r))
+#define PCS_CONTROL_1(p)                    SGMII_REG(p, 0x00)
+#define PCS_SPEED_ABILITY(p)                SGMII_REG(p, 0x08)
+#define SGMII_MODE(p)                       SGMII_REG(p, 0x20)
+#define QPHY_PWR_STATE_CTRL(p)              SGMII_REG(p, 0xE8)
+#define PHYA_CTRL_SIGNAL3(p)                SGMII_REG(p, 0x128)
+
+/* Fields of PCS_CONTROL_1 */
+#define SGMII_AN_ABILITY                    (1 << 19)
+#define SGMII_LINK_STATUS                   (1 << 18)
+#define SGMII_AN_ENABLE_OFFT                (12)
+#define SGMII_AN_ENABLE                     (1 << 12)
+#define SGMII_AN_RESTART                    (1 << 9)
+
+/* Fields of SGMII_MODE */
+#define SGMII_REMOTE_FAULT_DIS              (1 << 8)
+#define SGMII_IF_MODE_FORCE_DUPLEX          (1 << 4)
+#define SGMII_IF_MODE_FORCE_SPEED_OFFT      (0x2)
+#define SGMII_IF_MODE_FORCE_SPEED_R         (0x2)
+#define SGMII_IF_MODE_FORCE_SPEED_M         (0x0C)
+#define SGMII_IF_MODE_ADVERT_AN             (1 << 1)
+
+/* Config of AN Tx control information (SGMII)
+* LINK- 1:link up, 0:link down
+* DUPLEX- 1:full, 0:half
+* MODE - 1:SGMII, 0:Clause37
+*/
+#define AN_CONFIG_TX_LINK                   (1 << 15)
+#define AN_CONFIG_TX_DUPLEX                 (1 << 12)
+#define AN_CONFIG_TX_SPEED_OFFT             (10)
+#define AN_CONFIG_TX_SPEED_MSK              (3 << AN_CONFIG_TX_SPEED_OFFT)
+#define AN_CONFIG_TX_MODE_SGMII             (1)
+
+/* Config of AN Tx control information (Clause37)
+* MODE - 1:SGMII, 0:Clause37
+*/
+#define AN_CONFIG_TX_FULL_DUPLEX_CL37       (1 << 5)
+#define AN_CONFIG_TX_HALF_DUPLEX_CL37       (1 << 6)
+#define AN_CONFIG_TX_SYMMETRIC_PAUSE        (1 << 7)
+#define AN_CONFIG_TX_ASYMMETRIC_PAUSE       (1 << 8)
+
+/* Values of SGMII_IF_MODE_FORCE_SPEED */
+#define SGMII_IF_MODE_FORCE_SPEED_10        0
+#define SGMII_IF_MODE_FORCE_SPEED_100       1
+#define SGMII_IF_MODE_FORCE_SPEED_1000      2
+
+/* Fields of QPHY_PWR_STATE_CTRL */
+#define PHYA_PWD                            (1 << 4)
+
+/* Fields of PHYA_CTRL_SIGNAL3 */
+#define RG_TPHY_SPEED_S                     2
+#define RG_TPHY_SPEED_M                     0x0c
+
+/* Values of RG_TPHY_SPEED */
+#define RG_TPHY_SPEED_1000                  0
+#define RG_TPHY_SPEED_2500                  1
+
+
+#define SCU_BASE                            0x10000000
+#define RG_RGMII_TXCK_C                     (SCU_BASE + 0x1d0)
+
+#define HSGMII_AN_CSR_BASE                  0x10220000
+#define SGMII_REG_AN0                       (HSGMII_AN_CSR_BASE + 0x000)
+#define SGMII_REG_AN_13                     (HSGMII_AN_CSR_BASE + 0x034)
+#define SGMII_REG_AN_FORCE_CL37             (HSGMII_AN_CSR_BASE + 0x060)
+
+#define HSGMII_CSR_PCS_BASE                 0x10220000
+#define RG_HSGMII_PCS_CTROL_1               (HSGMII_CSR_PCS_BASE + 0xa00)
+#define RG_AN_SGMII_MODE_FORCE              (HSGMII_CSR_PCS_BASE + 0xa24)
+
+#define MULTI_SGMII_CSR_BASE                0x10224000
+#define SGMII_STS_CTRL_0                    (MULTI_SGMII_CSR_BASE + 0x018)
+#define MSG_RX_CTRL_0                       (MULTI_SGMII_CSR_BASE + 0x100)
+#define MSG_RX_LIK_STS_0                    (MULTI_SGMII_CSR_BASE + 0x514)
+#define MSG_RX_LIK_STS_2                    (MULTI_SGMII_CSR_BASE + 0x51c)
+#define PHY_RX_FORCE_CTRL_0                 (MULTI_SGMII_CSR_BASE + 0x520)
+
+#define XFI_CSR_PCS_BASE                    0x10225000
+#define RG_USXGMII_AN_CONTROL_0             (XFI_CSR_PCS_BASE + 0xbf8)
+
+#define MULTI_PHY_RA_CSR_BASE               0x10226000
+#define RG_RATE_ADAPT_CTRL_0               (MULTI_PHY_RA_CSR_BASE + 0x000)
+#define RATE_ADP_P0_CTRL_0                 (MULTI_PHY_RA_CSR_BASE + 0x100)
+#define MII_RA_AN_ENABLE                   (MULTI_PHY_RA_CSR_BASE + 0x300)
+
+#define QP_DIG_CSR_BASE                     0x1022a000
+#define QP_CK_RST_CTRL_4                    (QP_DIG_CSR_BASE + 0x310)
+#define QP_DIG_MODE_CTRL_0                  (QP_DIG_CSR_BASE + 0x324)
+#define QP_DIG_MODE_CTRL_1                  (QP_DIG_CSR_BASE + 0x330)
+
+#define SERDES_WRAPPER_BASE                 0x1022c000
+#define USGMII_CTRL_0                       (SERDES_WRAPPER_BASE + 0x000)
+
+#define QP_PMA_TOP_BASE                     0x1022e000
+#define PON_RXFEDIG_CTRL_0                  (QP_PMA_TOP_BASE + 0x100)
+#define PON_RXFEDIG_CTRL_9                  (QP_PMA_TOP_BASE + 0x124)
+
+#define SS_LCPLL_PWCTL_SETTING_2            (QP_PMA_TOP_BASE + 0x208)
+#define SS_LCPLL_TDC_FLT_2                  (QP_PMA_TOP_BASE + 0x230)
+#define SS_LCPLL_TDC_FLT_5                  (QP_PMA_TOP_BASE + 0x23c)
+#define SS_LCPLL_TDC_PCW_1                  (QP_PMA_TOP_BASE + 0x248)
+#define INTF_CTRL_8                         (QP_PMA_TOP_BASE + 0x320)
+#define INTF_CTRL_9                         (QP_PMA_TOP_BASE + 0x324)
+#define PLL_CTRL_0                          (QP_PMA_TOP_BASE + 0x400)
+#define PLL_CTRL_2                          (QP_PMA_TOP_BASE + 0x408)
+#define PLL_CTRL_3                          (QP_PMA_TOP_BASE + 0x40c)
+#define PLL_CTRL_4                          (QP_PMA_TOP_BASE + 0x410)
+#define PLL_CK_CTRL_0                       (QP_PMA_TOP_BASE + 0x414)
+#define RX_DLY_0                            (QP_PMA_TOP_BASE + 0x614)
+#define RX_CTRL_2                           (QP_PMA_TOP_BASE + 0x630)
+#define RX_CTRL_5                           (QP_PMA_TOP_BASE + 0x63c)
+#define RX_CTRL_6                           (QP_PMA_TOP_BASE + 0x640)
+#define RX_CTRL_7                           (QP_PMA_TOP_BASE + 0x644)
+#define RX_CTRL_8                           (QP_PMA_TOP_BASE + 0x648)
+#define RX_CTRL_26                          (QP_PMA_TOP_BASE + 0x690)
+#define RX_CTRL_42                          (QP_PMA_TOP_BASE + 0x6d0)
+
+#define QP_ANA_CSR_BASE                     0x1022f000
+#define RG_QP_RX_DAC_EN                     (QP_ANA_CSR_BASE + 0x00)
+#define RG_QP_RXAFE_RESERVE                 (QP_ANA_CSR_BASE + 0x04)
+#define RG_QP_CDR_LPF_MJV_LIM               (QP_ANA_CSR_BASE + 0x0c)
+#define RG_QP_CDR_LPF_SETVALUE              (QP_ANA_CSR_BASE + 0x14)
+#define RG_QP_CDR_PR_CKREF_DIV1             (QP_ANA_CSR_BASE + 0x18)
+#define RG_QP_CDR_PR_KBAND_DIV_PCIE         (QP_ANA_CSR_BASE + 0x1c)
+#define RG_QP_CDR_FORCE_IBANDLPF_R_OFF      (QP_ANA_CSR_BASE + 0x20)
+#define RG_QP_TX_MODE_16B_EN                (QP_ANA_CSR_BASE + 0x28)
+#define RG_QP_PLL_IPLL_DIG_PWR_SEL          (QP_ANA_CSR_BASE + 0x3c)
+#define RG_QP_PLL_SDM_ORD                   (QP_ANA_CSR_BASE + 0x40)
+
+#define ETHER_SYS_BASE                      0x1028c800
+#define RG_P5MUX_MODE                       (ETHER_SYS_BASE + 0x00)
+#define RG_FORCE_CKDIR_SEL                  (ETHER_SYS_BASE + 0x04)
+#define RG_SWITCH_MODE                      (ETHER_SYS_BASE + 0x08)
+#define RG_FORCE_MAC5_SB                    (ETHER_SYS_BASE + 0x2c)
+#define CSR_RMII                            (ETHER_SYS_BASE + 0x70)
+
+
+#define SYS_CTRL                            0x7000
+#define SW_PHY_RST                          (1 << 2)
+#define SW_SYS_RST                          (1 << 1)
+#define SW_REG_RST                          (1 << 0)
+
+#define PHY_IAC                             0x1000e000
+
+#define CLKGEN_CTRL                         0x7500
+#define CLK_SKEW_OUT_S                      8
+#define CLK_SKEW_OUT_M                      0x300
+#define CLK_SKEW_IN_S                       6
+#define CLK_SKEW_IN_M                       0xc0
+#define RXCLK_NO_DELAY                      (1 << 5)
+#define TXCLK_NO_REVERSE                    (1 << 4)
+#define GP_MODE_S                           1
+#define GP_MODE_M                           0x06
+#define GP_CLK_EN                           (1 << 0)
+
+/* Values of GP_MODE */
+#define GP_MODE_RGMII                       0
+#define GP_MODE_MII                         1
+#define GP_MODE_REV_MII                     2
+
+/* Values of CLK_SKEW_IN */
+#define CLK_SKEW_IN_NO_CHANGE               0
+#define CLK_SKEW_IN_DELAY_100PPS            1
+#define CLK_SKEW_IN_DELAY_200PPS            2
+#define CLK_SKEW_IN_REVERSE                 3
+
+/* Values of CLK_SKEW_OUT */
+#define CLK_SKEW_OUT_NO_CHANGE              0
+#define CLK_SKEW_OUT_DELAY_100PPS           1
+#define CLK_SKEW_OUT_DELAY_200PPS           2
+#define CLK_SKEW_OUT_REVERSE                3
+
+#define HWSTRAP                             0x7800
+#define XTAL_FSEL_S                         7
+#define XTAL_FSEL_M                         (1 << 7)
+
+#define XTAL_40MHZ                          0
+#define XTAL_25MHZ                          1
+
+#define PLLGP_EN                            0x7820
+#define EN_COREPLL                          (1 << 2)
+#define SW_CLKSW                            (1 << 1)
+#define SW_PLLGP                            (1 << 0)
+
+#define PLLGP_CR0                           0x78a8
+#define RG_COREPLL_EN                       (1 << 22)
+#define RG_COREPLL_POSDIV_S                 23
+#define RG_COREPLL_POSDIV_M                 0x3800000
+#define RG_COREPLL_SDM_PCW_S                1
+#define RG_COREPLL_SDM_PCW_M                0x3ffffe
+#define RG_COREPLL_SDM_PCW_CHG              (1 << 0)
+
+#define MHWSTRAP                            0x7804
+#define STRAP_CHG_STRAP                     (1 << 8)
+#define STRAP_PHY_EN                        (1 << 6)
+
+#define TOP_SIG_SR                          0x780c
+#define PAD_DUAL_SGMII_EN                   (1 << 1)
+
+/* RGMII and SGMII PLL clock */
+#define ANA_PLLGP_CR2                       0x78b0
+#define ANA_PLLGP_CR5                       0x78bc
+
+/* Efuse Register Define */
+#define GBE_EFUSE                           0x7bc8
+#define GBE_SEL_EFUSE_EN                    (1 << 0)
+
+/* GPIO_PAD_0 */
+#define GPIO_MODE0                          0x7c0c
+#define GPIO_MODE0_S                        0
+#define GPIO_MODE0_M                        0xf
+#define GPIO_0_INTERRUPT_MODE               0x1
+
+#define SMT0_IOLB                           0x7f04
+#define SMT_IOLB_5_SMI_MDC_EN               (1 << 5)
+
+/* PHY CL22 reg */
+#define PHY_PAGE_0                          0x0
+/* Mode Control Register */
+#define PHY_MCR                             0x00
+#define MCR_SR                              (1 << 15)
+#define MCR_LB                              (1 << 14)
+#define MCR_MR_FC_SPD_INT_0                 (1 << 13)
+#define MCR_AN_EN                           (1 << 12)
+#define MCR_PW_DN                           (1 << 11)
+#define MCR_ISO                             (1 << 10)
+#define MCR_RST_AN                          (1 << 9)
+#define MCR_MR_DUX                          (1 << 8)
+#define MCR_MR_CLS_TEST                     (1 << 7)
+#define MCR_MR_FC_SPD_INT_1                 (1 << 6)
+
+/* Mode Status Register */
+#define PHY_MSR                             0x01
+#define MSR_CAP_100T4                       (1 << 15)
+#define MSR_CAP_100X_FDX                    (1 << 14)
+#define MSR_CAP_100X_HDX                    (1 << 13)
+#define MSR_CAP_10T_FDX                     (1 << 12)
+#define MSR_CAP_10T_HDX                     (1 << 11)
+#define MSR_CAP_100T2_HDX                   (1 << 10)
+#define MSR_CAP_100T2_FDX                   (1 << 9)
+#define MSR_EXT_STA_EN                      (1 << 8)
+#define MSR_PRAM_SUP_CAP                    (1 << 6)
+#define MSR_AN_COMP                         (1 << 5)
+#define MSR_RMT_FAULT                       (1 << 4)
+#define MSR_AN_CAP                          (1 << 3)
+#define MSR_LINK_STA                        (1 << 2)
+#define MSR_JAB_DECT                        (1 << 1)
+#define MSR_EXT_CAP                         (1 << 0)
+
+/* Auto-Negotiation Advertisement Register */
+#define PHY_AN_ADV                          0x04
+#define AN_ADV_NX_PAGE_REQ                  (1 << 15)
+#define AN_ADV_RF                           (1 << 13)
+#define AN_ADV_CAP_PAUSE                    (3 << 10)
+#define AN_ADV_CAP_100_T4                   (1 << 9)
+#define AN_ADV_CAP_100_FDX                  (1 << 8)
+#define AN_ADV_CAP_100_HDX                  (1 << 7)
+#define AN_ADV_CAP_10_FDX                   (1 << 6)
+#define AN_ADV_CAP_10_HDX                   (1 << 5)
+#define AN_ADV_802_9_ISLAN_16T              (2 << 0)
+#define AN_ADV_802_3                        (1 << 0)
+
+/* Auto-Negotiation Link Partner Advertisement Register */
+#define PHY_AN_LP_ADV                       0x05
+#define AN_LP_NX_PAGE_REQ                   (1 << 15)
+#define AN_LP_ACK                           (1 << 14)
+#define AN_LP_RF                            (1 << 13)
+#define AN_LP_CAP_PAUSE                     (3 << 10)
+#define AN_LP_CAP_100_T4                    (1 << 9)
+#define AN_LP_CAP_100_FDX                   (1 << 8)
+#define AN_LP_CAP_100_HDX                   (1 << 7)
+#define AN_LP_CAP_10_FDX                    (1 << 6)
+#define AN_LP_CAP_10_HDX                    (1 << 5)
+#define AN_LP_802_9_ISLAN_16T               (2 << 0)
+#define AN_LP_802_3                         (1 << 0)
+
+/* 1000BASE-T Control Register */
+#define PHY_CR1G                            0x09
+#define CR1G_TEST_TM4                       (4 << 13)
+#define CR1G_TEST_TM3                       (3 << 13)
+#define CR1G_TEST_TM2                       (2 << 13)
+#define CR1G_TEST_TM1                       (1 << 13)
+#define CR1G_TEST_NORMAL                    (0 << 13)
+#define CR1G_MS_EN                          (1 << 12)
+#define CR1G_MS_CONF                        (1 << 11)
+#define CR1G_PORT_TYPE                      (1 << 10)
+#define CR1G_ADV_CAP1000_FDX                (1 << 9)
+#define CR1G_ADV_CAP1000_HDX                (1 << 8)
+
+/* 1000BASE-T Status Register */
+#define PHY_SR1G                            0x0A
+#define SR1G_MS_CFG_FAULT                   (1 << 15)
+#define SR1G_MS_CFG_RES                     (1 << 14)
+#define SR1G_LOC_RX                         (1 << 13)
+#define SR1G_RMT_RX                         (1 << 12)
+#define SR1G_CAP1000_FDX                    (1 << 11)
+#define SR1G_CAP1000_HDX                    (1 << 10)
+#define SR1G_IDLE_ERR_MASK                  0xFF
+
+#define PHY_PAGE_1                          0x1
+/* Ethernet Packet Generator Control Register */
+#define PHY_EPG                             0x1D
+#define EPG_EN                              (1 << 15)
+#define EPG_RUN                             (1 << 14)
+#define EPG_TX_DUR                          (1 << 13)
+#define EPG_PKT_LEN_10KB                    (3 << 11)
+#define EPG_PKT_LEN_1518B                   (2 << 11)
+#define EPG_PKT_LEN_64B                     (1 << 11)
+#define EPG_PKT_LEN_125B                    (0 << 11)
+#define EPG_PKT_GAP                         (1 << 10)
+#define EPG_DES_ADDR(a)                     ( ( (a) & 0xF ) << 6 )
+#define EPG_SUR_ADDR(a)                     ( ( (a) & 0xF ) << 2 )
+#define EPG_PL_TYP_RANDOM                   (1 << 1)
+#define EPG_BAD_FCS                         (1 << 0)
+
+/* external*/
+#define EXPHY_CMD_WRITE                     (0x10)
+#define DFETAILDC_COEFF_L                   (0x11)
+#define DFETAILDC_COEFF_M                   (0x12)
+
+/* PHY CL22 reg */
+#define PHY_PAGE                            (0x1F)
+
+/* PHY CL45 reg */
+#define PHY_DEV_07H                         (0x07)
+#define PHY_DEV_1FH                         (0x1F)
+#define PHY_DEV_1EH                         (0x1E)
+
+/* dev 07h, reg 03Ch: EEE Advertisement Register */
+#define EEE_ADV_REG                         (0x3C)
+#define EEE_ADV_1000BT                      (1 << 2)
+#define EEE_ADV_100BT                       (1 << 1)
+
+/* dev 1Eh, reg 013h: TX pair delay Register */
+#define TX_PAIR_DELAY_SEL_REG               (0x013)
+
+/* dev 1Eh, reg 03Ch: Bypass power-down Register */
+#define BYPASS_POWER_DOWN_REG0              (0x3C)
+#define BYPASS_POWER_DOWN_REG1              (0x3D)
+#define BYPASS_POWER_DOWN_REG2              (0x3E)
+
+
+/* dev 1Eh, reg 145h: T10 Test Conttrol Register */
+#define PD_DIS                              (1 << 15)
+#define FC_TDI_EN                           (1 << 14)
+#define FC_DI_ACT                           (1 << 13)
+#define FC_LITN_NO_COMP                     (1 << 12)
+#define FC_MDI_CO_MDIX                      (3 << 3)
+#define FC_MDI_CO_MDI                       (2 << 3)
+#define FC_MDI_CO_NOT                       (0 << 3)
+#define FC_10T_POLAR_SWAP                   (3 << 1)
+#define FC_10T_POLAR_NORMAL                 (2 << 1)
+#define FC_10T_POLAR_NOT                    (0 << 1)
+
+/* dev 1Eh, reg 14Ah: DSP control 1 Register */
+#define DSP_CONTROL_REG                     (0x14A)
+#define PICMD_MISER_MODE_INT(v)             (((v) & 0x7ff) << 5)
+
+/* dev 1Eh, reg 20Bh: DSP state machine PM control Register */
+#define DSP_FRE_PM_REG                      (0x20B)
+
+/* dev 1Eh, reg 20Eh: DSP state machine FRE control Register */
+#define DSP_FRE_REG                         (0x20E)
+#define DSP_FRE_RP_FSM_EN                   (1 << 4)
+#define DSP_FRE_DW_AUTO_INC                 (1 << 2)
+#define DSP_FRE_WR_EN                       (1 << 1)
+#define DSP_FRE_SW_RST                      (1 << 0)
+
+/* dev 1Eh, reg 2d1h: Register */
+#define RG_LPI_REG                          (0x2D1)
+#define RG_LPI_VCO_EEE_STGO_EN              (1 << 10)
+#define RG_LPI_TR_READY                     (1 << 9)
+#define RG_LPI_SKIP_SD_SLV_TR               (1 << 8)
+#define VCO_SLICER_THRES_H                  (0x33)
+
+/* dev 1Fh, reg 021h: LED Basic control Register */
+#define LED_BCR                             (0x021)
+#define LED_BCR_EXT_CTRL                    (1 << 15)
+#define LED_BCR_EVT_ALL                     (1 << 4)
+#define LED_BCR_CLK_EN                      (1 << 3)
+#define LED_BCR_TIME_TEST                   (1 << 2)
+#define LED_BCR_MODE_MASK                   (3)
+#define LED_BCR_MODE_DISABLE                (0)
+#define LED_BCR_MODE_2LED                   (1)
+#define LED_BCR_MODE_3LED_1                 (2)
+#define LED_BCR_MODE_3LED_2                 (3)
+
+/* dev 1Fh, reg 022h: LED On Duration Register */
+#define LED_ON_DUR                          (0x022)
+#define LED_ON_DUR_MASK                     (0xFFFF)
+
+/* dev 1Fh, reg 023h: LED Blinking Duration Register */
+#define LED_BLK_DUR                         (0x023)
+#define LED_BLK_DUR_MASK                    (0xFFFF)
+
+/* dev 1Fh, reg 024h: LED On Control Register */
+#define LED_ON_CTRL(i)                      (0x024 + ( (i) * 2 ))
+#define LED_ON_EN                           (1 << 15)
+#define LED_ON_POL                          (1 << 14)
+#define LED_ON_EVT_MASK                     (0x7F)
+#define LED_ON_EVT_FORCE                    (1 << 6)
+#define LED_ON_EVT_HDX                      (1 << 5)
+#define LED_ON_EVT_FDX                      (1 << 4)
+#define LED_ON_EVT_LINK_DN                  (1 << 3)
+#define LED_ON_EVT_LINK_10M                 (1 << 2)
+#define LED_ON_EVT_LINK_100M                (1 << 1)
+#define LED_ON_EVT_LINK_1000M               (1 << 0)
+
+/* dev 1Fh, reg 025h: LED Blinking Control Register */
+#define LED_BLK_CTRL(i)                     (0x025 + ( (i) * 2 ))
+#define LED_BLK_EVT_MASK                    (0x3FF)
+#define LED_BLK_EVT_FORCE                   (1 << 9)
+#define LED_BLK_EVT_RX_IDL                  (1 << 8)
+#define LED_BLK_EVT_RX_CRC                  (1 << 7)
+#define LED_BLK_EVT_CLS                     (1 << 6)
+#define LED_BLK_EVT_10M_RX_ACT              (1 << 5)
+#define LED_BLK_EVT_10M_TX_ACT              (1 << 4)
+#define LED_BLK_EVT_100M_RX_ACT             (1 << 3)
+#define LED_BLK_EVT_100M_TX_ACT             (1 << 2)
+#define LED_BLK_EVT_1000M_RX_ACT            (1 << 1)
+#define LED_BLK_EVT_1000M_TX_ACT            (1 << 0)
+
+/* dev 1Fh, reg 27Bh: 10M Driver Register */
+#define CR_RG_TX_CM_10M(val)                ( ( (val) & 0x3 ) << 12 )
+#define CR_RG_DELAY_TX_10M(val)             ( ( (val) & 0x3 ) << 8 )
+#define CR_DA_TX_GAIN_10M_EEE(val)          ( ( ( ( (val) / 10 ) - 3 ) & 0x7 ) << 4 )
+#define CR_DA_TX_GAIN_10M(val)              ( ( ( (val) / 10 ) - 3 ) & 0x7 )
+
+/* dev 1Fh, reg 403h: PLL_group Control Register */
+#define PLL_GROUP_CONTROL_REG               (0x403)
+#define RG_SYSPLL_DDSFBK_EN                 (1 << 12)
+#define RG_SYSPLL_DMY1                      (3 << 8)
+#define RG_SYSPLL_EEE_EN                    (1 << 7)    //1:enable/0:disable EEE mode when RG_SYSPLL_EEE_EN_PYPASS = 1
+#define RG_SYSPLL_EEE_EN_PYPASS             (1 << 6)    //EEE enable is control by 0:top/1:RG_SYSPLL_EEE_EN
+#define RG_SYSPLL_AFE_PWD                   (1 << 5)    //1:enable/0:disable analog power down when RG_SYSPLL_AFE_PWD_BYPASS = 1
+#define RG_SYSPLL_AFE_PWD_BYPASS            (1 << 4)    //Analog power down is control by 0:top/1:RG_SYSPLL_AFE_PWD
+#define RG_SYSPLL_EFUSE_DIS                 (1 << 3)    //1:efuse mode / 0:disable efuse mode, and use internal RG
+#define RG_CLKDRV_FORCEIN                   (3 << 1)    //analog test mode
+#define RG_XSQ_LPF_EN                       (1 << 0)    //analog test mode
+
+/* Register of ACL address */
+#define ARL_GLOBAL_CNTRL        (REG_ARL_BASE_ADDRESS + 0x00c)
+#define ACL_BASE                (REG_ARL_BASE_ADDRESS + 0x500)
+#define ACL_GLOBAL_CFG          (ACL_BASE + 0x00)
+#define ACL_PORT_EN             (ACL_BASE + 0x04)
+#define ACL_GROUP_CFG           (ACL_BASE + 0x08)
+#define ACL_MEM_CFG             (ACL_BASE + 0x0c)
+#define ACL_MEM_CFG_WDATA0      (ACL_BASE + 0x10)
+#define ACL_MEM_CFG_WDATA1      (ACL_BASE + 0x14)
+#define ACL_MEM_CFG_WDATA2      (ACL_BASE + 0x18)
+#define ACL_MEM_CFG_WDATA3      (ACL_BASE + 0x1c)
+#define ACL_MEM_CFG_RDATA0      (ACL_BASE + 0x20)
+#define ACL_MEM_CFG_RDATA1      (ACL_BASE + 0x24)
+#define ACL_MEM_CFG_RDATA2      (ACL_BASE + 0x28)
+#define ACL_MEM_CFG_RDATA3      (ACL_BASE + 0x2c)
+#define ACL_STATUS              (ACL_BASE + 0x30)
+#define ACL_TRTCM               (REG_ARL_BASE_ADDRESS + 0x100)
+#define ACL_TRTCMA              (REG_ARL_BASE_ADDRESS + 0x104)
+#define ACL_TRTCMW_CBS          (REG_ARL_BASE_ADDRESS + 0x108)
+#define ACL_TRTCMW_EBS          (REG_ARL_BASE_ADDRESS + 0x10C)
+#define ACL_TRTCMW_CIR          (REG_ARL_BASE_ADDRESS + 0x110)
+#define ACL_TRTCMW_EIR          (REG_ARL_BASE_ADDRESS + 0x114)
+#define ACL_TRTCMR_CBS          (REG_ARL_BASE_ADDRESS + 0x118)
+#define ACL_TRTCMR_EBS          (REG_ARL_BASE_ADDRESS + 0x11c)
+#define ACL_TRTCMR_CIR          (REG_ARL_BASE_ADDRESS + 0x120)
+#define ACL_TRTCMR_EIR          (REG_ARL_BASE_ADDRESS + 0x124)
+
+#define ACLRMC                  (REG_ARL_BASE_ADDRESS + 0x470)
+#define ACLRMD1                 (REG_ARL_BASE_ADDRESS + 0x474)
+#define ACLRMD2                 (REG_ARL_BASE_ADDRESS + 0x478)
+
+#define ACL_UDF_BASE            (REG_ARL_BASE_ADDRESS + 0x200)
+#define ACL_AUTC                (ACL_UDF_BASE + 0x00)
+#define ACL_AUTW0               (ACL_UDF_BASE + 0x08)
+#define ACL_AUTW1               (ACL_UDF_BASE + 0x0c)
+#define ACL_AUTW2               (ACL_UDF_BASE + 0x10)
+#define ACL_AUTR0               (ACL_UDF_BASE + 0x20)
+#define ACL_AUTR1               (ACL_UDF_BASE + 0x24)
+#define ACL_AUTR2               (ACL_UDF_BASE + 0x28)
+
+/* Register of DPCR */
+#define BMU_PORT_BASE               (0x10204000)
+#define DPCR_COLOR_OFFSET           (0x20)
+#define DPCR_QUEUE_OFFSET           (0x4)
+#define DPCR_EN(p)                  (BMU_PORT_BASE + (p * PORT_CTRL_PORT_OFFSET) + 0x08)
+#define DPCR_BASE                   (BMU_PORT_BASE + 0x10)
+#define DPCR(p, c, q)               (DPCR_BASE + (p * PORT_CTRL_PORT_OFFSET) + (c * DPCR_COLOR_OFFSET) + (q * DPCR_QUEUE_OFFSET))
+
+/* Register of VLAN */
+#define VTCR                    (0x10200600)
+#define VLNWDATA0               (0x10200604)
+#define VLNWDATA1               (0x10200608)
+#define VLNWDATA2               (0x1020060C)
+#define VLNWDATA3               (0x10200610)
+#define VLNWDATA4               (0x10200614)
+#define VLNRDATA0               (0x10200618)
+#define VLNRDATA1               (0x1020061C)
+#define VLNRDATA2               (0x10200620)
+#define VLNRDATA3               (0x10200624)
+#define VLNRDATA4               (0x10200628)
+
+/* MACRO FUNCTION DECLARATIONS
+*/
+
+/* DATA TYPE DECLARATIONS
+*/
+
+/* EXPORTED SUBPROGRAM SPECIFICATIONS
+*/
+
+#endif  /* AIR_REG_H */
diff --git a/recipes-devtools/switch/files/src/an8855_sdk/api/inc/air_sec.h b/recipes-devtools/switch/files/src/an8855_sdk/api/inc/air_sec.h
new file mode 100644
index 0000000..1f56fdd
--- /dev/null
+++ b/recipes-devtools/switch/files/src/an8855_sdk/api/inc/air_sec.h
@@ -0,0 +1,308 @@
+/* FILE NAME: air_sec.h
+ * PURPOSE:
+ *      Define the security function in AIR SDK.
+ *
+ * NOTES:
+ *      None
+ */
+
+#ifndef AIR_SEC_H
+#define AIR_SEC_H
+
+/* INCLUDE FILE DECLARATIONS
+*/
+
+/* NAMING CONSTANT DECLARATIONS
+*/
+
+/* Field for storm control */
+#define AIR_STORM_MAX_COUNT    (255)
+
+#define AIR_MAX_NUM_OF_MAC     (2048)
+
+typedef enum
+{
+    AIR_STORM_TYPE_BCST,
+    AIR_STORM_TYPE_MCST,
+    AIR_STORM_TYPE_UCST,
+    AIR_STORM_TYPE_LAST
+}AIR_STORM_TYPE_T;
+
+typedef enum
+{
+    AIR_STORM_UNIT_64K,
+    AIR_STORM_UNIT_256K,
+    AIR_STORM_UNIT_1M,
+    AIR_STORM_UNIT_4M,
+    AIR_STORM_UNIT_16M,
+    AIR_STORM_UNIT_32M,
+    AIR_STORM_UNIT_LAST
+}AIR_STORM_UNIT_T;
+
+/* Field for flooding port */
+typedef enum
+{
+    AIR_FLOOD_TYPE_BCST,
+    AIR_FLOOD_TYPE_MCST,
+    AIR_FLOOD_TYPE_UCST,
+    AIR_FLOOD_TYPE_QURY,
+    AIR_FLOOD_TYPE_LAST
+}AIR_FLOOD_TYPE_T;
+
+/* Port security port control configurations */
+typedef struct AIR_SEC_PORTSEC_PORT_CONFIG_S
+{
+    /* Source MAC address learning mode */
+    BOOL_T sa_lrn_en;
+
+    /* Learned source MAC address counter */
+    BOOL_T sa_lmt_en;
+
+    /* Rx SA allowable learning limit number */
+    UI32_T sa_lmt_cnt;
+
+}AIR_SEC_PORTSEC_PORT_CONFIG_T;
+
+/* MACRO FUNCTION DECLARATIONS
+*/
+
+/* DATA TYPE DECLARATIONS
+*/
+
+/* EXPORTED SUBPROGRAM SPECIFICATIONS
+*/
+/* FUNCTION NAME: air_sec_setStormEnable
+ * PURPOSE:
+ *      Enable or disable per port storm control for specific type.
+ *
+ * INPUT:
+ *      unit            --  Select device ID
+ *      port            --  Select port number
+ *      type            --  AIR_STORM_TYPE_BCST
+ *                          AIR_STORM_TYPE_MCST
+ *                          AIR_STORM_TYPE_UCST
+ *      storm_en        --  TRUE
+ *                          FALSE
+ * OUTPUT:
+ *      None
+ *
+ * RETURN:
+ *      AIR_E_OK
+ *      AIR_E_BAD_PARAMETER
+ *
+ * NOTES:
+ *      None
+ */
+AIR_ERROR_NO_T
+air_sec_setStormEnable(
+    const UI32_T unit,
+    const UI32_T port,
+    const AIR_STORM_TYPE_T type,
+    const BOOL_T storm_en);
+
+/* FUNCTION NAME: air_sec_getStormEnable
+ * PURPOSE:
+ *      Get per port status of storm control for specific type.
+ *
+ * INPUT:
+ *      unit            --  Select device ID
+ *      port            --  Select port number
+ *      type            --  AIR_STORM_TYPE_BCST
+ *                          AIR_STORM_TYPE_MCST
+ *                          AIR_STORM_TYPE_UCST
+ * OUTPUT:
+ *      ptr_storm_en    --  TRUE
+ *                          FALSE
+ * RETURN:
+ *      AIR_E_OK
+ *      AIR_E_BAD_PARAMETER
+ *
+ * NOTES:
+ *      None
+ */
+AIR_ERROR_NO_T
+air_sec_getStormEnable(
+    const UI32_T unit,
+    const UI32_T port,
+    const AIR_STORM_TYPE_T type,
+    BOOL_T *ptr_storm_en);
+
+/* FUNCTION NAME: air_sec_setStormRate
+ * PURPOSE:
+ *      Set per port storm rate limit control for specific type.
+ *
+ * INPUT:
+ *      unit            --  Select device ID
+ *      port            --  Select port number
+ *      type            --  AIR_STORM_TYPE_BCST
+ *                          AIR_STORM_TYPE_MCST
+ *                          AIR_STORM_TYPE_UCST
+ *      count           --  Count of the unit
+ *                          Range 0..255
+ *                          Rate = (count * unit) bps
+ *      unit            --  AIR_STORM_UNIT_64K
+ *                          AIR_STORM_UNIT_256K
+ *                          AIR_STORM_UNIT_1M
+ *                          AIR_STORM_UNIT_4M
+ *                          AIR_STORM_UNIT_16M
+ *                          AIR_STORM_UNIT_32M
+ * OUTPUT:
+ *      None
+ *
+ * RETURN:
+ *      AIR_E_OK
+ *      AIR_E_BAD_PARAMETER
+ *
+ * NOTES:
+ *      None
+ */
+AIR_ERROR_NO_T
+air_sec_setStormRate(
+    const UI32_T unit,
+    const UI32_T port,
+    const AIR_STORM_TYPE_T type,
+    const UI32_T count,
+    const AIR_STORM_UNIT_T storm_unit);
+
+/* FUNCTION NAME: air_sec_getStormRate
+ * PURPOSE:
+ *      Get per port storm rate limit control for specific type.
+ *
+ * INPUT:
+ *      unit            --  Select device ID
+ *      port            --  Select port number
+ *      type            --  AIR_STORM_TYPE_BCST
+ *                          AIR_STORM_TYPE_MCST
+ *                          AIR_STORM_TYPE_UCST
+ * OUTPUT:
+ *      ptr_count       --  Count of the unit
+ *                          Range 0..255
+ *                          Rate = (count * unit) bps
+ *      ptr_unit        --  AIR_STORM_UNIT_64K
+ *                          AIR_STORM_UNIT_256K
+ *                          AIR_STORM_UNIT_1M
+ *                          AIR_STORM_UNIT_4M
+ *                          AIR_STORM_UNIT_16M
+ *                          AIR_STORM_UNIT_32M
+ * RETURN:
+ *      AIR_E_OK
+ *      AIR_E_BAD_PARAMETER
+ *
+ * NOTES:
+ *      None
+ */
+AIR_ERROR_NO_T
+air_sec_getStormRate(
+    const UI32_T unit,
+    const UI32_T port,
+    const AIR_STORM_TYPE_T type,
+    UI32_T *ptr_count,
+    AIR_STORM_UNIT_T *ptr_unit);
+
+/* FUNCTION NAME: air_sec_setFldMode
+ * PURPOSE:
+ *      Set per port flooding status for unknown type frame.
+ *
+ * INPUT:
+ *      unit            --  Select device ID
+ *      port            --  Select port to setting
+ *      type            --  AIR_FLOOD_TYPE_BCST
+ *                          AIR_FLOOD_TYPE_MCST
+ *                          AIR_FLOOD_TYPE_UCST
+ *                          AIR_FLOOD_TYPE_QURY
+ *      fld_en          --  TRUE : flooding specific type frame for specific port
+ *                          FALSE: drop specific type frame for specific port
+ * OUTPUT:
+ *      None
+ *
+ * RETURN:
+ *      AIR_E_OK
+ *      AIR_E_BAD_PARAMETER
+ * NOTES:
+ *      None
+ */
+AIR_ERROR_NO_T
+air_sec_setFldMode(
+    const UI32_T unit,
+    const UI32_T port,
+    const AIR_FLOOD_TYPE_T type,
+    const BOOL_T fld_en);
+
+/* FUNCTION NAME: air_sec_getFldMode
+ * PURPOSE:
+ *      Get per port flooding status for unknown type frame.
+ *
+ * INPUT:
+ *      unit            --  Select device ID
+ *      port            --  Select port to setting
+ *      type            --  AIR_FLOOD_TYPE_BCST
+ *                          AIR_FLOOD_TYPE_MCST
+ *                          AIR_FLOOD_TYPE_UCST
+ *                          AIR_FLOOD_TYPE_QURY
+ * OUTPUT:
+ *      ptr_fld_en      --  TRUE : flooding specific type frame for specific port
+ *                          FALSE: drop specific type frame for specific port
+ * RETURN:
+ *      AIR_E_OK
+ *      AIR_E_BAD_PARAMETER
+ *
+ * NOTES:
+ *      None
+ */
+AIR_ERROR_NO_T
+air_sec_getFldMode(
+    const UI32_T unit,
+    const UI32_T port,
+    const AIR_FLOOD_TYPE_T type,
+    BOOL_T *ptr_fld_en);
+
+/* FUNCTION NAME: air_sec_setPortSecPortCfg
+ * PURPOSE:
+ *      Set port security configurations for specific port.
+ *
+ * INPUT:
+ *      unit            --  Device ID
+ *      port            --  Port ID
+ *      port_config     --  Structure of port configuration.
+ *
+ * OUTPUT:
+ *      None
+ *
+ * RETURN:
+ *      AIR_E_OK
+ *      AIR_E_BAD_PARAMETER
+ *
+ * NOTES:
+ *      None
+ */
+AIR_ERROR_NO_T
+air_sec_setPortSecPortCfg(
+    const UI32_T unit,
+    const UI32_T port,
+    const AIR_SEC_PORTSEC_PORT_CONFIG_T port_config);
+
+/* FUNCTION NAME: air_sec_getPortSecPortCfg
+ * PURPOSE:
+ *      Get port security configurations for specific port.
+ *
+ * INPUT:
+ *      unit            --  Device ID
+ *      port            --  Port ID
+ *
+ * OUTPUT:
+ *      ptr_port_config --  Structure of port configuration.
+ *
+ * RETURN:
+ *      AIR_E_OK
+ *      AIR_E_BAD_PARAMETER
+ *
+ * NOTES:
+ *      None
+ */
+AIR_ERROR_NO_T
+air_sec_getPortSecPortCfg(
+    const UI32_T unit,
+    const UI32_T port,
+    AIR_SEC_PORTSEC_PORT_CONFIG_T *ptr_port_config);
+
+#endif /* End of AIR_SEC_H */
diff --git a/recipes-devtools/switch/files/src/an8855_sdk/api/inc/air_sptag.h b/recipes-devtools/switch/files/src/an8855_sdk/api/inc/air_sptag.h
new file mode 100644
index 0000000..99d2028
--- /dev/null
+++ b/recipes-devtools/switch/files/src/an8855_sdk/api/inc/air_sptag.h
@@ -0,0 +1,277 @@
+/* FILE NAME: air_sptag.h
+ * PURPOSE:
+ *      Define the Special Tag function in AIR SDK.
+ *
+ * NOTES:
+ *      None
+ */
+
+#ifndef AIR_SPTAG_H
+#define AIR_SPTAG_H
+
+/* INCLUDE FILE DECLARATIONS
+*/
+
+/* NAMING CONSTANT DECLARATIONS
+*/
+
+#define AIR_STAG_BUF_LEN                (4)
+#define AIR_STAG_ALIGN_BIT_WIDTH        (8)
+#define AIR_STAG_REPLACE_MODE_MAX_DP    (10)
+
+/* cpu tx stag offset */
+#define AIR_STAG_TX_OPC_BIT_OFFSET      (5)
+#define AIR_STAG_TX_OPC_BIT_WIDTH       (3)
+#define AIR_STAG_TX_VPM_BIT_OFFSET      (0)
+#define AIR_STAG_TX_VPM_BIT_WIDTH       (2)
+#define AIR_STAG_TX_PCP_BIT_OFFSET      (5)
+#define AIR_STAG_TX_PCP_BIT_WIDTH       (3)
+#define AIR_STAG_TX_DEI_BIT_OFFSET      (4)
+#define AIR_STAG_TX_DEI_BIT_WIDTH       (1)
+
+/* cpu rx stag offset */
+#define AIR_STAG_RX_RSN_BIT_OFFSET      (2)
+#define AIR_STAG_RX_RSN_BIT_WIDTH       (3)
+#define AIR_STAG_RX_VPM_BIT_OFFSET      (0)
+#define AIR_STAG_RX_VPM_BIT_WIDTH       (2)
+#define AIR_STAG_RX_SP_BIT_OFFSET       (0)
+#define AIR_STAG_RX_SP_BIT_WIDTH        (5)
+#define AIR_STAG_RX_PCP_BIT_OFFSET      (5)
+#define AIR_STAG_RX_PCP_BIT_WIDTH       (3)
+#define AIR_STAG_RX_DEI_BIT_OFFSET      (4)
+#define AIR_STAG_RX_DEI_BIT_WIDTH       (1)
+#define AIR_PORT_NUM                    (6)
+
+#define AIR_PORT_FOREACH(bitmap, port)                 \
+            for(port = 0; port < AIR_PORT_NUM; port++) \
+                if(bitmap & BIT(port))
+
+
+/* MACRO FUNCTION DECLARATIONS
+*/
+
+/* DATA TYPE DECLARATIONS
+*/
+typedef enum
+{
+    AIR_STAG_MODE_INSERT,
+    AIR_STAG_MODE_REPLACE,
+    AIR_STAG_MODE_LAST
+} AIR_STAG_MODE_T;
+
+typedef enum
+{
+    /* Egress DP is port map */
+    AIR_STAG_OPC_PORTMAP,
+
+    /* Egress DP is port id */
+    AIR_STAG_OPC_PORTID,
+
+    /* Forward the packet according to lookup result */
+    AIR_STAG_OPC_LOOKUP,
+    AIR_STAG_OPC_LAST
+} AIR_STAG_OPC_T;
+
+typedef enum
+{
+    AIR_STAG_REASON_CODE_NORMAL,
+    AIR_STAG_REASON_CODE_SFLOW,
+    AIR_STAG_REASON_CODE_TTL_ERR,
+    AIR_STAG_REASON_CODE_ACL,
+    AIR_STAG_REASON_CODE_SA_FULL,
+    AIR_STAG_REASON_CODE_PORT_MOVE_ERR,
+    AIR_STAG_REASON_CODE_LAST,
+} AIR_STAG_REASON_CODE_T;
+
+typedef enum
+{
+    AIR_STAG_VPM_UNTAG,
+    AIR_STAG_VPM_TPID_8100,
+    AIR_STAG_VPM_TPID_88A8,
+    AIR_STAG_VPM_TPID_PRE_DEFINED,
+    AIR_STAG_VPM_LAST,
+} AIR_STAG_VPM_T;
+
+typedef struct AIR_STAG_TX_PARA_S
+{
+    /* destination port operation code */
+    AIR_STAG_OPC_T      opc;
+
+    /* tag attribute */
+    AIR_STAG_VPM_T      vpm;
+
+    /* destination port map */
+    UI32_T              pbm;
+
+    /* PRI in vlan tag */
+    UI32_T              pri :3;
+
+    /* CFI in vlan tag */
+    UI32_T              cfi :1;
+
+    /* VID in vlan tag */
+    UI32_T              vid :12;
+} AIR_STAG_TX_PARA_T;
+
+
+typedef struct AIR_SPTAG_RX_PARA_S
+{
+    AIR_STAG_REASON_CODE_T rsn;        /* tag attribute */
+    AIR_STAG_VPM_T         vpm;        /* tag attribute */
+    UI32_T                 spn;        /* source port */
+    UI32_T                 pri;        /* PRI in vlan tag */
+    UI32_T                 cfi;        /* CFI in vlan tag */
+    UI32_T                 vid;        /* VID in vlan tag */
+}AIR_SPTAG_RX_PARA_T;
+
+/* EXPORTED SUBPROGRAM SPECIFICATIONS
+*/
+/* FUNCTION NAME: air_sptag_setState
+ * PURPOSE:
+ *      Set special tag enable/disable for port
+ *
+ * INPUT:
+ *      unit            --  Device ID
+ *      port            --  Special tag Port
+ *      sp_en           --  special tag Enable or Disable
+ *
+ * OUTPUT:
+ *      None
+ *
+ * RETURN:
+ *      AIR_E_OK
+ *      AIR_E_BAD_PARAMETER
+ *
+ * NOTES:
+ *      None
+ */
+AIR_ERROR_NO_T
+air_sptag_setState(
+    const UI32_T unit,
+    const UI32_T port,
+    const BOOL_T sp_en);
+
+/* FUNCTION NAME: air_switch_getCpuPortEn
+ * PURPOSE:
+ *      Get CPU port member
+ *
+ * INPUT:
+ *      unit            --  Device ID
+ *      port            --  Special tag Port
+ *
+ * OUTPUT:
+ *      sp_en           --  special tag enable or disable
+ *
+ * RETURN:
+ *      AIR_E_OK
+ *      AIR_E_BAD_PARAMETER
+ *
+ * NOTES:
+ *      None
+ */
+AIR_ERROR_NO_T
+air_sptag_getState(
+    const UI32_T unit,
+    const UI32_T port,
+    BOOL_T *sp_en);
+
+/* FUNCTION NAME: air_sptag_setMode
+ * PURPOSE:
+ *      Set special tag enable/disable for port
+ *
+ * INPUT:
+ *      unit            --  Device ID
+ *      port            --  Special tag Port
+ *      mode            --  insert mode or replace mode
+ *
+ * OUTPUT:
+ *      None
+ *
+ * RETURN:
+ *      AIR_E_OK
+ *      AIR_E_BAD_PARAMETER
+ *
+ * NOTES:
+ *      None
+ */
+AIR_ERROR_NO_T
+air_sptag_setMode(
+    const UI32_T unit,
+    const UI32_T port,
+    const BOOL_T mode);
+
+/* FUNCTION NAME: air_sptag_getMode
+ * PURPOSE:
+ *      Get CPU port member
+ *
+ * INPUT:
+ *      unit            --  Device ID
+ *      port            --  Special tag Port
+ *
+ * OUTPUT:
+ *      mode            --  insert or replace mode
+ *
+ * RETURN:
+ *      AIR_E_OK
+ *      AIR_E_BAD_PARAMETER
+ *
+ * NOTES:
+ *      None
+ */
+AIR_ERROR_NO_T
+air_sptag_getMode(
+    const UI32_T unit,
+    const UI32_T port,
+    BOOL_T *mode);
+
+/* FUNCTION NAME: air_sptag_encodeTx
+ * PURPOSE:
+ *      Encode tx special tag into buffer.
+ * INPUT:
+ *      unit            --  Device ID
+ *      ptr_sptag_tx    --  Special tag parameters
+ *      ptr_buf         --  Buffer address
+ *      ptr_len         --  Buffer length
+ * OUTPUT:
+ *      ptr_len         --  Written buffer length
+ *
+ * RETURN:
+ *      AIR_E_OK
+ *      AIR_E_BAD_PARAMETER
+ *
+ * NOTES:
+ *      None
+ */
+AIR_ERROR_NO_T
+air_sptag_encodeTx(
+    const UI32_T unit,
+    const AIR_STAG_MODE_T mode,
+    AIR_STAG_TX_PARA_T *ptr_sptag_tx,
+    UI8_T *ptr_buf,
+    UI32_T *ptr_len);
+
+/* FUNCTION NAME: air_sptag_decodeRx
+ * PURPOSE:
+ *      Decode rx special tag from buffer.
+ * INPUT:
+ *      unit            --  Device ID
+ *      ptr_buf         --  Buffer address
+ *      len             --  Buffer length
+ * OUTPUT:
+ *      ptr_sptag_rx    --  Special tag parameters
+ *
+ * RETURN:
+ *      AIR_E_OK
+ *      AIR_E_BAD_PARAMETER
+ *
+ * NOTES:
+ *      None
+ */
+AIR_ERROR_NO_T
+air_sptag_decodeRx(
+    const UI32_T unit,
+    const UI8_T *ptr_buf,
+    const UI32_T len,
+    AIR_SPTAG_RX_PARA_T *ptr_sptag_rx);
+
+#endif  /* AIR_SPTAG_H */
diff --git a/recipes-devtools/switch/files/src/an8855_sdk/api/inc/air_stp.h b/recipes-devtools/switch/files/src/an8855_sdk/api/inc/air_stp.h
new file mode 100644
index 0000000..2497392
--- /dev/null
+++ b/recipes-devtools/switch/files/src/an8855_sdk/api/inc/air_stp.h
@@ -0,0 +1,101 @@
+/* FILE NAME: air_stp.h
+ * PURPOSE:
+ *      Define the STP function in AIR SDK.
+ *
+ * NOTES:
+ *      None
+ */
+
+#ifndef AIR_STP_H
+#define AIR_STP_H
+
+/* INCLUDE FILE DECLARATIONS
+*/
+
+/* NAMING CONSTANT DECLARATIONS
+*/
+
+/* Definition of STP state
+ * 2'b00: Disable(STP)    / Discard(RSTP)
+ * 2'b01: Listening(STP)  / Discard(RSTP)
+ * 2'b10: Learning(STP)   / Learning(RSTP)
+ * 2'b11: Forwarding(STP) / Forwarding(RSTP)
+ * */
+typedef enum
+{
+    AIR_STP_STATE_DISABLE,
+    AIR_STP_STATE_LISTEN,
+    AIR_STP_STATE_LEARN,
+    AIR_STP_STATE_FORWARD,
+    AIR_STP_STATE_LAST
+}AIR_STP_STATE_T;
+
+#define AIR_STP_FID_NUMBER    (16)
+
+/* MACRO FUNCTION DECLARATIONS
+*/
+
+/* DATA TYPE DECLARATIONS
+*/
+
+/* EXPORTED SUBPROGRAM SPECIFICATIONS
+*/
+/* FUNCTION NAME: air_stp_setPortstate
+ * PURPOSE:
+ *      Set the STP port state for a specifiec port.
+ *
+ * INPUT:
+ *      unit            --  Device ID
+ *      port            --  Index of port number
+ *      fid             --  Filter ID for MSTP
+ *      state           --  AIR_STP_STATE_DISABLE
+ *                          AIR_STP_STATE_LISTEN
+ *                          AIR_STP_STATE_LEARN
+ *                          AIR_STP_STATE_FORWARD
+ * OUTPUT:
+ *        None
+ *
+ * RETURN:
+ *        AIR_E_OK
+ *        AIR_E_BAD_PARAMETER
+ *
+ * NOTES:
+ *      None
+ */
+AIR_ERROR_NO_T
+air_stp_setPortstate(
+    const UI32_T unit,
+    const UI8_T port,
+    const UI8_T fid,
+    const AIR_STP_STATE_T state);
+
+/* FUNCTION NAME: air_stp_getPortstate
+ * PURPOSE:
+ *      Get the STP port state for a specifiec port.
+ *
+ * INPUT:
+ *      unit            --  Device ID
+ *      port            --  Index of port number
+ *      fid             --  Filter ID for MSTP
+ *
+ * OUTPUT:
+ *      ptr_state       --  AIR_STP_STATE_DISABLE
+ *                          AIR_STP_STATE_LISTEN
+ *                          AIR_STP_STATE_LEARN
+ *                          AIR_STP_STATE_FORWARD
+ * RETURN:
+ *        AIR_E_OK
+ *        AIR_E_BAD_PARAMETER
+ *
+ * NOTES:
+ *      None
+ */
+
+AIR_ERROR_NO_T
+air_stp_getPortstate(
+    const UI32_T unit,
+    const UI32_T port,
+    const UI32_T fid,
+    AIR_STP_STATE_T *ptr_state);
+
+#endif /* End of AIR_STP_H */
diff --git a/recipes-devtools/switch/files/src/an8855_sdk/api/inc/air_switch.h b/recipes-devtools/switch/files/src/an8855_sdk/api/inc/air_switch.h
new file mode 100644
index 0000000..0c10cc4
--- /dev/null
+++ b/recipes-devtools/switch/files/src/an8855_sdk/api/inc/air_switch.h
@@ -0,0 +1,250 @@
+/* FILE NAME: air_switch.h
+ * PURPOSE:
+ *      Define the switch function in AIR SDK.
+ *
+ * NOTES:
+ *      None
+ */
+
+#ifndef AIR_SWITCH_H
+#define AIR_SWITCH_H
+
+/* INCLUDE FILE DECLARATIONS
+*/
+
+/* NAMING CONSTANT DECLARATIONS
+*/
+
+/* MACRO FUNCTION DECLARATIONS
+*/
+#define SYS_INT_EN                 0x1021C010
+#define SYS_INT_STS                0x1021C014
+
+/* DATA TYPE DECLARATIONS
+*/
+typedef enum
+{
+    AIR_SYS_INTR_TYPE_PHY0_LC = 0,
+    AIR_SYS_INTR_TYPE_PHY1_LC,
+    AIR_SYS_INTR_TYPE_PHY2_LC,
+    AIR_SYS_INTR_TYPE_PHY3_LC,
+    AIR_SYS_INTR_TYPE_PHY4_LC,
+    AIR_SYS_INTR_TYPE_PHY5_LC,
+    AIR_SYS_INTR_TYPE_PHY6_LC,
+    AIR_SYS_INTR_TYPE_PHY7_LC,
+    AIR_SYS_INTR_TYPE_MAC_PC = 16,
+    AIR_SYS_INTR_TYPE_LAST
+}AIR_SYS_INTR_TYPE_T;
+
+/* EXPORTED SUBPROGRAM SPECIFICATIONS
+*/
+
+/* FUNCTION NAME: air_switch_setCpuPort
+ * PURPOSE:
+ *      Set CPU port member
+ *
+ * INPUT:
+ *      unit            --  Device ID
+ *      port            --  CPU port index
+ *
+ * OUTPUT:
+ *      None
+ *
+ * RETURN:
+ *      AIR_E_OK
+ *      AIR_E_BAD_PARAMETER
+ *
+ * NOTES:
+ *      None
+ */
+AIR_ERROR_NO_T
+air_switch_setCpuPort(
+    const UI32_T unit,
+    const UI32_T portmap);
+
+/* FUNCTION NAME: air_switch_getCpuPort
+ * PURPOSE:
+ *      Get CPU port member
+ *
+ * INPUT:
+ *      unit            --  Device ID
+ *
+ * OUTPUT:
+ *      ptr_port        --  CPU port index
+ *
+ * RETURN:
+ *      AIR_E_OK
+ *      AIR_E_BAD_PARAMETER
+ *
+ * NOTES:
+ *      None
+ */
+AIR_ERROR_NO_T
+air_switch_getCpuPort(
+    const UI32_T unit,
+    UI32_T *ptr_portmap);
+
+/* FUNCTION NAME: air_switch_setCpuPortEN
+ * PURPOSE:
+ *      Set CPU port Enable
+ *
+ * INPUT:
+ *      unit            --  Device ID
+ *      cpu_en          --  CPU Port Enable
+ *
+ * OUTPUT:
+ *      None
+ *
+ * RETURN:
+ *      AIR_E_OK
+ *      AIR_E_BAD_PARAMETER
+ *
+ * NOTES:
+ *      None
+ */
+AIR_ERROR_NO_T
+air_switch_setCpuPortEn(
+    const UI32_T unit,
+    const BOOL_T cpu_en);
+
+/* FUNCTION NAME: air_switch_getCpuPortEn
+ * PURPOSE:
+ *      Get CPU port member
+ *
+ * INPUT:
+ *      unit            --  Device ID
+ *
+ * OUTPUT:
+ *      cpu_en          --  CPU Port enable
+ *
+ * RETURN:
+ *      AIR_E_OK
+ *      AIR_E_BAD_PARAMETER
+ *
+ * NOTES:
+ *      None
+ */
+AIR_ERROR_NO_T
+air_switch_getCpuPortEn(
+    const UI32_T unit,
+    BOOL_T *cpu_en);
+
+/* FUNCTION NAME: air_switch_setSysIntrEn
+ * PURPOSE:
+ *      Set system interrupt enable
+ *
+ * INPUT:
+ *      unit            --  Device ID
+ *      intr            --  system interrupt type
+ *      enable          --  system interrupt enable/disable
+ *
+ * OUTPUT:
+ *      None
+ *
+ * RETURN:
+ *      AIR_E_OK
+ *      AIR_E_BAD_PARAMETER
+ *
+ * NOTES:
+ *      None
+ */
+AIR_ERROR_NO_T
+air_switch_setSysIntrEn(
+    const UI32_T unit,
+    const AIR_SYS_INTR_TYPE_T intr,
+    const BOOL_T enable);
+
+/* FUNCTION NAME: air_switch_getSysIntrEn
+ * PURPOSE:
+ *      Get system interrupt enable
+ *
+ * INPUT:
+ *      unit            --  Device ID
+ *      intr            --  system interrupt type
+ *
+ * OUTPUT:
+ *      ptr_enable      --  system interrupt enable/disable
+ *
+ * RETURN:
+ *      AIR_E_OK
+ *      AIR_E_BAD_PARAMETER
+ *
+ * NOTES:
+ *      None
+ */
+AIR_ERROR_NO_T
+air_switch_getSysIntrEn(
+    const UI32_T unit,
+    const AIR_SYS_INTR_TYPE_T intr,
+    BOOL_T *ptr_enable);
+
+/* FUNCTION NAME: air_switch_setSysIntrStatus
+ * PURPOSE:
+ *      Set system interrupt status
+ *
+ * INPUT:
+ *      unit            --  Device ID
+ *      intr            --  system interrupt type
+ *      enable          --  write TRUE to clear interrupt status
+ *
+ * OUTPUT:
+ *      None
+ *
+ * RETURN:
+ *      AIR_E_OK
+ *      AIR_E_BAD_PARAMETER
+ *
+ * NOTES:
+ *      None
+ */
+AIR_ERROR_NO_T
+air_switch_setSysIntrStatus(
+    const UI32_T unit,
+    const AIR_SYS_INTR_TYPE_T intr,
+    const BOOL_T enable);
+
+/* FUNCTION NAME: air_switch_getSysIntrStatus
+ * PURPOSE:
+ *      Get system interrupt status
+ *
+ * INPUT:
+ *      unit            --  Device ID
+ *      intr            --  system interrupt type
+ *
+ * OUTPUT:
+ *      ptr_enable      --  system interrupt status
+ *
+ * RETURN:
+ *      AIR_E_OK
+ *      AIR_E_BAD_PARAMETER
+ *
+ * NOTES:
+ *      None
+ */
+AIR_ERROR_NO_T
+air_switch_getSysIntrStatus(
+    const UI32_T unit,
+    const AIR_SYS_INTR_TYPE_T intr,
+    BOOL_T *ptr_enable);
+
+/* FUNCTION NAME: air_switch_reset
+ * PURPOSE:
+ *      Reset whole system
+ *
+ * INPUT:
+ *      None
+ *
+ * OUTPUT:
+ *      None
+ *
+ * RETURN:
+ *      AIR_E_OK
+ *
+ * NOTES:
+ *      None
+ */
+AIR_ERROR_NO_T
+air_switch_reset(
+    const UI32_T unit);
+
+#endif /* End of AIR_SWITCH_H */
diff --git a/recipes-devtools/switch/files/src/an8855_sdk/api/inc/air_types.h b/recipes-devtools/switch/files/src/an8855_sdk/api/inc/air_types.h
new file mode 100644
index 0000000..3bae3bd
--- /dev/null
+++ b/recipes-devtools/switch/files/src/an8855_sdk/api/inc/air_types.h
@@ -0,0 +1,56 @@
+/* FILE NAME:   air_types.h
+ * PURPOSE:
+ *      Define the commom data type in AIR SDK.
+ * NOTES:
+ */
+
+#ifndef AIR_TYPES_H
+#define AIR_TYPES_H
+
+/* INCLUDE FILE DECLARATIONS
+ */
+
+/* NAMING CONSTANT DECLARATIONS
+ */
+#ifndef FALSE
+#define FALSE               0
+#endif
+
+#ifndef TRUE
+#define TRUE                1
+#endif
+
+#ifndef NULL
+#define NULL                (void *)0
+#endif
+
+#ifndef LOW
+#define LOW                 0
+#endif
+
+#ifndef HIGH
+#define HIGH                1
+#endif
+
+/* MACRO FUNCTION DECLARATIONS
+ */
+
+/* DATA TYPE DECLARATIONS
+ */
+typedef int                 BOOL_T;
+typedef signed char         I8_T;
+typedef unsigned char       UI8_T;
+typedef signed short        I16_T;
+typedef unsigned short      UI16_T;
+typedef signed int          I32_T;
+typedef unsigned int        UI32_T;
+typedef char                C8_T;
+typedef unsigned long long  UI64_T;
+
+typedef UI8_T   AIR_MAC_T[6];
+
+/* EXPORTED SUBPROGRAM SPECIFICATIONS
+ */
+
+#endif  /* AIR_TYPES_H */
+
diff --git a/recipes-devtools/switch/files/src/an8855_sdk/api/inc/air_ver.h b/recipes-devtools/switch/files/src/an8855_sdk/api/inc/air_ver.h
new file mode 100644
index 0000000..0681b6c
--- /dev/null
+++ b/recipes-devtools/switch/files/src/an8855_sdk/api/inc/air_ver.h
@@ -0,0 +1,29 @@
+/* FILE NAME: air_ver.h

+ * PURPOSE:

+ *      Define the version for AIR SDK.

+ *

+ * NOTES:

+ *      None

+ */

+

+#ifndef AIR_VER_H

+#define AIR_VER_H

+

+/* INCLUDE FILE DECLARATIONS

+ */

+

+/* NAMING CONSTANT DECLARATIONS

+ */

+#define AIR_VER_SDK    "v1.0.1"

+

+/* MACRO FUNCTION DECLARATIONS

+ */

+

+/* DATA TYPE DECLARATIONS

+ */

+

+/* EXPORTED SUBPROGRAM SPECIFICATIONS

+ */

+

+#endif  /* AIR_VER_H */

+

diff --git a/recipes-devtools/switch/files/src/an8855_sdk/api/inc/air_vlan.h b/recipes-devtools/switch/files/src/an8855_sdk/api/inc/air_vlan.h
new file mode 100644
index 0000000..1ae6237
--- /dev/null
+++ b/recipes-devtools/switch/files/src/an8855_sdk/api/inc/air_vlan.h
@@ -0,0 +1,977 @@
+/* FILE NAME:   air_vlan.h

+ * PURPOSE:

+ *      Define the vlan functions in AIR SDK.

+ * NOTES:

+ */

+

+#ifndef AIR_VLAN_H

+#define AIR_VLAN_H

+

+/* INCLUDE FILE DECLARATIONS

+ */

+

+/* NAMING CONSTANT DECLARATIONS

+ */

+#define AIR_VLAN_ID_MIN                             0

+#define AIR_VLAN_ID_MAX                             4095

+#define AIR_DEFAULT_VLAN_ID                         1

+

+#define AIR_FILTER_ID_MAX                           7

+

+/* MACRO FUNCTION DECLARATIONS

+ */

+

+/* DATA TYPE DECLARATIONS

+ */

+typedef enum

+{

+    AIR_VLAN_PORT_EGS_TAG_CTL_TYPE_UNTAGGED = 0,

+    AIR_VLAN_PORT_EGS_TAG_CTL_TYPE_TAGGED = 2,

+    AIR_VLAN_PORT_EGS_TAG_CTL_TYPE_LAST,

+} AIR_VLAN_PORT_EGS_TAG_CTL_TYPE_T;

+

+typedef enum

+{

+    AIR_PORT_EGS_TAG_ATTR_UNTAGGED = 0,

+    AIR_PORT_EGS_TAG_ATTR_SWAP,

+    AIR_PORT_EGS_TAG_ATTR_TAGGED,

+    AIR_PORT_EGS_TAG_ATTR_STACK,

+    AIR_PORT_EGS_TAG_ATTR_LAST

+} AIR_PORT_EGS_TAG_ATTR_T;

+

+typedef enum

+{

+    AIR_VLAN_ACCEPT_FRAME_TYPE_ALL = 0,            /* untagged, priority-tagged and tagged  */

+    AIR_VLAN_ACCEPT_FRAME_TYPE_TAG_ONLY,           /* tagged                                */

+    AIR_VLAN_ACCEPT_FRAME_TYPE_UNTAG_ONLY,         /* untagged and priority-tagged          */

+    AIR_VLAN_ACCEPT_FRAME_TYPE_RESERVED,           /* reserved                              */

+    AIR_VLAN_ACCEPT_FRAME_TYPE_LAST

+} AIR_VLAN_ACCEPT_FRAME_TYPE_T;

+

+typedef enum

+{

+    AIR_LEAKY_PKT_TYPE_UNICAST = 0,                /* unicast pkt      */

+    AIR_LEAKY_PKT_TYPE_MULTICAST,                  /* multicast pkt    */

+    AIR_LEAKY_PKT_TYPE_BROADCAST,                  /* broadcast pkt    */

+    AIR_LEAKY_PKT_TYPE_LAST

+} AIR_LEAKY_PKT_TYPE_T;

+

+typedef enum

+{

+    AIR_VLAN_PORT_ATTR_USER_PORT = 0,              /* user port        */

+    AIR_VLAN_PORT_ATTR_STACK_PORT,                 /* stack port       */

+    AIR_VLAN_PORT_ATTR_TRANSLATION_PORT,           /* translation port */

+    AIR_VLAN_PORT_ATTR_TRANSPARENT_PORT,           /* transparent port */

+    AIR_VLAN_PORT_ATTR_LAST

+} AIR_VLAN_PORT_ATTR_T;

+

+typedef enum

+{

+    AIR_IGR_PORT_EG_TAG_ATTR_DISABLE = 0,

+    AIR_IGR_PORT_EG_TAG_ATTR_CONSISTENT,

+    AIR_IGR_PORT_EG_TAG_ATTR_UNTAGGED = 4,

+    AIR_IGR_PORT_EG_TAG_ATTR_SWAP,

+    AIR_IGR_PORT_EG_TAG_ATTR_TAGGED,

+    AIR_IGR_PORT_EG_TAG_ATTR_STACK,

+    AIR_IGR_PORT_EG_TAG_ATTR_LAST

+} AIR_IGR_PORT_EG_TAG_ATTR_T;

+

+typedef union AIR_VLAN_ENTRY_S

+{

+    UI8_T valid : 1;

+    struct

+    {

+        UI32_T  vlan_table0;

+        UI32_T  vlan_table1;

+    } vlan_table;

+    struct

+    {

+        UI64_T   valid             : 1;

+        UI64_T   fid               : 4;

+        UI64_T   ivl               : 1;

+        UI64_T   copy_pri          : 1;

+        UI64_T   user_pri          : 3;

+        UI64_T   eg_ctrl_en        : 1;

+        UI64_T   eg_con            : 1;

+        UI64_T   eg_ctrl           : 14;

+        UI64_T   port_mem          : 7;

+        UI64_T   port_stag         : 1;

+        UI64_T   stag              : 12;

+        UI64_T   unm_vlan_drop     : 1;

+    } vlan_entry_format;

+} AIR_VLAN_ENTRY_T;

+

+typedef union AIR_VLAN_ENTRY_ATTR_S

+{

+    UI8_T valid : 1;

+    struct

+    {

+        UI32_T  vlan_table0;

+        UI32_T  vlan_table1;

+        UI32_T  vlan_table2;

+        UI32_T  vlan_table3;

+        UI32_T  vlan_table4;

+    } vlan_table;

+    struct

+    {

+        UI64_T   valid             : 1;

+        UI64_T   fid               : 4;

+        UI64_T   ivl               : 1;

+        UI64_T   copy_pri          : 1;

+        UI64_T   user_pri          : 3;

+        UI64_T   eg_ctrl_en        : 1;

+        UI64_T   eg_con            : 1;

+        UI64_T   eg_ctrl           : 14;

+        UI64_T   port_mem          : 7;

+        UI64_T   port_stag         : 1;

+        UI64_T   stag              : 12;

+        UI64_T   unm_vlan_drop     : 1;

+    } vlan_entry_format;

+#if 0

+    struct

+    {

+        UI64_T   valid             : 1;

+        UI64_T   type              : 3;

+        UI64_T   mac_addr          : 48;

+        UI64_T   mac_mask_len      : 6;

+        UI64_T   priority          : 3;

+        UI64_T   :0;

+        UI64_T   vid               : 12;

+    } mac_based_vlan_entry_format;

+    struct

+    {

+        UI64_T   valid             : 1;

+        UI64_T   type              : 3;

+        UI64_T   check_field       : 36;

+        UI64_T   :0;

+        UI64_T   check_field_mask  : 36;

+        UI64_T   untagged_packet   : 1;

+        UI64_T   vlan_priority     : 3;

+        UI64_T   svid              : 12;

+    } qinq_based_vlan_entry_format;

+    struct

+    {

+        UI64_T   valid             : 1;

+        UI64_T   type              : 3;

+        UI64_T   ipv4              : 32;

+        UI64_T   :0;

+        UI64_T   subnetmask        : 32;

+        UI64_T   priority          : 3;

+        UI64_T   cvid              : 12;

+    } ipv4_based_vlan_entry_format;

+    struct

+    {

+        UI64_T   valid             : 1;

+        UI64_T   :0;

+        UI64_T   ipv6_high         : 64;

+        UI64_T   ipv6_low          : 64;

+        UI64_T   subnetmask        : 8;

+        UI64_T   priority          : 3;

+        UI64_T   cvid              : 12;

+    } ipv6_based_vlan_entry_format;

+#endif

+} AIR_VLAN_ENTRY_ATTR_T;

+

+void

+_air_vlan_readEntry(

+    const UI32_T unit,

+    const UI16_T vid,

+    AIR_VLAN_ENTRY_T* vlan_entry);

+

+void

+_air_vlan_writeEntry(

+    const UI32_T unit,

+    const UI16_T vid,

+    AIR_VLAN_ENTRY_T* vlan_entry);

+

+void

+_air_untagged_vlan_readEntry(

+    const UI32_T unit,

+    const UI16_T vid,

+    AIR_VLAN_ENTRY_ATTR_T* vlan_entry);

+

+void

+_air_untagged_vlan_writeEntry(

+    const UI32_T unit,

+    const UI16_T vid,

+    AIR_VLAN_ENTRY_ATTR_T* vlan_entry);

+

+/* EXPORTED SUBPROGRAM SPECIFICATIONS

+ */

+/* FUNCTION NAME:   air_vlan_create

+ * PURPOSE:

+ *      Create the vlan in the specified device.

+ * INPUT:

+ *      unit        -- unit id

+ *      vid         -- vlan id

+ *      p_attr      -- vlan attr

+ * OUTPUT:

+ *      None

+ * RETURN:

+ *      AIR_E_OK                -- Successfully read the data.

+ *      AIR_E_OTHERS            -- Vlan creation failed.

+ *      AIR_E_BAD_PARAMETER     -- Invalid parameter.

+ * NOTES:

+ *      none

+ */

+AIR_ERROR_NO_T

+air_vlan_create(

+    const UI32_T    unit,

+    const UI16_T    vid,

+    AIR_VLAN_ENTRY_ATTR_T *p_attr);

+

+/* FUNCTION NAME:   air_vlan_destroy

+ * PURPOSE:

+ *      Destroy the vlan in the specified device.

+ * INPUT:

+ *      unit        -- unit id

+ *      vid         -- vlan id

+ * OUTPUT:

+ *      None

+ * RETURN:

+ *      AIR_E_OK     -- Successfully read the data.

+ *      AIR_E_OTHERS -- Vlan destroy failed.

+ * NOTES:

+ *      none

+ */

+AIR_ERROR_NO_T

+air_vlan_destroy(

+    const UI32_T    unit,

+    const UI16_T    vid);

+

+/* FUNCTION NAME:   air_vlan_destroyAll

+ * PURPOSE:

+ *      Destroy the vlan in the specified device.

+ * INPUT:

+ *      unit        -- unit id

+ *      vid         -- vlan id

+ * OUTPUT:

+ *      None

+ * RETURN:

+ *      AIR_E_OK     -- Successfully read the data.

+ *      AIR_E_OTHERS -- Vlan destroy failed.

+ * NOTES:

+ *      none

+ */

+AIR_ERROR_NO_T

+air_vlan_destroyAll(

+    const UI32_T    unit,

+    const UI32_T    keep_and_restore_default_vlan);

+

+/* FUNCTION NAME:   air_vlan_reset

+ * PURPOSE:

+ *      Destroy the vlan in the specified device.

+ * INPUT:

+ *      unit        -- unit id

+ *      vid         -- vlan id

+ * OUTPUT:

+ *      None

+ * RETURN:

+ *      AIR_E_OK     -- Successfully reset the data.

+ *      AIR_E_OTHERS -- Vlan reset failed.

+ * NOTES:

+ *      none

+ */

+AIR_ERROR_NO_T

+air_vlan_reset(

+    const UI32_T    unit,

+    const UI16_T    vid);

+

+/* FUNCTION NAME:   air_vlan_setFid

+ * PURPOSE:

+ *      Set the filter id of the vlan to the specified device.

+ * INPUT:

+ *      unit        -- unit id

+ *      vid         -- vlan id

+ *      fid         -- filter id

+ * OUTPUT:

+ *      None

+ * RETURN:

+ *      AIR_E_OK                -- Successfully read the data.

+ *      AIR_E_OTHERS            -- Operation failed.

+ *      AIR_E_BAD_PARAMETER     -- Invalid parameter.

+ * NOTES:

+ *      none

+ */

+AIR_ERROR_NO_T

+air_vlan_setFid(

+    const UI32_T    unit,

+    const UI16_T    vid,

+    const UI8_T     fid);

+

+/* FUNCTION NAME:   air_vlan_getFid

+ * PURPOSE:

+ *      Get the filter id of the vlan from the specified device.

+ * INPUT:

+ *      unit        -- unit id

+ *      vid         -- vlan id to be created

+ * OUTPUT:

+ *      p_fid       -- filter id

+ * RETURN:

+ *      AIR_E_OK                -- Successfully read the data.

+ *      AIR_E_OTHERS            -- Operation failed.

+ *      AIR_E_BAD_PARAMETER     -- Invalid parameter.

+ * NOTES:

+ *      none

+ */

+AIR_ERROR_NO_T

+air_vlan_getFid(

+    const UI32_T    unit,

+    const UI16_T    vid,

+    UI8_T           *p_fid);

+

+/* FUNCTION NAME:   air_vlan_addMemberPort

+ * PURPOSE:

+ *      Add one vlan member to the specified device.

+ * INPUT:

+ *      unit        -- unit id

+ *      vid         -- vlan id

+ *      port        -- port id

+ * OUTPUT:

+ *      None

+ * RETURN:

+ *      AIR_E_OK                -- Successfully read the data.

+ *      AIR_E_OTHERS            -- Operation failed.

+ *      AIR_E_BAD_PARAMETER     -- Invalid parameter.

+ * NOTES:

+ *      none

+ */

+AIR_ERROR_NO_T

+air_vlan_addMemberPort(

+    const UI32_T    unit,

+    const UI16_T    vid,

+    const UI32_T    port);

+

+/* FUNCTION NAME:   air_vlan_delMemberPort

+ * PURPOSE:

+ *      Delete one vlan member from the specified device.

+ * INPUT:

+ *      unit        -- unit id

+ *      vid         -- vlan id

+ *      port        -- port id

+ * OUTPUT:

+ *      None

+ * RETURN:

+ *      AIR_E_OK                -- Successfully read the data.

+ *      AIR_E_OTHERS            -- Operation failed.

+ *      AIR_E_BAD_PARAMETER     -- Invalid parameter.

+ * NOTES:

+ *      none

+ */

+AIR_ERROR_NO_T

+air_vlan_delMemberPort(

+    const UI32_T    unit,

+    const UI16_T    vid,

+    const UI32_T    port);

+

+/* FUNCTION NAME:   air_vlan_setMemberPort

+ * PURPOSE:

+ *      Replace the vlan members in the specified device.

+ * INPUT:

+ *      unit        -- unit id

+ *      vid         -- vlan id

+ *      port_bitmap -- member port bitmap

+ * OUTPUT:

+ *      None

+ * RETURN:

+ *      AIR_E_OK                -- Successfully read the data.

+ *      AIR_E_OTHERS            -- Operation failed.

+ *      AIR_E_BAD_PARAMETER     -- Invalid parameter.

+ * NOTES:

+ *      none

+ */

+AIR_ERROR_NO_T

+air_vlan_setMemberPort(

+    const UI32_T    unit,

+    const UI16_T    vid,

+    const UI32_T    port_bitmap);

+

+/* FUNCTION NAME:   air_vlan_getMemberPort

+ * PURPOSE:

+ *      Get the vlan members from the specified device.

+ * INPUT:

+ *      unit        -- unit id

+ *      vid         -- vlan id

+ * OUTPUT:

+ *      port_bitmap -- member port bitmap

+ * RETURN:

+ *      AIR_E_OK                -- Successfully read the data.

+ *      AIR_E_OTHERS            -- Operation failed.

+ *      AIR_E_BAD_PARAMETER     -- Invalid parameter.

+ * NOTES:

+ *      none

+ */

+AIR_ERROR_NO_T

+air_vlan_getMemberPort(

+    const UI32_T    unit,

+    const UI16_T    vid,

+    UI32_T          *p_port_bitmap);

+

+/* FUNCTION NAME:   air_vlan_setIVL

+ * PURPOSE:

+ *      Set L2 lookup mode IVL/SVL for L2 traffic.

+ * INPUT:

+ *      unit        -- unit id

+ *      vid         -- vlan id

+ *      enable      -- enable IVL

+ * OUTPUT:

+ *      None

+ * RETURN:

+ *      AIR_E_OK                -- Successfully read the data.

+ *      AIR_E_OTHERS            -- Operation failed.

+ *      AIR_E_BAD_PARAMETER     -- Invalid parameter.

+ * NOTES:

+ *      none

+ */

+AIR_ERROR_NO_T

+air_vlan_setIVL(

+    const UI32_T    unit,

+    const UI16_T    vid,

+    const BOOL_T    enable);

+

+/* FUNCTION NAME:   air_vlan_getIVL

+ * PURPOSE:

+ *      Get L2 lookup mode IVL/SVL for L2 traffic.

+ * INPUT:

+ *      unit        -- unit id

+ *      vid         -- vlan id

+ * OUTPUT:

+ *      p_enable    -- enable IVL

+ * RETURN:

+ *      AIR_E_OK                -- Successfully read the data.

+ *      AIR_E_OTHERS            -- Operation failed.

+ *      AIR_E_BAD_PARAMETER     -- Invalid parameter.

+ * NOTES:

+ *      none

+ */

+AIR_ERROR_NO_T

+air_vlan_getIVL(

+    const UI32_T    unit,

+    const UI16_T    vid,

+    BOOL_T          *p_enable);

+

+/* FUNCTION NAME:   air_vlan_setPortAcceptFrameType

+ * PURPOSE:

+ *      Set vlan accept frame type of the port from the specified device.

+ * INPUT:

+ *      unit        -- unit id

+ *      port        -- port id

+ *      type        -- accept frame type

+ * OUTPUT:

+ *      None

+ * RETURN:

+ *      AIR_E_OK                -- Successfully read the data.

+ *      AIR_E_OTHERS            -- Operation failed.

+ *      AIR_E_BAD_PARAMETER     -- Invalid parameter.

+ * NOTES:

+ *      none

+ */

+AIR_ERROR_NO_T

+air_vlan_setPortAcceptFrameType(

+    const UI32_T    unit,

+    const UI32_T    port,

+    const AIR_VLAN_ACCEPT_FRAME_TYPE_T type);

+

+/* FUNCTION NAME:   air_vlan_getPortAcceptFrameType

+ * PURPOSE:

+ *      Get vlan accept frame type of the port from the specified device.

+ * INPUT:

+ *      unit        -- unit id

+ *      port        -- port id

+ * OUTPUT:

+ *      p_type      -- accept frame type

+ * RETURN:

+ *      AIR_E_OK                -- Successfully read the data.

+ *      AIR_E_OTHERS            -- Operation failed.

+ *      AIR_E_BAD_PARAMETER     -- Invalid parameter.

+ * NOTES:

+ *      none

+ */

+AIR_ERROR_NO_T

+air_vlan_getPortAcceptFrameType(

+    const UI32_T    unit,

+    const UI32_T    port,

+    AIR_VLAN_ACCEPT_FRAME_TYPE_T *p_type);

+

+/* FUNCTION NAME:   air_vlan_setPortLeakyVlanEnable

+ * PURPOSE:

+ *      Set leaky vlan enable of the port from the specified device.

+ * INPUT:

+ *      unit        -- unit id

+ *      port        -- port id

+ *      pkt_type    -- packet type

+ *      enable      -- enable leaky

+ * OUTPUT:

+ *      None

+ * RETURN:

+ *      AIR_E_OK                -- Successfully read the data.

+ *      AIR_E_OTHERS            -- Operation failed.

+ *      AIR_E_BAD_PARAMETER     -- Invalid parameter.

+ * NOTES:

+ *      none

+ */

+AIR_ERROR_NO_T

+air_vlan_setPortLeakyVlanEnable(

+    const UI32_T    unit,

+    const UI32_T    port,

+    AIR_LEAKY_PKT_TYPE_T   pkt_type,

+    const BOOL_T    enable);

+

+/* FUNCTION NAME:   air_vlan_getPortLeakyVlanEnable

+ * PURPOSE:

+ *      Get leaky vlan enable of the port from the specified device.

+ * INPUT:

+ *      unit        -- unit id

+ *      port        -- port id

+ *      pkt_type    -- packet type

+ * OUTPUT:

+ *      p_enable    -- enable leaky

+ * RETURN:

+ *      AIR_E_OK                -- Successfully read the data.

+ *      AIR_E_OTHERS            -- Operation failed.

+ *      AIR_E_BAD_PARAMETER     -- Invalid parameter.

+ * NOTES:

+ *      none

+ */

+AIR_ERROR_NO_T

+air_vlan_getPortLeakyVlanEnable(

+    const UI32_T    unit,

+    const UI32_T    port,

+    AIR_LEAKY_PKT_TYPE_T   pkt_type,

+    BOOL_T          *p_enable);

+

+/* FUNCTION NAME:   air_vlan_setPortAttr

+ * PURPOSE:

+ *      Set vlan port attribute from the specified device.

+ * INPUT:

+ *      unit        -- unit id

+ *      port        -- port id

+ *      attr        -- vlan port attr

+ * OUTPUT:

+ *      None

+ * RETURN:

+ *      AIR_E_OK                -- Successfully read the data.

+ *      AIR_E_OTHERS            -- Operation failed.

+ *      AIR_E_BAD_PARAMETER     -- Invalid parameter.

+ * NOTES:

+ *      none

+ */

+AIR_ERROR_NO_T

+air_vlan_setPortAttr(

+    const UI32_T    unit,

+    const UI32_T    port,

+    const AIR_VLAN_PORT_ATTR_T attr);

+

+/* FUNCTION NAME:   air_vlan_getPortAttr

+ * PURPOSE:

+ *      Get vlan port attribute from the specified device.

+ * INPUT:

+ *      unit        -- unit id

+ *      port        -- port id

+ * OUTPUT:

+ *      p_attr      -- vlan port attr

+ * RETURN:

+ *      AIR_E_OK                -- Successfully read the data.

+ *      AIR_E_OTHERS            -- Operation failed.

+ *      AIR_E_BAD_PARAMETER     -- Invalid parameter.

+ * NOTES:

+ *      none

+ */

+AIR_ERROR_NO_T

+air_vlan_getPortAttr(

+    const UI32_T    unit,

+    const UI32_T    port,

+    AIR_VLAN_PORT_ATTR_T *p_attr);

+

+/* FUNCTION NAME:   air_vlan_setIgrPortTagAttr

+ * PURPOSE:

+ *      Set vlan incoming port egress tag attribute from the specified device.

+ * INPUT:

+ *      unit        -- unit id

+ *      port        -- port id

+ *      attr        -- egress tag attr

+ * OUTPUT:

+ *      None

+ * RETURN:

+ *      AIR_E_OK                -- Successfully read the data.

+ *      AIR_E_OTHERS            -- Operation failed.

+ *      AIR_E_BAD_PARAMETER     -- Invalid parameter.

+ * NOTES:

+ *      none

+ */

+AIR_ERROR_NO_T

+air_vlan_setIgrPortTagAttr(

+    const UI32_T    unit,

+    const UI32_T    port,

+    const AIR_IGR_PORT_EG_TAG_ATTR_T attr);

+

+/* FUNCTION NAME:   air_vlan_getIgrPortTagAttr

+ * PURPOSE:

+ *      Get vlan incoming port egress tag attribute from the specified device.

+ * INPUT:

+ *      unit        -- unit id

+ *      port        -- port id

+ * OUTPUT:

+ *      p_attr      -- egress tag attr

+ * RETURN:

+ *      AIR_E_OK                -- Successfully read the data.

+ *      AIR_E_OTHERS            -- Operation failed.

+ *      AIR_E_BAD_PARAMETER     -- Invalid parameter.

+ * NOTES:

+ *      none

+ */

+AIR_ERROR_NO_T

+air_vlan_getIgrPortTagAttr(

+    const UI32_T    unit,

+    const UI32_T    port,

+    AIR_IGR_PORT_EG_TAG_ATTR_T *p_attr);

+

+/* FUNCTION NAME:   air_vlan_setPortEgsTagAttr

+ * PURPOSE:

+ *      Set vlan port egress tag attribute from the specified device.

+ * INPUT:

+ *      unit        -- unit id

+ *      port        -- port id

+ *      attr        -- egress tag attr

+ * OUTPUT:

+ *      None

+ * RETURN:

+ *      AIR_E_OK                -- Successfully read the data.

+ *      AIR_E_OTHERS            -- Operation failed.

+ *      AIR_E_BAD_PARAMETER     -- Invalid parameter.

+ * NOTES:

+ *      none

+ */

+AIR_ERROR_NO_T

+air_vlan_setPortEgsTagAttr(

+    const UI32_T    unit,

+    const UI32_T    port,

+    const AIR_PORT_EGS_TAG_ATTR_T attr);

+

+/* FUNCTION NAME:   air_vlan_getPortEgsTagAttr

+ * PURPOSE:

+ *      Get vlan port egress tag attribute from the specified device.

+ * INPUT:

+ *      unit        -- unit id

+ *      port        -- port id

+ * OUTPUT:

+ *      p_attr      -- egress tag attr

+ * RETURN:

+ *      AIR_E_OK                -- Successfully read the data.

+ *      AIR_E_OTHERS            -- Operation failed.

+ *      AIR_E_BAD_PARAMETER     -- Invalid parameter.

+ * NOTES:

+ *      none

+ */

+AIR_ERROR_NO_T

+air_vlan_getPortEgsTagAttr(

+    const UI32_T    unit,

+    const UI32_T    port,

+    AIR_PORT_EGS_TAG_ATTR_T *p_attr);

+

+/* FUNCTION NAME:   air_vlan_setPortOuterTPID

+ * PURPOSE:

+ *      Set stack tag TPID of the port from the specified device.

+ * INPUT:

+ *      unit        -- unit id

+ *      port        -- port id

+ *      tpid        -- TPID

+ * OUTPUT:

+ *      None

+ * RETURN:

+ *      AIR_E_OK                -- Successfully read the data.

+ *      AIR_E_OTHERS            -- Operation failed.

+ *      AIR_E_BAD_PARAMETER     -- Invalid parameter.

+ * NOTES:

+ *      none

+ */

+AIR_ERROR_NO_T

+air_vlan_setPortOuterTPID(

+    const UI32_T    unit,

+    const UI32_T    port,

+    const UI16_T    tpid);

+

+/* FUNCTION NAME:   air_vlan_getPortOuterTPID

+ * PURPOSE:

+ *      Get stack tag TPID of the port from the specified device.

+ * INPUT:

+ *      unit        -- unit id

+ *      port        -- port id

+ * OUTPUT:

+ *      p_tpid        -- TPID

+ * RETURN:

+ *      AIR_E_OK                -- Successfully read the data.

+ *      AIR_E_OTHERS            -- Operation failed.

+ *      AIR_E_BAD_PARAMETER     -- Invalid parameter.

+ * NOTES:

+ *      none

+ */

+AIR_ERROR_NO_T

+air_vlan_getPortOuterTPID(

+    const UI32_T    unit,

+    const UI32_T    port,

+    UI16_T          *p_tpid);

+

+/* FUNCTION NAME:   air_vlan_setPortPVID

+ * PURPOSE:

+ *      Set PVID of the port from the specified device.

+ * INPUT:

+ *      unit        -- unit id

+ *      port        -- port id

+ *      pvid        -- native vlan id

+ * OUTPUT:

+ *      None

+ * RETURN:

+ *      AIR_E_OK                -- Successfully read the data.

+ *      AIR_E_OTHERS            -- Operation failed.

+ *      AIR_E_BAD_PARAMETER     -- Invalid parameter.

+ * NOTES:

+ *      none

+ */

+AIR_ERROR_NO_T

+air_vlan_setPortPVID(

+    const UI32_T    unit,

+    const UI32_T    port,

+    const UI16_T    pvid);

+

+/* FUNCTION NAME:   air_vlan_getPortPVID

+ * PURPOSE:

+ *      Get PVID of the port from the specified device.

+ * INPUT:

+ *      unit        -- unit id

+ *      port        -- port id

+ * OUTPUT:

+ *      p_pvid      -- native vlan id

+ * RETURN:

+ *      AIR_E_OK                -- Successfully read the data.

+ *      AIR_E_OTHERS            -- Operation failed.

+ *      AIR_E_BAD_PARAMETER     -- Invalid parameter.

+ * NOTES:

+ *      none

+ */

+AIR_ERROR_NO_T

+air_vlan_getPortPVID(

+    const UI32_T    unit,

+    const UI32_T    port,

+    UI16_T          *p_pvid);

+

+/* FUNCTION NAME:   air_vlan_setServiceTag

+ * PURPOSE:

+ *      Set Vlan service tag.

+ * INPUT:

+ *      unit        -- unit id

+ *      vid         -- vlan id

+ *      stag        -- service stag

+ * OUTPUT:

+ *      None

+ * RETURN:

+ *      AIR_E_OK                -- Successfully read the data.

+ *      AIR_E_OTHERS            -- Operation failed.

+ *      AIR_E_BAD_PARAMETER     -- Invalid parameter.

+ * NOTES:

+ *      none

+ */

+AIR_ERROR_NO_T

+air_vlan_setServiceTag(

+    const UI32_T    unit,

+    const UI16_T    vid,

+    const UI16_T    stag);

+

+/* FUNCTION NAME:   air_vlan_getServiceTag

+ * PURPOSE:

+ *      Get Vlan service tag.

+ * INPUT:

+ *      unit        -- unit id

+ *      vid         -- vlan id

+ * OUTPUT:

+ *      p_stag      -- service stag

+ * RETURN:

+ *      AIR_E_OK                -- Successfully read the data.

+ *      AIR_E_OTHERS            -- Operation failed.

+ *      AIR_E_BAD_PARAMETER     -- Invalid parameter.

+ * NOTES:

+ *      none

+ */

+AIR_ERROR_NO_T

+air_vlan_getServiceTag(

+    const UI32_T    unit,

+    const UI16_T    vid,

+    UI16_T          *p_stag);

+

+/* FUNCTION NAME:   air_vlan_setEgsTagCtlEnable

+ * PURPOSE:

+ *      Set per vlan egress tag control.

+ * INPUT:

+ *      unit        -- unit id

+ *      vid         -- vlan id

+ *      enable      -- enable vlan egress tag control

+ * OUTPUT:

+ *      None

+ * RETURN:

+ *      AIR_E_OK                -- Successfully read the data.

+ *      AIR_E_OTHERS            -- Operation failed.

+ *      AIR_E_BAD_PARAMETER     -- Invalid parameter.

+ * NOTES:

+ *      none

+ */

+AIR_ERROR_NO_T

+air_vlan_setEgsTagCtlEnable(

+    const UI32_T    unit,

+    const UI16_T    vid,

+    const BOOL_T    enable);

+

+/* FUNCTION NAME:   air_vlan_getEgsTagCtlEnable

+ * PURPOSE:

+ *      Get per vlan egress tag control.

+ * INPUT:

+ *      unit        -- unit id

+ *      vid         -- vlan id

+ * OUTPUT:

+ *      p_enable    -- enable vlan egress tag control

+ * RETURN:

+ *      AIR_E_OK                -- Successfully read the data.

+ *      AIR_E_OTHERS            -- Operation failed.

+ *      AIR_E_BAD_PARAMETER     -- Invalid parameter.

+ * NOTES:

+ *      none

+ */

+AIR_ERROR_NO_T

+air_vlan_getEgsTagCtlEnable(

+    const UI32_T    unit,

+    const UI16_T    vid,

+    BOOL_T          *p_enable);

+

+/* FUNCTION NAME:   air_vlan_setEgsTagConsistent

+ * PURPOSE:

+ *      Set per vlan egress tag consistent.

+ * INPUT:

+ *      unit        -- unit id

+ *      vid         -- vlan id

+ *      enable      -- enable vlan egress tag consistent

+ * OUTPUT:

+ *      None

+ * RETURN:

+ *      AIR_E_OK                -- Successfully read the data.

+ *      AIR_E_OTHERS            -- Operation failed.

+ *      AIR_E_BAD_PARAMETER     -- Invalid parameter.

+ * NOTES:

+ *      none

+ */

+AIR_ERROR_NO_T

+air_vlan_setEgsTagConsistent(

+    const UI32_T    unit,

+    const UI16_T    vid,

+    const BOOL_T    enable);

+

+/* FUNCTION NAME:   air_vlan_getEgsTagConsistent

+ * PURPOSE:

+ *      Get per vlan egress tag consistent.

+ * INPUT:

+ *      unit        -- unit id

+ *      vid         -- vlan id

+ * OUTPUT:

+ *      p_enable    -- enable vlan egress tag consistent

+ * RETURN:

+ *      AIR_E_OK                -- Successfully read the data.

+ *      AIR_E_OTHERS            -- Operation failed.

+ *      AIR_E_BAD_PARAMETER     -- Invalid parameter.

+ * NOTES:

+ *      none

+ */

+AIR_ERROR_NO_T

+air_vlan_getEgsTagConsistent(

+    const UI32_T    unit,

+    const UI16_T    vid,

+    BOOL_T          *p_enable);

+

+/* FUNCTION NAME:   air_vlan_setPortBasedStag

+ * PURPOSE:

+ *      Set vlan port based stag enable.

+ * INPUT:

+ *      unit        -- unit id

+ *      vid         -- vlan id

+ *      enable      -- vlan port based stag enable

+ * OUTPUT:

+ *      None

+ * RETURN:

+ *      AIR_E_OK                -- Successfully read the data.

+ *      AIR_E_OTHERS            -- Operation failed.

+ *      AIR_E_BAD_PARAMETER     -- Invalid parameter.

+ * NOTES:

+ *      none

+ */

+AIR_ERROR_NO_T

+air_vlan_setPortBasedStag(

+    const UI32_T    unit,

+    const UI16_T    vid,

+    const BOOL_T    enable);

+

+/* FUNCTION NAME:   air_vlan_getPortBasedStag

+ * PURPOSE:

+ *      Get vlan port based stag enable.

+ * INPUT:

+ *      unit        -- unit id

+ *      vid         -- vlan id

+ * OUTPUT:

+ *      p_enable    -- vlan port based stag enable

+ * RETURN:

+ *      AIR_E_OK                -- Successfully read the data.

+ *      AIR_E_OTHERS            -- Operation failed.

+ *      AIR_E_BAD_PARAMETER     -- Invalid parameter.

+ * NOTES:

+ *      none

+ */

+AIR_ERROR_NO_T

+air_vlan_getPortBasedStag(

+    const UI32_T    unit,

+    const UI16_T    vid,

+    BOOL_T          *p_enable);

+

+/* FUNCTION NAME:   air_vlan_setPortEgsTagCtl

+ * PURPOSE:

+ *      Set vlan port egress tag control.

+ * INPUT:

+ *      unit        -- unit id

+ *      vid         -- vlan id

+ *      port        -- port id

+ *      tag_ctl     -- egress tag control

+ * OUTPUT:

+ *      None

+ * RETURN:

+ *      AIR_E_OK                -- Successfully read the data.

+ *      AIR_E_OTHERS            -- Operation failed.

+ *      AIR_E_BAD_PARAMETER     -- Invalid parameter.

+ * NOTES:

+ *      none

+ */

+AIR_ERROR_NO_T

+air_vlan_setPortEgsTagCtl(

+    const UI32_T    unit,

+    const UI16_T    vid,

+    const UI32_T    port,

+    const AIR_VLAN_PORT_EGS_TAG_CTL_TYPE_T    tag_ctl);

+

+/* FUNCTION NAME:   air_vlan_getPortEgsTagCtl

+ * PURPOSE:

+ *      Get vlan port egress tag control.

+ * INPUT:

+ *      unit        -- unit id

+ *      vid         -- vlan id

+ * OUTPUT:

+ *      p_tag_ctl   -- egress tag control

+ * RETURN:

+ *      AIR_E_OK                -- Successfully read the data.

+ *      AIR_E_OTHERS            -- Operation failed.

+ *      AIR_E_BAD_PARAMETER     -- Invalid parameter.

+ * NOTES:

+ *      none

+ */

+AIR_ERROR_NO_T

+air_vlan_getPortEgsTagCtl(

+    const UI32_T    unit,

+    const UI16_T    vid,

+    const UI32_T    port,

+    AIR_VLAN_PORT_EGS_TAG_CTL_TYPE_T   *ptr_tag_ctl);

+

+#endif  /* AIR_VLAN_H */

+

diff --git a/recipes-devtools/switch/files/src/an8855_sdk/api/src/air_acl.c b/recipes-devtools/switch/files/src/an8855_sdk/api/src/air_acl.c
new file mode 100644
index 0000000..9be3e0f
--- /dev/null
+++ b/recipes-devtools/switch/files/src/an8855_sdk/api/src/air_acl.c
@@ -0,0 +1,2032 @@
+/* FILE NAME: air_acl.c
+ * PURPOSE:
+ *      Define the ACL function in AIR SDK.
+ *
+ * NOTES:
+ *      None
+ */
+
+/* INCLUDE FILE DECLARATIONS
+*/
+#include "air.h"
+
+/* NAMING CONSTANT DECLARATIONS
+*/
+
+/* MACRO FUNCTION DECLARATIONS
+*/
+#define ACL_DERIVE_TBL_MULTIFIELDS(data_buffer, offset, width, dst)             \
+({                                                                              \
+    UI32_T value = 0;                                                           \
+    _deriveTblMultiFields((data_buffer), (offset), (width), &value);            \
+    dst = value;                                                                \
+})
+
+/* DATA TYPE DECLARATIONS
+*/
+
+/* GLOBAL VARIABLE DECLARATIONS
+*/
+
+/* LOCAL SUBPROGRAM DECLARATIONS
+*/
+
+/* STATIC VARIABLE DECLARATIONS
+*/
+
+/* LOCAL SUBPROGRAM BODIES
+*/
+static AIR_ERROR_NO_T
+_checkDone(
+    const UI32_T unit,
+    const AIR_ACL_CHECK_TYPE_T type)
+{
+    UI32_T check_bit = 0, i = 0, reg = 0, value = 0, offset = 0;
+
+    switch(type)
+    {
+        case AIR_ACL_CHECK_ACL:
+            check_bit = 1;
+            reg = ACL_MEM_CFG;
+            offset = ACL_MEM_CFG_DONE_OFFSET;
+            break;
+        case AIR_ACL_CHECK_UDF:
+            check_bit = 0;
+            reg = ACL_AUTC;
+            offset = ACL_UDF_ACC_OFFSET;
+            break;
+        case AIR_ACL_CHECK_TRTCM:
+            check_bit = 0;
+            reg = ACL_TRTCMA;
+            offset = ACL_TRTCM_BUSY_OFFSET;
+            break;
+        case AIR_ACL_CHECK_METER:
+            check_bit = 0;
+            reg = ACLRMC;
+            offset = ACL_RATE_BUSY_OFFSET;
+            break;
+        default:
+            return AIR_E_BAD_PARAMETER;
+    }
+    for(i=0; i < ACL_MAX_BUSY_TIME; i++)
+    {
+        aml_readReg(unit, reg, &value);
+        if (check_bit == (value >> offset))
+        {
+            break;
+        }
+        AIR_UDELAY(1);
+    }
+    if(i >= ACL_MAX_BUSY_TIME)
+    {
+        return AIR_E_TIMEOUT;
+    }
+    return AIR_E_OK;
+}
+
+static void
+_convertToTCcell(
+    const UI32_T *data0,
+    const UI32_T *data1,
+    UI32_T *arr0,
+    UI32_T *arr1,
+    UI32_T size)
+{
+    UI32_T i = 0;
+
+    for(i = 0; i < size; i++)
+    {
+        arr0[i] = data0[i] | (~data1[i]);
+        arr1[i] = (~data0[i]) | (~data1[i]);
+    }
+}
+
+static void
+_parseFromTCcell(
+    const UI32_T *data0,
+    const UI32_T *data1,
+    UI32_T *arr0,
+    UI32_T *arr1,
+    UI32_T size)
+{
+    UI32_T i = 0;
+
+    for(i = 0; i < size; i++)
+    {
+        arr1[i] = ~(data0[i] & data1[i]);
+        arr0[i] = data0[i] | (~arr1[i]);
+    }
+}
+
+static int
+_fillTblMultiFields(
+    UI32_T          *data_buffer,
+    UI32_T          data_count,
+    const UI32_T    offset,
+    const UI32_T    width,
+    const UI32_T    value)
+{
+    UI32_T data_index = 0, bit_index = 0;
+    UI32_T extended_data[2] = {0};
+    UI32_T extended_mask[2] = {0};
+    UI32_T msk;
+    UI32_T val;
+
+    AIR_CHECK_PTR(data_buffer);
+
+    if((0 == data_count) || (0 == width) || (width > 32) || (offset+width > data_count*32))
+    {
+        return 0;
+    }
+
+    msk = ((1U<<(width-1U))<<1U)-1U;
+    val = value & msk;
+    data_index = offset / 32;
+    bit_index = offset % 32;
+
+    extended_data[0] = val << bit_index;
+    extended_data[1] = (val >> (31U-bit_index))>>1U;
+    extended_mask[0] = msk << bit_index;
+    extended_mask[1] = (msk >> (31U-bit_index))>>1U;
+
+    data_buffer[data_index] = (data_buffer[data_index] & ~extended_mask[0]) | extended_data[0];
+    if ((data_index+1)<data_count)
+    {
+        data_buffer[data_index+1] = (data_buffer[data_index+1] & ~extended_mask[1]) | extended_data[1];
+    }
+
+    return 0;
+}
+
+static int
+_deriveTblMultiFields(
+    UI32_T          *data_buffer,
+    const UI32_T    offset,
+    const UI32_T    width,
+    UI32_T          *ptr_value)
+{
+    UI32_T data_index = 0, bit_index = 0;
+    UI32_T extended_data[2] = {0};
+    UI32_T extended_mask[2] = {0};
+    UI32_T msk = 0;
+
+    AIR_CHECK_PTR(data_buffer);
+    AIR_CHECK_PTR(ptr_value);
+
+    if(width==0 || width>32)
+    {
+        return 0;
+    }
+    msk = ((1U<<(width-1U))<<1U)-1U;
+    data_index = offset / 32;
+    bit_index = offset % 32;
+
+    extended_mask[0] = msk << bit_index;
+    extended_mask[1] = (msk >> (31U-bit_index))>>1U;
+    extended_data[0] = (data_buffer[data_index] & extended_mask[0]) >> bit_index;
+    extended_data[1] = ((data_buffer[data_index+1] & extended_mask[1]) << (31U-bit_index))<<1U;
+
+    *ptr_value = extended_data[0] | extended_data[1];
+    return 0;
+}
+
+static void
+_air_acl_setRuleTable(
+    const AIR_ACL_RULE_TYPE_T type,
+    const BOOL_T iskey,
+    const AIR_ACL_FIELD_T *ptr_field,
+    UI32_T *data)
+{
+    UI32_T n = 0;
+
+    switch(type)
+    {
+        case AIR_ACL_RULE_TYPE_0:
+            if(TRUE == iskey)
+            {
+                _fillTblMultiFields(data, 12, RULE_TYPE0_OFFSET, RULE_TYPE0_WIDTH, 0);
+            }
+            else
+            {
+                _fillTblMultiFields(data, 12, RULE_TYPE0_OFFSET, RULE_TYPE0_WIDTH, 1);
+            }
+            for(n=0; n<6; n++)
+            {
+                _fillTblMultiFields(data, 12, DMAC_OFFSET + DMAC_WIDTH*(5-n), DMAC_WIDTH, ptr_field->dmac[n]);
+            }
+            for(n=0; n<6; n++)
+            {
+                _fillTblMultiFields(data, 12, SMAC_OFFSET + SMAC_WIDTH*(5-n), SMAC_WIDTH, ptr_field->smac[n]);
+            }
+            _fillTblMultiFields(data, 12, STAG_OFFSET, STAG_WIDTH, ptr_field->stag);
+            _fillTblMultiFields(data, 12, CTAG_OFFSET, CTAG_WIDTH, ptr_field->ctag);
+            _fillTblMultiFields(data, 12, ETYPE_OFFSET, ETYPE_WIDTH, ptr_field->etype);
+            _fillTblMultiFields(data, 12, DIP_OFFSET, DIP_WIDTH, ptr_field->dip[0]);
+            _fillTblMultiFields(data, 12, SIP_OFFSET, SIP_WIDTH, ptr_field->sip[0]);
+            _fillTblMultiFields(data, 12, DSCP_OFFSET, DSCP_WIDTH, ptr_field->dscp);
+            _fillTblMultiFields(data, 12, PROTOCOL_OFFSET, PROTOCOL_WIDTH, ptr_field->protocol);
+            _fillTblMultiFields(data, 12, DPORT_OFFSET, DPORT_WIDTH, ptr_field->dport);
+            _fillTblMultiFields(data, 12, SPORT_OFFSET, SPORT_WIDTH, ptr_field->sport);
+            _fillTblMultiFields(data, 12, UDF_OFFSET, UDF_WIDTH, ptr_field->udf);
+            _fillTblMultiFields(data, 12, FIELDMAP_OFFSET, FIELDMAP_WIDTH, ptr_field->fieldmap);
+            _fillTblMultiFields(data, 12, IS_IPV6_OFFSET, IS_IPV6_WIDTH, ptr_field->isipv6);
+            _fillTblMultiFields(data, 12, PORTMAP_OFFSET, PORTMAP_WIDTH, ptr_field->portmap);
+            break;
+         case AIR_ACL_RULE_TYPE_1:
+            _fillTblMultiFields(data, 12, RULE_TYPE1_OFFSET, RULE_TYPE1_WIDTH, 1);
+            for(n=1; n<4; n++)
+            {
+                _fillTblMultiFields(data, 12, DIP_IPV6_OFFSET + DIP_IPV6_WIDTH*(n-1), DIP_IPV6_WIDTH, ptr_field->dip[n]);
+            }
+            for(n=1; n<4; n++)
+            {
+                _fillTblMultiFields(data, 12, SIP_IPV6_OFFSET + SIP_IPV6_WIDTH*(n-1), SIP_IPV6_WIDTH, ptr_field->sip[n]);
+            }
+            _fillTblMultiFields(data, 12, FLOW_LABEL_OFFSET, FLOW_LABEL_WIDTH, ptr_field->flow_label);
+            break;
+        default:
+            return;
+    }
+}
+
+static void
+_air_acl_getRuleTable(
+    const AIR_ACL_RULE_TYPE_T type,
+    UI32_T *data,
+    AIR_ACL_FIELD_T *ptr_field)
+{
+    UI32_T n = 0;
+
+    switch(type)
+    {
+        case AIR_ACL_RULE_TYPE_0:
+            for(n=0; n<6; n++)
+            {
+                ACL_DERIVE_TBL_MULTIFIELDS(data, DMAC_OFFSET + DMAC_WIDTH*(5-n), DMAC_WIDTH, ptr_field->dmac[n]);
+            }
+            for(n=0; n<6; n++)
+            {
+                ACL_DERIVE_TBL_MULTIFIELDS(data, SMAC_OFFSET + SMAC_WIDTH*(5-n), SMAC_WIDTH, ptr_field->smac[n]);
+            }
+            ACL_DERIVE_TBL_MULTIFIELDS(data, STAG_OFFSET, STAG_WIDTH, ptr_field->stag);
+            ACL_DERIVE_TBL_MULTIFIELDS(data, CTAG_OFFSET, CTAG_WIDTH, ptr_field->ctag);
+            ACL_DERIVE_TBL_MULTIFIELDS(data, ETYPE_OFFSET, ETYPE_WIDTH, ptr_field->etype);
+            ACL_DERIVE_TBL_MULTIFIELDS(data, DIP_OFFSET, DIP_WIDTH, ptr_field->dip[0]);
+            ACL_DERIVE_TBL_MULTIFIELDS(data, SIP_OFFSET, SIP_WIDTH, ptr_field->sip[0]);
+            ACL_DERIVE_TBL_MULTIFIELDS(data, DSCP_OFFSET, DSCP_WIDTH, ptr_field->dscp);
+            ACL_DERIVE_TBL_MULTIFIELDS(data, PROTOCOL_OFFSET, PROTOCOL_WIDTH, ptr_field->protocol);
+            ACL_DERIVE_TBL_MULTIFIELDS(data, DPORT_OFFSET, DPORT_WIDTH, ptr_field->dport);
+            ACL_DERIVE_TBL_MULTIFIELDS(data, SPORT_OFFSET, SPORT_WIDTH, ptr_field->sport);
+            ACL_DERIVE_TBL_MULTIFIELDS(data, UDF_OFFSET, UDF_WIDTH, ptr_field->udf);
+            ACL_DERIVE_TBL_MULTIFIELDS(data, FIELDMAP_OFFSET, FIELDMAP_WIDTH, ptr_field->fieldmap);
+            ACL_DERIVE_TBL_MULTIFIELDS(data, IS_IPV6_OFFSET, IS_IPV6_WIDTH, ptr_field->isipv6);
+            ACL_DERIVE_TBL_MULTIFIELDS(data, PORTMAP_OFFSET, PORTMAP_WIDTH, ptr_field->portmap);
+            break;
+         case AIR_ACL_RULE_TYPE_1:
+            for(n=1; n<4; n++)
+            {
+                ACL_DERIVE_TBL_MULTIFIELDS(data, DIP_IPV6_OFFSET + DIP_IPV6_WIDTH*(n-1), DIP_IPV6_WIDTH, ptr_field->dip[n]);
+            }
+            for(n=1; n<4; n++)
+            {
+                ACL_DERIVE_TBL_MULTIFIELDS(data, SIP_IPV6_OFFSET + SIP_IPV6_WIDTH*(n-1), SIP_IPV6_WIDTH, ptr_field->sip[n]);
+            }
+            ACL_DERIVE_TBL_MULTIFIELDS(data, FLOW_LABEL_OFFSET, FLOW_LABEL_WIDTH, ptr_field->flow_label);
+            break;
+        default:
+            return;
+    }
+}
+
+static void
+_air_acl_setActionTable(
+    const AIR_ACL_ACTION_T *ptr_action,
+    UI32_T *data)
+{
+    int i = 0;
+
+    _fillTblMultiFields(data, 4, PORT_FORCE_OFFSET, PORT_FORCE_WIDTH, ptr_action->port_en);
+    _fillTblMultiFields(data, 4, VLAN_PORT_SWAP_OFFSET, VLAN_PORT_SWAP_WIDTH, ptr_action->vlan_port_sel);
+    _fillTblMultiFields(data, 4, DST_PORT_SWAP_OFFSET, DST_PORT_SWAP_WIDTH, ptr_action->dest_port_sel);
+    _fillTblMultiFields(data, 4, PORT_OFFSET, PORT_WIDTH, ptr_action->portmap);
+
+    _fillTblMultiFields(data, 4, ACL_MIB_EN_OFFSET, ACL_MIB_EN_WIDTH, ptr_action->cnt_en);
+    _fillTblMultiFields(data, 4, ACL_MIB_ID_OFFSET, ACL_MIB_ID_WIDTH, ptr_action->cnt_idx);
+
+    _fillTblMultiFields(data, 4, ATTACK_RATE_EN_OFFSET, ATTACK_RATE_EN_WIDTH, ptr_action->attack_en);
+    _fillTblMultiFields(data, 4, ATTACK_RATE_ID_OFFSET, ATTACK_RATE_ID_WIDTH, ptr_action->attack_idx);
+
+    _fillTblMultiFields(data, 4, RATE_EN_OFFSET, RATE_EN_WIDTH, ptr_action->rate_en);
+    _fillTblMultiFields(data, 4, RATE_INDEX_OFFSET, RATE_INDEX_WIDTH, ptr_action->rate_idx);
+
+    _fillTblMultiFields(data, 4, PORT_FW_EN_OFFSET, PORT_FW_EN_WIDTH, ptr_action->fwd_en);
+    _fillTblMultiFields(data, 4, FW_PORT_OFFSET, FW_PORT_WIDTH, ptr_action->fwd);
+
+    _fillTblMultiFields(data, 4, MIRROR_OFFSET, MIRROR_WIDTH, ptr_action->mirrormap);
+
+    _fillTblMultiFields(data, 4, PRI_USER_EN_OFFSET, PRI_USER_EN_WIDTH, ptr_action->pri_user_en);
+    _fillTblMultiFields(data, 4, PRI_USER_OFFSET, PRI_USER_WIDTH, ptr_action->pri_user);
+
+    _fillTblMultiFields(data, 4, EG_TAG_EN_OFFSET, EG_TAG_EN_WIDTH, ptr_action->egtag_en);
+    _fillTblMultiFields(data, 4, EG_TAG_OFFSET, EG_TAG_WIDTH, ptr_action->egtag);
+
+    _fillTblMultiFields(data, 4, LKY_VLAN_EN_OFFSET, LKY_VLAN_EN_WIDTH, ptr_action->lyvlan_en);
+    _fillTblMultiFields(data, 4, LKY_VLAN_OFFSET, LKY_VLAN_WIDTH, ptr_action->lyvlan);
+
+    _fillTblMultiFields(data, 4, BPDU_OFFSET, BPDU_WIDTH, ptr_action->bpdu);
+
+    _fillTblMultiFields(data, 4, ACL_MANG_OFFSET, ACL_MANG_WIDTH, ptr_action->mang);
+
+    _fillTblMultiFields(data, 4, TRTCM_EN_OFFSET, TRTCM_EN_WIDTH, ptr_action->trtcm_en);
+    _fillTblMultiFields(data, 4, DROP_PCD_SEL_OFFSET, DROP_PCD_SEL_WIDTH, ptr_action->trtcm.drop_pcd_sel);
+    _fillTblMultiFields(data, 4, ACL_DROP_PCD_R_OFFSET, ACL_DROP_PCD_R_WIDTH, ptr_action->trtcm.drop_pcd_r);
+    _fillTblMultiFields(data, 4, ACL_DROP_PCD_Y_OFFSET, ACL_DROP_PCD_Y_WIDTH, ptr_action->trtcm.drop_pcd_y);
+    _fillTblMultiFields(data, 4, ACL_DROP_PCD_G_OFFSET, ACL_DROP_PCD_G_WIDTH, ptr_action->trtcm.drop_pcd_g);
+    _fillTblMultiFields(data, 4, CLASS_SLR_SEL_OFFSET, CLASS_SLR_SEL_WIDTH, ptr_action->trtcm.cls_slr_sel);
+    _fillTblMultiFields(data, 4, CLASS_SLR_OFFSET, CLASS_SLR_WIDTH, ptr_action->trtcm.cls_slr);
+    _fillTblMultiFields(data, 4, ACL_TCM_SEL_OFFSET, ACL_TCM_SEL_WIDTH, ptr_action->trtcm.tcm_sel);
+    _fillTblMultiFields(data, 4, ACL_TCM_OFFSET, ACL_TCM_WIDTH, ptr_action->trtcm.usr_tcm);
+    _fillTblMultiFields(data, 4, ACL_CLASS_IDX_OFFSET, ACL_CLASS_IDX_WIDTH, ptr_action->trtcm.tcm_idx);
+
+    _fillTblMultiFields(data, 4, ACL_VLAN_HIT_OFFSET, ACL_VLAN_HIT_WIDTH, ptr_action->vlan_en);
+    _fillTblMultiFields(data, 4, ACL_VLAN_VID_OFFSET, ACL_VLAN_VID_WIDTH, ptr_action->vlan_idx);
+}
+
+static void
+_air_acl_getActionTable(
+    UI32_T *data,
+    AIR_ACL_ACTION_T *ptr_action)
+{
+    ACL_DERIVE_TBL_MULTIFIELDS(data, PORT_FORCE_OFFSET, PORT_FORCE_WIDTH, ptr_action->port_en);
+    ACL_DERIVE_TBL_MULTIFIELDS(data, VLAN_PORT_SWAP_OFFSET, VLAN_PORT_SWAP_WIDTH, ptr_action->vlan_port_sel);
+    ACL_DERIVE_TBL_MULTIFIELDS(data, DST_PORT_SWAP_OFFSET, DST_PORT_SWAP_WIDTH, ptr_action->dest_port_sel);
+    ACL_DERIVE_TBL_MULTIFIELDS(data, PORT_OFFSET, PORT_WIDTH, ptr_action->portmap);
+
+    ACL_DERIVE_TBL_MULTIFIELDS(data, ACL_MIB_EN_OFFSET, ACL_MIB_EN_WIDTH, ptr_action->cnt_en);
+    ACL_DERIVE_TBL_MULTIFIELDS(data, ACL_MIB_ID_OFFSET, ACL_MIB_ID_WIDTH, ptr_action->cnt_idx);
+
+    ACL_DERIVE_TBL_MULTIFIELDS(data, ATTACK_RATE_EN_OFFSET, ATTACK_RATE_EN_WIDTH, ptr_action->attack_en);
+    ACL_DERIVE_TBL_MULTIFIELDS(data, ATTACK_RATE_ID_OFFSET, ATTACK_RATE_ID_WIDTH, ptr_action->attack_idx);
+
+    ACL_DERIVE_TBL_MULTIFIELDS(data, RATE_EN_OFFSET, RATE_EN_WIDTH, ptr_action->rate_en);
+    ACL_DERIVE_TBL_MULTIFIELDS(data, RATE_INDEX_OFFSET, RATE_INDEX_WIDTH, ptr_action->rate_idx);
+
+    ACL_DERIVE_TBL_MULTIFIELDS(data, PORT_FW_EN_OFFSET, PORT_FW_EN_WIDTH, ptr_action->fwd_en);
+    ACL_DERIVE_TBL_MULTIFIELDS(data, FW_PORT_OFFSET, FW_PORT_WIDTH, ptr_action->fwd);
+
+    ACL_DERIVE_TBL_MULTIFIELDS(data, MIRROR_OFFSET, MIRROR_WIDTH, ptr_action->mirrormap);
+
+    ACL_DERIVE_TBL_MULTIFIELDS(data, PRI_USER_EN_OFFSET, PRI_USER_EN_WIDTH, ptr_action->pri_user_en);
+    ACL_DERIVE_TBL_MULTIFIELDS(data, PRI_USER_OFFSET, PRI_USER_WIDTH, ptr_action->pri_user);
+
+    ACL_DERIVE_TBL_MULTIFIELDS(data, EG_TAG_EN_OFFSET, EG_TAG_EN_WIDTH, ptr_action->egtag_en);
+    ACL_DERIVE_TBL_MULTIFIELDS(data, EG_TAG_OFFSET, EG_TAG_WIDTH, ptr_action->egtag);
+
+    ACL_DERIVE_TBL_MULTIFIELDS(data, LKY_VLAN_EN_OFFSET, LKY_VLAN_EN_WIDTH, ptr_action->lyvlan_en);
+    ACL_DERIVE_TBL_MULTIFIELDS(data, LKY_VLAN_OFFSET, LKY_VLAN_WIDTH, ptr_action->lyvlan);
+
+    ACL_DERIVE_TBL_MULTIFIELDS(data, BPDU_OFFSET, BPDU_WIDTH, ptr_action->bpdu);
+
+    ACL_DERIVE_TBL_MULTIFIELDS(data, ACL_MANG_OFFSET, ACL_MANG_WIDTH, ptr_action->mang);
+
+    ACL_DERIVE_TBL_MULTIFIELDS(data, TRTCM_EN_OFFSET, TRTCM_EN_WIDTH, ptr_action->trtcm_en);
+    ACL_DERIVE_TBL_MULTIFIELDS(data, DROP_PCD_SEL_OFFSET, DROP_PCD_SEL_WIDTH, ptr_action->trtcm.drop_pcd_sel);
+    ACL_DERIVE_TBL_MULTIFIELDS(data, ACL_DROP_PCD_R_OFFSET, ACL_DROP_PCD_R_WIDTH, ptr_action->trtcm.drop_pcd_r);
+    ACL_DERIVE_TBL_MULTIFIELDS(data, ACL_DROP_PCD_Y_OFFSET, ACL_DROP_PCD_Y_WIDTH, ptr_action->trtcm.drop_pcd_y);
+    ACL_DERIVE_TBL_MULTIFIELDS(data, ACL_DROP_PCD_G_OFFSET, ACL_DROP_PCD_G_WIDTH, ptr_action->trtcm.drop_pcd_g);
+    ACL_DERIVE_TBL_MULTIFIELDS(data, CLASS_SLR_SEL_OFFSET, CLASS_SLR_SEL_WIDTH, ptr_action->trtcm.cls_slr_sel);
+    ACL_DERIVE_TBL_MULTIFIELDS(data, CLASS_SLR_OFFSET, CLASS_SLR_WIDTH, ptr_action->trtcm.cls_slr);
+    ACL_DERIVE_TBL_MULTIFIELDS(data, ACL_TCM_SEL_OFFSET, ACL_TCM_SEL_WIDTH, ptr_action->trtcm.tcm_sel);
+    ACL_DERIVE_TBL_MULTIFIELDS(data, ACL_TCM_OFFSET, ACL_TCM_WIDTH, ptr_action->trtcm.usr_tcm);
+    ACL_DERIVE_TBL_MULTIFIELDS(data, ACL_CLASS_IDX_OFFSET, ACL_CLASS_IDX_WIDTH, ptr_action->trtcm.tcm_idx);
+
+    ACL_DERIVE_TBL_MULTIFIELDS(data, ACL_VLAN_HIT_OFFSET, ACL_VLAN_HIT_WIDTH, ptr_action->vlan_en);
+    ACL_DERIVE_TBL_MULTIFIELDS(data, ACL_VLAN_VID_OFFSET, ACL_VLAN_VID_WIDTH, ptr_action->vlan_idx);
+
+}
+
+static AIR_ERROR_NO_T
+_air_acl_writeReg(
+    const UI32_T unit,
+    const UI32_T rule_idx,
+    const UI32_T block_num,
+    const AIR_ACL_RULE_TCAM_T type,
+    const AIR_ACL_MEM_SEL_T sel,
+    const AIR_ACL_MEM_FUNC_T func,
+    const UI32_T *data)
+{
+    UI32_T bn = 0, value = 0;
+    AIR_ERROR_NO_T ret = AIR_E_OK;
+
+    for (bn = 0; bn < block_num; bn++)
+    {
+        if(AIR_E_TIMEOUT == _checkDone(unit, AIR_ACL_CHECK_ACL))
+        {
+            return AIR_E_TIMEOUT;
+        }
+        aml_writeReg(unit, ACL_MEM_CFG_WDATA0, data[bn*4]);
+        aml_writeReg(unit, ACL_MEM_CFG_WDATA1, data[bn*4+1]);
+        aml_writeReg(unit, ACL_MEM_CFG_WDATA2, data[bn*4+2]);
+        aml_writeReg(unit, ACL_MEM_CFG_WDATA3, data[bn*4+3]);
+
+        value = (rule_idx << ACL_MEM_CFG_RULE_ID_OFFSET) | (type << ACL_MEM_CFG_TCAM_CELL_OFFSET) |
+            (bn << ACL_MEM_CFG_DATA_BN_OFFSET) | (sel << ACL_MEM_CFG_MEM_SEL_OFFSET) |
+            (func << ACL_MEM_CFG_FUNC_SEL_OFFSET) | ACL_MEM_CFG_EN;
+        if ((ret = aml_writeReg(unit, ACL_MEM_CFG, value)) != AIR_E_OK)
+        {
+            return ret;
+        }
+    }
+    return AIR_E_OK;
+}
+
+static AIR_ERROR_NO_T
+_air_acl_readReg(
+    const UI32_T unit,
+    const UI32_T rule_idx,
+    const UI32_T block_num,
+    const AIR_ACL_RULE_TCAM_T type,
+    const AIR_ACL_MEM_SEL_T sel,
+    const AIR_ACL_MEM_FUNC_T func,
+    UI32_T *data)
+{
+    UI32_T bn = 0, value = 0;
+    AIR_ERROR_NO_T ret = AIR_E_OK;
+
+    for (bn = 0; bn < block_num; bn++)
+    {
+        value = (rule_idx << ACL_MEM_CFG_RULE_ID_OFFSET) | (type << ACL_MEM_CFG_TCAM_CELL_OFFSET) |
+            (bn << ACL_MEM_CFG_DATA_BN_OFFSET) | (sel << ACL_MEM_CFG_MEM_SEL_OFFSET) |
+            (func << ACL_MEM_CFG_FUNC_SEL_OFFSET) | ACL_MEM_CFG_EN;
+        if ((ret = aml_writeReg(unit, ACL_MEM_CFG, value)) != AIR_E_OK)
+        {
+            return ret;
+        }
+        if(AIR_E_TIMEOUT == _checkDone(unit, AIR_ACL_CHECK_ACL))
+        {
+            return AIR_E_TIMEOUT;
+        }
+        aml_readReg(unit, ACL_MEM_CFG_RDATA0, data+bn*4);
+        aml_readReg(unit, ACL_MEM_CFG_RDATA1, data+bn*4+1);
+        aml_readReg(unit, ACL_MEM_CFG_RDATA2, data+bn*4+2);
+        aml_readReg(unit, ACL_MEM_CFG_RDATA3, data+bn*4+3);
+    }
+
+    return AIR_E_OK;
+}
+
+/* FUNCTION NAME: air_acl_setRuleCtrl
+ * PURPOSE:
+ *      Set ACL rule control.
+ *
+ * INPUT:
+ *      unit            --  Device ID
+ *      rule_idx        --  Index of ACL rule entry
+ *      ptr_rule        --  Structure of ACL rule control
+ *
+ * OUTPUT:
+ *      None
+ *
+ * RETURN:
+ *      AIR_E_OK
+ *      AIR_E_BAD_PARAMETER
+ *      AIR_E_TIMEOUT
+ *
+ * NOTES:
+ *      None
+ */
+AIR_ERROR_NO_T
+air_acl_setRuleCtrl(
+    const UI32_T unit,
+    const UI32_T rule_idx,
+    AIR_ACL_CTRL_T *ptr_ctrl)
+{
+    UI32_T data_en[4] = {0}, data_end[4] = {0}, data_rev[4] = {0};
+
+    if(TRUE == ptr_ctrl->rule_en)
+    {
+        _air_acl_readReg(unit, AIR_ACL_RULE_CONFIG_ENABLE, 1, 0, 0, AIR_ACL_MEM_FUNC_CONFIG_READ, data_en);
+        data_en[rule_idx/32] |= (1 << (rule_idx%32));
+        _air_acl_writeReg(unit, AIR_ACL_RULE_CONFIG_ENABLE, 1, 0, 0, AIR_ACL_MEM_FUNC_CONFIG_WRITE, data_en);
+    }
+    else
+    {
+        _air_acl_readReg(unit, AIR_ACL_RULE_CONFIG_ENABLE, 1, 0, 0, AIR_ACL_MEM_FUNC_CONFIG_READ, data_en);
+        data_en[rule_idx/32] &= ~(1 << (rule_idx%32));
+        _air_acl_writeReg(unit, AIR_ACL_RULE_CONFIG_ENABLE, 1, 0, 0, AIR_ACL_MEM_FUNC_CONFIG_WRITE, data_en);
+    }
+
+    if(TRUE == ptr_ctrl->end)
+    {
+        _air_acl_readReg(unit, AIR_ACL_RULE_CONFIG_END, 1, 0, 0, AIR_ACL_MEM_FUNC_CONFIG_READ, data_end);
+        data_end[rule_idx/32] |= (1 << (rule_idx%32));
+        _air_acl_writeReg(unit, AIR_ACL_RULE_CONFIG_END, 1, 0, 0, AIR_ACL_MEM_FUNC_CONFIG_WRITE, data_end);
+    }
+    else
+    {
+        _air_acl_readReg(unit, AIR_ACL_RULE_CONFIG_END, 1, 0, 0, AIR_ACL_MEM_FUNC_CONFIG_READ, data_end);
+        data_end[rule_idx/32] &= ~(1 << (rule_idx%32));
+        _air_acl_writeReg(unit, AIR_ACL_RULE_CONFIG_END, 1, 0, 0, AIR_ACL_MEM_FUNC_CONFIG_WRITE, data_end);
+
+    }
+
+    if(TRUE == ptr_ctrl->reverse)
+    {
+        _air_acl_readReg(unit, AIR_ACL_RULE_CONFIG_REVERSE, 1, 0, 0, AIR_ACL_MEM_FUNC_CONFIG_READ, data_rev);
+        data_rev[rule_idx/32] |= (1 << (rule_idx%32));
+        _air_acl_writeReg(unit, AIR_ACL_RULE_CONFIG_REVERSE, 1, 0, 0, AIR_ACL_MEM_FUNC_CONFIG_WRITE, data_rev);
+    }
+    else
+    {
+        _air_acl_readReg(unit, AIR_ACL_RULE_CONFIG_REVERSE, 1, 0, 0, AIR_ACL_MEM_FUNC_CONFIG_READ, data_rev);
+        data_rev[rule_idx/32] &= ~(1 << (rule_idx%32));
+        _air_acl_writeReg(unit, AIR_ACL_RULE_CONFIG_REVERSE, 1, 0, 0, AIR_ACL_MEM_FUNC_CONFIG_WRITE, data_rev);
+    }
+    return AIR_E_OK;
+}
+
+/* FUNCTION NAME: air_acl_getRuleCtrl
+ * PURPOSE:
+ *      Get ACL rule control.
+ *
+ * INPUT:
+ *      unit            --  Device ID
+ *      rule_idx        --  Index of ACL rule entry
+ *
+ * OUTPUT:
+ *      ptr_ctrl        --  Structure of ACL rule control
+ *
+ * RETURN:
+ *      AIR_E_OK
+ *      AIR_E_BAD_PARAMETER
+ *      AIR_E_TIMEOUT
+ *
+ * NOTES:
+ *      None
+ */
+AIR_ERROR_NO_T
+air_acl_getRuleCtrl(
+    const UI32_T unit,
+    const UI32_T rule_idx,
+    AIR_ACL_CTRL_T *ptr_ctrl)
+{
+    UI32_T data_en[4] = {0}, data_end[4] = {0}, data_rev[4] = {0};
+
+    _air_acl_readReg(unit, AIR_ACL_RULE_CONFIG_ENABLE, 1, 0, 0, AIR_ACL_MEM_FUNC_CONFIG_READ, data_en);
+    if(data_en[rule_idx/32] & (1 << (rule_idx%32)))
+    {
+        ptr_ctrl->rule_en = TRUE;
+    }
+    else
+    {
+        ptr_ctrl->rule_en = FALSE;
+    }
+
+    _air_acl_readReg(unit, AIR_ACL_RULE_CONFIG_END, 1, 0, 0, AIR_ACL_MEM_FUNC_CONFIG_READ, data_end);
+    if(data_end[rule_idx/32] & (1 << (rule_idx%32)))
+    {
+        ptr_ctrl->end = TRUE;
+    }
+    else
+    {
+        ptr_ctrl->end = FALSE;
+    }
+
+    _air_acl_readReg(unit, AIR_ACL_RULE_CONFIG_REVERSE, 1, 0, 0, AIR_ACL_MEM_FUNC_CONFIG_READ, data_rev);
+    if(data_rev[rule_idx/32] & (1 << (rule_idx%32)))
+    {
+        ptr_ctrl->reverse = TRUE;
+    }
+    else
+    {
+        ptr_ctrl->reverse = FALSE;
+    }
+    return AIR_E_OK;
+}
+
+/* FUNCTION NAME: air_acl_setRule
+ * PURPOSE:
+ *      Set ACL rule entry.
+ *
+ * INPUT:
+ *      unit            --  Device ID
+ *      rule_idx        --  Index of ACL rule entry
+ *      rule            --  Structure of ACL rule entry
+ *
+ * OUTPUT:
+ *      None
+ *
+ * RETURN:
+ *      AIR_E_OK
+ *      AIR_E_BAD_PARAMETER
+ *      AIR_E_TIMEOUT
+ *
+ * NOTES:
+ *      None
+ */
+AIR_ERROR_NO_T
+air_acl_setRule(
+    const UI32_T            unit,
+    const UI32_T            rule_idx,
+    AIR_ACL_RULE_T          *rule)
+{
+    UI32_T  type0_key[12] = {0}, type0_mask[12] = {0};
+    UI32_T  type1_key[12] = {0}, type1_mask[12] = {0};
+    UI32_T  type0_t[12] = {0}, type0_c[12] = {0};
+    UI32_T  type1_t[12] = {0}, type1_c[12] = {0};
+    AIR_ACL_CTRL_T ctrl;
+
+    /* Check parameter */
+    AIR_PARAM_CHK((rule_idx >= ACL_MAX_RULE_NUM), AIR_E_BAD_PARAMETER);
+    AIR_PARAM_CHK((rule->key.flow_label > BITS_RANGE(0, FLOW_LABEL_WIDTH)), AIR_E_BAD_PARAMETER);
+    AIR_PARAM_CHK((rule->key.fieldmap > BITS_RANGE(0, AIR_ACL_FIELD_TYPE_LAST)), AIR_E_BAD_PARAMETER);
+    AIR_PARAM_CHK((TRUE != rule->key.isipv6) && (FALSE != rule->key.isipv6), AIR_E_BAD_PARAMETER);
+    AIR_PARAM_CHK((rule->key.portmap & (~AIR_ALL_PORT_BITMAP)), AIR_E_BAD_PARAMETER);
+
+    AIR_PARAM_CHK((TRUE != rule->ctrl.rule_en) && (FALSE != rule->ctrl.rule_en), AIR_E_BAD_PARAMETER);
+    AIR_PARAM_CHK((TRUE != rule->ctrl.reverse) && (FALSE != rule->ctrl.reverse), AIR_E_BAD_PARAMETER);
+    AIR_PARAM_CHK((TRUE != rule->ctrl.end) && (FALSE != rule->ctrl.end), AIR_E_BAD_PARAMETER);
+
+    memset(type0_key, 0, sizeof(type0_key));
+    memset(type0_mask, 0, sizeof(type0_mask));
+    memset(type1_key, 0, sizeof(type1_key));
+    memset(type1_mask, 0, sizeof(type1_mask));
+
+    memset(type0_t, 0, sizeof(type0_t));
+    memset(type0_c, 0, sizeof(type0_c));
+    memset(type1_t, 0, sizeof(type1_t));
+    memset(type1_c, 0, sizeof(type1_c));
+
+    /* Fill rule type table */
+    _air_acl_setRuleTable(AIR_ACL_RULE_TYPE_0, TRUE, &rule->key, type0_key);
+    _air_acl_setRuleTable(AIR_ACL_RULE_TYPE_0, FALSE, &rule->mask, type0_mask);
+
+    /* Calculate T/C cell */
+    _convertToTCcell(type0_key, type0_mask, type0_t, type0_c, 12);
+
+    /* Set T/C cell to reg */
+    _air_acl_writeReg(unit, rule_idx, 3, AIR_ACL_RULE_T_CELL, AIR_ACL_MEM_SEL_RULE, AIR_ACL_MEM_FUNC_WRITE, type0_t);
+    _air_acl_writeReg(unit, rule_idx, 3, AIR_ACL_RULE_C_CELL, AIR_ACL_MEM_SEL_RULE, AIR_ACL_MEM_FUNC_WRITE, type0_c);
+
+    /* If match ipv6 flow lable or dip/dip, set rule type 1 */
+    if ((1 == rule->key.isipv6) && (rule->key.fieldmap & ((1 << AIR_ACL_DIP) | (1 << AIR_ACL_SIP) | (1 << AIR_ACL_FLOW_LABEL))))
+    {
+         _air_acl_setRuleTable(AIR_ACL_RULE_TYPE_1, TRUE, &rule->key, type1_key);
+         _air_acl_setRuleTable(AIR_ACL_RULE_TYPE_1, FALSE, &rule->mask, type1_mask);
+         _convertToTCcell(type1_key, type1_mask, type1_t, type1_c, 12);
+         _air_acl_writeReg(unit, rule_idx+1, 3, AIR_ACL_RULE_T_CELL, AIR_ACL_MEM_SEL_RULE, AIR_ACL_MEM_FUNC_WRITE, type1_t);
+         _air_acl_writeReg(unit, rule_idx+1, 3, AIR_ACL_RULE_C_CELL, AIR_ACL_MEM_SEL_RULE, AIR_ACL_MEM_FUNC_WRITE, type1_c);
+    }
+
+    /* Config rule enable/end/rev */
+    memcpy(&ctrl, &rule->ctrl, sizeof(AIR_ACL_CTRL_T));
+    if ((1 == rule->key.isipv6) && (rule->key.fieldmap & ((1 << AIR_ACL_DIP) | (1 << AIR_ACL_SIP) | (1 << AIR_ACL_FLOW_LABEL))))
+    {
+        ctrl.end = 0;
+        air_acl_setRuleCtrl(unit, rule_idx, &ctrl);
+        air_acl_setRuleCtrl(unit, rule_idx+1, &rule->ctrl);
+    }
+    else
+    {
+        air_acl_setRuleCtrl(unit, rule_idx, &rule->ctrl);
+    }
+
+    return AIR_E_OK;
+}
+
+/* FUNCTION NAME: air_acl_delRule
+ * PURPOSE:
+ *      Delete an ACL rule entry.
+ *
+ * INPUT:
+ *      unit            --  Device ID
+ *      rule_idx        --  Index of ACL rule entry
+ *
+ * OUTPUT:
+ *      None
+ *
+ * RETURN:
+ *      AIR_E_OK
+ *      AIR_E_BAD_PARAMETER
+ *      AIR_E_TIMEOUT
+ *
+ * NOTES:
+ *      None
+ */
+AIR_ERROR_NO_T
+air_acl_delRule(
+    const UI32_T unit,
+    const UI32_T rule_idx)
+{
+    UI32_T  type0_t[12]={0}, type0_c[12]={0}, type1_t[12]={0}, type1_c[12]={0};
+    AIR_ACL_CTRL_T ctrl={0};
+
+    /* Mistake proofing */
+    AIR_PARAM_CHK((rule_idx >= ACL_MAX_RULE_NUM), AIR_E_BAD_PARAMETER);
+
+    /* Delete the entry from ACL rule table */
+    _air_acl_writeReg(unit, rule_idx, 3, AIR_ACL_RULE_T_CELL, AIR_ACL_MEM_SEL_RULE, AIR_ACL_MEM_FUNC_WRITE, type0_t);
+    _air_acl_writeReg(unit, rule_idx, 3, AIR_ACL_RULE_C_CELL, AIR_ACL_MEM_SEL_RULE, AIR_ACL_MEM_FUNC_WRITE, type0_c);
+    air_acl_setRuleCtrl(unit, rule_idx, &ctrl);
+
+    return AIR_E_OK;
+}
+
+/* FUNCTION NAME: air_acl_clearRule
+ * PURPOSE:
+ *      Clear all ACL rule entries.
+ *
+ * INPUT:
+ *      unit            --  Device ID
+ *
+ * OUTPUT:
+ *      None
+ *
+ * RETURN:
+ *      AIR_E_OK
+ *      AIR_E_BAD_PARAMETER
+ *      AIR_E_TIMEOUT
+ *
+ * NOTES:
+ *      None
+ */
+AIR_ERROR_NO_T
+air_acl_clearRule(
+    const UI32_T   unit)
+{
+    AIR_ERROR_NO_T ret = AIR_E_OK;
+    UI32_T  value = 0;
+    UI32_T  data[4]={0};
+
+    value = (AIR_ACL_MEM_FUNC_CLEAR << ACL_MEM_CFG_FUNC_SEL_OFFSET) | ACL_MEM_CFG_EN;
+    if ((ret = aml_writeReg(unit, ACL_MEM_CFG, value)) != AIR_E_OK)
+    {
+        return ret;
+    }
+
+    _air_acl_writeReg(unit, AIR_ACL_RULE_CONFIG_ENABLE, 1, 0, 0, AIR_ACL_MEM_FUNC_CONFIG_WRITE, data);
+    _air_acl_writeReg(unit, AIR_ACL_RULE_CONFIG_END, 1, 0, 0, AIR_ACL_MEM_FUNC_CONFIG_WRITE, data);
+    _air_acl_writeReg(unit, AIR_ACL_RULE_CONFIG_REVERSE, 1, 0, 0, AIR_ACL_MEM_FUNC_CONFIG_WRITE, data);
+
+    return AIR_E_OK;
+}
+
+/* FUNCTION NAME: air_acl_clearAction
+ * PURPOSE:
+ *      Clear all ACL action entries.
+ *
+ * INPUT:
+ *      unit            --  Device ID
+ *
+ * OUTPUT:
+ *      None
+ *
+ * RETURN:
+ *      AIR_E_OK
+ *      AIR_E_BAD_PARAMETER
+ *      AIR_E_TIMEOUT
+ *
+ * NOTES:
+ *      None
+ */
+AIR_ERROR_NO_T
+air_acl_clearAction(
+    const UI32_T   unit)
+{
+    AIR_ERROR_NO_T ret = AIR_E_OK;
+    UI32_T  value = 0;
+    UI32_T  data[4]={0};
+
+    value = (AIR_ACL_MEM_SEL_ACTION << ACL_MEM_CFG_MEM_SEL_OFFSET) | (AIR_ACL_MEM_FUNC_CLEAR << ACL_MEM_CFG_FUNC_SEL_OFFSET) | ACL_MEM_CFG_EN;
+    if ((ret = aml_writeReg(unit, ACL_MEM_CFG, value)) != AIR_E_OK)
+    {
+        return ret;
+    }
+
+    return AIR_E_OK;
+}
+
+/* FUNCTION NAME: air_acl_getRule
+ * PURPOSE:
+ *      Get ACL rule entry.
+ *
+ * INPUT:
+ *      unit            --  Device ID
+ *      rule_idx        --  Index of ACL rule entry
+ *
+ * OUTPUT:
+ *      ptr_rule        --  Structure of ACL rule entry
+ *
+ * RETURN:
+ *      AIR_E_OK
+ *      AIR_E_BAD_PARAMETER
+ *      AIR_E_TIMEOUT
+ *
+ * NOTES:
+ *      None
+ */
+AIR_ERROR_NO_T
+air_acl_getRule(
+    const UI32_T unit,
+    const UI32_T rule_idx,
+    AIR_ACL_RULE_T *ptr_rule)
+{
+    AIR_ERROR_NO_T ret = AIR_E_OK;
+    UI32_T  bn = 0;
+    UI32_T  value = 0, n = 0, idx = 0;
+    UI32_T  type0_key[12] = {0}, type0_mask[12] = {0};
+    UI32_T  type1_key[12] = {0}, type1_mask[12] = {0};
+    UI32_T  type0_t[12] = {0}, type0_c[12] = {0};
+    UI32_T  type1_t[12] = {0}, type1_c[12] = {0};
+
+    /* Mistake proofing */
+    AIR_PARAM_CHK((rule_idx >= ACL_MAX_RULE_NUM), AIR_E_BAD_PARAMETER);
+    AIR_CHECK_PTR(ptr_rule);
+
+    _air_acl_readReg(unit, rule_idx, 3, AIR_ACL_RULE_T_CELL, AIR_ACL_MEM_SEL_RULE, AIR_ACL_MEM_FUNC_READ, type0_t);
+    _air_acl_readReg(unit, rule_idx, 3, AIR_ACL_RULE_C_CELL, AIR_ACL_MEM_SEL_RULE, AIR_ACL_MEM_FUNC_READ, type0_c);
+    /* rule type 1 */
+    if(1 == (type0_t[0] & 0x1))
+    {
+        idx = rule_idx-1;
+        AIR_PRINT("This is the part of ipv6 rule, please get rule(%d)\n", idx);
+        return AIR_E_OK;
+    }
+
+    _parseFromTCcell(type0_t, type0_c, type0_key, type0_mask, 12);
+
+    _air_acl_getRuleTable(AIR_ACL_RULE_TYPE_0, type0_key, &ptr_rule->key);
+    _air_acl_getRuleTable(AIR_ACL_RULE_TYPE_0, type0_mask, &ptr_rule->mask);
+
+    if ((TRUE == ptr_rule->key.isipv6) && (ptr_rule->mask.fieldmap & ((1 << AIR_ACL_DIP) | (1 << AIR_ACL_SIP) | (1 << AIR_ACL_FLOW_LABEL))))
+    {
+        _air_acl_readReg(unit, rule_idx+1, 3, AIR_ACL_RULE_T_CELL, AIR_ACL_MEM_SEL_RULE, AIR_ACL_MEM_FUNC_READ, type1_t);
+        _air_acl_readReg(unit, rule_idx+1, 3, AIR_ACL_RULE_C_CELL, AIR_ACL_MEM_SEL_RULE, AIR_ACL_MEM_FUNC_READ, type1_c);
+        _parseFromTCcell(type1_t, type1_c, type1_key, type1_mask, 12);
+
+        _air_acl_getRuleTable(AIR_ACL_RULE_TYPE_1, type1_key, &ptr_rule->key);
+        _air_acl_getRuleTable(AIR_ACL_RULE_TYPE_1, type1_mask, &ptr_rule->mask);
+    }
+    if ((TRUE == ptr_rule->key.isipv6) && (ptr_rule->mask.fieldmap & ((1 << AIR_ACL_DIP) | (1 << AIR_ACL_SIP) | (1 << AIR_ACL_FLOW_LABEL))))
+    {
+        air_acl_getRuleCtrl(unit, rule_idx+1, &ptr_rule->ctrl);
+    }
+    else
+    {
+        air_acl_getRuleCtrl(unit, rule_idx, &ptr_rule->ctrl);
+    }
+
+    return AIR_E_OK;
+}
+
+/* FUNCTION NAME: air_acl_setAction
+ * PURPOSE:
+ *      Set an ACL action entry.
+ *
+ * INPUT:
+ *      unit            --  Device ID
+ *      act_idx         --  Index of ACL action entry
+ *      act             --  Structure of ACL action entry
+ *
+ * OUTPUT:
+ *      None
+ *
+ * RETURN:
+ *      AIR_E_OK
+ *      AIR_E_BAD_PARAMETER
+ *      AIR_E_NOT_SUPPORT
+ *      AIR_E_TIMEOUT
+ *
+ * NOTES:
+ *      None
+ */
+AIR_ERROR_NO_T
+air_acl_setAction(
+    const UI32_T unit,
+    const UI32_T act_idx,
+    const AIR_ACL_ACTION_T act)
+{
+    AIR_ERROR_NO_T ret = AIR_E_OK;
+    UI32_T  data[4] = {0};
+
+    /* Check parameter */
+    AIR_PARAM_CHK((act_idx >= ACL_MAX_ACTION_NUM), AIR_E_BAD_PARAMETER);
+    AIR_PARAM_CHK((TRUE != act.port_en) && (FALSE != act.port_en), AIR_E_BAD_PARAMETER);
+    AIR_PARAM_CHK((TRUE != act.dest_port_sel) && (FALSE != act.dest_port_sel), AIR_E_BAD_PARAMETER);
+    AIR_PARAM_CHK((TRUE != act.vlan_port_sel) && (FALSE != act.vlan_port_sel), AIR_E_BAD_PARAMETER);
+    AIR_PARAM_CHK((act.portmap & (~AIR_ALL_PORT_BITMAP)), AIR_E_BAD_PARAMETER);
+
+    AIR_PARAM_CHK((TRUE != act.cnt_en) && (FALSE != act.cnt_en), AIR_E_BAD_PARAMETER);
+    AIR_PARAM_CHK((act.cnt_idx >= ACL_MAX_MIB_NUM), AIR_E_BAD_PARAMETER);
+
+    AIR_PARAM_CHK((TRUE != act.attack_en) && (FALSE != act.attack_en), AIR_E_BAD_PARAMETER);
+    AIR_PARAM_CHK((act.attack_idx >= ACL_MAX_ATTACK_RATE_NUM), AIR_E_BAD_PARAMETER);
+
+    AIR_PARAM_CHK((TRUE != act.rate_en) && (FALSE != act.rate_en), AIR_E_BAD_PARAMETER);
+    AIR_PARAM_CHK((act.rate_idx >= ACL_MAX_METER_NUM), AIR_E_BAD_PARAMETER);
+
+    AIR_PARAM_CHK((TRUE != act.vlan_en) && (FALSE != act.vlan_en), AIR_E_BAD_PARAMETER);
+    AIR_PARAM_CHK((act.vlan_idx >= ACL_MAX_VLAN_NUM), AIR_E_BAD_PARAMETER);
+
+    AIR_PARAM_CHK((act.mirrormap > BITS_RANGE(0, ACL_MAX_MIR_SESSION_NUM)), AIR_E_BAD_PARAMETER);
+
+    AIR_PARAM_CHK((TRUE != act.pri_user_en) && (FALSE != act.pri_user_en), AIR_E_BAD_PARAMETER);
+    AIR_PARAM_CHK((act.pri_user >= AIR_MAX_NUM_OF_QUEUE), AIR_E_BAD_PARAMETER);
+
+    AIR_PARAM_CHK((TRUE != act.lyvlan_en) && (FALSE != act.lyvlan_en), AIR_E_BAD_PARAMETER);
+    AIR_PARAM_CHK((TRUE != act.lyvlan) && (FALSE != act.lyvlan), AIR_E_BAD_PARAMETER);
+    AIR_PARAM_CHK((TRUE != act.mang) && (FALSE != act.mang), AIR_E_BAD_PARAMETER);
+    AIR_PARAM_CHK((TRUE != act.bpdu) && (FALSE != act.bpdu), AIR_E_BAD_PARAMETER);
+
+    AIR_PARAM_CHK((TRUE != act.fwd_en) && (FALSE != act.fwd_en), AIR_E_BAD_PARAMETER);
+    AIR_PARAM_CHK((act.fwd >= AIR_ACL_ACT_FWD_LAST), AIR_E_BAD_PARAMETER);
+
+    AIR_PARAM_CHK((TRUE != act.egtag_en) && (FALSE != act.egtag_en), AIR_E_BAD_PARAMETER);
+    AIR_PARAM_CHK((act.egtag >= AIR_ACL_ACT_EGTAG_LAST), AIR_E_BAD_PARAMETER);
+
+    AIR_PARAM_CHK((TRUE != act.trtcm_en) && (FALSE != act.trtcm_en), AIR_E_BAD_PARAMETER);
+    AIR_PARAM_CHK((TRUE != act.trtcm.cls_slr_sel) && (FALSE != act.trtcm.cls_slr), AIR_E_BAD_PARAMETER);
+    AIR_PARAM_CHK((act.trtcm.cls_slr >= ACL_MAX_CLASS_SLR_NUM), AIR_E_BAD_PARAMETER);
+    AIR_PARAM_CHK((TRUE != act.trtcm.drop_pcd_sel) && (FALSE != act.trtcm.drop_pcd_sel), AIR_E_BAD_PARAMETER);
+    AIR_PARAM_CHK((act.trtcm.drop_pcd_g >= ACL_MAX_DROP_PCD_NUM), AIR_E_BAD_PARAMETER);
+    AIR_PARAM_CHK((act.trtcm.drop_pcd_y >= ACL_MAX_DROP_PCD_NUM), AIR_E_BAD_PARAMETER);
+    AIR_PARAM_CHK((act.trtcm.drop_pcd_r >= ACL_MAX_DROP_PCD_NUM), AIR_E_BAD_PARAMETER);
+    AIR_PARAM_CHK((TRUE != act.trtcm.tcm_sel) && (FALSE != act.trtcm.tcm_sel), AIR_E_BAD_PARAMETER);
+    AIR_PARAM_CHK((act.trtcm.usr_tcm >= AIR_ACL_ACT_USR_TCM_LAST), AIR_E_BAD_PARAMETER);
+    AIR_PARAM_CHK((act.trtcm.tcm_idx >= ACL_MAX_TRTCM_NUM), AIR_E_BAD_PARAMETER);
+
+    _air_acl_setActionTable(&act, data);
+    _air_acl_writeReg(unit, act_idx, 1, 0, AIR_ACL_MEM_SEL_ACTION, AIR_ACL_MEM_FUNC_WRITE, data);
+
+    return ret;
+}
+
+/* FUNCTION NAME: air_acl_getAction
+ * PURPOSE:
+ *      Get an ACL action entry with speficic index.
+ *
+ * INPUT:
+ *      unit            --  Device ID
+ *      act_idx         --  Index of ACL action entry
+ *
+ * OUTPUT:
+ *      ptr_act         --  Structure of ACL action entry
+ *
+ * RETURN:
+ *      AIR_E_OK
+ *      AIR_E_BAD_PARAMETER
+ *      AIR_E_ENTRY_NOT_FOUND
+ *      AIR_E_TIMEOUT
+ *
+ * NOTES:
+ *      None
+ */
+AIR_ERROR_NO_T
+air_acl_getAction(
+    const UI32_T unit,
+    const UI32_T act_idx,
+    AIR_ACL_ACTION_T *ptr_act)
+{
+    AIR_ERROR_NO_T ret = AIR_E_OK;
+    UI32_T i = 0;
+    UI32_T data[4] = {0};
+
+    /* Mistake proofing */
+    AIR_PARAM_CHK((act_idx >= ACL_MAX_ACTION_NUM), AIR_E_BAD_PARAMETER);
+    AIR_CHECK_PTR(ptr_act);
+
+    _air_acl_readReg(unit, act_idx, 1, 0, AIR_ACL_MEM_SEL_ACTION, AIR_ACL_MEM_FUNC_READ, data);
+    _air_acl_getActionTable(data, ptr_act);
+
+    return AIR_E_OK;
+}
+
+/* FUNCTION NAME: air_acl_delAction
+ * PURPOSE:
+ *      Delete an ACL action entry with specific index
+ *
+ * INPUT:
+ *      unit            --  Device ID
+ *      act_idx         --  Index of ACL action entry
+ *
+ * OUTPUT:
+ *      None
+ *
+ * RETURN:
+ *      AIR_E_OK
+ *      AIR_E_BAD_PARAMETER
+ *      AIR_E_ENTRY_NOT_FOUND
+ *      AIR_E_TIMEOUT
+ *
+ * NOTES:
+ *      None
+ */
+AIR_ERROR_NO_T
+air_acl_delAction(
+    const UI32_T unit,
+    const UI32_T act_idx)
+{
+    AIR_ERROR_NO_T ret = AIR_E_OK;
+    UI32_T  value = 0;
+    UI32_T  data[4] = {0};
+
+    /* Check parameter */
+    AIR_PARAM_CHK((act_idx >= ACL_MAX_ACTION_NUM), AIR_E_BAD_PARAMETER);
+
+    _air_acl_writeReg(unit, act_idx, 1, 0, AIR_ACL_MEM_SEL_ACTION, AIR_ACL_MEM_FUNC_WRITE, data);
+    return ret;
+}
+
+/* FUNCTION NAME: air_acl_setTrtcm
+ * PURPOSE:
+ *      Set a trTCM entry with the specific index.
+ *
+ * INPUT:
+ *      unit            --  Device ID
+ *      tcm_idx         --  Index of trTCM entry
+ *      tcm             --  Structure of trTCM entry
+ *
+ * OUTPUT:
+ *      None
+ *
+ * RETURN:
+ *      AIR_E_OK
+ *      AIR_E_BAD_PARAMETER
+ *      AIR_E_TIMEOUT
+ *
+ * NOTES:
+ *      Index 0 ~ 31 can be selected in tcm_idx.
+ */
+AIR_ERROR_NO_T
+air_acl_setTrtcm(
+    const UI32_T unit,
+    const UI32_T tcm_idx,
+    const AIR_ACL_TRTCM_T tcm)
+{
+    AIR_ERROR_NO_T ret = AIR_E_OK;
+    UI32_T  value = 0;
+
+    /* Mistake proofing */
+    AIR_PARAM_CHK((tcm_idx >= ACL_MAX_TRTCM_NUM), AIR_E_BAD_PARAMETER);
+    AIR_PARAM_CHK((tcm.cbs > ACL_MAX_CBS_NUM), AIR_E_BAD_PARAMETER);
+    AIR_PARAM_CHK((tcm.cir > ACL_MAX_CIR_NUM), AIR_E_BAD_PARAMETER);
+    AIR_PARAM_CHK((tcm.pbs > ACL_MAX_PBS_NUM), AIR_E_BAD_PARAMETER);
+    AIR_PARAM_CHK((tcm.pir > ACL_MAX_PIR_NUM), AIR_E_BAD_PARAMETER);
+
+    if(AIR_E_TIMEOUT == _checkDone(unit, AIR_ACL_CHECK_TRTCM))
+    {
+        return AIR_E_TIMEOUT;
+    }
+
+    aml_writeReg(unit, ACL_TRTCMW_CBS, tcm.cbs & ACL_TRTCM_CBS_MASK);
+    aml_writeReg(unit, ACL_TRTCMW_EBS, tcm.pbs & ACL_TRTCM_EBS_MASK);
+    aml_writeReg(unit, ACL_TRTCMW_CIR, tcm.cir & ACL_TRTCM_CIR_MASK);
+    aml_writeReg(unit, ACL_TRTCMW_EIR, tcm.pir & ACL_TRTCM_EIR_MASK);
+
+    value = (1 << ACL_TRTCM_BUSY_OFFSET) | ACL_TRTCM_WRITE | ((tcm_idx & ACL_TRTCM_ID_MASK) << ACL_TRTCM_ID_OFFSET);
+
+    if ((ret = aml_writeReg(unit, ACL_TRTCMA, value)) != AIR_E_OK)
+    {
+        return ret;
+    }
+
+    return AIR_E_OK;
+}
+
+/* FUNCTION NAME: air_acl_delTrtcm
+ * PURPOSE:
+ *      Delete an ACL trTCM entry.
+ *
+ * INPUT:
+ *      unit            --  Device ID
+ *      trtcm_idx       --  Index of ACL trTCM entry
+ *
+ * OUTPUT:
+ *      None
+ *
+ * RETURN:
+ *      AIR_E_OK
+ *      AIR_E_BAD_PARAMETER
+ *      AIR_E_TIMEOUT
+ *
+ * NOTES:
+ *      Index 0 ~ 31 can be selected in tcm_idx.
+ */
+AIR_ERROR_NO_T
+air_acl_delTrtcm(
+    const UI32_T unit,
+    const UI32_T tcm_idx)
+{
+    AIR_ACL_TRTCM_T tcm;
+
+    /* Mistake proofing */
+    AIR_PARAM_CHK((tcm_idx >= ACL_MAX_TRTCM_NUM), AIR_E_BAD_PARAMETER);
+
+    /* Delete the entry from trTCM table */
+    memset(&tcm, 0, sizeof(tcm));
+    return air_acl_setTrtcm(unit, tcm_idx, tcm);
+}
+
+/* FUNCTION NAME: air_acl_clearTrtcm
+ * PURPOSE:
+ *      Clear all ACL trTCM entries.
+ *
+ * INPUT:
+ *      unit            --  Device ID
+ *
+ * OUTPUT:
+ *      None
+ *
+ * RETURN:
+ *      AIR_E_OK
+ *      AIR_E_BAD_PARAMETER
+ *      AIR_E_TIMEOUT
+ *
+ * NOTES:
+ *      None
+ */
+AIR_ERROR_NO_T
+air_acl_clearTrtcm(
+    const UI32_T unit)
+{
+    AIR_ERROR_NO_T ret = AIR_E_OK;
+    AIR_ACL_TRTCM_T tcm;
+    UI32_T i = 0;
+
+    /* Delete all entries from trTCM table */
+    memset(&tcm, 0, sizeof(tcm));
+    for(i=0; i < ACL_MAX_TRTCM_NUM; i++)
+    {
+        ret = air_acl_setTrtcm(unit, i, tcm);
+        if(AIR_E_OK != ret)
+        {
+            return ret;
+        }
+    }
+    return ret;
+}
+
+/* FUNCTION NAME: air_acl_getTrtcm
+ * PURPOSE:
+ *      Get a trTCM entry with the specific index.
+ *
+ * INPUT:
+ *      unit            --  Device ID
+ *      tcm_idx         --  Index of trTCM entry
+ *
+ * OUTPUT:
+ *      ptr_tcm         --  Structure of trTCM entry
+ *
+ * RETURN:
+ *      AIR_E_OK
+ *      AIR_E_BAD_PARAMETER
+ *      AIR_E_TIMEOUT
+ *
+ * NOTES:
+ *      Index 0 ~ 31 can be selected in tcm_idx.
+ */
+AIR_ERROR_NO_T
+air_acl_getTrtcm(
+    const UI32_T unit,
+    const UI32_T tcm_idx,
+    AIR_ACL_TRTCM_T *ptr_tcm)
+{
+    AIR_ERROR_NO_T ret = AIR_E_OK;
+    UI32_T  value = 0, trtcmr1 = 0, trtcmr2 = 0, trtcmr3 = 0, trtcmr4 = 0;
+
+    /* Mistake proofing */
+    AIR_PARAM_CHK((tcm_idx >= ACL_MAX_TRTCM_NUM), AIR_E_BAD_PARAMETER);
+    AIR_CHECK_PTR(ptr_tcm);
+
+    if(AIR_E_TIMEOUT == _checkDone(unit, AIR_ACL_CHECK_TRTCM))
+    {
+        return AIR_E_TIMEOUT;
+    }
+
+    value = (1 << ACL_TRTCM_BUSY_OFFSET) | ACL_TRTCM_READ | ((tcm_idx & ACL_TRTCM_ID_MASK) << ACL_TRTCM_ID_OFFSET);
+
+    if ((ret = aml_writeReg(unit, ACL_TRTCMA, value)) != AIR_E_OK)
+    {
+        return ret;
+    }
+
+    aml_readReg(unit, ACL_TRTCMR_CBS, &trtcmr1);
+    aml_readReg(unit, ACL_TRTCMR_EBS, &trtcmr2);
+    aml_readReg(unit, ACL_TRTCMR_CIR, &trtcmr3);
+    aml_readReg(unit, ACL_TRTCMR_EIR, &trtcmr4);
+
+    ptr_tcm->cbs = trtcmr1 & ACL_TRTCM_CBS_MASK;
+    ptr_tcm->pbs = trtcmr2 & ACL_TRTCM_EBS_MASK;
+    ptr_tcm->cir = trtcmr3 & ACL_TRTCM_CIR_MASK;
+    ptr_tcm->pir = trtcmr4 & ACL_TRTCM_EIR_MASK;
+
+    return AIR_E_OK;
+
+}
+
+/* FUNCTION NAME: air_acl_setTrtcmEnable
+ * PURPOSE:
+ *      Set trTCM enable so the meter table will be updated based on PIR and CIR.
+ *      The color marker will also be enabled when ACL is hit.
+ *
+ * INPUT:
+ *      unit            --  Device ID
+ *      state           --  FALSE:Disable
+ *                          TRUE: Enable
+ *
+ * OUTPUT:
+ *      None
+ *
+ * RETURN:
+ *      AIR_E_OK
+ *      AIR_E_BAD_PARAMETER
+ *
+ * NOTES:
+ *      None
+ */
+AIR_ERROR_NO_T
+air_acl_setTrtcmEnable(
+    const UI32_T unit,
+    const BOOL_T state)
+{
+    UI32_T u32dat = 0;
+
+    /* Mistake proofing for port checking */
+    AIR_PARAM_CHK(((TRUE != state) && (FALSE != state)), AIR_E_BAD_PARAMETER);
+
+    /* Read data from register */
+    aml_readReg(unit, ACL_TRTCM, &u32dat);
+
+    if (TRUE == state)
+    {
+        u32dat |= (BIT(ACL_TRTCM_EN_OFFSET));
+    }
+    else
+    {
+        u32dat &= ~(BIT(ACL_TRTCM_EN_OFFSET));
+    }
+
+    /* Write data to register */
+    aml_writeReg(unit, ACL_TRTCM, u32dat);
+
+    return AIR_E_OK;
+}
+
+/* FUNCTION NAME: air_acl_getTrtcm
+ * PURPOSE:
+ *      Get a trTCM enable state.
+ *
+ * INPUT:
+ *      unit            --  Device ID
+ *
+ * OUTPUT:
+ *      ptr_state       --  FALSE:Disable
+ *                          TRUE: Enable
+ *
+ * RETURN:
+ *      AIR_E_OK
+ *      AIR_E_BAD_PARAMETER
+ *
+ * NOTES:
+ *      None
+ */
+AIR_ERROR_NO_T
+air_acl_getTrtcmEnable(
+    const UI32_T unit,
+    BOOL_T *const ptr_state)
+{
+    UI32_T u32dat = 0;
+
+    /* Mistake proofing for port checking */
+    AIR_CHECK_PTR(ptr_state);
+
+    /* Read data from register */
+    aml_readReg(unit, ACL_TRTCM, &u32dat);
+
+    if (u32dat & BIT(ACL_TRTCM_EN_OFFSET))
+    {
+        (*ptr_state) = TRUE;
+    }
+    else
+    {
+        (*ptr_state) = FALSE;
+    }
+
+    return AIR_E_OK;
+}
+
+/* FUNCTION NAME: air_acl_setPortEnable
+ * PURPOSE:
+ *      Set ACL state for a specific port.
+ *
+ * INPUT:
+ *      unit            --  Device ID
+ *      port            --  Index of port number
+ *      state           --  FALSE:Disable
+ *                          TRUE: Enable
+ * OUTPUT:
+ *      None
+ *
+ * RETURN:
+ *      AIR_E_OK
+ *      AIR_E_BAD_PARAMETER
+ *
+ * NOTES:
+ *      None
+ */
+AIR_ERROR_NO_T
+air_acl_setPortEnable(
+    const UI32_T unit,
+    const UI32_T port,
+    const BOOL_T state)
+{
+    UI32_T u32dat = 0, value = 0;
+
+    /* Mistake proofing for port checking */
+    AIR_PARAM_CHK((port >= AIR_MAX_NUM_OF_PORTS), AIR_E_BAD_PARAMETER);
+    AIR_PARAM_CHK(((TRUE != state) && (FALSE != state)), AIR_E_BAD_PARAMETER);
+
+    value = state ? 1 : 0;
+    aml_readReg(unit, ACL_PORT_EN, &u32dat);
+    u32dat = (u32dat & ~(ACL_EN_MASK << port)) | (value << port);
+    aml_writeReg(unit, ACL_PORT_EN, u32dat);
+
+    return AIR_E_OK;
+}
+
+/* FUNCTION NAME: air_acl_getPortEnable
+ * PURPOSE:
+ *      Get ACL state for a specific port.
+ *
+ * INPUT:
+ *      unit            --  Device ID
+ *      port            --  Index of port number
+ *
+ * OUTPUT:
+ *      ptr_state       --  FALSE:Disable
+ *                          TRUE: Enable
+ * RETURN:
+ *      AIR_E_OK
+ *      AIR_E_BAD_PARAMETER
+ *
+ * NOTES:
+ *      None
+ */
+AIR_ERROR_NO_T
+air_acl_getPortEnable(
+    const UI32_T unit,
+    const UI32_T port,
+    UI32_T *ptr_state)
+{
+    UI32_T u32dat = 0;
+
+    /* Mistake proofing for port checking */
+    AIR_PARAM_CHK((port >= AIR_MAX_NUM_OF_PORTS), AIR_E_BAD_PARAMETER);
+
+    /* Mistake proofing for state checking */
+    AIR_CHECK_PTR(ptr_state);
+
+    /* Read data from register */
+    aml_readReg(unit, ACL_PORT_EN, &u32dat);
+
+    (*ptr_state) = BITS_OFF_R(u32dat, port, ACL_EN_MASK);
+
+    return AIR_E_OK;
+}
+
+/* FUNCTION NAME: air_acl_setDropEnable
+ * PURPOSE:
+ *      Set ACL drop precedence state
+ *
+ * INPUT:
+ *      unit            --  Device ID
+ *      port            --  Index of port number
+ *      state           --  FALSE:Disable
+ *                          TRUE: Enable
+ * OUTPUT:
+ *      None
+ *
+ * RETURN:
+ *      AIR_E_OK
+ *      AIR_E_BAD_PARAMETER
+ *
+ * NOTES:
+ *      None
+ */
+AIR_ERROR_NO_T
+air_acl_setDropEnable(
+    const UI32_T unit,
+    const UI32_T port,
+    const BOOL_T state)
+{
+    UI32_T u32dat = 0;
+
+    /* Mistake proofing for port checking */
+    AIR_PARAM_CHK((port >= AIR_MAX_NUM_OF_PORTS), AIR_E_BAD_PARAMETER);
+    AIR_PARAM_CHK(((TRUE != state) && (FALSE != state)), AIR_E_BAD_PARAMETER);
+
+    u32dat = state ? 1 : 0;
+    aml_writeReg(unit, DPCR_EN(port), u32dat);
+    return AIR_E_OK;
+
+}
+
+/* FUNCTION NAME: air_acl_getDropEnable
+ * PURPOSE:
+ *      Get ACL drop precedence state
+ *
+ * INPUT:
+ *      unit            --  Device ID
+ *      port            --  Index of port number
+ *
+ * OUTPUT:
+ *      ptr_state       --  FALSE:Disable
+ *                          TRUE: Enable
+ * RETURN:
+ *      AIR_E_OK
+ *      AIR_E_BAD_PARAMETER
+ *
+ * NOTES:
+ *      None
+ */
+AIR_ERROR_NO_T
+air_acl_getDropEnable(
+    const UI32_T unit,
+    const UI32_T port,
+    BOOL_T *ptr_state)
+{
+    UI32_T u32dat = 0;
+
+    /* Mistake proofing for port checking */
+    AIR_PARAM_CHK((port >= AIR_MAX_NUM_OF_PORTS), AIR_E_BAD_PARAMETER);
+    AIR_CHECK_PTR(ptr_state);
+
+    aml_readReg(unit, DPCR_EN(port), &u32dat);
+    *ptr_state = u32dat ? TRUE : FALSE;
+
+    return AIR_E_OK;
+}
+
+/* FUNCTION NAME: air_acl_setDropThreshold
+ * PURPOSE:
+ *      Set ACL drop threshold.
+ *
+ * INPUT:
+ *      unit            --  Device ID
+ *      port            --  Index of port number
+ *      color           --  AIR_ACL_DP_COLOR_YELLOW: Yellow
+ *                          AIR_ACL_DP_COLOR_RED   : Red
+ *      queue           --  Output queue number
+ *      high            --  High threshold
+ *      low             --  Low threshold
+ *
+ * OUTPUT:
+ *      None
+ *
+ * RETURN:
+ *      AIR_E_OK
+ *      AIR_E_BAD_PARAMETER
+ *
+ * NOTES:
+ *      Key parameter include port, color, queue.
+ */
+AIR_ERROR_NO_T
+air_acl_setDropThreshold(
+    const UI32_T unit,
+    const UI32_T port,
+    const AIR_ACL_DP_COLOR_T color,
+    const UI8_T queue,
+    const UI32_T high,
+    const UI32_T low)
+{
+    UI32_T u32dat = 0;
+
+    /* Mistake proofing for port checking */
+    AIR_PARAM_CHK((port >= AIR_MAX_NUM_OF_PORTS), AIR_E_BAD_PARAMETER);
+    AIR_PARAM_CHK((color >= AIR_ACL_DP_COLOR_LAST), AIR_E_BAD_PARAMETER);
+    AIR_PARAM_CHK((queue >= AIR_MAX_NUM_OF_QUEUE), AIR_E_BAD_PARAMETER);
+    AIR_PARAM_CHK((high > BITS_RANGE(0, DPCR_HIGH_THRSH_WIDTH)), AIR_E_BAD_PARAMETER);
+    AIR_PARAM_CHK((low > BITS_RANGE(0, DPCR_LOW_THRSH_WIDTH)), AIR_E_BAD_PARAMETER);
+
+    aml_readReg(unit, DPCR(port, color, queue), &u32dat);
+    u32dat = (u32dat & ~(DPCR_LOW_THRSH_MASK)) | low;
+    u32dat = (u32dat & ~(DPCR_HIGH_THRSH_MASK << DPCR_HIGH_THRSH_OFFSET)) | (high << DPCR_HIGH_THRSH_OFFSET);
+    aml_writeReg(unit, DPCR(port, color, queue), u32dat);
+    return AIR_E_OK;
+
+}
+
+/* FUNCTION NAME: air_acl_getDropThreshold
+ * PURPOSE:
+ *      Get ACL drop threshold.
+ *
+ * INPUT:
+ *      unit            --  Device ID
+ *      port            --  Index of port number
+ *      color           --  AIR_ACL_DP_COLOR_YELLOW: Yellow
+ *                          AIR_ACL_DP_COLOR_RED   : Red
+ *      queue           --  Output queue number
+ *
+ * OUTPUT:
+ *      ptr_high        --  High threshold
+ *      ptr_low         --  Low threshold
+ *
+ * RETURN:
+ *      AIR_E_OK
+ *      AIR_E_BAD_PARAMETER
+ *
+ * NOTES:
+ *      Key parameter include port, color, queue.
+ */
+AIR_ERROR_NO_T
+air_acl_getDropThreshold(
+    const UI32_T unit,
+    const UI32_T port,
+    const AIR_ACL_DP_COLOR_T color,
+    const UI8_T queue,
+    UI32_T *ptr_high,
+    UI32_T *ptr_low)
+{
+    UI32_T u32dat = 0;
+
+    /* Mistake proofing for port checking */
+    AIR_PARAM_CHK((port >= AIR_MAX_NUM_OF_PORTS), AIR_E_BAD_PARAMETER);
+    AIR_PARAM_CHK((color >= AIR_ACL_DP_COLOR_LAST), AIR_E_BAD_PARAMETER);
+    AIR_PARAM_CHK((queue >= AIR_MAX_NUM_OF_QUEUE), AIR_E_BAD_PARAMETER);
+    AIR_CHECK_PTR(ptr_high);
+    AIR_CHECK_PTR(ptr_low);
+
+    aml_readReg(unit, DPCR(port, color, queue), &u32dat);
+    *ptr_low = u32dat & DPCR_LOW_THRSH_MASK;
+    *ptr_high = (u32dat >> DPCR_HIGH_THRSH_OFFSET) & DPCR_HIGH_THRSH_MASK;
+    return AIR_E_OK;
+
+}
+
+/* FUNCTION NAME: air_acl_setDropProbability
+ * PURPOSE:
+ *      Set ACL drop probability.
+ *
+ * INPUT:
+ *      unit            --  Device ID
+ *      port            --  Index of port number
+ *      color           --  AIR_ACL_DP_COLOR_YELLOW: Yellow
+ *                          AIR_ACL_DP_COLOR_RED   : Red
+ *      queue           --  Output queue number
+ *      probability     --  Drop probability (value:0 ~ 1023, unit:1/1023; eg: value-102 = 10% )
+ *
+ * OUTPUT:
+ *      None
+ *
+ * RETURN:
+ *      AIR_E_OK
+ *      AIR_E_BAD_PARAMETER
+ *
+ * NOTES:
+ *      Key parameter include port, color, queue.
+ */
+AIR_ERROR_NO_T
+air_acl_setDropProbability(
+    const UI32_T unit,
+    const UI32_T port,
+    const AIR_ACL_DP_COLOR_T color,
+    const UI8_T queue,
+    const UI32_T probability)
+{
+    UI32_T u32dat = 0;
+
+    /* Mistake proofing for port checking */
+    AIR_PARAM_CHK((port >= AIR_MAX_NUM_OF_PORTS), AIR_E_BAD_PARAMETER);
+    AIR_PARAM_CHK((color >= AIR_ACL_DP_COLOR_LAST), AIR_E_BAD_PARAMETER);
+    AIR_PARAM_CHK((queue >= AIR_MAX_NUM_OF_QUEUE), AIR_E_BAD_PARAMETER);
+    AIR_PARAM_CHK((probability > BITS_RANGE(0, DPCR_PBB_WIDTH)), AIR_E_BAD_PARAMETER);
+
+    aml_readReg(unit, DPCR(port, color, queue), &u32dat);
+    u32dat = (u32dat & ~(DPCR_PBB_MASK << DPCR_PBB_OFFSET)) | (probability << DPCR_PBB_OFFSET);
+    aml_writeReg(unit, DPCR(port, color, queue), u32dat);
+    return AIR_E_OK;
+
+}
+
+/* FUNCTION NAME: air_acl_getDropProbability
+ * PURPOSE:
+ *      Get ACL drop probability.
+ *
+ * INPUT:
+ *      unit            --  Device ID
+ *      port            --  Index of port number
+ *      color           --  AIR_ACL_DP_COLOR_YELLOW: Yellow
+ *                          AIR_ACL_DP_COLOR_RED   : Red
+ *      queue           --  Output queue number
+ *
+ * OUTPUT:
+ *      ptr_probability --  Drop probability (value:0 ~ 1023, unit:1/1023; eg: value-102 = 10% )
+ *
+ * RETURN:
+ *      AIR_E_OK
+ *      AIR_E_BAD_PARAMETER
+ *
+ * NOTES:
+ *      Key parameter include port, color, queue.
+ */
+AIR_ERROR_NO_T
+air_acl_getDropProbability(
+    const UI32_T unit,
+    const UI32_T port,
+    const AIR_ACL_DP_COLOR_T color,
+    const UI8_T queue,
+    UI32_T *ptr_probability)
+{
+    UI32_T u32dat = 0;
+
+    /* Mistake proofing for port checking */
+    AIR_PARAM_CHK((port >= AIR_MAX_NUM_OF_PORTS), AIR_E_BAD_PARAMETER);
+    AIR_PARAM_CHK((color >= AIR_ACL_DP_COLOR_LAST), AIR_E_BAD_PARAMETER);
+    AIR_PARAM_CHK((queue >= AIR_MAX_NUM_OF_QUEUE), AIR_E_BAD_PARAMETER);
+    AIR_CHECK_PTR(ptr_probability);
+
+    /* Read data from register */
+    aml_readReg(unit, DPCR(port, color, queue), &u32dat);
+
+    (*ptr_probability) = BITS_OFF_R(u32dat, DPCR_PBB_OFFSET, DPCR_PBB_WIDTH);
+
+    return AIR_E_OK;
+}
+
+/* FUNCTION NAME:
+ *      air_acl_setGlobalState
+ * PURPOSE:
+ *      Set the ACL global enable state.
+ * INPUT:
+ *      unit        -- Device ID
+ *      state       -- Enable state of ACL
+ * OUTPUT:
+ *      None
+ * RETURN:
+ *      AIR_E_OK
+ *      AIR_E_BAD_PARAMETER
+ * NOTES:
+ *      None
+ */
+AIR_ERROR_NO_T
+air_acl_setGlobalState(
+    const UI32_T        unit,
+    const BOOL_T        state)
+{
+    AIR_ERROR_NO_T ret = AIR_E_OK;
+    UI32_T  value = 0, data = 0;
+
+    AIR_PARAM_CHK((TRUE != state) && (FALSE != state), AIR_E_BAD_PARAMETER);
+
+    value = state ? 1 : 0;
+    if ((ret = aml_readReg(unit, ACL_GLOBAL_CFG, &data)) != AIR_E_OK)
+    {
+        return ret;
+    }
+    data = (data & ~ACL_EN_MASK) | value;
+    if ((ret = aml_writeReg(unit, ACL_GLOBAL_CFG, data)) != AIR_E_OK)
+    {
+        return ret;
+    }
+    return AIR_E_OK;
+}
+
+/* FUNCTION NAME:
+ *      air_acl_getGlobalState
+ * PURPOSE:
+ *      Get the ACL global enable state.
+ * INPUT:
+ *      unit             -- Device ID
+ * OUTPUT:
+ *      ptr_state        -- Enable state
+ * RETURN:
+ *      AIR_E_OK
+ *      AIR_E_BAD_PARAMETER
+ * NOTES:
+ *      None
+ */
+AIR_ERROR_NO_T
+air_acl_getGlobalState(
+    const UI32_T         unit,
+    BOOL_T               *ptr_state)
+{
+    AIR_ERROR_NO_T ret = AIR_E_OK;
+    UI32_T  value = 0;
+
+    AIR_CHECK_PTR(ptr_state);
+    if ((ret = aml_readReg(unit, ACL_GLOBAL_CFG, &value)) != AIR_E_OK)
+    {
+        return ret;
+    }
+
+    value &= ACL_EN_MASK;
+    *ptr_state = value ? TRUE : FALSE;
+    return AIR_E_OK;
+}
+
+/* FUNCTION NAME:
+ *      air_acl_setUdfRule
+ * PURPOSE:
+ *      Set ACL UDF rule of specified entry index.
+ * INPUT:
+ *      unit             -- Device ID
+ *      rule_idx         -- ACLUDF table entry index
+ *      udf_rule         -- Structure of ACL UDF rule entry
+ * OUTPUT:
+ *      None
+ * RETURN:
+ *      AIR_E_OK
+ *      AIR_E_BAD_PARAMETER
+ * NOTES:
+ *      None
+ */
+AIR_ERROR_NO_T
+air_acl_setUdfRule(
+    const UI32_T                unit,
+    const UI32_T                rule_idx,
+    AIR_ACL_UDF_RULE_T          udf_rule)
+{
+    AIR_ERROR_NO_T ret = AIR_E_OK;
+    UI32_T  value = 0;
+    UI32_T  data[3] = {0};
+
+    /* Check parameter */
+    AIR_PARAM_CHK((rule_idx >= ACL_MAX_UDF_NUM), AIR_E_BAD_PARAMETER);
+    AIR_PARAM_CHK((TRUE != udf_rule.valid) && (FALSE != udf_rule.valid), AIR_E_BAD_PARAMETER);
+    AIR_PARAM_CHK((udf_rule.offset_format >= AIR_ACL_RULE_OFS_FMT_LAST), AIR_E_BAD_PARAMETER);
+    AIR_PARAM_CHK((udf_rule.offset >= ACL_MAX_WORD_OFST_NUM), AIR_E_BAD_PARAMETER);
+    AIR_PARAM_CHK((udf_rule.cmp_sel >= AIR_ACL_RULE_CMP_SEL_LAST), AIR_E_BAD_PARAMETER);
+    AIR_PARAM_CHK((udf_rule.pattern > ACL_MAX_CMP_PAT_NUM), AIR_E_BAD_PARAMETER);
+    AIR_PARAM_CHK((udf_rule.mask > ACL_MAX_CMP_BIT_NUM), AIR_E_BAD_PARAMETER);
+    AIR_PARAM_CHK((udf_rule.low_threshold > ACL_MAX_CMP_PAT_NUM), AIR_E_BAD_PARAMETER);
+    AIR_PARAM_CHK((udf_rule.high_threshold > ACL_MAX_CMP_BIT_NUM), AIR_E_BAD_PARAMETER);
+    AIR_PARAM_CHK((udf_rule.portmap & (~AIR_ALL_PORT_BITMAP)), AIR_E_BAD_PARAMETER);
+
+    _fillTblMultiFields(data, 3, PORT_BITMAP_OFFSET, PORT_BITMAP_WIDTH, udf_rule.portmap);
+    _fillTblMultiFields(data, 3, UDF_RULE_EN_OFFSET, UDF_RULE_EN_WIDTH, udf_rule.valid);
+    _fillTblMultiFields(data, 3, UDF_PKT_TYPE_OFFSET, UDF_PKT_TYPE_WIDTH, udf_rule.offset_format);
+    _fillTblMultiFields(data, 3, WORD_OFST_OFFSET, WORD_OFST_WIDTH, udf_rule.offset);
+
+    _fillTblMultiFields(data, 3, CMP_SEL_OFFSET, CMP_SEL_WIDTH, udf_rule.cmp_sel);
+    if(AIR_ACL_RULE_CMP_SEL_PATTERN == udf_rule.cmp_sel)
+    {
+        _fillTblMultiFields(data, 3, CMP_PAT_OFFSET, CMP_PAT_WIDTH, udf_rule.pattern);
+        _fillTblMultiFields(data, 3, CMP_MASK_OFFSET, CMP_MASK_WIDTH, udf_rule.mask);
+    }
+    else
+    {
+        _fillTblMultiFields(data, 3, CMP_PAT_OFFSET, CMP_PAT_WIDTH, udf_rule.low_threshold);
+        _fillTblMultiFields(data, 3, CMP_MASK_OFFSET, CMP_MASK_WIDTH, udf_rule.high_threshold);
+    }
+
+    if(AIR_E_TIMEOUT == _checkDone(unit, AIR_ACL_CHECK_UDF))
+    {
+        return AIR_E_TIMEOUT;
+    }
+    aml_writeReg(unit, ACL_AUTW0, data[0]);
+    aml_writeReg(unit, ACL_AUTW1, data[1]);
+    aml_writeReg(unit, ACL_AUTW2, data[2]);
+    value = (rule_idx & ACL_UDF_ADDR_MASK) | ACL_UDF_WRITE | (1U << ACL_UDF_ACC_OFFSET);
+    if ((ret = aml_writeReg(unit, ACL_AUTC, value)) != AIR_E_OK)
+    {
+        return ret;
+    }
+
+    return AIR_E_OK;
+}
+
+/* FUNCTION NAME:
+ *      air_acl_getUdfRule
+ * PURPOSE:
+ *      Get ACL UDF rule of specified entry index.
+ * INPUT:
+ *      unit             -- Device ID
+ *      rule_idx         -- ACLUDF table entry index
+ * OUTPUT:
+ *      ptr_udf_rule     -- Structure of ACL UDF rule entry
+ * RETURN:
+ *      AIR_E_OK
+ *      AIR_E_BAD_PARAMETER
+ * NOTES:
+ *      None
+ */
+AIR_ERROR_NO_T
+air_acl_getUdfRule(
+    const UI32_T                unit,
+    const UI8_T                 rule_idx,
+    AIR_ACL_UDF_RULE_T          *ptr_udf_rule)
+{
+    AIR_ERROR_NO_T ret = AIR_E_OK;
+    UI32_T  value = 0;
+    UI32_T  data[3] = {0};
+
+    /* Check parameter */
+    AIR_PARAM_CHK((rule_idx >= ACL_MAX_UDF_NUM), AIR_E_BAD_PARAMETER);
+    AIR_CHECK_PTR(ptr_udf_rule);
+
+    value = (rule_idx & ACL_UDF_ADDR_MASK) | ACL_UDF_READ | (1U << ACL_UDF_ACC_OFFSET);
+    if ((ret = aml_writeReg(unit, ACL_AUTC, value)) != AIR_E_OK)
+    {
+        return ret;
+    }
+    if(AIR_E_TIMEOUT == _checkDone(unit, AIR_ACL_CHECK_UDF))
+    {
+        return AIR_E_TIMEOUT;
+    }
+    aml_readReg(unit, ACL_AUTR0, data);
+    aml_readReg(unit, ACL_AUTR1, data+1);
+    aml_readReg(unit, ACL_AUTR2, data+2);
+
+    ACL_DERIVE_TBL_MULTIFIELDS(data, PORT_BITMAP_OFFSET, PORT_BITMAP_WIDTH, ptr_udf_rule->portmap);
+
+    ACL_DERIVE_TBL_MULTIFIELDS(data, UDF_RULE_EN_OFFSET, UDF_RULE_EN_WIDTH, ptr_udf_rule->valid);
+    ACL_DERIVE_TBL_MULTIFIELDS(data, UDF_PKT_TYPE_OFFSET, UDF_PKT_TYPE_WIDTH, ptr_udf_rule->offset_format);
+    ACL_DERIVE_TBL_MULTIFIELDS(data, WORD_OFST_OFFSET, WORD_OFST_WIDTH, ptr_udf_rule->offset);
+    ACL_DERIVE_TBL_MULTIFIELDS(data, CMP_SEL_OFFSET, CMP_SEL_WIDTH, ptr_udf_rule->cmp_sel);
+    if(AIR_ACL_RULE_CMP_SEL_PATTERN == ptr_udf_rule->cmp_sel)
+    {
+        ACL_DERIVE_TBL_MULTIFIELDS(data, CMP_PAT_OFFSET, CMP_PAT_WIDTH, ptr_udf_rule->pattern);
+        ACL_DERIVE_TBL_MULTIFIELDS(data, CMP_MASK_OFFSET, CMP_MASK_WIDTH, ptr_udf_rule->mask);
+    }
+    else
+    {
+        ACL_DERIVE_TBL_MULTIFIELDS(data, CMP_PAT_OFFSET, CMP_PAT_WIDTH, ptr_udf_rule->low_threshold);
+        ACL_DERIVE_TBL_MULTIFIELDS(data, CMP_MASK_OFFSET, CMP_MASK_WIDTH, ptr_udf_rule->high_threshold);
+    }
+    return AIR_E_OK;
+}
+
+/* FUNCTION NAME:
+ *      air_acl_delUdfRule
+ * PURPOSE:
+ *      Delete ACL UDF rule of specified entry index.
+ * INPUT:
+ *      unit             -- Device ID
+ *      rule_idx         -- ACLUDF table entry index
+ * OUTPUT:
+ *      None
+ * RETURN:
+ *      AIR_E_OK
+ *      AIR_E_BAD_PARAMETER
+ * NOTES:
+ *      None
+ */
+AIR_ERROR_NO_T
+air_acl_delUdfRule(
+    const UI32_T      unit,
+    const UI8_T       rule_idx)
+{
+    AIR_ERROR_NO_T ret = AIR_E_OK;
+    UI32_T  value = 0;
+    UI32_T  data = 0;
+
+    /* Check parameter */
+    AIR_PARAM_CHK((rule_idx >= ACL_MAX_UDF_NUM), AIR_E_BAD_PARAMETER);
+
+    aml_writeReg(unit, ACL_AUTW0, data);
+    aml_writeReg(unit, ACL_AUTW1, data);
+    aml_writeReg(unit, ACL_AUTW2, data);
+
+    value = (rule_idx & ACL_UDF_ADDR_MASK) | ACL_UDF_WRITE | (1U << ACL_UDF_ACC_OFFSET);
+    if ((ret = aml_writeReg(unit, ACL_AUTC, value)) != AIR_E_OK)
+    {
+        return ret;
+    }
+
+    return AIR_E_OK;
+}
+
+/* FUNCTION NAME:
+ *      air_acl_clearUdfRule
+ * PURPOSE:
+ *      Clear acl all udf rule.
+ * INPUT:
+ *      unit             -- Device ID
+ * OUTPUT:
+ *      None
+ * RETURN:
+ *      AIR_E_OK
+ *      AIR_E_BAD_PARAMETER
+ * NOTES:
+ *      None
+ */
+AIR_ERROR_NO_T
+air_acl_clearUdfRule(
+    const UI32_T    unit)
+{
+    AIR_ERROR_NO_T ret = AIR_E_OK;
+    UI32_T  value = 0;
+
+    value = ACL_UDF_CLEAR | (1U << ACL_UDF_ACC_OFFSET);
+    if ((ret = aml_writeReg(unit, ACL_AUTC, value)) != AIR_E_OK)
+    {
+        return ret;
+    }
+
+    return AIR_E_OK;
+}
+
+/* FUNCTION NAME:
+ *      air_acl_setMeterTable
+ * PURPOSE:
+ *      Set flow ingress rate limit by meter table.
+ * INPUT:
+ *      unit                -- Device ID
+ *      meter_id            -- Meter id
+ *      enable              -- Meter enable state
+ *      rate                -- Ratelimit(unit:64kbps)
+ * OUTPUT:
+ *      None
+ * RETURN:
+ *      AIR_E_OK
+ *      AIR_E_BAD_PARAMETER
+ * NOTES:
+ *      None
+ */
+AIR_ERROR_NO_T
+air_acl_setMeterTable(
+    const UI32_T            unit,
+    const UI32_T            meter_id,
+    const BOOL_T            enable,
+    const UI32_T            rate)
+{
+    AIR_ERROR_NO_T ret = AIR_E_OK;
+    UI32_T  value = 0;
+
+    /* Check parameter */
+    AIR_PARAM_CHK((meter_id >= ACL_MAX_METER_NUM), AIR_E_BAD_PARAMETER);
+    AIR_PARAM_CHK((rate > ACL_MAX_TOKEN_NUM), AIR_E_BAD_PARAMETER);
+
+    if(TRUE == enable)
+    {
+        value = (1 << ACL_RATE_BUSY_OFFSET) | ACL_RATE_WRITE | ((meter_id & ACL_RATE_ID_MASK) << ACL_RATE_ID_OFFSET) | ACL_RATE_EN |
+            (rate & ACL_RATE_TOKEN_MASK);
+    }
+    else if(FALSE == enable)
+    {
+        value = (1 << ACL_RATE_BUSY_OFFSET) | ACL_RATE_WRITE | ((meter_id & ACL_RATE_ID_MASK) << ACL_RATE_ID_OFFSET) | ACL_RATE_DIS;
+    }
+    else
+    {
+        return AIR_E_BAD_PARAMETER;
+    }
+
+    if(AIR_E_TIMEOUT == _checkDone(unit, AIR_ACL_CHECK_METER))
+    {
+        return AIR_E_TIMEOUT;
+    }
+    if ((ret = aml_writeReg(unit, ACLRMC, value)) != AIR_E_OK)
+    {
+        return ret;
+    }
+    return AIR_E_OK;
+}
+
+/* FUNCTION NAME:
+ *      air_acl_getMeterTable
+ * PURPOSE:
+ *      Get meter table configuration.
+ * INPUT:
+ *      unit                -- Device ID
+ *      meter_id            -- Meter id
+ * OUTPUT:
+ *      ptr_enable          -- Meter enable state
+ *      ptr_rate            -- Ratelimit(unit:64kbps)
+ * RETURN:
+ *      AIR_E_OK
+ *      AIR_E_BAD_PARAMETER
+ * NOTES:
+ *      None
+ */
+AIR_ERROR_NO_T
+air_acl_getMeterTable(
+    const UI32_T            unit,
+    const UI32_T            meter_id,
+    BOOL_T                  *ptr_enable,
+    UI32_T                  *ptr_rate)
+{
+    AIR_ERROR_NO_T ret = AIR_E_OK;
+    UI32_T  value = 0;
+
+    /* Check parameter */
+    AIR_PARAM_CHK((meter_id >= ACL_MAX_METER_NUM), AIR_E_BAD_PARAMETER);
+    AIR_CHECK_PTR(ptr_enable);
+    AIR_CHECK_PTR(ptr_rate);
+
+    if(AIR_E_TIMEOUT == _checkDone(unit, AIR_ACL_CHECK_METER))
+    {
+        return AIR_E_TIMEOUT;
+    }
+    value = (1 << ACL_RATE_BUSY_OFFSET) | ACL_RATE_READ | ((meter_id & ACL_RATE_ID_MASK) << ACL_RATE_ID_OFFSET) | ACL_RATE_EN;
+
+    if ((ret = aml_writeReg(unit, ACLRMC, value)) != AIR_E_OK)
+    {
+        return ret;
+    }
+    aml_readReg(unit, ACLRMD1, &value);
+    *ptr_enable = ((value >> ACL_RATE_EN_OFFSET) & 0x1) ? TRUE : FALSE;
+    *ptr_rate = value & ACL_RATE_TOKEN_MASK;
+
+    return AIR_E_OK;
+}
+
diff --git a/recipes-devtools/switch/files/src/an8855_sdk/api/src/air_aml.c b/recipes-devtools/switch/files/src/an8855_sdk/api/src/air_aml.c
new file mode 100644
index 0000000..38b85a4
--- /dev/null
+++ b/recipes-devtools/switch/files/src/an8855_sdk/api/src/air_aml.c
@@ -0,0 +1,218 @@
+/* FILE NAME:  air_aml.c

+ * PURPOSE:

+ *      It provides access management layer function.

+ * NOTES:

+ *

+ */

+

+/* INCLUDE FILE DECLARATIONS

+ */

+#include "air.h"

+

+/* NAMING CONSTANT DECLARATIONS

+ */

+

+/* MACRO FUNCTION DECLARATIONS

+ */

+

+/* DATA TYPE DECLARATIONS

+ */

+

+/* GLOBAL VARIABLE DECLARATIONS

+ */

+AML_DEV_ACCESS_T _ext_dev_access;

+

+/* EXPORTED SUBPROGRAM BODIES

+ */

+

+/* LOCAL SUBPROGRAM BODIES

+ */

+/* FUNCTION NAME:   aml_readReg

+ * PURPOSE:

+ *      To read data from the register of the specified chip unit.

+ * INPUT:

+ *      unit        -- the device unit

+ *      addr_offset -- the address of register

+ * OUTPUT:

+ *      ptr_data    -- pointer for the register data

+ * RETURN:

+ *      NPS_E_OK     -- Successfully read the data.

+ *      NPS_E_OTHERS -- Failed to read the data.

+ * NOTES:

+ *      none

+ */

+AIR_ERROR_NO_T

+aml_readReg(

+    const UI32_T    unit,

+    const UI32_T    addr_offset,

+    UI32_T          *ptr_data)

+{

+    AIR_CHECK_PTR(ptr_data);

+

+    if (!_ext_dev_access.read_callback)

+    {

+        return AIR_E_OTHERS;

+    }

+

+    return _ext_dev_access.read_callback(unit, addr_offset, ptr_data);

+}

+

+/* FUNCTION NAME:   aml_writeReg

+ * PURPOSE:

+ *      To write data to the register of the specified chip unit.

+ * INPUT:

+ *      unit        -- the device unit

+ *      addr_offset -- the address of register

+ *      data        -- written data

+ * OUTPUT:

+ *      none

+ * RETURN:

+ *      NPS_E_OK     -- Successfully write the data.

+ *      NPS_E_OTHERS -- Failed to write the data.

+ * NOTES:

+ *      none

+ */

+AIR_ERROR_NO_T

+aml_writeReg(

+    const UI32_T    unit,

+    const UI32_T    addr_offset,

+    const UI32_T    data)

+{

+    if (!_ext_dev_access.write_callback)

+    {

+        return AIR_E_OTHERS;

+    }

+

+    return _ext_dev_access.write_callback(unit, addr_offset, data);

+}

+

+/* FUNCTION NAME:   aml_readPhyReg

+ * PURPOSE:

+ *      To read data from the phy register of the specified chip unit in Clause22.

+ * INPUT:

+ *      unit        -- the device unit

+ *      port_id     -- physical port number

+ *      addr_offset -- the address of phy register

+ * OUTPUT:

+ *      ptr_data    -- pointer for the register data

+ * RETURN:

+ *      NPS_E_OK     -- Successfully read the data.

+ *      NPS_E_OTHERS -- Failed to read the data.

+ * NOTES:

+ *      none

+ */

+AIR_ERROR_NO_T

+aml_readPhyReg(

+    const UI32_T    unit,

+    const UI32_T    port_id,

+    const UI32_T    addr_offset,

+    UI32_T          *ptr_data)

+{

+    AIR_CHECK_PTR(ptr_data);

+

+    if (!_ext_dev_access.phy_read_callback)

+    {

+        return AIR_E_OTHERS;

+    }

+

+    return _ext_dev_access.phy_read_callback(unit, port_id, addr_offset, ptr_data);

+}

+

+/* FUNCTION NAME:   aml_writePhyReg

+ * PURPOSE:

+ *      To write data to the phy register of the specified chip unit in Clause22.

+ * INPUT:

+ *      unit        -- the device unit

+ *      port_id     -- physical port number

+ *      addr_offset -- the address of phy register

+ *      data        -- written data

+ * OUTPUT:

+ *      none

+ * RETURN:

+ *      NPS_E_OK     -- Successfully write the data.

+ *      NPS_E_OTHERS -- Failed to write the data.

+ * NOTES:

+ *      none

+ */

+AIR_ERROR_NO_T

+aml_writePhyReg(

+    const UI32_T    unit,

+    const UI32_T    port_id,

+    const UI32_T    addr_offset,

+    const UI32_T    data)

+{

+    if (!_ext_dev_access.phy_write_callback)

+    {

+        return AIR_E_OTHERS;

+    }

+

+    return _ext_dev_access.phy_write_callback(unit, port_id, addr_offset, data);

+}

+

+/* FUNCTION NAME:   aml_readPhyRegCL45

+ * PURPOSE:

+ *      To read data from the phy register of the specified chip unit in Clause45.

+ * INPUT:

+ *      unit        -- the device unit

+ *      port_id     -- physical port number

+ *      dev_type    -- phy register type

+ *      addr_offset -- the address of phy register

+ * OUTPUT:

+ *      ptr_data    -- pointer for the register data

+ * RETURN:

+ *      NPS_E_OK     -- Successfully read the data.

+ *      NPS_E_OTHERS -- Failed to read the data.

+ * NOTES:

+ *      none

+ */

+AIR_ERROR_NO_T

+aml_readPhyRegCL45(

+    const UI32_T    unit,

+    const UI32_T    port_id,

+    const UI32_T    dev_type,

+    const UI32_T    addr_offset,

+    UI32_T          *ptr_data)

+{

+    AIR_CHECK_PTR(ptr_data);

+

+    if (!_ext_dev_access.phy_cl45_read_callback)

+    {

+        return AIR_E_OTHERS;

+    }

+

+    return _ext_dev_access.phy_cl45_read_callback(unit, port_id, dev_type, addr_offset, ptr_data);

+}

+

+/* FUNCTION NAME:   aml_writePhyRegCL45

+ * PURPOSE:

+ *      To write data to the phy register of the specified chip unit in Clause45.

+ * INPUT:

+ *      unit        -- the device unit

+ *      port_id     -- physical port number

+ *      dev_type    -- phy register offset

+ *      addr_offset -- the address of phy register

+ *      data        -- written data

+ * OUTPUT:

+ *      none

+ * RETURN:

+ *      NPS_E_OK     -- Successfully write the data.

+ *      NPS_E_OTHERS -- Failed to write the data.

+ * NOTES:

+ *      none

+ */

+AIR_ERROR_NO_T

+aml_writePhyRegCL45(

+    const UI32_T    unit,

+    const UI32_T    port_id,

+    const UI32_T    dev_type,

+    const UI32_T    addr_offset,

+    const UI32_T    data)

+{

+    if (!_ext_dev_access.phy_cl45_write_callback)

+    {

+        return AIR_E_OTHERS;

+    }

+

+    return _ext_dev_access.phy_cl45_write_callback(unit, port_id, dev_type, addr_offset, data);

+}

+

diff --git a/recipes-devtools/switch/files/src/an8855_sdk/api/src/air_cmd.c b/recipes-devtools/switch/files/src/an8855_sdk/api/src/air_cmd.c
new file mode 100644
index 0000000..95c11e8
--- /dev/null
+++ b/recipes-devtools/switch/files/src/an8855_sdk/api/src/air_cmd.c
@@ -0,0 +1,8022 @@
+/* FILE NAME:   air_cmd.c

+ * PURPOSE:

+ *      Define the command line function in AIR SDK.

+ * NOTES:

+ */

+

+/* INCLUDE FILE DECLARATIONS

+*/

+#include "air.h"

+

+/* NAMING CONSTANT DECLARATIONS

+*/

+

+/* MACRO FUNCTION DECLARATIONS

+*/

+#define MAC_STR         "%02X%02X%02X%02X%02X%02X"

+#define MAC2STR(m)      (m)[0],(m)[1],(m)[2],(m)[3],(m)[4],(m)[5]

+#define AIR_MAC_LEN    (12)

+#define CMD_NO_PARA     (0xFFFFFFFF)

+#define CMD_VARIABLE_PARA (0xFFFFFFFE)

+#define L2_WDOG_KICK_NUM            (100)

+

+#define TOLOWER(x)      ((x) | 0x20)

+#define isxdigit(c)     (('0' <= (c) && (c) <= '9') || ('a' <= (c) && (c) <= 'f') || ('A' <= (c) && (c) <= 'F'))

+#define isdigit(c)      ('0' <= (c) && (c) <= '9')

+#define CMD_CHECK_PARA(__shift__, __op__, __size__) do          \

+{                                                               \

+    if ((__shift__) __op__ (__size__))                          \

+    {                                                           \

+        ;                                                       \

+    }                                                           \

+    else                                                        \

+    {                                                           \

+        return (AIR_E_BAD_PARAMETER);                           \

+    }                                                           \

+} while(0)

+

+/* DATA TYPE DECLARATIONS

+*/

+typedef struct {

+    C8_T*               name;

+    AIR_ERROR_NO_T     (*func)(UI32_T argc, C8_T *argv[]);

+    UI32_T              argc_min;

+    C8_T*               argc_errmsg;

+} AIR_CMD_T;

+

+/* GLOBAL VARIABLE DECLARATIONS

+*/

+

+/* LOCAL SUBPROGRAM DECLARATIONS

+*/

+/* String Utility */

+static BOOL_T _strcmp(const char *s1, const char *s2);

+static C8_T * _strtok_r(C8_T *s, const C8_T *delim, C8_T **last);

+static C8_T * _strtok(C8_T *s, const C8_T *delim, C8_T **last);

+UI32_T _strtoul(const C8_T *cp, C8_T **endp, UI32_T base);

+static I32_T _strtol(const C8_T *cp, C8_T **endp, UI32_T base);

+

+/* Type Converter */

+static AIR_ERROR_NO_T _str2mac(C8_T *str, C8_T *mac);

+static AIR_ERROR_NO_T _hex2bit(const UI32_T hex, UI32_T *ptr_bit);

+static AIR_ERROR_NO_T _hex2bitstr(const UI32_T hex, C8_T *ptr_bit_str, UI32_T str_len);

+static AIR_ERROR_NO_T _portListStr2Ary(const C8_T *str, UI32_T *ary, const UI32_T ary_num);

+

+/* Register Operation */

+static AIR_ERROR_NO_T doRegRead(UI32_T argc, C8_T *argv[]);

+static AIR_ERROR_NO_T doRegWrite(UI32_T argc, C8_T *argv[]);

+static AIR_ERROR_NO_T doReg(UI32_T argc, C8_T *argv[]);

+

+/* PHY Operation */

+static AIR_ERROR_NO_T doPhyCL22Read(UI32_T argc, C8_T *argv[]);

+static AIR_ERROR_NO_T doPhyCL22Write(UI32_T argc, C8_T *argv[]);

+static AIR_ERROR_NO_T doPhyCL22(UI32_T argc, C8_T *argv[]);

+static AIR_ERROR_NO_T doPhyCL45Read(UI32_T argc, C8_T *argv[]);

+static AIR_ERROR_NO_T doPhyCL45Write(UI32_T argc, C8_T *argv[]);

+static AIR_ERROR_NO_T doPhyCL45(UI32_T argc, C8_T *argv[]);

+static AIR_ERROR_NO_T doPhy(UI32_T argc, C8_T *argv[]);

+

+/* Porting setting */

+static AIR_ERROR_NO_T doPortSetMatrix(UI32_T argc, C8_T *argv[]);

+static AIR_ERROR_NO_T doPortSetVlanMode(UI32_T argc, C8_T *argv[]);

+static AIR_ERROR_NO_T doPortSet(UI32_T argc, C8_T *argv[]);

+

+static AIR_ERROR_NO_T doPortGetMatrix(UI32_T argc, C8_T *argv[]);

+static AIR_ERROR_NO_T doPortGetVlanMode(UI32_T argc, C8_T *argv[]);

+static AIR_ERROR_NO_T doPortGet(UI32_T argc, C8_T *argv[]);

+

+static AIR_ERROR_NO_T doPort(UI32_T argc, C8_T *argv[]);

+

+/* Vlan setting */

+static AIR_ERROR_NO_T doVlanInitiate(UI32_T argc, C8_T *argv[]);

+static AIR_ERROR_NO_T doVlanCreate(UI32_T argc, C8_T *argv[]);

+static AIR_ERROR_NO_T doVlanDestroy(UI32_T argc, C8_T *argv[]);

+static AIR_ERROR_NO_T doVlanDestroyAll(UI32_T argc, C8_T *argv[]);

+static AIR_ERROR_NO_T doVlanDump(UI32_T argc, C8_T *argv[]);

+static AIR_ERROR_NO_T doVlanAddPortMem(UI32_T argc, C8_T *argv[]);

+static AIR_ERROR_NO_T doVlanDelPortMem(UI32_T argc, C8_T *argv[]);

+

+static AIR_ERROR_NO_T doVlanSetFid(UI32_T argc, C8_T *argv[]);

+static AIR_ERROR_NO_T doVlanSetMemPort(UI32_T argc, C8_T *argv[]);

+static AIR_ERROR_NO_T doVlanSetIVL(UI32_T argc, C8_T *argv[]);

+static AIR_ERROR_NO_T doVlanSetPortBaseStag(UI32_T argc, C8_T *argv[]);

+static AIR_ERROR_NO_T doVlanSetStag(UI32_T argc, C8_T *argv[]);

+static AIR_ERROR_NO_T doVlanSetEgsTagCtlEn(UI32_T argc, C8_T *argv[]);

+static AIR_ERROR_NO_T doVlanSetEgsTagCtlCon(UI32_T argc, C8_T *argv[]);

+static AIR_ERROR_NO_T doVlanSetEgsTagCtl(UI32_T argc, C8_T *argv[]);

+static AIR_ERROR_NO_T doVlanSetPortActFrame(UI32_T argc, C8_T *argv[]);

+static AIR_ERROR_NO_T doVlanSetLeakyVlanEn(UI32_T argc, C8_T *argv[]);

+static AIR_ERROR_NO_T doVlanSetPortVlanAttr(UI32_T argc, C8_T *argv[]);

+static AIR_ERROR_NO_T doVlanSetIgsPortETagAttr(UI32_T argc, C8_T *argv[]);

+static AIR_ERROR_NO_T doVlanSetPortETagAttr(UI32_T argc, C8_T *argv[]);

+static AIR_ERROR_NO_T doVlanSetPortOuterTPID(UI32_T argc, C8_T *argv[]);

+static AIR_ERROR_NO_T doVlanSetPvid(UI32_T argc, C8_T *argv[]);

+static AIR_ERROR_NO_T doVlanSet(UI32_T argc, C8_T *argv[]);

+

+static AIR_ERROR_NO_T doVlanGetPortActFrame(UI32_T argc, C8_T *argv[]);

+static AIR_ERROR_NO_T doVlanGetLeakyVlanEn(UI32_T argc, C8_T *argv[]);

+static AIR_ERROR_NO_T doVlanGetPortVlanAttr(UI32_T argc, C8_T *argv[]);

+static AIR_ERROR_NO_T doVlanGetIgsPortETagAttr(UI32_T argc, C8_T *argv[]);

+static AIR_ERROR_NO_T doVlanGetPortETagAttr(UI32_T argc, C8_T *argv[]);

+static AIR_ERROR_NO_T doVlanGetPortOuterTPID(UI32_T argc, C8_T *argv[]);

+static AIR_ERROR_NO_T doVlanGetPvid(UI32_T argc, C8_T *argv[]);

+static AIR_ERROR_NO_T doVlanGet(UI32_T argc, C8_T *argv[]);

+

+static AIR_ERROR_NO_T doVlan(UI32_T argc, C8_T *argv[]);

+

+static AIR_ERROR_NO_T doFlowCtrl(UI32_T argc, C8_T *argv[]);

+static AIR_ERROR_NO_T doJumbo(UI32_T argc, C8_T *argv[]);

+

+static AIR_ERROR_NO_T doL2Add(UI32_T argc, C8_T *argv[]);

+static AIR_ERROR_NO_T doL2Del(UI32_T argc, C8_T *argv[]);

+static AIR_ERROR_NO_T doL2Clear(UI32_T argc, C8_T *argv[]);

+static AIR_ERROR_NO_T doL2Get(UI32_T argc, C8_T *argv[]);

+static AIR_ERROR_NO_T doL2Set(UI32_T argc, C8_T *argv[]);

+static AIR_ERROR_NO_T doL2Dump(UI32_T argc, C8_T *argv[]);

+static AIR_ERROR_NO_T doL2(UI32_T argc, C8_T *argv[]);

+

+static AIR_ERROR_NO_T doAnMode(UI32_T argc, C8_T *argv[]);

+static AIR_ERROR_NO_T doLocalAdv(UI32_T argc, C8_T *argv[]);

+static AIR_ERROR_NO_T doRemoteAdv(UI32_T argc, C8_T *argv[]);

+static AIR_ERROR_NO_T doPortSpeed(UI32_T argc, C8_T *argv[]);

+static AIR_ERROR_NO_T doPortDuplex(UI32_T argc, C8_T *argv[]);

+static AIR_ERROR_NO_T doPortStatus(UI32_T argc, C8_T *argv[]);

+static AIR_ERROR_NO_T doPortBckPres(UI32_T argc, C8_T *argv[]);

+static AIR_ERROR_NO_T doPortPsMode(UI32_T argc, C8_T *argv[]);

+static AIR_ERROR_NO_T doPortSmtSpdDwn(UI32_T argc, C8_T *argv[]);

+static AIR_ERROR_NO_T doPortSpTag(UI32_T argc, C8_T *argv[]);

+static AIR_ERROR_NO_T doPortEnable(UI32_T argc, C8_T *argv[]);

+static AIR_ERROR_NO_T doPort5GBaseRMode(UI32_T argc, C8_T *argv[]);

+static AIR_ERROR_NO_T doPortHsgmiiMode(UI32_T argc, C8_T *argv[]);

+static AIR_ERROR_NO_T doPortSgmiiMode(UI32_T argc, C8_T *argv[]);

+static AIR_ERROR_NO_T doPortRmiiMode(UI32_T argc, C8_T *argv[]);

+static AIR_ERROR_NO_T doPortRgmiiMode(UI32_T argc, C8_T *argv[]);

+

+static AIR_ERROR_NO_T doSptagEn(UI32_T argc, C8_T *argv[]);

+static AIR_ERROR_NO_T doSptagMode(UI32_T argc, C8_T *argv[]);

+static AIR_ERROR_NO_T doSptagDecode(UI32_T argc, C8_T *argv[]);

+static AIR_ERROR_NO_T doSptagEncode(UI32_T argc, C8_T *argv[]);

+static AIR_ERROR_NO_T doSptag(UI32_T argc, C8_T *argv[]);

+

+static AIR_ERROR_NO_T doMacAddr(UI32_T argc, C8_T *argv[]);

+static AIR_ERROR_NO_T _printMacEntry(AIR_MAC_ENTRY_T * mt, UI32_T age_unit, UI8_T count, UI8_T title);

+static AIR_ERROR_NO_T doGetMacAddr(UI32_T argc, C8_T *argv[]);

+static AIR_ERROR_NO_T doMacAddrAgeOut(UI32_T argc, C8_T *argv[]);

+static AIR_ERROR_NO_T doDumpMacAddr(UI32_T argc, C8_T *argv[]);

+

+static AIR_ERROR_NO_T doLagMember(UI32_T argc, C8_T *argv[]);

+static AIR_ERROR_NO_T doLagMemberCnt(UI32_T argc, C8_T *argv[]);

+static AIR_ERROR_NO_T doLagPtseed(UI32_T argc, C8_T *argv[]);

+static AIR_ERROR_NO_T doLagHashtype(UI32_T argc, C8_T *argv[]);

+static AIR_ERROR_NO_T doLagDstInfo(UI32_T argc, C8_T *argv[]);

+static AIR_ERROR_NO_T doLagState(UI32_T argc, C8_T *argv[]);

+static AIR_ERROR_NO_T doLagSpsel(UI32_T argc, C8_T *argv[]);

+static AIR_ERROR_NO_T doLagGet(UI32_T argc, C8_T *argv[]);

+static AIR_ERROR_NO_T doLagSet(UI32_T argc, C8_T *argv[]);

+static AIR_ERROR_NO_T doLag(UI32_T argc, C8_T *argv[]);

+

+static AIR_ERROR_NO_T doStpPortstate(UI32_T argc, C8_T *argv[]);

+static AIR_ERROR_NO_T doStpGet(UI32_T argc, C8_T *argv[]);

+static AIR_ERROR_NO_T doStpSet(UI32_T argc, C8_T *argv[]);

+static AIR_ERROR_NO_T doStp(UI32_T argc, C8_T *argv[]);

+

+static AIR_ERROR_NO_T doMirrorGetSid(UI32_T argc, C8_T *argv[]);

+static AIR_ERROR_NO_T doMirrorDelSid(UI32_T argc, C8_T *argv[]);

+static AIR_ERROR_NO_T doMirrorAddRlist(UI32_T argc, C8_T *argv[]);

+static AIR_ERROR_NO_T doMirrorAddTlist(UI32_T argc, C8_T *argv[]);

+static AIR_ERROR_NO_T doMirrorSetSessionEnable(UI32_T argc, C8_T *argv[]);

+static AIR_ERROR_NO_T doMirrorSetSession(UI32_T argc, C8_T *argv[]);

+static AIR_ERROR_NO_T doMirrorSet(UI32_T argc, C8_T *argv[]);

+static AIR_ERROR_NO_T doMirrorAdd(UI32_T argc, C8_T *argv[]);

+static AIR_ERROR_NO_T doMirrorGet(UI32_T argc, C8_T *argv[]);

+static AIR_ERROR_NO_T doMirrorDel(UI32_T argc, C8_T *argv[]);

+static AIR_ERROR_NO_T doMirror(UI32_T argc,C8_T *argv[]);

+

+static AIR_ERROR_NO_T doMibClearPort(UI32_T argc, C8_T *argv[]);

+static AIR_ERROR_NO_T doMibClearAcl(UI32_T argc, C8_T *argv[]);

+static AIR_ERROR_NO_T doMibGetPort(UI32_T argc, C8_T *argv[]);

+static AIR_ERROR_NO_T doMibGetAcl(UI32_T argc, C8_T *argv[]);

+static AIR_ERROR_NO_T doMibClear(UI32_T argc, C8_T *argv[]);

+static AIR_ERROR_NO_T doMibGet(UI32_T argc, C8_T *argv[]);

+static AIR_ERROR_NO_T doMib(UI32_T argc, C8_T *argv[]);

+

+static AIR_ERROR_NO_T doQosScheduleAlgo(UI32_T argc, C8_T *argv[]);

+static AIR_ERROR_NO_T doQosTrustMode(UI32_T argc, C8_T *argv[]);

+static AIR_ERROR_NO_T doQosPri2Queue(UI32_T argc, C8_T *argv[]);

+static AIR_ERROR_NO_T doQosDscp2Pri(UI32_T argc, C8_T *argv[]);

+static AIR_ERROR_NO_T doQosRateLimitEnable(UI32_T argc, C8_T *argv[]);

+static AIR_ERROR_NO_T doQosRateLimit(UI32_T argc, C8_T *argv[]);

+static AIR_ERROR_NO_T doQosPortPriority(UI32_T argc, C8_T *argv[]);

+static AIR_ERROR_NO_T doQosRateLimitExMngFrm(UI32_T argc, C8_T *argv[]);

+static AIR_ERROR_NO_T doQosGet(UI32_T argc, C8_T *argv[]);

+static AIR_ERROR_NO_T doQosSet(UI32_T argc, C8_T *argv[]);

+static AIR_ERROR_NO_T doQos(UI32_T argc, C8_T *argv[]);

+

+static AIR_ERROR_NO_T doDiagTxComply(UI32_T argc, C8_T *argv[]);

+static AIR_ERROR_NO_T doDiagSet(UI32_T argc, C8_T *argv[]);

+static AIR_ERROR_NO_T doDiagGet(UI32_T argc, C8_T *argv[]);

+static AIR_ERROR_NO_T doDiag(UI32_T argc, C8_T *argv[]);

+

+static AIR_ERROR_NO_T doLedMode(UI32_T argc, C8_T *argv[]);

+static AIR_ERROR_NO_T doLedState(UI32_T argc, C8_T *argv[]);

+static AIR_ERROR_NO_T doLedUsrDef(UI32_T argc, C8_T *argv[]);

+static AIR_ERROR_NO_T doLedBlkTime(UI32_T argc, C8_T *argv[]);

+static AIR_ERROR_NO_T doLedSet(UI32_T argc, C8_T *argv[]);

+static AIR_ERROR_NO_T doLedGet(UI32_T argc, C8_T *argv[]);

+static AIR_ERROR_NO_T doLed(UI32_T argc, C8_T *argv[]);

+

+static AIR_ERROR_NO_T doSwitchCpuPortEn(UI32_T argc, C8_T *argv[]);

+static AIR_ERROR_NO_T doSwitchCpuPort(UI32_T argc, C8_T *argv[]);

+static AIR_ERROR_NO_T doSwitchPhyLCIntrEn(UI32_T argc, C8_T *argv[]);

+static AIR_ERROR_NO_T doSwitchPhyLCIntrSts(UI32_T argc, C8_T *argv[]);

+static AIR_ERROR_NO_T doSwitchSet(UI32_T argc, C8_T *argv[]);

+static AIR_ERROR_NO_T doSwitchGet(UI32_T argc, C8_T *argv[]);

+static AIR_ERROR_NO_T doSwitch(UI32_T argc, C8_T *argv[]);

+

+static AIR_ERROR_NO_T doShowVersion(UI32_T argc, C8_T *argv[]);

+static AIR_ERROR_NO_T doShow(UI32_T argc, C8_T *argv[]);

+

+static AIR_ERROR_NO_T doStormEnable(UI32_T argc, C8_T *argv[]);

+static AIR_ERROR_NO_T doStormRate(UI32_T argc, C8_T *argv[]);

+static AIR_ERROR_NO_T doFldMode(UI32_T argc, C8_T *argv[]);

+static AIR_ERROR_NO_T doSaLearning(UI32_T argc, C8_T *argv[]);

+static AIR_ERROR_NO_T doSaLimit(UI32_T argc, C8_T *argv[]);

+static AIR_ERROR_NO_T doSecGet(UI32_T argc, C8_T *argv[]);

+static AIR_ERROR_NO_T doSecSet(UI32_T argc, C8_T *argv[]);

+static AIR_ERROR_NO_T doSec(UI32_T argc, C8_T *argv[]);

+

+static void _air_acl_printRuleMap(UI32_T *rule_map, UI32_T ary_num);

+static AIR_ERROR_NO_T doAclEn(UI32_T argc, C8_T *argv[]);

+static AIR_ERROR_NO_T doAclRule(UI32_T argc, C8_T *argv[]);

+static AIR_ERROR_NO_T doAclUdfRule(UI32_T argc, C8_T *argv[]);

+static AIR_ERROR_NO_T doAclRmvRule(UI32_T argc, C8_T *argv[]);

+static AIR_ERROR_NO_T doAclRmvUdfRule(UI32_T argc, C8_T *argv[]);

+static AIR_ERROR_NO_T doAclAction(UI32_T argc, C8_T *argv[]);

+static AIR_ERROR_NO_T doAclRmvAction(UI32_T argc, C8_T *argv[]);

+static AIR_ERROR_NO_T doAclDumpAction(UI32_T argc, C8_T *argv[]);

+static AIR_ERROR_NO_T doAclTrtcm(UI32_T argc, C8_T *argv[]);

+static AIR_ERROR_NO_T doAclTrtcmEn(UI32_T argc, C8_T *argv[]);

+static AIR_ERROR_NO_T doAclRmvTrtcm(UI32_T argc, C8_T *argv[]);

+static AIR_ERROR_NO_T doAclPortEn(UI32_T argc, C8_T *argv[]);

+static AIR_ERROR_NO_T doAclDropEn(UI32_T argc, C8_T *argv[]);

+static AIR_ERROR_NO_T doAclDropThrsh(UI32_T argc, C8_T *argv[]);

+static AIR_ERROR_NO_T doAclDropPbb(UI32_T argc, C8_T *argv[]);

+static AIR_ERROR_NO_T doAclMeter(UI32_T argc, C8_T *argv[]);

+static AIR_ERROR_NO_T doAclDump(UI32_T argc, C8_T *argv[]);

+static AIR_ERROR_NO_T doAclSet(UI32_T argc, C8_T *argv[]);

+static AIR_ERROR_NO_T doAclGet(UI32_T argc, C8_T *argv[]);

+static AIR_ERROR_NO_T doAclDel(UI32_T argc, C8_T *argv[]);

+static AIR_ERROR_NO_T doAclClear(UI32_T argc, C8_T *argv[]);

+static AIR_ERROR_NO_T doAcl(UI32_T argc, C8_T *argv[]);

+

+static AIR_ERROR_NO_T subcmd(const AIR_CMD_T tab[], UI32_T argc, C8_T *argv[]);

+

+/* STATIC VARIABLE DECLARATIONS

+*/

+const static C8_T *_sptag_vpm[] =

+{

+    "untagged",

+    "8100",

+    "predefined",

+    "unknown"

+};

+

+const static C8_T *_sptag_pt[] =

+{

+    "disable pass through",

+    "enable pass through"

+};

+

+const static C8_T *_air_mac_address_forward_control_string [] =

+{

+    "Default",

+    "CPU include",

+    "CPU exclude",

+    "CPU only",

+    "Drop"

+};

+

+static AIR_CMD_T regCmds[] =

+{

+    {"r",           doRegRead,      1,      "reg r <reg(4'hex)>"},

+    {"w",           doRegWrite,     2,      "reg w <reg(4'hex)> <value(8'hex)>"},

+

+    /* last entry, do not modify this entry */

+    {NULL, NULL, 0, NULL},

+};

+

+static AIR_CMD_T phyCL22Cmds[] =

+{

+    {"r",           doPhyCL22Read,  2,      "phy cl22 r <port(0..4)> <reg(2'hex)>"},

+    {"w",           doPhyCL22Write, 3,      "phy cl22 w <port(0..4)> <reg(2'hex)> <value(4'hex)>"},

+

+    /* last entry, do not modify this entry */

+    {NULL, NULL, 0, NULL},

+};

+

+static AIR_CMD_T phyCL45Cmds[] =

+{

+    {"r",           doPhyCL45Read,  3,      "phy cl45 r <port(0..4)> <dev(2'hex)> <reg(3'hex)>"},

+    {"w",           doPhyCL45Write, 4,      "phy cl45 w <port(0..4)> <dev(2'hex)> <reg(3'hex)> <value(4'hex)>"},

+

+    /* last entry, do not modify this entry */

+    {NULL, NULL, 0, NULL},

+};

+

+static AIR_CMD_T phyCmds[] =

+{

+    {"cl22",         doPhyCL22,     0,      NULL},

+    {"cl45",         doPhyCL45,     0,      NULL},

+

+    /* last entry, do not modify this entry */

+    {NULL, NULL, 0, NULL},

+};

+

+static AIR_CMD_T portSetCmds[] =

+{

+    {"matrix",      doPortSetMatrix,        2,                "port set matrix <port(0..6)> <matrix(6:0)>"},

+    {"vlanMode",    doPortSetVlanMode,      2,                "port set vlanMode <port(0..6)> <vlanMode(0:matrix,1:fallback,2:check,3:security)>"},

+    {"flowCtrl",    doFlowCtrl,             3,                "port set flowCtrl <port(0..6)> <dir(0:Tx,1:Rx)> <fc_en(1:En,0:Dis)>"},

+    {"jumbo",       doJumbo,                2,                "port set jumbo <pkt_len(0:1518,1:1536,2:1552,3:max)> <frame_len(2..15)>"},

+    {"anMode",      doAnMode,               2,                "port set anMode <port(0..4)> <en(0:force,1:AN)>"},

+    {"localAdv",    doLocalAdv,             7,                "port set localAdv <port(0..4)> <10H(1:En,0:Dis)> <10F(1:En,0:Dis)> <100H(1:En,0:Dis)> <100F(1:En,0:Dis)> <1000F(1:En,0:Dis)> <pause(1:En,0:Dis)>"},

+    {"speed",       doPortSpeed,            2,                "port set speed <port(0..4)> <speed(0:10M,1:100M,2:1G,3:2.5G)>"},

+    {"duplex",      doPortDuplex,           2,                "port set duplex <port(0..4)> <duplex(0:half,1:full)>"},

+    {"bckPres",     doPortBckPres,          2,                "port set bckPres <port(0..6)> <bckPres(1:En,0:Dis)>"},

+    {"psMode",      doPortPsMode,           3,                "port set psMode <port(0..4)> <ls(1:En,0:Dis)> <eee(1:En,0:Dis)>"},

+    {"smtSpdDwn",   doPortSmtSpdDwn,        3,                "port set smtSpdDwn <port(0..4)> <en(1:En,0:Dis)> <retry(2..5)>"},

+    {"spTag",       doPortSpTag,            2,                "port set spTag <port(0..6)> <en(1:En,0:Dis)>"},

+    {"enable",      doPortEnable,           2,                "port set enable <port(0..4)> <en(1:En,0:Dis)>"},

+    {"5GBaseRMode", doPort5GBaseRMode,      CMD_NO_PARA,      "port set 5GBaseRMode"},

+    {"hsgmiiMode",  doPortHsgmiiMode,       CMD_NO_PARA,      "port set hsgmiiMode"},

+    {"sgmiiMode",   doPortSgmiiMode,        2,                "port set sgmiiMode <mode(0:AN,1:Force)> <speed(0:10M,1:100M,2:1G)>"},

+    {"rmiiMode",    doPortRmiiMode,         1,                "port set rmiiMode <speed(0:10M,1:100M)>"},

+    {"rgmiiMode",   doPortRgmiiMode,        1,                "port set rgmiiMode <speed(0:10M,1:100M,2:1G)>"},

+

+    /* last entry, do not modify this entry */

+    {NULL, NULL, 0, NULL},

+};

+

+static AIR_CMD_T portGetCmds[] =

+{

+    {"matrix",      doPortGetMatrix,        1,                "port get matrix <port(0..6)>"},

+    {"vlanMode",    doPortGetVlanMode,      1,                "port get vlanMode <port(0..6)>"},

+    {"flowCtrl",    doFlowCtrl,             2,                "port get flowCtrl <port(0..6)> <dir(0:Tx,1:Rx)>"},

+    {"jumbo",       doJumbo,                CMD_NO_PARA,      "port get jumbo"},

+    {"anMode",      doAnMode,               1,                "port get anMode <port(0..4)>"},

+    {"localAdv",    doLocalAdv,             1,                "port get localAdv <port(0..4)>"},

+    {"remoteAdv",   doRemoteAdv,            1,                "port get remoteAdv <port(0..4)>"},

+    {"speed",       doPortSpeed,            1,                "port get speed <port(0..4)>"},

+    {"duplex",      doPortDuplex,           1,                "port get duplex <port(0..4)>"},

+    {"status",      doPortStatus,           1,                "port get status <port(0..4)>"},

+    {"bckPres",     doPortBckPres,          1,                "port get bckPres <port(0..6)>"},

+    {"psMode",      doPortPsMode,           1,                "port get psMode <port(0..4)>"},

+    {"smtSpdDwn",   doPortSmtSpdDwn,        1,                "port get smtSpdDwn <port(0..4)>"},

+    {"spTag",       doPortSpTag,            1,                "port get spTag <port(0..6)>"},

+    {"enable",      doPortEnable,           1,                "port get enable <port(0..4)>"},

+

+    /* last entry, do not modify this entry */

+    {NULL, NULL, 0, NULL},

+};

+

+static AIR_CMD_T portCmds[] =

+{

+    {"set",         doPortSet,      0,      NULL},

+    {"get",         doPortGet,      0,      NULL},

+

+    /* last entry, do not modify this entry */

+    {NULL, NULL, 0, NULL},

+};

+

+static AIR_CMD_T sptagCmds[] =

+{

+    {"setEnable",       doSptagEn,          2,      "sptag setEnable port<port(0..6)> enable<1:enable 0:disable>"},

+    {"getEnable",       doSptagEn,          1,      "sptag getEnable port<port(0..6)>"},

+    {"setmode",         doSptagMode,        2,      "sptag setmode port<port(0..6)> mode<0:inset 1:replace>"},

+    {"getmode",         doSptagMode,        1,      "sptag getmode port<port(0..6)>"},

+    {"encode",          doSptagEncode,      7,      "sptag encode mode={ insert | replace } opc={ portmap | portid | lookup } dp={bitimap hex} vpm={ untagged | 8100 | 88a8 } pri=<UINT> cfi=<UINT> vid=<UINT> "},

+    {"decode",          doSptagDecode,      4,      "sptag decode <byte(hex)> <byte(hex)> <byte(hex)> <byte(hex)>"},

+

+    /* last entry, do not modify this entry */

+    {NULL, NULL, 0, NULL},

+};

+

+static AIR_CMD_T vlanSetCmds[] =

+{

+    {"fid",                 doVlanSetFid,               2,      "vlan set fid <vid(0..4095)> <fid(0..7)>"},

+    {"memPort",             doVlanSetMemPort,           2,      "vlan set memPort <vid(0..4095)> <bitmap(6:0)>"},

+    {"ivl",                 doVlanSetIVL,               2,      "vlan set ivl <vid(0..4095)> <(1:En,0:Dis)>"},

+    {"portBaseStag",        doVlanSetPortBaseStag,      2,      "vlan set portBaseStag <vid(0..4095)> <(1:En,0:Dis)>"},

+    {"stag",                doVlanSetStag,              2,      "vlan set stag <vid(0..4095)> <stag(0..4095)>"},

+    {"egsTagCtlEn",         doVlanSetEgsTagCtlEn,       2,      "vlan set egsTagCtlEn <vid(0..4095)> <(1:En,0:Dis)>"},

+    {"egsTagCtlCon",        doVlanSetEgsTagCtlCon,      2,      "vlan set egsTagCtlCon <vid(0..4095)> <(1:En,0:Dis)>"},

+    {"egsTagCtl",           doVlanSetEgsTagCtl,         3,      "vlan set egsTagCtl <vid(0..4095)> <port(0..6)> <ctlType(0:untag,2:tagged)>"},

+

+    {"portActFrame",        doVlanSetPortActFrame,      2,      "vlan set portActFrame <port(0..6)> <frameType(0:all,1:tagged,2:untagged)>"},

+    {"leakyVlanEn",         doVlanSetLeakyVlanEn,       3,      "vlan set LeakyVlanEn <port(0..6)> <pktType(0:uc,1:mc,2:bc,3:ipmc)> <(1:En,0:Dis)>"},

+    {"portVlanAttr",        doVlanSetPortVlanAttr,      2,      "vlan set portVlanAttr <port(0..6)> <vlanAttr(0:user,1:stack,2:translation,3:transparent)>"},

+    {"igsPortETagAttr",     doVlanSetIgsPortETagAttr,   2,      "vlan set igsPortETagAttr <port(0..6)> <egsTagAttr(0:disable,1:consistent,4:untagged,5:swap,6:tagged,7:stack)>"},

+    {"portEgsTagAttr",      doVlanSetPortETagAttr,      2,      "vlan set portEgsTagAttr <port(0..6)> <egsTagAttr(0:untagged,1:swap,2:tagged,3:stack)>"},

+    {"portOuterTPID",       doVlanSetPortOuterTPID,     2,      "vlan set portOuterTPID <port(0..6)> <TPID(hex)>"},

+    {"pvid",                doVlanSetPvid,              2,      "vlan set pvid <port(0..6)> <vid(0..4095)>"},

+

+    /* last entry, do not modify this entry */

+    {NULL, NULL, 0, NULL},

+};

+

+static AIR_CMD_T vlanGetCmds[] =

+{

+    {"portActFrame",        doVlanGetPortActFrame,      1,      "vlan get portActFrame <port(0..6)>"},

+    {"leakyVlanEn",         doVlanGetLeakyVlanEn,       1,      "vlan get leakyVlanEn <port(0..6)>"},

+    {"portVlanAttr",        doVlanGetPortVlanAttr,      1,      "vlan get portVlanAttr <port(0..6)>"},

+    {"igsPortETagAttr",     doVlanGetIgsPortETagAttr,   1,      "vlan get igsPortETagAttr <port(0..6)>"},

+    {"portEgsTagAttr",      doVlanGetPortETagAttr,      1,      "vlan get portEgsTagAttr <port(0..6)>"},

+    {"portOuterTPID",       doVlanGetPortOuterTPID,     1,      "vlan get portOuterTPID <port(0..6)>"},

+    {"pvid",                doVlanGetPvid,              1,      "vlan get pvid <port(0..6)>"},

+

+    /* last entry, do not modify this entry */

+    {NULL, NULL, 0, NULL},

+};

+

+static AIR_CMD_T vlanCmds[] =

+{

+    {"initiate",        doVlanInitiate,         9,      "vlan initiate <vid(0..4095)> <fid(0..7)> <bitmap(6:0)> <ivl(1:En,0:Dis)> <portbasestag(1:En,0:Dis)> <stag(0..4095)> <egstagctlen(1:En,0:Dis)> <egstagcon(1:En,0:Dis)> <taggedbitmap(6:0)>"},

+    {"create",          doVlanCreate,           1,      "vlan create <vid(0..4095)>"},

+    {"destroy",         doVlanDestroy,          1,      "vlan destroy [ <vid(0..4095)> | <vidRange(vid0-vid1)> ]"},

+    {"destroyAll",      doVlanDestroyAll,       0,      "vlan destroyAll [ <restoreDefVlan(0:false,1:true)> | ]"},

+    {"dump",            doVlanDump,             0,      "vlan dump [ <vid(0..4095)> | <vidRange(vid0-vid1)> | ]"},

+    {"addPortMem",      doVlanAddPortMem,       2,      "vlan addPortMem <vid(0..4095)> <port(0..6)>"},

+    {"delPortMem",      doVlanDelPortMem,       2,      "vlan addPortMem <vid(0..4095)> <port(0..6)>"},

+    {"set",             doVlanSet,              0,      NULL},

+    {"get",             doVlanGet,              0,      NULL},

+

+    /* last entry, do not modify this entry */

+    {NULL, NULL, 0, NULL},

+};

+

+static AIR_CMD_T l2ClearCmds[] =

+{

+    {"mac",              doMacAddr,          CMD_NO_PARA,    "l2 clear mac"},

+    /* last entry, do not modify this entry */

+    {NULL, NULL, 0, NULL},

+};

+

+static AIR_CMD_T l2DelCmds[] =

+{

+    {"mac",             doMacAddr,           3,    "l2 del mac <mac(12'hex)> [ vid <vid(0..4095)> | fid <fid(0..15)> ]"},

+    /* last entry, do not modify this entry */

+    {NULL, NULL, 0, NULL},

+};

+

+static AIR_CMD_T l2AddCmds[] =

+{

+    {"mac",             doMacAddr,           7,    "l2 add mac <static(0:dynamic,1:static)> <unauth(0:auth,1:unauth)> <mac(12'hex)> <portlist(uintlist)> [ vid <vid(0..4095)> | fid <fid(0..15)> ] <src_mac_forward=(0:default,1:cpu-exclude,2:cpu-include,3:cpu-only,4:drop)>"},

+    /* last entry, do not modify this entry */

+    {NULL, NULL, 0, NULL},

+};

+

+static AIR_CMD_T l2SetCmds[] =

+{

+    {"macAddrAgeOut",   doMacAddrAgeOut,    1,    "l2 set macAddrAgeOut <time(1, 1000000)>"},

+    /* last entry, do not modify this entry */

+    {NULL, NULL, 0, NULL},

+};

+

+static AIR_CMD_T l2GetCmds[] =

+{

+    {"mac",             doGetMacAddr,       3,              "l2 get mac <mac(12'hex)> [ vid <vid(0..4095)> | fid <fid(0..15)> ]"},

+    {"macAddrAgeOut",   doMacAddrAgeOut,    CMD_NO_PARA,    "l2 get macAddrAgeOut"},

+    /* last entry, do not modify this entry */

+    {NULL, NULL, 0, NULL},

+};

+

+static AIR_CMD_T l2DumpCmds[] =

+{

+    {"mac",                doDumpMacAddr,        0,    "l2 dump mac"},

+    /* last entry, do not modify this entry */

+    {NULL, NULL, 0, NULL},

+};

+

+static AIR_CMD_T l2Cmds[] =

+{

+    {"add",         doL2Add,        0,        NULL},

+    {"del",         doL2Del,        0,        NULL},

+    {"clear",       doL2Clear,      0,        NULL},

+    {"get",         doL2Get,        0,        NULL},

+    {"set",         doL2Set,        0,        NULL},

+    {"dump",        doL2Dump,       0,        NULL},

+    /* last entry, do not modify this entry */

+    {NULL, NULL, 0, NULL},

+};

+

+static AIR_CMD_T lagGetCmds[] =

+{

+    {"member",      doLagMember,    1,              "lag get member group_id(0 or 1)"},

+    {"dstInfo",     doLagDstInfo,   CMD_NO_PARA,    "lag get dstInfo"},

+    {"ptseed",      doLagPtseed,    CMD_NO_PARA,    "lag get ptseed"},

+    {"hashtype",    doLagHashtype,  CMD_NO_PARA,    "lag get hashtype"},

+    {"state",       doLagState,     CMD_NO_PARA,    "lag get state"},

+    {"spsel",       doLagSpsel,     CMD_NO_PARA,    "lag get spsel"},

+    /* last entry, do not modify this entry */

+    {NULL, NULL, 0, NULL},

+};

+

+static AIR_CMD_T lagSetCmds[] =

+{

+    {"member",       doLagMember,        4,    "lag set member <group_id(0 or 1)> <member_index(0..3)> <enable(0,1)> <port index(0..6)>"},

+    {"dstInfo",      doLagDstInfo,       7,    "lag set dstInfo <sp(1:En,0:Dis)> <sa(1:En,0:Dis)> <da(1:En,0:Dis)> <sip(1:En,0:Dis)> <dip(1:En,0:Dis)> <sport(1:En,0:Dis)> <dport(1:En,0:Dis)>"},

+    {"ptseed",       doLagPtseed,        1,    "lag set ptseed <hex32>"},

+    {"hashtype",     doLagHashtype,      1,    "lag set hashtype <0-crc32lsb;1-crc32msb;2-crc16;3-xor4>"},

+    {"state",        doLagState,         1,    "lag set state <state(1:En,0:Dis)>"},

+    {"spsel",        doLagSpsel,         1,    "lag set spsel <soure port enable(1:En,0:Dis)>"},

+    /* last entry, do not modify this entry */

+    {NULL, NULL, 0, NULL},

+};

+

+static AIR_CMD_T lagCmds[] =

+{

+    {"get",          doLagGet,        0,        NULL},

+    {"set",          doLagSet,        0,        NULL},

+    /* last entry, do not modify this entry */

+    {NULL, NULL, 0, NULL},

+};

+

+static AIR_CMD_T stpGetCmds[] =

+{

+    {"portstate",    doStpPortstate,  2,    "stp get portstate <port(0..6)> <fid(0..15)>"},

+    {NULL, NULL, 0, NULL},

+};

+

+static AIR_CMD_T stpSetCmds[] =

+{

+    {"portstate",    doStpPortstate,  3,    "stp set portstate <port(0..6)> <fid(0..15)> <state(0:disable,1:listen,2:learn,3:forward)>"},

+    {NULL, NULL, 0, NULL},

+};

+

+static AIR_CMD_T stpCmds[] =

+{

+    {"get",         doStpGet,           0,      NULL},

+    {"set",         doStpSet,           0,      NULL},

+    /* last entry, do not modify this entry */

+    {NULL, NULL, 0, NULL},

+};

+

+static AIR_CMD_T mirrorSetCmds[] =

+{

+    {"session",        doMirrorSetSession,       6,      "mirror set session <sid(0,1)> <dst_port(UINT)> <state(1:En,0:Dis)> <tag(1:on, 0:off)> <list(UINTLIST)> <dir(0:none,1:tx,2:rx,3:both)>"},

+    {"session-enable", doMirrorSetSessionEnable, 2,      "mirror set session-enable <sid(0,1)> <state(1:En,0:Dis)>"},

+    /* last entry, do not modify this entry */

+    {NULL, NULL, 0, NULL},

+};

+

+static AIR_CMD_T mirrorAddCmds[] =

+{

+    {"session-rlist",  doMirrorAddRlist,       2,      "mirror add session-rlist <sid(0,1)> <list(UINTLIST)>"},

+    {"session-tlist",  doMirrorAddTlist,       2,      "mirror add session-tlist <sid(0,1)> <list(UINTLIST)>"},

+    /* last entry, do not modify this entry */

+    {NULL, NULL, 0, NULL},

+};

+

+static AIR_CMD_T mirrorGetCmds[] =

+{

+    {"session",        doMirrorGetSid,       1,      "mirror get session <sid(0,1)>"},

+    /* last entry, do not modify this entry */

+    {NULL, NULL, 0, NULL},

+};

+

+static AIR_CMD_T mirrorDelCmds[] =

+{

+    {"session",        doMirrorDelSid,       1,      "mirror del session <sid(0,1)>"},

+    /* last entry, do not modify this entry */

+    {NULL, NULL, 0, NULL},

+};

+

+static AIR_CMD_T mirrorCmds[] =

+{

+    {"set",         doMirrorSet,        0,      NULL},

+    {"add",         doMirrorAdd,        0,      NULL},

+    {"get",         doMirrorGet,        0,      NULL},

+    {"del",         doMirrorDel,        0,      NULL},

+    /* last entry, do not modify this entry */

+    {NULL, NULL, 0, NULL},

+};

+

+static AIR_CMD_T mibClearCmds[] =

+{

+    {"port",        doMibClearPort,     1,      "mib clear port <port(0..6)>"},

+    {"all",         doMibClearPort,     0,      "mib clear all"},

+    {"acl",         doMibClearAcl,      0,      "mib clear acl"},

+    /* last entry, do not modify this entry */

+    {NULL, NULL, 0, NULL},

+};

+

+static AIR_CMD_T mibGetCmds[] =

+{

+    {"port",        doMibGetPort,       1,      "mib get port <port(0..6)>"},

+    {"acl",         doMibGetAcl,        1,      "mib get acl <event(0..7)>"},

+    /* last entry, do not modify this entry */

+    {NULL, NULL, 0, NULL},

+};

+

+static AIR_CMD_T mibCmds[] =

+{

+    {"clear",       doMibClear,         0,      NULL},

+    {"get",         doMibGet,           0,      NULL},

+    /* last entry, do not modify this entry */

+    {NULL, NULL, 0, NULL},

+};

+

+static AIR_CMD_T qosGetCmds[] =

+{

+    {"scheduleAlgo",    doQosScheduleAlgo,      2,  "qos get scheduleAlgo <portlist(UINTLIST)> <queue(UINT)>"},

+    {"trustMode",       doQosTrustMode,         1,  "qos get trustMode <portlist(UINTLIST)>"},

+    {"pri2Queue",       doQosPri2Queue,         0,  "qos get pri2Queue"},

+    {"dscp2Pri",        doQosDscp2Pri,          1,  "qos get dscp2Pri <dscp(0..63)>"},

+    {"rateLimitEnable", doQosRateLimitEnable,   1,  "qos get rateLimitEnable <portlist(UINTLIST)>"},

+    {"rateLimit",       doQosRateLimit,         1,  "qos get rateLimit <portlist(UINTLIST)>"},

+    {"portPriority",    doQosPortPriority,      1,  "qos get portPriority <portlist(UINTLIST)>"},

+    {"rateLmtExMngFrm", doQosRateLimitExMngFrm, 0,  "qos get rateLmtExMngFrm"},

+    {NULL, NULL, 0, NULL},

+};

+

+static AIR_CMD_T qosSetCmds[] =

+{

+    {"scheduleAlgo",    doQosScheduleAlgo,      4,  "qos set scheduleAlgo <portlist(UINTLIST)> <queue(UINT)> <scheduler(0:SP,1:WRR,2:WFQ)> <weight(0..128)>, weight 0 is valid only on sp mode"},

+    {"trustMode",       doQosTrustMode,         2,  "qos set trustMode <portlist(UINTLIST)> <mode(0:port,1:1p-port,2:dscp-port,3:dscp-1p-port>"},

+    {"pri2Queue",       doQosPri2Queue,         2,  "qos set pri2Queue <priority(0..7)> <queue(0..7)>"},

+    {"dscp2Pri",        doQosDscp2Pri,          2,  "qos set dscp2Pri <dscp(0..63)> <priority(0..7)>"},

+    {"rateLimitEnable", doQosRateLimitEnable,   3,  "qos set rateLimitEnable <portlist(UINTLIST)> <dir(0:egress,1:ingress)> <rate_en(1:En,0:Dis)>"},

+    {"rateLimit",       doQosRateLimit,         5,  "qos set rateLimit <portlist(UINTLIST)> <I_CIR(0..80000)> <I_CBS(0..127)> <E_CIR(0..80000)> <E_CBS(0..127)>"},

+    {"portPriority",    doQosPortPriority,      2,  "qos set portPriority <portlist(UINTLIST)> <priority(0..7)>"},

+    {"rateLmtExMngFrm", doQosRateLimitExMngFrm, 2,  "qos set rateLmtExMngFrm <dir(0:egress)> <en(0:include,1:exclude)>"},

+    {NULL, NULL, 0, NULL},

+};

+

+static AIR_CMD_T qosCmds[] =

+{

+    {"get",          doQosGet,        0,        NULL},

+    {"set",          doQosSet,        0,        NULL},

+    /* last entry, do not modify this entry */

+    {NULL, NULL, 0, NULL},

+};

+

+static AIR_CMD_T diagSetCmds[] =

+{

+    {"txComply",    doDiagTxComply,     2,      "diag set txComply <phy(0..5)> <mode(0..8)>"},

+    /* last entry, do not modify this entry */

+    {NULL, NULL, 0, NULL},

+};

+

+static AIR_CMD_T diagGetCmds[] =

+{

+    {"txComply",    doDiagTxComply,     1,      "diag get txComply <phy(0..5)>"},

+    /* last entry, do not modify this entry */

+    {NULL, NULL, 0, NULL},

+};

+

+static AIR_CMD_T diagCmds[] =

+{

+    {"set",         doDiagSet,          0,      NULL},

+    {"get",         doDiagGet,          0,      NULL},

+    /* last entry, do not modify this entry */

+    {NULL, NULL, 0, NULL},

+};

+

+static AIR_CMD_T ledSetCmds[] =

+{

+    {"mode",        doLedMode,          1,      "led set mode <mode(0:disable, 1..3:2 LED, 4:user-define)>"},

+    {"state",       doLedState,         2,      "led set state <led(0..1)> <state(1:En,0:Dis)>"},

+    {"usr",         doLedUsrDef,        4,      "led set usr <led(0..1)> <polarity(0:low, 1:high)> <on_evt(7'bin)> <blink_evt(10'bin)>"},

+    {"time",        doLedBlkTime,       1,      "led set time <time(0..5:32ms~1024ms)>"},

+    /* last entry, do not modify this entry */

+    {NULL, NULL, 0, NULL},

+};

+

+static AIR_CMD_T ledGetCmds[] =

+{

+    {"mode",        doLedMode,          CMD_NO_PARA,      "led get mode"},

+    {"state",       doLedState,         1,                "led get state <led(0..1)>"},

+    {"usr",         doLedUsrDef,        1,                "led get usr <led(0..1)>"},

+    {"time",        doLedBlkTime,       CMD_NO_PARA,      "led get time"},

+    /* last entry, do not modify this entry */

+    {NULL, NULL, 0, NULL},

+};

+

+static AIR_CMD_T ledCmds[] =

+{

+    {"set",         doLedSet,           0,      NULL},

+    {"get",         doLedGet,           0,      NULL},

+    /* last entry, do not modify this entry */

+    {NULL, NULL, 0, NULL},

+};

+

+static AIR_CMD_T showCmds[] =

+{

+    {"version",     doShowVersion,        0,        NULL},

+    /* last entry, do not modify this entry */

+    {NULL, NULL, 0, NULL},

+};

+

+static AIR_CMD_T secGetCmds[] =

+{

+    {"stormEnable",     doStormEnable,   2,  "sec get stormEnable <port(0..6)> <type(0:bcst,1:mcst,2:ucst)>"},

+    {"stormRate",       doStormRate,     2,  "sec get stormRate <port(0..6)> <type(0:bcst,1:mcst,2:ucst)>"},

+    {"fldMode",         doFldMode,       2,  "sec get fldMode <port(0..6)> <type(0:bcst,1:mcst,2:ucst,3:qury>"},

+    {"saLearning",      doSaLearning,    1,  "sec get saLearning <port(0..6)>"},

+    {"saLimit",         doSaLimit,       1,  "sec get saLimit <port(0..6)>"},

+    {NULL, NULL, 0, NULL},

+};

+

+static AIR_CMD_T secSetCmds[] =

+{

+    {"stormEnable",     doStormEnable,   3,  "sec set stormEnable <port(0..6)> <type(0:bcst,1:mcst,2:ucst)> <en(1:En,0:Dis)>"},

+    {"stormRate",       doStormRate,     4,  "sec set stormRate <port(0..6)> <type(0:bcst,1:mcst,2:ucst)> <count(0..255)> <unit(0:64k,1:256k,2:1M,3:4M,4:16M)>"},

+    {"fldMode",         doFldMode,       3,  "sec set fldMode <port(0..6)> <type(0:bcst,1:mcst,2:ucst,3:qury> <en(1:En,0:Dis)>"},

+    {"saLearning",      doSaLearning,    2,  "sec set saLearning <port(0..6)> <learn(0:disable,1:enable)>"},

+    {"saLimit",         doSaLimit,       3,  "sec set saLimit <port(0..6)> <mode(0:disable,1:enable)> <count(0..4095)>"},

+    {NULL, NULL, 0, NULL},

+};

+

+static AIR_CMD_T secCmds[] =

+{

+    {"get",          doSecGet,        0,        NULL},

+    {"set",          doSecSet,        0,        NULL},

+    /* last entry, do not modify this entry */

+    {NULL, NULL, 0, NULL},

+};

+

+static AIR_CMD_T switchSetCmds[] =

+{

+    {"cpuPortEn",   doSwitchCpuPortEn,   1,              "switch set cpuPortEn <cpu_en(1:En,0:Dis)>"},

+    {"cpuPort",     doSwitchCpuPort,     1,              "switch set cpuPort <port_number>"},

+    {"phyLCIntrEn",     doSwitchPhyLCIntrEn,     2,      "switch set phyLCIntrEn <phy(0..6)> <(1:En,0:Dis)>"},

+    {"phyLCIntrSts",    doSwitchPhyLCIntrSts,    2,      "switch set phyLCIntrSts <phy(0..6)> <(1:Clear)>"},

+    /* last entry, do not modify this entry */

+    {NULL, NULL, 0, NULL},

+};

+

+static AIR_CMD_T switchGetCmds[] =

+{

+    {"cpuPortEn",   doSwitchCpuPortEn,   CMD_NO_PARA,      "switch get cpuPortEn"},

+    {"cpuPort",     doSwitchCpuPort,     CMD_NO_PARA,      "switch get cpuPort"},

+    {"phyLCIntrEn",     doSwitchPhyLCIntrEn,     1,        "switch get phyLCIntrEn <phy(0..6)>"},

+    {"phyLCIntrSts",    doSwitchPhyLCIntrSts,    1,        "switch get phyLCIntrSts <phy(0..6)>"},

+    /* last entry, do not modify this entry */

+    {NULL, NULL, 0, NULL},

+};

+

+static AIR_CMD_T switchCmds[] =

+{

+    {"set",         doSwitchSet,        0,      NULL},

+    {"get",         doSwitchGet,        0,      NULL},

+    /* last entry, do not modify this entry */

+    {NULL, NULL, 0, NULL},

+};

+

+static AIR_CMD_T aclSetCmds[] =

+{

+    {"en",              doAclEn,            1,                     "acl set en <en(1:En,0:Dis)>"},

+    {"rule",            doAclRule,          CMD_VARIABLE_PARA,     "acl set rule <idx(0..127)>\n <state(0:Dis,1:En)> <reverse(0:Dis,1:En)> <end(0:Dis,1:En)>\n <portmap(7'bin)><ipv6(0:Dis,1:En,2:Not care)>\n[ dmac <dmac(12'hex)> <dmac_mask(12'hex)> ]\n[ smac <smac(12'hex)> <smac_mask(12'hex)> ]\n[ stag <stag(4'hex)> <stag_mask(4'hex)> ]\n[ ctag <ctag(4'hex)> <ctag_mask(4'hex)> ]\n[ etype <etype(4'hex)> <etype_mask(4'hex)> ]\n[ dip <dip(IPADDR)> <dip_mask(IPADDR)> ]\n[ sip <sip(IPADDR)> <sip_mask(IPADDR)> ]\n[ dscp <dscp(2'hex)> <dscp_mask(2'hex)> ]\n[ protocol <protocol(12'hex)> <protocol_mask(12'hex)> ]\n[ dport <dport(4'hex)> <dport_mask(4'hex)> ]\n[ sport <sport(4'hex)> <sport_mask(4'hex)> ]\n[ flow_label <flow_label(4'hex)> <flow_label_mask(4'hex)> ]\n[ udf <udf(4'hex)> <udf_mask(4'hex)> ] "},

+    {"udfRule",         doAclUdfRule,       7,                     "acl set udfRule <idx(0..15)> <mode(0:pattern, 1:threshold)> [ <pat(4'hex)> <mask(4'hex)> | <low(4'hex)> <high(4'hex)> ] <start(0:MAC header, 1:L2 payload, 2:IPv4 header, 3:IPv6 header, 4:L3 payload, 5:TCP header, 6:UDP header, 7: L4 payload)> <offset(0..127,unit:2 bytes)> <portmap(7'bin)>"},

+    {"action",          doAclAction,        CMD_VARIABLE_PARA,     "acl set action <idx(0..127)> \n[ forward <forward(0:Default,4:Exclude CPU,5:Include CPU,6:CPU only,7:Drop)> ]\n[ egtag <egtag(0:Default,1:Consistent,4:Untag,5:Swap,6:Tag,7:Stack)> ]\n[ mirrormap <mirrormap(2'bin)> ]\n[ priority <priority(0..7)> ]\n[ redirect <redirect(0:Dst,1:Vlan)> <portmap(7'bin)> ]\n[ leaky_vlan <leaky_vlan(1:En,0:Dis)> ]\n[ cnt_idx <cnt_idx(0..63)> ]\n[ rate_idx <rate_idx(0..31)> ] \n[ attack_idx <attack_idx(0..95)> ] \n[ vid <vid(0..4095)> ] \n[ manage <manage(1:En,0:Dis)> ] \n[ bpdu <bpdu(1:En,0:Dis)> ]\n[ class <class(0:Original,1:Defined)>[0..7] ]\n[ drop_pcd <drop_pcd(0:Original,1:Defined)> [red <red(0..7)>][yellow <yellow(0..7)>][green <green(0..7)>] ]\n[ color <color(0:Defined,1:Trtcm)> [ <defined_color(0:Dis,1:Green,2:Yellow,3:Red)> | <trtcm_idx(0..31)> ] ]"},

+    {"trtcm",           doAclTrtcm,         5,                     "acl set trtcm <idx(1..31)> <cir(4'hex)> <pir(4'hex)> <cbs(4'hex)> <pbs(4'hex)>"},

+    {"trtcmEn",         doAclTrtcmEn,       1,                     "acl set trtcmEn <en(1:En,0:Dis)>"},

+    {"portEn",          doAclPortEn,        2,                     "acl set portEn <port(0..6)> <en(1:En,0:Dis)>"},

+    {"dropEn",          doAclDropEn,        2,                     "acl set dropEn <port(0..6)> <en(1:En,0:Dis)>"},

+    {"dropThrsh",       doAclDropThrsh,     5,                     "acl set dropThrsh <port(0..6)> <color(0:green,1:yellow,2:red)> <queue(0..7)> <high(0..2047)> <low(0..2047)>"},

+    {"dropPbb",         doAclDropPbb,       4,                     "acl set dropPbb <port(0..6)> <color(0:green,1:yellow,2:red)> <queue(0..7)> <probability(0..1023)>"},

+    {"meter",           doAclMeter,         3,                     "acl set meter <idx(0..31)> <en(1:En,0:Dis)> <rate(0..65535)>\n Note: Limit rate = rate * 64Kbps"},

+    /* last entry, do not modify this entry */

+    {NULL, NULL, 0, NULL},

+};

+

+static AIR_CMD_T aclGetCmds[] =

+{

+    {"en",              doAclEn,            CMD_NO_PARA,    "acl get en"},

+    {"rule",            doAclRule,          1,              "acl get rule <idx(0..127)> "},

+    {"udfRule",         doAclUdfRule,       1,              "acl get udfRule <idx(0..15)>"},

+    {"action",          doAclAction,        1,              "acl get action <idx(0..127)>"},

+    {"trtcm",           doAclTrtcm,         1,              "acl get trtcm <idx(1..31)>"},

+    {"trtcmEn",         doAclTrtcmEn,       CMD_NO_PARA,    "acl get trtcmEn"},

+    {"portEn",          doAclPortEn,        1,              "acl get portEn <port(0..6)>"},

+    {"dropEn",          doAclDropEn,        1,              "acl get dropEn <port(0..6)>"},

+    {"dropThrsh",       doAclDropThrsh,     3,              "acl get dropThrsh <port(0..6)> <color(0:green,1:yellow,2:red)> <queue(0..7)>"},

+    {"dropPbb",         doAclDropPbb,       3,              "acl get dropPbb <port(0..6)> <color(0:green,1:yellow,2:red)> <queue(0..7)>"},

+    {"meter",           doAclMeter,         1,              "acl get meter <idx(0..31)>"},

+    /* last entry, do not modify this entry */

+    {NULL, NULL, 0, NULL},

+};

+

+static AIR_CMD_T aclDelCmds[] =

+{

+    {"rule",        doAclRmvRule,          1,         "acl del rule <idx(0..127)>"},

+    {"udfRule",     doAclRmvUdfRule,       1,         "acl del udfRule <idx(0..15)>"},

+    {"action",      doAclRmvAction,        1,         "acl del action <idx(0..127)>"},

+    {"trtcm",       doAclRmvTrtcm,         1,         "acl del trtcm <idx(0..31)>"},

+    /* last entry, do not modify this entry */

+    {NULL, NULL, 0, NULL},

+};

+

+static AIR_CMD_T aclClearCmds[] =

+{

+    {"rule",        doAclRmvRule,          CMD_NO_PARA,       "acl clear rule"},

+    {"udfRule",     doAclRmvUdfRule,       CMD_NO_PARA,       "acl clear udfRule"},

+    {"action",      doAclRmvAction,        CMD_NO_PARA,       "acl clear action"},

+    {"trtcm",       doAclRmvTrtcm,         CMD_NO_PARA,       "acl clear trtcm"},

+    /* last entry, do not modify this entry */

+    {NULL, NULL, 0, NULL},

+};

+

+static AIR_CMD_T aclCmds[] =

+{

+    {"set",         doAclSet,           0,      NULL},

+    {"get",         doAclGet,           0,      NULL},

+    {"del",         doAclDel,           0,      NULL},

+    {"clear",       doAclClear,         0,      NULL},

+    {"dump",        doAclDump,          0,      NULL},

+    /* last entry, do not modify this entry */

+    {NULL, NULL, 0, NULL},

+};

+

+static AIR_CMD_T Cmds[] =

+{

+    {"reg",         doReg,          0,      NULL},

+    {"phy",         doPhy,          0,      NULL},

+    {"port",        doPort,         0,      NULL},

+    {"vlan",        doVlan,         0,      NULL},

+    {"l2",          doL2,           0,      NULL},

+    {"lag",         doLag,          0,      NULL},

+    {"stp",         doStp,          0,      NULL},

+    {"mirror",      doMirror,       0,      NULL},

+    {"mib",         doMib,          0,      NULL},

+    {"qos",         doQos,          0,      NULL},

+    {"diag",        doDiag,         0,      NULL},

+    {"led",         doLed,          0,      NULL},

+    {"switch",      doSwitch,       0,      NULL},

+    {"show",        doShow,         0,      NULL},

+    {"sec",         doSec,          0,      NULL},

+    {"acl",         doAcl,          0,      NULL},

+    {"sptag",       doSptag,        0,      NULL},

+

+    /* last entry, do not modify this entry */

+    {NULL, NULL, 0, NULL},

+};

+

+/* EXPORTED SUBPROGRAM BODIES

+*/

+

+/* LOCAL SUBPROGRAM BODIES

+*/

+static BOOL_T

+_strcmp(const char *s1, const char *s2)

+{

+    while(*s1 == *s2++)

+        if (*s1++ == '\0')

+            return (0);

+    return (*(const unsigned char *)s1 - *(const unsigned char *)(s2 -1));

+}

+

+static C8_T *

+_strtok_r(

+    C8_T *s,

+    const C8_T *delim,

+    C8_T **last)

+{

+    char *spanp;

+    int c = 0, sc = 0;

+    char *tok;

+

+    if (s == NULL && (s = *last) == NULL)

+    {

+        return (NULL);

+    }

+

+    /*

+     * Skip (span) leading delimiters (s += strspn(s, delim), sort of).

+     */

+    for (;;)

+    {

+        c = *s++;

+        spanp = (char *)delim;

+        do

+        {

+            if (c == (sc = *spanp++))

+            {

+                break;

+            }

+        } while (sc != 0);

+        if (sc == 0)

+        {

+            break;

+        }

+    }

+

+    if (c == 0)

+    {   /* no non-delimiter characters */

+        *last = NULL;

+        return (NULL);

+    }

+    tok = s - 1;

+

+    /*

+     * Scan token (scan for delimiters: s += strcspn(s, delim), sort of).

+     * Note that delim must have one NUL; we stop if we see that, too.

+     */

+    for (;;)

+    {

+        c = *s++;

+        spanp = (char *)delim;

+        do

+        {

+            if ((sc = *spanp++) == c)

+            {

+                if (c == 0)

+                {

+                    s = NULL;

+                }

+                else

+                {

+                    s[-1] = 0;

+                }

+                *last = s;

+                return (tok);

+            }

+        } while (sc != 0);

+    }

+    /* NOTREACHED */

+}

+

+static C8_T *

+_strtok(

+    C8_T *s,

+    const C8_T *delim,

+    C8_T **last)

+{

+    return _strtok_r(s, delim, last);

+}

+

+UI32_T

+_strtoul(

+    const C8_T *cp,

+    C8_T **endp,

+    UI32_T base)

+{

+    UI32_T result = 0, value = 0;

+

+    if (!base)

+    {

+        base = 10;

+        if (*cp == '0')

+        {

+            base = 8;

+            cp++;

+            if ((TOLOWER(*cp) == 'x') && isxdigit(cp[1]))

+            {

+                cp++;

+                base = 16;

+            }

+        }

+    }

+    else if (base == 16)

+    {

+        if (cp[0] == '0' && TOLOWER(cp[1]) == 'x')

+        {

+            cp += 2;

+        }

+    }

+    while (isxdigit(*cp) &&

+           (value = isdigit(*cp) ? *cp-'0' : TOLOWER(*cp)-'a'+10) < base)

+    {

+        result = result*base + value;

+        cp++;

+    }

+    if (endp)

+    {

+        *endp = (char *)cp;

+    }

+    return result;

+}

+

+static I32_T

+_strtol(

+    const C8_T *cp,

+    C8_T **endp,

+    UI32_T base)

+{

+    if(*cp=='-')

+    {

+        return -_strtoul(cp + 1, endp, base);

+    }

+    return _strtoul(cp, endp, base);

+}

+

+static AIR_ERROR_NO_T

+_str2mac(

+        C8_T *str,

+        C8_T *mac)

+{

+    UI32_T i = 0;

+    C8_T tmpstr[3];

+

+    /* check str */

+    AIR_CHECK_PTR(str);

+    AIR_PARAM_CHK(strlen(str) != AIR_MAC_LEN, AIR_E_BAD_PARAMETER);

+    AIR_CHECK_PTR(mac);

+

+    for(i=0; i<6; i++)

+    {

+        strncpy(tmpstr, str+(i*2), 2);

+        tmpstr[2] = '\0';

+        mac[i] = _strtoul(tmpstr, NULL, 16);

+    }

+

+    return AIR_E_OK;

+}

+

+static AIR_ERROR_NO_T

+_str2ipv4(

+    const C8_T *ptr_str,

+    UI32_T     *ptr_addr)

+{

+    UI32_T value = 0, idx = 0, shift = 0;

+

+    AIR_CHECK_PTR(ptr_str);

+    AIR_CHECK_PTR(ptr_addr);

+

+    /* e.g. 192.168.1.2, strlen = 11 */

+    for (idx = 0; idx < strlen(ptr_str); idx++)

+    {

+        if (('0' <= ptr_str[idx]) && ('9' >= ptr_str[idx]))

+        {

+            value = (value * 10) + (ptr_str[idx] - '0');

+        }

+        else if ('.' == ptr_str[idx])

+        {

+            CMD_CHECK_PARA(value, <, 256); /* Error: invalid value */

+            CMD_CHECK_PARA(shift, <, 4);   /* Error: mem-overwrite */

+            *ptr_addr |= value << (24 - shift * 8);

+            shift += 1;

+            value = 0;

+        }

+        else

+        {

+            return AIR_E_BAD_PARAMETER; /* Error: not a digit number or dot */

+        }

+    }

+    CMD_CHECK_PARA(value, <, 256); /* Error: invalid value */

+    CMD_CHECK_PARA(shift, ==, 3);  /* Error: not an ipv4 addr */

+    *ptr_addr |= value << (24 - shift * 8);

+

+    return AIR_E_OK;

+}

+

+AIR_ERROR_NO_T

+_str2ipv6(

+    const C8_T  *ptr_str,

+    UI8_T       *ptr_addr)

+{

+    UI32_T              hex_value = 0, dec_value = 0, idx = 0;

+    BOOL_T              double_colon = FALSE, ipv4_compatible = FALSE;

+    UI32_T              double_colon_pos = 0, last_pos = 0;

+    UI8_T               tmp_ipv6[16] = {0};

+

+    AIR_CHECK_PTR(ptr_str);

+    AIR_CHECK_PTR(ptr_addr);

+

+    /* e.g. invalid:

+     * 3ffe::c0a8:0:      last cannot be colon except double-colon

+     * 3ffe:::c0a8:0      triple-colon

+     * 3ffe::c0a8::0      two double-colons

+     */

+

+    /* e.g. valid:

+     * 3ffe::c0a8:0       strlen = 12 (double-colon in middle)

+     * 3ffe:c0a8:0::      strlen = 13 (double-colon in last)

+     * ::3ffe:c0a8:0      strlen = 13 (double-colon in first)

+     * 3ffe::192.168.0.0  strlen = 17 (IPv4-compatible address)

+     */

+    for (idx = 0; idx < strlen(ptr_str); idx++)

+    {

+        if (('0' <= ptr_str[idx]) && ('9' >= ptr_str[idx]))

+        {

+            hex_value = (hex_value << 4) + (ptr_str[idx] - '0');

+            dec_value = (dec_value * 10) + (ptr_str[idx] - '0');

+        }

+        else if (('a' <= ptr_str[idx]) && ('f' >= ptr_str[idx]))

+        {

+            hex_value = (hex_value << 4) + (ptr_str[idx] - 'a') + 10;

+        }

+        else if (('A' <= ptr_str[idx]) && ('F' >= ptr_str[idx]))

+        {

+            hex_value = (hex_value << 4) + (ptr_str[idx] - 'A') + 10;

+        }

+        else if (':' == ptr_str[idx])

+        {

+            /* must belong to double-colon, calculate from last */

+            if (0 == idx)

+            {

+                continue;

+            }

+            /* not the first ch but a double-colon */

+            else if (':' == ptr_str[idx - 1])

+            {

+                CMD_CHECK_PARA(double_colon, ==, FALSE); /* Error: triple-colon or two double-colons */

+                double_colon = TRUE;

+            }

+            /* not the first ch and a double-colon */

+            else

+            {

+                CMD_CHECK_PARA(double_colon_pos, <, 15); /* Error: only 16 units for UI8_T  */

+                CMD_CHECK_PARA(last_pos,         <, 15); /* Error: only 16 units for UI8_T  */

+                tmp_ipv6[last_pos]     = (UI8_T)((hex_value >> 8) & 0xff);

+                tmp_ipv6[last_pos + 1] = (UI8_T)((hex_value >> 0) & 0xff);

+                double_colon_pos += (FALSE == double_colon)? 2 : 0;

+                last_pos += 2;

+                hex_value = 0;

+                dec_value = 0;

+            }

+        }

+        else if ('.' == ptr_str[idx])

+        {

+            CMD_CHECK_PARA(last_pos, <, 16); /* Error: only 16 units for UI8_T  */

+            tmp_ipv6[last_pos] = dec_value;

+            last_pos += 1;

+            dec_value = 0;

+            ipv4_compatible = TRUE;

+        }

+        else

+        {

+            return AIR_E_BAD_PARAMETER; /* Error: not a hex number or colon */

+        }

+    }

+

+    /* last data */

+    if (':' != ptr_str[idx - 1])

+    {

+        if (FALSE == ipv4_compatible)

+        {

+            CMD_CHECK_PARA(last_pos, <, 15); /* Error: only 16 units for UI8_T  */

+            tmp_ipv6[last_pos]     = (UI8_T)((hex_value >> 8) & 0xff);

+            tmp_ipv6[last_pos + 1] = (UI8_T)((hex_value >> 0) & 0xff);

+            last_pos += 2;

+        }

+        else

+        {

+            CMD_CHECK_PARA(last_pos, <, 16); /* Error: only 16 units for UI8_T  */

+            tmp_ipv6[last_pos] = dec_value;

+            last_pos += 1;

+        }

+    }

+    else

+    {

+        if (':' != ptr_str[idx - 2])

+        {

+            return AIR_E_BAD_PARAMETER; /* Error: last cannot be colon except double-colon */

+        }

+    }

+

+    /* move tmp_ipv6 to ptr_value */

+    if (TRUE == double_colon)

+    {

+        /* e.g.

+         * 3ffe::c0a8:0       double_colon_pos = 2, last_pos = 4+2, tmp_ipv6 = {3f,fe,c0,a8,00,00,...}

+         * 3ffe:c0a8:0::      double_colon_pos = 6, last_pos = 6,   tmp_ipv6 = {3f,fe,c0,a8,00,00,...}

+         * ::3ffe:c0a8:0      double_colon_pos = 0, last_pos = 4+2, tmp_ipv6 = {3f,fe,c0,a8,00,00,...}

+         * 3ffe::192.168.0.0  double_colon_pos = 2, last_pos = 5+1, tmp_ipv6 = {3f,fe,c0,a8,00,00,...}

+         *

+         *                                 0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f

+         * 3ffe::c0a8:0       ptr_value = {3f,fe,--,--,--,--,--,--,--,--,--,--,--,--,--,--}

+         * 3ffe:c0a8:0::      ptr_value = {3f,fe,c0,a8,00,00,--,--,--,--,--,--,--,--,--,--}

+         * ::3ffe:c0a8:0      ptr_value = {--,--,--,--,--,--,--,--,--,--,--,--,--,--,--,--}

+         * 3ffe::192.168.0.0  ptr_value = {3f,fe,--,--,--,--,--,--,--,--,--,--,--,--,--,--}

+         */

+        for (idx = 0; idx < double_colon_pos; idx++)

+        {

+            ptr_addr[idx] = tmp_ipv6[idx];

+        }

+        /* e.g.

+         *                                 0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f

+         * 3ffe::c0a8:0       ptr_value = {3f,fe,--,--,--,--,--,--,--,--,--,--,c0,a8,00,00}

+         * 3ffe:c0a8:0::      ptr_value = {3f,fe,c0,a8,00,00,--,--,--,--,--,--,--,--,--,--}

+         * ::3ffe:c0a8:0      ptr_value = {--,--,--,--,--,--,--,--,--,--,3f,fe,c0,a8,00,00}

+         * 3ffe::192.168.0.0  ptr_value = {3f,fe,--,--,--,--,--,--,--,--,--,--,c0,a8,00,00}

+         */

+        for (idx = double_colon_pos; idx < last_pos; idx++)

+        {

+            ptr_addr[16 - (last_pos - idx)] = tmp_ipv6[idx];

+        }

+    }

+    else

+    {

+        for (idx = 0; idx < 16; idx++)

+        {

+            ptr_addr[idx] = tmp_ipv6[idx];

+        }

+    }

+

+    return AIR_E_OK;

+}

+

+void

+_showIpv6Str(

+    const UI8_T *ptr_ipv6,

+    C8_T *ptr_str)

+{

+    UI32_T idx = 0, next = 0, last = 16;

+    UI32_T cont_zero = 0;

+

+    while (idx < last)

+    {

+        if ((0 == cont_zero) && (0 == ptr_ipv6[idx]) && (0 == ptr_ipv6[idx + 1]))

+        {

+            next = idx + 2;

+

+            while (next < last)

+            {

+                if ((ptr_ipv6[next]) || (ptr_ipv6[next + 1]))

+                {

+                    AIR_PRINT(

+                            ptr_str + strlen(ptr_str),

+                            40 - strlen(ptr_str),

+                            "%s", (cont_zero) ? (":") : (":0"));

+                    break;

+                }

+

+                if (0 == cont_zero)

+                {

+                    cont_zero = 1;

+                }

+                next += 2;

+            }

+

+            if (next == last)

+            {

+

+                AIR_PRINT(

+                        ptr_str + strlen(ptr_str),

+                        40 - strlen(ptr_str),

+                        "%s", (cont_zero) ? ("::") : (":0"));

+            }

+

+            idx = next;

+        }

+        else

+        {

+            if (idx)

+            {

+                AIR_PRINT(

+                    ptr_str + strlen(ptr_str),

+                    40 - strlen(ptr_str),

+                    ":");

+            }

+

+            if (ptr_ipv6[idx])

+            {

+                AIR_PRINT(

+                    ptr_str + strlen(ptr_str),

+                    40 - strlen(ptr_str),

+                    "%0x%02x", ptr_ipv6[idx], ptr_ipv6[idx + 1]);

+            }

+            else

+            {

+                AIR_PRINT(

+                    ptr_str + strlen(ptr_str),

+                    40 - strlen(ptr_str),

+                    "%0x", ptr_ipv6[idx + 1]);

+            }

+

+            idx += 2;

+        }

+    }

+}

+

+static AIR_ERROR_NO_T

+_hex2bit(

+        const UI32_T hex,

+        UI32_T *ptr_bit)

+{

+    UI32_T i = 0;

+

+    /* Mistake proofing */

+    AIR_CHECK_PTR(ptr_bit);

+

+    (*ptr_bit) = 0;

+    for(i=0; i<AIR_MAX_NUM_OF_PORTS; i++)

+    {

+        if(hex & BIT(i))

+        {

+            (*ptr_bit) |= BITS_OFF_L(1UL, 4*(AIR_MAX_NUM_OF_PORTS - i - 1), 4);

+        }

+    }

+    return AIR_E_OK;

+}

+

+static AIR_ERROR_NO_T

+_hex2bitstr(

+        const UI32_T hex,

+        C8_T *ptr_bit_str,

+        UI32_T str_len)

+{

+    UI32_T i = 0;

+    C8_T str_bitmap[AIR_MAX_NUM_OF_PORTS+1];

+

+    /* Mistake proofing */

+    AIR_CHECK_PTR(ptr_bit_str);

+    AIR_PARAM_CHK(str_len <= AIR_MAX_NUM_OF_PORTS, AIR_E_BAD_PARAMETER);

+

+    memset(str_bitmap, 0, AIR_MAX_NUM_OF_PORTS+1);

+

+    for(i=0; i<AIR_MAX_NUM_OF_PORTS; i++)

+    {

+        if(hex & BIT(i))

+        {

+            str_bitmap[i] = '1';

+        }

+        else

+        {

+            str_bitmap[i] = '-';

+        }

+    }

+    str_bitmap[i] = '\0';

+    strncpy(ptr_bit_str, str_bitmap, i+1);

+

+    return AIR_E_OK;

+}

+

+static AIR_ERROR_NO_T

+_portListStr2Ary(

+    const C8_T *str,

+    UI32_T *ary,

+    const UI32_T ary_num)

+{

+    UI32_T i = 0;

+    UI32_T str_len = 0;

+    UI32_T val = 0;

+    C8_T *str2;

+    C8_T *pch;

+    C8_T *last;

+

+    /* Mistake proofing */

+    AIR_CHECK_PTR(str);

+    AIR_CHECK_PTR(ary);

+    AIR_PARAM_CHK(0 == ary_num, AIR_E_BAD_PARAMETER);

+

+    /* Allocate new string */

+    str_len = strlen(str);

+    str2 = AIR_MALLOC(str_len+1);

+    AIR_CHECK_PTR(str2);

+    memset(str2, 0, str_len+1);

+    strncpy(str2, str, str_len+1);

+

+    /* clear array */

+    memset(ary, 0, ary_num*4);

+

+    /* split string by ',' */

+    pch = _strtok(str2, ",", &last);

+    while(NULL != pch)

+    {

+        val = _strtoul(pch, NULL, 0);

+        ary[val/32] |= BIT(val%32);

+        pch = _strtok(NULL, ",", &last);

+    }

+

+    AIR_FREE(str2);

+    return AIR_E_OK;

+}

+

+static AIR_ERROR_NO_T

+doRegRead(

+        UI32_T argc,

+        C8_T *argv[])

+{

+    UI32_T reg = 0, val = 0;

+

+    reg = _strtoul(argv[0], NULL, 16);

+    aml_readReg(0, reg, &val);

+    AIR_PRINT("Read reg=0x%x, value=0x%x\n", reg, val);

+

+    return AIR_E_OK;

+}

+

+static AIR_ERROR_NO_T

+doRegWrite(

+        UI32_T argc,

+        C8_T *argv[])

+{

+    UI32_T reg = 0, val = 0;

+

+    reg = _strtoul(argv[0], NULL, 16);

+    val = _strtoul(argv[1], NULL, 16);

+    aml_writeReg(0, reg, val);

+    AIR_PRINT("Write reg=0x%x, value=0x%x\n", reg, val);

+

+    return AIR_E_OK;

+}

+

+static AIR_ERROR_NO_T

+doReg(

+        UI32_T argc,

+        C8_T *argv[])

+{

+    return subcmd(regCmds, argc, argv);

+}

+

+static AIR_ERROR_NO_T

+doPhyCL22Read(

+        UI32_T argc,

+        C8_T *argv[])

+{

+    UI32_T port = 0, reg = 0, val = 0;

+

+    port = _strtoul(argv[0], NULL, 0);

+    reg  = _strtoul(argv[1], NULL, 16);

+    aml_readPhyReg(0, port, reg, &val);

+    AIR_PRINT("Phy read port=%d, reg=0x%x, value=0x%x\n", port, reg, val);

+

+    return AIR_E_OK;

+}

+

+static AIR_ERROR_NO_T

+doPhyCL22Write(

+        UI32_T argc,

+        C8_T *argv[])

+{

+    UI32_T port = 0, reg = 0, val = 0;

+

+    port = _strtoul(argv[0], NULL, 0);

+    reg  = _strtoul(argv[1], NULL, 16);

+    val  = _strtoul(argv[2], NULL, 16);

+    aml_writePhyReg(0, port, reg, val);

+    AIR_PRINT("Phy write port=%d, reg=0x%x, value=0x%x\n", port, reg, val);

+

+    return AIR_E_OK;

+}

+

+static AIR_ERROR_NO_T

+doPhyCL22(

+        UI32_T argc,

+        C8_T *argv[])

+{

+    return subcmd(phyCL22Cmds, argc, argv);

+}

+

+static AIR_ERROR_NO_T

+doPhyCL45Read(

+        UI32_T argc,

+        C8_T *argv[])

+{

+    UI32_T port = 0, dev = 0, reg = 0, val = 0;

+

+    port = _strtoul(argv[0], NULL, 0);

+    dev  = _strtoul(argv[1], NULL, 16);

+    reg  = _strtoul(argv[2], NULL, 16);

+    aml_readPhyRegCL45(0, port, dev, reg, &val);

+    AIR_PRINT("Phy read port=%d, dev=0x%x, reg=0x%x, value=0x%x\n", port, dev, reg, val);

+

+    return AIR_E_OK;

+}

+

+static AIR_ERROR_NO_T

+doPhyCL45Write(

+        UI32_T argc,

+        C8_T *argv[])

+{

+    UI32_T port = 0, dev = 0, reg = 0, val = 0;

+

+    port = _strtoul(argv[0], NULL, 0);

+    dev  = _strtoul(argv[1], NULL, 16);

+    reg  = _strtoul(argv[2], NULL, 16);

+    val  = _strtoul(argv[3], NULL, 16);

+    aml_writePhyRegCL45(0, port, dev, reg, val);

+    AIR_PRINT("Phy write port=%d, dev=0x%x, reg=0x%x, value=0x%x\n", port, dev, reg, val);

+

+    return AIR_E_OK;

+}

+

+static AIR_ERROR_NO_T

+doPhyCL45(

+        UI32_T argc,

+        C8_T *argv[])

+{

+    return subcmd(phyCL45Cmds, argc, argv);

+}

+

+static AIR_ERROR_NO_T

+doPhy(

+        UI32_T argc,

+        C8_T *argv[])

+{

+    return subcmd(phyCmds, argc, argv);

+}

+

+static AIR_ERROR_NO_T

+doPortSetMatrix(UI32_T argc, C8_T *argv[])

+{

+    UI32_T port = 0;

+    UI32_T matrix = 0;

+    AIR_ERROR_NO_T rc = AIR_E_OK;

+

+    port   = _strtoul(argv[0], NULL, 0);

+    matrix = _strtoul(argv[1], NULL, 16);

+    rc = air_port_setPortMatrix(0, port, matrix);

+    if (rc != AIR_E_OK)

+    {

+        AIR_PRINT("Error: Operation failed!\n");

+    }

+    return rc;

+}

+

+static AIR_ERROR_NO_T

+doPortSetVlanMode(UI32_T argc, C8_T *argv[])

+{

+    UI32_T port = 0;

+    AIR_PORT_VLAN_MODE_T vlan_mode;

+    AIR_ERROR_NO_T rc = AIR_E_OK;

+

+    port      = _strtoul(argv[0], NULL, 0);

+    vlan_mode = _strtoul(argv[1], NULL, 0);

+    rc = air_port_setVlanMode(0, port, vlan_mode);

+    if (rc != AIR_E_OK)

+    {

+        AIR_PRINT("Error: Operation failed!\n");

+    }

+    return rc;

+}

+

+static AIR_ERROR_NO_T

+doPortSet(

+        UI32_T argc,

+        C8_T *argv[])

+{

+    return subcmd(portSetCmds, argc, argv);

+}

+

+static AIR_ERROR_NO_T

+doPortGetMatrix(UI32_T argc, C8_T *argv[])

+{

+    UI32_T port = 0;

+    UI32_T matrix = 0;

+    AIR_ERROR_NO_T rc = AIR_E_OK;

+

+    port = _strtoul(argv[0], NULL, 0);

+    rc = air_port_getPortMatrix(0, port, &matrix);

+    if (rc != AIR_E_OK)

+    {

+        AIR_PRINT("Error: Operation failed!\n");

+        return rc;

+    }

+    AIR_PRINT("Port %d Matrix: %2x\n", port, matrix);

+    return rc;

+}

+

+static AIR_ERROR_NO_T

+doPortGetVlanMode(UI32_T argc, C8_T *argv[])

+{

+    UI32_T port = 0;

+    AIR_PORT_VLAN_MODE_T vlan_mode;

+    AIR_ERROR_NO_T rc = AIR_E_OK;

+

+    port = _strtoul(argv[0], NULL, 0);

+    rc = air_port_getVlanMode(0, port, &vlan_mode);

+    if (rc != AIR_E_OK)

+    {

+        AIR_PRINT("Error: Operation failed!\n");

+        return rc;

+    }

+    AIR_PRINT("Port %d Vlan Mode: ", port);

+    switch(vlan_mode)

+    {

+        case AIR_PORT_VLAN_MODE_PORT_MATRIX:

+            AIR_PRINT("matrix(%d)\n", vlan_mode);

+            break;

+        case AIR_PORT_VLAN_MODE_FALLBACK:

+            AIR_PRINT("fallback(%d)\n", vlan_mode);

+            break;

+        case AIR_PORT_VLAN_MODE_CHECK:

+            AIR_PRINT("check(%d)\n", vlan_mode);

+            break;

+        case AIR_PORT_VLAN_MODE_SECURITY:

+            AIR_PRINT("security(%d)\n", vlan_mode);

+            break;

+        default:

+            AIR_PRINT("unknown(%d)\n", vlan_mode);

+            break;

+    };

+    return rc;

+}

+

+static AIR_ERROR_NO_T

+doPortGet(

+        UI32_T argc,

+        C8_T *argv[])

+{

+    return subcmd(portGetCmds, argc, argv);

+}

+

+static AIR_ERROR_NO_T

+doPort(

+        UI32_T argc,

+        C8_T *argv[])

+{

+    return subcmd(portCmds, argc, argv);

+}

+

+static AIR_ERROR_NO_T

+doVlanInitiate(UI32_T argc, C8_T *argv[])

+{

+    UI16_T vid = 0;

+    AIR_VLAN_ENTRY_ATTR_T vlan_entry = {0};

+    AIR_ERROR_NO_T rc = AIR_E_OK;

+

+    vid = _strtoul(argv[0], NULL, 0);

+    if (9 == argc)

+    {

+        vlan_entry.vlan_entry_format.fid           = _strtoul(argv[1], NULL, 0);

+        vlan_entry.vlan_entry_format.port_mem      = _strtoul(argv[2], NULL, 0);

+        vlan_entry.vlan_entry_format.ivl           = _strtoul(argv[3], NULL, 0);

+        vlan_entry.vlan_entry_format.port_stag     = _strtoul(argv[4], NULL, 0);

+        vlan_entry.vlan_entry_format.stag          = _strtoul(argv[5], NULL, 0);

+        vlan_entry.vlan_entry_format.eg_ctrl_en    = _strtoul(argv[6], NULL, 0);

+        vlan_entry.vlan_entry_format.eg_con        = _strtoul(argv[7], NULL, 0);

+        vlan_entry.vlan_entry_format.eg_ctrl       = _strtoul(argv[8], NULL, 0);

+

+        rc = air_vlan_create(0, vid, &vlan_entry);

+    }

+    else

+    {

+        AIR_PRINT("Unrecognized command.\n");

+        rc = AIR_E_BAD_PARAMETER;

+    }

+

+    switch (rc)

+    {

+        case     AIR_E_OK:                                                            break;

+        case     AIR_E_ENTRY_EXISTS:  AIR_PRINT("VLAN already exist!\n");             break;

+        default:                      AIR_PRINT("Error %d: Operation failed!\n", rc); break;

+    }

+    return rc;

+}

+

+static AIR_ERROR_NO_T

+doVlanCreate(UI32_T argc, C8_T *argv[])

+{

+    UI16_T vid = 0;

+    AIR_ERROR_NO_T rc = AIR_E_OK;

+

+    vid = _strtoul(argv[0], NULL, 0);

+    rc  = air_vlan_create(0, vid, NULL);

+

+    switch (rc)

+    {

+        case     AIR_E_OK:                                                            break;

+        case     AIR_E_ENTRY_EXISTS:  AIR_PRINT("VLAN already exist!\n");             break;

+        default:                      AIR_PRINT("Error %d: Operation failed!\n", rc); break;

+    }

+    return rc;

+}

+

+static AIR_ERROR_NO_T

+doVlanDestroy(UI32_T argc, C8_T *argv[])

+{

+    C8_T *token = NULL;

+    UI16_T vid = 0, vid_limit = AIR_VLAN_ID_MAX;

+    AIR_ERROR_NO_T rc = AIR_E_OK;

+

+    if (argc > 0)

+    {

+        if (isdigit(argv[0][0]))

+        {

+            token = _strtok(argv[0], "-", &argv[0]);

+            vid = _strtoul(token, NULL, 0);

+            if ((token = _strtok(argv[0], "-", &argv[0])))

+                vid_limit = _strtoul(token, NULL, 0);

+            else

+                vid_limit = vid;

+            if (AIR_VLAN_ID_MAX < vid_limit)

+            {

+                AIR_PRINT("vid number should less than %d!\n", AIR_VLAN_ID_MAX);

+                return AIR_E_BAD_PARAMETER;

+            }

+            if (vid > vid_limit)

+            {

+                AIR_PRINT("vid0 should less than vid1!\n");

+                return AIR_E_BAD_PARAMETER;

+            }

+        }

+        else

+        {

+            AIR_PRINT("Bad parameter!\n");

+            return AIR_E_BAD_PARAMETER;

+        }

+    }

+

+    for (; vid <= vid_limit; vid++)

+    {

+        rc = air_vlan_destroy(0, vid);

+    }

+    return rc;

+}

+

+static AIR_ERROR_NO_T

+doVlanDestroyAll(UI32_T argc, C8_T *argv[])

+{

+    UI32_T restore_def_vlan = 0;

+    AIR_ERROR_NO_T rc = AIR_E_OK;

+

+    if (argc > 0)

+    {

+        restore_def_vlan = _strtoul(argv[0], NULL, 0);

+    }

+

+    rc = air_vlan_destroyAll(0, restore_def_vlan);

+    if (rc != AIR_E_OK)

+    {

+        AIR_PRINT("Error: Operation failed!\n");

+    }

+    return rc;

+}

+

+static AIR_ERROR_NO_T

+doVlanDump(UI32_T argc, C8_T *argv[])

+{

+    C8_T *token = NULL;

+    UI16_T port = 0, valid_count = 0, vid = 0, vid_limit = AIR_VLAN_ID_MAX;

+    AIR_PORT_EGS_TAG_ATTR_T tag_ctl[AIR_MAX_NUM_OF_PORTS] = {0};

+    AIR_VLAN_ENTRY_T vlan_entry = {0};

+

+    if (argc > 0)

+    {

+        if (isdigit(argv[0][0]))

+        {

+            token = _strtok(argv[0], "-", &argv[0]);

+            vid = _strtoul(token, NULL, 0);

+            if ((token = _strtok(argv[0], "-", &argv[0])))

+                vid_limit = _strtoul(token, NULL, 0);

+            else

+                vid_limit = vid;

+            if (AIR_VLAN_ID_MAX < vid_limit)

+            {

+                AIR_PRINT("vid number should less than %d!\n", AIR_VLAN_ID_MAX);

+                return AIR_E_BAD_PARAMETER;

+            }

+            if (vid > vid_limit)

+            {

+                AIR_PRINT("vid0 should less than vid1!\n");

+                return AIR_E_BAD_PARAMETER;

+            }

+        }

+        else

+        {

+            AIR_PRINT("Bad parameter!\n");

+            return AIR_E_BAD_PARAMETER;

+        }

+    }

+

+    for (valid_count = 0; vid <= vid_limit; vid++)

+    {

+        _air_vlan_readEntry(0, vid, &vlan_entry);

+        if (vlan_entry.valid)

+        {

+            valid_count++;

+            if (1 == valid_count)

+                AIR_PRINT(" Vid Fid MemPort Ivl PortBaseStag Stag EgsTagCtlEn EgsTagCon EgsTagCtl\n======================================================================\n");

+            for (port = 0; port < AIR_MAX_NUM_OF_PORTS; port++)

+                tag_ctl[port] = (vlan_entry.vlan_entry_format.eg_ctrl >> (port * 2)) & 0x3;

+            AIR_PRINT("%4d %3d      %2x %3d %12d %4d %11d %9d   %1x%1x%1x%1x%1x%1x%1x\n",

+                vid, vlan_entry.vlan_entry_format.fid, vlan_entry.vlan_entry_format.port_mem, vlan_entry.vlan_entry_format.ivl,

+                vlan_entry.vlan_entry_format.port_stag, vlan_entry.vlan_entry_format.stag, vlan_entry.vlan_entry_format.eg_ctrl_en, vlan_entry.vlan_entry_format.eg_con,

+                tag_ctl[6], tag_ctl[5], tag_ctl[4], tag_ctl[3], tag_ctl[2], tag_ctl[1], tag_ctl[0]);

+        }

+    }

+

+    if (!valid_count)

+        AIR_PRINT("not found!\n");

+    else

+        AIR_PRINT("Found %d valid entries!\n", valid_count);

+

+    return AIR_E_OK;

+}

+

+static AIR_ERROR_NO_T

+doVlanAddPortMem(UI32_T argc, C8_T *argv[])

+{

+    UI16_T vid = 0, port = 0;

+    AIR_ERROR_NO_T rc = AIR_E_OK;

+

+    vid  = _strtoul(argv[0], NULL, 0);

+    port = _strtoul(argv[1], NULL, 0);

+    rc = air_vlan_addMemberPort(0, vid, port);

+    switch (rc)

+    {

+        case     AIR_E_OK:                                                               break;

+        case     AIR_E_ENTRY_NOT_FOUND:  AIR_PRINT("VLAN not found!\n");                 break;

+        default:                         AIR_PRINT("Error %d: Operation failed!\n", rc); break;

+    }

+    return rc;

+}

+

+static AIR_ERROR_NO_T

+doVlanDelPortMem(UI32_T argc, C8_T *argv[])

+{

+    UI16_T vid = 0, port = 0;

+    AIR_ERROR_NO_T rc = AIR_E_OK;

+

+    vid  = _strtoul(argv[0], NULL, 0);

+    port = _strtoul(argv[1], NULL, 0);

+    rc = air_vlan_delMemberPort(0, vid, port);

+    switch (rc)

+    {

+        case     AIR_E_OK:                                                               break;

+        case     AIR_E_ENTRY_NOT_FOUND:  AIR_PRINT("VLAN not found!\n");                 break;

+        default:                         AIR_PRINT("Error %d: Operation failed!\n", rc); break;

+    }

+    return rc;

+}

+

+static AIR_ERROR_NO_T

+doVlanSetFid(UI32_T argc, C8_T *argv[])

+{

+    UI16_T vid = 0;

+    UI8_T  fid = 0;

+    AIR_ERROR_NO_T rc = AIR_E_OK;

+

+    vid = _strtoul(argv[0], NULL, 0);

+    fid = _strtoul(argv[1], NULL, 0);

+    rc = air_vlan_setFid(0, vid, fid);

+    switch (rc)

+    {

+        case     AIR_E_OK:                                                               break;

+        case     AIR_E_ENTRY_NOT_FOUND:  AIR_PRINT("VLAN not found!\n");                 break;

+        default:                         AIR_PRINT("Error %d: Operation failed!\n", rc); break;

+    }

+    return rc;

+}

+

+static AIR_ERROR_NO_T

+doVlanSetMemPort(UI32_T argc, C8_T *argv[])

+{

+    UI16_T vid = 0, port_bitmap = 0;

+    AIR_ERROR_NO_T rc = AIR_E_OK;

+

+    vid         = _strtoul(argv[0], NULL, 0);

+    port_bitmap = _strtoul(argv[1], NULL, 16);

+    rc = air_vlan_setMemberPort(0, vid, port_bitmap);

+    switch (rc)

+    {

+        case     AIR_E_OK:                                                               break;

+        case     AIR_E_ENTRY_NOT_FOUND:  AIR_PRINT("VLAN not found!\n");                 break;

+        default:                         AIR_PRINT("Error %d: Operation failed!\n", rc); break;

+    }

+    return rc;

+}

+

+static AIR_ERROR_NO_T

+doVlanSetIVL(UI32_T argc, C8_T *argv[])

+{

+    UI16_T vid = 0;

+    BOOL_T enable = TRUE;

+    AIR_ERROR_NO_T rc = AIR_E_OK;

+

+    vid    = _strtoul(argv[0], NULL, 0);

+    enable = _strtoul(argv[1], NULL, 0);

+    rc = air_vlan_setIVL(0, vid, enable);

+    switch (rc)

+    {

+        case     AIR_E_OK:                                                               break;

+        case     AIR_E_ENTRY_NOT_FOUND:  AIR_PRINT("VLAN not found!\n");                 break;

+        default:                         AIR_PRINT("Error %d: Operation failed!\n", rc); break;

+    }

+    return rc;

+}

+

+static AIR_ERROR_NO_T

+doVlanSetPortBaseStag(UI32_T argc, C8_T *argv[])

+{

+    UI16_T vid = 0;

+    BOOL_T enable = TRUE;

+    AIR_ERROR_NO_T rc = AIR_E_OK;

+

+    vid    = _strtoul(argv[0], NULL, 0);

+    enable = _strtoul(argv[1], NULL, 0);

+    rc = air_vlan_setPortBasedStag(0, vid, enable);

+    switch (rc)

+    {

+        case     AIR_E_OK:                                                               break;

+        case     AIR_E_ENTRY_NOT_FOUND:  AIR_PRINT("VLAN not found!\n");                 break;

+        default:                         AIR_PRINT("Error %d: Operation failed!\n", rc); break;

+    }

+    return rc;

+}

+

+static AIR_ERROR_NO_T

+doVlanSetStag(UI32_T argc, C8_T *argv[])

+{

+    UI16_T vid = 0, stag = 0;

+    AIR_ERROR_NO_T rc = AIR_E_OK;

+

+    vid  = _strtoul(argv[0], NULL, 0);

+    stag = _strtoul(argv[1], NULL, 0);

+    rc = air_vlan_setServiceTag(0, vid, stag);

+    switch (rc)

+    {

+        case     AIR_E_OK:                                                               break;

+        case     AIR_E_ENTRY_NOT_FOUND:  AIR_PRINT("VLAN not found!\n");                 break;

+        default:                         AIR_PRINT("Error %d: Operation failed!\n", rc); break;

+    }

+    return rc;

+}

+

+static AIR_ERROR_NO_T

+doVlanSetEgsTagCtlEn(UI32_T argc, C8_T *argv[])

+{

+    UI16_T vid = 0;

+    BOOL_T enable = TRUE;

+    AIR_ERROR_NO_T rc = AIR_E_OK;

+

+    vid    = _strtoul(argv[0], NULL, 0);

+    enable = _strtoul(argv[1], NULL, 0);

+    rc = air_vlan_setEgsTagCtlEnable(0, vid, enable);

+    switch (rc)

+    {

+        case     AIR_E_OK:                                                               break;

+        case     AIR_E_ENTRY_NOT_FOUND:  AIR_PRINT("VLAN not found!\n");                 break;

+        default:                         AIR_PRINT("Error %d: Operation failed!\n", rc); break;

+    }

+    return rc;

+}

+

+static AIR_ERROR_NO_T

+doVlanSetEgsTagCtlCon(UI32_T argc, C8_T *argv[])

+{

+    UI16_T vid = 0;

+    BOOL_T enable = TRUE;

+    AIR_ERROR_NO_T rc = AIR_E_OK;

+

+    vid    = _strtoul(argv[0], NULL, 0);

+    enable = _strtoul(argv[1], NULL, 0);

+    rc = air_vlan_setEgsTagConsistent(0, vid, enable);

+    switch (rc)

+    {

+        case     AIR_E_OK:                                                               break;

+        case     AIR_E_ENTRY_NOT_FOUND:  AIR_PRINT("VLAN not found!\n");                 break;

+        default:                         AIR_PRINT("Error %d: Operation failed!\n", rc); break;

+    }

+    return rc;

+}

+

+static AIR_ERROR_NO_T

+doVlanSetEgsTagCtl(UI32_T argc, C8_T *argv[])

+{

+    UI16_T vid = 0, port = 0;

+    AIR_PORT_EGS_TAG_ATTR_T tag_ctl = AIR_PORT_EGS_TAG_ATTR_UNTAGGED;

+    AIR_ERROR_NO_T rc = AIR_E_OK;

+

+    vid     = _strtoul(argv[0], NULL, 0);

+    port    = _strtoul(argv[1], NULL, 0);

+    tag_ctl = _strtoul(argv[2], NULL, 0);

+    rc = air_vlan_setPortEgsTagCtl(0, vid, port, tag_ctl);

+    switch (rc)

+    {

+        case     AIR_E_OK:                                                               break;

+        case     AIR_E_ENTRY_NOT_FOUND:  AIR_PRINT("VLAN not found!\n");                 break;

+        default:                         AIR_PRINT("Error %d: Operation failed!\n", rc); break;

+    }

+    return rc;

+}

+

+static AIR_ERROR_NO_T

+doVlanSetPortActFrame(UI32_T argc, C8_T *argv[])

+{

+    UI16_T port = 0;

+    AIR_VLAN_ACCEPT_FRAME_TYPE_T type = AIR_VLAN_ACCEPT_FRAME_TYPE_ALL;

+    AIR_ERROR_NO_T rc = AIR_E_OK;

+

+    port = _strtoul(argv[0], NULL, 0);

+    type = _strtoul(argv[1], NULL, 0);

+    rc = air_vlan_setPortAcceptFrameType(0, port, type);

+    if (rc != AIR_E_OK)

+    {

+        AIR_PRINT("Error: Operation failed!\n");

+    }

+    return rc;

+}

+

+static AIR_ERROR_NO_T

+doVlanSetLeakyVlanEn(UI32_T argc, C8_T *argv[])

+{

+    UI16_T port = 0;

+    AIR_LEAKY_PKT_TYPE_T pkt_type = AIR_LEAKY_PKT_TYPE_UNICAST;

+    BOOL_T enable = TRUE;

+    AIR_ERROR_NO_T rc = AIR_E_OK;

+

+    port     = _strtoul(argv[0], NULL, 0);

+    pkt_type = _strtoul(argv[1], NULL, 0);

+    enable   = _strtoul(argv[2], NULL, 0);

+    rc = air_vlan_setPortLeakyVlanEnable(0, port, pkt_type, enable);

+    if (rc != AIR_E_OK)

+    {

+        AIR_PRINT("Error: Operation failed!\n");

+    }

+    return rc;

+}

+

+static AIR_ERROR_NO_T

+doVlanSetPortVlanAttr(UI32_T argc, C8_T *argv[])

+{

+    UI16_T port = 0;

+    AIR_VLAN_PORT_ATTR_T attr = AIR_VLAN_PORT_ATTR_USER_PORT;

+    AIR_ERROR_NO_T rc = AIR_E_OK;

+

+    port = _strtoul(argv[0], NULL, 0);

+    attr = _strtoul(argv[1], NULL, 0);

+    rc = air_vlan_setPortAttr(0, port, attr);

+    if (rc != AIR_E_OK)

+    {

+        AIR_PRINT("Error: Operation failed!\n");

+    }

+    return rc;

+}

+

+static AIR_ERROR_NO_T

+doVlanSetIgsPortETagAttr(UI32_T argc, C8_T *argv[])

+{

+    UI16_T port = 0;

+    AIR_IGR_PORT_EG_TAG_ATTR_T attr = AIR_IGR_PORT_EG_TAG_ATTR_DISABLE;

+    AIR_ERROR_NO_T rc = AIR_E_OK;

+

+    port = _strtoul(argv[0], NULL, 0);

+    attr = _strtoul(argv[1], NULL, 0);

+    rc = air_vlan_setIgrPortTagAttr(0, port, attr);

+    if (rc != AIR_E_OK)

+    {

+        AIR_PRINT("Error: Operation failed!\n");

+    }

+    return rc;

+}

+

+static AIR_ERROR_NO_T

+doVlanSetPortETagAttr(UI32_T argc, C8_T *argv[])

+{

+    UI16_T port = 0;

+    AIR_PORT_EGS_TAG_ATTR_T attr = AIR_PORT_EGS_TAG_ATTR_UNTAGGED;

+    AIR_ERROR_NO_T rc = AIR_E_OK;

+

+    port = _strtoul(argv[0], NULL, 0);

+    attr = _strtoul(argv[1], NULL, 0);

+    rc = air_vlan_setPortEgsTagAttr(0, port, attr);

+    if (rc != AIR_E_OK)

+    {

+        AIR_PRINT("Error: Operation failed!\n");

+    }

+    return rc;

+}

+

+static AIR_ERROR_NO_T

+doVlanSetPortOuterTPID(UI32_T argc, C8_T *argv[])

+{

+    UI16_T port = 0, tpid = 0;

+    AIR_ERROR_NO_T rc = AIR_E_OK;

+

+    port = _strtoul(argv[0], NULL, 0);

+    tpid = _strtoul(argv[1], NULL, 16);

+    rc = air_vlan_setPortOuterTPID(0, port, tpid);

+    if (rc != AIR_E_OK)

+    {

+        AIR_PRINT("Error: Operation failed!\n");

+    }

+    return rc;

+}

+

+static AIR_ERROR_NO_T

+doVlanSetPvid(UI32_T argc, C8_T *argv[])

+{

+    UI16_T port = 0, pvid = 0;

+    AIR_ERROR_NO_T rc = AIR_E_OK;

+

+    port = _strtoul(argv[0], NULL, 0);

+    pvid = _strtoul(argv[1], NULL, 0);

+    rc = air_vlan_setPortPVID(0, port, pvid);

+    if (rc != AIR_E_OK)

+    {

+        AIR_PRINT("Error: Operation failed!\n");

+    }

+    return rc;

+}

+

+static AIR_ERROR_NO_T

+doVlanSet(

+        UI32_T argc,

+        C8_T *argv[])

+{

+    return subcmd(vlanSetCmds, argc, argv);

+}

+

+static AIR_ERROR_NO_T

+doVlanGetPortActFrame(UI32_T argc, C8_T *argv[])

+{

+    UI32_T port = 0;

+    AIR_VLAN_ACCEPT_FRAME_TYPE_T type;

+    AIR_ERROR_NO_T rc = AIR_E_OK;

+

+    port = _strtoul(argv[0], NULL, 0);

+    rc = air_vlan_getPortAcceptFrameType(0, port, &type);

+    if (rc != AIR_E_OK)

+    {

+        AIR_PRINT("Error: Operation failed!\n");

+        return rc;

+    }

+    AIR_PRINT("Port %d Acceptable Frame Type: ", port);

+    switch(type)

+    {

+        case AIR_VLAN_ACCEPT_FRAME_TYPE_ALL:

+            AIR_PRINT("all(%d)\n", type);

+            break;

+        case AIR_VLAN_ACCEPT_FRAME_TYPE_TAG_ONLY:

+            AIR_PRINT("tagged-only(%d)\n", type);

+            break;

+        case AIR_VLAN_ACCEPT_FRAME_TYPE_UNTAG_ONLY:

+            AIR_PRINT("untagged-only(%d)\n", type);

+            break;

+        default:

+            AIR_PRINT("unknown(%d)\n", type);

+            break;

+    };

+    return rc;

+}

+

+static AIR_ERROR_NO_T

+doVlanGetLeakyVlanEn(UI32_T argc, C8_T *argv[])

+{

+    UI32_T port = 0;

+    BOOL_T uc = FALSE, mc = FALSE, bc = FALSE;

+    AIR_ERROR_NO_T rc = AIR_E_OK;

+

+    port = _strtoul(argv[0], NULL, 0);

+    rc += air_vlan_getPortLeakyVlanEnable(0, port, AIR_LEAKY_PKT_TYPE_UNICAST, &uc);

+    rc += air_vlan_getPortLeakyVlanEnable(0, port, AIR_LEAKY_PKT_TYPE_MULTICAST, &mc);

+    rc += air_vlan_getPortLeakyVlanEnable(0, port, AIR_LEAKY_PKT_TYPE_BROADCAST, &bc);

+    if (rc != AIR_E_OK)

+    {

+        AIR_PRINT("Error: Operation failed!\n");

+        return rc;

+    }

+

+    AIR_PRINT("Port %d Leaky Vlan Enable\n", port);

+    AIR_PRINT("Unicast     : %s\n", uc ? "TRUE" : "FALSE");

+    AIR_PRINT("Multicast   : %s\n", mc ? "TRUE" : "FALSE");

+    AIR_PRINT("Broadcast   : %s\n", bc ? "TRUE" : "FALSE");

+    return rc;

+}

+

+static AIR_ERROR_NO_T

+doVlanGetPortVlanAttr(UI32_T argc, C8_T *argv[])

+{

+    UI32_T port = 0;

+    AIR_VLAN_PORT_ATTR_T attr;

+    AIR_ERROR_NO_T rc = AIR_E_OK;

+

+    port = _strtoul(argv[0], NULL, 0);

+    rc = air_vlan_getPortAttr(0, port, &attr);

+    if (rc != AIR_E_OK)

+    {

+        AIR_PRINT("Error: Operation failed!\n");

+        return rc;

+    }

+    AIR_PRINT("Port %d Vlan Attr: ", port);

+    switch(attr)

+    {

+        case AIR_VLAN_PORT_ATTR_USER_PORT:

+            AIR_PRINT("user port(%d)\n", attr);

+            break;

+        case AIR_VLAN_PORT_ATTR_STACK_PORT:

+            AIR_PRINT("stack port(%d)\n", attr);

+            break;

+        case AIR_VLAN_PORT_ATTR_TRANSLATION_PORT:

+            AIR_PRINT("translation port(%d)\n", attr);

+            break;

+        case AIR_VLAN_PORT_ATTR_TRANSPARENT_PORT:

+            AIR_PRINT("transparent port(%d)\n", attr);

+            break;

+        default:

+            AIR_PRINT("unknown(%d)\n", attr);

+            break;

+    };

+    return rc;

+}

+

+static AIR_ERROR_NO_T

+doVlanGetIgsPortETagAttr(UI32_T argc, C8_T *argv[])

+{

+    UI32_T port = 0;

+    AIR_IGR_PORT_EG_TAG_ATTR_T attr;

+    AIR_ERROR_NO_T rc = AIR_E_OK;

+

+    port = _strtoul(argv[0], NULL, 0);

+    rc = air_vlan_getIgrPortTagAttr(0, port, &attr);

+    if (rc != AIR_E_OK)

+    {

+        AIR_PRINT("Error: Operation failed!\n");

+        return rc;

+    }

+    AIR_PRINT("Port %d Incomming Port Egress Tag Attr: ", port);

+    switch(attr)

+    {

+        case AIR_IGR_PORT_EG_TAG_ATTR_DISABLE:

+            AIR_PRINT("disable(%d)\n", attr);

+            break;

+        case AIR_IGR_PORT_EG_TAG_ATTR_CONSISTENT:

+            AIR_PRINT("consistent(%d)\n", attr);

+            break;

+        case AIR_IGR_PORT_EG_TAG_ATTR_UNTAGGED:

+            AIR_PRINT("untagged(%d)\n", attr);

+            break;

+        case AIR_IGR_PORT_EG_TAG_ATTR_SWAP:

+            AIR_PRINT("swap(%d)\n", attr);

+            break;

+        case AIR_IGR_PORT_EG_TAG_ATTR_TAGGED:

+            AIR_PRINT("tagged(%d)\n", attr);

+            break;

+        case AIR_IGR_PORT_EG_TAG_ATTR_STACK:

+            AIR_PRINT("stack(%d)\n", attr);

+            break;

+        default:

+            AIR_PRINT("unknown(%d)\n", attr);

+            break;

+    };

+    return rc;

+}

+

+static AIR_ERROR_NO_T

+doVlanGetPortETagAttr(UI32_T argc, C8_T *argv[])

+{

+    UI32_T port = 0;

+    AIR_PORT_EGS_TAG_ATTR_T attr;

+    AIR_ERROR_NO_T rc = AIR_E_OK;

+

+    port = _strtoul(argv[0], NULL, 0);

+    rc = air_vlan_getPortEgsTagAttr(0, port, &attr);

+    if (rc != AIR_E_OK)

+    {

+        AIR_PRINT("Error: Operation failed!\n");

+        return rc;

+    }

+    AIR_PRINT("Port %d Egress Tag Attr: ", port);

+    switch(attr)

+    {

+        case AIR_PORT_EGS_TAG_ATTR_UNTAGGED:

+            AIR_PRINT("untagged(%d)\n", attr);

+            break;

+        case AIR_PORT_EGS_TAG_ATTR_SWAP:

+            AIR_PRINT("swap(%d)\n", attr);

+            break;

+        case AIR_PORT_EGS_TAG_ATTR_TAGGED:

+            AIR_PRINT("tagged(%d)\n", attr);

+            break;

+        case AIR_PORT_EGS_TAG_ATTR_STACK:

+            AIR_PRINT("stack(%d)\n", attr);

+            break;

+        default:

+            AIR_PRINT("unknown(%d)\n", attr);

+            break;

+    };

+    return rc;

+}

+

+static AIR_ERROR_NO_T

+doVlanGetPortOuterTPID(UI32_T argc, C8_T *argv[])

+{

+    UI32_T port = 0;

+    UI16_T tpid = 0;

+    AIR_ERROR_NO_T rc = AIR_E_OK;

+

+    port = _strtoul(argv[0], NULL, 0);

+    rc = air_vlan_getPortOuterTPID(0, port, &tpid);

+    if (rc != AIR_E_OK)

+    {

+        AIR_PRINT("Error: Operation failed!\n");

+        return rc;

+    }

+    AIR_PRINT("Port %d Outer TPID: %4x\n", port, tpid);

+    return rc;

+}

+

+static AIR_ERROR_NO_T

+doVlanGetPvid(UI32_T argc, C8_T *argv[])

+{

+    UI32_T port = 0;

+    UI16_T pvid = 0;

+    AIR_ERROR_NO_T rc = AIR_E_OK;

+

+    port = _strtoul(argv[0], NULL, 0);

+    rc = air_vlan_getPortPVID(0, port, &pvid);

+    if (rc != AIR_E_OK)

+    {

+        AIR_PRINT("Error: Operation failed!\n");

+        return rc;

+    }

+    AIR_PRINT("Port %d PVID: %d\n", port, pvid);

+    return rc;

+}

+

+static AIR_ERROR_NO_T

+doVlanGet(

+        UI32_T argc,

+        C8_T *argv[])

+{

+    return subcmd(vlanGetCmds, argc, argv);

+}

+

+static AIR_ERROR_NO_T

+doVlan(

+        UI32_T argc,

+        C8_T *argv[])

+{

+    return subcmd(vlanCmds, argc, argv);

+}

+

+static AIR_ERROR_NO_T

+doJumbo(

+        UI32_T argc,

+        C8_T *argv[])

+{

+    AIR_ERROR_NO_T ret = AIR_E_OK;

+    I32_T pkt_len = 0, frame_len = 0;

+

+    if(0 == argc)

+    {

+        /* get command */

+        ret = air_port_getJumbo(0, &pkt_len, &frame_len);

+        if(ret == AIR_E_OK)

+        {

+            AIR_PRINT("Get ");

+            switch(pkt_len)

+            {

+                case 0:

+                    AIR_PRINT("RX_1518 ");

+                    break;

+                case 1:

+                    AIR_PRINT("RX_1536 ");

+                    break;

+                case 2:

+                    AIR_PRINT("RX_1552 ");

+                    break;

+                case 3:

+                    AIR_PRINT("RX_JUMBO ");

+                    break;

+            }

+            AIR_PRINT("frames lengths %d KBytes\n", frame_len);

+        }

+        else

+        {

+            AIR_PRINT("Get Jumbo Fail.\n");

+        }

+    }

+    else

+    {

+        /* set command */

+        pkt_len = _strtol(argv[0], NULL, 10);

+        frame_len = _strtol(argv[1], NULL, 10);

+

+        ret = air_port_setJumbo(0, pkt_len, frame_len);

+        if(ret == AIR_E_OK)

+        {

+            AIR_PRINT("Set ");

+            switch(pkt_len)

+            {

+                case 0:

+                    AIR_PRINT("RX_1518 ");

+                    break;

+                case 1:

+                    AIR_PRINT("RX_1536 ");

+                    break;

+                case 2:

+                    AIR_PRINT("RX_1552 ");

+                    break;

+                case 3:

+                    AIR_PRINT("RX_JUMBO ");

+                    break;

+            }

+            AIR_PRINT("frames lengths %d KBytes\n", frame_len);

+        }

+        else

+            AIR_PRINT("Set Jumbo Fail.\n");

+    }

+

+    return ret;

+}

+

+static AIR_ERROR_NO_T

+doFlowCtrl(

+        UI32_T argc,

+        C8_T *argv[])

+{

+    AIR_ERROR_NO_T ret = AIR_E_OK;

+    BOOL_T fc_en = 0, dir = 0;

+    I32_T port = 0;

+

+    port = _strtol(argv[0], NULL, 10);

+    dir = _strtol(argv[1], NULL, 10);

+

+    if(2 == argc)

+    {

+        /* get command */

+        ret = air_port_getFlowCtrl(0, port, dir, &fc_en);

+        if(ret == AIR_E_OK)

+            AIR_PRINT("Get Port%02d %s Flow Control %s\n", port, ((dir)?"RX":"TX"), ((fc_en)?"Enable":"Disable"));

+        else

+            AIR_PRINT("Get Flow Control Fail.\n");

+    }

+    else

+    {

+        /* set command */

+        fc_en = _strtol(argv[2], NULL, 10);

+

+        ret = air_port_setFlowCtrl(0, port, dir, fc_en);

+        if(ret == AIR_E_OK)

+            AIR_PRINT("Set Port%02d %s Flow Control %s\n", port, ((dir)?"RX":"TX"), ((fc_en)?"Enable":"Disable"));

+        else

+            AIR_PRINT("Set Flow Control Fail.\n");

+    }

+

+    return ret;

+}

+

+static AIR_ERROR_NO_T

+doL2Set(

+        UI32_T argc,

+        C8_T *argv[])

+{

+    return subcmd(l2SetCmds, argc, argv);

+}

+

+static AIR_ERROR_NO_T

+doL2Get(

+        UI32_T argc,

+        C8_T *argv[])

+{

+    return subcmd(l2GetCmds, argc, argv);

+}

+

+static AIR_ERROR_NO_T

+doL2Clear(

+        UI32_T argc,

+        C8_T *argv[])

+{

+    return subcmd(l2ClearCmds, argc, argv);

+}

+

+static AIR_ERROR_NO_T

+doL2Del(

+        UI32_T argc,

+        C8_T *argv[])

+{

+    return subcmd(l2DelCmds, argc, argv);

+}

+

+static AIR_ERROR_NO_T

+doL2Add(

+        UI32_T argc,

+        C8_T *argv[])

+{

+    return subcmd(l2AddCmds, argc, argv);

+}

+

+static AIR_ERROR_NO_T

+doL2(

+        UI32_T argc,

+        C8_T *argv[])

+{

+    return subcmd(l2Cmds, argc, argv);

+}

+

+static AIR_ERROR_NO_T

+doAnMode(

+        UI32_T argc,

+        C8_T *argv[])

+{

+    AIR_ERROR_NO_T ret = AIR_E_OK;

+    UI32_T port = 0;

+    BOOL_T en = 0;

+

+    port = _strtol(argv[0], NULL, 10);

+

+    if(1 == argc)

+    {

+        /* port get anCap <port> */

+        ret = air_port_getAnMode(0, port, &en);

+        if(ret == AIR_E_OK)

+            AIR_PRINT("Get Port%02d Auto-Negotiation %s\n", port, ((en)?"Enabled":"Disabled"));

+        else

+            AIR_PRINT("Get Port%02d Auto-Negotiation Fail.\n", port);

+    }

+    else if(2 == argc)

+    {

+        /* "port set anMode <port> <en> */

+        en = _strtol(argv[1], NULL, 10);

+        ret = air_port_setAnMode(0, port, en);

+        if(ret == AIR_E_OK)

+            AIR_PRINT("Set Port%02d Auto-Negotiation Mode:%s\n", port, ((en)?"Enabled":"Disabled"));

+        else

+            AIR_PRINT("Set Port%02d Auto-Negotiation Fail.\n", port);

+    }

+    else

+    {

+        AIR_PRINT("Unrecognized command.\n");

+        ret = AIR_E_BAD_PARAMETER;

+    }

+

+    return ret;

+}

+

+static AIR_ERROR_NO_T

+doLocalAdv(

+        UI32_T argc,

+        C8_T *argv[])

+{

+    AIR_ERROR_NO_T ret = AIR_E_OK;

+    UI32_T port = 0;

+    AIR_AN_ADV_T adv;

+

+    memset(&adv, 0, sizeof(AIR_AN_ADV_T));

+    port = _strtol(argv[0], NULL, 10);

+

+    if(1 == argc)

+    {

+        /* port get localAdv <port> */

+        ret = air_port_getLocalAdvAbility(0, port, &adv);

+        AIR_PRINT("Get Port%02d Local Auto-Negotiation Advertisement: ", port);

+        if(AIR_E_OK != ret)

+        {

+            AIR_PRINT("Fail!\n");

+        }

+    }

+    else if(7 == argc)

+    {

+        /* port set localAdv <port> <10H> <10F> <100H> <100F> <1000F> <pause> */

+        adv.advCap10HDX = _strtol(argv[1], NULL, 0) & BIT(0);

+        adv.advCap10FDX = _strtol(argv[2], NULL, 0) & BIT(0);

+        adv.advCap100HDX = _strtol(argv[3], NULL, 0) & BIT(0);

+        adv.advCap100FDX = _strtol(argv[4], NULL, 0) & BIT(0);

+        adv.advCap1000FDX = _strtol(argv[5], NULL, 0) & BIT(0);

+        adv.advPause = _strtol(argv[6], NULL, 0) & BIT(0);

+        ret = air_port_setLocalAdvAbility(0, port, adv);

+        AIR_PRINT("Set Port%02d Local Auto-Negotiation Advertisement: ", port);

+        if(AIR_E_OK != ret)

+        {

+            AIR_PRINT("Fail!\n");

+        }

+    }

+    else

+    {

+        AIR_PRINT("Unrecognized command.\n");

+        ret = AIR_E_BAD_PARAMETER;

+    }

+

+    if(ret == AIR_E_OK)

+    {

+        AIR_PRINT("\n");

+        AIR_PRINT("\tAdvertise 10BASE-T Half Duplex: %s\n", (adv.advCap10HDX)?"Effective":"Not Effective" );

+        AIR_PRINT("\tAdvertise 10BASE-T Full Duplex: %s\n", (adv.advCap10FDX)?"Effective":"Not Effective" );

+        AIR_PRINT("\tAdvertise 100BASE-T Half Duplex: %s\n", (adv.advCap100HDX)?"Effective":"Not Effective" );

+        AIR_PRINT("\tAdvertise 100BASE-T Full Duplex: %s\n", (adv.advCap100FDX)?"Effective":"Not Effective" );

+        AIR_PRINT("\tAdvertise 1000BASE-T Full Duplex: %s\n", (adv.advCap1000FDX)?"Effective":"Not Effective" );

+        AIR_PRINT("\tAdvertise Asynchronous Pause: %s\n", (adv.advPause)?"Effective":"Not Effective" );

+    }

+

+    return ret;

+}

+

+static AIR_ERROR_NO_T

+doRemoteAdv(

+        UI32_T argc,

+        C8_T *argv[])

+{

+    AIR_ERROR_NO_T ret = AIR_E_OK;

+    UI32_T port = 0;

+    AIR_AN_ADV_T lp_adv;

+

+    memset(&lp_adv, 0, sizeof(AIR_AN_ADV_T));

+    port = _strtol(argv[0], NULL, 10);

+

+    if(1 == argc)

+    {

+        /* port get remoteAdv <port> */

+        ret = air_port_getRemoteAdvAbility(0, port, &lp_adv);

+        AIR_PRINT("Get Port%02d Remote Auto-Negotiation Advertisement: ", port);

+        if(AIR_E_OK != ret)

+        {

+            AIR_PRINT("Fail!\n");

+        }

+    }

+    else

+    {

+        AIR_PRINT("Unrecognized command.\n");

+        ret = AIR_E_BAD_PARAMETER;

+    }

+

+    if(ret == AIR_E_OK)

+    {

+        AIR_PRINT("\n");

+        AIR_PRINT("\tAdvertise 10BASE-T Half Duplex: %s\n", lp_adv.advCap10HDX?"Effective":"Not Effective" );

+        AIR_PRINT("\tAdvertise 10BASE-T Full Duplex: %s\n", lp_adv.advCap10FDX?"Effective":"Not Effective" );

+        AIR_PRINT("\tAdvertise 100BASE-T Half Duplex: %s\n", lp_adv.advCap100HDX?"Effective":"Not Effective" );

+        AIR_PRINT("\tAdvertise 100BASE-T Full Duplex: %s\n", lp_adv.advCap100FDX?"Effective":"Not Effective" );

+        AIR_PRINT("\tAdvertise 1000BASE-T Full Duplex: %s\n", (lp_adv.advCap1000FDX)?"Effective":"Not Effective" );

+        AIR_PRINT("\tAdvertise Asynchronous Pause: %s\n", (lp_adv.advPause)?"Effective":"Not Effective" );

+    }

+

+    return ret;

+}

+

+static AIR_ERROR_NO_T

+doPortSpeed(

+        UI32_T argc,

+        C8_T *argv[])

+{

+    AIR_ERROR_NO_T ret = AIR_E_OK;

+    UI32_T port = 0;

+    UI32_T speed = 0;

+

+    port = _strtol(argv[0], NULL, 10);

+

+    if(1 == argc)

+    {

+        /* port get speed <port> */

+        ret = air_port_getSpeed(0, port, &speed);

+        if(ret == AIR_E_OK)

+        {

+            AIR_PRINT("Get Port%02d Speed:", port);

+        }

+        else

+        {

+            AIR_PRINT("Get Port%02d Speed Fail!\n", port);

+        }

+    }

+    else if(2 == argc)

+    {

+        /* port set speed <port> <speed> */

+        speed = _strtol(argv[1], NULL, 10);

+        ret = air_port_setSpeed(0, port, speed);

+        if(ret == AIR_E_OK)

+        {

+            AIR_PRINT("Set Port%02d Speed:", port);

+        }

+        else

+        {

+            AIR_PRINT("Set Port%02d Speed Fail!\n", port);

+        }

+    }

+    else

+    {

+        AIR_PRINT("Unrecognized command.\n");

+        ret = AIR_E_BAD_PARAMETER;

+    }

+

+    if(ret == AIR_E_OK)

+    {

+        switch(speed)

+        {

+            case AIR_PORT_SPEED_10M:

+                AIR_PRINT(" 10 Mbps\n");

+                break;

+            case AIR_PORT_SPEED_100M:

+                AIR_PRINT(" 100 Mbps\n");

+                break;

+            case AIR_PORT_SPEED_1000M:

+                AIR_PRINT(" 1 Gbps\n");

+                break;

+            case AIR_PORT_SPEED_2500M:

+                AIR_PRINT(" 2.5 Gbps\n");

+                break;

+            default:

+                AIR_PRINT(" Reserved\n");

+                break;

+        }

+    }

+

+    return ret;

+}

+

+static AIR_ERROR_NO_T

+doPortDuplex(

+        UI32_T argc,

+        C8_T *argv[])

+{

+    AIR_ERROR_NO_T ret = AIR_E_OK;

+    UI32_T port = 0;

+    UI32_T duplex = 0;

+

+    port = _strtol(argv[0], NULL, 10);

+

+    if(1 == argc)

+    {

+        /* port get duplex <port> */

+        ret = air_port_getDuplex(0, port, &duplex);

+        if(ret == AIR_E_OK)

+        {

+            AIR_PRINT("Get Port%02d Duplex:%s\n", port, duplex?"Full":"Half");

+        }

+        else

+        {

+            AIR_PRINT("Get Port%02d Duplex Fail!\n", port);

+        }

+    }

+    else if(2 == argc)

+    {

+        /* port set duplex <port> <duplex> */

+        duplex = _strtol(argv[1], NULL, 10);

+        ret = air_port_setDuplex(0, port, duplex);

+        if(ret == AIR_E_OK)

+        {

+            AIR_PRINT("Set Port%02d Duplex:%s\n", port, duplex?"Full":"Half");

+        }

+        else

+        {

+            AIR_PRINT("Set Port%02d Duplex Fail!\n", port);

+        }

+    }

+    else

+    {

+        AIR_PRINT("Unrecognized command.\n");

+        ret = AIR_E_BAD_PARAMETER;

+    }

+

+    return ret;

+}

+

+static AIR_ERROR_NO_T

+doPortStatus(

+        UI32_T argc,

+        C8_T *argv[])

+{

+    AIR_ERROR_NO_T ret = AIR_E_OK;

+    UI32_T port = 0;

+    AIR_PORT_STATUS_T ps;

+

+    memset(&ps, 0, sizeof(AIR_PORT_STATUS_T));

+    port = _strtol(argv[0], NULL, 10);

+

+    if(1 == argc)

+    {

+        /* port get status <port> */

+        ret = air_port_getLink(0, port, &ps);

+        if(ret == AIR_E_OK)

+        {

+            AIR_PRINT("Get Port%02d Link-Status\n", port);

+            AIR_PRINT("\tLink: %s\n", ps.link?"Up":"Down");

+            AIR_PRINT("\tDuplex: %s\n", ps.duplex?"Full":"Half");

+            AIR_PRINT("\tSpeed: ");

+            switch(ps.speed)

+            {

+                case AIR_PORT_SPEED_10M:

+                    AIR_PRINT("10 Mbps\n");

+                    break;

+                case AIR_PORT_SPEED_100M:

+                    AIR_PRINT("100 Mbps\n");

+                    break;

+                case AIR_PORT_SPEED_1000M:

+                    AIR_PRINT("1 Gbps\n");

+                    break;

+                case AIR_PORT_SPEED_2500M:

+                    AIR_PRINT("2.5 Gbps\n");

+                    break;

+                default:

+                    AIR_PRINT("Reserved\n");

+                    break;

+            }

+        }

+        else

+            AIR_PRINT("Get Port%02d Link-Status Fail!", port);

+    }

+    else

+    {

+        AIR_PRINT("Unrecognized command.\n");

+        ret = AIR_E_BAD_PARAMETER;

+    }

+

+    return ret;

+}

+

+static AIR_ERROR_NO_T

+doPortBckPres(

+        UI32_T argc,

+        C8_T *argv[])

+{

+    AIR_ERROR_NO_T ret = AIR_E_OK;

+    UI32_T port = 0;

+    UI32_T bckPres = 0;

+

+    port = _strtol(argv[0], NULL, 10);

+

+    if(1 == argc)

+    {

+        /* port get bckPres <port> */

+        ret = air_port_getBckPres(0, port, &bckPres);

+        if(ret == AIR_E_OK)

+            AIR_PRINT("Get Port%02d BckPres:%s\n", port, bckPres?"Enabled":"Disabled");

+        else

+            AIR_PRINT("Get Port%02d BckPres Fail!\n", port);

+    }

+    else if(2 == argc)

+    {

+        /* port set bckPres <port> <bckPres> */

+        bckPres = _strtol(argv[1], NULL, 10);

+        ret = air_port_setBckPres(0, port, bckPres);

+        if(ret == AIR_E_OK)

+            AIR_PRINT("Set Port%02d BckPres:%s\n", port, bckPres?"Enabled":"Disabled");

+        else

+            AIR_PRINT("Set Port%02d BckPres Fail!\n", port);

+    }

+    else

+    {

+        AIR_PRINT("Unrecognized command.\n");

+        ret = AIR_E_BAD_PARAMETER;

+    }

+

+    return ret;

+}

+

+static AIR_ERROR_NO_T

+doPortPsMode(

+        UI32_T argc,

+        C8_T *argv[])

+{

+    AIR_ERROR_NO_T ret = AIR_E_OK;

+    UI32_T port = 0;

+    UI32_T mode = 0;

+    BOOL_T ls_en = 0;

+    BOOL_T eee_en = 0;

+

+    port = _strtol(argv[0], NULL, 10);

+

+    if(1 == argc)

+    {

+        /* port get psMode <port> */

+        ret = air_port_getPsMode(0, port, &mode);

+        AIR_PRINT("Get Port%02d Power-Saving: ", port);

+        if(ret == AIR_E_OK)

+        {

+            AIR_PRINT("Done\n");

+        }

+        else

+        {

+            AIR_PRINT("Fail!\n");

+        }

+    }

+    else if(3 == argc)

+    {

+        /* port set psMode <port> <ls> <eee> */

+        ls_en = _strtol(argv[1], NULL, 0);

+        eee_en = _strtol(argv[2], NULL, 0);

+        if(TRUE == ls_en)

+        {

+            mode |= AIR_PORT_PS_LINKSTATUS;

+        }

+        if(TRUE == eee_en)

+        {

+            mode |= AIR_PORT_PS_EEE;

+        }

+        ret = air_port_setPsMode(0, port, mode);

+        AIR_PRINT("Set Port%02d Power-Saving: ", port);

+        if(ret == AIR_E_OK)

+        {

+            AIR_PRINT("Done\n");

+        }

+        else

+        {

+            AIR_PRINT("Fail!\n");

+        }

+    }

+    else

+    {

+        AIR_PRINT("Unrecognized command.\n");

+        ret = AIR_E_BAD_PARAMETER;

+    }

+    if(ret == AIR_E_OK)

+    {

+        AIR_PRINT("\tLink status:%s\n", (mode & AIR_PORT_PS_LINKSTATUS)?"Enable":"Disable");

+        AIR_PRINT("\tEEE:%s\n", (mode & AIR_PORT_PS_EEE)?"Enable":"Disable");

+    }

+    return ret;

+}

+

+static AIR_ERROR_NO_T

+doPortSmtSpdDwn(

+        UI32_T argc,

+        C8_T *argv[])

+{

+    AIR_ERROR_NO_T ret = AIR_E_OK;

+    UI32_T port = 0;

+    UI32_T state = 0;

+    UI32_T retry = 0;

+

+    port = _strtol(argv[0], NULL, 10);

+

+    if(1 == argc)

+    {

+        /* port get smtSpdDwn <port> */

+        ret = air_port_getSmtSpdDwn(0, port, &state, &retry);

+        if(ret == AIR_E_OK)

+        {

+            AIR_PRINT("Get Port%02d Smart Speed Down: %s\n", port, state?"Enabled":"Disabled");

+            AIR_PRINT("Get Port%02d Retry Time: %d\n", port, retry + 2);

+        }

+        else

+            AIR_PRINT("Get Port%02d Smart-SpeedDown Fail!\n", port);

+    }

+    else if(3 == argc)

+    {

+        /* port set smtSpdDwn <port> <en> <retry> */

+        state = _strtol(argv[1], NULL, 10);

+        retry = _strtol(argv[2], NULL, 10);

+        if(retry >= 2)

+        {

+            ret = air_port_setSmtSpdDwn(0, port, state, retry - 2);

+            if(ret == AIR_E_OK)

+            {

+                AIR_PRINT("Set Port%02d Smart Speed Down: %s\n", port, state?"Enabled":"Disabled");

+                AIR_PRINT("Set Port%02d Retry Time: %d\n", port, retry);

+            }

+            else

+                AIR_PRINT("Set Port%02d Smart-SpeedDown Fail!\n", port);

+        }

+        else

+        {

+            ret = AIR_E_BAD_PARAMETER;

+        }

+    }

+    else

+    {

+        AIR_PRINT("Unrecognized command.\n");

+        ret = AIR_E_BAD_PARAMETER;

+    }

+

+    return ret;

+}

+

+static AIR_ERROR_NO_T

+doPortSpTag(

+        UI32_T argc,

+        C8_T *argv[])

+{

+    AIR_ERROR_NO_T ret = AIR_E_OK;

+    UI32_T port = 0;

+    BOOL_T sptag_en = FALSE;

+

+    port = _strtol(argv[0], NULL, 10);

+

+    if(1 == argc)

+    {

+        /* port get spTag <port> */

+        ret = air_port_getSpTag(0, port, &sptag_en);

+        if(AIR_E_OK == ret)

+        {

+            AIR_PRINT("Get Port%02d Special Tag %s\n", port, ((sptag_en)?"Enabled":"Disabled"));

+        }

+        else

+        {

+            AIR_PRINT("Get Port%02d Special Tag Fail.\n", port);

+        }

+    }

+    else if(2 == argc)

+    {

+        /* port set spTag <port> <en> */

+        sptag_en = _strtol(argv[1], NULL, 10);

+        ret = air_port_setSpTag(0, port, sptag_en);

+        if(AIR_E_OK == ret)

+        {

+            AIR_PRINT("Set Port%02d Special Tag:%s\n", port, ((sptag_en)?"Enabled":"Disabled"));

+        }

+        else

+        {

+            AIR_PRINT("Set Port%02d Special Tag Fail.\n", port);

+        }

+    }

+    else

+    {

+        AIR_PRINT("Unrecognized command.\n");

+        ret = AIR_E_BAD_PARAMETER;

+    }

+

+    return ret;

+}

+

+static AIR_ERROR_NO_T

+doPortEnable(

+        UI32_T argc,

+        C8_T *argv[])

+{

+    AIR_ERROR_NO_T ret = AIR_E_OK;

+    UI32_T port = 0;

+    UI32_T state = 0;

+

+    port = _strtol(argv[0], NULL, 10);

+

+    if(1 == argc)

+    {

+        /* port get enable <port> */

+        ret = air_port_getEnable(0, port, &state);

+        if(ret == AIR_E_OK)

+            AIR_PRINT("Get Port%02d State:%s\n", port, state?"Enable":"Disable");

+        else

+            AIR_PRINT("Get Port%02d State Fail!\n", port);

+    }

+    else if(2 == argc)

+    {

+        /* port set enable <port> <en> */

+        state = _strtol(argv[1], NULL, 10);

+        ret = air_port_setEnable(0, port, state);

+        if(ret == AIR_E_OK)

+            AIR_PRINT("Set Port%02d State:%s\n", port, state?"Enable":"Disable");

+        else

+            AIR_PRINT("Set Port%02d State Fail!\n", port);

+    }

+    else

+    {

+        AIR_PRINT("Unrecognized command.\n");

+        ret = AIR_E_BAD_PARAMETER;

+    }

+

+    return ret;

+}

+

+static AIR_ERROR_NO_T

+doPort5GBaseRMode(

+    UI32_T argc,

+    C8_T *argv[])

+{

+    AIR_ERROR_NO_T ret = AIR_E_OK;

+

+    if(0 == argc)

+    {

+        /* port set 5GBaseRMode */

+        ret = air_port_set5GBaseRModeEn(0);

+        if(ret == AIR_E_OK)

+            AIR_PRINT("Set Port05 Mode: 5GBase-R\n");

+        else

+            AIR_PRINT("Set Port05 HSGMII Mode Fail.\n");

+    }

+    else

+    {

+        AIR_PRINT("Unrecognized command.\n");

+        ret = AIR_E_BAD_PARAMETER;

+    }

+

+    return ret;

+}

+

+static AIR_ERROR_NO_T

+doPortHsgmiiMode(

+    UI32_T argc,

+    C8_T *argv[])

+{

+    AIR_ERROR_NO_T ret = AIR_E_OK;

+

+    if(0 == argc)

+    {

+        /* port set hsgmiiMode */

+        ret = air_port_setHsgmiiModeEn(0);

+        if(ret == AIR_E_OK)

+            AIR_PRINT("Set Port05 Mode: HSGMII\n");

+        else

+            AIR_PRINT("Set Port05 HSGMII Mode Fail.\n");

+    }

+    else

+    {

+        AIR_PRINT("Unrecognized command.\n");

+        ret = AIR_E_BAD_PARAMETER;

+    }

+

+    return ret;

+}

+

+static AIR_ERROR_NO_T

+doPortSgmiiMode(

+    UI32_T argc,

+    C8_T *argv[])

+{

+    AIR_ERROR_NO_T ret = AIR_E_OK;

+    UI32_T mode = 0;

+    UI32_T speed = 0;

+

+    if(2 == argc)

+    {

+        /* port set sgmiiMode <mode(0:AN,1:Force)> <speed> */

+        mode = _strtol(argv[0], NULL, 10);

+        speed = _strtol(argv[1], NULL, 10);

+        ret = air_port_setSgmiiMode(0, mode, speed);

+        if(ret == AIR_E_OK)

+            AIR_PRINT("Set Port05 SGMII Mode:%s\nIf in Force Mode, speed:", mode?"Force":"AN");

+        else

+            AIR_PRINT("Set Port05 SGMII Mode Fail.\n");

+    }

+    else

+    {

+        AIR_PRINT("Unrecognized command.\n");

+        ret = AIR_E_BAD_PARAMETER;

+    }

+

+    if(ret == AIR_E_OK)

+    {

+        switch(speed)

+        {

+            case AIR_PORT_SPEED_10M:

+                AIR_PRINT(" 10 Mbps\n");

+                break;

+            case AIR_PORT_SPEED_100M:

+                AIR_PRINT(" 100 Mbps\n");

+                break;

+            case AIR_PORT_SPEED_1000M:

+                AIR_PRINT(" 1 Gbps\n");

+                break;

+            default:

+                AIR_PRINT(" Reserved\n");

+                break;

+        }

+    }

+

+    return ret;

+}

+

+static AIR_ERROR_NO_T

+doPortRmiiMode(

+        UI32_T argc,

+        C8_T *argv[])

+{

+    AIR_ERROR_NO_T ret = AIR_E_OK;

+    UI32_T speed = 0;

+

+    if(1 == argc)

+    {

+        /* port set rmiiMode <speed> */

+        speed = _strtol(argv[0], NULL, 10);

+        ret = air_port_setRmiiMode(0, speed);

+        if(ret == AIR_E_OK)

+        {

+            AIR_PRINT("Set Port05 RMII Mode Speed:");

+        }

+        else

+        {

+            AIR_PRINT("Set Port05 RMII Mode Fail!\n");

+        }

+    }

+    else

+    {

+        AIR_PRINT("Unrecognized command.\n");

+        ret = AIR_E_BAD_PARAMETER;

+    }

+

+    if(ret == AIR_E_OK)

+    {

+        switch(speed)

+        {

+            case AIR_PORT_SPEED_10M:

+                AIR_PRINT(" 10 Mbps\n");

+                break;

+            case AIR_PORT_SPEED_100M:

+                AIR_PRINT(" 100 Mbps\n");

+                break;

+            default:

+                AIR_PRINT(" Reserved\n");

+                break;

+        }

+    }

+

+    return ret;

+}

+

+static AIR_ERROR_NO_T

+doPortRgmiiMode(

+        UI32_T argc,

+        C8_T *argv[])

+{

+    AIR_ERROR_NO_T ret = AIR_E_OK;

+    UI32_T speed = 0;

+

+    if(1 == argc)

+    {

+        /* port set rgmiiMode <speed> */

+        speed = _strtol(argv[0], NULL, 10);

+        ret = air_port_setRgmiiMode(0, speed);

+        if(ret == AIR_E_OK)

+        {

+            AIR_PRINT("Set Port05 RGMII Mode Speed:");

+        }

+        else

+        {

+            AIR_PRINT("Set Port05 RGMII Mode Fail!\n");

+        }

+    }

+    else

+    {

+        AIR_PRINT("Unrecognized command.\n");

+        ret = AIR_E_BAD_PARAMETER;

+    }

+

+    if(ret == AIR_E_OK)

+    {

+        switch(speed)

+        {

+            case AIR_PORT_SPEED_10M:

+                AIR_PRINT(" 10 Mbps\n");

+                break;

+            case AIR_PORT_SPEED_100M:

+                AIR_PRINT(" 100 Mbps\n");

+                break;

+            case AIR_PORT_SPEED_1000M:

+                AIR_PRINT(" 1 Gbps\n");

+                break;

+            default:

+                AIR_PRINT(" Reserved\n");

+                break;

+        }

+    }

+

+    return ret;

+}

+

+static AIR_ERROR_NO_T

+doSptagEn(

+        UI32_T argc,

+        C8_T *argv[])

+{

+    AIR_ERROR_NO_T ret = AIR_E_OK;

+    UI32_T port = 0;

+    BOOL_T sp_en = FALSE;

+

+    port =  _strtol(argv[0], NULL, 10);

+    if (2 == argc)

+    {

+        sp_en =  _strtol(argv[1], NULL, 10);

+        ret = air_sptag_setState(0,port,sp_en);

+        if(AIR_E_OK == ret)

+        {

+            AIR_PRINT("set port %d SpTag state %s sucess\n", port,sp_en?"Enable":"Disable");

+        }

+        else

+        {

+            AIR_PRINT("set port %d SpTag state %s fail\n", port,sp_en?"Enable":"Disable");

+        }

+    }

+    else if(1 == argc)

+    {

+        air_sptag_getState(0,port,&sp_en);

+        AIR_PRINT("get port %d SpTag state: %s \n", port,sp_en?"Enable":"Disable");

+    }

+    else

+    {

+        AIR_PRINT("Unrecognized command.\n");

+        ret = AIR_E_BAD_PARAMETER;

+    }

+

+    return ret;

+}

+

+static AIR_ERROR_NO_T

+doSptagMode(

+        UI32_T argc,

+        C8_T *argv[])

+{

+    AIR_ERROR_NO_T ret = AIR_E_OK;

+    UI32_T port = 0;

+    BOOL_T sp_mode = FALSE;

+

+

+    port =  _strtol(argv[0], NULL, 10);

+    if (2 == argc)

+    {

+        sp_mode  =  _strtol(argv[1], NULL, 10);

+        ret = air_sptag_setMode(0,port,sp_mode);

+        if(AIR_E_OK == ret)

+        {

+            AIR_PRINT("set port %d SpTag Mode  %s sucess\n", port,sp_mode?"replace":"insert");

+        }

+        else

+        {

+            AIR_PRINT("set port %d SpTag state %s fail\n", port,sp_mode?"replace":"insert");

+        }

+    }

+    else if(1 == argc)

+    {

+        air_sptag_getMode(0,port,&sp_mode);

+        AIR_PRINT("get port %d SpTag state: %s \n", port,sp_mode?"replace":"insert");

+    }

+    else

+    {

+        AIR_PRINT("Unrecognized command.\n");

+        ret = AIR_E_BAD_PARAMETER;

+    }

+

+    return ret;

+}

+

+static AIR_ERROR_NO_T

+doSptagDecode(

+        UI32_T argc,

+        C8_T *argv[])

+{

+    AIR_ERROR_NO_T ret = AIR_E_OK;

+    AIR_SPTAG_RX_PARA_T sptag_rx = {0};

+    UI8_T buf[AIR_STAG_BUF_LEN] = {0};

+    UI32_T len = AIR_STAG_BUF_LEN, i = 0;

+

+    if (4 == argc)

+    {

+        for(i = 0; i < len; i++)

+        {

+            buf[i] = _strtoul(argv[i], NULL, 16);

+        }

+

+        ret = air_sptag_decodeRx(0, buf, len, &sptag_rx);

+        if (AIR_E_OK != ret)

+        {

+            AIR_PRINT("SpTag decode fail\n");

+            return ret;

+        }

+

+        AIR_PRINT("SpTag decode success:\n");

+        AIR_PRINT("RSN : %s\n", _sptag_pt[sptag_rx.rsn]);

+        AIR_PRINT("VPM : %s\n", _sptag_vpm[sptag_rx.vpm]);

+        AIR_PRINT("SPN : %d\n", sptag_rx.spn);

+        AIR_PRINT("PRI : %d\n", sptag_rx.pri);

+        AIR_PRINT("CFI : %d\n", sptag_rx.cfi);

+        AIR_PRINT("VID : %d\n", sptag_rx.vid);

+    }

+    else

+    {

+        AIR_PRINT("Unrecognized command.\n");

+        ret = AIR_E_BAD_PARAMETER;

+    }

+

+    return ret;

+}

+

+static AIR_ERROR_NO_T

+doSptagEncode(

+        UI32_T argc,

+        C8_T *argv[])

+{

+    AIR_ERROR_NO_T ret = AIR_E_OK;

+    AIR_STAG_TX_PARA_T sptag_tx = {0};

+    UI8_T buf[AIR_STAG_BUF_LEN] = {0};

+    UI32_T len = AIR_STAG_BUF_LEN;

+    char str[128] = {'\0'};

+    UI32_T data = 0;

+    AIR_STAG_MODE_T mode = AIR_STAG_MODE_LAST;

+

+    if (7 == argc)

+    {

+        if(_strcmp(argv[0],"mode=replace") == 0)

+            mode = AIR_STAG_MODE_REPLACE;

+        else if(_strcmp(argv[0],"mode=insert") == 0)

+            mode = AIR_STAG_MODE_INSERT;

+        else

+            printf("mode is wrong!!");

+

+        if(_strcmp(argv[1],"opc=portmap") == 0)

+            sptag_tx.opc = AIR_STAG_OPC_PORTMAP;

+        else if(_strcmp(argv[1],"opc=portid") == 0)

+            sptag_tx.opc = AIR_STAG_OPC_PORTID;

+        else if(_strcmp(argv[1],"opc=lookup") == 0)

+            sptag_tx.opc = AIR_STAG_OPC_LOOKUP;

+        else

+            printf("opc is wrong!!");

+

+        if(sscanf(argv[2],"dp=%x",&data) != -1)

+        {

+            sptag_tx.pbm = data;

+            AIR_PRINT("sptag_tx.pbm %x\n",sptag_tx.pbm);

+        }

+

+        if(_strcmp(argv[3],"vpm=untagged") == 0)

+            sptag_tx.vpm = AIR_STAG_VPM_UNTAG;

+        else if(_strcmp(argv[3],"vpm=8100") == 0)

+            sptag_tx.vpm = AIR_STAG_VPM_TPID_8100;

+        else if(_strcmp(argv[3],"vpm=88a8") == 0)

+            sptag_tx.vpm = AIR_STAG_VPM_TPID_88A8;

+        else

+            printf("vpm is wrong!!");

+

+        if(sscanf(argv[4],"pri=%d",&data) != -1)

+        {

+            sptag_tx.pri = data;

+            AIR_PRINT("sptag_tx.pri %d\n",sptag_tx.pri);

+        }

+

+        if(sscanf(argv[5],"cfi=%d",&data) != -1)

+        {

+            sptag_tx.cfi  = data;

+            AIR_PRINT("sptag_tx.cfi %d\n",sptag_tx.cfi);

+        }

+

+        if(sscanf(argv[6],"vid=%d",&data) != -1)

+        {

+            sptag_tx.vid = data;

+            AIR_PRINT("sptag_tx.vid %d\n",sptag_tx.vid);

+        }

+

+        ret = air_sptag_encodeTx(0,mode, &sptag_tx, (UI8_T *)&buf, &len);

+        if(AIR_E_OK == ret)

+        {

+            AIR_PRINT("SpTag encode sucess, returned len=%d\n", len);

+            AIR_PRINT("Encoded SpTag: %02x %02x %02x %02x\n", buf[0], buf[1], buf[2], buf[3]);

+        }

+        else

+        {

+            AIR_PRINT("SpTag encode fail\n");

+        }

+    }

+    else

+    {

+        AIR_PRINT("Unrecognized command.\n");

+        ret = AIR_E_BAD_PARAMETER;

+    }

+

+    return ret;

+}

+

+static AIR_ERROR_NO_T

+doSptag(

+        UI32_T argc,

+        C8_T *argv[])

+{

+    return subcmd(sptagCmds, argc, argv);

+}

+

+static AIR_ERROR_NO_T

+doL2Dump(

+        UI32_T argc,

+        C8_T *argv[])

+{

+    return subcmd(l2DumpCmds, argc, argv);

+}

+

+static AIR_ERROR_NO_T

+doMacAddr(

+        UI32_T argc,

+        C8_T *argv[])

+{

+    AIR_ERROR_NO_T ret = AIR_E_OK;

+    AIR_MAC_ENTRY_T mt;

+    UI32_T fwd = 0;

+

+    memset(&mt, 0, sizeof(AIR_MAC_ENTRY_T));

+

+    if(0 == argc)

+    {

+        /* l2 clear mac */

+        ret = air_l2_clearMacAddr(0);

+        if(ret == AIR_E_OK)

+            AIR_PRINT("Clear MAC Address Table Done.\n");

+        else

+            AIR_PRINT("Clear MAC Address Table Fail.\n");

+    }

+    else if(3 == argc)

+    {

+        /* l2 del mac <mac(12'hex)> { vid <vid(0..4095)> | fid <fid(0..15)> } */

+        ret = _str2mac(argv[0], (C8_T *)mt.mac);

+        if(ret != AIR_E_OK)

+        {

+            AIR_PRINT("Unrecognized command.\n");

+            return ret;

+        }

+

+        /* check argument 1 */

+        if(FALSE == _strcmp(argv[1], "vid"))

+        {

+            /* get mac entry by MAC address & vid */

+            mt.cvid = _strtoul(argv[2], NULL, 0);

+            mt.flags |= AIR_L2_MAC_ENTRY_FLAGS_IVL;

+            AIR_PRINT("Get MAC Address:" MAC_STR " with vid:%u", MAC2STR(mt.mac), mt.cvid);

+        }

+        else if(FALSE == _strcmp(argv[1], "fid"))

+        {

+            /* get mac entry by MAC address & fid */

+            mt.fid = _strtoul(argv[2], NULL, 0);

+            AIR_PRINT("Get MAC Address:" MAC_STR " with fid:%u", MAC2STR(mt.mac), mt.fid);

+        }

+        else

+        {

+            AIR_PRINT("Unrecognized command.\n");

+            return AIR_E_BAD_PARAMETER;

+        }

+        ret = air_l2_delMacAddr(0, &mt);

+        if(ret == AIR_E_OK)

+        {

+            AIR_PRINT(" Done.\n");

+        }

+        else

+            AIR_PRINT("\n Fail!\n");

+    }

+    else if(7 == argc)

+    {

+        /* l2 add mac <static(0:dynamic,1:static)> <unauth(0:auth,1:unauth)> <mac(12'hex)> <portlist(uintlist)> [ vid <vid(0..4095)> | fid <fid(0..15)> ] <src_mac_forward=(0:default,1:cpu-include,2:cpu-exclude,3:cpu-only,4:drop)> */

+        if(argv[0])

+            mt.flags |= AIR_L2_MAC_ENTRY_FLAGS_STATIC;

+

+        if(argv[1])

+            mt.flags |= AIR_L2_MAC_ENTRY_FLAGS_UNAUTH;

+

+        ret = _str2mac(argv[2], (C8_T *)mt.mac);

+        if(ret != AIR_E_OK)

+        {

+            AIR_PRINT("Unrecognized command.\n");

+            return ret;

+        }

+

+        ret = _portListStr2Ary(argv[3], mt.port_bitmap, 1);

+        if(ret != AIR_E_OK)

+        {

+            AIR_PRINT("Unrecognized command.\n");

+            return ret;

+        }

+

+        /* check argument fid or vid */

+        if(FALSE == _strcmp(argv[4], "vid"))

+        {

+            /* get mac entry by MAC address & vid */

+            mt.cvid = _strtoul(argv[5], NULL, 0);

+            mt.flags |= AIR_L2_MAC_ENTRY_FLAGS_IVL;

+        }

+        else if(FALSE == _strcmp(argv[4], "fid"))

+        {

+            /* get mac entry by MAC address & fid */

+            mt.fid = _strtoul(argv[5], NULL, 0);

+        }

+        else

+        {

+            AIR_PRINT("Unrecognized command.\n");

+            return AIR_E_BAD_PARAMETER;

+        }

+        fwd = _strtoul(argv[6], NULL, 0);

+        if(0 == fwd)

+            mt.sa_fwd = AIR_L2_FWD_CTRL_DEFAULT;

+        else if(1 == fwd)

+            mt.sa_fwd = AIR_L2_FWD_CTRL_CPU_INCLUDE;

+        else if(2 == fwd)

+            mt.sa_fwd = AIR_L2_FWD_CTRL_CPU_EXCLUDE;

+        else if(3 == fwd)

+            mt.sa_fwd = AIR_L2_FWD_CTRL_CPU_ONLY;

+        else if(4 == fwd)

+            mt.sa_fwd = AIR_L2_FWD_CTRL_DROP;

+        else

+        {

+            AIR_PRINT("Unrecognized command.\n");

+            return AIR_E_BAD_PARAMETER;

+        }

+        ret = air_l2_addMacAddr(0, &mt);

+        AIR_PRINT("Add MAC Address:" MAC_STR, MAC2STR(mt.mac));

+        if(ret == AIR_E_OK)

+            AIR_PRINT(" Done.\n");

+        else

+            AIR_PRINT(" Fail.\n");

+    }

+    else

+    {

+        AIR_PRINT("Unrecognized command.\n");

+        ret = AIR_E_BAD_PARAMETER;

+    }

+

+    return ret;

+}

+

+static AIR_ERROR_NO_T

+_printMacEntry(

+        AIR_MAC_ENTRY_T *mt,

+        UI32_T age_unit,

+        UI8_T count,

+        UI8_T title)

+{

+    AIR_ERROR_NO_T ret = AIR_E_OK;

+    I32_T i = 0, j = 0;

+    UI8_T first = 0;

+    UI8_T find = 0;

+    if(title)

+    {

+        AIR_PRINT("%-6s%-15s%-5s%-5s%-5s%-10s%-10s%-6s\n",

+                "unit",

+                "mac",

+                "ivl",

+                "vid",

+                "fid",

+                "age-time",

+                "forward",

+                "port");

+        return ret;

+    }

+    for(i = 0; i < count; i++)

+    {

+        AIR_PRINT("%-6d", age_unit);

+        AIR_PRINT(MAC_STR, MAC2STR(mt[i].mac));

+        AIR_PRINT("...");

+        if(mt[i].flags & AIR_L2_MAC_ENTRY_FLAGS_IVL)

+        {

+            AIR_PRINT("%-3s..", "ivl");

+            AIR_PRINT("%-5d", mt[i].cvid);

+            AIR_PRINT("%-5s", ".....");

+        }

+        else

+        {

+            AIR_PRINT("%-3s..", "svl");

+            AIR_PRINT("%-5s", ".....");

+            AIR_PRINT("%-5d", mt[i].fid);

+        }

+        if(mt[i].flags & AIR_L2_MAC_ENTRY_FLAGS_STATIC)

+        {

+            AIR_PRINT("%-10s.", "static");

+        }

+        else

+        {

+            AIR_PRINT("%d sec..", mt[i].timer);

+        }

+        AIR_PRINT("%-10s", _air_mac_address_forward_control_string[mt[i].sa_fwd]);

+        first = 0;

+        find = 0;

+        for (j = (AIR_MAX_NUM_OF_PORTS - 1); j >= 0; j--)

+        {

+            if((mt[i].port_bitmap[0]) & (1 << j))

+            {

+                first = j;

+                find = 1;

+                break;

+            }

+        }

+        if(find)

+        {

+            for (j = 0; j < AIR_MAX_NUM_OF_PORTS; j++)

+            {

+                if((mt[i].port_bitmap[0]) & (1 << j))

+                {

+                    if(j == first)

+                        AIR_PRINT("%-2d", j);

+                    else

+                        AIR_PRINT("%-2d,", j);

+                }

+            }

+        }

+        else

+            AIR_PRINT("no dst port");

+        AIR_PRINT("\n");

+    }

+    return ret;

+}

+

+static AIR_ERROR_NO_T

+doGetMacAddr(

+        UI32_T argc,

+        C8_T *argv[])

+{

+    AIR_ERROR_NO_T ret = AIR_E_OK;

+    UI8_T count = 0;

+    AIR_MAC_ENTRY_T * ptr_mt;

+

+    if(3 == argc)

+    {

+        ptr_mt = AIR_MALLOC(sizeof(AIR_MAC_ENTRY_T));

+        if (NULL == ptr_mt)

+        {

+            AIR_PRINT("***Error***, allocate memory fail\n");

+            return AIR_E_OTHERS;

+        }

+        memset(ptr_mt, 0, sizeof(AIR_MAC_ENTRY_T));

+        /* l2 get mac <mac(12'hex)> { vid <vid(0..4095)> | fid <fid(0..15)> } */

+        ret = _str2mac(argv[0], (C8_T *)ptr_mt->mac);

+        if(ret != AIR_E_OK)

+        {

+            AIR_PRINT("Unrecognized command.\n");

+            AIR_FREE(ptr_mt);

+            return ret;

+        }

+

+        /* check argument 1 */

+        if(FALSE == _strcmp(argv[1], "vid"))

+        {

+            /* get mac entry by MAC address & vid */

+            ptr_mt->cvid = _strtoul(argv[2], NULL, 0);

+            ptr_mt->flags |= AIR_L2_MAC_ENTRY_FLAGS_IVL;

+            AIR_PRINT("Get MAC Address:" MAC_STR " with vid:%u", MAC2STR(ptr_mt->mac), ptr_mt->cvid);

+        }

+        else if(FALSE == _strcmp(argv[1], "fid"))

+        {

+            /* get mac entry by MAC address & fid */

+            ptr_mt->fid = _strtoul(argv[2], NULL, 0);

+            AIR_PRINT("Get MAC Address:" MAC_STR " with fid:%u", MAC2STR(ptr_mt->mac), ptr_mt->fid);

+        }

+        else

+        {

+            AIR_PRINT("Unrecognized command.\n");

+            AIR_FREE(ptr_mt);

+            return AIR_E_BAD_PARAMETER;

+        }

+        ret = air_l2_getMacAddr(0, &count, ptr_mt);

+        if(ret == AIR_E_OK)

+        {

+            AIR_PRINT(" Done.\n");

+            _printMacEntry(ptr_mt, 0, 1, TRUE);

+            _printMacEntry(ptr_mt, 0, 1, FALSE);

+        }

+        else

+            AIR_PRINT("\n Not found!\n");

+        AIR_FREE(ptr_mt);

+    }

+    else

+    {

+        AIR_PRINT("Unrecognized command.\n");

+        ret = AIR_E_BAD_PARAMETER;

+    }

+

+    return ret;

+}

+

+static AIR_ERROR_NO_T

+doMacAddrAgeOut(

+        UI32_T argc,

+        C8_T *argv[])

+{

+    AIR_ERROR_NO_T ret = AIR_E_OK;

+    UI32_T time = 0;

+    if(0 == argc)

+    {

+        /* l2 get macAddrAgeOut */

+        ret = air_l2_getMacAddrAgeOut(0, &time);

+        if(ret == AIR_E_OK)

+        {

+            AIR_PRINT("Get MAC Address Age Out Time Done.\n");

+        }

+        else

+        {

+            AIR_PRINT("Get MAC Address Age Out Time Fail.\n");

+        }

+    }

+    else if(1 == argc)

+    {

+        /* l2 set macAddrAgeOut <time(1, 1000000)> */

+        time = _strtoul(argv[0], NULL, 0);

+        if(time < 1 || time > 1000000)

+        {

+            AIR_PRINT("Unrecognized command.\n");

+            return AIR_E_BAD_PARAMETER;

+        }

+        ret = air_l2_setMacAddrAgeOut(0, time);

+        if(ret == AIR_E_OK)

+        {

+            AIR_PRINT("Set MAC Address Age Out Time Done.\n");

+        }

+        else

+        {

+            AIR_PRINT("Set MAC Address Age Out Time Fail.\n");

+        }

+    }

+    else

+    {

+        AIR_PRINT("Unrecognized command.\n");

+        ret = AIR_E_BAD_PARAMETER;

+    }

+

+    if(ret == AIR_E_OK)

+    {

+        AIR_PRINT("MAC Address Age Out Time: %u seconds.\n", time);

+    }

+

+    return ret;

+}

+

+static AIR_ERROR_NO_T

+doDumpMacAddr(

+        UI32_T argc,

+        C8_T *argv[])

+{

+    AIR_ERROR_NO_T ret = AIR_E_OK;

+    AIR_MAC_ENTRY_T *ptr_mt;

+    UI8_T count = 0;

+    UI32_T bucket_size = 0;

+    UI32_T total_count = 0;

+

+    if(0 != argc)

+    {

+        AIR_PRINT("Unrecognized command.\n");

+        return AIR_E_BAD_PARAMETER;

+    }

+    /* get unit of aging time */

+    ret = air_l2_getMacBucketSize(0, &bucket_size);

+    if(ret != AIR_E_OK)

+    {

+        AIR_PRINT("Get MAC Age Time Fail!\n");

+        return ret;

+    }

+    ptr_mt = AIR_MALLOC(sizeof(AIR_MAC_ENTRY_T) * bucket_size);

+    if (NULL == ptr_mt)

+    {

+        AIR_PRINT("***Error***, allocate memory fail\n");

+        return AIR_E_OTHERS;

+    }

+    memset(ptr_mt, 0, sizeof(AIR_MAC_ENTRY_T) * bucket_size);

+    _printMacEntry(ptr_mt, 0, count, TRUE);

+    /* get 1st entry of MAC table */

+    ret = air_l2_getMacAddr(0, &count, ptr_mt);

+    switch(ret)

+    {

+        case AIR_E_ENTRY_NOT_FOUND:

+            AIR_FREE(ptr_mt);

+            AIR_PRINT("Not Found!\n");

+            return ret;

+        case AIR_E_TIMEOUT:

+            AIR_FREE(ptr_mt);

+            AIR_PRINT("Time Out!\n");

+            return ret;

+        case AIR_E_BAD_PARAMETER:

+            AIR_FREE(ptr_mt);

+            AIR_PRINT("Bad Parameter!\n");

+            return ret;

+        default:

+            break;

+    }

+    total_count += count;

+    _printMacEntry(ptr_mt, 0, count, FALSE);

+

+    /* get other entries of MAC table */

+    while(1)

+    {

+        memset(ptr_mt, 0, sizeof(AIR_MAC_ENTRY_T) * bucket_size);

+        ret = air_l2_getNextMacAddr(0, &count, ptr_mt);

+        if(AIR_E_OK != ret)

+        {

+            break;

+        }

+        total_count += count;

+        _printMacEntry(ptr_mt, 0, count, FALSE);

+    }

+    switch(ret)

+    {

+        case AIR_E_TIMEOUT:

+            AIR_PRINT("Time Out!\n");

+            break;

+        case AIR_E_BAD_PARAMETER:

+            AIR_PRINT("Bad Parameter!\n");

+            break;

+        default:

+            AIR_PRINT("Found %u %s\n", total_count, (total_count>1)?"entries":"entry");

+            break;

+    }

+    AIR_FREE(ptr_mt);

+    return ret;

+}

+

+static AIR_ERROR_NO_T

+doLagMember(

+        UI32_T argc,

+        C8_T *argv[])

+{

+    AIR_ERROR_NO_T ret = AIR_E_OK;

+    UI32_T portrunk_index = 0, member_index = 0, member_enable = 0, port_index = 0, i = 0;

+    AIR_LAG_PTGINFO_T  member;

+    memset(&member,0,sizeof(AIR_LAG_PTGINFO_T));

+

+    if(4 == argc)

+    {

+        /* lag set member <port trunk index> <member index> <member enable> <port_index>*/

+        portrunk_index  = _strtol(argv[0], NULL, 10);

+        member_index    = _strtol(argv[1], NULL, 10);

+        member_enable   = _strtol(argv[2], NULL, 10);

+        port_index      = _strtol(argv[3], NULL, 10);

+        ret = air_lag_setMember(0, portrunk_index, member_index, member_enable,port_index);

+        if(ret == AIR_E_OK)

+        {

+            AIR_PRINT("Set port trunk index %d member_index:%d member_enable:%d, port_index:%d ok.\n", portrunk_index, member_index, member_enable,port_index);

+        }

+        else

+        {

+            AIR_PRINT("Set port trunk index %d member_index:%d member_enable:%d, port_index:%d fail.\n", portrunk_index, member_index, member_enable,port_index);

+        }

+        memset(&member,0,sizeof(member));

+        air_lag_getMember(0, portrunk_index, &member);

+        if(! member.csr_gp_enable[0])

+        {

+            AIR_PRINT("\r\n!!!!!!!!!Port trunk index %d member_index:0 must be set,or else have taffic issues.\n", portrunk_index);

+        }

+    }

+    else if(1 == argc)

+    {

+        portrunk_index = _strtol(argv[0], NULL, 10);

+

+        /* lag get member <port> */

+        memset(&member,0,sizeof(member));

+        ret = air_lag_getMember(0, portrunk_index, &member);

+        if(ret == AIR_E_OK)

+        {

+            AIR_PRINT("Get port trunk %u member:\n", portrunk_index);

+            for(i = 0; i < AIR_LAG_MAX_MEM_NUM; i++)

+            {

+                if(member.csr_gp_enable[i])

+                    AIR_PRINT("port %d \r\n", member.csr_gp_port[i]);

+            }

+            AIR_PRINT("\r\n");

+        }

+        else

+        {

+            AIR_PRINT("Get port trunk:%u Member Fail.\n", portrunk_index);

+        }

+    }

+    else

+    {

+        AIR_PRINT("Unrecognized command.\n");

+        ret = AIR_E_BAD_PARAMETER;

+    }

+

+    return ret;

+}

+

+

+static AIR_ERROR_NO_T

+doLagDstInfo(

+        UI32_T argc,

+        C8_T *argv[])

+{

+    AIR_ERROR_NO_T ret = AIR_E_OK;

+    AIR_LAG_DISTINFO_T dstInfo;

+

+    memset(&dstInfo, 0, sizeof(AIR_LAG_DISTINFO_T));

+    if(7 == argc)

+    {

+        /* lag set dstInfo <sp> <sa> <da> <sip> <dip> <sport> <dport> */

+        dstInfo.sp = _strtol(argv[0], NULL, 10) & BIT(0);

+        dstInfo.sa = _strtol(argv[1], NULL, 10) & BIT(0);

+        dstInfo.da = _strtol(argv[2], NULL, 10) & BIT(0);

+        dstInfo.sip = _strtol(argv[3], NULL, 10) & BIT(0);

+        dstInfo.dip = _strtol(argv[4], NULL, 10) & BIT(0);

+        dstInfo.sport = _strtol(argv[5], NULL, 10) & BIT(0);

+        dstInfo.dport = _strtol(argv[6], NULL, 10) & BIT(0);

+        ret = air_lag_setDstInfo(0, dstInfo);

+        if(ret == AIR_E_OK)

+        {

+            AIR_PRINT("Set LAG packet distrubution.\n");

+        }

+        else

+        {

+            AIR_PRINT("Set LAG packet distrubution Fail.\n");

+        }

+    }

+    else if(0 == argc)

+    {

+        /* lag get dstInfo */

+        ret = air_lag_getDstInfo(0, &dstInfo);

+        if(ret == AIR_E_OK)

+        {

+            AIR_PRINT("Get LAG packet distrubution:\n");

+        }

+        else

+        {

+            AIR_PRINT("Get LAG packet distrubution Fail.\n");

+        }

+    }

+    else

+    {

+        AIR_PRINT("Unrecognized command.\n");

+        ret = AIR_E_BAD_PARAMETER;

+    }

+    if(ret == AIR_E_OK)

+    {

+        AIR_PRINT("%-5s|%-5s|%-5s|%-5s|%-5s|%-5s|%-5s\n",

+                "SP", "SA", "DA", "SIP", "DIP", "SPORT", "DPORT");

+        AIR_PRINT("%-5s|%-5s|%-5s|%-5s|%-5s|%-5s|%-5s\n",

+                (dstInfo.sp)?"En":"Dis",

+                (dstInfo.sa)?"En":"Dis",

+                (dstInfo.da)?"En":"Dis",

+                (dstInfo.sip)?"En":"Dis",

+                (dstInfo.dip)?"En":"Dis",

+                (dstInfo.sport)?"En":"Dis",

+                (dstInfo.dport)?"En":"Dis");

+    }

+    return ret;

+}

+

+static AIR_ERROR_NO_T

+doLagHashtype(

+        UI32_T argc,

+        C8_T *argv[])

+{

+    AIR_ERROR_NO_T ret = AIR_E_OK;

+    UI32_T hashtype = 0;

+

+    if(1 == argc)

+    {

+        hashtype = _strtol(argv[0], NULL, 10);

+        ret = air_lag_sethashtype(0, hashtype);

+        if(ret == AIR_E_OK)

+        {

+            AIR_PRINT("Set LAG hashtype Ok.\n");

+        }

+        else

+        {

+            AIR_PRINT("Set LAG hashtype Fail.\n");

+        }

+    }

+    else if(0 == argc)

+    {

+        /* lag get dstInfo */

+        ret = air_lag_gethashtype(0, &hashtype);

+        if(ret == AIR_E_OK)

+        {

+            AIR_PRINT("Get LAG hashtype:\n");

+        }

+        else

+        {

+            AIR_PRINT("Get LLAG hashtype Fail.\n");

+        }

+    }

+    else

+    {

+        AIR_PRINT("Unrecognized command.\n");

+        ret = AIR_E_BAD_PARAMETER;

+    }

+    if(ret == AIR_E_OK)

+    {

+        switch (hashtype)

+        {

+            case 0:

+                AIR_PRINT("hashtype:crc32lsb.\n");

+                break;

+            case 1:

+                AIR_PRINT("hashtype:crc32msb.\n");

+                break;

+            case 2:

+                AIR_PRINT("hashtype:crc16.\n");

+                break;

+            case 3:

+                AIR_PRINT("hashtype:xor4.\n");

+                break;

+            default:

+                AIR_PRINT("wrong hashtype:%d.\n",hashtype);

+        }

+

+    }

+    return ret;

+}

+

+static AIR_ERROR_NO_T

+doLagPtseed(

+        UI32_T argc,

+        C8_T *argv[])

+{

+    AIR_ERROR_NO_T ret = AIR_E_OK;

+    UI32_T ptseed = 0;

+

+    if(1 == argc)

+    {

+        ptseed = _strtol(argv[0], NULL, 16);

+        ret = air_lag_setPTSeed(0, ptseed);

+        if(ret == AIR_E_OK)

+        {

+            AIR_PRINT("Set LAG Port Seed:%x(hex) ok\n",ptseed);

+        }

+        else

+        {

+            AIR_PRINT("Set LAG Port Seed:%x(hex) fail\n",ptseed);

+        }

+    }

+    else if(0 == argc)

+    {

+        /* lag get seed */

+        ret = air_lag_getPTSeed(0, &ptseed);

+        if(ret == AIR_E_OK)

+        {

+            AIR_PRINT("Get port trunk seed: %x(hex)\n",ptseed);

+        }

+        else

+        {

+            AIR_PRINT("Get port trunk seed Fail.\n");

+        }

+    }

+    else

+    {

+        AIR_PRINT("Unrecognized command.\n");

+        ret = AIR_E_BAD_PARAMETER;

+    }

+

+    return ret;

+}

+

+static AIR_ERROR_NO_T

+doLagSpsel(

+        UI32_T argc,

+        C8_T *argv[])

+{

+    AIR_ERROR_NO_T ret = AIR_E_OK;

+    UI32_T port = 0;

+    UI32_T state = 0;

+

+    if(1 == argc)

+    {

+        /* lag set spsel <state> */

+        state = _strtol(argv[0], NULL, 10);

+        ret = air_lag_setSpSel(0,state);

+        if(ret == AIR_E_OK)

+        {

+            AIR_PRINT("Set source port compare function:%s.\n", (state)?"Enabled":"Disabled");

+        }

+        else

+        {

+            AIR_PRINT("Set source port compare function Fail.\n");

+        }

+    }

+    else if(0 == argc)

+    {

+        /* lag get spsel*/

+        ret = air_lag_getSpSel(0, &state);

+        if(ret == AIR_E_OK)

+        {

+            AIR_PRINT("Get source port compare function:%s.\n", (state)?"Enabled":"Disabled");

+        }

+        else

+        {

+            AIR_PRINT("Get source port compare function Fail.\n");

+        }

+    }

+    else

+    {

+        AIR_PRINT("Unrecognized command.\n");

+        ret = AIR_E_BAD_PARAMETER;

+    }

+

+    return ret;

+}

+

+

+static AIR_ERROR_NO_T

+doLagState(

+        UI32_T argc,

+        C8_T *argv[])

+{

+    AIR_ERROR_NO_T ret = AIR_E_OK;

+    UI32_T port = 0;

+    UI32_T state = 0;

+

+    if(1 == argc)

+    {

+        /* lag set state <state> */

+        state = _strtol(argv[0], NULL, 10);

+        ret = air_lag_set_ptgc_state(0,state);

+        if(ret == AIR_E_OK)

+        {

+            AIR_PRINT("Set LAG Port Trunk State:%s.\n", (state)?"Enabled":"Disabled");

+        }

+        else

+        {

+            AIR_PRINT("Set LAG Port Trunk State Fail.\n");

+        }

+    }

+    else if(0 == argc)

+    {

+        /* lag get state*/

+        ret = air_lag_get_ptgc_state(0, &state);

+        if(ret == AIR_E_OK)

+        {

+            AIR_PRINT("Get LAG Port Trunk State:%s.\n", (state)?"Enabled":"Disabled");

+        }

+        else

+        {

+            AIR_PRINT("Get LAG Port Trunk State Fail.\n");

+        }

+    }

+    else

+    {

+        AIR_PRINT("Unrecognized command.\n");

+        ret = AIR_E_BAD_PARAMETER;

+    }

+

+    return ret;

+}

+

+static AIR_ERROR_NO_T

+doLagGet(

+        UI32_T argc,

+        C8_T *argv[])

+{

+    return subcmd(lagGetCmds, argc, argv);

+}

+

+static AIR_ERROR_NO_T

+doLagSet(

+        UI32_T argc,

+        C8_T *argv[])

+{

+    return subcmd(lagSetCmds, argc, argv);

+}

+

+static AIR_ERROR_NO_T

+doLag(

+        UI32_T argc,

+        C8_T *argv[])

+{

+    return subcmd(lagCmds, argc, argv);

+}

+

+static AIR_ERROR_NO_T

+doStpPortstate(

+        UI32_T argc,

+        C8_T *argv[])

+{

+    AIR_ERROR_NO_T ret = AIR_E_OK;

+    UI32_T port = 0;

+    UI32_T fid = 0;

+    UI32_T state = 0;

+

+    port = _strtol(argv[0], NULL, 10);

+    fid = _strtol(argv[1], NULL, 10);

+    if(3 == argc)

+    {

+        /* stp set portstate <port> <fid(0..15)> <state> */

+        state = _strtol(argv[2], NULL, 10);

+        ret = air_stp_setPortstate(0, port, fid, state);

+        if(ret == AIR_E_OK)

+        {

+            AIR_PRINT("Set STP Port:%u FID:%u State:", port, fid);

+            switch(state)

+            {

+                case AIR_STP_STATE_DISABLE:

+                    AIR_PRINT("Disable(STP) / Discard(RSTP).\n");

+                    break;

+                case AIR_STP_STATE_LISTEN:

+                    AIR_PRINT("Listening(STP) / Discard(RSTP).\n");

+                    break;

+                case AIR_STP_STATE_LEARN:

+                    AIR_PRINT("Learning(STP) / Learning(RSTP).\n");

+                    break;

+                case AIR_STP_STATE_FORWARD:

+                    AIR_PRINT("Forwarding(STP) / Forwarding(RSTP).\n");

+                    break;

+                default:

+                    break;

+            }

+        }

+        else

+        {

+            AIR_PRINT("Set STP Port:%u FID:%u State Fail.", port, fid);

+        }

+    }

+    else if(2 == argc)

+    {

+        /* stp get portstate <port> <fid(0..15)> */

+        ret = air_stp_getPortstate(0, port, fid, &state);

+        if(ret == AIR_E_OK)

+        {

+            AIR_PRINT("Get STP Port:%u FID:%u State:", port, fid);

+            switch(state)

+            {

+                case AIR_STP_STATE_DISABLE:

+                    AIR_PRINT("Disable(STP) / Discard(RSTP).\n");

+                    break;

+                case AIR_STP_STATE_LISTEN:

+                    AIR_PRINT("Listening(STP) / Discard(RSTP).\n");

+                    break;

+                case AIR_STP_STATE_LEARN:

+                    AIR_PRINT("Learning(STP) / Learning(RSTP).\n");

+                    break;

+                case AIR_STP_STATE_FORWARD:

+                    AIR_PRINT("Forwarding(STP) / Forwarding(RSTP).\n");

+                    break;

+                default:

+                    break;

+            }

+        }

+        else

+        {

+            AIR_PRINT("Get STP Port:%u FID:%u State Fail.", port, fid);

+        }

+    }

+    else

+    {

+        AIR_PRINT("Unrecognized command.\n");

+        ret = AIR_E_BAD_PARAMETER;

+    }

+

+    return ret;

+}

+

+static AIR_ERROR_NO_T

+doStpGet(

+        UI32_T argc,

+        C8_T *argv[])

+{

+    return subcmd(stpGetCmds, argc, argv);

+}

+

+static AIR_ERROR_NO_T

+doStpSet(

+        UI32_T argc,

+        C8_T *argv[])

+{

+    return subcmd(stpSetCmds, argc, argv);

+}

+

+static AIR_ERROR_NO_T

+doStp(

+        UI32_T argc,

+        C8_T *argv[])

+{

+    return subcmd(stpCmds, argc, argv);

+}

+

+static void

+_mir_printPortList(UI32_T * mt)

+{

+    I8_T j = 0;

+    UI8_T first = 0;

+    UI8_T find = 0;

+    for(j = (AIR_MAX_NUM_OF_PORTS - 1); j >= 0; j--)

+    {

+        if((*mt) & (1 << j))

+        {

+            first = j;

+            find = 1;

+            break;

+        }

+    }

+    if(find)

+    {

+        for(j = 0; j < AIR_MAX_NUM_OF_PORTS; j++)

+        {

+            if((*mt) & (1 << j))

+            {

+                if(j == first)

+                    AIR_PRINT("%-2d", j);

+                else

+                    AIR_PRINT("%-2d,", j);

+            }

+        }

+    }

+    else

+        AIR_PRINT("NULL");

+    AIR_PRINT("\n");

+}

+

+static void

+_mir_printSrcPortList(

+    const UI32_T         unit,

+    const UI32_T         sessionid)

+{

+

+    I8_T i = 0;

+    AIR_MIR_SESSION_T   session;

+    AIR_PORT_BITMAP_T txPbm = {0}, rxPbm = {0};

+

+    for(i = 0; i < AIR_MAX_NUM_OF_PORTS; i++)

+    {

+         memset(&session, 0, sizeof(session));

+         session.src_port = i;

+         air_mir_getMirrorPort(unit, sessionid, &session);

+

+         if(session.flags & AIR_MIR_SESSION_FLAGS_DIR_TX)

+         {

+            txPbm[0] |= (1 << i);

+         }

+         if(session.flags & AIR_MIR_SESSION_FLAGS_DIR_RX)

+         {

+            rxPbm[0] |= (1 << i);

+         }

+    }

+    AIR_PRINT("Src PortList\n");

+    AIR_PRINT(" - Rx portlist = ");

+    _mir_printPortList(rxPbm);

+    AIR_PRINT(" - Tx portlist = ");

+    _mir_printPortList(txPbm);

+}

+

+static void

+_mir_printSession(

+    const UI32_T            unit,

+    const UI32_T            session_id,

+    const AIR_MIR_SESSION_T *ptr_session)

+{

+

+    AIR_PRINT("Session id: %d\n", session_id);

+    AIR_PRINT("State: %s \n", (ptr_session->flags & AIR_MIR_SESSION_FLAGS_ENABLE)? "enable": "disable");

+    AIR_PRINT("Tx tag: %s \n", (ptr_session->flags & AIR_MIR_SESSION_FLAGS_TX_TAG_OBEY_CFG)? "On": "Off");

+    AIR_PRINT("Dst port: %d \n", ptr_session->dst_port);

+    _mir_printSrcPortList(unit,session_id);

+}

+

+static AIR_ERROR_NO_T

+doMirrorGetSid(

+        UI32_T argc,

+        C8_T *argv[])

+{

+    AIR_ERROR_NO_T      rc = AIR_E_OK;

+    UI32_T              session_id = 0;

+    AIR_MIR_SESSION_T   session = {0};

+    I8_T i = 0;

+

+    session_id = _strtoul(argv[0], NULL, 0);

+    rc = air_mir_getSession(0, session_id, &session);

+    if (AIR_E_OK != rc)

+    {

+        AIR_PRINT("***Error***, get mirror session fail\n");

+        return rc;

+    }

+    /* print session information */

+    if(session.dst_port == AIR_PORT_INVALID)

+    {

+        AIR_PRINT("Session id %d not found\n", session_id);

+    }

+    else

+    {

+        _mir_printSession(0, session_id, &session);

+    }

+    return rc;

+}

+

+static AIR_ERROR_NO_T

+doMirrorDelSid(

+        UI32_T argc,

+        C8_T *argv[])

+{

+    AIR_ERROR_NO_T      rc = AIR_E_OK;

+    UI32_T              session_id = 0;

+    AIR_MIR_SESSION_T   session = {0};

+    UI8_T i = 0;

+

+    session_id = _strtoul(argv[0], NULL, 0);

+    rc = air_mir_delSession(0, session_id);

+    if (AIR_E_OK != rc)

+    {

+        AIR_PRINT("***Error***, del mirror session fail\n");

+        return rc;

+    }

+    for(i = 0; i < AIR_MAX_NUM_OF_PORTS; i++)

+    {

+        session.src_port = i;

+        rc = air_mir_setMirrorPort(0, session_id, &session);

+        if (AIR_E_OK != rc)

+        {

+            AIR_PRINT("***Error***,port=%u error\n", i);

+            return rc;

+        }

+    }

+    if (rc != AIR_E_OK)

+    {

+        AIR_PRINT("***Error***, delete mirror session fail\n");

+    }

+    else

+        AIR_PRINT("***OK***, delete mirror session success\n");

+

+    return rc;

+}

+

+static AIR_ERROR_NO_T

+doMirrorAddRlist(

+        UI32_T argc,

+        C8_T *argv[])

+{

+    AIR_ERROR_NO_T      rc = AIR_E_OK;

+    UI32_T              session_id = 0;

+    AIR_MIR_SESSION_T   session = {0};

+    AIR_PORT_BITMAP_T rxPbm = {0};

+    UI8_T i = 0;

+

+    /*mirror add session-rlist <sid(0..3)> <list(UINTLIST)>*/

+    session_id = _strtoul(argv[0], NULL, 0);

+    rc = _portListStr2Ary(argv[1], rxPbm, 1);

+    if(rc != AIR_E_OK)

+    {

+        AIR_PRINT("Unrecognized command.\n");

+        return rc;

+    }

+    if(!rxPbm[0])

+    {

+        for(i = 0; i < AIR_MAX_NUM_OF_PORTS; i++)

+        {

+            memset(&session, 0, sizeof(AIR_MIR_SESSION_T));

+            session.src_port = i;

+            rc = air_mir_getMirrorPort(0, session_id, &session);

+            if (AIR_E_OK != rc)

+            {

+                AIR_PRINT("***Error***,get port=%u error\n", i);

+                return rc;

+            }

+

+            session.flags &= ~AIR_MIR_SESSION_FLAGS_DIR_RX;

+            session.src_port = i;

+            rc = air_mir_setMirrorPort(0, session_id, &session);

+            if (AIR_E_OK != rc)

+            {

+                AIR_PRINT("***Error***,set rx port=%u error\n", i);

+                return rc;

+            }

+        }

+    }

+    else

+    {

+        for(i = 0; i < AIR_MAX_NUM_OF_PORTS; i++)

+        {

+            if(rxPbm[0] & (1 << i))

+            {

+                memset(&session, 0, sizeof(AIR_MIR_SESSION_T));

+                session.src_port = i;

+                rc = air_mir_getMirrorPort(0, session_id, &session);

+                if (AIR_E_OK != rc)

+                {

+                    AIR_PRINT("***Error***,get port=%u error\n", i);

+                    return rc;

+                }

+

+                session.flags |= AIR_MIR_SESSION_FLAGS_DIR_RX;

+                session.src_port = i;

+                rc = air_mir_setMirrorPort(0, session_id, &session);

+                if (AIR_E_OK != rc)

+                {

+                    AIR_PRINT("***Error***,port=%u error\n", i);

+                    return rc;

+                }

+            }

+        }

+    }

+

+    return rc;

+}

+

+static AIR_ERROR_NO_T

+doMirrorAddTlist(

+        UI32_T argc,

+        C8_T *argv[])

+{

+    AIR_ERROR_NO_T      rc = AIR_E_OK;

+    UI32_T              session_id = 0;

+    AIR_MIR_SESSION_T   session = {0};

+    AIR_PORT_BITMAP_T txPbm = {0};

+    UI8_T i = 0;

+

+    /*mirror add session-tlist <sid(0..3)> <list(UINTLIST)>*/

+    session_id = _strtoul(argv[0], NULL, 0);

+    rc = _portListStr2Ary(argv[1], txPbm, 1);

+    if(rc != AIR_E_OK)

+    {

+        AIR_PRINT("Unrecognized command.\n");

+        return rc;

+    }

+    if(!txPbm[0])

+    {

+        for(i = 0; i < AIR_MAX_NUM_OF_PORTS; i++)

+        {

+            memset(&session, 0, sizeof(AIR_MIR_SESSION_T));

+            session.src_port = i;

+            rc = air_mir_getMirrorPort(0, session_id, &session);

+            if (AIR_E_OK != rc)

+            {

+                AIR_PRINT("***Error***,get port=%u error\n", i);

+                return rc;

+            }

+

+            session.flags &= ~AIR_MIR_SESSION_FLAGS_DIR_TX;

+            session.src_port = i;

+            rc = air_mir_setMirrorPort(0, session_id, &session);

+            if (AIR_E_OK != rc)

+            {

+                AIR_PRINT("***Error***,set rx port=%u error\n", i);

+                return rc;

+            }

+        }

+    }

+    else

+    {

+        for(i = 0; i < AIR_MAX_NUM_OF_PORTS; i++)

+        {

+            if(txPbm[0] & (1 << i))

+            {

+                memset(&session, 0, sizeof(AIR_MIR_SESSION_T));

+                session.src_port = i;

+                rc = air_mir_getMirrorPort(0, session_id, &session);

+                if (AIR_E_OK != rc)

+                {

+                    AIR_PRINT("***Error***,get port=%u error\n", i);

+                    return rc;

+                }

+

+                session.flags |= AIR_MIR_SESSION_FLAGS_DIR_TX;

+                session.src_port = i;

+                rc = air_mir_setMirrorPort(0, session_id, &session);

+                if (AIR_E_OK != rc)

+                {

+                    AIR_PRINT("***Error***,port=%u error\n", i);

+                    return rc;

+                }

+            }

+        }

+    }

+

+    return rc;

+}

+

+static AIR_ERROR_NO_T

+doMirrorSetSessionEnable(

+    UI32_T argc,

+    C8_T *argv[])

+

+{

+    AIR_ERROR_NO_T      rc = AIR_E_OK;

+    UI32_T              session_id = 0;

+    UI32_T              enable = 0;

+    BOOL_T              tmp_en = FALSE;

+

+    /*mirror set session-enable <sid(0..3)> <state(1:En,0:Dis)>*/

+    session_id = _strtoul(argv[0], NULL, 0);

+    enable = _strtoul(argv[1], NULL, 0);

+    if(enable)

+        tmp_en = TRUE;

+    /* set port mirror state */

+    rc = air_mir_setSessionAdminMode(0, session_id, tmp_en);

+    if(AIR_E_OK!=rc)

+    {

+        AIR_PRINT("***Error***\n");

+    }

+    return rc;

+}

+

+static AIR_ERROR_NO_T

+doMirrorSetSession(

+    UI32_T argc,

+    C8_T *argv[])

+{

+    AIR_ERROR_NO_T      rc = AIR_E_OK;

+    UI32_T              session_id = 0;

+    UI32_T              dst_port = 0;

+    UI8_T               enable = 0;

+    UI8_T               tag_en = 0;

+    UI8_T               dir = 0;

+    AIR_MIR_SESSION_T  session = {0};

+    AIR_PORT_BITMAP_T   rxPbm = {0};

+    I8_T               i = 0;

+

+    /*mirror set session <sid(0..3)> <dst_port(UINT)> <state(1:En,0:Dis)> <tag(1:on, 0:off)> <list(UINTLIST)> <dir(0:none,1:tx,2:rx,3:both)>*/

+    session_id = _strtoul(argv[0], NULL, 0);

+    dst_port = _strtoul(argv[1], NULL, 0);

+    AIR_PRINT("session id %d dst port %d.\n", session_id, dst_port);

+    session.dst_port = dst_port;

+    enable = _strtoul(argv[2], NULL, 0);

+    if(enable)

+    {

+        session.flags |= AIR_MIR_SESSION_FLAGS_ENABLE;

+    }

+    else

+    {

+        session.flags &= ~AIR_MIR_SESSION_FLAGS_ENABLE;

+    }

+    tag_en = _strtoul(argv[3], NULL, 0);

+    if(tag_en)

+    {

+        session.flags |= AIR_MIR_SESSION_FLAGS_TX_TAG_OBEY_CFG;

+    }

+    else

+    {

+        session.flags &= ~AIR_MIR_SESSION_FLAGS_TX_TAG_OBEY_CFG;

+    }

+    rc = _portListStr2Ary(argv[4], rxPbm, 1);

+    if(rc != AIR_E_OK)

+    {

+        AIR_PRINT("Unrecognized command.\n");

+        return rc;

+    }

+    AIR_PRINT("pbm %x.\n", rxPbm);

+    dir = _strtoul(argv[5], NULL, 0);

+    if(dir == 1)

+    {

+        session.flags |= AIR_MIR_SESSION_FLAGS_DIR_TX;

+    }

+    else if(dir == 2)

+    {

+        session.flags |= AIR_MIR_SESSION_FLAGS_DIR_RX;

+    }

+    else if(dir == 3)

+    {

+        session.flags |= AIR_MIR_SESSION_FLAGS_DIR_TX;

+        session.flags |= AIR_MIR_SESSION_FLAGS_DIR_RX;

+    }

+    else if (!dir)

+    {

+        session.flags &= ~AIR_MIR_SESSION_FLAGS_DIR_TX;

+        session.flags &= ~AIR_MIR_SESSION_FLAGS_DIR_RX;

+    }

+    else

+    {

+        return AIR_E_BAD_PARAMETER;

+    }

+    for(i = 0; i < AIR_MAX_NUM_OF_PORTS; i++)

+    {

+        if(rxPbm[0] & (1 << i))

+        {

+            session.src_port = i;

+            /* set port mirror session */

+            rc = air_mir_addSession(0, session_id, &session);

+

+            if(AIR_E_OK!=rc)

+            {

+                AIR_PRINT("***Error***,dst-port=%u, src-port=%u error\n", session.dst_port, session.src_port);

+                return rc;

+            }

+            else

+                AIR_PRINT("add session %d,dst-port=%u, src-port=%u\n", session_id, session.dst_port, session.src_port);

+        }

+    }

+

+    return rc;

+}

+

+

+

+static AIR_ERROR_NO_T

+doMirrorSet(

+        UI32_T argc,

+        C8_T *argv[])

+{

+    return subcmd(mirrorSetCmds, argc, argv);

+}

+

+static AIR_ERROR_NO_T

+doMirrorAdd(

+        UI32_T argc,

+        C8_T *argv[])

+{

+    return subcmd(mirrorAddCmds, argc, argv);

+}

+

+static AIR_ERROR_NO_T

+doMirrorGet(

+        UI32_T argc,

+        C8_T *argv[])

+{

+    return subcmd(mirrorGetCmds, argc, argv);

+}

+

+static AIR_ERROR_NO_T

+doMirrorDel(

+        UI32_T argc,

+        C8_T *argv[])

+{

+    return subcmd(mirrorDelCmds, argc, argv);

+}

+

+static AIR_ERROR_NO_T

+doMirror(

+        UI32_T argc,

+        C8_T *argv[])

+{

+    return subcmd(mirrorCmds, argc, argv);

+}

+

+static AIR_ERROR_NO_T

+doMibClearPort(

+        UI32_T argc,

+        C8_T *argv[])

+{

+    AIR_ERROR_NO_T ret = AIR_E_OK;

+    UI32_T port = 0;

+

+    if(1 == argc)

+    {

+        /* mib clear port */

+        port = _strtoul(argv[0], NULL, 0);

+        ret = air_mib_clear_by_port(0,port);

+        AIR_PRINT("Clear port %d mib stats",port);

+        if(AIR_E_OK == ret)

+        {

+            AIR_PRINT("Done.\n");

+        }

+        else

+        {

+            AIR_PRINT("Fail.\n");

+        }

+    }

+    else if(0 == argc)

+    {

+        /*restart mib counter*/

+        air_mib_clear(0);

+        AIR_PRINT("Clear all mib stats",port);

+    }

+    else

+    {

+        AIR_PRINT("Unrecognized command.\n");

+        ret = AIR_E_BAD_PARAMETER;

+    }

+

+    return ret;

+}

+

+static AIR_ERROR_NO_T

+doMibClearAcl(

+        UI32_T argc,

+        C8_T *argv[])

+{

+    AIR_ERROR_NO_T ret = AIR_E_OK;

+    UI32_T port = 0;

+

+    if(0 == argc)

+    {

+        /* mib clear acl */

+        ret = air_mib_clearAclEvent(0);

+        AIR_PRINT("Clear ACL Event Counter ");

+        if(AIR_E_OK == ret)

+        {

+            AIR_PRINT("Done.\n");

+        }

+        else

+        {

+            AIR_PRINT("Fail.\n");

+        }

+    }

+    else

+    {

+        AIR_PRINT("Unrecognized command.\n");

+        ret = AIR_E_BAD_PARAMETER;

+    }

+

+    return ret;

+}

+

+static AIR_ERROR_NO_T

+doMibGetPort(

+        UI32_T argc,

+        C8_T *argv[])

+{

+    AIR_ERROR_NO_T ret = AIR_E_OK;

+    UI32_T port = 0;

+    UI32_T tmp32 = 0xffffffff;

+    AIR_MIB_CNT_RX_T rx_mib = {0};

+    AIR_MIB_CNT_TX_T tx_mib = {0};

+

+    port = _strtoul(argv[0], NULL, 0);

+    if(1 == argc)

+    {

+        /* mib get <port(0..6)> */

+        ret = air_mib_get(0, port, &rx_mib, &tx_mib);

+        AIR_PRINT("Get MIB Counter of Port %u ", port);

+        if(AIR_E_OK == ret)

+        {

+            AIR_PRINT("Done.\n");

+            AIR_PRINT("RX Drop Packet                    : %u\n", rx_mib.RDPC);

+            AIR_PRINT("RX filtering Packet               : %u\n", rx_mib.RFPC);

+            AIR_PRINT("RX Unicast Packet                 : %u\n", rx_mib.RUPC);

+            AIR_PRINT("RX Multicast Packet               : %u\n", rx_mib.RMPC);

+            AIR_PRINT("RX Broadcast Packet               : %u\n", rx_mib.RBPC);

+            AIR_PRINT("RX Alignment Error Packet         : %u\n", rx_mib.RAEPC);

+            AIR_PRINT("RX CRC Packet                     : %u\n", rx_mib.RCEPC);

+            AIR_PRINT("RX Undersize Packet               : %u\n", rx_mib.RUSPC);

+            AIR_PRINT("RX Fragment Error Packet          : %u\n", rx_mib.RFEPC);

+            AIR_PRINT("RX Oversize Packet                : %u\n", rx_mib.ROSPC);

+            AIR_PRINT("RX Jabber Error Packet            : %u\n", rx_mib.RJEPC);

+            AIR_PRINT("RX Pause Packet                   : %u\n", rx_mib.RPPC);

+            AIR_PRINT("RX Packet Length 64 bytes         : %u\n", rx_mib.RL64PC);

+            AIR_PRINT("RX Packet Length 65 ~ 127 bytes   : %u\n", rx_mib.RL65PC);

+            AIR_PRINT("RX Packet Length 128 ~ 255 bytes  : %u\n", rx_mib.RL128PC);

+            AIR_PRINT("RX Packet Length 256 ~ 511 bytes  : %u\n", rx_mib.RL256PC);

+            AIR_PRINT("RX Packet Length 512 ~ 1023 bytes : %u\n", rx_mib.RL512PC);

+            AIR_PRINT("RX Packet Length 1024 ~ 1518 bytes: %u\n", rx_mib.RL1024PC);

+            AIR_PRINT("RX Packet Length 1519 ~ max bytes : %u\n", rx_mib.RL1519PC);

+            AIR_PRINT("RX_CTRL Drop Packet               : %u\n", rx_mib.RCDPC);

+            AIR_PRINT("RX Ingress Drop Packet            : %u\n", rx_mib.RIDPC);

+            AIR_PRINT("RX ARL Drop Packet                : %u\n", rx_mib.RADPC);

+            AIR_PRINT("FLow Control Drop Packet          : %u\n", rx_mib.FCDPC);

+            AIR_PRINT("WRED Drop Packtet                 : %u\n", rx_mib.WRDPC);

+            AIR_PRINT("Mirror Drop Packet                : %u\n", rx_mib.MRDPC);

+            AIR_PRINT("RX  sFlow Sampling Packet         : %u\n", rx_mib.SFSPC);

+            AIR_PRINT("Rx sFlow Total Packet             : %u\n", rx_mib.SFTPC);

+            AIR_PRINT("Port Control Drop Packet          : %u\n", rx_mib.RXC_DPC);

+            AIR_PRINT("RX Octets good or bad packtes l32 : %u\n", (UI32_T)(rx_mib.ROC & tmp32));

+            AIR_PRINT("RX Octets good or bad packtes h32 : %u\n", (UI32_T)((rx_mib.ROC >> 32) & tmp32));

+            AIR_PRINT("RX Octets bad packets l32         : %u\n", (UI32_T)(rx_mib.ROC2 & tmp32));

+            AIR_PRINT("RX Octets bad packets h32         : %u\n", (UI32_T)((rx_mib.ROC2 >> 32) & tmp32));

+            AIR_PRINT("\n");

+            AIR_PRINT("TX Drop Packet                    : %u\n", tx_mib.TDPC);

+            AIR_PRINT("TX CRC Packet                     : %u\n", tx_mib.TCRC);

+            AIR_PRINT("TX Unicast Packet                 : %u\n", tx_mib.TUPC);

+            AIR_PRINT("TX Multicast Packet               : %u\n", tx_mib.TMPC);

+            AIR_PRINT("TX Broadcast Packet               : %u\n", tx_mib.TBPC);

+            AIR_PRINT("TX Collision Event Count          : %u\n", tx_mib.TCEC);

+            AIR_PRINT("TX Single Collision Event Count   : %u\n", tx_mib.TSCEC);

+            AIR_PRINT("TX Multiple Conllision Event Count: %u\n", tx_mib.TMCEC);

+            AIR_PRINT("TX Deferred Event Count           : %u\n", tx_mib.TDEC);

+            AIR_PRINT("TX Late Collision Event Count     : %u\n", tx_mib.TLCEC);

+            AIR_PRINT("TX Excessive Collision Event Count: %u\n", tx_mib.TXCEC);

+            AIR_PRINT("TX Pause Packet                   : %u\n", tx_mib.TPPC);

+            AIR_PRINT("TX Packet Length 64 bytes         : %u\n", tx_mib.TL64PC);

+            AIR_PRINT("TX Packet Length 65 ~ 127 bytes   : %u\n", tx_mib.TL65PC);

+            AIR_PRINT("TX Packet Length 128 ~ 255 bytes  : %u\n", tx_mib.TL128PC);

+            AIR_PRINT("TX Packet Length 256 ~ 511 bytes  : %u\n", tx_mib.TL256PC);

+            AIR_PRINT("TX Packet Length 512 ~ 1023 bytes : %u\n", tx_mib.TL512PC);

+            AIR_PRINT("TX Packet Length 1024 ~ 1518 bytes: %u\n", tx_mib.TL1024PC);

+            AIR_PRINT("TX Packet Length 1519 ~ max bytes : %u\n", tx_mib.TL1519PC);

+            AIR_PRINT("TX Oversize Drop Packet           : %u\n", tx_mib.TODPC);

+            AIR_PRINT("TX Octets good or bad packtes l32 : %u\n", (UI32_T)(tx_mib.TOC & tmp32));

+            AIR_PRINT("TX Octets good or bad packtes h32 : %u\n", (UI32_T)((tx_mib.TOC >> 32) & tmp32));

+            AIR_PRINT("TX Octets bad packets l32         : %u\n", (UI32_T)(tx_mib.TOC2 & tmp32));

+            AIR_PRINT("TX Octets bad packets h32         : %u\n", (UI32_T)((tx_mib.TOC2 >> 32) & tmp32));

+        }

+        else

+        {

+            AIR_PRINT("Fail.\n");

+        }

+    }

+    else

+    {

+        AIR_PRINT("Unrecognized command.\n");

+        ret = AIR_E_BAD_PARAMETER;

+    }

+

+    return ret;

+}

+

+static AIR_ERROR_NO_T

+doMibGetAcl(

+    UI32_T argc,

+    C8_T *argv[])

+{

+    AIR_ERROR_NO_T ret = AIR_E_OK;

+    UI32_T event = 0;

+    UI32_T cnt = 0;

+

+    if(1 == argc)

+    {

+        /* mib get acl <event(0..7)> */

+        event = _strtoul(argv[0], NULL, 0);

+        ret = air_mib_getAclEvent(0, event, &cnt);

+        AIR_PRINT("Get counter of ACL event %u ", event);

+        if(AIR_E_OK == ret)

+        {

+            AIR_PRINT("Done.\n");

+            AIR_PRINT("ACL Event Counter:%u\n", cnt);

+        }

+        else

+        {

+            AIR_PRINT("Fail.\n");

+        }

+    }

+    else

+    {

+        AIR_PRINT("Unrecognized command.\n");

+        ret = AIR_E_BAD_PARAMETER;

+    }

+

+    return ret;

+}

+

+static AIR_ERROR_NO_T

+doMibClear(

+        UI32_T argc,

+        C8_T *argv[])

+{

+    return subcmd(mibClearCmds, argc, argv);

+}

+

+static AIR_ERROR_NO_T

+doMibGet(

+        UI32_T argc,

+        C8_T *argv[])

+{

+    return subcmd(mibGetCmds, argc, argv);

+}

+

+static AIR_ERROR_NO_T

+doMib(

+        UI32_T argc,

+        C8_T *argv[])

+{

+    return subcmd(mibCmds, argc, argv);

+}

+

+static AIR_ERROR_NO_T

+doQosRateLimitExMngFrm(

+    UI32_T argc,

+    C8_T *argv[])

+{

+    AIR_ERROR_NO_T ret = AIR_E_OK;

+    UI32_T dir = 0;

+    BOOL_T enable = FALSE;

+

+    dir = _strtoul(argv[0], NULL, 0);

+    if(2 == argc)

+    {

+        if(dir == 0)

+            dir = AIR_QOS_RATE_DIR_EGRESS;

+        else if(dir == 1)

+            dir = AIR_QOS_RATE_DIR_INGRESS;

+        else

+        {

+            AIR_PRINT("Unrecognized command.\n");

+            ret = AIR_E_BAD_PARAMETER;

+            return ret;

+        }

+        enable = _strtoul(argv[1], NULL, 0);

+        ret = air_qos_setRateLimitExMngFrm(0, dir, enable);

+        if(ret == AIR_E_OK)

+        {

+            AIR_PRINT("Success.\n");

+            AIR_PRINT("Set %s Rate Limit Control %s management frame.\n",

+                    (AIR_QOS_RATE_DIR_INGRESS == dir)?"Ingress":"Egress",

+                    (TRUE == enable)?"exclude":"include");

+        }

+        else

+        {

+            AIR_PRINT("Fail.\n");

+            return ret;

+        }

+    }

+    else if(0 == argc)

+    {

+        dir = AIR_QOS_RATE_DIR_EGRESS;

+        ret = air_qos_getRateLimitExMngFrm(0, dir, &enable);

+        if(ret == AIR_E_OK)

+        {

+            AIR_PRINT("Success.\n");

+            AIR_PRINT("Get %s Rate Limit Control %s management frame.\n",

+                    (AIR_QOS_RATE_DIR_INGRESS == dir)?"Ingress":"Egress",

+                    (TRUE == enable)?"exclude":"include");

+        }

+        else

+        {

+            AIR_PRINT("Fail.\n");

+            return ret;

+        }

+        dir = AIR_QOS_RATE_DIR_INGRESS;

+        ret = air_qos_getRateLimitExMngFrm(0, dir, &enable);

+        if(ret == AIR_E_OK)

+        {

+            AIR_PRINT("Success.\n");

+            AIR_PRINT("Get %s Rate Limit Control %s management frame.\n",

+                    (AIR_QOS_RATE_DIR_INGRESS == dir)?"Ingress":"Egress",

+                    (TRUE == enable)?"exclude":"include");

+        }

+        else

+        {

+            AIR_PRINT("Fail.\n");

+            return ret;

+        }

+    }

+    else

+    {

+        AIR_PRINT("Unrecognized command.\n");

+        ret = AIR_E_BAD_PARAMETER;

+    }

+

+    return ret;

+

+}

+

+static AIR_ERROR_NO_T

+doQosPortPriority(

+    UI32_T argc,

+    C8_T *argv[])

+{

+    AIR_ERROR_NO_T ret = AIR_E_OK;

+    AIR_PORT_BITMAP_T portlist = {0};

+    UI32_T priority = 0;

+    UI8_T i = 0;

+

+    ret = _portListStr2Ary(argv[0], portlist, 1);

+    if(ret != AIR_E_OK)

+    {

+        AIR_PRINT("Unrecognized command.\n");

+        return ret;

+    }

+    if(2 == argc)

+    {

+        priority = _strtoul(argv[1], NULL, 0);

+        for(i = 0; i < AIR_MAX_NUM_OF_PORTS; i++)

+        {

+            if(portlist[0] & (1 << i))

+            {

+                ret = air_qos_setPortPriority(0, i, priority);

+                if(ret == AIR_E_OK)

+                {

+                    AIR_PRINT("Set Port%02d port based priority %d Success.\n", i, priority);

+                }

+                else

+                {

+                    AIR_PRINT("Set Port%02d port based priority %d Fail.\n", i, priority);

+                }

+            }

+        }

+    }

+    else if(1 == argc)

+    {

+        for(i = 0; i < AIR_MAX_NUM_OF_PORTS; i++)

+        {

+            if(portlist[0] & (1 << i))

+            {

+                ret = air_qos_getPortPriority(0, i, &priority);

+                if(ret == AIR_E_OK)

+                {

+                    AIR_PRINT("Get Port%d port based priority %d.\n", i, priority);

+                }

+                else

+                {

+                    AIR_PRINT("Get Port%d port based priority Fail.\n", i);

+                }

+            }

+        }

+    }

+    else

+    {

+        AIR_PRINT("Unrecognized command.\n");

+        ret = AIR_E_BAD_PARAMETER;

+    }

+

+    return ret;

+}

+

+static AIR_ERROR_NO_T

+doQosRateLimit(

+    UI32_T argc,

+    C8_T *argv[])

+{

+    AIR_ERROR_NO_T ret = AIR_E_OK;

+    AIR_PORT_BITMAP_T portlist = {0};

+    AIR_QOS_RATE_LIMIT_CFG_T rl = {0};

+    UI8_T i = 0;

+

+    ret = _portListStr2Ary(argv[0], portlist, 1);

+    if(ret != AIR_E_OK)

+    {

+        AIR_PRINT("Unrecognized command.\n");

+        return ret;

+    }

+    if(5 == argc)

+    {

+        rl.ingress_cir = _strtoul(argv[1], NULL, 0);

+        rl.ingress_cbs = _strtoul(argv[2], NULL, 0);

+        rl.egress_cir = _strtoul(argv[3], NULL, 0);

+        rl.egress_cbs = _strtoul(argv[4], NULL, 0);

+        rl.flags |= AIR_QOS_RATE_LIMIT_CFG_FLAGS_ENABLE_INGRESS;

+        rl.flags |= AIR_QOS_RATE_LIMIT_CFG_FLAGS_ENABLE_EGRESS;

+        for(i = 0; i < AIR_MAX_NUM_OF_PORTS; i++)

+        {

+            if(portlist[0] & (1 << i))

+            {

+                ret = air_qos_setRateLimit(0, i, &rl);

+                if(ret == AIR_E_OK)

+                {

+                    AIR_PRINT("Set Port%02d Ingress CIR %d CBS %d Egress CIR %d CBS %d Success.\n", i, rl.ingress_cir, rl.ingress_cbs, rl.egress_cir, rl.egress_cbs);

+                }

+                else

+                {

+                    AIR_PRINT("Set Port%02d Ingress CIR %d CBS %d Egress CIR %d CBS %d Fail.\n", i, rl.ingress_cir, rl.ingress_cbs, rl.egress_cir, rl.egress_cbs);

+                }

+            }

+        }

+    }

+    else if(1 == argc)

+    {

+        for(i = 0; i < AIR_MAX_NUM_OF_PORTS; i++)

+        {

+            if(portlist[0] & (1 << i))

+            {

+                ret = air_qos_getRateLimit(0, i, &rl);

+                if(ret == AIR_E_OK)

+                {

+                    AIR_PRINT("Get Port%02d Ingress CIR %d CBS %d Egress CIR %d CBS %d\n", i, rl.ingress_cir, rl.ingress_cbs, rl.egress_cir, rl.egress_cbs);

+                }

+                else

+                {

+                    AIR_PRINT("Get Port%02d Rate Info Fail.\n", i);

+                }

+            }

+        }

+    }

+    else

+    {

+        AIR_PRINT("Unrecognized command.\n");

+        ret = AIR_E_BAD_PARAMETER;

+    }

+

+    return ret;

+}

+

+static AIR_ERROR_NO_T

+doQosRateLimitEnable(

+    UI32_T argc,

+    C8_T *argv[])

+{

+    AIR_ERROR_NO_T ret = AIR_E_OK;

+    AIR_PORT_BITMAP_T portlist = {0};

+    C8_T sten[2][10] = {"Disable", "Enable"};

+    C8_T stdir[2][10] = {"Egress", "Ingress"};

+    UI32_T dir = 0, en = 0;

+    AIR_QOS_RATE_DIR_T tmp_dir = AIR_QOS_RATE_DIR_LAST;

+    BOOL_T state = FALSE;

+    UI8_T i = 0;

+

+    ret = _portListStr2Ary(argv[0], portlist, 1);

+    if(ret != AIR_E_OK)

+    {

+        AIR_PRINT("Unrecognized command.\n");

+        return ret;

+    }

+    if(3 == argc)

+    {

+        dir = _strtoul(argv[1], NULL, 0);

+        en = _strtoul(argv[2], NULL, 0);

+        if(dir == 0)

+            tmp_dir = AIR_QOS_RATE_DIR_EGRESS;

+        else if(dir == 1)

+            tmp_dir = AIR_QOS_RATE_DIR_INGRESS;

+        else

+        {

+            AIR_PRINT("Unrecognized command.\n");

+            return AIR_E_BAD_PARAMETER;

+        }

+        if(en)

+            state= TRUE;

+        else

+            state = FALSE;

+

+        for(i = 0; i < AIR_MAX_NUM_OF_PORTS; i++)

+        {

+            if(portlist[0] & (1 << i))

+            {

+                ret = air_qos_setRateLimitEnable(0, i, tmp_dir, state);

+                if(AIR_E_OK == ret)

+                {

+                    AIR_PRINT("Set Port%02d %s rate %s Success.\n", i, stdir[dir], sten[en]);

+                }

+                else

+                {

+                    AIR_PRINT("Set Port%02d %s rate %s Fail.\n", i, stdir[dir], sten[en]);

+                }

+            }

+        }

+    }

+    else if(1 == argc)

+    {

+        for(i = 0; i < AIR_MAX_NUM_OF_PORTS; i++)

+        {

+            if(portlist[0] & (1 << i))

+            {

+                tmp_dir = AIR_QOS_RATE_DIR_EGRESS;

+                dir = 0;

+                ret = air_qos_getRateLimitEnable(0, i, tmp_dir, &state);

+                if(AIR_E_OK == ret)

+                {

+                    AIR_PRINT("Get Port%02d %s rate %s Success.\n", i, stdir[dir], sten[state]);

+                }

+                else

+                {

+                    AIR_PRINT("Get Port%02d %s rate state Fail.\n", i, stdir[dir]);

+                }

+                tmp_dir = AIR_QOS_RATE_DIR_INGRESS;

+                dir = 1;

+                ret = air_qos_getRateLimitEnable(0, i, tmp_dir, &state);

+                if(AIR_E_OK == ret)

+                {

+                    AIR_PRINT("Get Port%02d %s rate %s Success.\n", i, stdir[dir], sten[state]);

+                }

+                else

+                {

+                    AIR_PRINT("Get Port%02d %s rate state Fail.\n", i, stdir[dir]);

+                }

+            }

+        }

+    }

+    else

+    {

+        AIR_PRINT("Unrecognized command.\n");

+        ret = AIR_E_BAD_PARAMETER;

+    }

+

+    return ret;

+

+}

+

+static AIR_ERROR_NO_T

+doQosDscp2Pri(

+    UI32_T argc,

+    C8_T *argv[])

+{

+    AIR_ERROR_NO_T ret = AIR_E_OK;

+    UI32_T dscp = 0, priority = 0;

+

+    dscp = _strtoul(argv[0], NULL, 0);

+    if(2 == argc)

+    {

+        priority = _strtoul(argv[1], NULL, 0);

+        ret = air_qos_setDscp2Pri(0, dscp, priority);

+        if(AIR_E_OK == ret)

+        {

+            AIR_PRINT("Set DSCP %d to priority %d Success.\n", dscp, priority);

+        }

+        else

+        {

+            AIR_PRINT("Set DSCP %d to priority %d Fail.\n", dscp, priority);

+        }

+    }

+    else if(1 == argc)

+    {

+        ret = air_qos_getDscp2Pri(0, dscp, &priority);

+        if(AIR_E_OK == ret)

+        {

+            AIR_PRINT("Get DSCP %d to priority %d\n", dscp, priority);

+        }

+        else

+        {

+            AIR_PRINT("Get DSCP %d to priority Fail.\n", dscp);

+        }

+    }

+    else

+    {

+        AIR_PRINT("Unrecognized command.\n");

+        ret = AIR_E_BAD_PARAMETER;

+    }

+

+    return ret;

+}

+

+static AIR_ERROR_NO_T

+doQosPri2Queue(

+    UI32_T argc,

+    C8_T *argv[])

+{

+    AIR_ERROR_NO_T ret = AIR_E_OK;

+    UI32_T priority = 0, queue = 0;

+

+    priority = _strtoul(argv[1], NULL, 0);

+

+    if(2 == argc)

+    {

+        priority = _strtoul(argv[0], NULL, 0);

+        queue = _strtoul(argv[1], NULL, 0);

+        ret = air_qos_setPri2Queue(0, priority, queue);

+        if(AIR_E_OK == ret)

+        {

+            AIR_PRINT("Set priority %d to queue %d Success.\n", priority, queue);

+        }

+        else

+        {

+            AIR_PRINT("Set priority %d to queue %d Fail.\n", priority, queue);

+        }

+    }

+    else

+    {

+        for(; priority < AIR_QOS_QUEUE_MAX_NUM; priority++)

+        {

+            ret = air_qos_getPri2Queue(0, priority, &queue);

+            if(AIR_E_OK == ret)

+            {

+                AIR_PRINT("Get priority %d to queue %d\n", priority, queue);

+            }

+            else

+            {

+                AIR_PRINT("Get priority %d to queue Fail.\n", priority);

+            }

+        }

+    }

+

+    return ret;

+}

+

+static AIR_ERROR_NO_T

+doQosTrustMode(

+    UI32_T argc,

+    C8_T *argv[])

+{

+    AIR_ERROR_NO_T ret = AIR_E_OK;

+    UI32_T mode = 0;

+    C8_T bs[4][13] = {"port", "1p_port", "dscp_port", "dscp_1p_port"};

+    AIR_QOS_TRUST_MODE_T mode_t = AIR_QOS_TRUST_MODE_LAST;

+    AIR_PORT_BITMAP_T portlist = {0};

+    UI8_T i = 0;

+

+    ret = _portListStr2Ary(argv[0], portlist, 1);

+    if(ret != AIR_E_OK)

+    {

+        AIR_PRINT("Unrecognized command.\n");

+        return ret;

+    }

+    if(2 == argc)

+    {

+        mode = _strtoul(argv[1], NULL, 0);

+        if(mode == 0)

+            mode_t = AIR_QOS_TRUST_MODE_PORT;

+        else if(mode == 1)

+            mode_t = AIR_QOS_TRUST_MODE_1P_PORT;

+        else if(mode == 2)

+            mode_t = AIR_QOS_TRUST_MODE_DSCP_PORT;

+        else if(mode == 3)

+            mode_t = AIR_QOS_TRUST_MODE_DSCP_1P_PORT;

+        else

+        {

+            AIR_PRINT("Unrecognized command.\n");

+            return AIR_E_BAD_PARAMETER;

+        }

+        for(i = 0; i < AIR_MAX_NUM_OF_PORTS; i++)

+        {

+            if(portlist[0] & (1 << i))

+            {

+                ret = air_qos_setTrustMode(0, i, mode_t);

+                if(AIR_E_OK == ret)

+                {

+                    AIR_PRINT("port %d Set Trust mode %s Success.\n", i, bs[mode]);

+                }

+                else

+                {

+                    AIR_PRINT("port %d Set Trust mode %s Fail.\n", i, bs[mode]);

+                }

+            }

+        }

+    }

+    else if(1 == argc)

+    {

+        for(i = 0; i < AIR_MAX_NUM_OF_PORTS; i++)

+        {

+            if(portlist[0] & (1 << i))

+            {

+                mode_t = AIR_QOS_TRUST_MODE_LAST;

+                ret = air_qos_getTrustMode(0, i, &mode_t);

+                if(AIR_E_OK == ret)

+                {

+                    if(mode_t == AIR_QOS_TRUST_MODE_PORT)

+                        mode = 0;

+                    else if(mode_t == AIR_QOS_TRUST_MODE_1P_PORT)

+                        mode = 1;

+                    else if(mode_t == AIR_QOS_TRUST_MODE_DSCP_PORT)

+                        mode = 2;

+                    else if(mode_t == AIR_QOS_TRUST_MODE_DSCP_1P_PORT)

+                        mode = 3;

+                    else

+                    {

+                        AIR_PRINT("port %d Get Trust mode Fail.\n", i);

+                        return AIR_E_OTHERS;

+                    }

+                    AIR_PRINT("port %d Get Trust mode %s\n", i, bs[mode]);

+                }

+                else

+                {

+                    AIR_PRINT("port %d Get Trust mode Fail.\n", i);

+                }

+            }

+        }

+    }

+    else

+    {

+        AIR_PRINT("Unrecognized command.\n");

+        ret = AIR_E_BAD_PARAMETER;

+    }

+

+    return ret;

+}

+

+static AIR_ERROR_NO_T

+doQosScheduleAlgo(

+    UI32_T argc,

+    C8_T *argv[])

+{

+    AIR_ERROR_NO_T ret = AIR_E_OK;

+    AIR_PORT_BITMAP_T portlist = {0};

+    AIR_QOS_SCH_MODE_T sch_mode = AIR_QOS_SCH_MODE_LAST;

+    UI32_T scheduler = 0;

+    UI8_T queue = 0;

+    C8_T sche[3][5] = {"SP", "WRR", "WFQ"};

+    UI32_T weight = AIR_QOS_SHAPER_NOSETTING;

+    UI8_T i = 0;

+

+    ret = _portListStr2Ary(argv[0], portlist, 1);

+    if(ret != AIR_E_OK)

+    {

+        AIR_PRINT("Unrecognized command.\n");

+        return ret;

+    }

+    AIR_PRINT("port list is %d\n", portlist[0]);

+    if(4 == argc)

+    {

+        queue = _strtoul(argv[1], NULL, 0);

+        AIR_PRINT("queue is %d\n", queue);

+        scheduler = _strtoul(argv[2], NULL, 0);

+        AIR_PRINT("scheduler is %d\n", scheduler);

+        weight = _strtoul(argv[3], NULL, 0);

+        AIR_PRINT("weight is %d\n", weight);

+        if(scheduler == 0)

+        {

+            sch_mode = AIR_QOS_SCH_MODE_SP;

+            weight = AIR_QOS_SHAPER_NOSETTING;

+            if(weight != AIR_QOS_SHAPER_NOSETTING)

+                AIR_PRINT("[Warning] SP schedule mode no need weight\n");

+        }

+        else if(scheduler == 1)

+        {

+            sch_mode = AIR_QOS_SCH_MODE_WRR;

+            if(weight == AIR_QOS_SHAPER_NOSETTING)

+            {

+                AIR_PRINT("[Warning] No weight value input , plz check\n");

+                return AIR_E_BAD_PARAMETER;

+            }

+            AIR_PRINT("sch_mode is 1\n");

+        }

+        else if(scheduler == 2)

+        {

+            sch_mode = AIR_QOS_SCH_MODE_WFQ;

+            if(weight == AIR_QOS_SHAPER_NOSETTING)

+            {

+                AIR_PRINT("[Warning] No weight value input , plz check\n");

+                return AIR_E_BAD_PARAMETER;

+            }

+        }

+        else

+        {

+            AIR_PRINT("Unknown schedule mode, plz check again\n");

+            return AIR_E_BAD_PARAMETER;

+        }

+        for(i = 0; i < AIR_MAX_NUM_OF_PORTS; i++)

+        {

+            if(portlist[0] & (1 << i))

+            {

+                AIR_PRINT("port %d\n", i);

+                ret = air_qos_setScheduleAlgo(0, i, queue, sch_mode, weight);

+                if(AIR_E_OK == ret)

+                {

+                    AIR_PRINT("Set Port%02d Scheduler %s Success.\n", i, sche[scheduler]);

+                }

+                else

+                {

+                    AIR_PRINT("Set Port%02d Scheduler %s Fail.\n", i, sche[scheduler]);

+                }

+            }

+        }

+    }

+    else if(2 == argc)

+    {

+        queue = _strtoul(argv[1], NULL, 0);

+        for(i = 0; i < AIR_MAX_NUM_OF_PORTS; i++)

+        {

+            if(portlist[0] & (1 << i))

+            {

+                ret = air_qos_getScheduleAlgo(0, i, queue, &sch_mode, &weight);

+                if(AIR_E_OK == ret)

+                {

+                    if(sch_mode == AIR_QOS_SCH_MODE_SP)

+                        AIR_PRINT("Get Port%02d queue %d Scheduler %s\n", i, queue, sche[sch_mode]);

+                    else if((sch_mode == AIR_QOS_SCH_MODE_WRR) || (sch_mode == AIR_QOS_SCH_MODE_WFQ))

+                        AIR_PRINT("Get Port%02d queue %d Scheduler %s weight %d\n", i, queue, sche[sch_mode], weight);

+                    else

+                        AIR_PRINT("Get Port%02d queue %d Scheduler unknown\n", i, queue);

+                }

+                else

+                {

+                    AIR_PRINT("Get Port%02d queue %d Scheduler Fail.\n", i, queue);

+                }

+            }

+        }

+    }

+    else

+    {

+        AIR_PRINT("Unrecognized command.\n");

+        ret = AIR_E_BAD_PARAMETER;

+    }

+

+    return ret;

+}

+

+static AIR_ERROR_NO_T

+doQosGet(

+        UI32_T argc,

+        C8_T *argv[])

+{

+    return subcmd(qosGetCmds, argc, argv);

+}

+

+static AIR_ERROR_NO_T

+doQosSet(

+        UI32_T argc,

+        C8_T *argv[])

+{

+    return subcmd(qosSetCmds, argc, argv);

+}

+

+static AIR_ERROR_NO_T

+doQos(

+        UI32_T argc,

+        C8_T *argv[])

+{

+    return subcmd(qosCmds, argc, argv);

+}

+static AIR_ERROR_NO_T

+doDiagTxComply(

+        UI32_T argc,

+        C8_T *argv[])

+{

+    AIR_ERROR_NO_T ret = AIR_E_OK;

+    UI32_T phy = 0;

+    UI32_T mode = 0;

+

+    phy = _strtoul(argv[0], NULL, 0);

+    if(2 == argc)

+    {

+        /* diag set txComply <phy(0~5)> <mode(0~8)> */

+        mode = _strtoul(argv[1], NULL, 0);

+        ret = air_diag_setTxComplyMode(0, phy, mode);

+        AIR_PRINT("Set diagnostic function: PHY %u Tx Compliance mode = %u ", phy, mode);

+    }

+    else if(1 == argc)

+    {

+        /* diag get txComply <phy(0~5)> */

+        ret = air_diag_getTxComplyMode(0, phy, &mode);

+        AIR_PRINT("Get diagnostic function: PHY %u Tx Compliance mode ", phy);

+    }

+    else

+    {

+        AIR_PRINT("Unrecognized command.\n");

+        return AIR_E_BAD_PARAMETER;

+    }

+

+    if(AIR_E_OK == ret)

+    {

+        AIR_PRINT("Done.\n\tMode=");

+        switch(mode)

+        {

+            case AIR_DIAG_TXCOMPLY_MODE_10M_NLP:

+                AIR_PRINT("%s\n", "10M_NLP");

+                break;

+            case AIR_DIAG_TXCOMPLY_MODE_10M_RANDOM:

+                AIR_PRINT("%s\n", "10M_Random");

+                break;

+            case AIR_DIAG_TXCOMPLY_MODE_10M_SINE:

+                AIR_PRINT("%s\n", "10M_Sine");

+                break;

+            case AIR_DIAG_TXCOMPLY_MODE_100M_PAIR_A:

+                AIR_PRINT("%s\n", "100M_Pair_a");

+                break;

+            case AIR_DIAG_TXCOMPLY_MODE_100M_PAIR_B:

+                AIR_PRINT("%s\n", "100M_Pair_b");

+                break;

+            case AIR_DIAG_TXCOMPLY_MODE_1000M_TM1:

+                AIR_PRINT("%s\n", "1000M_TM1");

+                break;

+            case AIR_DIAG_TXCOMPLY_MODE_1000M_TM2:

+                AIR_PRINT("%s\n", "1000M_TM2");

+                break;

+            case AIR_DIAG_TXCOMPLY_MODE_1000M_TM3:

+                AIR_PRINT("%s\n", "1000M_TM3");

+                break;

+            case AIR_DIAG_TXCOMPLY_MODE_1000M_TM4:

+                AIR_PRINT("%s\n", "1000M_TM4");

+                break;

+            default:

+                break;

+        }

+    }

+    else

+    if(AIR_E_OTHERS == ret)

+    {

+        AIR_PRINT("isn't setting.\n");

+    }

+    else

+    {

+        AIR_PRINT("Fail.\n");

+    }

+    return ret;

+}

+

+static AIR_ERROR_NO_T

+doDiagSet(

+        UI32_T argc,

+        C8_T *argv[])

+{

+    return subcmd(diagSetCmds, argc, argv);

+}

+

+static AIR_ERROR_NO_T

+doDiagGet(

+        UI32_T argc,

+        C8_T *argv[])

+{

+    return subcmd(diagGetCmds, argc, argv);

+}

+

+static AIR_ERROR_NO_T

+doDiag(

+        UI32_T argc,

+        C8_T *argv[])

+{

+    return subcmd(diagCmds, argc, argv);

+}

+

+static AIR_ERROR_NO_T

+doLedMode(

+        UI32_T argc,

+        C8_T *argv[])

+{

+    AIR_ERROR_NO_T ret = AIR_E_OK;

+    UI32_T mode = 0;

+

+    if(1 == argc)

+    {

+        /* led set mode <mode(0:disable, 1~3:2 LED, 4:User-Define)> */

+        mode = _strtoul(argv[0], NULL, 0);

+        ret = air_led_setMode(0, 0, mode);

+        AIR_PRINT("Set LED mode ");

+    }

+    else if(0 == argc)

+    {

+        /* led get mode */

+        ret = air_led_getMode(0, 0, &mode);

+        AIR_PRINT("Get LED mode ");

+    }

+    else

+    {

+        AIR_PRINT("Unrecognized command.\n");

+        return AIR_E_BAD_PARAMETER;

+    }

+

+    if(AIR_E_OK == ret)

+    {

+        switch(mode)

+        {

+            case AIR_LED_MODE_DISABLE:

+                AIR_PRINT(": Disabled.\n");

+                break;

+            case AIR_LED_MODE_2LED_MODE0:

+                AIR_PRINT(": LED 0:Link / LED 1:Activity.\n");

+                break;

+            case AIR_LED_MODE_2LED_MODE1:

+                AIR_PRINT(": LED 0:1000M Activity / LED 1:100M Activity.\n");

+                break;

+            case AIR_LED_MODE_2LED_MODE2:

+                AIR_PRINT(": LED 0:1000M Activity / LED 1:10&100M Activity.\n");

+                break;

+            case AIR_LED_MODE_USER_DEFINE:

+                AIR_PRINT(": User-Defined.\n");

+                break;

+            default:

+                AIR_PRINT(": Fail.\n");

+                break;

+        }

+    }

+    else

+    if(AIR_E_OTHERS == ret)

+    {

+        AIR_PRINT(": Unrecognized.\n");

+    }

+    else

+    {

+        AIR_PRINT("Fail.\n");

+    }

+    return ret;

+}

+

+static AIR_ERROR_NO_T

+doLedState(

+        UI32_T argc,

+        C8_T *argv[])

+{

+    AIR_ERROR_NO_T ret = AIR_E_OK;

+    UI8_T entity = 0;

+    BOOL_T state = FALSE;

+

+    entity = _strtoul(argv[0], NULL, 0);

+    if(2 == argc)

+    {

+        /* led set state <led(0..1)> <state(1:En 0:Dis)> */

+        state = _strtoul(argv[1], NULL, 0);

+        ret = air_led_setState(0, 0, entity, state);

+        AIR_PRINT("Set LED %u state ", entity);

+    }

+    else if(1 == argc)

+    {

+        /* led get state <led(0..1)> */

+        ret = air_led_getState(0, 0, entity, &state);

+        AIR_PRINT("Get LED %u state ", entity );

+    }

+    else

+    {

+        AIR_PRINT("Unrecognized command.\n");

+        return AIR_E_BAD_PARAMETER;

+    }

+

+    if(AIR_E_OK == ret)

+    {

+        AIR_PRINT(": %s.\n", (state)?"Enable":"Disabled");

+    }

+    else

+    if(AIR_E_OTHERS == ret)

+    {

+        AIR_PRINT(": Unrecognized.\n");

+    }

+    else

+    {

+        AIR_PRINT("Fail.\n");

+    }

+    return ret;

+}

+

+static AIR_ERROR_NO_T

+doLedUsrDef(

+        UI32_T argc,

+        C8_T *argv[])

+{

+    AIR_ERROR_NO_T ret = AIR_E_OK;

+    UI32_T i = 0;

+    UI8_T entity = 0;

+    BOOL_T polarity = LOW;

+    UI32_T on_evt_map = 0;

+    UI32_T blk_evt_map = 0;

+    AIR_LED_ON_EVT_T on_evt;

+    AIR_LED_BLK_EVT_T blk_evt;

+

+    entity = _strtoul(argv[0], NULL, 0);

+    if(4 == argc)

+    {

+        /* led set usr <led(0..1)> <polarity(0:low, 1:high)> <on_evt(7'bin)> <blink_evt(10'bin)> */

+        polarity = _strtoul(argv[1], NULL, 0);

+        on_evt_map = _strtoul(argv[2], NULL, 2);

+        blk_evt_map = _strtoul(argv[3], NULL, 2);

+

+        memset(&on_evt, 0, sizeof(AIR_LED_ON_EVT_T));

+        if(on_evt_map & BIT(0))

+        {

+            on_evt.link_1000m = TRUE;

+        }

+        if(on_evt_map & BIT(1))

+        {

+            on_evt.link_100m = TRUE;

+        }

+        if(on_evt_map & BIT(2))

+        {

+            on_evt.link_10m = TRUE;

+        }

+        if(on_evt_map & BIT(3))

+        {

+            on_evt.link_dn = TRUE;

+        }

+        if(on_evt_map & BIT(4))

+        {

+            on_evt.fdx = TRUE;

+        }

+        if(on_evt_map & BIT(5))

+        {

+            on_evt.hdx = TRUE;

+        }

+        if(on_evt_map & BIT(6))

+        {

+            on_evt.force = TRUE;

+        }

+

+        memset(&blk_evt, 0, sizeof(AIR_LED_BLK_EVT_T));

+        if(blk_evt_map & BIT(0))

+        {

+            blk_evt.tx_act_1000m = TRUE;

+        }

+        if(blk_evt_map & BIT(1))

+        {

+            blk_evt.rx_act_1000m = TRUE;

+        }

+        if(blk_evt_map & BIT(2))

+        {

+            blk_evt.tx_act_100m = TRUE;

+        }

+        if(blk_evt_map & BIT(3))

+        {

+            blk_evt.rx_act_100m = TRUE;

+        }

+        if(blk_evt_map & BIT(4))

+        {

+            blk_evt.tx_act_10m = TRUE;

+        }

+        if(blk_evt_map & BIT(5))

+        {

+            blk_evt.rx_act_10m = TRUE;

+        }

+        if(blk_evt_map & BIT(6))

+        {

+            blk_evt.cls = TRUE;

+        }

+        if(blk_evt_map & BIT(7))

+        {

+            blk_evt.rx_crc = TRUE;

+        }

+        if(blk_evt_map & BIT(8))

+        {

+            blk_evt.rx_idle = TRUE;

+        }

+        if(blk_evt_map & BIT(9))

+        {

+            blk_evt.force = TRUE;

+        }

+        ret = air_led_setUsrDef(0, 0, entity, polarity, on_evt, blk_evt);

+        AIR_PRINT("Set LED %u User-define ", entity);

+    }

+    else if(1 == argc)

+    {

+        /* led get usr <led(0..1)> */

+        ret = air_led_getUsrDef(0, 0, entity, &polarity, &on_evt, &blk_evt);

+        AIR_PRINT("Get LED %u User-define ", entity );

+    }

+    else

+    {

+        AIR_PRINT("Unrecognized command.\n");

+        return AIR_E_BAD_PARAMETER;

+    }

+

+    if(AIR_E_OK == ret)

+    {

+        AIR_PRINT("Done.\n");

+        AIR_PRINT("Polarity:%u.\n", polarity);

+        AIR_PRINT("On Event:\n");

+        i = 6;

+        AIR_PRINT("\t(%u)Force on :%s\n", i--, (on_evt.force)?"On":"Off");

+        AIR_PRINT("\t(%u)Half Duplex :%s\n", i--, (on_evt.hdx)?"On":"Off");

+        AIR_PRINT("\t(%u)Full Duplex :%s\n", i--, (on_evt.fdx)?"On":"Off");

+        AIR_PRINT("\t(%u)Link Down :%s\n", i--, (on_evt.link_dn)?"On":"Off");

+        AIR_PRINT("\t(%u)Link 10M :%s\n", i--, (on_evt.link_10m)?"On":"Off");

+        AIR_PRINT("\t(%u)Link 100M :%s\n", i--, (on_evt.link_100m)?"On":"Off");

+        AIR_PRINT("\t(%u)Link 1000M :%s\n", i--, (on_evt.link_1000m)?"On":"Off");

+

+        AIR_PRINT("Blinking Event:\n");

+        i = 9;

+        AIR_PRINT("\t(%u)Force blinks :%s\n", i--, (blk_evt.force)?"On":"Off");

+        AIR_PRINT("\t(%u)Rx Idle Error :%s\n", i--, (blk_evt.rx_idle)?"On":"Off");

+        AIR_PRINT("\t(%u)Rx CRC Error :%s\n", i--, (blk_evt.rx_crc)?"On":"Off");

+        AIR_PRINT("\t(%u)Collision :%s\n", i--, (blk_evt.cls)?"On":"Off");

+        AIR_PRINT("\t(%u)10Mbps RX Activity :%s\n", i--, (blk_evt.rx_act_10m)?"On":"Off");

+        AIR_PRINT("\t(%u)10Mbps TX Activity :%s\n", i--, (blk_evt.tx_act_10m)?"On":"Off");

+        AIR_PRINT("\t(%u)100Mbps RX Activity :%s\n", i--, (blk_evt.rx_act_100m)?"On":"Off");

+        AIR_PRINT("\t(%u)100Mbps TX Activity :%s\n", i--, (blk_evt.tx_act_100m)?"On":"Off");

+        AIR_PRINT("\t(%u)1000Mbps RX Activity :%s\n", i--, (blk_evt.rx_act_1000m)?"On":"Off");

+        AIR_PRINT("\t(%u)1000Mbps TX Activity :%s\n", i--, (blk_evt.tx_act_1000m)?"On":"Off");

+    }

+    else

+    {

+        AIR_PRINT("Fail.\n");

+    }

+    return ret;

+}

+

+static AIR_ERROR_NO_T

+doLedBlkTime(

+        UI32_T argc,

+        C8_T *argv[])

+{

+    AIR_ERROR_NO_T ret = AIR_E_OK;

+    AIR_LED_BLK_DUR_T time = 0;

+

+    if(1 == argc)

+    {

+        /* led set time <time(0~5)> */

+        time = _strtoul(argv[0], NULL, 0);

+        ret = air_led_setBlkTime(0, 0, time);

+        AIR_PRINT("Set Blinking Duration ");

+    }

+    else if(0 == argc)

+    {

+        /* led get time */

+        ret = air_led_getBlkTime(0, 0, &time);

+        AIR_PRINT("Get Blinking Duration ");

+    }

+    else

+    {

+        AIR_PRINT("Unrecognized command.\n");

+        return AIR_E_BAD_PARAMETER;

+    }

+

+    if(AIR_E_OK == ret)

+    {

+        AIR_PRINT("Done.\n");

+        AIR_PRINT("\tBlinking duration : %u (ms)\n", (32 << time) );

+    }

+    else

+    {

+        AIR_PRINT("Fail.\n");

+    }

+    return ret;

+}

+

+static AIR_ERROR_NO_T

+doLedSet(

+        UI32_T argc,

+        C8_T *argv[])

+{

+    return subcmd(ledSetCmds, argc, argv);

+}

+

+static AIR_ERROR_NO_T

+doLedGet(

+        UI32_T argc,

+        C8_T *argv[])

+{

+    return subcmd(ledGetCmds, argc, argv);

+}

+

+static AIR_ERROR_NO_T

+doLed(

+        UI32_T argc,

+        C8_T *argv[])

+{

+    return subcmd(ledCmds, argc, argv);

+}

+

+static AIR_ERROR_NO_T

+doShowVersion(

+    UI32_T argc,

+    C8_T *argv[])

+{

+    AIR_PRINT("VERSION: %s\n", AIR_VER_SDK);

+

+    return AIR_E_OK;

+}

+

+static AIR_ERROR_NO_T

+doShow(

+        UI32_T argc,

+        C8_T *argv[])

+{

+    return subcmd(showCmds, argc, argv);

+}

+

+static AIR_ERROR_NO_T

+doStormRate(

+    UI32_T argc,

+    C8_T *argv[])

+{

+    AIR_ERROR_NO_T ret = AIR_E_OK;

+    UI32_T port = 0, type = 0;

+    UI32_T unit = 0, count = 0;

+    C8_T stype[3][5] = {"Bcst", "Mcst", "Ucst"};

+    UI32_T kb = 0;

+

+    port = _strtol(argv[0], NULL, 10);

+    type = _strtol(argv[1], NULL, 10);

+    if(4 == argc)

+    {

+        count = _strtol(argv[2], NULL, 10);

+        unit = _strtol(argv[3], NULL, 10);

+

+        if(0 == unit)

+            kb = 64;

+        else if(1 == unit)

+            kb = 256;

+        else if(2 == unit)

+            kb = 1024;

+        else if(3 == unit)

+            kb = 4096;

+        else

+            kb = 16384;

+        ret = air_sec_setStormRate(0, port, type, count, unit);

+        if(AIR_E_OK == ret)

+        {

+            AIR_PRINT("Set Port%02d %s storm rate (%d * %d) = %d Kbps\n", port, stype[type], count, kb, (count*kb));

+        }

+        else

+        {

+            AIR_PRINT("Set Port%02d %s storm rate Fail.\n", port, stype[type]);

+            AIR_PRINT("Note: Port(0..4) can only select unit(0..3), port(5..6) can only select unit(4)\n");

+        }

+    }

+    else if(2 == argc)

+    {

+        ret = air_sec_getStormRate(0, port, type, &count, &unit);

+        if(AIR_E_OK == ret)

+        {

+            if(0 == unit)

+                kb = 64;

+            else if(1 == unit)

+                kb = 256;

+            else if(2 == unit)

+                kb = 1024;

+            else if(3 == unit)

+                kb = 4096;

+            else

+                kb = 16384;

+            AIR_PRINT("Port%02d %s storm rate (%d * %d) = %d Kbps\n", port, stype[type], count, kb, (count*kb));

+        }

+        else

+        {

+            AIR_PRINT("Get Port%02d %s storm rate Fail\n", port, stype[type]);

+        }

+    }

+    else

+    {

+        AIR_PRINT("Unrecognized command.\n");

+        ret = AIR_E_BAD_PARAMETER;

+    }

+

+    return ret;

+}

+

+static AIR_ERROR_NO_T

+doFldMode(

+        UI32_T argc,

+        C8_T *argv[])

+{

+    AIR_ERROR_NO_T ret = AIR_E_OK;

+    UI32_T port = 0, type = 0;

+    BOOL_T fld_en = 0;

+    C8_T stype[4][5] = {"Bcst", "Mcst", "Ucst", "Qury"};

+    C8_T sen[2][10] = {"Disable", "Enable"};

+

+    port = _strtol(argv[0], NULL, 10);

+    type = _strtol(argv[1], NULL, 10);

+

+    if(2 == argc)

+    {

+        ret = air_sec_getFldMode(0, port, type, &fld_en);

+        if(AIR_E_OK == ret)

+        {

+            AIR_PRINT("Get Port%02d flooding %s frame %s\n", port, stype[type], sen[fld_en]);

+        }

+        else

+        {

+            AIR_PRINT("Get Port%02d flooding %s frame Fail\n", port, stype[type]);

+        }

+    }

+    else if(3 == argc)

+    {

+        fld_en = _strtol(argv[2], NULL, 10);

+        ret = air_sec_setFldMode(0, port, type, fld_en);

+        if(AIR_E_OK == ret)

+        {

+            AIR_PRINT("Set Port%02d flooding %s frame %s Success\n", port, stype[type], sen[fld_en]);

+        }

+        else

+        {

+            AIR_PRINT("Set Port%02d flooding %s frame %s Fail\n", port, stype[type], sen[fld_en]);

+        }

+    }

+    else

+    {

+        AIR_PRINT("Unrecognized command.\n");

+        ret = AIR_E_BAD_PARAMETER;

+    }

+

+    return ret;

+}

+

+static AIR_ERROR_NO_T

+doStormEnable(

+    UI32_T argc,

+    C8_T *argv[])

+{

+    AIR_ERROR_NO_T ret = AIR_E_OK;

+    UI32_T port = 0, type = 0;

+    BOOL_T en = 0;

+    C8_T sen[2][10] = {"Disable", "Enable"};

+    C8_T stype[3][5] = {"Bcst", "Mcst", "Ucst"};

+

+    port = _strtol(argv[0], NULL, 10);

+    type = _strtol(argv[1], NULL, 10);

+    if(3 == argc)

+    {

+        en = _strtol(argv[2], NULL, 10);

+        ret = air_sec_setStormEnable(0, port, type, en);

+        if(AIR_E_OK == ret)

+        {

+            AIR_PRINT("Set Port%02d %s storm %s Success.\n", port, stype[type], sen[en]);

+        }

+        else

+        {

+            AIR_PRINT("Set Port%02d %s storm %s Fail.\n", port, stype[type], sen[en]);

+        }

+    }

+    else if(2 == argc)

+    {

+        ret = air_sec_getStormEnable(0, port, type, &en);

+        if(AIR_E_OK == ret)

+        {

+            AIR_PRINT("Port%02d %s storm %s\n", port, stype[type], sen[en]);

+        }

+        else

+        {

+            AIR_PRINT("Get Port%02d %s storm Fail\n", port, stype[type]);

+        }

+    }

+    else

+    {

+        AIR_PRINT("Unrecognized command.\n");

+        ret = AIR_E_BAD_PARAMETER;

+    }

+

+    return ret;

+}

+

+static AIR_ERROR_NO_T

+doSaLearning(UI32_T argc, C8_T *argv[])

+{

+    UI32_T port = 0;

+    AIR_SEC_PORTSEC_PORT_CONFIG_T port_config;

+    AIR_ERROR_NO_T rc = AIR_E_OK;

+

+    port = _strtoul(argv[0], NULL, 0);

+    if(2 == argc)

+    {

+        memset(&port_config, 0, sizeof(AIR_SEC_PORTSEC_PORT_CONFIG_T));

+        rc = air_sec_getPortSecPortCfg(0, port, &port_config);

+        port_config.sa_lrn_en = _strtoul(argv[1], NULL, 0);

+        rc = air_sec_setPortSecPortCfg(0, port, port_config);

+        if(AIR_E_OK == rc)

+        {

+            AIR_PRINT("Set Port%02d sa learn %s Success.\n", port, port_config.sa_lrn_en?"Enable":"Disable");

+        }

+        else

+        {

+            AIR_PRINT("Set Port%02d sa learn %s Fail.\n", port, port_config.sa_lrn_en?"Enable":"Disable");

+        }

+    }

+    else if(1 == argc)

+    {

+        rc = air_sec_getPortSecPortCfg(0, port, &port_config);

+        if(AIR_E_OK == rc)

+        {

+            AIR_PRINT("Port%02d sa learn: %s\n", port, port_config.sa_lrn_en?"Enable":"Disable");

+        }

+        else

+        {

+            AIR_PRINT("Get Port%02d sa learn Fail\n", port);

+        }

+    }

+    else

+    {

+        AIR_PRINT("Unrecognized command.\n");

+        rc = AIR_E_BAD_PARAMETER;

+    }

+    return rc;

+}

+

+static AIR_ERROR_NO_T

+doSaLimit(UI32_T argc, C8_T *argv[])

+{

+    UI32_T port = 0;

+    AIR_SEC_PORTSEC_PORT_CONFIG_T port_config;

+    AIR_ERROR_NO_T rc = AIR_E_OK;

+

+    port = _strtoul(argv[0], NULL, 0);

+    if(3 == argc)

+    {

+        memset(&port_config, 0, sizeof(AIR_SEC_PORTSEC_PORT_CONFIG_T));

+        rc = air_sec_getPortSecPortCfg(0, port, &port_config);

+        port_config.sa_lmt_en = _strtoul(argv[1], NULL, 0);

+        port_config.sa_lmt_cnt = _strtoul(argv[2], NULL, 0);

+        rc = air_sec_setPortSecPortCfg(0, port, port_config);

+        if(AIR_E_OK == rc)

+        {

+            AIR_PRINT("Set Port%02d sa limit %s Success.\n", port, port_config.sa_lmt_en?"Enable":"Disable");

+        }

+        else

+        {

+            AIR_PRINT("Set Port%02d sa limit %s Fail.\n", port, port_config.sa_lmt_en?"Enable":"Disable");

+        }

+    }

+    else if(1 == argc)

+    {

+        rc = air_sec_getPortSecPortCfg(0, port, &port_config);

+        if(AIR_E_OK == rc)

+        {

+            AIR_PRINT("Port%02d ", port);

+            AIR_PRINT("sa limit: %s\n", port_config.sa_lmt_en?"Enable":"Disable");

+            if(TRUE == (port_config.sa_lmt_en && (AIR_MAX_NUM_OF_MAC ==  port_config.sa_lmt_cnt)))

+            {

+                AIR_PRINT("Sa learning without limitation\n");

+            }

+            else if(TRUE == (port_config.sa_lmt_en && (AIR_MAX_NUM_OF_MAC >  port_config.sa_lmt_cnt)))

+            {

+                AIR_PRINT("Rx sa allowable learning number: %d\n", port_config.sa_lmt_cnt);

+            }

+        }

+        else

+        {

+            AIR_PRINT("Get Port%02d sa limit Fail\n", port);

+        }

+    }

+    else

+    {

+        AIR_PRINT("Unrecognized command.\n");

+        rc = AIR_E_BAD_PARAMETER;

+    }

+

+    return rc;

+}

+

+static AIR_ERROR_NO_T

+doSecGet(

+        UI32_T argc,

+        C8_T *argv[])

+{

+    return subcmd(secGetCmds, argc, argv);

+}

+

+static AIR_ERROR_NO_T

+doSecSet(

+        UI32_T argc,

+        C8_T *argv[])

+{

+    return subcmd(secSetCmds, argc, argv);

+}

+

+static AIR_ERROR_NO_T

+doSec(

+        UI32_T argc,

+        C8_T *argv[])

+{

+    return subcmd(secCmds, argc, argv);

+}

+

+static AIR_ERROR_NO_T

+doSwitchCpuPortEn(

+        UI32_T argc,

+        C8_T *argv[])

+{

+    AIR_ERROR_NO_T ret = AIR_E_OK;

+    BOOL_T cpu_en = FALSE;

+

+    if(0 == argc)

+    {

+        /* switch get sysPhyEn */

+        ret = air_switch_getCpuPortEn(0, &cpu_en);

+        AIR_PRINT("Get Cpu Port State ");

+        if(ret == AIR_E_OK)

+        {

+            AIR_PRINT(": %s\n", cpu_en?"Enable":"Disable");

+        }

+        else

+        {

+            AIR_PRINT("Fail!\n");

+        }

+    }

+    else if(1 == argc)

+    {

+        /* switch set sysPhyEn <phy_en> */

+        cpu_en = _strtol(argv[0], NULL, 0);

+        ret = air_switch_setCpuPortEn(0, cpu_en);

+        AIR_PRINT("Set CPU port State ");

+        if(ret == AIR_E_OK)

+        {

+            AIR_PRINT(": %s\n", cpu_en?"Enable":"Disable");

+        }

+        else

+        {

+            AIR_PRINT("Fail!\n");

+        }

+    }

+    else

+    {

+        AIR_PRINT("Unrecognized command.\n");

+        ret = AIR_E_BAD_PARAMETER;

+    }

+

+    return ret;

+}

+

+static AIR_ERROR_NO_T

+doSwitchCpuPort(

+        UI32_T argc,

+        C8_T *argv[])

+{

+    AIR_ERROR_NO_T ret = AIR_E_OK;

+    BOOL_T cpu_en = FALSE;

+    UI32_T port = 0;

+    C8_T str_temp[AIR_MAX_NUM_OF_PORTS+1];

+

+    if(1 == argc)

+    {

+        /* switch set cpuPort <portnumber> */

+        port = _strtol(argv[0], NULL, 10);

+        ret = air_switch_setCpuPort(0, port);

+        AIR_PRINT("Set CPU Port ");

+    }

+    else if(0 == argc)

+    {

+        /* switch get cpuPort */

+        ret = air_switch_getCpuPort(0, &port);

+        AIR_PRINT("Get CPU Port ");

+    }

+    else

+    {

+        AIR_PRINT("Unrecognized command.\n");

+        ret = AIR_E_BAD_PARAMETER;

+    }

+

+    if(AIR_E_OK == ret)

+    {

+        AIR_PRINT(": %d\n", port);

+    }

+    else

+    {

+        AIR_PRINT("Fail!\n");

+    }

+    return ret;

+}

+

+static AIR_ERROR_NO_T

+doSwitchPhyLCIntrEn(

+        UI32_T argc,

+        C8_T *argv[])

+{

+    AIR_ERROR_NO_T ret = AIR_E_OK;

+    UI32_T phy = 0;

+    BOOL_T enable = FALSE;

+

+    if(2 == argc)

+    {

+        /* switch set phyLCIntrEn <phy(0..6)> <(1:En,0:Dis)> */

+        phy    = _strtol(argv[0], NULL, 10);

+        enable = _strtol(argv[1], NULL, 10);

+        ret    = air_switch_setSysIntrEn(0, (phy + AIR_SYS_INTR_TYPE_PHY0_LC), enable);

+    }

+    else if(1 == argc)

+    {

+        /* switch get phyLCIntrEn <phy(0..6)> */

+        phy = _strtol(argv[0], NULL, 10);

+        ret = air_switch_getSysIntrEn(0, (phy + AIR_SYS_INTR_TYPE_PHY0_LC), &enable);

+        AIR_PRINT("PHY(%d) LinkChange interrupt : %s\n", phy, (TRUE == enable) ? "enable" : "disable");

+    }

+    else

+    {

+        AIR_PRINT("Unrecognized command.\n");

+        ret = AIR_E_BAD_PARAMETER;

+    }

+

+    return ret;

+}

+

+static AIR_ERROR_NO_T

+doSwitchPhyLCIntrSts(

+        UI32_T argc,

+        C8_T *argv[])

+{

+    AIR_ERROR_NO_T ret = AIR_E_OK;

+    UI32_T phy = 0;

+    BOOL_T enable = FALSE;

+

+    if(2 == argc)

+    {

+        /* switch set phyLCIntrSts <phy(0..6)> <(1:En)> */

+        phy    = _strtol(argv[0], NULL, 10);

+        enable = _strtol(argv[1], NULL, 10);

+        ret    = air_switch_setSysIntrStatus(0, (phy + AIR_SYS_INTR_TYPE_PHY0_LC), enable);

+    }

+    else if(1 == argc)

+    {

+        /* switch get phyLCIntrSts <phy(0..6)> */

+        phy = _strtol(argv[0], NULL, 10);

+        ret = air_switch_getSysIntrStatus(0, (phy + AIR_SYS_INTR_TYPE_PHY0_LC), &enable);

+        AIR_PRINT("PHY(%d) LinkChange interrupt state : %s\n", phy, (TRUE == enable) ? "set" : "unset");

+    }

+    else

+    {

+        AIR_PRINT("Unrecognized command.\n");

+        ret = AIR_E_BAD_PARAMETER;

+    }

+

+    return ret;

+}

+

+

+static AIR_ERROR_NO_T

+doSwitchSet(

+        UI32_T argc,

+        C8_T *argv[])

+{

+    return subcmd(switchSetCmds, argc, argv);

+}

+

+static AIR_ERROR_NO_T

+doSwitchGet(

+        UI32_T argc,

+        C8_T *argv[])

+{

+    return subcmd(switchGetCmds, argc, argv);

+}

+

+static AIR_ERROR_NO_T

+doSwitch(

+        UI32_T argc,

+        C8_T *argv[])

+{

+    return subcmd(switchCmds, argc, argv);

+}

+

+static void _air_acl_printRuleMap(UI32_T *rule_map, UI32_T ary_num)

+{

+    UI32_T i;

+    BOOL_T first;

+

+    first = TRUE;

+    for(i=0; i<ary_num*32; i++)

+    {

+        if(rule_map[i/32] & BIT(i%32))

+        {

+            if(TRUE == first)

+            {

+                AIR_PRINT("%u", i);

+                first = FALSE;

+            }

+            else

+            {

+                AIR_PRINT(",%u", i);

+            }

+        }

+    }

+    AIR_PRINT("\n");

+}

+

+static AIR_ERROR_NO_T

+doAclEn(

+    UI32_T argc,

+    C8_T *argv[])

+{

+    AIR_ERROR_NO_T ret = AIR_E_OK;

+    UI32_T argi=0;

+    UI32_T port = 0;

+    BOOL_T en = FALSE;

+

+    if(1 == argc)

+    {

+        /* acl set en <en(1:En,0:Dis)> */

+        en = _strtoul(argv[argi++], NULL, 2);

+        ret = air_acl_setGlobalState(0, en);

+        AIR_PRINT("Set Global ACL function ");

+    }

+    else if(0 == argc)

+    {

+        /* acl get en */

+        ret = air_acl_getGlobalState(0, &en);

+        AIR_PRINT("Get Global ACL function ");

+    }

+    else

+    {

+        AIR_PRINT("Unrecognized command.\n");

+        return AIR_E_BAD_PARAMETER;

+    }

+

+    if(ret == AIR_E_OK)

+    {

+        AIR_PRINT(": %s\n", (TRUE == en)?"Enable":"Disable");

+    }

+    else

+    {

+        AIR_PRINT("Fail!\n");

+    }

+

+    return ret;

+}

+

+static AIR_ERROR_NO_T

+doAclRule(

+        UI32_T argc,

+        C8_T *argv[])

+{

+    AIR_ERROR_NO_T ret = AIR_E_OK;

+    UI32_T rule_idx = 0;

+    BOOL_T state = FALSE, reverse = FALSE, end = FALSE;

+    UI32_T argi = 0, ipv6 = 0, i = 0;

+    AIR_ACL_RULE_T rule;

+    UI8_T tmp_ip[16] = {0};

+    C8_T str_temp[AIR_MAX_NUM_OF_PORTS+1];

+    C8_T str[40];

+

+    memset(&rule, 0, sizeof(AIR_ACL_RULE_T));

+    if(argc >= 6)

+    {

+        /* acl set rule <idx(0..255)> <state(0:Dis,1:En)> <reverse(0:Dis,1:En)> <end(0:Dis,1:En)> <portmap(7'bin)>

+        <ipv6(0:Dis,1:En,2:Not care)>

+        [ dmac <dmac(12'hex)> <dmac_mask(12'hex)> ]

+        [ smac <smac(12'hex)> <smac_mask(12'hex)> ]

+        [ stag <stag(4'hex)> <stag_mask(4'hex)> ]

+        [ ctag <ctag(4'hex)> <ctag_mask(4'hex)> ]

+        [ etype <etype(4'hex)> <etype_mask(4'hex)> ]

+        [ dip <dip(IPADDR)> <dip_mask(IPADDR)> ]

+        [ sip <sip(IPADDR)> <sip_mask(IPADDR)> ]

+        [ dscp <dscp(2'hex)> <dscp_mask(2'hex)> ]

+        [ protocol <protocol(2'hex)> <protocol_mask(2'hex)> ]

+        [ dport <dport(4'hex)> <dport_mask(4'hex)> ]

+        [ sport <sport(4'hex)> <sport_mask(4'hex)> ]

+        [ flow_label <flow_label(4'hex)> <flow_label_mask(4'hex)> ]

+        [ udf <udf(4'hex)> <udf_mask(4'hex)> ] */

+

+        rule_idx = _strtoul(argv[argi++], NULL, 0);

+

+        rule.ctrl.rule_en = _strtoul(argv[argi++], NULL, 0);

+        rule.ctrl.reverse = _strtoul(argv[argi++], NULL, 0);

+        rule.ctrl.end = _strtoul(argv[argi++], NULL, 0);

+

+        rule.key.portmap = _strtoul(argv[argi++], NULL, 2);

+        rule.mask.portmap = (~rule.key.portmap) & AIR_ALL_PORT_BITMAP;

+

+        ipv6 = _strtoul(argv[argi++], NULL, 0);

+        if(0 == ipv6)

+        {

+            rule.key.isipv6 = FALSE;

+            rule.mask.isipv6 = TRUE;

+        }

+        else if(1 == ipv6)

+        {

+            rule.key.isipv6 = TRUE;

+            rule.mask.isipv6 = TRUE;

+        }

+        else

+        {

+            rule.mask.isipv6 = FALSE;

+        }

+

+        if(0 == _strcmp(argv[argi], "dmac"))

+        {

+            argi++;

+            _str2mac(argv[argi++], rule.key.dmac);

+            _str2mac(argv[argi++], rule.mask.dmac);

+            rule.key.fieldmap |= 1 << AIR_ACL_DMAC;

+        }

+

+        if(0 == _strcmp(argv[argi], "smac"))

+        {

+            argi++;

+            _str2mac(argv[argi++], rule.key.smac);

+            _str2mac(argv[argi++], rule.mask.smac);

+            rule.key.fieldmap |= 1 << AIR_ACL_SMAC;

+        }

+

+        if(0 == _strcmp(argv[argi], "stag"))

+        {

+            argi++;

+            rule.key.stag = _strtoul(argv[argi++], NULL, 16);

+            rule.mask.stag = _strtoul(argv[argi++], NULL, 16);

+            rule.key.fieldmap |= 1 << AIR_ACL_STAG;

+        }

+

+        if(0 == _strcmp(argv[argi], "ctag"))

+        {

+            argi++;

+            rule.key.ctag = _strtoul(argv[argi++], NULL, 16);

+            rule.mask.ctag = _strtoul(argv[argi++], NULL, 16);

+            rule.key.fieldmap |= 1 << AIR_ACL_CTAG;

+        }

+

+        if(0 == _strcmp(argv[argi], "etype"))

+        {

+            argi++;

+            rule.key.etype= _strtoul(argv[argi++], NULL, 16);

+            rule.mask.etype = _strtoul(argv[argi++], NULL, 16);

+            rule.key.fieldmap |= 1 << AIR_ACL_ETYPE;

+        }

+

+        if(0 == _strcmp(argv[argi], "dip"))

+        {

+            argi++;

+            if(0 == ipv6)

+            {

+                _str2ipv4(argv[argi++], rule.key.dip);

+                _str2ipv4(argv[argi++], rule.mask.dip);

+            }

+            else if(1 == ipv6)

+            {

+                _str2ipv6(argv[argi++], tmp_ip);

+                rule.key.dip[3] = (tmp_ip[0]<<24) | (tmp_ip[1]<<16) | (tmp_ip[2]<<8) | tmp_ip[3];

+                rule.key.dip[2] = (tmp_ip[4]<<24) | (tmp_ip[5]<<16) | (tmp_ip[6]<<8) | tmp_ip[7];

+                rule.key.dip[1] = (tmp_ip[8]<<24) | (tmp_ip[9]<<16) | (tmp_ip[10]<<8) | tmp_ip[11];

+                rule.key.dip[0] = (tmp_ip[12]<<24) | (tmp_ip[13]<<16) | (tmp_ip[14]<<8) | tmp_ip[15];

+                _str2ipv6(argv[argi++], tmp_ip);

+                rule.mask.dip[3] = (tmp_ip[0]<<24) | (tmp_ip[1]<<16) | (tmp_ip[2]<<8) | tmp_ip[3];

+                rule.mask.dip[2] = (tmp_ip[4]<<24) | (tmp_ip[5]<<16) | (tmp_ip[6]<<8) | tmp_ip[7];

+                rule.mask.dip[1] = (tmp_ip[8]<<24) | (tmp_ip[9]<<16) | (tmp_ip[10]<<8) | tmp_ip[11];

+                rule.mask.dip[0] = (tmp_ip[12]<<24) | (tmp_ip[13]<<16) | (tmp_ip[14]<<8) | tmp_ip[15];

+            }

+            rule.key.fieldmap |= 1 << AIR_ACL_DIP;

+        }

+

+        if(0 == _strcmp(argv[argi], "sip"))

+        {

+            argi++;

+            if(0 == ipv6)

+            {

+                _str2ipv4(argv[argi++], rule.key.sip);

+                _str2ipv4(argv[argi++], rule.mask.sip);

+            }

+            else if(1 == ipv6)

+            {

+                _str2ipv6(argv[argi++], tmp_ip);

+                rule.key.sip[3] = (tmp_ip[0]<<24) | (tmp_ip[1]<<16) | (tmp_ip[2]<<8) | tmp_ip[3];

+                rule.key.sip[2] = (tmp_ip[4]<<24) | (tmp_ip[5]<<16) | (tmp_ip[6]<<8) | tmp_ip[7];

+                rule.key.sip[1] = (tmp_ip[8]<<24) | (tmp_ip[9]<<16) | (tmp_ip[10]<<8) | tmp_ip[11];

+                rule.key.sip[0] = (tmp_ip[12]<<24) | (tmp_ip[13]<<16) | (tmp_ip[14]<<8) | tmp_ip[15];

+                _str2ipv6(argv[argi++], tmp_ip);

+                rule.mask.sip[3] = (tmp_ip[0]<<24) | (tmp_ip[1]<<16) | (tmp_ip[2]<<8) | tmp_ip[3];

+                rule.mask.sip[2] = (tmp_ip[4]<<24) | (tmp_ip[5]<<16) | (tmp_ip[6]<<8) | tmp_ip[7];

+                rule.mask.sip[1] = (tmp_ip[8]<<24) | (tmp_ip[9]<<16) | (tmp_ip[10]<<8) | tmp_ip[11];

+                rule.mask.sip[0] = (tmp_ip[12]<<24) | (tmp_ip[13]<<16) | (tmp_ip[14]<<8) | tmp_ip[15];

+            }

+            rule.key.fieldmap |= 1 << AIR_ACL_SIP;

+        }

+

+        if(0 == _strcmp(argv[argi], "dscp"))

+        {

+            argi++;

+            rule.key.dscp = _strtoul(argv[argi++], NULL, 16);

+            rule.mask.dscp = _strtoul(argv[argi++], NULL, 16);

+            rule.key.fieldmap |= 1 << AIR_ACL_DSCP;

+        }

+

+        if(0 == _strcmp(argv[argi], "protocol"))

+        {

+            argi++;

+            rule.key.protocol = _strtoul(argv[argi++], NULL, 16);

+            rule.mask.protocol = _strtoul(argv[argi++], NULL, 16);

+            rule.key.fieldmap |= 1 << AIR_ACL_PROTOCOL;

+        }

+

+        if(0 == _strcmp(argv[argi], "dport"))

+        {

+            argi++;

+            rule.key.dport = _strtoul(argv[argi++], NULL, 16);

+            rule.mask.dport = _strtoul(argv[argi++], NULL, 16);

+            rule.key.fieldmap |= 1 << AIR_ACL_DPORT;

+        }

+

+        if(0 == _strcmp(argv[argi], "sport"))

+        {

+            argi++;

+            rule.key.sport = _strtoul(argv[argi++], NULL, 16);

+            rule.mask.sport = _strtoul(argv[argi++], NULL, 16);

+            rule.key.fieldmap |= 1 << AIR_ACL_SPORT;

+        }

+

+        if(0 == _strcmp(argv[argi], "flow_label"))

+        {

+            argi++;

+            rule.key.flow_label= _strtoul(argv[argi++], NULL, 16);

+            rule.mask.flow_label= _strtoul(argv[argi++], NULL, 16);

+            rule.key.fieldmap |= 1 << AIR_ACL_FLOW_LABEL;

+        }

+

+        if(0 == _strcmp(argv[argi], "udf"))

+        {

+            argi++;

+            rule.key.udf = _strtoul(argv[argi++], NULL, 16);

+            rule.mask.udf = _strtoul(argv[argi++], NULL, 16);

+            rule.key.fieldmap |= 1 << AIR_ACL_UDF;

+        }

+

+        rule.mask.fieldmap = rule.key.fieldmap;

+        ret = air_acl_setRule(0, rule_idx, &rule);

+        if(ret < AIR_E_LAST)

+            AIR_PRINT("Set ACL Rule(%u): %s\n", rule_idx, air_error_getString(ret));

+    }

+    else if(1 == argc)

+    {

+        rule_idx = _strtoul(argv[0], NULL, 0);

+        ret = air_acl_getRule(0, rule_idx, &rule);

+        if(ret < AIR_E_LAST)

+            AIR_PRINT("Get ACL Rule(%u): %s\n", rule_idx, air_error_getString(ret));

+    }

+    else

+    {

+        AIR_PRINT("Unrecognized command.\n");

+        return AIR_E_BAD_PARAMETER;

+    }

+

+    if(AIR_E_OK == ret)

+    {

+        if(TRUE == rule.ctrl.rule_en)

+        {

+            AIR_PRINT("\t Rule end          : %s\n", (TRUE == rule.ctrl.end)?"Enable":"Disable");

+            AIR_PRINT("\t Rule reverse      : %s\n", (TRUE == rule.ctrl.reverse)?"Enable":"Disable");

+            _hex2bitstr((~rule.mask.portmap) & AIR_ALL_PORT_BITMAP, str_temp, AIR_MAX_NUM_OF_PORTS+1);

+            AIR_PRINT("\t Portmap[0:6]      : %s\n", str_temp);

+            for(i = AIR_ACL_DMAC; i < AIR_ACL_FIELD_TYPE_LAST; i++)

+            {

+                if((1 << i) & rule.mask.fieldmap)

+                {

+                    switch (i)

+                    {

+                        case AIR_ACL_DMAC:

+                            AIR_PRINT("\t dmac: ");

+                            AIR_PRINT("%02x-%02x-%02x-%02x-%02x-%02x",

+                            rule.key.dmac[0], rule.key.dmac[1], rule.key.dmac[2],

+                            rule.key.dmac[3], rule.key.dmac[4], rule.key.dmac[5]);

+                            AIR_PRINT(", dmac-mask: ");

+                            AIR_PRINT("%02x-%02x-%02x-%02x-%02x-%02x\n",

+                            rule.mask.dmac[0], rule.mask.dmac[1], rule.mask.dmac[2],

+                            rule.mask.dmac[3], rule.mask.dmac[4], rule.mask.dmac[5]);

+                            break;

+                        case AIR_ACL_SMAC:

+                            AIR_PRINT("\t smac: ");

+                            AIR_PRINT("%02x-%02x-%02x-%02x-%02x-%02x",

+                            rule.key.smac[0], rule.key.smac[1], rule.key.smac[2],

+                            rule.key.smac[3], rule.key.smac[4], rule.key.smac[5]);

+                            AIR_PRINT(", smac-mask: ");

+                            AIR_PRINT("%02x-%02x-%02x-%02x-%02x-%02x\n",

+                            rule.mask.smac[0], rule.mask.smac[1], rule.mask.smac[2],

+                            rule.mask.smac[3], rule.mask.smac[4], rule.mask.smac[5]);

+                            break;

+                        case AIR_ACL_ETYPE:

+                            AIR_PRINT("\t etype: 0x%x, etype-mask: 0x%x\n", rule.key.etype, rule.mask.etype);

+                            break;

+                        case AIR_ACL_STAG:

+                            AIR_PRINT("\t stag: 0x%x, stag-mask: 0x%x\n", rule.key.stag, rule.mask.stag);

+                            break;

+                        case AIR_ACL_CTAG:

+                            AIR_PRINT("\t ctag: 0x%x, ctag-mask: 0x%x\n", rule.key.ctag, rule.mask.ctag);

+                            break;

+                        case AIR_ACL_DPORT:

+                            AIR_PRINT("\t dport: 0x%x, dport-mask: 0x%x\n", rule.key.dport, rule.mask.dport);

+                            break;

+                        case AIR_ACL_SPORT:

+                            AIR_PRINT("\t sport: 0x%x, sport-mask: 0x%x\n", rule.key.sport, rule.mask.sport);

+                            break;

+                        case AIR_ACL_UDF:

+                            AIR_PRINT("\t udf: 0x%x, udf-mask: 0x%x\n", rule.key.udf, rule.mask.udf);

+                            break;

+                        case AIR_ACL_DIP:

+                            if (0 == rule.key.isipv6)

+                            {

+                                AIR_PRINT("\t dip: ");

+                                AIR_PRINT("%d.%d.%d.%d",

+                                ((rule.key.dip[0])&0xFF000000)>>24,((rule.key.dip[0])&0x00FF0000)>>16,

+                                ((rule.key.dip[0])&0x0000FF00)>>8, ((rule.key.dip[0])&0x000000FF));

+                                AIR_PRINT(", dip-mask: ");

+                                AIR_PRINT("%d.%d.%d.%d\n ",

+                                ((rule.mask.dip[0])&0xFF000000)>>24,((rule.mask.dip[0])&0x00FF0000)>>16,

+                                ((rule.mask.dip[0])&0x0000FF00)>>8, ((rule.mask.dip[0])&0x000000FF));

+                            }

+                            else

+                            {

+                                for(i=0; i<4; i++){

+                                    tmp_ip[i] = (rule.key.dip[3] >> (8*(3-i))) & 0xff;

+                                    AIR_PRINT("get tmp_ip[%d]=0x%x\n", i, tmp_ip[i]);

+                                }

+                                for(i=4; i<8; i++){

+                                    tmp_ip[i] = (rule.key.dip[2] >> (8*(7-i))) & 0xff;

+                                }

+                                for(i=8; i<12; i++){

+                                    tmp_ip[i] = (rule.key.dip[1] >> (8*(11-i))) & 0xff;

+                                }

+                                for(i=12; i<16; i++){

+                                    tmp_ip[i] = (rule.key.dip[0] >> (8*(15-i))) & 0xff;

+                                }

+

+                                AIR_PRINT("\t dip: ");

+                                AIR_PRINT("%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x",

+                                    tmp_ip[0], tmp_ip[1],tmp_ip[2], tmp_ip[3],tmp_ip[4], tmp_ip[5],tmp_ip[6], tmp_ip[7],

+                                    tmp_ip[8], tmp_ip[9],tmp_ip[10], tmp_ip[11],tmp_ip[12], tmp_ip[13],tmp_ip[14], tmp_ip[15]);

+                                for(i=0; i<4; i++){

+                                    tmp_ip[i] = (rule.mask.dip[3] >> (8*(3-i))) & 0xff;

+                                }

+                                for(i=4; i<8; i++){

+                                    tmp_ip[i] = (rule.mask.dip[2] >> (8*(7-i))) & 0xff;

+                                }

+                                for(i=8; i<12; i++){

+                                    tmp_ip[i] = (rule.mask.dip[1] >> (8*(11-i))) & 0xff;

+                                }

+                                for(i=12; i<16; i++){

+                                    tmp_ip[i] = (rule.mask.dip[0] >> (8*(15-i))) & 0xff;

+                                }

+                                AIR_PRINT(", dip-mask: ");

+                                AIR_PRINT("%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x\n",

+                                    tmp_ip[0], tmp_ip[1],tmp_ip[2], tmp_ip[3],tmp_ip[4], tmp_ip[5],tmp_ip[6], tmp_ip[7],

+                                    tmp_ip[8], tmp_ip[9],tmp_ip[10], tmp_ip[11],tmp_ip[12], tmp_ip[13],tmp_ip[14], tmp_ip[15]);

+                            }

+                            break;

+                        case AIR_ACL_SIP:

+                            if (0 == rule.key.isipv6)

+                            {

+                                AIR_PRINT("\t sip: ");

+                                AIR_PRINT("%d.%d.%d.%d ",

+                                ((rule.key.sip[0])&0xFF000000)>>24,((rule.key.sip[0])&0x00FF0000)>>16,

+                                ((rule.key.sip[0])&0x0000FF00)>>8, ((rule.key.sip[0])&0x000000FF));

+                                AIR_PRINT(", sip-mask: ");

+                                AIR_PRINT("%d.%d.%d.%d\n ",

+                                ((rule.mask.sip[0])&0xFF000000)>>24,((rule.mask.sip[0])&0x00FF0000)>>16,

+                                ((rule.mask.sip[0])&0x0000FF00)>>8, ((rule.mask.sip[0])&0x000000FF));

+                            }

+                            else

+                            {

+                                for(i=0; i<4; i++){

+                                    tmp_ip[i] = (rule.key.sip[3] >> (8*(3-i))) & 0xff;

+                                }

+                                for(i=4; i<8; i++){

+                                    tmp_ip[i] = (rule.key.sip[2] >> (8*(7-i))) & 0xff;

+                                }

+                                for(i=8; i<12; i++){

+                                    tmp_ip[i] = (rule.key.sip[1] >> (8*(11-i))) & 0xff;

+                                }

+                                for(i=12; i<16; i++){

+                                    tmp_ip[i] = (rule.key.sip[0] >> (8*(15-i))) & 0xff;

+                                }

+                                AIR_PRINT("\t sip: ");

+                                AIR_PRINT("%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x",

+                                    tmp_ip[0], tmp_ip[1],tmp_ip[2], tmp_ip[3],tmp_ip[4], tmp_ip[5],tmp_ip[6], tmp_ip[7],

+                                    tmp_ip[8], tmp_ip[9],tmp_ip[10], tmp_ip[11],tmp_ip[12], tmp_ip[13],tmp_ip[14], tmp_ip[15]);

+                                for(i=0; i<4; i++){

+                                    tmp_ip[i] = (rule.mask.sip[3] >> (8*(3-i))) & 0xff;

+                                }

+                                for(i=4; i<8; i++){

+                                    tmp_ip[i] = (rule.mask.sip[2] >> (8*(7-i))) & 0xff;

+                                }

+                                for(i=8; i<12; i++){

+                                    tmp_ip[i] = (rule.mask.sip[1] >> (8*(11-i))) & 0xff;

+                                }

+                                for(i=12; i<16; i++){

+                                    tmp_ip[i] = (rule.mask.sip[0] >> (8*(15-i))) & 0xff;

+                                }

+                                AIR_PRINT(", sip-mask: ");

+                                AIR_PRINT("%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x\n",

+                                    tmp_ip[0], tmp_ip[1],tmp_ip[2], tmp_ip[3],tmp_ip[4], tmp_ip[5],tmp_ip[6], tmp_ip[7],

+                                    tmp_ip[8], tmp_ip[9],tmp_ip[10], tmp_ip[11],tmp_ip[12], tmp_ip[13],tmp_ip[14], tmp_ip[15]);

+                            }

+                            break;

+                        case AIR_ACL_DSCP:

+                            AIR_PRINT("\t dscp: 0x%x, dscp-mask: 0x%x\n", rule.key.dscp, rule.mask.dscp);

+                            break;

+                        case AIR_ACL_PROTOCOL:

+                            AIR_PRINT("\t protocol: 0x%x, protocol-mask: 0x%x\n", rule.key.protocol, rule.mask.protocol);

+                            break;

+                        case AIR_ACL_FLOW_LABEL:

+                            AIR_PRINT("\t flow-label: 0x%x, flow-label-mask: 0x%x\n", rule.key.flow_label, rule.mask.flow_label);

+                            break;

+                        default:

+                            AIR_PRINT("error\n");

+                            break;

+                    }

+                }

+            }

+        }

+        else

+        {

+            AIR_PRINT("Entry is Invalid.\n");

+        }

+    }

+

+    return ret;

+}

+

+static AIR_ERROR_NO_T

+doAclRmvRule(

+        UI32_T argc,

+        C8_T *argv[])

+{

+    AIR_ERROR_NO_T ret = AIR_E_OK;

+    UI32_T rule_idx = 0;

+

+    if(1 == argc)

+    {

+        /* acl del rule <idx(0..127)> */

+        rule_idx = _strtoul(argv[0], NULL, 0);

+        ret = air_acl_delRule(0, rule_idx);

+        if(ret < AIR_E_LAST)

+            AIR_PRINT("Delete ACL Rule(%u): %s\n", rule_idx, air_error_getString(ret));

+    }

+    else if(0 == argc)

+    {

+        /* acl clear rule */

+        ret = air_acl_clearRule(0);

+        if(ret < AIR_E_LAST)

+            AIR_PRINT("Clear ACL Rule: %s\n", air_error_getString(ret));

+    }

+    else

+    {

+        AIR_PRINT("Unrecognized command.\n");

+        return AIR_E_BAD_PARAMETER;

+    }

+

+    return ret;

+}

+

+static AIR_ERROR_NO_T

+doAclUdfRule(

+        UI32_T argc,

+        C8_T *argv[])

+{

+    AIR_ERROR_NO_T ret = AIR_E_OK;

+    UI32_T rule_idx;

+    AIR_ACL_UDF_RULE_T rule;

+    C8_T start_addr[8][12]=

+    {

+        "MAC header",

+        "L2 payload",

+        "IPv4 header",

+        "IPv6 header",

+        "L3 payload",

+        "TCP header",

+        "UDP header",

+        "L4 payload"

+    };

+    C8_T str_temp[AIR_MAX_NUM_OF_PORTS+1];

+

+    memset(&rule, 0, sizeof(AIR_ACL_UDF_RULE_T));

+    if(7 == argc)

+    {

+        /* acl set rule <idx(0..255)> <mode(0:pattern, 1:threshold)> [ <pat(4'hex)> <mask(4'hex)> | <low(4'hex)> <high(4'hex)> ] <start(0:MAC,1:ether,2:IP,3:IP_data,4:TCP/UDP,5:TCP/UDP data,6:IPv6)> <offset(0..62,unit:2 bytes)> <portmap(7'bin)> */

+        rule_idx = _strtoul(argv[0], NULL, 0);

+        rule.cmp_sel = _strtoul(argv[1], NULL, 2);

+        if(AIR_ACL_RULE_CMP_SEL_PATTERN == rule.cmp_sel)

+        {

+            rule.pattern = _strtoul(argv[2], NULL, 16);

+            rule.mask = _strtoul(argv[3], NULL, 16);

+        }

+        else

+        {

+            rule.low_threshold = _strtoul(argv[2], NULL, 16);

+            rule.high_threshold = _strtoul(argv[3], NULL, 16);

+        }

+        rule.offset_format = _strtoul(argv[4], NULL, 0);

+        rule.offset = _strtoul(argv[5], NULL, 0);

+        rule.portmap = _strtoul(argv[6], NULL, 2);

+        rule.valid = TRUE;

+        ret = air_acl_setUdfRule(0, rule_idx, rule);

+        if(ret < AIR_E_LAST)

+            AIR_PRINT("Set ACL UDF Rule(%u): %s\n", rule_idx, air_error_getString(ret));

+    }

+    else if(1 == argc)

+    {

+        rule_idx = _strtoul(argv[0], NULL, 0);

+        ret = air_acl_getUdfRule(0, rule_idx, &rule);

+        if(ret < AIR_E_LAST)

+            AIR_PRINT("Get ACL UDF Rule(%u): %s\n", rule_idx, air_error_getString(ret));

+    }

+    else

+    {

+        AIR_PRINT("Unrecognized command.\n");

+        return AIR_E_BAD_PARAMETER;

+    }

+

+    if(AIR_E_OK == ret)

+    {

+        if(TRUE == rule.valid)

+        {

+            AIR_PRINT("\tMode          : %s\n", (AIR_ACL_RULE_CMP_SEL_PATTERN == rule.cmp_sel)?"Pattern":"Threshold");

+            if(AIR_ACL_RULE_CMP_SEL_PATTERN == rule.cmp_sel)

+            {

+                AIR_PRINT("\tPattern       : 0x%04X\n", rule.pattern);

+                AIR_PRINT("\tMask          : 0x%04X\n", rule.mask);

+            }

+            else

+            {

+                AIR_PRINT("\tLow Threshold : 0x%04X\n", rule.low_threshold);

+                AIR_PRINT("\tHigh Threshold: 0x%04X\n", rule.high_threshold);

+            }

+            AIR_PRINT("\tOffset Start  : %s\n", start_addr[rule.offset_format]);

+            AIR_PRINT("\tOffset        : %u %s\n", rule.offset*2, (0==rule.offset)?"Byte":"Bytes");

+            _hex2bitstr(rule.portmap, str_temp, AIR_MAX_NUM_OF_PORTS+1);

+            AIR_PRINT("\tPortmap[0:6]  : %s\n", str_temp);

+        }

+        else

+        {

+            AIR_PRINT("Entry is Invalid.\n");

+        }

+    }

+

+    return ret;

+}

+

+static AIR_ERROR_NO_T

+doAclRmvUdfRule(

+        UI32_T argc,

+        C8_T *argv[])

+{

+    AIR_ERROR_NO_T ret = AIR_E_OK;

+    UI32_T rule_idx;

+

+    if(1 == argc)

+    {

+        /* acl del udfRule <idx(0..15)> */

+        rule_idx = _strtoul(argv[0], NULL, 0);

+        ret = air_acl_delUdfRule(0, rule_idx);

+        if(ret < AIR_E_LAST)

+            AIR_PRINT("Delete ACL UDF Rule(%u): %s\n", rule_idx, air_error_getString(ret));

+    }

+    else if(0 == argc)

+    {

+        /* acl clear udfRule */

+        ret = air_acl_clearUdfRule(0);

+        if(ret < AIR_E_LAST)

+            AIR_PRINT("Clear ACL UDF Rule: %s\n", air_error_getString(ret));

+    }

+    else

+    {

+        AIR_PRINT("Unrecognized command.\n");

+        return AIR_E_BAD_PARAMETER;

+    }

+

+    return ret;

+}

+

+static AIR_ERROR_NO_T

+doAclAction(

+        UI32_T argc,

+        C8_T *argv[])

+{

+    AIR_ERROR_NO_T ret = AIR_E_OK;

+    UI32_T argi = 0;

+    UI32_T act_idx;

+    AIR_ACL_ACTION_T act;

+    UI32_T redirect, trtcm, fwd;

+    C8_T fwding[AIR_ACL_ACT_FWD_LAST][25] =

+    {

+        "Default",

+        "Default",

+        "Default",

+        "Default",

+        "Default & CPU excluded",

+        "Default & CPU included",

+        "CPU only",

+        "Drop"

+    };

+    C8_T trtcm_usr[AIR_ACL_ACT_USR_TCM_LAST][8] =

+    {

+        "Default",

+        "Green",

+        "Yellow",

+        "Red"

+    };

+    C8_T egtag[AIR_ACL_ACT_EGTAG_LAST][11] =

+    {

+        "Default",

+        "Consistent",

+        "",

+        "",

+        "Untag",

+        "Swap",

+        "Tag",

+        "Stack"

+    };

+    C8_T str_temp[20];

+

+    memset(&act, 0, sizeof(AIR_ACL_ACTION_T));

+    if(2 < argc)

+    {

+        /* acl set action <idx(0..127)>

+        [ forward <forward(0:Default,4:Exclude CPU,5:Include CPU,6:CPU only,7:Drop)> ]

+        [ egtag <egtag(0:Default,1:Consistent,4:Untag,5:Swap,6:Tag,7:Stack)> ]

+        [ mirrormap <mirrormap(2'bin)> ]

+        [ priority <priority(0..7)> ]

+        [ redirect <redirect(0:Dst,1:Vlan)> <portmap(7'bin)> ]

+        [ leaky_vlan <leaky_vlan(1:En,0:Dis)> ]

+        [ cnt_idx <cnt_idx(0..63)> ]

+        [ rate_idx <rate_idx(0..31)> ]

+        [ attack_idx <attack_idx(0..95)> ]

+        [ vid <vid(0..4095)> ]

+        [ manage <manage(1:En,0:Dis)> ]

+        [ bpdu <bpdu(1:En,0:Dis)> ]

+        [ class <class(0:Original,1:Defined)>[0..7] ]

+        [ drop_pcd <drop_pcd(0:Original,1:Defined)> [red <red(0..7)>][yellow <yellow(0..7)>][green <green(0..7)>] ]

+        [ color <color(0:Defined,1:Trtcm)> [ <defined_color(0:Dis,1:Green,2:Yellow,3:Red)> | <trtcm_idx(0..31)> ] ]*/

+

+        act_idx = _strtoul(argv[argi++], NULL, 0);

+        if(0 == _strcmp(argv[argi], "forward"))

+        {

+            argi++;

+            fwd = _strtoul(argv[argi++], NULL, 0);

+            act.fwd_en = TRUE;

+            act.fwd = fwd;

+        }

+

+        if(0 == _strcmp(argv[argi], "egtag"))

+        {

+            argi++;

+            act.egtag_en = TRUE;

+            act.egtag = _strtoul(argv[argi++], NULL, 0);

+        }

+

+        if(0 == _strcmp(argv[argi], "mirrormap"))

+        {

+            argi++;

+            act.mirrormap = _strtoul(argv[argi++], NULL, 2);

+        }

+

+        if(0 == _strcmp(argv[argi], "priority"))

+        {

+            argi++;

+            act.pri_user_en = TRUE;

+            act.pri_user= _strtoul(argv[argi++], NULL, 0);

+        }

+

+        if(0 == _strcmp(argv[argi], "redirect"))

+        {

+            argi++;

+            redirect = _strtoul(argv[argi++], NULL, 0);

+            if(0 ==  redirect)

+            {

+                act.port_en = TRUE;

+                act.dest_port_sel = TRUE;

+                act.portmap = _strtoul(argv[argi++], NULL, 2);

+            }

+            else

+            {

+                act.port_en = TRUE;

+                act.vlan_port_sel = TRUE;

+                act.portmap = _strtoul(argv[argi++], NULL, 2);

+            }

+        }

+

+        if(0 == _strcmp(argv[argi], "leaky_vlan"))

+        {

+            argi++;

+            act.lyvlan_en = TRUE;

+            act.lyvlan = _strtoul(argv[argi++], NULL, 0);

+        }

+

+        /* ACL event counter */

+        if(0 == _strcmp(argv[argi], "cnt_idx"))

+        {

+            argi++;

+            act.cnt_en = TRUE;

+            act.cnt_idx = _strtol(argv[argi++], NULL, 0);

+        }

+

+        if(0 == _strcmp(argv[argi], "rate_idx"))

+        {

+            argi++;

+            act.rate_en = TRUE;

+            act.rate_idx = _strtol(argv[argi++], NULL, 0);

+        }

+

+        if(0 == _strcmp(argv[argi], "attack_idx"))

+        {

+            argi++;

+            act.attack_en = TRUE;

+            act.attack_idx = _strtol(argv[argi++], NULL, 0);

+        }

+

+        if(0 == _strcmp(argv[argi], "vid"))

+        {

+            argi++;

+            act.vlan_en = TRUE;

+            act.vlan_idx = _strtol(argv[argi++], NULL, 0);

+        }

+

+        /* Management frame */

+        if(0 == _strcmp(argv[argi], "manage"))

+        {

+            argi++;

+            act.mang = _strtoul(argv[argi++], NULL, 2);

+        }

+

+        if(0 == _strcmp(argv[argi], "bpdu"))

+        {

+            argi++;

+            act.bpdu = _strtoul(argv[argi++], NULL, 2);

+        }

+

+        /* DSCP class remap */

+        if(0 == _strcmp(argv[argi], "class"))

+        {

+            argi++;

+            act.trtcm_en = TRUE;

+            act.trtcm.cls_slr_sel = _strtoul(argv[argi++], NULL, 2);

+            if(TRUE == act.trtcm.cls_slr_sel)

+            {

+                act.trtcm.cls_slr = _strtoul(argv[argi++], NULL, 0);

+            }

+        }

+        if(0 == _strcmp(argv[argi], "drop_pcd"))

+        {

+            argi++;

+            act.trtcm_en = TRUE;

+            act.trtcm.drop_pcd_sel = _strtoul(argv[argi++], NULL, 2);

+            if(TRUE == act.trtcm.drop_pcd_sel)

+            {

+                if(0 == _strcmp(argv[argi], "red"))

+                {

+                    argi++;

+                    act.trtcm.drop_pcd_r= _strtoul(argv[argi++], NULL, 0);

+                }

+                if(0 == _strcmp(argv[argi], "yellow"))

+                {

+                    argi++;

+                    act.trtcm.drop_pcd_y= _strtoul(argv[argi++], NULL, 0);

+                }

+                if(0 == _strcmp(argv[argi], "green"))

+                {

+                    argi++;

+                    act.trtcm.drop_pcd_g= _strtoul(argv[argi++], NULL, 0);

+                }

+            }

+        }

+

+        /* trTCM */

+        if(0 == _strcmp(argv[argi], "color"))

+        {

+            argi++;

+            act.trtcm_en = TRUE;

+            act.trtcm.tcm_sel = _strtoul(argv[argi++], NULL, 2);

+            trtcm = _strtoul(argv[argi++], NULL, 0);

+            if(FALSE == act.trtcm.tcm_sel)

+            {

+                act.trtcm.usr_tcm = trtcm;

+            }

+            else

+            {

+                act.trtcm.tcm_idx = trtcm;

+            }

+        }

+        ret = air_acl_setAction(0, act_idx, act);

+        AIR_PRINT("Set ACL Action(%u): %s\n", act_idx, air_error_getString(ret));

+    }

+    else if(1 == argc)

+    {

+        /* acl get action <idx(0..127)> */

+        act_idx = _strtoul(argv[argi++], NULL, 0);

+        ret = air_acl_getAction(0, act_idx, &act);

+        AIR_PRINT("Get ACL Action(%u): %s\n", act_idx, air_error_getString(ret));

+    }

+    else

+    {

+        AIR_PRINT("Unrecognized command.\n");

+        return AIR_E_BAD_PARAMETER;

+    }

+

+    if(AIR_E_OK == ret)

+    {

+        if(TRUE == act.fwd_en)

+        {

+            AIR_PRINT("\t Forwarding           : %s\n", fwding[act.fwd]);

+        }

+

+        if(TRUE == act.egtag_en)

+        {

+            AIR_PRINT("\t Egress tag           : %s\n", egtag[act.egtag]);

+        }

+

+        if(act.mirrormap)

+        {

+            AIR_PRINT("\t Mirror Session Map   : %u\n", act.mirrormap);

+        }

+

+        if(TRUE == act.pri_user_en)

+        {

+            AIR_PRINT("\t User Priority        : %u\n", act.pri_user);

+        }

+

+        if(TRUE == act.port_en)

+        {

+            _hex2bitstr(act.portmap, str_temp, AIR_MAX_NUM_OF_PORTS+1);

+            if(TRUE == act.dest_port_sel)

+            {

+                AIR_PRINT("\t Destination Port[0:6]: %s\n", str_temp);

+            }

+            else

+            {

+                AIR_PRINT("\t VLAN Port[0:6]       : %s\n", str_temp);

+            }

+        }

+

+        if(TRUE == act.lyvlan_en)

+        {

+            AIR_PRINT("\t Leaky VLAN           : %s\n", (TRUE == act.lyvlan)?"Enable":"Disable");

+        }

+        AIR_PRINT("\t Management Frame     : %s\n", (TRUE == act.mang)?"Enable":"Disable");

+        AIR_PRINT("\t BPDU Frame           : %s\n", (TRUE == act.bpdu)?"Enable":"Disable");

+

+        if(TRUE == act.cnt_en)

+        {

+            AIR_PRINT("\t Event Index          : %u\n", act.cnt_idx);

+        }

+

+        /* trTCM*/

+        if(TRUE == act.trtcm_en)

+        {

+            if(TRUE == act.trtcm.cls_slr_sel)

+            {

+                AIR_PRINT("\t Class Selector Remap : %u\n", act.trtcm.cls_slr);

+            }

+            else

+            {

+                AIR_PRINT("\t Class Selector Remap : %s\n", "Disable");

+            }

+            if(TRUE == act.trtcm.drop_pcd_sel)

+            {

+                AIR_PRINT("\t Drop Precedence Remap(Red): %u\n", act.trtcm.drop_pcd_r);

+                AIR_PRINT("\t Drop Precedence Remap(Yel): %u\n", act.trtcm.drop_pcd_y);

+                AIR_PRINT("\t Drop Precedence Remap(Gre): %u\n", act.trtcm.drop_pcd_g);

+            }

+            else

+            {

+                AIR_PRINT("\t Drop Precedence Remap: %s\n", "Disable");

+            }

+

+            if(TRUE == act.trtcm.tcm_sel)

+            {

+                AIR_PRINT("\t trTCM Meter Index    : %u\n", act.trtcm.tcm_idx);

+            }

+            else

+            {

+                AIR_PRINT("\t trTCM User Defined   : %s\n", trtcm_usr[act.trtcm.usr_tcm]);

+            }

+        }

+        /* rate control */

+        if(TRUE == act.rate_en)

+        {

+            AIR_PRINT("\t Rate Control Index   : %u\n", act.rate_idx);

+        }

+

+        if(TRUE == act.attack_en)

+        {

+            AIR_PRINT("\t Attack Rate Control Index: %u\n", act.attack_idx);

+        }

+

+        if(TRUE == act.vlan_en)

+        {

+            AIR_PRINT("\t ACL VLAN Index       : %u\n", act.vlan_idx);

+        }

+    }

+

+    return ret;

+}

+

+static AIR_ERROR_NO_T

+doAclRmvAction(

+        UI32_T argc,

+        C8_T *argv[])

+{

+    AIR_ERROR_NO_T ret = AIR_E_OK;

+    UI32_T act_idx;

+

+    if(1 == argc)

+    {

+        /* acl del action <idx(0..127)> */

+        act_idx = _strtoul(argv[0], NULL, 0);

+        ret = air_acl_delAction(0, act_idx);

+        if(ret < AIR_E_LAST)

+            AIR_PRINT("Delete ACL Action(%u): %s\n", act_idx, air_error_getString(ret));

+    }

+    else if(0 == argc)

+    {

+        /* acl clear action */

+        ret = air_acl_clearAction(0);

+        if(ret < AIR_E_LAST)

+            AIR_PRINT("Clear ACL Action: %s\n", air_error_getString(ret));

+    }

+    else

+    {

+        AIR_PRINT("Unrecognized command.\n");

+        return AIR_E_BAD_PARAMETER;

+    }

+

+    return ret;

+}

+

+static AIR_ERROR_NO_T

+doAclTrtcm(

+    UI32_T argc,

+    C8_T *argv[])

+{

+    AIR_ERROR_NO_T ret = AIR_E_OK;

+    UI32_T argi = 0;

+    UI32_T tcm_idx;

+    AIR_ACL_TRTCM_T tcm;

+

+    memset(&tcm, 0, sizeof(AIR_ACL_TRTCM_T));

+    if(5 == argc)

+    {

+        /* acl set trtcm <idx(0..31)> <cir(4'hex)> <pir(4'hex)> <cbs(4'hex)> <pbs(4'hex)> */

+        tcm_idx = _strtoul(argv[argi++], NULL, 0);

+        tcm.cir = _strtoul(argv[argi++], NULL, 16);

+        tcm.pir = _strtoul(argv[argi++], NULL, 16);

+        tcm.cbs = _strtoul(argv[argi++], NULL, 16);

+        tcm.pbs = _strtoul(argv[argi++], NULL, 16);

+

+        ret = air_acl_setTrtcm(0, tcm_idx, tcm);

+        if(ret < AIR_E_LAST)

+            AIR_PRINT("Set ACL trTCM(%u): %s\n", tcm_idx, air_error_getString(ret));

+    }

+    else if(1 == argc)

+    {

+        /* acl get trtcm <idx(1..31)> */

+        tcm_idx = _strtoul(argv[argi++], NULL, 0);

+        ret = air_acl_getTrtcm(0, tcm_idx, &tcm);

+        if(ret < AIR_E_LAST)

+            AIR_PRINT("Get ACL trTCM(%u): %s\n", tcm_idx, air_error_getString(ret));

+    }

+    else

+    {

+        AIR_PRINT("Unrecognized command.\n");

+        return AIR_E_BAD_PARAMETER;

+    }

+

+    if(AIR_E_OK == ret)

+    {

+        AIR_PRINT("\t CIR: 0x%04X(unit:64Kbps)\n", tcm.cir);

+        AIR_PRINT("\t PIR: 0x%04X(unit:64Kbps)\n", tcm.pir);

+        AIR_PRINT("\t CBS: 0x%04X(unit:Byte)\n", tcm.cbs);

+        AIR_PRINT("\t PBS: 0x%04X(unit:Byte)\n", tcm.pbs);

+    }

+

+    return ret;

+}

+

+static AIR_ERROR_NO_T

+doAclTrtcmEn(

+    UI32_T argc,

+    C8_T *argv[])

+{

+    AIR_ERROR_NO_T ret = AIR_E_OK;

+    BOOL_T state = FALSE;

+

+    if (1 == argc)

+    {

+        /* acl set trtcmEn <en(1:En,0:Dis)> */

+        state = _strtol(argv[0], NULL, 10);

+        ret = air_acl_setTrtcmEnable(0, state);

+        AIR_PRINT("Set trTCM State ");

+    }

+    else if (0 == argc)

+    {

+        /* acl get trtcmEn */

+        ret = air_acl_getTrtcmEnable(0, &state);

+        AIR_PRINT("Get trTCM State ");

+    }

+    else

+    {

+        AIR_PRINT("Unrecognized command.\n");

+        return AIR_E_BAD_PARAMETER;

+    }

+

+    if (ret == AIR_E_OK)

+    {

+        AIR_PRINT(": %s\n", (TRUE == state) ? "Enable" : "Disable");

+    }

+    else

+    {

+        AIR_PRINT("Fail!\n");

+    }

+

+    return ret;

+}

+

+static AIR_ERROR_NO_T

+doAclRmvTrtcm(

+        UI32_T argc,

+        C8_T *argv[])

+{

+    AIR_ERROR_NO_T ret = AIR_E_OK;

+    UI32_T tcm_idx;

+

+    if(1 == argc)

+    {

+        /* acl del trtcm <idx(1..31)> */

+        tcm_idx = _strtoul(argv[0], NULL, 0);

+        ret = air_acl_delTrtcm(0, tcm_idx);

+        if(ret < AIR_E_LAST)

+            AIR_PRINT("Delete ACL TRTCM(%u): %s\n", tcm_idx, air_error_getString(ret));

+    }

+    else if(0 == argc)

+    {

+        /* acl clear trtcm */

+        ret = air_acl_clearTrtcm(0);

+        if(ret < AIR_E_LAST)

+            AIR_PRINT("Clear ACL TRTCM: %s\n", air_error_getString(ret));

+    }

+    else

+    {

+        AIR_PRINT("Unrecognized command.\n");

+        return AIR_E_BAD_PARAMETER;

+    }

+

+    return ret;

+}

+

+static AIR_ERROR_NO_T

+doAclPortEn(

+    UI32_T argc,

+    C8_T *argv[])

+{

+    AIR_ERROR_NO_T ret = AIR_E_OK;

+    UI32_T argi=0;

+    UI32_T port = 0;

+    BOOL_T en;

+

+    if(2 == argc)

+    {

+        /* acl set portEn <port(0..6)> <en(1:En,0:Dis)> */

+        port = _strtoul(argv[argi++], NULL, 0);

+        en = _strtoul(argv[argi++], NULL, 2);

+        ret = air_acl_setPortEnable(0, port, en);

+        AIR_PRINT("Set Port:%u ACL function ", port);

+    }

+    else if(1 == argc)

+    {

+        /* acl get portEn <port(0..6)> */

+        port = _strtoul(argv[argi++], NULL, 0);

+        ret = air_acl_getPortEnable(0, port, &en);

+        AIR_PRINT("Get Port:%u ACL function ", port);

+    }

+    else

+    {

+        AIR_PRINT("Unrecognized command.\n");

+        return AIR_E_BAD_PARAMETER;

+    }

+

+    if(ret == AIR_E_OK)

+    {

+        AIR_PRINT(": %s\n", (TRUE == en)?"Enable":"Disable");

+    }

+    else

+    {

+        AIR_PRINT("Fail!\n");

+    }

+

+    return ret;

+}

+

+static AIR_ERROR_NO_T

+doAclDropEn(

+    UI32_T argc,

+    C8_T *argv[])

+{

+    AIR_ERROR_NO_T ret = AIR_E_OK;

+    UI32_T argi=0;

+    UI32_T port = 0;

+    BOOL_T en;

+

+    if(2 == argc)

+    {

+        /* acl set dropEn <port(0..6)> <en(1:En,0:Dis)> */

+        port = _strtoul(argv[argi++], NULL, 0);

+        en = _strtoul(argv[argi++], NULL, 2);

+        ret = air_acl_setDropEnable(0, port, en);

+        AIR_PRINT("Set ACL Drop precedence ");

+    }

+    else if(1 == argc)

+    {

+        /* acl set dropEn <port(0..6)> */

+        port = _strtoul(argv[argi++], NULL, 0);

+        ret = air_acl_getDropEnable(0, port, &en);

+        AIR_PRINT("Get ACL Drop precedence ");

+    }

+    else

+    {

+        AIR_PRINT("Unrecognized command.\n");

+        return AIR_E_BAD_PARAMETER;

+    }

+

+    if(ret == AIR_E_OK)

+    {

+        AIR_PRINT("(Port %u):%s\n",

+                port,

+                (TRUE == en)?"Enable":"Disable");

+    }

+    else

+    {

+        AIR_PRINT("Fail!\n");

+    }

+

+    return ret;

+}

+

+static AIR_ERROR_NO_T

+doAclDropThrsh(

+    UI32_T argc,

+    C8_T *argv[])

+{

+    AIR_ERROR_NO_T ret = AIR_E_OK;

+    UI32_T argi=0;

+    UI32_T port = 0;

+    AIR_ACL_DP_COLOR_T color;

+    UI8_T queue;

+    UI32_T high, low;

+    C8_T dp_color[AIR_ACL_DP_COLOR_LAST][7] =

+    {

+        "Green",

+        "Yellow",

+        "Red"

+    };

+

+    if(5 == argc)

+    {

+        /* acl set dropThrsh <port(0..6)> <color(0:green,1:yellow,2:red)> <queue(0..7)> <high(0..2047)> <low(0..2047) */

+        port = _strtoul(argv[argi++], NULL, 0);

+        color = _strtoul(argv[argi++], NULL, 0);

+        queue = _strtoul(argv[argi++], NULL, 0);

+        high = _strtoul(argv[argi++], NULL, 0);

+        low = _strtoul(argv[argi++], NULL, 0);

+        ret = air_acl_setDropThreshold(0, port, color, queue, high, low);

+        AIR_PRINT("Set ACL Drop precedence ");

+    }

+    else if(3 == argc)

+    {

+        /* acl get dropThrsh <port(0..6)> <color(0:green,1:yellow,2:red)> <queue(0..7)> */

+        port = _strtoul(argv[argi++], NULL, 0);

+        color = _strtoul(argv[argi++], NULL, 0);

+        queue = _strtoul(argv[argi++], NULL, 0);

+        ret = air_acl_getDropThreshold(0, port, color, queue, &high, &low);

+        AIR_PRINT("Get ACL Drop precedence ");

+    }

+    else

+    {

+        AIR_PRINT("Unrecognized command.\n");

+        return AIR_E_BAD_PARAMETER;

+    }

+

+    if(ret == AIR_E_OK)

+    {

+        AIR_PRINT("(Port %u, color:%s, queue:%u):\n",

+                port,

+                dp_color[color],

+                queue);

+        AIR_PRINT("\tHigh Threshold :%u\n", high);

+        AIR_PRINT("\tLow Threshold  :%u\n", low);

+    }

+    else

+    {

+        AIR_PRINT("Fail!\n");

+    }

+

+    return ret;

+}

+

+static AIR_ERROR_NO_T

+doAclDropPbb(

+    UI32_T argc,

+    C8_T *argv[])

+{

+    AIR_ERROR_NO_T ret = AIR_E_OK;

+    UI32_T argi=0;

+    UI32_T port = 0;

+    AIR_ACL_DP_COLOR_T color;

+    UI8_T queue;

+    UI32_T pbb;

+    C8_T dp_color[AIR_ACL_DP_COLOR_LAST][7] =

+    {

+        "Green",

+        "Yellow",

+        "Red"

+    };

+

+    if(4 == argc)

+    {

+        /* acl set dropPbb <port(0..6)> <color(0:green,1:yellow,2:red)> <queue(0..7)> <probability(0..1023) */

+        port = _strtoul(argv[argi++], NULL, 0);

+        color = _strtoul(argv[argi++], NULL, 0);

+        queue = _strtoul(argv[argi++], NULL, 0);

+        pbb = _strtoul(argv[argi++], NULL, 0);

+        ret = air_acl_setDropProbability(0, port, color, queue, pbb);

+        AIR_PRINT("Set ACL Drop precedence ");

+    }

+    else if(3 == argc)

+    {

+        /* acl get dropPbb <port(0..6)> <color(0:green,1:yellow,2:red)> <queue(0..7)> */

+        port = _strtoul(argv[argi++], NULL, 0);

+        color = _strtoul(argv[argi++], NULL, 0);

+        queue = _strtoul(argv[argi++], NULL, 0);

+        ret = air_acl_getDropProbability(0, port, color, queue, &pbb);

+        AIR_PRINT("Get ACL Drop precedence ");

+    }

+    else

+    {

+        AIR_PRINT("Unrecognized command.\n");

+        return AIR_E_BAD_PARAMETER;

+    }

+

+    if(ret == AIR_E_OK)

+    {

+        AIR_PRINT("(Port %u, color:%s, queue %u):\n",

+                port,

+                dp_color[color],

+                queue);

+        AIR_PRINT("\tDrop probability:%u(unit=1/1023)\n", pbb);

+    }

+    else

+    {

+        AIR_PRINT("Fail!\n");

+    }

+

+    return ret;

+}

+

+static AIR_ERROR_NO_T

+doAclMeter(

+    UI32_T argc,

+    C8_T *argv[])

+{

+    AIR_ERROR_NO_T ret = AIR_E_OK;

+    UI32_T argi = 0;

+    UI32_T meter_idx, state, rate;

+

+    if(3 == argc)

+    {

+        /* acl set meter <idx(0..31)> <en(1:En,0:Dis)> <rate(0..65535)>

+           Note: Limit rate = rate * 64Kbps */

+        meter_idx = _strtoul(argv[argi++], NULL, 0);

+        state = _strtoul(argv[argi++], NULL, 2);

+        rate = _strtoul(argv[argi++], NULL, 0);

+

+        ret = air_acl_setMeterTable(0, meter_idx, state, rate);

+        if(ret < AIR_E_LAST)

+            AIR_PRINT("Set ACL Meter(%u): %s\n", meter_idx, air_error_getString(ret));

+    }

+    else if(1 == argc)

+    {

+        /* acl get meter <idx(0..31)> */

+        meter_idx = _strtoul(argv[argi++], NULL, 0);

+        ret = air_acl_getMeterTable(0, meter_idx, &state, &rate);

+        if(ret < AIR_E_LAST)

+            AIR_PRINT("Get ACL Meter(%u): %s\n", meter_idx, air_error_getString(ret));

+    }

+    else

+    {

+        AIR_PRINT("Unrecognized command.\n");

+        return AIR_E_BAD_PARAMETER;

+    }

+

+    if(AIR_E_OK == ret)

+    {

+        AIR_PRINT("\t State: %s\n", (TRUE == state)?"Enable":"Disable");

+        if(TRUE == state)

+        {

+            AIR_PRINT("\t Rate : %u(unit:64Kbps)\n", rate);

+        }

+    }

+

+    return ret;

+}

+

+static AIR_ERROR_NO_T

+doAclDump(

+    UI32_T argc,

+    C8_T *argv[])

+{

+    AIR_ERROR_NO_T ret = AIR_E_OK;

+    UI32_T i, cnt = 0;

+    AIR_ACL_CTRL_T ctrl;

+

+    if(0 != argc)

+    {

+        AIR_PRINT("Unrecognized command.\n");

+        return AIR_E_BAD_PARAMETER;

+    }

+

+    for(i=0; i<ACL_MAX_RULE_NUM; i++)

+    {

+        memset(&ctrl, 0, sizeof(AIR_ACL_CTRL_T));

+        ret = air_acl_getRuleCtrl(0, i, &ctrl);

+        if(AIR_E_OK == ret)

+        {

+            if(TRUE == ctrl.rule_en)

+            {

+                cnt++;

+                AIR_PRINT("\t Entry-%d vaild\n", i);

+            }

+        }

+    }

+    if(0 == cnt)

+    {

+        AIR_PRINT("\t No entry vaild\n");

+    }

+

+    return ret;

+}

+

+static AIR_ERROR_NO_T

+doAclSet(

+        UI32_T argc,

+        C8_T *argv[])

+{

+    return subcmd(aclSetCmds, argc, argv);

+}

+

+static AIR_ERROR_NO_T

+doAclGet(

+        UI32_T argc,

+        C8_T *argv[])

+{

+    return subcmd(aclGetCmds, argc, argv);

+}

+

+static AIR_ERROR_NO_T

+doAclDel(

+        UI32_T argc,

+        C8_T *argv[])

+{

+    return subcmd(aclDelCmds, argc, argv);

+}

+

+static AIR_ERROR_NO_T

+doAclClear(

+        UI32_T argc,

+        C8_T *argv[])

+{

+    return subcmd(aclClearCmds, argc, argv);

+}

+

+static AIR_ERROR_NO_T

+doAcl(

+        UI32_T argc,

+        C8_T *argv[])

+{

+    return subcmd(aclCmds, argc, argv);

+}

+

+static AIR_ERROR_NO_T

+subcmd(

+        const AIR_CMD_T tab[],

+        UI32_T argc,

+        C8_T *argv[])

+{

+    const AIR_CMD_T *cmdp;

+    I32_T found = 0;

+    I32_T i, len;

+

+    if (argc < 1)

+    {

+        goto print_out_cmds;

+    }

+

+    for (cmdp = tab; cmdp->name != NULL; cmdp++)

+    {

+        if (strlen(argv[0]) == strlen(cmdp->name))

+        {

+            if (strncmp(argv[0], cmdp->name, strlen(argv[0])) == 0)

+            {

+                found = 1;

+                break;

+            }

+        }

+    }

+

+    if(!found)

+    {

+        C8_T buf[66];

+

+print_out_cmds:

+        AIR_PRINT("valid subcommands:\n");

+        memset(buf, ' ', sizeof(buf));

+        buf[64] = '\n';

+        buf[65] = '\0';

+

+        for (i=0, cmdp = tab; cmdp->name != NULL; cmdp++)

+        {

+            len = strlen(cmdp->name);

+            strncpy(&buf[i*16], cmdp->name, (len > 16) ? 16 : len);

+            if(3 == i)

+            {

+                AIR_PRINT("%s\n", buf);

+                memset(buf, ' ', sizeof(buf));

+                buf[64] = '\n';

+                buf[65] = '\0';

+            }

+            i = (i + 1) % 4;

+        }

+

+        if (0 != i)

+            AIR_PRINT("%s\n", buf);

+

+        return AIR_E_BAD_PARAMETER;

+    }

+

+    if (CMD_NO_PARA == cmdp->argc_min)

+    {

+        if (argc != 1)

+        {

+            if (cmdp->argc_errmsg != NULL)

+            {

+                AIR_PRINT("Usage: %s\n", cmdp->argc_errmsg);

+            }

+

+            return AIR_E_BAD_PARAMETER;

+        }

+    }

+    else if (CMD_VARIABLE_PARA == cmdp->argc_min)

+    {

+        if (argc < 3)

+        {

+            if (cmdp->argc_errmsg != NULL)

+            {

+                AIR_PRINT("Usage: %s\n", cmdp->argc_errmsg);

+            }

+

+            return AIR_E_BAD_PARAMETER;

+        }

+    }

+    else

+    {

+        if ((argc <= cmdp->argc_min) || ((cmdp->argc_min != 0) && (argc != (cmdp->argc_min + 1))))

+        {

+            if (cmdp->argc_errmsg != NULL)

+            {

+                AIR_PRINT("Usage: %s\n", cmdp->argc_errmsg);

+            }

+

+            return AIR_E_BAD_PARAMETER;

+        }

+    }

+

+    if (cmdp->func)

+    {

+        argc--;

+        argv++;

+        return (*cmdp->func)(argc, argv);

+    }

+    return AIR_E_OK;

+}

+

+/* FUNCTION NAME:   air_parse_cmd

+ * PURPOSE:

+ *      This function is used process diagnostic cmd

+ * INPUT:

+ *      argc         -- parameter number

+ *      argv         -- parameter strings

+ * OUTPUT:

+ *      None

+ * RETURN:

+ *      NPS_E_OK     -- Successfully read the data.

+ *      NPS_E_OTHERS -- Failed to read the data.

+ * NOTES:

+ *

+ */

+AIR_ERROR_NO_T

+air_parse_cmd(

+        const UI32_T argc,

+        const C8_T **argv)

+{

+    return subcmd(Cmds, argc, (C8_T **)argv);

+}

+

diff --git a/recipes-devtools/switch/files/src/an8855_sdk/api/src/air_diag.c b/recipes-devtools/switch/files/src/an8855_sdk/api/src/air_diag.c
new file mode 100644
index 0000000..2f89ddf
--- /dev/null
+++ b/recipes-devtools/switch/files/src/an8855_sdk/api/src/air_diag.c
@@ -0,0 +1,410 @@
+/* FILE NAME: air_diag.c
+ * PURPOSE:
+ *      Define the diagnostic function in AIR SDK.
+ * NOTES:
+ *      None
+ */
+
+/* INCLUDE FILE DECLARATIONS
+*/
+#include "air.h"
+
+/* NAMING CONSTANT DECLARATIONS
+*/
+
+/* MACRO FUNCTION DECLARATIONS
+*/
+
+/* DATA TYPE DECLARATIONS
+*/
+
+/* GLOBAL VARIABLE DECLARATIONS
+*/
+
+/* LOCAL SUBPROGRAM DECLARATIONS
+*/
+
+/* STATIC VARIABLE DECLARATIONS
+*/
+
+/* LOCAL SUBPROGRAM BODIES
+*/
+
+/* EXPORTED SUBPROGRAM BODIES
+*/
+
+/* FUNCTION NAME: air_diag_setTxComplyMode
+ * PURPOSE:
+ *      Set Ethernet TX Compliance mode.
+ *
+ * INPUT:
+ *      unit            --  Device ID
+ *      port            --  Index of port number
+ *      mode            --  Testing mode of Ethernet TX Compliance
+ *
+ * OUTPUT:
+ *      None
+ *
+ * RETURN:
+ *      AIR_E_OK
+ *      AIR_E_BAD_PARAMETER
+ *
+ * NOTES:
+ */
+AIR_ERROR_NO_T
+air_diag_setTxComplyMode(
+    const UI32_T unit,
+    const UI8_T port,
+    const AIR_DIAG_TXCOMPLY_MODE_T mode)
+{
+    UI32_T page = 0;
+    UI32_T u32dat = 0;
+
+    /* Mistake proofing */
+    AIR_PARAM_CHK((port >= AIR_MAX_NUM_OF_GIGA_PORTS), AIR_E_BAD_PARAMETER);
+    AIR_PARAM_CHK((mode >= AIR_DIAG_TXCOMPLY_MODE_LAST), AIR_E_BAD_PARAMETER);
+
+    /* Backup page of CL22 */
+    aml_readPhyReg(unit, port, PHY_PAGE, &page);
+
+    switch(mode)
+    {
+        case AIR_DIAG_TXCOMPLY_MODE_10M_NLP:
+            /* PHY 00h = 0x0100 */
+            aml_writePhyReg(unit, port, PHY_PAGE, PHY_PAGE_0);
+            aml_writePhyReg(unit, port, PHY_MCR, MCR_MR_DUX);
+            /* PHY dev 1Eh reg 145h = 0x5010 */
+            u32dat = (FC_TDI_EN | FC_LITN_NO_COMP | FC_MDI_CO_MDI);
+            aml_writePhyRegCL45(unit, port, 0x1e, 0x0145, u32dat);
+            /* PHY dev 1Fh reg 17Bh = 0x1177 */
+            u32dat = (CR_RG_TX_CM_10M(1) | CR_RG_DELAY_TX_10M(1) \
+                    | CR_DA_TX_GAIN_10M_EEE(100) | CR_DA_TX_GAIN_10M(100));
+            aml_writePhyRegCL45(unit, port, 0x1f, 0x027b, u32dat);
+            break;
+        case AIR_DIAG_TXCOMPLY_MODE_10M_RANDOM:
+            /* PHY 00h = 0x0100 */
+            aml_writePhyReg(unit, port, PHY_PAGE, PHY_PAGE_0);
+            aml_writePhyReg(unit, port, PHY_MCR, MCR_MR_DUX);
+            /* PHY dev 1Eh reg 145h = 0x5010 */
+            u32dat = (FC_TDI_EN | FC_LITN_NO_COMP | FC_MDI_CO_MDI);
+            aml_writePhyRegCL45(unit, port, 0x1e, 0x0145, u32dat);
+            /* PHY dev 1Fh reg 27Bh = 0x1177 */
+            u32dat = (CR_RG_TX_CM_10M(1) | CR_RG_DELAY_TX_10M(1) \
+                    | CR_DA_TX_GAIN_10M_EEE(100) | CR_DA_TX_GAIN_10M(100));
+            aml_writePhyRegCL45(unit, port, 0x1f, 0x027b, u32dat);
+            /* PHY 11dh = 0xf842 */
+            aml_writePhyReg(unit, port, PHY_PAGE, PHY_PAGE_1);
+            u32dat = (EPG_EN | EPG_RUN | EPG_TX_DUR | EPG_PKT_LEN_10KB \
+                    | EPG_DES_ADDR(1) | EPG_PL_TYP_RANDOM);
+            aml_writePhyReg(unit, port, PHY_EPG, u32dat);
+            break;
+        case AIR_DIAG_TXCOMPLY_MODE_10M_SINE:
+            /* PHY 00h = 0x0100 */
+            aml_writePhyReg(unit, port, PHY_PAGE, PHY_PAGE_0);
+            aml_writePhyReg(unit, port, PHY_MCR, MCR_MR_DUX);
+            /* PHY dev 1Eh reg 145h = 0x5010 */
+            u32dat = (FC_TDI_EN | FC_LITN_NO_COMP | FC_MDI_CO_MDI);
+            aml_writePhyRegCL45(unit, port, 0x1e, 0x0145, u32dat);
+            /* PHY dev 1Fh reg 27Bh = 0x1177 */
+            u32dat = (CR_RG_TX_CM_10M(1) | CR_RG_DELAY_TX_10M(1) \
+                    | CR_DA_TX_GAIN_10M_EEE(100) | CR_DA_TX_GAIN_10M(100));
+            aml_writePhyRegCL45(unit, port, 0x1f, 0x027b, u32dat);
+            /* PHY dev 1Eh reg 1A3h = 0x0000 */
+            aml_writePhyRegCL45(unit, port, 0x1e, 0x01a3, 0x0000);
+            /* PHY dev 1Eh reg 1A4h = 0x0000 */
+            aml_writePhyRegCL45(unit, port, 0x1e, 0x01a4, 0x0000);
+            /* PHY 11dh = 0xf840 */
+            aml_writePhyReg(unit, port, PHY_PAGE, PHY_PAGE_1);
+            u32dat = (EPG_EN | EPG_RUN | EPG_TX_DUR \
+                    | EPG_PKT_LEN_10KB | EPG_DES_ADDR(1));
+            aml_writePhyReg(unit, port, PHY_EPG, u32dat);
+            break;
+        case AIR_DIAG_TXCOMPLY_MODE_100M_PAIR_A:
+            /* PHY 00h = 0x2100 */
+            aml_writePhyReg(unit, port, PHY_PAGE, PHY_PAGE_0);
+            u32dat = (MCR_MR_FC_SPD_INT_0 | MCR_MR_DUX);
+            aml_writePhyReg(unit, port, PHY_MCR, u32dat);
+            /* PHY dev 1Eh reg 145h = 0x5010 */
+            u32dat = (FC_TDI_EN | FC_LITN_NO_COMP | FC_MDI_CO_MDI);
+            aml_writePhyRegCL45(unit, port, 0x1e, 0x0145, u32dat);
+            break;
+        case AIR_DIAG_TXCOMPLY_MODE_100M_PAIR_B:
+            /* PHY 00h = 0x2100 */
+            aml_writePhyReg(unit, port, PHY_PAGE, PHY_PAGE_0);
+            u32dat = (MCR_MR_FC_SPD_INT_0 | MCR_MR_DUX);
+            aml_writePhyReg(unit, port, PHY_MCR, u32dat);
+            /* PHY dev 1Eh reg 145h = 0x5018 */
+            u32dat = (FC_TDI_EN | FC_LITN_NO_COMP | FC_MDI_CO_MDIX);
+            aml_writePhyRegCL45(unit, port, 0x1e, 0x0145, u32dat);
+            break;
+        case AIR_DIAG_TXCOMPLY_MODE_1000M_TM1:
+            /* PHY 09h = 0x2700 */
+            aml_writePhyReg(unit, port, PHY_PAGE, PHY_PAGE_0);
+            u32dat = (CR1G_TEST_TM1 | CR1G_PORT_TYPE \
+                    | CR1G_ADV_CAP1000_FDX | CR1G_ADV_CAP1000_HDX);
+            aml_writePhyReg(unit, port, PHY_CR1G, u32dat);
+            break;
+        case AIR_DIAG_TXCOMPLY_MODE_1000M_TM2:
+            aml_writePhyReg(unit, port, PHY_PAGE, PHY_PAGE_0);
+            /* PHY 09h = 0x4700 */
+            u32dat = (CR1G_TEST_TM2 | CR1G_PORT_TYPE \
+                    | CR1G_ADV_CAP1000_FDX | CR1G_ADV_CAP1000_HDX);
+            aml_writePhyReg(unit, port, PHY_CR1G, u32dat);
+            break;
+        case AIR_DIAG_TXCOMPLY_MODE_1000M_TM3:
+            aml_writePhyReg(unit, port, PHY_PAGE, PHY_PAGE_0);
+            /* PHY 09h = 0x6700 */
+            u32dat = (CR1G_TEST_TM3 | CR1G_PORT_TYPE \
+                    | CR1G_ADV_CAP1000_FDX | CR1G_ADV_CAP1000_HDX);
+            aml_writePhyReg(unit, port, PHY_CR1G, u32dat);
+            break;
+        case AIR_DIAG_TXCOMPLY_MODE_1000M_TM4:
+            aml_writePhyReg(unit, port, PHY_PAGE, PHY_PAGE_0);
+            /* PHY 09h = 0x8700 */
+            u32dat = (CR1G_TEST_TM4 | CR1G_PORT_TYPE \
+                    | CR1G_ADV_CAP1000_FDX | CR1G_ADV_CAP1000_HDX);
+            aml_writePhyReg(unit, port, PHY_CR1G, u32dat);
+            break;
+        default:
+            /* Unrecognized argument */
+            return AIR_E_BAD_PARAMETER;
+    }
+    /* Restore page of CL22 */
+    aml_writePhyReg(unit, port, PHY_PAGE, page);
+
+    return AIR_E_OK;
+}
+
+/* FUNCTION NAME: air_diag_getTxComplyMode
+ * PURPOSE:
+ *      Get Ethernet TX Compliance mode.
+ *
+ * INPUT:
+ *      unit            --  Device ID
+ *      port            --  Index of port number
+ *
+ * OUTPUT:
+ *      ptr_mode        --  Testing mode of Ethernet TX Compliance
+ *
+ * RETURN:
+ *      AIR_E_OK
+ *      AIR_E_BAD_PARAMETER
+ *      AIR_E_OTHERS
+ *
+ * NOTES:
+ */
+AIR_ERROR_NO_T
+air_diag_getTxComplyMode(
+    const UI32_T unit,
+    const UI8_T port,
+    AIR_DIAG_TXCOMPLY_MODE_T *ptr_mode)
+{
+    UI32_T page = 0;
+    UI32_T curReg[4] = {0};
+    UI32_T cmpReg[4] = {0};
+    BOOL_T hit = FALSE;
+
+    /* Mistake proofing */
+    AIR_PARAM_CHK((port >= AIR_MAX_NUM_OF_GIGA_PORTS), AIR_E_BAD_PARAMETER);
+    AIR_CHECK_PTR(ptr_mode);
+
+    /* Backup page of CL22 */
+    aml_readPhyReg(unit, port, PHY_PAGE, &page);
+
+    /* Test for AIR_DIAG_TXCOMPLY_MODE_1000M_TM1 */
+    if( FALSE == hit )
+    {
+        aml_writePhyReg(unit, port, PHY_PAGE, PHY_PAGE_0);
+        aml_readPhyReg(unit, port, PHY_CR1G, &curReg[0]);
+        cmpReg[0] = (CR1G_TEST_TM1 | CR1G_PORT_TYPE | CR1G_ADV_CAP1000_FDX | CR1G_ADV_CAP1000_HDX);
+
+        if( cmpReg[0] == curReg[0] )
+        {
+            (*ptr_mode) = AIR_DIAG_TXCOMPLY_MODE_1000M_TM1;
+            hit = TRUE;
+        }
+    }
+
+    /* Test for AIR_DIAG_TXCOMPLY_MODE_1000M_TM2 */
+    if( FALSE == hit )
+    {
+        aml_writePhyReg(unit, port, PHY_PAGE, PHY_PAGE_0);
+        aml_readPhyReg(unit, port, PHY_CR1G, &curReg[0]);
+        cmpReg[0] = (CR1G_TEST_TM2 | CR1G_PORT_TYPE | CR1G_ADV_CAP1000_FDX | CR1G_ADV_CAP1000_HDX);
+
+        if( cmpReg[0] == curReg[0] )
+        {
+            (*ptr_mode) = AIR_DIAG_TXCOMPLY_MODE_1000M_TM2;
+            hit = TRUE;
+        }
+    }
+
+    /* Test for AIR_DIAG_TXCOMPLY_MODE_1000M_TM3 */
+    if( FALSE == hit )
+    {
+        aml_writePhyReg(unit, port, PHY_PAGE, PHY_PAGE_0);
+        aml_readPhyReg(unit, port, PHY_CR1G, &curReg[0]);
+        cmpReg[0] = (CR1G_TEST_TM3 | CR1G_PORT_TYPE | CR1G_ADV_CAP1000_FDX | CR1G_ADV_CAP1000_HDX);
+
+        if( cmpReg[0] == curReg[0] )
+        {
+            (*ptr_mode) = AIR_DIAG_TXCOMPLY_MODE_1000M_TM3;
+            hit = TRUE;
+        }
+    }
+
+    /* Test for AIR_DIAG_TXCOMPLY_MODE_1000M_TM4 */
+    if( FALSE == hit )
+    {
+        aml_writePhyReg(unit, port, PHY_PAGE, PHY_PAGE_0);
+        aml_readPhyReg(unit, port, PHY_CR1G, &curReg[0]);
+        cmpReg[0] = (CR1G_TEST_TM4 | CR1G_PORT_TYPE | CR1G_ADV_CAP1000_FDX | CR1G_ADV_CAP1000_HDX);
+
+        if( cmpReg[0] == curReg[0] )
+        {
+            (*ptr_mode) = AIR_DIAG_TXCOMPLY_MODE_1000M_TM4;
+            hit = TRUE;
+        }
+    }
+
+    /* Test for AIR_DIAG_TXCOMPLY_MODE_100M_PAIR_A */
+    if( FALSE == hit )
+    {
+        aml_writePhyReg(unit, port, PHY_PAGE, PHY_PAGE_0);
+        aml_readPhyReg(unit, port, PHY_MCR, &curReg[0]);
+        cmpReg[0] = (MCR_MR_FC_SPD_INT_0 | MCR_MR_DUX);
+
+        aml_readPhyRegCL45(unit, port, 0x1e, 0x0145, &curReg[1]);
+        cmpReg[1] = (FC_TDI_EN | FC_LITN_NO_COMP | FC_MDI_CO_MDI);
+
+        if( (cmpReg[0] == curReg[0]) && (cmpReg[1] == curReg[1]) )
+        {
+            (*ptr_mode) = AIR_DIAG_TXCOMPLY_MODE_100M_PAIR_A;
+            hit = TRUE;
+        }
+    }
+
+    /* Test for AIR_DIAG_TXCOMPLY_MODE_100M_PAIR_B */
+    if( FALSE == hit )
+    {
+        aml_writePhyReg(unit, port, PHY_PAGE, PHY_PAGE_0);
+        aml_readPhyReg(unit, port, PHY_MCR, &curReg[0]);
+        cmpReg[0] = (MCR_MR_FC_SPD_INT_0 | MCR_MR_DUX);
+
+        aml_readPhyRegCL45(unit, port, 0x1e, 0x0145, &curReg[1]);
+        cmpReg[1] = (FC_TDI_EN | FC_LITN_NO_COMP | FC_MDI_CO_MDIX);
+
+        if( (cmpReg[0] == curReg[0]) && (cmpReg[1] == curReg[1]) )
+        {
+            (*ptr_mode) = AIR_DIAG_TXCOMPLY_MODE_100M_PAIR_B;
+            hit = TRUE;
+        }
+    }
+
+    /* Test for AIR_DIAG_TXCOMPLY_MODE_10M_SINE */
+    if( FALSE == hit )
+    {
+        aml_writePhyReg(unit, port, PHY_PAGE, PHY_PAGE_0);
+        aml_readPhyReg(unit, port, PHY_MCR, &curReg[0]);
+        cmpReg[0] = MCR_MR_DUX;
+
+        aml_readPhyRegCL45(unit, port, 0x1e, 0x0145, &curReg[1]);
+        cmpReg[1] = (FC_TDI_EN | FC_LITN_NO_COMP | FC_MDI_CO_MDI);
+
+        aml_readPhyRegCL45(unit, port, 0x1f, 0x027b, &curReg[2]);
+        cmpReg[2] = (CR_RG_TX_CM_10M(1) \
+                | CR_RG_DELAY_TX_10M(1) \
+                | CR_DA_TX_GAIN_10M_EEE(100) \
+                | CR_DA_TX_GAIN_10M(100));
+
+        aml_writePhyReg(unit, port, PHY_PAGE, PHY_PAGE_1);
+        aml_readPhyReg(unit, port, PHY_EPG, &curReg[3]);
+        cmpReg[3] = (EPG_EN \
+                | EPG_RUN \
+                | EPG_TX_DUR \
+                | EPG_PKT_LEN_10KB \
+                | EPG_DES_ADDR(1));
+
+        if( (cmpReg[0] == curReg[0])    \
+            && (cmpReg[1] == curReg[1]) \
+            && (cmpReg[2] == curReg[2]) \
+            && (cmpReg[3] == curReg[3]) )
+        {
+            (*ptr_mode) = AIR_DIAG_TXCOMPLY_MODE_10M_SINE;
+            hit = TRUE;
+        }
+    }
+
+    /* Test for AIR_DIAG_TXCOMPLY_MODE_10M_RANDOM */
+    if( FALSE == hit )
+    {
+        aml_writePhyReg(unit, port, PHY_PAGE, PHY_PAGE_0);
+        aml_readPhyReg(unit, port, PHY_MCR, &curReg[0]);
+        cmpReg[0] = MCR_MR_DUX;
+
+        aml_readPhyRegCL45(unit, port, 0x1e, 0x0145, &curReg[1]);
+        cmpReg[1] = (FC_TDI_EN | FC_LITN_NO_COMP | FC_MDI_CO_MDI);
+
+        aml_readPhyRegCL45(unit, port, 0x1f, 0x027b, &curReg[2]);
+        cmpReg[2] = (CR_RG_TX_CM_10M(1) \
+                | CR_RG_DELAY_TX_10M(1) \
+                | CR_DA_TX_GAIN_10M_EEE(100) \
+                | CR_DA_TX_GAIN_10M(100));
+
+        aml_writePhyReg(unit, port, PHY_PAGE, PHY_PAGE_1);
+        aml_readPhyReg(unit, port, PHY_EPG, &curReg[3]);
+        cmpReg[3] = (EPG_EN \
+                | EPG_RUN \
+                | EPG_TX_DUR \
+                | EPG_PKT_LEN_10KB \
+                | EPG_DES_ADDR(1) \
+                | EPG_PL_TYP_RANDOM);
+
+        if( (cmpReg[0] == curReg[0])    \
+            && (cmpReg[1] == curReg[1]) \
+            && (cmpReg[2] == curReg[2]) \
+            && (cmpReg[3] == curReg[3]) )
+        {
+            (*ptr_mode) = AIR_DIAG_TXCOMPLY_MODE_10M_RANDOM;
+            hit = TRUE;
+        }
+    }
+
+    /* Test for AIR_DIAG_TXCOMPLY_MODE_10M_NLP */
+    if( FALSE == hit )
+    {
+        aml_writePhyReg(unit, port, PHY_PAGE, PHY_PAGE_0);
+        aml_readPhyReg(unit, port, PHY_MCR, &curReg[0]);
+        cmpReg[0] = MCR_MR_DUX;
+
+        aml_readPhyRegCL45(unit, port, 0x1e, 0x0145, &curReg[1]);
+        cmpReg[1] = (FC_TDI_EN | FC_LITN_NO_COMP | FC_MDI_CO_MDI);
+
+        aml_readPhyRegCL45(unit, port, 0x1f, 0x027b, &curReg[2]);
+        cmpReg[2] = (CR_RG_TX_CM_10M(1) \
+                | CR_RG_DELAY_TX_10M(1) \
+                | CR_DA_TX_GAIN_10M_EEE(100) \
+                | CR_DA_TX_GAIN_10M(100));
+
+        if( (cmpReg[0] == curReg[0])    \
+            && (cmpReg[1] == curReg[1]) \
+            && (cmpReg[2] == curReg[2]) )
+        {
+            (*ptr_mode) = AIR_DIAG_TXCOMPLY_MODE_10M_NLP;
+            hit = TRUE;
+        }
+    }
+
+    /* Restore page of CL22 */
+    aml_writePhyReg(unit, port, PHY_PAGE, page);
+
+    if( TRUE == hit)
+    {
+        return AIR_E_OK;
+    }
+    else
+    {
+        return AIR_E_OTHERS;
+    }
+}
+
diff --git a/recipes-devtools/switch/files/src/an8855_sdk/api/src/air_error.c b/recipes-devtools/switch/files/src/an8855_sdk/api/src/air_error.c
new file mode 100644
index 0000000..3323e54
--- /dev/null
+++ b/recipes-devtools/switch/files/src/an8855_sdk/api/src/air_error.c
@@ -0,0 +1,73 @@
+/* FILE NAME:   air_error.c

+ * PURPOSE:

+ *      Define the software modules in AIR SDK.

+ * NOTES:

+ */

+

+/* INCLUDE FILE DECLARATIONS

+ */

+#include "air.h"

+

+/* NAMING CONSTANT DECLARATIONS

+ */

+

+/* MACRO FUNCTION DECLARATIONS

+ */

+

+/* DATA TYPE DECLARATIONS

+ */

+

+/* GLOBAL VARIABLE DECLARATIONS

+ */

+

+/* LOCAL SUBPROGRAM DECLARATIONS

+ */

+

+/* STATIC VARIABLE DECLARATIONS

+ */

+static C8_T *_air_error_cause[AIR_E_LAST] =

+{

+    "OK",

+    "NOT_OK",

+    "BAD_PARAMETER",

+    "TABLE_FULL",

+    "ENTRY_NOT_FOUND",

+    "ENTRY_EXISTS",

+    "NOT_SUPPORT",

+    "TIMEOUT",

+};

+

+/* EXPORTED SUBPROGRAM BODIES

+ */

+

+/* LOCAL SUBPROGRAM BODIES

+ */

+/* FUNCTION NAME:   air_error_getString

+ * PURPOSE:

+ *      To obtain the error string of the specified error code

+ *

+ * INPUT:

+ *      The specified error code

+ * OUTPUT:

+ *      None

+ * RETURN:

+ *      Pointer to the target error string

+ *

+ * NOTES:

+ *

+ *

+ */

+C8_T *

+air_error_getString(

+const AIR_ERROR_NO_T cause )

+{

+    if(cause < AIR_E_LAST)

+    {

+        return _air_error_cause[cause];

+    }

+    else

+    {

+        return "";

+    }

+}

+

diff --git a/recipes-devtools/switch/files/src/an8855_sdk/api/src/air_init.c b/recipes-devtools/switch/files/src/an8855_sdk/api/src/air_init.c
new file mode 100644
index 0000000..8a4f96f
--- /dev/null
+++ b/recipes-devtools/switch/files/src/an8855_sdk/api/src/air_init.c
@@ -0,0 +1,147 @@
+/* FILE NAME:   air_init.c

+ * PURPOSE:

+ *      Define the initialization function in AIR SDK.

+ *

+ * NOTES:

+ *      None

+ */

+

+/* INCLUDE FILE DECLARATIONS

+ */

+#include "air.h"

+

+/* NAMING CONSTANT DECLARATIONS

+ */

+

+/* MACRO FUNCTION DECLARATIONS

+ */

+

+/* DATA TYPE DECLARATIONS

+ */

+

+/* GLOBAL VARIABLE DECLARATIONS

+ */

+AIR_PRINTF _ext_printf;

+AIR_UDELAY _ext_udelay;

+AIR_MALLOC _ext_malloc;

+AIR_FREE   _ext_free;

+

+/* LOCAL SUBPROGRAM DECLARATIONS

+ */

+

+/* STATIC VARIABLE DECLARATIONS

+ */

+

+/* EXPORTED SUBPROGRAM BODIES

+ */

+

+/* LOCAL SUBPROGRAM BODIES

+ */

+

+/* FUNCTION NAME:   air_init

+ * PURPOSE:

+ *      This API is used to initialize the SDK.

+ *

+ * INPUT:

+ *      unit            --  The device unit

+ *      ptr_init_param  --  The sdk callback functions.

+ *

+ * OUTPUT:

+ *      None

+ *

+ * RETURN:

+ *      AIR_E_OK

+ *      AIR_E_OTHERS

+ *

+ * NOTES:

+ *      None

+ */

+AIR_ERROR_NO_T

+air_init(

+    const UI32_T unit,

+    AIR_INIT_PARAM_T *ptr_init_param)

+{

+    AIR_ERROR_NO_T rc = AIR_E_OK;

+    UI32_T u32dat = 0;

+    UI8_T port = 0;

+    AIR_LED_ON_EVT_T on_evt;

+    AIR_LED_BLK_EVT_T blk_evt;

+

+    /* check point */

+    AIR_CHECK_PTR(ptr_init_param);

+

+    _ext_dev_access.read_callback = ptr_init_param->dev_access.read_callback;

+    _ext_dev_access.write_callback = ptr_init_param->dev_access.write_callback;

+    _ext_dev_access.phy_read_callback = ptr_init_param->dev_access.phy_read_callback;

+    _ext_dev_access.phy_write_callback = ptr_init_param->dev_access.phy_write_callback;

+    _ext_dev_access.phy_cl45_read_callback = ptr_init_param->dev_access.phy_cl45_read_callback;

+    _ext_dev_access.phy_cl45_write_callback = ptr_init_param->dev_access.phy_cl45_write_callback;

+    _ext_printf = ptr_init_param->printf;

+    _ext_udelay = ptr_init_param->udelay;

+    _ext_malloc = ptr_init_param->malloc;

+    _ext_free   = ptr_init_param->free;

+    

+    return rc;

+}

+

+/* FUNCTION NAME:   air_hw_reset

+ * PURPOSE:

+ *      This API is used to reset hardware.

+ *

+ * INPUT:

+ *      unit            --  The device unit

+ *

+ * OUTPUT:

+ *      None

+ *

+ * RETURN:

+ *      AIR_E_OK

+ *      AIR_E_OTHERS

+ *

+ * NOTES:

+ *      None

+ */

+AIR_ERROR_NO_T

+air_hw_reset(

+    const UI32_T unit)

+{

+    AIR_PRINT(">>>>> enct_hw_reset\n");

+    /* Set an8855 reset pin to 0 */

+

+    /* Delay 100ms */

+

+    /* Set an8855 reset pin to 1 */

+

+    /* Delay 600ms */

+

+    return AIR_E_OK;

+}

+

+/* FUNCTION NAME:   air_set_gpio_pin_mux

+ * PURPOSE:

+ *      This API is used to set gpio pin mux.

+ *

+ * INPUT:

+ *      unit            --  The device unit

+ *

+ * OUTPUT:

+ *      None

+ *

+ * RETURN:

+ *      AIR_E_OK

+ *      AIR_E_OTHERS

+ *

+ * NOTES:

+ *      None

+ */

+AIR_ERROR_NO_T

+air_set_gpio_pin_mux(

+    const UI32_T unit)

+{

+    AIR_PRINT(">>>>> enct_set_gpio_pin_mux\n");

+    /* Set GPIO_MODE0 */

+    /* Implementation for SLT HW */

+    aml_writeReg(unit, GPIO_MODE0, 0x11111111);

+

+    return AIR_E_OK;

+}

diff --git a/recipes-devtools/switch/files/src/an8855_sdk/api/src/air_l2.c b/recipes-devtools/switch/files/src/an8855_sdk/api/src/air_l2.c
new file mode 100644
index 0000000..f8da749
--- /dev/null
+++ b/recipes-devtools/switch/files/src/an8855_sdk/api/src/air_l2.c
@@ -0,0 +1,1368 @@
+/* FILE NAME: air_l2.c
+ * PURPOSE:
+ *      Define the layer 2 function in AIR SDK.
+ *
+ * NOTES:
+ *      None
+ */
+
+/* INCLUDE FILE DECLARATIONS
+ */
+#include "air.h"
+
+/* NAMING CONSTANT DECLARATIONS
+ */
+#define AIR_L2_DELAY_US             (1000)
+#define AIR_L2_WDOG_KICK_NUM        (1000)
+#define AIR_L2_FORWARD_VALUE        (0xFFFFFFFF)
+#define AIR_L2_AGING_MS_CONSTANT    (1024)
+#define AIR_L2_AGING_1000MS         (1000)
+
+typedef enum
+{
+    AIR_L2_EXEC_FWD_CTRL_DEFAULT =      0x0,
+    AIR_L2_EXEC_FWD_CTRL_CPU_EXCLUDE =  0x4,
+    AIR_L2_EXEC_FWD_CTRL_CPU_INCLUDE =  0x5,
+    AIR_L2_EXEC_FWD_CTRL_CPU_ONLY =     0x6,
+    AIR_L2_EXEC_FWD_CTRL_DROP =         0x7,
+    AIR_L2_EXEC_FWD_CTRL_LAST
+}AIR_L2_EXEC_FWD_CTRL_T;
+
+typedef enum
+{
+    AIR_L2_MAC_MAT_MAC,
+    AIR_L2_MAC_MAT_DYNAMIC_MAC,
+    AIR_L2_MAC_MAT_STATIC_MAC,
+    AIR_L2_MAC_MAT_MAC_BY_VID,
+    AIR_L2_MAC_MAT_MAC_BY_FID,
+    AIR_L2_MAC_MAT_MAC_BY_PORT,
+    AIR_L2_MAC_MAT_MAC_BY_LAST
+}AIR_L2_MAC_MAT_T;
+
+/* L2 MAC table multi-searching */
+typedef enum
+{
+    AIR_L2_MAC_MS_START,   /* Start search */
+    AIR_L2_MAC_MS_NEXT,    /* Next search */
+    AIR_L2_MAC_MS_LAST
+}AIR_L2_MAC_MS_T;
+
+typedef enum
+{
+    AIR_L2_MAC_TB_TY_MAC,
+    AIR_L2_MAC_TB_TY_DIP,
+    AIR_L2_MAC_TB_TY_DIP_SIP,
+    AIR_L2_MAC_TB_TY_LAST
+}AIR_L2_MAC_TB_TY_T;
+
+/*
+typedef enum
+{
+    AIR_MAC_MAT_MAC,
+    AIR_MAC_MAT_DYNAMIC_MAC,
+    AIR_MAC_MAT_STATIC_MAC,
+    AIR_MAC_MAT_MAC_BY_VID,
+    AIR_MAC_MAT_MAC_BY_FID,
+    AIR_MAC_MAT_MAC_BY_PORT,
+    AIR_MAC_MAT_MAC_BY_LAST
+}AIR_MAC_MAT_T;
+*/
+
+/* MACRO FUNCTION DECLARATIONS
+ */
+#define AIR_L2_AGING_TIME(__cnt__, __unit__)   \
+        (((__cnt__) + 1) * ((__unit__) + 1) * AIR_L2_AGING_MS_CONSTANT / AIR_L2_AGING_1000MS)
+
+/* DATA TYPE DECLARATIONS
+ */
+
+/* GLOBAL VARIABLE DECLARATIONS
+ */
+static BOOL_T _search_end = FALSE;
+
+/* LOCAL SUBPROGRAM DECLARATIONS
+ */
+static BOOL_T
+_cmpMac(
+    const UI8_T mac1[6],
+    const UI8_T mac2[6]);
+
+static AIR_ERROR_NO_T
+_searchMacEntry(
+    const UI32_T unit,
+    const AIR_L2_MAC_MS_T ms,
+    const AIR_L2_MAC_MAT_T multi_target,
+    UI32_T *ptr_addr,
+    UI32_T *ptr_bank);
+
+static AIR_ERROR_NO_T
+_checkL2Busy(
+    const UI32_T unit);
+
+static void
+_fill_MAC_ATA(
+    const UI32_T unit,
+    const AIR_MAC_ENTRY_T *ptr_mac_entry);
+
+static void
+_fill_MAC_ATWD(
+    const UI32_T            unit,
+    const AIR_MAC_ENTRY_T   *ptr_mac_entry,
+    const BOOL_T            valid);
+
+static UI32_T
+_checkL2EntryHit(
+    const UI32_T unit);
+
+static void
+_fill_MAC_ATRDS(
+    const UI32_T unit,
+    UI8_T bank);
+
+static AIR_ERROR_NO_T
+_read_MAC_ATRD(
+    const UI32_T unit,
+    AIR_MAC_ENTRY_T *ptr_mac_entry);
+
+/* FUNCTION NAME: _cmpMac
+ * PURPOSE:
+ *      Compare MAC address to check whether those MAC is same.
+ *
+ * INPUT:
+ *      mac1            --  1st MAC address
+ *      mac2            --  2nd MAC address
+ *
+ * OUTPUT:
+ *      None
+ *
+ * RETURN:
+ *      TRUE
+ *      FALSE
+ *
+ * NOTES:
+ *      None
+ */
+static BOOL_T
+_cmpMac(
+    const UI8_T mac1[6],
+    const UI8_T mac2[6])
+{
+    UI32_T i;
+    for(i=0; i<6; i++)
+    {
+        if(mac1[i] != mac2[i])
+        {
+            return FALSE;
+        }
+    }
+    return TRUE;
+}
+/* FUNCTION NAME: _searchMacEntry
+ * PURPOSE:
+ *      Search MAC Address table.
+ *
+ * INPUT:
+ *      unit            --  Device ID
+ *      ms              --  _HAL_SCO_L2_MAC_MS_START:           Start search command
+ *                          _HAL_SCO_L2_MAC_MS_NEXT:            Next search command
+ *      multi_target    --  _HAL_SCO_L2_MAC_MAT_MAC:            MAC address entries
+ *                          _HAL_SCO_L2_MAC_MAT_DYNAMIC_MAC:    Dynamic MAC address entries
+ *                          _HAL_SCO_L2_MAC_MAT_STATIC_MAC:     Static MAC address entries
+ *                          _HAL_SCO_L2_MAC_MAT_MAC_BY_VID:     MAC address entries with specific CVID
+ *                          _HAL_SCO_L2_MAC_MAT_MAC_BY_FID:     MAC address entries with specific FID
+ *                          _HAL_SCO_L2_MAC_MAT_MAC_BY_PORT:    MAC address entries with specific port
+ * OUTPUT:
+ *      ptr_addr        --  MAC Table Access Index
+ *      ptr_bank        --  Searching result in which bank
+ *
+ * RETURN:
+ *      AIR_E_OK
+ *      AIR_E_BAD_PARAMETER
+ *      AIR_E_TIMEOUT
+ *
+ * NOTES:
+ *      None
+ */
+static AIR_ERROR_NO_T
+_searchMacEntry(
+    const UI32_T unit,
+    const AIR_L2_MAC_MS_T ms,
+    const AIR_L2_MAC_MAT_T multi_target,
+    UI32_T *ptr_addr,
+    UI32_T *ptr_bank)
+{
+    UI32_T u32dat = 0;
+
+    u32dat = (ATC_SAT_MAC | ATC_START_BUSY);
+    if (AIR_L2_MAC_MS_START == ms)
+    {
+        /* Start search 1st valid entry */
+        u32dat |= ATC_CMD_SEARCH;
+    }
+    else if (AIR_L2_MAC_MS_NEXT == ms)
+    {
+        /* Search next valid entry */
+        u32dat |= ATC_CMD_SEARCH_NEXT;
+    }
+    else
+    {
+        /* Unknown commnad */
+        return AIR_E_BAD_PARAMETER;
+    }
+
+    switch(multi_target)
+    {
+        case AIR_L2_MAC_MAT_MAC:
+            u32dat |= ATC_MAT_MAC;
+            break;
+        case AIR_L2_MAC_MAT_DYNAMIC_MAC:
+            u32dat |= ATC_MAT_DYNAMIC_MAC;
+            break;
+        case AIR_L2_MAC_MAT_STATIC_MAC:
+            u32dat |= ATC_MAT_STATIC_MAC;
+            break;
+        case AIR_L2_MAC_MAT_MAC_BY_VID:
+            u32dat |= ATC_MAT_MAC_BY_VID;
+            break;
+        case AIR_L2_MAC_MAT_MAC_BY_FID:
+            u32dat |= ATC_MAT_MAC_BY_FID;
+            break;
+        case AIR_L2_MAC_MAT_MAC_BY_PORT:
+            u32dat |= ATC_MAT_MAC_BY_PORT;
+            break;
+        default:
+            /* Unknown searching mode */
+            return AIR_E_BAD_PARAMETER;
+    }
+    aml_writeReg(unit, ATC, u32dat);
+    if (AIR_E_TIMEOUT == _checkL2Busy(unit))
+    {
+        return AIR_E_TIMEOUT;
+    }
+
+    aml_readReg(unit, ATC, &u32dat);
+    /* Get address */
+    (*ptr_addr) = BITS_OFF_R(u32dat, ATC_ADDR_OFFSET, ATC_ADDR_LENGTH);
+    /* Get banks */
+    (*ptr_bank) = BITS_OFF_R(u32dat, ATC_ENTRY_HIT_OFFSET, ATC_ENTRY_HIT_LENGTH);
+    if ((AIR_L2_MAX_SIZE - 1) == (*ptr_addr))
+    {
+        _search_end = TRUE;
+    }
+    else
+    {
+        _search_end = FALSE;
+    }
+
+    return AIR_E_OK;
+}
+
+/* FUNCTION NAME: _checkL2Busy
+ * PURPOSE:
+ *      Check BUSY bit of ATC
+ *
+ * INPUT:
+ *      unit            --  Device ID
+ *
+ * OUTPUT:
+ *      None
+ *
+ * RETURN:
+ *      AIR_E_OK
+ *      AIR_E_TIMEOUT
+ *
+ * NOTES:
+ *      None
+ */
+static AIR_ERROR_NO_T
+_checkL2Busy(
+    const UI32_T unit)
+{
+    UI32_T i = 0;
+    UI32_T reg_atc = 0;
+
+    /* Check BUSY bit is 0 */
+    for(i = 0; i < AIR_L2_MAX_BUSY_TIME; i++)
+    {
+        aml_readReg(unit, ATC, &reg_atc);
+        if(!BITS_OFF_R(reg_atc, ATC_BUSY_OFFSET, ATC_BUSY_LENGTH))
+        {
+            break;
+        }
+        AIR_UDELAY(AIR_L2_DELAY_US);
+    }
+    if(i >= AIR_L2_MAX_BUSY_TIME)
+    {
+        return AIR_E_TIMEOUT;
+    }
+    return AIR_E_OK;
+}
+/***************************************************************/
+/* FUNCTION NAME: _fill_MAC_ATA
+ * PURPOSE:
+ *      Fill register ATA for MAC Address table.
+ *
+ * INPUT:
+ *      unit            --  Device ID
+ *      ptr_mac_entry   --  Structure of MAC Address table
+ *
+ * OUTPUT:
+ *      None
+ *
+ * RETURN:
+ *      None
+ *
+ * NOTES:
+ *      None
+ */
+static void
+_fill_MAC_ATA(
+    const UI32_T unit,
+    const AIR_MAC_ENTRY_T *ptr_mac_entry)
+{
+    UI32_T u32dat = 0;
+    UI32_T i = 0;
+
+    /* Fill ATA1 */
+    for (i = 0; i < 4; i++)
+    {
+        u32dat |= ((UI32_T)(ptr_mac_entry->mac[i] & BITS(0,7))) << ( (3-i) * 8);
+    }
+    aml_writeReg(unit, ATA1, u32dat);
+    AIR_UDELAY(AIR_L2_DELAY_US);
+
+    /* Fill ATA2 */
+    u32dat=0;
+    for (i = 4; i < 6; i++)
+    {
+        u32dat |= ((UI32_T)(ptr_mac_entry->mac[i] & BITS(0,7))) << ( (7-i) * 8);
+    }
+    if (!(ptr_mac_entry->flags & AIR_L2_MAC_ENTRY_FLAGS_STATIC))
+    {
+        /* type is dynamic */
+        u32dat |= BITS_OFF_L(1UL, ATA2_MAC_LIFETIME_OFFSET, ATA2_MAC_LIFETIME_LENGTH);
+        /* set aging counter as system aging conuter */
+        u32dat |= BITS_OFF_L(ptr_mac_entry->timer, ATA2_MAC_AGETIME_OFFSET, ATA2_MAC_AGETIME_LENGTH);
+    }
+    if (ptr_mac_entry->flags & AIR_L2_MAC_ENTRY_FLAGS_UNAUTH)
+    {
+        u32dat |= BITS_OFF_L(1UL, ATA2_MAC_UNAUTH_OFFSET, ATA2_MAC_UNAUTH_LENGTH);
+    }
+
+    aml_writeReg(unit, ATA2, u32dat);
+    AIR_UDELAY(AIR_L2_DELAY_US);
+}
+
+/* FUNCTION NAME: _fill_MAC_ATWD
+ * PURPOSE:
+ *      Fill register ATWD for MAC Address table.
+ *
+ * INPUT:
+ *      unit            --  Device ID
+ *      ptr_mac_entry   --  Structure of MAC Address table
+ *      valid           --  TRUE
+ *                          FALSE
+ * OUTPUT:
+ *      None
+ *
+ * RETURN:
+ *      None
+ *
+ * NOTES:
+ *      None
+ */
+static void
+_fill_MAC_ATWD(
+    const UI32_T            unit,
+    const AIR_MAC_ENTRY_T   *ptr_mac_entry,
+    const BOOL_T            valid)
+{
+    UI32_T u32dat = 0;
+    UI32_T fwd_val = 0;
+
+    u32dat = 0;
+    /* Fill ATWD */
+    /* set valid bit */
+    if (TRUE == valid)
+    {
+        u32dat |= BITS_OFF_L(1UL, ATWD_MAC_LIVE_OFFSET, ATWD_MAC_LIVE_LENGTH);
+    }
+
+    /* set IVL */
+    if (ptr_mac_entry->flags & AIR_L2_MAC_ENTRY_FLAGS_IVL)
+    {
+        u32dat |= BITS_OFF_L(1UL, ATWD_MAC_IVL_OFFSET, ATWD_MAC_IVL_LENGTH);
+    }
+    /* set VID */
+    u32dat |= BITS_OFF_L(ptr_mac_entry->cvid, ATWD_MAC_VID_OFFSET, ATWD_MAC_VID_LENGTH);
+    /* set FID */
+    u32dat |= BITS_OFF_L(ptr_mac_entry->fid, ATWD_MAC_FID_OFFSET, ATWD_MAC_FID_LENGTH);
+
+    /* Set forwarding control */
+    switch (ptr_mac_entry->sa_fwd)
+    {
+        case AIR_L2_FWD_CTRL_DEFAULT:
+            fwd_val = AIR_L2_EXEC_FWD_CTRL_DEFAULT;
+            break;
+        case AIR_L2_FWD_CTRL_CPU_INCLUDE:
+            fwd_val = AIR_L2_EXEC_FWD_CTRL_CPU_INCLUDE;
+            break;
+        case AIR_L2_FWD_CTRL_CPU_EXCLUDE:
+            fwd_val = AIR_L2_EXEC_FWD_CTRL_CPU_EXCLUDE;
+            break;
+        case AIR_L2_FWD_CTRL_CPU_ONLY:
+            fwd_val = AIR_L2_EXEC_FWD_CTRL_CPU_ONLY;
+            break;
+        case AIR_L2_FWD_CTRL_DROP:
+            fwd_val = AIR_L2_EXEC_FWD_CTRL_DROP;
+            break;
+        default:
+            break;
+    }
+    u32dat |= BITS_OFF_L(fwd_val, ATWD_MAC_FWD_OFFSET, ATWD_MAC_FWD_LENGTH);
+    aml_writeReg(unit, ATWD, u32dat);
+    AIR_UDELAY(AIR_L2_DELAY_US);
+
+    /* Fill ATWD2 */
+    u32dat = BITS_OFF_L(ptr_mac_entry->port_bitmap[0], ATWD2_MAC_PORT_OFFSET, ATWD2_MAC_PORT_LENGTH);
+    aml_writeReg(unit, ATWD2, u32dat);
+    AIR_UDELAY(AIR_L2_DELAY_US);
+}
+
+/* FUNCTION NAME: _checkL2EntryHit
+ * PURPOSE:
+ *      Check entry hit of ATC
+ *
+ * INPUT:
+ *      unit            --  Device ID
+ *
+ * OUTPUT:
+ *      None
+ *
+ * RETURN:
+ *      The entry hit bitmap
+ *
+ * NOTES:
+ *      None
+ */
+static UI32_T
+_checkL2EntryHit(
+    const UI32_T unit)
+{
+    UI32_T reg_atc = 0;
+    aml_readReg(unit, ATC, &reg_atc);
+    return BITS_OFF_R(reg_atc, ATC_ENTRY_HIT_OFFSET, ATC_ENTRY_HIT_LENGTH);
+}
+
+/* FUNCTION NAME: _fill_MAC_ATRDS
+ * PURPOSE:
+ *      Fill register ATRDS for select bank after ATC search L2 table.
+ *
+ * INPUT:
+ *      unit            --  Device ID
+ *      bank            --  Selected index of bank
+ *
+ * OUTPUT:
+ *      None
+ *
+ * RETURN:
+ *      None
+ *
+ * NOTES:
+ *      None
+ */
+static void
+_fill_MAC_ATRDS(
+    const UI32_T unit,
+    UI8_T bank)
+{
+    UI32_T u32dat = 0;
+
+    /* Fill ATRDS */
+    u32dat = BITS_OFF_L(bank, ATRD0_MAC_SEL_OFFSET, ATRD0_MAC_SEL_LENGTH);
+    aml_writeReg(unit, ATRDS, u32dat);
+    AIR_UDELAY(AIR_L2_DELAY_US);
+}
+
+/* FUNCTION NAME: _read_MAC_ATRD
+ * PURPOSE:
+ *      Read register ATRD for MAC Address table.
+ *
+ * INPUT:
+ *      unit            --  Device ID
+ *
+ * OUTPUT:
+ *      ptr_mac_entry   --  Structure of MAC Address table
+ *
+ * RETURN:
+ *      AIR_E_OK
+ *      AIR_E_ENTRY_NOT_FOUND
+ *
+ * NOTES:
+ *      None
+ */
+static AIR_ERROR_NO_T
+_read_MAC_ATRD(
+    const UI32_T unit,
+    AIR_MAC_ENTRY_T *ptr_mac_entry)
+{
+    UI32_T u32dat = 0;
+    UI32_T i = 0;
+    BOOL_T live = FALSE;
+    UI32_T type = 0;
+    UI32_T age_unit = 0;
+    UI32_T age_cnt = 0;
+    UI32_T sa_fwd = 0;
+
+    /* Read ATRD0 */
+    aml_readReg(unit, ATRD0, &u32dat);
+    live = BITS_OFF_R(u32dat, ATRD0_MAC_LIVE_OFFSET, ATRD0_MAC_LIVE_LENGTH);
+    type = BITS_OFF_R(u32dat, ATRD0_MAC_TYPE_OFFSET, ATRD0_MAC_TYPE_LENGTH);
+    if (FALSE == live)
+    {
+        return AIR_E_ENTRY_NOT_FOUND;
+    }
+    if (AIR_L2_MAC_TB_TY_MAC != type)
+    {
+        return AIR_E_ENTRY_NOT_FOUND;
+    }
+    /* Clear table */
+    memset(ptr_mac_entry, 0, sizeof(AIR_MAC_ENTRY_T));
+
+    ptr_mac_entry->cvid = (UI16_T)BITS_OFF_R(u32dat, ATRD0_MAC_VID_OFFSET, ATRD0_MAC_VID_LENGTH);
+    ptr_mac_entry->fid = (UI16_T)BITS_OFF_R(u32dat, ATRD0_MAC_FID_OFFSET, ATRD0_MAC_FID_LENGTH);
+    if (!!BITS_OFF_R(u32dat, ATRD0_MAC_LIFETIME_OFFSET, ATRD0_MAC_LIFETIME_LENGTH))
+    {
+        ptr_mac_entry->flags |= AIR_L2_MAC_ENTRY_FLAGS_STATIC;
+    }
+    if (!!BITS_OFF_R(u32dat, ATRD0_MAC_IVL_OFFSET, ATRD0_MAC_IVL_LENGTH))
+    {
+        ptr_mac_entry->flags |= AIR_L2_MAC_ENTRY_FLAGS_IVL;
+    }
+    if (!!BITS_OFF_R(u32dat, ATRD1_MAC_UNAUTH_OFFSET, ATRD1_MAC_UNAUTH_LENGTH))
+    {
+        ptr_mac_entry->flags |= AIR_L2_MAC_ENTRY_FLAGS_UNAUTH;
+    }
+
+    /* Get the L2 MAC aging unit */
+    aml_readReg(unit, AAC, &u32dat);
+    age_unit = BITS_OFF_R(u32dat, AAC_AGE_UNIT_OFFSET, AAC_AGE_UNIT_LENGTH);
+
+    /* Read ATRD1 */
+    aml_readReg(unit, ATRD1, &u32dat);
+    for (i = 4; i < 6; i++)
+    {
+        ptr_mac_entry->mac[i] = BITS_OFF_R(u32dat, (7 - i)*8, 8);
+    }
+    /* Aging time */
+    age_cnt = BITS_OFF_R(u32dat, ATRD1_MAC_AGETIME_OFFSET, ATRD1_MAC_AGETIME_LENGTH);
+    ptr_mac_entry->timer = AIR_L2_AGING_TIME(age_cnt, age_unit);
+    /* SA forwarding */
+    sa_fwd = BITS_OFF_R(u32dat, ATRD1_MAC_FWD_OFFSET, ATRD1_MAC_FWD_LENGTH);
+    switch (sa_fwd)
+    {
+        case AIR_L2_EXEC_FWD_CTRL_DEFAULT:
+            ptr_mac_entry->sa_fwd = AIR_L2_FWD_CTRL_DEFAULT;
+            break;
+        case AIR_L2_EXEC_FWD_CTRL_CPU_INCLUDE:
+            ptr_mac_entry->sa_fwd = AIR_L2_FWD_CTRL_CPU_INCLUDE;
+            break;
+        case AIR_L2_EXEC_FWD_CTRL_CPU_EXCLUDE:
+            ptr_mac_entry->sa_fwd = AIR_L2_FWD_CTRL_CPU_EXCLUDE;
+            break;
+        case AIR_L2_EXEC_FWD_CTRL_CPU_ONLY:
+            ptr_mac_entry->sa_fwd = AIR_L2_FWD_CTRL_CPU_ONLY;
+            break;
+        case AIR_L2_EXEC_FWD_CTRL_DROP:
+            ptr_mac_entry->sa_fwd = AIR_L2_FWD_CTRL_DROP;
+            break;
+        default:
+            ptr_mac_entry->sa_fwd = AIR_L2_FWD_CTRL_DEFAULT;
+            break;
+    }
+
+    /* Read ATRD2 */
+    aml_readReg(unit, ATRD2, &u32dat);
+    for (i = 0; i < 4; i++)
+    {
+        ptr_mac_entry->mac[i] = BITS_OFF_R(u32dat, (3 - i)*8, 8);
+    }
+
+    /* Read ATRD3 */
+    aml_readReg(unit, ATRD3, &u32dat);
+    ptr_mac_entry->port_bitmap[0] = BITS_OFF_R(u32dat, ATRD3_MAC_PORT_OFFSET, ATRD3_MAC_PORT_LENGTH);
+
+    return AIR_E_OK;
+}
+
+static AIR_ERROR_NO_T _mac_entry_init(AIR_MAC_ENTRY_T   *ptr_mac_entry)
+{
+    AIR_CHECK_PTR(ptr_mac_entry);
+    memset(ptr_mac_entry->mac, 0, sizeof(ptr_mac_entry->mac));
+    ptr_mac_entry->cvid = 0;
+    ptr_mac_entry->fid = 0;
+    ptr_mac_entry->flags = 0;
+    ptr_mac_entry->port_bitmap[0] = 0;
+    ptr_mac_entry->sa_fwd = 0;
+    ptr_mac_entry->timer = 0;
+    return AIR_E_OK;
+}
+/* FUNCTION NAME: air_l2_addMacAddr
+ * PURPOSE:
+ *      Add or set a L2 unicast MAC address entry.
+ *      If the address entry doesn't exist, it will add the entry.
+ *      If the address entry already exists, it will set the entry
+ *      with user input value.
+ *
+ * INPUT:
+ *      unit            --  Device ID
+ *      ptr_mac_entry   --  Structure of MAC Address table
+ *
+ * OUTPUT:
+ *      None
+ *
+ * RETURN:
+ *      AIR_E_OK
+ *      AIR_E_BAD_PARAMETER
+ *      AIR_E_TABLE_FULL
+ *      AIR_E_TIMEOUT
+ *
+ * NOTES:
+ *      None
+ */
+AIR_ERROR_NO_T
+air_l2_addMacAddr(
+    const UI32_T unit,
+    const AIR_MAC_ENTRY_T   *ptr_mac_entry)
+{
+    UI32_T u32dat = 0;
+    UI32_T reg_aac = 0;
+    AIR_MAC_ENTRY_T set_mac_entry;
+
+    /* parameter sanity check */
+    AIR_PARAM_CHK((unit >= AIR_MAX_NUM_OF_UNIT), AIR_E_BAD_PARAMETER);
+    AIR_CHECK_PTR(ptr_mac_entry);
+    AIR_PARAM_CHK(((ptr_mac_entry->port_bitmap[0] & AIR_ALL_PORT_BITMAP) == 0), AIR_E_BAD_PARAMETER);
+    if (ptr_mac_entry->flags & AIR_L2_MAC_ENTRY_FLAGS_IVL)
+    {
+        AIR_PARAM_CHK(((ptr_mac_entry->cvid < 1) || (ptr_mac_entry->cvid > 4095)), AIR_E_BAD_PARAMETER);
+    }
+    else
+    {
+        AIR_PARAM_CHK(((ptr_mac_entry->fid > (AIR_STP_FID_NUMBER - 1))), AIR_E_BAD_PARAMETER);
+    }
+    _mac_entry_init(&set_mac_entry);
+    /* Set the target MAC entry as setting entry no mater the hash addrees is existed or not */
+    memcpy(&set_mac_entry, ptr_mac_entry, sizeof(AIR_MAC_ENTRY_T));
+    /* Translate port bitmap type */
+    /* set aging counter as system aging conuter */
+    aml_readReg(unit, AAC, &reg_aac);
+    set_mac_entry.timer = BITS_OFF_R(reg_aac, AAC_AGE_CNT_OFFSET, AAC_AGE_CNT_LENGTH);
+
+    /* Fill MAC address entry */
+    _fill_MAC_ATA(unit, &set_mac_entry);
+    _fill_MAC_ATWD(unit, &set_mac_entry, TRUE);
+
+    /* Write data by ATC */
+    u32dat = (ATC_SAT_MAC | ATC_CMD_WRITE | ATC_START_BUSY);
+    aml_writeReg(unit, ATC, u32dat);
+    if (AIR_E_TIMEOUT == _checkL2Busy(unit))
+    {
+        return AIR_E_TIMEOUT;
+    }
+    if ( !_checkL2EntryHit(unit))
+    {
+        return AIR_E_TABLE_FULL;
+    }
+    return AIR_E_OK;
+}
+
+/* FUNCTION NAME: air_l2_delMacAddr
+ * PURPOSE:
+ *      Delete a L2 unicast MAC address entry.
+ *
+ * INPUT:
+ *      unit            --  Device ID
+ *      ptr_mac_entry   --  The structure of MAC Address table
+ *
+ * OUTPUT:
+ *      None
+ *
+ * RETURN:
+ *      AIR_E_OK
+ *      AIR_E_BAD_PARAMETER
+ *
+ * NOTES:
+ *      None
+ */
+AIR_ERROR_NO_T
+air_l2_delMacAddr(
+    const UI32_T unit,
+    const AIR_MAC_ENTRY_T   *ptr_mac_entry)
+{
+    UI32_T u32dat = 0;
+    AIR_MAC_ENTRY_T del_mac_entry;
+
+    /* parameter sanity check */
+    AIR_PARAM_CHK((unit >= AIR_MAX_NUM_OF_UNIT), AIR_E_BAD_PARAMETER);
+    AIR_CHECK_PTR(ptr_mac_entry);
+    //AIR_PARAM_CHK(((ptr_mac_entry->port_bitmap[0] & AIR_ALL_PORT_BITMAP) == 0), AIR_E_BAD_PARAMETER);
+    if (ptr_mac_entry->flags & AIR_L2_MAC_ENTRY_FLAGS_IVL)
+    {
+        AIR_PARAM_CHK(((ptr_mac_entry->cvid < 1) || (ptr_mac_entry->cvid > 4095)), AIR_E_BAD_PARAMETER);
+    }
+    else
+    {
+        AIR_PARAM_CHK(((ptr_mac_entry->fid > (AIR_STP_FID_NUMBER - 1))), AIR_E_BAD_PARAMETER);
+    }
+    _mac_entry_init(&del_mac_entry);
+    memcpy(&del_mac_entry, ptr_mac_entry, sizeof(AIR_MAC_ENTRY_T));
+
+    /* Fill MAC address entry */
+    _fill_MAC_ATA(unit, &del_mac_entry);
+    _fill_MAC_ATWD(unit, &del_mac_entry, FALSE);
+
+    /* Write data by ATC to delete entry */
+    u32dat = (ATC_SAT_MAC | ATC_CMD_WRITE | ATC_START_BUSY);
+    aml_writeReg(unit, ATC, u32dat);
+    if (AIR_E_TIMEOUT == _checkL2Busy(unit))
+    {
+        return AIR_E_TIMEOUT;
+    }
+
+    return AIR_E_OK;
+}
+
+/* FUNCTION NAME:   air_l2_getMacBucketSize
+ * PURPOSE:
+ *      Get the bucket size of one MAC address set when searching L2
+ *      table.
+ * INPUT:
+ *      unit                     -- Device ID
+ * OUTPUT:
+ *      ptr_size                 -- The bucket size
+ * RETURN:
+ *      AIR_E_OK                 -- Operation success.
+ *      AIR_E_BAD_PARAMETER      -- Parameter is wrong.
+ * NOTES:
+ *      None
+ */
+AIR_ERROR_NO_T
+air_l2_getMacBucketSize(
+    const UI32_T    unit,
+    UI32_T          *ptr_size)
+{
+    /* parameter sanity check */
+    AIR_PARAM_CHK((unit >= AIR_MAX_NUM_OF_UNIT), AIR_E_BAD_PARAMETER);
+    AIR_CHECK_PTR(ptr_size);
+
+    /* Access regiser */
+    (*ptr_size) = AIR_L2_MAC_SET_NUM;
+
+    return AIR_E_OK;
+}
+
+
+/* FUNCTION NAME:  air_l2_getMacAddr
+ * PURPOSE:
+ *      Get a L2 unicast MAC address entry.
+ *
+ * INPUT:
+ *      unit            --  Device ID
+ *      ptr_mac_entry   --  The structure of MAC Address table
+ *
+ * OUTPUT:
+ *      ptr_count                -- The number of returned MAC entries
+ *      ptr_mac_entry            -- Structure of MAC Address table for
+ *                                  searching result.
+ *                                  The size of ptr_mac_entry depends
+ *                                  on the maximun number of bank.
+ *                                  The memory size should greater than
+ *                                  ((# of Bank) * (Size of entry
+ *                                  structure))
+ *                                  AIR_MAC_ENTRY_T
+ * RETURN:
+ *      AIR_E_OK                 -- Operation success.
+ *      AIR_E_BAD_PARAMETER      -- Parameter is wrong.
+ *      AIR_E_TIMEOUT            -- Timeout error.
+ *      AIR_E_ENTRY_NOT_FOUND    -- Entry is not found.
+ * NOTES:
+ *      If the parameter:mac in input argument ptr_mac_entry[0] is
+ *      empty. It means to search the first valid MAC address entry
+ *      in MAC address table. Otherwise, to search the specific MAC
+ *      address entry in input argument ptr_mac_entry[0].
+ *      Input argument ptr_mac_entry[0] needs include mac, ivl and
+ *      (fid or cvid) depends on ivl.
+ *      If argument ivl is TRUE, cvid is necessary, or fid is.
+ */
+AIR_ERROR_NO_T
+air_l2_getMacAddr(
+    const UI32_T unit,
+    UI8_T           *ptr_count,
+    AIR_MAC_ENTRY_T *ptr_mac_entry)
+{
+    AIR_ERROR_NO_T rc = AIR_E_OK;
+    UI32_T i = 0;
+    BOOL_T is_mac_empty = TRUE;
+    BOOL_T found_target = FALSE;
+    AIR_MAC_ENTRY_T mt_read;
+    UI32_T addr = 0;
+    UI32_T banks = 0;
+    AIR_L2_MAC_MAT_T mat = 0;
+
+    /* parameter sanity check */
+    AIR_PARAM_CHK((unit >= AIR_MAX_NUM_OF_UNIT), AIR_E_BAD_PARAMETER);
+    AIR_CHECK_PTR(ptr_mac_entry);
+    //AIR_PARAM_CHK(((ptr_mac_entry->port_bitmap[0] & AIR_ALL_PORT_BITMAP) == 0), AIR_E_BAD_PARAMETER);
+    if (ptr_mac_entry->flags & AIR_L2_MAC_ENTRY_FLAGS_IVL)
+    {
+        AIR_PARAM_CHK(((ptr_mac_entry->cvid < 1) || (ptr_mac_entry->cvid > 4095)), AIR_E_BAD_PARAMETER);
+    }
+    else
+    {
+        AIR_PARAM_CHK(((ptr_mac_entry->fid > (AIR_STP_FID_NUMBER - 1))), AIR_E_BAD_PARAMETER);
+    }
+    _mac_entry_init(&mt_read);
+    /* Check MAC Address field of input data */
+    for (i = 0; i < 6; i++)
+    {
+        if (0 != ptr_mac_entry->mac[i])
+        {
+            is_mac_empty = FALSE;
+            break;
+        }
+    }
+
+    (*ptr_count) = 0;
+    if (FALSE == is_mac_empty)
+    {
+        /* MAC address isn't empty, means to search a specific MAC entry */
+        if (ptr_mac_entry->flags & AIR_L2_MAC_ENTRY_FLAGS_IVL)
+        {
+            mat = AIR_L2_MAC_MAT_MAC_BY_VID;
+        }
+        else
+        {
+            mat = AIR_L2_MAC_MAT_MAC_BY_FID;
+        }
+        _fill_MAC_ATA(unit, ptr_mac_entry);
+        _fill_MAC_ATWD(unit, ptr_mac_entry, TRUE);
+
+        rc = _searchMacEntry(unit, AIR_L2_MAC_MS_START, mat, &addr, &banks);
+
+        while(AIR_E_OK == rc)
+        {
+            AIR_PRINT("banks=(%d)\n", banks);
+            if (0 == banks)
+            {
+                return AIR_E_ENTRY_NOT_FOUND;
+            }
+            for (i = 0; i < AIR_L2_MAC_SET_NUM; i++)
+            {
+                if (!!BITS_OFF_R(banks, i, 1))
+                {
+                    /* Found a valid MAC entry */
+                    /* Select bank */
+                    _fill_MAC_ATRDS(unit, i);
+
+                    /* Read MAC entry */
+                    memset(&mt_read, 0, sizeof(AIR_MAC_ENTRY_T));
+                    rc = _read_MAC_ATRD(unit, &mt_read);
+                    if (AIR_E_OK != rc)
+                    {
+                        AIR_PRINT("rc=(%d)\n", rc);
+                        continue;
+                    }
+                    if (TRUE == _cmpMac(ptr_mac_entry->mac, mt_read.mac))
+                    {
+                        /* The found MAC is the target, restore data and leave */
+                        memcpy(ptr_mac_entry, &mt_read, sizeof(AIR_MAC_ENTRY_T));
+                        /* Translate port bitmap type */
+                        found_target = TRUE;
+                        (*ptr_count)++;
+                        break;
+                    }
+                }
+            }
+
+            if ( TRUE == found_target)
+            {
+                break;
+            }
+
+            /* The found MAC isn't the target, keep searching or leave
+             * when found the last entry */
+            if (TRUE == _search_end)
+            {
+                return AIR_E_ENTRY_NOT_FOUND;
+            }
+            else
+            {
+                rc = _searchMacEntry(unit, AIR_L2_MAC_MS_NEXT, mat, &addr, &banks);
+            }
+        }
+        return rc;
+    }
+    else
+    {
+        /* MAC address is empty, means to search the 1st MAC entry */
+        rc = _searchMacEntry(unit, AIR_L2_MAC_MS_START, AIR_L2_MAC_MAT_MAC, &addr, &banks);
+
+        switch(rc)
+        {
+            case AIR_E_OK:
+                /* Searching bank and read data */
+                AIR_PRINT("banks=(%d)\n", banks);
+                if (0 == banks)
+                {
+                    return AIR_E_ENTRY_NOT_FOUND;
+                }
+                for (i = 0; i < AIR_L2_MAC_SET_NUM; i++)
+                {
+                    if (!!BITS_OFF_R(banks, i, 1))
+                    {
+                        /* Found a valid MAC entry */
+                        /* Select bank */
+                        _fill_MAC_ATRDS(unit, i);
+
+                        /* Read MAC entry */
+                        memset(&mt_read, 0, sizeof(AIR_MAC_ENTRY_T));
+                        rc = _read_MAC_ATRD(unit, &mt_read);
+                        if (AIR_E_OK != rc)
+                        {
+                            AIR_PRINT("rc=(%d)\n", rc);
+                            continue;
+                        }
+                        memcpy(&ptr_mac_entry[(*ptr_count)], &mt_read, sizeof(AIR_MAC_ENTRY_T));
+                        /* Translate port bitmap type */
+                        (*ptr_count)++;
+                    }
+                }
+                return AIR_E_OK;
+            case AIR_E_TIMEOUT:
+                /* Searching over time */
+                return AIR_E_TIMEOUT;
+            default:
+                AIR_PRINT("rc=(%d)\n", rc);
+                return AIR_E_ENTRY_NOT_FOUND;
+        }
+    }
+}
+
+/* FUNCTION NAME: air_l2_getNextMacAddr
+ * PURPOSE:
+ *      Get the next L2 unicast MAC address entry.
+ *
+ * INPUT:
+ *      unit            --  Device ID
+ *      ptr_mac_entry   --  The structure of MAC Address table
+ *
+ * OUTPUT:
+ *      ptr_count       --  The number of returned MAC entries
+ *      ptr_mac_entry   --  Structure of MAC Address table for searching result.
+ *                          The size of ptr_mac_entry depends on the max. number of bank.
+ *                          The memory size should greater than ((# of Bank) * (Table size))
+ * RETURN:
+ *      AIR_E_OK
+ *      AIR_E_BAD_PARAMETER
+ *      AIR_E_TIMEOUT
+ *      AIR_E_ENTRY_NOT_FOUND
+ * NOTES:
+ *      If the parameter:mac in input argument ptr_mac_entry[0] is empty.
+ *      It means to search the next valid MAC address entries of last searching result.
+ *      Otherwise, to search the next valid MAC address entry of the specific MAC address
+ *      entry in input argument ptr_mac_entry[0].
+ *      Input argument ptr_mac_entry[0] needs include mac, ivl and (fid or cvid) depends on ivl.
+ *      If argument ivl is TRUE, cvid is necessary, or fid is.
+ */
+AIR_ERROR_NO_T
+air_l2_getNextMacAddr(
+    const UI32_T unit,
+    UI8_T           *ptr_count,
+    AIR_MAC_ENTRY_T *ptr_mac_entry)
+
+{
+    AIR_ERROR_NO_T rc = AIR_E_OK;
+    UI32_T i = 0;
+    BOOL_T is_mac_empty = TRUE;
+    BOOL_T found_target = FALSE;
+    AIR_MAC_ENTRY_T mt_read;
+    UI32_T addr = 0;
+    UI32_T banks = 0;
+
+    /* parameter sanity check */
+    AIR_PARAM_CHK((unit >= AIR_MAX_NUM_OF_UNIT), AIR_E_BAD_PARAMETER);
+    AIR_CHECK_PTR(ptr_mac_entry);
+    //AIR_PARAM_CHK(((ptr_mac_entry->port_bitmap[0] & AIR_ALL_PORT_BITMAP) == 0), AIR_E_BAD_PARAMETER);
+    if (ptr_mac_entry->flags & AIR_L2_MAC_ENTRY_FLAGS_IVL)
+    {
+        AIR_PARAM_CHK(((ptr_mac_entry->cvid < 1) || (ptr_mac_entry->cvid > 4095)), AIR_E_BAD_PARAMETER);
+    }
+    else
+    {
+        AIR_PARAM_CHK(((ptr_mac_entry->fid > (AIR_STP_FID_NUMBER - 1))), AIR_E_BAD_PARAMETER);
+    }
+    _mac_entry_init(&mt_read);
+    /* If found the lastest entry last time, we couldn't keep to search the next entry */
+    if(TRUE == _search_end)
+    {
+        return AIR_E_ENTRY_NOT_FOUND;
+    }
+
+    /* Check MAC Address field of input data */
+    for (i = 0; i < 6; i++)
+    {
+        if (0 != ptr_mac_entry->mac[i])
+        {
+            is_mac_empty = FALSE;
+            break;
+        }
+    }
+    (*ptr_count)=0;
+
+    if (FALSE == is_mac_empty)
+    {
+        /* MAC address isn't empty, means to search the next entries of input MAC Address */
+        /* Search the target MAC entry */
+        _fill_MAC_ATA(unit, ptr_mac_entry);
+        rc = _searchMacEntry(unit, AIR_L2_MAC_MS_START, AIR_L2_MAC_MAT_MAC, &addr, &banks);
+        while(AIR_E_OK == rc)
+        {
+            AIR_PRINT("banks=(%d)\n", banks);
+            if (0 == banks)
+            {
+                return AIR_E_ENTRY_NOT_FOUND;
+            }
+            for (i = 0; i < AIR_L2_MAC_SET_NUM; i++)
+            {
+                if (!!BITS_OFF_R(banks, i, 1))
+                {
+                    /* Found a valid MAC entry */
+                    /* Select bank */
+                    _fill_MAC_ATRDS(unit, i);
+
+                    /* Read MAC entry */
+                    memset(&mt_read, 0, sizeof(AIR_MAC_ENTRY_T));
+                    rc = _read_MAC_ATRD(unit, &mt_read);
+                    if (AIR_E_OK != rc)
+                    {
+                        AIR_PRINT("rc=(%d)\n", rc);
+                        continue;
+                    }
+                    if (TRUE == _cmpMac(ptr_mac_entry->mac, mt_read.mac))
+                    {
+                        /* The found MAC is the target, restore data and leave */
+                        found_target = TRUE;
+                        break;
+                    }
+                }
+            }
+
+            if ( TRUE == found_target)
+            {
+                break;
+            }
+
+            /* The found MAC isn't the target, keep searching or leave
+             * when found the last entry */
+            if (TRUE == _search_end)
+            {
+                return AIR_E_ENTRY_NOT_FOUND;
+            }
+            else
+            {
+                rc = _searchMacEntry(unit, AIR_L2_MAC_MS_NEXT, AIR_L2_MAC_MAT_MAC, &addr, &banks);
+            }
+        }
+
+        if ( FALSE == found_target )
+        {
+            /* Entry not bank */
+            return AIR_E_ENTRY_NOT_FOUND;
+        }
+        else
+        {
+            /* Found the target MAC entry, and try to search the next address */
+            rc = _searchMacEntry(unit, AIR_L2_MAC_MS_NEXT, AIR_L2_MAC_MAT_MAC, &addr, &banks);
+            if (AIR_E_OK == rc)
+            {
+                AIR_PRINT("banks=(%d)\n", banks);
+                if (0 == banks)
+                {
+                    return AIR_E_ENTRY_NOT_FOUND;
+                }
+                for (i = 0; i < AIR_L2_MAC_SET_NUM; i++)
+                {
+                    if (!!BITS_OFF_R(banks, i, 1))
+                    {
+                        /* Found a valid MAC entry */
+                        /* Select bank */
+                        _fill_MAC_ATRDS(unit, i);
+
+                        /* Read MAC entry */
+                        memset(&mt_read, 0, sizeof(AIR_MAC_ENTRY_T));
+                        rc = _read_MAC_ATRD(unit, &mt_read);
+                        if (AIR_E_OK != rc)
+                        {
+                            AIR_PRINT("rc=(%d)\n", rc);
+                            continue;
+                        }
+                        memcpy(&ptr_mac_entry[(*ptr_count)], &mt_read, sizeof(AIR_MAC_ENTRY_T));
+                        /* Translate port bitmap type */
+                        (*ptr_count)++;
+                    }
+                }
+                return AIR_E_OK;
+            }
+            else
+            {
+                AIR_PRINT("rc=(%d)\n", rc);
+                return AIR_E_ENTRY_NOT_FOUND;
+            }
+        }
+    }
+    else
+    {
+        /* MAC address is empty, means to search next entry */
+        rc = _searchMacEntry(unit, AIR_L2_MAC_MS_NEXT, AIR_L2_MAC_MAT_MAC, &addr, &banks);
+        if (AIR_E_OK == rc)
+        {
+            AIR_PRINT("banks=(%d)\n", banks);
+            if (0 == banks)
+            {
+                return AIR_E_ENTRY_NOT_FOUND;
+            }
+            for (i = 0; i < AIR_L2_MAC_SET_NUM; i++)
+            {
+                if (!!BITS_OFF_R(banks, i, 1))
+                {
+                    /* Found a valid MAC entry */
+                    /* Select bank */
+                    _fill_MAC_ATRDS(unit, i);
+
+                    /* Read MAC entry */
+                    memset(&mt_read, 0, sizeof(AIR_MAC_ENTRY_T));
+                    rc = _read_MAC_ATRD(unit, &mt_read);
+                    if (AIR_E_OK != rc)
+                    {
+                        AIR_PRINT("rc=(%d)\n", rc);
+                        continue;
+                    }
+                    memcpy(&ptr_mac_entry[(*ptr_count)], &mt_read, sizeof(AIR_MAC_ENTRY_T));
+                    /* Translate port bitmap type */
+                    (*ptr_count)++;
+                }
+            }
+            return AIR_E_OK;
+        }
+        else
+        {
+            AIR_PRINT("rc=(%d)\n", rc);
+            return AIR_E_ENTRY_NOT_FOUND;
+        }
+    }
+}
+
+/* FUNCTION NAME: air_l2_clearMacAddr
+ * PURPOSE:
+ *      Clear all L2 unicast MAC address entry.
+ *
+ * INPUT:
+ *      unit            --  Device ID
+ *
+ * OUTPUT:
+ *      None
+ *
+ * RETURN:
+ *      AIR_E_OK
+ *      AIR_E_BAD_PARAMETER
+ *
+ * NOTES:
+ *      None
+ */
+AIR_ERROR_NO_T
+air_l2_clearMacAddr(
+    const UI32_T unit)
+{
+    UI32_T u32dat = 0;
+
+    /* parameter sanity check */
+    AIR_PARAM_CHK((unit >= AIR_MAX_NUM_OF_UNIT), AIR_E_BAD_PARAMETER);
+    /* Write data by ATC to clear all MAC address entries */
+    u32dat = (ATC_SAT_MAC | ATC_CMD_CLEAN | ATC_START_BUSY);
+    aml_writeReg(unit, ATC, u32dat);
+    if (AIR_E_TIMEOUT == _checkL2Busy(unit))
+    {
+        return AIR_E_TIMEOUT;
+    }
+
+    return AIR_E_OK;
+}
+
+/* FUNCTION NAME:   air_l2_setMacAddrAgeOut
+ * PURPOSE:
+ *      Set the age out time of L2 MAC address entries.
+ * INPUT:
+ *      unit                     -- Device ID
+ *      age_time                 -- Age out time (second)
+ *                                  (1..AIR_L2_MAC_MAX_AGE_OUT_TIME)
+ * OUTPUT:
+ *      None
+ * RETURN:
+ *      AIR_E_OK                 -- Operation success.
+ *      AIR_E_BAD_PARAMETER      -- Parameter is wrong.
+ * NOTES:
+ *      None
+ */
+
+AIR_ERROR_NO_T
+air_l2_setMacAddrAgeOut(
+    const UI32_T    unit,
+    const UI32_T    age_time)
+{
+    
+    UI32_T u32dat = 0;
+    UI32_T age_cnt = 0, age_unit = 0, age_value = 0;
+    /* parameter sanity check */
+    AIR_PARAM_CHK((unit >= AIR_MAX_NUM_OF_UNIT), AIR_E_BAD_PARAMETER);
+    AIR_PARAM_CHK(((age_time > AIR_L2_MAC_MAX_AGE_OUT_TIME) || (age_time < 1)), AIR_E_BAD_PARAMETER);
+
+    /* Read the old register value */
+    aml_readReg(unit, AAC, &u32dat);
+
+    u32dat &= ~ BITS_RANGE(AAC_AGE_UNIT_OFFSET, AAC_AGE_UNIT_LENGTH);
+    u32dat &= ~ BITS_RANGE(AAC_AGE_CNT_OFFSET, AAC_AGE_CNT_LENGTH);
+
+    /* Calcuate the aging count/unit */
+    age_value = age_time * AIR_L2_AGING_1000MS / AIR_L2_AGING_MS_CONSTANT;
+    age_unit = (age_value / BIT(AAC_AGE_CNT_LENGTH) + 1);
+    age_cnt = (age_value / age_unit + 1);
+
+    /* Write the new register value */
+    u32dat |= BITS_OFF_L((age_unit - 1), AAC_AGE_UNIT_OFFSET, AAC_AGE_UNIT_LENGTH);
+    u32dat |= BITS_OFF_L((age_cnt - 1), AAC_AGE_CNT_OFFSET, AAC_AGE_CNT_LENGTH);
+
+    aml_writeReg(unit, AAC, u32dat);
+
+    return AIR_E_OK;
+}
+
+/* FUNCTION NAME:   air_l2_getMacAddrAgeOut
+ * PURPOSE:
+ *      Get the age out time of unicast MAC address.
+ * INPUT:
+ *      unit                     -- Device ID
+ * OUTPUT:
+ *      ptr_age_time             -- age out time
+ * RETURN:
+ *      AIR_E_OK                 -- Operation success.
+ *      AIR_E_BAD_PARAMETER      -- Parameter is wrong.
+ * NOTES:
+ *      None
+ */
+AIR_ERROR_NO_T
+air_l2_getMacAddrAgeOut(
+    const UI32_T    unit,
+    UI32_T          *ptr_age_time)
+{
+    UI32_T u32dat = 0;
+    UI32_T age_cnt = 0, age_unit = 0;
+    /* parameter sanity check */
+    AIR_PARAM_CHK((unit >= AIR_MAX_NUM_OF_UNIT), AIR_E_BAD_PARAMETER);
+    AIR_CHECK_PTR(ptr_age_time);
+
+    /* Read data from register */
+    aml_readReg(unit, AAC, &u32dat);
+
+    age_cnt = BITS_OFF_R(u32dat, AAC_AGE_CNT_OFFSET, AAC_AGE_CNT_LENGTH);
+    age_unit = BITS_OFF_R(u32dat, AAC_AGE_UNIT_OFFSET, AAC_AGE_UNIT_LENGTH);
+    (*ptr_age_time) = AIR_L2_AGING_TIME(age_cnt, age_unit);
+
+    return AIR_E_OK;
+}
+
+/* FUNCTION NAME: air_l2_setAgeEnable
+ * PURPOSE:
+ *      Set aging state for a specific port.
+ *
+ * INPUT:
+ *      unit            --  Device ID
+ *      port            --  Index of port number
+ *      state           --  FALSE:Disable
+ *                          TRUE: Enable
+ * OUTPUT:
+ *      None
+ *
+ * RETURN:
+ *      AIR_E_OK
+ *      AIR_E_BAD_PARAMETER
+ *
+ * NOTES:
+ *      None
+ */
+AIR_ERROR_NO_T
+air_l2_setAgeEnable(
+    const UI32_T unit,
+    const UI32_T port,
+    const BOOL_T state)
+{
+    UI32_T u32dat = 0;
+
+    /* Mistake proofing for port checking */
+    AIR_PARAM_CHK((port >= AIR_MAX_NUM_OF_PORTS), AIR_E_BAD_PARAMETER);
+    AIR_PARAM_CHK(((TRUE != state) && (FALSE != state)), AIR_E_BAD_PARAMETER);
+
+    aml_readReg(unit, AGDIS, &u32dat);
+    if (state)
+    {
+        u32dat &= ~BIT(port);
+    }
+    else
+    {
+        u32dat |= BIT(port);
+    }
+    aml_writeReg(unit, AGDIS, u32dat);
+
+    return AIR_E_OK;
+}
+
+/* FUNCTION NAME: air_l2_getAgeEnable
+ * PURPOSE:
+ *      Get age state for a specific port.
+ *
+ * INPUT:
+ *      unit            --  Device ID
+ *      port            --  Index of port number
+ *
+ * OUTPUT:
+ *      ptr_state       --  FALSE:Disable
+ *                          TRUE: Enable
+ * RETURN:
+ *      AIR_E_OK
+ *      AIR_E_BAD_PARAMETER
+ *
+ * NOTES:
+ *      None
+ */
+AIR_ERROR_NO_T
+air_l2_getAgeEnable(
+    const UI32_T unit,
+    const UI32_T port,
+    UI32_T *ptr_state)
+{
+    UI32_T u32dat = 0;
+
+    /* Mistake proofing for port checking */
+    AIR_PARAM_CHK((port >= AIR_MAX_NUM_OF_PORTS), AIR_E_BAD_PARAMETER);
+
+    /* Mistake proofing for state checking */
+    AIR_CHECK_PTR(ptr_state);
+
+    /* Read data from register */
+    aml_readReg(unit, AGDIS, &u32dat);
+
+    (*ptr_state) = (u32dat & BIT(port)) ? TRUE : FALSE;
+
+    return AIR_E_OK;
+}
+
diff --git a/recipes-devtools/switch/files/src/an8855_sdk/api/src/air_lag.c b/recipes-devtools/switch/files/src/an8855_sdk/api/src/air_lag.c
new file mode 100644
index 0000000..d3f4e14
--- /dev/null
+++ b/recipes-devtools/switch/files/src/an8855_sdk/api/src/air_lag.c
@@ -0,0 +1,530 @@
+/* FILE NAME:  air_lag.c
+ * PURPOSE:
+ *      Define the Link Agrregation function in AIR SDK.
+ *
+ * NOTES:
+ *      None
+ */
+
+/* INCLUDE FILE DECLARATIONS
+*/
+#include "air.h"
+
+/* NAMING CONSTANT DECLARATIONS
+*/
+
+/* MACRO FUNCTION DECLARATIONS
+*/
+
+/* DATA TYPE DECLARATIONS
+*/
+
+/* GLOBAL VARIABLE DECLARATIONS
+*/
+
+/* LOCAL SUBPROGRAM DECLARATIONS
+*/
+
+/* STATIC VARIABLE DECLARATIONS
+*/
+
+/* LOCAL SUBPROGRAM BODIES
+*/
+
+/* EXPORTED SUBPROGRAM BODIES
+*/
+
+/* FUNCTION NAME: air_lag_setMember
+ * PURPOSE:
+ *      Set LAG member(s) for a specific LAG port.
+ *
+ * INPUT:
+ *      unit            --  Device ID
+ *      ptg_index       --  Port trunk index
+ *      mem_index       --  Member index
+ *      mem_en          --  enable Member
+ *      port_index      --  Member port
+ *
+ * OUTPUT:
+ *      None
+ *
+ * RETURN:
+ *      AIR_E_OK
+ *      AIR_E_BAD_PARAMETER
+ *
+ * NOTES:
+ *      None
+ */
+AIR_ERROR_NO_T
+air_lag_setMember(
+    const UI32_T        unit,
+    const UI32_T        ptg_index,
+    const UI32_T        mem_index,
+    const UI32_T        mem_en,
+    const UI32_T        port_index)
+{
+    UI32_T val = 0;
+    UI32_T i = 0, offset = 0;
+    UI32_T reg = 0;
+
+    /* Mistake proofing */
+    AIR_PARAM_CHK((ptg_index >= AIR_LAG_MAX_PTG_NUM), AIR_E_BAD_PARAMETER);
+    AIR_PARAM_CHK((mem_index > AIR_LAG_MAX_MEM_NUM), AIR_E_BAD_PARAMETER);
+    AIR_PARAM_CHK((mem_en !=0 && mem_en !=1), AIR_E_BAD_PARAMETER);
+    AIR_PARAM_CHK((port_index > AIR_MAX_NUM_OF_PORTS), AIR_E_BAD_PARAMETER);
+
+    offset = mem_index;
+    reg = (UI32_T)PTG(ptg_index);
+
+    AIR_PRINT("PTC REG:%x.\n", reg);
+
+    aml_readReg(unit,reg, &val);
+    AIR_PRINT("PTC REG val:%x.---1\n", val);
+    if(mem_en == 0)
+    {
+        val = val & ~(BIT(7 + 8*offset)); //port turnk group ptg_index; port port_index
+    }
+    else
+    {
+        val = val  | (BIT(7 + 8*offset)); //port turnk group ptg_index; port port_index
+    }
+    AIR_PRINT("PTC REG val:%x.----2\n", val);
+    val = val & ~( 0x1F << 8*offset);
+    val = val | AIR_GRP_PORT(port_index,offset); //port turnk group ptg_index; port port_index
+    AIR_PRINT("PTC REG val:%x. port %d----3\n", val,port_index);
+
+    aml_writeReg(unit, reg, val);
+
+    return AIR_E_OK;
+}
+
+/* FUNCTION NAME: air_lag_getMember
+ * PURPOSE:
+ *      Get LAG member count.
+ *
+ * INPUT:
+ *      unit            --  Device ID
+ *      ptg_index       --  Port trunk index
+ *
+ * OUTPUT:
+ *      member      --  Member ports of  one port trunk
+ *
+ * RETURN:
+ *      AIR_E_OK
+ *      AIR_E_BAD_PARAMETER
+ *
+ * NOTES:
+ *      None
+ */
+AIR_ERROR_NO_T
+air_lag_getMember(
+    const UI32_T unit,
+    const UI32_T ptg_index,
+    AIR_LAG_PTGINFO_T * member)
+{
+    UI32_T val0 = 0, val1 = 0, i = 0, offset = 0;
+
+    /* Mistake proofing */
+    AIR_PARAM_CHK((ptg_index >= AIR_LAG_MAX_PTG_NUM), AIR_E_BAD_PARAMETER);
+
+    /* Mistake proofing */
+    AIR_CHECK_PTR(member);
+    aml_readReg(unit, (UI32_T)PTG(ptg_index), &val0);
+
+    for(i = 0; i < AIR_LAG_MAX_MEM_NUM; i++){
+        member->csr_gp_enable[i] = (UI32_T)BITS_OFF_R(val0, 7 + 8*i, 1);
+        member->csr_gp_port[i] = (UI32_T)BITS_OFF_R(val0, 8*i, 5);
+    }
+
+    return AIR_E_OK;
+}
+
+/* FUNCTION NAME: air_lag_set_ptgc_state
+ * PURPOSE:
+ *     set port trunk group control state.
+ *
+ * INPUT:
+ *      unit            --  Device ID
+ *      ptgc_enable     --  enabble or disable port trunk function
+ *
+ * OUTPUT:
+ *      none
+ *
+ * RETURN:
+ *      AIR_E_OK
+ *      AIR_E_BAD_PARAMETER
+ *
+ * NOTES:
+ *      None
+ */
+AIR_ERROR_NO_T
+air_lag_set_ptgc_state(
+    const UI32_T unit,
+    const BOOL_T ptgc_enable)
+{
+    /* Mistake proofing */
+    AIR_PARAM_CHK(((TRUE != ptgc_enable) && (FALSE != ptgc_enable)), AIR_E_BAD_PARAMETER);
+
+    aml_writeReg(unit, PTGC, ptgc_enable);
+
+    return AIR_E_OK;
+}
+
+/* FUNCTION NAME: air_lag_get_ptgc_state
+ * PURPOSE:
+ *      Get port trunk group control state.
+ *
+ * INPUT:
+ *      unit            --  Device ID
+ *
+ * OUTPUT:
+ *      ptr_state        --  port trunk fucntion is enable or disable
+ *
+ * RETURN:
+ *      AIR_E_OK
+ *      AIR_E_BAD_PARAMETER
+ *
+ * NOTES:
+ *      None
+ */
+AIR_ERROR_NO_T
+air_lag_get_ptgc_state(
+    const UI32_T unit,
+    UI32_T *ptr_state)
+{
+    UI32_T u32dat = 0;
+    
+    AIR_CHECK_PTR(ptr_state);
+    aml_readReg(unit, PTGC, &u32dat);
+    (*ptr_state) = BITS_OFF_R(u32dat, 0, 1);
+
+    return AIR_E_OK;
+}
+
+
+/* FUNCTION NAME: air_lag_setDstInfo
+ * PURPOSE:
+ *      Set information for the packet distribution.
+ *
+ * INPUT:
+ *      unit            --  Device ID
+ *      dstInfo         --  Infomation selection of packet distribution
+ *
+ * OUTPUT:
+ *      None
+ *
+ * RETURN:
+ *      AIR_E_OK
+ *      AIR_E_BAD_PARAMETER
+ *      AIR_E_TIMEOUT
+ *
+ * NOTES:
+ *      None
+ */
+AIR_ERROR_NO_T
+air_lag_setDstInfo(
+    const UI32_T unit,
+    const AIR_LAG_DISTINFO_T dstInfo)
+{
+    UI32_T val = 0;
+    aml_readReg(unit, (UI32_T)PTC, &val);
+
+    /* Set infomation control bit map */
+    val = val & ~ BITS(0,6);
+    if(dstInfo.sp)
+    {
+        val |= PTC_INFO_SEL_SP;
+    }
+    if(dstInfo.sa)
+    {
+        val |= PTC_INFO_SEL_SA;
+    }
+    if(dstInfo.da)
+    {
+        val |= PTC_INFO_SEL_DA;
+    }
+    if(dstInfo.sip)
+    {
+        val |= PTC_INFO_SEL_SIP;
+    }
+    if(dstInfo.dip)
+    {
+        val |= PTC_INFO_SEL_DIP;
+    }
+    if(dstInfo.sport)
+    {
+        val |= PTC_INFO_SEL_SPORT;
+    }
+    if(dstInfo.dport)
+    {
+        val |= PTC_INFO_SEL_DPORT;
+    }
+
+    /* Write register */
+    aml_writeReg(unit, (UI32_T)PTC, val);
+
+    return AIR_E_OK;
+}
+
+/* FUNCTION NAME: air_lag_getDstInfo
+ * PURPOSE:
+ *      Set port trunk hashtype.
+ *
+ * INPUT:
+ *      unit            --  Device ID
+ *
+ * OUTPUT:
+ *      ptr_dstInfo     --  Infomation selection of packet distribution
+ *
+ * RETURN:
+ *      AIR_E_OK
+ *      AIR_E_BAD_PARAMETER
+ *      AIR_E_TIMEOUT
+ *
+ * NOTES:
+ *      None
+ */
+AIR_ERROR_NO_T
+air_lag_getDstInfo(
+    const UI32_T unit,
+    AIR_LAG_DISTINFO_T *ptr_dstInfo)
+{
+    UI32_T val = 0;
+
+    /* Mistake proofing */
+    AIR_CHECK_PTR(ptr_dstInfo);
+
+    /* Get infomation control bit map */
+    aml_readReg(unit, (UI32_T)PTC, &val);
+    if(val & PTC_INFO_SEL_SP)
+    {
+        ptr_dstInfo ->sp = 1;
+    }
+    if(val & PTC_INFO_SEL_SA)
+    {
+        ptr_dstInfo ->sa = 1;
+    }
+    if(val & PTC_INFO_SEL_DA)
+    {
+        ptr_dstInfo ->da = 1;
+    }
+    if(val & PTC_INFO_SEL_SIP)
+    {
+        ptr_dstInfo ->sip = 1;
+    }
+    if(val & PTC_INFO_SEL_DIP)
+    {
+        ptr_dstInfo ->dip = 1;
+    }
+    if(val & PTC_INFO_SEL_SPORT)
+    {
+        ptr_dstInfo ->sport = 1;
+    }
+    if(val & PTC_INFO_SEL_DPORT)
+    {
+        ptr_dstInfo ->dport = 1;
+    }
+
+    return AIR_E_OK;
+}
+
+
+/* FUNCTION NAME: air_lag_setState
+ * PURPOSE:
+ *      Set the enable/disable for a specific LAG port.
+ *
+ * INPUT:
+ *      unit            --  Device ID
+ *      hashtype        --  crc32msb/crc32lsb/crc16/xor4
+ * OUTPUT:
+ *      None
+ *
+ * RETURN:
+ *      AIR_E_OK
+ *      AIR_E_BAD_PARAMETER
+ *
+ * NOTES:
+ *      None
+ */
+AIR_ERROR_NO_T
+air_lag_sethashtype(
+    const UI32_T unit,
+    const UI32_T hashtype)
+{
+    UI32_T val = 0;
+
+    /* Mistake proofing */
+    AIR_PARAM_CHK((hashtype > 3), AIR_E_BAD_PARAMETER);
+
+    /* Read data from register */
+    aml_readReg(unit, (UI32_T)PTC, &val);
+    
+    val = val & ~ BITS(8,9);
+    val |= hashtype << 8;
+    
+    aml_writeReg(unit, (UI32_T)PTC, val);
+
+    return AIR_E_OK;
+}
+
+/* FUNCTION NAME: air_lag_getState
+ * PURPOSE:
+ *      Get port trunk hashtype.
+ *
+ * INPUT:
+ *      unit            --  Device ID
+ *
+ * OUTPUT:
+ *      hashtype        --  crc32msb/crc32lsb/crc16/xor4
+ * RETURN:
+ *      AIR_E_OK
+ *      AIR_E_BAD_PARAMETER
+ *
+ * NOTES:
+ *      None
+ */
+AIR_ERROR_NO_T
+air_lag_gethashtype(
+    const UI32_T unit,
+    UI32_T *hashtype)
+{
+    UI32_T val = 0;
+
+    /* Mistake proofing */
+    AIR_CHECK_PTR(hashtype);
+
+    /* Read data from register */
+    aml_readReg(unit, (UI32_T)PTC, &val);
+    (*hashtype) = BITS_OFF_R(val, 8, 9);
+
+    return AIR_E_OK;
+}
+
+/* FUNCTION NAME: air_lag_setSpSel
+ * PURPOSE:
+ *      Set the enable/disable for selection source port composition.
+ *
+ * INPUT:
+ *      unit            --  Device ID
+ *      enable          --  enable or disable source port compare
+ * OUTPUT:
+ *      None
+ *
+ * RETURN:
+ *      AIR_E_OK
+ *      AIR_E_BAD_PARAMETER
+ *
+ * NOTES:
+ *      None
+ */
+AIR_ERROR_NO_T
+air_lag_setSpSel(
+    const UI32_T unit,
+    const BOOL_T spsel_enable)
+{
+    UI32_T val = 0;
+
+    /* Mistake proofing */
+    AIR_PARAM_CHK(((TRUE != spsel_enable) && (FALSE != spsel_enable)), AIR_E_BAD_PARAMETER);
+
+    /* Read data from register */
+    aml_readReg(unit, (UI32_T)PTC, &val);
+    val = val & ~ BIT(20);
+    val |= spsel_enable << 20;
+    aml_writeReg(unit, (UI32_T)PTC, val);
+
+    return AIR_E_OK;
+}
+
+/* FUNCTION NAME: air_lag_getSpSel
+ * PURPOSE:
+ *      Get selection source port composition.
+ *
+ * INPUT:
+ *      unit            --  Device ID
+ *
+ * OUTPUT:
+ *      ptr_state       --  source port compare is enable or disable
+ * RETURN:
+ *      AIR_E_OK
+ *      AIR_E_BAD_PARAMETER
+ *
+ * NOTES:
+ *      None
+ */
+AIR_ERROR_NO_T
+air_lag_getSpSel(
+    const UI32_T unit,
+    UI32_T *ptr_state)
+{
+    UI32_T val = 0;
+
+    /* Mistake proofing */
+    AIR_CHECK_PTR(ptr_state);
+
+    /* Read data from register */
+    AIR_CHECK_PTR(ptr_state);
+    aml_readReg(unit, PTC, &val);
+    (*ptr_state) = val & BIT(20);
+
+    return AIR_E_OK;
+}
+
+/* FUNCTION NAME: air_lag_setPTSeed
+ * PURPOSE:
+ *      Set the enable/disable for a specific LAG port.
+ *
+ * INPUT:
+ *      unit            --  Device ID
+ *      ptseed          --  port trunk rand seed
+ * OUTPUT:
+ *      None
+ *
+ * RETURN:
+ *      AIR_E_OK
+ *      AIR_E_BAD_PARAMETER
+ *
+ * NOTES:
+ *      None
+ */
+AIR_ERROR_NO_T
+air_lag_setPTSeed(
+    const UI32_T unit,
+    const UI32_T ptseed)
+{
+    aml_writeReg(unit, (UI32_T)PTSEED, ptseed);
+    return AIR_E_OK;
+}
+
+/* FUNCTION NAME: air_lag_getPTSeed
+ * PURPOSE:
+ *      Get port trunk hashtype.
+ *
+ * INPUT:
+ *      unit            --  Device ID
+ *
+ * OUTPUT:
+ *      ptseed          --  port trunk rand seed
+ * RETURN:
+ *      AIR_E_OK
+ *      AIR_E_BAD_PARAMETER
+ *
+ * NOTES:
+ *      None
+ */
+AIR_ERROR_NO_T
+air_lag_getPTSeed(
+    const UI32_T unit,
+    UI32_T *ptseed)
+{
+    UI32_T val = 0;
+
+    /* Mistake proofing */
+    AIR_CHECK_PTR(ptseed);
+
+    /* Read data from register */
+    aml_readReg(unit, (UI32_T)PTSEED, ptseed);
+
+    return AIR_E_OK;
+}
+
diff --git a/recipes-devtools/switch/files/src/an8855_sdk/api/src/air_led.c b/recipes-devtools/switch/files/src/an8855_sdk/api/src/air_led.c
new file mode 100644
index 0000000..d89caa9
--- /dev/null
+++ b/recipes-devtools/switch/files/src/an8855_sdk/api/src/air_led.c
@@ -0,0 +1,528 @@
+/* FILE NAME: air_led.c
+ * PURPOSE:
+ *      Define the LED function in AIR SDK.
+ *
+ * NOTES:
+ *      None
+ */
+
+/* INCLUDE FILE DECLARATIONS
+*/
+#include "air.h"
+
+/* NAMING CONSTANT DECLARATIONS
+*/
+
+/* MACRO FUNCTION DECLARATIONS
+*/
+#define LED_SET_EVT(evt, reg, bit)          \
+    do{                                     \
+        if( TRUE == evt)                    \
+        {                                   \
+            reg |= bit;                     \
+        }                                   \
+    }while(0)
+
+/* DATA TYPE DECLARATIONS
+*/
+
+/* GLOBAL VARIABLE DECLARATIONS
+*/
+
+/* LOCAL SUBPROGRAM DECLARATIONS
+*/
+
+/* STATIC VARIABLE DECLARATIONS
+*/
+
+/* LOCAL SUBPROGRAM BODIES
+*/
+
+/* EXPORTED SUBPROGRAM BODIES
+*/
+/* FUNCTION NAME: air_led_setMode
+ * PURPOSE:
+ *      Set the LED processing mode for a specific port.
+ *
+ * INPUT:
+ *      unit            --  Device ID
+ *      port            --  Index of port number
+ *      mode            --  Setting mode of LED
+ *
+ * OUTPUT:
+ *      None
+ *
+ * RETURN:
+ *      AIR_E_OK
+ *      AIR_E_BAD_PARAMETER
+ *
+ * NOTES:
+ *      The LED control register is shared with all port on AN8855.
+ *      Setting LED on any one port will also set to each other ports.
+ */
+AIR_ERROR_NO_T
+air_led_setMode(
+    const UI32_T unit,
+    const UI8_T port,
+    const AIR_LED_MODE_T mode)
+{
+    UI32_T u32dat = 0;
+
+    /* Mistake proofing */
+    AIR_PARAM_CHK( ( port >= AIR_MAX_NUM_OF_GIGA_PORTS ), AIR_E_BAD_PARAMETER );
+    AIR_PARAM_CHK( ( mode >= AIR_LED_BLK_DUR_LAST ), AIR_E_BAD_PARAMETER );
+
+    /* Read data from register */
+    aml_readPhyRegCL45( unit, port, 0x1f, LED_BCR, &u32dat );
+
+    /* Set LED mode */
+    switch( mode )
+    {
+        case AIR_LED_MODE_DISABLE:
+            u32dat &= ~LED_BCR_EXT_CTRL;
+            u32dat &= ~LED_BCR_MODE_MASK;
+            u32dat |= LED_BCR_MODE_DISABLE;
+            break;
+        case AIR_LED_MODE_2LED_MODE0:
+            u32dat &= ~LED_BCR_EXT_CTRL;
+            u32dat &= ~LED_BCR_MODE_MASK;
+            u32dat |= LED_BCR_MODE_2LED;
+            break;
+        case AIR_LED_MODE_2LED_MODE1:
+            u32dat &= ~LED_BCR_EXT_CTRL;
+            u32dat &= ~LED_BCR_MODE_MASK;
+            u32dat |= LED_BCR_MODE_3LED_1;
+            break;
+        case AIR_LED_MODE_2LED_MODE2:
+            u32dat &= ~LED_BCR_EXT_CTRL;
+            u32dat &= ~LED_BCR_MODE_MASK;
+            u32dat |= LED_BCR_MODE_3LED_2;
+            break;
+        case AIR_LED_MODE_USER_DEFINE:
+            u32dat |= LED_BCR_EXT_CTRL;
+            break;
+    }
+
+    /* Write data to register */
+    aml_writePhyRegCL45( unit, port, 0x1f, LED_BCR, u32dat );
+
+    return AIR_E_OK;
+}
+
+/* FUNCTION NAME:air_led_getMode
+ * PURPOSE:
+ *      Get the LED processing mode for a specific port.
+ *
+ * INPUT:
+ *      unit            --  Device ID
+ *      port            --  Index of port number
+ *
+ * OUTPUT:
+ *      ptr_mode        --  Setting mode of LED
+ *
+ * RETURN:
+ *      AIR_E_OK
+ *      AIR_E_OTHERS
+ *      AIR_E_BAD_PARAMETER
+ *
+ * NOTES:
+ *      None
+ */
+AIR_ERROR_NO_T
+air_led_getMode(
+    const UI32_T unit,
+    const UI8_T port,
+    AIR_LED_MODE_T *ptr_mode)
+{
+    UI32_T u32dat = 0;
+
+    /* Mistake proofing */
+    AIR_PARAM_CHK( ( port >= AIR_MAX_NUM_OF_GIGA_PORTS ), AIR_E_BAD_PARAMETER );
+    AIR_CHECK_PTR( ptr_mode );
+
+    /* Read data from register */
+    aml_readPhyRegCL45( unit, port, 0x1f, LED_BCR, &u32dat );
+
+    /* Get LED mode */
+    if( LED_BCR_EXT_CTRL & u32dat )
+    {
+        (*ptr_mode ) = AIR_LED_MODE_USER_DEFINE;
+    }
+    else
+    {
+        switch( u32dat & LED_BCR_MODE_MASK )
+        {
+            case LED_BCR_MODE_DISABLE:
+                (*ptr_mode ) = AIR_LED_MODE_DISABLE;
+                break;
+            case LED_BCR_MODE_2LED:
+                (*ptr_mode ) = AIR_LED_MODE_2LED_MODE0;
+                break;
+            case LED_BCR_MODE_3LED_1:
+                (*ptr_mode ) = AIR_LED_MODE_2LED_MODE1;
+                break;
+            case LED_BCR_MODE_3LED_2:
+                (*ptr_mode ) = AIR_LED_MODE_2LED_MODE2;
+                break;
+            default:
+                return AIR_E_OTHERS;
+        }
+    }
+
+    return AIR_E_OK;
+}
+
+/* FUNCTION NAME: air_led_setState
+ * PURPOSE:
+ *      Set the enable state for a specific LED.
+ *
+ * INPUT:
+ *      unit            --  Device ID
+ *      port            --  Index of port number
+ *      entity          --  Entity of LED
+ *      state           --  TRUE: Enable
+ *                          FALSE: Disable
+ * OUTPUT:
+ *      None
+ *
+ * RETURN:
+ *      AIR_E_OK
+ *      AIR_E_BAD_PARAMETER
+ *
+ * NOTES:
+ *      The LED control register is shared with all port on AN8855.
+ *      Setting LED on any one port will also set to each other ports.
+ */
+AIR_ERROR_NO_T
+air_led_setState(
+    const UI32_T unit,
+    const UI8_T port,
+    const UI8_T entity,
+    const BOOL_T state)
+{
+    UI32_T u32dat = 0;
+
+    /* Mistake proofing */
+    AIR_PARAM_CHK( ( port >= AIR_MAX_NUM_OF_GIGA_PORTS ), AIR_E_BAD_PARAMETER );
+    AIR_PARAM_CHK( ( entity >= MAX_NUM_LED_ENTITY ), AIR_E_BAD_PARAMETER );
+    AIR_PARAM_CHK( ( ( TRUE != state ) && ( FALSE != state ) ), AIR_E_BAD_PARAMETER );
+
+    /* Read data from register */
+    aml_readPhyRegCL45( unit, port, 0x1f, LED_ON_CTRL(entity), &u32dat );
+
+    /* Set LED state */
+    if( TRUE == state)
+    {
+        u32dat |= LED_ON_EN;
+    }
+    else
+    {
+        u32dat &= ~LED_ON_EN;
+    }
+
+    /* Write data to register */
+    aml_writePhyRegCL45( unit, port, 0x1f, LED_ON_CTRL(entity), u32dat );
+
+    return AIR_E_OK;
+}
+
+/* FUNCTION NAME: air_led_getState
+ * PURPOSE:
+ *      Get the enable state for a specific LED.
+ *
+ * INPUT:
+ *      unit            --  Device ID
+ *      port            --  Index of port number
+ *      entity          --  Entity of LED
+ *
+ * OUTPUT:
+ *      ptr_state       --  TRUE: Enable
+ *                          FALSE: Disable
+ * RETURN:
+ *      AIR_E_OK
+ *      AIR_E_BAD_PARAMETER
+ *
+ * NOTES:
+ *      None
+ */
+AIR_ERROR_NO_T
+air_led_getState(
+    const UI32_T unit,
+    const UI8_T port,
+    const UI8_T entity,
+    BOOL_T *ptr_state)
+{
+    UI32_T u32dat = 0;
+
+    /* Mistake proofing */
+    AIR_PARAM_CHK( ( port >= AIR_MAX_NUM_OF_GIGA_PORTS ), AIR_E_BAD_PARAMETER );
+    AIR_PARAM_CHK( ( entity >= MAX_NUM_LED_ENTITY ), AIR_E_BAD_PARAMETER );
+    AIR_CHECK_PTR( ptr_state );
+
+    /* Read data from register */
+    aml_readPhyRegCL45( unit, port, 0x1f, LED_ON_CTRL(entity), &u32dat );
+
+    /* Get LED state */
+    (*ptr_state) = ( LED_ON_EN & u32dat )?TRUE:FALSE;
+
+    return AIR_E_OK;
+}
+
+/* FUNCTION NAME: air_led_setUsrDef
+ * PURPOSE:
+ *      Set the user-defined configuration of a speficic LED.
+ *      It only work when air_led_setState() set to AIR_LED_MODE_USER_DEFINE.
+ *
+ * INPUT:
+ *      unit            --  Device ID
+ *      port            --  Index of port number
+ *      entity          --  Entity of LED
+ *      polar           --  LOW: Active low
+ *                          HIGH: Active high
+ *      on_evt          --  AIR_LED_ON_EVT_T
+ *                          LED turns on if any event is detected
+ *      blk_evt         --  AIR_LED_BLK_EVT_T
+ *                          LED blinks blink if any event is detected
+ * OUTPUT:
+ *      None
+ *
+ * RETURN:
+ *      AIR_E_OK
+ *      AIR_E_BAD_PARAMETER
+ *
+ * NOTES:
+ *      The LED control register is shared with all port on AN8855.
+ *      Setting LED on any one port will also set to each other ports.
+ */
+AIR_ERROR_NO_T
+air_led_setUsrDef(
+    const UI32_T unit,
+    const UI8_T port,
+    const UI8_T entity,
+    const BOOL_T polar,
+    const AIR_LED_ON_EVT_T on_evt,
+    const AIR_LED_BLK_EVT_T blk_evt)
+{
+    UI32_T on_reg = 0;
+    UI32_T blk_reg = 0;
+
+    /* Mistake proofing */
+    AIR_PARAM_CHK( ( port >= AIR_MAX_NUM_OF_GIGA_PORTS ), AIR_E_BAD_PARAMETER );
+    AIR_PARAM_CHK( ( entity >= MAX_NUM_LED_ENTITY ), AIR_E_BAD_PARAMETER );
+    AIR_PARAM_CHK( ( ( HIGH != polar ) && ( LOW != polar ) ), AIR_E_BAD_PARAMETER );
+
+    /* Read data from register */
+    aml_readPhyRegCL45( unit, port, 0x1f, LED_ON_CTRL(entity), &on_reg );
+    aml_readPhyRegCL45( unit, port, 0x1f, LED_BLK_CTRL(entity), &blk_reg );
+
+    /* Set LED polarity */
+    if( HIGH == polar)
+    {
+        on_reg |= LED_ON_POL;
+    }
+    else
+    {
+        on_reg &= ~LED_ON_POL;
+    }
+
+    /* Set LED On Event */
+    on_reg &= ~LED_ON_EVT_MASK;
+    LED_SET_EVT(on_evt.link_1000m, on_reg, LED_ON_EVT_LINK_1000M);
+    LED_SET_EVT(on_evt.link_100m, on_reg, LED_ON_EVT_LINK_100M);
+    LED_SET_EVT(on_evt.link_10m, on_reg, LED_ON_EVT_LINK_10M);
+    LED_SET_EVT(on_evt.link_dn, on_reg, LED_ON_EVT_LINK_DN);
+    LED_SET_EVT(on_evt.fdx, on_reg, LED_ON_EVT_FDX);
+    LED_SET_EVT(on_evt.hdx, on_reg, LED_ON_EVT_HDX);
+    LED_SET_EVT(on_evt.force, on_reg, LED_ON_EVT_FORCE);
+
+    /* Set LED Blinking Event */
+    blk_reg &= ~LED_BLK_EVT_MASK;
+    LED_SET_EVT(blk_evt.tx_act_1000m, blk_reg, LED_BLK_EVT_1000M_TX_ACT);
+    LED_SET_EVT(blk_evt.rx_act_1000m, blk_reg, LED_BLK_EVT_1000M_RX_ACT);
+    LED_SET_EVT(blk_evt.tx_act_100m, blk_reg, LED_BLK_EVT_100M_TX_ACT);
+    LED_SET_EVT(blk_evt.rx_act_100m, blk_reg, LED_BLK_EVT_100M_RX_ACT);
+    LED_SET_EVT(blk_evt.tx_act_10m, blk_reg, LED_BLK_EVT_10M_TX_ACT);
+    LED_SET_EVT(blk_evt.rx_act_10m, blk_reg, LED_BLK_EVT_10M_RX_ACT);
+    LED_SET_EVT(blk_evt.cls, blk_reg, LED_BLK_EVT_CLS);
+    LED_SET_EVT(blk_evt.rx_crc, blk_reg, LED_BLK_EVT_RX_CRC);
+    LED_SET_EVT(blk_evt.rx_idle, blk_reg, LED_BLK_EVT_RX_IDL);
+    LED_SET_EVT(blk_evt.force, blk_reg, LED_BLK_EVT_FORCE);
+
+    /* Write data to register */
+    aml_writePhyRegCL45( unit, port, 0x1f, LED_ON_CTRL(entity), on_reg );
+    aml_writePhyRegCL45( unit, port, 0x1f, LED_BLK_CTRL(entity), blk_reg );
+
+    return AIR_E_OK;
+}
+
+/* FUNCTION NAME: air_led_getUsrDef
+ * PURPOSE:
+ *      Get the user-defined configuration of a speficic LED.
+ *
+ * INPUT:
+ *      unit            --  Device ID
+ *      port            --  Index of port number
+ *      entity          --  Entity of LED
+ * OUTPUT:
+ *      ptr_polar       --  LOW: Active low
+ *                          HIGH: Active high
+ *      ptr_on_evt      --  AIR_LED_ON_EVT_T
+ *                          LED turns on if any event is detected
+ *      ptr_blk_evt     --  AIR_LED_BLK_EVT_T
+ *                          LED blinks if any event is detected
+ * RETURN:
+ *      AIR_E_OK
+ *      AIR_E_BAD_PARAMETER
+ *
+ * NOTES:
+ *      None
+ */
+AIR_ERROR_NO_T
+air_led_getUsrDef(
+    const UI32_T unit,
+    const UI8_T port,
+    const UI8_T entity,
+    BOOL_T *ptr_polar,
+    AIR_LED_ON_EVT_T *ptr_on_evt,
+    AIR_LED_BLK_EVT_T *ptr_blk_evt)
+{
+    UI32_T on_reg = 0;
+    UI32_T blk_reg = 0;
+
+    /* Mistake proofing */
+    AIR_PARAM_CHK( ( port >= AIR_MAX_NUM_OF_GIGA_PORTS ), AIR_E_BAD_PARAMETER );
+    AIR_PARAM_CHK( ( entity >= MAX_NUM_LED_ENTITY ), AIR_E_BAD_PARAMETER );
+    AIR_CHECK_PTR( ptr_polar );
+    AIR_CHECK_PTR( ptr_on_evt );
+    AIR_CHECK_PTR( ptr_blk_evt );
+
+    /* Read data from register */
+    aml_readPhyRegCL45( unit, port, 0x1f, LED_ON_CTRL(entity), &on_reg );
+    aml_readPhyRegCL45( unit, port, 0x1f, LED_BLK_CTRL(entity), &blk_reg );
+
+    /* Get LED polarity */
+    (*ptr_polar) = ( on_reg & LED_ON_POL)?TRUE:FALSE;
+
+    /* Get LED On Event */
+    ptr_on_evt ->link_1000m = (on_reg & LED_ON_EVT_LINK_1000M)?TRUE:FALSE;
+    ptr_on_evt ->link_100m = (on_reg & LED_ON_EVT_LINK_100M)?TRUE:FALSE;
+    ptr_on_evt ->link_10m = (on_reg & LED_ON_EVT_LINK_10M)?TRUE:FALSE;
+    ptr_on_evt ->link_dn = (on_reg & LED_ON_EVT_LINK_DN)?TRUE:FALSE;
+    ptr_on_evt ->fdx = (on_reg & LED_ON_EVT_FDX)?TRUE:FALSE;
+    ptr_on_evt ->hdx = (on_reg & LED_ON_EVT_HDX)?TRUE:FALSE;
+    ptr_on_evt ->force = (on_reg & LED_ON_EVT_FORCE)?TRUE:FALSE;
+
+    /* Set LED Blinking Event */
+    ptr_blk_evt ->tx_act_1000m = (blk_reg & LED_BLK_EVT_1000M_TX_ACT)?TRUE:FALSE;
+    ptr_blk_evt ->rx_act_1000m = (blk_reg & LED_BLK_EVT_1000M_RX_ACT)?TRUE:FALSE;
+    ptr_blk_evt ->tx_act_100m = (blk_reg & LED_BLK_EVT_100M_TX_ACT)?TRUE:FALSE;
+    ptr_blk_evt ->rx_act_100m = (blk_reg & LED_BLK_EVT_100M_RX_ACT)?TRUE:FALSE;
+    ptr_blk_evt ->tx_act_10m = (blk_reg & LED_BLK_EVT_10M_TX_ACT)?TRUE:FALSE;
+    ptr_blk_evt ->rx_act_10m = (blk_reg & LED_BLK_EVT_10M_RX_ACT)?TRUE:FALSE;
+    ptr_blk_evt ->cls = (blk_reg & LED_BLK_EVT_CLS)?TRUE:FALSE;
+    ptr_blk_evt ->rx_crc = (blk_reg & LED_BLK_EVT_RX_CRC)?TRUE:FALSE;
+    ptr_blk_evt ->rx_idle = (blk_reg & LED_BLK_EVT_RX_IDL)?TRUE:FALSE;
+    ptr_blk_evt ->force = (blk_reg & LED_BLK_EVT_FORCE)?TRUE:FALSE;
+
+    return AIR_E_OK;
+}
+
+/* FUNCTION NAME: air_led_setBlkTime
+ * PURPOSE:
+ *      Set the Blinking duration of a speficic LED.
+ *      It only work when air_led_setState() set to AIR_LED_MODE_USER_DEFINE.
+ *
+ * INPUT:
+ *      unit            --  Device ID
+ *      port            --  Index of port number
+ *      dur             --  Blink duration
+ *
+ * OUTPUT:
+ *      None
+ *
+ * RETURN:
+ *      AIR_E_OK
+ *      AIR_E_BAD_PARAMETER
+ *
+ * NOTES:
+ *      The LED control register is shared with all port on AN8855.
+ *      Setting LED on any one port will also set to each other ports.
+ */
+AIR_ERROR_NO_T
+air_led_setBlkTime(
+    const UI32_T unit,
+    const UI8_T port,
+    const AIR_LED_BLK_DUR_T dur)
+{
+    UI32_T on_dur = 0;
+    UI32_T blk_dur = 0;
+
+    /* Mistake proofing */
+    AIR_PARAM_CHK( ( port >= AIR_MAX_NUM_OF_GIGA_PORTS ), AIR_E_BAD_PARAMETER );
+    AIR_PARAM_CHK( ( dur >= AIR_LED_BLK_DUR_LAST ), AIR_E_BAD_PARAMETER );
+
+    /* Read data from register */
+    aml_readPhyRegCL45( unit, port, 0x1f, LED_ON_DUR, &on_dur );
+    aml_readPhyRegCL45( unit, port, 0x1f, LED_BLK_DUR, &blk_dur );
+
+    /* Set LED Blinking duration */
+    /* Setting unit = 32ms, register unit = 32.768 us */
+    blk_dur = UNIT_LED_BLINK_DURATION << dur;
+    /* On duration should be half of blinking duration */
+    on_dur  = blk_dur >> 1;
+
+    /* Write data to register */
+    aml_writePhyRegCL45( unit, port, 0x1f, LED_ON_DUR, on_dur );
+    aml_writePhyRegCL45( unit, port, 0x1f, LED_BLK_DUR, blk_dur );
+
+    return AIR_E_OK;
+}
+
+/* FUNCTION NAME: air_led_getBlkTime
+ * PURPOSE:
+ *      Get the Blinking duration of a speficic LED.
+ * INPUT:
+ *      unit            --  Device ID
+ *      port            --  Index of port number
+ *
+ * OUTPUT:
+ *      ptr_dur         --  Blink duration
+ *
+ * RETURN:
+ *      AIR_E_OK
+ *      AIR_E_BAD_PARAMETER
+ *
+ * NOTES:
+ *      None
+ */
+AIR_ERROR_NO_T
+air_led_getBlkTime(
+    const UI32_T unit,
+    const UI8_T port,
+    AIR_LED_BLK_DUR_T *ptr_dur)
+{
+    UI32_T blk_dur = 0;
+    UI32_T u32dat = 0;
+    I8_T i = 0;
+
+    /* Mistake proofing */
+    AIR_PARAM_CHK( ( port >= AIR_MAX_NUM_OF_GIGA_PORTS ), AIR_E_BAD_PARAMETER );
+    AIR_CHECK_PTR( ptr_dur );
+
+    /* Read data from register */
+    aml_readPhyRegCL45( unit, port, 0x1f, LED_BLK_DUR, &blk_dur );
+
+    /* Get LED Blinking duration */
+    u32dat = blk_dur / UNIT_LED_BLINK_DURATION;
+    for(i = AIR_LED_BLK_DUR_LAST; i>=0; i--)
+    {
+        if( (u32dat >> i) & 0x1 )
+        {
+            break;
+        }
+    }
+    (*ptr_dur) = i;
+
+    return AIR_E_OK;
+}
+
diff --git a/recipes-devtools/switch/files/src/an8855_sdk/api/src/air_mib.c b/recipes-devtools/switch/files/src/an8855_sdk/api/src/air_mib.c
new file mode 100644
index 0000000..67088d1
--- /dev/null
+++ b/recipes-devtools/switch/files/src/an8855_sdk/api/src/air_mib.c
@@ -0,0 +1,366 @@
+/* FILE NAME: air_mib.c
+ * PURPOSE:
+ *      Define the MIB counter function in AIR SDK.
+ *
+ * NOTES:
+ *      None
+ */
+
+/* INCLUDE FILE DECLARATIONS
+*/
+#include "air.h"
+
+/* NAMING CONSTANT DECLARATIONS
+*/
+
+/* MACRO FUNCTION DECLARATIONS
+*/
+#define MIB_READ_DATA(unit, port, mib, reg, val)    \
+    do{                                             \
+        aml_readReg(unit, MIB_##reg(port), &val );  \
+        mib -> reg = val;                           \
+    }while(0)
+
+
+
+/* DATA TYPE DECLARATIONS
+*/
+
+/* GLOBAL VARIABLE DECLARATIONS
+*/
+
+/* LOCAL SUBPROGRAM DECLARATIONS
+*/
+
+/* STATIC VARIABLE DECLARATIONS
+*/
+
+/* LOCAL SUBPROGRAM BODIES
+*/
+
+/* EXPORTED SUBPROGRAM BODIES
+*/
+/* FUNCTION NAME: air_mib_setEnable
+ * PURPOSE:
+ *      Enable or Disable mib count fucntion.
+ *
+ * INPUT:
+ *      unit           --   Device ID
+ *      mib_en         --   enable or disable mib_en
+ *
+ * OUTPUT:
+ *      None
+ *
+ * RETURN:
+ *      AIR_E_OK
+ *      AIR_E_BAD_PARAMETER
+ *
+ * NOTES:
+ *      None
+ */
+AIR_ERROR_NO_T
+air_mib_setEnable(
+    const UI32_T unit,
+    const BOOL_T mib_en)
+{
+    UI32_T u32dat = 0;
+    AIR_PARAM_CHK(((TRUE != mib_en) && (FALSE != mib_en)), AIR_E_BAD_PARAMETER);
+
+    /* Write data to register */
+    aml_readReg(unit, MIB_CCR, &u32dat);
+    if(mib_en)
+    {
+        u32dat |= MIB_CCR_MIB_ENABLE;
+    }
+    else
+    {
+        u32dat &= ~MIB_CCR_MIB_ENABLE;
+    }
+    aml_writeReg(unit, MIB_CCR, u32dat);
+
+    return AIR_E_OK;
+}
+
+/* FUNCTION NAME: air_mib_getEnable
+ * PURPOSE:
+ *      Enable or Disable mib count fucntion.
+ *
+ * INPUT:
+ *      unit           --   Device ID
+ *
+ * OUTPUT:
+ *      mib_en         --   enable or disable mib_en
+
+ *
+ * RETURN:
+ *      AIR_E_OK
+ *      AIR_E_BAD_PARAMETER
+ *
+ * NOTES:
+ *      None
+ */
+AIR_ERROR_NO_T
+air_mib_getEnable(
+    const UI32_T unit,
+    BOOL_T *mib_en)
+{
+    UI32_T u32dat = 0;
+    /* Mistake proofing */
+    AIR_CHECK_PTR(mib_en);
+
+
+    /* Write data to register */
+    aml_readReg(unit, MIB_CCR, &u32dat);
+    (*mib_en) = BITS_OFF_R(u32dat, MIB_CCR_MIB_ENABLE_OFFSET, MIB_CCR_MIB_ENABLE_LENGTH);
+
+
+    return AIR_E_OK;
+}
+/* FUNCTION NAME: air_mib_clear
+ * PURPOSE:
+ *      Clear all counters of all MIB counters.
+ *
+ * INPUT:
+ *      unit            --  Device ID
+ *
+ * OUTPUT:
+ *      None
+ *
+ * RETURN:
+ *      AIR_E_OK
+ *      AIR_E_BAD_PARAMETER
+ *
+ * NOTES:
+ *      None
+ */
+AIR_ERROR_NO_T
+air_mib_clear(
+    const UI32_T unit)
+{
+    UI32_T u32dat = 0;
+
+    /* Write data to register */
+    aml_readReg(unit, MIB_CCR, &u32dat);
+    /* Restart MIB counter */
+    u32dat &= ~MIB_CCR_MIB_ENABLE;
+    aml_writeReg(unit, MIB_CCR, u32dat);
+    u32dat |= MIB_CCR_MIB_ENABLE;
+    aml_writeReg(unit, MIB_CCR, u32dat);
+
+    return AIR_E_OK;
+}
+
+/* EXPORTED SUBPROGRAM BODIES
+*/
+/* FUNCTION NAME: air_mib_clear_by_port
+ * PURPOSE:
+ *      Clear all counters of all MIB counters.
+ *
+ * INPUT:
+ *      unit            --  Device ID
+ *      port            --  clear port number
+ *
+ * OUTPUT:
+ *      None
+ *
+ * RETURN:
+ *      AIR_E_OK
+ *      AIR_E_BAD_PARAMETER
+ *
+ * NOTES:
+ *      None
+ */
+AIR_ERROR_NO_T
+air_mib_clear_by_port(
+    const UI32_T unit,
+    const UI32_T port)
+{
+    /* Mistake proofing */
+    AIR_PARAM_CHK(port > AIR_MAX_NUM_OF_PORTS, AIR_E_BAD_PARAMETER);
+
+    /* Write data to register */
+    aml_writeReg(unit, MIB_PCLR, 1 << port);
+    aml_writeReg(unit, MIB_PCLR, 0);
+
+    return AIR_E_OK;
+}
+
+/* FUNCTION NAME: air_mib_get
+ * PURPOSE:
+ *      Get the structure of MIB counter for a specific port.
+ *
+ * INPUT:
+ *      unit            --  Device ID
+ *      port            --  Index of port number
+ *
+ * OUTPUT:
+ *      ptr_rx_mib      --  MIB Counters of Rx Event
+ *      ptr_tx_mib      --  MIB Counters of Tx Event
+ *
+ * RETURN:
+ *      AIR_E_OK
+ *      AIR_E_BAD_PARAMETER
+ *
+ * NOTES:
+ *      None
+ */
+AIR_ERROR_NO_T
+air_mib_get(
+    const UI32_T unit,
+    const UI32_T port,
+    AIR_MIB_CNT_RX_T *ptr_rx_mib,
+    AIR_MIB_CNT_TX_T *ptr_tx_mib)
+{
+    UI32_T u32dat = 0, u32dat_h = 0;
+
+    /* Mistake proofing */
+    AIR_PARAM_CHK((port >= AIR_MAX_NUM_OF_PORTS), AIR_E_BAD_PARAMETER);
+    AIR_CHECK_PTR(ptr_rx_mib);
+    AIR_CHECK_PTR(ptr_tx_mib);
+
+    /* Read data from register */
+
+    /* Read Tx MIB Counter */
+    MIB_READ_DATA(unit, port, ptr_tx_mib, TDPC, u32dat);
+    MIB_READ_DATA(unit, port, ptr_tx_mib, TCRC, u32dat);
+    MIB_READ_DATA(unit, port, ptr_tx_mib, TUPC, u32dat);
+    MIB_READ_DATA(unit, port, ptr_tx_mib, TMPC, u32dat);
+    MIB_READ_DATA(unit, port, ptr_tx_mib, TBPC, u32dat);
+    MIB_READ_DATA(unit, port, ptr_tx_mib, TCEC, u32dat);
+    MIB_READ_DATA(unit, port, ptr_tx_mib, TSCEC, u32dat);
+    MIB_READ_DATA(unit, port, ptr_tx_mib, TMCEC, u32dat);
+    MIB_READ_DATA(unit, port, ptr_tx_mib, TDEC, u32dat);
+    MIB_READ_DATA(unit, port, ptr_tx_mib, TLCEC, u32dat);
+    MIB_READ_DATA(unit, port, ptr_tx_mib, TXCEC, u32dat);
+    MIB_READ_DATA(unit, port, ptr_tx_mib, TPPC, u32dat);
+    MIB_READ_DATA(unit, port, ptr_tx_mib, TL64PC, u32dat);
+    MIB_READ_DATA(unit, port, ptr_tx_mib, TL65PC, u32dat);
+    MIB_READ_DATA(unit, port, ptr_tx_mib, TL128PC, u32dat);
+    MIB_READ_DATA(unit, port, ptr_tx_mib, TL256PC, u32dat);
+    MIB_READ_DATA(unit, port, ptr_tx_mib, TL512PC, u32dat);
+    MIB_READ_DATA(unit, port, ptr_tx_mib, TL1024PC, u32dat);
+    MIB_READ_DATA(unit, port, ptr_tx_mib, TL1519PC, u32dat);
+    MIB_READ_DATA(unit, port, ptr_tx_mib, TODPC, u32dat);
+    aml_readReg(unit, MIB_TOCL(port), &u32dat);
+    aml_readReg(unit, MIB_TOCH(port), &u32dat_h);
+    ptr_tx_mib->TOC = u32dat | ((UI64_T)(u32dat_h) << 32);
+    u32dat = 0;
+    u32dat_h = 0;
+    aml_readReg(unit, MIB_TOCL2(port), &u32dat);
+    aml_readReg(unit, MIB_TOCH2(port), &u32dat_h);
+    ptr_tx_mib->TOC2 = u32dat | ((UI64_T)(u32dat_h) << 32);
+
+    /* Read Rx MIB Counter */
+    MIB_READ_DATA(unit, port, ptr_rx_mib, RDPC, u32dat);
+    MIB_READ_DATA(unit, port, ptr_rx_mib, RFPC, u32dat);
+    MIB_READ_DATA(unit, port, ptr_rx_mib, RUPC, u32dat);
+    MIB_READ_DATA(unit, port, ptr_rx_mib, RMPC, u32dat);
+    MIB_READ_DATA(unit, port, ptr_rx_mib, RBPC, u32dat);
+    MIB_READ_DATA(unit, port, ptr_rx_mib, RAEPC, u32dat);
+    MIB_READ_DATA(unit, port, ptr_rx_mib, RCEPC, u32dat);
+    MIB_READ_DATA(unit, port, ptr_rx_mib, RUSPC, u32dat);
+    MIB_READ_DATA(unit, port, ptr_rx_mib, RFEPC, u32dat);
+    MIB_READ_DATA(unit, port, ptr_rx_mib, ROSPC, u32dat);
+    MIB_READ_DATA(unit, port, ptr_rx_mib, RJEPC, u32dat);
+    MIB_READ_DATA(unit, port, ptr_rx_mib, RPPC, u32dat);
+    MIB_READ_DATA(unit, port, ptr_rx_mib, RL64PC, u32dat);
+    MIB_READ_DATA(unit, port, ptr_rx_mib, RL65PC, u32dat);
+    MIB_READ_DATA(unit, port, ptr_rx_mib, RL128PC, u32dat);
+    MIB_READ_DATA(unit, port, ptr_rx_mib, RL256PC, u32dat);
+    MIB_READ_DATA(unit, port, ptr_rx_mib, RL512PC, u32dat);
+    MIB_READ_DATA(unit, port, ptr_rx_mib, RL1024PC, u32dat);
+    MIB_READ_DATA(unit, port, ptr_rx_mib, RL1519PC, u32dat);
+    MIB_READ_DATA(unit, port, ptr_rx_mib, RCDPC, u32dat);
+    MIB_READ_DATA(unit, port, ptr_rx_mib, RIDPC, u32dat);
+    MIB_READ_DATA(unit, port, ptr_rx_mib, RADPC, u32dat);
+    MIB_READ_DATA(unit, port, ptr_rx_mib, FCDPC, u32dat);
+    MIB_READ_DATA(unit, port, ptr_rx_mib, WRDPC, u32dat);
+    MIB_READ_DATA(unit, port, ptr_rx_mib, MRDPC, u32dat);
+    MIB_READ_DATA(unit, port, ptr_rx_mib, SFSPC, u32dat);
+    MIB_READ_DATA(unit, port, ptr_rx_mib, SFTPC, u32dat);
+    MIB_READ_DATA(unit, port, ptr_rx_mib, RXC_DPC, u32dat);
+    u32dat = 0;
+    u32dat_h = 0;
+    aml_readReg(unit, MIB_ROCL(port), &u32dat);
+    aml_readReg(unit, MIB_ROCH(port), &u32dat_h);
+    ptr_rx_mib->ROC = u32dat | ((UI64_T)(u32dat_h) << 32);
+    u32dat = 0;
+    u32dat_h = 0;
+    aml_readReg(unit, MIB_ROCL2(port), &u32dat);
+    aml_readReg(unit, MIB_ROCH2(port), &u32dat_h);
+    ptr_rx_mib->ROC2 = u32dat | ((UI64_T)(u32dat_h) << 32);
+
+    return AIR_E_OK;
+}
+
+/* FUNCTION NAME: air_mib_clearAclEvent
+ * PURPOSE:
+ *      Clear all counters of ACL event
+ *
+ * INPUT:
+ *      unit            --  Device ID
+ *
+ * OUTPUT:
+ *      None
+ *
+ * RETURN:
+ *      AIR_E_OK
+ *      AIR_E_BAD_PARAMETER
+ *
+ * NOTES:
+ *      None
+ */
+AIR_ERROR_NO_T
+air_mib_clearAclEvent(
+    const UI32_T unit)
+{
+    UI32_T u32dat = 0;
+
+    aml_readReg(unit, ACL_MIB_CNT_CFG, &u32dat);
+    u32dat |= CSR_ACL_MIB_CLEAR;
+    aml_writeReg(unit, ACL_MIB_CNT_CFG, u32dat);
+
+    return AIR_E_OK;
+}
+
+/* FUNCTION NAME: air_mib_getAclEvent
+ * PURPOSE:
+ *      Get the total number of ACL event occurred.
+ *
+ * INPUT:
+ *      unit            --  Device ID
+ *      idx             --  Index of ACL event
+ *
+ * OUTPUT:
+ *      ptr_cnt         --  The total number of ACL event occured
+ *
+ * RETURN:
+ *      AIR_E_OK
+ *      AIR_E_BAD_PARAMETER
+ *
+ * NOTES:
+ *      None
+ */
+AIR_ERROR_NO_T
+air_mib_getAclEvent(
+    const UI32_T unit,
+    const UI32_T idx,
+    UI32_T *ptr_cnt)
+{
+    UI32_T reg = 0;
+    UI32_T u32dat = 0;
+
+    /* Mistake proofing */
+    AIR_PARAM_CHK((idx >= AIR_MIB_MAX_ACL_EVENT_NUM), AIR_E_BAD_PARAMETER);
+    AIR_CHECK_PTR(ptr_cnt);
+
+    aml_readReg(unit, ACL_MIB_CNT_CFG, &u32dat);
+    u32dat = u32dat | (idx << CSR_ACL_MIB_SEL_OFFSET);
+    aml_writeReg(unit, ACL_MIB_CNT_CFG, u32dat);
+
+    aml_readReg(unit, ACL_MIB_CNT, &u32dat);
+    (*ptr_cnt) = u32dat;
+
+    return AIR_E_OK;
+}
+
diff --git a/recipes-devtools/switch/files/src/an8855_sdk/api/src/air_mirror.c b/recipes-devtools/switch/files/src/an8855_sdk/api/src/air_mirror.c
new file mode 100644
index 0000000..00a72e4
--- /dev/null
+++ b/recipes-devtools/switch/files/src/an8855_sdk/api/src/air_mirror.c
@@ -0,0 +1,391 @@
+/* FILE NAME: air_mirror.c
+ * PURPOSE:
+ *      Define the port mirror function in ECNT SDK.
+ *
+ * NOTES:
+ *      None
+ */
+
+/* INCLUDE FILE DECLARATIONS
+*/
+#include "air.h"
+
+/* NAMING CONSTANT DECLARATIONS
+*/
+
+/* MACRO FUNCTION DECLARATIONS
+*/
+
+/* DATA TYPE DECLARATIONS
+*/
+
+/* GLOBAL VARIABLE DECLARATIONS
+*/
+
+/* LOCAL SUBPROGRAM DECLARATIONS
+*/
+
+/* STATIC VARIABLE DECLARATIONS
+*/
+
+/* LOCAL SUBPROGRAM BODIES
+*/
+/* FUNCTION NAME:   air_mir_addSession
+ * PURPOSE:
+ *      This API is used to add or set a mirror session.
+ * INPUT:
+ *      unit                 -- Device unit number
+ *      session_id           -- Session id
+ *      ptr_session          -- Session information
+ *                              AIR_MIR_SESSION_T
+ * OUTPUT:
+ *      None
+ * RETURN:
+ *      AIR_E_OK             -- Operation success.
+ *      AIR_E_BAD_PARAMETER  -- Parameter is wrong.
+ * NOTES:
+ *      None
+ */
+AIR_ERROR_NO_T
+air_mir_addSession(
+    const UI32_T    unit,
+    const UI32_T    session_id,
+    const AIR_MIR_SESSION_T   *ptr_session)
+{
+    UI32_T regMIR = 0, regPCR = 0;
+    UI32_T dst_mac_port = 0, src_mac_port = 0;
+    BOOL_T enable=FALSE, tx_tag_enable=FALSE;
+    
+    /* parameter sanity check */
+    AIR_PARAM_CHK((unit >= AIR_MAX_NUM_OF_UNIT), AIR_E_BAD_PARAMETER);
+    AIR_PARAM_CHK((session_id >= AIR_MAX_MIRROR_SESSION), AIR_E_BAD_PARAMETER);
+    AIR_CHECK_PTR(ptr_session);
+    AIR_PARAM_CHK((ptr_session->src_port >= AIR_MAX_NUM_OF_PORTS), AIR_E_BAD_PARAMETER);
+    AIR_PARAM_CHK((ptr_session->dst_port >= AIR_MAX_NUM_OF_PORTS), AIR_E_BAD_PARAMETER);
+    AIR_PARAM_CHK((ptr_session->dst_port == ptr_session->src_port), AIR_E_BAD_PARAMETER);
+
+    src_mac_port = ptr_session->src_port;
+    dst_mac_port = ptr_session->dst_port;
+    /* Read MIR */
+    aml_readReg(unit, MIR, &regMIR);
+
+    /* Set mirroring port */
+    regMIR &= ~ BITS_RANGE(MIR_MIRROR_PORT_OFFSER(session_id), MIR_MIRROR_PORT_LEN);
+    regMIR |= BITS_OFF_L(dst_mac_port, MIR_MIRROR_PORT_OFFSER(session_id), MIR_MIRROR_PORT_LEN);
+
+    /* Set mirroring port tx tag state */
+    if(ptr_session->flags & AIR_MIR_SESSION_FLAGS_TX_TAG_OBEY_CFG)
+    {
+        tx_tag_enable = TRUE;
+    }
+    regMIR &= ~ BITS_RANGE(MIR_MIRROR_TAG_TX_EN_OFFSER(session_id), MIR_MIRROR_TAG_TX_EN_LEN);
+    regMIR |= BITS_OFF_L(tx_tag_enable, MIR_MIRROR_TAG_TX_EN_OFFSER(session_id), MIR_MIRROR_TAG_TX_EN_LEN);
+
+    /* Set mirroring port state */
+    if(ptr_session->flags & AIR_MIR_SESSION_FLAGS_ENABLE)
+    {
+        enable = TRUE;
+    }
+    regMIR &= ~ BITS_RANGE(MIR_MIRROR_EN_OFFSER(session_id), MIR_MIRROR_EN_LEN);
+    regMIR |= BITS_OFF_L(enable, MIR_MIRROR_EN_OFFSER(session_id), MIR_MIRROR_EN_LEN);
+
+    /* Write MIR */
+    aml_writeReg(unit, MIR, regMIR);
+
+    /* Read PCR */
+    aml_readReg(unit, PCR(src_mac_port), &regPCR);
+
+    /* Set mirroring source port */
+    regPCR &= ~ BIT(PCR_PORT_TX_MIR_OFFT + session_id);
+    regPCR &= ~ BIT(PCR_PORT_RX_MIR_OFFT + session_id);
+    if(ptr_session->flags & AIR_MIR_SESSION_FLAGS_DIR_TX)
+    {
+        regPCR |= BIT(PCR_PORT_TX_MIR_OFFT + session_id);
+    }
+
+    if(ptr_session->flags & AIR_MIR_SESSION_FLAGS_DIR_RX)
+    {
+        regPCR |= BIT(PCR_PORT_RX_MIR_OFFT + session_id);
+    }
+
+    /* Write PCR */
+    aml_writeReg(unit, PCR(src_mac_port), regPCR);
+    return AIR_E_OK;
+}
+
+/* FUNCTION NAME:   air_mir_delSession
+ * PURPOSE:
+ *      This API is used to delete a mirror session.
+ * INPUT:
+ *      unit                 -- Device unit number
+ *      session_id           -- Session id
+ * OUTPUT:
+ *      None
+ * RETURN:
+ *      AIR_E_OK             -- Operation success.
+ *      AIR_E_BAD_PARAMETER  -- Parameter is wrong.
+ * NOTES:
+ *      None
+ */
+AIR_ERROR_NO_T
+air_mir_delSession(
+    const UI32_T    unit,
+    const UI32_T    session_id)
+{
+    UI32_T regMIR = 0;
+
+    /* parameter sanity check */
+    AIR_PARAM_CHK((unit >= AIR_MAX_NUM_OF_UNIT), AIR_E_BAD_PARAMETER);
+    AIR_PARAM_CHK((session_id >= AIR_MAX_MIRROR_SESSION), AIR_E_BAD_PARAMETER);
+
+    /* Read MIR */
+    aml_readReg(unit, MIR, &regMIR);
+
+    /* Set mirroring port */
+    regMIR &= ~ BITS_RANGE(MIR_MIRROR_PORT_OFFSER(session_id), MIR_MIRROR_PORT_LEN);
+    regMIR |= BITS_OFF_L(AIR_DST_DEFAULT_PORT, MIR_MIRROR_PORT_OFFSER(session_id), MIR_MIRROR_PORT_LEN);
+    /* Set mirroring port tx tag state */
+    regMIR &= ~ BITS_RANGE(MIR_MIRROR_TAG_TX_EN_OFFSER(session_id), MIR_MIRROR_TAG_TX_EN_LEN);
+    /* Set mirroring port state */
+    regMIR &= ~ BITS_RANGE(MIR_MIRROR_EN_OFFSER(session_id), MIR_MIRROR_EN_LEN);
+
+    /* Write MIR */
+    aml_writeReg(unit, MIR, regMIR);
+
+    return AIR_E_OK;
+}
+
+/* FUNCTION NAME:   air_mir_getSession
+ * PURPOSE:
+ *      This API is used to get mirror session information.
+ * INPUT:
+ *      unit                 -- Device unit number
+ *      session_id           -- Session id
+ * OUTPUT:
+ *      ptr_session          -- The information of the session to be
+ *                              obtained
+ *                              AIR_MIR_SESSION_T
+ * RETURN:
+ *      AIR_E_OK             -- Operation success.
+ *      AIR_E_BAD_PARAMETER  -- Parameter is wrong.
+ * NOTES:
+ *      None
+ */
+AIR_ERROR_NO_T
+air_mir_getSession(
+    const UI32_T        unit,
+    const UI32_T        session_id,
+    AIR_MIR_SESSION_T   *ptr_session)
+{
+    UI32_T regMIR = 0;
+    UI32_T dst_mac_port = 0;
+    BOOL_T enable = FALSE, tx_tag_enable = FALSE;
+
+    /* parameter sanity check */
+    AIR_PARAM_CHK((unit >= AIR_MAX_NUM_OF_UNIT), AIR_E_BAD_PARAMETER);
+    AIR_PARAM_CHK((session_id >= AIR_MAX_MIRROR_SESSION), AIR_E_BAD_PARAMETER);
+    AIR_CHECK_PTR(ptr_session);
+
+    /* Read MIR */
+    aml_readReg(unit, MIR, &regMIR);
+    /* Get mirroring port */
+    dst_mac_port = BITS_OFF_R(regMIR, MIR_MIRROR_PORT_OFFSER(session_id), MIR_MIRROR_PORT_LEN);
+    /* Get mirroring port state */
+    enable = BITS_OFF_R(regMIR, MIR_MIRROR_EN_OFFSER(session_id), MIR_MIRROR_EN_LEN);
+    /* Get mirroring tx tag state*/
+    tx_tag_enable = BITS_OFF_R(regMIR, MIR_MIRROR_TAG_TX_EN_OFFSER(session_id), MIR_MIRROR_TAG_TX_EN_LEN);
+    ptr_session->dst_port = dst_mac_port;
+    if(enable)
+    {
+        ptr_session->flags |= AIR_MIR_SESSION_FLAGS_ENABLE;
+    }
+    if(tx_tag_enable)
+    {
+        ptr_session->flags |= AIR_MIR_SESSION_FLAGS_TX_TAG_OBEY_CFG;
+    }
+
+    return AIR_E_OK;
+}
+
+/* FUNCTION NAME:   air_mir_setSessionAdminMode
+ * PURPOSE:
+ *      This API is used to set mirror session state.
+ * INPUT:
+ *      unit                 -- Device unit number
+ *      session_id           -- Session id
+ *      enable               -- State of session
+ * OUTPUT:
+ *      None
+ * RETURN:
+ *      AIR_E_OK             -- Operation success.
+ *      AIR_E_BAD_PARAMETER  -- Parameter is wrong.
+ * NOTES:
+ *      None
+ */
+AIR_ERROR_NO_T
+air_mir_setSessionAdminMode(
+    const UI32_T    unit,
+    const UI32_T    session_id,
+    const BOOL_T    enable)
+{
+    UI32_T regMIR = 0;
+
+    /* parameter sanity check */
+    AIR_PARAM_CHK((unit >= AIR_MAX_NUM_OF_UNIT), AIR_E_BAD_PARAMETER);
+    AIR_PARAM_CHK((session_id >= AIR_MAX_MIRROR_SESSION), AIR_E_BAD_PARAMETER);
+    AIR_PARAM_CHK((enable != TRUE && enable != FALSE), AIR_E_BAD_PARAMETER);
+
+    /* Read MIR */
+    aml_readReg(unit, MIR, &regMIR);
+
+    /* Set mirroring port state */
+    regMIR &= ~ BITS_RANGE(MIR_MIRROR_EN_OFFSER(session_id), MIR_MIRROR_EN_LEN);
+    regMIR |= BITS_OFF_L(enable, MIR_MIRROR_EN_OFFSER(session_id), MIR_MIRROR_EN_LEN);
+
+    /* Write MIR */
+    aml_writeReg(unit, MIR, regMIR);
+
+    return AIR_E_OK;
+}
+
+/* FUNCTION NAME:   air_mir_getSessionAdminMode
+ * PURPOSE:
+ *      This API is used to get mirror session state.
+ * INPUT:
+ *      unit                 -- Device unit number
+ *      session_id           -- mirror session id
+ * OUTPUT:
+ *      ptr_enable           -- State of session
+ * RETURN:
+ *      AIR_E_OK             -- Operation success.
+ *      AIR_E_BAD_PARAMETER  -- Parameter is wrong.
+ * NOTES:
+ *      None
+ */
+AIR_ERROR_NO_T
+air_mir_getSessionAdminMode(
+    const UI32_T    unit,
+    const UI32_T    session_id,
+    BOOL_T          *ptr_enable)
+{
+    UI32_T regMIR = 0;
+    BOOL_T enable = FALSE;
+
+    /* parameter sanity check */
+    AIR_PARAM_CHK((unit >= AIR_MAX_NUM_OF_UNIT), AIR_E_BAD_PARAMETER);
+    AIR_PARAM_CHK((session_id >= AIR_MAX_MIRROR_SESSION), AIR_E_BAD_PARAMETER);
+    AIR_CHECK_PTR(ptr_enable);
+
+    /* Read MIR */
+    aml_readReg(unit, MIR, &regMIR);
+
+    /* Get mirroring port state */
+    enable = BITS_OFF_R(regMIR, MIR_MIRROR_EN_OFFSER(session_id), MIR_MIRROR_EN_LEN);
+
+    *ptr_enable = enable;
+
+    return AIR_E_OK;
+}
+
+/* FUNCTION NAME:   air_mir_setMirrorPort
+ * PURPOSE:
+ *      This API is used to set mirror port mirroring type.
+ * INPUT:
+ *      unit                 -- Device unit number
+ *      session_id           -- Session id
+ *      ptr_session          -- Session information
+ *                              AIR_MIR_SESSION_T
+ * OUTPUT:
+ *      None
+ * RETURN:
+ *      AIR_E_OK             -- Operation success.
+ *      AIR_E_BAD_PARAMETER  -- Parameter is wrong.
+ * NOTES:
+ *      None
+ */
+AIR_ERROR_NO_T
+air_mir_setMirrorPort(
+    const UI32_T            unit,
+    const UI32_T            session_id,
+    const AIR_MIR_SESSION_T *ptr_session)
+{
+    UI32_T regPCR = 0;
+    UI32_T src_mac_port = 0;
+
+    /* parameter sanity check */
+    AIR_PARAM_CHK((unit >= AIR_MAX_NUM_OF_UNIT), AIR_E_BAD_PARAMETER);
+    AIR_PARAM_CHK((session_id >= AIR_MAX_MIRROR_SESSION), AIR_E_BAD_PARAMETER);
+    AIR_CHECK_PTR(ptr_session);
+    AIR_PARAM_CHK((ptr_session->src_port >= AIR_MAX_NUM_OF_PORTS), AIR_E_BAD_PARAMETER);
+
+    src_mac_port = ptr_session->src_port;
+    /* Read data from register */
+    aml_readReg(unit, PCR(src_mac_port), &regPCR);
+
+    regPCR &= ~ BIT(PCR_PORT_TX_MIR_OFFT + session_id);
+    regPCR &= ~ BIT(PCR_PORT_RX_MIR_OFFT + session_id);
+
+    if(ptr_session->flags & AIR_MIR_SESSION_FLAGS_DIR_TX)
+    {
+        regPCR |= BIT(PCR_PORT_TX_MIR_OFFT + session_id);
+    }
+
+    if(ptr_session->flags & AIR_MIR_SESSION_FLAGS_DIR_RX)
+    {
+        regPCR |= BIT(PCR_PORT_RX_MIR_OFFT + session_id);
+    }
+    /* Write data to register */
+    aml_writeReg(unit, PCR(src_mac_port), regPCR);
+    return AIR_E_OK;
+}
+
+/* FUNCTION NAME:   air_mir_getMirrorPort
+ * PURPOSE:
+ *      This API is used to get mirror port mirroring type.
+ * INPUT:
+ *      unit                 -- Device unit number
+ *      session_id           -- Session id
+ * OUTPUT:
+ *      ptr_session          -- The information of this session to be
+ *                              obtained.
+ *                              AIR_MIR_SESSION_T
+ * RETURN:
+ *      AIR_E_OK             -- Operation success.
+ *      AIR_E_BAD_PARAMETER  -- Parameter is wrong.
+ * NOTES:
+ *      None
+ */
+AIR_ERROR_NO_T
+air_mir_getMirrorPort(
+    const UI32_T        unit,
+    const UI32_T        session_id,
+    AIR_MIR_SESSION_T   *ptr_session)
+{
+    UI32_T regPCR = 0;
+    UI32_T src_mac_port = 0;
+
+    /* parameter sanity check */
+    AIR_PARAM_CHK((unit >= AIR_MAX_NUM_OF_UNIT), AIR_E_BAD_PARAMETER);
+    AIR_PARAM_CHK((session_id >= AIR_MAX_MIRROR_SESSION), AIR_E_BAD_PARAMETER);
+    AIR_CHECK_PTR(ptr_session);
+    AIR_PARAM_CHK((ptr_session->src_port >= AIR_MAX_NUM_OF_PORTS), AIR_E_BAD_PARAMETER);
+    
+    src_mac_port = ptr_session->src_port;
+    /* Read data from register */
+    aml_readReg(unit, PCR(src_mac_port), &regPCR);
+
+    if(regPCR & BIT(PCR_PORT_TX_MIR_OFFT + session_id))
+    {
+        ptr_session->flags |= AIR_MIR_SESSION_FLAGS_DIR_TX;
+    }
+
+    if(regPCR & BIT(PCR_PORT_RX_MIR_OFFT + session_id))
+    {
+        ptr_session->flags |= AIR_MIR_SESSION_FLAGS_DIR_RX;
+    }
+
+    return AIR_E_OK;
+}
+
+
+
diff --git a/recipes-devtools/switch/files/src/an8855_sdk/api/src/air_port.c b/recipes-devtools/switch/files/src/an8855_sdk/api/src/air_port.c
new file mode 100644
index 0000000..09dcef1
--- /dev/null
+++ b/recipes-devtools/switch/files/src/an8855_sdk/api/src/air_port.c
@@ -0,0 +1,2456 @@
+/* FILE NAME: air_port.c
+ * PURPOSE:
+ *      Define the port function in AIR SDK.
+ *
+ * NOTES:
+ *      None
+ */
+
+/* INCLUDE FILE DECLARATIONS
+ */
+#include "air.h"
+#include "air_port.h"
+
+/* NAMING CONSTANT DECLARATIONS
+ */
+
+/* MACRO FUNCTION DECLARATIONS
+ */
+#define AIR_SET_REG_BIT(cond, reg, bit)    \
+    do{                                     \
+        if(TRUE == (cond))                  \
+        {                                   \
+            (reg) |= (bit);                 \
+        }                                   \
+        else                                \
+        {                                   \
+            (reg) &= ~(bit);                \
+        }                                   \
+    }while(0)
+
+/* DATA TYPE DECLARATIONS
+ */
+
+/* GLOBAL VARIABLE DECLARATIONS
+ */
+
+/* LOCAL SUBPROGRAM DECLARATIONS
+ */
+
+/* STATIC VARIABLE DECLARATIONS
+ */
+
+/* LOCAL SUBPROGRAM BODIES
+ */
+
+/* FUNCTION NAME: air_port_setAnMode
+ * PURPOSE:
+ *      Set the auto-negotiation mode for a specific port.(Auto or Forced)
+ *
+ * INPUT:
+ *      unit            --  Device ID
+ *      port            --  Index of port number
+ *      state           --  FALSE:Disable
+ *                          TRUE: Enable
+ * OUTPUT:
+ *      None
+ *
+ * RETURN:
+ *      AIR_E_OK
+ *      AIR_E_BAD_PARAMETER
+ *
+ * NOTES:
+ *      None
+ */
+AIR_ERROR_NO_T
+air_port_setAnMode(
+    const UI32_T unit,
+    const UI32_T port,
+    const BOOL_T state)
+{
+    UI32_T u32CtrlReg = 0;
+    UI32_T u32Pmcr = 0;
+    UI32_T i = 0;
+    UI32_T mii_port = 0;
+    AIR_ERROR_NO_T ret = AIR_E_OK;
+
+    /* Mistake proofing for port checking */
+    AIR_PARAM_CHK((port >= AIR_MAX_NUM_OF_GIGA_PORTS), AIR_E_BAD_PARAMETER);
+    AIR_PARAM_CHK(((TRUE != state) && (FALSE != state)), AIR_E_BAD_PARAMETER);
+
+    /* Read data from phy register */
+    aml_readPhyReg(unit, port, 0x0, &u32CtrlReg);
+
+    if(TRUE == state)
+    {
+        /* Enable AN mode of PHY port */
+        u32CtrlReg |= BIT(12);
+    }
+    else
+    {
+        /* Disable AN mode of PHY port */
+        u32CtrlReg &= ~BIT(12);
+    }
+
+    /* Restart AN */
+    u32CtrlReg |= BIT(9);
+
+    /* Write data to register */
+    aml_writePhyReg(unit, port, 0x00, u32CtrlReg);
+
+    return ret;
+}
+
+/* FUNCTION NAME: air_port_getAnMode
+ * PURPOSE:
+ *      Get the auto-negotiation mode for a specific port.
+ *
+ * INPUT:
+ *      unit            --  Device ID
+ *      port            --  Index of port number
+ *
+ * OUTPUT:
+ *      state           --  FALSE:Disable
+ *                          TRUE: Enable
+ * RETURN:
+ *      AIR_E_OK
+ *      AIR_E_BAD_PARAMETER
+ *
+ * NOTES:
+ *      None
+ */
+AIR_ERROR_NO_T
+air_port_getAnMode(
+    const UI32_T unit,
+    const UI32_T port,
+    BOOL_T *ptr_state)
+{
+    UI32_T u32dat = 0;
+    UI32_T i = 0, mii_port = 0;
+    AIR_ERROR_NO_T ret = AIR_E_OK;
+
+    /* Mistake proofing */
+    AIR_PARAM_CHK((port >= AIR_MAX_NUM_OF_GIGA_PORTS), AIR_E_BAD_PARAMETER);
+    AIR_CHECK_PTR(ptr_state);
+
+    /* Read data from register */
+    aml_readPhyReg(unit, port, 0x0, &u32dat);
+    (*ptr_state) = BITS_OFF_R(u32dat, 12, 1);
+
+    return ret;
+}
+
+/* FUNCTION NAME: air_port_setLocalAdvAbility
+ * PURPOSE:
+ *      Set the auto-negotiation advertisement for a
+ *      specific port.
+ *
+ * INPUT:
+ *      unit            --  Device ID
+ *      port            --  Index of port number
+ *      adv             --  AN advertisement setting
+ *
+ * OUTPUT:
+ *      None
+ *
+ * RETURN:
+ *      AIR_E_OK
+ *      AIR_E_BAD_PARAMETER
+ *
+ * NOTES:
+ *      None
+ */
+AIR_ERROR_NO_T
+air_port_setLocalAdvAbility(
+    const UI32_T unit,
+    const UI32_T port,
+    const AIR_AN_ADV_T adv)
+{
+    UI32_T u32dat = 0;
+
+    /* Mistake proofing for port checking */
+    AIR_PARAM_CHK((port >= AIR_MAX_NUM_OF_GIGA_PORTS), AIR_E_BAD_PARAMETER);
+
+    /* Read AN Advertisement from register */
+    aml_readPhyReg(unit, port, PHY_AN_ADV, &u32dat);
+
+    /* Modify AN Advertisement */
+    AIR_SET_REG_BIT(adv.advCap10HDX, u32dat, AN_ADV_CAP_10_HDX);
+    AIR_SET_REG_BIT(adv.advCap10FDX, u32dat, AN_ADV_CAP_10_FDX);
+    AIR_SET_REG_BIT(adv.advCap100HDX, u32dat, AN_ADV_CAP_100_HDX);
+    AIR_SET_REG_BIT(adv.advCap100FDX, u32dat, AN_ADV_CAP_100_FDX);
+    AIR_SET_REG_BIT(adv.advPause, u32dat, AN_ADV_CAP_PAUSE);
+
+    /* Write AN Advertisement to register */
+    aml_writePhyReg(unit, port, PHY_AN_ADV, u32dat);
+
+    /* Write 1000BASE-T duplex capbility to  register */
+    aml_readPhyReg(unit, port, PHY_CR1G, &u32dat);
+    AIR_SET_REG_BIT(adv.advCap1000FDX, u32dat, CR1G_ADV_CAP1000_FDX);
+    aml_writePhyReg(unit, port, PHY_CR1G, u32dat);
+
+    return AIR_E_OK;
+}
+
+/* FUNCTION NAME: air_port_getLocalAdvAbility
+ * PURPOSE:
+ *      Get the auto-negotiation advertisement for a
+ *      specific port.
+ *
+ * INPUT:
+ *      unit            --  Device ID
+ *      port            --  Index of port number
+ *
+ * OUTPUT:
+ *      ptr_adv         --  AN advertisement setting
+ *
+ * RETURN:
+ *      AIR_E_OK
+ *      AIR_E_BAD_PARAMETER
+ *
+ * NOTES:
+ *      None
+ */
+AIR_ERROR_NO_T
+air_port_getLocalAdvAbility(
+    const UI32_T unit,
+    const UI32_T port,
+    AIR_AN_ADV_T *ptr_adv)
+{
+    UI32_T u32dat = 0;
+
+    /* Mistake proofing for port checking */
+    AIR_PARAM_CHK((port >= AIR_MAX_NUM_OF_GIGA_PORTS), AIR_E_BAD_PARAMETER);
+    /* Mistake proofing checking */
+    AIR_CHECK_PTR(ptr_adv);
+
+    /* Read AN Advertisement from register */
+    aml_readPhyReg(unit, port, PHY_AN_ADV, &u32dat);
+    ptr_adv ->advCap10HDX = (u32dat & AN_ADV_CAP_10_HDX)?TRUE:FALSE;
+    ptr_adv ->advCap10FDX = (u32dat & AN_ADV_CAP_10_FDX)?TRUE:FALSE;
+    ptr_adv ->advCap100HDX = (u32dat & AN_ADV_CAP_100_HDX)?TRUE:FALSE;
+    ptr_adv ->advCap100FDX = (u32dat & AN_ADV_CAP_100_FDX)?TRUE:FALSE;
+    ptr_adv ->advPause = (u32dat & AN_ADV_CAP_PAUSE)?TRUE:FALSE;
+
+    /* Read 1000BASE-T duplex capalibity from register */
+    aml_readPhyReg(unit, port, PHY_CR1G, &u32dat);
+    ptr_adv ->advCap1000FDX = (u32dat & CR1G_ADV_CAP1000_FDX)?TRUE:FALSE;
+
+    return AIR_E_OK;
+}
+
+/* FUNCTION NAME: air_port_getRemoteAdvAbility
+ * PURPOSE:
+ *      Get the auto-negotiation remote advertisement for a
+ *      specific port.
+ *
+ * INPUT:
+ *      unit            --  Device ID
+ *      port            --  Index of port number
+ *
+ * OUTPUT:
+ *      ptr_lp_adv      --  AN advertisement of link partner
+ *
+ * RETURN:
+ *      AIR_E_OK
+ *      AIR_E_BAD_PARAMETER
+ *
+ * NOTES:
+ *      None
+ */
+AIR_ERROR_NO_T
+air_port_getRemoteAdvAbility(
+    const UI32_T unit,
+    const UI32_T port,
+    AIR_AN_ADV_T *ptr_lp_adv)
+{
+    UI32_T u32dat = 0;
+
+    /* Mistake proofing for port checking */
+    AIR_PARAM_CHK((port >= AIR_MAX_NUM_OF_GIGA_PORTS), AIR_E_BAD_PARAMETER);
+    AIR_CHECK_PTR(ptr_lp_adv);
+
+    /* Read AN LP Advertisement from register */
+    aml_readPhyReg(unit, port, PHY_AN_LP_ADV, &u32dat);
+    ptr_lp_adv ->advCap10HDX = (u32dat & AN_LP_CAP_10_HDX)?TRUE:FALSE;
+    ptr_lp_adv ->advCap10FDX = (u32dat & AN_LP_CAP_10_FDX)?TRUE:FALSE;
+    ptr_lp_adv ->advCap100HDX = (u32dat & AN_LP_CAP_100_HDX)?TRUE:FALSE;
+    ptr_lp_adv ->advCap100FDX = (u32dat & AN_LP_CAP_100_FDX)?TRUE:FALSE;
+    ptr_lp_adv ->advPause = (u32dat & AN_LP_CAP_PAUSE)?TRUE:FALSE;
+
+    /* Read LP 1000BASE-T duplex capalibity from register */
+    aml_readPhyReg(unit, port, PHY_SR1G, &u32dat);
+    ptr_lp_adv ->advCap1000FDX = (u32dat & SR1G_CAP1000_FDX)?TRUE:FALSE;
+
+    return AIR_E_OK;
+}
+
+/* FUNCTION NAME: air_port_setSpeed
+ * PURPOSE:
+ *      Set the speed for a specific port.
+ *      This setting is used on force mode only.
+ *
+ * INPUT:
+ *      unit            --  Device ID
+ *      port            --  Index of port number
+ *      speed           --  AIR_PORT_SPEED_10M:  10Mbps
+ *                          AIR_PORT_SPEED_100M: 100Mbps
+ *                          AIR_PORT_SPEED_1000M:1Gbps
+ * OUTPUT:
+ *      None
+ *
+ * RETURN:
+ *      AIR_E_OK
+ *      AIR_E_BAD_PARAMETER
+ *      AIR_E_OTHERS
+ *
+ * NOTES:
+ *      None
+ */
+AIR_ERROR_NO_T
+air_port_setSpeed(
+    const UI32_T unit,
+    const UI32_T port,
+    const UI32_T speed)
+{
+    UI32_T u32dat = 0;
+    UI32_T mii_port = 0;
+    BOOL_T an = 0;
+
+    /* Mistake proofing for port checking */
+    AIR_PARAM_CHK((port >= AIR_MAX_NUM_OF_GIGA_PORTS), AIR_E_BAD_PARAMETER);
+
+    /* Mistake proofing for speed checking */
+    AIR_PARAM_CHK((speed >= AIR_PORT_SPEED_2500M), AIR_E_BAD_PARAMETER);
+
+    /* Read data from register */
+    aml_readPhyReg(unit, port, 0x0, &u32dat);
+
+    u32dat &= ~(BIT(13) | BIT(6));
+    switch(speed)
+    {
+        case AIR_PORT_SPEED_10M:
+            /* (bit6, bit13) = 2b'00 means 10M */
+            break;
+        case AIR_PORT_SPEED_100M:
+            /* (bit6, bit13) = 2b'01 means 100M */
+            u32dat |= BIT(13);
+            break;
+        case AIR_PORT_SPEED_1000M:
+            /* (bit6, bit13) = 2b'10 means 1000M */
+            u32dat |= BIT(6);
+            break;
+        default:
+            /* (bit6, bit13) = 2b'11 means reverse,
+             * other value is invalid */
+            AIR_PRINT("argument 3: speed(%u) is invalid.\n", speed);
+            return AIR_E_BAD_PARAMETER;
+    }
+
+    /* Write data to register */
+    aml_writePhyReg(unit, port, 0x00, u32dat);
+
+    return AIR_E_OK;
+}
+
+/* FUNCTION NAME: air_port_getSpeed
+ * PURPOSE:
+ *      Get the speed for a specific port.
+ *
+ * INPUT:
+ *      unit            --  Device ID
+ *      port            --  Index of port number
+ *
+ * OUTPUT:
+ *      ptr_speed       --  AIR_PORT_SPEED_10M:  10Mbps
+ *                          AIR_PORT_SPEED_100M: 100Mbps
+ *                          AIR_PORT_SPEED_1000M:1Gbps
+ *                          AIR_PORT_SPEED_2500M:2.5Gbps
+ * RETURN:
+ *      AIR_E_OK
+ *      AIR_E_BAD_PARAMETER
+ *
+ * NOTES:
+ *      None
+ */
+AIR_ERROR_NO_T
+air_port_getSpeed(
+    const UI32_T unit,
+    const UI32_T port,
+    UI32_T *ptr_speed)
+{
+    UI32_T u32dat = 0;
+    UI32_T mii_port = 0, sp = 0;
+    UI32_T ret = AIR_E_OK;
+
+    /* Mistake proofing for port checking */
+    AIR_PARAM_CHK((port >= AIR_MAX_NUM_OF_GIGA_PORTS), AIR_E_BAD_PARAMETER);
+
+    /* Mistake proofing for speed checking */
+    AIR_CHECK_PTR(ptr_speed);
+
+    /* Read data from register */
+    aml_readPhyReg(unit, port, 0x0, &u32dat);
+    (*ptr_speed) = (BITS_OFF_R(u32dat, 6, 1) << 1) | BITS_OFF_R(u32dat, 13, 1);
+
+    return ret;
+}
+
+/* FUNCTION NAME: air_port_setDuplex
+ * PURPOSE:
+ *      Get the duplex for a specific port.
+ *      This setting is used on force mode only.
+ *
+ * INPUT:
+ *      unit            --  Device ID
+ *      port            --  Index of port number
+ *      duplex          --  AIR_PORT_DUPLEX_HALF
+ *                          AIR_PORT_DUPLEX_FULL
+ * OUTPUT:
+ *      None
+ *
+ * RETURN:
+ *      AIR_E_OK
+ *      AIR_E_BAD_PARAMETER
+ *
+ * NOTES:
+ *      None
+ */
+AIR_ERROR_NO_T
+air_port_setDuplex(
+    const UI32_T unit,
+    const UI32_T port,
+    const BOOL_T duplex)
+{
+    UI32_T ret = AIR_E_OK;
+    UI32_T u32dat = 0;
+    UI32_T mii_port = 0, speed = 0;
+
+    /* Mistake proofing for port checking */
+    AIR_PARAM_CHK((port >= AIR_MAX_NUM_OF_GIGA_PORTS), AIR_E_BAD_PARAMETER);
+
+    /* Mistake proofing for duplex checking */
+    AIR_PARAM_CHK(((AIR_PORT_DUPLEX_HALF != duplex) && (AIR_PORT_DUPLEX_FULL != duplex)), AIR_E_BAD_PARAMETER);
+
+    /* Read data from register */
+    aml_readPhyReg(unit, port, 0x0, &u32dat);
+    speed = (BITS_OFF_R(u32dat, 6, 1) << 1) | BITS_OFF_R(u32dat, 13, 1);
+    if(AIR_PORT_SPEED_100M >= speed)
+    {
+        if(TRUE == duplex)
+        {
+            u32dat |= BIT(8);
+        }
+        else
+        {
+            u32dat &= ~BIT(8);
+        }
+    }
+    else
+    {
+        /* 1G support full duplex only */
+        u32dat |= BIT(8);
+    }
+
+    /* Write data to register */
+    aml_writePhyReg(unit, port, 0x0, u32dat);
+
+    return ret;
+}
+
+/* FUNCTION NAME: air_port_getDuplex
+ * PURPOSE:
+ *      Get the duplex for a specific port.
+ *
+ * INPUT:
+ *      unit            --  Device ID
+ *      port            --  Index of port number
+ *
+ * OUTPUT:
+ *      ptr_duplex      --  AIR_PORT_DUPLEX_HALF
+ *                          AIR_PORT_DUPLEX_FULL
+ * RETURN:
+ *      AIR_E_OK
+ *      AIR_E_BAD_PARAMETER
+ *
+ * NOTES:
+ *      None
+ */
+AIR_ERROR_NO_T
+air_port_getDuplex(
+    const UI32_T unit,
+    const UI32_T port,
+    BOOL_T *ptr_duplex)
+{
+    UI32_T u32dat = 0;
+    UI32_T mii_port = 0, duplex = 0;
+
+    /* Mistake proofing for port checking */
+    AIR_PARAM_CHK((port >= AIR_MAX_NUM_OF_GIGA_PORTS), AIR_E_BAD_PARAMETER);
+    /* Mistake proofing for duplex checking */
+    AIR_CHECK_PTR(ptr_duplex);
+
+    /* Read data from register */
+    aml_readPhyReg(unit, port, 0x0, &u32dat);
+    (*ptr_duplex) = BITS_OFF_R(u32dat, 8, 1);
+
+    return AIR_E_OK;
+}
+
+/* FUNCTION NAME: air_port_getLink
+ * PURPOSE:
+ *      Get the physical link status for a specific port.
+ *
+ * INPUT:
+ *      unit            --  Device ID
+ *      port            --  Index of port number
+ *
+ * OUTPUT:
+ *      ptr_ps          --  AIR_PORT_STATUS_T
+ *
+ * RETURN:
+ *      AIR_E_OK
+ *      AIR_E_BAD_PARAMETER
+ *
+ * NOTES:
+ *      None
+ */
+AIR_ERROR_NO_T
+air_port_getLink(
+    const UI32_T unit,
+    const UI32_T port,
+    AIR_PORT_STATUS_T *ptr_ps)
+{
+    UI32_T ret = AIR_E_OK;
+    UI32_T u32dat = 0;
+    UI32_T mii_port = 0;
+    BOOL_T an = 0;
+
+    /* Mistake proofing for port checking */
+    AIR_PARAM_CHK((port >= AIR_MAX_NUM_OF_GIGA_PORTS), AIR_E_BAD_PARAMETER);
+    /* Mistake proofing for duplex checking */
+    AIR_CHECK_PTR(ptr_ps);
+
+    /* Read data from register */
+    aml_readReg(unit, PMSR(port), &u32dat);
+    ptr_ps->link = BITS_OFF_R(u32dat, 24, 1);
+    ptr_ps->duplex = BITS_OFF_R(u32dat, 25, 1);
+    ptr_ps->speed = BITS_OFF_R(u32dat, 28, 3);
+
+    return ret;
+}
+
+/* FUNCTION NAME: air_port_setBckPres
+ * PURPOSE:
+ *      Set the back pressure configuration for a specific port.
+ *
+ * INPUT:
+ *      unit            --  Device ID
+ *      port            --  Index of port number
+ *      bckPres         --  FALSE:Disable
+ *                          TRUE: Enable
+ * OUTPUT:
+ *      None
+ *
+ * RETURN:
+ *      AIR_E_OK
+ *      AIR_E_BAD_PARAMETER
+ *
+ * NOTES:
+ *      None
+ */
+AIR_ERROR_NO_T
+air_port_setBckPres(
+    const UI32_T unit,
+    const UI32_T port,
+    const BOOL_T bckPres)
+{
+    UI32_T u32dat = 0;
+
+    /* Mistake proofing for port checking */
+    AIR_PARAM_CHK((port >= AIR_MAX_NUM_OF_PORTS), AIR_E_BAD_PARAMETER);
+    /* Mistake proofing for speed checking */
+    AIR_PARAM_CHK(((TRUE != bckPres) && (FALSE != bckPres)), AIR_E_BAD_PARAMETER);
+
+    /* Read data from register */
+    aml_readReg(unit, PMCR(port), &u32dat);
+    if(TRUE == bckPres)
+    {
+        u32dat |= BIT(11);
+    }
+    else
+    {
+        u32dat &= ~BIT(11);
+    }
+
+    /* Write data to register */
+    aml_writeReg(unit, PMCR(port), u32dat);
+
+    return AIR_E_OK;
+}
+
+/* FUNCTION NAME: air_port_getBckPres
+ * PURPOSE:
+ *      Get the back pressure configuration for a specific port.
+ *
+ * INPUT:
+ *      unit            --  Device ID
+ *      port            --  Index of port number
+ *
+ * OUTPUT:
+ *      ptr_bckPres     --  FALSE:Disable
+ *                          TRUE: Enable
+ * RETURN:
+ *      AIR_E_OK
+ *      AIR_E_BAD_PARAMETER
+ *
+ * NOTES:
+ *      None
+ */
+AIR_ERROR_NO_T
+air_port_getBckPres(
+    const UI32_T unit,
+    const UI32_T port,
+    BOOL_T *ptr_bckPres)
+{
+    UI32_T u32dat = 0;
+
+    /* Mistake proofing for port checking */
+    AIR_PARAM_CHK((port >= AIR_MAX_NUM_OF_PORTS), AIR_E_BAD_PARAMETER);
+
+    /* Mistake proofing for speed checking */
+    AIR_CHECK_PTR(ptr_bckPres);
+
+    /* Read data from register */
+    aml_readReg(unit, PMCR(port), &u32dat);
+    (*ptr_bckPres) = BITS_OFF_R(u32dat, 11, 1);
+
+    return AIR_E_OK;
+}
+
+/* FUNCTION NAME: air_port_setFlowCtrl
+ * PURPOSE:
+ *      Set the flow control configuration for specific port.
+ *
+ * INPUT:
+ *      unit            --  Select device ID
+ *      port            --  Select port number (0 - 6)
+ *      dir             --  Directions of AIR_PORT_TX or AIR_PORT_RX
+ *      fc_en           --  TRUE: Enable select port flow control
+ *                          FALSE:Disable select port flow control
+ * OUTPUT:
+ *      None
+ *
+ * RETURN:
+ *      AIR_E_OK
+ *      AIR_E_BAD_PARAMETER
+ *
+ * NOTES:
+ *      None
+ */
+AIR_ERROR_NO_T
+air_port_setFlowCtrl(
+    const UI32_T unit,
+    const UI32_T port,
+    const BOOL_T dir,
+    const BOOL_T fc_en)
+{
+    UI32_T u32dat = 0;
+
+    /* Check port range */
+    AIR_PARAM_CHK((port >= AIR_MAX_NUM_OF_PORTS), AIR_E_BAD_PARAMETER);
+
+    /* Check directions */
+    if(dir != AIR_PORT_TX && dir != AIR_PORT_RX)
+        return AIR_E_BAD_PARAMETER;;
+
+    /* Check fc_en */
+    AIR_PARAM_CHK(((TRUE != fc_en) && (FALSE != fc_en)), AIR_E_BAD_PARAMETER);
+
+    aml_readReg(unit, PMCR(port), &u32dat);
+    if(TRUE == fc_en)
+    {
+        /* Enable port flow control */
+        if(dir == AIR_PORT_TX)
+        {
+            u32dat |= FORCE_TX_FC;
+        }
+        else
+        {
+            u32dat |= FORCE_RX_FC;
+        }
+    }
+    else
+    {
+        /* Disable port flow control */
+        if(dir == AIR_PORT_TX)
+        {
+            u32dat &= ~(FORCE_TX_FC);
+        }
+        else
+        {
+            u32dat &= ~(FORCE_RX_FC);
+        }
+    }
+    aml_writeReg(unit, PMCR(port), u32dat);
+
+    return AIR_E_OK;
+}
+
+/* FUNCTION NAME: air_port_getFlowCtrl
+ * PURPOSE:
+ *      Get the flow control configuration for specific port.
+ *
+ * INPUT:
+ *      unit            --  Select device ID
+ *      port            --  Select port number (0..6)
+ *      dir             --  AIR_PORT_TX
+ *                          AIR_PORT_RX
+ * OUTPUT:
+ *      ptr_fc_en       --  FALSE: Port flow control disable
+ *                          TRUE: Port flow control enable
+ * RETURN:
+ *      AIR_E_OK
+ *      AIR_E_BAD_PARAMETER
+ *
+ * NOTES:
+ *      None
+ */
+AIR_ERROR_NO_T
+air_port_getFlowCtrl(
+    const UI32_T unit,
+    const UI32_T port,
+    const BOOL_T dir,
+    BOOL_T *ptr_fc_en)
+{
+    UI32_T u32dat = 0;
+
+    /* Check port range */
+    AIR_PARAM_CHK((port >= AIR_MAX_NUM_OF_PORTS), AIR_E_BAD_PARAMETER);
+    AIR_CHECK_PTR(ptr_fc_en);
+
+    /* Check directions */
+    if(dir != AIR_PORT_TX && dir != AIR_PORT_RX)
+        return AIR_E_BAD_PARAMETER;
+
+    /* Read port flow control status*/
+    aml_readReg(unit, PMCR(port), &u32dat);
+    if(dir == AIR_PORT_TX)
+    {
+        if((u32dat & FORCE_TX_FC) == FORCE_TX_FC)
+            *ptr_fc_en = TRUE;
+        else
+            *ptr_fc_en = FALSE;
+    }
+    else
+    {
+        if((u32dat & FORCE_RX_FC) == FORCE_RX_FC)
+            *ptr_fc_en = TRUE;
+        else
+            *ptr_fc_en = FALSE;
+    }
+
+    return AIR_E_OK;
+}
+
+/* FUNCTION NAME: air_port_setJumbo
+ * PURPOSE:
+ *      Set accepting jumbo frmes with specificied size.
+ *
+ * INPUT:
+ *      unit            --  Select device ID
+ *      pkt_len         --  Select max packet length
+ *                          RX_PKT_LEN_1518
+ *                          RX_PKT_LEN_1536
+ *                          RX_PKT_LEN_1552
+ *                          RX_PKT_LEN_MAX_JUMBO
+ *      frame_len       --  Select max lenght of jumbo frames
+ *                          Range : 2 - 16
+ *                          Units : K Bytes
+ * OUTPUT:
+ *      None
+ *
+ * RETURN:
+ *      AIR_E_OK
+ *      AIR_E_BAD_PARAMETER
+ *
+ * NOTES:
+ *      None
+ */
+AIR_ERROR_NO_T
+air_port_setJumbo(
+    const UI32_T unit,
+    const UI32_T pkt_len,
+    const UI32_T frame_len)
+{
+    UI32_T u32dat = 0;
+
+    /* Check packet length */
+    AIR_PARAM_CHK((pkt_len > 3), AIR_E_BAD_PARAMETER);
+
+    /* Check frame length */
+    AIR_PARAM_CHK((frame_len < 2), AIR_E_BAD_PARAMETER);
+    AIR_PARAM_CHK((frame_len > 16), AIR_E_BAD_PARAMETER);
+
+    /* Read and clear jumbo frame info */
+    aml_readReg(unit, GMACCR, &u32dat);
+    u32dat &= ~0x00F3;
+
+    /* Set max packet length */
+    u32dat |= pkt_len;
+
+    /* Set jumbo frames max length */
+    u32dat |= (frame_len << 4);
+
+    aml_writeReg(unit, GMACCR, u32dat);
+
+    return AIR_E_OK;
+}
+
+/* FUNCTION NAME: air_port_getJumbo
+ * PURPOSE:
+ *      Get accepting jumbo frmes with specificied size.
+ *
+ * INPUT:
+ *      unit            --  Select device ID
+ *
+ * OUTPUT:
+ *      ptr_pkt_len     --  Select max packet length
+ *                          RX_PKT_LEN_1518
+ *                          RX_PKT_LEN_1536
+ *                          RX_PKT_LEN_1552
+ *                          RX_PKT_LEN_MAX_JUMBO
+ *      ptr_frame_len   --  Select max lenght of jumbo frames
+ *                          Range : 2 - 16
+ *                          Units : K Bytes
+ * RETURN:
+ *      AIR_E_OK
+ *      AIR_E_BAD_PARAMETER
+ *
+ * NOTES:
+ *      None
+ */
+AIR_ERROR_NO_T
+air_port_getJumbo(
+    const UI32_T unit,
+    UI32_T *ptr_pkt_len,
+    UI32_T *ptr_frame_len)
+{
+    UI32_T u32dat = 0;
+
+    AIR_CHECK_PTR(ptr_pkt_len);
+    AIR_CHECK_PTR(ptr_frame_len);
+
+    /* Read and clear jumbo frame info */
+    aml_readReg(unit, GMACCR, &u32dat);
+
+    /* Set max packet length */
+    *ptr_pkt_len = (0x03 & u32dat);
+
+    /* Set jumbo frames max length */
+    *ptr_frame_len = (0x0F & (u32dat >> 4));
+
+    return AIR_E_OK;
+}
+
+/* FUNCTION NAME: air_port_setPsMode
+ * PURPOSE:
+ *      Set the power saving mode for a specific port.
+ *
+ * INPUT:
+ *      unit            --  Device ID
+ *      port            --  Index of port number
+ *      mode            --  Bit-map:
+ *                          AIR_PORT_PS_LINKSTATUS
+ *                          AIR_PORT_PS_EEE
+ *                          FALSE: Disable / TRUE: Enable
+ * OUTPUT:
+ *      None
+ *
+ * RETURN:
+ *      AIR_E_OK
+ *      AIR_E_BAD_PARAMETER
+ *
+ * NOTES:
+ *      None
+ */
+AIR_ERROR_NO_T
+air_port_setPsMode(
+    const UI32_T unit,
+    const UI32_T port,
+    const UI32_T mode)
+{
+    UI32_T u32dat = 0;
+    UI32_T u32cl45_1e_3c = 0;
+    UI32_T u32cl45_1e_3d = 0;
+    UI32_T u32cl45_1e_3e = 0;
+
+    /* Mistake proofing for port checking */
+    AIR_PARAM_CHK((port >= AIR_MAX_NUM_OF_GIGA_PORTS), AIR_E_BAD_PARAMETER);
+    AIR_PARAM_CHK((mode & (~AIR_PORT_PS_MASK)), AIR_E_BAD_PARAMETER);
+
+    /* Read data from register */
+    aml_readPhyRegCL45(unit, port, PHY_DEV_1EH, BYPASS_POWER_DOWN_REG0, &u32cl45_1e_3c);
+    aml_readPhyRegCL45(unit, port, PHY_DEV_1EH, BYPASS_POWER_DOWN_REG1, &u32cl45_1e_3d);
+    aml_readPhyRegCL45(unit, port, PHY_DEV_1EH, BYPASS_POWER_DOWN_REG2, &u32cl45_1e_3e);
+
+    if(mode & AIR_PORT_PS_LINKSTATUS)
+    {
+        /* Set Link Status
+         * Disable bypass function to enable */
+        u32cl45_1e_3c &= ~BITS(12, 15);
+        aml_writePhyRegCL45(unit, port, PHY_DEV_1EH, BYPASS_POWER_DOWN_REG0, u32cl45_1e_3c);
+        u32cl45_1e_3d &= ~BITS(12, 15);
+        aml_writePhyRegCL45(unit, port, PHY_DEV_1EH, BYPASS_POWER_DOWN_REG1, u32cl45_1e_3d);
+        u32cl45_1e_3e &= ~BITS(11, 15);
+        aml_writePhyRegCL45(unit, port, PHY_DEV_1EH, BYPASS_POWER_DOWN_REG2, u32cl45_1e_3e);
+    }
+    else
+    {
+        /* Set Link Status
+         * Enable bypass function to disable */
+        u32cl45_1e_3c |= BITS(12, 15);
+        aml_writePhyRegCL45(unit, port, PHY_DEV_1EH, BYPASS_POWER_DOWN_REG0, u32cl45_1e_3c);
+        u32cl45_1e_3d |= BITS(12, 15);
+        aml_writePhyRegCL45(unit, port, PHY_DEV_1EH, BYPASS_POWER_DOWN_REG1, u32cl45_1e_3d);
+        u32cl45_1e_3e |= BITS(11, 15);
+        aml_writePhyRegCL45(unit, port, PHY_DEV_1EH, BYPASS_POWER_DOWN_REG2, u32cl45_1e_3e);
+    }
+
+    if(mode & AIR_PORT_PS_EEE)
+    {
+        /* Enable EEE */
+        u32dat = (EEE_ADV_1000BT | EEE_ADV_100BT );
+        aml_writePhyRegCL45(unit, port, PHY_DEV_07H, EEE_ADV_REG, u32dat);
+    }
+    else
+    {
+        /* Disable EEE */
+        aml_writePhyRegCL45(unit, port, PHY_DEV_07H, EEE_ADV_REG, 0);
+    }
+    return AIR_E_OK;
+
+}
+
+/* FUNCTION NAME: air_port_getPsMode
+ * PURPOSE:
+ *      Get the power saving mode for a specific port.
+ *
+ * INPUT:
+ *      unit            --  Device ID
+ *      port            --  Index of port number
+ * OUTPUT:
+ *      ptr_mode        --  Bit-map:
+ *                          AIR_PORT_PS_LINKSTATUS
+ *                          AIR_PORT_PS_EEE
+ *                          FALSE: Disable / TRUE: Enable
+ * RETURN:
+ *      AIR_E_OK
+ *      AIR_E_BAD_PARAMETER
+ *
+ * NOTES:
+ *      None
+ */
+AIR_ERROR_NO_T
+air_port_getPsMode(
+    const UI32_T unit,
+    const UI32_T port,
+    UI32_T *ptr_mode)
+{
+    UI32_T u32cl45_1e_3e = 0;
+    UI32_T u32cl45_07_3c = 0;
+
+    /* Mistake proofing for port checking */
+    AIR_PARAM_CHK((port >= AIR_MAX_NUM_OF_GIGA_PORTS), AIR_E_BAD_PARAMETER);
+
+    /* Mistake proofing for mode checking */
+    AIR_CHECK_PTR(ptr_mode);
+
+    (*ptr_mode) = 0;
+
+    /* Check link-status power saving */
+    aml_readPhyRegCL45(unit, port, PHY_DEV_1EH, BYPASS_POWER_DOWN_REG2, &u32cl45_1e_3e);
+    if(!BITS_OFF_R(u32cl45_1e_3e, 11, 5))
+    {
+        /* Read Bypass the power-down TXVLD to check link-status
+         * power saving function state */
+        (*ptr_mode) |= AIR_PORT_PS_LINKSTATUS;
+    }
+
+    /* Check EEE */
+    aml_readPhyRegCL45(unit, port, PHY_DEV_07H, EEE_ADV_REG, &u32cl45_07_3c);
+    if( (u32cl45_07_3c & EEE_ADV_1000BT) && (u32cl45_07_3c & EEE_ADV_100BT) )
+    {
+        /* Read PMCR to check EEE ability */
+        (*ptr_mode) |= AIR_PORT_PS_EEE;
+    }
+
+    return AIR_E_OK;
+}
+
+/* FUNCTION NAME: air_port_setSmtSpdDwn
+ * PURPOSE:
+ *      Set Smart speed down feature for a specific port.
+ *
+ * INPUT:
+ *      unit            --  Device ID
+ *      port            --  Index of port number
+ *      state           --  FALSE:Disable
+ *                          TRUE: Enable
+ *      time            --  AIR_PORT_SSD_2T
+ *                          AIR_PORT_SSD_3T
+ *                          AIR_PORT_SSD_4T
+ *                          AIR_PORT_SSD_5T
+ * OUTPUT:
+ *      None
+ *
+ * RETURN:
+ *      AIR_E_OK
+ *      AIR_E_BAD_PARAMETER
+ *
+ * NOTES:
+ *      None
+ */
+AIR_ERROR_NO_T
+air_port_setSmtSpdDwn(
+    const UI32_T unit,
+    const UI32_T port,
+    const BOOL_T state,
+    const UI32_T time)
+{
+    UI32_T u32ext14 = 0;
+    UI32_T page = 0;
+
+    /* Mistake proofing for port checking */
+    AIR_PARAM_CHK((port >= AIR_MAX_NUM_OF_GIGA_PORTS), AIR_E_BAD_PARAMETER);
+
+    /* Mistake proofing for state checking */
+    AIR_PARAM_CHK(((TRUE != state) && (FALSE != state)), AIR_E_BAD_PARAMETER);
+
+    /* Mistake proofing for time checking */
+    AIR_PARAM_CHK((time >= AIR_PORT_SSD_LAST), AIR_E_BAD_PARAMETER);
+
+    /* Backup page */
+    aml_readPhyReg(unit, port, 0x1F, &page);
+
+    /* Switch to page 1*/
+    aml_writePhyReg(unit, port, 0x1F, 0x1);
+    /* Read data from register */
+    aml_readPhyReg(unit, port, 0x14, &u32ext14);
+
+    /* Write data to register */
+    if(TRUE == state)
+    {
+        u32ext14 |= BIT(4);
+    }
+    else
+    {
+        u32ext14 &= ~BIT(4);
+    }
+    u32ext14 &= ~BITS(2,3);
+    u32ext14 |= time << 2;
+
+    /* Switch to page 1*/
+    aml_writePhyReg(unit, port, 0x1F, 0x1);
+    /* Read data from register */
+    aml_writePhyReg(unit, port, 0x14, u32ext14);
+
+    /* Restore page */
+    aml_writePhyReg(unit, port, 0x1F, page);
+
+    return AIR_E_OK;
+}
+
+/* FUNCTION NAME: air_port_getSmtSpdDwn
+ * PURPOSE:
+ *      Get Smart speed down feature for a specific port.
+ *
+ * INPUT:
+ *      unit            --  Device ID
+ *      port            --  Index of port number
+ *
+ * OUTPUT:
+ *      ptr_state       --  FALSE:Disable
+ *                          TRUE: Enable
+ *      ptr_time        --  AIR_PORT_SSD_2T
+ *                          AIR_PORT_SSD_3T
+ *                          AIR_PORT_SSD_4T
+ *                          AIR_PORT_SSD_5T
+ * RETURN:
+ *      AIR_E_OK
+ *      AIR_E_BAD_PARAMETER
+ *
+ * NOTES:
+ *      None
+ */
+AIR_ERROR_NO_T
+air_port_getSmtSpdDwn(
+    const UI32_T unit,
+    const UI32_T port,
+    UI32_T *ptr_state,
+    UI32_T *ptr_time)
+{
+    UI32_T u32ext14 = 0;
+    UI32_T page = 0;
+
+    /* Mistake proofing for port checking */
+    AIR_PARAM_CHK((port >= AIR_MAX_NUM_OF_GIGA_PORTS), AIR_E_BAD_PARAMETER);
+
+    /* Mistake proofing for state checking */
+    AIR_CHECK_PTR(ptr_state);
+
+    /* Mistake proofing for time checking */
+    AIR_CHECK_PTR(ptr_time);
+
+    /* Backup page */
+    aml_readPhyReg(unit, port, 0x1F, &page);
+
+    /* Switch to page 1*/
+    aml_writePhyReg(unit, port, 0x1F, 0x1);
+    /* Read data from register */
+    aml_readPhyReg(unit, port, 0x14, &u32ext14);
+
+    (*ptr_state) = BITS_OFF_R(u32ext14, 4, 1);
+    (*ptr_time) = BITS_OFF_R(u32ext14, 2, 2);
+
+    /* Restore page */
+    aml_writePhyReg(unit, port, 0x1F, page);
+
+    return AIR_E_OK;
+}
+
+/* FUNCTION NAME: air_port_setEnable
+ * PURPOSE:
+ *      Set powerdown state for a specific port.
+ *
+ * INPUT:
+ *      unit            --  Device ID
+ *      port            --  Index of port number
+ *      state           --  FALSE:Disable
+ *                          TRUE: Enable
+ * OUTPUT:
+ *      None
+ *
+ * RETURN:
+ *      AIR_E_OK
+ *      AIR_E_BAD_PARAMETER
+ *
+ * NOTES:
+ *      None
+ */
+AIR_ERROR_NO_T
+air_port_setEnable(
+    const UI32_T unit,
+    const UI32_T port,
+    const BOOL_T state)
+{
+    UI32_T u32dat = 0;
+
+    /* Mistake proofing for port checking */
+    AIR_PARAM_CHK((port >= AIR_MAX_NUM_OF_GIGA_PORTS), AIR_E_BAD_PARAMETER);
+    AIR_PARAM_CHK(((TRUE != state) && (FALSE != state)), AIR_E_BAD_PARAMETER);
+
+    /* Read data from register */
+    aml_readPhyReg(unit, port, 0x0, &u32dat);
+
+    if(TRUE == state)
+    {
+        /* Enable port, so disable powerdown bit */
+        u32dat &= ~BIT(11);
+    }
+    else
+    {
+        /* Disable port, so enable powerdown bit */
+        u32dat |= BIT(11);
+    }
+
+    /* Write data to register */
+    aml_writePhyReg(unit, port, 0x0, u32dat);
+
+    return AIR_E_OK;
+}
+
+/* FUNCTION NAME: air_port_getEnable
+ * PURPOSE:
+ *      Get powerdown state for a specific port.
+ *
+ * INPUT:
+ *      unit            --  Device ID
+ *      port            --  Index of port number
+ *
+ * OUTPUT:
+ *      ptr_state       --  FALSE:Disable
+ *                          TRUE: Enable
+ * RETURN:
+ *      AIR_E_OK
+ *      AIR_E_BAD_PARAMETER
+ *
+ * NOTES:
+ *      None
+ */
+AIR_ERROR_NO_T
+air_port_getEnable(
+    const UI32_T unit,
+    const UI32_T port,
+    UI32_T *ptr_state)
+{
+    UI32_T u32dat = 0;
+
+    /* Mistake proofing for port checking */
+    AIR_PARAM_CHK((port >= AIR_MAX_NUM_OF_GIGA_PORTS), AIR_E_BAD_PARAMETER);
+
+    /* Mistake proofing for state checking */
+    AIR_CHECK_PTR(ptr_state);
+
+    /* Read data from register */
+    aml_readPhyReg(unit, port, 0x0, &u32dat);
+
+    (*ptr_state) = (~BITS_OFF_R(u32dat, 11, 1))&BIT(0);
+
+    return AIR_E_OK;
+}
+
+/* FUNCTION NAME: air_port_setPortMatrix
+ * PURPOSE:
+ *      Set port matrix from the specified device.
+ *
+ * INPUT:
+ *      unit            --  Unit id
+ *      port            --  Port id
+ *      port_bitmap     --  Matrix port bitmap
+ *
+ * OUTPUT:
+ *      None
+ *
+ * RETURN:
+ *      AIR_E_OK
+ *      AIR_E_OTHERS
+ *      AIR_E_BAD_PARAMETER
+ *
+ * NOTES:
+ *      none
+ */
+AIR_ERROR_NO_T
+air_port_setPortMatrix(
+    const UI32_T    unit,
+    const UI32_T    port,
+    const UI32_T    port_bitmap)
+{
+    AIR_ERROR_NO_T rc = AIR_E_OK;
+
+    AIR_PARAM_CHK((port >= AIR_MAX_NUM_OF_PORTS), AIR_E_BAD_PARAMETER);
+    AIR_PARAM_CHK((port_bitmap & (~AIR_ALL_PORT_BITMAP)), AIR_E_BAD_PARAMETER);
+
+    aml_writeReg(unit, PORTMATRIX(port), port_bitmap);
+
+    return rc;
+}
+
+/* FUNCTION NAME: air_port_getPortMatrix
+ * PURPOSE:
+ *      Get port matrix from the specified device.
+ *
+ * INPUT:
+ *      unit            --  Unit id
+ *      port            --  Port id
+ *
+ * OUTPUT:
+ *      p_port_bitmap   --  Matrix port bitmap
+ *
+ * RETURN:
+ *      AIR_E_OK
+ *      AIR_E_OTHERS
+ *      AIR_E_BAD_PARAMETER
+ *
+ * NOTES:
+ *      none
+ */
+AIR_ERROR_NO_T
+air_port_getPortMatrix(
+    const UI32_T    unit,
+    const UI32_T    port,
+    UI32_T          *p_port_bitmap)
+{
+    AIR_ERROR_NO_T rc = AIR_E_OK;
+    UI32_T val = 0;
+
+    AIR_PARAM_CHK((port >= AIR_MAX_NUM_OF_PORTS), AIR_E_BAD_PARAMETER);
+    AIR_CHECK_PTR(p_port_bitmap);
+
+    aml_readReg(unit, PORTMATRIX(port), &val);
+    *p_port_bitmap = val;
+
+    return rc;
+}
+
+/* FUNCTION NAME: air_port_setVlanMode
+ * PURPOSE:
+ *      Set port-based vlan mechanism from the specified device.
+ *
+ * INPUT:
+ *      unit            --  Unit id
+ *      port            --  Port id
+ *      mode            --  Port vlan mode
+ *
+ * OUTPUT:
+ *      None
+ *
+ * RETURN:
+ *      AIR_E_OK
+ *      AIR_E_OTHERS
+ *      AIR_E_BAD_PARAMETER
+ *
+ * NOTES:
+ *      none
+ */
+AIR_ERROR_NO_T
+air_port_setVlanMode(
+    const UI32_T    unit,
+    const UI32_T    port,
+    const AIR_PORT_VLAN_MODE_T mode)
+{
+    AIR_ERROR_NO_T rc = AIR_E_OK;
+    UI32_T val = 0;
+
+    AIR_PARAM_CHK((port >= AIR_MAX_NUM_OF_PORTS), AIR_E_BAD_PARAMETER);
+    AIR_PARAM_CHK((mode >= AIR_PORT_VLAN_MODE_LAST), AIR_E_BAD_PARAMETER);
+
+    aml_readReg(unit, PCR(port), &val);
+    val &= ~PCR_PORT_VLAN_MASK;
+    val |= (mode & PCR_PORT_VLAN_RELMASK) << PCR_PORT_VLAN_OFFT;
+    aml_writeReg(unit, PCR(port), val);
+
+    return rc;
+}
+
+/* FUNCTION NAME: air_port_getVlanMode
+ * PURPOSE:
+ *      Get port-based vlan mechanism from the specified device.
+ *
+ * INPUT:
+ *      unit            --  Unit id
+ *      port            --  Port id
+ *
+ * OUTPUT:
+ *      p_mode          --  Port vlan mode
+ *
+ * RETURN:
+ *      AIR_E_OK
+ *      AIR_E_OTHERS
+ *      AIR_E_BAD_PARAMETER
+ *
+ * NOTES:
+ *      none
+ */
+AIR_ERROR_NO_T
+air_port_getVlanMode(
+    const UI32_T    unit,
+    const UI32_T    port,
+    AIR_PORT_VLAN_MODE_T *p_mode)
+{
+    AIR_ERROR_NO_T rc = AIR_E_OK;
+    UI32_T val = 0;
+
+    AIR_PARAM_CHK((port >= AIR_MAX_NUM_OF_PORTS), AIR_E_BAD_PARAMETER);
+    AIR_CHECK_PTR(p_mode);
+
+    aml_readReg(unit, PCR(port), &val);
+    *p_mode = (val >> PCR_PORT_VLAN_OFFT) & PCR_PORT_VLAN_RELMASK;
+
+    return rc;
+}
+
+/* FUNCTION NAME: air_port_setSpTag
+ * PURPOSE:
+ *      Set special tag state of a specific port.
+ *
+ * INPUT:
+ *      unit            --  Device ID
+ *      port            --  Index of port number
+ *      sptag_en        --  TRUE:  Enable special tag
+ *                          FALSE: Disable special tag
+ * OUTPUT:
+ *        None
+ *
+ * RETURN:
+ *        AIR_E_OK
+ *        AIR_E_BAD_PARAMETER
+ *
+ * NOTES:
+ *      None
+ */
+AIR_ERROR_NO_T
+air_port_setSpTag(
+    const UI32_T unit,
+    const UI32_T port,
+    const BOOL_T sptag_en)
+{
+    UI32_T u32dat = 0;
+
+    /* Mistake proofing for port checking */
+    AIR_PARAM_CHK((port >= AIR_MAX_NUM_OF_PORTS), AIR_E_BAD_PARAMETER);
+    AIR_PARAM_CHK(((TRUE != sptag_en) && (FALSE != sptag_en)), AIR_E_BAD_PARAMETER);
+
+    /* Read data from register */
+    aml_readReg(unit, PVC(port), &u32dat);
+
+    /* Write data to register */
+    if(TRUE == sptag_en)
+    {
+        u32dat |= PVC_SPTAG_EN_MASK;
+    }
+    else
+    {
+        u32dat &= ~PVC_SPTAG_EN_MASK;
+    }
+    aml_writeReg(unit, PVC(port), u32dat);
+
+    return AIR_E_OK;
+}
+
+/* FUNCTION NAME: air_port_getSpTag
+ * PURPOSE:
+ *      Get special tag state of a specific port.
+ *
+ * INPUT:
+ *      unit            --  Device ID
+ *      port            --  Index of port number
+ * OUTPUT:
+ *      ptr_sptag_en    --  TRUE:  Special tag enable
+ *                          FALSE: Special tag disable
+ *
+ * RETURN:
+ *        AIR_E_OK
+ *        AIR_E_BAD_PARAMETER
+ *
+ * NOTES:
+ *      None
+ */
+AIR_ERROR_NO_T
+air_port_getSpTag(
+    const UI32_T unit,
+    const UI32_T port,
+    BOOL_T *ptr_sptag_en)
+{
+    UI32_T u32dat = 0;
+
+    /* Mistake proofing for port checking */
+    AIR_PARAM_CHK((port >= AIR_MAX_NUM_OF_PORTS), AIR_E_BAD_PARAMETER);
+
+    /* Mistake proofing for state checking */
+    AIR_CHECK_PTR(ptr_sptag_en);
+
+    /* Read data from register */
+    aml_readReg(unit, PVC(port), &u32dat);
+
+    *ptr_sptag_en = (u32dat & PVC_SPTAG_EN_MASK) >> PVC_SPTAG_EN_OFFT;
+
+    return AIR_E_OK;
+}
+
+/* FUNCTION NAME: air_port_set5GBaseRModeEnable
+ * PURPOSE:
+ *      Set the port5 5GBase-R mode enable
+ *
+ * INPUT:
+ *      unit            --  Device ID
+ *
+ * OUTPUT:
+ *      None
+ *
+ * RETURN:
+ *      AIR_E_OK
+ *      AIR_E_BAD_PARAMETER
+ *
+ * NOTES:
+ *      None
+ */
+AIR_ERROR_NO_T
+air_port_set5GBaseRModeEn(
+    const UI32_T unit)
+{
+    AIR_ERROR_NO_T ret = AIR_E_OK;
+    UI32_T u32dat = 0;
+
+    /* PHYA Cal Enable (EFUSE) */
+    aml_readReg(unit, INTF_CTRL_8, &u32dat);
+    u32dat |= BIT(7);
+    aml_writeReg(unit, INTF_CTRL_8, u32dat);
+
+    aml_readReg(unit, INTF_CTRL_9, &u32dat);
+    u32dat |= BIT(31);
+    aml_writeReg(unit, INTF_CTRL_9, u32dat);
+
+    /* PMA Init */
+    /* PLL */
+    aml_readReg(unit, RX_CTRL_26, &u32dat);
+    u32dat |= BIT(23);
+    u32dat &= (~BIT(24));
+    u32dat |= BIT(26);
+    aml_writeReg(unit, RX_CTRL_26, u32dat);
+
+    aml_readReg(unit, QP_DIG_MODE_CTRL_1, &u32dat);
+    u32dat |= BITS(2, 3);
+    aml_writeReg(unit, QP_DIG_MODE_CTRL_1, u32dat);
+
+    aml_readReg(unit, PLL_CTRL_2, &u32dat);
+    u32dat |= BITS(0, 1);
+    u32dat &= ~(0x7 << 2);
+    u32dat |= (0x5 << 2);
+    u32dat &= ~(0x3 << 6);
+    u32dat |= (0x1 << 6);
+    u32dat &= ~(0x7 << 8);
+    u32dat |= (0x3 << 8);
+    u32dat |= BIT(29);
+    u32dat &= ~BITS(12, 13);
+    aml_writeReg(unit, PLL_CTRL_2, u32dat);
+
+    aml_readReg(unit, PLL_CTRL_4, &u32dat);
+    u32dat &= ~BIT(2);
+    aml_writeReg(unit, PLL_CTRL_4, u32dat);
+
+    aml_readReg(unit, PLL_CTRL_2, &u32dat);
+    u32dat &= ~BIT(14);
+    u32dat &= ~(0xf << 16);
+    u32dat |= (0x8 << 16);
+    u32dat &= ~BITS(20, 21);
+    u32dat &= ~(0x3 << 24);
+    u32dat |= (0x1 << 24);
+    u32dat &= ~BIT(26);
+    u32dat |= BIT(22);
+    u32dat |= BIT(27);
+    u32dat |= BIT(28);
+    aml_writeReg(unit, PLL_CTRL_2, u32dat);
+
+    aml_readReg(unit, PLL_CTRL_4, &u32dat);
+    u32dat &= ~(0x3 << 3);
+    u32dat |= (0x1 << 3);
+    aml_writeReg(unit, PLL_CTRL_4, u32dat);
+
+    aml_readReg(unit, PLL_CTRL_2, &u32dat);
+    u32dat &= ~BIT(30);
+    aml_writeReg(unit, PLL_CTRL_2, u32dat);
+
+    aml_readReg(unit, SS_LCPLL_PWCTL_SETTING_2, &u32dat);
+    u32dat |= BITS(16, 17);
+    aml_writeReg(unit, SS_LCPLL_PWCTL_SETTING_2, u32dat);
+
+    aml_writeReg(unit, SS_LCPLL_TDC_FLT_2, 0x1c800000);
+    aml_writeReg(unit, SS_LCPLL_TDC_PCW_1, 0x1c800000);
+
+    aml_readReg(unit, SS_LCPLL_TDC_FLT_5, &u32dat);
+    u32dat &= ~BIT(24);
+    aml_writeReg(unit, SS_LCPLL_TDC_FLT_5, u32dat);
+
+    aml_readReg(unit, PLL_CK_CTRL_0, &u32dat);
+    u32dat &= ~BIT(8);
+    aml_writeReg(unit, PLL_CK_CTRL_0, u32dat);
+
+    aml_readReg(unit, PLL_CTRL_3, &u32dat);
+    u32dat &= ~BITS(0, 15);
+    aml_writeReg(unit, PLL_CTRL_3, u32dat);
+
+    aml_readReg(unit, PLL_CTRL_4, &u32dat);
+    u32dat &= ~BITS(0, 1);
+    aml_writeReg(unit, PLL_CTRL_4, u32dat);
+
+    aml_readReg(unit, PLL_CTRL_3, &u32dat);
+    u32dat &= ~BITS(16, 31);
+    aml_writeReg(unit, PLL_CTRL_3, u32dat);
+
+    aml_readReg(unit, PLL_CK_CTRL_0, &u32dat);
+    u32dat &= ~BIT(9);
+    aml_writeReg(unit, PLL_CK_CTRL_0, u32dat);
+
+    aml_readReg(unit, RG_QP_PLL_IPLL_DIG_PWR_SEL, &u32dat);
+    u32dat &= ~(0x3 << 25);
+    u32dat |= (0x1 << 25);
+    aml_writeReg(unit, RG_QP_PLL_IPLL_DIG_PWR_SEL, u32dat);
+
+    aml_readReg(unit, RG_QP_PLL_SDM_ORD, &u32dat);
+    u32dat |= BIT(3);
+    u32dat |= BIT(4);
+    aml_writeReg(unit, RG_QP_PLL_SDM_ORD, u32dat);
+
+    aml_readReg(unit, RG_QP_RX_DAC_EN, &u32dat);
+    u32dat &= ~(0x3 << 16);
+    u32dat |= (0x2 << 16);
+    aml_writeReg(unit, RG_QP_RX_DAC_EN, u32dat);
+
+    aml_readReg(unit, PON_RXFEDIG_CTRL_0, &u32dat);
+    u32dat &= ~BIT(12);
+    aml_writeReg(unit, PON_RXFEDIG_CTRL_0, u32dat);
+
+    /* RX Control */
+    aml_readReg(unit, RG_QP_CDR_LPF_MJV_LIM, &u32dat);
+    u32dat &= ~BITS(4, 5);
+    aml_writeReg(unit, RG_QP_CDR_LPF_MJV_LIM, u32dat);
+
+    aml_readReg(unit, RG_QP_RXAFE_RESERVE, &u32dat);
+    u32dat |= BIT(11);
+    aml_writeReg(unit, RG_QP_RXAFE_RESERVE, u32dat);
+
+    aml_readReg(unit, RG_QP_CDR_PR_CKREF_DIV1, &u32dat);
+    u32dat &= ~(0x1f << 8);
+    u32dat |= (0xc << 8);
+    aml_writeReg(unit, RG_QP_CDR_PR_CKREF_DIV1, u32dat);
+
+    aml_readReg(unit, RG_QP_CDR_FORCE_IBANDLPF_R_OFF, &u32dat);
+    u32dat |= BIT(13);
+    aml_writeReg(unit, RG_QP_CDR_FORCE_IBANDLPF_R_OFF, u32dat);
+
+    aml_readReg(unit, RG_QP_CDR_PR_KBAND_DIV_PCIE, &u32dat);
+    u32dat |= BIT(30);
+    aml_writeReg(unit, RG_QP_CDR_PR_KBAND_DIV_PCIE, u32dat);
+
+    aml_readReg(unit, PLL_CTRL_0, &u32dat);
+    u32dat |= BIT(0);
+    aml_writeReg(unit, PLL_CTRL_0, u32dat);
+
+    aml_readReg(unit, RX_DLY_0, &u32dat);
+    u32dat &= ~(0xff << 0);
+    u32dat |= (0x6f << 0);
+    u32dat |= BITS(8, 13);
+    aml_writeReg(unit, RX_DLY_0, u32dat);
+
+    aml_readReg(unit, RX_CTRL_42, &u32dat);
+    u32dat &= ~(0x1fff << 0);
+    u32dat |= (0x150 << 0);
+    aml_writeReg(unit, RX_CTRL_42, u32dat);
+
+    aml_readReg(unit, RX_CTRL_2, &u32dat);
+    u32dat &= ~(0x1fff << 16);
+    u32dat |= (0x150 << 16);
+    aml_writeReg(unit, RX_CTRL_2, u32dat);
+
+    aml_readReg(unit, PON_RXFEDIG_CTRL_9, &u32dat);
+    u32dat |= BITS(0, 2);
+    aml_writeReg(unit, PON_RXFEDIG_CTRL_9, u32dat);
+
+    aml_readReg(unit, RX_CTRL_8, &u32dat);
+    u32dat &= ~(0xfff << 16);
+    u32dat |= (0x200 << 16);
+    aml_writeReg(unit, RX_CTRL_8, u32dat);
+
+    /* Frequency memter */
+    aml_readReg(unit, RX_CTRL_5, &u32dat);
+    u32dat &= ~(0xfffff << 10);
+    u32dat |= (0x9 << 10);
+    aml_writeReg(unit, RX_CTRL_5, u32dat);
+
+    aml_readReg(unit, RX_CTRL_6, &u32dat);
+    u32dat &= ~(0xfffff << 0);
+    u32dat |= (0x64 << 0);
+    aml_writeReg(unit, RX_CTRL_6, u32dat);
+
+    aml_readReg(unit, RX_CTRL_7, &u32dat);
+    u32dat &= ~(0xfffff << 0);
+    u32dat |= (0x2710 << 0);
+    aml_writeReg(unit, RX_CTRL_7, u32dat);
+
+    /* PCS Init */
+    aml_readReg(unit, RG_USXGMII_AN_CONTROL_0, &u32dat);
+    u32dat &= ~BIT(0);
+    aml_writeReg(unit, RG_USXGMII_AN_CONTROL_0, u32dat);
+
+    aml_readReg(unit, USGMII_CTRL_0, &u32dat);
+    u32dat |= BIT(2);
+    aml_writeReg(unit, USGMII_CTRL_0, u32dat);
+
+    aml_readReg(unit, MSG_RX_CTRL_0, &u32dat);
+    u32dat |= BIT(28);
+    aml_writeReg(unit, MSG_RX_CTRL_0, u32dat);
+
+    aml_readReg(unit, QP_CK_RST_CTRL_4, &u32dat);
+    u32dat |= BITS(14, 20);
+    aml_writeReg(unit, QP_CK_RST_CTRL_4, u32dat);
+
+    /* bypass flow control to MAC */
+    aml_writeReg(unit, MSG_RX_LIK_STS_0, 0x01010107);
+    aml_writeReg(unit, MSG_RX_LIK_STS_2, 0x00000EEF);
+
+    return ret;
+}
+
+/* FUNCTION NAME: air_port_setHsgmiiModeEnable
+ * PURPOSE:
+ *      Set the port5 HSGMII mode enable
+ *
+ * INPUT:
+ *      unit            --  Device ID
+ *
+ * OUTPUT:
+ *      None
+ *
+ * RETURN:
+ *      AIR_E_OK
+ *      AIR_E_BAD_PARAMETER
+ *
+ * NOTES:
+ *      None
+ */
+AIR_ERROR_NO_T
+air_port_setHsgmiiModeEn(
+    const UI32_T unit)
+{
+    AIR_ERROR_NO_T ret = AIR_E_OK;
+    UI32_T u32dat = 0;
+
+    /* PLL */
+    aml_readReg(unit, QP_DIG_MODE_CTRL_1, &u32dat);
+    u32dat &= ~(0x3 << 2);
+    u32dat |= (0x1 << 2);
+    aml_writeReg(unit, QP_DIG_MODE_CTRL_1, u32dat);
+
+    /* PLL - LPF */
+    aml_readReg(unit, PLL_CTRL_2, &u32dat);
+    u32dat &= ~(0x3 << 0);
+    u32dat |= (0x1 << 0);
+    u32dat &= ~(0x7 << 2);
+    u32dat |= (0x5 << 2);
+    u32dat &= ~BITS(6, 7);
+    u32dat &= ~(0x7 << 8);
+    u32dat |= (0x3 << 8);
+    u32dat |= BIT(29);
+    u32dat &= ~BITS(12, 13);
+    aml_writeReg(unit, PLL_CTRL_2, u32dat);
+
+    /* PLL - ICO */
+    aml_readReg(unit, PLL_CTRL_4, &u32dat);
+    u32dat |= BIT(2);
+    aml_writeReg(unit, PLL_CTRL_4, u32dat);
+
+    aml_readReg(unit, PLL_CTRL_2, &u32dat);
+    u32dat &= ~BIT(14);
+    aml_writeReg(unit, PLL_CTRL_2, u32dat);
+
+    /* PLL - CHP */
+    aml_readReg(unit, PLL_CTRL_2, &u32dat);
+    u32dat &= ~(0xf << 16);
+    u32dat |= (0x6 << 16);
+    aml_writeReg(unit, PLL_CTRL_2, u32dat);
+
+
+    /* PLL - PFD */
+    aml_readReg(unit, PLL_CTRL_2, &u32dat);
+    u32dat &= ~(0x3 << 20);
+    u32dat |= (0x1 << 20);
+    u32dat &= ~(0x3 << 24);
+    u32dat |= (0x1 << 24);
+    u32dat &= ~BIT(26);
+    aml_writeReg(unit, PLL_CTRL_2, u32dat);
+
+    /* PLL - POSTDIV */
+    aml_readReg(unit, PLL_CTRL_2, &u32dat);
+    u32dat |= BIT(22);
+    u32dat &= ~BIT(27);
+    u32dat &= ~BIT(28);
+    aml_writeReg(unit, PLL_CTRL_2, u32dat);
+
+    /* PLL - SDM */
+    aml_readReg(unit, PLL_CTRL_4, &u32dat);
+    u32dat &= ~BITS(3, 4);
+    aml_writeReg(unit, PLL_CTRL_4, u32dat);
+
+    aml_readReg(unit, PLL_CTRL_2, &u32dat);
+    u32dat &= ~BIT(30);
+    aml_writeReg(unit, PLL_CTRL_2, u32dat);
+
+    aml_readReg(unit, SS_LCPLL_PWCTL_SETTING_2, &u32dat);
+    u32dat &= ~(0x3 << 16);
+    u32dat |= (0x1 << 16);
+    aml_writeReg(unit, SS_LCPLL_PWCTL_SETTING_2, u32dat);
+
+    aml_writeReg(unit, SS_LCPLL_TDC_FLT_2, 0x7a000000);
+    aml_writeReg(unit, SS_LCPLL_TDC_PCW_1, 0x7a000000);
+
+    aml_readReg(unit, SS_LCPLL_TDC_FLT_5, &u32dat);
+    u32dat &= ~BIT(24);
+    aml_writeReg(unit, SS_LCPLL_TDC_FLT_5, u32dat);
+
+    aml_readReg(unit, PLL_CK_CTRL_0, &u32dat);
+    u32dat &= ~BIT(8);
+    aml_writeReg(unit, PLL_CK_CTRL_0, u32dat);
+
+    /* PLL - SS */
+    aml_readReg(unit, PLL_CTRL_3, &u32dat);
+    u32dat &= ~BITS(0, 15);
+    aml_writeReg(unit, PLL_CTRL_3, u32dat);
+
+    aml_readReg(unit, PLL_CTRL_4, &u32dat);
+    u32dat &= ~BITS(0, 1);
+    aml_writeReg(unit, PLL_CTRL_4, u32dat);
+
+    aml_readReg(unit, PLL_CTRL_3, &u32dat);
+    u32dat &= ~BITS(16, 31);
+    aml_writeReg(unit, PLL_CTRL_3, u32dat);
+
+    /* PLL - TDC */
+    aml_readReg(unit, PLL_CK_CTRL_0, &u32dat);
+    u32dat &= ~BIT(9);
+    aml_writeReg(unit, PLL_CK_CTRL_0, u32dat);
+
+    aml_readReg(unit, RG_QP_PLL_SDM_ORD, &u32dat);
+    u32dat |= BIT(3);
+    u32dat |= BIT(4);
+    aml_writeReg(unit, RG_QP_PLL_SDM_ORD, u32dat);
+
+    aml_readReg(unit, RG_QP_RX_DAC_EN, &u32dat);
+    u32dat &= ~(0x3 << 16);
+    u32dat |= (0x2 << 16);
+    aml_writeReg(unit, RG_QP_RX_DAC_EN, u32dat);
+
+    /* TCL Disable (only for Co-SIM) */
+    aml_readReg(unit, PON_RXFEDIG_CTRL_0, &u32dat);
+    u32dat &= ~BIT(12);
+    aml_writeReg(unit, PON_RXFEDIG_CTRL_0, u32dat);
+
+    /* TX Init */
+    aml_readReg(unit, RG_QP_TX_MODE_16B_EN, &u32dat);
+    u32dat &= ~BIT(0);
+    u32dat &= ~(0xffff << 16);
+    u32dat |= (0x4 << 16);
+    aml_writeReg(unit, RG_QP_TX_MODE_16B_EN, u32dat);
+
+    /* RX Control */
+    aml_readReg(unit, RG_QP_RXAFE_RESERVE, &u32dat);
+    u32dat |= BIT(11);
+    aml_writeReg(unit, RG_QP_RXAFE_RESERVE, u32dat);
+
+    aml_readReg(unit, RG_QP_CDR_LPF_MJV_LIM, &u32dat);
+    u32dat &= ~(0x3 << 4);
+    u32dat |= (0x1 << 4);
+    aml_writeReg(unit, RG_QP_CDR_LPF_MJV_LIM, u32dat);
+
+    aml_readReg(unit, RG_QP_CDR_LPF_SETVALUE, &u32dat);
+    u32dat &= ~(0xf << 25);
+    u32dat |= (0x1 << 25);
+    u32dat &= ~(0x7 << 29);
+    u32dat |= (0x3 << 29);
+    aml_writeReg(unit, RG_QP_CDR_LPF_SETVALUE, u32dat);
+
+    aml_readReg(unit, RG_QP_CDR_PR_CKREF_DIV1, &u32dat);
+    u32dat &= ~(0x1f << 8);
+    u32dat |= (0xf << 8);
+    aml_writeReg(unit, RG_QP_CDR_PR_CKREF_DIV1, u32dat);
+
+    aml_readReg(unit, RG_QP_CDR_PR_KBAND_DIV_PCIE, &u32dat);
+    u32dat &= ~(0x3f << 0);
+    u32dat |= (0x19 << 0);
+    u32dat &= ~BIT(6);
+    aml_writeReg(unit, RG_QP_CDR_PR_KBAND_DIV_PCIE, u32dat);
+
+    aml_readReg(unit, RG_QP_CDR_FORCE_IBANDLPF_R_OFF, &u32dat);
+    u32dat &= ~(0x7f << 6);
+    u32dat |= (0x21 << 6);
+    u32dat &= ~(0x3 << 16);
+    u32dat |= (0x2 << 16);
+    u32dat &= ~BIT(13);
+    aml_writeReg(unit, RG_QP_CDR_FORCE_IBANDLPF_R_OFF, u32dat);
+
+    aml_readReg(unit, RG_QP_CDR_PR_KBAND_DIV_PCIE, &u32dat);
+    u32dat &= ~BIT(30);
+    aml_writeReg(unit, RG_QP_CDR_PR_KBAND_DIV_PCIE, u32dat);
+
+    aml_readReg(unit, RG_QP_CDR_PR_CKREF_DIV1, &u32dat);
+    u32dat &= ~(0x7 << 24);
+    u32dat |= (0x4 << 24);
+    aml_writeReg(unit, RG_QP_CDR_PR_CKREF_DIV1, u32dat);
+
+    aml_readReg(unit, PLL_CTRL_0, &u32dat);
+    u32dat |= BIT(0);
+    aml_writeReg(unit, PLL_CTRL_0, u32dat);
+
+    aml_readReg(unit, RX_CTRL_26, &u32dat);
+    u32dat &= ~BIT(23);
+    u32dat |= BIT(26);
+    aml_writeReg(unit, RX_CTRL_26, u32dat);
+
+    aml_readReg(unit, RX_DLY_0, &u32dat);
+    u32dat &= ~(0xff << 0);
+    u32dat |= (0x6f << 0);
+    u32dat |= BITS(8, 13);
+    aml_writeReg(unit, RX_DLY_0, u32dat);
+
+    aml_readReg(unit, RX_CTRL_42, &u32dat);
+    u32dat &= ~(0x1fff << 0);
+    u32dat |= (0x150 << 0);
+    aml_writeReg(unit, RX_CTRL_42, u32dat);
+
+    aml_readReg(unit, RX_CTRL_2, &u32dat);
+    u32dat &= ~(0x1fff << 16);
+    u32dat |= (0x150 << 16);
+    aml_writeReg(unit, RX_CTRL_2, u32dat);
+
+    aml_readReg(unit, PON_RXFEDIG_CTRL_9, &u32dat);
+    u32dat &= ~(0x7 << 0);
+    u32dat |= (0x1 << 0);
+    aml_writeReg(unit, PON_RXFEDIG_CTRL_9, u32dat);
+
+    aml_readReg(unit, RX_CTRL_8, &u32dat);
+    u32dat &= ~(0xfff << 16);
+    u32dat |= (0x200 << 16);
+    u32dat &= ~(0x7fff << 14);
+    u32dat |= (0xfff << 14);
+    aml_writeReg(unit, RX_CTRL_8, u32dat);
+
+    /* Frequency memter */
+    aml_readReg(unit, RX_CTRL_5, &u32dat);
+    u32dat &= ~(0xfffff << 10);
+    u32dat |= (0x10 << 10);
+    aml_writeReg(unit, RX_CTRL_5, u32dat);
+
+    aml_readReg(unit, RX_CTRL_6, &u32dat);
+    u32dat &= ~(0xfffff << 0);
+    u32dat |= (0x64 << 0);
+    aml_writeReg(unit, RX_CTRL_6, u32dat);
+
+    aml_readReg(unit, RX_CTRL_7, &u32dat);
+    u32dat &= ~(0xfffff << 0);
+    u32dat |= (0x2710 << 0);
+    aml_writeReg(unit, RX_CTRL_7, u32dat);
+
+    /* PCS Init */
+    aml_readReg(unit, RG_HSGMII_PCS_CTROL_1, &u32dat);
+    u32dat &= ~BIT(30);
+    aml_writeReg(unit, RG_HSGMII_PCS_CTROL_1, u32dat);
+
+    /* Rate Adaption */
+    aml_readReg(unit, RATE_ADP_P0_CTRL_0, &u32dat);
+    u32dat &= ~BIT(31);
+    aml_writeReg(unit, RATE_ADP_P0_CTRL_0, u32dat);
+
+    aml_readReg(unit, RG_RATE_ADAPT_CTRL_0, &u32dat);
+    u32dat |= BIT(0);
+    u32dat |= BIT(4);
+    u32dat |= BITS(26, 27);
+    aml_writeReg(unit, RG_RATE_ADAPT_CTRL_0, u32dat);
+
+    /* Disable AN */
+    aml_readReg(unit, SGMII_REG_AN0, &u32dat);
+    u32dat &= ~BIT(12);
+    aml_writeReg(unit, SGMII_REG_AN0, u32dat);
+
+    /* Force Speed */
+    aml_readReg(unit, SGMII_STS_CTRL_0, &u32dat);
+    u32dat |= BIT(2);
+    u32dat |= BITS(4, 5);
+    aml_writeReg(unit, SGMII_STS_CTRL_0, u32dat);
+
+    /* bypass flow control to MAC */
+    aml_writeReg(unit, MSG_RX_LIK_STS_0, 0x01010107);
+    aml_writeReg(unit, MSG_RX_LIK_STS_2, 0x00000EEF);
+
+    return ret;
+}
+
+/* FUNCTION NAME: air_port_setSgmiiMode
+ * PURPOSE:
+ *      Set the port5 SGMII mode for AN or force
+ *
+ * INPUT:
+ *      unit            --  Device ID
+ *      mode            --  AIR_PORT_SGMII_MODE_AN
+ *                          AIR_PORT_SGMII_MODE_FORCE
+ *      speed           --  AIR_PORT_SPEED_10M:   10Mbps
+ *                          AIR_PORT_SPEED_100M:  100Mbps
+ *                          AIR_PORT_SPEED_1000M: 1Gbps
+ *
+ * OUTPUT:
+ *      None
+ *
+ * RETURN:
+ *      AIR_E_OK
+ *      AIR_E_BAD_PARAMETER
+ *
+ * NOTES:
+ *      None
+ */
+AIR_ERROR_NO_T
+air_port_setSgmiiMode(
+    const UI32_T unit,
+    const UI32_T mode,
+    const UI32_T speed)
+{
+    AIR_ERROR_NO_T ret = AIR_E_OK;
+    UI32_T u32dat = 0;
+
+    AIR_PARAM_CHK(((AIR_PORT_SGMII_MODE_AN != mode) && (AIR_PORT_SGMII_MODE_FORCE != mode)), AIR_E_BAD_PARAMETER);
+    AIR_PARAM_CHK((speed >= AIR_PORT_SPEED_2500M), AIR_E_BAD_PARAMETER);
+
+    /* PMA Init */
+    /* PLL */
+    aml_readReg(unit, QP_DIG_MODE_CTRL_1, &u32dat);
+    u32dat &= ~BITS(2, 3);
+    aml_writeReg(unit, QP_DIG_MODE_CTRL_1, u32dat);
+
+    /* PLL - LPF */
+    aml_readReg(unit, PLL_CTRL_2, &u32dat);
+    u32dat &= ~(0x3 << 0);
+    u32dat |= (0x1 << 0);
+    u32dat &= ~(0x7 << 2);
+    u32dat |= (0x5 << 2);
+    u32dat &= ~BITS(6, 7);
+    u32dat &= ~(0x7 << 8);
+    u32dat |= (0x3 << 8);
+    u32dat |= BIT(29);
+    u32dat &= ~BITS(12, 13);
+    aml_writeReg(unit, PLL_CTRL_2, u32dat);
+
+    /* PLL - ICO */
+    aml_readReg(unit, PLL_CTRL_4, &u32dat);
+    u32dat |= BIT(2);
+    aml_writeReg(unit, PLL_CTRL_4, u32dat);
+
+    aml_readReg(unit, PLL_CTRL_2, &u32dat);
+    u32dat &= ~BIT(14);
+    aml_writeReg(unit, PLL_CTRL_2, u32dat);
+
+    /* PLL - CHP */
+    aml_readReg(unit, PLL_CTRL_2, &u32dat);
+    u32dat &= ~(0xf << 16);
+    u32dat |= (0x4 << 16);
+    aml_writeReg(unit, PLL_CTRL_2, u32dat);
+
+
+    /* PLL - PFD */
+    aml_readReg(unit, PLL_CTRL_2, &u32dat);
+    u32dat &= ~(0x3 << 20);
+    u32dat |= (0x1 << 20);
+    u32dat &= ~(0x3 << 24);
+    u32dat |= (0x1 << 24);
+    u32dat &= ~BIT(26);
+    aml_writeReg(unit, PLL_CTRL_2, u32dat);
+
+    /* PLL - POSTDIV */
+    aml_readReg(unit, PLL_CTRL_2, &u32dat);
+    u32dat |= BIT(22);
+    u32dat &= ~BIT(27);
+    u32dat &= ~BIT(28);
+    aml_writeReg(unit, PLL_CTRL_2, u32dat);
+
+    /* PLL - SDM */
+    aml_readReg(unit, PLL_CTRL_4, &u32dat);
+    u32dat &= ~BITS(3, 4);
+    aml_writeReg(unit, PLL_CTRL_4, u32dat);
+
+    aml_readReg(unit, PLL_CTRL_2, &u32dat);
+    u32dat &= ~BIT(30);
+    aml_writeReg(unit, PLL_CTRL_2, u32dat);
+
+    aml_readReg(unit, SS_LCPLL_PWCTL_SETTING_2, &u32dat);
+    u32dat &= ~(0x3 << 16);
+    u32dat |= (0x1 << 16);
+    aml_writeReg(unit, SS_LCPLL_PWCTL_SETTING_2, u32dat);
+
+    aml_writeReg(unit, SS_LCPLL_TDC_FLT_2, 0x48000000);
+    aml_writeReg(unit, SS_LCPLL_TDC_PCW_1, 0x48000000);
+
+    aml_readReg(unit, SS_LCPLL_TDC_FLT_5, &u32dat);
+    u32dat &= ~BIT(24);
+    aml_writeReg(unit, SS_LCPLL_TDC_FLT_5, u32dat);
+
+    aml_readReg(unit, PLL_CK_CTRL_0, &u32dat);
+    u32dat &= ~BIT(8);
+    aml_writeReg(unit, PLL_CK_CTRL_0, u32dat);
+
+    /* PLL - SS */
+    aml_readReg(unit, PLL_CTRL_3, &u32dat);
+    u32dat &= ~BITS(0, 15);
+    aml_writeReg(unit, PLL_CTRL_3, u32dat);
+
+    aml_readReg(unit, PLL_CTRL_4, &u32dat);
+    u32dat &= ~BITS(0, 1);
+    aml_writeReg(unit, PLL_CTRL_4, u32dat);
+
+    aml_readReg(unit, PLL_CTRL_3, &u32dat);
+    u32dat &= ~BITS(16, 31);
+    aml_writeReg(unit, PLL_CTRL_3, u32dat);
+
+    /* PLL - TDC */
+    aml_readReg(unit, PLL_CK_CTRL_0, &u32dat);
+    u32dat &= ~BIT(9);
+    aml_writeReg(unit, PLL_CK_CTRL_0, u32dat);
+
+    aml_readReg(unit, RG_QP_PLL_SDM_ORD, &u32dat);
+    u32dat |= BIT(3);
+    u32dat |= BIT(4);
+    aml_writeReg(unit, RG_QP_PLL_SDM_ORD, u32dat);
+
+    aml_readReg(unit, RG_QP_RX_DAC_EN, &u32dat);
+    u32dat &= ~(0x3 << 16);
+    u32dat |= (0x2 << 16);
+    aml_writeReg(unit, RG_QP_RX_DAC_EN, u32dat);
+
+    /* PLL - TCL Disable (only for Co-SIM) */
+    aml_readReg(unit, PON_RXFEDIG_CTRL_0, &u32dat);
+    u32dat &= ~BIT(12);
+    aml_writeReg(unit, PON_RXFEDIG_CTRL_0, u32dat);
+
+    /* TX Init */
+    aml_readReg(unit, RG_QP_TX_MODE_16B_EN, &u32dat);
+    u32dat &= ~BIT(0);
+    u32dat &= ~BITS(16, 31);
+    aml_writeReg(unit, RG_QP_TX_MODE_16B_EN, u32dat);
+
+    /* RX Init */
+    aml_readReg(unit, RG_QP_RXAFE_RESERVE, &u32dat);
+    u32dat |= BIT(11);
+    aml_writeReg(unit, RG_QP_RXAFE_RESERVE, u32dat);
+
+    aml_readReg(unit, RG_QP_CDR_LPF_MJV_LIM, &u32dat);
+    u32dat &= ~(0x3 << 4);
+    u32dat |= (0x2 << 4);
+    aml_writeReg(unit, RG_QP_CDR_LPF_MJV_LIM, u32dat);
+
+    aml_readReg(unit, RG_QP_CDR_LPF_SETVALUE, &u32dat);
+    u32dat &= ~(0xf << 25);
+    u32dat |= (0x1 << 25);
+    u32dat &= ~(0x7 << 29);
+    u32dat |= (0x6 << 29);
+    aml_writeReg(unit, RG_QP_CDR_LPF_SETVALUE, u32dat);
+
+    aml_readReg(unit, RG_QP_CDR_PR_CKREF_DIV1, &u32dat);
+    u32dat &= ~(0x1f << 8);
+    u32dat |= (0xc << 8);
+    aml_writeReg(unit, RG_QP_CDR_PR_CKREF_DIV1, u32dat);
+
+    aml_readReg(unit, RG_QP_CDR_PR_KBAND_DIV_PCIE, &u32dat);
+    u32dat &= ~(0x3f << 0);
+    u32dat |= (0x19 << 0);
+    u32dat &= ~BIT(6);
+    aml_writeReg(unit, RG_QP_CDR_PR_KBAND_DIV_PCIE, u32dat);
+
+    aml_readReg(unit, RG_QP_CDR_FORCE_IBANDLPF_R_OFF, &u32dat);
+    u32dat &= ~(0x7f << 6);
+    u32dat |= (0x21 << 6);
+    u32dat &= ~(0x3 << 16);
+    u32dat |= (0x2 << 16);
+    u32dat &= ~BIT(13);
+    aml_writeReg(unit, RG_QP_CDR_FORCE_IBANDLPF_R_OFF, u32dat);
+
+    aml_readReg(unit, RG_QP_CDR_PR_KBAND_DIV_PCIE, &u32dat);
+    u32dat &= ~BIT(30);
+    aml_writeReg(unit, RG_QP_CDR_PR_KBAND_DIV_PCIE, u32dat);
+
+    aml_readReg(unit, RG_QP_CDR_PR_CKREF_DIV1, &u32dat);
+    u32dat &= ~(0x7 << 24);
+    u32dat |= (0x4 << 24);
+    aml_writeReg(unit, RG_QP_CDR_PR_CKREF_DIV1, u32dat);
+
+    aml_readReg(unit, PLL_CTRL_0, &u32dat);
+    u32dat |= BIT(0);
+    aml_writeReg(unit, PLL_CTRL_0, u32dat);
+
+    aml_readReg(unit, RX_CTRL_26, &u32dat);
+    u32dat &= ~BIT(23);
+    if(AIR_PORT_SGMII_MODE_AN == mode)
+    {
+        u32dat |= BIT(26);
+    }
+    aml_writeReg(unit, RX_CTRL_26, u32dat);
+
+    aml_readReg(unit, RX_DLY_0, &u32dat);
+    u32dat &= ~(0xff << 0);
+    u32dat |= (0x6f << 0);
+    u32dat |= BITS(8, 13);
+    aml_writeReg(unit, RX_DLY_0, u32dat);
+
+    aml_readReg(unit, RX_CTRL_42, &u32dat);
+    u32dat &= ~(0x1fff << 0);
+    u32dat |= (0x150 << 0);
+    aml_writeReg(unit, RX_CTRL_42, u32dat);
+
+    aml_readReg(unit, RX_CTRL_2, &u32dat);
+    u32dat &= ~(0x1fff << 16);
+    u32dat |= (0x150 << 16);
+    aml_writeReg(unit, RX_CTRL_2, u32dat);
+
+    aml_readReg(unit, PON_RXFEDIG_CTRL_9, &u32dat);
+    u32dat &= ~(0x7 << 0);
+    u32dat |= (0x1 << 0);
+    aml_writeReg(unit, PON_RXFEDIG_CTRL_9, u32dat);
+
+    aml_readReg(unit, RX_CTRL_8, &u32dat);
+    u32dat &= ~(0xfff << 16);
+    u32dat |= (0x200 << 16);
+    u32dat &= ~(0x7fff << 0);
+    u32dat |= (0xfff << 0);
+    aml_writeReg(unit, RX_CTRL_8, u32dat);
+
+    /* Frequency memter */
+    aml_readReg(unit, RX_CTRL_5, &u32dat);
+    u32dat &= ~(0xfffff << 10);
+    u32dat |= (0x28 << 10);
+    aml_writeReg(unit, RX_CTRL_5, u32dat);
+
+    aml_readReg(unit, RX_CTRL_6, &u32dat);
+    u32dat &= ~(0xfffff << 0);
+    u32dat |= (0x64 << 0);
+    aml_writeReg(unit, RX_CTRL_6, u32dat);
+
+    aml_readReg(unit, RX_CTRL_7, &u32dat);
+    u32dat &= ~(0xfffff << 0);
+    u32dat |= (0x2710 << 0);
+    aml_writeReg(unit, RX_CTRL_7, u32dat);
+
+    if(AIR_PORT_SGMII_MODE_FORCE == mode)
+    {
+        /* PCS Init */
+        aml_readReg(unit, QP_DIG_MODE_CTRL_0, &u32dat);
+        u32dat &= ~BIT(0);
+        if(AIR_PORT_SPEED_1000M == speed)
+        {
+            u32dat &= ~BITS(4, 5);
+        }
+        else if(AIR_PORT_SPEED_100M == speed)
+        {
+            u32dat &= ~(0x3 << 4);
+            u32dat |= (0x1 << 4);
+        }
+        else
+        {
+            u32dat &= ~(0x3 << 4);
+            u32dat |= (0x2 << 4);
+        }
+        aml_writeReg(unit, QP_DIG_MODE_CTRL_0, u32dat);
+
+        aml_readReg(unit, RG_HSGMII_PCS_CTROL_1, &u32dat);
+        u32dat &= ~BIT(30);
+        aml_writeReg(unit, RG_HSGMII_PCS_CTROL_1, u32dat);
+
+        /* Rate Adaption - GMII path config. */
+        aml_readReg(unit, RG_AN_SGMII_MODE_FORCE, &u32dat);
+        u32dat |= BIT(0);
+        if(AIR_PORT_SPEED_1000M == speed)
+        {
+            u32dat &= ~BITS(4, 5);
+        }
+        else if(AIR_PORT_SPEED_100M == speed)
+        {
+            u32dat &= ~(0x3 << 4);
+            u32dat |= (0x1 << 4);
+        }
+        else
+        {
+            u32dat &= ~(0x3 << 4);
+            u32dat |= (0x2 << 4);
+        }
+        aml_writeReg(unit, RG_AN_SGMII_MODE_FORCE, u32dat);
+
+        aml_readReg(unit, SGMII_STS_CTRL_0, &u32dat);
+        u32dat |= BIT(2);
+        if(AIR_PORT_SPEED_1000M == speed)
+        {
+            u32dat &= ~(0x3 << 4);
+            u32dat |= (0x2 << 4);
+        }
+        else if(AIR_PORT_SPEED_100M == speed)
+        {
+            u32dat &= ~(0x3 << 4);
+            u32dat |= (0x1 << 4);
+        }
+        else
+        {
+            u32dat &= ~BITS(4, 5);
+        }
+        aml_writeReg(unit, SGMII_STS_CTRL_0, u32dat);
+
+        aml_readReg(unit, SGMII_REG_AN0, &u32dat);
+        u32dat &= ~BIT(12);
+        aml_writeReg(unit, SGMII_REG_AN0, u32dat);
+
+        aml_readReg(unit, PHY_RX_FORCE_CTRL_0, &u32dat);
+        u32dat |= BIT(4);
+        aml_writeReg(unit, PHY_RX_FORCE_CTRL_0, u32dat);
+
+        aml_readReg(unit, RATE_ADP_P0_CTRL_0, &u32dat);
+        if(AIR_PORT_SPEED_1000M == speed)
+        {
+            u32dat &= ~BITS(0, 3);
+        }
+        else if(AIR_PORT_SPEED_100M == speed)
+        {
+            u32dat &= ~(0xf << 0);
+            u32dat |= (0xc << 0);
+        }
+        else
+        {
+            u32dat |= BITS(0, 3);
+        }
+        u32dat |= BIT(28);
+        aml_writeReg(unit, RATE_ADP_P0_CTRL_0, u32dat);
+
+        aml_readReg(unit, RG_RATE_ADAPT_CTRL_0, &u32dat);
+        u32dat |= BIT(0);
+        u32dat |= BIT(4);
+        if(AIR_PORT_SPEED_1000M == speed)
+        {
+            u32dat |= BITS(26, 27);
+        }
+        else
+        {
+            u32dat &= ~BITS(26, 27);
+        }
+        aml_writeReg(unit, RG_RATE_ADAPT_CTRL_0, u32dat);
+
+    }
+    else
+    {
+        /* PCS Init */
+        aml_readReg(unit, RG_HSGMII_PCS_CTROL_1, &u32dat);
+        u32dat &= ~BIT(30);
+        aml_writeReg(unit, RG_HSGMII_PCS_CTROL_1, u32dat);
+
+        /* Set AN Ability - Interrupt */
+        aml_readReg(unit, SGMII_REG_AN_FORCE_CL37, &u32dat);
+        u32dat |= BIT(0);
+        aml_writeReg(unit, SGMII_REG_AN_FORCE_CL37, u32dat);
+
+        aml_readReg(unit, SGMII_REG_AN_13, &u32dat);
+        u32dat &= ~(0x3f << 0);
+        u32dat |= (0xb << 0);
+        u32dat |= BIT(8);
+        aml_writeReg(unit, SGMII_REG_AN_13, u32dat);
+
+        /* Rate Adaption - GMII path config. */
+        aml_readReg(unit, SGMII_REG_AN0, &u32dat);
+        u32dat |= BIT(12);
+        aml_writeReg(unit, SGMII_REG_AN0, u32dat);
+
+        aml_readReg(unit, MII_RA_AN_ENABLE, &u32dat);
+        u32dat |= BIT(0);
+        aml_writeReg(unit, MII_RA_AN_ENABLE, u32dat);
+
+        aml_readReg(unit, RATE_ADP_P0_CTRL_0, &u32dat);
+        u32dat |= BIT(28);
+        aml_writeReg(unit, RATE_ADP_P0_CTRL_0, u32dat);
+
+        aml_readReg(unit, RG_RATE_ADAPT_CTRL_0, &u32dat);
+        u32dat |= BIT(0);
+        u32dat |= BIT(4);
+        u32dat |= BITS(26, 27);
+        aml_writeReg(unit, RG_RATE_ADAPT_CTRL_0, u32dat);
+
+        /* Only for Co-SIM */
+
+        /* AN Speed up (Only for Co-SIM) */
+
+        /* Restart AN */
+        aml_readReg(unit, SGMII_REG_AN0, &u32dat);
+        u32dat |= BIT(9);
+        u32dat |= BIT(15);
+        aml_writeReg(unit, SGMII_REG_AN0, u32dat);
+    }
+
+    /* bypass flow control to MAC */
+    aml_writeReg(unit, MSG_RX_LIK_STS_0, 0x01010107);
+    aml_writeReg(unit, MSG_RX_LIK_STS_2, 0x00000EEF);
+
+    return ret;
+}
+
+/* FUNCTION NAME: air_port_setRmiiMode
+ * PURPOSE:
+ *      Set the port5 RMII mode for 100Mbps or 10Mbps
+ *
+ * INPUT:
+ *      unit            --  Device ID
+ *      speed           --  AIR_PORT_SPEED_10M:  10Mbps
+ *                          AIR_PORT_SPEED_100M: 100Mbps
+ *
+ * OUTPUT:
+ *      None
+ *
+ * RETURN:
+ *      AIR_E_OK
+ *      AIR_E_BAD_PARAMETER
+ *
+ * NOTES:
+ *      None
+ */
+AIR_ERROR_NO_T
+air_port_setRmiiMode(
+    const UI32_T unit,
+    const UI32_T speed)
+{
+    AIR_ERROR_NO_T ret = AIR_E_OK;
+    UI32_T u32dat = 0;
+
+    /* Mistake proofing for speed checking */
+    AIR_PARAM_CHK((speed >= AIR_PORT_SPEED_1000M), AIR_E_BAD_PARAMETER);
+
+    if(AIR_PORT_SPEED_100M == speed)
+    {
+        aml_writeReg(unit, PMCR(5), 0x93159000);
+        aml_writeReg(unit, RG_P5MUX_MODE, 0x301);
+        aml_writeReg(unit, RG_FORCE_CKDIR_SEL, 0x101);
+        aml_writeReg(unit, RG_SWITCH_MODE, 0x101);
+        aml_writeReg(unit, RG_FORCE_MAC5_SB, 0x1010101);
+        aml_writeReg(unit, CSR_RMII, 0x420102);
+        aml_writeReg(unit, RG_RGMII_TXCK_C, 0x1100910);
+    }
+    else
+    {
+        aml_writeReg(unit, PMCR(5), 0x83159000);
+        aml_writeReg(unit, RG_P5MUX_MODE, 0x301);
+        aml_writeReg(unit, RG_FORCE_CKDIR_SEL, 0x101);
+        aml_writeReg(unit, RG_SWITCH_MODE, 0x101);
+        aml_writeReg(unit, RG_FORCE_MAC5_SB, 0x1000101);
+        aml_writeReg(unit, CSR_RMII, 0x420102);
+        aml_writeReg(unit, RG_RGMII_TXCK_C, 0x1100910);
+    }
+
+    return ret;
+}
+
+/* FUNCTION NAME: air_port_setRgmiiMode
+ * PURPOSE:
+ *      Set the port5 RGMII mode for 1Gbps or 100Mbps or 10Mbps
+ *
+ * INPUT:
+ *      unit            --  Device ID
+ *      speed           --  AIR_PORT_SPEED_10M:   10Mbps
+ *                          AIR_PORT_SPEED_100M:  100Mbps
+ *                          AIR_PORT_SPEED_1000M: 1Gbps
+ *
+ * OUTPUT:
+ *      None
+ *
+ * RETURN:
+ *      AIR_E_OK
+ *      AIR_E_BAD_PARAMETER
+ *
+ * NOTES:
+ *      None
+ */
+AIR_ERROR_NO_T
+air_port_setRgmiiMode(
+    const UI32_T unit,
+    const UI32_T speed)
+{
+    AIR_ERROR_NO_T ret = AIR_E_OK;
+    UI32_T u32dat = 0;
+
+    /* Mistake proofing for speed checking */
+    AIR_PARAM_CHK((speed >= AIR_PORT_SPEED_2500M), AIR_E_BAD_PARAMETER);
+
+    if(AIR_PORT_SPEED_1000M == speed)
+    {
+        aml_writeReg(unit, PMCR(5), 0xa3159000);
+        aml_writeReg(unit, RG_FORCE_MAC5_SB, 0x20101);
+    }
+    else if(AIR_PORT_SPEED_100M == speed)
+    {
+        aml_writeReg(unit, PMCR(5), 0x93159000);
+        aml_writeReg(unit, RG_FORCE_MAC5_SB, 0x10101);
+    }
+    else
+    {
+        aml_writeReg(unit, PMCR(5), 0x83159000);
+        aml_writeReg(unit, RG_FORCE_MAC5_SB, 0x101);
+    }
+
+    return ret;
+}
+
diff --git a/recipes-devtools/switch/files/src/an8855_sdk/api/src/air_qos.c b/recipes-devtools/switch/files/src/an8855_sdk/api/src/air_qos.c
new file mode 100644
index 0000000..c3829c8
--- /dev/null
+++ b/recipes-devtools/switch/files/src/an8855_sdk/api/src/air_qos.c
@@ -0,0 +1,1495 @@
+/* FILE NAME: air_qos.c
+ * PURPOSE:
+ *      Define the Quailty of Service function in AIR SDK.
+ *
+ * NOTES:
+ *      None
+ */
+
+ /* INCLUDE FILE DECLARATIONS
+ */
+#include "air.h"
+
+/* NAMING CONSTANT DECLARATIONS
+ */
+
+/* MACRO FUNCTION DECLARATIONS
+ */
+
+/* DATA TYPE DECLARATIONS
+ */
+
+/* GLOBAL VARIABLE DECLARATIONS
+ */
+
+/* LOCAL SUBPROGRAM DECLARATIONS
+ */
+
+/* STATIC VARIABLE DECLARATIONS
+ */
+
+/* LOCAL SUBPROGRAM BODIES
+ */
+
+/* EXPORTED SUBPROGRAM BODIES
+ */
+
+/* FUNCTION NAME:   air_qos_setScheduleAlgo
+ * PURPOSE:
+ *      Set schedule mode of a port queue.
+ * INPUT:
+ *      unit                 -- Device unit number
+ *      port                 -- Port id
+ *      queue                -- Queue id
+ *      sch_mode             -- AIR_QOS_SCH_MODE_T
+ *      weight               -- weight for WRR/WFQ
+ * OUTPUT:
+ *      None
+ * RETURN:
+ *      AIR_E_OK             -- Operation success.
+ *      AIR_E_BAD_PARAMETER  -- Parameter is wrong.
+ * NOTES:
+ *      Weight default value is 1, only for WRR/WFQ mode
+ */
+AIR_ERROR_NO_T
+air_qos_setScheduleAlgo(
+    const UI32_T unit,
+    const UI32_T port,
+    const UI32_T                queue,
+    const AIR_QOS_SCH_MODE_T    sch_mode,
+    const UI32_T                weight)
+{
+    UI32_T rc = AIR_E_OK;
+    UI32_T mac_port = 0;
+    AIR_QOS_SHAPER_MIN_T min_v;
+    AIR_QOS_SHAPER_MAX_T max_v;
+
+    /* Check parameter */
+    AIR_PARAM_CHK((unit >= AIR_MAX_NUM_OF_UNIT), AIR_E_BAD_PARAMETER);
+    AIR_PARAM_CHK((port >= AIR_MAX_NUM_OF_PORTS), AIR_E_BAD_PARAMETER);
+    AIR_PARAM_CHK((queue >= AIR_QOS_QUEUE_MAX_NUM), AIR_E_BAD_PARAMETER);
+    AIR_PARAM_CHK((sch_mode >= AIR_QOS_SCH_MODE_LAST), AIR_E_BAD_PARAMETER);
+    if (AIR_QOS_SHAPER_NOSETTING != weight)
+    {
+        AIR_PARAM_CHK(((weight >  AIR_QOS_SHAPER_RATE_MAX_WEIGHT) || 
+            (weight <  AIR_QOS_SHAPER_RATE_MIN_WEIGHT)), AIR_E_BAD_PARAMETER);
+    }
+    mac_port = port;
+    min_v.byte = 0;
+    max_v.byte = 0;
+     /*Read register data*/
+    switch(queue)
+    {
+        case AIR_QOS_QUEUE_0:
+            rc += aml_readReg(unit, MMSCR0_Q0(mac_port), &min_v.byte);
+            rc += aml_readReg(unit, MMSCR1_Q0(mac_port), &max_v.byte);
+            if(AIR_E_OK != rc)
+            {
+                AIR_PRINT("Get port %d queue %d failed, rc is %d", port, queue, rc);
+                return AIR_E_OTHERS;
+            }
+            break;
+
+        case AIR_QOS_QUEUE_1:
+            rc += aml_readReg(unit, MMSCR0_Q1(mac_port), &min_v.byte);
+            rc += aml_readReg(unit, MMSCR1_Q1(mac_port), &max_v.byte);
+            if(AIR_E_OK != rc)
+            {
+                AIR_PRINT("Get port %d queue %d failed, rc is %d", port, queue, rc);
+                return AIR_E_OTHERS;
+            }
+            break;
+
+        case AIR_QOS_QUEUE_2:
+            rc += aml_readReg(unit, MMSCR0_Q2(mac_port), &min_v.byte);
+            rc += aml_readReg(unit, MMSCR1_Q2(mac_port), &max_v.byte);
+            if(AIR_E_OK != rc)
+            {
+                AIR_PRINT("Get port %d queue %d failed, rc is %d", port, queue, rc);
+                return AIR_E_OTHERS;
+            }
+            break;
+
+        case AIR_QOS_QUEUE_3:
+            rc += aml_readReg(unit, MMSCR0_Q3(mac_port), &min_v.byte);
+            rc += aml_readReg(unit, MMSCR1_Q3(mac_port), &max_v.byte);
+            if(AIR_E_OK != rc)
+            {
+                AIR_PRINT("Get port %d queue %d failed, rc is %d", port, queue, rc);
+                return AIR_E_OTHERS;
+            }
+            break;
+
+        case AIR_QOS_QUEUE_4:
+            rc += aml_readReg(unit, MMSCR0_Q4(mac_port), &min_v.byte);
+            rc += aml_readReg(unit, MMSCR1_Q4(mac_port), &max_v.byte);
+            if(AIR_E_OK != rc)
+            {
+                AIR_PRINT("Get port %d queue %d failed, rc is %d", port, queue, rc);
+                return AIR_E_OTHERS;
+            }
+            break;
+
+        case AIR_QOS_QUEUE_5:
+            rc += aml_readReg(unit, MMSCR0_Q5(mac_port), &min_v.byte);
+            rc += aml_readReg(unit, MMSCR1_Q5(mac_port), &max_v.byte);
+            if(AIR_E_OK != rc)
+            {
+                AIR_PRINT("Get port %d queue %d failed, rc is %d", port, queue, rc);
+                return AIR_E_OTHERS;
+            }
+            break;
+
+        case AIR_QOS_QUEUE_6:
+            rc += aml_readReg(unit, MMSCR0_Q6(mac_port), &min_v.byte);
+            rc += aml_readReg(unit, MMSCR1_Q6(mac_port), &max_v.byte);
+            if(AIR_E_OK != rc)
+            {
+                AIR_PRINT("Get port %d queue %d failed, rc is %d", port, queue, rc);
+                return AIR_E_OTHERS;
+            }
+            break;
+
+        case AIR_QOS_QUEUE_7:
+            rc += aml_readReg(unit, MMSCR0_Q7(mac_port), &min_v.byte);
+            rc += aml_readReg(unit, MMSCR1_Q7(mac_port), &max_v.byte);
+            if(AIR_E_OK != rc)
+            {
+                AIR_PRINT("Get port %d queue %d failed, rc is %d", port, queue, rc);
+                return AIR_E_OTHERS;
+            }
+            break;
+
+        default:
+            AIR_PRINT("Not Support this queue %d num, please check again\n", queue);
+            return AIR_E_BAD_PARAMETER;
+    }
+
+    /*Get para*/
+    switch(sch_mode)
+    {
+        case AIR_QOS_SCH_MODE_SP:
+            min_v.raw.min_sp_wrr_q = 1;
+            min_v.raw.min_rate_en = 0;
+            break;
+
+        case AIR_QOS_SCH_MODE_WRR:
+            min_v.raw.min_sp_wrr_q = 0;
+            min_v.raw.min_rate_en = 0;
+            min_v.raw.min_weight = weight - 1;
+            break;
+
+        case AIR_QOS_SCH_MODE_WFQ:
+            min_v.raw.min_sp_wrr_q = 1;
+            min_v.raw.min_rate_en = 1;
+            min_v.raw.min_rate_man = 0;
+            min_v.raw.min_rate_exp = 0;
+
+            max_v.raw.max_rate_en = 0;
+            max_v.raw.max_sp_wfq_q = 0;
+            max_v.raw.max_weight = weight - 1;
+            break;
+        default:
+            AIR_PRINT("Not Support this mode %d num, please check again\n", sch_mode);
+            return AIR_E_BAD_PARAMETER;
+    }
+
+    /*Send to driver*/
+    switch(queue)
+    {
+        case AIR_QOS_QUEUE_0:
+            rc += aml_writeReg(unit, MMSCR0_Q0(mac_port), min_v.byte);
+            rc += aml_writeReg(unit, MMSCR1_Q0(mac_port), max_v.byte);
+            if(AIR_E_OK != rc)
+            {
+                AIR_PRINT("Set port %d queue %d failed, rc is %d", port, queue, rc);
+                return AIR_E_OTHERS;
+            }
+            break;
+
+        case AIR_QOS_QUEUE_1:
+            rc += aml_writeReg(unit, MMSCR0_Q1(mac_port), min_v.byte);
+            rc += aml_writeReg(unit, MMSCR1_Q1(mac_port), max_v.byte);
+            if(AIR_E_OK != rc)
+            {
+                AIR_PRINT("Set port %d queue %d failed, rc is %d", port, queue, rc);
+                return AIR_E_OTHERS;
+            }
+            break;
+
+        case AIR_QOS_QUEUE_2:
+            rc += aml_writeReg(unit, MMSCR0_Q2(mac_port), min_v.byte);
+            rc += aml_writeReg(unit, MMSCR1_Q2(mac_port), max_v.byte);
+            if(AIR_E_OK != rc)
+            {
+                AIR_PRINT("Set port %d queue %d failed, rc is %d", port, queue, rc);
+                return AIR_E_OTHERS;
+            }
+            break;
+
+        case AIR_QOS_QUEUE_3:
+            rc += aml_writeReg(unit, MMSCR0_Q3(mac_port), min_v.byte);
+            rc += aml_writeReg(unit, MMSCR1_Q3(mac_port), max_v.byte);
+            if(AIR_E_OK != rc)
+            {
+                AIR_PRINT("Set port %d queue %d failed, rc is %d", port, queue, rc);
+                return AIR_E_OTHERS;
+            }
+            break;
+
+        case AIR_QOS_QUEUE_4:
+            rc += aml_writeReg(unit, MMSCR0_Q4(mac_port), min_v.byte);
+            rc += aml_writeReg(unit, MMSCR1_Q4(mac_port), max_v.byte);
+            if(AIR_E_OK != rc)
+            {
+                AIR_PRINT("Set port %d queue %d failed, rc is %d", port, queue, rc);
+                return AIR_E_OTHERS;
+            }
+            break;
+
+        case AIR_QOS_QUEUE_5:
+            rc += aml_writeReg(unit, MMSCR0_Q5(mac_port), min_v.byte);
+            rc += aml_writeReg(unit, MMSCR1_Q5(mac_port), max_v.byte);
+            if(AIR_E_OK != rc)
+            {
+                AIR_PRINT("Set port %d queue %d failed, rc is %d", port, queue, rc);
+                return AIR_E_OTHERS;
+            }
+            break;
+
+        case AIR_QOS_QUEUE_6:
+            rc += aml_writeReg(unit, MMSCR0_Q6(mac_port), min_v.byte);
+            rc += aml_writeReg(unit, MMSCR1_Q6(mac_port), max_v.byte);
+            if(AIR_E_OK != rc)
+            {
+                AIR_PRINT("Set port %d queue %d failed, rc is %d", port, queue, rc);
+                return AIR_E_OTHERS;
+            }
+            break;
+
+        case AIR_QOS_QUEUE_7:
+            rc += aml_writeReg(unit, MMSCR0_Q7(mac_port), min_v.byte);
+            rc += aml_writeReg(unit, MMSCR1_Q7(mac_port), max_v.byte);
+            if(AIR_E_OK != rc)
+            {
+                AIR_PRINT("Set port %d queue %d failed, rc is %d", port, queue, rc);
+                return AIR_E_OTHERS;
+            }
+            break;
+
+        default:
+            AIR_PRINT("Not Support this queue %d num, please check again\n", queue);
+            return AIR_E_BAD_PARAMETER;
+    }
+    AIR_PRINT("Set schedule mode success,port is %d, queue is %d, min hex is %x, max hex is %x\n", port, queue, min_v.byte, max_v.byte);
+
+    return rc;
+}
+
+/* FUNCTION NAME: air_qos_getScheduleAlgo
+ * PURPOSE:
+ *      Get schedule mode of a port queue.
+ *
+ * INPUT:
+ *      unit            --  Select device ID
+ *      port            --  Port id
+ *      queue           --  Queue id
+ * OUTPUT:
+ *      ptr_sch_mode    --  AIR_QOS_SCH_MODE_T
+ *      ptr_weight      --  weight for WRR/WFQ
+ * RETURN:
+ *      AIR_E_OK
+ *      AIR_E_BAD_PARAMETER
+ *
+ * NOTES:
+ *     None
+ */
+AIR_ERROR_NO_T
+air_qos_getScheduleAlgo(
+    const UI32_T          unit,
+    const UI32_T          port,
+    const UI32_T          queue,
+    AIR_QOS_SCH_MODE_T    *ptr_sch_mode,
+    UI32_T                *ptr_weight)
+{
+    UI32_T rc = AIR_E_OK;
+    UI32_T mac_port = 0;
+    AIR_QOS_SHAPER_MIN_T min_v;
+    AIR_QOS_SHAPER_MAX_T max_v;
+
+    /*Read register data*/
+    /* Check parameter */
+    AIR_PARAM_CHK((unit >= AIR_MAX_NUM_OF_UNIT), AIR_E_BAD_PARAMETER);
+    AIR_PARAM_CHK((port >= AIR_MAX_NUM_OF_PORTS), AIR_E_BAD_PARAMETER);
+    AIR_PARAM_CHK((queue >= AIR_QOS_QUEUE_MAX_NUM), AIR_E_BAD_PARAMETER);
+    AIR_CHECK_PTR(ptr_sch_mode);
+    AIR_CHECK_PTR(ptr_weight);
+    
+    mac_port = port;
+    min_v.byte = 0;
+    max_v.byte = 0;
+
+    switch(queue)
+    {
+        case AIR_QOS_QUEUE_0:
+            rc += aml_readReg(unit, MMSCR0_Q0(mac_port), &min_v.byte);
+            rc += aml_readReg(unit, MMSCR1_Q0(mac_port), &max_v.byte);
+            if(AIR_E_OK != rc)
+            {
+                AIR_PRINT("Get port %d queue %d failed, rc is %d", port, queue, rc);
+                return AIR_E_OTHERS;
+            }
+            break;
+
+        case AIR_QOS_QUEUE_1:
+            rc += aml_readReg(unit, MMSCR0_Q1(mac_port), &min_v.byte);
+            rc += aml_readReg(unit, MMSCR1_Q1(mac_port), &max_v.byte);
+            if(AIR_E_OK != rc)
+            {
+                AIR_PRINT("Get port %d queue %d failed, rc is %d", port, queue, rc);
+                return AIR_E_OTHERS;
+            }
+            break;
+
+        case AIR_QOS_QUEUE_2:
+            rc += aml_readReg(unit, MMSCR0_Q2(mac_port), &min_v.byte);
+            rc += aml_readReg(unit, MMSCR1_Q2(mac_port), &max_v.byte);
+            if(AIR_E_OK != rc)
+            {
+                AIR_PRINT("Get port %d queue %d failed, rc is %d", port, queue, rc);
+                return AIR_E_OTHERS;
+            }
+            break;
+
+        case AIR_QOS_QUEUE_3:
+            rc += aml_readReg(unit, MMSCR0_Q3(mac_port), &min_v.byte);
+            rc += aml_readReg(unit, MMSCR1_Q3(mac_port), &max_v.byte);
+            if(AIR_E_OK != rc)
+            {
+                AIR_PRINT("Get port %d queue %d failed, rc is %d", port, queue, rc);
+                return AIR_E_OTHERS;
+            }
+            break;
+
+        case AIR_QOS_QUEUE_4:
+            rc += aml_readReg(unit, MMSCR0_Q4(mac_port), &min_v.byte);
+            rc += aml_readReg(unit, MMSCR1_Q4(mac_port), &max_v.byte);
+            if(AIR_E_OK != rc)
+            {
+                AIR_PRINT("Get port %d queue %d failed, rc is %d", port, queue, rc);
+                return AIR_E_OTHERS;
+            }
+            break;
+
+        case AIR_QOS_QUEUE_5:
+            rc += aml_readReg(unit, MMSCR0_Q5(mac_port), &min_v.byte);
+            rc += aml_readReg(unit, MMSCR1_Q5(mac_port), &max_v.byte);
+            if(AIR_E_OK != rc)
+            {
+                AIR_PRINT("Get port %d queue %d failed, rc is %d", port, queue, rc);
+                return AIR_E_OTHERS;
+            }
+            break;
+
+        case AIR_QOS_QUEUE_6:
+            rc += aml_readReg(unit, MMSCR0_Q6(mac_port), &min_v.byte);
+            rc += aml_readReg(unit, MMSCR1_Q6(mac_port), &max_v.byte);
+            if(AIR_E_OK != rc)
+            {
+                AIR_PRINT("Get port %d queue %d failed, rc is %d", port, queue, rc);
+                return AIR_E_OTHERS;
+            }
+            break;
+
+        case AIR_QOS_QUEUE_7:
+            rc += aml_readReg(unit, MMSCR0_Q7(mac_port), &min_v.byte);
+            rc += aml_readReg(unit, MMSCR1_Q7(mac_port), &max_v.byte);
+            if(AIR_E_OK != rc)
+            {
+                AIR_PRINT("Get port %d queue %d failed, rc is %d", port, queue, rc);
+                return AIR_E_OTHERS;
+            }
+            break;
+
+        default:
+            AIR_PRINT("Not Support this queue %d num, please check again", queue);
+            return AIR_E_BAD_PARAMETER;
+    }
+
+    /*Send para*/
+    if ((min_v.raw.min_rate_en) && AIR_QOS_MAX_TRAFFIC_ARBITRATION_SCHEME_WFQ == max_v.raw.max_sp_wfq_q)
+    {
+        *ptr_sch_mode = AIR_QOS_SCH_MODE_WFQ;
+        *ptr_weight = max_v.raw.max_weight + 1;
+    }
+    else
+    {
+        if(AIR_QOS_MIN_TRAFFIC_ARBITRATION_SCHEME_WRR == min_v.raw.min_sp_wrr_q)
+        {
+            *ptr_sch_mode = AIR_QOS_SCH_MODE_WRR;
+            *ptr_weight = min_v.raw.min_weight + 1;
+        }
+        else if(AIR_QOS_MIN_TRAFFIC_ARBITRATION_SCHEME_SP == min_v.raw.min_sp_wrr_q)
+        {
+            *ptr_sch_mode = AIR_QOS_SCH_MODE_SP;
+            *ptr_weight = AIR_QOS_SHAPER_NOSETTING;
+        }
+    }
+    AIR_PRINT("Get schedule mode success,port is %d, queue is %d, min hex is %x, max hex is %x\n", port, queue, min_v.byte, max_v.byte);
+
+    return rc;
+}
+
+/* FUNCTION NAME:   air_qos_setTrustMode
+ * PURPOSE:
+ *      Set qos trust mode value.
+ * INPUT:
+ *      unit                 -- Device unit number
+ *      port                  -.Select port number
+ *      mode                 -- Qos support mode
+ *                              AIR_QOS_TRUST_MODE_T
+ * OUTPUT:
+ *      None
+ * RETURN:
+ *      AIR_E_OK             -- Operation success.
+ *      AIR_E_BAD_PARAMETER  -- Parameter is wrong.
+ * NOTES:
+ *      None
+ */
+
+AIR_ERROR_NO_T
+air_qos_setTrustMode(
+    const UI32_T                    unit,
+    const UI32_T                    port,
+    const AIR_QOS_TRUST_MODE_T      mode)
+
+{
+    UI32_T rc = AIR_E_OTHERS;
+    AIR_QOS_QUEUE_UPW_T stat;
+
+    /* Check parameter */
+    AIR_PARAM_CHK((unit >= AIR_MAX_NUM_OF_UNIT), AIR_E_BAD_PARAMETER);
+    AIR_PARAM_CHK((port >= AIR_MAX_NUM_OF_PORTS), AIR_E_BAD_PARAMETER);
+    AIR_PARAM_CHK((mode >= AIR_QOS_TRUST_MODE_LAST), AIR_E_BAD_PARAMETER);
+
+    stat.byte = 0;
+    /*get register val*/
+    rc = aml_readReg(unit, PUPW(port), &(stat.byte));
+    AIR_PRINT("[Dbg]: get port %d rate trust weight success, UPW hex is %x\n", port, stat.byte);
+    stat.byte = AIR_QOS_QUEUE_DEFAULT_VAL;
+    if(AIR_E_OK == rc)
+    {
+        switch(mode)
+        {
+            case AIR_QOS_TRUST_MODE_PORT:
+                stat.raw.csr_port_weight = AIR_QOS_QUEUE_TRUST_HIGH_WEIGHT;
+                break;
+
+            case AIR_QOS_TRUST_MODE_1P_PORT:
+                stat.raw.csr_1p_weight = AIR_QOS_QUEUE_TRUST_HIGH_WEIGHT;
+                stat.raw.csr_port_weight = AIR_QOS_QUEUE_TRUST_MID_WEIGHT;
+                break;
+
+            case AIR_QOS_TRUST_MODE_DSCP_PORT:
+                stat.raw.csr_dscp_weight = AIR_QOS_QUEUE_TRUST_HIGH_WEIGHT;
+                stat.raw.csr_port_weight = AIR_QOS_QUEUE_TRUST_MID_WEIGHT;
+                break;
+
+            case AIR_QOS_TRUST_MODE_DSCP_1P_PORT:
+                stat.raw.csr_dscp_weight = AIR_QOS_QUEUE_TRUST_HIGH_WEIGHT;
+                stat.raw.csr_1p_weight = AIR_QOS_QUEUE_TRUST_MID_WEIGHT;
+                stat.raw.csr_port_weight = AIR_QOS_QUEUE_TRUST_LOW_WEIGHT;
+                break;
+
+            default:
+                AIR_PRINT("Not Support this mode %d yet\n", mode);
+                return AIR_E_BAD_PARAMETER;
+
+        }
+    }
+
+    /*set register val*/
+    rc = aml_writeReg(unit, PUPW(port), stat.byte);
+    if(AIR_E_OK != rc)
+    {
+        AIR_PRINT("[Dbg]: set port %d rate trust mode failed  rc is %d\n", port, rc);
+    }
+    else
+    {
+        AIR_PRINT("[Dbg]: set port %d rate trust mode %d weight success, UPW hex is %x\n", port, mode, stat.byte);
+    }
+    return rc;
+}
+
+/* FUNCTION NAME: air_qos_getTrustMode
+ * PURPOSE:
+ *      Get qos trust mode value.
+ *
+ * INPUT:
+ *      unit            --  Select device ID
+ *      port              -.Select port number
+ * OUTPUT:
+ *      ptr_weight      --  All Qos weight value
+ * RETURN:
+ *      AIR_E_OK
+ *      AIR_E_BAD_PARAMETER
+ *
+ * NOTES:
+ *      None
+ */
+AIR_ERROR_NO_T
+air_qos_getTrustMode(
+    const UI32_T unit,
+    const UI32_T                    port,
+    AIR_QOS_TRUST_MODE_T *const ptr_mode)
+
+{
+    UI32_T rc = AIR_E_OTHERS;
+    AIR_QOS_QUEUE_UPW_T stat;
+
+    /* Check parameter */
+    AIR_PARAM_CHK((unit >= AIR_MAX_NUM_OF_UNIT), AIR_E_BAD_PARAMETER);
+    AIR_PARAM_CHK((port >= AIR_MAX_NUM_OF_PORTS), AIR_E_BAD_PARAMETER);
+    AIR_CHECK_PTR(ptr_mode);
+
+    /*get register val*/
+    stat.byte = 0;
+    *ptr_mode = AIR_QOS_TRUST_MODE_1P_PORT;
+    rc = aml_readReg(unit, PUPW(port), &(stat.byte));
+    if(AIR_E_OK != rc)
+    {
+        AIR_PRINT("[Dbg]: get port %d rate trust mode failed  rc is %d\n",port, rc);
+    }
+    else
+    {
+        if (AIR_QOS_QUEUE_TRUST_HIGH_WEIGHT == stat.raw.csr_1p_weight)
+        {
+            *ptr_mode = AIR_QOS_TRUST_MODE_1P_PORT;
+        }
+        else if (AIR_QOS_QUEUE_TRUST_HIGH_WEIGHT == stat.raw.csr_dscp_weight)
+        {
+            if (AIR_QOS_QUEUE_TRUST_MID_WEIGHT == stat.raw.csr_1p_weight)
+            {
+                *ptr_mode = AIR_QOS_TRUST_MODE_DSCP_1P_PORT;
+            }
+            else if (AIR_QOS_QUEUE_TRUST_MID_WEIGHT == stat.raw.csr_port_weight)
+            {
+                *ptr_mode = AIR_QOS_TRUST_MODE_DSCP_PORT;
+            }
+        }
+        else if (AIR_QOS_QUEUE_TRUST_HIGH_WEIGHT == stat.raw.csr_port_weight)
+        {
+            *ptr_mode = AIR_QOS_TRUST_MODE_PORT;
+        }
+        else
+        {
+            AIR_PRINT("[Dbg]: port %d Not support this trust mode, UPW hex is %x\n", port, stat.byte);
+        }
+    }
+    AIR_PRINT("[Dbg]: port %d get trust mode success, UPW hex is %x\n", port, stat.byte);
+    return rc;
+}
+
+/* FUNCTION NAME: air_qos_setPri2Queue
+ * PURPOSE:
+ *      Set per port priority to out queue.
+ *
+ * INPUT:
+ *      unit            --  Select device ID
+ *      pri             --  Qos pri value
+ *      queue           --  Qos Queue value
+ *
+ * OUTPUT:
+ *      None
+ *
+ * RETURN:
+ *      AIR_E_OK
+ *      AIR_E_BAD_PARAMETER
+ *
+ * NOTES:
+ *      None
+ */
+AIR_ERROR_NO_T
+air_qos_setPri2Queue(
+    const UI32_T unit,
+    const UI32_T pri,
+    const UI32_T queue)
+{
+    UI32_T rc = AIR_E_OTHERS;
+    AIR_QOS_QUEUE_PEM_T stat;
+
+    /* Check parameter */
+    AIR_PARAM_CHK((unit >= AIR_MAX_NUM_OF_UNIT), AIR_E_BAD_PARAMETER);
+    AIR_PARAM_CHK((queue >= AIR_QOS_QUEUE_MAX_NUM), AIR_E_BAD_PARAMETER);
+    AIR_PARAM_CHK((pri >= AIR_QOS_QUEUE_MAX_NUM), AIR_E_BAD_PARAMETER);
+
+    stat.byte = 0;
+    /*get register val*/
+    switch(pri / 2)
+    {
+        case 0:
+            rc = aml_readReg(unit, PEM1, &stat.byte);
+            if(AIR_E_OK == rc)
+            {
+                if (1 == pri % 2)
+                {
+                    stat.raw.csr_que_cpu_h = queue;
+                }
+                else
+                {
+                     stat.raw.csr_que_cpu_l = queue;
+                }
+            }
+            rc = aml_writeReg(unit, PEM1, stat.byte);
+            break;
+
+        case 1:
+            rc = aml_readReg(unit, PEM2, &stat.byte);
+            if(AIR_E_OK == rc)
+            {
+                if (1 == pri % 2)
+                {
+                    stat.raw.csr_que_cpu_h = queue;
+                }
+                else
+                {
+                    stat.raw.csr_que_cpu_l = queue;
+                }
+            }
+            rc = aml_writeReg(unit, PEM2, stat.byte);
+            break;
+
+        case 2:
+            rc = aml_readReg(unit, PEM3, &stat.byte);
+            if(AIR_E_OK == rc)
+            {
+                if (1 == pri % 2)
+                {
+                    stat.raw.csr_que_cpu_h = queue;
+                }
+                else
+                {
+                    stat.raw.csr_que_cpu_l = queue;
+                }
+            }
+            rc = aml_writeReg(unit, PEM3, stat.byte);
+            break;
+
+        case 3:
+            rc = aml_readReg(unit, PEM4, &stat.byte);
+            if(AIR_E_OK == rc)
+            {
+                if (1 == pri % 2)
+                {
+                    stat.raw.csr_que_cpu_h = queue;
+                }
+                else
+                {
+                    stat.raw.csr_que_cpu_l = queue;
+                }
+            }
+            rc = aml_writeReg(unit, PEM4, stat.byte);
+            break;
+
+        default:
+            AIR_PRINT("[Dbg]: Not Support this pri %d yet\n", pri);
+            return AIR_E_BAD_PARAMETER;
+    }
+    AIR_PRINT("[Dbg]: set pri %d to queue %d success, PEM hex is %x\n"
+        , pri, queue, stat.byte);
+    return rc;
+}
+
+/* FUNCTION NAME: air_qos_getPri2Queue
+ * PURPOSE:
+ *      Get per port priority to out queue.
+ *
+ * INPUT:
+ *      unit            --  Select device ID
+ *      pri             --  Qos pri value
+ *
+ * OUTPUT:
+ *      ptr_queue       --  Select out queue (0..7)
+ *
+ * RETURN:
+ *      AIR_E_OK
+ *      AIR_E_BAD_PARAMETER
+ *
+ * NOTES:
+ *      None
+ */
+AIR_ERROR_NO_T
+air_qos_getPri2Queue(
+    const UI32_T unit,
+    const UI32_T pri,
+    UI32_T *const ptr_queue)
+{
+    UI32_T rc = AIR_E_OTHERS;
+    AIR_QOS_QUEUE_PEM_T stat;
+
+    /* Check parameter */
+    AIR_PARAM_CHK((unit >= AIR_MAX_NUM_OF_UNIT), AIR_E_BAD_PARAMETER);
+    AIR_PARAM_CHK((pri >= AIR_QOS_QUEUE_MAX_NUM), AIR_E_BAD_PARAMETER);
+    AIR_CHECK_PTR(ptr_queue);
+
+   /*get register val*/
+    stat.byte = 0;
+    switch(pri / 2)
+    {
+        case 0:
+            rc = aml_readReg(unit, PEM1, &stat.byte);
+            if(AIR_E_OK == rc)
+            {
+                if (1 == pri % 2)
+                {
+                    *ptr_queue = stat.raw.csr_que_cpu_h;
+                }
+                else
+                {
+                    *ptr_queue = stat.raw.csr_que_cpu_l;
+                }
+            }
+            break;
+
+        case 1:
+            rc = aml_readReg(unit, PEM2, &stat.byte);
+            if(AIR_E_OK == rc)
+            {
+                if (1 == pri % 2)
+                {
+                    *ptr_queue = stat.raw.csr_que_cpu_h;
+                }
+                else
+                {
+                    *ptr_queue = stat.raw.csr_que_cpu_l;
+                }
+            }
+            break;
+
+        case 2:
+            rc = aml_readReg(unit, PEM3, &stat.byte);
+            if(AIR_E_OK == rc)
+            {
+                if (1 == pri % 2)
+                {
+                    *ptr_queue = stat.raw.csr_que_cpu_h;
+                }
+                else
+                {
+                    *ptr_queue = stat.raw.csr_que_cpu_l;
+                }
+            }
+            break;
+
+        case 3:
+            rc = aml_readReg(unit, PEM4, &stat.byte);
+            if(AIR_E_OK == rc)
+            {
+                if (1 == pri % 2)
+                {
+                    *ptr_queue = stat.raw.csr_que_cpu_h;
+                }
+                else
+                {
+                    *ptr_queue = stat.raw.csr_que_cpu_l;
+                }
+            }
+            break;
+
+        default:
+            AIR_PRINT("[Dbg]: Not Support this pri %d yet\n", pri);
+            return AIR_E_BAD_PARAMETER;
+    }
+
+    if(AIR_E_OK != rc)
+    {
+        AIR_PRINT("[Dbg]: get pri to queue failed  rc is %d\n", rc);
+    }
+
+    AIR_PRINT("[Dbg]: get pri %d to queue %d mode success, PEM hex is %x\n"
+        , pri, *ptr_queue, stat.byte);
+    return rc;
+}
+
+/* FUNCTION NAME: air_qos_setDscp2Pri
+ * PURPOSE:
+ *      Set DSCP mapping to priority.
+ *
+ * INPUT:
+ *      unit            --  Select device ID
+ *      dscp            --  Select DSCP value (0..63)
+ *      priority        --  Select priority (0..7)
+ *
+ * OUTPUT:
+ *      None
+ *
+ * RETURN:
+ *      AIR_E_OK
+ *      AIR_E_BAD_PARAMETER
+ *
+ * NOTES:
+ *      None
+ */
+AIR_ERROR_NO_T
+air_qos_setDscp2Pri(
+    const UI32_T unit,
+    const UI32_T dscp,
+    const UI32_T pri)
+{
+    UI32_T rc = AIR_E_OTHERS;
+    UI32_T reg = 0;
+
+    /* Check parameter */
+    AIR_PARAM_CHK((unit >= AIR_MAX_NUM_OF_UNIT), AIR_E_BAD_PARAMETER);
+    AIR_PARAM_CHK((dscp >= AIR_QOS_QUEUE_DSCP_MAX_NUM), AIR_E_BAD_PARAMETER);
+    AIR_PARAM_CHK((pri >= AIR_QOS_QUEUE_MAX_NUM), AIR_E_BAD_PARAMETER);
+
+    /*get register val*/
+    switch (dscp/10)
+    {
+        case 0:
+            rc = aml_readReg(unit, PIM1, &reg);
+            if(AIR_E_OK == rc)
+            {
+                reg &= ~(AIR_QOS_QUEUE_PIM_MASK << AIR_QOS_QUEUE_PIM_WIDTH * (dscp % 10));
+                reg |= pri << 3 * (dscp % 10);
+                rc = aml_writeReg(unit, PIM1, reg);
+            }
+            break;
+
+        case 1:
+            rc = aml_readReg(unit, PIM2, &reg);
+            if(AIR_E_OK == rc)
+            {
+                reg &= ~(AIR_QOS_QUEUE_PIM_MASK << AIR_QOS_QUEUE_PIM_WIDTH * (dscp % 10));
+                reg |= pri << AIR_QOS_QUEUE_PIM_WIDTH * (dscp % 10);
+                rc = aml_writeReg(unit, PIM2, reg);
+            }
+            break;
+
+        case 2:
+            rc = aml_readReg(unit, PIM3, &reg);
+            if(AIR_E_OK == rc)
+            {
+                reg &= ~(AIR_QOS_QUEUE_PIM_MASK << AIR_QOS_QUEUE_PIM_WIDTH * (dscp % 10));
+                reg |= pri << AIR_QOS_QUEUE_PIM_WIDTH * (dscp % 10);
+                rc = aml_writeReg(unit, PIM3, reg);
+            }
+            break;
+
+        case 3:
+            rc = aml_readReg(unit, PIM4, &reg);
+            if(AIR_E_OK == rc)
+            {
+                reg &= ~(AIR_QOS_QUEUE_PIM_MASK << AIR_QOS_QUEUE_PIM_WIDTH * (dscp % 10));
+                reg |= pri << AIR_QOS_QUEUE_PIM_WIDTH * (dscp % 10);
+                rc = aml_writeReg(unit, PIM4, reg);
+            }
+            break;
+
+        case 4:
+            rc = aml_readReg(unit, PIM5, &reg);
+            if(AIR_E_OK == rc)
+            {
+                reg &= ~(AIR_QOS_QUEUE_PIM_MASK << AIR_QOS_QUEUE_PIM_WIDTH * (dscp % 10));
+                reg |= pri << AIR_QOS_QUEUE_PIM_WIDTH * (dscp % 10);
+                rc = aml_writeReg(unit, PIM5, reg);
+            }
+            break;
+
+        case 5:
+            rc = aml_readReg(unit, PIM6, &reg);
+            if(AIR_E_OK == rc)
+            {
+                reg &= ~(AIR_QOS_QUEUE_PIM_MASK << AIR_QOS_QUEUE_PIM_WIDTH * (dscp % 10));
+                reg |= pri << AIR_QOS_QUEUE_PIM_WIDTH * (dscp % 10);
+                rc = aml_writeReg(unit, PIM6, reg);
+            }
+            break;
+
+        case 6:
+            rc = aml_readReg(unit, PIM7, &reg);
+            if(AIR_E_OK == rc)
+            {
+                reg &= ~(AIR_QOS_QUEUE_PIM_MASK << AIR_QOS_QUEUE_PIM_WIDTH * (dscp % 10));
+                reg |= pri << AIR_QOS_QUEUE_PIM_WIDTH * (dscp % 10);
+                rc = aml_writeReg(unit, PIM7, reg);
+            }
+            break;
+
+        default:
+            AIR_PRINT("Not Support this dscp %d to pri, rc is %d\n", dscp, rc);
+            return AIR_E_BAD_PARAMETER;
+    }
+
+    if(AIR_E_OK != rc)
+    {
+        AIR_PRINT("set dscp to pri failed ,rc is %d\n", rc);
+    }
+    else
+    {
+        AIR_PRINT("set dscp  %u to pri %u success, PIM hex is %x\n", dscp, pri, reg);
+    }
+    return rc;
+}
+
+/* FUNCTION NAME: air_qos_getDscp2Pri
+ * PURPOSE:
+ *      Get DSCP mapping priority.
+ *
+ * INPUT:
+ *      unit            --  Select device ID
+ *      dscp            --  Select DSCP value (0..63)
+ *
+ * OUTPUT:
+ *      ptr_pri         --  Priority value (0..7)
+ *
+ * RETURN:
+ *      AIR_E_OK
+ *      AIR_E_BAD_PARAMETER
+ *
+ * NOTES:
+ *      None
+ */
+AIR_ERROR_NO_T
+air_qos_getDscp2Pri(
+    const UI32_T unit,
+    const UI32_T dscp,
+    UI32_T * const ptr_pri)
+{
+    UI32_T rc = AIR_E_OTHERS;
+    UI32_T reg = 0;
+
+    /* Check parameter */
+    AIR_PARAM_CHK((unit >= AIR_MAX_NUM_OF_UNIT), AIR_E_BAD_PARAMETER);
+    AIR_PARAM_CHK((dscp >= AIR_QOS_QUEUE_DSCP_MAX_NUM), AIR_E_BAD_PARAMETER);
+    AIR_CHECK_PTR(ptr_pri);
+
+    /*get register val*/
+    switch (dscp/10)
+    {
+        case 0:
+            rc = aml_readReg(unit, PIM1, &reg);
+            if(AIR_E_OK == rc)
+            {
+                *ptr_pri = (reg & (AIR_QOS_QUEUE_PIM_MASK << AIR_QOS_QUEUE_PIM_WIDTH * (dscp % 10)))
+                    >> AIR_QOS_QUEUE_PIM_WIDTH  * (dscp % 10);
+            }
+            break;
+
+        case 1:
+            rc = aml_readReg(unit, PIM2, &reg);
+            if(AIR_E_OK == rc)
+            {
+                *ptr_pri = (reg & (AIR_QOS_QUEUE_PIM_MASK << AIR_QOS_QUEUE_PIM_WIDTH * (dscp % 10)))
+                    >> AIR_QOS_QUEUE_PIM_WIDTH * (dscp % 10);
+            }
+            break;
+
+        case 2:
+            rc = aml_readReg(unit, PIM3, &reg);
+            if(AIR_E_OK == rc)
+            {
+                *ptr_pri = (reg & (AIR_QOS_QUEUE_PIM_MASK << AIR_QOS_QUEUE_PIM_WIDTH * (dscp % 10)))
+                    >> AIR_QOS_QUEUE_PIM_WIDTH * (dscp % 10);
+            }
+            break;
+
+        case 3:
+            rc = aml_readReg(unit, PIM4, &reg);
+            if(AIR_E_OK == rc)
+            {
+                *ptr_pri = (reg & (AIR_QOS_QUEUE_PIM_MASK << AIR_QOS_QUEUE_PIM_WIDTH * (dscp % 10)))
+                    >> AIR_QOS_QUEUE_PIM_WIDTH * (dscp % 10);
+            }
+            break;
+
+        case 4:
+            rc = aml_readReg(unit, PIM5, &reg);
+            if(AIR_E_OK == rc)
+            {
+                *ptr_pri = (reg & (AIR_QOS_QUEUE_PIM_MASK << AIR_QOS_QUEUE_PIM_WIDTH * (dscp % 10)))
+                    >> AIR_QOS_QUEUE_PIM_WIDTH * (dscp % 10);
+            }
+            break;
+
+        case 5:
+            rc = aml_readReg(unit, PIM6, &reg);
+            if(AIR_E_OK == rc)
+            {
+                *ptr_pri = (reg & (AIR_QOS_QUEUE_PIM_MASK << AIR_QOS_QUEUE_PIM_WIDTH * (dscp % 10)))
+                    >> AIR_QOS_QUEUE_PIM_WIDTH * (dscp % 10);
+            }
+            break;
+
+        case 6:
+            rc = aml_readReg(unit, PIM7, &reg);
+            if(AIR_E_OK == rc)
+            {
+                *ptr_pri = (reg & (AIR_QOS_QUEUE_PIM_MASK << AIR_QOS_QUEUE_PIM_WIDTH * (dscp % 10)))
+                    >> AIR_QOS_QUEUE_PIM_WIDTH * (dscp % 10);
+            }
+            break;
+
+        default:
+            AIR_PRINT("Not Support this dscp %d to pri, rc is %d\n", dscp, rc);
+            return AIR_E_BAD_PARAMETER;
+    }
+
+    if(AIR_E_OK != rc)
+    {
+        AIR_PRINT("[Dbg]: get dscp %d to pri failed, rc is %d\n", dscp, rc);
+    }
+
+    AIR_PRINT("[Dbg]: get dscp %u to pri %d success, PIM hex is %d \n", dscp, *ptr_pri, reg);
+    return rc;
+}
+
+/* FUNCTION NAME: air_qos_setRateLimitEnable
+ * PURPOSE:
+ *      Enable or disable port rate limit.
+ *
+ * INPUT:
+ *      unit            --  Select device ID
+ *      port            --  Select port number (0..6)
+ *      dir             --  AIR_QOS_RATE_DIR_INGRESS
+ *                          AIR_QOS_RATE_DIR_EGRESS
+ *      rate_en         --  TRUE: eanble rate limit
+ *                          FALSE: disable rate limit
+ * OUTPUT:
+ *      None
+ *
+ * RETURN:
+ *      AIR_E_OK
+ *      AIR_E_BAD_PARAMETER
+ *
+ * NOTES:
+ *      None
+ */
+AIR_ERROR_NO_T
+air_qos_setRateLimitEnable(
+    const UI32_T unit,
+    const UI32_T port,
+    const AIR_QOS_RATE_DIR_T dir,
+    const BOOL_T enable)
+{
+    UI32_T u32dat = 0, reg = 0;
+    UI32_T u32glo = 0, greg = 0;
+    UI32_T mac_port = 0;
+
+    /* Check parameter */
+    AIR_PARAM_CHK((unit >= AIR_MAX_NUM_OF_UNIT), AIR_E_BAD_PARAMETER);
+    AIR_PARAM_CHK((port >= AIR_MAX_NUM_OF_PORTS), AIR_E_BAD_PARAMETER);
+    AIR_PARAM_CHK((dir >= AIR_QOS_RATE_DIR_LAST), AIR_E_BAD_PARAMETER);
+    AIR_PARAM_CHK((enable != TRUE && enable != FALSE), AIR_E_BAD_PARAMETER);
+
+    mac_port = port;
+    if(AIR_QOS_RATE_DIR_EGRESS == dir)
+    {
+        reg = ERLCR(mac_port);
+        greg = GERLCR;
+    }
+    else if (AIR_QOS_RATE_DIR_INGRESS == dir)
+    {
+        reg = IRLCR(mac_port);
+        greg = GIRLCR;
+    }
+    else
+    {
+        AIR_PRINT("Not Support this dir %d yet\n", dir);
+        return AIR_E_BAD_PARAMETER;
+    }
+
+    aml_readReg(unit, reg, &u32dat);
+    if(TRUE == enable)
+    {
+        u32dat |= BIT(REG_RATE_EN_OFFT);
+        /* Enable tobke bucket mode */
+        u32dat |= BIT(REG_TB_EN_OFFT);
+    }
+    else
+    {
+        u32dat &= ~(BIT(REG_RATE_EN_OFFT));
+        /* Disable tobke bucket mode */
+        u32dat &= ~(BIT(REG_TB_EN_OFFT));
+    }
+    aml_writeReg(unit, reg, u32dat);
+
+    /* Rate include preamble/IPG/CRC */
+    aml_readReg(unit, greg, &u32glo);
+    u32glo &= ~(BITS_RANGE(REG_IPG_BYTE_OFFT, REG_IPG_BYTE_LENG));
+    u32glo |= AIR_QOS_L1_RATE_LIMIT;
+    aml_writeReg(unit, greg, u32glo);
+
+    return AIR_E_OK;
+}
+
+/* FUNCTION NAME: air_qos_getRateLimitEnable
+ * PURPOSE:
+ *      Get port rate limit state.
+ *
+ * INPUT:
+ *      unit            --  Select device ID
+ *      port            --  Select port number (0..6)
+ *      dir              -- AIR_QOS_RATE_DIR_T
+ * OUTPUT:
+ *      ptr_enable        --  TRUE: eanble rate limit
+ *                          FALSE: disable rate limit
+ * RETURN:
+ *      AIR_E_OK
+ *      AIR_E_BAD_PARAMETER
+ *
+ * NOTES:
+ *      None
+ */
+AIR_ERROR_NO_T
+air_qos_getRateLimitEnable(
+    const UI32_T                unit,
+    const UI32_T                port,
+    const AIR_QOS_RATE_DIR_T    dir,
+    BOOL_T                      *ptr_enable)
+{
+    UI32_T u32dat = 0, reg = 0, ret = 0;
+    UI32_T mac_port = 0;
+
+    /* Check parameter */
+    AIR_PARAM_CHK((unit >= AIR_MAX_NUM_OF_UNIT), AIR_E_BAD_PARAMETER);
+    AIR_PARAM_CHK((port >= AIR_MAX_NUM_OF_PORTS), AIR_E_BAD_PARAMETER);
+    AIR_PARAM_CHK((dir >= AIR_QOS_RATE_DIR_LAST), AIR_E_BAD_PARAMETER);
+    AIR_CHECK_PTR(ptr_enable);
+
+    mac_port = port;
+    /* Get ingress / egress register value */
+    if(AIR_QOS_RATE_DIR_EGRESS == dir)
+    {
+        reg = ERLCR(mac_port);
+    }
+    else
+    {
+        reg = IRLCR(mac_port);
+    }
+    aml_readReg(unit, reg, &u32dat);
+
+    ret = (u32dat & BIT(REG_RATE_EN_OFFT));
+    if(!ret)
+    {
+        *ptr_enable = FALSE;
+    }
+    else
+    {
+        *ptr_enable = TRUE;
+    }
+
+    return AIR_E_OK;
+}
+
+/* FUNCTION NAME: air_qos_setRateLimit
+ * PURPOSE:
+ *      Set per port rate limit.
+ *
+ * INPUT:
+ *      unit            --  Select device ID
+ *      port            --  Select port number
+ *      ptr_cfg         --  AIR_QOS_RATE_LIMIT_CFG_T
+ *
+ * OUTPUT:
+ *      None
+ *
+ * RETURN:
+ *      AIR_E_OK
+ *      AIR_E_BAD_PARAMETER
+ *
+ * NOTES:
+ *      None
+ */
+AIR_ERROR_NO_T
+air_qos_setRateLimit(
+    const UI32_T unit,
+    const UI32_T port,
+    AIR_QOS_RATE_LIMIT_CFG_T    *ptr_cfg)
+{
+    UI32_T u32dat = 0;
+    UI32_T mac_port = 0;
+
+    /* Check parameter */
+    AIR_PARAM_CHK((unit >= AIR_MAX_NUM_OF_UNIT), AIR_E_BAD_PARAMETER);
+    AIR_PARAM_CHK((port >= AIR_MAX_NUM_OF_PORTS), AIR_E_BAD_PARAMETER);
+    AIR_CHECK_PTR(ptr_cfg);
+    AIR_PARAM_CHK((ptr_cfg->egress_cbs >= AIR_QOS_MAX_TOKEN), AIR_E_BAD_PARAMETER);
+    AIR_PARAM_CHK((ptr_cfg->ingress_cbs >= AIR_QOS_MAX_TOKEN), AIR_E_BAD_PARAMETER);
+    AIR_PARAM_CHK((ptr_cfg->egress_cir >= AIR_QOS_MAX_CIR), AIR_E_BAD_PARAMETER);
+    AIR_PARAM_CHK((ptr_cfg->ingress_cir >= AIR_QOS_MAX_CIR), AIR_E_BAD_PARAMETER);
+
+    mac_port = port;
+    /* For Egress rate setting */
+    /* Set egress rate CIR */
+    aml_readReg(unit, ERLCR(mac_port), &u32dat);
+    u32dat &= ~ BITS_RANGE(REG_RATE_CIR_OFFT, REG_RATE_CIR_LENG);
+    u32dat |= ptr_cfg->egress_cir;
+    /* Set egress rate CBS */
+    u32dat &= ~ BITS_RANGE(REG_RATE_CBS_OFFT, REG_RATE_CBS_LENG);
+    u32dat |= BITS_OFF_L(ptr_cfg->egress_cbs, REG_RATE_CBS_OFFT, REG_RATE_CBS_LENG);
+    /* Enable tobke bucket mode */
+    u32dat |= BIT(REG_TB_EN_OFFT);
+    /* Set token period to 4ms */
+    u32dat &= ~ BITS_RANGE(REG_RATE_TB_OFFT, REG_RATE_TB_LENG);
+    u32dat |= BITS_OFF_L(AIR_QOS_TOKEN_PERIOD_4MS, REG_RATE_TB_OFFT, REG_RATE_TB_LENG);
+    if(ptr_cfg->flags & AIR_QOS_RATE_LIMIT_CFG_FLAGS_ENABLE_EGRESS)
+    {
+        /* Enable ratelimit mode*/
+        u32dat |= BIT(REG_RATE_EN_OFFT);
+    }
+    aml_writeReg(unit, ERLCR(mac_port), u32dat);
+
+
+    /* For Ingress rate setting */
+    /* Set ingress rate CIR */
+    aml_readReg(unit, IRLCR(mac_port), &u32dat);
+    u32dat &= ~ BITS_RANGE(REG_RATE_CIR_OFFT, REG_RATE_CIR_LENG);
+    u32dat |= ptr_cfg->ingress_cir;
+    /* Set egress rate CBS */
+    u32dat &= ~ BITS_RANGE(REG_RATE_CBS_OFFT, REG_RATE_CBS_LENG);
+    u32dat |= BITS_OFF_L(ptr_cfg->ingress_cbs, REG_RATE_CBS_OFFT, REG_RATE_CBS_LENG);
+    /* Enable tobke bucket mode */
+    u32dat |= BIT(REG_TB_EN_OFFT);
+    /* Set token period to 4ms */
+    u32dat &= ~ BITS_RANGE(REG_RATE_TB_OFFT, REG_RATE_TB_LENG);
+    u32dat |= BITS_OFF_L(AIR_QOS_TOKEN_PERIOD_4MS, REG_RATE_TB_OFFT, REG_RATE_TB_LENG);
+    if(ptr_cfg->flags & AIR_QOS_RATE_LIMIT_CFG_FLAGS_ENABLE_INGRESS)
+    {
+        /* Enable ratelimit mode*/
+        u32dat |= BIT(REG_RATE_EN_OFFT);
+    }
+    aml_writeReg(unit, IRLCR(mac_port), u32dat);
+
+    return AIR_E_OK;
+}
+
+/* FUNCTION NAME: air_qos_getRateLimit
+ * PURPOSE:
+ *      Get per port rate limit.
+ *
+ * INPUT:
+ *      unit            --  Select device ID
+ *      port            --  Select port number
+ *
+ * OUTPUT:
+ *      ptr_cfg          --  AIR_QOS_RATE_LIMIT_CFG_T
+ *
+ * RETURN:
+ *      AIR_E_OK
+ *      AIR_E_BAD_PARAMETER
+ *
+ * NOTES:
+ *      None
+ */
+AIR_ERROR_NO_T
+air_qos_getRateLimit(
+    const UI32_T unit,
+    const UI32_T port,
+    AIR_QOS_RATE_LIMIT_CFG_T *ptr_cfg)
+{
+    UI32_T u32dat = 0;
+    UI32_T mac_port = 0;
+
+    /* Check parameter */
+    AIR_PARAM_CHK((unit >= AIR_MAX_NUM_OF_UNIT), AIR_E_BAD_PARAMETER);
+    AIR_PARAM_CHK((port >= AIR_MAX_NUM_OF_PORTS), AIR_E_BAD_PARAMETER);
+    AIR_CHECK_PTR(ptr_cfg);
+
+    mac_port = port;
+    /* For Egress rate info */
+    aml_readReg(unit, ERLCR(mac_port), &u32dat);
+    ptr_cfg->egress_cir = BITS_OFF_R(u32dat, REG_RATE_CIR_OFFT, REG_RATE_CIR_LENG);
+    ptr_cfg->egress_cbs = BITS_OFF_R(u32dat, REG_RATE_CBS_OFFT, REG_RATE_CBS_LENG);
+
+    /* For Ingress rate info */
+    aml_readReg(unit, IRLCR(mac_port), &u32dat);
+    ptr_cfg->ingress_cir = BITS_OFF_R(u32dat, REG_RATE_CIR_OFFT, REG_RATE_CIR_LENG);
+    ptr_cfg->ingress_cbs = BITS_OFF_R(u32dat, REG_RATE_CBS_OFFT, REG_RATE_CBS_LENG);
+
+    return AIR_E_OK;
+}
+
+/* FUNCTION NAME: air_qos_setPortPriority
+ * PURPOSE:
+ *      Get poer port based priority.
+ *
+ * INPUT:
+ *      unit            --  Select device ID
+ *      port            --  Select port number
+ *      priority        --  Select port priority
+ *
+ * OUTPUT:
+ *      None
+ *
+ * RETURN:
+ *      AIR_E_OK
+ *      AIR_E_BAD_PARAMETER
+ *
+ * NOTES:
+ *      None
+ */
+AIR_ERROR_NO_T
+air_qos_setPortPriority(
+    const UI32_T unit,
+    const UI32_T port,
+    const UI32_T priority)
+{
+    UI32_T regPCR = 0;
+    UI32_T mac_port = 0;
+
+    /* Check parameter */
+    AIR_PARAM_CHK((unit >= AIR_MAX_NUM_OF_UNIT), AIR_E_BAD_PARAMETER);
+    AIR_PARAM_CHK((port >= AIR_MAX_NUM_OF_PORTS), AIR_E_BAD_PARAMETER);
+    AIR_PARAM_CHK((priority >= AIR_QOS_QUEUE_MAX_NUM), AIR_E_BAD_PARAMETER);
+    mac_port = port;
+    aml_readReg(unit, PCR(mac_port), &regPCR);
+    regPCR &= ~PCR_PORT_PRI_MASK;
+    regPCR |= (priority & PCR_PORT_PRI_RELMASK) << PCR_PORT_PRI_OFFT;
+    aml_writeReg(unit, PCR(mac_port), regPCR);
+
+    return AIR_E_OK;
+}
+
+/* FUNCTION NAME: air_qos_getPortPriority
+ * PURPOSE:
+ *      Set per port based priority.
+ *
+ * INPUT:
+ *      unit            --  Select device ID
+ *      port            --  Select port number
+ *
+ * OUTPUT:
+ *      ptr_pri         --  Get port based priority
+ *
+ * RETURN:
+ *      AIR_E_OK
+ *      AIR_E_BAD_PARAMETER
+ *
+ * NOTES:
+ *      None
+ */
+AIR_ERROR_NO_T
+air_qos_getPortPriority(
+    const UI32_T unit,
+    const UI32_T port,
+    UI32_T *ptr_pri)
+{
+    UI32_T regPCR = 0;
+    UI32_T mac_port = 0;
+
+    /* Check parameter */
+    AIR_PARAM_CHK((unit >= AIR_MAX_NUM_OF_UNIT), AIR_E_BAD_PARAMETER);
+    AIR_PARAM_CHK((port >= AIR_MAX_NUM_OF_PORTS), AIR_E_BAD_PARAMETER);
+    AIR_CHECK_PTR(ptr_pri);
+    mac_port = port;
+    aml_readReg(unit, PCR(mac_port), &regPCR);
+    *ptr_pri = (regPCR >> PCR_PORT_PRI_OFFT) & PCR_PORT_PRI_RELMASK;
+    return AIR_E_OK;
+}
+
+/* FUNCTION NAME: air_qos_setRateLimitExMngFrm
+ * PURPOSE:
+ *      Set rate limit control exclude/include management frames.
+ *
+ * INPUT:
+ *      unit            --  Select device ID
+ *      dir             --  AIR_RATE_DIR_INGRESS
+ *                          AIR_RATE_DIR_EGRESS
+ *      exclude         --  TRUE: Exclude management frame
+ *                          FALSE:Include management frame
+ * OUTPUT:
+ *      None
+ *
+ * RETURN:
+ *      AIR_E_OK
+ *      AIR_E_BAD_PARAMETER
+ *
+ * NOTES:
+ *      None
+ */
+AIR_ERROR_NO_T
+air_qos_setRateLimitExMngFrm(
+    const UI32_T unit,
+    const AIR_QOS_RATE_DIR_T dir,
+    const BOOL_T exclude)
+{
+    UI32_T u32dat = 0, reg = 0;
+
+    /* Check parameter */
+    AIR_PARAM_CHK((unit >= AIR_MAX_NUM_OF_UNIT), AIR_E_BAD_PARAMETER);
+    AIR_PARAM_CHK((dir != AIR_QOS_RATE_DIR_EGRESS), AIR_E_BAD_PARAMETER);
+    AIR_PARAM_CHK(((TRUE != exclude) && (FALSE != exclude)), AIR_E_BAD_PARAMETER);
+
+    reg = GERLCR;
+    /* Set to register */
+    aml_readReg(unit, reg, &u32dat);
+    if(TRUE == exclude)
+    {
+        u32dat |= BIT(REG_MFRM_EX_OFFT);
+    }
+    else
+    {
+        u32dat &= ~(BIT(REG_MFRM_EX_OFFT));
+    }
+    aml_writeReg(unit, reg, u32dat);
+
+    return AIR_E_OK;
+}
+
+/* FUNCTION NAME: air_qos_getRateLimitExMngFrm
+ * PURPOSE:
+ *      Get rate limit control exclude/include management frames.
+ *
+ * INPUT:
+ *      unit            --  Select device ID
+ *      dir             --  AIR_RATE_DIR_INGRESS
+ *                          AIR_RATE_DIR_EGRESS
+ * OUTPUT:
+ *      ptr_exclude     --  TRUE: Exclude management frame
+ *                          FALSE:Include management frame
+ * RETURN:
+ *      AIR_E_OK
+ *      AIR_E_BAD_PARAMETER
+ *
+ * NOTES:
+ *      None
+ */
+AIR_ERROR_NO_T
+air_qos_getRateLimitExMngFrm(
+    const UI32_T unit,
+    const AIR_QOS_RATE_DIR_T dir,
+    BOOL_T *ptr_exclude)
+{
+    UI32_T reg = 0, u32dat = 0;
+
+    /* Check parameter */
+    AIR_PARAM_CHK((unit >= AIR_MAX_NUM_OF_UNIT), AIR_E_BAD_PARAMETER);
+    AIR_PARAM_CHK((dir >= AIR_QOS_RATE_DIR_LAST), AIR_E_BAD_PARAMETER);
+    AIR_CHECK_PTR(ptr_exclude);
+    
+
+    if(AIR_QOS_RATE_DIR_EGRESS == dir)
+    {
+        reg = GERLCR;
+    }
+    else
+    {
+        reg = GIRLCR;
+    }
+
+    /* Set to register */
+    aml_readReg(unit, reg, &u32dat);
+    if(BITS_OFF_R(u32dat, REG_MFRM_EX_OFFT, REG_MFRM_EX_LENG))
+    {
+        *ptr_exclude = TRUE;
+    }
+    else
+    {
+        *ptr_exclude = FALSE;
+    }
+
+    return AIR_E_OK;
+}
+
diff --git a/recipes-devtools/switch/files/src/an8855_sdk/api/src/air_sec.c b/recipes-devtools/switch/files/src/an8855_sdk/api/src/air_sec.c
new file mode 100644
index 0000000..336a14f
--- /dev/null
+++ b/recipes-devtools/switch/files/src/an8855_sdk/api/src/air_sec.c
@@ -0,0 +1,593 @@
+/* FILE NAME: air_sec.c
+ * PURPOSE:
+ *      Define the security function in AIR SDK.
+ *
+ * NOTES:
+ *      None
+ */
+
+/* INCLUDE FILE DECLARATIONS
+ */
+#include "air.h"
+
+/* NAMING CONSTANT DECLARATIONS
+ */
+
+/* MACRO FUNCTION DECLARATIONS
+ */
+
+/* DATA TYPE DECLARATIONS
+ */
+
+/* GLOBAL VARIABLE DECLARATIONS
+ */
+
+/* LOCAL SUBPROGRAM DECLARATIONS
+ */
+
+/* STATIC VARIABLE DECLARATIONS
+ */
+
+/* LOCAL SUBPROGRAM BODIES
+ */
+
+/* EXPORTED SUBPROGRAM BODIES
+ */
+
+/* FUNCTION NAME: air_sec_setStormEnable
+ * PURPOSE:
+ *      Enable or disable per port storm control for specific type.
+ *
+ * INPUT:
+ *      unit            --  Select device ID
+ *      port            --  Select port number
+ *      type            --  AIR_STORM_TYPE_BCST
+ *                          AIR_STORM_TYPE_MCST
+ *                          AIR_STORM_TYPE_UCST
+ *      storm_en        --  TRUE
+ *                          FALSE
+ * OUTPUT:
+ *      None
+ *
+ * RETURN:
+ *      AIR_E_OK
+ *      AIR_E_BAD_PARAMETER
+ *
+ * NOTES:
+ *      None
+ */
+AIR_ERROR_NO_T
+air_sec_setStormEnable(
+    const UI32_T unit,
+    const UI32_T port,
+    const AIR_STORM_TYPE_T type,
+    const BOOL_T storm_en)
+{
+    UI32_T u32dat = 0, reg = 0, sp_en = 0;
+
+    /* Check parameter */
+    AIR_PARAM_CHK((port >= AIR_MAX_NUM_OF_PORTS), AIR_E_BAD_PARAMETER);
+    AIR_PARAM_CHK((type >= AIR_STORM_TYPE_LAST), AIR_E_BAD_PARAMETER);
+    AIR_PARAM_CHK(((storm_en != TRUE) && (storm_en != FALSE)), AIR_E_BAD_PARAMETER);
+
+    /* Find register BSR:broadcast, BSR_EXT1:multicast, BSR_EXT2:unicast */
+    switch(type)
+    {
+        case AIR_STORM_TYPE_BCST:
+            reg = BSR(port);
+            sp_en = BSR_STORM_BCST_EN;
+            break;
+        case AIR_STORM_TYPE_MCST:
+            reg = BSR_EXT1(port);
+            sp_en = BSR_STORM_MCST_EN;
+            break;
+        case AIR_STORM_TYPE_UCST:
+            reg = BSR_EXT2(port);
+            sp_en = BSR_STORM_UCST_EN;
+            break;
+        default:
+            break;
+    }
+
+    /* Enable specific type */
+    aml_readReg(unit, reg, &u32dat);
+    if(TRUE == storm_en)
+    {
+        u32dat |= (BSR_STORM_DROP_EN | BSR_STORM_RATE_BASED);
+        u32dat |= sp_en;
+    }
+    else
+    {
+        u32dat &= ~(BSR_STORM_DROP_EN | BSR_STORM_RATE_BASED);
+        u32dat &= ~sp_en;
+    }
+    aml_writeReg(unit, reg, u32dat);
+
+    return AIR_E_OK;
+}
+
+/* FUNCTION NAME: air_sec_getStormEnable
+ * PURPOSE:
+ *      Get per port status of storm control for specific type.
+ *
+ * INPUT:
+ *      unit            --  Select device ID
+ *      port            --  Select port number
+ *      type            --  AIR_STORM_TYPE_BCST
+ *                          AIR_STORM_TYPE_MCST
+ *                          AIR_STORM_TYPE_UCST
+ * OUTPUT:
+ *      ptr_storm_en    --  TRUE
+ *                          FALSE
+ * RETURN:
+ *      AIR_E_OK
+ *      AIR_E_BAD_PARAMETER
+ *
+ * NOTES:
+ *      None
+ */
+AIR_ERROR_NO_T
+air_sec_getStormEnable(
+    const UI32_T unit,
+    const UI32_T port,
+    const AIR_STORM_TYPE_T type,
+    BOOL_T *ptr_storm_en)
+{
+    UI32_T u32dat = 0, reg = 0, en = 0;
+
+    /* Check parameter */
+    AIR_PARAM_CHK((port >= AIR_MAX_NUM_OF_PORTS), AIR_E_BAD_PARAMETER);
+    AIR_PARAM_CHK((type >= AIR_STORM_TYPE_LAST), AIR_E_BAD_PARAMETER);
+    AIR_CHECK_PTR(ptr_storm_en);
+
+    /* Find register BSR:broadcast, BSR_EXT1:multicast, BSR_EXT2:unicast */
+    switch(type)
+    {
+        case AIR_STORM_TYPE_BCST:
+            reg = BSR(port);
+            break;
+        case AIR_STORM_TYPE_MCST:
+            reg = BSR_EXT1(port);
+            break;
+        case AIR_STORM_TYPE_UCST:
+            reg = BSR_EXT2(port);
+            break;
+        default:
+            break;
+    }
+
+    /* Enable specific type */
+    aml_readReg(unit, reg, &u32dat);
+    en = (u32dat & BSR_STORM_DROP_EN);
+    if(FALSE == en)
+    {
+        *ptr_storm_en = FALSE;
+    }
+    else
+    {
+        *ptr_storm_en = TRUE;
+    }
+
+    return AIR_E_OK;
+}
+
+/* FUNCTION NAME: air_sec_setStormRate
+ * PURPOSE:
+ *      Set per port storm rate limit control for specific type.
+ *
+ * INPUT:
+ *      unit            --  Select device ID
+ *      port            --  Select port number
+ *      type            --  AIR_STORM_TYPE_BCST
+ *                          AIR_STORM_TYPE_MCST
+ *                          AIR_STORM_TYPE_UCST
+ *      count           --  Count of the unit
+ *                          Range 0..255
+ *                          Rate = (count * unit) bps
+ *      unit            --  AIR_STORM_UNIT_64K
+ *                          AIR_STORM_UNIT_256K
+ *                          AIR_STORM_UNIT_1M
+ *                          AIR_STORM_UNIT_4M
+ *                          AIR_STORM_UNIT_16M
+                            AIR_STORM_UNIT_32M
+ * OUTPUT:
+ *      None
+ *
+ * RETURN:
+ *      AIR_E_OK
+ *      AIR_E_BAD_PARAMETER
+ *
+ * NOTES:
+ *      None
+ */
+AIR_ERROR_NO_T
+air_sec_setStormRate(
+    const UI32_T unit,
+    const UI32_T port,
+    const AIR_STORM_TYPE_T type,
+    const UI32_T count,
+    const AIR_STORM_UNIT_T storm_unit)
+{
+    UI32_T u32dat = 0, reg = 0;
+
+    /* Check parameter */
+    AIR_PARAM_CHK((port >= AIR_MAX_NUM_OF_PORTS), AIR_E_BAD_PARAMETER);
+    AIR_PARAM_CHK((type >= AIR_STORM_TYPE_LAST), AIR_E_BAD_PARAMETER);
+    AIR_PARAM_CHK((count > AIR_STORM_MAX_COUNT), AIR_E_BAD_PARAMETER);
+    AIR_PARAM_CHK((storm_unit >= AIR_STORM_UNIT_LAST), AIR_E_BAD_PARAMETER);
+
+    /* Find register BSR:broadcast, BSR_EXT1:multicast, BSR_EXT2:unicast */
+    switch(type)
+    {
+        case AIR_STORM_TYPE_BCST:
+            reg = BSR(port);
+            break;
+        case AIR_STORM_TYPE_MCST:
+            reg = BSR_EXT1(port);
+            break;
+        case AIR_STORM_TYPE_UCST:
+            reg = BSR_EXT2(port);
+            break;
+        default:
+            break;
+    }
+    /* Set storm rate limit unit */
+    aml_readReg(unit, reg, &u32dat);
+    u32dat &= ~(BSR_STORM_UNIT_MSK << BSR_STORM_UNIT_OFFT);
+    u32dat |= (storm_unit << BSR_STORM_UNIT_OFFT);
+    aml_writeReg(unit, reg, u32dat);
+
+    /* Find register BSR1:broadcast, BSR1_EXT1:multicast, BSR1_EXT2:unicast */
+    switch(type)
+    {
+        case AIR_STORM_TYPE_BCST:
+            reg = BSR1(port);
+            break;
+        case AIR_STORM_TYPE_MCST:
+            reg = BSR1_EXT1(port);
+            break;
+        case AIR_STORM_TYPE_UCST:
+            reg = BSR1_EXT2(port);
+            break;
+        default:
+            break;
+    }
+    /* Set storm rate limit count */
+    u32dat &= ~(BSR_STORM_COUNT_MSK << BSR1_10M_COUNT_OFFT);
+    u32dat |= (count << BSR1_10M_COUNT_OFFT);
+
+    u32dat &= ~(BSR_STORM_COUNT_MSK << BSR1_100M_COUNT_OFFT);
+    u32dat |= (count << BSR1_100M_COUNT_OFFT);
+
+    u32dat &= ~(BSR_STORM_COUNT_MSK << BSR1_1000M_COUNT_OFFT);
+    u32dat |= (count << BSR1_1000M_COUNT_OFFT);
+
+    u32dat &= ~(BSR_STORM_COUNT_MSK << BSR1_2500M_COUNT_OFFT);
+    u32dat |= (count << BSR1_2500M_COUNT_OFFT);
+    aml_writeReg(unit, reg, u32dat);
+
+    return AIR_E_OK;
+}
+
+/* FUNCTION NAME: air_sec_getStormRate
+ * PURPOSE:
+ *      Get per port storm rate limit control for specific type.
+ *
+ * INPUT:
+ *      unit            --  Select device ID
+ *      port            --  Select port number
+ *      type            --  AIR_STORM_TYPE_BCST
+ *                          AIR_STORM_TYPE_MCST
+ *                          AIR_STORM_TYPE_UCST
+ * OUTPUT:
+ *      ptr_count       --  Count of the unit
+ *                          Range 0..255
+ *                          Rate = (count * unit) bps
+ *      ptr_unit        --  AIR_STORM_UNIT_64K
+ *                          AIR_STORM_UNIT_256K
+ *                          AIR_STORM_UNIT_1M
+ *                          AIR_STORM_UNIT_4M
+ *                          AIR_STORM_UNIT_16M
+ *                          AIR_STORM_UNIT_32M
+ * RETURN:
+ *      AIR_E_OK
+ *      AIR_E_BAD_PARAMETER
+ *
+ * NOTES:
+ *      None
+ */
+AIR_ERROR_NO_T
+air_sec_getStormRate(
+    const UI32_T unit,
+    const UI32_T port,
+    const AIR_STORM_TYPE_T type,
+    UI32_T *ptr_count,
+    AIR_STORM_UNIT_T *ptr_unit)
+{
+    UI32_T u32dat = 0, reg = 0;
+
+    /* Check parameter */
+    AIR_PARAM_CHK((port >= AIR_MAX_NUM_OF_PORTS), AIR_E_BAD_PARAMETER);
+    AIR_PARAM_CHK((type >= AIR_STORM_TYPE_LAST), AIR_E_BAD_PARAMETER);
+    AIR_CHECK_PTR(ptr_count);
+    AIR_CHECK_PTR(ptr_unit);
+
+    /* Find register BSR:broadcast, BSR_EXT1:multicast, BSR_EXT2:unicast */
+    switch(type)
+    {
+        case AIR_STORM_TYPE_BCST:
+            reg = BSR(port);
+            break;
+        case AIR_STORM_TYPE_MCST:
+            reg = BSR_EXT1(port);
+            break;
+        case AIR_STORM_TYPE_UCST:
+            reg = BSR_EXT2(port);
+            break;
+        default:
+            break;
+    }
+    aml_readReg(unit, reg, &u32dat);
+    /* Get storm rate limit unit */
+    *ptr_unit = (BSR_STORM_UNIT_MSK & (u32dat >> BSR_STORM_UNIT_OFFT));
+
+    /* Find register BSR1:broadcast, BSR1_EXT1:multicast, BSR1_EXT2:unicast */
+    switch(type)
+    {
+        case AIR_STORM_TYPE_BCST:
+            reg = BSR1(port);
+            break;
+        case AIR_STORM_TYPE_MCST:
+            reg = BSR1_EXT1(port);
+            break;
+        case AIR_STORM_TYPE_UCST:
+            reg = BSR1_EXT2(port);
+            break;
+        default:
+            break;
+    }
+    aml_readReg(unit, reg, &u32dat);
+    /* Get storm rate limit count */
+    *ptr_count = (u32dat & BSR_STORM_COUNT_MSK);
+
+    return AIR_E_OK;
+}
+
+/* FUNCTION NAME: air_sec_setFldMode
+ * PURPOSE:
+ *      Set per port flooding status for unknown type frame.
+ *
+ * INPUT:
+ *      unit            --  Select device ID
+ *      port            --  Select port to setting
+ *      type            --  AIR_FLOOD_TYPE_BCST
+ *                          AIR_FLOOD_TYPE_MCST
+ *                          AIR_FLOOD_TYPE_UCST
+ *                          AIR_FLOOD_TYPE_QURY
+ *      fld_en          --  TRUE : flooding specific type frame for specific port
+ *                          FALSE: drop specific type frame for specific port
+ * OUTPUT:
+ *      None
+ *
+ * RETURN:
+ *      AIR_E_OK
+ *      AIR_E_BAD_PARAMETER
+ * NOTES:
+ *      None
+ */
+AIR_ERROR_NO_T
+air_sec_setFldMode(
+    const UI32_T unit,
+    const UI32_T port,
+    const AIR_FLOOD_TYPE_T type,
+    const BOOL_T fld_en)
+{
+    UI32_T u32dat = 0, reg = 0;
+
+    /* Check parameter */
+    AIR_PARAM_CHK((port >= AIR_MAX_NUM_OF_PORTS), AIR_E_BAD_PARAMETER);
+    AIR_PARAM_CHK((type >= AIR_FLOOD_TYPE_LAST), AIR_E_BAD_PARAMETER);
+    AIR_PARAM_CHK(((fld_en != TRUE) && (fld_en != FALSE)), AIR_E_BAD_PARAMETER);
+
+    /* Find register */
+    switch(type)
+    {
+        case AIR_FLOOD_TYPE_BCST:
+            reg = BCF;
+            break;
+        case AIR_FLOOD_TYPE_MCST:
+            reg = UNMF;
+            break;
+        case AIR_FLOOD_TYPE_UCST:
+            reg = UNUF;
+            break;
+        case AIR_FLOOD_TYPE_QURY:
+            reg = QRYP;
+            break;
+        default:
+            break;
+    }
+
+    aml_readReg(unit, reg, &u32dat);
+    if(TRUE == fld_en)
+    {
+        u32dat |= BIT(port);
+    }
+    else
+    {
+        u32dat &= ~BIT(port);
+    }
+    aml_writeReg(unit, reg, u32dat);
+
+    return AIR_E_OK;
+}
+
+/* FUNCTION NAME: air_sec_getFldMode
+ * PURPOSE:
+ *      Get per port flooding status for unknown type frame.
+ *
+ * INPUT:
+ *      unit            --  Select device ID
+ *      port            --  Select port to setting
+ *      type            --  AIR_FLOOD_TYPE_BCST
+ *                          AIR_FLOOD_TYPE_MCST
+ *                          AIR_FLOOD_TYPE_UCST
+ *                          AIR_FLOOD_TYPE_QURY
+ * OUTPUT:
+ *      ptr_fld_en      --  TRUE : flooding specific type frame for specific port
+ *                          FALSE: drop specific type frame for specific port
+ * RETURN:
+ *      AIR_E_OK
+ *      AIR_E_BAD_PARAMETER
+ *
+ * NOTES:
+ *      None
+ */
+AIR_ERROR_NO_T
+air_sec_getFldMode(
+    const UI32_T unit,
+    const UI32_T port,
+    const AIR_FLOOD_TYPE_T type,
+    BOOL_T *ptr_fld_en)
+{
+    UI32_T u32dat = 0, reg = 0, value = 0;
+
+    /* Check parameter */
+    AIR_PARAM_CHK((port >= AIR_MAX_NUM_OF_PORTS), AIR_E_BAD_PARAMETER);
+    AIR_PARAM_CHK((type >= AIR_FLOOD_TYPE_LAST), AIR_E_BAD_PARAMETER);
+    AIR_CHECK_PTR(ptr_fld_en);
+
+    /* Find register */
+    switch(type)
+    {
+        case AIR_FLOOD_TYPE_BCST:
+            reg = BCF;
+            break;
+        case AIR_FLOOD_TYPE_MCST:
+            reg = UNMF;
+            break;
+        case AIR_FLOOD_TYPE_UCST:
+            reg = UNUF;
+            break;
+        case AIR_FLOOD_TYPE_QURY:
+            reg = QRYP;
+            break;
+        default:
+            break;
+    }
+
+    aml_readReg(unit, reg, &u32dat);
+    value = u32dat & BIT(port);
+    if(FALSE == value)
+    {
+        *ptr_fld_en = FALSE;
+    }
+    else
+    {
+        *ptr_fld_en = TRUE;
+    }
+
+    return AIR_E_OK;
+}
+
+/* FUNCTION NAME: air_sec_setPortSecPortCfg
+ * PURPOSE:
+ *      Set port security configurations for specific port.
+ *
+ * INPUT:
+ *      unit            --  Device ID
+ *      port            --  Port ID
+ *      port_config     --  Structure of port configuration.
+ *
+ * OUTPUT:
+ *      None
+ *
+ * RETURN:
+ *      AIR_E_OK
+ *      AIR_E_BAD_PARAMETER
+ *
+ * NOTES:
+ *      None
+ */
+AIR_ERROR_NO_T
+air_sec_setPortSecPortCfg(
+    const UI32_T unit,
+    const UI32_T port,
+    const AIR_SEC_PORTSEC_PORT_CONFIG_T port_config)
+{
+    AIR_ERROR_NO_T rc = AIR_E_OK;
+    UI32_T u32dat = 0, value = 0;
+
+    /* Mistake proofing */
+    AIR_PARAM_CHK((port >= AIR_MAX_NUM_OF_PORTS), AIR_E_BAD_PARAMETER);
+    AIR_PARAM_CHK(((TRUE != port_config.sa_lrn_en) && (FALSE != port_config.sa_lrn_en)), AIR_E_BAD_PARAMETER);
+    AIR_PARAM_CHK(((TRUE != port_config.sa_lmt_en) && (FALSE != port_config.sa_lmt_en)), AIR_E_BAD_PARAMETER);
+    AIR_PARAM_CHK((port_config.sa_lmt_cnt > AIR_MAX_NUM_OF_MAC), AIR_E_BAD_PARAMETER);
+
+    aml_readReg(unit, PSC(port), &u32dat);
+
+    if(FALSE == port_config.sa_lrn_en)
+    {
+        u32dat |= BITS_RANGE(PSC_DIS_LRN_OFFSET, PSC_DIS_LRN_LENGTH);
+    }
+    else
+    {
+        u32dat &= ~BITS_RANGE(PSC_DIS_LRN_OFFSET, PSC_DIS_LRN_LENGTH);
+    }
+    if(FALSE == port_config.sa_lmt_en)
+    {
+        u32dat &= ~BITS_RANGE(PSC_SA_CNT_EN_OFFSET, PSC_SA_CNT_EN_LENGTH);
+        u32dat &= ~PSC_SA_CNT_LMT_MASK;
+        u32dat |= (PSC_SA_CNT_LMT_MAX << PSC_SA_CNT_LMT_OFFSET);
+    }
+    else
+    {
+        u32dat |= BITS_RANGE(PSC_SA_CNT_EN_OFFSET, PSC_SA_CNT_EN_LENGTH);
+        u32dat &= ~PSC_SA_CNT_LMT_MASK;
+        value = (port_config.sa_lmt_cnt & PSC_SA_CNT_LMT_REALMASK);
+        u32dat |= (((value > PSC_SA_CNT_LMT_MAX) ? PSC_SA_CNT_LMT_MAX : value) << PSC_SA_CNT_LMT_OFFSET);
+    }
+
+    aml_writeReg(unit, PSC(port), u32dat);
+
+    return rc;
+}
+
+/* FUNCTION NAME: air_sec_getPortSecPortCfg
+ * PURPOSE:
+ *      Get port security configurations for specific port.
+ *
+ * INPUT:
+ *      unit            --  Device ID
+ *      port            --  Port ID
+ *
+ * OUTPUT:
+ *      ptr_port_config --  Structure of port configuration.
+ *
+ * RETURN:
+ *      AIR_E_OK
+ *      AIR_E_BAD_PARAMETER
+ *
+ * NOTES:
+ *      None
+ */
+ AIR_ERROR_NO_T
+air_sec_getPortSecPortCfg(
+    const UI32_T unit,
+    const UI32_T port,
+    AIR_SEC_PORTSEC_PORT_CONFIG_T *ptr_port_config)
+{
+    AIR_ERROR_NO_T rc = AIR_E_OK;
+    UI32_T u32dat = 0;
+
+    AIR_PARAM_CHK((port >= AIR_MAX_NUM_OF_PORTS), AIR_E_BAD_PARAMETER);
+    AIR_CHECK_PTR(ptr_port_config);
+
+    aml_readReg(unit, PSC(port), &u32dat);
+
+    ptr_port_config ->sa_lrn_en = ((~BITS_OFF_R(u32dat, PSC_DIS_LRN_OFFSET, PSC_DIS_LRN_LENGTH)) & BIT(0));
+    ptr_port_config ->sa_lmt_en = BITS_OFF_R(u32dat, PSC_SA_CNT_EN_OFFSET, PSC_SA_CNT_EN_LENGTH);
+    ptr_port_config ->sa_lmt_cnt = (u32dat >> PSC_SA_CNT_LMT_OFFSET) & PSC_SA_CNT_LMT_REALMASK;
+
+    return rc;
+}
diff --git a/recipes-devtools/switch/files/src/an8855_sdk/api/src/air_sptag.c b/recipes-devtools/switch/files/src/an8855_sdk/api/src/air_sptag.c
new file mode 100644
index 0000000..1f6e4ce
--- /dev/null
+++ b/recipes-devtools/switch/files/src/an8855_sdk/api/src/air_sptag.c
@@ -0,0 +1,342 @@
+/* FILE NAME: air_sptag.c
+ * PURPOSE:
+ *      Define the Special Tag function in AIR SDK.
+ * NOTES:
+ *      None
+ */
+
+/* INCLUDE FILE DECLARATIONS
+*/
+#include "air.h"
+
+/* NAMING CONSTANT DECLARATIONS
+*/
+
+/* MACRO FUNCTION DECLARATIONS
+*/
+
+/* DATA TYPE DECLARATIONS
+*/
+
+/* GLOBAL VARIABLE DECLARATIONS
+*/
+
+/* LOCAL SUBPROGRAM DECLARATIONS
+*/
+
+/* STATIC VARIABLE DECLARATIONS
+*/
+
+/* LOCAL SUBPROGRAM BODIES
+*/
+
+/* EXPORTED SUBPROGRAM BODIES
+*/
+/* FUNCTION NAME: air_sptag_setState
+ * PURPOSE:
+ *      Set special tag enable/disable for port
+ *
+ * INPUT:
+ *      unit            --  Device ID
+ *      port            --  Special tag Port
+ *      sp_en           --  special tag Enable or Disable
+ *
+ * OUTPUT:
+ *      None
+ *
+ * RETURN:
+ *      AIR_E_OK
+ *      AIR_E_BAD_PARAMETER
+ *
+ * NOTES:
+ *      None
+ */
+AIR_ERROR_NO_T
+air_sptag_setState(
+    const UI32_T unit,
+    const UI32_T port,
+    const BOOL_T sp_en)
+{
+    UI32_T udat32 = 0;
+
+    /* Mistake proofing */
+    AIR_PARAM_CHK(port > AIR_MAX_NUM_OF_PORTS, AIR_E_BAD_PARAMETER);
+    AIR_PARAM_CHK(((TRUE != sp_en) && (FALSE != sp_en)), AIR_E_BAD_PARAMETER);
+
+    /* Read PVC */
+    aml_readReg(unit, PVC(port), &udat32);
+    AIR_PRINT("PVC REG:%x. val:%x\n", PVC(port),udat32);
+
+    /* Set special tag enable or disable */
+    udat32 &= ~BITS_RANGE(PVC_SPTAG_EN_OFFT, PVC_SPTAG_EN_LENG);
+    udat32 |= (sp_en << PVC_SPTAG_EN_OFFT);
+
+    /* Write PVC */
+    aml_writeReg(unit, PVC(port), udat32);
+    AIR_PRINT("PVC REG:%x. val:%x\n", PVC(port),udat32);
+
+    return AIR_E_OK;
+}
+
+/* FUNCTION NAME: air_switch_getCpuPortEn
+ * PURPOSE:
+ *      Get CPU port member
+ *
+ * INPUT:
+ *      unit            --  Device ID
+ *      port            --  Special tag Port
+ *
+ * OUTPUT:
+ *      sp_en           --  special tag enable or disable
+ *
+ * RETURN:
+ *      AIR_E_OK
+ *      AIR_E_BAD_PARAMETER
+ *
+ * NOTES:
+ *      None
+ */
+AIR_ERROR_NO_T
+air_sptag_getState(
+    const UI32_T unit,
+    const UI32_T port,
+    BOOL_T *sp_en)
+{
+    UI32_T udat32 = 0;
+
+    /* Mistake proofing */
+    AIR_CHECK_PTR(sp_en);
+    AIR_PARAM_CHK(port > AIR_MAX_NUM_OF_PORTS, AIR_E_BAD_PARAMETER);
+
+    /* Read PVC */
+    aml_readReg(unit, PVC(port), &udat32);
+
+    /* Get special tag state */
+    (*sp_en) = BITS_OFF_R(udat32, PVC_SPTAG_EN_OFFT, PVC_SPTAG_EN_LENG);
+
+    return AIR_E_OK;
+}
+
+
+/* FUNCTION NAME: air_sptag_setMode
+ * PURPOSE:
+ *      Set special tag enable/disable for port
+ *
+ * INPUT:
+ *      unit            --  Device ID
+ *      port            --  Special tag Port
+ *      mode            --  insert mode or replace mode
+ *
+ * OUTPUT:
+ *      None
+ *
+ * RETURN:
+ *      AIR_E_OK
+ *      AIR_E_BAD_PARAMETER
+ *
+ * NOTES:
+ *      None
+ */
+AIR_ERROR_NO_T
+air_sptag_setMode(
+    const UI32_T unit,
+    const UI32_T port,
+    const BOOL_T mode)
+{
+    UI32_T udat32 = 0;
+
+    /* Mistake proofing */
+    AIR_PARAM_CHK(port > AIR_MAX_NUM_OF_PORTS, AIR_E_BAD_PARAMETER);
+    AIR_PARAM_CHK(((TRUE != mode) && (FALSE != mode)), AIR_E_BAD_PARAMETER);
+
+    /* Read PVC */
+    aml_readReg(unit, PVC(port), &udat32);
+    AIR_PRINT("PVC REG:%x. val:%x\n", PVC(port),udat32);
+
+    /* Set special tag enable or disable */
+    udat32 &= ~BITS_RANGE(PVC_SPTAG_MODE_OFFT, PVC_SPTAG_MODE_LENG);
+    udat32 |= (mode << PVC_SPTAG_MODE_OFFT);
+
+    /* Write PVC */
+    aml_writeReg(unit, PVC(port), udat32);
+    AIR_PRINT("PVC REG:%x. val:%x\n", PVC(port),udat32);
+
+    return AIR_E_OK;
+}
+
+/* FUNCTION NAME: air_sptag_getMode
+ * PURPOSE:
+ *      Get CPU port member
+ *
+ * INPUT:
+ *      unit            --  Device ID
+ *      port            --  Special tag Port
+ *
+ * OUTPUT:
+ *      mode            --  insert or replace mode
+ *
+ * RETURN:
+ *      AIR_E_OK
+ *      AIR_E_BAD_PARAMETER
+ *
+ * NOTES:
+ *      None
+ */
+AIR_ERROR_NO_T
+air_sptag_getMode(
+    const UI32_T unit,
+    const UI32_T port,
+    BOOL_T *mode)
+{
+    UI32_T udat32 = 0;
+
+    /* Mistake proofing */
+    AIR_CHECK_PTR(mode);
+    AIR_PARAM_CHK(port > AIR_MAX_NUM_OF_PORTS, AIR_E_BAD_PARAMETER);
+
+    /* Read PVC */
+    aml_readReg(unit, PVC(port), &udat32);
+
+    /* Get special tag mode */
+    (*mode) = BITS_OFF_R(udat32, PVC_SPTAG_MODE_OFFT, PVC_SPTAG_MODE_LENG);
+
+    return AIR_E_OK;
+}
+
+/* FUNCTION NAME: air_sptag_encodeTx
+ * PURPOSE:
+ *      Encode tx special tag into buffer.
+ * INPUT:
+ *      unit            --  Device ID
+ *      ptr_sptag_tx    --  Special tag parameters
+ *      ptr_buf         --  Buffer address
+ *      ptr_len         --  Buffer length
+ * OUTPUT:
+ *      ptr_len         --  Written buffer length
+ *
+ * RETURN:
+ *      AIR_E_OK
+ *      AIR_E_BAD_PARAMETER
+ *
+ * NOTES:
+ *      None
+ */
+AIR_ERROR_NO_T
+air_sptag_encodeTx(
+    const UI32_T unit,
+    const AIR_STAG_MODE_T mode,
+    AIR_STAG_TX_PARA_T *ptr_stag_tx,
+    UI8_T *ptr_buf,
+    UI32_T *ptr_len)
+{
+    UI32_T port = 0, byte_off = 0, bit_off = 0;
+    BOOL_T found = FALSE;
+    UI16_T mac_pbmp;
+
+    AIR_PARAM_CHK(((ptr_stag_tx->opc <  AIR_STAG_OPC_PORTMAP) ||(ptr_stag_tx->opc > AIR_STAG_OPC_LOOKUP)),AIR_E_BAD_PARAMETER);
+    AIR_PARAM_CHK(((ptr_stag_tx->vpm <  AIR_STAG_VPM_UNTAG) ||(ptr_stag_tx->opc > AIR_STAG_VPM_TPID_PRE_DEFINED)),AIR_E_BAD_PARAMETER);
+
+    mac_pbmp = ptr_stag_tx->pbm;
+
+    /* insert mode only support port map */
+    if ((AIR_STAG_MODE_INSERT == mode)
+        && ((ptr_stag_tx->opc != AIR_STAG_OPC_PORTMAP) && (ptr_stag_tx->opc != AIR_STAG_OPC_LOOKUP)))
+    {
+        return AIR_E_BAD_PARAMETER;
+    }
+
+    /* clear output buffer */
+    memset(ptr_buf, 0, AIR_STAG_BUF_LEN);
+    AIR_PRINT("air_sptag_encode:mac_pbmp=%x\n", mac_pbmp);
+
+    ptr_buf[0] |= BITS_OFF_L(ptr_stag_tx->opc, AIR_STAG_TX_OPC_BIT_OFFSET, AIR_STAG_TX_OPC_BIT_WIDTH);
+    if (AIR_STAG_MODE_INSERT == mode)
+    {   /*insert only support bitmap , opc always 000*/
+        AIR_PORT_FOREACH(mac_pbmp, port)
+        {
+            ptr_buf[1] |= (0x1 << port);
+            AIR_PRINT("air_sptag_encode:port=%d,value = %x\n", port,(0x1 << port));
+        }
+    }
+    else
+    {
+        ptr_buf[0] |= BITS_OFF_L(ptr_stag_tx->vpm, AIR_STAG_TX_VPM_BIT_OFFSET, AIR_STAG_TX_VPM_BIT_WIDTH);
+        ptr_buf[0] |= BITS_OFF_L(ptr_stag_tx->opc, AIR_STAG_TX_OPC_BIT_OFFSET, AIR_STAG_TX_OPC_BIT_WIDTH);
+        if (AIR_STAG_OPC_PORTMAP == ptr_stag_tx->opc)
+        {
+            AIR_PORT_FOREACH(mac_pbmp, port)
+            {
+                ptr_buf[1] |= 0x1 << port;
+
+            }
+        }
+        else if (AIR_STAG_OPC_PORTID == ptr_stag_tx->opc)
+        {
+            AIR_PORT_FOREACH(mac_pbmp, port)
+            {
+                if (TRUE ==found)
+                {
+                    return AIR_E_BAD_PARAMETER;
+                }
+                ptr_buf[1] |= port;
+                found = TRUE;
+            }
+        }
+        AIR_PRINT("air_sptag_encode:pri = %d,cfi = %d,vid = %d\n", ptr_stag_tx->pri,ptr_stag_tx->cfi,ptr_stag_tx->vid);
+
+        ptr_buf[2] |= BITS_OFF_L(ptr_stag_tx->pri, AIR_STAG_TX_PCP_BIT_OFFSET, AIR_STAG_TX_PCP_BIT_WIDTH);
+        ptr_buf[2] |= BITS_OFF_L(ptr_stag_tx->cfi, AIR_STAG_TX_DEI_BIT_OFFSET, AIR_STAG_TX_DEI_BIT_WIDTH);
+        ptr_buf[2] |= BITS_OFF_L((ptr_stag_tx->vid >> AIR_STAG_ALIGN_BIT_WIDTH), 0,
+            (AIR_STAG_ALIGN_BIT_WIDTH - AIR_STAG_TX_PCP_BIT_WIDTH - AIR_STAG_TX_DEI_BIT_WIDTH));
+        AIR_PRINT("air_sptag_encode:pbuf[2] %02x\n", ptr_buf[2]);
+        ptr_buf[3] |= BITS_OFF_L((ptr_stag_tx->vid & 0xFF), 0, AIR_STAG_ALIGN_BIT_WIDTH);
+        AIR_PRINT("air_sptag_encode:pbuf[3] %02x\n", ptr_buf[3]);
+    }
+
+    *ptr_len = AIR_STAG_BUF_LEN;
+
+    return AIR_E_OK;
+}
+
+/* FUNCTION NAME: air_sptag_decodeRx
+ * PURPOSE:
+ *      Decode rx special tag from buffer.
+ * INPUT:
+ *      unit            --  Device ID
+ *      ptr_buf         --  Buffer address
+ *      len             --  Buffer length
+ * OUTPUT:
+ *      ptr_sptag_rx    --  Special tag parameters
+ *
+ * RETURN:
+ *      AIR_E_OK
+ *      AIR_E_BAD_PARAMETER
+ *
+ * NOTES:
+ *      None
+ */
+AIR_ERROR_NO_T
+air_sptag_decodeRx(
+    const UI32_T unit,
+    const UI8_T *ptr_buf,
+    const UI32_T len,
+    AIR_SPTAG_RX_PARA_T *ptr_sptag_rx)
+{
+    AIR_CHECK_PTR(ptr_buf);
+    AIR_CHECK_PTR(ptr_sptag_rx);
+    AIR_PARAM_CHK((len != AIR_STAG_BUF_LEN), AIR_E_BAD_PARAMETER);
+
+    ptr_sptag_rx->vpm  = BITS_OFF_R(ptr_buf[0], 0, 2);
+    ptr_sptag_rx->rsn  = BITS_OFF_R(ptr_buf[0], 2, 3);
+    ptr_sptag_rx->spn  = BITS_OFF_R(ptr_buf[1], 0, 5);
+    ptr_sptag_rx->pri  = BITS_OFF_R(ptr_buf[2], 5, 3);
+    ptr_sptag_rx->cfi  = BITS_OFF_R(ptr_buf[2], 4, 1);
+    ptr_sptag_rx->vid  = BITS_OFF_R(ptr_buf[2], 0, 4);
+    ptr_sptag_rx->vid  = (ptr_sptag_rx->vid << 8) | ptr_buf[3];
+
+    AIR_PARAM_CHK((ptr_sptag_rx->vpm >= AIR_STAG_REASON_CODE_LAST), AIR_E_BAD_PARAMETER);
+    AIR_PARAM_CHK((ptr_sptag_rx->rsn >= AIR_STAG_VPM_LAST), AIR_E_BAD_PARAMETER);
+
+    return AIR_E_OK;
+}
+
diff --git a/recipes-devtools/switch/files/src/an8855_sdk/api/src/air_stp.c b/recipes-devtools/switch/files/src/an8855_sdk/api/src/air_stp.c
new file mode 100644
index 0000000..6f69ed5
--- /dev/null
+++ b/recipes-devtools/switch/files/src/an8855_sdk/api/src/air_stp.c
@@ -0,0 +1,133 @@
+/* FILE NAME: air_stp.c
+ * PURPOSE:
+ *      Define the STP function in AIR SDK.
+ *
+ * NOTES:
+ *      None
+ */
+
+/* INCLUDE FILE DECLARATIONS
+*/
+#include "air.h"
+
+/* NAMING CONSTANT DECLARATIONS
+*/
+
+/* MACRO FUNCTION DECLARATIONS
+*/
+
+/* DATA TYPE DECLARATIONS
+*/
+
+/* GLOBAL VARIABLE DECLARATIONS
+*/
+
+/* LOCAL SUBPROGRAM DECLARATIONS
+*/
+
+/* STATIC VARIABLE DECLARATIONS
+*/
+
+/* LOCAL SUBPROGRAM BODIES
+*/
+
+/* EXPORTED SUBPROGRAM BODIES
+*/
+/* FUNCTION NAME: air_stp_setPortstate
+ * PURPOSE:
+ *      Set the STP port state for a specifiec port.
+ *
+ * INPUT:
+ *      unit            --  Device ID
+ *      port            --  Index of port number
+ *      fid             --  Filter ID for MSTP
+ *      state           --  AIR_STP_STATE_DISABLE
+ *                          AIR_STP_STATE_LISTEN
+ *                          AIR_STP_STATE_LEARN
+ *                          AIR_STP_STATE_FORWARD
+ * OUTPUT:
+ *        None
+ *
+ * RETURN:
+ *        AIR_E_OK
+ *        AIR_E_BAD_PARAMETER
+ *
+ * NOTES:
+ *      None
+ */
+AIR_ERROR_NO_T
+air_stp_setPortstate(
+    const UI32_T unit,
+    const UI8_T port,
+    const UI8_T fid,
+    const AIR_STP_STATE_T state)
+{
+    UI32_T u32dat = 0;
+
+    /* Mistake proofing for port checking */
+    AIR_PARAM_CHK((port >= AIR_MAX_NUM_OF_PORTS), AIR_E_BAD_PARAMETER);
+
+    /* Mistake proofing for fid checking */
+    AIR_PARAM_CHK((fid >= AIR_STP_FID_NUMBER), AIR_E_BAD_PARAMETER);
+
+    /* Mistake proofing for state checking */
+    AIR_PARAM_CHK((state >= AIR_STP_STATE_LAST), AIR_E_BAD_PARAMETER);
+
+    /* Read data from register */
+    aml_readReg(unit, SSC(port), &u32dat);
+
+    /* Write data to register */
+    u32dat &= ~BITS(fid*2, (fid*2)+1);
+    u32dat |= BITS_OFF_L(state, (fid*2), 2);
+    aml_writeReg(unit, SSC(port), u32dat);
+
+    return AIR_E_OK;
+}
+
+/* FUNCTION NAME: air_stp_getPortstate
+ * PURPOSE:
+ *      Get the STP port state for a specifiec port.
+ *
+ * INPUT:
+ *      unit            --  Device ID
+ *      port            --  Index of port number
+ *      fid             --  Filter ID for MSTP
+ *
+ * OUTPUT:
+ *      ptr_state       --  AIR_STP_STATE_DISABLE
+ *                          AIR_STP_STATE_LISTEN
+ *                          AIR_STP_STATE_LEARN
+ *                          AIR_STP_STATE_FORWARD
+ * RETURN:
+ *        AIR_E_OK
+ *        AIR_E_BAD_PARAMETER
+ *
+ * NOTES:
+ *      None
+ */
+
+AIR_ERROR_NO_T
+air_stp_getPortstate(
+    const UI32_T unit,
+    const UI32_T port,
+    const UI32_T fid,
+    AIR_STP_STATE_T *ptr_state)
+{
+    UI32_T u32dat = 0;
+
+    /* Mistake proofing for port checking */
+    AIR_PARAM_CHK((port >= AIR_MAX_NUM_OF_PORTS), AIR_E_BAD_PARAMETER);
+
+    /* Mistake proofing for fid checking */
+    AIR_PARAM_CHK((fid >= AIR_STP_FID_NUMBER), AIR_E_BAD_PARAMETER);
+
+    /* Mistake proofing for state checking */
+    AIR_CHECK_PTR(ptr_state);
+
+    /* Read data from register */
+    aml_readReg(unit, SSC(port), &u32dat);
+    (*ptr_state) = BITS_OFF_R(u32dat, fid*2, 2);
+
+    return AIR_E_OK;
+}
+
diff --git a/recipes-devtools/switch/files/src/an8855_sdk/api/src/air_switch.c b/recipes-devtools/switch/files/src/an8855_sdk/api/src/air_switch.c
new file mode 100644
index 0000000..91f689e
--- /dev/null
+++ b/recipes-devtools/switch/files/src/an8855_sdk/api/src/air_switch.c
@@ -0,0 +1,369 @@
+/* FILE NAME: air_switch.c
+ * PURPOSE:
+ *      Define the switch function in AIR SDK.
+ *
+ * NOTES:
+ *      None
+ */
+
+/* INCLUDE FILE DECLARATIONS
+*/
+#include "air.h"
+
+/* NAMING CONSTANT DECLARATIONS
+*/
+#define AIR_SYS_RST_WAIT_TIME       (100000)
+
+/* MACRO FUNCTION DECLARATIONS
+*/
+
+/* DATA TYPE DECLARATIONS
+*/
+
+/* GLOBAL VARIABLE DECLARATIONS
+*/
+
+/* LOCAL SUBPROGRAM DECLARATIONS
+*/
+
+/* STATIC VARIABLE DECLARATIONS
+*/
+
+/* LOCAL SUBPROGRAM BODIES
+*/
+
+/* EXPORTED SUBPROGRAM BODIES
+*/
+
+
+/* FUNCTION NAME: air_switch_setCpuPort
+ * PURPOSE:
+ *      Set CPU port member
+ *
+ * INPUT:
+ *      unit            --  Device ID
+ *      port            --  CPU port index
+ *
+ * OUTPUT:
+ *      None
+ *
+ * RETURN:
+ *      AIR_E_OK
+ *      AIR_E_BAD_PARAMETER
+ *
+ * NOTES:
+ *      None
+ */
+AIR_ERROR_NO_T
+air_switch_setCpuPort(
+    const UI32_T unit,
+    const UI32_T port)
+{
+    UI32_T regMFC = 0;
+
+    /* Mistake proofing */
+    AIR_PARAM_CHK(port > AIR_MAX_NUM_OF_PORTS, AIR_E_BAD_PARAMETER);
+
+    /* Read CFC */
+    aml_readReg(unit, MFC, &regMFC);
+    AIR_PRINT("PTC REG:%x. val:%x\n", MFC,regMFC);
+
+    /* Set CPU portmap */
+    regMFC &= ~BITS_RANGE(MFC_CPU_PORT_OFFSET, MFC_CPU_PORT_LENGTH);
+    regMFC |= (port << MFC_CPU_PORT_OFFSET);
+
+    /* Write CFC */
+    aml_writeReg(unit, MFC, regMFC);
+    AIR_PRINT("PTC REG:%x. val:%x\n", MFC,regMFC);
+
+    return AIR_E_OK;
+}
+
+/* FUNCTION NAME: air_switch_getCpuPort
+ * PURPOSE:
+ *      Get CPU port member
+ *
+ * INPUT:
+ *      unit            --  Device ID
+ *
+ * OUTPUT:
+ *      ptr_port        --  CPU port index
+ *
+ * RETURN:
+ *      AIR_E_OK
+ *      AIR_E_BAD_PARAMETER
+ *
+ * NOTES:
+ *      None
+ */
+AIR_ERROR_NO_T
+air_switch_getCpuPort(
+    const UI32_T unit,
+    UI32_T *ptr_port)
+{
+    UI32_T regMFC = 0;
+
+    /* Mistake proofing */
+    AIR_CHECK_PTR(ptr_port);
+
+    /* Read CFC */
+    aml_readReg(unit, MFC, &regMFC);
+
+    /* Get CPU portmap */
+    (*ptr_port) = BITS_OFF_R(regMFC, MFC_CPU_PORT_OFFSET, MFC_CPU_PORT_LENGTH);
+
+    return AIR_E_OK;
+}
+
+
+/* FUNCTION NAME: air_switch_setCpuPortEN
+ * PURPOSE:
+ *      Set CPU port Enable
+ *
+ * INPUT:
+ *      unit            --  Device ID
+ *      cpu_en          --  CPU Port Enable
+ *
+ * OUTPUT:
+ *      None
+ *
+ * RETURN:
+ *      AIR_E_OK
+ *      AIR_E_BAD_PARAMETER
+ *
+ * NOTES:
+ *      None
+ */
+AIR_ERROR_NO_T
+air_switch_setCpuPortEn(
+    const UI32_T unit,
+    const BOOL_T cpu_en)
+{
+    UI32_T regMFC = 0;
+
+    /* Mistake proofing */
+    AIR_PARAM_CHK(((TRUE != cpu_en) && (FALSE != cpu_en)), AIR_E_BAD_PARAMETER);
+
+    /* Read CFC */
+    aml_readReg(unit, MFC, &regMFC);
+
+    /* Set CPU portmap */
+    regMFC &= ~BITS_RANGE(MFC_CPU_EN_OFFSET, MFC_CPU_EN_LENGTH);
+    regMFC |= cpu_en << MFC_CPU_EN_OFFSET ;
+
+    /* Write CFC */
+    aml_writeReg(unit, MFC, regMFC);
+
+    return AIR_E_OK;
+}
+
+/* FUNCTION NAME: air_switch_getCpuPortEn
+ * PURPOSE:
+ *      Get CPU port member
+ *
+ * INPUT:
+ *      unit            --  Device ID
+ *
+ * OUTPUT:
+ *      cpu_en          --  CPU Port enable
+ *
+ * RETURN:
+ *      AIR_E_OK
+ *      AIR_E_BAD_PARAMETER
+ *
+ * NOTES:
+ *      None
+ */
+AIR_ERROR_NO_T
+air_switch_getCpuPortEn(
+    const UI32_T unit,
+    BOOL_T *cpu_en)
+{
+    UI32_T regMFC = 0;
+
+    /* Mistake proofing */
+    AIR_CHECK_PTR(cpu_en);
+
+    /* Read CFC */
+    aml_readReg(unit, MFC, &regMFC);
+
+    /* Get CPU portmap */
+    (*cpu_en) = BITS_OFF_R(regMFC, MFC_CPU_EN_OFFSET, MFC_CPU_EN_LENGTH);
+
+    return AIR_E_OK;
+}
+
+/* FUNCTION NAME: air_switch_setSysIntrEn
+ * PURPOSE:
+ *      Set system interrupt enable
+ *
+ * INPUT:
+ *      unit            --  Device ID
+ *      intr            --  system interrupt type
+ *      enable          --  system interrupt enable/disable
+ *
+ * OUTPUT:
+ *      None
+ *
+ * RETURN:
+ *      AIR_E_OK
+ *      AIR_E_BAD_PARAMETER
+ *
+ * NOTES:
+ *      None
+ */
+AIR_ERROR_NO_T
+air_switch_setSysIntrEn(
+    const UI32_T unit,
+    const AIR_SYS_INTR_TYPE_T intr,
+    const BOOL_T enable)
+{
+    UI32_T val = 0;
+
+    AIR_PARAM_CHK((intr >= AIR_SYS_INTR_TYPE_LAST), AIR_E_BAD_PARAMETER);
+    AIR_PARAM_CHK(((intr > AIR_SYS_INTR_TYPE_PHY7_LC) && (intr < AIR_SYS_INTR_TYPE_MAC_PC)), AIR_E_BAD_PARAMETER);
+    AIR_PARAM_CHK(((TRUE != enable) && (FALSE != enable)), AIR_E_BAD_PARAMETER);
+
+    aml_readReg(unit, SYS_INT_EN, &val);
+    val &= ~BIT(intr);
+    val |= (TRUE == enable) ? BIT(intr) : 0;
+    aml_writeReg(unit, SYS_INT_EN, val);
+
+    return AIR_E_OK;
+}
+
+/* FUNCTION NAME: air_switch_getSysIntrEn
+ * PURPOSE:
+ *      Get system interrupt enable
+ *
+ * INPUT:
+ *      unit            --  Device ID
+ *      intr            --  system interrupt type
+ *
+ * OUTPUT:
+ *      ptr_enable      --  system interrupt enable/disable
+ *
+ * RETURN:
+ *      AIR_E_OK
+ *      AIR_E_BAD_PARAMETER
+ *
+ * NOTES:
+ *      None
+ */
+AIR_ERROR_NO_T
+air_switch_getSysIntrEn(
+    const UI32_T unit,
+    const AIR_SYS_INTR_TYPE_T intr,
+    BOOL_T *ptr_enable)
+{
+    UI32_T val = 0;
+
+    AIR_PARAM_CHK((intr >= AIR_SYS_INTR_TYPE_LAST), AIR_E_BAD_PARAMETER);
+    AIR_PARAM_CHK(((intr > AIR_SYS_INTR_TYPE_PHY7_LC) && (intr < AIR_SYS_INTR_TYPE_MAC_PC)), AIR_E_BAD_PARAMETER);
+    AIR_CHECK_PTR(ptr_enable);
+
+    aml_readReg(unit, SYS_INT_EN, &val);
+    *ptr_enable = (val & BIT(intr)) ? TRUE : FALSE;
+
+    return AIR_E_OK;
+}
+
+/* FUNCTION NAME: air_switch_setSysIntrStatus
+ * PURPOSE:
+ *      Set system interrupt status
+ *
+ * INPUT:
+ *      unit            --  Device ID
+ *      intr            --  system interrupt type
+ *      enable          --  write TRUE to clear interrupt status
+ *
+ * OUTPUT:
+ *      None
+ *
+ * RETURN:
+ *      AIR_E_OK
+ *      AIR_E_BAD_PARAMETER
+ *
+ * NOTES:
+ *      None
+ */
+AIR_ERROR_NO_T
+air_switch_setSysIntrStatus(
+    const UI32_T unit,
+    const AIR_SYS_INTR_TYPE_T intr,
+    const BOOL_T enable)
+{
+    UI32_T val = 0;
+
+    AIR_PARAM_CHK((intr >= AIR_SYS_INTR_TYPE_LAST), AIR_E_BAD_PARAMETER);
+    AIR_PARAM_CHK(((intr > AIR_SYS_INTR_TYPE_PHY6_LC) && (intr < AIR_SYS_INTR_TYPE_MAC_PC)), AIR_E_BAD_PARAMETER);
+    AIR_PARAM_CHK((TRUE != enable), AIR_E_BAD_PARAMETER);
+
+    aml_writeReg(unit, SYS_INT_STS, BIT(intr));
+
+    return AIR_E_OK;
+}
+
+/* FUNCTION NAME: air_switch_getSysIntrStatus
+ * PURPOSE:
+ *      Get system interrupt status
+ *
+ * INPUT:
+ *      unit            --  Device ID
+ *      intr            --  system interrupt type
+ *
+ * OUTPUT:
+ *      ptr_enable      --  system interrupt status
+ *
+ * RETURN:
+ *      AIR_E_OK
+ *      AIR_E_BAD_PARAMETER
+ *
+ * NOTES:
+ *      None
+ */
+AIR_ERROR_NO_T
+air_switch_getSysIntrStatus(
+    const UI32_T unit,
+    const AIR_SYS_INTR_TYPE_T intr,
+    BOOL_T *ptr_enable)
+{
+    UI32_T val = 0;
+
+    AIR_PARAM_CHK((intr >= AIR_SYS_INTR_TYPE_LAST), AIR_E_BAD_PARAMETER);
+    AIR_PARAM_CHK(((intr > AIR_SYS_INTR_TYPE_PHY6_LC) && (intr < AIR_SYS_INTR_TYPE_MAC_PC)), AIR_E_BAD_PARAMETER);
+    AIR_CHECK_PTR(ptr_enable);
+
+    aml_readReg(unit, SYS_INT_STS, &val);
+    *ptr_enable = (val & BIT(intr)) ? TRUE : FALSE;
+
+    return AIR_E_OK;
+}
+
+/* FUNCTION NAME: air_switch_reset
+ * PURPOSE:
+ *      Reset whole system
+ *
+ * INPUT:
+ *      None
+ *
+ * OUTPUT:
+ *      None
+ *
+ * RETURN:
+ *      AIR_E_OK
+ *
+ * NOTES:
+ *      None
+ */
+AIR_ERROR_NO_T
+air_switch_reset(
+    const UI32_T unit)
+{
+    UI32_T val = 0;
+
+    aml_writeReg(unit, RST_CTRL1, BIT(SYS_SW_RST_OFFT));
+    AIR_UDELAY(AIR_SYS_RST_WAIT_TIME);
+
+    return AIR_E_OK;
+}
diff --git a/recipes-devtools/switch/files/src/an8855_sdk/api/src/air_vlan.c b/recipes-devtools/switch/files/src/an8855_sdk/api/src/air_vlan.c
new file mode 100644
index 0000000..6629165
--- /dev/null
+++ b/recipes-devtools/switch/files/src/an8855_sdk/api/src/air_vlan.c
@@ -0,0 +1,1448 @@
+/* FILE NAME:   air_vlan.c

+ * PURPOSE:

+ *      Define the VLAN function in AIR SDK.

+ * NOTES:

+ */

+

+/* INCLUDE FILE DECLARATIONS

+ */

+#include "air.h"

+

+/* NAMING CONSTANT DECLARATIONS

+ */

+

+/* MACRO FUNCTION DECLARATIONS

+ */

+

+/* DATA TYPE DECLARATIONS

+ */

+

+/* GLOBAL VARIABLE DECLARATIONS

+ */

+

+/* LOCAL SUBPROGRAM DECLARATIONS

+ */

+

+/* STATIC VARIABLE DECLARATIONS

+ */

+

+/* EXPORTED SUBPROGRAM BODIES

+ */

+

+/* LOCAL SUBPROGRAM BODIES

+*/

+void

+_air_vlan_readEntry(

+    const UI32_T unit,

+    const UI16_T vid,

+    AIR_VLAN_ENTRY_T* vlan_entry)

+{

+    UI32_T val = 0;

+    val = (0x80000000 + vid); //r_vid_cmd

+    aml_writeReg(unit, VTCR, val);

+

+    for (;;)

+    {

+        aml_readReg(unit, VTCR, &val);

+        if ((val & 0x80000000) == 0)

+            break;

+        AIR_UDELAY(10);

+    }

+

+    aml_readReg(unit, VLNRDATA0, &(vlan_entry->vlan_table.vlan_table0));

+    aml_readReg(unit, VLNRDATA1, &(vlan_entry->vlan_table.vlan_table1));

+}

+

+void

+_air_vlan_writeEntry(

+    const UI32_T unit,

+    const UI16_T vid,

+    AIR_VLAN_ENTRY_T* vlan_entry)

+{

+    UI32_T val = 0;

+

+    aml_writeReg(unit, VLNWDATA0, vlan_entry->vlan_table.vlan_table0);

+    aml_writeReg(unit, VLNWDATA1, vlan_entry->vlan_table.vlan_table1);

+    aml_writeReg(unit, VLNWDATA2, 0);

+    aml_writeReg(unit, VLNWDATA3, 0);

+    aml_writeReg(unit, VLNWDATA4, 0);

+

+    val = (0x80001000 + vid); //w_vid_cmd

+    aml_writeReg(unit, VTCR, val);

+

+    for (;;)

+    {

+        aml_readReg(unit, VTCR, &val);

+        if ((val & 0x80000000) == 0)

+            break;

+        AIR_UDELAY(10);

+    }

+}

+

+void

+_air_untagged_vlan_readEntry(

+    const UI32_T unit,

+    const UI16_T vid,

+    AIR_VLAN_ENTRY_ATTR_T* vlan_entry)

+{

+    UI32_T val = 0;

+    val = (0x80000000 + vid); //r_vid_cmd

+    aml_writeReg(unit, VTCR, val);

+

+    for (;;)

+    {

+        aml_readReg(unit, VTCR, &val);

+        if ((val & 0x80000000) == 0)

+            break;

+        AIR_UDELAY(10);

+    }

+

+    aml_readReg(unit, VLNRDATA0, &(vlan_entry->vlan_table.vlan_table0));

+    aml_readReg(unit, VLNRDATA1, &(vlan_entry->vlan_table.vlan_table1));

+    aml_readReg(unit, VLNRDATA2, &(vlan_entry->vlan_table.vlan_table2));

+    aml_readReg(unit, VLNRDATA3, &(vlan_entry->vlan_table.vlan_table3));

+    aml_readReg(unit, VLNRDATA4, &(vlan_entry->vlan_table.vlan_table4));

+}

+

+void

+_air_untagged_vlan_writeEntry(

+    const UI32_T unit,

+    const UI16_T vid,

+    AIR_VLAN_ENTRY_ATTR_T* vlan_entry)

+{

+    UI32_T val = 0;

+

+    aml_writeReg(unit, VLNWDATA0, vlan_entry->vlan_table.vlan_table0);

+    aml_writeReg(unit, VLNWDATA1, vlan_entry->vlan_table.vlan_table1);

+    aml_writeReg(unit, VLNWDATA2, vlan_entry->vlan_table.vlan_table2);

+    aml_writeReg(unit, VLNWDATA3, vlan_entry->vlan_table.vlan_table3);

+    aml_writeReg(unit, VLNWDATA4, vlan_entry->vlan_table.vlan_table4);

+

+    val = (0x80001000 + vid); //w_vid_cmd

+    aml_writeReg(unit, VTCR, val);

+

+    for (;;)

+    {

+        aml_readReg(unit, VTCR, &val);

+        if ((val & 0x80000000) == 0)

+            break;

+        AIR_UDELAY(10);

+    }

+}

+

+/* FUNCTION NAME:   air_vlan_create

+ * PURPOSE:

+ *      Create the vlan in the specified device.

+ * INPUT:

+ *      unit        -- unit id

+ *      vid         -- vlan id

+ *      p_attr      -- vlan attr

+ * OUTPUT:

+ *      None

+ * RETURN:

+ *      AIR_E_OK                -- Successfully read the data.

+ *      AIR_E_OTHERS            -- Vlan creation failed.

+ *      AIR_E_BAD_PARAMETER     -- Invalid parameter.

+ * NOTES:

+ *      none

+ */

+AIR_ERROR_NO_T

+air_vlan_create(

+    const UI32_T    unit,

+    const UI16_T    vid,

+    AIR_VLAN_ENTRY_ATTR_T *p_attr)

+{

+    AIR_VLAN_ENTRY_T vlan_entry = {0};

+

+    AIR_PARAM_CHK((vid > AIR_VLAN_ID_MAX), AIR_E_BAD_PARAMETER);

+

+    _air_vlan_readEntry(unit, vid, &vlan_entry);

+    if (vlan_entry.valid)

+        return AIR_E_ENTRY_EXISTS;

+

+    if (NULL != p_attr)

+    {

+        p_attr->valid = 1;

+        _air_untagged_vlan_writeEntry(unit, vid, p_attr);

+    }

+    else

+    {

+        memset(&vlan_entry, 0, sizeof(vlan_entry));

+        vlan_entry.valid = 1;

+        _air_untagged_vlan_writeEntry(unit, vid, &vlan_entry);

+    }

+

+    return AIR_E_OK;

+}

+

+/* FUNCTION NAME:   air_vlan_destroy

+ * PURPOSE:

+ *      Destroy the vlan in the specified device.

+ * INPUT:

+ *      unit        -- unit id

+ *      vid         -- vlan id

+ * OUTPUT:

+ *      None

+ * RETURN:

+ *      AIR_E_OK     -- Successfully read the data.

+ *      AIR_E_OTHERS -- Vlan destroy failed.

+ * NOTES:

+ *      none

+ */

+AIR_ERROR_NO_T

+air_vlan_destroy(

+    const UI32_T    unit,

+    const UI16_T    vid)

+{

+    AIR_VLAN_ENTRY_T vlan_entry = {0};

+

+    AIR_PARAM_CHK((vid > AIR_VLAN_ID_MAX), AIR_E_BAD_PARAMETER);

+

+    _air_vlan_writeEntry(unit, vid, &vlan_entry);

+

+    return AIR_E_OK;

+}

+

+/* FUNCTION NAME:   air_vlan_destroyAll

+ * PURPOSE:

+ *      Destroy the vlan in the specified device.

+ * INPUT:

+ *      unit        -- unit id

+ *      vid         -- vlan id

+ * OUTPUT:

+ *      None

+ * RETURN:

+ *      AIR_E_OK     -- Successfully read the data.

+ *      AIR_E_OTHERS -- Vlan destroy failed.

+ * NOTES:

+ *      none

+ */

+AIR_ERROR_NO_T

+air_vlan_destroyAll(

+    const UI32_T    unit,

+    const UI32_T    keep_and_restore_default_vlan)

+{

+    UI16_T vid = 0;

+

+    for (vid = AIR_VLAN_ID_MIN; vid <= AIR_VLAN_ID_MAX; vid++)

+    {

+        if (keep_and_restore_default_vlan)

+        {

+            air_vlan_reset(unit, vid);

+        }

+        else

+        {

+            air_vlan_destroy(unit, vid);

+        }

+    }

+

+    return AIR_E_OK;

+}

+

+/* FUNCTION NAME:   air_vlan_reset

+ * PURPOSE:

+ *      Destroy the vlan in the specified device.

+ * INPUT:

+ *      unit        -- unit id

+ *      vid         -- vlan id

+ * OUTPUT:

+ *      None

+ * RETURN:

+ *      AIR_E_OK     -- Successfully reset the data.

+ *      AIR_E_OTHERS -- Vlan reset failed.

+ * NOTES:

+ *      none

+ */

+AIR_ERROR_NO_T

+air_vlan_reset(

+    const UI32_T    unit,

+    const UI16_T    vid)

+{

+    AIR_VLAN_ENTRY_T vlan_entry = {0};

+

+    AIR_PARAM_CHK((vid > AIR_VLAN_ID_MAX), AIR_E_BAD_PARAMETER);

+

+    vlan_entry.vlan_entry_format.port_mem = AIR_ALL_PORT_BITMAP;

+    vlan_entry.valid = TRUE;

+

+    _air_vlan_writeEntry(unit, vid, &vlan_entry);

+

+    return AIR_E_OK;

+}

+

+/* FUNCTION NAME:   air_vlan_setFid

+ * PURPOSE:

+ *      Set the filter id of the vlan to the specified device.

+ * INPUT:

+ *      unit        -- unit id

+ *      vid         -- vlan id

+ *      fid         -- filter id

+ * OUTPUT:

+ *      None

+ * RETURN:

+ *      AIR_E_OK                -- Successfully read the data.

+ *      AIR_E_OTHERS            -- Operation failed.

+ *      AIR_E_BAD_PARAMETER     -- Invalid parameter.

+ * NOTES:

+ *      none

+ */

+AIR_ERROR_NO_T

+air_vlan_setFid(

+    const UI32_T    unit,

+    const UI16_T    vid,

+    const UI8_T     fid)

+{

+    AIR_VLAN_ENTRY_T vlan_entry = {0};

+

+    /* VID check */

+    AIR_PARAM_CHK((vid > AIR_VLAN_ID_MAX), AIR_E_BAD_PARAMETER);

+    AIR_PARAM_CHK((fid > AIR_FILTER_ID_MAX), AIR_E_BAD_PARAMETER);

+

+    _air_vlan_readEntry(unit, vid, &vlan_entry);

+    if (!vlan_entry.valid)

+        return AIR_E_ENTRY_NOT_FOUND;

+

+    vlan_entry.vlan_entry_format.fid = fid;

+    _air_vlan_writeEntry(unit, vid, &vlan_entry);

+

+    return AIR_E_OK;

+}

+

+/* FUNCTION NAME:   air_vlan_getFid

+ * PURPOSE:

+ *      Get the filter id of the vlan from the specified device.

+ * INPUT:

+ *      unit        -- unit id

+ *      vid         -- vlan id to be created

+ * OUTPUT:

+ *      ptr_fid     -- filter id

+ * RETURN:

+ *      AIR_E_OK                -- Successfully read the data.

+ *      AIR_E_OTHERS            -- Operation failed.

+ *      AIR_E_BAD_PARAMETER     -- Invalid parameter.

+ * NOTES:

+ *      none

+ */

+AIR_ERROR_NO_T

+air_vlan_getFid(

+    const UI32_T    unit,

+    const UI16_T    vid,

+    UI8_T           *ptr_fid)

+{

+    AIR_VLAN_ENTRY_T vlan_entry = {0};

+

+    AIR_PARAM_CHK((vid > AIR_VLAN_ID_MAX), AIR_E_BAD_PARAMETER);

+    AIR_CHECK_PTR(ptr_fid);

+

+    _air_vlan_readEntry(unit, vid, &vlan_entry);

+    if (!vlan_entry.valid)

+        return AIR_E_ENTRY_NOT_FOUND;

+

+    *ptr_fid = vlan_entry.vlan_entry_format.fid;

+

+    return AIR_E_OK;

+}

+

+/* FUNCTION NAME:   air_vlan_addMemberPort

+ * PURPOSE:

+ *      Add one vlan member to the specified device.

+ * INPUT:

+ *      unit        -- unit id

+ *      vid         -- vlan id

+ *      port        -- port id

+ * OUTPUT:

+ *      None

+ * RETURN:

+ *      AIR_E_OK                -- Successfully read the data.

+ *      AIR_E_OTHERS            -- Operation failed.

+ *      AIR_E_BAD_PARAMETER     -- Invalid parameter.

+ * NOTES:

+ *      none

+ */

+AIR_ERROR_NO_T

+air_vlan_addMemberPort(

+    const UI32_T    unit,

+    const UI16_T    vid,

+    const UI32_T    port)

+{

+    AIR_VLAN_ENTRY_T vlan_entry = {0};

+

+    AIR_PARAM_CHK((vid > AIR_VLAN_ID_MAX), AIR_E_BAD_PARAMETER);

+    AIR_PARAM_CHK((port >= AIR_MAX_NUM_OF_PORTS), AIR_E_BAD_PARAMETER);

+

+    _air_vlan_readEntry(unit, vid, &vlan_entry);

+    if (!vlan_entry.valid)

+        return AIR_E_ENTRY_NOT_FOUND;

+

+    vlan_entry.vlan_entry_format.port_mem |= 1 << port;

+    _air_vlan_writeEntry(unit, vid, &vlan_entry);

+

+    return AIR_E_OK;

+}

+

+/* FUNCTION NAME:   air_vlan_delMemberPort

+ * PURPOSE:

+ *      Delete one vlan member from the specified device.

+ * INPUT:

+ *      unit        -- unit id

+ *      vid         -- vlan id

+ *      port        -- port id

+ * OUTPUT:

+ *      None

+ * RETURN:

+ *      AIR_E_OK                -- Successfully read the data.

+ *      AIR_E_OTHERS            -- Operation failed.

+ *      AIR_E_BAD_PARAMETER     -- Invalid parameter.

+ * NOTES:

+ *      none

+ */

+AIR_ERROR_NO_T

+air_vlan_delMemberPort(

+    const UI32_T    unit,

+    const UI16_T    vid,

+    const UI32_T    port)

+{

+    AIR_VLAN_ENTRY_T vlan_entry = {0};

+

+    AIR_PARAM_CHK((vid > AIR_VLAN_ID_MAX), AIR_E_BAD_PARAMETER);

+    AIR_PARAM_CHK((port >= AIR_MAX_NUM_OF_PORTS), AIR_E_BAD_PARAMETER);

+

+    _air_vlan_readEntry(unit, vid, &vlan_entry);

+    if (!vlan_entry.valid)

+        return AIR_E_ENTRY_NOT_FOUND;

+

+    vlan_entry.vlan_entry_format.port_mem &= ~(1 << port);

+    _air_vlan_writeEntry(unit, vid, &vlan_entry);

+

+    return AIR_E_OK;

+}

+

+/* FUNCTION NAME:   air_vlan_setMemberPort

+ * PURPOSE:

+ *      Replace the vlan members in the specified device.

+ * INPUT:

+ *      unit        -- unit id

+ *      vid         -- vlan id

+ *      port_bitmap -- member port bitmap

+ * OUTPUT:

+ *      None

+ * RETURN:

+ *      AIR_E_OK                -- Successfully read the data.

+ *      AIR_E_OTHERS            -- Operation failed.

+ *      AIR_E_BAD_PARAMETER     -- Invalid parameter.

+ * NOTES:

+ *      none

+ */

+AIR_ERROR_NO_T

+air_vlan_setMemberPort(

+    const UI32_T    unit,

+    const UI16_T    vid,

+    const UI32_T    port_bitmap)

+{

+    AIR_VLAN_ENTRY_T vlan_entry = {0};

+

+    AIR_PARAM_CHK((vid > AIR_VLAN_ID_MAX), AIR_E_BAD_PARAMETER);

+    AIR_PARAM_CHK((port_bitmap & (~AIR_ALL_PORT_BITMAP)), AIR_E_BAD_PARAMETER);

+

+    _air_vlan_readEntry(unit, vid, &vlan_entry);

+    if (!vlan_entry.valid)

+        return AIR_E_ENTRY_NOT_FOUND;

+

+    vlan_entry.vlan_entry_format.port_mem = port_bitmap;

+    _air_vlan_writeEntry(unit, vid, &vlan_entry);

+

+    return AIR_E_OK;

+}

+

+/* FUNCTION NAME:   air_vlan_getMemberPort

+ * PURPOSE:

+ *      Get the vlan members from the specified device.

+ * INPUT:

+ *      unit        -- unit id

+ *      vid         -- vlan id

+ * OUTPUT:

+ *      port_bitmap -- member port bitmap

+ * RETURN:

+ *      AIR_E_OK                -- Successfully read the data.

+ *      AIR_E_OTHERS            -- Operation failed.

+ *      AIR_E_BAD_PARAMETER     -- Invalid parameter.

+ * NOTES:

+ *      none

+ */

+AIR_ERROR_NO_T

+air_vlan_getMemberPort(

+    const UI32_T    unit,

+    const UI16_T    vid,

+    UI32_T          *ptr_port_bitmap)

+{

+    AIR_VLAN_ENTRY_T vlan_entry = {0};

+

+    AIR_PARAM_CHK((vid > AIR_VLAN_ID_MAX), AIR_E_BAD_PARAMETER);

+    AIR_CHECK_PTR(ptr_port_bitmap);

+

+    _air_vlan_readEntry(unit, vid, &vlan_entry);

+    if (!vlan_entry.valid)

+        return AIR_E_ENTRY_NOT_FOUND;

+

+    *ptr_port_bitmap = vlan_entry.vlan_entry_format.port_mem;

+

+    return AIR_E_OK;

+}

+

+/* FUNCTION NAME:   air_vlan_setIVL

+ * PURPOSE:

+ *      Set L2 lookup mode IVL/SVL for L2 traffic.

+ * INPUT:

+ *      unit        -- unit id

+ *      vid         -- vlan id

+ *      enable      -- enable IVL

+ * OUTPUT:

+ *      None

+ * RETURN:

+ *      AIR_E_OK                -- Successfully read the data.

+ *      AIR_E_OTHERS            -- Operation failed.

+ *      AIR_E_BAD_PARAMETER     -- Invalid parameter.

+ * NOTES:

+ *      none

+ */

+AIR_ERROR_NO_T

+air_vlan_setIVL(

+    const UI32_T    unit,

+    const UI16_T    vid,

+    const BOOL_T    enable)

+{

+    AIR_VLAN_ENTRY_T vlan_entry = {0};

+

+    AIR_PARAM_CHK((vid > AIR_VLAN_ID_MAX), AIR_E_BAD_PARAMETER);

+

+    _air_vlan_readEntry(unit, vid, &vlan_entry);

+    if (!vlan_entry.valid)

+        return AIR_E_ENTRY_NOT_FOUND;

+

+    vlan_entry.vlan_entry_format.ivl = enable ? 1 : 0;

+    _air_vlan_writeEntry(unit, vid, &vlan_entry);

+

+    return AIR_E_OK;

+}

+

+/* FUNCTION NAME:   air_vlan_getIVL

+ * PURPOSE:

+ *      Get L2 lookup mode IVL/SVL for L2 traffic.

+ * INPUT:

+ *      unit        -- unit id

+ *      vid         -- vlan id

+ * OUTPUT:

+ *      ptr_enable  -- enable IVL

+ * RETURN:

+ *      AIR_E_OK                -- Successfully read the data.

+ *      AIR_E_OTHERS            -- Operation failed.

+ *      AIR_E_BAD_PARAMETER     -- Invalid parameter.

+ * NOTES:

+ *      none

+ */

+AIR_ERROR_NO_T

+air_vlan_getIVL(

+    const UI32_T    unit,

+    const UI16_T    vid,

+    BOOL_T          *ptr_enable)

+{

+    AIR_VLAN_ENTRY_T vlan_entry = {0};

+

+    AIR_PARAM_CHK((vid > AIR_VLAN_ID_MAX), AIR_E_BAD_PARAMETER);

+    AIR_CHECK_PTR(ptr_enable);

+

+    _air_vlan_readEntry(unit, vid, &vlan_entry);

+    if (!vlan_entry.valid)

+        return AIR_E_ENTRY_NOT_FOUND;

+

+    *ptr_enable = vlan_entry.vlan_entry_format.ivl;

+

+    return AIR_E_OK;

+}

+

+/* FUNCTION NAME:   air_vlan_setPortAcceptFrameType

+ * PURPOSE:

+ *      Set vlan accept frame type of the port from the specified device.

+ * INPUT:

+ *      unit        -- unit id

+ *      port        -- port id

+ *      type        -- accept frame type

+ * OUTPUT:

+ *      None

+ * RETURN:

+ *      AIR_E_OK                -- Successfully read the data.

+ *      AIR_E_OTHERS            -- Operation failed.

+ *      AIR_E_BAD_PARAMETER     -- Invalid parameter.

+ * NOTES:

+ *      none

+ */

+AIR_ERROR_NO_T

+air_vlan_setPortAcceptFrameType(

+    const UI32_T    unit,

+    const UI32_T    port,

+    const AIR_VLAN_ACCEPT_FRAME_TYPE_T type)

+{

+    AIR_ERROR_NO_T rc = AIR_E_OK;

+    UI32_T val = 0;

+

+    AIR_PARAM_CHK((port >= AIR_MAX_NUM_OF_PORTS), AIR_E_BAD_PARAMETER);

+    AIR_PARAM_CHK((type >= AIR_VLAN_ACCEPT_FRAME_TYPE_LAST), AIR_E_BAD_PARAMETER);

+

+    aml_readReg(unit, PVC(port), &val);

+    val &= ~PVC_ACC_FRM_MASK;

+    val |= (type & PVC_ACC_FRM_RELMASK) << PVC_ACC_FRM_OFFT;

+    aml_writeReg(unit, PVC(port), val);

+

+    return rc;

+}

+

+/* FUNCTION NAME:   air_vlan_getPortAcceptFrameType

+ * PURPOSE:

+ *      Get vlan accept frame type of the port from the specified device.

+ * INPUT:

+ *      unit        -- unit id

+ *      port        -- port id

+ * OUTPUT:

+ *      ptr_type    -- accept frame type

+ * RETURN:

+ *      AIR_E_OK                -- Successfully read the data.

+ *      AIR_E_OTHERS            -- Operation failed.

+ *      AIR_E_BAD_PARAMETER     -- Invalid parameter.

+ * NOTES:

+ *      none

+ */

+AIR_ERROR_NO_T

+air_vlan_getPortAcceptFrameType(

+    const UI32_T    unit,

+    const UI32_T    port,

+    AIR_VLAN_ACCEPT_FRAME_TYPE_T *ptr_type)

+{

+    AIR_ERROR_NO_T rc = AIR_E_OK;

+    UI32_T val = 0;

+

+    AIR_PARAM_CHK((port >= AIR_MAX_NUM_OF_PORTS), AIR_E_BAD_PARAMETER);

+    AIR_CHECK_PTR(ptr_type);

+

+    aml_readReg(unit, PVC(port), &val);

+    *ptr_type = (val >> PVC_ACC_FRM_OFFT) & PVC_ACC_FRM_RELMASK;

+

+    return rc;

+}

+

+/* FUNCTION NAME:   air_vlan_setPortLeakyVlanEnable

+ * PURPOSE:

+ *      Set leaky vlan enable of the port from the specified device.

+ * INPUT:

+ *      unit        -- unit id

+ *      port        -- port id

+ *      pkt_type    -- packet type

+ *      enable      -- enable leaky

+ * OUTPUT:

+ *      None

+ * RETURN:

+ *      AIR_E_OK                -- Successfully read the data.

+ *      AIR_E_OTHERS            -- Operation failed.

+ *      AIR_E_BAD_PARAMETER     -- Invalid parameter.

+ * NOTES:

+ *      none

+ */

+AIR_ERROR_NO_T

+air_vlan_setPortLeakyVlanEnable(

+    const UI32_T    unit,

+    const UI32_T    port,

+    AIR_LEAKY_PKT_TYPE_T   pkt_type,

+    const BOOL_T    enable)

+{

+    AIR_ERROR_NO_T rc = AIR_E_OK;

+    UI32_T val = 0;

+

+    AIR_PARAM_CHK((port >= AIR_MAX_NUM_OF_PORTS), AIR_E_BAD_PARAMETER);

+    AIR_PARAM_CHK((pkt_type >= AIR_LEAKY_PKT_TYPE_LAST), AIR_E_BAD_PARAMETER);

+

+    aml_readReg(unit, PVC(port), &val);

+

+    if (pkt_type == AIR_LEAKY_PKT_TYPE_UNICAST)

+    {

+        if (enable)

+        {

+            val |= PVC_UC_LKYV_EN_MASK;

+        }

+        else

+        {

+            val &= ~PVC_UC_LKYV_EN_MASK;

+        }

+    }

+    else if (pkt_type == AIR_LEAKY_PKT_TYPE_MULTICAST)

+    {

+        if (enable)

+        {

+            val |= PVC_MC_LKYV_EN_MASK;

+        }

+        else

+        {

+            val &= ~PVC_MC_LKYV_EN_MASK;

+        }

+    }

+    else

+    {

+        if (enable)

+        {

+            val |= PVC_BC_LKYV_EN_MASK;

+        }

+        else

+        {

+            val &= ~PVC_BC_LKYV_EN_MASK;

+        }

+    }

+

+    aml_writeReg(unit, PVC(port), val);

+

+    return rc;

+}

+

+/* FUNCTION NAME:   air_vlan_getPortLeakyVlanEnable

+ * PURPOSE:

+ *      Get leaky vlan enable of the port from the specified device.

+ * INPUT:

+ *      unit        -- unit id

+ *      port        -- port id

+ *      pkt_type    -- packet type

+ * OUTPUT:

+ *      ptr_enable  -- enable leaky

+ * RETURN:

+ *      AIR_E_OK                -- Successfully read the data.

+ *      AIR_E_OTHERS            -- Operation failed.

+ *      AIR_E_BAD_PARAMETER     -- Invalid parameter.

+ * NOTES:

+ *      none

+ */

+AIR_ERROR_NO_T

+air_vlan_getPortLeakyVlanEnable(

+    const UI32_T    unit,

+    const UI32_T    port,

+    AIR_LEAKY_PKT_TYPE_T   pkt_type,

+    BOOL_T          *ptr_enable)

+{

+    AIR_ERROR_NO_T rc = AIR_E_OK;

+    UI32_T val = 0;

+

+    AIR_PARAM_CHK((port >= AIR_MAX_NUM_OF_PORTS), AIR_E_BAD_PARAMETER);

+    AIR_PARAM_CHK((pkt_type >= AIR_LEAKY_PKT_TYPE_LAST), AIR_E_BAD_PARAMETER);

+    AIR_CHECK_PTR(ptr_enable);

+

+    aml_readReg(unit, PVC(port), &val);

+

+    if (pkt_type == AIR_LEAKY_PKT_TYPE_UNICAST)

+    {

+        *ptr_enable = val & PVC_UC_LKYV_EN_MASK ? TRUE : FALSE;

+    }

+    else if (pkt_type == AIR_LEAKY_PKT_TYPE_MULTICAST)

+    {

+        *ptr_enable = val & PVC_MC_LKYV_EN_MASK ? TRUE : FALSE;

+    }

+    else

+    {

+        *ptr_enable = val & PVC_BC_LKYV_EN_MASK ? TRUE : FALSE;

+    }

+

+    return rc;

+}

+

+/* FUNCTION NAME:   air_vlan_setPortAttr

+ * PURPOSE:

+ *      Set vlan port attribute from the specified device.

+ * INPUT:

+ *      unit        -- unit id

+ *      port        -- port id

+ *      attr        -- vlan port attr

+ * OUTPUT:

+ *      None

+ * RETURN:

+ *      AIR_E_OK                -- Successfully read the data.

+ *      AIR_E_OTHERS            -- Operation failed.

+ *      AIR_E_BAD_PARAMETER     -- Invalid parameter.

+ * NOTES:

+ *      none

+ */

+AIR_ERROR_NO_T

+air_vlan_setPortAttr(

+    const UI32_T    unit,

+    const UI32_T    port,

+    const AIR_VLAN_PORT_ATTR_T attr)

+{

+    AIR_ERROR_NO_T rc = AIR_E_OK;

+    UI32_T val = 0;

+

+    AIR_PARAM_CHK((port >= AIR_MAX_NUM_OF_PORTS), AIR_E_BAD_PARAMETER);

+    AIR_PARAM_CHK((attr >= AIR_VLAN_PORT_ATTR_LAST), AIR_E_BAD_PARAMETER);

+

+    aml_readReg(unit, PVC(port), &val);

+    val &= ~PVC_VLAN_ATTR_MASK;

+    val |= (attr & PVC_VLAN_ATTR_RELMASK) << PVC_VLAN_ATTR_OFFT;

+    aml_writeReg(unit, PVC(port), val);

+

+    return rc;

+}

+

+/* FUNCTION NAME:   air_vlan_getPortAttr

+ * PURPOSE:

+ *      Get vlan port attribute from the specified device.

+ * INPUT:

+ *      unit        -- unit id

+ *      port        -- port id

+ * OUTPUT:

+ *      ptr_attr    -- vlan port attr

+ * RETURN:

+ *      AIR_E_OK                -- Successfully read the data.

+ *      AIR_E_OTHERS            -- Operation failed.

+ *      AIR_E_BAD_PARAMETER     -- Invalid parameter.

+ * NOTES:

+ *      none

+ */

+AIR_ERROR_NO_T

+air_vlan_getPortAttr(

+    const UI32_T    unit,

+    const UI32_T    port,

+    AIR_VLAN_PORT_ATTR_T *ptr_attr)

+{

+    AIR_ERROR_NO_T rc = AIR_E_OK;

+    UI32_T val = 0;

+

+    AIR_PARAM_CHK((port >= AIR_MAX_NUM_OF_PORTS), AIR_E_BAD_PARAMETER);

+    AIR_CHECK_PTR(ptr_attr);

+

+    aml_readReg(unit, PVC(port), &val);

+    *ptr_attr = (val >> PVC_VLAN_ATTR_OFFT) & PVC_VLAN_ATTR_RELMASK;

+

+    return rc;

+}

+

+/* FUNCTION NAME:   air_vlan_setIgrPortTagAttr

+ * PURPOSE:

+ *      Set vlan incoming port egress tag attribute from the specified device.

+ * INPUT:

+ *      unit        -- unit id

+ *      port        -- port id

+ *      attr        -- egress tag attr

+ * OUTPUT:

+ *      None

+ * RETURN:

+ *      AIR_E_OK                -- Successfully read the data.

+ *      AIR_E_OTHERS            -- Operation failed.

+ *      AIR_E_BAD_PARAMETER     -- Invalid parameter.

+ * NOTES:

+ *      none

+ */

+AIR_ERROR_NO_T

+air_vlan_setIgrPortTagAttr(

+    const UI32_T    unit,

+    const UI32_T    port,

+    const AIR_IGR_PORT_EG_TAG_ATTR_T attr)

+{

+    UI32_T val = 0;

+

+    AIR_PARAM_CHK((port >= AIR_MAX_NUM_OF_PORTS), AIR_E_BAD_PARAMETER);

+    AIR_PARAM_CHK((attr >= AIR_IGR_PORT_EG_TAG_ATTR_LAST), AIR_E_BAD_PARAMETER);

+

+    aml_readReg(unit, PVC(port), &val);

+    val &= ~PVC_EG_TAG_MASK;

+    val |= (attr & PVC_EG_TAG_RELMASK) << PVC_EG_TAG_OFFT;

+    aml_writeReg(unit, PVC(port), val);

+

+    return AIR_E_OK;

+}

+

+/* FUNCTION NAME:   air_vlan_getIgrPortTagAttr

+ * PURPOSE:

+ *      Get vlan incoming port egress tag attribute from the specified device.

+ * INPUT:

+ *      unit        -- unit id

+ *      port        -- port id

+ * OUTPUT:

+ *      ptr_attr    -- egress tag attr

+ * RETURN:

+ *      AIR_E_OK                -- Successfully read the data.

+ *      AIR_E_OTHERS            -- Operation failed.

+ *      AIR_E_BAD_PARAMETER     -- Invalid parameter.

+ * NOTES:

+ *      none

+ */

+AIR_ERROR_NO_T

+air_vlan_getIgrPortTagAttr(

+    const UI32_T    unit,

+    const UI32_T    port,

+    AIR_IGR_PORT_EG_TAG_ATTR_T *ptr_attr)

+{

+    UI32_T val = 0;

+

+    AIR_PARAM_CHK((port >= AIR_MAX_NUM_OF_PORTS), AIR_E_BAD_PARAMETER);

+    AIR_CHECK_PTR(ptr_attr);

+

+    aml_readReg(unit, PVC(port), &val);

+    *ptr_attr = (val >> PVC_EG_TAG_OFFT) & PVC_EG_TAG_RELMASK;

+

+    return AIR_E_OK;

+}

+

+/* FUNCTION NAME:   air_vlan_setPortEgsTagAttr

+ * PURPOSE:

+ *      Set vlan port egress tag attribute from the specified device.

+ * INPUT:

+ *      unit        -- unit id

+ *      port        -- port id

+ *      attr        -- egress tag attr

+ * OUTPUT:

+ *      None

+ * RETURN:

+ *      AIR_E_OK                -- Successfully read the data.

+ *      AIR_E_OTHERS            -- Operation failed.

+ *      AIR_E_BAD_PARAMETER     -- Invalid parameter.

+ * NOTES:

+ *      none

+ */

+AIR_ERROR_NO_T

+air_vlan_setPortEgsTagAttr(

+    const UI32_T    unit,

+    const UI32_T    port,

+    const AIR_PORT_EGS_TAG_ATTR_T attr)

+{

+    UI32_T val = 0;

+

+    AIR_PARAM_CHK((port >= AIR_MAX_NUM_OF_PORTS), AIR_E_BAD_PARAMETER);

+    AIR_PARAM_CHK((attr >= AIR_PORT_EGS_TAG_ATTR_LAST), AIR_E_BAD_PARAMETER);

+

+    aml_readReg(unit, PCR(port), &val);

+    val &= ~PCR_EG_TAG_MASK;

+    val |= (attr & PCR_EG_TAG_RELMASK) << PCR_EG_TAG_OFFT;

+    aml_writeReg(unit, PCR(port), val);

+

+    return AIR_E_OK;

+}

+

+/* FUNCTION NAME:   air_vlan_getPortEgsTagAttr

+ * PURPOSE:

+ *      Get vlan port egress tag attribute from the specified device.

+ * INPUT:

+ *      unit        -- unit id

+ *      port        -- port id

+ * OUTPUT:

+ *      ptr_attr    -- egress tag attr

+ * RETURN:

+ *      AIR_E_OK                -- Successfully read the data.

+ *      AIR_E_OTHERS            -- Operation failed.

+ *      AIR_E_BAD_PARAMETER     -- Invalid parameter.

+ * NOTES:

+ *      none

+ */

+AIR_ERROR_NO_T

+air_vlan_getPortEgsTagAttr(

+    const UI32_T    unit,

+    const UI32_T    port,

+    AIR_PORT_EGS_TAG_ATTR_T *ptr_attr)

+{

+    UI32_T val = 0;

+

+    AIR_PARAM_CHK((port >= AIR_MAX_NUM_OF_PORTS), AIR_E_BAD_PARAMETER);

+    AIR_CHECK_PTR(ptr_attr);

+

+    aml_readReg(unit, PCR(port), &val);

+    *ptr_attr = (val >> PCR_EG_TAG_OFFT) & PCR_EG_TAG_RELMASK;

+

+    return AIR_E_OK;

+}

+

+/* FUNCTION NAME:   air_vlan_setPortOuterTPID

+ * PURPOSE:

+ *      Set stack tag TPID of the port from the specified device.

+ * INPUT:

+ *      unit        -- unit id

+ *      port        -- port id

+ *      tpid        -- TPID

+ * OUTPUT:

+ *      None

+ * RETURN:

+ *      AIR_E_OK                -- Successfully read the data.

+ *      AIR_E_OTHERS            -- Operation failed.

+ *      AIR_E_BAD_PARAMETER     -- Invalid parameter.

+ * NOTES:

+ *      none

+ */

+AIR_ERROR_NO_T

+air_vlan_setPortOuterTPID(

+    const UI32_T    unit,

+    const UI32_T    port,

+    const UI16_T    tpid)

+{

+    UI32_T val = 0;

+

+    AIR_PARAM_CHK((port >= AIR_MAX_NUM_OF_PORTS), AIR_E_BAD_PARAMETER);

+

+    aml_readReg(unit, PVC(port), &val);

+    val &= ~PVC_STAG_VPID_MASK;

+    val |= (tpid & PVC_STAG_VPID_RELMASK) << PVC_STAG_VPID_OFFT;

+    aml_writeReg(unit, PVC(port), val);

+

+    return AIR_E_OK;

+}

+

+/* FUNCTION NAME:   air_vlan_getPortOuterTPID

+ * PURPOSE:

+ *      Get stack tag TPID of the port from the specified device.

+ * INPUT:

+ *      unit        -- unit id

+ *      port        -- port id

+ * OUTPUT:

+ *      ptr_tpid    -- TPID

+ * RETURN:

+ *      AIR_E_OK                -- Successfully read the data.

+ *      AIR_E_OTHERS            -- Operation failed.

+ *      AIR_E_BAD_PARAMETER     -- Invalid parameter.

+ * NOTES:

+ *      none

+ */

+AIR_ERROR_NO_T

+air_vlan_getPortOuterTPID(

+    const UI32_T    unit,

+    const UI32_T    port,

+    UI16_T          *ptr_tpid)

+{

+    UI32_T val = 0;

+

+    AIR_PARAM_CHK((port >= AIR_MAX_NUM_OF_PORTS), AIR_E_BAD_PARAMETER);

+    AIR_CHECK_PTR(ptr_tpid);

+

+    aml_readReg(unit, PVC(port), &val);

+    *ptr_tpid = (val >> PVC_STAG_VPID_OFFT) & PVC_STAG_VPID_RELMASK;

+

+    return AIR_E_OK;

+}

+

+/* FUNCTION NAME:   air_vlan_setPortPVID

+ * PURPOSE:

+ *      Set PVID of the port from the specified device.

+ * INPUT:

+ *      unit        -- unit id

+ *      port        -- port id

+ *      pvid        -- native vlan id

+ * OUTPUT:

+ *      None

+ * RETURN:

+ *      AIR_E_OK                -- Successfully read the data.

+ *      AIR_E_OTHERS            -- Operation failed.

+ *      AIR_E_BAD_PARAMETER     -- Invalid parameter.

+ * NOTES:

+ *      none

+ */

+AIR_ERROR_NO_T

+air_vlan_setPortPVID(

+    const UI32_T    unit,

+    const UI32_T    port,

+    const UI16_T    pvid)

+{

+    UI32_T val = 0;

+

+    AIR_PARAM_CHK((port >= AIR_MAX_NUM_OF_PORTS), AIR_E_BAD_PARAMETER);

+    AIR_PARAM_CHK((pvid > AIR_VLAN_ID_MAX), AIR_E_BAD_PARAMETER);

+

+    aml_readReg(unit, PVID(port), &val);

+    val &= ~PVID_PCVID_MASK;

+    val |= (pvid & PVID_PCVID_RELMASK) << PVID_PCVID_OFFT;

+    aml_writeReg(unit, PVID(port), val);

+

+    return AIR_E_OK;

+}

+

+/* FUNCTION NAME:   air_vlan_getPortPVID

+ * PURPOSE:

+ *      Get PVID of the port from the specified device.

+ * INPUT:

+ *      unit        -- unit id

+ *      port        -- port id

+ * OUTPUT:

+ *      ptr_pvid    -- native vlan id

+ * RETURN:

+ *      AIR_E_OK                -- Successfully read the data.

+ *      AIR_E_OTHERS            -- Operation failed.

+ *      AIR_E_BAD_PARAMETER     -- Invalid parameter.

+ * NOTES:

+ *      none

+ */

+AIR_ERROR_NO_T

+air_vlan_getPortPVID(

+    const UI32_T    unit,

+    const UI32_T    port,

+    UI16_T          *ptr_pvid)

+{

+    UI32_T val = 0;

+

+    AIR_PARAM_CHK((port >= AIR_MAX_NUM_OF_PORTS), AIR_E_BAD_PARAMETER);

+    AIR_CHECK_PTR(ptr_pvid);

+

+    aml_readReg(unit, PVID(port), &val);

+    *ptr_pvid = (val >> PVID_PCVID_OFFT) & PVID_PCVID_RELMASK;

+

+    return AIR_E_OK;

+}

+

+/* FUNCTION NAME:   air_vlan_setServiceTag

+ * PURPOSE:

+ *      Set Vlan service tag.

+ * INPUT:

+ *      unit        -- unit id

+ *      vid         -- vlan id

+ *      stag        -- service stag

+ * OUTPUT:

+ *      None

+ * RETURN:

+ *      AIR_E_OK                -- Successfully read the data.

+ *      AIR_E_OTHERS            -- Operation failed.

+ *      AIR_E_BAD_PARAMETER     -- Invalid parameter.

+ * NOTES:

+ *      none

+ */

+AIR_ERROR_NO_T

+air_vlan_setServiceTag(

+    const UI32_T    unit,

+    const UI16_T    vid,

+    const UI16_T    stag)

+{

+    AIR_VLAN_ENTRY_T vlan_entry = {0};

+

+    AIR_PARAM_CHK((vid > AIR_VLAN_ID_MAX), AIR_E_BAD_PARAMETER);

+    AIR_PARAM_CHK((stag > AIR_VLAN_ID_MAX), AIR_E_BAD_PARAMETER);

+

+    _air_vlan_readEntry(unit, vid, &vlan_entry);

+    if (!vlan_entry.valid)

+        return AIR_E_ENTRY_NOT_FOUND;

+

+    vlan_entry.vlan_entry_format.stag = stag;

+    _air_vlan_writeEntry(unit, vid, &vlan_entry);

+

+    return AIR_E_OK;

+}

+

+/* FUNCTION NAME:   air_vlan_getServiceTag

+ * PURPOSE:

+ *      Get Vlan service tag.

+ * INPUT:

+ *      unit        -- unit id

+ *      vid         -- vlan id

+ * OUTPUT:

+ *      ptr_stag    -- service stag

+ * RETURN:

+ *      AIR_E_OK                -- Successfully read the data.

+ *      AIR_E_OTHERS            -- Operation failed.

+ *      AIR_E_BAD_PARAMETER     -- Invalid parameter.

+ * NOTES:

+ *      none

+ */

+AIR_ERROR_NO_T

+air_vlan_getServiceTag(

+    const UI32_T    unit,

+    const UI16_T    vid,

+    UI16_T          *ptr_stag)

+{

+    AIR_VLAN_ENTRY_T vlan_entry = {0};

+

+    AIR_PARAM_CHK((vid > AIR_VLAN_ID_MAX), AIR_E_BAD_PARAMETER);

+    AIR_CHECK_PTR(ptr_stag);

+

+    _air_vlan_readEntry(unit, vid, &vlan_entry);

+    if (!vlan_entry.valid)

+        return AIR_E_ENTRY_NOT_FOUND;

+

+    *ptr_stag = vlan_entry.vlan_entry_format.stag;

+

+    return AIR_E_OK;

+}

+

+/* FUNCTION NAME:   air_vlan_setEgsTagCtlEnable

+ * PURPOSE:

+ *      Set per vlan egress tag control.

+ * INPUT:

+ *      unit        -- unit id

+ *      vid         -- vlan id

+ *      enable      -- enable vlan egress tag control

+ * OUTPUT:

+ *      None

+ * RETURN:

+ *      AIR_E_OK                -- Successfully read the data.

+ *      AIR_E_OTHERS            -- Operation failed.

+ *      AIR_E_BAD_PARAMETER     -- Invalid parameter.

+ * NOTES:

+ *      none

+ */

+AIR_ERROR_NO_T

+air_vlan_setEgsTagCtlEnable(

+    const UI32_T    unit,

+    const UI16_T    vid,

+    const BOOL_T    enable)

+{

+    AIR_VLAN_ENTRY_T vlan_entry = {0};

+

+    AIR_PARAM_CHK((vid > AIR_VLAN_ID_MAX), AIR_E_BAD_PARAMETER);

+

+    _air_vlan_readEntry(unit, vid, &vlan_entry);

+    if (!vlan_entry.valid)

+        return AIR_E_ENTRY_NOT_FOUND;

+

+    vlan_entry.vlan_entry_format.eg_ctrl_en = enable ? 1 : 0;

+    _air_vlan_writeEntry(unit, vid, &vlan_entry);

+

+    return AIR_E_OK;

+}

+

+/* FUNCTION NAME:   air_vlan_getEgsTagCtlEnable

+ * PURPOSE:

+ *      Get per vlan egress tag control.

+ * INPUT:

+ *      unit        -- unit id

+ *      vid         -- vlan id

+ * OUTPUT:

+ *      ptr_enable  -- enable vlan egress tag control

+ * RETURN:

+ *      AIR_E_OK                -- Successfully read the data.

+ *      AIR_E_OTHERS            -- Operation failed.

+ *      AIR_E_BAD_PARAMETER     -- Invalid parameter.

+ * NOTES:

+ *      none

+ */

+AIR_ERROR_NO_T

+air_vlan_getEgsTagCtlEnable(

+    const UI32_T    unit,

+    const UI16_T    vid,

+    BOOL_T          *ptr_enable)

+{

+    AIR_VLAN_ENTRY_T vlan_entry = {0};

+

+    AIR_PARAM_CHK((vid > AIR_VLAN_ID_MAX), AIR_E_BAD_PARAMETER);

+    AIR_CHECK_PTR(ptr_enable);

+

+    _air_vlan_readEntry(unit, vid, &vlan_entry);

+    if (!vlan_entry.valid)

+        return AIR_E_ENTRY_NOT_FOUND;

+

+    *ptr_enable = vlan_entry.vlan_entry_format.eg_ctrl_en;

+

+    return AIR_E_OK;

+}

+

+/* FUNCTION NAME:   air_vlan_setEgsTagConsistent

+ * PURPOSE:

+ *      Set per vlan egress tag consistent.

+ * INPUT:

+ *      unit        -- unit id

+ *      vid         -- vlan id

+ *      enable      -- enable vlan egress tag consistent

+ * OUTPUT:

+ *      None

+ * RETURN:

+ *      AIR_E_OK                -- Successfully read the data.

+ *      AIR_E_OTHERS            -- Operation failed.

+ *      AIR_E_BAD_PARAMETER     -- Invalid parameter.

+ * NOTES:

+ *      none

+ */

+AIR_ERROR_NO_T

+air_vlan_setEgsTagConsistent(

+    const UI32_T    unit,

+    const UI16_T    vid,

+    const BOOL_T    enable)

+{

+    AIR_VLAN_ENTRY_T vlan_entry = {0};

+

+    AIR_PARAM_CHK((vid > AIR_VLAN_ID_MAX), AIR_E_BAD_PARAMETER);

+

+    _air_vlan_readEntry(unit, vid, &vlan_entry);

+    if (!vlan_entry.valid)

+        return AIR_E_ENTRY_NOT_FOUND;

+

+    vlan_entry.vlan_entry_format.eg_con = enable;

+    _air_vlan_writeEntry(unit, vid, &vlan_entry);

+

+    return AIR_E_OK;

+}

+

+/* FUNCTION NAME:   air_vlan_getEgsTagConsistent

+ * PURPOSE:

+ *      Get per vlan egress tag consistent.

+ * INPUT:

+ *      unit        -- unit id

+ *      vid         -- vlan id

+ * OUTPUT:

+ *      ptr_enable  -- enable vlan egress tag consistent

+ * RETURN:

+ *      AIR_E_OK                -- Successfully read the data.

+ *      AIR_E_OTHERS            -- Operation failed.

+ *      AIR_E_BAD_PARAMETER     -- Invalid parameter.

+ * NOTES:

+ *      none

+ */

+AIR_ERROR_NO_T

+air_vlan_getEgsTagConsistent(

+    const UI32_T    unit,

+    const UI16_T    vid,

+    BOOL_T          *ptr_enable)

+{

+    AIR_VLAN_ENTRY_T vlan_entry = {0};

+

+    AIR_PARAM_CHK((vid > AIR_VLAN_ID_MAX), AIR_E_BAD_PARAMETER);

+    AIR_CHECK_PTR(ptr_enable);

+

+    _air_vlan_readEntry(unit, vid, &vlan_entry);

+    if (!vlan_entry.valid)

+        return AIR_E_ENTRY_NOT_FOUND;

+

+    *ptr_enable = vlan_entry.vlan_entry_format.eg_con;

+

+    return AIR_E_OK;

+}

+

+/* FUNCTION NAME:   air_vlan_setPortBasedStag

+ * PURPOSE:

+ *      Set vlan port based stag enable.

+ * INPUT:

+ *      unit        -- unit id

+ *      vid         -- vlan id

+ *      enable      -- vlan port based stag enable

+ * OUTPUT:

+ *      None

+ * RETURN:

+ *      AIR_E_OK                -- Successfully read the data.

+ *      AIR_E_OTHERS            -- Operation failed.

+ *      AIR_E_BAD_PARAMETER     -- Invalid parameter.

+ * NOTES:

+ *      none

+ */

+AIR_ERROR_NO_T

+air_vlan_setPortBasedStag(

+    const UI32_T    unit,

+    const UI16_T    vid,

+    const BOOL_T    enable)

+{

+    AIR_VLAN_ENTRY_T vlan_entry = {0};

+

+    AIR_PARAM_CHK((vid > AIR_VLAN_ID_MAX), AIR_E_BAD_PARAMETER);

+

+    _air_vlan_readEntry(unit, vid, &vlan_entry);

+    if (!vlan_entry.valid)

+        return AIR_E_ENTRY_NOT_FOUND;

+

+    vlan_entry.vlan_entry_format.port_stag = enable;

+    _air_vlan_writeEntry(unit, vid, &vlan_entry);

+

+    return AIR_E_OK;

+}

+

+/* FUNCTION NAME:   air_vlan_getPortBasedStag

+ * PURPOSE:

+ *      Get vlan port based stag enable.

+ * INPUT:

+ *      unit        -- unit id

+ *      vid         -- vlan id

+ * OUTPUT:

+ *      ptr_enable  -- vlan port based stag enable

+ * RETURN:

+ *      AIR_E_OK                -- Successfully read the data.

+ *      AIR_E_OTHERS            -- Operation failed.

+ *      AIR_E_BAD_PARAMETER     -- Invalid parameter.

+ * NOTES:

+ *      none

+ */

+AIR_ERROR_NO_T

+air_vlan_getPortBasedStag(

+    const UI32_T    unit,

+    const UI16_T    vid,

+    BOOL_T          *ptr_enable)

+{

+    AIR_VLAN_ENTRY_T vlan_entry = {0};

+

+    AIR_PARAM_CHK((vid > AIR_VLAN_ID_MAX), AIR_E_BAD_PARAMETER);

+    AIR_CHECK_PTR(ptr_enable);

+

+    _air_vlan_readEntry(unit, vid, &vlan_entry);

+    if (!vlan_entry.valid)

+        return AIR_E_ENTRY_NOT_FOUND;

+

+    *ptr_enable = vlan_entry.vlan_entry_format.port_stag;

+

+    return AIR_E_OK;

+}

+

+/* FUNCTION NAME:   air_vlan_setPortEgsTagCtl

+ * PURPOSE:

+ *      Set vlan port egress tag control.

+ * INPUT:

+ *      unit        -- unit id

+ *      vid         -- vlan id

+ *      port        -- port id

+ *      tag_ctl     -- egress tag control

+ * OUTPUT:

+ *      None

+ * RETURN:

+ *      AIR_E_OK                -- Successfully read the data.

+ *      AIR_E_OTHERS            -- Operation failed.

+ *      AIR_E_BAD_PARAMETER     -- Invalid parameter.

+ * NOTES:

+ *      none

+ */

+AIR_ERROR_NO_T

+air_vlan_setPortEgsTagCtl(

+    const UI32_T    unit,

+    const UI16_T    vid,

+    const UI32_T    port,

+    const AIR_VLAN_PORT_EGS_TAG_CTL_TYPE_T    tag_ctl)

+{

+    AIR_VLAN_ENTRY_T vlan_entry = {0};

+

+    AIR_PARAM_CHK((vid > AIR_VLAN_ID_MAX), AIR_E_BAD_PARAMETER);

+    AIR_PARAM_CHK((port >= AIR_MAX_NUM_OF_PORTS), AIR_E_BAD_PARAMETER);

+    AIR_PARAM_CHK((tag_ctl >= AIR_PORT_EGS_TAG_ATTR_LAST), AIR_E_BAD_PARAMETER);

+

+    _air_vlan_readEntry(unit, vid, &vlan_entry);

+    if (!vlan_entry.valid)

+        return AIR_E_ENTRY_NOT_FOUND;

+

+    vlan_entry.vlan_entry_format.eg_ctrl &= ~(0x3 << (port * 2));

+    vlan_entry.vlan_entry_format.eg_ctrl |= (tag_ctl & 0x3) << (port * 2);

+    _air_vlan_writeEntry(unit, vid, &vlan_entry);

+

+    return AIR_E_OK;

+}

+

+/* FUNCTION NAME:   air_vlan_getPortEgsTagCtl

+ * PURPOSE:

+ *      Get vlan port egress tag control.

+ * INPUT:

+ *      unit        -- unit id

+ *      vid         -- vlan id

+ * OUTPUT:

+ *      ptr_tag_ctl -- egress tag control

+ * RETURN:

+ *      AIR_E_OK                -- Successfully read the data.

+ *      AIR_E_OTHERS            -- Operation failed.

+ *      AIR_E_BAD_PARAMETER     -- Invalid parameter.

+ * NOTES:

+ *      none

+ */

+AIR_ERROR_NO_T

+air_vlan_getPortEgsTagCtl(

+    const UI32_T    unit,

+    const UI16_T    vid,

+    const UI32_T    port,

+    AIR_VLAN_PORT_EGS_TAG_CTL_TYPE_T   *ptr_tag_ctl)

+{

+    AIR_VLAN_ENTRY_T vlan_entry = {0};

+

+    AIR_PARAM_CHK((vid > AIR_VLAN_ID_MAX), AIR_E_BAD_PARAMETER);

+    AIR_PARAM_CHK((port >= AIR_MAX_NUM_OF_PORTS), AIR_E_BAD_PARAMETER);

+    AIR_CHECK_PTR(ptr_tag_ctl);

+

+    _air_vlan_readEntry(unit, vid, &vlan_entry);

+    if (!vlan_entry.valid)

+        return AIR_E_ENTRY_NOT_FOUND;

+

+    *ptr_tag_ctl = (vlan_entry.vlan_entry_format.eg_ctrl >> (port * 2)) & 0x3;

+

+    return AIR_E_OK;

+}

diff --git a/recipes-devtools/switch/files/src/an8855_sdk/core/an8855_init.c b/recipes-devtools/switch/files/src/an8855_sdk/core/an8855_init.c
new file mode 100644
index 0000000..c754955
--- /dev/null
+++ b/recipes-devtools/switch/files/src/an8855_sdk/core/an8855_init.c
@@ -0,0 +1,138 @@
+/* FILE NAME:  an8855_init.c
+ * PURPOSE:
+ *    It provides an8855 switch intialize flow.
+ *
+ * NOTES:
+ *
+ */
+
+/* INCLUDE FILE DECLARATIONS
+ */
+#include "an8855_reg.h"
+#include "an8855_mdio.h"
+#include "an8855_phy.h"
+
+/* NAMING CONSTANT DECLARATIONS
+*/
+
+/* MACRO FUNCTION DECLARATIONS
+ */
+
+/* DATA TYPE DECLARATIONS
+*/
+
+/* GLOBAL VARIABLE DECLARATIONS
+*/
+
+/* LOCAL SUBPROGRAM DECLARATIONS
+*/
+
+/* STATIC VARIABLE DECLARATIONS
+*/
+
+/* EXPORTED SUBPROGRAM BODIES
+*/
+
+/* FUNCTION NAME:   an8855_hw_reset
+ * PURPOSE:
+ *      This API is used to reset an8855 hw.
+ * INPUT:
+ * OUTPUT:
+ * RETURN:
+ * NOTES:
+ *      Attention!! Customer should implement this func
+ */
+void
+an8855_hw_reset(void)
+{
+    //dbg_print(">>>>> an8855_hw_reset\n");
+    /* set an8855 reset pin to 0 */
+
+    /* delay 100ms */
+
+    /* set an8855 reset pin to 1 */
+
+    /* delay 600ms */
+
+}
+
+/* FUNCTION NAME:   an8855_sw_reset
+ * PURPOSE:
+ *      This API is used to reset an8855 system.
+ * INPUT:
+ * OUTPUT:
+ * RETURN:
+ * NOTES:
+ */
+void
+an8855_sw_reset(void)
+{
+    //dbg_print(">>>>> an8855_sw_reset\n");
+    an8855_reg_write(0x100050c0, 0x80000000);
+    an8855_udelay(100000);
+}
+
+/* FUNCTION NAME:   an8855_phy_calibration_setting
+ * PURPOSE:
+ *      This API is used to set an8855 phy calibration.
+ * INPUT:
+ * OUTPUT:
+ * RETURN:
+ * NOTES:
+ *      None
+ */
+void
+an8855_phy_calibration_setting(void)
+{
+    int i = 0;
+
+    //dbg_print("\nSMI IOMUX initial ...");
+    an8855_reg_write(0x10000070, 0x2);
+    an8855_udelay(10000);
+    //dbg_print("\nGPHY initial ...");
+    an8855_reg_write(0x1028C840, 0x0);
+    for(i = 0; i <= 4; i++)
+    {
+        an8855_phy_write(i, 0, 0x1040);
+    }
+    an8855_udelay(10000);
+    //dbg_print("Done");
+    //dbg_print("\nSw calibration ... ");
+    gphy_calibration(g_smi_addr);
+    //dbg_print("\nDone");
+}
+
+/* FUNCTION NAME:   an8855_init
+ * PURPOSE:
+ *      This API is used to init an8855.
+ * INPUT:
+ * OUTPUT:
+ * RETURN:
+ *      0 -- init success
+ *      -1 -- init failure
+ * NOTES:
+ *      Attention!! Customer should implement part of this func
+ */
+int
+an8855_init(void)
+{
+    u32 data = 0;
+
+    /* an8855 hw reset */
+    an8855_hw_reset();
+
+    /* an8855 system reset */
+    an8855_sw_reset();
+
+    /* Keep the clock ticking when all ports link down */
+    data = an8855_reg_read(0x10213e1c);
+    data &= ~(0x3);
+    an8855_reg_write(0x10213e1c, data);
+
+    /* internal phy calibration */
+    /* please comment out this func after calibration data loaded from ROM code */
+    an8855_phy_calibration_setting();
+
+    return 0;
+}
+
diff --git a/recipes-devtools/switch/files/src/an8855_sdk/core/an8855_mdio.c b/recipes-devtools/switch/files/src/an8855_sdk/core/an8855_mdio.c
new file mode 100644
index 0000000..3ff7ded
--- /dev/null
+++ b/recipes-devtools/switch/files/src/an8855_sdk/core/an8855_mdio.c
@@ -0,0 +1,285 @@
+/* FILE NAME:  an8855_mdio.c
+ * PURPOSE:
+ *    It provides an8855 registers and PHY mdio access.
+ *
+ * NOTES:
+ *
+ */
+
+/* INCLUDE FILE DECLARATIONS
+ */
+#include "an8855_reg.h"
+#include "an8855_mdio.h"
+
+/* NAMING CONSTANT DECLARATIONS
+*/
+
+/* MACRO FUNCTION DECLARATIONS
+ */
+#define AN8855_SMI_ADDR     (1)
+
+/* DATA TYPE DECLARATIONS
+*/
+
+/* GLOBAL VARIABLE DECLARATIONS
+*/
+
+/* LOCAL SUBPROGRAM DECLARATIONS
+*/
+
+/* STATIC VARIABLE DECLARATIONS
+*/
+u32 g_smi_addr = AN8855_SMI_ADDR;
+
+static AIR_MII_READ_FUNC_T g_mii_read = NULL;
+static AIR_MII_WRITE_FUNC_T g_mii_write = NULL;
+static AIR_MII_C45_READ_FUNC_T g_mii_c45_read = NULL;
+static AIR_MII_C45_WRITE_FUNC_T g_mii_c45_write = NULL;
+
+/* EXPORTED SUBPROGRAM BODIES
+*/
+
+/* FUNCTION NAME:   an8855_set_smi_addr
+ * PURPOSE:
+ *      This API is used to set an8855 smi address.
+ * INPUT:
+ *      smi_addr -- AN8855 smi address
+ * OUTPUT:
+ * RETURN:
+ * NOTES:
+ *      None
+ */
+void
+an8855_set_smi_addr(u32 smi_addr)
+{
+    an8855_reg_write(0x1028C848, smi_addr);
+    g_smi_addr = smi_addr;
+}
+
+/* FUNCTION NAME:   an8855_set_mii_callback
+ * PURPOSE:
+ *      This API is used to set an8855 mii access callbacks.
+ * INPUT:
+ *      mii_read -- mii read api function
+ *      mii_write -- mii write api function
+ *      mii_c45_read --  mii c45 read api function
+ *      mii_c45_write -- mii c45 write api function
+ * OUTPUT:
+ * RETURN:
+ *      0     -- Successfully set callback.
+ *      -1    -- Setting callback failed.
+ * NOTES:
+ *      None
+ */
+int
+an8855_set_mii_callback(
+    AIR_MII_READ_FUNC_T mii_read,
+    AIR_MII_WRITE_FUNC_T mii_write,
+    AIR_MII_C45_READ_FUNC_T mii_c45_read,
+    AIR_MII_C45_WRITE_FUNC_T mii_c45_write)
+{
+    if (!mii_read || !mii_write || !mii_c45_read || !mii_c45_write)
+        return -1;
+
+    g_mii_read = mii_read;
+    g_mii_write = mii_write;
+    g_mii_c45_read = mii_c45_read;
+    g_mii_c45_write = mii_c45_write;
+
+    return 0;
+}
+
+/* FUNCTION NAME:   an8855_reg_read
+ * PURPOSE:
+ *      This API is used read an8855 registers.
+ * INPUT:
+ *      reg -- register offset
+ * OUTPUT:
+ * RETURN:
+ *      Register value
+ * NOTES:
+ *      Attention!! Customer should implement mdio mutex
+ *      lock in this func
+ */
+u32
+an8855_reg_read(u32 reg)
+{
+    u16 data_h = 0;
+    u16 data_l = 0;
+    int ret = 0;
+
+    g_mii_write(g_smi_addr, 0x1F, 0x4);
+    g_mii_write(g_smi_addr, 0x10, 0x0);
+
+    g_mii_write(g_smi_addr, 0x15, ((reg >> 16) & 0xFFFF));
+    g_mii_write(g_smi_addr, 0x16, (reg & 0xFFFF));
+
+    ret = g_mii_read(g_smi_addr, 0x17, &data_h);
+    if(ret != 0)
+    {
+        printf("read reg 0x%x 0x17 fail\n", reg);
+    }
+    ret = g_mii_read(g_smi_addr, 0x18, &data_l);
+    if(ret != 0)
+    {
+        printf("read reg 0x%x 0x18 fail\n", reg);
+    }
+
+    g_mii_write(g_smi_addr, 0x1F, 0x0);
+    g_mii_write(g_smi_addr, 0x10, 0x0);
+    //printf("read reg:0x%08x data:0x%08x\n", reg, ((data_h << 16) | (data_l & 0xffff)));
+
+    return ((data_h << 16) | (data_l & 0xffff));
+}
+
+/* FUNCTION NAME:   an8855_reg_write
+ * PURPOSE:
+ *      This API is used write an8855 registers.
+ * INPUT:
+ *      reg -- register offset
+ *      val -- register value
+ * OUTPUT:
+ * RETURN:
+ * NOTES:
+ *      Attention!! Customer should implement mdio mutex
+ *      lock in this func
+ */
+void
+an8855_reg_write(u32 reg, u32 val)
+{
+    g_mii_write(g_smi_addr, 0x1F, 0x4);
+    g_mii_write(g_smi_addr, 0x10, 0x0);
+
+    g_mii_write(g_smi_addr, 0x11, ((reg >> 16) & 0xFFFF));
+    g_mii_write(g_smi_addr, 0x12, (reg & 0xFFFF));
+
+    g_mii_write(g_smi_addr, 0x13, ((val >> 16) & 0xFFFF));
+    g_mii_write(g_smi_addr, 0x14, (val & 0xFFFF));
+
+    g_mii_write(g_smi_addr, 0x1F, 0x0);
+    g_mii_write(g_smi_addr, 0x10, 0x0);
+    //printf("write reg:0x%08x data:0x%08x\n", reg, val);
+}
+
+/* FUNCTION NAME:   an8855_phy_read
+ * PURPOSE:
+ *      This API is used read an8855 phy registers.
+ * INPUT:
+ *      port_num -- port number, 0~4
+ *      reg -- phy register offset
+ * OUTPUT:
+ *      p_val -- phy register value
+ * RETURN:
+ *      0 -- read success
+ *      -1 -- read failure
+ * NOTES:
+ *      Attention!! Customer should implement mii mutex
+ *      lock in this func
+ */
+int
+an8855_phy_read(u32 port_num, u32 reg, u32 *p_val)
+{
+    u32 phy = 0, data = 0;
+
+    if (port_num >= AN8855_PHY_NUM)
+        return -1;
+
+    phy = g_smi_addr + port_num;
+    g_mii_read(phy, reg, &data);
+    *p_val = data & 0x0000FFFF;
+
+    return 0;
+}
+
+/* FUNCTION NAME:   an8855_phy_write
+ * PURPOSE:
+ *      This API is used write an8855 phy registers.
+ * INPUT:
+ *      port_num -- port number, 0~4
+ *      reg -- phy register offset
+ *      val -- phy register value
+ * OUTPUT:
+ * RETURN:
+ *      0 -- write success
+ *      -1 -- write failure
+ * NOTES:
+ *      Attention!! Customer should implement mii mutex
+ *      lock in this func
+ */
+int
+an8855_phy_write(u32 port_num, u32 reg, u32 val)
+{
+    u32 phy = 0, data = 0;
+
+    if (port_num >= AN8855_PHY_NUM)
+        return -1;
+
+    phy = g_smi_addr + port_num;
+    data = val & 0x0000FFFF;
+    g_mii_write(phy, reg, data);
+
+    return 0;
+}
+
+/* FUNCTION NAME:   an8855_phy_read_cl45
+ * PURPOSE:
+ *      This API is used read an8855 phy registers.
+ * INPUT:
+ *      port_num -- port number, 0~4
+ *      dev_addr -- phy device type
+ *      reg_addr -- phy register offset
+ * OUTPUT:
+ *      p_val -- phy register value
+ * RETURN:
+ *      0 -- read success
+ *      -1 -- read failure
+ * NOTES:
+ *      Attention!! Customer should implement mii mutex
+ *      lock in this func or before/after calling this func
+ */
+u32
+an8855_phy_read_cl45(u32 port_num, u32 dev_addr, u32 reg_addr, u32 *p_val)
+{
+    u32 phy = 0, data = 0;
+
+    if (port_num >= AN8855_PHY_NUM)
+        return -1;
+
+    phy = g_smi_addr + port_num;
+    g_mii_c45_read(phy, dev_addr, reg_addr, &data);
+    *p_val = data & 0x0000FFFF;
+
+    return 0;
+}
+
+/* FUNCTION NAME:   an8855_phy_write_cl45
+ * PURPOSE:
+ *      This API is used write an8855 phy registers.
+ * INPUT:
+ *      port_num -- port number, 0~4
+ *      dev_addr -- phy device type
+ *      reg_addr -- phy register offset
+ *      val -- phy register value
+ * OUTPUT:
+ * RETURN:
+ *      0 -- write success
+ *      -1 -- write failure
+ * NOTES:
+ *      Attention!! Customer should implement mii mutex
+ *      lock in this func or before/after calling this func
+ */
+int
+an8855_phy_write_cl45(u32 port_num, u32 dev_addr, u32 reg_addr, u32 val)
+{
+    u32 phy = 0, data = 0;
+
+    if (port_num >= AN8855_PHY_NUM)
+        return -1;
+
+    phy = g_smi_addr + port_num;
+    data = val & 0x0000FFFF;
+    g_mii_c45_write(phy, dev_addr, reg_addr, data);
+
+    return 0;
+}
+
diff --git a/recipes-devtools/switch/files/src/an8855_sdk/core/an8855_mdio.h b/recipes-devtools/switch/files/src/an8855_sdk/core/an8855_mdio.h
new file mode 100644
index 0000000..c2d4bd7
--- /dev/null
+++ b/recipes-devtools/switch/files/src/an8855_sdk/core/an8855_mdio.h
@@ -0,0 +1,203 @@
+/* FILE NAME:  an8855_mdio.h

+ * PURPOSE:

+ *      It provides AN8855 mdio access API.

+ * NOTES:

+ *

+ */

+

+#ifndef AN8855_MDIO_H

+#define AN8855_MDIO_H

+

+/* INCLUDE FILE DECLARATIONS

+ */

+//#include "CTP_type.h"

+//#include "CTP_shell.h"

+//#include "common.h"

+//#include "eth.h"

+

+/* NAMING CONSTANT DECLARATIONS

+ */

+

+/* MACRO FUNCTION DECLARATIONS

+ */

+/* Attention!! Customer should define udelay function */

+void delayUs(int usecond);

+#define an8855_udelay(us) delayUs(us)

+

+/* Attention!! Customer should define dbg_print to get dbg output */

+#ifndef dbg_print

+#define dbg_print(...)

+#endif

+

+#define AN8855_PHY_NUM                      5

+

+/* DATA TYPE DECLARATIONS

+ */

+#ifndef NULL

+#define NULL 0L

+#endif

+

+#ifndef u32

+#define u32 unsigned int

+#endif

+

+#ifndef u16

+#define u16 unsigned short

+#endif

+

+#ifndef u8

+#define u8 unsigned char

+#endif

+

+typedef u32 (*AIR_MII_READ_FUNC_T) (u32 phy_addr, u32 reg, u32 *p_data);

+

+typedef u32 (*AIR_MII_WRITE_FUNC_T) (u32 phy_addr, u32 reg, u32 data);

+

+typedef u32 (*AIR_MII_C45_READ_FUNC_T) (u32 phy_addr, u32 dev, u32 reg, u32 *p_data);

+

+typedef u32 (*AIR_MII_C45_WRITE_FUNC_T) (u32 phy_addr, u32 dev, u32 reg, u32 data);

+

+extern u32 g_smi_addr;

+

+/* EXPORTED SUBPROGRAM SPECIFICATIONS

+ */

+

+/* FUNCTION NAME:   an8855_set_smi_addr

+ * PURPOSE:

+ *      This API is used to set an8855 smi address.

+ * INPUT:

+ *      smi_addr -- AN8855 smi address

+ * OUTPUT:

+ * RETURN:

+ * NOTES:

+ *      None

+ */

+void

+an8855_set_smi_addr(u32 smi_addr);

+

+/* FUNCTION NAME:   an8855_set_mii_callback

+ * PURPOSE:

+ *      This API is used to set an8855 mii access callbacks.

+ * INPUT:

+ *      mii_read -- mii read api function

+ *      mii_write -- mii write api function

+ * OUTPUT:

+ * RETURN:

+ *      0     -- Successfully set callback.

+ *      -1    -- Setting callback failed.

+ * NOTES:

+ *      None

+ */

+int

+an8855_set_mii_callback(

+    AIR_MII_READ_FUNC_T mii_read, 

+    AIR_MII_WRITE_FUNC_T mii_write,

+    AIR_MII_C45_READ_FUNC_T mii_c45_read, 

+    AIR_MII_C45_WRITE_FUNC_T mii_c45_write);

+

+/* FUNCTION NAME:   an8855_reg_read

+ * PURPOSE:

+ *      This API is used read an8855 registers.

+ * INPUT:

+ *      reg -- register offset

+ * OUTPUT:

+ * RETURN:

+ *      Register value

+ * NOTES:

+ *      Attention!! Customer should implement mdio mutex

+ *      lock in this func

+ */

+u32

+an8855_reg_read(u32 reg);

+

+/* FUNCTION NAME:   an8855_reg_write

+ * PURPOSE:

+ *      This API is used write an8855 registers.

+ * INPUT:

+ *      reg -- register offset

+ *      val -- register value

+ * OUTPUT:

+ * RETURN:

+ * NOTES:

+ *      Attention!! Customer should implement mdio mutex

+ *      lock in this func

+ */

+void

+an8855_reg_write(u32 reg, u32 val);

+

+/* FUNCTION NAME:   an8855_phy_read

+ * PURPOSE:

+ *      This API is used read an8855 phy registers.

+ * INPUT:

+ *      port_num -- port number, 0~4

+ *      reg -- phy register offset

+ * OUTPUT:

+ *      p_val -- phy register value

+ * RETURN:

+ *      0 -- read success

+ *      -1 -- read failure

+ * NOTES:

+ *      Attention!! Customer should implement mii mutex

+ *      lock in this func

+ */

+int

+an8855_phy_read(u32 port_num, u32 reg, u32 *p_val);

+

+/* FUNCTION NAME:   an8855_phy_write

+ * PURPOSE:

+ *      This API is used write an8855 phy registers.

+ * INPUT:

+ *      port_num -- port number, 0~4

+ *      reg -- phy register offset

+ *      val -- phy register value

+ * OUTPUT:

+ * RETURN:

+ *      0 -- write success

+ *      -1 -- write failure

+ * NOTES:

+ *      Attention!! Customer should implement mii mutex

+ *      lock in this func

+ */

+int

+an8855_phy_write(u32 port_num, u32 reg, u32 val);

+

+/* FUNCTION NAME:   an8855_phy_read_cl45

+ * PURPOSE:

+ *      This API is used read an8855 phy registers.

+ * INPUT:

+ *      port_num -- port number, 0~4

+ *      dev_addr -- phy device type

+ *      reg_addr -- phy register offset

+ * OUTPUT:

+ *      p_val -- phy register value

+ * RETURN:

+ *      0 -- read success

+ *      -1 -- read failure

+ * NOTES:

+ *      Attention!! Customer should implement mii mutex

+ *      lock in this func or before/after calling this func

+ */

+u32

+an8855_phy_read_cl45(u32 port_num, u32 dev_addr, u32 reg_addr, u32 *p_val);

+

+/* FUNCTION NAME:   an8855_phy_write_cl45

+ * PURPOSE:

+ *      This API is used write an8855 phy registers.

+ * INPUT:

+ *      port_num -- port number, 0~4

+ *      dev_addr -- phy device type

+ *      reg_addr -- phy register offset

+ *      val -- phy register value

+ * OUTPUT:

+ * RETURN:

+ *      0 -- write success

+ *      -1 -- write failure

+ * NOTES:

+ *      Attention!! Customer should implement mii mutex

+ *      lock in this func or before/after calling this func

+ */

+int

+an8855_phy_write_cl45(u32 port_num, u32 dev_addr, u32 reg_addr, u32 val);

+

+#endif  /* End of AN8855_MDIO_H */

+

diff --git a/recipes-devtools/switch/files/src/an8855_sdk/core/an8855_phy.h b/recipes-devtools/switch/files/src/an8855_sdk/core/an8855_phy.h
new file mode 100644
index 0000000..3c810e7
--- /dev/null
+++ b/recipes-devtools/switch/files/src/an8855_sdk/core/an8855_phy.h
@@ -0,0 +1,409 @@
+/* FILE NAME:  an8855_phy.h

+ * PURPOSE:

+ *      It provides AN8855 phy definition.

+ * NOTES:

+ *

+ */

+

+#ifndef _AN8855_PHY_H_

+#define _AN8855_PHY_H_

+

+

+/* Type Definitions */

+#define int8_t char

+#define uint8_t unsigned char

+#define int16_t short

+#define uint16_t unsigned short

+#define int32_t int

+#define uint32_t unsigned int

+/* DATA TYPE DECLARATIONS

+ */

+typedef int                 BOOL_T;

+typedef signed char         I8_T;

+typedef unsigned char       UI8_T;

+typedef signed short        I16_T;

+typedef unsigned short      UI16_T;

+typedef signed int          I32_T;

+typedef unsigned int        UI32_T;

+typedef char                C8_T;

+typedef unsigned long long  UI64_T;

+

+typedef UI8_T   AIR_MAC_T[6];

+

+/* Debug flags */

+//#define _MDIO_BOOTS_MODE     1 // Boots for preamble

+#define _DEBUG_PRINT         1 // Debug print for Arduino

+//#define _DEBUG_PRINT_eFuse     1

+#define _write_eFuse     1

+

+#define _DEBUG_SCAN_ALL      0 // Scan all Code for SerDes Calibration

+#define _WRITE_RG_DIR        1 // Write RG directly for Calibration

+#define _USER_DEFINE_MODE    0 // Replace to user-defined RG for Calibration

+#define _DEBUG_MANUAL        1 // dbg_20210604  // manual dbg_20210604

+/**************************************************************************/

+

+/* Phy Address */

+//#define phyadd_common 0x1d            // EN8801

+//#define PHY_NUM 1             // EN8801

+//#define phyadd_common 0x9         // EN7523

+//#define PHY_NUM 4             // EN7523

+//#define phyadd_common 0x0         // EN8850

+//#define PHY_NUM   5           // EN8850

+#define PHY_NUM   4             // EN8851

+#define CALIPOLARITY  1

+

+#define TXAMP_offset  0    // for 8851

+

+/* On/Off */

+//#define ENABLE  1

+//#define DISABLE 0

+#define Relay_ENABLE  1

+#define Relay_DISABLE 0

+

+/* FT Pattern */

+#define _MDIO     0x0

+#define _I2C      0x1

+#define FT_USB3_T101    0x0

+#define FT_PCIE0_T101   0x1

+#define FT_PCIE1_T101   0x2

+#define FT_PON_T101     0x3

+

+/********* Digital pin definition *************/

+#define Relay_Tx_PN         22   // relay 1

+#define Relay_R_R50         23   // relay 2

+#define Relay_Tx_Vol        24   // relay 3

+#define Relay_Rx_Vol        25   // relay 4

+#define Relay_DUT_GND       26   // relay 5

+#define Relay_I2C           27   // PIN for SCL&SDA , relay 6

+//#define Relay_I2C_SCL       27   // PIN for SCL&SDA , relay 6

+//#define Relay_I2C_SDA       28   // PIN for SCL&SDA , relay 6

+

+#define pin_MDIO           36   // PIN for MDIO

+#define pin_MDC            37   // PIN for MDC

+#define FT_PATTERN_bit0    49   // PIN for FT0

+#define FT_PATTERN_bit1    48   // PIN for FT1

+#define Relay_MDIO         35   // PIN for MDIO relay, relay 7

+

+/***********************************************/

+/* Use for I/O register PORTA control */

+#define POR_Relay_Tx_PN    D22   // use for PORTA control, relay 1

+#define POR_Relay_R_R50    D23   // use for PORTA control, relay 2

+#define POR_Relay_Tx_Vol   D24   // use for PORTA control, relay 3

+#define POR_Relay_Rx_Vol   D25   // use for PORTA control, relay 4

+#define POR_Relay_DUT_GND  D26   // use for PORTA control, relay 5

+//#define POR_Relay_I2C      D27   // use for PORTA control, relay 6

+#define POR_Relay_I2C_SCL  D27   // use for PORTA control, relay 6

+#define POR_Relay_I2C_SDA  D28   // use for PORTA control, relay 7

+

+/* Use for I/O register PORTC control */

+#define POR_MDIO               D36  // use for PORTC control

+#define POR_MDC                D37  // use for PORTC control

+#define POR_Relay_MDIO         D35  // use for PORTC control, relay 7

+

+/* Use for I/O register PORTL control */

+#define POR_FT_PATTERN_bit0    D49  // use for PORTL control

+#define POR_FT_PATTERN_bit1    D48  // use for PORTL control

+

+

+/* I/O register Port A */

+#define D22   0

+#define D23   1

+#define D24   2

+#define D25   3

+#define D26   4

+#define D27   5

+#define D28   6

+#define D29   7

+

+/* I/O register Port C */

+#define D37   0

+#define D36   1

+#define D35   2

+#define D34   3

+#define D33   4

+#define D32   5

+#define D31   6

+#define D30   7

+

+/* I/O register Port L */

+#define D49   0

+#define D48   1

+#define D47   2

+#define D46   3

+#define D45   4

+#define D44   5

+#define D43   6

+#define D42   7

+

+/* I/O register Port D */

+#define D21   0

+#define D20   1

+#define D19   2

+#define D18   3

+

+

+/***************************************************************************

+**************************************************************************

+* MDC/MDIO

+***************************************************************************

+***************************************************************************/

+#define SET_HIGH(data, nbit) ((data)|=(nbit))

+#define SET_LOW(data, nbit) ((data)&=~(nbit))

+

+#define MDIO_ONE  _BV(POR_MDIO)

+#define MDIO_ZERO 0x00

+#define MDC_ONE   _BV(POR_MDC)

+#define MDC_ZERO  0x00

+

+#define delay_us delayMicroseconds(0)

+

+#define ANACAL_INIT        0x01

+#define ANACAL_ERROR       0xFD

+#define ANACAL_SATURATION  0xFE

+#define ANACAL_FINISH      0xFF

+#define ANACAL_PAIR_A      0

+#define ANACAL_PAIR_B      1

+#define ANACAL_PAIR_C      2

+#define ANACAL_PAIR_D      3

+#define DAC_IN_0V          0x000

+#define DAC_IN_2V          0x0f0  // +/-1V

+

+#define ZCAL_MIDDLE        0x20

+#define TX_OFFSET_0mV_idx  31

+#define TX_AMP_MIDDLE      0x20

+

+#define TX_i2mpb_hbt_ofs  0x4   // 8851 fine tune 100M v1 (20220414)

+#define R50_OFFSET_VALUE  0x5

+

+//============== definition value for GbE ===================//

+#define BG_VOLTAGE_OUT     0xc0

+#define FORCE_MDI          2

+#define FORCE_MDIX         3

+#define LDO_1p15_VOSEL_1   1

+#define RX_CAL_VALUE_9       0x3

+#define RX_CAL_HVGA_BW_2     0x2

+#define RX_CAL_DCO_Normal    0x0

+#define RX_CAL_DCO_BYPASS_TX_RX  0x3

+#define RX_CAL_DCO_0xF    0xF

+

+#define TANA_MON_DCV_SEL__MASK         0xE0

+#define TANA_MON_DCV_SEL__MPX_TANA_A   0x20

+#define TANA_MON_DCV_SEL__MPX_TANA_B   0x40

+#define TANA_MON_DCV_SEL__MPX_TANA_C   0x60

+#define TANA_MON_DCV_SEL__MPX_TANA_D   0x80

+#define TANA_MON_DCV_SEL__MONVC__MASK  0x008000C8

+#define TANA_MON_DCV__TANA__VBG_MON    0x000000C0

+#define TANA_MON_DCV__TANA__MONVC      0x000000C8

+

+#define AN_disable_force_1000M 0x0140

+#define BG_voltage_output 0xc000

+#define Fix_mdi 0x1010

+#define Disable_tx_slew_control 0x0000

+#define LDO_control 0x0100

+#define Cal_control_BG 0x1110

+#define Cal_control_R50 0x1100

+#define Cal_control_TX_AMP 0x1100

+#define Cal_control_TX_OFST 0x0100

+#define Cal_control_R50_pairA_ENABLE 0x1101

+#define Disable_all 0x0

+#define Zcalen_A_ENABLE 0x0000

+#define Zcalen_B_ENABLE 0x1000

+#define Zcalen_C_ENABLE 0x0100

+#define Zcalen_D_ENABLE 0x0010

+#define MASK_MSB_8bit 0xff00

+#define MASK_LSB_8bit 0x00ff

+#define MASK_r50ohm_rsel_tx_a 0x7f00

+#define MASK_r50ohm_rsel_tx_b 0x007f

+#define MASK_r50ohm_rsel_tx_c 0x7f00

+#define MASK_r50ohm_rsel_tx_d 0x007f

+#define Rg_r50ohm_rsel_tx_a_en 0x8000

+#define Rg_r50ohm_rsel_tx_b_en 0x0080

+#define Rg_r50ohm_rsel_tx_c_en 0x8000

+#define Rg_r50ohm_rsel_tx_d_en 0x0080

+#define Rg_txvos_calen_ENABLE 0x0001

+#define Bypass_tx_offset_cal 0x8000

+#define Enable_Tx_VLD 0xf808

+#define Rg_txg_calen_a_ENABLE 0x1000

+#define Rg_txg_calen_b_ENABLE 0x0100

+#define Rg_txg_calen_c_ENABLE 0x0010

+#define Rg_txg_calen_d_ENABLE 0x0001

+#define Force_dasn_dac_in0_ENABLE 0x8000

+#define Force_dasn_dac_in1_ENABLE 0x8000

+#define MASK_cr_tx_amp_offset_MSB 0x3f00

+#define MASK_cr_tx_amp_offset_LSB 0x003f

+#define Rg_cal_refsel_ENABLE 0x0010

+#define MASK_da_tx_i2mpb_a_gbe 0xfc00

+#define MASK_da_tx_i2mpb_b_c_d_gbe 0x3f00

+

+#define LED_basic_control_en_active_low 0x800a

+#define LED_led0_en_active_high 0xc007

+#define LED_led0_force_blinking 0x0200

+

+

+

+/*phy calibration use*/

+//Type defines

+typedef unsigned char    UINT8;

+typedef unsigned short   UINT16;

+typedef unsigned long    UINT32;

+

+typedef struct

+{

+  UINT16 DATA_Lo;

+  UINT8  DATA_Hi;

+}TR_DATA_T;

+

+//CL22 Reg Support Page Select//

+#define RgAddr_Reg1Fh        0x1f

+#define CL22_Page_Reg        0x0000

+#define CL22_Page_ExtReg     0x0001

+#define CL22_Page_MiscReg    0x0002

+#define CL22_Page_LpiReg     0x0003

+#define CL22_Page_tReg       0x02A3

+#define CL22_Page_TrReg      0x52B5

+

+//CL45 Reg Support DEVID//

+#define DEVID_03             0x03

+#define DEVID_07             0x07

+#define DEVID_1E             0x1E

+#define DEVID_1F             0x1F

+

+//TokenRing Reg Access//

+#define TrReg_PKT_XMT_STA    0x8000

+#define TrReg_WR             0x8000

+#define TrReg_RD             0xA000

+

+/* ----------------- gephy_all Bit Field Definitions ------------------- */

+

+

+

+//-------------------------------------

+//0x0000

+#define RgAddr_Reg00h                               0x00

+

+//0x51e01200

+#define RgAddr_dev1Eh_reg120h                       0x0120

+//0x51e01220

+#define RgAddr_dev1Eh_reg122h                       0x0122

+//0x51e01440

+#define RgAddr_dev1Eh_reg144h                       0x0144

+//0x51e014a0

+#define RgAddr_dev1Eh_reg14Ah                       0x014a

+//0x51e019b0

+#define RgAddr_dev1Eh_reg19Bh                       0x019b

+//0x51e02340

+#define RgAddr_dev1Eh_reg234h                       0x0234

+//0x51e02380

+#define RgAddr_dev1Eh_reg238h                       0x0238

+//0x51e02390

+#define RgAddr_dev1Eh_reg239h                       0x0239

+//0x51f02680

+#define RgAddr_dev1Fh_reg268h                       0x0268

+//0x51e02d10

+#define RgAddr_dev1Eh_reg2D1h                       0x02d1

+//0x51e03230

+#define RgAddr_dev1Eh_reg323h                       0x0323

+//0x51e03240

+#define RgAddr_dev1Eh_reg324h                       0x0324

+//0x51e03260

+#define RgAddr_dev1Eh_reg326h                       0x0326

+

+//0x51f01000

+#define RgAddr_dev1Fh_reg100h                       0x0100

+//0x51e01450

+#define RgAddr_dev1Eh_reg145h                       0x0145

+//0x51f00ff0

+#define RgAddr_dev1Fh_reg0FFh                       0x00ff

+//0x51e00db0

+#define RgAddr_dev1Eh_reg0DBh                       0x00db

+//0x51e00dc0

+#define RgAddr_dev1Eh_reg0DCh                       0x00dc

+//0x51e00e00

+#define RgAddr_dev1Eh_reg0E0h                       0x00e0

+//0x51e00e10

+#define RgAddr_dev1Eh_reg0E1h                       0x00e1

+//0x51e00e00

+#define RgAddr_dev1Eh_reg0E0h                       0x00e0

+//0x51e017a0

+#define RgAddr_dev1Eh_reg17Ah                       0x017a

+//0x51f01150

+#define RgAddr_dev1Fh_reg115h                       0x0115

+//0x51f01000

+#define RgAddr_dev1Fh_reg100h                       0x0100

+//0x51e01450

+#define RgAddr_dev1Eh_reg145h                       0x0145

+//0x51e01450

+#define RgAddr_dev1Eh_reg145h                       0x0145

+//0x51e01850

+#define RgAddr_dev1Eh_reg185h                       0x0185

+//0x51e00fb0

+#define RgAddr_dev1Eh_reg0FBh                       0x00fb

+//0x51e01740

+#define RgAddr_dev1Eh_reg174h                       0x0174

+//0x51e01750

+#define RgAddr_dev1Eh_reg175h                       0x0175

+//0x51e01850

+#define RgAddr_dev1Eh_reg185h                       0x0185

+//0x51e00fb0

+#define RgAddr_dev1Eh_reg0FBh                       0x00fb

+//0x51e00960

+#define RgAddr_dev1Eh_reg096h                       0x0096

+//0x51e003e0

+#define RgAddr_dev1Eh_reg03Eh                       0x003e

+//0x51e00dd0

+#define RgAddr_dev1Eh_reg0DDh                       0x00dd

+//0x51e017d0

+#define RgAddr_dev1Eh_reg17Dh                       0x017d

+//0x51e01810

+#define RgAddr_dev1Eh_reg181h                       0x0181

+//0x51e00120

+#define RgAddr_dev1Eh_reg012h                       0x0012

+//0x51e017e0

+#define RgAddr_dev1Eh_reg17Eh                       0x017e

+//0x51e01820

+#define RgAddr_dev1Eh_reg182h                       0x0182

+//0x51e00170

+#define RgAddr_dev1Eh_reg017h                       0x0017

+//0x51e01830

+#define RgAddr_dev1Eh_reg183h                       0x0183

+//0x51e00190

+#define RgAddr_dev1Eh_reg019h                       0x0019

+//0x51e01800

+#define RgAddr_dev1Eh_reg180h                       0x0180

+//0x51e01840

+#define RgAddr_dev1Eh_reg184h                       0x0184

+//0x51e00210

+#define RgAddr_dev1Eh_reg021h                       0x0021

+//0x51e01720

+#define RgAddr_dev1Eh_reg172h                       0x0172

+//0x51e01730

+#define RgAddr_dev1Eh_reg173h                       0x0173

+//0x51e017c0

+#define RgAddr_dev1Eh_reg17Ch                       0x017c

+//0x51e017f0

+#define RgAddr_dev1Eh_reg17Fh                       0x017f

+

+//0x52b5100

+#define RgAddr_TrReg10h                             0x10

+//0x52b5110

+#define RgAddr_TrReg11h                             0x11

+//0x52b5120

+#define RgAddr_TrReg12h                             0x12

+

+//0x31c0

+#define RgAddr_LpiReg1Ch                            0x1c

+//0x31d0

+#define RgAddr_LpiReg1Dh                            0x1d

+uint8_t BG_Calibration(uint8_t phyadd, int8_t calipolarity);

+uint8_t R50_Calibration(uint8_t phyadd, uint8_t phyadd_common);

+uint8_t TX_OFS_Calibration(uint8_t phyadd, uint8_t phyadd_common);

+uint8_t TX_AMP_Calibration(uint8_t phyadd, uint8_t phyadd_common);

+//void config_gphy_port(UINT8, UINT8);

+

+void set_gphy_reg_cl22(uint8_t, uint8_t, uint16_t);

+uint16_t get_gphy_reg_cl45(uint8_t, uint8_t, uint16_t);

+void set_gphy_reg_cl45(uint8_t, uint8_t, uint16_t, uint16_t);

+void anacal_exe(uint8_t);

+

+#endif /* _AN8855_PHY_H_ */

+

diff --git a/recipes-devtools/switch/files/src/an8855_sdk/core/an8855_phy_cal.c b/recipes-devtools/switch/files/src/an8855_sdk/core/an8855_phy_cal.c
new file mode 100644
index 0000000..c2e8e5c
--- /dev/null
+++ b/recipes-devtools/switch/files/src/an8855_sdk/core/an8855_phy_cal.c
@@ -0,0 +1,967 @@
+/* FILE NAME:  an8855_phy_cal.c

+* PURPOSE:

+*    It provides an8855 switch phy calibration function.

+*

+* NOTES:

+*

+*/

+

+/* INCLUDE FILE DECLARATIONS

+*/

+#include "an8855_mdio.h"

+#include "an8855_phy.h"

+//#include "swk_gphy_reg.h"

+//#include "gphy_calibration.h"

+//#include "gsw_reg.h"

+

+/* NAMING CONSTANT DECLARATIONS

+ */

+#define MII_BMCR                (0)

+#define BMCR_PDOWN              (0x0800)

+/* MACRO FUNCTION DECLARATIONS

+ */

+

+#define FULL_BITS(_n_) ((1UL << (_n_)) - 1)

+

+/* DATA TYPE DECLARATIONS

+ */

+

+/* GLOBAL VARIABLE DECLARATIONS

+ */

+/* Zcal to R50 mapping table (20220404) */

+const uint8_t ZCAL_TO_R50ohm_TBL[64] =

+{

+    127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127,

+    127, 127, 127, 127, 127, 123, 118, 114, 110, 106, 102, 98, 96, 92, 88, 85,

+    82, 80, 76, 72, 70, 67, 64, 62, 60, 56, 54, 52, 49, 48, 45, 43,

+    40, 39, 36, 34, 32, 32, 30, 28, 25, 24, 22, 20, 18, 16, 16, 14

+};

+

+/* Tx offset table, value is from small to big */

+const uint8_t  EN753x_TX_OFS_TBL[64] =

+{

+    0x3f, 0x3e, 0x3d, 0x3c, 0x3b, 0x3a, 0x39, 0x38, 0x37, 0x36, 0x35, 0x34, 0x33, 0x32, 0x31, 0x30,

+    0x2f, 0x2e, 0x2d, 0x2c, 0x2b, 0x2a, 0x29, 0x28, 0x27, 0x26, 0x25, 0x24, 0x23, 0x22, 0x21, 0x20,

+    0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,

+    0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f

+};

+

+#define TOTAL_PATCH_C45_ITEMS   (15)

+#define TOTAL_PATCH_TR_ITEMS    (19)

+const uint16_t C45_PATCH_TABLE[TOTAL_PATCH_C45_ITEMS][3] =

+{

+    {0x1E, 0x120, 0x8014},

+    {0x1E, 0x122, 0xFFFF},

+    {0x1E, 0x122, 0xFFFF},

+    {0x1E, 0x144, 0x0200},

+    {0x1E, 0x14A, 0xEE20},

+    {0x1E, 0x189, 0x0110},

+    {0x1E, 0x19B, 0x0111},

+    {0x1E, 0x234, 0x0181},

+    {0x1E, 0x238, 0x0120},

+    {0x1E, 0x239, 0x0117},

+    {0x1F, 0x268, 0x07F4},

+    {0x1E, 0x2d1, 0x0733},

+    {0x1E, 0x323, 0x0011},

+    {0x1E, 0x324, 0x013F},

+    {0x1E, 0x326, 0x0037},

+};

+

+const uint32_t TR_PATCH_TABLE[TOTAL_PATCH_TR_ITEMS][2] =

+{

+    {0x83AA, 0x055a0 },

+    {0x83AE, 0x7FF3F },

+    {0x8F80, 0x0001e },

+    {0x8F82, 0x6FB90A},

+    {0x8FAE, 0x060671},

+    {0x8FB0, 0xE2F00 },

+    {0x8ECC, 0x444444},

+    {0x9686, 0x00000 },

+    {0x968C, 0x2EBAEF},

+    {0x9690, 0x00000b},

+    {0x9698, 0x0504D },

+    {0x969A, 0x2314f },

+    {0x969E, 0x03028 },

+    {0x96A0, 0x05010 },

+    {0x96A2, 0x40001 },

+    {0x96A6, 0x018670},

+    {0x96A8, 0x0024A },

+    {0x96B6, 0x00072 },

+    {0x96B8, 0x03210 },

+};

+

+#define TOTAL_NUMBER_OF_PATCH    (14)

+static uint16_t eee_patch_table[TOTAL_NUMBER_OF_PATCH][2] = {

+    {RgAddr_dev1Eh_reg120h, 0x8014},

+    {RgAddr_dev1Eh_reg122h, 0xFFFF},

+    {RgAddr_dev1Eh_reg122h, 0xFFFF},

+    {RgAddr_dev1Eh_reg144h, 0x0200},

+    {RgAddr_dev1Eh_reg14Ah, 0xEE20},

+    {RgAddr_dev1Eh_reg19Bh, 0x0111},

+    {RgAddr_dev1Eh_reg234h, 0x1181},

+    {RgAddr_dev1Eh_reg238h, 0x0120},

+    {RgAddr_dev1Eh_reg239h, 0x0117},

+    {RgAddr_dev1Fh_reg268h, 0x07F4},

+    {RgAddr_dev1Eh_reg2D1h, 0x0733},

+    {RgAddr_dev1Eh_reg323h, 0x0011},

+    {RgAddr_dev1Eh_reg324h, 0x013F},

+    {RgAddr_dev1Eh_reg326h, 0x0037}

+};

+

+#define TOTAL_NUMBER_OF_TR      (19)

+static uint16_t tr_reg_table[TOTAL_NUMBER_OF_TR][3] = {

+    {0x55A0, 0x0000, 0x83AA},

+    {0xFF3F, 0x0007, 0x83AE},

+    {0x001E, 0x0000, 0x8F80},

+    {0xB90A, 0x006F, 0x8F82},

+    {0x0671, 0x0006, 0x8FAE},

+    {0x2F00, 0x000E, 0x8FB0},

+    {0x4444, 0x0044, 0x8ECC},

+    {0x0004, 0x0000, 0x9686},

+    {0xBAEF, 0x002E, 0x968C},

+    {0x000B, 0x0000, 0x9690},

+    {0x504D, 0x0000, 0x9698},

+    {0x314F, 0x0002, 0x969A},

+    {0x3028, 0x0000, 0x969E},

+    {0x5010, 0x0000, 0x96A0},

+    {0x0001, 0x0004, 0x96A2},

+    {0x8670, 0x0001, 0x96A6},

+    {0x024A, 0x0000, 0x96A8},

+    {0x0072, 0x0000, 0x96B6},

+    {0x3210, 0x0000, 0x96B8}

+};

+

+void TR_RegWr(uint16_t phyadd, uint16_t tr_reg_addr, uint32_t tr_data);

+

+uint16_t get_gphy_reg_cl22(uint8_t phyad, uint8_t reg)

+{

+    uint32_t rdata = 0;

+

+    an8855_phy_read(phyad-g_smi_addr, reg, &rdata);

+

+    return ((uint16_t)rdata);

+    /*

+    gsw_top_reg_REG_PHY_IAC REG_PHY_IAC_val;

+    gsw_top_reg_REG_PHY_IAD REG_PHY_IAD_val;

+

+    // Wait until done

+    do

+    {

+      REG_PHY_IAC_val.Raw   = io_read32(RgAddr_gsw_top_reg_REG_PHY_IAC);

+    }

+    while(REG_PHY_IAC_val.Bits.csr_phy_acs_st);

+

+    // Set address

+    REG_PHY_IAC_val.Bits.csr_mdio_st = 1;

+    REG_PHY_IAC_val.Bits.csr_mdio_cmd   = 2;

+    REG_PHY_IAC_val.Bits.csr_mdio_phy_addr = phyad;

+    REG_PHY_IAC_val.Bits.csr_mdio_reg_addr = reg;

+    REG_PHY_IAC_val.Bits.csr_phy_acs_st =   1;

+    io_write32(RgAddr_gsw_top_reg_REG_PHY_IAC, REG_PHY_IAC_val.Raw);

+    // Wait until done

+    do

+    {

+        REG_PHY_IAC_val.Raw = io_read32(RgAddr_gsw_top_reg_REG_PHY_IAC);

+    }

+    while(REG_PHY_IAC_val.Bits.csr_phy_acs_st);

+

+    REG_PHY_IAD_val.Raw = io_read32(RgAddr_gsw_top_reg_REG_PHY_IAD);

+

+    return REG_PHY_IAD_val.Raw;

+    */

+}

+

+/* EXPORTED SUBPROGRAM BODIES

+ */

+void gphy_config(void)

+{

+    uint8_t port = 1;

+    uint8_t phy_base = 0, phys_in_chip = 8;

+

+    for (port = 1; port <= phys_in_chip; port++)

+    {

+        set_gphy_reg_cl45(phy_base + port, 0x7, 0x3c, 0x0006); // Enable EEE

+        set_gphy_reg_cl45(phy_base + port, 0x1e, 0x3e, 0xf000); // force on TXVLD

+    }

+}

+

+static void set_gphy_TrReg(uint8_t prtid, uint16_t parm_1, uint16_t parm_2, uint16_t parm_3)

+{

+    set_gphy_reg_cl22(prtid, RgAddr_TrReg11h, parm_1);

+    set_gphy_reg_cl22(prtid, RgAddr_TrReg12h, parm_2);

+    set_gphy_reg_cl22(prtid, RgAddr_TrReg10h, parm_3);

+}

+

+static void gphy_eee_patch(uint8_t phy_base)

+{

+    UI8_T   port = 1, index = 0, phy_addr = 1;

+    UI16_T  data = 0;

+

+    for (port = 1; port <=8; port++)

+    {

+        phy_addr = phy_base + port;

+        data = get_gphy_reg_cl22(phy_addr, MII_BMCR);

+        set_gphy_reg_cl22(phy_addr, MII_BMCR, data & ~(BMCR_PDOWN));    /* PHY power on */

+

+        /* Change EEE RG default value */

+        for (index = 0; index < TOTAL_NUMBER_OF_PATCH; index++)

+        {

+            set_gphy_reg_cl45(phy_addr, DEVID_1E, eee_patch_table[index][0], eee_patch_table[index][1]);

+        }

+

+        set_gphy_reg_cl22(phy_addr, RgAddr_Reg1Fh, CL22_Page_TrReg);   /* change CL22page to LpiReg(0x3) */

+        for (index = 0; index < TOTAL_NUMBER_OF_TR; index++)

+        {

+            set_gphy_TrReg(phy_addr, tr_reg_table[index][0], tr_reg_table[index][1], tr_reg_table[index][2]);

+        }

+

+        set_gphy_reg_cl22(phy_addr, RgAddr_Reg1Fh, CL22_Page_LpiReg);  /* change CL22page to LpiReg(0x3) */

+        set_gphy_reg_cl22(phy_addr, RgAddr_LpiReg1Ch, 0x0c92);         /* Fine turn SigDet for B2B LPI link down issue */

+        set_gphy_reg_cl22(phy_addr, RgAddr_LpiReg1Dh, 0x0001);         /* Enable "lpi_quit_waitafesigdet_en" for LPI link down issue */

+

+        set_gphy_reg_cl22(phy_addr, RgAddr_Reg1Fh, CL22_Page_Reg);     /* change CL22page to Reg(0x0) */

+    }

+}

+

+void gphy_calibration(uint8_t phy_base)

+{

+    uint8_t port = 1, phy_addr = 1 ,phy_group = 1, index = 0;

+    uint8_t phys_in_chip = 5;

+

+    BG_Calibration(phy_base, 0x1);

+    if (phys_in_chip > 4)

+    {

+        BG_Calibration(phy_base + 0x4, 0x1);

+    }

+

+    for (port = 0; port < phys_in_chip; port++)

+    {

+        if (port < 4)

+        {

+            phy_group = phy_base;     /* PHY group 1 */

+        }

+        else

+        {

+            phy_group = phy_base + 0x04;     /* PHY group 2 */

+        }

+        phy_addr = phy_base + port;

+        R50_Calibration(phy_addr, phy_group);

+        TX_OFS_Calibration(phy_addr, phy_group);

+        TX_AMP_Calibration(phy_addr, phy_group);

+    }

+

+    for (port = 0; port < phys_in_chip; port++)

+    {

+        phy_addr = phy_base + port;

+        set_gphy_reg_cl45(phy_addr, 0x1e, 0x017d, 0x0000);

+        set_gphy_reg_cl45(phy_addr, 0x1e, 0x017e, 0x0000);

+        set_gphy_reg_cl45(phy_addr, 0x1e, 0x017f, 0x0000);

+        set_gphy_reg_cl45(phy_addr, 0x1e, 0x0180, 0x0000);

+        set_gphy_reg_cl45(phy_addr, 0x1e, 0x0181, 0x0000);

+        set_gphy_reg_cl45(phy_addr, 0x1e, 0x0182, 0x0000);

+        set_gphy_reg_cl45(phy_addr, 0x1e, 0x0183, 0x0000);

+        set_gphy_reg_cl45(phy_addr, 0x1e, 0x0184, 0x0000);

+        set_gphy_reg_cl45(phy_addr, 0x1e, 0x00db, 0x0000);  // disable analog calibration circuit

+        set_gphy_reg_cl45(phy_addr, 0x1e, 0x00dc, 0x0000);  // disable Tx offset calibration circuit

+        set_gphy_reg_cl45(phy_addr, 0x1e, 0x003e, 0x0000);  // disable Tx VLD force mode

+        set_gphy_reg_cl45(phy_addr, 0x1e, 0x00dd, 0x0000);  // disable Tx offset/amplitude calibration circuit

+        set_gphy_reg_cl45(phy_addr, 0x1e, 0x0145, 0x1000);  // enable auto MDI/MDIX

+

+        set_gphy_reg_cl22(phy_addr, 0, 0x1200);

+        /* GPHY Rx low pass filter */

+        set_gphy_reg_cl45(phy_addr, 0x1e, 0xc7, 0xd000);

+        /* patch */

+        for (index = 0; index < TOTAL_PATCH_C45_ITEMS; index++)

+        {

+            set_gphy_reg_cl45(phy_addr, C45_PATCH_TABLE[index][0], C45_PATCH_TABLE[index][1], C45_PATCH_TABLE[index][2]);

+        }

+        for (index = 0; index < TOTAL_PATCH_TR_ITEMS; index++)

+        {

+            TR_RegWr(phy_addr, TR_PATCH_TABLE[index][0], TR_PATCH_TABLE[index][1]);

+        }

+        set_gphy_reg_cl22(phy_addr, 0x1f, 0x0  );

+        set_gphy_reg_cl22(phy_addr, 0x1f, 0x3  );

+        set_gphy_reg_cl22(phy_addr, 0x1c, 0xc92);

+        set_gphy_reg_cl22(phy_addr, 0x1d, 0x01 );

+        set_gphy_reg_cl22(phy_addr, 0x1f, 0x0  );

+    }

+    gphy_eee_patch(phy_base);

+}

+

+/* LOCAL SUBPROGRAM BODIES

+ */

+void TR_RegWr(uint16_t phyadd, uint16_t tr_reg_addr, uint32_t tr_data)

+{

+    set_gphy_reg_cl22(phyadd, 0x1F, 0x52b5);       /* page select */

+    set_gphy_reg_cl22(phyadd, 0x11, (uint16_t)(tr_data & 0xffff));

+    set_gphy_reg_cl22(phyadd, 0x12, (uint16_t)(tr_data >> 16));

+    set_gphy_reg_cl22(phyadd, 0x10, (uint16_t)(tr_reg_addr | TrReg_WR));

+    set_gphy_reg_cl22(phyadd, 0x1F, 0x0);          /* page resetore */

+    return;

+}

+

+uint8_t BG_Calibration(uint8_t phyadd, int8_t calipolarity)

+{

+    int8_t rg_zcal_ctrl = 0, calibration_polarity = 0;

+    uint8_t all_ana_cal_status = 1;

+    uint16_t ad_cal_comp_out_init = 0;

+

+    /* setting */

+    set_gphy_reg_cl22(phyadd, RgAddr_Reg1Fh, CL22_Page_Reg);        // g0

+    set_gphy_reg_cl22(phyadd, RgAddr_Reg00h, AN_disable_force_1000M);  // AN disable, force 1000M

+    set_gphy_reg_cl45(phyadd, DEVID_1F, RgAddr_dev1Fh_reg100h, BG_voltage_output);// BG voltage output

+    set_gphy_reg_cl45(phyadd, DEVID_1E, RgAddr_dev1Eh_reg145h, Fix_mdi);// fix mdi

+    set_gphy_reg_cl45(phyadd, DEVID_1E, RgAddr_dev1Fh_reg0FFh, 0x2);

+    set_gphy_reg_cl45(phyadd, DEVID_1E, RgAddr_dev1Eh_reg0DBh, Cal_control_BG);// 1e_db[12]:rg_cal_ckinv, [8]:rg_ana_calen, [4]:rg_rext_calen

+    set_gphy_reg_cl45(phyadd, DEVID_1E, RgAddr_dev1Eh_reg0DCh, Disable_all);// 1e_dc[0]:rg_txvos_calen

+    set_gphy_reg_cl45(phyadd, DEVID_1E, RgAddr_dev1Eh_reg0E1h, Disable_all);// 1e_e1[4]:rg_cal_refsel(0:1.2V) enable BG 1.2V to REXT PAD

+

+    /* calibrate */

+    rg_zcal_ctrl = ZCAL_MIDDLE;

+

+    set_gphy_reg_cl45(phyadd, DEVID_1E, RgAddr_dev1Eh_reg0E0h, (uint16_t)rg_zcal_ctrl);

+

+    anacal_exe(phyadd);

+    if (all_ana_cal_status == 0)

+    {

+        all_ana_cal_status = ANACAL_ERROR;

+    }

+    ad_cal_comp_out_init = (get_gphy_reg_cl45(phyadd, DEVID_1E, RgAddr_dev1Eh_reg17Ah) >> 8) & 0x1;

+

+

+    if (ad_cal_comp_out_init == 1)

+    {

+        calibration_polarity = -calipolarity;

+    }

+    else // ad_cal_comp_out_init == 0

+    {

+        calibration_polarity = calipolarity;

+    }

+

+    while (all_ana_cal_status < ANACAL_ERROR)

+    {

+        rg_zcal_ctrl += calibration_polarity;

+

+        set_gphy_reg_cl45(phyadd, DEVID_1E, RgAddr_dev1Eh_reg0E0h, (uint16_t)rg_zcal_ctrl);

+

+

+        anacal_exe(phyadd);

+

+        if (all_ana_cal_status == 0)

+        {

+            all_ana_cal_status = ANACAL_ERROR;

+        }

+

+        else if (((get_gphy_reg_cl45(phyadd, DEVID_1E, RgAddr_dev1Eh_reg17Ah) >> 8) & 0x1) != ad_cal_comp_out_init)

+        {

+            all_ana_cal_status = ANACAL_FINISH;

+        }

+        else

+        {

+            if ((rg_zcal_ctrl == 0x3F) || (rg_zcal_ctrl == 0x00))

+            {

+                all_ana_cal_status = ANACAL_SATURATION;  // need to FT

+                rg_zcal_ctrl = ZCAL_MIDDLE;  // 0 dB

+            }

+        }

+    }

+

+    if (all_ana_cal_status == ANACAL_ERROR)

+    {

+        rg_zcal_ctrl = ZCAL_MIDDLE;  // 0 dB

+

+        set_gphy_reg_cl45(phyadd, DEVID_1E, RgAddr_dev1Eh_reg0E0h, (uint16_t)rg_zcal_ctrl);

+    }

+    else

+    {

+        // rg_zcal_ctrl[5:0] rg_rext_trim[13:8]

+        set_gphy_reg_cl45(phyadd, DEVID_1E, RgAddr_dev1Eh_reg0E0h, (uint16_t)((rg_zcal_ctrl << 8) | rg_zcal_ctrl));

+

+        // 1f_115[2:0](rg_bg_rasel) = rg_zcal_ctrl[5:3]

+        set_gphy_reg_cl45(phyadd, DEVID_1F, RgAddr_dev1Fh_reg115h, (uint16_t)((rg_zcal_ctrl & 0x3f) >> 3));

+    }

+

+    set_gphy_reg_cl45(phyadd, DEVID_1E, RgAddr_dev1Eh_reg0DBh, Disable_all);

+    return all_ana_cal_status;

+}

+

+uint8_t R50_Calibration(uint8_t phyadd, uint8_t phyadd_common)

+{

+    int8_t rg_zcal_ctrl = 0, rg_r50ohm_rsel_tx = 0, calibration_polarity = 0;

+    uint8_t all_ana_cal_status = 1;

+    int16_t backup_dev1e_e0 = 0, ad_cal_comp_out_init = 0, calibration_pair = 0;

+

+    /* setting */

+    set_gphy_reg_cl22(phyadd, RgAddr_Reg1Fh, CL22_Page_Reg);        // g0

+    set_gphy_reg_cl22(phyadd, RgAddr_Reg00h, AN_disable_force_1000M);  // AN disable, force 1000M

+

+    set_gphy_reg_cl45(phyadd_common, DEVID_1F, RgAddr_dev1Fh_reg100h, BG_voltage_output); // BG voltage output

+    set_gphy_reg_cl45(phyadd, DEVID_1E, RgAddr_dev1Eh_reg145h, Fix_mdi); // fix mdi

+    set_gphy_reg_cl45(phyadd, DEVID_1E, RgAddr_dev1Eh_reg185h, Disable_tx_slew_control); // disable tx slew control

+    set_gphy_reg_cl45(phyadd, DEVID_1E, RgAddr_dev1Eh_reg0FBh, LDO_control); // ldo

+    set_gphy_reg_cl45(phyadd_common, DEVID_1E, RgAddr_dev1Eh_reg0DBh, Cal_control_R50); // 1e_db[12]:rg_cal_ckinv, [8]:rg_ana_calen, [4]:rg_rext_calen

+    set_gphy_reg_cl45(phyadd_common, DEVID_1E, RgAddr_dev1Eh_reg0DCh, Disable_all); // 1e_dc[0]:rg_txvos_calen

+    set_gphy_reg_cl45(phyadd_common, DEVID_1E, RgAddr_dev1Eh_reg0E1h, Disable_all); // 1e_e1[4]:rg_cal_refsel(0:1.2V) enable BG 1.2V to REXT PAD

+

+    for (calibration_pair = ANACAL_PAIR_A; calibration_pair <= ANACAL_PAIR_D; calibration_pair++)

+    {

+        all_ana_cal_status = 1;

+

+        if (calibration_pair == ANACAL_PAIR_A)

+        {

+            set_gphy_reg_cl45(phyadd, DEVID_1E, RgAddr_dev1Eh_reg0DBh, Cal_control_R50_pairA_ENABLE); // 1e_db[12]:rg_cal_ckinv, [8]:rg_ana_calen, [4]:rg_rext_calen, [0]:rg_zcalen_a

+            set_gphy_reg_cl45(phyadd, DEVID_1E, RgAddr_dev1Eh_reg0DCh, Zcalen_A_ENABLE);

+        }

+        else if (calibration_pair == ANACAL_PAIR_B)

+        {

+            set_gphy_reg_cl45(phyadd, DEVID_1E, RgAddr_dev1Eh_reg0DBh, Cal_control_R50); // 1e_db[12]:rg_cal_ckinv, [8]:rg_ana_calen, [4]:rg_rext_calen, [0]:rg_zcalen_a

+            set_gphy_reg_cl45(phyadd, DEVID_1E, RgAddr_dev1Eh_reg0DCh, Zcalen_B_ENABLE); // 1e_dc[12]:rg_zcalen_b

+        }

+        else if (calibration_pair == ANACAL_PAIR_C)

+        {

+            set_gphy_reg_cl45(phyadd, DEVID_1E, RgAddr_dev1Eh_reg0DBh, Cal_control_R50); // 1e_db[12]:rg_cal_ckinv, [8]:rg_ana_calen, [4]:rg_rext_calen, [0]:rg_zcalen_a

+            set_gphy_reg_cl45(phyadd, DEVID_1E, RgAddr_dev1Eh_reg0DCh, Zcalen_C_ENABLE); // 1e_dc[8]:rg_zcalen_c

+        }

+        else // if(calibration_pair == ANACAL_PAIR_D)

+        {

+            set_gphy_reg_cl45(phyadd, DEVID_1E, RgAddr_dev1Eh_reg0DBh, Cal_control_R50); // 1e_db[12]:rg_cal_ckinv, [8]:rg_ana_calen, [4]:rg_rext_calen, [0]:rg_zcalen_a

+            set_gphy_reg_cl45(phyadd, DEVID_1E, RgAddr_dev1Eh_reg0DCh, Zcalen_D_ENABLE); // 1e_dc[4]:rg_zcalen_d

+        }

+

+        /* calibrate */

+        rg_zcal_ctrl = ZCAL_MIDDLE;             // start with 0 dB

+

+        backup_dev1e_e0 = (get_gphy_reg_cl45(phyadd_common, DEVID_1E, RgAddr_dev1Eh_reg0E0h)&(~0x003f));

+        set_gphy_reg_cl45(phyadd_common, DEVID_1E, RgAddr_dev1Eh_reg0E0h, (backup_dev1e_e0 | rg_zcal_ctrl));

+

+        anacal_exe(phyadd_common);

+        if (all_ana_cal_status == 0)

+        {

+            all_ana_cal_status = ANACAL_ERROR;

+        }

+

+        ad_cal_comp_out_init = (get_gphy_reg_cl45(phyadd_common, DEVID_1E, RgAddr_dev1Eh_reg17Ah) >> 8) & 0x1;  // 1e_17a[8]:ad_cal_comp_out

+

+        if (ad_cal_comp_out_init == 1)

+        {

+            calibration_polarity = -1;

+        }

+        else

+        {

+            calibration_polarity = 1;

+        }

+

+        while (all_ana_cal_status < ANACAL_ERROR)

+        {

+            rg_zcal_ctrl += calibration_polarity;

+

+            set_gphy_reg_cl45(phyadd_common, DEVID_1E, RgAddr_dev1Eh_reg0E0h, (backup_dev1e_e0 | rg_zcal_ctrl));

+

+            anacal_exe(phyadd_common);

+

+            if (all_ana_cal_status == 0)

+            {

+                all_ana_cal_status = ANACAL_ERROR;

+            }

+            else if (((get_gphy_reg_cl45(phyadd_common, DEVID_1E, RgAddr_dev1Eh_reg17Ah) >> 8) & 0x1) != ad_cal_comp_out_init)

+            {

+                all_ana_cal_status = ANACAL_FINISH;

+            }

+            else

+            {

+                if ((rg_zcal_ctrl == 0x3F) || (rg_zcal_ctrl == 0x00))

+                {

+                    all_ana_cal_status = ANACAL_SATURATION;  // need to FT

+                    rg_zcal_ctrl = ZCAL_MIDDLE;  // 0 dB

+                }

+            }

+        }

+

+        if (all_ana_cal_status == ANACAL_ERROR)

+        {

+            rg_r50ohm_rsel_tx = ZCAL_MIDDLE;  // 0 dB

+        }

+        else

+        {

+            if (rg_zcal_ctrl > (0x3F - R50_OFFSET_VALUE))

+            {

+                all_ana_cal_status = ANACAL_SATURATION;  // need to FT

+                rg_zcal_ctrl = ZCAL_MIDDLE;  // 0 dB

+            }

+            else

+            {

+                rg_zcal_ctrl += R50_OFFSET_VALUE;

+            }

+

+            rg_r50ohm_rsel_tx = ZCAL_TO_R50ohm_TBL[rg_zcal_ctrl];

+        }

+

+        if (calibration_pair == ANACAL_PAIR_A)

+        {

+            // cr_r50ohm_rsel_tx_a

+            ad_cal_comp_out_init = get_gphy_reg_cl45(phyadd, DEVID_1E, RgAddr_dev1Eh_reg174h)&(~MASK_r50ohm_rsel_tx_a);

+            set_gphy_reg_cl45(phyadd, DEVID_1E, RgAddr_dev1Eh_reg174h, (ad_cal_comp_out_init | (((rg_r50ohm_rsel_tx << 8) & MASK_MSB_8bit) | Rg_r50ohm_rsel_tx_a_en))); // 1e_174[15:8]

+        }

+        else if (calibration_pair == ANACAL_PAIR_B)

+        {

+            // cr_r50ohm_rsel_tx_b

+            ad_cal_comp_out_init = get_gphy_reg_cl45(phyadd, DEVID_1E, RgAddr_dev1Eh_reg174h)&(~MASK_r50ohm_rsel_tx_b);

+            set_gphy_reg_cl45(phyadd, DEVID_1E, RgAddr_dev1Eh_reg174h, (ad_cal_comp_out_init | (((rg_r50ohm_rsel_tx << 0) & MASK_LSB_8bit) | Rg_r50ohm_rsel_tx_b_en))); // 1e_174[7:0]

+        }

+        else if (calibration_pair == ANACAL_PAIR_C)

+        {

+            // cr_r50ohm_rsel_tx_c

+            ad_cal_comp_out_init = get_gphy_reg_cl45(phyadd, DEVID_1E, RgAddr_dev1Eh_reg175h)&(~MASK_r50ohm_rsel_tx_c);

+            set_gphy_reg_cl45(phyadd, DEVID_1E, RgAddr_dev1Eh_reg175h, (ad_cal_comp_out_init | (((rg_r50ohm_rsel_tx << 8) & MASK_MSB_8bit) | Rg_r50ohm_rsel_tx_c_en))); // 1e_175[15:8]

+        }

+        else // if(calibration_pair == ANACAL_PAIR_D)

+        {

+            // cr_r50ohm_rsel_tx_d

+            ad_cal_comp_out_init = get_gphy_reg_cl45(phyadd, DEVID_1E, RgAddr_dev1Eh_reg175h)&(~MASK_r50ohm_rsel_tx_d);

+            set_gphy_reg_cl45(phyadd, DEVID_1E, RgAddr_dev1Eh_reg175h, (ad_cal_comp_out_init | (((rg_r50ohm_rsel_tx << 0) & MASK_LSB_8bit) | Rg_r50ohm_rsel_tx_d_en))); // 1e_175[7:0]

+        }

+    }

+

+    set_gphy_reg_cl45(phyadd, DEVID_1E, RgAddr_dev1Eh_reg0DBh, Disable_all);

+    set_gphy_reg_cl45(phyadd_common, DEVID_1E, RgAddr_dev1Eh_reg0DBh, Disable_all);

+    set_gphy_reg_cl45(phyadd, DEVID_1E, RgAddr_dev1Eh_reg0DCh, Disable_all);

+

+    return all_ana_cal_status;

+}

+

+uint8_t TX_OFS_Calibration(uint8_t phyadd, uint8_t phyadd_common)

+{

+    int8_t tx_offset_index = 0, calibration_polarity = 0;

+    uint8_t all_ana_cal_status = 1, tx_offset_reg_shift = 0, tbl_idx = 0;

+    int16_t ad_cal_comp_out_init = 0, calibration_pair = 0, tx_offset_reg = 0, reg_temp = 0;

+

+    /* setting */

+    set_gphy_reg_cl22(phyadd, RgAddr_Reg1Fh, CL22_Page_Reg);        // g0

+    set_gphy_reg_cl22(phyadd, RgAddr_Reg00h, AN_disable_force_1000M);  // AN disable, force 1000M

+

+    set_gphy_reg_cl45(phyadd, DEVID_1F, RgAddr_dev1Fh_reg100h, BG_voltage_output); // BG voltage output

+    set_gphy_reg_cl45(phyadd, DEVID_1E, RgAddr_dev1Eh_reg145h, Fix_mdi); // fix mdi

+    set_gphy_reg_cl45(phyadd, DEVID_1E, RgAddr_dev1Eh_reg185h, Disable_tx_slew_control); // disable tx slew control

+    set_gphy_reg_cl45(phyadd, DEVID_1E, RgAddr_dev1Eh_reg0FBh, LDO_control); // ldo

+    set_gphy_reg_cl45(phyadd, DEVID_1E, RgAddr_dev1Eh_reg0DBh, Cal_control_TX_OFST); // 1e_db[12]:rg_cal_ckinv, [8]:rg_ana_calen, [4]:rg_rext_calen

+    set_gphy_reg_cl45(phyadd, DEVID_1E, RgAddr_dev1Eh_reg0DCh, Rg_txvos_calen_ENABLE); // 1e_dc[0]:rg_txvos_calen

+    set_gphy_reg_cl45(phyadd_common, DEVID_1E, RgAddr_dev1Eh_reg0DBh, Cal_control_TX_OFST); // 1e_db[12]:rg_cal_ckinv, [8]:rg_ana_calen, [4]:rg_rext_calen

+    set_gphy_reg_cl45(phyadd_common, DEVID_1E, RgAddr_dev1Eh_reg0DCh, Rg_txvos_calen_ENABLE); // 1e_dc[0]:rg_txvos_calen

+    set_gphy_reg_cl45(phyadd, DEVID_1E, RgAddr_dev1Eh_reg0E1h, Disable_all); // 1e_e1[4]:rg_cal_refsel(0:1.2V) enable BG 1.2V to REXT PAD

+    set_gphy_reg_cl45(phyadd, DEVID_1E, RgAddr_dev1Eh_reg096h, Bypass_tx_offset_cal); // 1e_96[15]:bypass_tx_offset_cal, Hw bypass, Fw cal

+    set_gphy_reg_cl45(phyadd, DEVID_1E, RgAddr_dev1Eh_reg03Eh, Enable_Tx_VLD); // 1e_3e:enable Tx VLD

+

+    for (calibration_pair = ANACAL_PAIR_A; calibration_pair <= ANACAL_PAIR_D; calibration_pair++)

+    {

+        all_ana_cal_status = 1;

+

+        tbl_idx = TX_OFFSET_0mV_idx;

+        tx_offset_index = EN753x_TX_OFS_TBL[tbl_idx];

+

+        if (calibration_pair == ANACAL_PAIR_A)

+        {

+            set_gphy_reg_cl45(phyadd, DEVID_1E, RgAddr_dev1Eh_reg0DDh, Rg_txg_calen_a_ENABLE);       // 1e_dd[12]:rg_txg_calen_a

+            set_gphy_reg_cl45(phyadd, DEVID_1E, RgAddr_dev1Eh_reg17Dh, (Force_dasn_dac_in0_ENABLE | DAC_IN_0V));  // 1e_17d:dac_in0_a

+            set_gphy_reg_cl45(phyadd, DEVID_1E, RgAddr_dev1Eh_reg181h, (Force_dasn_dac_in1_ENABLE | DAC_IN_0V));  // 1e_181:dac_in1_a

+

+            reg_temp = (get_gphy_reg_cl45(phyadd, DEVID_1E, RgAddr_dev1Eh_reg172h)&(~MASK_cr_tx_amp_offset_MSB));

+            tx_offset_reg_shift = 8;  // 1e_172[13:8]

+            tx_offset_reg = RgAddr_dev1Eh_reg172h;

+        }

+        else if (calibration_pair == ANACAL_PAIR_B)

+        {

+            set_gphy_reg_cl45(phyadd, DEVID_1E, RgAddr_dev1Eh_reg0DDh, Rg_txg_calen_b_ENABLE);       // 1e_dd[8]:rg_txg_calen_b

+            set_gphy_reg_cl45(phyadd, DEVID_1E, RgAddr_dev1Eh_reg17Eh, (Force_dasn_dac_in0_ENABLE | DAC_IN_0V));  // 1e_17e:dac_in0_b

+            set_gphy_reg_cl45(phyadd, DEVID_1E, RgAddr_dev1Eh_reg182h, (Force_dasn_dac_in1_ENABLE | DAC_IN_0V));  // 1e_182:dac_in1_b

+

+            reg_temp = (get_gphy_reg_cl45(phyadd, DEVID_1E, RgAddr_dev1Eh_reg172h)&(~MASK_cr_tx_amp_offset_LSB));

+            tx_offset_reg_shift = 0;  // 1e_172[5:0]

+            tx_offset_reg = RgAddr_dev1Eh_reg172h;

+        }

+        else if (calibration_pair == ANACAL_PAIR_C)

+        {

+            set_gphy_reg_cl45(phyadd, DEVID_1E, RgAddr_dev1Eh_reg0DDh, Rg_txg_calen_c_ENABLE);       // 1e_dd[4]:rg_txg_calen_c

+            set_gphy_reg_cl45(phyadd, DEVID_1E, RgAddr_dev1Eh_reg17Fh, (Force_dasn_dac_in0_ENABLE | DAC_IN_0V));  // 1e_17f:dac_in0_c

+            set_gphy_reg_cl45(phyadd, DEVID_1E, RgAddr_dev1Eh_reg183h, (Force_dasn_dac_in1_ENABLE | DAC_IN_0V));  // 1e_183:dac_in1_c

+

+            reg_temp = (get_gphy_reg_cl45(phyadd, DEVID_1E, RgAddr_dev1Eh_reg173h)&(~MASK_cr_tx_amp_offset_MSB));

+            tx_offset_reg_shift = 8;  // 1e_173[13:8]

+            tx_offset_reg = RgAddr_dev1Eh_reg173h;

+        }

+        else // if(calibration_pair == ANACAL_PAIR_D)

+        {

+            set_gphy_reg_cl45(phyadd, DEVID_1E, RgAddr_dev1Eh_reg0DDh, Rg_txg_calen_d_ENABLE);       // 1e_dd[0]:rg_txg_calen_d

+            set_gphy_reg_cl45(phyadd, DEVID_1E, RgAddr_dev1Eh_reg180h, (Force_dasn_dac_in0_ENABLE | DAC_IN_0V));  // 1e_180:dac_in0_d

+            set_gphy_reg_cl45(phyadd, DEVID_1E, RgAddr_dev1Eh_reg184h, (Force_dasn_dac_in1_ENABLE | DAC_IN_0V));  // 1e_184:dac_in1_d

+

+            reg_temp = (get_gphy_reg_cl45(phyadd, DEVID_1E, RgAddr_dev1Eh_reg173h)&(~MASK_cr_tx_amp_offset_LSB));

+            tx_offset_reg_shift = 0;  // 1e_173[5:0]

+            tx_offset_reg = RgAddr_dev1Eh_reg173h;

+        }

+

+        /* calibrate */

+        //tx_offset_index = TX_AMP_OFFSET_0mV;

+        tbl_idx = TX_OFFSET_0mV_idx;

+        tx_offset_index = EN753x_TX_OFS_TBL[tbl_idx];

+        set_gphy_reg_cl45(phyadd, DEVID_1E, tx_offset_reg, (reg_temp | (tx_offset_index << tx_offset_reg_shift)));  // 1e_172, 1e_173

+

+        anacal_exe(phyadd_common);

+        if (all_ana_cal_status == 0)

+        {

+            all_ana_cal_status = ANACAL_ERROR;

+        }

+

+        ad_cal_comp_out_init = (get_gphy_reg_cl45(phyadd_common, DEVID_1E, RgAddr_dev1Eh_reg17Ah) >> 8) & 0x1;  // 1e_17a[8]:ad_cal_comp_out

+

+        if (ad_cal_comp_out_init == 1)

+        {

+            calibration_polarity = -1;

+        }

+        else

+        {

+            calibration_polarity = 1;

+        }

+

+        while (all_ana_cal_status < ANACAL_ERROR)

+        {

+            tbl_idx += calibration_polarity;

+            tx_offset_index = EN753x_TX_OFS_TBL[tbl_idx];

+

+            set_gphy_reg_cl45(phyadd, DEVID_1E, tx_offset_reg, (reg_temp | (tx_offset_index << tx_offset_reg_shift)));  // 1e_172, 1e_173

+

+            anacal_exe(phyadd_common);

+

+            if (all_ana_cal_status == 0)

+            {

+                all_ana_cal_status = ANACAL_ERROR;

+            }

+            else if (((get_gphy_reg_cl45(phyadd_common, DEVID_1E, RgAddr_dev1Eh_reg17Ah) >> 8) & 0x1) != ad_cal_comp_out_init)

+            {

+                all_ana_cal_status = ANACAL_FINISH;

+            }

+            else

+            {

+                if ((tx_offset_index == 0x3f) || (tx_offset_index == 0x1f))

+                {

+                    all_ana_cal_status = ANACAL_SATURATION;  // need to FT

+                }

+            }

+        }

+

+        if (all_ana_cal_status == ANACAL_ERROR)

+        {

+            tbl_idx = TX_OFFSET_0mV_idx;

+            tx_offset_index = EN753x_TX_OFS_TBL[tbl_idx];

+

+            set_gphy_reg_cl45(phyadd, DEVID_1E, tx_offset_reg, (reg_temp | (tx_offset_index << tx_offset_reg_shift)));  // cr_tx_amp_offset_a/b/c/d, 1e_172, 1e_173

+        }

+    }

+

+    set_gphy_reg_cl45(phyadd, DEVID_1E, RgAddr_dev1Eh_reg17Dh, Disable_all);

+    set_gphy_reg_cl45(phyadd, DEVID_1E, RgAddr_dev1Eh_reg17Eh, Disable_all);

+    set_gphy_reg_cl45(phyadd, DEVID_1E, RgAddr_dev1Eh_reg17Fh, Disable_all);

+    set_gphy_reg_cl45(phyadd, DEVID_1E, RgAddr_dev1Eh_reg180h, Disable_all);

+    set_gphy_reg_cl45(phyadd, DEVID_1E, RgAddr_dev1Eh_reg181h, Disable_all);

+    set_gphy_reg_cl45(phyadd, DEVID_1E, RgAddr_dev1Eh_reg182h, Disable_all);

+    set_gphy_reg_cl45(phyadd, DEVID_1E, RgAddr_dev1Eh_reg183h, Disable_all);

+    set_gphy_reg_cl45(phyadd, DEVID_1E, RgAddr_dev1Eh_reg184h, Disable_all);

+    set_gphy_reg_cl45(phyadd, DEVID_1E, RgAddr_dev1Eh_reg0DBh, Disable_all); // disable analog calibration circuit

+    set_gphy_reg_cl45(phyadd, DEVID_1E, RgAddr_dev1Eh_reg0DCh, Disable_all); // disable Tx offset calibration circuit

+    set_gphy_reg_cl45(phyadd_common, DEVID_1E, RgAddr_dev1Eh_reg0DBh, Disable_all); // disable analog calibration circuit

+    set_gphy_reg_cl45(phyadd_common, DEVID_1E, RgAddr_dev1Eh_reg0DCh, Disable_all); // disable Tx offset calibration circuit

+    set_gphy_reg_cl45(phyadd, DEVID_1E, RgAddr_dev1Eh_reg03Eh, Disable_all); // disable Tx VLD force mode

+    set_gphy_reg_cl45(phyadd, DEVID_1E, RgAddr_dev1Eh_reg0DDh, Disable_all); // disable Tx offset/amplitude calibration circuit

+

+    return all_ana_cal_status;

+}

+

+uint8_t TX_AMP_Calibration(uint8_t phyadd, uint8_t phyadd_common)

+{

+    int8_t tx_amp_index = 0, calibration_polarity = 0;

+    uint8_t all_ana_cal_status = 1, tx_amp_reg_shift = 0;

+    uint8_t tx_amp_reg = 0, tx_amp_reg_100 = 0, tst_offset = 0, hbt_offset = 0, gbe_offset = 0, tbt_offset = 0;

+    uint16_t ad_cal_comp_out_init = 0, calibration_pair = 0, reg_temp = 0;

+

+  //phyadd_common = phyadd;

+

+    /* setting */

+    set_gphy_reg_cl22(phyadd, RgAddr_Reg1Fh, CL22_Page_Reg);        // g0

+    set_gphy_reg_cl22(phyadd, RgAddr_Reg00h, AN_disable_force_1000M);  // AN disable, force 1000M

+

+    set_gphy_reg_cl45(phyadd, DEVID_1F, RgAddr_dev1Fh_reg100h, BG_voltage_output); // BG voltage output

+    set_gphy_reg_cl45(phyadd, DEVID_1E, RgAddr_dev1Eh_reg145h, Fix_mdi); // fix mdi

+    set_gphy_reg_cl45(phyadd, DEVID_1E, RgAddr_dev1Eh_reg185h, Disable_tx_slew_control); // disable tx slew control

+    set_gphy_reg_cl45(phyadd, DEVID_1E, RgAddr_dev1Eh_reg0FBh, LDO_control); // ldo

+    set_gphy_reg_cl45(phyadd, DEVID_1E, RgAddr_dev1Eh_reg0DBh, Cal_control_TX_AMP); // 1e_db[12]:rg_cal_ckinv, [8]:rg_ana_calen, [4]:rg_rext_calen

+    set_gphy_reg_cl45(phyadd, DEVID_1E, RgAddr_dev1Eh_reg0DCh, Rg_txvos_calen_ENABLE); // 1e_dc[0]:rg_txvos_calen

+    set_gphy_reg_cl45(phyadd, DEVID_1E, RgAddr_dev1Eh_reg0E1h, Rg_cal_refsel_ENABLE); // 1e_e1[4]:rg_cal_refsel(0:1.2V) enable BG 1.2V to REXT PAD

+    set_gphy_reg_cl45(phyadd_common, DEVID_1E, RgAddr_dev1Eh_reg0DBh, Cal_control_TX_AMP); // 1e_db[12]:rg_cal_ckinv, [8]:rg_ana_calen, [4]:rg_rext_calen

+    set_gphy_reg_cl45(phyadd_common, DEVID_1E, RgAddr_dev1Eh_reg0DCh, Rg_txvos_calen_ENABLE); // 1e_dc[0]:rg_txvos_calen

+    set_gphy_reg_cl45(phyadd_common, DEVID_1E, RgAddr_dev1Eh_reg0E1h, Rg_cal_refsel_ENABLE); // 1e_e1[4]:rg_cal_refsel(0:1.2V) enable BG 1.2V to REXT PAD

+    set_gphy_reg_cl45(phyadd, DEVID_1E, RgAddr_dev1Eh_reg096h, Bypass_tx_offset_cal); // 1e_96[15]:bypass_tx_offset_cal, Hw bypass, Fw cal

+    set_gphy_reg_cl45(phyadd, DEVID_1E, RgAddr_dev1Eh_reg03Eh, Enable_Tx_VLD); // 1e_3e:enable Tx VLD

+

+    for (calibration_pair = ANACAL_PAIR_A; calibration_pair <= ANACAL_PAIR_D; calibration_pair++)

+    //for (calibration_pair = ANACAL_PAIR_A; calibration_pair <= ANACAL_PAIR_B; calibration_pair++) // debugging

+    {

+        all_ana_cal_status = 1;

+

+        /* calibrate */

+        tx_amp_index = TX_AMP_MIDDLE;   // start with 0 dB

+        if (calibration_pair == ANACAL_PAIR_A)

+        {

+            set_gphy_reg_cl45(phyadd, DEVID_1E, RgAddr_dev1Eh_reg0DDh, Rg_txg_calen_a_ENABLE);       // 1e_dd[12]:rg_txg_calen_a amp calibration enable

+            set_gphy_reg_cl45(phyadd, DEVID_1E, RgAddr_dev1Eh_reg17Dh, (Force_dasn_dac_in0_ENABLE | DAC_IN_2V));  // 1e_17d:dac_in0_a

+            set_gphy_reg_cl45(phyadd, DEVID_1E, RgAddr_dev1Eh_reg181h, (Force_dasn_dac_in1_ENABLE | DAC_IN_2V));  // 1e_181:dac_in1_a

+

+            reg_temp = (get_gphy_reg_cl45(phyadd, DEVID_1E, RgAddr_dev1Eh_reg012h)&(~MASK_da_tx_i2mpb_a_gbe));

+            tx_amp_reg_shift = 10;  // 1e_12[15:10]

+            tx_amp_reg = RgAddr_dev1Eh_reg012h;

+            tx_amp_reg_100 = 0x16;

+        }

+        else if (calibration_pair == ANACAL_PAIR_B)

+        {

+            set_gphy_reg_cl45(phyadd, DEVID_1E, RgAddr_dev1Eh_reg0DDh, Rg_txg_calen_b_ENABLE);       // 1e_dd[8]:rg_txg_calen_b amp calibration enable

+            //Serial.println(Rg_txg_calen_b_ENABLE, HEX);

+            set_gphy_reg_cl45(phyadd, DEVID_1E, RgAddr_dev1Eh_reg17Eh, (Force_dasn_dac_in0_ENABLE | DAC_IN_2V));  // 1e_17e:dac_in0_b

+            set_gphy_reg_cl45(phyadd, DEVID_1E, RgAddr_dev1Eh_reg182h, (Force_dasn_dac_in1_ENABLE | DAC_IN_2V));  // 1e_182:dac_in1_b

+

+            reg_temp = (get_gphy_reg_cl45(phyadd, DEVID_1E, RgAddr_dev1Eh_reg017h)&(~MASK_da_tx_i2mpb_b_c_d_gbe));

+            tx_amp_reg_shift = 8; // 1e_17[13:8]

+            tx_amp_reg = RgAddr_dev1Eh_reg017h;

+            tx_amp_reg_100 = 0x18;

+        }

+        else if (calibration_pair == ANACAL_PAIR_C)

+        {

+            set_gphy_reg_cl45(phyadd, DEVID_1E, RgAddr_dev1Eh_reg0DDh, Rg_txg_calen_c_ENABLE);       // 1e_dd[4]:rg_txg_calen_c amp calibration enable

+            set_gphy_reg_cl45(phyadd, DEVID_1E, RgAddr_dev1Eh_reg17Fh, (Force_dasn_dac_in0_ENABLE | DAC_IN_2V));  // 1e_17f:dac_in0_c

+            set_gphy_reg_cl45(phyadd, DEVID_1E, RgAddr_dev1Eh_reg183h, (Force_dasn_dac_in1_ENABLE | DAC_IN_2V));  // 1e_183:dac_in1_c

+

+            reg_temp = (get_gphy_reg_cl45(phyadd, DEVID_1E, RgAddr_dev1Eh_reg019h)&(~MASK_da_tx_i2mpb_b_c_d_gbe));

+            tx_amp_reg_shift = 8; // 1e_19[13:8]

+            tx_amp_reg = RgAddr_dev1Eh_reg019h;

+            tx_amp_reg_100 = 0x20;

+        }

+        else //if(calibration_pair == ANACAL_PAIR_D)

+        {

+            set_gphy_reg_cl45(phyadd, DEVID_1E, RgAddr_dev1Eh_reg0DDh, Rg_txg_calen_d_ENABLE);       // 1e_dd[0]:rg_txg_calen_d amp calibration enable

+            set_gphy_reg_cl45(phyadd, DEVID_1E, RgAddr_dev1Eh_reg180h, (Force_dasn_dac_in0_ENABLE | DAC_IN_2V));  // 1e_180:dac_in0_d

+            set_gphy_reg_cl45(phyadd, DEVID_1E, RgAddr_dev1Eh_reg184h, (Force_dasn_dac_in1_ENABLE | DAC_IN_2V));  // 1e_184:dac_in1_d

+

+            reg_temp = (get_gphy_reg_cl45(phyadd, DEVID_1E, RgAddr_dev1Eh_reg021h)&(~MASK_da_tx_i2mpb_b_c_d_gbe));

+            tx_amp_reg_shift = 8; // 1e_21[13:8]

+            tx_amp_reg = RgAddr_dev1Eh_reg021h;

+            tx_amp_reg_100 = 0x22;

+        }

+

+        /* calibrate */

+        tx_amp_index = TX_AMP_MIDDLE; // start with 0 dB

+

+        set_gphy_reg_cl45(phyadd, DEVID_1E, tx_amp_reg, (reg_temp | (tx_amp_index << tx_amp_reg_shift))); // 1e_12/17/19/21

+

+        anacal_exe(phyadd_common);

+        if (all_ana_cal_status == 0)

+        {

+            all_ana_cal_status = ANACAL_ERROR;

+        }

+

+

+        ad_cal_comp_out_init = (get_gphy_reg_cl45(phyadd_common, DEVID_1E, RgAddr_dev1Eh_reg17Ah) >> 8) & 0x1;    // 1e_17a[8]:ad_cal_comp_out

+        //Serial.println(ad_cal_comp_out_init, HEX);

+

+        if (ad_cal_comp_out_init == 1)

+        {

+            calibration_polarity = -1;

+        }

+        else

+        {

+            calibration_polarity = 1;

+        }

+        while (all_ana_cal_status < ANACAL_ERROR)

+        {

+            tx_amp_index += calibration_polarity;

+            //Serial.println(tx_amp_index, HEX);

+

+            set_gphy_reg_cl45(phyadd, DEVID_1E, tx_amp_reg, (reg_temp | (tx_amp_index << tx_amp_reg_shift)));

+

+            anacal_exe(phyadd_common);

+

+            if (all_ana_cal_status == 0)

+            {

+                all_ana_cal_status = ANACAL_ERROR;

+            }

+            else if (((get_gphy_reg_cl45(phyadd_common, DEVID_1E, RgAddr_dev1Eh_reg17Ah) >> 8) & 0x1) != ad_cal_comp_out_init)

+            {

+                all_ana_cal_status = ANACAL_FINISH;

+                //Serial.print("    tx_amp_index: ");

+                //Serial.println(tx_amp_index, HEX);

+                //reg_temp = get_gphy_reg_cl45(phyadd, 0x1e, tx_amp_reg)&(~0xff00);

+                //set_gphy_reg_cl45(phyadd, 0x1e, tx_amp_reg, (reg_temp|((tx_amp_index + tst_offset)<<tx_amp_reg_shift)));  // for gbe(DAC)

+            }

+            else

+            {

+                if ((tx_amp_index == 0x3f) || (tx_amp_index == 0x00))

+                {

+                    all_ana_cal_status = ANACAL_SATURATION;  // need to FT

+                    tx_amp_index = TX_AMP_MIDDLE;

+                }

+            }

+        }

+

+        if (all_ana_cal_status == ANACAL_ERROR)

+        {

+            tx_amp_index = TX_AMP_MIDDLE;

+        }

+

+        // da_tx_i2mpb_a_gbe / b/c/d, only GBE for now

+        set_gphy_reg_cl45(phyadd, DEVID_1E, tx_amp_reg, ((tx_amp_index - TXAMP_offset) | ((tx_amp_index - TXAMP_offset) << tx_amp_reg_shift)));  // // temp modify

+        set_gphy_reg_cl45(phyadd, DEVID_1E, tx_amp_reg_100, ((tx_amp_index - TXAMP_offset) | ((tx_amp_index + TX_i2mpb_hbt_ofs) << tx_amp_reg_shift)));

+    }

+

+    set_gphy_reg_cl45(phyadd, DEVID_1E, RgAddr_dev1Eh_reg17Dh, Disable_all);

+    set_gphy_reg_cl45(phyadd, DEVID_1E, RgAddr_dev1Eh_reg17Eh, Disable_all);

+    set_gphy_reg_cl45(phyadd, DEVID_1E, RgAddr_dev1Eh_reg17Fh, Disable_all);

+    set_gphy_reg_cl45(phyadd, DEVID_1E, RgAddr_dev1Eh_reg180h, Disable_all);

+    set_gphy_reg_cl45(phyadd, DEVID_1E, RgAddr_dev1Eh_reg181h, Disable_all);

+    set_gphy_reg_cl45(phyadd, DEVID_1E, RgAddr_dev1Eh_reg182h, Disable_all);

+    set_gphy_reg_cl45(phyadd, DEVID_1E, RgAddr_dev1Eh_reg183h, Disable_all);

+    set_gphy_reg_cl45(phyadd, DEVID_1E, RgAddr_dev1Eh_reg184h, Disable_all);

+    set_gphy_reg_cl45(phyadd, DEVID_1E, RgAddr_dev1Eh_reg0DBh, Disable_all); // disable analog calibration circuit

+    set_gphy_reg_cl45(phyadd, DEVID_1E, RgAddr_dev1Eh_reg0DCh, Disable_all); // disable Tx offset calibration circuit

+    set_gphy_reg_cl45(phyadd, DEVID_1E, RgAddr_dev1Eh_reg03Eh, Disable_all); // disable Tx VLD force mode

+    set_gphy_reg_cl45(phyadd, DEVID_1E, RgAddr_dev1Eh_reg0DDh, Disable_all); // disable Tx offset/amplitude calibration circuit

+

+    return all_ana_cal_status;

+}

+

+void set_gphy_reg_cl22(uint8_t phyad, uint8_t reg, uint16_t value)

+{

+    an8855_phy_write(phyad-g_smi_addr, reg, value);

+    /*

+       gsw_top_reg_REG_PHY_IAC REG_PHY_IAC_val;

+       gsw_top_reg_REG_PHY_IAD REG_PHY_IAD_val;

+

+    // Wait until done

+    do

+    {

+    REG_PHY_IAC_val.Raw = io_read32(RgAddr_gsw_top_reg_REG_PHY_IAC);

+    }

+    while(REG_PHY_IAC_val.Bits.csr_phy_acs_st);

+

+    // Set address

+    REG_PHY_IAC_val.Bits.csr_mdio_st = 1;

+    REG_PHY_IAC_val.Bits.csr_mdio_cmd = 1;

+    REG_PHY_IAC_val.Bits.csr_mdio_phy_addr = phyad;

+    REG_PHY_IAC_val.Bits.csr_mdio_reg_addr = reg;

+    REG_PHY_IAC_val.Bits.csr_mdio_wr_data = value;

+    REG_PHY_IAC_val.Bits.csr_phy_acs_st = 1;

+

+    io_write32(RgAddr_gsw_top_reg_REG_PHY_IAC, REG_PHY_IAC_val.Raw);

+    */

+}

+

+UINT16 get_gphy_reg_cl45(uint8_t prtid, uint8_t devid, uint16_t reg)

+{

+    UINT32 rdata = 0;

+

+    an8855_phy_read_cl45(prtid-g_smi_addr, devid, reg, &rdata);

+    return ((UINT16)rdata);

+    /*

+    gsw_top_reg_REG_PHY_IAC REG_PHY_IAC_val;

+    gsw_top_reg_REG_PHY_IAD REG_PHY_IAD_val;

+

+    // Wait until done

+    do

+    {

+    REG_PHY_IAC_val.Raw = io_read32(RgAddr_gsw_top_reg_REG_PHY_IAC);

+    }

+    while(REG_PHY_IAC_val.Bits.csr_phy_acs_st);

+

+    // Set address

+    REG_PHY_IAC_val.Bits.csr_mdio_st = 0;

+    REG_PHY_IAC_val.Bits.csr_mdio_cmd = 0;

+    REG_PHY_IAC_val.Bits.csr_mdio_phy_addr = prtid;

+    REG_PHY_IAC_val.Bits.csr_mdio_reg_addr = devid;

+    REG_PHY_IAC_val.Bits.csr_mdio_wr_data = reg;

+    REG_PHY_IAC_val.Bits.csr_phy_acs_st = 1;

+

+    io_write32(RgAddr_gsw_top_reg_REG_PHY_IAC, REG_PHY_IAC_val.Raw);

+

+    // Wait until done

+    do

+    {

+    REG_PHY_IAC_val.Raw = io_read32(RgAddr_gsw_top_reg_REG_PHY_IAC);

+    }

+    while(REG_PHY_IAC_val.Bits.csr_phy_acs_st);

+

+    // Read value

+    REG_PHY_IAC_val.Bits.csr_mdio_st = 0;

+    REG_PHY_IAC_val.Bits.csr_mdio_cmd = 3;

+    REG_PHY_IAC_val.Bits.csr_mdio_phy_addr = prtid;

+    REG_PHY_IAC_val.Bits.csr_mdio_reg_addr = devid;

+    REG_PHY_IAC_val.Bits.csr_mdio_wr_data = 0;

+    REG_PHY_IAC_val.Bits.csr_phy_acs_st = 1;

+    io_write32(RgAddr_gsw_top_reg_REG_PHY_IAC, REG_PHY_IAC_val.Raw);

+

+    // Wait until done

+    do

+    {

+    REG_PHY_IAC_val.Raw = io_read32(RgAddr_gsw_top_reg_REG_PHY_IAC);

+    }

+    while(REG_PHY_IAC_val.Bits.csr_phy_acs_st);

+

+    REG_PHY_IAD_val.Raw = io_read32(RgAddr_gsw_top_reg_REG_PHY_IAD);

+

+    return REG_PHY_IAD_val.Raw;

+    */

+}

+

+void set_gphy_reg_cl45(uint8_t prtid, uint8_t devid, uint16_t reg, uint16_t value)

+{

+    an8855_phy_write_cl45(prtid-g_smi_addr, devid, reg, value);

+    /*

+    gsw_top_reg_REG_PHY_IAC REG_PHY_IAC_val;

+

+    // Wait until done

+    do

+    {

+        REG_PHY_IAC_val.Raw = io_read32(RgAddr_gsw_top_reg_REG_PHY_IAC);

+    }

+    while(REG_PHY_IAC_val.Bits.csr_phy_acs_st);

+

+    // Set address

+    REG_PHY_IAC_val.Bits.csr_mdio_st = 0;

+    REG_PHY_IAC_val.Bits.csr_mdio_cmd = 0;

+    REG_PHY_IAC_val.Bits.csr_mdio_phy_addr = prtid;

+    REG_PHY_IAC_val.Bits.csr_mdio_reg_addr = devid;

+    REG_PHY_IAC_val.Bits.csr_mdio_wr_data = reg;

+    REG_PHY_IAC_val.Bits.csr_phy_acs_st = 1;

+

+    io_write32(RgAddr_gsw_top_reg_REG_PHY_IAC, REG_PHY_IAC_val.Raw);

+

+    // Wait until done

+    do

+    {

+        REG_PHY_IAC_val.Raw = io_read32(RgAddr_gsw_top_reg_REG_PHY_IAC);

+    }

+    while(REG_PHY_IAC_val.Bits.csr_phy_acs_st);

+

+    // Write value

+    REG_PHY_IAC_val.Bits.csr_mdio_st = 0;

+    REG_PHY_IAC_val.Bits.csr_mdio_cmd = 1;

+    REG_PHY_IAC_val.Bits.csr_mdio_phy_addr = prtid;

+    REG_PHY_IAC_val.Bits.csr_mdio_reg_addr = devid;

+    REG_PHY_IAC_val.Bits.csr_mdio_wr_data = value;

+    REG_PHY_IAC_val.Bits.csr_phy_acs_st = 1;

+

+    io_write32(RgAddr_gsw_top_reg_REG_PHY_IAC, REG_PHY_IAC_val.Raw);

+    */

+}

+

+void anacal_exe(uint8_t phyadd_common)

+{

+    set_gphy_reg_cl45(phyadd_common, DEVID_1E, RgAddr_dev1Eh_reg17Ch, 1);// da_calin_flag pull high

+    an8855_udelay(1000);

+    set_gphy_reg_cl45(phyadd_common, DEVID_1E, RgAddr_dev1Eh_reg17Ch, 0);// da_calin_flag pull low

+}

+

diff --git a/recipes-devtools/switch/files/src/an8855_sdk/core/an8855_reg.h b/recipes-devtools/switch/files/src/an8855_sdk/core/an8855_reg.h
new file mode 100644
index 0000000..3459cef
--- /dev/null
+++ b/recipes-devtools/switch/files/src/an8855_sdk/core/an8855_reg.h
@@ -0,0 +1,191 @@
+    /* FILE NAME:  an8855_reg.h

+ * PURPOSE:

+ *      It provides AN8855 register definition.

+ * NOTES:

+ *

+ */

+

+#ifndef AN8855_REG_H

+#define AN8855_REG_H

+

+#define PORT_CTRL_BASE                      0x10208000

+#define PORT_CTRL_PORT_OFFSET               0x200

+#define PORT_CTRL_REG(p, r)                 (PORT_CTRL_BASE + (p) * PORT_CTRL_PORT_OFFSET + (r))

+#define PCR(p)                              PORT_CTRL_REG(p, 0x04)

+

+#define PORT_MAC_CTRL_BASE                  0x10210000

+#define PORT_MAC_CTRL_PORT_OFFSET           0x200

+#define PORT_MAC_CTRL_REG(p, r)             (PORT_MAC_CTRL_BASE + (p) * PORT_MAC_CTRL_PORT_OFFSET + (r))

+#define PMCR(p)                             PORT_MAC_CTRL_REG(p, 0x00)

+

+/* Port debug count register */

+#define DBG_CNT_BASE                        0x3018

+#define DBG_CNT_PORT_BASE                   0x100

+#define DBG_CNT(p)                          (DBG_CNT_BASE + (p) * DBG_CNT_PORT_BASE)

+#define DIS_CLR                             (1 << 31)

+

+#define GMACCR                              (PORT_MAC_CTRL_BASE + 0x30e0)

+#define MTCC_LMT_S                          8

+#define MAX_RX_JUMBO_S                      4

+

+/* Values of MAX_RX_PKT_LEN */

+#define RX_PKT_LEN_1518                     0

+#define RX_PKT_LEN_1536                     1

+#define RX_PKT_LEN_1522                     2

+#define RX_PKT_LEN_MAX_JUMBO                3

+

+/* Fields of PMCR */

+#define FORCE_MODE                          (1 << 31)

+#define IPG_CFG_S                           20

+#define IPG_CFG_M                           0x300000

+#define EXT_PHY                             (1 << 19)

+#define MAC_MODE                            (1 << 18)

+#define MAC_TX_EN                           (1 << 16)

+#define MAC_RX_EN                           (1 << 15)

+#define MAC_PRE                             (1 << 14)

+#define BKOFF_EN                            (1 << 12)

+#define BACKPR_EN                           (1 << 11)

+#define FORCE_EEE1G                         (1 << 7)

+#define FORCE_EEE100                        (1 << 6)

+#define FORCE_RX_FC                         (1 << 5)

+#define FORCE_TX_FC                         (1 << 4)

+#define FORCE_SPD_S                         28

+#define FORCE_SPD_M                         0x70000000

+#define FORCE_DPX                           (1 << 25)

+#define FORCE_LINK                          (1 << 24)

+

+/* Fields of PMSR */

+#define EEE1G_STS                           (1 << 7)

+#define EEE100_STS                          (1 << 6)

+#define RX_FC_STS                           (1 << 5)

+#define TX_FC_STS                           (1 << 4)

+#define MAC_SPD_STS_S                       28

+#define MAC_SPD_STS_M                       0x70000000

+#define MAC_DPX_STS                         (1 << 25)

+#define MAC_LNK_STS                         (1 << 24)

+

+/* Values of MAC_SPD_STS */

+#define MAC_SPD_10                          0

+#define MAC_SPD_100                         1

+#define MAC_SPD_1000                        2

+#define MAC_SPD_2500                        3

+

+/* Values of IPG_CFG */

+#define IPG_96BIT                           0

+#define IPG_96BIT_WITH_SHORT_IPG            1

+#define IPG_64BIT                           2

+

+#define SGMII_REG_BASE                      0x5000

+#define SGMII_REG_PORT_BASE                 0x1000

+#define SGMII_REG(p, r)                     (SGMII_REG_BASE + (p) * SGMII_REG_PORT_BASE + (r))

+#define PCS_CONTROL_1(p)                    SGMII_REG(p, 0x00)

+#define SGMII_MODE(p)                       SGMII_REG(p, 0x20)

+#define QPHY_PWR_STATE_CTRL(p)              SGMII_REG(p, 0xe8)

+#define PHYA_CTRL_SIGNAL3(p)                SGMII_REG(p, 0x128)

+

+/* Fields of PCS_CONTROL_1 */

+#define SGMII_LINK_STATUS                   (1 << 18)

+#define SGMII_AN_ENABLE                     (1 << 12)

+#define SGMII_AN_RESTART                    (1 << 9)

+

+/* Fields of SGMII_MODE */

+#define SGMII_REMOTE_FAULT_DIS              (1 << 8)

+#define SGMII_IF_MODE_FORCE_DUPLEX          (1 << 4)

+#define SGMII_IF_MODE_FORCE_SPEED_S         0x2

+#define SGMII_IF_MODE_FORCE_SPEED_M         0x0c

+#define SGMII_IF_MODE_ADVERT_AN             (1 << 1)

+

+/* Values of SGMII_IF_MODE_FORCE_SPEED */

+#define SGMII_IF_MODE_FORCE_SPEED_10        0

+#define SGMII_IF_MODE_FORCE_SPEED_100       1

+#define SGMII_IF_MODE_FORCE_SPEED_1000      2

+

+/* Fields of QPHY_PWR_STATE_CTRL */

+#define PHYA_PWD                            (1 << 4)

+

+/* Fields of PHYA_CTRL_SIGNAL3 */

+#define RG_TPHY_SPEED_S                     2

+#define RG_TPHY_SPEED_M                     0x0c

+

+/* Values of RG_TPHY_SPEED */

+#define RG_TPHY_SPEED_1000                  0

+#define RG_TPHY_SPEED_2500                  1

+

+#define SYS_CTRL                            0x7000

+#define SW_PHY_RST                          (1 << 2)

+#define SW_SYS_RST                          (1 << 1)

+#define SW_REG_RST                          (1 << 0)

+

+#define PHY_IAC                             (0x1000e000)

+#define IAC_MAX_BUSY_TIME                   (1000)

+

+#define CLKGEN_CTRL                         0x7500

+#define CLK_SKEW_OUT_S                      8

+#define CLK_SKEW_OUT_M                      0x300

+#define CLK_SKEW_IN_S                       6

+#define CLK_SKEW_IN_M                       0xc0

+#define RXCLK_NO_DELAY                      (1 << 5)

+#define TXCLK_NO_REVERSE                    (1 << 4)

+#define GP_MODE_S                           1

+#define GP_MODE_M                           0x06

+#define GP_CLK_EN                           (1 << 0)

+

+/* Values of GP_MODE */

+#define GP_MODE_RGMII                       0

+#define GP_MODE_MII                         1

+#define GP_MODE_REV_MII                     2

+

+/* Values of CLK_SKEW_IN */

+#define CLK_SKEW_IN_NO_CHANGE               0

+#define CLK_SKEW_IN_DELAY_100PPS            1

+#define CLK_SKEW_IN_DELAY_200PPS            2

+#define CLK_SKEW_IN_REVERSE                 3

+

+/* Values of CLK_SKEW_OUT */

+#define CLK_SKEW_OUT_NO_CHANGE              0

+#define CLK_SKEW_OUT_DELAY_100PPS           1

+#define CLK_SKEW_OUT_DELAY_200PPS           2

+#define CLK_SKEW_OUT_REVERSE                3

+

+#define HWSTRAP                             0x7800

+#define XTAL_FSEL_S                         7

+#define XTAL_FSEL_M                         (1 << 7)

+

+#define XTAL_40MHZ                          0

+#define XTAL_25MHZ                          1

+

+#define PLLGP_EN                            0x7820

+#define EN_COREPLL                          (1 << 2)

+#define SW_CLKSW                            (1 << 1)

+#define SW_PLLGP                            (1 << 0)

+

+#define PLLGP_CR0                           0x78a8

+#define RG_COREPLL_EN                       (1 << 22)

+#define RG_COREPLL_POSDIV_S                 23

+#define RG_COREPLL_POSDIV_M                 0x3800000

+#define RG_COREPLL_SDM_PCW_S                1

+#define RG_COREPLL_SDM_PCW_M                0x3ffffe

+#define RG_COREPLL_SDM_PCW_CHG              (1 << 0)

+

+#define MHWSTRAP                            0x7804

+#define TOP_SIG_SR                          0x780c

+#define PAD_DUAL_SGMII_EN                   (1 << 1)

+

+/* RGMII and SGMII PLL clock */

+#define ANA_PLLGP_CR2                       0x78b0

+#define ANA_PLLGP_CR5                       0x78bc

+

+/* Efuse Register Define */

+#define GBE_EFUSE                           0x7bc8

+#define GBE_SEL_EFUSE_EN                    (1 << 0)

+

+/* GPIO_PAD_0 */

+#define GPIO_MODE0                          0x7c0c

+#define GPIO_MODE0_S                        0

+#define GPIO_MODE0_M                        0xf

+#define GPIO_0_INTERRUPT_MODE               0x1

+

+#define SMT0_IOLB                           0x7f04

+#define SMT_IOLB_5_SMI_MDC_EN               (1 << 5)

+

+#endif  /* End of AN8855_REG_H */

diff --git a/recipes-devtools/switch/files/src/switch_753x.c b/recipes-devtools/switch/files/src/switch_753x.c
index 9c7c921..6936f6a 100644
--- a/recipes-devtools/switch/files/src/switch_753x.c
+++ b/recipes-devtools/switch/files/src/switch_753x.c
@@ -12,10 +12,14 @@
 #include "switch_netlink.h"
 #include "switch_ioctl.h"
 #include "switch_fun.h"
+#include "switch_fun_an8855.h"
+
+#define SWITCH_APP_VERSION "1.0.1"
 
 struct mt753x_attr *attres;
 int chip_name;
 bool nl_init_flag;
+struct switch_func_s *p_switch_func;
 
 static void usage(char *cmd)
 {
@@ -23,16 +27,16 @@
 
 	/* 1. basic operations */
 	printf("1) mt753x switch Basic operations=================================================================================================================>>>>\n");
-	printf(" 1.1) %s devs							- list switch device id and model name  \n", cmd);
-	printf(" 1.2) %s sysctl							- show the ways to access kenerl driver: netlink or ioctl \n", cmd);
+	printf(" 1.1) %s devs							- list switch device id and model name\n", cmd);
+	printf(" 1.2) %s sysctl							- show the ways to access kenerl driver: netlink or ioctl\n", cmd);
 	printf(" 1.3) %s reset							- sw reset switch fsm and registers\n", cmd);
-	printf(" 1.4) %s reg r [offset]						- read the reg with default switch \n", cmd);
-	printf(" 1.5) %s reg w [offset] [value]					- write the reg with default switch \n", cmd);
+	printf(" 1.4) %s reg r [offset]						- read the reg with default switch\n", cmd);
+	printf(" 1.5) %s reg w [offset] [value]					- write the reg with default switch\n", cmd);
 	printf(" 1.6) %s reg d [offset]						- dump the reg with default switch\n", cmd);
-	printf(" 1.7) %s dev [devid] reg r [addr]				- read the reg with the switch devid  \n", cmd);
-	printf(" 1.8) %s dev [devid] reg w [addr] [value] 			- write the regs with the switch devid \n", cmd);
-	printf(" 1.9) %s dev [devid] reg d [addr]				- dump the regs with the switch devid \n", cmd);
-	printf("																			\n");
+	printf(" 1.7) %s dev [devid] reg r [addr]				- read the reg with the switch devid\n", cmd);
+	printf(" 1.8) %s dev [devid] reg w [addr] [value]			- write the regs with the switch devid\n", cmd);
+	printf(" 1.9) %s dev [devid] reg d [addr]				- dump the regs with the switch devid\n", cmd);
+	printf("\n");
 
 	/* 2. phy operations */
 	printf("2) mt753x switch PHY operations===================================================================================================================>>>>\n");
@@ -42,13 +46,13 @@
 	printf(" 2.4) %s phy cl22 w [port_num] [phy_reg] [value]		- write specific phy register of specific port by clause 22\n", cmd);
 	printf(" 2.5) %s phy cl45 r [port_num] [dev_num] [phy_reg]		- read specific phy register of specific port by clause 45\n", cmd);
 	printf(" 2.6) %s phy cl45 w [port_num] [dev_num] [phy_reg] [value]	- write specific phy register of specific port by clause 45\n", cmd);
-	printf(" 2.7) %s phy fc [port_num] [enable 0|1]				- set switch phy flow control, port is 0~4, enable is 1, disable is 0 \n", cmd);
-	printf(" 2.8) %s phy an [port_num] [enable 0|1]				- set switch phy auto-negotiation, port is 0~4, enable is 1, disable is 0 \n", cmd);
+	printf(" 2.7) %s phy fc [port_num] [enable 0|1]				- set switch phy flow control, port is 0~4, enable is 1, disable is 0\n", cmd);
+	printf(" 2.8) %s phy an [port_num] [enable 0|1]				- set switch phy auto-negotiation, port is 0~4, enable is 1, disable is 0\n", cmd);
 	printf(" 2.9) %s trreg r [port_num] [ch_addr] [node_addr] [data_addr]	- read phy token-ring of specific port\n", cmd);
 	printf(" 2.10) %s trreg w [port_num] [ch_addr] [node_addr] [data_addr]	- write phy token-ring of specific port\n", cmd);
-	printf("		[high_value] [low_value]									\n");
+	printf("		[high_value] [low_value]\n");
 	printf(" 2.11) %s crossover [port_num] [mode auto|mdi|mdix]		- switch auto or force mdi/mdix mode for crossover cable\n", cmd);
-	printf("																			\n");
+	printf("\n");
 
 	/* 3. mac operations */
 	printf("3) mt753x switch MAC operations====================================================================================================================>>>>\n");
@@ -65,35 +69,35 @@
 	printf(" 3.11) %s filt [mac] [portmap]					- add a SA filtering entry (with portmap)to switch mac table\n", cmd);
 	printf(" 3.12) %s filt [mac] [portmap] [vlan id				- add a SA filtering entry (with portmap, vlan id)to switch mac table\n", cmd);
 	printf(" 3.13) %s filt [mac] [portmap] [vlan id] [age]			- add a SA filtering entry (with portmap, vlan id, age out time) to switch table\n", cmd);
-	printf(" 3.14) %s arl aging [active:0|1] [time:1~65536]			- set switch arl aging timeout value \n", cmd);
-	printf(" 3.15) %s macctl fc [enable|disable]				- set switch mac global flow control,enable is 1, disable is 0 \n", cmd);
-	printf("																			\n");
+	printf(" 3.14) %s arl aging [active:0|1] [time:1~65536]			- set switch arl aging timeout value\n", cmd);
+	printf(" 3.15) %s macctl fc [enable|disable]				- set switch mac global flow control,enable is 1, disable is 0\n", cmd);
+	printf("\n");
 
 	/* 4. mib counter operations */
 	printf("4) mt753x switch mib counter operations============================================================================================================>>>>\n");
-	printf(" 4.1) %s esw_cnt get						-get switch mib counters          \n", cmd);
-	printf(" 4.2) %s esw_cnt clear						-clear switch mib counters         \n", cmd);
-	printf(" 4.3) %s output_queue_cnt get					-get switch output queue counters \n", cmd);
-	printf(" 4.4) %s free_page get						-get switch system free page counters  \n", cmd);
-	printf("																			\n");
+	printf(" 4.1) %s esw_cnt get						-get switch mib counters\n", cmd);
+	printf(" 4.2) %s esw_cnt clear						-clear switch mib counters\n", cmd);
+	printf(" 4.3) %s output_queue_cnt get					-get switch output queue counters\n", cmd);
+	printf(" 4.4) %s free_page get						-get switch system free page counters\n", cmd);
+	printf("\n");
 
 	/* 5. acl function operations */
 	printf("5) mt753x switch acl function operations============================================================================================================>>>>\n");
-	printf(" 5.1) %s acl enable [port] [port_enable:0|1]			- set switch acl function enabled, port is 0~6,enable is 1, disable is 0  \n", cmd);
-	printf(" 5.2) %s acl etype add [ethtype] [portmap]			- drop L2 ethertype packets \n", cmd);
-	printf(" 5.3) %s acl dmac add [mac] [portmap]				- drop L2 dest-Mac packets \n", cmd);
-	printf(" 5.4) %s acl dip add [dip] [portmap]				- drop dip packets \n", cmd);
+	printf(" 5.1) %s acl enable [port] [port_enable:0|1]			- set switch acl function enabled, port is 0~6,enable is 1, disable is 0\n", cmd);
+	printf(" 5.2) %s acl etype add [ethtype] [portmap]			- drop L2 ethertype packets\n", cmd);
+	printf(" 5.3) %s acl dmac add [mac] [portmap]				- drop L2 dest-Mac packets\n", cmd);
+	printf(" 5.4) %s acl dip add [dip] [portmap]				- drop dip packets\n", cmd);
 	printf(" 5.5) %s acl port add [sport] [portmap]				- drop L4 UDP/TCP source port packets\n", cmd);
 	printf(" 5.6) %s acl L4 add [2byes] [portmap]				- drop L4 packets with 2bytes payload\n", cmd);
-	printf(" 5.7) %s acl acltbl-add  [tbl_idx:0~63/255] [vawd1] [vawd2]	- set switch acl table new entry, max index-7530:63,7531:255 \n", cmd);
-	printf(" 5.8) %s acl masktbl-add [tbl_idx:0~31/127] [vawd1] [vawd2]	- set switch acl mask table new entry, max index-7530:31,7531:127   \n", cmd);
-	printf(" 5.9) %s acl ruletbl-add [tbl_idx:0~31/127] [vawd1] [vawd2]	- set switch acl rule table new entry, max index-7530:31,7531:127  \n", cmd);
-	printf(" 5.10) %s acl ratetbl-add [tbl_idx:0~31] [vawd1] [vawd2] 	- set switch acl rate table new entry  \n", cmd);
-	printf(" 5.11) %s acl dip meter [dip] [portmap][meter:kbps]		- rate limit dip packets \n", cmd);
-	printf(" 5.12) %s acl dip trtcm [dip] [portmap][CIR:kbps][CBS][PIR][PBS]- TrTCM dip packets \n", cmd);
-	printf(" 5.13) %s acl dip modup [dip] [portmap][usr_pri]		- modify usr priority from ACL \n", cmd);
-	printf(" 5.14) %s acl dip pppoe [dip] [portmap]				- pppoe header removal \n", cmd);
-	printf("																			\n");
+	printf(" 5.7) %s acl acltbl-add  [tbl_idx:0~63/255] [vawd1] [vawd2]	- set switch acl table new entry, max index-7530:63,7531:255\n", cmd);
+	printf(" 5.8) %s acl masktbl-add [tbl_idx:0~31/127] [vawd1] [vawd2]	- set switch acl mask table new entry, max index-7530:31,7531:127\n", cmd);
+	printf(" 5.9) %s acl ruletbl-add [tbl_idx:0~31/127] [vawd1] [vawd2]	- set switch acl rule table new entry, max index-7530:31,7531:127\n", cmd);
+	printf(" 5.10) %s acl ratetbl-add [tbl_idx:0~31] [vawd1] [vawd2]	- set switch acl rate table new entry\n", cmd);
+	printf(" 5.11) %s acl dip meter [dip] [portmap][meter:kbps]		- rate limit dip packets\n", cmd);
+	printf(" 5.12) %s acl dip trtcm [dip] [portmap][CIR:kbps][CBS][PIR][PBS]- TrTCM dip packets\n", cmd);
+	printf(" 5.13) %s acl dip modup [dip] [portmap][usr_pri]		- modify usr priority from ACL\n", cmd);
+	printf(" 5.14) %s acl dip pppoe [dip] [portmap]				- pppoe header removal\n", cmd);
+	printf("\n");
 
 	/* 6. dip table operations */
 	printf("6) mt753x switch dip table operations=================================================================================================================>>>>\n");
@@ -101,7 +105,7 @@
 	printf(" 6.2) %s dip clear						- clear switch dip table\n", cmd);
 	printf(" 6.3) %s dip add [dip] [portmap]				- add a dip entry to switch table\n", cmd);
 	printf(" 6.4) %s dip del [dip]						- del a dip entry to switch table\n", cmd);
-	printf("																			\n");
+	printf("\n");
 
 	/* 7. sip table operations */
 	printf("7) mt753x switch sip table operations=================================================================================================================>>>>\n");
@@ -109,36 +113,36 @@
 	printf(" 7.2) %s sip clear						- clear switch sip table\n", cmd);
 	printf(" 7.3) %s sip add [sip] [dip] [portmap]				- add a sip entry to switch table\n", cmd);
 	printf(" 7.4) %s sip del [sip] [dip]					- del a sip entry to switch table\n", cmd);
-	printf("																			\n");
+	printf("\n");
 
 	/* 8. vlan table operations */
 	printf("8) mt753x switch sip table operations====================================================================================================================>>>>\n");
 	printf(" 8.1) %s vlan dump (egtag)					- dump switch vlan table (with per port eg_tag setting)\n", cmd);
 	printf(" 8.2) %s vlan set [fid:0~7] [vid] [portmap]			- set vlan id and associated member at switch vlan table\n", cmd);
-	printf("			([stag:0~4095] [eg_con:0|1] [egtagPortMap 0:untagged 2:tagged]) \n");
+	printf("			([stag:0~4095] [eg_con:0|1] [egtagPortMap 0:untagged 2:tagged])\n");
 	printf("			Full Example: %s vlan set 0 3 10000100 0 0 20000200\n", cmd);
-	printf(" 8.3) %s vlan vid [vlan idx] [active:0|1] [vid] [portMap] 	- set switch vlan vid elements  \n", cmd);
-	printf("			[egtagPortMap] [ivl_en] [fid] [stag]							 \n");
-	printf(" 8.4) %s vlan pvid [port] [pvid]				- set switch vlan pvid  \n", cmd);
-	printf(" 8.5) %s vlan acc-frm [port] [acceptable_frame_type:0~3]	- set switch vlan acceptable_frame type : admit all frames: 0, \n", cmd);
-	printf("									admit only vlan-taged frames: 1,admit only untagged or priority-tagged frames: 2, reserved:3 \n");
-	printf(" 8.6) %s vlan port-attr [port] [attr:0~3]			- set switch vlan port attribute: user port: 0, statck port: 1, \n", cmd);
-	printf("									translation port: 2, transparent port:3        \n");
-	printf(" 8.7) %s vlan port-mode [port] [mode:0~3]			- set switch vlan port mode : port matrix mode: 0, fallback mode: 1,  \n", cmd);
-	printf("									check mode: 2, security mode:3                    \n");
-	printf(" 8.8) %s vlan eg-tag-pvc [port] [eg_tag:0~7]			- set switch vlan eg tag pvc : disable: 0, consistent: 1, reserved: 2, \n", cmd);
-	printf("									reserved:3,untagged:4,swap:5,tagged:6, stack:7                 \n");
-	printf(" 8.9) %s vlan eg-tag-pcr [port] [eg_tag:0~3]			- set switch vlan eg tag pcr : untagged: 0, swap: 1, tagged: 2, stack:3 \n", cmd);
-	printf("																			\n");
+	printf(" 8.3) %s vlan vid [vlan idx] [active:0|1] [vid] [portMap]	- set switch vlan vid elements\n", cmd);
+	printf("			[egtagPortMap] [ivl_en] [fid] [stag]\n");
+	printf(" 8.4) %s vlan pvid [port] [pvid]				- set switch vlan pvid\n", cmd);
+	printf(" 8.5) %s vlan acc-frm [port] [acceptable_frame_type:0~3]	- set switch vlan acceptable_frame type : admit all frames: 0,\n", cmd);
+	printf("									admit only vlan-taged frames: 1,admit only untagged or priority-tagged frames: 2, reserved:3\n");
+	printf(" 8.6) %s vlan port-attr [port] [attr:0~3]			- set switch vlan port attribute: user port: 0, statck port: 1,\n", cmd);
+	printf("									translation port: 2, transparent port:3\n");
+	printf(" 8.7) %s vlan port-mode [port] [mode:0~3]			- set switch vlan port mode : port matrix mode: 0, fallback mode: 1,\n", cmd);
+	printf("									check mode: 2, security mode:3\n");
+	printf(" 8.8) %s vlan eg-tag-pvc [port] [eg_tag:0~7]			- set switch vlan eg tag pvc : disable: 0, consistent: 1, reserved: 2,\n", cmd);
+	printf("									reserved:3,untagged:4,swap:5,tagged:6, stack:7\n");
+	printf(" 8.9) %s vlan eg-tag-pcr [port] [eg_tag:0~3]			- set switch vlan eg tag pcr : untagged: 0, swap: 1, tagged: 2, stack:3\n", cmd);
+	printf("\n");
 
 	/* 9. rate limit operations */
 	printf("9) mt753x switch rate limit operations=================================================================================================================>>>>\n");
-	printf(" 9.1) %s ratectl [in_ex_gress:0|1] [port] [rate]		- set switch port ingress(1) or egress(0) rate  \n", cmd);
-	printf(" 9.2) %s ingress-rate on [port] [Kbps]				- set ingress rate limit on port n (n= 0~ switch max port) \n", cmd);
-	printf(" 9.3) %s egress-rate on [port] [Kbps]				- set egress rate limit on port n (n= 0~ switch max port) \n", cmd);
-	printf(" 9.4) %s ingress-rate off [port]				- disable ingress rate limit on port n (n= 0~ switch max port) \n", cmd);
+	printf(" 9.1) %s ratectl [in_ex_gress:0|1] [port] [rate]		- set switch port ingress(1) or egress(0) rate\n", cmd);
+	printf(" 9.2) %s ingress-rate on [port] [Kbps]				- set ingress rate limit on port n (n= 0~ switch max port)\n", cmd);
+	printf(" 9.3) %s egress-rate on [port] [Kbps]				- set egress rate limit on port n (n= 0~ switch max port)\n", cmd);
+	printf(" 9.4) %s ingress-rate off [port]				- disable ingress rate limit on port n (n= 0~ switch max port)\n", cmd);
 	printf(" 9.5) %s egress-rate off [port]					- disable egress rate limit on port n (n= 0~ switch max port)\n", cmd);
-	printf("																			\n");
+	printf("\n");
 
 	/* 10. igmp operations */
 	printf("10) mt753x igmp operations===============================================================================================================================>>>>\n");
@@ -147,37 +151,37 @@
 	printf(" 10.2) %s igmpsnoop off						- turn off IGMP snoop and router port learning\n", cmd);
 	printf(" 10.3) %s igmpsnoop enable [port#]				- enable IGMP HW leave/join/Squery/Gquery\n", cmd);
 	printf(" 10.4) %s igmpsnoop disable [port#]				- disable IGMP HW leave/join/Squery/Gquery\n", cmd);
-	printf("																			\n");
+	printf("\n");
 
 	/* 11. QoS operations */
 	printf("11) mt753x QoS operations================================================================================================================================>>>>\n");
-	printf(" 11.1) %s qos sch [port:0~6] [queue:0~7] [shaper:min|max] [type:rr:0|sp:1|wfq:2]     - set switch qos sch type\n", cmd);
-	printf(" 11.2) %s qos base [port:0~6] [base]					- set switch qos base(UPW); port-based:0, tag-based:1, \n", cmd);
-	printf("									dscp-based:2, acl-based:3, arl-based:4, stag-based:5   \n");
-	printf(" 11.3) %s qos port-weight [port:0~6] [q0] [q1][q2][q3]		- set switch qos port queue weight; \n", cmd);
-	printf("				[q4][q5][q6][q7]				 [qn]: the weight of queue n, range: 1~16     \n");
-	printf(" 11.4) %s qos port-prio [port:0~6] [prio:0~7]			- set switch port qos user priority;  port is 0~6, priority is 0~7  \n", cmd);
-	printf(" 11.5) %s qos dscp-prio [dscp:0~63] [prio:0~7]			- set switch qos dscp user priority;  dscp is 0~63, priority is 0~7  \n", cmd);
-	printf(" 11.6) %s qos prio-qmap [port:0~6] [prio:0~7]  [queue:0~7]			- set switch qos priority queue map; priority is 0~7,queue is 0~7  \n", cmd);
-	printf("																			\n");
+	printf(" 11.1) %s qos sch [port:0~6] [queue:0~7] [shaper:min|max] [type:rr:0|sp:1|wfq:2]	 - set switch qos sch type\n", cmd);
+	printf(" 11.2) %s qos base [port:0~6] [base]					- set switch qos base(UPW); port-based:0, tag-based:1,\n", cmd);
+	printf("									dscp-based:2, acl-based:3, arl-based:4, stag-based:5\n");
+	printf(" 11.3) %s qos port-weight [port:0~6] [q0] [q1][q2][q3]		- set switch qos port queue weight;\n", cmd);
+	printf("				[q4][q5][q6][q7]				 [qn]: the weight of queue n, range: 1~16\n");
+	printf(" 11.4) %s qos port-prio [port:0~6] [prio:0~7]			- set switch port qos user priority;  port is 0~6, priority is 0~7\n", cmd);
+	printf(" 11.5) %s qos dscp-prio [dscp:0~63] [prio:0~7]			- set switch qos dscp user priority;  dscp is 0~63, priority is 0~7\n", cmd);
+	printf(" 11.6) %s qos prio-qmap [port:0~6] [prio:0~7]  [queue:0~7]			- set switch qos priority queue map; priority is 0~7,queue is 0~7\n", cmd);
+	printf("\n");
 
 	/*12. port mirror operations*/
 	printf(" 12) mt753x port mirror operations========================================================================================================================>>>>\n");
 	printf(" 12.1) %s mirror monitor [port]					- enable port mirror and indicate monitor port number\n", cmd);
 	printf(" 12.2) %s mirror target  [port]					- set port mirror target\n", cmd);
-	printf("			[direction| 0:off, 1:rx, 2:tx, 3:all]					\n");
-	printf(" 12.3) %s mirror enable [mirror_en:0|1] [mirror_port: 0-6]	- set switch mirror function enable(1) or disabled(0) for port 0~6  \n", cmd);
+	printf("			[direction| 0:off, 1:rx, 2:tx, 3:all]\n");
+	printf(" 12.3) %s mirror enable [mirror_en:0|1] [mirror_port: 0-6]	- set switch mirror function enable(1) or disabled(0) for port 0~6\n", cmd);
 	printf(" 12.4) %s mirror port-based [port] [port_tx_mir:0|1]		- set switch mirror port: target tx/rx/acl/vlan/igmp\n", cmd);
-	printf("				[port_rx_mir:0|1] [acl_mir:0|1]						\n");
-	printf("				[vlan_mis:0|1] [igmp_mir:0|1]						\n");
-	printf("																			\n");
+	printf("				[port_rx_mir:0|1] [acl_mir:0|1]\n");
+	printf("				[vlan_mis:0|1] [igmp_mir:0|1]\n");
+	printf("\n");
 
 	/*13. stp function*/
 	printf(" 13) mt753x stp operations===============================================================================================================================>>>>\n");
-	printf(" 13.1) %s stp [port] [fid] [state]				- set switch spanning tree state, port is 0~6, fid is 0~7,  \n", cmd);
-	printf("									state is 0~3(Disable/Discarding:0,Blocking/Listening/Discarding:1,) \n");
-	printf("									Learning:2,Forwarding:3 \n");
-	printf("																			\n");
+	printf(" 13.1) %s stp [port] [fid] [state]				- set switch spanning tree state, port is 0~6, fid is 0~7,\n", cmd);
+	printf("									state is 0~3(Disable/Discarding:0,Blocking/Listening/Discarding:1,)\n");
+	printf("									Learning:2,Forwarding:3\n");
+	printf("\n");
 
 	/*14. collision pool operations*/
 	printf("14) mt753x collision pool operations========================================================================================================================>>>>\n");
@@ -185,20 +189,235 @@
 	printf(" 14.2) %s collision-pool mac dump				- dump collision pool mac table\n", cmd);
 	printf(" 14.3) %s collision-pool dip dump				- dump collision pool dip table\n", cmd);
 	printf(" 14.4) %s collision-pool sip dump				- dump collision pool sip table\n", cmd);
-	printf("																			\n");
+	printf("\n");
 
 	/*15. pfc(priority flow control) operations*/
 	printf("15) mt753x pfc(priority flow control) operations==============================================================================================================>>>>\n");
-	printf(" 15.1) %s pfc enable [port] [enable 0|1]			- enable or disable port's pfc \n", cmd);
-	printf(" 15.2) %s pfc rx_counter [port]					- get port n pfc 8 up rx counter \n", cmd);
-	printf(" 15.3) %s pfc tx_counter [port]					- get port n pfc 8 up rx counter \n", cmd);
-	printf("																			\n");
+	printf(" 15.1) %s pfc enable [port] [enable 0|1]			- enable or disable port's pfc\n", cmd);
+	printf(" 15.2) %s pfc rx_counter [port]					- get port n pfc 8 up rx counter\n", cmd);
+	printf(" 15.3) %s pfc tx_counter [port]					- get port n pfc 8 up rx counter\n", cmd);
+	printf("\n");
 
 	/*15. pfc(priority flow control) operations*/
 	printf("16) mt753x EEE(802.3az) operations==============================================================================================================>>>>\n");
 	printf(" 16.1) %s eee enable [enable 0|1] ([portMap])			- enable or disable EEE (by portMap)\n", cmd);
 	printf(" 16.2) %s eee dump ([port])					- dump EEE capability (by port)\n", cmd);
-	printf("																			\n");
+	printf("\n");
+
+	if (chip_name == 0x8855) {
+		printf("switch an8855 <sub cmd> supported commands===================================================================================================================>>>>\n");
+		printf("\n");
+		printf("Register/GPHY access commands===============================================================================================================>>>>\n");
+		printf("reg r <reg(4'hex)>\n");
+		printf("reg w <reg(4'hex)> <value(8'hex)>\n");
+		printf("phy cl22 r <port(0..4)> <reg(2'hex)>\n");
+		printf("phy cl22 w <port(0..4)> <reg(2'hex)> <value(4'hex)>\n");
+		printf("phy cl45 r <port(0..4)> <dev(2'hex)> <reg(3'hex)>\n");
+		printf("phy cl45 w <port(0..4)> <dev(2'hex)> <reg(3'hex)> <value(4'hex)>\n");
+		printf("\n");
+		printf("Port configuration commands=================================================================================================================>>>>\n");
+		printf("port set matrix <port(0..6)> <matrix(6:0)>\n");
+		printf("port get matrix <port(0..6)>\n");
+		printf("port set vlanMode <port(0..6)> <vlanMode(0:matrix,1:fallback,2:check,3:security)>\n");
+		printf("port get vlanMode <port(0..6)>\n");
+		printf("port set flowCtrl <port(0..6)> <dir(0:Tx,1:Rx)> <fc_en(1:En,0:Dis)>\n");
+		printf("port get flowCtrl <port(0..6)> <dir(0:Tx,1:Rx)>\n");
+		printf("port set jumbo <pkt_len(0:1518,1:1536,2:1552,3:max)> <frame_len(2..15)>\n");
+		printf("port get jumbo\n");
+		printf("port set anMode <port(0..4)> <en(0:force,1:AN)>\n");
+		printf("port get anMode <port(0..4)>\n");
+		printf("port set localAdv <port(0..4)> <10H(1:En,0:Dis)> <10F(1:En,0:Dis)> <100H(1:En,0:Dis)> <100F(1:En,0:Dis)> <1000F(1:En,0:Dis)> <pause(1:En,0:Dis)>\n");
+		printf("port get localAdv <port(0..4)>\n");
+		printf("port get remoteAdv <port(0..4)>\n");
+		printf("port set speed <port(0..4)> <speed(0:10M,1:100M,2:1G,3:2.5G)>\n");
+		printf("port get speed <port(0..4)>\n");
+		printf("port set duplex <port(0..4)> <duplex(0:half,1:full)>\n");
+		printf("port get duplex <port(0..4)>\n");
+		printf("port get status <port(0..4)>\n");
+		printf("port set bckPres <port(0..6)> <bckPres(1:En,0:Dis)>\n");
+		printf("port get bckPres <port(0..6)>\n");
+		printf("port set psMode <port(0..4)> <ls(1:En,0:Dis)> <eee(1:En,0:Dis)>\n");
+		printf("port get psMode <port(0..4)>\n");
+		printf("port set smtSpdDwn <port(0..4)> <en(1:En,0:Dis)> <retry(2..5)>\n");
+		printf("port get smtSpdDwn <port(0..4)>\n");
+		printf("port set spTag <port(0..6)> <en(1:En,0:Dis)>\n");
+		printf("port get spTag <port(0..6)>\n");
+		printf("port set enable <port(0..4)> <en(1:En,0:Dis)>\n");
+		printf("port get enable <port(0..4)>\n");
+		printf("port set 5GBaseRMode\n");
+		printf("port set hsgmiiMode\n");
+		printf("port set sgmiiMode <mode(0:AN,1:Force)> <speed(0:10M,1:100M,2:1G)>\n");
+		printf("port set rmiiMode <speed(0:10M,1:100M)>\n");
+		printf("port set rgmiiMode <speed(0:10M,1:100M,2:1G)>\n");
+		printf("\n");
+		printf("Special tag commands========================================================================================================================>>>>\n");
+		printf("sptag  setEnable port<port(0..6)> enable<1:enable 0:disable>\n");
+		printf("sptag  getEnable port<port(0..6)>\n");
+		printf("sptag  setmode port<port(0..6)> mode<0:inset 1:replace>\n");
+		printf("sptag  getmode port<port(0..6)>\n");
+		printf("sptag  encode mode={ insert | replace } opc={ portmap | portid | lookup } dp={bitimap hex} vpm={ untagged | 8100 | 88a8 } pri=<UINT> cfi=<UINT> vid=<UINT>\n");
+		printf("sptag  decode <byte(hex)> <byte(hex)> <byte(hex)> <byte(hex)>\n");
+		printf("\n");
+		printf("Vlan commands===============================================================================================================================>>>>\n");
+		printf("sptag  set fid <vid(0..4095)> <fid(0..7)>\n");
+		printf("sptag  set memPort <vid(0..4095)> <bitmap(6:0)>\n");
+		printf("sptag  set ivl <vid(0..4095)> <(1:En,0:Dis)>\n");
+		printf("sptag  set portBaseStag <vid(0..4095)> <(1:En,0:Dis)>\n");
+		printf("sptag  set stag <vid(0..4095)> <stag(0..4095)>\n");
+		printf("sptag  set egsTagCtlEn <vid(0..4095)> <(1:En,0:Dis)>\n");
+		printf("sptag  set egsTagCtlCon <vid(0..4095)> <(1:En,0:Dis)>\n");
+		printf("sptag  set egsTagCtl <vid(0..4095)> <port(0..6)> <ctlType(0:untag,2:tagged)>\n");
+		printf("sptag  set portActFrame <port(0..6)> <frameType(0:all,1:tagged,2:untagged)>\n");
+		printf("sptag  get portActFrame <port(0..6)>\n");
+		printf("sptag  set LeakyVlanEn <port(0..6)> <pktType(0:uc,1:mc,2:bc,3:ipmc)> <(1:En,0:Dis)>\n");
+		printf("sptag  get leakyVlanEn <port(0..6)>\n");
+		printf("sptag  set portVlanAttr <port(0..6)> <vlanAttr(0:user,1:stack,2:translation,3:transparent)>\n");
+		printf("sptag  get portVlanAttr <port(0..6)>\n");
+		printf("sptag  set igsPortETagAttr <port(0..6)> <egsTagAttr(0:disable,1:consistent,4:untagged,5:swap,6:tagged,7:stack)>\n");
+		printf("sptag  get igsPortETagAttr <port(0..6)>\n");
+		printf("sptag  set portEgsTagAttr <port(0..6)> <egsTagAttr(0:untagged,1:swap,2:tagged,3:stack)>\n");
+		printf("sptag  get portEgsTagAttr <port(0..6)>\n");
+		printf("sptag  set portOuterTPID <port(0..6)> <TPID(hex)>\n");
+		printf("sptag  get portOuterTPID <port(0..6)>\n");
+		printf("sptag  set pvid <port(0..6)> <vid(0..4095)>\n");
+		printf("sptag  get pvid <port(0..6)>\n");
+		printf("sptag  initiate <vid(0..4095)> <fid(0..7)> <bitmap(6:0)> <ivl(1:En,0:Dis)> <portbasestag(1:En,0:Dis)> <stag(0..4095)> <egstagctlen(1:En,0:Dis)> <egstagcon(1:En,0:Dis)> <taggedbitmap(6:0)>\n");
+		printf("sptag  create <vid(0..4095)>\n");
+		printf("sptag  destroy [ <vid(0..4095)> | <vidRange(vid0-vid1)> ]\n");
+		printf("sptag  destroyAll [ <restoreDefVlan(0:false,1:true)> | ]\n");
+		printf("sptag  dump [ <vid(0..4095)> | <vidRange(vid0-vid1)> | ]\n");
+		printf("sptag  addPortMem <vid(0..4095)> <port(0..6)>\n");
+		printf("sptag  addPortMem <vid(0..4095)> <port(0..6)>\n");
+		printf("\n");
+		printf("Layer2 commands=============================================================================================================================>>>>\n");
+		printf("l2 dump mac\n");
+		printf("l2 add mac <static(0:dynamic,1:static)> <unauth(0:auth,1:unauth)> <mac(12'hex)> <portlist(uintlist)> [ vid <vid(0..4095)> | fid <fid(0..15)> ] <src_mac_forward=(0:default,1:cpu-exclude,2:cpu-include,3:cpu-only,4:drop)>\n");
+		printf("l2 del mac <mac(12'hex)> [ vid <vid(0..4095)> | fid <fid(0..15)> ]\n");
+		printf("l2 get mac <mac(12'hex)> [ vid <vid(0..4095)> | fid <fid(0..15)> ]\n");
+		printf("l2 clear mac\n");
+		printf("l2 set macAddrAgeOut <time(1, 1000000)>\n");
+		printf("l2 get macAddrAgeOut\n");
+		printf("\n");
+		printf("Link Aggregation commands===================================================================================================================>>>>\n");
+		printf("lag set member <group_id(0 or 1)> <member_index(0..3)> <enable(0,1)> <port index(0..6)>\n");
+		printf("lag get member group_id(0 or 1)\n");
+		printf("lag set dstInfo <sp(1:En,0:Dis)> <sa(1:En,0:Dis)> <da(1:En,0:Dis)> <sip(1:En,0:Dis)> <dip(1:En,0:Dis)> <sport(1:En,0:Dis)> <dport(1:En,0:Dis)>\n");
+		printf("lag get dstInfo\n");
+		printf("lag set ptseed <hex32>\n");
+		printf("lag get ptseed\n");
+		printf("lag set hashtype <0-crc32lsb;1-crc32msb;2-crc16;3-xor4>\n");
+		printf("lag get hashtype\n");
+		printf("lag set state <state(1:En,0:Dis)>\n");
+		printf("lag get state\n");
+		printf("lag set spsel <soure port enable(1:En,0:Dis)>\n");
+		printf("lag get spsel\n");
+		printf("\n");
+		printf("STP commands================================================================================================================================>>>>\n");
+		printf("stp set portstate <port(0..6)> <fid(0..15)> <state(0:disable,1:listen,2:learn,3:forward)>\n");
+		printf("stp get portstate <port(0..6)> <fid(0..15)>\n");
+		printf("\n");
+		printf("Mirror commands=============================================================================================================================>>>>\n");
+		printf("mirror set session <sid(0,1)> <dst_port(UINT)> <state(1:En,0:Dis)> <tag(1:on, 0:off)> <list(UINTLIST)> <dir(0:none,1:tx,2:rx,3:both)>\n");
+		printf("mirror set session-enable <sid(0,1)> <state(1:En,0:Dis)>\n");
+		printf("mirror add session-rlist <sid(0,1)> <list(UINTLIST)>\n");
+		printf("mirror add session-tlist <sid(0,1)> <list(UINTLIST)>\n");
+		printf("mirror get session <sid(0,1)>\n");
+		printf("mirror del session <sid(0,1)>\n");
+		printf("\n");
+		printf("MIB commands================================================================================================================================>>>>\n");
+		printf("mib get port <port(0..6)>\n");
+		printf("mib get acl <event(0..7)>\n");
+		printf("mib clear port <port(0..6)>\n");
+		printf("mib clear all\n");
+		printf("mib clear acl\n");
+		printf("\n");
+		printf("QoS commands================================================================================================================================>>>>\n");
+		printf("qos set scheduleAlgo <portlist(UINTLIST)> <queue(UINT)> <scheduler(0:SP,1:WRR,2:WFQ)> <weight(0..128)>, weight 0 is valid only on sp mode\n");
+		printf("qos get scheduleAlgo <portlist(UINTLIST)> <queue(UINT)>\n");
+		printf("qos set trustMode <portlist(UINTLIST)> <mode(0:port,1:1p-port,2:dscp-port,3:dscp-1p-port>\n");
+		printf("qos get trustMode <portlist(UINTLIST)>\n");
+		printf("qos set pri2Queue <priority(0..7)> <queue(0..7)>\n");
+		printf("qos get pri2Queue\n");
+		printf("qos set dscp2Pri <dscp(0..63)> <priority(0..7)>\n");
+		printf("qos get dscp2Pri <dscp(0..63)>\n");
+		printf("qos set rateLimitEnable <portlist(UINTLIST)> <dir(0:egress,1:ingress)> <rate_en(1:En,0:Dis)>\n");
+		printf("qos get rateLimitEnable <portlist(UINTLIST)>\n");
+		printf("qos set rateLimit <portlist(UINTLIST)> <I_CIR(0..80000)> <I_CBS(0..127)> <E_CIR(0..80000)> <E_CBS(0..127)>\n");
+		printf("qos get rateLimit <portlist(UINTLIST)>\n");
+		printf("qos set portPriority <portlist(UINTLIST)> <priority(0..7)>\n");
+		printf("qos get portPriority <portlist(UINTLIST)>\n");
+		printf("qos set rateLmtExMngFrm <dir(0:egress)> <en(0:include,1:exclude)>\n");
+		printf("qos get rateLmtExMngFrm\n");
+		printf("\n");
+		printf("Diag commands===============================================================================================================================>>>>\n");
+		printf("diag set txComply <phy(0..4)> <mode(0..8)>\n");
+		printf("diag get txComply <phy(0..4)>\n");
+		printf("\n");
+		printf("LED commands================================================================================================================================>>>>\n");
+		printf("led set mode <mode(0:disable, 1..3:2 LED, 4:user-define)>\n");
+		printf("led get mode\n");
+		printf("led set state <led(0..1)> <state(1:En,0:Dis)>\n");
+		printf("led get state <led(0..1)>\n");
+		printf("led set usr <led(0..1)> <polarity(0:low, 1:high)> <on_evt(7'bin)> <blink_evt(10'bin)>\n");
+		printf("led get usr <led(0..1)>\n");
+		printf("led set time <time(0..5:32ms~1024ms)>\n");
+		printf("led get time\n");
+		printf("\n");
+		printf("Security commands===========================================================================================================================>>>>\n");
+		printf("sec set stormEnable <port(0..6)> <type(0:bcst,1:mcst,2:ucst)> <en(1:En,0:Dis)>\n");
+		printf("sec get stormEnable <port(0..6)> <type(0:bcst,1:mcst,2:ucst)>\n");
+		printf("sec set stormRate <port(0..6)> <type(0:bcst,1:mcst,2:ucst)> <count(0..255)> <unit(0:64k,1:256k,2:1M,3:4M,4:16M)>\n");
+		printf("sec get stormRate <port(0..6)> <type(0:bcst,1:mcst,2:ucst)>\n");
+		printf("sec set fldMode <port(0..6)> <type(0:bcst,1:mcst,2:ucst,3:qury> <en(1:En,0:Dis)>\n");
+		printf("sec get fldMode <port(0..6)> <type(0:bcst,1:mcst,2:ucst,3:qury>\n");
+		printf("sec set saLearning <port(0..6)> <learn(0:disable,1:enable)>\n");
+		printf("sec get saLearning <port(0..6)>\n");
+		printf("sec set saLimit <port(0..6)> <mode(0:disable,1:enable)> <count(0..4095)>\n");
+		printf("sec get saLimit <port(0..6)>\n");
+		printf("\n");
+		printf("Switch commands=============================================================================================================================>>>>\n");
+		printf("switch set cpuPortEn <cpu_en(1:En,0:Dis)>\n");
+		printf("switch get cpuPortEn\n");
+		printf("switch set cpuPort <port_number>\n");
+		printf("switch get cpuPort\n");
+		printf("switch set phyLCIntrEn <phy(0..6)> <(1:En,0:Dis)>\n");
+		printf("switch get phyLCIntrEn <phy(0..6)>\n");
+		printf("switch set phyLCIntrSts <phy(0..6)> <(1:Clear)>\n");
+		printf("switch get phyLCIntrSts <phy(0..6)>\n");
+		printf("\n");
+		printf("ACL commands================================================================================================================================>>>>\n");
+		printf("acl set en <en(1:En,0:Dis)>\n");
+		printf("acl get en\n");
+		printf("acl set rule <idx(0..127)>\n <state(0:Dis,1:En)> <reverse(0:Dis,1:En)> <end(0:Dis,1:En)>\n <portmap(7'bin)><ipv6(0:Dis,1:En,2:Not care)>\n[ dmac <dmac(12'hex)> <dmac_mask(12'hex)> ]\n[ smac <smac(12'hex)> <smac_mask(12'hex)> ]\n[ stag <stag(4'hex)> <stag_mask(4'hex)> ]\n[ ctag <ctag(4'hex)> <ctag_mask(4'hex)> ]\n[ etype <etype(4'hex)> <etype_mask(4'hex)> ]\n[ dip <dip(IPADDR)> <dip_mask(IPADDR)> ]\n[ sip <sip(IPADDR)> <sip_mask(IPADDR)> ]\n[ dscp <dscp(2'hex)> <dscp_mask(2'hex)> ]\n[ protocol <protocol(12'hex)> <protocol_mask(12'hex)> ]\n[ dport <dport(4'hex)> <dport_mask(4'hex)> ]\n[ sport <sport(4'hex)> <sport_mask(4'hex)> ]\n[ flow_label <flow_label(4'hex)> <flow_label_mask(4'hex)> ]\n[ udf <udf(4'hex)> <udf_mask(4'hex)> ] ");
+		printf("acl get rule <idx(0..127)> ");
+		printf("acl del rule <idx(0..127)>\n");
+		printf("acl clear rule\n");
+		printf("acl set udfRule <idx(0..15)> <mode(0:pattern, 1:threshold)> [ <pat(4'hex)> <mask(4'hex)> | <low(4'hex)> <high(4'hex)> ] <start(0:MAC header, 1:L2 payload, 2:IPv4 header, 3:IPv6 header, 4:L3 payload, 5:TCP header, 6:UDP header, 7: L4 payload)> <offset(0..127,unit:2 bytes)> <portmap(7'bin)>\n");
+		printf("acl get udfRule <idx(0..15)>\n");
+		printf("acl del udfRule <idx(0..15)>\n");
+		printf("acl clear udfRule\n");
+		printf("acl set action <idx(0..127)>\n[ forward <forward(0:Default,4:Exclude CPU,5:Include CPU,6:CPU only,7:Drop)> ]\n[ egtag <egtag(0:Default,1:Consistent,4:Untag,5:Swap,6:Tag,7:Stack)> ]\n[ mirrormap <mirrormap(2'bin)> ]\n[ priority <priority(0..7)> ]\n[ redirect <redirect(0:Dst,1:Vlan)> <portmap(7'bin)> ]\n[ leaky_vlan <leaky_vlan(1:En,0:Dis)> ]\n[ cnt_idx <cnt_idx(0..63)> ]\n[ rate_idx <rate_idx(0..31)> ]\n[ attack_idx <attack_idx(0..95)> ]\n[ vid <vid(0..4095)> ]\n[ manage <manage(1:En,0:Dis)> ]\n[ bpdu <bpdu(1:En,0:Dis)> ]\n[ class <class(0:Original,1:Defined)>[0..7] ]\n[ drop_pcd <drop_pcd(0:Original,1:Defined)> [red <red(0..7)>][yellow <yellow(0..7)>][green <green(0..7)>] ]\n[ color <color(0:Defined,1:Trtcm)> [ <defined_color(0:Dis,1:Green,2:Yellow,3:Red)> | <trtcm_idx(0..31)> ] ]");
+		printf("acl get action <idx(0..127)>\n");
+		printf("acl del action <idx(0..127)>\n");
+		printf("acl clear action\n");
+		printf("acl set trtcm <idx(1..31)> <cir(4'hex)> <pir(4'hex)> <cbs(4'hex)> <pbs(4'hex)>\n");
+		printf("acl get trtcm <idx(1..31)>\n");
+		printf("acl del trtcm <idx(0..31)>\n");
+		printf("acl clear trtcm\n");
+		printf("acl set trtcmEn <en(1:En,0:Dis)>\n");
+		printf("acl get trtcmEn\n");
+		printf("acl set portEn <port(0..6)> <en(1:En,0:Dis)>\n");
+		printf("acl get portEn <port(0..6)>\n");
+		printf("acl set dropEn <port(0..6)> <en(1:En,0:Dis)>\n");
+		printf("acl get dropEn <port(0..6)>\n");
+		printf("acl set dropThrsh <port(0..6)> <color(0:green,1:yellow,2:red)> <queue(0..7)> <high(0..2047)> <low(0..2047)>\n");
+		printf("acl get dropThrsh <port(0..6)> <color(0:green,1:yellow,2:red)> <queue(0..7)>\n");
+		printf("acl set dropPbb <port(0..6)> <color(0:green,1:yellow,2:red)> <queue(0..7)> <probability(0..1023)>\n");
+		printf("acl get dropPbb <port(0..6)> <color(0:green,1:yellow,2:red)> <queue(0..7)>\n");
+		printf("acl set meter <idx(0..31)> <en(1:En,0:Dis)> <rate(0..65535)>\n Note: Limit rate = rate * 64Kbps");
+		printf("acl get meter <idx(0..31)>\n");
+		printf("\n");
+	}
 
 	exit_free();
 	exit(0);
@@ -227,7 +446,8 @@
 			for (i = 0; i < 16; i++) {
 				printf("0x%08x: ", off + 0x10 * i);
 				for (j = 0; j < 4; j++) {
-					reg_read(off + i * 0x10 + j * 0x4, &val);
+					reg_read(off + i * 0x10 + j * 0x4,
+						 &val);
 					printf(" 0x%08x", val);
 				}
 				printf("\n");
@@ -240,41 +460,48 @@
 
 static int get_chip_name()
 {
-	int temp;
+	int temp = 0, rc = 0;
 	FILE *fp = NULL;
 	char buff[255];
 
-	/*judge 7530*/
+	/*judge jaguar embedded switch */
+	fp = fopen("/proc/device-tree/compatible", "r");
+	if (fp != NULL) {
+		temp = -1;
+		if (fgets(buff, 255, (FILE *) fp) && strstr(buff, "mt7988"))
+			temp = 0x7988;
+
+		rc = fclose(fp);
+		if (rc == 0 && temp == 0x7988)
+			return temp;
+	}
+
+	/*judge 7530 */
 	reg_read((0x7ffc), &temp);
 	temp = temp >> 16;
 	if (temp == 0x7530)
 		return temp;
-	/*judge 7531*/
+
+	/*judge 7531 */
 	reg_read(0x781c, &temp);
 	temp = temp >> 16;
 	if (temp == 0x7531)
 		return temp;
 
-	/*judge jaguar embedded switch*/
-	fp = fopen("/proc/device-tree/compatible", "r");
-	if (fp != NULL) {
-		temp = -1;
-		if (fgets(buff, 255, (FILE *)fp) && strstr(buff, "mt7988"))
-			temp = 0x7988;
-
-		fclose(fp);
+	/*judge an8855 */
+	reg_read(0x10005000, &temp);
+	if (temp == 0x8855)
 		return temp;
-	}
 
 	return -1;
 }
 
 static int phy_operate(int argc, char *argv[])
 {
-	unsigned int port_num;
-	unsigned int dev_num;
-	unsigned int value, cl_value;
-	unsigned int reg;
+	unsigned int port_num = 0;
+	unsigned int dev_num = 0;
+	unsigned int value = 0, cl_value = 0;
+	unsigned int reg = 0;
 	int ret = 0, cl_ret = 0;
 	char op;
 
@@ -283,65 +510,125 @@
 
 	op = argv[3][0];
 
-	switch(op) {
-		case 'r':
-			reg = strtoul(argv[argc-1], NULL, 0);
-			if (argc == 6) {
-				port_num = strtoul(argv[argc-2], NULL, 0);
-				ret = mii_mgr_read(port_num, reg, &value);
-				if (ret < 0)
-					printf(" Phy read reg fail\n");
-				else
-					printf(" Phy read reg=0x%x, value=0x%x\n", reg, value);
-			} else if (argc == 7) {
-				dev_num = strtoul(argv[argc-2], NULL, 0);
-				port_num = strtoul(argv[argc-3], NULL, 0);
-				ret = mii_mgr_c45_read(port_num, dev_num, reg, &value);
-				if (ret < 0)
-					printf(" Phy read reg fail\n");
-				else
-					printf(" Phy read reg=0x%x, value=0x%x\n", reg, value);
-			} else
-				ret = phy_dump(32);
+	switch (op) {
+	case 'r':
+		reg = strtoul(argv[argc - 1], NULL, 16);
+		if (reg >= 0xFFFFFFFF) {
+			printf(" Phy read reg fail\n");
+			ret = -1;
 			break;
-		case 'w':
-			reg = strtoul(argv[argc-2], NULL, 0);
-			value = strtoul(argv[argc-1], NULL, 0);
-			if (argc == 7) {
-				port_num = strtoul(argv[argc-3], NULL, 0);
-				ret = mii_mgr_write(port_num, reg, value);
-				cl_ret = mii_mgr_read(port_num, reg, &cl_value);
-				if (cl_ret < 0)
-					printf(" Phy read reg fail\n");
-				else
-					printf(" Phy read reg=0x%x, value=0x%x\n", reg, cl_value);
+		}
+
+		if (argc == 6) {
+			port_num = strtoul(argv[argc - 2], NULL, 0);
+			if (port_num > MAX_PORT) {
+				printf(" Phy read reg fail\n");
+				ret = -1;
+				break;
 			}
-			else if (argc == 8) {
-				dev_num = strtoul(argv[argc-3], NULL, 0);
-				port_num = strtoul(argv[argc-4], NULL, 0);
-				ret = mii_mgr_c45_write(port_num, dev_num, reg, value);
-				cl_ret = mii_mgr_c45_read(port_num, dev_num, reg, &cl_value);
-				if (cl_ret < 0)
-					printf(" Phy read reg fail\n");
-				else
-					printf(" Phy read reg=0x%x, value=0x%x\n", reg, cl_value);
+
+			ret = mii_mgr_read(port_num, reg, &value);
+			if (ret < 0)
+				printf(" Phy read reg fail\n");
+			else
+				printf(" Phy read reg=0x%x, value=0x%x\n",
+				       reg, value);
+		} else if (argc == 7) {
+			dev_num = strtoul(argv[argc - 2], NULL, 16);
+			if (dev_num > 0xFFFFFFFF) {
+				printf(" Phy read reg fail\n");
+				ret = -1;
+				break;
 			}
+
+			port_num = strtoul(argv[argc - 3], NULL, 0);
+			if (port_num > MAX_PORT) {
+				printf(" Phy read reg fail\n");
+				ret = -1;
+				break;
+			}
+
+			ret = mii_mgr_c45_read(port_num, dev_num, reg,
+					       &value);
+			if (ret < 0)
+				printf(" Phy read reg fail\n");
 			else
-				usage(argv[0]);
+				printf(" Phy read dev_num=0x%x, reg=0x%x, value=0x%x\n",
+				       dev_num, reg, value);
+		} else
+			ret = phy_dump(32);
+		break;
+	case 'w':
+		reg = strtoul(argv[argc - 2], NULL, 16);
+		if (reg >= 0xFFFFFFFF) {
+			printf(" Phy write reg fail\n");
+			ret = -1;
 			break;
-		default:
+		}
+
+		value = strtoul(argv[argc - 1], NULL, 16);
+		if (value > 0xFFFF) {
+			printf(" Phy write reg fail\n");
+			ret = -1;
 			break;
+		}
+
+		if (argc == 7) {
+			port_num = strtoul(argv[argc - 3], NULL, 0);
+			if (port_num > MAX_PORT) {
+				printf(" Phy write reg fail\n");
+				ret = -1;
+				break;
+			}
+
+			ret = mii_mgr_write(port_num, reg, value);
+			cl_ret = mii_mgr_read(port_num, reg, &cl_value);
+			if (cl_ret < 0)
+				printf(" Phy write reg fail\n");
+			else
+				printf(" Phy write reg=0x%x, value=0x%x\n",
+				       reg, cl_value);
+		} else if (argc == 8) {
+			dev_num = strtoul(argv[argc - 3], NULL, 16);
+			if (dev_num > 0xFFFFFFFF) {
+				printf(" Phy write reg fail\n");
+				ret = -1;
+				break;
+			}
+
+			port_num = strtoul(argv[argc - 4], NULL, 0);
+			if (port_num > MAX_PORT) {
+				printf(" Phy write reg fail\n");
+				ret = -1;
+				break;
+			}
+
+			ret = mii_mgr_c45_write(port_num, dev_num, reg, value);
+			cl_ret = mii_mgr_c45_read(port_num, dev_num, reg,
+						  &cl_value);
+			if (cl_ret < 0)
+				printf(" Phy write reg fail\n");
+			else
+				printf(" Phy write dev_num=0x%x reg=0x%x, value=0x%x\n",
+				       dev_num, reg, cl_value);
+		}
+		break;
+	default:
+		break;
 	}
 
 	return ret;
 }
 
-
 int main(int argc, char *argv[])
 {
 	int err;
 
 	attres = (struct mt753x_attr *)malloc(sizeof(struct mt753x_attr));
+	if (attres == NULL) {
+		printf("Failed to allocate memory.\n");
+		exit(0);
+	}
 	attres->dev_id = -1;
 	attres->port_num = -1;
 	attres->phy_dev = -1;
@@ -357,30 +644,96 @@
 		if (!err)
 			chip_name = get_chip_name();
 	}
-	
+
+	if (err < 0) {
+		err = mt753x_netlink_init(AN8855_DSA_GENL_NAME);
+		if (!err)
+			chip_name = get_chip_name();
+	}
+
+	if (err < 0) {
+		err = mt753x_netlink_init(AN8855_GENL_NAME);
+		if (!err)
+			chip_name = get_chip_name();
+	}
+
 	if (err < 0) {
 		err = switch_ioctl_init();
 		if (!err) {
 			nl_init_flag = false;
 			chip_name = get_chip_name();
 			if (chip_name < 0) {
-				printf("no chip unsupport or chip id is invalid!\n");
+				printf
+				    ("no chip unsupport or chip id is invalid!\n");
 				exit_free();
 				exit(0);
 			}
 		}
 	}
+#ifndef COMPAT_MODE
+	if (chip_name == 0x8855) {
+		AIR_INIT_PARAM_T init_param = { 0 };
+
+		init_param.printf = printf;
+		init_param.malloc = malloc;
+		init_param.free = free;
+		init_param.udelay = usleep;
+		init_param.dev_access.read_callback = an8855_reg_read;
+		init_param.dev_access.write_callback = an8855_reg_write;
+		init_param.dev_access.phy_read_callback = an8855_phy_cl22_read;
+		init_param.dev_access.phy_write_callback =
+		    an8855_phy_cl22_write;
+		init_param.dev_access.phy_cl45_read_callback =
+		    an8855_phy_cl45_read;
+		init_param.dev_access.phy_cl45_write_callback =
+		    an8855_phy_cl45_write;
+
+		air_init(0, &init_param);
+		air_parse_cmd((argc - 1), &argv[1]);
+	}
 
+	exit_free();
+	return 0;
+#else
 	if (argc < 2)
 		usage(argv[0]);
 
+	if (chip_name == 0x8855) {
+		AIR_INIT_PARAM_T init_param = { 0 };
+
+		init_param.printf = printf;
+		init_param.malloc = malloc;
+		init_param.free = free;
+		init_param.udelay = usleep;
+		init_param.dev_access.read_callback = an8855_reg_read;
+		init_param.dev_access.write_callback = an8855_reg_write;
+		init_param.dev_access.phy_read_callback = an8855_phy_cl22_read;
+		init_param.dev_access.phy_write_callback =
+		    an8855_phy_cl22_write;
+		init_param.dev_access.phy_cl45_read_callback =
+		    an8855_phy_cl45_read;
+		init_param.dev_access.phy_cl45_write_callback =
+		    an8855_phy_cl45_write;
+		air_init(0, &init_param);
+
+		p_switch_func = &an8855_switch_func;
+	} else {
+		p_switch_func = &mt753x_switch_func;
+	}
+
+	if ((argc > 2) && !strcmp(argv[1], "an8855")
+	    && (chip_name == 0x8855)) {
+		air_parse_cmd((argc - 2), (const char **)&argv[2]);
+		exit_free();
+		return 0;
+	}
+
 	if (!strcmp(argv[1], "dev")) {
 		attres->dev_id = strtoul(argv[2], NULL, 0);
 		argv += 2;
 		argc -= 2;
 		if (argc < 2)
 			usage(argv[0]);
-
 	}
 
 	if (argc == 2) {
@@ -388,60 +741,69 @@
 			attres->type = MT753X_ATTR_TYPE_MESG;
 			mt753x_list_swdev(attres, MT753X_CMD_REQUEST);
 		} else if (!strncmp(argv[1], "dump", 5)) {
-			table_dump();
+			p_switch_func->pf_table_dump(argc, argv);
 		} else if (!strncmp(argv[1], "clear", 6)) {
-			table_clear();
+			p_switch_func->pf_table_clear(argc, argv);
 			printf("done.\n");
 		} else if (!strncmp(argv[1], "reset", 5)) {
-			switch_reset(argc, argv);
+			p_switch_func->pf_switch_reset(argc, argv);
 		} else if (!strncmp(argv[1], "phy", 4)) {
-			phy_dump(32); //dump all phy register
+			phy_dump(32);	//dump all phy register
 		} else if (!strncmp(argv[1], "sysctl", 7)) {
-			if (nl_init_flag)
-				printf("netlink(%s)\n",MT753X_GENL_NAME);
-			else
-				printf("ioctl(%s)\n",ETH_DEVNAME);
+			if (nl_init_flag) {
+				if (chip_name == 0x8855)
+					printf("netlink(%s)\n",
+					       AN8855_GENL_NAME);
+				else
+					printf("netlink(%s)\n",
+					       MT753X_GENL_NAME);
+			} else
+				printf("ioctl(%s)\n", ETH_DEVNAME);
+		} else if (!strncmp(argv[1], "ver", 4)) {
+			if (chip_name == 0x8855)
+				printf("Switch APP version: %s\r\n",
+				       SWITCH_APP_VERSION);
 		} else
 			usage(argv[0]);
 	} else if (!strncmp(argv[1], "arl", 4)) {
 		if (!strncmp(argv[2], "aging", 6))
-			doArlAging(argc, argv);
+			p_switch_func->pf_doArlAging(argc, argv);
 	} else if (!strncmp(argv[1], "esw_cnt", 8)) {
 		if (!strncmp(argv[2], "get", 4))
-			read_mib_counters();
+			p_switch_func->pf_read_mib_counters(argc, argv);
 		else if (!strncmp(argv[2], "clear", 6))
-			clear_mib_counters();
+			p_switch_func->pf_clear_mib_counters(argc, argv);
 		else
 			usage(argv[0]);
-	}else if (!strncmp(argv[1], "output_queue_cnt", 17)) {
+	} else if (!strncmp(argv[1], "output_queue_cnt", 17)) {
 		if (!strncmp(argv[2], "get", 4))
-			read_output_queue_counters();
+			p_switch_func->pf_read_output_queue_counters(argc,
+								     argv);
 		else
 			usage(argv[0]);
-	}else if (!strncmp(argv[1], "free_page", 10)) {
+	} else if (!strncmp(argv[1], "free_page", 10)) {
 		if (!strncmp(argv[2], "get", 4))
-			read_free_page_counters();
+			p_switch_func->pf_read_free_page_counters(argc, argv);
 		else
 			usage(argv[0]);
-	}
-	else if (!strncmp(argv[1], "ratectl", 8))
-		rate_control(argc, argv);
+	} else if (!strncmp(argv[1], "ratectl", 8))
+		p_switch_func->pf_rate_control(argc, argv);
 	else if (!strncmp(argv[1], "add", 4))
-		table_add(argc, argv);
+		p_switch_func->pf_table_add(argc, argv);
 	else if (!strncmp(argv[1], "filt", 5))
-		table_add(argc, argv);
+		p_switch_func->pf_table_add(argc, argv);
 	else if (!strncmp(argv[1], "del", 4)) {
 		if (!strncmp(argv[4], "fid", 4))
-			table_del_fid(argc, argv);
+			p_switch_func->pf_table_del_fid(argc, argv);
 		else if (!strncmp(argv[4], "vid", 4))
-			table_del_vid(argc, argv);
+			p_switch_func->pf_table_del_vid(argc, argv);
 		else
 			usage(argv[0]);
 	} else if (!strncmp(argv[1], "search", 7)) {
 		if (!strncmp(argv[4], "fid", 4))
-			table_search_mac_fid(argc, argv);
+			p_switch_func->pf_table_search_mac_fid(argc, argv);
 		else if (!strncmp(argv[4], "vid", 4))
-			table_search_mac_vid(argc, argv);
+			p_switch_func->pf_table_search_mac_vid(argc, argv);
 		else
 			usage(argv[0]);
 	} else if (!strncmp(argv[1], "phy", 4)) {
@@ -466,70 +828,70 @@
 		if (argc < 3)
 			usage(argv[0]);
 		if (!strncmp(argv[2], "fc", 3))
-			global_set_mac_fc(argc, argv);
+			p_switch_func->pf_global_set_mac_fc(argc, argv);
 		else if (!strncmp(argv[2], "pfc", 4))
-			set_mac_pfc(argc, argv);
+			p_switch_func->pf_set_mac_pfc(argc, argv);
 		else
 			usage(argv[0]);
 	} else if (!strncmp(argv[1], "qos", 4)) {
 		if (argc < 3)
 			usage(argv[0]);
 		if (!strncmp(argv[2], "sch", 4))
-			qos_sch_select(argc, argv);
+			p_switch_func->pf_qos_sch_select(argc, argv);
 		else if (!strncmp(argv[2], "base", 5))
-			qos_set_base(argc, argv);
+			p_switch_func->pf_qos_set_base(argc, argv);
 		else if (!strncmp(argv[2], "port-weight", 12))
-			qos_wfq_set_weight(argc, argv);
+			p_switch_func->pf_qos_wfq_set_weight(argc, argv);
 		else if (!strncmp(argv[2], "port-prio", 10))
-			qos_set_portpri(argc, argv);
+			p_switch_func->pf_qos_set_portpri(argc, argv);
 		else if (!strncmp(argv[2], "dscp-prio", 10))
-			qos_set_dscppri(argc, argv);
+			p_switch_func->pf_qos_set_dscppri(argc, argv);
 		else if (!strncmp(argv[2], "prio-qmap", 10))
-			qos_pri_mapping_queue(argc, argv);
+			p_switch_func->pf_qos_pri_mapping_queue(argc, argv);
 		else
 			usage(argv[0]);
 	} else if (!strncmp(argv[1], "stp", 3)) {
 		if (argc < 3)
 			usage(argv[0]);
 		else
-			doStp(argc, argv);
+			p_switch_func->pf_doStp(argc, argv);
 	} else if (!strncmp(argv[1], "sip", 5)) {
 		if (argc < 3)
 			usage(argv[0]);
 		if (!strncmp(argv[2], "dump", 5))
-			sip_dump();
+			p_switch_func->pf_sip_dump(argc, argv);
 		else if (!strncmp(argv[2], "add", 4))
-			sip_add(argc, argv);
+			p_switch_func->pf_sip_add(argc, argv);
 		else if (!strncmp(argv[2], "del", 4))
-			sip_del(argc, argv);
+			p_switch_func->pf_sip_del(argc, argv);
 		else if (!strncmp(argv[2], "clear", 6))
-			sip_clear();
+			p_switch_func->pf_sip_clear(argc, argv);
 		else
 			usage(argv[0]);
 	} else if (!strncmp(argv[1], "dip", 4)) {
 		if (argc < 3)
 			usage(argv[0]);
 		if (!strncmp(argv[2], "dump", 5))
-			dip_dump();
+			p_switch_func->pf_dip_dump(argc, argv);
 		else if (!strncmp(argv[2], "add", 4))
-			dip_add(argc, argv);
+			p_switch_func->pf_dip_add(argc, argv);
 		else if (!strncmp(argv[2], "del", 4))
-			dip_del(argc, argv);
+			p_switch_func->pf_dip_del(argc, argv);
 		else if (!strncmp(argv[2], "clear", 6))
-			dip_clear();
+			p_switch_func->pf_dip_clear(argc, argv);
 		else
 			usage(argv[0]);
 	} else if (!strncmp(argv[1], "mirror", 7)) {
 		if (argc < 3)
 			usage(argv[0]);
 		if (!strncmp(argv[2], "monitor", 8))
-			set_mirror_to(argc, argv);
+			p_switch_func->pf_set_mirror_to(argc, argv);
 		else if (!strncmp(argv[2], "target", 7))
-			set_mirror_from(argc, argv);
+			p_switch_func->pf_set_mirror_from(argc, argv);
 		else if (!strncmp(argv[2], "enable", 7))
-			doMirrorEn(argc, argv);
+			p_switch_func->pf_doMirrorEn(argc, argv);
 		else if (!strncmp(argv[2], "port-based", 11))
-			doMirrorPortBased(argc, argv);
+			p_switch_func->pf_doMirrorPortBased(argc, argv);
 		else
 			usage(argv[0]);
 	} else if (!strncmp(argv[1], "acl", 4)) {
@@ -537,152 +899,127 @@
 			usage(argv[0]);
 		if (!strncmp(argv[2], "dip", 4)) {
 			if (!strncmp(argv[3], "add", 4))
-				acl_dip_add(argc, argv);
+				p_switch_func->pf_acl_dip_add(argc, argv);
 			else if (!strncmp(argv[3], "modup", 6))
-				acl_dip_modify(argc, argv);
+				p_switch_func->pf_acl_dip_modify(argc, argv);
 			else if (!strncmp(argv[3], "pppoe", 6))
-				acl_dip_pppoe(argc, argv);
+				p_switch_func->pf_acl_dip_pppoe(argc, argv);
 			else if (!strncmp(argv[3], "trtcm", 4))
-				acl_dip_trtcm(argc, argv);
+				p_switch_func->pf_acl_dip_trtcm(argc, argv);
 			else if (!strncmp(argv[3], "meter", 6))
-				acl_dip_meter(argc, argv);
+				p_switch_func->pf_acl_dip_meter(argc, argv);
 			else
 				usage(argv[0]);
 		} else if (!strncmp(argv[2], "dmac", 6)) {
 			if (!strncmp(argv[3], "add", 4))
-				acl_mac_add(argc, argv);
+				p_switch_func->pf_acl_mac_add(argc, argv);
 			else
 				usage(argv[0]);
 		} else if (!strncmp(argv[2], "etype", 6)) {
 			if (!strncmp(argv[3], "add", 4))
-				acl_ethertype(argc, argv);
+				p_switch_func->pf_acl_ethertype(argc, argv);
 			else
 				usage(argv[0]);
 		} else if (!strncmp(argv[2], "port", 5)) {
 			if (!strncmp(argv[3], "add", 4))
-				acl_sp_add(argc, argv);
+				p_switch_func->pf_acl_sp_add(argc, argv);
 			else
 				usage(argv[0]);
 		} else if (!strncmp(argv[2], "L4", 5)) {
 			if (!strncmp(argv[3], "add", 4))
-				acl_l4_add(argc, argv);
+				p_switch_func->pf_acl_l4_add(argc, argv);
 			else
 				usage(argv[0]);
 		} else if (!strncmp(argv[2], "enable", 7))
-			acl_port_enable(argc, argv);
+			p_switch_func->pf_acl_port_enable(argc, argv);
 		else if (!strncmp(argv[2], "acltbl-add", 11))
-			acl_table_add(argc, argv);
+			p_switch_func->pf_acl_table_add(argc, argv);
 		else if (!strncmp(argv[2], "masktbl-add", 12))
-			acl_mask_table_add(argc, argv);
+			p_switch_func->pf_acl_mask_table_add(argc, argv);
 		else if (!strncmp(argv[2], "ruletbl-add", 12))
-			acl_rule_table_add(argc, argv);
+			p_switch_func->pf_acl_rule_table_add(argc, argv);
 		else if (!strncmp(argv[2], "ratetbl-add", 12))
-			acl_rate_table_add(argc, argv);
+			p_switch_func->pf_acl_rate_table_add(argc, argv);
 		else
 			usage(argv[0]);
 	} else if (!strncmp(argv[1], "vlan", 5)) {
 		if (argc < 3)
 			usage(argv[0]);
 		if (!strncmp(argv[2], "dump", 5))
-			vlan_dump(argc, argv);
+			p_switch_func->pf_vlan_dump(argc, argv);
 		else if (!strncmp(argv[2], "set", 4))
-			vlan_set(argc, argv);
+			p_switch_func->pf_vlan_set(argc, argv);
 		else if (!strncmp(argv[2], "clear", 6))
-			vlan_clear(argc, argv);
+			p_switch_func->pf_vlan_clear(argc, argv);
 		else if (!strncmp(argv[2], "vid", 4))
-			doVlanSetVid(argc, argv);
+			p_switch_func->pf_doVlanSetVid(argc, argv);
 		else if (!strncmp(argv[2], "pvid", 5))
-			doVlanSetPvid(argc, argv);
+			p_switch_func->pf_doVlanSetPvid(argc, argv);
 		else if (!strncmp(argv[2], "acc-frm", 8))
-			doVlanSetAccFrm(argc, argv);
+			p_switch_func->pf_doVlanSetAccFrm(argc, argv);
 		else if (!strncmp(argv[2], "port-attr", 10))
-			doVlanSetPortAttr(argc, argv);
+			p_switch_func->pf_doVlanSetPortAttr(argc, argv);
 		else if (!strncmp(argv[2], "port-mode", 10))
-			doVlanSetPortMode(argc, argv);
+			p_switch_func->pf_doVlanSetPortMode(argc, argv);
 		else if (!strncmp(argv[2], "eg-tag-pcr", 11))
-			doVlanSetEgressTagPCR(argc, argv);
+			p_switch_func->pf_doVlanSetEgressTagPCR(argc, argv);
 		else if (!strncmp(argv[2], "eg-tag-pvc", 11))
-			doVlanSetEgressTagPVC(argc, argv);
+			p_switch_func->pf_doVlanSetEgressTagPVC(argc, argv);
 		else
 			usage(argv[0]);
 	} else if (!strncmp(argv[1], "reg", 4)) {
 		parse_reg_cmd(argc, argv, 4);
 	} else if (!strncmp(argv[1], "ingress-rate", 6)) {
-		int port = 0, bw = 0;
-		if (argv[2][1] == 'n') {
-			port = strtoul(argv[3], NULL, 0);
-			bw = strtoul(argv[4], NULL, 0);
-			if (ingress_rate_set(1, port, bw) == 0)
-				printf("switch port=%d, bw=%d\n", port, bw);
-		}
-		else if (argv[2][1] == 'f') {
-			if (argc != 4)
-				usage(argv[0]);
-			port = strtoul(argv[3], NULL, 0);
-			if (ingress_rate_set(0, port, bw) == 0)
-				printf("switch port=%d ingress rate limit off\n", port);
-		} else
-			usage(argv[0]);
+		p_switch_func->pf_igress_rate_set(argc, argv);
 	} else if (!strncmp(argv[1], "egress-rate", 6)) {
-		int port = 0, bw = 0;
-		if (argv[2][1] == 'n') {
-			port = strtoul(argv[3], NULL, 0);
-			bw = strtoul(argv[4], NULL, 0);
-			if (egress_rate_set(1, port, bw) == 0)
-				printf("switch port=%d, bw=%d\n", port, bw);
-		} else if (argv[2][1] == 'f') {
-			if (argc != 4)
-				usage(argv[0]);
-			port = strtoul(argv[3], NULL, 0);
-			if (egress_rate_set(0, port, bw) == 0)
-				printf("switch port=%d egress rate limit off\n", port);
-		} else
-			usage(argv[0]);
+		p_switch_func->pf_egress_rate_set(argc, argv);
 	} else if (!strncmp(argv[1], "igmpsnoop", 10)) {
 		if (argc < 3)
 			usage(argv[0]);
 		if (!strncmp(argv[2], "on", 3))
-			igmp_on(argc, argv);
+			p_switch_func->pf_igmp_on(argc, argv);
 		else if (!strncmp(argv[2], "off", 4))
-			igmp_off();
+			p_switch_func->pf_igmp_off(argc, argv);
 		else if (!strncmp(argv[2], "enable", 7))
-			igmp_enable(argc, argv);
+			p_switch_func->pf_igmp_enable(argc, argv);
 		else if (!strncmp(argv[2], "disable", 8))
-			igmp_disable(argc, argv);
+			p_switch_func->pf_igmp_disable(argc, argv);
 		else
 			usage(argv[0]);
 	} else if (!strncmp(argv[1], "collision-pool", 15)) {
 		if (argc < 3)
 			usage(argv[0]);
 		if (!strncmp(argv[2], "enable", 7))
-			collision_pool_enable(argc, argv);
-		else if (!strncmp(argv[2], "mac", 4)){
+			p_switch_func->pf_collision_pool_enable(argc, argv);
+		else if (!strncmp(argv[2], "mac", 4)) {
 			if (!strncmp(argv[3], "dump", 5))
-				collision_pool_mac_dump();
+				p_switch_func->pf_collision_pool_mac_dump(argc,
+									  argv);
 			else
 				usage(argv[0]);
-		} else if (!strncmp(argv[2], "dip", 4)){
+		} else if (!strncmp(argv[2], "dip", 4)) {
 			if (!strncmp(argv[3], "dump", 5))
-				collision_pool_dip_dump();
+				p_switch_func->pf_collision_pool_dip_dump(argc,
+									  argv);
 			else
 				usage(argv[0]);
-		} else if (!strncmp(argv[2], "sip", 4)){
+		} else if (!strncmp(argv[2], "sip", 4)) {
 			if (!strncmp(argv[3], "dump", 5))
-				collision_pool_sip_dump();
+				p_switch_func->pf_collision_pool_sip_dump(argc,
+									  argv);
 			else
 				usage(argv[0]);
-			}
-		else
+		} else
 			usage(argv[0]);
-	}  else if (!strncmp(argv[1], "pfc", 15)) {
+	} else if (!strncmp(argv[1], "pfc", 15)) {
 		if (argc < 4 || argc > 5)
 			usage(argv[0]);
 		if (!strncmp(argv[2], "enable", 7))
-			set_mac_pfc(argc, argv);
-		else if (!strncmp(argv[2], "rx_counter", 11)){
-			pfc_get_rx_counter(argc, argv);
-		} else if (!strncmp(argv[2], "tx_counter", 11)){
-			pfc_get_tx_counter(argc, argv);
+			p_switch_func->pf_set_mac_pfc(argc, argv);
+		else if (!strncmp(argv[2], "rx_counter", 11)) {
+			p_switch_func->pf_pfc_get_rx_counter(argc, argv);
+		} else if (!strncmp(argv[2], "tx_counter", 11)) {
+			p_switch_func->pf_pfc_get_tx_counter(argc, argv);
 		} else
 			usage(argv[0]);
 	} else if (!strncmp(argv[1], "crossover", 10)) {
@@ -694,10 +1031,10 @@
 		if (argc < 3)
 			usage(argv[0]);
 		if (!strncmp(argv[2], "enable", 7) ||
-			 !strncmp(argv[2], "disable", 8))
-			eee_enable(argc, argv);
+		    !strncmp(argv[2], "disable", 8))
+			p_switch_func->pf_eee_enable(argc, argv);
 		else if (!strncmp(argv[2], "dump", 5))
-			eee_dump(argc, argv);
+			p_switch_func->pf_eee_dump(argc, argv);
 		else
 			usage(argv[0]);
 	} else
@@ -705,4 +1042,5 @@
 
 	exit_free();
 	return 0;
+#endif
 }
diff --git a/recipes-devtools/switch/files/src/switch_fun.c b/recipes-devtools/switch/files/src/switch_fun.c
index 8ee9675..9e9f4fe 100644
--- a/recipes-devtools/switch/files/src/switch_fun.c
+++ b/recipes-devtools/switch/files/src/switch_fun.c
@@ -19,6 +19,82 @@
 
 #define leaky_bucket 0
 
+struct switch_func_s mt753x_switch_func = {
+	.pf_table_dump = table_dump,
+	.pf_table_clear = table_clear,
+	.pf_switch_reset = switch_reset,
+	.pf_doArlAging = doArlAging,
+	.pf_read_mib_counters = read_mib_counters,
+	.pf_clear_mib_counters = clear_mib_counters,
+	.pf_read_output_queue_counters = read_output_queue_counters,
+	.pf_read_free_page_counters = read_free_page_counters,
+	.pf_rate_control = rate_control,
+	.pf_igress_rate_set = ingress_rate_set,
+	.pf_egress_rate_set = egress_rate_set,
+	.pf_table_add = table_add,
+	.pf_table_del_fid = table_del_fid,
+	.pf_table_del_vid = table_del_vid,
+	.pf_table_search_mac_fid = table_search_mac_fid,
+	.pf_table_search_mac_vid = table_search_mac_vid,
+	.pf_global_set_mac_fc = global_set_mac_fc,
+	.pf_set_mac_pfc = set_mac_pfc,
+	.pf_qos_sch_select = qos_sch_select,
+	.pf_qos_set_base = qos_set_base,
+	.pf_qos_wfq_set_weight = qos_wfq_set_weight,
+	.pf_qos_set_portpri = qos_set_portpri,
+	.pf_qos_set_dscppri = qos_set_dscppri,
+	.pf_qos_pri_mapping_queue = qos_pri_mapping_queue,
+	.pf_doStp = doStp,
+	.pf_sip_dump = sip_dump,
+	.pf_sip_add = sip_add,
+	.pf_sip_del = sip_del,
+	.pf_sip_clear = sip_clear,
+	.pf_dip_dump = dip_dump,
+	.pf_dip_add = dip_add,
+	.pf_dip_del = dip_del,
+	.pf_dip_clear = dip_clear,
+	.pf_set_mirror_to = set_mirror_to,
+	.pf_set_mirror_from = set_mirror_from,
+	.pf_doMirrorEn = doMirrorEn,
+	.pf_doMirrorPortBased = doMirrorPortBased,
+	.pf_acl_dip_add = acl_dip_add,
+	.pf_acl_dip_modify = acl_dip_modify,
+	.pf_acl_dip_pppoe = acl_dip_pppoe,
+	.pf_acl_dip_trtcm = acl_dip_trtcm,
+	.pf_acl_dip_meter = acl_dip_meter,
+	.pf_acl_mac_add = acl_mac_add,
+	.pf_acl_ethertype = acl_ethertype,
+	.pf_acl_sp_add = acl_sp_add,
+	.pf_acl_l4_add = acl_l4_add,
+	.pf_acl_port_enable = acl_port_enable,
+	.pf_acl_table_add = acl_table_add,
+	.pf_acl_mask_table_add = acl_mask_table_add,
+	.pf_acl_rule_table_add = acl_rule_table_add,
+	.pf_acl_rate_table_add = acl_rate_table_add,
+	.pf_vlan_dump = vlan_dump,
+	.pf_vlan_set = vlan_set,
+	.pf_vlan_clear = vlan_clear,
+	.pf_doVlanSetVid = doVlanSetVid,
+	.pf_doVlanSetPvid = doVlanSetPvid,
+	.pf_doVlanSetAccFrm = doVlanSetAccFrm,
+	.pf_doVlanSetPortAttr = doVlanSetPortAttr,
+	.pf_doVlanSetPortMode = doVlanSetPortMode,
+	.pf_doVlanSetEgressTagPCR = doVlanSetEgressTagPCR,
+	.pf_doVlanSetEgressTagPVC = doVlanSetEgressTagPVC,
+	.pf_igmp_on = igmp_on,
+	.pf_igmp_off = igmp_off,
+	.pf_igmp_enable = igmp_enable,
+	.pf_igmp_disable = igmp_disable,
+	.pf_collision_pool_enable = collision_pool_enable,
+	.pf_collision_pool_mac_dump = collision_pool_mac_dump,
+	.pf_collision_pool_dip_dump = collision_pool_dip_dump,
+	.pf_collision_pool_sip_dump = collision_pool_sip_dump,
+	.pf_pfc_get_rx_counter = pfc_get_rx_counter,
+	.pf_pfc_get_tx_counter = pfc_get_tx_counter,
+	.pf_eee_enable = eee_enable,
+	.pf_eee_dump = eee_dump,
+};
+
 static int getnext(char *src, int separator, char *dest)
 {
 	char *c;
@@ -66,7 +142,7 @@
 	c[1] = *(ptr + 1);
 	c[2] = *(ptr + 2);
 	c[3] = *(ptr + 3);
-	/*sprintf(str, "%d.%d.%d.%d", c[0], c[1], c[2], c[3]);*/
+	/*sprintf(str, "%d.%d.%d.%d", c[0], c[1], c[2], c[3]); */
 	sprintf(str, "%d.%d.%d.%d", c[3], c[2], c[1], c[0]);
 }
 
@@ -153,7 +229,8 @@
 	return 0;
 }
 
-int mii_mgr_c45_read(unsigned int port_num, unsigned int dev, unsigned int reg, unsigned int *value)
+int mii_mgr_c45_read(unsigned int port_num, unsigned int dev, unsigned int reg,
+		     unsigned int *value)
 {
 	int ret;
 
@@ -176,7 +253,8 @@
 	return 0;
 }
 
-int mii_mgr_c45_write(unsigned int port_num, unsigned int dev, unsigned int reg, unsigned int value)
+int mii_mgr_c45_write(unsigned int port_num, unsigned int dev, unsigned int reg,
+		      unsigned int value)
 {
 	int ret;
 
@@ -199,7 +277,6 @@
 	return 0;
 }
 
-
 int phy_dump(int phy_addr)
 {
 	int ret;
@@ -221,7 +298,7 @@
 void phy_crossover(int argc, char *argv[])
 {
 	unsigned int port_num = strtoul(argv[2], NULL, 10);
-	unsigned int value;
+	unsigned int value = 0;
 	int ret;
 
 	if (port_num > 4) {
@@ -230,9 +307,13 @@
 	}
 
 	if (nl_init_flag == true)
-		ret = phy_cl45_read_netlink(attres, port_num, 0x1E, MT7530_T10_TEST_CONTROL, &value);
+		ret =
+		    phy_cl45_read_netlink(attres, port_num, 0x1E,
+					  MT7530_T10_TEST_CONTROL, &value);
 	else
-		ret = mii_mgr_cl45_read_ioctl(port_num, 0x1E, MT7530_T10_TEST_CONTROL, &value);
+		ret =
+		    mii_mgr_cl45_read_ioctl(port_num, 0x1E,
+					    MT7530_T10_TEST_CONTROL, &value);
 	if (ret < 0) {
 		printf("phy_cl45 read fail\n");
 		exit_free();
@@ -240,10 +321,10 @@
 	}
 
 	printf("mii_mgr_cl45:");
-	printf("Read:  port#=%d, device=0x%x, reg=0x%x, value=0x%x\n", port_num, 0x1E, MT7530_T10_TEST_CONTROL, value);
+	printf("Read:  port#=%d, device=0x%x, reg=0x%x, value=0x%x\n", port_num,
+	       0x1E, MT7530_T10_TEST_CONTROL, value);
 
-	if (!strncmp(argv[3], "auto", 5))
-	{
+	if (!strncmp(argv[3], "auto", 5)) {
 		value &= (~(0x3 << 3));
 	} else if (!strncmp(argv[3], "mdi", 4)) {
 		value &= (~(0x3 << 3));
@@ -254,12 +335,17 @@
 		printf("invaild parameter\n");
 		return;
 	}
-	printf("Write: port#=%d, device=0x%x, reg=0x%x. value=0x%x\n", port_num, 0x1E, MT7530_T10_TEST_CONTROL, value);
+	printf("Write: port#=%d, device=0x%x, reg=0x%x. value=0x%x\n", port_num,
+	       0x1E, MT7530_T10_TEST_CONTROL, value);
 
 	if (nl_init_flag == true)
-		ret = phy_cl45_write_netlink(attres, port_num, 0x1E, MT7530_T10_TEST_CONTROL, value);
+		ret =
+		    phy_cl45_write_netlink(attres, port_num, 0x1E,
+					   MT7530_T10_TEST_CONTROL, value);
 	else
-		ret = mii_mgr_cl45_write_ioctl(port_num, 0x1E, MT7530_T10_TEST_CONTROL, value);
+		ret =
+		    mii_mgr_cl45_write_ioctl(port_num, 0x1E,
+					     MT7530_T10_TEST_CONTROL, value);
 
 	if (ret < 0) {
 		printf("phy_cl45 write fail\n");
@@ -282,7 +368,7 @@
 	if (argv[2][0] == 'r') {
 		if (argc != 7)
 			return -1;
-		mii_mgr_write(0, 0x1f, 0x52b5); // r31 = 0x52b5
+		mii_mgr_write(0, 0x1f, 0x52b5);	// r31 = 0x52b5
 		port_num = strtoul(argv[3], NULL, 0);
 		if (port_num > MAX_PORT) {
 			printf("Illegal port index and port:0~6\n");
@@ -291,16 +377,21 @@
 		ch_addr = strtoul(argv[4], NULL, 0);
 		node_addr = strtoul(argv[5], NULL, 0);
 		data_addr = strtoul(argv[6], NULL, 0);
-		printf("port = %x, ch_addr = %x, node_addr=%x, data_addr=%x\n", port_num, ch_addr, node_addr, data_addr);
-		tr_reg_control = (1 << 15) | (1 << 13) | (ch_addr << 11) | (node_addr << 7) | (data_addr << 1);
-		mii_mgr_write(port_num, 16, tr_reg_control); // r16 = tr_reg_control
+		printf("port = %x, ch_addr = %x, node_addr=%x, data_addr=%x\n",
+		       port_num, ch_addr, node_addr, data_addr);
+		tr_reg_control =
+		    (1 << 15) | (1 << 13) | (ch_addr << 11) | (node_addr << 7) |
+		    (data_addr << 1);
+		mii_mgr_write(port_num, 16, tr_reg_control);	// r16 = tr_reg_control
 		mii_mgr_read(port_num, 17, &val_l);
 		mii_mgr_read(port_num, 18, &val_h);
-		printf("switch trreg read tr_reg_control=%x, value_H=%x, value_L=%x\n", tr_reg_control, val_h, val_l);
+		printf
+		    ("switch trreg read tr_reg_control=%x, value_H=%x, value_L=%x\n",
+		     tr_reg_control, val_h, val_l);
 	} else if (argv[2][0] == 'w') {
 		if (argc != 9)
 			return -1;
-		mii_mgr_write(0, 0x1f, 0x52b5); // r31 = 0x52b5
+		mii_mgr_write(0, 0x1f, 0x52b5);	// r31 = 0x52b5
 		port_num = strtoul(argv[3], NULL, 0);
 		if (port_num > MAX_PORT) {
 			printf("\n**Illegal port index and port:0~6\n");
@@ -311,20 +402,26 @@
 		data_addr = strtoul(argv[6], NULL, 0);
 		val_h = strtoul(argv[7], NULL, 0);
 		val_l = strtoul(argv[8], NULL, 0);
-		printf("port = %x, ch_addr = %x, node_addr=%x, data_addr=%x\n", port_num, ch_addr, node_addr, data_addr);
-		tr_reg_control = (1 << 15) | (0 << 13) | (ch_addr << 11) | (node_addr << 7) | (data_addr << 1);
+		printf("port = %x, ch_addr = %x, node_addr=%x, data_addr=%x\n",
+		       port_num, ch_addr, node_addr, data_addr);
+		tr_reg_control =
+		    (1 << 15) | (0 << 13) | (ch_addr << 11) | (node_addr << 7) |
+		    (data_addr << 1);
 		mii_mgr_write(port_num, 17, val_l);
 		mii_mgr_write(port_num, 18, val_h);
-		mii_mgr_write(port_num, 16, tr_reg_control); // r16 = tr_reg_control
-		printf("switch trreg Write tr_reg_control=%x, value_H=%x, value_L=%x\n", tr_reg_control, val_h, val_l);
+		mii_mgr_write(port_num, 16, tr_reg_control);	// r16 = tr_reg_control
+		printf
+		    ("switch trreg Write tr_reg_control=%x, value_H=%x, value_L=%x\n",
+		     tr_reg_control, val_h, val_l);
 	} else
 		return -1;
 	return 0;
 }
 
-void write_acl_table(unsigned char tbl_idx, unsigned int vawd1, unsigned int vawd2)
+void write_acl_table(unsigned char tbl_idx, unsigned int vawd1,
+		     unsigned int vawd2)
 {
-	unsigned int value, reg;
+	unsigned int value = 0, reg = 0;
 	unsigned int max_index;
 
 	if (chip_name == 0x7531 || chip_name == 0x7988)
@@ -340,8 +437,7 @@
 	}
 
 	reg = REG_VTCR_ADDR;
-	while (1)
-	{ // wait until not busy
+	while (1) {		// wait until not busy
 		reg_read(reg, &value);
 		if ((value & REG_VTCR_BUSY_MASK) == 0) {
 			break;
@@ -356,8 +452,7 @@
 	reg_write(reg, value);
 	printf("write reg: %x, value: %x\n", reg, value);
 
-	while (1)
-	{ 	// wait until not busy
+	while (1) {		// wait until not busy
 		reg_read(reg, &value);
 		if ((value & REG_VTCR_BUSY_MASK) == 0)
 			break;
@@ -366,8 +461,8 @@
 
 void acl_table_add(int argc, char *argv[])
 {
-	unsigned int vawd1, vawd2;
-	unsigned char tbl_idx;
+	unsigned int vawd1 = 0, vawd2 = 0;
+	unsigned char tbl_idx = 0;
 
 	tbl_idx = atoi(argv[3]);
 	vawd1 = strtoul(argv[4], (char **)NULL, 16);
@@ -375,10 +470,11 @@
 	write_acl_table(tbl_idx, vawd1, vawd2);
 }
 
-void write_acl_mask_table(unsigned char tbl_idx, unsigned int vawd1, unsigned int vawd2)
+void write_acl_mask_table(unsigned char tbl_idx, unsigned int vawd1,
+			  unsigned int vawd2)
 {
-	unsigned int value, reg;
-	unsigned int max_index;
+	unsigned int value = 0, reg = 0;
+	unsigned int max_index = 0;
 
 	if (chip_name == 0x7531 || chip_name == 0x7988)
 		max_index = 128;
@@ -392,8 +488,7 @@
 		return;
 	}
 	reg = REG_VTCR_ADDR;
-	while (1)
-	{ // wait until not busy
+	while (1) {		// wait until not busy
 		reg_read(reg, &value);
 		if ((value & REG_VTCR_BUSY_MASK) == 0)
 			break;
@@ -406,8 +501,7 @@
 	value = REG_VTCR_BUSY_MASK | (0x09 << REG_VTCR_FUNC_OFFT) | tbl_idx;
 	reg_write(reg, value);
 	printf("write reg: %x, value: %x\n", reg, value);
-	while (1)
-	{ // wait until not busy
+	while (1) {		// wait until not busy
 		reg_read(reg, &value);
 		if ((value & REG_VTCR_BUSY_MASK) == 0)
 			break;
@@ -416,8 +510,8 @@
 
 void acl_mask_table_add(int argc, char *argv[])
 {
-	unsigned int vawd1, vawd2;
-	unsigned char tbl_idx;
+	unsigned int vawd1 = 0, vawd2 = 0;
+	unsigned char tbl_idx = 0;
 
 	tbl_idx = atoi(argv[3]);
 	vawd1 = strtoul(argv[4], (char **)NULL, 16);
@@ -425,10 +519,11 @@
 	write_acl_mask_table(tbl_idx, vawd1, vawd2);
 }
 
-void write_acl_rule_table(unsigned char tbl_idx, unsigned int vawd1, unsigned int vawd2)
+void write_acl_rule_table(unsigned char tbl_idx, unsigned int vawd1,
+			  unsigned int vawd2)
 {
-	unsigned int value, reg;
-	unsigned int max_index;
+	unsigned int value = 0, reg = 0;
+	unsigned int max_index = 0;
 
 	if (chip_name == 0x7531 || chip_name == 0x7988)
 		max_index = 128;
@@ -437,14 +532,13 @@
 
 	printf("Rule_control_tbl_idx:%d\n", tbl_idx);
 
-	if (tbl_idx >= max_index) { /*Check the input parameters is right or not.*/
+	if (tbl_idx >= max_index) {	/* Check the input parameters is right or not. */
 		printf(HELP_ACL_RULE_TBL_ADD);
 		return;
 	}
 	reg = REG_VTCR_ADDR;
 
-	while (1)
-	{ // wait until not busy
+	while (1) {		// wait until not busy
 		reg_read(reg, &value);
 		if ((value & REG_VTCR_BUSY_MASK) == 0) {
 			break;
@@ -459,8 +553,7 @@
 	reg_write(reg, value);
 	printf("write reg: %x, value: %x\n", reg, value);
 
-	while (1)
-	{ // wait until not busy
+	while (1) {		// wait until not busy
 		reg_read(reg, &value);
 		if ((value & REG_VTCR_BUSY_MASK) == 0) {
 			break;
@@ -470,8 +563,8 @@
 
 void acl_rule_table_add(int argc, char *argv[])
 {
-	unsigned int vawd1, vawd2;
-	unsigned char tbl_idx;
+	unsigned int vawd1 = 0, vawd2 = 0;
+	unsigned char tbl_idx = 0;
 
 	tbl_idx = atoi(argv[3]);
 	vawd1 = strtoul(argv[4], (char **)NULL, 16);
@@ -479,9 +572,10 @@
 	write_acl_rule_table(tbl_idx, vawd1, vawd2);
 }
 
-void write_rate_table(unsigned char tbl_idx, unsigned int vawd1, unsigned int vawd2)
+void write_rate_table(unsigned char tbl_idx, unsigned int vawd1,
+		      unsigned int vawd2)
 {
-	unsigned int value, reg;
+	unsigned int value = 0, reg = 0;
 	unsigned int max_index = 32;
 
 	printf("Rule_action_tbl_idx:%d\n", tbl_idx);
@@ -492,7 +586,7 @@
 	}
 
 	reg = REG_VTCR_ADDR;
-	while (1) { 	// wait until not busy
+	while (1) {		// wait until not busy
 		reg_read(reg, &value);
 		if ((value & REG_VTCR_BUSY_MASK) == 0)
 			break;
@@ -507,7 +601,7 @@
 	reg_write(reg, value);
 	printf("write reg: %x, value: %x\n", reg, value);
 
-	while (1) { // wait until not busy
+	while (1) {		// wait until not busy
 		reg_read(reg, &value);
 		if ((value & REG_VTCR_BUSY_MASK) == 0)
 			break;
@@ -516,8 +610,8 @@
 
 void acl_rate_table_add(int argc, char *argv[])
 {
-	unsigned int vawd1, vawd2;
-	unsigned char tbl_idx;
+	unsigned int vawd1 = 0, vawd2 = 0;
+	unsigned char tbl_idx = 0;
 
 	tbl_idx = atoi(argv[3]);
 	vawd1 = strtoul(argv[4], (char **)NULL, 16);
@@ -526,9 +620,10 @@
 	write_rate_table(tbl_idx, vawd1, vawd2);
 }
 
-void write_trTCM_table(unsigned char tbl_idx, unsigned int vawd1, unsigned int vawd2)
+void write_trTCM_table(unsigned char tbl_idx, unsigned int vawd1,
+		       unsigned int vawd2)
 {
-	unsigned int value, reg;
+	unsigned int value = 0, reg = 0;
 	unsigned int max_index = 32;
 
 	printf("trTCM_tbl_idx:%d\n", tbl_idx);
@@ -539,7 +634,7 @@
 	}
 
 	reg = REG_VTCR_ADDR;
-	while (1) { 	// wait until not busy
+	while (1) {		// wait until not busy
 		reg_read(reg, &value);
 		if ((value & REG_VTCR_BUSY_MASK) == 0)
 			break;
@@ -554,16 +649,17 @@
 	reg_write(reg, value);
 	printf("write reg: %x, value: %x\n", reg, value);
 
-	while (1) { // wait until not busy
+	while (1) {		// wait until not busy
 		reg_read(reg, &value);
 		if ((value & REG_VTCR_BUSY_MASK) == 0)
 			break;
 	}
 }
 
-int acl_parameters_pre_del(int len1, int len2, int argc, char *argv[], int *port)
+int acl_parameters_pre_del(int len1, int len2, int argc, char *argv[],
+			   int *port)
 {
-	int i;
+	int i = 0;
 
 	*port = 0;
 	if (argc < len1) {
@@ -571,10 +667,11 @@
 		return -1;
 	}
 
-	if (len2 == 12)
-	{
+	if (len2 == 12) {
 		if (!argv[4] || strlen(argv[4]) != len2) {
-			printf("The [%s] format error, should be of length %d\n",argv[4], len2);
+			printf
+			    ("The [%s] format error, should be of length %d\n",
+			     argv[4], len2);
 			return -1;
 		}
 	}
@@ -586,7 +683,8 @@
 
 	for (i = 0; i < 7; i++) {
 		if (argv[5][i] != '0' && argv[5][i] != '1') {
-			printf("portmap format error, should be of combination of 0 or 1\n");
+			printf
+			    ("portmap format error, should be of combination of 0 or 1\n");
 			return -1;
 		}
 		*port += (argv[5][i] - '0') * (1 << i);
@@ -594,31 +692,32 @@
 	return 0;
 }
 
-void acl_compare_pattern(int ports, int comparion, int base, int word, unsigned char table_index)
+void acl_compare_pattern(int ports, int comparion, int base, int word,
+			 unsigned char table_index)
 {
-	unsigned int value;
+	unsigned int value = 0;
 
-	comparion |= 0xffff0000; //compare mask
+	comparion |= 0xffff0000;	//compare mask
 
-	value = ports << 8; //w_port_map
-	value |= 0x1 << 19; //enable
-	value |= base << 16; //mac header
-	value |= word << 1;  //word offset
+	value = ports << 8;	//w_port_map
+	value |= 0x1 << 19;	//enable
+	value |= base << 16;	//mac header
+	value |= word << 1;	//word offset
 
 	write_acl_table(table_index, comparion, value);
 }
 
 void acl_mac_add(int argc, char *argv[])
 {
-	unsigned int value;
-	int ports;
+	unsigned int value = 0;
+	int ports = 0;
 	char tmpstr[5];
 	int ret;
 
 	ret = acl_parameters_pre_del(6, 12, argc, argv, &ports);
 	if (ret < 0)
 		return;
-	//set pattern
+	/* Set pattern */
 	strncpy(tmpstr, argv[4], 4);
 	tmpstr[4] = '\0';
 	value = strtoul(tmpstr, NULL, 16);
@@ -635,20 +734,20 @@
 	acl_compare_pattern(ports, value, 0x0, 2, 2);
 
 	//set mask
-	write_acl_mask_table(0,0x7,0);
+	write_acl_mask_table(0, 0x7, 0);
 
 	//set action
-	value = 0x7;      //drop
-	value |= 1 << 28; //acl intterupt enable
-	value |= 1 << 27; //acl hit count
-	value |= 2 << 24; //acl hit count group index (0~3)
-	write_acl_rule_table(0,value,0);
+	value = 0x7;		//drop
+	value |= 1 << 28;	//acl intterupt enable
+	value |= 1 << 27;	//acl hit count
+	value |= 2 << 24;	//acl hit count group index (0~3)
+	write_acl_rule_table(0, value, 0);
 }
 
 void acl_dip_meter(int argc, char *argv[])
 {
-	unsigned int value, ip_value, meter;
-	int ports;
+	unsigned int value = 0, ip_value = 0, meter = 0;
+	int ports = 0;
 	int ret;
 
 	ip_value = 0;
@@ -666,31 +765,31 @@
 	acl_compare_pattern(ports, value, 0x2, 0x9, 1);
 
 	//set mask
-	write_acl_mask_table(0,0x3,0);
+	write_acl_mask_table(0, 0x3, 0);
 
 	//set action
 	meter = strtoul(argv[6], NULL, 0);
 	if (((chip_name == 0x7530) && (meter > 1000000)) ||
-		((chip_name == 0x7531) && (meter > 2500000)) ||
-		((chip_name == 0x7988) && (meter > 4000000))) {
+	    ((chip_name == 0x7531) && (meter > 2500000)) ||
+	    ((chip_name == 0x7988) && (meter > 4000000))) {
 		printf("\n**Illegal meter input, and 7530: 0~1000000Kpbs, 7531: 0~2500000Kpbs, 7988: 0~4000000Kpbs**\n");
 		return;
 	}
 	if (((chip_name == 0x7531 || chip_name == 0x7988) && (meter > 1000000))) {
-		reg_read(0xc,&value);
+		reg_read(0xc, &value);
 		value |= 0x1 << 30;
-		reg_write(0xC,value);
-		printf("AGC: 0x%x\n",value);
-		value = meter / 1000; //uint is 1Mbps
+		reg_write(0xC, value);
+		printf("AGC: 0x%x\n", value);
+		value = meter / 1000;	//uint is 1Mbps
 	} else {
-		reg_read(0xc,&value);
+		reg_read(0xc, &value);
 		value &= ~(0x1 << 30);
-		reg_write(0xC,value);
-		printf("AGC: 0x%x\n",value);
-		value = meter >> 6; //uint is 64Kbps
+		reg_write(0xC, value);
+		printf("AGC: 0x%x\n", value);
+		value = meter >> 6;	//uint is 64Kbps
 	}
-	value |= 0x1 << 15; //enable rate control
-	printf("Acl rate control:0x%x\n",value);
+	value |= 0x1 << 15;	//enable rate control
+	printf("Acl rate control:0x%x\n", value);
 	write_rate_table(0, value, 0);
 }
 
@@ -721,30 +820,30 @@
 	PIR = strtoul(argv[8], NULL, 0);
 	PBS = strtoul(argv[9], NULL, 0);
 
-	if (CIR > 65535*64 || CBS > 65535 || PIR > 65535*64  || PBS > 65535) {
+	if (CIR > 65535 * 64 || CBS > 65535 || PIR > 65535 * 64 || PBS > 65535) {
 		printf("\n**Illegal input parameters**\n");
 		return;
 	}
 
-	value = CBS << 16; //bit16~31
-	value |= PBS;      //bit0~15
-			   //value |= 1;//valid
+	value = CBS << 16;	//bit16~31
+	value |= PBS;		//bit0~15
+	//value |= 1;//valid
 	CIR = CIR >> 6;
 	PIR = PIR >> 6;
 
-	value2 = CIR << 16; //bit16~31
-	value2 |= PIR;      //bit0~15
-	write_trTCM_table(0,value,value2);
+	value2 = CIR << 16;	//bit16~31
+	value2 |= PIR;		//bit0~15
+	write_trTCM_table(0, value, value2);
 
 	//set pattern
-	write_acl_mask_table(0,0x3,0);
+	write_acl_mask_table(0, 0x3, 0);
 
 	//set action
-	value = 0x1 << (11 + 1); //TrTCM green  meter#0 Low drop
-	value |= 0x2 << (8 + 1); //TrTCM yellow  meter#0 Med drop
-	value |= 0x3 << (5 + 1); //TrTCM red  meter#0    Hig drop
-	value |= 0x1 << 0;       //TrTCM drop pcd select
-	write_acl_rule_table(0,0,value);
+	value = 0x1 << (11 + 1);	//TrTCM green  meter#0 Low drop
+	value |= 0x2 << (8 + 1);	//TrTCM yellow  meter#0 Med drop
+	value |= 0x3 << (5 + 1);	//TrTCM red  meter#0    Hig drop
+	value |= 0x1 << 0;	//TrTCM drop pcd select
+	write_acl_rule_table(0, 0, value);
 }
 
 void acl_ethertype(int argc, char *argv[])
@@ -756,21 +855,21 @@
 	ret = acl_parameters_pre_del(6, -1, argc, argv, &ports);
 	if (ret < 0)
 		return;
-	printf("ports:0x%x\n",ports);
+	printf("ports:0x%x\n", ports);
 	ethertype = strtoul(argv[4], NULL, 16);
 	//set pattern
 	value = ethertype;
 	acl_compare_pattern(ports, value, 0x0, 0x6, 0);
 
 	//set pattern
-	write_acl_mask_table(0,0x1,0);
+	write_acl_mask_table(0, 0x1, 0);
 
 	//set action(drop)
-	value = 0x7;      //default. Nodrop
-	value |= 1 << 28; //acl intterupt enable
-	value |= 1 << 27; //acl hit count
+	value = 0x7;		//default. Nodrop
+	value |= 1 << 28;	//acl intterupt enable
+	value |= 1 << 27;	//acl hit count
 
-	write_acl_rule_table(0,value,0);
+	write_acl_rule_table(0, value, 0);
 }
 
 void acl_dip_modify(int argc, char *argv[])
@@ -801,14 +900,14 @@
 	acl_compare_pattern(ports, value, 0x2, 0x9, 1);
 
 	//set pattern
-	write_acl_mask_table(0,0x3,0);
+	write_acl_mask_table(0, 0x3, 0);
 
 	//set action
-	value = 0x0;      //default. Nodrop
-	value |= 1 << 28; //acl intterupt enable
-	value |= 1 << 27; //acl hit count
-	value |= priority << 4;  //acl UP
-	write_acl_rule_table(0,value,0);
+	value = 0x0;		//default. Nodrop
+	value |= 1 << 28;	//acl intterupt enable
+	value |= 1 << 27;	//acl hit count
+	value |= priority << 4;	//acl UP
+	write_acl_rule_table(0, value, 0);
 }
 
 void acl_dip_pppoe(int argc, char *argv[])
@@ -832,16 +931,16 @@
 	acl_compare_pattern(ports, value, 0x2, 0x9, 1);
 
 	//set pattern
-	write_acl_mask_table(0,0x3,0);
+	write_acl_mask_table(0, 0x3, 0);
 
 	//set action
-	value = 0x0;      //default. Nodrop
-	value |= 1 << 28; //acl intterupt enable
-	value |= 1 << 27; //acl hit count
-	value |= 1 << 20; //pppoe header remove
-	value |= 1 << 21; //SA MAC SWAP
-	value |= 1 << 22; //DA MAC SWAP
-	write_acl_rule_table(0,value,7);
+	value = 0x0;		//default. Nodrop
+	value |= 1 << 28;	//acl intterupt enable
+	value |= 1 << 27;	//acl hit count
+	value |= 1 << 20;	//pppoe header remove
+	value |= 1 << 21;	//SA MAC SWAP
+	value |= 1 << 22;	//DA MAC SWAP
+	write_acl_rule_table(0, value, 7);
 }
 
 void acl_dip_add(int argc, char *argv[])
@@ -865,20 +964,20 @@
 	acl_compare_pattern(ports, value, 0x2, 0x9, 1);
 
 	//set pattern
-	write_acl_mask_table(0,0x3,0);
+	write_acl_mask_table(0, 0x3, 0);
 
 	//set action
 	//value = 0x0; //default
-	value = 0x7;      //drop
-	value |= 1 << 28; //acl intterupt enable
-	value |= 1 << 27; //acl hit count
-	value |= 2 << 24; //acl hit count group index (0~3)
-	write_acl_rule_table(0,value,0);
+	value = 0x7;		//drop
+	value |= 1 << 28;	//acl intterupt enable
+	value |= 1 << 27;	//acl hit count
+	value |= 2 << 24;	//acl hit count group index (0~3)
+	write_acl_rule_table(0, value, 0);
 }
 
 void acl_l4_add(int argc, char *argv[])
 {
-	unsigned int value;
+	unsigned int value = 0;
 	int ports;
 	int ret;
 
@@ -891,16 +990,16 @@
 	acl_compare_pattern(ports, value, 0x5, 0x0, 0);
 
 	//set rue mask
-	write_acl_mask_table(0,0x1,0);
+	write_acl_mask_table(0, 0x1, 0);
 	//set action
-	value = 0x7; //drop
-		     //value |= 1;//valid
-	write_acl_rule_table(0,value,0);
+	value = 0x7;		//drop
+	//value |= 1;//valid
+	write_acl_rule_table(0, value, 0);
 }
 
 void acl_sp_add(int argc, char *argv[])
 {
-	unsigned int value;
+	unsigned int value = 0;
 	int ports;
 	int ret;
 
@@ -912,31 +1011,31 @@
 	acl_compare_pattern(ports, value, 0x4, 0x0, 0);
 
 	//set rue mask
-	write_acl_mask_table(0,0x1,0);
+	write_acl_mask_table(0, 0x1, 0);
 
 	//set action
-	value = 0x7; //drop
-		     //value |= 1;//valid
-	write_acl_rule_table(0,value,0);
+	value = 0x7;		//drop
+	//value |= 1;//valid
+	write_acl_rule_table(0, value, 0);
 }
 
 void acl_port_enable(int argc, char *argv[])
 {
-	unsigned int value, reg;
-	unsigned char acl_port, acl_en;
+	unsigned int value = 0, reg = 0;
+	unsigned char acl_port = 0, acl_en = 0;
 
 	acl_port = atoi(argv[3]);
 	acl_en = atoi(argv[4]);
 
 	printf("acl_port:%d, acl_en:%d\n", acl_port, acl_en);
 
-	/*Check the input parameters is right or not.*/
+	/*Check the input parameters is right or not. */
 	if ((acl_port > SWITCH_MAX_PORT) || (acl_en > 1)) {
 		printf(HELP_ACL_SETPORTEN);
 		return;
 	}
 
-	reg = REG_PCR_P0_ADDR + (0x100 * acl_port); // 0x2004[10]
+	reg = REG_PCR_P0_ADDR + (0x100 * acl_port);	// 0x2004[10]
 	reg_read(reg, &value);
 	value &= (~REG_PORT_ACL_EN_MASK);
 	value |= (acl_en << REG_PORT_ACL_EN_OFFT);
@@ -948,37 +1047,37 @@
 static void dip_dump_internal(int type)
 {
 	unsigned int i, j, value, mac, mac2, value2;
-	char tmpstr[16];
+	char tmpstr[16] = { 0 };
 	int table_size = 0;
 	int hit_value1 = 0;
 	int hit_value2 = 0;
 
-	if(type == GENERAL_TABLE) {
+	if (type == GENERAL_TABLE) {
 		table_size = 0x800;
-		reg_write(REG_ATC_ADDR, 0x8104); //dip search command
-		} else {
+		reg_write(REG_ATC_ADDR, 0x8104);	//dip search command
+	} else {
 		table_size = 0x40;
-		reg_write(REG_ATC_ADDR, 0x811c); //dip search command
+		reg_write(REG_ATC_ADDR, 0x811c);	//dip search command
 	}
-	printf("hash   port(0:6)   rsp_cnt  flag  timer    dip-address       ATRD\n");
+	printf
+	    ("hash   port(0:6)   rsp_cnt  flag  timer    dip-address       ATRD\n");
 	for (i = 0; i < table_size; i++) {
-		while (1)
-		{
+		while (1) {
 			reg_read(REG_ATC_ADDR, &value);
-			if(type == GENERAL_TABLE) {
+			if (type == GENERAL_TABLE) {
 				hit_value1 = value & (0x1 << 13);
 				hit_value2 = 1;
-			}else {
+			} else {
 				hit_value1 = value & (0x1 << 13);
 				hit_value2 = value & (0x1 << 28);
 			}
 
-			if (hit_value1 && hit_value2 ) { //search_rdy
+			if (hit_value1 && hit_value2) {	//search_rdy
 				reg_read(REG_ATRD_ADDR, &value2);
 				//printf("REG_ATRD_ADDR=0x%x\n\r",value2);
 
-				printf("%03x:   ", (value >> 16) & 0xfff); //hash_addr_lu
-				j = (value2 >> 4) & 0xff;		   //r_port_map
+				printf("%03x:   ", (value >> 16) & 0xfff);	//hash_addr_lu
+				j = (value2 >> 4) & 0xff;	//r_port_map
 				printf("%c", (j & 0x01) ? '1' : '-');
 				printf("%c", (j & 0x02) ? '1' : '-');
 				printf("%c", (j & 0x04) ? '1' : '-');
@@ -989,38 +1088,38 @@
 
 				reg_read(REG_TSRA2_ADDR, &mac2);
 
-				printf("     0x%4x", (mac2 & 0xffff));    //RESP_CNT
-				printf("  0x%2x", ((mac2 >> 16) & 0xff)); //RESP_FLAG
-				printf("  %3d", ((mac2 >> 24) & 0xff));   //RESP_TIMER
-									  //printf(" %4d", (value2 >> 24) & 0xff); //r_age_field
+				printf("     0x%4x", (mac2 & 0xffff));	//RESP_CNT
+				printf("  0x%2x", ((mac2 >> 16) & 0xff));	//RESP_FLAG
+				printf("  %3d", ((mac2 >> 24) & 0xff));	//RESP_TIMER
+				//printf(" %4d", (value2 >> 24) & 0xff); //r_age_field
 				reg_read(REG_TSRA1_ADDR, &mac);
 				ip_to_str(tmpstr, mac);
 				printf("     %s", tmpstr);
-				printf("  0x%8x\n", value2); //ATRD
-							     //printf("%04x", ((mac2 >> 16) & 0xffff));
-							     //printf("     %c\n", (((value2 >> 20) & 0x03)== 0x03)? 'y':'-');
+				printf("  0x%8x\n", value2);	//ATRD
+				//printf("%04x", ((mac2 >> 16) & 0xffff));
+				//printf("     %c\n", (((value2 >> 20) & 0x03)== 0x03)? 'y':'-');
 				if (value & 0x4000) {
 					printf("end of table %d\n", i);
 					return;
 				}
 				break;
-			}
-			else if (value & 0x4000) { //at_table_end
-				printf("found the last entry %d (not ready)\n", i);
+			} else if (value & 0x4000) {	//at_table_end
+				printf("found the last entry %d (not ready)\n",
+				       i);
 				return;
 			}
 			usleep(5000);
 		}
 
-		if(type == GENERAL_TABLE)
-			reg_write(REG_ATC_ADDR, 0x8105); //search for next dip address
+		if (type == GENERAL_TABLE)
+			reg_write(REG_ATC_ADDR, 0x8105);	//search for next dip address
 		else
-			reg_write(REG_ATC_ADDR, 0x811d); //search for next dip address
+			reg_write(REG_ATC_ADDR, 0x811d);	//search for next dip address
 		usleep(5000);
 	}
 }
 
-void dip_dump(void)
+void dip_dump(int argc, char *argv[])
 {
 	dip_dump_internal(GENERAL_TABLE);
 
@@ -1029,7 +1128,7 @@
 void dip_add(int argc, char *argv[])
 {
 	unsigned int value = 0;
-	unsigned int i, j;
+	unsigned int i = 0, j = 0;
 
 	value = 0;
 
@@ -1049,13 +1148,14 @@
 	j = 0;
 	for (i = 0; i < 7; i++) {
 		if (argv[4][i] != '0' && argv[4][i] != '1') {
-			printf("portmap format error, should be of combination of 0 or 1\n");
+			printf
+			    ("portmap format error, should be of combination of 0 or 1\n");
 			return;
 		}
 		j += (argv[4][i] - '0') * (1 << i);
 	}
-	value = j << 4;      //w_port_map
-	value |= (0x3 << 2); //static
+	value = j << 4;		//w_port_map
+	value |= (0x3 << 2);	//static
 
 	reg_write(REG_ATWD_ADDR, value);
 
@@ -1063,14 +1163,14 @@
 	reg_read(REG_ATWD_ADDR, &value);
 	printf("REG_ATWD_ADDR is 0x%x\n\r", value);
 
-	value = 0x8011; //single w_dip_cmd
+	value = 0x8011;		//single w_dip_cmd
 	reg_write(REG_ATC_ADDR, value);
 
 	usleep(1000);
 
 	for (i = 0; i < 20; i++) {
 		reg_read(REG_ATC_ADDR, &value);
-		if ((value & 0x8000) == 0) { //mac address busy
+		if ((value & 0x8000) == 0) {	//mac address busy
 			printf("done.\n");
 			return;
 		}
@@ -1092,15 +1192,15 @@
 	value = 0;
 	reg_write(REG_ATA2_ADDR, value);
 
-	value = 0; //STATUS=0, delete dip
+	value = 0;		//STATUS=0, delete dip
 	reg_write(REG_ATWD_ADDR, value);
 
-	value = 0x8011; //w_dip_cmd
+	value = 0x8011;		//w_dip_cmd
 	reg_write(REG_ATC_ADDR, value);
 
 	for (i = 0; i < 20; i++) {
 		reg_read(REG_ATC_ADDR, &value);
-		if ((value & 0x8000) == 0) { //mac address busy
+		if ((value & 0x8000) == 0) {	//mac address busy
 			if (argv[1] != NULL)
 				printf("done.\n");
 			return;
@@ -1111,12 +1211,12 @@
 		printf("timeout.\n");
 }
 
-void dip_clear(void)
+void dip_clear(int argc, char *argv[])
 {
 
-	unsigned int value;
+	unsigned int value = 0;
 
-	reg_write(REG_ATC_ADDR, 0x8102); //clear all dip
+	reg_write(REG_ATC_ADDR, 0x8102);	//clear all dip
 	usleep(5000);
 	reg_read(REG_ATC_ADDR, &value);
 	printf("REG_ATC_ADDR is 0x%x\n\r", value);
@@ -1124,25 +1224,24 @@
 
 static void sip_dump_internal(int type)
 {
-	unsigned int i, j, value, mac, mac2, value2;
+	unsigned int i = 0, j = 0, value = 0, mac = 0, mac2 = 0, value2 = 0;
 	int table_size = 0;
 	int hit_value1 = 0;
 	int hit_value2 = 0;
-	char tmpstr[16];
+	char tmpstr[16] = { 0 };
 
 	if (type == GENERAL_TABLE) {
 		table_size = 0x800;
-		reg_write(REG_ATC_ADDR, 0x8204); //sip search command
-		}else {
+		reg_write(REG_ATC_ADDR, 0x8204);	//sip search command
+	} else {
 		table_size = 0x40;
-		reg_write(REG_ATC_ADDR, 0x822c); //sip search command
+		reg_write(REG_ATC_ADDR, 0x822c);	//sip search command
 	}
 	printf("hash  port(0:6)   dip-address    sip-address      ATRD\n");
 	for (i = 0; i < table_size; i++) {
-		while (1)
-		{
+		while (1) {
 			reg_read(REG_ATC_ADDR, &value);
-			if(type == GENERAL_TABLE) {
+			if (type == GENERAL_TABLE) {
 				hit_value1 = value & (0x1 << 13);
 				hit_value2 = 1;
 			} else {
@@ -1150,12 +1249,12 @@
 				hit_value2 = value & (0x1 << 28);
 			}
 
-			if (hit_value1 && hit_value2) { //search_rdy
+			if (hit_value1 && hit_value2) {	//search_rdy
 				reg_read(REG_ATRD_ADDR, &value2);
 				//printf("REG_ATRD_ADDR=0x%x\n\r",value2);
 
-				printf("%03x:  ", (value >> 16) & 0xfff); //hash_addr_lu
-				j = (value2 >> 4) & 0xff;		  //r_port_map
+				printf("%03x:  ", (value >> 16) & 0xfff);	//hash_addr_lu
+				j = (value2 >> 4) & 0xff;	//r_port_map
 				printf("%c", (j & 0x01) ? '1' : '-');
 				printf("%c", (j & 0x02) ? '1' : '-');
 				printf("%c", (j & 0x04) ? '1' : '-');
@@ -1181,42 +1280,42 @@
 					return;
 				}
 				break;
-			} else if (value & 0x4000) { //at_table_end
-				printf("found the last entry %d (not ready)\n", i);
+			} else if (value & 0x4000) {	//at_table_end
+				printf("found the last entry %d (not ready)\n",
+				       i);
 				return;
 			}
 			usleep(5000);
 		}
 
-	if(type == GENERAL_TABLE)
-		reg_write(REG_ATC_ADDR, 0x8205); //search for next sip address
-	else
-		reg_write(REG_ATC_ADDR, 0x822d); //search for next sip address
-	usleep(5000);
+		if (type == GENERAL_TABLE)
+			reg_write(REG_ATC_ADDR, 0x8205);	//search for next sip address
+		else
+			reg_write(REG_ATC_ADDR, 0x822d);	//search for next sip address
+		usleep(5000);
 	}
 }
 
-void sip_dump(void)
+void sip_dump(int argc, char *argv[])
 {
 
 	sip_dump_internal(GENERAL_TABLE);
 
 }
 
-
 void sip_add(int argc, char *argv[])
 {
-	unsigned int i, j, value;
+	unsigned int i = 0, j = 0, value = 0;
 
 	value = 0;
-	str_to_ip(&value, argv[3]); //SIP
+	str_to_ip(&value, argv[3]);	//SIP
 
 	reg_write(REG_ATA2_ADDR, value);
 	printf("REG_ATA2_ADDR is 0x%x\n\r", value);
 
 	value = 0;
 
-	str_to_ip(&value, argv[4]); //DIP
+	str_to_ip(&value, argv[4]);	//DIP
 	reg_write(REG_ATA1_ADDR, value);
 	printf("REG_ATA1_ADDR is 0x%x\n\r", value);
 
@@ -1227,13 +1326,14 @@
 	j = 0;
 	for (i = 0; i < 7; i++) {
 		if (argv[5][i] != '0' && argv[5][i] != '1') {
-			printf("portmap format error, should be of combination of 0 or 1\n");
+			printf
+			    ("portmap format error, should be of combination of 0 or 1\n");
 			return;
 		}
 		j += (argv[5][i] - '0') * (1 << i);
 	}
-	value = j << 4;      //w_port_map
-	value |= (0x3 << 2); //static
+	value = j << 4;		//w_port_map
+	value |= (0x3 << 2);	//static
 
 	reg_write(REG_ATWD_ADDR, value);
 
@@ -1241,14 +1341,14 @@
 	reg_read(REG_ATWD_ADDR, &value);
 	printf("REG_ATWD_ADDR is 0x%x\n\r", value);
 
-	value = 0x8021; //single w_sip_cmd
+	value = 0x8021;		//single w_sip_cmd
 	reg_write(REG_ATC_ADDR, value);
 
 	usleep(1000);
 
 	for (i = 0; i < 20; i++) {
 		reg_read(REG_ATC_ADDR, &value);
-		if ((value & 0x8000) == 0) { //mac address busy
+		if ((value & 0x8000) == 0) {	//mac address busy
 			printf("done.\n");
 			return;
 		}
@@ -1260,25 +1360,25 @@
 
 void sip_del(int argc, char *argv[])
 {
-	unsigned int i, value;
+	unsigned int i = 0, value = 0;
 
 	value = 0;
 	str_to_ip(&value, argv[3]);
 
-	reg_write(REG_ATA2_ADDR, value); //SIP
+	reg_write(REG_ATA2_ADDR, value);	//SIP
 
 	str_to_ip(&value, argv[4]);
-	reg_write(REG_ATA1_ADDR, value); //DIP
+	reg_write(REG_ATA1_ADDR, value);	//DIP
 
-	value = 0; //STATUS=0, delete sip
+	value = 0;		//STATUS=0, delete sip
 	reg_write(REG_ATWD_ADDR, value);
 
-	value = 0x8021; //w_sip_cmd
+	value = 0x8021;		//w_sip_cmd
 	reg_write(REG_ATC_ADDR, value);
 
 	for (i = 0; i < 20; i++) {
 		reg_read(REG_ATC_ADDR, &value);
-		if ((value & 0x8000) == 0) { //mac address busy
+		if ((value & 0x8000) == 0) {	//mac address busy
 			if (argv[1] != NULL)
 				printf("done.\n");
 			return;
@@ -1289,11 +1389,11 @@
 		printf("timeout.\n");
 }
 
-void sip_clear(void)
+void sip_clear(int argc, char *argv[])
 {
-	unsigned int value;
+	unsigned int value = 0;
 
-	reg_write(REG_ATC_ADDR, 0x8202); //clear all sip
+	reg_write(REG_ATC_ADDR, 0x8202);	//clear all sip
 	usleep(5000);
 	reg_read(REG_ATC_ADDR, &value);
 	printf("REG_ATC_ADDR is 0x%x\n\r", value);
@@ -1301,13 +1401,13 @@
 
 static void table_dump_internal(int type)
 {
-	unsigned int i, j, value, mac, mac2, value2;
+	unsigned int i = 0, j = 0, value = 0, mac = 0, mac2 = 0, value2 = 0;
 	int table_size = 0;
 	int table_end = 0;
 	int hit_value1 = 0;
 	int hit_value2 = 0;
 
-	if (type == GENERAL_TABLE){
+	if (type == GENERAL_TABLE) {
 		table_size = 0x800;
 		table_end = 0x7FF;
 		reg_write(REG_ATC_ADDR, 0x8004);
@@ -1316,13 +1416,13 @@
 		table_end = 0x3F;
 		reg_write(REG_ATC_ADDR, 0x800C);
 	}
-	printf("hash  port(0:6)   fid   vid  age(s)   mac-address     filter my_mac\n");
+	printf
+	    ("hash  port(0:6)   fid   vid  age(s)   mac-address     filter my_mac\n");
 	for (i = 0; i < table_size; i++) {
-		while (1)
-		{
+		while (1) {
 			reg_read(REG_ATC_ADDR, &value);
 			//printf("ATC =  0x%x\n", value);
-			if(type == GENERAL_TABLE) {
+			if (type == GENERAL_TABLE) {
 				hit_value1 = value & (0x1 << 13);
 				hit_value2 = 1;
 			} else {
@@ -1330,10 +1430,11 @@
 				hit_value2 = value & (0x1 << 28);
 			}
 
-			if (hit_value1 && hit_value2 && (((value >> 15) & 0x1) == 0)) {
+			if (hit_value1 && hit_value2
+			    && (((value >> 15) & 0x1) == 0)) {
 				printf("%03x:   ", (value >> 16) & 0xfff);
 				reg_read(REG_ATRD_ADDR, &value2);
-				j = (value2 >> 4) & 0xff; //r_port_map
+				j = (value2 >> 4) & 0xff;	//r_port_map
 				printf("%c", (j & 0x01) ? '1' : '-');
 				printf("%c", (j & 0x02) ? '1' : '-');
 				printf("%c", (j & 0x04) ? '1' : '-');
@@ -1345,49 +1446,52 @@
 
 				reg_read(REG_TSRA2_ADDR, &mac2);
 
-				printf("   %2d", (mac2 >> 12) & 0x7); //FID
+				printf("   %2d", (mac2 >> 12) & 0x7);	//FID
 				printf("  %4d", (mac2 & 0xfff));
 				if (((value2 >> 24) & 0xff) == 0xFF)
-					printf("   --- "); //r_age_field:static
+					printf("   --- ");	//r_age_field:static
 				else
-					printf(" %5d ", (((value2 >> 24) & 0xff)+1)*2); //r_age_field
+					printf(" %5d ", (((value2 >> 24) & 0xff) + 1) * 2);	//r_age_field
 				reg_read(REG_TSRA1_ADDR, &mac);
 				printf("  %08x", mac);
 				printf("%04x", ((mac2 >> 16) & 0xffff));
-				printf("     %c", (((value2 >> 20) & 0x03) == 0x03) ? 'y' : '-');
-				printf("     %c\n", (((value2 >> 23) & 0x01) == 0x01) ? 'y' : '-');
-				if ((value & 0x4000) && (((value >> 16) & 0xfff) == table_end)) {
+				printf("     %c",
+				       (((value2 >> 20) & 0x03) ==
+					0x03) ? 'y' : '-');
+				printf("     %c\n",
+				       (((value2 >> 23) & 0x01) ==
+					0x01) ? 'y' : '-');
+				if ((value & 0x4000)
+				    && (((value >> 16) & 0xfff) == table_end)) {
 					printf("end of table %d\n", i);
 					return;
 				}
 				break;
-			}
-			else if ((value & 0x4000) && (((value >> 15) & 0x1) == 0) && (((value >> 16) & 0xfff) == table_end)) { //at_table_end
-				printf("found the last entry %d (not ready)\n", i);
+			} else if ((value & 0x4000) && (((value >> 15) & 0x1) == 0) && (((value >> 16) & 0xfff) == table_end)) {	//at_table_end
+				printf("found the last entry %d (not ready)\n",
+				       i);
 				return;
-			}
-			else
+			} else
 				usleep(5);
 		}
 
-	if(type == GENERAL_TABLE)
-		reg_write(REG_ATC_ADDR, 0x8005);//search for next address
-	else
-		reg_write(REG_ATC_ADDR, 0x800d);//search for next address
+		if (type == GENERAL_TABLE)
+			reg_write(REG_ATC_ADDR, 0x8005);	//search for next address
+		else
+			reg_write(REG_ATC_ADDR, 0x800d);	//search for next address
 		usleep(5);
 	}
 }
 
-void table_dump(void)
+void table_dump(int argc, char *argv[])
 {
 	table_dump_internal(GENERAL_TABLE);
 
 }
 
-
 void table_add(int argc, char *argv[])
 {
-	unsigned int i, j, value, is_filter, is_mymac;
+	unsigned int i = 0, j = 0, value = 0, is_filter = 0, is_mymac = 0;
 	char tmpstr[9];
 
 	is_filter = (argv[1][0] == 'f') ? 1 : 0;
@@ -1407,7 +1511,7 @@
 
 	value = strtoul(tmpstr, NULL, 16);
 	value = (value << 16);
-	value |= (1 << 15); //IVL=1
+	value |= (1 << 15);	//IVL=1
 
 	if (argc > 4) {
 		j = strtoul(argv[4], NULL, 0);
@@ -1415,7 +1519,7 @@
 			printf("wrong vid range, should be within 0~4095\n");
 			return;
 		}
-		value |= j; //vid
+		value |= j;	//vid
 	}
 
 	reg_write(REG_ATA2_ADDR, value);
@@ -1432,12 +1536,13 @@
 	j = 0;
 	for (i = 0; i < 7; i++) {
 		if (argv[3][i] != '0' && argv[3][i] != '1') {
-			printf("portmap format error, should be of combination of 0 or 1\n");
+			printf
+			    ("portmap format error, should be of combination of 0 or 1\n");
 			return;
 		}
 		j += (argv[3][i] - '0') * (1 << i);
 	}
-	value = j << 4; //w_port_map
+	value = j << 4;		//w_port_map
 
 	if (argc > 5) {
 		j = strtoul(argv[5], NULL, 0);
@@ -1445,11 +1550,11 @@
 			printf("wrong age range, should be within 1~255\n");
 			return;
 		}
-		value |= (j << 24);  //w_age_field
-		value |= (0x1 << 2); //dynamic
+		value |= (j << 24);	//w_age_field
+		value |= (0x1 << 2);	//dynamic
 	} else {
-		value |= (0xff << 24); //w_age_field
-		value |= (0x3 << 2);   //static
+		value |= (0xff << 24);	//w_age_field
+		value |= (0x3 << 2);	//static
 	}
 
 	if (argc > 6) {
@@ -1458,11 +1563,11 @@
 			printf("wrong eg-tag range, should be within 0~7\n");
 			return;
 		}
-		value |= (j << 13); //EG_TAG
+		value |= (j << 13);	//EG_TAG
 	}
 
 	if (is_filter)
-		value |= (7 << 20); //sa_filter
+		value |= (7 << 20);	//sa_filter
 
 	if (is_mymac)
 		value |= (1 << 23);
@@ -1473,14 +1578,14 @@
 	reg_read(REG_ATWD_ADDR, &value);
 	printf("REG_ATWD_ADDR is 0x%x\n\r", value);
 
-	value = 0x8001; //w_mac_cmd
+	value = 0x8001;		//w_mac_cmd
 	reg_write(REG_ATC_ADDR, value);
 
 	usleep(1000);
 
 	for (i = 0; i < 20; i++) {
 		reg_read(REG_ATC_ADDR, &value);
-		if ((value & 0x8000) == 0) { //mac address busy
+		if ((value & 0x8000) == 0) {	//mac address busy
 			printf("done.\n");
 			return;
 		}
@@ -1492,7 +1597,7 @@
 
 void table_search_mac_vid(int argc, char *argv[])
 {
-	unsigned int i, j, value, mac, mac2, value2;
+	unsigned int i = 0, j = 0, value = 0, mac = 0, mac2 = 0, value2 = 0;
 	char tmpstr[9];
 
 	if (!argv[3] || strlen(argv[3]) != 12) {
@@ -1510,26 +1615,26 @@
 
 	value = strtoul(tmpstr, NULL, 16);
 	value = (value << 16);
-	value |= (1 << 15); //IVL=1
+	value |= (1 << 15);	//IVL=1
 
 	j = strtoul(argv[5], NULL, 0);
 	if (4095 < j) {
 		printf("wrong vid range, should be within 0~4095\n");
 		return;
 	}
-	value |= j; //vid
+	value |= j;		//vid
 
 	reg_write(REG_ATA2_ADDR, value);
 	//printf("REG_ATA2_ADDR is 0x%x\n\r",value);
 
-	value = 0x8000; //w_mac_cmd
+	value = 0x8000;		//w_mac_cmd
 	reg_write(REG_ATC_ADDR, value);
 
 	usleep(1000);
 
 	for (i = 0; i < 20; i++) {
 		reg_read(REG_ATC_ADDR, &value);
-		if ((value & 0x8000) == 0) { //mac address busy
+		if ((value & 0x8000) == 0) {	//mac address busy
 			break;
 		}
 		usleep(1000);
@@ -1545,11 +1650,12 @@
 	}
 
 	printf("search done.\n");
-	printf("hash  port(0:6)   fid   vid  age   mac-address     filter my_mac\n");
+	printf
+	    ("hash  port(0:6)   fid   vid  age   mac-address     filter my_mac\n");
 
-	printf("%03x:   ", (value >> 16) & 0xfff); //hash_addr_lu
+	printf("%03x:   ", (value >> 16) & 0xfff);	//hash_addr_lu
 	reg_read(REG_ATRD_ADDR, &value2);
-	j = (value2 >> 4) & 0xff; //r_port_map
+	j = (value2 >> 4) & 0xff;	//r_port_map
 	printf("%c", (j & 0x01) ? '1' : '-');
 	printf("%c", (j & 0x02) ? '1' : '-');
 	printf("%c", (j & 0x04) ? '1' : '-');
@@ -1561,9 +1667,9 @@
 
 	reg_read(REG_TSRA2_ADDR, &mac2);
 
-	printf("   %2d", (mac2 >> 12) & 0x7); //FID
+	printf("   %2d", (mac2 >> 12) & 0x7);	//FID
 	printf("  %4d", (mac2 & 0xfff));
-	printf(" %4d", (value2 >> 24) & 0xff); //r_age_field
+	printf(" %4d", (value2 >> 24) & 0xff);	//r_age_field
 	reg_read(REG_TSRA1_ADDR, &mac);
 	printf("  %08x", mac);
 	printf("%04x", ((mac2 >> 16) & 0xffff));
@@ -1573,7 +1679,7 @@
 
 void table_search_mac_fid(int argc, char *argv[])
 {
-	unsigned int i, j, value, mac, mac2, value2;
+	unsigned int i = 0, j = 0, value = 0, mac = 0, mac2 = 0, value2 = 0;
 	char tmpstr[9];
 
 	if (!argv[3] || strlen(argv[3]) != 12) {
@@ -1591,26 +1697,26 @@
 
 	value = strtoul(tmpstr, NULL, 16);
 	value = (value << 16);
-	value &= ~(1 << 15); //IVL=0
+	value &= ~(1 << 15);	//IVL=0
 
 	j = strtoul(argv[5], NULL, 0);
 	if (7 < j) {
 		printf("wrong fid range, should be within 0~7\n");
 		return;
 	}
-	value |= (j << 12); //vid
+	value |= (j << 12);	//vid
 
 	reg_write(REG_ATA2_ADDR, value);
 	//printf("REG_ATA2_ADDR is 0x%x\n\r",value);
 
-	value = 0x8000; //w_mac_cmd
+	value = 0x8000;		//w_mac_cmd
 	reg_write(REG_ATC_ADDR, value);
 
 	usleep(1000);
 
 	for (i = 0; i < 20; i++) {
 		reg_read(REG_ATC_ADDR, &value);
-		if ((value & 0x8000) == 0) { //mac address busy
+		if ((value & 0x8000) == 0) {	//mac address busy
 			break;
 		}
 		usleep(1000);
@@ -1626,11 +1732,12 @@
 	}
 
 	printf("search done.\n");
-	printf("hash  port(0:6)   fid   vid  age   mac-address     filter my_mac\n");
+	printf
+	    ("hash  port(0:6)   fid   vid  age   mac-address     filter my_mac\n");
 
-	printf("%03x:   ", (value >> 16) & 0xfff); //hash_addr_lu
+	printf("%03x:   ", (value >> 16) & 0xfff);	//hash_addr_lu
 	reg_read(REG_ATRD_ADDR, &value2);
-	j = (value2 >> 4) & 0xff; //r_port_map
+	j = (value2 >> 4) & 0xff;	//r_port_map
 	printf("%c", (j & 0x01) ? '1' : '-');
 	printf("%c", (j & 0x02) ? '1' : '-');
 	printf("%c", (j & 0x04) ? '1' : '-');
@@ -1642,9 +1749,9 @@
 
 	reg_read(REG_TSRA2_ADDR, &mac2);
 
-	printf("   %2d", (mac2 >> 12) & 0x7); //FID
+	printf("   %2d", (mac2 >> 12) & 0x7);	//FID
 	printf("  %4d", (mac2 & 0xfff));
-	printf(" %4d", (value2 >> 24) & 0xff); //r_age_field
+	printf(" %4d", (value2 >> 24) & 0xff);	//r_age_field
 	reg_read(REG_TSRA1_ADDR, &mac);
 	printf("  %08x", mac);
 	printf("%04x", ((mac2 >> 16) & 0xffff));
@@ -1654,7 +1761,7 @@
 
 void table_del_fid(int argc, char *argv[])
 {
-	unsigned int i, j, value;
+	unsigned int i = 0, j = 0, value = 0;
 	char tmpstr[9];
 
 	if (!argv[3] || strlen(argv[3]) != 12) {
@@ -1676,20 +1783,20 @@
 			printf("wrong fid range, should be within 0~7\n");
 			return;
 		}
-		value |= (j << 12); //fid
+		value |= (j << 12);	/* fid */
 	}
 
 	reg_write(REG_ATA2_ADDR, value);
 
-	value = 0; //STATUS=0, delete mac
+	value = 0;		/* STATUS=0, delete mac */
 	reg_write(REG_ATWD_ADDR, value);
 
-	value = 0x8001; //w_mac_cmd
+	value = 0x8001;		//w_mac_cmd
 	reg_write(REG_ATC_ADDR, value);
 
 	for (i = 0; i < 20; i++) {
 		reg_read(REG_ATC_ADDR, &value);
-		if ((value & 0x8000) == 0) { //mac address busy
+		if ((value & 0x8000) == 0) {	/* mac address busy */
 			if (argv[1] != NULL)
 				printf("done.\n");
 			return;
@@ -1702,7 +1809,7 @@
 
 void table_del_vid(int argc, char *argv[])
 {
-	unsigned int i, j, value;
+	unsigned int i = 0, j = 0, value = 0;
 	char tmpstr[9];
 
 	if (!argv[3] || strlen(argv[3]) != 12) {
@@ -1724,19 +1831,19 @@
 		printf("wrong fid range, should be within 0~4095\n");
 		return;
 	}
-	value |= j; //vid
+	value |= j;		//vid
 	value |= 1 << 15;
 	reg_write(REG_ATA2_ADDR, value);
 
-	value = 0; //STATUS=0, delete mac
+	value = 0;		//STATUS=0, delete mac
 	reg_write(REG_ATWD_ADDR, value);
 
-	value = 0x8001; //w_mac_cmd
+	value = 0x8001;		//w_mac_cmd
 	reg_write(REG_ATC_ADDR, value);
 
 	for (i = 0; i < 20; i++) {
 		reg_read(REG_ATC_ADDR, &value);
-		if ((value & 0x8000) == 0) { //mac address busy
+		if ((value & 0x8000) == 0) {	//mac address busy
 			if (argv[1] != NULL)
 				printf("done.\n");
 			return;
@@ -1747,9 +1854,10 @@
 		printf("timeout.\n");
 }
 
-void table_clear(void)
+void table_clear(int argc, char *argv[])
 {
-	unsigned int value;
+	unsigned int value = 0;
+
 	reg_write(REG_ATC_ADDR, 0x8002);
 	usleep(5000);
 	reg_read(REG_ATC_ADDR, &value);
@@ -1759,8 +1867,8 @@
 
 void set_mirror_to(int argc, char *argv[])
 {
-	unsigned int value;
-	int idx;
+	unsigned int value = 0;
+	int idx = 0;
 
 	idx = strtoul(argv[3], NULL, 0);
 	if (idx < 0 || MAX_PORT < idx) {
@@ -1788,8 +1896,8 @@
 
 void set_mirror_from(int argc, char *argv[])
 {
-	unsigned int offset, value;
-	int idx, mirror;
+	unsigned int offset = 0, value = 0;
+	int idx = 0, mirror = 0;
 
 	idx = strtoul(argv[3], NULL, 0);
 	mirror = strtoul(argv[4], NULL, 0);
@@ -1815,7 +1923,7 @@
 
 void vlan_dump(int argc, char *argv[])
 {
-	unsigned int i, j, value, value2;
+	unsigned int i = 0, j = 0, value = 0, value2 = 0;
 	int eg_tag = 0;
 
 	if (argc == 4) {
@@ -1824,17 +1932,18 @@
 	}
 
 	if (eg_tag)
-		printf("  vid  fid  portmap    s-tag\teg_tag(0:untagged 2:tagged)\n");
+		printf
+		    ("  vid  fid  portmap    s-tag\teg_tag(0:untagged 2:tagged)\n");
 	else
 		printf("  vid  fid  portmap    s-tag\n");
 
 	for (i = 1; i < 4095; i++) {
-		value = (0x80000000 + i); //r_vid_cmd
+		value = (0x80000000 + i);	//r_vid_cmd
 		reg_write(REG_VTCR_ADDR, value);
 
 		for (j = 0; j < 20; j++) {
 			reg_read(REG_VTCR_ADDR, &value);
-			if ((value & 0x80000000) == 0) { //mac address busy
+			if ((value & 0x80000000) == 0) {	//mac address busy
 				break;
 			}
 			usleep(1000);
@@ -1881,7 +1990,7 @@
 			}
 			printf("\n");
 		} else {
-			/*print 16 vid for reference information*/
+			/*print 16 vid for reference information */
 			if (i <= 16) {
 				printf(" %4d  ", i);
 				printf(" %2d ", ((value & 0xe) >> 1));
@@ -1891,7 +2000,6 @@
 	}
 }
 
-
 static long timespec_diff_us(struct timespec start, struct timespec end)
 {
 	struct timespec temp;
@@ -1904,32 +2012,31 @@
 		temp.tv_sec = end.tv_sec - start.tv_sec;
 		temp.tv_nsec = end.tv_nsec - start.tv_nsec;
 	}
-	/* calculate second part*/
+	/* calculate second part */
 	duration += temp.tv_sec * 1000000;
-	/* calculate ns part*/
+	/* calculate ns part */
 	duration += temp.tv_nsec >> 10;
 
 	return duration;
 }
 
-
 void vlan_clear(int argc, char *argv[])
 {
-	unsigned int value;
-	int vid;
+	unsigned int value = 0;
+	int vid = 0;
 	unsigned long duration_us = 0;
 	struct timespec start, end;
 
 	for (vid = 0; vid < 4096; vid++) {
 		clock_gettime(CLOCK_REALTIME, &start);
-		value = 0; //invalid
+		value = 0;	//invalid
 		reg_write(REG_VAWD1_ADDR, value);
 
-		value = (0x80001000 + vid); //w_vid_cmd
+		value = (0x80001000 + vid);	//w_vid_cmd
 		reg_write(REG_VTCR_ADDR, value);
 		while (duration_us <= 1000) {
 			reg_read(REG_VTCR_ADDR, &value);
-			if ((value & 0x80000000) == 0) { //table busy
+			if ((value & 0x80000000) == 0) {	//table busy
 				break;
 			}
 			clock_gettime(CLOCK_REALTIME, &end);
@@ -1945,7 +2052,7 @@
 	unsigned int vlan_mem = 0;
 	unsigned int value = 0;
 	unsigned int value2 = 0;
-	int i, vid, fid;
+	int i = 0, vid = 0, fid = 0;
 	int stag = 0;
 	unsigned long eg_con = 0;
 	unsigned int eg_tag = 0;
@@ -1976,7 +2083,8 @@
 	vlan_mem = 0;
 	for (i = 0; i < 8; i++) {
 		if (argv[5][i] != '0' && argv[5][i] != '1') {
-			printf("portmap format error, should be of combination of 0 or 1\n");
+			printf
+			    ("portmap format error, should be of combination of 0 or 1\n");
 			return;
 		}
 		vlan_mem += (argv[5][i] - '0') * (1 << i);
@@ -1986,7 +2094,8 @@
 	if (argc > 6) {
 		stag = strtoul(argv[6], NULL, 16);
 		if (stag < 0 || 0xfff < stag) {
-			printf("wrong stag id range, should be within 0~4095\n");
+			printf
+			    ("wrong stag id range, should be within 0~4095\n");
 			return;
 		}
 		//printf("STAG is 0x%x\n", stag);
@@ -1994,33 +2103,35 @@
 
 	/* set vlan member */
 	value |= (vlan_mem << 16);
-	value |= (1 << 30);		//IVL=1
-	value |= ((stag & 0xfff) << 4); //stag
-	value |= 1;			//valid
+	value |= (1 << 30);	//IVL=1
+	value |= ((stag & 0xfff) << 4);	//stag
+	value |= 1;		//valid
 
 	if (argc > 7) {
 		eg_con = strtoul(argv[7], NULL, 2);
 		eg_con = !!eg_con;
-		value |= (eg_con << 29); //eg_con
-		value |= (1 << 28);      //eg tag control enable
+		value |= (eg_con << 29);	//eg_con
+		value |= (1 << 28);	//eg tag control enable
 	}
 
 	if (argc > 8 && !eg_con) {
 		if (strlen(argv[8]) != 8) {
-			printf("egtag portmap format error, should be of length 7\n");
+			printf
+			    ("egtag portmap format error, should be of length 7\n");
 			return;
 		}
 
 		for (i = 0; i < 8; i++) {
 			if (argv[8][i] < '0' || argv[8][i] > '3') {
-				printf("egtag portmap format error, should be of combination of 0 or 3\n");
+				printf
+				    ("egtag portmap format error, should be of combination of 0 or 3\n");
 				return;
 			}
 			//eg_tag += (argv[8][i] - '0') * (1 << i * 2);
 			eg_tag |= (argv[8][i] - '0') << (i * 2);
 		}
 
-		value |= (1 << 28);    //eg tag control enable
+		value |= (1 << 28);	//eg tag control enable
 		value2 &= ~(0xffff);
 		value2 |= eg_tag;
 	}
@@ -2028,14 +2139,14 @@
 	reg_write(REG_VAWD2_ADDR, value2);
 	//printf("VAWD1=0x%08x VAWD2=0x%08x ", value, value2);
 
-	value = (0x80001000 + vid); //w_vid_cmd
+	value = (0x80001000 + vid);	//w_vid_cmd
 	reg_write(REG_VTCR_ADDR, value);
 	//printf("VTCR=0x%08x\n", value);
 
 	for (i = 0; i < 300; i++) {
 		usleep(1000);
 		reg_read(REG_VTCR_ADDR, &value);
-		if ((value & 0x80000000) == 0) //table busy
+		if ((value & 0x80000000) == 0)	//table busy
 			break;
 	}
 
@@ -2047,7 +2158,7 @@
 {
 	unsigned int leaky_en = 0;
 	unsigned int wan_num = 4;
-	unsigned int port, offset, value;
+	unsigned int port = 0, offset = 0, value = 0;
 	char cmd[80];
 	int ret;
 
@@ -2074,8 +2185,7 @@
 			reg_write(0x2410, value & (~(1 << 3)));
 			reg_write(REG_ISC_ADDR, 0x01027d01);
 		}
-	}
-	else
+	} else
 		reg_write(REG_ISC_ADDR, 0x10027d60);
 
 	reg_write(0x1c, 0x08100810);
@@ -2086,15 +2196,15 @@
 	reg_write(0x2408, 0xb3ff);
 	reg_write(0x2608, 0xb3ff);
 	/* Enable Port ACL
-	* reg_write(0x2P04, 0xff0403);
-	*/
+	 * reg_write(0x2P04, 0xff0403);
+	 */
 	for (port = 0; port <= 6; port++) {
 		offset = 0x2004 + port * 0x100;
 		reg_read(offset, &value);
 		reg_write(offset, value | (1 << 10));
 	}
 
-	/*IGMP query only p4 -> p5*/
+	/*IGMP query only p4 -> p5 */
 	reg_write(0x94, 0x00ff0002);
 	if (wan_num == 4)
 		reg_write(0x98, 0x000a1008);
@@ -2114,7 +2224,7 @@
 	reg_write(0x98, 0x0);
 	reg_write(0x90, 0x8000b000);
 
-	/*IGMP p5 -> p4*/
+	/*IGMP p5 -> p4 */
 	reg_write(0x94, 0x00ff0002);
 	reg_write(0x98, 0x000a2008);
 	reg_write(0x90, 0x80005002);
@@ -2128,7 +2238,7 @@
 	reg_write(0x98, 0x0);
 	reg_write(0x90, 0x8000b001);
 
-	/*IGMP p0~p3 -> p6*/
+	/*IGMP p0~p3 -> p6 */
 	reg_write(0x94, 0x00ff0002);
 	if (wan_num == 4)
 		reg_write(0x98, 0x000a0f08);
@@ -2142,7 +2252,7 @@
 	reg_write(0x98, 0x0);
 	reg_write(0x90, 0x8000b002);
 
-	/*IGMP query only p6 -> p0~p3*/
+	/*IGMP query only p6 -> p0~p3 */
 	reg_write(0x94, 0x00ff0002);
 	reg_write(0x98, 0x000a4008);
 	reg_write(0x90, 0x80005004);
@@ -2159,18 +2269,21 @@
 	reg_write(0x98, 0x0);
 	reg_write(0x90, 0x8000b003);
 
-	/*Force eth2 to receive all igmp packets*/
-	snprintf(cmd, sizeof(cmd), "echo 2 > /sys/devices/virtual/net/%s/brif/%s/multicast_router", BR_DEVNAME, ETH_DEVNAME);
+	/*Force eth2 to receive all igmp packets */
+	snprintf(cmd, sizeof(cmd),
+		 "echo 2 > /sys/devices/virtual/net/%s/brif/%s/multicast_router",
+		 BR_DEVNAME, ETH_DEVNAME);
 	ret = system(cmd);
 	if (ret)
-		printf("Failed to set /sys/devices/virtual/net/%s/brif/%s/multicast_router\n",
-		       BR_DEVNAME, ETH_DEVNAME);
+		printf
+		    ("Failed to set /sys/devices/virtual/net/%s/brif/%s/multicast_router\n",
+		     BR_DEVNAME, ETH_DEVNAME);
 }
 
 void igmp_disable(int argc, char *argv[])
 {
-	unsigned int reg_offset, value;
-	int port_num;
+	unsigned int reg_offset = 0, value = 0;
+	int port_num = 0;
 
 	if (argc < 4) {
 		printf("insufficient arguments!\n");
@@ -2181,7 +2294,6 @@
 		printf("wrong port range, should be within 0~6\n");
 		return;
 	}
-
 	//set ISC: IGMP Snooping Control Register (offset: 0x0018)
 	reg_offset = 0x2008;
 	reg_offset |= (port_num << 8);
@@ -2192,7 +2304,7 @@
 
 void igmp_enable(int argc, char *argv[])
 {
-	unsigned int reg_offset, value;
+	unsigned int reg_offset = 0, value = 0;
 	int port_num;
 
 	if (argc < 4) {
@@ -2204,7 +2316,6 @@
 		printf("wrong port range, should be within 0~6\n");
 		return;
 	}
-
 	//set ISC: IGMP Snooping Control Register (offset: 0x0018)
 	reg_offset = 0x2008;
 	reg_offset |= (port_num << 8);
@@ -2212,15 +2323,15 @@
 	reg_write(reg_offset, value);
 }
 
-void igmp_off()
+void igmp_off(int argc, char *argv[])
 {
-	unsigned int value;
+	unsigned int value = 0;
 	//set ISC: IGMP Snooping Control Register (offset: 0x0018)
 	reg_read(REG_ISC_ADDR, &value);
-	value &= ~(1 << 18); //disable
+	value &= ~(1 << 18);	//disable
 	reg_write(REG_ISC_ADDR, value);
 
-	/*restore wan port multicast leaky vlan function: default disabled*/
+	/*restore wan port multicast leaky vlan function: default disabled */
 	reg_read(0x2010, &value);
 	reg_write(0x2010, value & (~(1 << 3)));
 	reg_read(0x2410, &value);
@@ -2229,10 +2340,10 @@
 	printf("config igmpsnoop off.\n");
 }
 
-int switch_reset(int argc, char *argv[])
+void switch_reset(int argc, char *argv[])
 {
 	if (chip_name == 0x7988)
-		return -1;
+		return;
 
 	unsigned int value = 0;
 	/*Software Register Reset  and Software System Reset */
@@ -2245,23 +2356,24 @@
 		printf("GPIO Mode (0x7c0c) select value =0x%x  \n", value);
 	}
 	printf("Switch Software Reset !!! \n");
-	return 0;
 }
 
-int phy_set_fc(int argc, char *argv[])
+void phy_set_fc(int argc, char *argv[])
 {
-	unsigned int port, pause_capable;
-	unsigned int phy_value;
+	unsigned int port = 0, pause_capable = 0;
+	unsigned int phy_value = 0;
 
 	port = atoi(argv[3]);
 	pause_capable = atoi(argv[4]);
 
-	/*Check the input parameters is right or not.*/
+	/*Check the input parameters is right or not. */
 	if (port > MAX_PORT - 2 || pause_capable > 1) {
-		printf("Illegal parameter (port:0~4, full_duplex_pause_capable:0|1)\n");
-		return -1;
+		printf
+		    ("Illegal parameter (port:0~4, full_duplex_pause_capable:0|1)\n");
+		return;
 	}
 	printf("port=%d, full_duplex_pause_capable:%d\n", port, pause_capable);
+
 	mii_mgr_read(port, 4, &phy_value);
 	printf("read phy_value:0x%x\r\n", phy_value);
 	phy_value &= (~(0x1 << 10));
@@ -2272,35 +2384,36 @@
 	}
 	mii_mgr_write(port, 4, phy_value);
 	printf("write phy_value:0x%x\r\n", phy_value);
-	return 0;
-} /*end phy_set_fc*/
+	return;
+}				/*end phy_set_fc */
 
-int phy_set_an(int argc, char *argv[])
+void phy_set_an(int argc, char *argv[])
 {
-	unsigned int port, auto_negotiation_en;
-	unsigned int phy_value;
+	unsigned int port = 0, auto_negotiation_en = 0;
+	unsigned int phy_value = 0;
 
 	port = atoi(argv[3]);
 	auto_negotiation_en = atoi(argv[4]);
 
-	/*Check the input parameters is right or not.*/
+	/*Check the input parameters is right or not. */
 	if (port > MAX_PORT - 2 || auto_negotiation_en > 1) {
-		printf("Illegal parameter (port:0~4, auto_negotiation_en:0|1)\n");
-		return -1;
+		printf
+		    ("Illegal parameter (port:0~4, auto_negotiation_en:0|1)\n");
+		return;
 	}
 	printf("port=%d, auto_negotiation_en:%d\n", port, auto_negotiation_en);
+
 	mii_mgr_read(port, 0, &phy_value);
 	printf("read phy_value:0x%x\r\n", phy_value);
 	phy_value &= (~(1 << 12));
 	phy_value |= (auto_negotiation_en << 12);
 	mii_mgr_write(port, 0, phy_value);
 	printf("write phy_value:0x%x\r\n", phy_value);
-	return 0;
-} /*end phy_set_an*/
+}				/*end phy_set_an */
 
-int set_mac_pfc(int argc, char *argv[])
+void set_mac_pfc(int argc, char *argv[])
 {
-	unsigned int value;
+	unsigned int value = 0;
 	int port, enable = 0;
 
 	port = atoi(argv[3]);
@@ -2308,7 +2421,7 @@
 	printf("enable: %d\n", enable);
 	if (port < 0 || port > 6 || enable < 0 || enable > 1) {
 		printf("Illegal parameter (port:0~6, enable|diable:0|1) \n");
-		return -1;
+		return;
 	}
 	if (chip_name == 0x7531 || chip_name == 0x7988) {
 		reg_read(REG_PFC_CTRL_ADDR, &value);
@@ -2316,25 +2429,23 @@
 		value |= (enable << port);
 		printf("write reg: %x, value: %x\n", REG_PFC_CTRL_ADDR, value);
 		reg_write(REG_PFC_CTRL_ADDR, value);
-	}
-	else
+	} else
 		printf("\nCommand not support by this chip.\n");
-	return 0;
 }
 
-int global_set_mac_fc(int argc, char *argv[])
+void global_set_mac_fc(int argc, char *argv[])
 {
 	unsigned char enable = 0;
-	unsigned int value, reg;
+	unsigned int value = 0, reg = 0;
 
 	if (chip_name == 0x7530) {
 		enable = atoi(argv[3]);
 		printf("enable: %d\n", enable);
 
-		/*Check the input parameters is right or not.*/
+		/*Check the input parameters is right or not. */
 		if (enable > 1) {
 			printf(HELP_MACCTL_FC);
-			return -1;
+			return;
 		}
 		reg_write(0x7000, 0x3);
 		reg = REG_GFCCR0_ADDR;
@@ -2345,17 +2456,16 @@
 		reg_write(REG_GFCCR0_ADDR, value);
 	} else
 		printf("\r\nCommand not support by this chip.\n");
-	return 0;
-} /*end mac_set_fc*/
+}				/*end mac_set_fc */
 
-int qos_sch_select(int argc, char *argv[])
+void qos_sch_select(int argc, char *argv[])
 {
-	unsigned char port, queue;
+	unsigned char port = 0, queue = 0;
 	unsigned char type = 0;
-	unsigned int value, reg;
+	unsigned int value = 0, reg = 0;
 
 	if (argc < 7)
-		return -1;
+		return;
 
 	port = atoi(argv[3]);
 	queue = atoi(argv[4]);
@@ -2363,26 +2473,26 @@
 
 	if (port > 6 || queue > 7) {
 		printf("\n Illegal input parameters\n");
-		return -1;
+		return;
 	}
 
 	if ((type != 0 && type != 1 && type != 2)) {
 		printf(HELP_QOS_TYPE);
-		return -1;
+		return;
 	}
 
-	printf("\r\nswitch qos type: %d.\n",type);
+	printf("\r\nswitch qos type: %d.\n", type);
 
 	if (!strncmp(argv[5], "min", 4)) {
 
 		if (type == 0) {
-			/*min sharper-->round roubin, disable min sharper rate limit*/
+			/*min sharper-->round roubin, disable min sharper rate limit */
 			reg = GSW_MMSCR0_Q(queue) + 0x100 * port;
 			reg_read(reg, &value);
 			value = 0x0;
 			reg_write(reg, value);
 		} else if (type == 1) {
-			/*min sharper-->sp, disable min sharper rate limit*/
+			/*min sharper-->sp, disable min sharper rate limit */
 			reg = GSW_MMSCR0_Q(queue) + 0x100 * port;
 			reg_read(reg, &value);
 			value = 0x0;
@@ -2390,75 +2500,72 @@
 			reg_write(reg, value);
 		} else {
 			printf("min sharper only support: rr or sp\n");
-			return -1;
+			return;
 		}
 	} else if (!strncmp(argv[5], "max", 4)) {
 		if (type == 1) {
-			/*max sharper-->sp, disable max sharper rate limit*/
+			/*max sharper-->sp, disable max sharper rate limit */
 			reg = GSW_MMSCR1_Q(queue) + 0x100 * port;
 			reg_read(reg, &value);
 			value = 0x0;
 			value |= (1 << 31);
 			reg_write(reg, value);
 		} else if (type == 2) {
-			/*max sharper-->wfq, disable max sharper rate limit*/
+			/*max sharper-->wfq, disable max sharper rate limit */
 			reg = GSW_MMSCR1_Q(queue) + 0x100 * port;
 			reg_read(reg, &value);
 			value = 0x0;
 			reg_write(reg, value);
 		} else {
 			printf("max sharper only support: wfq or sp\n");
-			return -1;
+			return;
 		}
 	} else {
-		printf("\r\nIllegal sharper:%s\n",argv[5]);
-		return -1;
+		printf("\r\nIllegal sharper:%s\n", argv[5]);
+		return;
 	}
-	printf("reg:0x%x--value:0x%x\n",reg,value);
-
-	return 0;
+	printf("reg:0x%x--value:0x%x\n", reg, value);
 }
 
 void get_upw(unsigned int *value, unsigned char base)
 {
 	*value &= (~((0x7 << 0) | (0x7 << 4) | (0x7 << 8) | (0x7 << 12) |
 		     (0x7 << 16) | (0x7 << 20)));
-	switch (base)
-	{
-		case 0: /* port-based 0x2x40[18:16] */
-			*value |= ((0x2 << 0) | (0x2 << 4) | (0x2 << 8) |
-				(0x2 << 12) | (0x7 << 16) | (0x2 << 20));
-			break;
-		case 1: /* tagged-based 0x2x40[10:8] */
-			*value |= ((0x2 << 0) | (0x2 << 4) | (0x7 << 8) |
-				(0x2 << 12) | (0x2 << 16) | (0x2 << 20));
-			break;
-		case 2: /* DSCP-based 0x2x40[14:12] */
-			*value |= ((0x2 << 0) | (0x2 << 4) | (0x2 << 8) |
-				(0x7 << 12) | (0x2 << 16) | (0x2 << 20));
-			break;
-		case 3: /* acl-based 0x2x40[2:0] */
-			*value |= ((0x7 << 0) | (0x2 << 4) | (0x2 << 8) |
-				(0x2 << 12) | (0x2 << 16) | (0x2 << 20));
-			break;
-		case 4: /* arl-based 0x2x40[22:20] */
-			*value |= ((0x2 << 0) | (0x2 << 4) | (0x2 << 8) |
-				(0x2 << 12) | (0x2 << 16) | (0x7 << 20));
-			break;
-		case 5: /* stag-based 0x2x40[6:4] */
-			*value |= ((0x2 << 0) | (0x7 << 4) | (0x2 << 8) |
-				(0x2 << 12) | (0x2 << 16) | (0x2 << 20));
-			break;
-		default:
-			break;
+	switch (base) {
+	case 0:		/* port-based 0x2x40[18:16] */
+		*value |= ((0x2 << 0) | (0x2 << 4) | (0x2 << 8) |
+			   (0x2 << 12) | (0x7 << 16) | (0x2 << 20));
+		break;
+	case 1:		/* tagged-based 0x2x40[10:8] */
+		*value |= ((0x2 << 0) | (0x2 << 4) | (0x7 << 8) |
+			   (0x2 << 12) | (0x2 << 16) | (0x2 << 20));
+		break;
+	case 2:		/* DSCP-based 0x2x40[14:12] */
+		*value |= ((0x2 << 0) | (0x2 << 4) | (0x2 << 8) |
+			   (0x7 << 12) | (0x2 << 16) | (0x2 << 20));
+		break;
+	case 3:		/* acl-based 0x2x40[2:0] */
+		*value |= ((0x7 << 0) | (0x2 << 4) | (0x2 << 8) |
+			   (0x2 << 12) | (0x2 << 16) | (0x2 << 20));
+		break;
+	case 4:		/* arl-based 0x2x40[22:20] */
+		*value |= ((0x2 << 0) | (0x2 << 4) | (0x2 << 8) |
+			   (0x2 << 12) | (0x2 << 16) | (0x7 << 20));
+		break;
+	case 5:		/* stag-based 0x2x40[6:4] */
+		*value |= ((0x2 << 0) | (0x7 << 4) | (0x2 << 8) |
+			   (0x2 << 12) | (0x2 << 16) | (0x2 << 20));
+		break;
+	default:
+		break;
 	}
 }
 
 void qos_set_base(int argc, char *argv[])
 {
 	unsigned char base = 0;
-	unsigned char port;
-	unsigned int value;
+	unsigned char port = 0;
+	unsigned int value = 0;
 
 	if (argc < 5)
 		return;
@@ -2472,13 +2579,12 @@
 	}
 
 	if (port > 6) {
-		printf("Illegal port index:%d\n",port);
+		printf("Illegal port index:%d\n", port);
 		return;
 	}
 
 	printf("\r\nswitch qos base : %d. (port-based:0, tag-based:1,\
-		dscp-based:2, acl-based:3, arl-based:4, stag-based:5)\n",
-	       base);
+		dscp-based:2, acl-based:3, arl-based:4, stag-based:5)\n", base);
 	if (chip_name == 0x7530) {
 
 		reg_read(0x44, &value);
@@ -2491,7 +2597,7 @@
 		reg_read(GSW_UPW(port), &value);
 		get_upw(&value, base);
 		reg_write(GSW_UPW(port), value);
-		printf("reg:0x%x, value: 0x%x\n",GSW_UPW(port),value);
+		printf("reg:0x%x, value: 0x%x\n", GSW_UPW(port), value);
 
 	} else {
 		printf("unknown switch device");
@@ -2501,9 +2607,9 @@
 
 void qos_wfq_set_weight(int argc, char *argv[])
 {
-	int port, weight[8], i;
-	unsigned char queue;
-	unsigned int reg, value;
+	int port = 0, weight[8], i = 0;
+	unsigned char queue = 0;
+	unsigned int reg = 0, value = 0;
 
 	port = atoi(argv[3]);
 
@@ -2524,14 +2630,12 @@
 		}
 	}
 	printf("port: %x, q0: %x, q1: %x, q2: %x, q3: %x, \
-		q4: %x, q5: %x, q6: %x, q7: %x\n",
-	       port, weight[0], weight[1], weight[2], weight[3], weight[4],
-	       weight[5], weight[6], weight[7]);
+		q4: %x, q5: %x, q6: %x, q7: %x\n", port, weight[0], weight[1], weight[2], weight[3], weight[4], weight[5], weight[6], weight[7]);
 
 	for (queue = 0; queue < 8; queue++) {
 		reg = GSW_MMSCR1_Q(queue) + 0x100 * port;
 		reg_read(reg, &value);
-		value &= (~(0xf << 24)); //bit24~27
+		value &= (~(0xf << 24));	//bit24~27
 		value |= (((weight[queue] - 1) & 0xf) << 24);
 		printf("reg: %x, value: %x\n", reg, value);
 		reg_write(reg, value);
@@ -2540,8 +2644,8 @@
 
 void qos_set_portpri(int argc, char *argv[])
 {
-	unsigned char port, prio;
-	unsigned int value;
+	unsigned char port = 0, prio = 0;
+	unsigned int value = 0;
 
 	port = atoi(argv[3]);
 	prio = atoi(argv[4]);
@@ -2560,8 +2664,8 @@
 
 void qos_set_dscppri(int argc, char *argv[])
 {
-	unsigned char prio, dscp, pim_n, pim_offset;
-	unsigned int reg, value;
+	unsigned char prio = 0, dscp = 0, pim_n = 0, pim_offset = 0;
+	unsigned int value = 0, reg = 0;
 
 	dscp = atoi(argv[3]);
 	prio = atoi(argv[4]);
@@ -2583,8 +2687,8 @@
 
 void qos_pri_mapping_queue(int argc, char *argv[])
 {
-	unsigned char prio, queue, pem_n, port;
-	unsigned int reg, value;
+	unsigned char prio = 0, queue = 0, pem_n = 0, port = 0;
+	unsigned int value = 0, reg = 0;
 
 	if (argc < 6)
 		return;
@@ -2597,6 +2701,7 @@
 		printf(HELP_QOS_PRIO_QMAP);
 		return;
 	}
+
 	if (chip_name == 0x7530) {
 		pem_n = prio / 2;
 		reg = pem_n * 0x4 + 0x48;
@@ -2614,34 +2719,33 @@
 		pem_n = prio / 2;
 		reg = GSW_PEM(pem_n) + 0x100 * port;
 		reg_read(reg, &value);
-		if (prio % 2) { // 1 1
+		if (prio % 2) {	// 1 1
 			value &= (~(0x7 << 25));
 			value |= ((queue & 0x7) << 25);
-		} else { // 0 0
+		} else {	// 0 0
 			value &= (~(0x7 << 9));
 			value |= ((queue & 0x7) << 9);
 		}
 		reg_write(reg, value);
 		printf("write reg: %x, value: %x\n", reg, value);
-	}
-	else {
+	} else {
 		printf("unknown switch device");
 		return;
 	}
 }
 
 static int macMT753xVlanSetVid(unsigned char index, unsigned char active,
-			       unsigned short vid, unsigned char portMap, unsigned char tagPortMap,
-			       unsigned char ivl_en, unsigned char fid, unsigned short stag)
+			       unsigned short vid, unsigned char portMap,
+			       unsigned char tagPortMap, unsigned char ivl_en,
+			       unsigned char fid, unsigned short stag)
 {
 	unsigned int value = 0;
 	unsigned int value2 = 0;
-	unsigned int reg;
-	int i;
+	unsigned int reg = 0;
+	int i = 0;
 
 	printf("index: %x, active: %x, vid: %x, portMap: %x, \
-		tagPortMap: %x, ivl_en: %x, fid: %x, stag: %x\n",
-	       index, active, vid, portMap, tagPortMap, ivl_en, fid, stag);
+		tagPortMap: %x, ivl_en: %x, fid: %x, stag: %x\n", index, active, vid, portMap, tagPortMap, ivl_en, fid, stag);
 
 	value = (portMap << 16);
 	value |= (stag << 4);
@@ -2656,22 +2760,22 @@
 	}
 
 	if (value2)
-		value |= (1 << 28); // eg_tag
+		value |= (1 << 28);	// eg_tag
 
-	reg = 0x98; // VAWD2
+	reg = 0x98;		// VAWD2
 	reg_write(reg, value2);
 
-	reg = 0x94; // VAWD1
+	reg = 0x94;		// VAWD1
 	reg_write(reg, value);
 
-	reg = 0x90; // VTCR
+	reg = 0x90;		// VTCR
 	value = (0x80001000 + vid);
 	reg_write(reg, value);
 
-	reg = 0x90; // VTCR
+	reg = 0x90;		// VTCR
 	while (1) {
 		reg_read(reg, &value);
-		if ((value & 0x80000000) == 0) //table busy
+		if ((value & 0x80000000) == 0)	//table busy
 			break;
 	}
 
@@ -2685,45 +2789,14 @@
 	       index, active, vid, portMap, tagPortMap);
 	return 0;
 
-} /*end macMT753xVlanSetVid*/
-/*
-static int macMT753xVlanGetVtbl(unsigned short index)
-{
-	unsigned int reg, value, vawd1, vawd2;
-
-	reg = 0x90; // VTCR
-	value = (0x80000000 + index);
-
-	reg_write(reg, value);
-
-	reg = 0x90; // VTCR
-	while (1) {
-		reg_read(reg, &value);
-		if ((value & 0x80000000) == 0) //table busy
-			break;
-	}
-
-	reg = 0x94; // VAWD1
-	reg_read(reg, &vawd1);
-
-	reg = 0x98; // VAWD2
-	reg_read(reg, &vawd2);
-
-	if (vawd1 & 0x1) {
-		fprintf(stderr, "%d.%s vid:%d fid:%d portMap:0x%x \
-				tagMap:0x%x stag:0x%x ivl_en:0x%x\r\n",
-			index, (vawd1 & 0x1) ? "on" : "off", index, ((vawd1 & 0xe) >> 1),
-			(vawd1 & 0xff0000) >> 16, vawd2, (vawd1 & 0xfff0) >> 0x4, (vawd1 >> 30) & 0x1);
-	}
-	return 0;
-} */ /*end macMT753xVlanGetVtbl*/
+}				/*end macMT753xVlanSetVid */
 
 static int macMT753xVlanSetPvid(unsigned char port, unsigned short pvid)
 {
-	unsigned int value;
-	unsigned int reg;
+	unsigned int value = 0;
+	unsigned int reg = 0;
 
-	/*Parameters is error*/
+	/*Parameters is error */
 	if (port > 6)
 		return -1;
 
@@ -2742,38 +2815,6 @@
 	printf("SetPVID: port:%d pvid:%d\r\n", port, pvid);
 	return 0;
 }
-/*
-static int macMT753xVlanGetPvid(unsigned char port)
-{
-	unsigned int value;
-	unsigned int reg;
-
-	if (port > 6)
-		return -1;
-	reg = 0x2014 + (port * 0x100);
-	reg_read(reg, &value);
-	return (value & 0xfff);
-} */
-/*
-static int macMT753xVlanDisp(void)
-{
-	unsigned int i = 0;
-	unsigned int reg, value;
-
-	reg = 0x2604;
-	reg_read(reg, &value);
-	value &= 0x30000000;
-
-	fprintf(stderr, "VLAN function is %s\n", value ? ETHCMD_ENABLE : ETHCMD_DISABLE);
-	fprintf(stderr, "PVID e0:%02d e1:%02d e2:%02d e3:%02d e4:%02d e5:%02d e6:%02d\n",
-		macMT753xVlanGetPvid(0), macMT753xVlanGetPvid(1), macMT753xVlanGetPvid(2),
-		macMT753xVlanGetPvid(3), macMT753xVlanGetPvid(4), macMT753xVlanGetPvid(5), macMT753xVlanGetPvid(6));
-
-	for (i = 0; i < MAX_VID_VALUE; i++)
-		macMT753xVlanGetVtbl(i);
-
-	return 0;
-}*/ /*end macMT753xVlanDisp*/
 
 void doVlanSetPvid(int argc, char *argv[])
 {
@@ -2782,7 +2823,7 @@
 
 	port = atoi(argv[3]);
 	pvid = atoi(argv[4]);
-	/*Check the input parameters is right or not.*/
+	/*Check the input parameters is right or not. */
 	if ((port >= SWITCH_MAX_PORT) || (pvid > MAX_VID_VALUE)) {
 		printf(HELP_VLAN_PVID);
 		return;
@@ -2792,7 +2833,7 @@
 
 	printf("port:%d pvid:%d,vlancap: max_port:%d maxvid:%d\r\n",
 	       port, pvid, SWITCH_MAX_PORT, MAX_VID_VALUE);
-} /*end doVlanSetPvid*/
+}				/*end doVlanSetPvid */
 
 void doVlanSetVid(int argc, char *argv[])
 {
@@ -2810,13 +2851,13 @@
 	active = atoi(argv[4]);
 	vid = atoi(argv[5]);
 
-	/*Check the input parameters is right or not.*/
+	/*Check the input parameters is right or not. */
 	if ((index >= MAX_VLAN_RULE) || (vid >= 4096) || (active > ACTIVED)) {
 		printf(HELP_VLAN_VID);
 		return;
 	}
 
-	/*CPU Port is always the membership*/
+	/*CPU Port is always the membership */
 	portMap = atoi(argv[6]);
 	tagPortMap = atoi(argv[7]);
 
@@ -2832,21 +2873,21 @@
 	macMT753xVlanSetVid(index, active, vid, portMap, tagPortMap,
 			    ivl_en, fid, stag);
 	printf("index:%d active:%d vid:%d\r\n", index, active, vid);
-} /*end doVlanSetVid*/
+}				/*end doVlanSetVid */
 
 void doVlanSetAccFrm(int argc, char *argv[])
 {
 	unsigned char port = 0;
 	unsigned char type = 0;
-	unsigned int value;
-	unsigned int reg;
+	unsigned int value = 0;
+	unsigned int reg = 0;
 
 	port = atoi(argv[3]);
 	type = atoi(argv[4]);
 
 	printf("port: %d, type: %d\n", port, type);
 
-	/*Check the input parameters is right or not.*/
+	/*Check the input parameters is right or not. */
 	if ((port > SWITCH_MAX_PORT) || (type > REG_PVC_ACC_FRM_RELMASK)) {
 		printf(HELP_VLAN_ACC_FRM);
 		return;
@@ -2859,21 +2900,21 @@
 
 	printf("write reg: %x, value: %x\n", reg, value);
 	reg_write(reg, value);
-} /*end doVlanSetAccFrm*/
+}				/*end doVlanSetAccFrm */
 
 void doVlanSetPortAttr(int argc, char *argv[])
 {
 	unsigned char port = 0;
 	unsigned char attr = 0;
-	unsigned int value;
-	unsigned int reg;
+	unsigned int value = 0;
+	unsigned int reg = 0;
 
 	port = atoi(argv[3]);
 	attr = atoi(argv[4]);
 
 	printf("port: %x, attr: %x\n", port, attr);
 
-	/*Check the input parameters is right or not.*/
+	/*Check the input parameters is right or not. */
 	if (port > SWITCH_MAX_PORT || attr > 3) {
 		printf(HELP_VLAN_PORT_ATTR);
 		return;
@@ -2892,13 +2933,14 @@
 {
 	unsigned char port = 0;
 	unsigned char mode = 0;
-	unsigned int value;
-	unsigned int reg;
+	unsigned int value = 0;
+	unsigned int reg = 0;
+
 	port = atoi(argv[3]);
 	mode = atoi(argv[4]);
 	printf("port: %x, mode: %x\n", port, mode);
 
-	/*Check the input parameters is right or not.*/
+	/*Check the input parameters is right or not. */
 	if (port > SWITCH_MAX_PORT || mode > 3) {
 		printf(HELP_VLAN_PORT_MODE);
 		return;
@@ -2916,15 +2958,15 @@
 {
 	unsigned char port = 0;
 	unsigned char eg_tag = 0;
-	unsigned int value;
-	unsigned int reg;
+	unsigned int value = 0;
+	unsigned int reg = 0;
 
 	port = atoi(argv[3]);
 	eg_tag = atoi(argv[4]);
 
 	printf("port: %d, eg_tag: %d\n", port, eg_tag);
 
-	/*Check the input parameters is right or not.*/
+	/*Check the input parameters is right or not. */
 	if ((port > SWITCH_MAX_PORT) || (eg_tag > REG_PCR_EG_TAG_RELMASK)) {
 		printf(HELP_VLAN_EGRESS_TAG_PCR);
 		return;
@@ -2938,21 +2980,21 @@
 	printf("write reg: %x, value: %x\n", reg, value);
 	reg_write(reg, value);
 
-} /*end doVlanSetEgressTagPCR*/
+}				/*end doVlanSetEgressTagPCR */
 
 void doVlanSetEgressTagPVC(int argc, char *argv[])
 {
 	unsigned char port = 0;
 	unsigned char eg_tag = 0;
-	unsigned int value;
-	unsigned int reg;
+	unsigned int value = 0;
+	unsigned int reg = 0;
 
 	port = atoi(argv[3]);
 	eg_tag = atoi(argv[4]);
 
 	printf("port: %d, eg_tag: %d\n", port, eg_tag);
 
-	/*Check the input parameters is right or not.*/
+	/*Check the input parameters is right or not. */
 	if ((port > SWITCH_MAX_PORT) || (eg_tag > REG_PVC_EG_TAG_RELMASK)) {
 		printf(HELP_VLAN_EGRESS_TAG_PVC);
 		return;
@@ -2965,19 +3007,19 @@
 
 	printf("write reg: %x, value: %x\n", reg, value);
 	reg_write(reg, value);
-} /*end doVlanSetEgressTagPVC*/
+}				/*end doVlanSetEgressTagPVC */
 
 void doArlAging(int argc, char *argv[])
 {
 	unsigned char aging_en = 0;
-	unsigned int time = 0, aging_cnt = 0, aging_unit = 0, value, reg;
-	;
+	unsigned int time = 0, aging_cnt = 0, aging_unit = 0, value = 0, reg =
+	    0;
 
 	aging_en = atoi(argv[3]);
 	time = atoi(argv[4]);
 	printf("aging_en: %x, aging time: %x\n", aging_en, time);
 
-	/*Check the input parameters is right or not.*/
+	/*Check the input parameters is right or not. */
 	if ((aging_en != 0 && aging_en != 1) || (time <= 0 || time > 65536)) {
 		printf(HELP_ARL_AGING);
 		return;
@@ -3006,16 +3048,16 @@
 
 void doMirrorEn(int argc, char *argv[])
 {
-	unsigned char mirror_en;
-	unsigned char mirror_port;
-	unsigned int value, reg;
+	unsigned char mirror_en = 0;
+	unsigned char mirror_port = 0;
+	unsigned int value = 0, reg = 0;
 
 	mirror_en = atoi(argv[3]);
 	mirror_port = atoi(argv[4]);
 
 	printf("mirror_en: %d, mirror_port: %d\n", mirror_en, mirror_port);
 
-	/*Check the input parameters is right or not.*/
+	/*Check the input parameters is right or not. */
 	if ((mirror_en > 1) || (mirror_port > REG_CFC_MIRROR_PORT_RELMASK)) {
 		printf(HELP_MIRROR_EN);
 		return;
@@ -3031,12 +3073,13 @@
 	printf("write reg: %x, value: %x\n", reg, value);
 	reg_write(reg, value);
 
-} /*end doMirrorEn*/
+}				/*end doMirrorEn */
 
 void doMirrorPortBased(int argc, char *argv[])
 {
-	unsigned char port, port_tx_mir, port_rx_mir, vlan_mis, acl_mir, igmp_mir;
-	unsigned int value, reg;
+	unsigned char port = 0, port_tx_mir = 0, port_rx_mir = 0, vlan_mis =
+	    0, acl_mir = 0, igmp_mir = 0;
+	unsigned int value = 0, reg = 0;
 
 	port = atoi(argv[3]);
 	port_tx_mir = atoi(argv[4]);
@@ -3045,20 +3088,28 @@
 	vlan_mis = atoi(argv[7]);
 	igmp_mir = atoi(argv[8]);
 
-	printf("port:%d, port_tx_mir:%d, port_rx_mir:%d, acl_mir:%d, vlan_mis:%d, igmp_mir:%d\n", port, port_tx_mir, port_rx_mir, acl_mir, vlan_mis, igmp_mir);
+	printf
+	    ("port:%d, port_tx_mir:%d, port_rx_mir:%d, acl_mir:%d, vlan_mis:%d, igmp_mir:%d\n",
+	     port, port_tx_mir, port_rx_mir, acl_mir, vlan_mis, igmp_mir);
 
-	/*Check the input parameters is right or not.*/
+	/*Check the input parameters is right or not. */
 	//if((port >= vlanCap->max_port_no) || (port_tx_mir > 1) || (port_rx_mir > 1) || (acl_mir > 1) || (vlan_mis > 1)){
-	if ((port >= 7) || (port_tx_mir > 1) || (port_rx_mir > 1) || (acl_mir > 1) || (vlan_mis > 1)) { // also allow CPU port (port6)
+	if ((port >= 7) || (port_tx_mir > 1) || (port_rx_mir > 1) || (acl_mir > 1) || (vlan_mis > 1)) {	// also allow CPU port (port6)
 		printf(HELP_MIRROR_PORTBASED);
 		return;
 	}
 
 	reg = REG_PCR_P0_ADDR + port * 0x100;
 	reg_read(reg, &value);
-	value &= ~(REG_PORT_TX_MIR_MASK | REG_PORT_RX_MIR_MASK | REG_PCR_ACL_MIR_MASK | REG_PCR_VLAN_MIS_MASK);
-	value |= (port_tx_mir << REG_PORT_TX_MIR_OFFT) + (port_rx_mir << REG_PORT_RX_MIR_OFFT);
-	value |= (acl_mir << REG_PCR_ACL_MIR_OFFT) + (vlan_mis << REG_PCR_VLAN_MIS_OFFT);
+	value &=
+	    ~(REG_PORT_TX_MIR_MASK | REG_PORT_RX_MIR_MASK | REG_PCR_ACL_MIR_MASK
+	      | REG_PCR_VLAN_MIS_MASK);
+	value |=
+	    (port_tx_mir << REG_PORT_TX_MIR_OFFT) +
+	    (port_rx_mir << REG_PORT_RX_MIR_OFFT);
+	value |=
+	    (acl_mir << REG_PCR_ACL_MIR_OFFT) +
+	    (vlan_mis << REG_PCR_VLAN_MIS_OFFT);
 
 	printf("write reg: %x, value: %x\n", reg, value);
 	reg_write(reg, value);
@@ -3071,15 +3122,15 @@
 	printf("write reg: %x, value: %x\n", reg, value);
 	reg_write(reg, value);
 
-} /*end doMirrorPortBased*/
+}				/*end doMirrorPortBased */
 
 void doStp(int argc, char *argv[])
 {
 	unsigned char port = 0;
 	unsigned char fid = 0;
 	unsigned char state = 0;
-	unsigned int value;
-	unsigned int reg;
+	unsigned int value = 0;
+	unsigned int reg = 0;
 
 	port = atoi(argv[2]);
 	fid = atoi(argv[3]);
@@ -3087,7 +3138,7 @@
 
 	printf("port: %d, fid: %d, state: %d\n", port, fid, state);
 
-	/*Check the input parameters is right or not.*/
+	/*Check the input parameters is right or not. */
 	if ((port > MAX_PORT + 1) || (fid > 7) || (state > 3)) {
 		printf(HELP_STP);
 		return;
@@ -3102,45 +3153,54 @@
 	reg_write(reg, value);
 }
 
-int ingress_rate_set(int on_off, unsigned int port, unsigned int bw)
+void _ingress_rate_set(int on_off, int port, int bw)
 {
-	unsigned int reg, value;
+	unsigned int reg = 0, value = 0;
 
 	reg = 0x1800 + (0x100 * port);
 	value = 0;
-	/*token-bucket*/
+	/*token-bucket */
 	if (on_off == 1) {
 		if (chip_name == 0x7530) {
 			if (bw > 1000000) {
-				printf("\n**Charge rate(%d) is larger than line rate(1000000kbps)**\n",bw);
-				return -1;
+				printf
+				    ("\n**Charge rate(%d) is larger than line rate(1000000kbps)**\n",
+				     bw);
+				return;
 			}
-			value = ((bw / 32) << 16) + (1 << 15) + (7 << 8) + (1 << 7) + 0x0f;
+			value =
+			    ((bw / 32) << 16) + (1 << 15) + (7 << 8) +
+			    (1 << 7) + 0x0f;
 		} else if (chip_name == 0x7531 || chip_name == 0x7988) {
 			if ((chip_name == 0x7531) && (bw > 2500000)) {
-				printf("\n**Charge rate(%d) is larger than line rate(2500000kbps)**\n",bw);
-				return -1;
+				printf
+				    ("\n**Charge rate(%d) is larger than line rate(2500000kbps)**\n",
+				     bw);
+				return;
 			}
 
 			if ((chip_name == 0x7988) && (bw > 4000000)) {
-				printf("\n**Charge rate(%d) is larger than line rate(4000000kbps)**\n",bw);
-				return -1;
+				printf
+				    ("\n**Charge rate(%d) is larger than line rate(4000000kbps)**\n",
+				     bw);
+				return;
 			}
 
-			if (bw/32 >= 65536) //supoort 2.5G case
-				value = ((bw / 32) << 16) + (1 << 15) + (1 << 14) + (1 << 12) + (7 << 8) + 0xf;
+			if (bw / 32 >= 65536)	//supoort 2.5G case
+				value =
+				    ((bw / 32) << 16) + (1 << 15) + (1 << 14) +
+				    (1 << 12) + (7 << 8) + 0xf;
 			else
-				value = ((bw / 32) << 16) + (1 << 15) + (1 << 14) + (7 << 8) + 0xf;
-		}
-		else
+				value =
+				    ((bw / 32) << 16) + (1 << 15) + (1 << 14) +
+				    (7 << 8) + 0xf;
+		} else
 			printf("unknow chip\n");
 	}
-
 #if leaky_bucket
 	reg_read(reg, &value);
 	value &= 0xffff0000;
-	if (on_off == 1)
-	{
+	if (on_off == 1) {
 		value |= on_off << 15;
 		//7530 same as 7531
 		if (bw < 100) {
@@ -3166,39 +3226,71 @@
 	reg_read(reg, &value);
 	value = 0x110104;
 	reg_write(reg, value);
-	return 0;
+
+	if (on_off)
+		printf("switch port=%d, bw=%d\n", port, bw);
+	else
+		printf("switch port=%d ingress rate limit off\n", port);
 }
 
-int egress_rate_set(int on_off, int port, int bw)
+void ingress_rate_set(int argc, char *argv[])
 {
-	unsigned int reg, value;
+	int on_off = 0, port = 0, bw = 0;
+
+	port = strtoul(argv[3], NULL, 0);
+	if (argv[2][1] == 'n') {
+		bw = strtoul(argv[4], NULL, 0);
+		on_off = 1;
+	} else if (argv[2][1] == 'f') {
+		if (argc != 4)
+			return;
+		on_off = 0;
+	}
+
+	_ingress_rate_set(on_off, port, bw);
+}
+
+void _egress_rate_set(int on_off, int port, int bw)
+{
+	unsigned int value = 0, reg = 0;
 
 	reg = 0x1040 + (0x100 * port);
 	value = 0;
-	/*token-bucket*/
+	/*token-bucket */
 	if (on_off == 1) {
 		if (chip_name == 0x7530) {
 			if (bw < 0 || bw > 1000000) {
-				printf("\n**Charge rate(%d) is larger than line rate(1000000kbps)**\n",bw);
-				return -1;
+				printf
+				    ("\n**Charge rate(%d) is larger than line rate(1000000kbps)**\n",
+				     bw);
+				return;
 			}
-			value = ((bw / 32) << 16) + (1 << 15) + (7 << 8) + (1 << 7) + 0xf;
+			value =
+			    ((bw / 32) << 16) + (1 << 15) + (7 << 8) +
+			    (1 << 7) + 0xf;
 		} else if (chip_name == 0x7531 || chip_name == 0x7988) {
 			if ((chip_name == 0x7531) && (bw < 0 || bw > 2500000)) {
-				printf("\n**Charge rate(%d) is larger than line rate(2500000kbps)**\n",bw);
-				return -1;
+				printf
+				    ("\n**Charge rate(%d) is larger than line rate(2500000kbps)**\n",
+				     bw);
+				return;
 			}
 			if ((chip_name == 0x7988) && (bw < 0 || bw > 4000000)) {
-				printf("\n**Charge rate(%d) is larger than line rate(4000000kbps)**\n",bw);
-				return -1;
+				printf
+				    ("\n**Charge rate(%d) is larger than line rate(4000000kbps)**\n",
+				     bw);
+				return;
 			}
 
-			if (bw/32 >= 65536)	//support 2.5G cases
-				value = ((bw / 32) << 16) + (1 << 15) + (1 << 14) + (1 << 12) + (7 << 8) + 0xf;
+			if (bw / 32 >= 65536)	//support 2.5G cases
+				value =
+				    ((bw / 32) << 16) + (1 << 15) + (1 << 14) +
+				    (1 << 12) + (7 << 8) + 0xf;
 			else
-				value = ((bw / 32) << 16) + (1 << 15) + (1 << 14) + (7 << 8) + 0xf;
-		}
-		else
+				value =
+				    ((bw / 32) << 16) + (1 << 15) + (1 << 14) +
+				    (7 << 8) + 0xf;
+		} else
 			printf("unknow chip\n");
 	}
 	reg_write(reg, value);
@@ -3207,7 +3299,28 @@
 	value &= 0x18;
 	reg_write(reg, value);
 
-	return 0;
+	if (on_off)
+		printf("switch port=%d, bw=%d\n", port, bw);
+	else
+		printf("switch port=%d egress rate limit off\n", port);
+}
+
+void egress_rate_set(int argc, char *argv[])
+{
+	unsigned int value = 0, reg = 0;
+	int on_off = 0, port = 0, bw = 0;
+
+	port = strtoul(argv[3], NULL, 0);
+	if (argv[2][1] == 'n') {
+		bw = strtoul(argv[4], NULL, 0);
+		on_off = 1;
+	} else if (argv[2][1] == 'f') {
+		if (argc != 4)
+			return;
+		on_off = 0;
+	}
+
+	_egress_rate_set(on_off, port, bw);
 }
 
 void rate_control(int argc, char *argv[])
@@ -3223,34 +3336,33 @@
 	if (port > 6)
 		return;
 
-	if (dir == 1) //ingress
-		ingress_rate_set(1, port, rate);
-	else if (dir == 0) //egress
-		egress_rate_set(1, port, rate);
+	if (dir == 1)		//ingress
+		_ingress_rate_set(1, port, rate);
+	else if (dir == 0)	//egress
+		_egress_rate_set(1, port, rate);
 	else
 		return;
 }
 
-int collision_pool_enable(int argc, char *argv[])
+void collision_pool_enable(int argc, char *argv[])
 {
 
-	unsigned char enable;
-	unsigned int value, reg;
+	unsigned char enable = 0;
+	unsigned int value = 0, reg = 0;
 
 	enable = atoi(argv[3]);
 
-
 	printf("collision pool enable: %d \n", enable);
 
-	/*Check the input parameters is right or not.*/
+	/*Check the input parameters is right or not. */
 	if (enable > 1) {
 		printf(HELP_COLLISION_POOL_EN);
-		return -1;
+		return;
 	}
 
 	if (chip_name == 0x7531 || chip_name == 0x7988) {
 		reg = REG_CPGC_ADDR;
-		if(enable == 1) {
+		if (enable == 1) {
 			/* active reset */
 			reg_read(reg, &value);
 			value &= (~REG_CPCG_COL_RST_N_MASK);
@@ -3276,7 +3388,7 @@
 
 			reg_read(reg, &value);
 			printf("write reg: %x, value: %x\n", reg, value);
-		}else {
+		} else {
 
 			/* disable collision pool */
 			reg_read(reg, &value);
@@ -3303,70 +3415,67 @@
 			printf("write reg: %x, value: %x\n", reg, value);
 
 		}
-	}else{
+	} else {
 		printf("\nCommand not support by this chip.\n");
-}
-
- return 0;
+	}
 }
 
-void collision_pool_mac_dump()
+void collision_pool_mac_dump(int argc, char *argv[])
 {
-	unsigned int value, reg;
+	unsigned int value = 0, reg = 0;
 
 	if (chip_name == 0x7531 || chip_name == 0x7988) {
 		reg = REG_CPGC_ADDR;
 		reg_read(reg, &value);
-		if(value & REG_CPCG_COL_EN_MASK)
+		if (value & REG_CPCG_COL_EN_MASK)
 			table_dump_internal(COLLISION_TABLE);
 		else
-			printf("\ncollision pool is disabled, please enable it before use this command.\n");
-	}else {
+			printf
+			    ("\ncollision pool is disabled, please enable it before use this command.\n");
+	} else {
 		printf("\nCommand not support by this chip.\n");
 	}
 }
 
-void collision_pool_dip_dump()
+void collision_pool_dip_dump(int argc, char *argv[])
 {
-	unsigned int value, reg;
+	unsigned int value = 0, reg = 0;
 
 	if (chip_name == 0x7531 || chip_name == 0x7988) {
 		reg = REG_CPGC_ADDR;
 		reg_read(reg, &value);
-		if(value & REG_CPCG_COL_EN_MASK)
+		if (value & REG_CPCG_COL_EN_MASK)
 			dip_dump_internal(COLLISION_TABLE);
 		else
-			printf("\ncollision pool is disabled, please enable it before use this command.\n");
-		}else {
+			printf
+			    ("\ncollision pool is disabled, please enable it before use this command.\n");
+	} else {
 		printf("\nCommand not support by this chip.\n");
 	}
-
-
 }
 
-void collision_pool_sip_dump()
+void collision_pool_sip_dump(int argc, char *argv[])
 {
-	unsigned int value, reg;
+	unsigned int value = 0, reg = 0;
 
-	if (chip_name == 0x7531 ||  chip_name == 0x7988) {
+	if (chip_name == 0x7531 || chip_name == 0x7988) {
 		reg = REG_CPGC_ADDR;
 		reg_read(reg, &value);
-		if(value & REG_CPCG_COL_EN_MASK)
+		if (value & REG_CPCG_COL_EN_MASK)
 			sip_dump_internal(COLLISION_TABLE);
 		else
-			printf("\ncollision pool is disabled, please enable it before use this command.\n");
-	}else {
+			printf
+			    ("\ncollision pool is disabled, please enable it before use this command.\n");
+	} else {
 		printf("\nCommand not support by this chip.\n");
 	}
-
-
 }
 
 void pfc_get_rx_counter(int argc, char *argv[])
 {
-	int port;
-	unsigned int value, reg;
-	unsigned int user_pri;
+	int port = 0;
+	unsigned int value = 0, reg = 0;
+	unsigned int user_pri = 0;
 
 	port = strtoul(argv[3], NULL, 0);
 	if (port < 0 || 6 < port) {
@@ -3374,33 +3483,41 @@
 		return;
 	}
 
-	if (chip_name == 0x7531 ||  chip_name == 0x7988) {
-		reg= PFC_RX_COUNTER_L(port);
+	if (chip_name == 0x7531 || chip_name == 0x7988) {
+		reg = PFC_RX_COUNTER_L(port);
 		reg_read(reg, &value);
 		user_pri = value & 0xff;
-		printf("\n port %d rx pfc (up=0)pause on counter is %d.\n", port,user_pri);
+		printf("\n port %d rx pfc (up=0)pause on counter is %d.\n",
+		       port, user_pri);
 		user_pri = (value & 0xff00) >> 8;
-		printf("\n port %d rx pfc (up=1)pause on counter is %d.\n", port,user_pri);
+		printf("\n port %d rx pfc (up=1)pause on counter is %d.\n",
+		       port, user_pri);
 		user_pri = (value & 0xff0000) >> 16;
-		printf("\n port %d rx pfc (up=2)pause on counter is %d.\n", port,user_pri);
+		printf("\n port %d rx pfc (up=2)pause on counter is %d.\n",
+		       port, user_pri);
 		user_pri = (value & 0xff000000) >> 24;
-		printf("\n port %d rx pfc (up=3)pause on counter is %d.\n", port,user_pri);
+		printf("\n port %d rx pfc (up=3)pause on counter is %d.\n",
+		       port, user_pri);
 
-		reg= PFC_RX_COUNTER_H(port);
+		reg = PFC_RX_COUNTER_H(port);
 		reg_read(reg, &value);
 		user_pri = value & 0xff;
-		printf("\n port %d rx pfc (up=4)pause on counter is %d.\n", port,user_pri);
+		printf("\n port %d rx pfc (up=4)pause on counter is %d.\n",
+		       port, user_pri);
 		user_pri = (value & 0xff00) >> 8;
-		printf("\n port %d rx pfc (up=5)pause on counter is %d.\n", port,user_pri);
+		printf("\n port %d rx pfc (up=5)pause on counter is %d.\n",
+		       port, user_pri);
 		user_pri = (value & 0xff0000) >> 16;
-		printf("\n port %d rx pfc (up=6)pause on counter is %d.\n", port,user_pri);
+		printf("\n port %d rx pfc (up=6)pause on counter is %d.\n",
+		       port, user_pri);
 		user_pri = (value & 0xff000000) >> 24;
-		printf("\n port %d rx pfc (up=7)pause on counter is %d.\n", port,user_pri);
+		printf("\n port %d rx pfc (up=7)pause on counter is %d.\n",
+		       port, user_pri);
 
 		/* for rx counter could be updated successfully */
 		reg_read(PMSR_P(port), &value);
 		reg_read(PMSR_P(port), &value);
-	}else {
+	} else {
 		printf("\nCommand not support by this chip.\n");
 	}
 
@@ -3408,9 +3525,9 @@
 
 void pfc_get_tx_counter(int argc, char *argv[])
 {
-	int port;
-	unsigned int value, reg;
-	unsigned int user_pri;
+	int port = 0;
+	unsigned int value = 0, reg = 0;
+	unsigned int user_pri = 0;
 
 	port = strtoul(argv[3], NULL, 0);
 	if (port < 0 || 6 < port) {
@@ -3419,83 +3536,99 @@
 	}
 
 	if (chip_name == 0x7531 || chip_name == 0x7988) {
-		reg= PFC_TX_COUNTER_L(port);
+		reg = PFC_TX_COUNTER_L(port);
 		reg_read(reg, &value);
 		user_pri = value & 0xff;
-		printf("\n port %d tx pfc (up=0)pause on counter is %d.\n", port,user_pri);
+		printf("\n port %d tx pfc (up=0)pause on counter is %d.\n",
+		       port, user_pri);
 		user_pri = (value & 0xff00) >> 8;
-		printf("\n port %d tx pfc (up=1)pause on counter is %d.\n", port,user_pri);
+		printf("\n port %d tx pfc (up=1)pause on counter is %d.\n",
+		       port, user_pri);
 		user_pri = (value & 0xff0000) >> 16;
-		printf("\n port %d tx pfc (up=2)pause on counter is %d.\n", port,user_pri);
+		printf("\n port %d tx pfc (up=2)pause on counter is %d.\n",
+		       port, user_pri);
 		user_pri = (value & 0xff000000) >> 24;
-		printf("\n port %d tx pfc (up=3)pause on counter is %d.\n", port,user_pri);
+		printf("\n port %d tx pfc (up=3)pause on counter is %d.\n",
+		       port, user_pri);
 
-		reg= PFC_TX_COUNTER_H(port);
+		reg = PFC_TX_COUNTER_H(port);
 		reg_read(reg, &value);
 		user_pri = value & 0xff;
-		printf("\n port %d tx pfc (up=4)pause on counter is %d.\n", port,user_pri);
+		printf("\n port %d tx pfc (up=4)pause on counter is %d.\n",
+		       port, user_pri);
 		user_pri = (value & 0xff00) >> 8;
-		printf("\n port %d tx pfc (up=5)pause on counter is %d.\n", port,user_pri);
+		printf("\n port %d tx pfc (up=5)pause on counter is %d.\n",
+		       port, user_pri);
 		user_pri = (value & 0xff0000) >> 16;
-		printf("\n port %d tx pfc (up=6)pause on counter is %d.\n", port,user_pri);
+		printf("\n port %d tx pfc (up=6)pause on counter is %d.\n",
+		       port, user_pri);
 		user_pri = (value & 0xff000000) >> 24;
-		printf("\n port %d tx pfc (up=7)pause on counter is %d.\n", port,user_pri);
+		printf("\n port %d tx pfc (up=7)pause on counter is %d.\n",
+		       port, user_pri);
 
 		/* for tx counter could be updated successfully */
 		reg_read(PMSR_P(port), &value);
 		reg_read(PMSR_P(port), &value);
-	}else {
-		 printf("\nCommand not support by this chip.\n");
+	} else {
+		printf("\nCommand not support by this chip.\n");
 	}
 }
 
-void read_output_queue_counters()
+void read_output_queue_counters(int argc, char *argv[])
 {
-	unsigned int port=0;
-	unsigned int value, output_queue;
-	unsigned int base=0x220;
+	unsigned int port = 0;
+	unsigned int value = 0, output_queue = 0;
+	unsigned int base = 0x220;
 
 	for (port = 0; port < 7; port++) {
-		reg_write(0x7038, base + (port *4));
+		reg_write(0x7038, base + (port * 4));
 		reg_read(0x7034, &value);
 		output_queue = value & 0xff;
-		printf("\n port %d  output queue 0 counter is %d.\n", port,output_queue);
+		printf("\n port %d  output queue 0 counter is %d.\n", port,
+		       output_queue);
 		output_queue = (value & 0xff00) >> 8;
-		printf("\n port %d  output queue 1 counter is %d.\n", port,output_queue);
+		printf("\n port %d  output queue 1 counter is %d.\n", port,
+		       output_queue);
 
-		reg_write(0x7038, base + (port *4) + 1);
+		reg_write(0x7038, base + (port * 4) + 1);
 		reg_read(0x7034, &value);
 		output_queue = value & 0xff;
-		printf("\n port %d  output queue 2 counter is %d.\n", port,output_queue);
+		printf("\n port %d  output queue 2 counter is %d.\n", port,
+		       output_queue);
 		output_queue = (value & 0xff00) >> 8;
-		printf("\n port %d  output queue 3 counter is %d.\n", port,output_queue);
+		printf("\n port %d  output queue 3 counter is %d.\n", port,
+		       output_queue);
 
-		reg_write(0x7038, base + (port *4) + 2);
+		reg_write(0x7038, base + (port * 4) + 2);
 		reg_read(0x7034, &value);
 		output_queue = value & 0xff;
-		printf("\n port %d  output queue 4 counter is %d.\n", port,output_queue);
+		printf("\n port %d  output queue 4 counter is %d.\n", port,
+		       output_queue);
 		output_queue = (value & 0xff00) >> 8;
-		printf("\n port %d  output queue 5 counter is %d.\n", port,output_queue);
+		printf("\n port %d  output queue 5 counter is %d.\n", port,
+		       output_queue);
 
-		reg_write(0x7038, base + (port *4) + 3);
+		reg_write(0x7038, base + (port * 4) + 3);
 		reg_read(0x7034, &value);
 		output_queue = value & 0xff;
-		printf("\n port %d  output queue 6 counter is %d.\n", port,output_queue);
+		printf("\n port %d  output queue 6 counter is %d.\n", port,
+		       output_queue);
 		output_queue = (value & 0xff00) >> 8;
-		printf("\n port %d  output queue 7 counter is %d.\n", port,output_queue);
+		printf("\n port %d  output queue 7 counter is %d.\n", port,
+		       output_queue);
 	}
 }
 
-void read_free_page_counters()
+void read_free_page_counters(int argc, char *argv[])
 {
-	unsigned int value;
-	unsigned int free_page,free_page_last_read;
-	unsigned int fc_free_blk_lothd,fc_free_blk_hithd;
-	unsigned int fc_port_blk_thd,fc_port_blk_hi_thd;
-	unsigned int queue[8]={0};
+	unsigned int value = 0;
+	unsigned int free_page = 0, free_page_last_read = 0;
+	unsigned int fc_free_blk_lothd = 0, fc_free_blk_hithd = 0;
+	unsigned int fc_port_blk_thd = 0, fc_port_blk_hi_thd = 0;
+	unsigned int queue[8] = { 0 };
 
 	if (chip_name == 0x7531 || chip_name == 0x7988) {
-		/* get system free page link counter*/
+		/* get system free page link counter */
 		reg_read(0x1fc0, &value);
 		free_page = value & 0xFFF;
 		free_page_last_read = (value & 0xFFF0000) >> 16;
@@ -3512,17 +3645,17 @@
 
 		/* get queue flow control waterwark */
 		reg_read(0x1fe8, &value);
-		queue[0]= value & 0x3F;
-		queue[1]= (value & 0x3F00) >> 8;
-		queue[2]= (value & 0x3F0000) >> 16;
-		queue[3]= (value & 0x3F000000) >> 24;
+		queue[0] = value & 0x3F;
+		queue[1] = (value & 0x3F00) >> 8;
+		queue[2] = (value & 0x3F0000) >> 16;
+		queue[3] = (value & 0x3F000000) >> 24;
 		reg_read(0x1fec, &value);
-		queue[4]= value & 0x3F;
-		queue[5]= (value & 0x3F00) >> 8;
-		queue[6]= (value & 0x3F0000) >> 16;
-		queue[7]= (value & 0x3F000000) >> 24;
+		queue[4] = value & 0x3F;
+		queue[5] = (value & 0x3F00) >> 8;
+		queue[6] = (value & 0x3F0000) >> 16;
+		queue[7] = (value & 0x3F000000) >> 24;
 	} else {
-		/* get system free page link counter*/
+		/* get system free page link counter */
 		reg_read(0x1fc0, &value);
 		free_page = value & 0x3FF;
 		free_page_last_read = (value & 0x3FF0000) >> 16;
@@ -3540,50 +3673,61 @@
 
 		/* get queue flow control waterwark */
 		reg_read(0x1fe4, &value);
-		queue[0]= value & 0xF;
-		queue[1]= (value & 0xF0) >> 4;
-		queue[2]= (value & 0xF00) >> 8;
-		queue[3]= (value & 0xF000) >>12;
-		queue[4]= (value & 0xF0000) >>16;
-		queue[5]= (value & 0xF00000) >> 20;
-		queue[6]= (value & 0xF000000) >> 24;
-		queue[7]= (value & 0xF0000000) >> 28;
+		queue[0] = value & 0xF;
+		queue[1] = (value & 0xF0) >> 4;
+		queue[2] = (value & 0xF00) >> 8;
+		queue[3] = (value & 0xF000) >> 12;
+		queue[4] = (value & 0xF0000) >> 16;
+		queue[5] = (value & 0xF00000) >> 20;
+		queue[6] = (value & 0xF000000) >> 24;
+		queue[7] = (value & 0xF0000000) >> 28;
 	}
 
-	printf("<===Free Page=======Current=======Last Read access=====> \n ");
-	printf("	                                                 \n ");
-	printf(" page counter      %u                %u               \n ",free_page,free_page_last_read);
-	printf("                                                        \n ");
-	printf("========================================================= \n ");
-	printf("<===Type=======High threshold======Low threshold=========\n ");
-	printf("                                                        \n ");
-	printf("  system:         %u                 %u               \n", fc_free_blk_hithd*2,  fc_free_blk_lothd*2);
-	printf("    port:         %u                 %u               \n", fc_port_blk_hi_thd*2, fc_port_blk_thd*2);
-	printf(" queue 0:         %u                 NA                \n", queue[0]);
-	printf(" queue 1:         %u                 NA                \n", queue[1]);
-	printf(" queue 2:         %u                 NA                 \n", queue[2]);
-	printf(" queue 3:         %u                 NA                \n", queue[3]);
-	printf(" queue 4:         %u                 NA                \n", queue[4]);
-	printf(" queue 5:         %u                 NA                \n", queue[5]);
-	printf(" queue 6:         %u                 NA                \n", queue[6]);
-	printf(" queue 7:         %u                 NA                \n", queue[7]);
-	printf("=========================================================\n ");
+	printf("<===Free Page=======Current=======Last Read access=====>\n");
+	printf("\n");
+	printf(" page counter      %u                %u\n ",
+	       free_page, free_page_last_read);
+	printf("\n ");
+	printf("=========================================================\n");
+	printf("<===Type=======High threshold======Low threshold=========\n");
+	printf("\n ");
+	printf("  system:         %u                 %u\n",
+	       fc_free_blk_hithd * 2, fc_free_blk_lothd * 2);
+	printf("    port:         %u                 %u\n",
+	       fc_port_blk_hi_thd * 2, fc_port_blk_thd * 2);
+	printf(" queue 0:         %u                 NA\n",
+	       queue[0]);
+	printf(" queue 1:         %u                 NA\n",
+	       queue[1]);
+	printf(" queue 2:         %u                 NA\n",
+	       queue[2]);
+	printf(" queue 3:         %u                 NA\n",
+	       queue[3]);
+	printf(" queue 4:         %u                 NA\n",
+	       queue[4]);
+	printf(" queue 5:         %u                 NA\n",
+	       queue[5]);
+	printf(" queue 6:         %u                 NA\n",
+	       queue[6]);
+	printf(" queue 7:         %u                 NA\n",
+	       queue[7]);
+	printf("=========================================================\n");
 }
 
 void eee_enable(int argc, char *argv[])
 {
-	unsigned long enable;
-	unsigned int value;
-	unsigned int eee_cap;
+	unsigned long enable = 0;
+	unsigned int value = 0;
+	unsigned int eee_cap = 0;
 	unsigned int eee_en_bitmap = 0;
-	unsigned long port_map;
+	unsigned long port_map = 0;
 	long port_num = -1;
-	int p;
+	int p = 0;
 
 	if (argc < 3)
 		goto error;
 
-	/*Check the input parameters is right or not.*/
+	/* Check the input parameters is right or not. */
 	if (!strncmp(argv[2], "enable", 7))
 		enable = 1;
 	else if (!strncmp(argv[2], "disable", 8))
@@ -3603,23 +3747,25 @@
 			port_map = 0;
 			for (p = 0; p < MAX_PHY_PORT; p++) {
 				if (argv[3][p] != '0' && argv[3][p] != '1') {
-					printf("portmap format error, should be combination of 0 or 1\n");
+					printf
+					    ("portmap format error, should be combination of 0 or 1\n");
 					goto error;
 				}
 				port_map |= ((argv[3][p] - '0') << p);
 			}
 		} else {
-			printf("port_no or portmap format error, should be length of 1 or 5\n");
+			printf
+			    ("port_no or portmap format error, should be length of 1 or 5\n");
 			goto error;
 		}
 	} else {
 		port_map = 0x1f;
 	}
 
-	eee_cap = (enable)? 6: 0;
+	eee_cap = (enable) ? 6 : 0;
 	for (p = 0; p < MAX_PHY_PORT; p++) {
 		/* port_map describe p0p1p2p3p4 from left to rignt */
-		if(!!(port_map & (1 << p)))
+		if (!!(port_map & (1 << p)))
 			mii_mgr_c45_write(p, 0x7, 0x3c, eee_cap);
 
 		mii_mgr_c45_read(p, 0x7, 0x3c, &value);
@@ -3642,7 +3788,7 @@
 		printf("\nCommand not support by this chip.\n");
 	}
 
-	printf("EEE(802.3az) %s", (enable)? "enable": "disable");
+	printf("EEE(802.3az) %s", (enable) ? "enable" : "disable");
 	if (argc == 4) {
 		if (port_num >= 0)
 			printf(" port%ld", port_num);
@@ -3661,9 +3807,9 @@
 
 void eee_dump(int argc, char *argv[])
 {
-	unsigned int cap, lp_cap;
+	unsigned int cap = 0, lp_cap = 0;
 	long port = -1;
-	int p;
+	int p = 0;
 
 	if (argc > 3) {
 		if (strlen(argv[3]) > 1) {
@@ -3674,7 +3820,7 @@
 		port = strtol(argv[3], (char **)NULL, 0);
 		if (port < 0 || port > MAX_PHY_PORT) {
 			printf("port# format error, should be 0 to %d\n",
-				       MAX_PHY_PORT);
+			       MAX_PHY_PORT);
 			return;
 		}
 	}
@@ -3716,7 +3862,7 @@
 	printf("\n");
 }
 
-void read_mib_counters()
+void read_mib_counters(int argc, char *argv[])
 {
 	printf("===================== %8s %8s %8s %8s %8s %8s %8s\n",
 	       "Port0", "Port1", "Port2", "Port3", "Port4", "Port5", "Port6");
@@ -3760,14 +3906,13 @@
 	dump_each_port(0x408C);
 }
 
-void clear_mib_counters()
+void clear_mib_counters(int argc, char *argv[])
 {
 	reg_write(0x4fe0, 0xf0);
-	read_mib_counters();
+	read_mib_counters(argc, argv);
 	reg_write(0x4fe0, 0x800000f0);
 }
 
-
 void exit_free()
 {
 	free(attres);
diff --git a/recipes-devtools/switch/files/src/switch_fun.h b/recipes-devtools/switch/files/src/switch_fun.h
index 70e4d18..cc16c20 100644
--- a/recipes-devtools/switch/files/src/switch_fun.h
+++ b/recipes-devtools/switch/files/src/switch_fun.h
@@ -6,6 +6,84 @@
 
 #include <stdbool.h>
 
+void (*pf_chip_func)(int argc, char *argv[]);
+
+struct switch_func_s {
+	void (*pf_table_dump)(int argc, char *argv[]);
+	void (*pf_table_clear)(int argc, char *argv[]);
+	void (*pf_switch_reset)(int argc, char *argv[]);
+	void (*pf_doArlAging)(int argc, char *argv[]);
+	void (*pf_read_mib_counters)(int argc, char *argv[]);
+	void (*pf_clear_mib_counters)(int argc, char *argv[]);
+	void (*pf_read_output_queue_counters)(int argc, char *argv[]);
+	void (*pf_read_free_page_counters)(int argc, char *argv[]);
+	void (*pf_rate_control)(int argc, char *argv[]);
+	void (*pf_igress_rate_set)(int argc, char *argv[]);
+	void (*pf_egress_rate_set)(int argc, char *argv[]);
+	void (*pf_table_add)(int argc, char *argv[]);
+	void (*pf_table_del_fid)(int argc, char *argv[]);
+	void (*pf_table_del_vid)(int argc, char *argv[]);
+	void (*pf_table_search_mac_fid)(int argc, char *argv[]);
+	void (*pf_table_search_mac_vid)(int argc, char *argv[]);
+	void (*pf_global_set_mac_fc)(int argc, char *argv[]);
+	void (*pf_set_mac_pfc)(int argc, char *argv[]);
+	void (*pf_qos_sch_select)(int argc, char *argv[]);
+	void (*pf_qos_set_base)(int argc, char *argv[]);
+	void (*pf_qos_wfq_set_weight)(int argc, char *argv[]);
+	void (*pf_qos_set_portpri)(int argc, char *argv[]);
+	void (*pf_qos_set_dscppri)(int argc, char *argv[]);
+	void (*pf_qos_pri_mapping_queue)(int argc, char *argv[]);
+	void (*pf_doStp)(int argc, char *argv[]);
+	void (*pf_sip_dump)(int argc, char *argv[]);
+	void (*pf_sip_add)(int argc, char *argv[]);
+	void (*pf_sip_del)(int argc, char *argv[]);
+	void (*pf_sip_clear)(int argc, char *argv[]);
+	void (*pf_dip_dump)(int argc, char *argv[]);
+	void (*pf_dip_add)(int argc, char *argv[]);
+	void (*pf_dip_del)(int argc, char *argv[]);
+	void (*pf_dip_clear)(int argc, char *argv[]);
+	void (*pf_set_mirror_to)(int argc, char *argv[]);
+	void (*pf_set_mirror_from)(int argc, char *argv[]);
+	void (*pf_doMirrorEn)(int argc, char *argv[]);
+	void (*pf_doMirrorPortBased)(int argc, char *argv[]);
+	void (*pf_acl_dip_add)(int argc, char *argv[]);
+	void (*pf_acl_dip_modify)(int argc, char *argv[]);
+	void (*pf_acl_dip_pppoe)(int argc, char *argv[]);
+	void (*pf_acl_dip_trtcm)(int argc, char *argv[]);
+	void (*pf_acl_dip_meter)(int argc, char *argv[]);
+	void (*pf_acl_mac_add)(int argc, char *argv[]);
+	void (*pf_acl_ethertype)(int argc, char *argv[]);
+	void (*pf_acl_sp_add)(int argc, char *argv[]);
+	void (*pf_acl_l4_add)(int argc, char *argv[]);
+	void (*pf_acl_port_enable)(int argc, char *argv[]);
+	void (*pf_acl_table_add)(int argc, char *argv[]);
+	void (*pf_acl_mask_table_add)(int argc, char *argv[]);
+	void (*pf_acl_rule_table_add)(int argc, char *argv[]);
+	void (*pf_acl_rate_table_add)(int argc, char *argv[]);
+	void (*pf_vlan_dump)(int argc, char *argv[]);
+	void (*pf_vlan_set)(int argc, char *argv[]);
+	void (*pf_vlan_clear)(int argc, char *argv[]);
+	void (*pf_doVlanSetVid)(int argc, char *argv[]);
+	void (*pf_doVlanSetPvid)(int argc, char *argv[]);
+	void (*pf_doVlanSetAccFrm)(int argc, char *argv[]);
+	void (*pf_doVlanSetPortAttr)(int argc, char *argv[]);
+	void (*pf_doVlanSetPortMode)(int argc, char *argv[]);
+	void (*pf_doVlanSetEgressTagPCR)(int argc, char *argv[]);
+	void (*pf_doVlanSetEgressTagPVC)(int argc, char *argv[]);
+	void (*pf_igmp_on)(int argc, char *argv[]);
+	void (*pf_igmp_off)(int argc, char *argv[]);
+	void (*pf_igmp_enable)(int argc, char *argv[]);
+	void (*pf_igmp_disable)(int argc, char *argv[]);
+	void (*pf_collision_pool_enable)(int argc, char *argv[]);
+	void (*pf_collision_pool_mac_dump)(int argc, char *argv[]);
+	void (*pf_collision_pool_dip_dump)(int argc, char *argv[]);
+	void (*pf_collision_pool_sip_dump)(int argc, char *argv[]);
+	void (*pf_pfc_get_rx_counter)(int argc, char *argv[]);
+	void (*pf_pfc_get_tx_counter)(int argc, char *argv[]);
+	void (*pf_eee_enable)(int argc, char *argv[]);
+	void (*pf_eee_dump)(int argc, char *argv[]);
+};
+
 #define MT7530_T10_TEST_CONTROL 0x145
 
 #define MAX_PORT 6
@@ -15,14 +93,18 @@
 extern int chip_name;
 extern struct mt753x_attr *attres;
 extern bool nl_init_flag;
+extern struct switch_func_s mt753x_switch_func;
+extern struct switch_func_s an8855_switch_func;
 
 /*basic operation*/
 int reg_read(unsigned int offset, unsigned int *value);
 int reg_write(unsigned int offset, unsigned int value);
 int mii_mgr_read(unsigned int port_num, unsigned int reg, unsigned int *value);
 int mii_mgr_write(unsigned int port_num, unsigned int reg, unsigned int value);
-int mii_mgr_c45_read(unsigned int port_num, unsigned int dev, unsigned int reg, unsigned int *value);
-int mii_mgr_c45_write(unsigned int port_num, unsigned int dev, unsigned int reg, unsigned int value);
+int mii_mgr_c45_read(unsigned int port_num, unsigned int dev, unsigned int reg,
+		     unsigned int *value);
+int mii_mgr_c45_write(unsigned int port_num, unsigned int dev, unsigned int reg,
+		      unsigned int value);
 
 /*phy setting*/
 int phy_dump(int phy_addr);
@@ -50,28 +132,28 @@
 void acl_rate_table_add(int argc, char *argv[]);
 
 /*dip table*/
-void dip_dump(void);
+void dip_dump(int argc, char *argv[]);
 void dip_add(int argc, char *argv[]);
 void dip_del(int argc, char *argv[]);
-void dip_clear(void);
+void dip_clear(int argc, char *argv[]);
 
 /*sip table*/
-void sip_dump(void);
+void sip_dump(int argc, char *argv[]);
 void sip_add(int argc, char *argv[]);
 void sip_del(int argc, char *argv[]);
-void sip_clear(void);
+void sip_clear(int argc, char *argv[]);
 
 /*stp*/
 void doStp(int argc, char *argv[]);
 
 /*mac table*/
-void table_dump(void);
+void table_dump(int argc, char *argv[]);
 void table_add(int argc, char *argv[]);
 void table_search_mac_vid(int argc, char *argv[]);
 void table_search_mac_fid(int argc, char *argv[]);
 void table_del_fid(int argc, char *argv[]);
 void table_del_vid(int argc, char *argv[]);
-void table_clear(void);
+void table_clear(int argc, char *argv[]);
 
 /*vlan table*/
 void vlan_dump(int argc, char *argv[]);
@@ -88,7 +170,7 @@
 
 /*igmp function*/
 void igmp_on(int argc, char *argv[]);
-void igmp_off();
+void igmp_off(int argc, char *argv[]);
 void igmp_disable(int argc, char *argv[]);
 void igmp_enable(int argc, char *argv[]);
 
@@ -100,11 +182,11 @@
 
 /*rate control*/
 void rate_control(int argc, char *argv[]);
-int ingress_rate_set(int on_off, unsigned int port, unsigned int bw);
-int egress_rate_set(int on_off, int port, int bw);
+void ingress_rate_set(int argc, char *argv[]);
+void egress_rate_set(int argc, char *argv[]);
 
 /*QoS*/
-int qos_sch_select(int argc, char *argv[]);
+void qos_sch_select(int argc, char *argv[]);
 void qos_set_base(int argc, char *argv[]);
 void qos_wfq_set_weight(int argc, char *argv[]);
 void qos_set_portpri(int argc, char *argv[]);
@@ -112,32 +194,32 @@
 void qos_pri_mapping_queue(int argc, char *argv[]);
 
 /*flow control*/
-int global_set_mac_fc(int argc, char *argv[]);
-int phy_set_fc(int argc, char *argv[]);
-int phy_set_an(int argc, char *argv[]);
+void global_set_mac_fc(int argc, char *argv[]);
+void phy_set_fc(int argc, char *argv[]);
+void phy_set_an(int argc, char *argv[]);
 
 /* collision pool functions */
-int collision_pool_enable(int argc, char *argv[]);
-void collision_pool_mac_dump();
-void collision_pool_dip_dump();
-void collision_pool_sip_dump();
+void collision_pool_enable(int argc, char *argv[]);
+void collision_pool_mac_dump(int argc, char *argv[]);
+void collision_pool_dip_dump(int argc, char *argv[]);
+void collision_pool_sip_dump(int argc, char *argv[]);
 
 /*pfc functions*/
-int set_mac_pfc(int argc, char *argv[]);
+void set_mac_pfc(int argc, char *argv[]);
 void pfc_get_rx_counter(int argc, char *argv[]);
 void pfc_get_tx_counter(int argc, char *argv[]);
 
 /*switch reset*/
-int switch_reset(int argc, char *argv[]);
+void switch_reset(int argc, char *argv[]);
 
 /* EEE(802.3az) function  */
 void eee_enable(int argc, char *argv[]);
 void eee_dump(int argc, char *argv[]);
 
-void read_mib_counters();
-void clear_mib_counters();
-void read_output_queue_counters();
-void read_free_page_counters();
+void read_mib_counters(int argc, char *argv[]);
+void clear_mib_counters(int argc, char *argv[]);
+void read_output_queue_counters(int argc, char *argv[]);
+void read_free_page_counters(int argc, char *argv[]);
 
 void phy_crossover(int argc, char *argv[]);
 void exit_free();
diff --git a/recipes-devtools/switch/files/src/switch_fun_an8855.c b/recipes-devtools/switch/files/src/switch_fun_an8855.c
new file mode 100644
index 0000000..e5ec490
--- /dev/null
+++ b/recipes-devtools/switch/files/src/switch_fun_an8855.c
@@ -0,0 +1,1804 @@
+/*
+* switch_fun.c: switch function sets
+*/
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdbool.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#include <linux/if.h>
+#include <stdbool.h>
+#include <time.h>
+
+#include "switch_extend.h"
+#include "switch_netlink.h"
+#include "switch_fun.h"
+#include "switch_fun_an8855.h"
+
+#define MAC_STR         "%02X%02X%02X%02X%02X%02X"
+#define MAC2STR(m)      (m)[0],(m)[1],(m)[2],(m)[3],(m)[4],(m)[5]
+
+const static C8_T *mac_address_forward_control_string[] = {
+	"Default",
+	"CPU include",
+	"CPU exclude",
+	"CPU only",
+	"Drop"
+};
+
+struct switch_func_s an8855_switch_func = {
+	.pf_table_dump = an8855_table_dump,
+	.pf_table_clear = an8855_table_clear,
+	.pf_switch_reset = an8855_switch_reset,
+	.pf_doArlAging = an8855_doArlAging,
+	.pf_read_mib_counters = an8855_read_mib_counters,
+	.pf_clear_mib_counters = an8855_clear_mib_counters,
+	.pf_read_output_queue_counters = an8855_read_output_queue_counters,
+	.pf_read_free_page_counters = an8855_read_free_page_counters,
+	.pf_rate_control = an8855_rate_control,
+	.pf_igress_rate_set = an8855_ingress_rate_set,
+	.pf_egress_rate_set = an8855_egress_rate_set,
+	.pf_table_add = an8855_table_add,
+	.pf_table_del_fid = an8855_table_del_fid,
+	.pf_table_del_vid = an8855_table_del_vid,
+	.pf_table_search_mac_fid = an8855_table_search_mac_fid,
+	.pf_table_search_mac_vid = an8855_table_search_mac_vid,
+	.pf_global_set_mac_fc = an8855_global_set_mac_fc,
+	.pf_set_mac_pfc = an8855_not_supported,
+	.pf_qos_sch_select = an8855_qos_sch_select,
+	.pf_qos_set_base = an8855_qos_set_base,
+	.pf_qos_wfq_set_weight = an8855_qos_wfq_set_weight,
+	.pf_qos_set_portpri = an8855_qos_set_portpri,
+	.pf_qos_set_dscppri = an8855_qos_set_dscppri,
+	.pf_qos_pri_mapping_queue = an8855_qos_pri_mapping_queue,
+	.pf_doStp = an8855_doStp,
+	.pf_sip_dump = an8855_not_supported,
+	.pf_sip_add = an8855_not_supported,
+	.pf_sip_del = an8855_not_supported,
+	.pf_sip_clear = an8855_not_supported,
+	.pf_dip_dump = an8855_not_supported,
+	.pf_dip_add = an8855_not_supported,
+	.pf_dip_del = an8855_not_supported,
+	.pf_dip_clear = an8855_not_supported,
+	.pf_set_mirror_to = an8855_set_mirror_to,
+	.pf_set_mirror_from = an8855_set_mirror_from,
+	.pf_doMirrorEn = an8855_doMirrorEn,
+	.pf_doMirrorPortBased = an8855_doMirrorPortBased,
+	.pf_acl_dip_add = an8855_not_supported,
+	.pf_acl_dip_modify = an8855_not_supported,
+	.pf_acl_dip_pppoe = an8855_not_supported,
+	.pf_acl_dip_trtcm = an8855_not_supported,
+	.pf_acl_dip_meter = an8855_not_supported,
+	.pf_acl_mac_add = an8855_not_supported,
+	.pf_acl_ethertype = an8855_not_supported,
+	.pf_acl_sp_add = an8855_not_supported,
+	.pf_acl_l4_add = an8855_not_supported,
+	.pf_acl_port_enable = an8855_not_supported,
+	.pf_acl_table_add = an8855_not_supported,
+	.pf_acl_mask_table_add = an8855_not_supported,
+	.pf_acl_rule_table_add = an8855_not_supported,
+	.pf_acl_rate_table_add = an8855_not_supported,
+	.pf_vlan_dump = an8855_vlan_dump,
+	.pf_vlan_set = an8855_vlan_set,
+	.pf_vlan_clear = an8855_vlan_clear,
+	.pf_doVlanSetVid = an8855_doVlanSetVid,
+	.pf_doVlanSetPvid = an8855_doVlanSetPvid,
+	.pf_doVlanSetAccFrm = an8855_doVlanSetAccFrm,
+	.pf_doVlanSetPortAttr = an8855_doVlanSetPortAttr,
+	.pf_doVlanSetPortMode = an8855_doVlanSetPortMode,
+	.pf_doVlanSetEgressTagPCR = an8855_doVlanSetEgressTagPCR,
+	.pf_doVlanSetEgressTagPVC = an8855_doVlanSetEgressTagPVC,
+	.pf_igmp_on = an8855_not_supported,
+	.pf_igmp_off = an8855_not_supported,
+	.pf_igmp_enable = an8855_not_supported,
+	.pf_igmp_disable = an8855_not_supported,
+	.pf_collision_pool_enable = an8855_not_supported,
+	.pf_collision_pool_mac_dump = an8855_not_supported,
+	.pf_collision_pool_dip_dump = an8855_not_supported,
+	.pf_collision_pool_sip_dump = an8855_not_supported,
+	.pf_pfc_get_rx_counter = an8855_not_supported,
+	.pf_pfc_get_tx_counter = an8855_not_supported,
+	.pf_eee_enable = an8855_eee_enable,
+	.pf_eee_dump = an8855_eee_dump,
+};
+
+AIR_ERROR_NO_T
+an8855_reg_read(const UI32_T unit, const UI32_T addr_offset, UI32_T * ptr_data)
+{
+	int ret;
+
+	ret = reg_read(addr_offset, ptr_data);
+	if (ret < 0) {
+		return AIR_E_OTHERS;
+	}
+
+	return AIR_E_OK;
+}
+
+AIR_ERROR_NO_T
+an8855_reg_write(const UI32_T unit, const UI32_T addr_offset, const UI32_T data)
+{
+	int ret;
+
+	ret = reg_write(addr_offset, data);
+	if (ret < 0) {
+		return AIR_E_OTHERS;
+	}
+
+	return AIR_E_OK;
+}
+
+AIR_ERROR_NO_T
+an8855_phy_cl22_read(const UI32_T unit,
+		     const UI32_T port_id,
+		     const UI32_T addr_offset, UI32_T * ptr_data)
+{
+	int ret;
+
+	ret = mii_mgr_read(port_id, addr_offset, ptr_data);
+	if (ret < 0) {
+		return AIR_E_OTHERS;
+	}
+
+	return AIR_E_OK;
+}
+
+AIR_ERROR_NO_T
+an8855_phy_cl22_write(const UI32_T unit,
+		      const UI32_T port_id,
+		      const UI32_T addr_offset, const UI32_T data)
+{
+	int ret;
+
+	ret = mii_mgr_write(port_id, addr_offset, data);
+	if (ret < 0) {
+		return AIR_E_OTHERS;
+	}
+
+	return AIR_E_OK;
+}
+
+AIR_ERROR_NO_T
+an8855_phy_cl45_read(const UI32_T unit,
+		     const UI32_T port_id,
+		     const UI32_T dev_type,
+		     const UI32_T addr_offset, UI32_T * ptr_data)
+{
+	int ret;
+
+	ret = mii_mgr_c45_read(port_id, dev_type, addr_offset, ptr_data);
+	if (ret < 0) {
+		return AIR_E_OTHERS;
+	}
+
+	return AIR_E_OK;
+}
+
+AIR_ERROR_NO_T
+an8855_phy_cl45_write(const UI32_T unit,
+		      const UI32_T port_id,
+		      const UI32_T dev_type,
+		      const UI32_T addr_offset, const UI32_T data)
+{
+	int ret;
+
+	ret = mii_mgr_c45_write(port_id, dev_type, addr_offset, data);
+	if (ret < 0) {
+		return AIR_E_OTHERS;
+	}
+
+	return AIR_E_OK;
+}
+
+void an8855_not_supported(int argc, char *argv[])
+{
+	printf("Cmd not supported by AN8855.\n");
+}
+
+static AIR_ERROR_NO_T
+_printMacEntry(AIR_MAC_ENTRY_T * mt, UI32_T age_unit, UI8_T count, UI8_T title)
+{
+	AIR_ERROR_NO_T ret = AIR_E_OK;
+	I32_T i = 0, j = 0;
+	UI8_T first = 0;
+	UI8_T find = 0;
+	if (title) {
+		printf("%-6s%-15s%-5s%-5s%-5s%-10s%-10s%-6s\n",
+		       "unit",
+		       "mac",
+		       "ivl", "vid", "fid", "age-time", "forward", "port");
+		return ret;
+	}
+	for (i = 0; i < count; i++) {
+		printf("%-6d", age_unit);
+		printf(MAC_STR, MAC2STR(mt[i].mac));
+		printf("...");
+		if (mt[i].flags & AIR_L2_MAC_ENTRY_FLAGS_IVL) {
+			printf("%-3s..", "ivl");
+			printf("%-5d", mt[i].cvid);
+			printf("%-5s", ".....");
+		} else {
+			printf("%-3s..", "svl");
+			printf("%-5s", ".....");
+			printf("%-5d", mt[i].fid);
+		}
+		if (mt[i].flags & AIR_L2_MAC_ENTRY_FLAGS_STATIC) {
+			printf("%-7s.", "static");
+		} else {
+			printf("%d sec..", mt[i].timer);
+		}
+		printf("%-10s",
+		       mac_address_forward_control_string[mt[i].sa_fwd]);
+		first = 0;
+		find = 0;
+		for (j = (AIR_MAX_NUM_OF_PORTS - 1); j >= 0; j--) {
+			if ((mt[i].port_bitmap[0]) & (1 << j)) {
+				first = j;
+				find = 1;
+				break;
+			}
+		}
+		if (find) {
+			for (j = 0; j < AIR_MAX_NUM_OF_PORTS; j++) {
+				if ((mt[i].port_bitmap[0]) & (1 << j)) {
+					if (j == first)
+						printf("%-2d", j);
+					else
+						printf("%-2d,", j);
+				}
+			}
+		} else
+			printf("no dst port");
+		printf("\n");
+	}
+	return ret;
+}
+
+static AIR_ERROR_NO_T _str2mac(C8_T * str, C8_T * mac)
+{
+	UI32_T i;
+	C8_T tmpstr[3];
+
+	for (i = 0; i < 6; i++) {
+		strncpy(tmpstr, str + (i * 2), 2);
+		tmpstr[2] = '\0';
+		mac[i] = strtoul(tmpstr, NULL, 16);
+	}
+
+	return AIR_E_OK;
+}
+
+static void an8855_table_dump_internal(int type)
+{
+	unsigned char count = 0;
+	unsigned int total_count = 0;
+	unsigned int bucket_size = 0;
+	AIR_ERROR_NO_T ret = 0;
+	AIR_MAC_ENTRY_T *ptr_mt;
+
+	bucket_size = AIR_L2_MAC_SET_NUM;
+	ptr_mt = malloc(sizeof(AIR_MAC_ENTRY_T) * bucket_size);
+	if (ptr_mt == NULL) {
+		printf("Error, malloc fail\n\r");
+		return;
+	}
+	memset(ptr_mt, 0, sizeof(AIR_MAC_ENTRY_T) * bucket_size);
+	_printMacEntry(ptr_mt, 0, count, TRUE);
+	/* get 1st entry of MAC table */
+	ret = air_l2_getMacAddr(0, &count, ptr_mt);
+	switch (ret) {
+	case AIR_E_ENTRY_NOT_FOUND:
+		printf("Not Found!\n");
+		goto DUMP_ERROR;
+	case AIR_E_TIMEOUT:
+		printf("Time Out!\n");
+		goto DUMP_ERROR;
+	case AIR_E_BAD_PARAMETER:
+		printf("Bad Parameter!\n");
+		goto DUMP_ERROR;
+	default:
+		break;
+	}
+	total_count += count;
+	_printMacEntry(ptr_mt, 0, count, FALSE);
+	/* get other entries of MAC table */
+	while (1) {
+		memset(ptr_mt, 0, sizeof(AIR_MAC_ENTRY_T) * bucket_size);
+		ret = air_l2_getNextMacAddr(0, &count, ptr_mt);
+		if (AIR_E_OK != ret) {
+			break;
+		}
+		total_count += count;
+		_printMacEntry(ptr_mt, 0, count, FALSE);
+	}
+	switch (ret) {
+	case AIR_E_TIMEOUT:
+		printf("Time Out!\n");
+		break;
+	case AIR_E_BAD_PARAMETER:
+		printf("Bad Parameter!\n");
+		break;
+	default:
+		printf("Found %u %s\n", total_count,
+		       (total_count > 1) ? "entries" : "entry");
+		break;
+	}
+
+DUMP_ERROR:
+	free(ptr_mt);
+	return;
+}
+
+void an8855_table_dump(int argc, char *argv[])
+{
+	an8855_table_dump_internal(GENERAL_TABLE);
+}
+
+void an8855_table_add(int argc, char *argv[])
+{
+	AIR_ERROR_NO_T ret = AIR_E_OK;
+	AIR_MAC_ENTRY_T mt;
+	unsigned int i = 0;
+	unsigned int age_time = 0;
+	memset(&mt, 0, sizeof(AIR_MAC_ENTRY_T));
+	if (!argv[2] || strlen(argv[2]) != 12) {
+		printf("MAC address format error, should be of length 12\n");
+		return;
+	}
+	ret = _str2mac(argv[2], (C8_T *) mt.mac);
+	if (ret != AIR_E_OK) {
+		printf("Unrecognized command.\n");
+		return;
+	}
+	if (argc > 4) {
+		mt.cvid = strtoul(argv[4], NULL, 0);
+		if (4095 < mt.cvid) {
+			printf("wrong vid range, should be within 0~4095\n");
+			return;
+		}
+		mt.flags |= AIR_L2_MAC_ENTRY_FLAGS_IVL;
+	}
+	if (!argv[3] || strlen(argv[3]) != 6) {
+		/*bit0~5, each map port0~port5 */
+		printf("portmap format error, should be of length 6\n");
+		return;
+	}
+	for (i = 0; i < 6; i++) {
+		if (argv[3][i] != '0' && argv[3][i] != '1') {
+			printf
+			    ("portmap format error, should be of combination of 0 or 1\n");
+			return;
+		}
+		mt.port_bitmap[0] |= ((argv[3][i] - '0') << i);
+	}
+	if (argc > 5) {
+		age_time = strtoul(argv[5], NULL, 0);
+		if (age_time < 1 || 1000000 < age_time) {
+			printf("wrong age range, should be within 1~1000000\n");
+			return;
+		}
+	} else {
+		mt.flags |= AIR_L2_MAC_ENTRY_FLAGS_STATIC;
+	}
+	mt.sa_fwd = AIR_L2_FWD_CTRL_DEFAULT;
+	ret = air_l2_addMacAddr(0, &mt);
+	if (ret == AIR_E_OK) {
+		printf("add mac address done.\n");
+		usleep(5000);
+		if (!(mt.flags & AIR_L2_MAC_ENTRY_FLAGS_STATIC)) {
+			ret = air_l2_setMacAddrAgeOut(0, age_time);
+			if (ret == AIR_E_OK) {
+				printf("set age out time done.\n");
+			} else {
+				printf("set age out time fail.\n");
+			}
+		}
+	} else {
+		printf("add mac address fail.\n");
+	}
+	return;
+}
+
+void an8855_table_search_mac_vid(int argc, char *argv[])
+{
+	AIR_ERROR_NO_T ret = AIR_E_OK;
+	unsigned char count = 0;
+	char tmpstr[9];
+	AIR_MAC_ENTRY_T *ptr_mt;
+
+	if (!argv[3] || strlen(argv[3]) != 12) {
+		printf("MAC address format error, should be of length 12\n");
+		return;
+	}
+
+	ptr_mt = malloc(sizeof(AIR_MAC_ENTRY_T));
+	if (NULL == ptr_mt) {
+		printf("Error, malloc fail\n");
+		return;
+	}
+	memset(ptr_mt, 0, sizeof(AIR_MAC_ENTRY_T));
+	ret = _str2mac(argv[3], (C8_T *) ptr_mt->mac);
+	if (ret != AIR_E_OK) {
+		printf("Unrecognized command.\n");
+		free(ptr_mt);
+		return;
+	}
+
+	/* get mac entry by MAC address & vid */
+	ptr_mt->cvid = strtoul(argv[5], NULL, 0);
+	ptr_mt->flags |= AIR_L2_MAC_ENTRY_FLAGS_IVL;
+	if (ptr_mt->cvid > 4095) {
+		printf("wrong vid range, should be within 0~4095\n");
+		free(ptr_mt);
+		return;
+	}
+
+	ret = air_l2_getMacAddr(0, &count, ptr_mt);
+	if (ret == AIR_E_OK) {
+		_printMacEntry(ptr_mt, 0, 1, TRUE);
+		_printMacEntry(ptr_mt, 0, 1, FALSE);
+	} else {
+		printf("\n Not found!\n");
+	}
+	free(ptr_mt);
+	return;
+}
+
+void an8855_table_search_mac_fid(int argc, char *argv[])
+{
+	AIR_ERROR_NO_T ret = AIR_E_OK;
+	unsigned char count = 0;
+	char tmpstr[9];
+	AIR_MAC_ENTRY_T *ptr_mt;
+
+	if (!argv[3] || strlen(argv[3]) != 12) {
+		printf("MAC address format error, should be of length 12\n");
+		return;
+	}
+
+	ptr_mt = malloc(sizeof(AIR_MAC_ENTRY_T));
+	if (NULL == ptr_mt) {
+		printf("Error, malloc fail\n");
+		return;
+	}
+	memset(ptr_mt, 0, sizeof(AIR_MAC_ENTRY_T));
+	ret = _str2mac(argv[3], (C8_T *) ptr_mt->mac);
+	if (ret != AIR_E_OK) {
+		printf("Unrecognized command.\n");
+		free(ptr_mt);
+		return;
+	}
+
+	/* get mac entry by MAC address & fid */
+	ptr_mt->fid = strtoul(argv[5], NULL, 0);
+	if (ptr_mt->fid > 7) {
+		printf("wrong fid range, should be within 0~7\n");
+		free(ptr_mt);
+		return;
+	}
+
+	ret = air_l2_getMacAddr(0, &count, ptr_mt);
+	if (ret == AIR_E_OK) {
+		_printMacEntry(ptr_mt, 0, 1, TRUE);
+		_printMacEntry(ptr_mt, 0, 1, FALSE);
+	} else {
+		printf("\n Not found!\n");
+	}
+	free(ptr_mt);
+	return;
+}
+
+void an8855_table_del_fid(int argc, char *argv[])
+{
+	AIR_ERROR_NO_T ret = AIR_E_OK;
+	char tmpstr[9];
+	AIR_MAC_ENTRY_T mt;
+
+	if (!argv[3] || strlen(argv[3]) != 12) {
+		printf("MAC address format error, should be of length 12\n");
+		return;
+	}
+
+	memset(&mt, 0, sizeof(AIR_MAC_ENTRY_T));
+	ret = _str2mac(argv[3], (C8_T *) mt.mac);
+	if (ret != AIR_E_OK) {
+		printf("Unrecognized command.\n");
+		return;
+	}
+
+	/* get mac entry by MAC address & fid */
+	mt.fid = strtoul(argv[5], NULL, 0);
+	if (mt.fid > 7) {
+		printf("wrong fid range, should be within 0~7\n");
+		return;
+	}
+
+	ret = air_l2_delMacAddr(0, &mt);
+	if (ret == AIR_E_OK) {
+		printf("Done.\n");
+	} else {
+		printf("Fail.\n");
+	}
+	return;
+}
+
+void an8855_table_del_vid(int argc, char *argv[])
+{
+	AIR_ERROR_NO_T ret = AIR_E_OK;
+	char tmpstr[9];
+	AIR_MAC_ENTRY_T mt;
+
+	if (!argv[3] || strlen(argv[3]) != 12) {
+		printf("MAC address format error, should be of length 12\n");
+		return;
+	}
+
+	memset(&mt, 0, sizeof(AIR_MAC_ENTRY_T));
+	ret = _str2mac(argv[3], (C8_T *) mt.mac);
+	if (ret != AIR_E_OK) {
+		printf("Unrecognized command.\n");
+		return;
+	}
+
+	/* get mac entry by MAC address & vid */
+	mt.cvid = strtoul(argv[5], NULL, 0);
+	mt.flags |= AIR_L2_MAC_ENTRY_FLAGS_IVL;
+	if (mt.cvid > 4095) {
+		printf("wrong vid range, should be within 0~4095\n");
+		return;
+	}
+
+	ret = air_l2_delMacAddr(0, &mt);
+	if (ret == AIR_E_OK) {
+		printf("Done.\n");
+	} else {
+		printf("Fail.\n");
+	}
+	return;
+}
+
+void an8855_table_clear(int argc, char *argv[])
+{
+	AIR_ERROR_NO_T ret = AIR_E_OK;
+
+	ret = air_l2_clearMacAddr(0);
+	if (ret == AIR_E_OK)
+		printf("Clear MAC Address Table Done.\n");
+	else
+		printf("Clear MAC Address Table Fail.\n");
+	return;
+}
+
+void an8855_set_mirror_to(int argc, char *argv[])
+{
+	int idx;
+	AIR_MIR_SESSION_T session = { 0 };
+
+	idx = strtoul(argv[3], NULL, 0);
+	if (idx < 0 || MAX_PORT < idx) {
+		printf("wrong port member, should be within 0~%d\n", MAX_PORT);
+		return;
+	}
+
+	memset(&session, 0, sizeof(AIR_MIR_SESSION_T));
+
+	air_mir_getSession(0, 0, &session);
+	session.dst_port = idx;
+	session.flags |= AIR_MIR_SESSION_FLAGS_ENABLE;
+	air_mir_addSession(0, 0, &session);
+}
+
+void an8855_set_mirror_from(int argc, char *argv[])
+{
+	int idx = 0, mirror = 0;
+	AIR_MIR_SESSION_T session = { 0 };
+
+	idx = _strtoul(argv[3], NULL, 0);
+	mirror = _strtoul(argv[4], NULL, 0);
+
+	if (idx < 0 || MAX_PORT < idx) {
+		printf("wrong port member, should be within 0~%d\n", MAX_PORT);
+		return;
+	}
+
+	if (mirror < 0 || 3 < mirror) {
+		printf("wrong mirror setting, should be within 0~3\n");
+		return;
+	}
+
+	memset(&session, 0, sizeof(AIR_MIR_SESSION_T));
+
+	if (mirror & 0x1) {	// rx enable
+		session.src_port = idx;
+		air_mir_getMirrorPort(0, 0, &session);
+
+		session.flags |= AIR_MIR_SESSION_FLAGS_DIR_RX;
+		session.src_port = idx;
+		air_mir_setMirrorPort(0, 0, &session);
+	}
+
+	if (mirror & 0x2) {	//tx enable
+		session.src_port = idx;
+		air_mir_getMirrorPort(0, 0, &session);
+
+		session.flags |= AIR_MIR_SESSION_FLAGS_DIR_TX;
+		session.src_port = idx;
+		air_mir_setMirrorPort(0, 0, &session);
+	}
+}
+
+void an8855_vlan_dump(int argc, char *argv[])
+{
+	AIR_VLAN_ENTRY_T vlan_entry = { 0 };
+	unsigned int i;
+	int eg_tag = 0;
+
+	if (argc == 4) {
+		if (!strncmp(argv[3], "egtag", 6))
+			eg_tag = 1;
+	}
+
+	if (eg_tag)
+		printf
+		    ("  vid  fid  portmap    s-tag\teg_tag(0:untagged 2:tagged)\n");
+	else
+		printf("  vid  fid  portmap    s-tag\n");
+
+	for (i = 1; i < 4096; i++) {
+		_air_vlan_readEntry(0, i, &vlan_entry);
+
+		if (vlan_entry.valid) {
+			printf(" %4d  ", i);
+			printf(" %2d ", vlan_entry.vlan_entry_format.fid);
+			printf(" %c",
+			       (vlan_entry.
+				vlan_entry_format.port_mem & 0b0000001) ? '1' :
+			       '-');
+			printf("%c",
+			       (vlan_entry.
+				vlan_entry_format.port_mem & 0b0000010) ? '1' :
+			       '-');
+			printf("%c",
+			       (vlan_entry.
+				vlan_entry_format.port_mem & 0b0000100) ? '1' :
+			       '-');
+			printf("%c",
+			       (vlan_entry.
+				vlan_entry_format.port_mem & 0b0001000) ? '1' :
+			       '-');
+			printf("%c",
+			       (vlan_entry.
+				vlan_entry_format.port_mem & 0b0010000) ? '1' :
+			       '-');
+			printf("%c",
+			       (vlan_entry.
+				vlan_entry_format.port_mem & 0b0100000) ? '1' :
+			       '-');
+			printf("%c",
+			       (vlan_entry.
+				vlan_entry_format.port_mem & 0b1000000) ? '1' :
+			       '-');
+			printf("    %4d", vlan_entry.vlan_entry_format.eg_ctrl);
+			if (eg_tag) {
+				printf("\t");
+				if (vlan_entry.vlan_entry_format.eg_con
+				    && vlan_entry.
+				    vlan_entry_format.eg_ctrl_en) {
+					/* VTAG_EN=1 and EG_CON=1 */
+					printf("CONSISTENT");
+				} else if (vlan_entry.
+					   vlan_entry_format.eg_ctrl_en) {
+					/* VTAG_EN=1 */
+					printf("%d",
+					       (vlan_entry.
+						vlan_entry_format.eg_ctrl >> 0)
+					       & 0x3);
+					printf("%d",
+					       (vlan_entry.
+						vlan_entry_format.eg_ctrl >> 2)
+					       & 0x3);
+					printf("%d",
+					       (vlan_entry.
+						vlan_entry_format.eg_ctrl >> 4)
+					       & 0x3);
+					printf("%d",
+					       (vlan_entry.
+						vlan_entry_format.eg_ctrl >> 6)
+					       & 0x3);
+					printf("%d",
+					       (vlan_entry.
+						vlan_entry_format.eg_ctrl >> 8)
+					       & 0x3);
+					printf("%d",
+					       (vlan_entry.
+						vlan_entry_format.eg_ctrl >> 10)
+					       & 0x3);
+					printf("%d",
+					       (vlan_entry.
+						vlan_entry_format.eg_ctrl >> 12)
+					       & 0x3);
+				} else {
+					/* VTAG_EN=0 */
+					printf("DISABLED");
+				}
+			}
+			printf("\n");
+		} else {
+			/*print 16 vid for reference information */
+			if (i <= 16) {
+				printf(" %4d  ", i);
+				printf(" %2d ",
+				       vlan_entry.vlan_entry_format.fid);
+				printf(" invalid\n");
+			}
+		}
+	}
+}
+
+void an8855_vlan_clear(int argc, char *argv[])
+{
+	air_vlan_destroyAll(0, 0);
+}
+
+void an8855_vlan_set(int argc, char *argv[])
+{
+	unsigned int vlan_mem = 0;
+	int i, vid, fid;
+	int stag = 0;
+	unsigned long eg_con = 0;
+	unsigned int eg_tag = 0;
+	AIR_VLAN_ENTRY_T vlan_entry = { 0 };
+
+	if (argc < 5) {
+		printf("insufficient arguments!\n");
+		return;
+	}
+
+	fid = strtoul(argv[3], NULL, 0);
+	if (fid < 0 || fid > 7) {
+		printf("wrong filtering db id range, should be within 0~7\n");
+		return;
+	}
+
+	vid = strtoul(argv[4], NULL, 0);
+	if (vid < 0 || MAX_VID_VALUE < vid) {
+		printf("wrong vlan id range, should be within 0~4095\n");
+		return;
+	}
+
+	if (strlen(argv[5]) != SWITCH_MAX_PORT) {
+		printf("portmap format error, should be of length %d\n",
+		       SWITCH_MAX_PORT);
+		return;
+	}
+
+	vlan_mem = 0;
+	for (i = 0; i < SWITCH_MAX_PORT; i++) {
+		if (argv[5][i] != '0' && argv[5][i] != '1') {
+			printf
+			    ("portmap format error, should be of combination of 0 or 1\n");
+			return;
+		}
+		vlan_mem += (argv[5][i] - '0') * (1 << i);
+	}
+
+	/* VLAN stag */
+	if (argc > 6) {
+		stag = strtoul(argv[6], NULL, 16);
+		if (stag < 0 || 0xfff < stag) {
+			printf
+			    ("wrong stag id range, should be within 0~4095\n");
+			return;
+		}
+	}
+
+	/* set vlan member */
+	vlan_entry.vlan_entry_format.port_mem = vlan_mem;
+	vlan_entry.vlan_entry_format.ivl = 1;
+	vlan_entry.vlan_entry_format.stag = stag;
+	vlan_entry.valid = 1;
+
+	if (argc > 7) {
+		eg_con = strtoul(argv[7], NULL, 2);
+		eg_con = ! !eg_con;
+		vlan_entry.vlan_entry_format.eg_con = eg_con;
+		vlan_entry.vlan_entry_format.eg_ctrl_en = 1;
+	}
+
+	if (argc > 8 && !eg_con) {
+		if (strlen(argv[8]) != SWITCH_MAX_PORT) {
+			printf
+			    ("egtag portmap format error, should be of length %d\n",
+			     SWITCH_MAX_PORT);
+			return;
+		}
+
+		for (i = 0; i < SWITCH_MAX_PORT; i++) {
+			if (argv[8][i] < '0' || argv[8][i] > '3') {
+				printf
+				    ("egtag portmap format error, should be of combination of 0 or 3\n");
+				return;
+			}
+			eg_tag |= (argv[8][i] - '0') << (i * 2);
+		}
+
+		vlan_entry.vlan_entry_format.eg_ctrl_en = 1;
+		vlan_entry.vlan_entry_format.eg_ctrl = eg_tag;
+	}
+
+	_air_vlan_writeEntry(0, vid, &vlan_entry);
+}
+
+void an8855_switch_reset(int argc, char *argv[])
+{
+	air_switch_reset(0);
+}
+
+void an8855_global_set_mac_fc(int argc, char *argv[])
+{
+	unsigned char enable = 0;
+	unsigned int reg = 0, value = 0;
+
+	enable = _strtoul(argv[3], NULL, 10);
+	printf("enable: %d\n", enable);
+
+	/* Check the input parameters is right or not. */
+	if (enable > 1) {
+		printf(HELP_MACCTL_FC);
+		return;
+	}
+	reg_read(0x10207e04, &value);
+	value &= (~(1 << 31));
+	value |= (enable << 31);
+	reg_write(0x10207e04, value);
+}				/*end mac_set_fc */
+
+void an8855_qos_sch_select(int argc, char *argv[])
+{
+	unsigned char port, queue;
+	unsigned char type = 0;
+	unsigned int value, reg;
+
+	if (argc < 7)
+		return;
+
+	port = _strtoul(argv[3], NULL, 10);
+	queue = _strtoul(argv[4], NULL, 10);
+	type = _strtoul(argv[6], NULL, 10);
+
+	if (port > 6 || queue > 7) {
+		printf("\n Illegal input parameters\n");
+		return;
+	}
+
+	if ((type != 0 && type != 1 && type != 2)) {
+		printf(HELP_QOS_TYPE);
+		return;
+	}
+
+	printf("\r\nswitch qos type: %d.\n", type);
+
+	if (type == 0) {
+		air_qos_setScheduleAlgo(0, port, queue, AIR_QOS_SCH_MODE_WRR,
+					1);
+	} else if (type == 1) {
+		air_qos_setScheduleAlgo(0, port, queue, AIR_QOS_SCH_MODE_SP, 1);
+	} else {
+		air_qos_setScheduleAlgo(0, port, queue, AIR_QOS_SCH_MODE_WFQ,
+					1);
+	}
+}
+
+void an8855_get_upw(unsigned int *value, unsigned char base)
+{
+	*value &= (~((0x7 << 0) | (0x7 << 4) | (0x7 << 8) | (0x7 << 12) |
+		     (0x7 << 16) | (0x7 << 20)));
+	switch (base) {
+	case 0:		/* port-based 0x2x40[18:16] */
+		*value |= ((0x2 << 0) | (0x2 << 4) | (0x2 << 8) |
+			   (0x2 << 12) | (0x7 << 16) | (0x2 << 20));
+		break;
+	case 1:		/* tagged-based 0x2x40[10:8] */
+		*value |= ((0x2 << 0) | (0x2 << 4) | (0x7 << 8) |
+			   (0x2 << 12) | (0x2 << 16) | (0x2 << 20));
+		break;
+	case 2:		/* DSCP-based 0x2x40[14:12] */
+		*value |= ((0x2 << 0) | (0x2 << 4) | (0x2 << 8) |
+			   (0x7 << 12) | (0x2 << 16) | (0x2 << 20));
+		break;
+	case 3:		/* acl-based 0x2x40[2:0] */
+		*value |= ((0x7 << 0) | (0x2 << 4) | (0x2 << 8) |
+			   (0x2 << 12) | (0x2 << 16) | (0x2 << 20));
+		break;
+	case 4:		/* arl-based 0x2x40[22:20] */
+		*value |= ((0x2 << 0) | (0x2 << 4) | (0x2 << 8) |
+			   (0x2 << 12) | (0x2 << 16) | (0x7 << 20));
+		break;
+	case 5:		/* stag-based 0x2x40[6:4] */
+		*value |= ((0x2 << 0) | (0x7 << 4) | (0x2 << 8) |
+			   (0x2 << 12) | (0x2 << 16) | (0x2 << 20));
+		break;
+	default:
+		break;
+	}
+}
+
+void an8855_qos_set_base(int argc, char *argv[])
+{
+	unsigned char base = 0;
+	unsigned char port;
+	unsigned int value;
+
+	if (argc < 5)
+		return;
+
+	port = _strtoul(argv[3], NULL, 10);
+	base = _strtoul(argv[4], NULL, 10);
+
+	if (base > 6) {
+		printf(HELP_QOS_BASE);
+		return;
+	}
+
+	if (port > 6) {
+		printf("Illegal port index:%d\n", port);
+		return;
+	}
+
+	printf("\r\nswitch qos base : %d. (port-based:0, tag-based:1,\
+		dscp-based:2, acl-based:3, arl-based:4, stag-based:5)\n", base);
+	reg_read(0x10208030 + 0x200 * port, &value);
+	an8855_get_upw(&value, base);
+	reg_write(0x10208030 + 0x200 * port, value);
+}
+
+void an8855_qos_wfq_set_weight(int argc, char *argv[])
+{
+	int port, weight[8], i;
+	unsigned char queue;
+	unsigned int reg = 0, value = 0;
+
+	port = _strtoul(argv[3], NULL, 10);
+
+	for (i = 0; i < 8; i++) {
+		weight[i] = _strtoul(argv[i + 4], NULL, 10);
+	}
+
+	/* MT7530 total 7 port */
+	if (port < 0 || port > 6) {
+		printf(HELP_QOS_PORT_WEIGHT);
+		return;
+	}
+
+	for (i = 0; i < 8; i++) {
+		if (weight[i] < 1 || weight[i] > 16) {
+			printf(HELP_QOS_PORT_WEIGHT);
+			return;
+		}
+	}
+	printf("port: %x, q0: %x, q1: %x, q2: %x, q3: %x, \
+		q4: %x, q5: %x, q6: %x, q7: %x\n", port, weight[0], weight[1], weight[2], weight[3], weight[4], weight[5], weight[6], weight[7]);
+
+	for (queue = 0; queue < 8; queue++) {
+		air_qos_setScheduleAlgo(0, port, queue, AIR_QOS_SCH_MODE_WFQ,
+					weight[queue]);
+	}
+}
+
+void an8855_qos_set_portpri(int argc, char *argv[])
+{
+	unsigned char port = 0, prio = 0;
+	unsigned int value = 0;
+
+	port = _strtoul(argv[3], NULL, 10);
+	prio = _strtoul(argv[4], NULL, 10);
+
+	if (port >= 7 || prio > 7) {
+		printf(HELP_QOS_PORT_PRIO);
+		return;
+	}
+
+	air_qos_setPortPriority(0, port, prio);
+}
+
+void an8855_qos_set_dscppri(int argc, char *argv[])
+{
+	unsigned char prio = 0, dscp = 0, pim_n = 0, pim_offset = 0;
+	unsigned int reg = 0, value = 0;
+
+	dscp = _strtoul(argv[3], NULL, 10);
+	prio = _strtoul(argv[4], NULL, 10);
+
+	if (dscp > 63 || prio > 7) {
+		printf(HELP_QOS_DSCP_PRIO);
+		return;
+	}
+
+	air_qos_setDscp2Pri(0, dscp, prio);
+}
+
+void an8855_qos_pri_mapping_queue(int argc, char *argv[])
+{
+	unsigned char prio = 0, queue = 0, pem_n = 0, port = 0;
+	unsigned int reg = 0, value = 0;
+
+	if (argc < 6)
+		return;
+
+	port = _strtoul(argv[3], NULL, 10);
+	prio = _strtoul(argv[4], NULL, 10);
+	queue = _strtoul(argv[5], NULL, 10);
+
+	if (prio > 7 || queue > 7) {
+		printf(HELP_QOS_PRIO_QMAP);
+		return;
+	}
+
+	air_qos_setPri2Queue(0, prio, queue);
+}
+
+void an8855_doVlanSetPvid(int argc, char *argv[])
+{
+	unsigned char port = 0;
+	unsigned short pvid = 0;
+
+	port = _strtoul(argv[3], NULL, 10);
+	pvid = _strtoul(argv[4], NULL, 10);
+	/*Check the input parameters is right or not. */
+	if ((port >= SWITCH_MAX_PORT) || (pvid > MAX_VID_VALUE)) {
+		printf(HELP_VLAN_PVID);
+		return;
+	}
+
+	air_vlan_setPortPVID(0, port, pvid);
+
+	printf("port:%d pvid:%d,vlancap: max_port:%d maxvid:%d\r\n",
+	       port, pvid, SWITCH_MAX_PORT, MAX_VID_VALUE);
+}				/*end doVlanSetPvid */
+
+void an8855_doVlanSetVid(int argc, char *argv[])
+{
+	unsigned char index = 0;
+	unsigned char active = 0;
+	unsigned char portMap = 0;
+	unsigned char tagPortMap = 0;
+	unsigned short vid = 0;
+
+	unsigned char ivl_en = 0;
+	unsigned char fid = 0;
+	unsigned short stag = 0;
+	int i = 0;
+	AIR_VLAN_ENTRY_T vlan_entry = { 0 };
+
+	index = _strtoul(argv[3], NULL, 10);
+	active = _strtoul(argv[4], NULL, 10);
+	vid = _strtoul(argv[5], NULL, 10);
+
+	/*Check the input parameters is right or not. */
+	if ((index >= MAX_VLAN_RULE) || (vid >= 4096) || (active > ACTIVED)) {
+		printf(HELP_VLAN_VID);
+		return;
+	}
+
+	/*CPU Port is always the membership */
+	portMap = _strtoul(argv[6], NULL, 10);
+	tagPortMap = _strtoul(argv[7], NULL, 10);
+
+	printf("subcmd parameter argc = %d\r\n", argc);
+	if (argc >= 9) {
+		ivl_en = _strtoul(argv[8], NULL, 10);
+		if (argc >= 10) {
+			fid = _strtoul(argv[9], NULL, 10);
+			if (argc >= 11)
+				stag = _strtoul(argv[10], NULL, 10);
+		}
+	}
+
+	printf("index: %x, active: %x, vid: %x, portMap: %x, \
+		tagPortMap: %x, ivl_en: %x, fid: %x, stag: %x\n", index, active, vid, portMap, tagPortMap, ivl_en, fid, stag);
+
+	vlan_entry.valid = ! !active;
+	vlan_entry.vlan_entry_format.port_mem = portMap;
+	/* Total 6 ports */
+	for (i = 0; i < SWITCH_MAX_PORT; i++) {
+		if (tagPortMap & (1 << i))
+			vlan_entry.vlan_entry_format.eg_ctrl |= 0x2 << (i * 2);
+	}
+	vlan_entry.vlan_entry_format.ivl = ! !ivl_en;
+	vlan_entry.vlan_entry_format.fid = fid;
+	vlan_entry.vlan_entry_format.stag = stag;
+
+	_air_vlan_writeEntry(0, vid, &vlan_entry);
+
+	printf("index:%d active:%d vid:%d\r\n", index, active, vid);
+}				/*end doVlanSetVid */
+
+void an8855_doVlanSetAccFrm(int argc, char *argv[])
+{
+	unsigned char port = 0;
+	unsigned char type = 0;
+	AIR_VLAN_ACCEPT_FRAME_TYPE_T type_t = AIR_VLAN_ACCEPT_FRAME_TYPE_ALL;
+
+	port = _strtoul(argv[3], NULL, 10);
+	type = _strtoul(argv[4], NULL, 10);
+
+	printf("port: %d, type: %d\n", port, type);
+
+	/*Check the input parameters is right or not. */
+	if ((port > SWITCH_MAX_PORT) || (type > REG_PVC_ACC_FRM_RELMASK)) {
+		printf(HELP_VLAN_ACC_FRM);
+		return;
+	}
+
+	type_t = (AIR_VLAN_ACCEPT_FRAME_TYPE_T) type;
+	air_vlan_setPortAcceptFrameType(0, port, type_t);
+}				/*end doVlanSetAccFrm */
+
+void an8855_doVlanSetPortAttr(int argc, char *argv[])
+{
+	unsigned char port = 0;
+	unsigned char attr = 0;
+	AIR_VLAN_PORT_ATTR_T attr_t = AIR_VLAN_PORT_ATTR_USER_PORT;
+
+	port = _strtoul(argv[3], NULL, 10);
+	attr = _strtoul(argv[4], NULL, 10);
+
+	printf("port: %x, attr: %x\n", port, attr);
+
+	/*Check the input parameters is right or not. */
+	if (port > SWITCH_MAX_PORT || attr > 3) {
+		printf(HELP_VLAN_PORT_ATTR);
+		return;
+	}
+
+	attr_t = (AIR_VLAN_PORT_ATTR_T) attr;
+	air_vlan_setPortAttr(0, port, attr_t);
+}
+
+void an8855_doVlanSetPortMode(int argc, char *argv[])
+{
+	unsigned char port = 0;
+	unsigned char mode = 0;
+	AIR_PORT_VLAN_MODE_T mode_t = AIR_PORT_VLAN_MODE_PORT_MATRIX;
+
+	port = _strtoul(argv[3], NULL, 10);
+	mode = _strtoul(argv[4], NULL, 10);
+	printf("port: %x, mode: %x\n", port, mode);
+
+	/*Check the input parameters is right or not. */
+	if (port > SWITCH_MAX_PORT || mode > 3) {
+		printf(HELP_VLAN_PORT_MODE);
+		return;
+	}
+
+	mode_t = (AIR_PORT_VLAN_MODE_T) mode;
+	air_port_setVlanMode(0, port, mode_t);
+}
+
+void an8855_doVlanSetEgressTagPCR(int argc, char *argv[])
+{
+	unsigned char port = 0;
+	unsigned char eg_tag = 0;
+	AIR_PORT_EGS_TAG_ATTR_T eg_tag_t = AIR_PORT_EGS_TAG_ATTR_UNTAGGED;
+
+	port = _strtoul(argv[3], NULL, 10);
+	eg_tag = _strtoul(argv[4], NULL, 10);
+
+	printf("port: %d, eg_tag: %d\n", port, eg_tag);
+
+	/*Check the input parameters is right or not. */
+	if ((port > SWITCH_MAX_PORT) || (eg_tag > REG_PCR_EG_TAG_RELMASK)) {
+		printf(HELP_VLAN_EGRESS_TAG_PCR);
+		return;
+	}
+
+	eg_tag_t = (AIR_PORT_EGS_TAG_ATTR_T) eg_tag;
+	air_vlan_setPortEgsTagAttr(0, port, eg_tag_t);
+}				/*end doVlanSetEgressTagPCR */
+
+void an8855_doVlanSetEgressTagPVC(int argc, char *argv[])
+{
+	unsigned char port = 0;
+	unsigned char eg_tag = 0;
+	AIR_IGR_PORT_EG_TAG_ATTR_T eg_tag_t = 0;
+
+	port = _strtoul(argv[3], NULL, 10);
+	eg_tag = _strtoul(argv[4], NULL, 10);
+
+	printf("port: %d, eg_tag: %d\n", port, eg_tag);
+
+	/*Check the input parameters is right or not. */
+	if ((port > SWITCH_MAX_PORT) || (eg_tag > REG_PVC_EG_TAG_RELMASK)) {
+		printf(HELP_VLAN_EGRESS_TAG_PVC);
+		return;
+	}
+
+	eg_tag_t = (AIR_IGR_PORT_EG_TAG_ATTR_T) eg_tag;
+	air_vlan_setIgrPortTagAttr(0, port, eg_tag_t);
+}				/*end doVlanSetEgressTagPVC */
+
+void an8855_doArlAging(int argc, char *argv[])
+{
+	unsigned char aging_en = 0;
+	unsigned int time = 0, port = 0;
+
+	aging_en = _strtoul(argv[3], NULL, 10);
+	time = _strtoul(argv[4], NULL, 10);
+	printf("aging_en: %x, aging time: %x\n", aging_en, time);
+
+	/*Check the input parameters is right or not. */
+	if ((aging_en != 0 && aging_en != 1) || (time <= 0 || time > 65536)) {
+		printf(HELP_ARL_AGING);
+		return;
+	}
+
+	for (port = 0; port < 6; port++) {
+		air_l2_setAgeEnable(0, port, aging_en);
+	}
+
+	air_l2_setMacAddrAgeOut(0, time);
+}
+
+void an8855_doMirrorEn(int argc, char *argv[])
+{
+	unsigned char mirror_en = 0;
+	unsigned char mirror_port = 0;
+	AIR_MIR_SESSION_T session = { 0 };
+
+	mirror_en = _strtoul(argv[3], NULL, 10);
+	mirror_port = _strtoul(argv[4], NULL, 10);
+
+	printf("mirror_en: %d, mirror_port: %d\n", mirror_en, mirror_port);
+
+	/*Check the input parameters is right or not. */
+	if ((mirror_en > 1) || (mirror_port > REG_CFC_MIRROR_PORT_RELMASK)) {
+		printf(HELP_MIRROR_EN);
+		return;
+	}
+
+	memset(&session, 0, sizeof(AIR_MIR_SESSION_T));
+
+	if (mirror_en) {
+		session.dst_port = mirror_port;
+		session.flags |= AIR_MIR_SESSION_FLAGS_ENABLE;
+		air_mir_addSession(0, 0, &session);
+	} else {
+		air_mir_delSession(0, 0);
+	}
+
+	air_mir_setSessionAdminMode(0, 0, (int)mirror_en);
+}				/*end doMirrorEn */
+
+void an8855_doMirrorPortBased(int argc, char *argv[])
+{
+	unsigned char port = 0, port_tx_mir = 0, port_rx_mir = 0, vlan_mis =
+	    0, acl_mir = 0, igmp_mir = 0;
+	unsigned int reg = 0, value = 0;
+	AIR_MIR_SESSION_T session = { 0 };
+
+	port = _strtoul(argv[3], NULL, 10);
+	port_tx_mir = _strtoul(argv[4], NULL, 10);
+	port_rx_mir = _strtoul(argv[5], NULL, 10);
+	acl_mir = _strtoul(argv[6], NULL, 10);
+	vlan_mis = _strtoul(argv[7], NULL, 10);
+	igmp_mir = _strtoul(argv[8], NULL, 10);
+
+	printf
+	    ("port:%d, port_tx_mir:%d, port_rx_mir:%d, acl_mir:%d, vlan_mis:%d, igmp_mir:%d\n",
+	     port, port_tx_mir, port_rx_mir, acl_mir, vlan_mis, igmp_mir);
+
+	/*Check the input parameters is right or not. */
+	//if((port >= vlanCap->max_port_no) || (port_tx_mir > 1) || (port_rx_mir > 1) || (acl_mir > 1) || (vlan_mis > 1)){
+	if ((port >= SWITCH_MAX_PORT) || (port_tx_mir > 1) || (port_rx_mir > 1) || (acl_mir > 1) || (vlan_mis > 1)) {	// also allow CPU port (port6)
+		printf(HELP_MIRROR_PORTBASED);
+		return;
+	}
+
+	memset(&session, 0, sizeof(AIR_MIR_SESSION_T));
+	air_mir_getSession(0, 0, &session);
+	session.src_port = port;
+
+	if (port_tx_mir)
+		session.flags |= AIR_MIR_SESSION_FLAGS_DIR_TX;
+	else
+		session.flags &= ~AIR_MIR_SESSION_FLAGS_DIR_TX;
+
+	if (port_rx_mir)
+		session.flags |= AIR_MIR_SESSION_FLAGS_DIR_RX;
+	else
+		session.flags &= ~AIR_MIR_SESSION_FLAGS_DIR_RX;
+
+	air_mir_setMirrorPort(0, 0, &session);
+
+	/*
+
+	   not support acl/vlan/igmp mismatch
+
+	 */
+}				/*end doMirrorPortBased */
+
+void an8855_doStp(int argc, char *argv[])
+{
+	unsigned char port = 0;
+	unsigned char fid = 0;
+	unsigned char state = 0;
+	unsigned int value = 0;
+	unsigned int reg = 0;
+
+	port = _strtoul(argv[2], NULL, 10);
+	fid = _strtoul(argv[3], NULL, 10);
+	state = _strtoul(argv[4], NULL, 10);
+
+	printf("port: %d, fid: %d, state: %d\n", port, fid, state);
+
+	/*Check the input parameters is right or not. */
+	if ((port > 5) || (fid > 16) || (state > 3)) {
+		printf(HELP_STP);
+		return;
+	}
+
+	air_stp_setPortstate(0, port, fid, state);
+}
+
+void _an8855_ingress_rate_set(int on_off, unsigned char port, unsigned int bw)
+{
+	AIR_ERROR_NO_T ret = AIR_E_OK;
+	AIR_QOS_RATE_LIMIT_CFG_T rl = { 0 };
+	if (on_off) {
+		ret =
+		    air_qos_setRateLimitEnable(0, port,
+					       AIR_QOS_RATE_DIR_INGRESS, TRUE);
+		if (AIR_E_OK != ret) {
+			printf("an8855 set ingress ratelimit eanble fail\n");
+			return;
+		}
+		rl.ingress_cir = bw;
+		rl.flags |= AIR_QOS_RATE_LIMIT_CFG_FLAGS_ENABLE_INGRESS;
+		ret = air_qos_setRateLimit(0, port, &rl);
+		if (AIR_E_OK != ret) {
+			printf("an8855 set ingress ratelimit value %d fail\n",
+			       bw);
+			return;
+		} else {
+			printf("an8855 set ingress ratelimit value %d ok\n",
+			       bw);
+		}
+	} else {
+		ret =
+		    air_qos_setRateLimitEnable(0, port,
+					       AIR_QOS_RATE_DIR_INGRESS, FALSE);
+		if (AIR_E_OK != ret) {
+			printf("an8855 set ingress ratelimit disable fail\n");
+			return;
+		} else {
+			printf("an8855 set ingress ratelimit disable ok\n");
+		}
+	}
+}
+
+void _an8855_egress_rate_set(int on_off, unsigned char port, unsigned int bw)
+{
+	AIR_ERROR_NO_T ret = AIR_E_OK;
+	AIR_QOS_RATE_LIMIT_CFG_T rl = { 0 };
+	if (on_off) {
+		ret =
+		    air_qos_setRateLimitEnable(0, port, AIR_QOS_RATE_DIR_EGRESS,
+					       TRUE);
+		if (AIR_E_OK != ret) {
+			printf("an8855 set egress ratelimit eanble fail\n");
+			return;
+		}
+		rl.egress_cir = bw;
+		rl.flags |= AIR_QOS_RATE_LIMIT_CFG_FLAGS_ENABLE_EGRESS;
+		ret = air_qos_setRateLimit(0, port, &rl);
+		if (AIR_E_OK != ret) {
+			printf("an8855 set egress ratelimit value %d fail\n",
+			       bw);
+			return;
+		} else {
+			printf("an8855 set egress ratelimit value %d ok\n", bw);
+		}
+	} else {
+		ret =
+		    air_qos_setRateLimitEnable(0, port, AIR_QOS_RATE_DIR_EGRESS,
+					       FALSE);
+		if (AIR_E_OK != ret) {
+			printf("an8855 set egress ratelimit disable fail\n");
+			return;
+		} else {
+			printf("an8855 set egress ratelimit disable ok\n");
+		}
+	}
+}
+
+void an8855_ingress_rate_set(int argc, char *argv[])
+{
+	int on_off = 0, port, bw = 0;
+
+	port = _strtoul(argv[3], NULL, 0);
+	if (argv[2][1] == 'n') {
+		bw = _strtoul(argv[4], NULL, 0);
+		on_off = 1;
+	} else if (argv[2][1] == 'f') {
+		if (argc != 4) {
+			return;
+		}
+		on_off = 0;
+	}
+
+	_an8855_ingress_rate_set(on_off, port, bw);
+}
+
+void an8855_egress_rate_set(int argc, char *argv[])
+{
+	unsigned int reg = 0, value = 0;
+	int on_off = 0, port = 0, bw = 0;
+
+	port = _strtoul(argv[3], NULL, 0);
+	if (argv[2][1] == 'n') {
+		bw = _strtoul(argv[4], NULL, 0);
+		on_off = 1;
+	} else if (argv[2][1] == 'f') {
+		if (argc != 4) {
+			return;
+		}
+		on_off = 0;
+	}
+
+	_an8855_egress_rate_set(on_off, port, bw);
+}
+
+void an8855_rate_control(int argc, char *argv[])
+{
+	unsigned char dir = 0;
+	unsigned char port = 0;
+	unsigned int rate_cir = 0;
+
+	dir = _strtoul(argv[2], NULL, 10);
+	port = _strtoul(argv[3], NULL, 10);
+	rate_cir = _strtoul(argv[4], NULL, 10);
+
+	if (port > 5) {
+		printf("Error, port %d is bigger than 5\n\r", port);
+		return;
+	}
+	if (rate_cir > 80000) {
+		printf("Error, rate_cir %d is bigger than 80000\n\r", rate_cir);
+		return;
+	}
+
+	if (dir == 1)		//ingress
+		_an8855_ingress_rate_set(1, port, rate_cir);
+	else if (dir == 0)	//egress
+		_an8855_egress_rate_set(1, port, rate_cir);
+	else
+		printf("Error, dir %d is not 1(ingress) and 0(egress)\n\r",
+		       dir);
+}
+
+void an8855_read_output_queue_counters(int argc, char *argv[])
+{
+	unsigned int port = 0;
+	unsigned int value = 0, output_queue = 0;
+
+	for (port = 0; port < 7; port++) {
+		reg_write(0x10207e48, 0x80000000 | (port << 8) | 0x0);
+		reg_read(0x10207e4c, &output_queue);
+		printf("\n port %d  output queue 0 counter is %d.\n", port,
+		       output_queue);
+		reg_write(0x10207e48, 0x80000000 | (port << 8) | 0x1);
+		reg_read(0x10207e4c, &output_queue);
+		printf("\n port %d  output queue 1 counter is %d.\n", port,
+		       output_queue);
+		reg_write(0x10207e48, 0x80000000 | (port << 8) | 0x2);
+		reg_read(0x10207e4c, &output_queue);
+		printf("\n port %d  output queue 2 counter is %d.\n", port,
+		       output_queue);
+		reg_write(0x10207e48, 0x80000000 | (port << 8) | 0x3);
+		reg_read(0x10207e4c, &output_queue);
+		printf("\n port %d  output queue 3 counter is %d.\n", port,
+		       output_queue);
+		reg_write(0x10207e48, 0x80000000 | (port << 8) | 0x4);
+		reg_read(0x10207e4c, &output_queue);
+		printf("\n port %d  output queue 4 counter is %d.\n", port,
+		       output_queue);
+		reg_write(0x10207e48, 0x80000000 | (port << 8) | 0x5);
+		reg_read(0x10207e4c, &output_queue);
+		printf("\n port %d  output queue 5 counter is %d.\n", port,
+		       output_queue);
+		reg_write(0x10207e48, 0x80000000 | (port << 8) | 0x6);
+		reg_read(0x10207e4c, &output_queue);
+		printf("\n port %d  output queue 6 counter is %d.\n", port,
+		       output_queue);
+		reg_write(0x10207e48, 0x80000000 | (port << 8) | 0x7);
+		reg_read(0x10207e4c, &output_queue);
+		printf("\n port %d  output queue 7 counter is %d.\n", port,
+		       output_queue);
+	}
+}
+
+void an8855_read_free_page_counters(int argc, char *argv[])
+{
+	unsigned int value = 0;
+	unsigned int free_page = 0, free_page_min = 0;
+	unsigned int fc_free_blk_lothd = 0, fc_free_blk_hithd = 0;
+	unsigned int fc_port_blk_thd = 0, fc_port_blk_hi_thd = 0;
+	unsigned int queue[8] = { 0 };
+
+	/* get system free page link counter */
+	reg_read(0x10207e00, &value);
+	free_page = value & 0xFFF;
+	free_page_min = (value & 0xFFF0000) >> 16;
+
+	/* get system flow control waterwark */
+	reg_read(0x10207e04, &value);
+	fc_free_blk_lothd = value & 0x3FF;
+	fc_free_blk_hithd = (value & 0x1FF8000) >> 15;
+
+	/* get port flow control waterwark */
+	reg_read(0x10207e08, &value);
+	fc_port_blk_thd = (value & 0xFF00) >> 8;
+	fc_port_blk_hi_thd = (value & 0xFF0000) >> 16;
+
+	/* get queue flow control waterwark */
+	reg_read(0x10207e10, &value);
+	queue[0] = value & 0x3F;
+	queue[1] = (value & 0x3F00) >> 8;
+	queue[2] = (value & 0x3F0000) >> 16;
+	queue[3] = (value & 0x3F000000) >> 24;
+	reg_read(0x10207e0c, &value);
+	queue[4] = value & 0x3F;
+	queue[5] = (value & 0x3F00) >> 8;
+	queue[6] = (value & 0x3F0000) >> 16;
+	queue[7] = (value & 0x3F000000) >> 24;
+
+	printf("<===Free Page=======Current============Minimal=========> \n ");
+	printf("	                                                 \n ");
+	printf(" page counter      %u                %u               \n ",
+	       free_page, free_page_min);
+	printf("                                                        \n ");
+	printf("========================================================= \n ");
+	printf("<===Type=======High threshold======Low threshold=========\n ");
+	printf("                                                        \n ");
+	printf("  system:         %u                 %u               \n",
+	       fc_free_blk_hithd * 2, fc_free_blk_lothd * 2);
+	printf("    port:         %u                 %u               \n",
+	       fc_port_blk_hi_thd * 2, fc_port_blk_thd * 2);
+	printf(" queue 0:         %u                 NA                \n",
+	       queue[0]);
+	printf(" queue 1:         %u                 NA                \n",
+	       queue[1]);
+	printf(" queue 2:         %u                 NA                 \n",
+	       queue[2]);
+	printf(" queue 3:         %u                 NA                \n",
+	       queue[3]);
+	printf(" queue 4:         %u                 NA                \n",
+	       queue[4]);
+	printf(" queue 5:         %u                 NA                \n",
+	       queue[5]);
+	printf(" queue 6:         %u                 NA                \n",
+	       queue[6]);
+	printf(" queue 7:         %u                 NA                \n",
+	       queue[7]);
+	printf("=========================================================\n ");
+}
+
+void an8855_eee_enable(int argc, char *argv[])
+{
+	unsigned long enable = 0;
+	unsigned int value, mode = 0;
+	unsigned int eee_cap = 0;
+	unsigned int eee_en_bitmap = 0;
+	unsigned long port_map = 0;
+	long port_num = -1;
+	int p = 0;
+
+	if (argc < 3)
+		goto error;
+
+	/* Check the input parameters is right or not. */
+	if (!strncmp(argv[2], "enable", 7))
+		enable = 1;
+	else if (!strncmp(argv[2], "disable", 8))
+		enable = 0;
+	else
+		goto error;
+
+	if (argc > 3) {
+		if (strlen(argv[3]) == 1) {
+			port_num = strtol(argv[3], (char **)NULL, 10);
+			if (port_num < 0 || port_num > MAX_PHY_PORT - 1) {
+				printf("Illegal port index and port:0~4\n");
+				goto error;
+			}
+			port_map = 1 << port_num;
+		} else if (strlen(argv[3]) == 5) {
+			port_map = 0;
+			for (p = 0; p < MAX_PHY_PORT; p++) {
+				if (argv[3][p] != '0' && argv[3][p] != '1') {
+					printf
+					    ("portmap format error, should be combination of 0 or 1\n");
+					goto error;
+				}
+				port_map |= ((argv[3][p] - '0') << p);
+			}
+		} else {
+			printf
+			    ("port_no or portmap format error, should be length of 1 or 5\n");
+			goto error;
+		}
+	} else {
+		port_map = 0x1f;
+	}
+
+	for (port_num = 0; port_num < MAX_PHY_PORT; port_num++) {
+		if (port_map & (1 << port_num)) {
+			air_port_getPsMode(0, port_num, &mode);
+			if (enable) {
+				mode |= AIR_PORT_PS_EEE;
+			} else {
+				mode &= ~AIR_PORT_PS_EEE;
+			}
+			air_port_setPsMode(0, port_num, mode);
+		}
+	}
+	return;
+
+error:
+	printf(HELP_EEE_EN);
+	return;
+}
+
+void an8855_eee_dump(int argc, char *argv[])
+{
+	unsigned int cap = 0, lp_cap = 0;
+	long port = -1;
+	int p = 0;
+
+	if (argc > 3) {
+		if (strlen(argv[3]) > 1) {
+			printf("port# format error, should be of length 1\n");
+			return;
+		}
+
+		port = strtol(argv[3], (char **)NULL, 0);
+		if (port < 0 || port > MAX_PHY_PORT) {
+			printf("port# format error, should be 0 to %d\n",
+			       MAX_PHY_PORT);
+			return;
+		}
+	}
+
+	for (p = 0; p < MAX_PHY_PORT; p++) {
+		if (port >= 0 && p != port)
+			continue;
+
+		mii_mgr_c45_read(p, 0x7, 0x3c, &cap);
+		mii_mgr_c45_read(p, 0x7, 0x3d, &lp_cap);
+		printf("port%d EEE cap=0x%02x, link partner EEE cap=0x%02x",
+		       p, cap, lp_cap);
+
+		if (port >= 0 && p == port) {
+			mii_mgr_c45_read(p, 0x3, 0x1, &cap);
+			printf(", st=0x%03x", cap);
+		}
+		printf("\n");
+	}
+}
+
+void an8855_read_mib_counters(int argc, char *argv[])
+{
+	int port = 0;
+	AIR_MIB_CNT_RX_T rx_mib[7];
+	AIR_MIB_CNT_TX_T tx_mib[7];
+
+	printf("===================== %8s %8s %8s %8s %8s %8s %8s\n",
+	       "Port0", "Port1", "Port2", "Port3", "Port4", "Port5", "Port6");
+
+	for (port = 0; port < 7; port++) {
+		air_mib_get(0, port, &rx_mib[port], &tx_mib[port]);
+	}
+
+	printf("Tx Drop Packet      :");
+	for (port = 0; port < 7; port++) {
+		printf("%8u ", tx_mib[port].TDPC);
+	}
+	printf("\n");
+	printf("Tx CRC Error        :");
+	for (port = 0; port < 7; port++) {
+		printf("%8u ", tx_mib[port].TCRC);
+	}
+	printf("\n");
+	printf("Tx Unicast Packet   :");
+	for (port = 0; port < 7; port++) {
+		printf("%8u ", tx_mib[port].TUPC);
+	}
+	printf("\n");
+	printf("Tx Multicast Packet :");
+	for (port = 0; port < 7; port++) {
+		printf("%8u ", tx_mib[port].TMPC);
+	}
+	printf("\n");
+	printf("Tx Broadcast Packet :");
+	for (port = 0; port < 7; port++) {
+		printf("%8u ", tx_mib[port].TBPC);
+	}
+	printf("\n");
+	printf("Tx Collision Event  :");
+	for (port = 0; port < 7; port++) {
+		printf("%8u ", tx_mib[port].TCEC);
+	}
+	printf("\n");
+	printf("Tx Pause Packet     :");
+	for (port = 0; port < 7; port++) {
+		printf("%8u ", tx_mib[port].TPPC);
+	}
+	printf("\n");
+	printf("Rx Drop Packet      :");
+	for (port = 0; port < 7; port++) {
+		printf("%8u ", rx_mib[port].RDPC);
+	}
+	printf("\n");
+	printf("Rx Filtering Packet :");
+	for (port = 0; port < 7; port++) {
+		printf("%8u ", rx_mib[port].RFPC);
+	}
+	printf("\n");
+	printf("Rx Unicast Packet   :");
+	for (port = 0; port < 7; port++) {
+		printf("%8u ", rx_mib[port].RUPC);
+	}
+	printf("\n");
+	printf("Rx Multicast Packet :");
+	for (port = 0; port < 7; port++) {
+		printf("%8u ", rx_mib[port].RMPC);
+	}
+	printf("\n");
+	printf("Rx Broadcast Packet :");
+	for (port = 0; port < 7; port++) {
+		printf("%8u ", rx_mib[port].RBPC);
+	}
+	printf("\n");
+	printf("Rx Alignment Error  :");
+	for (port = 0; port < 7; port++) {
+		printf("%8u ", rx_mib[port].RAEPC);
+	}
+	printf("\n");
+	printf("Rx CRC Error	    :");
+	for (port = 0; port < 7; port++) {
+		printf("%8u ", rx_mib[port].RCEPC);
+	}
+	printf("\n");
+	printf("Rx Undersize Error  :");
+	for (port = 0; port < 7; port++) {
+		printf("%8u ", rx_mib[port].RUSPC);
+	}
+	printf("\n");
+	printf("Rx Fragment Error   :");
+	for (port = 0; port < 7; port++) {
+		printf("%8u ", rx_mib[port].RFEPC);
+	}
+	printf("\n");
+	printf("Rx Oversize Error   :");
+	for (port = 0; port < 7; port++) {
+		printf("%8u ", rx_mib[port].ROSPC);
+	}
+	printf("\n");
+	printf("Rx Jabber Error     :");
+	for (port = 0; port < 7; port++) {
+		printf("%8u ", rx_mib[port].RJEPC);
+	}
+	printf("\n");
+	printf("Rx Pause Packet     :");
+	for (port = 0; port < 7; port++) {
+		printf("%8u ", rx_mib[port].RPPC);
+	}
+	printf("\n");
+}
+
+void an8855_clear_mib_counters(int argc, char *argv[])
+{
+	air_mib_clear(0);
+}
diff --git a/recipes-devtools/switch/files/src/switch_fun_an8855.h b/recipes-devtools/switch/files/src/switch_fun_an8855.h
new file mode 100644
index 0000000..1d67080
--- /dev/null
+++ b/recipes-devtools/switch/files/src/switch_fun_an8855.h
@@ -0,0 +1,134 @@
+/*
+* switch_fun.h: switch function sets
+*/
+#ifndef SWITCH_FUN_AN8855_H
+#define SWITCH_FUN_AN8855_H
+
+#include "air.h"
+
+AIR_ERROR_NO_T
+an8855_reg_read(const UI32_T unit, const UI32_T addr_offset, UI32_T * ptr_data);
+
+AIR_ERROR_NO_T
+an8855_reg_write(const UI32_T unit,
+		 const UI32_T addr_offset, const UI32_T data);
+
+AIR_ERROR_NO_T
+an8855_phy_cl22_read(const UI32_T unit,
+		     const UI32_T port_id,
+		     const UI32_T addr_offset, UI32_T * ptr_data);
+
+AIR_ERROR_NO_T
+an8855_phy_cl22_write(const UI32_T unit,
+		      const UI32_T port_id,
+		      const UI32_T addr_offset, const UI32_T data);
+
+AIR_ERROR_NO_T
+an8855_phy_cl45_read(const UI32_T unit,
+		     const UI32_T port_id,
+		     const UI32_T dev_type,
+		     const UI32_T addr_offset, UI32_T * ptr_data);
+
+AIR_ERROR_NO_T
+an8855_phy_cl45_write(const UI32_T unit,
+		      const UI32_T port_id,
+		      const UI32_T dev_type,
+		      const UI32_T addr_offset, const UI32_T data);
+
+/*arl setting*/
+void an8855_doArlAging(int argc, char *argv[]);
+
+void an8855_not_supported(int argc, char *argv[]);
+
+#if 0
+/*acl setting*/
+void an8855_acl_mac_add(int argc, char *argv[]);
+void an8855_acl_dip_meter(int argc, char *argv[]);
+void an8855_acl_dip_trtcm(int argc, char *argv[]);
+void an8855_acl_ethertype(int argc, char *argv[]);
+void an8855_acl_ethertype(int argc, char *argv[]);
+void an8855_acl_dip_modify(int argc, char *argv[]);
+void an8855_acl_dip_pppoe(int argc, char *argv[]);
+void an8855_acl_dip_add(int argc, char *argv[]);
+void an8855_acl_l4_add(int argc, char *argv[]);
+void an8855_acl_sp_add(int argc, char *argv[]);
+
+void an8855_acl_port_enable(int argc, char *argv[]);
+void an8855_acl_table_add(int argc, char *argv[]);
+void an8855_acl_mask_table_add(int argc, char *argv[]);
+void an8855_acl_rule_table_add(int argc, char *argv[]);
+void an8855_acl_rate_table_add(int argc, char *argv[]);
+
+/*dip table*/
+void an8855_dip_dump(void);
+void an8855_dip_add(int argc, char *argv[]);
+void an8855_dip_del(int argc, char *argv[]);
+void an8855_dip_clear(void);
+
+/*sip table*/
+void an8855_sip_dump(void);
+void an8855_sip_add(int argc, char *argv[]);
+void an8855_sip_del(int argc, char *argv[]);
+void an8855_sip_clear(void);
+#endif
+
+/*stp*/
+void an8855_doStp(int argc, char *argv[]);
+
+/*mac table*/
+void an8855_table_dump(int argc, char *argv[]);
+void an8855_table_add(int argc, char *argv[]);
+void an8855_table_search_mac_vid(int argc, char *argv[]);
+void an8855_table_search_mac_fid(int argc, char *argv[]);
+void an8855_table_del_fid(int argc, char *argv[]);
+void an8855_table_del_vid(int argc, char *argv[]);
+void an8855_table_clear(int argc, char *argv[]);
+
+/*vlan table*/
+void an8855_vlan_dump(int argc, char *argv[]);
+void an8855_vlan_clear(int argc, char *argv[]);
+void an8855_vlan_set(int argc, char *argv[]);
+
+void an8855_doVlanSetPvid(int argc, char *argv[]);
+void an8855_doVlanSetVid(int argc, char *argv[]);
+void an8855_doVlanSetAccFrm(int argc, char *argv[]);
+void an8855_doVlanSetPortAttr(int argc, char *argv[]);
+void an8855_doVlanSetPortMode(int argc, char *argv[]);
+void an8855_doVlanSetEgressTagPCR(int argc, char *argv[]);
+void an8855_doVlanSetEgressTagPVC(int argc, char *argv[]);
+
+/*mirror function*/
+void an8855_set_mirror_to(int argc, char *argv[]);
+void an8855_set_mirror_from(int argc, char *argv[]);
+void an8855_doMirrorPortBased(int argc, char *argv[]);
+void an8855_doMirrorEn(int argc, char *argv[]);
+
+/*rate control*/
+void an8855_rate_control(int argc, char *argv[]);
+void an8855_ingress_rate_set(int argc, char *argv[]);
+void an8855_egress_rate_set(int argc, char *argv[]);
+
+/*QoS*/
+void an8855_qos_sch_select(int argc, char *argv[]);
+void an8855_qos_set_base(int argc, char *argv[]);
+void an8855_qos_wfq_set_weight(int argc, char *argv[]);
+void an8855_qos_set_portpri(int argc, char *argv[]);
+void an8855_qos_set_dscppri(int argc, char *argv[]);
+void an8855_qos_pri_mapping_queue(int argc, char *argv[]);
+
+/*flow control*/
+void an8855_global_set_mac_fc(int argc, char *argv[]);
+
+/*switch reset*/
+void an8855_switch_reset(int argc, char *argv[]);
+
+/* EEE(802.3az) function  */
+void an8855_eee_enable(int argc, char *argv[]);
+void an8855_eee_dump(int argc, char *argv[]);
+
+void an8855_read_mib_counters(int argc, char *argv[]);
+void an8855_clear_mib_counters(int argc, char *argv[]);
+void an8855_read_output_queue_counters(int argc, char *argv[]);
+void an8855_read_free_page_counters(int argc, char *argv[]);
+
+#endif
diff --git a/recipes-devtools/switch/files/src/switch_ioctl.c b/recipes-devtools/switch/files/src/switch_ioctl.c
index 366079e..f6b97d4 100644
--- a/recipes-devtools/switch/files/src/switch_ioctl.c
+++ b/recipes-devtools/switch/files/src/switch_ioctl.c
@@ -235,24 +235,18 @@
 	mii.reg_num = 13;
 	mii.val_in = dev;
 	ret = ioctl(sk, method, &ifr);
-	if (ret < 0)
-		printf("ioctl failed with error %d\n", ret);
 
 	method = RAETH_MII_WRITE;
 	mii.phy_id = port_num;
 	mii.reg_num = 14;
 	mii.val_in = reg;
 	ret = ioctl(sk, method, &ifr);
-	if (ret < 0)
-		printf("ioctl failed with error %d\n", ret);
 
 	method = RAETH_MII_WRITE;
 	mii.phy_id = port_num;
 	mii.reg_num = 13;
 	mii.val_in = (0x6000 | dev);
 	ret = ioctl(sk, method, &ifr);
-	if (ret < 0)
-		printf("ioctl failed with error %d\n", ret);
 
 	usleep(1000);
 
@@ -260,8 +254,6 @@
 	mii.phy_id = port_num;
 	mii.reg_num = 14;
 	ret = ioctl(sk, method, &ifr);
-	if (ret < 0)
-		printf("ioctl failed with error %d\n", ret);
 
 	close(sk);
 	*value = mii.val_out;
@@ -291,24 +283,18 @@
 	mii.reg_num = 13;
 	mii.val_in = dev;
 	ret = ioctl(sk, method, &ifr);
-	if (ret < 0)
-		printf("ioctl failed with error %d\n", ret);
 
 	method = RAETH_MII_WRITE;
 	mii.phy_id = port_num;
 	mii.reg_num = 14;
 	mii.val_in = reg;
 	ret = ioctl(sk, method, &ifr);
-	if (ret < 0)
-		printf("ioctl failed with error %d\n", ret);
 
 	method = RAETH_MII_WRITE;
 	mii.phy_id = port_num;
 	mii.reg_num = 13;
 	mii.val_in = (0x6000 | dev);
 	ret = ioctl(sk, method, &ifr);
-	if (ret < 0)
-		printf("ioctl failed with error %d\n", ret);
 
 	usleep(1000);
 
@@ -317,8 +303,6 @@
 	mii.reg_num = 14;
 	mii.val_in = value;
 	ret = ioctl(sk, method, &ifr);
-	if (ret < 0)
-		printf("ioctl failed with error %d\n", ret);
 
 	close(sk);
 
diff --git a/recipes-devtools/switch/files/src/switch_netlink.c b/recipes-devtools/switch/files/src/switch_netlink.c
index 90a4a19..397ebe5 100644
--- a/recipes-devtools/switch/files/src/switch_netlink.c
+++ b/recipes-devtools/switch/files/src/switch_netlink.c
@@ -41,10 +41,9 @@
 	if (gnlh->cmd == MT753X_CMD_REPLY) {
 		if (attrs[MT753X_ATTR_TYPE_MESG]) {
 			val->dev_info =
-				nla_get_string(attrs[MT753X_ATTR_TYPE_MESG]);
+			    nla_get_string(attrs[MT753X_ATTR_TYPE_MESG]);
 			printf("register switch dev:\n%s", val->dev_info);
-		}
-		else {
+		} else {
 			fprintf(stderr, "ERROR:No switch dev now\n");
 			goto done;
 		}
@@ -65,13 +64,15 @@
 
 	if (val->op == 'r') {
 		if (val->phy_dev != -1)
-			NLA_PUT_U32(msg, MT753X_ATTR_TYPE_PHY_DEV, val->phy_dev);
+			NLA_PUT_U32(msg, MT753X_ATTR_TYPE_PHY_DEV,
+				    val->phy_dev);
 		if (val->port_num >= 0)
 			NLA_PUT_U32(msg, MT753X_ATTR_TYPE_PHY, val->port_num);
 		NLA_PUT_U32(msg, type, val->reg);
 	} else if (val->op == 'w') {
 		if (val->phy_dev != -1)
-			NLA_PUT_U32(msg, MT753X_ATTR_TYPE_PHY_DEV, val->phy_dev);
+			NLA_PUT_U32(msg, MT753X_ATTR_TYPE_PHY_DEV,
+				    val->phy_dev);
 		if (val->port_num >= 0)
 			NLA_PUT_U32(msg, MT753X_ATTR_TYPE_PHY, val->port_num);
 		NLA_PUT_U32(msg, type, val->reg);
@@ -104,15 +105,12 @@
 				goto done;
 		}
 		if (attrs[MT753X_ATTR_TYPE_REG]) {
-			val->reg =
-			    nla_get_u32(attrs[MT753X_ATTR_TYPE_REG]);
+			val->reg = nla_get_u32(attrs[MT753X_ATTR_TYPE_REG]);
 		}
 		if (attrs[MT753X_ATTR_TYPE_VAL]) {
-			val->value =
-			    nla_get_u32(attrs[MT753X_ATTR_TYPE_VAL]);
+			val->value = nla_get_u32(attrs[MT753X_ATTR_TYPE_VAL]);
 		}
-	}
-	else
+	} else
 		goto done;
 
 	return 0;
@@ -120,7 +118,8 @@
 	return NL_SKIP;
 }
 
-static int mt753x_request_callback(int cmd, int (*spilt)(struct nl_msg *, void *),
+static int mt753x_request_callback(int cmd,
+				   int (*spilt)(struct nl_msg *, void *),
 				   int (*construct)(struct nl_msg *, void *),
 				   void *arg)
 {
@@ -130,7 +129,7 @@
 	int flags = 0;
 	int err;
 
-	/*Allocate an netllink message buffer*/
+	/* Allocate an netllink message buffer */
 	msg = nlmsg_alloc();
 	if (!msg) {
 		fprintf(stderr, "Failed to allocate netlink message\n");
@@ -145,7 +144,7 @@
 	genlmsg_put(msg, NL_AUTO_PID, NL_AUTO_SEQ, genl_family_get_id(family),
 		    0, flags, cmd, 0);
 
-	/*Fill attaribute of netlink message by construct function*/
+	/* Fill attaribute of netlink message by construct function */
 	if (construct) {
 		err = construct(msg, arg);
 		if (err < 0) {
@@ -154,14 +153,14 @@
 		}
 	}
 
-	/*Allocate an new callback handler*/
+	/* Allocate an new callback handler */
 	callback = nl_cb_alloc(NL_CB_CUSTOM);
 	if (!callback) {
 		fprintf(stderr, "Failed to allocate callback handler\n");
 		exit(1);
 	}
 
-	/*Send netlink message*/
+	/* Send netlink message */
 	err = nl_send_auto_complete(user_sock, msg);
 	if (err < 0) {
 		fprintf(stderr, "nl_send_auto_complete failied:%d\n", err);
@@ -178,12 +177,12 @@
 		nl_cb_set(callback, NL_CB_FINISH, NL_CB_CUSTOM, wait_handler,
 			  &finished);
 
-	/*receive message from kernel request*/
+	/* Receive message from kernel request */
 	err = nl_recvmsgs(user_sock, callback);
 	if (err < 0)
 		goto out;
 
-	/*wait until an ACK is received for the latest not yet acknowledge*/
+	/* Wait until an ACK is received for the latest not yet acknowledge */
 	if (!finished)
 		err = nl_wait_for_ack(user_sock);
 out:
@@ -216,18 +215,18 @@
 	cache = NULL;
 	family = NULL;
 
-	/*Allocate an new netlink socket*/
+	/* Allocate an new netlink socket */
 	user_sock = nl_socket_alloc();
 	if (!user_sock) {
 		fprintf(stderr, "Failed to create user socket\n");
 		goto err;
 	}
-	/*Connetct the genl controller*/
+	/* Connetct the genl controller */
 	if (genl_connect(user_sock)) {
 		fprintf(stderr, "Failed to connetct to generic netlink\n");
 		goto err;
 	}
-	/*Allocate an new nl_cache*/
+	/* Allocate an new nl_cache */
 	ret = genl_ctrl_alloc_cache(user_sock, &cache);
 	if (ret < 0) {
 		fprintf(stderr, "Failed to allocate netlink cache\n");
@@ -237,10 +236,10 @@
 	if (name == NULL)
 		return -EINVAL;
 
-	/*Look up generic netlik family by "mt753x" in the provided cache*/
+	/* Look up generic netlik family by "mt753x" in the provided cache */
 	family = genl_ctrl_search_by_name(cache, name);
 	if (!family) {
-		//fprintf(stderr,"switch(mt753x) API not be prepared\n");
+		/* printf("switch(mt753x) API not be prepared\n"); */
 		goto err;
 	}
 	return 0;
@@ -283,20 +282,19 @@
 	attr->value = -1;
 	attr->type = MT753X_ATTR_TYPE_REG;
 
-	switch (op)
-	{
-		case 'r':
-			attr->op = 'r';
-			ret = mt753x_request(attr, MT753X_CMD_READ);
-			*value = attr->value;
-			break;
-		case 'w':
-			attr->op = 'w';
-			attr->value = *value;
-			ret = mt753x_request(attr, MT753X_CMD_WRITE);
-			break;
-		default:
-			break;
+	switch (op) {
+	case 'r':
+		attr->op = 'r';
+		ret = mt753x_request(attr, MT753X_CMD_READ);
+		*value = attr->value;
+		break;
+	case 'w':
+		attr->op = 'w';
+		attr->value = *value;
+		ret = mt753x_request(attr, MT753X_CMD_WRITE);
+		break;
+	default:
+		break;
 	}
 
 	return ret;
@@ -354,60 +352,66 @@
 {
 	int ret;
 
-	ret = phy_operate_netlink('w', arg, port_num, phy_dev, phy_addr, &value);
+	ret =
+	    phy_operate_netlink('w', arg, port_num, phy_dev, phy_addr, &value);
 	return ret;
 }
 
 void dump_extend_phy_reg(struct mt753x_attr *arg, int port_no, int from,
-			int to, int is_local, int page_no)
+			 int to, int is_local, int page_no)
 {
-        unsigned int temp = 0;
-        int r31 = 0;
-        int i = 0;
+	unsigned int temp = 0;
+	int r31 = 0;
+	int i = 0;
 
-        if (is_local == 0) {
-            printf("\n\nGlobal Register Page %d\n",page_no);
-            printf("===============");
-            r31 |= 0 << 15; //global
-            r31 |= ((page_no&0x7) << 12); //page no
-            phy_cl22_write_netlink(arg, port_no, 31, r31); //select global page x
-            for (i = 16; i < 32; i++) {
-                if(i%8 == 0)
-                    printf("\n");
-		phy_cl22_read_netlink(arg, port_no, i, &temp);
-                printf("%02d: %04X ", i, temp);
-            }
-        } else {
-            printf("\n\nLocal Register Port %d Page %d\n",port_no, page_no);
-            printf("===============");
-            r31 |= 1 << 15; //local
-            r31 |= ((page_no&0x7) << 12); //page no
-            phy_cl22_write_netlink(arg, port_no, 31, r31); //select global page x
-            for (i = 16; i < 32; i++) {
-                if (i%8 == 0) {
-                    printf("\n");
-                }
-		phy_cl22_read_netlink(arg, port_no, i, &temp);
-                printf("%02d: %04X ",i, temp);
-            }
-        }
-        printf("\n");
+	if (is_local == 0) {
+		printf("\n\nGlobal Register Page %d\n", page_no);
+		printf("===============");
+		r31 |= 0 << 15;	/* global */
+		r31 |= ((page_no & 0x7) << 12);	/* page no */
+		phy_cl22_write_netlink(arg, port_no, 31, r31);	/* select global page x */
+		for (i = 16; i < 32; i++) {
+			if (i % 8 == 0)
+				printf("\n");
+			phy_cl22_read_netlink(arg, port_no, i, &temp);
+			printf("%02d: %04X ", i, temp);
+		}
+	} else {
+		printf("\n\nLocal Register Port %d Page %d\n", port_no,
+		       page_no);
+		printf("===============");
+		r31 |= 1 << 15;	/* Local */
+		r31 |= ((page_no & 0x7) << 12);	/* Page no */
+		phy_cl22_write_netlink(arg, port_no, 31, r31);	/* Select global page x */
+		for (i = 16; i < 32; i++) {
+			if (i % 8 == 0)
+				printf("\n");
+			phy_cl22_read_netlink(arg, port_no, i, &temp);
+			printf("%02d: %04X ", i, temp);
+		}
+	}
+	printf("\n");
 }
 
 int phy_dump_netlink(struct mt753x_attr *arg, int phy_addr)
 {
 	int i;
 	int ret;
-	unsigned int offset, value;
+	unsigned int offset, value, phy_base = 0;
+
+	if (chip_name == 0x8855)
+		phy_base = 6;
 
 	if (phy_addr == 32) {
-		/*dump all phy register*/
+		/* Dump all phy register */
 		for (i = 0; i < 5; i++) {
 			printf("\n[Port %d]=============", i);
 			for (offset = 0; offset < 16; offset++) {
 				if (offset % 8 == 0)
 					printf("\n");
-				ret = phy_cl22_read_netlink(arg, i, offset, &value);
+				ret =
+				    phy_cl22_read_netlink(arg, phy_base + i,
+							  offset, &value);
 				printf("%02d: %04X ", offset, value);
 			}
 		}
@@ -416,30 +420,32 @@
 		for (offset = 0; offset < 16; offset++) {
 			if (offset % 8 == 0)
 				printf("\n");
-			ret = phy_cl22_read_netlink(arg, phy_addr, offset, &value);
+			ret =
+			    phy_cl22_read_netlink(arg, phy_addr, offset,
+						  &value);
 			printf("%02d: %04X ", offset, value);
 		}
 	}
 	printf("\n");
-	for (offset = 0; offset < 5; offset++) { //global register  page 0~4
-		if (phy_addr == 32) //dump all phy register
+	for (offset = 0; offset < 5; offset++) {	/* Global register  page 0~4 */
+		if (phy_addr == 32)	/* Dump all phy register */
 			dump_extend_phy_reg(arg, 0, 16, 31, 0, offset);
 		else
 			dump_extend_phy_reg(arg, phy_addr, 16, 31, 0, offset);
 	}
 
-	if (phy_addr == 32) {	//dump all phy register
-		for (offset = 0; offset < 5; offset++) { //local register port 0-port4
-			dump_extend_phy_reg(arg, offset, 16, 31, 1, 0); //dump local page 0
-			dump_extend_phy_reg(arg, offset, 16, 31, 1, 1); //dump local page 1
-			dump_extend_phy_reg(arg, offset, 16, 31, 1, 2); //dump local page 2
-			dump_extend_phy_reg(arg, offset, 16, 31, 1, 3); //dump local page 3
+	if (phy_addr == 32) {	/* Dump all phy register */
+		for (offset = 0; offset < 5; offset++) {	/* Local register port 0-port4 */
+			dump_extend_phy_reg(arg, phy_base + offset, 16, 31, 1, 0);	/* Dump local page 0 */
+			dump_extend_phy_reg(arg, phy_base + offset, 16, 31, 1, 1);	/* Dump local page 1 */
+			dump_extend_phy_reg(arg, phy_base + offset, 16, 31, 1, 2);	/* Dump local page 2 */
+			dump_extend_phy_reg(arg, phy_base + offset, 16, 31, 1, 3);	/* Dump local page 3 */
 		}
 	} else {
-		dump_extend_phy_reg(arg, phy_addr, 16, 31, 1, 0); //dump local page 0
-		dump_extend_phy_reg(arg, phy_addr, 16, 31, 1, 1); //dump local page 1
-		dump_extend_phy_reg(arg, phy_addr, 16, 31, 1, 2); //dump local page 2
-		dump_extend_phy_reg(arg, phy_addr, 16, 31, 1, 3); //dump local page 3
+		dump_extend_phy_reg(arg, phy_addr, 16, 31, 1, 0);	/* Dump local page 0 */
+		dump_extend_phy_reg(arg, phy_addr, 16, 31, 1, 1);	/* Dump local page 1 */
+		dump_extend_phy_reg(arg, phy_addr, 16, 31, 1, 2);	/* Dump local page 2 */
+		dump_extend_phy_reg(arg, phy_addr, 16, 31, 1, 3);	/* Dump local page 3 */
 	}
 	return ret;
 }
diff --git a/recipes-devtools/switch/files/src/switch_netlink.h b/recipes-devtools/switch/files/src/switch_netlink.h
index b3f946e..cb812d5 100644
--- a/recipes-devtools/switch/files/src/switch_netlink.h
+++ b/recipes-devtools/switch/files/src/switch_netlink.h
@@ -9,12 +9,14 @@
 #define MT753X_GENL_NAME "mt753x"
 #define MT753X_DSA_GENL_NAME "mt753x_dsa"
 #define MT753X_GENL_VERSION 0X1
+#define AN8855_GENL_NAME "an8855"
+#define AN8855_DSA_GENL_NAME "an8855_dsa"
 
 /*add your cmd to here*/
 enum {
-	MT753X_CMD_UNSPEC = 0, /*Reserved*/
-	MT753X_CMD_REQUEST,    /*user->kernelrequest/get-response*/
-	MT753X_CMD_REPLY,      /*kernel->user event*/
+	MT753X_CMD_UNSPEC = 0,	/*Reserved */
+	MT753X_CMD_REQUEST,	/*user->kernelrequest/get-response */
+	MT753X_CMD_REPLY,	/*kernel->user event */
 	MT753X_CMD_READ,
 	MT753X_CMD_WRITE,
 	__MT753X_CMD_MAX,
@@ -22,10 +24,9 @@
 #define MT753X_CMD_MAX (__MT753X_CMD_MAX - 1)
 
 /*define attar types */
-enum
-{
+enum {
 	MT753X_ATTR_TYPE_UNSPEC = 0,
-	MT753X_ATTR_TYPE_MESG, /*MT753X message*/
+	MT753X_ATTR_TYPE_MESG,	/*MT753X message */
 	MT753X_ATTR_TYPE_PHY,
 	MT753X_ATTR_TYPE_PHY_DEV,
 	MT753X_ATTR_TYPE_REG,
@@ -48,6 +49,8 @@
 	int dev_id;
 };
 
+extern int chip_name;
+
 int mt753x_netlink_init(const char *name);
 void mt753x_netlink_free(void);
 void mt753x_list_swdev(struct mt753x_attr *arg, int cmd);
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/backport-5.4.inc b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/backport-5.4.inc
index 69688ff..4a3ac15 100644
--- a/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/backport-5.4.inc
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/backport-5.4.inc
@@ -299,10 +299,5 @@
     file://900-v5.9-0001-dt-bindings-Add-multicolor-class-dt-bindings-documen.patch \
     file://900-v5.9-0002-leds-Add-multicolor-ID-to-the-color-ID-list.patch \
     file://900-v5.9-0003-leds-add-RGB-color-option-as-that-is-different-from-.patch \
-    file://999-2360-v5.16-spi-add-power-control-when-set_cs.patch \
-    file://999-2700-v5.7-iopoll-introduce-read_poll_timeout-macro.patch \
-    file://999-2701-v5.8-net-phy-add-concept-of-shared-storage-for-PHYs.patch \
-    file://999-2702-v5.9-net-phy-add-support-for-a-common-probe-between-shared-PHYs.patch;apply=no \
-    file://999-2703-net-phy-backport-v5.4-mediatek-ge-and-v6.4-mediatek-ge-soc.patch \
     file://999-update-uapi-header-files-for-bridger.patch \
     "
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/hack-5.4/hack-5.4.inc b/recipes-kernel/linux/linux-mediatek-5.4/generic/hack-5.4/hack-5.4.inc
index 11b86e3..17e6307 100644
--- a/recipes-kernel/linux/linux-mediatek-5.4/generic/hack-5.4/hack-5.4.inc
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/hack-5.4/hack-5.4.inc
@@ -41,5 +41,4 @@
     file://910-kobject_uevent.patch \
     file://911-kobject_add_broadcast_uevent.patch \
     file://921-always-create-console-node-in-initramfs.patch \
-    file://999-2540-cmdline-boot-parameters.patch \
     "
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/pending-5.4.inc b/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/pending-5.4.inc
index af11131..ccbdcff 100644
--- a/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/pending-5.4.inc
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/pending-5.4.inc
@@ -120,7 +120,4 @@
     file://834-ledtrig-libata.patch \
     file://840-hwrng-bcm2835-set-quality-to-1000.patch \
     file://920-mangle_bootargs.patch \
-    file://999-2328-mtd-add-nmbm-support.patch \
-    file://999-2329-ubi-add-configurable-rootdev.patch \
-    file://999-2704-netfilter_optional_tcp_window_check.patch \
     "
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7981-spim-nand-2500wan-an8855-gsw.dts b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7981-spim-nand-2500wan-an8855-gsw.dts
new file mode 100644
index 0000000..3f0bb90
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7981-spim-nand-2500wan-an8855-gsw.dts
@@ -0,0 +1,295 @@
+/dts-v1/;
+#include "mt7981.dtsi"
+/ {
+	model = "MediaTek MT7981 RFB";
+	compatible = "mediatek,mt7981-spim-snand-2500wan-an8855-gsw-rfb";
+	chosen {
+		bootargs = "console=ttyS0,115200n1 loglevel=8  \
+				earlycon=uart8250,mmio32,0x11002000";
+	};
+
+	memory {
+		// fpga ddr2: 128MB*2
+		reg = <0 0x40000000 0 0x10000000>;
+	};
+
+	gpio-keys {
+			compatible = "gpio-keys";
+				reset {
+					label = "reset";
+					linux,code = <KEY_RESTART>;
+					gpios = <&pio 1 GPIO_ACTIVE_LOW>;
+				};
+
+				wps {
+					label = "wps";
+					linux,code = <KEY_WPS_BUTTON>;
+					gpios = <&pio 0 GPIO_ACTIVE_HIGH>;
+				};
+	};
+
+	nmbm_spim_nand {
+		compatible = "generic,nmbm";
+
+		#address-cells = <1>;
+		#size-cells = <1>;
+
+		lower-mtd-device = <&spi_nand>;
+		forced-create;
+
+		partitions {
+			compatible = "fixed-partitions";
+			#address-cells = <1>;
+			#size-cells = <1>;
+
+			partition@0 {
+				label = "BL2";
+				reg = <0x00000 0x0100000>;
+				read-only;
+			};
+
+			partition@100000 {
+				label = "u-boot-env";
+				reg = <0x0100000 0x0080000>;
+			};
+
+			factory: partition@180000 {
+				label = "Factory";
+				reg = <0x180000 0x0200000>;
+			};
+
+			partition@380000 {
+				label = "FIP";
+				reg = <0x380000 0x0200000>;
+			};
+
+			partition@580000 {
+				label = "ubi";
+				reg = <0x580000 0x4000000>;
+			};
+		};
+	};
+
+	gsw: gsw@0 {
+		compatible = "airoha,an8855";
+		#mediatek,ethsys = <&ethsys>;
+		#address-cells = <1>;
+		#size-cells = <0>;
+	};
+};
+
+&uart0 {
+	status = "okay";
+};
+
+&watchdog {
+	status = "okay";
+};
+
+&eth {
+	status = "okay";
+
+	gmac0: mac@0 {
+		compatible = "mediatek,eth-mac";
+		reg = <0>;
+		phy-mode = "2500base-x";
+
+		fixed-link {
+			speed = <2500>;
+			full-duplex;
+			pause;
+		};
+	};
+
+	gmac1: mac@1 {
+		compatible = "mediatek,eth-mac";
+		reg = <1>;
+		phy-mode = "2500base-x";
+		phy-handle = <&phy5>;
+	};
+
+	mdio: mdio-bus {
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		reset-gpios = <&pio 14 1>;
+		reset-delay-us = <600>;
+
+		phy5: phy@5 {
+			compatible = "ethernet-phy-ieee802.3-c45";
+			reg = <5>;
+		};
+	};
+};
+
+&gsw {
+	airoha,mdio = <&mdio>;
+	airoha,portmap = "llllw";
+	airoha,smi-addr = <6>;
+	reset-gpios = <&pio 39 0>;
+	interrupt-parent = <&pio>;
+	interrupts = <38 IRQ_TYPE_LEVEL_HIGH>;
+	status = "okay";
+
+	port5: port@5 {
+		compatible = "airoha,an8855-port";
+		reg = <5>;
+		phy-mode = "2500base-x";
+		/* airoha,stag-on = <1>; */
+
+		fixed-link {
+			speed = <2500>;
+			full-duplex;
+		};
+	};
+};
+
+&hnat {
+	mtketh-wan = "eth1";
+	mtketh-lan = "eth0";
+	mtketh-max-gmac = <2>;
+	status = "okay";
+};
+
+&spi0 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&spi0_flash_pins>;
+	status = "okay";
+	spi_nand: spi_nand@0 {
+		#address-cells = <1>;
+		#size-cells = <1>;
+		compatible = "spi-nand";
+		spi-cal-enable;
+		spi-cal-mode = "read-data";
+		spi-cal-datalen = <7>;
+		spi-cal-data = /bits/ 8 <0x53 0x50 0x49 0x4E 0x41 0x4E 0x44>;
+		spi-cal-addrlen = <5>;
+		spi-cal-addr = /bits/ 32 <0x0 0x0 0x0 0x0 0x0>;
+		reg = <0>;
+		spi-max-frequency = <52000000>;
+		spi-tx-bus-width = <4>;
+		spi-rx-bus-width = <4>;
+	};
+};
+
+&spi1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&spic_pins>;
+	status = "disabled";
+
+	slb9670: slb9670@0 {
+		compatible = "infineon,slb9670";
+		reg = <0>; /* CE0 */
+		#address-cells = <1>;
+		#size-cells = <0>;
+		spi-cal-enable;
+		spi-cal-mode = "read-data";
+		spi-cal-datalen = <2>;
+		spi-cal-data = /bits/ 8 <0x00 0x1b>;
+		spi-max-frequency = <20000000>;
+	};
+};
+
+&wbsys {
+	mediatek,mtd-eeprom = <&factory 0x0000>;
+	status = "okay";
+	pinctrl-names = "dbdc";
+	pinctrl-0 = <&wf_dbdc_pins>;
+};
+
+&pio {
+
+	i2c_pins: i2c-pins-g0 {
+		mux {
+			function = "i2c";
+			groups = "i2c0_0";
+		};
+	};
+
+	pcm_pins: pcm-pins-g0 {
+		mux {
+			function = "pcm";
+			groups = "pcm";
+		};
+	};
+
+	pwm0_pin: pwm0-pin-g0 {
+		mux {
+			function = "pwm";
+			groups = "pwm0_0";
+		};
+	};
+
+	pwm1_pin: pwm1-pin-g0 {
+		mux {
+			function = "pwm";
+			groups = "pwm1_0";
+		};
+	};
+
+	pwm2_pin: pwm2-pin {
+		mux {
+			function = "pwm";
+			groups = "pwm2";
+		};
+	};
+
+	spi0_flash_pins: spi0-pins {
+		mux {
+			function = "spi";
+			groups = "spi0", "spi0_wp_hold";
+		};
+
+		conf-pu {
+			pins = "SPI0_CS", "SPI0_HOLD", "SPI0_WP";
+			drive-strength = <MTK_DRIVE_8mA>;
+			bias-pull-up = <MTK_PUPD_SET_R1R0_11>;
+		};
+
+		conf-pd {
+			pins = "SPI0_CLK", "SPI0_MOSI", "SPI0_MISO";
+			drive-strength = <MTK_DRIVE_8mA>;
+			bias-pull-down = <MTK_PUPD_SET_R1R0_11>;
+		};
+	};
+
+	spic_pins: spi1-pins {
+		mux {
+			function = "spi";
+			groups = "spi1_1";
+		};
+	};
+
+	uart1_pins: uart1-pins-g1 {
+		mux {
+			function = "uart";
+			groups = "uart1_1";
+		};
+	};
+
+	uart2_pins: uart2-pins-g1 {
+		mux {
+			function = "uart";
+			groups = "uart2_1";
+		};
+	};
+
+	wf_dbdc_pins: wf_dbdc-pins {
+		mux {
+			function = "eth";
+			groups = "wf0_mode1";
+		};
+		conf {
+			pins = "WF_HB1", "WF_HB2", "WF_HB3", "WF_HB4",
+			       "WF_HB0", "WF_HB0_B", "WF_HB5", "WF_HB6",
+			       "WF_HB7", "WF_HB8", "WF_HB9", "WF_HB10",
+			       "WF_TOP_CLK", "WF_TOP_DATA", "WF_XO_REQ",
+			       "WF_CBA_RESETB", "WF_DIG_RESETB";
+			drive-strength = <MTK_DRIVE_4mA>;
+		};
+	};
+};
+
+&xhci {
+	status = "okay";
+};
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7981-spim-nand-2500wan-an8855.dts b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7981-spim-nand-2500wan-an8855.dts
new file mode 100644
index 0000000..4697ef5
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7981-spim-nand-2500wan-an8855.dts
@@ -0,0 +1,310 @@
+/dts-v1/;
+#include "mt7981.dtsi"
+/ {
+	model = "MediaTek MT7981 RFB";
+	compatible = "mediatek,mt7981-spim-snand-2500wan-an8855-rfb";
+	chosen {
+		bootargs = "console=ttyS0,115200n1 loglevel=8  \
+				earlycon=uart8250,mmio32,0x11002000";
+	};
+
+	memory {
+		// fpga ddr2: 128MB*2
+		reg = <0 0x40000000 0 0x10000000>;
+	};
+
+	gpio-keys {
+			compatible = "gpio-keys";
+				reset {
+					label = "reset";
+					linux,code = <KEY_RESTART>;
+					gpios = <&pio 1 GPIO_ACTIVE_LOW>;
+				};
+
+				wps {
+					label = "wps";
+					linux,code = <KEY_WPS_BUTTON>;
+					gpios = <&pio 0 GPIO_ACTIVE_HIGH>;
+				};
+	};
+
+	nmbm_spim_nand {
+		compatible = "generic,nmbm";
+
+		#address-cells = <1>;
+		#size-cells = <1>;
+
+		lower-mtd-device = <&spi_nand>;
+		forced-create;
+
+		partitions {
+			compatible = "fixed-partitions";
+			#address-cells = <1>;
+			#size-cells = <1>;
+
+			partition@0 {
+				label = "BL2";
+				reg = <0x00000 0x0100000>;
+				read-only;
+			};
+
+			partition@100000 {
+				label = "u-boot-env";
+				reg = <0x0100000 0x0080000>;
+			};
+
+			factory: partition@180000 {
+				label = "Factory";
+				reg = <0x180000 0x0200000>;
+			};
+
+			partition@380000 {
+				label = "FIP";
+				reg = <0x380000 0x0200000>;
+			};
+
+			partition@580000 {
+				label = "ubi";
+				reg = <0x580000 0x4000000>;
+			};
+		};
+	};
+};
+
+&uart0 {
+	status = "okay";
+};
+
+&watchdog {
+	status = "okay";
+};
+
+&eth {
+	status = "okay";
+
+	gmac0: mac@0 {
+		compatible = "mediatek,eth-mac";
+		reg = <0>;
+		phy-mode = "2500base-x";
+
+		fixed-link {
+			speed = <2500>;
+			full-duplex;
+			pause;
+		};
+	};
+
+	gmac1: mac@1 {
+		compatible = "mediatek,eth-mac";
+		reg = <1>;
+		phy-mode = "2500base-x";
+		phy-handle = <&phy5>;
+	};
+
+	mdio: mdio-bus {
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		reset-gpios = <&pio 14 1>;
+		reset-delay-us = <600>;
+
+		phy5: phy@5 {
+			compatible = "ethernet-phy-ieee802.3-c45";
+			reg = <5>;
+		};
+
+		switch@0 {
+			compatible = "airoha,an8855";
+			reg = <1>;
+			reset-gpios = <&pio 39 0>;
+			changesmiaddr = <6>;
+			ports {
+				#address-cells = <1>;
+				#size-cells = <0>;
+
+				port@0 {
+					reg = <0>;
+					label = "lan1";
+				};
+
+				port@1 {
+					reg = <1>;
+					label = "lan2";
+				};
+
+				port@2 {
+					reg = <2>;
+					label = "lan3";
+				};
+
+				port@3 {
+					reg = <3>;
+					label = "lan4";
+				};
+
+				port@5 {
+					reg = <5>;
+					label = "cpu";
+					ethernet = <&gmac0>;
+					phy-mode = "2500base-x";
+
+					fixed-link {
+						speed = <2500>;
+						full-duplex;
+						pause;
+					};
+				};
+			};
+		};
+	};
+};
+
+&hnat {
+	mtketh-wan = "eth1";
+	mtketh-lan = "lan";
+	mtketh-max-gmac = <2>;
+	status = "okay";
+};
+
+&spi0 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&spi0_flash_pins>;
+	status = "okay";
+	spi_nand: spi_nand@0 {
+		#address-cells = <1>;
+		#size-cells = <1>;
+		compatible = "spi-nand";
+		spi-cal-enable;
+		spi-cal-mode = "read-data";
+		spi-cal-datalen = <7>;
+		spi-cal-data = /bits/ 8 <0x53 0x50 0x49 0x4E 0x41 0x4E 0x44>;
+		spi-cal-addrlen = <5>;
+		spi-cal-addr = /bits/ 32 <0x0 0x0 0x0 0x0 0x0>;
+		reg = <0>;
+		spi-max-frequency = <52000000>;
+		spi-tx-bus-width = <4>;
+		spi-rx-bus-width = <4>;
+	};
+};
+
+&spi1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&spic_pins>;
+	status = "disabled";
+
+	slb9670: slb9670@0 {
+		compatible = "infineon,slb9670";
+		reg = <0>; /* CE0 */
+		#address-cells = <1>;
+		#size-cells = <0>;
+		spi-cal-enable;
+		spi-cal-mode = "read-data";
+		spi-cal-datalen = <2>;
+		spi-cal-data = /bits/ 8 <0x00 0x1b>;
+		spi-max-frequency = <20000000>;
+	};
+};
+
+&wbsys {
+	mediatek,mtd-eeprom = <&factory 0x0000>;
+	status = "okay";
+	pinctrl-names = "dbdc";
+	pinctrl-0 = <&wf_dbdc_pins>;
+};
+
+&pio {
+
+	i2c_pins: i2c-pins-g0 {
+		mux {
+			function = "i2c";
+			groups = "i2c0_0";
+		};
+	};
+
+	pcm_pins: pcm-pins-g0 {
+		mux {
+			function = "pcm";
+			groups = "pcm";
+		};
+	};
+
+	pwm0_pin: pwm0-pin-g0 {
+		mux {
+			function = "pwm";
+			groups = "pwm0_0";
+		};
+	};
+
+	pwm1_pin: pwm1-pin-g0 {
+		mux {
+			function = "pwm";
+			groups = "pwm1_0";
+		};
+	};
+
+	pwm2_pin: pwm2-pin {
+		mux {
+			function = "pwm";
+			groups = "pwm2";
+		};
+	};
+
+	spi0_flash_pins: spi0-pins {
+		mux {
+			function = "spi";
+			groups = "spi0", "spi0_wp_hold";
+		};
+
+		conf-pu {
+			pins = "SPI0_CS", "SPI0_HOLD", "SPI0_WP";
+			drive-strength = <MTK_DRIVE_8mA>;
+			bias-pull-up = <MTK_PUPD_SET_R1R0_11>;
+		};
+
+		conf-pd {
+			pins = "SPI0_CLK", "SPI0_MOSI", "SPI0_MISO";
+			drive-strength = <MTK_DRIVE_8mA>;
+			bias-pull-down = <MTK_PUPD_SET_R1R0_11>;
+		};
+	};
+
+	spic_pins: spi1-pins {
+		mux {
+			function = "spi";
+			groups = "spi1_1";
+		};
+	};
+
+	uart1_pins: uart1-pins-g1 {
+		mux {
+			function = "uart";
+			groups = "uart1_1";
+		};
+	};
+
+	uart2_pins: uart2-pins-g1 {
+		mux {
+			function = "uart";
+			groups = "uart2_1";
+		};
+	};
+
+	wf_dbdc_pins: wf_dbdc-pins {
+		mux {
+			function = "eth";
+			groups = "wf0_mode1";
+		};
+		conf {
+			pins = "WF_HB1", "WF_HB2", "WF_HB3", "WF_HB4",
+			       "WF_HB0", "WF_HB0_B", "WF_HB5", "WF_HB6",
+			       "WF_HB7", "WF_HB8", "WF_HB9", "WF_HB10",
+			       "WF_TOP_CLK", "WF_TOP_DATA", "WF_XO_REQ",
+			       "WF_CBA_RESETB", "WF_DIG_RESETB";
+			drive-strength = <MTK_DRIVE_4mA>;
+		};
+	};
+};
+
+&xhci {
+	status = "okay";
+};
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7988.dtsi b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7988.dtsi
index 7e96640..0fd2d47 100644
--- a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7988.dtsi
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7988.dtsi
@@ -381,6 +381,7 @@
 		dma-names = "tnl-sync";
 
 		fe_mem = <&eth>;
+		hnat = <&hnat>;
 	};
 
 	tops-mbox {
@@ -584,6 +585,7 @@
 		interrupt-names = "ring0", "ring1", "ring2", "ring3";
 		status = "okay";
 		eth = <&eth>;
+		hnat = <&hnat>;
 	};
 
 	afe: audio-controller@11210000 {
@@ -864,8 +866,7 @@
 			 <&topckgen CK_TOP_NETSYS_SYNC_250M_SEL>,
 			 <&topckgen CK_TOP_NETSYS_PPEFB_250M_SEL>,
 			 <&topckgen CK_TOP_NETSYS_WARP_SEL>,
-			 <&topckgen CK_TOP_MACSEC_SEL>,
-			 <&topckgen CK_TOP_NETSYS_TOPS_400M_SEL>;
+			 <&topckgen CK_TOP_MACSEC_SEL>;
 		clock-names = "xgp1", "xgp2", "xgp3", "fe", "gp2", "gp1",
 			      "gp3", "esw", "crypto", "sgmii_tx250m",
 			      "sgmii_rx250m", "sgmii2_tx250m", "sgmii2_rx250m",
@@ -881,24 +882,21 @@
 			      "top_netsys_sync_250m_sel",
 			      "top_netsys_ppefb_250m_sel",
 			      "top_netsys_warp_sel",
-			      "top_macsec_sel",
-			      "macsec_bus_clk";
+			      "top_macsec_sel";
 		assigned-clocks = <&topckgen CK_TOP_NETSYS_2X_SEL>,
 				  <&topckgen CK_TOP_NETSYS_GSW_SEL>,
 				  <&topckgen CK_TOP_USXGMII_SBUS_0_SEL>,
 				  <&topckgen CK_TOP_USXGMII_SBUS_1_SEL>,
 				  <&topckgen CK_TOP_SGM_0_SEL>,
 				  <&topckgen CK_TOP_SGM_1_SEL>,
-				  <&topckgen CK_TOP_MACSEC_SEL>,
-				  <&topckgen CK_TOP_NETSYS_TOPS_400M_SEL>;
+				  <&topckgen CK_TOP_MACSEC_SEL>;
 		assigned-clock-parents = <&topckgen CK_TOP_CB_NET2_800M>,
 					 <&topckgen CK_TOP_CB_NET1_D4>,
 					 <&topckgen CK_TOP_NET1_D8_D4>,
 					 <&topckgen CK_TOP_NET1_D8_D4>,
 					 <&topckgen CK_TOP_CB_SGM_325M>,
 					 <&topckgen CK_TOP_CB_SGM_325M>,
-					 <&topckgen CK_TOP_CB_SGM_325M>,
-					 <&topckgen CK_TOP_CB_NET2_D2>;
+					 <&topckgen CK_TOP_CB_SGM_325M>;
 		mediatek,ethsys = <&ethsys>;
 		mediatek,sgmiisys = <&sgmiisys0>, <&sgmiisys1>;
 		mediatek,usxgmiisys = <&usxgmiisys0>, <&usxgmiisys1>;
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/misc/mediatek/Makefile b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/misc/mediatek/Makefile
index b725c38..f3f3692 100644
--- a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/misc/mediatek/Makefile
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/misc/mediatek/Makefile
@@ -1,2 +1,3 @@
 obj-$(CONFIG_MTK_ICE_DEBUG) += ice_debug/
 obj-y += infra_bus_prot/
+obj-y += reset-boot-count/
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/misc/mediatek/reset-boot-count/Makefile b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/misc/mediatek/reset-boot-count/Makefile
new file mode 100644
index 0000000..a8c3756
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/misc/mediatek/reset-boot-count/Makefile
@@ -0,0 +1,2 @@
+

+obj-y      := reset-boot-count.o

diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/misc/mediatek/reset-boot-count/reset-boot-count.c b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/misc/mediatek/reset-boot-count/reset-boot-count.c
new file mode 100644
index 0000000..2b82d89
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/misc/mediatek/reset-boot-count/reset-boot-count.c
@@ -0,0 +1,143 @@
+// SPDX-License-Identifier: BSD-3-Clause

+/*

+ * Copyright (C) 2024 MediaTek Inc. All rights reserved.

+ *

+ * Helper for resetting boot count of A/B boot systems

+ *

+ * Author: Weijie Gao <weijie.gao@mediatek.com>

+ */

+

+#include <linux/kernel.h>

+#include <linux/module.h>

+#include <linux/delay.h>

+#include <linux/init.h>

+#include <linux/proc_fs.h>

+#include <linux/seq_file.h>

+#include <linux/arm-smccc.h>

+

+#define RBC "reset_boot_count"

+

+#define MTK_SIP_READ_NONRST_REG			0xC2000550

+#define MTK_SIP_WRITE_NONRST_REG		0xC2000551

+

+static struct proc_dir_entry *rbc_entry;

+

+static bool dual_boot_get_boot_count(u32 *retslot, u32 *retcnt)

+{

+	struct arm_smccc_res res = {0};

+	u32 val, slot;

+	s8 neg, pos;

+

+	arm_smccc_smc(MTK_SIP_READ_NONRST_REG, 0, 0, 0, 0, 0, 0, 0, &res);

+

+	val = (u32)res.a0;

+

+	/* slot: val[31..24] = -slot, val[23..16] = slot */

+	pos = (val >> 16) & 0xff;

+	neg = (val >> 24) & 0xff;

+

+	if (!(pos >= 0 && neg <= 0 && pos + neg == 0)) {

+		pr_debug("slot of boot count is invalid\n");

+		goto err;

+	}

+

+	slot = pos;

+

+	/* count: val[15..8] = -count, val[7..0] = count */

+	pos = val & 0xff;

+	neg = (val >> 8) & 0xff;

+

+	if (!(pos >= 0 && neg <= 0 && pos + neg == 0)) {

+		pr_debug("count of boot count is invalid\n");

+		goto err;

+	}

+

+	if (retslot)

+		*retslot = slot;

+

+	if (retcnt)

+		*retcnt = pos;

+

+	return true;

+

+err:

+	if (retslot)

+		*retslot = 0;

+

+	if (retcnt)

+		*retcnt = 0;

+

+	return false;

+}

+

+static void dual_boot_set_boot_count(u32 slot, u32 count)

+{

+	struct arm_smccc_res res = {0};

+	u32 val;

+	s32 neg;

+

+	if (slot > 127 || count > 127)

+		return;

+

+	neg = -count;

+	val = count | ((neg << 8) & 0xff00);

+

+	neg = -slot;

+	val = val | ((uint32_t)slot << 16) | ((neg << 24) & 0xff000000);

+

+	arm_smccc_smc(MTK_SIP_WRITE_NONRST_REG, 0, val, 0, 0, 0, 0, 0, &res);

+}

+

+static int rbc_display(struct seq_file *seq, void *v)

+{

+	return 0;

+}

+

+static int rbc_open(struct inode *inode, struct file *file)

+{

+	return single_open(file, rbc_display, inode->i_private);

+}

+

+static ssize_t rbc_write(struct file *file, const char __user *buffer,

+			 size_t count, loff_t *pos)

+{

+	u32 slot;

+

+	dual_boot_get_boot_count(&slot, NULL);

+	dual_boot_set_boot_count(slot, 0);

+

+	pr_info("Boot count reset\n");

+

+	return count;

+}

+

+static const struct file_operations rbc_fops =

+{

+	.open  = rbc_open,

+	.read = seq_read,

+	.write = rbc_write,

+	.llseek  = seq_lseek,

+	.release = single_release,

+};

+

+static int __init rbc_init(void)

+{

+	rbc_entry = proc_create(RBC, 0200, NULL, &rbc_fops);

+

+	if (!rbc_entry)

+		pr_err("failed to create proc entry " RBC);

+

+	return 0;

+}

+

+static void __exit rbc_exit(void)

+{

+	remove_proc_entry(RBC, NULL);

+}

+

+module_init(rbc_init);

+module_exit(rbc_exit);

+

+MODULE_AUTHOR("Weijie Gao <weijie.gao@mediatek.com>");

+MODULE_DESCRIPTION("Kernel module for resetting boot count of A/B boot systems");

+MODULE_LICENSE("BSD");

diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/dsa/airoha/an8855/Kconfig b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/dsa/airoha/an8855/Kconfig
new file mode 100644
index 0000000..fc00f75
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/dsa/airoha/an8855/Kconfig
@@ -0,0 +1,10 @@
+
+config NET_DSA_AN8855
+	tristate "Airoha AN8855 Ethernet switch support"
+	depends on NET_DSA
+	select NET_DSA_TAG_AIROHA
+	help
+	  AN8855 support 2.5G speed and managed by SMI interface.
+	  This enables support for the Airoha AN8855 Ethernet switch
+	  chip.
+	  To compile this driver as a module, choose M here.
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/dsa/airoha/an8855/Makefile b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/dsa/airoha/an8855/Makefile
new file mode 100644
index 0000000..99c99bd
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/dsa/airoha/an8855/Makefile
@@ -0,0 +1,5 @@
+#
+# Makefile for Airoha AN8855 gigabit switch
+#
+obj-$(CONFIG_NET_DSA_AN8855)	+= an8855-dsa.o
+an8855-dsa-objs			:= an8855.o an8855_nl.o an8855_phy.o
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/dsa/airoha/an8855/an8855.c b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/dsa/airoha/an8855/an8855.c
new file mode 100644
index 0000000..b0ba4be
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/dsa/airoha/an8855/an8855.c
@@ -0,0 +1,2358 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Airoha AN8855 DSA Switch driver
+ * Copyright (C) 2023 Min Yao <min.yao@airoha.com>
+ */
+#include <linux/etherdevice.h>
+#include <linux/if_bridge.h>
+#include <linux/iopoll.h>
+#include <linux/mdio.h>
+#include <linux/mfd/syscon.h>
+#include <linux/module.h>
+#include <linux/netdevice.h>
+#include <linux/of_mdio.h>
+#include <linux/of_net.h>
+#include <linux/of_platform.h>
+#include <linux/phylink.h>
+#include <linux/regmap.h>
+#include <linux/regulator/consumer.h>
+#include <linux/reset.h>
+#include <linux/gpio/consumer.h>
+#include <net/dsa.h>
+#include <linux/of_address.h>
+
+#include "an8855.h"
+#include "an8855_nl.h"
+
+/* AN8855 driver version */
+#define ARHT_AN8855_DSA_DRIVER_VER	"1.0.1-L5.4"
+
+/* String, offset, and register size in bytes if different from 4 bytes */
+static const struct an8855_mib_desc an8855_mib[] = {
+	MIB_DESC(1, 0x00, "TxDrop"),
+	MIB_DESC(1, 0x04, "TxCrcErr"),
+	MIB_DESC(1, 0x08, "TxUnicast"),
+	MIB_DESC(1, 0x0c, "TxMulticast"),
+	MIB_DESC(1, 0x10, "TxBroadcast"),
+	MIB_DESC(1, 0x14, "TxCollision"),
+	MIB_DESC(1, 0x18, "TxSingleCollision"),
+	MIB_DESC(1, 0x1c, "TxMultipleCollision"),
+	MIB_DESC(1, 0x20, "TxDeferred"),
+	MIB_DESC(1, 0x24, "TxLateCollision"),
+	MIB_DESC(1, 0x28, "TxExcessiveCollistion"),
+	MIB_DESC(1, 0x2c, "TxPause"),
+	MIB_DESC(1, 0x30, "TxPktSz64"),
+	MIB_DESC(1, 0x34, "TxPktSz65To127"),
+	MIB_DESC(1, 0x38, "TxPktSz128To255"),
+	MIB_DESC(1, 0x3c, "TxPktSz256To511"),
+	MIB_DESC(1, 0x40, "TxPktSz512To1023"),
+	MIB_DESC(1, 0x44, "TxPktSz1024To1518"),
+	MIB_DESC(1, 0x48, "TxPktSz1519ToMax"),
+	MIB_DESC(2, 0x4c, "TxBytes"),
+	MIB_DESC(1, 0x54, "TxOversizeDrop"),
+	MIB_DESC(2, 0x58, "TxBadPktBytes"),
+	MIB_DESC(1, 0x80, "RxDrop"),
+	MIB_DESC(1, 0x84, "RxFiltering"),
+	MIB_DESC(1, 0x88, "RxUnicast"),
+	MIB_DESC(1, 0x8c, "RxMulticast"),
+	MIB_DESC(1, 0x90, "RxBroadcast"),
+	MIB_DESC(1, 0x94, "RxAlignErr"),
+	MIB_DESC(1, 0x98, "RxCrcErr"),
+	MIB_DESC(1, 0x9c, "RxUnderSizeErr"),
+	MIB_DESC(1, 0xa0, "RxFragErr"),
+	MIB_DESC(1, 0xa4, "RxOverSzErr"),
+	MIB_DESC(1, 0xa8, "RxJabberErr"),
+	MIB_DESC(1, 0xac, "RxPause"),
+	MIB_DESC(1, 0xb0, "RxPktSz64"),
+	MIB_DESC(1, 0xb4, "RxPktSz65To127"),
+	MIB_DESC(1, 0xb8, "RxPktSz128To255"),
+	MIB_DESC(1, 0xbc, "RxPktSz256To511"),
+	MIB_DESC(1, 0xc0, "RxPktSz512To1023"),
+	MIB_DESC(1, 0xc4, "RxPktSz1024To1518"),
+	MIB_DESC(1, 0xc8, "RxPktSz1519ToMax"),
+	MIB_DESC(2, 0xcc, "RxBytes"),
+	MIB_DESC(1, 0xd4, "RxCtrlDrop"),
+	MIB_DESC(1, 0xd8, "RxIngressDrop"),
+	MIB_DESC(1, 0xdc, "RxArlDrop"),
+	MIB_DESC(1, 0xe0, "FlowControlDrop"),
+	MIB_DESC(1, 0xe4, "WredDrop"),
+	MIB_DESC(1, 0xe8, "MirrorDrop"),
+	MIB_DESC(2, 0xec, "RxBadPktBytes"),
+	MIB_DESC(1, 0xf4, "RxsFlowSamplingPktDrop"),
+	MIB_DESC(1, 0xf8, "RxsFlowTotalPktDrop"),
+	MIB_DESC(1, 0xfc, "PortControlDrop"),
+};
+
+static int
+an8855_mii_write(struct an8855_priv *priv, u32 reg, u32 val)
+{
+	struct mii_bus *bus = priv->bus;
+	int ret = 0;
+
+	ret = bus->write(bus, priv->phy_base, 0x1f, 0x4);
+	ret = bus->write(bus, priv->phy_base, 0x10, 0);
+
+	ret = bus->write(bus, priv->phy_base, 0x11, ((reg >> 16) & 0xFFFF));
+	ret = bus->write(bus, priv->phy_base, 0x12, (reg & 0xFFFF));
+
+	ret = bus->write(bus, priv->phy_base, 0x13, ((val >> 16) & 0xFFFF));
+	ret = bus->write(bus, priv->phy_base, 0x14, (val & 0xFFFF));
+
+	ret = bus->write(bus, priv->phy_base, 0x1f, 0);
+	ret = bus->write(bus, priv->phy_base, 0x10, 0);
+
+	if (ret < 0) {
+		dev_err(&bus->dev, "failed to write an8855 register\n");
+		return ret;
+	}
+
+	return ret;
+}
+
+static u32
+an8855_mii_read(struct an8855_priv *priv, u32 reg)
+{
+	struct mii_bus *bus = priv->bus;
+	u16 lo, hi;
+	int ret;
+
+	ret = bus->write(bus, priv->phy_base, 0x1f, 0x4);
+	ret = bus->write(bus, priv->phy_base, 0x10, 0);
+
+	ret = bus->write(bus, priv->phy_base, 0x15, ((reg >> 16) & 0xFFFF));
+	ret = bus->write(bus, priv->phy_base, 0x16, (reg & 0xFFFF));
+	if (ret < 0) {
+		dev_err(&bus->dev, "failed to read an8855 register\n");
+		return ret;
+	}
+
+	lo = bus->read(bus, priv->phy_base, 0x18);
+	hi = bus->read(bus, priv->phy_base, 0x17);
+
+	ret = bus->write(bus, priv->phy_base, 0x1f, 0);
+	ret = bus->write(bus, priv->phy_base, 0x10, 0);
+	if (ret < 0) {
+		dev_err(&bus->dev, "failed to read an8855 register\n");
+		return ret;
+	}
+
+	return (hi << 16) | (lo & 0xffff);
+}
+
+void
+an8855_write(struct an8855_priv *priv, u32 reg, u32 val)
+{
+	struct mii_bus *bus = priv->bus;
+
+	mutex_lock_nested(&bus->mdio_lock, MDIO_MUTEX_NESTED);
+
+	an8855_mii_write(priv, reg, val);
+
+	mutex_unlock(&bus->mdio_lock);
+}
+
+static u32
+_an8855_read(struct an8855_dummy_poll *p)
+{
+	struct mii_bus *bus = p->priv->bus;
+	u32 val;
+
+	mutex_lock_nested(&bus->mdio_lock, MDIO_MUTEX_NESTED);
+
+	val = an8855_mii_read(p->priv, p->reg);
+
+	mutex_unlock(&bus->mdio_lock);
+
+	return val;
+}
+
+u32
+an8855_read(struct an8855_priv *priv, u32 reg)
+{
+	struct an8855_dummy_poll p;
+
+	INIT_AN8855_DUMMY_POLL(&p, priv, reg);
+	return _an8855_read(&p);
+}
+
+static void
+an8855_rmw(struct an8855_priv *priv, u32 reg, u32 mask, u32 set)
+{
+	struct mii_bus *bus = priv->bus;
+	u32 val;
+
+	mutex_lock_nested(&bus->mdio_lock, MDIO_MUTEX_NESTED);
+
+	val = an8855_mii_read(priv, reg);
+	val &= ~mask;
+	val |= set;
+	an8855_mii_write(priv, reg, val);
+
+	mutex_unlock(&bus->mdio_lock);
+}
+
+static void
+an8855_set(struct an8855_priv *priv, u32 reg, u32 val)
+{
+	an8855_rmw(priv, reg, 0, val);
+}
+
+static void
+an8855_clear(struct an8855_priv *priv, u32 reg, u32 val)
+{
+	an8855_rmw(priv, reg, val, 0);
+}
+
+static int
+an8855_fdb_cmd(struct an8855_priv *priv, u32 cmd, u32 *rsp)
+{
+	u32 val;
+	int ret;
+	struct an8855_dummy_poll p;
+
+	/* Set the command operating upon the MAC address entries */
+	val = ATC_BUSY | cmd;
+	an8855_write(priv, AN8855_ATC, val);
+
+	INIT_AN8855_DUMMY_POLL(&p, priv, AN8855_ATC);
+	ret = readx_poll_timeout(_an8855_read, &p, val,
+				 !(val & ATC_BUSY), 20, 200000);
+	if (ret < 0) {
+		dev_err(priv->dev, "reset timeout\n");
+		return ret;
+	}
+
+	if (rsp)
+		*rsp = val;
+
+	return 0;
+}
+
+static void
+an8855_fdb_read(struct an8855_priv *priv, struct an8855_fdb *fdb)
+{
+	u32 reg[4];
+	int i;
+
+	/* Read from ARL table into an array */
+	for (i = 0; i < 4; i++)
+		reg[i] = an8855_read(priv, AN8855_ATRD0 + (i * 4));
+
+	fdb->live = reg[0] & 0x1;
+	fdb->type = (reg[0] >> 3) & 0x3;
+	fdb->ivl = (reg[0] >> 9) & 0x1;
+	fdb->vid = (reg[0] >> 10) & 0xfff;
+	fdb->fid = (reg[0] >> 25) & 0xf;
+	fdb->aging = (reg[1] >> 3) & 0x1ff;
+	fdb->port_mask = reg[3] & 0xff;
+	fdb->mac[0] = (reg[2] >> MAC_BYTE_0) & MAC_BYTE_MASK;
+	fdb->mac[1] = (reg[2] >> MAC_BYTE_1) & MAC_BYTE_MASK;
+	fdb->mac[2] = (reg[2] >> MAC_BYTE_2) & MAC_BYTE_MASK;
+	fdb->mac[3] = (reg[2] >> MAC_BYTE_3) & MAC_BYTE_MASK;
+	fdb->mac[4] = (reg[1] >> MAC_BYTE_4) & MAC_BYTE_MASK;
+	fdb->mac[5] = (reg[1] >> MAC_BYTE_5) & MAC_BYTE_MASK;
+	fdb->noarp = !!((reg[0] >> 1) & 0x3);
+}
+
+static void
+an8855_fdb_write(struct an8855_priv *priv, u16 vid,
+		 u8 port_mask, const u8 *mac, u8 add)
+{
+	u32 reg = 0;
+
+	reg |= mac[3] << MAC_BYTE_3;
+	reg |= mac[2] << MAC_BYTE_2;
+	reg |= mac[1] << MAC_BYTE_1;
+	reg |= mac[0] << MAC_BYTE_0;
+	an8855_write(priv, AN8855_ATA1, reg);
+	reg = 0;
+	reg |= mac[5] << MAC_BYTE_5;
+	reg |= mac[4] << MAC_BYTE_4;
+	an8855_write(priv, AN8855_ATA2, reg);
+	reg = 0;
+	if (add)
+		reg |= 0x1;
+	reg |= 0x1 << 15;
+	reg |= vid << 16;
+	an8855_write(priv, AN8855_ATWD, reg);
+	an8855_write(priv, AN8855_ATWD2, port_mask);
+}
+
+static int
+an8855_pad_setup(struct dsa_switch *ds, phy_interface_t interface)
+{
+	return 0;
+}
+
+static void
+an8855_mib_reset(struct dsa_switch *ds)
+{
+	struct an8855_priv *priv = ds->priv;
+
+	an8855_write(priv, AN8855_MIB_CCR, CCR_MIB_FLUSH);
+	an8855_write(priv, AN8855_MIB_CCR, CCR_MIB_ACTIVATE);
+}
+
+static int
+an8855_cl22_read(struct an8855_priv *priv, int port, int regnum)
+{
+	return mdiobus_read_nested(priv->bus, port, regnum);
+}
+
+static int
+an8855_cl22_write(struct an8855_priv *priv, int port, int regnum, u16 val)
+{
+	return mdiobus_write_nested(priv->bus, port, regnum, val);
+}
+
+static int
+an8855_phy_read(struct dsa_switch *ds, int port, int regnum)
+{
+	struct an8855_priv *priv = ds->priv;
+
+	port += priv->phy_base;
+	return an8855_cl22_read(ds->priv, port, regnum);
+}
+
+static int
+an8855_phy_write(struct dsa_switch *ds, int port, int regnum,
+			    u16 val)
+{
+	struct an8855_priv *priv = ds->priv;
+
+	port += priv->phy_base;
+	return an8855_cl22_write(ds->priv, port, regnum, val);
+}
+
+static int
+an8855_cl45_read(struct an8855_priv *priv, int port, int devad, int regnum)
+{
+	regnum = MII_ADDR_C45 | (devad << 16) | regnum;
+	return mdiobus_read_nested(priv->bus, port, regnum);
+}
+
+static int
+an8855_cl45_write(struct an8855_priv *priv, int port, int devad, int regnum,
+		      u16 val)
+{
+	regnum = MII_ADDR_C45 | (devad << 16) | regnum;
+	return mdiobus_write_nested(priv->bus, port, regnum, val);
+}
+
+int
+an8855_phy_cl22_read(struct an8855_priv *priv, int port, int regnum)
+{
+	port += priv->phy_base;
+	return an8855_cl22_read(priv, port, regnum);
+}
+
+int
+an8855_phy_cl22_write(struct an8855_priv *priv, int port, int regnum,
+			    u16 val)
+{
+	port += priv->phy_base;
+	return an8855_cl22_write(priv, port, regnum, val);
+}
+
+int
+an8855_phy_cl45_read(struct an8855_priv *priv, int port, int devad, int regnum)
+{
+	port += priv->phy_base;
+	return an8855_cl45_read(priv, port, devad, regnum);
+}
+
+int
+an8855_phy_cl45_write(struct an8855_priv *priv, int port, int devad, int regnum,
+		      u16 val)
+{
+	port += priv->phy_base;
+	return an8855_cl45_write(priv, port, devad, regnum, val);
+}
+
+static void
+an8855_get_strings(struct dsa_switch *ds, int port, u32 stringset,
+		   uint8_t *data)
+{
+	int i;
+
+	if (stringset != ETH_SS_STATS)
+		return;
+
+	for (i = 0; i < ARRAY_SIZE(an8855_mib); i++)
+		strncpy(data + i * ETH_GSTRING_LEN, an8855_mib[i].name,
+			ETH_GSTRING_LEN);
+}
+
+static void
+an8855_get_ethtool_stats(struct dsa_switch *ds, int port, uint64_t *data)
+{
+	struct an8855_priv *priv = ds->priv;
+	const struct an8855_mib_desc *mib;
+	u32 reg, i;
+	u64 hi;
+
+	for (i = 0; i < ARRAY_SIZE(an8855_mib); i++) {
+		mib = &an8855_mib[i];
+		reg = AN8855_PORT_MIB_COUNTER(port) + mib->offset;
+
+		data[i] = an8855_read(priv, reg);
+		if (mib->size == 2) {
+			hi = an8855_read(priv, reg + 4);
+			data[i] |= hi << 32;
+		}
+	}
+}
+
+static int
+an8855_get_sset_count(struct dsa_switch *ds, int port, int sset)
+{
+	if (sset != ETH_SS_STATS)
+		return 0;
+
+	return ARRAY_SIZE(an8855_mib);
+}
+
+static int
+an8855_cpu_port_enable(struct dsa_switch *ds, int port)
+{
+	struct an8855_priv *priv = ds->priv;
+
+	/* Setup max capability of CPU port at first */
+	if (priv->info->cpu_port_config)
+		priv->info->cpu_port_config(ds, port);
+
+	/* Enable Airoha header mode on the cpu port */
+	an8855_write(priv, AN8855_PVC_P(port),
+		     PORT_SPEC_REPLACE_MODE | PORT_SPEC_TAG);
+
+	/* Unknown multicast frame forwarding to the cpu port */
+	an8855_write(priv, AN8855_UNMF, BIT(port));
+
+	/* Set CPU port number */
+	an8855_rmw(priv, AN8855_MFC, CPU_MASK, CPU_EN | CPU_PORT(port));
+
+	/* CPU port gets connected to all user ports of
+	 * the switch.
+	 */
+	an8855_write(priv, AN8855_PORTMATRIX_P(port),
+		     PORTMATRIX_MATRIX(dsa_user_ports(priv->ds)));
+
+	return 0;
+}
+
+static int
+an8855_port_enable(struct dsa_switch *ds, int port, struct phy_device *phy)
+{
+	struct an8855_priv *priv = ds->priv;
+
+	if (!dsa_is_user_port(ds, port))
+		return 0;
+
+	mutex_lock(&priv->reg_mutex);
+
+	/* Allow the user port gets connected to the cpu port and also
+	 * restore the port matrix if the port is the member of a certain
+	 * bridge.
+	 */
+	priv->ports[port].pm |= PORTMATRIX_MATRIX(BIT(AN8855_CPU_PORT));
+	priv->ports[port].enable = true;
+	an8855_write(priv, AN8855_PORTMATRIX_P(port), priv->ports[port].pm);
+	an8855_clear(priv, AN8855_PMCR_P(port), PMCR_LINK_SETTINGS_MASK);
+
+	mutex_unlock(&priv->reg_mutex);
+
+	return 0;
+}
+
+static void
+an8855_port_disable(struct dsa_switch *ds, int port)
+{
+	struct an8855_priv *priv = ds->priv;
+
+	if (!dsa_is_user_port(ds, port))
+		return;
+
+	mutex_lock(&priv->reg_mutex);
+
+	/* Clear up all port matrix which could be restored in the next
+	 * enablement for the port.
+	 */
+	priv->ports[port].enable = false;
+	an8855_write(priv, AN8855_PORTMATRIX_P(port), PORTMATRIX_CLR);
+	an8855_clear(priv, AN8855_PMCR_P(port), PMCR_LINK_SETTINGS_MASK);
+
+	mutex_unlock(&priv->reg_mutex);
+}
+
+static void
+an8855_stp_state_set(struct dsa_switch *ds, int port, u8 state)
+{
+	struct an8855_priv *priv = ds->priv;
+	u32 stp_state;
+
+	if (dsa_is_unused_port(ds, port))
+		return;
+
+	switch (state) {
+	case BR_STATE_DISABLED:
+		stp_state = AN8855_STP_DISABLED;
+		break;
+	case BR_STATE_BLOCKING:
+		stp_state = AN8855_STP_BLOCKING;
+		break;
+	case BR_STATE_LISTENING:
+		stp_state = AN8855_STP_LISTENING;
+		break;
+	case BR_STATE_LEARNING:
+		stp_state = AN8855_STP_LEARNING;
+		break;
+	case BR_STATE_FORWARDING:
+	default:
+		stp_state = AN8855_STP_FORWARDING;
+		break;
+	}
+
+	an8855_rmw(priv, AN8855_SSP_P(port), FID_PST_MASK, stp_state);
+}
+
+static int
+an8855_port_bridge_join(struct dsa_switch *ds, int port,
+			struct net_device *bridge)
+{
+	struct an8855_priv *priv = ds->priv;
+	u32 port_bitmap = BIT(AN8855_CPU_PORT);
+	int i;
+
+	mutex_lock(&priv->reg_mutex);
+
+	for (i = 0; i < AN8855_NUM_PORTS; i++) {
+		/* Add this port to the port matrix of the other ports in the
+		 * same bridge. If the port is disabled, port matrix is kept
+		 * and not being setup until the port becomes enabled.
+		 */
+		if (dsa_is_user_port(ds, i) && i != port) {
+			if (dsa_to_port(ds, i)->bridge_dev != bridge)
+				continue;
+			if (priv->ports[i].enable)
+				an8855_set(priv, AN8855_PORTMATRIX_P(i),
+					   PORTMATRIX_MATRIX(BIT(port)));
+			priv->ports[i].pm |= PORTMATRIX_MATRIX(BIT(port));
+
+			port_bitmap |= BIT(i);
+		}
+	}
+
+	/* Add the all other ports to this port matrix. */
+	if (priv->ports[port].enable)
+		an8855_rmw(priv, AN8855_PORTMATRIX_P(port),
+			   PORTMATRIX_MASK, PORTMATRIX_MATRIX(port_bitmap));
+	priv->ports[port].pm |= PORTMATRIX_MATRIX(port_bitmap);
+
+	mutex_unlock(&priv->reg_mutex);
+
+	return 0;
+}
+
+static void
+an8855_port_set_vlan_unaware(struct dsa_switch *ds, int port)
+{
+	struct an8855_priv *priv = ds->priv;
+	bool all_user_ports_removed = true;
+	int i;
+
+	/* When a port is removed from the bridge, the port would be set up
+	 * back to the default as is at initial boot which is a VLAN-unaware
+	 * port.
+	 */
+	an8855_rmw(priv, AN8855_PCR_P(port), PCR_PORT_VLAN_MASK,
+		   AN8855_PORT_MATRIX_MODE);
+	an8855_rmw(priv, AN8855_PVC_P(port), VLAN_ATTR_MASK | PVC_EG_TAG_MASK,
+		   VLAN_ATTR(AN8855_VLAN_TRANSPARENT) |
+		   PVC_EG_TAG(AN8855_VLAN_EG_CONSISTENT));
+
+	for (i = 0; i < AN8855_NUM_PORTS; i++) {
+		if (dsa_is_user_port(ds, i) &&
+		    dsa_port_is_vlan_filtering(&ds->ports[i])) {
+			all_user_ports_removed = false;
+			break;
+		}
+	}
+
+	/* CPU port also does the same thing until all user ports belonging to
+	 * the CPU port get out of VLAN filtering mode.
+	 */
+	if (all_user_ports_removed) {
+		an8855_write(priv, AN8855_PORTMATRIX_P(AN8855_CPU_PORT),
+			     PORTMATRIX_MATRIX(dsa_user_ports(priv->ds)));
+		an8855_write(priv, AN8855_PVC_P(AN8855_CPU_PORT),
+			     PORT_SPEC_REPLACE_MODE | PORT_SPEC_TAG |
+			     PVC_EG_TAG(AN8855_VLAN_EG_CONSISTENT));
+	}
+}
+
+static void
+an8855_port_set_vlan_aware(struct dsa_switch *ds, int port)
+{
+	struct an8855_priv *priv = ds->priv;
+
+	/* Trapped into security mode allows packet forwarding through VLAN
+	 * table lookup. CPU port is set to fallback mode to let untagged
+	 * frames pass through.
+	 */
+	if (dsa_is_cpu_port(ds, port))
+		an8855_rmw(priv, AN8855_PCR_P(port), PCR_PORT_VLAN_MASK,
+			   AN8855_PORT_FALLBACK_MODE);
+	else
+		an8855_rmw(priv, AN8855_PCR_P(port), PCR_PORT_VLAN_MASK,
+			   AN8855_PORT_SECURITY_MODE);
+
+	/* Set the port as a user port which is to be able to recognize VID
+	 * from incoming packets before fetching entry within the VLAN table.
+	 */
+	an8855_rmw(priv, AN8855_PVC_P(port), VLAN_ATTR_MASK | PVC_EG_TAG_MASK,
+		   VLAN_ATTR(AN8855_VLAN_USER) |
+		   PVC_EG_TAG(AN8855_VLAN_EG_DISABLED));
+}
+
+static void
+an8855_port_bridge_leave(struct dsa_switch *ds, int port,
+			 struct net_device *bridge)
+{
+	struct an8855_priv *priv = ds->priv;
+	int i;
+
+	mutex_lock(&priv->reg_mutex);
+
+	for (i = 0; i < AN8855_NUM_PORTS; i++) {
+		/* Remove this port from the port matrix of the other ports
+		 * in the same bridge. If the port is disabled, port matrix
+		 * is kept and not being setup until the port becomes enabled.
+		 */
+		if (dsa_is_user_port(ds, i) && i != port) {
+			if (dsa_to_port(ds, i)->bridge_dev != bridge)
+				continue;
+			if (priv->ports[i].enable)
+				an8855_clear(priv, AN8855_PORTMATRIX_P(i),
+					     PORTMATRIX_MATRIX(BIT(port)));
+			priv->ports[i].pm &= PORTMATRIX_MATRIX(BIT(port));
+		}
+	}
+
+	/* Set the cpu port to be the only one in the port matrix of
+	 * this port.
+	 */
+	if (priv->ports[port].enable)
+		an8855_rmw(priv, AN8855_PORTMATRIX_P(port), PORTMATRIX_MASK,
+			   PORTMATRIX_MATRIX(BIT(AN8855_CPU_PORT)));
+	priv->ports[port].pm = PORTMATRIX_MATRIX(BIT(AN8855_CPU_PORT));
+
+	mutex_unlock(&priv->reg_mutex);
+}
+
+static int
+an8855_port_fdb_add(struct dsa_switch *ds, int port,
+		    const unsigned char *addr, u16 vid)
+{
+	struct an8855_priv *priv = ds->priv;
+	int ret;
+	u8 port_mask = BIT(port);
+
+	mutex_lock(&priv->reg_mutex);
+	an8855_fdb_write(priv, vid, port_mask, addr, 1);
+	ret = an8855_fdb_cmd(priv, AN8855_FDB_WRITE, NULL);
+	mutex_unlock(&priv->reg_mutex);
+
+	return ret;
+}
+
+static int
+an8855_port_fdb_del(struct dsa_switch *ds, int port,
+		    const unsigned char *addr, u16 vid)
+{
+	struct an8855_priv *priv = ds->priv;
+	int ret;
+	u8 port_mask = BIT(port);
+
+	mutex_lock(&priv->reg_mutex);
+	an8855_fdb_write(priv, vid, port_mask, addr, 0);
+	ret = an8855_fdb_cmd(priv, AN8855_FDB_WRITE, NULL);
+	mutex_unlock(&priv->reg_mutex);
+
+	return ret;
+}
+
+static int
+an8855_port_fdb_dump(struct dsa_switch *ds, int port,
+		     dsa_fdb_dump_cb_t *cb, void *data)
+{
+	struct an8855_priv *priv = ds->priv;
+	struct an8855_fdb _fdb = { 0 };
+	int cnt = 512;
+	int num = 4;
+	int index = 0;
+	bool flag = false;
+	int banks = 0;
+	int i = 0;
+	int ret = 0;
+	u32 rsp = 0;
+
+	mutex_lock(&priv->reg_mutex);
+
+	an8855_write(priv, AN8855_ATWD2, (0x1 << port));
+	ret = an8855_fdb_cmd(priv, ATC_MAT(0xc) | AN8855_FDB_START, &rsp);
+	if (ret < 0)
+		goto err;
+
+	index = (rsp >> ATC_HASH) & ATC_HASH_MASK;
+	if (index == (cnt - 1))
+		flag = true;
+	else
+		flag = false;
+
+	banks = (rsp >> ATC_HIT) & ATC_HIT_MASK;
+	if (banks == 0) {
+		mutex_unlock(&priv->reg_mutex);
+		return 0;
+	}
+	for (i = 0; i < num; i++) {
+		if ((banks >> i) & 0x1) {
+			an8855_write(priv, AN8855_ATRDS, i);
+			udelay(1000);
+			an8855_fdb_read(priv, &_fdb);
+			if (!_fdb.live)
+				continue;
+			if (_fdb.port_mask & BIT(port)) {
+				ret = cb(_fdb.mac, _fdb.vid, _fdb.noarp, data);
+				if (ret < 0)
+					continue;
+			}
+		}
+	}
+	while (1) {
+		if (flag == true)
+			break;
+
+		ret =
+		    an8855_fdb_cmd(priv, ATC_MAT(0xc) | AN8855_FDB_NEXT, &rsp);
+		index = (rsp >> ATC_HASH) & ATC_HASH_MASK;
+		if (index == (cnt - 1))
+			flag = true;
+		else
+			flag = false;
+
+		banks = (rsp >> ATC_HIT) & ATC_HIT_MASK;
+		if (banks == 0) {
+			mutex_unlock(&priv->reg_mutex);
+			return 0;
+		}
+		for (i = 0; i < num; i++) {
+			if ((banks >> i) & 0x1) {
+				an8855_write(priv, AN8855_ATRDS, i);
+				udelay(1000);
+				an8855_fdb_read(priv, &_fdb);
+				if (!_fdb.live)
+					continue;
+				if (_fdb.port_mask & BIT(port)) {
+					ret = cb(_fdb.mac, _fdb.vid, _fdb.noarp,
+						 data);
+					if (ret < 0)
+						continue;
+				}
+			}
+		}
+	}
+
+err:
+	mutex_unlock(&priv->reg_mutex);
+	return 0;
+}
+
+static int
+an8855_vlan_cmd(struct an8855_priv *priv, enum an8855_vlan_cmd cmd, u16 vid)
+{
+	struct an8855_dummy_poll p;
+	u32 val;
+	int ret;
+
+	if (vid > 0xFFF) {
+		dev_err(priv->dev, "vid number invalid\n");
+		return -EINVAL;
+	}
+
+	val = VTCR_BUSY | VTCR_FUNC(cmd) | vid;
+	an8855_write(priv, AN8855_VTCR, val);
+
+	INIT_AN8855_DUMMY_POLL(&p, priv, AN8855_VTCR);
+	ret = readx_poll_timeout(_an8855_read, &p, val,
+				 !(val & VTCR_BUSY), 20, 200000);
+	if (ret < 0) {
+		dev_err(priv->dev, "poll timeout\n");
+		return ret;
+	}
+
+	return 0;
+}
+
+static int
+an8855_port_vlan_filtering(struct dsa_switch *ds, int port, bool vlan_filtering)
+{
+	if (vlan_filtering) {
+		/* The port is being kept as VLAN-unaware port when bridge is
+		 * set up with vlan_filtering not being set, Otherwise, the
+		 * port and the corresponding CPU port is required the setup
+		 * for becoming a VLAN-aware port.
+		 */
+		an8855_port_set_vlan_aware(ds, port);
+		an8855_port_set_vlan_aware(ds, AN8855_CPU_PORT);
+	} else {
+		an8855_port_set_vlan_unaware(ds, port);
+	}
+
+	return 0;
+}
+
+static int
+an8855_port_vlan_prepare(struct dsa_switch *ds, int port,
+			 const struct switchdev_obj_port_vlan *vlan)
+{
+	/* nothing needed */
+	return 0;
+}
+
+static void
+an8855_hw_vlan_add(struct an8855_priv *priv, struct an8855_hw_vlan_entry *entry)
+{
+	u8 new_members;
+	u32 val;
+
+	new_members = entry->old_members | BIT(entry->port) |
+	    BIT(AN8855_CPU_PORT);
+
+	/* Validate the entry with independent learning, create egress tag per
+	 * VLAN and joining the port as one of the port members.
+	 */
+	val =
+	    an8855_read(priv,
+			AN8855_VARD0) & (ETAG_CTRL_MASK << PORT_EG_CTRL_SHIFT);
+	val |= (IVL_MAC | VTAG_EN | PORT_MEM(new_members) | VLAN_VALID);
+	an8855_write(priv, AN8855_VAWD0, val);
+	an8855_write(priv, AN8855_VAWD1, 0);
+
+	/* Decide whether adding tag or not for those outgoing packets from the
+	 * port inside the VLAN.
+	 */
+	val =
+	    entry->untagged ? AN8855_VLAN_EGRESS_UNTAG : AN8855_VLAN_EGRESS_TAG;
+	an8855_rmw(priv, AN8855_VAWD0,
+		   ETAG_CTRL_P_MASK(entry->port) << PORT_EG_CTRL_SHIFT,
+		   ETAG_CTRL_P(entry->port, val) << PORT_EG_CTRL_SHIFT);
+
+	/* CPU port is always taken as a tagged port for serving more than one
+	 * VLANs across and also being applied with egress type stack mode for
+	 * that VLAN tags would be appended after hardware special tag used as
+	 * DSA tag.
+	 */
+	an8855_rmw(priv, AN8855_VAWD0,
+		   ETAG_CTRL_P_MASK(AN8855_CPU_PORT) << PORT_EG_CTRL_SHIFT,
+		   ETAG_CTRL_P(AN8855_CPU_PORT,
+			       AN8855_VLAN_EGRESS_STACK) << PORT_EG_CTRL_SHIFT);
+}
+
+static void
+an8855_hw_vlan_del(struct an8855_priv *priv, struct an8855_hw_vlan_entry *entry)
+{
+	u8 new_members;
+	u32 val;
+
+	new_members = entry->old_members & ~BIT(entry->port);
+
+	val = an8855_read(priv, AN8855_VARD0);
+	if (!(val & VLAN_VALID)) {
+		dev_err(priv->dev, "Cannot be deleted due to invalid entry\n");
+		return;
+	}
+
+	/* If certain member apart from CPU port is still alive in the VLAN,
+	 * the entry would be kept valid. Otherwise, the entry is got to be
+	 * disabled.
+	 */
+	if (new_members && new_members != BIT(AN8855_CPU_PORT)) {
+		val = IVL_MAC | VTAG_EN | PORT_MEM(new_members) | VLAN_VALID;
+		an8855_write(priv, AN8855_VAWD0, val);
+	} else {
+		an8855_write(priv, AN8855_VAWD0, 0);
+		an8855_write(priv, AN8855_VAWD1, 0);
+	}
+}
+
+static void
+an8855_hw_vlan_update(struct an8855_priv *priv, u16 vid,
+		      struct an8855_hw_vlan_entry *entry,
+		      an8855_vlan_op vlan_op)
+{
+	u32 val;
+
+	/* Fetch entry */
+	an8855_vlan_cmd(priv, AN8855_VTCR_RD_VID, vid);
+
+	val = an8855_read(priv, AN8855_VARD0);
+
+	entry->old_members = (val >> PORT_MEM_SHFT) & PORT_MEM_MASK;
+
+	/* Manipulate entry */
+	vlan_op(priv, entry);
+
+	/* Flush result to hardware */
+	an8855_vlan_cmd(priv, AN8855_VTCR_WR_VID, vid);
+}
+
+static void
+an8855_port_vlan_add(struct dsa_switch *ds, int port,
+		     const struct switchdev_obj_port_vlan *vlan)
+{
+	bool untagged = vlan->flags & BRIDGE_VLAN_INFO_UNTAGGED;
+	bool pvid = vlan->flags & BRIDGE_VLAN_INFO_PVID;
+	struct an8855_hw_vlan_entry new_entry;
+	struct an8855_priv *priv = ds->priv;
+	u16 vid;
+
+	mutex_lock(&priv->reg_mutex);
+
+	for (vid = vlan->vid_begin; vid <= vlan->vid_end; ++vid) {
+		an8855_hw_vlan_entry_init(&new_entry, port, untagged);
+		an8855_hw_vlan_update(priv, vid, &new_entry,
+				      an8855_hw_vlan_add);
+	}
+
+	if (pvid) {
+		an8855_rmw(priv, AN8855_PVID_P(port), G0_PORT_VID_MASK,
+			   G0_PORT_VID(vlan->vid_end));
+		priv->ports[port].pvid = vlan->vid_end;
+	}
+
+	mutex_unlock(&priv->reg_mutex);
+}
+
+static int
+an8855_port_vlan_del(struct dsa_switch *ds, int port,
+		     const struct switchdev_obj_port_vlan *vlan)
+{
+	struct an8855_hw_vlan_entry target_entry;
+	struct an8855_priv *priv = ds->priv;
+	u16 vid, pvid;
+
+	mutex_lock(&priv->reg_mutex);
+
+	pvid = priv->ports[port].pvid;
+	for (vid = vlan->vid_begin; vid <= vlan->vid_end; ++vid) {
+		an8855_hw_vlan_entry_init(&target_entry, port, 0);
+		an8855_hw_vlan_update(priv, vid, &target_entry,
+				      an8855_hw_vlan_del);
+
+		/* PVID is being restored to the default whenever the PVID port
+		 * is being removed from the VLAN.
+		 */
+		if (pvid == vid)
+			pvid = G0_PORT_VID_DEF;
+	}
+
+	an8855_rmw(priv, AN8855_PVID_P(port), G0_PORT_VID_MASK, pvid);
+	priv->ports[port].pvid = pvid;
+
+	mutex_unlock(&priv->reg_mutex);
+
+	return 0;
+}
+
+static int an8855_port_mirror_add(struct dsa_switch *ds, int port,
+				  struct dsa_mall_mirror_tc_entry *mirror,
+				  bool ingress)
+{
+	struct an8855_priv *priv = ds->priv;
+	int monitor_port;
+	u32 val;
+
+	/* Check for existent entry */
+	if ((ingress ? priv->mirror_rx : priv->mirror_tx) & BIT(port))
+		return -EEXIST;
+
+	val = an8855_read(priv, AN8855_MIR);
+
+	/* AN8855 supports 4 monitor port, but only use first group */
+	monitor_port = AN8855_MIRROR_PORT_GET(val);
+	if (val & AN8855_MIRROR_EN && monitor_port != mirror->to_local_port)
+		return -EEXIST;
+
+	val |= AN8855_MIRROR_EN;
+	val &= ~AN8855_MIRROR_MASK;
+	val |= AN8855_MIRROR_PORT_SET(mirror->to_local_port);
+	an8855_write(priv, AN8855_MIR, val);
+
+	val = an8855_read(priv, AN8855_PCR_P(port));
+	if (ingress) {
+		val |= PORT_RX_MIR;
+		priv->mirror_rx |= BIT(port);
+	} else {
+		val |= PORT_TX_MIR;
+		priv->mirror_tx |= BIT(port);
+	}
+	an8855_write(priv, AN8855_PCR_P(port), val);
+
+	return 0;
+}
+
+static void an8855_port_mirror_del(struct dsa_switch *ds, int port,
+				   struct dsa_mall_mirror_tc_entry *mirror)
+{
+	struct an8855_priv *priv = ds->priv;
+	u32 val;
+
+	val = an8855_read(priv, AN8855_PCR_P(port));
+	if (mirror->ingress) {
+		val &= ~PORT_RX_MIR;
+		priv->mirror_rx &= ~BIT(port);
+	} else {
+		val &= ~PORT_TX_MIR;
+		priv->mirror_tx &= ~BIT(port);
+	}
+	an8855_write(priv, AN8855_PCR_P(port), val);
+
+	if (!priv->mirror_rx && !priv->mirror_tx) {
+		val = an8855_read(priv, AN8855_MIR);
+		val &= ~AN8855_MIRROR_EN;
+		an8855_write(priv, AN8855_MIR, val);
+	}
+}
+
+static enum dsa_tag_protocol
+air_get_tag_protocol(struct dsa_switch *ds, int port, enum dsa_tag_protocol mp)
+{
+	struct an8855_priv *priv = ds->priv;
+
+	if (port != AN8855_CPU_PORT) {
+		dev_warn(priv->dev, "port not matched with tagging CPU port\n");
+		return DSA_TAG_PROTO_NONE;
+	} else {
+		return DSA_TAG_PROTO_ARHT;
+	}
+}
+
+static int
+setup_unused_ports(struct dsa_switch *ds, u32 pm)
+{
+	struct an8855_priv *priv = ds->priv;
+	u32 egtag_mask = 0;
+	u32 egtag_val = 0;
+	int i;
+
+	if (!pm)
+		return 0;
+
+	for (i = 0; i < AN8855_NUM_PORTS; i++) {
+		if (!dsa_is_unused_port(ds, i))
+			continue;
+
+		/* Setup MAC port with maximum capability. */
+		if (i == 5)
+			if (priv->info->cpu_port_config)
+				priv->info->cpu_port_config(ds, i);
+
+		an8855_rmw(priv, AN8855_PORTMATRIX_P(i), PORTMATRIX_MASK,
+			   AN8855_PORTMATRIX_P(pm));
+		an8855_rmw(priv, AN8855_PCR_P(i), PCR_PORT_VLAN_MASK,
+			   AN8855_PORT_SECURITY_MODE);
+		egtag_mask |= ETAG_CTRL_P_MASK(i);
+		egtag_val |= ETAG_CTRL_P(i, AN8855_VLAN_EGRESS_UNTAG);
+	}
+
+	/* Add unused ports to VLAN2 group for using IVL fdb. */
+	an8855_write(priv, AN8855_VAWD0,
+		     IVL_MAC | VTAG_EN | PORT_MEM(pm) | VLAN_VALID);
+	an8855_rmw(priv, AN8855_VAWD0, egtag_mask << PORT_EG_CTRL_SHIFT,
+		   egtag_val << PORT_EG_CTRL_SHIFT);
+	an8855_write(priv, AN8855_VAWD1, 0);
+	an8855_vlan_cmd(priv, AN8855_VTCR_WR_VID, AN8855_RESERVED_VLAN);
+
+	for (i = 0; i < AN8855_NUM_PORTS; i++) {
+		if (!dsa_is_unused_port(ds, i))
+			continue;
+
+		an8855_rmw(priv, AN8855_PVID_P(i), G0_PORT_VID_MASK,
+			   G0_PORT_VID(AN8855_RESERVED_VLAN));
+		an8855_rmw(priv, AN8855_SSP_P(i), FID_PST_MASK,
+			   AN8855_STP_FORWARDING);
+
+		dev_dbg(ds->dev, "Add unused port%d to reserved VLAN%d group\n",
+			i, AN8855_RESERVED_VLAN);
+	}
+
+	return 0;
+}
+
+static int
+an8855_setup(struct dsa_switch *ds)
+{
+	struct an8855_priv *priv = ds->priv;
+	struct an8855_dummy_poll p;
+	u32 unused_pm = 0;
+	u32 val, id;
+	int ret, i;
+
+	/* Reset whole chip through gpio pin or memory-mapped registers for
+	 * different type of hardware
+	 */
+	gpiod_set_value_cansleep(priv->reset, 0);
+	usleep_range(100000, 150000);
+	gpiod_set_value_cansleep(priv->reset, 1);
+	usleep_range(100000, 150000);
+
+	/* Waiting for AN8855 got to stable */
+	INIT_AN8855_DUMMY_POLL(&p, priv, 0x1000009c);
+	ret = readx_poll_timeout(_an8855_read, &p, val, val != 0, 20, 1000000);
+	if (ret < 0) {
+		dev_err(priv->dev, "reset timeout\n");
+		return ret;
+	}
+
+	id = an8855_read(priv, AN8855_CREV);
+	if (id != AN8855_ID) {
+		dev_err(priv->dev, "chip %x can't be supported\n", id);
+		return -ENODEV;
+	}
+
+	/* Reset the switch through internal reset */
+	an8855_write(priv, AN8855_RST_CTRL, SYS_CTRL_SYS_RST);
+	usleep_range(100000, 110000);
+
+	/* change gphy smi address */
+	if (priv->phy_base_new > 0) {
+		an8855_write(priv, RG_GPHY_SMI_ADDR, priv->phy_base_new);
+		priv->phy_base = priv->phy_base_new;
+	}
+
+	/* Let phylink decide the interface later. */
+	priv->p5_interface = PHY_INTERFACE_MODE_NA;
+
+	/* BPDU to CPU port */
+	//an8855_rmw(priv, AN8855_CFC, AN8855_CPU_PMAP_MASK,
+	//         BIT(AN8855_CPU_PORT));
+	an8855_rmw(priv, AN8855_BPC, AN8855_BPDU_PORT_FW_MASK,
+		   AN8855_BPDU_CPU_ONLY);
+
+	/* Enable and reset MIB counters */
+	an8855_mib_reset(ds);
+
+	for (i = 0; i < AN8855_NUM_PORTS; i++) {
+		/* Disable forwarding by default on all ports */
+		an8855_rmw(priv, AN8855_PORTMATRIX_P(i), PORTMATRIX_MASK,
+			   PORTMATRIX_CLR);
+		if (dsa_is_unused_port(ds, i))
+			unused_pm |= BIT(i);
+		else if (dsa_is_cpu_port(ds, i))
+			an8855_cpu_port_enable(ds, i);
+		else
+			an8855_port_disable(ds, i);
+		/* Enable consistent egress tag */
+		an8855_rmw(priv, AN8855_PVC_P(i), PVC_EG_TAG_MASK,
+			   PVC_EG_TAG(AN8855_VLAN_EG_CONSISTENT));
+	}
+
+	an8855_phy_setup(ds);
+
+	/* Group and enable unused ports as a standalone dumb switch. */
+	setup_unused_ports(ds, unused_pm);
+
+	ds->configure_vlan_while_not_filtering = true;
+
+	/* Flush the FDB table */
+	ret = an8855_fdb_cmd(priv, AN8855_FDB_FLUSH, NULL);
+	if (ret < 0)
+		return ret;
+
+	return 0;
+}
+
+static bool
+an8855_phy_supported(struct dsa_switch *ds, int port,
+		     const struct phylink_link_state *state)
+{
+	struct an8855_priv *priv = ds->priv;
+
+	switch (port) {
+	case 0:		/* Internal phy */
+	case 1:
+	case 2:
+	case 3:
+	case 4:
+		if (state->interface != PHY_INTERFACE_MODE_GMII)
+			goto unsupported;
+		break;
+	case 5:
+		if (state->interface != PHY_INTERFACE_MODE_SGMII
+		    && state->interface != PHY_INTERFACE_MODE_RGMII
+			&& state->interface != PHY_INTERFACE_MODE_2500BASEX)
+			goto unsupported;
+		break;
+	default:
+		dev_err(priv->dev, "%s: unsupported port: %i\n", __func__,
+			port);
+		goto unsupported;
+	}
+
+	return true;
+
+unsupported:
+	return false;
+}
+
+static bool
+an8855_phy_mode_supported(struct dsa_switch *ds, int port,
+			  const struct phylink_link_state *state)
+{
+	struct an8855_priv *priv = ds->priv;
+
+	return priv->info->phy_mode_supported(ds, port, state);
+}
+
+static int
+an8855_rgmii_setup(struct an8855_priv *priv, u32 port,
+			      phy_interface_t interface,
+			      struct phy_device *phydev)
+{
+	return 0;
+}
+
+static void
+an8855_sgmii_validate(struct an8855_priv *priv, int port,
+				  unsigned long *supported)
+{
+	switch (port) {
+	case 5:
+		phylink_set(supported, 1000baseX_Full);
+		phylink_set(supported, 2500baseX_Full);
+	}
+}
+
+static void
+an8855_sgmii_link_up_force(struct dsa_switch *ds, int port,
+			   unsigned int mode, phy_interface_t interface,
+			   int speed, int duplex)
+{
+	/* For adjusting speed and duplex of SGMII force mode. */
+	if (interface != PHY_INTERFACE_MODE_SGMII ||
+	    phylink_autoneg_inband(mode))
+		return;
+}
+
+static bool
+an8855_is_mac_port(u32 port)
+{
+	return (port == 5);
+}
+
+static int
+an8855_set_hsgmii_mode(struct an8855_priv *priv)
+{
+	u32 val = 0;
+
+	/* PLL */
+	val = an8855_read(priv, QP_DIG_MODE_CTRL_1);
+	val &= ~(0x3 << 2);
+	val |= (0x1 << 2);
+	an8855_write(priv, QP_DIG_MODE_CTRL_1, val);
+
+	/* PLL - LPF */
+	val = an8855_read(priv, PLL_CTRL_2);
+	val &= ~(0x3 << 0);
+	val |= (0x1 << 0);
+	val &= ~(0x7 << 2);
+	val |= (0x5 << 2);
+	val &= ~BITS(6, 7);
+	val &= ~(0x7 << 8);
+	val |= (0x3 << 8);
+	val |= BIT(29);
+	val &= ~BITS(12, 13);
+	an8855_write(priv, PLL_CTRL_2, val);
+
+	/* PLL - ICO */
+	val = an8855_read(priv, PLL_CTRL_4);
+	val |= BIT(2);
+	an8855_write(priv, PLL_CTRL_4, val);
+
+	val = an8855_read(priv, PLL_CTRL_2);
+	val &= ~BIT(14);
+	an8855_write(priv, PLL_CTRL_2, val);
+
+	/* PLL - CHP */
+	val = an8855_read(priv, PLL_CTRL_2);
+	val &= ~(0xf << 16);
+	val |= (0x6 << 16);
+	an8855_write(priv, PLL_CTRL_2, val);
+
+	/* PLL - PFD */
+	val = an8855_read(priv, PLL_CTRL_2);
+	val &= ~(0x3 << 20);
+	val |= (0x1 << 20);
+	val &= ~(0x3 << 24);
+	val |= (0x1 << 24);
+	val &= ~BIT(26);
+	an8855_write(priv, PLL_CTRL_2, val);
+
+	/* PLL - POSTDIV */
+	val = an8855_read(priv, PLL_CTRL_2);
+	val |= BIT(22);
+	val &= ~BIT(27);
+	val &= ~BIT(28);
+	an8855_write(priv, PLL_CTRL_2, val);
+
+	/* PLL - SDM */
+	val = an8855_read(priv, PLL_CTRL_4);
+	val &= ~BITS(3, 4);
+	an8855_write(priv, PLL_CTRL_4, val);
+
+	val = an8855_read(priv, PLL_CTRL_2);
+	val &= ~BIT(30);
+	an8855_write(priv, PLL_CTRL_2, val);
+
+	val = an8855_read(priv, SS_LCPLL_PWCTL_SETTING_2);
+	val &= ~(0x3 << 16);
+	val |= (0x1 << 16);
+	an8855_write(priv, SS_LCPLL_PWCTL_SETTING_2, val);
+
+	an8855_write(priv, SS_LCPLL_TDC_FLT_2, 0x7a000000);
+	an8855_write(priv, SS_LCPLL_TDC_PCW_1, 0x7a000000);
+
+	val = an8855_read(priv, SS_LCPLL_TDC_FLT_5);
+	val &= ~BIT(24);
+	an8855_write(priv, SS_LCPLL_TDC_FLT_5, val);
+
+	val = an8855_read(priv, PLL_CK_CTRL_0);
+	val &= ~BIT(8);
+	an8855_write(priv, PLL_CK_CTRL_0, val);
+
+	/* PLL - SS */
+	val = an8855_read(priv, PLL_CTRL_3);
+	val &= ~BITS(0, 15);
+	an8855_write(priv, PLL_CTRL_3, val);
+
+	val = an8855_read(priv, PLL_CTRL_4);
+	val &= ~BITS(0, 1);
+	an8855_write(priv, PLL_CTRL_4, val);
+
+	val = an8855_read(priv, PLL_CTRL_3);
+	val &= ~BITS(16, 31);
+	an8855_write(priv, PLL_CTRL_3, val);
+
+	/* PLL - TDC */
+	val = an8855_read(priv, PLL_CK_CTRL_0);
+	val &= ~BIT(9);
+	an8855_write(priv, PLL_CK_CTRL_0, val);
+
+	val = an8855_read(priv, RG_QP_PLL_SDM_ORD);
+	val |= BIT(3);
+	val |= BIT(4);
+	an8855_write(priv, RG_QP_PLL_SDM_ORD, val);
+
+	val = an8855_read(priv, RG_QP_RX_DAC_EN);
+	val &= ~(0x3 << 16);
+	val |= (0x2 << 16);
+	an8855_write(priv, RG_QP_RX_DAC_EN, val);
+
+	/* TCL Disable (only for Co-SIM) */
+	val = an8855_read(priv, PON_RXFEDIG_CTRL_0);
+	val &= ~BIT(12);
+	an8855_write(priv, PON_RXFEDIG_CTRL_0, val);
+
+	/* TX Init */
+	val = an8855_read(priv, RG_QP_TX_MODE_16B_EN);
+	val &= ~BIT(0);
+	val &= ~(0xffff << 16);
+	val |= (0x4 << 16);
+	an8855_write(priv, RG_QP_TX_MODE_16B_EN, val);
+
+	/* RX Control */
+	val = an8855_read(priv, RG_QP_RXAFE_RESERVE);
+	val |= BIT(11);
+	an8855_write(priv, RG_QP_RXAFE_RESERVE, val);
+
+	val = an8855_read(priv, RG_QP_CDR_LPF_MJV_LIM);
+	val &= ~(0x3 << 4);
+	val |= (0x1 << 4);
+	an8855_write(priv, RG_QP_CDR_LPF_MJV_LIM, val);
+
+	val = an8855_read(priv, RG_QP_CDR_LPF_SETVALUE);
+	val &= ~(0xf << 25);
+	val |= (0x1 << 25);
+	val &= ~(0x7 << 29);
+	val |= (0x3 << 29);
+	an8855_write(priv, RG_QP_CDR_LPF_SETVALUE, val);
+
+	val = an8855_read(priv, RG_QP_CDR_PR_CKREF_DIV1);
+	val &= ~(0x1f << 8);
+	val |= (0xf << 8);
+	an8855_write(priv, RG_QP_CDR_PR_CKREF_DIV1, val);
+
+	val = an8855_read(priv, RG_QP_CDR_PR_KBAND_DIV_PCIE);
+	val &= ~(0x3f << 0);
+	val |= (0x19 << 0);
+	val &= ~BIT(6);
+	an8855_write(priv, RG_QP_CDR_PR_KBAND_DIV_PCIE, val);
+
+	val = an8855_read(priv, RG_QP_CDR_FORCE_IBANDLPF_R_OFF);
+	val &= ~(0x7f << 6);
+	val |= (0x21 << 6);
+	val &= ~(0x3 << 16);
+	val |= (0x2 << 16);
+	val &= ~BIT(13);
+	an8855_write(priv, RG_QP_CDR_FORCE_IBANDLPF_R_OFF, val);
+
+	val = an8855_read(priv, RG_QP_CDR_PR_KBAND_DIV_PCIE);
+	val &= ~BIT(30);
+	an8855_write(priv, RG_QP_CDR_PR_KBAND_DIV_PCIE, val);
+
+	val = an8855_read(priv, RG_QP_CDR_PR_CKREF_DIV1);
+	val &= ~(0x7 << 24);
+	val |= (0x4 << 24);
+	an8855_write(priv, RG_QP_CDR_PR_CKREF_DIV1, val);
+
+	val = an8855_read(priv, PLL_CTRL_0);
+	val |= BIT(0);
+	an8855_write(priv, PLL_CTRL_0, val);
+
+	val = an8855_read(priv, RX_CTRL_26);
+	val &= ~BIT(23);
+	val |= BIT(26);
+	an8855_write(priv, RX_CTRL_26, val);
+
+	val = an8855_read(priv, RX_DLY_0);
+	val &= ~(0xff << 0);
+	val |= (0x6f << 0);
+	val |= BITS(8, 13);
+	an8855_write(priv, RX_DLY_0, val);
+
+	val = an8855_read(priv, RX_CTRL_42);
+	val &= ~(0x1fff << 0);
+	val |= (0x150 << 0);
+	an8855_write(priv, RX_CTRL_42, val);
+
+	val = an8855_read(priv, RX_CTRL_2);
+	val &= ~(0x1fff << 16);
+	val |= (0x150 << 16);
+	an8855_write(priv, RX_CTRL_2, val);
+
+	val = an8855_read(priv, PON_RXFEDIG_CTRL_9);
+	val &= ~(0x7 << 0);
+	val |= (0x1 << 0);
+	an8855_write(priv, PON_RXFEDIG_CTRL_9, val);
+
+	val = an8855_read(priv, RX_CTRL_8);
+	val &= ~(0xfff << 16);
+	val |= (0x200 << 16);
+	val &= ~(0x7fff << 14);
+	val |= (0xfff << 14);
+	an8855_write(priv, RX_CTRL_8, val);
+
+	/* Frequency memter */
+	val = an8855_read(priv, RX_CTRL_5);
+	val &= ~(0xfffff << 10);
+	val |= (0x10 << 10);
+	an8855_write(priv, RX_CTRL_5, val);
+
+	val = an8855_read(priv, RX_CTRL_6);
+	val &= ~(0xfffff << 0);
+	val |= (0x64 << 0);
+	an8855_write(priv, RX_CTRL_6, val);
+
+	val = an8855_read(priv, RX_CTRL_7);
+	val &= ~(0xfffff << 0);
+	val |= (0x2710 << 0);
+	an8855_write(priv, RX_CTRL_7, val);
+
+	/* PCS Init */
+	val = an8855_read(priv, RG_HSGMII_PCS_CTROL_1);
+	val &= ~BIT(30);
+	an8855_write(priv, RG_HSGMII_PCS_CTROL_1, val);
+
+	/* Rate Adaption */
+	val = an8855_read(priv, RATE_ADP_P0_CTRL_0);
+	val &= ~BIT(31);
+	an8855_write(priv, RATE_ADP_P0_CTRL_0, val);
+
+	val = an8855_read(priv, RG_RATE_ADAPT_CTRL_0);
+	val |= BIT(0);
+	val |= BIT(4);
+	val |= BITS(26, 27);
+	an8855_write(priv, RG_RATE_ADAPT_CTRL_0, val);
+
+	/* Disable AN */
+	val = an8855_read(priv, SGMII_REG_AN0);
+	val &= ~BIT(12);
+	an8855_write(priv, SGMII_REG_AN0, val);
+
+	/* Force Speed */
+	val = an8855_read(priv, SGMII_STS_CTRL_0);
+	val |= BIT(2);
+	val |= BITS(4, 5);
+	an8855_write(priv, SGMII_STS_CTRL_0, val);
+
+	/* bypass flow control to MAC */
+	an8855_write(priv, MSG_RX_LIK_STS_0, 0x01010107);
+	an8855_write(priv, MSG_RX_LIK_STS_2, 0x00000EEF);
+
+	return 0;
+}
+
+static int
+an8855_sgmii_setup(struct an8855_priv *priv, int mode)
+{
+	u32 val = 0;
+
+	/* PMA Init */
+	/* PLL */
+	val = an8855_read(priv, QP_DIG_MODE_CTRL_1);
+	val &= ~BITS(2, 3);
+	an8855_write(priv, QP_DIG_MODE_CTRL_1, val);
+
+	/* PLL - LPF */
+	val = an8855_read(priv, PLL_CTRL_2);
+	val &= ~(0x3 << 0);
+	val |= (0x1 << 0);
+	val &= ~(0x7 << 2);
+	val |= (0x5 << 2);
+	val &= ~BITS(6, 7);
+	val &= ~(0x7 << 8);
+	val |= (0x3 << 8);
+	val |= BIT(29);
+	val &= ~BITS(12, 13);
+	an8855_write(priv, PLL_CTRL_2, val);
+
+	/* PLL - ICO */
+	val = an8855_read(priv, PLL_CTRL_4);
+	val |= BIT(2);
+	an8855_write(priv, PLL_CTRL_4, val);
+
+	val = an8855_read(priv, PLL_CTRL_2);
+	val &= ~BIT(14);
+	an8855_write(priv, PLL_CTRL_2, val);
+
+	/* PLL - CHP */
+	val = an8855_read(priv, PLL_CTRL_2);
+	val &= ~(0xf << 16);
+	val |= (0x4 << 16);
+	an8855_write(priv, PLL_CTRL_2, val);
+
+	/* PLL - PFD */
+	val = an8855_read(priv, PLL_CTRL_2);
+	val &= ~(0x3 << 20);
+	val |= (0x1 << 20);
+	val &= ~(0x3 << 24);
+	val |= (0x1 << 24);
+	val &= ~BIT(26);
+	an8855_write(priv, PLL_CTRL_2, val);
+
+	/* PLL - POSTDIV */
+	val = an8855_read(priv, PLL_CTRL_2);
+	val |= BIT(22);
+	val &= ~BIT(27);
+	val &= ~BIT(28);
+	an8855_write(priv, PLL_CTRL_2, val);
+
+	/* PLL - SDM */
+	val = an8855_read(priv, PLL_CTRL_4);
+	val &= ~BITS(3, 4);
+	an8855_write(priv, PLL_CTRL_4, val);
+
+	val = an8855_read(priv, PLL_CTRL_2);
+	val &= ~BIT(30);
+	an8855_write(priv, PLL_CTRL_2, val);
+
+	val = an8855_read(priv, SS_LCPLL_PWCTL_SETTING_2);
+	val &= ~(0x3 << 16);
+	val |= (0x1 << 16);
+	an8855_write(priv, SS_LCPLL_PWCTL_SETTING_2, val);
+
+	an8855_write(priv, SS_LCPLL_TDC_FLT_2, 0x48000000);
+	an8855_write(priv, SS_LCPLL_TDC_PCW_1, 0x48000000);
+
+	val = an8855_read(priv, SS_LCPLL_TDC_FLT_5);
+	val &= ~BIT(24);
+	an8855_write(priv, SS_LCPLL_TDC_FLT_5, val);
+
+	val = an8855_read(priv, PLL_CK_CTRL_0);
+	val &= ~BIT(8);
+	an8855_write(priv, PLL_CK_CTRL_0, val);
+
+	/* PLL - SS */
+	val = an8855_read(priv, PLL_CTRL_3);
+	val &= ~BITS(0, 15);
+	an8855_write(priv, PLL_CTRL_3, val);
+
+	val = an8855_read(priv, PLL_CTRL_4);
+	val &= ~BITS(0, 1);
+	an8855_write(priv, PLL_CTRL_4, val);
+
+	val = an8855_read(priv, PLL_CTRL_3);
+	val &= ~BITS(16, 31);
+	an8855_write(priv, PLL_CTRL_3, val);
+
+	/* PLL - TDC */
+	val = an8855_read(priv, PLL_CK_CTRL_0);
+	val &= ~BIT(9);
+	an8855_write(priv, PLL_CK_CTRL_0, val);
+
+	val = an8855_read(priv, RG_QP_PLL_SDM_ORD);
+	val |= BIT(3);
+	val |= BIT(4);
+	an8855_write(priv, RG_QP_PLL_SDM_ORD, val);
+
+	val = an8855_read(priv, RG_QP_RX_DAC_EN);
+	val &= ~(0x3 << 16);
+	val |= (0x2 << 16);
+	an8855_write(priv, RG_QP_RX_DAC_EN, val);
+
+	/* PLL - TCL Disable (only for Co-SIM) */
+	val = an8855_read(priv, PON_RXFEDIG_CTRL_0);
+	val &= ~BIT(12);
+	an8855_write(priv, PON_RXFEDIG_CTRL_0, val);
+
+	/* TX Init */
+	val = an8855_read(priv, RG_QP_TX_MODE_16B_EN);
+	val &= ~BIT(0);
+	val &= ~BITS(16, 31);
+	an8855_write(priv, RG_QP_TX_MODE_16B_EN, val);
+
+	/* RX Init */
+	val = an8855_read(priv, RG_QP_RXAFE_RESERVE);
+	val |= BIT(11);
+	an8855_write(priv, RG_QP_RXAFE_RESERVE, val);
+
+	val = an8855_read(priv, RG_QP_CDR_LPF_MJV_LIM);
+	val &= ~(0x3 << 4);
+	val |= (0x2 << 4);
+	an8855_write(priv, RG_QP_CDR_LPF_MJV_LIM, val);
+
+	val = an8855_read(priv, RG_QP_CDR_LPF_SETVALUE);
+	val &= ~(0xf << 25);
+	val |= (0x1 << 25);
+	val &= ~(0x7 << 29);
+	val |= (0x6 << 29);
+	an8855_write(priv, RG_QP_CDR_LPF_SETVALUE, val);
+
+	val = an8855_read(priv, RG_QP_CDR_PR_CKREF_DIV1);
+	val &= ~(0x1f << 8);
+	val |= (0xc << 8);
+	an8855_write(priv, RG_QP_CDR_PR_CKREF_DIV1, val);
+
+	val = an8855_read(priv, RG_QP_CDR_PR_KBAND_DIV_PCIE);
+	val &= ~(0x3f << 0);
+	val |= (0x19 << 0);
+	val &= ~BIT(6);
+	an8855_write(priv, RG_QP_CDR_PR_KBAND_DIV_PCIE, val);
+
+	val = an8855_read(priv, RG_QP_CDR_FORCE_IBANDLPF_R_OFF);
+	val &= ~(0x7f << 6);
+	val |= (0x21 << 6);
+	val &= ~(0x3 << 16);
+	val |= (0x2 << 16);
+	val &= ~BIT(13);
+	an8855_write(priv, RG_QP_CDR_FORCE_IBANDLPF_R_OFF, val);
+
+	val = an8855_read(priv, RG_QP_CDR_PR_KBAND_DIV_PCIE);
+	val &= ~BIT(30);
+	an8855_write(priv, RG_QP_CDR_PR_KBAND_DIV_PCIE, val);
+
+	val = an8855_read(priv, RG_QP_CDR_PR_CKREF_DIV1);
+	val &= ~(0x7 << 24);
+	val |= (0x4 << 24);
+	an8855_write(priv, RG_QP_CDR_PR_CKREF_DIV1, val);
+
+	val = an8855_read(priv, PLL_CTRL_0);
+	val |= BIT(0);
+	an8855_write(priv, PLL_CTRL_0, val);
+
+	val = an8855_read(priv, RX_CTRL_26);
+	val &= ~BIT(23);
+	if (mode == SGMII_MODE_AN)
+		val |= BIT(26);
+
+	an8855_write(priv, RX_CTRL_26, val);
+
+	val = an8855_read(priv, RX_DLY_0);
+	val &= ~(0xff << 0);
+	val |= (0x6f << 0);
+	val |= BITS(8, 13);
+	an8855_write(priv, RX_DLY_0, val);
+
+	val = an8855_read(priv, RX_CTRL_42);
+	val &= ~(0x1fff << 0);
+	val |= (0x150 << 0);
+	an8855_write(priv, RX_CTRL_42, val);
+
+	val = an8855_read(priv, RX_CTRL_2);
+	val &= ~(0x1fff << 16);
+	val |= (0x150 << 16);
+	an8855_write(priv, RX_CTRL_2, val);
+
+	val = an8855_read(priv, PON_RXFEDIG_CTRL_9);
+	val &= ~(0x7 << 0);
+	val |= (0x1 << 0);
+	an8855_write(priv, PON_RXFEDIG_CTRL_9, val);
+
+	val = an8855_read(priv, RX_CTRL_8);
+	val &= ~(0xfff << 16);
+	val |= (0x200 << 16);
+	val &= ~(0x7fff << 0);
+	val |= (0xfff << 0);
+	an8855_write(priv, RX_CTRL_8, val);
+
+	/* Frequency memter */
+	val = an8855_read(priv, RX_CTRL_5);
+	val &= ~(0xfffff << 10);
+	val |= (0x28 << 10);
+	an8855_write(priv, RX_CTRL_5, val);
+
+	val = an8855_read(priv, RX_CTRL_6);
+	val &= ~(0xfffff << 0);
+	val |= (0x64 << 0);
+	an8855_write(priv, RX_CTRL_6, val);
+
+	val = an8855_read(priv, RX_CTRL_7);
+	val &= ~(0xfffff << 0);
+	val |= (0x2710 << 0);
+	an8855_write(priv, RX_CTRL_7, val);
+
+	if (mode == SGMII_MODE_FORCE) {
+		/* PCS Init */
+		val = an8855_read(priv, QP_DIG_MODE_CTRL_0);
+		val &= ~BIT(0);
+		val &= ~BITS(4, 5);
+		an8855_write(priv, QP_DIG_MODE_CTRL_0, val);
+
+		val = an8855_read(priv, RG_HSGMII_PCS_CTROL_1);
+		val &= ~BIT(30);
+		an8855_write(priv, RG_HSGMII_PCS_CTROL_1, val);
+
+		/* Rate Adaption - GMII path config. */
+		val = an8855_read(priv, RG_AN_SGMII_MODE_FORCE);
+		val |= BIT(0);
+		val &= ~BITS(4, 5);
+		an8855_write(priv, RG_AN_SGMII_MODE_FORCE, val);
+
+		val = an8855_read(priv, SGMII_STS_CTRL_0);
+		val |= BIT(2);
+		val &= ~(0x3 << 4);
+		val |= (0x2 << 4);
+		an8855_write(priv, SGMII_STS_CTRL_0, val);
+
+		val = an8855_read(priv, SGMII_REG_AN0);
+		val &= ~BIT(12);
+		an8855_write(priv, SGMII_REG_AN0, val);
+
+		val = an8855_read(priv, PHY_RX_FORCE_CTRL_0);
+		val |= BIT(4);
+		an8855_write(priv, PHY_RX_FORCE_CTRL_0, val);
+
+		val = an8855_read(priv, RATE_ADP_P0_CTRL_0);
+		val &= ~BITS(0, 3);
+		val |= BIT(28);
+		an8855_write(priv, RATE_ADP_P0_CTRL_0, val);
+
+		val = an8855_read(priv, RG_RATE_ADAPT_CTRL_0);
+		val |= BIT(0);
+		val |= BIT(4);
+		val |= BITS(26, 27);
+		an8855_write(priv, RG_RATE_ADAPT_CTRL_0, val);
+	} else {
+		/* PCS Init */
+		val = an8855_read(priv, RG_HSGMII_PCS_CTROL_1);
+		val &= ~BIT(30);
+		an8855_write(priv, RG_HSGMII_PCS_CTROL_1, val);
+
+		/* Set AN Ability - Interrupt */
+		val = an8855_read(priv, SGMII_REG_AN_FORCE_CL37);
+		val |= BIT(0);
+		an8855_write(priv, SGMII_REG_AN_FORCE_CL37, val);
+
+		val = an8855_read(priv, SGMII_REG_AN_13);
+		val &= ~(0x3f << 0);
+		val |= (0xb << 0);
+		val |= BIT(8);
+		an8855_write(priv, SGMII_REG_AN_13, val);
+
+		/* Rate Adaption - GMII path config. */
+		val = an8855_read(priv, SGMII_REG_AN0);
+		val |= BIT(12);
+		an8855_write(priv, SGMII_REG_AN0, val);
+
+		val = an8855_read(priv, MII_RA_AN_ENABLE);
+		val |= BIT(0);
+		an8855_write(priv, MII_RA_AN_ENABLE, val);
+
+		val = an8855_read(priv, RATE_ADP_P0_CTRL_0);
+		val |= BIT(28);
+		an8855_write(priv, RATE_ADP_P0_CTRL_0, val);
+
+		val = an8855_read(priv, RG_RATE_ADAPT_CTRL_0);
+		val |= BIT(0);
+		val |= BIT(4);
+		val |= BITS(26, 27);
+		an8855_write(priv, RG_RATE_ADAPT_CTRL_0, val);
+
+		/* Only for Co-SIM */
+
+		/* AN Speed up (Only for Co-SIM) */
+
+		/* Restart AN */
+		val = an8855_read(priv, SGMII_REG_AN0);
+		val |= BIT(9);
+		val |= BIT(15);
+		an8855_write(priv, SGMII_REG_AN0, val);
+	}
+
+	/* bypass flow control to MAC */
+	an8855_write(priv, MSG_RX_LIK_STS_0, 0x01010107);
+	an8855_write(priv, MSG_RX_LIK_STS_2, 0x00000EEF);
+
+	return 0;
+}
+
+static int
+an8855_sgmii_setup_mode_force(struct an8855_priv *priv, u32 port,
+					 phy_interface_t interface)
+{
+	return an8855_sgmii_setup(priv, SGMII_MODE_FORCE);
+}
+
+static int
+an8855_sgmii_setup_mode_an(struct an8855_priv *priv, int port,
+				      phy_interface_t interface)
+{
+	return an8855_sgmii_setup(priv, SGMII_MODE_AN);
+}
+
+static int
+an8855_mac_config(struct dsa_switch *ds, int port, unsigned int mode,
+		  phy_interface_t interface)
+{
+	struct an8855_priv *priv = ds->priv;
+	struct phy_device *phydev;
+	const struct dsa_port *dp;
+
+	if (!an8855_is_mac_port(port)) {
+		dev_err(priv->dev, "port %d is not a MAC port\n", port);
+		return -EINVAL;
+	}
+
+	switch (interface) {
+	case PHY_INTERFACE_MODE_RGMII:
+		dp = dsa_to_port(ds, port);
+		phydev = (dp->slave) ? dp->slave->phydev : NULL;
+		return an8855_rgmii_setup(priv, port, interface, phydev);
+	case PHY_INTERFACE_MODE_SGMII:
+		return an8855_sgmii_setup_mode_an(priv, port, interface);
+	case PHY_INTERFACE_MODE_2500BASEX:
+		if (phylink_autoneg_inband(mode))
+			return -EINVAL;
+		return an8855_set_hsgmii_mode(priv);
+	default:
+		return -EINVAL;
+	}
+
+	return -EINVAL;
+}
+
+static int
+an8855_sw_mac_config(struct dsa_switch *ds, int port, unsigned int mode,
+		     const struct phylink_link_state *state)
+{
+	struct an8855_priv *priv = ds->priv;
+
+	return priv->info->mac_port_config(ds, port, mode, state->interface);
+}
+
+static void
+an8855_phylink_mac_config(struct dsa_switch *ds, int port, unsigned int mode,
+			  const struct phylink_link_state *state)
+{
+	struct an8855_priv *priv = ds->priv;
+	u32 mcr_cur, mcr_new;
+
+	if (!an8855_phy_mode_supported(ds, port, state))
+		goto unsupported;
+
+	switch (port) {
+	case 0:		/* Internal phy */
+	case 1:
+	case 2:
+	case 3:
+	case 4:
+		if (state->interface != PHY_INTERFACE_MODE_GMII)
+			goto unsupported;
+		break;
+	case 5:
+		if (priv->p5_interface == state->interface)
+			break;
+
+		if (an8855_sw_mac_config(ds, port, mode, state) < 0)
+			goto unsupported;
+
+		priv->p5_interface = state->interface;
+		break;
+	default:
+unsupported:
+		dev_err(ds->dev, "%s: unsupported %s port: %i\n",
+			__func__, phy_modes(state->interface), port);
+		return;
+	}
+
+	if (phylink_autoneg_inband(mode) &&
+	    state->interface != PHY_INTERFACE_MODE_SGMII) {
+		dev_err(ds->dev, "%s: in-band negotiation unsupported\n",
+			__func__);
+		return;
+	}
+
+	mcr_cur = an8855_read(priv, AN8855_PMCR_P(port));
+	mcr_new = mcr_cur;
+	mcr_new &= ~PMCR_LINK_SETTINGS_MASK;
+	mcr_new |= PMCR_IFG_XMIT(1) | PMCR_MAC_MODE | PMCR_BACKOFF_EN |
+	    PMCR_BACKPR_EN | AN8855_FORCE_MODE;
+
+	if (mcr_new != mcr_cur)
+		an8855_write(priv, AN8855_PMCR_P(port), mcr_new);
+}
+
+static void
+an8855_phylink_mac_link_down(struct dsa_switch *ds, int port,
+					 unsigned int mode,
+					 phy_interface_t interface)
+{
+	struct an8855_priv *priv = ds->priv;
+
+	an8855_clear(priv, AN8855_PMCR_P(port), PMCR_LINK_SETTINGS_MASK);
+}
+
+static void
+an8855_phylink_mac_link_up(struct dsa_switch *ds, int port,
+				       unsigned int mode,
+				       phy_interface_t interface,
+				       struct phy_device *phydev,
+				       int speed, int duplex,
+				       bool tx_pause, bool rx_pause)
+{
+	struct an8855_priv *priv = ds->priv;
+	u32 mcr;
+
+	mcr = an8855_read(priv, AN8855_PMCR_P(port));
+	mcr |= PMCR_RX_EN | PMCR_TX_EN | PMCR_FORCE_LNK;
+	mcr &=
+	    ~(PMCR_FORCE_FDX | PMCR_SPEED_MASK | PMCR_TX_FC_EN | PMCR_RX_FC_EN);
+
+	if (interface == PHY_INTERFACE_MODE_RGMII
+	    || interface == PHY_INTERFACE_MODE_SGMII) {
+		speed = SPEED_1000;
+		duplex = DUPLEX_FULL;
+	} else if (interface == PHY_INTERFACE_MODE_2500BASEX) {
+		speed = SPEED_2500;
+		duplex = DUPLEX_FULL;
+	}
+
+	switch (speed) {
+	case SPEED_2500:
+		mcr |= PMCR_FORCE_SPEED_2500;
+		break;
+	case SPEED_1000:
+		mcr |= PMCR_FORCE_SPEED_1000;
+		if (priv->eee_enable & BIT(port))
+			mcr |= PMCR_FORCE_EEE1G;
+		break;
+	case SPEED_100:
+		mcr |= PMCR_FORCE_SPEED_100;
+		if (priv->eee_enable & BIT(port))
+			mcr |= PMCR_FORCE_EEE100;
+		break;
+	}
+	if (duplex == DUPLEX_FULL) {
+		mcr |= PMCR_FORCE_FDX;
+		if (tx_pause)
+			mcr |= PMCR_TX_FC_EN;
+		if (rx_pause)
+			mcr |= PMCR_RX_FC_EN;
+	}
+
+	an8855_write(priv, AN8855_PMCR_P(port), mcr);
+}
+
+static int
+an8855_cpu_port_config(struct dsa_switch *ds, int port)
+{
+	struct an8855_priv *priv = ds->priv;
+	phy_interface_t interface = PHY_INTERFACE_MODE_NA;
+	int speed;
+
+	switch (port) {
+	case 5:
+		interface = PHY_INTERFACE_MODE_2500BASEX;
+
+		priv->p5_interface = interface;
+		break;
+	};
+	if (interface == PHY_INTERFACE_MODE_NA)
+		dev_err(priv->dev, "invalid interface\n");
+
+	if (interface == PHY_INTERFACE_MODE_2500BASEX)
+		speed = SPEED_2500;
+	else
+		speed = SPEED_1000;
+
+	an8855_mac_config(ds, port, MLO_AN_FIXED, interface);
+	an8855_write(priv, AN8855_PMCR_P(port),
+		     PMCR_CPU_PORT_SETTING(priv->id));
+	an8855_phylink_mac_link_up(ds, port, MLO_AN_FIXED, interface, NULL,
+				   speed, DUPLEX_FULL, true, true);
+
+	return 0;
+}
+
+static void
+an8855_mac_port_validate(struct dsa_switch *ds, int port,
+				     unsigned long *supported)
+{
+	struct an8855_priv *priv = ds->priv;
+
+	an8855_sgmii_validate(priv, port, supported);
+}
+
+static void
+an8855_phylink_validate(struct dsa_switch *ds, int port,
+			unsigned long *supported,
+			struct phylink_link_state *state)
+{
+	struct an8855_priv *priv = ds->priv;
+	__ETHTOOL_DECLARE_LINK_MODE_MASK(mask) = {0,};
+
+	if (state->interface != PHY_INTERFACE_MODE_NA &&
+	    !an8855_phy_mode_supported(ds, port, state)) {
+		linkmode_zero(supported);
+		return;
+	}
+
+	phylink_set_port_modes(mask);
+
+	if (state->interface != PHY_INTERFACE_MODE_TRGMII
+	    || state->interface != PHY_INTERFACE_MODE_USXGMII
+	    || state->interface != PHY_INTERFACE_MODE_10GKR
+	    || !phy_interface_mode_is_8023z(state->interface)) {
+		phylink_set(mask, 10baseT_Half);
+		phylink_set(mask, 10baseT_Full);
+		phylink_set(mask, 100baseT_Half);
+		phylink_set(mask, 100baseT_Full);
+		phylink_set(mask, Autoneg);
+	}
+
+	/* This switch only supports 1G full-duplex. */
+	if (state->interface != PHY_INTERFACE_MODE_MII)
+		phylink_set(mask, 1000baseT_Full);
+
+	priv->info->mac_port_validate(ds, port, mask);
+
+	phylink_set(mask, Pause);
+	phylink_set(mask, Asym_Pause);
+
+	linkmode_and(supported, supported, mask);
+	linkmode_and(state->advertising, state->advertising, mask);
+
+	/* We can only operate at 2500BaseX or 1000BaseX.  If requested
+	 * to advertise both, only report advertising at 2500BaseX.
+	 */
+	phylink_helper_basex_speed(state);
+}
+
+static int
+an8855_get_mac_eee(struct dsa_switch *ds, int port,
+			      struct ethtool_eee *e)
+{
+	struct an8855_priv *priv = ds->priv;
+	u32 eeecr, pmsr, ckgcr;
+
+	e->eee_enabled = !!(priv->eee_enable & BIT(port));
+
+	if (e->eee_enabled) {
+		eeecr = an8855_read(priv, AN8855_PMEEECR_P(port));
+		e->tx_lpi_enabled = !(eeecr & LPI_MODE_EN);
+		ckgcr = an8855_read(priv, AN8855_CKGCR);
+		e->tx_lpi_timer =
+		    ((ckgcr & LPI_TXIDLE_THD_MASK) >> LPI_TXIDLE_THD) / 500;
+		pmsr = an8855_read(priv, AN8855_PMSR_P(port));
+		e->eee_active = e->eee_enabled
+		    && !!(pmsr & (PMSR_EEE1G | PMSR_EEE100M));
+	} else {
+		e->tx_lpi_enabled = 0;
+		e->tx_lpi_timer = 0;
+		e->eee_active = 0;
+	}
+	return 0;
+}
+
+static int
+an8855_set_mac_eee(struct dsa_switch *ds, int port,
+			      struct ethtool_eee *e)
+{
+	struct an8855_priv *priv = ds->priv;
+	u32 eeecr;
+
+	if (e->eee_enabled) {
+		priv->eee_enable |= BIT(port);
+		eeecr = an8855_read(priv, AN8855_PMEEECR_P(port));
+		eeecr &= ~LPI_MODE_EN;
+		if (e->tx_lpi_enabled)
+			eeecr |= LPI_MODE_EN;
+		an8855_write(priv, AN8855_PMEEECR_P(port), eeecr);
+	} else {
+		priv->eee_enable &= ~(BIT(port));
+		eeecr = an8855_read(priv, AN8855_PMEEECR_P(port));
+		eeecr &= ~LPI_MODE_EN;
+		an8855_write(priv, AN8855_PMEEECR_P(port), eeecr);
+	}
+
+	return 0;
+}
+
+static int
+an8855_phylink_mac_link_state(struct dsa_switch *ds, int port,
+			      struct phylink_link_state *state)
+{
+	struct an8855_priv *priv = ds->priv;
+	u32 pmsr;
+
+	if (port < 0 || port >= AN8855_NUM_PORTS)
+		return -EINVAL;
+
+	pmsr = an8855_read(priv, AN8855_PMSR_P(port));
+
+	state->link = (pmsr & PMSR_LINK);
+	state->an_complete = state->link;
+	state->duplex = !!(pmsr & PMSR_DPX);
+
+	switch (pmsr & PMSR_SPEED_MASK) {
+	case PMSR_SPEED_10:
+		state->speed = SPEED_10;
+		break;
+	case PMSR_SPEED_100:
+		state->speed = SPEED_100;
+		break;
+	case PMSR_SPEED_1000:
+		state->speed = SPEED_1000;
+		break;
+	case PMSR_SPEED_2500:
+		state->speed = SPEED_2500;
+		break;
+	default:
+		state->speed = SPEED_UNKNOWN;
+		break;
+	}
+
+	state->pause &= ~(MLO_PAUSE_RX | MLO_PAUSE_TX);
+	if (pmsr & PMSR_RX_FC)
+		state->pause |= MLO_PAUSE_RX;
+	if (pmsr & PMSR_TX_FC)
+		state->pause |= MLO_PAUSE_TX;
+
+	return 1;
+}
+
+static int
+an8855_sw_phylink_mac_link_state(struct dsa_switch *ds, int port,
+				 struct phylink_link_state *state)
+{
+	struct an8855_priv *priv = ds->priv;
+
+	return priv->info->mac_port_get_state(ds, port, state);
+}
+
+static int
+an8855_sw_setup(struct dsa_switch *ds)
+{
+	struct an8855_priv *priv = ds->priv;
+
+	return priv->info->sw_setup(ds);
+}
+
+static int
+an8855_sw_phy_read(struct dsa_switch *ds, int port, int regnum)
+{
+	struct an8855_priv *priv = ds->priv;
+
+	return priv->info->phy_read(ds, port, regnum);
+}
+
+static int
+an8855_sw_phy_write(struct dsa_switch *ds, int port, int regnum, u16 val)
+{
+	struct an8855_priv *priv = ds->priv;
+
+	return priv->info->phy_write(ds, port, regnum, val);
+}
+
+static const struct dsa_switch_ops an8855_switch_ops = {
+	.get_tag_protocol = air_get_tag_protocol,
+	.setup = an8855_sw_setup,
+	.get_strings = an8855_get_strings,
+	.phy_read = an8855_sw_phy_read,
+	.phy_write = an8855_sw_phy_write,
+	.get_ethtool_stats = an8855_get_ethtool_stats,
+	.get_sset_count = an8855_get_sset_count,
+	.port_enable = an8855_port_enable,
+	.port_disable = an8855_port_disable,
+	.port_stp_state_set = an8855_stp_state_set,
+	.port_bridge_join = an8855_port_bridge_join,
+	.port_bridge_leave = an8855_port_bridge_leave,
+	.port_fdb_add = an8855_port_fdb_add,
+	.port_fdb_del = an8855_port_fdb_del,
+	.port_fdb_dump = an8855_port_fdb_dump,
+	.port_vlan_filtering = an8855_port_vlan_filtering,
+	.port_vlan_prepare = an8855_port_vlan_prepare,
+	.port_vlan_add = an8855_port_vlan_add,
+	.port_vlan_del = an8855_port_vlan_del,
+	.port_mirror_add = an8855_port_mirror_add,
+	.port_mirror_del = an8855_port_mirror_del,
+	.phylink_validate = an8855_phylink_validate,
+	.phylink_mac_link_state = an8855_sw_phylink_mac_link_state,
+	.phylink_mac_config = an8855_phylink_mac_config,
+	.phylink_mac_link_down = an8855_phylink_mac_link_down,
+	.phylink_mac_link_up = an8855_phylink_mac_link_up,
+	.get_mac_eee = an8855_get_mac_eee,
+	.set_mac_eee = an8855_set_mac_eee,
+};
+
+static const struct an8855_dev_info an8855_table[] = {
+	[ID_AN8855] = {
+		.id = ID_AN8855,
+		.sw_setup = an8855_setup,
+		.phy_read = an8855_phy_read,
+		.phy_write = an8855_phy_write,
+		.pad_setup = an8855_pad_setup,
+		.cpu_port_config = an8855_cpu_port_config,
+		.phy_mode_supported = an8855_phy_supported,
+		.mac_port_validate = an8855_mac_port_validate,
+		.mac_port_get_state = an8855_phylink_mac_link_state,
+		.mac_port_config = an8855_mac_config,
+	},
+};
+
+static const struct of_device_id an8855_of_match[] = {
+	{.compatible = "airoha,an8855", .data = &an8855_table[ID_AN8855],
+	},
+	{ /* sentinel */ },
+};
+
+MODULE_DEVICE_TABLE(of, an8855_of_match);
+
+static int
+an8855_probe(struct mdio_device *mdiodev)
+{
+	struct an8855_priv *priv;
+	struct device_node *dn;
+	struct device_node *switch_node = NULL;
+	int ret;
+
+	dn = mdiodev->dev.of_node;
+
+	priv = devm_kzalloc(&mdiodev->dev, sizeof(*priv), GFP_KERNEL);
+	if (!priv)
+		return -ENOMEM;
+
+	priv->ds = dsa_switch_alloc(&mdiodev->dev, AN8855_NUM_PORTS);
+	if (!priv->ds)
+		return -ENOMEM;
+
+	/* Get the hardware identifier from the devicetree node.
+	 * We will need it for some of the clock and regulator setup.
+	 */
+	priv->info = of_device_get_match_data(&mdiodev->dev);
+	if (!priv->info)
+		return -EINVAL;
+
+	/* Sanity check if these required device operations are filled
+	 * properly.
+	 */
+	if (!priv->info->sw_setup || !priv->info->pad_setup ||
+	    !priv->info->phy_read || !priv->info->phy_write ||
+	    !priv->info->phy_mode_supported ||
+	    !priv->info->mac_port_validate ||
+	    !priv->info->mac_port_get_state || !priv->info->mac_port_config)
+		return -EINVAL;
+
+	dev_info(&mdiodev->dev, "Airoha AN8855 DSA driver, version %s\n",
+			ARHT_AN8855_DSA_DRIVER_VER);
+	priv->phy_base = AN8855_GPHY_SMI_ADDR_DEFAULT;
+	priv->id = priv->info->id;
+
+	priv->reset = devm_gpiod_get_optional(&mdiodev->dev, "reset",
+					      GPIOD_OUT_LOW);
+	if (IS_ERR(priv->reset)) {
+		dev_err(&mdiodev->dev, "Couldn't get our reset line\n");
+		return PTR_ERR(priv->reset);
+	}
+
+	switch_node = of_find_node_by_name(NULL, "switch0");
+	if (switch_node) {
+		priv->base = of_iomap(switch_node, 0);
+		if (priv->base == NULL) {
+			dev_err(&mdiodev->dev, "of_iomap failed\n");
+			return -ENOMEM;
+		}
+	}
+
+	ret = of_property_read_u32(dn, "changesmiaddr", &priv->phy_base_new);
+	if ((ret < 0) || (priv->phy_base_new > 0x1f))
+		priv->phy_base_new = -1;
+
+	priv->bus = mdiodev->bus;
+	priv->dev = &mdiodev->dev;
+	priv->ds->priv = priv;
+	priv->ds->ops = &an8855_switch_ops;
+	mutex_init(&priv->reg_mutex);
+	dev_set_drvdata(&mdiodev->dev, priv);
+
+	ret = dsa_register_switch(priv->ds);
+	if (ret) {
+		if (priv->base)
+			iounmap(priv->base);
+
+		return ret;
+	}
+	an8855_nl_init(&priv);
+
+	return 0;
+}
+
+static void
+an8855_remove(struct mdio_device *mdiodev)
+{
+	struct an8855_priv *priv = dev_get_drvdata(&mdiodev->dev);
+
+	dsa_unregister_switch(priv->ds);
+	mutex_destroy(&priv->reg_mutex);
+
+	if (priv->base)
+		iounmap(priv->base);
+
+	an8855_nl_exit();
+}
+
+static struct mdio_driver an8855_mdio_driver = {
+	.probe = an8855_probe,
+	.remove = an8855_remove,
+	.mdiodrv.driver = {
+		.name = "an8855",
+		.of_match_table = an8855_of_match,
+	},
+};
+
+mdio_module_driver(an8855_mdio_driver);
+
+MODULE_AUTHOR("Min Yao <min.yao@airoha.com>");
+MODULE_DESCRIPTION("Driver for Airoha AN8855 Switch");
+MODULE_VERSION(ARHT_AN8855_DSA_DRIVER_VER);
+MODULE_LICENSE("GPL");
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/dsa/airoha/an8855/an8855.h b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/dsa/airoha/an8855/an8855.h
new file mode 100644
index 0000000..531d9be
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/dsa/airoha/an8855/an8855.h
@@ -0,0 +1,580 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (C) 2023 Min Yao <min.yao@airoha.com>
+ */
+
+#ifndef __AN8855_H
+#define __AN8855_H
+
+#define BITS(m, n)	 (~(BIT(m) - 1) & ((BIT(n) - 1) | BIT(n)))
+
+#define AN8855_NUM_PORTS				6
+#define AN8855_CPU_PORT					5
+#define AN8855_NUM_FDB_RECORDS			2048
+#define AN8855_ALL_MEMBERS				0x3f
+#define AN8855_RESERVED_VLAN			2
+#define AN8855_GPHY_SMI_ADDR_DEFAULT	1
+
+enum an8855_id {
+	ID_AN8855 = 0,
+};
+
+enum sgmii_mode {
+	SGMII_MODE_AN,
+	SGMII_MODE_FORCE,
+};
+
+/* Registers to mac forward control for unknown frames */
+#define AN8855_MFC			0x10200010
+#define	 CPU_EN				BIT(15)
+#define	 CPU_PORT(x)		((x) << 8)
+#define	 CPU_MASK			(0x9f << 8)
+
+#define AN8855_UNUF			0x102000b4
+#define AN8855_UNMF			0x102000b8
+#define AN8855_BCF			0x102000bc
+
+/* Registers for mirror port control */
+#define	AN8855_MIR						  0x102000cc
+#define	 AN8855_MIRROR_EN				  BIT(7)
+#define	 AN8855_MIRROR_MASK				  (0x1f)
+#define	 AN8855_MIRROR_PORT_GET(x)		  ((x) & AN8855_MIRROR_MASK)
+#define	 AN8855_MIRROR_PORT_SET(x)		  ((x) & AN8855_MIRROR_MASK)
+
+/* Registers for BPDU and PAE frame control*/
+#define AN8855_BPC					0x102000D0
+#define	AN8855_BPDU_PORT_FW_MASK	GENMASK(2, 0)
+
+enum an8855_bpdu_port_fw {
+	AN8855_BPDU_FOLLOW_MFC,
+	AN8855_BPDU_CPU_EXCLUDE = 4,
+	AN8855_BPDU_CPU_INCLUDE = 5,
+	AN8855_BPDU_CPU_ONLY = 6,
+	AN8855_BPDU_DROP = 7,
+};
+
+/* Registers for address table access */
+#define AN8855_ATA1			0x10200304
+#define AN8855_ATA2			0x10200308
+
+/* Register for address table write data */
+#define AN8855_ATWD			0x10200324
+#define AN8855_ATWD2		0x10200328
+
+/* Register for address table control */
+#define AN8855_ATC			0x10200300
+#define	 ATC_BUSY			BIT(31)
+#define	 ATC_INVALID		~BIT(30)
+#define	 ATC_HASH			16
+#define	 ATC_HASH_MASK		0x1ff
+#define	 ATC_HIT			12
+#define	 ATC_HIT_MASK		0xf
+#define	 ATC_MAT(x)			(((x) & 0x1f) << 7)
+#define	 ATC_MAT_MACTAB		ATC_MAT(1)
+
+enum an8855_fdb_cmds {
+	AN8855_FDB_READ = 0,
+	AN8855_FDB_WRITE = 1,
+	AN8855_FDB_FLUSH = 2,
+	AN8855_FDB_START = 4,
+	AN8855_FDB_NEXT = 5,
+};
+
+/* Registers for table search read address */
+#define AN8855_ATRDS		0x10200330
+#define AN8855_ATRD0		0x10200334
+#define	 CVID				10
+#define	 CVID_MASK			0xfff
+
+enum an8855_fdb_type {
+	AN8855_MAC_TB_TY_MAC = 0,
+	AN8855_MAC_TB_TY_DIP = 1,
+	AN8855_MAC_TB_TY_DIP_SIP = 2,
+};
+
+#define AN8855_ATRD1		0x10200338
+#define	 MAC_BYTE_4			24
+#define	 MAC_BYTE_5			16
+#define	 AGE_TIMER			3
+#define	 AGE_TIMER_MASK		0x1ff
+
+#define AN8855_ATRD2		0x1020033c
+#define	 MAC_BYTE_0			24
+#define	 MAC_BYTE_1			16
+#define	 MAC_BYTE_2			8
+#define	 MAC_BYTE_3			0
+#define	 MAC_BYTE_MASK		0xff
+
+#define AN8855_ATRD3		0x10200340
+#define	 PORT_MAP			4
+#define	 PORT_MAP_MASK		0xff
+
+/* Register for vlan table control */
+#define AN8855_VTCR			0x10200600
+#define	 VTCR_BUSY			BIT(31)
+#define	 VTCR_FUNC(x)		(((x) & 0xf) << 12)
+#define	 VTCR_VID			((x) & 0xfff)
+
+enum an8855_vlan_cmd {
+	/* Read/Write the specified VID entry from VAWD register based
+	 * on VID.
+	 */
+	AN8855_VTCR_RD_VID = 0,
+	AN8855_VTCR_WR_VID = 1,
+};
+
+/* Register for setup vlan write data */
+#define AN8855_VAWD0			0x10200604
+
+/* Independent VLAN Learning */
+#define	 IVL_MAC			BIT(5)
+/* Per VLAN Egress Tag Control */
+#define	 VTAG_EN			BIT(10)
+/* Egress Tag Control */
+#define PORT_EG_CTRL_SHIFT	12
+/* VLAN Member Control */
+#define	 PORT_MEM_SHFT		26
+#define	 PORT_MEM_MASK		0x7f
+#define	 PORT_MEM(x)		(((x) & PORT_MEM_MASK) << PORT_MEM_SHFT)
+/* VLAN Entry Valid */
+#define	 VLAN_VALID			BIT(0)
+
+#define AN8855_VAWD1			0x10200608
+#define	 PORT_STAG			BIT(1)
+/* Egress Tag Control */
+#define	 ETAG_CTRL_P(p, x)		(((x) & 0x3) << ((p) << 1))
+#define	 ETAG_CTRL_P_MASK(p)	ETAG_CTRL_P(p, 3)
+#define	 ETAG_CTRL_MASK			(0x3FFF)
+
+#define AN8855_VARD0			0x10200618
+
+enum an8855_vlan_egress_attr {
+	AN8855_VLAN_EGRESS_UNTAG = 0,
+	AN8855_VLAN_EGRESS_TAG = 2,
+	AN8855_VLAN_EGRESS_STACK = 3,
+};
+
+/* Register for port STP state control */
+#define AN8855_SSP_P(x)		(0x10208000 + ((x) * 0x200))
+#define	 FID_PST(x)			((x) & 0x3)
+#define	 FID_PST_MASK		FID_PST(0x3)
+
+enum an8855_stp_state {
+	AN8855_STP_DISABLED = 0,
+	AN8855_STP_BLOCKING = 1,
+	AN8855_STP_LISTENING = 1,
+	AN8855_STP_LEARNING = 2,
+	AN8855_STP_FORWARDING = 3
+};
+
+/* Register for port control */
+#define AN8855_PCR_P(x)		(0x10208004 + ((x) * 0x200))
+#define	 PORT_TX_MIR		BIT(20)
+#define	 PORT_RX_MIR		BIT(16)
+#define	 PORT_VLAN(x)		((x) & 0x3)
+
+enum an8855_port_mode {
+	/* Port Matrix Mode: Frames are forwarded by the PCR_MATRIX members. */
+	AN8855_PORT_MATRIX_MODE = PORT_VLAN(0),
+
+	/* Fallback Mode: Forward received frames with ingress ports that do
+	 * not belong to the VLAN member. Frames whose VID is not listed on
+	 * the VLAN table are forwarded by the PCR_MATRIX members.
+	 */
+	AN8855_PORT_FALLBACK_MODE = PORT_VLAN(1),
+
+	/* Security Mode: Discard any frame due to ingress membership
+	 * violation or VID missed on the VLAN table.
+	 */
+	AN8855_PORT_SECURITY_MODE = PORT_VLAN(3),
+};
+
+#define	 PORT_PRI(x)		(((x) & 0x7) << 24)
+#define	 EG_TAG(x)			(((x) & 0x3) << 28)
+#define	 PCR_PORT_VLAN_MASK	PORT_VLAN(3)
+
+/* Register for port security control */
+#define AN8855_PSC_P(x)		(0x1020800c + ((x) * 0x200))
+#define	 SA_DIS				BIT(4)
+
+/* Register for port vlan control */
+#define AN8855_PVC_P(x)			(0x10208010 + ((x) * 0x200))
+#define	 PORT_SPEC_REPLACE_MODE	BIT(11)
+#define	 PORT_SPEC_TAG			BIT(5)
+#define	 PVC_EG_TAG(x)			(((x) & 0x7) << 8)
+#define	 PVC_EG_TAG_MASK		PVC_EG_TAG(7)
+#define	 VLAN_ATTR(x)			(((x) & 0x3) << 6)
+#define	 VLAN_ATTR_MASK			VLAN_ATTR(3)
+
+#define AN8855_PORTMATRIX_P(x)	(0x10208044 + ((x) * 0x200))
+#define PORTMATRIX_MATRIX(x)	((x) & 0x3f)
+#define PORTMATRIX_MASK			PORTMATRIX_MATRIX(0x3f)
+#define PORTMATRIX_CLR			PORTMATRIX_MATRIX(0)
+
+enum an8855_vlan_port_eg_tag {
+	AN8855_VLAN_EG_DISABLED = 0,
+	AN8855_VLAN_EG_CONSISTENT = 1,
+};
+
+enum an8855_vlan_port_attr {
+	AN8855_VLAN_USER = 0,
+	AN8855_VLAN_TRANSPARENT = 3,
+};
+
+/* Register for port PVID */
+#define AN8855_PVID_P(x)		(0x10208048 + ((x) * 0x200))
+#define	 G0_PORT_VID(x)			(((x) & 0xfff) << 0)
+#define	 G0_PORT_VID_MASK		G0_PORT_VID(0xfff)
+#define	 G0_PORT_VID_DEF		G0_PORT_VID(1)
+
+/* Register for port MAC control register */
+#define AN8855_PMCR_P(x)		(0x10210000 + ((x) * 0x200))
+#define	 PMCR_IFG_XMIT(x)		(((x) & 0x3) << 20)
+#define	 PMCR_EXT_PHY			BIT(19)
+#define	 PMCR_MAC_MODE			BIT(18)
+#define	 PMCR_FORCE_MODE		BIT(31)
+#define	 PMCR_TX_EN				BIT(16)
+#define	 PMCR_RX_EN				BIT(15)
+#define	 PMCR_BACKOFF_EN		BIT(12)
+#define	 PMCR_BACKPR_EN			BIT(11)
+#define	 PMCR_FORCE_EEE2P5G		BIT(8)
+#define	 PMCR_FORCE_EEE1G		BIT(7)
+#define	 PMCR_FORCE_EEE100		BIT(6)
+#define	 PMCR_TX_FC_EN			BIT(5)
+#define	 PMCR_RX_FC_EN			BIT(4)
+#define	 PMCR_FORCE_SPEED_2500	(0x3 << 28)
+#define	 PMCR_FORCE_SPEED_1000	(0x2 << 28)
+#define	 PMCR_FORCE_SPEED_100	(0x1 << 28)
+#define	 PMCR_FORCE_FDX			BIT(25)
+#define	 PMCR_FORCE_LNK			BIT(24)
+#define	 PMCR_SPEED_MASK		BITS(28, 30)
+#define	 AN8855_FORCE_LNK		BIT(31)
+#define	 AN8855_FORCE_MODE		(AN8855_FORCE_LNK)
+#define	 PMCR_LINK_SETTINGS_MASK	(PMCR_TX_EN | \
+					 PMCR_RX_EN | PMCR_FORCE_SPEED_2500 | \
+					 PMCR_TX_FC_EN | PMCR_RX_FC_EN | \
+					 PMCR_FORCE_FDX | PMCR_FORCE_LNK)
+#define	 PMCR_CPU_PORT_SETTING(id)	(AN8855_FORCE_MODE | \
+					 PMCR_IFG_XMIT(1) | PMCR_MAC_MODE | \
+					 PMCR_BACKOFF_EN | PMCR_BACKPR_EN | \
+					 PMCR_TX_EN | PMCR_RX_EN | \
+					 PMCR_TX_FC_EN | PMCR_RX_FC_EN | \
+					 PMCR_FORCE_SPEED_2500 | \
+					 PMCR_FORCE_FDX | PMCR_FORCE_LNK)
+
+#define AN8855_PMSR_P(x)		(0x10210010 + (x) * 0x200)
+#define	 PMSR_EEE1G				BIT(7)
+#define	 PMSR_EEE100M			BIT(6)
+#define	 PMSR_RX_FC				BIT(5)
+#define	 PMSR_TX_FC				BIT(4)
+#define	 PMSR_SPEED_2500		(0x3 << 28)
+#define	 PMSR_SPEED_1000		(0x2 << 28)
+#define	 PMSR_SPEED_100			(0x1 << 28)
+#define	 PMSR_SPEED_10			(0x0 << 28)
+#define	 PMSR_SPEED_MASK		BITS(28, 30)
+#define	 PMSR_DPX				BIT(25)
+#define	 PMSR_LINK				BIT(24)
+
+#define AN8855_PMEEECR_P(x)		(0x10210004 + (x) * 0x200)
+#define	 WAKEUP_TIME_2500(x)	((x & 0xFF) << 16)
+#define	 WAKEUP_TIME_1000(x)	((x & 0xFF) << 8)
+#define	 WAKEUP_TIME_100(x)		((x & 0xFF) << 0)
+#define	 LPI_MODE_EN			BIT(31)
+#define AN8855_PMEEECR2_P(x)	(0x10210008 + (x) * 0x200)
+#define	 WAKEUP_TIME_5000(x)	((x & 0xFF) << 0)
+
+#define AN8855_CKGCR			(0x10213e1c)
+#define LPI_TXIDLE_THD			14
+#define LPI_TXIDLE_THD_MASK		BITS(14, 31)
+
+/* Register for MIB */
+#define AN8855_PORT_MIB_COUNTER(x)	(0x10214000 + (x) * 0x200)
+#define AN8855_MIB_CCR			0x10213e30
+#define	 CCR_MIB_ENABLE			BIT(31)
+#define	 CCR_RX_OCT_CNT_GOOD	BIT(7)
+#define	 CCR_RX_OCT_CNT_BAD		BIT(6)
+#define	 CCR_TX_OCT_CNT_GOOD	BIT(5)
+#define	 CCR_TX_OCT_CNT_BAD		BIT(4)
+#define	 CCR_RX_OCT_CNT_GOOD_2	BIT(3)
+#define	 CCR_RX_OCT_CNT_BAD_2	BIT(2)
+#define	 CCR_TX_OCT_CNT_GOOD_2	BIT(1)
+#define	 CCR_TX_OCT_CNT_BAD_2	BIT(0)
+#define	 CCR_MIB_FLUSH			(CCR_RX_OCT_CNT_GOOD | \
+					 CCR_RX_OCT_CNT_BAD | \
+					 CCR_TX_OCT_CNT_GOOD | \
+					 CCR_TX_OCT_CNT_BAD | \
+					 CCR_RX_OCT_CNT_GOOD_2 | \
+					 CCR_RX_OCT_CNT_BAD_2 | \
+					 CCR_TX_OCT_CNT_GOOD_2 | \
+					 CCR_TX_OCT_CNT_BAD_2)
+#define	 CCR_MIB_ACTIVATE		(CCR_MIB_ENABLE | \
+					 CCR_RX_OCT_CNT_GOOD | \
+					 CCR_RX_OCT_CNT_BAD | \
+					 CCR_TX_OCT_CNT_GOOD | \
+					 CCR_TX_OCT_CNT_BAD | \
+					 CCR_RX_OCT_CNT_GOOD_2 | \
+					 CCR_RX_OCT_CNT_BAD_2 | \
+					 CCR_TX_OCT_CNT_GOOD_2 | \
+					 CCR_TX_OCT_CNT_BAD_2)
+
+/* AN8855 SGMII register group */
+#define AN8855_SGMII_REG_BASE		0x10220000
+#define AN8855_SGMII_REG(p, r)		(AN8855_SGMII_REG_BASE + \
+					((p) - 5) * 0x1000 + (r))
+
+/* Register forSGMII PCS_CONTROL_1 */
+#define AN8855_PCS_CONTROL_1(p)		AN8855_SGMII_REG(p, 0x00)
+#define	 AN8855_SGMII_AN_ENABLE		BIT(12)
+#define	 AN8855_SGMII_AN_RESTART	BIT(9)
+
+/* Register for system reset */
+#define AN8855_RST_CTRL			0x100050c0
+#define	 SYS_CTRL_SYS_RST		BIT(31)
+
+/* Register for hw trap status */
+#define AN8855_HWTRAP			0x1000009c
+
+#define AN8855_CREV				0x10005000
+#define	 AN8855_ID				0x8855
+
+#define SCU_BASE				0x10000000
+#define RG_RGMII_TXCK_C			(SCU_BASE + 0x1d0)
+
+#define HSGMII_AN_CSR_BASE		0x10220000
+#define SGMII_REG_AN0			(HSGMII_AN_CSR_BASE + 0x000)
+#define SGMII_REG_AN_13			(HSGMII_AN_CSR_BASE + 0x034)
+#define SGMII_REG_AN_FORCE_CL37	(HSGMII_AN_CSR_BASE + 0x060)
+
+#define HSGMII_CSR_PCS_BASE		0x10220000
+#define RG_HSGMII_PCS_CTROL_1	(HSGMII_CSR_PCS_BASE + 0xa00)
+#define RG_AN_SGMII_MODE_FORCE	(HSGMII_CSR_PCS_BASE + 0xa24)
+
+#define MULTI_SGMII_CSR_BASE	0x10224000
+#define SGMII_STS_CTRL_0		(MULTI_SGMII_CSR_BASE + 0x018)
+#define MSG_RX_CTRL_0			(MULTI_SGMII_CSR_BASE + 0x100)
+#define MSG_RX_LIK_STS_0		(MULTI_SGMII_CSR_BASE + 0x514)
+#define MSG_RX_LIK_STS_2		(MULTI_SGMII_CSR_BASE + 0x51c)
+#define PHY_RX_FORCE_CTRL_0		(MULTI_SGMII_CSR_BASE + 0x520)
+
+#define XFI_CSR_PCS_BASE		0x10225000
+#define RG_USXGMII_AN_CONTROL_0	(XFI_CSR_PCS_BASE + 0xbf8)
+
+#define MULTI_PHY_RA_CSR_BASE	0x10226000
+#define RG_RATE_ADAPT_CTRL_0	(MULTI_PHY_RA_CSR_BASE + 0x000)
+#define RATE_ADP_P0_CTRL_0		(MULTI_PHY_RA_CSR_BASE + 0x100)
+#define MII_RA_AN_ENABLE		(MULTI_PHY_RA_CSR_BASE + 0x300)
+
+#define QP_DIG_CSR_BASE			0x1022a000
+#define QP_CK_RST_CTRL_4		(QP_DIG_CSR_BASE + 0x310)
+#define QP_DIG_MODE_CTRL_0		(QP_DIG_CSR_BASE + 0x324)
+#define QP_DIG_MODE_CTRL_1		(QP_DIG_CSR_BASE + 0x330)
+
+#define SERDES_WRAPPER_BASE		0x1022c000
+#define USGMII_CTRL_0			(SERDES_WRAPPER_BASE + 0x000)
+
+#define QP_PMA_TOP_BASE			0x1022e000
+#define PON_RXFEDIG_CTRL_0		(QP_PMA_TOP_BASE + 0x100)
+#define PON_RXFEDIG_CTRL_9		(QP_PMA_TOP_BASE + 0x124)
+
+#define SS_LCPLL_PWCTL_SETTING_2	(QP_PMA_TOP_BASE + 0x208)
+#define SS_LCPLL_TDC_FLT_2			(QP_PMA_TOP_BASE + 0x230)
+#define SS_LCPLL_TDC_FLT_5			(QP_PMA_TOP_BASE + 0x23c)
+#define SS_LCPLL_TDC_PCW_1			(QP_PMA_TOP_BASE + 0x248)
+#define INTF_CTRL_8			(QP_PMA_TOP_BASE + 0x320)
+#define INTF_CTRL_9			(QP_PMA_TOP_BASE + 0x324)
+#define PLL_CTRL_0			(QP_PMA_TOP_BASE + 0x400)
+#define PLL_CTRL_2			(QP_PMA_TOP_BASE + 0x408)
+#define PLL_CTRL_3			(QP_PMA_TOP_BASE + 0x40c)
+#define PLL_CTRL_4			(QP_PMA_TOP_BASE + 0x410)
+#define PLL_CK_CTRL_0		(QP_PMA_TOP_BASE + 0x414)
+#define RX_DLY_0			(QP_PMA_TOP_BASE + 0x614)
+#define RX_CTRL_2			(QP_PMA_TOP_BASE + 0x630)
+#define RX_CTRL_5			(QP_PMA_TOP_BASE + 0x63c)
+#define RX_CTRL_6			(QP_PMA_TOP_BASE + 0x640)
+#define RX_CTRL_7			(QP_PMA_TOP_BASE + 0x644)
+#define RX_CTRL_8			(QP_PMA_TOP_BASE + 0x648)
+#define RX_CTRL_26			(QP_PMA_TOP_BASE + 0x690)
+#define RX_CTRL_42			(QP_PMA_TOP_BASE + 0x6d0)
+
+#define QP_ANA_CSR_BASE				0x1022f000
+#define RG_QP_RX_DAC_EN				(QP_ANA_CSR_BASE + 0x00)
+#define RG_QP_RXAFE_RESERVE			(QP_ANA_CSR_BASE + 0x04)
+#define RG_QP_CDR_LPF_MJV_LIM		(QP_ANA_CSR_BASE + 0x0c)
+#define RG_QP_CDR_LPF_SETVALUE		(QP_ANA_CSR_BASE + 0x14)
+#define RG_QP_CDR_PR_CKREF_DIV1		(QP_ANA_CSR_BASE + 0x18)
+#define RG_QP_CDR_PR_KBAND_DIV_PCIE	(QP_ANA_CSR_BASE + 0x1c)
+#define RG_QP_CDR_FORCE_IBANDLPF_R_OFF	(QP_ANA_CSR_BASE + 0x20)
+#define RG_QP_TX_MODE_16B_EN		(QP_ANA_CSR_BASE + 0x28)
+#define RG_QP_PLL_IPLL_DIG_PWR_SEL	(QP_ANA_CSR_BASE + 0x3c)
+#define RG_QP_PLL_SDM_ORD			(QP_ANA_CSR_BASE + 0x40)
+
+#define ETHER_SYS_BASE				0x1028c800
+#define RG_GPHY_AFE_PWD				(ETHER_SYS_BASE + 0x40)
+#define RG_GPHY_SMI_ADDR			(ETHER_SYS_BASE + 0x48)
+
+#define MIB_DESC(_s, _o, _n)	\
+	{			\
+		.size = (_s),	\
+		.offset = (_o),	\
+		.name = (_n),	\
+	}
+
+struct an8855_mib_desc {
+	unsigned int size;
+	unsigned int offset;
+	const char *name;
+};
+
+struct an8855_fdb {
+	u16 vid;
+	u8 port_mask;
+	u8 aging;
+	u8 mac[6];
+	bool noarp;
+	u8 live;
+	u8 type;
+	u8 fid;
+	u8 ivl;
+};
+
+/* struct an8855_port -	This is the main data structure for holding the state
+ *			of the port.
+ * @enable:	The status used for show port is enabled or not.
+ * @pm:		The matrix used to show all connections with the port.
+ * @pvid:	The VLAN specified is to be considered a PVID at ingress.  Any
+ *		untagged frames will be assigned to the related VLAN.
+ * @vlan_filtering: The flags indicating whether the port that can recognize
+ *			VLAN-tagged frames.
+ */
+struct an8855_port {
+	bool enable;
+	u32 pm;
+	u16 pvid;
+};
+
+/* struct an8855_info -	This is the main data structure for holding the specific
+ *			part for each supported device
+ * @sw_setup:		Holding the handler to a device initialization
+ * @phy_read:		Holding the way reading PHY port
+ * @phy_write:		Holding the way writing PHY port
+ * @pad_setup:		Holding the way setting up the bus pad for a certain
+ *			MAC port
+ * @phy_mode_supported:	Check if the PHY type is being supported on a certain
+ *			port
+ * @mac_port_validate:	Holding the way to set addition validate type for a
+ *			certan MAC port
+ * @mac_port_get_state: Holding the way getting the MAC/PCS state for a certain
+ *			MAC port
+ * @mac_port_config:	Holding the way setting up the PHY attribute to a
+ *			certain MAC port
+ * @mac_pcs_an_restart	Holding the way restarting PCS autonegotiation for a
+ *			certain MAC port
+ * @mac_pcs_link_up:	Holding the way setting up the PHY attribute to the pcs
+ *			of the certain MAC port
+ */
+struct an8855_dev_info {
+	enum an8855_id id;
+
+	int (*sw_setup)(struct dsa_switch *ds);
+	int (*phy_read)(struct dsa_switch *ds, int port, int regnum);
+	int (*phy_write)(struct dsa_switch *ds, int port, int regnum,
+			  u16 val);
+	int (*pad_setup)(struct dsa_switch *ds, phy_interface_t interface);
+	int (*cpu_port_config)(struct dsa_switch *ds, int port);
+	bool (*phy_mode_supported)(struct dsa_switch *ds, int port,
+					const struct phylink_link_state *state);
+	void (*mac_port_validate)(struct dsa_switch *ds, int port,
+				   unsigned long *supported);
+	int (*mac_port_get_state)(struct dsa_switch *ds, int port,
+				   struct phylink_link_state *state);
+	int (*mac_port_config)(struct dsa_switch *ds, int port,
+				unsigned int mode, phy_interface_t interface);
+	void (*mac_pcs_an_restart)(struct dsa_switch *ds, int port);
+};
+
+/* struct an8855_priv -	This is the main data structure for holding the state
+ *			of the driver
+ * @dev:		The device pointer
+ * @ds:			The pointer to the dsa core structure
+ * @bus:		The bus used for the device and built-in PHY
+ * @rstc:		The pointer to reset control used by MCM
+ * @core_pwr:		The power supplied into the core
+ * @io_pwr:		The power supplied into the I/O
+ * @reset:		The descriptor for GPIO line tied to its reset pin
+ * @mcm:		Flag for distinguishing if standalone IC or module
+ *			coupling
+ * @ports:		Holding the state among ports
+ * @reg_mutex:		The lock for protecting among process accessing
+ *			registers
+ * @p6_interface	Holding the current port 6 interface
+ * @p5_intf_sel:	Holding the current port 5 interface select
+ */
+struct an8855_priv {
+	struct device *dev;
+	struct dsa_switch *ds;
+	struct mii_bus *bus;
+	struct reset_control *rstc;
+	struct regulator *core_pwr;
+	struct regulator *io_pwr;
+	struct gpio_desc *reset;
+	void __iomem *base;
+	const struct an8855_dev_info *info;
+	unsigned int phy_base;
+	int phy_base_new;
+	unsigned int id;
+	phy_interface_t p5_interface;
+	unsigned int p5_intf_sel;
+	u8 mirror_rx;
+	u8 mirror_tx;
+	u8 eee_enable;
+
+	struct an8855_port ports[AN8855_NUM_PORTS];
+	/* protect among processes for registers access */
+	struct mutex reg_mutex;
+};
+
+struct an8855_hw_vlan_entry {
+	int port;
+	u8 old_members;
+	bool untagged;
+};
+
+static inline void an8855_hw_vlan_entry_init(struct an8855_hw_vlan_entry *e,
+						 int port, bool untagged)
+{
+	e->port = port;
+	e->untagged = untagged;
+}
+
+typedef void (*an8855_vlan_op) (struct an8855_priv *,
+				struct an8855_hw_vlan_entry *);
+
+struct an8855_hw_stats {
+	const char *string;
+	u16 reg;
+	u8 sizeof_stat;
+};
+
+struct an8855_dummy_poll {
+	struct an8855_priv *priv;
+	u32 reg;
+};
+
+static inline void INIT_AN8855_DUMMY_POLL(struct an8855_dummy_poll *p,
+					  struct an8855_priv *priv, u32 reg)
+{
+	p->priv = priv;
+	p->reg = reg;
+}
+
+int an8855_phy_setup(struct dsa_switch *ds);
+u32 an8855_read(struct an8855_priv *priv, u32 reg);
+void an8855_write(struct an8855_priv *priv, u32 reg, u32 val);
+int an8855_phy_cl22_read(struct an8855_priv *priv, int port, int regnum);
+int an8855_phy_cl22_write(struct an8855_priv *priv, int port,
+				int regnum, u16 val);
+int an8855_phy_cl45_read(struct an8855_priv *priv, int port, int devad,
+				int regnum);
+int an8855_phy_cl45_write(struct an8855_priv *priv, int port, int devad,
+				int regnum,	u16 val);
+#endif /* __AN8855_H */
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/dsa/airoha/an8855/an8855_nl.c b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/dsa/airoha/an8855/an8855_nl.c
new file mode 100644
index 0000000..b80ce6f
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/dsa/airoha/an8855/an8855_nl.c
@@ -0,0 +1,322 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2023 Airoha Inc.
+ * Author: Min Yao <min.yao@airoha.com>
+ */
+
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <net/genetlink.h>
+#include <linux/of_mdio.h>
+#include <linux/phylink.h>
+#include <net/dsa.h>
+
+#include "an8855.h"
+#include "an8855_nl.h"
+
+struct an8855_nl_cmd_item {
+	enum an8855_cmd cmd;
+	bool require_dev;
+	int (*process)(struct genl_info *info);
+	u32 nr_required_attrs;
+	const enum an8855_attr *required_attrs;
+};
+
+struct an8855_priv *an8855_sw_priv;
+
+static DEFINE_MUTEX(an8855_devs_lock);
+
+void
+an8855_put(void)
+{
+	mutex_unlock(&an8855_devs_lock);
+}
+
+void
+an8855_lock(void)
+{
+	mutex_lock(&an8855_devs_lock);
+}
+
+static int an8855_nl_response(struct sk_buff *skb, struct genl_info *info);
+
+static const struct nla_policy an8855_nl_cmd_policy[] = {
+	[AN8855_ATTR_TYPE_MESG] = {.type = NLA_STRING},
+	[AN8855_ATTR_TYPE_PHY] = {.type = NLA_S32},
+	[AN8855_ATTR_TYPE_REG] = {.type = NLA_S32},
+	[AN8855_ATTR_TYPE_VAL] = {.type = NLA_S32},
+	[AN8855_ATTR_TYPE_DEV_NAME] = {.type = NLA_S32},
+	[AN8855_ATTR_TYPE_DEV_ID] = {.type = NLA_S32},
+	[AN8855_ATTR_TYPE_DEVAD] = {.type = NLA_S32},
+};
+
+static const struct genl_ops an8855_nl_ops[] = {
+	{
+		.cmd = AN8855_CMD_REQUEST,
+		.doit = an8855_nl_response,
+		.flags = GENL_ADMIN_PERM,
+	},
+	{
+		.cmd = AN8855_CMD_READ,
+		.doit = an8855_nl_response,
+		.flags = GENL_ADMIN_PERM,
+	},
+	{
+		.cmd = AN8855_CMD_WRITE,
+		.doit = an8855_nl_response,
+		.flags = GENL_ADMIN_PERM,
+	},
+};
+
+static struct genl_family an8855_nl_family = {
+	.name = AN8855_DSA_GENL_NAME,
+	.version = AN8855_GENL_VERSION,
+	.maxattr = AN8855_NR_ATTR_TYPE,
+	.ops = an8855_nl_ops,
+	.n_ops = ARRAY_SIZE(an8855_nl_ops),
+	.policy = an8855_nl_cmd_policy,
+};
+
+static int
+an8855_nl_prepare_reply(struct genl_info *info, u8 cmd,
+				   struct sk_buff **skbp)
+{
+	struct sk_buff *msg;
+	void *reply;
+
+	if (!info)
+		return -EINVAL;
+
+	msg = genlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
+	if (!msg)
+		return -ENOMEM;
+
+	/* Construct send-back message header */
+	reply = genlmsg_put(msg, info->snd_portid, info->snd_seq,
+				&an8855_nl_family, 0, cmd);
+	if (!reply) {
+		nlmsg_free(msg);
+		return -EINVAL;
+	}
+
+	*skbp = msg;
+	return 0;
+}
+
+static int
+an8855_nl_send_reply(struct sk_buff *skb, struct genl_info *info)
+{
+	struct genlmsghdr *genlhdr = nlmsg_data(nlmsg_hdr(skb));
+	void *reply = genlmsg_data(genlhdr);
+
+	/* Finalize a generic netlink message (update message header) */
+	genlmsg_end(skb, reply);
+
+	/* reply to a request */
+	return genlmsg_reply(skb, info);
+}
+
+static s32
+an8855_nl_get_s32(struct genl_info *info, enum an8855_attr attr,
+				 s32 defval)
+{
+	struct nlattr *na;
+
+	na = info->attrs[attr];
+	if (na)
+		return nla_get_s32(na);
+
+	return defval;
+}
+
+static int
+an8855_nl_get_u32(struct genl_info *info, enum an8855_attr attr,
+				 u32 *val)
+{
+	struct nlattr *na;
+
+	na = info->attrs[attr];
+	if (na) {
+		*val = nla_get_u32(na);
+		return 0;
+	}
+
+	return -1;
+}
+
+static int
+an8855_nl_reply_read(struct genl_info *info)
+{
+	struct sk_buff *rep_skb = NULL;
+	s32 phy, devad, reg;
+	int value;
+	int ret = 0;
+
+	phy = an8855_nl_get_s32(info, AN8855_ATTR_TYPE_PHY, -1);
+	devad = an8855_nl_get_s32(info, AN8855_ATTR_TYPE_DEVAD, -1);
+	reg = an8855_nl_get_s32(info, AN8855_ATTR_TYPE_REG, -1);
+
+	if (reg < 0)
+		goto err;
+
+	ret = an8855_nl_prepare_reply(info, AN8855_CMD_READ, &rep_skb);
+	if (ret < 0)
+		goto err;
+	if (phy >= 0) {
+		if (devad < 0)
+			value = an8855_phy_cl22_read(an8855_sw_priv, phy, reg);
+		else
+			value =	an8855_phy_cl45_read(an8855_sw_priv, phy,
+						devad, reg);
+	} else
+		value = an8855_read(an8855_sw_priv, reg);
+	ret = nla_put_s32(rep_skb, AN8855_ATTR_TYPE_REG, reg);
+	if (ret < 0)
+		goto err;
+
+	ret = nla_put_s32(rep_skb, AN8855_ATTR_TYPE_VAL, value);
+	if (ret < 0)
+		goto err;
+
+	return an8855_nl_send_reply(rep_skb, info);
+
+err:
+	if (rep_skb)
+		nlmsg_free(rep_skb);
+
+	return ret;
+}
+
+static int
+an8855_nl_reply_write(struct genl_info *info)
+{
+	struct sk_buff *rep_skb = NULL;
+	s32 phy, devad, reg;
+	u32 value;
+	int ret = 0;
+
+	phy = an8855_nl_get_s32(info, AN8855_ATTR_TYPE_PHY, -1);
+	devad = an8855_nl_get_s32(info, AN8855_ATTR_TYPE_DEVAD, -1);
+	reg = an8855_nl_get_s32(info, AN8855_ATTR_TYPE_REG, -1);
+
+	if (an8855_nl_get_u32(info, AN8855_ATTR_TYPE_VAL, &value))
+		goto err;
+
+	if (reg < 0)
+		goto err;
+
+	ret = an8855_nl_prepare_reply(info, AN8855_CMD_WRITE, &rep_skb);
+	if (ret < 0)
+		goto err;
+	if (phy >= 0) {
+		if (devad < 0)
+			an8855_phy_cl22_write(an8855_sw_priv, phy, reg, value);
+		else
+			an8855_phy_cl45_write(an8855_sw_priv, phy, devad, reg,
+					  value);
+	} else
+		an8855_write(an8855_sw_priv, reg, value);
+	ret = nla_put_s32(rep_skb, AN8855_ATTR_TYPE_REG, reg);
+	if (ret < 0)
+		goto err;
+
+	ret = nla_put_s32(rep_skb, AN8855_ATTR_TYPE_VAL, value);
+	if (ret < 0)
+		goto err;
+
+	return an8855_nl_send_reply(rep_skb, info);
+
+err:
+	if (rep_skb)
+		nlmsg_free(rep_skb);
+
+	return ret;
+}
+
+static const enum an8855_attr an8855_nl_cmd_read_attrs[] = {
+	AN8855_ATTR_TYPE_REG
+};
+
+static const enum an8855_attr an8855_nl_cmd_write_attrs[] = {
+	AN8855_ATTR_TYPE_REG,
+	AN8855_ATTR_TYPE_VAL
+};
+
+static const struct an8855_nl_cmd_item an8855_nl_cmds[] = {
+	{
+	 .cmd = AN8855_CMD_READ,
+	 .require_dev = true,
+	 .process = an8855_nl_reply_read,
+	 .required_attrs = an8855_nl_cmd_read_attrs,
+	 .nr_required_attrs = ARRAY_SIZE(an8855_nl_cmd_read_attrs),
+	},
+	{
+		 .cmd = AN8855_CMD_WRITE,
+		 .require_dev = true,
+		 .process = an8855_nl_reply_write,
+		 .required_attrs = an8855_nl_cmd_write_attrs,
+		 .nr_required_attrs = ARRAY_SIZE(an8855_nl_cmd_write_attrs),
+	}
+};
+
+static int
+an8855_nl_response(struct sk_buff *skb, struct genl_info *info)
+{
+	struct genlmsghdr *hdr = nlmsg_data(info->nlhdr);
+	const struct an8855_nl_cmd_item *cmditem = NULL;
+	u32 sat_req_attrs = 0;
+	int i, ret;
+
+	for (i = 0; i < ARRAY_SIZE(an8855_nl_cmds); i++) {
+		if (hdr->cmd == an8855_nl_cmds[i].cmd) {
+			cmditem = &an8855_nl_cmds[i];
+			break;
+		}
+	}
+
+	if (!cmditem) {
+		pr_info("an8855-nl: unknown cmd %u\n", hdr->cmd);
+		return -EINVAL;
+	}
+
+	for (i = 0; i < cmditem->nr_required_attrs; i++) {
+		if (info->attrs[cmditem->required_attrs[i]])
+			sat_req_attrs++;
+	}
+
+	if (sat_req_attrs != cmditem->nr_required_attrs) {
+		pr_info("an8855-nl: missing required attr(s) for cmd %u\n",
+			hdr->cmd);
+		return -EINVAL;
+	}
+
+	ret = cmditem->process(info);
+
+	an8855_put();
+
+	return ret;
+}
+
+int
+an8855_nl_init(struct an8855_priv **priv)
+{
+	int ret;
+
+	pr_info("an8855-nl: genl_register_family_with_ops\n");
+
+	an8855_sw_priv = *priv;
+	ret = genl_register_family(&an8855_nl_family);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+void
+an8855_nl_exit(void)
+{
+	an8855_sw_priv = NULL;
+	genl_unregister_family(&an8855_nl_family);
+}
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/dsa/airoha/an8855/an8855_nl.h b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/dsa/airoha/an8855/an8855_nl.h
new file mode 100644
index 0000000..f8a462d
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/dsa/airoha/an8855/an8855_nl.h
@@ -0,0 +1,43 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (c) 2023 Airoha Inc.
+ * Author: Min Yao <min.yao@airoha.com>
+ */
+
+#ifndef _AN8855_NL_H_
+#define _AN8855_NL_H_
+
+#define AN8855_DSA_GENL_NAME "an8855_dsa"
+#define AN8855_GENL_VERSION		0x1
+
+enum an8855_cmd {
+	AN8855_CMD_UNSPEC = 0,
+	AN8855_CMD_REQUEST,
+	AN8855_CMD_REPLY,
+	AN8855_CMD_READ,
+	AN8855_CMD_WRITE,
+
+	__AN8855_CMD_MAX,
+};
+
+enum an8855_attr {
+	AN8855_ATTR_TYPE_UNSPEC = 0,
+	AN8855_ATTR_TYPE_MESG,
+	AN8855_ATTR_TYPE_PHY,
+	AN8855_ATTR_TYPE_DEVAD,
+	AN8855_ATTR_TYPE_REG,
+	AN8855_ATTR_TYPE_VAL,
+	AN8855_ATTR_TYPE_DEV_NAME,
+	AN8855_ATTR_TYPE_DEV_ID,
+
+	__AN8855_ATTR_TYPE_MAX,
+};
+
+#define AN8855_NR_ATTR_TYPE		(__AN8855_ATTR_TYPE_MAX - 1)
+
+#ifdef __KERNEL__
+int an8855_nl_init(struct an8855_priv **priv);
+void an8855_nl_exit(void);
+#endif /* __KERNEL__ */
+
+#endif /* _AN8855_NL_H_ */
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/dsa/airoha/an8855/an8855_phy.c b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/dsa/airoha/an8855/an8855_phy.c
new file mode 100644
index 0000000..5499312
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/dsa/airoha/an8855/an8855_phy.c
@@ -0,0 +1,141 @@
+// SPDX-License-Identifier:     GPL-2.0+
+/*
+ * Common part for Airoha AN8855 gigabit switch
+ *
+ * Copyright (C) 2023 Airoha Inc. All Rights Reserved.
+ *
+ * Author: Min Yao <min.yao@airoha.com>
+ */
+
+#include <linux/delay.h>
+#include <linux/hrtimer.h>
+#include <linux/kernel.h>
+#include <net/dsa.h>
+#include "an8855.h"
+#include "an8855_phy.h"
+
+#define AN8855_NUM_PHYS 5
+
+static u32
+an8855_phy_read_dev_reg(struct dsa_switch *ds, u32 port_num,
+				   u32 dev_addr, u32 reg_addr)
+{
+	struct an8855_priv *priv = ds->priv;
+	u32 phy_val;
+	u32 addr;
+
+	addr = MII_ADDR_C45 | (dev_addr << 16) | (reg_addr & 0xffff);
+	phy_val = priv->info->phy_read(ds, port_num, addr);
+
+	return phy_val;
+}
+
+static void
+an8855_phy_write_dev_reg(struct dsa_switch *ds, u32 port_num,
+				     u32 dev_addr, u32 reg_addr, u32 write_data)
+{
+	struct an8855_priv *priv = ds->priv;
+	u32 addr;
+
+	addr = MII_ADDR_C45 | (dev_addr << 16) | (reg_addr & 0xffff);
+
+	priv->info->phy_write(ds, port_num, addr, write_data);
+}
+
+static void
+an8855_switch_phy_write(struct dsa_switch *ds, u32 port_num,
+				    u32 reg_addr, u32 write_data)
+{
+	struct an8855_priv *priv = ds->priv;
+
+	priv->info->phy_write(ds, port_num, reg_addr, write_data);
+}
+
+static u32
+an8855_switch_phy_read(struct dsa_switch *ds, u32 port_num,
+				  u32 reg_addr)
+{
+	struct an8855_priv *priv = ds->priv;
+
+	return priv->info->phy_read(ds, port_num, reg_addr);
+}
+
+static void
+an8855_phy_setting(struct dsa_switch *ds)
+{
+	struct an8855_priv *priv = ds->priv;
+	int i;
+	u32 val;
+
+	/* Release power down */
+	an8855_write(priv, RG_GPHY_AFE_PWD, 0x0);
+	for (i = 0; i < AN8855_NUM_PHYS; i++) {
+		/* Enable HW auto downshift */
+		an8855_switch_phy_write(ds, i, 0x1f, 0x1);
+		val = an8855_switch_phy_read(ds, i, PHY_EXT_REG_14);
+		val |= PHY_EN_DOWN_SHFIT;
+		an8855_switch_phy_write(ds, i, PHY_EXT_REG_14, val);
+		an8855_switch_phy_write(ds, i, 0x1f, 0x0);
+
+		/* Enable Asymmetric Pause Capability */
+		val = an8855_switch_phy_read(ds, i, MII_ADVERTISE);
+		val |= ADVERTISE_PAUSE_ASYM;
+		an8855_switch_phy_write(ds, i, MII_ADVERTISE, val);
+	}
+}
+
+static void
+an8855_low_power_setting(struct dsa_switch *ds)
+{
+	int port, addr;
+
+	for (port = 0; port < AN8855_NUM_PHYS; port++) {
+		an8855_phy_write_dev_reg(ds, port, 0x1e, 0x11, 0x0f00);
+		an8855_phy_write_dev_reg(ds, port, 0x1e, 0x3c, 0x0000);
+		an8855_phy_write_dev_reg(ds, port, 0x1e, 0x3d, 0x0000);
+		an8855_phy_write_dev_reg(ds, port, 0x1e, 0x3e, 0x0000);
+		an8855_phy_write_dev_reg(ds, port, 0x1e, 0xc6, 0x53aa);
+	}
+
+	an8855_phy_write_dev_reg(ds, 0, 0x1f, 0x268, 0x07f1);
+	an8855_phy_write_dev_reg(ds, 0, 0x1f, 0x269, 0x2111);
+	an8855_phy_write_dev_reg(ds, 0, 0x1f, 0x26a, 0x0000);
+	an8855_phy_write_dev_reg(ds, 0, 0x1f, 0x26b, 0x0074);
+	an8855_phy_write_dev_reg(ds, 0, 0x1f, 0x26e, 0x00f6);
+	an8855_phy_write_dev_reg(ds, 0, 0x1f, 0x26f, 0x6666);
+	an8855_phy_write_dev_reg(ds, 0, 0x1f, 0x271, 0x2c02);
+	an8855_phy_write_dev_reg(ds, 0, 0x1f, 0x272, 0x0c22);
+	an8855_phy_write_dev_reg(ds, 0, 0x1f, 0x700, 0x0001);
+	an8855_phy_write_dev_reg(ds, 0, 0x1f, 0x701, 0x0803);
+	an8855_phy_write_dev_reg(ds, 0, 0x1f, 0x702, 0x01b6);
+	an8855_phy_write_dev_reg(ds, 0, 0x1f, 0x703, 0x2111);
+
+	an8855_phy_write_dev_reg(ds, 1, 0x1f, 0x700, 0x0001);
+
+	for (addr = 0x200; addr <= 0x230; addr += 2)
+		an8855_phy_write_dev_reg(ds, 0, 0x1f, addr, 0x2020);
+
+	for (addr = 0x201; addr <= 0x231; addr += 2)
+		an8855_phy_write_dev_reg(ds, 0, 0x1f, addr, 0x0020);
+}
+
+static void
+an8855_eee_setting(struct dsa_switch *ds, u32 port)
+{
+	/* Disable EEE */
+	an8855_phy_write_dev_reg(ds, port, PHY_DEV07, PHY_DEV07_REG_03C, 0);
+}
+
+int
+an8855_phy_setup(struct dsa_switch *ds)
+{
+	int ret = 0;
+	int i;
+
+	an8855_phy_setting(ds);
+
+	for (i = 0; i < AN8855_NUM_PHYS; i++)
+		an8855_eee_setting(ds, i);
+
+	return ret;
+}
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/dsa/airoha/an8855/an8855_phy.h b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/dsa/airoha/an8855/an8855_phy.h
new file mode 100644
index 0000000..63a03bb
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/dsa/airoha/an8855/an8855_phy.h
@@ -0,0 +1,261 @@
+// SPDX-License-Identifier:     GPL-2.0+
+/*
+ * Common part for Airoha AN8855 gigabit switch
+ *
+ * Copyright (C) 2023 Airoha Inc. All Rights Reserved.
+ *
+ * Author: Min Yao <min.yao@airoha.com>
+ */
+
+#ifndef _AN8855_PHY_H_
+#define _AN8855_PHY_H_
+
+#include <linux/bitops.h>
+
+/*phy calibration use*/
+#define DEV_1E				0x1E
+/*global device 0x1f, always set P0*/
+#define DEV_1F				0x1F
+
+/************IEXT/REXT CAL***************/
+/* bits range: for example BITS(16,23) = 0xFF0000*/
+#define BITS(m, n)	 (~(BIT(m) - 1) & ((BIT(n) - 1) | BIT(n)))
+#define ANACAL_INIT			0x01
+#define ANACAL_ERROR			0xFD
+#define ANACAL_SATURATION		0xFE
+#define	ANACAL_FINISH			0xFF
+#define ANACAL_PAIR_A			0
+#define ANACAL_PAIR_B			1
+#define ANACAL_PAIR_C			2
+#define ANACAL_PAIR_D			3
+#define DAC_IN_0V			0x00
+#define DAC_IN_2V			0xf0
+#define TX_AMP_OFFSET_0MV		0x20
+#define TX_AMP_OFFSET_VALID_BITS	6
+
+#define R0				0
+#define PHY0				0
+#define PHY1				1
+#define PHY2				2
+#define PHY3				3
+#define PHY4				4
+#define ANA_TEST_MODE			BITS(8, 15)
+#define TST_TCLK_SEL			BITs(6, 7)
+#define ANA_TEST_VGA_RG			0x100
+
+#define FORCE_MDI_CROSS_OVER		BITS(3, 4)
+#define T10_TEST_CTL_RG			0x145
+#define RG_185				0x185
+#define RG_TX_SLEW			BIT(0)
+#define ANA_CAL_0			0xdb
+#define RG_CAL_CKINV			BIT(12)
+#define RG_ANA_CALEN			BIT(8)
+#define RG_REXT_CALEN			BIT(4)
+#define RG_ZCALEN_A			BIT(0)
+#define ANA_CAL_1			0xdc
+#define RG_ZCALEN_B			BIT(12)
+#define RG_ZCALEN_C			BIT(8)
+#define RG_ZCALEN_D			BIT(4)
+#define RG_TXVOS_CALEN			BIT(0)
+#define ANA_CAL_6			0xe1
+#define RG_CAL_REFSEL			BIT(4)
+#define RG_CAL_COMP_PWD			BIT(0)
+#define ANA_CAL_5			0xe0
+#define RG_REXT_TRIM			BITs(8, 13)
+#define RG_ZCAL_CTRL			BITs(0, 5)
+#define RG_17A				0x17a
+#define AD_CAL_COMP_OUT			BIT(8)
+#define RG_17B				0x17b
+#define AD_CAL_CLK			bit(0)
+#define RG_17C				0x17c
+#define DA_CALIN_FLAG			bit(0)
+/************R50 CAL****************************/
+#define RG_174				0x174
+#define RG_R50OHM_RSEL_TX_A_EN		BIT[15]
+#define CR_R50OHM_RSEL_TX_A		BITS[8:14]
+#define RG_R50OHM_RSEL_TX_B_EN		BIT[7]
+#define CR_R50OHM_RSEL_TX_B		BITS[6:0]
+#define RG_175				0x175
+#define RG_R50OHM_RSEL_TX_C_EN		BITS[15]
+#define CR_R50OHM_RSEL_TX_C		BITS[8:14]
+#define RG_R50OHM_RSEL_TX_D_EN		BIT[7]
+#define CR_R50OHM_RSEL_TX_D		BITS[0:6]
+/**********TX offset Calibration***************************/
+#define RG_95				0x96
+#define BYPASS_TX_OFFSET_CAL		BIT(15)
+#define RG_3E				0x3e
+#define BYPASS_PD_TXVLD_A		BIT(15)
+#define BYPASS_PD_TXVLD_B		BIT(14)
+#define BYPASS_PD_TXVLD_C		BIT(13)
+#define BYPASS_PD_TXVLD_D		BIT(12)
+#define BYPASS_PD_TX_10M		BIT(11)
+#define POWER_DOWN_TXVLD_A		BIT(7)
+#define POWER_DOWN_TXVLD_B		BIT(6)
+#define POWER_DOWN_TXVLD_C		BIT(5)
+#define POWER_DOWN_TXVLD_D		BIT(4)
+#define POWER_DOWN_TX_10M		BIT(3)
+#define RG_DD				0xdd
+#define RG_TXG_CALEN_A			BIT(12)
+#define RG_TXG_CALEN_B			BIT(8)
+#define RG_TXG_CALEN_C			BIT(4)
+#define RG_TXG_CALEN_D			BIT(0)
+#define RG_17D				0x17D
+#define FORCE_DASN_DAC_IN0_A		BIT(15)
+#define DASN_DAC_IN0_A			BITS(0, 9)
+#define RG_17E				0x17E
+#define FORCE_DASN_DAC_IN0_B		BIT(15)
+#define DASN_DAC_IN0_B			BITS(0, 9)
+#define RG_17F				0x17F
+
+#define FORCE_DASN_DAC_IN0_C		BIT(15)
+#define DASN_DAC_IN0_C			BITS(0, 9)
+#define RG_180				0x180
+#define FORCE_DASN_DAC_IN0_D		BIT(15)
+#define DASN_DAC_IN0_D			BITS(0, 9)
+
+#define RG_181				0x181
+#define FORCE_DASN_DAC_IN1_A		BIT(15)
+#define DASN_DAC_IN1_A			BITS(0, 9)
+#define RG_182				0x182
+#define FORCE_DASN_DAC_IN1_B		BIT(15)
+#define DASN_DAC_IN1_B			BITS(0, 9)
+#define RG_183				0x183
+#define FORCE_DASN_DAC_IN1_C		BIT(15)
+#define DASN_DAC_IN1_C			BITS(0, 9)
+#define RG_184				0x184
+#define FORCE_DASN_DAC_IN1_D		BIT(15)
+#define DASN_DAC_IN1_D			BITS(0, 9)
+#define RG_172				0x172
+#define CR_TX_AMP_OFFSET_A		BITS(8, 13)
+#define CR_TX_AMP_OFFSET_B		BITS(0, 5)
+#define RG_173				0x173
+#define CR_TX_AMP_OFFSET_C		BITS(8, 13)
+#define CR_TX_AMP_OFFSET_D		BITS(0, 5)
+/**********TX Amp Calibration ***************************/
+#define RG_12				0x12
+#define DA_TX_I2MPB_A_GBE		BITS(10, 15)
+#define RG_17				0x17
+#define DA_TX_I2MPB_B_GBE		BITS(8, 13)
+#define RG_19				0x19
+#define DA_TX_I2MPB_C_GBE		BITS(8, 13)
+#define RG_21				0x21
+#define DA_TX_I2MPB_D_GBE		BITS(8, 13)
+#define TX_AMP_MAX			0x3f
+#define TX_AMP_MAX_OFFSET		0xb
+#define TX_AMP_HIGHEST_TS		((TX_AMP_MAX) + 3)
+#define TX_AMP_LOWEST_TS		(0 - 3)
+#define TX_AMP_HIGH_TS			(TX_AMP_MAX)
+#define TX_AMP_LOW_TS			0
+
+/* PHY Extend Register 0x14 bitmap of define */
+#define PHY_EXT_REG_14			0x14
+
+/* Fields of PHY_EXT_REG_14 */
+#define PHY_EN_DOWN_SHFIT		BIT(4)
+
+/* PHY Extend Register 0x17 bitmap of define */
+#define PHY_EXT_REG_17			0x17
+
+/* Fields of PHY_EXT_REG_17 */
+#define PHY_LINKDOWN_POWER_SAVING_EN	BIT(4)
+
+/* PHY PMA Register 0x17 bitmap of define */
+#define SLV_DSP_READY_TIME_S		15
+#define SLV_DSP_READY_TIME_M		(0xff << SLV_DSP_READY_TIME_S)
+
+/* PHY PMA Register 0x18 bitmap of define */
+#define ENABLE_RANDOM_UPDATE_TRIGGER	BIT(8)
+
+/* PHY EEE Register bitmap of define */
+#define PHY_DEV07			0x07
+#define PHY_DEV07_REG_03C		0x3c
+
+/* PHY DEV 0x1e Register bitmap of define */
+#define PHY_DEV1E			0x1e
+#define PHY_DEV1F			0x1f
+
+/* Proprietory Control Register of Internal Phy device 0x1e */
+#define PHY_TX_MLT3_BASE		0x0
+#define PHY_DEV1E_REG_13		0x13
+#define PHY_DEV1E_REG_14		0x14
+#define PHY_DEV1E_REG_41		0x41
+#define PHY_DEV1E_REG_A6		0xa6
+#define RXADC_CONTROL_3			0xc2
+#define PHY_DEV1E_REG_0C6		0xc6
+#define RXADC_LDO_CONTROL_2		0xd3
+#define PHY_DEV1E_REG_0FE		0xfe
+#define PHY_DEV1E_REG_123		0x123
+#define PHY_DEV1E_REG_189		0x189
+#define PHY_DEV1E_REG_234		0x234
+
+/* Proprietory Control Register of Internal Phy device 0x1f */
+#define PHY_DEV1F_REG_44		0x44
+#define PHY_DEV1F_REG_268		0x268
+#define PHY_DEV1F_REG_269		0x269
+#define PHY_DEV1F_REG_26A		0x26A
+#define TXVLD_DA_271			0x271
+#define TXVLD_DA_272			0x272
+#define TXVLD_DA_273			0x273
+
+/* Fields of PHY_DEV1E_REG_0C6 */
+#define PHY_POWER_SAVING_S		8
+#define PHY_POWER_SAVING_M		0x300
+#define PHY_POWER_SAVING_TX		0x0
+
+/* Fields of PHY_DEV1E_REG_189 */
+#define DESCRAMBLER_CLEAR_EN		0x1
+
+/* Fields of PHY_DEV1E_REG_234 */
+#define TR_OPEN_LOOP_EN			BIT(0)
+
+/* Internal GPHY Page Control Register */
+#define PHY_CL22_PAGE_CTRL		0x1f
+#define PHY_TR_PAGE			0x52b5
+
+/* Internal GPHY Token Ring Access Registers */
+#define PHY_TR_CTRL			0x10
+#define PHY_TR_LOW_DATA			0x11
+#define PHY_TR_HIGH_DATA		0x12
+
+/* Fields of PHY_TR_CTRL */
+#define PHY_TR_PKT_XMT_STA		BIT(15)
+#define PHY_TR_WR_S			13
+#define PHY_TR_CH_ADDR_S		11
+#define PHY_TR_NODE_ADDR_S		7
+#define PHY_TR_DATA_ADDR_S		1
+
+enum phy_tr_wr {
+	PHY_TR_WRITE = 0,
+	PHY_TR_READ = 1,
+};
+
+/* Helper macro for GPHY Token Ring Access */
+#define PHY_TR_LOW_VAL(x)		((x) & 0xffff)
+#define PHY_TR_HIGH_VAL(x)		(((x) & 0xff0000) >> 16)
+
+/* Token Ring Channels */
+#define PMA_CH				0x1
+#define DSP_CH				0x2
+
+/* Token Ring Nodes */
+#define PMA_NOD				0xf
+#define DSP_NOD				0xd
+
+/* Token Ring register range */
+enum tr_pma_reg_addr {
+	PMA_MIN = 0x0,
+	PMA_01 = 0x1,
+	PMA_17 = 0x17,
+	PMA_18 = 0x18,
+	PMA_MAX = 0x3d,
+};
+
+enum tr_dsp_reg_addr {
+	DSP_MIN = 0x0,
+	DSP_06 = 0x6,
+	DSP_08 = 0x8,
+	DSP_0f = 0xf,
+	DSP_10 = 0x10,
+	DSP_MAX = 0x3e,
+};
+#endif /* _AN8855_REGS_H_ */
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_eth_soc.c b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_eth_soc.c
index 49c123b..bd4aac7 100644
--- a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_eth_soc.c
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_eth_soc.c
@@ -258,7 +258,7 @@
 	"top_eth_xgmii_sel", "top_eth_mii_sel", "top_netsys_sel",
 	"top_netsys_500m_sel", "top_netsys_pao_2x_sel",
 	"top_netsys_sync_250m_sel", "top_netsys_ppefb_250m_sel",
-	"top_netsys_warp_sel", "top_macsec_sel", "macsec_bus_clk",
+	"top_netsys_warp_sel", "top_macsec_sel",
 };
 
 void mtk_w32(struct mtk_eth *eth, u32 val, unsigned reg)
@@ -967,10 +967,28 @@
 		pr_info("%s fsm invalid", __func__);
 }
 
-static void mtk_pse_port_link_set(struct mtk_mac *mac, bool up)
+static void mtk_pse_port_link_set(struct mtk_mac *mac, bool up,
+				  phy_interface_t interface)
 {
 	u32 fe_glo_cfg, val = 0;
 
+	if (!up && interface == PHY_INTERFACE_MODE_XGMII) {
+		void __iomem *base;
+
+		base = ioremap(0x0F0CFB00, SZ_4K);
+		if (base) {
+			/* wait for internal 2.5G PHY to turn off */
+			usleep_range(100, 1000);
+			/* enable the XGMAC clock for 10 msecs to
+			 * flush the packets.
+			 */
+			writel(readl(base) | BIT(9), base);
+			usleep_range(10000, 11000);
+			writel(readl(base) & ~BIT(9), base);
+			iounmap(base);
+		}
+	}
+
 	fe_glo_cfg = mtk_r32(mac->hw, MTK_FE_GLO_CFG(mac->id));
 	switch (mac->id) {
 	case MTK_GMAC1_ID:
@@ -1002,7 +1020,7 @@
 	unsigned int id;
 	u32 mcr, sts;
 
-	mtk_pse_port_link_set(mac, false);
+	mtk_pse_port_link_set(mac, false, interface);
 	if (mac->type == MTK_GDM_TYPE) {
 		mcr = mtk_r32(mac->hw, MTK_MAC_MCR(mac->id));
 		mcr &= ~(MAC_MCR_TX_EN | MAC_MCR_RX_EN | MAC_MCR_FORCE_LINK);
@@ -1140,6 +1158,8 @@
 		if (duplex == DUPLEX_FULL ||
 		    interface == PHY_INTERFACE_MODE_SGMII)
 			mcr |= MAC_MCR_FORCE_DPX;
+		else if (interface == PHY_INTERFACE_MODE_GMII)
+			mcr |= MAC_MCR_PRMBL_LMT_EN;
 
 		/* Configure pause modes -
 		 * phylink will avoid these for half duplex
@@ -1184,7 +1204,7 @@
 		mcr &= ~(XMAC_MCR_TRX_DISABLE);
 		mtk_w32(mac->hw, mcr, MTK_XMAC_MCR(mac->id));
 	}
-	mtk_pse_port_link_set(mac, true);
+	mtk_pse_port_link_set(mac, true, interface);
 }
 
 static void mtk_validate(struct phylink_config *config,
@@ -4383,6 +4403,7 @@
 		mtk_w32(eth, 0x00600009, PSE_IQ_REV(8));
 
 		/* GDM and CDM Threshold */
+		mtk_w32(eth, 0x00000004, MTK_CDM2_THRES);
 		mtk_w32(eth, 0x00000707, MTK_CDMW0_THRES);
 		mtk_w32(eth, 0x00000077, MTK_CDMW1_THRES);
 
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_eth_soc.h b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_eth_soc.h
index c32a0ee..355b745 100644
--- a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_eth_soc.h
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_eth_soc.h
@@ -175,6 +175,7 @@
 
 /* GDM and CDM Threshold */
 #define MTK_GDM2_THRES		0x1530
+#define MTK_CDM2_THRES		0x1534
 #define MTK_CDMW0_THRES		0x164c
 #define MTK_CDMW1_THRES		0x1650
 #define MTK_CDME0_THRES		0x1654
@@ -745,6 +746,7 @@
 #define MAC_MCR_FORCE_MODE	BIT(15)
 #define MAC_MCR_TX_EN		BIT(14)
 #define MAC_MCR_RX_EN		BIT(13)
+#define MAC_MCR_PRMBL_LMT_EN	BIT(10)
 #define MAC_MCR_BACKOFF_EN	BIT(9)
 #define MAC_MCR_BACKPR_EN	BIT(8)
 #define MAC_MCR_FORCE_EEE1000	BIT(7)
@@ -1192,7 +1194,6 @@
 	MTK_CLK_TOP_NETSYS_PPEFB_250M_SEL,
 	MTK_CLK_TOP_NETSYS_WARP_SEL,
 	MTK_CLK_TOP_MACSEC_SEL,
-	MTK_CLK_TOP_NETSYS_TOPS_400M_SEL,
 	MTK_CLK_MAX
 };
 
@@ -1277,8 +1278,7 @@
 				 BIT(MTK_CLK_TOP_NETSYS_SYNC_250M_SEL) | \
 				 BIT(MTK_CLK_TOP_NETSYS_PPEFB_250M_SEL) | \
 				 BIT(MTK_CLK_TOP_NETSYS_WARP_SEL) | \
-				 BIT(MTK_CLK_TOP_MACSEC_SEL) | \
-				 BIT(MTK_CLK_TOP_NETSYS_TOPS_400M_SEL))
+				 BIT(MTK_CLK_TOP_MACSEC_SEL))
 
 enum mtk_dev_state {
 	MTK_HW_INIT,
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_hnat/hnat.c b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_hnat/hnat.c
index a0c22b5..e5d7240 100644
--- a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_hnat/hnat.c
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_hnat/hnat.c
@@ -419,6 +419,7 @@
 	    hnat_priv->data->version == MTK_HNAT_V3) {
 		writel(0xcb777, hnat_priv->ppe_base[ppe_id] + PPE_DFT_CPORT1);
 		writel(0x7f, hnat_priv->ppe_base[ppe_id] + PPE_SBW_CTRL);
+		cr_set_field(hnat_priv->ppe_base[ppe_id] + PPE_GLO_CFG, SP_CMP_EN, 1);
 	}
 
 	if (hnat_priv->data->version == MTK_HNAT_V3) {
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_hnat/hnat.h b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_hnat/hnat.h
index 0ecdb25..ead9e1f 100644
--- a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_hnat/hnat.h
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_hnat/hnat.h
@@ -188,6 +188,7 @@
 #define TTL0_DRP (0x1 << 4) /* RW */
 #define MCAST_TB_EN (0x1 << 7) /* RW */
 #define MCAST_HASH (0x3 << 12) /* RW */
+#define SP_CMP_EN (0x1 << 25) /* RW */
 
 #define MC_P3_PPSE (0xf << 12) /* RW */
 #define MC_P2_PPSE (0xf << 8) /* RW */
@@ -1091,8 +1092,13 @@
 #define entry_hnat_is_bound(e) (e->bfib1.state == BIND)
 #define entry_hnat_state(e) (e->bfib1.state)
 
-#define skb_hnat_is_hashed(skb)                                                \
+#if defined(CONFIG_MEDIATEK_NETSYS_V2) || defined(CONFIG_MEDIATEK_NETSYS_V3)
+#define skb_hnat_is_hashed(skb)                                                 \
+	(skb_hnat_entry(skb) != 0x7fff && skb_hnat_entry(skb) < hnat_priv->foe_etry_num)
+#else
+#define skb_hnat_is_hashed(skb)                                                 \
 	(skb_hnat_entry(skb) != 0x3fff && skb_hnat_entry(skb) < hnat_priv->foe_etry_num)
+#endif
 #define FROM_GE_LAN_GRP(skb) (FROM_GE_LAN(skb) | FROM_GE_LAN2(skb))
 #define FROM_GE_LAN(skb) (skb_hnat_iface(skb) == FOE_MAGIC_GE_LAN)
 #define FROM_GE_LAN2(skb) (skb_hnat_iface(skb) == FOE_MAGIC_GE_LAN2)
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_sgmii.c b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_sgmii.c
index 54ec897..c36a174 100755
--- a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_sgmii.c
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_sgmii.c
@@ -227,6 +227,8 @@
 	regmap_update_bits(mpcs->regmap_pextp, 0x0070, GENMASK(31, 0),
 			   0x02002800);
 	ndelay(1020);
+	regmap_update_bits(mpcs->regmap_pextp, 0x3040, GENMASK(31, 0),
+			   0x20000000);
 	/* Setup DA default value */
 	regmap_update_bits(mpcs->regmap_pextp, 0x30B0, GENMASK(31, 0),
 			   0x00000020);
@@ -337,6 +339,8 @@
 	regmap_update_bits(mpcs->regmap_pextp, 0x0070, GENMASK(31, 0),
 			   0x02002800);
 	ndelay(1020);
+	regmap_update_bits(mpcs->regmap_pextp, 0x3040, GENMASK(31, 0),
+			   0x20000000);
 	/* Setup DA default value */
 	regmap_update_bits(mpcs->regmap_pextp, 0x30B0, GENMASK(31, 0),
 			   0x00000020);
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/airoha/an8855/Kconfig b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/airoha/an8855/Kconfig
new file mode 100644
index 0000000..654aa37
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/airoha/an8855/Kconfig
@@ -0,0 +1,8 @@
+
+config AN8855_GSW
+	tristate "Driver for the Airoha AN8855 switch"
+	help
+	  Airoha AN8855 devices and swconfig driver code,
+	  Provide swconfig command for basic switch operation.
+	  AN8855 support 2.5G speed and managed by SMI interface.
+	  To compile this driver as a module, choose M here.
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/airoha/an8855/Makefile b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/airoha/an8855/Makefile
new file mode 100644
index 0000000..5c24bda
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/airoha/an8855/Makefile
@@ -0,0 +1,10 @@
+#
+# Makefile for Airoha AN8855 gigabit switch
+#
+
+obj-$(CONFIG_AN8855_GSW)	+= an8855.o
+
+an8855-$(CONFIG_SWCONFIG)	+= an8855_swconfig.o
+
+an8855-y			+= an8855_mdio.o an8855.o \
+					an8855_common.o an8855_vlan.o an8855_nl.o
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/airoha/an8855/an8855.c b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/airoha/an8855/an8855.c
new file mode 100644
index 0000000..f3db8b8
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/airoha/an8855/an8855.c
@@ -0,0 +1,913 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2023 Airoha Inc.
+ * Author: Min Yao <min.yao@airoha.com>
+ */
+
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/hrtimer.h>
+#include <linux/of_platform.h>
+#include <linux/mfd/syscon.h>
+#include <linux/regmap.h>
+#include <linux/of_address.h>
+
+#include "an8855.h"
+#include "an8855_regs.h"
+
+/* AN8855 registers */
+#define SCU_BASE					0x10000000
+#define RG_RGMII_TXCK_C				(SCU_BASE + 0x1d0)
+
+#define HSGMII_AN_CSR_BASE			0x10220000
+#define SGMII_REG_AN0				(HSGMII_AN_CSR_BASE + 0x000)
+#define SGMII_REG_AN_13				(HSGMII_AN_CSR_BASE + 0x034)
+#define SGMII_REG_AN_FORCE_CL37		(HSGMII_AN_CSR_BASE + 0x060)
+
+#define HSGMII_CSR_PCS_BASE			0x10220000
+#define RG_HSGMII_PCS_CTROL_1		(HSGMII_CSR_PCS_BASE + 0xa00)
+#define RG_AN_SGMII_MODE_FORCE		(HSGMII_CSR_PCS_BASE + 0xa24)
+
+#define MULTI_SGMII_CSR_BASE		0x10224000
+#define SGMII_STS_CTRL_0			(MULTI_SGMII_CSR_BASE + 0x018)
+#define MSG_RX_CTRL_0				(MULTI_SGMII_CSR_BASE + 0x100)
+#define MSG_RX_LIK_STS_0			(MULTI_SGMII_CSR_BASE + 0x514)
+#define MSG_RX_LIK_STS_2			(MULTI_SGMII_CSR_BASE + 0x51c)
+#define PHY_RX_FORCE_CTRL_0			(MULTI_SGMII_CSR_BASE + 0x520)
+
+#define XFI_CSR_PCS_BASE			0x10225000
+#define RG_USXGMII_AN_CONTROL_0		(XFI_CSR_PCS_BASE + 0xbf8)
+
+#define MULTI_PHY_RA_CSR_BASE		0x10226000
+#define RG_RATE_ADAPT_CTRL_0		(MULTI_PHY_RA_CSR_BASE + 0x000)
+#define RATE_ADP_P0_CTRL_0			(MULTI_PHY_RA_CSR_BASE + 0x100)
+#define MII_RA_AN_ENABLE			(MULTI_PHY_RA_CSR_BASE + 0x300)
+
+#define QP_DIG_CSR_BASE				0x1022a000
+#define QP_CK_RST_CTRL_4			(QP_DIG_CSR_BASE + 0x310)
+#define QP_DIG_MODE_CTRL_0			(QP_DIG_CSR_BASE + 0x324)
+#define QP_DIG_MODE_CTRL_1			(QP_DIG_CSR_BASE + 0x330)
+
+#define SERDES_WRAPPER_BASE			0x1022c000
+#define USGMII_CTRL_0				(SERDES_WRAPPER_BASE + 0x000)
+
+#define QP_PMA_TOP_BASE				0x1022e000
+#define PON_RXFEDIG_CTRL_0			(QP_PMA_TOP_BASE + 0x100)
+#define PON_RXFEDIG_CTRL_9			(QP_PMA_TOP_BASE + 0x124)
+
+#define SS_LCPLL_PWCTL_SETTING_2	(QP_PMA_TOP_BASE + 0x208)
+#define SS_LCPLL_TDC_FLT_2			(QP_PMA_TOP_BASE + 0x230)
+#define SS_LCPLL_TDC_FLT_5			(QP_PMA_TOP_BASE + 0x23c)
+#define SS_LCPLL_TDC_PCW_1			(QP_PMA_TOP_BASE + 0x248)
+#define INTF_CTRL_8		(QP_PMA_TOP_BASE + 0x320)
+#define INTF_CTRL_9		(QP_PMA_TOP_BASE + 0x324)
+#define PLL_CTRL_0		(QP_PMA_TOP_BASE + 0x400)
+#define PLL_CTRL_2		(QP_PMA_TOP_BASE + 0x408)
+#define PLL_CTRL_3		(QP_PMA_TOP_BASE + 0x40c)
+#define PLL_CTRL_4		(QP_PMA_TOP_BASE + 0x410)
+#define PLL_CK_CTRL_0	(QP_PMA_TOP_BASE + 0x414)
+#define RX_DLY_0		(QP_PMA_TOP_BASE + 0x614)
+#define RX_CTRL_2		(QP_PMA_TOP_BASE + 0x630)
+#define RX_CTRL_5		(QP_PMA_TOP_BASE + 0x63c)
+#define RX_CTRL_6		(QP_PMA_TOP_BASE + 0x640)
+#define RX_CTRL_7		(QP_PMA_TOP_BASE + 0x644)
+#define RX_CTRL_8		(QP_PMA_TOP_BASE + 0x648)
+#define RX_CTRL_26		(QP_PMA_TOP_BASE + 0x690)
+#define RX_CTRL_42		(QP_PMA_TOP_BASE + 0x6d0)
+
+#define QP_ANA_CSR_BASE				0x1022f000
+#define RG_QP_RX_DAC_EN				(QP_ANA_CSR_BASE + 0x00)
+#define RG_QP_RXAFE_RESERVE			(QP_ANA_CSR_BASE + 0x04)
+#define RG_QP_CDR_LPF_MJV_LIM		(QP_ANA_CSR_BASE + 0x0c)
+#define RG_QP_CDR_LPF_SETVALUE		(QP_ANA_CSR_BASE + 0x14)
+#define RG_QP_CDR_PR_CKREF_DIV1		(QP_ANA_CSR_BASE + 0x18)
+#define RG_QP_CDR_PR_KBAND_DIV_PCIE	(QP_ANA_CSR_BASE + 0x1c)
+#define RG_QP_CDR_FORCE_IBANDLPF_R_OFF	(QP_ANA_CSR_BASE + 0x20)
+#define RG_QP_TX_MODE_16B_EN		(QP_ANA_CSR_BASE + 0x28)
+#define RG_QP_PLL_IPLL_DIG_PWR_SEL	(QP_ANA_CSR_BASE + 0x3c)
+#define RG_QP_PLL_SDM_ORD			(QP_ANA_CSR_BASE + 0x40)
+
+#define ETHER_SYS_BASE				0x1028c800
+#define RG_P5MUX_MODE				(ETHER_SYS_BASE + 0x00)
+#define RG_FORCE_CKDIR_SEL			(ETHER_SYS_BASE + 0x04)
+#define RG_SWITCH_MODE				(ETHER_SYS_BASE + 0x08)
+#define RG_FORCE_MAC5_SB			(ETHER_SYS_BASE + 0x2c)
+#define RG_GPHY_AFE_PWD				(ETHER_SYS_BASE + 0x40)
+#define RG_GPHY_SMI_ADDR			(ETHER_SYS_BASE + 0x48)
+#define CSR_RMII					(ETHER_SYS_BASE + 0x70)
+
+/* PHY EEE Register bitmap of define */
+#define PHY_DEV07				0x07
+#define PHY_DEV07_REG_03C		0x3c
+
+/* PHY Extend Register 0x14 bitmap of define */
+#define PHY_EXT_REG_14			0x14
+
+/* Fields of PHY_EXT_REG_14 */
+#define PHY_EN_DOWN_SHFIT		BIT(4)
+
+/* Unique fields of PMCR for AN8855 */
+#define FORCE_TX_FC		BIT(4)
+#define FORCE_RX_FC		BIT(5)
+#define FORCE_DPX		BIT(25)
+#define FORCE_SPD		BITS(28, 30)
+#define FORCE_LNK		BIT(24)
+#define FORCE_MODE		BIT(31)
+
+#define CHIP_ID			0x10005000
+#define CHIP_REV		0x10005004
+
+static int an8855_set_hsgmii_mode(struct gsw_an8855 *gsw)
+{
+	u32 val = 0;
+
+	/* PLL */
+	val = an8855_reg_read(gsw, QP_DIG_MODE_CTRL_1);
+	val &= ~(0x3 << 2);
+	val |= (0x1 << 2);
+	an8855_reg_write(gsw, QP_DIG_MODE_CTRL_1, val);
+
+	/* PLL - LPF */
+	val = an8855_reg_read(gsw, PLL_CTRL_2);
+	val &= ~(0x3 << 0);
+	val |= (0x1 << 0);
+	val &= ~(0x7 << 2);
+	val |= (0x5 << 2);
+	val &= ~BITS(6, 7);
+	val &= ~(0x7 << 8);
+	val |= (0x3 << 8);
+	val |= BIT(29);
+	val &= ~BITS(12, 13);
+	an8855_reg_write(gsw, PLL_CTRL_2, val);
+
+	/* PLL - ICO */
+	val = an8855_reg_read(gsw, PLL_CTRL_4);
+	val |= BIT(2);
+	an8855_reg_write(gsw, PLL_CTRL_4, val);
+
+	val = an8855_reg_read(gsw, PLL_CTRL_2);
+	val &= ~BIT(14);
+	an8855_reg_write(gsw, PLL_CTRL_2, val);
+
+	/* PLL - CHP */
+	val = an8855_reg_read(gsw, PLL_CTRL_2);
+	val &= ~(0xf << 16);
+	val |= (0x6 << 16);
+	an8855_reg_write(gsw, PLL_CTRL_2, val);
+
+	/* PLL - PFD */
+	val = an8855_reg_read(gsw, PLL_CTRL_2);
+	val &= ~(0x3 << 20);
+	val |= (0x1 << 20);
+	val &= ~(0x3 << 24);
+	val |= (0x1 << 24);
+	val &= ~BIT(26);
+	an8855_reg_write(gsw, PLL_CTRL_2, val);
+
+	/* PLL - POSTDIV */
+	val = an8855_reg_read(gsw, PLL_CTRL_2);
+	val |= BIT(22);
+	val &= ~BIT(27);
+	val &= ~BIT(28);
+	an8855_reg_write(gsw, PLL_CTRL_2, val);
+
+	/* PLL - SDM */
+	val = an8855_reg_read(gsw, PLL_CTRL_4);
+	val &= ~BITS(3, 4);
+	an8855_reg_write(gsw, PLL_CTRL_4, val);
+
+	val = an8855_reg_read(gsw, PLL_CTRL_2);
+	val &= ~BIT(30);
+	an8855_reg_write(gsw, PLL_CTRL_2, val);
+
+	val = an8855_reg_read(gsw, SS_LCPLL_PWCTL_SETTING_2);
+	val &= ~(0x3 << 16);
+	val |= (0x1 << 16);
+	an8855_reg_write(gsw, SS_LCPLL_PWCTL_SETTING_2, val);
+
+	an8855_reg_write(gsw, SS_LCPLL_TDC_FLT_2, 0x7a000000);
+	an8855_reg_write(gsw, SS_LCPLL_TDC_PCW_1, 0x7a000000);
+
+	val = an8855_reg_read(gsw, SS_LCPLL_TDC_FLT_5);
+	val &= ~BIT(24);
+	an8855_reg_write(gsw, SS_LCPLL_TDC_FLT_5, val);
+
+	val = an8855_reg_read(gsw, PLL_CK_CTRL_0);
+	val &= ~BIT(8);
+	an8855_reg_write(gsw, PLL_CK_CTRL_0, val);
+
+	/* PLL - SS */
+	val = an8855_reg_read(gsw, PLL_CTRL_3);
+	val &= ~BITS(0, 15);
+	an8855_reg_write(gsw, PLL_CTRL_3, val);
+
+	val = an8855_reg_read(gsw, PLL_CTRL_4);
+	val &= ~BITS(0, 1);
+	an8855_reg_write(gsw, PLL_CTRL_4, val);
+
+	val = an8855_reg_read(gsw, PLL_CTRL_3);
+	val &= ~BITS(16, 31);
+	an8855_reg_write(gsw, PLL_CTRL_3, val);
+
+	/* PLL - TDC */
+	val = an8855_reg_read(gsw, PLL_CK_CTRL_0);
+	val &= ~BIT(9);
+	an8855_reg_write(gsw, PLL_CK_CTRL_0, val);
+
+	val = an8855_reg_read(gsw, RG_QP_PLL_SDM_ORD);
+	val |= BIT(3);
+	val |= BIT(4);
+	an8855_reg_write(gsw, RG_QP_PLL_SDM_ORD, val);
+
+	val = an8855_reg_read(gsw, RG_QP_RX_DAC_EN);
+	val &= ~(0x3 << 16);
+	val |= (0x2 << 16);
+	an8855_reg_write(gsw, RG_QP_RX_DAC_EN, val);
+
+	/* TCL Disable (only for Co-SIM) */
+	val = an8855_reg_read(gsw, PON_RXFEDIG_CTRL_0);
+	val &= ~BIT(12);
+	an8855_reg_write(gsw, PON_RXFEDIG_CTRL_0, val);
+
+	/* TX Init */
+	val = an8855_reg_read(gsw, RG_QP_TX_MODE_16B_EN);
+	val &= ~BIT(0);
+	val &= ~(0xffff << 16);
+	val |= (0x4 << 16);
+	an8855_reg_write(gsw, RG_QP_TX_MODE_16B_EN, val);
+
+	/* RX Control */
+	val = an8855_reg_read(gsw, RG_QP_RXAFE_RESERVE);
+	val |= BIT(11);
+	an8855_reg_write(gsw, RG_QP_RXAFE_RESERVE, val);
+
+	val = an8855_reg_read(gsw, RG_QP_CDR_LPF_MJV_LIM);
+	val &= ~(0x3 << 4);
+	val |= (0x1 << 4);
+	an8855_reg_write(gsw, RG_QP_CDR_LPF_MJV_LIM, val);
+
+	val = an8855_reg_read(gsw, RG_QP_CDR_LPF_SETVALUE);
+	val &= ~(0xf << 25);
+	val |= (0x1 << 25);
+	val &= ~(0x7 << 29);
+	val |= (0x3 << 29);
+	an8855_reg_write(gsw, RG_QP_CDR_LPF_SETVALUE, val);
+
+	val = an8855_reg_read(gsw, RG_QP_CDR_PR_CKREF_DIV1);
+	val &= ~(0x1f << 8);
+	val |= (0xf << 8);
+	an8855_reg_write(gsw, RG_QP_CDR_PR_CKREF_DIV1, val);
+
+	val = an8855_reg_read(gsw, RG_QP_CDR_PR_KBAND_DIV_PCIE);
+	val &= ~(0x3f << 0);
+	val |= (0x19 << 0);
+	val &= ~BIT(6);
+	an8855_reg_write(gsw, RG_QP_CDR_PR_KBAND_DIV_PCIE, val);
+
+	val = an8855_reg_read(gsw, RG_QP_CDR_FORCE_IBANDLPF_R_OFF);
+	val &= ~(0x7f << 6);
+	val |= (0x21 << 6);
+	val &= ~(0x3 << 16);
+	val |= (0x2 << 16);
+	val &= ~BIT(13);
+	an8855_reg_write(gsw, RG_QP_CDR_FORCE_IBANDLPF_R_OFF, val);
+
+	val = an8855_reg_read(gsw, RG_QP_CDR_PR_KBAND_DIV_PCIE);
+	val &= ~BIT(30);
+	an8855_reg_write(gsw, RG_QP_CDR_PR_KBAND_DIV_PCIE, val);
+
+	val = an8855_reg_read(gsw, RG_QP_CDR_PR_CKREF_DIV1);
+	val &= ~(0x7 << 24);
+	val |= (0x4 << 24);
+	an8855_reg_write(gsw, RG_QP_CDR_PR_CKREF_DIV1, val);
+
+	val = an8855_reg_read(gsw, PLL_CTRL_0);
+	val |= BIT(0);
+	an8855_reg_write(gsw, PLL_CTRL_0, val);
+
+	val = an8855_reg_read(gsw, RX_CTRL_26);
+	val &= ~BIT(23);
+	val |= BIT(26);
+	an8855_reg_write(gsw, RX_CTRL_26, val);
+
+	val = an8855_reg_read(gsw, RX_DLY_0);
+	val &= ~(0xff << 0);
+	val |= (0x6f << 0);
+	val |= BITS(8, 13);
+	an8855_reg_write(gsw, RX_DLY_0, val);
+
+	val = an8855_reg_read(gsw, RX_CTRL_42);
+	val &= ~(0x1fff << 0);
+	val |= (0x150 << 0);
+	an8855_reg_write(gsw, RX_CTRL_42, val);
+
+	val = an8855_reg_read(gsw, RX_CTRL_2);
+	val &= ~(0x1fff << 16);
+	val |= (0x150 << 16);
+	an8855_reg_write(gsw, RX_CTRL_2, val);
+
+	val = an8855_reg_read(gsw, PON_RXFEDIG_CTRL_9);
+	val &= ~(0x7 << 0);
+	val |= (0x1 << 0);
+	an8855_reg_write(gsw, PON_RXFEDIG_CTRL_9, val);
+
+	val = an8855_reg_read(gsw, RX_CTRL_8);
+	val &= ~(0xfff << 16);
+	val |= (0x200 << 16);
+	val &= ~(0x7fff << 14);
+	val |= (0xfff << 14);
+	an8855_reg_write(gsw, RX_CTRL_8, val);
+
+	/* Frequency memter */
+	val = an8855_reg_read(gsw, RX_CTRL_5);
+	val &= ~(0xfffff << 10);
+	val |= (0x10 << 10);
+	an8855_reg_write(gsw, RX_CTRL_5, val);
+
+	val = an8855_reg_read(gsw, RX_CTRL_6);
+	val &= ~(0xfffff << 0);
+	val |= (0x64 << 0);
+	an8855_reg_write(gsw, RX_CTRL_6, val);
+
+	val = an8855_reg_read(gsw, RX_CTRL_7);
+	val &= ~(0xfffff << 0);
+	val |= (0x2710 << 0);
+	an8855_reg_write(gsw, RX_CTRL_7, val);
+
+	/* PCS Init */
+	val = an8855_reg_read(gsw, RG_HSGMII_PCS_CTROL_1);
+	val &= ~BIT(30);
+	an8855_reg_write(gsw, RG_HSGMII_PCS_CTROL_1, val);
+
+	/* Rate Adaption */
+	val = an8855_reg_read(gsw, RATE_ADP_P0_CTRL_0);
+	val &= ~BIT(31);
+	an8855_reg_write(gsw, RATE_ADP_P0_CTRL_0, val);
+
+	val = an8855_reg_read(gsw, RG_RATE_ADAPT_CTRL_0);
+	val |= BIT(0);
+	val |= BIT(4);
+	val |= BITS(26, 27);
+	an8855_reg_write(gsw, RG_RATE_ADAPT_CTRL_0, val);
+
+	/* Disable AN */
+	val = an8855_reg_read(gsw, SGMII_REG_AN0);
+	val &= ~BIT(12);
+	an8855_reg_write(gsw, SGMII_REG_AN0, val);
+
+	/* Force Speed */
+	val = an8855_reg_read(gsw, SGMII_STS_CTRL_0);
+	val |= BIT(2);
+	val |= BITS(4, 5);
+	an8855_reg_write(gsw, SGMII_STS_CTRL_0, val);
+
+	/* bypass flow control to MAC */
+	an8855_reg_write(gsw, MSG_RX_LIK_STS_0, 0x01010107);
+	an8855_reg_write(gsw, MSG_RX_LIK_STS_2, 0x00000EEF);
+
+	return 0;
+}
+
+static int an8855_sgmii_setup(struct gsw_an8855 *gsw, int mode)
+{
+	u32 val = 0;
+
+	/* PMA Init */
+	/* PLL */
+	val = an8855_reg_read(gsw, QP_DIG_MODE_CTRL_1);
+	val &= ~BITS(2, 3);
+	an8855_reg_write(gsw, QP_DIG_MODE_CTRL_1, val);
+
+	/* PLL - LPF */
+	val = an8855_reg_read(gsw, PLL_CTRL_2);
+	val &= ~(0x3 << 0);
+	val |= (0x1 << 0);
+	val &= ~(0x7 << 2);
+	val |= (0x5 << 2);
+	val &= ~BITS(6, 7);
+	val &= ~(0x7 << 8);
+	val |= (0x3 << 8);
+	val |= BIT(29);
+	val &= ~BITS(12, 13);
+	an8855_reg_write(gsw, PLL_CTRL_2, val);
+
+	/* PLL - ICO */
+	val = an8855_reg_read(gsw, PLL_CTRL_4);
+	val |= BIT(2);
+	an8855_reg_write(gsw, PLL_CTRL_4, val);
+
+	val = an8855_reg_read(gsw, PLL_CTRL_2);
+	val &= ~BIT(14);
+	an8855_reg_write(gsw, PLL_CTRL_2, val);
+
+	/* PLL - CHP */
+	val = an8855_reg_read(gsw, PLL_CTRL_2);
+	val &= ~(0xf << 16);
+	val |= (0x4 << 16);
+	an8855_reg_write(gsw, PLL_CTRL_2, val);
+
+	/* PLL - PFD */
+	val = an8855_reg_read(gsw, PLL_CTRL_2);
+	val &= ~(0x3 << 20);
+	val |= (0x1 << 20);
+	val &= ~(0x3 << 24);
+	val |= (0x1 << 24);
+	val &= ~BIT(26);
+	an8855_reg_write(gsw, PLL_CTRL_2, val);
+
+	/* PLL - POSTDIV */
+	val = an8855_reg_read(gsw, PLL_CTRL_2);
+	val |= BIT(22);
+	val &= ~BIT(27);
+	val &= ~BIT(28);
+	an8855_reg_write(gsw, PLL_CTRL_2, val);
+
+	/* PLL - SDM */
+	val = an8855_reg_read(gsw, PLL_CTRL_4);
+	val &= ~BITS(3, 4);
+	an8855_reg_write(gsw, PLL_CTRL_4, val);
+
+	val = an8855_reg_read(gsw, PLL_CTRL_2);
+	val &= ~BIT(30);
+	an8855_reg_write(gsw, PLL_CTRL_2, val);
+
+	val = an8855_reg_read(gsw, SS_LCPLL_PWCTL_SETTING_2);
+	val &= ~(0x3 << 16);
+	val |= (0x1 << 16);
+	an8855_reg_write(gsw, SS_LCPLL_PWCTL_SETTING_2, val);
+
+	an8855_reg_write(gsw, SS_LCPLL_TDC_FLT_2, 0x48000000);
+	an8855_reg_write(gsw, SS_LCPLL_TDC_PCW_1, 0x48000000);
+
+	val = an8855_reg_read(gsw, SS_LCPLL_TDC_FLT_5);
+	val &= ~BIT(24);
+	an8855_reg_write(gsw, SS_LCPLL_TDC_FLT_5, val);
+
+	val = an8855_reg_read(gsw, PLL_CK_CTRL_0);
+	val &= ~BIT(8);
+	an8855_reg_write(gsw, PLL_CK_CTRL_0, val);
+
+	/* PLL - SS */
+	val = an8855_reg_read(gsw, PLL_CTRL_3);
+	val &= ~BITS(0, 15);
+	an8855_reg_write(gsw, PLL_CTRL_3, val);
+
+	val = an8855_reg_read(gsw, PLL_CTRL_4);
+	val &= ~BITS(0, 1);
+	an8855_reg_write(gsw, PLL_CTRL_4, val);
+
+	val = an8855_reg_read(gsw, PLL_CTRL_3);
+	val &= ~BITS(16, 31);
+	an8855_reg_write(gsw, PLL_CTRL_3, val);
+
+	/* PLL - TDC */
+	val = an8855_reg_read(gsw, PLL_CK_CTRL_0);
+	val &= ~BIT(9);
+	an8855_reg_write(gsw, PLL_CK_CTRL_0, val);
+
+	val = an8855_reg_read(gsw, RG_QP_PLL_SDM_ORD);
+	val |= BIT(3);
+	val |= BIT(4);
+	an8855_reg_write(gsw, RG_QP_PLL_SDM_ORD, val);
+
+	val = an8855_reg_read(gsw, RG_QP_RX_DAC_EN);
+	val &= ~(0x3 << 16);
+	val |= (0x2 << 16);
+	an8855_reg_write(gsw, RG_QP_RX_DAC_EN, val);
+
+	/* PLL - TCL Disable (only for Co-SIM) */
+	val = an8855_reg_read(gsw, PON_RXFEDIG_CTRL_0);
+	val &= ~BIT(12);
+	an8855_reg_write(gsw, PON_RXFEDIG_CTRL_0, val);
+
+	/* TX Init */
+	val = an8855_reg_read(gsw, RG_QP_TX_MODE_16B_EN);
+	val &= ~BIT(0);
+	val &= ~BITS(16, 31);
+	an8855_reg_write(gsw, RG_QP_TX_MODE_16B_EN, val);
+
+	/* RX Init */
+	val = an8855_reg_read(gsw, RG_QP_RXAFE_RESERVE);
+	val |= BIT(11);
+	an8855_reg_write(gsw, RG_QP_RXAFE_RESERVE, val);
+
+	val = an8855_reg_read(gsw, RG_QP_CDR_LPF_MJV_LIM);
+	val &= ~(0x3 << 4);
+	val |= (0x2 << 4);
+	an8855_reg_write(gsw, RG_QP_CDR_LPF_MJV_LIM, val);
+
+	val = an8855_reg_read(gsw, RG_QP_CDR_LPF_SETVALUE);
+	val &= ~(0xf << 25);
+	val |= (0x1 << 25);
+	val &= ~(0x7 << 29);
+	val |= (0x6 << 29);
+	an8855_reg_write(gsw, RG_QP_CDR_LPF_SETVALUE, val);
+
+	val = an8855_reg_read(gsw, RG_QP_CDR_PR_CKREF_DIV1);
+	val &= ~(0x1f << 8);
+	val |= (0xc << 8);
+	an8855_reg_write(gsw, RG_QP_CDR_PR_CKREF_DIV1, val);
+
+	val = an8855_reg_read(gsw, RG_QP_CDR_PR_KBAND_DIV_PCIE);
+	val &= ~(0x3f << 0);
+	val |= (0x19 << 0);
+	val &= ~BIT(6);
+	an8855_reg_write(gsw, RG_QP_CDR_PR_KBAND_DIV_PCIE, val);
+
+	val = an8855_reg_read(gsw, RG_QP_CDR_FORCE_IBANDLPF_R_OFF);
+	val &= ~(0x7f << 6);
+	val |= (0x21 << 6);
+	val &= ~(0x3 << 16);
+	val |= (0x2 << 16);
+	val &= ~BIT(13);
+	an8855_reg_write(gsw, RG_QP_CDR_FORCE_IBANDLPF_R_OFF, val);
+
+	val = an8855_reg_read(gsw, RG_QP_CDR_PR_KBAND_DIV_PCIE);
+	val &= ~BIT(30);
+	an8855_reg_write(gsw, RG_QP_CDR_PR_KBAND_DIV_PCIE, val);
+
+	val = an8855_reg_read(gsw, RG_QP_CDR_PR_CKREF_DIV1);
+	val &= ~(0x7 << 24);
+	val |= (0x4 << 24);
+	an8855_reg_write(gsw, RG_QP_CDR_PR_CKREF_DIV1, val);
+
+	val = an8855_reg_read(gsw, PLL_CTRL_0);
+	val |= BIT(0);
+	an8855_reg_write(gsw, PLL_CTRL_0, val);
+
+	val = an8855_reg_read(gsw, RX_CTRL_26);
+	val &= ~BIT(23);
+	if (mode == SGMII_MODE_AN)
+		val |= BIT(26);
+
+	an8855_reg_write(gsw, RX_CTRL_26, val);
+
+	val = an8855_reg_read(gsw, RX_DLY_0);
+	val &= ~(0xff << 0);
+	val |= (0x6f << 0);
+	val |= BITS(8, 13);
+	an8855_reg_write(gsw, RX_DLY_0, val);
+
+	val = an8855_reg_read(gsw, RX_CTRL_42);
+	val &= ~(0x1fff << 0);
+	val |= (0x150 << 0);
+	an8855_reg_write(gsw, RX_CTRL_42, val);
+
+	val = an8855_reg_read(gsw, RX_CTRL_2);
+	val &= ~(0x1fff << 16);
+	val |= (0x150 << 16);
+	an8855_reg_write(gsw, RX_CTRL_2, val);
+
+	val = an8855_reg_read(gsw, PON_RXFEDIG_CTRL_9);
+	val &= ~(0x7 << 0);
+	val |= (0x1 << 0);
+	an8855_reg_write(gsw, PON_RXFEDIG_CTRL_9, val);
+
+	val = an8855_reg_read(gsw, RX_CTRL_8);
+	val &= ~(0xfff << 16);
+	val |= (0x200 << 16);
+	val &= ~(0x7fff << 0);
+	val |= (0xfff << 0);
+	an8855_reg_write(gsw, RX_CTRL_8, val);
+
+	/* Frequency memter */
+	val = an8855_reg_read(gsw, RX_CTRL_5);
+	val &= ~(0xfffff << 10);
+	val |= (0x28 << 10);
+	an8855_reg_write(gsw, RX_CTRL_5, val);
+
+	val = an8855_reg_read(gsw, RX_CTRL_6);
+	val &= ~(0xfffff << 0);
+	val |= (0x64 << 0);
+	an8855_reg_write(gsw, RX_CTRL_6, val);
+
+	val = an8855_reg_read(gsw, RX_CTRL_7);
+	val &= ~(0xfffff << 0);
+	val |= (0x2710 << 0);
+	an8855_reg_write(gsw, RX_CTRL_7, val);
+
+	if (mode == SGMII_MODE_FORCE) {
+		/* PCS Init */
+		val = an8855_reg_read(gsw, QP_DIG_MODE_CTRL_0);
+		val &= ~BIT(0);
+		val &= ~BITS(4, 5);
+		an8855_reg_write(gsw, QP_DIG_MODE_CTRL_0, val);
+
+		val = an8855_reg_read(gsw, RG_HSGMII_PCS_CTROL_1);
+		val &= ~BIT(30);
+		an8855_reg_write(gsw, RG_HSGMII_PCS_CTROL_1, val);
+
+		/* Rate Adaption - GMII path config. */
+		val = an8855_reg_read(gsw, RG_AN_SGMII_MODE_FORCE);
+		val |= BIT(0);
+		val &= ~BITS(4, 5);
+		an8855_reg_write(gsw, RG_AN_SGMII_MODE_FORCE, val);
+
+		val = an8855_reg_read(gsw, SGMII_STS_CTRL_0);
+		val |= BIT(2);
+		val &= ~(0x3 << 4);
+		val |= (0x2 << 4);
+		an8855_reg_write(gsw, SGMII_STS_CTRL_0, val);
+
+		val = an8855_reg_read(gsw, SGMII_REG_AN0);
+		val &= ~BIT(12);
+		an8855_reg_write(gsw, SGMII_REG_AN0, val);
+
+		val = an8855_reg_read(gsw, PHY_RX_FORCE_CTRL_0);
+		val |= BIT(4);
+		an8855_reg_write(gsw, PHY_RX_FORCE_CTRL_0, val);
+
+		val = an8855_reg_read(gsw, RATE_ADP_P0_CTRL_0);
+		val &= ~BITS(0, 3);
+		val |= BIT(28);
+		an8855_reg_write(gsw, RATE_ADP_P0_CTRL_0, val);
+
+		val = an8855_reg_read(gsw, RG_RATE_ADAPT_CTRL_0);
+		val |= BIT(0);
+		val |= BIT(4);
+		val |= BITS(26, 27);
+		an8855_reg_write(gsw, RG_RATE_ADAPT_CTRL_0, val);
+	} else {
+		/* PCS Init */
+		val = an8855_reg_read(gsw, RG_HSGMII_PCS_CTROL_1);
+		val &= ~BIT(30);
+		an8855_reg_write(gsw, RG_HSGMII_PCS_CTROL_1, val);
+
+		/* Set AN Ability - Interrupt */
+		val = an8855_reg_read(gsw, SGMII_REG_AN_FORCE_CL37);
+		val |= BIT(0);
+		an8855_reg_write(gsw, SGMII_REG_AN_FORCE_CL37, val);
+
+		val = an8855_reg_read(gsw, SGMII_REG_AN_13);
+		val &= ~(0x3f << 0);
+		val |= (0xb << 0);
+		val |= BIT(8);
+		an8855_reg_write(gsw, SGMII_REG_AN_13, val);
+
+		/* Rate Adaption - GMII path config. */
+		val = an8855_reg_read(gsw, SGMII_REG_AN0);
+		val |= BIT(12);
+		an8855_reg_write(gsw, SGMII_REG_AN0, val);
+
+		val = an8855_reg_read(gsw, MII_RA_AN_ENABLE);
+		val |= BIT(0);
+		an8855_reg_write(gsw, MII_RA_AN_ENABLE, val);
+
+		val = an8855_reg_read(gsw, RATE_ADP_P0_CTRL_0);
+		val |= BIT(28);
+		an8855_reg_write(gsw, RATE_ADP_P0_CTRL_0, val);
+
+		val = an8855_reg_read(gsw, RG_RATE_ADAPT_CTRL_0);
+		val |= BIT(0);
+		val |= BIT(4);
+		val |= BITS(26, 27);
+		an8855_reg_write(gsw, RG_RATE_ADAPT_CTRL_0, val);
+
+		/* Only for Co-SIM */
+
+		/* AN Speed up (Only for Co-SIM) */
+
+		/* Restart AN */
+		val = an8855_reg_read(gsw, SGMII_REG_AN0);
+		val |= BIT(9);
+		val |= BIT(15);
+		an8855_reg_write(gsw, SGMII_REG_AN0, val);
+	}
+
+	/* bypass flow control to MAC */
+	an8855_reg_write(gsw, MSG_RX_LIK_STS_0, 0x01010107);
+	an8855_reg_write(gsw, MSG_RX_LIK_STS_2, 0x00000EEF);
+
+	return 0;
+}
+
+static int an8855_set_port_rmii(struct gsw_an8855 *gsw)
+{
+	an8855_reg_write(gsw, RG_P5MUX_MODE, 0x301);
+	an8855_reg_write(gsw, RG_FORCE_CKDIR_SEL, 0x101);
+	an8855_reg_write(gsw, RG_SWITCH_MODE, 0x101);
+	an8855_reg_write(gsw, RG_FORCE_MAC5_SB, 0x1010101);
+	an8855_reg_write(gsw, CSR_RMII, 0x420102);
+	an8855_reg_write(gsw, RG_RGMII_TXCK_C, 0x1100910);
+	return 0;
+}
+
+static int an8855_set_port_rgmii(struct gsw_an8855 *gsw)
+{
+	an8855_reg_write(gsw, RG_FORCE_MAC5_SB, 0x20101);
+	return 0;
+}
+
+static int an8855_mac_port_setup(struct gsw_an8855 *gsw, u32 port,
+				 struct an8855_port_cfg *port_cfg)
+{
+	u32 pmcr;
+
+	if (port != 5) {
+		dev_info(gsw->dev, "port %d is not a MAC port\n", port);
+		return -EINVAL;
+	}
+
+	if (port_cfg->enabled) {
+		pmcr = an8855_reg_read(gsw, PMCR(5));
+
+		switch (port_cfg->phy_mode) {
+		case PHY_INTERFACE_MODE_RMII:
+			pmcr &= ~FORCE_SPD;
+			pmcr |= FORCE_MODE | (MAC_SPD_100 << 28) | FORCE_DPX
+				| FORCE_LNK | FORCE_TX_FC | FORCE_RX_FC;
+			an8855_set_port_rmii(gsw);
+			break;
+		case PHY_INTERFACE_MODE_RGMII:
+			pmcr &= ~FORCE_SPD;
+			pmcr |= FORCE_MODE | (MAC_SPD_1000 << 28) | FORCE_DPX
+				| FORCE_LNK | FORCE_TX_FC | FORCE_RX_FC;
+			an8855_set_port_rgmii(gsw);
+			break;
+		case PHY_INTERFACE_MODE_SGMII:
+			if (port_cfg->force_link) {
+				pmcr &= ~FORCE_SPD;
+				pmcr |= FORCE_MODE | (MAC_SPD_1000 << 28)
+					 | FORCE_DPX | FORCE_LNK | FORCE_TX_FC
+					 | FORCE_RX_FC;
+				an8855_sgmii_setup(gsw, SGMII_MODE_FORCE);
+			} else
+				an8855_sgmii_setup(gsw, SGMII_MODE_AN);
+			break;
+		case PHY_INTERFACE_MODE_2500BASEX:
+			pmcr &= ~FORCE_SPD;
+			pmcr |= FORCE_MODE | (MAC_SPD_2500 << 28) | FORCE_DPX
+				| FORCE_LNK | FORCE_TX_FC | FORCE_RX_FC;
+			an8855_set_hsgmii_mode(gsw);
+			break;
+		default:
+			dev_info(gsw->dev, "%s is not supported by port %d\n",
+				 phy_modes(port_cfg->phy_mode), port);
+		}
+
+		if (port_cfg->force_link)
+			an8855_reg_write(gsw, PMCR(port), pmcr);
+	}
+
+	return 0;
+}
+
+static int an8855_sw_detect(struct gsw_an8855 *gsw, struct chip_rev *crev)
+{
+	u32 id, rev;
+
+	id = an8855_reg_read(gsw, CHIP_ID);
+	rev = an8855_reg_read(gsw, CHIP_REV);
+	if (id == AN8855) {
+		if (crev) {
+			crev->rev = rev;
+			crev->name = "AN8855";
+		}
+
+		return 0;
+	}
+
+	return -ENODEV;
+}
+
+static void an8855_phy_setting(struct gsw_an8855 *gsw)
+{
+	int i;
+	u32 val;
+
+	/* Release power down */
+	an8855_reg_write(gsw, RG_GPHY_AFE_PWD, 0x0);
+
+	for (i = 0; i < AN8855_NUM_PHYS; i++) {
+		/* Enable HW auto downshift */
+		gsw->mii_write(gsw, i, 0x1f, 0x1);
+		val = gsw->mii_read(gsw, i, PHY_EXT_REG_14);
+		val |= PHY_EN_DOWN_SHFIT;
+		gsw->mii_write(gsw, i, PHY_EXT_REG_14, val);
+		gsw->mii_write(gsw, i, 0x1f, 0x0);
+
+		/* Enable Asymmetric Pause Capability */
+		val = gsw->mii_read(gsw, i, MII_ADVERTISE);
+		val |= ADVERTISE_PAUSE_ASYM;
+		gsw->mii_write(gsw, i, MII_ADVERTISE, val);
+	}
+}
+
+static void an8855_low_power_setting(struct gsw_an8855 *gsw)
+{
+	int port, addr;
+
+	for (port = 0; port < AN8855_NUM_PHYS; port++) {
+		gsw->mmd_write(gsw, port, 0x1e, 0x11, 0x0f00);
+		gsw->mmd_write(gsw, port, 0x1e, 0x3c, 0x0000);
+		gsw->mmd_write(gsw, port, 0x1e, 0x3d, 0x0000);
+		gsw->mmd_write(gsw, port, 0x1e, 0x3e, 0x0000);
+		gsw->mmd_write(gsw, port, 0x1e, 0xc6, 0x53aa);
+	}
+
+	gsw->mmd_write(gsw, 0, 0x1f, 0x268, 0x07f1);
+	gsw->mmd_write(gsw, 0, 0x1f, 0x269, 0x2111);
+	gsw->mmd_write(gsw, 0, 0x1f, 0x26a, 0x0000);
+	gsw->mmd_write(gsw, 0, 0x1f, 0x26b, 0x0074);
+	gsw->mmd_write(gsw, 0, 0x1f, 0x26e, 0x00f6);
+	gsw->mmd_write(gsw, 0, 0x1f, 0x26f, 0x6666);
+	gsw->mmd_write(gsw, 0, 0x1f, 0x271, 0x2c02);
+	gsw->mmd_write(gsw, 0, 0x1f, 0x272, 0x0c22);
+	gsw->mmd_write(gsw, 0, 0x1f, 0x700, 0x0001);
+	gsw->mmd_write(gsw, 0, 0x1f, 0x701, 0x0803);
+	gsw->mmd_write(gsw, 0, 0x1f, 0x702, 0x01b6);
+	gsw->mmd_write(gsw, 0, 0x1f, 0x703, 0x2111);
+
+	gsw->mmd_write(gsw, 1, 0x1f, 0x700, 0x0001);
+
+	for (addr = 0x200; addr <= 0x230; addr += 2)
+		gsw->mmd_write(gsw, 0, 0x1f, addr, 0x2020);
+
+	for (addr = 0x201; addr <= 0x231; addr += 2)
+		gsw->mmd_write(gsw, 0, 0x1f, addr, 0x0020);
+}
+
+static void an8855_eee_setting(struct gsw_an8855 *gsw, u32 port)
+{
+	/* Disable EEE */
+	gsw->mmd_write(gsw, port, PHY_DEV07, PHY_DEV07_REG_03C, 0);
+}
+
+static int an8855_sw_init(struct gsw_an8855 *gsw)
+{
+	int i;
+	u32 val;
+
+	gsw->phy_base = gsw->smi_addr & AN8855_SMI_ADDR_MASK;
+
+	gsw->mii_read = an8855_mii_read;
+	gsw->mii_write = an8855_mii_write;
+	gsw->mmd_read = an8855_mmd_read;
+	gsw->mmd_write = an8855_mmd_write;
+
+	/* Force MAC link down before reset */
+	an8855_reg_write(gsw, PMCR(5), FORCE_MODE);
+
+	/* Switch soft reset */
+	an8855_reg_write(gsw, SYS_CTRL, SW_SYS_RST);
+	usleep_range(100000, 110000);
+
+	/* change gphy smi address */
+	if (gsw->new_smi_addr != gsw->smi_addr) {
+		an8855_reg_write(gsw, RG_GPHY_SMI_ADDR, gsw->new_smi_addr);
+		gsw->smi_addr = gsw->new_smi_addr;
+		gsw->phy_base = gsw->new_smi_addr;
+	}
+
+	for (i = 0; i < AN8855_NUM_PHYS; i++) {
+		val = gsw->mii_read(gsw, i, MII_BMCR);
+		val |= BMCR_ISOLATE;
+		gsw->mii_write(gsw, i, MII_BMCR, val);
+	}
+
+	an8855_mac_port_setup(gsw, 5, &gsw->port5_cfg);
+
+	/* Global mac control settings */
+	val = an8855_reg_read(gsw, GMACCR);
+	val |= (15 << MAX_RX_JUMBO_S) | RX_PKT_LEN_MAX_JUMBO;
+	an8855_reg_write(gsw, GMACCR, val);
+
+	val = an8855_reg_read(gsw, CKGCR);
+	val &= ~(CKG_LNKDN_GLB_STOP | CKG_LNKDN_PORT_STOP);
+	an8855_reg_write(gsw, CKGCR, val);
+	return 0;
+}
+
+static int an8855_sw_post_init(struct gsw_an8855 *gsw)
+{
+	int i;
+	u32 val;
+
+	for (i = 0; i < AN8855_NUM_PHYS; i++) {
+		val = gsw->mii_read(gsw, i, MII_BMCR);
+		val &= ~BMCR_ISOLATE;
+		gsw->mii_write(gsw, i, MII_BMCR, val);
+	}
+
+	an8855_phy_setting(gsw);
+
+	for (i = 0; i < AN8855_NUM_PHYS; i++)
+		an8855_eee_setting(gsw, i);
+
+	/* PHY restart AN*/
+	for (i = 0; i < AN8855_NUM_PHYS; i++)
+		gsw->mii_write(gsw, i, MII_BMCR, 0x1240);
+
+	return 0;
+}
+
+struct an8855_sw_id an8855_id = {
+	.model = AN8855,
+	.detect = an8855_sw_detect,
+	.init = an8855_sw_init,
+	.post_init = an8855_sw_post_init
+};
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Min Yao <min.yao@airoha.com>");
+MODULE_DESCRIPTION("Driver for Airoha AN8855 Gigabit Switch");
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/airoha/an8855/an8855.h b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/airoha/an8855/an8855.h
new file mode 100644
index 0000000..883ba6e
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/airoha/an8855/an8855.h
@@ -0,0 +1,122 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2023 Airoha Inc.
+ * Author: Min Yao <min.yao@airoha.com>
+ */
+
+#ifndef _AN8855_H_
+#define _AN8855_H_
+
+#include <linux/list.h>
+#include <linux/mutex.h>
+#include <linux/netdevice.h>
+#include <linux/of_mdio.h>
+#include <linux/workqueue.h>
+#include <linux/gpio/consumer.h>
+#include <linux/phy.h>
+
+#ifdef CONFIG_SWCONFIG
+#include <linux/switch.h>
+#endif
+
+#include "an8855_vlan.h"
+
+#define AN8855_DFL_CPU_PORT		5
+#define AN8855_NUM_PHYS			5
+#define AN8855_DFL_SMI_ADDR		0x1
+#define AN8855_SMI_ADDR_MASK	0x1f
+
+struct gsw_an8855;
+
+enum an8855_model {
+	AN8855 = 0x8855,
+};
+
+enum sgmii_mode {
+	SGMII_MODE_AN,
+	SGMII_MODE_FORCE,
+};
+
+struct an8855_port_cfg {
+	struct device_node *np;
+	phy_interface_t phy_mode;
+	u32 enabled: 1;
+	u32 force_link: 1;
+	u32 speed: 2;
+	u32 duplex: 1;
+	bool stag_on;
+};
+
+struct gsw_an8855 {
+	u32 id;
+
+	struct device *dev;
+	struct mii_bus *host_bus;
+	u32 smi_addr;
+	u32 new_smi_addr;
+	u32 phy_base;
+
+	enum an8855_model model;
+	const char *name;
+
+	struct an8855_port_cfg port5_cfg;
+
+	int phy_link_sts;
+
+	int irq;
+	int reset_pin;
+	struct work_struct irq_worker;
+
+#ifdef CONFIG_SWCONFIG
+	struct switch_dev swdev;
+	u32 cpu_port;
+#endif
+
+	int global_vlan_enable;
+	struct an8855_vlan_entry vlan_entries[AN8855_NUM_VLANS];
+	struct an8855_port_entry port_entries[AN8855_NUM_PORTS];
+
+	int (*mii_read)(struct gsw_an8855 *gsw, int phy, int reg);
+	void (*mii_write)(struct gsw_an8855 *gsw, int phy, int reg, u16 val);
+
+	int (*mmd_read)(struct gsw_an8855 *gsw, int addr, int devad, u16 reg);
+	void (*mmd_write)(struct gsw_an8855 *gsw, int addr, int devad, u16 reg,
+			  u16 val);
+
+	struct list_head list;
+};
+
+struct chip_rev {
+	const char *name;
+	u32 rev;
+};
+
+struct an8855_sw_id {
+	enum an8855_model model;
+	int (*detect)(struct gsw_an8855 *gsw, struct chip_rev *crev);
+	int (*init)(struct gsw_an8855 *gsw);
+	int (*post_init)(struct gsw_an8855 *gsw);
+};
+
+extern struct list_head an8855_devs;
+extern struct an8855_sw_id an8855_id;
+
+struct gsw_an8855 *an8855_get_gsw(u32 id);
+struct gsw_an8855 *an8855_get_first_gsw(void);
+void an8855_put_gsw(void);
+void an8855_lock_gsw(void);
+
+u32 an8855_reg_read(struct gsw_an8855 *gsw, u32 reg);
+void an8855_reg_write(struct gsw_an8855 *gsw, u32 reg, u32 val);
+
+int an8855_mii_read(struct gsw_an8855 *gsw, int phy, int reg);
+void an8855_mii_write(struct gsw_an8855 *gsw, int phy, int reg, u16 val);
+
+int an8855_mmd_read(struct gsw_an8855 *gsw, int addr, int devad, u16 reg);
+void an8855_mmd_write(struct gsw_an8855 *gsw, int addr, int devad, u16 reg,
+			  u16 val);
+
+void an8855_irq_worker(struct work_struct *work);
+void an8855_irq_enable(struct gsw_an8855 *gsw);
+
+#endif /* _AN8855_H_ */
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/airoha/an8855/an8855_common.c b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/airoha/an8855/an8855_common.c
new file mode 100644
index 0000000..c01b5c4
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/airoha/an8855/an8855_common.c
@@ -0,0 +1,96 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) 2023 Airoha Inc.
+ * Author: Min Yao <min.yao@airoha.com>
+ */
+
+#include <linux/kernel.h>
+#include <linux/delay.h>
+
+#include "an8855.h"
+#include "an8855_regs.h"
+
+void an8855_irq_enable(struct gsw_an8855 *gsw)
+{
+	u32 val;
+	int i;
+
+	/* Record initial PHY link status */
+	for (i = 0; i < AN8855_NUM_PHYS; i++) {
+		val = gsw->mii_read(gsw, i, MII_BMSR);
+		if (val & BMSR_LSTATUS)
+			gsw->phy_link_sts |= BIT(i);
+	}
+
+	val = BIT(AN8855_NUM_PHYS) - 1;
+	an8855_reg_write(gsw, SYS_INT_EN, val);
+
+	val = an8855_reg_read(gsw, INT_MASK);
+	val |= INT_SYS_BIT;
+	an8855_reg_write(gsw, INT_MASK, val);
+}
+
+static void display_port_link_status(struct gsw_an8855 *gsw, u32 port)
+{
+	u32 pmsr, speed_bits;
+	const char *speed;
+
+	pmsr = an8855_reg_read(gsw, PMSR(port));
+
+	speed_bits = (pmsr & MAC_SPD_STS_M) >> MAC_SPD_STS_S;
+
+	switch (speed_bits) {
+	case MAC_SPD_10:
+		speed = "10Mbps";
+		break;
+	case MAC_SPD_100:
+		speed = "100Mbps";
+		break;
+	case MAC_SPD_1000:
+		speed = "1Gbps";
+		break;
+	case MAC_SPD_2500:
+		speed = "2.5Gbps";
+		break;
+	default:
+		dev_info(gsw->dev, "Invalid speed\n");
+		return;
+	}
+
+	if (pmsr & MAC_LNK_STS) {
+		dev_info(gsw->dev, "Port %d Link is Up - %s/%s\n",
+			 port, speed, (pmsr & MAC_DPX_STS) ? "Full" : "Half");
+	} else {
+		dev_info(gsw->dev, "Port %d Link is Down\n", port);
+	}
+}
+
+void an8855_irq_worker(struct work_struct *work)
+{
+	struct gsw_an8855 *gsw;
+	u32 sts, physts, laststs;
+	int i;
+
+	gsw = container_of(work, struct gsw_an8855, irq_worker);
+
+	sts = an8855_reg_read(gsw, SYS_INT_STS);
+
+	/* Check for changed PHY link status */
+	for (i = 0; i < AN8855_NUM_PHYS; i++) {
+		if (!(sts & PHY_LC_INT(i)))
+			continue;
+
+		laststs = gsw->phy_link_sts & BIT(i);
+		physts = !!(gsw->mii_read(gsw, i, MII_BMSR) & BMSR_LSTATUS);
+		physts <<= i;
+
+		if (physts ^ laststs) {
+			gsw->phy_link_sts ^= BIT(i);
+			display_port_link_status(gsw, i);
+		}
+	}
+
+	an8855_reg_write(gsw, SYS_INT_STS, sts);
+
+	enable_irq(gsw->irq);
+}
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/airoha/an8855/an8855_mdio.c b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/airoha/an8855/an8855_mdio.c
new file mode 100644
index 0000000..920240d
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/airoha/an8855/an8855_mdio.c
@@ -0,0 +1,491 @@
+// SPDX-License-Identifian8855_gsw_ider: GPL-2.0
+/*
+ * Copyright (c) 2023 Airoha Inc.
+ * Author: Min Yao <min.yao@airoha.com>
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/device.h>
+#include <linux/delay.h>
+#include <linux/reset.h>
+#include <linux/hrtimer.h>
+#include <linux/mii.h>
+#include <linux/of_mdio.h>
+#include <linux/of_platform.h>
+#include <linux/of_gpio.h>
+#include <linux/of_net.h>
+#include <linux/of_irq.h>
+#include <linux/phy.h>
+
+#include "an8855.h"
+#include "an8855_swconfig.h"
+#include "an8855_regs.h"
+#include "an8855_nl.h"
+
+/* AN8855 driver version */
+#define ARHT_AN8855_SWCFG_DRIVER_VER	"1.0.1-L5.4"
+
+static u32 an8855_gsw_id;
+struct list_head an8855_devs;
+static DEFINE_MUTEX(an8855_devs_lock);
+
+static struct an8855_sw_id *an8855_sw_ids[] = {
+	&an8855_id,
+};
+
+u32 an8855_reg_read(struct gsw_an8855 *gsw, u32 reg)
+{
+	u32 high, low;
+
+	mutex_lock(&gsw->host_bus->mdio_lock);
+
+	gsw->host_bus->write(gsw->host_bus, gsw->smi_addr, 0x1f, 0x4);
+	gsw->host_bus->write(gsw->host_bus, gsw->smi_addr, 0x10, 0x0);
+
+	gsw->host_bus->write(gsw->host_bus, gsw->smi_addr, 0x15,
+			     ((reg >> 16) & 0xFFFF));
+	gsw->host_bus->write(gsw->host_bus, gsw->smi_addr, 0x16,
+			     (reg & 0xFFFF));
+
+	low = gsw->host_bus->read(gsw->host_bus, gsw->smi_addr, 0x18);
+	high = gsw->host_bus->read(gsw->host_bus, gsw->smi_addr, 0x17);
+
+	gsw->host_bus->write(gsw->host_bus, gsw->smi_addr, 0x1f, 0x0);
+	gsw->host_bus->write(gsw->host_bus, gsw->smi_addr, 0x10, 0x0);
+
+	mutex_unlock(&gsw->host_bus->mdio_lock);
+
+	return (high << 16) | (low & 0xffff);
+}
+
+void an8855_reg_write(struct gsw_an8855 *gsw, u32 reg, u32 val)
+{
+	mutex_lock(&gsw->host_bus->mdio_lock);
+
+	gsw->host_bus->write(gsw->host_bus, gsw->smi_addr, 0x1f, 0x4);
+	gsw->host_bus->write(gsw->host_bus, gsw->smi_addr, 0x10, 0x0);
+
+	gsw->host_bus->write(gsw->host_bus, gsw->smi_addr, 0x11,
+			     ((reg >> 16) & 0xFFFF));
+	gsw->host_bus->write(gsw->host_bus, gsw->smi_addr, 0x12,
+			     (reg & 0xFFFF));
+
+	gsw->host_bus->write(gsw->host_bus, gsw->smi_addr, 0x13,
+			     ((val >> 16) & 0xFFFF));
+	gsw->host_bus->write(gsw->host_bus, gsw->smi_addr, 0x14,
+			     (val & 0xFFFF));
+
+	gsw->host_bus->write(gsw->host_bus, gsw->smi_addr, 0x1f, 0x0);
+	gsw->host_bus->write(gsw->host_bus, gsw->smi_addr, 0x10, 0x0);
+
+	mutex_unlock(&gsw->host_bus->mdio_lock);
+}
+
+int an8855_mii_read(struct gsw_an8855 *gsw, int phy, int reg)
+{
+	int val;
+
+	if (phy < AN8855_NUM_PHYS)
+		phy = (gsw->phy_base + phy) & AN8855_SMI_ADDR_MASK;
+
+	mutex_lock(&gsw->host_bus->mdio_lock);
+	val = gsw->host_bus->read(gsw->host_bus, phy, reg);
+	mutex_unlock(&gsw->host_bus->mdio_lock);
+
+	return val;
+}
+
+void an8855_mii_write(struct gsw_an8855 *gsw, int phy, int reg, u16 val)
+{
+	if (phy < AN8855_NUM_PHYS)
+		phy = (gsw->phy_base + phy) & AN8855_SMI_ADDR_MASK;
+
+	mutex_lock(&gsw->host_bus->mdio_lock);
+	gsw->host_bus->write(gsw->host_bus, phy, reg, val);
+	mutex_unlock(&gsw->host_bus->mdio_lock);
+}
+
+int an8855_mmd_read(struct gsw_an8855 *gsw, int addr, int devad, u16 reg)
+{
+	int val;
+	u32 regnum = MII_ADDR_C45 | (devad << 16) | reg;
+
+	if (addr < AN8855_NUM_PHYS)
+		addr = (gsw->phy_base + addr) & AN8855_SMI_ADDR_MASK;
+
+	mutex_lock(&gsw->host_bus->mdio_lock);
+	val = gsw->host_bus->read(gsw->host_bus, addr, regnum);
+	mutex_unlock(&gsw->host_bus->mdio_lock);
+
+	return val;
+}
+
+void an8855_mmd_write(struct gsw_an8855 *gsw, int addr, int devad, u16 reg,
+		      u16 val)
+{
+	u32 regnum = MII_ADDR_C45 | (devad << 16) | reg;
+
+	if (addr < AN8855_NUM_PHYS)
+		addr = (gsw->phy_base + addr) & AN8855_SMI_ADDR_MASK;
+
+	mutex_lock(&gsw->host_bus->mdio_lock);
+	gsw->host_bus->write(gsw->host_bus, addr, regnum, val);
+	mutex_unlock(&gsw->host_bus->mdio_lock);
+}
+
+static inline int an8855_get_duplex(const struct device_node *np)
+{
+	return of_property_read_bool(np, "full-duplex");
+}
+
+static void an8855_load_port_cfg(struct gsw_an8855 *gsw)
+{
+	struct device_node *port_np;
+	struct device_node *fixed_link_node;
+	struct an8855_port_cfg *port_cfg;
+	u32 port;
+
+	for_each_child_of_node(gsw->dev->of_node, port_np) {
+		if (!of_device_is_compatible(port_np, "airoha,an8855-port"))
+			continue;
+
+		if (!of_device_is_available(port_np))
+			continue;
+
+		if (of_property_read_u32(port_np, "reg", &port))
+			continue;
+
+		switch (port) {
+		case 5:
+			port_cfg = &gsw->port5_cfg;
+			break;
+		default:
+			continue;
+		}
+
+		if (port_cfg->enabled) {
+			dev_info(gsw->dev, "duplicated node for port%d\n",
+				 port_cfg->phy_mode);
+			continue;
+		}
+
+		port_cfg->np = port_np;
+
+		port_cfg->phy_mode = of_get_phy_mode(port_np);
+		if (port_cfg->phy_mode < 0) {
+			dev_info(gsw->dev, "incorrect phy-mode %d\n", port);
+			continue;
+		}
+
+		fixed_link_node = of_get_child_by_name(port_np, "fixed-link");
+		if (fixed_link_node) {
+			u32 speed;
+
+			port_cfg->force_link = 1;
+			port_cfg->duplex = an8855_get_duplex(fixed_link_node);
+
+			if (of_property_read_u32(fixed_link_node, "speed",
+						 &speed)) {
+				speed = 0;
+				continue;
+			}
+
+			of_node_put(fixed_link_node);
+
+			switch (speed) {
+			case 10:
+				port_cfg->speed = MAC_SPD_10;
+				break;
+			case 100:
+				port_cfg->speed = MAC_SPD_100;
+				break;
+			case 1000:
+				port_cfg->speed = MAC_SPD_1000;
+				break;
+			case 2500:
+				port_cfg->speed = MAC_SPD_2500;
+				break;
+
+			default:
+				dev_info(gsw->dev, "incorrect speed %d\n",
+					 speed);
+				continue;
+			}
+		}
+
+		port_cfg->stag_on =
+		    of_property_read_bool(port_cfg->np, "airoha,stag-on");
+		port_cfg->enabled = 1;
+	}
+}
+
+static void an8855_add_gsw(struct gsw_an8855 *gsw)
+{
+	mutex_lock(&an8855_devs_lock);
+	gsw->id = an8855_gsw_id++;
+	INIT_LIST_HEAD(&gsw->list);
+	list_add_tail(&gsw->list, &an8855_devs);
+	mutex_unlock(&an8855_devs_lock);
+}
+
+static void an8855_remove_gsw(struct gsw_an8855 *gsw)
+{
+	mutex_lock(&an8855_devs_lock);
+	list_del(&gsw->list);
+	mutex_unlock(&an8855_devs_lock);
+}
+
+struct gsw_an8855 *an8855_get_gsw(u32 id)
+{
+	struct gsw_an8855 *dev;
+
+	mutex_lock(&an8855_devs_lock);
+
+	list_for_each_entry(dev, &an8855_devs, list) {
+		if (dev->id == id)
+			return dev;
+	}
+
+	mutex_unlock(&an8855_devs_lock);
+
+	return NULL;
+}
+
+struct gsw_an8855 *an8855_get_first_gsw(void)
+{
+	struct gsw_an8855 *dev;
+
+	mutex_lock(&an8855_devs_lock);
+
+	list_for_each_entry(dev, &an8855_devs, list)
+		return dev;
+
+	mutex_unlock(&an8855_devs_lock);
+
+	return NULL;
+}
+
+void an8855_put_gsw(void)
+{
+	mutex_unlock(&an8855_devs_lock);
+}
+
+void an8855_lock_gsw(void)
+{
+	mutex_lock(&an8855_devs_lock);
+}
+
+static int an8855_hw_reset(struct gsw_an8855 *gsw)
+{
+	struct device_node *np = gsw->dev->of_node;
+	int ret;
+
+	gsw->reset_pin = of_get_named_gpio(np, "reset-gpios", 0);
+	if (gsw->reset_pin < 0) {
+		dev_info(gsw->dev, "No reset pin of switch\n");
+		return 0;
+	}
+
+	ret = devm_gpio_request(gsw->dev, gsw->reset_pin, "an8855-reset");
+	if (ret) {
+		dev_info(gsw->dev, "Failed to request gpio %d\n",
+			 gsw->reset_pin);
+		return ret;
+	}
+
+	gpio_direction_output(gsw->reset_pin, 0);
+	usleep_range(100000, 150000);
+	gpio_set_value(gsw->reset_pin, 1);
+	usleep_range(100000, 150000);
+
+	return 0;
+}
+
+static irqreturn_t an8855_irq_handler(int irq, void *dev)
+{
+	struct gsw_an8855 *gsw = dev;
+
+	disable_irq_nosync(gsw->irq);
+
+	schedule_work(&gsw->irq_worker);
+
+	return IRQ_HANDLED;
+}
+
+static int an8855_probe(struct platform_device *pdev)
+{
+	struct gsw_an8855 *gsw;
+	struct an8855_sw_id *sw;
+	struct device_node *np = pdev->dev.of_node;
+	struct device_node *mdio;
+	struct mii_bus *mdio_bus;
+	int ret = -EINVAL;
+	struct chip_rev rev;
+	struct an8855_mapping *map;
+	int i;
+
+	mdio = of_parse_phandle(np, "airoha,mdio", 0);
+	if (!mdio)
+		return -EINVAL;
+
+	mdio_bus = of_mdio_find_bus(mdio);
+	if (!mdio_bus)
+		return -EPROBE_DEFER;
+
+	gsw = devm_kzalloc(&pdev->dev, sizeof(struct gsw_an8855), GFP_KERNEL);
+	if (!gsw)
+		return -ENOMEM;
+
+	gsw->host_bus = mdio_bus;
+	gsw->dev = &pdev->dev;
+
+	dev_info(gsw->dev, "AN8855 Driver Version=%s\n",
+			ARHT_AN8855_SWCFG_DRIVER_VER);
+
+	/* Switch hard reset */
+	if (an8855_hw_reset(gsw)) {
+		dev_info(&pdev->dev, "reset switch fail.\n");
+		goto fail;
+	}
+
+	/* Fetch the SMI address first */
+	gsw->smi_addr = AN8855_DFL_SMI_ADDR;
+	if (of_property_read_u32(np, "airoha,smi-addr", &gsw->new_smi_addr))
+		gsw->new_smi_addr = AN8855_DFL_SMI_ADDR;
+
+	/* Get LAN/WAN port mapping */
+	map = an8855_find_mapping(np);
+	if (map) {
+		an8855_apply_mapping(gsw, map);
+		gsw->global_vlan_enable = 1;
+		dev_info(gsw->dev, "LAN/WAN VLAN setting=%s\n", map->name);
+	}
+
+	/* Load MAC port configurations */
+	an8855_load_port_cfg(gsw);
+
+	/* Check for valid switch and then initialize */
+	an8855_gsw_id = 0;
+	for (i = 0; i < ARRAY_SIZE(an8855_sw_ids); i++) {
+		if (!an8855_sw_ids[i]->detect(gsw, &rev)) {
+			sw = an8855_sw_ids[i];
+
+			gsw->name = rev.name;
+			gsw->model = sw->model;
+
+			dev_info(gsw->dev, "Switch is Airoha %s rev %d",
+				 gsw->name, rev.rev);
+
+			/* Initialize the switch */
+			ret = sw->init(gsw);
+			if (ret)
+				goto fail;
+
+			break;
+		}
+	}
+
+	if (i >= ARRAY_SIZE(an8855_sw_ids)) {
+		dev_err(gsw->dev, "No an8855 switch found\n");
+		goto fail;
+	}
+
+	gsw->irq = platform_get_irq(pdev, 0);
+	if (gsw->irq >= 0) {
+		ret = devm_request_irq(gsw->dev, gsw->irq, an8855_irq_handler,
+				       0, dev_name(gsw->dev), gsw);
+		if (ret) {
+			dev_err(gsw->dev, "Failed to request irq %d\n",
+				gsw->irq);
+			goto fail;
+		}
+
+		INIT_WORK(&gsw->irq_worker, an8855_irq_worker);
+	}
+
+	platform_set_drvdata(pdev, gsw);
+
+	an8855_add_gsw(gsw);
+
+	an8855_gsw_nl_init();
+
+	an8855_swconfig_init(gsw);
+
+	if (sw->post_init)
+		sw->post_init(gsw);
+
+	if (gsw->irq >= 0)
+		an8855_irq_enable(gsw);
+
+	return 0;
+
+fail:
+	devm_kfree(&pdev->dev, gsw);
+
+	return ret;
+}
+
+static int an8855_remove(struct platform_device *pdev)
+{
+	struct gsw_an8855 *gsw = platform_get_drvdata(pdev);
+
+	if (gsw->irq >= 0)
+		cancel_work_sync(&gsw->irq_worker);
+
+	if (gsw->reset_pin >= 0)
+		devm_gpio_free(&pdev->dev, gsw->reset_pin);
+
+#ifdef CONFIG_SWCONFIG
+	an8855_swconfig_destroy(gsw);
+#endif
+
+	an8855_gsw_nl_exit();
+
+	an8855_remove_gsw(gsw);
+
+	platform_set_drvdata(pdev, NULL);
+
+	return 0;
+}
+
+static const struct of_device_id an8855_ids[] = {
+	{.compatible = "airoha,an8855"},
+	{},
+};
+
+MODULE_DEVICE_TABLE(of, an8855_ids);
+
+static struct platform_driver an8855_driver = {
+	.probe = an8855_probe,
+	.remove = an8855_remove,
+	.driver = {
+		   .name = "an8855",
+		   .of_match_table = an8855_ids,
+		   },
+};
+
+static int __init an8855_init(void)
+{
+	int ret;
+
+	INIT_LIST_HEAD(&an8855_devs);
+	ret = platform_driver_register(&an8855_driver);
+
+	return ret;
+}
+
+module_init(an8855_init);
+
+static void __exit an8855_exit(void)
+{
+	platform_driver_unregister(&an8855_driver);
+}
+
+module_exit(an8855_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Min Yao <min.yao@airoha.com>");
+MODULE_VERSION(ARHT_AN8855_SWCFG_DRIVER_VER);
+MODULE_DESCRIPTION("Driver for Airoha AN8855 Gigabit Switch");
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/airoha/an8855/an8855_nl.c b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/airoha/an8855/an8855_nl.c
new file mode 100644
index 0000000..37e3dad
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/airoha/an8855/an8855_nl.c
@@ -0,0 +1,384 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2023 Airoha Inc.
+ * Author: Min Yao <min.yao@airoha.com>
+ */
+
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <net/genetlink.h>
+
+#include "an8855.h"
+#include "an8855_nl.h"
+
+struct an8855_nl_cmd_item {
+	enum an8855_cmd cmd;
+	bool require_dev;
+	int (*process)(struct genl_info *info, struct gsw_an8855 *gsw);
+	u32 nr_required_attrs;
+	const enum an8855_attr *required_attrs;
+};
+
+static int an8855_nl_response(struct sk_buff *skb, struct genl_info *info);
+
+static const struct nla_policy an8855_nl_cmd_policy[] = {
+	[AN8855_ATTR_TYPE_MESG] = { .type = NLA_STRING },
+	[AN8855_ATTR_TYPE_PHY] = { .type = NLA_S32 },
+	[AN8855_ATTR_TYPE_REG] = { .type = NLA_S32 },
+	[AN8855_ATTR_TYPE_VAL] = { .type = NLA_S32 },
+	[AN8855_ATTR_TYPE_DEV_NAME] = { .type = NLA_S32 },
+	[AN8855_ATTR_TYPE_DEV_ID] = { .type = NLA_S32 },
+	[AN8855_ATTR_TYPE_DEVAD] = { .type = NLA_S32 },
+};
+
+static const struct genl_ops an8855_nl_ops[] = {
+	{
+		.cmd = AN8855_CMD_REQUEST,
+		.doit = an8855_nl_response,
+//		.policy = an8855_nl_cmd_policy,
+		.flags = GENL_ADMIN_PERM,
+	}, {
+		.cmd = AN8855_CMD_READ,
+		.doit = an8855_nl_response,
+//		.policy = an8855_nl_cmd_policy,
+		.flags = GENL_ADMIN_PERM,
+	}, {
+		.cmd = AN8855_CMD_WRITE,
+		.doit = an8855_nl_response,
+//		.policy = an8855_nl_cmd_policy,
+		.flags = GENL_ADMIN_PERM,
+	},
+};
+
+static struct genl_family an8855_nl_family = {
+	.name =		AN8855_GENL_NAME,
+	.version =	AN8855_GENL_VERSION,
+	.maxattr =	AN8855_NR_ATTR_TYPE,
+	.ops =		an8855_nl_ops,
+	.n_ops =	ARRAY_SIZE(an8855_nl_ops),
+	.policy =	an8855_nl_cmd_policy,
+};
+
+static int an8855_nl_list_devs(char *buff, int size)
+{
+	struct gsw_an8855 *gsw;
+	int len, total = 0;
+	char buf[80];
+
+	memset(buff, 0, size);
+
+	an8855_lock_gsw();
+
+	list_for_each_entry(gsw, &an8855_devs, list) {
+		len = snprintf(buf, sizeof(buf),
+				   "id: %d, model: %s, node: %s\n",
+				   gsw->id, gsw->name, gsw->dev->of_node->name);
+		if (len == strlen(buf)) {
+			if (size - total > 0)
+				strncat(buff, buf, size - total);
+			total += len;
+		}
+	}
+
+	an8855_put_gsw();
+
+	return total;
+}
+
+static int an8855_nl_prepare_reply(struct genl_info *info, u8 cmd,
+				   struct sk_buff **skbp)
+{
+	struct sk_buff *msg;
+	void *reply;
+
+	if (!info)
+		return -EINVAL;
+
+	msg = genlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
+	if (!msg)
+		return -ENOMEM;
+
+	/* Construct send-back message header */
+	reply = genlmsg_put(msg, info->snd_portid, info->snd_seq,
+				&an8855_nl_family, 0, cmd);
+	if (!reply) {
+		nlmsg_free(msg);
+		return -EINVAL;
+	}
+
+	*skbp = msg;
+	return 0;
+}
+
+static int an8855_nl_send_reply(struct sk_buff *skb, struct genl_info *info)
+{
+	struct genlmsghdr *genlhdr = nlmsg_data(nlmsg_hdr(skb));
+	void *reply = genlmsg_data(genlhdr);
+
+	/* Finalize a generic netlink message (update message header) */
+	genlmsg_end(skb, reply);
+
+	/* reply to a request */
+	return genlmsg_reply(skb, info);
+}
+
+static s32 an8855_nl_get_s32(struct genl_info *info, enum an8855_attr attr,
+				 s32 defval)
+{
+	struct nlattr *na;
+
+	na = info->attrs[attr];
+	if (na)
+		return nla_get_s32(na);
+
+	return defval;
+}
+
+static int an8855_nl_get_u32(struct genl_info *info, enum an8855_attr attr,
+				 u32 *val)
+{
+	struct nlattr *na;
+
+	na = info->attrs[attr];
+	if (na) {
+		*val = nla_get_u32(na);
+		return 0;
+	}
+
+	return -1;
+}
+
+static struct gsw_an8855 *an8855_nl_parse_find_gsw(struct genl_info *info)
+{
+	struct gsw_an8855 *gsw;
+	struct nlattr *na;
+	int gsw_id;
+
+	na = info->attrs[AN8855_ATTR_TYPE_DEV_ID];
+	if (na) {
+		gsw_id = nla_get_s32(na);
+		if (gsw_id >= 0)
+			gsw = an8855_get_gsw(gsw_id);
+		else
+			gsw = an8855_get_first_gsw();
+	} else {
+		gsw = an8855_get_first_gsw();
+	}
+
+	return gsw;
+}
+
+static int an8855_nl_get_swdevs(struct genl_info *info, struct gsw_an8855 *gsw)
+{
+	struct sk_buff *rep_skb = NULL;
+	char dev_info[512];
+	int ret;
+
+	ret = an8855_nl_list_devs(dev_info, sizeof(dev_info) - 1);
+	if (!ret) {
+		pr_info("No switch registered\n");
+		return -EINVAL;
+	}
+
+	ret = an8855_nl_prepare_reply(info, AN8855_CMD_REPLY, &rep_skb);
+	if (ret < 0)
+		goto err;
+
+	ret = nla_put_string(rep_skb, AN8855_ATTR_TYPE_MESG, dev_info);
+	if (ret < 0)
+		goto err;
+
+	return an8855_nl_send_reply(rep_skb, info);
+
+err:
+	if (rep_skb)
+		nlmsg_free(rep_skb);
+
+	return ret;
+}
+
+static int an8855_nl_reply_read(struct genl_info *info, struct gsw_an8855 *gsw)
+{
+	struct sk_buff *rep_skb = NULL;
+	s32 phy, devad, reg;
+	int value;
+	int ret = 0;
+
+	phy = an8855_nl_get_s32(info, AN8855_ATTR_TYPE_PHY, -1);
+	devad = an8855_nl_get_s32(info, AN8855_ATTR_TYPE_DEVAD, -1);
+	reg = an8855_nl_get_s32(info, AN8855_ATTR_TYPE_REG, -1);
+
+	if (reg < 0)
+		goto err;
+
+	ret = an8855_nl_prepare_reply(info, AN8855_CMD_READ, &rep_skb);
+	if (ret < 0)
+		goto err;
+
+	if (phy >= 0) {
+		if (devad < 0)
+			value = gsw->mii_read(gsw, phy, reg);
+		else
+			value = gsw->mmd_read(gsw, phy, devad, reg);
+	} else {
+		value = an8855_reg_read(gsw, reg);
+	}
+
+	ret = nla_put_s32(rep_skb, AN8855_ATTR_TYPE_REG, reg);
+	if (ret < 0)
+		goto err;
+
+	ret = nla_put_s32(rep_skb, AN8855_ATTR_TYPE_VAL, value);
+	if (ret < 0)
+		goto err;
+
+	return an8855_nl_send_reply(rep_skb, info);
+
+err:
+	if (rep_skb)
+		nlmsg_free(rep_skb);
+
+	return ret;
+}
+
+static int an8855_nl_reply_write(struct genl_info *info, struct gsw_an8855 *gsw)
+{
+	struct sk_buff *rep_skb = NULL;
+	s32 phy, devad, reg;
+	u32 value;
+	int ret = 0;
+
+	phy = an8855_nl_get_s32(info, AN8855_ATTR_TYPE_PHY, -1);
+	devad = an8855_nl_get_s32(info, AN8855_ATTR_TYPE_DEVAD, -1);
+	reg = an8855_nl_get_s32(info, AN8855_ATTR_TYPE_REG, -1);
+
+	if (an8855_nl_get_u32(info, AN8855_ATTR_TYPE_VAL, &value))
+		goto err;
+
+	if (reg < 0)
+		goto err;
+
+	ret = an8855_nl_prepare_reply(info, AN8855_CMD_WRITE, &rep_skb);
+	if (ret < 0)
+		goto err;
+
+	if (phy >= 0) {
+		if (devad < 0)
+			gsw->mii_write(gsw, phy, reg, value);
+		else
+			gsw->mmd_write(gsw, phy, devad, reg, value);
+	} else {
+		an8855_reg_write(gsw, reg, value);
+	}
+
+	ret = nla_put_s32(rep_skb, AN8855_ATTR_TYPE_REG, reg);
+	if (ret < 0)
+		goto err;
+
+	ret = nla_put_s32(rep_skb, AN8855_ATTR_TYPE_VAL, value);
+	if (ret < 0)
+		goto err;
+
+	return an8855_nl_send_reply(rep_skb, info);
+
+err:
+	if (rep_skb)
+		nlmsg_free(rep_skb);
+
+	return ret;
+}
+
+static const enum an8855_attr an8855_nl_cmd_read_attrs[] = {
+	AN8855_ATTR_TYPE_REG
+};
+
+static const enum an8855_attr an8855_nl_cmd_write_attrs[] = {
+	AN8855_ATTR_TYPE_REG,
+	AN8855_ATTR_TYPE_VAL
+};
+
+static const struct an8855_nl_cmd_item an8855_nl_cmds[] = {
+	{
+		.cmd = AN8855_CMD_REQUEST,
+		.require_dev = false,
+		.process = an8855_nl_get_swdevs
+	}, {
+		.cmd = AN8855_CMD_READ,
+		.require_dev = true,
+		.process = an8855_nl_reply_read,
+		.required_attrs = an8855_nl_cmd_read_attrs,
+		.nr_required_attrs = ARRAY_SIZE(an8855_nl_cmd_read_attrs),
+	}, {
+		.cmd = AN8855_CMD_WRITE,
+		.require_dev = true,
+		.process = an8855_nl_reply_write,
+		.required_attrs = an8855_nl_cmd_write_attrs,
+		.nr_required_attrs = ARRAY_SIZE(an8855_nl_cmd_write_attrs),
+	}
+};
+
+static int an8855_nl_response(struct sk_buff *skb, struct genl_info *info)
+{
+	struct genlmsghdr *hdr = nlmsg_data(info->nlhdr);
+	const struct an8855_nl_cmd_item *cmditem = NULL;
+	struct gsw_an8855 *gsw = NULL;
+	u32 sat_req_attrs = 0;
+	int i, ret;
+
+	for (i = 0; i < ARRAY_SIZE(an8855_nl_cmds); i++) {
+		if (hdr->cmd == an8855_nl_cmds[i].cmd) {
+			cmditem = &an8855_nl_cmds[i];
+			break;
+		}
+	}
+
+	if (!cmditem) {
+		pr_info("an8855-nl: unknown cmd %u\n", hdr->cmd);
+		return -EINVAL;
+	}
+
+	for (i = 0; i < cmditem->nr_required_attrs; i++) {
+		if (info->attrs[cmditem->required_attrs[i]])
+			sat_req_attrs++;
+	}
+
+	if (sat_req_attrs != cmditem->nr_required_attrs) {
+		pr_info("an8855-nl: missing required attr(s) for cmd %u\n",
+			hdr->cmd);
+		return -EINVAL;
+	}
+
+	if (cmditem->require_dev) {
+		gsw = an8855_nl_parse_find_gsw(info);
+		if (!gsw) {
+			pr_info("an8855-nl: failed to find switch dev\n");
+			return -EINVAL;
+		}
+	}
+
+	ret = cmditem->process(info, gsw);
+
+	an8855_put_gsw();
+
+	return ret;
+}
+
+int an8855_gsw_nl_init(void)
+{
+	int ret;
+
+	ret = genl_register_family(&an8855_nl_family);
+	if (ret) {
+		pr_info("an8855-nl: genl_register_family_with_ops failed\n");
+		return ret;
+	}
+
+	return 0;
+}
+
+void an8855_gsw_nl_exit(void)
+{
+	genl_unregister_family(&an8855_nl_family);
+}
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/airoha/an8855/an8855_nl.h b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/airoha/an8855/an8855_nl.h
new file mode 100644
index 0000000..b00df75
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/airoha/an8855/an8855_nl.h
@@ -0,0 +1,43 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (c) 2023 Airoha Inc.
+ * Author: Min Yao <min.yao@airoha.com>
+ */
+
+#ifndef _AN8855_NL_H_
+#define _AN8855_NL_H_
+
+#define AN8855_GENL_NAME		"an8855"
+#define AN8855_GENL_VERSION		0x1
+
+enum an8855_cmd {
+	AN8855_CMD_UNSPEC = 0,
+	AN8855_CMD_REQUEST,
+	AN8855_CMD_REPLY,
+	AN8855_CMD_READ,
+	AN8855_CMD_WRITE,
+
+	__AN8855_CMD_MAX,
+};
+
+enum an8855_attr {
+	AN8855_ATTR_TYPE_UNSPEC = 0,
+	AN8855_ATTR_TYPE_MESG,
+	AN8855_ATTR_TYPE_PHY,
+	AN8855_ATTR_TYPE_DEVAD,
+	AN8855_ATTR_TYPE_REG,
+	AN8855_ATTR_TYPE_VAL,
+	AN8855_ATTR_TYPE_DEV_NAME,
+	AN8855_ATTR_TYPE_DEV_ID,
+
+	__AN8855_ATTR_TYPE_MAX,
+};
+
+#define AN8855_NR_ATTR_TYPE		(__AN8855_ATTR_TYPE_MAX - 1)
+
+#ifdef __KERNEL__
+int an8855_gsw_nl_init(void);
+void an8855_gsw_nl_exit(void);
+#endif /* __KERNEL__ */
+
+#endif /* _AN8855_NL_H_ */
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/airoha/an8855/an8855_regs.h b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/airoha/an8855/an8855_regs.h
new file mode 100644
index 0000000..9dbfaeb
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/airoha/an8855/an8855_regs.h
@@ -0,0 +1,188 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2023 Airoha Inc.
+ * Author: Min Yao <min.yao@airoha.com>
+ */
+
+#ifndef _AN8855_REGS_H_
+#define _AN8855_REGS_H_
+
+#include <linux/bitops.h>
+
+#define BITS(m, n)	 (~(BIT(m) - 1) & ((BIT(n) - 1) | BIT(n)))
+
+/* Values of Egress TAG Control */
+#define ETAG_CTRL_UNTAG			0
+#define ETAG_CTRL_TAG			2
+#define ETAG_CTRL_SWAP			1
+#define ETAG_CTRL_STACK			3
+
+#define VTCR					0x10200600
+#define VAWD0					0x10200604
+#define VAWD1					0x10200608
+#define VARD0					0x10200618
+#define VARD1					0x1020061C
+
+/* Fields of VTCR */
+#define VTCR_BUSY				BIT(31)
+#define VTCR_FUNC_S				12
+#define VTCR_FUNC_M				0xf000
+#define VTCR_VID_S				0
+#define VTCR_VID_M				0xfff
+
+/* Values of VTCR_FUNC */
+#define VTCR_READ_VLAN_ENTRY	0
+#define VTCR_WRITE_VLAN_ENTRY	1
+
+/* VLAN entry fields */
+#define IVL_MAC					BIT(5)
+#define EG_CON					BIT(11)
+#define VTAG_EN					BIT(10)
+#define PORT_MEM_S				26
+#define PORT_MEM_M				0xfc000000
+#define VENTRY_VALID			BIT(0)
+#define ETAG_M					0x3fff000
+#define PORT_ETAG_S(p)			(((p) * 2) + 12)
+#define PORT_ETAG_M				0x03
+
+#define PORT_CTRL_BASE			0x10208000
+#define PORT_CTRL_PORT_OFFSET	0x200
+#define PORT_CTRL_REG(p, r)		(PORT_CTRL_BASE + \
+					(p) * PORT_CTRL_PORT_OFFSET +  (r))
+#define PCR(p)					PORT_CTRL_REG(p, 0x04)
+#define PVC(p)					PORT_CTRL_REG(p, 0x10)
+#define PORTMATRIX(p)			PORT_CTRL_REG(p, 0x44)
+#define PVID(p)					PORT_CTRL_REG(p, 0x48)
+
+#define GRP_PORT_VID_M			0xfff
+
+/* Values of PORT_VLAN */
+#define PORT_MATRIX_MODE		0
+#define FALLBACK_MODE			1
+#define CHECK_MODE				2
+#define SECURITY_MODE			3
+
+/* Fields of PVC */
+#define STAG_VPID_S				16
+#define STAG_VPID_M				0xffff0000
+#define VLAN_ATTR_S				6
+#define VLAN_ATTR_M				0xc0
+#define PVC_STAG_REPLACE		BIT(11)
+#define PVC_PORT_STAG			BIT(5)
+
+/* Values of VLAN_ATTR */
+#define VA_USER_PORT			0
+#define VA_STACK_PORT			1
+#define VA_TRANSLATION_PORT		2
+#define VA_TRANSPARENT_PORT		3
+
+#define PORT_MATRIX_M			((1 << AN8855_NUM_PORTS) - 1)
+
+#define PORT_MAC_CTRL_BASE		0x10210000
+#define PORT_MAC_CTRL_PORT_OFFSET	0x200
+#define PORT_MAC_CTRL_REG(p, r)		(PORT_MAC_CTRL_BASE + \
+					(p) * PORT_MAC_CTRL_PORT_OFFSET + (r))
+#define PMCR(p)					PORT_MAC_CTRL_REG(p, 0x00)
+#define PMSR(p)					PORT_MAC_CTRL_REG(p, 0x10)
+
+#define GMACCR					(PORT_MAC_CTRL_BASE + 0x30e0)
+
+#define MAX_RX_JUMBO_S			2
+#define MAX_RX_JUMBO_M			0x3c
+#define MAX_RX_PKT_LEN_S		0
+#define MAX_RX_PKT_LEN_M		0x3
+
+/* Values of MAX_RX_PKT_LEN */
+#define RX_PKT_LEN_1518			0
+#define RX_PKT_LEN_1536			1
+#define RX_PKT_LEN_1522			2
+#define RX_PKT_LEN_MAX_JUMBO	3
+
+/* Fields of PMSR */
+#define EEE1G_STS			BIT(7)
+#define EEE100_STS			BIT(6)
+#define RX_FC_STS			BIT(5)
+#define TX_FC_STS			BIT(4)
+#define MAC_SPD_STS_S		28
+#define MAC_SPD_STS_M		0x70000000
+#define MAC_DPX_STS			BIT(25)
+#define MAC_LNK_STS			BIT(24)
+
+/* Values of MAC_SPD_STS */
+#define MAC_SPD_10			0
+#define MAC_SPD_100			1
+#define MAC_SPD_1000		2
+#define MAC_SPD_2500		3
+
+#define MIB_COUNTER_BASE			0x10214000
+#define MIB_COUNTER_PORT_OFFSET		0x200
+#define MIB_COUNTER_REG(p, r)		(MIB_COUNTER_BASE + \
+					(p) * MIB_COUNTER_PORT_OFFSET + (r))
+#define STATS_TDPC			0x00
+#define STATS_TCRC			0x04
+#define STATS_TUPC			0x08
+#define STATS_TMPC			0x0C
+#define STATS_TBPC			0x10
+#define STATS_TCEC			0x14
+#define STATS_TSCEC			0x18
+#define STATS_TMCEC			0x1C
+#define STATS_TDEC			0x20
+#define STATS_TLCEC			0x24
+#define STATS_TXCEC			0x28
+#define STATS_TPPC			0x2C
+#define STATS_TL64PC		0x30
+#define STATS_TL65PC		0x34
+#define STATS_TL128PC		0x38
+#define STATS_TL256PC		0x3C
+#define STATS_TL512PC		0x40
+#define STATS_TL1024PC		0x44
+#define STATS_TL1519PC		0x48
+#define STATS_TOC			0x4C
+#define STATS_TODPC			0x54
+#define STATS_TOC2			0x58
+
+#define STATS_RDPC			0x80
+#define STATS_RFPC			0x84
+#define STATS_RUPC			0x88
+#define STATS_RMPC			0x8C
+#define STATS_RBPC			0x90
+#define STATS_RAEPC			0x94
+#define STATS_RCEPC			0x98
+#define STATS_RUSPC			0x9C
+#define STATS_RFEPC			0xA0
+#define STATS_ROSPC			0xA4
+#define STATS_RJEPC			0xA8
+#define STATS_RPPC			0xAC
+#define STATS_RL64PC		0xB0
+#define STATS_RL65PC		0xB4
+#define STATS_RL128PC		0xB8
+#define STATS_RL256PC		0xBC
+#define STATS_RL512PC		0xC0
+#define STATS_RL1024PC		0xC4
+#define STATS_RL1519PC		0xC8
+#define STATS_ROC			0xCC
+#define STATS_RDPC_CTRL		0xD4
+#define STATS_RDPC_ING		0xD8
+#define STATS_RDPC_ARL		0xDC
+#define STATS_RDPC_FC		0xE0
+#define STATS_RDPC_WRED		0xE4
+#define STATS_RDPC_MIR		0xE8
+#define STATS_ROC2			0xEC
+#define STATS_RSFSPC		0xF4
+#define STATS_RSFTPC		0xF8
+#define STATS_RXCDPC		0xFC
+
+#define SYS_CTRL			0x100050C0
+#define SW_SYS_RST			BIT(31)
+
+#define INT_MASK			0x100050F0
+#define INT_SYS_BIT			BIT(15)
+
+#define SYS_INT_EN			0x1021C010
+#define SYS_INT_STS			0x1021C014
+#define PHY_LC_INT(p)		BIT(p)
+
+#define CKGCR				(0x10213E1C)
+#define CKG_LNKDN_GLB_STOP	(0x01)
+#define CKG_LNKDN_PORT_STOP	(0x02)
+#endif /* _AN8855_REGS_H_ */
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/airoha/an8855/an8855_swconfig.c b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/airoha/an8855/an8855_swconfig.c
new file mode 100644
index 0000000..e796582
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/airoha/an8855/an8855_swconfig.c
@@ -0,0 +1,527 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2023 Airoha Inc.
+ * Author: Min Yao <min.yao@airoha.com>
+ */
+
+#include <linux/if.h>
+#include <linux/list.h>
+#include <linux/if_ether.h>
+#include <linux/skbuff.h>
+#include <linux/netdevice.h>
+#include <linux/netlink.h>
+#include <linux/bitops.h>
+#include <net/genetlink.h>
+#include <linux/delay.h>
+#include <linux/phy.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/lockdep.h>
+#include <linux/workqueue.h>
+#include <linux/of_device.h>
+
+#include "an8855.h"
+#include "an8855_swconfig.h"
+#include "an8855_regs.h"
+
+#define AN8855_PORT_MIB_TXB_ID	19	/* TxByte */
+#define AN8855_PORT_MIB_RXB_ID	40	/* RxByte */
+
+#define MIB_DESC(_s, _o, _n)   \
+	{						\
+		.size = (_s),	\
+		.offset = (_o), \
+		.name = (_n),	\
+	}
+
+struct an8855_mib_desc {
+	unsigned int size;
+	unsigned int offset;
+	const char *name;
+};
+
+static const struct an8855_mib_desc an8855_mibs[] = {
+	MIB_DESC(1, STATS_TDPC, "TxDrop"),
+	MIB_DESC(1, STATS_TCRC, "TxCRC"),
+	MIB_DESC(1, STATS_TUPC, "TxUni"),
+	MIB_DESC(1, STATS_TMPC, "TxMulti"),
+	MIB_DESC(1, STATS_TBPC, "TxBroad"),
+	MIB_DESC(1, STATS_TCEC, "TxCollision"),
+	MIB_DESC(1, STATS_TSCEC, "TxSingleCol"),
+	MIB_DESC(1, STATS_TMCEC, "TxMultiCol"),
+	MIB_DESC(1, STATS_TDEC, "TxDefer"),
+	MIB_DESC(1, STATS_TLCEC, "TxLateCol"),
+	MIB_DESC(1, STATS_TXCEC, "TxExcCol"),
+	MIB_DESC(1, STATS_TPPC, "TxPause"),
+	MIB_DESC(1, STATS_TL64PC, "Tx64Byte"),
+	MIB_DESC(1, STATS_TL65PC, "Tx65Byte"),
+	MIB_DESC(1, STATS_TL128PC, "Tx128Byte"),
+	MIB_DESC(1, STATS_TL256PC, "Tx256Byte"),
+	MIB_DESC(1, STATS_TL512PC, "Tx512Byte"),
+	MIB_DESC(1, STATS_TL1024PC, "Tx1024Byte"),
+	MIB_DESC(1, STATS_TL1519PC, "Tx1519Byte"),
+	MIB_DESC(2, STATS_TOC, "TxByte"),
+	MIB_DESC(1, STATS_TODPC, "TxOverSize"),
+	MIB_DESC(2, STATS_TOC2, "SecondaryTxByte"),
+	MIB_DESC(1, STATS_RDPC, "RxDrop"),
+	MIB_DESC(1, STATS_RFPC, "RxFiltered"),
+	MIB_DESC(1, STATS_RUPC, "RxUni"),
+	MIB_DESC(1, STATS_RMPC, "RxMulti"),
+	MIB_DESC(1, STATS_RBPC, "RxBroad"),
+	MIB_DESC(1, STATS_RAEPC, "RxAlignErr"),
+	MIB_DESC(1, STATS_RCEPC, "RxCRC"),
+	MIB_DESC(1, STATS_RUSPC, "RxUnderSize"),
+	MIB_DESC(1, STATS_RFEPC, "RxFragment"),
+	MIB_DESC(1, STATS_ROSPC, "RxOverSize"),
+	MIB_DESC(1, STATS_RJEPC, "RxJabber"),
+	MIB_DESC(1, STATS_RPPC, "RxPause"),
+	MIB_DESC(1, STATS_RL64PC, "Rx64Byte"),
+	MIB_DESC(1, STATS_RL65PC, "Rx65Byte"),
+	MIB_DESC(1, STATS_RL128PC, "Rx128Byte"),
+	MIB_DESC(1, STATS_RL256PC, "Rx256Byte"),
+	MIB_DESC(1, STATS_RL512PC, "Rx512Byte"),
+	MIB_DESC(1, STATS_RL1024PC, "Rx1024Byte"),
+	MIB_DESC(2, STATS_ROC, "RxByte"),
+	MIB_DESC(1, STATS_RDPC_CTRL, "RxCtrlDrop"),
+	MIB_DESC(1, STATS_RDPC_ING, "RxIngDrop"),
+	MIB_DESC(1, STATS_RDPC_ARL, "RxARLDrop"),
+	MIB_DESC(1, STATS_RDPC_FC, "RxFCDrop"),
+	MIB_DESC(1, STATS_RDPC_WRED, "RxWREDDrop"),
+	MIB_DESC(1, STATS_RDPC_MIR, "RxMIRDrop"),
+	MIB_DESC(2, STATS_ROC2, "SecondaryRxByte"),
+	MIB_DESC(1, STATS_RSFSPC, "RxsFlowSampling"),
+	MIB_DESC(1, STATS_RSFTPC, "RxsFlowTotal"),
+	MIB_DESC(1, STATS_RXCDPC, "RxPortDrop"),
+};
+
+enum {
+	/* Global attributes. */
+	AN8855_ATTR_ENABLE_VLAN,
+};
+
+static int an8855_get_vlan_enable(struct switch_dev *dev,
+				  const struct switch_attr *attr,
+				  struct switch_val *val)
+{
+	struct gsw_an8855 *gsw = container_of(dev, struct gsw_an8855, swdev);
+
+	val->value.i = gsw->global_vlan_enable;
+
+	return 0;
+}
+
+static int an8855_set_vlan_enable(struct switch_dev *dev,
+				  const struct switch_attr *attr,
+				  struct switch_val *val)
+{
+	struct gsw_an8855 *gsw = container_of(dev, struct gsw_an8855, swdev);
+
+	gsw->global_vlan_enable = val->value.i != 0;
+
+	return 0;
+}
+
+static int an8855_get_port_pvid(struct switch_dev *dev, int port, int *val)
+{
+	struct gsw_an8855 *gsw = container_of(dev, struct gsw_an8855, swdev);
+
+	if (port >= AN8855_NUM_PORTS)
+		return -EINVAL;
+
+	*val = an8855_reg_read(gsw, PVID(port));
+	*val &= GRP_PORT_VID_M;
+
+	return 0;
+}
+
+static int an8855_set_port_pvid(struct switch_dev *dev, int port, int pvid)
+{
+	struct gsw_an8855 *gsw = container_of(dev, struct gsw_an8855, swdev);
+
+	if (port >= AN8855_NUM_PORTS)
+		return -EINVAL;
+
+	if (pvid < AN8855_MIN_VID || pvid > AN8855_MAX_VID)
+		return -EINVAL;
+
+	gsw->port_entries[port].pvid = pvid;
+
+	return 0;
+}
+
+static int an8855_get_vlan_ports(struct switch_dev *dev, struct switch_val *val)
+{
+	struct gsw_an8855 *gsw = container_of(dev, struct gsw_an8855, swdev);
+	u32 member;
+	u32 etags;
+	int i;
+
+	val->len = 0;
+
+	if (val->port_vlan >= AN8855_NUM_VLANS)
+		return -EINVAL;
+
+	an8855_vlan_ctrl(gsw, VTCR_READ_VLAN_ENTRY, val->port_vlan);
+
+	member = an8855_reg_read(gsw, VARD0);
+	member &= PORT_MEM_M;
+	member >>= PORT_MEM_S;
+	member |= ((an8855_reg_read(gsw, VARD1) & 0x1) << 6);
+
+	etags = an8855_reg_read(gsw, VARD0) & ETAG_M;
+
+	for (i = 0; i < AN8855_NUM_PORTS; i++) {
+		struct switch_port *p;
+		int etag;
+
+		if (!(member & BIT(i)))
+			continue;
+
+		p = &val->value.ports[val->len++];
+		p->id = i;
+
+		etag = (etags >> PORT_ETAG_S(i)) & PORT_ETAG_M;
+
+		if (etag == ETAG_CTRL_TAG)
+			p->flags |= BIT(SWITCH_PORT_FLAG_TAGGED);
+		else if (etag != ETAG_CTRL_UNTAG)
+			dev_info(gsw->dev,
+				 "vlan egress tag control neither untag nor tag.\n");
+	}
+
+	return 0;
+}
+
+static int an8855_set_vlan_ports(struct switch_dev *dev, struct switch_val *val)
+{
+	struct gsw_an8855 *gsw = container_of(dev, struct gsw_an8855, swdev);
+	u8 member = 0;
+	u8 etags = 0;
+	int i;
+
+	if (val->port_vlan >= AN8855_NUM_VLANS ||
+		val->len > AN8855_NUM_PORTS)
+		return -EINVAL;
+
+	for (i = 0; i < val->len; i++) {
+		struct switch_port *p = &val->value.ports[i];
+
+		if (p->id >= AN8855_NUM_PORTS)
+			return -EINVAL;
+
+		member |= BIT(p->id);
+
+		if (p->flags & BIT(SWITCH_PORT_FLAG_TAGGED))
+			etags |= BIT(p->id);
+	}
+
+	gsw->vlan_entries[val->port_vlan].member = member;
+	gsw->vlan_entries[val->port_vlan].etags = etags;
+
+	return 0;
+}
+
+static int an8855_set_vid(struct switch_dev *dev,
+			  const struct switch_attr *attr,
+			  struct switch_val *val)
+{
+	struct gsw_an8855 *gsw = container_of(dev, struct gsw_an8855, swdev);
+	int vlan;
+	u16 vid;
+
+	vlan = val->port_vlan;
+	vid = (u16)val->value.i;
+
+	if (vlan < 0 || vlan >= AN8855_NUM_VLANS)
+		return -EINVAL;
+
+	if (vid > AN8855_MAX_VID)
+		return -EINVAL;
+
+	gsw->vlan_entries[vlan].vid = vid;
+	return 0;
+}
+
+static int an8855_get_vid(struct switch_dev *dev,
+			  const struct switch_attr *attr,
+			  struct switch_val *val)
+{
+	val->value.i = val->port_vlan;
+	return 0;
+}
+
+static int an8855_get_port_link(struct switch_dev *dev, int port,
+				struct switch_port_link *link)
+{
+	struct gsw_an8855 *gsw = container_of(dev, struct gsw_an8855, swdev);
+	u32 speed, pmsr;
+
+	if (port < 0 || port >= AN8855_NUM_PORTS)
+		return -EINVAL;
+
+	pmsr = an8855_reg_read(gsw, PMSR(port));
+
+	link->link = pmsr & MAC_LNK_STS;
+	link->duplex = pmsr & MAC_DPX_STS;
+	speed = (pmsr & MAC_SPD_STS_M) >> MAC_SPD_STS_S;
+
+	switch (speed) {
+	case MAC_SPD_10:
+		link->speed = SWITCH_PORT_SPEED_10;
+		break;
+	case MAC_SPD_100:
+		link->speed = SWITCH_PORT_SPEED_100;
+		break;
+	case MAC_SPD_1000:
+		link->speed = SWITCH_PORT_SPEED_1000;
+		break;
+	case MAC_SPD_2500:
+		/* TODO: swconfig has no support for 2500 now */
+		link->speed = SWITCH_PORT_SPEED_UNKNOWN;
+		break;
+	}
+
+	return 0;
+}
+
+static int an8855_set_port_link(struct switch_dev *dev, int port,
+				struct switch_port_link *link)
+{
+#ifndef MODULE
+	if (port >= AN8855_NUM_PHYS)
+		return -EINVAL;
+
+	return switch_generic_set_link(dev, port, link);
+#else
+	return -ENOTSUPP;
+#endif
+}
+
+static u64 get_mib_counter(struct gsw_an8855 *gsw, int i, int port)
+{
+	unsigned int offset;
+	u64 lo, hi, hi2;
+
+	offset = an8855_mibs[i].offset;
+
+	if (an8855_mibs[i].size == 1)
+		return an8855_reg_read(gsw, MIB_COUNTER_REG(port, offset));
+
+	do {
+		hi = an8855_reg_read(gsw, MIB_COUNTER_REG(port, offset + 4));
+		lo = an8855_reg_read(gsw, MIB_COUNTER_REG(port, offset));
+		hi2 = an8855_reg_read(gsw, MIB_COUNTER_REG(port, offset + 4));
+	} while (hi2 != hi);
+
+	return (hi << 32) | lo;
+}
+
+static int an8855_get_port_mib(struct switch_dev *dev,
+				   const struct switch_attr *attr,
+				   struct switch_val *val)
+{
+	static char buf[4096];
+	struct gsw_an8855 *gsw = container_of(dev, struct gsw_an8855, swdev);
+	int i, len = 0;
+
+	if (val->port_vlan >= AN8855_NUM_PORTS)
+		return -EINVAL;
+
+	len += snprintf(buf + len, sizeof(buf) - len,
+			"Port %d MIB counters\n", val->port_vlan);
+
+	for (i = 0; i < ARRAY_SIZE(an8855_mibs); ++i) {
+		u64 counter;
+
+		len += snprintf(buf + len, sizeof(buf) - len,
+				"%-11s: ", an8855_mibs[i].name);
+		counter = get_mib_counter(gsw, i, val->port_vlan);
+		len += snprintf(buf + len, sizeof(buf) - len, "%llu\n",
+				counter);
+	}
+
+	val->value.s = buf;
+	val->len = len;
+	return 0;
+}
+
+static int an8855_get_port_stats(struct switch_dev *dev, int port,
+				 struct switch_port_stats *stats)
+{
+	struct gsw_an8855 *gsw = container_of(dev, struct gsw_an8855, swdev);
+
+	if (port < 0 || port >= AN8855_NUM_PORTS)
+		return -EINVAL;
+
+	stats->tx_bytes = get_mib_counter(gsw, AN8855_PORT_MIB_TXB_ID, port);
+	stats->rx_bytes = get_mib_counter(gsw, AN8855_PORT_MIB_RXB_ID, port);
+
+	return 0;
+}
+
+static void an8855_port_isolation(struct gsw_an8855 *gsw)
+{
+	int i;
+
+	for (i = 0; i < AN8855_NUM_PORTS; i++)
+		an8855_reg_write(gsw, PORTMATRIX(i),
+				 BIT(gsw->cpu_port));
+
+	an8855_reg_write(gsw, PORTMATRIX(gsw->cpu_port), PORT_MATRIX_M);
+
+	for (i = 0; i < AN8855_NUM_PORTS; i++) {
+		u32 pvc_mode = 0x8100 << STAG_VPID_S;
+
+		if (gsw->port5_cfg.stag_on && i == 5)
+			pvc_mode |= PVC_PORT_STAG | PVC_STAG_REPLACE;
+		else
+			pvc_mode |= (VA_TRANSPARENT_PORT << VLAN_ATTR_S);
+
+		an8855_reg_write(gsw, PVC(i), pvc_mode);
+	}
+}
+
+static int an8855_apply_config(struct switch_dev *dev)
+{
+	struct gsw_an8855 *gsw = container_of(dev, struct gsw_an8855, swdev);
+
+	if (!gsw->global_vlan_enable) {
+		an8855_port_isolation(gsw);
+		return 0;
+	}
+
+	an8855_apply_vlan_config(gsw);
+
+	return 0;
+}
+
+static int an8855_reset_switch(struct switch_dev *dev)
+{
+	struct gsw_an8855 *gsw = container_of(dev, struct gsw_an8855, swdev);
+	int i;
+
+	memset(gsw->port_entries, 0, sizeof(gsw->port_entries));
+	memset(gsw->vlan_entries, 0, sizeof(gsw->vlan_entries));
+
+	/* set default vid of each vlan to the same number of vlan, so the vid
+	 * won't need be set explicitly.
+	 */
+	for (i = 0; i < AN8855_NUM_VLANS; i++)
+		gsw->vlan_entries[i].vid = i;
+
+	return 0;
+}
+
+static int an8855_phy_read16(struct switch_dev *dev, int addr, u8 reg,
+				 u16 *value)
+{
+	struct gsw_an8855 *gsw = container_of(dev, struct gsw_an8855, swdev);
+
+	*value = gsw->mii_read(gsw, addr, reg);
+
+	return 0;
+}
+
+static int an8855_phy_write16(struct switch_dev *dev, int addr, u8 reg,
+				  u16 value)
+{
+	struct gsw_an8855 *gsw = container_of(dev, struct gsw_an8855, swdev);
+
+	gsw->mii_write(gsw, addr, reg, value);
+
+	return 0;
+}
+
+static const struct switch_attr an8855_global[] = {
+	{
+		.type = SWITCH_TYPE_INT,
+		.name = "enable_vlan",
+		.description = "VLAN mode (1:enabled)",
+		.max = 1,
+		.id = AN8855_ATTR_ENABLE_VLAN,
+		.get = an8855_get_vlan_enable,
+		.set = an8855_set_vlan_enable,
+	}
+};
+
+static const struct switch_attr an8855_port[] = {
+	{
+		.type = SWITCH_TYPE_STRING,
+		.name = "mib",
+		.description = "Get MIB counters for port",
+		.get = an8855_get_port_mib,
+		.set = NULL,
+	},
+};
+
+static const struct switch_attr an8855_vlan[] = {
+	{
+		.type = SWITCH_TYPE_INT,
+		.name = "vid",
+		.description = "VLAN ID (0-4094)",
+		.set = an8855_set_vid,
+		.get = an8855_get_vid,
+		.max = 4094,
+	},
+};
+
+static const struct switch_dev_ops an8855_swdev_ops = {
+	.attr_global = {
+		.attr = an8855_global,
+		.n_attr = ARRAY_SIZE(an8855_global),
+	},
+	.attr_port = {
+		.attr = an8855_port,
+		.n_attr = ARRAY_SIZE(an8855_port),
+	},
+	.attr_vlan = {
+		.attr = an8855_vlan,
+		.n_attr = ARRAY_SIZE(an8855_vlan),
+	},
+	.get_vlan_ports = an8855_get_vlan_ports,
+	.set_vlan_ports = an8855_set_vlan_ports,
+	.get_port_pvid = an8855_get_port_pvid,
+	.set_port_pvid = an8855_set_port_pvid,
+	.get_port_link = an8855_get_port_link,
+	.set_port_link = an8855_set_port_link,
+	.get_port_stats = an8855_get_port_stats,
+	.apply_config = an8855_apply_config,
+	.reset_switch = an8855_reset_switch,
+	.phy_read16 = an8855_phy_read16,
+	.phy_write16 = an8855_phy_write16,
+};
+
+int an8855_swconfig_init(struct gsw_an8855 *gsw)
+{
+	struct device_node *np = gsw->dev->of_node;
+	struct switch_dev *swdev;
+	int ret;
+
+	if (of_property_read_u32(np, "airoha,cpuport", &gsw->cpu_port))
+		gsw->cpu_port = AN8855_DFL_CPU_PORT;
+
+	swdev = &gsw->swdev;
+
+	swdev->name = gsw->name;
+	swdev->alias = gsw->name;
+	swdev->cpu_port = gsw->cpu_port;
+	swdev->ports = AN8855_NUM_PORTS;
+	swdev->vlans = AN8855_NUM_VLANS;
+	swdev->ops = &an8855_swdev_ops;
+
+	ret = register_switch(swdev, NULL);
+	if (ret) {
+		dev_notice(gsw->dev, "Failed to register switch %s\n",
+			   swdev->name);
+		return ret;
+	}
+
+	an8855_apply_config(swdev);
+
+	return 0;
+}
+
+void an8855_swconfig_destroy(struct gsw_an8855 *gsw)
+{
+	unregister_switch(&gsw->swdev);
+}
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/airoha/an8855/an8855_swconfig.h b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/airoha/an8855/an8855_swconfig.h
new file mode 100644
index 0000000..4c8f2bf
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/airoha/an8855/an8855_swconfig.h
@@ -0,0 +1,29 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (c) 2023 Airoha Inc.
+ * Author: Min Yao <min.yao@airoha.com>
+ */
+
+#ifndef _AN8855_SWCONFIG_H_
+#define _AN8855_SWCONFIG_H_
+
+#ifdef CONFIG_SWCONFIG
+#include <linux/switch.h>
+#include "an8855.h"
+
+int an8855_swconfig_init(struct gsw_an8855 *gsw);
+void an8855_swconfig_destroy(struct gsw_an8855 *gsw);
+#else
+static inline int an8855_swconfig_init(struct gsw_an8855 *gsw)
+{
+	an8855_apply_vlan_config(gsw);
+
+	return 0;
+}
+
+static inline void an8855_swconfig_destroy(struct gsw_an8855 *gsw)
+{
+}
+#endif
+
+#endif /* _AN8855_SWCONFIG_H_ */
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/airoha/an8855/an8855_vlan.c b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/airoha/an8855/an8855_vlan.c
new file mode 100644
index 0000000..6ef8c99
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/airoha/an8855/an8855_vlan.c
@@ -0,0 +1,199 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2023 Airoha Inc.
+ */
+
+#include "an8855.h"
+#include "an8855_regs.h"
+
+struct an8855_mapping an8855_def_mapping[] = {
+	{
+		.name = "llllw",
+		.pvids = { 1, 1, 1, 1, 2, 1 },
+		.members = { 0, 0x2f, 0x30 },
+		.etags = { 0, 0, 0x20 },
+		.vids = { 0, 1, 2 },
+	}, {
+		.name = "wllll",
+		.pvids = { 2, 1, 1, 1, 1, 1 },
+		.members = { 0, 0x3e, 0x21 },
+		.etags = { 0, 0, 0x20 },
+		.vids = { 0, 1, 2 },
+	}, {
+		.name = "lwlll",
+		.pvids = { 1, 2, 1, 1, 1, 1 },
+		.members = { 0, 0x3d, 0x22 },
+		.etags = { 0, 0, 0x20 },
+		.vids = { 0, 1, 2 },
+	}, {
+		.name = "lllll",
+		.pvids = { 1, 1, 1, 1, 1, 1 },
+		.members = { 0, 0x3f },
+		.etags = { 0, 0 },
+		.vids = { 0, 1 },
+	},
+};
+
+void an8855_vlan_ctrl(struct gsw_an8855 *gsw, u32 cmd, u32 val)
+{
+	int i;
+
+	an8855_reg_write(gsw, VTCR,
+			 VTCR_BUSY | ((cmd << VTCR_FUNC_S) & VTCR_FUNC_M) |
+			 (val & VTCR_VID_M));
+
+	for (i = 0; i < 300; i++) {
+		u32 val = an8855_reg_read(gsw, VTCR);
+
+		if ((val & VTCR_BUSY) == 0)
+			break;
+
+		usleep_range(1000, 1100);
+	}
+
+	if (i == 300)
+		dev_info(gsw->dev, "vtcr timeout\n");
+}
+
+static void an8855_write_vlan_entry(struct gsw_an8855 *gsw, int vlan, u16 vid,
+					u8 ports, u8 etags)
+{
+	int port;
+	u32 val;
+
+	/* vlan port membership */
+	if (ports) {
+		val = IVL_MAC | VTAG_EN | VENTRY_VALID
+			| ((ports << PORT_MEM_S) & PORT_MEM_M);
+		/* egress mode */
+		for (port = 0; port < AN8855_NUM_PORTS; port++) {
+			if (etags & BIT(port))
+				val |= (ETAG_CTRL_TAG << PORT_ETAG_S(port));
+			else
+				val |= (ETAG_CTRL_UNTAG << PORT_ETAG_S(port));
+		}
+		an8855_reg_write(gsw, VAWD0, val);
+	} else {
+		an8855_reg_write(gsw, VAWD0, 0);
+	}
+
+	if (ports & 0x40)
+		an8855_reg_write(gsw, VAWD1, 0x1);
+	else
+		an8855_reg_write(gsw, VAWD1, 0x0);
+
+	/* write to vlan table */
+	an8855_vlan_ctrl(gsw, VTCR_WRITE_VLAN_ENTRY, vid);
+}
+
+void an8855_apply_vlan_config(struct gsw_an8855 *gsw)
+{
+	int i, j;
+	u8 tag_ports;
+	u8 untag_ports;
+	u32 val;
+
+	/* set all ports as security mode */
+	for (i = 0; i < AN8855_NUM_PORTS; i++) {
+		val = an8855_reg_read(gsw, PCR(i));
+		an8855_reg_write(gsw, PCR(i), val | SECURITY_MODE);
+		an8855_reg_write(gsw, PORTMATRIX(i), PORT_MATRIX_M);
+	}
+
+	/* check if a port is used in tag/untag vlan egress mode */
+	tag_ports = 0;
+	untag_ports = 0;
+
+	for (i = 0; i < AN8855_NUM_VLANS; i++) {
+		u8 member = gsw->vlan_entries[i].member;
+		u8 etags = gsw->vlan_entries[i].etags;
+
+		if (!member)
+			continue;
+
+		for (j = 0; j < AN8855_NUM_PORTS; j++) {
+			if (!(member & BIT(j)))
+				continue;
+
+			if (etags & BIT(j))
+				tag_ports |= 1u << j;
+			else
+				untag_ports |= 1u << j;
+		}
+	}
+
+	/* set all untag-only ports as transparent and the rest as user port */
+	for (i = 0; i < AN8855_NUM_PORTS; i++) {
+		u32 pvc_mode = 0x8100 << STAG_VPID_S;
+
+		if (untag_ports & BIT(i) && !(tag_ports & BIT(i)))
+			pvc_mode = (0x8100 << STAG_VPID_S) |
+				(VA_TRANSPARENT_PORT << VLAN_ATTR_S);
+
+		if (gsw->port5_cfg.stag_on && i == 5)
+			pvc_mode = (u32)((0x8100 << STAG_VPID_S) | PVC_PORT_STAG
+						| PVC_STAG_REPLACE);
+
+		an8855_reg_write(gsw, PVC(i), pvc_mode);
+	}
+
+	/* first clear the switch vlan table */
+	for (i = 0; i < AN8855_NUM_VLANS; i++)
+		an8855_write_vlan_entry(gsw, i, i, 0, 0);
+
+	/* now program only vlans with members to avoid
+	 * clobbering remapped entries in later iterations
+	 */
+	for (i = 0; i < AN8855_NUM_VLANS; i++) {
+		u16 vid = gsw->vlan_entries[i].vid;
+		u8 member = gsw->vlan_entries[i].member;
+		u8 etags = gsw->vlan_entries[i].etags;
+
+		if (member)
+			an8855_write_vlan_entry(gsw, i, vid, member, etags);
+	}
+
+	/* Port Default PVID */
+	for (i = 0; i < AN8855_NUM_PORTS; i++) {
+		int vlan = gsw->port_entries[i].pvid;
+		u16 pvid = 0;
+		u32 val;
+
+		if (vlan < AN8855_NUM_VLANS && gsw->vlan_entries[vlan].member)
+			pvid = gsw->vlan_entries[vlan].vid;
+
+		val = an8855_reg_read(gsw, PVID(i));
+		val &= ~GRP_PORT_VID_M;
+		val |= pvid;
+		an8855_reg_write(gsw, PVID(i), val);
+	}
+}
+
+struct an8855_mapping *an8855_find_mapping(struct device_node *np)
+{
+	const char *map;
+	int i;
+
+	if (of_property_read_string(np, "airoha,portmap", &map))
+		return NULL;
+
+	for (i = 0; i < ARRAY_SIZE(an8855_def_mapping); i++)
+		if (!strcmp(map, an8855_def_mapping[i].name))
+			return &an8855_def_mapping[i];
+
+	return NULL;
+}
+
+void an8855_apply_mapping(struct gsw_an8855 *gsw, struct an8855_mapping *map)
+{
+	int i = 0;
+
+	for (i = 0; i < AN8855_NUM_PORTS; i++)
+		gsw->port_entries[i].pvid = map->pvids[i];
+
+	for (i = 0; i < AN8855_NUM_VLANS; i++) {
+		gsw->vlan_entries[i].member = map->members[i];
+		gsw->vlan_entries[i].etags = map->etags[i];
+		gsw->vlan_entries[i].vid = map->vids[i];
+	}
+}
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/airoha/an8855/an8855_vlan.h b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/airoha/an8855/an8855_vlan.h
new file mode 100644
index 0000000..d2cd68a
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/airoha/an8855/an8855_vlan.h
@@ -0,0 +1,40 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (c) 2023 Airoha Inc.
+ */
+
+#ifndef _AN8855_VLAN_H_
+#define _AN8855_VLAN_H_
+
+#define AN8855_NUM_PORTS	6
+#define AN8855_NUM_VLANS	4095
+#define AN8855_MAX_VID		4095
+#define AN8855_MIN_VID		0
+
+struct gsw_an8855;
+
+struct an8855_port_entry {
+	u16	pvid;
+};
+
+struct an8855_vlan_entry {
+	u16	vid;
+	u8	member;
+	u8	etags;
+};
+
+struct an8855_mapping {
+	char	*name;
+	u16	pvids[AN8855_NUM_PORTS];
+	u8	members[AN8855_NUM_VLANS];
+	u8	etags[AN8855_NUM_VLANS];
+	u16	vids[AN8855_NUM_VLANS];
+};
+
+extern struct an8855_mapping an8855_defaults[];
+
+void an8855_vlan_ctrl(struct gsw_an8855 *gsw, u32 cmd, u32 val);
+void an8855_apply_vlan_config(struct gsw_an8855 *gsw);
+struct an8855_mapping *an8855_find_mapping(struct device_node *np);
+void an8855_apply_mapping(struct gsw_an8855 *gsw, struct an8855_mapping *map);
+#endif /* _AN8855_VLAN_H_ */
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/net/dsa/tag_arht.c b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/net/dsa/tag_arht.c
new file mode 100644
index 0000000..60ca986
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/net/dsa/tag_arht.c
@@ -0,0 +1,133 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Airoha DSA Tag support
+ * Copyright (C) 2023 Min Yao <min.yao@airoha.com>
+ */
+
+#include <linux/etherdevice.h>
+#include <linux/if_vlan.h>
+
+#include "dsa_priv.h"
+
+#define AIR_HDR_LEN		4
+#define AIR_HDR_XMIT_UNTAGGED		0
+#define AIR_HDR_XMIT_TAGGED_TPID_8100	1
+#define AIR_HDR_XMIT_TAGGED_TPID_88A8	2
+#define AIR_HDR_RECV_SOURCE_PORT_MASK	GENMASK(2, 0)
+#define AIR_HDR_XMIT_DP_BIT_MASK	GENMASK(5, 0)
+
+static struct sk_buff *air_tag_xmit(struct sk_buff *skb,
+				    struct net_device *dev)
+{
+	struct dsa_port *dp = dsa_slave_to_port(dev);
+	u8 xmit_tpid;
+	u8 *air_tag;
+	unsigned char *dest = eth_hdr(skb)->h_dest;
+
+	/* Build the special tag after the MAC Source Address. If VLAN header
+	 * is present, it's required that VLAN header and special tag is
+	 * being combined. Only in this way we can allow the switch can parse
+	 * the both special and VLAN tag at the same time and then look up VLAN
+	 * table with VID.
+	 */
+	switch (skb->protocol) {
+	case htons(ETH_P_8021Q):
+		xmit_tpid = AIR_HDR_XMIT_TAGGED_TPID_8100;
+		break;
+	case htons(ETH_P_8021AD):
+		xmit_tpid = AIR_HDR_XMIT_TAGGED_TPID_88A8;
+		break;
+	default:
+		if (skb_cow_head(skb, AIR_HDR_LEN) < 0)
+			return NULL;
+
+		xmit_tpid = AIR_HDR_XMIT_UNTAGGED;
+		skb_push(skb, AIR_HDR_LEN);
+		memmove(skb->data, skb->data + AIR_HDR_LEN, 2 * ETH_ALEN);
+	}
+
+	air_tag = skb->data + 2 * ETH_ALEN;
+
+	/* Mark tag attribute on special tag insertion to notify hardware
+	 * whether that's a combined special tag with 802.1Q header.
+	 */
+	air_tag[0] = xmit_tpid;
+	air_tag[1] = (1 << dp->index) & AIR_HDR_XMIT_DP_BIT_MASK;
+
+	/* Tag control information is kept for 802.1Q */
+	if (xmit_tpid == AIR_HDR_XMIT_UNTAGGED) {
+		air_tag[2] = 0;
+		air_tag[3] = 0;
+	}
+
+	return skb;
+}
+
+static struct sk_buff *air_tag_rcv(struct sk_buff *skb, struct net_device *dev,
+				   struct packet_type *pt)
+{
+	int port;
+	__be16 *phdr, hdr;
+	unsigned char *dest = eth_hdr(skb)->h_dest;
+	bool is_multicast_skb = is_multicast_ether_addr(dest) &&
+				!is_broadcast_ether_addr(dest);
+
+	if (dev->features & NETIF_F_HW_VLAN_CTAG_RX) {
+		hdr = ntohs(skb->vlan_proto);
+		skb->vlan_proto = 0;
+		skb->vlan_tci = 0;
+	} else {
+		if (unlikely(!pskb_may_pull(skb, AIR_HDR_LEN)))
+			return NULL;
+
+		/* The AIR header is added by the switch between src addr
+		 * and ethertype at this point, skb->data points to 2 bytes
+		 * after src addr so header should be 2 bytes right before.
+		 */
+		phdr = (__be16 *)(skb->data - 2);
+		hdr = ntohs(*phdr);
+
+		/* Remove AIR tag and recalculate checksum. */
+		skb_pull_rcsum(skb, AIR_HDR_LEN);
+
+		memmove(skb->data - ETH_HLEN,
+			skb->data - ETH_HLEN - AIR_HDR_LEN,
+			2 * ETH_ALEN);
+	}
+
+	/* Get source port information */
+	port = (hdr & AIR_HDR_RECV_SOURCE_PORT_MASK);
+
+	skb->dev = dsa_master_find_slave(dev, 0, port);
+	if (!skb->dev)
+		return NULL;
+
+	/* Only unicast or broadcast frames are offloaded */
+	if (likely(!is_multicast_skb))
+		skb->offload_fwd_mark = 1;
+
+	return skb;
+}
+
+static int air_tag_flow_dissect(const struct sk_buff *skb, __be16 *proto,
+				int *offset)
+{
+	*offset = 4;
+	*proto = ((__be16 *)skb->data)[1];
+
+	return 0;
+}
+
+static const struct dsa_device_ops air_netdev_ops = {
+	.name		= "air",
+	.proto		= DSA_TAG_PROTO_ARHT,
+	.xmit		= air_tag_xmit,
+	.rcv		= air_tag_rcv,
+	.flow_dissect	= air_tag_flow_dissect,
+	.overhead	= AIR_HDR_LEN,
+};
+
+MODULE_LICENSE("GPL");
+MODULE_ALIAS_DSA_TAG_DRIVER(DSA_TAG_PROTO_AIR);
+
+module_dsa_tag_driver(air_netdev_ops);
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/wed3/999-2952-net-ethernet-mtk_eth_soc-modify-fq-size-4K.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/flow_patch/999-2952-net-ethernet-mtk_eth_soc-modify-fq-size-4K.patch
similarity index 100%
rename from recipes-kernel/linux/linux-mediatek-5.4/mediatek/wed3/999-2952-net-ethernet-mtk_eth_soc-modify-fq-size-4K.patch
rename to recipes-kernel/linux/linux-mediatek-5.4/mediatek/flow_patch/999-2952-net-ethernet-mtk_eth_soc-modify-fq-size-4K.patch
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/flow_patch/999-3001-mt7622-backport-nf-hw-offload-framework-and-upstream.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/flow_patch/999-3001-mt7622-backport-nf-hw-offload-framework-and-upstream.patch
index 1ba25be..4a9bfae 100644
--- a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/flow_patch/999-3001-mt7622-backport-nf-hw-offload-framework-and-upstream.patch
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/flow_patch/999-3001-mt7622-backport-nf-hw-offload-framework-and-upstream.patch
@@ -1,14 +1,14 @@
-From b80c745d2b90b30558e4f5b12060af956ae8e76d Mon Sep 17 00:00:00 2001
+From 35623475d9eb8522756b0b4833c95a31a0ceb10b Mon Sep 17 00:00:00 2001
 From: Bo Jiao <Bo.Jiao@mediatek.com>
 Date: Mon, 18 Sep 2023 10:52:27 +0800
-Subject: [PATCH 02/22] mt7622 backport nf hw offload framework and upstream
+Subject: [PATCH 01/24] mt7622 backport nf hw offload framework and upstream
  hnat plus xt-FLOWOFFLOAD update v2
 
 ---
  drivers/net/ethernet/mediatek/Makefile        |    3 +-
  drivers/net/ethernet/mediatek/mtk_eth_soc.c   |   25 +-
  drivers/net/ethernet/mediatek/mtk_eth_soc.h   |   19 +-
- drivers/net/ethernet/mediatek/mtk_ppe.c       |  510 +++++++
+ drivers/net/ethernet/mediatek/mtk_ppe.c       |  514 +++++++
  drivers/net/ethernet/mediatek/mtk_ppe.h       |  288 ++++
  .../net/ethernet/mediatek/mtk_ppe_debugfs.c   |  214 +++
  .../net/ethernet/mediatek/mtk_ppe_offload.c   |  535 ++++++++
@@ -46,7 +46,7 @@
  net/netfilter/nf_flow_table_ip.c              |  447 +++---
  net/netfilter/nf_flow_table_offload.c         | 1199 +++++++++++++++++
  net/netfilter/xt_FLOWOFFLOAD.c                |  800 +++++++++++
- 41 files changed, 4995 insertions(+), 435 deletions(-)
+ 41 files changed, 4999 insertions(+), 435 deletions(-)
  mode change 100644 => 100755 drivers/net/ethernet/mediatek/Makefile
  mode change 100644 => 100755 drivers/net/ethernet/mediatek/mtk_eth_soc.c
  mode change 100644 => 100755 drivers/net/ethernet/mediatek/mtk_eth_soc.h
@@ -76,10 +76,10 @@
 diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.c b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
 old mode 100644
 new mode 100755
-index c4bea4d..9c85e16
+index 37fd338..20b2943
 --- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c
 +++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
-@@ -3573,6 +3573,7 @@ static int mtk_open(struct net_device *dev)
+@@ -4001,6 +4001,7 @@ static int mtk_open(struct net_device *dev)
  	u32 id = mtk_mac2xgmii_id(eth, mac->id);
  	int err, i;
  	struct device_node *phy_node;
@@ -87,7 +87,7 @@
  
  	err = phylink_of_phy_connect(mac->phylink, mac->of_node, 0);
  	if (err) {
-@@ -3650,7 +3651,10 @@ static int mtk_open(struct net_device *dev)
+@@ -4085,7 +4086,10 @@ static int mtk_open(struct net_device *dev)
  		regmap_write(eth->sgmii->pcs[id].regmap,
  			     SGMSYS_QPHY_PWR_STATE_CTRL, 0);
  
@@ -99,7 +99,7 @@
  
  	return 0;
  }
-@@ -3730,6 +3734,9 @@ static int mtk_stop(struct net_device *dev)
+@@ -4172,6 +4176,9 @@ static int mtk_stop(struct net_device *dev)
  
  	mtk_dma_free(eth);
  
@@ -109,7 +109,7 @@
  	return 0;
  }
  
-@@ -4576,6 +4583,7 @@ static const struct net_device_ops mtk_netdev_ops = {
+@@ -5081,6 +5088,7 @@ static const struct net_device_ops mtk_netdev_ops = {
  #ifdef CONFIG_NET_POLL_CONTROLLER
  	.ndo_poll_controller	= mtk_poll_controller,
  #endif
@@ -117,7 +117,7 @@
  };
  
  static void mux_poll(struct work_struct *work)
-@@ -5161,6 +5169,17 @@ static int mtk_probe(struct platform_device *pdev)
+@@ -5711,6 +5719,17 @@ static int mtk_probe(struct platform_device *pdev)
  			goto err_free_dev;
  	}
  
@@ -135,7 +135,7 @@
  	for (i = 0; i < MTK_MAX_DEVS; i++) {
  		if (!eth->netdev[i])
  			continue;
-@@ -5254,6 +5273,7 @@ static const struct mtk_soc_data mt2701_data = {
+@@ -5811,6 +5830,7 @@ static const struct mtk_soc_data mt2701_data = {
  	.required_clks = MT7623_CLKS_BITMAP,
  	.required_pctl = true,
  	.has_sram = false,
@@ -143,7 +143,7 @@
  	.rss_num = 0,
  	.txrx = {
  		.txd_size = sizeof(struct mtk_tx_dma),
-@@ -5271,6 +5291,7 @@ static const struct mtk_soc_data mt7621_data = {
+@@ -5828,6 +5848,7 @@ static const struct mtk_soc_data mt7621_data = {
  	.required_clks = MT7621_CLKS_BITMAP,
  	.required_pctl = false,
  	.has_sram = false,
@@ -151,7 +151,7 @@
  	.rss_num = 0,
  	.txrx = {
  		.txd_size = sizeof(struct mtk_tx_dma),
-@@ -5289,6 +5310,7 @@ static const struct mtk_soc_data mt7622_data = {
+@@ -5846,6 +5867,7 @@ static const struct mtk_soc_data mt7622_data = {
  	.required_clks = MT7622_CLKS_BITMAP,
  	.required_pctl = false,
  	.has_sram = false,
@@ -159,7 +159,7 @@
  	.rss_num = 0,
  	.txrx = {
  		.txd_size = sizeof(struct mtk_tx_dma),
-@@ -5306,6 +5328,7 @@ static const struct mtk_soc_data mt7623_data = {
+@@ -5863,6 +5885,7 @@ static const struct mtk_soc_data mt7623_data = {
  	.required_clks = MT7623_CLKS_BITMAP,
  	.required_pctl = true,
  	.has_sram = false,
@@ -170,7 +170,7 @@
 diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.h b/drivers/net/ethernet/mediatek/mtk_eth_soc.h
 old mode 100644
 new mode 100755
-index 8a9b615..a87e46d
+index 26a99d1..4d3a63c
 --- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h
 +++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h
 @@ -15,6 +15,8 @@
@@ -182,7 +182,7 @@
  
  #define MTK_QDMA_PAGE_SIZE	2048
  #define	MTK_MAX_RX_LENGTH	1536
-@@ -44,7 +46,8 @@
+@@ -47,7 +49,8 @@
  				 NETIF_F_HW_VLAN_CTAG_TX | \
  				 NETIF_F_SG | NETIF_F_TSO | \
  				 NETIF_F_TSO6 | \
@@ -192,7 +192,7 @@
  #define MTK_SET_FEATURES	(NETIF_F_LRO | \
  				 NETIF_F_HW_VLAN_CTAG_RX)
  #define MTK_HW_FEATURES_MT7628	(NETIF_F_SG | NETIF_F_RXCSUM)
-@@ -127,6 +130,7 @@
+@@ -134,6 +137,7 @@
  #define MTK_GDMA_UCS_EN		BIT(20)
  #define MTK_GDMA_STRP_CRC	BIT(16)
  #define MTK_GDMA_TO_PDMA	0x0
@@ -200,7 +200,7 @@
  #define MTK_GDMA_DROP_ALL	0x7777
  
  /* GDM Egress Control Register */
-@@ -617,6 +621,12 @@
+@@ -661,6 +665,12 @@
  #define RX_DMA_TCI(_x)		((_x) & (VLAN_PRIO_MASK | VLAN_VID_MASK))
  #define RX_DMA_VPID(_x)		(((_x) >> 16) & 0xffff)
  
@@ -213,7 +213,7 @@
  /* QDMA descriptor rxd4 */
  #define RX_DMA_L4_VALID		BIT(24)
  #define RX_DMA_L4_VALID_PDMA	BIT(30)		/* when PDMA is used */
-@@ -1651,6 +1661,7 @@ struct mtk_soc_data {
+@@ -1712,6 +1722,7 @@ struct mtk_soc_data {
  	u64		caps;
  	u64		required_clks;
  	bool		required_pctl;
@@ -221,7 +221,7 @@
  	netdev_features_t hw_features;
  	bool		has_sram;
  	struct {
-@@ -1847,6 +1858,9 @@ struct mtk_eth {
+@@ -1912,6 +1923,9 @@ struct mtk_eth {
  	int				ip_align;
  	spinlock_t			syscfg0_lock;
  	struct timer_list		mtk_dma_monitor_timer;
@@ -231,7 +231,7 @@
  };
  
  /* struct mtk_mac -	the structure that holds the info about the MACs of the
-@@ -1927,6 +1941,9 @@ int mtk_toprgu_init(struct mtk_eth *eth, struct device_node *r);
+@@ -1993,6 +2007,9 @@ int mtk_toprgu_init(struct mtk_eth *eth, struct device_node *r);
  int mtk_dump_usxgmii(struct regmap *pmap, char *name, u32 offset, u32 range);
  void mtk_usxgmii_link_poll(struct work_struct *work);
  
@@ -243,7 +243,7 @@
  #endif /* MTK_ETH_H */
 diff --git a/drivers/net/ethernet/mediatek/mtk_ppe.c b/drivers/net/ethernet/mediatek/mtk_ppe.c
 new file mode 100644
-index 0000000..27b5be5
+index 0000000..6965d98
 --- /dev/null
 +++ b/drivers/net/ethernet/mediatek/mtk_ppe.c
 @@ -0,0 +1,514 @@
@@ -1967,10 +1967,10 @@
 +
 +#endif
 diff --git a/drivers/net/ppp/ppp_generic.c b/drivers/net/ppp/ppp_generic.c
-index 078c0f4..f8a98d8 100644
+index 555ba50..25dcff2 100644
 --- a/drivers/net/ppp/ppp_generic.c
 +++ b/drivers/net/ppp/ppp_generic.c
-@@ -1378,12 +1378,34 @@ static void ppp_dev_priv_destructor(struct net_device *dev)
+@@ -1380,12 +1380,34 @@ static void ppp_dev_priv_destructor(struct net_device *dev)
  		ppp_destroy_interface(ppp);
  }
  
@@ -2043,10 +2043,10 @@
  
  static int pppoe_recvmsg(struct socket *sock, struct msghdr *m,
 diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
-index 631d158..ef44d9a 100644
+index 1c1ab37..44842a2 100644
 --- a/include/linux/netdevice.h
 +++ b/include/linux/netdevice.h
-@@ -838,6 +838,59 @@ typedef u16 (*select_queue_fallback_t)(struct net_device *dev,
+@@ -843,6 +843,59 @@ typedef u16 (*select_queue_fallback_t)(struct net_device *dev,
  				       struct sk_buff *skb,
  				       struct net_device *sb_dev);
  
@@ -2106,7 +2106,7 @@
  enum tc_setup_type {
  	TC_SETUP_QDISC_MQPRIO,
  	TC_SETUP_CLSU32,
-@@ -853,6 +906,7 @@ enum tc_setup_type {
+@@ -858,6 +911,7 @@ enum tc_setup_type {
  	TC_SETUP_ROOT_QDISC,
  	TC_SETUP_QDISC_GRED,
  	TC_SETUP_QDISC_TAPRIO,
@@ -2114,7 +2114,7 @@
  };
  
  /* These structures hold the attributes of bpf state that are being passed
-@@ -1248,6 +1302,8 @@ struct tlsdev_ops;
+@@ -1253,6 +1307,8 @@ struct tlsdev_ops;
   *	Get devlink port instance associated with a given netdev.
   *	Called with a reference on the netdevice and devlink locks only,
   *	rtnl_lock is not held.
@@ -2123,7 +2123,7 @@
   */
  struct net_device_ops {
  	int			(*ndo_init)(struct net_device *dev);
-@@ -1445,6 +1501,8 @@ struct net_device_ops {
+@@ -1450,6 +1506,8 @@ struct net_device_ops {
  	int			(*ndo_xsk_wakeup)(struct net_device *dev,
  						  u32 queue_id, u32 flags);
  	struct devlink_port *	(*ndo_get_devlink_port)(struct net_device *dev);
@@ -2132,7 +2132,7 @@
  };
  
  /**
-@@ -2670,6 +2728,8 @@ void dev_remove_offload(struct packet_offload *po);
+@@ -2689,6 +2747,8 @@ void dev_remove_offload(struct packet_offload *po);
  
  int dev_get_iflink(const struct net_device *dev);
  int dev_fill_metadata_dst(struct net_device *dev, struct sk_buff *skb);
@@ -2210,7 +2210,7 @@
 -
  #endif /* _NF_CONNTRACK_IPV6_H*/
 diff --git a/include/net/netfilter/nf_conntrack.h b/include/net/netfilter/nf_conntrack.h
-index 90690e3..ce0bc3e 100644
+index 90690e3..38a8d3f 100644
 --- a/include/net/netfilter/nf_conntrack.h
 +++ b/include/net/netfilter/nf_conntrack.h
 @@ -105,6 +105,8 @@ struct nf_conn {
@@ -2222,7 +2222,7 @@
  };
  
  static inline struct nf_conn *
-@@ -279,6 +279,18 @@ static inline bool nf_ct_should_gc(const struct nf_conn *ct)
+@@ -279,6 +281,18 @@ static inline bool nf_ct_should_gc(const struct nf_conn *ct)
  	       !nf_ct_is_dying(ct);
  }
  
@@ -2264,7 +2264,7 @@
  
  int nf_conntrack_acct_init(void);
 diff --git a/include/net/netfilter/nf_flow_table.h b/include/net/netfilter/nf_flow_table.h
-index 68d7fc9..feac793 100644
+index 68d7fc9..7374cb2 100644
 --- a/include/net/netfilter/nf_flow_table.h
 +++ b/include/net/netfilter/nf_flow_table.h
 @@ -8,31 +8,101 @@
@@ -2370,7 +2370,7 @@
  
  struct flow_offload_tuple {
  	union {
-@@ -52,13 +120,30 @@ struct flow_offload_tuple {
+@@ -52,13 +122,30 @@ struct flow_offload_tuple {
  
  	u8				l3proto;
  	u8				l4proto;
@@ -2406,7 +2406,7 @@
  	};
  };
  
-@@ -67,52 +152,140 @@ struct flow_offload_tuple_rhash {
+@@ -67,52 +154,140 @@ struct flow_offload_tuple_rhash {
  	struct flow_offload_tuple	tuple;
  };
  
@@ -2569,7 +2569,7 @@
  
  struct flow_ports {
  	__be16 source, dest;
-@@ -126,4 +299,41 @@ unsigned int nf_flow_offload_ipv6_hook(void *priv, struct sk_buff *skb,
+@@ -126,4 +301,41 @@ unsigned int nf_flow_offload_ipv6_hook(void *priv, struct sk_buff *skb,
  #define MODULE_ALIAS_NF_FLOWTABLE(family)	\
  	MODULE_ALIAS("nf-flowtable-" __stringify(family))
  
@@ -2685,10 +2685,10 @@
 +
 +#endif /* _XT_FLOWOFFLOAD_H */
 diff --git a/net/8021q/vlan_dev.c b/net/8021q/vlan_dev.c
-index 0a3a167..6112266 100644
+index dd7e09e..c373f1d 100644
 --- a/net/8021q/vlan_dev.c
 +++ b/net/8021q/vlan_dev.c
-@@ -747,6 +747,26 @@ static int vlan_dev_get_iflink(const struct net_device *dev)
+@@ -771,6 +771,26 @@ static int vlan_dev_get_iflink(const struct net_device *dev)
  	return real_dev->ifindex;
  }
  
@@ -2715,7 +2715,7 @@
  static const struct ethtool_ops vlan_ethtool_ops = {
  	.get_link_ksettings	= vlan_ethtool_get_link_ksettings,
  	.get_drvinfo	        = vlan_ethtool_get_drvinfo,
-@@ -785,6 +805,7 @@ static const struct net_device_ops vlan_netdev_ops = {
+@@ -809,6 +829,7 @@ static const struct net_device_ops vlan_netdev_ops = {
  #endif
  	.ndo_fix_features	= vlan_dev_fix_features,
  	.ndo_get_iflink		= vlan_dev_get_iflink,
@@ -2724,10 +2724,10 @@
  
  static void vlan_dev_free(struct net_device *dev)
 diff --git a/net/bridge/br_device.c b/net/bridge/br_device.c
-index 501f77f..0940b44 100644
+index ab201d5..deec45b 100644
 --- a/net/bridge/br_device.c
 +++ b/net/bridge/br_device.c
-@@ -377,6 +377,54 @@ static int br_del_slave(struct net_device *dev, struct net_device *slave_dev)
+@@ -385,6 +385,54 @@ static int br_del_slave(struct net_device *dev, struct net_device *slave_dev)
  	return br_del_if(br, slave_dev);
  }
  
@@ -2782,7 +2782,7 @@
  static const struct ethtool_ops br_ethtool_ops = {
  	.get_drvinfo    = br_getinfo,
  	.get_link	= ethtool_op_get_link,
-@@ -410,6 +458,7 @@ static const struct net_device_ops br_netdev_ops = {
+@@ -418,6 +466,7 @@ static const struct net_device_ops br_netdev_ops = {
  	.ndo_bridge_setlink	 = br_setlink,
  	.ndo_bridge_dellink	 = br_dellink,
  	.ndo_features_check	 = passthru_features_check,
@@ -2895,10 +2895,10 @@
  		     struct bridge_vlan_info *p_vinfo)
  {
 diff --git a/net/core/dev.c b/net/core/dev.c
-index 54cc544..a117bd0 100644
+index ef7362b..5bade26 100644
 --- a/net/core/dev.c
 +++ b/net/core/dev.c
-@@ -639,6 +639,52 @@ int dev_fill_metadata_dst(struct net_device *dev, struct sk_buff *skb)
+@@ -722,6 +722,52 @@ int dev_fill_metadata_dst(struct net_device *dev, struct sk_buff *skb)
  }
  EXPORT_SYMBOL_GPL(dev_fill_metadata_dst);
  
@@ -2952,7 +2952,7 @@
   *	__dev_get_by_name	- find a device by its name
   *	@net: the applicable net namespace
 diff --git a/net/dsa/slave.c b/net/dsa/slave.c
-index e2b91b3..2dfaa1e 100644
+index cd5b354..2ea9ec1 100644
 --- a/net/dsa/slave.c
 +++ b/net/dsa/slave.c
 @@ -1031,14 +1031,32 @@ static int dsa_slave_setup_tc_block(struct net_device *dev,
@@ -3042,7 +3042,7 @@
  	tristate "Netfilter IPv4 packet duplication to alternate destination"
  	depends on !NF_CONNTRACK || NF_CONNTRACK
 diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c
-index 8231a7a..7176d7f 100644
+index 816275b..671f767 100644
 --- a/net/ipv6/ip6_output.c
 +++ b/net/ipv6/ip6_output.c
 @@ -607,7 +607,7 @@ int ip6_forward(struct sk_buff *skb)
@@ -3181,7 +3181,7 @@
  obj-$(CONFIG_NETFILTER_XT_TARGET_HMARK) += xt_HMARK.o
  obj-$(CONFIG_NETFILTER_XT_TARGET_LED) += xt_LED.o
 diff --git a/net/netfilter/nf_conntrack_core.c b/net/netfilter/nf_conntrack_core.c
-index f6ab6f4..f689e19 100644
+index 706d180..65d16ef 100644
 --- a/net/netfilter/nf_conntrack_core.c
 +++ b/net/netfilter/nf_conntrack_core.c
 @@ -864,9 +864,8 @@ nf_conntrack_hash_check_insert(struct nf_conn *ct)
@@ -6086,7 +6086,7 @@
 +}
 diff --git a/net/netfilter/xt_FLOWOFFLOAD.c b/net/netfilter/xt_FLOWOFFLOAD.c
 new file mode 100644
-index 0000000..2cab008
+index 0000000..e4c7db9
 --- /dev/null
 +++ b/net/netfilter/xt_FLOWOFFLOAD.c
 @@ -0,0 +1,800 @@
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/flow_patch/999-3002-dts-netsys2-wed-changes.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/flow_patch/999-3002-dts-netsys2-wed-changes.patch
index eacae85..213c69e 100644
--- a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/flow_patch/999-3002-dts-netsys2-wed-changes.patch
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/flow_patch/999-3002-dts-netsys2-wed-changes.patch
@@ -1,19 +1,37 @@
-From be48305fd2e3ecd9a9853f2ae11fb9432e40b299 Mon Sep 17 00:00:00 2001
+From f99c7b63e766c2ff8851a8ba6ff77f3d8bfef0d5 Mon Sep 17 00:00:00 2001
 From: Bo Jiao <Bo.Jiao@mediatek.com>
 Date: Mon, 18 Sep 2023 10:55:08 +0800
-Subject: [PATCH 03/22] dts mt7986 wed changes
+Subject: [PATCH 02/24] dts netsys2 wed changes
 
 ---
- arch/arm64/boot/dts/mediatek/mt7986a.dtsi | 33 ++++++++---------------
- arch/arm64/boot/dts/mediatek/mt7986b.dtsi | 33 ++++++++---------------
- 2 files changed, 22 insertions(+), 44 deletions(-)
+ .../boot/dts/mediatek/mt7981-spim-nor-rfb.dts |  8 -----
+ arch/arm64/boot/dts/mediatek/mt7981.dtsi      | 21 ++++--------
+ arch/arm64/boot/dts/mediatek/mt7986a.dtsi     | 33 +++++++------------
+ arch/arm64/boot/dts/mediatek/mt7986b.dtsi     | 33 +++++++------------
+ 4 files changed, 28 insertions(+), 67 deletions(-)
 
-diff --git a/arch/arm64/boot/dts/mediatek/mt7986a.dtsi b/arch/arm64/boot/dts/mediatek/mt7986a.dtsi
-index e43c306..e5d4e12 100644
---- a/arch/arm64/boot/dts/mediatek/mt7986a.dtsi
-+++ b/arch/arm64/boot/dts/mediatek/mt7986a.dtsi
-@@ -58,32 +58,20 @@
- 		};
+diff --git a/arch/arm64/boot/dts/mediatek/mt7981-spim-nor-rfb.dts b/arch/arm64/boot/dts/mediatek/mt7981-spim-nor-rfb.dts
+index 3fa55a0..f5c70a4 100755
+--- a/arch/arm64/boot/dts/mediatek/mt7981-spim-nor-rfb.dts
++++ b/arch/arm64/boot/dts/mediatek/mt7981-spim-nor-rfb.dts
+@@ -211,11 +211,3 @@
+ &xhci {  
+         status = "okay";
+ };
+-
+-&wed {
+-	dy_txbm_enable = "true";
+-	dy_txbm_budget = <8>;
+-	txbm_init_sz = <8>;
+-	txbm_max_sz = <32>;
+-	status = "okay";
+-};
+diff --git a/arch/arm64/boot/dts/mediatek/mt7981.dtsi b/arch/arm64/boot/dts/mediatek/mt7981.dtsi
+index 91415e4..283421a 100644
+--- a/arch/arm64/boot/dts/mediatek/mt7981.dtsi
++++ b/arch/arm64/boot/dts/mediatek/mt7981.dtsi
+@@ -90,22 +90,12 @@
+ 		#io-channel-cells = <1>;
  	};
  
 -	wed: wed@15010000 {
@@ -24,49 +42,34 @@
 -		reg = <0 0x15010000 0 0x1000>,
 -		      <0 0x15011000 0 0x1000>;
 +	wed0: wed@15010000 {
-+		compatible = "mediatek,mt7986-wed",
++		compatible = "mediatek,mt7981-wed",
 +			     "syscon";
 +		reg = <0 0x15010000 0 0x1000>;
  		interrupt-parent = <&gic>;
 -		interrupts = <GIC_SPI 205 IRQ_TYPE_LEVEL_HIGH>,
 -			     <GIC_SPI 206 IRQ_TYPE_LEVEL_HIGH>;
-+		interrupts = <GIC_SPI 205 IRQ_TYPE_LEVEL_HIGH>;
- 	};
- 
--	wed2: wed2@15011000 {
--		compatible = "mediatek,wed2";
--		wed_num = <2>;
--		reg = <0 0x15010000 0 0x1000>,
--		      <0 0x15011000 0 0x1000>;
-+	wed1: wed@15011000 {
-+		compatible = "mediatek,mt7986-wed",
-+			     "syscon";
-+		reg = <0 0x15011000 0 0x1000>;
- 		interrupt-parent = <&gic>;
--		interrupts = <GIC_SPI 205 IRQ_TYPE_LEVEL_HIGH>,
--			     <GIC_SPI 206 IRQ_TYPE_LEVEL_HIGH>;
 -	};
 -
 -	wdma: wdma@15104800 {
 -		compatible = "mediatek,wed-wdma";
 -		reg = <0 0x15104800 0 0x400>,
 -		      <0 0x15104c00 0 0x400>;
-+		interrupts = <GIC_SPI 206 IRQ_TYPE_LEVEL_HIGH>;
++		interrupts = <GIC_SPI 205 IRQ_TYPE_LEVEL_HIGH>;
  	};
  
  	ap2woccif: ap2woccif@151A5000 {
-@@ -507,6 +495,7 @@
- 					 <&topckgen CK_TOP_CB_SGM_325M>;
+@@ -423,6 +413,7 @@
                  mediatek,ethsys = <&ethsys>;
  		mediatek,sgmiisys = <&sgmiisys0>, <&sgmiisys1>;
-+		mediatek,wed = <&wed0>, <&wed1>;
+ 		mediatek,infracfg = <&topmisc>;
++		mediatek,wed = <&wed0>;
                  #reset-cells = <1>;
                  #address-cells = <1>;
                  #size-cells = <0>;
-diff --git a/arch/arm64/boot/dts/mediatek/mt7986b.dtsi b/arch/arm64/boot/dts/mediatek/mt7986b.dtsi
-index 21d8357..2d2207f 100644
---- a/arch/arm64/boot/dts/mediatek/mt7986b.dtsi
-+++ b/arch/arm64/boot/dts/mediatek/mt7986b.dtsi
+diff --git a/arch/arm64/boot/dts/mediatek/mt7986a.dtsi b/arch/arm64/boot/dts/mediatek/mt7986a.dtsi
+index 2c7e171..3a4f279 100644
+--- a/arch/arm64/boot/dts/mediatek/mt7986a.dtsi
++++ b/arch/arm64/boot/dts/mediatek/mt7986a.dtsi
 @@ -58,32 +58,20 @@
  		};
  	};
@@ -110,7 +113,7 @@
  	};
  
  	ap2woccif: ap2woccif@151A5000 {
-@@ -409,6 +397,7 @@
+@@ -494,6 +482,7 @@
  					 <&topckgen CK_TOP_CB_SGM_325M>;
                  mediatek,ethsys = <&ethsys>;
  		mediatek,sgmiisys = <&sgmiisys0>, <&sgmiisys1>;
@@ -118,12 +121,12 @@
                  #reset-cells = <1>;
                  #address-cells = <1>;
                  #size-cells = <0>;
-diff --git a/arch/arm64/boot/dts/mediatek/mt7981.dtsi b/arch/arm64/boot/dts/mediatek/mt7981.dtsi
-index ccaf0ad0..b2f53b13 100644
---- a/arch/arm64/boot/dts/mediatek/mt7981.dtsi
-+++ b/arch/arm64/boot/dts/mediatek/mt7981.dtsi
-@@ -90,22 +90,12 @@
- 		#io-channel-cells = <1>;
+diff --git a/arch/arm64/boot/dts/mediatek/mt7986b.dtsi b/arch/arm64/boot/dts/mediatek/mt7986b.dtsi
+index 26f093b..ce884f0 100644
+--- a/arch/arm64/boot/dts/mediatek/mt7986b.dtsi
++++ b/arch/arm64/boot/dts/mediatek/mt7986b.dtsi
+@@ -58,32 +58,20 @@
+ 		};
  	};
  
 -	wed: wed@15010000 {
@@ -134,46 +137,45 @@
 -		reg = <0 0x15010000 0 0x1000>,
 -		      <0 0x15011000 0 0x1000>;
 +	wed0: wed@15010000 {
-+		compatible = "mediatek,mt7981-wed",
++		compatible = "mediatek,mt7986-wed",
 +			     "syscon";
 +		reg = <0 0x15010000 0 0x1000>;
  		interrupt-parent = <&gic>;
 -		interrupts = <GIC_SPI 205 IRQ_TYPE_LEVEL_HIGH>,
 -			     <GIC_SPI 206 IRQ_TYPE_LEVEL_HIGH>;
++		interrupts = <GIC_SPI 205 IRQ_TYPE_LEVEL_HIGH>;
+ 	};
+ 
+-	wed2: wed2@15011000 {
+-		compatible = "mediatek,wed2";
+-		wed_num = <2>;
+-		reg = <0 0x15010000 0 0x1000>,
+-		      <0 0x15011000 0 0x1000>;
++	wed1: wed@15011000 {
++		compatible = "mediatek,mt7986-wed",
++			     "syscon";
++		reg = <0 0x15011000 0 0x1000>;
+ 		interrupt-parent = <&gic>;
+-		interrupts = <GIC_SPI 205 IRQ_TYPE_LEVEL_HIGH>,
+-			     <GIC_SPI 206 IRQ_TYPE_LEVEL_HIGH>;
 -	};
 -
 -	wdma: wdma@15104800 {
 -		compatible = "mediatek,wed-wdma";
 -		reg = <0 0x15104800 0 0x400>,
 -		      <0 0x15104c00 0 0x400>;
-+		interrupts = <GIC_SPI 205 IRQ_TYPE_LEVEL_HIGH>;
++		interrupts = <GIC_SPI 206 IRQ_TYPE_LEVEL_HIGH>;
  	};
  
  	ap2woccif: ap2woccif@151A5000 {
-@@ -423,6 +413,7 @@
+@@ -408,6 +396,7 @@
+ 					 <&topckgen CK_TOP_CB_SGM_325M>;
                  mediatek,ethsys = <&ethsys>;
  		mediatek,sgmiisys = <&sgmiisys0>, <&sgmiisys1>;
- 		mediatek,infracfg = <&topmisc>;
-+		mediatek,wed = <&wed0>;
++		mediatek,wed = <&wed0>, <&wed1>;
                  #reset-cells = <1>;
                  #address-cells = <1>;
                  #size-cells = <0>;
-diff --git a/arch/arm64/boot/dts/mediatek/mt7981-spim-nor-rfb.dts b/arch/arm64/boot/dts/mediatek/mt7981-spim-nor-rfb.dts
-index 3fa55a07..f5c70a4e 100755
---- a/arch/arm64/boot/dts/mediatek/mt7981-spim-nor-rfb.dts
-+++ b/arch/arm64/boot/dts/mediatek/mt7981-spim-nor-rfb.dts
-@@ -211,11 +211,3 @@
- &xhci {  
-         status = "okay";
- };
--
--&wed {
--	dy_txbm_enable = "true";
--	dy_txbm_budget = <8>;
--	txbm_init_sz = <8>;
--	txbm_max_sz = <32>;
--	status = "okay";
--};
 -- 
 2.18.0
 
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/flow_patch/999-3003-add-wed.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/flow_patch/999-3003-add-wed.patch
index 16c04b5..a60b6ce 100644
--- a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/flow_patch/999-3003-add-wed.patch
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/flow_patch/999-3003-add-wed.patch
@@ -1,7 +1,7 @@
-From cdb36beeb6725bcef3faad499c017c26bc17fd4a Mon Sep 17 00:00:00 2001
+From b895d23fa63dd712191b6d223fe6c41682c7d375 Mon Sep 17 00:00:00 2001
 From: Sujuan Chen <sujuan.chen@mediatek.com>
 Date: Mon, 18 Sep 2023 10:56:21 +0800
-Subject: [PATCH 04/22] add wed
+Subject: [PATCH 03/24] add wed
 
 ---
  arch/arm64/boot/dts/mediatek/mt7622.dtsi      |  32 +-
@@ -13,7 +13,7 @@
  drivers/net/ethernet/mediatek/mtk_ppe.h       |  89 +-
  .../net/ethernet/mediatek/mtk_ppe_debugfs.c   |   4 +-
  .../net/ethernet/mediatek/mtk_ppe_offload.c   | 167 +++-
- drivers/net/ethernet/mediatek/mtk_wed.c       | 876 ++++++++++++++++++
+ drivers/net/ethernet/mediatek/mtk_wed.c       | 881 ++++++++++++++++++
  drivers/net/ethernet/mediatek/mtk_wed.h       | 135 +++
  .../net/ethernet/mediatek/mtk_wed_debugfs.c   | 175 ++++
  drivers/net/ethernet/mediatek/mtk_wed_ops.c   |   8 +
@@ -21,7 +21,7 @@
  include/linux/netdevice.h                     |   7 +
  include/linux/soc/mediatek/mtk_wed.h          | 131 +++
  net/core/dev.c                                |   4 +
- 17 files changed, 2207 insertions(+), 103 deletions(-)
+ 17 files changed, 2212 insertions(+), 103 deletions(-)
  mode change 100755 => 100644 drivers/net/ethernet/mediatek/Kconfig
  mode change 100755 => 100644 drivers/net/ethernet/mediatek/Makefile
  mode change 100755 => 100644 drivers/net/ethernet/mediatek/mtk_eth_soc.c
@@ -134,7 +134,7 @@
 diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.c b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
 old mode 100755
 new mode 100644
-index 9c85e16..88b38e2
+index 20b2943..8d15399
 --- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c
 +++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
 @@ -21,11 +21,13 @@
@@ -151,7 +151,7 @@
  
  #if defined(CONFIG_NET_MEDIATEK_HNAT) || defined(CONFIG_NET_MEDIATEK_HNAT_MODULE)
  #include "mtk_hnat/nf_hnat_mtk.h"
-@@ -2191,6 +2193,7 @@ static int mtk_poll_rx(struct napi_struct *napi, int budget,
+@@ -2356,6 +2358,7 @@ static int mtk_poll_rx(struct napi_struct *napi, int budget,
  		struct net_device *netdev = NULL;
  		dma_addr_t dma_addr = DMA_MAPPING_ERROR;
  		u64 addr64 = 0;
@@ -159,7 +159,7 @@
  		int mac = 0;
  
  		idx = NEXT_DESP_IDX(ring->calc_idx, ring->dma_size);
-@@ -2282,6 +2285,17 @@ static int mtk_poll_rx(struct napi_struct *napi, int budget,
+@@ -2444,6 +2447,17 @@ static int mtk_poll_rx(struct napi_struct *napi, int budget,
  			skb_checksum_none_assert(skb);
  		skb->protocol = eth_type_trans(skb, netdev);
  
@@ -177,7 +177,7 @@
  		if (netdev->features & NETIF_F_HW_VLAN_CTAG_RX) {
  			if (MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_RX_V2)) {
  				if (trxd.rxd3 & RX_DMA_VTAG_V2)
-@@ -3735,7 +3749,7 @@ static int mtk_stop(struct net_device *dev)
+@@ -4177,7 +4191,7 @@ static int mtk_stop(struct net_device *dev)
  	mtk_dma_free(eth);
  
  	if (eth->soc->offload_version)
@@ -186,7 +186,7 @@
  
  	return 0;
  }
-@@ -5044,6 +5058,22 @@ static int mtk_probe(struct platform_device *pdev)
+@@ -5560,6 +5574,22 @@ static int mtk_probe(struct platform_device *pdev)
  		}
  	}
  
@@ -208,8 +208,8 @@
 +
  	if (MTK_HAS_CAPS(eth->soc->caps, MTK_PDMA_INT)) {
  		for (i = 0; i < MTK_PDMA_IRQ_NUM; i++)
- 
-@@ -5170,10 +5200,11 @@ static int mtk_probe(struct platform_device *pdev)
+ 			eth->irq_pdma[i] = platform_get_irq(pdev, i);
+@@ -5720,10 +5750,11 @@ static int mtk_probe(struct platform_device *pdev)
  	}
  
  	if (eth->soc->offload_version) {
@@ -227,10 +227,10 @@
 diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.h b/drivers/net/ethernet/mediatek/mtk_eth_soc.h
 old mode 100755
 new mode 100644
-index a87e46d..15337d3
+index 4d3a63c..00cfe3b
 --- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h
 +++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h
-@@ -578,6 +578,9 @@
+@@ -615,6 +615,9 @@
  #define RX_DMA_SPORT_MASK       0x7
  #define RX_DMA_SPORT_MASK_V2    0xf
  
@@ -240,7 +240,7 @@
  /* QDMA descriptor txd4 */
  #define TX_DMA_CHKSUM		(0x7 << 29)
  #define TX_DMA_TSO		BIT(28)
-@@ -1859,7 +1862,7 @@ struct mtk_eth {
+@@ -1924,7 +1927,7 @@ struct mtk_eth {
  	spinlock_t			syscfg0_lock;
  	struct timer_list		mtk_dma_monitor_timer;
  
@@ -252,7 +252,7 @@
 diff --git a/drivers/net/ethernet/mediatek/mtk_ppe.c b/drivers/net/ethernet/mediatek/mtk_ppe.c
 old mode 100644
 new mode 100755
-index 27b5be5..86741bf
+index 6965d98..eeaec1b
 --- a/drivers/net/ethernet/mediatek/mtk_ppe.c
 +++ b/drivers/net/ethernet/mediatek/mtk_ppe.c
 @@ -6,9 +6,22 @@
@@ -1262,10 +1262,10 @@
  	return rhashtable_init(&eth->flow_table, &mtk_flow_ht_params);
 diff --git a/drivers/net/ethernet/mediatek/mtk_wed.c b/drivers/net/ethernet/mediatek/mtk_wed.c
 new file mode 100644
-index 0000000..ea1cbdf
+index 0000000..affa704
 --- /dev/null
 +++ b/drivers/net/ethernet/mediatek/mtk_wed.c
-@@ -0,0 +1,876 @@
+@@ -0,0 +1,881 @@
 +// SPDX-License-Identifier: GPL-2.0-only
 +/* Copyright (C) 2021 Felix Fietkau <nbd@nbd.name> */
 +
@@ -1413,16 +1413,17 @@
 +
 +		for (s = 0; s < MTK_WED_BUF_PER_PAGE; s++) {
 +			u32 txd_size;
++			u32 ctrl;
 +
 +			txd_size = dev->wlan.init_buf(buf, buf_phys, token++);
 +
-+			desc->buf0 = buf_phys;
-+			desc->buf1 = buf_phys + txd_size;
-+			desc->ctrl = FIELD_PREP(MTK_WDMA_DESC_CTRL_LEN0,
-+						txd_size) |
-+				     FIELD_PREP(MTK_WDMA_DESC_CTRL_LEN1,
-+						MTK_WED_BUF_SIZE - txd_size) |
-+				     MTK_WDMA_DESC_CTRL_LAST_SEG1;
++			desc->buf0 = cpu_to_le32(buf_phys);
++			desc->buf1 = cpu_to_le32(buf_phys + txd_size);
++			ctrl = FIELD_PREP(MTK_WDMA_DESC_CTRL_LEN0, txd_size) |
++			       FIELD_PREP(MTK_WDMA_DESC_CTRL_LEN1,
++					  MTK_WED_BUF_SIZE - txd_size) |
++			       MTK_WDMA_DESC_CTRL_LAST_SEG1;
++			desc->ctrl = cpu_to_le32(ctrl);
 +			desc->info = 0;
 +			desc++;
 +
@@ -1453,12 +1454,14 @@
 +
 +	for (i = 0, page_idx = 0; i < dev->buf_ring.size; i += MTK_WED_BUF_PER_PAGE) {
 +		void *page = page_list[page_idx++];
++		dma_addr_t buf_addr;
 +
 +		if (!page)
 +			break;
 +
-+		dma_unmap_page(dev->hw->dev, desc[i].buf0,
-+			       PAGE_SIZE, DMA_BIDIRECTIONAL);
++		buf_addr = le32_to_cpu(desc[i].buf0);
++		dma_unmap_page(dev->hw->dev, buf_addr, PAGE_SIZE,
++			       DMA_BIDIRECTIONAL);
 +		__free_page(page);
 +	}
 +
@@ -1917,7 +1920,7 @@
 +	 * WDMA RX.
 +	 */
 +
-+	BUG_ON(idx > ARRAY_SIZE(dev->tx_ring));
++	BUG_ON(idx >= ARRAY_SIZE(dev->tx_ring));
 +
 +	if (mtk_wed_ring_alloc(dev, ring, MTK_WED_TX_RING_SIZE))
 +		return -ENOMEM;
@@ -2082,7 +2085,7 @@
 +		return;
 +
 +	regs = syscon_regmap_lookup_by_phandle(np, NULL);
-+	if (!regs)
++	if (IS_ERR(regs))
 +		return;
 +
 +	rcu_assign_pointer(mtk_soc_wed_ops, &wed_ops);
@@ -2093,6 +2096,8 @@
 +		goto unlock;
 +
 +	hw = kzalloc(sizeof(*hw), GFP_KERNEL);
++	if (!hw)
++		goto unlock;
 +	hw->node = np;
 +	hw->regs = regs;
 +	hw->eth = eth;
@@ -2736,10 +2741,10 @@
 +
 +#endif
 diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
-index ef44d9a..59a3e96 100644
+index 44842a2..5305384 100644
 --- a/include/linux/netdevice.h
 +++ b/include/linux/netdevice.h
-@@ -844,6 +844,7 @@ enum net_device_path_type {
+@@ -849,6 +849,7 @@ enum net_device_path_type {
  	DEV_PATH_BRIDGE,
  	DEV_PATH_PPPOE,
  	DEV_PATH_DSA,
@@ -2747,7 +2752,7 @@
  };
  
  struct net_device_path {
-@@ -869,6 +870,12 @@ struct net_device_path {
+@@ -874,6 +875,12 @@ struct net_device_path {
  			int port;
  			u16 proto;
  		} dsa;
@@ -2898,10 +2903,10 @@
 +
 +#endif
 diff --git a/net/core/dev.c b/net/core/dev.c
-index a117bd0..1b6d42b 100644
+index 5bade26..0775e8d 100644
 --- a/net/core/dev.c
 +++ b/net/core/dev.c
-@@ -675,6 +675,10 @@ int dev_fill_forward_path(const struct net_device *dev, const u8 *daddr,
+@@ -758,6 +758,10 @@ int dev_fill_forward_path(const struct net_device *dev, const u8 *daddr,
  		if (WARN_ON_ONCE(last_dev == ctx.dev))
  			return -1;
  	}
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/flow_patch/999-3004-ethernet-update-ppe-from-netsys1-to-netsys2.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/flow_patch/999-3004-ethernet-update-ppe-from-netsys1-to-netsys2.patch
index d613ce8..9f22f37 100644
--- a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/flow_patch/999-3004-ethernet-update-ppe-from-netsys1-to-netsys2.patch
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/flow_patch/999-3004-ethernet-update-ppe-from-netsys1-to-netsys2.patch
@@ -1,51 +1,50 @@
-From 3562f05aedc6c2d793b34b3ee3eb78e8352804c8 Mon Sep 17 00:00:00 2001
-From: Sujuan Chen <sujuan.chen@mediatek.com>
-Date: Mon, 18 Sep 2023 10:58:32 +0800
-Subject: [PATCH 05/22] ethernet update ppe from mt7622 to mt7986
+From 07a3ac0ae724c4df67316e01b03432d8ee9f4229 Mon Sep 17 00:00:00 2001
+From: Bo-Cun Chen <bc-bocun.chen@mediatek.com>
+Date: Mon, 18 Mar 2024 17:56:01 +0800
+Subject: [PATCH 04/24] ethernet update ppe from netsys1 to netsys2
 
 ---
- drivers/net/ethernet/mediatek/mtk_eth_soc.c   | 14 ++++-
+ drivers/net/ethernet/mediatek/mtk_eth_soc.c   | 19 ++++---
  drivers/net/ethernet/mediatek/mtk_eth_soc.h   |  7 ++-
  drivers/net/ethernet/mediatek/mtk_ppe.c       | 29 +++++++++--
  drivers/net/ethernet/mediatek/mtk_ppe.h       | 51 +++++++++++++++++++
  .../net/ethernet/mediatek/mtk_ppe_offload.c   |  8 +++
  drivers/net/ethernet/mediatek/mtk_ppe_regs.h  | 10 ++++
- 6 files changed, 113 insertions(+), 6 deletions(-)
+ 6 files changed, 112 insertions(+), 12 deletions(-)
 
 diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.c b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
-index 88b38e2..bfda873 100644
+index ffaa515..9262227 100644
 --- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c
 +++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
-@@ -2285,16 +2285,27 @@ static int mtk_poll_rx(struct napi_struct *napi, int budget,
+@@ -2447,16 +2447,20 @@ static int mtk_poll_rx(struct napi_struct *napi, int budget,
  			skb_checksum_none_assert(skb);
  		skb->protocol = eth_type_trans(skb, netdev);
  
--		hash = trxd.rxd4 & MTK_RXD4_FOE_ENTRY;
 +#if defined(CONFIG_MEDIATEK_NETSYS_RX_V2)
-+			hash = trxd.rxd5 & MTK_RXD5_FOE_ENTRY_V2;
-+#else
-+			hash = trxd.rxd4 & MTK_RXD4_FOE_ENTRY;
-+#endif
- 		if (hash != MTK_RXD4_FOE_ENTRY) {
- 			hash = jhash_1word(hash, 0);
- 			skb_set_hash(skb, hash, PKT_HASH_TYPE_L4);
- 		}
- 
-+#if defined(CONFIG_MEDIATEK_NETSYS_RX_V2)
++		hash = trxd.rxd5 & MTK_RXD5_FOE_ENTRY_V2;
 +		reason = FIELD_GET(MTK_RXD5_PPE_CPU_REASON_V2, trxd.rxd5);
-+		if (reason == MTK_PPE_CPU_REASON_HIT_UNBIND_RATE_REACHED)
-+			mtk_ppe_check_skb(eth->ppe, skb,
-+					  trxd.rxd5 & MTK_RXD5_FOE_ENTRY_V2);
++		if (hash != MTK_RXD5_FOE_ENTRY_V2)
++			skb_set_hash(skb, jhash_1word(hash, 0), PKT_HASH_TYPE_L4);
 +#else
+ 		hash = trxd.rxd4 & MTK_RXD4_FOE_ENTRY;
+-		if (hash != MTK_RXD4_FOE_ENTRY) {
+-			hash = jhash_1word(hash, 0);
+-			skb_set_hash(skb, hash, PKT_HASH_TYPE_L4);
+-		}
+-
  		reason = FIELD_GET(MTK_RXD4_PPE_CPU_REASON, trxd.rxd4);
- 		if (reason == MTK_PPE_CPU_REASON_HIT_UNBIND_RATE_REACHED)
- 			mtk_ppe_check_skb(eth->ppe, skb,
- 					  trxd.rxd4 & MTK_RXD4_FOE_ENTRY);
++		if (hash != MTK_RXD4_FOE_ENTRY)
++			skb_set_hash(skb, jhash_1word(hash, 0), PKT_HASH_TYPE_L4);
 +#endif
++
+ 		if (reason == MTK_PPE_CPU_REASON_HIT_UNBIND_RATE_REACHED)
+-			mtk_ppe_check_skb(eth->ppe, skb,
+-					  trxd.rxd4 & MTK_RXD4_FOE_ENTRY);
++			mtk_ppe_check_skb(eth->ppe, skb, hash);
  
  		if (netdev->features & NETIF_F_HW_VLAN_CTAG_RX) {
  			if (MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_RX_V2)) {
-@@ -5396,6 +5407,7 @@ static const struct mtk_soc_data mt7986_data = {
+@@ -5957,6 +5961,7 @@ static const struct mtk_soc_data mt7986_data = {
  	.required_clks = MT7986_CLKS_BITMAP,
  	.required_pctl = false,
  	.has_sram = false,
@@ -54,10 +53,10 @@
  	.txrx = {
  		.txd_size = sizeof(struct mtk_tx_dma_v2),
 diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.h b/drivers/net/ethernet/mediatek/mtk_eth_soc.h
-index 15337d3..a385df5 100644
+index 41daeb2..910baaf 100644
 --- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h
 +++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h
-@@ -130,7 +130,7 @@
+@@ -137,7 +137,7 @@
  #define MTK_GDMA_UCS_EN		BIT(20)
  #define MTK_GDMA_STRP_CRC	BIT(16)
  #define MTK_GDMA_TO_PDMA	0x0
@@ -66,7 +65,7 @@
  #define MTK_GDMA_DROP_ALL	0x7777
  
  /* GDM Egress Control Register */
-@@ -630,6 +630,11 @@
+@@ -680,6 +680,11 @@
  #define MTK_RXD4_SRC_PORT	GENMASK(21, 19)
  #define MTK_RXD4_ALG		GENMASK(31, 22)
  
@@ -79,7 +78,7 @@
  #define RX_DMA_L4_VALID		BIT(24)
  #define RX_DMA_L4_VALID_PDMA	BIT(30)		/* when PDMA is used */
 diff --git a/drivers/net/ethernet/mediatek/mtk_ppe.c b/drivers/net/ethernet/mediatek/mtk_ppe.c
-index 86741bf..ef8acbc 100755
+index eeaec1b..e195fb3 100755
 --- a/drivers/net/ethernet/mediatek/mtk_ppe.c
 +++ b/drivers/net/ethernet/mediatek/mtk_ppe.c
 @@ -122,7 +122,7 @@ static u32 mtk_ppe_hash_entry(struct mtk_foe_entry *e)
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/flow_patch/999-3005-flow-offload-add-mkhnat-dual-ppe-new-v2.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/flow_patch/999-3005-flow-offload-add-mkhnat-dual-ppe-new-v2.patch
index 8d605e0..5ff363b 100644
--- a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/flow_patch/999-3005-flow-offload-add-mkhnat-dual-ppe-new-v2.patch
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/flow_patch/999-3005-flow-offload-add-mkhnat-dual-ppe-new-v2.patch
@@ -1,25 +1,25 @@
-From 806bb7d1a0a44a92101c506564a41dc6c4b68fd0 Mon Sep 17 00:00:00 2001
+From 01556d88ad11f0d096d2816b2a69999994e1740f Mon Sep 17 00:00:00 2001
 From: Bo-Cun Chen <bc-bocun.chen@mediatek.com>
-Date: Tue, 26 Dec 2023 16:31:34 +0800
-Subject: [PATCH 06/22] flow-offload-add-mkhnat-dual-ppe-new-v2
+Date: Mon, 18 Mar 2024 16:26:28 +0800
+Subject: [PATCH 05/24] flow-offload-add-mkhnat-dual-ppe-new-v2
 
 ---
  arch/arm64/boot/dts/mediatek/mt7986a.dtsi     |  1 +
- drivers/net/ethernet/mediatek/mtk_eth_soc.c   | 58 ++++++++++++++-----
- drivers/net/ethernet/mediatek/mtk_eth_soc.h   | 14 ++++-
+ drivers/net/ethernet/mediatek/mtk_eth_soc.c   | 50 ++++++++++++++-----
+ drivers/net/ethernet/mediatek/mtk_eth_soc.h   | 14 ++++--
  drivers/net/ethernet/mediatek/mtk_ppe.c       |  5 +-
  drivers/net/ethernet/mediatek/mtk_ppe.h       |  7 ++-
- .../net/ethernet/mediatek/mtk_ppe_debugfs.c   | 27 ++++++---
- .../net/ethernet/mediatek/mtk_ppe_offload.c   | 48 +++++++++++----
+ .../net/ethernet/mediatek/mtk_ppe_debugfs.c   | 27 +++++++---
+ .../net/ethernet/mediatek/mtk_ppe_offload.c   | 48 ++++++++++++++----
  include/linux/netdevice.h                     |  4 ++
- 8 files changed, 124 insertions(+), 40 deletions(-)
+ 8 files changed, 119 insertions(+), 37 deletions(-)
  mode change 100644 => 100755 drivers/net/ethernet/mediatek/mtk_ppe_offload.c
 
 diff --git a/arch/arm64/boot/dts/mediatek/mt7986a.dtsi b/arch/arm64/boot/dts/mediatek/mt7986a.dtsi
-index e5d4e12..0c54e12 100644
+index 3a4f279..d70151b 100644
 --- a/arch/arm64/boot/dts/mediatek/mt7986a.dtsi
 +++ b/arch/arm64/boot/dts/mediatek/mt7986a.dtsi
-@@ -496,6 +496,7 @@
+@@ -483,6 +483,7 @@
                  mediatek,ethsys = <&ethsys>;
  		mediatek,sgmiisys = <&sgmiisys0>, <&sgmiisys1>;
  		mediatek,wed = <&wed0>, <&wed1>;
@@ -28,31 +28,19 @@
                  #address-cells = <1>;
                  #size-cells = <0>;
 diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.c b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
-index bfda873..ee5e0c6 100644
+index 2fb67e0..7eeddb3 100644
 --- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c
 +++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
-@@ -2276,14 +2276,16 @@ static int mtk_poll_rx(struct napi_struct *napi, int budget,
- 
- #if defined(CONFIG_MEDIATEK_NETSYS_RX_V2)
- 		reason = FIELD_GET(MTK_RXD5_PPE_CPU_REASON_V2, trxd.rxd5);
--		if (reason == MTK_PPE_CPU_REASON_HIT_UNBIND_RATE_REACHED)
--			mtk_ppe_check_skb(eth->ppe, skb,
-+		if (reason == MTK_PPE_CPU_REASON_HIT_UNBIND_RATE_REACHED) {
-+			mtk_ppe_check_skb(eth->ppe[0], skb,
- 					  trxd.rxd5 & MTK_RXD5_FOE_ENTRY_V2);
-+		}
- #else
- 		reason = FIELD_GET(MTK_RXD4_PPE_CPU_REASON, trxd.rxd4);
--		if (reason == MTK_PPE_CPU_REASON_HIT_UNBIND_RATE_REACHED)
--			mtk_ppe_check_skb(eth->ppe, skb,
-+		if (reason == MTK_PPE_CPU_REASON_HIT_UNBIND_RATE_REACHED) {
-+			mtk_ppe_check_skb(eth->ppe[0], skb,
- 					  trxd.rxd4 & MTK_RXD4_FOE_ENTRY);
-+		}
+@@ -2464,7 +2464,7 @@ static int mtk_poll_rx(struct napi_struct *napi, int budget,
  #endif
  
+ 		if (reason == MTK_PPE_CPU_REASON_HIT_UNBIND_RATE_REACHED)
+-			mtk_ppe_check_skb(eth->ppe, skb, hash);
++			mtk_ppe_check_skb(eth->ppe[0], skb, hash);
+ 
  		if (netdev->features & NETIF_F_HW_VLAN_CTAG_RX) {
-@@ -3676,8 +3683,12 @@ static int mtk_open(struct net_device *dev)
+ 			if (MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_RX_V2)) {
+@@ -4112,8 +4112,12 @@ static int mtk_open(struct net_device *dev)
  		regmap_write(eth->sgmii->pcs[id].regmap,
  			     SGMSYS_QPHY_PWR_STATE_CTRL, 0);
  
@@ -67,7 +55,7 @@
  
  	mtk_gdm_config(eth, mac->id, gdm_config);
  
-@@ -3759,8 +3770,10 @@ static int mtk_stop(struct net_device *dev)
+@@ -4202,8 +4206,10 @@ static int mtk_stop(struct net_device *dev)
  
  	mtk_dma_free(eth);
  
@@ -80,7 +68,7 @@
  
  	return 0;
  }
-@@ -5211,15 +5224,35 @@ static int mtk_probe(struct platform_device *pdev)
+@@ -5762,15 +5768,35 @@ static int mtk_probe(struct platform_device *pdev)
  	}
  
  	if (eth->soc->offload_version) {
@@ -124,10 +112,10 @@
  
  	for (i = 0; i < MTK_MAX_DEVS; i++) {
 diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.h b/drivers/net/ethernet/mediatek/mtk_eth_soc.h
-index a385df5..783166d 100644
+index 910baaf..3995608 100644
 --- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h
 +++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h
-@@ -130,7 +130,12 @@
+@@ -137,7 +137,12 @@
  #define MTK_GDMA_UCS_EN		BIT(20)
  #define MTK_GDMA_STRP_CRC	BIT(16)
  #define MTK_GDMA_TO_PDMA	0x0
@@ -141,7 +129,7 @@
  #define MTK_GDMA_DROP_ALL	0x7777
  
  /* GDM Egress Control Register */
-@@ -1867,7 +1872,8 @@ struct mtk_eth {
+@@ -1936,7 +1941,8 @@ struct mtk_eth {
  	spinlock_t			syscfg0_lock;
  	struct timer_list		mtk_dma_monitor_timer;
  
@@ -151,7 +139,7 @@
  	struct rhashtable		flow_table;
  };
  
-@@ -1949,9 +1955,11 @@ int mtk_toprgu_init(struct mtk_eth *eth, struct device_node *r);
+@@ -2019,9 +2025,11 @@ int mtk_toprgu_init(struct mtk_eth *eth, struct device_node *r);
  int mtk_dump_usxgmii(struct regmap *pmap, char *name, u32 offset, u32 range);
  void mtk_usxgmii_link_poll(struct work_struct *work);
  
@@ -165,7 +153,7 @@
 +int mtk_ppe_debugfs_init(struct mtk_eth *eth);
  #endif /* MTK_ETH_H */
 diff --git a/drivers/net/ethernet/mediatek/mtk_ppe.c b/drivers/net/ethernet/mediatek/mtk_ppe.c
-index ef8acbc..96c15b3 100755
+index e195fb3..c9ee505 100755
 --- a/drivers/net/ethernet/mediatek/mtk_ppe.c
 +++ b/drivers/net/ethernet/mediatek/mtk_ppe.c
 @@ -696,7 +696,7 @@ int mtk_foe_entry_idle_time(struct mtk_ppe *ppe, struct mtk_flow_entry *entry)
@@ -449,10 +437,10 @@
  
  	return rhashtable_init(&eth->flow_table, &mtk_flow_ht_params);
 diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
-index 59a3e96..0967dc2 100644
+index 5305384..b2abebe 100644
 --- a/include/linux/netdevice.h
 +++ b/include/linux/netdevice.h
-@@ -1311,6 +1311,8 @@ struct tlsdev_ops;
+@@ -1316,6 +1316,8 @@ struct tlsdev_ops;
   *	rtnl_lock is not held.
   * int (*ndo_fill_forward_path)(struct net_device_path_ctx *ctx, struct net_device_path *path);
   *     Get the forwarding path to reach the real device from the HW destination address
@@ -461,7 +449,7 @@
   */
  struct net_device_ops {
  	int			(*ndo_init)(struct net_device *dev);
-@@ -1510,6 +1512,8 @@ struct net_device_ops {
+@@ -1515,6 +1517,8 @@ struct net_device_ops {
  	struct devlink_port *	(*ndo_get_devlink_port)(struct net_device *dev);
  	int                     (*ndo_fill_forward_path)(struct net_device_path_ctx *ctx,
                                                           struct net_device_path *path);
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/flow_patch/999-3006-add-wed-tx-support-for-netsys2.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/flow_patch/999-3006-add-wed-tx-support-for-netsys2.patch
index 5cfedfc..5197d21 100644
--- a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/flow_patch/999-3006-add-wed-tx-support-for-netsys2.patch
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/flow_patch/999-3006-add-wed-tx-support-for-netsys2.patch
@@ -1,23 +1,23 @@
-From d76914437a405265b298b7b01235a7304634c567 Mon Sep 17 00:00:00 2001
+From 56e9bf306919ffb33d45951541d908cd7d21c081 Mon Sep 17 00:00:00 2001
 From: Bo Jiao <Bo.Jiao@mediatek.com>
 Date: Mon, 18 Sep 2023 11:01:55 +0800
-Subject: [PATCH] add-wed-tx-support-for-mt7986
+Subject: [PATCH 06/24] add-wed-tx-support-for-netsys2
 
 ---
  arch/arm64/boot/dts/mediatek/mt7981.dtsi      |   1 +
- arch/arm64/boot/dts/mediatek/mt7986a.dtsi     |   2 +
- arch/arm64/boot/dts/mediatek/mt7986b.dtsi     |   2 +
- drivers/net/ethernet/mediatek/mtk_eth_soc.c   |  17 +-
- drivers/net/ethernet/mediatek/mtk_eth_soc.h   |   5 +
- drivers/net/ethernet/mediatek/mtk_wed.c       | 498 +++++++++++++-----
- drivers/net/ethernet/mediatek/mtk_wed.h       |  18 +-
+ arch/arm64/boot/dts/mediatek/mt7986a.dtsi     |   6 +-
+ arch/arm64/boot/dts/mediatek/mt7986b.dtsi     |   6 +-
+ drivers/net/ethernet/mediatek/mtk_eth_soc.c   |  41 +-
+ drivers/net/ethernet/mediatek/mtk_eth_soc.h   |   3 -
+ drivers/net/ethernet/mediatek/mtk_wed.c       | 525 +++++++++++++-----
+ drivers/net/ethernet/mediatek/mtk_wed.h       |  21 +-
  .../net/ethernet/mediatek/mtk_wed_debugfs.c   |   3 +
- drivers/net/ethernet/mediatek/mtk_wed_regs.h  | 130 ++++-
- include/linux/soc/mediatek/mtk_wed.h          |  23 +
- 10 files changed, 549 insertions(+), 150 deletions(-)
+ drivers/net/ethernet/mediatek/mtk_wed_regs.h  | 111 +++-
+ include/linux/soc/mediatek/mtk_wed.h          |  21 +-
+ 10 files changed, 575 insertions(+), 163 deletions(-)
 
 diff --git a/arch/arm64/boot/dts/mediatek/mt7981.dtsi b/arch/arm64/boot/dts/mediatek/mt7981.dtsi
-index e1b9b2c..3e0d2c0 100644
+index 283421a..cb8f4e1 100644
 --- a/arch/arm64/boot/dts/mediatek/mt7981.dtsi
 +++ b/arch/arm64/boot/dts/mediatek/mt7981.dtsi
 @@ -96,6 +96,7 @@
@@ -29,7 +29,7 @@
  
  	ap2woccif: ap2woccif@151A5000 {
 diff --git a/arch/arm64/boot/dts/mediatek/mt7986a.dtsi b/arch/arm64/boot/dts/mediatek/mt7986a.dtsi
-index 7e3101c..e9756bd 100644
+index d70151b..9c288fc 100644
 --- a/arch/arm64/boot/dts/mediatek/mt7986a.dtsi
 +++ b/arch/arm64/boot/dts/mediatek/mt7986a.dtsi
 @@ -64,6 +64,7 @@
@@ -48,8 +48,26 @@
  	};
  
  	ap2woccif: ap2woccif@151A5000 {
+@@ -482,6 +484,7 @@
+ 					 <&topckgen CK_TOP_CB_SGM_325M>;
+                 mediatek,ethsys = <&ethsys>;
+ 		mediatek,sgmiisys = <&sgmiisys0>, <&sgmiisys1>;
++		mediatek,wed-pcie = <&wed_pcie>;
+ 		mediatek,wed = <&wed0>, <&wed1>;
+                 mtketh-ppe-num = <2>;
+                 #reset-cells = <1>;
+@@ -549,7 +552,8 @@
+ 	};
+ 
+ 	wed_pcie: wed_pcie@10003000 {
+-		compatible = "mediatek,wed_pcie";
++		compatible = "mediatek,wed_pcie",
++			     "syscon";
+ 		reg = <0 0x10003000 0 0x10>;
+ 	};
+ 
 diff --git a/arch/arm64/boot/dts/mediatek/mt7986b.dtsi b/arch/arm64/boot/dts/mediatek/mt7986b.dtsi
-index a780cfb..eafe314 100644
+index ce884f0..02feaa9 100644
 --- a/arch/arm64/boot/dts/mediatek/mt7986b.dtsi
 +++ b/arch/arm64/boot/dts/mediatek/mt7986b.dtsi
 @@ -64,6 +64,7 @@
@@ -68,11 +86,29 @@
  	};
  
  	ap2woccif: ap2woccif@151A5000 {
+@@ -396,6 +398,7 @@
+ 					 <&topckgen CK_TOP_CB_SGM_325M>;
+                 mediatek,ethsys = <&ethsys>;
+ 		mediatek,sgmiisys = <&sgmiisys0>, <&sgmiisys1>;
++		mediatek,wed-pcie = <&wed_pcie>;
+ 		mediatek,wed = <&wed0>, <&wed1>;
+                 #reset-cells = <1>;
+                 #address-cells = <1>;
+@@ -462,7 +465,8 @@
+ 	};
+ 
+ 	wed_pcie: wed_pcie@10003000 {
+-		compatible = "mediatek,wed_pcie";
++		compatible = "mediatek,wed_pcie",
++			     "syscon";
+ 		reg = <0 0x10003000 0 0x10>;
+ 	};
+ 
 diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.c b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
-index 3685926..51fe4b3 100644
+index 07209f0..268c9e7 100644
 --- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c
 +++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
-@@ -5091,6 +5091,7 @@ static int mtk_probe(struct platform_device *pdev)
+@@ -5476,6 +5476,7 @@ static int mtk_probe(struct platform_device *pdev)
  {
  	struct device_node *mac_np, *mux_np;
  	struct mtk_eth *eth;
@@ -80,8 +116,8 @@
  	int err, i;
  
  	eth = devm_kzalloc(&pdev->dev, sizeof(*eth), GFP_KERNEL);
-@@ -5111,13 +5112,12 @@ static int mtk_probe(struct platform_device *pdev)
- 			return PTR_ERR(eth->sram_base);
+@@ -5498,13 +5499,12 @@ static int mtk_probe(struct platform_device *pdev)
+ 		eth->sram_base = (void __force *)eth->base + MTK_ETH_SRAM_OFFSET;
  	}
  
 -	if(eth->soc->has_sram) {
@@ -93,49 +129,66 @@
 +	if (unlikely(!res))
 +		return -EINVAL;
 +
-+	if(eth->soc->has_sram)
++	if (eth->soc->has_sram)
  		eth->phy_scratch_ring = res->start + MTK_ETH_SRAM_OFFSET;
 -	}
  
  	mtk_get_hwver(eth);
  
+@@ -5593,20 +5593,25 @@ static int mtk_probe(struct platform_device *pdev)
+ 		}
+ 	}
+ 
-@@ -5213,12 +5213,15 @@ static int mtk_probe(struct platform_device *pdev)
- 			MTK_WDMA1_BASE
- 		};
- 		void __iomem *wdma;
-+		u32 wdma_phy;
+-	for (i = 0;; i++) {
+-		struct device_node *np = of_parse_phandle(pdev->dev.of_node,
+-							  "mediatek,wed", i);
+-		static const u32 wdma_regs[] = {
+-			MTK_WDMA0_BASE,
+-			MTK_WDMA1_BASE
+-		};
+-		void __iomem *wdma;
++	if (eth->soc->offload_version) {
++		for (i = 0;; i++) {
++			struct device_node *np;
++			phys_addr_t wdma_phy;
++			u32 wdma_base;
  
- 		if (!np || i >= ARRAY_SIZE(wdma_regs))
- 			break;
+-		if (!np || i >= ARRAY_SIZE(wdma_regs))
+-			break;
++			if (i >= ARRAY_SIZE(eth->soc->reg_map->wdma_base))
++				break;
  
- 		wdma = eth->base + wdma_regs[i];
+-		wdma = eth->base + wdma_regs[i];
 -		mtk_wed_add_hw(np, eth, wdma, i);
-+		wdma_phy = res->start + wdma_regs[i];
++			np = of_parse_phandle(pdev->dev.of_node,
++					      "mediatek,wed", i);
++			if (!np)
++				break;
 +
-+		mtk_wed_add_hw(np, eth, wdma, wdma_phy, i);
++			wdma_base = eth->soc->reg_map->wdma_base[i];
++			wdma_phy = res ? res->start + wdma_base : 0;
++			mtk_wed_add_hw(np, eth, eth->base + wdma_base,
++				       wdma_phy, i);
++		}
  	}
  
  	if (MTK_HAS_CAPS(eth->soc->caps, MTK_PDMA_INT)) {
 diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.h b/drivers/net/ethernet/mediatek/mtk_eth_soc.h
-index b714c27..e9d88f1 100644
+index a00583f..9099dea 100644
 --- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h
 +++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h
-@@ -593,8 +593,13 @@
+@@ -620,9 +620,6 @@
  #define RX_DMA_SPORT_MASK       0x7
  #define RX_DMA_SPORT_MASK_V2    0xf
  
-+#if defined(CONFIG_MEDIATEK_NETSYS_V2)
-+#define MTK_WDMA0_BASE		0x4800
-+#define MTK_WDMA1_BASE		0x4c00
-+#else
- #define MTK_WDMA0_BASE		0x2800
- #define MTK_WDMA1_BASE		0x2c00
-+#endif
- 
+-#define MTK_WDMA0_BASE		0x2800
+-#define MTK_WDMA1_BASE		0x2c00
+-
  /* QDMA descriptor txd4 */
  #define TX_DMA_CHKSUM		(0x7 << 29)
+ #define TX_DMA_TSO		BIT(28)
 diff --git a/drivers/net/ethernet/mediatek/mtk_wed.c b/drivers/net/ethernet/mediatek/mtk_wed.c
-index ea1cbdf..948f013 100644
+index affa704..02e06a8 100644
 --- a/drivers/net/ethernet/mediatek/mtk_wed.c
 +++ b/drivers/net/ethernet/mediatek/mtk_wed.c
 @@ -18,15 +18,6 @@
@@ -154,37 +207,44 @@
  static struct mtk_wed_hw *hw_list[2];
  static DEFINE_MUTEX(hw_lock);
  
-@@ -80,14 +71,19 @@ mtk_wed_reset(struct mtk_wed_device *dev, u32 mask)
- static struct mtk_wed_hw *
+@@ -81,11 +72,31 @@ static struct mtk_wed_hw *
  mtk_wed_assign(struct mtk_wed_device *dev)
  {
--	struct mtk_wed_hw *hw;
+ 	struct mtk_wed_hw *hw;
 +	int i;
 +
-+	for (i = 0; i < ARRAY_SIZE(hw_list); i++) {
-+		struct mtk_wed_hw *hw = hw_list[i];
++	if (dev->wlan.bus_type == MTK_WED_BUS_PCIE) {
++		hw = hw_list[pci_domain_nr(dev->wlan.pci_dev->bus)];
++		if (!hw)
++			return NULL;
 +
-+		if (!hw || hw->wed_dev)
-+			continue;
++		if (!hw->wed_dev)
++			goto out;
++
++		if (hw->version == 1)
++			return NULL;
++
++		/* MT7986 WED devices do not have any pcie slot restrictions */
++	}
++	/* MT7986 PCIE or AXI */
++	for (i = 0; i < ARRAY_SIZE(hw_list); i++) {
++		hw = hw_list[i];
++		if (hw && !hw->wed_dev)
++			goto out;
++	}
  
 -	hw = hw_list[pci_domain_nr(dev->wlan.pci_dev->bus)];
 -	if (!hw || hw->wed_dev)
 -		return NULL;
-+		hw->wed_dev = dev;
-+		return hw;
-+	}
- 
--	hw->wed_dev = dev;
--	return hw;
 +	return NULL;
- }
  
- static int
-@@ -96,19 +92,27 @@ mtk_wed_buffer_alloc(struct mtk_wed_device *dev)
- 	struct mtk_wdma_desc *desc;
++out:
+ 	hw->wed_dev = dev;
+ 	return hw;
+ }
+@@ -97,11 +108,16 @@ mtk_wed_buffer_alloc(struct mtk_wed_device *dev)
  	dma_addr_t desc_phys;
  	void **page_list;
-+	u32 last_seg = MTK_WDMA_DESC_CTRL_LAST_SEG1;
  	int token = dev->wlan.token_start;
 -	int ring_size;
 -	int n_pages;
@@ -193,130 +253,65 @@
 +	int i;
 +
 +
-+	if (dev->ver == MTK_WED_V1) {
++	if (dev->hw->version == 1)
 +		ring_size = dev->wlan.nbuf & ~(MTK_WED_BUF_PER_PAGE - 1);
-+	} else {
++	else
 +		ring_size = MTK_WED_VLD_GROUP_SIZE * MTK_WED_PER_GROUP_PKT +
 +			    MTK_WED_WDMA_RING_SIZE * 2;
-+		last_seg = MTK_WDMA_DESC_CTRL_LAST_SEG0;
-+	}
  
 -	ring_size = dev->wlan.nbuf & ~(MTK_WED_BUF_PER_PAGE - 1);
  	n_pages = ring_size / MTK_WED_BUF_PER_PAGE;
  
  	page_list = kcalloc(n_pages, sizeof(*page_list), GFP_KERNEL);
- 	if (!page_list)
- 		return -ENOMEM;
- 
--	dev->buf_ring.size = ring_size;
-+	dev->buf_ring.size = dev->wlan.nbuf & ~(MTK_WED_BUF_PER_PAGE - 1);
- 	dev->buf_ring.pages = page_list;
+@@ -151,10 +167,17 @@ mtk_wed_buffer_alloc(struct mtk_wed_device *dev)
  
- 	desc = dma_alloc_coherent(dev->hw->dev, ring_size * sizeof(*desc),
-@@ -154,7 +158,7 @@ mtk_wed_buffer_alloc(struct mtk_wed_device *dev)
- 						txd_size) |
- 				     FIELD_PREP(MTK_WDMA_DESC_CTRL_LEN1,
- 						MTK_WED_BUF_SIZE - txd_size) |
--				     MTK_WDMA_DESC_CTRL_LAST_SEG1;
-+						last_seg;
+ 			desc->buf0 = cpu_to_le32(buf_phys);
+ 			desc->buf1 = cpu_to_le32(buf_phys + txd_size);
+-			ctrl = FIELD_PREP(MTK_WDMA_DESC_CTRL_LEN0, txd_size) |
+-			       FIELD_PREP(MTK_WDMA_DESC_CTRL_LEN1,
+-					  MTK_WED_BUF_SIZE - txd_size) |
+-			       MTK_WDMA_DESC_CTRL_LAST_SEG1;
++
++			if (dev->hw->version == 1)
++				ctrl = FIELD_PREP(MTK_WDMA_DESC_CTRL_LEN0, txd_size) |
++				       FIELD_PREP(MTK_WDMA_DESC_CTRL_LEN1,
++						  MTK_WED_BUF_SIZE - txd_size) |
++				       MTK_WDMA_DESC_CTRL_LAST_SEG1;
++			else
++				ctrl = FIELD_PREP(MTK_WDMA_DESC_CTRL_LEN0, txd_size) |
++				       FIELD_PREP(MTK_WDMA_DESC_CTRL_LEN1_V2,
++						  MTK_WED_BUF_SIZE - txd_size) |
++				       MTK_WDMA_DESC_CTRL_LAST_SEG0;
+ 			desc->ctrl = cpu_to_le32(ctrl);
  			desc->info = 0;
  			desc++;
- 
-@@ -202,12 +206,12 @@ mtk_wed_free_buffer(struct mtk_wed_device *dev)
- }
- 
- static void
--mtk_wed_free_ring(struct mtk_wed_device *dev, struct mtk_wed_ring *ring)
-+mtk_wed_free_ring(struct mtk_wed_device *dev, struct mtk_wed_ring *ring, int scale)
- {
+@@ -210,7 +233,7 @@ mtk_wed_free_ring(struct mtk_wed_device *dev, struct mtk_wed_ring *ring)
  	if (!ring->desc)
  		return;
  
 -	dma_free_coherent(dev->hw->dev, ring->size * sizeof(*ring->desc),
-+	dma_free_coherent(dev->hw->dev, ring->size * sizeof(*ring->desc) * scale,
++	dma_free_coherent(dev->hw->dev, ring->size * ring->desc_size,
  			  ring->desc, ring->desc_phys);
  }
  
-@@ -217,9 +221,69 @@ mtk_wed_free_tx_rings(struct mtk_wed_device *dev)
- 	int i;
+@@ -230,6 +253,9 @@ mtk_wed_set_ext_int(struct mtk_wed_device *dev, bool en)
+ {
+ 	u32 mask = MTK_WED_EXT_INT_STATUS_ERROR_MASK;
  
- 	for (i = 0; i < ARRAY_SIZE(dev->tx_ring); i++)
--		mtk_wed_free_ring(dev, &dev->tx_ring[i]);
-+		mtk_wed_free_ring(dev, &dev->tx_ring[i], 1);
- 	for (i = 0; i < ARRAY_SIZE(dev->tx_wdma); i++)
--		mtk_wed_free_ring(dev, &dev->tx_wdma[i]);
-+		mtk_wed_free_ring(dev, &dev->tx_wdma[i], dev->ver);
-+}
-+
-+static void
-+mtk_wed_set_int(struct mtk_wed_device *dev, u32 irq_mask)
-+{
-+	u32 wdma_mask;
-+
-+	wdma_mask = FIELD_PREP(MTK_WDMA_INT_MASK_RX_DONE, GENMASK(1, 0));
-+
-+	/* wed control cr set */
-+	wed_set(dev, MTK_WED_CTRL,
-+		MTK_WED_CTRL_WDMA_INT_AGENT_EN |
-+		MTK_WED_CTRL_WPDMA_INT_AGENT_EN |
-+		MTK_WED_CTRL_WED_TX_BM_EN |
-+		MTK_WED_CTRL_WED_TX_FREE_AGENT_EN);
-+
-+	if (dev->ver == MTK_WED_V1) {
-+		wed_w32(dev, MTK_WED_PCIE_INT_TRIGGER,
-+			MTK_WED_PCIE_INT_TRIGGER_STATUS);
-+
-+		wed_w32(dev, MTK_WED_WPDMA_INT_TRIGGER,
-+			MTK_WED_WPDMA_INT_TRIGGER_RX_DONE |
-+			MTK_WED_WPDMA_INT_TRIGGER_TX_DONE);
-+
-+		wed_set(dev, MTK_WED_WPDMA_INT_CTRL,
-+			MTK_WED_WPDMA_INT_CTRL_SUBRT_ADV);
-+	} else {
-+		/* initail tx interrupt trigger */
-+		wed_w32(dev, MTK_WED_WPDMA_INT_CTRL_TX,
-+			MTK_WED_WPDMA_INT_CTRL_TX0_DONE_EN |
-+			MTK_WED_WPDMA_INT_CTRL_TX0_DONE_CLR |
-+			MTK_WED_WPDMA_INT_CTRL_TX1_DONE_EN |
-+			MTK_WED_WPDMA_INT_CTRL_TX1_DONE_CLR |
-+			FIELD_PREP(MTK_WED_WPDMA_INT_CTRL_TX0_DONE_TRIG,
-+				   dev->wlan.tx_tbit[0]) |
-+			FIELD_PREP(MTK_WED_WPDMA_INT_CTRL_TX1_DONE_TRIG,
-+				   dev->wlan.tx_tbit[1]));
++	if (dev->hw->version == 1)
++		mask |= MTK_WED_EXT_INT_STATUS_TX_DRV_R_RESP_ERR;
 +
-+		/* initail txfree interrupt trigger */
-+		wed_w32(dev, MTK_WED_WPDMA_INT_CTRL_TX_FREE,
-+			MTK_WED_WPDMA_INT_CTRL_TX_FREE_DONE_EN |
-+			MTK_WED_WPDMA_INT_CTRL_TX_FREE_DONE_CLR |
-+			FIELD_PREP(MTK_WED_WPDMA_INT_CTRL_TX_FREE_DONE_TRIG,
-+				    dev->wlan.txfree_tbit));
-+	}
-+	/* initail wdma interrupt agent */
-+	wed_w32(dev, MTK_WED_WDMA_INT_TRIGGER, wdma_mask);
-+	if (dev->ver == MTK_WED_V1) {
-+		wed_clr(dev, MTK_WED_WDMA_INT_CTRL, wdma_mask);
-+	} else {
-+		wed_w32(dev, MTK_WED_WDMA_INT_CLR, wdma_mask);
-+		wed_set(dev, MTK_WED_WDMA_INT_CTRL,
-+			FIELD_PREP(MTK_WED_WDMA_INT_POLL_SRC_SEL,dev->wdma_idx));
-+
-+	}
-+
-+	wdma_w32(dev, MTK_WDMA_INT_MASK, wdma_mask);
-+	wdma_w32(dev, MTK_WDMA_INT_GRP2, wdma_mask);
-+	wed_w32(dev, MTK_WED_WPDMA_INT_MASK, irq_mask);
-+	wed_w32(dev, MTK_WED_INT_MASK, irq_mask);
- }
+ 	if (!dev->hw->num_flows)
+ 		mask &= ~MTK_WED_EXT_INT_STATUS_TKID_WO_PYLD;
  
- static void
-@@ -234,10 +298,95 @@ mtk_wed_set_ext_int(struct mtk_wed_device *dev, bool en)
+@@ -237,10 +263,57 @@ mtk_wed_set_ext_int(struct mtk_wed_device *dev, bool en)
  	wed_r32(dev, MTK_WED_EXT_INT_MASK);
  }
  
 +static void
-+mtk_wed_set_512_support(struct mtk_wed_device *dev, bool en)
++mtk_wed_set_512_support(struct mtk_wed_device *dev, bool enable)
 +{
-+	if (en) {
++	if (enable) {
 +		wed_w32(dev, MTK_WED_TXDP_CTRL, MTK_WED_TXDP_DW9_OVERWR);
 +		wed_w32(dev, MTK_WED_TXP_DW1,
 +			FIELD_PREP(MTK_WED_WPDMA_WRITE_TXP, 0x0103));
@@ -328,43 +323,6 @@
 +}
 +
 +static void
-+mtk_wed_dma_enable(struct mtk_wed_device *dev)
-+{
-+	wed_set(dev, MTK_WED_WPDMA_INT_CTRL,
-+		MTK_WED_WPDMA_INT_CTRL_SUBRT_ADV);
-+
-+	wed_set(dev, MTK_WED_GLO_CFG,
-+		MTK_WED_GLO_CFG_TX_DMA_EN |
-+		MTK_WED_GLO_CFG_RX_DMA_EN);
-+	wed_set(dev, MTK_WED_WPDMA_GLO_CFG,
-+		MTK_WED_WPDMA_GLO_CFG_TX_DRV_EN |
-+		MTK_WED_WPDMA_GLO_CFG_RX_DRV_EN);
-+	wed_set(dev, MTK_WED_WDMA_GLO_CFG,
-+		MTK_WED_WDMA_GLO_CFG_RX_DRV_EN);
-+
-+	wdma_set(dev, MTK_WDMA_GLO_CFG,
-+		 MTK_WDMA_GLO_CFG_TX_DMA_EN |
-+		 MTK_WDMA_GLO_CFG_RX_INFO1_PRERES |
-+		 MTK_WDMA_GLO_CFG_RX_INFO2_PRERES);
-+
-+	if (dev->ver == MTK_WED_V1) {
-+		wdma_set(dev, MTK_WDMA_GLO_CFG,
-+			 MTK_WDMA_GLO_CFG_RX_INFO3_PRERES);
-+	} else {
-+		wed_set(dev, MTK_WED_WPDMA_CTRL,
-+			MTK_WED_WPDMA_CTRL_SDL1_FIXED);
-+
-+		wed_set(dev, MTK_WED_WPDMA_GLO_CFG,
-+			MTK_WED_WPDMA_GLO_CFG_RX_DRV_R0_PKT_PROC |
-+			MTK_WED_WPDMA_GLO_CFG_RX_DRV_R0_CRX_SYNC);
-+
-+		wed_clr(dev, MTK_WED_WPDMA_GLO_CFG,
-+			MTK_WED_WPDMA_GLO_CFG_TX_TKID_KEEP |
-+			MTK_WED_WPDMA_GLO_CFG_TX_DMAD_DW3_PREV);
-+	}
-+}
-+
-+static void
 +mtk_wed_dma_disable(struct mtk_wed_device *dev)
 +{
 +	wed_clr(dev, MTK_WED_WPDMA_GLO_CFG,
@@ -383,7 +341,7 @@
 +		 MTK_WDMA_GLO_CFG_RX_INFO1_PRERES |
 +		 MTK_WDMA_GLO_CFG_RX_INFO2_PRERES, 0);
 +
-+	if (dev->ver == MTK_WED_V1) {
++	if (dev->hw->version == 1) {
 +		regmap_write(dev->hw->mirror, dev->hw->index * 4, 0);
 +		wdma_m32(dev, MTK_WDMA_GLO_CFG,
 +			 MTK_WDMA_GLO_CFG_RX_INFO3_PRERES, 0);
@@ -391,6 +349,8 @@
 +		wed_clr(dev, MTK_WED_WPDMA_GLO_CFG,
 +			MTK_WED_WPDMA_GLO_CFG_RX_DRV_R0_PKT_PROC |
 +			MTK_WED_WPDMA_GLO_CFG_RX_DRV_R0_CRX_SYNC);
++
++		mtk_wed_set_512_support (dev, false)
 +	}
 +}
 +
@@ -400,13 +360,10 @@
 -	regmap_write(dev->hw->mirror, dev->hw->index * 4, 0);
 +	mtk_wed_dma_disable(dev);
 +
-+	if (dev->ver > MTK_WED_V1)
-+		mtk_wed_set_512_support(dev, false);
-+
  	mtk_wed_set_ext_int(dev, false);
  
  	wed_clr(dev, MTK_WED_CTRL,
-@@ -245,26 +394,18 @@ mtk_wed_stop(struct mtk_wed_device *dev)
+@@ -248,26 +321,18 @@ mtk_wed_stop(struct mtk_wed_device *dev)
  		MTK_WED_CTRL_WPDMA_INT_AGENT_EN |
  		MTK_WED_CTRL_WED_TX_BM_EN |
  		MTK_WED_CTRL_WED_TX_FREE_AGENT_EN);
@@ -435,7 +392,7 @@
  	struct mtk_wed_hw *hw = dev->hw;
  
  	mutex_lock(&hw_lock);
-@@ -279,11 +420,14 @@ mtk_wed_detach(struct mtk_wed_device *dev)
+@@ -282,11 +347,14 @@ mtk_wed_detach(struct mtk_wed_device *dev)
  	mtk_wed_free_buffer(dev);
  	mtk_wed_free_tx_rings(dev);
  
@@ -444,7 +401,7 @@
 -				   BIT(hw->index), BIT(hw->index));
 +	if (dev->wlan.bus_type == MTK_BUS_TYPE_PCIE) {
 +		wlan_node = dev->wlan.pci_dev->dev.of_node;
-+		if (of_dma_is_coherent(wlan_node))
++		if (of_dma_is_coherent(wlan_node) && hw->hifsys)
 +			regmap_update_bits(hw->hifsys, HIFSYS_DMA_AG_MAP,
 +					   BIT(hw->index), BIT(hw->index));
 +	}
@@ -454,31 +411,25 @@
  	    hw->eth->dma_dev != hw->eth->dev)
  		mtk_eth_set_dma_device(hw->eth, hw->eth->dev);
  
-@@ -294,15 +438,87 @@ mtk_wed_detach(struct mtk_wed_device *dev)
+@@ -297,14 +365,76 @@ mtk_wed_detach(struct mtk_wed_device *dev)
  	mutex_unlock(&hw_lock);
  }
  
++#define PCIE_BASE_ADDR0 0x11280000
 +static void
 +mtk_wed_bus_init(struct mtk_wed_device *dev)
 +{
-+#define PCIE_BASE_ADDR0 0x11280000
-+
-+	if (dev->wlan.bus_type == MTK_BUS_TYPE_PCIE) {
-+		struct device_node *node;
-+		void __iomem * base_addr;
-+		u32 value = 0;
++	switch (dev->wlan.bus_type) {
++	case MTK_BUS_TYPE_PCIE: {
++		struct device_node *np = dev->hw->eth->dev->of_node;
++		struct regmap *regs;
 +
-+		node = of_parse_phandle(dev->hw->node, "mediatek,wed_pcie", 0);
-+		if (!node) {
-+			pr_err("%s: no wed_pcie node\n", __func__);
-+			return;
-+		}
-+
-+		base_addr = of_iomap(node, 0);
++		regs = syscon_regmap_lookup_by_phandle(np,
++						       "mediatek,wed-pcie");
++		if (IS_ERR(regs))
++			break;
 +
-+		value = readl(base_addr);
-+		value |= BIT(0);
-+		writel(value, base_addr);
++		regmap_update_bits(regs, 0, BIT(0), BIT(0));
 +
 +		wed_w32(dev, MTK_WED_PCIE_INT_CTRL,
 +			FIELD_PREP(MTK_WED_PCIE_INT_CTRL_POLL_EN, 2));
@@ -489,40 +440,40 @@
 +			FIELD_PREP(MTK_WED_PCIE_INT_CTRL_SRC_SEL, 1));
 +		wed_r32(dev, MTK_WED_PCIE_INT_CTRL);
 +
-+		value = wed_r32(dev, MTK_WED_PCIE_CFG_INTM);
-+		value = wed_r32(dev, MTK_WED_PCIE_CFG_BASE);
 +		wed_w32(dev, MTK_WED_PCIE_CFG_INTM, PCIE_BASE_ADDR0 | 0x180);
 +		wed_w32(dev, MTK_WED_PCIE_CFG_BASE, PCIE_BASE_ADDR0 | 0x184);
 +
-+		value = wed_r32(dev, MTK_WED_PCIE_CFG_INTM);
-+		value = wed_r32(dev, MTK_WED_PCIE_CFG_BASE);
-+
 +		/* pcie interrupt status trigger register */
 +		wed_w32(dev, MTK_WED_PCIE_INT_TRIGGER, BIT(24));
 +		wed_r32(dev, MTK_WED_PCIE_INT_TRIGGER);
 +
 +		/* pola setting */
-+		value = wed_r32(dev, MTK_WED_PCIE_INT_CTRL);
 +		wed_set(dev, MTK_WED_PCIE_INT_CTRL,
 +			MTK_WED_PCIE_INT_CTRL_MSK_EN_POLA);
-+	} else if (dev->wlan.bus_type == MTK_BUS_TYPE_AXI) {
++		break;
++	}
++	case MTK_BUS_TYPE_AXI:
 +		wed_set(dev, MTK_WED_WPDMA_INT_CTRL,
 +			MTK_WED_WPDMA_INT_CTRL_SIG_SRC |
 +			FIELD_PREP(MTK_WED_WPDMA_INT_CTRL_SRC_SEL, 0));
++		break;
++	default:
++		break;
 +	}
-+	return;
 +}
 +
 +static void
 +mtk_wed_set_wpdma(struct mtk_wed_device *dev)
 +{
-+	if (dev->ver > MTK_WED_V1) {
++	if (dev->hw->version == 1) {
++		wed_w32(dev, MTK_WED_WPDMA_CFG_BASE,  dev->wlan.wpdma_phys);
++	} else {
++		mtk_wed_bus_init(dev);
++
 +		wed_w32(dev, MTK_WED_WPDMA_CFG_BASE,  dev->wlan.wpdma_int);
 +		wed_w32(dev, MTK_WED_WPDMA_CFG_INT_MASK,  dev->wlan.wpdma_mask);
 +		wed_w32(dev, MTK_WED_WPDMA_CFG_TX,  dev->wlan.wpdma_tx);
 +		wed_w32(dev, MTK_WED_WPDMA_CFG_TX_FREE,  dev->wlan.wpdma_txfree);
-+	} else {
-+		wed_w32(dev, MTK_WED_WPDMA_CFG_BASE,  dev->wlan.wpdma_phys);
 +	}
 +}
 +
@@ -534,21 +485,16 @@
  
  	mtk_wed_stop(dev);
  	mtk_wed_reset(dev, MTK_WED_RESET_WED);
- 
-+	if (dev->ver > MTK_WED_V1)
-+		mtk_wed_bus_init(dev);
-+
 +	mtk_wed_set_wpdma(dev);
-+
+ 
  	mask = MTK_WED_WDMA_GLO_CFG_BT_SIZE |
  	       MTK_WED_WDMA_GLO_CFG_DYNAMIC_DMAD_RECYCLE |
- 	       MTK_WED_WDMA_GLO_CFG_RX_DIS_FSM_AUTO_IDLE;
-@@ -311,30 +527,54 @@ mtk_wed_hw_init_early(struct mtk_wed_device *dev)
+@@ -314,14 +444,30 @@ mtk_wed_hw_init_early(struct mtk_wed_device *dev)
  	      MTK_WED_WDMA_GLO_CFG_IDLE_DMAD_SUPPLY;
  	wed_m32(dev, MTK_WED_WDMA_GLO_CFG, mask, set);
  
 -	wdma_set(dev, MTK_WDMA_GLO_CFG, MTK_WDMA_GLO_CFG_RX_INFO_PRERES);
-+	if (dev->ver == MTK_WED_V1) {
++	if (dev->hw->version == 1) {
 +		u32 offset;
 +		offset = dev->hw->index ? 0x04000400 : 0;
 +		wed_w32(dev, MTK_WED_WDMA_OFFSET0, 0x2a042a20 + offset);
@@ -557,7 +503,8 @@
 -	offset = dev->hw->index ? 0x04000400 : 0;
 -	wed_w32(dev, MTK_WED_WDMA_OFFSET0, 0x2a042a20 + offset);
 -	wed_w32(dev, MTK_WED_WDMA_OFFSET1, 0x29002800 + offset);
-+		wed_w32(dev, MTK_WED_PCIE_CFG_BASE, MTK_PCIE_BASE(dev->hw->index));
++		wed_w32(dev, MTK_WED_PCIE_CFG_BASE,
++			MTK_PCIE_BASE(dev->hw->index));
 +	} else {
 +		wed_w32(dev, MTK_WED_WDMA_CFG_BASE, dev->hw->wdma_phy);
 +		wed_set(dev, MTK_WED_CTRL, MTK_WED_CTRL_ETH_DMAD_FMT);
@@ -579,44 +526,62 @@
  }
  
  static void
- mtk_wed_hw_init(struct mtk_wed_device *dev)
- {
-+	int size = dev->buf_ring.size;
-+	int rev_size = MTK_WED_TX_RING_SIZE / 2;
-+	int thr = 1;
-+
- 	if (dev->init_done)
- 		return;
+@@ -332,46 +478,79 @@ mtk_wed_hw_init(struct mtk_wed_device *dev)
  
  	dev->init_done = true;
  	mtk_wed_set_ext_int(dev, false);
-+
-+	if (dev->ver > MTK_WED_V1) {
-+		size = MTK_WED_WDMA_RING_SIZE * 2 + dev->buf_ring.size;
-+		rev_size = size;
-+		thr = 0;
-+	}
-+
- 	wed_w32(dev, MTK_WED_TX_BM_CTRL,
- 		MTK_WED_TX_BM_CTRL_PAUSE |
+-	wed_w32(dev, MTK_WED_TX_BM_CTRL,
+-		MTK_WED_TX_BM_CTRL_PAUSE |
 -		FIELD_PREP(MTK_WED_TX_BM_CTRL_VLD_GRP_NUM,
 -			   dev->buf_ring.size / 128) |
 -		FIELD_PREP(MTK_WED_TX_BM_CTRL_RSV_GRP_NUM,
 -			   MTK_WED_TX_RING_SIZE / 256));
-+		FIELD_PREP(MTK_WED_TX_BM_CTRL_VLD_GRP_NUM, size / 128) |
-+		FIELD_PREP(MTK_WED_TX_BM_CTRL_RSV_GRP_NUM, rev_size / 128));
  
  	wed_w32(dev, MTK_WED_TX_BM_BASE, dev->buf_ring.desc_phys);
  
-@@ -347,28 +587,38 @@ mtk_wed_hw_init(struct mtk_wed_device *dev)
+-	wed_w32(dev, MTK_WED_TX_BM_TKID,
+-		FIELD_PREP(MTK_WED_TX_BM_TKID_START,
+-			   dev->wlan.token_start) |
+-		FIELD_PREP(MTK_WED_TX_BM_TKID_END,
+-			   dev->wlan.token_start + dev->wlan.nbuf - 1));
+-
  	wed_w32(dev, MTK_WED_TX_BM_BUF_LEN, MTK_WED_PKT_SIZE);
  
- 	wed_w32(dev, MTK_WED_TX_BM_DYN_THR,
+-	wed_w32(dev, MTK_WED_TX_BM_DYN_THR,
 -		FIELD_PREP(MTK_WED_TX_BM_DYN_THR_LO, 1) |
-+		FIELD_PREP(MTK_WED_TX_BM_DYN_THR_LO, thr) |
- 		MTK_WED_TX_BM_DYN_THR_HI);
- 
-+	if (dev->ver > MTK_WED_V1) {
+-		MTK_WED_TX_BM_DYN_THR_HI);
++	if (dev->hw->version == 1) {
++		wed_w32(dev, MTK_WED_TX_BM_CTRL,
++			MTK_WED_TX_BM_CTRL_PAUSE |
++			FIELD_PREP(MTK_WED_TX_BM_CTRL_VLD_GRP_NUM,
++				   dev->buf_ring.size / 128) |
++			FIELD_PREP(MTK_WED_TX_BM_CTRL_RSV_GRP_NUM,
++				   MTK_WED_TX_RING_SIZE / 256));
++		wed_w32(dev, MTK_WED_TX_BM_TKID,
++			FIELD_PREP(MTK_WED_TX_BM_TKID_START,
++				   dev->wlan.token_start) |
++			FIELD_PREP(MTK_WED_TX_BM_TKID_END,
++				   dev->wlan.token_start +
++				   dev->wlan.nbuf - 1));
++		wed_w32(dev, MTK_WED_TX_BM_DYN_THR,
++			FIELD_PREP(MTK_WED_TX_BM_DYN_THR_LO, 1) |
++			MTK_WED_TX_BM_DYN_THR_HI);
++	} else {
++		wed_w32(dev, MTK_WED_TX_BM_CTRL,
++			MTK_WED_TX_BM_CTRL_PAUSE |
++			FIELD_PREP(MTK_WED_TX_BM_CTRL_VLD_GRP_NUM,
++				   dev->buf_ring.size / 128) |
++			FIELD_PREP(MTK_WED_TX_BM_CTRL_RSV_GRP_NUM,
++				   dev->buf_ring.size / 128));
++		wed_w32(dev, MTK_WED_TX_BM_TKID_V2,
++			FIELD_PREP(MTK_WED_TX_BM_TKID_START,
++				   dev->wlan.token_start) |
++			FIELD_PREP(MTK_WED_TX_BM_TKID_END,
++				   dev->wlan.token_start +
++				   dev->wlan.nbuf - 1));
++		wed_w32(dev, MTK_WED_TX_BM_DYN_THR,
++			FIELD_PREP(MTK_WED_TX_BM_DYN_THR_LO_V2, 0) |
++			MTK_WED_TX_BM_DYN_THR_HI_V2);
 +		wed_w32(dev, MTK_WED_TX_TKID_CTRL,
 +			MTK_WED_TX_TKID_CTRL_PAUSE |
 +			FIELD_PREP(MTK_WED_TX_TKID_CTRL_VLD_GRP_NUM,
@@ -627,21 +592,27 @@
 +			FIELD_PREP(MTK_WED_TX_TKID_DYN_THR_LO, 0) |
 +			MTK_WED_TX_TKID_DYN_THR_HI);
 +	}
+ 
  	mtk_wed_reset(dev, MTK_WED_RESET_TX_BM);
  
 -	wed_set(dev, MTK_WED_CTRL,
 -		MTK_WED_CTRL_WED_TX_BM_EN |
 -		MTK_WED_CTRL_WED_TX_FREE_AGENT_EN);
--
- 	wed_clr(dev, MTK_WED_TX_BM_CTRL, MTK_WED_TX_BM_CTRL_PAUSE);
-+	if (dev->ver > MTK_WED_V1)
++	if (dev->hw->version == 1)
++		wed_set(dev, MTK_WED_CTRL,
++			MTK_WED_CTRL_WED_TX_BM_EN |
++			MTK_WED_CTRL_WED_TX_FREE_AGENT_EN);
++	else
 +		wed_clr(dev, MTK_WED_TX_TKID_CTRL, MTK_WED_TX_TKID_CTRL_PAUSE);
+ 
+ 	wed_clr(dev, MTK_WED_TX_BM_CTRL, MTK_WED_TX_BM_CTRL_PAUSE);
  }
  
  static void
 -mtk_wed_ring_reset(struct mtk_wdma_desc *desc, int size)
-+mtk_wed_ring_reset(struct mtk_wdma_desc *desc, int size, int scale)
++mtk_wed_ring_reset(struct mtk_wed_ring *ring, int size)
  {
++	void *head = (void *)ring->desc;
  	int i;
  
  	for (i = 0; i < size; i++) {
@@ -649,136 +620,228 @@
 -		desc[i].ctrl = cpu_to_le32(MTK_WDMA_DESC_CTRL_DMA_DONE);
 -		desc[i].buf1 = 0;
 -		desc[i].info = 0;
++		struct mtk_wdma_desc *desc;
++		desc = (struct mtk_wdma_desc *)(head + i * ring->desc_size);
 +		desc->buf0 = 0;
 +		desc->ctrl = cpu_to_le32(MTK_WDMA_DESC_CTRL_DMA_DONE);
 +		desc->buf1 = 0;
 +		desc->info = 0;
-+		desc += scale;
  	}
  }
  
-@@ -424,7 +674,7 @@ mtk_wed_reset_dma(struct mtk_wed_device *dev)
- 		if (!desc)
+@@ -422,12 +601,10 @@ mtk_wed_reset_dma(struct mtk_wed_device *dev)
+ 	int i;
+ 
+ 	for (i = 0; i < ARRAY_SIZE(dev->tx_ring); i++) {
+-		struct mtk_wdma_desc *desc = dev->tx_ring[i].desc;
+-
+-		if (!desc)
++		if (!dev->tx_ring[i].desc)
  			continue;
  
 -		mtk_wed_ring_reset(desc, MTK_WED_TX_RING_SIZE);
-+		mtk_wed_ring_reset(desc, MTK_WED_TX_RING_SIZE, dev->ver);
++		mtk_wed_ring_reset(&dev->tx_ring[i], MTK_WED_TX_RING_SIZE);
  	}
  
  	if (mtk_wed_poll_busy(dev))
-@@ -481,16 +731,16 @@ mtk_wed_reset_dma(struct mtk_wed_device *dev)
+@@ -484,16 +661,16 @@ mtk_wed_reset_dma(struct mtk_wed_device *dev)
  
  static int
  mtk_wed_ring_alloc(struct mtk_wed_device *dev, struct mtk_wed_ring *ring,
 -		   int size)
-+		   int size, int scale)
++		   int size, u32 desc_size)
  {
- 	ring->desc = dma_alloc_coherent(dev->hw->dev,
+-	ring->desc = dma_alloc_coherent(dev->hw->dev,
 -					size * sizeof(*ring->desc),
-+					size * sizeof(*ring->desc) * scale,
++	ring->desc = dma_alloc_coherent(dev->hw->dev, size * desc_size,
  					&ring->desc_phys, GFP_KERNEL);
  	if (!ring->desc)
  		return -ENOMEM;
  
++	ring->desc_size = desc_size;
  	ring->size = size;
 -	mtk_wed_ring_reset(ring->desc, size);
-+	mtk_wed_ring_reset(ring->desc, size, scale);
++	mtk_wed_ring_reset(ring, size);
  
  	return 0;
  }
-@@ -500,7 +750,7 @@ mtk_wed_wdma_ring_setup(struct mtk_wed_device *dev, int idx, int size)
+@@ -501,9 +678,10 @@ mtk_wed_ring_alloc(struct mtk_wed_device *dev, struct mtk_wed_ring *ring,
+ static int
+ mtk_wed_wdma_ring_setup(struct mtk_wed_device *dev, int idx, int size)
  {
++	u32 desc_size = sizeof(struct mtk_wdma_desc) * dev->hw->version;
  	struct mtk_wed_ring *wdma = &dev->tx_wdma[idx];
  
 -	if (mtk_wed_ring_alloc(dev, wdma, MTK_WED_WDMA_RING_SIZE))
-+	if (mtk_wed_ring_alloc(dev, wdma, MTK_WED_WDMA_RING_SIZE, dev->ver))
++	if (mtk_wed_ring_alloc(dev, wdma, MTK_WED_WDMA_RING_SIZE, desc_size))
  		return -ENOMEM;
  
  	wdma_w32(dev, MTK_WDMA_RING_RX(idx) + MTK_WED_RING_OFS_BASE,
-@@ -521,60 +771,36 @@ static void
- mtk_wed_start(struct mtk_wed_device *dev, u32 irq_mask)
+@@ -521,43 +699,63 @@ mtk_wed_wdma_ring_setup(struct mtk_wed_device *dev, int idx, int size)
+ }
+ 
+ static void
+-mtk_wed_start(struct mtk_wed_device *dev, u32 irq_mask)
++mtk_wed_configure_irq(struct mtk_wed_device *dev, u32 irq_mask)
  {
- 	u32 wdma_mask;
+-	u32 wdma_mask;
 -	u32 val;
- 	int i;
- 
- 	for (i = 0; i < ARRAY_SIZE(dev->tx_wdma); i++)
- 		if (!dev->tx_wdma[i].desc)
- 			mtk_wed_wdma_ring_setup(dev, i, 16);
- 
+-	int i;
+-
+-	for (i = 0; i < ARRAY_SIZE(dev->tx_wdma); i++)
+-		if (!dev->tx_wdma[i].desc)
+-			mtk_wed_wdma_ring_setup(dev, i, 16);
+-
 -	wdma_mask = FIELD_PREP(MTK_WDMA_INT_MASK_RX_DONE, GENMASK(1, 0));
+-
+-	mtk_wed_hw_init(dev);
++	u32 wdma_mask = FIELD_PREP(MTK_WDMA_INT_MASK_RX_DONE, GENMASK(1, 0));
  
- 	mtk_wed_hw_init(dev);
++	/* wed control cr set */
+ 	wed_set(dev, MTK_WED_CTRL,
+ 		MTK_WED_CTRL_WDMA_INT_AGENT_EN |
+ 		MTK_WED_CTRL_WPDMA_INT_AGENT_EN |
+ 		MTK_WED_CTRL_WED_TX_BM_EN |
+ 		MTK_WED_CTRL_WED_TX_FREE_AGENT_EN);
  
--	wed_set(dev, MTK_WED_CTRL,
--		MTK_WED_CTRL_WDMA_INT_AGENT_EN |
--		MTK_WED_CTRL_WPDMA_INT_AGENT_EN |
--		MTK_WED_CTRL_WED_TX_BM_EN |
--		MTK_WED_CTRL_WED_TX_FREE_AGENT_EN);
--
 -	wed_w32(dev, MTK_WED_PCIE_INT_TRIGGER, MTK_WED_PCIE_INT_TRIGGER_STATUS);
--
++	if (dev->hw->version == 1) {
++		wed_w32(dev, MTK_WED_PCIE_INT_TRIGGER,
++			MTK_WED_PCIE_INT_TRIGGER_STATUS);
+ 
 -	wed_w32(dev, MTK_WED_WPDMA_INT_TRIGGER,
 -		MTK_WED_WPDMA_INT_TRIGGER_RX_DONE |
 -		MTK_WED_WPDMA_INT_TRIGGER_TX_DONE);
-+	mtk_wed_set_int(dev, irq_mask);
- 
+-
 -	wed_set(dev, MTK_WED_WPDMA_INT_CTRL,
 -		MTK_WED_WPDMA_INT_CTRL_SUBRT_ADV);
--
--	wed_w32(dev, MTK_WED_WDMA_INT_TRIGGER, wdma_mask);
++		wed_w32(dev, MTK_WED_WPDMA_INT_TRIGGER,
++			MTK_WED_WPDMA_INT_TRIGGER_RX_DONE |
++			MTK_WED_WPDMA_INT_TRIGGER_TX_DONE);
+ 
++		wed_clr(dev, MTK_WED_WDMA_INT_CTRL, wdma_mask);
++	} else {
++		/* initail tx interrupt trigger */
++		wed_w32(dev, MTK_WED_WPDMA_INT_CTRL_TX,
++			MTK_WED_WPDMA_INT_CTRL_TX0_DONE_EN |
++			MTK_WED_WPDMA_INT_CTRL_TX0_DONE_CLR |
++			MTK_WED_WPDMA_INT_CTRL_TX1_DONE_EN |
++			MTK_WED_WPDMA_INT_CTRL_TX1_DONE_CLR |
++			FIELD_PREP(MTK_WED_WPDMA_INT_CTRL_TX0_DONE_TRIG,
++				   dev->wlan.tx_tbit[0]) |
++			FIELD_PREP(MTK_WED_WPDMA_INT_CTRL_TX1_DONE_TRIG,
++				   dev->wlan.tx_tbit[1]));
++
++		/* initail txfree interrupt trigger */
++		wed_w32(dev, MTK_WED_WPDMA_INT_CTRL_TX_FREE,
++			MTK_WED_WPDMA_INT_CTRL_TX_FREE_DONE_EN |
++			MTK_WED_WPDMA_INT_CTRL_TX_FREE_DONE_CLR |
++			FIELD_PREP(MTK_WED_WPDMA_INT_CTRL_TX_FREE_DONE_TRIG,
++				    dev->wlan.txfree_tbit));
++
++		wed_w32(dev, MTK_WED_WDMA_INT_CLR, wdma_mask);
++		wed_set(dev, MTK_WED_WDMA_INT_CTRL,
++			FIELD_PREP(MTK_WED_WDMA_INT_POLL_SRC_SEL,dev->wdma_idx));
++	}
++	/* initail wdma interrupt agent */
+ 	wed_w32(dev, MTK_WED_WDMA_INT_TRIGGER, wdma_mask);
 -	wed_clr(dev, MTK_WED_WDMA_INT_CTRL, wdma_mask);
--
--	wdma_w32(dev, MTK_WDMA_INT_MASK, wdma_mask);
--	wdma_w32(dev, MTK_WDMA_INT_GRP2, wdma_mask);
  
--	wed_w32(dev, MTK_WED_WPDMA_INT_MASK, irq_mask);
--	wed_w32(dev, MTK_WED_INT_MASK, irq_mask);
-+	mtk_wed_set_ext_int(dev, true);
+ 	wdma_w32(dev, MTK_WDMA_INT_MASK, wdma_mask);
+ 	wdma_w32(dev, MTK_WDMA_INT_GRP2, wdma_mask);
+-
+ 	wed_w32(dev, MTK_WED_WPDMA_INT_MASK, irq_mask);
+ 	wed_w32(dev, MTK_WED_INT_MASK, irq_mask);
++}
++
++static void
++mtk_wed_dma_enable(struct mtk_wed_device *dev)
++{
++	wed_set(dev, MTK_WED_WPDMA_INT_CTRL,
++		MTK_WED_WPDMA_INT_CTRL_SUBRT_ADV);
  
--	wed_set(dev, MTK_WED_GLO_CFG,
--		MTK_WED_GLO_CFG_TX_DMA_EN |
--		MTK_WED_GLO_CFG_RX_DMA_EN);
--	wed_set(dev, MTK_WED_WPDMA_GLO_CFG,
--		MTK_WED_WPDMA_GLO_CFG_TX_DRV_EN |
--		MTK_WED_WPDMA_GLO_CFG_RX_DRV_EN);
--	wed_set(dev, MTK_WED_WDMA_GLO_CFG,
--		MTK_WED_WDMA_GLO_CFG_RX_DRV_EN);
-+	if (dev->ver == MTK_WED_V1) {
-+		u32 val;
+ 	wed_set(dev, MTK_WED_GLO_CFG,
+ 		MTK_WED_GLO_CFG_TX_DMA_EN |
+@@ -568,16 +766,57 @@ mtk_wed_start(struct mtk_wed_device *dev, u32 irq_mask)
+ 	wed_set(dev, MTK_WED_WDMA_GLO_CFG,
+ 		MTK_WED_WDMA_GLO_CFG_RX_DRV_EN);
  
--	mtk_wed_set_ext_int(dev, true);
++	wdma_set(dev, MTK_WDMA_GLO_CFG,
++		 MTK_WDMA_GLO_CFG_TX_DMA_EN |
++		 MTK_WDMA_GLO_CFG_RX_INFO1_PRERES |
++		 MTK_WDMA_GLO_CFG_RX_INFO2_PRERES);
++
++	if (dev->hw->version == 1) {
++		wdma_set(dev, MTK_WDMA_GLO_CFG,
++			 MTK_WDMA_GLO_CFG_RX_INFO3_PRERES);
++	} else {
++		wed_set(dev, MTK_WED_WPDMA_CTRL,
++			MTK_WED_WPDMA_CTRL_SDL1_FIXED);
++
++		wed_set(dev, MTK_WED_WPDMA_GLO_CFG,
++			MTK_WED_WPDMA_GLO_CFG_RX_DRV_R0_PKT_PROC |
++			MTK_WED_WPDMA_GLO_CFG_RX_DRV_R0_CRX_SYNC);
++
++		wed_clr(dev, MTK_WED_WPDMA_GLO_CFG,
++			MTK_WED_WPDMA_GLO_CFG_TX_TKID_KEEP |
++			MTK_WED_WPDMA_GLO_CFG_TX_DMAD_DW3_PREV);
++	}
++}
++
++static void
++mtk_wed_start(struct mtk_wed_device *dev, u32 irq_mask)
++{
++	u32 wdma_mask;
++	int i;
++
++	for (i = 0; i < ARRAY_SIZE(dev->tx_wdma); i++)
++		if (!dev->tx_wdma[i].desc)
++			mtk_wed_wdma_ring_setup(dev, i, 16);
++
++
++	mtk_wed_hw_init(dev);
++	mtk_wed_configure_irq(dev, irq_mask);
++
+ 	mtk_wed_set_ext_int(dev, true);
 -	val = dev->wlan.wpdma_phys |
 -	      MTK_PCIE_MIRROR_MAP_EN |
 -	      FIELD_PREP(MTK_PCIE_MIRROR_MAP_WED_ID, dev->hw->index);
-+		val = dev->wlan.wpdma_phys |
-+		      MTK_PCIE_MIRROR_MAP_EN |
-+		      FIELD_PREP(MTK_PCIE_MIRROR_MAP_WED_ID, dev->hw->index);
  
 -	if (dev->hw->index)
 -		val |= BIT(1);
 -	val |= BIT(0);
 -	regmap_write(dev->hw->mirror, dev->hw->index * 4, val);
-+		if (dev->hw->index)
-+			val |= BIT(1);
-+		val |= BIT(0);
++	if (dev->hw->version == 1) {
++		u32 val;
++
++		val = dev->wlan.wpdma_phys | MTK_PCIE_MIRROR_MAP_EN |
++		      FIELD_PREP(MTK_PCIE_MIRROR_MAP_WED_ID, dev->hw->index);
+ 
++		val |= BIT(0) | (BIT(1) * !!dev->hw->index);
 +		regmap_write(dev->hw->mirror, dev->hw->index * 4, val);
 +	} else {
 +		mtk_wed_set_512_support(dev, true);
 +	}
- 
++
 +	mtk_wed_dma_enable(dev);
  	dev->running = true;
  }
  
+@@ -586,20 +825,19 @@ mtk_wed_attach(struct mtk_wed_device *dev)
+ 	__releases(RCU)
+ {
+ 	struct mtk_wed_hw *hw;
++	struct device *device;
+ 	int ret = 0;
+ 
-@@ -588,15 +814,11 @@ mtk_wed_attach(struct mtk_wed_device *dev)
  	RCU_LOCKDEP_WARN(!rcu_read_lock_held(),
  			 "mtk_wed_attach without holding the RCU read lock");
  
 -	if (pci_domain_nr(dev->wlan.pci_dev->bus) > 1 ||
--	    !try_module_get(THIS_MODULE))
++	if ((dev->wlan.bus_type == MTK_WED_BUS_PCIE &&
++	     pci_domain_nr(dev->wlan.pci_dev->bus) > 1) ||
+ 	    !try_module_get(THIS_MODULE))
 -		ret = -ENODEV;
-+	if (!try_module_get(THIS_MODULE))
 +		return -ENODEV;
  
  	rcu_read_unlock();
@@ -789,55 +852,48 @@
  	mutex_lock(&hw_lock);
  
  	hw = mtk_wed_assign(dev);
-@@ -606,8 +828,6 @@ mtk_wed_attach(struct mtk_wed_device *dev)
+@@ -609,8 +847,11 @@ mtk_wed_attach(struct mtk_wed_device *dev)
  		goto out;
  	}
  
 -	dev_info(&dev->wlan.pci_dev->dev, "attaching wed device %d\n", hw->index);
 -
++	device = dev->wlan.bus_type == MTK_WED_BUS_PCIE ?
++				       &dev->wlan.pci_dev->dev
++				       : &dev->wlan.platform_dev->dev;
++	dev_info(device, "attaching wed device %d version %d\n",
++		 hw->index, hw->version);
  	dev->hw = hw;
  	dev->dev = hw->dev;
  	dev->irq = hw->irq;
-@@ -617,6 +837,9 @@ mtk_wed_attach(struct mtk_wed_device *dev)
- 	    of_dma_is_coherent(hw->eth->dev->of_node))
- 		mtk_eth_set_dma_device(hw->eth, hw->dev);
- 
-+	dev->ver = FIELD_GET(MTK_WED_REV_ID_MAJOR,
-+			    wed_r32(dev, MTK_WED_REV_ID));
-+
- 	ret = mtk_wed_buffer_alloc(dev);
- 	if (ret) {
- 		mtk_wed_detach(dev);
-@@ -624,7 +847,10 @@ mtk_wed_attach(struct mtk_wed_device *dev)
+@@ -627,7 +868,10 @@ mtk_wed_attach(struct mtk_wed_device *dev)
  	}
  
  	mtk_wed_hw_init_early(dev);
 -	regmap_update_bits(hw->hifsys, HIFSYS_DMA_AG_MAP, BIT(hw->index), 0);
 +
-+	if (dev->ver == MTK_WED_V1)
++	if (hw->hifsys)
 +		regmap_update_bits(hw->hifsys, HIFSYS_DMA_AG_MAP,
 +				   BIT(hw->index), 0);
  
  out:
  	mutex_unlock(&hw_lock);
-@@ -651,7 +877,7 @@ mtk_wed_tx_ring_setup(struct mtk_wed_device *dev, int idx, void __iomem *regs)
+@@ -654,7 +898,8 @@ mtk_wed_tx_ring_setup(struct mtk_wed_device *dev, int idx, void __iomem *regs)
  
- 	BUG_ON(idx > ARRAY_SIZE(dev->tx_ring));
+ 	BUG_ON(idx >= ARRAY_SIZE(dev->tx_ring));
  
 -	if (mtk_wed_ring_alloc(dev, ring, MTK_WED_TX_RING_SIZE))
-+	if (mtk_wed_ring_alloc(dev, ring, MTK_WED_TX_RING_SIZE, 1))
++	if (mtk_wed_ring_alloc(dev, ring, MTK_WED_TX_RING_SIZE,
++			       sizeof(*ring->desc)))
  		return -ENOMEM;
  
  	if (mtk_wed_wdma_ring_setup(dev, idx, MTK_WED_WDMA_RING_SIZE))
-@@ -678,21 +904,24 @@ static int
+@@ -681,21 +926,21 @@ static int
  mtk_wed_txfree_ring_setup(struct mtk_wed_device *dev, void __iomem *regs)
  {
  	struct mtk_wed_ring *ring = &dev->txfree_ring;
 -	int i;
-+	int i, idx = 1;
-+
-+	if(dev->ver > MTK_WED_V1)
-+		idx = 0;
++	int i, index = dev->hw->version == 1;
  
  	/*
  	 * For txfree event handling, the same DMA ring is shared between WED
@@ -845,7 +901,7 @@
  	 * WED
  	 */
 -	ring->reg_base = MTK_WED_RING_RX(1);
-+	ring->reg_base = MTK_WED_RING_RX(idx);
++	ring->reg_base = MTK_WED_RING_RX(index);
  	ring->wpdma = regs;
  
  	for (i = 0; i < 12; i += 4) {
@@ -853,22 +909,43 @@
  
 -		wed_w32(dev, MTK_WED_RING_RX(1) + i, val);
 -		wed_w32(dev, MTK_WED_WPDMA_RING_RX(1) + i, val);
-+		wed_w32(dev, MTK_WED_RING_RX(idx) + i, val);
-+		wed_w32(dev, MTK_WED_WPDMA_RING_RX(idx) + i, val);
++		wed_w32(dev, MTK_WED_RING_RX(index) + i, val);
++		wed_w32(dev, MTK_WED_WPDMA_RING_RX(index) + i, val);
  	}
  
  	return 0;
-@@ -780,7 +1009,8 @@ void mtk_wed_flow_remove(int index)
+@@ -783,7 +1028,9 @@ void mtk_wed_flow_remove(int index)
  }
  
  void mtk_wed_add_hw(struct device_node *np, struct mtk_eth *eth,
 -		    void __iomem *wdma, int index)
-+			void __iomem *wdma, u32 wdma_phy, int index)
++		    void __iomem *wdma, phys_addr_t wdma_phy,
++		    int index)
 +
  {
  	static const struct mtk_wed_ops wed_ops = {
  		.attach = mtk_wed_attach,
-@@ -830,21 +1060,27 @@ void mtk_wed_add_hw(struct device_node *np, struct mtk_eth *eth,
+@@ -809,16 +1056,16 @@ void mtk_wed_add_hw(struct device_node *np, struct mtk_eth *eth,
+ 
+ 	pdev = of_find_device_by_node(np);
+ 	if (!pdev)
+-		return;
++		goto err_of_node_put;
+ 
+ 	get_device(&pdev->dev);
+ 	irq = platform_get_irq(pdev, 0);
+ 	if (irq < 0)
+-		return;
++		goto err_put_device;
+ 
+ 	regs = syscon_regmap_lookup_by_phandle(np, NULL);
+ 	if (IS_ERR(regs))
+-		return;
++		goto err_put_device;
+ 
+ 	rcu_assign_pointer(mtk_soc_wed_ops, &wed_ops);
+ 
+@@ -835,27 +1082,42 @@ void mtk_wed_add_hw(struct device_node *np, struct mtk_eth *eth,
  	hw->eth = eth;
  	hw->dev = &pdev->dev;
  	hw->wdma = wdma;
@@ -883,16 +960,17 @@
 -		kfree(hw);
 -		goto unlock;
 -	}
- 
--	if (!index) {
--		regmap_write(hw->mirror, 0, 0);
--		regmap_write(hw->mirror, 4, 0);
-+	if (!MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V2)) {
++	hw->version = MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V2) ? 2 : 1;
++
++	if (hw->version == 1) {
 +		hw->mirror = syscon_regmap_lookup_by_phandle(eth_np,
 +							     "mediatek,pcie-mirror");
 +		hw->hifsys = syscon_regmap_lookup_by_phandle(eth_np,
 +							     "mediatek,hifsys");
-+
+ 
+-	if (!index) {
+-		regmap_write(hw->mirror, 0, 0);
+-		regmap_write(hw->mirror, 4, 0);
 +		if (IS_ERR(hw->mirror) || IS_ERR(hw->hifsys)) {
 +			kfree(hw);
 +			goto unlock;
@@ -907,8 +985,30 @@
  	mtk_wed_hw_add_debugfs(hw);
  
  	hw_list[index] = hw;
+ 
++	mutex_unlock(&hw_lock);
++
++	return;
++
+ unlock:
+ 	mutex_unlock(&hw_lock);
++err_put_device:
++	put_device(&pdev->dev);
++err_of_node_put:
++	of_node_put(np);
+ }
+ 
+ void mtk_wed_exit(void)
+@@ -876,6 +1138,7 @@ void mtk_wed_exit(void)
+ 		hw_list[i] = NULL;
+ 		debugfs_remove(hw->debugfs_dir);
+ 		put_device(hw->dev);
++		of_node_put(hw->node);
+ 		kfree(hw);
+ 	}
+ }
 diff --git a/drivers/net/ethernet/mediatek/mtk_wed.h b/drivers/net/ethernet/mediatek/mtk_wed.h
-index 981ec61..9b17b74 100644
+index 981ec61..c9a20e4 100644
 --- a/drivers/net/ethernet/mediatek/mtk_wed.h
 +++ b/drivers/net/ethernet/mediatek/mtk_wed.h
 @@ -8,6 +8,19 @@
@@ -931,20 +1031,27 @@
  
  struct mtk_eth;
  
-@@ -23,6 +36,7 @@ struct mtk_wed_hw {
+@@ -18,11 +31,13 @@ struct mtk_wed_hw {
+ 	struct regmap *hifsys;
+ 	struct device *dev;
+ 	void __iomem *wdma;
++	phys_addr_t wdma_phy;
+ 	struct regmap *mirror;
+ 	struct dentry *debugfs_dir;
  	struct mtk_wed_device *wed_dev;
  	u32 debugfs_reg;
  	u32 num_flows;
-+	u32 wdma_phy;
++	u8 version;
  	char dirname[5];
  	int irq;
  	int index;
-@@ -101,14 +115,14 @@ wpdma_txfree_w32(struct mtk_wed_device *dev, u32 reg, u32 val)
+@@ -101,14 +116,16 @@ wpdma_txfree_w32(struct mtk_wed_device *dev, u32 reg, u32 val)
  }
  
  void mtk_wed_add_hw(struct device_node *np, struct mtk_eth *eth,
 -		    void __iomem *wdma, int index);
-+		    void __iomem *wdma, u32 wdma_phy, int index);
++		    void __iomem *wdma, phys_addr_t wdma_phy,
++		    int index);
  void mtk_wed_exit(void);
  int mtk_wed_flow_add(int index);
  void mtk_wed_flow_remove(int index);
@@ -952,7 +1059,8 @@
  static inline void
  mtk_wed_add_hw(struct device_node *np, struct mtk_eth *eth,
 -	       void __iomem *wdma, int index)
-+	       void __iomem *wdma, u32 wdma_phy, int index)
++	       void __iomem *wdma, phys_addr_t wdma_phy,
++	       int index)
  {
  }
  static inline void
@@ -971,26 +1079,18 @@
  	struct mtk_wed_hw *hw = s->private;
  	struct mtk_wed_device *dev = hw->wed_dev;
 diff --git a/drivers/net/ethernet/mediatek/mtk_wed_regs.h b/drivers/net/ethernet/mediatek/mtk_wed_regs.h
-index 0a0465e..a9b9e2a 100644
+index 0a0465e..e66acda 100644
 --- a/drivers/net/ethernet/mediatek/mtk_wed_regs.h
 +++ b/drivers/net/ethernet/mediatek/mtk_wed_regs.h
-@@ -4,9 +4,15 @@
- #ifndef __MTK_WED_REGS_H
+@@ -5,6 +5,7 @@
  #define __MTK_WED_REGS_H
  
-+#if defined(CONFIG_MEDIATEK_NETSYS_V2)
-+#define MTK_WDMA_DESC_CTRL_LEN1			GENMASK(13, 0)
-+#define MTK_WDMA_DESC_CTRL_LAST_SEG1		BIT(14)
-+#define MTK_WDMA_DESC_CTRL_BURST		BIT(15)
-+#else
  #define MTK_WDMA_DESC_CTRL_LEN1			GENMASK(14, 0)
++#define MTK_WDMA_DESC_CTRL_LEN1_V2		GENMASK(13, 0)
  #define MTK_WDMA_DESC_CTRL_LAST_SEG1		BIT(15)
  #define MTK_WDMA_DESC_CTRL_BURST		BIT(16)
-+#endif
  #define MTK_WDMA_DESC_CTRL_LEN0			GENMASK(29, 16)
- #define MTK_WDMA_DESC_CTRL_LAST_SEG0		BIT(30)
- #define MTK_WDMA_DESC_CTRL_DMA_DONE		BIT(31)
-@@ -18,6 +24,14 @@ struct mtk_wdma_desc {
+@@ -18,6 +19,14 @@ struct mtk_wdma_desc {
  	__le32 info;
  } __packed __aligned(4);
  
@@ -1005,7 +1105,7 @@
  #define MTK_WED_RESET					0x008
  #define MTK_WED_RESET_TX_BM				BIT(0)
  #define MTK_WED_RESET_TX_FREE_AGENT			BIT(4)
-@@ -41,6 +55,7 @@ struct mtk_wdma_desc {
+@@ -41,6 +50,7 @@ struct mtk_wdma_desc {
  #define MTK_WED_CTRL_RESERVE_EN				BIT(12)
  #define MTK_WED_CTRL_RESERVE_BUSY			BIT(13)
  #define MTK_WED_CTRL_FINAL_DIDX_READ			BIT(24)
@@ -1013,7 +1113,7 @@
  #define MTK_WED_CTRL_MIB_READ_CLEAR			BIT(28)
  
  #define MTK_WED_EXT_INT_STATUS				0x020
-@@ -49,6 +64,10 @@ struct mtk_wdma_desc {
+@@ -49,6 +59,10 @@ struct mtk_wdma_desc {
  #define MTK_WED_EXT_INT_STATUS_TKID_TITO_INVALID	BIT(4)
  #define MTK_WED_EXT_INT_STATUS_TX_FBUF_LO_TH		BIT(8)
  #define MTK_WED_EXT_INT_STATUS_TX_FBUF_HI_TH		BIT(9)
@@ -1024,7 +1124,7 @@
  #define MTK_WED_EXT_INT_STATUS_RX_FBUF_LO_TH		BIT(12)
  #define MTK_WED_EXT_INT_STATUS_RX_FBUF_HI_TH		BIT(13)
  #define MTK_WED_EXT_INT_STATUS_RX_DRV_R_RESP_ERR	BIT(16)
-@@ -57,16 +76,23 @@ struct mtk_wdma_desc {
+@@ -57,16 +71,23 @@ struct mtk_wdma_desc {
  #define MTK_WED_EXT_INT_STATUS_RX_DRV_INIT_WDMA_EN	BIT(19)
  #define MTK_WED_EXT_INT_STATUS_RX_DRV_BM_DMAD_COHERENT	BIT(20)
  #define MTK_WED_EXT_INT_STATUS_TX_DRV_R_RESP_ERR	BIT(21)
@@ -1051,36 +1151,21 @@
  
  #define MTK_WED_EXT_INT_MASK				0x028
  
-@@ -80,10 +106,6 @@ struct mtk_wdma_desc {
- 
+@@ -81,6 +102,7 @@ struct mtk_wdma_desc {
  #define MTK_WED_TX_BM_BASE				0x084
  
--#define MTK_WED_TX_BM_TKID				0x088
--#define MTK_WED_TX_BM_TKID_START			GENMASK(15, 0)
--#define MTK_WED_TX_BM_TKID_END				GENMASK(31, 16)
--
- #define MTK_WED_TX_BM_BUF_LEN				0x08c
+ #define MTK_WED_TX_BM_TKID				0x088
++#define MTK_WED_TX_BM_TKID_V2				0x0c8
+ #define MTK_WED_TX_BM_TKID_START			GENMASK(15, 0)
+ #define MTK_WED_TX_BM_TKID_END				GENMASK(31, 16)
  
- #define MTK_WED_TX_BM_INTF				0x09c
-@@ -93,9 +115,38 @@ struct mtk_wdma_desc {
- #define MTK_WED_TX_BM_INTF_TKID_READ			BIT(29)
+@@ -94,7 +116,25 @@ struct mtk_wdma_desc {
  
  #define MTK_WED_TX_BM_DYN_THR				0x0a0
-+#if defined(CONFIG_MEDIATEK_NETSYS_V2)
-+#define MTK_WED_TX_BM_DYN_THR_LO			GENMASK(8, 0)
-+#define MTK_WED_TX_BM_DYN_THR_HI			GENMASK(24, 16)
-+
-+#define MTK_WED_TX_BM_TKID				0x0c8
-+#define MTK_WED_TX_BM_TKID_START			GENMASK(15, 0)
-+#define MTK_WED_TX_BM_TKID_END				GENMASK(31, 16)
-+#else
  #define MTK_WED_TX_BM_DYN_THR_LO			GENMASK(6, 0)
++#define MTK_WED_TX_BM_DYN_THR_LO_V2			GENMASK(8, 0)
  #define MTK_WED_TX_BM_DYN_THR_HI			GENMASK(22, 16)
- 
-+#define MTK_WED_TX_BM_TKID				0x088
-+#define MTK_WED_TX_BM_TKID_START			GENMASK(15, 0)
-+#define MTK_WED_TX_BM_TKID_END				GENMASK(31, 16)
-+#endif
++#define MTK_WED_TX_BM_DYN_THR_HI_V2			GENMASK(24, 16)
 +
 +#define MTK_WED_TX_TKID_CTRL				0x0c0
 +#define MTK_WED_TX_TKID_CTRL_VLD_GRP_NUM		GENMASK(6, 0)
@@ -1097,11 +1182,10 @@
 +#define MTK_WED_TXDP_CTRL				0x130
 +#define MTK_WED_TXDP_DW9_OVERWR				BIT(9)
 +#define MTK_WED_RX_BM_TKID_MIB				0x1cc
-+
+ 
  #define MTK_WED_INT_STATUS				0x200
  #define MTK_WED_INT_MASK				0x204
- 
-@@ -125,6 +176,7 @@ struct mtk_wdma_desc {
+@@ -125,6 +165,7 @@ struct mtk_wdma_desc {
  #define MTK_WED_RESET_IDX_RX				GENMASK(17, 16)
  
  #define MTK_WED_TX_MIB(_n)				(0x2a0 + (_n) * 4)
@@ -1109,7 +1193,7 @@
  
  #define MTK_WED_RING_TX(_n)				(0x300 + (_n) * 0x10)
  
-@@ -139,6 +191,19 @@ struct mtk_wdma_desc {
+@@ -139,6 +180,19 @@ struct mtk_wdma_desc {
  #define MTK_WED_WPDMA_GLO_CFG_TX_DRV_BUSY		BIT(1)
  #define MTK_WED_WPDMA_GLO_CFG_RX_DRV_EN			BIT(2)
  #define MTK_WED_WPDMA_GLO_CFG_RX_DRV_BUSY		BIT(3)
@@ -1129,7 +1213,7 @@
  #define MTK_WED_WPDMA_GLO_CFG_RX_BT_SIZE		GENMASK(5, 4)
  #define MTK_WED_WPDMA_GLO_CFG_TX_WB_DDONE		BIT(6)
  #define MTK_WED_WPDMA_GLO_CFG_BIG_ENDIAN		BIT(7)
-@@ -152,24 +217,54 @@ struct mtk_wdma_desc {
+@@ -152,24 +206,54 @@ struct mtk_wdma_desc {
  #define MTK_WED_WPDMA_GLO_CFG_FIRST_TOKEN_ONLY		BIT(26)
  #define MTK_WED_WPDMA_GLO_CFG_OMIT_RX_INFO		BIT(27)
  #define MTK_WED_WPDMA_GLO_CFG_OMIT_TX_INFO		BIT(28)
@@ -1185,7 +1269,7 @@
  
  #define MTK_WED_WPDMA_TX_MIB(_n)			(0x5a0 + (_n) * 4)
  #define MTK_WED_WPDMA_TX_COHERENT_MIB(_n)		(0x5d0 + (_n) * 4)
-@@ -203,14 +298,22 @@ struct mtk_wdma_desc {
+@@ -203,14 +287,22 @@ struct mtk_wdma_desc {
  #define MTK_WED_WDMA_RESET_IDX_RX			GENMASK(17, 16)
  #define MTK_WED_WDMA_RESET_IDX_DRV			GENMASK(25, 24)
  
@@ -1209,7 +1293,7 @@
  
  #define MTK_WED_WDMA_RX_MIB(_n)				(0xae0 + (_n) * 4)
  #define MTK_WED_WDMA_RX_RECYCLE_MIB(_n)			(0xae8 + (_n) * 4)
-@@ -221,14 +324,21 @@ struct mtk_wdma_desc {
+@@ -221,14 +313,21 @@ struct mtk_wdma_desc {
  #define MTK_WED_RING_OFS_CPU_IDX			0x08
  #define MTK_WED_RING_OFS_DMA_IDX			0x0c
  
@@ -1233,21 +1317,14 @@
  #define MTK_WDMA_INT_MASK				0x228
  #define MTK_WDMA_INT_MASK_TX_DONE			GENMASK(3, 0)
 diff --git a/include/linux/soc/mediatek/mtk_wed.h b/include/linux/soc/mediatek/mtk_wed.h
-index 7e00cca..ffd547a 100644
+index 7e00cca..4db70b0 100644
 --- a/include/linux/soc/mediatek/mtk_wed.h
 +++ b/include/linux/soc/mediatek/mtk_wed.h
-@@ -8,6 +8,19 @@
+@@ -8,12 +8,19 @@
  
  #define MTK_WED_TX_QUEUES		2
  
 +enum {
-+	MTK_NO_WED,
-+	MTK_WED_V1,
-+	MTK_WED_V2,
-+	MTK_WED_VMAX
-+};
-+
-+enum {
 +	MTK_BUS_TYPE_PCIE,
 +	MTK_BUS_TYPE_AXI,
 +	MTK_BUS_TYPE_MAX
@@ -1256,20 +1333,24 @@
  struct mtk_wed_hw;
  struct mtk_wdma_desc;
  
-@@ -28,6 +41,7 @@ struct mtk_wed_device {
- 	bool init_done, running;
- 	int wdma_idx;
- 	int irq;
-+	u8 ver;
+ struct mtk_wed_ring {
+ 	struct mtk_wdma_desc *desc;
+ 	dma_addr_t desc_phys;
++	u32 desc_size;
+ 	int size;
+ 
+ 	u32 reg_base;
+@@ -42,9 +49,21 @@ struct mtk_wed_device {
  
- 	struct mtk_wed_ring tx_ring[MTK_WED_TX_QUEUES];
- 	struct mtk_wed_ring txfree_ring;
-@@ -43,8 +57,17 @@ struct mtk_wed_device {
  	/* filled by driver: */
  	struct {
- 		struct pci_dev *pci_dev;
+-		struct pci_dev *pci_dev;
++		union {
++			struct platform_device *platform_dev;
++			struct pci_dev *pci_dev;
++		};
++		enum mtk_wed_bus_tye bus_type;
 +		void __iomem *base;
-+		u32 bus_type;
  
  		u32 wpdma_phys;
 +		u32 wpdma_int;
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/flow_patch/999-3007-add-wed-tx-wds-support-for-netsys2.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/flow_patch/999-3007-add-wed-tx-wds-support-for-netsys2.patch
index aaa6c48..d8c1c8c 100644
--- a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/flow_patch/999-3007-add-wed-tx-wds-support-for-netsys2.patch
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/flow_patch/999-3007-add-wed-tx-wds-support-for-netsys2.patch
@@ -1,20 +1,20 @@
-From 396ce749479219467ea3f1123d5e9a303e5051ec Mon Sep 17 00:00:00 2001
+From 7c68ae1b991064bc0904313c56b83d2f3e03ccd7 Mon Sep 17 00:00:00 2001
 From: Sujuan Chen <sujuan.chen@mediatek.com>
 Date: Mon, 18 Sep 2023 11:03:33 +0800
-Subject: [PATCH 08/22] add-wed-tx-wds-support-for-mt7986
+Subject: [PATCH 07/24] add-wed-tx-wds-support-for-netsys2
 
 ---
- drivers/net/ethernet/mediatek/mtk_wed.c      | 8 +++++++-
+ drivers/net/ethernet/mediatek/mtk_wed.c      | 6 ++++--
  drivers/net/ethernet/mediatek/mtk_wed_regs.h | 1 +
  include/linux/soc/mediatek/mtk_wed.h         | 3 +++
- 3 files changed, 11 insertions(+), 1 deletion(-)
+ 3 files changed, 8 insertions(+), 2 deletions(-)
 
 diff --git a/drivers/net/ethernet/mediatek/mtk_wed.c b/drivers/net/ethernet/mediatek/mtk_wed.c
-index 0588e32..23e3dc5 100644
+index 02e06a8..ea8b2db 100644
 --- a/drivers/net/ethernet/mediatek/mtk_wed.c
 +++ b/drivers/net/ethernet/mediatek/mtk_wed.c
-@@ -797,7 +797,7 @@ mtk_wed_start(struct mtk_wed_device *dev, u32 irq_mask)
- 		val |= BIT(0);
+@@ -813,7 +813,7 @@ mtk_wed_start(struct mtk_wed_device *dev, u32 irq_mask)
+ 		val |= BIT(0) | (BIT(1) * !!dev->hw->index);
  		regmap_write(dev->hw->mirror, dev->hw->index * 4, val);
  	} else {
 -		mtk_wed_set_512_support(dev, true);
@@ -22,31 +22,24 @@
  	}
  
  	mtk_wed_dma_enable(dev);
-@@ -809,6 +809,7 @@ mtk_wed_attach(struct mtk_wed_device *dev)
- 	__releases(RCU)
- {
- 	struct mtk_wed_hw *hw;
-+	u16 ver;
- 	int ret = 0;
+@@ -869,9 +869,11 @@ mtk_wed_attach(struct mtk_wed_device *dev)
  
- 	RCU_LOCKDEP_WARN(!rcu_read_lock_held(),
-@@ -839,6 +840,11 @@ mtk_wed_attach(struct mtk_wed_device *dev)
+ 	mtk_wed_hw_init_early(dev);
  
- 	dev->ver = FIELD_GET(MTK_WED_REV_ID_MAJOR,
- 			    wed_r32(dev, MTK_WED_REV_ID));
-+	if (dev->ver > MTK_WED_V1)
-+		ver = FIELD_GET(MTK_WED_REV_ID_MINOR,
-+			    wed_r32(dev, MTK_WED_REV_ID));
-+
-+	dev->rev_id = ((dev->ver << 28) | ver << 16);
+-	if (hw->hifsys)
++	if (hw->version == 1)
+ 		regmap_update_bits(hw->hifsys, HIFSYS_DMA_AG_MAP,
+ 				   BIT(hw->index), 0);
++	else
++		dev->rev_id = wed_r32(dev, MTK_WED_REV_ID);
  
- 	ret = mtk_wed_buffer_alloc(dev);
- 	if (ret) {
+ out:
+ 	mutex_unlock(&hw_lock);
 diff --git a/drivers/net/ethernet/mediatek/mtk_wed_regs.h b/drivers/net/ethernet/mediatek/mtk_wed_regs.h
-index a9b9e2a..14e0e21 100644
+index e66acda..e797e9d 100644
 --- a/drivers/net/ethernet/mediatek/mtk_wed_regs.h
 +++ b/drivers/net/ethernet/mediatek/mtk_wed_regs.h
-@@ -31,6 +31,7 @@ struct mtk_wdma_desc {
+@@ -26,6 +26,7 @@ struct mtk_wdma_desc {
  #define MTK_WED_REV_ID					0x000
  #define MTK_WED_REV_ID_MAJOR				GENMASK(7, 0)
  #endif
@@ -55,18 +48,18 @@
  #define MTK_WED_RESET					0x008
  #define MTK_WED_RESET_TX_BM				BIT(0)
 diff --git a/include/linux/soc/mediatek/mtk_wed.h b/include/linux/soc/mediatek/mtk_wed.h
-index ffd547a..e914cb4 100644
+index 4db70b0..00036f9 100644
 --- a/include/linux/soc/mediatek/mtk_wed.h
 +++ b/include/linux/soc/mediatek/mtk_wed.h
-@@ -42,6 +42,7 @@ struct mtk_wed_device {
+@@ -35,6 +35,7 @@ struct mtk_wed_device {
+ 	bool init_done, running;
  	int wdma_idx;
  	int irq;
- 	u8 ver;
 +	u32 rev_id;
  
  	struct mtk_wed_ring tx_ring[MTK_WED_TX_QUEUES];
  	struct mtk_wed_ring txfree_ring;
-@@ -72,6 +73,8 @@ struct mtk_wed_device {
+@@ -68,6 +69,8 @@ struct mtk_wed_device {
  		u16 token_start;
  		unsigned int nbuf;
  
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/flow_patch/999-3008-add-wed-rx-support-for-netsys2.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/flow_patch/999-3008-add-wed-rx-support-for-netsys2.patch
index 7efa9df..fd64dcf 100644
--- a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/flow_patch/999-3008-add-wed-rx-support-for-netsys2.patch
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/flow_patch/999-3008-add-wed-rx-support-for-netsys2.patch
@@ -1,24 +1,25 @@
-From d35f304a7d0ec9612064a41b98338d9f712fbb48 Mon Sep 17 00:00:00 2001
+From fad15885ddf2f138ed3ec652b4fcd0cbdf54bf4e Mon Sep 17 00:00:00 2001
 From: Sujuan Chen <sujuan.chen@mediatek.com>
 Date: Mon, 18 Sep 2023 11:04:53 +0800
-Subject: [PATCH 09/22] add-wed-rx-support-for-mt7896
+Subject: [PATCH 08/24] add-wed-rx-support-for-netsys2
 
 ---
+ arch/arm64/boot/dts/mediatek/mt7981.dtsi      |  23 +-
  arch/arm64/boot/dts/mediatek/mt7986a.dtsi     |  42 +-
  arch/arm64/boot/dts/mediatek/mt7986b.dtsi     |  42 +-
  drivers/net/ethernet/mediatek/Makefile        |   2 +-
- drivers/net/ethernet/mediatek/mtk_wed.c       | 639 ++++++++++++++++--
+ drivers/net/ethernet/mediatek/mtk_wed.c       | 645 ++++++++++++++++--
  drivers/net/ethernet/mediatek/mtk_wed.h       |  51 ++
  drivers/net/ethernet/mediatek/mtk_wed_ccif.c  | 133 ++++
  drivers/net/ethernet/mediatek/mtk_wed_ccif.h  |  45 ++
  .../net/ethernet/mediatek/mtk_wed_debugfs.c   |  90 +++
- drivers/net/ethernet/mediatek/mtk_wed_mcu.c   | 586 ++++++++++++++++
- drivers/net/ethernet/mediatek/mtk_wed_mcu.h   |  96 +++
- drivers/net/ethernet/mediatek/mtk_wed_regs.h  | 144 +++-
- drivers/net/ethernet/mediatek/mtk_wed_wo.c    | 564 ++++++++++++++++
- drivers/net/ethernet/mediatek/mtk_wed_wo.h    | 324 +++++++++
- include/linux/soc/mediatek/mtk_wed.h          | 126 +++-
- 14 files changed, 2801 insertions(+), 83 deletions(-)
+ drivers/net/ethernet/mediatek/mtk_wed_mcu.c   | 604 ++++++++++++++++
+ drivers/net/ethernet/mediatek/mtk_wed_mcu.h   |  97 +++
+ drivers/net/ethernet/mediatek/mtk_wed_regs.h  | 143 +++-
+ drivers/net/ethernet/mediatek/mtk_wed_wo.c    | 564 +++++++++++++++
+ drivers/net/ethernet/mediatek/mtk_wed_wo.h    | 325 +++++++++
+ include/linux/soc/mediatek/mtk_wed.h          | 114 +++-
+ 15 files changed, 2822 insertions(+), 98 deletions(-)
  create mode 100644 drivers/net/ethernet/mediatek/mtk_wed_ccif.c
  create mode 100644 drivers/net/ethernet/mediatek/mtk_wed_ccif.h
  create mode 100644 drivers/net/ethernet/mediatek/mtk_wed_mcu.c
@@ -26,8 +27,52 @@
  create mode 100644 drivers/net/ethernet/mediatek/mtk_wed_wo.c
  create mode 100644 drivers/net/ethernet/mediatek/mtk_wed_wo.h
 
+diff --git a/arch/arm64/boot/dts/mediatek/mt7981.dtsi b/arch/arm64/boot/dts/mediatek/mt7981.dtsi
+index cb8f4e1..39b99d8 100644
+--- a/arch/arm64/boot/dts/mediatek/mt7981.dtsi
++++ b/arch/arm64/boot/dts/mediatek/mt7981.dtsi
+@@ -97,26 +97,29 @@
+ 		interrupt-parent = <&gic>;
+ 		interrupts = <GIC_SPI 205 IRQ_TYPE_LEVEL_HIGH>;
+ 		mediatek,wed_pcie = <&wed_pcie>;
++		mediatek,ap2woccif = <&ap2woccif0>;
++		mediatek,wocpu_ilm = <&wocpu0_ilm>;
++		mediatek,wocpu_dlm = <&wocpu0_dlm>;
++		mediatek,wocpu_boot = <&cpu_boot>;
++		mediatek,wocpu_emi = <&wocpu0_emi>;
++		mediatek,wocpu_data = <&wocpu_data>;
+ 	};
+ 
+-	ap2woccif: ap2woccif@151A5000 {
+-		compatible = "mediatek,ap2woccif";
+-		reg = <0 0x151A5000 0 0x1000>,
+-		      <0 0x151AD000 0 0x1000>;
++	ap2woccif0: ap2woccif@151A5000 {
++		compatible = "mediatek,ap2woccif", "syscon";
++		reg = <0 0x151A5000 0 0x1000>;
+ 		interrupt-parent = <&gic>;
+-		interrupts = <GIC_SPI 211 IRQ_TYPE_LEVEL_HIGH>,
+-			     <GIC_SPI 212 IRQ_TYPE_LEVEL_HIGH>;
+-        };
++		interrupts = <GIC_SPI 211 IRQ_TYPE_LEVEL_HIGH>;
++	};
+ 
+ 	wocpu0_ilm: wocpu0_ilm@151E0000 {
+ 		compatible = "mediatek,wocpu0_ilm";
+ 		reg = <0 0x151E0000 0 0x8000>;
+ 	};
+ 
+-	wocpu_dlm: wocpu_dlm@151E8000 {
++	wocpu0_dlm: wocpu_dlm@151E8000 {
+ 		compatible = "mediatek,wocpu_dlm";
+-		reg = <0 0x151E8000 0 0x2000>,
+-		      <0 0x151F8000 0 0x2000>;
++		reg = <0 0x151E8000 0 0x2000>;
+ 
+ 		resets = <&ethsysrst 0>;
+ 		reset-names = "wocpu_rst";
 diff --git a/arch/arm64/boot/dts/mediatek/mt7986a.dtsi b/arch/arm64/boot/dts/mediatek/mt7986a.dtsi
-index 3ff8994..c5dc5e8 100644
+index 9c288fc..e6f50d5 100644
 --- a/arch/arm64/boot/dts/mediatek/mt7986a.dtsi
 +++ b/arch/arm64/boot/dts/mediatek/mt7986a.dtsi
 @@ -65,6 +65,12 @@
@@ -98,7 +143,7 @@
  		resets = <&ethsysrst 0>;
  		reset-names = "wocpu_rst";
 diff --git a/arch/arm64/boot/dts/mediatek/mt7986b.dtsi b/arch/arm64/boot/dts/mediatek/mt7986b.dtsi
-index 043e509..bfd2a02 100644
+index 02feaa9..3bacadc 100644
 --- a/arch/arm64/boot/dts/mediatek/mt7986b.dtsi
 +++ b/arch/arm64/boot/dts/mediatek/mt7986b.dtsi
 @@ -65,6 +65,12 @@
@@ -168,50 +213,6 @@
  
  		resets = <&ethsysrst 0>;
  		reset-names = "wocpu_rst";
-diff --git a/arch/arm64/boot/dts/mediatek/mt7981.dtsi b/arch/arm64/boot/dts/mediatek/mt7981.dtsi
-index d34943e7..512fb5d6 100644
---- a/arch/arm64/boot/dts/mediatek/mt7981.dtsi
-+++ b/arch/arm64/boot/dts/mediatek/mt7981.dtsi
-@@ -97,26 +97,29 @@
- 		interrupt-parent = <&gic>;
- 		interrupts = <GIC_SPI 205 IRQ_TYPE_LEVEL_HIGH>;
- 		mediatek,wed_pcie = <&wed_pcie>;
-+		mediatek,ap2woccif = <&ap2woccif0>;
-+		mediatek,wocpu_ilm = <&wocpu0_ilm>;
-+		mediatek,wocpu_dlm = <&wocpu0_dlm>;
-+		mediatek,wocpu_boot = <&cpu_boot>;
-+		mediatek,wocpu_emi = <&wocpu0_emi>;
-+		mediatek,wocpu_data = <&wocpu_data>;
- 	};
- 
--	ap2woccif: ap2woccif@151A5000 {
--		compatible = "mediatek,ap2woccif";
--		reg = <0 0x151A5000 0 0x1000>,
--		      <0 0x151AD000 0 0x1000>;
-+	ap2woccif0: ap2woccif@151A5000 {
-+		compatible = "mediatek,ap2woccif", "syscon";
-+		reg = <0 0x151A5000 0 0x1000>;
- 		interrupt-parent = <&gic>;
--		interrupts = <GIC_SPI 211 IRQ_TYPE_LEVEL_HIGH>,
--			     <GIC_SPI 212 IRQ_TYPE_LEVEL_HIGH>;
--        };
-+		interrupts = <GIC_SPI 211 IRQ_TYPE_LEVEL_HIGH>;
-+	};
- 
- 	wocpu0_ilm: wocpu0_ilm@151E0000 {
- 		compatible = "mediatek,wocpu0_ilm";
- 		reg = <0 0x151E0000 0 0x8000>;
- 	};
- 
--	wocpu_dlm: wocpu_dlm@151E8000 {
-+	wocpu0_dlm: wocpu_dlm@151E8000 {
- 		compatible = "mediatek,wocpu_dlm";
--		reg = <0 0x151E8000 0 0x2000>,
--		      <0 0x151F8000 0 0x2000>;
-+		reg = <0 0x151E8000 0 0x2000>;
- 
- 		resets = <&ethsysrst 0>;
- 		reset-names = "wocpu_rst";
 diff --git a/drivers/net/ethernet/mediatek/Makefile b/drivers/net/ethernet/mediatek/Makefile
 index 4090132..fdbb90f 100644
 --- a/drivers/net/ethernet/mediatek/Makefile
@@ -224,10 +225,10 @@
 +obj-$(CONFIG_NET_MEDIATEK_SOC_WED) += mtk_wed_ops.o mtk_wed_wo.o mtk_wed_mcu.o mtk_wed_ccif.o
  obj-$(CONFIG_NET_MEDIATEK_HNAT)			+= mtk_hnat/
 diff --git a/drivers/net/ethernet/mediatek/mtk_wed.c b/drivers/net/ethernet/mediatek/mtk_wed.c
-index 23e3dc5..4b2f1a2 100644
+index ea8b2db..ad9f3d5 100644
 --- a/drivers/net/ethernet/mediatek/mtk_wed.c
 +++ b/drivers/net/ethernet/mediatek/mtk_wed.c
-@@ -13,11 +13,19 @@
+@@ -13,10 +13,13 @@
  #include <linux/debugfs.h>
  #include <linux/iopoll.h>
  #include <linux/soc/mediatek/mtk_wed.h>
@@ -236,19 +237,12 @@
  #include "mtk_wed_regs.h"
  #include "mtk_wed.h"
  #include "mtk_ppe.h"
--
 +#include "mtk_wed_mcu.h"
 +#include "mtk_wed_wo.h"
-+
-+struct wo_cmd_ring {
-+	u32 q_base;
-+	u32 cnt;
-+	u32 unit;
-+};
+ 
  static struct mtk_wed_hw *hw_list[2];
  static DEFINE_MUTEX(hw_lock);
- 
-@@ -51,6 +59,56 @@ wdma_set(struct mtk_wed_device *dev, u32 reg, u32 mask)
+@@ -51,12 +54,65 @@ wdma_set(struct mtk_wed_device *dev, u32 reg, u32 mask)
  	wdma_m32(dev, reg, 0, mask);
  }
  
@@ -258,92 +252,107 @@
 +	wdma_m32(dev, reg, mask, 0);
 +}
 +
+ static u32
+ mtk_wed_read_reset(struct mtk_wed_device *dev)
+ {
+ 	return wed_r32(dev, MTK_WED_RESET);
+ }
+ 
 +static u32
 +mtk_wdma_read_reset(struct mtk_wed_device *dev)
 +{
 +	return wdma_r32(dev, MTK_WDMA_GLO_CFG);
 +}
 +
-+static void
++static int
 +mtk_wdma_rx_reset(struct mtk_wed_device *dev)
 +{
-+	u32 status;
-+	u32 mask = MTK_WDMA_GLO_CFG_RX_DMA_BUSY;
-+	int i;
++	u32 status, mask = MTK_WDMA_GLO_CFG_RX_DMA_BUSY;
++	int i, ret;
 +
 +	wdma_clr(dev, MTK_WDMA_GLO_CFG, MTK_WDMA_GLO_CFG_RX_DMA_EN);
-+	if (readx_poll_timeout(mtk_wdma_read_reset, dev, status,
-+			       !(status & mask), 0, 1000))
-+		WARN_ON_ONCE(1);
++	ret = readx_poll_timeout(mtk_wdma_read_reset, dev, status,
++				 !(status & mask), 0, 1000)
++	if (ret)
++		dev_err(dev->hw->dev, "rx reset failed \n");
 +
-+	for (i = 0; i < ARRAY_SIZE(dev->rx_wdma); i++)
-+		if (!dev->rx_wdma[i].desc) {
-+			wdma_w32(dev, MTK_WDMA_RING_RX(i) +
-+				 MTK_WED_RING_OFS_CPU_IDX, 0);
++	for (i = 0; i < ARRAY_SIZE(dev->rx_wdma); i++) {
++		if (!dev->rx_wdma[i].desc)
++			continue;
++
++		wdma_w32(dev,
++			 MTK_WDMA_RING_RX(i) + MTK_WED_RING_OFS_CPU_IDX, 0);
 +	}
 +}
 +
 +static void
 +mtk_wdma_tx_reset(struct mtk_wed_device *dev)
 +{
-+	u32 status;
-+	u32 mask = MTK_WDMA_GLO_CFG_TX_DMA_BUSY;
++	u32 status, mask = MTK_WDMA_GLO_CFG_TX_DMA_BUSY;
 +	int i;
 +
 +	wdma_clr(dev, MTK_WDMA_GLO_CFG, MTK_WDMA_GLO_CFG_TX_DMA_EN);
 +	if (readx_poll_timeout(mtk_wdma_read_reset, dev, status,
 +			       !(status & mask), 0, 1000))
-+		WARN_ON_ONCE(1);
++		dev_err(dev->hw->dev, "tx reset failed \n");
 +
-+	for (i = 0; i < ARRAY_SIZE(dev->tx_wdma); i++)
-+		if (!dev->tx_wdma[i].desc) {
-+			wdma_w32(dev, MTK_WDMA_RING_TX(i) +
-+				 MTK_WED_RING_OFS_CPU_IDX, 0);
++	for (i = 0; i < ARRAY_SIZE(dev->tx_wdma); i++) {
++		if (!dev->tx_wdma[i].desc)
++			continue;
++
++		wdma_w32(dev,
++			 MTK_WDMA_RING_TX(i) + MTK_WED_RING_OFS_CPU_IDX, 0);
 +	}
 +}
 +
- static u32
- mtk_wed_read_reset(struct mtk_wed_device *dev)
+ static void
+ mtk_wed_reset(struct mtk_wed_device *dev, u32 mask)
  {
-@@ -68,6 +126,52 @@ mtk_wed_reset(struct mtk_wed_device *dev, u32 mask)
+@@ -68,6 +124,58 @@ mtk_wed_reset(struct mtk_wed_device *dev, u32 mask)
  		WARN_ON_ONCE(1);
  }
  
++static u32
++mtk_wed_wo_read_status(struct mtk_wed_device *dev)
++{
++	return wed_r32(dev, MTK_WED_SCR0 + 4 * WED_DUMMY_CR_WO_STATUS);
++}
++
 +static void
 +mtk_wed_wo_reset(struct mtk_wed_device *dev)
 +{
 +	struct mtk_wed_wo *wo = dev->hw->wed_wo;
 +	u8 state = WO_STATE_DISABLE;
-+	u8 state_done = WOIF_DISABLE_DONE;
 +	void __iomem *reg;
-+	u32 value;
-+	unsigned long timeout = jiffies + WOCPU_TIMEOUT;
++	u32 val;
 +
 +	mtk_wdma_tx_reset(dev);
 +
 +	mtk_wed_reset(dev, MTK_WED_RESET_WED);
 +
-+	mtk_wed_mcu_send_msg(wo, MODULE_ID_WO, MTK_WED_WO_CMD_CHANGE_STATE,
-+			     &state, sizeof(state), false);
++	mtk_wed_mcu_send_msg(wo, MTK_WED_MODULE_ID_WO,
++			     MTK_WED_WO_CMD_CHANGE_STATE, &state,
++			     sizeof(state), false);
 +
-+	do {
-+		value = wed_r32(dev, MTK_WED_SCR0 + 4 * WED_DUMMY_CR_WO_STATUS);
-+	} while (value != state_done && !time_after(jiffies, timeout));
++	if (readx_poll_timeout(mtk_wed_wo_read_status, dev, val,
++			       val == WOIF_DISABLE_DONE,
++			       100, WOCPU_TIMEOUT))
++		dev_err(dev->hw->dev, "failed to disable wed-wo\n");
 +
 +	reg = ioremap(WOCPU_MCUSYS_RESET_ADDR, 4);
-+	value = readl((void *)reg);
++	val = readl((void *)reg);
 +	switch(dev->hw->index) {
 +	case 0:
-+		value |= WOCPU_WO0_MCUSYS_RESET_MASK;
-+		writel(value, (void *)reg);
-+		value &= ~WOCPU_WO0_MCUSYS_RESET_MASK;
-+		writel(value, (void *)reg);
++		val |= WOCPU_WO0_MCUSYS_RESET_MASK;
++		writel(val, (void *)reg);
++		val &= ~WOCPU_WO0_MCUSYS_RESET_MASK;
++		writel(val, (void *)reg);
 +		break;
 +	case 1:
-+		value |= WOCPU_WO1_MCUSYS_RESET_MASK;
-+		writel(value, (void *)reg);
-+		value &= ~WOCPU_WO1_MCUSYS_RESET_MASK;
-+		writel(value, (void *)reg);
++		val |= WOCPU_WO1_MCUSYS_RESET_MASK;
++		writel(val, (void *)reg);
++		val &= ~WOCPU_WO1_MCUSYS_RESET_MASK;
++		writel(val, (void *)reg);
 +		break;
 +	default:
 +		dev_err(dev->hw->dev, "wrong mtk_wed%d\n",
@@ -358,21 +367,58 @@
  static struct mtk_wed_hw *
  mtk_wed_assign(struct mtk_wed_device *dev)
  {
-@@ -178,7 +282,7 @@ mtk_wed_free_buffer(struct mtk_wed_device *dev)
+@@ -102,7 +210,7 @@ mtk_wed_assign(struct mtk_wed_device *dev)
+ }
+ 
+ static int
+-mtk_wed_buffer_alloc(struct mtk_wed_device *dev)
++mtk_wed_tx_buffer_alloc(struct mtk_wed_device *dev)
+ {
+ 	struct mtk_wdma_desc *desc;
+ 	dma_addr_t desc_phys;
+@@ -124,16 +232,16 @@ mtk_wed_buffer_alloc(struct mtk_wed_device *dev)
+ 	if (!page_list)
+ 		return -ENOMEM;
+ 
+-	dev->buf_ring.size = ring_size;
+-	dev->buf_ring.pages = page_list;
++	dev->tx_buf_ring.size = ring_size;
++	dev->tx_buf_ring.pages = page_list;
+ 
+ 	desc = dma_alloc_coherent(dev->hw->dev, ring_size * sizeof(*desc),
+ 				  &desc_phys, GFP_KERNEL);
+ 	if (!desc)
+ 		return -ENOMEM;
+ 
+-	dev->buf_ring.desc = desc;
+-	dev->buf_ring.desc_phys = desc_phys;
++	dev->tx_buf_ring.desc = desc;
++	dev->tx_buf_ring.desc_phys = desc_phys;
+ 
+ 	for (i = 0, page_idx = 0; i < ring_size; i += MTK_WED_BUF_PER_PAGE) {
+ 		dma_addr_t page_phys, buf_phys;
+@@ -194,11 +302,11 @@ mtk_wed_buffer_alloc(struct mtk_wed_device *dev)
+ }
+ 
+ static void
+-mtk_wed_free_buffer(struct mtk_wed_device *dev)
++mtk_wed_free_tx_buffer(struct mtk_wed_device *dev)
  {
- 	struct mtk_wdma_desc *desc = dev->buf_ring.desc;
- 	void **page_list = dev->buf_ring.pages;
+-	struct mtk_wdma_desc *desc = dev->buf_ring.desc;
+-	void **page_list = dev->buf_ring.pages;
 -	int page_idx;
++	struct mtk_wdma_desc *desc = dev->tx_buf_ring.desc;
++	void **page_list = dev->tx_buf_ring.pages;
 +	int ring_size, page_idx;
  	int i;
  
  	if (!page_list)
-@@ -187,7 +291,14 @@ mtk_wed_free_buffer(struct mtk_wed_device *dev)
+@@ -207,7 +315,14 @@ mtk_wed_free_buffer(struct mtk_wed_device *dev)
  	if (!desc)
  		goto free_pagelist;
  
 -	for (i = 0, page_idx = 0; i < dev->buf_ring.size; i += MTK_WED_BUF_PER_PAGE) {
-+	if (dev->ver == MTK_WED_V1) {
++	if (dev->hw->version == 1) {
 +		ring_size = dev->wlan.nbuf & ~(MTK_WED_BUF_PER_PAGE - 1);
 +	} else {
 +		ring_size = MTK_WED_VLD_GROUP_SIZE * MTK_WED_PER_GROUP_PKT +
@@ -381,201 +427,141 @@
 +
 +	for (i = 0, page_idx = 0; i < ring_size; i += MTK_WED_BUF_PER_PAGE) {
  		void *page = page_list[page_idx++];
+ 		dma_addr_t buf_addr;
  
- 		if (!page)
-@@ -198,13 +309,49 @@ mtk_wed_free_buffer(struct mtk_wed_device *dev)
+@@ -220,13 +335,64 @@ mtk_wed_free_buffer(struct mtk_wed_device *dev)
  		__free_page(page);
  	}
  
 -	dma_free_coherent(dev->hw->dev, dev->buf_ring.size * sizeof(*desc),
+-			  desc, dev->buf_ring.desc_phys);
 +	dma_free_coherent(dev->hw->dev, ring_size * sizeof(*desc),
- 			  desc, dev->buf_ring.desc_phys);
++			  desc, dev->tx_buf_ring.desc_phys);
  
  free_pagelist:
  	kfree(page_list);
  }
  
 +static int
-+mtk_wed_rx_bm_alloc(struct mtk_wed_device *dev)
++mtk_wed_rx_buffer_alloc(struct mtk_wed_device *dev)
 +{
 +	struct mtk_rxbm_desc *desc;
 +	dma_addr_t desc_phys;
-+	int ring_size;
 +
-+	ring_size = dev->wlan.rx_nbuf;
-+	dev->rx_buf_ring.size = ring_size;
-+	desc = dma_alloc_coherent(dev->hw->dev, ring_size * sizeof(*desc),
++	dev->rx_buf_ring.size = dev->wlan.rx_nbuf;
++	desc = dma_alloc_coherent(dev->hw->dev,
++				  dev->wlan.rx_nbuf * sizeof(*desc),
 +				  &desc_phys, GFP_KERNEL);
 +	if (!desc)
 +		return -ENOMEM;
 +
 +	dev->rx_buf_ring.desc = desc;
 +	dev->rx_buf_ring.desc_phys = desc_phys;
-+
 +	dev->wlan.init_rx_buf(dev, dev->wlan.rx_npkt);
++
 +	return 0;
 +}
 +
 +static void
-+mtk_wed_free_rx_bm(struct mtk_wed_device *dev)
++mtk_wed_free_rx_buffer(struct mtk_wed_device *dev)
 +{
 +	struct mtk_rxbm_desc *desc = dev->rx_buf_ring.desc;
-+	int ring_size = dev->rx_buf_ring.size;
 +
 +	if (!desc)
 +		return;
 +
 +	dev->wlan.release_rx_buf(dev);
 +
-+	dma_free_coherent(dev->hw->dev, ring_size * sizeof(*desc),
++	dma_free_coherent(dev->hw->dev, dev->rx_buf_ring.size * sizeof(*desc),
 +			  desc, dev->rx_buf_ring.desc_phys);
 +}
 +
++static void
++mtk_wed_rx_buffer_hw_init(struct mtk_wed_device *dev)
++{
++	wed_w32(dev, MTK_WED_RX_BM_RX_DMAD,
++		FIELD_PREP(MTK_WED_RX_BM_RX_DMAD_SDL0,  dev->wlan.rx_size));
++
++	wed_w32(dev, MTK_WED_RX_BM_BASE, dev->rx_buf_ring.desc_phys);
++
++	wed_w32(dev, MTK_WED_RX_BM_INIT_PTR, MTK_WED_RX_BM_INIT_SW_TAIL |
++		FIELD_PREP(MTK_WED_RX_BM_SW_TAIL, dev->wlan.rx_npkt));
++
++	wed_w32(dev, MTK_WED_RX_BM_DYN_ALLOC_TH,
++		FIELD_PREP(MTK_WED_RX_BM_DYN_ALLOC_TH_H, 0xffff));
++
++	wed_set(dev, MTK_WED_CTRL, MTK_WED_CTRL_WED_RX_BM_EN);
++}
++
  static void
- mtk_wed_free_ring(struct mtk_wed_device *dev, struct mtk_wed_ring *ring, int scale)
+ mtk_wed_free_ring(struct mtk_wed_device *dev, struct mtk_wed_ring *ring)
  {
-@@ -226,13 +373,22 @@ mtk_wed_free_tx_rings(struct mtk_wed_device *dev)
- 		mtk_wed_free_ring(dev, &dev->tx_wdma[i], dev->ver);
+@@ -237,6 +403,13 @@ mtk_wed_free_ring(struct mtk_wed_device *dev, struct mtk_wed_ring *ring)
+ 			  ring->desc, ring->desc_phys);
  }
  
 +static void
 +mtk_wed_free_rx_rings(struct mtk_wed_device *dev)
 +{
-+	mtk_wed_free_rx_bm(dev);
-+	mtk_wed_free_ring(dev, &dev->rro.rro_ring, 1);
++	mtk_wed_free_rx_buffer(dev);
++	mtk_wed_free_ring(dev, &dev->rro.ring);
 +}
 +
  static void
- mtk_wed_set_int(struct mtk_wed_device *dev, u32 irq_mask)
+ mtk_wed_free_tx_rings(struct mtk_wed_device *dev)
  {
- 	u32 wdma_mask;
- 
- 	wdma_mask = FIELD_PREP(MTK_WDMA_INT_MASK_RX_DONE, GENMASK(1, 0));
--
-+	if (dev->ver > MTK_WED_V1)
-+		wdma_mask |= FIELD_PREP(MTK_WDMA_INT_MASK_TX_DONE,
-+					GENMASK(1, 0));
- 	/* wed control cr set */
- 	wed_set(dev, MTK_WED_CTRL,
- 		MTK_WED_CTRL_WDMA_INT_AGENT_EN |
-@@ -251,7 +407,7 @@ mtk_wed_set_int(struct mtk_wed_device *dev, u32 irq_mask)
- 		wed_set(dev, MTK_WED_WPDMA_INT_CTRL,
- 			MTK_WED_WPDMA_INT_CTRL_SUBRT_ADV);
- 	} else {
--		/* initail tx interrupt trigger */
-+
- 		wed_w32(dev, MTK_WED_WPDMA_INT_CTRL_TX,
- 			MTK_WED_WPDMA_INT_CTRL_TX0_DONE_EN |
- 			MTK_WED_WPDMA_INT_CTRL_TX0_DONE_CLR |
-@@ -262,22 +418,30 @@ mtk_wed_set_int(struct mtk_wed_device *dev, u32 irq_mask)
- 			FIELD_PREP(MTK_WED_WPDMA_INT_CTRL_TX1_DONE_TRIG,
- 				   dev->wlan.tx_tbit[1]));
+@@ -244,8 +417,8 @@ mtk_wed_free_tx_rings(struct mtk_wed_device *dev)
  
--		/* initail txfree interrupt trigger */
- 		wed_w32(dev, MTK_WED_WPDMA_INT_CTRL_TX_FREE,
- 			MTK_WED_WPDMA_INT_CTRL_TX_FREE_DONE_EN |
- 			MTK_WED_WPDMA_INT_CTRL_TX_FREE_DONE_CLR |
- 			FIELD_PREP(MTK_WED_WPDMA_INT_CTRL_TX_FREE_DONE_TRIG,
- 				    dev->wlan.txfree_tbit));
-+
-+		wed_w32(dev, MTK_WED_WPDMA_INT_CTRL_RX,
-+			MTK_WED_WPDMA_INT_CTRL_RX0_EN |
-+			MTK_WED_WPDMA_INT_CTRL_RX0_CLR |
-+			MTK_WED_WPDMA_INT_CTRL_RX1_EN |
-+			MTK_WED_WPDMA_INT_CTRL_RX1_CLR |
-+			FIELD_PREP(MTK_WED_WPDMA_INT_CTRL_RX0_DONE_TRIG,
-+				   dev->wlan.rx_tbit[0]) |
-+			FIELD_PREP(MTK_WED_WPDMA_INT_CTRL_RX1_DONE_TRIG,
-+				   dev->wlan.rx_tbit[1]));
- 	}
--	/* initail wdma interrupt agent */
- 	wed_w32(dev, MTK_WED_WDMA_INT_TRIGGER, wdma_mask);
- 	if (dev->ver == MTK_WED_V1) {
- 		wed_clr(dev, MTK_WED_WDMA_INT_CTRL, wdma_mask);
- 	} else {
- 		wed_w32(dev, MTK_WED_WDMA_INT_CLR, wdma_mask);
- 		wed_set(dev, MTK_WED_WDMA_INT_CTRL,
--			FIELD_PREP(MTK_WED_WDMA_INT_POLL_SRC_SEL,dev->wdma_idx));
--
-+			FIELD_PREP(MTK_WED_WDMA_INT_POLL_SRC_SEL,
-+				   dev->wdma_idx));
- 	}
+ 	for (i = 0; i < ARRAY_SIZE(dev->tx_ring); i++)
+ 		mtk_wed_free_ring(dev, &dev->tx_ring[i]);
+-	for (i = 0; i < ARRAY_SIZE(dev->tx_wdma); i++)
+-		mtk_wed_free_ring(dev, &dev->tx_wdma[i]);
++	for (i = 0; i < ARRAY_SIZE(dev->rx_wdma); i++)
++		mtk_wed_free_ring(dev, &dev->rx_wdma[i]);
+ }
  
- 	wdma_w32(dev, MTK_WDMA_INT_MASK, wdma_mask);
-@@ -312,6 +476,40 @@ mtk_wed_set_512_support(struct mtk_wed_device *dev, bool en)
+ static void
+@@ -277,6 +450,39 @@ mtk_wed_set_512_support(struct mtk_wed_device *dev, bool enable)
  	}
  }
  
++#define MTK_WFMDA_RX_DMA_EN	BIT(2)
 +static void
 +mtk_wed_check_wfdma_rx_fill(struct mtk_wed_device *dev, int idx)
 +{
-+#define MTK_WFMDA_RX_DMA_EN 	BIT(2)
++	u32 val;
++	int i;
 +
-+	int timeout = 3;
-+	u32 cur_idx, regs;
++	if(!(dev->rx_ring[idx].flags & MTK_WED_RING_CONFIGURED))
++		return;
 +
-+	do {
-+		regs = MTK_WED_WPDMA_RING_RX_DATA(idx) +
-+		       MTK_WED_RING_OFS_CPU_IDX;
-+		cur_idx = wed_r32(dev, regs);
++	for (i = 0; i < 3; i++) {
++		u32 cur_idx;
++
++		cur_idx = wed_r32(dev,
++				  MTK_WED_WPDMA_RING_RX_DATA(idx) +
++				  MTK_WED_RING_OFS_CPU_IDX);
 +		if (cur_idx == MTK_WED_RX_RING_SIZE - 1)
 +			break;
 +
 +		usleep_range(100000, 200000);
-+		timeout--;
-+	} while (timeout > 0);
-+
-+	if (timeout) {
-+		unsigned int val;
-+
-+		val = wifi_r32(dev, dev->wlan.wpdma_rx_glo -
-+			       dev->wlan.phy_base);
-+		val |= MTK_WFMDA_RX_DMA_EN;
++	}
 +
-+		wifi_w32(dev, dev->wlan.wpdma_rx_glo -
-+			 dev->wlan.phy_base, val);
-+	} else {
++	if (i == 3) {
 +		dev_err(dev->hw->dev, "mtk_wed%d: rx dma enable failed!\n",
 +			       dev->hw->index);
++		return;
 +	}
++
++	val = wifi_r32(dev, dev->wlan.wpdma_rx_glo - dev->wlan.phy_base) |
++	      MTK_WFMDA_RX_DMA_EN;
++	wifi_w32(dev, dev->wlan.wpdma_rx_glo - dev->wlan.phy_base, val);
 +}
 +
  static void
- mtk_wed_dma_enable(struct mtk_wed_device *dev)
+ mtk_wed_dma_disable(struct mtk_wed_device *dev)
  {
-@@ -336,9 +534,15 @@ mtk_wed_dma_enable(struct mtk_wed_device *dev)
- 		wdma_set(dev, MTK_WDMA_GLO_CFG,
- 			 MTK_WDMA_GLO_CFG_RX_INFO3_PRERES);
- 	} else {
-+		int idx = 0;
-+
- 		wed_set(dev, MTK_WED_WPDMA_CTRL,
- 			MTK_WED_WPDMA_CTRL_SDL1_FIXED);
- 
-+		wed_set(dev, MTK_WED_WDMA_GLO_CFG,
-+			MTK_WED_WDMA_GLO_CFG_TX_DRV_EN |
-+			MTK_WED_WDMA_GLO_CFG_TX_DDONE_CHK);
-+
- 		wed_set(dev, MTK_WED_WPDMA_GLO_CFG,
- 			MTK_WED_WPDMA_GLO_CFG_RX_DRV_R0_PKT_PROC |
- 			MTK_WED_WPDMA_GLO_CFG_RX_DRV_R0_CRX_SYNC);
-@@ -346,6 +550,15 @@ mtk_wed_dma_enable(struct mtk_wed_device *dev)
- 		wed_clr(dev, MTK_WED_WPDMA_GLO_CFG,
- 			MTK_WED_WPDMA_GLO_CFG_TX_TKID_KEEP |
- 			MTK_WED_WPDMA_GLO_CFG_TX_DMAD_DW3_PREV);
-+
-+		wed_set(dev, MTK_WED_WPDMA_RX_D_GLO_CFG,
-+			MTK_WED_WPDMA_RX_D_RX_DRV_EN |
-+			FIELD_PREP(MTK_WED_WPDMA_RX_D_RXD_READ_LEN, 0x18) |
-+			FIELD_PREP(MTK_WED_WPDMA_RX_D_INIT_PHASE_RXEN_SEL,
-+				   0x2));
-+
-+		for (idx = 0; idx < MTK_WED_RX_QUEUES; idx++)
-+			mtk_wed_check_wfdma_rx_fill(dev, idx);
- 	}
- }
- 
-@@ -363,19 +576,23 @@ mtk_wed_dma_disable(struct mtk_wed_device *dev)
+@@ -291,22 +497,26 @@ mtk_wed_dma_disable(struct mtk_wed_device *dev)
  		MTK_WED_GLO_CFG_TX_DMA_EN |
  		MTK_WED_GLO_CFG_RX_DMA_EN);
  
@@ -586,7 +572,7 @@
 -		 MTK_WDMA_GLO_CFG_RX_INFO2_PRERES, 0);
 +		 MTK_WDMA_GLO_CFG_RX_INFO2_PRERES);
  
- 	if (dev->ver == MTK_WED_V1) {
+ 	if (dev->hw->version == 1) {
  		regmap_write(dev->hw->mirror, dev->hw->index * 4, 0);
 -		wdma_m32(dev, MTK_WDMA_GLO_CFG,
 -			 MTK_WDMA_GLO_CFG_RX_INFO3_PRERES, 0);
@@ -596,125 +582,169 @@
  		wed_clr(dev, MTK_WED_WPDMA_GLO_CFG,
  			MTK_WED_WPDMA_GLO_CFG_RX_DRV_R0_PKT_PROC |
  			MTK_WED_WPDMA_GLO_CFG_RX_DRV_R0_CRX_SYNC);
+-
+-		mtk_wed_set_512_support (dev, false)
 +		wed_clr(dev, MTK_WED_WPDMA_RX_D_GLO_CFG,
 +			MTK_WED_WPDMA_RX_D_RX_DRV_EN);
 +		wed_clr(dev, MTK_WED_WDMA_GLO_CFG,
 +			MTK_WED_WDMA_GLO_CFG_TX_DDONE_CHK);
  	}
++
++	mtk_wed_set_512_support (dev, false);
  }
  
-@@ -383,10 +600,12 @@ static void
- mtk_wed_stop(struct mtk_wed_device *dev)
- {
- 	mtk_wed_dma_disable(dev);
-+	mtk_wed_set_512_support(dev, false);
- 
--	if (dev->ver > MTK_WED_V1)
--		mtk_wed_set_512_support(dev, false);
--
-+	if (dev->ver > MTK_WED_V1) {
-+		wed_w32(dev, MTK_WED_EXT_INT_MASK1, 0);
-+		wed_w32(dev, MTK_WED_EXT_INT_MASK2, 0);
-+	}
- 	mtk_wed_set_ext_int(dev, false);
- 
- 	wed_clr(dev, MTK_WED_CTRL,
-@@ -395,6 +614,11 @@ mtk_wed_stop(struct mtk_wed_device *dev)
- 		MTK_WED_CTRL_WED_TX_BM_EN |
- 		MTK_WED_CTRL_WED_TX_FREE_AGENT_EN);
- 
-+	if (dev->ver > MTK_WED_V1) {
-+		wed_clr(dev, MTK_WED_CTRL,
-+			MTK_WED_CTRL_WED_RX_BM_EN);
-+	}
-+
- 	wed_w32(dev, MTK_WED_WPDMA_INT_TRIGGER, 0);
- 	wed_w32(dev, MTK_WED_WDMA_INT_TRIGGER, 0);
+ static void
+@@ -327,6 +537,14 @@ mtk_wed_stop(struct mtk_wed_device *dev)
  	wdma_w32(dev, MTK_WDMA_INT_MASK, 0);
-@@ -417,10 +641,21 @@ mtk_wed_detach(struct mtk_wed_device *dev)
+ 	wdma_w32(dev, MTK_WDMA_INT_GRP2, 0);
+ 	wed_w32(dev, MTK_WED_WPDMA_INT_MASK, 0);
++
++	if (dev->hw->version == 1)
++		return;
++
++	wed_w32(dev, MTK_WED_EXT_INT_MASK1, 0);
++	wed_w32(dev, MTK_WED_EXT_INT_MASK2, 0);
++	wed_clr(dev, MTK_WED_CTRL, MTK_WED_CTRL_WED_RX_BM_EN);
++
+ }
+ 
+ static void
+@@ -344,10 +562,23 @@ mtk_wed_detach(struct mtk_wed_device *dev)
  
  	mtk_wed_reset(dev, MTK_WED_RESET_WED);
  
-+	wdma_clr(dev, MTK_WDMA_GLO_CFG, MTK_WDMA_GLO_CFG_TX_DMA_EN);
-+	wdma_w32(dev, MTK_WDMA_RESET_IDX, MTK_WDMA_RESET_IDX_TX);
-+	wdma_w32(dev, MTK_WDMA_RESET_IDX, 0);
+-	mtk_wed_free_buffer(dev);
++	if (mtk_wed_get_rx_capa(dev)) {
++		wdma_clr(dev, MTK_WDMA_GLO_CFG, MTK_WDMA_GLO_CFG_TX_DMA_EN);
++		wdma_w32(dev, MTK_WDMA_RESET_IDX, MTK_WDMA_RESET_IDX_TX);
++		wdma_w32(dev, MTK_WDMA_RESET_IDX, 0);
++	}
 +
- 	mtk_wed_free_buffer(dev);
++	mtk_wed_free_tx_buffer(dev);
  	mtk_wed_free_tx_rings(dev);
-+	if (dev->ver > MTK_WED_V1) {
+ 
+-	if (dev->wlan.bus_type == MTK_BUS_TYPE_PCIE) {
++	if (mtk_wed_get_rx_capa(dev)) {
 +		mtk_wed_wo_reset(dev);
 +		mtk_wed_free_rx_rings(dev);
 +		mtk_wed_wo_exit(hw);
++		mtk_wdma_rx_reset(dev);
 +	}
 +
-+	mtk_wdma_rx_reset(dev);
- 
--	if (dev->wlan.bus_type == MTK_BUS_TYPE_PCIE) {
 +	if (dev->wlan.bus_type == MTK_WED_BUS_PCIE) {
  		wlan_node = dev->wlan.pci_dev->dev.of_node;
- 		if (of_dma_is_coherent(wlan_node))
+ 		if (of_dma_is_coherent(wlan_node) && hw->hifsys)
  			regmap_update_bits(hw->hifsys, HIFSYS_DMA_AG_MAP,
-@@ -443,7 +678,7 @@ mtk_wed_bus_init(struct mtk_wed_device *dev)
+@@ -370,7 +601,7 @@ static void
+ mtk_wed_bus_init(struct mtk_wed_device *dev)
  {
- #define PCIE_BASE_ADDR0 0x11280000
- 
--	if (dev->wlan.bus_type == MTK_BUS_TYPE_PCIE) {
-+	if (dev->wlan.bus_type == MTK_WED_BUS_PCIE) {
- 		struct device_node *node;
- 		void __iomem * base_addr;
- 		u32 value = 0;
-@@ -477,7 +712,6 @@ mtk_wed_bus_init(struct mtk_wed_device *dev)
- 		value = wed_r32(dev, MTK_WED_PCIE_CFG_INTM);
- 		value = wed_r32(dev, MTK_WED_PCIE_CFG_BASE);
- 
--		/* pcie interrupt status trigger register */
- 		wed_w32(dev, MTK_WED_PCIE_INT_TRIGGER, BIT(24));
- 		wed_r32(dev, MTK_WED_PCIE_INT_TRIGGER);
+ 	switch (dev->wlan.bus_type) {
+-	case MTK_BUS_TYPE_PCIE: {
++	case MTK_WED_BUS_PCIE: {
+ 		struct device_node *np = dev->hw->eth->dev->of_node;
+ 		struct regmap *regs;
  
-@@ -485,7 +719,7 @@ mtk_wed_bus_init(struct mtk_wed_device *dev)
- 		value = wed_r32(dev, MTK_WED_PCIE_INT_CTRL);
- 		wed_set(dev, MTK_WED_PCIE_INT_CTRL,
+@@ -402,7 +633,7 @@ mtk_wed_bus_init(struct mtk_wed_device *dev)
  			MTK_WED_PCIE_INT_CTRL_MSK_EN_POLA);
--	} else if (dev->wlan.bus_type == MTK_BUS_TYPE_AXI) {
-+	} else if (dev->wlan.bus_type == MTK_WED_BUS_AXI) {
+ 		break;
+ 	}
+-	case MTK_BUS_TYPE_AXI:
++	case MTK_WED_BUS_AXI:
  		wed_set(dev, MTK_WED_WPDMA_INT_CTRL,
  			MTK_WED_WPDMA_INT_CTRL_SIG_SRC |
  			FIELD_PREP(MTK_WED_WPDMA_INT_CTRL_SRC_SEL, 0));
-@@ -501,6 +735,9 @@ mtk_wed_set_wpdma(struct mtk_wed_device *dev)
+@@ -424,6 +655,8 @@ mtk_wed_set_wpdma(struct mtk_wed_device *dev)
  		wed_w32(dev, MTK_WED_WPDMA_CFG_INT_MASK,  dev->wlan.wpdma_mask);
  		wed_w32(dev, MTK_WED_WPDMA_CFG_TX,  dev->wlan.wpdma_tx);
  		wed_w32(dev, MTK_WED_WPDMA_CFG_TX_FREE,  dev->wlan.wpdma_txfree);
-+
 +		wed_w32(dev, MTK_WED_WPDMA_RX_GLO_CFG,  dev->wlan.wpdma_rx_glo);
 +		wed_w32(dev, MTK_WED_WPDMA_RX_RING,  dev->wlan.wpdma_rx);
- 	} else {
- 		wed_w32(dev, MTK_WED_WPDMA_CFG_BASE,  dev->wlan.wpdma_phys);
  	}
-@@ -549,24 +786,92 @@ mtk_wed_hw_init_early(struct mtk_wed_device *dev)
- 			FIELD_PREP(MTK_WED_WDMA_OFST1_RX_CTRL,
- 				   MTK_WDMA_RING_RX(0)));
- 	}
-+}
+ }
  
-+static void
-+mtk_wed_rx_bm_hw_init(struct mtk_wed_device *dev)
+@@ -470,6 +703,141 @@ mtk_wed_hw_init_early(struct mtk_wed_device *dev)
+ 
+ }
+ 
++static int
++mtk_wed_rro_ring_alloc(struct mtk_wed_device *dev, struct mtk_wed_ring *ring,
++		   int size)
 +{
-+	wed_w32(dev, MTK_WED_RX_BM_RX_DMAD,
-+		FIELD_PREP(MTK_WED_RX_BM_RX_DMAD_SDL0,  dev->wlan.rx_size));
++	ring->desc = dma_alloc_coherent(dev->hw->dev,
++					size * sizeof(*ring->desc),
++					&ring->desc_phys, GFP_KERNEL);
++	if (!ring->desc)
++		return -ENOMEM;
 +
-+	wed_w32(dev, MTK_WED_RX_BM_BASE, dev->rx_buf_ring.desc_phys);
++	ring->desc_size = sizeof(*ring->desc);
++	ring->size = size;
++	memset(ring->desc, 0, size);
 +
-+	wed_w32(dev, MTK_WED_RX_BM_INIT_PTR, MTK_WED_RX_BM_INIT_SW_TAIL |
-+		FIELD_PREP(MTK_WED_RX_BM_SW_TAIL, dev->wlan.rx_npkt));
++	return 0;
++}
 +
-+	wed_w32(dev, MTK_WED_RX_BM_DYN_ALLOC_TH,
-+		FIELD_PREP(MTK_WED_RX_BM_DYN_ALLOC_TH_H, 0xffff));
++#define MTK_WED_MIOD_COUNT	(MTK_WED_MIOD_ENTRY_CNT * MTK_WED_MIOD_CNT)
++static int
++mtk_wed_rro_alloc(struct mtk_wed_device *dev)
++{
++	struct device_node *np, *node = dev->hw->node;
++	struct mtk_wed_ring *ring;
++	struct resource res;
++	int ret;
 +
-+	wed_set(dev, MTK_WED_CTRL, MTK_WED_CTRL_WED_RX_BM_EN);
- }
- 
- static void
--mtk_wed_hw_init(struct mtk_wed_device *dev)
++	np = of_parse_phandle(node, "mediatek,wocpu_dlm", 0);
++	if (!np)
++		return -ENODEV;
++
++	ret = of_address_to_resource(np, 0, &res);
++	if (ret)
++		return ret;
++
++	dev->rro.rro_desc = ioremap(res.start, resource_size(&res));
++
++	ring = &dev->rro.ring;
++
++	dev->rro.miod_phys = res.start;
++	dev->rro.fdbk_phys = MTK_WED_MIOD_COUNT + dev->rro.miod_phys;
++
++	if (mtk_wed_rro_ring_alloc(dev, ring, MTK_WED_RRO_QUE_CNT))
++		return -ENOMEM;
++
++	return 0;
++}
++
++static int
++mtk_wed_rro_cfg(struct mtk_wed_device *dev)
++{
++	struct mtk_wed_wo *wo = dev->hw->wed_wo;
++	struct {
++		struct {
++			__le32 base;
++			__le32 cnt;
++			__le32 unit;
++		} ring[2];
++
++		__le32 wed;
++		u8 version;
++	} req = {
++		.ring[0] = {
++			.base = cpu_to_le32(MTK_WED_WOCPU_VIEW_MIOD_BASE),
++			.cnt = cpu_to_le32(MTK_WED_MIOD_CNT),
++			.unit = cpu_to_le32(MTK_WED_MIOD_ENTRY_CNT),
++		},
++		.ring[1] = {
++			.base = cpu_to_le32(MTK_WED_WOCPU_VIEW_MIOD_BASE +
++					    MTK_WED_MIOD_COUNT),
++			.cnt = cpu_to_le32(MTK_WED_FB_CMD_CNT),
++			.unit = cpu_to_le32(4),
++		},
++	};
++
++	return mtk_wed_mcu_send_msg(wo, MTK_WED_MODULE_ID_WO, MTK_WED_WO_CMD_WED_CFG,
++				    &req, sizeof(req), true);
++}
++
++static void
 +mtk_wed_rro_hw_init(struct mtk_wed_device *dev)
 +{
 +	wed_w32(dev, MTK_WED_RROQM_MIOD_CFG,
@@ -723,19 +753,19 @@
 +		FIELD_PREP(MTK_WED_RROQM_MIOD_ENTRY_DW,
 +			   MTK_WED_MIOD_ENTRY_CNT >> 2));
 +
-+	wed_w32(dev, MTK_WED_RROQM_MIOD_CTRL0, dev->rro.miod_desc_phys);
++	wed_w32(dev, MTK_WED_RROQM_MIOD_CTRL0, dev->rro.miod_phys);
 +
 +	wed_w32(dev, MTK_WED_RROQM_MIOD_CTRL1,
 +		FIELD_PREP(MTK_WED_RROQM_MIOD_CNT, MTK_WED_MIOD_CNT));
 +
-+	wed_w32(dev, MTK_WED_RROQM_FDBK_CTRL0, dev->rro.fdbk_desc_phys);
++	wed_w32(dev, MTK_WED_RROQM_FDBK_CTRL0, dev->rro.fdbk_phys);
 +
 +	wed_w32(dev, MTK_WED_RROQM_FDBK_CTRL1,
 +		FIELD_PREP(MTK_WED_RROQM_FDBK_CNT, MTK_WED_FB_CMD_CNT));
 +
 +	wed_w32(dev, MTK_WED_RROQM_FDBK_CTRL2, 0);
 +
-+	wed_w32(dev, MTK_WED_RROQ_BASE_L, dev->rro.rro_ring.desc_phys);
++	wed_w32(dev, MTK_WED_RROQ_BASE_L, dev->rro.ring.desc_phys);
 +
 +	wed_set(dev, MTK_WED_RROQM_RST_IDX,
 +		MTK_WED_RROQM_RST_IDX_MIOD |
@@ -753,12 +783,12 @@
 +{
 +	wed_w32(dev, MTK_WED_RESET, MTK_WED_RESET_RX_ROUTE_QM);
 +
-+	do {
-+		udelay(100);
++	for (;;) {
++		usleep_range(100, 200);
 +
 +		if (!(wed_r32(dev, MTK_WED_RESET) & MTK_WED_RESET_RX_ROUTE_QM))
 +			break;
-+	} while (1);
++	}
 +
 +	/* configure RX_ROUTE_QM */
 +	wed_clr(dev, MTK_WED_RTQM_GLO_CFG, MTK_WED_RTQM_Q_RST);
@@ -771,85 +801,109 @@
 +	wed_set(dev, MTK_WED_CTRL, MTK_WED_CTRL_RX_ROUTE_QM_EN);
 +}
 +
-+static void
-+mtk_wed_tx_hw_init(struct mtk_wed_device *dev)
+ static void
+ mtk_wed_hw_init(struct mtk_wed_device *dev)
  {
- 	int size = dev->buf_ring.size;
- 	int rev_size = MTK_WED_TX_RING_SIZE / 2;
- 	int thr = 1;
+@@ -479,7 +847,7 @@ mtk_wed_hw_init(struct mtk_wed_device *dev)
+ 	dev->init_done = true;
+ 	mtk_wed_set_ext_int(dev, false);
  
--	if (dev->init_done)
--		return;
--
--	dev->init_done = true;
--	mtk_wed_set_ext_int(dev, false);
--
- 	if (dev->ver > MTK_WED_V1) {
--		size = MTK_WED_WDMA_RING_SIZE * 2 + dev->buf_ring.size;
-+		size = MTK_WED_WDMA_RING_SIZE * ARRAY_SIZE(dev->tx_wdma) +
-+		       dev->buf_ring.size;
- 		rev_size = size;
- 		thr = 0;
- 	}
-@@ -609,13 +914,46 @@ mtk_wed_hw_init(struct mtk_wed_device *dev)
+-	wed_w32(dev, MTK_WED_TX_BM_BASE, dev->buf_ring.desc_phys);
++	wed_w32(dev, MTK_WED_TX_BM_BASE, dev->tx_buf_ring.desc_phys);
+ 
+ 	wed_w32(dev, MTK_WED_TX_BM_BUF_LEN, MTK_WED_PKT_SIZE);
+ 
+@@ -487,7 +855,7 @@ mtk_wed_hw_init(struct mtk_wed_device *dev)
+ 		wed_w32(dev, MTK_WED_TX_BM_CTRL,
+ 			MTK_WED_TX_BM_CTRL_PAUSE |
+ 			FIELD_PREP(MTK_WED_TX_BM_CTRL_VLD_GRP_NUM,
+-				   dev->buf_ring.size / 128) |
++				   dev->tx_buf_ring.size / 128) |
+ 			FIELD_PREP(MTK_WED_TX_BM_CTRL_RSV_GRP_NUM,
+ 				   MTK_WED_TX_RING_SIZE / 256));
+ 		wed_w32(dev, MTK_WED_TX_BM_TKID,
+@@ -503,9 +871,9 @@ mtk_wed_hw_init(struct mtk_wed_device *dev)
+ 		wed_w32(dev, MTK_WED_TX_BM_CTRL,
+ 			MTK_WED_TX_BM_CTRL_PAUSE |
+ 			FIELD_PREP(MTK_WED_TX_BM_CTRL_VLD_GRP_NUM,
+-				   dev->buf_ring.size / 128) |
++				   dev->tx_buf_ring.size / 128) |
+ 			FIELD_PREP(MTK_WED_TX_BM_CTRL_RSV_GRP_NUM,
+-				   dev->buf_ring.size / 128));
++				   dev->tx_buf_ring.size / 128));
+ 		wed_w32(dev, MTK_WED_TX_BM_TKID_V2,
+ 			FIELD_PREP(MTK_WED_TX_BM_TKID_START,
+ 				   dev->wlan.token_start) |
+@@ -518,9 +886,9 @@ mtk_wed_hw_init(struct mtk_wed_device *dev)
+ 		wed_w32(dev, MTK_WED_TX_TKID_CTRL,
+ 			MTK_WED_TX_TKID_CTRL_PAUSE |
+ 			FIELD_PREP(MTK_WED_TX_TKID_CTRL_VLD_GRP_NUM,
+-				   dev->buf_ring.size / 128) |
++				   dev->tx_buf_ring.size / 128) |
+ 			FIELD_PREP(MTK_WED_TX_TKID_CTRL_RSV_GRP_NUM,
+-				   dev->buf_ring.size / 128));
++				   dev->tx_buf_ring.size / 128));
+ 		wed_w32(dev, MTK_WED_TX_TKID_DYN_THR,
+ 			FIELD_PREP(MTK_WED_TX_TKID_DYN_THR_LO, 0) |
+ 			MTK_WED_TX_TKID_DYN_THR_HI);
+@@ -528,27 +896,42 @@ mtk_wed_hw_init(struct mtk_wed_device *dev)
+ 
+ 	mtk_wed_reset(dev, MTK_WED_RESET_TX_BM);
+ 
+-	if (dev->hw->version == 1)
++	if (dev->hw->version == 1) {
+ 		wed_set(dev, MTK_WED_CTRL,
+ 			MTK_WED_CTRL_WED_TX_BM_EN |
+ 			MTK_WED_CTRL_WED_TX_FREE_AGENT_EN);
+-	else
++	} else {
+ 		wed_clr(dev, MTK_WED_TX_TKID_CTRL, MTK_WED_TX_TKID_CTRL_PAUSE);
++		/* rx hw init*/
++		wed_w32(dev, MTK_WED_WPDMA_RX_D_RST_IDX,
++			MTK_WED_WPDMA_RX_D_RST_CRX_IDX |
++			MTK_WED_WPDMA_RX_D_RST_DRV_IDX);
++
++		wed_w32(dev, MTK_WED_WPDMA_RX_D_RST_IDX, 0);
++
++		mtk_wed_rx_buffer_hw_init(dev);
++		mtk_wed_rro_hw_init(dev);
++		mtk_wed_route_qm_hw_init(dev);
++	}
+ 
+ 	wed_clr(dev, MTK_WED_TX_BM_CTRL, MTK_WED_TX_BM_CTRL_PAUSE);
  }
  
  static void
--mtk_wed_ring_reset(struct mtk_wdma_desc *desc, int size, int scale)
-+mtk_wed_rx_hw_init(struct mtk_wed_device *dev)
+-mtk_wed_ring_reset(struct mtk_wed_ring *ring, int size)
++mtk_wed_ring_reset(struct mtk_wed_ring *ring, int size, bool tx)
  {
-+	wed_w32(dev, MTK_WED_WPDMA_RX_D_RST_IDX,
-+		MTK_WED_WPDMA_RX_D_RST_CRX_IDX |
-+		MTK_WED_WPDMA_RX_D_RST_DRV_IDX);
-+
-+	wed_w32(dev, MTK_WED_WPDMA_RX_D_RST_IDX, 0);
-+
-+	mtk_wed_rx_bm_hw_init(dev);
-+	mtk_wed_rro_hw_init(dev);
-+	mtk_wed_route_qm_hw_init(dev);
-+}
-+
-+static void
-+mtk_wed_hw_init(struct mtk_wed_device *dev)
-+{
-+	if (dev->init_done)
-+		return;
-+
-+	dev->init_done = true;
-+	mtk_wed_set_ext_int(dev, false);
-+	mtk_wed_tx_hw_init(dev);
-+	if (dev->ver > MTK_WED_V1)
-+		mtk_wed_rx_hw_init(dev);
-+}
-+
-+static void
-+mtk_wed_ring_reset(struct mtk_wdma_desc *desc, int size, int scale, bool tx)
-+{
-+	__le32 ctrl;
+ 	void *head = (void *)ring->desc;
  	int i;
  
-+	if (tx)
-+		ctrl = cpu_to_le32(MTK_WDMA_DESC_CTRL_DMA_DONE);
-+	else
-+		ctrl = cpu_to_le32(MTK_WFDMA_DESC_CTRL_TO_HOST);
-+
  	for (i = 0; i < size; i++) {
+ 		struct mtk_wdma_desc *desc;
++
+ 		desc = (struct mtk_wdma_desc *)(head + i * ring->desc_size);
  		desc->buf0 = 0;
 -		desc->ctrl = cpu_to_le32(MTK_WDMA_DESC_CTRL_DMA_DONE);
-+		desc->ctrl = ctrl;
++		if (tx)
++			desc->ctrl = cpu_to_le32(MTK_WDMA_DESC_CTRL_DMA_DONE);
++		else
++			desc->ctrl = cpu_to_le32(MTK_WFDMA_DESC_CTRL_TO_HOST);
  		desc->buf1 = 0;
  		desc->info = 0;
- 		desc += scale;
-@@ -674,7 +1012,7 @@ mtk_wed_reset_dma(struct mtk_wed_device *dev)
- 		if (!desc)
+ 	}
+@@ -604,7 +987,8 @@ mtk_wed_reset_dma(struct mtk_wed_device *dev)
+ 		if (!dev->tx_ring[i].desc)
  			continue;
  
--		mtk_wed_ring_reset(desc, MTK_WED_TX_RING_SIZE, dev->ver);
-+		mtk_wed_ring_reset(desc, MTK_WED_TX_RING_SIZE, dev->ver, true);
+-		mtk_wed_ring_reset(&dev->tx_ring[i], MTK_WED_TX_RING_SIZE);
++		mtk_wed_ring_reset(&dev->tx_ring[i], MTK_WED_TX_RING_SIZE,
++				   true);
  	}
  
  	if (mtk_wed_poll_busy(dev))
-@@ -692,6 +1030,8 @@ mtk_wed_reset_dma(struct mtk_wed_device *dev)
+@@ -622,6 +1006,8 @@ mtk_wed_reset_dma(struct mtk_wed_device *dev)
  	wdma_w32(dev, MTK_WDMA_RESET_IDX, MTK_WDMA_RESET_IDX_RX);
  	wdma_w32(dev, MTK_WDMA_RESET_IDX, 0);
  
@@ -858,38 +912,21 @@
  	if (busy) {
  		mtk_wed_reset(dev, MTK_WED_RESET_WDMA_INT_AGENT);
  		mtk_wed_reset(dev, MTK_WED_RESET_WDMA_RX_DRV);
-@@ -729,9 +1069,24 @@ mtk_wed_reset_dma(struct mtk_wed_device *dev)
- 
- }
+@@ -661,7 +1047,7 @@ mtk_wed_reset_dma(struct mtk_wed_device *dev)
  
-+static int
-+mtk_wed_rro_ring_alloc(struct mtk_wed_device *dev, struct mtk_wed_ring *ring,
-+		   int size)
-+{
-+	ring->desc = dma_alloc_coherent(dev->hw->dev,
-+					size * sizeof(*ring->desc),
-+					&ring->desc_phys, GFP_KERNEL);
-+	if (!ring->desc)
-+		return -ENOMEM;
-+
-+	ring->size = size;
-+	memset(ring->desc, 0, size);
-+	return 0;
-+}
-+
  static int
  mtk_wed_ring_alloc(struct mtk_wed_device *dev, struct mtk_wed_ring *ring,
--		   int size, int scale)
-+		   int size, int scale, bool tx)
+-		   int size, u32 desc_size)
++		   int size, u32 desc_size, bool tx)
  {
- 	ring->desc = dma_alloc_coherent(dev->hw->dev,
- 					size * sizeof(*ring->desc) * scale,
-@@ -740,17 +1095,18 @@ mtk_wed_ring_alloc(struct mtk_wed_device *dev, struct mtk_wed_ring *ring,
- 		return -ENOMEM;
+ 	ring->desc = dma_alloc_coherent(dev->hw->dev, size * desc_size,
+ 					&ring->desc_phys, GFP_KERNEL);
+@@ -670,18 +1056,23 @@ mtk_wed_ring_alloc(struct mtk_wed_device *dev, struct mtk_wed_ring *ring,
  
+ 	ring->desc_size = desc_size;
  	ring->size = size;
--	mtk_wed_ring_reset(ring->desc, size, scale);
-+	mtk_wed_ring_reset(ring->desc, size, scale, tx);
+-	mtk_wed_ring_reset(ring, size);
++	mtk_wed_ring_reset(ring, size, tx);
  
  	return 0;
  }
@@ -898,25 +935,36 @@
 -mtk_wed_wdma_ring_setup(struct mtk_wed_device *dev, int idx, int size)
 +mtk_wed_wdma_rx_ring_setup(struct mtk_wed_device *dev, int idx, int size)
  {
- 	struct mtk_wed_ring *wdma = &dev->tx_wdma[idx];
+ 	u32 desc_size = sizeof(struct mtk_wdma_desc) * dev->hw->version;
+-	struct mtk_wed_ring *wdma = &dev->tx_wdma[idx];
++	struct mtk_wed_ring *wdma;
  
--	if (mtk_wed_ring_alloc(dev, wdma, MTK_WED_WDMA_RING_SIZE, dev->ver))
-+	if (mtk_wed_ring_alloc(dev, wdma, MTK_WED_WDMA_RING_SIZE,
-+			       dev->ver, true))
+-	if (mtk_wed_ring_alloc(dev, wdma, MTK_WED_WDMA_RING_SIZE, desc_size))
++	if (idx >= ARRAY_SIZE(dev->rx_wdma))
++		return -EINVAL;
++
++	wdma = &dev->rx_wdma[idx];
++	if (mtk_wed_ring_alloc(dev, wdma, MTK_WED_WDMA_RING_SIZE, desc_size,
++			       true))
  		return -ENOMEM;
  
  	wdma_w32(dev, MTK_WDMA_RING_RX(idx) + MTK_WED_RING_OFS_BASE,
-@@ -767,22 +1123,143 @@ mtk_wed_wdma_ring_setup(struct mtk_wed_device *dev, int idx, int size)
+@@ -698,6 +1089,62 @@ mtk_wed_wdma_ring_setup(struct mtk_wed_device *dev, int idx, int size)
  	return 0;
  }
  
 +static int
 +mtk_wed_wdma_tx_ring_setup(struct mtk_wed_device *dev, int idx, int size)
 +{
-+	struct mtk_wed_ring *wdma = &dev->rx_wdma[idx];
++	u32 desc_size = sizeof(struct mtk_wdma_desc) * dev->hw->version;
++	struct mtk_wed_ring *wdma;
 +
++	if (idx >= ARRAY_SIZE(dev->tx_wdma))
++		return -EINVAL;
++
++	wdma = &dev->tx_wdma[idx];
 +	if (mtk_wed_ring_alloc(dev, wdma, MTK_WED_WDMA_RING_SIZE,
-+			       dev->ver, true))
++			       desc_size, true))
 +		return -ENOMEM;
 +
 +	wdma_w32(dev, MTK_WDMA_RING_TX(idx) + MTK_WED_RING_OFS_BASE,
@@ -928,136 +976,117 @@
 +	wdma_w32(dev,
 +		 MTK_WDMA_RING_TX(idx) + MTK_WED_RING_OFS_DMA_IDX, 0);
 +
-+	if (idx == 0)  {
-+		wed_w32(dev, MTK_WED_WDMA_RING_TX
-+			+ MTK_WED_RING_OFS_BASE, wdma->desc_phys);
-+		wed_w32(dev, MTK_WED_WDMA_RING_TX
-+			+ MTK_WED_RING_OFS_COUNT, size);
-+		wed_w32(dev, MTK_WED_WDMA_RING_TX
-+			+ MTK_WED_RING_OFS_CPU_IDX, 0);
-+		wed_w32(dev, MTK_WED_WDMA_RING_TX
-+			+ MTK_WED_RING_OFS_DMA_IDX, 0);
++	if (!idx)  {
++		wed_w32(dev, MTK_WED_WDMA_RING_TX + MTK_WED_RING_OFS_BASE,
++			wdma->desc_phys);
++		wed_w32(dev, MTK_WED_WDMA_RING_TX + MTK_WED_RING_OFS_COUNT,
++			size);
++		wed_w32(dev, MTK_WED_WDMA_RING_TX + MTK_WED_RING_OFS_CPU_IDX,
++			0);
++		wed_w32(dev, MTK_WED_WDMA_RING_TX + MTK_WED_RING_OFS_DMA_IDX,
++			0);
 +	}
 +
 +	return 0;
 +}
 +
-+static int
-+mtk_wed_rro_alloc(struct mtk_wed_device *dev)
++static void
++mtk_wed_ppe_check(struct mtk_wed_device *dev, struct sk_buff *skb,
++			u32 reason, u32 hash)
 +{
-+	struct device_node *np, *node = dev->hw->node;
-+	struct mtk_wed_ring *ring;
-+	struct resource res;
-+	int ret;
-+
-+	np = of_parse_phandle(node, "mediatek,wocpu_dlm", 0);
-+	if (!np)
-+		return -ENODEV;
-+
-+	ret = of_address_to_resource(np, 0, &res);
-+	if (ret)
-+		return ret;
-+
-+	dev->rro.rro_desc = ioremap(res.start, resource_size(&res));
-+
-+	ring = &dev->rro.rro_ring;
-+
-+	dev->rro.miod_desc_phys = res.start;
-+
-+	dev->rro.mcu_view_miod = MTK_WED_WOCPU_VIEW_MIOD_BASE;
-+	dev->rro.fdbk_desc_phys = MTK_WED_MIOD_ENTRY_CNT * MTK_WED_MIOD_CNT
-+				  + dev->rro.miod_desc_phys;
-+
-+	if (mtk_wed_rro_ring_alloc(dev, ring, MTK_WED_RRO_QUE_CNT))
-+		return -ENOMEM;
-+
-+	return 0;
-+}
++	struct mtk_eth *eth = dev->hw->eth;
++	struct ethhdr *eh;
 +
-+static int
-+mtk_wed_rro_cfg(struct mtk_wed_device *dev)
-+{
-+	struct mtk_wed_wo *wo = dev->hw->wed_wo;
-+	struct {
-+		struct wo_cmd_ring ring[2];
++	if (!skb)
++		return;
 +
-+		u32 wed;
-+		u8 ver;
-+	} req = {
-+		.ring = {
-+			[0] = {
-+				.q_base = dev->rro.mcu_view_miod,
-+				.cnt = MTK_WED_MIOD_CNT,
-+				.unit = MTK_WED_MIOD_ENTRY_CNT,
-+			},
-+			[1] = {
-+				.q_base = dev->rro.mcu_view_miod +
-+					  MTK_WED_MIOD_ENTRY_CNT *
-+					  MTK_WED_MIOD_CNT,
-+				.cnt = MTK_WED_FB_CMD_CNT,
-+				.unit = 4,
-+			},
-+		},
-+		.wed = 0,
-+	};
++	if (reason != MTK_PPE_CPU_REASON_HIT_UNBIND_RATE_REACHED)
++		return;
 +
-+	return mtk_wed_mcu_send_msg(wo, MODULE_ID_WO, MTK_WED_WO_CMD_WED_CFG,
-+				    &req, sizeof(req), true);
++	skb_set_mac_header(skb, 0);
++	eh = eth_hdr(skb);
++	skb->protocol = eh->h_proto;
++	mtk_ppe_check_skb(eth->ppe[dev->hw->index], skb, hash);	
 +}
 +
-+static int
-+mtk_wed_send_msg(struct mtk_wed_device *dev, int cmd_id, void *data, int len)
-+{
-+	struct mtk_wed_wo *wo = dev->hw->wed_wo;
-+
-+	if (dev->ver == MTK_WED_V1)
-+		return 0;
+ static void
+ mtk_wed_configure_irq(struct mtk_wed_device *dev, u32 irq_mask)
+ {
+@@ -720,6 +1167,8 @@ mtk_wed_configure_irq(struct mtk_wed_device *dev, u32 irq_mask)
+ 
+ 		wed_clr(dev, MTK_WED_WDMA_INT_CTRL, wdma_mask);
+ 	} else {
++		wdma_mask |= FIELD_PREP(MTK_WDMA_INT_MASK_TX_DONE,
++					GENMASK(1, 0));
+ 		/* initail tx interrupt trigger */
+ 		wed_w32(dev, MTK_WED_WPDMA_INT_CTRL_TX,
+ 			MTK_WED_WPDMA_INT_CTRL_TX0_DONE_EN |
+@@ -738,6 +1187,16 @@ mtk_wed_configure_irq(struct mtk_wed_device *dev, u32 irq_mask)
+ 			FIELD_PREP(MTK_WED_WPDMA_INT_CTRL_TX_FREE_DONE_TRIG,
+ 				    dev->wlan.txfree_tbit));
+ 
++		wed_w32(dev, MTK_WED_WPDMA_INT_CTRL_RX,
++			MTK_WED_WPDMA_INT_CTRL_RX0_EN |
++			MTK_WED_WPDMA_INT_CTRL_RX0_CLR |
++			MTK_WED_WPDMA_INT_CTRL_RX1_EN |
++			MTK_WED_WPDMA_INT_CTRL_RX1_CLR |
++			FIELD_PREP(MTK_WED_WPDMA_INT_CTRL_RX0_DONE_TRIG,
++				   dev->wlan.rx_tbit[0]) |
++			FIELD_PREP(MTK_WED_WPDMA_INT_CTRL_RX1_DONE_TRIG,
++				   dev->wlan.rx_tbit[1]));
 +
-+	return mtk_wed_mcu_send_msg(wo, MODULE_ID_WO, cmd_id, data, len, true);
-+}
+ 		wed_w32(dev, MTK_WED_WDMA_INT_CLR, wdma_mask);
+ 		wed_set(dev, MTK_WED_WDMA_INT_CTRL,
+ 			FIELD_PREP(MTK_WED_WDMA_INT_POLL_SRC_SEL,dev->wdma_idx));
+@@ -775,9 +1234,15 @@ mtk_wed_dma_enable(struct mtk_wed_device *dev)
+ 		wdma_set(dev, MTK_WDMA_GLO_CFG,
+ 			 MTK_WDMA_GLO_CFG_RX_INFO3_PRERES);
+ 	} else {
++		int i;
 +
-+static void
-+mtk_wed_ppe_check(struct mtk_wed_device *dev, struct sk_buff *skb,
-+			u32 reason, u32 hash)
-+{
-+	int idx = dev->hw->index;
-+	struct mtk_eth *eth = dev->hw->eth;
-+	struct ethhdr *eh;
+ 		wed_set(dev, MTK_WED_WPDMA_CTRL,
+ 			MTK_WED_WPDMA_CTRL_SDL1_FIXED);
+ 
++		wed_set(dev, MTK_WED_WDMA_GLO_CFG,
++			MTK_WED_WDMA_GLO_CFG_TX_DRV_EN |
++			MTK_WED_WDMA_GLO_CFG_TX_DDONE_CHK);
 +
-+	if (reason == MTK_PPE_CPU_REASON_HIT_UNBIND_RATE_REACHED) {
-+		if (!skb)
-+			return;
+ 		wed_set(dev, MTK_WED_WPDMA_GLO_CFG,
+ 			MTK_WED_WPDMA_GLO_CFG_RX_DRV_R0_PKT_PROC |
+ 			MTK_WED_WPDMA_GLO_CFG_RX_DRV_R0_CRX_SYNC);
+@@ -785,18 +1250,26 @@ mtk_wed_dma_enable(struct mtk_wed_device *dev)
+ 		wed_clr(dev, MTK_WED_WPDMA_GLO_CFG,
+ 			MTK_WED_WPDMA_GLO_CFG_TX_TKID_KEEP |
+ 			MTK_WED_WPDMA_GLO_CFG_TX_DMAD_DW3_PREV);
 +
-+		skb_set_mac_header(skb, 0);
-+		eh = eth_hdr(skb);
-+		skb->protocol = eh->h_proto;
-+		mtk_ppe_check_skb(eth->ppe[idx], skb, hash);
-+	}
-+}
++		wed_set(dev, MTK_WED_WPDMA_RX_D_GLO_CFG,
++			MTK_WED_WPDMA_RX_D_RX_DRV_EN |
++			FIELD_PREP(MTK_WED_WPDMA_RX_D_RXD_READ_LEN, 0x18) |
++			FIELD_PREP(MTK_WED_WPDMA_RX_D_INIT_PHASE_RXEN_SEL,
++				   0x2));
 +
++		for (i = 0; i < MTK_WED_RX_QUEUES; i++)
++			mtk_wed_check_wfdma_rx_fill(dev, i);
+ 	}
+ }
+ 
  static void
  mtk_wed_start(struct mtk_wed_device *dev, u32 irq_mask)
  {
 -	u32 wdma_mask;
--	int i;
-+	int i, ret;
+ 	int i;
  
- 	for (i = 0; i < ARRAY_SIZE(dev->tx_wdma); i++)
- 		if (!dev->tx_wdma[i].desc)
+-	for (i = 0; i < ARRAY_SIZE(dev->tx_wdma); i++)
+-		if (!dev->tx_wdma[i].desc)
 -			mtk_wed_wdma_ring_setup(dev, i, 16);
--
++	for (i = 0; i < ARRAY_SIZE(dev->rx_wdma); i++)
++		if (!dev->rx_wdma[i].desc)
 +			mtk_wed_wdma_rx_ring_setup(dev, i, 16);
  
- 	mtk_wed_hw_init(dev);
- 
- 	mtk_wed_set_int(dev, irq_mask);
--
--
- 	mtk_wed_set_ext_int(dev, true);
  
- 	if (dev->ver == MTK_WED_V1) {
-@@ -797,8 +1274,20 @@ mtk_wed_start(struct mtk_wed_device *dev, u32 irq_mask)
- 		val |= BIT(0);
+ 	mtk_wed_hw_init(dev);
+@@ -813,9 +1286,22 @@ mtk_wed_start(struct mtk_wed_device *dev, u32 irq_mask)
+ 		val |= BIT(0) | (BIT(1) * !!dev->hw->index);
  		regmap_write(dev->hw->mirror, dev->hw->index * 4, val);
  	} else {
 -		mtk_wed_set_512_support(dev, dev->wlan.wcid_512);
@@ -1070,75 +1099,83 @@
 +		wed_r32(dev, MTK_WED_EXT_INT_MASK1);
 +		wed_r32(dev, MTK_WED_EXT_INT_MASK2);
 +
-+		ret = mtk_wed_rro_cfg(dev);
-+		if (ret)
++		if (mtk_wed_rro_cfg(dev))
 +			return;
++
  	}
-+	mtk_wed_set_512_support(dev, dev->wlan.wcid_512);
  
++	mtk_wed_set_512_support(dev, dev->wlan.wcid_512);
++
  	mtk_wed_dma_enable(dev);
  	dev->running = true;
-@@ -809,6 +1298,7 @@ mtk_wed_attach(struct mtk_wed_device *dev)
- 	__releases(RCU)
- {
- 	struct mtk_wed_hw *hw;
-+	struct device *device;
- 	u16 ver;
- 	int ret = 0;
- 
-@@ -829,6 +1319,12 @@ mtk_wed_attach(struct mtk_wed_device *dev)
- 		goto out;
+ }
+@@ -844,7 +1330,7 @@ mtk_wed_attach(struct mtk_wed_device *dev)
+ 	if (!hw) {
+ 		module_put(THIS_MODULE);
+ 		ret = -ENODEV;
+-		goto out;
++		goto unlock;
  	}
  
-+	device = dev->wlan.bus_type == MTK_WED_BUS_PCIE
-+	? &dev->wlan.pci_dev->dev
-+	: &dev->wlan.platform_dev->dev;
-+	dev_info(device, "attaching wed device %d version %d\n",
-+		 hw->index, hw->ver);
-+
- 	dev->hw = hw;
+ 	device = dev->wlan.bus_type == MTK_WED_BUS_PCIE ?
+@@ -856,26 +1342,40 @@ mtk_wed_attach(struct mtk_wed_device *dev)
  	dev->dev = hw->dev;
  	dev->irq = hw->irq;
-@@ -847,9 +1343,17 @@ mtk_wed_attach(struct mtk_wed_device *dev)
- 	dev->rev_id = ((dev->ver << 28) | ver << 16);
+ 	dev->wdma_idx = hw->index;
++	dev->version = hw->version;
+ 
+ 	if (hw->eth->dma_dev == hw->eth->dev &&
+ 	    of_dma_is_coherent(hw->eth->dev->of_node))
+ 		mtk_eth_set_dma_device(hw->eth, hw->dev);
  
- 	ret = mtk_wed_buffer_alloc(dev);
+-	ret = mtk_wed_buffer_alloc(dev);
 -	if (ret) {
 -		mtk_wed_detach(dev);
--		goto out;
++	ret = mtk_wed_tx_buffer_alloc(dev);
 +	if (ret)
-+		goto error;
+ 		goto out;
+-	}
 +
-+	if (dev->ver > MTK_WED_V1) {
-+		ret = mtk_wed_rx_bm_alloc(dev);
++	if (mtk_wed_get_rx_capa(dev)) {
++		ret = mtk_wed_rx_buffer_alloc(dev);
 +		if (ret)
-+			goto error;
++			goto out;
 +
 +		ret = mtk_wed_rro_alloc(dev);
 +		if (ret)
-+			goto error;
- 	}
++			goto out;
++ 	}
  
  	mtk_wed_hw_init_early(dev);
-@@ -857,7 +1361,12 @@ mtk_wed_attach(struct mtk_wed_device *dev)
- 	if (dev->ver == MTK_WED_V1)
+ 
+-	if (hw->version == 1)
++	if (hw->version == 1) {
  		regmap_update_bits(hw->hifsys, HIFSYS_DMA_AG_MAP,
  				   BIT(hw->index), 0);
-+	else
+-	else
++	} else {
+ 		dev->rev_id = wed_r32(dev, MTK_WED_REV_ID);
 +		ret = mtk_wed_wo_init(hw);
++	}
  
-+error:
+ out:
 +	if (ret)
 +		mtk_wed_detach(dev);
- out:
++unlock:
  	mutex_unlock(&hw_lock);
  
-@@ -883,10 +1392,10 @@ mtk_wed_tx_ring_setup(struct mtk_wed_device *dev, int idx, void __iomem *regs)
+ 	return ret;
+@@ -898,13 +1398,14 @@ mtk_wed_tx_ring_setup(struct mtk_wed_device *dev, int idx, void __iomem *regs)
+ 	 * WDMA RX.
+ 	 */
  
- 	BUG_ON(idx > ARRAY_SIZE(dev->tx_ring));
+-	BUG_ON(idx >= ARRAY_SIZE(dev->tx_ring));
++	if (WARN_ON(idx >= ARRAY_SIZE(dev->tx_ring)))
++		return -EINVAL;
  
--	if (mtk_wed_ring_alloc(dev, ring, MTK_WED_TX_RING_SIZE, 1))
-+	if (mtk_wed_ring_alloc(dev, ring, MTK_WED_TX_RING_SIZE, 1, true))
+ 	if (mtk_wed_ring_alloc(dev, ring, MTK_WED_TX_RING_SIZE,
+-			       sizeof(*ring->desc)))
++			       sizeof(*ring->desc), true))
  		return -ENOMEM;
  
 -	if (mtk_wed_wdma_ring_setup(dev, idx, MTK_WED_WDMA_RING_SIZE))
@@ -1146,7 +1183,7 @@
  		return -ENOMEM;
  
  	ring->reg_base = MTK_WED_RING_TX(idx);
-@@ -933,6 +1442,35 @@ mtk_wed_txfree_ring_setup(struct mtk_wed_device *dev, void __iomem *regs)
+@@ -948,6 +1449,37 @@ mtk_wed_txfree_ring_setup(struct mtk_wed_device *dev, void __iomem *regs)
  	return 0;
  }
  
@@ -1155,10 +1192,11 @@
 +{
 +	struct mtk_wed_ring *ring = &dev->rx_ring[idx];
 +
-+	BUG_ON(idx > ARRAY_SIZE(dev->rx_ring));
-+
++	if (WARN_ON(idx >= ARRAY_SIZE(dev->rx_ring)))
++		return -EINVAL;
 +
-+	if (mtk_wed_ring_alloc(dev, ring, MTK_WED_RX_RING_SIZE, 1, false))
++	if (mtk_wed_ring_alloc(dev, ring, MTK_WED_RX_RING_SIZE,
++			       sizeof(*ring->desc), false))
 +		return -ENOMEM;
 +
 +	if (mtk_wed_wdma_tx_ring_setup(dev, idx, MTK_WED_WDMA_RING_SIZE))
@@ -1166,6 +1204,7 @@
 +
 +	ring->reg_base = MTK_WED_RING_RX_DATA(idx);
 +	ring->wpdma = regs;
++	ring->flags |= MTK_WED_RING_CONFIGURED;
 +
 +	/* WPDMA ->  WED */
 +	wpdma_rx_w32(dev, idx, MTK_WED_RING_OFS_BASE, ring->desc_phys);
@@ -1182,16 +1221,17 @@
  static u32
  mtk_wed_irq_get(struct mtk_wed_device *dev, u32 mask)
  {
-@@ -1022,6 +1560,8 @@ void mtk_wed_add_hw(struct device_node *np, struct mtk_eth *eth,
+@@ -1037,7 +1569,9 @@ void mtk_wed_add_hw(struct device_node *np, struct mtk_eth *eth,
+ 	static const struct mtk_wed_ops wed_ops = {
  		.attach = mtk_wed_attach,
  		.tx_ring_setup = mtk_wed_tx_ring_setup,
- 		.txfree_ring_setup = mtk_wed_txfree_ring_setup,
 +		.rx_ring_setup = mtk_wed_rx_ring_setup,
-+		.msg_update = mtk_wed_send_msg,
+ 		.txfree_ring_setup = mtk_wed_txfree_ring_setup,
++		.msg_update = mtk_wed_mcu_msg_update,
  		.start = mtk_wed_start,
  		.stop = mtk_wed_stop,
  		.reset_dma = mtk_wed_reset_dma,
-@@ -1030,6 +1570,7 @@ void mtk_wed_add_hw(struct device_node *np, struct mtk_eth *eth,
+@@ -1046,6 +1580,7 @@ void mtk_wed_add_hw(struct device_node *np, struct mtk_eth *eth,
  		.irq_get = mtk_wed_irq_get,
  		.irq_set_mask = mtk_wed_irq_set_mask,
  		.detach = mtk_wed_detach,
@@ -1199,24 +1239,8 @@
  	};
  	struct device_node *eth_np = eth->dev->of_node;
  	struct platform_device *pdev;
-@@ -1069,6 +1610,7 @@ void mtk_wed_add_hw(struct device_node *np, struct mtk_eth *eth,
- 	hw->wdma_phy = wdma_phy;
- 	hw->index = index;
- 	hw->irq = irq;
-+	hw->ver = MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V2) ? 2 : 1;
- 
- 	if (!MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V2)) {
- 		hw->mirror = syscon_regmap_lookup_by_phandle(eth_np,
-@@ -1085,6 +1627,7 @@ void mtk_wed_add_hw(struct device_node *np, struct mtk_eth *eth,
- 			regmap_write(hw->mirror, 0, 0);
- 			regmap_write(hw->mirror, 4, 0);
- 		}
-+		hw->ver = MTK_WED_V1;
- 	}
- 
- 	mtk_wed_hw_add_debugfs(hw);
 diff --git a/drivers/net/ethernet/mediatek/mtk_wed.h b/drivers/net/ethernet/mediatek/mtk_wed.h
-index 9b17b74..8ef5253 100644
+index c9a20e4..1bfd96f 100644
 --- a/drivers/net/ethernet/mediatek/mtk_wed.h
 +++ b/drivers/net/ethernet/mediatek/mtk_wed.h
 @@ -13,6 +13,7 @@
@@ -1236,29 +1260,22 @@
 +#define MTK_WED_RRO_QUE_CNT		8192
 +#define MTK_WED_MIOD_ENTRY_CNT		128
 +
-+#define MODULE_ID_WO		1
++#define MTK_WED_MODULE_ID_WO		1
  
  struct mtk_eth;
 +struct mtk_wed_wo;
  
  struct mtk_wed_hw {
  	struct device_node *node;
-@@ -34,12 +42,14 @@ struct mtk_wed_hw {
+@@ -35,6 +43,7 @@ struct mtk_wed_hw {
  	struct regmap *mirror;
  	struct dentry *debugfs_dir;
  	struct mtk_wed_device *wed_dev;
 +	struct mtk_wed_wo *wed_wo;
  	u32 debugfs_reg;
  	u32 num_flows;
- 	u32 wdma_phy;
- 	char dirname[5];
- 	int irq;
- 	int index;
-+	u32 ver;
- };
- 
- struct mtk_wdma_info {
-@@ -66,6 +76,18 @@ wed_r32(struct mtk_wed_device *dev, u32 reg)
+ 	u8 version;
+@@ -67,6 +76,18 @@ wed_r32(struct mtk_wed_device *dev, u32 reg)
  	return val;
  }
  
@@ -1277,8 +1294,8 @@
  static inline void
  wdma_w32(struct mtk_wed_device *dev, u32 reg, u32 val)
  {
-@@ -114,6 +136,23 @@ wpdma_txfree_w32(struct mtk_wed_device *dev, u32 reg, u32 val)
- 	writel(val, dev->txfree_ring.wpdma + reg);
+@@ -97,6 +118,24 @@ wpdma_tx_w32(struct mtk_wed_device *dev, int ring, u32 reg, u32 val)
+ 	writel(val, dev->tx_ring[ring].wpdma + reg);
  }
  
 +static inline u32
@@ -1298,10 +1315,11 @@
 +
 +	writel(val, dev->rx_ring[ring].wpdma + reg);
 +}
- void mtk_wed_add_hw(struct device_node *np, struct mtk_eth *eth,
- 		    void __iomem *wdma, u32 wdma_phy, int index);
- void mtk_wed_exit(void);
-@@ -146,4 +185,16 @@ static inline void mtk_wed_hw_add_debugfs(struct mtk_wed_hw *hw)
++
+ static inline u32
+ wpdma_txfree_r32(struct mtk_wed_device *dev, u32 reg)
+ {
+@@ -149,4 +188,16 @@ static inline void mtk_wed_hw_add_debugfs(struct mtk_wed_hw *hw)
  }
  #endif
  
@@ -1509,7 +1527,7 @@
 +
 +#endif
 diff --git a/drivers/net/ethernet/mediatek/mtk_wed_debugfs.c b/drivers/net/ethernet/mediatek/mtk_wed_debugfs.c
-index f420f18..4a9e684 100644
+index f420f18..7d8be99 100644
 --- a/drivers/net/ethernet/mediatek/mtk_wed_debugfs.c
 +++ b/drivers/net/ethernet/mediatek/mtk_wed_debugfs.c
 @@ -2,6 +2,7 @@
@@ -1645,16 +1663,16 @@
  	debugfs_create_file_unsafe("regval", 0600, dir, hw, &fops_regval);
  	debugfs_create_file_unsafe("txinfo", 0400, dir, hw, &wed_txinfo_fops);
 +	debugfs_create_file_unsafe("rxinfo", 0400, dir, hw, &wed_rxinfo_fops);
-+	if (hw->ver != MTK_WED_V1) {
++	if (hw->version != 1) {
 +		wed_wo_mcu_debugfs(hw, dir);
 +	}
  }
 diff --git a/drivers/net/ethernet/mediatek/mtk_wed_mcu.c b/drivers/net/ethernet/mediatek/mtk_wed_mcu.c
 new file mode 100644
-index 0000000..96e30a3
+index 0000000..be63406
 --- /dev/null
 +++ b/drivers/net/ethernet/mediatek/mtk_wed_mcu.c
-@@ -0,0 +1,590 @@
+@@ -0,0 +1,604 @@
 +// SPDX-License-Identifier: GPL-2.0-only
 +
 +#include <linux/skbuff.h>
@@ -1743,6 +1761,20 @@
 +	return ret;
 +}
 +
++int
++mtk_wed_mcu_msg_update(struct mtk_wed_device *dev, int id, void *data, int len)
++{
++	struct mtk_wed_wo *wo = dev->hw->wed_wo;
++
++	if (dev->hw->version == 1)
++		return 0;
++
++	if (WARN_ON(!wo))
++		return -ENODEV;
++
++	return mtk_wed_mcu_send_msg(wo, MTK_WED_MODULE_ID_WO, id, data, len, true);
++}
++
 +void mtk_wed_mcu_rx_event(struct mtk_wed_wo *wo,
 +			struct sk_buff *skb)
 +{
@@ -1804,7 +1836,7 @@
 +	req.arg0 = (u32)exp->phys;
 +	req.arg1 = (u32)exp->log_size;
 +
-+	return mtk_wed_mcu_send_msg(wo, MODULE_ID_WO, MTK_WED_WO_CMD_EXCEPTION_INIT,
++	return mtk_wed_mcu_send_msg(wo, MTK_WED_MODULE_ID_WO, MTK_WED_WO_CMD_EXCEPTION_INIT,
 +				    &req, sizeof(req), false);
 +
 +free:
@@ -2030,7 +2062,7 @@
 +	hdr->length = cpu_to_le16(skb->len);
 +	hdr->uni_id = seq;
 +
-+	if (to_id == MODULE_ID_WO)
++	if (to_id == MTK_WED_MODULE_ID_WO)
 +		hdr->flag |= WARP_CMD_FLAG_FROM_TO_WO;
 +
 +	if (wait_resp && wait_seq)
@@ -2225,7 +2257,7 @@
 +		return count;
 +	}
 +
-+	mtk_wed_mcu_send_msg(wo, MODULE_ID_WO, cmd_id, (void *)msgbuf, sizeof(struct wo_cmd_query), wait);
++	mtk_wed_mcu_send_msg(wo, MTK_WED_MODULE_ID_WO, cmd_id, (void *)msgbuf, sizeof(struct wo_cmd_query), wait);
 +
 +	return count;
 +
@@ -2247,7 +2279,7 @@
 +
 diff --git a/drivers/net/ethernet/mediatek/mtk_wed_mcu.h b/drivers/net/ethernet/mediatek/mtk_wed_mcu.h
 new file mode 100644
-index 0000000..19e1199
+index 0000000..dbb17ae
 --- /dev/null
 +++ b/drivers/net/ethernet/mediatek/mtk_wed_mcu.h
 @@ -0,0 +1,97 @@
@@ -2349,19 +2381,18 @@
 +
 +#endif
 diff --git a/drivers/net/ethernet/mediatek/mtk_wed_regs.h b/drivers/net/ethernet/mediatek/mtk_wed_regs.h
-index 14e0e21..31871f7 100644
+index e797e9d..a79305f 100644
 --- a/drivers/net/ethernet/mediatek/mtk_wed_regs.h
 +++ b/drivers/net/ethernet/mediatek/mtk_wed_regs.h
-@@ -4,6 +4,8 @@
+@@ -4,6 +4,7 @@
  #ifndef __MTK_WED_REGS_H
  #define __MTK_WED_REGS_H
  
 +#define MTK_WFDMA_DESC_CTRL_TO_HOST		BIT(8)
-+
- #if defined(CONFIG_MEDIATEK_NETSYS_V2)
- #define MTK_WDMA_DESC_CTRL_LEN1			GENMASK(13, 0)
- #define MTK_WDMA_DESC_CTRL_LAST_SEG1		BIT(14)
-@@ -16,6 +18,7 @@
+ #define MTK_WDMA_DESC_CTRL_LEN1			GENMASK(14, 0)
+ #define MTK_WDMA_DESC_CTRL_LEN1_V2		GENMASK(13, 0)
+ #define MTK_WDMA_DESC_CTRL_LAST_SEG1		BIT(15)
+@@ -11,6 +12,7 @@
  #define MTK_WDMA_DESC_CTRL_LEN0			GENMASK(29, 16)
  #define MTK_WDMA_DESC_CTRL_LAST_SEG0		BIT(30)
  #define MTK_WDMA_DESC_CTRL_DMA_DONE		BIT(31)
@@ -2369,7 +2400,7 @@
  
  struct mtk_wdma_desc {
  	__le32 buf0;
-@@ -42,6 +45,8 @@ struct mtk_wdma_desc {
+@@ -37,6 +39,8 @@ struct mtk_wdma_desc {
  #define MTK_WED_RESET_WED_TX_DMA			BIT(12)
  #define MTK_WED_RESET_WDMA_RX_DRV			BIT(17)
  #define MTK_WED_RESET_WDMA_INT_AGENT			BIT(19)
@@ -2378,7 +2409,7 @@
  #define MTK_WED_RESET_WED				BIT(31)
  
  #define MTK_WED_CTRL					0x00c
-@@ -53,8 +58,12 @@ struct mtk_wdma_desc {
+@@ -48,8 +52,12 @@ struct mtk_wdma_desc {
  #define MTK_WED_CTRL_WED_TX_BM_BUSY			BIT(9)
  #define MTK_WED_CTRL_WED_TX_FREE_AGENT_EN		BIT(10)
  #define MTK_WED_CTRL_WED_TX_FREE_AGENT_BUSY		BIT(11)
@@ -2393,7 +2424,7 @@
  #define MTK_WED_CTRL_FINAL_DIDX_READ			BIT(24)
  #define MTK_WED_CTRL_ETH_DMAD_FMT			BIT(25)
  #define MTK_WED_CTRL_MIB_READ_CLEAR			BIT(28)
-@@ -69,8 +78,8 @@ struct mtk_wdma_desc {
+@@ -64,8 +72,8 @@ struct mtk_wdma_desc {
  #define MTK_WED_EXT_INT_STATUS_TX_TKID_LO_TH		BIT(10)
  #define MTK_WED_EXT_INT_STATUS_TX_TKID_HI_TH		BIT(11)
  #endif
@@ -2404,7 +2435,7 @@
  #define MTK_WED_EXT_INT_STATUS_RX_DRV_R_RESP_ERR	BIT(16)
  #define MTK_WED_EXT_INT_STATUS_RX_DRV_W_RESP_ERR	BIT(17)
  #define MTK_WED_EXT_INT_STATUS_RX_DRV_COHERENT		BIT(18)
-@@ -87,8 +96,8 @@ struct mtk_wdma_desc {
+@@ -82,8 +90,8 @@ struct mtk_wdma_desc {
  #define MTK_WED_EXT_INT_STATUS_ERROR_MASK		(MTK_WED_EXT_INT_STATUS_TF_LEN_ERR | \
  							 MTK_WED_EXT_INT_STATUS_TKID_WO_PYLD | \
  							 MTK_WED_EXT_INT_STATUS_TKID_TITO_INVALID | \
@@ -2415,7 +2446,7 @@
  							 MTK_WED_EXT_INT_STATUS_RX_DRV_R_RESP_ERR | \
  							 MTK_WED_EXT_INT_STATUS_RX_DRV_W_RESP_ERR | \
  							 MTK_WED_EXT_INT_STATUS_RX_DRV_INIT_WDMA_EN | \
-@@ -96,6 +105,8 @@ struct mtk_wdma_desc {
+@@ -91,6 +99,8 @@ struct mtk_wdma_desc {
  							 MTK_WED_EXT_INT_STATUS_TX_DMA_W_RESP_ERR)
  
  #define MTK_WED_EXT_INT_MASK				0x028
@@ -2424,7 +2455,7 @@
  
  #define MTK_WED_STATUS					0x060
  #define MTK_WED_STATUS_TX				GENMASK(15, 8)
-@@ -183,6 +194,9 @@ struct mtk_wdma_desc {
+@@ -172,6 +182,9 @@ struct mtk_wdma_desc {
  
  #define MTK_WED_RING_RX(_n)				(0x400 + (_n) * 0x10)
  
@@ -2434,7 +2465,7 @@
  #define MTK_WED_WPDMA_INT_TRIGGER			0x504
  #define MTK_WED_WPDMA_INT_TRIGGER_RX_DONE		BIT(1)
  #define MTK_WED_WPDMA_INT_TRIGGER_TX_DONE		GENMASK(5, 4)
-@@ -239,13 +253,19 @@ struct mtk_wdma_desc {
+@@ -228,13 +241,19 @@ struct mtk_wdma_desc {
  
  #define MTK_WED_WPDMA_INT_CTRL_TX			0x530
  #define MTK_WED_WPDMA_INT_CTRL_TX0_DONE_EN 		BIT(0)
@@ -2455,7 +2486,7 @@
  
  #define MTK_WED_WPDMA_INT_CTRL_TX_FREE			0x538
  #define MTK_WED_WPDMA_INT_CTRL_TX_FREE_DONE_EN		BIT(0)
-@@ -270,13 +290,40 @@ struct mtk_wdma_desc {
+@@ -259,13 +278,40 @@ struct mtk_wdma_desc {
  #define MTK_WED_WPDMA_TX_MIB(_n)			(0x5a0 + (_n) * 4)
  #define MTK_WED_WPDMA_TX_COHERENT_MIB(_n)		(0x5d0 + (_n) * 4)
  
@@ -2496,7 +2527,7 @@
  #define MTK_WED_WDMA_GLO_CFG_RX_DRV_EN			BIT(2)
  #define MTK_WED_WDMA_GLO_CFG_RX_DRV_BUSY		BIT(3)
  #define MTK_WED_WDMA_GLO_CFG_BT_SIZE			GENMASK(5, 4)
-@@ -320,6 +367,20 @@ struct mtk_wdma_desc {
+@@ -309,6 +355,20 @@ struct mtk_wdma_desc {
  #define MTK_WED_WDMA_RX_RECYCLE_MIB(_n)			(0xae8 + (_n) * 4)
  #define MTK_WED_WDMA_RX_PROCESSED_MIB(_n)		(0xaf0 + (_n) * 4)
  
@@ -2517,7 +2548,7 @@
  #define MTK_WED_RING_OFS_BASE				0x00
  #define MTK_WED_RING_OFS_COUNT				0x04
  #define MTK_WED_RING_OFS_CPU_IDX			0x08
-@@ -330,12 +391,13 @@ struct mtk_wdma_desc {
+@@ -319,12 +379,13 @@ struct mtk_wdma_desc {
  
  #define MTK_WDMA_GLO_CFG				0x204
  #define MTK_WDMA_GLO_CFG_TX_DMA_EN			BIT(0)
@@ -2532,7 +2563,7 @@
  #define MTK_WDMA_RESET_IDX				0x208
  #define MTK_WDMA_RESET_IDX_TX				GENMASK(3, 0)
  #define MTK_WDMA_RESET_IDX_RX				GENMASK(17, 16)
-@@ -359,4 +421,70 @@ struct mtk_wdma_desc {
+@@ -348,4 +409,70 @@ struct mtk_wdma_desc {
  /* DMA channel mapping */
  #define HIFSYS_DMA_AG_MAP				0x008
  
@@ -3175,10 +3206,10 @@
 +}
 diff --git a/drivers/net/ethernet/mediatek/mtk_wed_wo.h b/drivers/net/ethernet/mediatek/mtk_wed_wo.h
 new file mode 100644
-index 0000000..548b38e
+index 0000000..b24fef3
 --- /dev/null
 +++ b/drivers/net/ethernet/mediatek/mtk_wed_wo.h
-@@ -0,0 +1,324 @@
+@@ -0,0 +1,325 @@
 +// SPDX-License-Identifier: GPL-2.0-only
 +/* Copyright (C) 2021 Felix Fietkau <nbd@nbd.name> */
 +
@@ -3499,23 +3530,31 @@
 +	return val;
 +}
 +
++int mtk_wed_mcu_msg_update(struct mtk_wed_device *dev, int id, void *data, int len);
 +int mtk_wed_wo_init(struct mtk_wed_hw *hw);
 +void mtk_wed_wo_exit(struct mtk_wed_hw *hw);
 +#endif
 +
 diff --git a/include/linux/soc/mediatek/mtk_wed.h b/include/linux/soc/mediatek/mtk_wed.h
-index e914cb4..e8fca31 100644
+index 00036f9..658f392 100644
 --- a/include/linux/soc/mediatek/mtk_wed.h
 +++ b/include/linux/soc/mediatek/mtk_wed.h
-@@ -6,7 +6,39 @@
- #include <linux/regmap.h>
+@@ -7,26 +7,73 @@
  #include <linux/pci.h>
  
-+#define WED_WO_STA_REC			0x6
-+
  #define MTK_WED_TX_QUEUES		2
 +#define MTK_WED_RX_QUEUES		2
-+
+ 
+-enum {
+-	MTK_BUS_TYPE_PCIE,
+-	MTK_BUS_TYPE_AXI,
+-	MTK_BUS_TYPE_MAX
+-};
++#define WED_WO_STA_REC			0x6
+ 
+ struct mtk_wed_hw;
+ struct mtk_wdma_desc;
+ 
 +enum mtk_wed_wo_cmd {
 +	MTK_WED_WO_CMD_WED_CFG,
 +	MTK_WED_WO_CMD_WED_RX_STAT,
@@ -3544,45 +3583,29 @@
 +	MTK_WED_WO_CMD_CCIF_RING_DUMP,
 +	MTK_WED_WO_CMD_WED_END
 +};
- 
- enum {
- 	MTK_NO_WED,
-@@ -15,10 +47,9 @@ enum {
- 	MTK_WED_VMAX
- };
- 
--enum {
--	MTK_BUS_TYPE_PCIE,
--	MTK_BUS_TYPE_AXI,
--	MTK_BUS_TYPE_MAX
-+enum mtk_wed_bus_tye {
-+	MTK_WED_BUS_PCIE,
-+	MTK_WED_BUS_AXI,
- };
- 
- struct mtk_wed_hw;
-@@ -33,6 +64,33 @@ struct mtk_wed_ring {
- 	void __iomem *wpdma;
- };
- 
++
 +struct mtk_rxbm_desc {
 +	__le32 buf0;
 +	__le32 token;
 +} __packed __aligned(4);
 +
-+struct dma_buf {
-+	int size;
-+	void **pages;
-+	struct mtk_wdma_desc *desc;
-+	dma_addr_t desc_phys;
-+};
-+
-+struct dma_entry {
-+	int size;
-+	struct mtk_rxbm_desc *desc;
-+	dma_addr_t desc_phys;
++enum mtk_wed_bus_tye{
++	MTK_WED_BUS_PCIE,
++	MTK_WED_BUS_AXI,
 +};
 +
++#define MTK_WED_RING_CONFIGURED		BIT(0)
+ struct mtk_wed_ring {
+ 	struct mtk_wdma_desc *desc;
+ 	dma_addr_t desc_phys;
+ 	u32 desc_size;
+ 	int size;
++	u32 flags;
+ 
+ 	u32 reg_base;
+ 	void __iomem *wpdma;
+ };
+ 
 +struct mtk_wed_wo_rx_stats {
 +	__le16 wlan_idx;
 +	__le16 tid;
@@ -3595,42 +3618,49 @@
  struct mtk_wed_device {
  #ifdef CONFIG_NET_MEDIATEK_SOC_WED
  	const struct mtk_wed_ops *ops;
-@@ -47,37 +105,64 @@ struct mtk_wed_device {
+@@ -35,18 +82,37 @@ struct mtk_wed_device {
+ 	bool init_done, running;
+ 	int wdma_idx;
+ 	int irq;
++	u8 version;
++
++	/* used by wlan driver */
+ 	u32 rev_id;
+ 
  	struct mtk_wed_ring tx_ring[MTK_WED_TX_QUEUES];
++	struct mtk_wed_ring rx_ring[MTK_WED_RX_QUEUES];
  	struct mtk_wed_ring txfree_ring;
  	struct mtk_wed_ring tx_wdma[MTK_WED_TX_QUEUES];
-+	struct mtk_wed_ring rx_ring[MTK_WED_RX_QUEUES];
 +	struct mtk_wed_ring rx_wdma[MTK_WED_RX_QUEUES];
-+
-+	struct dma_buf buf_ring;
  
  	struct {
  		int size;
--		void **pages;
--		struct mtk_wdma_desc *desc;
-+		struct page_frag_cache rx_page;
-+		struct mtk_rxbm_desc *desc;
+ 		void **pages;
+ 		struct mtk_wdma_desc *desc;
  		dma_addr_t desc_phys;
 -	} buf_ring;
-+	} rx_buf_ring;
++	} tx_buf_ring;
++
++ 	struct {
++ 		int size;
++ 		struct page_frag_cache rx_page;
++		struct mtk_rxbm_desc *desc;
++ 		dma_addr_t desc_phys;
++ 	} rx_buf_ring;
 +
 +	struct {
-+		struct mtk_wed_ring rro_ring;
++		struct mtk_wed_ring ring;
 +		void __iomem *rro_desc;
-+		dma_addr_t miod_desc_phys;
-+		dma_addr_t fdbk_desc_phys;
-+		u32 mcu_view_miod;
++		dma_addr_t miod_phys;
++		dma_addr_t fdbk_phys;
 +	} rro;
  
  	/* filled by driver: */
  	struct {
--		struct pci_dev *pci_dev;
-+		union {
-+			struct platform_device *platform_dev;
-+			struct pci_dev *pci_dev;
-+		};
+@@ -56,24 +122,35 @@ struct mtk_wed_device {
+ 		};
+ 		enum mtk_wed_bus_tye bus_type;
  		void __iomem *base;
- 		u32 bus_type;
 +		u32 phy_base;
  
  		u32 wpdma_phys;
@@ -3656,35 +3686,30 @@
  		u32 (*init_buf)(void *ptr, dma_addr_t phys, int token_id);
  		int (*offload_enable)(struct mtk_wed_device *wed);
  		void (*offload_disable)(struct mtk_wed_device *wed);
-+		u32 (*init_rx_buf)(struct mtk_wed_device *wed,
-+				   int pkt_num);
++		u32 (*init_rx_buf)(struct mtk_wed_device *wed, int size);
 +		void (*release_rx_buf)(struct mtk_wed_device *wed);
 +		void (*update_wo_rx_stats)(struct mtk_wed_device *wed,
 +					   struct mtk_wed_wo_rx_stats *stats);
  	} wlan;
  #endif
  };
-@@ -88,6 +173,10 @@ struct mtk_wed_ops {
+@@ -82,9 +159,15 @@ struct mtk_wed_ops {
+ 	int (*attach)(struct mtk_wed_device *dev);
+ 	int (*tx_ring_setup)(struct mtk_wed_device *dev, int ring,
  			     void __iomem *regs);
++	int (*rx_ring_setup)(struct mtk_wed_device *dev, int ring,
++			     void __iomem *regs);
  	int (*txfree_ring_setup)(struct mtk_wed_device *dev,
  				 void __iomem *regs);
-+	int (*rx_ring_setup)(struct mtk_wed_device *dev, int ring,
-+				 void __iomem *regs);
 +	int (*msg_update)(struct mtk_wed_device *dev, int cmd_id,
 +			  void *data, int len);
  	void (*detach)(struct mtk_wed_device *dev);
- 
- 	void (*stop)(struct mtk_wed_device *dev);
-@@ -99,6 +188,8 @@ struct mtk_wed_ops {
- 
- 	u32 (*irq_get)(struct mtk_wed_device *dev, u32 mask);
- 	void (*irq_set_mask)(struct mtk_wed_device *dev, u32 mask);
 +	void (*ppe_check)(struct mtk_wed_device *dev, struct sk_buff *skb,
 +			  u32 reason, u32 hash);
- };
  
- extern const struct mtk_wed_ops __rcu *mtk_soc_wed_ops;
-@@ -123,6 +214,16 @@ mtk_wed_device_attach(struct mtk_wed_device *dev)
+ 	void (*stop)(struct mtk_wed_device *dev);
+ 	void (*start)(struct mtk_wed_device *dev, u32 irq_mask);
+@@ -119,6 +202,16 @@ mtk_wed_device_attach(struct mtk_wed_device *dev)
  	return ret;
  }
  
@@ -3692,7 +3717,7 @@
 +mtk_wed_get_rx_capa(struct mtk_wed_device *dev)
 +{
 +#ifdef CONFIG_NET_MEDIATEK_SOC_WED
-+	return dev->ver != 1;
++	return dev->version != 1;
 +#else
 +	return false;
 +#endif
@@ -3701,37 +3726,26 @@
  #ifdef CONFIG_NET_MEDIATEK_SOC_WED
  #define mtk_wed_device_active(_dev) !!(_dev)->ops
  #define mtk_wed_device_detach(_dev) (_dev)->ops->detach(_dev)
-@@ -131,6 +232,10 @@ mtk_wed_device_attach(struct mtk_wed_device *dev)
- 	(_dev)->ops->tx_ring_setup(_dev, _ring, _regs)
- #define mtk_wed_device_txfree_ring_setup(_dev, _regs) \
- 	(_dev)->ops->txfree_ring_setup(_dev, _regs)
-+#define mtk_wed_device_rx_ring_setup(_dev, _ring, _regs) \
-+	(_dev)->ops->rx_ring_setup(_dev, _ring, _regs)
-+#define mtk_wed_device_update_msg(_dev, _id, _msg, _len) \
-+	(_dev)->ops->msg_update(_dev, _id, _msg, _len)
- #define mtk_wed_device_reg_read(_dev, _reg) \
- 	(_dev)->ops->reg_read(_dev, _reg)
- #define mtk_wed_device_reg_write(_dev, _reg, _val) \
-@@ -139,6 +244,8 @@ mtk_wed_device_attach(struct mtk_wed_device *dev)
+@@ -135,6 +228,12 @@ mtk_wed_device_attach(struct mtk_wed_device *dev)
  	(_dev)->ops->irq_get(_dev, _mask)
  #define mtk_wed_device_irq_set_mask(_dev, _mask) \
  	(_dev)->ops->irq_set_mask(_dev, _mask)
++#define mtk_wed_device_rx_ring_setup(_dev, _ring, _regs) \
++	(_dev)->ops->rx_ring_setup(_dev, _ring, _regs)
 +#define mtk_wed_device_ppe_check(_dev, _skb, _reason, _hash) \
 +	(_dev)->ops->ppe_check(_dev, _skb, _reason, _hash)
++#define mtk_wed_device_update_msg(_dev, _id, _msg, _len) \
++	(_dev)->ops->msg_update(_dev, _id, _msg, _len)
  #else
  static inline bool mtk_wed_device_active(struct mtk_wed_device *dev)
  {
-@@ -148,10 +255,13 @@ static inline bool mtk_wed_device_active(struct mtk_wed_device *dev)
- #define mtk_wed_device_start(_dev, _mask) do {} while (0)
- #define mtk_wed_device_tx_ring_setup(_dev, _ring, _regs) -ENODEV
- #define mtk_wed_device_txfree_ring_setup(_dev, _ring, _regs) -ENODEV
-+#define mtk_wed_device_rx_ring_setup(_dev, _ring, _regs) -ENODEV
-+#define mtk_wed_device_update_msg(_dev, _id, _msg, _len) -ENODEV
- #define mtk_wed_device_reg_read(_dev, _reg) 0
+@@ -148,6 +247,9 @@ static inline bool mtk_wed_device_active(struct mtk_wed_device *dev)
  #define mtk_wed_device_reg_write(_dev, _reg, _val) do {} while (0)
  #define mtk_wed_device_irq_get(_dev, _mask) 0
  #define mtk_wed_device_irq_set_mask(_dev, _mask) do {} while (0)
++#define mtk_wed_device_rx_ring_setup(_dev, _ring, _regs) -ENODEV
 +#define mtk_wed_device_ppe_check(_dev, _hash)  do {} while (0)
++#define mtk_wed_device_update_msg(_dev, _id, _msg, _len) -ENODEV
  #endif
  
  #endif
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/flow_patch/999-3009-add-wed-ser-support.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/flow_patch/999-3009-add-wed-ser-support.patch
index c53746f..2aa0131 100644
--- a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/flow_patch/999-3009-add-wed-ser-support.patch
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/flow_patch/999-3009-add-wed-ser-support.patch
@@ -1,21 +1,21 @@
-From de9cc10d4e2d5aad4801dc92fb37c42478a4ab68 Mon Sep 17 00:00:00 2001
+From 7f1319357888271ea4aeeda81723b19a8f5ef2c0 Mon Sep 17 00:00:00 2001
 From: Sujuan Chen <sujuan.chen@mediatek.com>
 Date: Mon, 18 Sep 2023 11:05:45 +0800
-Subject: [PATCH 10/22] add-wed-ser-support
+Subject: [PATCH] add-wed-ser-support
 
 ---
  drivers/net/ethernet/mediatek/mtk_eth_soc.c  |   8 +
- drivers/net/ethernet/mediatek/mtk_wed.c      | 361 ++++++++++++++-----
- drivers/net/ethernet/mediatek/mtk_wed.h      |  11 +
- drivers/net/ethernet/mediatek/mtk_wed_regs.h |  12 +
- include/linux/soc/mediatek/mtk_wed.h         |  27 +-
- 5 files changed, 320 insertions(+), 99 deletions(-)
+ drivers/net/ethernet/mediatek/mtk_wed.c      | 391 ++++++++++++++-----
+ drivers/net/ethernet/mediatek/mtk_wed.h      |  10 +
+ drivers/net/ethernet/mediatek/mtk_wed_regs.h |   9 +
+ include/linux/soc/mediatek/mtk_wed.h         |  25 +-
+ 5 files changed, 342 insertions(+), 101 deletions(-)
 
 diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.c b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
-index 2cab49a..c1399c5 100644
+index 268c9e7..a24b223 100644
 --- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c
 +++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
-@@ -4158,6 +4158,9 @@ static void mtk_pending_work(struct work_struct *work)
+@@ -4619,6 +4619,9 @@ static void mtk_pending_work(struct work_struct *work)
  	for (i = 0; i < MTK_MAC_COUNT; i++) {
  		if (!eth->netdev[i])
  			continue;
@@ -25,7 +25,7 @@
  		if (mtk_reset_flag == MTK_FE_STOP_TRAFFIC) {
  			pr_info("send MTK_FE_STOP_TRAFFIC event\n");
  			call_netdevice_notifiers(MTK_FE_STOP_TRAFFIC,
-@@ -4183,6 +4186,7 @@ static void mtk_pending_work(struct work_struct *work)
+@@ -4644,6 +4647,7 @@ static void mtk_pending_work(struct work_struct *work)
  			pr_warn("wait for MTK_FE_START_RESET\n");
  		}
  		rtnl_lock();
@@ -33,7 +33,7 @@
  		break;
  	}
  
-@@ -4221,6 +4225,9 @@ static void mtk_pending_work(struct work_struct *work)
+@@ -4682,6 +4686,9 @@ static void mtk_pending_work(struct work_struct *work)
  	for (i = 0; i < MTK_MAC_COUNT; i++) {
  		if (!eth->netdev[i])
  			continue;
@@ -43,7 +43,7 @@
  		if (mtk_reset_flag == MTK_FE_STOP_TRAFFIC) {
  			pr_info("send MTK_FE_START_TRAFFIC event\n");
  			call_netdevice_notifiers(MTK_FE_START_TRAFFIC,
-@@ -4230,6 +4237,7 @@ static void mtk_pending_work(struct work_struct *work)
+@@ -4691,6 +4698,7 @@ static void mtk_pending_work(struct work_struct *work)
  			call_netdevice_notifiers(MTK_FE_RESET_DONE,
  				eth->netdev[i]);
  		}
@@ -52,7 +52,7 @@
  			eth->netdev[i]);
  		break;
 diff --git a/drivers/net/ethernet/mediatek/mtk_wed.c b/drivers/net/ethernet/mediatek/mtk_wed.c
-index 4b2f1a2..ae31412 100644
+index ad9f3d5..b993f0e 100644
 --- a/drivers/net/ethernet/mediatek/mtk_wed.c
 +++ b/drivers/net/ethernet/mediatek/mtk_wed.c
 @@ -13,8 +13,10 @@
@@ -66,60 +66,52 @@
  #include "mtk_wed_regs.h"
  #include "mtk_wed.h"
  #include "mtk_ppe.h"
-@@ -71,23 +73,27 @@ mtk_wdma_read_reset(struct mtk_wed_device *dev)
- 	return wdma_r32(dev, MTK_WDMA_GLO_CFG);
- }
- 
--static void
-+static int
- mtk_wdma_rx_reset(struct mtk_wed_device *dev)
- {
- 	u32 status;
- 	u32 mask = MTK_WDMA_GLO_CFG_RX_DMA_BUSY;
--	int i;
-+	int busy, i;
+@@ -80,10 +82,13 @@ mtk_wdma_rx_reset(struct mtk_wed_device *dev)
  
  	wdma_clr(dev, MTK_WDMA_GLO_CFG, MTK_WDMA_GLO_CFG_RX_DMA_EN);
--	if (readx_poll_timeout(mtk_wdma_read_reset, dev, status,
--			       !(status & mask), 0, 1000))
--		WARN_ON_ONCE(1);
-+	busy = readx_poll_timeout(mtk_wdma_read_reset, dev, status,
-+			       !(status & mask), 0, 10000);
-+
+ 	ret = readx_poll_timeout(mtk_wdma_read_reset, dev, status,
+-				 !(status & mask), 0, 1000)
++				 !(status & mask), 0, 10000);
+ 	if (ret)
+ 		dev_err(dev->hw->dev, "rx reset failed \n");
+ 
 +	wdma_w32(dev, MTK_WDMA_RESET_IDX, MTK_WDMA_RESET_IDX_RX);
 +	wdma_w32(dev, MTK_WDMA_RESET_IDX, 0);
- 
- 	for (i = 0; i < ARRAY_SIZE(dev->rx_wdma); i++)
- 		if (!dev->rx_wdma[i].desc) {
- 			wdma_w32(dev, MTK_WDMA_RING_RX(i) +
- 				 MTK_WED_RING_OFS_CPU_IDX, 0);
++
+ 	for (i = 0; i < ARRAY_SIZE(dev->rx_wdma); i++) {
+ 		if (!dev->rx_wdma[i].desc)
+ 			continue;
+@@ -91,6 +96,8 @@ mtk_wdma_rx_reset(struct mtk_wed_device *dev)
+ 		wdma_w32(dev,
+ 			 MTK_WDMA_RING_RX(i) + MTK_WED_RING_OFS_CPU_IDX, 0);
  	}
 +
-+	return busy;
++	return ret;
  }
  
  static void
-@@ -99,14 +105,14 @@ mtk_wdma_tx_reset(struct mtk_wed_device *dev)
+@@ -101,16 +108,15 @@ mtk_wdma_tx_reset(struct mtk_wed_device *dev)
  
  	wdma_clr(dev, MTK_WDMA_GLO_CFG, MTK_WDMA_GLO_CFG_TX_DMA_EN);
  	if (readx_poll_timeout(mtk_wdma_read_reset, dev, status,
 -			       !(status & mask), 0, 1000))
 +			       !(status & mask), 0, 10000))
- 		WARN_ON_ONCE(1);
+ 		dev_err(dev->hw->dev, "tx reset failed \n");
  
+-	for (i = 0; i < ARRAY_SIZE(dev->tx_wdma); i++) {
+-		if (!dev->tx_wdma[i].desc)
+-			continue;
 +	wdma_w32(dev, MTK_WDMA_RESET_IDX, MTK_WDMA_RESET_IDX_TX);
 +	wdma_w32(dev, MTK_WDMA_RESET_IDX, 0);
- 	for (i = 0; i < ARRAY_SIZE(dev->tx_wdma); i++)
--		if (!dev->tx_wdma[i].desc) {
--			wdma_w32(dev, MTK_WDMA_RING_TX(i) +
--				 MTK_WED_RING_OFS_CPU_IDX, 0);
+ 
++	for (i = 0; i < ARRAY_SIZE(dev->tx_wdma); i++)
+ 		wdma_w32(dev,
+ 			 MTK_WDMA_RING_TX(i) + MTK_WED_RING_OFS_CPU_IDX, 0);
 -	}
-+		wdma_w32(dev, MTK_WDMA_RING_TX(i) +
-+			 MTK_WED_RING_OFS_CPU_IDX, 0);
  }
  
- static u32
-@@ -172,6 +178,51 @@ mtk_wed_wo_reset(struct mtk_wed_device *dev)
+ static void
+@@ -176,6 +182,59 @@ mtk_wed_wo_reset(struct mtk_wed_device *dev)
  	iounmap((void *)reg);
  }
  
@@ -131,9 +123,13 @@
 +
 +	for (i = 0; i < ARRAY_SIZE(hw_list); i++) {
 +		struct mtk_wed_hw *hw = hw_list[i];
-+		struct mtk_wed_device *dev = hw->wed_dev;
++		struct mtk_wed_device *dev;
 +		int err;
 +
++		if (!hw)
++			break;
++
++		dev = hw->wed_dev;
 +		if (!dev || !dev->wlan.reset)
 +			continue;
 +
@@ -156,8 +152,12 @@
 +
 +	for (i = 0; i < ARRAY_SIZE(hw_list); i++) {
 +		struct mtk_wed_hw *hw = hw_list[i];
-+		struct mtk_wed_device *dev = hw->wed_dev;
++		struct mtk_wed_device *dev;
 +
++		if (!hw)
++			break;
++
++		dev = hw->wed_dev;
 +		if (!dev || !dev->wlan.reset_complete)
 +			continue;
 +
@@ -171,123 +171,134 @@
  static struct mtk_wed_hw *
  mtk_wed_assign(struct mtk_wed_device *dev)
  {
-@@ -505,8 +556,8 @@ mtk_wed_check_wfdma_rx_fill(struct mtk_wed_device *dev, int idx)
- 		wifi_w32(dev, dev->wlan.wpdma_rx_glo -
- 			 dev->wlan.phy_base, val);
- 	} else {
+@@ -473,8 +532,8 @@ mtk_wed_check_wfdma_rx_fill(struct mtk_wed_device *dev, int idx)
+ 	}
+ 
+ 	if (i == 3) {
 -		dev_err(dev->hw->dev, "mtk_wed%d: rx dma enable failed!\n",
 -			       dev->hw->index);
 +		dev_err(dev->hw->dev, "mtk_wed%d: rx(%d) dma enable failed!\n",
 +			       dev->hw->index, idx);
+ 		return;
  	}
- }
  
-@@ -557,7 +608,7 @@ mtk_wed_dma_enable(struct mtk_wed_device *dev)
- 			FIELD_PREP(MTK_WED_WPDMA_RX_D_INIT_PHASE_RXEN_SEL,
- 				   0x2));
- 
--		for (idx = 0; idx < MTK_WED_RX_QUEUES; idx++)
-+		for (idx = 0; idx < dev->hw->ring_num; idx++)
- 			mtk_wed_check_wfdma_rx_fill(dev, idx);
- 	}
- }
-@@ -594,36 +645,45 @@ mtk_wed_dma_disable(struct mtk_wed_device *dev)
- 		wed_clr(dev, MTK_WED_WDMA_GLO_CFG,
- 			MTK_WED_WDMA_GLO_CFG_TX_DDONE_CHK);
- 	}
-+
-+	mtk_wed_set_512_support(dev, false);
- }
- 
+@@ -522,16 +581,8 @@ mtk_wed_dma_disable(struct mtk_wed_device *dev)
  static void
  mtk_wed_stop(struct mtk_wed_device *dev)
  {
 -	mtk_wed_dma_disable(dev);
--	mtk_wed_set_512_support(dev, false);
 -
- 	if (dev->ver > MTK_WED_V1) {
- 		wed_w32(dev, MTK_WED_EXT_INT_MASK1, 0);
- 		wed_w32(dev, MTK_WED_EXT_INT_MASK2, 0);
- 	}
  	mtk_wed_set_ext_int(dev, false);
  
-+	wed_w32(dev, MTK_WED_WPDMA_INT_TRIGGER, 0);
-+	wed_w32(dev, MTK_WED_WDMA_INT_TRIGGER, 0);
-+	wdma_w32(dev, MTK_WDMA_INT_MASK, 0);
-+	wdma_w32(dev, MTK_WDMA_INT_GRP2, 0);
-+	wed_w32(dev, MTK_WED_WPDMA_INT_MASK, 0);
-+}
-+
-+static void
+-	wed_clr(dev, MTK_WED_CTRL,
+-		MTK_WED_CTRL_WDMA_INT_AGENT_EN |
+-		MTK_WED_CTRL_WPDMA_INT_AGENT_EN |
+-		MTK_WED_CTRL_WED_TX_BM_EN |
+-		MTK_WED_CTRL_WED_TX_FREE_AGENT_EN);
+-
+ 	wed_w32(dev, MTK_WED_WPDMA_INT_TRIGGER, 0);
+ 	wed_w32(dev, MTK_WED_WDMA_INT_TRIGGER, 0);
+ 	wdma_w32(dev, MTK_WDMA_INT_MASK, 0);
+@@ -543,39 +594,49 @@ mtk_wed_stop(struct mtk_wed_device *dev)
+ 
+ 	wed_w32(dev, MTK_WED_EXT_INT_MASK1, 0);
+ 	wed_w32(dev, MTK_WED_EXT_INT_MASK2, 0);
+-	wed_clr(dev, MTK_WED_CTRL, MTK_WED_CTRL_WED_RX_BM_EN);
+-
+ }
+ 
+ static void
+-mtk_wed_detach(struct mtk_wed_device *dev)
 +mtk_wed_deinit(struct mtk_wed_device *dev)
-+{
+ {
+-	struct device_node *wlan_node;
+-	struct mtk_wed_hw *hw = dev->hw;
 +	mtk_wed_stop(dev);
 +	mtk_wed_dma_disable(dev);
-+
- 	wed_clr(dev, MTK_WED_CTRL,
- 		MTK_WED_CTRL_WDMA_INT_AGENT_EN |
- 		MTK_WED_CTRL_WPDMA_INT_AGENT_EN |
- 		MTK_WED_CTRL_WED_TX_BM_EN |
- 		MTK_WED_CTRL_WED_TX_FREE_AGENT_EN);
  
--	if (dev->ver > MTK_WED_V1) {
--		wed_clr(dev, MTK_WED_CTRL,
--			MTK_WED_CTRL_WED_RX_BM_EN);
--	}
-+	if (dev->hw->ver == 1)
+-	mutex_lock(&hw_lock);
++	wed_clr(dev, MTK_WED_CTRL,
++		MTK_WED_CTRL_WDMA_INT_AGENT_EN |
++		MTK_WED_CTRL_WPDMA_INT_AGENT_EN |
++		MTK_WED_CTRL_WED_TX_BM_EN |
++		MTK_WED_CTRL_WED_TX_FREE_AGENT_EN);
+ 
+-	mtk_wed_stop(dev);
++	if (dev->hw->version == 1)
 +		return;
  
--	wed_w32(dev, MTK_WED_WPDMA_INT_TRIGGER, 0);
--	wed_w32(dev, MTK_WED_WDMA_INT_TRIGGER, 0);
--	wdma_w32(dev, MTK_WDMA_INT_MASK, 0);
--	wdma_w32(dev, MTK_WDMA_INT_GRP2, 0);
--	wed_w32(dev, MTK_WED_WPDMA_INT_MASK, 0);
+-	wdma_w32(dev, MTK_WDMA_RESET_IDX, MTK_WDMA_RESET_IDX_RX);
+-	wdma_w32(dev, MTK_WDMA_RESET_IDX, 0);
 +	wed_clr(dev, MTK_WED_CTRL,
 +		MTK_WED_CTRL_RX_ROUTE_QM_EN |
 +		MTK_WED_CTRL_WED_RX_BM_EN |
 +		MTK_WED_CTRL_RX_RRO_QM_EN);
- }
- 
- static void
-@@ -634,16 +694,13 @@ mtk_wed_detach(struct mtk_wed_device *dev)
++}
  
- 	mutex_lock(&hw_lock);
+-	mtk_wed_reset(dev, MTK_WED_RESET_WED);
++static void
++__mtk_wed_detach(struct mtk_wed_device *dev)
++{
++	struct device_node *wlan_node;
++	struct mtk_wed_hw *hw = dev->hw;
  
--	mtk_wed_stop(dev);
+-	if (mtk_wed_get_rx_capa(dev)) {
+-		wdma_clr(dev, MTK_WDMA_GLO_CFG, MTK_WDMA_GLO_CFG_TX_DMA_EN);
+-		wdma_w32(dev, MTK_WDMA_RESET_IDX, MTK_WDMA_RESET_IDX_TX);
+-		wdma_w32(dev, MTK_WDMA_RESET_IDX, 0);
+-	}
 +	mtk_wed_deinit(dev);
  
--	wdma_w32(dev, MTK_WDMA_RESET_IDX, MTK_WDMA_RESET_IDX_RX);
--	wdma_w32(dev, MTK_WDMA_RESET_IDX, 0);
 +	mtk_wdma_rx_reset(dev);
- 
- 	mtk_wed_reset(dev, MTK_WED_RESET_WED);
- 
--	wdma_clr(dev, MTK_WDMA_GLO_CFG, MTK_WDMA_GLO_CFG_TX_DMA_EN);
--	wdma_w32(dev, MTK_WDMA_RESET_IDX, MTK_WDMA_RESET_IDX_TX);
--	wdma_w32(dev, MTK_WDMA_RESET_IDX, 0);
-+	mtk_wdma_tx_reset(dev);
- 
- 	mtk_wed_free_buffer(dev);
++	mtk_wed_reset(dev, MTK_WED_RESET_WED);
+ 	mtk_wed_free_tx_buffer(dev);
  	mtk_wed_free_tx_rings(dev);
-@@ -653,8 +710,6 @@ mtk_wed_detach(struct mtk_wed_device *dev)
- 		mtk_wed_wo_exit(hw);
+ 
+ 	if (mtk_wed_get_rx_capa(dev)) {
+-		mtk_wed_wo_reset(dev);
++		if(hw->wed_wo)
++			mtk_wed_wo_reset(dev);
+ 		mtk_wed_free_rx_rings(dev);
+-		mtk_wed_wo_exit(hw);
+-		mtk_wdma_rx_reset(dev);
++		if(hw->wed_wo)
++			mtk_wed_wo_exit(hw);
++		mtk_wdma_tx_reset(dev);
  	}
  
--	mtk_wdma_rx_reset(dev);
--
  	if (dev->wlan.bus_type == MTK_WED_BUS_PCIE) {
- 		wlan_node = dev->wlan.pci_dev->dev.of_node;
- 		if (of_dma_is_coherent(wlan_node))
-@@ -748,7 +803,7 @@ mtk_wed_hw_init_early(struct mtk_wed_device *dev)
+@@ -593,6 +654,13 @@ mtk_wed_detach(struct mtk_wed_device *dev)
+ 	module_put(THIS_MODULE);
+ 
+ 	hw->wed_dev = NULL;
++}
++
++static void
++mtk_wed_detach(struct mtk_wed_device *dev)
++{
++	mutex_lock(&hw_lock);
++	__mtk_wed_detach(dev);
+ 	mutex_unlock(&hw_lock);
+ }
+ 
+@@ -665,7 +733,7 @@ mtk_wed_hw_init_early(struct mtk_wed_device *dev)
  {
  	u32 mask, set;
  
 -	mtk_wed_stop(dev);
 +	mtk_wed_deinit(dev);
  	mtk_wed_reset(dev, MTK_WED_RESET_WED);
+ 	mtk_wed_set_wpdma(dev);
  
- 	if (dev->ver > MTK_WED_V1)
-@@ -961,44 +1016,127 @@ mtk_wed_ring_reset(struct mtk_wdma_desc *desc, int size, int scale, bool tx)
+@@ -715,7 +783,6 @@ mtk_wed_rro_ring_alloc(struct mtk_wed_device *dev, struct mtk_wed_ring *ring,
+ 
+ 	ring->desc_size = sizeof(*ring->desc);
+ 	ring->size = size;
+-	memset(ring->desc, 0, size);
+ 
+ 	return 0;
+ }
+@@ -938,44 +1005,140 @@ mtk_wed_ring_reset(struct mtk_wed_ring *ring, int size, bool tx)
  }
  
  static u32
@@ -314,7 +325,7 @@
 -
 -	if (wed_r32(dev, MTK_WED_CTRL) &
 -	    (MTK_WED_CTRL_WED_TX_BM_BUSY | MTK_WED_CTRL_WED_TX_FREE_AGENT_BUSY))
-+ 	if (wed_r32(dev, reg) & mask)
++	if (wed_r32(dev, reg) & mask)
  		return true;
  
  	return false;
@@ -334,21 +345,24 @@
 +				 timeout, false, dev, reg, mask);
  }
  
-+static void
++static int
 +mtk_wed_rx_reset(struct mtk_wed_device *dev)
 +{
 +	struct mtk_wed_wo *wo = dev->hw->wed_wo;
-+	u8 state = WO_STATE_SER_RESET;
-+	bool busy = false;
-+	int i;
++	u8 val = WO_STATE_SER_RESET;
++	int i, ret;
 +
-+	mtk_wed_mcu_send_msg(wo, MODULE_ID_WO, MTK_WED_WO_CMD_CHANGE_STATE,
-+			     &state, sizeof(state), true);
++	ret = mtk_wed_mcu_send_msg(wo, MTK_WED_MODULE_ID_WO,
++				   MTK_WED_WO_CMD_CHANGE_STATE, &val,
++				   sizeof(val), true);
++
++	if (ret)
++		return ret;
 +
 +	wed_clr(dev, MTK_WED_WPDMA_RX_D_GLO_CFG, MTK_WED_WPDMA_RX_D_RX_DRV_EN);
-+	busy = mtk_wed_poll_busy(dev, MTK_WED_WPDMA_RX_D_GLO_CFG,
-+				 MTK_WED_WPDMA_RX_D_RX_DRV_BUSY);
-+	if (busy) {
++	ret = mtk_wed_poll_busy(dev, MTK_WED_WPDMA_RX_D_GLO_CFG,
++				MTK_WED_WPDMA_RX_D_RX_DRV_BUSY);
++	if (ret) {
 +		mtk_wed_reset(dev, MTK_WED_RESET_WPDMA_INT_AGENT);
 +		mtk_wed_reset(dev, MTK_WED_RESET_WPDMA_RX_D_DRV);
 +	} else {
@@ -368,9 +382,9 @@
 +
 +	/* reset rro qm */
 +	wed_clr(dev, MTK_WED_CTRL, MTK_WED_CTRL_RX_RRO_QM_EN);
-+	busy = mtk_wed_poll_busy(dev, MTK_WED_CTRL,
-+				 MTK_WED_CTRL_RX_RRO_QM_BUSY);
-+	if (busy) {
++	ret = mtk_wed_poll_busy(dev, MTK_WED_CTRL,
++				MTK_WED_CTRL_RX_RRO_QM_BUSY);
++	if (ret) {
 +		mtk_wed_reset(dev, MTK_WED_RESET_RX_RRO_QM);
 +	} else {
 +		wed_set(dev, MTK_WED_RROQM_RST_IDX,
@@ -381,9 +395,9 @@
 +
 +	/* reset route qm */
 +	wed_clr(dev, MTK_WED_CTRL, MTK_WED_CTRL_RX_ROUTE_QM_EN);
-+	busy = mtk_wed_poll_busy(dev, MTK_WED_CTRL,
-+				 MTK_WED_CTRL_RX_ROUTE_QM_BUSY);
-+	if (busy) {
++	ret = mtk_wed_poll_busy(dev, MTK_WED_CTRL,
++				MTK_WED_CTRL_RX_ROUTE_QM_BUSY);
++	if (ret) {
 +		mtk_wed_reset(dev, MTK_WED_RESET_RX_ROUTE_QM);
 +	} else {
 +		wed_set(dev, MTK_WED_RTQM_GLO_CFG,
@@ -400,66 +414,73 @@
 +	mtk_wed_reset(dev, MTK_WED_RESET_WDMA_TX_DRV);
 +
 +	/* reset wed rx dma */
-+	busy = mtk_wed_poll_busy(dev, MTK_WED_GLO_CFG,
-+				 MTK_WED_GLO_CFG_RX_DMA_BUSY);
++	ret = mtk_wed_poll_busy(dev, MTK_WED_GLO_CFG,
++				MTK_WED_GLO_CFG_RX_DMA_BUSY);
 +	wed_clr(dev, MTK_WED_GLO_CFG, MTK_WED_GLO_CFG_RX_DMA_EN);
-+	if (busy) {
++	if (ret) {
 +		mtk_wed_reset(dev, MTK_WED_RESET_WED_RX_DMA);
 +	} else {
-+		wed_set(dev, MTK_WED_RESET_IDX,
-+			MTK_WED_RESET_IDX_RX);
++		struct mtk_eth *eth = dev->hw->eth;
++
++		if(MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V2))
++			wed_set(dev, MTK_WED_RESET_IDX,
++				MTK_WED_RESET_IDX_RX_V2);
++		else
++			wed_set(dev, MTK_WED_RESET_IDX, MTK_WED_RESET_IDX_RX);
 +		wed_w32(dev, MTK_WED_RESET_IDX, 0);
 +	}
 +
 +	/* reset rx bm */
 +	wed_clr(dev, MTK_WED_CTRL, MTK_WED_CTRL_WED_RX_BM_EN);
 +	mtk_wed_poll_busy(dev, MTK_WED_CTRL,
-+			   MTK_WED_CTRL_WED_RX_BM_BUSY);
++			  MTK_WED_CTRL_WED_RX_BM_BUSY);
 +	mtk_wed_reset(dev, MTK_WED_RESET_RX_BM);
 +
 +	/* wo change to enable state */
-+	state = WO_STATE_ENABLE;
-+	mtk_wed_mcu_send_msg(wo, MODULE_ID_WO, MTK_WED_WO_CMD_CHANGE_STATE,
-+			     &state, sizeof(state), true);
++	val = WO_STATE_ENABLE;
++	ret = mtk_wed_mcu_send_msg(wo, MTK_WED_MODULE_ID_WO,
++				   MTK_WED_WO_CMD_CHANGE_STATE, &val,
++				   sizeof(val), true);
++
++	if (ret)
++		return ret;
 +
 +	/* wed_rx_ring_reset */
 +	for (i = 0; i < ARRAY_SIZE(dev->rx_ring); i++) {
-+		struct mtk_wdma_desc *desc = dev->rx_ring[i].desc;
-+
-+		if (!desc)
++		if (!dev->rx_ring[i].desc)
 +			continue;
 +
-+		mtk_wed_ring_reset(desc, MTK_WED_RX_RING_SIZE, 1, false);
++		mtk_wed_ring_reset(&dev->rx_ring[i], MTK_WED_RX_RING_SIZE,
++				   false);
 +	}
 +
-+	mtk_wed_free_rx_bm(dev);
++	mtk_wed_free_rx_buffer(dev);
++
++	return 0;
 +}
 +
 +
  static void
  mtk_wed_reset_dma(struct mtk_wed_device *dev)
  {
-@@ -1012,25 +1150,28 @@ mtk_wed_reset_dma(struct mtk_wed_device *dev)
- 		if (!desc)
- 			continue;
- 
--		mtk_wed_ring_reset(desc, MTK_WED_TX_RING_SIZE, dev->ver, true);
-+		mtk_wed_ring_reset(desc, MTK_WED_TX_RING_SIZE, 1, true);
+@@ -991,22 +1154,25 @@ mtk_wed_reset_dma(struct mtk_wed_device *dev)
+ 				   true);
  	}
  
 -	if (mtk_wed_poll_busy(dev))
 -		busy = mtk_wed_check_busy(dev);
 +	/* 1.Reset WED Tx DMA */
 +	wed_clr(dev, MTK_WED_GLO_CFG, MTK_WED_GLO_CFG_TX_DMA_EN);
-+	busy = mtk_wed_poll_busy(dev, MTK_WED_GLO_CFG, MTK_WED_GLO_CFG_TX_DMA_BUSY);
++	busy = mtk_wed_poll_busy(dev, MTK_WED_GLO_CFG,
++				 MTK_WED_GLO_CFG_TX_DMA_BUSY);
  
  	if (busy) {
  		mtk_wed_reset(dev, MTK_WED_RESET_WED_TX_DMA);
  	} else {
- 		wed_w32(dev, MTK_WED_RESET_IDX,
+-		wed_w32(dev, MTK_WED_RESET_IDX,
 -			MTK_WED_RESET_IDX_TX |
 -			MTK_WED_RESET_IDX_RX);
-+			MTK_WED_RESET_IDX_TX);
++		wed_w32(dev, MTK_WED_RESET_IDX, MTK_WED_RESET_IDX_TX);
  		wed_w32(dev, MTK_WED_RESET_IDX, 0);
  	}
  
@@ -470,138 +491,153 @@
  
 -	mtk_wdma_rx_reset(dev);
 +	wed_clr(dev, MTK_WED_WDMA_GLO_CFG, MTK_WED_WDMA_GLO_CFG_RX_DRV_EN);
-+	busy = !!(busy ||
-+		  mtk_wed_poll_busy(dev, MTK_WED_WDMA_GLO_CFG,
-+					 MTK_WED_WDMA_GLO_CFG_RX_DRV_BUSY));
++	if (!busy)
++		busy = mtk_wed_poll_busy(dev, MTK_WED_WDMA_GLO_CFG,
++					 MTK_WED_WDMA_GLO_CFG_RX_DRV_BUSY);
  
  	if (busy) {
  		mtk_wed_reset(dev, MTK_WED_RESET_WDMA_INT_AGENT);
-@@ -1047,15 +1188,30 @@ mtk_wed_reset_dma(struct mtk_wed_device *dev)
+@@ -1023,6 +1189,9 @@ mtk_wed_reset_dma(struct mtk_wed_device *dev)
  			MTK_WED_WDMA_GLO_CFG_RST_INIT_COMPLETE);
  	}
  
 +	/* 3. Reset WED WPDMA Tx Driver Engine */
-+	wed_clr(dev, MTK_WED_CTRL,
-+		MTK_WED_CTRL_WED_TX_FREE_AGENT_EN);
++	wed_clr(dev, MTK_WED_CTRL, MTK_WED_CTRL_WED_TX_FREE_AGENT_EN);
 +
  	for (i = 0; i < 100; i++) {
  		val = wed_r32(dev, MTK_WED_TX_BM_INTF);
  		if (FIELD_GET(MTK_WED_TX_BM_INTF_TKFIFO_FDEP, val) == 0x40)
- 			break;
+@@ -1030,8 +1199,21 @@ mtk_wed_reset_dma(struct mtk_wed_device *dev)
  	}
--
+ 
  	mtk_wed_reset(dev, MTK_WED_RESET_TX_FREE_AGENT);
-+
 +	wed_clr(dev, MTK_WED_CTRL, MTK_WED_CTRL_WED_TX_BM_EN);
  	mtk_wed_reset(dev, MTK_WED_RESET_TX_BM);
  
 +	/* 4. Reset WED WPDMA Tx Driver Engine */
 +	busy = mtk_wed_poll_busy(dev, MTK_WED_WPDMA_GLO_CFG,
-+				      MTK_WED_WPDMA_GLO_CFG_TX_DRV_BUSY);
++				 MTK_WED_WPDMA_GLO_CFG_TX_DRV_BUSY);
++
 +	wed_clr(dev, MTK_WED_WPDMA_GLO_CFG,
 +		MTK_WED_WPDMA_GLO_CFG_TX_DRV_EN |
 +		MTK_WED_WPDMA_GLO_CFG_RX_DRV_EN);
 +
-+	busy = !!(busy ||
-+		  mtk_wed_poll_busy(dev, MTK_WED_WPDMA_GLO_CFG,
-+					 MTK_WED_WPDMA_GLO_CFG_RX_DRV_BUSY));
++	if(!busy)
++		mtk_wed_poll_busy(dev, MTK_WED_WPDMA_GLO_CFG,
++				  MTK_WED_WPDMA_GLO_CFG_RX_DRV_BUSY);
++
  	if (busy) {
  		mtk_wed_reset(dev, MTK_WED_RESET_WPDMA_INT_AGENT);
  		mtk_wed_reset(dev, MTK_WED_RESET_WPDMA_TX_DRV);
-@@ -1065,6 +1221,16 @@ mtk_wed_reset_dma(struct mtk_wed_device *dev)
- 			MTK_WED_WPDMA_RESET_IDX_TX |
- 			MTK_WED_WPDMA_RESET_IDX_RX);
+@@ -1043,6 +1225,16 @@ mtk_wed_reset_dma(struct mtk_wed_device *dev)
  		wed_w32(dev, MTK_WED_WPDMA_RESET_IDX, 0);
-+		if (dev->ver > MTK_WED_V1) {
-+			wed_w32(dev, MTK_WED_RESET_IDX,
-+				MTK_WED_RESET_WPDMA_IDX_RX);
-+			wed_w32(dev, MTK_WED_RESET_IDX, 0);
-+		}
-+	}
-+
-+	if (dev->ver > MTK_WED_V1) {
-+		dev->init_done = false;
-+		mtk_wed_rx_reset(dev);
  	}
  
++	dev->init_done = false;
++	if (dev->hw->version == 1)
++		return;
++
++	if (!busy) {
++		wed_w32(dev, MTK_WED_RESET_IDX, MTK_WED_RESET_WPDMA_IDX_RX);
++		wed_w32(dev, MTK_WED_RESET_IDX, 0);
++	}
++
++	mtk_wed_rx_reset(dev);
  }
-@@ -1101,13 +1267,15 @@ mtk_wed_ring_alloc(struct mtk_wed_device *dev, struct mtk_wed_ring *ring,
+ 
+ static int
+@@ -1062,7 +1254,8 @@ mtk_wed_ring_alloc(struct mtk_wed_device *dev, struct mtk_wed_ring *ring,
  }
  
  static int
 -mtk_wed_wdma_rx_ring_setup(struct mtk_wed_device *dev, int idx, int size)
-+mtk_wed_wdma_rx_ring_setup(struct mtk_wed_device *dev,
-+		int idx, int size, bool reset)
++mtk_wed_wdma_rx_ring_setup(struct mtk_wed_device *dev, int idx, int size,
++			   bool reset)
  {
- 	struct mtk_wed_ring *wdma = &dev->tx_wdma[idx];
+ 	u32 desc_size = sizeof(struct mtk_wdma_desc) * dev->hw->version;
+ 	struct mtk_wed_ring *wdma;
+@@ -1071,8 +1264,8 @@ mtk_wed_wdma_rx_ring_setup(struct mtk_wed_device *dev, int idx, int size)
+ 		return -EINVAL;
  
--	if (mtk_wed_ring_alloc(dev, wdma, MTK_WED_WDMA_RING_SIZE,
--			       dev->ver, true))
--		return -ENOMEM;
-+	if(!reset)
-+		if (mtk_wed_ring_alloc(dev, wdma, MTK_WED_WDMA_RING_SIZE,
-+				       dev->ver, true))
-+			return -ENOMEM;
+ 	wdma = &dev->rx_wdma[idx];
+-	if (mtk_wed_ring_alloc(dev, wdma, MTK_WED_WDMA_RING_SIZE, desc_size,
+-			       true))
++	if (!reset && mtk_wed_ring_alloc(dev, wdma, MTK_WED_WDMA_RING_SIZE,
++					 desc_size, true))
+ 		return -ENOMEM;
  
  	wdma_w32(dev, MTK_WDMA_RING_RX(idx) + MTK_WED_RING_OFS_BASE,
- 		 wdma->desc_phys);
-@@ -1124,13 +1292,15 @@ mtk_wed_wdma_rx_ring_setup(struct mtk_wed_device *dev, int idx, int size)
+@@ -1090,7 +1283,8 @@ mtk_wed_wdma_rx_ring_setup(struct mtk_wed_device *dev, int idx, int size)
  }
  
  static int
 -mtk_wed_wdma_tx_ring_setup(struct mtk_wed_device *dev, int idx, int size)
-+mtk_wed_wdma_tx_ring_setup(struct mtk_wed_device *dev,
-+	int idx, int size, bool reset)
++mtk_wed_wdma_tx_ring_setup(struct mtk_wed_device *dev, int idx, int size,
++			   bool reset)
  {
- 	struct mtk_wed_ring *wdma = &dev->rx_wdma[idx];
+ 	u32 desc_size = sizeof(struct mtk_wdma_desc) * dev->hw->version;
+ 	struct mtk_wed_ring *wdma;
+@@ -1099,8 +1293,8 @@ mtk_wed_wdma_tx_ring_setup(struct mtk_wed_device *dev, int idx, int size)
+ 		return -EINVAL;
  
+ 	wdma = &dev->tx_wdma[idx];
 -	if (mtk_wed_ring_alloc(dev, wdma, MTK_WED_WDMA_RING_SIZE,
--			       dev->ver, true))
--		return -ENOMEM;
-+	if (!reset)
-+		if (mtk_wed_ring_alloc(dev, wdma, MTK_WED_WDMA_RING_SIZE,
-+				       dev->ver, true))
-+			return -ENOMEM;
+-			       desc_size, true))
++	if (!reset && mtk_wed_ring_alloc(dev, wdma, MTK_WED_WDMA_RING_SIZE,
++					 desc_size, true))
+ 		return -ENOMEM;
  
  	wdma_w32(dev, MTK_WDMA_RING_TX(idx) + MTK_WED_RING_OFS_BASE,
- 		 wdma->desc_phys);
-@@ -1140,7 +1310,9 @@ mtk_wed_wdma_tx_ring_setup(struct mtk_wed_device *dev, int idx, int size)
- 		 MTK_WDMA_RING_TX(idx) + MTK_WED_RING_OFS_CPU_IDX, 0);
+@@ -1112,6 +1306,9 @@ mtk_wed_wdma_tx_ring_setup(struct mtk_wed_device *dev, int idx, int size)
  	wdma_w32(dev,
  		 MTK_WDMA_RING_TX(idx) + MTK_WED_RING_OFS_DMA_IDX, 0);
--
+ 
 +	if (reset)
-+		mtk_wed_ring_reset(wdma->desc, MTK_WED_WDMA_RING_SIZE,
-+				   dev->ver, true);
- 	if (idx == 0)  {
- 		wed_w32(dev, MTK_WED_WDMA_RING_TX
- 			+ MTK_WED_RING_OFS_BASE, wdma->desc_phys);
-@@ -1253,9 +1425,12 @@ mtk_wed_start(struct mtk_wed_device *dev, u32 irq_mask)
++		mtk_wed_ring_reset(wdma, MTK_WED_WDMA_RING_SIZE, true);
++
+ 	if (!idx)  {
+ 		wed_w32(dev, MTK_WED_WDMA_RING_TX + MTK_WED_RING_OFS_BASE,
+ 			wdma->desc_phys);
+@@ -1267,9 +1464,12 @@ mtk_wed_start(struct mtk_wed_device *dev, u32 irq_mask)
  {
- 	int i, ret;
+ 	int i;
  
-+	if (dev->ver > MTK_WED_V1)
-+		ret = mtk_wed_rx_bm_alloc(dev);
++	if (mtk_wed_get_rx_capa(dev) && mtk_wed_rx_buffer_alloc(dev))
++		return;
 +
- 	for (i = 0; i < ARRAY_SIZE(dev->tx_wdma); i++)
- 		if (!dev->tx_wdma[i].desc)
+ 	for (i = 0; i < ARRAY_SIZE(dev->rx_wdma); i++)
+ 		if (!dev->rx_wdma[i].desc)
 -			mtk_wed_wdma_rx_ring_setup(dev, i, 16);
 +			mtk_wed_wdma_rx_ring_setup(dev, i, 16, false);
  
+ 
  	mtk_wed_hw_init(dev);
+@@ -1278,10 +1478,9 @@ mtk_wed_start(struct mtk_wed_device *dev, u32 irq_mask)
+ 	mtk_wed_set_ext_int(dev, true);
+ 
+ 	if (dev->hw->version == 1) {
+-		u32 val;
+-
+-		val = dev->wlan.wpdma_phys | MTK_PCIE_MIRROR_MAP_EN |
+-		      FIELD_PREP(MTK_PCIE_MIRROR_MAP_WED_ID, dev->hw->index);
++		u32 val = dev->wlan.wpdma_phys | MTK_PCIE_MIRROR_MAP_EN |
++			  FIELD_PREP(MTK_PCIE_MIRROR_MAP_WED_ID,
++				     dev->hw->index);
  
-@@ -1347,10 +1522,6 @@ mtk_wed_attach(struct mtk_wed_device *dev)
- 		goto error;
+ 		val |= BIT(0) | (BIT(1) * !!dev->hw->index);
+ 		regmap_write(dev->hw->mirror, dev->hw->index * 4, val);
+@@ -1353,10 +1552,6 @@ mtk_wed_attach(struct mtk_wed_device *dev)
+ 		goto out;
  
- 	if (dev->ver > MTK_WED_V1) {
--		ret = mtk_wed_rx_bm_alloc(dev);
+ 	if (mtk_wed_get_rx_capa(dev)) {
+-		ret = mtk_wed_rx_buffer_alloc(dev);
 -		if (ret)
--			goto error;
+-			goto out;
 -
  		ret = mtk_wed_rro_alloc(dev);
  		if (ret)
- 			goto error;
-@@ -1358,6 +1529,10 @@ mtk_wed_attach(struct mtk_wed_device *dev)
+ 			goto out;
+@@ -1364,6 +1559,10 @@ mtk_wed_attach(struct mtk_wed_device *dev)
  
  	mtk_wed_hw_init_early(dev);
  
@@ -609,10 +645,23 @@
 +	init_completion(&dev->wlan_reset_done);
 +	atomic_set(&dev->fe_reset, 0);
 +
- 	if (dev->ver == MTK_WED_V1)
+ 	if (hw->version == 1) {
  		regmap_update_bits(hw->hifsys, HIFSYS_DMA_AG_MAP,
  				   BIT(hw->index), 0);
-@@ -1374,7 +1549,8 @@ mtk_wed_attach(struct mtk_wed_device *dev)
+@@ -1373,8 +1572,10 @@ mtk_wed_attach(struct mtk_wed_device *dev)
+ 	}
+ 
+ out:
+-	if (ret)
+-		mtk_wed_detach(dev);
++	if (ret) {
++		dev_err(dev->hw->dev, "failed to attach wed device\n");
++		__mtk_wed_detach(dev);
++	}
+ unlock:
+ 	mutex_unlock(&hw_lock);
+ 
+@@ -1382,7 +1583,8 @@ mtk_wed_attach(struct mtk_wed_device *dev)
  }
  
  static int
@@ -622,65 +671,52 @@
  {
  	struct mtk_wed_ring *ring = &dev->tx_ring[idx];
  
-@@ -1392,10 +1568,12 @@ mtk_wed_tx_ring_setup(struct mtk_wed_device *dev, int idx, void __iomem *regs)
+@@ -1401,11 +1603,12 @@ mtk_wed_tx_ring_setup(struct mtk_wed_device *dev, int idx, void __iomem *regs)
+ 	if (WARN_ON(idx >= ARRAY_SIZE(dev->tx_ring)))
+ 		return -EINVAL;
  
- 	BUG_ON(idx > ARRAY_SIZE(dev->tx_ring));
- 
--	if (mtk_wed_ring_alloc(dev, ring, MTK_WED_TX_RING_SIZE, 1, true))
--		return -ENOMEM;
-+	if (!reset)
-+		if (mtk_wed_ring_alloc(dev, ring, MTK_WED_TX_RING_SIZE,
-+				       1, true))
-+			return -ENOMEM;
+-	if (mtk_wed_ring_alloc(dev, ring, MTK_WED_TX_RING_SIZE,
+-			       sizeof(*ring->desc), true))
++	if (!reset && mtk_wed_ring_alloc(dev, ring, MTK_WED_TX_RING_SIZE,
++					 sizeof(*ring->desc), true))
+ 		return -ENOMEM;
  
 -	if (mtk_wed_wdma_rx_ring_setup(dev, idx, MTK_WED_WDMA_RING_SIZE))
-+	if (mtk_wed_wdma_rx_ring_setup(dev, idx, MTK_WED_WDMA_RING_SIZE, reset))
++	if (mtk_wed_wdma_rx_ring_setup(dev, idx, MTK_WED_WDMA_RING_SIZE,
++				       reset))
  		return -ENOMEM;
  
  	ring->reg_base = MTK_WED_RING_TX(idx);
-@@ -1443,21 +1621,24 @@ mtk_wed_txfree_ring_setup(struct mtk_wed_device *dev, void __iomem *regs)
+@@ -1450,18 +1653,20 @@ mtk_wed_txfree_ring_setup(struct mtk_wed_device *dev, void __iomem *regs)
  }
  
  static int
 -mtk_wed_rx_ring_setup(struct mtk_wed_device *dev, int idx, void __iomem *regs)
-+mtk_wed_rx_ring_setup(struct mtk_wed_device *dev,
-+		int idx, void __iomem *regs, bool reset)
++mtk_wed_rx_ring_setup(struct mtk_wed_device *dev, int idx, void __iomem *regs,
++		      bool reset)
  {
  	struct mtk_wed_ring *ring = &dev->rx_ring[idx];
  
- 	BUG_ON(idx > ARRAY_SIZE(dev->rx_ring));
+ 	if (WARN_ON(idx >= ARRAY_SIZE(dev->rx_ring)))
+ 		return -EINVAL;
  
-+	if (!reset)
-+		if (mtk_wed_ring_alloc(dev, ring, MTK_WED_RX_RING_SIZE,
-+				       1, false))
-+			return -ENOMEM;
+-	if (mtk_wed_ring_alloc(dev, ring, MTK_WED_RX_RING_SIZE,
+-			       sizeof(*ring->desc), false))
++	if (!reset && mtk_wed_ring_alloc(dev, ring, MTK_WED_RX_RING_SIZE,
++					 sizeof(*ring->desc), false))
+ 		return -ENOMEM;
  
--	if (mtk_wed_ring_alloc(dev, ring, MTK_WED_RX_RING_SIZE, 1, false))
--		return -ENOMEM;
--
 -	if (mtk_wed_wdma_tx_ring_setup(dev, idx, MTK_WED_WDMA_RING_SIZE))
-+	if (mtk_wed_wdma_tx_ring_setup(dev, idx, MTK_WED_WDMA_RING_SIZE, reset))
++	if (mtk_wed_wdma_tx_ring_setup(dev, idx, MTK_WED_WDMA_RING_SIZE,
++				       reset))
  		return -ENOMEM;
  
  	ring->reg_base = MTK_WED_RING_RX_DATA(idx);
- 	ring->wpdma = regs;
-+	dev->hw->ring_num = idx + 1;
- 
- 	/* WPDMA ->  WED */
- 	wpdma_rx_w32(dev, idx, MTK_WED_RING_OFS_BASE, ring->desc_phys);
 diff --git a/drivers/net/ethernet/mediatek/mtk_wed.h b/drivers/net/ethernet/mediatek/mtk_wed.h
-index 8ef5253..490873c 100644
+index 1bfd96f..2ce1a5b 100644
 --- a/drivers/net/ethernet/mediatek/mtk_wed.h
 +++ b/drivers/net/ethernet/mediatek/mtk_wed.h
-@@ -47,6 +47,7 @@ struct mtk_wed_hw {
- 	u32 num_flows;
- 	u32 wdma_phy;
- 	char dirname[5];
-+	int ring_num;
- 	int irq;
- 	int index;
- 	u32 ver;
-@@ -158,6 +159,9 @@ void mtk_wed_add_hw(struct device_node *np, struct mtk_eth *eth,
+@@ -160,6 +160,9 @@ void mtk_wed_add_hw(struct device_node *np, struct mtk_eth *eth,
  void mtk_wed_exit(void);
  int mtk_wed_flow_add(int index);
  void mtk_wed_flow_remove(int index);
@@ -690,7 +726,7 @@
  #else
  static inline void
  mtk_wed_add_hw(struct device_node *np, struct mtk_eth *eth,
-@@ -175,6 +179,13 @@ static inline int mtk_wed_flow_add(int index)
+@@ -178,6 +181,13 @@ static inline int mtk_wed_flow_add(int index)
  static inline void mtk_wed_flow_remove(int index)
  {
  }
@@ -705,10 +741,10 @@
  
  #ifdef CONFIG_DEBUG_FS
 diff --git a/drivers/net/ethernet/mediatek/mtk_wed_regs.h b/drivers/net/ethernet/mediatek/mtk_wed_regs.h
-index 31871f7..403a36b 100644
+index a79305f..645b8b1 100644
 --- a/drivers/net/ethernet/mediatek/mtk_wed_regs.h
 +++ b/drivers/net/ethernet/mediatek/mtk_wed_regs.h
-@@ -38,11 +38,15 @@ struct mtk_wdma_desc {
+@@ -32,11 +32,15 @@ struct mtk_wdma_desc {
  
  #define MTK_WED_RESET					0x008
  #define MTK_WED_RESET_TX_BM				BIT(0)
@@ -724,20 +760,16 @@
  #define MTK_WED_RESET_WDMA_RX_DRV			BIT(17)
  #define MTK_WED_RESET_WDMA_INT_AGENT			BIT(19)
  #define MTK_WED_RESET_RX_RRO_QM				BIT(20)
-@@ -185,7 +189,12 @@ struct mtk_wdma_desc {
- 
+@@ -174,6 +178,8 @@ struct mtk_wdma_desc {
  #define MTK_WED_RESET_IDX				0x20c
  #define MTK_WED_RESET_IDX_TX				GENMASK(3, 0)
-+#if defined(CONFIG_MEDIATEK_NETSYS_V2)
-+#define MTK_WED_RESET_IDX_RX				GENMASK(7, 6)
-+#else
  #define MTK_WED_RESET_IDX_RX				GENMASK(17, 16)
-+#endif
++#define MTK_WED_RESET_IDX_RX_V2				GENMASK(7, 6)
 +#define MTK_WED_RESET_WPDMA_IDX_RX			GENMASK(31, 30)
  
  #define MTK_WED_TX_MIB(_n)				(0x2a0 + (_n) * 4)
  #define MTK_WED_RX_MIB(_n)				(0x2e0 + (_n) * 4)
-@@ -299,6 +308,9 @@ struct mtk_wdma_desc {
+@@ -287,6 +293,9 @@ struct mtk_wdma_desc {
  
  #define MTK_WED_WPDMA_RX_D_GLO_CFG			0x75c
  #define MTK_WED_WPDMA_RX_D_RX_DRV_EN			BIT(0)
@@ -748,10 +780,10 @@
  #define MTK_WED_WPDMA_RX_D_RXD_READ_LEN			GENMASK(31, 24)
  
 diff --git a/include/linux/soc/mediatek/mtk_wed.h b/include/linux/soc/mediatek/mtk_wed.h
-index e8fca31..98ed390 100644
+index 658f392..6772ea8 100644
 --- a/include/linux/soc/mediatek/mtk_wed.h
 +++ b/include/linux/soc/mediatek/mtk_wed.h
-@@ -163,18 +163,23 @@ struct mtk_wed_device {
+@@ -151,16 +151,21 @@ struct mtk_wed_device {
  		void (*release_rx_buf)(struct mtk_wed_device *wed);
  		void (*update_wo_rx_stats)(struct mtk_wed_device *wed,
  					   struct mtk_wed_wo_rx_stats *stats);
@@ -769,60 +801,60 @@
  	int (*tx_ring_setup)(struct mtk_wed_device *dev, int ring,
 -			     void __iomem *regs);
 +			     void __iomem *regs, bool reset);
- 	int (*txfree_ring_setup)(struct mtk_wed_device *dev,
- 				 void __iomem *regs);
  	int (*rx_ring_setup)(struct mtk_wed_device *dev, int ring,
--				 void __iomem *regs);
+-			     void __iomem *regs);
 +			     void __iomem *regs, bool reset);
+ 	int (*txfree_ring_setup)(struct mtk_wed_device *dev,
+ 				 void __iomem *regs);
  	int (*msg_update)(struct mtk_wed_device *dev, int cmd_id,
- 			  void *data, int len);
- 	void (*detach)(struct mtk_wed_device *dev);
-@@ -228,12 +233,13 @@ mtk_wed_get_rx_capa(struct mtk_wed_device *dev)
+@@ -216,8 +221,8 @@ mtk_wed_get_rx_capa(struct mtk_wed_device *dev)
  #define mtk_wed_device_active(_dev) !!(_dev)->ops
  #define mtk_wed_device_detach(_dev) (_dev)->ops->detach(_dev)
  #define mtk_wed_device_start(_dev, _mask) (_dev)->ops->start(_dev, _mask)
 -#define mtk_wed_device_tx_ring_setup(_dev, _ring, _regs) \
 -	(_dev)->ops->tx_ring_setup(_dev, _ring, _regs)
-+#define mtk_wed_device_stop(_dev) (_dev)->ops->stop(_dev)
 +#define mtk_wed_device_tx_ring_setup(_dev, _ring, _regs, _reset) \
-+	(_dev)->ops->tx_ring_setup(_dev, _ring, _regs,  _reset)
++	(_dev)->ops->tx_ring_setup(_dev, _ring, _regs, _reset)
  #define mtk_wed_device_txfree_ring_setup(_dev, _regs) \
  	(_dev)->ops->txfree_ring_setup(_dev, _regs)
--#define mtk_wed_device_rx_ring_setup(_dev, _ring, _regs) \
--	(_dev)->ops->rx_ring_setup(_dev, _ring, _regs)
-+#define mtk_wed_device_rx_ring_setup(_dev, _ring, _regs, _reset) \
-+	(_dev)->ops->rx_ring_setup(_dev, _ring, _regs, _reset)
- #define mtk_wed_device_update_msg(_dev, _id, _msg, _len) \
- 	(_dev)->ops->msg_update(_dev, _id, _msg, _len)
  #define mtk_wed_device_reg_read(_dev, _reg) \
-@@ -244,6 +250,8 @@ mtk_wed_get_rx_capa(struct mtk_wed_device *dev)
+@@ -228,12 +233,14 @@ mtk_wed_get_rx_capa(struct mtk_wed_device *dev)
  	(_dev)->ops->irq_get(_dev, _mask)
  #define mtk_wed_device_irq_set_mask(_dev, _mask) \
  	(_dev)->ops->irq_set_mask(_dev, _mask)
-+#define mtk_wed_device_dma_reset(_dev) \
-+	(_dev)->ops->reset_dma(_dev)
+-#define mtk_wed_device_rx_ring_setup(_dev, _ring, _regs) \
+-	(_dev)->ops->rx_ring_setup(_dev, _ring, _regs)
++#define mtk_wed_device_rx_ring_setup(_dev, _ring, _regs, _reset) \
++	(_dev)->ops->rx_ring_setup(_dev, _ring, _regs, reset)
  #define mtk_wed_device_ppe_check(_dev, _skb, _reason, _hash) \
  	(_dev)->ops->ppe_check(_dev, _skb, _reason, _hash)
+ #define mtk_wed_device_update_msg(_dev, _id, _msg, _len) \
+ 	(_dev)->ops->msg_update(_dev, _id, _msg, _len)
++#define mtk_wed_device_stop(_dev) (_dev)->ops->stop(_dev)
++#define mtk_wed_device_dma_reset(_dev) (_dev)->ops->reset_dma(_dev)
  #else
-@@ -253,14 +261,15 @@ static inline bool mtk_wed_device_active(struct mtk_wed_device *dev)
+ static inline bool mtk_wed_device_active(struct mtk_wed_device *dev)
+ {
+@@ -241,15 +248,17 @@ static inline bool mtk_wed_device_active(struct mtk_wed_device *dev)
  }
  #define mtk_wed_device_detach(_dev) do {} while (0)
  #define mtk_wed_device_start(_dev, _mask) do {} while (0)
 -#define mtk_wed_device_tx_ring_setup(_dev, _ring, _regs) -ENODEV
-+#define mtk_wed_device_stop(_dev) do {} while (0)
 +#define mtk_wed_device_tx_ring_setup(_dev, _ring, _regs, _reset) -ENODEV
  #define mtk_wed_device_txfree_ring_setup(_dev, _ring, _regs) -ENODEV
--#define mtk_wed_device_rx_ring_setup(_dev, _ring, _regs) -ENODEV
--#define mtk_wed_device_update_msg(_dev, _id, _msg, _len) -ENODEV
-+#define mtk_wed_device_rx_ring_setup(_dev, _ring, _regs, _reset) -ENODEV
  #define mtk_wed_device_reg_read(_dev, _reg) 0
  #define mtk_wed_device_reg_write(_dev, _reg, _val) do {} while (0)
  #define mtk_wed_device_irq_get(_dev, _mask) 0
  #define mtk_wed_device_irq_set_mask(_dev, _mask) do {} while (0)
-+#define mtk_wed_device_dma_reset(_dev) do {} while (0)
+-#define mtk_wed_device_rx_ring_setup(_dev, _ring, _regs) -ENODEV
++#define mtk_wed_device_rx_ring_setup(_dev, _ring, _regs, _reset) -ENODEV
  #define mtk_wed_device_ppe_check(_dev, _hash)  do {} while (0)
+ #define mtk_wed_device_update_msg(_dev, _id, _msg, _len) -ENODEV
++#define mtk_wed_device_stop(_dev) do {} while (0)
++#define mtk_wed_device_dma_reset(_dev) do {} while (0)
  #endif
  
+ #endif
 -- 
 2.18.0
 
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/flow_patch/999-3010-ethernet-update-ppe-backward-compatible-two-way-hash.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/flow_patch/999-3010-ethernet-update-ppe-backward-compatible-two-way-hash.patch
index b547328..18c6d2a 100644
--- a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/flow_patch/999-3010-ethernet-update-ppe-backward-compatible-two-way-hash.patch
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/flow_patch/999-3010-ethernet-update-ppe-backward-compatible-two-way-hash.patch
@@ -1,7 +1,7 @@
-From 84fd451dd7379943e6957e9ceb749be4d6c41540 Mon Sep 17 00:00:00 2001
+From 7feee53fdfd481fc2beb02739ccd0e87f1c96b7a Mon Sep 17 00:00:00 2001
 From: Bc-bocun Chen <bc-bocun.chen@mediatek.com>
 Date: Mon, 18 Sep 2023 11:07:14 +0800
-Subject: [PATCH 11/22] ethernet-update-ppe-backward-compatible-two-way-hash
+Subject: [PATCH 10/24] ethernet-update-ppe-backward-compatible-two-way-hash
 
 ---
  drivers/net/ethernet/mediatek/mtk_eth_soc.c | 10 ++++++++-
@@ -11,10 +11,10 @@
  4 files changed, 29 insertions(+), 11 deletions(-)
 
 diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.c b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
-index c1399c5..bd622d3 100644
+index a24b223..e8837b6 100644
 --- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c
 +++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
-@@ -5252,7 +5252,8 @@ static int mtk_probe(struct platform_device *pdev)
+@@ -5799,7 +5799,8 @@ static int mtk_probe(struct platform_device *pdev)
  
  		for (i = 0; i < eth->ppe_num; i++) {
  			eth->ppe[i] = mtk_ppe_init(eth,
@@ -24,7 +24,7 @@
  			if (!eth->ppe[i]) {
  				err = -ENOMEM;
  				goto err_free_dev;
-@@ -5359,6 +5360,7 @@ static const struct mtk_soc_data mt2701_data = {
+@@ -5913,6 +5914,7 @@ static const struct mtk_soc_data mt2701_data = {
  	.required_clks = MT7623_CLKS_BITMAP,
  	.required_pctl = true,
  	.has_sram = false,
@@ -32,7 +32,7 @@
  	.offload_version = 2,
  	.rss_num = 0,
  	.txrx = {
-@@ -5377,6 +5379,7 @@ static const struct mtk_soc_data mt7621_data = {
+@@ -5931,6 +5933,7 @@ static const struct mtk_soc_data mt7621_data = {
  	.required_clks = MT7621_CLKS_BITMAP,
  	.required_pctl = false,
  	.has_sram = false,
@@ -40,7 +40,7 @@
  	.offload_version = 2,
  	.rss_num = 0,
  	.txrx = {
-@@ -5396,6 +5399,7 @@ static const struct mtk_soc_data mt7622_data = {
+@@ -5950,6 +5953,7 @@ static const struct mtk_soc_data mt7622_data = {
  	.required_clks = MT7622_CLKS_BITMAP,
  	.required_pctl = false,
  	.has_sram = false,
@@ -48,7 +48,7 @@
  	.offload_version = 2,
  	.rss_num = 0,
  	.txrx = {
-@@ -5414,6 +5418,7 @@ static const struct mtk_soc_data mt7623_data = {
+@@ -5968,6 +5972,7 @@ static const struct mtk_soc_data mt7623_data = {
  	.required_clks = MT7623_CLKS_BITMAP,
  	.required_pctl = true,
  	.has_sram = false,
@@ -56,7 +56,7 @@
  	.offload_version = 2,
  	.rss_num = 0,
  	.txrx = {
-@@ -5451,6 +5456,7 @@ static const struct mtk_soc_data mt7986_data = {
+@@ -6005,6 +6010,7 @@ static const struct mtk_soc_data mt7986_data = {
  	.required_clks = MT7986_CLKS_BITMAP,
  	.required_pctl = false,
  	.has_sram = false,
@@ -64,7 +64,7 @@
  	.offload_version = 2,
  	.rss_num = 4,
  	.txrx = {
-@@ -5470,6 +5476,8 @@ static const struct mtk_soc_data mt7981_data = {
+@@ -6024,6 +6030,8 @@ static const struct mtk_soc_data mt7981_data = {
  	.required_clks = MT7981_CLKS_BITMAP,
  	.required_pctl = false,
  	.has_sram = false,
@@ -74,10 +74,10 @@
  	.txrx = {
  		.txd_size = sizeof(struct mtk_tx_dma_v2),
 diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.h b/drivers/net/ethernet/mediatek/mtk_eth_soc.h
-index 960b979..68b8ab1 100644
+index 9099dea..b4f04e2 100644
 --- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h
 +++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h
-@@ -1679,6 +1679,7 @@ struct mtk_soc_data {
+@@ -1732,6 +1732,7 @@ struct mtk_soc_data {
  	u64		caps;
  	u64		required_clks;
  	bool		required_pctl;
@@ -86,7 +86,7 @@
  	netdev_features_t hw_features;
  	bool		has_sram;
 diff --git a/drivers/net/ethernet/mediatek/mtk_ppe.c b/drivers/net/ethernet/mediatek/mtk_ppe.c
-index 96c15b3..4da7e7a 100755
+index c9ee505..569bf34 100755
 --- a/drivers/net/ethernet/mediatek/mtk_ppe.c
 +++ b/drivers/net/ethernet/mediatek/mtk_ppe.c
 @@ -88,7 +88,7 @@ static void mtk_ppe_cache_enable(struct mtk_ppe *ppe, bool enable)
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/flow_patch/999-3011-flow-offload-add-mtkhnat-flow-accounting.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/flow_patch/999-3011-flow-offload-add-mtkhnat-flow-accounting.patch
index c516fd6..6a2a6f6 100644
--- a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/flow_patch/999-3011-flow-offload-add-mtkhnat-flow-accounting.patch
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/flow_patch/999-3011-flow-offload-add-mtkhnat-flow-accounting.patch
@@ -1,7 +1,7 @@
-From 77bdae190ded4dfafa80dfaf04a77018e33e233c Mon Sep 17 00:00:00 2001
+From 4eaba588e0c730d6188f5f1b667a55d1b9ca0fe6 Mon Sep 17 00:00:00 2001
 From: Bc-bocun Chen <bc-bocun.chen@mediatek.com>
 Date: Mon, 18 Sep 2023 11:09:23 +0800
-Subject: [PATCH 12/22] flow-offload-add-mtkhnat-flow-accounting
+Subject: [PATCH 11/24] flow-offload-add-mtkhnat-flow-accounting
 
 ---
  drivers/net/ethernet/mediatek/mtk_eth_soc.c   |  11 +-
@@ -15,10 +15,10 @@
  8 files changed, 191 insertions(+), 8 deletions(-)
 
 diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.c b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
-index bd622d3..9d8ce07 100644
+index e8837b6..9cd306d 100644
 --- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c
 +++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
-@@ -5253,7 +5253,8 @@ static int mtk_probe(struct platform_device *pdev)
+@@ -5800,7 +5800,8 @@ static int mtk_probe(struct platform_device *pdev)
  		for (i = 0; i < eth->ppe_num; i++) {
  			eth->ppe[i] = mtk_ppe_init(eth,
  						   eth->base + MTK_ETH_PPE_BASE + i * 0x400,
@@ -28,7 +28,7 @@
  			if (!eth->ppe[i]) {
  				err = -ENOMEM;
  				goto err_free_dev;
-@@ -5360,6 +5361,7 @@ static const struct mtk_soc_data mt2701_data = {
+@@ -5914,6 +5915,7 @@ static const struct mtk_soc_data mt2701_data = {
  	.required_clks = MT7623_CLKS_BITMAP,
  	.required_pctl = true,
  	.has_sram = false,
@@ -36,7 +36,7 @@
  	.hash_way = 2,
  	.offload_version = 2,
  	.rss_num = 0,
-@@ -5379,6 +5381,7 @@ static const struct mtk_soc_data mt7621_data = {
+@@ -5933,6 +5935,7 @@ static const struct mtk_soc_data mt7621_data = {
  	.required_clks = MT7621_CLKS_BITMAP,
  	.required_pctl = false,
  	.has_sram = false,
@@ -44,7 +44,7 @@
  	.hash_way = 2,
  	.offload_version = 2,
  	.rss_num = 0,
-@@ -5399,6 +5402,7 @@ static const struct mtk_soc_data mt7622_data = {
+@@ -5953,6 +5956,7 @@ static const struct mtk_soc_data mt7622_data = {
  	.required_clks = MT7622_CLKS_BITMAP,
  	.required_pctl = false,
  	.has_sram = false,
@@ -52,7 +52,7 @@
  	.hash_way = 2,
  	.offload_version = 2,
  	.rss_num = 0,
-@@ -5418,6 +5422,7 @@ static const struct mtk_soc_data mt7623_data = {
+@@ -5972,6 +5976,7 @@ static const struct mtk_soc_data mt7623_data = {
  	.required_clks = MT7623_CLKS_BITMAP,
  	.required_pctl = true,
  	.has_sram = false,
@@ -60,7 +60,7 @@
  	.hash_way = 2,
  	.offload_version = 2,
  	.rss_num = 0,
-@@ -5438,6 +5443,7 @@ static const struct mtk_soc_data mt7629_data = {
+@@ -5992,6 +5997,7 @@ static const struct mtk_soc_data mt7629_data = {
  	.required_clks = MT7629_CLKS_BITMAP,
  	.required_pctl = false,
  	.has_sram = false,
@@ -68,7 +68,7 @@
  	.rss_num = 0,
  	.txrx = {
  		.txd_size = sizeof(struct mtk_tx_dma),
-@@ -5456,6 +5462,7 @@ static const struct mtk_soc_data mt7986_data = {
+@@ -6010,6 +6016,7 @@ static const struct mtk_soc_data mt7986_data = {
  	.required_clks = MT7986_CLKS_BITMAP,
  	.required_pctl = false,
  	.has_sram = false,
@@ -76,7 +76,7 @@
  	.hash_way = 4,
  	.offload_version = 2,
  	.rss_num = 4,
-@@ -5476,6 +5483,7 @@ static const struct mtk_soc_data mt7981_data = {
+@@ -6030,6 +6037,7 @@ static const struct mtk_soc_data mt7981_data = {
  	.required_clks = MT7981_CLKS_BITMAP,
  	.required_pctl = false,
  	.has_sram = false,
@@ -84,7 +84,7 @@
  	.hash_way = 4,
  	.offload_version = 2,
  	.rss_num = 4,
-@@ -5513,6 +5521,7 @@ static const struct mtk_soc_data rt5350_data = {
+@@ -6067,6 +6075,7 @@ static const struct mtk_soc_data rt5350_data = {
  	.required_clks = MT7628_CLKS_BITMAP,
  	.required_pctl = false,
  	.has_sram = false,
@@ -93,10 +93,10 @@
  	.txrx = {
  		.txd_size = sizeof(struct mtk_tx_dma),
 diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.h b/drivers/net/ethernet/mediatek/mtk_eth_soc.h
-index 68b8ab1..101c233 100644
+index b4f04e2..5f90765 100644
 --- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h
 +++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h
-@@ -1683,6 +1683,7 @@ struct mtk_soc_data {
+@@ -1736,6 +1736,7 @@ struct mtk_soc_data {
  	u8		offload_version;
  	netdev_features_t hw_features;
  	bool		has_sram;
@@ -105,7 +105,7 @@
  		u32	txd_size;
  		u32	rxd_size;
 diff --git a/drivers/net/ethernet/mediatek/mtk_ppe.c b/drivers/net/ethernet/mediatek/mtk_ppe.c
-index 4da7e7a..f55a95c 100755
+index 569bf34..94e03b2 100755
 --- a/drivers/net/ethernet/mediatek/mtk_ppe.c
 +++ b/drivers/net/ethernet/mediatek/mtk_ppe.c
 @@ -74,6 +74,46 @@ static int mtk_ppe_wait_busy(struct mtk_ppe *ppe)
@@ -446,10 +446,10 @@
  #define MTK_PPE_MIB_CACHE_CTL_EN		BIT(0)
  #define MTK_PPE_MIB_CACHE_CTL_FLUSH		BIT(2)
 diff --git a/net/netfilter/xt_FLOWOFFLOAD.c b/net/netfilter/xt_FLOWOFFLOAD.c
-index 2cab008..1defb15 100644
+index e4c7db9..aae37f5 100644
 --- a/net/netfilter/xt_FLOWOFFLOAD.c
 +++ b/net/netfilter/xt_FLOWOFFLOAD.c
-@@ -766,7 +766,7 @@ static int __init xt_flowoffload_tg_init(void)
+@@ -772,7 +772,7 @@ static int __init xt_flowoffload_tg_init(void)
  	if (ret)
  		goto cleanup;
  
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/flow_patch/999-3012-flow-offload-add-mtkhnat-qdma-qos.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/flow_patch/999-3012-flow-offload-add-mtkhnat-qdma-qos.patch
index d51f24f..4110b83 100644
--- a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/flow_patch/999-3012-flow-offload-add-mtkhnat-qdma-qos.patch
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/flow_patch/999-3012-flow-offload-add-mtkhnat-qdma-qos.patch
@@ -1,19 +1,19 @@
-From 9e21d6fa97e93cb2ba9b923810666ddaf7a981ee Mon Sep 17 00:00:00 2001
+From 0247c9d63f56bbe34f4205f986957b5036a9a4d8 Mon Sep 17 00:00:00 2001
 From: Bc-bocun Chen <bc-bocun.chen@mediatek.com>
 Date: Mon, 18 Sep 2023 11:11:03 +0800
-Subject: [PATCH 13/22] flow-offload-add-mtkhnat-qdma-qos
+Subject: [PATCH 12/24] flow-offload-add-mtkhnat-qdma-qos
 
 ---
  drivers/net/ethernet/mediatek/Makefile        |   2 +-
  drivers/net/ethernet/mediatek/mtk_eth_soc.c   |  10 +
- drivers/net/ethernet/mediatek/mtk_eth_soc.h   |  48 ++-
+ drivers/net/ethernet/mediatek/mtk_eth_soc.h   |  50 ++
  drivers/net/ethernet/mediatek/mtk_ppe.c       |  48 +-
  drivers/net/ethernet/mediatek/mtk_ppe.h       |   4 +
  .../net/ethernet/mediatek/mtk_ppe_offload.c   |  28 +-
  .../net/ethernet/mediatek/mtk_qdma_debugfs.c  | 439 ++++++++++++++++++
  include/net/flow_offload.h                    |   1 +
  net/netfilter/nf_flow_table_offload.c         |   4 +-
- 9 files changed, 593 insertions(+), 6 deletions(-)
+ 9 files changed, 581 insertions(+), 5 deletions(-)
  create mode 100644 drivers/net/ethernet/mediatek/mtk_qdma_debugfs.c
 
 diff --git a/drivers/net/ethernet/mediatek/Makefile b/drivers/net/ethernet/mediatek/Makefile
@@ -30,10 +30,10 @@
  ifdef CONFIG_DEBUG_FS
  mtk_eth-$(CONFIG_NET_MEDIATEK_SOC_WED) += mtk_wed_debugfs.o
 diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.c b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
-index 9d8ce07..0f6613b 100644
+index 9cd306d..1660fd9 100644
 --- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c
 +++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
-@@ -5266,6 +5266,8 @@ static int mtk_probe(struct platform_device *pdev)
+@@ -5813,6 +5813,8 @@ static int mtk_probe(struct platform_device *pdev)
  		}
  
  		mtk_ppe_debugfs_init(eth);
@@ -42,7 +42,7 @@
  	}
  
  	for (i = 0; i < MTK_MAX_DEVS; i++) {
-@@ -5371,6 +5373,7 @@ static const struct mtk_soc_data mt2701_data = {
+@@ -5925,6 +5927,7 @@ static const struct mtk_soc_data mt2701_data = {
  		.rx_dma_l4_valid = RX_DMA_L4_VALID,
  		.dma_max_len = MTK_TX_DMA_BUF_LEN,
  		.dma_len_offset = MTK_TX_DMA_BUF_SHIFT,
@@ -50,7 +50,7 @@
  	},
  };
  
-@@ -5391,6 +5394,7 @@ static const struct mtk_soc_data mt7621_data = {
+@@ -5945,6 +5948,7 @@ static const struct mtk_soc_data mt7621_data = {
  		.rxd_size = sizeof(struct mtk_rx_dma),
  		.dma_max_len = MTK_TX_DMA_BUF_LEN,
  		.dma_len_offset = MTK_TX_DMA_BUF_SHIFT,
@@ -58,7 +58,7 @@
  	},
  };
  
-@@ -5412,6 +5416,7 @@ static const struct mtk_soc_data mt7622_data = {
+@@ -5966,6 +5970,7 @@ static const struct mtk_soc_data mt7622_data = {
  		.rx_dma_l4_valid = RX_DMA_L4_VALID,
  		.dma_max_len = MTK_TX_DMA_BUF_LEN,
  		.dma_len_offset = MTK_TX_DMA_BUF_SHIFT,
@@ -66,7 +66,7 @@
  	},
  };
  
-@@ -5432,6 +5437,7 @@ static const struct mtk_soc_data mt7623_data = {
+@@ -5986,6 +5991,7 @@ static const struct mtk_soc_data mt7623_data = {
  		.rx_dma_l4_valid = RX_DMA_L4_VALID,
  		.dma_max_len = MTK_TX_DMA_BUF_LEN,
  		.dma_len_offset = MTK_TX_DMA_BUF_SHIFT,
@@ -74,7 +74,7 @@
  	},
  };
  
-@@ -5472,6 +5478,7 @@ static const struct mtk_soc_data mt7986_data = {
+@@ -6026,6 +6032,7 @@ static const struct mtk_soc_data mt7986_data = {
  		.rx_dma_l4_valid = RX_DMA_L4_VALID_V2,
  		.dma_max_len = MTK_TX_DMA_BUF_LEN_V2,
  		.dma_len_offset = MTK_TX_DMA_BUF_SHIFT_V2,
@@ -82,7 +82,7 @@
  	},
  };
  
-@@ -5493,6 +5500,7 @@ static const struct mtk_soc_data mt7981_data = {
+@@ -6047,6 +6054,7 @@ static const struct mtk_soc_data mt7981_data = {
  		.rx_dma_l4_valid = RX_DMA_L4_VALID_V2,
  		.dma_max_len = MTK_TX_DMA_BUF_LEN_V2,
  		.dma_len_offset = MTK_TX_DMA_BUF_SHIFT_V2,
@@ -90,7 +90,7 @@
  	},
  };
  
-@@ -5511,6 +5519,7 @@ static const struct mtk_soc_data mt7988_data = {
+@@ -6065,6 +6073,7 @@ static const struct mtk_soc_data mt7988_data = {
  		.rx_dma_l4_valid = RX_DMA_L4_VALID_V2,
  		.dma_max_len = MTK_TX_DMA_BUF_LEN_V2,
  		.dma_len_offset = MTK_TX_DMA_BUF_SHIFT_V2,
@@ -98,7 +98,7 @@
  	},
  };
  
-@@ -5529,6 +5538,7 @@ static const struct mtk_soc_data rt5350_data = {
+@@ -6083,6 +6092,7 @@ static const struct mtk_soc_data rt5350_data = {
  		.rx_dma_l4_valid = RX_DMA_L4_VALID_PDMA,
  		.dma_max_len = MTK_TX_DMA_BUF_LEN,
  		.dma_len_offset = MTK_TX_DMA_BUF_SHIFT,
@@ -107,10 +107,10 @@
  };
  
 diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.h b/drivers/net/ethernet/mediatek/mtk_eth_soc.h
-index 101c233..7ea380e 100644
+index 5f90765..02ca0b2 100644
 --- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h
 +++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h
-@@ -458,6 +471,9 @@
+@@ -487,6 +487,9 @@
  #define FC_THRES_DROP_EN	(7 << 16)
  #define FC_THRES_MIN		0x4444
  
@@ -120,7 +120,7 @@
  /* QDMA Interrupt Status Register */
  #define MTK_QDMA_INT_STATUS	(QDMA_BASE + 0x218)
  #if defined(CONFIG_MEDIATEK_NETSYS_RX_V2) || defined(CONFIG_MEDIATEK_NETSYS_V3)
-@@ -494,6 +510,11 @@
+@@ -530,6 +533,11 @@
  /* QDMA Interrupt Mask Register */
  #define MTK_QDMA_HRED2		(QDMA_BASE + 0x244)
  
@@ -132,7 +132,7 @@
  /* QDMA TX Forward CPU Pointer Register */
  #define MTK_QTX_CTX_PTR		(QDMA_BASE +0x300)
  
-@@ -521,6 +542,14 @@
+@@ -557,6 +565,14 @@
  /* QDMA FQ Free Page Buffer Length Register */
  #define MTK_QDMA_FQ_BLEN	(QDMA_BASE +0x32c)
  
@@ -147,7 +147,7 @@
  /* WDMA Registers */
  #define MTK_WDMA_CTX_PTR(x)	(WDMA_BASE(x) + 0x8)
  #define MTK_WDMA_DTX_PTR(x)	(WDMA_BASE(x) + 0xC)
-@@ -1690,6 +1719,7 @@ struct mtk_soc_data {
+@@ -1743,6 +1759,7 @@ struct mtk_soc_data {
  		u32	rx_dma_l4_valid;
  		u32	dma_max_len;
  		u32	dma_len_offset;
@@ -155,7 +155,7 @@
  	} txrx;
  };
  
-@@ -1879,6 +1909,7 @@ struct mtk_eth {
+@@ -1936,6 +1953,7 @@ struct mtk_eth {
  	spinlock_t			syscfg0_lock;
  	struct timer_list		mtk_dma_monitor_timer;
  
@@ -163,7 +163,7 @@
  	u8				ppe_num;
  	struct mtk_ppe			*ppe[MTK_MAX_PPE_NUM];
  	struct rhashtable		flow_table;
-@@ -1936,6 +1967,36 @@ extern const struct of_device_id of_mtk_match[];
+@@ -1994,6 +2012,36 @@ extern const struct of_device_id of_mtk_match[];
  extern u32 mtk_hwlro_stats_ebl;
  extern u32 dbg_show_level;
  
@@ -200,7 +200,7 @@
  /* read the hardware status register */
  void mtk_stats_update_mac(struct mtk_mac *mac);
  
-@@ -1969,4 +2028,6 @@ void mtk_eth_set_dma_device(struct mtk_eth *eth, struct device *dma_dev);
+@@ -2027,4 +2075,6 @@ void mtk_eth_set_dma_device(struct mtk_eth *eth, struct device *dma_dev);
  u32 mtk_rss_indr_table(struct mtk_rss_params *rss_params, int index);
  
  int mtk_ppe_debugfs_init(struct mtk_eth *eth);
@@ -208,7 +208,7 @@
 +int mtk_qdma_debugfs_init(struct mtk_eth *eth);
  #endif /* MTK_ETH_H */
 diff --git a/drivers/net/ethernet/mediatek/mtk_ppe.c b/drivers/net/ethernet/mediatek/mtk_ppe.c
-index f55a95c..6d6c1e4 100755
+index 94e03b2..8388f65 100755
 --- a/drivers/net/ethernet/mediatek/mtk_ppe.c
 +++ b/drivers/net/ethernet/mediatek/mtk_ppe.c
 @@ -128,7 +128,7 @@ static void mtk_ppe_cache_enable(struct mtk_ppe *ppe, bool enable)
@@ -366,7 +366,7 @@
  		return err;
 diff --git a/drivers/net/ethernet/mediatek/mtk_qdma_debugfs.c b/drivers/net/ethernet/mediatek/mtk_qdma_debugfs.c
 new file mode 100644
-index 0000000..3a7c585
+index 0000000..d76b3c5
 --- /dev/null
 +++ b/drivers/net/ethernet/mediatek/mtk_qdma_debugfs.c
 @@ -0,0 +1,439 @@
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/flow_patch/999-3013-flow-offload-ovs-support.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/flow_patch/999-3013-flow-offload-ovs-support.patch
index a164d1a..5220a63 100644
--- a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/flow_patch/999-3013-flow-offload-ovs-support.patch
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/flow_patch/999-3013-flow-offload-ovs-support.patch
@@ -1,7 +1,7 @@
-From 842a435bd21807447504a387e5ebb8071b0db93f Mon Sep 17 00:00:00 2001
+From f3112e335a7f95aeb3d834962de813baadc1f620 Mon Sep 17 00:00:00 2001
 From: Evelyn Tsai <evelyn.tsai@mediatek.com>
 Date: Mon, 18 Sep 2023 11:11:41 +0800
-Subject: [PATCH 14/22] flow-offload-ovs-support
+Subject: [PATCH 13/24] flow-offload-ovs-support
 
 ---
  net/openvswitch/vport-internal_dev.c | 46 ++++++++++++++++++++++++++++
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/flow_patch/999-3014-update-net-bridge-for-bridger.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/flow_patch/999-3014-update-net-bridge-for-bridger.patch
index 89e664f..a23233f 100644
--- a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/flow_patch/999-3014-update-net-bridge-for-bridger.patch
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/flow_patch/999-3014-update-net-bridge-for-bridger.patch
@@ -1,7 +1,7 @@
-From 120baca4e8b019d03c8d1a29012cea911629247a Mon Sep 17 00:00:00 2001
+From 552ae5e27e936eb74dd563485ab77f40b96a61a5 Mon Sep 17 00:00:00 2001
 From: Bc-bocun Chen <bc-bocun.chen@mediatek.com>
 Date: Mon, 18 Sep 2023 11:13:51 +0800
-Subject: [PATCH 15/22] update-net-bridge-for-bridger
+Subject: [PATCH 14/24] update-net-bridge-for-bridger
 
 ---
  include/net/switchdev.h        |   2 +
@@ -1805,10 +1805,10 @@
 +	return false;
 +}
 diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c
-index da1ef00..b896f71 100644
+index 4eed989..de75eb2 100644
 --- a/net/core/rtnetlink.c
 +++ b/net/core/rtnetlink.c
-@@ -1998,6 +1998,7 @@ static int rtnl_dump_ifinfo(struct sk_buff *skb, struct netlink_callback *cb)
+@@ -2004,6 +2004,7 @@ static int rtnl_dump_ifinfo(struct sk_buff *skb, struct netlink_callback *cb)
  				goto cont;
  			if (idx < s_idx)
  				goto cont;
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/flow_patch/999-3015-ethernet-update-ppe-from-netsys2-to-netsys3.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/flow_patch/999-3015-ethernet-update-ppe-from-netsys2-to-netsys3.patch
index bedf09e..b6c0d41 100644
--- a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/flow_patch/999-3015-ethernet-update-ppe-from-netsys2-to-netsys3.patch
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/flow_patch/999-3015-ethernet-update-ppe-from-netsys2-to-netsys3.patch
@@ -1,44 +1,31 @@
-From 5481f7ecbd3cfffd8234bc8e952a6e07f42de76c Mon Sep 17 00:00:00 2001
+From aaac91720ca1fd7679896286eac2b014e7150fca Mon Sep 17 00:00:00 2001
 From: Bo-Cun Chen <bc-bocun.chen@mediatek.com>
-Date: Tue, 21 Nov 2023 16:42:01 +0800
-Subject: [PATCH 16/22] ethernet-update-ppe-from-netsys2-to-netsys3
+Date: Mon, 18 Mar 2024 16:35:07 +0800
+Subject: [PATCH 15/24] ethernet-update-ppe-from-netsys2-to-netsys3
 
 ---
- drivers/net/ethernet/mediatek/mtk_eth_soc.c   | 14 ++++---
+ drivers/net/ethernet/mediatek/mtk_eth_soc.c   |  8 +++-
  drivers/net/ethernet/mediatek/mtk_eth_soc.h   |  7 ++--
  drivers/net/ethernet/mediatek/mtk_ppe.c       | 35 ++++++++++++++---
  drivers/net/ethernet/mediatek/mtk_ppe.h       | 38 ++++++++++++++++---
  .../net/ethernet/mediatek/mtk_ppe_offload.c   |  6 ++-
  drivers/net/ethernet/mediatek/mtk_ppe_regs.h  |  7 ++++
- 6 files changed, 85 insertions(+), 22 deletions(-)
+ 6 files changed, 82 insertions(+), 19 deletions(-)
 
 diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.c b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
-index 850bc4f..8910d40 100644
+index 952bf51..f477ff3 100644
 --- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c
 +++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
-@@ -2248,17 +2248,17 @@ static int mtk_poll_rx(struct napi_struct *napi, int budget,
+@@ -2447,7 +2447,7 @@ static int mtk_poll_rx(struct napi_struct *napi, int budget,
  			skb_checksum_none_assert(skb);
  		skb->protocol = eth_type_trans(skb, netdev);
  
 -#if defined(CONFIG_MEDIATEK_NETSYS_RX_V2)
--			hash = trxd.rxd5 & MTK_RXD5_FOE_ENTRY_V2;
 +#if defined(CONFIG_MEDIATEK_NETSYS_RX_V2) || defined(CONFIG_MEDIATEK_NETSYS_V3)
-+		hash = trxd.rxd5 & MTK_RXD5_FOE_ENTRY_V2;
- #else
--			hash = trxd.rxd4 & MTK_RXD4_FOE_ENTRY;
-+		hash = trxd.rxd4 & MTK_RXD4_FOE_ENTRY;
- #endif
- 		if (hash != MTK_RXD4_FOE_ENTRY) {
- 			hash = jhash_1word(hash, 0);
- 			skb_set_hash(skb, hash, PKT_HASH_TYPE_L4);
- 		}
- 
--#if defined(CONFIG_MEDIATEK_NETSYS_RX_V2)
-+#if defined(CONFIG_MEDIATEK_NETSYS_RX_V2) || defined(CONFIG_MEDIATEK_NETSYS_V3)
+ 		hash = trxd.rxd5 & MTK_RXD5_FOE_ENTRY_V2;
  		reason = FIELD_GET(MTK_RXD5_PPE_CPU_REASON_V2, trxd.rxd5);
- 		if (reason == MTK_PPE_CPU_REASON_HIT_UNBIND_RATE_REACHED) {
- 			for (i = 0; i < eth->ppe_num; i++) {
-@@ -5290,7 +5290,8 @@ static int mtk_probe(struct platform_device *pdev)
+ 		if (hash != MTK_RXD5_FOE_ENTRY_V2) {
+@@ -5798,7 +5798,8 @@ static int mtk_probe(struct platform_device *pdev)
  
  		for (i = 0; i < eth->ppe_num; i++) {
  			eth->ppe[i] = mtk_ppe_init(eth,
@@ -48,7 +35,7 @@
  						   2, eth->soc->hash_way, i,
  						   eth->soc->has_accounting);
  			if (!eth->ppe[i]) {
-@@ -5557,6 +5558,9 @@ static const struct mtk_soc_data mt7988_data = {
+@@ -6065,6 +6066,9 @@ static const struct mtk_soc_data mt7988_data = {
  	.required_clks = MT7988_CLKS_BITMAP,
  	.required_pctl = false,
  	.has_sram = true,
@@ -59,10 +46,10 @@
  	.txrx = {
  		.txd_size = sizeof(struct mtk_tx_dma_v2),
 diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.h b/drivers/net/ethernet/mediatek/mtk_eth_soc.h
-index 9c77f14..c7d36c5 100644
+index 58547af..9c46ac1 100644
 --- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h
 +++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h
-@@ -134,9 +134,10 @@
+@@ -137,9 +137,10 @@
  #define MTK_GDMA_UCS_EN		BIT(20)
  #define MTK_GDMA_STRP_CRC	BIT(16)
  #define MTK_GDMA_TO_PDMA	0x0
@@ -74,7 +61,7 @@
  #else
  #define MTK_GDMA_TO_PPE0	0x4444
  #endif
-@@ -1978,14 +1979,14 @@ extern u32 dbg_show_level;
+@@ -2018,14 +2019,14 @@ extern u32 dbg_show_level;
  
  static inline void mtk_set_ib1_sp(struct mtk_eth *eth, struct mtk_foe_entry *foe, u32 val)
  {
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/flow_patch/999-3016-mediatek-ethernet-add-wifi2wifi-offload-support.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/flow_patch/999-3016-mediatek-ethernet-add-wifi2wifi-offload-support.patch
index 121db94..14639c4 100644
--- a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/flow_patch/999-3016-mediatek-ethernet-add-wifi2wifi-offload-support.patch
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/flow_patch/999-3016-mediatek-ethernet-add-wifi2wifi-offload-support.patch
@@ -1,21 +1,21 @@
-From d3183ad9ed0a8a35047a37f30d85f920a729897c Mon Sep 17 00:00:00 2001
+From 743b10e8e2a17c904f27cf78d46aea64193fc41c Mon Sep 17 00:00:00 2001
 From: Sujuan Chen <sujuan.chen@mediatek.com>
 Date: Mon, 18 Sep 2023 11:16:18 +0800
-Subject: [PATCH 17/22] mediatek-ethernet-add-wifi2wifi-offload-support
+Subject: [PATCH 16/24] mediatek-ethernet-add-wifi2wifi-offload-support
 
 ---
  drivers/net/ethernet/mediatek/mtk_eth_soc.h   |  2 ++
  .../net/ethernet/mediatek/mtk_ppe_offload.c   | 35 +++++++++++++------
  drivers/net/ethernet/mediatek/mtk_wed.c       | 13 +++++++
- include/linux/soc/mediatek/mtk_wed.h          |  6 +++-
- 4 files changed, 45 insertions(+), 11 deletions(-)
+ include/linux/soc/mediatek/mtk_wed.h          |  5 +++
+ 4 files changed, 45 insertions(+), 10 deletions(-)
  mode change 100755 => 100644 drivers/net/ethernet/mediatek/mtk_ppe_offload.c
 
 diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.h b/drivers/net/ethernet/mediatek/mtk_eth_soc.h
-index 23c5f49..ee89b4c 100644
+index f9dda59..88d2f46 100644
 --- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h
 +++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h
-@@ -2027,6 +2027,8 @@ void mtk_usxgmii_link_poll(struct work_struct *work);
+@@ -2072,6 +2072,8 @@ void mtk_usxgmii_link_poll(struct work_struct *work);
  int mtk_eth_offload_init(struct mtk_eth *eth, int id);
  int mtk_eth_setup_tc(struct net_device *dev, enum tc_setup_type type,
  		     void *type_data);
@@ -100,15 +100,15 @@
  		return -EOPNOTSUPP;
  	}
 diff --git a/drivers/net/ethernet/mediatek/mtk_wed.c b/drivers/net/ethernet/mediatek/mtk_wed.c
-index ae31412..3e760f7 100644
+index 5dd1182..68eedd3 100644
 --- a/drivers/net/ethernet/mediatek/mtk_wed.c
 +++ b/drivers/net/ethernet/mediatek/mtk_wed.c
-@@ -1733,6 +1733,18 @@ void mtk_wed_flow_remove(int index)
+@@ -1766,6 +1766,18 @@ void mtk_wed_flow_remove(int index)
  	mutex_unlock(&hw_lock);
  }
  
 +static int mtk_wed_eth_setup_tc(struct mtk_wed_device *wed, struct net_device *dev,
-+		int type, void *type_data)
++				int type, void *type_data)
 +{
 +	switch (type) {
 +	case TC_SETUP_BLOCK:
@@ -120,9 +120,9 @@
 +}
 +
  void mtk_wed_add_hw(struct device_node *np, struct mtk_eth *eth,
- 			void __iomem *wdma, u32 wdma_phy, int index)
- 
-@@ -1751,6 +1763,7 @@ void mtk_wed_add_hw(struct device_node *np, struct mtk_eth *eth,
+ 		    void __iomem *wdma, phys_addr_t wdma_phy,
+ 		    int index)
+@@ -1785,6 +1797,7 @@ void mtk_wed_add_hw(struct device_node *np, struct mtk_eth *eth,
  		.irq_get = mtk_wed_irq_get,
  		.irq_set_mask = mtk_wed_irq_set_mask,
  		.detach = mtk_wed_detach,
@@ -131,36 +131,35 @@
  	};
  	struct device_node *eth_np = eth->dev->of_node;
 diff --git a/include/linux/soc/mediatek/mtk_wed.h b/include/linux/soc/mediatek/mtk_wed.h
-index 98ed390..27cf284 100644
+index 6772ea8..470beb2 100644
 --- a/include/linux/soc/mediatek/mtk_wed.h
 +++ b/include/linux/soc/mediatek/mtk_wed.h
-@@ -183,7 +183,8 @@ struct mtk_wed_ops {
- 	int (*msg_update)(struct mtk_wed_device *dev, int cmd_id,
- 			  void *data, int len);
+@@ -173,6 +173,8 @@ struct mtk_wed_ops {
  	void (*detach)(struct mtk_wed_device *dev);
--
+ 	void (*ppe_check)(struct mtk_wed_device *dev, struct sk_buff *skb,
+ 			  u32 reason, u32 hash);
 +	int (*setup_tc)(struct mtk_wed_device *wed, struct net_device *dev,
-+			 int type, void *type_data);
++			int type, void *type_data);
+ 
  	void (*stop)(struct mtk_wed_device *dev);
  	void (*start)(struct mtk_wed_device *dev, u32 irq_mask);
- 	void (*reset_dma)(struct mtk_wed_device *dev);
-@@ -232,6 +233,8 @@ mtk_wed_get_rx_capa(struct mtk_wed_device *dev)
- #ifdef CONFIG_NET_MEDIATEK_SOC_WED
- #define mtk_wed_device_active(_dev) !!(_dev)->ops
- #define mtk_wed_device_detach(_dev) (_dev)->ops->detach(_dev)
+@@ -241,6 +243,8 @@ mtk_wed_get_rx_capa(struct mtk_wed_device *dev)
+ 	(_dev)->ops->msg_update(_dev, _id, _msg, _len)
+ #define mtk_wed_device_stop(_dev) (_dev)->ops->stop(_dev)
+ #define mtk_wed_device_dma_reset(_dev) (_dev)->ops->reset_dma(_dev)
 +#define mtk_wed_device_setup_tc(_dev, _ndev, _type, _data) \
 +	(_dev)->ops->setup_tc(_dev, _ndev, _type, _data)
- #define mtk_wed_device_start(_dev, _mask) (_dev)->ops->start(_dev, _mask)
- #define mtk_wed_device_stop(_dev) (_dev)->ops->stop(_dev)
- #define mtk_wed_device_tx_ring_setup(_dev, _ring, _regs, _reset) \
-@@ -270,6 +273,7 @@ static inline bool mtk_wed_device_active(struct mtk_wed_device *dev)
- #define mtk_wed_device_irq_get(_dev, _mask) 0
- #define mtk_wed_device_irq_set_mask(_dev, _mask) do {} while (0)
+ #else
+ static inline bool mtk_wed_device_active(struct mtk_wed_device *dev)
+ {
+@@ -259,6 +263,7 @@ static inline bool mtk_wed_device_active(struct mtk_wed_device *dev)
+ #define mtk_wed_device_update_msg(_dev, _id, _msg, _len) -ENODEV
+ #define mtk_wed_device_stop(_dev) do {} while (0)
  #define mtk_wed_device_dma_reset(_dev) do {} while (0)
 +#define mtk_wed_device_setup_tc(_dev, _ndev, _type, _data) do {} while (0)
- #define mtk_wed_device_ppe_check(_dev, _hash)  do {} while (0)
  #endif
  
+ #endif
 -- 
 2.18.0
 
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/flow_patch/999-3017-flow-offload-add-mtkhnat-dscp.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/flow_patch/999-3017-flow-offload-add-mtkhnat-dscp.patch
index 478a7a9..070bb7c 100644
--- a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/flow_patch/999-3017-flow-offload-add-mtkhnat-dscp.patch
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/flow_patch/999-3017-flow-offload-add-mtkhnat-dscp.patch
@@ -1,7 +1,7 @@
-From 3e4d44d8da90b9ba20abc5cec255d92b67e3fb00 Mon Sep 17 00:00:00 2001
+From 8c918e858df4b7cb12ea185acf23e83bae883cd2 Mon Sep 17 00:00:00 2001
 From: Bc-bocun Chen <bc-bocun.chen@mediatek.com>
 Date: Mon, 18 Sep 2023 11:17:24 +0800
-Subject: [PATCH 18/22] flow-offload-add-mtkhnat-dscp
+Subject: [PATCH 17/24] flow-offload-add-mtkhnat-dscp
 
 ---
  drivers/net/ethernet/mediatek/mtk_ppe.c       | 11 +++++++
@@ -13,10 +13,10 @@
  6 files changed, 64 insertions(+), 1 deletion(-)
 
 diff --git a/drivers/net/ethernet/mediatek/mtk_ppe.c b/drivers/net/ethernet/mediatek/mtk_ppe.c
-index 446acca..384e811 100755
+index 184e29d..0e9c0bd 100755
 --- a/drivers/net/ethernet/mediatek/mtk_ppe.c
 +++ b/drivers/net/ethernet/mediatek/mtk_ppe.c
-@@ -435,6 +435,17 @@ int mtk_foe_entry_set_qid(struct mtk_foe_entry *entry, int qid)
+@@ -446,6 +446,17 @@ int mtk_foe_entry_set_qid(struct mtk_foe_entry *entry, int qid)
  
  	return 0;
  }
@@ -84,10 +84,10 @@
  
  	err = mtk_flow_set_output_device(eth, &foe, odev, f->flow->ct, data.eth.h_dest,
 diff --git a/include/net/netfilter/nf_flow_table.h b/include/net/netfilter/nf_flow_table.h
-index feac793..97a277d 100644
+index 7374cb2..d5dd3fe 100644
 --- a/include/net/netfilter/nf_flow_table.h
 +++ b/include/net/netfilter/nf_flow_table.h
-@@ -36,6 +36,7 @@ struct nf_flow_key {
+@@ -38,6 +38,7 @@ struct nf_flow_key {
  	};
  	struct flow_dissector_key_tcp			tcp;
  	struct flow_dissector_key_ports			tp;
@@ -95,7 +95,7 @@
  } __aligned(BITS_PER_LONG / 8); /* Ensure that we can do comparisons as longs. */
  
  struct nf_flow_match {
-@@ -145,6 +146,7 @@ struct flow_offload_tuple {
+@@ -147,6 +148,7 @@ struct flow_offload_tuple {
  			u8		h_dest[ETH_ALEN];
  		} out;
  	};
@@ -132,7 +132,7 @@
  }
  
 diff --git a/net/netfilter/xt_FLOWOFFLOAD.c b/net/netfilter/xt_FLOWOFFLOAD.c
-index 1defb15..d4aecab 100644
+index aae37f5..5364a32 100644
 --- a/net/netfilter/xt_FLOWOFFLOAD.c
 +++ b/net/netfilter/xt_FLOWOFFLOAD.c
 @@ -49,6 +49,35 @@ static DEFINE_SPINLOCK(hooks_lock);
@@ -171,7 +171,7 @@
  static unsigned int
  xt_flowoffload_net_hook(void *priv, struct sk_buff *skb,
  			const struct nf_hook_state *state)
-@@ -617,6 +646,9 @@ flowoffload_tg(struct sk_buff *skb, const struct xt_action_param *par)
+@@ -623,6 +652,9 @@ flowoffload_tg(struct sk_buff *skb, const struct xt_action_param *par)
  	if (flow_offload_route_init(flow, &route) < 0)
  		goto err_flow_add;
  
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/flow_patch/999-3018-flow-offload-add-mtkhnat-netlink.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/flow_patch/999-3018-flow-offload-add-mtkhnat-netlink.patch
index 3bb7e7a..ff6f58f 100644
--- a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/flow_patch/999-3018-flow-offload-add-mtkhnat-netlink.patch
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/flow_patch/999-3018-flow-offload-add-mtkhnat-netlink.patch
@@ -1,7 +1,7 @@
-From 6bda18f107acbf04f01c18ad5964be6f7404d3cf Mon Sep 17 00:00:00 2001
+From 122cb2a2ae7ececd20412083b5bb9bfd6f9c8d26 Mon Sep 17 00:00:00 2001
 From: Bc-bocun Chen <bc-bocun.chen@mediatek.com>
 Date: Mon, 18 Sep 2023 13:14:08 +0800
-Subject: [PATCH 19/22] flow-offload-add-mtkhnat-netlink
+Subject: [PATCH 18/24] flow-offload-add-mtkhnat-netlink
 
 ---
  include/net/netfilter/nf_flow_table.h    |   1 +
@@ -14,10 +14,10 @@
  create mode 100644 net/netfilter/nf_flow_table_netlink.c
 
 diff --git a/include/net/netfilter/nf_flow_table.h b/include/net/netfilter/nf_flow_table.h
-index 97a277d..3490d90 100644
+index d5dd3fe..f2bce73 100644
 --- a/include/net/netfilter/nf_flow_table.h
 +++ b/include/net/netfilter/nf_flow_table.h
-@@ -277,6 +277,7 @@ int nf_flow_table_init(struct nf_flowtable *flow_table);
+@@ -279,6 +279,7 @@ int nf_flow_table_init(struct nf_flowtable *flow_table);
  void nf_flow_table_free(struct nf_flowtable *flow_table);
  
  void flow_offload_teardown(struct flow_offload *flow);
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/flow_patch/999-3019-mtk-wed-add-wed3-support.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/flow_patch/999-3019-mtk-wed-add-wed3-support.patch
new file mode 100644
index 0000000..9307157
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/flow_patch/999-3019-mtk-wed-add-wed3-support.patch
@@ -0,0 +1,3873 @@
+From da90def8adfa6139e8710c282a41024cfc4b23b3 Mon Sep 17 00:00:00 2001
+From: Sujuan Chen <sujuan.chen@mediatek.com>
+Date: Mon, 18 Sep 2023 13:21:15 +0800
+Subject: [PATCH] mtk:wed:add wed3 support
+
+---
+ arch/arm64/boot/dts/mediatek/mt7988.dtsi      |  152 +-
+ .../dts/mediatek/mt7988a-dsa-10g-spim-nor.dts |   16 +-
+ .../dts/mediatek/mt7988d-dsa-10g-spim-nor.dts |   16 +-
+ drivers/net/ethernet/mediatek/mtk_ppe.c       |   17 +-
+ drivers/net/ethernet/mediatek/mtk_ppe.h       |    2 +-
+ .../net/ethernet/mediatek/mtk_ppe_offload.c   |    9 +-
+ drivers/net/ethernet/mediatek/mtk_wed.c       | 1228 +++++++++++++----
+ drivers/net/ethernet/mediatek/mtk_wed.h       |   73 +-
+ .../net/ethernet/mediatek/mtk_wed_debugfs.c   |  584 +++++++-
+ drivers/net/ethernet/mediatek/mtk_wed_mcu.c   |   40 +-
+ drivers/net/ethernet/mediatek/mtk_wed_mcu.h   |    7 +-
+ drivers/net/ethernet/mediatek/mtk_wed_regs.h  |  353 ++++-
+ include/linux/netdevice.h                     |    7 +
+ include/linux/soc/mediatek/mtk_wed.h          |   77 +-
+ 14 files changed, 2161 insertions(+), 420 deletions(-)
+ mode change 100755 => 100644 drivers/net/ethernet/mediatek/mtk_ppe.c
+
+diff --git a/arch/arm64/boot/dts/mediatek/mt7988.dtsi b/arch/arm64/boot/dts/mediatek/mt7988.dtsi
+index 7e96640..3368240 100644
+--- a/arch/arm64/boot/dts/mediatek/mt7988.dtsi
++++ b/arch/arm64/boot/dts/mediatek/mt7988.dtsi
+@@ -193,44 +193,49 @@
+ 		status = "disabled";
+ 	};
+ 
+-	wed: wed@15010000 {
+-		compatible = "mediatek,wed";
+-		wed_num = <3>;
+-		/* add this property for wed get the pci slot number. */
+-		pci_slot_map = <0>, <1>, <2>;
+-		reg = <0 0x15010000 0 0x2000>,
+-		      <0 0x15012000 0 0x2000>,
+-		      <0 0x15014000 0 0x2000>;
++	wed0: wed@15010000 {
++		compatible = "mediatek,mt7988-wed",
++			     "syscon";
++		reg = <0 0x15010000 0 0x2000>;
+ 		interrupt-parent = <&gic>;
+-		interrupts = <GIC_SPI 205 IRQ_TYPE_LEVEL_HIGH>,
+-			     <GIC_SPI 206 IRQ_TYPE_LEVEL_HIGH>,
+-			     <GIC_SPI 270 IRQ_TYPE_LEVEL_HIGH>;
+-	};
+-
+-	wed2: wed2@15012000 {
+-		compatible = "mediatek,wed2";
+-		wed_num = <3>;
+-		/* add this property for wed get the pci slot number. */
+-		reg = <0 0x15010000 0 0x2000>,
+-		      <0 0x15012000 0 0x2000>,
+-		      <0 0x15014000 0 0x2000>;
++		interrupts = <GIC_SPI 205 IRQ_TYPE_LEVEL_HIGH>;
++		mediatek,wed_pcie = <&wed_pcie>;
++		mediatek,ap2woccif = <&ap2woccif0>;
++		mediatek,wocpu_ilm = <&wocpu0_ilm>;
++		mediatek,wocpu_dlm = <&wocpu0_dlm>;
++		mediatek,wocpu_boot = <&cpu0_boot>;
++		mediatek,wocpu_emi = <&wocpu0_emi>;
++		mediatek,wocpu_data = <&wocpu_data>;
++	};
++
++	wed1: wed@15012000 {
++		compatible = "mediatek,mt7988-wed",
++                             "syscon";
++		reg = <0 0x15012000 0 0x2000>;
+ 		interrupt-parent = <&gic>;
+-		interrupts = <GIC_SPI 205 IRQ_TYPE_LEVEL_HIGH>,
+-			     <GIC_SPI 206 IRQ_TYPE_LEVEL_HIGH>,
+-			     <GIC_SPI 270 IRQ_TYPE_LEVEL_HIGH>;
+-	};
+-
+-	wed3: wed3@15014000 {
+-		compatible = "mediatek,wed3";
+-		wed_num = <3>;
+-		/* add this property for wed get the pci slot number. */
+-		reg = <0 0x15010000 0 0x2000>,
+-		      <0 0x15012000 0 0x2000>,
+-		      <0 0x15014000 0 0x2000>;
++		interrupts = <GIC_SPI 206 IRQ_TYPE_LEVEL_HIGH>;
++		mediatek,wed_pcie = <&wed_pcie>;
++		mediatek,ap2woccif = <&ap2woccif1>;
++		mediatek,wocpu_ilm = <&wocpu1_ilm>;
++		mediatek,wocpu_dlm = <&wocpu1_dlm>;
++		mediatek,wocpu_boot = <&cpu1_boot>;
++		mediatek,wocpu_emi = <&wocpu1_emi>;
++		mediatek,wocpu_data = <&wocpu_data>;
++	};
++
++	wed2: wed@15014000 {
++		compatible = "mediatek,mt7988-wed",
++                             "syscon";
++		reg = <0 0x15014000 0 0x2000>;
+ 		interrupt-parent = <&gic>;
+-		interrupts = <GIC_SPI 205 IRQ_TYPE_LEVEL_HIGH>,
+-			     <GIC_SPI 206 IRQ_TYPE_LEVEL_HIGH>,
+-			     <GIC_SPI 270 IRQ_TYPE_LEVEL_HIGH>;
++		interrupts = <GIC_SPI 207 IRQ_TYPE_LEVEL_HIGH>;
++		mediatek,wed_pcie = <&wed_pcie>;
++		mediatek,ap2woccif = <&ap2woccif2>;
++		mediatek,wocpu_ilm = <&wocpu2_ilm>;
++		mediatek,wocpu_dlm = <&wocpu2_dlm>;
++		mediatek,wocpu_boot = <&cpu2_boot>;
++		mediatek,wocpu_emi = <&wocpu2_emi>;
++		mediatek,wocpu_data = <&wocpu_data>;
+ 	};
+ 
+ 	wdma: wdma@15104800 {
+@@ -240,15 +245,25 @@
+ 		      <0 0x15105000 0 0x400>;
+ 	};
+ 
+-	ap2woccif: ap2woccif@151A5000 {
+-		compatible = "mediatek,ap2woccif";
+-		reg = <0 0x151A5000 0 0x1000>,
+-		      <0 0x152A5000 0 0x1000>,
+-		      <0 0x153A5000 0 0x1000>;
++	ap2woccif0: ap2woccif@151A5000 {
++		compatible = "mediatek,ap2woccif", "syscon";
++		reg = <0 0x151A5000 0 0x1000>;
++		interrupt-parent = <&gic>;
++		interrupts = <GIC_SPI 211 IRQ_TYPE_LEVEL_HIGH>;
++	};
++
++	ap2woccif1: ap2woccif@152A5000 {
++		compatible = "mediatek,ap2woccif", "syscon";
++		reg = <0 0x152A5000 0 0x1000>;
+ 		interrupt-parent = <&gic>;
+-		interrupts = <GIC_SPI 211 IRQ_TYPE_LEVEL_HIGH>,
+-			     <GIC_SPI 212 IRQ_TYPE_LEVEL_HIGH>,
+-			     <GIC_SPI 272 IRQ_TYPE_LEVEL_HIGH>;
++		interrupts = <GIC_SPI 212 IRQ_TYPE_LEVEL_HIGH>;
++	};
++
++	ap2woccif2: ap2woccif@153A5000 {
++		compatible = "mediatek,ap2woccif", "syscon";
++		reg = <0 0x153A5000 0 0x1000>;
++		interrupt-parent = <&gic>;
++		interrupts = <GIC_SPI 272 IRQ_TYPE_LEVEL_HIGH>;
+ 	};
+ 
+ 	wocpu0_ilm: wocpu0_ilm@151E0000 {
+@@ -256,31 +271,53 @@
+ 		reg = <0 0x151E0000 0 0x8000>;
+ 	};
+ 
+-	wocpu1_ilm: wocpu1_ilm@152E0000 {
+-		compatible = "mediatek,wocpu1_ilm";
++	wocpu1_ilm: wocpu_ilm@152E0000 {
++		compatible = "mediatek,wocpu_ilm";
+ 		reg = <0 0x152E0000 0 0x8000>;
+ 	};
+ 
+-	wocpu2_ilm: wocpu2_ilm@153E0000 {
+-		compatible = "mediatek,wocpu2_ilm";
+-		reg = <0 0x153E0000 0 0x8000>;
++	wocpu2_ilm: wocpu_ilm@153E0000 {
++                compatible = "mediatek,wocpu_ilm";
++                reg = <0 0x153E0000 0 0x8000>;
++    };
++
++	wocpu0_dlm: wocpu_dlm@151E8000 {
++		compatible = "mediatek,wocpu_dlm";
++		reg = <0 0x151E8000 0 0x2000>;
++
++		resets = <&ethsysrst 0>;
++		reset-names = "wocpu_rst";
++	};
++
++	wocpu1_dlm: wocpu_dlm@0x152E8000 {
++		compatible = "mediatek,wocpu_dlm";
++		reg = <0 0x152E8000 0 0x2000>;
++
++		resets = <&ethsysrst 0>;
++		reset-names = "wocpu_rst";
+ 	};
+ 
+-	wocpu_dlm: wocpu_dlm@151E8000 {
++	wocpu2_dlm: wocpu_dlm@0x153E8000 {
+ 		compatible = "mediatek,wocpu_dlm";
+-		reg = <0 0x151E8000 0 0x2000>,
+-		      <0 0x152E8000 0 0x2000>,
+-		      <0 0x153E8000 0 0x2000>;
++		reg = <0 0x153E8000 0 0x2000>;
+ 
+ 		resets = <&ethsysrst 0>;
+ 		reset-names = "wocpu_rst";
+ 	};
+ 
+-	cpu_boot: wocpu_boot@15194000 {
+-		compatible = "mediatek,wocpu_boot";
+-		reg = <0 0x15194000 0 0x1000>,
+-		      <0 0x15294000 0 0x1000>,
+-		      <0 0x15394000 0 0x1000>;
++	cpu0_boot: wocpu_boot@15194000 {
++		compatible = "mediatek,wocpu0_boot";
++		reg = <0 0x15194000 0 0x1000>;
++	};
++
++	cpu1_boot: wocpu_boot@15294000 {
++		compatible = "mediatek,wocpu1_boot";
++		reg = <0 0x15294000 0 0x1000>;
++	};
++
++	cpu2_boot: wocpu_boot@15394000 {
++		compatible = "mediatek,wocpu2_boot";
++		reg = <0 0x15394000 0 0x1000>;
+ 	};
+ 
+ 	reserved-memory {
+@@ -901,6 +938,7 @@
+ 					 <&topckgen CK_TOP_CB_NET2_D2>;
+ 		mediatek,ethsys = <&ethsys>;
+ 		mediatek,sgmiisys = <&sgmiisys0>, <&sgmiisys1>;
++		mediatek,wed = <&wed0>, <&wed1>, <&wed2>;
+ 		mediatek,usxgmiisys = <&usxgmiisys0>, <&usxgmiisys1>;
+ 		mediatek,xfi_pextp = <&xfi_pextp0>, <&xfi_pextp1>;
+ 		mediatek,xfi_pll = <&xfi_pll>;
+diff --git a/arch/arm64/boot/dts/mediatek/mt7988a-dsa-10g-spim-nor.dts b/arch/arm64/boot/dts/mediatek/mt7988a-dsa-10g-spim-nor.dts
+index a22af29..9169188 100644
+--- a/arch/arm64/boot/dts/mediatek/mt7988a-dsa-10g-spim-nor.dts
++++ b/arch/arm64/boot/dts/mediatek/mt7988a-dsa-10g-spim-nor.dts
+@@ -372,9 +372,23 @@
+ 	status = "okay";
+ };
+ 
+-&wed {
++&wed0 {
+ 	dy_txbm_enable = "true";
+ 	dy_txbm_budge = <8>;
+ 	txbm_init_sz = <10>;
+ 	status = "okay";
+ };
++
++&wed1 {
++	dy_txbm_enable = "true";
++	dy_txbm_budge = <8>;
++	txbm_init_sz = <10>;
++	status = "okay";
++};
++
++&wed2 {
++	dy_txbm_enable = "true";
++	dy_txbm_budge = <8>;
++	txbm_init_sz = <10>;
++	status = "okay";
++};
+\ No newline at end of file
+diff --git a/arch/arm64/boot/dts/mediatek/mt7988d-dsa-10g-spim-nor.dts b/arch/arm64/boot/dts/mediatek/mt7988d-dsa-10g-spim-nor.dts
+index effcfd8..30e4846 100644
+--- a/arch/arm64/boot/dts/mediatek/mt7988d-dsa-10g-spim-nor.dts
++++ b/arch/arm64/boot/dts/mediatek/mt7988d-dsa-10g-spim-nor.dts
+@@ -382,9 +382,23 @@
+ 	status = "okay";
+ };
+ 
+-&wed {
++&wed0 {
+ 	dy_txbm_enable = "true";
+ 	dy_txbm_budge = <8>;
+ 	txbm_init_sz = <10>;
+ 	status = "okay";
+ };
++
++&wed1 {
++	dy_txbm_enable = "true";
++	dy_txbm_budge = <8>;
++	txbm_init_sz = <10>;
++	status = "okay";
++};
++
++&wed2 {
++	dy_txbm_enable = "true";
++	dy_txbm_budge = <8>;
++	txbm_init_sz = <10>;
++	status = "okay";
++};
+\ No newline at end of file
+diff --git a/drivers/net/ethernet/mediatek/mtk_ppe.c b/drivers/net/ethernet/mediatek/mtk_ppe.c
+old mode 100755
+new mode 100644
+index 0e9c0bd..ae0acd5
+--- a/drivers/net/ethernet/mediatek/mtk_ppe.c
++++ b/drivers/net/ethernet/mediatek/mtk_ppe.c
+@@ -9,6 +9,7 @@
+ #include <linux/if_ether.h>
+ #include <linux/if_vlan.h>
+ #include <net/dsa.h>
++#include <net/route.h>
+ #include "mtk_eth_soc.h"
+ #include "mtk_ppe.h"
+ #include "mtk_ppe_regs.h"
+@@ -407,7 +408,7 @@ int mtk_foe_entry_set_pppoe(struct mtk_foe_entry *entry, int sid)
+ }
+ 
+ int mtk_foe_entry_set_wdma(struct mtk_foe_entry *entry, int wdma_idx, int txq,
+-			   int bss, int wcid)
++			   int bss, int wcid, bool amsdu_en)
+ {
+ 	struct mtk_foe_mac_info *l2 = mtk_foe_entry_l2(entry);
+ 	u32 *ib2 = mtk_foe_entry_ib2(entry);
+@@ -419,6 +420,9 @@ int mtk_foe_entry_set_wdma(struct mtk_foe_entry *entry, int wdma_idx, int txq,
+ 
+ 	l2->winfo = FIELD_PREP(MTK_FOE_WINFO_WCID, wcid) |
+ 		    FIELD_PREP(MTK_FOE_WINFO_BSS, bss);
++#if defined(CONFIG_MEDIATEK_NETSYS_V3)
++	l2->winfo_pao = FIELD_PREP(MTK_FOE_WINFO_PAO_AMSDU_EN, amsdu_en);
++#endif
+ #else
+ 	if (wdma_idx)
+ 		*ib2 |= MTK_FOE_IB2_WDMA_DEVIDX;
+@@ -454,6 +458,17 @@ int mtk_foe_entry_set_dscp(struct mtk_foe_entry *entry, int dscp)
+ 	*ib2 &= ~MTK_FOE_IB2_DSCP;
+ 	*ib2 |= FIELD_PREP(MTK_FOE_IB2_DSCP, dscp);
+ 
++#if defined(CONFIG_MEDIATEK_NETSYS_V3)
++	struct mtk_foe_mac_info *l2 = mtk_foe_entry_l2(entry);
++
++	if (*ib2 & MTK_FOE_IB2_WDMA_WINFO &&
++	    l2->winfo_pao & MTK_FOE_WINFO_PAO_AMSDU_EN) {
++		u8 tid = (dscp >> 5) & 0xf;
++
++		l2->winfo_pao |= FIELD_PREP(MTK_FOE_WINFO_PAO_TID, tid);
++	}
++#endif
++
+ 	return 0;
+ }
+ 
+diff --git a/drivers/net/ethernet/mediatek/mtk_ppe.h b/drivers/net/ethernet/mediatek/mtk_ppe.h
+index 2a8b6ef..66c7f10 100644
+--- a/drivers/net/ethernet/mediatek/mtk_ppe.h
++++ b/drivers/net/ethernet/mediatek/mtk_ppe.h
+@@ -428,7 +428,7 @@ int mtk_foe_entry_set_dsa(struct mtk_foe_entry *entry, int port);
+ int mtk_foe_entry_set_vlan(struct mtk_foe_entry *entry, int vid);
+ int mtk_foe_entry_set_pppoe(struct mtk_foe_entry *entry, int sid);
+ int mtk_foe_entry_set_wdma(struct mtk_foe_entry *entry, int wdma_idx, int txq,
+-			   int bss, int wcid);
++			   int bss, int wcid, bool amsdu_en);
+ int mtk_foe_entry_set_qid(struct mtk_foe_entry *entry, int qid);
+ int mtk_foe_entry_set_dscp(struct mtk_foe_entry *entry, int dscp);
+ bool mtk_foe_entry_match(struct mtk_foe_entry *entry, struct mtk_foe_entry *data);
+diff --git a/drivers/net/ethernet/mediatek/mtk_ppe_offload.c b/drivers/net/ethernet/mediatek/mtk_ppe_offload.c
+index 95174b7..2d432f2 100644
+--- a/drivers/net/ethernet/mediatek/mtk_ppe_offload.c
++++ b/drivers/net/ethernet/mediatek/mtk_ppe_offload.c
+@@ -112,6 +112,7 @@ mtk_flow_get_wdma_info(struct net_device *dev, const u8 *addr, struct mtk_wdma_i
+ 	info->queue = path.mtk_wdma.queue;
+ 	info->bss = path.mtk_wdma.bss;
+ 	info->wcid = path.mtk_wdma.wcid;
++	info->amsdu = path.mtk_wdma.amsdu;
+ 
+ 	return 0;
+ }
+@@ -193,13 +194,15 @@ mtk_flow_set_output_device(struct mtk_eth *eth, struct mtk_foe_entry *foe,
+ 
+ 	if (mtk_flow_get_wdma_info(dev, dest_mac, &info) == 0) {
+ 		mtk_foe_entry_set_wdma(foe, info.wdma_idx, info.queue, info.bss,
+-				       info.wcid);
++				       info.wcid, info.amsdu);
+ 		pse_port = PSE_PPE0_PORT;
+ #if defined(CONFIG_MEDIATEK_NETSYS_V2) || defined(CONFIG_MEDIATEK_NETSYS_V3)
+ 		if (info.wdma_idx == 0)
+ 			pse_port = PSE_WDMA0_PORT;
+ 		else if (info.wdma_idx == 1)
+ 			pse_port = PSE_WDMA1_PORT;
++		else if (info.wdma_idx == 2)
++			pse_port = PSE_WDMA2_PORT;
+ 		else
+ 			return -EOPNOTSUPP;
+ #endif
+@@ -481,8 +484,6 @@ mtk_flow_offload_replace(struct mtk_eth *eth, struct flow_cls_offload *f)
+ 	if (data.pppoe.num == 1)
+ 		mtk_foe_entry_set_pppoe(&foe, data.pppoe.sid);
+ 
+-	mtk_foe_entry_set_dscp(&foe, dscp);
+-
+ 	mtk_foe_entry_set_sp(eth->ppe[ppe_index], &foe);
+ 
+ 	err = mtk_flow_set_output_device(eth, &foe, odev, f->flow->ct, data.eth.h_dest,
+@@ -490,6 +491,8 @@ mtk_flow_offload_replace(struct mtk_eth *eth, struct flow_cls_offload *f)
+ 	if (err)
+ 		return err;
+ 
++	mtk_foe_entry_set_dscp(&foe, dscp);
++
+ 	if (wed_index >= 0 && (err = mtk_wed_flow_add(wed_index)) < 0)
+ 		return err;
+ 
+diff --git a/drivers/net/ethernet/mediatek/mtk_wed.c b/drivers/net/ethernet/mediatek/mtk_wed.c
+index a7d2166..92df014 100644
+--- a/drivers/net/ethernet/mediatek/mtk_wed.c
++++ b/drivers/net/ethernet/mediatek/mtk_wed.c
+@@ -23,9 +23,45 @@
+ #include "mtk_wed_mcu.h"
+ #include "mtk_wed_wo.h"
+ 
+-static struct mtk_wed_hw *hw_list[2];
++#define MTK_WED_AMSDU_BUF_SIZE		(PAGE_SIZE << 4)
++#define MTK_WED_AMSDU_NPAGES		32
++
++static struct mtk_wed_hw *hw_list[3];
+ static DEFINE_MUTEX(hw_lock);
+ 
++static const struct mtk_wed_soc_data mt7622_data = {
++	.regmap = {
++		.tx_bm_tkid		= 0x088,
++		.wpdma_rx_ring0		= 0x770,
++		.reset_idx_tx_mask	= GENMASK(3, 0),
++		.reset_idx_rx_mask	= GENMASK(17, 16),
++	},
++	.tx_ring_desc_size = sizeof(struct mtk_wdma_desc),
++	.wdma_desc_size = sizeof(struct mtk_wdma_desc),
++};
++
++static const struct mtk_wed_soc_data mt7986_data = {
++	.regmap = {
++		.tx_bm_tkid		= 0x0c8,
++		.wpdma_rx_ring0		= 0x770,
++		.reset_idx_tx_mask	= GENMASK(1, 0),
++		.reset_idx_rx_mask	= GENMASK(7, 6),
++	},
++	.tx_ring_desc_size = sizeof(struct mtk_wdma_desc),
++	.wdma_desc_size = 2 * sizeof(struct mtk_wdma_desc),
++};
++
++static const struct mtk_wed_soc_data mt7988_data = {
++	.regmap = {
++		.tx_bm_tkid		= 0x0c8,
++		.wpdma_rx_ring0		= 0x7d0,
++		.reset_idx_tx_mask	= GENMASK(1, 0),
++		.reset_idx_rx_mask	= GENMASK(7, 6),
++	},
++	.tx_ring_desc_size = sizeof(struct mtk_wed_bm_desc),
++	.wdma_desc_size = 2 * sizeof(struct mtk_wdma_desc),
++};
++
+ static void
+ wed_m32(struct mtk_wed_device *dev, u32 reg, u32 mask, u32 val)
+ {
+@@ -74,6 +110,26 @@ mtk_wdma_read_reset(struct mtk_wed_device *dev)
+ 	return wdma_r32(dev, MTK_WDMA_GLO_CFG);
+ }
+ 
++static u32
++mtk_wed_check_busy(struct mtk_wed_device *dev, u32 reg, u32 mask)
++{
++	if (wed_r32(dev, reg) & mask)
++		return true;
++
++	return false;
++}
++
++static int
++mtk_wed_poll_busy(struct mtk_wed_device *dev, u32 reg, u32 mask)
++{
++	int sleep = 1000;
++	int timeout = 100 * sleep;
++	u32 val;
++
++	return read_poll_timeout(mtk_wed_check_busy, val, !val, sleep,
++				 timeout, false, dev, reg, mask);
++}
++
+ static int
+ mtk_wdma_rx_reset(struct mtk_wed_device *dev)
+ {
+@@ -238,71 +294,171 @@ void mtk_wed_fe_reset_complete(void)
+ static struct mtk_wed_hw *
+ mtk_wed_assign(struct mtk_wed_device *dev)
+ {
+-	struct mtk_wed_hw *hw;
+ 	int i;
+ 
+-	if (dev->wlan.bus_type == MTK_WED_BUS_PCIE) {
+-		hw = hw_list[pci_domain_nr(dev->wlan.pci_dev->bus)];
+-		if (!hw)
+-			return NULL;
++	for (i = 0; i < ARRAY_SIZE(hw_list); i++) {
++		struct mtk_wed_hw *hw = hw_list[i];
+ 
+-		if (!hw->wed_dev)
+-			goto out;
++		if (!hw || hw->wed_dev)
++			continue;
+ 
+-		if (hw->version == 1)
+-			return NULL;
++		hw->wed_dev = dev;
++		hw->pci_base = MTK_WED_PCIE_BASE;
+ 
+-		/* MT7986 WED devices do not have any pcie slot restrictions */
+-	}
+-	/* MT7986 PCIE or AXI */
+-	for (i = 0; i < ARRAY_SIZE(hw_list); i++) {
+-		hw = hw_list[i];
+-		if (hw && !hw->wed_dev)
+-			goto out;
++		return hw;
+ 	}
+ 
+ 	return NULL;
++}
+ 
+-out:
+-	hw->wed_dev = dev;
+-	return hw;
++static int
++mtk_wed_amsdu_buffer_alloc(struct mtk_wed_device *dev)
++{
++	struct mtk_wed_hw *hw = dev->hw;
++	struct mtk_wed_amsdu *wed_amsdu;
++	int i;
++
++	if (!mtk_wed_is_v3_or_greater(hw))
++		return 0;
++
++	wed_amsdu = devm_kcalloc(hw->dev, MTK_WED_AMSDU_NPAGES,
++				 sizeof(*wed_amsdu), GFP_KERNEL);
++	if (!wed_amsdu)
++		return -ENOMEM;
++
++	for (i = 0; i < MTK_WED_AMSDU_NPAGES; i++) {
++		void *ptr;
++
++		/* each segment is 64K */
++		ptr = (void *)__get_free_pages(GFP_KERNEL | __GFP_NOWARN |
++					       __GFP_ZERO | __GFP_COMP |
++					       GFP_DMA32,
++					       get_order(MTK_WED_AMSDU_BUF_SIZE));
++		if (!ptr)
++			goto error;
++
++		wed_amsdu[i].txd = ptr;
++		wed_amsdu[i].txd_phy = dma_map_single(hw->dev, ptr,
++						      MTK_WED_AMSDU_BUF_SIZE,
++						      DMA_TO_DEVICE);
++		if (dma_mapping_error(hw->dev, wed_amsdu[i].txd_phy))
++			goto error;
++	}
++	dev->hw->wed_amsdu = wed_amsdu;
++
++	return 0;
++
++error:
++	for (i--; i >= 0; i--)
++		dma_unmap_single(hw->dev, wed_amsdu[i].txd_phy,
++				 MTK_WED_AMSDU_BUF_SIZE, DMA_TO_DEVICE);
++	return -ENOMEM;
++}
++
++
++static void
++mtk_wed_amsdu_free_buffer(struct mtk_wed_device *dev)
++{
++	struct mtk_wed_amsdu *wed_amsdu = dev->hw->wed_amsdu;
++	int i;
++
++	if (!wed_amsdu)
++		return;
++
++	for (i = 0; i < MTK_WED_AMSDU_NPAGES; i++) {
++		dma_unmap_single(dev->hw->dev, wed_amsdu[i].txd_phy,
++				 MTK_WED_AMSDU_BUF_SIZE, DMA_TO_DEVICE);
++		free_pages((unsigned long)wed_amsdu[i].txd,
++			   get_order(MTK_WED_AMSDU_BUF_SIZE));
++	}
++}
++
++static int
++mtk_wed_amsdu_init(struct mtk_wed_device *dev)
++{
++	struct mtk_wed_amsdu *wed_amsdu = dev->hw->wed_amsdu;
++	int i, ret;
++
++	if (!wed_amsdu)
++		return 0;
++
++	for (i = 0; i < MTK_WED_AMSDU_NPAGES; i++)
++		wed_w32(dev, MTK_WED_AMSDU_HIFTXD_BASE_L(i),
++			wed_amsdu[i].txd_phy);
++
++	/* init all sta parameter */
++	wed_w32(dev, MTK_WED_AMSDU_STA_INFO_INIT, MTK_WED_AMSDU_STA_RMVL |
++		MTK_WED_AMSDU_STA_WTBL_HDRT_MODE |
++		FIELD_PREP(MTK_WED_AMSDU_STA_MAX_AMSDU_LEN,
++			   dev->wlan.amsdu_max_len >> 8) |
++		FIELD_PREP(MTK_WED_AMSDU_STA_MAX_AMSDU_NUM,
++			   dev->wlan.amsdu_max_subframes));
++
++	wed_w32(dev, MTK_WED_AMSDU_STA_INFO, MTK_WED_AMSDU_STA_INFO_DO_INIT);
++
++	ret = mtk_wed_poll_busy(dev, MTK_WED_AMSDU_STA_INFO,
++				MTK_WED_AMSDU_STA_INFO_DO_INIT);
++	if (ret) {
++		dev_err(dev->hw->dev, "amsdu initialization failed\n");
++		return ret;
++	}
++
++	/* init partial amsdu offload txd src */
++	wed_set(dev, MTK_WED_AMSDU_HIFTXD_CFG,
++		FIELD_PREP(MTK_WED_AMSDU_HIFTXD_SRC, dev->hw->index));
++
++	/* init qmem */
++	wed_set(dev, MTK_WED_AMSDU_PSE, MTK_WED_AMSDU_PSE_RESET);
++	ret = mtk_wed_poll_busy(dev, MTK_WED_MON_AMSDU_QMEM_STS1, BIT(29));
++	if (ret) {
++		pr_info("%s: amsdu qmem initialization failed\n", __func__);
++		return ret;
++	}
++
++	/* eagle E1 PCIE1 tx ring 22 flow control issue */
++	if (dev->wlan.id == 0x7991)
++		wed_clr(dev, MTK_WED_AMSDU_FIFO, MTK_WED_AMSDU_IS_PRIOR0_RING);
++
++	wed_set(dev, MTK_WED_CTRL, MTK_WED_CTRL_TX_AMSDU_EN);
++
++	return 0;
+ }
+ 
+ static int
+ mtk_wed_tx_buffer_alloc(struct mtk_wed_device *dev)
+ {
+-	struct mtk_wdma_desc *desc;
+-	dma_addr_t desc_phys;
+-	void **page_list;
++	u32 desc_size = dev->hw->soc->tx_ring_desc_size;
++	int i, page_idx = 0, n_pages, ring_size;
+ 	int token = dev->wlan.token_start;
+-	int ring_size, n_pages, page_idx;
+-	int i;
+-
++	struct mtk_wed_buf *page_list;
++	dma_addr_t desc_phys;
++	void *desc_ptr;
+ 
+-	if (dev->hw->version == 1)
++	if (!mtk_wed_is_v3_or_greater(dev->hw)) {
+ 		ring_size = dev->wlan.nbuf & ~(MTK_WED_BUF_PER_PAGE - 1);
+-	else
+-		ring_size = MTK_WED_VLD_GROUP_SIZE * MTK_WED_PER_GROUP_PKT +
+-			    MTK_WED_WDMA_RING_SIZE * 2;
+-
+-	n_pages = ring_size / MTK_WED_BUF_PER_PAGE;
++		dev->tx_buf_ring.size = ring_size;
++	} else {
++		dev->tx_buf_ring.size = MTK_WED_TX_BM_DMA_SIZE;
++		ring_size = MTK_WED_TX_BM_PKT_CNT;
++	}
++	n_pages = dev->tx_buf_ring.size / MTK_WED_BUF_PER_PAGE;
+ 
+ 	page_list = kcalloc(n_pages, sizeof(*page_list), GFP_KERNEL);
+ 	if (!page_list)
+ 		return -ENOMEM;
+ 
+-	dev->tx_buf_ring.size = ring_size;
+ 	dev->tx_buf_ring.pages = page_list;
+ 
+-	desc = dma_alloc_coherent(dev->hw->dev, ring_size * sizeof(*desc),
+-				  &desc_phys, GFP_KERNEL);
+-	if (!desc)
++	desc_ptr = dma_alloc_coherent(dev->hw->dev,
++				      dev->tx_buf_ring.size * desc_size,
++				      &desc_phys, GFP_KERNEL);
++	if (!desc_ptr)
+ 		return -ENOMEM;
+ 
+-	dev->tx_buf_ring.desc = desc;
++	dev->tx_buf_ring.desc = desc_ptr;
+ 	dev->tx_buf_ring.desc_phys = desc_phys;
+ 
+-	for (i = 0, page_idx = 0; i < ring_size; i += MTK_WED_BUF_PER_PAGE) {
++	for (i = 0; i < ring_size; i += MTK_WED_BUF_PER_PAGE) {
+ 		dma_addr_t page_phys, buf_phys;
+ 		struct page *page;
+ 		void *buf;
+@@ -319,7 +475,8 @@ mtk_wed_tx_buffer_alloc(struct mtk_wed_device *dev)
+ 			return -ENOMEM;
+ 		}
+ 
+-		page_list[page_idx++] = page;
++		page_list[page_idx].p = page;
++		page_list[page_idx++].phy_addr = page_phys;
+ 		dma_sync_single_for_cpu(dev->hw->dev, page_phys, PAGE_SIZE,
+ 					DMA_BIDIRECTIONAL);
+ 
+@@ -327,28 +484,31 @@ mtk_wed_tx_buffer_alloc(struct mtk_wed_device *dev)
+ 		buf_phys = page_phys;
+ 
+ 		for (s = 0; s < MTK_WED_BUF_PER_PAGE; s++) {
+-			u32 txd_size;
+-			u32 ctrl;
+-
+-			txd_size = dev->wlan.init_buf(buf, buf_phys, token++);
++			struct mtk_wdma_desc *desc = desc_ptr;
+ 
+ 			desc->buf0 = cpu_to_le32(buf_phys);
+-			desc->buf1 = cpu_to_le32(buf_phys + txd_size);
+-
+-			if (dev->hw->version == 1)
+-				ctrl = FIELD_PREP(MTK_WDMA_DESC_CTRL_LEN0, txd_size) |
+-				       FIELD_PREP(MTK_WDMA_DESC_CTRL_LEN1,
+-						  MTK_WED_BUF_SIZE - txd_size) |
+-				       MTK_WDMA_DESC_CTRL_LAST_SEG1;
+-			else
+-				ctrl = FIELD_PREP(MTK_WDMA_DESC_CTRL_LEN0, txd_size) |
+-				       FIELD_PREP(MTK_WDMA_DESC_CTRL_LEN1_V2,
+-						  MTK_WED_BUF_SIZE - txd_size) |
+-				       MTK_WDMA_DESC_CTRL_LAST_SEG0;
+-			desc->ctrl = cpu_to_le32(ctrl);
+-			desc->info = 0;
+-			desc++;
+-
++			if (!mtk_wed_is_v3_or_greater(dev->hw)) {
++				u32 txd_size, ctrl;
++
++				txd_size = dev->wlan.init_buf(buf, buf_phys,
++							      token++);
++				desc->buf1 = cpu_to_le32(buf_phys + txd_size);
++				ctrl = FIELD_PREP(MTK_WDMA_DESC_CTRL_LEN0, txd_size);
++				if (mtk_wed_is_v1(dev->hw))
++					ctrl |= MTK_WDMA_DESC_CTRL_LAST_SEG1 |
++						FIELD_PREP(MTK_WDMA_DESC_CTRL_LEN1,
++							   MTK_WED_BUF_SIZE - txd_size);
++				else
++					ctrl |= MTK_WDMA_DESC_CTRL_LAST_SEG0 |
++						FIELD_PREP(MTK_WDMA_DESC_CTRL_LEN1_V2,
++							   MTK_WED_BUF_SIZE - txd_size);
++				desc->ctrl = cpu_to_le32(ctrl);
++				desc->info = 0;
++			} else {
++				desc->ctrl = cpu_to_le32(token << 16);
++			}
++
++			desc_ptr += desc_size;
+ 			buf += MTK_WED_BUF_SIZE;
+ 			buf_phys += MTK_WED_BUF_SIZE;
+ 		}
+@@ -363,48 +523,107 @@ mtk_wed_tx_buffer_alloc(struct mtk_wed_device *dev)
+ static void
+ mtk_wed_free_tx_buffer(struct mtk_wed_device *dev)
+ {
+-	struct mtk_wdma_desc *desc = dev->tx_buf_ring.desc;
+-	void **page_list = dev->tx_buf_ring.pages;
+-	int ring_size, page_idx;
+-	int i;
++	struct mtk_wed_buf *page_list = dev->tx_buf_ring.pages;
++	struct mtk_wed_hw *hw = dev->hw;
++	int i, page_idx = 0;
+ 
+ 	if (!page_list)
+ 		return;
+ 
+-	if (!desc)
++	if (!dev->tx_buf_ring.desc)
+ 		goto free_pagelist;
+ 
+-	if (dev->hw->version == 1) {
+-		ring_size = dev->wlan.nbuf & ~(MTK_WED_BUF_PER_PAGE - 1);
+-	} else {
+-		ring_size = MTK_WED_VLD_GROUP_SIZE * MTK_WED_PER_GROUP_PKT +
+-			    MTK_WED_WDMA_RING_SIZE * 2;
+-	}
+-
+-	for (i = 0, page_idx = 0; i < ring_size; i += MTK_WED_BUF_PER_PAGE) {
+-		void *page = page_list[page_idx++];
+-		dma_addr_t buf_addr;
++	for (i = 0; i < dev->tx_buf_ring.size; i += MTK_WED_BUF_PER_PAGE) {
++		dma_addr_t page_phy = page_list[page_idx].phy_addr;
++		void *page = page_list[page_idx++].p;
+ 
+ 		if (!page)
+ 			break;
+ 
+-		buf_addr = le32_to_cpu(desc[i].buf0);
+-		dma_unmap_page(dev->hw->dev, buf_addr, PAGE_SIZE,
++		dma_unmap_page(dev->hw->dev, page_phy, PAGE_SIZE,
+ 			       DMA_BIDIRECTIONAL);
+ 		__free_page(page);
+ 	}
+ 
+-	dma_free_coherent(dev->hw->dev, ring_size * sizeof(*desc),
+-			  desc, dev->tx_buf_ring.desc_phys);
++	dma_free_coherent(dev->hw->dev,
++			  dev->tx_buf_ring.size * hw->soc->tx_ring_desc_size,
++			  dev->tx_buf_ring.desc,
++			  dev->tx_buf_ring.desc_phys);
+ 
+ free_pagelist:
+ 	kfree(page_list);
+ }
+ 
++static int
++mtk_wed_hwrro_buffer_alloc(struct mtk_wed_device *dev)
++{
++	int n_pages = MTK_WED_RX_PG_BM_CNT / MTK_WED_RX_PAGE_BUF_PER_PAGE;
++	struct mtk_wed_buf *page_list;
++	struct mtk_wed_bm_desc *desc;
++	dma_addr_t desc_phys;
++	int i, page_idx = 0;
++
++	if (!dev->wlan.hw_rro)
++		return 0;
++
++	page_list = kcalloc(n_pages, sizeof(*page_list), GFP_KERNEL);
++	if (!page_list)
++		return -ENOMEM;
++
++	dev->hw_rro.size = dev->wlan.rx_nbuf & ~(MTK_WED_BUF_PER_PAGE - 1);
++	dev->hw_rro.pages = page_list;
++
++	desc = dma_alloc_coherent(dev->hw->dev,
++				  dev->wlan.rx_nbuf * sizeof(*desc),
++				  &desc_phys, GFP_KERNEL);
++	if (!desc)
++		return -ENOMEM;
++
++	dev->hw_rro.desc = desc;
++	dev->hw_rro.desc_phys = desc_phys;
++
++	for (i = 0, page_idx = 0; i < MTK_WED_RX_PG_BM_CNT; i += MTK_WED_RX_PAGE_BUF_PER_PAGE) {
++		dma_addr_t page_phys, buf_phys;
++		struct page *page;
++		void *buf;
++		int s;
++
++		page = __dev_alloc_pages(GFP_KERNEL, 0);
++		if (!page)
++			return -ENOMEM;
++
++		page_phys = dma_map_page(dev->hw->dev, page, 0, PAGE_SIZE,
++		                        DMA_BIDIRECTIONAL);
++		if (dma_mapping_error(dev->hw->dev, page_phys)) {
++			__free_page(page);
++			return -ENOMEM;
++		}
++
++		page_list[page_idx].p= page;
++		page_list[page_idx++].phy_addr= page_phys;
++		dma_sync_single_for_cpu(dev->hw->dev, page_phys, PAGE_SIZE,
++		                       DMA_BIDIRECTIONAL);
++
++		buf = page_to_virt(page);
++		buf_phys = page_phys;
++		for (s = 0; s < MTK_WED_RX_PAGE_BUF_PER_PAGE; s++) {
++			desc->buf0 = cpu_to_le32(buf_phys);
++			desc++;
++			buf += MTK_WED_PAGE_BUF_SIZE;
++			buf_phys += MTK_WED_PAGE_BUF_SIZE;
++		}
++
++		dma_sync_single_for_device(dev->hw->dev, page_phys, PAGE_SIZE,
++					   DMA_BIDIRECTIONAL);
++	}
++
++	return 0;
++}
++
+ static int
+ mtk_wed_rx_buffer_alloc(struct mtk_wed_device *dev)
+ {
+-	struct mtk_rxbm_desc *desc;
++	struct mtk_wed_bm_desc *desc;
+ 	dma_addr_t desc_phys;
+ 
+ 	dev->rx_buf_ring.size = dev->wlan.rx_nbuf;
+@@ -418,13 +637,48 @@ mtk_wed_rx_buffer_alloc(struct mtk_wed_device *dev)
+ 	dev->rx_buf_ring.desc_phys = desc_phys;
+ 	dev->wlan.init_rx_buf(dev, dev->wlan.rx_npkt);
+ 
+-	return 0;
++	return mtk_wed_hwrro_buffer_alloc(dev);
++}
++
++static void
++mtk_wed_hwrro_free_buffer(struct mtk_wed_device *dev)
++{
++	struct mtk_wed_buf *page_list = dev->hw_rro.pages;
++	struct mtk_wed_bm_desc *desc = dev->hw_rro.desc;
++	int i, page_idx = 0;
++
++	if (!dev->wlan.hw_rro)
++		return;
++
++	if (!page_list)
++		return;
++
++	if (!desc)
++		goto free_pagelist;
++
++	for (i = 0; i < MTK_WED_RX_PG_BM_CNT; i += MTK_WED_RX_PAGE_BUF_PER_PAGE) {
++		dma_addr_t buf_addr = page_list[page_idx].phy_addr;
++		void *page = page_list[page_idx++].p;
++
++		if (!page)
++			break;
++
++		dma_unmap_page(dev->hw->dev, buf_addr, PAGE_SIZE,
++			       DMA_BIDIRECTIONAL);
++		__free_page(page);
++       }
++
++	dma_free_coherent(dev->hw->dev, dev->hw_rro.size * sizeof(*desc),
++                         desc, dev->hw_rro.desc_phys);
++
++free_pagelist:
++       kfree(page_list);
+ }
+ 
+ static void
+ mtk_wed_free_rx_buffer(struct mtk_wed_device *dev)
+ {
+-	struct mtk_rxbm_desc *desc = dev->rx_buf_ring.desc;
++	struct mtk_wed_bm_desc *desc = dev->rx_buf_ring.desc;
+ 
+ 	if (!desc)
+ 		return;
+@@ -433,6 +687,28 @@ mtk_wed_free_rx_buffer(struct mtk_wed_device *dev)
+ 
+ 	dma_free_coherent(dev->hw->dev, dev->rx_buf_ring.size * sizeof(*desc),
+ 			  desc, dev->rx_buf_ring.desc_phys);
++
++	mtk_wed_hwrro_free_buffer(dev);
++}
++
++static void
++mtk_wed_hwrro_init(struct mtk_wed_device *dev)
++{
++	if (!mtk_wed_get_rx_capa(dev) || !dev->wlan.hw_rro)
++		return;
++
++	wed_set(dev, MTK_WED_RRO_PG_BM_RX_DMAM,
++		FIELD_PREP(MTK_WED_RRO_PG_BM_RX_SDL0, 128));
++
++	wed_w32(dev, MTK_WED_RRO_PG_BM_BASE, dev->hw_rro.desc_phys);
++
++	wed_w32(dev, MTK_WED_RRO_PG_BM_INIT_PTR,
++		MTK_WED_RRO_PG_BM_INIT_SW_TAIL_IDX |
++		FIELD_PREP(MTK_WED_RRO_PG_BM_SW_TAIL_IDX,
++			   MTK_WED_RX_PG_BM_CNT));
++
++	/* enable rx_page_bm to fetch dmad */
++	wed_set(dev, MTK_WED_CTRL, MTK_WED_CTRL_WED_RX_PG_BM_EN);
+ }
+ 
+ static void
+@@ -450,6 +726,8 @@ mtk_wed_rx_buffer_hw_init(struct mtk_wed_device *dev)
+ 		FIELD_PREP(MTK_WED_RX_BM_DYN_ALLOC_TH_H, 0xffff));
+ 
+ 	wed_set(dev, MTK_WED_CTRL, MTK_WED_CTRL_WED_RX_BM_EN);
++
++	mtk_wed_hwrro_init(dev);
+ }
+ 
+ static void
+@@ -465,6 +743,16 @@ mtk_wed_free_ring(struct mtk_wed_device *dev, struct mtk_wed_ring *ring)
+ static void
+ mtk_wed_free_rx_rings(struct mtk_wed_device *dev)
+ {
++	int i;
++
++	for (i = 0; i < ARRAY_SIZE(dev->rx_ring); i++)
++		if ((dev->tx_ring[i].flags & MTK_WED_RING_CONFIGURED))
++			mtk_wed_free_ring(dev, &dev->rx_ring[i]);
++
++	for (i = 0; i < ARRAY_SIZE(dev->tx_wdma); i++)
++		if ((dev->tx_wdma[i].flags & MTK_WED_RING_CONFIGURED))
++			mtk_wed_free_ring(dev, &dev->tx_wdma[i]);
++
+ 	mtk_wed_free_rx_buffer(dev);
+ 	mtk_wed_free_ring(dev, &dev->rro.ring);
+ }
+@@ -475,9 +763,12 @@ mtk_wed_free_tx_rings(struct mtk_wed_device *dev)
+ 	int i;
+ 
+ 	for (i = 0; i < ARRAY_SIZE(dev->tx_ring); i++)
+-		mtk_wed_free_ring(dev, &dev->tx_ring[i]);
++		if ((dev->tx_ring[i].flags & MTK_WED_RING_CONFIGURED))
++			mtk_wed_free_ring(dev, &dev->tx_ring[i]);
++
+ 	for (i = 0; i < ARRAY_SIZE(dev->rx_wdma); i++)
+-		mtk_wed_free_ring(dev, &dev->rx_wdma[i]);
++		if ((dev->rx_wdma[i].flags & MTK_WED_RING_CONFIGURED))
++			mtk_wed_free_ring(dev, &dev->rx_wdma[i]);
+ }
+ 
+ static void
+@@ -485,8 +776,20 @@ mtk_wed_set_ext_int(struct mtk_wed_device *dev, bool en)
+ {
+ 	u32 mask = MTK_WED_EXT_INT_STATUS_ERROR_MASK;
+ 
+-	if (dev->hw->version == 1)
++	switch (dev->hw->version) {
++	case 1:
+ 		mask |= MTK_WED_EXT_INT_STATUS_TX_DRV_R_RESP_ERR;
++		break;
++	case 2:
++		mask |= MTK_WED_EXT_INT_STATUS_RX_FBUF_LO_TH2 |
++			MTK_WED_EXT_INT_STATUS_RX_FBUF_HI_TH2 |
++			MTK_WED_EXT_INT_STATUS_RX_DRV_COHERENT |
++			MTK_WED_EXT_INT_STATUS_TX_DMA_W_RESP_ERR;
++		break;
++	case 3:
++		mask = MTK_WED_EXT_INT_STATUS_RX_DRV_COHERENT;
++		break;
++	}
+ 
+ 	if (!dev->hw->num_flows)
+ 		mask &= ~MTK_WED_EXT_INT_STATUS_TKID_WO_PYLD;
+@@ -498,6 +801,9 @@ mtk_wed_set_ext_int(struct mtk_wed_device *dev, bool en)
+ static void
+ mtk_wed_set_512_support(struct mtk_wed_device *dev, bool enable)
+ {
++	if (!mtk_wed_is_v2(dev->hw))
++		return;
++
+ 	if (enable) {
+ 		wed_w32(dev, MTK_WED_TXDP_CTRL, MTK_WED_TXDP_DW9_OVERWR);
+ 		wed_w32(dev, MTK_WED_TXP_DW1,
+@@ -509,22 +815,15 @@ mtk_wed_set_512_support(struct mtk_wed_device *dev, bool enable)
+ 	}
+ }
+ 
+-#define MTK_WFMDA_RX_DMA_EN	BIT(2)
+-static void
+-mtk_wed_check_wfdma_rx_fill(struct mtk_wed_device *dev, int idx)
++static int
++mtk_wed_check_wfdma_rx_fill(struct mtk_wed_device *dev,
++			    struct mtk_wed_ring *ring)
+ {
+-	u32 val;
+ 	int i;
+ 
+-	if(!(dev->rx_ring[idx].flags & MTK_WED_RING_CONFIGURED))
+-		return;
+-
+ 	for (i = 0; i < 3; i++) {
+-		u32 cur_idx;
++		u32 cur_idx = readl(ring->wpdma + MTK_WED_RING_OFS_CPU_IDX);
+ 
+-		cur_idx = wed_r32(dev,
+-				  MTK_WED_WPDMA_RING_RX_DATA(idx) +
+-				  MTK_WED_RING_OFS_CPU_IDX);
+ 		if (cur_idx == MTK_WED_RX_RING_SIZE - 1)
+ 			break;
+ 
+@@ -532,14 +831,12 @@ mtk_wed_check_wfdma_rx_fill(struct mtk_wed_device *dev, int idx)
+ 	}
+ 
+ 	if (i == 3) {
+-		dev_err(dev->hw->dev, "mtk_wed%d: rx(%d) dma enable failed!\n",
+-			       dev->hw->index, idx);
+-		return;
++		dev_err(dev->hw->dev, "mtk_wed%d: dma enable failed!\n",
++			dev->hw->index);
++		return -ETIMEDOUT;
+ 	}
+ 
+-	val = wifi_r32(dev, dev->wlan.wpdma_rx_glo - dev->wlan.phy_base) |
+-	      MTK_WFMDA_RX_DMA_EN;
+-	wifi_w32(dev, dev->wlan.wpdma_rx_glo - dev->wlan.phy_base, val);
++	return 0;
+ }
+ 
+ static void
+@@ -561,7 +858,7 @@ mtk_wed_dma_disable(struct mtk_wed_device *dev)
+ 		 MTK_WDMA_GLO_CFG_RX_INFO1_PRERES |
+ 		 MTK_WDMA_GLO_CFG_RX_INFO2_PRERES);
+ 
+-	if (dev->hw->version == 1) {
++	if (mtk_wed_is_v1(dev->hw)) {
+ 		regmap_write(dev->hw->mirror, dev->hw->index * 4, 0);
+ 		wdma_clr(dev, MTK_WDMA_GLO_CFG,
+ 			 MTK_WDMA_GLO_CFG_RX_INFO3_PRERES);
+@@ -573,9 +870,17 @@ mtk_wed_dma_disable(struct mtk_wed_device *dev)
+ 			MTK_WED_WPDMA_RX_D_RX_DRV_EN);
+ 		wed_clr(dev, MTK_WED_WDMA_GLO_CFG,
+ 			MTK_WED_WDMA_GLO_CFG_TX_DDONE_CHK);
++
++		if (mtk_wed_is_v3_or_greater(dev->hw) &&
++		    mtk_wed_get_rx_capa(dev)) {
++			wdma_clr(dev, MTK_WDMA_PREF_TX_CFG,
++				 MTK_WDMA_PREF_TX_CFG_PREF_EN);
++			wdma_clr(dev, MTK_WDMA_PREF_RX_CFG,
++				 MTK_WDMA_PREF_RX_CFG_PREF_EN);
++		}
+ 	}
+ 
+-	mtk_wed_set_512_support (dev, false);
++	mtk_wed_set_512_support(dev, false);
+ }
+ 
+ static void
+@@ -589,7 +894,7 @@ mtk_wed_stop(struct mtk_wed_device *dev)
+ 	wdma_w32(dev, MTK_WDMA_INT_GRP2, 0);
+ 	wed_w32(dev, MTK_WED_WPDMA_INT_MASK, 0);
+ 
+-	if (dev->hw->version == 1)
++	if (!mtk_wed_get_rx_capa(dev))
+ 		return;
+ 
+ 	wed_w32(dev, MTK_WED_EXT_INT_MASK1, 0);
+@@ -608,13 +913,21 @@ mtk_wed_deinit(struct mtk_wed_device *dev)
+ 		MTK_WED_CTRL_WED_TX_BM_EN |
+ 		MTK_WED_CTRL_WED_TX_FREE_AGENT_EN);
+ 
+-	if (dev->hw->version == 1)
++	if (mtk_wed_is_v1(dev->hw))
+ 		return;
+ 
+ 	wed_clr(dev, MTK_WED_CTRL,
+ 		MTK_WED_CTRL_RX_ROUTE_QM_EN |
+ 		MTK_WED_CTRL_WED_RX_BM_EN |
+ 		MTK_WED_CTRL_RX_RRO_QM_EN);
++
++	if (mtk_wed_is_v3_or_greater(dev->hw)) {
++		wed_clr(dev, MTK_WED_CTRL, MTK_WED_CTRL_TX_AMSDU_EN);
++		wed_clr(dev, MTK_WED_RESET, MTK_WED_RESET_TX_AMSDU);
++		wed_clr(dev, MTK_WED_PCIE_INT_CTRL,
++			MTK_WED_PCIE_INT_CTRL_MSK_EN_POLA |
++			MTK_WED_PCIE_INT_CTRL_MSK_IRQ_FILTER);
++	}
+ }
+ 
+ static void
+@@ -627,6 +940,8 @@ __mtk_wed_detach(struct mtk_wed_device *dev)
+ 
+ 	mtk_wdma_rx_reset(dev);
+ 	mtk_wed_reset(dev, MTK_WED_RESET_WED);
++	mtk_wed_amsdu_free_buffer(dev);
++	mtk_wdma_tx_reset(dev);
+ 	mtk_wed_free_tx_buffer(dev);
+ 	mtk_wed_free_tx_rings(dev);
+ 
+@@ -636,7 +951,6 @@ __mtk_wed_detach(struct mtk_wed_device *dev)
+ 		mtk_wed_free_rx_rings(dev);
+ 		if(hw->wed_wo)
+ 			mtk_wed_wo_exit(hw);
+-		mtk_wdma_tx_reset(dev);
+ 	}
+ 
+ 	if (dev->wlan.bus_type == MTK_WED_BUS_PCIE) {
+@@ -664,21 +978,36 @@ mtk_wed_detach(struct mtk_wed_device *dev)
+ 	mutex_unlock(&hw_lock);
+ }
+ 
+-#define PCIE_BASE_ADDR0 0x11280000
+ static void
+ mtk_wed_bus_init(struct mtk_wed_device *dev)
+ {
+ 	switch (dev->wlan.bus_type) {
+ 	case MTK_WED_BUS_PCIE: {
+ 		struct device_node *np = dev->hw->eth->dev->of_node;
+-		struct regmap *regs;
+ 
+-		regs = syscon_regmap_lookup_by_phandle(np,
+-						       "mediatek,wed-pcie");
+-		if (IS_ERR(regs))
+-			break;
++		if (mtk_wed_is_v2(dev->hw)) {
++			struct regmap *regs;
++			regs = syscon_regmap_lookup_by_phandle(np,
++							       "mediatek,wed-pcie");
++			if (IS_ERR(regs))
++				break;
++
++			regmap_update_bits(regs, 0, BIT(0), BIT(0));
++		}
+ 
+-		regmap_update_bits(regs, 0, BIT(0), BIT(0));
++		if (dev->wlan.msi) {
++		     wed_w32(dev, MTK_WED_PCIE_CFG_INTM,
++			     dev->hw->pci_base | 0xc08);
++		     wed_w32(dev, MTK_WED_PCIE_CFG_BASE,
++			     dev->hw->pci_base | 0xc04);
++		     wed_w32(dev, MTK_WED_PCIE_INT_TRIGGER, BIT(8));
++		} else {
++		     wed_w32(dev, MTK_WED_PCIE_CFG_INTM,
++			     dev->hw->pci_base | 0x180);
++		     wed_w32(dev, MTK_WED_PCIE_CFG_BASE,
++			     dev->hw->pci_base | 0x184);
++		     wed_w32(dev, MTK_WED_PCIE_INT_TRIGGER, BIT(24));
++		}
+ 
+ 		wed_w32(dev, MTK_WED_PCIE_INT_CTRL,
+ 			FIELD_PREP(MTK_WED_PCIE_INT_CTRL_POLL_EN, 2));
+@@ -686,19 +1015,9 @@ mtk_wed_bus_init(struct mtk_wed_device *dev)
+ 		/* pcie interrupt control: pola/source selection */
+ 		wed_set(dev, MTK_WED_PCIE_INT_CTRL,
+ 			MTK_WED_PCIE_INT_CTRL_MSK_EN_POLA |
+-			FIELD_PREP(MTK_WED_PCIE_INT_CTRL_SRC_SEL, 1));
+-		wed_r32(dev, MTK_WED_PCIE_INT_CTRL);
+-
+-		wed_w32(dev, MTK_WED_PCIE_CFG_INTM, PCIE_BASE_ADDR0 | 0x180);
+-		wed_w32(dev, MTK_WED_PCIE_CFG_BASE, PCIE_BASE_ADDR0 | 0x184);
+-
+-		/* pcie interrupt status trigger register */
+-		wed_w32(dev, MTK_WED_PCIE_INT_TRIGGER, BIT(24));
+-		wed_r32(dev, MTK_WED_PCIE_INT_TRIGGER);
+-
+-		/* pola setting */
+-		wed_set(dev, MTK_WED_PCIE_INT_CTRL,
+-			MTK_WED_PCIE_INT_CTRL_MSK_EN_POLA);
++			MTK_WED_PCIE_INT_CTRL_MSK_IRQ_FILTER |
++			FIELD_PREP(MTK_WED_PCIE_INT_CTRL_SRC_SEL,
++				   dev->hw->index));
+ 		break;
+ 	}
+ 	case MTK_WED_BUS_AXI:
+@@ -714,45 +1033,71 @@ mtk_wed_bus_init(struct mtk_wed_device *dev)
+ static void
+ mtk_wed_set_wpdma(struct mtk_wed_device *dev)
+ {
+-	if (dev->hw->version == 1) {
+-		wed_w32(dev, MTK_WED_WPDMA_CFG_BASE,  dev->wlan.wpdma_phys);
+-	} else {
+-		mtk_wed_bus_init(dev);
++	int i;
+ 
+-		wed_w32(dev, MTK_WED_WPDMA_CFG_BASE,  dev->wlan.wpdma_int);
+-		wed_w32(dev, MTK_WED_WPDMA_CFG_INT_MASK,  dev->wlan.wpdma_mask);
+-		wed_w32(dev, MTK_WED_WPDMA_CFG_TX,  dev->wlan.wpdma_tx);
+-		wed_w32(dev, MTK_WED_WPDMA_CFG_TX_FREE,  dev->wlan.wpdma_txfree);
+-		wed_w32(dev, MTK_WED_WPDMA_RX_GLO_CFG,  dev->wlan.wpdma_rx_glo);
+-		wed_w32(dev, MTK_WED_WPDMA_RX_RING,  dev->wlan.wpdma_rx);
++	if (mtk_wed_is_v1(dev->hw)) {
++		wed_w32(dev, MTK_WED_WPDMA_CFG_BASE,  dev->wlan.wpdma_phys);
++		return;
+ 	}
++
++	mtk_wed_bus_init(dev);
++
++	wed_w32(dev, MTK_WED_WPDMA_CFG_BASE,  dev->wlan.wpdma_int);
++	wed_w32(dev, MTK_WED_WPDMA_CFG_INT_MASK,  dev->wlan.wpdma_mask);
++	wed_w32(dev, MTK_WED_WPDMA_CFG_TX, dev->wlan.wpdma_tx);
++	wed_w32(dev, MTK_WED_WPDMA_CFG_TX_FREE,  dev->wlan.wpdma_txfree);
++
++	if (!mtk_wed_get_rx_capa(dev)) 
++		return;
++
++	wed_w32(dev, MTK_WED_WPDMA_RX_GLO_CFG,  dev->wlan.wpdma_rx_glo);
++	wed_w32(dev, dev->hw->soc->regmap.wpdma_rx_ring0,  dev->wlan.wpdma_rx[0]);
++
++	if (dev->wlan.wpdma_rx[1])
++		wed_w32(dev, MTK_WED_WPDMA_RX_RING1,  dev->wlan.wpdma_rx[1]);
++
++	if (!dev->wlan.hw_rro)
++		return;
++
++	wed_w32(dev, MTK_WED_RRO_RX_D_CFG(0), dev->wlan.wpdma_rx_rro[0]);
++	wed_w32(dev, MTK_WED_RRO_RX_D_CFG(1), dev->wlan.wpdma_rx_rro[1]);
++	for (i = 0; i < MTK_WED_RX_PAGE_QUEUES; i++)
++		wed_w32(dev, MTK_WED_RRO_MSDU_PG_RING_CFG(i),
++			dev->wlan.wpdma_rx_pg + i * 0x10);	
+ }
+ 
+ static void
+ mtk_wed_hw_init_early(struct mtk_wed_device *dev)
+ {
+-	u32 mask, set;
++	u32 set = FIELD_PREP(MTK_WED_WDMA_GLO_CFG_BT_SIZE, 2);
++	u32 mask = MTK_WED_WDMA_GLO_CFG_BT_SIZE;
+ 
+ 	mtk_wed_deinit(dev);
+ 	mtk_wed_reset(dev, MTK_WED_RESET_WED);
+ 	mtk_wed_set_wpdma(dev);
+ 
+-	mask = MTK_WED_WDMA_GLO_CFG_BT_SIZE |
+-	       MTK_WED_WDMA_GLO_CFG_DYNAMIC_DMAD_RECYCLE |
+-	       MTK_WED_WDMA_GLO_CFG_RX_DIS_FSM_AUTO_IDLE;
+-	set = FIELD_PREP(MTK_WED_WDMA_GLO_CFG_BT_SIZE, 2) |
+-	      MTK_WED_WDMA_GLO_CFG_DYNAMIC_SKIP_DMAD_PREP |
+-	      MTK_WED_WDMA_GLO_CFG_IDLE_DMAD_SUPPLY;
++	if (!mtk_wed_is_v3_or_greater(dev->hw)) {
++		mask |= MTK_WED_WDMA_GLO_CFG_DYNAMIC_DMAD_RECYCLE |
++			MTK_WED_WDMA_GLO_CFG_RX_DIS_FSM_AUTO_IDLE;
++		set |= MTK_WED_WDMA_GLO_CFG_DYNAMIC_SKIP_DMAD_PREP |
++		       MTK_WED_WDMA_GLO_CFG_IDLE_DMAD_SUPPLY;
++	}
+ 	wed_m32(dev, MTK_WED_WDMA_GLO_CFG, mask, set);
+ 
+-	if (dev->hw->version == 1) {
++	if (mtk_wed_is_v1(dev->hw)) {
+ 		u32 offset;
++
+ 		offset = dev->hw->index ? 0x04000400 : 0;
++
++		wdma_set(dev, MTK_WDMA_GLO_CFG,
++			 MTK_WDMA_GLO_CFG_RX_INFO1_PRERES |
++			 MTK_WDMA_GLO_CFG_RX_INFO2_PRERES |
++			 MTK_WDMA_GLO_CFG_RX_INFO3_PRERES);
++
+ 		wed_w32(dev, MTK_WED_WDMA_OFFSET0, 0x2a042a20 + offset);
+ 		wed_w32(dev, MTK_WED_WDMA_OFFSET1, 0x29002800 + offset);
+ 
+-		wed_w32(dev, MTK_WED_PCIE_CFG_BASE,
+-			MTK_PCIE_BASE(dev->hw->index));
++		wed_w32(dev, MTK_WED_PCIE_CFG_BASE, MTK_PCIE_BASE(dev->hw->index));
+ 	} else {
+ 		wed_w32(dev, MTK_WED_WDMA_CFG_BASE, dev->hw->wdma_phy);
+ 		wed_set(dev, MTK_WED_CTRL, MTK_WED_CTRL_ETH_DMAD_FMT);
+@@ -844,7 +1189,8 @@ mtk_wed_rro_cfg(struct mtk_wed_device *dev)
+ 		},
+ 	};
+ 
+-	return mtk_wed_mcu_send_msg(wo, MTK_WED_MODULE_ID_WO, MTK_WED_WO_CMD_WED_CFG,
++	return mtk_wed_mcu_send_msg(wo, MTK_WED_MODULE_ID_WO,
++				    MTK_WED_WO_CMD_WED_CFG,
+ 				    &req, sizeof(req), true);
+ }
+ 
+@@ -895,11 +1241,18 @@ mtk_wed_route_qm_hw_init(struct mtk_wed_device *dev)
+ 	}
+ 
+ 	/* configure RX_ROUTE_QM */
+-	wed_clr(dev, MTK_WED_RTQM_GLO_CFG, MTK_WED_RTQM_Q_RST);
+-	wed_clr(dev, MTK_WED_RTQM_GLO_CFG, MTK_WED_RTQM_TXDMAD_FPORT);
+-	wed_set(dev, MTK_WED_RTQM_GLO_CFG,
+-		FIELD_PREP(MTK_WED_RTQM_TXDMAD_FPORT, 0x3 + dev->hw->index));
+-	wed_clr(dev, MTK_WED_RTQM_GLO_CFG, MTK_WED_RTQM_Q_RST);
++	if (mtk_wed_is_v2(dev->hw)) {
++		wed_clr(dev, MTK_WED_RTQM_GLO_CFG, MTK_WED_RTQM_Q_RST);
++		wed_clr(dev, MTK_WED_RTQM_GLO_CFG, MTK_WED_RTQM_TXDMAD_FPORT);
++		wed_set(dev, MTK_WED_RTQM_GLO_CFG,
++			FIELD_PREP(MTK_WED_RTQM_TXDMAD_FPORT,
++				   0x3 + dev->hw->index));
++		wed_clr(dev, MTK_WED_RTQM_GLO_CFG, MTK_WED_RTQM_Q_RST);
++	} else {
++		wed_set(dev, MTK_WED_RTQM_ENQ_CFG0,
++			FIELD_PREP(MTK_WED_RTQM_ENQ_CFG_TXDMAD_FPORT,
++				   0x3 + dev->hw->index));
++	}
+ 
+ 	/* enable RX_ROUTE_QM */
+ 	wed_set(dev, MTK_WED_CTRL, MTK_WED_CTRL_RX_ROUTE_QM_EN);
+@@ -918,35 +1271,26 @@ mtk_wed_hw_init(struct mtk_wed_device *dev)
+ 
+ 	wed_w32(dev, MTK_WED_TX_BM_BUF_LEN, MTK_WED_PKT_SIZE);
+ 
+-	if (dev->hw->version == 1) {
++	if (mtk_wed_is_v1(dev->hw)) {
+ 		wed_w32(dev, MTK_WED_TX_BM_CTRL,
+ 			MTK_WED_TX_BM_CTRL_PAUSE |
+ 			FIELD_PREP(MTK_WED_TX_BM_CTRL_VLD_GRP_NUM,
+ 				   dev->tx_buf_ring.size / 128) |
+ 			FIELD_PREP(MTK_WED_TX_BM_CTRL_RSV_GRP_NUM,
+ 				   MTK_WED_TX_RING_SIZE / 256));
+-		wed_w32(dev, MTK_WED_TX_BM_TKID,
+-			FIELD_PREP(MTK_WED_TX_BM_TKID_START,
+-				   dev->wlan.token_start) |
+-			FIELD_PREP(MTK_WED_TX_BM_TKID_END,
+-				   dev->wlan.token_start +
+-				   dev->wlan.nbuf - 1));
+ 		wed_w32(dev, MTK_WED_TX_BM_DYN_THR,
+ 			FIELD_PREP(MTK_WED_TX_BM_DYN_THR_LO, 1) |
+ 			MTK_WED_TX_BM_DYN_THR_HI);
+-	} else {
++	} else if (mtk_wed_is_v2(dev->hw)) {
+ 		wed_w32(dev, MTK_WED_TX_BM_CTRL,
+ 			MTK_WED_TX_BM_CTRL_PAUSE |
+ 			FIELD_PREP(MTK_WED_TX_BM_CTRL_VLD_GRP_NUM,
+ 				   dev->tx_buf_ring.size / 128) |
+ 			FIELD_PREP(MTK_WED_TX_BM_CTRL_RSV_GRP_NUM,
+ 				   dev->tx_buf_ring.size / 128));
+-		wed_w32(dev, MTK_WED_TX_BM_TKID_V2,
+-			FIELD_PREP(MTK_WED_TX_BM_TKID_START,
+-				   dev->wlan.token_start) |
+-			FIELD_PREP(MTK_WED_TX_BM_TKID_END,
+-				   dev->wlan.token_start +
+-				   dev->wlan.nbuf - 1));
++		wed_w32(dev, MTK_WED_TX_TKID_DYN_THR,
++			FIELD_PREP(MTK_WED_TX_TKID_DYN_THR_LO, 0) |
++			MTK_WED_TX_TKID_DYN_THR_HI);
+ 		wed_w32(dev, MTK_WED_TX_BM_DYN_THR,
+ 			FIELD_PREP(MTK_WED_TX_BM_DYN_THR_LO_V2, 0) |
+ 			MTK_WED_TX_BM_DYN_THR_HI_V2);
+@@ -956,32 +1300,73 @@ mtk_wed_hw_init(struct mtk_wed_device *dev)
+ 				   dev->tx_buf_ring.size / 128) |
+ 			FIELD_PREP(MTK_WED_TX_TKID_CTRL_RSV_GRP_NUM,
+ 				   dev->tx_buf_ring.size / 128));
+-		wed_w32(dev, MTK_WED_TX_TKID_DYN_THR,
+-			FIELD_PREP(MTK_WED_TX_TKID_DYN_THR_LO, 0) |
+-			MTK_WED_TX_TKID_DYN_THR_HI);
+ 	}
+ 
++	wed_w32(dev, dev->hw->soc->regmap.tx_bm_tkid,
++		FIELD_PREP(MTK_WED_TX_BM_TKID_START,
++			   dev->wlan.token_start) |
++		FIELD_PREP(MTK_WED_TX_BM_TKID_END,
++			   dev->wlan.token_start + dev->wlan.nbuf - 1));
++
+ 	mtk_wed_reset(dev, MTK_WED_RESET_TX_BM);
+ 
+-	if (dev->hw->version == 1) {
++	if (mtk_wed_is_v3_or_greater(dev->hw)) {
++		/* switch to new bm architecture */
++		wed_clr(dev, MTK_WED_TX_BM_CTRL,
++			MTK_WED_TX_BM_CTRL_LEGACY_EN);
++
++		wed_w32(dev, MTK_WED_TX_TKID_CTRL,
++			MTK_WED_TX_TKID_CTRL_PAUSE |
++			FIELD_PREP(MTK_WED_TX_TKID_CTRL_VLD_GRP_NUM_V3,
++				   dev->wlan.nbuf / 128) |
++			FIELD_PREP(MTK_WED_TX_TKID_CTRL_RSV_GRP_NUM_V3,
++				   dev->wlan.nbuf / 128));
++		/* return SKBID + SDP back to bm */
++		wed_set(dev, MTK_WED_TX_TKID_CTRL,
++			MTK_WED_TX_TKID_CTRL_FREE_FORMAT);
++
++		wed_w32(dev, MTK_WED_TX_BM_INIT_PTR,
++			MTK_WED_TX_BM_PKT_CNT |
++			MTK_WED_TX_BM_INIT_SW_TAIL_IDX);
++	}
++
++	if (mtk_wed_is_v1(dev->hw)) {
+ 		wed_set(dev, MTK_WED_CTRL,
+ 			MTK_WED_CTRL_WED_TX_BM_EN |
+ 			MTK_WED_CTRL_WED_TX_FREE_AGENT_EN);
+-	} else {
+-		wed_clr(dev, MTK_WED_TX_TKID_CTRL, MTK_WED_TX_TKID_CTRL_PAUSE);
+-		/* rx hw init*/
++	} else if (mtk_wed_get_rx_capa(dev)) {
++		/* rx hw init */
+ 		wed_w32(dev, MTK_WED_WPDMA_RX_D_RST_IDX,
+ 			MTK_WED_WPDMA_RX_D_RST_CRX_IDX |
+ 			MTK_WED_WPDMA_RX_D_RST_DRV_IDX);
+ 
+ 		wed_w32(dev, MTK_WED_WPDMA_RX_D_RST_IDX, 0);
+ 
++		/* reset prefetch index of ring */
++		wed_set(dev, MTK_WED_WPDMA_RX_D_PREF_RX0_SIDX,
++			MTK_WED_WPDMA_RX_D_PREF_SIDX_IDX_CLR);
++		wed_clr(dev, MTK_WED_WPDMA_RX_D_PREF_RX0_SIDX,
++			MTK_WED_WPDMA_RX_D_PREF_SIDX_IDX_CLR);
++
++		wed_set(dev, MTK_WED_WPDMA_RX_D_PREF_RX1_SIDX,
++			MTK_WED_WPDMA_RX_D_PREF_SIDX_IDX_CLR);
++		wed_clr(dev, MTK_WED_WPDMA_RX_D_PREF_RX1_SIDX,
++			MTK_WED_WPDMA_RX_D_PREF_SIDX_IDX_CLR);
++
++		/* reset prefetch FIFO of ring */
++		wed_set(dev, MTK_WED_WPDMA_RX_D_PREF_FIFO_CFG,
++			MTK_WED_WPDMA_RX_D_PREF_FIFO_CFG_R0_CLR |
++			MTK_WED_WPDMA_RX_D_PREF_FIFO_CFG_R1_CLR);
++		wed_w32(dev, MTK_WED_WPDMA_RX_D_PREF_FIFO_CFG, 0);
++
+ 		mtk_wed_rx_buffer_hw_init(dev);
+ 		mtk_wed_rro_hw_init(dev);
+ 		mtk_wed_route_qm_hw_init(dev);
+ 	}
+ 
+ 	wed_clr(dev, MTK_WED_TX_BM_CTRL, MTK_WED_TX_BM_CTRL_PAUSE);
++	if (!mtk_wed_is_v1(dev->hw))
++		wed_clr(dev, MTK_WED_TX_TKID_CTRL, MTK_WED_TX_TKID_CTRL_PAUSE);
+ }
+ 
+ static void
+@@ -1099,13 +1484,8 @@ mtk_wed_rx_reset(struct mtk_wed_device *dev)
+ 	if (ret) {
+ 		mtk_wed_reset(dev, MTK_WED_RESET_WED_RX_DMA);
+ 	} else {
+-		struct mtk_eth *eth = dev->hw->eth;
+-
+-		if(MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V2))
+-			wed_set(dev, MTK_WED_RESET_IDX,
+-				MTK_WED_RESET_IDX_RX_V2);
+-		else
+-			wed_set(dev, MTK_WED_RESET_IDX, MTK_WED_RESET_IDX_RX);
++		wed_set(dev, MTK_WED_RESET_IDX,
++			dev->hw->soc->regmap.reset_idx_rx_mask);
+ 		wed_w32(dev, MTK_WED_RESET_IDX, 0);
+ 	}
+ 
+@@ -1162,7 +1542,8 @@ mtk_wed_reset_dma(struct mtk_wed_device *dev)
+ 	if (busy) {
+ 		mtk_wed_reset(dev, MTK_WED_RESET_WED_TX_DMA);
+ 	} else {
+-		wed_w32(dev, MTK_WED_RESET_IDX, MTK_WED_RESET_IDX_TX);
++		wed_w32(dev, MTK_WED_RESET_IDX,
++			dev->hw->soc->regmap.reset_idx_tx_mask);
+ 		wed_w32(dev, MTK_WED_RESET_IDX, 0);
+ 	}
+ 
+@@ -1226,7 +1607,7 @@ mtk_wed_reset_dma(struct mtk_wed_device *dev)
+ 	}
+ 
+ 	dev->init_done = false;
+-	if (dev->hw->version == 1)
++	if (mtk_wed_is_v1(dev->hw))
+ 		return;
+ 
+ 	if (!busy) {
+@@ -1257,7 +1638,6 @@ static int
+ mtk_wed_wdma_rx_ring_setup(struct mtk_wed_device *dev, int idx, int size,
+ 			   bool reset)
+ {
+-	u32 desc_size = sizeof(struct mtk_wdma_desc) * dev->hw->version;
+ 	struct mtk_wed_ring *wdma;
+ 
+ 	if (idx >= ARRAY_SIZE(dev->rx_wdma))
+@@ -1265,9 +1645,11 @@ mtk_wed_wdma_rx_ring_setup(struct mtk_wed_device *dev, int idx, int size,
+ 
+ 	wdma = &dev->rx_wdma[idx];
+ 	if (!reset && mtk_wed_ring_alloc(dev, wdma, MTK_WED_WDMA_RING_SIZE,
+-					 desc_size, true))
++					 dev->hw->soc->wdma_desc_size, true))
+ 		return -ENOMEM;
+ 
++	wdma->flags |= MTK_WED_RING_CONFIGURED;
++
+ 	wdma_w32(dev, MTK_WDMA_RING_RX(idx) + MTK_WED_RING_OFS_BASE,
+ 		 wdma->desc_phys);
+ 	wdma_w32(dev, MTK_WDMA_RING_RX(idx) + MTK_WED_RING_OFS_COUNT,
+@@ -1286,7 +1668,6 @@ static int
+ mtk_wed_wdma_tx_ring_setup(struct mtk_wed_device *dev, int idx, int size,
+ 			   bool reset)
+ {
+-	u32 desc_size = sizeof(struct mtk_wdma_desc) * dev->hw->version;
+ 	struct mtk_wed_ring *wdma;
+ 
+ 	if (idx >= ARRAY_SIZE(dev->tx_wdma))
+@@ -1294,9 +1675,29 @@ mtk_wed_wdma_tx_ring_setup(struct mtk_wed_device *dev, int idx, int size,
+ 
+ 	wdma = &dev->tx_wdma[idx];
+ 	if (!reset && mtk_wed_ring_alloc(dev, wdma, MTK_WED_WDMA_RING_SIZE,
+-					 desc_size, true))
++					 dev->hw->soc->wdma_desc_size, true))
+ 		return -ENOMEM;
+ 
++	if (mtk_wed_is_v3_or_greater(dev->hw)) {
++		struct mtk_wdma_desc *desc = wdma->desc;
++		int i;
++
++		for (i = 0; i < MTK_WED_WDMA_RING_SIZE; i++) {
++			desc->buf0 = 0;
++			desc->ctrl = MTK_WDMA_DESC_CTRL_DMA_DONE;
++			desc->buf1 = 0;
++			desc->info = MTK_WDMA_TXD0_DESC_INFO_DMA_DONE;
++			desc++;
++			desc->buf0 = 0;
++			desc->ctrl = MTK_WDMA_DESC_CTRL_DMA_DONE;
++			desc->buf1 = 0;
++			desc->info = MTK_WDMA_TXD1_DESC_INFO_DMA_DONE;
++			desc++;
++		}
++	}
++
++	wdma->flags |= MTK_WED_RING_CONFIGURED;
++
+ 	wdma_w32(dev, MTK_WDMA_RING_TX(idx) + MTK_WED_RING_OFS_BASE,
+ 		 wdma->desc_phys);
+ 	wdma_w32(dev, MTK_WDMA_RING_TX(idx) + MTK_WED_RING_OFS_COUNT,
+@@ -1354,7 +1755,7 @@ mtk_wed_configure_irq(struct mtk_wed_device *dev, u32 irq_mask)
+ 		MTK_WED_CTRL_WED_TX_BM_EN |
+ 		MTK_WED_CTRL_WED_TX_FREE_AGENT_EN);
+ 
+-	if (dev->hw->version == 1) {
++	if (mtk_wed_is_v1(dev->hw)) {
+ 		wed_w32(dev, MTK_WED_PCIE_INT_TRIGGER,
+ 			MTK_WED_PCIE_INT_TRIGGER_STATUS);
+ 
+@@ -1364,8 +1765,9 @@ mtk_wed_configure_irq(struct mtk_wed_device *dev, u32 irq_mask)
+ 
+ 		wed_clr(dev, MTK_WED_WDMA_INT_CTRL, wdma_mask);
+ 	} else {
+-		wdma_mask |= FIELD_PREP(MTK_WDMA_INT_MASK_TX_DONE,
+-					GENMASK(1, 0));
++		if (mtk_wed_is_v3_or_greater(dev->hw))
++			wed_set(dev, MTK_WED_CTRL, MTK_WED_CTRL_TX_TKID_ALI_EN);
++
+ 		/* initail tx interrupt trigger */
+ 		wed_w32(dev, MTK_WED_WPDMA_INT_CTRL_TX,
+ 			MTK_WED_WPDMA_INT_CTRL_TX0_DONE_EN |
+@@ -1384,19 +1786,25 @@ mtk_wed_configure_irq(struct mtk_wed_device *dev, u32 irq_mask)
+ 			FIELD_PREP(MTK_WED_WPDMA_INT_CTRL_TX_FREE_DONE_TRIG,
+ 				    dev->wlan.txfree_tbit));
+ 
+-		wed_w32(dev, MTK_WED_WPDMA_INT_CTRL_RX,
+-			MTK_WED_WPDMA_INT_CTRL_RX0_EN |
+-			MTK_WED_WPDMA_INT_CTRL_RX0_CLR |
+-			MTK_WED_WPDMA_INT_CTRL_RX1_EN |
+-			MTK_WED_WPDMA_INT_CTRL_RX1_CLR |
+-			FIELD_PREP(MTK_WED_WPDMA_INT_CTRL_RX0_DONE_TRIG,
+-				   dev->wlan.rx_tbit[0]) |
+-			FIELD_PREP(MTK_WED_WPDMA_INT_CTRL_RX1_DONE_TRIG,
+-				   dev->wlan.rx_tbit[1]));
++		if (mtk_wed_get_rx_capa(dev)) {
++			wed_w32(dev, MTK_WED_WPDMA_INT_CTRL_RX,
++				MTK_WED_WPDMA_INT_CTRL_RX0_EN |
++				MTK_WED_WPDMA_INT_CTRL_RX0_CLR |
++				MTK_WED_WPDMA_INT_CTRL_RX1_EN |
++				MTK_WED_WPDMA_INT_CTRL_RX1_CLR |
++				FIELD_PREP(MTK_WED_WPDMA_INT_CTRL_RX0_DONE_TRIG,
++					   dev->wlan.rx_tbit[0]) |
++				FIELD_PREP(MTK_WED_WPDMA_INT_CTRL_RX1_DONE_TRIG,
++					   dev->wlan.rx_tbit[1]));
++
++			wdma_mask |= FIELD_PREP(MTK_WDMA_INT_MASK_TX_DONE,
++						GENMASK(1, 0));
++		}
+ 
+ 		wed_w32(dev, MTK_WED_WDMA_INT_CLR, wdma_mask);
+ 		wed_set(dev, MTK_WED_WDMA_INT_CTRL,
+-			FIELD_PREP(MTK_WED_WDMA_INT_POLL_SRC_SEL,dev->wdma_idx));
++			FIELD_PREP(MTK_WED_WDMA_INT_POLL_SRC_SEL,
++				   dev->wdma_idx));
+ 	}
+ 	/* initail wdma interrupt agent */
+ 	wed_w32(dev, MTK_WED_WDMA_INT_TRIGGER, wdma_mask);
+@@ -1407,58 +1815,295 @@ mtk_wed_configure_irq(struct mtk_wed_device *dev, u32 irq_mask)
+ 	wed_w32(dev, MTK_WED_INT_MASK, irq_mask);
+ }
+ 
++#define MTK_WFMDA_RX_DMA_EN 	BIT(2)
+ static void
+ mtk_wed_dma_enable(struct mtk_wed_device *dev)
+ {
+-	wed_set(dev, MTK_WED_WPDMA_INT_CTRL,
+-		MTK_WED_WPDMA_INT_CTRL_SUBRT_ADV);
++	int i;
++
++	if (!mtk_wed_is_v3_or_greater(dev->hw)) {
++		wed_set(dev, MTK_WED_WPDMA_INT_CTRL,
++			MTK_WED_WPDMA_INT_CTRL_SUBRT_ADV);
++		wed_set(dev, MTK_WED_WPDMA_GLO_CFG,
++			MTK_WED_WPDMA_GLO_CFG_TX_DRV_EN |
++			MTK_WED_WPDMA_GLO_CFG_RX_DRV_EN);
++		wdma_set(dev, MTK_WDMA_GLO_CFG,
++			 MTK_WDMA_GLO_CFG_TX_DMA_EN |
++			 MTK_WDMA_GLO_CFG_RX_INFO1_PRERES |
++			 MTK_WDMA_GLO_CFG_RX_INFO2_PRERES);
++		wed_set(dev, MTK_WED_WPDMA_CTRL, MTK_WED_WPDMA_CTRL_SDL1_FIXED);
++	} else {
++		wed_set(dev, MTK_WED_WPDMA_GLO_CFG,
++			MTK_WED_WPDMA_GLO_CFG_TX_DRV_EN |
++			MTK_WED_WPDMA_GLO_CFG_RX_DRV_EN |
++			MTK_WED_WPDMA_GLO_CFG_RX_DDONE2_WR);
++		wdma_set(dev, MTK_WDMA_GLO_CFG, MTK_WDMA_GLO_CFG_TX_DMA_EN);
++	}
+ 
+ 	wed_set(dev, MTK_WED_GLO_CFG,
+ 		MTK_WED_GLO_CFG_TX_DMA_EN |
+ 		MTK_WED_GLO_CFG_RX_DMA_EN);
+-	wed_set(dev, MTK_WED_WPDMA_GLO_CFG,
+-		MTK_WED_WPDMA_GLO_CFG_TX_DRV_EN |
+-		MTK_WED_WPDMA_GLO_CFG_RX_DRV_EN);
++
+ 	wed_set(dev, MTK_WED_WDMA_GLO_CFG,
+ 		MTK_WED_WDMA_GLO_CFG_RX_DRV_EN);
+ 
+-	wdma_set(dev, MTK_WDMA_GLO_CFG,
+-		 MTK_WDMA_GLO_CFG_TX_DMA_EN |
+-		 MTK_WDMA_GLO_CFG_RX_INFO1_PRERES |
+-		 MTK_WDMA_GLO_CFG_RX_INFO2_PRERES);
+-
+-	if (dev->hw->version == 1) {
++	if (mtk_wed_is_v1(dev->hw)) {
+ 		wdma_set(dev, MTK_WDMA_GLO_CFG,
+ 			 MTK_WDMA_GLO_CFG_RX_INFO3_PRERES);
+-	} else {
+-		int i;
++		return;
++	}
+ 
+-		wed_set(dev, MTK_WED_WPDMA_CTRL,
+-			MTK_WED_WPDMA_CTRL_SDL1_FIXED);
++	wed_set(dev, MTK_WED_WPDMA_GLO_CFG,
++		MTK_WED_WPDMA_GLO_CFG_RX_DRV_R0_PKT_PROC |
++		MTK_WED_WPDMA_GLO_CFG_RX_DRV_R0_CRX_SYNC);
+ 
+-		wed_set(dev, MTK_WED_WDMA_GLO_CFG,
+-			MTK_WED_WDMA_GLO_CFG_TX_DRV_EN |
+-			MTK_WED_WDMA_GLO_CFG_TX_DDONE_CHK);
++	if (mtk_wed_is_v3_or_greater(dev->hw)) {
++		wed_set(dev, MTK_WED_WDMA_RX_PREF_CFG,
++			FIELD_PREP(MTK_WED_WDMA_RX_PREF_BURST_SIZE, 0x10) |
++			FIELD_PREP(MTK_WED_WDMA_RX_PREF_LOW_THRES, 0x8));
++		wed_clr(dev, MTK_WED_WDMA_RX_PREF_CFG,
++			MTK_WED_WDMA_RX_PREF_DDONE2_EN);
++		wed_set(dev, MTK_WED_WDMA_RX_PREF_CFG, MTK_WED_WDMA_RX_PREF_EN);
+ 
+ 		wed_set(dev, MTK_WED_WPDMA_GLO_CFG,
+-			MTK_WED_WPDMA_GLO_CFG_RX_DRV_R0_PKT_PROC |
+-			MTK_WED_WPDMA_GLO_CFG_RX_DRV_R0_CRX_SYNC);
++			MTK_WED_WPDMA_GLO_CFG_TX_DDONE_CHK_LAST);
++		wed_set(dev, MTK_WED_WPDMA_GLO_CFG,
++			MTK_WED_WPDMA_GLO_CFG_TX_DDONE_CHK |
++			MTK_WED_WPDMA_GLO_CFG_RX_DRV_EVENT_PKT_FMT_CHK |
++			MTK_WED_WPDMA_GLO_CFG_RX_DRV_UNS_VER_FORCE_4);
+ 
+-		wed_clr(dev, MTK_WED_WPDMA_GLO_CFG,
+-			MTK_WED_WPDMA_GLO_CFG_TX_TKID_KEEP |
+-			MTK_WED_WPDMA_GLO_CFG_TX_DMAD_DW3_PREV);
++		wdma_set(dev, MTK_WDMA_PREF_RX_CFG, MTK_WDMA_PREF_RX_CFG_PREF_EN);
++		wdma_set(dev, MTK_WDMA_WRBK_RX_CFG, MTK_WDMA_WRBK_RX_CFG_WRBK_EN);
++	}
+ 
+-		wed_set(dev, MTK_WED_WPDMA_RX_D_GLO_CFG,
+-			MTK_WED_WPDMA_RX_D_RX_DRV_EN |
+-			FIELD_PREP(MTK_WED_WPDMA_RX_D_RXD_READ_LEN, 0x18) |
+-			FIELD_PREP(MTK_WED_WPDMA_RX_D_INIT_PHASE_RXEN_SEL,
+-				   0x2));
++	wed_clr(dev, MTK_WED_WPDMA_GLO_CFG,
++		MTK_WED_WPDMA_GLO_CFG_TX_TKID_KEEP |
++		MTK_WED_WPDMA_GLO_CFG_TX_DMAD_DW3_PREV);
++
++	if (!mtk_wed_get_rx_capa(dev))
++		return;
+ 
+-		for (i = 0; i < MTK_WED_RX_QUEUES; i++)
+-			mtk_wed_check_wfdma_rx_fill(dev, i);
++	wed_set(dev, MTK_WED_WDMA_GLO_CFG,
++		MTK_WED_WDMA_GLO_CFG_TX_DRV_EN |
++		MTK_WED_WDMA_GLO_CFG_TX_DDONE_CHK);
++
++	wed_clr(dev, MTK_WED_WPDMA_RX_D_GLO_CFG, MTK_WED_WPDMA_RX_D_RXD_READ_LEN);
++	wed_set(dev, MTK_WED_WPDMA_RX_D_GLO_CFG,
++		MTK_WED_WPDMA_RX_D_RX_DRV_EN |
++		FIELD_PREP(MTK_WED_WPDMA_RX_D_RXD_READ_LEN, 0x18) |
++		FIELD_PREP(MTK_WED_WPDMA_RX_D_INIT_PHASE_RXEN_SEL, 0x2));
++
++	if (mtk_wed_is_v3_or_greater(dev->hw)) {
++		wed_set(dev, MTK_WED_WPDMA_RX_D_PREF_CFG,
++			MTK_WED_WPDMA_RX_D_PREF_EN |
++			FIELD_PREP(MTK_WED_WPDMA_RX_D_PREF_BURST_SIZE, 0x10) |
++			FIELD_PREP(MTK_WED_WPDMA_RX_D_PREF_LOW_THRES, 0x8));
++
++		wed_set(dev, MTK_WED_RRO_RX_D_CFG(2), MTK_WED_RRO_RX_D_DRV_EN);
++		wdma_set(dev, MTK_WDMA_PREF_TX_CFG, MTK_WDMA_PREF_TX_CFG_PREF_EN);
++		wdma_set(dev, MTK_WDMA_WRBK_TX_CFG, MTK_WDMA_WRBK_TX_CFG_WRBK_EN);
++	}
++
++	for (i = 0; i < MTK_WED_RX_QUEUES; i++) {
++		struct mtk_wed_ring *ring = &dev->rx_ring[i];
++		u32 val;
++
++		if(!(ring->flags & MTK_WED_RING_CONFIGURED))
++			continue;
++
++		if(mtk_wed_check_wfdma_rx_fill(dev, ring)) {
++			dev_err(dev->hw->dev,
++				"mtk_wed%d: rx(%d) dma enable failed!\n",
++				dev->hw->index, i);
++			continue;
++		}
++
++		val = wifi_r32(dev, dev->wlan.wpdma_rx_glo -
++				dev->wlan.phy_base) | MTK_WFMDA_RX_DMA_EN;
++
++		wifi_w32(dev,
++			 dev->wlan.wpdma_rx_glo - dev->wlan.phy_base,
++			 val);
++
++		dev_err(dev->hw->dev,
++			"mtk_wed%d: rx(%d) dma enable successful!\n",
++			dev->hw->index, i);
+ 	}
+ }
+ 
++static void
++mtk_wed_start_hw_rro(struct mtk_wed_device *dev, u32 irq_mask)
++{
++	int i;
++
++	wed_w32(dev, MTK_WED_WPDMA_INT_MASK, irq_mask);
++	wed_w32(dev, MTK_WED_INT_MASK, irq_mask);
++
++	if (!mtk_wed_get_rx_capa(dev) || !dev->wlan.hw_rro)
++		return;
++
++	wed_set(dev, MTK_WED_RRO_RX_D_CFG(2), MTK_WED_RRO_MSDU_PG_DRV_CLR);
++	wed_w32(dev, MTK_WED_RRO_MSDU_PG_RING2_CFG,
++		MTK_WED_RRO_MSDU_PG_DRV_CLR);
++
++	wed_w32(dev, MTK_WED_WPDMA_INT_CTRL_RRO_RX,
++		MTK_WED_WPDMA_INT_CTRL_RRO_RX0_EN |
++		MTK_WED_WPDMA_INT_CTRL_RRO_RX0_CLR |
++		MTK_WED_WPDMA_INT_CTRL_RRO_RX1_EN |
++		MTK_WED_WPDMA_INT_CTRL_RRO_RX1_CLR |
++		FIELD_PREP(MTK_WED_WPDMA_INT_CTRL_RRO_RX0_DONE_TRIG,
++			   dev->wlan.rro_rx_tbit[0]) |
++		FIELD_PREP(MTK_WED_WPDMA_INT_CTRL_RRO_RX1_DONE_TRIG,
++			   dev->wlan.rro_rx_tbit[1]));
++
++	wed_w32(dev, MTK_WED_WPDMA_INT_CTRL_RRO_MSDU_PG,
++		MTK_WED_WPDMA_INT_CTRL_RRO_PG0_EN |
++		MTK_WED_WPDMA_INT_CTRL_RRO_PG0_CLR |
++		MTK_WED_WPDMA_INT_CTRL_RRO_PG1_EN |
++		MTK_WED_WPDMA_INT_CTRL_RRO_PG1_CLR |
++		MTK_WED_WPDMA_INT_CTRL_RRO_PG2_EN |
++		MTK_WED_WPDMA_INT_CTRL_RRO_PG2_CLR |
++		FIELD_PREP(MTK_WED_WPDMA_INT_CTRL_RRO_PG0_DONE_TRIG,
++			   dev->wlan.rx_pg_tbit[0]) |
++		FIELD_PREP(MTK_WED_WPDMA_INT_CTRL_RRO_PG1_DONE_TRIG,
++			   dev->wlan.rx_pg_tbit[1])|
++		FIELD_PREP(MTK_WED_WPDMA_INT_CTRL_RRO_PG2_DONE_TRIG,
++			   dev->wlan.rx_pg_tbit[2]));
++
++	/*
++	 * RRO_MSDU_PG_RING2_CFG1_FLD_DRV_EN should be enabled after
++	 * WM FWDL completed, otherwise RRO_MSDU_PG ring may broken
++	 */
++	wed_set(dev, MTK_WED_RRO_MSDU_PG_RING2_CFG,
++		MTK_WED_RRO_MSDU_PG_DRV_EN);
++
++	for (i = 0; i < MTK_WED_RX_QUEUES; i++) {
++		struct mtk_wed_ring *ring = &dev->rx_rro_ring[i];
++
++		if(!(ring->flags & MTK_WED_RING_CONFIGURED))
++			continue;
++
++		if (mtk_wed_check_wfdma_rx_fill(dev, ring))
++			dev_err(dev->hw->dev,
++				"mtk_wed%d: rx_rro_ring(%d) init failed!\n",
++				dev->hw->index, i);
++	}
++
++	for (i = 0; i < MTK_WED_RX_PAGE_QUEUES; i++){
++		struct mtk_wed_ring *ring = &dev->rx_page_ring[i];
++
++		if(!(ring->flags & MTK_WED_RING_CONFIGURED))
++			continue;
++
++		if (mtk_wed_check_wfdma_rx_fill(dev, ring))
++			dev_err(dev->hw->dev,
++				"mtk_wed%d: rx_page_ring(%d) init failed!\n",
++				dev->hw->index, i);
++	}
++}
++
++static void
++mtk_wed_rro_rx_ring_setup(struct mtk_wed_device *dev, int idx, void __iomem *regs)
++{
++	struct mtk_wed_ring *ring = &dev->rx_rro_ring[idx];
++
++	ring->wpdma = regs;
++
++	wed_w32(dev, MTK_WED_RRO_RX_D_RX(idx) + MTK_WED_RING_OFS_BASE,
++		readl(regs));
++	wed_w32(dev, MTK_WED_RRO_RX_D_RX(idx) + MTK_WED_RING_OFS_COUNT,
++		readl(regs + MTK_WED_RING_OFS_COUNT));
++
++	ring->flags |= MTK_WED_RING_CONFIGURED;
++}
++
++static void
++mtk_wed_msdu_pg_rx_ring_setup(struct mtk_wed_device *dev, int idx, void __iomem *regs)
++{
++	struct mtk_wed_ring *ring = &dev->rx_page_ring[idx];
++
++	ring->wpdma = regs;
++
++	wed_w32(dev, MTK_WED_RRO_MSDU_PG_CTRL0(idx) + MTK_WED_RING_OFS_BASE,
++		readl(regs));
++	wed_w32(dev, MTK_WED_RRO_MSDU_PG_CTRL0(idx) + MTK_WED_RING_OFS_COUNT,
++		readl(regs + MTK_WED_RING_OFS_COUNT));
++
++	ring->flags |= MTK_WED_RING_CONFIGURED;
++}
++
++static int
++mtk_wed_ind_rx_ring_setup(struct mtk_wed_device *dev, void __iomem *regs)
++{
++	struct mtk_wed_ring *ring = &dev->ind_cmd_ring;
++	u32 val = readl(regs + MTK_WED_RING_OFS_COUNT);
++	int i = 0, count = 0;
++
++	ring->wpdma = regs;
++
++	if (readl(regs) & 0xf)
++		pr_info("%s(): address is not 16-byte alignment\n", __func__);
++
++	wed_w32(dev, MTK_WED_IND_CMD_RX_CTRL1 + MTK_WED_RING_OFS_BASE,
++		readl(regs) & 0xfffffff0);
++
++	wed_w32(dev, MTK_WED_IND_CMD_RX_CTRL1 + MTK_WED_RING_OFS_COUNT,
++		readl(regs + MTK_WED_RING_OFS_COUNT));
++
++	/* ack sn cr */
++	wed_w32(dev, MTK_WED_RRO_CFG0, dev->wlan.phy_base +
++		dev->wlan.ind_cmd.ack_sn_addr);
++	wed_w32(dev, MTK_WED_RRO_CFG1,
++		FIELD_PREP(MTK_WED_RRO_CFG1_MAX_WIN_SZ,
++			   dev->wlan.ind_cmd.win_size) |
++		FIELD_PREP(MTK_WED_RRO_CFG1_PARTICL_SE_ID,
++			   dev->wlan.ind_cmd.particular_sid));
++
++	/* particular session addr element */
++	wed_w32(dev, MTK_WED_ADDR_ELEM_CFG0,
++		dev->wlan.ind_cmd.particular_se_phys);
++
++	for (i = 0; i < dev->wlan.ind_cmd.se_group_nums; i++) {
++		wed_w32(dev, MTK_WED_RADDR_ELEM_TBL_WDATA,
++			dev->wlan.ind_cmd.addr_elem_phys[i] >> 4);
++		wed_w32(dev, MTK_WED_ADDR_ELEM_TBL_CFG,
++			MTK_WED_ADDR_ELEM_TBL_WR | (i & 0x7f));
++
++		val = wed_r32(dev, MTK_WED_ADDR_ELEM_TBL_CFG);
++		while (!(val & MTK_WED_ADDR_ELEM_TBL_WR_RDY) && count++ < 100)
++			val = wed_r32(dev, MTK_WED_ADDR_ELEM_TBL_CFG);
++
++		if (count >= 100)
++			dev_err(dev->hw->dev,
++				"mtk_wed%d: write ba session base failed!\n",
++				dev->hw->index);
++	}
++
++	/* pn check init */
++	for (i = 0; i < dev->wlan.ind_cmd.particular_sid; i++) {
++		wed_w32(dev, MTK_WED_PN_CHECK_WDATA_M,
++			MTK_WED_PN_CHECK_IS_FIRST);
++
++		wed_w32(dev, MTK_WED_PN_CHECK_CFG, MTK_WED_PN_CHECK_WR |
++			FIELD_PREP(MTK_WED_PN_CHECK_SE_ID, i));
++
++		count = 0;
++		val = wed_r32(dev, MTK_WED_PN_CHECK_CFG);
++		while (!(val & MTK_WED_PN_CHECK_WR_RDY) && count++ < 100)
++			val = wed_r32(dev, MTK_WED_PN_CHECK_CFG);
++
++		if (count >= 100)
++			dev_err(dev->hw->dev,
++				"mtk_wed%d: session(%d) init failed!\n",
++				dev->hw->index, i);
++	}
++
++	wed_w32(dev, MTK_WED_RX_IND_CMD_CNT0, MTK_WED_RX_IND_CMD_DBG_CNT_EN);
++	wed_set(dev, MTK_WED_CTRL, MTK_WED_CTRL_WED_RX_IND_CMD_EN);
++
++	return 0;
++}
++
+ static void
+ mtk_wed_start(struct mtk_wed_device *dev, u32 irq_mask)
+ {
+@@ -1471,20 +2116,29 @@ mtk_wed_start(struct mtk_wed_device *dev, u32 irq_mask)
+ 		if (!dev->rx_wdma[i].desc)
+ 			mtk_wed_wdma_rx_ring_setup(dev, i, 16, false);
+ 
++	if (dev->wlan.hw_rro) {
++		for (i = 0; i < ARRAY_SIZE(dev->rx_page_ring); i++) {
++			u32 count = MTK_WED_RRO_MSDU_PG_CTRL0(i) +
++				    MTK_WED_RING_OFS_COUNT;
++
++			if (!wed_r32(dev, count))
++				wed_w32(dev, count, 1);
++		}
++	}
+ 
+ 	mtk_wed_hw_init(dev);
+ 	mtk_wed_configure_irq(dev, irq_mask);
+ 
+ 	mtk_wed_set_ext_int(dev, true);
+ 
+-	if (dev->hw->version == 1) {
++	if (mtk_wed_is_v1(dev->hw)) {
+ 		u32 val = dev->wlan.wpdma_phys | MTK_PCIE_MIRROR_MAP_EN |
+ 			  FIELD_PREP(MTK_PCIE_MIRROR_MAP_WED_ID,
+ 				     dev->hw->index);
+ 
+ 		val |= BIT(0) | (BIT(1) * !!dev->hw->index);
+ 		regmap_write(dev->hw->mirror, dev->hw->index * 4, val);
+-	} else {
++	} else if (mtk_wed_get_rx_capa(dev)) {
+ 		/* driver set mid ready and only once */
+ 		wed_w32(dev, MTK_WED_EXT_INT_MASK1,
+ 			MTK_WED_EXT_INT_STATUS_WPDMA_MID_RDY);
+@@ -1494,12 +2148,19 @@ mtk_wed_start(struct mtk_wed_device *dev, u32 irq_mask)
+ 		wed_r32(dev, MTK_WED_EXT_INT_MASK1);
+ 		wed_r32(dev, MTK_WED_EXT_INT_MASK2);
+ 
++		if (mtk_wed_is_v3_or_greater(dev->hw)) {
++			wed_w32(dev, MTK_WED_EXT_INT_MASK3,
++				MTK_WED_EXT_INT_STATUS_WPDMA_MID_RDY);
++			wed_r32(dev, MTK_WED_EXT_INT_MASK3);
++		}
++
+ 		if (mtk_wed_rro_cfg(dev))
+ 			return;
+ 
+ 	}
+ 
+ 	mtk_wed_set_512_support(dev, dev->wlan.wcid_512);
++	mtk_wed_amsdu_init(dev);
+ 
+ 	mtk_wed_dma_enable(dev);
+ 	dev->running = true;
+@@ -1516,9 +2177,7 @@ mtk_wed_attach(struct mtk_wed_device *dev)
+ 	RCU_LOCKDEP_WARN(!rcu_read_lock_held(),
+ 			 "mtk_wed_attach without holding the RCU read lock");
+ 
+-	if ((dev->wlan.bus_type == MTK_WED_BUS_PCIE &&
+-	     pci_domain_nr(dev->wlan.pci_dev->bus) > 1) ||
+-	    !try_module_get(THIS_MODULE))
++	if (!try_module_get(THIS_MODULE))
+ 		return -ENODEV;
+ 
+ 	rcu_read_unlock();
+@@ -1537,11 +2196,13 @@ mtk_wed_attach(struct mtk_wed_device *dev)
+ 				       : &dev->wlan.platform_dev->dev;
+ 	dev_info(device, "attaching wed device %d version %d\n",
+ 		 hw->index, hw->version);
++
+ 	dev->hw = hw;
+ 	dev->dev = hw->dev;
+ 	dev->irq = hw->irq;
+ 	dev->wdma_idx = hw->index;
+ 	dev->version = hw->version;
++	dev->hw->pci_base = mtk_wed_get_pci_base(dev);
+ 
+ 	if (hw->eth->dma_dev == hw->eth->dev &&
+ 	    of_dma_is_coherent(hw->eth->dev->of_node))
+@@ -1551,6 +2212,10 @@ mtk_wed_attach(struct mtk_wed_device *dev)
+ 	if (ret)
+ 		goto out;
+ 
++	ret = mtk_wed_amsdu_buffer_alloc(dev);
++	if (ret)
++		goto out;
++
+ 	if (mtk_wed_get_rx_capa(dev)) {
+ 		ret = mtk_wed_rro_alloc(dev);
+ 		if (ret)
+@@ -1563,13 +2228,14 @@ mtk_wed_attach(struct mtk_wed_device *dev)
+ 	init_completion(&dev->wlan_reset_done);
+ 	atomic_set(&dev->fe_reset, 0);
+ 
+-	if (hw->version == 1) {
++	if (mtk_wed_is_v1(hw))
+ 		regmap_update_bits(hw->hifsys, HIFSYS_DMA_AG_MAP,
+ 				   BIT(hw->index), 0);
+-	} else {
++	else
+ 		dev->rev_id = wed_r32(dev, MTK_WED_REV_ID);
++
++	if (mtk_wed_get_rx_capa(dev))
+ 		ret = mtk_wed_wo_init(hw);
+-	}
+ 
+ out:
+ 	if (ret) {
+@@ -1613,6 +2279,24 @@ mtk_wed_tx_ring_setup(struct mtk_wed_device *dev, int idx,
+ 
+ 	ring->reg_base = MTK_WED_RING_TX(idx);
+ 	ring->wpdma = regs;
++	ring->flags |= MTK_WED_RING_CONFIGURED;
++
++	if (mtk_wed_is_v3_or_greater(dev->hw) && idx == 1) {
++		/* reset prefetch index */
++		wed_set(dev, MTK_WED_WDMA_RX_PREF_CFG,
++		       MTK_WED_WDMA_RX_PREF_RX0_SIDX_CLR |
++		       MTK_WED_WDMA_RX_PREF_RX1_SIDX_CLR);
++
++		wed_clr(dev, MTK_WED_WDMA_RX_PREF_CFG,
++		       MTK_WED_WDMA_RX_PREF_RX0_SIDX_CLR |
++		       MTK_WED_WDMA_RX_PREF_RX1_SIDX_CLR);
++
++		/* reset prefetch FIFO */
++		wed_w32(dev, MTK_WED_WDMA_RX_PREF_FIFO_CFG,
++		       MTK_WED_WDMA_RX_PREF_FIFO_RX0_CLR |
++		       MTK_WED_WDMA_RX_PREF_FIFO_RX1_CLR);
++		wed_w32(dev, MTK_WED_WDMA_RX_PREF_FIFO_CFG, 0);
++	}
+ 
+ 	/* WED -> WPDMA */
+ 	wpdma_tx_w32(dev, idx, MTK_WED_RING_OFS_BASE, ring->desc_phys);
+@@ -1632,7 +2316,7 @@ static int
+ mtk_wed_txfree_ring_setup(struct mtk_wed_device *dev, void __iomem *regs)
+ {
+ 	struct mtk_wed_ring *ring = &dev->txfree_ring;
+-	int i, index = dev->hw->version == 1;
++	int i, index = mtk_wed_is_v1(dev->hw);
+ 
+ 	/*
+ 	 * For txfree event handling, the same DMA ring is shared between WED
+@@ -1692,9 +2376,13 @@ mtk_wed_irq_get(struct mtk_wed_device *dev, u32 mask)
+ 
+ 	val = wed_r32(dev, MTK_WED_EXT_INT_STATUS);
+ 	wed_w32(dev, MTK_WED_EXT_INT_STATUS, val);
+-	val &= MTK_WED_EXT_INT_STATUS_ERROR_MASK;
+-	if (!dev->hw->num_flows)
+-		val &= ~MTK_WED_EXT_INT_STATUS_TKID_WO_PYLD;
++	if (mtk_wed_is_v3_or_greater(dev->hw)) {
++		val &= MTK_WED_EXT_INT_STATUS_RX_DRV_COHERENT;
++	} else {
++		val &= MTK_WED_EXT_INT_STATUS_ERROR_MASK;
++		if (!dev->hw->num_flows)
++			val &= ~MTK_WED_EXT_INT_STATUS_TKID_WO_PYLD;
++	}
+ 	if (val && net_ratelimit())
+ 		pr_err("mtk_wed%d: error status=%08x\n", dev->hw->index, val);
+ 
+@@ -1718,19 +2406,20 @@ mtk_wed_irq_set_mask(struct mtk_wed_device *dev, u32 mask)
+ int mtk_wed_flow_add(int index)
+ {
+ 	struct mtk_wed_hw *hw = hw_list[index];
+-	int ret;
++	int ret = 0;
+ 
+-	if (!hw || !hw->wed_dev)
+-		return -ENODEV;
++	mutex_lock(&hw_lock);
+ 
+-	if (hw->num_flows) {
+-		hw->num_flows++;
+-		return 0;
++	if (!hw || !hw->wed_dev) {
++		ret = -ENODEV;
++		goto out;
+ 	}
+ 
+-	mutex_lock(&hw_lock);
+-	if (!hw->wed_dev) {
+-		ret = -ENODEV;
++	if (!hw->wed_dev->wlan.offload_enable)
++		goto out;
++
++	if (hw->num_flows) {
++		hw->num_flows++;
+ 		goto out;
+ 	}
+ 
+@@ -1749,14 +2438,15 @@ void mtk_wed_flow_remove(int index)
+ {
+ 	struct mtk_wed_hw *hw = hw_list[index];
+ 
+-	if (!hw)
+-		return;
++	mutex_lock(&hw_lock);
+ 
+-	if (--hw->num_flows)
+-		return;
++	if (!hw || !hw->wed_dev)
++		goto out;
+ 
+-	mutex_lock(&hw_lock);
+-	if (!hw->wed_dev)
++	if (!hw->wed_dev->wlan.offload_disable)
++		goto out;
++
++	if (--hw->num_flows)
+ 		goto out;
+ 
+ 	hw->wed_dev->wlan.offload_disable(hw->wed_dev);
+@@ -1799,6 +2489,10 @@ void mtk_wed_add_hw(struct device_node *np, struct mtk_eth *eth,
+ 		.detach = mtk_wed_detach,
+ 		.setup_tc = mtk_wed_eth_setup_tc,
+ 		.ppe_check = mtk_wed_ppe_check,
++		.start_hw_rro = mtk_wed_start_hw_rro,
++		.rro_rx_ring_setup = mtk_wed_rro_rx_ring_setup,
++		.msdu_pg_rx_ring_setup = mtk_wed_msdu_pg_rx_ring_setup,
++		.ind_rx_ring_setup = mtk_wed_ind_rx_ring_setup,
+ 	};
+ 	struct device_node *eth_np = eth->dev->of_node;
+ 	struct platform_device *pdev;
+@@ -1840,14 +2534,22 @@ void mtk_wed_add_hw(struct device_node *np, struct mtk_eth *eth,
+ 	hw->wdma_phy = wdma_phy;
+ 	hw->index = index;
+ 	hw->irq = irq;
+-	hw->version = MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V2) ? 2 : 1;
++	hw->version = MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V3) ?
++		      3 : MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V2) ? 2 : 1;
+ 
+-	if (hw->version == 1) {
++	switch (hw->version) {
++	case 2:
++		hw->soc = &mt7986_data;
++		break;
++	case 3:
++		hw->soc = &mt7988_data;
++		break;
++	default:
++	case 1:
+ 		hw->mirror = syscon_regmap_lookup_by_phandle(eth_np,
+-							     "mediatek,pcie-mirror");
++				"mediatek,pcie-mirror");
+ 		hw->hifsys = syscon_regmap_lookup_by_phandle(eth_np,
+-							     "mediatek,hifsys");
+-
++				"mediatek,hifsys");
+ 		if (IS_ERR(hw->mirror) || IS_ERR(hw->hifsys)) {
+ 			kfree(hw);
+ 			goto unlock;
+@@ -1857,8 +2559,10 @@ void mtk_wed_add_hw(struct device_node *np, struct mtk_eth *eth,
+ 			regmap_write(hw->mirror, 0, 0);
+ 			regmap_write(hw->mirror, 4, 0);
+ 		}
++		hw->soc = &mt7622_data;
++		break;
+ 	}
+-
++		
+ 	mtk_wed_hw_add_debugfs(hw);
+ 
+ 	hw_list[index] = hw;
+diff --git a/drivers/net/ethernet/mediatek/mtk_wed.h b/drivers/net/ethernet/mediatek/mtk_wed.h
+index 2ce1a5b..f5e30ce 100644
+--- a/drivers/net/ethernet/mediatek/mtk_wed.h
++++ b/drivers/net/ethernet/mediatek/mtk_wed.h
+@@ -8,12 +8,18 @@
+ #include <linux/debugfs.h>
+ #include <linux/regmap.h>
+ #include <linux/netdevice.h>
++
++#include "mtk_wed_regs.h"
++
+ #define MTK_PCIE_BASE(n)		(0x1a143000 + (n) * 0x2000)
+ 
+-#define MTK_WED_PKT_SIZE		1900
++#define MTK_WED_PKT_SIZE		1920//1900
+ #define MTK_WED_BUF_SIZE		2048
++#define MTK_WED_PAGE_BUF_SIZE		128
+ #define MTK_WED_BUF_PER_PAGE		(PAGE_SIZE / 2048)
++#define MTK_WED_RX_PAGE_BUF_PER_PAGE	(PAGE_SIZE / 128)
+ #define MTK_WED_RX_RING_SIZE		1536
++#define MTK_WED_RX_PG_BM_CNT		8192
+ 
+ #define MTK_WED_TX_RING_SIZE		2048
+ #define MTK_WED_WDMA_RING_SIZE		512
+@@ -27,12 +33,27 @@
+ #define MTK_WED_RRO_QUE_CNT		8192
+ #define MTK_WED_MIOD_ENTRY_CNT		128
+ 
++#define MTK_WED_TX_BM_DMA_SIZE		65536
++#define MTK_WED_TX_BM_PKT_CNT		32768
++
+ #define MTK_WED_MODULE_ID_WO		1
+ 
+ struct mtk_eth;
+ struct mtk_wed_wo;
+ 
++struct mtk_wed_soc_data {
++	struct {
++		u32 tx_bm_tkid;
++		u32 wpdma_rx_ring0;
++		u32 reset_idx_tx_mask;
++		u32 reset_idx_rx_mask;
++	} regmap;
++	u32 tx_ring_desc_size;
++	u32 wdma_desc_size;
++};
++
+ struct mtk_wed_hw {
++	const struct mtk_wed_soc_data *soc;
+ 	struct device_node *node;
+ 	struct mtk_eth *eth;
+ 	struct regmap *regs;
+@@ -44,12 +65,15 @@ struct mtk_wed_hw {
+ 	struct dentry *debugfs_dir;
+ 	struct mtk_wed_device *wed_dev;
+ 	struct mtk_wed_wo *wed_wo;
++	struct mtk_wed_amsdu *wed_amsdu;
++	u32 pci_base;
+ 	u32 debugfs_reg;
+ 	u32 num_flows;
+ 	u8 version;
+ 	char dirname[5];
+ 	int irq;
+ 	int index;
++	int token_id;
+ };
+ 
+ struct mtk_wdma_info {
+@@ -57,9 +81,41 @@ struct mtk_wdma_info {
+ 	u8 queue;
+ 	u16 wcid;
+ 	u8 bss;
++	u32 usr_info;
++	u8 tid;
++	u8 is_fixedrate;
++	u8 is_prior;
++	u8 is_sp;
++	u8 hf;
++	u8 amsdu;
++};
++
++struct mtk_wed_amsdu {
++	void *txd;
++	dma_addr_t txd_phy;
+ };
+ 
+ #ifdef CONFIG_NET_MEDIATEK_SOC_WED
++static inline bool mtk_wed_is_v1(struct mtk_wed_hw *hw)
++{
++	return hw->version == 1;
++}
++
++static inline bool mtk_wed_is_v2(struct mtk_wed_hw *hw)
++{
++	return hw->version == 2;
++}
++
++static inline bool mtk_wed_is_v3(struct mtk_wed_hw *hw)
++{
++	return hw->version == 3;
++}
++
++static inline bool mtk_wed_is_v3_or_greater(struct mtk_wed_hw *hw)
++{
++	return hw->version > 2;
++}
++
+ static inline void
+ wed_w32(struct mtk_wed_device *dev, u32 reg, u32 val)
+ {
+@@ -154,6 +210,21 @@ wpdma_txfree_w32(struct mtk_wed_device *dev, u32 reg, u32 val)
+ 	writel(val, dev->txfree_ring.wpdma + reg);
+ }
+ 
++static inline u32 mtk_wed_get_pci_base(struct mtk_wed_device *dev)
++{
++	if (!mtk_wed_is_v3_or_greater(dev->hw))
++		return MTK_WED_PCIE_BASE;
++
++	switch (dev->hw->index) {
++	case 1:
++		return MTK_WED_PCIE_BASE1;
++	case 2:
++		return MTK_WED_PCIE_BASE2;
++	default:
++		return MTK_WED_PCIE_BASE0;
++	}
++}
++
+ void mtk_wed_add_hw(struct device_node *np, struct mtk_eth *eth,
+ 		    void __iomem *wdma, phys_addr_t wdma_phy,
+ 		    int index);
+diff --git a/drivers/net/ethernet/mediatek/mtk_wed_debugfs.c b/drivers/net/ethernet/mediatek/mtk_wed_debugfs.c
+index 7d8be99..69fe29b 100644
+--- a/drivers/net/ethernet/mediatek/mtk_wed_debugfs.c
++++ b/drivers/net/ethernet/mediatek/mtk_wed_debugfs.c
+@@ -11,9 +11,11 @@ struct reg_dump {
+ 	u16 offset;
+ 	u8 type;
+ 	u8 base;
++	u32 mask;
+ };
+ 
+ enum {
++	DUMP_TYPE_END,
+ 	DUMP_TYPE_STRING,
+ 	DUMP_TYPE_WED,
+ 	DUMP_TYPE_WDMA,
+@@ -23,8 +25,11 @@ enum {
+ 	DUMP_TYPE_WED_RRO,
+ };
+ 
++#define DUMP_END() { .type = DUMP_TYPE_END }
+ #define DUMP_STR(_str) { _str, 0, DUMP_TYPE_STRING }
+ #define DUMP_REG(_reg, ...) { #_reg, MTK_##_reg, __VA_ARGS__ }
++#define DUMP_REG_MASK(_reg, _mask) { #_mask, MTK_##_reg, DUMP_TYPE_WED, 0, MTK_##_mask }
++
+ #define DUMP_RING(_prefix, _base, ...)				\
+ 	{ _prefix " BASE", _base, __VA_ARGS__ },		\
+ 	{ _prefix " CNT",  _base + 0x4, __VA_ARGS__ },	\
+@@ -32,6 +37,7 @@ enum {
+ 	{ _prefix " DIDX", _base + 0xc, __VA_ARGS__ }
+ 
+ #define DUMP_WED(_reg) DUMP_REG(_reg, DUMP_TYPE_WED)
++#define DUMP_WED_MASK(_reg, _mask) DUMP_REG_MASK(_reg, _mask)
+ #define DUMP_WED_RING(_base) DUMP_RING(#_base, MTK_##_base, DUMP_TYPE_WED)
+ 
+ #define DUMP_WDMA(_reg) DUMP_REG(_reg, DUMP_TYPE_WDMA)
+@@ -52,36 +58,49 @@ print_reg_val(struct seq_file *s, const char *name, u32 val)
+ 
+ static void
+ dump_wed_regs(struct seq_file *s, struct mtk_wed_device *dev,
+-	      const struct reg_dump *regs, int n_regs)
++	      const struct reg_dump **regs)
+ {
+-	const struct reg_dump *cur;
++	const struct reg_dump **cur_o = regs, *cur;
++	bool newline = false;
+ 	u32 val;
+ 
+-	for (cur = regs; cur < &regs[n_regs]; cur++) {
+-		switch (cur->type) {
+-		case DUMP_TYPE_STRING:
+-			seq_printf(s, "%s======== %s:\n",
+-				   cur > regs ? "\n" : "",
+-				   cur->name);
+-			continue;
+-		case DUMP_TYPE_WED:
+-		case DUMP_TYPE_WED_RRO:
+-			val = wed_r32(dev, cur->offset);
+-			break;
+-		case DUMP_TYPE_WDMA:
+-			val = wdma_r32(dev, cur->offset);
+-			break;
+-		case DUMP_TYPE_WPDMA_TX:
+-			val = wpdma_tx_r32(dev, cur->base, cur->offset);
+-			break;
+-		case DUMP_TYPE_WPDMA_TXFREE:
+-			val = wpdma_txfree_r32(dev, cur->offset);
+-			break;
+-		case DUMP_TYPE_WPDMA_RX:
+-			val = wpdma_rx_r32(dev, cur->base, cur->offset);
+-			break;
++	while (*cur_o) {
++		cur = *cur_o;
++
++		while (cur->type != DUMP_TYPE_END) {
++			switch (cur->type) {
++			case DUMP_TYPE_STRING:
++				seq_printf(s, "%s======== %s:\n",
++					   newline ? "\n" : "",
++					   cur->name);
++				newline = true;
++				cur++;
++				continue;
++			case DUMP_TYPE_WED:
++			case DUMP_TYPE_WED_RRO:
++				val = wed_r32(dev, cur->offset);
++				break;
++			case DUMP_TYPE_WDMA:
++				val = wdma_r32(dev, cur->offset);
++				break;
++			case DUMP_TYPE_WPDMA_TX:
++				val = wpdma_tx_r32(dev, cur->base, cur->offset);
++				break;
++			case DUMP_TYPE_WPDMA_TXFREE:
++				val = wpdma_txfree_r32(dev, cur->offset);
++				break;
++			case DUMP_TYPE_WPDMA_RX:
++				val = wpdma_rx_r32(dev, cur->base, cur->offset);
++				break;
++			}
++
++			if (cur->mask)
++				val = (cur->mask & val) >> (ffs(cur->mask) - 1);
++
++			print_reg_val(s, cur->name, val);
++			cur++;
+ 		}
+-		print_reg_val(s, cur->name, val);
++		cur_o++;
+ 	}
+ }
+ 
+@@ -89,7 +108,7 @@ dump_wed_regs(struct seq_file *s, struct mtk_wed_device *dev,
+ static int
+ wed_txinfo_show(struct seq_file *s, void *data)
+ {
+-	static const struct reg_dump regs[] = {
++	static const struct reg_dump regs_common[] = {
+ 		DUMP_STR("WED TX"),
+ 		DUMP_WED(WED_TX_MIB(0)),
+ 		DUMP_WED_RING(WED_RING_TX(0)),
+@@ -128,16 +147,32 @@ wed_txinfo_show(struct seq_file *s, void *data)
+ 		DUMP_WDMA_RING(WDMA_RING_RX(0)),
+ 		DUMP_WDMA_RING(WDMA_RING_RX(1)),
+ 
+-		DUMP_STR("TX FREE"),
++		DUMP_STR("WED TX FREE"),
+ 		DUMP_WED(WED_RX_MIB(0)),
++		DUMP_WED_RING(WED_RING_RX(0)),
++		DUMP_WED(WED_WPDMA_RX_COHERENT_MIB(0)),
++
++		DUMP_WED(WED_RX_MIB(1)),
++		DUMP_WED_RING(WED_RING_RX(1)),
++		DUMP_WED(WED_WPDMA_RX_COHERENT_MIB(1)),
++		DUMP_STR("WED_WPDMA TX FREE"),
++		DUMP_WED_RING(WED_WPDMA_RING_RX(0)),
++		DUMP_WED_RING(WED_WPDMA_RING_RX(1)),
++		DUMP_END(),
++	};
++
++	static const struct reg_dump *regs[] = {
++		&regs_common[0],
++		NULL,
+ 	};
++
+ 	struct mtk_wed_hw *hw = s->private;
+ 	struct mtk_wed_device *dev = hw->wed_dev;
+ 
+ 	if (!dev)
+ 		return 0;
+ 
+-	dump_wed_regs(s, dev, regs, ARRAY_SIZE(regs));
++	dump_wed_regs(s, dev, regs);
+ 
+ 	return 0;
+ }
+@@ -146,7 +181,7 @@ DEFINE_SHOW_ATTRIBUTE(wed_txinfo);
+ static int
+ wed_rxinfo_show(struct seq_file *s, void *data)
+ {
+-	static const struct reg_dump regs[] = {
++	static const struct reg_dump regs_common[] = {
+ 		DUMP_STR("WPDMA RX"),
+ 		DUMP_WPDMA_RX_RING(0),
+ 		DUMP_WPDMA_RX_RING(1),
+@@ -164,7 +199,7 @@ wed_rxinfo_show(struct seq_file *s, void *data)
+ 		DUMP_WED_RING(WED_RING_RX_DATA(0)),
+ 		DUMP_WED_RING(WED_RING_RX_DATA(1)),
+ 
+-		DUMP_STR("WED RRO"),
++		DUMP_STR("WED WO RRO"),
+ 		DUMP_WED_RRO_RING(WED_RROQM_MIOD_CTRL0),
+ 		DUMP_WED(WED_RROQM_MID_MIB),
+ 		DUMP_WED(WED_RROQM_MOD_MIB),
+@@ -175,16 +210,6 @@ wed_rxinfo_show(struct seq_file *s, void *data)
+ 		DUMP_WED(WED_RROQM_FDBK_ANC_MIB),
+ 		DUMP_WED(WED_RROQM_FDBK_ANC2H_MIB),
+ 
+-		DUMP_STR("WED Route QM"),
+-		DUMP_WED(WED_RTQM_R2H_MIB(0)),
+-		DUMP_WED(WED_RTQM_R2Q_MIB(0)),
+-		DUMP_WED(WED_RTQM_Q2H_MIB(0)),
+-		DUMP_WED(WED_RTQM_R2H_MIB(1)),
+-		DUMP_WED(WED_RTQM_R2Q_MIB(1)),
+-		DUMP_WED(WED_RTQM_Q2H_MIB(1)),
+-		DUMP_WED(WED_RTQM_Q2N_MIB),
+-		DUMP_WED(WED_RTQM_Q2B_MIB),
+-		DUMP_WED(WED_RTQM_PFDBK_MIB),
+ 
+ 		DUMP_STR("WED WDMA TX"),
+ 		DUMP_WED(WED_WDMA_TX_MIB),
+@@ -205,15 +230,99 @@ wed_rxinfo_show(struct seq_file *s, void *data)
+ 		DUMP_WED(WED_RX_BM_INTF2),
+ 		DUMP_WED(WED_RX_BM_INTF),
+ 		DUMP_WED(WED_RX_BM_ERR_STS),
++		DUMP_END()
++	};
++
++	static const struct reg_dump regs_v2[] = {
++		DUMP_STR("WED Route QM"),
++		DUMP_WED(WED_RTQM_R2H_MIB(0)),
++		DUMP_WED(WED_RTQM_R2Q_MIB(0)),
++		DUMP_WED(WED_RTQM_Q2H_MIB(0)),
++		DUMP_WED(WED_RTQM_R2H_MIB(1)),
++		DUMP_WED(WED_RTQM_R2Q_MIB(1)),
++		DUMP_WED(WED_RTQM_Q2H_MIB(1)),
++		DUMP_WED(WED_RTQM_Q2N_MIB),
++		DUMP_WED(WED_RTQM_Q2B_MIB),
++		DUMP_WED(WED_RTQM_PFDBK_MIB),
++
++		DUMP_END()
++	};
++
++	static const struct reg_dump regs_v3[] = {
++		DUMP_STR("WED RX RRO DATA"),
++		DUMP_WED_RING(WED_RRO_RX_D_RX(0)),
++		DUMP_WED_RING(WED_RRO_RX_D_RX(1)),
++
++		DUMP_STR("WED RX MSDU PAGE"),
++		DUMP_WED_RING(WED_RRO_MSDU_PG_CTRL0(0)),
++		DUMP_WED_RING(WED_RRO_MSDU_PG_CTRL0(1)),
++		DUMP_WED_RING(WED_RRO_MSDU_PG_CTRL0(2)),
++
++		DUMP_STR("WED RX IND CMD"),
++		DUMP_WED(WED_IND_CMD_RX_CTRL1),
++		DUMP_WED_MASK(WED_IND_CMD_RX_CTRL2, WED_IND_CMD_MAX_CNT),
++		DUMP_WED_MASK(WED_IND_CMD_RX_CTRL0, WED_IND_CMD_PROC_IDX),
++		DUMP_WED_MASK(RRO_IND_CMD_SIGNATURE, RRO_IND_CMD_DMA_IDX),
++		DUMP_WED_MASK(WED_IND_CMD_RX_CTRL0, WED_IND_CMD_MAGIC_CNT),
++		DUMP_WED_MASK(RRO_IND_CMD_SIGNATURE, RRO_IND_CMD_MAGIC_CNT),
++		DUMP_WED_MASK(WED_IND_CMD_RX_CTRL0,
++			      WED_IND_CMD_PREFETCH_FREE_CNT),
++		DUMP_WED_MASK(WED_RRO_CFG1, WED_RRO_CFG1_PARTICL_SE_ID),
++
++		DUMP_STR("WED ADDR ELEM"),
++		DUMP_WED(WED_ADDR_ELEM_CFG0),
++		DUMP_WED_MASK(WED_ADDR_ELEM_CFG1,
++			      WED_ADDR_ELEM_PREFETCH_FREE_CNT),
++
++		DUMP_STR("WED Route QM"),
++		DUMP_WED(WED_RTQM_ENQ_I2Q_DMAD_CNT),
++		DUMP_WED(WED_RTQM_ENQ_I2N_DMAD_CNT),
++		DUMP_WED(WED_RTQM_ENQ_I2Q_PKT_CNT),
++		DUMP_WED(WED_RTQM_ENQ_I2N_PKT_CNT),
++		DUMP_WED(WED_RTQM_ENQ_USED_ENTRY_CNT),
++		DUMP_WED(WED_RTQM_ENQ_ERR_CNT),
++
++		DUMP_WED(WED_RTQM_DEQ_DMAD_CNT),
++		DUMP_WED(WED_RTQM_DEQ_Q2I_DMAD_CNT),
++		DUMP_WED(WED_RTQM_DEQ_PKT_CNT),
++		DUMP_WED(WED_RTQM_DEQ_Q2I_PKT_CNT),
++		DUMP_WED(WED_RTQM_DEQ_USED_PFDBK_CNT),
++		DUMP_WED(WED_RTQM_DEQ_ERR_CNT),
++
++		DUMP_END()
++	};
++
++	static const struct reg_dump *regs_new_v2[] = {
++		&regs_common[0],
++		&regs_v2[0],
++		NULL,
++	};
++
++	static const struct reg_dump *regs_new_v3[] = {
++		&regs_common[0],
++		&regs_v3[0],
++		NULL,
+ 	};
+ 
+ 	struct mtk_wed_hw *hw = s->private;
+ 	struct mtk_wed_device *dev = hw->wed_dev;
++	const struct reg_dump **regs;
+ 
+ 	if (!dev)
+ 		return 0;
+ 
+-	dump_wed_regs(s, dev, regs, ARRAY_SIZE(regs));
++	switch(dev->hw->version) {
++	case 2:
++		regs = regs_new_v2;
++		break;
++	case 3:
++		regs = regs_new_v3;
++		break;
++	default:
++		return 0;
++	}
++
++	dump_wed_regs(s, dev, regs);
+ 
+ 	return 0;
+ }
+@@ -248,6 +357,381 @@ mtk_wed_reg_get(void *data, u64 *val)
+ DEFINE_DEBUGFS_ATTRIBUTE(fops_regval, mtk_wed_reg_get, mtk_wed_reg_set,
+              "0x%08llx\n");
+ 
++static int
++wed_token_txd_show(struct seq_file *s, void *data)
++{
++	struct mtk_wed_hw *hw = s->private;
++	struct mtk_wed_device *dev = hw->wed_dev;
++	struct mtk_wed_buf *page_list = dev->tx_buf_ring.pages;
++	int token = dev->wlan.token_start;
++	u32 val = hw->token_id, size = 1;
++	int page_idx = (val - token) / 2;
++	int i;
++
++	if (val < token) {
++		size = val;
++		page_idx = 0;
++	}
++
++	for (i = 0; i < size; i += MTK_WED_BUF_PER_PAGE) {
++		void *page = page_list[page_idx++].p;
++		void *buf;
++		int j;
++
++		if (!page)
++			break;
++
++		buf = page_to_virt(page);
++
++		for (j = 0; j < MTK_WED_BUF_PER_PAGE; j++) {
++			printk("[TXD]:token id = %d\n", token + 2 * (page_idx - 1) + j);
++			print_hex_dump(KERN_ERR , "", DUMP_PREFIX_OFFSET, 16, 1, (u8 *)buf, 128, false);
++			seq_printf(s, "\n");
++
++			buf += MTK_WED_BUF_SIZE;
++		}
++	}
++
++	return 0;
++}
++
++DEFINE_SHOW_ATTRIBUTE(wed_token_txd);
++
++static int
++wed_amsdu_show(struct seq_file *s, void *data)
++{
++	static const struct reg_dump regs_common[] = {
++		DUMP_STR("WED AMDSU INFO"),
++		DUMP_WED(WED_MON_AMSDU_FIFO_DMAD),
++
++		DUMP_STR("WED AMDSU ENG0 INFO"),
++		DUMP_WED(WED_MON_AMSDU_ENG_DMAD(0)),
++		DUMP_WED(WED_MON_AMSDU_ENG_QFPL(0)),
++		DUMP_WED(WED_MON_AMSDU_ENG_QENI(0)),
++		DUMP_WED(WED_MON_AMSDU_ENG_QENO(0)),
++		DUMP_WED(WED_MON_AMSDU_ENG_MERG(0)),
++		DUMP_WED_MASK(WED_MON_AMSDU_ENG_CNT8(0),
++			      WED_AMSDU_ENG_MAX_PL_CNT),
++		DUMP_WED_MASK(WED_MON_AMSDU_ENG_CNT8(0),
++			      WED_AMSDU_ENG_MAX_QGPP_CNT),
++		DUMP_WED_MASK(WED_MON_AMSDU_ENG_CNT9(0),
++			      WED_AMSDU_ENG_CUR_ENTRY),
++		DUMP_WED_MASK(WED_MON_AMSDU_ENG_CNT9(0),
++			      WED_AMSDU_ENG_MAX_BUF_MERGED),
++		DUMP_WED_MASK(WED_MON_AMSDU_ENG_CNT9(0),
++			      WED_AMSDU_ENG_MAX_MSDU_MERGED),
++
++		DUMP_STR("WED AMDSU ENG1 INFO"),
++		DUMP_WED(WED_MON_AMSDU_ENG_DMAD(1)),
++		DUMP_WED(WED_MON_AMSDU_ENG_QFPL(1)),
++		DUMP_WED(WED_MON_AMSDU_ENG_QENI(1)),
++		DUMP_WED(WED_MON_AMSDU_ENG_QENO(1)),
++		DUMP_WED(WED_MON_AMSDU_ENG_MERG(1)),
++		DUMP_WED_MASK(WED_MON_AMSDU_ENG_CNT8(1),
++			      WED_AMSDU_ENG_MAX_PL_CNT),
++		DUMP_WED_MASK(WED_MON_AMSDU_ENG_CNT8(1),
++			      WED_AMSDU_ENG_MAX_QGPP_CNT),
++		DUMP_WED_MASK(WED_MON_AMSDU_ENG_CNT9(1),
++			      WED_AMSDU_ENG_CUR_ENTRY),
++		DUMP_WED_MASK(WED_MON_AMSDU_ENG_CNT9(2),
++			      WED_AMSDU_ENG_MAX_BUF_MERGED),
++		DUMP_WED_MASK(WED_MON_AMSDU_ENG_CNT9(2),
++			      WED_AMSDU_ENG_MAX_MSDU_MERGED),
++
++		DUMP_STR("WED AMDSU ENG2 INFO"),
++		DUMP_WED(WED_MON_AMSDU_ENG_DMAD(2)),
++		DUMP_WED(WED_MON_AMSDU_ENG_QFPL(2)),
++		DUMP_WED(WED_MON_AMSDU_ENG_QENI(2)),
++		DUMP_WED(WED_MON_AMSDU_ENG_QENO(2)),
++		DUMP_WED(WED_MON_AMSDU_ENG_MERG(2)),
++		DUMP_WED_MASK(WED_MON_AMSDU_ENG_CNT8(2),
++			      WED_AMSDU_ENG_MAX_PL_CNT),
++		DUMP_WED_MASK(WED_MON_AMSDU_ENG_CNT8(2),
++			      WED_AMSDU_ENG_MAX_QGPP_CNT),
++		DUMP_WED_MASK(WED_MON_AMSDU_ENG_CNT9(2),
++			      WED_AMSDU_ENG_CUR_ENTRY),
++		DUMP_WED_MASK(WED_MON_AMSDU_ENG_CNT9(2),
++			      WED_AMSDU_ENG_MAX_BUF_MERGED),
++		DUMP_WED_MASK(WED_MON_AMSDU_ENG_CNT9(2),
++			      WED_AMSDU_ENG_MAX_MSDU_MERGED),
++
++		DUMP_STR("WED AMDSU ENG3 INFO"),
++		DUMP_WED(WED_MON_AMSDU_ENG_DMAD(3)),
++		DUMP_WED(WED_MON_AMSDU_ENG_QFPL(3)),
++		DUMP_WED(WED_MON_AMSDU_ENG_QENI(3)),
++		DUMP_WED(WED_MON_AMSDU_ENG_QENO(3)),
++		DUMP_WED(WED_MON_AMSDU_ENG_MERG(3)),
++		DUMP_WED_MASK(WED_MON_AMSDU_ENG_CNT8(3),
++			      WED_AMSDU_ENG_MAX_PL_CNT),
++		DUMP_WED_MASK(WED_MON_AMSDU_ENG_CNT8(3),
++			      WED_AMSDU_ENG_MAX_QGPP_CNT),
++		DUMP_WED_MASK(WED_MON_AMSDU_ENG_CNT9(3),
++			      WED_AMSDU_ENG_CUR_ENTRY),
++		DUMP_WED_MASK(WED_MON_AMSDU_ENG_CNT9(3),
++			      WED_AMSDU_ENG_MAX_BUF_MERGED),
++		DUMP_WED_MASK(WED_MON_AMSDU_ENG_CNT9(3),
++			      WED_AMSDU_ENG_MAX_MSDU_MERGED),
++
++		DUMP_STR("WED AMDSU ENG4 INFO"),
++		DUMP_WED(WED_MON_AMSDU_ENG_DMAD(4)),
++		DUMP_WED(WED_MON_AMSDU_ENG_QFPL(4)),
++		DUMP_WED(WED_MON_AMSDU_ENG_QENI(4)),
++		DUMP_WED(WED_MON_AMSDU_ENG_QENO(4)),
++		DUMP_WED(WED_MON_AMSDU_ENG_MERG(4)),
++		DUMP_WED_MASK(WED_MON_AMSDU_ENG_CNT8(4),
++			      WED_AMSDU_ENG_MAX_PL_CNT),
++		DUMP_WED_MASK(WED_MON_AMSDU_ENG_CNT8(4),
++			      WED_AMSDU_ENG_MAX_QGPP_CNT),
++		DUMP_WED_MASK(WED_MON_AMSDU_ENG_CNT9(4),
++			      WED_AMSDU_ENG_CUR_ENTRY),
++		DUMP_WED_MASK(WED_MON_AMSDU_ENG_CNT9(4),
++			      WED_AMSDU_ENG_MAX_BUF_MERGED),
++		DUMP_WED_MASK(WED_MON_AMSDU_ENG_CNT9(4),
++			      WED_AMSDU_ENG_MAX_MSDU_MERGED),
++
++		DUMP_STR("WED AMDSU ENG5 INFO"),
++		DUMP_WED(WED_MON_AMSDU_ENG_DMAD(5)),
++		DUMP_WED(WED_MON_AMSDU_ENG_QFPL(5)),
++		DUMP_WED(WED_MON_AMSDU_ENG_QENI(5)),
++		DUMP_WED(WED_MON_AMSDU_ENG_QENO(5)),
++		DUMP_WED(WED_MON_AMSDU_ENG_MERG(5)),
++		DUMP_WED_MASK(WED_MON_AMSDU_ENG_CNT8(5),
++			      WED_AMSDU_ENG_MAX_PL_CNT),
++		DUMP_WED_MASK(WED_MON_AMSDU_ENG_CNT8(5),
++			      WED_AMSDU_ENG_MAX_QGPP_CNT),
++		DUMP_WED_MASK(WED_MON_AMSDU_ENG_CNT9(5),
++			      WED_AMSDU_ENG_CUR_ENTRY),
++		DUMP_WED_MASK(WED_MON_AMSDU_ENG_CNT9(5),
++			      WED_AMSDU_ENG_MAX_BUF_MERGED),
++		DUMP_WED_MASK(WED_MON_AMSDU_ENG_CNT9(5),
++			      WED_AMSDU_ENG_MAX_MSDU_MERGED),
++
++		DUMP_STR("WED AMDSU ENG6 INFO"),
++		DUMP_WED(WED_MON_AMSDU_ENG_DMAD(6)),
++		DUMP_WED(WED_MON_AMSDU_ENG_QFPL(6)),
++		DUMP_WED(WED_MON_AMSDU_ENG_QENI(6)),
++		DUMP_WED(WED_MON_AMSDU_ENG_QENO(6)),
++		DUMP_WED(WED_MON_AMSDU_ENG_MERG(6)),
++		DUMP_WED_MASK(WED_MON_AMSDU_ENG_CNT8(6),
++			      WED_AMSDU_ENG_MAX_PL_CNT),
++		DUMP_WED_MASK(WED_MON_AMSDU_ENG_CNT8(6),
++			      WED_AMSDU_ENG_MAX_QGPP_CNT),
++		DUMP_WED_MASK(WED_MON_AMSDU_ENG_CNT9(6),
++			      WED_AMSDU_ENG_CUR_ENTRY),
++		DUMP_WED_MASK(WED_MON_AMSDU_ENG_CNT9(6),
++			      WED_AMSDU_ENG_MAX_BUF_MERGED),
++		DUMP_WED_MASK(WED_MON_AMSDU_ENG_CNT9(6),
++			      WED_AMSDU_ENG_MAX_MSDU_MERGED),
++
++		DUMP_STR("WED AMDSU ENG7 INFO"),
++		DUMP_WED(WED_MON_AMSDU_ENG_DMAD(7)),
++		DUMP_WED(WED_MON_AMSDU_ENG_QFPL(7)),
++		DUMP_WED(WED_MON_AMSDU_ENG_QENI(7)),
++		DUMP_WED(WED_MON_AMSDU_ENG_QENO(7)),
++		DUMP_WED(WED_MON_AMSDU_ENG_MERG(7)),
++		DUMP_WED_MASK(WED_MON_AMSDU_ENG_CNT8(7),
++			      WED_AMSDU_ENG_MAX_PL_CNT),
++		DUMP_WED_MASK(WED_MON_AMSDU_ENG_CNT8(7),
++			      WED_AMSDU_ENG_MAX_QGPP_CNT),
++		DUMP_WED_MASK(WED_MON_AMSDU_ENG_CNT9(7),
++			      WED_AMSDU_ENG_CUR_ENTRY),
++		DUMP_WED_MASK(WED_MON_AMSDU_ENG_CNT9(7),
++			      WED_AMSDU_ENG_MAX_BUF_MERGED),
++		DUMP_WED_MASK(WED_MON_AMSDU_ENG_CNT9(4),
++			      WED_AMSDU_ENG_MAX_MSDU_MERGED),
++
++		DUMP_STR("WED AMDSU ENG8 INFO"),
++		DUMP_WED(WED_MON_AMSDU_ENG_DMAD(8)),
++		DUMP_WED(WED_MON_AMSDU_ENG_QFPL(8)),
++		DUMP_WED(WED_MON_AMSDU_ENG_QENI(8)),
++		DUMP_WED(WED_MON_AMSDU_ENG_QENO(8)),
++		DUMP_WED(WED_MON_AMSDU_ENG_MERG(8)),
++		DUMP_WED_MASK(WED_MON_AMSDU_ENG_CNT8(8),
++			      WED_AMSDU_ENG_MAX_PL_CNT),
++		DUMP_WED_MASK(WED_MON_AMSDU_ENG_CNT8(8),
++			      WED_AMSDU_ENG_MAX_QGPP_CNT),
++		DUMP_WED_MASK(WED_MON_AMSDU_ENG_CNT9(8),
++			      WED_AMSDU_ENG_CUR_ENTRY),
++		DUMP_WED_MASK(WED_MON_AMSDU_ENG_CNT9(8),
++			      WED_AMSDU_ENG_MAX_BUF_MERGED),
++		DUMP_WED_MASK(WED_MON_AMSDU_ENG_CNT9(8),
++			      WED_AMSDU_ENG_MAX_MSDU_MERGED),
++
++		DUMP_STR("WED QMEM INFO"),
++		DUMP_WED_MASK(WED_MON_AMSDU_QMEM_CNT(0), WED_AMSDU_QMEM_FQ_CNT),
++		DUMP_WED_MASK(WED_MON_AMSDU_QMEM_CNT(0), WED_AMSDU_QMEM_SP_QCNT),
++		DUMP_WED_MASK(WED_MON_AMSDU_QMEM_CNT(1), WED_AMSDU_QMEM_TID0_QCNT),
++		DUMP_WED_MASK(WED_MON_AMSDU_QMEM_CNT(1), WED_AMSDU_QMEM_TID1_QCNT),
++		DUMP_WED_MASK(WED_MON_AMSDU_QMEM_CNT(2), WED_AMSDU_QMEM_TID2_QCNT),
++		DUMP_WED_MASK(WED_MON_AMSDU_QMEM_CNT(2), WED_AMSDU_QMEM_TID3_QCNT),
++		DUMP_WED_MASK(WED_MON_AMSDU_QMEM_CNT(3), WED_AMSDU_QMEM_TID4_QCNT),
++		DUMP_WED_MASK(WED_MON_AMSDU_QMEM_CNT(3), WED_AMSDU_QMEM_TID5_QCNT),
++		DUMP_WED_MASK(WED_MON_AMSDU_QMEM_CNT(4), WED_AMSDU_QMEM_TID6_QCNT),
++		DUMP_WED_MASK(WED_MON_AMSDU_QMEM_CNT(4), WED_AMSDU_QMEM_TID7_QCNT),
++
++		DUMP_STR("WED QMEM HEAD INFO"),
++		DUMP_WED_MASK(WED_MON_AMSDU_QMEM_PTR(0), WED_AMSDU_QMEM_FQ_HEAD),
++		DUMP_WED_MASK(WED_MON_AMSDU_QMEM_PTR(0), WED_AMSDU_QMEM_SP_QHEAD),
++		DUMP_WED_MASK(WED_MON_AMSDU_QMEM_PTR(1), WED_AMSDU_QMEM_TID0_QHEAD),
++		DUMP_WED_MASK(WED_MON_AMSDU_QMEM_PTR(1), WED_AMSDU_QMEM_TID1_QHEAD),
++		DUMP_WED_MASK(WED_MON_AMSDU_QMEM_PTR(2), WED_AMSDU_QMEM_TID2_QHEAD),
++		DUMP_WED_MASK(WED_MON_AMSDU_QMEM_PTR(2), WED_AMSDU_QMEM_TID3_QHEAD),
++		DUMP_WED_MASK(WED_MON_AMSDU_QMEM_PTR(3), WED_AMSDU_QMEM_TID4_QHEAD),
++		DUMP_WED_MASK(WED_MON_AMSDU_QMEM_PTR(3), WED_AMSDU_QMEM_TID5_QHEAD),
++		DUMP_WED_MASK(WED_MON_AMSDU_QMEM_PTR(4), WED_AMSDU_QMEM_TID6_QHEAD),
++		DUMP_WED_MASK(WED_MON_AMSDU_QMEM_PTR(4), WED_AMSDU_QMEM_TID7_QHEAD),
++
++		DUMP_STR("WED QMEM TAIL INFO"),
++		DUMP_WED_MASK(WED_MON_AMSDU_QMEM_PTR(5), WED_AMSDU_QMEM_FQ_TAIL),
++		DUMP_WED_MASK(WED_MON_AMSDU_QMEM_PTR(5), WED_AMSDU_QMEM_SP_QTAIL),
++		DUMP_WED_MASK(WED_MON_AMSDU_QMEM_PTR(6), WED_AMSDU_QMEM_TID0_QTAIL),
++		DUMP_WED_MASK(WED_MON_AMSDU_QMEM_PTR(6), WED_AMSDU_QMEM_TID1_QTAIL),
++		DUMP_WED_MASK(WED_MON_AMSDU_QMEM_PTR(7), WED_AMSDU_QMEM_TID2_QTAIL),
++		DUMP_WED_MASK(WED_MON_AMSDU_QMEM_PTR(7), WED_AMSDU_QMEM_TID3_QTAIL),
++		DUMP_WED_MASK(WED_MON_AMSDU_QMEM_PTR(8), WED_AMSDU_QMEM_TID4_QTAIL),
++		DUMP_WED_MASK(WED_MON_AMSDU_QMEM_PTR(8), WED_AMSDU_QMEM_TID5_QTAIL),
++		DUMP_WED_MASK(WED_MON_AMSDU_QMEM_PTR(9), WED_AMSDU_QMEM_TID6_QTAIL),
++		DUMP_WED_MASK(WED_MON_AMSDU_QMEM_PTR(9), WED_AMSDU_QMEM_TID7_QTAIL),
++
++		DUMP_STR("WED HIFTXD MSDU INFO"),
++		DUMP_WED(WED_MON_AMSDU_HIFTXD_FETCH_MSDU(1)),
++		DUMP_WED(WED_MON_AMSDU_HIFTXD_FETCH_MSDU(2)),
++		DUMP_WED(WED_MON_AMSDU_HIFTXD_FETCH_MSDU(3)),
++		DUMP_WED(WED_MON_AMSDU_HIFTXD_FETCH_MSDU(4)),
++		DUMP_WED(WED_MON_AMSDU_HIFTXD_FETCH_MSDU(5)),
++		DUMP_WED(WED_MON_AMSDU_HIFTXD_FETCH_MSDU(6)),
++		DUMP_WED(WED_MON_AMSDU_HIFTXD_FETCH_MSDU(7)),
++		DUMP_WED(WED_MON_AMSDU_HIFTXD_FETCH_MSDU(8)),
++		DUMP_WED(WED_MON_AMSDU_HIFTXD_FETCH_MSDU(9)),
++		DUMP_WED(WED_MON_AMSDU_HIFTXD_FETCH_MSDU(10)),
++		DUMP_WED(WED_MON_AMSDU_HIFTXD_FETCH_MSDU(11)),
++		DUMP_WED(WED_MON_AMSDU_HIFTXD_FETCH_MSDU(12)),
++		DUMP_WED(WED_MON_AMSDU_HIFTXD_FETCH_MSDU(13)),
++	};
++
++	static const struct reg_dump *regs[] = {
++		&regs_common[0],
++		NULL,
++	};
++	struct mtk_wed_hw *hw = s->private;
++	struct mtk_wed_device *dev = hw->wed_dev;
++
++	if (!dev)
++		return 0;
++
++	dump_wed_regs(s, dev, regs);
++
++	return 0;
++}
++DEFINE_SHOW_ATTRIBUTE(wed_amsdu);
++
++static int
++wed_rtqm_show(struct seq_file *s, void *data)
++{
++	static const struct reg_dump regs_common[] = {
++		DUMP_STR("WED Route QM IGRS0(N2H + Recycle)"),
++		DUMP_WED(WED_RTQM_IGRS0_I2HW_DMAD_CNT),
++		DUMP_WED(WED_RTQM_IGRS0_I2H_DMAD_CNT(0)),
++		DUMP_WED(WED_RTQM_IGRS0_I2H_DMAD_CNT(1)),
++		DUMP_WED(WED_RTQM_IGRS0_I2HW_PKT_CNT),
++		DUMP_WED(WED_RTQM_IGRS0_I2H_PKT_CNT(0)),
++		DUMP_WED(WED_RTQM_IGRS0_I2H_PKT_CNT(0)),
++		DUMP_WED(WED_RTQM_IGRS0_FDROP_CNT),
++
++
++		DUMP_STR("WED Route QM IGRS1(Legacy)"),
++		DUMP_WED(WED_RTQM_IGRS1_I2HW_DMAD_CNT),
++		DUMP_WED(WED_RTQM_IGRS1_I2H_DMAD_CNT(0)),
++		DUMP_WED(WED_RTQM_IGRS1_I2H_DMAD_CNT(1)),
++		DUMP_WED(WED_RTQM_IGRS1_I2HW_PKT_CNT),
++		DUMP_WED(WED_RTQM_IGRS1_I2H_PKT_CNT(0)),
++		DUMP_WED(WED_RTQM_IGRS1_I2H_PKT_CNT(1)),
++		DUMP_WED(WED_RTQM_IGRS1_FDROP_CNT),
++
++		DUMP_STR("WED Route QM IGRS2(RRO3.0)"),
++		DUMP_WED(WED_RTQM_IGRS2_I2HW_DMAD_CNT),
++		DUMP_WED(WED_RTQM_IGRS2_I2H_DMAD_CNT(0)),
++		DUMP_WED(WED_RTQM_IGRS2_I2H_DMAD_CNT(1)),
++		DUMP_WED(WED_RTQM_IGRS2_I2HW_PKT_CNT),
++		DUMP_WED(WED_RTQM_IGRS2_I2H_PKT_CNT(0)),
++		DUMP_WED(WED_RTQM_IGRS2_I2H_PKT_CNT(1)),
++		DUMP_WED(WED_RTQM_IGRS2_FDROP_CNT),
++
++		DUMP_STR("WED Route QM IGRS3(DEBUG)"),
++		DUMP_WED(WED_RTQM_IGRS2_I2HW_DMAD_CNT),
++		DUMP_WED(WED_RTQM_IGRS3_I2H_DMAD_CNT(0)),
++		DUMP_WED(WED_RTQM_IGRS3_I2H_DMAD_CNT(1)),
++		DUMP_WED(WED_RTQM_IGRS3_I2HW_PKT_CNT),
++		DUMP_WED(WED_RTQM_IGRS3_I2H_PKT_CNT(0)),
++		DUMP_WED(WED_RTQM_IGRS3_I2H_PKT_CNT(1)),
++		DUMP_WED(WED_RTQM_IGRS3_FDROP_CNT),
++
++		DUMP_END()
++	};
++
++	static const struct reg_dump *regs[] = {
++		&regs_common[0],
++		NULL,
++	};
++	struct mtk_wed_hw *hw = s->private;
++	struct mtk_wed_device *dev = hw->wed_dev;
++
++	if (!dev)
++		return 0;
++
++	dump_wed_regs(s, dev, regs);
++
++	return 0;
++}
++DEFINE_SHOW_ATTRIBUTE(wed_rtqm);
++
++
++static int
++wed_rro_show(struct seq_file *s, void *data)
++{
++	static const struct reg_dump regs_common[] = {
++		DUMP_STR("RRO/IND CMD CNT"),
++		DUMP_WED(WED_RX_IND_CMD_CNT(1)),
++		DUMP_WED(WED_RX_IND_CMD_CNT(2)),
++		DUMP_WED(WED_RX_IND_CMD_CNT(3)),
++		DUMP_WED(WED_RX_IND_CMD_CNT(4)),
++		DUMP_WED(WED_RX_IND_CMD_CNT(5)),
++		DUMP_WED(WED_RX_IND_CMD_CNT(6)),
++		DUMP_WED(WED_RX_IND_CMD_CNT(7)),
++		DUMP_WED(WED_RX_IND_CMD_CNT(8)),
++		DUMP_WED_MASK(WED_RX_IND_CMD_CNT(9),
++			      WED_IND_CMD_MAGIC_CNT_FAIL_CNT),
++
++		DUMP_WED(WED_RX_ADDR_ELEM_CNT(0)),
++		DUMP_WED_MASK(WED_RX_ADDR_ELEM_CNT(1),
++			      WED_ADDR_ELEM_SIG_FAIL_CNT),
++		DUMP_WED(WED_RX_MSDU_PG_CNT(1)),
++		DUMP_WED(WED_RX_MSDU_PG_CNT(2)),
++		DUMP_WED(WED_RX_MSDU_PG_CNT(3)),
++		DUMP_WED(WED_RX_MSDU_PG_CNT(4)),
++		DUMP_WED(WED_RX_MSDU_PG_CNT(5)),
++		DUMP_WED_MASK(WED_RX_PN_CHK_CNT,
++			      WED_PN_CHK_FAIL_CNT),
++
++		DUMP_END()
++	};
++
++	static const struct reg_dump *regs[] = {
++		&regs_common[0],
++		NULL,
++	};
++	struct mtk_wed_hw *hw = s->private;
++	struct mtk_wed_device *dev = hw->wed_dev;
++
++	if (!dev)
++		return 0;
++
++	dump_wed_regs(s, dev, regs);
++
++	return 0;
++}
++DEFINE_SHOW_ATTRIBUTE(wed_rro);
++
+ void mtk_wed_hw_add_debugfs(struct mtk_wed_hw *hw)
+ {
+ 	struct dentry *dir;
+@@ -261,8 +745,20 @@ void mtk_wed_hw_add_debugfs(struct mtk_wed_hw *hw)
+ 	debugfs_create_u32("regidx", 0600, dir, &hw->debugfs_reg);
+ 	debugfs_create_file_unsafe("regval", 0600, dir, hw, &fops_regval);
+ 	debugfs_create_file_unsafe("txinfo", 0400, dir, hw, &wed_txinfo_fops);
+-	debugfs_create_file_unsafe("rxinfo", 0400, dir, hw, &wed_rxinfo_fops);
+-	if (hw->version != 1) {
++	debugfs_create_u32("token_id", 0600, dir, &hw->token_id);
++	debugfs_create_file_unsafe("token_txd", 0600, dir, hw, &wed_token_txd_fops);
++
++	if (!mtk_wed_is_v1(hw)) {
++		debugfs_create_file_unsafe("rxinfo", 0400, dir, hw,
++					   &wed_rxinfo_fops);
+ 		wed_wo_mcu_debugfs(hw, dir);
++		if (mtk_wed_is_v3_or_greater(hw)) {
++			debugfs_create_file_unsafe("amsdu", 0400, dir, hw,
++						   &wed_amsdu_fops);
++			debugfs_create_file_unsafe("rtqm", 0400, dir, hw,
++						   &wed_rtqm_fops);
++			debugfs_create_file_unsafe("rro", 0400, dir, hw,
++						   &wed_rro_fops);
++		}
+ 	}
+ }
+diff --git a/drivers/net/ethernet/mediatek/mtk_wed_mcu.c b/drivers/net/ethernet/mediatek/mtk_wed_mcu.c
+index be63406..18d1fb1 100644
+--- a/drivers/net/ethernet/mediatek/mtk_wed_mcu.c
++++ b/drivers/net/ethernet/mediatek/mtk_wed_mcu.c
+@@ -91,7 +91,7 @@ mtk_wed_mcu_msg_update(struct mtk_wed_device *dev, int id, void *data, int len)
+ {
+ 	struct mtk_wed_wo *wo = dev->hw->wed_wo;
+ 
+-	if (dev->hw->version == 1)
++	if (!mtk_wed_get_rx_capa(dev))
+ 		return 0;
+ 
+ 	if (WARN_ON(!wo))
+@@ -248,7 +248,7 @@ mtk_wed_load_firmware(struct mtk_wed_wo *wo)
+ 		u8 reserved1[15];
+ 	} __packed *region;
+ 
+-	char *mcu;
++	char *fw_name;
+ 	const struct mtk_wed_fw_trailer *hdr;
+ 	static u8 shared[MAX_REGION_SIZE] = {0};
+ 	const struct firmware *fw;
+@@ -256,13 +256,24 @@ mtk_wed_load_firmware(struct mtk_wed_wo *wo)
+ 	u32 ofs = 0;
+ 	u32 boot_cr, val;
+ 
+-	if (of_device_is_compatible(wo->hw->node, "mediatek,mt7981-wed"))
+-		mcu = MT7981_FIRMWARE_WO;
+-	else
+-		mcu = wo->hw->index ? MT7986_FIRMWARE_WO_2 :
+-				      MT7986_FIRMWARE_WO_1;
++	switch (wo->hw->version) {
++	case 2:
++		if (of_device_is_compatible(wo->hw->node,
++					    "mediatek,mt7981-wed"))
++			fw_name = MT7981_FIRMWARE_WO;
++		else
++			fw_name = wo->hw->index ? MT7986_FIRMWARE_WO1
++						: MT7986_FIRMWARE_WO0;
++		break;
++	case 3:
++		fw_name = wo->hw->index ? MT7988_FIRMWARE_WO1
++					: MT7988_FIRMWARE_WO0;
++		break;
++	default:
++		return -EINVAL;
++	}
+ 
+-	ret = request_firmware(&fw, mcu, wo->hw->dev);
++	ret = request_firmware(&fw, fw_name, wo->hw->dev);
+ 	if (ret)
+ 		return ret;
+ 
+@@ -307,8 +318,11 @@ mtk_wed_load_firmware(struct mtk_wed_wo *wo)
+ 	}
+ 
+ 	/* write the start address */
+-	boot_cr = wo->hw->index ?
+-		WOX_MCU_CFG_LS_WA_BOOT_ADDR_ADDR : WOX_MCU_CFG_LS_WM_BOOT_ADDR_ADDR;
++	if (!mtk_wed_is_v3_or_greater(wo->hw) && wo->hw->index)
++		boot_cr = WOX_MCU_CFG_LS_WA_BOOT_ADDR_ADDR;
++	else
++		boot_cr = WOX_MCU_CFG_LS_WM_BOOT_ADDR_ADDR;
++
+ 	wo_w32(wo, boot_cr, (wo->region[WO_REGION_EMI].addr_pa >> 16));
+ 
+ 	/* wo firmware reset */
+@@ -316,8 +330,10 @@ mtk_wed_load_firmware(struct mtk_wed_wo *wo)
+ 
+ 	val = wo_r32(wo, WOX_MCU_CFG_LS_WF_MCU_CFG_WM_WA_ADDR);
+ 
+-	val |= wo->hw->index ? WOX_MCU_CFG_LS_WF_MCU_CFG_WM_WA_WA_CPU_RSTB_MASK :
+-		WOX_MCU_CFG_LS_WF_MCU_CFG_WM_WA_WM_CPU_RSTB_MASK;
++	if (!mtk_wed_is_v3_or_greater(wo->hw) && wo->hw->index)
++		val |= WOX_MCU_CFG_LS_WF_MCU_CFG_WM_WA_WA_CPU_RSTB_MASK;
++	else
++		val |= WOX_MCU_CFG_LS_WF_MCU_CFG_WM_WA_WM_CPU_RSTB_MASK;
+ 
+ 	wo_w32(wo, WOX_MCU_CFG_LS_WF_MCU_CFG_WM_WA_ADDR, val);
+ 
+diff --git a/drivers/net/ethernet/mediatek/mtk_wed_mcu.h b/drivers/net/ethernet/mediatek/mtk_wed_mcu.h
+index dbb17ae..6d4c9a7 100644
+--- a/drivers/net/ethernet/mediatek/mtk_wed_mcu.h
++++ b/drivers/net/ethernet/mediatek/mtk_wed_mcu.h
+@@ -17,8 +17,11 @@
+ #define WARP_ALREADY_DONE_STATUS (1)
+ 
+ #define MT7981_FIRMWARE_WO		"mediatek/mt7981_wo.bin"
+-#define MT7986_FIRMWARE_WO_1		"mediatek/mt7986_wo_0.bin"
+-#define MT7986_FIRMWARE_WO_2		"mediatek/mt7986_wo_1.bin"
++#define MT7986_FIRMWARE_WO0		"mediatek/mt7986_wo_0.bin"
++#define MT7986_FIRMWARE_WO1		"mediatek/mt7986_wo_1.bin"
++#define MT7988_FIRMWARE_WO0		"mediatek/mtk_wo_0.bin"
++#define MT7988_FIRMWARE_WO1		"mediatek/mtk_wo_1.bin"
++#define MT7988_FIRMWARE_WO2		"mediatek/mtk_wo_2.bin"
+ 
+ #define WOCPU_EMI_DEV_NODE		"mediatek,wocpu_emi"
+ #define WOCPU_ILM_DEV_NODE		"mediatek,wocpu_ilm"
+diff --git a/drivers/net/ethernet/mediatek/mtk_wed_regs.h b/drivers/net/ethernet/mediatek/mtk_wed_regs.h
+index 645b8b1..0af264d 100644
+--- a/drivers/net/ethernet/mediatek/mtk_wed_regs.h
++++ b/drivers/net/ethernet/mediatek/mtk_wed_regs.h
+@@ -14,6 +14,9 @@
+ #define MTK_WDMA_DESC_CTRL_DMA_DONE		BIT(31)
+ #define MTK_WED_RX_BM_TOKEN			GENMASK(31, 16)
+ 
++#define MTK_WDMA_TXD0_DESC_INFO_DMA_DONE	BIT(29)
++#define MTK_WDMA_TXD1_DESC_INFO_DMA_DONE	BIT(31)
++
+ struct mtk_wdma_desc {
+ 	__le32 buf0;
+ 	__le32 ctrl;
+@@ -45,6 +48,7 @@ struct mtk_wdma_desc {
+ #define MTK_WED_RESET_WDMA_INT_AGENT			BIT(19)
+ #define MTK_WED_RESET_RX_RRO_QM				BIT(20)
+ #define MTK_WED_RESET_RX_ROUTE_QM			BIT(21)
++#define MTK_WED_RESET_TX_AMSDU				BIT(22)
+ #define MTK_WED_RESET_WED				BIT(31)
+ 
+ #define MTK_WED_CTRL					0x00c
+@@ -52,6 +56,9 @@ struct mtk_wdma_desc {
+ #define MTK_WED_CTRL_WPDMA_INT_AGENT_BUSY		BIT(1)
+ #define MTK_WED_CTRL_WDMA_INT_AGENT_EN			BIT(2)
+ #define MTK_WED_CTRL_WDMA_INT_AGENT_BUSY		BIT(3)
++#define MTK_WED_CTRL_WED_RX_IND_CMD_EN			BIT(5)
++#define MTK_WED_CTRL_WED_RX_PG_BM_EN			BIT(6)
++#define MTK_WED_CTRL_WED_RX_PG_BM_BUSU			BIT(7)
+ #define MTK_WED_CTRL_WED_TX_BM_EN			BIT(8)
+ #define MTK_WED_CTRL_WED_TX_BM_BUSY			BIT(9)
+ #define MTK_WED_CTRL_WED_TX_FREE_AGENT_EN		BIT(10)
+@@ -62,9 +69,14 @@ struct mtk_wdma_desc {
+ #define MTK_WED_CTRL_RX_RRO_QM_BUSY			BIT(15)
+ #define MTK_WED_CTRL_RX_ROUTE_QM_EN			BIT(16)
+ #define MTK_WED_CTRL_RX_ROUTE_QM_BUSY			BIT(17)
++#define MTK_WED_CTRL_TX_TKID_ALI_EN			BIT(20)
++#define MTK_WED_CTRL_TX_TKID_ALI_BUSY			BIT(21)
++#define MTK_WED_CTRL_TX_AMSDU_EN			BIT(22)
++#define MTK_WED_CTRL_TX_AMSDU_BUSY			BIT(23)
+ #define MTK_WED_CTRL_FINAL_DIDX_READ			BIT(24)
+ #define MTK_WED_CTRL_ETH_DMAD_FMT			BIT(25)
+ #define MTK_WED_CTRL_MIB_READ_CLEAR			BIT(28)
++#define MTK_WED_CTRL_FLD_MIB_RD_CLR			BIT(28)
+ 
+ #define MTK_WED_EXT_INT_STATUS				0x020
+ #define MTK_WED_EXT_INT_STATUS_TF_LEN_ERR		BIT(0)
+@@ -72,12 +84,10 @@ struct mtk_wdma_desc {
+ #define MTK_WED_EXT_INT_STATUS_TKID_TITO_INVALID	BIT(4)
+ #define MTK_WED_EXT_INT_STATUS_TX_FBUF_LO_TH		BIT(8)
+ #define MTK_WED_EXT_INT_STATUS_TX_FBUF_HI_TH		BIT(9)
+-#if defined(CONFIG_MEDIATEK_NETSYS_V2)
+-#define MTK_WED_EXT_INT_STATUS_TX_TKID_LO_TH		BIT(10)
+-#define MTK_WED_EXT_INT_STATUS_TX_TKID_HI_TH		BIT(11)
+-#endif
+-#define MTK_WED_EXT_INT_STATUS_RX_FREE_AT_EMPTY		BIT(12)
+-#define MTK_WED_EXT_INT_STATUS_RX_FBUF_DMAD_ER		BIT(13)
++#define MTK_WED_EXT_INT_STATUS_RX_FBUF_LO_TH2		BIT(10)
++#define MTK_WED_EXT_INT_STATUS_RX_FBUF_HI_TH2		BIT(11)
++#define MTK_WED_EXT_INT_STATUS_RX_FBUF_LO_TH		BIT(12)
++#define MTK_WED_EXT_INT_STATUS_RX_FBUF_HI_TH		BIT(13)
+ #define MTK_WED_EXT_INT_STATUS_RX_DRV_R_RESP_ERR	BIT(16)
+ #define MTK_WED_EXT_INT_STATUS_RX_DRV_W_RESP_ERR	BIT(17)
+ #define MTK_WED_EXT_INT_STATUS_RX_DRV_COHERENT		BIT(18)
+@@ -94,17 +104,15 @@ struct mtk_wdma_desc {
+ #define MTK_WED_EXT_INT_STATUS_ERROR_MASK		(MTK_WED_EXT_INT_STATUS_TF_LEN_ERR | \
+ 							 MTK_WED_EXT_INT_STATUS_TKID_WO_PYLD | \
+ 							 MTK_WED_EXT_INT_STATUS_TKID_TITO_INVALID | \
+-							 MTK_WED_EXT_INT_STATUS_RX_FREE_AT_EMPTY | \
+-							 MTK_WED_EXT_INT_STATUS_RX_FBUF_DMAD_ER | \
+ 							 MTK_WED_EXT_INT_STATUS_RX_DRV_R_RESP_ERR | \
+ 							 MTK_WED_EXT_INT_STATUS_RX_DRV_W_RESP_ERR | \
+ 							 MTK_WED_EXT_INT_STATUS_RX_DRV_INIT_WDMA_EN | \
+-							 MTK_WED_EXT_INT_STATUS_TX_DMA_R_RESP_ERR | \
+-							 MTK_WED_EXT_INT_STATUS_TX_DMA_W_RESP_ERR)
++							 MTK_WED_EXT_INT_STATUS_TX_DMA_R_RESP_ERR)
+ 
+ #define MTK_WED_EXT_INT_MASK				0x028
+ #define MTK_WED_EXT_INT_MASK1				0x02c
+ #define MTK_WED_EXT_INT_MASK2				0x030
++#define MTK_WED_EXT_INT_MASK3				0x034
+ 
+ #define MTK_WED_STATUS					0x060
+ #define MTK_WED_STATUS_TX				GENMASK(15, 8)
+@@ -112,12 +120,15 @@ struct mtk_wdma_desc {
+ #define MTK_WED_TX_BM_CTRL				0x080
+ #define MTK_WED_TX_BM_CTRL_VLD_GRP_NUM			GENMASK(6, 0)
+ #define MTK_WED_TX_BM_CTRL_RSV_GRP_NUM			GENMASK(22, 16)
++#define MTK_WED_TX_BM_CTRL_LEGACY_EN			BIT(26)
++#define MTK_WED_TX_TKID_CTRL_FREE_FORMAT		BIT(27)
+ #define MTK_WED_TX_BM_CTRL_PAUSE			BIT(28)
+ 
+ #define MTK_WED_TX_BM_BASE				0x084
++#define MTK_WED_TX_BM_INIT_PTR				0x088
++#define MTK_WED_TX_BM_SW_TAIL_IDX			GENMASK(16, 0)
++#define MTK_WED_TX_BM_INIT_SW_TAIL_IDX			BIT(16)
+ 
+-#define MTK_WED_TX_BM_TKID				0x088
+-#define MTK_WED_TX_BM_TKID_V2				0x0c8
+ #define MTK_WED_TX_BM_TKID_START			GENMASK(15, 0)
+ #define MTK_WED_TX_BM_TKID_END				GENMASK(31, 16)
+ 
+@@ -140,6 +151,9 @@ struct mtk_wdma_desc {
+ #define MTK_WED_TX_TKID_CTRL_RSV_GRP_NUM		GENMASK(22, 16)
+ #define MTK_WED_TX_TKID_CTRL_PAUSE			BIT(28)
+ 
++#define MTK_WED_TX_TKID_CTRL_VLD_GRP_NUM_V3		GENMASK(7, 0)
++#define MTK_WED_TX_TKID_CTRL_RSV_GRP_NUM_V3		GENMASK(23, 16)
++
+ #define MTK_WED_TX_TKID_DYN_THR				0x0e0
+ #define MTK_WED_TX_TKID_DYN_THR_LO			GENMASK(6, 0)
+ #define MTK_WED_TX_TKID_DYN_THR_HI			GENMASK(22, 16)
+@@ -205,12 +219,15 @@ struct mtk_wdma_desc {
+ #define MTK_WED_WPDMA_GLO_CFG_RX_DRV_R1_PKT_PROC	BIT(5)
+ #define MTK_WED_WPDMA_GLO_CFG_RX_DRV_R0_CRX_SYNC	BIT(6)
+ #define MTK_WED_WPDMA_GLO_CFG_RX_DRV_R1_CRX_SYNC	BIT(7)
+-#define MTK_WED_WPDMA_GLO_CFG_RX_DRV_EVENT_PKT_FMT_VER	GENMASK(18, 16)
++#define MTK_WED_WPDMA_GLO_CFG_RX_DRV_EVENT_PKT_FMT_VER	GENMASK(15, 12)
++#define MTK_WED_WPDMA_GLO_CFG_RX_DRV_UNS_VER_FORCE_4	BIT(18)
+ #define MTK_WED_WPDMA_GLO_CFG_RX_DRV_UNSUPPORT_FMT	BIT(19)
+-#define MTK_WED_WPDMA_GLO_CFG_RX_DRV_UEVENT_PKT_FMT_CHK BIT(20)
++#define MTK_WED_WPDMA_GLO_CFG_RX_DRV_EVENT_PKT_FMT_CHK	BIT(20)
+ #define MTK_WED_WPDMA_GLO_CFG_RX_DDONE2_WR		BIT(21)
+ #define MTK_WED_WPDMA_GLO_CFG_TX_TKID_KEEP		BIT(24)
++#define MTK_WED_WPDMA_GLO_CFG_TX_DDONE_CHK_LAST		BIT(25)
+ #define MTK_WED_WPDMA_GLO_CFG_TX_DMAD_DW3_PREV		BIT(28)
++#define MTK_WED_WPDMA_GLO_CFG_TX_DDONE_CHK		BIT(30)
+ 
+ /* CONFIG_MEDIATEK_NETSYS_V1 */
+ #define MTK_WED_WPDMA_GLO_CFG_RX_BT_SIZE		GENMASK(5, 4)
+@@ -273,9 +290,11 @@ struct mtk_wdma_desc {
+ #define MTK_WED_PCIE_INT_TRIGGER_STATUS			BIT(16)
+ 
+ #define MTK_WED_PCIE_INT_CTRL				0x57c
+-#define MTK_WED_PCIE_INT_CTRL_MSK_EN_POLA		BIT(20)
++#define MTK_WED_PCIE_INT_CTRL_POLL_EN			GENMASK(13, 12)
+ #define MTK_WED_PCIE_INT_CTRL_SRC_SEL			GENMASK(17, 16)
+-#define MTK_WED_PCIE_INT_CTRL_POLL_EN 			GENMASK(13, 12)
++#define MTK_WED_PCIE_INT_CTRL_MSK_EN_POLA		BIT(20)
++#define MTK_WED_PCIE_INT_CTRL_MSK_IRQ_FILTER		BIT(21)
++
+ #define MTK_WED_WPDMA_CFG_BASE				0x580
+ #define MTK_WED_WPDMA_CFG_INT_MASK			0x584
+ #define MTK_WED_WPDMA_CFG_TX				0x588
+@@ -304,20 +323,50 @@ struct mtk_wdma_desc {
+ #define MTK_WED_WPDMA_RX_D_RST_DRV_IDX			GENMASK(25, 24)
+ 
+ #define MTK_WED_WPDMA_RX_GLO_CFG			0x76c
+-#define MTK_WED_WPDMA_RX_RING				0x770
++#if defined(CONFIG_MEDIATEK_NETSYS_V2)
++#define MTK_WED_WPDMA_RX_RING0				0x770
++#else
++#define MTK_WED_WPDMA_RX_RING0				0x7d0
++#endif
++#define MTK_WED_WPDMA_RX_RING1				0x7d8
+ 
+ #define MTK_WED_WPDMA_RX_D_MIB(_n)			(0x774 + (_n) * 4)
+ #define MTK_WED_WPDMA_RX_D_PROCESSED_MIB(_n)		(0x784 + (_n) * 4)
+ #define MTK_WED_WPDMA_RX_D_COHERENT_MIB			0x78c
+ 
++#define MTK_WED_WPDMA_RX_D_PREF_CFG			0x7b4
++#define MTK_WED_WPDMA_RX_D_PREF_EN			BIT(0)
++#define MTK_WED_WPDMA_RX_D_PREF_BURST_SIZE		GENMASK(12, 8)
++#define MTK_WED_WPDMA_RX_D_PREF_LOW_THRES		GENMASK(21, 16)
++
++#define MTK_WED_WPDMA_RX_D_PREF_RX0_SIDX		0x7b8
++#define MTK_WED_WPDMA_RX_D_PREF_SIDX_IDX_CLR		BIT(15)
++
++#define MTK_WED_WPDMA_RX_D_PREF_RX1_SIDX		0x7bc
++
++#define MTK_WED_WPDMA_RX_D_PREF_FIFO_CFG		0x7c0
++#define MTK_WED_WPDMA_RX_D_PREF_FIFO_CFG_R0_CLR		BIT(0)
++#define MTK_WED_WPDMA_RX_D_PREF_FIFO_CFG_R1_CLR		BIT(16)
++
+ #define MTK_WED_WDMA_RING_TX				0x800
+ 
+ #define MTK_WED_WDMA_TX_MIB				0x810
+ 
+-
+ #define MTK_WED_WDMA_RING_RX(_n)			(0x900 + (_n) * 0x10)
+ #define MTK_WED_WDMA_RX_THRES(_n)			(0x940 + (_n) * 0x4)
+ 
++#define MTK_WED_WDMA_RX_PREF_CFG			0x950
++#define MTK_WED_WDMA_RX_PREF_EN				BIT(0)
++#define MTK_WED_WDMA_RX_PREF_BURST_SIZE			GENMASK(12, 8)
++#define MTK_WED_WDMA_RX_PREF_LOW_THRES			GENMASK(21, 16)
++#define MTK_WED_WDMA_RX_PREF_RX0_SIDX_CLR		BIT(24)
++#define MTK_WED_WDMA_RX_PREF_RX1_SIDX_CLR		BIT(25)
++#define MTK_WED_WDMA_RX_PREF_DDONE2_EN			BIT(26)
++
++#define MTK_WED_WDMA_RX_PREF_FIFO_CFG			0x95C
++#define MTK_WED_WDMA_RX_PREF_FIFO_RX0_CLR		BIT(0)
++#define MTK_WED_WDMA_RX_PREF_FIFO_RX1_CLR		BIT(16)
++
+ #define MTK_WED_WDMA_GLO_CFG				0xa04
+ #define MTK_WED_WDMA_GLO_CFG_TX_DRV_EN			BIT(0)
+ #define MTK_WED_WDMA_GLO_CFG_TX_DDONE_CHK		BIT(1)
+@@ -350,6 +399,7 @@ struct mtk_wdma_desc {
+ #define MTK_WED_WDMA_INT_TRIGGER_RX_DONE		GENMASK(17, 16)
+ 
+ #define MTK_WED_WDMA_INT_CTRL				0xa2c
++#define MTK_WED_WDMA_INT_POLL_PRD			GENMASK(7, 0)
+ #define MTK_WED_WDMA_INT_POLL_SRC_SEL			GENMASK(17, 16)
+ 
+ #define MTK_WED_WDMA_CFG_BASE				0xaa0
+@@ -369,7 +419,7 @@ struct mtk_wdma_desc {
+ 
+ #define MTK_WED_RX_BM_BASE				0xd84
+ #define MTK_WED_RX_BM_INIT_PTR				0xd88
+-#define MTK_WED_RX_BM_SW_TAIL 				GENMASK(15, 0)
++#define MTK_WED_RX_BM_SW_TAIL				GENMASK(15, 0)
+ #define MTK_WED_RX_BM_INIT_SW_TAIL			BIT(16)
+ 
+ #define MTK_WED_RX_PTR					0xd8c
+@@ -411,6 +461,18 @@ struct mtk_wdma_desc {
+ #define MTK_WDMA_INT_GRP1				0x250
+ #define MTK_WDMA_INT_GRP2				0x254
+ 
++#define MTK_WDMA_PREF_TX_CFG				0x2d0
++#define MTK_WDMA_PREF_TX_CFG_PREF_EN			BIT(0)
++
++#define MTK_WDMA_PREF_RX_CFG				0x2dc
++#define MTK_WDMA_PREF_RX_CFG_PREF_EN			BIT(0)
++
++#define MTK_WDMA_WRBK_TX_CFG				0x300
++#define MTK_WDMA_WRBK_TX_CFG_WRBK_EN			BIT(30)
++
++#define MTK_WDMA_WRBK_RX_CFG				0x344
++#define MTK_WDMA_WRBK_RX_CFG_WRBK_EN			BIT(30)
++
+ #define MTK_PCIE_MIRROR_MAP(n)				((n) ? 0x4 : 0x0)
+ #define MTK_PCIE_MIRROR_MAP_EN				BIT(0)
+ #define MTK_PCIE_MIRROR_MAP_WED_ID			BIT(1)
+@@ -419,11 +481,36 @@ struct mtk_wdma_desc {
+ #define HIFSYS_DMA_AG_MAP				0x008
+ 
+ #define MTK_WED_RTQM_GLO_CFG				0xb00
+-#define MTK_WED_RTQM_BUSY	 			BIT(1)
+-#define MTK_WED_RTQM_Q_RST	 			BIT(2)
++#define MTK_WED_RTQM_BUSY				BIT(1)
++#define MTK_WED_RTQM_Q_RST				BIT(2)
+ #define MTK_WED_RTQM_Q_DBG_BYPASS			BIT(5)
+ #define MTK_WED_RTQM_TXDMAD_FPORT			GENMASK(23, 20)
+ 
++#define MTK_WED_RTQM_IGRS0_I2HW_DMAD_CNT		0xb1c
++#define MTK_WED_RTQM_IGRS0_I2H_DMAD_CNT(_n)		(0xb20 + (_n) * 0x4)
++#define	MTK_WED_RTQM_IGRS0_I2HW_PKT_CNT			0xb28
++#define MTK_WED_RTQM_IGRS0_I2H_PKT_CNT(_n)		(0xb2c + (_n) * 0x4)
++#define MTK_WED_RTQM_IGRS0_FDROP_CNT			0xb34
++
++
++#define MTK_WED_RTQM_IGRS1_I2HW_DMAD_CNT		0xb44
++#define MTK_WED_RTQM_IGRS1_I2H_DMAD_CNT(_n)		(0xb48 + (_n) * 0x4)
++#define MTK_WED_RTQM_IGRS1_I2HW_PKT_CNT			0xb50
++#define MTK_WED_RTQM_IGRS1_I2H_PKT_CNT(_n)		(0xb54 + (_n) * 0x4)
++#define MTK_WED_RTQM_IGRS1_FDROP_CNT			0xb5c
++
++#define MTK_WED_RTQM_IGRS2_I2HW_DMAD_CNT		0xb6c
++#define MTK_WED_RTQM_IGRS2_I2H_DMAD_CNT(_n)		(0xb70 + (_n) * 0x4)
++#define MTK_WED_RTQM_IGRS2_I2HW_PKT_CNT			0xb78
++#define MTK_WED_RTQM_IGRS2_I2H_PKT_CNT(_n)		(0xb7c + (_n) * 0x4)
++#define MTK_WED_RTQM_IGRS2_FDROP_CNT			0xb84
++
++#define MTK_WED_RTQM_IGRS3_I2HW_DMAD_CNT		0xb94
++#define MTK_WED_RTQM_IGRS3_I2H_DMAD_CNT(_n)		(0xb98 + (_n) * 0x4)
++#define MTK_WED_RTQM_IGRS3_I2HW_PKT_CNT			0xba0
++#define MTK_WED_RTQM_IGRS3_I2H_PKT_CNT(_n)		(0xba4 + (_n) * 0x4)
++#define MTK_WED_RTQM_IGRS3_FDROP_CNT			0xbac
++
+ #define MTK_WED_RTQM_R2H_MIB(_n)			(0xb70 + (_n) * 0x4)
+ #define MTK_WED_RTQM_R2Q_MIB(_n)			(0xb78 + (_n) * 0x4)
+ #define MTK_WED_RTQM_Q2N_MIB				0xb80
+@@ -432,21 +519,39 @@ struct mtk_wdma_desc {
+ #define MTK_WED_RTQM_Q2B_MIB				0xb8c
+ #define MTK_WED_RTQM_PFDBK_MIB				0xb90
+ 
++#define MTK_WED_RTQM_ENQ_CFG0				0xbb8
++#define MTK_WED_RTQM_ENQ_CFG_TXDMAD_FPORT		GENMASK(15, 12)
++
++#define MTK_WED_RTQM_FDROP_MIB				0xb84
++#define MTK_WED_RTQM_ENQ_I2Q_DMAD_CNT			0xbbc
++#define MTK_WED_RTQM_ENQ_I2N_DMAD_CNT			0xbc0
++#define MTK_WED_RTQM_ENQ_I2Q_PKT_CNT			0xbc4
++#define MTK_WED_RTQM_ENQ_I2N_PKT_CNT			0xbc8
++#define MTK_WED_RTQM_ENQ_USED_ENTRY_CNT			0xbcc
++#define MTK_WED_RTQM_ENQ_ERR_CNT			0xbd0
++
++#define MTK_WED_RTQM_DEQ_DMAD_CNT			0xbd8
++#define MTK_WED_RTQM_DEQ_Q2I_DMAD_CNT			0xbdc
++#define MTK_WED_RTQM_DEQ_PKT_CNT			0xbe0
++#define MTK_WED_RTQM_DEQ_Q2I_PKT_CNT			0xbe4
++#define MTK_WED_RTQM_DEQ_USED_PFDBK_CNT			0xbe8
++#define MTK_WED_RTQM_DEQ_ERR_CNT			0xbec
++
+ #define MTK_WED_RROQM_GLO_CFG				0xc04
+ #define MTK_WED_RROQM_RST_IDX				0xc08
+-#define MTK_WED_RROQM_RST_IDX_MIOD 			BIT(0)
+-#define MTK_WED_RROQM_RST_IDX_FDBK 			BIT(4)
++#define MTK_WED_RROQM_RST_IDX_MIOD			BIT(0)
++#define MTK_WED_RROQM_RST_IDX_FDBK			BIT(4)
+ 
+ #define MTK_WED_RROQM_MIOD_CTRL0			0xc40
+ #define MTK_WED_RROQM_MIOD_CTRL1			0xc44
+-#define MTK_WED_RROQM_MIOD_CNT 				GENMASK(11, 0)
++#define MTK_WED_RROQM_MIOD_CNT				GENMASK(11, 0)
+ 
+ #define MTK_WED_RROQM_MIOD_CTRL2			0xc48
+ #define MTK_WED_RROQM_MIOD_CTRL3			0xc4c
+ 
+ #define MTK_WED_RROQM_FDBK_CTRL0			0xc50
+ #define MTK_WED_RROQM_FDBK_CTRL1			0xc54
+-#define MTK_WED_RROQM_FDBK_CNT 				GENMASK(11, 0)
++#define MTK_WED_RROQM_FDBK_CNT				GENMASK(11, 0)
+ 
+ #define MTK_WED_RROQM_FDBK_CTRL2			0xc58
+ 
+@@ -454,7 +559,7 @@ struct mtk_wdma_desc {
+ #define MTK_WED_RROQ_BASE_H				0xc84
+ 
+ #define MTK_WED_RROQM_MIOD_CFG                          0xc8c
+-#define MTK_WED_RROQM_MIOD_MID_DW 			GENMASK(5, 0)
++#define MTK_WED_RROQM_MIOD_MID_DW			GENMASK(5, 0)
+ #define MTK_WED_RROQM_MIOD_MOD_DW			GENMASK(13, 8)
+ #define MTK_WED_RROQM_MIOD_ENTRY_DW			GENMASK(22, 16)
+ 
+@@ -468,20 +573,206 @@ struct mtk_wdma_desc {
+ #define MTK_WED_RROQM_FDBK_ANC_MIB			0xce8
+ #define MTK_WED_RROQM_FDBK_ANC2H_MIB			0xcec
+ 
+-#define MTK_WED_RX_BM_RX_DMAD  				0xd80
++#define MTK_WED_RX_BM_RX_DMAD				0xd80
+ #define MTK_WED_RX_BM_BASE				0xd84
+ #define MTK_WED_RX_BM_INIT_PTR				0xd88
+-#define MTK_WED_RX_BM_PTR	      			0xd8c
+-#define MTK_WED_RX_BM_PTR_HEAD				GENMASK(32, 16)
++#define MTK_WED_RX_BM_PTR				0xd8c
+ #define MTK_WED_RX_BM_PTR_TAIL				GENMASK(15, 0)
++#define MTK_WED_RX_BM_PTR_HEAD				GENMASK(32, 16)
+ 
+-#define MTK_WED_RX_BM_BLEN	      			0xd90
++#define MTK_WED_RX_BM_BLEN				0xd90
+ #define MTK_WED_RX_BM_STS				0xd94
+ #define MTK_WED_RX_BM_INTF2				0xd98
+ #define MTK_WED_RX_BM_INTF				0xd9c
+ #define MTK_WED_RX_BM_ERR_STS				0xda8
+ 
+-#define MTK_WED_WOCPU_VIEW_MIOD_BASE		 	0x8000
++#define MTK_RRO_IND_CMD_SIGNATURE			0xe00
++#define MTK_RRO_IND_CMD_DMA_IDX				GENMASK(11, 0)
++#define MTK_RRO_IND_CMD_MAGIC_CNT			GENMASK(30, 28)
++
++#define MTK_WED_IND_CMD_RX_CTRL0			0xe04
++#define MTK_WED_IND_CMD_PROC_IDX			GENMASK(11, 0)
++#define MTK_WED_IND_CMD_PREFETCH_FREE_CNT		GENMASK(19, 16)
++#define MTK_WED_IND_CMD_MAGIC_CNT			GENMASK(30, 28)
++
++#define MTK_WED_IND_CMD_RX_CTRL1			0xe08
++#define MTK_WED_IND_CMD_RX_CTRL2			0xe0c
++#define MTK_WED_IND_CMD_MAX_CNT				GENMASK(11, 0)
++#define MTK_WED_IND_CMD_BASE_M				GENMASK(19, 16)
++
++#define MTK_WED_RRO_CFG0				0xe10
++#define MTK_WED_RRO_CFG1				0xe14
++#define MTK_WED_RRO_CFG1_MAX_WIN_SZ			GENMASK(31, 29)
++#define MTK_WED_RRO_CFG1_ACK_SN_BASE_M			GENMASK(19, 16)
++#define MTK_WED_RRO_CFG1_PARTICL_SE_ID			GENMASK(11, 0)
++
++#define MTK_WED_ADDR_ELEM_CFG0				0xe18
++#define MTK_WED_ADDR_ELEM_CFG1				0xe1c
++#define MTK_WED_ADDR_ELEM_PREFETCH_FREE_CNT		GENMASK(19, 16)
++
++#define MTK_WED_ADDR_ELEM_TBL_CFG			0xe20
++#define MTK_WED_ADDR_ELEM_TBL_OFFSET			GENMASK(6, 0)
++#define MTK_WED_ADDR_ELEM_TBL_RD_RDY			BIT(28)
++#define MTK_WED_ADDR_ELEM_TBL_WR_RDY			BIT(29)
++#define MTK_WED_ADDR_ELEM_TBL_RD			BIT(30)
++#define MTK_WED_ADDR_ELEM_TBL_WR			BIT(31)
++
++#define MTK_WED_RADDR_ELEM_TBL_WDATA			0xe24
++#define MTK_WED_RADDR_ELEM_TBL_RDATA			0xe28
++
++#define MTK_WED_PN_CHECK_CFG				0xe30
++#define MTK_WED_PN_CHECK_SE_ID				GENMASK(11, 0)
++#define MTK_WED_PN_CHECK_RD_RDY				BIT(28)
++#define MTK_WED_PN_CHECK_WR_RDY				BIT(29)
++#define MTK_WED_PN_CHECK_RD				BIT(30)
++#define MTK_WED_PN_CHECK_WR				BIT(31)
++
++#define MTK_WED_PN_CHECK_WDATA_M			0xe38
++#define MTK_WED_PN_CHECK_IS_FIRST			BIT(17)
++
++#define MTK_WED_RRO_MSDU_PG_RING_CFG(_n)		(0xe44 + (_n) * 0x8)
++
++#define MTK_WED_RRO_MSDU_PG_RING2_CFG			0xe58
++#define MTK_WED_RRO_MSDU_PG_DRV_CLR			BIT(26)
++#define MTK_WED_RRO_MSDU_PG_DRV_EN			BIT(31)
++
++#define MTK_WED_RRO_MSDU_PG_CTRL0(_n)			(0xe5c + (_n) * 0xc)
++#define MTK_WED_RRO_MSDU_PG_CTRL1(_n)			(0xe60 + (_n) * 0xc)
++#define MTK_WED_RRO_MSDU_PG_CTRL2(_n)			(0xe64 + (_n) * 0xc)
++
++#define MTK_WED_RRO_RX_D_RX(_n)				(0xe80 + (_n) * 0x10)
++
++#define MTK_WED_RRO_RX_MAGIC_CNT			BIT(13)
++
++#define MTK_WED_RRO_RX_D_CFG(_n)			(0xea0 + (_n) * 0x4)
++#define MTK_WED_RRO_RX_D_DRV_CLR			BIT(26)
++#define MTK_WED_RRO_RX_D_DRV_EN				BIT(31)
++
++#define MTK_WED_RRO_PG_BM_RX_DMAM			0xeb0
++#define MTK_WED_RRO_PG_BM_RX_SDL0			GENMASK(13, 0)
++
++#define MTK_WED_RRO_PG_BM_BASE				0xeb4
++#define MTK_WED_RRO_PG_BM_INIT_PTR			0xeb8
++#define MTK_WED_RRO_PG_BM_SW_TAIL_IDX			GENMASK(15, 0)
++#define MTK_WED_RRO_PG_BM_INIT_SW_TAIL_IDX		BIT(16)
++
++#define MTK_WED_WPDMA_INT_CTRL_RRO_RX			0xeec
++#define MTK_WED_WPDMA_INT_CTRL_RRO_RX0_EN		BIT(0)
++#define MTK_WED_WPDMA_INT_CTRL_RRO_RX0_CLR		BIT(1)
++#define MTK_WED_WPDMA_INT_CTRL_RRO_RX0_DONE_TRIG	GENMASK(6, 2)
++#define MTK_WED_WPDMA_INT_CTRL_RRO_RX1_EN		BIT(8)
++#define MTK_WED_WPDMA_INT_CTRL_RRO_RX1_CLR		BIT(9)
++#define MTK_WED_WPDMA_INT_CTRL_RRO_RX1_DONE_TRIG	GENMASK(14, 10)
++
++#define MTK_WED_WPDMA_INT_CTRL_RRO_MSDU_PG		0xef4
++#define MTK_WED_WPDMA_INT_CTRL_RRO_PG0_EN		BIT(0)
++#define MTK_WED_WPDMA_INT_CTRL_RRO_PG0_CLR		BIT(1)
++#define MTK_WED_WPDMA_INT_CTRL_RRO_PG0_DONE_TRIG	GENMASK(6, 2)
++#define MTK_WED_WPDMA_INT_CTRL_RRO_PG1_EN		BIT(8)
++#define MTK_WED_WPDMA_INT_CTRL_RRO_PG1_CLR		BIT(9)
++#define MTK_WED_WPDMA_INT_CTRL_RRO_PG1_DONE_TRIG	GENMASK(14, 10)
++#define MTK_WED_WPDMA_INT_CTRL_RRO_PG2_EN		BIT(16)
++#define MTK_WED_WPDMA_INT_CTRL_RRO_PG2_CLR		BIT(17)
++#define MTK_WED_WPDMA_INT_CTRL_RRO_PG2_DONE_TRIG	GENMASK(22, 18)
++
++#define MTK_WED_RX_IND_CMD_CNT0				0xf20
++#define MTK_WED_RX_IND_CMD_DBG_CNT_EN			BIT(31)
++
++#define MTK_WED_RX_IND_CMD_CNT(_n)			(0xf20 + (_n) * 0x4)
++#define MTK_WED_IND_CMD_MAGIC_CNT_FAIL_CNT		GENMASK(15, 0)
++
++#define MTK_WED_RX_ADDR_ELEM_CNT(_n)			(0xf48 + (_n) * 0x4)
++#define MTK_WED_ADDR_ELEM_SIG_FAIL_CNT			GENMASK(15, 0)
++#define MTK_WED_ADDR_ELEM_FIRST_SIG_FAIL_CNT		GENMASK(31, 16)
++#define MTK_WED_ADDR_ELEM_ACKSN_CNT			GENMASK(27, 0)
++
++#define MTK_WED_RX_MSDU_PG_CNT(_n)			(0xf5c + (_n) * 0x4)
++
++#define MTK_WED_RX_PN_CHK_CNT				0xf70
++#define MTK_WED_PN_CHK_FAIL_CNT				GENMASK(15, 0)
++
++#define MTK_WED_WOCPU_VIEW_MIOD_BASE			0x8000
+ #define MTK_WED_PCIE_INT_MASK				0x0
+ 
++#define MTK_WED_AMSDU_FIFO				0x1800
++#define MTK_WED_AMSDU_IS_PRIOR0_RING			BIT(10)
++
++#define MTK_WED_AMSDU_STA_INFO				0x01810
++#define MTK_WED_AMSDU_STA_INFO_DO_INIT			BIT(0)
++#define MTK_WED_AMSDU_STA_INFO_SET_INIT			BIT(1)
++
++#define MTK_WED_AMSDU_STA_INFO_INIT			0x01814
++#define MTK_WED_AMSDU_STA_WTBL_HDRT_MODE		BIT(0)
++#define MTK_WED_AMSDU_STA_RMVL				BIT(1)
++#define MTK_WED_AMSDU_STA_MAX_AMSDU_LEN			GENMASK(7, 2)
++#define MTK_WED_AMSDU_STA_MAX_AMSDU_NUM			GENMASK(11, 8)
++
++#define MTK_WED_AMSDU_HIFTXD_BASE_L(_n)			(0x1980 + (_n) * 0x4)
++
++#define MTK_WED_AMSDU_PSE				0x1910
++#define MTK_WED_AMSDU_PSE_RESET				BIT(16)
++
++#define MTK_WED_AMSDU_HIFTXD_CFG			0x1968
++#define MTK_WED_AMSDU_HIFTXD_SRC			GENMASK(16, 15)
++
++#define MTK_WED_MON_AMSDU_FIFO_DMAD			0x1a34
++
++#define MTK_WED_MON_AMSDU_ENG_DMAD(_n)			(0x1a80 + (_n) * 0x50)
++#define MTK_WED_MON_AMSDU_ENG_QFPL(_n)			(0x1a84 + (_n) * 0x50)
++#define MTK_WED_MON_AMSDU_ENG_QENI(_n)			(0x1a88 + (_n) * 0x50)
++#define MTK_WED_MON_AMSDU_ENG_QENO(_n)			(0x1a8c + (_n) * 0x50)
++#define MTK_WED_MON_AMSDU_ENG_MERG(_n)			(0x1a90 + (_n) * 0x50)
++
++#define MTK_WED_MON_AMSDU_ENG_CNT8(_n)			(0x1a94 + (_n) * 0x50)
++#define MTK_WED_AMSDU_ENG_MAX_QGPP_CNT			GENMASK(10, 0)
++#define MTK_WED_AMSDU_ENG_MAX_PL_CNT			GENMASK(27, 16)
++
++#define MTK_WED_MON_AMSDU_ENG_CNT9(_n)			(0x1a98 + (_n) * 0x50)
++#define MTK_WED_AMSDU_ENG_CUR_ENTRY			GENMASK(10, 0)
++#define MTK_WED_AMSDU_ENG_MAX_BUF_MERGED		GENMASK(20, 16)
++#define MTK_WED_AMSDU_ENG_MAX_MSDU_MERGED		GENMASK(28, 24)
++
++#define MTK_WED_MON_AMSDU_QMEM_STS1			0x1e04
++
++#define MTK_WED_MON_AMSDU_QMEM_CNT(_n)			(0x1e0c + (_n) * 0x4)
++#define MTK_WED_AMSDU_QMEM_FQ_CNT			GENMASK(27, 16)
++#define MTK_WED_AMSDU_QMEM_SP_QCNT			GENMASK(11, 0)
++#define MTK_WED_AMSDU_QMEM_TID0_QCNT			GENMASK(27, 16)
++#define MTK_WED_AMSDU_QMEM_TID1_QCNT			GENMASK(11, 0)
++#define MTK_WED_AMSDU_QMEM_TID2_QCNT			GENMASK(27, 16)
++#define MTK_WED_AMSDU_QMEM_TID3_QCNT			GENMASK(11, 0)
++#define MTK_WED_AMSDU_QMEM_TID4_QCNT			GENMASK(27, 16)
++#define MTK_WED_AMSDU_QMEM_TID5_QCNT			GENMASK(11, 0)
++#define MTK_WED_AMSDU_QMEM_TID6_QCNT			GENMASK(27, 16)
++#define MTK_WED_AMSDU_QMEM_TID7_QCNT			GENMASK(11, 0)
++
++#define MTK_WED_MON_AMSDU_QMEM_PTR(_n)			(0x1e20 + (_n) * 0x4)
++#define MTK_WED_AMSDU_QMEM_FQ_HEAD			GENMASK(27, 16)
++#define MTK_WED_AMSDU_QMEM_SP_QHEAD			GENMASK(11, 0)
++#define MTK_WED_AMSDU_QMEM_TID0_QHEAD			GENMASK(27, 16)
++#define MTK_WED_AMSDU_QMEM_TID1_QHEAD			GENMASK(11, 0)
++#define MTK_WED_AMSDU_QMEM_TID2_QHEAD			GENMASK(27, 16)
++#define MTK_WED_AMSDU_QMEM_TID3_QHEAD			GENMASK(11, 0)
++#define MTK_WED_AMSDU_QMEM_TID4_QHEAD			GENMASK(27, 16)
++#define MTK_WED_AMSDU_QMEM_TID5_QHEAD			GENMASK(11, 0)
++#define MTK_WED_AMSDU_QMEM_TID6_QHEAD			GENMASK(27, 16)
++#define MTK_WED_AMSDU_QMEM_TID7_QHEAD			GENMASK(11, 0)
++#define MTK_WED_AMSDU_QMEM_FQ_TAIL			GENMASK(27, 16)
++#define MTK_WED_AMSDU_QMEM_SP_QTAIL			GENMASK(11, 0)
++#define MTK_WED_AMSDU_QMEM_TID0_QTAIL			GENMASK(27, 16)
++#define MTK_WED_AMSDU_QMEM_TID1_QTAIL			GENMASK(11, 0)
++#define MTK_WED_AMSDU_QMEM_TID2_QTAIL			GENMASK(27, 16)
++#define MTK_WED_AMSDU_QMEM_TID3_QTAIL			GENMASK(11, 0)
++#define MTK_WED_AMSDU_QMEM_TID4_QTAIL			GENMASK(27, 16)
++#define MTK_WED_AMSDU_QMEM_TID5_QTAIL			GENMASK(11, 0)
++#define MTK_WED_AMSDU_QMEM_TID6_QTAIL			GENMASK(27, 16)
++#define MTK_WED_AMSDU_QMEM_TID7_QTAIL			GENMASK(11, 0)
++
++#define MTK_WED_MON_AMSDU_HIFTXD_FETCH_MSDU(_n)		(0x1ec4 + (_n) * 0x4)
++
++#define MTK_WED_PCIE_BASE			0x11280000
++
++#define MTK_WED_PCIE_BASE0			0x11300000
++#define MTK_WED_PCIE_BASE1			0x11310000
++#define MTK_WED_PCIE_BASE2			0x11290000
+ #endif
+diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
+index b2abebe..a9e455d 100644
+--- a/include/linux/netdevice.h
++++ b/include/linux/netdevice.h
+@@ -880,6 +880,13 @@ struct net_device_path {
+ 			u8 queue;
+ 			u16 wcid;
+ 			u8 bss;
++			u32 usr_info;
++			u8 tid;
++			u8 is_fixedrate;
++			u8 is_prior;
++			u8 is_sp;
++			u8 hf;
++			u8 amsdu;
+ 		} mtk_wdma;
+ 	};
+ };
+diff --git a/include/linux/soc/mediatek/mtk_wed.h b/include/linux/soc/mediatek/mtk_wed.h
+index 470beb2..e81e41f 100644
+--- a/include/linux/soc/mediatek/mtk_wed.h
++++ b/include/linux/soc/mediatek/mtk_wed.h
+@@ -5,9 +5,12 @@
+ #include <linux/rcupdate.h>
+ #include <linux/regmap.h>
+ #include <linux/pci.h>
++#include <linux/skbuff.h>
++#include <linux/iopoll.h>
+ 
+ #define MTK_WED_TX_QUEUES		2
+ #define MTK_WED_RX_QUEUES		2
++#define MTK_WED_RX_PAGE_QUEUES		3
+ 
+ #define WED_WO_STA_REC			0x6
+ 
+@@ -43,7 +46,7 @@ enum mtk_wed_wo_cmd {
+ 	MTK_WED_WO_CMD_WED_END
+ };
+ 
+-struct mtk_rxbm_desc {
++struct mtk_wed_bm_desc {
+ 	__le32 buf0;
+ 	__le32 token;
+ } __packed __aligned(4);
+@@ -74,6 +77,11 @@ struct mtk_wed_wo_rx_stats {
+ 	__le32 rx_drop_cnt;
+ };
+ 
++struct mtk_wed_buf {
++	void *p;
++	dma_addr_t phy_addr;
++};
++
+ struct mtk_wed_device {
+ #ifdef CONFIG_NET_MEDIATEK_SOC_WED
+ 	const struct mtk_wed_ops *ops;
+@@ -92,10 +100,13 @@ struct mtk_wed_device {
+ 	struct mtk_wed_ring txfree_ring;
+ 	struct mtk_wed_ring tx_wdma[MTK_WED_TX_QUEUES];
+ 	struct mtk_wed_ring rx_wdma[MTK_WED_RX_QUEUES];
++	struct mtk_wed_ring rx_rro_ring[MTK_WED_RX_QUEUES];
++	struct mtk_wed_ring rx_page_ring[MTK_WED_RX_PAGE_QUEUES];
++	struct mtk_wed_ring ind_cmd_ring;
+ 
+ 	struct {
+ 		int size;
+-		void **pages;
++		struct mtk_wed_buf *pages;
+ 		struct mtk_wdma_desc *desc;
+ 		dma_addr_t desc_phys;
+ 	} tx_buf_ring;
+@@ -103,7 +114,7 @@ struct mtk_wed_device {
+  	struct {
+  		int size;
+  		struct page_frag_cache rx_page;
+-		struct mtk_rxbm_desc *desc;
++		struct mtk_wed_bm_desc *desc;
+  		dma_addr_t desc_phys;
+  	} rx_buf_ring;
+ 
+@@ -114,6 +125,13 @@ struct mtk_wed_device {
+ 		dma_addr_t fdbk_phys;
+ 	} rro;
+ 
++	struct {
++		int size;
++		struct mtk_wed_buf *pages;
++		struct mtk_wed_bm_desc *desc;
++		dma_addr_t desc_phys;
++	} hw_rro;
++
+ 	/* filled by driver: */
+ 	struct {
+ 		union {
+@@ -123,6 +141,7 @@ struct mtk_wed_device {
+ 		enum mtk_wed_bus_tye bus_type;
+ 		void __iomem *base;
+ 		u32 phy_base;
++		u32 id;
+ 
+ 		u32 wpdma_phys;
+ 		u32 wpdma_int;
+@@ -130,10 +149,14 @@ struct mtk_wed_device {
+ 		u32 wpdma_tx;
+ 		u32 wpdma_txfree;
+ 		u32 wpdma_rx_glo;
+-		u32 wpdma_rx;
++		u32 wpdma_rx[MTK_WED_RX_QUEUES];
++		u32 wpdma_rx_rro[MTK_WED_RX_QUEUES];
++		u32 wpdma_rx_pg;
+ 
+ 		u8 tx_tbit[MTK_WED_TX_QUEUES];
+ 		u8 rx_tbit[MTK_WED_RX_QUEUES];
++		u8 rro_rx_tbit[MTK_WED_RX_QUEUES];
++		u8 rx_pg_tbit[MTK_WED_RX_PAGE_QUEUES];
+ 		u8 txfree_tbit;
+ 
+ 		u16 token_start;
+@@ -141,8 +164,22 @@ struct mtk_wed_device {
+ 		unsigned int rx_nbuf;
+ 		unsigned int rx_npkt;
+ 		unsigned int rx_size;
++		unsigned int amsdu_max_len;
+ 
+ 		bool wcid_512;
++		bool hw_rro;
++		bool msi;
++
++		u8 amsdu_max_subframes;
++
++		struct {
++			u8 se_group_nums;
++			u16 win_size;
++			u16 particular_sid;
++			u32 ack_sn_addr;
++			dma_addr_t particular_se_phys;
++			dma_addr_t addr_elem_phys[1024];
++		} ind_cmd;
+ 
+ 		u32 (*init_buf)(void *ptr, dma_addr_t phys, int token_id);
+ 		int (*offload_enable)(struct mtk_wed_device *wed);
+@@ -185,6 +222,13 @@ struct mtk_wed_ops {
+ 
+ 	u32 (*irq_get)(struct mtk_wed_device *dev, u32 mask);
+ 	void (*irq_set_mask)(struct mtk_wed_device *dev, u32 mask);
++	void (*start_hw_rro)(struct mtk_wed_device *dev, u32 irq_mask);
++	void (*rro_rx_ring_setup)(struct mtk_wed_device *dev, int ring,
++				  void __iomem *regs);
++	void (*msdu_pg_rx_ring_setup)(struct mtk_wed_device *dev, int ring,
++				      void __iomem *regs);
++	int (*ind_rx_ring_setup)(struct mtk_wed_device *dev,
++				 void __iomem *regs);
+ };
+ 
+ extern const struct mtk_wed_ops __rcu *mtk_soc_wed_ops;
+@@ -213,12 +257,25 @@ static inline bool
+ mtk_wed_get_rx_capa(struct mtk_wed_device *dev)
+ {
+ #ifdef CONFIG_NET_MEDIATEK_SOC_WED
++	if (dev->version == 3)
++		return dev->wlan.hw_rro;
++
+ 	return dev->version != 1;
+ #else
+ 	return false;
+ #endif
+ }
+ 
++static inline bool
++mtk_wed_is_amsdu_supported(struct mtk_wed_device *dev)
++{
++#ifdef CONFIG_NET_MEDIATEK_SOC_WED
++	return dev->version == 3;
++#else
++	return false;
++#endif
++}
++
+ #ifdef CONFIG_NET_MEDIATEK_SOC_WED
+ #define mtk_wed_device_active(_dev) !!(_dev)->ops
+ #define mtk_wed_device_detach(_dev) (_dev)->ops->detach(_dev)
+@@ -245,6 +302,14 @@ mtk_wed_get_rx_capa(struct mtk_wed_device *dev)
+ #define mtk_wed_device_dma_reset(_dev) (_dev)->ops->reset_dma(_dev)
+ #define mtk_wed_device_setup_tc(_dev, _ndev, _type, _data) \
+ 	(_dev)->ops->setup_tc(_dev, _ndev, _type, _data)
++#define mtk_wed_device_start_hw_rro(_dev, _mask) \
++	(_dev)->ops->start_hw_rro(_dev, _mask)
++#define mtk_wed_device_rro_rx_ring_setup(_dev, _ring, _regs) \
++	(_dev)->ops->rro_rx_ring_setup(_dev, _ring, _regs)
++#define mtk_wed_device_msdu_pg_rx_ring_setup(_dev, _ring, _regs) \
++	(_dev)->ops->msdu_pg_rx_ring_setup(_dev, _ring, _regs)
++#define mtk_wed_device_ind_rx_ring_setup(_dev, _regs) \
++	(_dev)->ops->ind_rx_ring_setup(_dev, _regs)
+ #else
+ static inline bool mtk_wed_device_active(struct mtk_wed_device *dev)
+ {
+@@ -264,6 +329,10 @@ static inline bool mtk_wed_device_active(struct mtk_wed_device *dev)
+ #define mtk_wed_device_stop(_dev) do {} while (0)
+ #define mtk_wed_device_dma_reset(_dev) do {} while (0)
+ #define mtk_wed_device_setup_tc(_dev, _ndev, _type, _data) do {} while (0)
++#define mtk_wed_device_start_hw_rro(_dev, _mask) do {} while (0)
++#define mtk_wed_device_rro_rx_ring_setup(_dev, _ring, _regs) -ENODEV
++#define mtk_wed_device_msdu_pg_rx_ring_setup(_dev, _ring, _regs)  -ENODEV
++#define mtk_wed_device_ind_rx_ring_setup(_dev, _regs)  -ENODEV
+ #endif
+ 
+ #endif
+-- 
+2.18.0
+
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/flow_patch/999-3020-mtk-wed-add-wed3-ser-support.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/flow_patch/999-3020-mtk-wed-add-wed3-ser-support.patch
new file mode 100644
index 0000000..7423a6e
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/flow_patch/999-3020-mtk-wed-add-wed3-ser-support.patch
@@ -0,0 +1,697 @@
+From 67a20e07982e9c43d299679f75fd81638271fc63 Mon Sep 17 00:00:00 2001
+From: mtk27745 <rex.lu@mediatek.com>
+Date: Mon, 18 Sep 2023 13:22:44 +0800
+Subject: [PATCH 2/6] mtk wed add wed3 ser support
+
+---
+ drivers/net/ethernet/mediatek/mtk_wed.c      | 339 ++++++++++++++++---
+ drivers/net/ethernet/mediatek/mtk_wed_regs.h |  68 +++-
+ include/linux/soc/mediatek/mtk_wed.h         |   8 +-
+ 3 files changed, 367 insertions(+), 48 deletions(-)
+
+diff --git a/drivers/net/ethernet/mediatek/mtk_wed.c b/drivers/net/ethernet/mediatek/mtk_wed.c
+index 4b32a82..02c156a 100644
+--- a/drivers/net/ethernet/mediatek/mtk_wed.c
++++ b/drivers/net/ethernet/mediatek/mtk_wed.c
+@@ -110,24 +110,88 @@ mtk_wdma_read_reset(struct mtk_wed_device *dev)
+ 	return wdma_r32(dev, MTK_WDMA_GLO_CFG);
+ }
+ 
+-static u32
+-mtk_wed_check_busy(struct mtk_wed_device *dev, u32 reg, u32 mask)
++static void
++mtk_wdma_v3_rx_reset(struct mtk_wed_device *dev)
+ {
+-	if (wed_r32(dev, reg) & mask)
+-		return true;
+-
+-	return false;
+-}
++	u32 status;
+ 
+-static int
+-mtk_wed_poll_busy(struct mtk_wed_device *dev, u32 reg, u32 mask)
+-{
+-	int sleep = 1000;
+-	int timeout = 100 * sleep;
+-	u32 val;
++	if (!mtk_wed_is_v3_or_greater(dev->hw))
++		return;
+ 
+-	return read_poll_timeout(mtk_wed_check_busy, val, !val, sleep,
+-				 timeout, false, dev, reg, mask);
++	wdma_clr(dev, MTK_WDMA_PREF_TX_CFG, MTK_WDMA_PREF_TX_CFG_PREF_EN);
++	wdma_clr(dev, MTK_WDMA_PREF_RX_CFG, MTK_WDMA_PREF_RX_CFG_PREF_EN);
++
++	if (read_poll_timeout(wdma_r32, status,
++			      !(status & MTK_WDMA_PREF_TX_CFG_PREF_BUSY),
++			      0, 10000, false, dev, MTK_WDMA_PREF_TX_CFG))
++		dev_err(dev->hw->dev, "rx reset failed\n");
++
++	if (read_poll_timeout(wdma_r32, status,
++			      !(status & MTK_WDMA_PREF_RX_CFG_PREF_BUSY),
++			      0, 10000, false, dev, MTK_WDMA_PREF_RX_CFG))
++		dev_err(dev->hw->dev, "rx reset failed\n");
++
++	wdma_clr(dev, MTK_WDMA_WRBK_TX_CFG, MTK_WDMA_WRBK_TX_CFG_WRBK_EN);
++	wdma_clr(dev, MTK_WDMA_WRBK_RX_CFG, MTK_WDMA_WRBK_RX_CFG_WRBK_EN);
++
++	if (read_poll_timeout(wdma_r32, status,
++			      !(status & MTK_WDMA_WRBK_TX_CFG_WRBK_BUSY),
++			      0, 10000, false, dev, MTK_WDMA_WRBK_TX_CFG))
++		dev_err(dev->hw->dev, "rx reset failed\n");
++
++	if (read_poll_timeout(wdma_r32, status,
++			      !(status & MTK_WDMA_WRBK_RX_CFG_WRBK_BUSY),
++			      0, 10000, false, dev, MTK_WDMA_WRBK_RX_CFG))
++		dev_err(dev->hw->dev, "rx reset failed\n");
++
++	/* prefetch FIFO */
++	wdma_w32(dev, MTK_WDMA_PREF_RX_FIFO_CFG,
++		 MTK_WDMA_PREF_RX_FIFO_CFG_RING0_CLEAR |
++		 MTK_WDMA_PREF_RX_FIFO_CFG_RING1_CLEAR);
++	wdma_clr(dev, MTK_WDMA_PREF_RX_FIFO_CFG,
++		 MTK_WDMA_PREF_RX_FIFO_CFG_RING0_CLEAR |
++		 MTK_WDMA_PREF_RX_FIFO_CFG_RING1_CLEAR);
++
++	/* core FIFO */
++	wdma_w32(dev, MTK_WDMA_XDMA_RX_FIFO_CFG,
++		 MTK_WDMA_XDMA_RX_FIFO_CFG_RX_PAR_FIFO_CLEAR |
++		 MTK_WDMA_XDMA_RX_FIFO_CFG_RX_CMD_FIFO_CLEAR |
++		 MTK_WDMA_XDMA_RX_FIFO_CFG_RX_DMAD_FIFO_CLEAR |
++		 MTK_WDMA_XDMA_RX_FIFO_CFG_RX_ARR_FIFO_CLEAR |
++		 MTK_WDMA_XDMA_RX_FIFO_CFG_RX_LEN_FIFO_CLEAR |
++		 MTK_WDMA_XDMA_RX_FIFO_CFG_RX_WID_FIFO_CLEAR |
++		 MTK_WDMA_XDMA_RX_FIFO_CFG_RX_BID_FIFO_CLEAR);
++	wdma_clr(dev, MTK_WDMA_XDMA_RX_FIFO_CFG,
++		 MTK_WDMA_XDMA_RX_FIFO_CFG_RX_PAR_FIFO_CLEAR |
++		 MTK_WDMA_XDMA_RX_FIFO_CFG_RX_CMD_FIFO_CLEAR |
++		 MTK_WDMA_XDMA_RX_FIFO_CFG_RX_DMAD_FIFO_CLEAR |
++		 MTK_WDMA_XDMA_RX_FIFO_CFG_RX_ARR_FIFO_CLEAR |
++		 MTK_WDMA_XDMA_RX_FIFO_CFG_RX_LEN_FIFO_CLEAR |
++		 MTK_WDMA_XDMA_RX_FIFO_CFG_RX_WID_FIFO_CLEAR |
++		 MTK_WDMA_XDMA_RX_FIFO_CFG_RX_BID_FIFO_CLEAR);
++
++	/* writeback FIFO */
++	wdma_w32(dev, MTK_WDMA_WRBK_RX_FIFO_CFG(0),
++		 MTK_WDMA_WRBK_RX_FIFO_CFG_RING_CLEAR);
++	wdma_w32(dev, MTK_WDMA_WRBK_RX_FIFO_CFG(1),
++		 MTK_WDMA_WRBK_RX_FIFO_CFG_RING_CLEAR);
++
++	wdma_clr(dev, MTK_WDMA_WRBK_RX_FIFO_CFG(0),
++		 MTK_WDMA_WRBK_RX_FIFO_CFG_RING_CLEAR);
++	wdma_clr(dev, MTK_WDMA_WRBK_RX_FIFO_CFG(1),
++		 MTK_WDMA_WRBK_RX_FIFO_CFG_RING_CLEAR);
++
++	/* prefetch ring status */
++	wdma_w32(dev, MTK_WDMA_PREF_SIDX_CFG,
++		 MTK_WDMA_PREF_SIDX_CFG_RX_RING_CLEAR);
++	wdma_clr(dev, MTK_WDMA_PREF_SIDX_CFG,
++		 MTK_WDMA_PREF_SIDX_CFG_RX_RING_CLEAR);
++
++	/* writeback ring status */
++	wdma_w32(dev, MTK_WDMA_WRBK_SIDX_CFG,
++		 MTK_WDMA_WRBK_SIDX_CFG_RX_RING_CLEAR);
++	wdma_clr(dev, MTK_WDMA_WRBK_SIDX_CFG,
++		 MTK_WDMA_WRBK_SIDX_CFG_RX_RING_CLEAR);
+ }
+ 
+ static int
+@@ -142,6 +206,7 @@ mtk_wdma_rx_reset(struct mtk_wed_device *dev)
+ 	if (ret)
+ 		dev_err(dev->hw->dev, "rx reset failed \n");
+ 
++	mtk_wdma_v3_rx_reset(dev);
+ 	wdma_w32(dev, MTK_WDMA_RESET_IDX, MTK_WDMA_RESET_IDX_RX);
+ 	wdma_w32(dev, MTK_WDMA_RESET_IDX, 0);
+ 
+@@ -156,6 +221,101 @@ mtk_wdma_rx_reset(struct mtk_wed_device *dev)
+ 	return ret;
+ }
+ 
++static u32
++mtk_wed_check_busy(struct mtk_wed_device *dev, u32 reg, u32 mask)
++{
++	return !!(wed_r32(dev, reg) & mask);
++}
++
++static int
++mtk_wed_poll_busy(struct mtk_wed_device *dev, u32 reg, u32 mask)
++{
++	int sleep = 15000;
++	int timeout = 100 * sleep;
++	u32 val;
++
++	return read_poll_timeout(mtk_wed_check_busy, val, !val, sleep,
++				 timeout, false, dev, reg, mask);
++}
++
++static void
++mtk_wdma_v3_tx_reset(struct mtk_wed_device *dev)
++{
++	u32 status;
++
++	if (!mtk_wed_is_v3_or_greater(dev->hw))
++		return;
++
++	wdma_clr(dev, MTK_WDMA_PREF_TX_CFG, MTK_WDMA_PREF_TX_CFG_PREF_EN);
++	wdma_clr(dev, MTK_WDMA_PREF_RX_CFG, MTK_WDMA_PREF_RX_CFG_PREF_EN);
++
++	if (read_poll_timeout(wdma_r32, status,
++			      !(status & MTK_WDMA_PREF_TX_CFG_PREF_BUSY),
++			      0, 10000, false, dev, MTK_WDMA_PREF_TX_CFG))
++		dev_err(dev->hw->dev, "tx reset failed\n");
++
++	if (read_poll_timeout(wdma_r32, status,
++			      !(status & MTK_WDMA_PREF_RX_CFG_PREF_BUSY),
++			      0, 10000, false, dev, MTK_WDMA_PREF_RX_CFG))
++		dev_err(dev->hw->dev, "tx reset failed\n");
++
++	wdma_clr(dev, MTK_WDMA_WRBK_TX_CFG, MTK_WDMA_WRBK_TX_CFG_WRBK_EN);
++	wdma_clr(dev, MTK_WDMA_WRBK_RX_CFG, MTK_WDMA_WRBK_RX_CFG_WRBK_EN);
++
++	if (read_poll_timeout(wdma_r32, status,
++			      !(status & MTK_WDMA_WRBK_TX_CFG_WRBK_BUSY),
++			      0, 10000, false, dev, MTK_WDMA_WRBK_TX_CFG))
++		dev_err(dev->hw->dev, "tx reset failed\n");
++
++	if (read_poll_timeout(wdma_r32, status,
++			      !(status & MTK_WDMA_WRBK_RX_CFG_WRBK_BUSY),
++			      0, 10000, false, dev, MTK_WDMA_WRBK_RX_CFG))
++		dev_err(dev->hw->dev, "tx reset failed\n");
++
++	/* prefetch FIFO */
++	wdma_w32(dev, MTK_WDMA_PREF_TX_FIFO_CFG,
++		 MTK_WDMA_PREF_TX_FIFO_CFG_RING0_CLEAR |
++		 MTK_WDMA_PREF_TX_FIFO_CFG_RING1_CLEAR);
++	wdma_clr(dev, MTK_WDMA_PREF_TX_FIFO_CFG,
++		 MTK_WDMA_PREF_TX_FIFO_CFG_RING0_CLEAR |
++		 MTK_WDMA_PREF_TX_FIFO_CFG_RING1_CLEAR);
++
++	/* core FIFO */
++	wdma_w32(dev, MTK_WDMA_XDMA_TX_FIFO_CFG,
++		 MTK_WDMA_XDMA_TX_FIFO_CFG_TX_PAR_FIFO_CLEAR |
++		 MTK_WDMA_XDMA_TX_FIFO_CFG_TX_CMD_FIFO_CLEAR |
++		 MTK_WDMA_XDMA_TX_FIFO_CFG_TX_DMAD_FIFO_CLEAR |
++		 MTK_WDMA_XDMA_TX_FIFO_CFG_TX_ARR_FIFO_CLEAR);
++	wdma_clr(dev, MTK_WDMA_XDMA_TX_FIFO_CFG,
++		 MTK_WDMA_XDMA_TX_FIFO_CFG_TX_PAR_FIFO_CLEAR |
++		 MTK_WDMA_XDMA_TX_FIFO_CFG_TX_CMD_FIFO_CLEAR |
++		 MTK_WDMA_XDMA_TX_FIFO_CFG_TX_DMAD_FIFO_CLEAR |
++		 MTK_WDMA_XDMA_TX_FIFO_CFG_TX_ARR_FIFO_CLEAR);
++
++	/* writeback FIFO */
++	wdma_w32(dev, MTK_WDMA_WRBK_TX_FIFO_CFG(0),
++		 MTK_WDMA_WRBK_TX_FIFO_CFG_RING_CLEAR);
++	wdma_w32(dev, MTK_WDMA_WRBK_TX_FIFO_CFG(1),
++		 MTK_WDMA_WRBK_TX_FIFO_CFG_RING_CLEAR);
++
++	wdma_clr(dev, MTK_WDMA_WRBK_TX_FIFO_CFG(0),
++		 MTK_WDMA_WRBK_TX_FIFO_CFG_RING_CLEAR);
++	wdma_clr(dev, MTK_WDMA_WRBK_TX_FIFO_CFG(1),
++		 MTK_WDMA_WRBK_TX_FIFO_CFG_RING_CLEAR);
++
++	/* prefetch ring status */
++	wdma_w32(dev, MTK_WDMA_PREF_SIDX_CFG,
++		 MTK_WDMA_PREF_SIDX_CFG_TX_RING_CLEAR);
++	wdma_clr(dev, MTK_WDMA_PREF_SIDX_CFG,
++		 MTK_WDMA_PREF_SIDX_CFG_TX_RING_CLEAR);
++
++	/* writeback ring status */
++	wdma_w32(dev, MTK_WDMA_WRBK_SIDX_CFG,
++		 MTK_WDMA_WRBK_SIDX_CFG_TX_RING_CLEAR);
++	wdma_clr(dev, MTK_WDMA_WRBK_SIDX_CFG,
++		 MTK_WDMA_WRBK_SIDX_CFG_TX_RING_CLEAR);
++}
++
+ static void
+ mtk_wdma_tx_reset(struct mtk_wed_device *dev)
+ {
+@@ -167,6 +327,7 @@ mtk_wdma_tx_reset(struct mtk_wed_device *dev)
+ 			       !(status & mask), 0, 10000))
+ 		dev_err(dev->hw->dev, "tx reset failed \n");
+ 
++	mtk_wdma_v3_tx_reset(dev);
+ 	wdma_w32(dev, MTK_WDMA_RESET_IDX, MTK_WDMA_RESET_IDX_TX);
+ 	wdma_w32(dev, MTK_WDMA_RESET_IDX, 0);
+ 
+@@ -1389,25 +1550,6 @@ mtk_wed_ring_reset(struct mtk_wed_ring *ring, int size, bool tx)
+ 	}
+ }
+ 
+-static u32
+-mtk_wed_check_busy(struct mtk_wed_device *dev, u32 reg, u32 mask)
+-{
+-	if (wed_r32(dev, reg) & mask)
+-		return true;
+-
+-	return false;
+-}
+-
+-static int
+-mtk_wed_poll_busy(struct mtk_wed_device *dev, u32 reg, u32 mask)
+-{
+-	int sleep = 1000;
+-	int timeout = 100 * sleep;
+-	u32 val;
+-
+-	return read_poll_timeout(mtk_wed_check_busy, val, !val, sleep,
+-				 timeout, false, dev, reg, mask);
+-}
+ 
+ static int
+ mtk_wed_rx_reset(struct mtk_wed_device *dev)
+@@ -1423,13 +1565,32 @@ mtk_wed_rx_reset(struct mtk_wed_device *dev)
+ 	if (ret)
+ 		return ret;
+ 
++	if (dev->wlan.hw_rro) {
++		wed_clr(dev, MTK_WED_CTRL, MTK_WED_CTRL_WED_RX_IND_CMD_EN);
++		mtk_wed_poll_busy(dev, MTK_WED_RRO_RX_HW_STS,
++				  MTK_WED_RX_IND_CMD_BUSY);
++		mtk_wed_reset(dev, MTK_WED_RESET_RRO_RX_TO_PG);
++	}
++
+ 	wed_clr(dev, MTK_WED_WPDMA_RX_D_GLO_CFG, MTK_WED_WPDMA_RX_D_RX_DRV_EN);
+ 	ret = mtk_wed_poll_busy(dev, MTK_WED_WPDMA_RX_D_GLO_CFG,
+ 				MTK_WED_WPDMA_RX_D_RX_DRV_BUSY);
++	if (!ret && mtk_wed_is_v3_or_greater(dev->hw))
++		ret = mtk_wed_poll_busy(dev, MTK_WED_WPDMA_RX_D_PREF_CFG,
++					 MTK_WED_WPDMA_RX_D_PREF_BUSY);
+ 	if (ret) {
+ 		mtk_wed_reset(dev, MTK_WED_RESET_WPDMA_INT_AGENT);
+ 		mtk_wed_reset(dev, MTK_WED_RESET_WPDMA_RX_D_DRV);
+ 	} else {
++		if (mtk_wed_is_v3_or_greater(dev->hw)) {
++			/*1.a. Disable Prefetch HW*/
++			wed_clr(dev, MTK_WED_WPDMA_RX_D_PREF_CFG, MTK_WED_WPDMA_RX_D_PREF_EN);
++			mtk_wed_poll_busy(dev, MTK_WED_WPDMA_RX_D_PREF_CFG,
++					  MTK_WED_WPDMA_RX_D_PREF_BUSY);
++			wed_w32(dev, MTK_WED_WPDMA_RX_D_RST_IDX,
++				MTK_WED_WPDMA_RX_D_RST_DRV_IDX_ALL);
++		}
++
+ 		wed_w32(dev, MTK_WED_WPDMA_RX_D_RST_IDX,
+ 			MTK_WED_WPDMA_RX_D_RST_CRX_IDX |
+ 			MTK_WED_WPDMA_RX_D_RST_DRV_IDX);
+@@ -1457,15 +1618,36 @@ mtk_wed_rx_reset(struct mtk_wed_device *dev)
+ 		wed_w32(dev, MTK_WED_RROQM_RST_IDX, 0);
+ 	}
+ 
++	if (dev->wlan.hw_rro) {
++		/* Disable RRO MSDU Page Drv */
++		wed_clr(dev, MTK_WED_RRO_MSDU_PG_RING2_CFG, MTK_WED_RRO_MSDU_PG_DRV_EN);
++
++		/* Disable RRO Data Drv */
++		wed_clr(dev, MTK_WED_RRO_RX_D_CFG(2), MTK_WED_RRO_RX_D_DRV_EN);
++
++		/* RRO MSDU Page Drv Reset */
++		wed_w32(dev, MTK_WED_RRO_MSDU_PG_RING2_CFG, MTK_WED_RRO_MSDU_PG_DRV_CLR);
++		mtk_wed_poll_busy(dev, MTK_WED_RRO_MSDU_PG_RING2_CFG,
++				  MTK_WED_RRO_MSDU_PG_DRV_CLR);
++
++		/* RRO Data Drv Reset */
++		wed_w32(dev, MTK_WED_RRO_RX_D_CFG(2), MTK_WED_RRO_RX_D_DRV_CLR);
++		mtk_wed_poll_busy(dev, MTK_WED_RRO_RX_D_CFG(2),
++				  MTK_WED_RRO_RX_D_DRV_CLR);
++	}
++
+ 	/* reset route qm */
+ 	wed_clr(dev, MTK_WED_CTRL, MTK_WED_CTRL_RX_ROUTE_QM_EN);
+ 	ret = mtk_wed_poll_busy(dev, MTK_WED_CTRL,
+ 				MTK_WED_CTRL_RX_ROUTE_QM_BUSY);
+ 	if (ret) {
+ 		mtk_wed_reset(dev, MTK_WED_RESET_RX_ROUTE_QM);
++	} else if (mtk_wed_is_v3_or_greater(dev->hw)) {
++		wed_set(dev, MTK_WED_RTQM_RST, BIT(0));
++		wed_clr(dev, MTK_WED_RTQM_RST, BIT(0));
++		mtk_wed_reset(dev, MTK_WED_RESET_RX_ROUTE_QM);
+ 	} else {
+-		wed_set(dev, MTK_WED_RTQM_GLO_CFG,
+-			MTK_WED_RTQM_Q_RST);
++		wed_set(dev, MTK_WED_RTQM_GLO_CFG, MTK_WED_RTQM_Q_RST);
+ 	}
+ 
+ 	/* reset tx wdma */
+@@ -1473,8 +1655,12 @@ mtk_wed_rx_reset(struct mtk_wed_device *dev)
+ 
+ 	/* reset tx wdma drv */
+ 	wed_clr(dev, MTK_WED_WDMA_GLO_CFG, MTK_WED_WDMA_GLO_CFG_TX_DRV_EN);
+-	mtk_wed_poll_busy(dev, MTK_WED_CTRL,
+-			  MTK_WED_CTRL_WDMA_INT_AGENT_BUSY);
++	if (mtk_wed_is_v3_or_greater(dev->hw))
++		mtk_wed_poll_busy(dev, MTK_WED_WPDMA_STATUS,
++				  MTK_WED_WPDMA_STATUS_TX_DRV);
++	else
++		mtk_wed_poll_busy(dev, MTK_WED_CTRL,
++				  MTK_WED_CTRL_WDMA_INT_AGENT_BUSY);
+ 	mtk_wed_reset(dev, MTK_WED_RESET_WDMA_TX_DRV);
+ 
+ 	/* reset wed rx dma */
+@@ -1495,6 +1681,14 @@ mtk_wed_rx_reset(struct mtk_wed_device *dev)
+ 			  MTK_WED_CTRL_WED_RX_BM_BUSY);
+ 	mtk_wed_reset(dev, MTK_WED_RESET_RX_BM);
+ 
++	if (dev->wlan.hw_rro) {
++		wed_clr(dev, MTK_WED_CTRL, MTK_WED_CTRL_WED_RX_PG_BM_EN);
++		mtk_wed_poll_busy(dev, MTK_WED_CTRL,
++				  MTK_WED_CTRL_WED_RX_PG_BM_BUSY);
++		wed_set(dev, MTK_WED_RESET, MTK_WED_RESET_RX_PG_BM);
++		wed_clr(dev, MTK_WED_RESET, MTK_WED_RESET_RX_PG_BM);
++	}
++
+ 	/* wo change to enable state */
+ 	val = WO_STATE_ENABLE;
+ 	ret = mtk_wed_mcu_send_msg(wo, MTK_WED_MODULE_ID_WO,
+@@ -1549,16 +1743,55 @@ mtk_wed_reset_dma(struct mtk_wed_device *dev)
+ 
+ 	/* 2. Reset WDMA Rx DMA/Driver_Engine */
+ 	busy = !!mtk_wdma_rx_reset(dev);
++	if (mtk_wed_is_v3_or_greater(dev->hw)) {
++		val = MTK_WED_WDMA_GLO_CFG_RX_DIS_FSM_AUTO_IDLE |
++		      wed_r32(dev, MTK_WED_WDMA_GLO_CFG);
++		val &= ~MTK_WED_WDMA_GLO_CFG_RX_DRV_EN;
++		wed_w32(dev, MTK_WED_WDMA_GLO_CFG, val);
++	} else {
++		wed_clr(dev, MTK_WED_WDMA_GLO_CFG,
++			MTK_WED_WDMA_GLO_CFG_RX_DRV_EN);
++	}
+ 
+-	wed_clr(dev, MTK_WED_WDMA_GLO_CFG, MTK_WED_WDMA_GLO_CFG_RX_DRV_EN);
+ 	if (!busy)
+ 		busy = mtk_wed_poll_busy(dev, MTK_WED_WDMA_GLO_CFG,
+ 					 MTK_WED_WDMA_GLO_CFG_RX_DRV_BUSY);
++	if (!busy && mtk_wed_is_v3_or_greater(dev->hw))
++		busy = mtk_wed_poll_busy(dev, MTK_WED_WDMA_RX_PREF_CFG,
++					 MTK_WED_WDMA_RX_PREF_BUSY);
+ 
+ 	if (busy) {
+ 		mtk_wed_reset(dev, MTK_WED_RESET_WDMA_INT_AGENT);
+ 		mtk_wed_reset(dev, MTK_WED_RESET_WDMA_RX_DRV);
+ 	} else {
++		if (mtk_wed_is_v3_or_greater(dev->hw)) {
++			/*1.a. Disable Prefetch HW*/
++			wed_clr(dev, MTK_WED_WDMA_RX_PREF_CFG,
++				MTK_WED_WDMA_RX_PREF_EN);
++			mtk_wed_poll_busy(dev, MTK_WED_WDMA_RX_PREF_CFG,
++					  MTK_WED_WDMA_RX_PREF_BUSY);
++			wed_clr(dev, MTK_WED_WDMA_RX_PREF_CFG,
++				MTK_WED_WDMA_RX_PREF_DDONE2_EN);
++
++			/* reset prefetch index */
++			wed_set(dev, MTK_WED_WDMA_RX_PREF_CFG,
++				MTK_WED_WDMA_RX_PREF_RX0_SIDX_CLR |
++				MTK_WED_WDMA_RX_PREF_RX1_SIDX_CLR);
++
++			wed_clr(dev, MTK_WED_WDMA_RX_PREF_CFG,
++				MTK_WED_WDMA_RX_PREF_RX0_SIDX_CLR |
++				MTK_WED_WDMA_RX_PREF_RX1_SIDX_CLR);
++
++			/* reset prefetch FIFO */
++			wed_w32(dev, MTK_WED_WDMA_RX_PREF_FIFO_CFG,
++				MTK_WED_WDMA_RX_PREF_FIFO_RX0_CLR |
++				MTK_WED_WDMA_RX_PREF_FIFO_RX1_CLR);
++			wed_w32(dev, MTK_WED_WDMA_RX_PREF_FIFO_CFG, 0);
++
++			/*2. Reset dma index*/
++			wed_w32(dev, MTK_WED_WDMA_RESET_IDX,
++				MTK_WED_WDMA_RESET_IDX_RX_ALL);
++		}
+ 		wed_w32(dev, MTK_WED_WDMA_RESET_IDX,
+ 			MTK_WED_WDMA_RESET_IDX_RX | MTK_WED_WDMA_RESET_IDX_DRV);
+ 		wed_w32(dev, MTK_WED_WDMA_RESET_IDX, 0);
+@@ -1574,8 +1807,13 @@ mtk_wed_reset_dma(struct mtk_wed_device *dev)
+ 	wed_clr(dev, MTK_WED_CTRL, MTK_WED_CTRL_WED_TX_FREE_AGENT_EN);
+ 
+ 	for (i = 0; i < 100; i++) {
+-		val = wed_r32(dev, MTK_WED_TX_BM_INTF);
+-		if (FIELD_GET(MTK_WED_TX_BM_INTF_TKFIFO_FDEP, val) == 0x40)
++		if (mtk_wed_is_v1(dev->hw))
++			val = FIELD_GET(MTK_WED_TX_BM_INTF_TKFIFO_FDEP,
++					wed_r32(dev, MTK_WED_TX_BM_INTF));
++		else
++			val = FIELD_GET(MTK_WED_TX_TKID_INTF_TKFIFO_FDEP,
++					wed_r32(dev, MTK_WED_TX_TKID_INTF));
++		if (val == 0x40)
+ 			break;
+ 	}
+ 
+@@ -1599,6 +1837,8 @@ mtk_wed_reset_dma(struct mtk_wed_device *dev)
+ 		mtk_wed_reset(dev, MTK_WED_RESET_WPDMA_INT_AGENT);
+ 		mtk_wed_reset(dev, MTK_WED_RESET_WPDMA_TX_DRV);
+ 		mtk_wed_reset(dev, MTK_WED_RESET_WPDMA_RX_DRV);
++		if (mtk_wed_is_v3_or_greater(dev->hw))
++			wed_w32(dev, MTK_WED_RX1_CTRL2, 0);
+ 	} else {
+ 		wed_w32(dev, MTK_WED_WPDMA_RESET_IDX,
+ 			MTK_WED_WPDMA_RESET_IDX_TX |
+@@ -1615,7 +1855,14 @@ mtk_wed_reset_dma(struct mtk_wed_device *dev)
+ 		wed_w32(dev, MTK_WED_RESET_IDX, 0);
+ 	}
+ 
+-	mtk_wed_rx_reset(dev);
++	if (mtk_wed_is_v3_or_greater(dev->hw)) {
++		/* reset amsdu engine */
++		wed_clr(dev, MTK_WED_CTRL, MTK_WED_CTRL_TX_AMSDU_EN);
++		mtk_wed_reset(dev, MTK_WED_RESET_TX_AMSDU);
++	}
++
++	if (mtk_wed_get_rx_capa(dev))
++		mtk_wed_rx_reset(dev);
+ }
+ 
+ static int
+@@ -1932,7 +2179,7 @@ mtk_wed_dma_enable(struct mtk_wed_device *dev)
+ }
+ 
+ static void
+-mtk_wed_start_hw_rro(struct mtk_wed_device *dev, u32 irq_mask)
++mtk_wed_start_hw_rro(struct mtk_wed_device *dev, u32 irq_mask, bool reset)
+ {
+ 	int i;
+ 
+@@ -1942,6 +2189,12 @@ mtk_wed_start_hw_rro(struct mtk_wed_device *dev, u32 irq_mask)
+ 	if (!mtk_wed_get_rx_capa(dev) || !dev->wlan.hw_rro)
+ 		return;
+ 
++	if (reset) {
++		wed_set(dev, MTK_WED_RRO_MSDU_PG_RING2_CFG,
++			MTK_WED_RRO_MSDU_PG_DRV_EN);
++		return;
++	}
++
+ 	wed_set(dev, MTK_WED_RRO_RX_D_CFG(2), MTK_WED_RRO_MSDU_PG_DRV_CLR);
+ 	wed_w32(dev, MTK_WED_RRO_MSDU_PG_RING2_CFG,
+ 		MTK_WED_RRO_MSDU_PG_DRV_CLR);
+diff --git a/drivers/net/ethernet/mediatek/mtk_wed_regs.h b/drivers/net/ethernet/mediatek/mtk_wed_regs.h
+index 0af264d..1ee0fe1 100644
+--- a/drivers/net/ethernet/mediatek/mtk_wed_regs.h
++++ b/drivers/net/ethernet/mediatek/mtk_wed_regs.h
+@@ -36,6 +36,8 @@ struct mtk_wdma_desc {
+ #define MTK_WED_RESET					0x008
+ #define MTK_WED_RESET_TX_BM				BIT(0)
+ #define MTK_WED_RESET_RX_BM				BIT(1)
++#define MTK_WED_RESET_RX_PG_BM				BIT(2)
++#define MTK_WED_RESET_RRO_RX_TO_PG			BIT(3)
+ #define MTK_WED_RESET_TX_FREE_AGENT			BIT(4)
+ #define MTK_WED_RESET_WPDMA_TX_DRV			BIT(8)
+ #define MTK_WED_RESET_WPDMA_RX_DRV			BIT(9)
+@@ -58,7 +60,7 @@ struct mtk_wdma_desc {
+ #define MTK_WED_CTRL_WDMA_INT_AGENT_BUSY		BIT(3)
+ #define MTK_WED_CTRL_WED_RX_IND_CMD_EN			BIT(5)
+ #define MTK_WED_CTRL_WED_RX_PG_BM_EN			BIT(6)
+-#define MTK_WED_CTRL_WED_RX_PG_BM_BUSU			BIT(7)
++#define MTK_WED_CTRL_WED_RX_PG_BM_BUSY			BIT(7)
+ #define MTK_WED_CTRL_WED_TX_BM_EN			BIT(8)
+ #define MTK_WED_CTRL_WED_TX_BM_BUSY			BIT(9)
+ #define MTK_WED_CTRL_WED_TX_FREE_AGENT_EN		BIT(10)
+@@ -117,6 +119,10 @@ struct mtk_wdma_desc {
+ #define MTK_WED_STATUS					0x060
+ #define MTK_WED_STATUS_TX				GENMASK(15, 8)
+ 
++#define MTK_WED_WPDMA_STATUS				0x068
++#define MTK_WED_WPDMA_STATUS_TX_DRV			GENMASK(15, 8)
++
++
+ #define MTK_WED_TX_BM_CTRL				0x080
+ #define MTK_WED_TX_BM_CTRL_VLD_GRP_NUM			GENMASK(6, 0)
+ #define MTK_WED_TX_BM_CTRL_RSV_GRP_NUM			GENMASK(22, 16)
+@@ -154,6 +160,9 @@ struct mtk_wdma_desc {
+ #define MTK_WED_TX_TKID_CTRL_VLD_GRP_NUM_V3		GENMASK(7, 0)
+ #define MTK_WED_TX_TKID_CTRL_RSV_GRP_NUM_V3		GENMASK(23, 16)
+ 
++#define MTK_WED_TX_TKID_INTF				0x0dc
++#define MTK_WED_TX_TKID_INTF_TKFIFO_FDEP		GENMASK(25, 16)
++
+ #define MTK_WED_TX_TKID_DYN_THR				0x0e0
+ #define MTK_WED_TX_TKID_DYN_THR_LO			GENMASK(6, 0)
+ #define MTK_WED_TX_TKID_DYN_THR_HI			GENMASK(22, 16)
+@@ -205,6 +214,7 @@ struct mtk_wdma_desc {
+ #define MTK_WED_RING_RX_DATA(_n)			(0x420 + (_n) * 0x10)
+ 
+ #define MTK_WED_SCR0					0x3c0
++#define MTK_WED_RX1_CTRL2				0x418
+ #define MTK_WED_WPDMA_INT_TRIGGER			0x504
+ #define MTK_WED_WPDMA_INT_TRIGGER_RX_DONE		BIT(1)
+ #define MTK_WED_WPDMA_INT_TRIGGER_TX_DONE		GENMASK(5, 4)
+@@ -320,6 +330,7 @@ struct mtk_wdma_desc {
+ 
+ #define MTK_WED_WPDMA_RX_D_RST_IDX			0x760
+ #define MTK_WED_WPDMA_RX_D_RST_CRX_IDX			GENMASK(17, 16)
++#define MTK_WED_WPDMA_RX_D_RST_DRV_IDX_ALL		BIT(20)
+ #define MTK_WED_WPDMA_RX_D_RST_DRV_IDX			GENMASK(25, 24)
+ 
+ #define MTK_WED_WPDMA_RX_GLO_CFG			0x76c
+@@ -336,6 +347,7 @@ struct mtk_wdma_desc {
+ 
+ #define MTK_WED_WPDMA_RX_D_PREF_CFG			0x7b4
+ #define MTK_WED_WPDMA_RX_D_PREF_EN			BIT(0)
++#define MTK_WED_WPDMA_RX_D_PREF_BUSY		BIT(1)
+ #define MTK_WED_WPDMA_RX_D_PREF_BURST_SIZE		GENMASK(12, 8)
+ #define MTK_WED_WPDMA_RX_D_PREF_LOW_THRES		GENMASK(21, 16)
+ 
+@@ -357,11 +369,13 @@ struct mtk_wdma_desc {
+ 
+ #define MTK_WED_WDMA_RX_PREF_CFG			0x950
+ #define MTK_WED_WDMA_RX_PREF_EN				BIT(0)
++#define MTK_WED_WDMA_RX_PREF_BUSY			BIT(1)
+ #define MTK_WED_WDMA_RX_PREF_BURST_SIZE			GENMASK(12, 8)
+ #define MTK_WED_WDMA_RX_PREF_LOW_THRES			GENMASK(21, 16)
+ #define MTK_WED_WDMA_RX_PREF_RX0_SIDX_CLR		BIT(24)
+ #define MTK_WED_WDMA_RX_PREF_RX1_SIDX_CLR		BIT(25)
+ #define MTK_WED_WDMA_RX_PREF_DDONE2_EN			BIT(26)
++#define MTK_WED_WDMA_RX_PREF_DDONE2_BUSY		BIT(27)
+ 
+ #define MTK_WED_WDMA_RX_PREF_FIFO_CFG			0x95C
+ #define MTK_WED_WDMA_RX_PREF_FIFO_RX0_CLR		BIT(0)
+@@ -390,6 +404,7 @@ struct mtk_wdma_desc {
+ 
+ #define MTK_WED_WDMA_RESET_IDX				0xa08
+ #define MTK_WED_WDMA_RESET_IDX_RX			GENMASK(17, 16)
++#define MTK_WED_WDMA_RESET_IDX_RX_ALL			BIT(20)
+ #define MTK_WED_WDMA_RESET_IDX_DRV			GENMASK(25, 24)
+ 
+ #define MTK_WED_WDMA_INT_CLR				0xa24
+@@ -458,21 +473,66 @@ struct mtk_wdma_desc {
+ #define MTK_WDMA_INT_MASK_RX_DELAY			BIT(30)
+ #define MTK_WDMA_INT_MASK_RX_COHERENT			BIT(31)
+ 
++#define MTK_WDMA_XDMA_TX_FIFO_CFG			0x238
++#define MTK_WDMA_XDMA_TX_FIFO_CFG_TX_PAR_FIFO_CLEAR		BIT(0)
++#define MTK_WDMA_XDMA_TX_FIFO_CFG_TX_CMD_FIFO_CLEAR		BIT(4)
++#define MTK_WDMA_XDMA_TX_FIFO_CFG_TX_DMAD_FIFO_CLEAR		BIT(8)
++#define MTK_WDMA_XDMA_TX_FIFO_CFG_TX_ARR_FIFO_CLEAR		BIT(12)
++
++#define MTK_WDMA_XDMA_RX_FIFO_CFG			0x23c
++#define MTK_WDMA_XDMA_RX_FIFO_CFG_RX_PAR_FIFO_CLEAR		BIT(0)
++#define MTK_WDMA_XDMA_RX_FIFO_CFG_RX_CMD_FIFO_CLEAR		BIT(4)
++#define MTK_WDMA_XDMA_RX_FIFO_CFG_RX_DMAD_FIFO_CLEAR		BIT(8)
++#define MTK_WDMA_XDMA_RX_FIFO_CFG_RX_ARR_FIFO_CLEAR		BIT(12)
++#define MTK_WDMA_XDMA_RX_FIFO_CFG_RX_LEN_FIFO_CLEAR		BIT(15)
++#define MTK_WDMA_XDMA_RX_FIFO_CFG_RX_WID_FIFO_CLEAR		BIT(18)
++#define MTK_WDMA_XDMA_RX_FIFO_CFG_RX_BID_FIFO_CLEAR		BIT(21)
++
++
++
+ #define MTK_WDMA_INT_GRP1				0x250
+ #define MTK_WDMA_INT_GRP2				0x254
+ 
+ #define MTK_WDMA_PREF_TX_CFG				0x2d0
+ #define MTK_WDMA_PREF_TX_CFG_PREF_EN			BIT(0)
++#define MTK_WDMA_PREF_TX_CFG_PREF_BUSY			BIT(1)
+ 
+ #define MTK_WDMA_PREF_RX_CFG				0x2dc
+ #define MTK_WDMA_PREF_RX_CFG_PREF_EN			BIT(0)
++#define MTK_WDMA_PREF_RX_CFG_PREF_BUSY			BIT(1)
++
++#define MTK_WDMA_PREF_RX_FIFO_CFG			0x2e0
++#define MTK_WDMA_PREF_RX_FIFO_CFG_RING0_CLEAR		BIT(0)
++#define MTK_WDMA_PREF_RX_FIFO_CFG_RING1_CLEAR		BIT(16)
++
++#define MTK_WDMA_PREF_TX_FIFO_CFG			0x2d4
++#define MTK_WDMA_PREF_TX_FIFO_CFG_RING0_CLEAR		BIT(0)
++#define MTK_WDMA_PREF_TX_FIFO_CFG_RING1_CLEAR		BIT(16)
++
++#define MTK_WDMA_PREF_SIDX_CFG				0x2e4
++#define MTK_WDMA_PREF_SIDX_CFG_TX_RING_CLEAR		GENMASK(3, 0)
++#define MTK_WDMA_PREF_SIDX_CFG_RX_RING_CLEAR		GENMASK(5, 4)
+ 
+ #define MTK_WDMA_WRBK_TX_CFG				0x300
++#define MTK_WDMA_WRBK_TX_CFG_WRBK_BUSY			BIT(0)
+ #define MTK_WDMA_WRBK_TX_CFG_WRBK_EN			BIT(30)
+ 
++#define MTK_WDMA_WRBK_TX_FIFO_CFG(_n)			(0x304 + (_n) * 0x4)
++#define MTK_WDMA_WRBK_TX_FIFO_CFG_RING_CLEAR		BIT(0)
++
++
+ #define MTK_WDMA_WRBK_RX_CFG				0x344
++#define MTK_WDMA_WRBK_RX_CFG_WRBK_BUSY			BIT(0)
+ #define MTK_WDMA_WRBK_RX_CFG_WRBK_EN			BIT(30)
+ 
++#define MTK_WDMA_WRBK_RX_FIFO_CFG(_n)			(0x348 + (_n) * 0x4)
++#define MTK_WDMA_WRBK_RX_FIFO_CFG_RING_CLEAR		BIT(0)
++
++
++#define MTK_WDMA_WRBK_SIDX_CFG				0x388
++#define MTK_WDMA_WRBK_SIDX_CFG_TX_RING_CLEAR		GENMASK(3, 0)
++#define MTK_WDMA_WRBK_SIDX_CFG_RX_RING_CLEAR		GENMASK(5, 4)
++
+ #define MTK_PCIE_MIRROR_MAP(n)				((n) ? 0x4 : 0x0)
+ #define MTK_PCIE_MIRROR_MAP_EN				BIT(0)
+ #define MTK_PCIE_MIRROR_MAP_WED_ID			BIT(1)
+@@ -486,6 +546,9 @@ struct mtk_wdma_desc {
+ #define MTK_WED_RTQM_Q_DBG_BYPASS			BIT(5)
+ #define MTK_WED_RTQM_TXDMAD_FPORT			GENMASK(23, 20)
+ 
++#define MTK_WED_RTQM_RST				0xb04
++
++
+ #define MTK_WED_RTQM_IGRS0_I2HW_DMAD_CNT		0xb1c
+ #define MTK_WED_RTQM_IGRS0_I2H_DMAD_CNT(_n)		(0xb20 + (_n) * 0x4)
+ #define	MTK_WED_RTQM_IGRS0_I2HW_PKT_CNT			0xb28
+@@ -675,6 +738,9 @@ struct mtk_wdma_desc {
+ #define MTK_WED_WPDMA_INT_CTRL_RRO_PG2_CLR		BIT(17)
+ #define MTK_WED_WPDMA_INT_CTRL_RRO_PG2_DONE_TRIG	GENMASK(22, 18)
+ 
++#define MTK_WED_RRO_RX_HW_STS				0xf00
++#define MTK_WED_RX_IND_CMD_BUSY			GENMASK(31, 0)
++
+ #define MTK_WED_RX_IND_CMD_CNT0				0xf20
+ #define MTK_WED_RX_IND_CMD_DBG_CNT_EN			BIT(31)
+ 
+diff --git a/include/linux/soc/mediatek/mtk_wed.h b/include/linux/soc/mediatek/mtk_wed.h
+index e81e41f..83a4b8b 100644
+--- a/include/linux/soc/mediatek/mtk_wed.h
++++ b/include/linux/soc/mediatek/mtk_wed.h
+@@ -222,7 +222,7 @@ struct mtk_wed_ops {
+ 
+ 	u32 (*irq_get)(struct mtk_wed_device *dev, u32 mask);
+ 	void (*irq_set_mask)(struct mtk_wed_device *dev, u32 mask);
+-	void (*start_hw_rro)(struct mtk_wed_device *dev, u32 irq_mask);
++	void (*start_hw_rro)(struct mtk_wed_device *dev, u32 irq_mask, bool reset);
+ 	void (*rro_rx_ring_setup)(struct mtk_wed_device *dev, int ring,
+ 				  void __iomem *regs);
+ 	void (*msdu_pg_rx_ring_setup)(struct mtk_wed_device *dev, int ring,
+@@ -302,8 +302,8 @@ mtk_wed_is_amsdu_supported(struct mtk_wed_device *dev)
+ #define mtk_wed_device_dma_reset(_dev) (_dev)->ops->reset_dma(_dev)
+ #define mtk_wed_device_setup_tc(_dev, _ndev, _type, _data) \
+ 	(_dev)->ops->setup_tc(_dev, _ndev, _type, _data)
+-#define mtk_wed_device_start_hw_rro(_dev, _mask) \
+-	(_dev)->ops->start_hw_rro(_dev, _mask)
++#define mtk_wed_device_start_hw_rro(_dev, _mask, _reset) \
++	(_dev)->ops->start_hw_rro(_dev, _mask, _reset)
+ #define mtk_wed_device_rro_rx_ring_setup(_dev, _ring, _regs) \
+ 	(_dev)->ops->rro_rx_ring_setup(_dev, _ring, _regs)
+ #define mtk_wed_device_msdu_pg_rx_ring_setup(_dev, _ring, _regs) \
+@@ -329,7 +329,7 @@ static inline bool mtk_wed_device_active(struct mtk_wed_device *dev)
+ #define mtk_wed_device_stop(_dev) do {} while (0)
+ #define mtk_wed_device_dma_reset(_dev) do {} while (0)
+ #define mtk_wed_device_setup_tc(_dev, _ndev, _type, _data) do {} while (0)
+-#define mtk_wed_device_start_hw_rro(_dev, _mask) do {} while (0)
++#define mtk_wed_device_start_hw_rro(_dev, _mask, _reset) do {} while (0)
+ #define mtk_wed_device_rro_rx_ring_setup(_dev, _ring, _regs) -ENODEV
+ #define mtk_wed_device_msdu_pg_rx_ring_setup(_dev, _ring, _regs)  -ENODEV
+ #define mtk_wed_device_ind_rx_ring_setup(_dev, _regs)  -ENODEV
+-- 
+2.18.0
+
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/flow_patch/999-3021-mtk-wed-add-dma-mask-limitation-and-GFP_DMA32-for-bo.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/flow_patch/999-3021-mtk-wed-add-dma-mask-limitation-and-GFP_DMA32-for-bo.patch
new file mode 100644
index 0000000..d3747af
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/flow_patch/999-3021-mtk-wed-add-dma-mask-limitation-and-GFP_DMA32-for-bo.patch
@@ -0,0 +1,140 @@
+From f83c601c7b525c0adedcf1f5e8041acd350c7e2d Mon Sep 17 00:00:00 2001
+From: Sujuan Chen <sujuan.chen@mediatek.com>
+Date: Mon, 18 Sep 2023 13:23:56 +0800
+Subject: [PATCH] mtk: wed: add dma mask limitation and GFP_DMA32 for board >=
+ 4GB dram
+
+---
+ drivers/net/ethernet/mediatek/mtk_wed.c     | 16 +++++++++++-----
+ drivers/net/ethernet/mediatek/mtk_wed_mcu.c |  4 ++--
+ drivers/net/ethernet/mediatek/mtk_wed_wo.c  |  4 ++--
+ drivers/net/ethernet/mediatek/mtk_wed_wo.h  |  1 +
+ 4 files changed, 16 insertions(+), 9 deletions(-)
+
+diff --git a/drivers/net/ethernet/mediatek/mtk_wed.c b/drivers/net/ethernet/mediatek/mtk_wed.c
+index 5eeb3ed..094bc94 100644
+--- a/drivers/net/ethernet/mediatek/mtk_wed.c
++++ b/drivers/net/ethernet/mediatek/mtk_wed.c
+@@ -625,7 +625,7 @@ mtk_wed_tx_buffer_alloc(struct mtk_wed_device *dev)
+ 		void *buf;
+ 		int s;
+ 
+-		page = __dev_alloc_pages(GFP_KERNEL, 0);
++		page = __dev_alloc_pages(GFP_KERNEL | GFP_DMA32, 0);
+ 		if (!page)
+ 			return -ENOMEM;
+ 
+@@ -646,10 +646,11 @@ mtk_wed_tx_buffer_alloc(struct mtk_wed_device *dev)
+ 
+ 		for (s = 0; s < MTK_WED_BUF_PER_PAGE; s++) {
+ 			struct mtk_wdma_desc *desc = desc_ptr;
++			u32 ctrl;
+ 
+ 			desc->buf0 = cpu_to_le32(buf_phys);
+ 			if (!mtk_wed_is_v3_or_greater(dev->hw)) {
+-				u32 txd_size, ctrl;
++				u32 txd_size;
+ 
+ 				txd_size = dev->wlan.init_buf(buf, buf_phys,
+ 							      token++);
+@@ -663,11 +664,11 @@ mtk_wed_tx_buffer_alloc(struct mtk_wed_device *dev)
+ 					ctrl |= MTK_WDMA_DESC_CTRL_LAST_SEG0 |
+ 						FIELD_PREP(MTK_WDMA_DESC_CTRL_LEN1_V2,
+ 							   MTK_WED_BUF_SIZE - txd_size);
+-				desc->ctrl = cpu_to_le32(ctrl);
+ 				desc->info = 0;
+ 			} else {
+-				desc->ctrl = cpu_to_le32(token << 16);
++				ctrl = token << 16 | TX_DMA_SDP1(buf_phys);
+ 			}
++			desc->ctrl = cpu_to_le32(ctrl);
+ 
+ 			desc_ptr += desc_size;
+ 			buf += MTK_WED_BUF_SIZE;
+@@ -749,7 +750,7 @@ mtk_wed_hwrro_buffer_alloc(struct mtk_wed_device *dev)
+ 		void *buf;
+ 		int s;
+ 
+-		page = __dev_alloc_pages(GFP_KERNEL, 0);
++		page = __dev_alloc_pages(GFP_KERNEL | GFP_DMA32, 0);
+ 		if (!page)
+ 			return -ENOMEM;
+ 
+@@ -769,6 +770,7 @@ mtk_wed_hwrro_buffer_alloc(struct mtk_wed_device *dev)
+ 		buf_phys = page_phys;
+ 		for (s = 0; s < MTK_WED_RX_PAGE_BUF_PER_PAGE; s++) {
+ 			desc->buf0 = cpu_to_le32(buf_phys);
++			desc->token = cpu_to_le32(RX_DMA_SDP1(buf_phys));
+ 			desc++;
+ 			buf += MTK_WED_PAGE_BUF_SIZE;
+ 			buf_phys += MTK_WED_PAGE_BUF_SIZE;
+@@ -2457,6 +2459,10 @@ mtk_wed_attach(struct mtk_wed_device *dev)
+ 	dev->version = hw->version;
+ 	dev->hw->pci_base = mtk_wed_get_pci_base(dev);
+ 
++	ret = dma_set_mask_and_coherent(hw->dev, DMA_BIT_MASK(32));
++	if (ret)
++		return ret;
++
+ 	if (hw->eth->dma_dev == hw->eth->dev &&
+ 	    of_dma_is_coherent(hw->eth->dev->of_node))
+ 		mtk_eth_set_dma_device(hw->eth, hw->dev);
+diff --git a/drivers/net/ethernet/mediatek/mtk_wed_mcu.c b/drivers/net/ethernet/mediatek/mtk_wed_mcu.c
+index 18d1fb1..a88061c 100644
+--- a/drivers/net/ethernet/mediatek/mtk_wed_mcu.c
++++ b/drivers/net/ethernet/mediatek/mtk_wed_mcu.c
+@@ -145,7 +145,7 @@ int mtk_wed_exception_init(struct mtk_wed_wo *wo)
+ 	}req;
+ 
+ 	exp->log_size = EXCEPTION_LOG_SIZE;
+-	exp->log = kmalloc(exp->log_size, GFP_ATOMIC);
++	exp->log = page_frag_alloc(&wo->page, exp->log_size, GFP_ATOMIC | GFP_DMA32);
+ 	if (!exp->log)
+ 		return -ENOMEM;
+ 
+@@ -165,7 +165,7 @@ int mtk_wed_exception_init(struct mtk_wed_wo *wo)
+ 				    &req, sizeof(req), false);
+ 
+ free:
+-	kfree(exp->log);
++	skb_free_frag(exp->log);
+ 	return -ENOMEM;
+ }
+ 
+diff --git a/drivers/net/ethernet/mediatek/mtk_wed_wo.c b/drivers/net/ethernet/mediatek/mtk_wed_wo.c
+index 54b7787..e991d20 100644
+--- a/drivers/net/ethernet/mediatek/mtk_wed_wo.c
++++ b/drivers/net/ethernet/mediatek/mtk_wed_wo.c
+@@ -88,7 +88,7 @@ woif_q_rx_fill(struct mtk_wed_wo *wo, struct wed_wo_queue *q, bool rx)
+ 		page = &q->rx_page;
+ 
+ 	while (q->queued < q->ndesc) {
+-		buf = page_frag_alloc(page, len, GFP_ATOMIC);
++		buf = page_frag_alloc(page, len, GFP_ATOMIC | GFP_DMA32);
+ 		if (!buf)
+ 			break;
+ 
+@@ -555,7 +555,7 @@ void mtk_wed_wo_exit(struct mtk_wed_hw *hw)
+ 
+ 	if (wo->exp.log) {
+ 		dma_unmap_single(wo->hw->dev, wo->exp.phys, wo->exp.log_size, DMA_FROM_DEVICE);
+-		kfree(wo->exp.log);
++		skb_free_frag(wo->exp.log);
+ 	}
+ 
+ 	wo->hw = NULL;
+diff --git a/drivers/net/ethernet/mediatek/mtk_wed_wo.h b/drivers/net/ethernet/mediatek/mtk_wed_wo.h
+index b24fef3..5afa6de 100644
+--- a/drivers/net/ethernet/mediatek/mtk_wed_wo.h
++++ b/drivers/net/ethernet/mediatek/mtk_wed_wo.h
+@@ -193,6 +193,7 @@ struct mtk_wed_wo {
+ 	const struct wed_wo_drv_ops *drv_ops;
+ 	const struct wed_wo_mcu_ops *mcu_ops;
+ 	const struct wed_wo_queue_ops *queue_ops;
++	struct page_frag_cache page;
+ 
+ 	struct net_device napi_dev;
+ 	spinlock_t rx_lock;
+-- 
+2.18.0
+
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/wed3/999-3022-mediatek-ethernet-add-multiple-ppe-allocation.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/flow_patch/999-3022-mediatek-ethernet-add-multiple-ppe-allocati.patch
similarity index 70%
rename from recipes-kernel/linux/linux-mediatek-5.4/mediatek/wed3/999-3022-mediatek-ethernet-add-multiple-ppe-allocation.patch
rename to recipes-kernel/linux/linux-mediatek-5.4/mediatek/flow_patch/999-3022-mediatek-ethernet-add-multiple-ppe-allocati.patch
index cd6c8ca..c96eaa8 100644
--- a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/wed3/999-3022-mediatek-ethernet-add-multiple-ppe-allocation.patch
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/flow_patch/999-3022-mediatek-ethernet-add-multiple-ppe-allocati.patch
@@ -1,20 +1,21 @@
-From f80b9b330efd9d675c7c548c5af459792037ca99 Mon Sep 17 00:00:00 2001
+From e917fdd9042787edd43e4070c3480baf0dfb8d33 Mon Sep 17 00:00:00 2001
 From: Bo-Cun Chen <bc-bocun.chen@mediatek.com>
-Date: Tue, 26 Dec 2023 16:46:16 +0800
-Subject: [PATCH] 999-3022-mediatek-ethernet-add-multiple-ppe-allocatiion.patch
+Date: Mon, 18 Mar 2024 16:57:13 +0800
+Subject: [PATCH 22/24] 
+ 999-3022-mediatek-ethernet-add-multiple-ppe-allocatiion.patch
 
 ---
  arch/arm64/boot/dts/mediatek/mt7988.dtsi      |  1 +
- drivers/net/ethernet/mediatek/mtk_eth_soc.c   | 19 +++++++++++++++++--
+ drivers/net/ethernet/mediatek/mtk_eth_soc.c   | 22 ++++++++++++++++---
  drivers/net/ethernet/mediatek/mtk_eth_soc.h   |  3 +++
- .../net/ethernet/mediatek/mtk_ppe_offload.c   | 10 ++++++++++
- 4 files changed, 31 insertions(+), 2 deletions(-)
+ .../net/ethernet/mediatek/mtk_ppe_offload.c   | 10 +++++++++
+ 4 files changed, 33 insertions(+), 3 deletions(-)
 
 diff --git a/arch/arm64/boot/dts/mediatek/mt7988.dtsi b/arch/arm64/boot/dts/mediatek/mt7988.dtsi
-index 44a2f1b..cf50542 100644
+index 4a1a446..57b27f8 100644
 --- a/arch/arm64/boot/dts/mediatek/mt7988.dtsi
 +++ b/arch/arm64/boot/dts/mediatek/mt7988.dtsi
-@@ -949,6 +949,7 @@
+@@ -942,6 +942,7 @@
  		mediatek,infracfg = <&topmisc>;
  		mediatek,toprgu = <&watchdog>;
  		mediatek,hwver = <&hwver>;
@@ -23,10 +24,10 @@
  		#address-cells = <1>;
  		#size-cells = <0>;
 diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.c b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
-index 4cdfead..9009960 100644
+index 291afdc..c0f4ade 100644
 --- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c
 +++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
-@@ -2170,6 +2170,7 @@ static int mtk_poll_rx(struct napi_struct *napi, int budget,
+@@ -2349,6 +2349,7 @@ static int mtk_poll_rx(struct napi_struct *napi, int budget,
  	u8 *data, *new_data;
  	struct mtk_rx_dma_v2 *rxd, trxd;
  	int done = 0;
@@ -34,17 +35,20 @@
  
  	if (unlikely(!ring))
  		goto rx_done;
-@@ -2277,7 +2278,8 @@ static int mtk_poll_rx(struct napi_struct *napi, int budget,
- #if defined(CONFIG_MEDIATEK_NETSYS_RX_V2) || defined(CONFIG_MEDIATEK_NETSYS_V3)
- 		reason = FIELD_GET(MTK_RXD5_PPE_CPU_REASON_V2, trxd.rxd5);
- 		if (reason == MTK_PPE_CPU_REASON_HIT_UNBIND_RATE_REACHED) {
--			mtk_ppe_check_skb(eth->ppe[0], skb,
-+			i = eth->mac[mac]->ppe_idx;
-+			mtk_ppe_check_skb(eth->ppe[i], skb,
- 					  trxd.rxd5 & MTK_RXD5_FOE_ENTRY_V2);
+@@ -2463,8 +2464,10 @@ static int mtk_poll_rx(struct napi_struct *napi, int budget,
  		}
- #else
-@@ -3781,7 +3783,19 @@ static int mtk_open(struct net_device *dev)
+ #endif
+ 
+-		if (reason == MTK_PPE_CPU_REASON_HIT_UNBIND_RATE_REACHED)
+-			mtk_ppe_check_skb(eth->ppe[0], skb, hash);
++		if (reason == MTK_PPE_CPU_REASON_HIT_UNBIND_RATE_REACHED) {
++			i = eth->mac[mac]->ppe_idx;
++			mtk_ppe_check_skb(eth->ppe[i], skb, hash);
++		}
+ 
+ 		if (netdev->features & NETIF_F_HW_VLAN_CTAG_RX) {
+ 			if (MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_RX_V2)) {
+@@ -4113,7 +4116,19 @@ static int mtk_open(struct net_device *dev)
  			     SGMSYS_QPHY_PWR_STATE_CTRL, 0);
  
  	if (eth->soc->offload_version) {
@@ -65,7 +69,7 @@
  
  			for (i = 0; i < eth->ppe_num; i++)
  				mtk_ppe_start(eth->ppe[i]);
-@@ -4748,6 +4762,7 @@ static const struct net_device_ops mtk_netdev_ops = {
+@@ -5129,6 +5144,7 @@ static const struct net_device_ops mtk_netdev_ops = {
  	.ndo_poll_controller	= mtk_poll_controller,
  #endif
  	.ndo_setup_tc		= mtk_eth_setup_tc,
@@ -74,10 +78,10 @@
  
  static void mux_poll(struct work_struct *work)
 diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.h b/drivers/net/ethernet/mediatek/mtk_eth_soc.h
-index 12ffb3c..1bf335c 100644
+index 8454361..d958aec 100644
 --- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h
 +++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h
-@@ -1945,6 +1945,7 @@ struct mtk_mac {
+@@ -1978,6 +1978,7 @@ struct mtk_mac {
  	phy_interface_t			interface;
  	unsigned int			mode;
  	unsigned int			type;
@@ -85,7 +89,7 @@
  	int				speed;
  	struct device_node		*of_node;
  	struct phylink			*phylink;
-@@ -2045,6 +2046,8 @@ int mtk_eth_setup_tc(struct net_device *dev, enum tc_setup_type type,
+@@ -2079,6 +2080,8 @@ int mtk_eth_setup_tc(struct net_device *dev, enum tc_setup_type type,
  		     void *type_data);
  int mtk_eth_setup_tc_block(struct net_device *dev, struct flow_block_offload *f,
  			   struct mtk_eth *eth);
@@ -95,10 +99,10 @@
  u32 mtk_rss_indr_table(struct mtk_rss_params *rss_params, int index);
  
 diff --git a/drivers/net/ethernet/mediatek/mtk_ppe_offload.c b/drivers/net/ethernet/mediatek/mtk_ppe_offload.c
-index 339359e..8f721ba 100644
+index 402f1e3..3bfbec8 100644
 --- a/drivers/net/ethernet/mediatek/mtk_ppe_offload.c
 +++ b/drivers/net/ethernet/mediatek/mtk_ppe_offload.c
-@@ -693,6 +693,16 @@ int mtk_eth_setup_tc(struct net_device *dev, enum tc_setup_type type,
+@@ -828,6 +828,16 @@ int mtk_eth_setup_tc(struct net_device *dev, enum tc_setup_type type,
  	}
  }
  
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/wed3/999-3024-mtk-ppe-dispatch-short-packets-to-high-priority-TXQ-in-PPPQ.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/flow_patch/999-3023-mtk-ppe-dispatch-short-packets-to-high-prio.patch
similarity index 76%
rename from recipes-kernel/linux/linux-mediatek-5.4/mediatek/wed3/999-3024-mtk-ppe-dispatch-short-packets-to-high-priority-TXQ-in-PPPQ.patch
rename to recipes-kernel/linux/linux-mediatek-5.4/mediatek/flow_patch/999-3023-mtk-ppe-dispatch-short-packets-to-high-prio.patch
index 31d8b89..d0ad23e 100644
--- a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/wed3/999-3024-mtk-ppe-dispatch-short-packets-to-high-priority-TXQ-in-PPPQ.patch
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/flow_patch/999-3023-mtk-ppe-dispatch-short-packets-to-high-prio.patch
@@ -1,29 +1,34 @@
-From 8306aa4c52abf96af2c229762207369f279c89e2 Mon Sep 17 00:00:00 2001
+From e8a6054c824c5c65abd501bfd7437a3d7c5f2751 Mon Sep 17 00:00:00 2001
 From: Bo-Cun Chen <bc-bocun.chen@mediatek.com>
 Date: Tue, 28 Nov 2023 13:25:03 +0800
-Subject: [PATCH] 999-3024-mtk-ppe-dispatch-short-packets-to-high-priority-TXQ-in-PPPQ
+Subject: [PATCH 23/24] 
+ mtk-ppe-dispatch-short-packets-to-high-priority-TXQ-in-PPPQ
 
 ---
  drivers/net/ethernet/mediatek/mtk_ppe.c | 27 +++++++++++++++++++++++++
  1 file changed, 27 insertions(+)
 
 diff --git a/drivers/net/ethernet/mediatek/mtk_ppe.c b/drivers/net/ethernet/mediatek/mtk_ppe.c
-index 16aec2e..1e2b96e 100644
+index ae0acd5..547b5a0 100644
 --- a/drivers/net/ethernet/mediatek/mtk_ppe.c
 +++ b/drivers/net/ethernet/mediatek/mtk_ppe.c
-@@ -451,6 +451,28 @@ int mtk_foe_entry_set_qid(struct mtk_foe_entry *entry, int qid)
+@@ -451,6 +451,31 @@ int mtk_foe_entry_set_qid(struct mtk_foe_entry *entry, int qid)
  	return 0;
  }
  
-+#if defined(CONFIG_MEDIATEK_NETSYS_V3)
 +void mtk_foe_entry_adjust_qid(struct mtk_ppe *ppe, struct mtk_flow_entry *entry)
 +{
 +	struct mtk_foe_mac_info *l2 = mtk_foe_entry_l2(&entry->data);
 +	u32 *ib2 = mtk_foe_entry_ib2(&entry->data);
 +	u8 qid;
 +
++#if defined(CONFIG_MEDIATEK_NETSYS_V3)
 +	if (l2->tport_id != 1)
 +		return;
++#else
++	if (!(*ib2 & MTK_FOE_IB2_PSE_QOS))
++		return;
++#endif
 +
 +	qid = FIELD_GET(MTK_FOE_IB2_QID, *ib2);
 +	/* To enhance performance in the unbalanced PHY rate test,
@@ -35,23 +40,19 @@
 +		*ib2 |= FIELD_PREP(MTK_FOE_IB2_QID, qid);
 +	}
 +}
-+#endif
 +
  int mtk_foe_entry_set_dscp(struct mtk_foe_entry *entry, int dscp)
  {
  	u32 *ib2 = mtk_foe_entry_ib2(entry);
-@@ -790,6 +812,11 @@ void __mtk_ppe_check_skb(struct mtk_ppe *ppe, struct sk_buff *skb, u16 hash)
+@@ -790,6 +815,9 @@ void __mtk_ppe_check_skb(struct mtk_ppe *ppe, struct sk_buff *skb, u16 hash)
  			continue;
  		}
  
-+#if defined(CONFIG_MEDIATEK_NETSYS_V3)
 +		if (skb && skb->len < 100)
 +			mtk_foe_entry_adjust_qid(ppe, entry);
-+#endif
 +
  		entry->hash = hash;
  		__mtk_foe_entry_commit(ppe, &entry->data, hash);
  		found = true;
 -- 
 2.18.0
-
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/wed3/999-3025-dts-88d-option-type-2-support.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/flow_patch/999-3024-dts-88d-option-type-2-support.patch
similarity index 83%
rename from recipes-kernel/linux/linux-mediatek-5.4/mediatek/wed3/999-3025-dts-88d-option-type-2-support.patch
rename to recipes-kernel/linux/linux-mediatek-5.4/mediatek/flow_patch/999-3024-dts-88d-option-type-2-support.patch
index 9084982..9125b94 100644
--- a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/wed3/999-3025-dts-88d-option-type-2-support.patch
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/flow_patch/999-3024-dts-88d-option-type-2-support.patch
@@ -1,7 +1,7 @@
-From a344727c9d91c162839e7283aeac281f88f30e8a Mon Sep 17 00:00:00 2001
+From b294202119468041b6f4b6651f968c9d2a0adcc2 Mon Sep 17 00:00:00 2001
 From: Rex Lu <rex.lu@mediatek.com>
 Date: Mon, 22 Jan 2024 13:50:29 +0800
-Subject: [PATCH] dts 88d option type 2 support
+Subject: [PATCH 24/24] dts 88d option type 2 support
 
 Signed-off-by: Rex Lu <rex.lu@mediatek.com>
 ---
@@ -10,10 +10,10 @@
  2 files changed, 2 insertions(+)
 
 diff --git a/arch/arm64/boot/dts/mediatek/mt7988a-88d-10g-spim-nand.dts b/arch/arm64/boot/dts/mediatek/mt7988a-88d-10g-spim-nand.dts
-index 5513d04..7619009 100644
+index 8ebcbaf..df15051 100644
 --- a/arch/arm64/boot/dts/mediatek/mt7988a-88d-10g-spim-nand.dts
 +++ b/arch/arm64/boot/dts/mediatek/mt7988a-88d-10g-spim-nand.dts
-@@ -569,6 +569,7 @@
+@@ -572,6 +572,7 @@
  	mt7996@0,0 {
  		reg = <0x0000 0 0 0 0>;
  		device_type = "pci";
@@ -22,10 +22,10 @@
  	};
  };
 diff --git a/arch/arm64/boot/dts/mediatek/mt7988d-dsa-10g-spim-nand.dts b/arch/arm64/boot/dts/mediatek/mt7988d-dsa-10g-spim-nand.dts
-index 4cab1ae..b98efb9 100644
+index d4f96c8..c27ffa6 100644
 --- a/arch/arm64/boot/dts/mediatek/mt7988d-dsa-10g-spim-nand.dts
 +++ b/arch/arm64/boot/dts/mediatek/mt7988d-dsa-10g-spim-nand.dts
-@@ -546,6 +546,7 @@
+@@ -547,6 +547,7 @@
  	mt7996@0,0 {
  		reg = <0x0000 0 0 0 0>;
  		device_type = "pci";
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/mt7986.cfg b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/mt7986.cfg
index 8626ee4..488fa22 100644
--- a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/mt7986.cfg
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/mt7986.cfg
@@ -3,6 +3,7 @@
 CONFIG_AIROHA_EN8801SC_PHY=y
 # CONFIG_AIROHA_EN8811H_PHY is not set
 # CONFIG_AIROHA_AN8801_PHY is not set
+# CONFIG_AN8855_GSW is not set
 CONFIG_ARCH_CLOCKSOURCE_DATA=y
 CONFIG_ARCH_DMA_ADDR_T_64BIT=y
 CONFIG_ARCH_KEEP_MEMBLOCK=y
@@ -355,7 +356,9 @@
 CONFIG_NETFILTER_XT_TARGET_MASQUERADE=m
 CONFIG_NET_DEVLINK=y
 CONFIG_NET_DSA=y
+# CONFIG_NET_DSA_AN8855 is not set
 CONFIG_NET_DSA_MT7530=y
+# CONFIG_NET_DSA_TAG_ARHT is not set
 CONFIG_NET_DSA_TAG_MTK=y
 CONFIG_NET_FLOW_LIMIT=y
 # CONFIG_NET_MEDIATEK_HNAT is not set
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/mt7988.cfg b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/mt7988.cfg
index 714ff5d..8241edf 100644
--- a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/mt7988.cfg
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/mt7988.cfg
@@ -3,11 +3,12 @@
 # CONFIG_AIROHA_EN8801SC_PHY is not set
 # CONFIG_AIROHA_EN8811H_PHY is not set
 # CONFIG_AIROHA_AN8801_PHY is not set
+# CONFIG_AN8855_GSW is not set
 CONFIG_AQUANTIA_PHY=y
 CONFIG_AQUANTIA_PHY_FW_DOWNLOAD=y
 CONFIG_AQUANTIA_PHY_FW_DOWNLOAD_GANG=y
 # CONFIG_AQUANTIA_PHY_FW_DOWNLOAD_SINGLE is not set
-CONFIG_AQUANTIA_PHY_FW_FILE="Rhe-05.06-Candidate9-AQR_Mediatek_23B_P5_ID45824_LCLVER1.cld"
+CONFIG_AQUANTIA_PHY_FW_FILE="AQR-G4_v5.7.0-AQR_EVB_Generic_X3410_StdCfg_MDISwap_USX_ID46316_VER2140.cld"
 CONFIG_AQUANTIA_PHY_MIB=y
 CONFIG_ARCH_CLOCKSOURCE_DATA=y
 CONFIG_ARCH_DMA_ADDR_T_64BIT=y
@@ -325,7 +326,9 @@
 CONFIG_NEED_SG_DMA_LENGTH=y
 CONFIG_NET_DEVLINK=y
 CONFIG_NET_DSA=y
+# CONFIG_NET_DSA_AN8855 is not set
 CONFIG_NET_DSA_MT7530=y
+# CONFIG_NET_DSA_TAG_ARHT is not set
 CONFIG_NET_DSA_TAG_MTK=y
 CONFIG_NET_FLOW_LIMIT=y
 CONFIG_NET_MEDIATEK_SOC=y
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/999-2700-v5.7-iopoll-introduce-read_poll_timeout-macro.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-1021-v5.7-iopoll-introduce-read_poll_timeout-macro.patch
similarity index 100%
rename from recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/999-2700-v5.7-iopoll-introduce-read_poll_timeout-macro.patch
rename to recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-1021-v5.7-iopoll-introduce-read_poll_timeout-macro.patch
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/999-2360-v5.16-spi-add-power-control-when-set_cs.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-1400-v5.16-spi-add-power-control-when-set_cs.patch
similarity index 100%
rename from recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/999-2360-v5.16-spi-add-power-control-when-set_cs.patch
rename to recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-1400-v5.16-spi-add-power-control-when-set_cs.patch
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/999-2701-v5.8-net-phy-add-concept-of-shared-storage-for-PHYs.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-1700-v5.8-net-phy-add-concept-of-shared-storage-for-PHYs.patch
similarity index 100%
rename from recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/999-2701-v5.8-net-phy-add-concept-of-shared-storage-for-PHYs.patch
rename to recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-1700-v5.8-net-phy-add-concept-of-shared-storage-for-PHYs.patch
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/999-2702-v5.9-net-phy-add-support-for-a-common-probe-between-shared-PHYs.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-1701-v5.8-net-phy-add-concept-of-shared-storage-for-PHYs.patch
similarity index 100%
rename from recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/999-2702-v5.9-net-phy-add-support-for-a-common-probe-between-shared-PHYs.patch
rename to recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-1701-v5.8-net-phy-add-concept-of-shared-storage-for-PHYs.patch
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/999-2703-net-phy-backport-v5.4-mediatek-ge-and-v6.4-mediatek-ge-soc.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-1702-v6.4-backport-mediatek-ge-and-mediatek-ge-soc.patch
similarity index 100%
rename from recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/999-2703-net-phy-backport-v5.4-mediatek-ge-and-v6.4-mediatek-ge-soc.patch
rename to recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-1702-v6.4-backport-mediatek-ge-and-mediatek-ge-soc.patch
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/999-2328-mtd-add-nmbm-support.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-2328-mtd-add-nmbm-support.patch
similarity index 100%
rename from recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/999-2328-mtd-add-nmbm-support.patch
rename to recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-2328-mtd-add-nmbm-support.patch
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/999-2329-ubi-add-configurable-rootdev.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-2329-ubi-add-configurable-rootdev.patch
similarity index 100%
rename from recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/999-2329-ubi-add-configurable-rootdev.patch
rename to recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-2329-ubi-add-configurable-rootdev.patch
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-2344-mtd-spinand-Add-support-fudanmicro.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-2344-mtd-spinand-Add-support-fudanmicro.patch
new file mode 100644
index 0000000..34d249e
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-2344-mtd-spinand-Add-support-fudanmicro.patch
@@ -0,0 +1,141 @@
+Index: linux-5.4.260/drivers/mtd/nand/spi/core.c
+===================================================================
+--- linux-5.4.260.orig/drivers/mtd/nand/spi/core.c
++++ linux-5.4.260/drivers/mtd/nand/spi/core.c
+@@ -755,6 +755,7 @@ static const struct nand_ops spinand_ops
+ 
+ static const struct spinand_manufacturer *spinand_manufacturers[] = {
+ 	&etron_spinand_manufacturer,
++	&fudan_spinand_manufacturer,
+ 	&gigadevice_spinand_manufacturer,
+ 	&macronix_spinand_manufacturer,
+ 	&micron_spinand_manufacturer,
+Index: linux-5.4.260/drivers/mtd/nand/spi/Makefile
+===================================================================
+--- linux-5.4.260.orig/drivers/mtd/nand/spi/Makefile
++++ linux-5.4.260/drivers/mtd/nand/spi/Makefile
+@@ -1,3 +1,3 @@
+ # SPDX-License-Identifier: GPL-2.0
+-spinand-objs := core.o gigadevice.o macronix.o micron.o paragon.o toshiba.o winbond.o etron.o
++spinand-objs := core.o etron.o fudanmicro.o gigadevice.o macronix.o micron.o paragon.o toshiba.o winbond.o
+ obj-$(CONFIG_MTD_SPI_NAND) += spinand.o
+Index: linux-5.4.260/include/linux/mtd/spinand.h
+===================================================================
+--- linux-5.4.260.orig/include/linux/mtd/spinand.h
++++ linux-5.4.260/include/linux/mtd/spinand.h
+@@ -239,6 +239,7 @@ struct spinand_manufacturer {
+ 
+ /* SPI NAND manufacturers */
+ extern const struct spinand_manufacturer etron_spinand_manufacturer;
++extern const struct spinand_manufacturer fudan_spinand_manufacturer;
+ extern const struct spinand_manufacturer gigadevice_spinand_manufacturer;
+ extern const struct spinand_manufacturer macronix_spinand_manufacturer;
+ extern const struct spinand_manufacturer micron_spinand_manufacturer;
+Index: linux-5.4.260/drivers/mtd/nand/spi/fudanmicro.c
+===================================================================
+--- /dev/null
++++ linux-5.4.260/drivers/mtd/nand/spi/fudanmicro.c
+@@ -0,0 +1,103 @@
++#include <linux/device.h>
++#include <linux/kernel.h>
++#include <linux/mtd/spinand.h>
++
++#define SPINAND_MFR_FUDAN		0xA1
++
++#define FM25S01B_STATUS_ECC_MASK		(7 << 4)
++#define STATUS_ECC_1_3_BITFLIPS	(1 << 4)
++#define STATUS_ECC_4_6_BITFLIPS	(3 << 4)
++#define STATUS_ECC_7_8_BITFLIPS	(5 << 4)
++
++static SPINAND_OP_VARIANTS(read_cache_variants,
++		SPINAND_PAGE_READ_FROM_CACHE_X4_OP(0, 1, NULL, 0),
++		SPINAND_PAGE_READ_FROM_CACHE_X2_OP(0, 1, NULL, 0),
++		SPINAND_PAGE_READ_FROM_CACHE_OP(true, 0, 1, NULL, 0),
++		SPINAND_PAGE_READ_FROM_CACHE_OP(false, 0, 1, NULL, 0));
++
++static SPINAND_OP_VARIANTS(write_cache_variants,
++		SPINAND_PROG_LOAD_X4(true, 0, NULL, 0),
++		SPINAND_PROG_LOAD(true, 0, NULL, 0));
++
++static SPINAND_OP_VARIANTS(update_cache_variants,
++		SPINAND_PROG_LOAD_X4(false, 0, NULL, 0),
++		SPINAND_PROG_LOAD(false, 0, NULL, 0));
++
++static int fm25s01b_ooblayout_ecc(struct mtd_info *mtd, int section,
++				      struct mtd_oob_region *region)
++{
++	if (section)
++		return -ERANGE;
++
++	region->offset = 64;
++	region->length = 64;
++
++	return 0;
++}
++
++static int fm25s01b_ooblayout_free(struct mtd_info *mtd, int section,
++				       struct mtd_oob_region *region)
++{
++	if (section > 3)
++		return -ERANGE;
++
++	region->offset = (16 * section) + 4;
++	region->length = 12;
++
++	return 0;
++}
++
++static const struct mtd_ooblayout_ops fm25s01b_ooblayout = {
++	.ecc = fm25s01b_ooblayout_ecc,
++	.free = fm25s01b_ooblayout_free,
++};
++
++static int fm25s01b_ecc_get_status(struct spinand_device *spinand,
++				       u8 status)
++{
++	switch (status & FM25S01B_STATUS_ECC_MASK) {
++	case STATUS_ECC_NO_BITFLIPS:
++		return 0;
++
++	case STATUS_ECC_UNCOR_ERROR:
++		return -EBADMSG;
++
++	case STATUS_ECC_1_3_BITFLIPS:
++		return 3;
++
++	case STATUS_ECC_4_6_BITFLIPS:
++		return 6;
++
++	case STATUS_ECC_7_8_BITFLIPS:
++		return 8;
++
++	default:
++		break;
++	}
++
++	return -EINVAL;
++}
++
++static const struct spinand_info fudan_spinand_table[] = {
++	SPINAND_INFO("FM25s01B",
++			 SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xD4),
++		     NAND_MEMORG(1, 2048, 128, 64, 1024, 20, 1, 1, 1),
++		     NAND_ECCREQ(8, 512),
++		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
++					      &write_cache_variants,
++					      &update_cache_variants),
++		     SPINAND_HAS_QE_BIT,
++		     SPINAND_ECCINFO(&fm25s01b_ooblayout,
++				     fm25s01b_ecc_get_status)),
++};
++
++static const struct spinand_manufacturer_ops fudan_spinand_manuf_ops = {
++};
++
++const struct spinand_manufacturer fudan_spinand_manufacturer = {
++	.id = SPINAND_MFR_FUDAN,
++	.name = "FUDAN Micron",
++	.chips = fudan_spinand_table,
++	.nchips = ARRAY_SIZE(fudan_spinand_table),
++	.ops = &fudan_spinand_manuf_ops,
++};
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/hack-5.4/999-2540-cmdline-boot-parameters.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-2540-cmdline-boot-parameters.patch
similarity index 95%
rename from recipes-kernel/linux/linux-mediatek-5.4/generic/hack-5.4/999-2540-cmdline-boot-parameters.patch
rename to recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-2540-cmdline-boot-parameters.patch
index eadc288..a160814 100644
--- a/recipes-kernel/linux/linux-mediatek-5.4/generic/hack-5.4/999-2540-cmdline-boot-parameters.patch
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-2540-cmdline-boot-parameters.patch
@@ -27,7 +27,7 @@
 index 000000000..3dfe828bc
 --- /dev/null
 +++ b/kernel/boot_param.c
-@@ -0,0 +1,44 @@
+@@ -0,0 +1,47 @@
 +/* SPDX-License-Identifier: BSD-3-Clause */
 +/*
 +* Copyright (C) 2022 MediaTek Inc. All rights reserved.
@@ -40,9 +40,12 @@
 +
 +#define BOOT_PARAM_STR_MAX_LEN			256
 +
-+static bool dual_boot;
++bool dual_boot;
 +module_param(dual_boot, bool, 0444);
 +
++static bool reset_boot_count;
++module_param(reset_boot_count, bool, 0444);
++
 +static bool no_split_rootfs_data;
 +module_param(no_split_rootfs_data, bool, 0444);
 +
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-2550-dual-image-mount-rootfs.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-2550-dual-image-mount-rootfs.patch
index 350e7d3..48b94cd 100644
--- a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-2550-dual-image-mount-rootfs.patch
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-2550-dual-image-mount-rootfs.patch
@@ -22,19 +22,6 @@
  		return;
  #endif
  #ifdef CONFIG_BLOCK
-diff --git a/kernel/boot_param.c b/kernel/boot_param.c
-index 3dfe828bc..cc0b2b8b0 100644
---- a/kernel/boot_param.c
-+++ b/kernel/boot_param.c
-@@ -10,7 +10,7 @@
- 
- #define BOOT_PARAM_STR_MAX_LEN			256
- 
--static bool dual_boot;
-+bool dual_boot;
- module_param(dual_boot, bool, 0444);
- 
- static bool no_split_rootfs_data;
 -- 
 2.34.1
 
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/999-2704-netfilter_optional_tcp_window_check.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-2700-netfilter_optional_tcp_window_check.patch
similarity index 97%
rename from recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/999-2704-netfilter_optional_tcp_window_check.patch
rename to recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-2700-netfilter_optional_tcp_window_check.patch
index 0aea6d3..62a81d1 100644
--- a/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/999-2704-netfilter_optional_tcp_window_check.patch
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-2700-netfilter_optional_tcp_window_check.patch
@@ -2,7 +2,7 @@
 From: Sam Shih <sam.shih@mediatek.com>
 Date: Fri, 2 Jun 2023 13:06:28 +0800
 Subject: [PATCH] 
- [networking][999-2704-netfilter_optional_tcp_window_check.patch]
+ [networking][999-2700-netfilter_optional_tcp_window_check.patch]
 
 ---
  net/netfilter/nf_conntrack_proto_tcp.c  |  8 +++++++-
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-2739-drivers_net_dsa_add_an8855.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-2739-drivers_net_dsa_add_an8855.patch
new file mode 100644
index 0000000..d089c96
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-2739-drivers_net_dsa_add_an8855.patch
@@ -0,0 +1,25 @@
+Index: linux-5.4.238/drivers/net/dsa/Kconfig
+===================================================================
+--- linux-5.4.238.orig/drivers/net/dsa/Kconfig	2023-12-26 15:31:49.427259000 +0800
++++ linux-5.4.238/drivers/net/dsa/Kconfig	2023-12-26 15:46:52.655226000 +0800
+@@ -48,6 +48,8 @@
+ 	  This enables support for the Marvell 88E6060 ethernet switch
+ 	  chip.
+ 
++source "drivers/net/dsa/airoha/an8855/Kconfig"
++
+ source "drivers/net/dsa/microchip/Kconfig"
+ 
+ source "drivers/net/dsa/mv88e6xxx/Kconfig"
+Index: linux-5.4.238/drivers/net/dsa/Makefile
+===================================================================
+--- linux-5.4.238.orig/drivers/net/dsa/Makefile	2023-12-26 15:32:08.081306000 +0800
++++ linux-5.4.238/drivers/net/dsa/Makefile	2023-12-26 15:47:59.858217000 +0800
+@@ -18,6 +18,7 @@
+ obj-$(CONFIG_NET_DSA_VITESSE_VSC73XX) += vitesse-vsc73xx-core.o
+ obj-$(CONFIG_NET_DSA_VITESSE_VSC73XX_PLATFORM) += vitesse-vsc73xx-platform.o
+ obj-$(CONFIG_NET_DSA_VITESSE_VSC73XX_SPI) += vitesse-vsc73xx-spi.o
++obj-y				+= airoha/an8855/
+ obj-y				+= b53/
+ obj-y				+= microchip/
+ obj-y				+= mv88e6xxx/
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-2739-drivers_net_ethernet_mediatek_hnat.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-2739-drivers_net_ethernet_mediatek_hnat.patch
new file mode 100644
index 0000000..34855a5
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-2739-drivers_net_ethernet_mediatek_hnat.patch
@@ -0,0 +1,13 @@
+Index: linux-5.4.238/drivers/net/ethernet/mediatek/mtk_hnat/Makefile
+===================================================================
+--- linux-5.4.238.orig/drivers/net/ethernet/mediatek/mtk_hnat/Makefile	2023-09-05 21:55:25.000000000 +0800
++++ linux-5.4.238/drivers/net/ethernet/mediatek/mtk_hnat/Makefile	2023-12-18 11:26:54.110684000 +0800
+@@ -2,4 +2,8 @@
+ 
+ obj-$(CONFIG_NET_MEDIATEK_HNAT)         += mtkhnat.o
+ mtkhnat-objs := hnat.o hnat_nf_hook.o hnat_debugfs.o hnat_mcast.o
++ifeq ($(CONFIG_NET_DSA_AN8855), y)
++mtkhnat-y	+= hnat_stag.o
++else
+ mtkhnat-$(CONFIG_NET_DSA_MT7530)	+= hnat_stag.o
++endif
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-2739-drivers_net_phy_add_an8855_gsw.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-2739-drivers_net_phy_add_an8855_gsw.patch
new file mode 100644
index 0000000..58220b3
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-2739-drivers_net_phy_add_an8855_gsw.patch
@@ -0,0 +1,24 @@
+Index: linux-5.4.238/drivers/net/phy/Kconfig
+===================================================================
+--- linux-5.4.238.orig/drivers/net/phy/Kconfig	2023-12-19 12:20:34.714805000 +0800
++++ linux-5.4.238/drivers/net/phy/Kconfig	2023-12-25 10:11:11.328554000 +0800
+@@ -337,6 +337,8 @@
+ 
+ source "drivers/net/phy/mtk/mt753x/Kconfig"
+ 
++source "drivers/net/phy/airoha/an8855/Kconfig"
++
+ comment "MII PHY device drivers"
+ 
+ config SFP
+Index: linux-5.4.238/drivers/net/phy/Makefile
+===================================================================
+--- linux-5.4.238.orig/drivers/net/phy/Makefile	2023-12-19 12:20:34.718809000 +0800
++++ linux-5.4.238/drivers/net/phy/Makefile	2023-12-25 10:13:11.891535000 +0800
+@@ -121,5 +121,6 @@
+ obj-$(CONFIG_VITESSE_PHY)	+= vitesse.o
+ obj-$(CONFIG_XILINX_GMII2RGMII) += xilinx_gmii2rgmii.o
+ obj-$(CONFIG_MT753X_GSW)        += mtk/mt753x/
++obj-$(CONFIG_AN8855_GSW)        += airoha/an8855/
+ obj-$(CONFIG_RTL8367S_GSW)	+= rtk/
+ 
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-2739-net-phy-aquantia-add-CUX3410.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-2739-net-phy-aquantia-add-CUX3410.patch
new file mode 100644
index 0000000..fcd1fee
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-2739-net-phy-aquantia-add-CUX3410.patch
@@ -0,0 +1,160 @@
+diff --git a/drivers/net/phy/aquantia.h b/drivers/net/phy/aquantia.h
+index f46d95f..135b103 100644
+--- a/drivers/net/phy/aquantia.h
++++ b/drivers/net/phy/aquantia.h
+@@ -81,6 +81,8 @@ struct aqr107_priv {
+ int aqr107_set_downshift(struct phy_device *phydev, u8 cnt);
+ void aqr107_chip_info(struct phy_device *phydev);
+ int aqr107_config_mdi(struct phy_device *phydev);
++int aqr107_config_usx_aneg_en(struct phy_device *phydev);
++int aqr107_config_led(struct phy_device *phydev);
+ 
+ #if IS_REACHABLE(CONFIG_HWMON)
+ int aqr_hwmon_probe(struct phy_device *phydev);
+diff --git a/drivers/net/phy/aquantia_firmware.c b/drivers/net/phy/aquantia_firmware.c
+index b4ce32f..f37bee1 100644
+--- a/drivers/net/phy/aquantia_firmware.c
++++ b/drivers/net/phy/aquantia_firmware.c
+@@ -973,6 +973,14 @@ retry:
+ 
+ 			aqr107_chip_info(phydevs[i]);
+ 
++			ret = aqr107_config_usx_aneg_en(phydevs[i]);
++			if (ret)
++				dev_err(dev, "USX autonegotiation disabled, ret: %d\n", ret);
++
++			ret = aqr107_config_led(phydevs[i]);
++			if (ret)
++				dev_err(dev, "LED configuration failed, ret: %d\n", ret);
++
+ 			aqr107_config_mdi(phydevs[i]);
+ 
+ 			aqr107_set_downshift(phydevs[i],
+diff --git a/drivers/net/phy/aquantia_main.c b/drivers/net/phy/aquantia_main.c
+index e545b28..f445ef9 100644
+--- a/drivers/net/phy/aquantia_main.c
++++ b/drivers/net/phy/aquantia_main.c
+@@ -25,6 +25,7 @@
+ #define PHY_ID_AQCS109	0x03a1b5c2
+ #define PHY_ID_AQR405	0x03a1b4b0
+ #define PHY_ID_AQR113C	0x31c31c12
++#define PHY_ID_CUX3410	0x31c31dd3
+ 
+ #define MDIO_PHYXS_VEND_IF_STATUS		0xe812
+ #define MDIO_PHYXS_VEND_IF_STATUS_TYPE_MASK	GENMASK(7, 3)
+@@ -34,6 +35,9 @@
+ #define MDIO_PHYXS_VEND_IF_STATUS_TYPE_SGMII	6
+ #define MDIO_PHYXS_VEND_IF_STATUS_TYPE_OCSGMII	10
+ 
++#define MDIO_PHYXS_TX_RSVD_VEND_PROV2           0xc441
++#define MDIO_PHYXS_TX_RSVD_VEND_PROV2_ANEG      BIT(3)
++
+ #define MDIO_AN_VEND_PROV			0xc400
+ #define MDIO_AN_VEND_PROV_1000BASET_FULL	BIT(15)
+ #define MDIO_AN_VEND_PROV_1000BASET_HALF	BIT(14)
+@@ -113,6 +117,16 @@
+ #define VEND1_GLOBAL_INT_VEND_MASK_GLOBAL2	BIT(1)
+ #define VEND1_GLOBAL_INT_VEND_MASK_GLOBAL3	BIT(0)
+ 
++#define VEND1_GLOBAL_LED_PROV(x)		(0xc430 + (x - 1))
++#define VEND1_GLOBAL_LED_5000_LINK_EST		BIT(15)
++#define VEND1_GLOBAL_LED_2500_LINK_EST		BIT(14)
++#define VEND1_GLOBAL_LED_10G_LINK_EST		BIT(7)
++#define VEND1_GLOBAL_LED_1000_LINK_EST		BIT(6)
++#define VEND1_GLOBAL_LED_100_LINK_EST		BIT(5)
++#define VEND1_GLOBAL_LED_PROV_RX_ACT		BIT(3)
++#define VEND1_GLOBAL_LED_PROV_TX_ACT		BIT(2)
++#define VEND1_GLOBAL_LED_PROV_ACT_STRETCH_MASK	GENMASK(1, 0)
++
+ static int aqr107_get_sset_count(struct phy_device *phydev)
+ {
+ 	return AQR107_SGMII_STAT_SZ;
+@@ -170,6 +184,40 @@ static void aqr107_get_stats(struct phy_device *phydev,
+ 	}
+ }
+ 
++int aqr107_config_led(struct phy_device *phydev)
++{
++	u16 val;
++	int err;
++
++	val = phy_read_mmd(phydev, MDIO_MMD_VEND1, VEND1_GLOBAL_LED_PROV(1));
++	val |= VEND1_GLOBAL_LED_10G_LINK_EST;
++	err = phy_write_mmd(phydev, MDIO_MMD_VEND1, VEND1_GLOBAL_LED_PROV(1), val);
++	if (err < 0)
++		return err;
++
++	val = phy_read_mmd(phydev, MDIO_MMD_VEND1, VEND1_GLOBAL_LED_PROV(2));
++	val |= VEND1_GLOBAL_LED_100_LINK_EST | VEND1_GLOBAL_LED_1000_LINK_EST |
++	       VEND1_GLOBAL_LED_2500_LINK_EST | VEND1_GLOBAL_LED_5000_LINK_EST;
++	err = phy_write_mmd(phydev, MDIO_MMD_VEND1, VEND1_GLOBAL_LED_PROV(2), val);
++	if (err < 0)
++		return err;
++
++	val = phy_read_mmd(phydev, MDIO_MMD_VEND1, VEND1_GLOBAL_LED_PROV(3));
++	val |= VEND1_GLOBAL_LED_PROV_ACT_STRETCH_MASK |
++	       VEND1_GLOBAL_LED_PROV_TX_ACT | VEND1_GLOBAL_LED_PROV_RX_ACT;
++	return phy_write_mmd(phydev, MDIO_MMD_VEND1, VEND1_GLOBAL_LED_PROV(3), val);
++}
++
++int aqr107_config_usx_aneg_en(struct phy_device *phydev)
++{
++	u16 val;
++
++	val = phy_read_mmd(phydev, MDIO_MMD_PHYXS, MDIO_PHYXS_TX_RSVD_VEND_PROV2);
++	val |= MDIO_PHYXS_TX_RSVD_VEND_PROV2_ANEG;
++
++	return phy_write_mmd(phydev, MDIO_MMD_PHYXS, MDIO_PHYXS_TX_RSVD_VEND_PROV2, val);
++}
++
+ static int aqr_config_aneg(struct phy_device *phydev)
+ {
+ 	bool changed = false;
+@@ -483,6 +531,14 @@ static int aqr107_config_init(struct phy_device *phydev)
+ 		return aqr_firmware_download(phydev);
+ #endif
+ 
++	ret = aqr107_config_usx_aneg_en(phydev);
++	if (ret)
++		dev_err(&phydev->mdio.dev, "USX autonegotiation disabled, ret: %d\n", ret);
++
++	ret = aqr107_config_led(phydev);
++	if (ret)
++		dev_err(&phydev->mdio.dev, "LED configuration failed, ret: %d\n", ret);
++
+ 	aqr107_config_mdi(phydev);
+ 
+ 	return aqr107_set_downshift(phydev, MDIO_AN_VEND_PROV_DOWNSHIFT_DFLT);
+@@ -711,6 +767,24 @@ static struct phy_driver aqr_driver[] = {
+ 	.get_stats      = aqr107_get_stats,
+ 	.link_change_notify = aqr107_link_change_notify,
+ },
++{
++	PHY_ID_MATCH_MODEL(PHY_ID_CUX3410),
++	.name           = "Aquantia CUX3410",
++	.probe          = aqr107_probe,
++	.config_init    = aqr107_config_init,
++	.config_aneg    = aqr_config_aneg,
++	.config_intr    = aqr_config_intr,
++	.ack_interrupt  = aqr_ack_interrupt,
++	.read_status    = aqr107_read_status,
++	.get_tunable    = aqr107_get_tunable,
++	.set_tunable    = aqr107_set_tunable,
++	.suspend        = aqr107_suspend,
++	.resume         = aqr107_resume,
++	.get_sset_count = aqr107_get_sset_count,
++	.get_strings    = aqr107_get_strings,
++	.get_stats      = aqr107_get_stats,
++	.link_change_notify = aqr107_link_change_notify,
++},
+ };
+ 
+ module_phy_driver(aqr_driver);
+@@ -724,6 +798,7 @@ static struct mdio_device_id __maybe_unused aqr_tbl[] = {
+ 	{ PHY_ID_MATCH_MODEL(PHY_ID_AQCS109) },
+ 	{ PHY_ID_MATCH_MODEL(PHY_ID_AQR405) },
+ 	{ PHY_ID_MATCH_MODEL(PHY_ID_AQR113C) },
++	{ PHY_ID_MATCH_MODEL(PHY_ID_CUX3410) },
+ 	{ }
+ };
+ 
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-2739-net_dsa_add_tag_arht.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-2739-net_dsa_add_tag_arht.patch
new file mode 100644
index 0000000..ca36a0c
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-2739-net_dsa_add_tag_arht.patch
@@ -0,0 +1,46 @@
+Index: linux-5.4.238/net/dsa/Makefile
+===================================================================
+--- linux-5.4.238.orig/net/dsa/Makefile	2023-12-09 09:43:04.335694000 +0800
++++ linux-5.4.238/net/dsa/Makefile	2023-12-09 10:24:27.672514000 +0800
+@@ -16,3 +16,4 @@
+ obj-$(CONFIG_NET_DSA_TAG_QCA) += tag_qca.o
+ obj-$(CONFIG_NET_DSA_TAG_SJA1105) += tag_sja1105.o
+ obj-$(CONFIG_NET_DSA_TAG_TRAILER) += tag_trailer.o
++obj-$(CONFIG_NET_DSA_TAG_AIROHA) += tag_arht.o
+Index: linux-5.4.238/net/dsa/Kconfig
+===================================================================
+--- linux-5.4.238.orig/net/dsa/Kconfig	2023-12-09 09:43:04.332694000 +0800
++++ linux-5.4.238/net/dsa/Kconfig	2023-12-09 10:26:13.596504000 +0800
+@@ -74,6 +74,12 @@
+ 	  Say Y or M if you want to enable support for tagging frames for
+ 	  Mediatek switches.
+ 
++config NET_DSA_TAG_AIROHA
++	tristate "Tag driver for Airoha switches"
++	help
++	  Say Y or M if you want to enable support for tagging frames for
++	  Airoha switches.
++
+ config NET_DSA_TAG_KSZ
+ 	tristate "Tag driver for Microchip 8795/9477/9893 families of switches"
+ 	help
+Index: linux-5.4.238/include/net/dsa.h
+===================================================================
+--- linux-5.4.238.orig/include/net/dsa.h	2023-12-09 09:43:17.940694000 +0800
++++ linux-5.4.238/include/net/dsa.h	2023-12-09 10:30:06.432504000 +0800
+@@ -43,6 +43,7 @@
+ #define DSA_TAG_PROTO_SJA1105_VALUE		13
+ #define DSA_TAG_PROTO_KSZ8795_VALUE		14
+ #define DSA_TAG_PROTO_RTL4_A_VALUE		17
++#define DSA_TAG_PROTO_ARHT_VALUE		28
+ 
+ enum dsa_tag_protocol {
+ 	DSA_TAG_PROTO_NONE		= DSA_TAG_PROTO_NONE_VALUE,
+@@ -61,6 +62,7 @@
+ 	DSA_TAG_PROTO_SJA1105		= DSA_TAG_PROTO_SJA1105_VALUE,
+ 	DSA_TAG_PROTO_KSZ8795		= DSA_TAG_PROTO_KSZ8795_VALUE,
+ 	DSA_TAG_PROTO_RTL4_A		= DSA_TAG_PROTO_RTL4_A_VALUE,
++	DSA_TAG_PROTO_ARHT		= DSA_TAG_PROTO_ARHT_VALUE,
+ };
+ 
+ struct packet_type;
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/patches-5.4.inc b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/patches-5.4.inc
index e5109db..38511b9 100644
--- a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/patches-5.4.inc
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/patches-5.4.inc
@@ -35,11 +35,16 @@
     file://1010-pcie-mediatek-fix-clearing-interrupt-status.patch \
     file://1020-spi-nor-w25q512jv.patch \
     file://1021-ubnt-ledbar-driver.patch \
+    file://999-1021-v5.7-iopoll-introduce-read_poll_timeout-macro.patch \
     file://999-1050-v6.4-backport-jitterrng-2.2.0.patch;apply=no \
     file://999-1051-v5.10-backport-libkcapi.patch \
+    file://999-1400-v5.16-spi-add-power-control-when-set_cs.patch \
     file://999-1401-v5.7-mtd-spinand-backport-winbond-and-base-file.patch \
     file://999-1402-v6.4-mtd-spinand-backport-series-flash.patch \
     file://999-1600-v5.18-mdiobus-add-c45.patch \
+    file://999-1700-v5.8-net-phy-add-concept-of-shared-storage-for-PHYs.patch \
+    file://999-1701-v5.8-net-phy-add-concept-of-shared-storage-for-PHYs.patch \
+    file://999-1702-v6.4-backport-mediatek-ge-and-mediatek-ge-soc.patch \
     file://999-1703-v5.18-mxl-gpy-phy-support.patch \
     file://999-1704-v6.2-net-phy-aquantia-add-AQR113C.patch \
     file://999-1708-v6.2-net-phy-add-5GBASER.patch \
@@ -124,6 +129,8 @@
     file://999-2153-sound-add-si3218x-spi-driver.patch \
     file://999-2300-mtk-sd-add-mt7986-support.patch \
     file://999-2301-mtk-sd-Add-subsys-clock-control.patch \
+    file://999-2328-mtd-add-nmbm-support.patch \
+    file://999-2329-ubi-add-configurable-rootdev.patch \
     file://999-2330-mtd-spinand-winbond-Support-for-W25MxxGV-W25NxxKV-series.patch \
     file://999-2331-mtd-spinand-macronix-suppress-mx35lf1ge4ab-warning-log.patch \
     file://999-2332-mtd-add-mtk-snand-driver.patch \
@@ -134,6 +141,7 @@
     file://999-2341-mtd-spinand-Add-support-etron.patch \
     file://999-2342-drivers-mtd-spi-nor-Add-support-EN25QX256A-2S.patch \
     file://999-2343-mtd-spinand-gigadevice-Add-support-for-F50L1G41LB.patch \
+    file://999-2344-mtd-spinand-Add-support-fudanmicro.patch \
     file://999-2350-nvmem-core-Add-functions-to-make-number-reading-easy.patch \
     file://999-2351-nvmem-mtk-efuse-support-minimum-one-byte-access-stri.patch \
     file://999-2361-add-spimem-support-to-mtk-spi.patch \
@@ -159,6 +167,7 @@
     file://999-2503-cpufreq-mtk-vbining-add-mt7988-support.patch \
     file://999-2530-add-pmic-config.patch \
     file://999-2531-iio-add-zts8032-config.patch \
+    file://999-2540-cmdline-boot-parameters.patch \
     file://999-2550-dual-image-mount-rootfs.patch \
     file://999-2600-pcie-add-pcie-gen3-upstream-driver.patch \
     file://999-2601-pcie-add-multi-MSI-support.patch \
@@ -171,6 +180,7 @@
     file://999-2620-xHCI-change-compliance-mode-de-emphasis-default-as-g.patch \
     file://999-2621-xHCI-MT7986-USB-2.0-USBIF-compliance-toolkit.patch \
     file://999-2622-usb-add-embedded-Host-feature-support.patch \
+    file://999-2700-netfilter_optional_tcp_window_check.patch \
     file://999-2704-en8811h-2p5gphy-support.patch \
     file://999-2705-hwnat_Kconfig_Makefile.patch \
     file://999-2706-crypto-add-eip197-inside-secure-support.patch \
@@ -202,6 +212,11 @@
     file://999-2737-net-mt753x-phy-coverity-scan.patch;apply=no \
     file://999-2738-an8801sb-gphy-support.patch \
     file://999-2738-net-pptp-bypass-seq-check.patch \
+    file://999-2739-drivers_net_dsa_add_an8855.patch \
+    file://999-2739-drivers_net_ethernet_mediatek_hnat.patch;apply=no \
+    file://999-2739-drivers_net_phy_add_an8855_gsw.patch \
+    file://999-2739-net-phy-aquantia-add-CUX3410.patch \
+    file://999-2739-net_dsa_add_tag_arht.patch \
     file://999-2800-misc-add-mtk-platform.patch \
     file://999-2850-fips-140-3-compliance.patch \
     file://999-2900-dts-mt7622-enable-new-mtk-snand-for-ubi.patch \
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/wed3/999-3019-mtk-wed-add-wed3-support.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/wed3/999-3019-mtk-wed-add-wed3-support.patch
deleted file mode 100644
index b90693d..0000000
--- a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/wed3/999-3019-mtk-wed-add-wed3-support.patch
+++ /dev/null
@@ -1,3755 +0,0 @@
-From 542064ad977706558be071e0f7d706f5aa37f390 Mon Sep 17 00:00:00 2001
-From: Sujuan Chen <sujuan.chen@mediatek.com>
-Date: Mon, 18 Sep 2023 13:21:15 +0800
-Subject: [PATCH 1/5] mtk:wed:add wed3 support
-
----
- arch/arm64/boot/dts/mediatek/mt7988.dtsi      |  152 ++-
- .../dts/mediatek/mt7988a-dsa-10g-spim-nor.dts |   16 +-
- .../dts/mediatek/mt7988d-dsa-10g-spim-nor.dts |   16 +-
- drivers/net/ethernet/mediatek/mtk_eth_soc.c   |    3 +-
- drivers/net/ethernet/mediatek/mtk_eth_soc.h   |    5 +-
- drivers/net/ethernet/mediatek/mtk_ppe.c       |   17 +-
- drivers/net/ethernet/mediatek/mtk_ppe.h       |    2 +-
- .../net/ethernet/mediatek/mtk_ppe_offload.c   |   16 +-
- drivers/net/ethernet/mediatek/mtk_wed.c       | 1178 +++++++++++++----
- drivers/net/ethernet/mediatek/mtk_wed.h       |   25 +-
- .../net/ethernet/mediatek/mtk_wed_debugfs.c   |  584 +++++++-
- drivers/net/ethernet/mediatek/mtk_wed_mcu.c   |   14 +-
- drivers/net/ethernet/mediatek/mtk_wed_mcu.h   |    5 +-
- drivers/net/ethernet/mediatek/mtk_wed_regs.h  |  338 ++++-
- include/linux/netdevice.h                     |    7 +
- include/linux/soc/mediatek/mtk_wed.h          |   83 +-
- 16 files changed, 2070 insertions(+), 391 deletions(-)
- mode change 100755 => 100644 drivers/net/ethernet/mediatek/mtk_ppe.c
-
-diff --git a/arch/arm64/boot/dts/mediatek/mt7988.dtsi b/arch/arm64/boot/dts/mediatek/mt7988.dtsi
-index 7e96640..3368240 100644
---- a/arch/arm64/boot/dts/mediatek/mt7988.dtsi
-+++ b/arch/arm64/boot/dts/mediatek/mt7988.dtsi
-@@ -193,44 +193,49 @@
- 		status = "disabled";
- 	};
- 
--	wed: wed@15010000 {
--		compatible = "mediatek,wed";
--		wed_num = <3>;
--		/* add this property for wed get the pci slot number. */
--		pci_slot_map = <0>, <1>, <2>;
--		reg = <0 0x15010000 0 0x2000>,
--		      <0 0x15012000 0 0x2000>,
--		      <0 0x15014000 0 0x2000>;
-+	wed0: wed@15010000 {
-+		compatible = "mediatek,mt7988-wed",
-+			     "syscon";
-+		reg = <0 0x15010000 0 0x2000>;
- 		interrupt-parent = <&gic>;
--		interrupts = <GIC_SPI 205 IRQ_TYPE_LEVEL_HIGH>,
--			     <GIC_SPI 206 IRQ_TYPE_LEVEL_HIGH>,
--			     <GIC_SPI 270 IRQ_TYPE_LEVEL_HIGH>;
--	};
--
--	wed2: wed2@15012000 {
--		compatible = "mediatek,wed2";
--		wed_num = <3>;
--		/* add this property for wed get the pci slot number. */
--		reg = <0 0x15010000 0 0x2000>,
--		      <0 0x15012000 0 0x2000>,
--		      <0 0x15014000 0 0x2000>;
-+		interrupts = <GIC_SPI 205 IRQ_TYPE_LEVEL_HIGH>;
-+		mediatek,wed_pcie = <&wed_pcie>;
-+		mediatek,ap2woccif = <&ap2woccif0>;
-+		mediatek,wocpu_ilm = <&wocpu0_ilm>;
-+		mediatek,wocpu_dlm = <&wocpu0_dlm>;
-+		mediatek,wocpu_boot = <&cpu0_boot>;
-+		mediatek,wocpu_emi = <&wocpu0_emi>;
-+		mediatek,wocpu_data = <&wocpu_data>;
-+	};
-+
-+	wed1: wed@15012000 {
-+		compatible = "mediatek,mt7988-wed",
-+                             "syscon";
-+		reg = <0 0x15012000 0 0x2000>;
- 		interrupt-parent = <&gic>;
--		interrupts = <GIC_SPI 205 IRQ_TYPE_LEVEL_HIGH>,
--			     <GIC_SPI 206 IRQ_TYPE_LEVEL_HIGH>,
--			     <GIC_SPI 270 IRQ_TYPE_LEVEL_HIGH>;
--	};
--
--	wed3: wed3@15014000 {
--		compatible = "mediatek,wed3";
--		wed_num = <3>;
--		/* add this property for wed get the pci slot number. */
--		reg = <0 0x15010000 0 0x2000>,
--		      <0 0x15012000 0 0x2000>,
--		      <0 0x15014000 0 0x2000>;
-+		interrupts = <GIC_SPI 206 IRQ_TYPE_LEVEL_HIGH>;
-+		mediatek,wed_pcie = <&wed_pcie>;
-+		mediatek,ap2woccif = <&ap2woccif1>;
-+		mediatek,wocpu_ilm = <&wocpu1_ilm>;
-+		mediatek,wocpu_dlm = <&wocpu1_dlm>;
-+		mediatek,wocpu_boot = <&cpu1_boot>;
-+		mediatek,wocpu_emi = <&wocpu1_emi>;
-+		mediatek,wocpu_data = <&wocpu_data>;
-+	};
-+
-+	wed2: wed@15014000 {
-+		compatible = "mediatek,mt7988-wed",
-+                             "syscon";
-+		reg = <0 0x15014000 0 0x2000>;
- 		interrupt-parent = <&gic>;
--		interrupts = <GIC_SPI 205 IRQ_TYPE_LEVEL_HIGH>,
--			     <GIC_SPI 206 IRQ_TYPE_LEVEL_HIGH>,
--			     <GIC_SPI 270 IRQ_TYPE_LEVEL_HIGH>;
-+		interrupts = <GIC_SPI 207 IRQ_TYPE_LEVEL_HIGH>;
-+		mediatek,wed_pcie = <&wed_pcie>;
-+		mediatek,ap2woccif = <&ap2woccif2>;
-+		mediatek,wocpu_ilm = <&wocpu2_ilm>;
-+		mediatek,wocpu_dlm = <&wocpu2_dlm>;
-+		mediatek,wocpu_boot = <&cpu2_boot>;
-+		mediatek,wocpu_emi = <&wocpu2_emi>;
-+		mediatek,wocpu_data = <&wocpu_data>;
- 	};
- 
- 	wdma: wdma@15104800 {
-@@ -240,15 +245,25 @@
- 		      <0 0x15105000 0 0x400>;
- 	};
- 
--	ap2woccif: ap2woccif@151A5000 {
--		compatible = "mediatek,ap2woccif";
--		reg = <0 0x151A5000 0 0x1000>,
--		      <0 0x152A5000 0 0x1000>,
--		      <0 0x153A5000 0 0x1000>;
-+	ap2woccif0: ap2woccif@151A5000 {
-+		compatible = "mediatek,ap2woccif", "syscon";
-+		reg = <0 0x151A5000 0 0x1000>;
-+		interrupt-parent = <&gic>;
-+		interrupts = <GIC_SPI 211 IRQ_TYPE_LEVEL_HIGH>;
-+	};
-+
-+	ap2woccif1: ap2woccif@152A5000 {
-+		compatible = "mediatek,ap2woccif", "syscon";
-+		reg = <0 0x152A5000 0 0x1000>;
- 		interrupt-parent = <&gic>;
--		interrupts = <GIC_SPI 211 IRQ_TYPE_LEVEL_HIGH>,
--			     <GIC_SPI 212 IRQ_TYPE_LEVEL_HIGH>,
--			     <GIC_SPI 272 IRQ_TYPE_LEVEL_HIGH>;
-+		interrupts = <GIC_SPI 212 IRQ_TYPE_LEVEL_HIGH>;
-+	};
-+
-+	ap2woccif2: ap2woccif@153A5000 {
-+		compatible = "mediatek,ap2woccif", "syscon";
-+		reg = <0 0x153A5000 0 0x1000>;
-+		interrupt-parent = <&gic>;
-+		interrupts = <GIC_SPI 272 IRQ_TYPE_LEVEL_HIGH>;
- 	};
- 
- 	wocpu0_ilm: wocpu0_ilm@151E0000 {
-@@ -256,31 +271,53 @@
- 		reg = <0 0x151E0000 0 0x8000>;
- 	};
- 
--	wocpu1_ilm: wocpu1_ilm@152E0000 {
--		compatible = "mediatek,wocpu1_ilm";
-+	wocpu1_ilm: wocpu_ilm@152E0000 {
-+		compatible = "mediatek,wocpu_ilm";
- 		reg = <0 0x152E0000 0 0x8000>;
- 	};
- 
--	wocpu2_ilm: wocpu2_ilm@153E0000 {
--		compatible = "mediatek,wocpu2_ilm";
--		reg = <0 0x153E0000 0 0x8000>;
-+	wocpu2_ilm: wocpu_ilm@153E0000 {
-+                compatible = "mediatek,wocpu_ilm";
-+                reg = <0 0x153E0000 0 0x8000>;
-+    };
-+
-+	wocpu0_dlm: wocpu_dlm@151E8000 {
-+		compatible = "mediatek,wocpu_dlm";
-+		reg = <0 0x151E8000 0 0x2000>;
-+
-+		resets = <&ethsysrst 0>;
-+		reset-names = "wocpu_rst";
-+	};
-+
-+	wocpu1_dlm: wocpu_dlm@0x152E8000 {
-+		compatible = "mediatek,wocpu_dlm";
-+		reg = <0 0x152E8000 0 0x2000>;
-+
-+		resets = <&ethsysrst 0>;
-+		reset-names = "wocpu_rst";
- 	};
- 
--	wocpu_dlm: wocpu_dlm@151E8000 {
-+	wocpu2_dlm: wocpu_dlm@0x153E8000 {
- 		compatible = "mediatek,wocpu_dlm";
--		reg = <0 0x151E8000 0 0x2000>,
--		      <0 0x152E8000 0 0x2000>,
--		      <0 0x153E8000 0 0x2000>;
-+		reg = <0 0x153E8000 0 0x2000>;
- 
- 		resets = <&ethsysrst 0>;
- 		reset-names = "wocpu_rst";
- 	};
- 
--	cpu_boot: wocpu_boot@15194000 {
--		compatible = "mediatek,wocpu_boot";
--		reg = <0 0x15194000 0 0x1000>,
--		      <0 0x15294000 0 0x1000>,
--		      <0 0x15394000 0 0x1000>;
-+	cpu0_boot: wocpu_boot@15194000 {
-+		compatible = "mediatek,wocpu0_boot";
-+		reg = <0 0x15194000 0 0x1000>;
-+	};
-+
-+	cpu1_boot: wocpu_boot@15294000 {
-+		compatible = "mediatek,wocpu1_boot";
-+		reg = <0 0x15294000 0 0x1000>;
-+	};
-+
-+	cpu2_boot: wocpu_boot@15394000 {
-+		compatible = "mediatek,wocpu2_boot";
-+		reg = <0 0x15394000 0 0x1000>;
- 	};
- 
- 	reserved-memory {
-@@ -901,6 +938,7 @@
- 					 <&topckgen CK_TOP_CB_NET2_D2>;
- 		mediatek,ethsys = <&ethsys>;
- 		mediatek,sgmiisys = <&sgmiisys0>, <&sgmiisys1>;
-+		mediatek,wed = <&wed0>, <&wed1>, <&wed2>;
- 		mediatek,usxgmiisys = <&usxgmiisys0>, <&usxgmiisys1>;
- 		mediatek,xfi_pextp = <&xfi_pextp0>, <&xfi_pextp1>;
- 		mediatek,xfi_pll = <&xfi_pll>;
-diff --git a/arch/arm64/boot/dts/mediatek/mt7988a-dsa-10g-spim-nor.dts b/arch/arm64/boot/dts/mediatek/mt7988a-dsa-10g-spim-nor.dts
-index 578a489..596f0ca 100644
---- a/arch/arm64/boot/dts/mediatek/mt7988a-dsa-10g-spim-nor.dts
-+++ b/arch/arm64/boot/dts/mediatek/mt7988a-dsa-10g-spim-nor.dts
-@@ -369,9 +369,23 @@
- 	status = "okay";
- };
- 
--&wed {
-+&wed0 {
- 	dy_txbm_enable = "true";
- 	dy_txbm_budge = <8>;
- 	txbm_init_sz = <10>;
- 	status = "okay";
- };
-+
-+&wed1 {
-+	dy_txbm_enable = "true";
-+	dy_txbm_budge = <8>;
-+	txbm_init_sz = <10>;
-+	status = "okay";
-+};
-+
-+&wed2 {
-+	dy_txbm_enable = "true";
-+	dy_txbm_budge = <8>;
-+	txbm_init_sz = <10>;
-+	status = "okay";
-+};
-\ No newline at end of file
-diff --git a/arch/arm64/boot/dts/mediatek/mt7988d-dsa-10g-spim-nor.dts b/arch/arm64/boot/dts/mediatek/mt7988d-dsa-10g-spim-nor.dts
-index e743718..f430118 100644
---- a/arch/arm64/boot/dts/mediatek/mt7988d-dsa-10g-spim-nor.dts
-+++ b/arch/arm64/boot/dts/mediatek/mt7988d-dsa-10g-spim-nor.dts
-@@ -381,9 +381,23 @@
- 	status = "okay";
- };
- 
--&wed {
-+&wed0 {
- 	dy_txbm_enable = "true";
- 	dy_txbm_budge = <8>;
- 	txbm_init_sz = <10>;
- 	status = "okay";
- };
-+
-+&wed1 {
-+	dy_txbm_enable = "true";
-+	dy_txbm_budge = <8>;
-+	txbm_init_sz = <10>;
-+	status = "okay";
-+};
-+
-+&wed2 {
-+	dy_txbm_enable = "true";
-+	dy_txbm_budge = <8>;
-+	txbm_init_sz = <10>;
-+	status = "okay";
-+};
-\ No newline at end of file
-diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.c b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
-index c75ce25..ec78adf 100644
---- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c
-+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
-@@ -5216,7 +5216,8 @@ static int mtk_probe(struct platform_device *pdev)
- 							  "mediatek,wed", i);
- 		static const u32 wdma_regs[] = {
- 			MTK_WDMA0_BASE,
--			MTK_WDMA1_BASE
-+			MTK_WDMA1_BASE,
-+			MTK_WDMA2_BASE
- 		};
- 		void __iomem *wdma;
- 		u32 wdma_phy;
-diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.h b/drivers/net/ethernet/mediatek/mtk_eth_soc.h
-index 1074f46..a788d43 100644
---- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h
-+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h
-@@ -623,9 +623,12 @@
- #define RX_DMA_SPORT_MASK       0x7
- #define RX_DMA_SPORT_MASK_V2    0xf
- 
--#if defined(CONFIG_MEDIATEK_NETSYS_V2)
-+#if defined(CONFIG_MEDIATEK_NETSYS_V2) || defined(CONFIG_MEDIATEK_NETSYS_V3)
- #define MTK_WDMA0_BASE		0x4800
- #define MTK_WDMA1_BASE		0x4c00
-+#if defined(CONFIG_MEDIATEK_NETSYS_V3)
-+#define MTK_WDMA2_BASE		0x5000
-+#endif
- #else
- #define MTK_WDMA0_BASE		0x2800
- #define MTK_WDMA1_BASE		0x2c00
-diff --git a/drivers/net/ethernet/mediatek/mtk_ppe.c b/drivers/net/ethernet/mediatek/mtk_ppe.c
-old mode 100755
-new mode 100644
-index 0e9c0bd..ae0acd5
---- a/drivers/net/ethernet/mediatek/mtk_ppe.c
-+++ b/drivers/net/ethernet/mediatek/mtk_ppe.c
-@@ -9,6 +9,7 @@
- #include <linux/if_ether.h>
- #include <linux/if_vlan.h>
- #include <net/dsa.h>
-+#include <net/route.h>
- #include "mtk_eth_soc.h"
- #include "mtk_ppe.h"
- #include "mtk_ppe_regs.h"
-@@ -407,7 +408,7 @@ int mtk_foe_entry_set_pppoe(struct mtk_foe_entry *entry, int sid)
- }
- 
- int mtk_foe_entry_set_wdma(struct mtk_foe_entry *entry, int wdma_idx, int txq,
--			   int bss, int wcid)
-+			   int bss, int wcid, bool amsdu_en)
- {
- 	struct mtk_foe_mac_info *l2 = mtk_foe_entry_l2(entry);
- 	u32 *ib2 = mtk_foe_entry_ib2(entry);
-@@ -419,6 +420,9 @@ int mtk_foe_entry_set_wdma(struct mtk_foe_entry *entry, int wdma_idx, int txq,
- 
- 	l2->winfo = FIELD_PREP(MTK_FOE_WINFO_WCID, wcid) |
- 		    FIELD_PREP(MTK_FOE_WINFO_BSS, bss);
-+#if defined(CONFIG_MEDIATEK_NETSYS_V3)
-+	l2->winfo_pao = FIELD_PREP(MTK_FOE_WINFO_PAO_AMSDU_EN, amsdu_en);
-+#endif
- #else
- 	if (wdma_idx)
- 		*ib2 |= MTK_FOE_IB2_WDMA_DEVIDX;
-@@ -454,6 +458,17 @@ int mtk_foe_entry_set_dscp(struct mtk_foe_entry *entry, int dscp)
- 	*ib2 &= ~MTK_FOE_IB2_DSCP;
- 	*ib2 |= FIELD_PREP(MTK_FOE_IB2_DSCP, dscp);
- 
-+#if defined(CONFIG_MEDIATEK_NETSYS_V3)
-+	struct mtk_foe_mac_info *l2 = mtk_foe_entry_l2(entry);
-+
-+	if (*ib2 & MTK_FOE_IB2_WDMA_WINFO &&
-+	    l2->winfo_pao & MTK_FOE_WINFO_PAO_AMSDU_EN) {
-+		u8 tid = (dscp >> 5) & 0xf;
-+
-+		l2->winfo_pao |= FIELD_PREP(MTK_FOE_WINFO_PAO_TID, tid);
-+	}
-+#endif
-+
- 	return 0;
- }
- 
-diff --git a/drivers/net/ethernet/mediatek/mtk_ppe.h b/drivers/net/ethernet/mediatek/mtk_ppe.h
-index 2a8b6ef..66c7f10 100644
---- a/drivers/net/ethernet/mediatek/mtk_ppe.h
-+++ b/drivers/net/ethernet/mediatek/mtk_ppe.h
-@@ -428,7 +428,7 @@ int mtk_foe_entry_set_dsa(struct mtk_foe_entry *entry, int port);
- int mtk_foe_entry_set_vlan(struct mtk_foe_entry *entry, int vid);
- int mtk_foe_entry_set_pppoe(struct mtk_foe_entry *entry, int sid);
- int mtk_foe_entry_set_wdma(struct mtk_foe_entry *entry, int wdma_idx, int txq,
--			   int bss, int wcid);
-+			   int bss, int wcid, bool amsdu_en);
- int mtk_foe_entry_set_qid(struct mtk_foe_entry *entry, int qid);
- int mtk_foe_entry_set_dscp(struct mtk_foe_entry *entry, int dscp);
- bool mtk_foe_entry_match(struct mtk_foe_entry *entry, struct mtk_foe_entry *data);
-diff --git a/drivers/net/ethernet/mediatek/mtk_ppe_offload.c b/drivers/net/ethernet/mediatek/mtk_ppe_offload.c
-index 95174b7..339359e 100644
---- a/drivers/net/ethernet/mediatek/mtk_ppe_offload.c
-+++ b/drivers/net/ethernet/mediatek/mtk_ppe_offload.c
-@@ -112,6 +112,7 @@ mtk_flow_get_wdma_info(struct net_device *dev, const u8 *addr, struct mtk_wdma_i
- 	info->queue = path.mtk_wdma.queue;
- 	info->bss = path.mtk_wdma.bss;
- 	info->wcid = path.mtk_wdma.wcid;
-+	info->amsdu_en = path.mtk_wdma.amsdu_en;
- 
- 	return 0;
- }
-@@ -193,13 +194,15 @@ mtk_flow_set_output_device(struct mtk_eth *eth, struct mtk_foe_entry *foe,
- 
- 	if (mtk_flow_get_wdma_info(dev, dest_mac, &info) == 0) {
- 		mtk_foe_entry_set_wdma(foe, info.wdma_idx, info.queue, info.bss,
--				       info.wcid);
-+				       info.wcid, info.amsdu_en);
- 		pse_port = PSE_PPE0_PORT;
- #if defined(CONFIG_MEDIATEK_NETSYS_V2) || defined(CONFIG_MEDIATEK_NETSYS_V3)
- 		if (info.wdma_idx == 0)
- 			pse_port = PSE_WDMA0_PORT;
- 		else if (info.wdma_idx == 1)
- 			pse_port = PSE_WDMA1_PORT;
-+		else if (info.wdma_idx == 2)
-+			pse_port = PSE_WDMA2_PORT;
- 		else
- 			return -EOPNOTSUPP;
- #endif
-@@ -481,8 +484,6 @@ mtk_flow_offload_replace(struct mtk_eth *eth, struct flow_cls_offload *f)
- 	if (data.pppoe.num == 1)
- 		mtk_foe_entry_set_pppoe(&foe, data.pppoe.sid);
- 
--	mtk_foe_entry_set_dscp(&foe, dscp);
--
- 	mtk_foe_entry_set_sp(eth->ppe[ppe_index], &foe);
- 
- 	err = mtk_flow_set_output_device(eth, &foe, odev, f->flow->ct, data.eth.h_dest,
-@@ -490,8 +491,9 @@ mtk_flow_offload_replace(struct mtk_eth *eth, struct flow_cls_offload *f)
- 	if (err)
- 		return err;
- 
--	if (wed_index >= 0 && (err = mtk_wed_flow_add(wed_index)) < 0)
--		return err;
-+	mtk_foe_entry_set_dscp(&foe, dscp);
-+	/*if (wed_index >= 0 && (err = mtk_wed_flow_add(wed_index)) < 0)
-+		return err;*/
- 
- 	entry = kzalloc(sizeof(*entry), GFP_KERNEL);
- 	if (!entry)
-@@ -516,8 +518,8 @@ mtk_flow_offload_replace(struct mtk_eth *eth, struct flow_cls_offload *f)
- 	mtk_foe_entry_clear(eth->ppe[ppe_index], entry);
- free:
- 	kfree(entry);
--	if (wed_index >= 0)
--	    mtk_wed_flow_remove(wed_index);
-+	/*if (wed_index >= 0)
-+	    mtk_wed_flow_remove(wed_index);*/
- 	return err;
- }
- 
-diff --git a/drivers/net/ethernet/mediatek/mtk_wed.c b/drivers/net/ethernet/mediatek/mtk_wed.c
-index 48c35ae..561fc6c 100644
---- a/drivers/net/ethernet/mediatek/mtk_wed.c
-+++ b/drivers/net/ethernet/mediatek/mtk_wed.c
-@@ -28,7 +28,7 @@ struct wo_cmd_ring {
- 	u32 cnt;
- 	u32 unit;
- };
--static struct mtk_wed_hw *hw_list[2];
-+static struct mtk_wed_hw *hw_list[3];
- static DEFINE_MUTEX(hw_lock);
- 
- static void
-@@ -73,6 +73,26 @@ mtk_wdma_read_reset(struct mtk_wed_device *dev)
- 	return wdma_r32(dev, MTK_WDMA_GLO_CFG);
- }
- 
-+static u32
-+mtk_wed_check_busy(struct mtk_wed_device *dev, u32 reg, u32 mask)
-+{
-+	if (wed_r32(dev, reg) & mask)
-+		return true;
-+
-+	return false;
-+}
-+
-+static int
-+mtk_wed_poll_busy(struct mtk_wed_device *dev, u32 reg, u32 mask)
-+{
-+	int sleep = 1000;
-+	int timeout = 100 * sleep;
-+	u32 val;
-+
-+	return read_poll_timeout(mtk_wed_check_busy, val, !val, sleep,
-+				 timeout, false, dev, reg, mask);
-+}
-+
- static int
- mtk_wdma_rx_reset(struct mtk_wed_device *dev)
- {
-@@ -235,6 +255,8 @@ mtk_wed_assign(struct mtk_wed_device *dev)
- 			continue;
- 
- 		hw->wed_dev = dev;
-+		hw->pci_base = MTK_WED_PCIE_BASE;
-+
- 		return hw;
- 	}
- 
-@@ -242,23 +264,84 @@ mtk_wed_assign(struct mtk_wed_device *dev)
- }
- 
- static int
--mtk_wed_buffer_alloc(struct mtk_wed_device *dev)
-+mtk_wed_pao_buffer_alloc(struct mtk_wed_device *dev)
-+{
-+	struct mtk_wed_pao *pao;
-+	int i, j;
-+
-+	pao = kzalloc(sizeof(struct mtk_wed_pao), GFP_KERNEL);
-+	if (!pao)
-+		return -ENOMEM;
-+
-+	dev->hw->wed_pao = pao;
-+
-+	for (i = 0; i < 32; i++) {
-+		/* each segment is 64K*/
-+		pao->hif_txd[i] = (char *)__get_free_pages(GFP_ATOMIC |
-+							   GFP_DMA32 |
-+							   __GFP_ZERO, 4);
-+		if (!pao->hif_txd[i])
-+			goto err;
-+
-+		pao->hif_txd_phys[i] = dma_map_single(dev->hw->dev,
-+						      pao->hif_txd[i],
-+						      16 * PAGE_SIZE,
-+						      DMA_TO_DEVICE);
-+		if (unlikely(dma_mapping_error(dev->hw->dev,
-+					       pao->hif_txd_phys[i])))
-+			goto err;
-+	}
-+
-+	return 0;
-+
-+err:
-+	for (j = 0; j < i; j++)
-+		dma_unmap_single(dev->hw->dev, pao->hif_txd_phys[j],
-+			     16 * PAGE_SIZE, DMA_TO_DEVICE);
-+
-+	return -ENOMEM;
-+}
-+
-+static int
-+mtk_wed_pao_free_buffer(struct mtk_wed_device *dev)
-+{
-+	struct mtk_wed_pao *pao = dev->hw->wed_pao;
-+	int i;
-+
-+	for (i = 0; i < 32; i++) {
-+		dma_unmap_single(dev->hw->dev, pao->hif_txd_phys[i],
-+				 16 * PAGE_SIZE, DMA_TO_DEVICE);
-+		free_pages((unsigned long)pao->hif_txd[i], 4);
-+	}
-+
-+	return 0;
-+}
-+
-+static int
-+mtk_wed_tx_buffer_alloc(struct mtk_wed_device *dev)
- {
- 	struct mtk_wdma_desc *desc;
-+	void *desc_ptr;
- 	dma_addr_t desc_phys;
--	void **page_list;
-+	struct dma_page_info *page_list;
- 	u32 last_seg = MTK_WDMA_DESC_CTRL_LAST_SEG1;
- 	int token = dev->wlan.token_start;
--	int ring_size, n_pages, page_idx;
--	int i;
--
-+	int ring_size, pkt_nums, n_pages, page_idx;
-+	int i, ret = 0;
- 
- 	if (dev->ver == MTK_WED_V1) {
- 		ring_size = dev->wlan.nbuf & ~(MTK_WED_BUF_PER_PAGE - 1);
--	} else {
-+		pkt_nums = ring_size;
-+		dev->tx_buf_ring.desc_size = sizeof(struct mtk_wdma_desc);
-+	} else if (dev->hw->version == 2) {
- 		ring_size = MTK_WED_VLD_GROUP_SIZE * MTK_WED_PER_GROUP_PKT +
- 			    MTK_WED_WDMA_RING_SIZE * 2;
- 		last_seg = MTK_WDMA_DESC_CTRL_LAST_SEG0;
-+		dev->tx_buf_ring.desc_size = sizeof(struct mtk_wdma_desc);
-+	} else if (dev->hw->version == 3) {
-+		ring_size = MTK_WED_TX_BM_DMA_SIZE;
-+		pkt_nums = MTK_WED_TX_BM_PKT_CNT;
-+		dev->tx_buf_ring.desc_size = sizeof(struct mtk_rxbm_desc);
- 	}
- 
- 	n_pages = ring_size / MTK_WED_BUF_PER_PAGE;
-@@ -267,18 +350,20 @@ mtk_wed_buffer_alloc(struct mtk_wed_device *dev)
- 	if (!page_list)
- 		return -ENOMEM;
- 
--	dev->buf_ring.size = dev->wlan.nbuf & ~(MTK_WED_BUF_PER_PAGE - 1);
--	dev->buf_ring.pages = page_list;
-+	dev->tx_buf_ring.size = ring_size;
-+	dev->tx_buf_ring.pages = page_list;
-+	dev->tx_buf_ring.pkt_nums = pkt_nums;
- 
--	desc = dma_alloc_coherent(dev->hw->dev, ring_size * sizeof(*desc),
--				  &desc_phys, GFP_KERNEL);
--	if (!desc)
-+	desc_ptr = dma_alloc_coherent(dev->hw->dev,
-+				      ring_size * dev->tx_buf_ring.desc_size,
-+				      &desc_phys, GFP_KERNEL);
-+	if (!desc_ptr)
- 		return -ENOMEM;
- 
--	dev->buf_ring.desc = desc;
--	dev->buf_ring.desc_phys = desc_phys;
-+	dev->tx_buf_ring.desc = desc_ptr;
-+	dev->tx_buf_ring.desc_phys = desc_phys;
- 
--	for (i = 0, page_idx = 0; i < ring_size; i += MTK_WED_BUF_PER_PAGE) {
-+	for (i = 0, page_idx = 0; i < pkt_nums; i += MTK_WED_BUF_PER_PAGE) {
- 		dma_addr_t page_phys, buf_phys;
- 		struct page *page;
- 		void *buf;
-@@ -295,7 +380,10 @@ mtk_wed_buffer_alloc(struct mtk_wed_device *dev)
- 			return -ENOMEM;
- 		}
- 
--		page_list[page_idx++] = page;
-+		page_list[page_idx].addr = page;
-+		page_list[page_idx].addr_phys = page_phys;
-+		page_idx++;
-+
- 		dma_sync_single_for_cpu(dev->hw->dev, page_phys, PAGE_SIZE,
- 					DMA_BIDIRECTIONAL);
- 
-@@ -303,19 +391,23 @@ mtk_wed_buffer_alloc(struct mtk_wed_device *dev)
- 		buf_phys = page_phys;
- 
- 		for (s = 0; s < MTK_WED_BUF_PER_PAGE; s++) {
--			u32 txd_size;
--
--			txd_size = dev->wlan.init_buf(buf, buf_phys, token++);
--
-+			desc = desc_ptr;
- 			desc->buf0 = buf_phys;
--			desc->buf1 = buf_phys + txd_size;
--			desc->ctrl = FIELD_PREP(MTK_WDMA_DESC_CTRL_LEN0,
--						txd_size) |
--				     FIELD_PREP(MTK_WDMA_DESC_CTRL_LEN1,
--						MTK_WED_BUF_SIZE - txd_size) |
--						last_seg;
--			desc->info = 0;
--			desc++;
-+			if (dev->hw->version < 3) {
-+				u32 txd_size;
-+
-+				txd_size = dev->wlan.init_buf(buf, buf_phys, token++);
-+				desc->buf1 = buf_phys + txd_size;
-+				desc->ctrl = FIELD_PREP(MTK_WDMA_DESC_CTRL_LEN0,
-+							txd_size) |
-+					     FIELD_PREP(MTK_WDMA_DESC_CTRL_LEN1,
-+							MTK_WED_BUF_SIZE - txd_size) |
-+							last_seg;
-+				desc->info = 0;
-+			} else {
-+				desc->ctrl = token << 16;
-+			}
-+			desc_ptr += dev->tx_buf_ring.desc_size;
- 
- 			buf += MTK_WED_BUF_SIZE;
- 			buf_phys += MTK_WED_BUF_SIZE;
-@@ -325,15 +417,18 @@ mtk_wed_buffer_alloc(struct mtk_wed_device *dev)
- 					   DMA_BIDIRECTIONAL);
- 	}
- 
--	return 0;
-+	if (dev->hw->version == 3)
-+		ret = mtk_wed_pao_buffer_alloc(dev);
-+
-+	return ret;
- }
- 
- static void
--mtk_wed_free_buffer(struct mtk_wed_device *dev)
-+mtk_wed_free_tx_buffer(struct mtk_wed_device *dev)
- {
--	struct mtk_wdma_desc *desc = dev->buf_ring.desc;
--	void **page_list = dev->buf_ring.pages;
--	int ring_size, page_idx;
-+	struct mtk_rxbm_desc *desc = dev->tx_buf_ring.desc;
-+	struct dma_page_info *page_list = dev->tx_buf_ring.pages;
-+	int ring_size, page_idx, pkt_nums;
- 	int i;
- 
- 	if (!page_list)
-@@ -342,33 +437,33 @@ mtk_wed_free_buffer(struct mtk_wed_device *dev)
- 	if (!desc)
- 		goto free_pagelist;
- 
--	if (dev->ver == MTK_WED_V1) {
--		ring_size = dev->wlan.nbuf & ~(MTK_WED_BUF_PER_PAGE - 1);
--	} else {
--		ring_size = MTK_WED_VLD_GROUP_SIZE * MTK_WED_PER_GROUP_PKT +
--			    MTK_WED_WDMA_RING_SIZE * 2;
-+	pkt_nums = ring_size = dev->tx_buf_ring.size;
-+	if (dev->hw->version == 3) {
-+		mtk_wed_pao_free_buffer(dev);
-+		pkt_nums = dev->tx_buf_ring.pkt_nums;
- 	}
- 
--	for (i = 0, page_idx = 0; i < ring_size; i += MTK_WED_BUF_PER_PAGE) {
--		void *page = page_list[page_idx++];
-+	for (i = 0, page_idx = 0; i < pkt_nums; i += MTK_WED_BUF_PER_PAGE) {
-+		void *page = page_list[page_idx].addr;
- 
- 		if (!page)
- 			break;
- 
--		dma_unmap_page(dev->hw->dev, desc[i].buf0,
-+		dma_unmap_page(dev->hw->dev, page_list[page_idx].addr_phys,
- 			       PAGE_SIZE, DMA_BIDIRECTIONAL);
- 		__free_page(page);
-+		page_idx++;
- 	}
- 
--	dma_free_coherent(dev->hw->dev, ring_size * sizeof(*desc),
--			  desc, dev->buf_ring.desc_phys);
-+	dma_free_coherent(dev->hw->dev, ring_size * dev->tx_buf_ring.desc_size,
-+			  dev->tx_buf_ring.desc, dev->tx_buf_ring.desc_phys);
- 
- free_pagelist:
- 	kfree(page_list);
- }
- 
- static int
--mtk_wed_rx_bm_alloc(struct mtk_wed_device *dev)
-+mtk_wed_rx_buffer_alloc(struct mtk_wed_device *dev)
- {
- 	struct mtk_rxbm_desc *desc;
- 	dma_addr_t desc_phys;
-@@ -389,7 +484,7 @@ mtk_wed_rx_bm_alloc(struct mtk_wed_device *dev)
- }
- 
- static void
--mtk_wed_free_rx_bm(struct mtk_wed_device *dev)
-+mtk_wed_free_rx_buffer(struct mtk_wed_device *dev)
- {
- 	struct mtk_rxbm_desc *desc = dev->rx_buf_ring.desc;
- 	int ring_size = dev->rx_buf_ring.size;
-@@ -403,6 +498,113 @@ mtk_wed_free_rx_bm(struct mtk_wed_device *dev)
- 			  desc, dev->rx_buf_ring.desc_phys);
- }
- 
-+/* TODO */
-+static int
-+mtk_wed_rx_page_buffer_alloc(struct mtk_wed_device *dev)
-+{
-+	int ring_size = dev->wlan.rx_nbuf, buf_num = MTK_WED_RX_PG_BM_CNT;
-+	struct mtk_rxbm_desc *desc;
-+	dma_addr_t desc_phys;
-+	struct dma_page_info *page_list;
-+	int n_pages, page_idx;
-+	int i;
-+
-+	n_pages = buf_num / MTK_WED_RX_PAGE_BUF_PER_PAGE;
-+
-+	page_list = kcalloc(n_pages, sizeof(*page_list), GFP_KERNEL);
-+	if (!page_list)
-+		return -ENOMEM;
-+
-+	dev->rx_page_buf_ring.size = ring_size & ~(MTK_WED_BUF_PER_PAGE - 1);
-+	dev->rx_page_buf_ring.pages = page_list;
-+	dev->rx_page_buf_ring.pkt_nums = buf_num;
-+
-+	desc = dma_alloc_coherent(dev->hw->dev, ring_size * sizeof(*desc),
-+	                         &desc_phys, GFP_KERNEL);
-+	if (!desc)
-+		return -ENOMEM;
-+
-+	dev->rx_page_buf_ring.desc = desc;
-+	dev->rx_page_buf_ring.desc_phys = desc_phys;
-+
-+	for (i = 0, page_idx = 0; i < buf_num; i += MTK_WED_RX_PAGE_BUF_PER_PAGE) {
-+		dma_addr_t page_phys, buf_phys;
-+		struct page *page;
-+		void *buf;
-+		int s;
-+
-+		page = __dev_alloc_pages(GFP_KERNEL, 0);
-+		if (!page)
-+			return -ENOMEM;
-+
-+		page_phys = dma_map_page(dev->hw->dev, page, 0, PAGE_SIZE,
-+		                        DMA_BIDIRECTIONAL);
-+		if (dma_mapping_error(dev->hw->dev, page_phys)) {
-+			__free_page(page);
-+			return -ENOMEM;
-+		}
-+
-+		page_list[page_idx].addr= page;
-+		page_list[page_idx].addr_phys= page_phys;
-+		page_idx++;
-+
-+		dma_sync_single_for_cpu(dev->hw->dev, page_phys, PAGE_SIZE,
-+		                       DMA_BIDIRECTIONAL);
-+
-+		buf = page_to_virt(page);
-+		buf_phys = page_phys;
-+
-+		for (s = 0; s < MTK_WED_RX_PAGE_BUF_PER_PAGE; s++) {
-+
-+			desc->buf0 = cpu_to_le32(buf_phys);
-+			desc++;
-+
-+			buf += MTK_WED_PAGE_BUF_SIZE;
-+			buf_phys += MTK_WED_PAGE_BUF_SIZE;
-+		}
-+
-+		dma_sync_single_for_device(dev->hw->dev, page_phys, PAGE_SIZE,
-+					   DMA_BIDIRECTIONAL);
-+	}
-+
-+	return 0;
-+}
-+
-+static void
-+mtk_wed_rx_page_free_buffer(struct mtk_wed_device *dev)
-+{
-+	struct mtk_rxbm_desc *desc = dev->rx_page_buf_ring.desc;
-+	struct dma_page_info *page_list = dev->rx_page_buf_ring.pages;
-+	int ring_size, page_idx;
-+	int i;
-+
-+	if (!page_list)
-+		return;
-+
-+	if (!desc)
-+		goto free_pagelist;
-+
-+	ring_size = dev->rx_page_buf_ring.pkt_nums;
-+
-+	for (i = 0, page_idx = 0; i < ring_size; i += MTK_WED_RX_PAGE_BUF_PER_PAGE) {
-+		void *page = page_list[page_idx].addr;
-+
-+		if (!page)
-+			break;
-+
-+		dma_unmap_page(dev->hw->dev, page_list[page_idx].addr_phys,
-+                              PAGE_SIZE, DMA_BIDIRECTIONAL);
-+		__free_page(page);
-+		page_idx++;
-+       }
-+
-+	dma_free_coherent(dev->hw->dev, dev->rx_page_buf_ring.size * sizeof(*desc),
-+                         desc, dev->rx_page_buf_ring.desc_phys);
-+
-+free_pagelist:
-+       kfree(page_list);
-+}
-+
- static void
- mtk_wed_free_ring(struct mtk_wed_device *dev, struct mtk_wed_ring *ring, int scale)
- {
-@@ -416,19 +618,35 @@ mtk_wed_free_ring(struct mtk_wed_device *dev, struct mtk_wed_ring *ring, int sca
- static void
- mtk_wed_free_tx_rings(struct mtk_wed_device *dev)
- {
--	int i;
-+	int i, scale = dev->hw->version > 1 ? 2 : 1;
- 
- 	for (i = 0; i < ARRAY_SIZE(dev->tx_ring); i++)
--		mtk_wed_free_ring(dev, &dev->tx_ring[i], 1);
-+		if ((dev->tx_ring[i].flags & MTK_WED_RING_CONFIGURED))
-+			mtk_wed_free_ring(dev, &dev->tx_ring[i], 1);
-+
- 	for (i = 0; i < ARRAY_SIZE(dev->tx_wdma); i++)
--		mtk_wed_free_ring(dev, &dev->tx_wdma[i], dev->ver);
-+		if ((dev->tx_wdma[i].flags & MTK_WED_RING_CONFIGURED))
-+			mtk_wed_free_ring(dev, &dev->tx_wdma[i], scale);
- }
- 
- static void
- mtk_wed_free_rx_rings(struct mtk_wed_device *dev)
- {
--	mtk_wed_free_rx_bm(dev);
-+	int i, scale = dev->hw->version > 1 ? 2 : 1;
-+
-+	for (i = 0; i < ARRAY_SIZE(dev->rx_ring); i++)
-+		if ((dev->rx_ring[i].flags & MTK_WED_RING_CONFIGURED))
-+			mtk_wed_free_ring(dev, &dev->rx_ring[i], 1);
-+
-+	for (i = 0; i < ARRAY_SIZE(dev->rx_wdma); i++)
-+		if ((dev->rx_wdma[i].flags & MTK_WED_RING_CONFIGURED))
-+			mtk_wed_free_ring(dev, &dev->rx_wdma[i], scale);
-+
-+	mtk_wed_free_rx_buffer(dev);
- 	mtk_wed_free_ring(dev, &dev->rro.rro_ring, 1);
-+
-+	if (dev->wlan.hwrro)
-+		mtk_wed_rx_page_free_buffer(dev);
- }
- 
- static void
-@@ -437,7 +655,7 @@ mtk_wed_set_int(struct mtk_wed_device *dev, u32 irq_mask)
- 	u32 wdma_mask;
- 
- 	wdma_mask = FIELD_PREP(MTK_WDMA_INT_MASK_RX_DONE, GENMASK(1, 0));
--	if (dev->ver > MTK_WED_V1)
-+	if (mtk_wed_get_rx_capa(dev))
- 		wdma_mask |= FIELD_PREP(MTK_WDMA_INT_MASK_TX_DONE,
- 					GENMASK(1, 0));
- 	/* wed control cr set */
-@@ -447,7 +665,7 @@ mtk_wed_set_int(struct mtk_wed_device *dev, u32 irq_mask)
- 		MTK_WED_CTRL_WED_TX_BM_EN |
- 		MTK_WED_CTRL_WED_TX_FREE_AGENT_EN);
- 
--	if (dev->ver == MTK_WED_V1) {
-+	if (dev->hw->version == 1) {
- 		wed_w32(dev, MTK_WED_PCIE_INT_TRIGGER,
- 			MTK_WED_PCIE_INT_TRIGGER_STATUS);
- 
-@@ -458,6 +676,8 @@ mtk_wed_set_int(struct mtk_wed_device *dev, u32 irq_mask)
- 		wed_set(dev, MTK_WED_WPDMA_INT_CTRL,
- 			MTK_WED_WPDMA_INT_CTRL_SUBRT_ADV);
- 	} else {
-+		if (dev->hw->version == 3)
-+			wed_set(dev, MTK_WED_CTRL, MTK_WED_CTRL_TX_TKID_ALI_EN);
- 
- 		wed_w32(dev, MTK_WED_WPDMA_INT_CTRL_TX,
- 			MTK_WED_WPDMA_INT_CTRL_TX0_DONE_EN |
-@@ -475,18 +695,20 @@ mtk_wed_set_int(struct mtk_wed_device *dev, u32 irq_mask)
- 			FIELD_PREP(MTK_WED_WPDMA_INT_CTRL_TX_FREE_DONE_TRIG,
- 				    dev->wlan.txfree_tbit));
- 
--		wed_w32(dev, MTK_WED_WPDMA_INT_CTRL_RX,
--			MTK_WED_WPDMA_INT_CTRL_RX0_EN |
--			MTK_WED_WPDMA_INT_CTRL_RX0_CLR |
--			MTK_WED_WPDMA_INT_CTRL_RX1_EN |
--			MTK_WED_WPDMA_INT_CTRL_RX1_CLR |
--			FIELD_PREP(MTK_WED_WPDMA_INT_CTRL_RX0_DONE_TRIG,
--				   dev->wlan.rx_tbit[0]) |
--			FIELD_PREP(MTK_WED_WPDMA_INT_CTRL_RX1_DONE_TRIG,
--				   dev->wlan.rx_tbit[1]));
-+		if (mtk_wed_get_rx_capa(dev))
-+			wed_w32(dev, MTK_WED_WPDMA_INT_CTRL_RX,
-+				MTK_WED_WPDMA_INT_CTRL_RX0_EN |
-+				MTK_WED_WPDMA_INT_CTRL_RX0_CLR |
-+				MTK_WED_WPDMA_INT_CTRL_RX1_EN |
-+				MTK_WED_WPDMA_INT_CTRL_RX1_CLR |
-+				FIELD_PREP(MTK_WED_WPDMA_INT_CTRL_RX0_DONE_TRIG,
-+					   dev->wlan.rx_tbit[0]) |
-+				FIELD_PREP(MTK_WED_WPDMA_INT_CTRL_RX1_DONE_TRIG,
-+					   dev->wlan.rx_tbit[1]));
- 	}
-+
- 	wed_w32(dev, MTK_WED_WDMA_INT_TRIGGER, wdma_mask);
--	if (dev->ver == MTK_WED_V1) {
-+	if (dev->hw->version == 1) {
- 		wed_clr(dev, MTK_WED_WDMA_INT_CTRL, wdma_mask);
- 	} else {
- 		wed_w32(dev, MTK_WED_WDMA_INT_CLR, wdma_mask);
-@@ -506,6 +728,21 @@ mtk_wed_set_ext_int(struct mtk_wed_device *dev, bool en)
- {
- 	u32 mask = MTK_WED_EXT_INT_STATUS_ERROR_MASK;
- 
-+	switch (dev->hw->version) {
-+	case 1:
-+		mask |= MTK_WED_EXT_INT_STATUS_TX_DRV_R_RESP_ERR;
-+		break;
-+	case 2 :
-+		mask |= MTK_WED_EXT_INT_STATUS_RX_FBUF_LO_TH2 |
-+			MTK_WED_EXT_INT_STATUS_RX_FBUF_HI_TH2 |
-+			MTK_WED_EXT_INT_STATUS_RX_DRV_COHERENT |
-+			MTK_WED_EXT_INT_STATUS_TX_DMA_W_RESP_ERR;
-+		break;
-+	case 3:
-+		mask = MTK_WED_EXT_INT_STATUS_RX_DRV_COHERENT;
-+		break;
-+	}
-+
- 	if (!dev->hw->num_flows)
- 		mask &= ~MTK_WED_EXT_INT_STATUS_TKID_WO_PYLD;
- 
-@@ -514,31 +751,86 @@ mtk_wed_set_ext_int(struct mtk_wed_device *dev, bool en)
- }
- 
- static void
--mtk_wed_set_512_support(struct mtk_wed_device *dev, bool en)
-+mtk_wed_pao_init(struct mtk_wed_device *dev)
- {
--	if (en) {
--		wed_w32(dev, MTK_WED_TXDP_CTRL, MTK_WED_TXDP_DW9_OVERWR);
--		wed_w32(dev, MTK_WED_TXP_DW1,
--			FIELD_PREP(MTK_WED_WPDMA_WRITE_TXP, 0x0103));
--	} else {
--		wed_w32(dev, MTK_WED_TXP_DW1,
--			FIELD_PREP(MTK_WED_WPDMA_WRITE_TXP, 0x0100));
--		wed_clr(dev, MTK_WED_TXDP_CTRL, MTK_WED_TXDP_DW9_OVERWR);
-+	struct mtk_wed_pao *pao = dev->hw->wed_pao;
-+	int i;
-+
-+	for (i = 0; i < 32; i++)
-+		wed_w32(dev, MTK_WED_PAO_HIFTXD_BASE_L(i),
-+			pao->hif_txd_phys[i]);
-+
-+	/* init all sta parameter */
-+	wed_w32(dev, MTK_WED_PAO_STA_INFO_INIT, MTK_WED_PAO_STA_RMVL |
-+		MTK_WED_PAO_STA_WTBL_HDRT_MODE |
-+		FIELD_PREP(MTK_WED_PAO_STA_MAX_AMSDU_LEN,
-+			   dev->wlan.max_amsdu_len >> 8) |
-+		FIELD_PREP(MTK_WED_PAO_STA_MAX_AMSDU_NUM,
-+			   dev->wlan.max_amsdu_nums));
-+
-+	wed_w32(dev, MTK_WED_PAO_STA_INFO, MTK_WED_PAO_STA_INFO_DO_INIT);
-+
-+	if (mtk_wed_poll_busy(dev, MTK_WED_PAO_STA_INFO,
-+			      MTK_WED_PAO_STA_INFO_DO_INIT)) {
-+		dev_err(dev->hw->dev, "mtk_wed%d: pao init failed!\n",
-+			dev->hw->index);
-+		return;
- 	}
-+
-+	/* init pao txd src */
-+	wed_set(dev, MTK_WED_PAO_HIFTXD_CFG,
-+		FIELD_PREP(MTK_WED_PAO_HIFTXD_SRC, dev->hw->index));
-+
-+	/* init qmem */
-+	wed_set(dev, MTK_WED_PAO_PSE, MTK_WED_PAO_PSE_RESET);
-+	if (mtk_wed_poll_busy(dev, MTK_WED_PAO_MON_QMEM_STS1, BIT(29))) {
-+		pr_info("%s: init pao qmem fail\n", __func__);
-+		return;
-+	}
-+
-+	/* eagle E1 PCIE1 tx ring 22 flow control issue */
-+	if (dev->wlan.chip_id == 0x7991) {
-+		wed_clr(dev, MTK_WED_PAO_AMSDU_FIFO,
-+			MTK_WED_PAO_AMSDU_IS_PRIOR0_RING);
-+	}
-+
-+	wed_set(dev, MTK_WED_CTRL, MTK_WED_CTRL_TX_PAO_EN);
-+
-+	return;
- }
- 
--static void
--mtk_wed_check_wfdma_rx_fill(struct mtk_wed_device *dev, int idx)
-+static int
-+mtk_wed_hwrro_init(struct mtk_wed_device *dev)
- {
--#define MTK_WFMDA_RX_DMA_EN 	BIT(2)
-+	if (!mtk_wed_get_rx_capa(dev))
-+		return 0;
- 
-+	wed_set(dev, MTK_WED_RRO_PG_BM_RX_DMAM,
-+		FIELD_PREP(MTK_WED_RRO_PG_BM_RX_SDL0, 128));
-+
-+	wed_w32(dev, MTK_WED_RRO_PG_BM_BASE,
-+		dev->rx_page_buf_ring.desc_phys);
-+
-+	wed_w32(dev, MTK_WED_RRO_PG_BM_INIT_PTR,
-+		MTK_WED_RRO_PG_BM_INIT_SW_TAIL_IDX |
-+		FIELD_PREP(MTK_WED_RRO_PG_BM_SW_TAIL_IDX,
-+			   MTK_WED_RX_PG_BM_CNT));
-+
-+	/* enable rx_page_bm to fetch dmad */
-+	wed_set(dev, MTK_WED_CTRL, MTK_WED_CTRL_WED_RX_PG_BM_EN);
-+
-+	return 0;
-+}
-+
-+static int
-+mtk_wed_check_wfdma_rx_fill(struct mtk_wed_device *dev,
-+			   struct mtk_wed_ring *ring)
-+{
- 	int timeout = 3;
--	u32 cur_idx, regs;
-+	u32 cur_idx;
- 
- 	do {
--		regs = MTK_WED_WPDMA_RING_RX_DATA(idx) +
--		       MTK_WED_RING_OFS_CPU_IDX;
--		cur_idx = wed_r32(dev, regs);
-+		cur_idx = readl(ring->wpdma + MTK_WED_RING_OFS_CPU_IDX);
- 		if (cur_idx == MTK_WED_RX_RING_SIZE - 1)
- 			break;
- 
-@@ -546,70 +838,133 @@ mtk_wed_check_wfdma_rx_fill(struct mtk_wed_device *dev, int idx)
- 		timeout--;
- 	} while (timeout > 0);
- 
--	if (timeout) {
--		unsigned int val;
-+	return timeout;
-+}
- 
--		val = wifi_r32(dev, dev->wlan.wpdma_rx_glo -
--			       dev->wlan.phy_base);
--		val |= MTK_WFMDA_RX_DMA_EN;
- 
--		wifi_w32(dev, dev->wlan.wpdma_rx_glo -
--			 dev->wlan.phy_base, val);
-+static void
-+mtk_wed_set_512_support(struct mtk_wed_device *dev, bool en)
-+{
-+	if (en) {
-+		wed_w32(dev, MTK_WED_TXDP_CTRL, MTK_WED_TXDP_DW9_OVERWR);
-+		wed_w32(dev, MTK_WED_TXP_DW1,
-+			FIELD_PREP(MTK_WED_WPDMA_WRITE_TXP, 0x0103));
- 	} else {
--		dev_err(dev->hw->dev, "mtk_wed%d: rx(%d) dma enable failed!\n",
--			       dev->hw->index, idx);
-+		wed_w32(dev, MTK_WED_TXP_DW1,
-+			FIELD_PREP(MTK_WED_WPDMA_WRITE_TXP, 0x0100));
-+		wed_clr(dev, MTK_WED_TXDP_CTRL, MTK_WED_TXDP_DW9_OVERWR);
- 	}
- }
- 
- static void
- mtk_wed_dma_enable(struct mtk_wed_device *dev)
- {
--	wed_set(dev, MTK_WED_WPDMA_INT_CTRL,
--		MTK_WED_WPDMA_INT_CTRL_SUBRT_ADV);
-+#define MTK_WFMDA_RX_DMA_EN 	BIT(2)
-+
-+	if (dev->hw->version == 1)
-+		wed_set(dev, MTK_WED_WPDMA_INT_CTRL,
-+			MTK_WED_WPDMA_INT_CTRL_SUBRT_ADV);
- 
- 	wed_set(dev, MTK_WED_GLO_CFG,
- 		MTK_WED_GLO_CFG_TX_DMA_EN |
- 		MTK_WED_GLO_CFG_RX_DMA_EN);
-+
-+	wed_set(dev, MTK_WED_WDMA_RX_PREF_CFG,
-+		FIELD_PREP(MTK_WED_WDMA_RX_PREF_BURST_SIZE, 0x10) |
-+		FIELD_PREP(MTK_WED_WDMA_RX_PREF_LOW_THRES, 0x8));
-+	wed_clr(dev, MTK_WED_WDMA_RX_PREF_CFG,
-+		MTK_WED_WDMA_RX_PREF_DDONE2_EN);
-+
-+	wed_set(dev, MTK_WED_WDMA_RX_PREF_CFG, MTK_WED_WDMA_RX_PREF_EN);
-+
- 	wed_set(dev, MTK_WED_WPDMA_GLO_CFG,
- 		MTK_WED_WPDMA_GLO_CFG_TX_DRV_EN |
--		MTK_WED_WPDMA_GLO_CFG_RX_DRV_EN);
-+		MTK_WED_WPDMA_GLO_CFG_RX_DRV_EN |
-+		MTK_WED_WPDMA_GLO_CFG_RX_DDONE2_WR);
- 	wed_set(dev, MTK_WED_WDMA_GLO_CFG,
- 		MTK_WED_WDMA_GLO_CFG_RX_DRV_EN);
- 
- 	wdma_set(dev, MTK_WDMA_GLO_CFG,
--		 MTK_WDMA_GLO_CFG_TX_DMA_EN |
-+		 MTK_WDMA_GLO_CFG_TX_DMA_EN /*|
- 		 MTK_WDMA_GLO_CFG_RX_INFO1_PRERES |
--		 MTK_WDMA_GLO_CFG_RX_INFO2_PRERES);
-+		 MTK_WDMA_GLO_CFG_RX_INFO2_PRERES*/);
- 
--	if (dev->ver == MTK_WED_V1) {
-+	if (dev->hw->version == 1) {
- 		wdma_set(dev, MTK_WDMA_GLO_CFG,
- 			 MTK_WDMA_GLO_CFG_RX_INFO3_PRERES);
- 	} else {
- 		int idx = 0;
- 
--		wed_set(dev, MTK_WED_WPDMA_CTRL,
--			MTK_WED_WPDMA_CTRL_SDL1_FIXED);
--
--		wed_set(dev, MTK_WED_WDMA_GLO_CFG,
--			MTK_WED_WDMA_GLO_CFG_TX_DRV_EN |
--			MTK_WED_WDMA_GLO_CFG_TX_DDONE_CHK);
-+		if (mtk_wed_get_rx_capa(dev))
-+			wed_set(dev, MTK_WED_WDMA_GLO_CFG,
-+				MTK_WED_WDMA_GLO_CFG_TX_DRV_EN |
-+				MTK_WED_WDMA_GLO_CFG_TX_DDONE_CHK);
- 
- 		wed_set(dev, MTK_WED_WPDMA_GLO_CFG,
- 			MTK_WED_WPDMA_GLO_CFG_RX_DRV_R0_PKT_PROC |
- 			MTK_WED_WPDMA_GLO_CFG_RX_DRV_R0_CRX_SYNC);
- 
-+		if (dev->hw->version == 3) {
-+			wed_clr(dev, MTK_WED_WPDMA_GLO_CFG,
-+				MTK_WED_WPDMA_GLO_CFG_TX_DDONE_CHK_LAST);
-+			wed_set(dev, MTK_WED_WPDMA_GLO_CFG,
-+				MTK_WED_WPDMA_GLO_CFG_TX_DDONE_CHK |
-+				MTK_WED_WPDMA_GLO_CFG_RX_DRV_EVENT_PKT_FMT_CHK |
-+				MTK_WED_WPDMA_GLO_CFG_RX_DRV_UNS_VER_FORCE_4);
-+
-+			wdma_set(dev, MTK_WDMA_PREF_RX_CFG, MTK_WDMA_PREF_RX_CFG_PREF_EN);
-+			//wdma_w32(dev, MTK_WDMA_WRBK_RX_CFG, MTK_WDMA_WRBK_RX_CFG_WRBK_EN);
-+			if (mtk_wed_get_rx_capa(dev)) {
-+				wed_set(dev, MTK_WED_WPDMA_RX_D_PREF_CFG,
-+					MTK_WED_WPDMA_RX_D_PREF_EN |
-+					FIELD_PREP(MTK_WED_WPDMA_RX_D_PREF_BURST_SIZE, 0x10) |
-+					FIELD_PREP(MTK_WED_WPDMA_RX_D_PREF_LOW_THRES, 0x8));
-+
-+				wed_set(dev, MTK_WED_RRO_RX_D_CFG(2), MTK_WED_RRO_RX_D_DRV_EN);
-+
-+				wdma_set(dev, MTK_WDMA_PREF_TX_CFG, MTK_WDMA_PREF_TX_CFG_PREF_EN);
-+
-+				wdma_set(dev, MTK_WDMA_WRBK_TX_CFG, MTK_WDMA_WRBK_TX_CFG_WRBK_EN);
-+			}
-+		}
-+
- 		wed_clr(dev, MTK_WED_WPDMA_GLO_CFG,
- 			MTK_WED_WPDMA_GLO_CFG_TX_TKID_KEEP |
- 			MTK_WED_WPDMA_GLO_CFG_TX_DMAD_DW3_PREV);
- 
-+		if (!mtk_wed_get_rx_capa(dev))
-+			return;
-+
-+		wed_clr(dev, MTK_WED_WPDMA_RX_D_GLO_CFG, MTK_WED_WPDMA_RX_D_RXD_READ_LEN);
- 		wed_set(dev, MTK_WED_WPDMA_RX_D_GLO_CFG,
- 			MTK_WED_WPDMA_RX_D_RX_DRV_EN |
- 			FIELD_PREP(MTK_WED_WPDMA_RX_D_RXD_READ_LEN, 0x18) |
- 			FIELD_PREP(MTK_WED_WPDMA_RX_D_INIT_PHASE_RXEN_SEL,
- 				   0x2));
- 
--		for (idx = 0; idx < dev->hw->ring_num; idx++)
--			mtk_wed_check_wfdma_rx_fill(dev, idx);
-+		for (idx = 0; idx < dev->hw->ring_num; idx++) {
-+			struct mtk_wed_ring *ring = &dev->rx_ring[idx];
-+
-+			if(!(ring->flags & MTK_WED_RING_CONFIGURED))
-+				continue;
-+
-+			if(mtk_wed_check_wfdma_rx_fill(dev, ring)) {
-+				unsigned int val;
-+
-+				val = wifi_r32(dev, dev->wlan.wpdma_rx_glo -
-+					       dev->wlan.phy_base);
-+				val |= MTK_WFMDA_RX_DMA_EN;
-+
-+				wifi_w32(dev, dev->wlan.wpdma_rx_glo -
-+					 dev->wlan.phy_base, val);
-+
-+				dev_err(dev->hw->dev, "mtk_wed%d: rx(%d) dma enable successful!\n",
-+						dev->hw->index, idx);
-+			} else {
-+				dev_err(dev->hw->dev, "mtk_wed%d: rx(%d) dma enable failed!\n",
-+					dev->hw->index, idx);
-+			}
-+		}
- 	}
- }
- 
-@@ -644,15 +999,20 @@ mtk_wed_dma_disable(struct mtk_wed_device *dev)
- 			MTK_WED_WPDMA_RX_D_RX_DRV_EN);
- 		wed_clr(dev, MTK_WED_WDMA_GLO_CFG,
- 			MTK_WED_WDMA_GLO_CFG_TX_DDONE_CHK);
--	}
- 
--	mtk_wed_set_512_support(dev, false);
-+		if (dev->hw->version == 3 && mtk_wed_get_rx_capa(dev)) {
-+			wdma_clr(dev, MTK_WDMA_PREF_TX_CFG,
-+				 MTK_WDMA_PREF_TX_CFG_PREF_EN);
-+			wdma_clr(dev, MTK_WDMA_PREF_RX_CFG,
-+				 MTK_WDMA_PREF_RX_CFG_PREF_EN);
-+		}
-+	}
- }
- 
- static void
- mtk_wed_stop(struct mtk_wed_device *dev)
- {
--	if (dev->ver > MTK_WED_V1) {
-+	if (mtk_wed_get_rx_capa(dev)) {
- 		wed_w32(dev, MTK_WED_EXT_INT_MASK1, 0);
- 		wed_w32(dev, MTK_WED_EXT_INT_MASK2, 0);
- 	}
-@@ -677,13 +1037,21 @@ mtk_wed_deinit(struct mtk_wed_device *dev)
- 		MTK_WED_CTRL_WED_TX_BM_EN |
- 		MTK_WED_CTRL_WED_TX_FREE_AGENT_EN);
- 
--	if (dev->hw->ver == 1)
-+	if (dev->hw->version == 1)
- 		return;
- 
- 	wed_clr(dev, MTK_WED_CTRL,
- 		MTK_WED_CTRL_RX_ROUTE_QM_EN |
- 		MTK_WED_CTRL_WED_RX_BM_EN |
- 		MTK_WED_CTRL_RX_RRO_QM_EN);
-+
-+	if (dev->hw->version == 3) {
-+		wed_clr(dev, MTK_WED_CTRL, MTK_WED_CTRL_TX_PAO_EN);
-+		wed_clr(dev, MTK_WED_RESET, MTK_WED_RESET_TX_PAO);
-+		wed_clr(dev, MTK_WED_PCIE_INT_CTRL,
-+			MTK_WED_PCIE_INT_CTRL_MSK_EN_POLA |
-+			MTK_WED_PCIE_INT_CTRL_MSK_IRQ_FILTER);
-+	}
- }
- 
- static void
-@@ -702,9 +1070,9 @@ mtk_wed_detach(struct mtk_wed_device *dev)
- 
- 	mtk_wdma_tx_reset(dev);
- 
--	mtk_wed_free_buffer(dev);
-+	mtk_wed_free_tx_buffer(dev);
- 	mtk_wed_free_tx_rings(dev);
--	if (dev->ver > MTK_WED_V1) {
-+	if (mtk_wed_get_rx_capa(dev)) {
- 		mtk_wed_wo_reset(dev);
- 		mtk_wed_free_rx_rings(dev);
- 		mtk_wed_wo_exit(hw);
-@@ -731,24 +1099,29 @@ mtk_wed_detach(struct mtk_wed_device *dev)
- static void
- mtk_wed_bus_init(struct mtk_wed_device *dev)
- {
--#define PCIE_BASE_ADDR0 0x11280000
-+	switch (dev->wlan.bus_type) {
-+	case MTK_WED_BUS_PCIE: {
-+		struct device_node *np = dev->hw->eth->dev->of_node;
-+		struct regmap *regs;
- 
--	if (dev->wlan.bus_type == MTK_WED_BUS_PCIE) {
--		struct device_node *node;
--		void __iomem * base_addr;
--		u32 value = 0;
-+		if (dev->hw->version == 2) {
-+			regs = syscon_regmap_lookup_by_phandle(np,
-+							       "mediatek,wed-pcie");
-+			if (IS_ERR(regs))
-+				break;
- 
--		node = of_parse_phandle(dev->hw->node, "mediatek,wed_pcie", 0);
--		if (!node) {
--			pr_err("%s: no wed_pcie node\n", __func__);
--			return;
-+			regmap_update_bits(regs, 0, BIT(0), BIT(0));
- 		}
- 
--		base_addr = of_iomap(node, 0);
--
--		value = readl(base_addr);
--		value |= BIT(0);
--		writel(value, base_addr);
-+		if (dev->wlan.msi) {
-+		     wed_w32(dev, MTK_WED_PCIE_CFG_INTM, dev->hw->pci_base| 0xc08);
-+		     wed_w32(dev, MTK_WED_PCIE_CFG_BASE, dev->hw->pci_base | 0xc04);
-+		     wed_w32(dev, MTK_WED_PCIE_INT_TRIGGER, BIT(8));
-+		} else {
-+		     wed_w32(dev, MTK_WED_PCIE_CFG_INTM, dev->hw->pci_base | 0x180);
-+		     wed_w32(dev, MTK_WED_PCIE_CFG_BASE, dev->hw->pci_base | 0x184);
-+		     wed_w32(dev, MTK_WED_PCIE_INT_TRIGGER, BIT(24));
-+		}
- 
- 		wed_w32(dev, MTK_WED_PCIE_INT_CTRL,
- 			FIELD_PREP(MTK_WED_PCIE_INT_CTRL_POLL_EN, 2));
-@@ -756,45 +1129,53 @@ mtk_wed_bus_init(struct mtk_wed_device *dev)
- 		/* pcie interrupt control: pola/source selection */
- 		wed_set(dev, MTK_WED_PCIE_INT_CTRL,
- 			MTK_WED_PCIE_INT_CTRL_MSK_EN_POLA |
--			FIELD_PREP(MTK_WED_PCIE_INT_CTRL_SRC_SEL, 1));
--		wed_r32(dev, MTK_WED_PCIE_INT_CTRL);
--
--		value = wed_r32(dev, MTK_WED_PCIE_CFG_INTM);
--		value = wed_r32(dev, MTK_WED_PCIE_CFG_BASE);
--		wed_w32(dev, MTK_WED_PCIE_CFG_INTM, PCIE_BASE_ADDR0 | 0x180);
--		wed_w32(dev, MTK_WED_PCIE_CFG_BASE, PCIE_BASE_ADDR0 | 0x184);
-+			MTK_WED_PCIE_INT_CTRL_MSK_IRQ_FILTER |
-+			FIELD_PREP(MTK_WED_PCIE_INT_CTRL_SRC_SEL, dev->hw->index));
- 
--		value = wed_r32(dev, MTK_WED_PCIE_CFG_INTM);
--		value = wed_r32(dev, MTK_WED_PCIE_CFG_BASE);
--
--		wed_w32(dev, MTK_WED_PCIE_INT_TRIGGER, BIT(24));
--		wed_r32(dev, MTK_WED_PCIE_INT_TRIGGER);
--
--		/* pola setting */
--		value = wed_r32(dev, MTK_WED_PCIE_INT_CTRL);
--		wed_set(dev, MTK_WED_PCIE_INT_CTRL,
--			MTK_WED_PCIE_INT_CTRL_MSK_EN_POLA);
--	} else if (dev->wlan.bus_type == MTK_WED_BUS_AXI) {
-+		break;
-+	}
-+	case MTK_WED_BUS_AXI:
- 		wed_set(dev, MTK_WED_WPDMA_INT_CTRL,
- 			MTK_WED_WPDMA_INT_CTRL_SIG_SRC |
- 			FIELD_PREP(MTK_WED_WPDMA_INT_CTRL_SRC_SEL, 0));
-+		break;
-+	default:
-+		break;
- 	}
-+
- 	return;
- }
- 
- static void
- mtk_wed_set_wpdma(struct mtk_wed_device *dev)
- {
--	if (dev->ver > MTK_WED_V1) {
-+	if (dev->hw->version == 1) {
-+		wed_w32(dev, MTK_WED_WPDMA_CFG_BASE,  dev->wlan.wpdma_phys);
-+	} else {
-+		mtk_wed_bus_init(dev);
-+
- 		wed_w32(dev, MTK_WED_WPDMA_CFG_BASE,  dev->wlan.wpdma_int);
- 		wed_w32(dev, MTK_WED_WPDMA_CFG_INT_MASK,  dev->wlan.wpdma_mask);
--		wed_w32(dev, MTK_WED_WPDMA_CFG_TX,  dev->wlan.wpdma_tx);
-+		wed_w32(dev, MTK_WED_WPDMA_CFG_TX, dev->wlan.wpdma_tx);
- 		wed_w32(dev, MTK_WED_WPDMA_CFG_TX_FREE,  dev->wlan.wpdma_txfree);
- 
--		wed_w32(dev, MTK_WED_WPDMA_RX_GLO_CFG,  dev->wlan.wpdma_rx_glo);
--		wed_w32(dev, MTK_WED_WPDMA_RX_RING,  dev->wlan.wpdma_rx);
--	} else {
--		wed_w32(dev, MTK_WED_WPDMA_CFG_BASE,  dev->wlan.wpdma_phys);
-+		if (mtk_wed_get_rx_capa(dev)) {
-+			int i;
-+
-+			wed_w32(dev, MTK_WED_WPDMA_RX_GLO_CFG,  dev->wlan.wpdma_rx_glo);
-+			wed_w32(dev, MTK_WED_WPDMA_RX_RING0,  dev->wlan.wpdma_rx[0]);
-+			if (dev->wlan.wpdma_rx[1])
-+				wed_w32(dev, MTK_WED_WPDMA_RX_RING1,  dev->wlan.wpdma_rx[1]);
-+
-+			if (dev->wlan.hwrro) {
-+				wed_w32(dev, MTK_WED_RRO_RX_D_CFG(0), dev->wlan.wpdma_rx_rro[0]);
-+				wed_w32(dev, MTK_WED_RRO_RX_D_CFG(1), dev->wlan.wpdma_rx_rro[1]);
-+				for (i = 0; i < MTK_WED_RX_PAGE_QUEUES; i++) {
-+					wed_w32(dev, MTK_WED_RRO_MSDU_PG_RING_CFG(i),
-+						dev->wlan.wpdma_rx_pg + i * 0x10);
-+			       }
-+			}
-+		}
- 	}
- }
- 
-@@ -806,21 +1187,25 @@ mtk_wed_hw_init_early(struct mtk_wed_device *dev)
- 	mtk_wed_deinit(dev);
- 	mtk_wed_reset(dev, MTK_WED_RESET_WED);
- 
--	if (dev->ver > MTK_WED_V1)
--		mtk_wed_bus_init(dev);
--
- 	mtk_wed_set_wpdma(dev);
- 
--	mask = MTK_WED_WDMA_GLO_CFG_BT_SIZE |
--	       MTK_WED_WDMA_GLO_CFG_DYNAMIC_DMAD_RECYCLE |
--	       MTK_WED_WDMA_GLO_CFG_RX_DIS_FSM_AUTO_IDLE;
--	set = FIELD_PREP(MTK_WED_WDMA_GLO_CFG_BT_SIZE, 2) |
--	      MTK_WED_WDMA_GLO_CFG_DYNAMIC_SKIP_DMAD_PREP |
--	      MTK_WED_WDMA_GLO_CFG_IDLE_DMAD_SUPPLY;
-+	if (dev->hw->version == 3) {
-+		mask = MTK_WED_WDMA_GLO_CFG_BT_SIZE;
-+		set = FIELD_PREP(MTK_WED_WDMA_GLO_CFG_BT_SIZE, 2);
-+	} else {
-+		mask = MTK_WED_WDMA_GLO_CFG_BT_SIZE |
-+		       MTK_WED_WDMA_GLO_CFG_DYNAMIC_DMAD_RECYCLE |
-+		       MTK_WED_WDMA_GLO_CFG_RX_DIS_FSM_AUTO_IDLE;
-+		set = FIELD_PREP(MTK_WED_WDMA_GLO_CFG_BT_SIZE, 2) |
-+		      MTK_WED_WDMA_GLO_CFG_DYNAMIC_SKIP_DMAD_PREP |
-+		      MTK_WED_WDMA_GLO_CFG_IDLE_DMAD_SUPPLY;
-+	}
-+
- 	wed_m32(dev, MTK_WED_WDMA_GLO_CFG, mask, set);
- 
--	if (dev->ver == MTK_WED_V1) {
-+	if (dev->hw->version == 1) {
- 		u32 offset;
-+
- 		offset = dev->hw->index ? 0x04000400 : 0;
- 		wed_w32(dev, MTK_WED_WDMA_OFFSET0, 0x2a042a20 + offset);
- 		wed_w32(dev, MTK_WED_WDMA_OFFSET1, 0x29002800 + offset);
-@@ -907,11 +1292,16 @@ mtk_wed_route_qm_hw_init(struct mtk_wed_device *dev)
- 	} while (1);
- 
- 	/* configure RX_ROUTE_QM */
--	wed_clr(dev, MTK_WED_RTQM_GLO_CFG, MTK_WED_RTQM_Q_RST);
--	wed_clr(dev, MTK_WED_RTQM_GLO_CFG, MTK_WED_RTQM_TXDMAD_FPORT);
--	wed_set(dev, MTK_WED_RTQM_GLO_CFG,
--		FIELD_PREP(MTK_WED_RTQM_TXDMAD_FPORT, 0x3 + dev->hw->index));
--	wed_clr(dev, MTK_WED_RTQM_GLO_CFG, MTK_WED_RTQM_Q_RST);
-+	if (dev->hw->version == 2) {
-+		wed_clr(dev, MTK_WED_RTQM_GLO_CFG, MTK_WED_RTQM_Q_RST);
-+		wed_clr(dev, MTK_WED_RTQM_GLO_CFG, MTK_WED_RTQM_TXDMAD_FPORT);
-+		wed_set(dev, MTK_WED_RTQM_GLO_CFG,
-+			FIELD_PREP(MTK_WED_RTQM_TXDMAD_FPORT, 0x3 + dev->hw->index));
-+		wed_clr(dev, MTK_WED_RTQM_GLO_CFG, MTK_WED_RTQM_Q_RST);
-+	} else {
-+		wed_set(dev, MTK_WED_RTQM_ENQ_CFG0,
-+			FIELD_PREP(MTK_WED_RTQM_ENQ_CFG_TXDMAD_FPORT, 0x3 + dev->hw->index));
-+	}
- 
- 	/* enable RX_ROUTE_QM */
- 	wed_set(dev, MTK_WED_CTRL, MTK_WED_CTRL_RX_ROUTE_QM_EN);
-@@ -920,23 +1310,45 @@ mtk_wed_route_qm_hw_init(struct mtk_wed_device *dev)
- static void
- mtk_wed_tx_hw_init(struct mtk_wed_device *dev)
- {
--	int size = dev->buf_ring.size;
-+	int size = dev->wlan.nbuf;
- 	int rev_size = MTK_WED_TX_RING_SIZE / 2;
--	int thr = 1;
-+	int thr_lo = 1, thr_hi = 1;
- 
--	if (dev->ver > MTK_WED_V1) {
-+	if (dev->hw->version == 1) {
-+		wed_w32(dev, MTK_WED_TX_BM_CTRL,
-+			MTK_WED_TX_BM_CTRL_PAUSE |
-+			FIELD_PREP(MTK_WED_TX_BM_CTRL_VLD_GRP_NUM, size / 128) |
-+			FIELD_PREP(MTK_WED_TX_BM_CTRL_RSV_GRP_NUM, rev_size / 128));
-+	} else {
- 		size = MTK_WED_WDMA_RING_SIZE * ARRAY_SIZE(dev->tx_wdma) +
--		       dev->buf_ring.size;
-+		       dev->tx_buf_ring.size;
- 		rev_size = size;
--		thr = 0;
-+		thr_lo = 0;
-+		thr_hi = MTK_WED_TX_BM_DYN_THR_HI;
-+
-+		wed_w32(dev, MTK_WED_TX_TKID_CTRL,
-+			MTK_WED_TX_TKID_CTRL_PAUSE |
-+			FIELD_PREP(MTK_WED_TX_TKID_CTRL_VLD_GRP_NUM,
-+				   size / 128) |
-+			FIELD_PREP(MTK_WED_TX_TKID_CTRL_RSV_GRP_NUM,
-+				   size / 128));
-+
-+		/* return SKBID + SDP back to bm */
-+		if (dev->ver == 3) {
-+			wed_set(dev, MTK_WED_TX_TKID_CTRL,
-+				MTK_WED_TX_TKID_CTRL_FREE_FORMAT);
-+			 size = dev->wlan.nbuf;
-+			 rev_size = size;
-+		} else {
-+			wed_w32(dev, MTK_WED_TX_TKID_DYN_THR,
-+				FIELD_PREP(MTK_WED_TX_TKID_DYN_THR_LO, 0) |
-+				MTK_WED_TX_TKID_DYN_THR_HI);
-+		}
- 	}
- 
--	wed_w32(dev, MTK_WED_TX_BM_CTRL,
--		MTK_WED_TX_BM_CTRL_PAUSE |
--		FIELD_PREP(MTK_WED_TX_BM_CTRL_VLD_GRP_NUM, size / 128) |
--		FIELD_PREP(MTK_WED_TX_BM_CTRL_RSV_GRP_NUM, rev_size / 128));
-+	mtk_wed_reset(dev, MTK_WED_RESET_TX_BM);
- 
--	wed_w32(dev, MTK_WED_TX_BM_BASE, dev->buf_ring.desc_phys);
-+	wed_w32(dev, MTK_WED_TX_BM_BASE, dev->tx_buf_ring.desc_phys);
- 
- 	wed_w32(dev, MTK_WED_TX_BM_TKID,
- 		FIELD_PREP(MTK_WED_TX_BM_TKID_START,
-@@ -946,25 +1358,44 @@ mtk_wed_tx_hw_init(struct mtk_wed_device *dev)
- 
- 	wed_w32(dev, MTK_WED_TX_BM_BUF_LEN, MTK_WED_PKT_SIZE);
- 
--	wed_w32(dev, MTK_WED_TX_BM_DYN_THR,
--		FIELD_PREP(MTK_WED_TX_BM_DYN_THR_LO, thr) |
--		MTK_WED_TX_BM_DYN_THR_HI);
-+	if (dev->hw->version < 3)
-+		wed_w32(dev, MTK_WED_TX_BM_DYN_THR,
-+			FIELD_PREP(MTK_WED_TX_BM_DYN_THR_LO, thr_lo) |
-+			FIELD_PREP(MTK_WED_TX_BM_DYN_THR_LO, thr_hi));
-+	else {
-+		/* change to new bm */
-+		wed_w32(dev, MTK_WED_TX_BM_INIT_PTR, dev->tx_buf_ring.pkt_nums |
-+			MTK_WED_TX_BM_INIT_SW_TAIL_IDX);
-+		wed_clr(dev, MTK_WED_TX_BM_CTRL, MTK_WED_TX_BM_CTRL_LEGACY_EN);
-+	}
- 
--	if (dev->ver > MTK_WED_V1) {
-+	if (dev->hw->version != 1) {
- 		wed_w32(dev, MTK_WED_TX_TKID_CTRL,
- 			MTK_WED_TX_TKID_CTRL_PAUSE |
- 			FIELD_PREP(MTK_WED_TX_TKID_CTRL_VLD_GRP_NUM,
--				   dev->buf_ring.size / 128) |
-+				   size / 128) |
- 			FIELD_PREP(MTK_WED_TX_TKID_CTRL_RSV_GRP_NUM,
--				   dev->buf_ring.size / 128));
--		wed_w32(dev, MTK_WED_TX_TKID_DYN_THR,
--			FIELD_PREP(MTK_WED_TX_TKID_DYN_THR_LO, 0) |
--			MTK_WED_TX_TKID_DYN_THR_HI);
-+				   size / 128));
-+
-+		/* return SKBID + SDP back to bm */
-+		if (dev->ver == 3)
-+			wed_set(dev, MTK_WED_TX_TKID_CTRL,
-+				MTK_WED_TX_TKID_CTRL_FREE_FORMAT);
-+		else
-+			wed_w32(dev, MTK_WED_TX_TKID_DYN_THR,
-+				FIELD_PREP(MTK_WED_TX_TKID_DYN_THR_LO, 0) |
-+				MTK_WED_TX_TKID_DYN_THR_HI);
- 	}
--	mtk_wed_reset(dev, MTK_WED_RESET_TX_BM);
-+	wed_w32(dev, MTK_WED_TX_BM_TKID,
-+		FIELD_PREP(MTK_WED_TX_BM_TKID_START,
-+			   dev->wlan.token_start) |
-+		FIELD_PREP(MTK_WED_TX_BM_TKID_END,
-+			   dev->wlan.token_start + dev->wlan.nbuf - 1));
- 
-+	wed_w32(dev, MTK_WED_TX_BM_INIT_PTR, dev->tx_buf_ring.pkt_nums |
-+		MTK_WED_TX_BM_INIT_SW_TAIL_IDX);
- 	wed_clr(dev, MTK_WED_TX_BM_CTRL, MTK_WED_TX_BM_CTRL_PAUSE);
--	if (dev->ver > MTK_WED_V1)
-+	if (dev->hw->version != 1)
- 		wed_clr(dev, MTK_WED_TX_TKID_CTRL, MTK_WED_TX_TKID_CTRL_PAUSE);
- }
- 
-@@ -977,7 +1408,26 @@ mtk_wed_rx_hw_init(struct mtk_wed_device *dev)
- 
- 	wed_w32(dev, MTK_WED_WPDMA_RX_D_RST_IDX, 0);
- 
-+	/* reset prefetch index of ring */
-+	wed_set(dev, MTK_WED_WPDMA_RX_D_PREF_RX0_SIDX,
-+		MTK_WED_WPDMA_RX_D_PREF_SIDX_IDX_CLR);
-+	wed_clr(dev, MTK_WED_WPDMA_RX_D_PREF_RX0_SIDX,
-+		MTK_WED_WPDMA_RX_D_PREF_SIDX_IDX_CLR);
-+
-+	wed_set(dev, MTK_WED_WPDMA_RX_D_PREF_RX1_SIDX,
-+		MTK_WED_WPDMA_RX_D_PREF_SIDX_IDX_CLR);
-+	wed_clr(dev, MTK_WED_WPDMA_RX_D_PREF_RX1_SIDX,
-+		MTK_WED_WPDMA_RX_D_PREF_SIDX_IDX_CLR);
-+
-+	/* reset prefetch FIFO of ring */
-+	wed_set(dev, MTK_WED_WPDMA_RX_D_PREF_FIFO_CFG,
-+		MTK_WED_WPDMA_RX_D_PREF_FIFO_CFG_R0_CLR |
-+		MTK_WED_WPDMA_RX_D_PREF_FIFO_CFG_R1_CLR);
-+	wed_w32(dev, MTK_WED_WPDMA_RX_D_PREF_FIFO_CFG, 0);
-+
- 	mtk_wed_rx_bm_hw_init(dev);
-+	if (dev->wlan.hwrro)
-+		mtk_wed_hwrro_init(dev);
- 	mtk_wed_rro_hw_init(dev);
- 	mtk_wed_route_qm_hw_init(dev);
- }
-@@ -991,7 +1441,7 @@ mtk_wed_hw_init(struct mtk_wed_device *dev)
- 	dev->init_done = true;
- 	mtk_wed_set_ext_int(dev, false);
- 	mtk_wed_tx_hw_init(dev);
--	if (dev->ver > MTK_WED_V1)
-+	if (mtk_wed_get_rx_capa(dev))
- 		mtk_wed_rx_hw_init(dev);
- }
- 
-@@ -1015,26 +1465,6 @@ mtk_wed_ring_reset(struct mtk_wdma_desc *desc, int size, int scale, bool tx)
- 	}
- }
- 
--static u32
--mtk_wed_check_busy(struct mtk_wed_device *dev, u32 reg, u32 mask)
--{
-- 	if (wed_r32(dev, reg) & mask)
--		return true;
--
--	return false;
--}
--
--static int
--mtk_wed_poll_busy(struct mtk_wed_device *dev, u32 reg, u32 mask)
--{
--	int sleep = 1000;
--	int timeout = 100 * sleep;
--	u32 val;
--
--	return read_poll_timeout(mtk_wed_check_busy, val, !val, sleep,
--				 timeout, false, dev, reg, mask);
--}
--
- static void
- mtk_wed_rx_reset(struct mtk_wed_device *dev)
- {
-@@ -1133,7 +1563,7 @@ mtk_wed_rx_reset(struct mtk_wed_device *dev)
- 		mtk_wed_ring_reset(desc, MTK_WED_RX_RING_SIZE, 1, false);
- 	}
- 
--	mtk_wed_free_rx_bm(dev);
-+	mtk_wed_free_rx_buffer(dev);
- }
- 
- 
-@@ -1271,12 +1701,15 @@ mtk_wed_wdma_rx_ring_setup(struct mtk_wed_device *dev,
- 		int idx, int size, bool reset)
- {
- 	struct mtk_wed_ring *wdma = &dev->tx_wdma[idx];
-+	int scale = dev->hw->version > 1 ? 2 : 1;
- 
- 	if(!reset)
- 		if (mtk_wed_ring_alloc(dev, wdma, MTK_WED_WDMA_RING_SIZE,
--				       dev->ver, true))
-+				       scale, true))
- 			return -ENOMEM;
- 
-+	wdma->flags |= MTK_WED_RING_CONFIGURED;
-+
- 	wdma_w32(dev, MTK_WDMA_RING_RX(idx) + MTK_WED_RING_OFS_BASE,
- 		 wdma->desc_phys);
- 	wdma_w32(dev, MTK_WDMA_RING_RX(idx) + MTK_WED_RING_OFS_COUNT,
-@@ -1296,12 +1729,33 @@ mtk_wed_wdma_tx_ring_setup(struct mtk_wed_device *dev,
- 	int idx, int size, bool reset)
- {
- 	struct mtk_wed_ring *wdma = &dev->rx_wdma[idx];
-+	int scale = dev->hw->version > 1 ? 2 : 1;
- 
- 	if (!reset)
- 		if (mtk_wed_ring_alloc(dev, wdma, MTK_WED_WDMA_RING_SIZE,
--				       dev->ver, true))
-+				       scale, true))
- 			return -ENOMEM;
- 
-+	if (dev->hw->version == 3) {
-+		struct mtk_wdma_desc *desc = wdma->desc;
-+		int i;
-+
-+		for (i = 0; i < MTK_WED_WDMA_RING_SIZE; i++) {
-+			desc->buf0 = 0;
-+			desc->ctrl = MTK_WDMA_DESC_CTRL_DMA_DONE;
-+			desc->buf1 = 0;
-+			desc->info = MTK_WDMA_TXD0_DESC_INFO_DMA_DONE;
-+			desc++;
-+			desc->buf0 = 0;
-+			desc->ctrl = MTK_WDMA_DESC_CTRL_DMA_DONE;
-+			desc->buf1 = 0;
-+			desc->info = MTK_WDMA_TXD1_DESC_INFO_DMA_DONE;
-+			desc++;
-+		}
-+	}
-+
-+	wdma->flags |= MTK_WED_RING_CONFIGURED;
-+
- 	wdma_w32(dev, MTK_WDMA_RING_TX(idx) + MTK_WED_RING_OFS_BASE,
- 		 wdma->desc_phys);
- 	wdma_w32(dev, MTK_WDMA_RING_TX(idx) + MTK_WED_RING_OFS_COUNT,
-@@ -1312,7 +1766,7 @@ mtk_wed_wdma_tx_ring_setup(struct mtk_wed_device *dev,
- 		 MTK_WDMA_RING_TX(idx) + MTK_WED_RING_OFS_DMA_IDX, 0);
- 	if (reset)
- 		mtk_wed_ring_reset(wdma->desc, MTK_WED_WDMA_RING_SIZE,
--				   dev->ver, true);
-+				   scale, true);
- 	if (idx == 0)  {
- 		wed_w32(dev, MTK_WED_WDMA_RING_TX
- 			+ MTK_WED_RING_OFS_BASE, wdma->desc_phys);
-@@ -1395,7 +1849,7 @@ mtk_wed_send_msg(struct mtk_wed_device *dev, int cmd_id, void *data, int len)
- {
- 	struct mtk_wed_wo *wo = dev->hw->wed_wo;
- 
--	if (dev->ver == MTK_WED_V1)
-+	if (!mtk_wed_get_rx_capa(dev))
- 		return 0;
- 
- 	return mtk_wed_mcu_send_msg(wo, MODULE_ID_WO, cmd_id, data, len, true);
-@@ -1420,24 +1874,106 @@ mtk_wed_ppe_check(struct mtk_wed_device *dev, struct sk_buff *skb,
- 	}
- }
- 
-+static void
-+mtk_wed_start_hwrro(struct mtk_wed_device *dev, u32 irq_mask)
-+{
-+	int idx, ret;
-+
-+	wed_w32(dev, MTK_WED_WPDMA_INT_MASK, irq_mask);
-+	wed_w32(dev, MTK_WED_INT_MASK, irq_mask);
-+
-+	if (!mtk_wed_get_rx_capa(dev) || !dev->wlan.hwrro)
-+		return;
-+
-+	wed_set(dev, MTK_WED_RRO_RX_D_CFG(2), MTK_WED_RRO_MSDU_PG_DRV_CLR);
-+	wed_w32(dev, MTK_WED_RRO_MSDU_PG_RING2_CFG, MTK_WED_RRO_MSDU_PG_DRV_CLR);
-+
-+	wed_w32(dev, MTK_WED_WPDMA_INT_CTRL_RRO_RX,
-+		MTK_WED_WPDMA_INT_CTRL_RRO_RX0_EN |
-+		MTK_WED_WPDMA_INT_CTRL_RRO_RX0_CLR |
-+		MTK_WED_WPDMA_INT_CTRL_RRO_RX1_EN |
-+		MTK_WED_WPDMA_INT_CTRL_RRO_RX1_CLR |
-+		FIELD_PREP(MTK_WED_WPDMA_INT_CTRL_RRO_RX0_DONE_TRIG,
-+			   dev->wlan.rro_rx_tbit[0]) |
-+		FIELD_PREP(MTK_WED_WPDMA_INT_CTRL_RRO_RX1_DONE_TRIG,
-+			   dev->wlan.rro_rx_tbit[1]));
-+
-+	wed_w32(dev, MTK_WED_WPDMA_INT_CTRL_RRO_MSDU_PG,
-+		MTK_WED_WPDMA_INT_CTRL_RRO_PG0_EN |
-+		MTK_WED_WPDMA_INT_CTRL_RRO_PG0_CLR |
-+		MTK_WED_WPDMA_INT_CTRL_RRO_PG1_EN |
-+		MTK_WED_WPDMA_INT_CTRL_RRO_PG1_CLR |
-+		MTK_WED_WPDMA_INT_CTRL_RRO_PG2_EN |
-+		MTK_WED_WPDMA_INT_CTRL_RRO_PG2_CLR |
-+		FIELD_PREP(MTK_WED_WPDMA_INT_CTRL_RRO_PG0_DONE_TRIG,
-+			   dev->wlan.rx_pg_tbit[0]) |
-+		FIELD_PREP(MTK_WED_WPDMA_INT_CTRL_RRO_PG1_DONE_TRIG,
-+			   dev->wlan.rx_pg_tbit[1])|
-+		FIELD_PREP(MTK_WED_WPDMA_INT_CTRL_RRO_PG2_DONE_TRIG,
-+			   dev->wlan.rx_pg_tbit[2]));
-+
-+	/*
-+	 * RRO_MSDU_PG_RING2_CFG1_FLD_DRV_EN should be enabled after
-+	 * WM FWDL completed, otherwise RRO_MSDU_PG ring may broken
-+	 */
-+	wed_set(dev, MTK_WED_RRO_MSDU_PG_RING2_CFG, MTK_WED_RRO_MSDU_PG_DRV_EN);
-+
-+	for (idx = 0; idx < MTK_WED_RX_QUEUES; idx++) {
-+		struct mtk_wed_ring *ring = &dev->rx_rro_ring[idx];
-+
-+		if(!(ring->flags & MTK_WED_RING_CONFIGURED))
-+			continue;
-+
-+		ret = mtk_wed_check_wfdma_rx_fill(dev, ring);
-+		if (!ret)
-+			dev_err(dev->hw->dev, "mtk_wed%d: rx_rro_ring(%d) init failed!\n",
-+				dev->hw->index, idx);
-+	}
-+
-+	for (idx = 0; idx < MTK_WED_RX_PAGE_QUEUES; idx++){
-+		struct mtk_wed_ring *ring = &dev->rx_page_ring[idx];
-+		if(!(ring->flags & MTK_WED_RING_CONFIGURED))
-+			continue;
-+
-+		ret = mtk_wed_check_wfdma_rx_fill(dev, ring);
-+		if (!ret)
-+			dev_err(dev->hw->dev, "mtk_wed%d: rx_page_ring(%d) init failed!\n",
-+				dev->hw->index, idx);
-+	}
-+}
-+
- static void
- mtk_wed_start(struct mtk_wed_device *dev, u32 irq_mask)
- {
- 	int i, ret;
- 
--	if (dev->ver > MTK_WED_V1)
--		ret = mtk_wed_rx_bm_alloc(dev);
-+	if (mtk_wed_get_rx_capa(dev)) {
-+		ret = mtk_wed_rx_buffer_alloc(dev);
-+		if (ret)
-+			return;
-+
-+		if (dev->wlan.hwrro)
-+			mtk_wed_rx_page_buffer_alloc(dev);
-+	}
- 
- 	for (i = 0; i < ARRAY_SIZE(dev->tx_wdma); i++)
- 		if (!dev->tx_wdma[i].desc)
- 			mtk_wed_wdma_rx_ring_setup(dev, i, 16, false);
- 
-+	for (i = 0; i < ARRAY_SIZE(dev->rx_page_ring); i++) {
-+		u32 count = MTK_WED_RRO_MSDU_PG_CTRL0(i) +
-+			    MTK_WED_RING_OFS_COUNT;
-+
-+		if (!wed_r32(dev, count))
-+			wed_w32(dev, count, 1);
-+	}
-+
- 	mtk_wed_hw_init(dev);
- 
- 	mtk_wed_set_int(dev, irq_mask);
- 	mtk_wed_set_ext_int(dev, true);
- 
--	if (dev->ver == MTK_WED_V1) {
-+	if (dev->hw->version == 1) {
- 		u32 val;
- 
- 		val = dev->wlan.wpdma_phys |
-@@ -1448,33 +1984,52 @@ mtk_wed_start(struct mtk_wed_device *dev, u32 irq_mask)
- 			val |= BIT(1);
- 		val |= BIT(0);
- 		regmap_write(dev->hw->mirror, dev->hw->index * 4, val);
--	} else {
-+	} else if (mtk_wed_get_rx_capa(dev)) {
- 		/* driver set mid ready and only once */
- 		wed_w32(dev, MTK_WED_EXT_INT_MASK1,
- 			MTK_WED_EXT_INT_STATUS_WPDMA_MID_RDY);
- 		wed_w32(dev, MTK_WED_EXT_INT_MASK2,
- 			MTK_WED_EXT_INT_STATUS_WPDMA_MID_RDY);
-+		if (dev->hw->version == 3)
-+			wed_w32(dev, MTK_WED_EXT_INT_MASK3,
-+				MTK_WED_EXT_INT_STATUS_WPDMA_MID_RDY);
- 
- 		wed_r32(dev, MTK_WED_EXT_INT_MASK1);
- 		wed_r32(dev, MTK_WED_EXT_INT_MASK2);
-+		if (dev->hw->version == 3)
-+			wed_r32(dev, MTK_WED_EXT_INT_MASK3);
- 
- 		ret = mtk_wed_rro_cfg(dev);
- 		if (ret)
- 			return;
- 	}
--	mtk_wed_set_512_support(dev, dev->wlan.wcid_512);
-+
-+	if (dev->hw->version == 2)
-+		mtk_wed_set_512_support(dev, dev->wlan.wcid_512);
-+	else if (dev->hw->version == 3)
-+		mtk_wed_pao_init(dev);
- 
- 	mtk_wed_dma_enable(dev);
- 	dev->running = true;
- }
- 
-+static int
-+mtk_wed_get_pci_base(struct mtk_wed_device *dev)
-+{
-+	if (dev->hw->index == 0)
-+		return MTK_WED_PCIE_BASE0;
-+	else if (dev->hw->index == 1)
-+		return MTK_WED_PCIE_BASE1;
-+	else
-+		return MTK_WED_PCIE_BASE2;
-+}
-+
- static int
- mtk_wed_attach(struct mtk_wed_device *dev)
- 	__releases(RCU)
- {
- 	struct mtk_wed_hw *hw;
- 	struct device *device;
--	u16 ver;
- 	int ret = 0;
- 
- 	RCU_LOCKDEP_WARN(!rcu_read_lock_held(),
-@@ -1494,34 +2049,30 @@ mtk_wed_attach(struct mtk_wed_device *dev)
- 		goto out;
- 	}
- 
--	device = dev->wlan.bus_type == MTK_WED_BUS_PCIE
--	? &dev->wlan.pci_dev->dev
--	: &dev->wlan.platform_dev->dev;
-+	device = dev->wlan.bus_type == MTK_WED_BUS_PCIE ?
-+				       &dev->wlan.pci_dev->dev
-+				       : &dev->wlan.platform_dev->dev;
- 	dev_info(device, "attaching wed device %d version %d\n",
--		 hw->index, hw->ver);
-+		 hw->index, hw->version);
- 
- 	dev->hw = hw;
- 	dev->dev = hw->dev;
- 	dev->irq = hw->irq;
- 	dev->wdma_idx = hw->index;
-+	dev->ver = hw->version;
-+
-+	if (dev->hw->version == 3)
-+		dev->hw->pci_base = mtk_wed_get_pci_base(dev);
- 
- 	if (hw->eth->dma_dev == hw->eth->dev &&
- 	    of_dma_is_coherent(hw->eth->dev->of_node))
- 		mtk_eth_set_dma_device(hw->eth, hw->dev);
- 
--	dev->ver = FIELD_GET(MTK_WED_REV_ID_MAJOR,
--			    wed_r32(dev, MTK_WED_REV_ID));
--	if (dev->ver > MTK_WED_V1)
--		ver = FIELD_GET(MTK_WED_REV_ID_MINOR,
--			    wed_r32(dev, MTK_WED_REV_ID));
--
--	dev->rev_id = ((dev->ver << 28) | ver << 16);
--
--	ret = mtk_wed_buffer_alloc(dev);
-+	ret = mtk_wed_tx_buffer_alloc(dev);
- 	if (ret)
- 		goto error;
- 
--	if (dev->ver > MTK_WED_V1) {
-+	if (mtk_wed_get_rx_capa(dev)) {
- 		ret = mtk_wed_rro_alloc(dev);
- 		if (ret)
- 			goto error;
-@@ -1533,15 +2084,20 @@ mtk_wed_attach(struct mtk_wed_device *dev)
- 	init_completion(&dev->wlan_reset_done);
- 	atomic_set(&dev->fe_reset, 0);
- 
--	if (dev->ver == MTK_WED_V1)
-+	if (dev->hw->version != 1)
-+		dev->rev_id = wed_r32(dev, MTK_WED_REV_ID);
-+	else
- 		regmap_update_bits(hw->hifsys, HIFSYS_DMA_AG_MAP,
- 				   BIT(hw->index), 0);
--	else
-+
-+	if (mtk_wed_get_rx_capa(dev))
- 		ret = mtk_wed_wo_init(hw);
- 
- error:
--	if (ret)
-+	if (ret) {
-+		pr_info("%s: detach wed\n", __func__);
- 		mtk_wed_detach(dev);
-+	}
- out:
- 	mutex_unlock(&hw_lock);
- 
-@@ -1576,8 +2132,26 @@ mtk_wed_tx_ring_setup(struct mtk_wed_device *dev, int idx,
- 	if (mtk_wed_wdma_rx_ring_setup(dev, idx, MTK_WED_WDMA_RING_SIZE, reset))
- 		return -ENOMEM;
- 
-+	if (dev->hw->version == 3 && idx == 1) {
-+		/* reset prefetch index */
-+		wed_set(dev, MTK_WED_WDMA_RX_PREF_CFG,
-+		       MTK_WED_WDMA_RX_PREF_RX0_SIDX_CLR |
-+		       MTK_WED_WDMA_RX_PREF_RX1_SIDX_CLR);
-+
-+		wed_clr(dev, MTK_WED_WDMA_RX_PREF_CFG,
-+		       MTK_WED_WDMA_RX_PREF_RX0_SIDX_CLR |
-+		       MTK_WED_WDMA_RX_PREF_RX1_SIDX_CLR);
-+
-+		/* reset prefetch FIFO */
-+		wed_w32(dev, MTK_WED_WDMA_RX_PREF_FIFO_CFG,
-+		       MTK_WED_WDMA_RX_PREF_FIFO_RX0_CLR |
-+		       MTK_WED_WDMA_RX_PREF_FIFO_RX1_CLR);
-+		wed_w32(dev, MTK_WED_WDMA_RX_PREF_FIFO_CFG, 0);
-+	}
-+
- 	ring->reg_base = MTK_WED_RING_TX(idx);
- 	ring->wpdma = regs;
-+	ring->flags |= MTK_WED_RING_CONFIGURED;
- 
- 	/* WED -> WPDMA */
- 	wpdma_tx_w32(dev, idx, MTK_WED_RING_OFS_BASE, ring->desc_phys);
-@@ -1599,7 +2173,7 @@ mtk_wed_txfree_ring_setup(struct mtk_wed_device *dev, void __iomem *regs)
- 	struct mtk_wed_ring *ring = &dev->txfree_ring;
- 	int i, idx = 1;
- 
--	if(dev->ver > MTK_WED_V1)
-+	if(dev->hw->version > 1)
- 		idx = 0;
- 
- 	/*
-@@ -1638,6 +2212,7 @@ mtk_wed_rx_ring_setup(struct mtk_wed_device *dev,
- 
- 	ring->reg_base = MTK_WED_RING_RX_DATA(idx);
- 	ring->wpdma = regs;
-+	ring->flags |= MTK_WED_RING_CONFIGURED;
- 	dev->hw->ring_num = idx + 1;
- 
- 	/* WPDMA ->  WED */
-@@ -1652,6 +2227,129 @@ mtk_wed_rx_ring_setup(struct mtk_wed_device *dev,
- 	return 0;
- }
- 
-+static int
-+mtk_wed_rro_rx_ring_setup(struct mtk_wed_device *dev, int idx, void __iomem *regs)
-+{
-+	struct mtk_wed_ring *ring = &dev->rx_rro_ring[idx];
-+
-+	ring->wpdma = regs;
-+
-+	wed_w32(dev, MTK_WED_RRO_RX_D_RX(idx) + MTK_WED_RING_OFS_BASE,
-+		readl(regs));
-+	wed_w32(dev, MTK_WED_RRO_RX_D_RX(idx) + MTK_WED_RING_OFS_COUNT,
-+		readl(regs + MTK_WED_RING_OFS_COUNT));
-+
-+	ring->flags |= MTK_WED_RING_CONFIGURED;
-+
-+	return 0;
-+}
-+
-+static int
-+mtk_wed_msdu_pg_rx_ring_setup(struct mtk_wed_device *dev, int idx, void __iomem *regs)
-+{
-+	struct mtk_wed_ring *ring = &dev->rx_page_ring[idx];
-+
-+	ring->wpdma = regs;
-+
-+	wed_w32(dev, MTK_WED_RRO_MSDU_PG_CTRL0(idx) + MTK_WED_RING_OFS_BASE,
-+		readl(regs));
-+	wed_w32(dev, MTK_WED_RRO_MSDU_PG_CTRL0(idx) + MTK_WED_RING_OFS_COUNT,
-+		readl(regs + MTK_WED_RING_OFS_COUNT));
-+
-+	ring->flags |= MTK_WED_RING_CONFIGURED;
-+
-+	return 0;
-+}
-+
-+static int
-+mtk_wed_ind_rx_ring_setup(struct mtk_wed_device *dev, void __iomem *regs)
-+{
-+	struct mtk_wed_ring *ring = &dev->ind_cmd_ring;
-+	u32 val = readl(regs + MTK_WED_RING_OFS_COUNT);
-+	int i = 0, cnt = 0;
-+
-+	ring->wpdma = regs;
-+
-+	if (readl(regs) & 0xf)
-+		pr_info("%s(): address is not 16-byte alignment\n", __func__);
-+
-+	wed_w32(dev, MTK_WED_IND_CMD_RX_CTRL1 + MTK_WED_RING_OFS_BASE,
-+		readl(regs) & 0xfffffff0);
-+
-+	wed_w32(dev, MTK_WED_IND_CMD_RX_CTRL1 + MTK_WED_RING_OFS_COUNT,
-+		readl(regs + MTK_WED_RING_OFS_COUNT));
-+
-+	/* ack sn cr */
-+	wed_w32(dev, MTK_WED_RRO_CFG0, dev->wlan.phy_base +
-+		dev->wlan.ind_cmd.ack_sn_addr);
-+	wed_w32(dev, MTK_WED_RRO_CFG1,
-+		FIELD_PREP(MTK_WED_RRO_CFG1_MAX_WIN_SZ,
-+			   dev->wlan.ind_cmd.win_size) |
-+		FIELD_PREP(MTK_WED_RRO_CFG1_PARTICL_SE_ID,
-+			   dev->wlan.ind_cmd.particular_sid));
-+
-+	/* particular session addr element */
-+	wed_w32(dev, MTK_WED_ADDR_ELEM_CFG0, dev->wlan.ind_cmd.particular_se_phys);
-+
-+	for (i = 0; i < dev->wlan.ind_cmd.se_group_nums; i++) {
-+		wed_w32(dev, MTK_WED_RADDR_ELEM_TBL_WDATA,
-+			dev->wlan.ind_cmd.addr_elem_phys[i] >> 4);
-+		wed_w32(dev, MTK_WED_ADDR_ELEM_TBL_CFG,
-+			MTK_WED_ADDR_ELEM_TBL_WR | (i & 0x7f));
-+
-+		val = wed_r32(dev, MTK_WED_ADDR_ELEM_TBL_CFG);
-+		while (!(val & MTK_WED_ADDR_ELEM_TBL_WR_RDY) &&
-+			 cnt < 100) {
-+			val = wed_r32(dev, MTK_WED_ADDR_ELEM_TBL_CFG);
-+			cnt++;
-+		}
-+		if (cnt >= 100) {
-+			dev_err(dev->hw->dev, "mtk_wed%d: write ba session base failed!\n",
-+				dev->hw->index);
-+		}
-+		/*if (mtk_wed_poll_busy(dev, MTK_WED_ADDR_ELEM_TBL_CFG,
-+				      MTK_WED_ADDR_ELEM_TBL_WR_RDY)) {
-+			dev_err(dev->hw->dev, "mtk_wed%d: write ba session base failed!\n",
-+				dev->hw->index);
-+			return -1;
-+		}*/
-+	}
-+
-+	/* pn check init */
-+	for (i = 0; i < dev->wlan.ind_cmd.particular_sid; i++) {
-+		wed_w32(dev, MTK_WED_PN_CHECK_WDATA_M,
-+			MTK_WED_PN_CHECK_IS_FIRST);
-+
-+		wed_w32(dev, MTK_WED_PN_CHECK_CFG, MTK_WED_PN_CHECK_WR |
-+			FIELD_PREP(MTK_WED_PN_CHECK_SE_ID, i));
-+
-+		cnt = 0;
-+		val = wed_r32(dev, MTK_WED_PN_CHECK_CFG);
-+		while (!(val & MTK_WED_PN_CHECK_WR_RDY) &&
-+			 cnt < 100) {
-+			val = wed_r32(dev, MTK_WED_PN_CHECK_CFG);
-+			cnt++;
-+		}
-+		if (cnt >= 100) {
-+			dev_err(dev->hw->dev, "mtk_wed%d: session(%d) init failed!\n",
-+				dev->hw->index, i);
-+		}
-+		/*if (mtk_wed_poll_busy(dev, MTK_WED_PN_CHECK_CFG,
-+				      MTK_WED_PN_CHECK_WR_RDY)) {
-+			dev_err(dev->hw->dev, "mtk_wed%d: session(%d) init failed!\n",
-+				dev->hw->index, i);
-+			//return -1;
-+		}*/
-+	}
-+
-+	wed_w32(dev, MTK_WED_RX_IND_CMD_CNT0, MTK_WED_RX_IND_CMD_DBG_CNT_EN);
-+
-+	wed_set(dev, MTK_WED_CTRL, MTK_WED_CTRL_WED_RX_IND_CMD_EN);
-+
-+	return 0;
-+}
-+
-+
- static u32
- mtk_wed_irq_get(struct mtk_wed_device *dev, u32 mask)
- {
-@@ -1659,9 +2357,13 @@ mtk_wed_irq_get(struct mtk_wed_device *dev, u32 mask)
- 
- 	val = wed_r32(dev, MTK_WED_EXT_INT_STATUS);
- 	wed_w32(dev, MTK_WED_EXT_INT_STATUS, val);
--	val &= MTK_WED_EXT_INT_STATUS_ERROR_MASK;
--	if (!dev->hw->num_flows)
--		val &= ~MTK_WED_EXT_INT_STATUS_TKID_WO_PYLD;
-+	if (dev->hw->version == 3) {
-+		val &= MTK_WED_EXT_INT_STATUS_RX_DRV_COHERENT;
-+	} else {
-+		val &= MTK_WED_EXT_INT_STATUS_ERROR_MASK;	
-+		if (!dev->hw->num_flows)
-+			val &= ~MTK_WED_EXT_INT_STATUS_TKID_WO_PYLD;	
-+	}
- 	if (val && net_ratelimit())
- 		pr_err("mtk_wed%d: error status=%08x\n", dev->hw->index, val);
- 
-@@ -1754,6 +2456,9 @@ void mtk_wed_add_hw(struct device_node *np, struct mtk_eth *eth,
- 		.tx_ring_setup = mtk_wed_tx_ring_setup,
- 		.txfree_ring_setup = mtk_wed_txfree_ring_setup,
- 		.rx_ring_setup = mtk_wed_rx_ring_setup,
-+		.rro_rx_ring_setup = mtk_wed_rro_rx_ring_setup,
-+		.msdu_pg_rx_ring_setup = mtk_wed_msdu_pg_rx_ring_setup,
-+		.ind_rx_ring_setup = mtk_wed_ind_rx_ring_setup,
- 		.msg_update = mtk_wed_send_msg,
- 		.start = mtk_wed_start,
- 		.stop = mtk_wed_stop,
-@@ -1765,6 +2470,7 @@ void mtk_wed_add_hw(struct device_node *np, struct mtk_eth *eth,
- 		.detach = mtk_wed_detach,
- 		.setup_tc = mtk_wed_eth_setup_tc,
- 		.ppe_check = mtk_wed_ppe_check,
-+		.start_hwrro = mtk_wed_start_hwrro,
- 	};
- 	struct device_node *eth_np = eth->dev->of_node;
- 	struct platform_device *pdev;
-@@ -1804,9 +2510,10 @@ void mtk_wed_add_hw(struct device_node *np, struct mtk_eth *eth,
- 	hw->wdma_phy = wdma_phy;
- 	hw->index = index;
- 	hw->irq = irq;
--	hw->ver = MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V2) ? 2 : 1;
-+	hw->version = MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V3) ?
-+		      3 : MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V2) ? 2 : 1;
- 
--	if (!MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V2)) {
-+	if (hw->version == 1) {
- 		hw->mirror = syscon_regmap_lookup_by_phandle(eth_np,
- 							     "mediatek,pcie-mirror");
- 		hw->hifsys = syscon_regmap_lookup_by_phandle(eth_np,
-@@ -1821,7 +2528,6 @@ void mtk_wed_add_hw(struct device_node *np, struct mtk_eth *eth,
- 			regmap_write(hw->mirror, 0, 0);
- 			regmap_write(hw->mirror, 4, 0);
- 		}
--		hw->ver = MTK_WED_V1;
- 	}
- 
- 	mtk_wed_hw_add_debugfs(hw);
-diff --git a/drivers/net/ethernet/mediatek/mtk_wed.h b/drivers/net/ethernet/mediatek/mtk_wed.h
-index 490873c..fcf7bd0 100644
---- a/drivers/net/ethernet/mediatek/mtk_wed.h
-+++ b/drivers/net/ethernet/mediatek/mtk_wed.h
-@@ -10,10 +10,13 @@
- #include <linux/netdevice.h>
- #define MTK_PCIE_BASE(n)		(0x1a143000 + (n) * 0x2000)
- 
--#define MTK_WED_PKT_SIZE		1900
-+#define MTK_WED_PKT_SIZE		1920//1900
- #define MTK_WED_BUF_SIZE		2048
-+#define MTK_WED_PAGE_BUF_SIZE		128
- #define MTK_WED_BUF_PER_PAGE		(PAGE_SIZE / 2048)
-+#define MTK_WED_RX_PAGE_BUF_PER_PAGE	(PAGE_SIZE / 128)
- #define MTK_WED_RX_RING_SIZE		1536
-+#define MTK_WED_RX_PG_BM_CNT		8192
- 
- #define MTK_WED_TX_RING_SIZE		2048
- #define MTK_WED_WDMA_RING_SIZE		512
-@@ -27,6 +30,9 @@
- #define MTK_WED_RRO_QUE_CNT		8192
- #define MTK_WED_MIOD_ENTRY_CNT		128
- 
-+#define MTK_WED_TX_BM_DMA_SIZE		65536
-+#define MTK_WED_TX_BM_PKT_CNT		32768
-+
- #define MODULE_ID_WO		1
- 
- struct mtk_eth;
-@@ -43,6 +49,8 @@ struct mtk_wed_hw {
- 	struct dentry *debugfs_dir;
- 	struct mtk_wed_device *wed_dev;
- 	struct mtk_wed_wo *wed_wo;
-+	struct mtk_wed_pao *wed_pao;
-+	u32 pci_base;
- 	u32 debugfs_reg;
- 	u32 num_flows;
- 	u32 wdma_phy;
-@@ -50,7 +58,8 @@ struct mtk_wed_hw {
- 	int ring_num;
- 	int irq;
- 	int index;
--	u32 ver;
-+	int token_id;
-+	u32 version;
- };
- 
- struct mtk_wdma_info {
-@@ -58,6 +67,18 @@ struct mtk_wdma_info {
- 	u8 queue;
- 	u16 wcid;
- 	u8 bss;
-+	u32 usr_info;
-+	u8 tid;
-+	u8 is_fixedrate;
-+	u8 is_prior;
-+	u8 is_sp;
-+	u8 hf;
-+	u8 amsdu_en;
-+};
-+
-+struct mtk_wed_pao {
-+	char *hif_txd[32];
-+	dma_addr_t hif_txd_phys[32];
- };
- 
- #ifdef CONFIG_NET_MEDIATEK_SOC_WED
-diff --git a/drivers/net/ethernet/mediatek/mtk_wed_debugfs.c b/drivers/net/ethernet/mediatek/mtk_wed_debugfs.c
-index 4a9e684..51e3d7c 100644
---- a/drivers/net/ethernet/mediatek/mtk_wed_debugfs.c
-+++ b/drivers/net/ethernet/mediatek/mtk_wed_debugfs.c
-@@ -11,9 +11,11 @@ struct reg_dump {
- 	u16 offset;
- 	u8 type;
- 	u8 base;
-+	u32 mask;
- };
- 
- enum {
-+	DUMP_TYPE_END,
- 	DUMP_TYPE_STRING,
- 	DUMP_TYPE_WED,
- 	DUMP_TYPE_WDMA,
-@@ -23,8 +25,11 @@ enum {
- 	DUMP_TYPE_WED_RRO,
- };
- 
-+#define DUMP_END() { .type = DUMP_TYPE_END }
- #define DUMP_STR(_str) { _str, 0, DUMP_TYPE_STRING }
- #define DUMP_REG(_reg, ...) { #_reg, MTK_##_reg, __VA_ARGS__ }
-+#define DUMP_REG_MASK(_reg, _mask) { #_mask, MTK_##_reg, DUMP_TYPE_WED, 0, MTK_##_mask }
-+
- #define DUMP_RING(_prefix, _base, ...)				\
- 	{ _prefix " BASE", _base, __VA_ARGS__ },		\
- 	{ _prefix " CNT",  _base + 0x4, __VA_ARGS__ },	\
-@@ -32,6 +37,7 @@ enum {
- 	{ _prefix " DIDX", _base + 0xc, __VA_ARGS__ }
- 
- #define DUMP_WED(_reg) DUMP_REG(_reg, DUMP_TYPE_WED)
-+#define DUMP_WED_MASK(_reg, _mask) DUMP_REG_MASK(_reg, _mask)
- #define DUMP_WED_RING(_base) DUMP_RING(#_base, MTK_##_base, DUMP_TYPE_WED)
- 
- #define DUMP_WDMA(_reg) DUMP_REG(_reg, DUMP_TYPE_WDMA)
-@@ -52,36 +58,49 @@ print_reg_val(struct seq_file *s, const char *name, u32 val)
- 
- static void
- dump_wed_regs(struct seq_file *s, struct mtk_wed_device *dev,
--	      const struct reg_dump *regs, int n_regs)
-+	      const struct reg_dump **regs)
- {
--	const struct reg_dump *cur;
-+	const struct reg_dump **cur_o = regs, *cur;
-+	bool newline = false;
- 	u32 val;
- 
--	for (cur = regs; cur < &regs[n_regs]; cur++) {
--		switch (cur->type) {
--		case DUMP_TYPE_STRING:
--			seq_printf(s, "%s======== %s:\n",
--				   cur > regs ? "\n" : "",
--				   cur->name);
--			continue;
--		case DUMP_TYPE_WED:
--		case DUMP_TYPE_WED_RRO:
--			val = wed_r32(dev, cur->offset);
--			break;
--		case DUMP_TYPE_WDMA:
--			val = wdma_r32(dev, cur->offset);
--			break;
--		case DUMP_TYPE_WPDMA_TX:
--			val = wpdma_tx_r32(dev, cur->base, cur->offset);
--			break;
--		case DUMP_TYPE_WPDMA_TXFREE:
--			val = wpdma_txfree_r32(dev, cur->offset);
--			break;
--		case DUMP_TYPE_WPDMA_RX:
--			val = wpdma_rx_r32(dev, cur->base, cur->offset);
--			break;
-+	while (*cur_o) {
-+		cur = *cur_o;
-+
-+		while (cur->type != DUMP_TYPE_END) {
-+			switch (cur->type) {
-+			case DUMP_TYPE_STRING:
-+				seq_printf(s, "%s======== %s:\n",
-+					   newline ? "\n" : "",
-+					   cur->name);
-+				newline = true;
-+				cur++;
-+				continue;
-+			case DUMP_TYPE_WED:
-+			case DUMP_TYPE_WED_RRO:
-+				val = wed_r32(dev, cur->offset);
-+				break;
-+			case DUMP_TYPE_WDMA:
-+				val = wdma_r32(dev, cur->offset);
-+				break;
-+			case DUMP_TYPE_WPDMA_TX:
-+				val = wpdma_tx_r32(dev, cur->base, cur->offset);
-+				break;
-+			case DUMP_TYPE_WPDMA_TXFREE:
-+				val = wpdma_txfree_r32(dev, cur->offset);
-+				break;
-+			case DUMP_TYPE_WPDMA_RX:
-+				val = wpdma_rx_r32(dev, cur->base, cur->offset);
-+				break;
-+			}
-+
-+			if (cur->mask)
-+				val = (cur->mask & val) >> (ffs(cur->mask) - 1);
-+
-+			print_reg_val(s, cur->name, val);
-+			cur++;
- 		}
--		print_reg_val(s, cur->name, val);
-+		cur_o++;
- 	}
- }
- 
-@@ -89,7 +108,7 @@ dump_wed_regs(struct seq_file *s, struct mtk_wed_device *dev,
- static int
- wed_txinfo_show(struct seq_file *s, void *data)
- {
--	static const struct reg_dump regs[] = {
-+	static const struct reg_dump regs_common[] = {
- 		DUMP_STR("WED TX"),
- 		DUMP_WED(WED_TX_MIB(0)),
- 		DUMP_WED_RING(WED_RING_TX(0)),
-@@ -128,16 +147,32 @@ wed_txinfo_show(struct seq_file *s, void *data)
- 		DUMP_WDMA_RING(WDMA_RING_RX(0)),
- 		DUMP_WDMA_RING(WDMA_RING_RX(1)),
- 
--		DUMP_STR("TX FREE"),
-+		DUMP_STR("WED TX FREE"),
- 		DUMP_WED(WED_RX_MIB(0)),
-+		DUMP_WED_RING(WED_RING_RX(0)),
-+		DUMP_WED(WED_WPDMA_RX_COHERENT_MIB(0)),
-+
-+		DUMP_WED(WED_RX_MIB(1)),
-+		DUMP_WED_RING(WED_RING_RX(1)),
-+		DUMP_WED(WED_WPDMA_RX_COHERENT_MIB(1)),
-+		DUMP_STR("WED_WPDMA TX FREE"),
-+		DUMP_WED_RING(WED_WPDMA_RING_RX(0)),
-+		DUMP_WED_RING(WED_WPDMA_RING_RX(1)),
-+		DUMP_END(),
-+	};
-+
-+	static const struct reg_dump *regs[] = {
-+		&regs_common[0],
-+		NULL,
- 	};
-+
- 	struct mtk_wed_hw *hw = s->private;
- 	struct mtk_wed_device *dev = hw->wed_dev;
- 
- 	if (!dev)
- 		return 0;
- 
--	dump_wed_regs(s, dev, regs, ARRAY_SIZE(regs));
-+	dump_wed_regs(s, dev, regs);
- 
- 	return 0;
- }
-@@ -146,7 +181,7 @@ DEFINE_SHOW_ATTRIBUTE(wed_txinfo);
- static int
- wed_rxinfo_show(struct seq_file *s, void *data)
- {
--	static const struct reg_dump regs[] = {
-+	static const struct reg_dump regs_common[] = {
- 		DUMP_STR("WPDMA RX"),
- 		DUMP_WPDMA_RX_RING(0),
- 		DUMP_WPDMA_RX_RING(1),
-@@ -164,7 +199,7 @@ wed_rxinfo_show(struct seq_file *s, void *data)
- 		DUMP_WED_RING(WED_RING_RX_DATA(0)),
- 		DUMP_WED_RING(WED_RING_RX_DATA(1)),
- 
--		DUMP_STR("WED RRO"),
-+		DUMP_STR("WED WO RRO"),
- 		DUMP_WED_RRO_RING(WED_RROQM_MIOD_CTRL0),
- 		DUMP_WED(WED_RROQM_MID_MIB),
- 		DUMP_WED(WED_RROQM_MOD_MIB),
-@@ -175,16 +210,6 @@ wed_rxinfo_show(struct seq_file *s, void *data)
- 		DUMP_WED(WED_RROQM_FDBK_ANC_MIB),
- 		DUMP_WED(WED_RROQM_FDBK_ANC2H_MIB),
- 
--		DUMP_STR("WED Route QM"),
--		DUMP_WED(WED_RTQM_R2H_MIB(0)),
--		DUMP_WED(WED_RTQM_R2Q_MIB(0)),
--		DUMP_WED(WED_RTQM_Q2H_MIB(0)),
--		DUMP_WED(WED_RTQM_R2H_MIB(1)),
--		DUMP_WED(WED_RTQM_R2Q_MIB(1)),
--		DUMP_WED(WED_RTQM_Q2H_MIB(1)),
--		DUMP_WED(WED_RTQM_Q2N_MIB),
--		DUMP_WED(WED_RTQM_Q2B_MIB),
--		DUMP_WED(WED_RTQM_PFDBK_MIB),
- 
- 		DUMP_STR("WED WDMA TX"),
- 		DUMP_WED(WED_WDMA_TX_MIB),
-@@ -205,15 +230,99 @@ wed_rxinfo_show(struct seq_file *s, void *data)
- 		DUMP_WED(WED_RX_BM_INTF2),
- 		DUMP_WED(WED_RX_BM_INTF),
- 		DUMP_WED(WED_RX_BM_ERR_STS),
-+		DUMP_END()
-+	};
-+
-+	static const struct reg_dump regs_v2[] = {
-+		DUMP_STR("WED Route QM"),
-+		DUMP_WED(WED_RTQM_R2H_MIB(0)),
-+		DUMP_WED(WED_RTQM_R2Q_MIB(0)),
-+		DUMP_WED(WED_RTQM_Q2H_MIB(0)),
-+		DUMP_WED(WED_RTQM_R2H_MIB(1)),
-+		DUMP_WED(WED_RTQM_R2Q_MIB(1)),
-+		DUMP_WED(WED_RTQM_Q2H_MIB(1)),
-+		DUMP_WED(WED_RTQM_Q2N_MIB),
-+		DUMP_WED(WED_RTQM_Q2B_MIB),
-+		DUMP_WED(WED_RTQM_PFDBK_MIB),
-+
-+		DUMP_END()
-+	};
-+
-+	static const struct reg_dump regs_v3[] = {
-+		DUMP_STR("WED RX RRO DATA"),
-+		DUMP_WED_RING(WED_RRO_RX_D_RX(0)),
-+		DUMP_WED_RING(WED_RRO_RX_D_RX(1)),
-+
-+		DUMP_STR("WED RX MSDU PAGE"),
-+		DUMP_WED_RING(WED_RRO_MSDU_PG_CTRL0(0)),
-+		DUMP_WED_RING(WED_RRO_MSDU_PG_CTRL0(1)),
-+		DUMP_WED_RING(WED_RRO_MSDU_PG_CTRL0(2)),
-+
-+		DUMP_STR("WED RX IND CMD"),
-+		DUMP_WED(WED_IND_CMD_RX_CTRL1),
-+		DUMP_WED_MASK(WED_IND_CMD_RX_CTRL2, WED_IND_CMD_MAX_CNT),
-+		DUMP_WED_MASK(WED_IND_CMD_RX_CTRL0, WED_IND_CMD_PROC_IDX),
-+		DUMP_WED_MASK(RRO_IND_CMD_SIGNATURE, RRO_IND_CMD_DMA_IDX),
-+		DUMP_WED_MASK(WED_IND_CMD_RX_CTRL0, WED_IND_CMD_MAGIC_CNT),
-+		DUMP_WED_MASK(RRO_IND_CMD_SIGNATURE, RRO_IND_CMD_MAGIC_CNT),
-+		DUMP_WED_MASK(WED_IND_CMD_RX_CTRL0,
-+			      WED_IND_CMD_PREFETCH_FREE_CNT),
-+		DUMP_WED_MASK(WED_RRO_CFG1, WED_RRO_CFG1_PARTICL_SE_ID),
-+
-+		DUMP_STR("WED ADDR ELEM"),
-+		DUMP_WED(WED_ADDR_ELEM_CFG0),
-+		DUMP_WED_MASK(WED_ADDR_ELEM_CFG1,
-+			      WED_ADDR_ELEM_PREFETCH_FREE_CNT),
-+
-+		DUMP_STR("WED Route QM"),
-+		DUMP_WED(WED_RTQM_ENQ_I2Q_DMAD_CNT),
-+		DUMP_WED(WED_RTQM_ENQ_I2N_DMAD_CNT),
-+		DUMP_WED(WED_RTQM_ENQ_I2Q_PKT_CNT),
-+		DUMP_WED(WED_RTQM_ENQ_I2N_PKT_CNT),
-+		DUMP_WED(WED_RTQM_ENQ_USED_ENTRY_CNT),
-+		DUMP_WED(WED_RTQM_ENQ_ERR_CNT),
-+
-+		DUMP_WED(WED_RTQM_DEQ_DMAD_CNT),
-+		DUMP_WED(WED_RTQM_DEQ_Q2I_DMAD_CNT),
-+		DUMP_WED(WED_RTQM_DEQ_PKT_CNT),
-+		DUMP_WED(WED_RTQM_DEQ_Q2I_PKT_CNT),
-+		DUMP_WED(WED_RTQM_DEQ_USED_PFDBK_CNT),
-+		DUMP_WED(WED_RTQM_DEQ_ERR_CNT),
-+
-+		DUMP_END()
-+	};
-+
-+	static const struct reg_dump *regs_new_v2[] = {
-+		&regs_common[0],
-+		&regs_v2[0],
-+		NULL,
-+	};
-+
-+	static const struct reg_dump *regs_new_v3[] = {
-+		&regs_common[0],
-+		&regs_v3[0],
-+		NULL,
- 	};
- 
- 	struct mtk_wed_hw *hw = s->private;
- 	struct mtk_wed_device *dev = hw->wed_dev;
-+	const struct reg_dump **regs;
- 
- 	if (!dev)
- 		return 0;
- 
--	dump_wed_regs(s, dev, regs, ARRAY_SIZE(regs));
-+	switch(dev->hw->version) {
-+	case 2:
-+		regs = regs_new_v2;
-+		break;
-+	case 3:
-+		regs = regs_new_v3;
-+		break;
-+	default:
-+		return 0;
-+	}
-+
-+	dump_wed_regs(s, dev, regs);
- 
- 	return 0;
- }
-@@ -248,6 +357,383 @@ mtk_wed_reg_get(void *data, u64 *val)
- DEFINE_DEBUGFS_ATTRIBUTE(fops_regval, mtk_wed_reg_get, mtk_wed_reg_set,
-              "0x%08llx\n");
- 
-+static int
-+wed_token_txd_show(struct seq_file *s, void *data)
-+{
-+	struct mtk_wed_hw *hw = s->private;
-+	struct mtk_wed_device *dev = hw->wed_dev;
-+	struct dma_page_info *page_list = dev->tx_buf_ring.pages;
-+	int token = dev->wlan.token_start;
-+	u32 val = hw->token_id, size = 1;
-+	int page_idx = (val - token) / 2;
-+	int i;
-+
-+	if (val < token) {
-+		size = val;
-+		page_idx = 0;
-+	}
-+
-+	for (i = 0; i < size; i += MTK_WED_BUF_PER_PAGE) {
-+		void *page = page_list[page_idx++].addr;
-+		void *buf;
-+		int j;
-+
-+		if (!page)
-+			break;
-+
-+		buf = page_to_virt(page);
-+
-+		for (j = 0; j < MTK_WED_BUF_PER_PAGE; j++) {
-+			printk("[TXD]:token id = %d\n", token + 2 * (page_idx - 1) + j);
-+			print_hex_dump(KERN_ERR , "", DUMP_PREFIX_OFFSET, 16, 1, (u8 *)buf, 128, false);
-+			seq_printf(s, "\n");
-+
-+			buf += MTK_WED_BUF_SIZE;
-+		}
-+	}
-+
-+	return 0;
-+}
-+
-+DEFINE_SHOW_ATTRIBUTE(wed_token_txd);
-+
-+static int
-+wed_pao_show(struct seq_file *s, void *data)
-+{
-+	static const struct reg_dump regs_common[] = {
-+		DUMP_STR("PAO AMDSU INFO"),
-+		DUMP_WED(WED_PAO_MON_AMSDU_FIFO_DMAD),
-+
-+		DUMP_STR("PAO AMDSU ENG0 INFO"),
-+		DUMP_WED(WED_PAO_MON_AMSDU_ENG_DMAD(0)),
-+		DUMP_WED(WED_PAO_MON_AMSDU_ENG_QFPL(0)),
-+		DUMP_WED(WED_PAO_MON_AMSDU_ENG_QENI(0)),
-+		DUMP_WED(WED_PAO_MON_AMSDU_ENG_QENO(0)),
-+		DUMP_WED(WED_PAO_MON_AMSDU_ENG_MERG(0)),
-+		DUMP_WED_MASK(WED_PAO_MON_AMSDU_ENG_CNT8(0),
-+			      WED_PAO_AMSDU_ENG_MAX_PL_CNT),
-+		DUMP_WED_MASK(WED_PAO_MON_AMSDU_ENG_CNT8(0),
-+			      WED_PAO_AMSDU_ENG_MAX_QGPP_CNT),
-+		DUMP_WED_MASK(WED_PAO_MON_AMSDU_ENG_CNT9(0),
-+			      WED_PAO_AMSDU_ENG_CUR_ENTRY),
-+		DUMP_WED_MASK(WED_PAO_MON_AMSDU_ENG_CNT9(0),
-+			      WED_PAO_AMSDU_ENG_MAX_BUF_MERGED),
-+		DUMP_WED_MASK(WED_PAO_MON_AMSDU_ENG_CNT9(0),
-+			      WED_PAO_AMSDU_ENG_MAX_MSDU_MERGED),
-+
-+		DUMP_STR("PAO AMDSU ENG1 INFO"),
-+		DUMP_WED(WED_PAO_MON_AMSDU_ENG_DMAD(1)),
-+		DUMP_WED(WED_PAO_MON_AMSDU_ENG_QFPL(1)),
-+		DUMP_WED(WED_PAO_MON_AMSDU_ENG_QENI(1)),
-+		DUMP_WED(WED_PAO_MON_AMSDU_ENG_QENO(1)),
-+		DUMP_WED(WED_PAO_MON_AMSDU_ENG_MERG(1)),
-+		DUMP_WED_MASK(WED_PAO_MON_AMSDU_ENG_CNT8(1),
-+			      WED_PAO_AMSDU_ENG_MAX_PL_CNT),
-+		DUMP_WED_MASK(WED_PAO_MON_AMSDU_ENG_CNT8(1),
-+			      WED_PAO_AMSDU_ENG_MAX_QGPP_CNT),
-+		DUMP_WED_MASK(WED_PAO_MON_AMSDU_ENG_CNT9(1),
-+			      WED_PAO_AMSDU_ENG_CUR_ENTRY),
-+		DUMP_WED_MASK(WED_PAO_MON_AMSDU_ENG_CNT9(2),
-+			      WED_PAO_AMSDU_ENG_MAX_BUF_MERGED),
-+		DUMP_WED_MASK(WED_PAO_MON_AMSDU_ENG_CNT9(2),
-+			      WED_PAO_AMSDU_ENG_MAX_MSDU_MERGED),
-+
-+		DUMP_STR("PAO AMDSU ENG2 INFO"),
-+		DUMP_WED(WED_PAO_MON_AMSDU_ENG_DMAD(2)),
-+		DUMP_WED(WED_PAO_MON_AMSDU_ENG_QFPL(2)),
-+		DUMP_WED(WED_PAO_MON_AMSDU_ENG_QENI(2)),
-+		DUMP_WED(WED_PAO_MON_AMSDU_ENG_QENO(2)),
-+		DUMP_WED(WED_PAO_MON_AMSDU_ENG_MERG(2)),
-+		DUMP_WED_MASK(WED_PAO_MON_AMSDU_ENG_CNT8(2),
-+			      WED_PAO_AMSDU_ENG_MAX_PL_CNT),
-+		DUMP_WED_MASK(WED_PAO_MON_AMSDU_ENG_CNT8(2),
-+			      WED_PAO_AMSDU_ENG_MAX_QGPP_CNT),
-+		DUMP_WED_MASK(WED_PAO_MON_AMSDU_ENG_CNT9(2),
-+			      WED_PAO_AMSDU_ENG_CUR_ENTRY),
-+		DUMP_WED_MASK(WED_PAO_MON_AMSDU_ENG_CNT9(2),
-+			      WED_PAO_AMSDU_ENG_MAX_BUF_MERGED),
-+		DUMP_WED_MASK(WED_PAO_MON_AMSDU_ENG_CNT9(2),
-+			      WED_PAO_AMSDU_ENG_MAX_MSDU_MERGED),
-+
-+		DUMP_STR("PAO AMDSU ENG3 INFO"),
-+		DUMP_WED(WED_PAO_MON_AMSDU_ENG_DMAD(3)),
-+		DUMP_WED(WED_PAO_MON_AMSDU_ENG_QFPL(3)),
-+		DUMP_WED(WED_PAO_MON_AMSDU_ENG_QENI(3)),
-+		DUMP_WED(WED_PAO_MON_AMSDU_ENG_QENO(3)),
-+		DUMP_WED(WED_PAO_MON_AMSDU_ENG_MERG(3)),
-+		DUMP_WED_MASK(WED_PAO_MON_AMSDU_ENG_CNT8(3),
-+			      WED_PAO_AMSDU_ENG_MAX_PL_CNT),
-+		DUMP_WED_MASK(WED_PAO_MON_AMSDU_ENG_CNT8(3),
-+			      WED_PAO_AMSDU_ENG_MAX_QGPP_CNT),
-+		DUMP_WED_MASK(WED_PAO_MON_AMSDU_ENG_CNT9(3),
-+			      WED_PAO_AMSDU_ENG_CUR_ENTRY),
-+		DUMP_WED_MASK(WED_PAO_MON_AMSDU_ENG_CNT9(3),
-+			      WED_PAO_AMSDU_ENG_MAX_BUF_MERGED),
-+		DUMP_WED_MASK(WED_PAO_MON_AMSDU_ENG_CNT9(3),
-+			      WED_PAO_AMSDU_ENG_MAX_MSDU_MERGED),
-+
-+		DUMP_STR("PAO AMDSU ENG4 INFO"),
-+		DUMP_WED(WED_PAO_MON_AMSDU_ENG_DMAD(4)),
-+		DUMP_WED(WED_PAO_MON_AMSDU_ENG_QFPL(4)),
-+		DUMP_WED(WED_PAO_MON_AMSDU_ENG_QENI(4)),
-+		DUMP_WED(WED_PAO_MON_AMSDU_ENG_QENO(4)),
-+		DUMP_WED(WED_PAO_MON_AMSDU_ENG_MERG(4)),
-+		DUMP_WED_MASK(WED_PAO_MON_AMSDU_ENG_CNT8(4),
-+			      WED_PAO_AMSDU_ENG_MAX_PL_CNT),
-+		DUMP_WED_MASK(WED_PAO_MON_AMSDU_ENG_CNT8(4),
-+			      WED_PAO_AMSDU_ENG_MAX_QGPP_CNT),
-+		DUMP_WED_MASK(WED_PAO_MON_AMSDU_ENG_CNT9(4),
-+			      WED_PAO_AMSDU_ENG_CUR_ENTRY),
-+		DUMP_WED_MASK(WED_PAO_MON_AMSDU_ENG_CNT9(4),
-+			      WED_PAO_AMSDU_ENG_MAX_BUF_MERGED),
-+		DUMP_WED_MASK(WED_PAO_MON_AMSDU_ENG_CNT9(4),
-+			      WED_PAO_AMSDU_ENG_MAX_MSDU_MERGED),
-+
-+		DUMP_STR("PAO AMDSU ENG5 INFO"),
-+		DUMP_WED(WED_PAO_MON_AMSDU_ENG_DMAD(5)),
-+		DUMP_WED(WED_PAO_MON_AMSDU_ENG_QFPL(5)),
-+		DUMP_WED(WED_PAO_MON_AMSDU_ENG_QENI(5)),
-+		DUMP_WED(WED_PAO_MON_AMSDU_ENG_QENO(5)),
-+		DUMP_WED(WED_PAO_MON_AMSDU_ENG_MERG(5)),
-+		DUMP_WED_MASK(WED_PAO_MON_AMSDU_ENG_CNT8(5),
-+			      WED_PAO_AMSDU_ENG_MAX_PL_CNT),
-+		DUMP_WED_MASK(WED_PAO_MON_AMSDU_ENG_CNT8(5),
-+			      WED_PAO_AMSDU_ENG_MAX_QGPP_CNT),
-+		DUMP_WED_MASK(WED_PAO_MON_AMSDU_ENG_CNT9(5),
-+			      WED_PAO_AMSDU_ENG_CUR_ENTRY),
-+		DUMP_WED_MASK(WED_PAO_MON_AMSDU_ENG_CNT9(5),
-+			      WED_PAO_AMSDU_ENG_MAX_BUF_MERGED),
-+		DUMP_WED_MASK(WED_PAO_MON_AMSDU_ENG_CNT9(5),
-+			      WED_PAO_AMSDU_ENG_MAX_MSDU_MERGED),
-+
-+		DUMP_STR("PAO AMDSU ENG6 INFO"),
-+		DUMP_WED(WED_PAO_MON_AMSDU_ENG_DMAD(6)),
-+		DUMP_WED(WED_PAO_MON_AMSDU_ENG_QFPL(6)),
-+		DUMP_WED(WED_PAO_MON_AMSDU_ENG_QENI(6)),
-+		DUMP_WED(WED_PAO_MON_AMSDU_ENG_QENO(6)),
-+		DUMP_WED(WED_PAO_MON_AMSDU_ENG_MERG(6)),
-+		DUMP_WED_MASK(WED_PAO_MON_AMSDU_ENG_CNT8(6),
-+			      WED_PAO_AMSDU_ENG_MAX_PL_CNT),
-+		DUMP_WED_MASK(WED_PAO_MON_AMSDU_ENG_CNT8(6),
-+			      WED_PAO_AMSDU_ENG_MAX_QGPP_CNT),
-+		DUMP_WED_MASK(WED_PAO_MON_AMSDU_ENG_CNT9(6),
-+			      WED_PAO_AMSDU_ENG_CUR_ENTRY),
-+		DUMP_WED_MASK(WED_PAO_MON_AMSDU_ENG_CNT9(6),
-+			      WED_PAO_AMSDU_ENG_MAX_BUF_MERGED),
-+		DUMP_WED_MASK(WED_PAO_MON_AMSDU_ENG_CNT9(6),
-+			      WED_PAO_AMSDU_ENG_MAX_MSDU_MERGED),
-+
-+		DUMP_STR("PAO AMDSU ENG7 INFO"),
-+		DUMP_WED(WED_PAO_MON_AMSDU_ENG_DMAD(7)),
-+		DUMP_WED(WED_PAO_MON_AMSDU_ENG_QFPL(7)),
-+		DUMP_WED(WED_PAO_MON_AMSDU_ENG_QENI(7)),
-+		DUMP_WED(WED_PAO_MON_AMSDU_ENG_QENO(7)),
-+		DUMP_WED(WED_PAO_MON_AMSDU_ENG_MERG(7)),
-+		DUMP_WED_MASK(WED_PAO_MON_AMSDU_ENG_CNT8(7),
-+			      WED_PAO_AMSDU_ENG_MAX_PL_CNT),
-+		DUMP_WED_MASK(WED_PAO_MON_AMSDU_ENG_CNT8(7),
-+			      WED_PAO_AMSDU_ENG_MAX_QGPP_CNT),
-+		DUMP_WED_MASK(WED_PAO_MON_AMSDU_ENG_CNT9(7),
-+			      WED_PAO_AMSDU_ENG_CUR_ENTRY),
-+		DUMP_WED_MASK(WED_PAO_MON_AMSDU_ENG_CNT9(7),
-+			      WED_PAO_AMSDU_ENG_MAX_BUF_MERGED),
-+		DUMP_WED_MASK(WED_PAO_MON_AMSDU_ENG_CNT9(4),
-+			      WED_PAO_AMSDU_ENG_MAX_MSDU_MERGED),
-+
-+		DUMP_STR("PAO AMDSU ENG8 INFO"),
-+		DUMP_WED(WED_PAO_MON_AMSDU_ENG_DMAD(8)),
-+		DUMP_WED(WED_PAO_MON_AMSDU_ENG_QFPL(8)),
-+		DUMP_WED(WED_PAO_MON_AMSDU_ENG_QENI(8)),
-+		DUMP_WED(WED_PAO_MON_AMSDU_ENG_QENO(8)),
-+		DUMP_WED(WED_PAO_MON_AMSDU_ENG_MERG(8)),
-+		DUMP_WED_MASK(WED_PAO_MON_AMSDU_ENG_CNT8(8),
-+			      WED_PAO_AMSDU_ENG_MAX_PL_CNT),
-+		DUMP_WED_MASK(WED_PAO_MON_AMSDU_ENG_CNT8(8),
-+			      WED_PAO_AMSDU_ENG_MAX_QGPP_CNT),
-+		DUMP_WED_MASK(WED_PAO_MON_AMSDU_ENG_CNT9(8),
-+			      WED_PAO_AMSDU_ENG_CUR_ENTRY),
-+		DUMP_WED_MASK(WED_PAO_MON_AMSDU_ENG_CNT9(8),
-+			      WED_PAO_AMSDU_ENG_MAX_BUF_MERGED),
-+		DUMP_WED_MASK(WED_PAO_MON_AMSDU_ENG_CNT9(8),
-+			      WED_PAO_AMSDU_ENG_MAX_MSDU_MERGED),
-+
-+		DUMP_STR("PAO QMEM INFO"),
-+		DUMP_WED_MASK(WED_PAO_MON_QMEM_CNT(0), WED_PAO_QMEM_FQ_CNT),
-+		DUMP_WED_MASK(WED_PAO_MON_QMEM_CNT(0), WED_PAO_QMEM_SP_QCNT),
-+		DUMP_WED_MASK(WED_PAO_MON_QMEM_CNT(1), WED_PAO_QMEM_TID0_QCNT),
-+		DUMP_WED_MASK(WED_PAO_MON_QMEM_CNT(1), WED_PAO_QMEM_TID1_QCNT),
-+		DUMP_WED_MASK(WED_PAO_MON_QMEM_CNT(2), WED_PAO_QMEM_TID2_QCNT),
-+		DUMP_WED_MASK(WED_PAO_MON_QMEM_CNT(2), WED_PAO_QMEM_TID3_QCNT),
-+		DUMP_WED_MASK(WED_PAO_MON_QMEM_CNT(3), WED_PAO_QMEM_TID4_QCNT),
-+		DUMP_WED_MASK(WED_PAO_MON_QMEM_CNT(3), WED_PAO_QMEM_TID5_QCNT),
-+		DUMP_WED_MASK(WED_PAO_MON_QMEM_CNT(4), WED_PAO_QMEM_TID6_QCNT),
-+		DUMP_WED_MASK(WED_PAO_MON_QMEM_CNT(4), WED_PAO_QMEM_TID7_QCNT),
-+
-+
-+		DUMP_STR("PAO QMEM HEAD INFO"),
-+		DUMP_WED_MASK(WED_PAO_MON_QMEM_PTR(0), WED_PAO_QMEM_FQ_HEAD),
-+		DUMP_WED_MASK(WED_PAO_MON_QMEM_PTR(0), WED_PAO_QMEM_SP_QHEAD),
-+		DUMP_WED_MASK(WED_PAO_MON_QMEM_PTR(1), WED_PAO_QMEM_TID0_QHEAD),
-+		DUMP_WED_MASK(WED_PAO_MON_QMEM_PTR(1), WED_PAO_QMEM_TID1_QHEAD),
-+		DUMP_WED_MASK(WED_PAO_MON_QMEM_PTR(2), WED_PAO_QMEM_TID2_QHEAD),
-+		DUMP_WED_MASK(WED_PAO_MON_QMEM_PTR(2), WED_PAO_QMEM_TID3_QHEAD),
-+		DUMP_WED_MASK(WED_PAO_MON_QMEM_PTR(3), WED_PAO_QMEM_TID4_QHEAD),
-+		DUMP_WED_MASK(WED_PAO_MON_QMEM_PTR(3), WED_PAO_QMEM_TID5_QHEAD),
-+		DUMP_WED_MASK(WED_PAO_MON_QMEM_PTR(4), WED_PAO_QMEM_TID6_QHEAD),
-+		DUMP_WED_MASK(WED_PAO_MON_QMEM_PTR(4), WED_PAO_QMEM_TID7_QHEAD),
-+
-+		DUMP_STR("PAO QMEM TAIL INFO"),
-+		DUMP_WED_MASK(WED_PAO_MON_QMEM_PTR(5), WED_PAO_QMEM_FQ_TAIL),
-+		DUMP_WED_MASK(WED_PAO_MON_QMEM_PTR(5), WED_PAO_QMEM_SP_QTAIL),
-+		DUMP_WED_MASK(WED_PAO_MON_QMEM_PTR(6), WED_PAO_QMEM_TID0_QTAIL),
-+		DUMP_WED_MASK(WED_PAO_MON_QMEM_PTR(6), WED_PAO_QMEM_TID1_QTAIL),
-+		DUMP_WED_MASK(WED_PAO_MON_QMEM_PTR(7), WED_PAO_QMEM_TID2_QTAIL),
-+		DUMP_WED_MASK(WED_PAO_MON_QMEM_PTR(7), WED_PAO_QMEM_TID3_QTAIL),
-+		DUMP_WED_MASK(WED_PAO_MON_QMEM_PTR(8), WED_PAO_QMEM_TID4_QTAIL),
-+		DUMP_WED_MASK(WED_PAO_MON_QMEM_PTR(8), WED_PAO_QMEM_TID5_QTAIL),
-+		DUMP_WED_MASK(WED_PAO_MON_QMEM_PTR(9), WED_PAO_QMEM_TID6_QTAIL),
-+		DUMP_WED_MASK(WED_PAO_MON_QMEM_PTR(9), WED_PAO_QMEM_TID7_QTAIL),
-+
-+		DUMP_STR("PAO HIFTXD MSDU INFO"),
-+		DUMP_WED(WED_PAO_MON_HIFTXD_FETCH_MSDU(1)),
-+		DUMP_WED(WED_PAO_MON_HIFTXD_FETCH_MSDU(2)),
-+		DUMP_WED(WED_PAO_MON_HIFTXD_FETCH_MSDU(3)),
-+		DUMP_WED(WED_PAO_MON_HIFTXD_FETCH_MSDU(4)),
-+		DUMP_WED(WED_PAO_MON_HIFTXD_FETCH_MSDU(5)),
-+		DUMP_WED(WED_PAO_MON_HIFTXD_FETCH_MSDU(6)),
-+		DUMP_WED(WED_PAO_MON_HIFTXD_FETCH_MSDU(7)),
-+		DUMP_WED(WED_PAO_MON_HIFTXD_FETCH_MSDU(8)),
-+		DUMP_WED(WED_PAO_MON_HIFTXD_FETCH_MSDU(9)),
-+		DUMP_WED(WED_PAO_MON_HIFTXD_FETCH_MSDU(10)),
-+		DUMP_WED(WED_PAO_MON_HIFTXD_FETCH_MSDU(11)),
-+		DUMP_WED(WED_PAO_MON_HIFTXD_FETCH_MSDU(12)),
-+		DUMP_WED(WED_PAO_MON_HIFTXD_FETCH_MSDU(13)),
-+		DUMP_END()
-+	};
-+
-+	static const struct reg_dump *regs[] = {
-+		&regs_common[0],
-+		NULL,
-+	};
-+	struct mtk_wed_hw *hw = s->private;
-+	struct mtk_wed_device *dev = hw->wed_dev;
-+
-+	if (!dev)
-+		return 0;
-+
-+	dump_wed_regs(s, dev, regs);
-+
-+	return 0;
-+}
-+DEFINE_SHOW_ATTRIBUTE(wed_pao);
-+
-+static int
-+wed_rtqm_show(struct seq_file *s, void *data)
-+{
-+	static const struct reg_dump regs_common[] = {
-+		DUMP_STR("WED Route QM IGRS0(N2H + Recycle)"),
-+		DUMP_WED(WED_RTQM_IGRS0_I2HW_DMAD_CNT),
-+		DUMP_WED(WED_RTQM_IGRS0_I2H_DMAD_CNT(0)),
-+		DUMP_WED(WED_RTQM_IGRS0_I2H_DMAD_CNT(1)),
-+		DUMP_WED(WED_RTQM_IGRS0_I2HW_PKT_CNT),
-+		DUMP_WED(WED_RTQM_IGRS0_I2H_PKT_CNT(0)),
-+		DUMP_WED(WED_RTQM_IGRS0_I2H_PKT_CNT(0)),
-+		DUMP_WED(WED_RTQM_IGRS0_FDROP_CNT),
-+
-+
-+		DUMP_STR("WED Route QM IGRS1(Legacy)"),
-+		DUMP_WED(WED_RTQM_IGRS1_I2HW_DMAD_CNT),
-+		DUMP_WED(WED_RTQM_IGRS1_I2H_DMAD_CNT(0)),
-+		DUMP_WED(WED_RTQM_IGRS1_I2H_DMAD_CNT(1)),
-+		DUMP_WED(WED_RTQM_IGRS1_I2HW_PKT_CNT),
-+		DUMP_WED(WED_RTQM_IGRS1_I2H_PKT_CNT(0)),
-+		DUMP_WED(WED_RTQM_IGRS1_I2H_PKT_CNT(1)),
-+		DUMP_WED(WED_RTQM_IGRS1_FDROP_CNT),
-+
-+		DUMP_STR("WED Route QM IGRS2(RRO3.0)"),
-+		DUMP_WED(WED_RTQM_IGRS2_I2HW_DMAD_CNT),
-+		DUMP_WED(WED_RTQM_IGRS2_I2H_DMAD_CNT(0)),
-+		DUMP_WED(WED_RTQM_IGRS2_I2H_DMAD_CNT(1)),
-+		DUMP_WED(WED_RTQM_IGRS2_I2HW_PKT_CNT),
-+		DUMP_WED(WED_RTQM_IGRS2_I2H_PKT_CNT(0)),
-+		DUMP_WED(WED_RTQM_IGRS2_I2H_PKT_CNT(1)),
-+		DUMP_WED(WED_RTQM_IGRS2_FDROP_CNT),
-+
-+		DUMP_STR("WED Route QM IGRS3(DEBUG)"),
-+		DUMP_WED(WED_RTQM_IGRS2_I2HW_DMAD_CNT),
-+		DUMP_WED(WED_RTQM_IGRS3_I2H_DMAD_CNT(0)),
-+		DUMP_WED(WED_RTQM_IGRS3_I2H_DMAD_CNT(1)),
-+		DUMP_WED(WED_RTQM_IGRS3_I2HW_PKT_CNT),
-+		DUMP_WED(WED_RTQM_IGRS3_I2H_PKT_CNT(0)),
-+		DUMP_WED(WED_RTQM_IGRS3_I2H_PKT_CNT(1)),
-+		DUMP_WED(WED_RTQM_IGRS3_FDROP_CNT),
-+
-+		DUMP_END()
-+	};
-+
-+	static const struct reg_dump *regs[] = {
-+		&regs_common[0],
-+		NULL,
-+	};
-+	struct mtk_wed_hw *hw = s->private;
-+	struct mtk_wed_device *dev = hw->wed_dev;
-+
-+	if (!dev)
-+		return 0;
-+
-+	dump_wed_regs(s, dev, regs);
-+
-+	return 0;
-+}
-+DEFINE_SHOW_ATTRIBUTE(wed_rtqm);
-+
-+
-+static int
-+wed_rro_show(struct seq_file *s, void *data)
-+{
-+	static const struct reg_dump regs_common[] = {
-+		DUMP_STR("RRO/IND CMD CNT"),
-+		DUMP_WED(WED_RX_IND_CMD_CNT(1)),
-+		DUMP_WED(WED_RX_IND_CMD_CNT(2)),
-+		DUMP_WED(WED_RX_IND_CMD_CNT(3)),
-+		DUMP_WED(WED_RX_IND_CMD_CNT(4)),
-+		DUMP_WED(WED_RX_IND_CMD_CNT(5)),
-+		DUMP_WED(WED_RX_IND_CMD_CNT(6)),
-+		DUMP_WED(WED_RX_IND_CMD_CNT(7)),
-+		DUMP_WED(WED_RX_IND_CMD_CNT(8)),
-+		DUMP_WED_MASK(WED_RX_IND_CMD_CNT(9),
-+			      WED_IND_CMD_MAGIC_CNT_FAIL_CNT),
-+
-+		DUMP_WED(WED_RX_ADDR_ELEM_CNT(0)),
-+		DUMP_WED_MASK(WED_RX_ADDR_ELEM_CNT(1),
-+			      WED_ADDR_ELEM_SIG_FAIL_CNT),
-+		DUMP_WED(WED_RX_MSDU_PG_CNT(1)),
-+		DUMP_WED(WED_RX_MSDU_PG_CNT(2)),
-+		DUMP_WED(WED_RX_MSDU_PG_CNT(3)),
-+		DUMP_WED(WED_RX_MSDU_PG_CNT(4)),
-+		DUMP_WED(WED_RX_MSDU_PG_CNT(5)),
-+		DUMP_WED_MASK(WED_RX_PN_CHK_CNT,
-+			      WED_PN_CHK_FAIL_CNT),
-+
-+		DUMP_END()
-+	};
-+
-+	static const struct reg_dump *regs[] = {
-+		&regs_common[0],
-+		NULL,
-+	};
-+	struct mtk_wed_hw *hw = s->private;
-+	struct mtk_wed_device *dev = hw->wed_dev;
-+
-+	if (!dev)
-+		return 0;
-+
-+	dump_wed_regs(s, dev, regs);
-+
-+	return 0;
-+}
-+DEFINE_SHOW_ATTRIBUTE(wed_rro);
-+
- void mtk_wed_hw_add_debugfs(struct mtk_wed_hw *hw)
- {
- 	struct dentry *dir;
-@@ -261,8 +747,18 @@ void mtk_wed_hw_add_debugfs(struct mtk_wed_hw *hw)
- 	debugfs_create_u32("regidx", 0600, dir, &hw->debugfs_reg);
- 	debugfs_create_file_unsafe("regval", 0600, dir, hw, &fops_regval);
- 	debugfs_create_file_unsafe("txinfo", 0400, dir, hw, &wed_txinfo_fops);
--	debugfs_create_file_unsafe("rxinfo", 0400, dir, hw, &wed_rxinfo_fops);
--	if (hw->ver != MTK_WED_V1) {
-+	debugfs_create_u32("token_id", 0600, dir, &hw->token_id);
-+	debugfs_create_file_unsafe("token_txd", 0600, dir, hw, &wed_token_txd_fops);
-+
-+	if (hw->version == 3)
-+		debugfs_create_file_unsafe("pao", 0400, dir, hw, &wed_pao_fops);
-+
-+	if (hw->version != 1) {
-+		debugfs_create_file_unsafe("rxinfo", 0400, dir, hw, &wed_rxinfo_fops);
-+		if (hw->version == 3) {
-+			debugfs_create_file_unsafe("rtqm", 0400, dir, hw, &wed_rtqm_fops);
-+			debugfs_create_file_unsafe("rro", 0400, dir, hw, &wed_rro_fops);
-+		}
- 		wed_wo_mcu_debugfs(hw, dir);
- 	}
- }
-diff --git a/drivers/net/ethernet/mediatek/mtk_wed_mcu.c b/drivers/net/ethernet/mediatek/mtk_wed_mcu.c
-index b5a86f6..c2d060b 100644
---- a/drivers/net/ethernet/mediatek/mtk_wed_mcu.c
-+++ b/drivers/net/ethernet/mediatek/mtk_wed_mcu.c
-@@ -245,8 +245,7 @@ mtk_wed_load_firmware(struct mtk_wed_wo *wo)
- 	if (of_device_is_compatible(wo->hw->node, "mediatek,mt7981-wed"))
- 		mcu = MT7981_FIRMWARE_WO;
- 	else
--		mcu = wo->hw->index ? MT7986_FIRMWARE_WO_2 :
--				      MT7986_FIRMWARE_WO_1;
-+		mcu = wo->hw->index ? MTK_FIRMWARE_WO_1 : MTK_FIRMWARE_WO_0;
- 
- 	ret = request_firmware(&fw, mcu, wo->hw->dev);
- 	if (ret)
-@@ -293,8 +292,12 @@ mtk_wed_load_firmware(struct mtk_wed_wo *wo)
- 	}
- 
- 	/* write the start address */
--	boot_cr = wo->hw->index ?
--		WOX_MCU_CFG_LS_WA_BOOT_ADDR_ADDR : WOX_MCU_CFG_LS_WM_BOOT_ADDR_ADDR;
-+	if (wo->hw->version == 3)
-+		boot_cr = WOX_MCU_CFG_LS_WM_BOOT_ADDR_ADDR;
-+	else
-+		boot_cr = wo->hw->index ?
-+			WOX_MCU_CFG_LS_WA_BOOT_ADDR_ADDR : WOX_MCU_CFG_LS_WM_BOOT_ADDR_ADDR;
-+
- 	wo_w32(wo, boot_cr, (wo->region[WO_REGION_EMI].addr_pa >> 16));
- 
- 	/* wo firmware reset */
-@@ -302,8 +305,7 @@ mtk_wed_load_firmware(struct mtk_wed_wo *wo)
- 
- 	val = wo_r32(wo, WOX_MCU_CFG_LS_WF_MCU_CFG_WM_WA_ADDR);
- 
--	val |= wo->hw->index ? WOX_MCU_CFG_LS_WF_MCU_CFG_WM_WA_WA_CPU_RSTB_MASK :
--		WOX_MCU_CFG_LS_WF_MCU_CFG_WM_WA_WM_CPU_RSTB_MASK;
-+	val |= WOX_MCU_CFG_LS_WF_MCU_CFG_WM_WA_WM_CPU_RSTB_MASK;
- 
- 	wo_w32(wo, WOX_MCU_CFG_LS_WF_MCU_CFG_WM_WA_ADDR, val);
- 
-diff --git a/drivers/net/ethernet/mediatek/mtk_wed_mcu.h b/drivers/net/ethernet/mediatek/mtk_wed_mcu.h
-index dbb17ae..a533b6e 100644
---- a/drivers/net/ethernet/mediatek/mtk_wed_mcu.h
-+++ b/drivers/net/ethernet/mediatek/mtk_wed_mcu.h
-@@ -17,8 +17,9 @@
- #define WARP_ALREADY_DONE_STATUS (1)
- 
- #define MT7981_FIRMWARE_WO		"mediatek/mt7981_wo.bin"
--#define MT7986_FIRMWARE_WO_1		"mediatek/mt7986_wo_0.bin"
--#define MT7986_FIRMWARE_WO_2		"mediatek/mt7986_wo_1.bin"
-+#define MTK_FIRMWARE_WO_0		"mediatek/mtk_wo_0.bin"
-+#define MTK_FIRMWARE_WO_1		"mediatek/mtk_wo_1.bin"
-+#define MTK_FIRMWARE_WO_2		"mediatek/mtk_wo_2.bin"
- 
- #define WOCPU_EMI_DEV_NODE		"mediatek,wocpu_emi"
- #define WOCPU_ILM_DEV_NODE		"mediatek,wocpu_ilm"
-diff --git a/drivers/net/ethernet/mediatek/mtk_wed_regs.h b/drivers/net/ethernet/mediatek/mtk_wed_regs.h
-index 403a36b..25be547 100644
---- a/drivers/net/ethernet/mediatek/mtk_wed_regs.h
-+++ b/drivers/net/ethernet/mediatek/mtk_wed_regs.h
-@@ -20,6 +20,9 @@
- #define MTK_WDMA_DESC_CTRL_DMA_DONE		BIT(31)
- #define MTK_WED_RX_BM_TOKEN			GENMASK(31, 16)
- 
-+#define MTK_WDMA_TXD0_DESC_INFO_DMA_DONE	BIT(29)
-+#define MTK_WDMA_TXD1_DESC_INFO_DMA_DONE	BIT(31)
-+
- struct mtk_wdma_desc {
- 	__le32 buf0;
- 	__le32 ctrl;
-@@ -51,6 +54,7 @@ struct mtk_wdma_desc {
- #define MTK_WED_RESET_WDMA_INT_AGENT			BIT(19)
- #define MTK_WED_RESET_RX_RRO_QM				BIT(20)
- #define MTK_WED_RESET_RX_ROUTE_QM			BIT(21)
-+#define MTK_WED_RESET_TX_PAO				BIT(22)
- #define MTK_WED_RESET_WED				BIT(31)
- 
- #define MTK_WED_CTRL					0x00c
-@@ -58,6 +62,9 @@ struct mtk_wdma_desc {
- #define MTK_WED_CTRL_WPDMA_INT_AGENT_BUSY		BIT(1)
- #define MTK_WED_CTRL_WDMA_INT_AGENT_EN			BIT(2)
- #define MTK_WED_CTRL_WDMA_INT_AGENT_BUSY		BIT(3)
-+#define MTK_WED_CTRL_WED_RX_IND_CMD_EN			BIT(5)
-+#define MTK_WED_CTRL_WED_RX_PG_BM_EN			BIT(6)
-+#define MTK_WED_CTRL_WED_RX_PG_BM_BUSU			BIT(7)
- #define MTK_WED_CTRL_WED_TX_BM_EN			BIT(8)
- #define MTK_WED_CTRL_WED_TX_BM_BUSY			BIT(9)
- #define MTK_WED_CTRL_WED_TX_FREE_AGENT_EN		BIT(10)
-@@ -68,9 +75,14 @@ struct mtk_wdma_desc {
- #define MTK_WED_CTRL_RX_RRO_QM_BUSY			BIT(15)
- #define MTK_WED_CTRL_RX_ROUTE_QM_EN			BIT(16)
- #define MTK_WED_CTRL_RX_ROUTE_QM_BUSY			BIT(17)
-+#define MTK_WED_CTRL_TX_TKID_ALI_EN			BIT(20)
-+#define MTK_WED_CTRL_TX_TKID_ALI_BUSY			BIT(21)
-+#define MTK_WED_CTRL_TX_PAO_EN				BIT(22)
-+#define MTK_WED_CTRL_TX_PAO_BUSY			BIT(23)
- #define MTK_WED_CTRL_FINAL_DIDX_READ			BIT(24)
- #define MTK_WED_CTRL_ETH_DMAD_FMT			BIT(25)
- #define MTK_WED_CTRL_MIB_READ_CLEAR			BIT(28)
-+#define MTK_WED_CTRL_FLD_MIB_RD_CLR			BIT(28)
- 
- #define MTK_WED_EXT_INT_STATUS				0x020
- #define MTK_WED_EXT_INT_STATUS_TF_LEN_ERR		BIT(0)
-@@ -78,12 +90,10 @@ struct mtk_wdma_desc {
- #define MTK_WED_EXT_INT_STATUS_TKID_TITO_INVALID	BIT(4)
- #define MTK_WED_EXT_INT_STATUS_TX_FBUF_LO_TH		BIT(8)
- #define MTK_WED_EXT_INT_STATUS_TX_FBUF_HI_TH		BIT(9)
--#if defined(CONFIG_MEDIATEK_NETSYS_V2)
--#define MTK_WED_EXT_INT_STATUS_TX_TKID_LO_TH		BIT(10)
--#define MTK_WED_EXT_INT_STATUS_TX_TKID_HI_TH		BIT(11)
--#endif
--#define MTK_WED_EXT_INT_STATUS_RX_FREE_AT_EMPTY		BIT(12)
--#define MTK_WED_EXT_INT_STATUS_RX_FBUF_DMAD_ER		BIT(13)
-+#define MTK_WED_EXT_INT_STATUS_RX_FBUF_LO_TH2		BIT(10)
-+#define MTK_WED_EXT_INT_STATUS_RX_FBUF_HI_TH2		BIT(11)
-+#define MTK_WED_EXT_INT_STATUS_RX_FBUF_LO_TH		BIT(12)
-+#define MTK_WED_EXT_INT_STATUS_RX_FBUF_HI_TH		BIT(13)
- #define MTK_WED_EXT_INT_STATUS_RX_DRV_R_RESP_ERR	BIT(16)
- #define MTK_WED_EXT_INT_STATUS_RX_DRV_W_RESP_ERR	BIT(17)
- #define MTK_WED_EXT_INT_STATUS_RX_DRV_COHERENT		BIT(18)
-@@ -100,17 +110,15 @@ struct mtk_wdma_desc {
- #define MTK_WED_EXT_INT_STATUS_ERROR_MASK		(MTK_WED_EXT_INT_STATUS_TF_LEN_ERR | \
- 							 MTK_WED_EXT_INT_STATUS_TKID_WO_PYLD | \
- 							 MTK_WED_EXT_INT_STATUS_TKID_TITO_INVALID | \
--							 MTK_WED_EXT_INT_STATUS_RX_FREE_AT_EMPTY | \
--							 MTK_WED_EXT_INT_STATUS_RX_FBUF_DMAD_ER | \
- 							 MTK_WED_EXT_INT_STATUS_RX_DRV_R_RESP_ERR | \
- 							 MTK_WED_EXT_INT_STATUS_RX_DRV_W_RESP_ERR | \
- 							 MTK_WED_EXT_INT_STATUS_RX_DRV_INIT_WDMA_EN | \
--							 MTK_WED_EXT_INT_STATUS_TX_DMA_R_RESP_ERR | \
--							 MTK_WED_EXT_INT_STATUS_TX_DMA_W_RESP_ERR)
-+							 MTK_WED_EXT_INT_STATUS_TX_DMA_R_RESP_ERR)
- 
- #define MTK_WED_EXT_INT_MASK				0x028
- #define MTK_WED_EXT_INT_MASK1				0x02c
- #define MTK_WED_EXT_INT_MASK2				0x030
-+#define MTK_WED_EXT_INT_MASK3				0x034
- 
- #define MTK_WED_STATUS					0x060
- #define MTK_WED_STATUS_TX				GENMASK(15, 8)
-@@ -118,9 +126,14 @@ struct mtk_wdma_desc {
- #define MTK_WED_TX_BM_CTRL				0x080
- #define MTK_WED_TX_BM_CTRL_VLD_GRP_NUM			GENMASK(6, 0)
- #define MTK_WED_TX_BM_CTRL_RSV_GRP_NUM			GENMASK(22, 16)
-+#define MTK_WED_TX_BM_CTRL_LEGACY_EN			BIT(26)
-+#define MTK_WED_TX_TKID_CTRL_FREE_FORMAT		BIT(27)
- #define MTK_WED_TX_BM_CTRL_PAUSE			BIT(28)
- 
- #define MTK_WED_TX_BM_BASE				0x084
-+#define MTK_WED_TX_BM_INIT_PTR				0x088
-+#define MTK_WED_TX_BM_SW_TAIL_IDX			GENMASK(16, 0)
-+#define MTK_WED_TX_BM_INIT_SW_TAIL_IDX			BIT(16)
- 
- #define MTK_WED_TX_BM_BUF_LEN				0x08c
- 
-@@ -134,22 +147,24 @@ struct mtk_wdma_desc {
- #if defined(CONFIG_MEDIATEK_NETSYS_V2)
- #define MTK_WED_TX_BM_DYN_THR_LO			GENMASK(8, 0)
- #define MTK_WED_TX_BM_DYN_THR_HI			GENMASK(24, 16)
--
--#define MTK_WED_TX_BM_TKID				0x0c8
--#define MTK_WED_TX_BM_TKID_START			GENMASK(15, 0)
--#define MTK_WED_TX_BM_TKID_END				GENMASK(31, 16)
- #else
- #define MTK_WED_TX_BM_DYN_THR_LO			GENMASK(6, 0)
- #define MTK_WED_TX_BM_DYN_THR_HI			GENMASK(22, 16)
-+#endif
- 
--#define MTK_WED_TX_BM_TKID				0x088
-+#define MTK_WED_TX_BM_TKID				0x0c8
- #define MTK_WED_TX_BM_TKID_START			GENMASK(15, 0)
- #define MTK_WED_TX_BM_TKID_END				GENMASK(31, 16)
--#endif
- 
- #define MTK_WED_TX_TKID_CTRL				0x0c0
-+#if defined(CONFIG_MEDIATEK_NETSYS_V3)
-+#define MTK_WED_TX_TKID_CTRL_VLD_GRP_NUM		GENMASK(7, 0)
-+#define MTK_WED_TX_TKID_CTRL_RSV_GRP_NUM		GENMASK(23, 16)
-+#else
- #define MTK_WED_TX_TKID_CTRL_VLD_GRP_NUM		GENMASK(6, 0)
- #define MTK_WED_TX_TKID_CTRL_RSV_GRP_NUM		GENMASK(22, 16)
-+#endif
-+
- #define MTK_WED_TX_TKID_CTRL_PAUSE			BIT(28)
- 
- #define MTK_WED_TX_TKID_DYN_THR				0x0e0
-@@ -220,12 +235,15 @@ struct mtk_wdma_desc {
- #define MTK_WED_WPDMA_GLO_CFG_RX_DRV_R1_PKT_PROC	BIT(5)
- #define MTK_WED_WPDMA_GLO_CFG_RX_DRV_R0_CRX_SYNC	BIT(6)
- #define MTK_WED_WPDMA_GLO_CFG_RX_DRV_R1_CRX_SYNC	BIT(7)
--#define MTK_WED_WPDMA_GLO_CFG_RX_DRV_EVENT_PKT_FMT_VER	GENMASK(18, 16)
-+#define MTK_WED_WPDMA_GLO_CFG_RX_DRV_EVENT_PKT_FMT_VER	GENMASK(15, 12)
-+#define MTK_WED_WPDMA_GLO_CFG_RX_DRV_UNS_VER_FORCE_4	BIT(18)
- #define MTK_WED_WPDMA_GLO_CFG_RX_DRV_UNSUPPORT_FMT	BIT(19)
--#define MTK_WED_WPDMA_GLO_CFG_RX_DRV_UEVENT_PKT_FMT_CHK BIT(20)
-+#define MTK_WED_WPDMA_GLO_CFG_RX_DRV_EVENT_PKT_FMT_CHK	BIT(20)
- #define MTK_WED_WPDMA_GLO_CFG_RX_DDONE2_WR		BIT(21)
- #define MTK_WED_WPDMA_GLO_CFG_TX_TKID_KEEP		BIT(24)
-+#define MTK_WED_WPDMA_GLO_CFG_TX_DDONE_CHK_LAST		BIT(25)
- #define MTK_WED_WPDMA_GLO_CFG_TX_DMAD_DW3_PREV		BIT(28)
-+#define MTK_WED_WPDMA_GLO_CFG_TX_DDONE_CHK		BIT(30)
- 
- /* CONFIG_MEDIATEK_NETSYS_V1 */
- #define MTK_WED_WPDMA_GLO_CFG_RX_BT_SIZE		GENMASK(5, 4)
-@@ -288,9 +306,11 @@ struct mtk_wdma_desc {
- #define MTK_WED_PCIE_INT_TRIGGER_STATUS			BIT(16)
- 
- #define MTK_WED_PCIE_INT_CTRL				0x57c
--#define MTK_WED_PCIE_INT_CTRL_MSK_EN_POLA		BIT(20)
--#define MTK_WED_PCIE_INT_CTRL_SRC_SEL			GENMASK(17, 16)
- #define MTK_WED_PCIE_INT_CTRL_POLL_EN 			GENMASK(13, 12)
-+#define MTK_WED_PCIE_INT_CTRL_SRC_SEL			GENMASK(17, 16)
-+#define MTK_WED_PCIE_INT_CTRL_MSK_EN_POLA		BIT(20)
-+#define MTK_WED_PCIE_INT_CTRL_MSK_IRQ_FILTER		BIT(21)
-+
- #define MTK_WED_WPDMA_CFG_BASE				0x580
- #define MTK_WED_WPDMA_CFG_INT_MASK			0x584
- #define MTK_WED_WPDMA_CFG_TX				0x588
-@@ -319,20 +339,50 @@ struct mtk_wdma_desc {
- #define MTK_WED_WPDMA_RX_D_RST_DRV_IDX			GENMASK(25, 24)
- 
- #define MTK_WED_WPDMA_RX_GLO_CFG			0x76c
--#define MTK_WED_WPDMA_RX_RING				0x770
-+#if defined(CONFIG_MEDIATEK_NETSYS_V2)
-+#define MTK_WED_WPDMA_RX_RING0				0x770
-+#else
-+#define MTK_WED_WPDMA_RX_RING0				0x7d0
-+#endif
-+#define MTK_WED_WPDMA_RX_RING1				0x7d8
- 
- #define MTK_WED_WPDMA_RX_D_MIB(_n)			(0x774 + (_n) * 4)
- #define MTK_WED_WPDMA_RX_D_PROCESSED_MIB(_n)		(0x784 + (_n) * 4)
- #define MTK_WED_WPDMA_RX_D_COHERENT_MIB			0x78c
- 
-+#define MTK_WED_WPDMA_RX_D_PREF_CFG			0x7b4
-+#define MTK_WED_WPDMA_RX_D_PREF_EN			BIT(0)
-+#define MTK_WED_WPDMA_RX_D_PREF_BURST_SIZE		GENMASK(12, 8)
-+#define MTK_WED_WPDMA_RX_D_PREF_LOW_THRES		GENMASK(21, 16)
-+
-+#define MTK_WED_WPDMA_RX_D_PREF_RX0_SIDX		0x7b8
-+#define MTK_WED_WPDMA_RX_D_PREF_SIDX_IDX_CLR		BIT(15)
-+
-+#define MTK_WED_WPDMA_RX_D_PREF_RX1_SIDX		0x7bc
-+
-+#define MTK_WED_WPDMA_RX_D_PREF_FIFO_CFG		0x7c0
-+#define MTK_WED_WPDMA_RX_D_PREF_FIFO_CFG_R0_CLR		BIT(0)
-+#define MTK_WED_WPDMA_RX_D_PREF_FIFO_CFG_R1_CLR		BIT(16)
-+
- #define MTK_WED_WDMA_RING_TX				0x800
- 
- #define MTK_WED_WDMA_TX_MIB				0x810
- 
--
- #define MTK_WED_WDMA_RING_RX(_n)			(0x900 + (_n) * 0x10)
- #define MTK_WED_WDMA_RX_THRES(_n)			(0x940 + (_n) * 0x4)
- 
-+#define MTK_WED_WDMA_RX_PREF_CFG			0x950
-+#define MTK_WED_WDMA_RX_PREF_EN				BIT(0)
-+#define MTK_WED_WDMA_RX_PREF_BURST_SIZE			GENMASK(12, 8)
-+#define MTK_WED_WDMA_RX_PREF_LOW_THRES			GENMASK(21, 16)
-+#define MTK_WED_WDMA_RX_PREF_RX0_SIDX_CLR		BIT(24)
-+#define MTK_WED_WDMA_RX_PREF_RX1_SIDX_CLR		BIT(25)
-+#define MTK_WED_WDMA_RX_PREF_DDONE2_EN			BIT(26)
-+
-+#define MTK_WED_WDMA_RX_PREF_FIFO_CFG			0x95C
-+#define MTK_WED_WDMA_RX_PREF_FIFO_RX0_CLR		BIT(0)
-+#define MTK_WED_WDMA_RX_PREF_FIFO_RX1_CLR		BIT(16)
-+
- #define MTK_WED_WDMA_GLO_CFG				0xa04
- #define MTK_WED_WDMA_GLO_CFG_TX_DRV_EN			BIT(0)
- #define MTK_WED_WDMA_GLO_CFG_TX_DDONE_CHK		BIT(1)
-@@ -365,6 +415,7 @@ struct mtk_wdma_desc {
- #define MTK_WED_WDMA_INT_TRIGGER_RX_DONE		GENMASK(17, 16)
- 
- #define MTK_WED_WDMA_INT_CTRL				0xa2c
-+#define MTK_WED_WDMA_INT_POLL_PRD			GENMASK(7, 0)
- #define MTK_WED_WDMA_INT_POLL_SRC_SEL			GENMASK(17, 16)
- 
- #define MTK_WED_WDMA_CFG_BASE				0xaa0
-@@ -426,6 +477,18 @@ struct mtk_wdma_desc {
- #define MTK_WDMA_INT_GRP1				0x250
- #define MTK_WDMA_INT_GRP2				0x254
- 
-+#define MTK_WDMA_PREF_TX_CFG				0x2d0
-+#define MTK_WDMA_PREF_TX_CFG_PREF_EN			BIT(0)
-+
-+#define MTK_WDMA_PREF_RX_CFG				0x2dc
-+#define MTK_WDMA_PREF_RX_CFG_PREF_EN			BIT(0)
-+
-+#define MTK_WDMA_WRBK_TX_CFG				0x300
-+#define MTK_WDMA_WRBK_TX_CFG_WRBK_EN			BIT(30)
-+
-+#define MTK_WDMA_WRBK_RX_CFG				0x344
-+#define MTK_WDMA_WRBK_RX_CFG_WRBK_EN			BIT(30)
-+
- #define MTK_PCIE_MIRROR_MAP(n)				((n) ? 0x4 : 0x0)
- #define MTK_PCIE_MIRROR_MAP_EN				BIT(0)
- #define MTK_PCIE_MIRROR_MAP_WED_ID			BIT(1)
-@@ -439,6 +502,31 @@ struct mtk_wdma_desc {
- #define MTK_WED_RTQM_Q_DBG_BYPASS			BIT(5)
- #define MTK_WED_RTQM_TXDMAD_FPORT			GENMASK(23, 20)
- 
-+#define MTK_WED_RTQM_IGRS0_I2HW_DMAD_CNT		0xb1c
-+#define MTK_WED_RTQM_IGRS0_I2H_DMAD_CNT(_n)		(0xb20 + (_n) * 0x4)
-+#define	MTK_WED_RTQM_IGRS0_I2HW_PKT_CNT			0xb28
-+#define MTK_WED_RTQM_IGRS0_I2H_PKT_CNT(_n)		(0xb2c + (_n) * 0x4)
-+#define MTK_WED_RTQM_IGRS0_FDROP_CNT			0xb34
-+
-+
-+#define MTK_WED_RTQM_IGRS1_I2HW_DMAD_CNT		0xb44
-+#define MTK_WED_RTQM_IGRS1_I2H_DMAD_CNT(_n)		(0xb48 + (_n) * 0x4)
-+#define MTK_WED_RTQM_IGRS1_I2HW_PKT_CNT			0xb50
-+#define MTK_WED_RTQM_IGRS1_I2H_PKT_CNT(_n)		(0xb54+ (_n) * 0x4)
-+#define MTK_WED_RTQM_IGRS1_FDROP_CNT			0xb5c
-+
-+#define MTK_WED_RTQM_IGRS2_I2HW_DMAD_CNT		0xb6c
-+#define MTK_WED_RTQM_IGRS2_I2H_DMAD_CNT(_n)		(0xb70 + (_n) * 0x4)
-+#define MTK_WED_RTQM_IGRS2_I2HW_PKT_CNT			0xb78
-+#define MTK_WED_RTQM_IGRS2_I2H_PKT_CNT(_n)		(0xb7c+ (_n) * 0x4)
-+#define MTK_WED_RTQM_IGRS2_FDROP_CNT			0xb84
-+
-+#define MTK_WED_RTQM_IGRS3_I2HW_DMAD_CNT		0xb94
-+#define MTK_WED_RTQM_IGRS3_I2H_DMAD_CNT(_n)		(0xb98 + (_n) * 0x4)
-+#define MTK_WED_RTQM_IGRS3_I2HW_PKT_CNT			0xba0
-+#define MTK_WED_RTQM_IGRS3_I2H_PKT_CNT(_n)		(0xba4+ (_n) * 0x4)
-+#define MTK_WED_RTQM_IGRS3_FDROP_CNT			0xbac
-+
- #define MTK_WED_RTQM_R2H_MIB(_n)			(0xb70 + (_n) * 0x4)
- #define MTK_WED_RTQM_R2Q_MIB(_n)			(0xb78 + (_n) * 0x4)
- #define MTK_WED_RTQM_Q2N_MIB				0xb80
-@@ -447,6 +535,24 @@ struct mtk_wdma_desc {
- #define MTK_WED_RTQM_Q2B_MIB				0xb8c
- #define MTK_WED_RTQM_PFDBK_MIB				0xb90
- 
-+#define MTK_WED_RTQM_ENQ_CFG0				0xbb8
-+#define MTK_WED_RTQM_ENQ_CFG_TXDMAD_FPORT		GENMASK(15, 12)
-+
-+#define MTK_WED_RTQM_FDROP_MIB				0xb84
-+#define MTK_WED_RTQM_ENQ_I2Q_DMAD_CNT			0xbbc
-+#define MTK_WED_RTQM_ENQ_I2N_DMAD_CNT			0xbc0
-+#define MTK_WED_RTQM_ENQ_I2Q_PKT_CNT			0xbc4
-+#define MTK_WED_RTQM_ENQ_I2N_PKT_CNT			0xbc8
-+#define MTK_WED_RTQM_ENQ_USED_ENTRY_CNT			0xbcc
-+#define MTK_WED_RTQM_ENQ_ERR_CNT			0xbd0
-+
-+#define MTK_WED_RTQM_DEQ_DMAD_CNT			0xbd8
-+#define MTK_WED_RTQM_DEQ_Q2I_DMAD_CNT			0xbdc
-+#define MTK_WED_RTQM_DEQ_PKT_CNT			0xbe0
-+#define MTK_WED_RTQM_DEQ_Q2I_PKT_CNT			0xbe4
-+#define MTK_WED_RTQM_DEQ_USED_PFDBK_CNT			0xbe8
-+#define MTK_WED_RTQM_DEQ_ERR_CNT			0xbec
-+
- #define MTK_WED_RROQM_GLO_CFG				0xc04
- #define MTK_WED_RROQM_RST_IDX				0xc08
- #define MTK_WED_RROQM_RST_IDX_MIOD 			BIT(0)
-@@ -487,8 +593,8 @@ struct mtk_wdma_desc {
- #define MTK_WED_RX_BM_BASE				0xd84
- #define MTK_WED_RX_BM_INIT_PTR				0xd88
- #define MTK_WED_RX_BM_PTR	      			0xd8c
--#define MTK_WED_RX_BM_PTR_HEAD				GENMASK(32, 16)
- #define MTK_WED_RX_BM_PTR_TAIL				GENMASK(15, 0)
-+#define MTK_WED_RX_BM_PTR_HEAD				GENMASK(32, 16)
- 
- #define MTK_WED_RX_BM_BLEN	      			0xd90
- #define MTK_WED_RX_BM_STS				0xd94
-@@ -496,7 +602,193 @@ struct mtk_wdma_desc {
- #define MTK_WED_RX_BM_INTF				0xd9c
- #define MTK_WED_RX_BM_ERR_STS				0xda8
- 
-+#define MTK_RRO_IND_CMD_SIGNATURE			0xe00
-+#define MTK_RRO_IND_CMD_DMA_IDX				GENMASK(11, 0)
-+#define MTK_RRO_IND_CMD_MAGIC_CNT			GENMASK(30, 28)
-+
-+#define MTK_WED_IND_CMD_RX_CTRL0			0xe04
-+#define MTK_WED_IND_CMD_PROC_IDX			GENMASK(11, 0)
-+#define MTK_WED_IND_CMD_PREFETCH_FREE_CNT		GENMASK(19, 16)
-+#define MTK_WED_IND_CMD_MAGIC_CNT			GENMASK(30, 28)
-+
-+#define MTK_WED_IND_CMD_RX_CTRL1			0xe08
-+#define MTK_WED_IND_CMD_RX_CTRL2			0xe0c
-+#define MTK_WED_IND_CMD_MAX_CNT				GENMASK(11, 0)
-+#define MTK_WED_IND_CMD_BASE_M				GENMASK(19, 16)
-+
-+#define MTK_WED_RRO_CFG0				0xe10
-+#define MTK_WED_RRO_CFG1				0xe14
-+#define MTK_WED_RRO_CFG1_MAX_WIN_SZ			GENMASK(31, 29)
-+#define MTK_WED_RRO_CFG1_ACK_SN_BASE_M			GENMASK(19, 16)
-+#define MTK_WED_RRO_CFG1_PARTICL_SE_ID			GENMASK(11, 0)
-+
-+#define MTK_WED_ADDR_ELEM_CFG0				0xe18
-+#define MTK_WED_ADDR_ELEM_CFG1				0xe1c
-+#define MTK_WED_ADDR_ELEM_PREFETCH_FREE_CNT		GENMASK(19, 16)
-+
-+#define MTK_WED_ADDR_ELEM_TBL_CFG 			0xe20
-+#define MTK_WED_ADDR_ELEM_TBL_OFFSET			GENMASK(6, 0)
-+#define MTK_WED_ADDR_ELEM_TBL_RD_RDY			BIT(28)
-+#define MTK_WED_ADDR_ELEM_TBL_WR_RDY			BIT(29)
-+#define MTK_WED_ADDR_ELEM_TBL_RD			BIT(30)
-+#define MTK_WED_ADDR_ELEM_TBL_WR			BIT(31)
-+
-+#define MTK_WED_RADDR_ELEM_TBL_WDATA 			0xe24
-+#define MTK_WED_RADDR_ELEM_TBL_RDATA 			0xe28
-+
-+#define MTK_WED_PN_CHECK_CFG 				0xe30
-+#define MTK_WED_PN_CHECK_SE_ID				GENMASK(11, 0)
-+#define MTK_WED_PN_CHECK_RD_RDY				BIT(28)
-+#define MTK_WED_PN_CHECK_WR_RDY				BIT(29)
-+#define MTK_WED_PN_CHECK_RD				BIT(30)
-+#define MTK_WED_PN_CHECK_WR				BIT(31)
-+
-+#define MTK_WED_PN_CHECK_WDATA_M 			0xe38
-+#define MTK_WED_PN_CHECK_IS_FIRST			BIT(17)
-+
-+#define MTK_WED_RRO_MSDU_PG_RING_CFG(_n)		(0xe44 + (_n) * 0x8)
-+
-+#define MTK_WED_RRO_MSDU_PG_RING2_CFG			0xe58
-+#define MTK_WED_RRO_MSDU_PG_DRV_CLR			BIT(26)
-+#define MTK_WED_RRO_MSDU_PG_DRV_EN			BIT(31)
-+
-+#define MTK_WED_RRO_MSDU_PG_CTRL0(_n)			(0xe5c + (_n) * 0xc)
-+#define MTK_WED_RRO_MSDU_PG_CTRL1(_n)			(0xe60 + (_n) * 0xc)
-+#define MTK_WED_RRO_MSDU_PG_CTRL2(_n)			(0xe64 + (_n) * 0xc)
-+
-+#define MTK_WED_RRO_RX_D_RX(_n)				(0xe80 + (_n) * 0x10)
-+
-+#define MTK_WED_RRO_RX_MAGIC_CNT			BIT(13)
-+
-+#define MTK_WED_RRO_RX_D_CFG(_n)			(0xea0 + (_n) * 0x4)
-+#define MTK_WED_RRO_RX_D_DRV_CLR			BIT(26)
-+#define MTK_WED_RRO_RX_D_DRV_EN				BIT(31)
-+
-+#define MTK_WED_RRO_PG_BM_RX_DMAM			0xeb0
-+#define MTK_WED_RRO_PG_BM_RX_SDL0			GENMASK(13, 0)
-+
-+#define MTK_WED_RRO_PG_BM_BASE				0xeb4
-+#define MTK_WED_RRO_PG_BM_INIT_PTR			0xeb8
-+#define MTK_WED_RRO_PG_BM_SW_TAIL_IDX			GENMASK(15, 0)
-+#define MTK_WED_RRO_PG_BM_INIT_SW_TAIL_IDX		BIT(16)
-+
-+#define MTK_WED_WPDMA_INT_CTRL_RRO_RX			0xeec
-+#define MTK_WED_WPDMA_INT_CTRL_RRO_RX0_EN		BIT(0)
-+#define MTK_WED_WPDMA_INT_CTRL_RRO_RX0_CLR		BIT(1)
-+#define MTK_WED_WPDMA_INT_CTRL_RRO_RX0_DONE_TRIG	GENMASK(6, 2)
-+#define MTK_WED_WPDMA_INT_CTRL_RRO_RX1_EN		BIT(8)
-+#define MTK_WED_WPDMA_INT_CTRL_RRO_RX1_CLR		BIT(9)
-+#define MTK_WED_WPDMA_INT_CTRL_RRO_RX1_DONE_TRIG	GENMASK(14, 10)
-+
-+#define MTK_WED_WPDMA_INT_CTRL_RRO_MSDU_PG		0xef4
-+#define MTK_WED_WPDMA_INT_CTRL_RRO_PG0_EN		BIT(0)
-+#define MTK_WED_WPDMA_INT_CTRL_RRO_PG0_CLR		BIT(1)
-+#define MTK_WED_WPDMA_INT_CTRL_RRO_PG0_DONE_TRIG	GENMASK(6, 2)
-+#define MTK_WED_WPDMA_INT_CTRL_RRO_PG1_EN		BIT(8)
-+#define MTK_WED_WPDMA_INT_CTRL_RRO_PG1_CLR		BIT(9)
-+#define MTK_WED_WPDMA_INT_CTRL_RRO_PG1_DONE_TRIG	GENMASK(14, 10)
-+#define MTK_WED_WPDMA_INT_CTRL_RRO_PG2_EN		BIT(16)
-+#define MTK_WED_WPDMA_INT_CTRL_RRO_PG2_CLR		BIT(17)
-+#define MTK_WED_WPDMA_INT_CTRL_RRO_PG2_DONE_TRIG	GENMASK(22, 18)
-+
-+#define MTK_WED_RX_IND_CMD_CNT0				0xf20
-+#define MTK_WED_RX_IND_CMD_DBG_CNT_EN			BIT(31)
-+
-+#define MTK_WED_RX_IND_CMD_CNT(_n)			(0xf20 + (_n) * 0x4)
-+#define MTK_WED_IND_CMD_MAGIC_CNT_FAIL_CNT		GENMASK(15, 0)
-+
-+#define MTK_WED_RX_ADDR_ELEM_CNT(_n)			(0xf48 + (_n) * 0x4)
-+#define MTK_WED_ADDR_ELEM_SIG_FAIL_CNT			GENMASK(15, 0)
-+#define MTK_WED_ADDR_ELEM_FIRST_SIG_FAIL_CNT		GENMASK(31, 16)
-+#define MTK_WED_ADDR_ELEM_ACKSN_CNT			GENMASK(27, 0)
-+
-+#define MTK_WED_RX_MSDU_PG_CNT(_n)			(0xf5c + (_n) * 0x4)
-+
-+#define MTK_WED_RX_PN_CHK_CNT 				0xf70
-+#define MTK_WED_PN_CHK_FAIL_CNT				GENMASK(15, 0)
-+
- #define MTK_WED_WOCPU_VIEW_MIOD_BASE		 	0x8000
- #define MTK_WED_PCIE_INT_MASK				0x0
- 
-+#define MTK_WED_PAO_AMSDU_FIFO				0x1800
-+#define MTK_WED_PAO_AMSDU_IS_PRIOR0_RING		BIT(10)
-+
-+#define MTK_WED_PAO_STA_INFO				0x01810
-+#define MTK_WED_PAO_STA_INFO_DO_INIT			BIT(0)
-+#define MTK_WED_PAO_STA_INFO_SET_INIT			BIT(1)
-+
-+#define MTK_WED_PAO_STA_INFO_INIT			0x01814
-+#define MTK_WED_PAO_STA_WTBL_HDRT_MODE			BIT(0)
-+#define MTK_WED_PAO_STA_RMVL				BIT(1)
-+#define MTK_WED_PAO_STA_MAX_AMSDU_LEN			GENMASK(7, 2)
-+#define MTK_WED_PAO_STA_MAX_AMSDU_NUM			GENMASK(11, 8)
-+
-+#define MTK_WED_PAO_HIFTXD_BASE_L(_n)			(0x1980 + (_n) * 0x4)
-+
-+#define MTK_WED_PAO_PSE					0x1910
-+#define MTK_WED_PAO_PSE_RESET				BIT(16)
-+
-+#define MTK_WED_PAO_HIFTXD_CFG				0x1968
-+#define MTK_WED_PAO_HIFTXD_SRC				GENMASK(16, 15)
-+
-+#define MTK_WED_PAO_MON_AMSDU_FIFO_DMAD			0x1a34
-+
-+#define MTK_WED_PAO_MON_AMSDU_ENG_DMAD(_n)		(0x1a80 + (_n) * 0x50)
-+#define MTK_WED_PAO_MON_AMSDU_ENG_QFPL(_n)		(0x1a84 + (_n) * 0x50)
-+#define MTK_WED_PAO_MON_AMSDU_ENG_QENI(_n)		(0x1a88 + (_n) * 0x50)
-+#define MTK_WED_PAO_MON_AMSDU_ENG_QENO(_n)		(0x1a8c + (_n) * 0x50)
-+#define MTK_WED_PAO_MON_AMSDU_ENG_MERG(_n)		(0x1a90 + (_n) * 0x50)
-+
-+#define MTK_WED_PAO_MON_AMSDU_ENG_CNT8(_n)		(0x1a94 + (_n) * 0x50)
-+#define MTK_WED_PAO_AMSDU_ENG_MAX_QGPP_CNT		GENMASK(10, 0)
-+#define MTK_WED_PAO_AMSDU_ENG_MAX_PL_CNT		GENMASK(27, 16)
-+
-+#define MTK_WED_PAO_MON_AMSDU_ENG_CNT9(_n)		(0x1a98 + (_n) * 0x50)
-+#define MTK_WED_PAO_AMSDU_ENG_CUR_ENTRY			GENMASK(10, 0)
-+#define MTK_WED_PAO_AMSDU_ENG_MAX_BUF_MERGED		GENMASK(20, 16)
-+#define MTK_WED_PAO_AMSDU_ENG_MAX_MSDU_MERGED		GENMASK(28, 24)
-+
-+#define MTK_WED_PAO_MON_QMEM_STS1			0x1e04
-+
-+#define MTK_WED_PAO_MON_QMEM_CNT(_n)			(0x1e0c + (_n) * 0x4)
-+#define MTK_WED_PAO_QMEM_FQ_CNT				GENMASK(27, 16)
-+#define MTK_WED_PAO_QMEM_SP_QCNT			GENMASK(11, 0)
-+#define MTK_WED_PAO_QMEM_TID0_QCNT			GENMASK(27, 16)
-+#define MTK_WED_PAO_QMEM_TID1_QCNT			GENMASK(11, 0)
-+#define MTK_WED_PAO_QMEM_TID2_QCNT			GENMASK(27, 16)
-+#define MTK_WED_PAO_QMEM_TID3_QCNT			GENMASK(11, 0)
-+#define MTK_WED_PAO_QMEM_TID4_QCNT			GENMASK(27, 16)
-+#define MTK_WED_PAO_QMEM_TID5_QCNT			GENMASK(11, 0)
-+#define MTK_WED_PAO_QMEM_TID6_QCNT			GENMASK(27, 16)
-+#define MTK_WED_PAO_QMEM_TID7_QCNT			GENMASK(11, 0)
-+
-+#define MTK_WED_PAO_MON_QMEM_PTR(_n)			(0x1e20 + (_n) * 0x4)
-+#define MTK_WED_PAO_QMEM_FQ_HEAD				GENMASK(27, 16)
-+#define MTK_WED_PAO_QMEM_SP_QHEAD			GENMASK(11, 0)
-+#define MTK_WED_PAO_QMEM_TID0_QHEAD			GENMASK(27, 16)
-+#define MTK_WED_PAO_QMEM_TID1_QHEAD			GENMASK(11, 0)
-+#define MTK_WED_PAO_QMEM_TID2_QHEAD			GENMASK(27, 16)
-+#define MTK_WED_PAO_QMEM_TID3_QHEAD			GENMASK(11, 0)
-+#define MTK_WED_PAO_QMEM_TID4_QHEAD			GENMASK(27, 16)
-+#define MTK_WED_PAO_QMEM_TID5_QHEAD			GENMASK(11, 0)
-+#define MTK_WED_PAO_QMEM_TID6_QHEAD			GENMASK(27, 16)
-+#define MTK_WED_PAO_QMEM_TID7_QHEAD			GENMASK(11, 0)
-+#define MTK_WED_PAO_QMEM_FQ_TAIL			GENMASK(27, 16)
-+#define MTK_WED_PAO_QMEM_SP_QTAIL			GENMASK(11, 0)
-+#define MTK_WED_PAO_QMEM_TID0_QTAIL			GENMASK(27, 16)
-+#define MTK_WED_PAO_QMEM_TID1_QTAIL			GENMASK(11, 0)
-+#define MTK_WED_PAO_QMEM_TID2_QTAIL			GENMASK(27, 16)
-+#define MTK_WED_PAO_QMEM_TID3_QTAIL			GENMASK(11, 0)
-+#define MTK_WED_PAO_QMEM_TID4_QTAIL			GENMASK(27, 16)
-+#define MTK_WED_PAO_QMEM_TID5_QTAIL			GENMASK(11, 0)
-+#define MTK_WED_PAO_QMEM_TID6_QTAIL			GENMASK(27, 16)
-+#define MTK_WED_PAO_QMEM_TID7_QTAIL			GENMASK(11, 0)
-+
-+#define MTK_WED_PAO_MON_HIFTXD_FETCH_MSDU(_n)		(0x1ec4 + (_n) * 0x4)
-+
-+#define MTK_WED_PCIE_BASE			0x11280000
-+
-+#define MTK_WED_PCIE_BASE0			0x11300000
-+#define MTK_WED_PCIE_BASE1			0x11310000
-+#define MTK_WED_PCIE_BASE2			0x11290000
- #endif
-diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
-index b2abebe..204051d 100644
---- a/include/linux/netdevice.h
-+++ b/include/linux/netdevice.h
-@@ -880,6 +880,13 @@ struct net_device_path {
- 			u8 queue;
- 			u16 wcid;
- 			u8 bss;
-+			u32 usr_info;
-+			u8 tid;
-+			u8 is_fixedrate;
-+			u8 is_prior;
-+			u8 is_sp;
-+			u8 hf;
-+			u8 amsdu_en;
- 		} mtk_wdma;
- 	};
- };
-diff --git a/include/linux/soc/mediatek/mtk_wed.h b/include/linux/soc/mediatek/mtk_wed.h
-index 27cf284..92df4ba 100644
---- a/include/linux/soc/mediatek/mtk_wed.h
-+++ b/include/linux/soc/mediatek/mtk_wed.h
-@@ -5,11 +5,14 @@
- #include <linux/rcupdate.h>
- #include <linux/regmap.h>
- #include <linux/pci.h>
-+#include <linux/skbuff.h>
-+#include <linux/iopoll.h>
- 
- #define WED_WO_STA_REC			0x6
- 
- #define MTK_WED_TX_QUEUES		2
- #define MTK_WED_RX_QUEUES		2
-+#define MTK_WED_RX_PAGE_QUEUES         3
- 
- enum mtk_wed_wo_cmd {
- 	MTK_WED_WO_CMD_WED_CFG,
-@@ -55,10 +58,13 @@ enum mtk_wed_bus_tye {
- struct mtk_wed_hw;
- struct mtk_wdma_desc;
- 
-+#define MTK_WED_RING_CONFIGURED		BIT(0)
-+
- struct mtk_wed_ring {
- 	struct mtk_wdma_desc *desc;
- 	dma_addr_t desc_phys;
- 	int size;
-+	u32 flags;
- 
- 	u32 reg_base;
- 	void __iomem *wpdma;
-@@ -69,11 +75,18 @@ struct mtk_rxbm_desc {
- 	__le32 token;
- } __packed __aligned(4);
- 
-+struct dma_page_info {
-+	void *addr;
-+	dma_addr_t addr_phys;
-+};
-+
- struct dma_buf {
- 	int size;
--	void **pages;
--	struct mtk_wdma_desc *desc;
-+	int pkt_nums;
-+	void *desc;
-+	int desc_size;
- 	dma_addr_t desc_phys;
-+	struct dma_page_info *pages;
- };
- 
- struct dma_entry {
-@@ -97,6 +110,7 @@ struct mtk_wed_device {
- 	struct device *dev;
- 	struct mtk_wed_hw *hw;
- 	bool init_done, running;
-+	bool wdma_init_done;
- 	int wdma_idx;
- 	int irq;
- 	u8 ver;
-@@ -108,7 +122,11 @@ struct mtk_wed_device {
- 	struct mtk_wed_ring rx_ring[MTK_WED_RX_QUEUES];
- 	struct mtk_wed_ring rx_wdma[MTK_WED_RX_QUEUES];
- 
--	struct dma_buf buf_ring;
-+	struct mtk_wed_ring rx_rro_ring[MTK_WED_RX_QUEUES];
-+	struct mtk_wed_ring rx_page_ring[MTK_WED_RX_PAGE_QUEUES];
-+	struct mtk_wed_ring ind_cmd_ring;
-+
-+	struct dma_buf tx_buf_ring;
- 
- 	struct {
- 		int size;
-@@ -117,6 +135,8 @@ struct mtk_wed_device {
- 		dma_addr_t desc_phys;
- 	} rx_buf_ring;
- 
-+	struct dma_buf rx_page_buf_ring;
-+
- 	struct {
- 		struct mtk_wed_ring rro_ring;
- 		void __iomem *rro_desc;
-@@ -131,8 +151,9 @@ struct mtk_wed_device {
- 			struct platform_device *platform_dev;
- 			struct pci_dev *pci_dev;
- 		};
-+		enum mtk_wed_bus_tye bus_type;
- 		void __iomem *base;
--		u32 bus_type;
-+		void __iomem *regs;
- 		u32 phy_base;
- 
- 		u32 wpdma_phys;
-@@ -141,10 +162,14 @@ struct mtk_wed_device {
- 		u32 wpdma_tx;
- 		u32 wpdma_txfree;
- 		u32 wpdma_rx_glo;
--		u32 wpdma_rx;
-+		u32 wpdma_rx[MTK_WED_RX_QUEUES];
-+		u32 wpdma_rx_rro[MTK_WED_RX_QUEUES];
-+		u32 wpdma_rx_pg;
- 
- 		u8 tx_tbit[MTK_WED_TX_QUEUES];
- 		u8 rx_tbit[MTK_WED_RX_QUEUES];
-+		u8 rro_rx_tbit[MTK_WED_RX_QUEUES];
-+		u8 rx_pg_tbit[MTK_WED_RX_PAGE_QUEUES];
- 		u8 txfree_tbit;
- 
- 		u16 token_start;
-@@ -154,12 +179,26 @@ struct mtk_wed_device {
- 		unsigned int rx_size;
- 
- 		bool wcid_512;
--
-+		bool hwrro;
-+		bool msi;
-+
-+		u8 max_amsdu_nums;
-+		u32 max_amsdu_len;
-+
-+		struct {
-+			u8 se_group_nums;
-+			u16 win_size;
-+			u16 particular_sid;
-+			u32 ack_sn_addr;
-+			dma_addr_t particular_se_phys;
-+			dma_addr_t addr_elem_phys[1024];
-+		} ind_cmd;
-+
-+		u32 chip_id;
- 		u32 (*init_buf)(void *ptr, dma_addr_t phys, int token_id);
- 		int (*offload_enable)(struct mtk_wed_device *wed);
- 		void (*offload_disable)(struct mtk_wed_device *wed);
--		u32 (*init_rx_buf)(struct mtk_wed_device *wed,
--				   int pkt_num);
-+		u32 (*init_rx_buf)(struct mtk_wed_device *wed, int size);
- 		void (*release_rx_buf)(struct mtk_wed_device *wed);
- 		void (*update_wo_rx_stats)(struct mtk_wed_device *wed,
- 					   struct mtk_wed_wo_rx_stats *stats);
-@@ -180,6 +219,11 @@ struct mtk_wed_ops {
- 				 void __iomem *regs);
- 	int (*rx_ring_setup)(struct mtk_wed_device *dev, int ring,
- 			     void __iomem *regs, bool reset);
-+	int (*rro_rx_ring_setup)(struct mtk_wed_device *dev, int ring,
-+			     void __iomem *regs);
-+	int (*msdu_pg_rx_ring_setup)(struct mtk_wed_device *dev, int ring,
-+			     void __iomem *regs);
-+	int (*ind_rx_ring_setup)(struct mtk_wed_device *dev, void __iomem *regs);
- 	int (*msg_update)(struct mtk_wed_device *dev, int cmd_id,
- 			  void *data, int len);
- 	void (*detach)(struct mtk_wed_device *dev);
-@@ -196,6 +240,7 @@ struct mtk_wed_ops {
- 	void (*irq_set_mask)(struct mtk_wed_device *dev, u32 mask);
- 	void (*ppe_check)(struct mtk_wed_device *dev, struct sk_buff *skb,
- 			  u32 reason, u32 hash);
-+	void (*start_hwrro)(struct mtk_wed_device *dev, u32 irq_mask);
- };
- 
- extern const struct mtk_wed_ops __rcu *mtk_soc_wed_ops;
-@@ -224,12 +269,21 @@ static inline bool
- mtk_wed_get_rx_capa(struct mtk_wed_device *dev)
- {
- #ifdef CONFIG_NET_MEDIATEK_SOC_WED
-+	if (dev->ver == 3 && !dev->wlan.hwrro)
-+		return false;
-+
- 	return dev->ver != 1;
- #else
- 	return false;
- #endif
- }
- 
-+static inline bool
-+mtk_wed_device_support_pao(struct mtk_wed_device *dev)
-+{
-+	return dev->ver == 3;
-+}
-+
- #ifdef CONFIG_NET_MEDIATEK_SOC_WED
- #define mtk_wed_device_active(_dev) !!(_dev)->ops
- #define mtk_wed_device_detach(_dev) (_dev)->ops->detach(_dev)
-@@ -243,6 +297,12 @@ mtk_wed_get_rx_capa(struct mtk_wed_device *dev)
- 	(_dev)->ops->txfree_ring_setup(_dev, _regs)
- #define mtk_wed_device_rx_ring_setup(_dev, _ring, _regs, _reset) \
- 	(_dev)->ops->rx_ring_setup(_dev, _ring, _regs, _reset)
-+#define mtk_wed_device_rro_rx_ring_setup(_dev, _ring, _regs) \
-+	(_dev)->ops->rro_rx_ring_setup(_dev, _ring, _regs)
-+#define mtk_wed_device_msdu_pg_rx_ring_setup(_dev, _ring, _regs) \
-+	(_dev)->ops->msdu_pg_rx_ring_setup(_dev, _ring, _regs)
-+#define mtk_wed_device_ind_rx_ring_setup(_dev, _regs) \
-+	(_dev)->ops->ind_rx_ring_setup(_dev, _regs)
- #define mtk_wed_device_update_msg(_dev, _id, _msg, _len) \
- 	(_dev)->ops->msg_update(_dev, _id, _msg, _len)
- #define mtk_wed_device_reg_read(_dev, _reg) \
-@@ -257,6 +317,9 @@ mtk_wed_get_rx_capa(struct mtk_wed_device *dev)
- 	(_dev)->ops->reset_dma(_dev)
- #define mtk_wed_device_ppe_check(_dev, _skb, _reason, _hash) \
- 	(_dev)->ops->ppe_check(_dev, _skb, _reason, _hash)
-+#define mtk_wed_device_start_hwrro(_dev, _mask) \
-+	(_dev)->ops->start_hwrro(_dev, _mask)
-+
- #else
- static inline bool mtk_wed_device_active(struct mtk_wed_device *dev)
- {
-@@ -268,6 +331,9 @@ static inline bool mtk_wed_device_active(struct mtk_wed_device *dev)
- #define mtk_wed_device_tx_ring_setup(_dev, _ring, _regs, _reset) -ENODEV
- #define mtk_wed_device_txfree_ring_setup(_dev, _ring, _regs) -ENODEV
- #define mtk_wed_device_rx_ring_setup(_dev, _ring, _regs, _reset) -ENODEV
-+#define mtk_wed_device_rro_rx_ring_setup(_dev, _ring, _regs) -ENODEV
-+#define mtk_wed_device_msdu_pg_rx_ring_setup(_dev, _ring, _regs)  -ENODEV
-+#define mtk_wed_device_ind_rx_ring_setup(_dev, _regs)  -ENODEV
- #define mtk_wed_device_reg_read(_dev, _reg) 0
- #define mtk_wed_device_reg_write(_dev, _reg, _val) do {} while (0)
- #define mtk_wed_device_irq_get(_dev, _mask) 0
-@@ -275,6 +341,7 @@ static inline bool mtk_wed_device_active(struct mtk_wed_device *dev)
- #define mtk_wed_device_dma_reset(_dev) do {} while (0)
- #define mtk_wed_device_setup_tc(_dev, _ndev, _type, _data) do {} while (0)
- #define mtk_wed_device_ppe_check(_dev, _hash)  do {} while (0)
-+#define mtk_wed_device_start_hwrro(_dev, _mask) do {} while (0)
- #endif
- 
- #endif
--- 
-2.18.0
-
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/wed3/999-3020-mtk-wed-add-wed3-ser-support.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/wed3/999-3020-mtk-wed-add-wed3-ser-support.patch
deleted file mode 100644
index 328a4bc..0000000
--- a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/wed3/999-3020-mtk-wed-add-wed3-ser-support.patch
+++ /dev/null
@@ -1,642 +0,0 @@
-From f0b9f017b170690be346d3e08371fdadca0d59d3 Mon Sep 17 00:00:00 2001
-From: mtk27745 <rex.lu@mediatek.com>
-Date: Mon, 18 Sep 2023 13:22:44 +0800
-Subject: [PATCH] mtk wed add wed3 ser support
-
----
- drivers/net/ethernet/mediatek/mtk_wed.c      | 260 +++++++++++++++++--
- drivers/net/ethernet/mediatek/mtk_wed_regs.h |  73 +++++-
- include/linux/soc/mediatek/mtk_wed.h         |   6 +-
- 3 files changed, 310 insertions(+), 29 deletions(-)
-
-diff --git a/drivers/net/ethernet/mediatek/mtk_wed.c b/drivers/net/ethernet/mediatek/mtk_wed.c
-index 561fc6c..f20a4ae 100644
---- a/drivers/net/ethernet/mediatek/mtk_wed.c
-+++ b/drivers/net/ethernet/mediatek/mtk_wed.c
-@@ -99,16 +99,70 @@ mtk_wdma_rx_reset(struct mtk_wed_device *dev)
- 	u32 status;
- 	u32 mask = MTK_WDMA_GLO_CFG_RX_DMA_BUSY;
- 	int busy, i;
-+	u32 value;
- 
- 	wdma_clr(dev, MTK_WDMA_GLO_CFG, MTK_WDMA_GLO_CFG_RX_DMA_EN);
- 	busy = readx_poll_timeout(mtk_wdma_read_reset, dev, status,
--			       !(status & mask), 0, 10000);
-+				  !(status & mask), 0, 10000);
- 
-+	if (dev->hw->version == 3) {
-+		wdma_clr(dev, MTK_WDMA_PREF_TX_CFG, MTK_WDMA_PREF_TX_CFG_PREF_EN);
-+		wdma_clr(dev, MTK_WDMA_PREF_RX_CFG, MTK_WDMA_PREF_RX_CFG_PREF_EN);
-+		busy = read_poll_timeout(wdma_r32, status,
-+					 !(status & MTK_WDMA_PREF_TX_CFG_PREF_BUSY), 0, 10000,
-+					 false, dev, MTK_WDMA_PREF_TX_CFG);
-+		busy = read_poll_timeout(wdma_r32, status,
-+					 !(status & MTK_WDMA_PREF_RX_CFG_PREF_BUSY), 0, 10000,
-+					 false, dev, MTK_WDMA_PREF_RX_CFG);
-+
-+		wdma_clr(dev, MTK_WDMA_WRBK_TX_CFG, MTK_WDMA_WRBK_TX_CFG_WRBK_EN);
-+		wdma_clr(dev, MTK_WDMA_WRBK_RX_CFG, MTK_WDMA_WRBK_RX_CFG_WRBK_EN);
-+		busy = read_poll_timeout(wdma_r32, status,
-+					 !(status & MTK_WDMA_WRBK_TX_CFG_WRBK_BUSY), 0, 10000,
-+					 false, dev, MTK_WDMA_WRBK_TX_CFG);
-+		busy = read_poll_timeout(wdma_r32, status,
-+					 !(status & MTK_WDMA_WRBK_RX_CFG_WRBK_BUSY), 0, 10000,
-+					 false, dev, MTK_WDMA_WRBK_RX_CFG);
-+
-+		/* Prefetch FIFO */
-+		wdma_w32(dev, MTK_WDMA_PREF_RX_FIFO_CFG,
-+			 MTK_WDMA_PREF_RX_FIFO_CFG_RING0_CLEAR |
-+			 MTK_WDMA_PREF_RX_FIFO_CFG_RING1_CLEAR);
-+		wdma_clr(dev, MTK_WDMA_PREF_RX_FIFO_CFG,
-+			 MTK_WDMA_PREF_RX_FIFO_CFG_RING0_CLEAR |
-+			 MTK_WDMA_PREF_RX_FIFO_CFG_RING1_CLEAR);
-+
-+		/* Core FIFO */
-+		value = (MTK_WDMA_XDMA_RX_FIFO_CFG_RX_PAR_FIFO_CLEAR |
-+			 MTK_WDMA_XDMA_RX_FIFO_CFG_RX_CMD_FIFO_CLEAR |
-+			 MTK_WDMA_XDMA_RX_FIFO_CFG_RX_DMAD_FIFO_CLEAR |
-+			 MTK_WDMA_XDMA_RX_FIFO_CFG_RX_ARR_FIFO_CLEAR |
-+			 MTK_WDMA_XDMA_RX_FIFO_CFG_RX_LEN_FIFO_CLEAR |
-+			 MTK_WDMA_XDMA_RX_FIFO_CFG_RX_WID_FIFO_CLEAR |
-+			 MTK_WDMA_XDMA_RX_FIFO_CFG_RX_BID_FIFO_CLEAR);
-+
-+		wdma_w32(dev, MTK_WDMA_XDMA_RX_FIFO_CFG, value);
-+		wdma_clr(dev, MTK_WDMA_XDMA_RX_FIFO_CFG, value);
-+
-+		/* Writeback FIFO */
-+		wdma_w32(dev, MTK_WDMA_WRBK_RX_FIFO_CFG(0), MTK_WDMA_WRBK_RX_FIFO_CFG_RING_CLEAR);
-+		wdma_w32(dev, MTK_WDMA_WRBK_RX_FIFO_CFG(1), MTK_WDMA_WRBK_RX_FIFO_CFG_RING_CLEAR);
-+
-+		wdma_clr(dev, MTK_WDMA_WRBK_RX_FIFO_CFG(0), MTK_WDMA_WRBK_RX_FIFO_CFG_RING_CLEAR);
-+		wdma_clr(dev, MTK_WDMA_WRBK_RX_FIFO_CFG(1), MTK_WDMA_WRBK_RX_FIFO_CFG_RING_CLEAR);
-+
-+		/* Prefetch ring status */
-+		wdma_w32(dev, MTK_WDMA_PREF_SIDX_CFG, MTK_WDMA_PREF_SIDX_CFG_RX_RING_CLEAR);
-+		wdma_clr(dev, MTK_WDMA_PREF_SIDX_CFG, MTK_WDMA_PREF_SIDX_CFG_RX_RING_CLEAR);
-+		/* Writeback ring status */
-+		wdma_w32(dev, MTK_WDMA_WRBK_SIDX_CFG, MTK_WDMA_WRBK_SIDX_CFG_RX_RING_CLEAR);
-+		wdma_clr(dev, MTK_WDMA_WRBK_SIDX_CFG, MTK_WDMA_WRBK_SIDX_CFG_RX_RING_CLEAR);
-+	}
- 	wdma_w32(dev, MTK_WDMA_RESET_IDX, MTK_WDMA_RESET_IDX_RX);
- 	wdma_w32(dev, MTK_WDMA_RESET_IDX, 0);
- 
--	for (i = 0; i < ARRAY_SIZE(dev->rx_wdma); i++)
--		if (!dev->rx_wdma[i].desc) {
-+	for (i = 0; i < ARRAY_SIZE(dev->tx_wdma); i++)
-+		if (!dev->tx_wdma[i].desc) {
- 			wdma_w32(dev, MTK_WDMA_RING_RX(i) +
- 				 MTK_WED_RING_OFS_CPU_IDX, 0);
- 	}
-@@ -121,16 +175,65 @@ mtk_wdma_tx_reset(struct mtk_wed_device *dev)
- {
- 	u32 status;
- 	u32 mask = MTK_WDMA_GLO_CFG_TX_DMA_BUSY;
--	int i;
-+	int busy, i;
-+	u32 value;
- 
- 	wdma_clr(dev, MTK_WDMA_GLO_CFG, MTK_WDMA_GLO_CFG_TX_DMA_EN);
- 	if (readx_poll_timeout(mtk_wdma_read_reset, dev, status,
- 			       !(status & mask), 0, 10000))
- 		WARN_ON_ONCE(1);
- 
-+	if (dev->hw->version == 3) {
-+		wdma_clr(dev, MTK_WDMA_PREF_TX_CFG, MTK_WDMA_PREF_TX_CFG_PREF_EN);
-+		wdma_clr(dev, MTK_WDMA_PREF_RX_CFG, MTK_WDMA_PREF_RX_CFG_PREF_EN);
-+		busy = read_poll_timeout(wdma_r32, status,
-+					 !(status & MTK_WDMA_PREF_TX_CFG_PREF_BUSY), 0, 10000,
-+					 false, dev, MTK_WDMA_PREF_TX_CFG);
-+		busy = read_poll_timeout(wdma_r32, status,
-+					 !(status & MTK_WDMA_PREF_RX_CFG_PREF_BUSY), 0, 10000,
-+					 false, dev, MTK_WDMA_PREF_RX_CFG);
-+
-+		wdma_clr(dev, MTK_WDMA_WRBK_TX_CFG, MTK_WDMA_WRBK_TX_CFG_WRBK_EN);
-+		wdma_clr(dev, MTK_WDMA_WRBK_RX_CFG, MTK_WDMA_WRBK_RX_CFG_WRBK_EN);
-+		busy = read_poll_timeout(wdma_r32, status,
-+					 !(status & MTK_WDMA_WRBK_TX_CFG_WRBK_BUSY), 0, 10000,
-+					 false, dev, MTK_WDMA_WRBK_TX_CFG);
-+		busy = read_poll_timeout(wdma_r32, status,
-+					 !(status & MTK_WDMA_WRBK_RX_CFG_WRBK_BUSY), 0, 10000,
-+					 false, dev, MTK_WDMA_WRBK_RX_CFG);
-+
-+		/* Prefetch FIFO */
-+		wdma_w32(dev, MTK_WDMA_PREF_TX_FIFO_CFG,
-+			 MTK_WDMA_PREF_TX_FIFO_CFG_RING0_CLEAR |
-+			 MTK_WDMA_PREF_TX_FIFO_CFG_RING1_CLEAR);
-+		wdma_clr(dev, MTK_WDMA_PREF_TX_FIFO_CFG,
-+			 MTK_WDMA_PREF_TX_FIFO_CFG_RING0_CLEAR |
-+			 MTK_WDMA_PREF_TX_FIFO_CFG_RING1_CLEAR);
-+		/* Core FIFO */
-+		value = (MTK_WDMA_XDMA_TX_FIFO_CFG_TX_PAR_FIFO_CLEAR |
-+			 MTK_WDMA_XDMA_TX_FIFO_CFG_TX_CMD_FIFO_CLEAR |
-+			 MTK_WDMA_XDMA_TX_FIFO_CFG_TX_DMAD_FIFO_CLEAR |
-+			 MTK_WDMA_XDMA_TX_FIFO_CFG_TX_ARR_FIFO_CLEAR);
-+
-+		wdma_w32(dev, MTK_WDMA_XDMA_TX_FIFO_CFG, value);
-+		wdma_clr(dev, MTK_WDMA_XDMA_TX_FIFO_CFG, value);
-+		/* Writeback FIFO */
-+		wdma_w32(dev, MTK_WDMA_WRBK_TX_FIFO_CFG(0), MTK_WDMA_WRBK_TX_FIFO_CFG_RING_CLEAR);
-+		wdma_w32(dev, MTK_WDMA_WRBK_TX_FIFO_CFG(1), MTK_WDMA_WRBK_TX_FIFO_CFG_RING_CLEAR);
-+
-+		wdma_clr(dev, MTK_WDMA_WRBK_TX_FIFO_CFG(0), MTK_WDMA_WRBK_TX_FIFO_CFG_RING_CLEAR);
-+		wdma_clr(dev, MTK_WDMA_WRBK_TX_FIFO_CFG(1), MTK_WDMA_WRBK_TX_FIFO_CFG_RING_CLEAR);
-+
-+		/* Prefetch ring status */
-+		wdma_w32(dev, MTK_WDMA_PREF_SIDX_CFG, MTK_WDMA_PREF_SIDX_CFG_TX_RING_CLEAR);
-+		wdma_clr(dev, MTK_WDMA_PREF_SIDX_CFG, MTK_WDMA_PREF_SIDX_CFG_TX_RING_CLEAR);
-+		/* Writeback ring status */
-+		wdma_w32(dev, MTK_WDMA_WRBK_SIDX_CFG, MTK_WDMA_WRBK_SIDX_CFG_TX_RING_CLEAR);
-+		wdma_clr(dev, MTK_WDMA_WRBK_SIDX_CFG, MTK_WDMA_WRBK_SIDX_CFG_TX_RING_CLEAR);
-+	}
- 	wdma_w32(dev, MTK_WDMA_RESET_IDX, MTK_WDMA_RESET_IDX_TX);
- 	wdma_w32(dev, MTK_WDMA_RESET_IDX, 0);
--	for (i = 0; i < ARRAY_SIZE(dev->tx_wdma); i++)
-+	for (i = 0; i < ARRAY_SIZE(dev->rx_wdma); i++)
- 		wdma_w32(dev, MTK_WDMA_RING_TX(i) +
- 			 MTK_WED_RING_OFS_CPU_IDX, 0);
- }
-@@ -913,7 +1016,7 @@ mtk_wed_dma_enable(struct mtk_wed_device *dev)
- 				MTK_WED_WPDMA_GLO_CFG_RX_DRV_UNS_VER_FORCE_4);
- 
- 			wdma_set(dev, MTK_WDMA_PREF_RX_CFG, MTK_WDMA_PREF_RX_CFG_PREF_EN);
--			//wdma_w32(dev, MTK_WDMA_WRBK_RX_CFG, MTK_WDMA_WRBK_RX_CFG_WRBK_EN);
-+			wdma_set(dev, MTK_WDMA_WRBK_RX_CFG, MTK_WDMA_WRBK_RX_CFG_WRBK_EN);
- 			if (mtk_wed_get_rx_capa(dev)) {
- 				wed_set(dev, MTK_WED_WPDMA_RX_D_PREF_CFG,
- 					MTK_WED_WPDMA_RX_D_PREF_EN |
-@@ -1476,13 +1579,30 @@ mtk_wed_rx_reset(struct mtk_wed_device *dev)
- 	mtk_wed_mcu_send_msg(wo, MODULE_ID_WO, MTK_WED_WO_CMD_CHANGE_STATE,
- 			     &state, sizeof(state), true);
- 
-+	if (dev->wlan.hwrro) {
-+		wed_clr(dev, MTK_WED_CTRL, MTK_WED_CTRL_WED_RX_IND_CMD_EN);
-+		mtk_wed_poll_busy(dev, MTK_WED_RRO_RX_HW_STS,
-+				  MTK_WED_RX_IND_CMD_BUSY);
-+		mtk_wed_reset(dev, MTK_WED_RESET_RRO_RX_TO_PG);
-+	}
- 	wed_clr(dev, MTK_WED_WPDMA_RX_D_GLO_CFG, MTK_WED_WPDMA_RX_D_RX_DRV_EN);
- 	busy = mtk_wed_poll_busy(dev, MTK_WED_WPDMA_RX_D_GLO_CFG,
- 				 MTK_WED_WPDMA_RX_D_RX_DRV_BUSY);
-+	if (dev->hw->version == 3)
-+		busy = mtk_wed_poll_busy(dev, MTK_WED_WPDMA_RX_D_PREF_CFG,
-+					 MTK_WED_WPDMA_RX_D_PREF_BUSY);
- 	if (busy) {
- 		mtk_wed_reset(dev, MTK_WED_RESET_WPDMA_INT_AGENT);
- 		mtk_wed_reset(dev, MTK_WED_RESET_WPDMA_RX_D_DRV);
- 	} else {
-+		if (dev->hw->version == 3) {
-+			/*1.a. Disable Prefetch HW*/
-+			wed_clr(dev, MTK_WED_WPDMA_RX_D_PREF_CFG, MTK_WED_WPDMA_RX_D_PREF_EN);
-+			mtk_wed_poll_busy(dev, MTK_WED_WPDMA_RX_D_PREF_CFG,
-+					  MTK_WED_WPDMA_RX_D_PREF_BUSY);
-+			wed_w32(dev, MTK_WED_WPDMA_RX_D_RST_IDX,
-+				MTK_WED_WPDMA_RX_D_RST_DRV_IDX_ALL);
-+		}
- 		wed_w32(dev, MTK_WED_WPDMA_RX_D_RST_IDX,
- 			MTK_WED_WPDMA_RX_D_RST_CRX_IDX |
- 			MTK_WED_WPDMA_RX_D_RST_DRV_IDX);
-@@ -1510,6 +1630,24 @@ mtk_wed_rx_reset(struct mtk_wed_device *dev)
- 		wed_w32(dev, MTK_WED_RROQM_RST_IDX, 0);
- 	}
- 
-+	if (dev->wlan.hwrro) {
-+		/* Disable RRO MSDU Page Drv */
-+		wed_clr(dev, MTK_WED_RRO_MSDU_PG_RING2_CFG, MTK_WED_RRO_MSDU_PG_DRV_EN);
-+
-+		/* Disable RRO Data Drv */
-+		wed_clr(dev, MTK_WED_RRO_RX_D_CFG(2), MTK_WED_RRO_RX_D_DRV_EN);
-+
-+		/* RRO MSDU Page Drv Reset */
-+		wed_w32(dev, MTK_WED_RRO_MSDU_PG_RING2_CFG, MTK_WED_RRO_MSDU_PG_DRV_CLR);
-+		mtk_wed_poll_busy(dev, MTK_WED_RRO_MSDU_PG_RING2_CFG,
-+				  MTK_WED_RRO_MSDU_PG_DRV_CLR);
-+
-+		/* RRO Data Drv Reset */
-+		wed_w32(dev, MTK_WED_RRO_RX_D_CFG(2), MTK_WED_RRO_RX_D_DRV_CLR);
-+		mtk_wed_poll_busy(dev, MTK_WED_RRO_RX_D_CFG(2),
-+				  MTK_WED_RRO_RX_D_DRV_CLR);
-+	}
-+
- 	/* reset route qm */
- 	wed_clr(dev, MTK_WED_CTRL, MTK_WED_CTRL_RX_ROUTE_QM_EN);
- 	busy = mtk_wed_poll_busy(dev, MTK_WED_CTRL,
-@@ -1517,8 +1655,13 @@ mtk_wed_rx_reset(struct mtk_wed_device *dev)
- 	if (busy) {
- 		mtk_wed_reset(dev, MTK_WED_RESET_RX_ROUTE_QM);
- 	} else {
--		wed_set(dev, MTK_WED_RTQM_GLO_CFG,
--			MTK_WED_RTQM_Q_RST);
-+		if (dev->hw->version == 3) {
-+			wed_set(dev, MTK_WED_RTQM_RST, BIT(0));
-+			wed_clr(dev, MTK_WED_RTQM_RST, BIT(0));
-+			mtk_wed_reset(dev, MTK_WED_RESET_RX_ROUTE_QM);
-+		} else
-+			wed_set(dev, MTK_WED_RTQM_GLO_CFG,
-+				MTK_WED_RTQM_Q_RST);
- 	}
- 
- 	/* reset tx wdma */
-@@ -1526,8 +1669,13 @@ mtk_wed_rx_reset(struct mtk_wed_device *dev)
- 
- 	/* reset tx wdma drv */
- 	wed_clr(dev, MTK_WED_WDMA_GLO_CFG, MTK_WED_WDMA_GLO_CFG_TX_DRV_EN);
--	mtk_wed_poll_busy(dev, MTK_WED_CTRL,
--			  MTK_WED_CTRL_WDMA_INT_AGENT_BUSY);
-+	if (dev->hw->version == 3)
-+		mtk_wed_poll_busy(dev, MTK_WED_WPDMA_STATUS,
-+				  MTK_WED_WPDMA_STATUS_TX_DRV);
-+	else
-+		mtk_wed_poll_busy(dev, MTK_WED_CTRL,
-+				  MTK_WED_CTRL_WDMA_INT_AGENT_BUSY);
-+
- 	mtk_wed_reset(dev, MTK_WED_RESET_WDMA_TX_DRV);
- 
- 	/* reset wed rx dma */
-@@ -1545,9 +1693,17 @@ mtk_wed_rx_reset(struct mtk_wed_device *dev)
- 	/* reset rx bm */
- 	wed_clr(dev, MTK_WED_CTRL, MTK_WED_CTRL_WED_RX_BM_EN);
- 	mtk_wed_poll_busy(dev, MTK_WED_CTRL,
--			   MTK_WED_CTRL_WED_RX_BM_BUSY);
-+			  MTK_WED_CTRL_WED_RX_BM_BUSY);
- 	mtk_wed_reset(dev, MTK_WED_RESET_RX_BM);
- 
-+	if (dev->wlan.hwrro) {
-+		wed_clr(dev, MTK_WED_CTRL, MTK_WED_CTRL_WED_RX_PG_BM_EN);
-+		mtk_wed_poll_busy(dev, MTK_WED_CTRL,
-+				  MTK_WED_CTRL_WED_RX_PG_BM_BUSY);
-+		wed_set(dev, MTK_WED_RESET, MTK_WED_RESET_RX_PG_BM);
-+		wed_clr(dev, MTK_WED_RESET, MTK_WED_RESET_RX_PG_BM);
-+	}
-+
- 	/* wo change to enable state */
- 	state = WO_STATE_ENABLE;
- 	mtk_wed_mcu_send_msg(wo, MODULE_ID_WO, MTK_WED_WO_CMD_CHANGE_STATE,
-@@ -1564,6 +1720,9 @@ mtk_wed_rx_reset(struct mtk_wed_device *dev)
- 	}
- 
- 	mtk_wed_free_rx_buffer(dev);
-+
-+	if (dev->wlan.hwrro)
-+		mtk_wed_rx_page_free_buffer(dev);
- }
- 
- 
-@@ -1597,18 +1756,54 @@ mtk_wed_reset_dma(struct mtk_wed_device *dev)
- 
- 	/* 2. Reset WDMA Rx DMA/Driver_Engine */
- 	busy = !!mtk_wdma_rx_reset(dev);
-+	if (dev->hw->version == 3) {
-+		val = wed_r32(dev, MTK_WED_WDMA_GLO_CFG);
-+		val |= MTK_WED_WDMA_GLO_CFG_RX_DIS_FSM_AUTO_IDLE;
-+		val &= ~MTK_WED_WDMA_GLO_CFG_RX_DRV_EN;
-+		wed_w32(dev, MTK_WED_WDMA_GLO_CFG, val);
-+	} else
-+		wed_clr(dev, MTK_WED_WDMA_GLO_CFG, MTK_WED_WDMA_GLO_CFG_RX_DRV_EN);
- 
--	wed_clr(dev, MTK_WED_WDMA_GLO_CFG, MTK_WED_WDMA_GLO_CFG_RX_DRV_EN);
- 	busy = !!(busy ||
- 		  mtk_wed_poll_busy(dev, MTK_WED_WDMA_GLO_CFG,
--					 MTK_WED_WDMA_GLO_CFG_RX_DRV_BUSY));
-+				    MTK_WED_WDMA_GLO_CFG_RX_DRV_BUSY));
-+	if (dev->hw->version == 3)
-+		busy = !!(busy ||
-+			  mtk_wed_poll_busy(dev, MTK_WED_WDMA_RX_PREF_CFG,
-+					    MTK_WED_WDMA_RX_PREF_BUSY));
- 
- 	if (busy) {
- 		mtk_wed_reset(dev, MTK_WED_RESET_WDMA_INT_AGENT);
- 		mtk_wed_reset(dev, MTK_WED_RESET_WDMA_RX_DRV);
- 	} else {
-+		if (dev->hw->version == 3) {
-+			/*1.a. Disable Prefetch HW*/
-+			wed_clr(dev, MTK_WED_WDMA_RX_PREF_CFG, MTK_WED_WDMA_RX_PREF_EN);
-+			mtk_wed_poll_busy(dev, MTK_WED_WDMA_RX_PREF_CFG,
-+					  MTK_WED_WDMA_RX_PREF_BUSY);
-+			wed_clr(dev, MTK_WED_WDMA_RX_PREF_CFG, MTK_WED_WDMA_RX_PREF_DDONE2_EN);
-+
-+			/* reset prefetch index */
-+			wed_set(dev, MTK_WED_WDMA_RX_PREF_CFG,
-+				MTK_WED_WDMA_RX_PREF_RX0_SIDX_CLR |
-+				MTK_WED_WDMA_RX_PREF_RX1_SIDX_CLR);
-+
-+			wed_clr(dev, MTK_WED_WDMA_RX_PREF_CFG,
-+				MTK_WED_WDMA_RX_PREF_RX0_SIDX_CLR |
-+				MTK_WED_WDMA_RX_PREF_RX1_SIDX_CLR);
-+
-+			/* reset prefetch FIFO */
-+			wed_w32(dev, MTK_WED_WDMA_RX_PREF_FIFO_CFG,
-+				MTK_WED_WDMA_RX_PREF_FIFO_RX0_CLR |
-+				MTK_WED_WDMA_RX_PREF_FIFO_RX1_CLR);
-+			wed_w32(dev, MTK_WED_WDMA_RX_PREF_FIFO_CFG, 0);
-+			/*2. Reset dma index*/
-+			wed_w32(dev, MTK_WED_WDMA_RESET_IDX,
-+				MTK_WED_WDMA_RESET_IDX_RX_ALL);
-+		}
- 		wed_w32(dev, MTK_WED_WDMA_RESET_IDX,
--			MTK_WED_WDMA_RESET_IDX_RX | MTK_WED_WDMA_RESET_IDX_DRV);
-+			MTK_WED_WDMA_RESET_IDX_RX |
-+			MTK_WED_WDMA_RESET_IDX_DRV);
- 		wed_w32(dev, MTK_WED_WDMA_RESET_IDX, 0);
- 
- 		wed_set(dev, MTK_WED_WDMA_GLO_CFG,
-@@ -1623,9 +1818,15 @@ mtk_wed_reset_dma(struct mtk_wed_device *dev)
- 		MTK_WED_CTRL_WED_TX_FREE_AGENT_EN);
- 
- 	for (i = 0; i < 100; i++) {
--		val = wed_r32(dev, MTK_WED_TX_BM_INTF);
--		if (FIELD_GET(MTK_WED_TX_BM_INTF_TKFIFO_FDEP, val) == 0x40)
--			break;
-+		if (dev->ver > MTK_WED_V1) {
-+			val = wed_r32(dev, MTK_WED_TX_TKID_INTF);
-+			if (FIELD_GET(MTK_WED_TX_TKID_INTF_TKFIFO_FDEP, val) == 0x40)
-+				break;
-+		} else {
-+			val = wed_r32(dev, MTK_WED_TX_BM_INTF);
-+			if (FIELD_GET(MTK_WED_TX_BM_INTF_TKFIFO_FDEP, val) == 0x40)
-+				break;
-+		}
- 	}
- 	mtk_wed_reset(dev, MTK_WED_RESET_TX_FREE_AGENT);
- 
-@@ -1634,18 +1835,20 @@ mtk_wed_reset_dma(struct mtk_wed_device *dev)
- 
- 	/* 4. Reset WED WPDMA Tx Driver Engine */
- 	busy = mtk_wed_poll_busy(dev, MTK_WED_WPDMA_GLO_CFG,
--				      MTK_WED_WPDMA_GLO_CFG_TX_DRV_BUSY);
-+				 MTK_WED_WPDMA_GLO_CFG_TX_DRV_BUSY);
- 	wed_clr(dev, MTK_WED_WPDMA_GLO_CFG,
- 		MTK_WED_WPDMA_GLO_CFG_TX_DRV_EN |
- 		MTK_WED_WPDMA_GLO_CFG_RX_DRV_EN);
- 
- 	busy = !!(busy ||
- 		  mtk_wed_poll_busy(dev, MTK_WED_WPDMA_GLO_CFG,
--					 MTK_WED_WPDMA_GLO_CFG_RX_DRV_BUSY));
-+				    MTK_WED_WPDMA_GLO_CFG_RX_DRV_BUSY));
- 	if (busy) {
- 		mtk_wed_reset(dev, MTK_WED_RESET_WPDMA_INT_AGENT);
- 		mtk_wed_reset(dev, MTK_WED_RESET_WPDMA_TX_DRV);
- 		mtk_wed_reset(dev, MTK_WED_RESET_WPDMA_RX_DRV);
-+		if (dev->hw->version == 3)
-+			wed_w32(dev, MTK_WED_RX1_CTRL2, 0);
- 	} else {
- 		wed_w32(dev, MTK_WED_WPDMA_RESET_IDX,
- 			MTK_WED_WPDMA_RESET_IDX_TX |
-@@ -1658,11 +1861,17 @@ mtk_wed_reset_dma(struct mtk_wed_device *dev)
- 		}
- 	}
- 
--	if (dev->ver > MTK_WED_V1) {
--		dev->init_done = false;
--		mtk_wed_rx_reset(dev);
-+	dev->init_done = false;
-+
-+	if (dev->hw->version == 3) {
-+		/*reset wed pao*/
-+		wed_clr(dev, MTK_WED_CTRL, MTK_WED_CTRL_TX_PAO_EN);
-+		mtk_wed_reset(dev, MTK_WED_RESET_TX_PAO);
- 	}
- 
-+	if (mtk_wed_get_rx_capa(dev))
-+		mtk_wed_rx_reset(dev);
-+
- }
- 
- static int
-@@ -1875,7 +2084,7 @@ mtk_wed_ppe_check(struct mtk_wed_device *dev, struct sk_buff *skb,
- }
- 
- static void
--mtk_wed_start_hwrro(struct mtk_wed_device *dev, u32 irq_mask)
-+mtk_wed_start_hwrro(struct mtk_wed_device *dev, u32 irq_mask, bool reset)
- {
- 	int idx, ret;
- 
-@@ -1885,6 +2094,11 @@ mtk_wed_start_hwrro(struct mtk_wed_device *dev, u32 irq_mask)
- 	if (!mtk_wed_get_rx_capa(dev) || !dev->wlan.hwrro)
- 		return;
- 
-+	if (reset) {
-+		wed_set(dev, MTK_WED_RRO_MSDU_PG_RING2_CFG, MTK_WED_RRO_MSDU_PG_DRV_EN);
-+		return;
-+	}
-+	
- 	wed_set(dev, MTK_WED_RRO_RX_D_CFG(2), MTK_WED_RRO_MSDU_PG_DRV_CLR);
- 	wed_w32(dev, MTK_WED_RRO_MSDU_PG_RING2_CFG, MTK_WED_RRO_MSDU_PG_DRV_CLR);
- 
-diff --git a/drivers/net/ethernet/mediatek/mtk_wed_regs.h b/drivers/net/ethernet/mediatek/mtk_wed_regs.h
-index 25be547..4379dc4 100644
---- a/drivers/net/ethernet/mediatek/mtk_wed_regs.h
-+++ b/drivers/net/ethernet/mediatek/mtk_wed_regs.h
-@@ -42,6 +42,8 @@ struct mtk_wdma_desc {
- #define MTK_WED_RESET					0x008
- #define MTK_WED_RESET_TX_BM				BIT(0)
- #define MTK_WED_RESET_RX_BM				BIT(1)
-+#define MTK_WED_RESET_RX_PG_BM				BIT(2)
-+#define MTK_WED_RESET_RRO_RX_TO_PG			BIT(3)
- #define MTK_WED_RESET_TX_FREE_AGENT			BIT(4)
- #define MTK_WED_RESET_WPDMA_TX_DRV			BIT(8)
- #define MTK_WED_RESET_WPDMA_RX_DRV			BIT(9)
-@@ -64,7 +66,7 @@ struct mtk_wdma_desc {
- #define MTK_WED_CTRL_WDMA_INT_AGENT_BUSY		BIT(3)
- #define MTK_WED_CTRL_WED_RX_IND_CMD_EN			BIT(5)
- #define MTK_WED_CTRL_WED_RX_PG_BM_EN			BIT(6)
--#define MTK_WED_CTRL_WED_RX_PG_BM_BUSU			BIT(7)
-+#define MTK_WED_CTRL_WED_RX_PG_BM_BUSY			BIT(7)
- #define MTK_WED_CTRL_WED_TX_BM_EN			BIT(8)
- #define MTK_WED_CTRL_WED_TX_BM_BUSY			BIT(9)
- #define MTK_WED_CTRL_WED_TX_FREE_AGENT_EN		BIT(10)
-@@ -123,6 +125,10 @@ struct mtk_wdma_desc {
- #define MTK_WED_STATUS					0x060
- #define MTK_WED_STATUS_TX				GENMASK(15, 8)
- 
-+#define MTK_WED_WPDMA_STATUS				0x068
-+#define MTK_WED_WPDMA_STATUS_TX_DRV			GENMASK(15, 8)
-+
-+
- #define MTK_WED_TX_BM_CTRL				0x080
- #define MTK_WED_TX_BM_CTRL_VLD_GRP_NUM			GENMASK(6, 0)
- #define MTK_WED_TX_BM_CTRL_RSV_GRP_NUM			GENMASK(22, 16)
-@@ -167,6 +173,9 @@ struct mtk_wdma_desc {
- 
- #define MTK_WED_TX_TKID_CTRL_PAUSE			BIT(28)
- 
-+#define MTK_WED_TX_TKID_INTF				0x0dc
-+#define MTK_WED_TX_TKID_INTF_TKFIFO_FDEP		GENMASK(25, 16)
-+
- #define MTK_WED_TX_TKID_DYN_THR				0x0e0
- #define MTK_WED_TX_TKID_DYN_THR_LO			GENMASK(6, 0)
- #define MTK_WED_TX_TKID_DYN_THR_HI			GENMASK(22, 16)
-@@ -203,10 +212,11 @@ struct mtk_wdma_desc {
- #define MTK_WED_GLO_CFG_RX_2B_OFFSET			BIT(31)
- 
- #define MTK_WED_RESET_IDX				0x20c
--#define MTK_WED_RESET_IDX_TX				GENMASK(3, 0)
--#if defined(CONFIG_MEDIATEK_NETSYS_V2)
-+#if defined(CONFIG_MEDIATEK_NETSYS_V2) || defined(CONFIG_MEDIATEK_NETSYS_V3)
-+#define MTK_WED_RESET_IDX_TX				GENMASK(1, 0)
- #define MTK_WED_RESET_IDX_RX				GENMASK(7, 6)
- #else
-+#define MTK_WED_RESET_IDX_TX				GENMASK(3, 0)
- #define MTK_WED_RESET_IDX_RX				GENMASK(17, 16)
- #endif
- #define MTK_WED_RESET_WPDMA_IDX_RX			GENMASK(31, 30)
-@@ -221,6 +231,7 @@ struct mtk_wdma_desc {
- #define MTK_WED_RING_RX_DATA(_n)			(0x420 + (_n) * 0x10)
- 
- #define MTK_WED_SCR0					0x3c0
-+#define MTK_WED_RX1_CTRL2				0x418
- #define MTK_WED_WPDMA_INT_TRIGGER			0x504
- #define MTK_WED_WPDMA_INT_TRIGGER_RX_DONE		BIT(1)
- #define MTK_WED_WPDMA_INT_TRIGGER_TX_DONE		GENMASK(5, 4)
-@@ -336,6 +347,7 @@ struct mtk_wdma_desc {
- 
- #define MTK_WED_WPDMA_RX_D_RST_IDX			0x760
- #define MTK_WED_WPDMA_RX_D_RST_CRX_IDX			GENMASK(17, 16)
-+#define MTK_WED_WPDMA_RX_D_RST_DRV_IDX_ALL		BIT(20)
- #define MTK_WED_WPDMA_RX_D_RST_DRV_IDX			GENMASK(25, 24)
- 
- #define MTK_WED_WPDMA_RX_GLO_CFG			0x76c
-@@ -352,6 +364,7 @@ struct mtk_wdma_desc {
- 
- #define MTK_WED_WPDMA_RX_D_PREF_CFG			0x7b4
- #define MTK_WED_WPDMA_RX_D_PREF_EN			BIT(0)
-+#define MTK_WED_WPDMA_RX_D_PREF_BUSY		BIT(1)
- #define MTK_WED_WPDMA_RX_D_PREF_BURST_SIZE		GENMASK(12, 8)
- #define MTK_WED_WPDMA_RX_D_PREF_LOW_THRES		GENMASK(21, 16)
- 
-@@ -373,11 +386,13 @@ struct mtk_wdma_desc {
- 
- #define MTK_WED_WDMA_RX_PREF_CFG			0x950
- #define MTK_WED_WDMA_RX_PREF_EN				BIT(0)
-+#define MTK_WED_WDMA_RX_PREF_BUSY			BIT(1)
- #define MTK_WED_WDMA_RX_PREF_BURST_SIZE			GENMASK(12, 8)
- #define MTK_WED_WDMA_RX_PREF_LOW_THRES			GENMASK(21, 16)
- #define MTK_WED_WDMA_RX_PREF_RX0_SIDX_CLR		BIT(24)
- #define MTK_WED_WDMA_RX_PREF_RX1_SIDX_CLR		BIT(25)
- #define MTK_WED_WDMA_RX_PREF_DDONE2_EN			BIT(26)
-+#define MTK_WED_WDMA_RX_PREF_DDONE2_BUSY		BIT(27)
- 
- #define MTK_WED_WDMA_RX_PREF_FIFO_CFG			0x95C
- #define MTK_WED_WDMA_RX_PREF_FIFO_RX0_CLR		BIT(0)
-@@ -406,6 +421,7 @@ struct mtk_wdma_desc {
- 
- #define MTK_WED_WDMA_RESET_IDX				0xa08
- #define MTK_WED_WDMA_RESET_IDX_RX			GENMASK(17, 16)
-+#define MTK_WED_WDMA_RESET_IDX_RX_ALL			BIT(20)
- #define MTK_WED_WDMA_RESET_IDX_DRV			GENMASK(25, 24)
- 
- #define MTK_WED_WDMA_INT_CLR				0xa24
-@@ -474,21 +490,66 @@ struct mtk_wdma_desc {
- #define MTK_WDMA_INT_MASK_RX_DELAY			BIT(30)
- #define MTK_WDMA_INT_MASK_RX_COHERENT			BIT(31)
- 
-+#define MTK_WDMA_XDMA_TX_FIFO_CFG			0x238
-+#define MTK_WDMA_XDMA_TX_FIFO_CFG_TX_PAR_FIFO_CLEAR		BIT(0)
-+#define MTK_WDMA_XDMA_TX_FIFO_CFG_TX_CMD_FIFO_CLEAR		BIT(4)
-+#define MTK_WDMA_XDMA_TX_FIFO_CFG_TX_DMAD_FIFO_CLEAR		BIT(8)
-+#define MTK_WDMA_XDMA_TX_FIFO_CFG_TX_ARR_FIFO_CLEAR		BIT(12)
-+
-+#define MTK_WDMA_XDMA_RX_FIFO_CFG			0x23c
-+#define MTK_WDMA_XDMA_RX_FIFO_CFG_RX_PAR_FIFO_CLEAR		BIT(0)
-+#define MTK_WDMA_XDMA_RX_FIFO_CFG_RX_CMD_FIFO_CLEAR		BIT(4)
-+#define MTK_WDMA_XDMA_RX_FIFO_CFG_RX_DMAD_FIFO_CLEAR		BIT(8)
-+#define MTK_WDMA_XDMA_RX_FIFO_CFG_RX_ARR_FIFO_CLEAR		BIT(12)
-+#define MTK_WDMA_XDMA_RX_FIFO_CFG_RX_LEN_FIFO_CLEAR		BIT(15)
-+#define MTK_WDMA_XDMA_RX_FIFO_CFG_RX_WID_FIFO_CLEAR		BIT(18)
-+#define MTK_WDMA_XDMA_RX_FIFO_CFG_RX_BID_FIFO_CLEAR		BIT(21)
-+
-+
-+
- #define MTK_WDMA_INT_GRP1				0x250
- #define MTK_WDMA_INT_GRP2				0x254
- 
- #define MTK_WDMA_PREF_TX_CFG				0x2d0
- #define MTK_WDMA_PREF_TX_CFG_PREF_EN			BIT(0)
-+#define MTK_WDMA_PREF_TX_CFG_PREF_BUSY			BIT(1)
- 
- #define MTK_WDMA_PREF_RX_CFG				0x2dc
- #define MTK_WDMA_PREF_RX_CFG_PREF_EN			BIT(0)
-+#define MTK_WDMA_PREF_RX_CFG_PREF_BUSY			BIT(1)
-+
-+#define MTK_WDMA_PREF_RX_FIFO_CFG			0x2e0
-+#define MTK_WDMA_PREF_RX_FIFO_CFG_RING0_CLEAR		BIT(0)
-+#define MTK_WDMA_PREF_RX_FIFO_CFG_RING1_CLEAR		BIT(16)
-+
-+#define MTK_WDMA_PREF_TX_FIFO_CFG			0x2d4
-+#define MTK_WDMA_PREF_TX_FIFO_CFG_RING0_CLEAR		BIT(0)
-+#define MTK_WDMA_PREF_TX_FIFO_CFG_RING1_CLEAR		BIT(16)
-+
-+#define MTK_WDMA_PREF_SIDX_CFG				0x2e4
-+#define MTK_WDMA_PREF_SIDX_CFG_TX_RING_CLEAR		GENMASK(3, 0)
-+#define MTK_WDMA_PREF_SIDX_CFG_RX_RING_CLEAR		GENMASK(5, 4)
- 
- #define MTK_WDMA_WRBK_TX_CFG				0x300
-+#define MTK_WDMA_WRBK_TX_CFG_WRBK_BUSY			BIT(0)
- #define MTK_WDMA_WRBK_TX_CFG_WRBK_EN			BIT(30)
- 
-+#define MTK_WDMA_WRBK_TX_FIFO_CFG(_n)			(0x304 + (_n) * 0x4)
-+#define MTK_WDMA_WRBK_TX_FIFO_CFG_RING_CLEAR		BIT(0)
-+
-+
- #define MTK_WDMA_WRBK_RX_CFG				0x344
-+#define MTK_WDMA_WRBK_RX_CFG_WRBK_BUSY			BIT(0)
- #define MTK_WDMA_WRBK_RX_CFG_WRBK_EN			BIT(30)
- 
-+#define MTK_WDMA_WRBK_RX_FIFO_CFG(_n)			(0x348 + (_n) * 0x4)
-+#define MTK_WDMA_WRBK_RX_FIFO_CFG_RING_CLEAR		BIT(0)
-+
-+
-+#define MTK_WDMA_WRBK_SIDX_CFG				0x388
-+#define MTK_WDMA_WRBK_SIDX_CFG_TX_RING_CLEAR		GENMASK(3, 0)
-+#define MTK_WDMA_WRBK_SIDX_CFG_RX_RING_CLEAR		GENMASK(5, 4)
-+
- #define MTK_PCIE_MIRROR_MAP(n)				((n) ? 0x4 : 0x0)
- #define MTK_PCIE_MIRROR_MAP_EN				BIT(0)
- #define MTK_PCIE_MIRROR_MAP_WED_ID			BIT(1)
-@@ -502,6 +563,9 @@ struct mtk_wdma_desc {
- #define MTK_WED_RTQM_Q_DBG_BYPASS			BIT(5)
- #define MTK_WED_RTQM_TXDMAD_FPORT			GENMASK(23, 20)
- 
-+#define MTK_WED_RTQM_RST				0xb04
-+
-+
- #define MTK_WED_RTQM_IGRS0_I2HW_DMAD_CNT		0xb1c
- #define MTK_WED_RTQM_IGRS0_I2H_DMAD_CNT(_n)		(0xb20 + (_n) * 0x4)
- #define	MTK_WED_RTQM_IGRS0_I2HW_PKT_CNT			0xb28
-@@ -691,6 +755,9 @@ struct mtk_wdma_desc {
- #define MTK_WED_WPDMA_INT_CTRL_RRO_PG2_CLR		BIT(17)
- #define MTK_WED_WPDMA_INT_CTRL_RRO_PG2_DONE_TRIG	GENMASK(22, 18)
- 
-+#define MTK_WED_RRO_RX_HW_STS				0xf00
-+#define MTK_WED_RX_IND_CMD_BUSY			GENMASK(31, 0)
-+
- #define MTK_WED_RX_IND_CMD_CNT0				0xf20
- #define MTK_WED_RX_IND_CMD_DBG_CNT_EN			BIT(31)
- 
-diff --git a/include/linux/soc/mediatek/mtk_wed.h b/include/linux/soc/mediatek/mtk_wed.h
-index 92df4ba..1438692 100644
---- a/include/linux/soc/mediatek/mtk_wed.h
-+++ b/include/linux/soc/mediatek/mtk_wed.h
-@@ -240,7 +240,7 @@ struct mtk_wed_ops {
- 	void (*irq_set_mask)(struct mtk_wed_device *dev, u32 mask);
- 	void (*ppe_check)(struct mtk_wed_device *dev, struct sk_buff *skb,
- 			  u32 reason, u32 hash);
--	void (*start_hwrro)(struct mtk_wed_device *dev, u32 irq_mask);
-+	void (*start_hwrro)(struct mtk_wed_device *dev, u32 irq_mask, bool reset);
- };
- 
- extern const struct mtk_wed_ops __rcu *mtk_soc_wed_ops;
-@@ -317,8 +317,8 @@ mtk_wed_device_support_pao(struct mtk_wed_device *dev)
- 	(_dev)->ops->reset_dma(_dev)
- #define mtk_wed_device_ppe_check(_dev, _skb, _reason, _hash) \
- 	(_dev)->ops->ppe_check(_dev, _skb, _reason, _hash)
--#define mtk_wed_device_start_hwrro(_dev, _mask) \
--	(_dev)->ops->start_hwrro(_dev, _mask)
-+#define mtk_wed_device_start_hwrro(_dev, _mask, _reset) \
-+	(_dev)->ops->start_hwrro(_dev, _mask, _reset)
- 
- #else
- static inline bool mtk_wed_device_active(struct mtk_wed_device *dev)
--- 
-2.18.0
-
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/wed3/999-3021-mtk-wed-add-dma-mask-limitation-and-GFP_DMA32-for-bo.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/wed3/999-3021-mtk-wed-add-dma-mask-limitation-and-GFP_DMA32-for-bo.patch
deleted file mode 100644
index af32459..0000000
--- a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/wed3/999-3021-mtk-wed-add-dma-mask-limitation-and-GFP_DMA32-for-bo.patch
+++ /dev/null
@@ -1,105 +0,0 @@
-From 659d8d088ee856cbc7598a26a307fd3e20a70e8e Mon Sep 17 00:00:00 2001
-From: Sujuan Chen <sujuan.chen@mediatek.com>
-Date: Mon, 18 Sep 2023 13:23:56 +0800
-Subject: [PATCH 22/22] mtk: wed: add dma mask limitation and GFP_DMA32 for
- board >= 4GB dram
-
----
- drivers/net/ethernet/mediatek/mtk_wed.c     | 8 ++++++--
- drivers/net/ethernet/mediatek/mtk_wed_mcu.c | 4 ++--
- drivers/net/ethernet/mediatek/mtk_wed_wo.c  | 4 ++--
- drivers/net/ethernet/mediatek/mtk_wed_wo.h  | 1 +
- 4 files changed, 11 insertions(+), 6 deletions(-)
-
-diff --git a/drivers/net/ethernet/mediatek/mtk_wed.c b/drivers/net/ethernet/mediatek/mtk_wed.c
-index 0d101d5..2ec7148 100644
---- a/drivers/net/ethernet/mediatek/mtk_wed.c
-+++ b/drivers/net/ethernet/mediatek/mtk_wed.c
-@@ -472,7 +472,7 @@ mtk_wed_tx_buffer_alloc(struct mtk_wed_device *dev)
- 		void *buf;
- 		int s;
- 
--		page = __dev_alloc_pages(GFP_KERNEL, 0);
-+		page = __dev_alloc_pages(GFP_KERNEL | GFP_DMA32, 0);
- 		if (!page)
- 			return -ENOMEM;
- 
-@@ -636,7 +636,7 @@ mtk_wed_rx_page_buffer_alloc(struct mtk_wed_device *dev)
- 		void *buf;
- 		int s;
- 
--		page = __dev_alloc_pages(GFP_KERNEL, 0);
-+		page = __dev_alloc_pages(GFP_KERNEL | GFP_DMA32, 0);
- 		if (!page)
- 			return -ENOMEM;
- 
-@@ -2249,6 +2249,10 @@ mtk_wed_attach(struct mtk_wed_device *dev)
- 	dev->wdma_idx = hw->index;
- 	dev->ver = hw->version;
- 
-+	ret = dma_set_mask_and_coherent(hw->dev, DMA_BIT_MASK(32));
-+	if (ret)
-+		return ret;
-+
- 	if (dev->hw->version == 3)
- 		dev->hw->pci_base = mtk_wed_get_pci_base(dev);
- 
-diff --git a/drivers/net/ethernet/mediatek/mtk_wed_mcu.c b/drivers/net/ethernet/mediatek/mtk_wed_mcu.c
-index 055594d..4ed1548 100644
---- a/drivers/net/ethernet/mediatek/mtk_wed_mcu.c
-+++ b/drivers/net/ethernet/mediatek/mtk_wed_mcu.c
-@@ -131,7 +131,7 @@ int mtk_wed_exception_init(struct mtk_wed_wo *wo)
- 	}req;
- 
- 	exp->log_size = EXCEPTION_LOG_SIZE;
--	exp->log = kmalloc(exp->log_size, GFP_ATOMIC);
-+	exp->log = page_frag_alloc(&wo->page, exp->log_size, GFP_ATOMIC | GFP_DMA32);
- 	if (!exp->log)
- 		return -ENOMEM;
- 
-@@ -151,7 +151,7 @@ int mtk_wed_exception_init(struct mtk_wed_wo *wo)
- 				    &req, sizeof(req), false);
- 
- free:
--	kfree(exp->log);
-+	skb_free_frag(exp->log);
- 	return -ENOMEM;
- }
- 
-diff --git a/drivers/net/ethernet/mediatek/mtk_wed_wo.c b/drivers/net/ethernet/mediatek/mtk_wed_wo.c
-index 54b7787..e991d20 100644
---- a/drivers/net/ethernet/mediatek/mtk_wed_wo.c
-+++ b/drivers/net/ethernet/mediatek/mtk_wed_wo.c
-@@ -88,7 +88,7 @@ woif_q_rx_fill(struct mtk_wed_wo *wo, struct wed_wo_queue *q, bool rx)
- 		page = &q->rx_page;
- 
- 	while (q->queued < q->ndesc) {
--		buf = page_frag_alloc(page, len, GFP_ATOMIC);
-+		buf = page_frag_alloc(page, len, GFP_ATOMIC | GFP_DMA32);
- 		if (!buf)
- 			break;
- 
-@@ -555,7 +555,7 @@ void mtk_wed_wo_exit(struct mtk_wed_hw *hw)
- 
- 	if (wo->exp.log) {
- 		dma_unmap_single(wo->hw->dev, wo->exp.phys, wo->exp.log_size, DMA_FROM_DEVICE);
--		kfree(wo->exp.log);
-+		skb_free_frag(wo->exp.log);
- 	}
- 
- 	wo->hw = NULL;
-diff --git a/drivers/net/ethernet/mediatek/mtk_wed_wo.h b/drivers/net/ethernet/mediatek/mtk_wed_wo.h
-index 548b38e..3fd1f3f 100644
---- a/drivers/net/ethernet/mediatek/mtk_wed_wo.h
-+++ b/drivers/net/ethernet/mediatek/mtk_wed_wo.h
-@@ -193,6 +193,7 @@ struct mtk_wed_wo {
- 	const struct wed_wo_drv_ops *drv_ops;
- 	const struct wed_wo_mcu_ops *mcu_ops;
- 	const struct wed_wo_queue_ops *queue_ops;
-+	struct page_frag_cache page;
- 
- 	struct net_device napi_dev;
- 	spinlock_t rx_lock;
--- 
-2.18.0
-
diff --git a/recipes-kernel/linux/linux-mediatek_5.4.bb b/recipes-kernel/linux/linux-mediatek_5.4.bb
index 2c688d4..a6e6a07 100644
--- a/recipes-kernel/linux/linux-mediatek_5.4.bb
+++ b/recipes-kernel/linux/linux-mediatek_5.4.bb
@@ -103,9 +103,9 @@
             patch -p1 < ${WORKDIR}/999-2737-net-mt753x-phy-coverity-scan.patch
             patch -p1 < ${WORKDIR}/999-1710-v6.2-net-phy-add-phylink-pcs-support.patch
             patch -p1 < ${WORKDIR}/999-1712-v6.2-net-phy-add-phylink-rate-matching-support.patch
-            patch -p1 < ${WORKDIR}/999-2702-v5.9-net-phy-add-support-for-a-common-probe-between-shared-PHYs.patch
             patch -p1 < ${WORKDIR}/999-2725-iwconfig-wireless-rate-fix.patch
             patch -p1 < ${WORKDIR}/999-2729-net-phy-remove-reporting-line-rate-to-mac.patch
+            patch -p1 < ${WORKDIR}/999-2739-drivers_net_ethernet_mediatek_hnat.patch
             if [ $DISTRO_secure_boot_ENABLED = 'true' ]; then
                 patch -p1 < ${WORKDIR}/0404-mtdsplit-dm-verity.patch
                 patch -p1 < ${WORKDIR}/0800-dm-verity-redo-hash-for-safexel-sha256.patch
@@ -124,14 +124,6 @@
         fi
 }
 
-do_filogic_patches_append_mt7988() {
-    if [ ! -e wed3_patch_applied ]; then
-        if [ $DISTRO_FlowBlock_ENABLED = 'true' ]; then
-                for i in ${WORKDIR}/mediatek/wed3/*.patch; do patch -p1 < $i; done
-        fi
-        touch wed3_patch_applied
-    fi
-}
 addtask filogic_patches after do_patch before do_compile
 
 KERNEL_MODULE_AUTOLOAD += "${@bb.utils.contains('DISTRO_FEATURES','logan','mtkhnat nf_flow_table_hw','',d)}"