zte's code,first commit

Change-Id: I9a04da59e459a9bc0d67f101f700d9d7dc8d681b
diff --git a/ap/os/linux/linux-3.4.x/drivers/net/phy/Kconfig b/ap/os/linux/linux-3.4.x/drivers/net/phy/Kconfig
new file mode 100644
index 0000000..6f0a635
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/net/phy/Kconfig
@@ -0,0 +1,146 @@
+#
+# PHY Layer Configuration
+#
+
+menuconfig PHYLIB
+	tristate "PHY Device support and infrastructure"
+	depends on !S390
+	depends on NETDEVICES
+	help
+	  Ethernet controllers are usually attached to PHY
+	  devices.  This option provides infrastructure for
+	  managing PHY devices.
+
+if PHYLIB
+
+comment "MII PHY device drivers"
+
+config AMD_PHY
+	tristate "Drivers for the AMD PHYs"
+	---help---
+	  Currently supports the am79c874
+
+config MARVELL_PHY
+	tristate "Drivers for Marvell PHYs"
+	---help---
+	  Currently has a driver for the 88E1011S
+	
+config DAVICOM_PHY
+	tristate "Drivers for Davicom PHYs"
+	---help---
+	  Currently supports dm9161e and dm9131
+
+config QSEMI_PHY
+	tristate "Drivers for Quality Semiconductor PHYs"
+	---help---
+	  Currently supports the qs6612
+
+config LXT_PHY
+	tristate "Drivers for the Intel LXT PHYs"
+	---help---
+	  Currently supports the lxt970, lxt971
+
+config CICADA_PHY
+	tristate "Drivers for the Cicada PHYs"
+	---help---
+	  Currently supports the cis8204
+
+config VITESSE_PHY
+        tristate "Drivers for the Vitesse PHYs"
+        ---help---
+          Currently supports the vsc8244
+
+config SMSC_PHY
+	tristate "Drivers for SMSC PHYs"
+	---help---
+	  Currently supports the LAN83C185, LAN8187 and LAN8700 PHYs
+
+config BROADCOM_PHY
+	tristate "Drivers for Broadcom PHYs"
+	---help---
+	  Currently supports the BCM5411, BCM5421, BCM5461, BCM5464, BCM5481
+	  and BCM5482 PHYs.
+
+config BCM63XX_PHY
+	tristate "Drivers for Broadcom 63xx SOCs internal PHY"
+	depends on BCM63XX
+	---help---
+	  Currently supports the 6348 and 6358 PHYs.
+
+config ICPLUS_PHY
+	tristate "Drivers for ICPlus PHYs"
+	---help---
+	  Currently supports the IP175C and IP1001 PHYs.
+
+config REALTEK_PHY
+	tristate "Drivers for Realtek PHYs"
+	---help---
+	  Supports the Realtek 821x PHY.
+
+config NATIONAL_PHY
+	tristate "Drivers for National Semiconductor PHYs"
+	---help---
+	  Currently supports the DP83865 PHY.
+
+config STE10XP
+	tristate "Driver for STMicroelectronics STe10Xp PHYs"
+	---help---
+	  This is the driver for the STe100p and STe101p PHYs.
+
+config LSI_ET1011C_PHY
+	tristate "Driver for LSI ET1011C PHY"
+	---help---
+	  Supports the LSI ET1011C PHY.
+
+config MICREL_PHY
+	tristate "Driver for Micrel PHYs"
+	---help---
+	  Supports the KSZ9021, VSC8201, KS8001 PHYs.
+
+config FIXED_PHY
+	bool "Driver for MDIO Bus/PHY emulation with fixed speed/link PHYs"
+	depends on PHYLIB=y
+	---help---
+	  Adds the platform "fixed" MDIO Bus to cover the boards that use
+	  PHYs that are not connected to the real MDIO bus.
+
+	  Currently tested with mpc866ads and mpc8349e-mitx.
+
+config MDIO_BITBANG
+	tristate "Support for bitbanged MDIO buses"
+	help
+	  This module implements the MDIO bus protocol in software,
+	  for use by low level drivers that export the ability to
+	  drive the relevant pins.
+
+	  If in doubt, say N.
+
+config MDIO_GPIO
+	tristate "Support for GPIO lib-based bitbanged MDIO buses"
+	depends on MDIO_BITBANG && GENERIC_GPIO
+	---help---
+	  Supports GPIO lib-based MDIO busses.
+
+	  To compile this driver as a module, choose M here: the module
+	  will be called mdio-gpio.
+
+config MDIO_OCTEON
+	tristate "Support for MDIO buses on Octeon SOCs"
+	depends on  CPU_CAVIUM_OCTEON
+	default y
+	help
+
+	  This module provides a driver for the Octeon MDIO busses.
+	  It is required by the Octeon Ethernet device drivers.
+
+	  If in doubt, say Y.
+
+endif # PHYLIB
+
+config MICREL_KS8995MA
+	tristate "Micrel KS8995MA 5-ports 10/100 managed Ethernet switch"
+	depends on SPI
+
+source "drivers/net/phy/icplus/Kconfig"
+source "drivers/net/phy/realtek/Kconfig"
+
diff --git a/ap/os/linux/linux-3.4.x/drivers/net/phy/Makefile b/ap/os/linux/linux-3.4.x/drivers/net/phy/Makefile
new file mode 100644
index 0000000..a940953
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/net/phy/Makefile
@@ -0,0 +1,27 @@
+# Makefile for Linux PHY drivers
+
+libphy-objs			:= phy.o phy_device.o mdio_bus.o
+
+obj-$(CONFIG_PHYLIB)		+= libphy.o
+obj-$(CONFIG_MARVELL_PHY)	+= marvell.o
+obj-$(CONFIG_DAVICOM_PHY)	+= davicom.o
+obj-$(CONFIG_CICADA_PHY)	+= cicada.o
+obj-$(CONFIG_LXT_PHY)		+= lxt.o
+obj-$(CONFIG_QSEMI_PHY)		+= qsemi.o
+obj-$(CONFIG_SMSC_PHY)		+= smsc.o
+obj-$(CONFIG_VITESSE_PHY)	+= vitesse.o
+obj-$(CONFIG_BROADCOM_PHY)	+= broadcom.o
+obj-$(CONFIG_BCM63XX_PHY)	+= bcm63xx.o
+obj-$(CONFIG_ICPLUS_PHY)	+= icplus/
+obj-$(CONFIG_REALTEK_PHY)	+= realtek/
+obj-$(CONFIG_LSI_ET1011C_PHY)	+= et1011c.o
+obj-$(CONFIG_FIXED_PHY)		+= fixed.o
+obj-$(CONFIG_MDIO_BITBANG)	+= mdio-bitbang.o
+obj-$(CONFIG_MDIO_GPIO)		+= mdio-gpio.o
+obj-$(CONFIG_NATIONAL_PHY)	+= national.o
+obj-$(CONFIG_DP83640_PHY)	+= dp83640.o
+obj-$(CONFIG_STE10XP)		+= ste10Xp.o
+obj-$(CONFIG_MICREL_PHY)	+= micrel.o
+obj-$(CONFIG_MDIO_OCTEON)	+= mdio-octeon.o
+obj-$(CONFIG_MICREL_KS8995MA)	+= spi_ks8995.o
+obj-$(CONFIG_AMD_PHY)		+= amd.o
diff --git a/ap/os/linux/linux-3.4.x/drivers/net/phy/amd.c b/ap/os/linux/linux-3.4.x/drivers/net/phy/amd.c
new file mode 100644
index 0000000..cfabd5f
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/net/phy/amd.c
@@ -0,0 +1,102 @@
+/*
+ * Driver for AMD am79c PHYs
+ *
+ * Author: Heiko Schocher <hs@denx.de>
+ *
+ * Copyright (c) 2011 DENX Software Engineering GmbH
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ *
+ */
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/mii.h>
+#include <linux/phy.h>
+
+#define PHY_ID_AM79C874		0x0022561b
+
+#define MII_AM79C_IR		17	/* Interrupt Status/Control Register */
+#define MII_AM79C_IR_EN_LINK	0x0400	/* IR enable Linkstate */
+#define MII_AM79C_IR_EN_ANEG	0x0100	/* IR enable Aneg Complete */
+#define MII_AM79C_IR_IMASK_INIT	(MII_AM79C_IR_EN_LINK | MII_AM79C_IR_EN_ANEG)
+
+MODULE_DESCRIPTION("AMD PHY driver");
+MODULE_AUTHOR("Heiko Schocher <hs@denx.de>");
+MODULE_LICENSE("GPL");
+
+static int am79c_ack_interrupt(struct phy_device *phydev)
+{
+	int err;
+
+	err = phy_read(phydev, MII_BMSR);
+	if (err < 0)
+		return err;
+
+	err = phy_read(phydev, MII_AM79C_IR);
+	if (err < 0)
+		return err;
+
+	return 0;
+}
+
+static int am79c_config_init(struct phy_device *phydev)
+{
+	return 0;
+}
+
+static int am79c_config_intr(struct phy_device *phydev)
+{
+	int err;
+
+	if (phydev->interrupts == PHY_INTERRUPT_ENABLED)
+		err = phy_write(phydev, MII_AM79C_IR, MII_AM79C_IR_IMASK_INIT);
+	else
+		err = phy_write(phydev, MII_AM79C_IR, 0);
+
+	return err;
+}
+
+static struct phy_driver am79c_driver = {
+	.phy_id		= PHY_ID_AM79C874,
+	.name		= "AM79C874",
+	.phy_id_mask	= 0xfffffff0,
+	.features	= PHY_BASIC_FEATURES,
+	.flags		= PHY_HAS_INTERRUPT,
+	.config_init	= am79c_config_init,
+	.config_aneg	= genphy_config_aneg,
+	.read_status	= genphy_read_status,
+	.ack_interrupt	= am79c_ack_interrupt,
+	.config_intr	= am79c_config_intr,
+	.driver		= { .owner = THIS_MODULE,},
+};
+
+static int __init am79c_init(void)
+{
+	int ret;
+
+	ret = phy_driver_register(&am79c_driver);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+static void __exit am79c_exit(void)
+{
+	phy_driver_unregister(&am79c_driver);
+}
+
+module_init(am79c_init);
+module_exit(am79c_exit);
+
+static struct mdio_device_id __maybe_unused amd_tbl[] = {
+	{ PHY_ID_AM79C874, 0xfffffff0 },
+	{ }
+};
+
+MODULE_DEVICE_TABLE(mdio, amd_tbl);
diff --git a/ap/os/linux/linux-3.4.x/drivers/net/phy/bcm63xx.c b/ap/os/linux/linux-3.4.x/drivers/net/phy/bcm63xx.c
new file mode 100644
index 0000000..e16f98c
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/net/phy/bcm63xx.c
@@ -0,0 +1,140 @@
+/*
+ *	Driver for Broadcom 63xx SOCs integrated PHYs
+ *
+ *	This program is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU General Public License
+ *	as published by the Free Software Foundation; either version
+ *	2 of the License, or (at your option) any later version.
+ */
+#include <linux/module.h>
+#include <linux/phy.h>
+
+#define MII_BCM63XX_IR		0x1a	/* interrupt register */
+#define MII_BCM63XX_IR_EN	0x4000	/* global interrupt enable */
+#define MII_BCM63XX_IR_DUPLEX	0x0800	/* duplex changed */
+#define MII_BCM63XX_IR_SPEED	0x0400	/* speed changed */
+#define MII_BCM63XX_IR_LINK	0x0200	/* link changed */
+#define MII_BCM63XX_IR_GMASK	0x0100	/* global interrupt mask */
+
+MODULE_DESCRIPTION("Broadcom 63xx internal PHY driver");
+MODULE_AUTHOR("Maxime Bizon <mbizon@freebox.fr>");
+MODULE_LICENSE("GPL");
+
+static int bcm63xx_config_init(struct phy_device *phydev)
+{
+	int reg, err;
+
+	reg = phy_read(phydev, MII_BCM63XX_IR);
+	if (reg < 0)
+		return reg;
+
+	/* Mask interrupts globally.  */
+	reg |= MII_BCM63XX_IR_GMASK;
+	err = phy_write(phydev, MII_BCM63XX_IR, reg);
+	if (err < 0)
+		return err;
+
+	/* Unmask events we are interested in  */
+	reg = ~(MII_BCM63XX_IR_DUPLEX |
+		MII_BCM63XX_IR_SPEED |
+		MII_BCM63XX_IR_LINK) |
+		MII_BCM63XX_IR_EN;
+	err = phy_write(phydev, MII_BCM63XX_IR, reg);
+	if (err < 0)
+		return err;
+	return 0;
+}
+
+static int bcm63xx_ack_interrupt(struct phy_device *phydev)
+{
+	int reg;
+
+	/* Clear pending interrupts.  */
+	reg = phy_read(phydev, MII_BCM63XX_IR);
+	if (reg < 0)
+		return reg;
+
+	return 0;
+}
+
+static int bcm63xx_config_intr(struct phy_device *phydev)
+{
+	int reg, err;
+
+	reg = phy_read(phydev, MII_BCM63XX_IR);
+	if (reg < 0)
+		return reg;
+
+	if (phydev->interrupts == PHY_INTERRUPT_ENABLED)
+		reg &= ~MII_BCM63XX_IR_GMASK;
+	else
+		reg |= MII_BCM63XX_IR_GMASK;
+
+	err = phy_write(phydev, MII_BCM63XX_IR, reg);
+	return err;
+}
+
+static struct phy_driver bcm63xx_1_driver = {
+	.phy_id		= 0x00406000,
+	.phy_id_mask	= 0xfffffc00,
+	.name		= "Broadcom BCM63XX (1)",
+	/* ASYM_PAUSE bit is marked RO in datasheet, so don't cheat */
+	.features	= (PHY_BASIC_FEATURES | SUPPORTED_Pause),
+	.flags		= PHY_HAS_INTERRUPT,
+	.config_init	= bcm63xx_config_init,
+	.config_aneg	= genphy_config_aneg,
+	.read_status	= genphy_read_status,
+	.ack_interrupt	= bcm63xx_ack_interrupt,
+	.config_intr	= bcm63xx_config_intr,
+	.driver		= { .owner = THIS_MODULE },
+};
+
+/* same phy as above, with just a different OUI */
+static struct phy_driver bcm63xx_2_driver = {
+	.phy_id		= 0x002bdc00,
+	.phy_id_mask	= 0xfffffc00,
+	.name		= "Broadcom BCM63XX (2)",
+	.features	= (PHY_BASIC_FEATURES | SUPPORTED_Pause),
+	.flags		= PHY_HAS_INTERRUPT,
+	.config_init	= bcm63xx_config_init,
+	.config_aneg	= genphy_config_aneg,
+	.read_status	= genphy_read_status,
+	.ack_interrupt	= bcm63xx_ack_interrupt,
+	.config_intr	= bcm63xx_config_intr,
+	.driver		= { .owner = THIS_MODULE },
+};
+
+static int __init bcm63xx_phy_init(void)
+{
+	int ret;
+
+	ret = phy_driver_register(&bcm63xx_1_driver);
+	if (ret)
+		goto out_63xx_1;
+	ret = phy_driver_register(&bcm63xx_2_driver);
+	if (ret)
+		goto out_63xx_2;
+	return ret;
+
+out_63xx_2:
+	phy_driver_unregister(&bcm63xx_1_driver);
+out_63xx_1:
+	return ret;
+}
+
+static void __exit bcm63xx_phy_exit(void)
+{
+	phy_driver_unregister(&bcm63xx_1_driver);
+	phy_driver_unregister(&bcm63xx_2_driver);
+}
+
+module_init(bcm63xx_phy_init);
+module_exit(bcm63xx_phy_exit);
+
+static struct mdio_device_id __maybe_unused bcm63xx_tbl[] = {
+	{ 0x00406000, 0xfffffc00 },
+	{ 0x002bdc00, 0xfffffc00 },
+	{ }
+};
+
+MODULE_DEVICE_TABLE(mdio, bcm63xx_tbl);
diff --git a/ap/os/linux/linux-3.4.x/drivers/net/phy/broadcom.c b/ap/os/linux/linux-3.4.x/drivers/net/phy/broadcom.c
new file mode 100644
index 0000000..60338ff
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/net/phy/broadcom.c
@@ -0,0 +1,946 @@
+/*
+ *	drivers/net/phy/broadcom.c
+ *
+ *	Broadcom BCM5411, BCM5421 and BCM5461 Gigabit Ethernet
+ *	transceivers.
+ *
+ *	Copyright (c) 2006  Maciej W. Rozycki
+ *
+ *	Inspired by code written by Amy Fong.
+ *
+ *	This program is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU General Public License
+ *	as published by the Free Software Foundation; either version
+ *	2 of the License, or (at your option) any later version.
+ */
+
+#include <linux/module.h>
+#include <linux/phy.h>
+#include <linux/brcmphy.h>
+
+
+#define BRCM_PHY_MODEL(phydev) \
+	((phydev)->drv->phy_id & (phydev)->drv->phy_id_mask)
+
+#define BRCM_PHY_REV(phydev) \
+	((phydev)->drv->phy_id & ~((phydev)->drv->phy_id_mask))
+
+
+#define MII_BCM54XX_ECR		0x10	/* BCM54xx extended control register */
+#define MII_BCM54XX_ECR_IM	0x1000	/* Interrupt mask */
+#define MII_BCM54XX_ECR_IF	0x0800	/* Interrupt force */
+
+#define MII_BCM54XX_ESR		0x11	/* BCM54xx extended status register */
+#define MII_BCM54XX_ESR_IS	0x1000	/* Interrupt status */
+
+#define MII_BCM54XX_EXP_DATA	0x15	/* Expansion register data */
+#define MII_BCM54XX_EXP_SEL	0x17	/* Expansion register select */
+#define MII_BCM54XX_EXP_SEL_SSD	0x0e00	/* Secondary SerDes select */
+#define MII_BCM54XX_EXP_SEL_ER	0x0f00	/* Expansion register select */
+
+#define MII_BCM54XX_AUX_CTL	0x18	/* Auxiliary control register */
+#define MII_BCM54XX_ISR		0x1a	/* BCM54xx interrupt status register */
+#define MII_BCM54XX_IMR		0x1b	/* BCM54xx interrupt mask register */
+#define MII_BCM54XX_INT_CRCERR	0x0001	/* CRC error */
+#define MII_BCM54XX_INT_LINK	0x0002	/* Link status changed */
+#define MII_BCM54XX_INT_SPEED	0x0004	/* Link speed change */
+#define MII_BCM54XX_INT_DUPLEX	0x0008	/* Duplex mode changed */
+#define MII_BCM54XX_INT_LRS	0x0010	/* Local receiver status changed */
+#define MII_BCM54XX_INT_RRS	0x0020	/* Remote receiver status changed */
+#define MII_BCM54XX_INT_SSERR	0x0040	/* Scrambler synchronization error */
+#define MII_BCM54XX_INT_UHCD	0x0080	/* Unsupported HCD negotiated */
+#define MII_BCM54XX_INT_NHCD	0x0100	/* No HCD */
+#define MII_BCM54XX_INT_NHCDL	0x0200	/* No HCD link */
+#define MII_BCM54XX_INT_ANPR	0x0400	/* Auto-negotiation page received */
+#define MII_BCM54XX_INT_LC	0x0800	/* All counters below 128 */
+#define MII_BCM54XX_INT_HC	0x1000	/* Counter above 32768 */
+#define MII_BCM54XX_INT_MDIX	0x2000	/* MDIX status change */
+#define MII_BCM54XX_INT_PSERR	0x4000	/* Pair swap error */
+
+#define MII_BCM54XX_SHD		0x1c	/* 0x1c shadow registers */
+#define MII_BCM54XX_SHD_WRITE	0x8000
+#define MII_BCM54XX_SHD_VAL(x)	((x & 0x1f) << 10)
+#define MII_BCM54XX_SHD_DATA(x)	((x & 0x3ff) << 0)
+
+/*
+ * AUXILIARY CONTROL SHADOW ACCESS REGISTERS.  (PHY REG 0x18)
+ */
+#define MII_BCM54XX_AUXCTL_SHDWSEL_AUXCTL	0x0000
+#define MII_BCM54XX_AUXCTL_ACTL_TX_6DB		0x0400
+#define MII_BCM54XX_AUXCTL_ACTL_SMDSP_ENA	0x0800
+
+#define MII_BCM54XX_AUXCTL_MISC_WREN	0x8000
+#define MII_BCM54XX_AUXCTL_MISC_FORCE_AMDIX	0x0200
+#define MII_BCM54XX_AUXCTL_MISC_RDSEL_MISC	0x7000
+#define MII_BCM54XX_AUXCTL_SHDWSEL_MISC	0x0007
+
+#define MII_BCM54XX_AUXCTL_SHDWSEL_AUXCTL	0x0000
+
+
+/*
+ * Broadcom LED source encodings.  These are used in BCM5461, BCM5481,
+ * BCM5482, and possibly some others.
+ */
+#define BCM_LED_SRC_LINKSPD1	0x0
+#define BCM_LED_SRC_LINKSPD2	0x1
+#define BCM_LED_SRC_XMITLED	0x2
+#define BCM_LED_SRC_ACTIVITYLED	0x3
+#define BCM_LED_SRC_FDXLED	0x4
+#define BCM_LED_SRC_SLAVE	0x5
+#define BCM_LED_SRC_INTR	0x6
+#define BCM_LED_SRC_QUALITY	0x7
+#define BCM_LED_SRC_RCVLED	0x8
+#define BCM_LED_SRC_MULTICOLOR1	0xa
+#define BCM_LED_SRC_OPENSHORT	0xb
+#define BCM_LED_SRC_OFF		0xe	/* Tied high */
+#define BCM_LED_SRC_ON		0xf	/* Tied low */
+
+
+/*
+ * BCM5482: Shadow registers
+ * Shadow values go into bits [14:10] of register 0x1c to select a shadow
+ * register to access.
+ */
+/* 00101: Spare Control Register 3 */
+#define BCM54XX_SHD_SCR3		0x05
+#define  BCM54XX_SHD_SCR3_DEF_CLK125	0x0001
+#define  BCM54XX_SHD_SCR3_DLLAPD_DIS	0x0002
+#define  BCM54XX_SHD_SCR3_TRDDAPD	0x0004
+
+/* 01010: Auto Power-Down */
+#define BCM54XX_SHD_APD			0x0a
+#define  BCM54XX_SHD_APD_EN		0x0020
+
+#define BCM5482_SHD_LEDS1	0x0d	/* 01101: LED Selector 1 */
+					/* LED3 / ~LINKSPD[2] selector */
+#define BCM5482_SHD_LEDS1_LED3(src)	((src & 0xf) << 4)
+					/* LED1 / ~LINKSPD[1] selector */
+#define BCM5482_SHD_LEDS1_LED1(src)	((src & 0xf) << 0)
+#define BCM54XX_SHD_RGMII_MODE	0x0b	/* 01011: RGMII Mode Selector */
+#define BCM5482_SHD_SSD		0x14	/* 10100: Secondary SerDes control */
+#define BCM5482_SHD_SSD_LEDM	0x0008	/* SSD LED Mode enable */
+#define BCM5482_SHD_SSD_EN	0x0001	/* SSD enable */
+#define BCM5482_SHD_MODE	0x1f	/* 11111: Mode Control Register */
+#define BCM5482_SHD_MODE_1000BX	0x0001	/* Enable 1000BASE-X registers */
+
+
+/*
+ * EXPANSION SHADOW ACCESS REGISTERS.  (PHY REG 0x15, 0x16, and 0x17)
+ */
+#define MII_BCM54XX_EXP_AADJ1CH0		0x001f
+#define  MII_BCM54XX_EXP_AADJ1CH0_SWP_ABCD_OEN	0x0200
+#define  MII_BCM54XX_EXP_AADJ1CH0_SWSEL_THPF	0x0100
+#define MII_BCM54XX_EXP_AADJ1CH3		0x601f
+#define  MII_BCM54XX_EXP_AADJ1CH3_ADCCKADJ	0x0002
+#define MII_BCM54XX_EXP_EXP08			0x0F08
+#define  MII_BCM54XX_EXP_EXP08_RJCT_2MHZ	0x0001
+#define  MII_BCM54XX_EXP_EXP08_EARLY_DAC_WAKE	0x0200
+#define MII_BCM54XX_EXP_EXP75			0x0f75
+#define  MII_BCM54XX_EXP_EXP75_VDACCTRL		0x003c
+#define  MII_BCM54XX_EXP_EXP75_CM_OSC		0x0001
+#define MII_BCM54XX_EXP_EXP96			0x0f96
+#define  MII_BCM54XX_EXP_EXP96_MYST		0x0010
+#define MII_BCM54XX_EXP_EXP97			0x0f97
+#define  MII_BCM54XX_EXP_EXP97_MYST		0x0c0c
+
+/*
+ * BCM5482: Secondary SerDes registers
+ */
+#define BCM5482_SSD_1000BX_CTL		0x00	/* 1000BASE-X Control */
+#define BCM5482_SSD_1000BX_CTL_PWRDOWN	0x0800	/* Power-down SSD */
+#define BCM5482_SSD_SGMII_SLAVE		0x15	/* SGMII Slave Register */
+#define BCM5482_SSD_SGMII_SLAVE_EN	0x0002	/* Slave mode enable */
+#define BCM5482_SSD_SGMII_SLAVE_AD	0x0001	/* Slave auto-detection */
+
+
+/*****************************************************************************/
+/* Fast Ethernet Transceiver definitions. */
+/*****************************************************************************/
+
+#define MII_BRCM_FET_INTREG		0x1a	/* Interrupt register */
+#define MII_BRCM_FET_IR_MASK		0x0100	/* Mask all interrupts */
+#define MII_BRCM_FET_IR_LINK_EN		0x0200	/* Link status change enable */
+#define MII_BRCM_FET_IR_SPEED_EN	0x0400	/* Link speed change enable */
+#define MII_BRCM_FET_IR_DUPLEX_EN	0x0800	/* Duplex mode change enable */
+#define MII_BRCM_FET_IR_ENABLE		0x4000	/* Interrupt enable */
+
+#define MII_BRCM_FET_BRCMTEST		0x1f	/* Brcm test register */
+#define MII_BRCM_FET_BT_SRE		0x0080	/* Shadow register enable */
+
+
+/*** Shadow register definitions ***/
+
+#define MII_BRCM_FET_SHDW_MISCCTRL	0x10	/* Shadow misc ctrl */
+#define MII_BRCM_FET_SHDW_MC_FAME	0x4000	/* Force Auto MDIX enable */
+
+#define MII_BRCM_FET_SHDW_AUXMODE4	0x1a	/* Auxiliary mode 4 */
+#define MII_BRCM_FET_SHDW_AM4_LED_MASK	0x0003
+#define MII_BRCM_FET_SHDW_AM4_LED_MODE1 0x0001
+
+#define MII_BRCM_FET_SHDW_AUXSTAT2	0x1b	/* Auxiliary status 2 */
+#define MII_BRCM_FET_SHDW_AS2_APDE	0x0020	/* Auto power down enable */
+
+
+MODULE_DESCRIPTION("Broadcom PHY driver");
+MODULE_AUTHOR("Maciej W. Rozycki");
+MODULE_LICENSE("GPL");
+
+/*
+ * Indirect register access functions for the 1000BASE-T/100BASE-TX/10BASE-T
+ * 0x1c shadow registers.
+ */
+static int bcm54xx_shadow_read(struct phy_device *phydev, u16 shadow)
+{
+	phy_write(phydev, MII_BCM54XX_SHD, MII_BCM54XX_SHD_VAL(shadow));
+	return MII_BCM54XX_SHD_DATA(phy_read(phydev, MII_BCM54XX_SHD));
+}
+
+static int bcm54xx_shadow_write(struct phy_device *phydev, u16 shadow, u16 val)
+{
+	return phy_write(phydev, MII_BCM54XX_SHD,
+			 MII_BCM54XX_SHD_WRITE |
+			 MII_BCM54XX_SHD_VAL(shadow) |
+			 MII_BCM54XX_SHD_DATA(val));
+}
+
+/* Indirect register access functions for the Expansion Registers */
+static int bcm54xx_exp_read(struct phy_device *phydev, u16 regnum)
+{
+	int val;
+
+	val = phy_write(phydev, MII_BCM54XX_EXP_SEL, regnum);
+	if (val < 0)
+		return val;
+
+	val = phy_read(phydev, MII_BCM54XX_EXP_DATA);
+
+	/* Restore default value.  It's O.K. if this write fails. */
+	phy_write(phydev, MII_BCM54XX_EXP_SEL, 0);
+
+	return val;
+}
+
+static int bcm54xx_exp_write(struct phy_device *phydev, u16 regnum, u16 val)
+{
+	int ret;
+
+	ret = phy_write(phydev, MII_BCM54XX_EXP_SEL, regnum);
+	if (ret < 0)
+		return ret;
+
+	ret = phy_write(phydev, MII_BCM54XX_EXP_DATA, val);
+
+	/* Restore default value.  It's O.K. if this write fails. */
+	phy_write(phydev, MII_BCM54XX_EXP_SEL, 0);
+
+	return ret;
+}
+
+static int bcm54xx_auxctl_write(struct phy_device *phydev, u16 regnum, u16 val)
+{
+	return phy_write(phydev, MII_BCM54XX_AUX_CTL, regnum | val);
+}
+
+/* Needs SMDSP clock enabled via bcm54xx_phydsp_config() */
+static int bcm50610_a0_workaround(struct phy_device *phydev)
+{
+	int err;
+
+	err = bcm54xx_exp_write(phydev, MII_BCM54XX_EXP_AADJ1CH0,
+				MII_BCM54XX_EXP_AADJ1CH0_SWP_ABCD_OEN |
+				MII_BCM54XX_EXP_AADJ1CH0_SWSEL_THPF);
+	if (err < 0)
+		return err;
+
+	err = bcm54xx_exp_write(phydev, MII_BCM54XX_EXP_AADJ1CH3,
+					MII_BCM54XX_EXP_AADJ1CH3_ADCCKADJ);
+	if (err < 0)
+		return err;
+
+	err = bcm54xx_exp_write(phydev, MII_BCM54XX_EXP_EXP75,
+				MII_BCM54XX_EXP_EXP75_VDACCTRL);
+	if (err < 0)
+		return err;
+
+	err = bcm54xx_exp_write(phydev, MII_BCM54XX_EXP_EXP96,
+				MII_BCM54XX_EXP_EXP96_MYST);
+	if (err < 0)
+		return err;
+
+	err = bcm54xx_exp_write(phydev, MII_BCM54XX_EXP_EXP97,
+				MII_BCM54XX_EXP_EXP97_MYST);
+
+	return err;
+}
+
+static int bcm54xx_phydsp_config(struct phy_device *phydev)
+{
+	int err, err2;
+
+	/* Enable the SMDSP clock */
+	err = bcm54xx_auxctl_write(phydev,
+				   MII_BCM54XX_AUXCTL_SHDWSEL_AUXCTL,
+				   MII_BCM54XX_AUXCTL_ACTL_SMDSP_ENA |
+				   MII_BCM54XX_AUXCTL_ACTL_TX_6DB);
+	if (err < 0)
+		return err;
+
+	if (BRCM_PHY_MODEL(phydev) == PHY_ID_BCM50610 ||
+	    BRCM_PHY_MODEL(phydev) == PHY_ID_BCM50610M) {
+		/* Clear bit 9 to fix a phy interop issue. */
+		err = bcm54xx_exp_write(phydev, MII_BCM54XX_EXP_EXP08,
+					MII_BCM54XX_EXP_EXP08_RJCT_2MHZ);
+		if (err < 0)
+			goto error;
+
+		if (phydev->drv->phy_id == PHY_ID_BCM50610) {
+			err = bcm50610_a0_workaround(phydev);
+			if (err < 0)
+				goto error;
+		}
+	}
+
+	if (BRCM_PHY_MODEL(phydev) == PHY_ID_BCM57780) {
+		int val;
+
+		val = bcm54xx_exp_read(phydev, MII_BCM54XX_EXP_EXP75);
+		if (val < 0)
+			goto error;
+
+		val |= MII_BCM54XX_EXP_EXP75_CM_OSC;
+		err = bcm54xx_exp_write(phydev, MII_BCM54XX_EXP_EXP75, val);
+	}
+
+error:
+	/* Disable the SMDSP clock */
+	err2 = bcm54xx_auxctl_write(phydev,
+				    MII_BCM54XX_AUXCTL_SHDWSEL_AUXCTL,
+				    MII_BCM54XX_AUXCTL_ACTL_TX_6DB);
+
+	/* Return the first error reported. */
+	return err ? err : err2;
+}
+
+static void bcm54xx_adjust_rxrefclk(struct phy_device *phydev)
+{
+	u32 orig;
+	int val;
+	bool clk125en = true;
+
+	/* Abort if we are using an untested phy. */
+	if (BRCM_PHY_MODEL(phydev) != PHY_ID_BCM57780 &&
+	    BRCM_PHY_MODEL(phydev) != PHY_ID_BCM50610 &&
+	    BRCM_PHY_MODEL(phydev) != PHY_ID_BCM50610M)
+		return;
+
+	val = bcm54xx_shadow_read(phydev, BCM54XX_SHD_SCR3);
+	if (val < 0)
+		return;
+
+	orig = val;
+
+	if ((BRCM_PHY_MODEL(phydev) == PHY_ID_BCM50610 ||
+	     BRCM_PHY_MODEL(phydev) == PHY_ID_BCM50610M) &&
+	    BRCM_PHY_REV(phydev) >= 0x3) {
+		/*
+		 * Here, bit 0 _disables_ CLK125 when set.
+		 * This bit is set by default.
+		 */
+		clk125en = false;
+	} else {
+		if (phydev->dev_flags & PHY_BRCM_RX_REFCLK_UNUSED) {
+			/* Here, bit 0 _enables_ CLK125 when set */
+			val &= ~BCM54XX_SHD_SCR3_DEF_CLK125;
+			clk125en = false;
+		}
+	}
+
+	if (!clk125en || (phydev->dev_flags & PHY_BRCM_AUTO_PWRDWN_ENABLE))
+		val &= ~BCM54XX_SHD_SCR3_DLLAPD_DIS;
+	else
+		val |= BCM54XX_SHD_SCR3_DLLAPD_DIS;
+
+	if (phydev->dev_flags & PHY_BRCM_DIS_TXCRXC_NOENRGY)
+		val |= BCM54XX_SHD_SCR3_TRDDAPD;
+
+	if (orig != val)
+		bcm54xx_shadow_write(phydev, BCM54XX_SHD_SCR3, val);
+
+	val = bcm54xx_shadow_read(phydev, BCM54XX_SHD_APD);
+	if (val < 0)
+		return;
+
+	orig = val;
+
+	if (!clk125en || (phydev->dev_flags & PHY_BRCM_AUTO_PWRDWN_ENABLE))
+		val |= BCM54XX_SHD_APD_EN;
+	else
+		val &= ~BCM54XX_SHD_APD_EN;
+
+	if (orig != val)
+		bcm54xx_shadow_write(phydev, BCM54XX_SHD_APD, val);
+}
+
+static int bcm54xx_config_init(struct phy_device *phydev)
+{
+	int reg, err;
+
+	reg = phy_read(phydev, MII_BCM54XX_ECR);
+	if (reg < 0)
+		return reg;
+
+	/* Mask interrupts globally.  */
+	reg |= MII_BCM54XX_ECR_IM;
+	err = phy_write(phydev, MII_BCM54XX_ECR, reg);
+	if (err < 0)
+		return err;
+
+	/* Unmask events we are interested in.  */
+	reg = ~(MII_BCM54XX_INT_DUPLEX |
+		MII_BCM54XX_INT_SPEED |
+		MII_BCM54XX_INT_LINK);
+	err = phy_write(phydev, MII_BCM54XX_IMR, reg);
+	if (err < 0)
+		return err;
+
+	if ((BRCM_PHY_MODEL(phydev) == PHY_ID_BCM50610 ||
+	     BRCM_PHY_MODEL(phydev) == PHY_ID_BCM50610M) &&
+	    (phydev->dev_flags & PHY_BRCM_CLEAR_RGMII_MODE))
+		bcm54xx_shadow_write(phydev, BCM54XX_SHD_RGMII_MODE, 0);
+
+	if ((phydev->dev_flags & PHY_BRCM_RX_REFCLK_UNUSED) ||
+	    (phydev->dev_flags & PHY_BRCM_DIS_TXCRXC_NOENRGY) ||
+	    (phydev->dev_flags & PHY_BRCM_AUTO_PWRDWN_ENABLE))
+		bcm54xx_adjust_rxrefclk(phydev);
+
+	bcm54xx_phydsp_config(phydev);
+
+	return 0;
+}
+
+static int bcm5482_config_init(struct phy_device *phydev)
+{
+	int err, reg;
+
+	err = bcm54xx_config_init(phydev);
+
+	if (phydev->dev_flags & PHY_BCM_FLAGS_MODE_1000BX) {
+		/*
+		 * Enable secondary SerDes and its use as an LED source
+		 */
+		reg = bcm54xx_shadow_read(phydev, BCM5482_SHD_SSD);
+		bcm54xx_shadow_write(phydev, BCM5482_SHD_SSD,
+				     reg |
+				     BCM5482_SHD_SSD_LEDM |
+				     BCM5482_SHD_SSD_EN);
+
+		/*
+		 * Enable SGMII slave mode and auto-detection
+		 */
+		reg = BCM5482_SSD_SGMII_SLAVE | MII_BCM54XX_EXP_SEL_SSD;
+		err = bcm54xx_exp_read(phydev, reg);
+		if (err < 0)
+			return err;
+		err = bcm54xx_exp_write(phydev, reg, err |
+					BCM5482_SSD_SGMII_SLAVE_EN |
+					BCM5482_SSD_SGMII_SLAVE_AD);
+		if (err < 0)
+			return err;
+
+		/*
+		 * Disable secondary SerDes powerdown
+		 */
+		reg = BCM5482_SSD_1000BX_CTL | MII_BCM54XX_EXP_SEL_SSD;
+		err = bcm54xx_exp_read(phydev, reg);
+		if (err < 0)
+			return err;
+		err = bcm54xx_exp_write(phydev, reg,
+					err & ~BCM5482_SSD_1000BX_CTL_PWRDOWN);
+		if (err < 0)
+			return err;
+
+		/*
+		 * Select 1000BASE-X register set (primary SerDes)
+		 */
+		reg = bcm54xx_shadow_read(phydev, BCM5482_SHD_MODE);
+		bcm54xx_shadow_write(phydev, BCM5482_SHD_MODE,
+				     reg | BCM5482_SHD_MODE_1000BX);
+
+		/*
+		 * LED1=ACTIVITYLED, LED3=LINKSPD[2]
+		 * (Use LED1 as secondary SerDes ACTIVITY LED)
+		 */
+		bcm54xx_shadow_write(phydev, BCM5482_SHD_LEDS1,
+			BCM5482_SHD_LEDS1_LED1(BCM_LED_SRC_ACTIVITYLED) |
+			BCM5482_SHD_LEDS1_LED3(BCM_LED_SRC_LINKSPD2));
+
+		/*
+		 * Auto-negotiation doesn't seem to work quite right
+		 * in this mode, so we disable it and force it to the
+		 * right speed/duplex setting.  Only 'link status'
+		 * is important.
+		 */
+		phydev->autoneg = AUTONEG_DISABLE;
+		phydev->speed = SPEED_1000;
+		phydev->duplex = DUPLEX_FULL;
+	}
+
+	return err;
+}
+
+static int bcm5482_read_status(struct phy_device *phydev)
+{
+	int err;
+
+	err = genphy_read_status(phydev);
+
+	if (phydev->dev_flags & PHY_BCM_FLAGS_MODE_1000BX) {
+		/*
+		 * Only link status matters for 1000Base-X mode, so force
+		 * 1000 Mbit/s full-duplex status
+		 */
+		if (phydev->link) {
+			phydev->speed = SPEED_1000;
+			phydev->duplex = DUPLEX_FULL;
+		}
+	}
+
+	return err;
+}
+
+static int bcm54xx_ack_interrupt(struct phy_device *phydev)
+{
+	int reg;
+
+	/* Clear pending interrupts.  */
+	reg = phy_read(phydev, MII_BCM54XX_ISR);
+	if (reg < 0)
+		return reg;
+
+	return 0;
+}
+
+static int bcm54xx_config_intr(struct phy_device *phydev)
+{
+	int reg, err;
+
+	reg = phy_read(phydev, MII_BCM54XX_ECR);
+	if (reg < 0)
+		return reg;
+
+	if (phydev->interrupts == PHY_INTERRUPT_ENABLED)
+		reg &= ~MII_BCM54XX_ECR_IM;
+	else
+		reg |= MII_BCM54XX_ECR_IM;
+
+	err = phy_write(phydev, MII_BCM54XX_ECR, reg);
+	return err;
+}
+
+static int bcm5481_config_aneg(struct phy_device *phydev)
+{
+	int ret;
+
+	/* Aneg firsly. */
+	ret = genphy_config_aneg(phydev);
+
+	/* Then we can set up the delay. */
+	if (phydev->interface == PHY_INTERFACE_MODE_RGMII_RXID) {
+		u16 reg;
+
+		/*
+		 * There is no BCM5481 specification available, so down
+		 * here is everything we know about "register 0x18". This
+		 * at least helps BCM5481 to successfully receive packets
+		 * on MPC8360E-RDK board. Peter Barada <peterb@logicpd.com>
+		 * says: "This sets delay between the RXD and RXC signals
+		 * instead of using trace lengths to achieve timing".
+		 */
+
+		/* Set RDX clk delay. */
+		reg = 0x7 | (0x7 << 12);
+		phy_write(phydev, 0x18, reg);
+
+		reg = phy_read(phydev, 0x18);
+		/* Set RDX-RXC skew. */
+		reg |= (1 << 8);
+		/* Write bits 14:0. */
+		reg |= (1 << 15);
+		phy_write(phydev, 0x18, reg);
+	}
+
+	return ret;
+}
+
+static int brcm_phy_setbits(struct phy_device *phydev, int reg, int set)
+{
+	int val;
+
+	val = phy_read(phydev, reg);
+	if (val < 0)
+		return val;
+
+	return phy_write(phydev, reg, val | set);
+}
+
+static int brcm_fet_config_init(struct phy_device *phydev)
+{
+	int reg, err, err2, brcmtest;
+
+	/* Reset the PHY to bring it to a known state. */
+	err = phy_write(phydev, MII_BMCR, BMCR_RESET);
+	if (err < 0)
+		return err;
+
+	reg = phy_read(phydev, MII_BRCM_FET_INTREG);
+	if (reg < 0)
+		return reg;
+
+	/* Unmask events we are interested in and mask interrupts globally. */
+	reg = MII_BRCM_FET_IR_DUPLEX_EN |
+	      MII_BRCM_FET_IR_SPEED_EN |
+	      MII_BRCM_FET_IR_LINK_EN |
+	      MII_BRCM_FET_IR_ENABLE |
+	      MII_BRCM_FET_IR_MASK;
+
+	err = phy_write(phydev, MII_BRCM_FET_INTREG, reg);
+	if (err < 0)
+		return err;
+
+	/* Enable shadow register access */
+	brcmtest = phy_read(phydev, MII_BRCM_FET_BRCMTEST);
+	if (brcmtest < 0)
+		return brcmtest;
+
+	reg = brcmtest | MII_BRCM_FET_BT_SRE;
+
+	err = phy_write(phydev, MII_BRCM_FET_BRCMTEST, reg);
+	if (err < 0)
+		return err;
+
+	/* Set the LED mode */
+	reg = phy_read(phydev, MII_BRCM_FET_SHDW_AUXMODE4);
+	if (reg < 0) {
+		err = reg;
+		goto done;
+	}
+
+	reg &= ~MII_BRCM_FET_SHDW_AM4_LED_MASK;
+	reg |= MII_BRCM_FET_SHDW_AM4_LED_MODE1;
+
+	err = phy_write(phydev, MII_BRCM_FET_SHDW_AUXMODE4, reg);
+	if (err < 0)
+		goto done;
+
+	/* Enable auto MDIX */
+	err = brcm_phy_setbits(phydev, MII_BRCM_FET_SHDW_MISCCTRL,
+				       MII_BRCM_FET_SHDW_MC_FAME);
+	if (err < 0)
+		goto done;
+
+	if (phydev->dev_flags & PHY_BRCM_AUTO_PWRDWN_ENABLE) {
+		/* Enable auto power down */
+		err = brcm_phy_setbits(phydev, MII_BRCM_FET_SHDW_AUXSTAT2,
+					       MII_BRCM_FET_SHDW_AS2_APDE);
+	}
+
+done:
+	/* Disable shadow register access */
+	err2 = phy_write(phydev, MII_BRCM_FET_BRCMTEST, brcmtest);
+	if (!err)
+		err = err2;
+
+	return err;
+}
+
+static int brcm_fet_ack_interrupt(struct phy_device *phydev)
+{
+	int reg;
+
+	/* Clear pending interrupts.  */
+	reg = phy_read(phydev, MII_BRCM_FET_INTREG);
+	if (reg < 0)
+		return reg;
+
+	return 0;
+}
+
+static int brcm_fet_config_intr(struct phy_device *phydev)
+{
+	int reg, err;
+
+	reg = phy_read(phydev, MII_BRCM_FET_INTREG);
+	if (reg < 0)
+		return reg;
+
+	if (phydev->interrupts == PHY_INTERRUPT_ENABLED)
+		reg &= ~MII_BRCM_FET_IR_MASK;
+	else
+		reg |= MII_BRCM_FET_IR_MASK;
+
+	err = phy_write(phydev, MII_BRCM_FET_INTREG, reg);
+	return err;
+}
+
+static struct phy_driver bcm5411_driver = {
+	.phy_id		= PHY_ID_BCM5411,
+	.phy_id_mask	= 0xfffffff0,
+	.name		= "Broadcom BCM5411",
+	.features	= PHY_GBIT_FEATURES |
+			  SUPPORTED_Pause | SUPPORTED_Asym_Pause,
+	.flags		= PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT,
+	.config_init	= bcm54xx_config_init,
+	.config_aneg	= genphy_config_aneg,
+	.read_status	= genphy_read_status,
+	.ack_interrupt	= bcm54xx_ack_interrupt,
+	.config_intr	= bcm54xx_config_intr,
+	.driver		= { .owner = THIS_MODULE },
+};
+
+static struct phy_driver bcm5421_driver = {
+	.phy_id		= PHY_ID_BCM5421,
+	.phy_id_mask	= 0xfffffff0,
+	.name		= "Broadcom BCM5421",
+	.features	= PHY_GBIT_FEATURES |
+			  SUPPORTED_Pause | SUPPORTED_Asym_Pause,
+	.flags		= PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT,
+	.config_init	= bcm54xx_config_init,
+	.config_aneg	= genphy_config_aneg,
+	.read_status	= genphy_read_status,
+	.ack_interrupt	= bcm54xx_ack_interrupt,
+	.config_intr	= bcm54xx_config_intr,
+	.driver		= { .owner = THIS_MODULE },
+};
+
+static struct phy_driver bcm5461_driver = {
+	.phy_id		= PHY_ID_BCM5461,
+	.phy_id_mask	= 0xfffffff0,
+	.name		= "Broadcom BCM5461",
+	.features	= PHY_GBIT_FEATURES |
+			  SUPPORTED_Pause | SUPPORTED_Asym_Pause,
+	.flags		= PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT,
+	.config_init	= bcm54xx_config_init,
+	.config_aneg	= genphy_config_aneg,
+	.read_status	= genphy_read_status,
+	.ack_interrupt	= bcm54xx_ack_interrupt,
+	.config_intr	= bcm54xx_config_intr,
+	.driver		= { .owner = THIS_MODULE },
+};
+
+static struct phy_driver bcm5464_driver = {
+	.phy_id		= PHY_ID_BCM5464,
+	.phy_id_mask	= 0xfffffff0,
+	.name		= "Broadcom BCM5464",
+	.features	= PHY_GBIT_FEATURES |
+			  SUPPORTED_Pause | SUPPORTED_Asym_Pause,
+	.flags		= PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT,
+	.config_init	= bcm54xx_config_init,
+	.config_aneg	= genphy_config_aneg,
+	.read_status	= genphy_read_status,
+	.ack_interrupt	= bcm54xx_ack_interrupt,
+	.config_intr	= bcm54xx_config_intr,
+	.driver		= { .owner = THIS_MODULE },
+};
+
+static struct phy_driver bcm5481_driver = {
+	.phy_id		= PHY_ID_BCM5481,
+	.phy_id_mask	= 0xfffffff0,
+	.name		= "Broadcom BCM5481",
+	.features	= PHY_GBIT_FEATURES |
+			  SUPPORTED_Pause | SUPPORTED_Asym_Pause,
+	.flags		= PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT,
+	.config_init	= bcm54xx_config_init,
+	.config_aneg	= bcm5481_config_aneg,
+	.read_status	= genphy_read_status,
+	.ack_interrupt	= bcm54xx_ack_interrupt,
+	.config_intr	= bcm54xx_config_intr,
+	.driver		= { .owner = THIS_MODULE },
+};
+
+static struct phy_driver bcm5482_driver = {
+	.phy_id		= PHY_ID_BCM5482,
+	.phy_id_mask	= 0xfffffff0,
+	.name		= "Broadcom BCM5482",
+	.features	= PHY_GBIT_FEATURES |
+			  SUPPORTED_Pause | SUPPORTED_Asym_Pause,
+	.flags		= PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT,
+	.config_init	= bcm5482_config_init,
+	.config_aneg	= genphy_config_aneg,
+	.read_status	= bcm5482_read_status,
+	.ack_interrupt	= bcm54xx_ack_interrupt,
+	.config_intr	= bcm54xx_config_intr,
+	.driver		= { .owner = THIS_MODULE },
+};
+
+static struct phy_driver bcm50610_driver = {
+	.phy_id		= PHY_ID_BCM50610,
+	.phy_id_mask	= 0xfffffff0,
+	.name		= "Broadcom BCM50610",
+	.features	= PHY_GBIT_FEATURES |
+			  SUPPORTED_Pause | SUPPORTED_Asym_Pause,
+	.flags		= PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT,
+	.config_init	= bcm54xx_config_init,
+	.config_aneg	= genphy_config_aneg,
+	.read_status	= genphy_read_status,
+	.ack_interrupt	= bcm54xx_ack_interrupt,
+	.config_intr	= bcm54xx_config_intr,
+	.driver		= { .owner = THIS_MODULE },
+};
+
+static struct phy_driver bcm50610m_driver = {
+	.phy_id		= PHY_ID_BCM50610M,
+	.phy_id_mask	= 0xfffffff0,
+	.name		= "Broadcom BCM50610M",
+	.features	= PHY_GBIT_FEATURES |
+			  SUPPORTED_Pause | SUPPORTED_Asym_Pause,
+	.flags		= PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT,
+	.config_init	= bcm54xx_config_init,
+	.config_aneg	= genphy_config_aneg,
+	.read_status	= genphy_read_status,
+	.ack_interrupt	= bcm54xx_ack_interrupt,
+	.config_intr	= bcm54xx_config_intr,
+	.driver		= { .owner = THIS_MODULE },
+};
+
+static struct phy_driver bcm57780_driver = {
+	.phy_id		= PHY_ID_BCM57780,
+	.phy_id_mask	= 0xfffffff0,
+	.name		= "Broadcom BCM57780",
+	.features	= PHY_GBIT_FEATURES |
+			  SUPPORTED_Pause | SUPPORTED_Asym_Pause,
+	.flags		= PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT,
+	.config_init	= bcm54xx_config_init,
+	.config_aneg	= genphy_config_aneg,
+	.read_status	= genphy_read_status,
+	.ack_interrupt	= bcm54xx_ack_interrupt,
+	.config_intr	= bcm54xx_config_intr,
+	.driver		= { .owner = THIS_MODULE },
+};
+
+static struct phy_driver bcmac131_driver = {
+	.phy_id		= PHY_ID_BCMAC131,
+	.phy_id_mask	= 0xfffffff0,
+	.name		= "Broadcom BCMAC131",
+	.features	= PHY_BASIC_FEATURES |
+			  SUPPORTED_Pause | SUPPORTED_Asym_Pause,
+	.flags		= PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT,
+	.config_init	= brcm_fet_config_init,
+	.config_aneg	= genphy_config_aneg,
+	.read_status	= genphy_read_status,
+	.ack_interrupt	= brcm_fet_ack_interrupt,
+	.config_intr	= brcm_fet_config_intr,
+	.driver		= { .owner = THIS_MODULE },
+};
+
+static struct phy_driver bcm5241_driver = {
+	.phy_id		= PHY_ID_BCM5241,
+	.phy_id_mask	= 0xfffffff0,
+	.name		= "Broadcom BCM5241",
+	.features	= PHY_BASIC_FEATURES |
+			  SUPPORTED_Pause | SUPPORTED_Asym_Pause,
+	.flags		= PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT,
+	.config_init	= brcm_fet_config_init,
+	.config_aneg	= genphy_config_aneg,
+	.read_status	= genphy_read_status,
+	.ack_interrupt	= brcm_fet_ack_interrupt,
+	.config_intr	= brcm_fet_config_intr,
+	.driver		= { .owner = THIS_MODULE },
+};
+
+static int __init broadcom_init(void)
+{
+	int ret;
+
+	ret = phy_driver_register(&bcm5411_driver);
+	if (ret)
+		goto out_5411;
+	ret = phy_driver_register(&bcm5421_driver);
+	if (ret)
+		goto out_5421;
+	ret = phy_driver_register(&bcm5461_driver);
+	if (ret)
+		goto out_5461;
+	ret = phy_driver_register(&bcm5464_driver);
+	if (ret)
+		goto out_5464;
+	ret = phy_driver_register(&bcm5481_driver);
+	if (ret)
+		goto out_5481;
+	ret = phy_driver_register(&bcm5482_driver);
+	if (ret)
+		goto out_5482;
+	ret = phy_driver_register(&bcm50610_driver);
+	if (ret)
+		goto out_50610;
+	ret = phy_driver_register(&bcm50610m_driver);
+	if (ret)
+		goto out_50610m;
+	ret = phy_driver_register(&bcm57780_driver);
+	if (ret)
+		goto out_57780;
+	ret = phy_driver_register(&bcmac131_driver);
+	if (ret)
+		goto out_ac131;
+	ret = phy_driver_register(&bcm5241_driver);
+	if (ret)
+		goto out_5241;
+	return ret;
+
+out_5241:
+	phy_driver_unregister(&bcmac131_driver);
+out_ac131:
+	phy_driver_unregister(&bcm57780_driver);
+out_57780:
+	phy_driver_unregister(&bcm50610m_driver);
+out_50610m:
+	phy_driver_unregister(&bcm50610_driver);
+out_50610:
+	phy_driver_unregister(&bcm5482_driver);
+out_5482:
+	phy_driver_unregister(&bcm5481_driver);
+out_5481:
+	phy_driver_unregister(&bcm5464_driver);
+out_5464:
+	phy_driver_unregister(&bcm5461_driver);
+out_5461:
+	phy_driver_unregister(&bcm5421_driver);
+out_5421:
+	phy_driver_unregister(&bcm5411_driver);
+out_5411:
+	return ret;
+}
+
+static void __exit broadcom_exit(void)
+{
+	phy_driver_unregister(&bcm5241_driver);
+	phy_driver_unregister(&bcmac131_driver);
+	phy_driver_unregister(&bcm57780_driver);
+	phy_driver_unregister(&bcm50610m_driver);
+	phy_driver_unregister(&bcm50610_driver);
+	phy_driver_unregister(&bcm5482_driver);
+	phy_driver_unregister(&bcm5481_driver);
+	phy_driver_unregister(&bcm5464_driver);
+	phy_driver_unregister(&bcm5461_driver);
+	phy_driver_unregister(&bcm5421_driver);
+	phy_driver_unregister(&bcm5411_driver);
+}
+
+module_init(broadcom_init);
+module_exit(broadcom_exit);
+
+static struct mdio_device_id __maybe_unused broadcom_tbl[] = {
+	{ PHY_ID_BCM5411, 0xfffffff0 },
+	{ PHY_ID_BCM5421, 0xfffffff0 },
+	{ PHY_ID_BCM5461, 0xfffffff0 },
+	{ PHY_ID_BCM5464, 0xfffffff0 },
+	{ PHY_ID_BCM5482, 0xfffffff0 },
+	{ PHY_ID_BCM5482, 0xfffffff0 },
+	{ PHY_ID_BCM50610, 0xfffffff0 },
+	{ PHY_ID_BCM50610M, 0xfffffff0 },
+	{ PHY_ID_BCM57780, 0xfffffff0 },
+	{ PHY_ID_BCMAC131, 0xfffffff0 },
+	{ PHY_ID_BCM5241, 0xfffffff0 },
+	{ }
+};
+
+MODULE_DEVICE_TABLE(mdio, broadcom_tbl);
diff --git a/ap/os/linux/linux-3.4.x/drivers/net/phy/cicada.c b/ap/os/linux/linux-3.4.x/drivers/net/phy/cicada.c
new file mode 100644
index 0000000..d281731
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/net/phy/cicada.c
@@ -0,0 +1,168 @@
+/*
+ * drivers/net/phy/cicada.c
+ *
+ * Driver for Cicada PHYs
+ *
+ * Author: Andy Fleming
+ *
+ * Copyright (c) 2004 Freescale Semiconductor, Inc.
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ *
+ */
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/errno.h>
+#include <linux/unistd.h>
+#include <linux/interrupt.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+#include <linux/spinlock.h>
+#include <linux/mm.h>
+#include <linux/module.h>
+#include <linux/mii.h>
+#include <linux/ethtool.h>
+#include <linux/phy.h>
+
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/uaccess.h>
+
+/* Cicada Extended Control Register 1 */
+#define MII_CIS8201_EXT_CON1           0x17
+#define MII_CIS8201_EXTCON1_INIT       0x0000
+
+/* Cicada Interrupt Mask Register */
+#define MII_CIS8201_IMASK		0x19
+#define MII_CIS8201_IMASK_IEN		0x8000
+#define MII_CIS8201_IMASK_SPEED	0x4000
+#define MII_CIS8201_IMASK_LINK		0x2000
+#define MII_CIS8201_IMASK_DUPLEX	0x1000
+#define MII_CIS8201_IMASK_MASK		0xf000
+
+/* Cicada Interrupt Status Register */
+#define MII_CIS8201_ISTAT		0x1a
+#define MII_CIS8201_ISTAT_STATUS	0x8000
+#define MII_CIS8201_ISTAT_SPEED	0x4000
+#define MII_CIS8201_ISTAT_LINK		0x2000
+#define MII_CIS8201_ISTAT_DUPLEX	0x1000
+
+/* Cicada Auxiliary Control/Status Register */
+#define MII_CIS8201_AUX_CONSTAT        0x1c
+#define MII_CIS8201_AUXCONSTAT_INIT    0x0004
+#define MII_CIS8201_AUXCONSTAT_DUPLEX  0x0020
+#define MII_CIS8201_AUXCONSTAT_SPEED   0x0018
+#define MII_CIS8201_AUXCONSTAT_GBIT    0x0010
+#define MII_CIS8201_AUXCONSTAT_100     0x0008
+
+MODULE_DESCRIPTION("Cicadia PHY driver");
+MODULE_AUTHOR("Andy Fleming");
+MODULE_LICENSE("GPL");
+
+static int cis820x_config_init(struct phy_device *phydev)
+{
+	int err;
+
+	err = phy_write(phydev, MII_CIS8201_AUX_CONSTAT,
+			MII_CIS8201_AUXCONSTAT_INIT);
+
+	if (err < 0)
+		return err;
+
+	err = phy_write(phydev, MII_CIS8201_EXT_CON1,
+			MII_CIS8201_EXTCON1_INIT);
+
+	return err;
+}
+
+static int cis820x_ack_interrupt(struct phy_device *phydev)
+{
+	int err = phy_read(phydev, MII_CIS8201_ISTAT);
+
+	return (err < 0) ? err : 0;
+}
+
+static int cis820x_config_intr(struct phy_device *phydev)
+{
+	int err;
+
+	if(phydev->interrupts == PHY_INTERRUPT_ENABLED)
+		err = phy_write(phydev, MII_CIS8201_IMASK, 
+				MII_CIS8201_IMASK_MASK);
+	else
+		err = phy_write(phydev, MII_CIS8201_IMASK, 0);
+
+	return err;
+}
+
+/* Cicada 8201, a.k.a Vitesse VSC8201 */
+static struct phy_driver cis8201_driver = {
+	.phy_id		= 0x000fc410,
+	.name		= "Cicada Cis8201",
+	.phy_id_mask	= 0x000ffff0,
+	.features	= PHY_GBIT_FEATURES,
+	.flags		= PHY_HAS_INTERRUPT,
+	.config_init	= &cis820x_config_init,
+	.config_aneg	= &genphy_config_aneg,
+	.read_status	= &genphy_read_status,
+	.ack_interrupt	= &cis820x_ack_interrupt,
+	.config_intr	= &cis820x_config_intr,
+	.driver 	= { .owner = THIS_MODULE,},
+};
+
+/* Cicada 8204 */
+static struct phy_driver cis8204_driver = {
+	.phy_id		= 0x000fc440,
+	.name		= "Cicada Cis8204",
+	.phy_id_mask	= 0x000fffc0,
+	.features	= PHY_GBIT_FEATURES,
+	.flags		= PHY_HAS_INTERRUPT,
+	.config_init	= &cis820x_config_init,
+	.config_aneg	= &genphy_config_aneg,
+	.read_status	= &genphy_read_status,
+	.ack_interrupt	= &cis820x_ack_interrupt,
+	.config_intr	= &cis820x_config_intr,
+	.driver 	= { .owner = THIS_MODULE,},
+};
+
+static int __init cicada_init(void)
+{
+	int ret;
+
+	ret = phy_driver_register(&cis8204_driver);
+	if (ret)
+		goto err1;
+
+	ret = phy_driver_register(&cis8201_driver);
+	if (ret)
+		goto err2;
+	return 0;
+
+err2:
+	phy_driver_unregister(&cis8204_driver);
+err1:
+	return ret;
+}
+
+static void __exit cicada_exit(void)
+{
+	phy_driver_unregister(&cis8204_driver);
+	phy_driver_unregister(&cis8201_driver);
+}
+
+module_init(cicada_init);
+module_exit(cicada_exit);
+
+static struct mdio_device_id __maybe_unused cicada_tbl[] = {
+	{ 0x000fc410, 0x000ffff0 },
+	{ 0x000fc440, 0x000fffc0 },
+	{ }
+};
+
+MODULE_DEVICE_TABLE(mdio, cicada_tbl);
diff --git a/ap/os/linux/linux-3.4.x/drivers/net/phy/davicom.c b/ap/os/linux/linux-3.4.x/drivers/net/phy/davicom.c
new file mode 100644
index 0000000..2f774ac
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/net/phy/davicom.c
@@ -0,0 +1,229 @@
+/*
+ * drivers/net/phy/davicom.c
+ *
+ * Driver for Davicom PHYs
+ *
+ * Author: Andy Fleming
+ *
+ * Copyright (c) 2004 Freescale Semiconductor, Inc.
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ *
+ */
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/errno.h>
+#include <linux/unistd.h>
+#include <linux/interrupt.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+#include <linux/spinlock.h>
+#include <linux/mm.h>
+#include <linux/module.h>
+#include <linux/mii.h>
+#include <linux/ethtool.h>
+#include <linux/phy.h>
+
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/uaccess.h>
+
+#define MII_DM9161_SCR		0x10
+#define MII_DM9161_SCR_INIT	0x0610
+#define MII_DM9161_SCR_RMII	0x0100
+
+/* DM9161 Interrupt Register */
+#define MII_DM9161_INTR	0x15
+#define MII_DM9161_INTR_PEND		0x8000
+#define MII_DM9161_INTR_DPLX_MASK	0x0800
+#define MII_DM9161_INTR_SPD_MASK	0x0400
+#define MII_DM9161_INTR_LINK_MASK	0x0200
+#define MII_DM9161_INTR_MASK		0x0100
+#define MII_DM9161_INTR_DPLX_CHANGE	0x0010
+#define MII_DM9161_INTR_SPD_CHANGE	0x0008
+#define MII_DM9161_INTR_LINK_CHANGE	0x0004
+#define MII_DM9161_INTR_INIT 		0x0000
+#define MII_DM9161_INTR_STOP	\
+(MII_DM9161_INTR_DPLX_MASK | MII_DM9161_INTR_SPD_MASK \
+ | MII_DM9161_INTR_LINK_MASK | MII_DM9161_INTR_MASK)
+
+/* DM9161 10BT Configuration/Status */
+#define MII_DM9161_10BTCSR	0x12
+#define MII_DM9161_10BTCSR_INIT	0x7800
+
+MODULE_DESCRIPTION("Davicom PHY driver");
+MODULE_AUTHOR("Andy Fleming");
+MODULE_LICENSE("GPL");
+
+
+#define DM9161_DELAY 1
+static int dm9161_config_intr(struct phy_device *phydev)
+{
+	int temp;
+
+	temp = phy_read(phydev, MII_DM9161_INTR);
+
+	if (temp < 0)
+		return temp;
+
+	if(PHY_INTERRUPT_ENABLED == phydev->interrupts )
+		temp &= ~(MII_DM9161_INTR_STOP);
+	else
+		temp |= MII_DM9161_INTR_STOP;
+
+	temp = phy_write(phydev, MII_DM9161_INTR, temp);
+
+	return temp;
+}
+
+static int dm9161_config_aneg(struct phy_device *phydev)
+{
+	int err;
+
+	/* Isolate the PHY */
+	err = phy_write(phydev, MII_BMCR, BMCR_ISOLATE);
+
+	if (err < 0)
+		return err;
+
+	/* Configure the new settings */
+	err = genphy_config_aneg(phydev);
+
+	if (err < 0)
+		return err;
+
+	return 0;
+}
+
+static int dm9161_config_init(struct phy_device *phydev)
+{
+	int err, temp;
+
+	/* Isolate the PHY */
+	err = phy_write(phydev, MII_BMCR, BMCR_ISOLATE);
+
+	if (err < 0)
+		return err;
+
+	switch (phydev->interface) {
+	case PHY_INTERFACE_MODE_MII:
+		temp = MII_DM9161_SCR_INIT;
+		break;
+	case PHY_INTERFACE_MODE_RMII:
+		temp =  MII_DM9161_SCR_INIT | MII_DM9161_SCR_RMII;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	/* Do not bypass the scrambler/descrambler */
+	err = phy_write(phydev, MII_DM9161_SCR, temp);
+	if (err < 0)
+		return err;
+
+	/* Clear 10BTCSR to default */
+	err = phy_write(phydev, MII_DM9161_10BTCSR, MII_DM9161_10BTCSR_INIT);
+
+	if (err < 0)
+		return err;
+
+	/* Reconnect the PHY, and enable Autonegotiation */
+	err = phy_write(phydev, MII_BMCR, BMCR_ANENABLE);
+
+	if (err < 0)
+		return err;
+
+	return 0;
+}
+
+static int dm9161_ack_interrupt(struct phy_device *phydev)
+{
+	int err = phy_read(phydev, MII_DM9161_INTR);
+
+	return (err < 0) ? err : 0;
+}
+
+static struct phy_driver dm9161e_driver = {
+	.phy_id		= 0x0181b880,
+	.name		= "Davicom DM9161E",
+	.phy_id_mask	= 0x0ffffff0,
+	.features	= PHY_BASIC_FEATURES,
+	.config_init	= dm9161_config_init,
+	.config_aneg	= dm9161_config_aneg,
+	.read_status	= genphy_read_status,
+	.driver		= { .owner = THIS_MODULE,},
+};
+
+static struct phy_driver dm9161a_driver = {
+	.phy_id		= 0x0181b8a0,
+	.name		= "Davicom DM9161A",
+	.phy_id_mask	= 0x0ffffff0,
+	.features	= PHY_BASIC_FEATURES,
+	.config_init	= dm9161_config_init,
+	.config_aneg	= dm9161_config_aneg,
+	.read_status	= genphy_read_status,
+	.driver		= { .owner = THIS_MODULE,},
+};
+
+static struct phy_driver dm9131_driver = {
+	.phy_id		= 0x00181b80,
+	.name		= "Davicom DM9131",
+	.phy_id_mask	= 0x0ffffff0,
+	.features	= PHY_BASIC_FEATURES,
+	.flags		= PHY_HAS_INTERRUPT,
+	.config_aneg	= genphy_config_aneg,
+	.read_status	= genphy_read_status,
+	.ack_interrupt	= dm9161_ack_interrupt,
+	.config_intr	= dm9161_config_intr,
+	.driver		= { .owner = THIS_MODULE,},
+};
+
+static int __init davicom_init(void)
+{
+	int ret;
+
+	ret = phy_driver_register(&dm9161e_driver);
+	if (ret)
+		goto err1;
+
+	ret = phy_driver_register(&dm9161a_driver);
+	if (ret)
+		goto err2;
+
+	ret = phy_driver_register(&dm9131_driver);
+	if (ret)
+		goto err3;
+	return 0;
+
+ err3:
+	phy_driver_unregister(&dm9161a_driver);
+ err2:
+	phy_driver_unregister(&dm9161e_driver);
+ err1:
+	return ret;
+}
+
+static void __exit davicom_exit(void)
+{
+	phy_driver_unregister(&dm9161e_driver);
+	phy_driver_unregister(&dm9161a_driver);
+	phy_driver_unregister(&dm9131_driver);
+}
+
+module_init(davicom_init);
+module_exit(davicom_exit);
+
+static struct mdio_device_id __maybe_unused davicom_tbl[] = {
+	{ 0x0181b880, 0x0ffffff0 },
+	{ 0x0181b8a0, 0x0ffffff0 },
+	{ 0x00181b80, 0x0ffffff0 },
+	{ }
+};
+
+MODULE_DEVICE_TABLE(mdio, davicom_tbl);
diff --git a/ap/os/linux/linux-3.4.x/drivers/net/phy/dp83640.c b/ap/os/linux/linux-3.4.x/drivers/net/phy/dp83640.c
new file mode 100644
index 0000000..dd7ae19
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/net/phy/dp83640.c
@@ -0,0 +1,1257 @@
+/*
+ * Driver for the National Semiconductor DP83640 PHYTER
+ *
+ * Copyright (C) 2010 OMICRON electronics GmbH
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+#include <linux/ethtool.h>
+#include <linux/kernel.h>
+#include <linux/list.h>
+#include <linux/mii.h>
+#include <linux/module.h>
+#include <linux/net_tstamp.h>
+#include <linux/netdevice.h>
+#include <linux/phy.h>
+#include <linux/ptp_classify.h>
+#include <linux/ptp_clock_kernel.h>
+
+#include "dp83640_reg.h"
+
+#define DP83640_PHY_ID	0x20005ce1
+#define PAGESEL		0x13
+#define LAYER4		0x02
+#define LAYER2		0x01
+#define MAX_RXTS	64
+#define N_EXT_TS	6
+#define PSF_PTPVER	2
+#define PSF_EVNT	0x4000
+#define PSF_RX		0x2000
+#define PSF_TX		0x1000
+#define EXT_EVENT	1
+#define CAL_EVENT	7
+#define CAL_TRIGGER	7
+#define PER_TRIGGER	6
+
+/* phyter seems to miss the mark by 16 ns */
+#define ADJTIME_FIX	16
+
+#if defined(__BIG_ENDIAN)
+#define ENDIAN_FLAG	0
+#elif defined(__LITTLE_ENDIAN)
+#define ENDIAN_FLAG	PSF_ENDIAN
+#endif
+
+#define SKB_PTP_TYPE(__skb) (*(unsigned int *)((__skb)->cb))
+
+struct phy_rxts {
+	u16 ns_lo;   /* ns[15:0] */
+	u16 ns_hi;   /* overflow[1:0], ns[29:16] */
+	u16 sec_lo;  /* sec[15:0] */
+	u16 sec_hi;  /* sec[31:16] */
+	u16 seqid;   /* sequenceId[15:0] */
+	u16 msgtype; /* messageType[3:0], hash[11:0] */
+};
+
+struct phy_txts {
+	u16 ns_lo;   /* ns[15:0] */
+	u16 ns_hi;   /* overflow[1:0], ns[29:16] */
+	u16 sec_lo;  /* sec[15:0] */
+	u16 sec_hi;  /* sec[31:16] */
+};
+
+struct rxts {
+	struct list_head list;
+	unsigned long tmo;
+	u64 ns;
+	u16 seqid;
+	u8  msgtype;
+	u16 hash;
+};
+
+struct dp83640_clock;
+
+struct dp83640_private {
+	struct list_head list;
+	struct dp83640_clock *clock;
+	struct phy_device *phydev;
+	struct work_struct ts_work;
+	int hwts_tx_en;
+	int hwts_rx_en;
+	int layer;
+	int version;
+	/* remember state of cfg0 during calibration */
+	int cfg0;
+	/* remember the last event time stamp */
+	struct phy_txts edata;
+	/* list of rx timestamps */
+	struct list_head rxts;
+	struct list_head rxpool;
+	struct rxts rx_pool_data[MAX_RXTS];
+	/* protects above three fields from concurrent access */
+	spinlock_t rx_lock;
+	/* queues of incoming and outgoing packets */
+	struct sk_buff_head rx_queue;
+	struct sk_buff_head tx_queue;
+};
+
+struct dp83640_clock {
+	/* keeps the instance in the 'phyter_clocks' list */
+	struct list_head list;
+	/* we create one clock instance per MII bus */
+	struct mii_bus *bus;
+	/* protects extended registers from concurrent access */
+	struct mutex extreg_lock;
+	/* remembers which page was last selected */
+	int page;
+	/* our advertised capabilities */
+	struct ptp_clock_info caps;
+	/* protects the three fields below from concurrent access */
+	struct mutex clock_lock;
+	/* the one phyter from which we shall read */
+	struct dp83640_private *chosen;
+	/* list of the other attached phyters, not chosen */
+	struct list_head phylist;
+	/* reference to our PTP hardware clock */
+	struct ptp_clock *ptp_clock;
+};
+
+/* globals */
+
+enum {
+	CALIBRATE_GPIO,
+	PEROUT_GPIO,
+	EXTTS0_GPIO,
+	EXTTS1_GPIO,
+	EXTTS2_GPIO,
+	EXTTS3_GPIO,
+	EXTTS4_GPIO,
+	EXTTS5_GPIO,
+	GPIO_TABLE_SIZE
+};
+
+static int chosen_phy = -1;
+static ushort gpio_tab[GPIO_TABLE_SIZE] = {
+	1, 2, 3, 4, 8, 9, 10, 11
+};
+
+module_param(chosen_phy, int, 0444);
+module_param_array(gpio_tab, ushort, NULL, 0444);
+
+MODULE_PARM_DESC(chosen_phy, \
+	"The address of the PHY to use for the ancillary clock features");
+MODULE_PARM_DESC(gpio_tab, \
+	"Which GPIO line to use for which purpose: cal,perout,extts1,...,extts6");
+
+/* a list of clocks and a mutex to protect it */
+static LIST_HEAD(phyter_clocks);
+static DEFINE_MUTEX(phyter_clocks_lock);
+
+static void rx_timestamp_work(struct work_struct *work);
+
+/* extended register access functions */
+
+#define BROADCAST_ADDR 31
+
+static inline int broadcast_write(struct mii_bus *bus, u32 regnum, u16 val)
+{
+	return mdiobus_write(bus, BROADCAST_ADDR, regnum, val);
+}
+
+/* Caller must hold extreg_lock. */
+static int ext_read(struct phy_device *phydev, int page, u32 regnum)
+{
+	struct dp83640_private *dp83640 = phydev->priv;
+	int val;
+
+	if (dp83640->clock->page != page) {
+		broadcast_write(phydev->bus, PAGESEL, page);
+		dp83640->clock->page = page;
+	}
+	val = phy_read(phydev, regnum);
+
+	return val;
+}
+
+/* Caller must hold extreg_lock. */
+static void ext_write(int broadcast, struct phy_device *phydev,
+		      int page, u32 regnum, u16 val)
+{
+	struct dp83640_private *dp83640 = phydev->priv;
+
+	if (dp83640->clock->page != page) {
+		broadcast_write(phydev->bus, PAGESEL, page);
+		dp83640->clock->page = page;
+	}
+	if (broadcast)
+		broadcast_write(phydev->bus, regnum, val);
+	else
+		phy_write(phydev, regnum, val);
+}
+
+/* Caller must hold extreg_lock. */
+static int tdr_write(int bc, struct phy_device *dev,
+		     const struct timespec *ts, u16 cmd)
+{
+	ext_write(bc, dev, PAGE4, PTP_TDR, ts->tv_nsec & 0xffff);/* ns[15:0]  */
+	ext_write(bc, dev, PAGE4, PTP_TDR, ts->tv_nsec >> 16);   /* ns[31:16] */
+	ext_write(bc, dev, PAGE4, PTP_TDR, ts->tv_sec & 0xffff); /* sec[15:0] */
+	ext_write(bc, dev, PAGE4, PTP_TDR, ts->tv_sec >> 16);    /* sec[31:16]*/
+
+	ext_write(bc, dev, PAGE4, PTP_CTL, cmd);
+
+	return 0;
+}
+
+/* convert phy timestamps into driver timestamps */
+
+static void phy2rxts(struct phy_rxts *p, struct rxts *rxts)
+{
+	u32 sec;
+
+	sec = p->sec_lo;
+	sec |= p->sec_hi << 16;
+
+	rxts->ns = p->ns_lo;
+	rxts->ns |= (p->ns_hi & 0x3fff) << 16;
+	rxts->ns += ((u64)sec) * 1000000000ULL;
+	rxts->seqid = p->seqid;
+	rxts->msgtype = (p->msgtype >> 12) & 0xf;
+	rxts->hash = p->msgtype & 0x0fff;
+	rxts->tmo = jiffies + 2;
+}
+
+static u64 phy2txts(struct phy_txts *p)
+{
+	u64 ns;
+	u32 sec;
+
+	sec = p->sec_lo;
+	sec |= p->sec_hi << 16;
+
+	ns = p->ns_lo;
+	ns |= (p->ns_hi & 0x3fff) << 16;
+	ns += ((u64)sec) * 1000000000ULL;
+
+	return ns;
+}
+
+static void periodic_output(struct dp83640_clock *clock,
+			    struct ptp_clock_request *clkreq, bool on)
+{
+	struct dp83640_private *dp83640 = clock->chosen;
+	struct phy_device *phydev = dp83640->phydev;
+	u32 sec, nsec, period;
+	u16 gpio, ptp_trig, trigger, val;
+
+	gpio = on ? gpio_tab[PEROUT_GPIO] : 0;
+	trigger = PER_TRIGGER;
+
+	ptp_trig = TRIG_WR |
+		(trigger & TRIG_CSEL_MASK) << TRIG_CSEL_SHIFT |
+		(gpio & TRIG_GPIO_MASK) << TRIG_GPIO_SHIFT |
+		TRIG_PER |
+		TRIG_PULSE;
+
+	val = (trigger & TRIG_SEL_MASK) << TRIG_SEL_SHIFT;
+
+	if (!on) {
+		val |= TRIG_DIS;
+		mutex_lock(&clock->extreg_lock);
+		ext_write(0, phydev, PAGE5, PTP_TRIG, ptp_trig);
+		ext_write(0, phydev, PAGE4, PTP_CTL, val);
+		mutex_unlock(&clock->extreg_lock);
+		return;
+	}
+
+	sec = clkreq->perout.start.sec;
+	nsec = clkreq->perout.start.nsec;
+	period = clkreq->perout.period.sec * 1000000000UL;
+	period += clkreq->perout.period.nsec;
+
+	mutex_lock(&clock->extreg_lock);
+
+	ext_write(0, phydev, PAGE5, PTP_TRIG, ptp_trig);
+
+	/*load trigger*/
+	val |= TRIG_LOAD;
+	ext_write(0, phydev, PAGE4, PTP_CTL, val);
+	ext_write(0, phydev, PAGE4, PTP_TDR, nsec & 0xffff);   /* ns[15:0] */
+	ext_write(0, phydev, PAGE4, PTP_TDR, nsec >> 16);      /* ns[31:16] */
+	ext_write(0, phydev, PAGE4, PTP_TDR, sec & 0xffff);    /* sec[15:0] */
+	ext_write(0, phydev, PAGE4, PTP_TDR, sec >> 16);       /* sec[31:16] */
+	ext_write(0, phydev, PAGE4, PTP_TDR, period & 0xffff); /* ns[15:0] */
+	ext_write(0, phydev, PAGE4, PTP_TDR, period >> 16);    /* ns[31:16] */
+
+	/*enable trigger*/
+	val &= ~TRIG_LOAD;
+	val |= TRIG_EN;
+	ext_write(0, phydev, PAGE4, PTP_CTL, val);
+
+	mutex_unlock(&clock->extreg_lock);
+}
+
+/* ptp clock methods */
+
+static int ptp_dp83640_adjfreq(struct ptp_clock_info *ptp, s32 ppb)
+{
+	struct dp83640_clock *clock =
+		container_of(ptp, struct dp83640_clock, caps);
+	struct phy_device *phydev = clock->chosen->phydev;
+	u64 rate;
+	int neg_adj = 0;
+	u16 hi, lo;
+
+	if (ppb < 0) {
+		neg_adj = 1;
+		ppb = -ppb;
+	}
+	rate = ppb;
+	rate <<= 26;
+	rate = div_u64(rate, 1953125);
+
+	hi = (rate >> 16) & PTP_RATE_HI_MASK;
+	if (neg_adj)
+		hi |= PTP_RATE_DIR;
+
+	lo = rate & 0xffff;
+
+	mutex_lock(&clock->extreg_lock);
+
+	ext_write(1, phydev, PAGE4, PTP_RATEH, hi);
+	ext_write(1, phydev, PAGE4, PTP_RATEL, lo);
+
+	mutex_unlock(&clock->extreg_lock);
+
+	return 0;
+}
+
+static int ptp_dp83640_adjtime(struct ptp_clock_info *ptp, s64 delta)
+{
+	struct dp83640_clock *clock =
+		container_of(ptp, struct dp83640_clock, caps);
+	struct phy_device *phydev = clock->chosen->phydev;
+	struct timespec ts;
+	int err;
+
+	delta += ADJTIME_FIX;
+
+	ts = ns_to_timespec(delta);
+
+	mutex_lock(&clock->extreg_lock);
+
+	err = tdr_write(1, phydev, &ts, PTP_STEP_CLK);
+
+	mutex_unlock(&clock->extreg_lock);
+
+	return err;
+}
+
+static int ptp_dp83640_gettime(struct ptp_clock_info *ptp, struct timespec *ts)
+{
+	struct dp83640_clock *clock =
+		container_of(ptp, struct dp83640_clock, caps);
+	struct phy_device *phydev = clock->chosen->phydev;
+	unsigned int val[4];
+
+	mutex_lock(&clock->extreg_lock);
+
+	ext_write(0, phydev, PAGE4, PTP_CTL, PTP_RD_CLK);
+
+	val[0] = ext_read(phydev, PAGE4, PTP_TDR); /* ns[15:0] */
+	val[1] = ext_read(phydev, PAGE4, PTP_TDR); /* ns[31:16] */
+	val[2] = ext_read(phydev, PAGE4, PTP_TDR); /* sec[15:0] */
+	val[3] = ext_read(phydev, PAGE4, PTP_TDR); /* sec[31:16] */
+
+	mutex_unlock(&clock->extreg_lock);
+
+	ts->tv_nsec = val[0] | (val[1] << 16);
+	ts->tv_sec  = val[2] | (val[3] << 16);
+
+	return 0;
+}
+
+static int ptp_dp83640_settime(struct ptp_clock_info *ptp,
+			       const struct timespec *ts)
+{
+	struct dp83640_clock *clock =
+		container_of(ptp, struct dp83640_clock, caps);
+	struct phy_device *phydev = clock->chosen->phydev;
+	int err;
+
+	mutex_lock(&clock->extreg_lock);
+
+	err = tdr_write(1, phydev, ts, PTP_LOAD_CLK);
+
+	mutex_unlock(&clock->extreg_lock);
+
+	return err;
+}
+
+static int ptp_dp83640_enable(struct ptp_clock_info *ptp,
+			      struct ptp_clock_request *rq, int on)
+{
+	struct dp83640_clock *clock =
+		container_of(ptp, struct dp83640_clock, caps);
+	struct phy_device *phydev = clock->chosen->phydev;
+	int index;
+	u16 evnt, event_num, gpio_num;
+
+	switch (rq->type) {
+	case PTP_CLK_REQ_EXTTS:
+		index = rq->extts.index;
+		if (index < 0 || index >= N_EXT_TS)
+			return -EINVAL;
+		event_num = EXT_EVENT + index;
+		evnt = EVNT_WR | (event_num & EVNT_SEL_MASK) << EVNT_SEL_SHIFT;
+		if (on) {
+			gpio_num = gpio_tab[EXTTS0_GPIO + index];
+			evnt |= (gpio_num & EVNT_GPIO_MASK) << EVNT_GPIO_SHIFT;
+			evnt |= EVNT_RISE;
+		}
+		ext_write(0, phydev, PAGE5, PTP_EVNT, evnt);
+		return 0;
+
+	case PTP_CLK_REQ_PEROUT:
+		if (rq->perout.index != 0)
+			return -EINVAL;
+		periodic_output(clock, rq, on);
+		return 0;
+
+	default:
+		break;
+	}
+
+	return -EOPNOTSUPP;
+}
+
+static u8 status_frame_dst[6] = { 0x01, 0x1B, 0x19, 0x00, 0x00, 0x00 };
+static u8 status_frame_src[6] = { 0x08, 0x00, 0x17, 0x0B, 0x6B, 0x0F };
+
+static void enable_status_frames(struct phy_device *phydev, bool on)
+{
+	u16 cfg0 = 0, ver;
+
+	if (on)
+		cfg0 = PSF_EVNT_EN | PSF_RXTS_EN | PSF_TXTS_EN | ENDIAN_FLAG;
+
+	ver = (PSF_PTPVER & VERSIONPTP_MASK) << VERSIONPTP_SHIFT;
+
+	ext_write(0, phydev, PAGE5, PSF_CFG0, cfg0);
+	ext_write(0, phydev, PAGE6, PSF_CFG1, ver);
+
+	if (!phydev->attached_dev) {
+		pr_warning("dp83640: expected to find an attached netdevice\n");
+		return;
+	}
+
+	if (on) {
+		if (dev_mc_add(phydev->attached_dev, status_frame_dst))
+			pr_warning("dp83640: failed to add mc address\n");
+	} else {
+		if (dev_mc_del(phydev->attached_dev, status_frame_dst))
+			pr_warning("dp83640: failed to delete mc address\n");
+	}
+}
+
+static bool is_status_frame(struct sk_buff *skb, int type)
+{
+	struct ethhdr *h = eth_hdr(skb);
+
+	if (PTP_CLASS_V2_L2 == type &&
+	    !memcmp(h->h_source, status_frame_src, sizeof(status_frame_src)))
+		return true;
+	else
+		return false;
+}
+
+static int expired(struct rxts *rxts)
+{
+	return time_after(jiffies, rxts->tmo);
+}
+
+/* Caller must hold rx_lock. */
+static void prune_rx_ts(struct dp83640_private *dp83640)
+{
+	struct list_head *this, *next;
+	struct rxts *rxts;
+
+	list_for_each_safe(this, next, &dp83640->rxts) {
+		rxts = list_entry(this, struct rxts, list);
+		if (expired(rxts)) {
+			list_del_init(&rxts->list);
+			list_add(&rxts->list, &dp83640->rxpool);
+		}
+	}
+}
+
+/* synchronize the phyters so they act as one clock */
+
+static void enable_broadcast(struct phy_device *phydev, int init_page, int on)
+{
+	int val;
+	phy_write(phydev, PAGESEL, 0);
+	val = phy_read(phydev, PHYCR2);
+	if (on)
+		val |= BC_WRITE;
+	else
+		val &= ~BC_WRITE;
+	phy_write(phydev, PHYCR2, val);
+	phy_write(phydev, PAGESEL, init_page);
+}
+
+static void recalibrate(struct dp83640_clock *clock)
+{
+	s64 now, diff;
+	struct phy_txts event_ts;
+	struct timespec ts;
+	struct list_head *this;
+	struct dp83640_private *tmp;
+	struct phy_device *master = clock->chosen->phydev;
+	u16 cal_gpio, cfg0, evnt, ptp_trig, trigger, val;
+
+	trigger = CAL_TRIGGER;
+	cal_gpio = gpio_tab[CALIBRATE_GPIO];
+
+	mutex_lock(&clock->extreg_lock);
+
+	/*
+	 * enable broadcast, disable status frames, enable ptp clock
+	 */
+	list_for_each(this, &clock->phylist) {
+		tmp = list_entry(this, struct dp83640_private, list);
+		enable_broadcast(tmp->phydev, clock->page, 1);
+		tmp->cfg0 = ext_read(tmp->phydev, PAGE5, PSF_CFG0);
+		ext_write(0, tmp->phydev, PAGE5, PSF_CFG0, 0);
+		ext_write(0, tmp->phydev, PAGE4, PTP_CTL, PTP_ENABLE);
+	}
+	enable_broadcast(master, clock->page, 1);
+	cfg0 = ext_read(master, PAGE5, PSF_CFG0);
+	ext_write(0, master, PAGE5, PSF_CFG0, 0);
+	ext_write(0, master, PAGE4, PTP_CTL, PTP_ENABLE);
+
+	/*
+	 * enable an event timestamp
+	 */
+	evnt = EVNT_WR | EVNT_RISE | EVNT_SINGLE;
+	evnt |= (CAL_EVENT & EVNT_SEL_MASK) << EVNT_SEL_SHIFT;
+	evnt |= (cal_gpio & EVNT_GPIO_MASK) << EVNT_GPIO_SHIFT;
+
+	list_for_each(this, &clock->phylist) {
+		tmp = list_entry(this, struct dp83640_private, list);
+		ext_write(0, tmp->phydev, PAGE5, PTP_EVNT, evnt);
+	}
+	ext_write(0, master, PAGE5, PTP_EVNT, evnt);
+
+	/*
+	 * configure a trigger
+	 */
+	ptp_trig = TRIG_WR | TRIG_IF_LATE | TRIG_PULSE;
+	ptp_trig |= (trigger  & TRIG_CSEL_MASK) << TRIG_CSEL_SHIFT;
+	ptp_trig |= (cal_gpio & TRIG_GPIO_MASK) << TRIG_GPIO_SHIFT;
+	ext_write(0, master, PAGE5, PTP_TRIG, ptp_trig);
+
+	/* load trigger */
+	val = (trigger & TRIG_SEL_MASK) << TRIG_SEL_SHIFT;
+	val |= TRIG_LOAD;
+	ext_write(0, master, PAGE4, PTP_CTL, val);
+
+	/* enable trigger */
+	val &= ~TRIG_LOAD;
+	val |= TRIG_EN;
+	ext_write(0, master, PAGE4, PTP_CTL, val);
+
+	/* disable trigger */
+	val = (trigger & TRIG_SEL_MASK) << TRIG_SEL_SHIFT;
+	val |= TRIG_DIS;
+	ext_write(0, master, PAGE4, PTP_CTL, val);
+
+	/*
+	 * read out and correct offsets
+	 */
+	val = ext_read(master, PAGE4, PTP_STS);
+	pr_info("master PTP_STS  0x%04hx", val);
+	val = ext_read(master, PAGE4, PTP_ESTS);
+	pr_info("master PTP_ESTS 0x%04hx", val);
+	event_ts.ns_lo  = ext_read(master, PAGE4, PTP_EDATA);
+	event_ts.ns_hi  = ext_read(master, PAGE4, PTP_EDATA);
+	event_ts.sec_lo = ext_read(master, PAGE4, PTP_EDATA);
+	event_ts.sec_hi = ext_read(master, PAGE4, PTP_EDATA);
+	now = phy2txts(&event_ts);
+
+	list_for_each(this, &clock->phylist) {
+		tmp = list_entry(this, struct dp83640_private, list);
+		val = ext_read(tmp->phydev, PAGE4, PTP_STS);
+		pr_info("slave  PTP_STS  0x%04hx", val);
+		val = ext_read(tmp->phydev, PAGE4, PTP_ESTS);
+		pr_info("slave  PTP_ESTS 0x%04hx", val);
+		event_ts.ns_lo  = ext_read(tmp->phydev, PAGE4, PTP_EDATA);
+		event_ts.ns_hi  = ext_read(tmp->phydev, PAGE4, PTP_EDATA);
+		event_ts.sec_lo = ext_read(tmp->phydev, PAGE4, PTP_EDATA);
+		event_ts.sec_hi = ext_read(tmp->phydev, PAGE4, PTP_EDATA);
+		diff = now - (s64) phy2txts(&event_ts);
+		pr_info("slave offset %lld nanoseconds\n", diff);
+		diff += ADJTIME_FIX;
+		ts = ns_to_timespec(diff);
+		tdr_write(0, tmp->phydev, &ts, PTP_STEP_CLK);
+	}
+
+	/*
+	 * restore status frames
+	 */
+	list_for_each(this, &clock->phylist) {
+		tmp = list_entry(this, struct dp83640_private, list);
+		ext_write(0, tmp->phydev, PAGE5, PSF_CFG0, tmp->cfg0);
+	}
+	ext_write(0, master, PAGE5, PSF_CFG0, cfg0);
+
+	mutex_unlock(&clock->extreg_lock);
+}
+
+/* time stamping methods */
+
+static inline u16 exts_chan_to_edata(int ch)
+{
+	return 1 << ((ch + EXT_EVENT) * 2);
+}
+
+static int decode_evnt(struct dp83640_private *dp83640,
+		       void *data, u16 ests)
+{
+	struct phy_txts *phy_txts;
+	struct ptp_clock_event event;
+	int i, parsed;
+	int words = (ests >> EVNT_TS_LEN_SHIFT) & EVNT_TS_LEN_MASK;
+	u16 ext_status = 0;
+
+	if (ests & MULT_EVNT) {
+		ext_status = *(u16 *) data;
+		data += sizeof(ext_status);
+	}
+
+	phy_txts = data;
+
+	switch (words) { /* fall through in every case */
+	case 3:
+		dp83640->edata.sec_hi = phy_txts->sec_hi;
+	case 2:
+		dp83640->edata.sec_lo = phy_txts->sec_lo;
+	case 1:
+		dp83640->edata.ns_hi = phy_txts->ns_hi;
+	case 0:
+		dp83640->edata.ns_lo = phy_txts->ns_lo;
+	}
+
+	if (ext_status) {
+		parsed = words + 2;
+	} else {
+		parsed = words + 1;
+		i = ((ests >> EVNT_NUM_SHIFT) & EVNT_NUM_MASK) - EXT_EVENT;
+		ext_status = exts_chan_to_edata(i);
+	}
+
+	event.type = PTP_CLOCK_EXTTS;
+	event.timestamp = phy2txts(&dp83640->edata);
+
+	for (i = 0; i < N_EXT_TS; i++) {
+		if (ext_status & exts_chan_to_edata(i)) {
+			event.index = i;
+			ptp_clock_event(dp83640->clock->ptp_clock, &event);
+		}
+	}
+
+	return parsed * sizeof(u16);
+}
+
+static void decode_rxts(struct dp83640_private *dp83640,
+			struct phy_rxts *phy_rxts)
+{
+	struct rxts *rxts;
+	unsigned long flags;
+
+	spin_lock_irqsave(&dp83640->rx_lock, flags);
+
+	prune_rx_ts(dp83640);
+
+	if (list_empty(&dp83640->rxpool)) {
+		pr_debug("dp83640: rx timestamp pool is empty\n");
+		goto out;
+	}
+	rxts = list_first_entry(&dp83640->rxpool, struct rxts, list);
+	list_del_init(&rxts->list);
+	phy2rxts(phy_rxts, rxts);
+	list_add_tail(&rxts->list, &dp83640->rxts);
+out:
+	spin_unlock_irqrestore(&dp83640->rx_lock, flags);
+}
+
+static void decode_txts(struct dp83640_private *dp83640,
+			struct phy_txts *phy_txts)
+{
+	struct skb_shared_hwtstamps shhwtstamps;
+	struct sk_buff *skb;
+	u64 ns;
+
+	/* We must already have the skb that triggered this. */
+
+	skb = skb_dequeue(&dp83640->tx_queue);
+
+	if (!skb) {
+		pr_debug("dp83640: have timestamp but tx_queue empty\n");
+		return;
+	}
+	ns = phy2txts(phy_txts);
+	memset(&shhwtstamps, 0, sizeof(shhwtstamps));
+	shhwtstamps.hwtstamp = ns_to_ktime(ns);
+	skb_complete_tx_timestamp(skb, &shhwtstamps);
+}
+
+static void decode_status_frame(struct dp83640_private *dp83640,
+				struct sk_buff *skb)
+{
+	struct phy_rxts *phy_rxts;
+	struct phy_txts *phy_txts;
+	u8 *ptr;
+	int len, size;
+	u16 ests, type;
+
+	ptr = skb->data + 2;
+
+	for (len = skb_headlen(skb) - 2; len > sizeof(type); len -= size) {
+
+		type = *(u16 *)ptr;
+		ests = type & 0x0fff;
+		type = type & 0xf000;
+		len -= sizeof(type);
+		ptr += sizeof(type);
+
+		if (PSF_RX == type && len >= sizeof(*phy_rxts)) {
+
+			phy_rxts = (struct phy_rxts *) ptr;
+			decode_rxts(dp83640, phy_rxts);
+			size = sizeof(*phy_rxts);
+
+		} else if (PSF_TX == type && len >= sizeof(*phy_txts)) {
+
+			phy_txts = (struct phy_txts *) ptr;
+			decode_txts(dp83640, phy_txts);
+			size = sizeof(*phy_txts);
+
+		} else if (PSF_EVNT == type && len >= sizeof(*phy_txts)) {
+
+			size = decode_evnt(dp83640, ptr, ests);
+
+		} else {
+			size = 0;
+			break;
+		}
+		ptr += size;
+	}
+}
+
+static int is_sync(struct sk_buff *skb, int type)
+{
+	u8 *data = skb->data, *msgtype;
+	unsigned int offset = 0;
+
+	switch (type) {
+	case PTP_CLASS_V1_IPV4:
+	case PTP_CLASS_V2_IPV4:
+		offset = ETH_HLEN + IPV4_HLEN(data) + UDP_HLEN;
+		break;
+	case PTP_CLASS_V1_IPV6:
+	case PTP_CLASS_V2_IPV6:
+		offset = OFF_PTP6;
+		break;
+	case PTP_CLASS_V2_L2:
+		offset = ETH_HLEN;
+		break;
+	case PTP_CLASS_V2_VLAN:
+		offset = ETH_HLEN + VLAN_HLEN;
+		break;
+	default:
+		return 0;
+	}
+
+	if (type & PTP_CLASS_V1)
+		offset += OFF_PTP_CONTROL;
+
+	if (skb->len < offset + 1)
+		return 0;
+
+	msgtype = data + offset;
+
+	return (*msgtype & 0xf) == 0;
+}
+
+static int match(struct sk_buff *skb, unsigned int type, struct rxts *rxts)
+{
+	u16 *seqid;
+	unsigned int offset;
+	u8 *msgtype, *data = skb_mac_header(skb);
+
+	/* check sequenceID, messageType, 12 bit hash of offset 20-29 */
+
+	switch (type) {
+	case PTP_CLASS_V1_IPV4:
+	case PTP_CLASS_V2_IPV4:
+		offset = ETH_HLEN + IPV4_HLEN(data) + UDP_HLEN;
+		break;
+	case PTP_CLASS_V1_IPV6:
+	case PTP_CLASS_V2_IPV6:
+		offset = OFF_PTP6;
+		break;
+	case PTP_CLASS_V2_L2:
+		offset = ETH_HLEN;
+		break;
+	case PTP_CLASS_V2_VLAN:
+		offset = ETH_HLEN + VLAN_HLEN;
+		break;
+	default:
+		return 0;
+	}
+
+	if (skb->len + ETH_HLEN < offset + OFF_PTP_SEQUENCE_ID + sizeof(*seqid))
+		return 0;
+
+	if (unlikely(type & PTP_CLASS_V1))
+		msgtype = data + offset + OFF_PTP_CONTROL;
+	else
+		msgtype = data + offset;
+
+	seqid = (u16 *)(data + offset + OFF_PTP_SEQUENCE_ID);
+
+	return (rxts->msgtype == (*msgtype & 0xf) &&
+		rxts->seqid   == ntohs(*seqid));
+}
+
+static void dp83640_free_clocks(void)
+{
+	struct dp83640_clock *clock;
+	struct list_head *this, *next;
+
+	mutex_lock(&phyter_clocks_lock);
+
+	list_for_each_safe(this, next, &phyter_clocks) {
+		clock = list_entry(this, struct dp83640_clock, list);
+		if (!list_empty(&clock->phylist)) {
+			pr_warning("phy list non-empty while unloading");
+			BUG();
+		}
+		list_del(&clock->list);
+		mutex_destroy(&clock->extreg_lock);
+		mutex_destroy(&clock->clock_lock);
+		put_device(&clock->bus->dev);
+		kfree(clock);
+	}
+
+	mutex_unlock(&phyter_clocks_lock);
+}
+
+static void dp83640_clock_init(struct dp83640_clock *clock, struct mii_bus *bus)
+{
+	INIT_LIST_HEAD(&clock->list);
+	clock->bus = bus;
+	mutex_init(&clock->extreg_lock);
+	mutex_init(&clock->clock_lock);
+	INIT_LIST_HEAD(&clock->phylist);
+	clock->caps.owner = THIS_MODULE;
+	sprintf(clock->caps.name, "dp83640 timer");
+	clock->caps.max_adj	= 1953124;
+	clock->caps.n_alarm	= 0;
+	clock->caps.n_ext_ts	= N_EXT_TS;
+	clock->caps.n_per_out	= 1;
+	clock->caps.pps		= 0;
+	clock->caps.adjfreq	= ptp_dp83640_adjfreq;
+	clock->caps.adjtime	= ptp_dp83640_adjtime;
+	clock->caps.gettime	= ptp_dp83640_gettime;
+	clock->caps.settime	= ptp_dp83640_settime;
+	clock->caps.enable	= ptp_dp83640_enable;
+	/*
+	 * Get a reference to this bus instance.
+	 */
+	get_device(&bus->dev);
+}
+
+static int choose_this_phy(struct dp83640_clock *clock,
+			   struct phy_device *phydev)
+{
+	if (chosen_phy == -1 && !clock->chosen)
+		return 1;
+
+	if (chosen_phy == phydev->addr)
+		return 1;
+
+	return 0;
+}
+
+static struct dp83640_clock *dp83640_clock_get(struct dp83640_clock *clock)
+{
+	if (clock)
+		mutex_lock(&clock->clock_lock);
+	return clock;
+}
+
+/*
+ * Look up and lock a clock by bus instance.
+ * If there is no clock for this bus, then create it first.
+ */
+static struct dp83640_clock *dp83640_clock_get_bus(struct mii_bus *bus)
+{
+	struct dp83640_clock *clock = NULL, *tmp;
+	struct list_head *this;
+
+	mutex_lock(&phyter_clocks_lock);
+
+	list_for_each(this, &phyter_clocks) {
+		tmp = list_entry(this, struct dp83640_clock, list);
+		if (tmp->bus == bus) {
+			clock = tmp;
+			break;
+		}
+	}
+	if (clock)
+		goto out;
+
+	clock = kzalloc(sizeof(struct dp83640_clock), GFP_KERNEL);
+	if (!clock)
+		goto out;
+
+	dp83640_clock_init(clock, bus);
+	list_add_tail(&phyter_clocks, &clock->list);
+out:
+	mutex_unlock(&phyter_clocks_lock);
+
+	return dp83640_clock_get(clock);
+}
+
+static void dp83640_clock_put(struct dp83640_clock *clock)
+{
+	mutex_unlock(&clock->clock_lock);
+}
+
+static int dp83640_probe(struct phy_device *phydev)
+{
+	struct dp83640_clock *clock;
+	struct dp83640_private *dp83640;
+	int err = -ENOMEM, i;
+
+	if (phydev->addr == BROADCAST_ADDR)
+		return 0;
+
+	clock = dp83640_clock_get_bus(phydev->bus);
+	if (!clock)
+		goto no_clock;
+
+	dp83640 = kzalloc(sizeof(struct dp83640_private), GFP_KERNEL);
+	if (!dp83640)
+		goto no_memory;
+
+	dp83640->phydev = phydev;
+	INIT_WORK(&dp83640->ts_work, rx_timestamp_work);
+
+	INIT_LIST_HEAD(&dp83640->rxts);
+	INIT_LIST_HEAD(&dp83640->rxpool);
+	for (i = 0; i < MAX_RXTS; i++)
+		list_add(&dp83640->rx_pool_data[i].list, &dp83640->rxpool);
+
+	phydev->priv = dp83640;
+
+	spin_lock_init(&dp83640->rx_lock);
+	skb_queue_head_init(&dp83640->rx_queue);
+	skb_queue_head_init(&dp83640->tx_queue);
+
+	dp83640->clock = clock;
+
+	if (choose_this_phy(clock, phydev)) {
+		clock->chosen = dp83640;
+		clock->ptp_clock = ptp_clock_register(&clock->caps);
+		if (IS_ERR(clock->ptp_clock)) {
+			err = PTR_ERR(clock->ptp_clock);
+			goto no_register;
+		}
+	} else
+		list_add_tail(&dp83640->list, &clock->phylist);
+
+	if (clock->chosen && !list_empty(&clock->phylist))
+		recalibrate(clock);
+	else
+		enable_broadcast(dp83640->phydev, clock->page, 1);
+
+	dp83640_clock_put(clock);
+	return 0;
+
+no_register:
+	clock->chosen = NULL;
+	kfree(dp83640);
+no_memory:
+	dp83640_clock_put(clock);
+no_clock:
+	return err;
+}
+
+static void dp83640_remove(struct phy_device *phydev)
+{
+	struct dp83640_clock *clock;
+	struct list_head *this, *next;
+	struct dp83640_private *tmp, *dp83640 = phydev->priv;
+	struct sk_buff *skb;
+
+	if (phydev->addr == BROADCAST_ADDR)
+		return;
+
+	enable_status_frames(phydev, false);
+	cancel_work_sync(&dp83640->ts_work);
+
+	while ((skb = skb_dequeue(&dp83640->rx_queue)) != NULL)
+		kfree_skb(skb);
+
+	while ((skb = skb_dequeue(&dp83640->tx_queue)) != NULL)
+		skb_complete_tx_timestamp(skb, NULL);
+
+	clock = dp83640_clock_get(dp83640->clock);
+
+	if (dp83640 == clock->chosen) {
+		ptp_clock_unregister(clock->ptp_clock);
+		clock->chosen = NULL;
+	} else {
+		list_for_each_safe(this, next, &clock->phylist) {
+			tmp = list_entry(this, struct dp83640_private, list);
+			if (tmp == dp83640) {
+				list_del_init(&tmp->list);
+				break;
+			}
+		}
+	}
+
+	dp83640_clock_put(clock);
+	kfree(dp83640);
+}
+
+static int dp83640_hwtstamp(struct phy_device *phydev, struct ifreq *ifr)
+{
+	struct dp83640_private *dp83640 = phydev->priv;
+	struct hwtstamp_config cfg;
+	u16 txcfg0, rxcfg0;
+
+	if (copy_from_user(&cfg, ifr->ifr_data, sizeof(cfg)))
+		return -EFAULT;
+
+	if (cfg.flags) /* reserved for future extensions */
+		return -EINVAL;
+
+	if (cfg.tx_type < 0 || cfg.tx_type > HWTSTAMP_TX_ONESTEP_SYNC)
+		return -ERANGE;
+
+	dp83640->hwts_tx_en = cfg.tx_type;
+
+	switch (cfg.rx_filter) {
+	case HWTSTAMP_FILTER_NONE:
+		dp83640->hwts_rx_en = 0;
+		dp83640->layer = 0;
+		dp83640->version = 0;
+		break;
+	case HWTSTAMP_FILTER_PTP_V1_L4_EVENT:
+	case HWTSTAMP_FILTER_PTP_V1_L4_SYNC:
+	case HWTSTAMP_FILTER_PTP_V1_L4_DELAY_REQ:
+		dp83640->hwts_rx_en = 1;
+		dp83640->layer = LAYER4;
+		dp83640->version = 1;
+		break;
+	case HWTSTAMP_FILTER_PTP_V2_L4_EVENT:
+	case HWTSTAMP_FILTER_PTP_V2_L4_SYNC:
+	case HWTSTAMP_FILTER_PTP_V2_L4_DELAY_REQ:
+		dp83640->hwts_rx_en = 1;
+		dp83640->layer = LAYER4;
+		dp83640->version = 2;
+		break;
+	case HWTSTAMP_FILTER_PTP_V2_L2_EVENT:
+	case HWTSTAMP_FILTER_PTP_V2_L2_SYNC:
+	case HWTSTAMP_FILTER_PTP_V2_L2_DELAY_REQ:
+		dp83640->hwts_rx_en = 1;
+		dp83640->layer = LAYER2;
+		dp83640->version = 2;
+		break;
+	case HWTSTAMP_FILTER_PTP_V2_EVENT:
+	case HWTSTAMP_FILTER_PTP_V2_SYNC:
+	case HWTSTAMP_FILTER_PTP_V2_DELAY_REQ:
+		dp83640->hwts_rx_en = 1;
+		dp83640->layer = LAYER4|LAYER2;
+		dp83640->version = 2;
+		break;
+	default:
+		return -ERANGE;
+	}
+
+	txcfg0 = (dp83640->version & TX_PTP_VER_MASK) << TX_PTP_VER_SHIFT;
+	rxcfg0 = (dp83640->version & TX_PTP_VER_MASK) << TX_PTP_VER_SHIFT;
+
+	if (dp83640->layer & LAYER2) {
+		txcfg0 |= TX_L2_EN;
+		rxcfg0 |= RX_L2_EN;
+	}
+	if (dp83640->layer & LAYER4) {
+		txcfg0 |= TX_IPV6_EN | TX_IPV4_EN;
+		rxcfg0 |= RX_IPV6_EN | RX_IPV4_EN;
+	}
+
+	if (dp83640->hwts_tx_en)
+		txcfg0 |= TX_TS_EN;
+
+	if (dp83640->hwts_tx_en == HWTSTAMP_TX_ONESTEP_SYNC)
+		txcfg0 |= SYNC_1STEP | CHK_1STEP;
+
+	if (dp83640->hwts_rx_en)
+		rxcfg0 |= RX_TS_EN;
+
+	mutex_lock(&dp83640->clock->extreg_lock);
+
+	if (dp83640->hwts_tx_en || dp83640->hwts_rx_en) {
+		enable_status_frames(phydev, true);
+		ext_write(0, phydev, PAGE4, PTP_CTL, PTP_ENABLE);
+	}
+
+	ext_write(0, phydev, PAGE5, PTP_TXCFG0, txcfg0);
+	ext_write(0, phydev, PAGE5, PTP_RXCFG0, rxcfg0);
+
+	mutex_unlock(&dp83640->clock->extreg_lock);
+
+	return copy_to_user(ifr->ifr_data, &cfg, sizeof(cfg)) ? -EFAULT : 0;
+}
+
+static void rx_timestamp_work(struct work_struct *work)
+{
+	struct dp83640_private *dp83640 =
+		container_of(work, struct dp83640_private, ts_work);
+	struct list_head *this, *next;
+	struct rxts *rxts;
+	struct skb_shared_hwtstamps *shhwtstamps;
+	struct sk_buff *skb;
+	unsigned int type;
+	unsigned long flags;
+
+	/* Deliver each deferred packet, with or without a time stamp. */
+
+	while ((skb = skb_dequeue(&dp83640->rx_queue)) != NULL) {
+		type = SKB_PTP_TYPE(skb);
+		spin_lock_irqsave(&dp83640->rx_lock, flags);
+		list_for_each_safe(this, next, &dp83640->rxts) {
+			rxts = list_entry(this, struct rxts, list);
+			if (match(skb, type, rxts)) {
+				shhwtstamps = skb_hwtstamps(skb);
+				memset(shhwtstamps, 0, sizeof(*shhwtstamps));
+				shhwtstamps->hwtstamp = ns_to_ktime(rxts->ns);
+				list_del_init(&rxts->list);
+				list_add(&rxts->list, &dp83640->rxpool);
+				break;
+			}
+		}
+		spin_unlock_irqrestore(&dp83640->rx_lock, flags);
+		netif_rx_ni(skb);
+	}
+
+	/* Clear out expired time stamps. */
+
+	spin_lock_irqsave(&dp83640->rx_lock, flags);
+	prune_rx_ts(dp83640);
+	spin_unlock_irqrestore(&dp83640->rx_lock, flags);
+}
+
+static bool dp83640_rxtstamp(struct phy_device *phydev,
+			     struct sk_buff *skb, int type)
+{
+	struct dp83640_private *dp83640 = phydev->priv;
+
+	if (!dp83640->hwts_rx_en)
+		return false;
+
+	if (is_status_frame(skb, type)) {
+		decode_status_frame(dp83640, skb);
+		kfree_skb(skb);
+		return true;
+	}
+
+	SKB_PTP_TYPE(skb) = type;
+	skb_queue_tail(&dp83640->rx_queue, skb);
+	schedule_work(&dp83640->ts_work);
+
+	return true;
+}
+
+static void dp83640_txtstamp(struct phy_device *phydev,
+			     struct sk_buff *skb, int type)
+{
+	struct dp83640_private *dp83640 = phydev->priv;
+
+	switch (dp83640->hwts_tx_en) {
+
+	case HWTSTAMP_TX_ONESTEP_SYNC:
+		if (is_sync(skb, type)) {
+			skb_complete_tx_timestamp(skb, NULL);
+			return;
+		}
+		/* fall through */
+	case HWTSTAMP_TX_ON:
+		skb_queue_tail(&dp83640->tx_queue, skb);
+		schedule_work(&dp83640->ts_work);
+		break;
+
+	case HWTSTAMP_TX_OFF:
+	default:
+		skb_complete_tx_timestamp(skb, NULL);
+		break;
+	}
+}
+
+static struct phy_driver dp83640_driver = {
+	.phy_id		= DP83640_PHY_ID,
+	.phy_id_mask	= 0xfffffff0,
+	.name		= "NatSemi DP83640",
+	.features	= PHY_BASIC_FEATURES,
+	.flags		= 0,
+	.probe		= dp83640_probe,
+	.remove		= dp83640_remove,
+	.config_aneg	= genphy_config_aneg,
+	.read_status	= genphy_read_status,
+	.hwtstamp	= dp83640_hwtstamp,
+	.rxtstamp	= dp83640_rxtstamp,
+	.txtstamp	= dp83640_txtstamp,
+	.driver		= {.owner = THIS_MODULE,}
+};
+
+static int __init dp83640_init(void)
+{
+	return phy_driver_register(&dp83640_driver);
+}
+
+static void __exit dp83640_exit(void)
+{
+	dp83640_free_clocks();
+	phy_driver_unregister(&dp83640_driver);
+}
+
+MODULE_DESCRIPTION("National Semiconductor DP83640 PHY driver");
+MODULE_AUTHOR("Richard Cochran <richardcochran@gmail.at>");
+MODULE_LICENSE("GPL");
+
+module_init(dp83640_init);
+module_exit(dp83640_exit);
+
+static struct mdio_device_id __maybe_unused dp83640_tbl[] = {
+	{ DP83640_PHY_ID, 0xfffffff0 },
+	{ }
+};
+
+MODULE_DEVICE_TABLE(mdio, dp83640_tbl);
diff --git a/ap/os/linux/linux-3.4.x/drivers/net/phy/dp83640_reg.h b/ap/os/linux/linux-3.4.x/drivers/net/phy/dp83640_reg.h
new file mode 100644
index 0000000..e7fe411
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/net/phy/dp83640_reg.h
@@ -0,0 +1,267 @@
+/* dp83640_reg.h
+ * Generated by regen.tcl on Thu Feb 17 10:02:48 AM CET 2011
+ */
+#ifndef HAVE_DP83640_REGISTERS
+#define HAVE_DP83640_REGISTERS
+
+#define PAGE0                     0x0000
+#define PHYCR2                    0x001c /* PHY Control Register 2 */
+
+#define PAGE4                     0x0004
+#define PTP_CTL                   0x0014 /* PTP Control Register */
+#define PTP_TDR                   0x0015 /* PTP Time Data Register */
+#define PTP_STS                   0x0016 /* PTP Status Register */
+#define PTP_TSTS                  0x0017 /* PTP Trigger Status Register */
+#define PTP_RATEL                 0x0018 /* PTP Rate Low Register */
+#define PTP_RATEH                 0x0019 /* PTP Rate High Register */
+#define PTP_RDCKSUM               0x001a /* PTP Read Checksum */
+#define PTP_WRCKSUM               0x001b /* PTP Write Checksum */
+#define PTP_TXTS                  0x001c /* PTP Transmit Timestamp Register, in four 16-bit reads */
+#define PTP_RXTS                  0x001d /* PTP Receive Timestamp Register, in six? 16-bit reads */
+#define PTP_ESTS                  0x001e /* PTP Event Status Register */
+#define PTP_EDATA                 0x001f /* PTP Event Data Register */
+
+#define PAGE5                     0x0005
+#define PTP_TRIG                  0x0014 /* PTP Trigger Configuration Register */
+#define PTP_EVNT                  0x0015 /* PTP Event Configuration Register */
+#define PTP_TXCFG0                0x0016 /* PTP Transmit Configuration Register 0 */
+#define PTP_TXCFG1                0x0017 /* PTP Transmit Configuration Register 1 */
+#define PSF_CFG0                  0x0018 /* PHY Status Frame Configuration Register 0 */
+#define PTP_RXCFG0                0x0019 /* PTP Receive Configuration Register 0 */
+#define PTP_RXCFG1                0x001a /* PTP Receive Configuration Register 1 */
+#define PTP_RXCFG2                0x001b /* PTP Receive Configuration Register 2 */
+#define PTP_RXCFG3                0x001c /* PTP Receive Configuration Register 3 */
+#define PTP_RXCFG4                0x001d /* PTP Receive Configuration Register 4 */
+#define PTP_TRDL                  0x001e /* PTP Temporary Rate Duration Low Register */
+#define PTP_TRDH                  0x001f /* PTP Temporary Rate Duration High Register */
+
+#define PAGE6                     0x0006
+#define PTP_COC                   0x0014 /* PTP Clock Output Control Register */
+#define PSF_CFG1                  0x0015 /* PHY Status Frame Configuration Register 1 */
+#define PSF_CFG2                  0x0016 /* PHY Status Frame Configuration Register 2 */
+#define PSF_CFG3                  0x0017 /* PHY Status Frame Configuration Register 3 */
+#define PSF_CFG4                  0x0018 /* PHY Status Frame Configuration Register 4 */
+#define PTP_SFDCFG                0x0019 /* PTP SFD Configuration Register */
+#define PTP_INTCTL                0x001a /* PTP Interrupt Control Register */
+#define PTP_CLKSRC                0x001b /* PTP Clock Source Register */
+#define PTP_ETR                   0x001c /* PTP Ethernet Type Register */
+#define PTP_OFF                   0x001d /* PTP Offset Register */
+#define PTP_GPIOMON               0x001e /* PTP GPIO Monitor Register */
+#define PTP_RXHASH                0x001f /* PTP Receive Hash Register */
+
+/* Bit definitions for the PHYCR2 register */
+#define BC_WRITE                  (1<<11) /* Broadcast Write Enable */
+
+/* Bit definitions for the PTP_CTL register */
+#define TRIG_SEL_SHIFT            (10)    /* PTP Trigger Select */
+#define TRIG_SEL_MASK             (0x7)
+#define TRIG_DIS                  (1<<9)  /* Disable PTP Trigger */
+#define TRIG_EN                   (1<<8)  /* Enable PTP Trigger */
+#define TRIG_READ                 (1<<7)  /* Read PTP Trigger */
+#define TRIG_LOAD                 (1<<6)  /* Load PTP Trigger */
+#define PTP_RD_CLK                (1<<5)  /* Read PTP Clock */
+#define PTP_LOAD_CLK              (1<<4)  /* Load PTP Clock */
+#define PTP_STEP_CLK              (1<<3)  /* Step PTP Clock */
+#define PTP_ENABLE                (1<<2)  /* Enable PTP Clock */
+#define PTP_DISABLE               (1<<1)  /* Disable PTP Clock */
+#define PTP_RESET                 (1<<0)  /* Reset PTP Clock */
+
+/* Bit definitions for the PTP_STS register */
+#define TXTS_RDY                  (1<<11) /* Transmit Timestamp Ready */
+#define RXTS_RDY                  (1<<10) /* Receive Timestamp Ready */
+#define TRIG_DONE                 (1<<9)  /* PTP Trigger Done */
+#define EVENT_RDY                 (1<<8)  /* PTP Event Timestamp Ready */
+#define TXTS_IE                   (1<<3)  /* Transmit Timestamp Interrupt Enable */
+#define RXTS_IE                   (1<<2)  /* Receive Timestamp Interrupt Enable */
+#define TRIG_IE                   (1<<1)  /* Trigger Interrupt Enable */
+#define EVENT_IE                  (1<<0)  /* Event Interrupt Enable */
+
+/* Bit definitions for the PTP_TSTS register */
+#define TRIG7_ERROR               (1<<15) /* Trigger 7 Error */
+#define TRIG7_ACTIVE              (1<<14) /* Trigger 7 Active */
+#define TRIG6_ERROR               (1<<13) /* Trigger 6 Error */
+#define TRIG6_ACTIVE              (1<<12) /* Trigger 6 Active */
+#define TRIG5_ERROR               (1<<11) /* Trigger 5 Error */
+#define TRIG5_ACTIVE              (1<<10) /* Trigger 5 Active */
+#define TRIG4_ERROR               (1<<9)  /* Trigger 4 Error */
+#define TRIG4_ACTIVE              (1<<8)  /* Trigger 4 Active */
+#define TRIG3_ERROR               (1<<7)  /* Trigger 3 Error */
+#define TRIG3_ACTIVE              (1<<6)  /* Trigger 3 Active */
+#define TRIG2_ERROR               (1<<5)  /* Trigger 2 Error */
+#define TRIG2_ACTIVE              (1<<4)  /* Trigger 2 Active */
+#define TRIG1_ERROR               (1<<3)  /* Trigger 1 Error */
+#define TRIG1_ACTIVE              (1<<2)  /* Trigger 1 Active */
+#define TRIG0_ERROR               (1<<1)  /* Trigger 0 Error */
+#define TRIG0_ACTIVE              (1<<0)  /* Trigger 0 Active */
+
+/* Bit definitions for the PTP_RATEH register */
+#define PTP_RATE_DIR              (1<<15) /* PTP Rate Direction */
+#define PTP_TMP_RATE              (1<<14) /* PTP Temporary Rate */
+#define PTP_RATE_HI_SHIFT         (0)     /* PTP Rate High 10-bits */
+#define PTP_RATE_HI_MASK          (0x3ff)
+
+/* Bit definitions for the PTP_ESTS register */
+#define EVNTS_MISSED_SHIFT        (8)     /* Indicates number of events missed */
+#define EVNTS_MISSED_MASK         (0x7)
+#define EVNT_TS_LEN_SHIFT         (6)     /* Indicates length of the Timestamp field in 16-bit words minus 1 */
+#define EVNT_TS_LEN_MASK          (0x3)
+#define EVNT_RF                   (1<<5)  /* Indicates whether the event is a rise or falling event */
+#define EVNT_NUM_SHIFT            (2)     /* Indicates Event Timestamp Unit which detected an event */
+#define EVNT_NUM_MASK             (0x7)
+#define MULT_EVNT                 (1<<1)  /* Indicates multiple events were detected at the same time */
+#define EVENT_DET                 (1<<0)  /* PTP Event Detected */
+
+/* Bit definitions for the PTP_EDATA register */
+#define E7_RISE                   (1<<15) /* Indicates direction of Event 7 */
+#define E7_DET                    (1<<14) /* Indicates Event 7 detected */
+#define E6_RISE                   (1<<13) /* Indicates direction of Event 6 */
+#define E6_DET                    (1<<12) /* Indicates Event 6 detected */
+#define E5_RISE                   (1<<11) /* Indicates direction of Event 5 */
+#define E5_DET                    (1<<10) /* Indicates Event 5 detected */
+#define E4_RISE                   (1<<9)  /* Indicates direction of Event 4 */
+#define E4_DET                    (1<<8)  /* Indicates Event 4 detected */
+#define E3_RISE                   (1<<7)  /* Indicates direction of Event 3 */
+#define E3_DET                    (1<<6)  /* Indicates Event 3 detected */
+#define E2_RISE                   (1<<5)  /* Indicates direction of Event 2 */
+#define E2_DET                    (1<<4)  /* Indicates Event 2 detected */
+#define E1_RISE                   (1<<3)  /* Indicates direction of Event 1 */
+#define E1_DET                    (1<<2)  /* Indicates Event 1 detected */
+#define E0_RISE                   (1<<1)  /* Indicates direction of Event 0 */
+#define E0_DET                    (1<<0)  /* Indicates Event 0 detected */
+
+/* Bit definitions for the PTP_TRIG register */
+#define TRIG_PULSE                (1<<15) /* generate a Pulse rather than a single edge */
+#define TRIG_PER                  (1<<14) /* generate a periodic signal */
+#define TRIG_IF_LATE              (1<<13) /* trigger immediately if already past */
+#define TRIG_NOTIFY               (1<<12) /* Trigger Notification Enable */
+#define TRIG_GPIO_SHIFT           (8)     /* Trigger GPIO Connection, value 1-12 */
+#define TRIG_GPIO_MASK            (0xf)
+#define TRIG_TOGGLE               (1<<7)  /* Trigger Toggle Mode Enable */
+#define TRIG_CSEL_SHIFT           (1)     /* Trigger Configuration Select */
+#define TRIG_CSEL_MASK            (0x7)
+#define TRIG_WR                   (1<<0)  /* Trigger Configuration Write */
+
+/* Bit definitions for the PTP_EVNT register */
+#define EVNT_RISE                 (1<<14) /* Event Rise Detect Enable */
+#define EVNT_FALL                 (1<<13) /* Event Fall Detect Enable */
+#define EVNT_SINGLE               (1<<12) /* enable single event capture operation */
+#define EVNT_GPIO_SHIFT           (8)     /* Event GPIO Connection, value 1-12 */
+#define EVNT_GPIO_MASK            (0xf)
+#define EVNT_SEL_SHIFT            (1)     /* Event Select */
+#define EVNT_SEL_MASK             (0x7)
+#define EVNT_WR                   (1<<0)  /* Event Configuration Write */
+
+/* Bit definitions for the PTP_TXCFG0 register */
+#define SYNC_1STEP                (1<<15) /* insert timestamp into transmit Sync Messages */
+#define DR_INSERT                 (1<<13) /* Insert Delay_Req Timestamp in Delay_Resp (dangerous) */
+#define NTP_TS_EN                 (1<<12) /* Enable Timestamping of NTP Packets */
+#define IGNORE_2STEP              (1<<11) /* Ignore Two_Step flag for One-Step operation */
+#define CRC_1STEP                 (1<<10) /* Disable checking of CRC for One-Step operation */
+#define CHK_1STEP                 (1<<9)  /* Enable UDP Checksum correction for One-Step Operation */
+#define IP1588_EN                 (1<<8)  /* Enable IEEE 1588 defined IP address filter */
+#define TX_L2_EN                  (1<<7)  /* Layer2 Timestamp Enable */
+#define TX_IPV6_EN                (1<<6)  /* IPv6 Timestamp Enable */
+#define TX_IPV4_EN                (1<<5)  /* IPv4 Timestamp Enable */
+#define TX_PTP_VER_SHIFT          (1)     /* Enable Timestamp capture for IEEE 1588 version X */
+#define TX_PTP_VER_MASK           (0xf)
+#define TX_TS_EN                  (1<<0)  /* Transmit Timestamp Enable */
+
+/* Bit definitions for the PTP_TXCFG1 register */
+#define BYTE0_MASK_SHIFT          (8)     /* Bit mask to be used for matching Byte0 of the PTP Message */
+#define BYTE0_MASK_MASK           (0xff)
+#define BYTE0_DATA_SHIFT          (0)     /* Data to be used for matching Byte0 of the PTP Message */
+#define BYTE0_DATA_MASK           (0xff)
+
+/* Bit definitions for the PSF_CFG0 register */
+#define MAC_SRC_ADD_SHIFT         (11)    /* Status Frame Mac Source Address */
+#define MAC_SRC_ADD_MASK          (0x3)
+#define MIN_PRE_SHIFT             (8)     /* Status Frame Minimum Preamble */
+#define MIN_PRE_MASK              (0x7)
+#define PSF_ENDIAN                (1<<7)  /* Status Frame Endian Control */
+#define PSF_IPV4                  (1<<6)  /* Status Frame IPv4 Enable */
+#define PSF_PCF_RD                (1<<5)  /* Control Frame Read PHY Status Frame Enable */
+#define PSF_ERR_EN                (1<<4)  /* Error PHY Status Frame Enable */
+#define PSF_TXTS_EN               (1<<3)  /* Transmit Timestamp PHY Status Frame Enable */
+#define PSF_RXTS_EN               (1<<2)  /* Receive Timestamp PHY Status Frame Enable */
+#define PSF_TRIG_EN               (1<<1)  /* Trigger PHY Status Frame Enable */
+#define PSF_EVNT_EN               (1<<0)  /* Event PHY Status Frame Enable */
+
+/* Bit definitions for the PTP_RXCFG0 register */
+#define DOMAIN_EN                 (1<<15) /* Domain Match Enable */
+#define ALT_MAST_DIS              (1<<14) /* Alternate Master Timestamp Disable */
+#define USER_IP_SEL               (1<<13) /* Selects portion of IP address accessible thru PTP_RXCFG2 */
+#define USER_IP_EN                (1<<12) /* Enable User-programmed IP address filter */
+#define RX_SLAVE                  (1<<11) /* Receive Slave Only */
+#define IP1588_EN_SHIFT           (8)     /* Enable IEEE 1588 defined IP address filters */
+#define IP1588_EN_MASK            (0xf)
+#define RX_L2_EN                  (1<<7)  /* Layer2 Timestamp Enable */
+#define RX_IPV6_EN                (1<<6)  /* IPv6 Timestamp Enable */
+#define RX_IPV4_EN                (1<<5)  /* IPv4 Timestamp Enable */
+#define RX_PTP_VER_SHIFT          (1)     /* Enable Timestamp capture for IEEE 1588 version X */
+#define RX_PTP_VER_MASK           (0xf)
+#define RX_TS_EN                  (1<<0)  /* Receive Timestamp Enable */
+
+/* Bit definitions for the PTP_RXCFG1 register */
+#define BYTE0_MASK_SHIFT          (8)     /* Bit mask to be used for matching Byte0 of the PTP Message */
+#define BYTE0_MASK_MASK           (0xff)
+#define BYTE0_DATA_SHIFT          (0)     /* Data to be used for matching Byte0 of the PTP Message */
+#define BYTE0_DATA_MASK           (0xff)
+
+/* Bit definitions for the PTP_RXCFG3 register */
+#define TS_MIN_IFG_SHIFT          (12)    /* Minimum Inter-frame Gap */
+#define TS_MIN_IFG_MASK           (0xf)
+#define ACC_UDP                   (1<<11) /* Record Timestamp if UDP Checksum Error */
+#define ACC_CRC                   (1<<10) /* Record Timestamp if CRC Error */
+#define TS_APPEND                 (1<<9)  /* Append Timestamp for L2 */
+#define TS_INSERT                 (1<<8)  /* Enable Timestamp Insertion */
+#define PTP_DOMAIN_SHIFT          (0)     /* PTP Message domainNumber field */
+#define PTP_DOMAIN_MASK           (0xff)
+
+/* Bit definitions for the PTP_RXCFG4 register */
+#define IPV4_UDP_MOD              (1<<15) /* Enable IPV4 UDP Modification */
+#define TS_SEC_EN                 (1<<14) /* Enable Timestamp Seconds */
+#define TS_SEC_LEN_SHIFT          (12)    /* Inserted Timestamp Seconds Length */
+#define TS_SEC_LEN_MASK           (0x3)
+#define RXTS_NS_OFF_SHIFT         (6)     /* Receive Timestamp Nanoseconds offset */
+#define RXTS_NS_OFF_MASK          (0x3f)
+#define RXTS_SEC_OFF_SHIFT        (0)     /* Receive Timestamp Seconds offset */
+#define RXTS_SEC_OFF_MASK         (0x3f)
+
+/* Bit definitions for the PTP_COC register */
+#define PTP_CLKOUT_EN             (1<<15) /* PTP Clock Output Enable */
+#define PTP_CLKOUT_SEL            (1<<14) /* PTP Clock Output Source Select */
+#define PTP_CLKOUT_SPEEDSEL       (1<<13) /* PTP Clock Output I/O Speed Select */
+#define PTP_CLKDIV_SHIFT          (0)     /* PTP Clock Divide-by Value */
+#define PTP_CLKDIV_MASK           (0xff)
+
+/* Bit definitions for the PSF_CFG1 register */
+#define PTPRESERVED_SHIFT         (12)    /* PTP v2 reserved field */
+#define PTPRESERVED_MASK          (0xf)
+#define VERSIONPTP_SHIFT          (8)     /* PTP v2 versionPTP field */
+#define VERSIONPTP_MASK           (0xf)
+#define TRANSPORT_SPECIFIC_SHIFT  (4)     /* PTP v2 Header transportSpecific field */
+#define TRANSPORT_SPECIFIC_MASK   (0xf)
+#define MESSAGETYPE_SHIFT         (0)     /* PTP v2 messageType field */
+#define MESSAGETYPE_MASK          (0xf)
+
+/* Bit definitions for the PTP_SFDCFG register */
+#define TX_SFD_GPIO_SHIFT         (4)     /* TX SFD GPIO Select, value 1-12 */
+#define TX_SFD_GPIO_MASK          (0xf)
+#define RX_SFD_GPIO_SHIFT         (0)     /* RX SFD GPIO Select, value 1-12 */
+#define RX_SFD_GPIO_MASK          (0xf)
+
+/* Bit definitions for the PTP_INTCTL register */
+#define PTP_INT_GPIO_SHIFT        (0)     /* PTP Interrupt GPIO Select */
+#define PTP_INT_GPIO_MASK         (0xf)
+
+/* Bit definitions for the PTP_CLKSRC register */
+#define CLK_SRC_SHIFT             (14)    /* PTP Clock Source Select */
+#define CLK_SRC_MASK              (0x3)
+#define CLK_SRC_PER_SHIFT         (0)     /* PTP Clock Source Period */
+#define CLK_SRC_PER_MASK          (0x7f)
+
+/* Bit definitions for the PTP_OFF register */
+#define PTP_OFFSET_SHIFT          (0)     /* PTP Message offset from preceding header */
+#define PTP_OFFSET_MASK           (0xff)
+
+#endif
diff --git a/ap/os/linux/linux-3.4.x/drivers/net/phy/et1011c.c b/ap/os/linux/linux-3.4.x/drivers/net/phy/et1011c.c
new file mode 100644
index 0000000..a8eb19e
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/net/phy/et1011c.c
@@ -0,0 +1,119 @@
+/*
+ * drivers/net/phy/et1011c.c
+ *
+ * Driver for LSI ET1011C PHYs
+ *
+ * Author: Chaithrika U S
+ *
+ * Copyright (c) 2008 Texas Instruments
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ *
+ */
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/errno.h>
+#include <linux/unistd.h>
+#include <linux/interrupt.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+#include <linux/spinlock.h>
+#include <linux/mm.h>
+#include <linux/module.h>
+#include <linux/mii.h>
+#include <linux/ethtool.h>
+#include <linux/phy.h>
+#include <linux/io.h>
+#include <linux/uaccess.h>
+#include <asm/irq.h>
+
+#define ET1011C_STATUS_REG	(0x1A)
+#define ET1011C_CONFIG_REG	(0x16)
+#define ET1011C_SPEED_MASK		(0x0300)
+#define ET1011C_GIGABIT_SPEED		(0x0200)
+#define ET1011C_TX_FIFO_MASK		(0x3000)
+#define ET1011C_TX_FIFO_DEPTH_8		(0x0000)
+#define ET1011C_TX_FIFO_DEPTH_16	(0x1000)
+#define ET1011C_INTERFACE_MASK		(0x0007)
+#define ET1011C_GMII_INTERFACE		(0x0002)
+#define ET1011C_SYS_CLK_EN		(0x01 << 4)
+
+
+MODULE_DESCRIPTION("LSI ET1011C PHY driver");
+MODULE_AUTHOR("Chaithrika U S");
+MODULE_LICENSE("GPL");
+
+static int et1011c_config_aneg(struct phy_device *phydev)
+{
+	int ctl = 0;
+	ctl = phy_read(phydev, MII_BMCR);
+	if (ctl < 0)
+		return ctl;
+	ctl &= ~(BMCR_FULLDPLX | BMCR_SPEED100 | BMCR_SPEED1000 |
+		 BMCR_ANENABLE);
+	/* First clear the PHY */
+	phy_write(phydev, MII_BMCR, ctl | BMCR_RESET);
+
+	return genphy_config_aneg(phydev);
+}
+
+static int et1011c_read_status(struct phy_device *phydev)
+{
+	int ret;
+	u32 val;
+	static int speed;
+	ret = genphy_read_status(phydev);
+
+	if (speed != phydev->speed) {
+		speed = phydev->speed;
+		val = phy_read(phydev, ET1011C_STATUS_REG);
+		if ((val & ET1011C_SPEED_MASK) ==
+					ET1011C_GIGABIT_SPEED) {
+			val = phy_read(phydev, ET1011C_CONFIG_REG);
+			val &= ~ET1011C_TX_FIFO_MASK;
+			phy_write(phydev, ET1011C_CONFIG_REG, val\
+					| ET1011C_GMII_INTERFACE\
+					| ET1011C_SYS_CLK_EN\
+					| ET1011C_TX_FIFO_DEPTH_16);
+
+		}
+	}
+	return ret;
+}
+
+static struct phy_driver et1011c_driver = {
+	.phy_id		= 0x0282f014,
+	.name		= "ET1011C",
+	.phy_id_mask	= 0xfffffff0,
+	.features	= (PHY_BASIC_FEATURES | SUPPORTED_1000baseT_Full),
+	.flags		= PHY_POLL,
+	.config_aneg	= et1011c_config_aneg,
+	.read_status	= et1011c_read_status,
+	.driver 	= { .owner = THIS_MODULE,},
+};
+
+static int __init et1011c_init(void)
+{
+	return phy_driver_register(&et1011c_driver);
+}
+
+static void __exit et1011c_exit(void)
+{
+	phy_driver_unregister(&et1011c_driver);
+}
+
+module_init(et1011c_init);
+module_exit(et1011c_exit);
+
+static struct mdio_device_id __maybe_unused et1011c_tbl[] = {
+	{ 0x0282f014, 0xfffffff0 },
+	{ }
+};
+
+MODULE_DEVICE_TABLE(mdio, et1011c_tbl);
diff --git a/ap/os/linux/linux-3.4.x/drivers/net/phy/fixed.c b/ap/os/linux/linux-3.4.x/drivers/net/phy/fixed.c
new file mode 100644
index 0000000..633680d
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/net/phy/fixed.c
@@ -0,0 +1,264 @@
+/*
+ * Fixed MDIO bus (MDIO bus emulation with fixed PHYs)
+ *
+ * Author: Vitaly Bordug <vbordug@ru.mvista.com>
+ *         Anton Vorontsov <avorontsov@ru.mvista.com>
+ *
+ * Copyright (c) 2006-2007 MontaVista Software, Inc.
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/list.h>
+#include <linux/mii.h>
+#include <linux/phy.h>
+#include <linux/phy_fixed.h>
+#include <linux/err.h>
+#include <linux/slab.h>
+
+#define MII_REGS_NUM 29
+
+struct fixed_mdio_bus {
+	int irqs[PHY_MAX_ADDR];
+	struct mii_bus *mii_bus;
+	struct list_head phys;
+};
+
+struct fixed_phy {
+	int id;
+	u16 regs[MII_REGS_NUM];
+	struct phy_device *phydev;
+	struct fixed_phy_status status;
+	int (*link_update)(struct net_device *, struct fixed_phy_status *);
+	struct list_head node;
+};
+
+static struct platform_device *pdev;
+static struct fixed_mdio_bus platform_fmb = {
+	.phys = LIST_HEAD_INIT(platform_fmb.phys),
+};
+
+static int fixed_phy_update_regs(struct fixed_phy *fp)
+{
+	u16 bmsr = BMSR_ANEGCAPABLE;
+	u16 bmcr = 0;
+	u16 lpagb = 0;
+	u16 lpa = 0;
+
+	if (fp->status.duplex) {
+		bmcr |= BMCR_FULLDPLX;
+
+		switch (fp->status.speed) {
+		case 1000:
+			bmsr |= BMSR_ESTATEN;
+			bmcr |= BMCR_SPEED1000;
+			lpagb |= LPA_1000FULL;
+			break;
+		case 100:
+			bmsr |= BMSR_100FULL;
+			bmcr |= BMCR_SPEED100;
+			lpa |= LPA_100FULL;
+			break;
+		case 10:
+			bmsr |= BMSR_10FULL;
+			lpa |= LPA_10FULL;
+			break;
+		default:
+			printk(KERN_WARNING "fixed phy: unknown speed\n");
+			return -EINVAL;
+		}
+	} else {
+		switch (fp->status.speed) {
+		case 1000:
+			bmsr |= BMSR_ESTATEN;
+			bmcr |= BMCR_SPEED1000;
+			lpagb |= LPA_1000HALF;
+			break;
+		case 100:
+			bmsr |= BMSR_100HALF;
+			bmcr |= BMCR_SPEED100;
+			lpa |= LPA_100HALF;
+			break;
+		case 10:
+			bmsr |= BMSR_10HALF;
+			lpa |= LPA_10HALF;
+			break;
+		default:
+			printk(KERN_WARNING "fixed phy: unknown speed\n");
+			return -EINVAL;
+		}
+	}
+
+	if (fp->status.link)
+		bmsr |= BMSR_LSTATUS | BMSR_ANEGCOMPLETE;
+
+	if (fp->status.pause)
+		lpa |= LPA_PAUSE_CAP;
+
+	if (fp->status.asym_pause)
+		lpa |= LPA_PAUSE_ASYM;
+
+	fp->regs[MII_PHYSID1] = fp->id >> 16;
+	fp->regs[MII_PHYSID2] = fp->id;
+
+	fp->regs[MII_BMSR] = bmsr;
+	fp->regs[MII_BMCR] = bmcr;
+	fp->regs[MII_LPA] = lpa;
+	fp->regs[MII_STAT1000] = lpagb;
+
+	return 0;
+}
+
+static int fixed_mdio_read(struct mii_bus *bus, int phy_id, int reg_num)
+{
+	struct fixed_mdio_bus *fmb = bus->priv;
+	struct fixed_phy *fp;
+
+	if (reg_num >= MII_REGS_NUM)
+		return -1;
+
+	list_for_each_entry(fp, &fmb->phys, node) {
+		if (fp->id == phy_id) {
+			/* Issue callback if user registered it. */
+			if (fp->link_update) {
+				fp->link_update(fp->phydev->attached_dev,
+						&fp->status);
+				fixed_phy_update_regs(fp);
+			}
+			return fp->regs[reg_num];
+		}
+	}
+
+	return 0xFFFF;
+}
+
+static int fixed_mdio_write(struct mii_bus *bus, int phy_id, int reg_num,
+			    u16 val)
+{
+	return 0;
+}
+
+/*
+ * If something weird is required to be done with link/speed,
+ * network driver is able to assign a function to implement this.
+ * May be useful for PHY's that need to be software-driven.
+ */
+int fixed_phy_set_link_update(struct phy_device *phydev,
+			      int (*link_update)(struct net_device *,
+						 struct fixed_phy_status *))
+{
+	struct fixed_mdio_bus *fmb = &platform_fmb;
+	struct fixed_phy *fp;
+
+	if (!link_update || !phydev || !phydev->bus)
+		return -EINVAL;
+
+	list_for_each_entry(fp, &fmb->phys, node) {
+		if (fp->id == phydev->phy_id) {
+			fp->link_update = link_update;
+			fp->phydev = phydev;
+			return 0;
+		}
+	}
+
+	return -ENOENT;
+}
+EXPORT_SYMBOL_GPL(fixed_phy_set_link_update);
+
+int fixed_phy_add(unsigned int irq, int phy_id,
+		  struct fixed_phy_status *status)
+{
+	int ret;
+	struct fixed_mdio_bus *fmb = &platform_fmb;
+	struct fixed_phy *fp;
+
+	fp = kzalloc(sizeof(*fp), GFP_KERNEL);
+	if (!fp)
+		return -ENOMEM;
+
+	memset(fp->regs, 0xFF,  sizeof(fp->regs[0]) * MII_REGS_NUM);
+
+	fmb->irqs[phy_id] = irq;
+
+	fp->id = phy_id;
+	fp->status = *status;
+
+	ret = fixed_phy_update_regs(fp);
+	if (ret)
+		goto err_regs;
+
+	list_add_tail(&fp->node, &fmb->phys);
+
+	return 0;
+
+err_regs:
+	kfree(fp);
+	return ret;
+}
+EXPORT_SYMBOL_GPL(fixed_phy_add);
+
+static int __init fixed_mdio_bus_init(void)
+{
+	struct fixed_mdio_bus *fmb = &platform_fmb;
+	int ret;
+
+	pdev = platform_device_register_simple("Fixed MDIO bus", 0, NULL, 0);
+	if (IS_ERR(pdev)) {
+		ret = PTR_ERR(pdev);
+		goto err_pdev;
+	}
+
+	fmb->mii_bus = mdiobus_alloc();
+	if (fmb->mii_bus == NULL) {
+		ret = -ENOMEM;
+		goto err_mdiobus_reg;
+	}
+
+	snprintf(fmb->mii_bus->id, MII_BUS_ID_SIZE, "fixed-0");
+	fmb->mii_bus->name = "Fixed MDIO Bus";
+	fmb->mii_bus->priv = fmb;
+	fmb->mii_bus->parent = &pdev->dev;
+	fmb->mii_bus->read = &fixed_mdio_read;
+	fmb->mii_bus->write = &fixed_mdio_write;
+	fmb->mii_bus->irq = fmb->irqs;
+
+	ret = mdiobus_register(fmb->mii_bus);
+	if (ret)
+		goto err_mdiobus_alloc;
+
+	return 0;
+
+err_mdiobus_alloc:
+	mdiobus_free(fmb->mii_bus);
+err_mdiobus_reg:
+	platform_device_unregister(pdev);
+err_pdev:
+	return ret;
+}
+module_init(fixed_mdio_bus_init);
+
+static void __exit fixed_mdio_bus_exit(void)
+{
+	struct fixed_mdio_bus *fmb = &platform_fmb;
+	struct fixed_phy *fp, *tmp;
+
+	mdiobus_unregister(fmb->mii_bus);
+	mdiobus_free(fmb->mii_bus);
+	platform_device_unregister(pdev);
+
+	list_for_each_entry_safe(fp, tmp, &fmb->phys, node) {
+		list_del(&fp->node);
+		kfree(fp);
+	}
+}
+module_exit(fixed_mdio_bus_exit);
+
+MODULE_DESCRIPTION("Fixed MDIO bus (MDIO bus emulation with fixed PHYs)");
+MODULE_AUTHOR("Vitaly Bordug");
+MODULE_LICENSE("GPL");
diff --git a/ap/os/linux/linux-3.4.x/drivers/net/phy/icplus.c b/ap/os/linux/linux-3.4.x/drivers/net/phy/icplus.c
new file mode 100644
index 0000000..5ac46f5
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/net/phy/icplus.c
@@ -0,0 +1,273 @@
+/*
+ * Driver for ICPlus PHYs
+ *
+ * Copyright (c) 2007 Freescale Semiconductor, Inc.
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ *
+ */
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/errno.h>
+#include <linux/unistd.h>
+#include <linux/interrupt.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+#include <linux/spinlock.h>
+#include <linux/mm.h>
+#include <linux/module.h>
+#include <linux/mii.h>
+#include <linux/ethtool.h>
+#include <linux/phy.h>
+
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/uaccess.h>
+
+MODULE_DESCRIPTION("ICPlus IP175C/IP101A/IP101G/IC1001 PHY drivers");
+MODULE_AUTHOR("Michael Barkowski");
+MODULE_LICENSE("GPL");
+
+/* IP101A/G - IP1001 */
+#define IP10XX_SPEC_CTRL_STATUS		16	/* Spec. Control Register */
+#define IP1001_SPEC_CTRL_STATUS_2	20	/* IP1001 Spec. Control Reg 2 */
+#define IP1001_PHASE_SEL_MASK		3	/* IP1001 RX/TXPHASE_SEL */
+#define IP1001_APS_ON			11	/* IP1001 APS Mode  bit */
+#define IP101A_G_APS_ON			2	/* IP101A/G APS Mode bit */
+#define IP101A_G_IRQ_CONF_STATUS	0x11	/* Conf Info IRQ & Status Reg */
+
+static int ip175c_config_init(struct phy_device *phydev)
+{
+	int err, i;
+	static int full_reset_performed = 0;
+
+	if (full_reset_performed == 0) {
+
+		/* master reset */
+		err = mdiobus_write(phydev->bus, 30, 0, 0x175c);
+		if (err < 0)
+			return err;
+
+		/* ensure no bus delays overlap reset period */
+		err = mdiobus_read(phydev->bus, 30, 0);
+
+		/* data sheet specifies reset period is 2 msec */
+		mdelay(2);
+
+		/* enable IP175C mode */
+		err = mdiobus_write(phydev->bus, 29, 31, 0x175c);
+		if (err < 0)
+			return err;
+
+		/* Set MII0 speed and duplex (in PHY mode) */
+		err = mdiobus_write(phydev->bus, 29, 22, 0x420);
+		if (err < 0)
+			return err;
+
+		/* reset switch ports */
+		for (i = 0; i < 5; i++) {
+			err = mdiobus_write(phydev->bus, i,
+					    MII_BMCR, BMCR_RESET);
+			if (err < 0)
+				return err;
+		}
+
+		for (i = 0; i < 5; i++)
+			err = mdiobus_read(phydev->bus, i, MII_BMCR);
+
+		mdelay(2);
+
+		full_reset_performed = 1;
+	}
+
+	if (phydev->addr != 4) {
+		phydev->state = PHY_RUNNING;
+		phydev->speed = SPEED_100;
+		phydev->duplex = DUPLEX_FULL;
+		phydev->link = 1;
+		netif_carrier_on(phydev->attached_dev);
+	}
+
+	return 0;
+}
+
+static int ip1xx_reset(struct phy_device *phydev)
+{
+	int bmcr;
+
+	/* Software Reset PHY */
+	bmcr = phy_read(phydev, MII_BMCR);
+	if (bmcr < 0)
+		return bmcr;
+	bmcr |= BMCR_RESET;
+	bmcr = phy_write(phydev, MII_BMCR, bmcr);
+	if (bmcr < 0)
+		return bmcr;
+
+	do {
+		bmcr = phy_read(phydev, MII_BMCR);
+		if (bmcr < 0)
+			return bmcr;
+	} while (bmcr & BMCR_RESET);
+
+	return 0;
+}
+
+static int ip1001_config_init(struct phy_device *phydev)
+{
+	int c;
+
+	c = ip1xx_reset(phydev);
+	if (c < 0)
+		return c;
+
+	/* Enable Auto Power Saving mode */
+	c = phy_read(phydev, IP1001_SPEC_CTRL_STATUS_2);
+	if (c < 0)
+		return c;
+	c |= IP1001_APS_ON;
+	c = phy_write(phydev, IP1001_SPEC_CTRL_STATUS_2, c);
+	if (c < 0)
+		return c;
+
+	if (phydev->interface == PHY_INTERFACE_MODE_RGMII) {
+		/* Additional delay (2ns) used to adjust RX clock phase
+		 * at RGMII interface */
+		c = phy_read(phydev, IP10XX_SPEC_CTRL_STATUS);
+		if (c < 0)
+			return c;
+
+		c |= IP1001_PHASE_SEL_MASK;
+		c = phy_write(phydev, IP10XX_SPEC_CTRL_STATUS, c);
+		if (c < 0)
+			return c;
+	}
+
+	return 0;
+}
+
+static int ip101a_g_config_init(struct phy_device *phydev)
+{
+	int c;
+
+	c = ip1xx_reset(phydev);
+	if (c < 0)
+		return c;
+
+	/* Enable Auto Power Saving mode */
+	c = phy_read(phydev, IP10XX_SPEC_CTRL_STATUS);
+	c |= IP101A_G_APS_ON;
+
+	return phy_write(phydev, IP10XX_SPEC_CTRL_STATUS, c);
+}
+
+static int ip175c_read_status(struct phy_device *phydev)
+{
+	if (phydev->addr == 4) /* WAN port */
+		genphy_read_status(phydev);
+	else
+		/* Don't need to read status for switch ports */
+		phydev->irq = PHY_IGNORE_INTERRUPT;
+
+	return 0;
+}
+
+static int ip175c_config_aneg(struct phy_device *phydev)
+{
+	if (phydev->addr == 4) /* WAN port */
+		genphy_config_aneg(phydev);
+
+	return 0;
+}
+
+static int ip101a_g_ack_interrupt(struct phy_device *phydev)
+{
+	int err = phy_read(phydev, IP101A_G_IRQ_CONF_STATUS);
+	if (err < 0)
+		return err;
+
+	return 0;
+}
+
+static struct phy_driver ip175c_driver = {
+	.phy_id		= 0x02430d80,
+	.name		= "ICPlus IP175C",
+	.phy_id_mask	= 0x0ffffff0,
+	.features	= PHY_BASIC_FEATURES,
+	.config_init	= &ip175c_config_init,
+	.config_aneg	= &ip175c_config_aneg,
+	.read_status	= &ip175c_read_status,
+	.suspend	= genphy_suspend,
+	.resume		= genphy_resume,
+	.driver		= { .owner = THIS_MODULE,},
+};
+
+static struct phy_driver ip1001_driver = {
+	.phy_id		= 0x02430d90,
+	.name		= "ICPlus IP1001",
+	.phy_id_mask	= 0x0ffffff0,
+	.features	= PHY_GBIT_FEATURES | SUPPORTED_Pause |
+			  SUPPORTED_Asym_Pause,
+	.config_init	= &ip1001_config_init,
+	.config_aneg	= &genphy_config_aneg,
+	.read_status	= &genphy_read_status,
+	.suspend	= genphy_suspend,
+	.resume		= genphy_resume,
+	.driver		= { .owner = THIS_MODULE,},
+};
+
+static struct phy_driver ip101a_g_driver = {
+	.phy_id		= 0x02430c54,
+	.name		= "ICPlus IP101A/G",
+	.phy_id_mask	= 0x0ffffff0,
+	.features	= PHY_BASIC_FEATURES | SUPPORTED_Pause |
+			  SUPPORTED_Asym_Pause,
+	.flags		= PHY_HAS_INTERRUPT,
+	.ack_interrupt	= ip101a_g_ack_interrupt,
+	.config_init	= &ip101a_g_config_init,
+	.config_aneg	= &genphy_config_aneg,
+	.read_status	= &genphy_read_status,
+	.suspend	= genphy_suspend,
+	.resume		= genphy_resume,
+	.driver		= { .owner = THIS_MODULE,},
+};
+
+static int __init icplus_init(void)
+{
+	int ret = 0;
+
+	ret = phy_driver_register(&ip1001_driver);
+	if (ret < 0)
+		return -ENODEV;
+
+	ret = phy_driver_register(&ip101a_g_driver);
+	if (ret < 0)
+		return -ENODEV;
+
+	return phy_driver_register(&ip175c_driver);
+}
+
+static void __exit icplus_exit(void)
+{
+	phy_driver_unregister(&ip1001_driver);
+	phy_driver_unregister(&ip101a_g_driver);
+	phy_driver_unregister(&ip175c_driver);
+}
+
+module_init(icplus_init);
+module_exit(icplus_exit);
+
+static struct mdio_device_id __maybe_unused icplus_tbl[] = {
+	{ 0x02430d80, 0x0ffffff0 },
+	{ 0x02430d90, 0x0ffffff0 },
+	{ 0x02430c54, 0x0ffffff0 },
+	{ }
+};
+
+MODULE_DEVICE_TABLE(mdio, icplus_tbl);
diff --git a/ap/os/linux/linux-3.4.x/drivers/net/phy/icplus/Kconfig b/ap/os/linux/linux-3.4.x/drivers/net/phy/icplus/Kconfig
new file mode 100755
index 0000000..7ba1d2c
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/net/phy/icplus/Kconfig
@@ -0,0 +1,8 @@
+#
+# PHY/SWITCH device configuration
+#
+config IP175L_PHY
+	tristate "Drivers for ICPlus PHYs 175L"
+	---help---
+	  Currently supports the IP175C IP175L and IP1001 PHYs.
+
diff --git a/ap/os/linux/linux-3.4.x/drivers/net/phy/icplus/Makefile b/ap/os/linux/linux-3.4.x/drivers/net/phy/icplus/Makefile
new file mode 100755
index 0000000..9cd0d34
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/net/phy/icplus/Makefile
@@ -0,0 +1,2 @@
+obj-$(CONFIG_IP175L_PHY)	+= icp175l/175d.o
+obj-y += icplus.o
diff --git a/ap/os/linux/linux-3.4.x/drivers/net/phy/icplus/icp175l/175d.c b/ap/os/linux/linux-3.4.x/drivers/net/phy/icplus/icp175l/175d.c
new file mode 100755
index 0000000..ca342b3
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/net/phy/icplus/icp175l/175d.c
@@ -0,0 +1,1651 @@
+#if 0

+

+#if defined(MODVERSIONS)

+#include <linux/modversions.h>

+#endif
+#include <linux/version.h>
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0)
+#include <linux/config.h>
+#elif LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 33)

+#include <linux/autoconf.h>
+#else
+#include <generated/autoconf.h>
+#endif

+#include <linux/init.h>

+#include <linux/errno.h>

+#include <linux/pci.h>

+#include <linux/kernel.h>

+#include <linux/module.h>

+#include <linux/mii.h>

+#include <linux/netdevice.h>

+#include <linux/etherdevice.h>

+#include <linux/skbuff.h>

+#include <linux/spinlock.h>

+#include <asm/dma.h>

+

+#include "ip175d.h"

+

+#define DRV_NAME	"ip175d"

+#define DRV_VERSION	"1.3.0"

+#define DRV_RELDATE	"2014-08-28"

+

+static struct net_device* pNet_dev=NULL;

+

+//#define TEST_REG

+#ifdef TEST_REG

+u16 RegList[32][32];

+#endif

+

+#define Write_Reg(phy,reg,val)	phy_write(phy,reg,val)	//modify this to MII interface

+#define Read_Reg(phy,reg)	phy_read(phy,reg)	//modify this to MII interface

+void phy_write(int phyaddr, int regaddr, int value)	//modify this to MII interface

+{

+#ifdef TEST_REG

+	RegList[phyaddr][regaddr]=value;

+#endif

+}

+u16 phy_read(int phyaddr, int regaddr)			//modify this to MII interface

+{

+#ifdef TEST_REG

+	return RegList[phyaddr][regaddr];

+#endif

+	return 0;

+}

+

+void write_reg_bits(u16 phyaddr,u16 regaddr,u16 bitnum,u16 bitstart,u16 value)

+{

+    u16 reg_val=Read_Reg(phyaddr,regaddr);

+    u16 bitmsk=0,i;

+    for(i=0;i<bitnum;i++){

+        bitmsk|=(u16)0x1<<(i);

+    }

+    reg_val &= ~(bitmsk<<bitstart);

+    reg_val |= (value&bitmsk)<<bitstart;

+	Write_Reg(phyaddr,regaddr,reg_val);

+}

+

+u16 read_reg_bits(u16 phyaddr,u16 regaddr,u16 bitnum,u16 bitstart)

+{

+    u16 reg_val=Read_Reg(phyaddr,regaddr);

+    u16 bitmsk=0,i;

+    for(i=0;i<bitnum;i++){

+        bitmsk|=(u16)0x1<<(i);

+    }

+    return (reg_val>>bitstart)&bitmsk;

+}

+

+

+void VLAN_Set( struct _VLAN_setting *VLAN_setting )

+{	u16 Valid=0x0,FVID=0x0,Reg_Val;

+	int i,j,len=PBASE_VLAN_NUM;

+//	printk("\nVLAN Mode=%d",VLAN_setting->cmd);

+	if(VLAN_setting->vmode != VLAN_MODE_ALL_PBASE){

+		len=TBASE_VLAN_NUM;

+	}

+

+	Reg_Val=Read_Reg(PHY22,VLAN_CLASS);

+/*

+	if(VLAN_setting->vmode)

+	{	Reg_Val |= 0x003f;	}

+	else

+	{	Reg_Val &=~0x003f;	}

+*/

+//	printf("vmode=%x\n",VLAN_setting->vmode);

+	Reg_Val |= VLAN_setting->vmode&0x3f;

+	Reg_Val |= (VLAN_setting->cmode&0x3f) << 6;

+	Write_Reg(PHY22,VLAN_CLASS,Reg_Val);	//set vlan mode

+

+	for(i=0;i<MAX_PORT_NUM;i++){

+//		printf("pvid %d=%d\n",i,VLAN_setting->PVID[i]);

+		Reg_Val=(VLAN_setting->PVID[i] & 0x0fff);

+		Write_Reg(PHY22,VLAN_INFO_0+i, Reg_Val );

+	}                       //set PVID

+	for(i=0;i<len;i++){

+		Reg_Val = 0;

+		if(VLAN_setting->VLAN_entry[i].qos_enable){

+			Reg_Val |= 0x1<<i;

+		}

+	}

+	Write_Reg(PHY22,VLAN_QU_NUM_EN,Reg_Val);

+	for(i=0;i<(len/2);i++)

+	{

+//		printf("member %d=%x\n",i*2,VLAN_setting->VLAN_entry[i*2].member);

+//		printf("member %d=%x\n",i*2+1,VLAN_setting->VLAN_entry[i*2+1].member);

+

+		Reg_Val = (VLAN_setting->VLAN_entry[i*2].member&0x3f) |

+					  ((VLAN_setting->VLAN_entry[i*2+1].member&0x3f)<<8);

+//		reg_setting &=0x003f;

+//		Reg_Val = ( Read_Reg(PHY23,VLAN_MEMBER_00+i/2) );

+//		Reg_Val&= ~(0x00ff<< (8*(i%2)) );

+//		Reg_Val|=reg_setting;

+		Write_Reg(PHY23,VLAN_MEMBER_00+i,Reg_Val) ;	//set VLAN member

+

+//		printf("AddTag %d=%x\n",i*2,VLAN_setting->VLAN_entry[i*2].AddTag);

+//		printf("AddTag %d=%x\n",i*2+1,VLAN_setting->VLAN_entry[i*2+1].AddTag);

+

+		Reg_Val = (VLAN_setting->VLAN_entry[i*2].AddTag&0x3f) |

+						((VLAN_setting->VLAN_entry[i*2+1].AddTag&0x3f)<<8);

+//		reg_setting &=0x003f;

+//		reg_setting<<=(8*(i%2));

+//		Reg_Val = ( Read_Reg(PHY23,VLAN_ADDTAG_00+i/2) );

+//		Reg_Val&= ~(0x00ff<< (8*(i%2)) );

+//		Reg_Val|=reg_setting;

+		Write_Reg(PHY23,VLAN_ADDTAG_00+i,Reg_Val) ;	//set AddTag

+

+//		printf("RmvTag %d=%x\n",i*2,VLAN_setting->VLAN_entry[i*2].RmvTag);

+//		printf("RmvTag %d=%x\n",i*2+1,VLAN_setting->VLAN_entry[i*2+1].RmvTag);

+

+		Reg_Val  = (VLAN_setting->VLAN_entry[i*2].RmvTag&0x3f) |

+						((VLAN_setting->VLAN_entry[i*2+1].RmvTag&0x3f)<<8);

+//		reg_setting &=0x003f;

+//		reg_setting<<=(8*(i%2));

+//		Reg_Val = ( Read_Reg(PHY23,VLAN_REMOVETAG_00+i/2) );

+//		Reg_Val&= ~(0x00ff<< (8*(i%2)) );

+//		Reg_Val|=reg_setting;

+		Write_Reg(PHY23,VLAN_REMOVETAG_00+i,Reg_Val);	//set RemoveTag

+

+		//Set VLAN MISC - QoS.

+		Reg_Val = ((VLAN_setting->VLAN_entry[i*2].queue&0x3)<<2) |

+					((VLAN_setting->VLAN_entry[i*2+1].queue&0x3)<<10);

+		Write_Reg(PHY23,VLAN_MISC_00+i,Reg_Val);

+

+

+		for(j=i*2;j<i*2+2;j++){

+			if(VLAN_setting->vmode&(0x1<<j) || (j>=MAX_PORT_NUM)){

+        		if(VLAN_setting->VLAN_entry[j].valid)

+					{ Valid |= (0x0001<<j); }

+//				printf("VID %d=%x\n",j,VLAN_setting->VLAN_entry[j].VID);

+    			FVID = (VLAN_setting->VLAN_entry[j].VID&0x0fff);

+//				printf("FID %d=%x\n",j,VLAN_setting->VLAN_entry[j].FID);

+				FVID|=((VLAN_setting->VLAN_entry[j].FID&0x000f)<<12);

+    			Write_Reg(PHY22, VLAN_FID_VID0+j ,FVID);    //set FID&VID

+			}

+		}

+

+/*

+		if(i<PBASE_VLAN_NUM)

+		{	Reg_Val=(VLAN_setting->VLAN_entry[i].PVID & 0x0fff);

+			Write_Reg(PHY22,VLAN_INFO_0+i, Reg_Val );

+		}						//set PVID

+*/

+	}

+	Write_Reg(PHY22,VLAN_VALID,Valid);			//set valid

+

+	VLAN_setting->cmd &= VLAN_CMD_OKMASK;

+	VLAN_setting->cmd |= VLAN_CMD_OK;	//command complete

+}

+

+void VLAN_Query( struct _VLAN_setting *VLAN_setting )

+{	u16 Valid=0x0,FVID=0x0,Reg_Val;

+	int i,len=PBASE_VLAN_NUM;

+	VLAN_setting->vmode=( Read_Reg(PHY22,VLAN_CLASS)&0x3f );

+	VLAN_setting->cmode=( Read_Reg(PHY22,VLAN_CLASS)&(0x3f<<6))>>6;

+    if(VLAN_setting->vmode != VLAN_MODE_ALL_PBASE){

+		        len=TBASE_VLAN_NUM;

+	}

+    for(i=0;i<MAX_PORT_NUM;i++){

+		VLAN_setting->PVID[i] = Read_Reg(PHY22,VLAN_INFO_0+i)&0x0fff;

+	}                       //set PVID

+

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

+	{

+        if((i<PBASE_VLAN_NUM)&&(VLAN_setting->vmode&(0x1<<i))){

+			Valid=Read_Reg(PHY22,VLAN_VALID);

+			if(Valid & (0x0001<<i))

+			{ VLAN_setting->VLAN_entry[i].valid=1; }	//query valid port

+

+			FVID=Read_Reg(PHY22, VLAN_FID_VID0+i);

+			VLAN_setting->VLAN_entry[i].VID= (FVID&0x0fff);	//query VID

+			VLAN_setting->VLAN_entry[i].FID=((FVID&0xf000)>>12);//query FID

+		}

+

+		Reg_Val = ( Read_Reg(PHY23,VLAN_MEMBER_00+i/2) >> (8*(i%2)) );

+		Reg_Val&= 0x00ff;

+		VLAN_setting->VLAN_entry[i].member = Reg_Val;	//query VLAM member

+

+		Reg_Val = ( Read_Reg(PHY23,VLAN_ADDTAG_00+i/2) >> (8*(i%2)) );

+		Reg_Val&= 0x00ff;

+		VLAN_setting->VLAN_entry[i].AddTag = Reg_Val;	//query add tag

+

+		Reg_Val = ( Read_Reg(PHY23,VLAN_REMOVETAG_00+i/2) >> (8*(i%2)) );

+		Reg_Val&= 0x00ff;

+		VLAN_setting->VLAN_entry[i].RmvTag = Reg_Val;	//query remove tag

+/*

+		Reg_Val = Read_Reg(PHY22,VLAN_INFO_0);

+		Reg_Val&= 0x0fff;				//query PVID

+		if(i<PBASE_VLAN_NUM)				//(only 6 entries)

+		{	VLAN_setting->VLAN_entry[i].PVID  = Reg_Val;	}

+		else

+		{	VLAN_setting->VLAN_entry[i].PVID  = 0x0;	}

+*/

+	}

+

+	VLAN_setting->cmd &= VLAN_CMD_OKMASK;

+	VLAN_setting->cmd |= VLAN_CMD_OK;	//command complete

+}

+

+#define exchange(a,b)	{		  \

+							u16 t;\

+							t = a;\

+							a = b;\

+							b = t;\

+						}

+

+void QoS_Set(struct _QoS_setting *QoS_setting)

+{	u16 Reg2522=0,Reg2523=0,Reg2511=0,Reg2520=0;

+	u16 Reg2500=0;

+	u16 Regtmp=0;

+	u16 i;

+

+	if(!(QoS_setting->enable)){	//disable QoS function

+		Write_Reg(PHY25,QOS_CTRL,0x0);	return;

+	}

+	else{

+		if(QoS_setting->pri_cos_enable&0x3f){

+			if(QoS_setting->pri_cos_enable == QoS_CLASS_COS_ALL_ENABLE){

+				Reg2500 |= 0x3f<<8;

+				Reg2500 |= 0x1 <14;

+			}

+			else{

+				Reg2500 |= (QoS_setting->pri_cos_enable&0x3f)<<8;

+				Reg2500 |= 0x1 <<14;

+			}

+			for(i=0;i<MAX_COS_PRI_NUM;i++){

+				Regtmp |= (QoS_setting->cos_queue[i]&0xf)<<(2*(i%8));

+				if(((i%8)==7)){

+					Write_Reg(PHY25,QOS_TOS_PRI_0+(i/8),Regtmp);

+					Regtmp=0;

+				}

+			}

+		}

+		if(QoS_setting->priority_class&QoS_CLASS_ACL_ENABLE){

+			Reg2500 |= 0x1 << 7;

+		}

+

+		Write_Reg(PHY25,QOS_CTRL,Reg2500);

+//		Write_Reg(PHY25,QOS_CTRL,0xff80);

+	}

+

+	QoS_setting->mode&=0x3;

+//printk(KERN_ERR"\nQoS mode:%01x",QoS_setting->mode);

+	Reg2522=0x0000;

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

+	{	Reg2522|= ( QoS_setting->mode<<(2*i) );	}

+

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

+	{	QoS_setting->queue_weight[i]&=0xf;

+		Reg2523|= ( QoS_setting->queue_weight[i]<<(4*i) );

+	}

+

+	QoS_setting->type&=0x3;

+	Reg2511|=(QoS_setting->type<<6);

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

+	{	if( QoS_setting->protocol[i].enable )

+		{	Reg2511|= (0x01<<(0+i));		}

+	}

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

+	{	if( QoS_setting->range[i].enable )

+		{	Reg2511|= (0x01<<(4+i));		}

+	}

+

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

+	{	Write_Reg(PHY25,QOS_PRE_LOGI_0+i, QoS_setting->protocol[i].port );	}

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

+	{	if(QoS_setting->range[i].s_port>QoS_setting->range[i].e_port)

+		{ exchange(QoS_setting->range[i].s_port,QoS_setting->range[i].e_port); }

+		Write_Reg(PHY25,QOS_USER_RG_LOW_0+(2*i),QoS_setting->range[i].s_port);

+		Write_Reg(PHY25,QOS_USER_RG_HI_0 +(2*i),QoS_setting->range[i].e_port);

+	}

+

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

+	{	QoS_setting->protocol[i].queue&=0x3;

+		Reg2520|= ( QoS_setting->protocol[i].queue<<(0+i*2) );

+	}

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

+	{	QoS_setting->range[i].queue&=0x3;

+		Reg2520|= ( QoS_setting->range[i].queue<<(8+i*2) );

+	}

+

+//printk(KERN_ERR" reg2522:%04x",Reg2522);

+	Write_Reg(PHY25,QOS_SCH_CONFIG	,Reg2522);

+	Write_Reg(PHY25,QOS_SCH_WEIGHT	,Reg2523);

+	Write_Reg(PHY25,QOS_TCP_CTRL	,Reg2511);

+	Write_Reg(PHY25,QOS_TCP_QU_MAP	,Reg2520);

+	return;

+}

+

+void QoS_Query(struct _QoS_setting *QoS_setting)

+{

+	u16 Reg2500=0;

+	u16 i,j;

+

+	if(Read_Reg(PHY25,QOS_SCH_CONFIG)&0x2000)

+		QoS_setting->enable = 1;

+	Reg2500 = Read_Reg(PHY25,QOS_CTRL);

+

+	QoS_setting->pri_cos_enable = (Reg2500&0x3f00)>>8;

+

+	for(i=0;i<MAX_COS_PRI_NUM;){

+		for(j=0;j<8;j++,i++)

+			QoS_setting->cos_queue[i] =

+				(Read_Reg(PHY25,QOS_TOS_PRI_0+(i/8))&(0x3<<(j*2)))>>(j*2);

+	}

+

+	QoS_setting->type = (Read_Reg(PHY25,QOS_TCP_CTRL)&0xc0)>>6;

+	QoS_setting->mode = (Read_Reg(PHY25,QOS_SCH_CONFIG)&0xc00)>>10;

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

+		QoS_setting->queue_weight[i] = (Read_Reg(PHY25,QOS_SCH_WEIGHT)>>(i*4))&0xf;

+

+	for(i=0;i<MAX_PROTOCOL_NUM;i++){

+		QoS_setting->protocol[i].enable = Read_Reg(PHY25,QOS_TCP_CTRL)&(0x1<<i)? 1:0;

+		QoS_setting->protocol[i].port = Read_Reg(PHY25,QOS_PRE_LOGI_0+i);

+		QoS_setting->protocol[i].queue = (Read_Reg(PHY25,QOS_TCP_QU_MAP)>>(i*2))&0x3;

+	}

+	for(i=0;i<MAX_RANGE_NUM;i++){

+		QoS_setting->range[i].enable = Read_Reg(PHY25,QOS_TCP_CTRL)&(0x1<<(i+4))? 1:0;

+		QoS_setting->range[i].s_port = Read_Reg(PHY25,QOS_USER_RG_LOW_0+(i*2));

+		QoS_setting->range[i].e_port = Read_Reg(PHY25,QOS_USER_RG_LOW_0+(i*2)+1);

+	}

+	return;

+}

+

+u16 MAC_LUT_hash(u8 *mac, u16 entry, u16 fid)

+{

+      u16 tmp;

+      tmp = (fid<<3|mac[0]>>5)^

+                      ((mac[0]&0x1f)<<4|mac[1]>>4)^

+                      ((mac[1]&0x0f)<<5|mac[2]>>3)^

+                      ((mac[2]&0x07)<<6|mac[3]>>2)^

+                      ((mac[3]&0x03)<<7|mac[4]>>1)^

+                      ((mac[4]&0x01)<<8|mac[5]);

+      tmp = tmp << 2 | (entry&0x3);

+      return tmp;

+}

+

+u16 IGMP_LUT_hash(u8 type,u8 *mac, u16 entry, u16 fid)

+{

+	u16 tmp;

+	tmp =	fid^mac[0]^mac[1]^mac[2]^mac[3]^mac[4]^mac[5];//0x5F = 0x5E^0x00^0x01

+	tmp =  (tmp<<2) | (entry&0x3);

+	if (type==LUT_MAC_UNICAST){

+		tmp |= (0x0<<10);

+	}

+	else{

+		tmp |= (0x1<<10);

+	}

+	return tmp;

+}

+

+void IGMP_LUT_Set(struct _MAC_LUT_entry *MAC_LUT_setting)

+{

+	u16 Reg2114=0,Reg2116=0,Reg2117=0,Reg2118=0,Reg2119=0;

+	u16 i,tmpMAC;

+

+  tmpMAC=Read_Reg(PHY20,13);

+  tmpMAC|=(0x1<<3);

+  Write_Reg(PHY20,13,tmpMAC);

+

+	//tmpMAC = (MAC_LUT_setting->MAC[4]<<8)|(MAC_LUT_setting->MAC[5]);

+	tmpMAC = MAC_LUT_setting->MAC[4];	tmpMAC<<=8;

+	tmpMAC|= MAC_LUT_setting->MAC[5];	

+	Write_Reg(PHY21,MAC_ADDR0,tmpMAC);

+	Reg2116 = MAC_LUT_setting->MAC[3]&0x7f;

+	for(i=0;i<2;i++){

+		Reg2116 |= (MAC_LUT_setting->timeout[i]&0x7)<<(8+i*3);

+	}

+	Reg2116 |= (MAC_LUT_setting->timeout[2]&0x3)<<14;

+	Write_Reg(PHY21,MAC_ADDR1,Reg2116);

+

+	Reg2117 = (MAC_LUT_setting->timeout[2]&0x4)>>2;

+    for(i=0;i<3;i++){

+		Reg2117 |= (MAC_LUT_setting->timeout[i+3]&0x7)<<(1+i*3);

+	}

+	Write_Reg(PHY21,MAC_ADDR2,Reg2117);

+

+	Reg2118 |= (MAC_LUT_setting->filter_function&0x3)<<14;

+  Reg2118 |= (MAC_LUT_setting->pri_function&0x3)<<12;

+	Reg2118 |= (MAC_LUT_setting->queue&0x3)<<10;

+	Reg2118 |= (MAC_LUT_setting->fid&0xf)<<6;

+	Reg2118 |= (MAC_LUT_setting->phy_port&0x3f);

+

+	Reg2119 = 0x1 | ((MAC_LUT_setting->valid&0x1)<<1);

+

+	Reg2114 = IGMP_LUT_hash(MAC_LUT_setting->type,MAC_LUT_setting->MAC,MAC_LUT_setting->entry,MAC_LUT_setting->fid);

+

+	Reg2114 |= (0x1)<<11;

+	Reg2114 |= 0x8000;

+

+    Write_Reg(PHY21,MAC_CONTROL,Reg2118);

+    Write_Reg(PHY21,MAC_STATIC,Reg2119);

+    Write_Reg(PHY21,MAC_COMMAND,Reg2114);

+    return;

+}

+

+void IGMP_Entry_Set(u8 *GDA_MACaddr,u8 port_map,u8 add_entry)

+{ struct _MAC_LUT_entry MAC_LUT_setting;

+  u16 i;

+

+//printk(KERN_ERR "\n IGMP_Entry_Set [%x][%x][%x]t[%x]",GDA_MACaddr[0],GDA_MACaddr[1],GDA_MACaddr[2],add_entry);    

+	MAC_LUT_setting.type=LUT_IGMP_MULTICAST;// 0:unicast 1:multicast 2:IGMP

+	MAC_LUT_setting.valid=add_entry;// in unicast: set 1 for static entry, in mcast& igmp: set 1 for valid.

+	if(!add_entry)

+	{  IGMP_LUT_Set(&MAC_LUT_setting);

+	   return;

+  }

+	MAC_LUT_setting.entry=0;//bit 0~1: entry num(0~3)

+	MAC_LUT_setting.fid=0;//0~15

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

+	{  MAC_LUT_setting.MAC[i]=*(GDA_MACaddr+i);

+  }

+	MAC_LUT_setting.age=4; //careless in Multicast

+	MAC_LUT_setting.pri_function=0;//1:match DMAC 2:match SMAC 3:match either DMAC or SMAC

+	//filter_function - 1:drop if SA match 2:ignore VLAN member 3:copy to mirror port if DA match

+	MAC_LUT_setting.filter_function=0;

+	MAC_LUT_setting.queue=0;//0~3

+	MAC_LUT_setting.phy_port=port_map;//unicast- 0:drop 1~6: forward to port0~5

+                           //multicast- bit0~5: forward to port0~5 enable/disable

+                           //IGMP     - bit0~5: forward to port0~5 enable/disable

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

+    MAC_LUT_setting.timeout[i]=1; //MAX time to timeout

+

+  IGMP_LUT_Set(&MAC_LUT_setting);

+}

+

+

+void MAC_LUT_Set(u8 lut_mode,struct _MAC_LUT_entry *MAC_LUT_setting)

+{

+

+	u16 Reg2114=0,Reg2118=0,Reg2119=0;

+	u16 i,tmpMAC;

+

+	for(i=0;i<3;i++){

+		tmpMAC =((MAC_LUT_setting->MAC[i*2])<<8) | ((MAC_LUT_setting->MAC[i*2+1])&0xff);

+		Write_Reg(PHY21,MAC_ADDR2-i,tmpMAC);

+	}

+

+	Reg2118 |= (MAC_LUT_setting->filter_function&0x3)<<14;

+	Reg2118 |= (MAC_LUT_setting->pri_function&0x3)<<12;

+	Reg2118 |= (MAC_LUT_setting->queue&0x3)<<10;

+	Reg2118 |= (MAC_LUT_setting->fid&0xf)<<6;

+

+	if(MAC_LUT_setting->type == LUT_MAC_UNICAST){

+		Reg2118 |= (MAC_LUT_setting->phy_port&0x7)<<3;

+		Reg2118 |= (MAC_LUT_setting->age&0x7);

+		if (MAC_LUT_setting->valid)

+			Reg2119 = 0x2;

+	}

+	else{

+		Reg2118 |= (MAC_LUT_setting->phy_port&0x3f);

+		if (MAC_LUT_setting->valid)

+			Reg2119 = 0x2;

+	}

+	if(lut_mode == LUT_2K){

+		Reg2114 = MAC_LUT_hash(MAC_LUT_setting->MAC,MAC_LUT_setting->entry,MAC_LUT_setting->fid);

+	}

+	else{

+		Reg2114 = IGMP_LUT_hash(MAC_LUT_setting->type,MAC_LUT_setting->MAC,MAC_LUT_setting->entry,MAC_LUT_setting->fid);

+	}

+	Reg2114 |= (0x1)<<11;

+	Reg2114 |= 0x8000;

+

+	Write_Reg(PHY21,MAC_CONTROL,Reg2118);

+	Write_Reg(PHY21,MAC_STATIC,Reg2119);

+	Write_Reg(PHY21,MAC_COMMAND,Reg2114);

+	return;

+}

+

+

+void MAC_LUT_Query(struct _MAC_LUT_entry *MAC_LUT_setting)

+{

+	u16 Reg2114=0;

+

+	Reg2114 = MAC_LUT_hash(MAC_LUT_setting->MAC,MAC_LUT_setting->entry,MAC_LUT_setting->fid);

+	Reg2114 |= (0x2)<<11;

+	Reg2114 |= 0x8000;

+

+	Write_Reg(PHY21,MAC_COMMAND,Reg2114);

+	/*Make sure the data is valid*/

+//	while(!(Read_Reg(PHY21,MAC_COMMAND)&0x2000))

+//		break;

+

+    MAC_LUT_setting->phy_port = (Read_Reg(PHY21,MAC_CONTROL)&0x0038)>>3;

+	if (Read_Reg(PHY21,MAC_STATIC)&0x2){

+		MAC_LUT_setting->valid = 1;

+	}

+	MAC_LUT_setting->pri_function = (Read_Reg(PHY21,MAC_CONTROL)&0x3000)>>12;

+	MAC_LUT_setting->queue = (Read_Reg(PHY21,MAC_CONTROL)&0x0c00)>>10;

+	return;

+}

+

+u8 MAC_Query_portno(u8 *MACaddr)

+{ u8 port_no=0,i;

+  struct _MAC_LUT_entry MAC_LUT_setting;

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

+  MAC_LUT_setting.MAC[i]=*(MACaddr+i);

+  MAC_LUT_setting.entry=0;

+  MAC_LUT_setting.fid=0;  

+  MAC_LUT_Query(&MAC_LUT_setting);

+  port_no=MAC_LUT_setting.phy_port;

+  return port_no;

+}

+

+void IGMP_LUT_Query(struct _MAC_LUT_entry *MAC_LUT_setting)

+{

+	u16 Reg2114=0;

+	u8 type=MAC_LUT_setting->type;

+	Reg2114 = IGMP_LUT_hash(type,MAC_LUT_setting->MAC,MAC_LUT_setting->entry,MAC_LUT_setting->fid);

+//printf("  midx:%03x",Reg2114);

+	Reg2114 |= (0x2)<<11;

+	Reg2114 |= 0x8000;

+

+	Write_Reg(PHY21,MAC_COMMAND,Reg2114);

+	/*Make sure the data is valid*/

+//	while(!(Read_Reg(PHY21,MAC_COMMAND)&0x2000))

+//		break;

+

+//    MAC_LUT_setting->phy_port = (Read_Reg(PHY21,MAC_CONTROL)&0x0038)>>3;

+    MAC_LUT_setting->phy_port = (Read_Reg(PHY21,MAC_CONTROL)&0x003f);

+	if (Read_Reg(PHY21,MAC_STATIC)&0x2){

+		MAC_LUT_setting->valid = 1;

+	}

+	MAC_LUT_setting->pri_function = (Read_Reg(PHY21,MAC_CONTROL)&0x3000)>>12;

+	MAC_LUT_setting->queue = (Read_Reg(PHY21,MAC_CONTROL)&0x0c00)>>10;

+	return;

+}

+u8 MAC_Query_portno_1k1k(u8 *MACaddr,u8 type)

+{ u8 port_no=0,i;

+  struct _MAC_LUT_entry MAC_LUT_setting;

+//printk(KERN_ERR "\n MAC_Query_portno_1k1k [%x][%x][%x]t[%x]",MACaddr[0],MACaddr[1],MACaddr[2],type);  

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

+  MAC_LUT_setting.MAC[i]=*(MACaddr+i);

+  MAC_LUT_setting.entry=0;

+  MAC_LUT_setting.fid=0;  

+  MAC_LUT_setting.type=type;  

+  IGMP_LUT_Query(&MAC_LUT_setting);

+  port_no=MAC_LUT_setting.phy_port;

+  if(type==LUT_MAC_UNICAST)

+	{port_no>>=3; }

+  return port_no;

+}

+

+

+void LUT_Set(struct _LUT_setting *lut)

+{

+	u16 Reg2013=0;

+

+	Reg2013 = Read_Reg(PHY20,LEARNING_CTRL_REG);

+	Reg2013 &= ~(0x9);

+

+	if(lut->lut_mode == LUT_2K){

+		Reg2013 |= 0x1;

+		Write_Reg(PHY20,LEARNING_CTRL_REG,Reg2013);

+		MAC_LUT_Set(lut->lut_mode,&lut->lut_entry);

+	}

+	else{

+		Reg2013 |= 0x9;

+		Write_Reg(PHY20,LEARNING_CTRL_REG,Reg2013);

+		if((lut->lut_entry.type == LUT_MAC_MULTICAST)||

+			(lut->lut_entry.type == LUT_MAC_UNICAST))

+			MAC_LUT_Set(lut->lut_mode,&lut->lut_entry);

+		else if(lut->lut_entry.type==LUT_IGMP_MULTICAST)

+			IGMP_LUT_Set(&lut->lut_entry);

+

+	}

+	return;

+}

+

+int get_valid_MAC_LUT_entry(int idx, u8 type, struct _MAC_LUT_entry *MAC_LUT_setting)

+{

+	int i, j, k, vidx=0xFFFF;

+	u16 Reg2013=0, Reg2114=0;

+	u16 LUT_data[5];

+	u32 u32dat;

+

+	if (idx > 0x7FF)	return -1;

+

+	j = 0x800;

+	Reg2013 = Read_Reg(PHY20, LEARNING_CTRL_REG);

+	if (type == LUT_MAC_UNICAST)

+	{

+		if (Reg2013 & 0x8)

+		{

+			j = 0x400;

+			if (idx >= 0x400)	return -1;

+		}

+	}

+	else

+	{

+		if (Reg2013 & 0x8)

+		{	if (idx < 0x400)	idx = 0x400;	}

+		else

+			return -1;

+	}

+

+	for (i=idx; i < j; i++)

+	{

+		Reg2114 = (i | 0x9000);

+		Write_Reg(PHY21, MAC_COMMAND, Reg2114);

+		do {

+			Reg2114 = Read_Reg(PHY21, MAC_COMMAND);

+		} while ((Reg2114 & 0x2000) == 0);

+

+		for (k=0; k < 5; k++)

+			LUT_data[k] = Read_Reg(PHY21, MAC_ADDR0+k);

+

+		if (LUT_data[4] & 0x2)

+		{

+			if ( (type==LUT_MAC_UNICAST) ||

+			     ( type==LUT_MAC_MULTICAST && !(LUT_data[4]&0x1) ) ||

+			     ( type==LUT_IGMP_MULTICAST && (LUT_data[4]&0x1) ) )

+			{	vidx = i;	break;	}

+		}

+		else

+		{

+			if (type==LUT_MAC_UNICAST && (LUT_data[3] & 0x7))

+			{	vidx = i;	break;	}

+		}

+	}

+

+	if (vidx < 0x800)

+	{

+		if (type == LUT_IGMP_MULTICAST)

+		{

+			MAC_LUT_setting->MAC[0] = 0x01;

+			MAC_LUT_setting->MAC[1] = 0x00;

+			MAC_LUT_setting->MAC[2] = 0x5E;

+			MAC_LUT_setting->MAC[3] = (u8)(LUT_data[1] & 0x7F);

+			MAC_LUT_setting->MAC[4] = (u8)(LUT_data[0] >> 8);

+			MAC_LUT_setting->MAC[5] = (u8)(LUT_data[0] & 0xFF);

+

+			u32dat = (u32)( ((LUT_data[2] << 16) | LUT_data[1]) >> 8 );

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

+			{

+				MAC_LUT_setting->timeout[i] = (u8)(u32dat & 0x7);

+				u32dat = u32dat >> 3;

+			}

+		}

+		else

+		{

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

+			{

+				MAC_LUT_setting->MAC[i] = (u8)(LUT_data[2-(i/2)] >> 8);

+				MAC_LUT_setting->MAC[i+1] = (u8)(LUT_data[2-(i/2)] & 0xFF);

+			}

+		}

+

+		MAC_LUT_setting->valid = (u8)((LUT_data[4] >> 1) & 0x1);

+		MAC_LUT_setting->type  = type;

+		MAC_LUT_setting->entry = (u8)(vidx & 0x3);

+		MAC_LUT_setting->fid   = (u8)((LUT_data[3] >> 6) & 0xF);

+		MAC_LUT_setting->filter_function = (u8)(LUT_data[3] >> 14);

+		MAC_LUT_setting->pri_function = (u8)((LUT_data[3] >> 12) & 0x3);

+		MAC_LUT_setting->queue = (u8)((LUT_data[3] >> 10) & 0x3);

+		if (type == LUT_MAC_UNICAST)

+		{

+			MAC_LUT_setting->phy_port = (u8)((LUT_data[3] >> 3) & 0x7);

+			MAC_LUT_setting->age = (u8)(LUT_data[3] & 0x7);

+		}

+		else

+			MAC_LUT_setting->phy_port = (u8)(LUT_data[3] & 0x3F);

+

+		return vidx;

+	}

+	else

+		return -1;

+}

+

+void igmp_set_func(u16 func)

+{

+    Write_Reg(PHY21,IGMP_CTRL,func);

+}

+u16 igmp_get_func()

+{

+    Read_Reg(PHY21,IGMP_CTRL);

+    return 0;

+}

+void igmp_set_router_port(u8 ports)

+{

+    write_reg_bits(PHY21,IGMP_RP_TIME,6,0,ports);

+}

+u8 igmp_get_router_port()

+{

+    read_reg_bits(PHY21,IGMP_RP_TIME,6,0);

+    return 0;

+}

+void igmp_set_router_timeout(u16 timeout)

+{

+    u16 reg_val=Read_Reg(PHY21,IGMP_RP_TIME);

+	reg_val &= 0x3f;

+    reg_val|=timeout;

+    Write_Reg(PHY21,IGMP_RP_TIME,reg_val);

+}

+u16 igmp_get_router_timeout()

+{

+    return Read_Reg(PHY21,IGMP_RP_TIME)&(~(0x3F));

+}

+void igmp_set_group_timeout(u16 timeout)

+{

+    Write_Reg(PHY21,IGMP_GROUP_TIME,timeout);

+}

+u16 igmp_get_group_timeout()

+{

+    return Read_Reg(PHY21,IGMP_GROUP_TIME);

+}

+

+void IGMP_Set(struct _IGMP_setting *igmp)

+{

+	igmp_set_func(igmp->func);

+	igmp_set_router_port(igmp->router_port);

+	igmp_set_router_timeout(igmp->rp_timeout);

+	igmp_set_group_timeout(igmp->group_timeout);

+}

+

+void IGMP_Query(struct _IGMP_setting *igmp)

+{

+	igmp->func=igmp_get_func();

+	igmp->router_port=igmp_get_router_port();

+	igmp->rp_timeout=igmp_get_router_timeout();

+	igmp->group_timeout=igmp_get_group_timeout();

+}

+void IGMP_Set_Entry(struct _IGMP_entry *igmp)

+{

+	IGMP_Entry_Set(igmp->mac,igmp->port,igmp->type);

+}

+u8 IGMP_Query_Entry(struct _IGMP_entry *igmp)

+{

+	u16 Reg2013 = Read_Reg(PHY20,LEARNING_CTRL_REG);

+	if(igmp->type!=LUT_MAC_UNICAST && !(Reg2013&0x8) )

+		return -EOPNOTSUPP;

+	igmp->port=MAC_Query_portno_1k1k(igmp->mac,igmp->type);

+	return 0;

+}

+

+void ACL_MF_Set(struct _ACL_MF_entry *ACL_MF_setting)

+{

+	u16 Reg2601=0,Reg2609=0,Reg2610=0,Reg2620=0,Reg2613=0,Reg2614=0,Reg2619;

+	u16 tmpAddr,i;

+

+	Reg2619 = Read_Reg(PHY26,MF_VALID);

+	Reg2619 = Reg2619 &(~(0x1<< ACL_MF_setting->index));

+	Reg2619 |= (ACL_MF_setting->valid)<< ACL_MF_setting->index;

+

+	Reg2620 |= ACL_MF_setting->index;

+

+	/* Setup Action*/

+	switch(ACL_MF_setting->action){

+		case ACL_ACTION_RATE_CONTROL:

+			Reg2601 |= (0x1<<14);

+			Write_Reg(PHY26,MF_CREDIT_SIZE,ACL_MF_setting->rate);

+			Write_Reg(PHY26,MF_MBS,0x5EE);

+			break;

+		case ACL_ACTION_MONITOR_RATE:

+			Reg2620 |= 0x0040;

+			Write_Reg(PHY26,MF_ACCESS_CTRL,Reg2620);

+			if(!(Read_Reg(PHY26,MF_OVERFLOW)&(0x1<<ACL_MF_setting->index))){

+				ACL_MF_setting->traffic_count = Read_Reg(PHY26,MF_CNT_MSB);

+				ACL_MF_setting->traffic_count = ACL_MF_setting->traffic_count << 16;

+				ACL_MF_setting->traffic_count |= Read_Reg(PHY26,MF_CNT_LSB);

+			}

+			return;

+		case ACL_ACTION_QUEUE_SET:

+			Reg2609 |= (ACL_MF_setting->queue&0x7) << 9;

+			break;

+		case ACL_ACTION_MIRROR_PORT:

+			Reg2609 |= (0x1<<13);

+			break;

+		case ACL_ACTION_FORWARD_CPU:

+			Reg2609 |= (0x1<<12);

+			break;

+		case ACL_ACTION_DROP:

+			Reg2601 |= (0x1<<15);

+			break;

+		default:

+			break;

+	}

+	Reg2620 |= (0x1)<<3;

+	Reg2620 |= (0x1)<<4;

+	/* Setup Ethernet Type*/

+	if(ACL_MF_setting->function&ACL_FILTER_ETHTYPE_ENABLE){

+		Reg2609 |= (0x1<<15);

+		Write_Reg(PHY26,MF_ET_VALUE,ACL_MF_setting->ether_type);

+	}

+	else{

+		Reg2609 &= ~(0x1<<15);

+	}

+	/* Setup IP Protocol*/

+	if(ACL_MF_setting->function&ACL_FILTER_IP_PROTOCOL_ENABLE){

+		Reg2609 |= (0x1<<8);

+		Reg2609 |= (ACL_MF_setting->ip_protocol&0xff);

+	}

+	else{

+		Reg2609 &= ~(0x1<<8);

+	}

+	/* Setup VLAN/DSCP/ToS Aggregation */

+	if((ACL_MF_setting->function&ACL_FILTER_VLAN_ENABLE)||

+		(ACL_MF_setting->function&ACL_FILTER_COS_ENABLE)){

+		Reg2614 |= (0x1<<7);

+		/* Select VLAN */

+		if(ACL_MF_setting->function&ACL_FILTER_VLAN_ENABLE){

+			Reg2614 |= (0x1<<6);

+			Reg2614 |= ACL_MF_setting->cos_type<<3;

+		}

+		else

+			Reg2614 |= ACL_MF_setting->cos_type;

+		Write_Reg(PHY26,MF_BEHAVIOR,Reg2614);

+	}

+

+	/* Setup Physical Port*/

+	if(ACL_MF_setting->function&ACL_FILTER_PHYPORT_ENABLE){

+		Reg2613 |= (0x1<<15);

+		Reg2613 |= ((ACL_MF_setting->port_num&0x1f)<<10);

+		Write_Reg(PHY26,MF_SP_PORTNUM,Reg2613);

+	}

+

+	/* Setup IP Addressed */

+	if(ACL_MF_setting->function&ACL_FILTER_IP_ADDRESS_ENABLE){

+		switch(ACL_MF_setting->ip_mac_type)

+		{

+			case ACL_FILTER_IP_SINGAL_SOURCE:

+			case ACL_FILTER_IP_SINGAL_DESTINATION:

+			case ACL_FILTER_IP_SINGAL_BOTH:

+				if(ACL_MF_setting->ip_mac_type == ACL_FILTER_IP_SINGAL_SOURCE ||

+					ACL_MF_setting->ip_mac_type == ACL_FILTER_IP_SINGAL_BOTH){

+					Reg2601 |= 0x3 << 10;/*Enable IP field*/

+					for(i=0;i<2;i++){

+						tmpAddr = ACL_MF_setting->sip[i*2]<<8 | ACL_MF_setting->sip[i*2+1];

+						Write_Reg(PHY26,MF_IM_SA1-i,tmpAddr);

+					}

+				}

+				if(ACL_MF_setting->ip_mac_type == ACL_FILTER_IP_SINGAL_DESTINATION ||

+					ACL_MF_setting->ip_mac_type == ACL_FILTER_IP_SINGAL_BOTH){

+					Reg2601 |= 0x3 << 4;

+					for(i=0;i<2;i++){

+						tmpAddr = ACL_MF_setting->eip[i*2]<<8 | ACL_MF_setting->eip[i*2+1];

+						Write_Reg(PHY26,MF_IM_DA1-i,tmpAddr);

+					}

+				}

+				Reg2601 |= 0x3cf;

+				break;

+

+			case ACL_FILTER_IP_RANGE_SOURCE:

+			case ACL_FILTER_IP_RANGE_DESTINATION:

+			case ACL_FILTER_IP_RANGE_BOTH:

+

+				Reg2601 |= 0x1 << 12;

+				Reg2601 |= 0x1 << 11;

+				Reg2601 |= 0x1 << 5;

+

+				if((ACL_MF_setting->ip_mac_type == ACL_FILTER_IP_RANGE_SOURCE) ||

+					(ACL_MF_setting->ip_mac_type == ACL_FILTER_IP_RANGE_BOTH) ){

+					for(i=0;i<4;i++){

+						if (ACL_MF_setting->sip[i] != ACL_MF_setting->eip[i])

+							Reg2601 |= 0x1 << (9-i);

+					}

+					if(ACL_MF_setting->ip_mac_type == ACL_FILTER_IP_RANGE_SOURCE)

+						Reg2601 |= 0xf;

+					Reg2601 |= 0x1 << 10;

+				}

+				if((ACL_MF_setting->ip_mac_type == ACL_FILTER_IP_RANGE_DESTINATION) ||

+					(ACL_MF_setting->ip_mac_type == ACL_FILTER_IP_RANGE_BOTH) ){

+					for(i=0;i<4;i++){

+						if (ACL_MF_setting->sip[i] != ACL_MF_setting->eip[i])

+							Reg2601 |= 0x1 << (3-i);

+					}

+					if(ACL_MF_setting->ip_mac_type == ACL_FILTER_IP_RANGE_DESTINATION)

+						Reg2601 |= 0xf << 6;

+					Reg2601 |= 0x1 << 4;

+				}

+

+    	        for(i=0;i<2;i++){

+        	        tmpAddr = ACL_MF_setting->sip[i*2]<<8 | ACL_MF_setting->sip[i*2+1];

+            	    Write_Reg(PHY26,MF_IM_SA1-i,tmpAddr);

+	            }

+    	        for(i=0;i<2;i++){

+        	        tmpAddr = ACL_MF_setting->eip[i*2]<<8 | ACL_MF_setting->eip[i*2+1];

+            	    Write_Reg(PHY26,MF_IM_DA1-i,tmpAddr);

+	            }

+				break;

+		}/*For ip_mac_type switch statement*/

+	}/*For IP Address enable if statement*/

+

+	/*Setup MAC */

+	if(ACL_MF_setting->function&ACL_FILTER_MAC_ENABLE){

+		switch(ACL_MF_setting->ip_mac_type)

+		{

+            case ACL_FILTER_MAC_SMAC_ENABLE:

+			case ACL_FILTER_MAC_DMAC_ENABLE:

+			case ACL_FILTER_MAC_BOTH_ENABLE:

+				if((ACL_MF_setting->ip_mac_type == ACL_FILTER_MAC_SMAC_ENABLE) ||

+						(ACL_MF_setting->ip_mac_type == ACL_FILTER_MAC_BOTH_ENABLE)){

+					Reg2601 |= (0x1<<11);

+					for(i=0;i<3;i++){

+						tmpAddr = ACL_MF_setting->sMAC[i*2]<<8 | ACL_MF_setting->sMAC[i*2+1];

+						Write_Reg(PHY26,MF_IM_SA2-i,tmpAddr);

+					}

+				}

+				if((ACL_MF_setting->ip_mac_type == ACL_FILTER_MAC_DMAC_ENABLE) ||

+						(ACL_MF_setting->ip_mac_type == ACL_FILTER_MAC_BOTH_ENABLE)){

+					Reg2601 |= (0x1<<5);

+					for(i=0;i<3;i++){

+						tmpAddr = ACL_MF_setting->dMAC[i*2]<<8 | ACL_MF_setting->dMAC[i*2+1];

+						Write_Reg(PHY26,MF_IM_DA2-i,tmpAddr);

+					}

+				}

+				break;

+		}

+	}

+

+	/* Setup Logical Port */

+	if(ACL_MF_setting->function&ACL_FILTER_LOGICAL_PORT_ENABLE){

+		switch(ACL_MF_setting->logical_port_protocol)

+		{

+			case ACL_FILTER_LP_STCP:

+			case ACL_FILTER_LP_SUDP:

+				Reg2610 |= (0x1<<3);

+				if (ACL_MF_setting->logical_port_protocol == ACL_FILTER_LP_SUDP)

+					Reg2610 |= (0x1<<2);

+				Write_Reg(PHY26,MF_LG_SP_NUM,ACL_MF_setting->s_port);

+				break;

+			case ACL_FILTER_LP_DTCP:

+			case ACL_FILTER_LP_DUDP:

+				Reg2610 |= (0x1<<1);

+				if (ACL_MF_setting->logical_port_protocol == ACL_FILTER_LP_DUDP)

+					Reg2610 |= 0x1;

+				Write_Reg(PHY26,MF_LG_DP_NUM,ACL_MF_setting->e_port);

+				break;

+

+			case ACL_FILTER_LP_STCP_DTCP:

+			case ACL_FILTER_LP_STCP_DUDP:

+			case ACL_FILTER_LP_SUDP_DTCP:

+			case ACL_FILTER_LP_SUDP_DUDP:

+				Reg2610 |= (0x1<<3);

+				Reg2610 |= (0x1<<1);

+				if ((ACL_MF_setting->logical_port_protocol == ACL_FILTER_LP_SUDP_DTCP)||

+						(ACL_MF_setting->logical_port_protocol == ACL_FILTER_LP_SUDP_DUDP))

+					Reg2610 |= (0x1<<2);

+				if ((ACL_MF_setting->logical_port_protocol == ACL_FILTER_LP_STCP_DUDP)||

+						(ACL_MF_setting->logical_port_protocol == ACL_FILTER_LP_SUDP_DUDP))

+					Reg2610 |= 0x1;

+				Write_Reg(PHY26,MF_LG_SP_NUM,ACL_MF_setting->s_port);

+				Write_Reg(PHY26,MF_LG_DP_NUM,ACL_MF_setting->e_port);

+				break;

+

+			case ACL_FILTER_LP_RANGE_STCP:

+			case ACL_FILTER_LP_RANGE_SUDP:

+			case ACL_FILTER_LP_RANGE_SBOTH:

+			case ACL_FILTER_LP_RANGE_DTCP:

+            case ACL_FILTER_LP_RANGE_DUDP:

+			case ACL_FILTER_LP_RANGE_DBOTH:

+			case ACL_FILTER_LP_RANGE_BOTH_TCP:

+			case ACL_FILTER_LP_RANGE_BOTH_UDP:

+			case ACL_FILTER_LP_RANGE_BOTH_BOTH:

+				switch(ACL_MF_setting->logical_port_protocol)

+				{

+					case ACL_FILTER_LP_RANGE_STCP:

+						Reg2610 |= (0x1<<3);

+						Reg2610 |= (0x1<<2);

+						break;

+					case ACL_FILTER_LP_RANGE_SUDP:

+						Reg2610 |= (0x1<<3);

+						Reg2610 |= 0x1;

+						break;

+					case ACL_FILTER_LP_RANGE_SBOTH:

+						Reg2610 |= (0x1<<3);

+						Reg2610 |= (0x1<<2);

+						Reg2610 |= 0x1;

+						break;

+					case ACL_FILTER_LP_RANGE_DTCP:

+						Reg2610 |= (0x1<<1);

+						Reg2610 |= (0x1<<2);

+						break;

+					case ACL_FILTER_LP_RANGE_DUDP:

+						Reg2610 |= (0x1<<1);

+						Reg2610 |= 0x1;

+						break;

+					case ACL_FILTER_LP_RANGE_DBOTH:

+						Reg2610 |= (0x1<<1);

+						Reg2610 |= (0x1<<2);

+						Reg2610 |= 0x1;

+						break;

+					case ACL_FILTER_LP_RANGE_BOTH_TCP:

+						Reg2610 |= (0x1<<1);

+						Reg2610 |= (0x1<<3);

+						Reg2610 |= (0x1<<2);

+						break;

+					case ACL_FILTER_LP_RANGE_BOTH_UDP:

+						Reg2610 |= (0x1<<1);

+						Reg2610 |= (0x1<<3);

+						Reg2610 |= 0x1;

+						break;

+					case ACL_FILTER_LP_RANGE_BOTH_BOTH:

+						Reg2610 |= (0x1<<1);

+						Reg2610 |= (0x1<<3);

+						Reg2610 |= (0x1<<2);

+						Reg2610 |= 0x1;

+						break;

+

+				}

+

+				Reg2610 |= (0x1<<4);

+				if(ACL_MF_setting->s_port>ACL_MF_setting->e_port)

+					exchange(ACL_MF_setting->e_port,ACL_MF_setting->s_port);

+

+				Write_Reg(PHY26,MF_LG_SP_NUM,ACL_MF_setting->s_port);

+				Write_Reg(PHY26,MF_LG_DP_NUM,ACL_MF_setting->e_port);

+				break;

+

+			default:

+				break;

+		}/*For logical_port_type switch statement*/

+

+		Write_Reg(PHY26,MF_TCP_UDP,Reg2610);

+	}/*For Logical Port enable if statement*/

+

+	Write_Reg(PHY26,MF_VALID,Reg2619);

+	Write_Reg(PHY26,MF_CLASS,Reg2601);

+	Write_Reg(PHY26,MF_REG9,Reg2609);

+	Write_Reg(PHY26,MF_ACCESS_CTRL,Reg2620);

+	return;

+}

+

+void ACL_MF_Query(struct _ACL_MF_entry *ACL_MF_setting)

+{

+	u16 Reg2620=0;

+	u16 i;

+

+    Reg2620 |= ACL_MF_setting->index;

+    Reg2620 |= (0x1)<<4;

+

+	Write_Reg(PHY26,MF_ACCESS_CTRL,Reg2620);

+

+	ACL_MF_setting->valid = Read_Reg(PHY26,MF_VALID)&(0x1<<ACL_MF_setting->index);

+	if(Read_Reg(PHY26,MF_CLASS)&0x8000)

+		ACL_MF_setting->action = ACL_ACTION_DROP;

+	else{

+		if(Read_Reg(PHY26,MF_CLASS)&0x4000){

+			ACL_MF_setting->action = ACL_ACTION_RATE_CONTROL;

+			ACL_MF_setting->rate = Read_Reg(PHY26,MF_CREDIT_SIZE);

+		}

+		else{

+			switch(Read_Reg(PHY26,MF_REG9)&0x3000)

+			{

+				case 0x1000:

+					ACL_MF_setting->action = ACL_ACTION_FORWARD_CPU;

+					break;

+				case 0x2000:

+					ACL_MF_setting->action = ACL_ACTION_MIRROR_PORT;

+					break;

+			}

+		}

+		if(Read_Reg(PHY26,MF_REG9)&0xe00){

+			ACL_MF_setting->action = ACL_ACTION_QUEUE_SET;

+			ACL_MF_setting->queue = (Read_Reg(PHY26,MF_REG9)&0xe00)>>9;

+		}

+	}

+

+

+	if(Read_Reg(PHY26,MF_REG9)&0x8000){

+		ACL_MF_setting->function |= ACL_FILTER_ETHTYPE_ENABLE;

+		ACL_MF_setting->ether_type = Read_Reg(PHY26,MF_ET_VALUE);

+	}

+	if(Read_Reg(PHY26,MF_REG9)&0x0100){

+		ACL_MF_setting->function |= ACL_FILTER_IP_PROTOCOL_ENABLE;

+		ACL_MF_setting->ip_protocol = Read_Reg(PHY26,MF_REG9)&0xff;

+	}

+	if(Read_Reg(PHY26,MF_SP_PORTNUM)&0x8000){

+		ACL_MF_setting->function |= ACL_FILTER_PHYPORT_ENABLE;

+		ACL_MF_setting->port_num = (Read_Reg(PHY26,MF_SP_PORTNUM)&0x7c00) >>10;

+	}

+	if(Read_Reg(PHY26,MF_BEHAVIOR)&0x0080){

+		if(Read_Reg(PHY26,MF_BEHAVIOR)&0x0040)

+			ACL_MF_setting->function |= ACL_FILTER_VLAN_ENABLE;

+		else

+			ACL_MF_setting->function |= ACL_FILTER_COS_ENABLE;

+

+		if (ACL_MF_setting->function == ACL_FILTER_COS_ENABLE )

+			ACL_MF_setting->cos_type = Read_Reg(PHY26,MF_BEHAVIOR)&0x003F;

+		else

+			ACL_MF_setting->cos_type = (Read_Reg(PHY26,MF_BEHAVIOR)&0x003F) >> 3;

+	}

+	switch(Read_Reg(PHY26,MF_TCP_UDP)&0x001f)

+	{

+		case 0x0002:

+		case 0x0003:

+		case 0x0008:

+		case 0x000a:

+		case 0x000b:

+		case 0x000c:

+		case 0x000e:

+		case 0x000f:

+			ACL_MF_setting->function |= ACL_FILTER_LOGICAL_PORT_ENABLE;

+			switch(Read_Reg(PHY26,MF_TCP_UDP)&0x001f)

+			{

+				case 0x0002:

+					ACL_MF_setting->logical_port_protocol = ACL_FILTER_LP_DTCP;

+					break;

+				case 0x0003:

+					ACL_MF_setting->logical_port_protocol = ACL_FILTER_LP_DUDP;

+					break;

+				case 0x0008:

+					ACL_MF_setting->logical_port_protocol = ACL_FILTER_LP_STCP;

+					break;

+				case 0x000a:

+					ACL_MF_setting->logical_port_protocol = ACL_FILTER_LP_STCP_DTCP;

+					break;

+				case 0x000b:

+					ACL_MF_setting->logical_port_protocol = ACL_FILTER_LP_STCP_DUDP;

+					break;

+				case 0x000c:

+					ACL_MF_setting->logical_port_protocol = ACL_FILTER_LP_SUDP;

+					break;

+				case 0x000e:

+					ACL_MF_setting->logical_port_protocol = ACL_FILTER_LP_SUDP_DTCP;

+					break;

+				case 0x000f:

+					ACL_MF_setting->logical_port_protocol = ACL_FILTER_LP_SUDP_DUDP;

+					break;

+			}

+			if(Read_Reg(PHY26,MF_TCP_UDP)&0x0008)

+				ACL_MF_setting->s_port = Read_Reg(PHY26,MF_LG_SP_NUM)&0xffff;

+			if(Read_Reg(PHY26,MF_TCP_UDP)&0x0002)

+				ACL_MF_setting->e_port = Read_Reg(PHY26,MF_LG_DP_NUM)&0xffff;

+			break;

+

+		case 0x0013:

+		case 0x0016:

+		case 0x0017:

+		case 0x0019:

+		case 0x001b:

+		case 0x001c:

+		case 0x001d:

+		case 0x001e:

+		case 0x001f:

+			ACL_MF_setting->function |= ACL_FILTER_LOGICAL_PORT_ENABLE;

+			switch(Read_Reg(PHY26,MF_TCP_UDP)&0x001f)

+			{

+				case 0x0013:

+					ACL_MF_setting->logical_port_protocol = ACL_FILTER_LP_RANGE_DUDP;

+					break;

+				case 0x0016:

+					ACL_MF_setting->logical_port_protocol = ACL_FILTER_LP_RANGE_DTCP;

+					break;

+				case 0x0017:

+					ACL_MF_setting->logical_port_protocol = ACL_FILTER_LP_RANGE_DBOTH;

+					break;

+				case 0x0019:

+					ACL_MF_setting->logical_port_protocol = ACL_FILTER_LP_RANGE_SUDP;

+					break;

+				case 0x001b:

+					ACL_MF_setting->logical_port_protocol = ACL_FILTER_LP_RANGE_BOTH_UDP;

+					break;

+				case 0x001c:

+					ACL_MF_setting->logical_port_protocol = ACL_FILTER_LP_RANGE_STCP;

+					break;

+				case 0x001d:

+					ACL_MF_setting->logical_port_protocol = ACL_FILTER_LP_RANGE_SBOTH;

+					break;

+				case 0x001e:

+					ACL_MF_setting->logical_port_protocol = ACL_FILTER_LP_RANGE_BOTH_TCP;

+					break;

+				case 0x001f:

+					ACL_MF_setting->logical_port_protocol = ACL_FILTER_LP_RANGE_BOTH_BOTH;

+					break;

+			}

+			ACL_MF_setting->s_port = Read_Reg(PHY26,MF_LG_SP_NUM)&0xffff;

+			ACL_MF_setting->e_port = Read_Reg(PHY26,MF_LG_DP_NUM)&0xffff;

+			break;

+	}

+

+	switch(Read_Reg(PHY26,MF_CLASS)&0x1c30)

+	{

+		case 0x0800:/* sMAC */

+			ACL_MF_setting->ip_mac_type = ACL_FILTER_MAC_SMAC_ENABLE;

+			ACL_MF_setting->function |= ACL_FILTER_MAC_ENABLE;

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

+                ACL_MF_setting->sMAC[i] = (Read_Reg(PHY26,MF_IM_SA2-(i/2))&(0xff<<(((i+1)%2)*8)))>>(((i+1)%2)*8);

+			break;

+		case 0x0020:/* dMAC */

+			ACL_MF_setting->ip_mac_type = ACL_FILTER_MAC_DMAC_ENABLE;

+			ACL_MF_setting->function |= ACL_FILTER_MAC_ENABLE;

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

+                ACL_MF_setting->dMAC[i] = (Read_Reg(PHY26,MF_IM_DA2-(i/2))&(0xff<<(((i+1)%2)*8)))>>(((i+1)%2)*8);

+			break;

+		case 0x0820:/* Both sMAC & dMAC */

+			ACL_MF_setting->ip_mac_type = ACL_FILTER_MAC_BOTH_ENABLE;

+			ACL_MF_setting->function |= ACL_FILTER_MAC_ENABLE;

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

+                ACL_MF_setting->sMAC[i] = (Read_Reg(PHY26,MF_IM_SA2-(i/2))&(0xff<<(((i+1)%2)*8)))>>(((i+1)%2)*8);

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

+                ACL_MF_setting->dMAC[i] = (Read_Reg(PHY26,MF_IM_DA2-(i/2))&(0xff<<(((i+1)%2)*8)))>>(((i+1)%2)*8);

+			break;

+		case 0x0c00:/* source single IP */

+			ACL_MF_setting->ip_mac_type = ACL_FILTER_IP_SINGAL_SOURCE;

+			ACL_MF_setting->function |= ACL_FILTER_IP_ADDRESS_ENABLE;

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

+	            ACL_MF_setting->sip[i] = (Read_Reg(PHY26,MF_IM_SA1-(i/2))&(0xff<<(((i+1)%2)*8)))>>(((i+1)%2)*8);

+			break;

+		case 0x0030:/* Destination single IP */

+			ACL_MF_setting->ip_mac_type = ACL_FILTER_IP_SINGAL_DESTINATION;

+			ACL_MF_setting->function |= ACL_FILTER_IP_ADDRESS_ENABLE;

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

+    	        ACL_MF_setting->eip[i] = (Read_Reg(PHY26,MF_IM_DA1-(i/2))&(0xff<<(((i+1)%2)*8)))>>(((i+1)%2)*8);

+			break;

+		case 0x0c30:

+		case 0x1c30:

+		case 0x1c20:

+		case 0x1830:

+			ACL_MF_setting->function |= ACL_FILTER_IP_ADDRESS_ENABLE;

+			switch(Read_Reg(PHY26,MF_CLASS)&0x1c30)

+			{

+				case 0x0c30:/* source/destination single IP */

+					ACL_MF_setting->ip_mac_type = ACL_FILTER_IP_SINGAL_BOTH;

+					break;

+				case 0x1c30:/* source/destination ranged IP */

+					ACL_MF_setting->ip_mac_type = ACL_FILTER_IP_RANGE_BOTH;

+					break;

+				case 0x1c20:

+					ACL_MF_setting->ip_mac_type = ACL_FILTER_IP_RANGE_SOURCE;

+					break;

+				case 0x1830:

+					ACL_MF_setting->ip_mac_type = ACL_FILTER_IP_RANGE_DESTINATION;

+					break;

+			}

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

+                ACL_MF_setting->sip[i] = (Read_Reg(PHY26,MF_IM_SA1-(i/2))&(0xff<<(((i+1)%2)*8)))>>(((i+1)%2)*8);

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

+                ACL_MF_setting->eip[i] = (Read_Reg(PHY26,MF_IM_DA1-(i/2))&(0xff<<(((i+1)%2)*8)))>>(((i+1)%2)*8);

+			break;

+	}

+	return;

+}

+

+void ACL_Set(struct _ACL_setting *ACL_setting)

+{

+	u16 i,Reg2511=0,Reg2006=0;

+

+	if(ACL_setting->function == ACL_FUNC_PHYPORT){

+		for(i=0;i<MAX_PORT_NUM;i++){

+			if(ACL_setting->port_state[i]&0x1){

+				Reg2006 |= (0x1<<(8+i));

+			}

+			if(ACL_setting->port_state[i]&0x2){

+				Reg2006 |= (0x1<<i);

+			}

+		}

+		Write_Reg(PHY20,PORT_STATE,Reg2006);

+		return;

+	}

+	if(ACL_setting->function == ACL_FUNC_LOGICPORT){

+	    ACL_setting->type&=0x3;

+	    Reg2511|=(ACL_setting->type<<6);

+	    for(i=0;i<MAX_PROTOCOL_NUM;i++){

+			if( ACL_setting->protocol[i].enable ){

+				Reg2511|= (0x01<<(0+i));

+			}

+		}

+	    for(i=0;i<MAX_RANGE_NUM;i++){

+   			if( ACL_setting->range[i].enable ){

+				Reg2511|= (0x01<<(4+i));

+			}

+		}

+	    for(i=0;i<MAX_PROTOCOL_NUM;i++){

+			Write_Reg(PHY25,QOS_PRE_LOGI_0+i, ACL_setting->protocol[i].port );  }

+	    for(i=0;i<MAX_RANGE_NUM;i++){

+			if(ACL_setting->range[i].s_port>ACL_setting->range[i].e_port){

+				exchange(ACL_setting->range[i].s_port,ACL_setting->range[i].e_port);

+			}

+			Write_Reg(PHY25,QOS_USER_RG_LOW_0+(2*i),ACL_setting->range[i].s_port);

+			Write_Reg(PHY25,QOS_USER_RG_HI_0 +(2*i),ACL_setting->range[i].e_port);

+		}

+		Write_Reg(PHY25,QOS_TCP_CTRL    ,Reg2511);

+		Write_Reg(PHY25,QOS_LP_DROP,ACL_setting->lp_drop&0x3f);

+		return ;

+	}

+	if(ACL_setting->function == ACL_FUNC_MULTIFIELD){

+		Write_Reg(PHY26,MF_CTRL,0x8000);

+		for(i=0;i<ACL_MAX_MULTI_ENTRY_NUM;i++){

+			ACL_setting->acl_mf_entry[i].index = (unsigned char)i;

+			if(ACL_setting->acl_mf_entry[i].action)

+				ACL_MF_Set(&ACL_setting->acl_mf_entry[i]);

+		}

+		return ;

+	}

+

+	return;

+}

+

+void ACL_Query(struct _ACL_setting *ACL_setting,int mfIndex)

+{

+    u16 i;

+

+	if(ACL_setting->function == ACL_FUNC_PHYPORT){

+		for(i=0;i<MAX_PORT_NUM;i++){

+			if(Read_Reg(PHY20,PORT_STATE)&(0x1<<(8+i)))

+				ACL_setting->port_state[i] |= 0x1;

+			if(Read_Reg(PHY20,PORT_STATE)&(0x1<<i))

+				ACL_setting->port_state[i] |= 0x2;

+		}

+	}

+

+	if(ACL_setting->function == ACL_FUNC_LOGICPORT){

+	    ACL_setting->type = (Read_Reg(PHY25,QOS_TCP_CTRL)&0xc0)>>6;

+		ACL_setting->lp_drop = (Read_Reg(PHY25,QOS_LP_DROP)&0x3f);

+

+		for(i=0;i<MAX_PROTOCOL_NUM;i++){

+			ACL_setting->protocol[i].enable = Read_Reg(PHY25,QOS_TCP_CTRL)&(0x1<<i)? 1:0;

+			ACL_setting->protocol[i].port = Read_Reg(PHY25,QOS_PRE_LOGI_0+i);

+			ACL_setting->protocol[i].queue = (Read_Reg(PHY25,QOS_TCP_QU_MAP)>>(i*2))&0x3;

+		}

+		for(i=0;i<MAX_RANGE_NUM;i++){

+			ACL_setting->range[i].enable = Read_Reg(PHY25,QOS_TCP_CTRL)&(0x1<<(i+4))? 1:0;

+			ACL_setting->range[i].s_port = Read_Reg(PHY25,QOS_USER_RG_LOW_0+(i*2));

+			ACL_setting->range[i].e_port = Read_Reg(PHY25,QOS_USER_RG_LOW_0+(i*2)+1);

+		}

+	}

+	if(ACL_setting->function == ACL_FUNC_MULTIFIELD){

+//		for(i=0;i<ACL_MAX_MULTI_ENTRY_NUM;i++){

+    	    ACL_setting->acl_mf_entry[mfIndex].index = (unsigned char)mfIndex;

+	        ACL_MF_Query(&ACL_setting->acl_mf_entry[mfIndex]);

+//	    }

+	}

+	return;

+}

+

+void Mirror_Set(struct _Mirror_setting *Mirror_setting)

+{	u16 Reg2020=Read_Reg(PHY20,PORT_MIRROR_0),Reg2021=0;

+	if(!(Mirror_setting->enable))	//disable Mirror function

+	{	Reg2020 &= ~0x8000;

+		Write_Reg(PHY20,PORT_MIRROR_0,Reg2020);

+		return;

+	}

+	else

+	{	Reg2020 = 0x8000;

+	}

+

+	Mirror_setting->mode&=0x3;

+	Reg2020 |= (Mirror_setting->mode<<13);

+

+	Mirror_setting->rx_from%=MAX_MIRROR_PORT;

+	Reg2020 |= (0x01<<Mirror_setting->rx_from);

+

+	Mirror_setting->tx_from%=MAX_MIRROR_PORT;

+	Reg2021 |= (0x01<<Mirror_setting->tx_from);

+

+	Mirror_setting->to%=MAX_MIRROR_PORT;

+	Reg2021 |= (Mirror_setting->to << 12);

+

+	Write_Reg(PHY20,PORT_MIRROR_0,Reg2020);

+	Write_Reg(PHY20,PORT_MIRROR_1,Reg2021);

+}

+

+void Mirror_Query(struct _Mirror_setting *Mirror_setting)

+{	u16 Reg2020=Read_Reg(PHY20,PORT_MIRROR_0);

+	u16 Reg2021=Read_Reg(PHY20,PORT_MIRROR_1);

+	u8  i;

+	if(Reg2020 & 0x8000)

+	{	Mirror_setting->enable=1;	}

+

+	Mirror_setting->mode=  ((Reg2020>>13)&0x3) ;

+

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

+	{

+		if( Reg2020 & (0x01<<i) )

+		{ Mirror_setting->rx_from=i; }

+		if( Reg2021 & (0x01<<i) )

+		{ Mirror_setting->tx_from=i; }

+	}

+

+	Mirror_setting->to = ((Reg2021>>12)&0x7);

+

+}

+

+void Datarate_Set(struct _Datarate_setting *Datarate_setting)

+{	u16 Reg_cmd,Reg_BW_MBS=0xf000,i;

+

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

+	{

+		if(Datarate_setting->tx_rate[i]>DATARATE_MAX_RATE)

+		{Datarate_setting->tx_rate[i]=0;}

+		Write_Reg(PHY21, BW_TI, 0x0001);

+		Write_Reg(PHY21, BW_CREDIT_SIZE, Datarate_setting->tx_rate[i]*(32/8));//32/8bit

+		Write_Reg(PHY21, BW_MBS, Reg_BW_MBS);

+		Reg_cmd= (0x308|i) ; // ( start | write | tx | port )

+		Write_Reg(PHY21, BW_SETTING, Reg_cmd);

+

+		if(Datarate_setting->rx_rate[i]>DATARATE_MAX_RATE)

+		{Datarate_setting->rx_rate[i]=0;}

+		Write_Reg(PHY21, BW_TI, 0x0001);

+		Write_Reg(PHY21, BW_CREDIT_SIZE, Datarate_setting->rx_rate[i]*(32/8));//32/8bit

+		Write_Reg(PHY21, BW_MBS, Reg_BW_MBS);

+		Reg_cmd= (0x300|i) ; // ( start | write | rx | port )

+		Write_Reg(PHY21, BW_SETTING, Reg_cmd);

+	}

+}

+

+void Datarate_Query(struct _Datarate_setting *Datarate_setting)

+{	u16 Reg_cmd,Reg_CREDIT,i;

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

+	{

+		Reg_cmd= (0x208|i) ; // ( start | read | tx | port )

+		Write_Reg(PHY21, BW_SETTING, Reg_cmd);

+		Reg_CREDIT=Read_Reg(PHY21, BW_CREDIT_SIZE);

+		Datarate_setting->tx_rate[i]= ( Reg_CREDIT/(32/8) );

+

+		Reg_cmd= (0x200|i) ; // ( start | read | tx | port )

+		Write_Reg(PHY21, BW_SETTING, Reg_cmd);

+		Reg_CREDIT=Read_Reg(PHY21, BW_CREDIT_SIZE);

+		Datarate_setting->rx_rate[i]= ( Reg_CREDIT/(32/8) );

+	}

+}

+

+void case_HWIGMP(void)

+{

+	Write_Reg(PHY20,LEARNING_CTRL_REG	,0x0028);//(1K unicast & 1K multicast)

+	Write_Reg(PHY21,5		,0x0467);//(enable H/W IGMP & learn router port)

+	Write_Reg(PHY21,6		,0x9640);//(router port timeout=300 seconds)

+	Write_Reg(PHY21,7		,0x9601);//(IGMP timeout=300 seconds)

+}

+

+

+static int os_do_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)

+{

+//	struct mii_ioctl_data *mii = (struct mii_ioctl_data*)&ifr->ifr_data;

+//	printk(KERN_ERR "\n IP175d IOCTL called! (%08x)\n",cmd);

+	switch(cmd)

+	{

+	case	SIOCSMIIREG:	//WriteMDC

+		{

+		struct mii_ioctl_data *mii = (struct mii_ioctl_data*)&ifr->ifr_data;

+		//printk(KERN_ERR"Phy:%d Reg:%d D:%04x",mii->phy_id,mii->reg_num,mii->val_in);

+		Write_Reg(mii->phy_id,mii->reg_num,mii->val_in);

+		}

+		return 0;

+		break;

+	case	SIOCGMIIREG:	//ReadMDC

+		{

+		struct mii_ioctl_data *mii = (struct mii_ioctl_data*)&ifr->ifr_data;

+		//printk(KERN_ERR"Phy:%d Reg:%d",mii->phy_id,mii->reg_num);

+		mii->val_out=Read_Reg(mii->phy_id,mii->reg_num);

+		//printk(KERN_ERR"D:%04x",mii->val_out);

+		}

+		return 0;

+		break;

+	case	SIOCVLAN:	//VLAN Setting

+		{

+		struct _VLAN_setting *VLAN_setting=ifr->ifr_data;

+		if(VLAN_setting->cmd&CMD_WRITE)	//write

+		 {	VLAN_Set(VLAN_setting);		 }

+		else

+		 {	VLAN_Query(VLAN_setting);	 }

+

+		}

+		return 0;

+	case	SIOCQOS:	//QoS Setting

+		{

+		struct _QoS_setting *QoS_setting=ifr->ifr_data;

+//		printk(KERN_ERR" QoS(0x%04x) called!!",SIOCQOS);

+		if(QoS_setting->cmd&CMD_WRITE)	//write

+		 {	QoS_Set(QoS_setting);		 }

+		else

+		 {	QoS_Query(QoS_setting);		 }

+		}

+		return 0;

+	case	SIOCMIRROR:	//Mirror Setting

+		{

+		struct _Mirror_setting *Mirror_setting=ifr->ifr_data;

+		if(Mirror_setting->cmd&CMD_WRITE)	//write

+		 {	Mirror_Set(Mirror_setting);	 }

+		else

+		 {	Mirror_Query(Mirror_setting);	 }

+		}

+		return 0;

+	case	SIOCDATARATE://Datarate Setting

+		{

+		struct _Datarate_setting *Datarate_setting=ifr->ifr_data;

+		if(Datarate_setting->cmd&CMD_WRITE)	//write

+		 {	Datarate_Set(Datarate_setting);	 }

+		else

+		 {	Datarate_Query(Datarate_setting);	 }

+		}

+		return 0;

+

+  case  SIOCLUT:

+  {

+    struct _LUT_setting *lut = ifr->ifr_data;

+    if(lut->cmd&CMD_WRITE)

+        LUT_Set(lut);

+  }

+    return 0;

+

+  case  SIOCACL:

+  {

+    struct  _ACL_setting *acl = ifr->ifr_data;

+    if(acl->cmd&CMD_WRITE){

+      ACL_Set(acl);

+    }

+  }

+  return 0;

+

+  case	SIOCHWIGMP:	//Hardware IGMP setting

+	{

+        struct _IGMP_setting *igmp=ifr->ifr_data;

+        if(igmp->cmd&CMD_WRITE){

+            IGMP_Set(igmp);

+        }

+        else{

+            IGMP_Query(igmp);

+        }

+		return 0;

+	};

+   case SIOCIGMPENT:

+	{

+		struct _IGMP_entry *igmp=ifr->ifr_data;

+        if(igmp->cmd&CMD_WRITE){

+            IGMP_Set_Entry(igmp);

+        }

+        else{

+            IGMP_Query_Entry(igmp);

+        }		

+		return 0;

+	}

+  }

+  return -EOPNOTSUPP;

+}
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0)

+static netdev_tx_t ip175d_xmit(struct sk_buff *skb, struct net_device *dev)

+{

+	dev_kfree_skb(skb);

+	return NETDEV_TX_OK;

+}

+#endif
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 30)
+static const struct net_device_ops ip175d_dev_ops = {
+	.ndo_do_ioctl = &os_do_ioctl,

+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0)

+//fix linux panic in newer versions

+	.ndo_start_xmit = &ip175d_xmit,

+#endif	
+};
+#endif

+

+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)

+static int linux_probe(struct net_device *dev)

+#else

+struct net_device * __init linux_probe(void)

+#endif

+{	u8 MACID[6]={0x00,0x00,0x00,0x00,0x17,0x5d};

+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0)

+	struct net_device* dev;

+	u16 register_err;

+#endif

+

+

+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)

+	dev=init_etherdev(dev,0);	//get device name eth0

+#else

+	dev= alloc_etherdev(sizeof(*dev));	//get device name eth0

+#endif

+	if(!dev)

+	{	printk("\ndriver allocation fail");

+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)

+		return -ENOMEM;

+#else

+		return ERR_PTR(-ENOMEM);

+#endif

+	}

+	pNet_dev=dev;

+	strcpy(dev->name,DRV_NAME);
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 30)
+	dev->netdev_ops		= &ip175d_dev_ops;
+#else

+	dev->do_ioctl		= &os_do_ioctl;
+#endif
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 23)

+	SET_MODULE_OWNER(dev);
+#endif

+	memcpy(dev->dev_addr,MACID,sizeof(MACID));

+

+	printk("\nModule load!");

+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)

+	return 0;

+#else

+	register_err=register_netdev(dev);

+	if( register_err )	//register netdevice fail

+	{	printk("\nregister netdev fail");

+		//release_region(dev->base_addr,2);

+		free_netdev(dev);

+		return(ERR_PTR(register_err));

+	}

+	return dev;

+#endif

+}

+int __init init_module(void)

+{

+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)

+	return linux_probe(0);

+#else

+	linux_probe();

+	return 0;

+#endif

+}

+void __exit cleanup_module(void)

+{

+	printk(KERN_ERR "\nModule");

+//	printk("\nModule(%s)",pNet_dev->name);

+	unregister_netdev(pNet_dev);

+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)

+	kfree(pNet_dev);

+#else

+	free_netdev(pNet_dev);

+#endif

+	printk(KERN_ERR " removed!\n");

+}

+

+//#define I3210

+#ifdef I3210

+module_init(init_module);

+module_exit(cleanup_module);

+#endif

+

+#endif

+

diff --git a/ap/os/linux/linux-3.4.x/drivers/net/phy/icplus/icp175l/ip175d.h b/ap/os/linux/linux-3.4.x/drivers/net/phy/icplus/icp175l/ip175d.h
new file mode 100755
index 0000000..abd8dec
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/net/phy/icplus/icp175l/ip175d.h
@@ -0,0 +1,577 @@
+/******************************************************************************

+*

+*   Name:           switch.h

+*

+*   Description:    SIOC data structure + switch Header

+*

+*   Copyright:      (c) 2005-2050    IC Plus Corp.

+*                   All rights reserved.  By DeNa + Chance

+*

+*******************************************************************************/

+#ifndef _IP175D_H_

+#define _IP175D_H_

+

+#ifndef SIOCDEVPRIV

+#define SIOCDEVPRIV		0x89f0

+#define SIOCVLAN		SIOCDEVPRIV+0x0

+#define SIOCQOS			SIOCDEVPRIV+0x1

+#define SIOCMIRROR		SIOCDEVPRIV+0x2

+#define SIOCDATARATE	SIOCDEVPRIV+0x3

+#define SIOCLUT    	SIOCDEVPRIV+0x4

+#define SIOCACL       	SIOCDEVPRIV+0x5

+

+#define SIOCIGMPENT		SIOCDEVPRIV+0xe

+#define SIOCHWIGMP		SIOCDEVPRIV+0xf

+#endif

+/*

+#ifndef u32

+typedef unsigned long   u32;

+#endif

+#ifndef u16

+typedef unsigned short  u16;

+#endif

+#ifndef u8

+typedef unsigned char   u8;

+#endif

+*/

+#define CMD_WRITE		0x10

+#define CMD_READ		0x00

+

+#define MAX_PORT_NUM	6

+#define MAX_VLAN_NUM	16

+#define TBASE_VLAN_NUM	MAX_VLAN_NUM

+#define PBASE_VLAN_NUM	6

+

+struct _VLAN_entry

+{

+  unsigned char	valid;	//0->disable  !0->Enable

+  unsigned int	VID;	//1~4093

+  unsigned char	FID;	//0~15

+  unsigned char	member;	// bit[5:0] -> P5~P0

+  unsigned char	AddTag;	// bit[5:0] -> P5~P0

+  unsigned char	RmvTag;	// bit[5:0] -> P5~P0

+  unsigned char qos_enable;

+  unsigned char queue;

+//  unsigned int	PVID;	//1~4093

+};

+

+#define VLAN_CMD_TBASE	0x01

+#define VLAN_CMD_PBASE	0x00

+#define VLAN_CMD_MIX	0x02

+

+#define VLAN_MODE_ALL_TBASE	0x3f

+#define VLAN_MODE_ALL_PBASE 0x00

+

+#define VLAN_CMD_OKMASK	0x3f

+#define VLAN_CMD_OK	0x80

+

+struct _VLAN_setting

+{

+  unsigned char	cmd;	//bit4->1:write 0:read , bit0->1:TagVLAN 0:PortBaseVLAN

+  unsigned char	vmode;	//bit[5:0] in write mode:0->PortBaseVLAN !0->TagBase VLAN

+  unsigned char cmode;  //bit[5:0] in vlan mode: 0 - VID classification 1 - PVID classification

+  unsigned int PVID[MAX_PORT_NUM];

+  struct _VLAN_entry VLAN_entry[MAX_VLAN_NUM];

+};

+

+

+#define QoS_QUEUE_0				0x00

+#define QoS_QUEUE_1				0x01

+#define QoS_QUEUE_2				0x02

+#define QoS_QUEUE_3				0x03

+#define QoS_MAX_QUEUE			4

+struct _protocol_entry

+{

+  unsigned char  enable;		// 0: disable  !0: enable

+  unsigned short port;			// TCP/UDP port number

+  unsigned char  queue;			// queue0~3

+};

+

+struct _range_entry

+{

+  unsigned char  enable;		// 0: disable  !0: enable

+  unsigned short s_port;		// TCP/UDP port range start number

+  unsigned short e_port;		// TCP/UDP port range end number

+  unsigned char  queue;			// queue0~3

+};

+

+#define QoS_CLASS_PORT0_ENABLE  0x1

+#define QoS_CLASS_PORT1_ENABLE  0x2

+#define QoS_CLASS_PORT2_ENABLE  0x4

+#define QoS_CLASS_PORT3_ENABLE  0x8

+#define QoS_CLASS_PORT4_ENABLE  0x10

+#define QoS_CLASS_PORT5_ENABLE  0x20

+#define QoS_CLASS_PORT_ALL_ENABLE	0x3f

+

+#define QoS_CLASS_COS0_ENABLE   0x1

+#define QoS_CLASS_COS1_ENABLE   0x2

+#define QoS_CLASS_COS2_ENABLE   0x4

+#define QoS_CLASS_COS3_ENABLE   0x8

+#define QoS_CLASS_COS4_ENABLE   0x10

+#define QoS_CLASS_COS5_ENABLE   0x20

+#define QoS_CLASS_COS_ALL_ENABLE	0x3f

+

+#define QoS_CLASS_ACL_ENABLE        0x1

+#define QoS_CLASS_VLAN_ENABLE       0x2

+#define QoS_CLASS_LP_ENABLE         0x4

+//#define QoS_CLASS_PORT_ALL_ENABLE   0x8

+//#define QoS_CLASS_COS_ALL_ENABLE    0x10

+

+#define QoS_TYPE_DISABLE		0x00

+#define QoS_TYPE_SOURCE			0x01

+#define QoS_TYPE_DESTINATION	0x02

+#define QoS_TYPE_SOURCEnDEST	0x03

+

+#define QoS_MODE_WRR			0x00

+#define QoS_MODE_WFQ			0x01

+#define QoS_MODE_SPM			0x02

+#define QoS_MODE_SP 			0x03

+#define QoS_MODE_HIGH_PASS		QoS_MODE_SP

+

+#define MAX_PROTOCOL_NUM		4

+#define MAX_RANGE_NUM			2

+#define MAX_VLAN_PRI_NUM        8

+#define MAX_COS_PRI_NUM         64

+

+struct _QoS_setting

+{

+  unsigned char	cmd;	//bit4->1:write 0:read

+  unsigned char enable;	// 0:disable !0:enable

+  unsigned char pri_port_enable;//bit0~5 => for port0~5 1:enable 0:disable port-based priority

+  unsigned char pri_cos_enable;//bit0~5 => for port0~5 1:enable 0:disable CoS priority

+  /*  priority_class:priority classification.for each bit 1:enable 0:disable

+   *  bit0:user-defined(ACL) priority/VLAN table priority

+   *  bit1:VLAN priority

+   *  bit2:Logical-port priority

+   *  bit3:port-based priority all port on/off

+   *  bit4:COS-based priority all port on/off

+   */

+  unsigned char priority_class;

+  unsigned char port_based_queue[MAX_PORT_NUM];

+  unsigned char vlan_queue[MAX_VLAN_PRI_NUM];

+  unsigned char cos_queue[MAX_COS_PRI_NUM];

+  unsigned char type;	// 0:disable 1:SA 2:DA 3:DA+SA

+  unsigned char mode;	// 0:WRR	3:High Priority first

+  unsigned int  queue_weight[QoS_MAX_QUEUE];//weight for q0(low)~q3(high) (unit:packet)

+  unsigned int  queue_rate[QoS_MAX_QUEUE];//WFQ:rate for q0(low)~q3(high) (unit:32 Kbps)

+  struct _protocol_entry protocol[MAX_PROTOCOL_NUM];

+  struct _range_entry range[MAX_RANGE_NUM];

+};

+

+#define MAC_LUT_ENABLE      0x1

+#define MAC_LUT_DISABLE     0x0

+

+#define LUT_MAC_UNICAST			0x0

+#define LUT_MAC_MULTICAST		0x1

+#define LUT_IGMP_MULTICAST		0x2

+

+#define LUT_STATIC_ENTRY    0x2

+

+#define MAC_LUT_PRI_DMAC		0x1

+#define MAC_LUT_PRI_SMAC		0x2

+#define MAC_LUT_PRI_BOTH		0x3

+

+#define MAC_LUT_FILTER_SMAC             0x1

+#define MAC_LUT_FILTER_IGNORE_VLAN      0x2

+#define MAC_LUT_FILTER_MIRROR           0x3

+

+struct _MAC_LUT_entry

+{

+	unsigned char valid;// in unicast: set 1 for static entry, in mcast& igmp: set 1 for valid.

+	unsigned char type;// 0:unicast 1:multicast 2:IGMP

+	unsigned char entry;//bit 0~1: entry num(0~3)

+	unsigned char fid;//0~15

+	unsigned char MAC[6];

+	unsigned char age;

+	unsigned char pri_function;//1:match DMAC 2:match SMAC 3:match either DMAC or SMAC

+	//filter_function - 1:drop if SA match 2:ignore VLAN member 3:copy to mirror port if DA match

+	unsigned char filter_function;

+	unsigned char queue;//0~3

+	unsigned char phy_port;//unicast- 0:drop 1~6: forward to port0~5

+                           //multicast- bit0~5: forward to port0~5 enable/disable

+                           //IGMP     - bit0~5: forward to port0~5 enable/disable

+	unsigned char timeout[MAX_PORT_NUM];

+};

+

+#define LUT_2K					0x0

+#define LUT_1K_1K				0x1

+

+struct _LUT_setting

+{

+	unsigned char lut_mode;

+	unsigned char cmd;

+	struct _MAC_LUT_entry lut_entry;

+};

+

+/*

+	func:

+	bit 0 	- HW IGMP snooping                              1:en 0:dis

+	bit 1 	- learn router port automatically 				1:en 0:dis

+	bit 2 	- learn router port even if sip=0.0.0.0 		1:en 0:dis

+	bit 3 	- broadcast "report pkt" to all ports			1:en 0:dis

+	bit 4 	- discard "leave pkt"							1:en 0:dis

+	bit 5~6 - filter mode for unknown IP multicast data		0:discard 1:to CPU 2:flood pkt 3:to router port

+	bit 7	- broadcast IP multicast control pkt			1:en 0:dis

+	bit 8	- broadcast unknown IGMP pkt					1:en 0:dis

+	bit 9	- IP multicast data pkt forward to group member	1:en 0:dis

+			  ports & router ports

+	bit10	- Fast leave									1:en 0:dis

+*/

+void igmp_set_func(u16 func);

+u16 igmp_get_func(void);

+

+/*

+	ports:

+	bit 0~5	-	Default router ports,each bit refers to each port.

+*/

+void igmp_set_router_port(u8 ports);

+u8 igmp_get_router_port(void);

+

+/*

+	Set timeout for router ports

+	timeout = timeout unit * timeout scale(unit:s)

+	bit 0~5 -   Set to 0.

+	bit 6~7	-	timeout unit		0:1s 1:2s 2:4s 3:8s

+	bit 8~15-	timeout scale

+*/

+void igmp_set_router_timeout(u16 timeout);

+u16 igmp_get_router_timeout(void);

+/*

+	Set timeout for group ports

+	timeout = timeout unit * timeout scale(unit:s)

+	bit 0~1	-	timeout unit		0:1s 1:2s 2:4s 3:8s

+	bit 8~15-	timeout scale

+*/

+void igmp_set_group_timeout(u16 timeout);

+u16 igmp_get_group_timeout(void);

+

+struct _IGMP_setting

+{

+    u8  cmd;

+	u16	func;

+	u8	router_port;

+	u16 rp_timeout;

+	u16 group_timeout;

+};

+#define IGMP_DEL_ENTRY  0

+#define IGMP_ADD_ENTRY	1

+struct _IGMP_entry

+{

+	u8 cmd;

+	u8 type;

+	u8 mac[6];

+	u8 port;

+};

+

+#define ACL_MAX_MULTI_ENTRY_NUM 8

+#define ACL_MAX_MACF_NUM        2048

+

+#define ACL_FILTER_PHYPORT_ENABLE       0x1

+#define ACL_FILTER_MAC_ENABLE           0x2

+#define ACL_FILTER_ETHTYPE_ENABLE       0x4

+#define ACL_FILTER_IP_PROTOCOL_ENABLE   0x8

+#define ACL_FILTER_VLAN_ENABLE          0x10

+#define ACL_FILTER_COS_ENABLE           0x20

+#define ACL_FILTER_IP_ADDRESS_ENABLE    0x40

+#define ACL_FILTER_LOGICAL_PORT_ENABLE  0x80

+

+#define ACL_ACTION_RATE_CONTROL         0x1

+#define ACL_ACTION_MONITOR_RATE         0x2

+#define ACL_ACTION_QUEUE_SET            0x3

+#define ACL_ACTION_MIRROR_PORT          0x4

+#define ACL_ACTION_FORWARD_CPU          0x5

+#define ACL_ACTION_DROP                 0x6

+#define ACL_ACTION_FORWARD				0x7

+

+#define ACL_QOS_QUEUE_DIABLE	0x0

+#define ACL_QOS_QUEUE0			0x4

+#define ACL_QOS_QUEUE1			0x5

+#define ACL_QOS_QUEUE2			0x6

+#define ACL_QOS_QUEUE3			0x7

+

+#define ACL_FILTER_IP_MAC_DISABLE           0x0

+#define ACL_FILTER_IP_SINGAL_SOURCE         0x1

+#define ACL_FILTER_IP_SINGAL_DESTINATION    0x2

+#define ACL_FILTER_IP_SINGAL_BOTH           0x3

+#define ACL_FILTER_IP_RANGE_SOURCE          0x4

+#define ACL_FILTER_IP_RANGE_DESTINATION     0x5

+#define ACL_FILTER_IP_RANGE_BOTH            0x6

+#define ACL_FILTER_MAC_SMAC_ENABLE          0x7

+#define ACL_FILTER_MAC_DMAC_ENABLE          0x8

+#define ACL_FILTER_MAC_BOTH_ENABLE          0x9

+

+#define ACL_PHY_PORT0_ENABLE	0x1

+#define ACL_PHY_PORT1_ENABLE	0x2

+#define ACL_PHY_PORT2_ENABLE	0x4

+#define ACL_PHY_PORT3_ENABLE	0x8

+#define ACL_PHY_PORT4_ENABLE	0x10

+#define ACL_PHY_PORT_ALL_ENABLE	0x1f

+

+/* for logical port protocol */

+#define ACL_FILTER_LP_STCP			0x1

+#define ACL_FILTER_LP_SUDP          0x2

+#define ACL_FILTER_LP_DTCP          0x3

+#define ACL_FILTER_LP_DUDP			0x4

+#define ACL_FILTER_LP_STCP_DTCP		0x5

+#define ACL_FILTER_LP_STCP_DUDP		0x6

+#define ACL_FILTER_LP_SUDP_DTCP		0x7

+#define ACL_FILTER_LP_SUDP_DUDP		0x8

+#define ACL_FILTER_LP_RANGE_STCP	0x9

+#define ACL_FILTER_LP_RANGE_SUDP	0xa

+#define ACL_FILTER_LP_RANGE_SBOTH	0xb

+#define ACL_FILTER_LP_RANGE_DTCP	0xc

+#define ACL_FILTER_LP_RANGE_DUDP	0xd

+#define ACL_FILTER_LP_RANGE_DBOTH	0xe

+#define ACL_FILTER_LP_RANGE_BOTH_TCP	0xf

+#define ACL_FILTER_LP_RANGE_BOTH_UDP	0x10

+#define ACL_FILTER_LP_RANGE_BOTH_BOTH	0x11

+

+struct _ACL_MF_entry

+{

+	unsigned char 	index;

+	unsigned char   valid;

+	/*  function:This is for enable/disable each field 1:enable 0:disable

+	 *  bit0:physical port  bit1:MAC

+	 *  bit2:ethernet type  bit3:IP protocol

+	 *  bit4:VLAN           bit5:DSCP/TOS

+	 *  bit6:IP Address     bit7:Logical port

+	 */

+	unsigned char   function;

+	unsigned char   port_num;

+	unsigned short  ether_type;

+	unsigned char   ip_protocol;

+

+	unsigned char   action;

+	unsigned char   queue;

+	unsigned short  rate;// unit:8Kbps

+	unsigned int	traffic_count;// unit:Bytes

+	unsigned char   cos_type;//Class of Service Number:VLAN/DSCP/TOS

+	unsigned short  ip_mac_type;//0:disable 1:source 2:desination 3:both - singal IP mode

+								//4:source  5:destination   6:both       - ranged IP mode

+								//7:source  8:destination   9:both       - MAC mode

+	unsigned char 	logical_port_protocol;

+

+    unsigned char   sMAC[6];

+    unsigned char   dMAC[6];

+    unsigned char   sip[4];

+    unsigned char   eip[4];

+    unsigned short  s_port;

+    unsigned short  e_port;

+};

+

+#define ACL_FUNC_PHYPORT    0x1

+#define ACL_FUNC_LOGICPORT  0x2

+#define ACL_FUNC_MULTIFIELD 0x3

+

+#define ACL_LP_USER0_DROP   0x1

+#define ACL_LP_USER1_DROP   0x2

+#define ACL_LP_PREDEF0_DROP 0x4

+#define ACL_LP_PREDEF1_DROP 0x8

+#define ACL_LP_PREDEF2_DROP 0x10

+#define ACL_LP_PREDEF3_DROP 0x20

+#define ACL_LP_ALL_DROP     0x3f

+

+#define ACL_TYPE_DISABLE        0x00

+#define ACL_TYPE_SOURCE         0x01

+#define ACL_TYPE_DESTINATION    0x02

+#define ACL_TYPE_SOURCEnDEST    0x03

+

+struct _ACL_setting

+{

+	unsigned char cmd;

+	unsigned char function;

+	unsigned char port_state[MAX_PORT_NUM];//bit0:Forwarding bit1:Learning 1:enable 0:disable

+	unsigned char type;

+	unsigned char lp_drop;

+    struct _protocol_entry protocol[MAX_PROTOCOL_NUM];

+    struct _range_entry range[MAX_RANGE_NUM];

+

+	struct _ACL_MF_entry acl_mf_entry[ACL_MAX_MULTI_ENTRY_NUM];

+};

+

+

+#define MAX_MIRROR_PORT		MAX_PORT_NUM

+

+#define MIRROR_MODE_RX		0x0

+#define MIRROR_MODE_TX		0x1

+#define MIRROR_MODE_TX2RX	0x2

+#define MIRROR_MODE_TXnRX	0x3

+struct _Mirror_setting

+{

+  unsigned char	cmd;	// bit4->1:write 0:read

+  unsigned char enable;	// 0:disable !0:enable

+  unsigned char mode;	// 0:rx 1:tx 2:tx_to_rx 3:tx nad rx

+  unsigned char tx_from;// mirror from which port's Tx (p0~p5)

+  unsigned char rx_from;// mirror from which port's Rx (p0~p5)

+  unsigned char to;		// mirror to which port p0~p5

+};

+

+#define DATARATE_MAX_RATE	3124

+struct _Datarate_setting

+{

+  unsigned char	cmd;	// bit4->1:write 0:read

+  unsigned short tx_rate[MAX_PORT_NUM];// per unit is 32Kbps (0~3124 0:full speed)

+  unsigned short rx_rate[MAX_PORT_NUM];// per unit is 32Kbps (0~3124 0:full speed)

+};

+//////////////////////////under is switch ip175d register map/////////////

+

+//PHY Control

+#define		PHY0			0

+#define		PHY_CTRL		0

+#define		PHY_STATUS		1

+#define		PHY_AN_ADV		4

+#define		PHY_AN_LPA		5

+

+

+//HU Table

+#define 	PHY20 			20

+#define		CONG_CTRL		5

+#define		PORT_STATE		6

+#define 	LEARNING_CTRL_REG 	13

+#define		BF_STM_CTRL		16

+#define		BF_STM_THR_0		17

+#define		PORT_MIRROR_0		20

+#define		PORT_MIRROR_1		21

+

+//Rate Control

+#define		PHY21			21//0x0B//21 original 0x11 for FPGA

+#define     IGMP_CTRL       5

+#define     IGMP_RP_TIME    6

+#define     IGMP_GROUP_TIME 7

+#define 	BW_TI			8

+#define 	BW_MBS			9

+#define 	BW_CREDIT_SIZE		10

+#define 	BW_TIME			11

+#define 	BW_SETTING		12

+#define		LEARN_CONSTRAIN		13

+#define		MAC_COMMAND		14

+#define		MAC_ADDR0		15

+#define		MAC_ADDR1		16

+#define		MAC_ADDR2		17

+#define		MAC_CONTROL		18

+#define		MAC_STATIC		19

+#define		CRC_COUNTER		25

+//VLAN Control

+#define 	PHY22			22

+

+#define     VLAN_CLASS                  0

+#define     VLAN_INGRESS                1

+#define     VLAN_EGRESS                 2

+#define     VLAN_INFO_0                 4

+#define     VLAN_INFO_1                 VLAN_INFO_0+1

+#define     VLAN_INFO_2                 VLAN_INFO_0+2

+#define     VLAN_INFO_3                 VLAN_INFO_0+3

+#define     VLAN_INFO_4                 VLAN_INFO_0+4

+#define     VLAN_INFO_5                 VLAN_INFO_0+5

+#define     VLAN_VALID                  10

+#define     VLAN_QU_NUM_EN              11

+#define     VLAN_STP_IDX_EN             12

+#define     VLAN_REW_VALN_PRI_EN        13

+

+#define     VLAN_FID_VID0               14

+#define     VLAN_FID_VID1               VLAN_FID_VID0+1

+#define     VLAN_FID_VID2               VLAN_FID_VID0+2

+#define     VLAN_FID_VID3               VLAN_FID_VID0+3

+#define     VLAN_FID_VID4               VLAN_FID_VID0+4

+#define     VLAN_FID_VID5               VLAN_FID_VID0+5

+#define     VLAN_FID_VID6               VLAN_FID_VID0+6

+#define     VLAN_FID_VID7               VLAN_FID_VID0+7

+#define     VLAN_FID_VID8               VLAN_FID_VID0+8

+#define     VLAN_FID_VID9               VLAN_FID_VID0+9

+#define     VLAN_FID_VID10              VLAN_FID_VID0+10

+#define     VLAN_FID_VID11              VLAN_FID_VID0+11

+#define     VLAN_FID_VID12              VLAN_FID_VID0+12

+#define     VLAN_FID_VID13              VLAN_FID_VID0+13

+#define     VLAN_FID_VID14              VLAN_FID_VID0+14

+#define     VLAN_FID_VID15              VLAN_FID_VID0+15

+

+#define     PHY23                       23

+#define     VLAN_MEMBER_00              00

+#define     VLAN_MEMBER_02              VLAN_MEMBER_00+1

+#define     VLAN_MEMBER_04              VLAN_MEMBER_00+2

+#define     VLAN_MEMBER_06              VLAN_MEMBER_00+3

+#define     VLAN_MEMBER_08              VLAN_MEMBER_00+4

+#define     VLAN_MEMBER_10              VLAN_MEMBER_00+5

+#define     VLAN_MEMBER_12              VLAN_MEMBER_00+6

+#define     VLAN_MEMBER_14              VLAN_MEMBER_00+7

+#define     VLAN_ADDTAG_00              8

+#define     VLAN_ADDTAG_02              VLAN_ADDTAG_00+1

+#define     VLAN_ADDTAG_04              VLAN_ADDTAG_00+2

+#define     VLAN_ADDTAG_06              VLAN_ADDTAG_00+3

+#define     VLAN_ADDTAG_08              VLAN_ADDTAG_00+4

+#define     VLAN_ADDTAG_10              VLAN_ADDTAG_00+5

+#define     VLAN_ADDTAG_12              VLAN_ADDTAG_00+6

+#define     VLAN_ADDTAG_14              VLAN_ADDTAG_00+7

+#define     VLAN_REMOVETAG_00           16

+#define     VLAN_REMOVETAG_02           VLAN_REMOVETAG_00+1

+#define     VLAN_REMOVETAG_04           VLAN_REMOVETAG_00+2

+#define     VLAN_REMOVETAG_06           VLAN_REMOVETAG_00+3

+#define     VLAN_REMOVETAG_08           VLAN_REMOVETAG_00+4

+#define     VLAN_REMOVETAG_10           VLAN_REMOVETAG_00+5

+#define     VLAN_REMOVETAG_12           VLAN_REMOVETAG_00+6

+#define     VLAN_REMOVETAG_14           VLAN_REMOVETAG_00+7

+#define     VLAN_MISC_00                24

+#define     VLAN_MISC_02                VLAN_MISC_00+1

+#define     VLAN_MISC_04                VLAN_MISC_00+2

+#define     VLAN_MISC_06                VLAN_MISC_00+3

+#define     VLAN_MISC_08                VLAN_MISC_00+4

+#define     VLAN_MISC_10                VLAN_MISC_00+5

+#define     VLAN_MISC_12                VLAN_MISC_00+6

+#define     VLAN_MISC_14                VLAN_MISC_00+7

+

+#define		PHY25			25

+#define		QOS_CTRL		0

+#define		QOS_PORT_PRI		1

+#define		QOS_TAG_PRI		2

+#define		QOS_TOS_PRI_0		3

+#define		QOS_TOS_PRI_1		QOS_TOS_PRI_0+1

+#define		QOS_TOS_PRI_2		QOS_TOS_PRI_0+2

+#define		QOS_TOS_PRI_3		QOS_TOS_PRI_0+3

+#define		QOS_TOS_PRI_4		QOS_TOS_PRI_0+4

+#define		QOS_TOS_PRI_5		QOS_TOS_PRI_0+5

+#define		QOS_TOS_PRI_6		QOS_TOS_PRI_0+6

+#define		QOS_TOS_PRI_7		QOS_TOS_PRI_0+7

+#define		QOS_TCP_CTRL		11

+#define		QOS_PRE_LOGI_0		12

+#define		QOS_PRE_LOGI_1		QOS_PRE_LOGI_0+1

+#define		QOS_PRE_LOGI_2		QOS_PRE_LOGI_0+2

+#define		QOS_PRE_LOGI_3		QOS_PRE_LOGI_0+3

+#define		QOS_USER_RG_LOW_0	16

+#define		QOS_USER_RG_HI_0	17

+#define		QOS_USER_RG_LOW_1	QOS_USER_RG_LOW_0+2

+#define		QOS_USER_RG_HI_1	QOS_USER_RG_HI_0+2

+#define		QOS_TCP_QU_MAP		20

+#define		QOS_LP_DROP			21

+#define		QOS_SCH_CONFIG		22

+#define		QOS_SCH_WEIGHT		23

+

+#define     PHY26                       26

+#define     MF_CTRL                     0

+#define     MF_CLASS                    1

+#define     MF_IM_SA0                   2

+#define     MF_IM_SA1                   MF_IM_SA0+1

+#define     MF_IM_SA2                   MF_IM_SA0+2

+#define     MF_IM_DA0                   5

+#define     MF_IM_DA1                   MF_IM_DA0+1

+#define     MF_IM_DA2                   MF_IM_DA0+2

+#define     MF_ET_VALUE                 8

+#define     MF_REG9                     9

+#define     MF_TCP_UDP                  10

+#define     MF_LG_SP_NUM                11

+#define     MF_LG_DP_NUM                12

+#define     MF_SP_PORTNUM               13

+#define     MF_BEHAVIOR                 14

+#define     MF_TI                       15

+#define     MF_MBS                      16

+#define     MF_CREDIT_SIZE              17

+#define     MF_TSEL                     18

+#define     MF_VALID                    19

+#define     MF_ACCESS_CTRL              20

+#define     MF_CNT_LSB                  21

+#define     MF_CNT_MSB                  22

+#define	    MF_OVERFLOW			23

+

+#define     PHY27                       27//0x23

+#define     QUEUE_MONITOR               9

+

+#endif

diff --git a/ap/os/linux/linux-3.4.x/drivers/net/phy/icplus/icplus.c b/ap/os/linux/linux-3.4.x/drivers/net/phy/icplus/icplus.c
new file mode 100755
index 0000000..b379692
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/net/phy/icplus/icplus.c
@@ -0,0 +1,681 @@
+/*
+ * Driver for ICPlus PHYs
+ *
+ * Copyright (c) 2007 Freescale Semiconductor, Inc.
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ *
+ */
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/errno.h>
+#include <linux/unistd.h>
+#include <linux/interrupt.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+#include <linux/spinlock.h>
+#include <linux/mm.h>
+#include <linux/module.h>
+#include <linux/mii.h>
+#include <linux/ethtool.h>
+#include <linux/phy.h>
+#include <linux/gmac/gmac.h>
+
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/uaccess.h>
+
+MODULE_DESCRIPTION("ICPlus IP175C/IP101A/IP101G/IC1001 PHY drivers");
+MODULE_AUTHOR("Michael Barkowski");
+MODULE_LICENSE("GPL");
+
+/* IP101A/G - IP1001 */
+#define IP10XX_SPEC_CTRL_STATUS		16	/* Spec. Control Register */
+#define IP1001_SPEC_CTRL_STATUS_2	20	/* IP1001 Spec. Control Reg 2 */
+#define IP1001_PHASE_SEL_MASK		3	/* IP1001 RX/TXPHASE_SEL */
+#define IP1001_APS_ON			11	/* IP1001 APS Mode  bit */
+#define IP101A_G_APS_ON			2	/* IP101A/G APS Mode bit */
+#define IP101A_G_IRQ_CONF_STATUS	0x11	/* Conf Info IRQ & Status Reg */
+
+/*  Interrupt status Register, page16 register17. */
+#define IP10XX_INT_SR             		        17
+#define IP10XX_INT_SR_INTR_PIN_USED            0x8000
+#define IP10XX_INT_SR_ALL_MASK                 0x800
+#define IP10XX_INT_SR_SPEED_MASK               0x400
+#define IP10XX_INT_SR_DUPLEX_MASK              0x200
+#define IP10XX_INT_SR_LINK_MASK                0x100
+#define IP10XX_INT_SR_INT_STATUS               0x8
+#define IP10XX_INT_SR_SPEED_INT                0x4
+#define IP10XX_INT_SR_DUPLEX_INT               0x2
+#define IP10XX_INT_SR_LINK_INT                 0x1
+
+/*  Interrupt status Register, page16 register29. */
+#define IP10XX_IO_SPEC_CR             		        29
+#define IP10XX_IO_SPEC_CR_SEL_INTR32               0x4
+
+static int ip175c_config_init(struct phy_device *phydev)
+{
+	int err, i;
+	static int full_reset_performed = 0;
+
+	if (full_reset_performed == 0) {
+
+		/* master reset */
+		err = mdiobus_write(phydev->bus, 30, 0, 0x175c);
+		if (err < 0)
+			return err;
+
+		/* ensure no bus delays overlap reset period */
+		err = mdiobus_read(phydev->bus, 30, 0);
+
+		/* data sheet specifies reset period is 2 msec */
+		mdelay(2);
+
+		/* enable IP175C mode */
+		err = mdiobus_write(phydev->bus, 29, 31, 0x175c);
+		if (err < 0)
+			return err;
+
+		/* Set MII0 speed and duplex (in PHY mode) */
+		err = mdiobus_write(phydev->bus, 29, 22, 0x420);
+		if (err < 0)
+			return err;
+
+		/* reset switch ports */
+		for (i = 0; i < 5; i++) {
+			err = mdiobus_write(phydev->bus, i,
+					    MII_BMCR, BMCR_RESET);
+			if (err < 0)
+				return err;
+		}
+
+		for (i = 0; i < 5; i++)
+			err = mdiobus_read(phydev->bus, i, MII_BMCR);
+
+		mdelay(2);
+
+		full_reset_performed = 1;
+	}
+
+	if (phydev->addr != 4) {
+		phydev->state = PHY_RUNNING;
+		phydev->speed = SPEED_100;
+		phydev->duplex = DUPLEX_FULL;
+		phydev->link = 1;
+		netif_carrier_on(phydev->attached_dev);
+	}
+
+	return 0;
+}
+
+#if 1
+static int  ip175l_ports_set(struct phy_device *phydev, int config) 
+{
+	 printk("####ip175l_port_set####\n");//cuichen
+	 mdiobus_write(phydev->bus, 22, 0, 0x07ff); //22.0=0x07FF (Tag based VLAN: Port0-5, PVID classification: Port0-4, VID classification: Port5)
+	if (config) {	
+        // port3 wan
+        /*
+            22.0=0x07FF (Tag based VLAN: Port0-5, PVID classification: Port0-4, VID classification: Port5)
+            22.4=0x0064 (Port0 PVID=100)
+            22.5=0x0064 (Port1 PVID=100)
+            22.6=0x00c8 (Port2 PVID=100)
+            22.7=0x00c8 (Port3 PVID=200)
+            22.10=0x000F (Enable VLAN0-3)
+            22.14=0x0064 (VLAN0 VID=100)
+            22.15=0x0064 (VLAN1 VID=100)
+            22.16=0x0064 (VLAN2 VID=100)
+            22.17=0x00c8 (VLAN3 VID=200)
+            23.0=0x2727 (VLAN0 member: Port0-2 & 5, VLAN1 member: Port0-2 & 5)
+            23.1=0x2827 (VLAN2 member: Port0-2 & 5, VLAN3 member: Port3 & 5)
+            23.8=0x2020 (VLAN0 add tag: port5, VLAN1 add tag: port5)
+            23.9=0x2020 (VLAN2 add tag: port5, VLAN3 add tag: port5)
+            23.16=0x0707 (VLAN0 remove tag: port0-2, VLAN1 remove tag: port0-2)
+            23.17=0x0807 (VLAN2 remove tag: port0-2, VLAN3 remove tag: port3)
+            */
+            //mdiobus_write(phydev->bus, 22, 0, 0x07ff);
+            mdiobus_write(phydev->bus, 22, 4, 0x0064);
+            mdiobus_write(phydev->bus, 22, 5, 0x0064);
+            mdiobus_write(phydev->bus, 22, 6, 0x0064);
+            mdiobus_write(phydev->bus, 22, 7, 0x00c8);
+            mdiobus_write(phydev->bus, 22, 10, 0x000F);
+            mdiobus_write(phydev->bus, 22, 14, 0x0064);
+            mdiobus_write(phydev->bus, 22, 15, 0x0064);
+            mdiobus_write(phydev->bus, 22, 16, 0x0064);
+            mdiobus_write(phydev->bus, 22, 17, 0x00c8);
+            
+            mdiobus_write(phydev->bus, 23, 0, 0x2727);
+            mdiobus_write(phydev->bus, 23, 1, 0x2827);
+            mdiobus_write(phydev->bus, 23, 8, 0x2020);
+            mdiobus_write(phydev->bus, 23, 9, 0x2020);
+            mdiobus_write(phydev->bus, 23, 16, 0x0707);
+            mdiobus_write(phydev->bus, 23, 17, 0x0807);
+	} else {
+		//port3 lan
+	    /*
+	    22.4=0x0064 (Port0 PVID=100)
+            22.5=0x0064 (Port1 PVID=100)
+            22.6=0x0064 (Port2 PVID=100)
+            22.7=0x0064 (Port3 PVID=100)
+            22.10=0x000F (Enable VLAN0-3)
+            22.14=0x0064 (VLAN0 VID=100)
+            22.15=0x0064 (VLAN1 VID=100)
+            22.16=0x0064 (VLAN2 VID=100)
+            22.17=0x0064 (VLAN3 VID=100)
+            23.0=0x2f2f (VLAN0 member: Port0-3 & 5, VLAN1 member: Port0-3 & 5)
+            23.1=0x2f2f (VLAN2 member: Port0-3 & 5, VLAN3 member: Port0-3 & 5)
+            23.8=0x2020 (VLAN0 add tag: port5, VLAN1 add tag: port5)
+            23.9=0x2020 (VLAN2 add tag: port5, VLAN3 add tag: port5)
+            23.16=0x0f0f (VLAN0 remove tag: port0-3, VLAN1 remove tag: port0-3)
+            23.17=0x0f0f (VLAN2 remove tag: port0-3, VLAN3 remove tag: port0-3)
+            */
+	    mdiobus_write(phydev->bus, 22, 4, 0x0064);
+            mdiobus_write(phydev->bus, 22, 5, 0x0064);
+            mdiobus_write(phydev->bus, 22, 6, 0x0064);
+            mdiobus_write(phydev->bus, 22, 7, 0x0064);
+            mdiobus_write(phydev->bus, 22, 10, 0x000F);
+            mdiobus_write(phydev->bus, 22, 14, 0x0064);
+            mdiobus_write(phydev->bus, 22, 15, 0x0064);
+            mdiobus_write(phydev->bus, 22, 16, 0x0064);
+            mdiobus_write(phydev->bus, 22, 17, 0x0064);
+            
+            mdiobus_write(phydev->bus, 23, 0, 0x2f2f);
+            mdiobus_write(phydev->bus, 23, 1, 0x2f2f);
+            mdiobus_write(phydev->bus, 23, 8, 0x2020);
+            mdiobus_write(phydev->bus, 23, 9, 0x2020);
+            mdiobus_write(phydev->bus, 23, 16, 0x0f0f);
+            mdiobus_write(phydev->bus, 23, 17, 0x0f0f);
+	}
+	return 0;
+}
+#endif
+
+static int ip175l_auto_adapt(struct phy_device *phydev, struct ifreq *ifr)
+{
+    	int config = *((int*)ifr->ifr_data);
+	ip175l_ports_set(phydev, config);
+	return 0;
+}
+
+static int ip175l_config_init(struct phy_device *phydev)
+{
+	int err, i;
+	static int full_reset_performed = 0;
+	printk("######175L config_init####\n");
+	if (full_reset_performed == 0) {
+
+		/* master reset */
+		err = mdiobus_write(phydev->bus, 20, 2, 0x175d);
+		if (err < 0)
+			return err;
+
+		/* ensure no bus delays overlap reset period */
+		err = mdiobus_read(phydev->bus, 20, 2);
+
+		/* data sheet specifies reset period is 2 msec */
+		mdelay(2);
+
+		/* enable IP175C mode */
+		//err = mdiobus_write(phydev->bus, 29, 31, 0x175c);
+		//if (err < 0)
+			//return err;
+
+		/* Set MII0 speed and duplex (in PHY mode) */
+		//err = mdiobus_write(phydev->bus, 29, 22, 0x420);
+		//if (err < 0)
+			//return err;
+        /* reset switch ports */ 
+		for (i = 0; i < 4; i++) {
+			int bmcr;
+			bmcr = mdiobus_read(phydev->bus, i, MII_BMCR);
+			if (bmcr < 0)
+		        return bmcr;
+			bmcr |= BMCR_RESET;
+			bmcr = mdiobus_write(phydev->bus, i, MII_BMCR, bmcr);
+			if (bmcr < 0)
+			    return bmcr;
+			do {
+			    bmcr = mdiobus_read(phydev->bus, i, MII_BMCR);
+		        if (bmcr < 0)
+			        return bmcr;
+	        } while (bmcr & BMCR_RESET);
+		}
+		printk("######175L config_init_end####\n");
+		full_reset_performed = 1;
+	}
+
+	/* force mode */
+	if(1)
+	{
+		int force_mode;
+
+		/*force phy mode, be connected to an external mac*/
+		force_mode = mdiobus_read(phydev->bus, 21, 3);
+		force_mode &= ~(1<<11);
+		err = mdiobus_write(phydev->bus, 21, 3, force_mode);
+		if (err < 0)
+			return err;
+
+		/*MAC5 force 100M, full duplex*/
+		force_mode = mdiobus_read(phydev->bus, 20, 4);
+		force_mode |= (1<<15) | (1<<13);
+		err = mdiobus_write(phydev->bus, 20, 4, force_mode);
+		if (err < 0)
+			return err;
+#if 0
+		/*flow control disable of mii0-2*/
+		force_mode = mdiobus_read(phydev->bus, 20, 5);
+		force_mode &= ~1;
+		err = mdiobus_write(phydev->bus, 20, 5, force_mode);
+		if (err < 0)
+			return err;
+
+		/*disable select of port5 mirror port*/
+		force_mode = mdiobus_read(phydev->bus, 21, 4);
+		force_mode |= 0x7<<12;
+		err = mdiobus_write(phydev->bus, 21, 4, force_mode);
+		if (err < 0)
+			return err;
+
+		/*config mii0 phy addr5*/
+		force_mode = mdiobus_read(phydev->bus, 21, 1);
+		force_mode |= 0x10;
+		err = mdiobus_write(phydev->bus, 21, 1, force_mode);
+		if (err < 0)
+			return err;
+#endif
+	}
+
+/*
+22.0=0x07FF (Tag based VLAN: Port0-5, PVID classification: Port0-4, VID classification: Port5)
+22.4=0x0001 (Port0 PVID=1)
+22.5=0x0002 (Port1 PVID=2)
+22.6=0x0003 (Port2 PVID=3)
+22.7=0x0004 (Port3 PVID=4)
+22.10=0x000F (Enable VLAN0-3)
+22.14=0x0001 (VLAN0 VID=1)
+22.15=0x0002 (VLAN1 VID=2)
+22.16=0x0003 (VLAN2 VID=3)
+22.17=0x0004 (VLAN3 VID=4)
+23.0=0x2727 (VLAN0 member: Port0-2 & 5, VLAN1 member: Port0-2 & 5)
+23.1=0x2827 (VLAN2 member: Port0-2 & 5, VLAN3 member: Port3 & 5)
+23.8=0x2020 (VLAN0 add tag: port5, VLAN1 add tag: port5)
+23.9=0x2020 (VLAN2 add tag: port5, VLAN3 add tag: port5)
+23.16=0x0707 (VLAN0 remove tag: port0-2, VLAN1 remove tag: port0-2)
+23.17=0x0807 (VLAN2 remove tag: port0-2, VLAN3 remove tag: port3)
+*/
+	mdiobus_write(phydev->bus, 22, 0, 0x07ff);
+	mdiobus_write(phydev->bus, 22, 4, 0x0064);
+	mdiobus_write(phydev->bus, 22, 5, 0x0064);
+	mdiobus_write(phydev->bus, 22, 6, 0x0064);
+	mdiobus_write(phydev->bus, 22, 7, 0x00c8);
+	mdiobus_write(phydev->bus, 22, 10, 0x000F);
+	mdiobus_write(phydev->bus, 22, 14, 0x0064);
+	mdiobus_write(phydev->bus, 22, 15, 0x0064);
+	mdiobus_write(phydev->bus, 22, 16, 0x0064);
+	mdiobus_write(phydev->bus, 22, 17, 0x00c8);
+
+	mdiobus_write(phydev->bus, 23, 0, 0x2727);
+	mdiobus_write(phydev->bus, 23, 1, 0x2827);
+	mdiobus_write(phydev->bus, 23, 8, 0x2020);
+	mdiobus_write(phydev->bus, 23, 9, 0x2020);
+	mdiobus_write(phydev->bus, 23, 16, 0x0707);
+	mdiobus_write(phydev->bus, 23, 17, 0x0807);
+
+	return 0;
+}
+
+typedef enum
+{
+	eLINK_OFF = 0,
+	eLINK_ON,
+	eLINK_END
+} E_LINK_STATE;
+static E_LINK_STATE ip175l_port_state[4]= {0};
+static E_LINK_STATE phy_port_state =  0;
+extern void gmac_event_notify(GMAC_NOTIFY_EVENT notify_type, void* puf);
+
+static int ip175l_private_proc(struct phy_device *phydev)
+{
+	int err = 0;
+	int i = 0;
+	int islink = 0;
+	int org_lan_status = 0;
+	int org_wan_status = 0;
+	int new_lan_status = 0;
+	int new_wan_status = 0;
+
+	if(phydev->bus == NULL)
+		return 0;
+
+	for(i=0; i<3; i++) {
+		if(ip175l_port_state[i] == 1)
+			org_lan_status = 1; 
+
+		islink = mdiobus_read(phydev->bus, i, 1);
+		islink = (islink&0x4)?1:0;
+			
+		//rtl8306e_port_phyLinkStatus_get(i,&islink);
+		ip175l_port_state[i] = islink;
+		if(islink == 1)
+			new_lan_status = 1;
+	}
+
+	org_wan_status = ip175l_port_state[3];
+	islink = mdiobus_read(phydev->bus, 3, 1);
+	islink = (islink&0x4)?1:0;
+
+	//rtl8306e_port_phyLinkStatus_get(i,&islink);
+	ip175l_port_state[3] = islink;
+	if(islink == 1)
+		new_wan_status = 1;
+
+	//for(i=0;i<4;i++)
+		//printk("port.%d linkstatus=%d. ",i,ip175l_port_state[i]);
+
+	islink = mdiobus_read(phydev->bus, 4, 1);
+	islink = (islink&0x4)?1:0;
+	//printk("port.4 linkstatus=%d. ",islink);
+
+	//printk("port.5 linkstatus=%d.\n",phydev->link);
+
+	if((org_lan_status == 0)&&(new_lan_status == 1))
+		gmac_event_notify(GMAC_ETH_SW_LAN_PLUGIN, NULL);
+
+	if((org_lan_status == 1)&&(new_lan_status == 0))
+		gmac_event_notify(GMAC_ETH_SW_LAN_PLUGOUT, NULL);
+
+	if((org_wan_status == 0)&&(new_wan_status == 1))
+		gmac_event_notify(GMAC_ETH_SW_WAN_PLUGIN, NULL);
+
+	if((org_wan_status == 1)&&(new_wan_status == 0))
+		gmac_event_notify(GMAC_ETH_SW_WAN_PLUGOUT, NULL);
+
+	return err;
+}
+
+
+static int ip101a_g_private_proc(struct phy_device *phydev)
+{
+	int err = 0;
+	int i = 0;
+	int islink = 0;
+	int org_phy_status = 0;
+	int new_phy_status = 0;
+
+	if(phydev->bus == NULL)
+		return 0;
+
+	org_phy_status = phy_port_state;
+	islink = mdiobus_read(phydev->bus, 1, 1);
+	islink = (islink & 0x4)?1:0;
+
+	phy_port_state = islink;
+	if(islink == 1)
+		new_phy_status = 1;
+
+	
+	//printk("port.1 linkstatus=%d. ",phy_port_state);
+
+	//printk("portlinkstatus=%d.\n",phydev->link);
+
+	if((org_phy_status == 0)&&(new_phy_status == 1))
+		gmac_event_notify(GMAC_ETH_PHY_PLUGIN, NULL);
+
+	if((org_phy_status == 1)&&(new_phy_status == 0))
+		gmac_event_notify(GMAC_ETH_PHY_PLUGOUT, NULL);
+
+	return err;
+}
+
+
+static int ip1xx_reset(struct phy_device *phydev)
+{
+	int bmcr;
+
+	/* Software Reset PHY */
+	bmcr = phy_read(phydev, MII_BMCR);
+	if (bmcr < 0)
+		return bmcr;
+	bmcr |= BMCR_RESET;
+	bmcr = phy_write(phydev, MII_BMCR, bmcr);
+	if (bmcr < 0)
+		return bmcr;
+
+	do {
+		bmcr = phy_read(phydev, MII_BMCR);
+		if (bmcr < 0)
+			return bmcr;
+	} while (bmcr & BMCR_RESET);
+
+	return 0;
+}
+
+static int ip1001_config_init(struct phy_device *phydev)
+{
+	int c;
+
+	c = ip1xx_reset(phydev);
+	if (c < 0)
+		return c;
+
+	/* Enable Auto Power Saving mode */
+	c = phy_read(phydev, IP1001_SPEC_CTRL_STATUS_2);
+	if (c < 0)
+		return c;
+	c |= IP1001_APS_ON;
+	c = phy_write(phydev, IP1001_SPEC_CTRL_STATUS_2, c);
+	if (c < 0)
+		return c;
+
+	if (phydev->interface == PHY_INTERFACE_MODE_RGMII) {
+		/* Additional delay (2ns) used to adjust RX clock phase
+		 * at RGMII interface */
+		c = phy_read(phydev, IP10XX_SPEC_CTRL_STATUS);
+		if (c < 0)
+			return c;
+
+		c |= IP1001_PHASE_SEL_MASK;
+		c = phy_write(phydev, IP10XX_SPEC_CTRL_STATUS, c);
+		if (c < 0)
+			return c;
+	}
+
+	return 0;
+}
+
+static int ip101a_g_config_init(struct phy_device *phydev)
+{
+	int c;
+
+	c = ip1xx_reset(phydev);
+	if (c < 0)
+		return c;
+
+	/* Enable Auto Power Saving mode */
+	c = phy_read(phydev, IP10XX_SPEC_CTRL_STATUS);
+	c |= IP101A_G_APS_ON;
+	phy_write(phydev, IP10XX_SPEC_CTRL_STATUS, c);
+
+	/*802.3.az¹Ø±Õ*/
+	phy_write(phydev, 0xd, 0x0007);
+	phy_write(phydev, 0xe, 0x003C);
+	phy_write(phydev, 0xd, 0x4007);
+	phy_write(phydev, 0xe, 0x0000);
+
+	/*enable interrupt*/
+	c = phy_read(phydev, IP10XX_INT_SR);
+    c |= IP10XX_INT_SR_INTR_PIN_USED;
+    c &= ~(IP10XX_INT_SR_ALL_MASK|IP10XX_INT_SR_LINK_MASK);
+	phy_write(phydev, IP10XX_INT_SR, c);
+
+	c = phy_read(phydev, IP10XX_IO_SPEC_CR);
+    c |= IP10XX_IO_SPEC_CR_SEL_INTR32;
+    phy_write(phydev, IP10XX_IO_SPEC_CR, c);	
+
+    //set auto-neg advertisement capabilities to 10/100 half/full
+    c = ADVERTISE_100FULL|ADVERTISE_100HALF|ADVERTISE_10FULL|ADVERTISE_10HALF|ADVERTISE_CSMA;
+    phy_write(phydev, MII_ADVERTISE, c);//0x1E1
+
+    c	= phy_read(phydev, MII_BMCR);
+    c |= BMCR_ANENABLE | BMCR_ANRESTART;
+    phy_write(phydev, MII_BMCR, c);
+
+	return 0;
+}
+
+
+static int ip175c_read_status(struct phy_device *phydev)
+{
+	if (phydev->addr == 4) /* WAN port */
+		genphy_read_status(phydev);
+	else
+		/* Don't need to read status for switch ports */
+		phydev->irq = PHY_IGNORE_INTERRUPT;
+
+	return 0;
+}
+
+static int ip175c_config_aneg(struct phy_device *phydev)
+{
+	if (phydev->addr == 4) /* WAN port */
+		genphy_config_aneg(phydev);
+
+	return 0;
+}
+
+
+static int ip175l_read_status(struct phy_device *phydev)
+{
+	int status;
+
+	status = mdiobus_read(phydev->bus, 21, 1);
+	
+	if ((status & (0x1<<13)) == 0)
+		phydev->link = 0;
+	else
+		phydev->link = 1;
+
+	phydev->speed = SPEED_100;
+	phydev->duplex = DUPLEX_FULL;
+	phydev->pause = phydev->asym_pause = 0;
+
+	return 0;
+}
+
+static int ip175l_config_aneg(struct phy_device *phydev)
+{
+
+	return 0;
+}
+
+static int ip101a_g_ack_interrupt(struct phy_device *phydev)
+{
+	int err = phy_read(phydev, IP101A_G_IRQ_CONF_STATUS);
+	if (err < 0)
+		return err;
+
+	return 0;
+}
+
+static struct phy_driver ip175l_driver = {
+	.phy_id		= 0x02430d80,
+	.name		= "ICPlus IP175L",
+	.phy_id_mask	= 0x0fffffc0,
+	.features	= SUPPORTED_100baseT_Full,
+	.config_init	= &ip175l_config_init,
+	.config_aneg	= &genphy_config_aneg,
+	.read_status	= &ip175l_read_status,
+	.private_proc	= &ip175l_private_proc,
+	.auto_adapt   =  &ip175l_auto_adapt,
+	.suspend	= genphy_suspend,
+	.resume		= genphy_resume,
+	.driver		= { .owner = THIS_MODULE,},
+};
+
+static struct phy_driver ip175c_driver = {
+	.phy_id		= 0x02430d80,
+	.name		= "ICPlus IP175C",
+	.phy_id_mask	= 0x0ffffff0,
+	.features	= PHY_BASIC_FEATURES,
+	.config_init	= &ip175c_config_init,
+	.config_aneg	= &ip175c_config_aneg,
+	.read_status	= &ip175c_read_status,
+	.suspend	= genphy_suspend,
+	.resume		= genphy_resume,
+	.driver		= { .owner = THIS_MODULE,},
+};
+
+static struct phy_driver ip1001_driver = {
+	.phy_id		= 0x02430d90,
+	.name		= "ICPlus IP1001",
+	.phy_id_mask	= 0x0ffffff0,
+	.features	= PHY_GBIT_FEATURES | SUPPORTED_Pause |
+			  SUPPORTED_Asym_Pause,
+	.config_init	= &ip1001_config_init,
+	.config_aneg	= &genphy_config_aneg,
+	.read_status	= &genphy_read_status,
+	.suspend	= genphy_suspend,
+	.resume		= genphy_resume,
+	.driver		= { .owner = THIS_MODULE,},
+};
+
+static struct phy_driver ip101a_g_driver = {
+	.phy_id		= 0x02430c54,
+	.name		= "ICPlus IP101A/G",
+	.phy_id_mask	= 0x0ffffff0,
+	.features	= PHY_BASIC_FEATURES | SUPPORTED_Pause |
+			  SUPPORTED_Asym_Pause,
+	.flags		= PHY_HAS_INTERRUPT,
+	.ack_interrupt	= ip101a_g_ack_interrupt,
+	.config_init	= &ip101a_g_config_init,
+	.config_aneg	= &genphy_config_aneg,
+	.read_status	= &genphy_read_status,
+	.private_proc	= &ip101a_g_private_proc,
+	.suspend	= genphy_suspend,
+	.resume		= genphy_resume,
+	.driver		= { .owner = THIS_MODULE,},
+};
+
+static int __init icplus_init(void)
+{
+	int ret = 0;
+
+	printk(KERN_INFO "icplus ethernet phy driver register\n");
+
+	ret = phy_driver_register(&ip1001_driver);
+	if (ret < 0)
+		return -ENODEV;
+
+	ret = phy_driver_register(&ip101a_g_driver);
+	if (ret < 0)
+		return -ENODEV;
+
+	return phy_driver_register(&ip175l_driver);
+}
+
+static void __exit icplus_exit(void)
+{
+	phy_driver_unregister(&ip1001_driver);
+	phy_driver_unregister(&ip101a_g_driver);
+	//phy_driver_unregister(&ip175c_driver);
+	phy_driver_unregister(&ip175l_driver);
+}
+
+subsys_initcall(icplus_init);
+module_exit(icplus_exit);
+
+static struct mdio_device_id __maybe_unused icplus_tbl[] = {
+	{ 0x02430d80, 0x0ffffff0 },
+	{ 0x02430d90, 0x0ffffff0 },
+	{ 0x02430c54, 0x0ffffff0 },
+	{ }
+};
+
+MODULE_DEVICE_TABLE(mdio, icplus_tbl);
diff --git a/ap/os/linux/linux-3.4.x/drivers/net/phy/lxt.c b/ap/os/linux/linux-3.4.x/drivers/net/phy/lxt.c
new file mode 100644
index 0000000..6f6e8b6
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/net/phy/lxt.c
@@ -0,0 +1,233 @@
+/*
+ * drivers/net/phy/lxt.c
+ *
+ * Driver for Intel LXT PHYs
+ *
+ * Author: Andy Fleming
+ *
+ * Copyright (c) 2004 Freescale Semiconductor, Inc.
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ *
+ */
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/errno.h>
+#include <linux/unistd.h>
+#include <linux/interrupt.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+#include <linux/spinlock.h>
+#include <linux/mm.h>
+#include <linux/module.h>
+#include <linux/mii.h>
+#include <linux/ethtool.h>
+#include <linux/phy.h>
+
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/uaccess.h>
+
+/* The Level one LXT970 is used by many boards				     */
+
+#define MII_LXT970_IER       17  /* Interrupt Enable Register */
+
+#define MII_LXT970_IER_IEN	0x0002
+
+#define MII_LXT970_ISR       18  /* Interrupt Status Register */
+
+#define MII_LXT970_CONFIG    19  /* Configuration Register    */
+
+/* ------------------------------------------------------------------------- */
+/* The Level one LXT971 is used on some of my custom boards                  */
+
+/* register definitions for the 971 */
+#define MII_LXT971_IER		18  /* Interrupt Enable Register */
+#define MII_LXT971_IER_IEN	0x00f2
+
+#define MII_LXT971_ISR		19  /* Interrupt Status Register */
+
+/* register definitions for the 973 */
+#define MII_LXT973_PCR 16 /* Port Configuration Register */
+#define PCR_FIBER_SELECT 1
+
+MODULE_DESCRIPTION("Intel LXT PHY driver");
+MODULE_AUTHOR("Andy Fleming");
+MODULE_LICENSE("GPL");
+
+static int lxt970_ack_interrupt(struct phy_device *phydev)
+{
+	int err;
+
+	err = phy_read(phydev, MII_BMSR);
+
+	if (err < 0)
+		return err;
+
+	err = phy_read(phydev, MII_LXT970_ISR);
+
+	if (err < 0)
+		return err;
+
+	return 0;
+}
+
+static int lxt970_config_intr(struct phy_device *phydev)
+{
+	int err;
+
+	if(phydev->interrupts == PHY_INTERRUPT_ENABLED)
+		err = phy_write(phydev, MII_LXT970_IER, MII_LXT970_IER_IEN);
+	else
+		err = phy_write(phydev, MII_LXT970_IER, 0);
+
+	return err;
+}
+
+static int lxt970_config_init(struct phy_device *phydev)
+{
+	int err;
+
+	err = phy_write(phydev, MII_LXT970_CONFIG, 0);
+
+	return err;
+}
+
+
+static int lxt971_ack_interrupt(struct phy_device *phydev)
+{
+	int err = phy_read(phydev, MII_LXT971_ISR);
+
+	if (err < 0)
+		return err;
+
+	return 0;
+}
+
+static int lxt971_config_intr(struct phy_device *phydev)
+{
+	int err;
+
+	if(phydev->interrupts == PHY_INTERRUPT_ENABLED)
+		err = phy_write(phydev, MII_LXT971_IER, MII_LXT971_IER_IEN);
+	else
+		err = phy_write(phydev, MII_LXT971_IER, 0);
+
+	return err;
+}
+
+static int lxt973_probe(struct phy_device *phydev)
+{
+	int val = phy_read(phydev, MII_LXT973_PCR);
+
+	if (val & PCR_FIBER_SELECT) {
+		/*
+		 * If fiber is selected, then the only correct setting
+		 * is 100Mbps, full duplex, and auto negotiation off.
+		 */
+		val = phy_read(phydev, MII_BMCR);
+		val |= (BMCR_SPEED100 | BMCR_FULLDPLX);
+		val &= ~BMCR_ANENABLE;
+		phy_write(phydev, MII_BMCR, val);
+		/* Remember that the port is in fiber mode. */
+		phydev->priv = lxt973_probe;
+	} else {
+		phydev->priv = NULL;
+	}
+	return 0;
+}
+
+static int lxt973_config_aneg(struct phy_device *phydev)
+{
+	/* Do nothing if port is in fiber mode. */
+	return phydev->priv ? 0 : genphy_config_aneg(phydev);
+}
+
+static struct phy_driver lxt970_driver = {
+	.phy_id		= 0x78100000,
+	.name		= "LXT970",
+	.phy_id_mask	= 0xfffffff0,
+	.features	= PHY_BASIC_FEATURES,
+	.flags		= PHY_HAS_INTERRUPT,
+	.config_init	= lxt970_config_init,
+	.config_aneg	= genphy_config_aneg,
+	.read_status	= genphy_read_status,
+	.ack_interrupt	= lxt970_ack_interrupt,
+	.config_intr	= lxt970_config_intr,
+	.driver 	= { .owner = THIS_MODULE,},
+};
+
+static struct phy_driver lxt971_driver = {
+	.phy_id		= 0x001378e0,
+	.name		= "LXT971",
+	.phy_id_mask	= 0xfffffff0,
+	.features	= PHY_BASIC_FEATURES,
+	.flags		= PHY_HAS_INTERRUPT,
+	.config_aneg	= genphy_config_aneg,
+	.read_status	= genphy_read_status,
+	.ack_interrupt	= lxt971_ack_interrupt,
+	.config_intr	= lxt971_config_intr,
+	.driver 	= { .owner = THIS_MODULE,},
+};
+
+static struct phy_driver lxt973_driver = {
+	.phy_id		= 0x00137a10,
+	.name		= "LXT973",
+	.phy_id_mask	= 0xfffffff0,
+	.features	= PHY_BASIC_FEATURES,
+	.flags		= 0,
+	.probe		= lxt973_probe,
+	.config_aneg	= lxt973_config_aneg,
+	.read_status	= genphy_read_status,
+	.driver 	= { .owner = THIS_MODULE,},
+};
+
+static int __init lxt_init(void)
+{
+	int ret;
+
+	ret = phy_driver_register(&lxt970_driver);
+	if (ret)
+		goto err1;
+
+	ret = phy_driver_register(&lxt971_driver);
+	if (ret)
+		goto err2;
+
+	ret = phy_driver_register(&lxt973_driver);
+	if (ret)
+		goto err3;
+	return 0;
+
+ err3:
+	phy_driver_unregister(&lxt971_driver);
+ err2:
+	phy_driver_unregister(&lxt970_driver);
+ err1:
+	return ret;
+}
+
+static void __exit lxt_exit(void)
+{
+	phy_driver_unregister(&lxt970_driver);
+	phy_driver_unregister(&lxt971_driver);
+	phy_driver_unregister(&lxt973_driver);
+}
+
+module_init(lxt_init);
+module_exit(lxt_exit);
+
+static struct mdio_device_id __maybe_unused lxt_tbl[] = {
+	{ 0x78100000, 0xfffffff0 },
+	{ 0x001378e0, 0xfffffff0 },
+	{ 0x00137a10, 0xfffffff0 },
+	{ }
+};
+
+MODULE_DEVICE_TABLE(mdio, lxt_tbl);
diff --git a/ap/os/linux/linux-3.4.x/drivers/net/phy/marvell.c b/ap/os/linux/linux-3.4.x/drivers/net/phy/marvell.c
new file mode 100644
index 0000000..e8b9c53
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/net/phy/marvell.c
@@ -0,0 +1,881 @@
+/*
+ * drivers/net/phy/marvell.c
+ *
+ * Driver for Marvell PHYs
+ *
+ * Author: Andy Fleming
+ *
+ * Copyright (c) 2004 Freescale Semiconductor, Inc.
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ *
+ */
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/errno.h>
+#include <linux/unistd.h>
+#include <linux/interrupt.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+#include <linux/spinlock.h>
+#include <linux/mm.h>
+#include <linux/module.h>
+#include <linux/mii.h>
+#include <linux/ethtool.h>
+#include <linux/phy.h>
+#include <linux/marvell_phy.h>
+#include <linux/of.h>
+
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/uaccess.h>
+
+#define MII_MARVELL_PHY_PAGE		22
+
+#define MII_M1011_IEVENT		0x13
+#define MII_M1011_IEVENT_CLEAR		0x0000
+
+#define MII_M1011_IMASK			0x12
+#define MII_M1011_IMASK_INIT		0x6400
+#define MII_M1011_IMASK_CLEAR		0x0000
+
+#define MII_M1011_PHY_SCR		0x10
+#define MII_M1011_PHY_SCR_AUTO_CROSS	0x0060
+
+#define MII_M1145_PHY_EXT_CR		0x14
+#define MII_M1145_RGMII_RX_DELAY	0x0080
+#define MII_M1145_RGMII_TX_DELAY	0x0002
+
+#define MII_M1111_PHY_LED_CONTROL	0x18
+#define MII_M1111_PHY_LED_DIRECT	0x4100
+#define MII_M1111_PHY_LED_COMBINE	0x411c
+#define MII_M1111_PHY_EXT_CR		0x14
+#define MII_M1111_RX_DELAY		0x80
+#define MII_M1111_TX_DELAY		0x2
+#define MII_M1111_PHY_EXT_SR		0x1b
+
+#define MII_M1111_HWCFG_MODE_MASK		0xf
+#define MII_M1111_HWCFG_MODE_COPPER_RGMII	0xb
+#define MII_M1111_HWCFG_MODE_FIBER_RGMII	0x3
+#define MII_M1111_HWCFG_MODE_SGMII_NO_CLK	0x4
+#define MII_M1111_HWCFG_MODE_COPPER_RTBI	0x9
+#define MII_M1111_HWCFG_FIBER_COPPER_AUTO	0x8000
+#define MII_M1111_HWCFG_FIBER_COPPER_RES	0x2000
+
+#define MII_M1111_COPPER		0
+#define MII_M1111_FIBER			1
+
+#define MII_88E1121_PHY_MSCR_PAGE	2
+#define MII_88E1121_PHY_MSCR_REG	21
+#define MII_88E1121_PHY_MSCR_RX_DELAY	BIT(5)
+#define MII_88E1121_PHY_MSCR_TX_DELAY	BIT(4)
+#define MII_88E1121_PHY_MSCR_DELAY_MASK	(~(0x3 << 4))
+
+#define MII_88E1318S_PHY_MSCR1_REG	16
+#define MII_88E1318S_PHY_MSCR1_PAD_ODD	BIT(6)
+
+#define MII_88E1121_PHY_LED_CTRL	16
+#define MII_88E1121_PHY_LED_PAGE	3
+#define MII_88E1121_PHY_LED_DEF		0x0030
+
+#define MII_M1011_PHY_STATUS		0x11
+#define MII_M1011_PHY_STATUS_1000	0x8000
+#define MII_M1011_PHY_STATUS_100	0x4000
+#define MII_M1011_PHY_STATUS_SPD_MASK	0xc000
+#define MII_M1011_PHY_STATUS_FULLDUPLEX	0x2000
+#define MII_M1011_PHY_STATUS_RESOLVED	0x0800
+#define MII_M1011_PHY_STATUS_LINK	0x0400
+
+
+MODULE_DESCRIPTION("Marvell PHY driver");
+MODULE_AUTHOR("Andy Fleming");
+MODULE_LICENSE("GPL");
+
+static int marvell_ack_interrupt(struct phy_device *phydev)
+{
+	int err;
+
+	/* Clear the interrupts by reading the reg */
+	err = phy_read(phydev, MII_M1011_IEVENT);
+
+	if (err < 0)
+		return err;
+
+	return 0;
+}
+
+static int marvell_config_intr(struct phy_device *phydev)
+{
+	int err;
+
+	if (phydev->interrupts == PHY_INTERRUPT_ENABLED)
+		err = phy_write(phydev, MII_M1011_IMASK, MII_M1011_IMASK_INIT);
+	else
+		err = phy_write(phydev, MII_M1011_IMASK, MII_M1011_IMASK_CLEAR);
+
+	return err;
+}
+
+static int marvell_config_aneg(struct phy_device *phydev)
+{
+	int err;
+
+	/* The Marvell PHY has an errata which requires
+	 * that certain registers get written in order
+	 * to restart autonegotiation */
+	err = phy_write(phydev, MII_BMCR, BMCR_RESET);
+
+	if (err < 0)
+		return err;
+
+	err = phy_write(phydev, 0x1d, 0x1f);
+	if (err < 0)
+		return err;
+
+	err = phy_write(phydev, 0x1e, 0x200c);
+	if (err < 0)
+		return err;
+
+	err = phy_write(phydev, 0x1d, 0x5);
+	if (err < 0)
+		return err;
+
+	err = phy_write(phydev, 0x1e, 0);
+	if (err < 0)
+		return err;
+
+	err = phy_write(phydev, 0x1e, 0x100);
+	if (err < 0)
+		return err;
+
+	err = phy_write(phydev, MII_M1011_PHY_SCR,
+			MII_M1011_PHY_SCR_AUTO_CROSS);
+	if (err < 0)
+		return err;
+
+	err = phy_write(phydev, MII_M1111_PHY_LED_CONTROL,
+			MII_M1111_PHY_LED_DIRECT);
+	if (err < 0)
+		return err;
+
+	err = genphy_config_aneg(phydev);
+	if (err < 0)
+		return err;
+
+	if (phydev->autoneg != AUTONEG_ENABLE) {
+		int bmcr;
+
+		/*
+		 * A write to speed/duplex bits (that is performed by
+		 * genphy_config_aneg() call above) must be followed by
+		 * a software reset. Otherwise, the write has no effect.
+		 */
+		bmcr = phy_read(phydev, MII_BMCR);
+		if (bmcr < 0)
+			return bmcr;
+
+		err = phy_write(phydev, MII_BMCR, bmcr | BMCR_RESET);
+		if (err < 0)
+			return err;
+	}
+
+	return 0;
+}
+
+#ifdef CONFIG_OF_MDIO
+/*
+ * Set and/or override some configuration registers based on the
+ * marvell,reg-init property stored in the of_node for the phydev.
+ *
+ * marvell,reg-init = <reg-page reg mask value>,...;
+ *
+ * There may be one or more sets of <reg-page reg mask value>:
+ *
+ * reg-page: which register bank to use.
+ * reg: the register.
+ * mask: if non-zero, ANDed with existing register value.
+ * value: ORed with the masked value and written to the regiser.
+ *
+ */
+static int marvell_of_reg_init(struct phy_device *phydev)
+{
+	const __be32 *paddr;
+	int len, i, saved_page, current_page, page_changed, ret;
+
+	if (!phydev->dev.of_node)
+		return 0;
+
+	paddr = of_get_property(phydev->dev.of_node, "marvell,reg-init", &len);
+	if (!paddr || len < (4 * sizeof(*paddr)))
+		return 0;
+
+	saved_page = phy_read(phydev, MII_MARVELL_PHY_PAGE);
+	if (saved_page < 0)
+		return saved_page;
+	page_changed = 0;
+	current_page = saved_page;
+
+	ret = 0;
+	len /= sizeof(*paddr);
+	for (i = 0; i < len - 3; i += 4) {
+		u16 reg_page = be32_to_cpup(paddr + i);
+		u16 reg = be32_to_cpup(paddr + i + 1);
+		u16 mask = be32_to_cpup(paddr + i + 2);
+		u16 val_bits = be32_to_cpup(paddr + i + 3);
+		int val;
+
+		if (reg_page != current_page) {
+			current_page = reg_page;
+			page_changed = 1;
+			ret = phy_write(phydev, MII_MARVELL_PHY_PAGE, reg_page);
+			if (ret < 0)
+				goto err;
+		}
+
+		val = 0;
+		if (mask) {
+			val = phy_read(phydev, reg);
+			if (val < 0) {
+				ret = val;
+				goto err;
+			}
+			val &= mask;
+		}
+		val |= val_bits;
+
+		ret = phy_write(phydev, reg, val);
+		if (ret < 0)
+			goto err;
+
+	}
+err:
+	if (page_changed) {
+		i = phy_write(phydev, MII_MARVELL_PHY_PAGE, saved_page);
+		if (ret == 0)
+			ret = i;
+	}
+	return ret;
+}
+#else
+static int marvell_of_reg_init(struct phy_device *phydev)
+{
+	return 0;
+}
+#endif /* CONFIG_OF_MDIO */
+
+static int m88e1121_config_aneg(struct phy_device *phydev)
+{
+	int err, oldpage, mscr;
+
+	oldpage = phy_read(phydev, MII_MARVELL_PHY_PAGE);
+
+	err = phy_write(phydev, MII_MARVELL_PHY_PAGE,
+			MII_88E1121_PHY_MSCR_PAGE);
+	if (err < 0)
+		return err;
+
+	if ((phydev->interface == PHY_INTERFACE_MODE_RGMII) ||
+	    (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID) ||
+	    (phydev->interface == PHY_INTERFACE_MODE_RGMII_RXID) ||
+	    (phydev->interface == PHY_INTERFACE_MODE_RGMII_TXID)) {
+
+		mscr = phy_read(phydev, MII_88E1121_PHY_MSCR_REG) &
+			MII_88E1121_PHY_MSCR_DELAY_MASK;
+
+		if (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID)
+			mscr |= (MII_88E1121_PHY_MSCR_RX_DELAY |
+				 MII_88E1121_PHY_MSCR_TX_DELAY);
+		else if (phydev->interface == PHY_INTERFACE_MODE_RGMII_RXID)
+			mscr |= MII_88E1121_PHY_MSCR_RX_DELAY;
+		else if (phydev->interface == PHY_INTERFACE_MODE_RGMII_TXID)
+			mscr |= MII_88E1121_PHY_MSCR_TX_DELAY;
+
+		err = phy_write(phydev, MII_88E1121_PHY_MSCR_REG, mscr);
+		if (err < 0)
+			return err;
+	}
+
+	phy_write(phydev, MII_MARVELL_PHY_PAGE, oldpage);
+
+	err = phy_write(phydev, MII_BMCR, BMCR_RESET);
+	if (err < 0)
+		return err;
+
+	err = phy_write(phydev, MII_M1011_PHY_SCR,
+			MII_M1011_PHY_SCR_AUTO_CROSS);
+	if (err < 0)
+		return err;
+
+	oldpage = phy_read(phydev, MII_MARVELL_PHY_PAGE);
+
+	phy_write(phydev, MII_MARVELL_PHY_PAGE, MII_88E1121_PHY_LED_PAGE);
+	phy_write(phydev, MII_88E1121_PHY_LED_CTRL, MII_88E1121_PHY_LED_DEF);
+	phy_write(phydev, MII_MARVELL_PHY_PAGE, oldpage);
+
+	err = genphy_config_aneg(phydev);
+
+	return err;
+}
+
+static int m88e1318_config_aneg(struct phy_device *phydev)
+{
+	int err, oldpage, mscr;
+
+	oldpage = phy_read(phydev, MII_MARVELL_PHY_PAGE);
+
+	err = phy_write(phydev, MII_MARVELL_PHY_PAGE,
+			MII_88E1121_PHY_MSCR_PAGE);
+	if (err < 0)
+		return err;
+
+	mscr = phy_read(phydev, MII_88E1318S_PHY_MSCR1_REG);
+	mscr |= MII_88E1318S_PHY_MSCR1_PAD_ODD;
+
+	err = phy_write(phydev, MII_88E1318S_PHY_MSCR1_REG, mscr);
+	if (err < 0)
+		return err;
+
+	err = phy_write(phydev, MII_MARVELL_PHY_PAGE, oldpage);
+	if (err < 0)
+		return err;
+
+	return m88e1121_config_aneg(phydev);
+}
+
+static int m88e1111_config_init(struct phy_device *phydev)
+{
+	int err;
+	int temp;
+
+	/* Enable Fiber/Copper auto selection */
+	temp = phy_read(phydev, MII_M1111_PHY_EXT_SR);
+	temp &= ~MII_M1111_HWCFG_FIBER_COPPER_AUTO;
+	phy_write(phydev, MII_M1111_PHY_EXT_SR, temp);
+
+	temp = phy_read(phydev, MII_BMCR);
+	temp |= BMCR_RESET;
+	phy_write(phydev, MII_BMCR, temp);
+
+	if ((phydev->interface == PHY_INTERFACE_MODE_RGMII) ||
+	    (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID) ||
+	    (phydev->interface == PHY_INTERFACE_MODE_RGMII_RXID) ||
+	    (phydev->interface == PHY_INTERFACE_MODE_RGMII_TXID)) {
+
+		temp = phy_read(phydev, MII_M1111_PHY_EXT_CR);
+		if (temp < 0)
+			return temp;
+
+		if (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID) {
+			temp |= (MII_M1111_RX_DELAY | MII_M1111_TX_DELAY);
+		} else if (phydev->interface == PHY_INTERFACE_MODE_RGMII_RXID) {
+			temp &= ~MII_M1111_TX_DELAY;
+			temp |= MII_M1111_RX_DELAY;
+		} else if (phydev->interface == PHY_INTERFACE_MODE_RGMII_TXID) {
+			temp &= ~MII_M1111_RX_DELAY;
+			temp |= MII_M1111_TX_DELAY;
+		}
+
+		err = phy_write(phydev, MII_M1111_PHY_EXT_CR, temp);
+		if (err < 0)
+			return err;
+
+		temp = phy_read(phydev, MII_M1111_PHY_EXT_SR);
+		if (temp < 0)
+			return temp;
+
+		temp &= ~(MII_M1111_HWCFG_MODE_MASK);
+
+		if (temp & MII_M1111_HWCFG_FIBER_COPPER_RES)
+			temp |= MII_M1111_HWCFG_MODE_FIBER_RGMII;
+		else
+			temp |= MII_M1111_HWCFG_MODE_COPPER_RGMII;
+
+		err = phy_write(phydev, MII_M1111_PHY_EXT_SR, temp);
+		if (err < 0)
+			return err;
+	}
+
+	if (phydev->interface == PHY_INTERFACE_MODE_SGMII) {
+		temp = phy_read(phydev, MII_M1111_PHY_EXT_SR);
+		if (temp < 0)
+			return temp;
+
+		temp &= ~(MII_M1111_HWCFG_MODE_MASK);
+		temp |= MII_M1111_HWCFG_MODE_SGMII_NO_CLK;
+		temp |= MII_M1111_HWCFG_FIBER_COPPER_AUTO;
+
+		err = phy_write(phydev, MII_M1111_PHY_EXT_SR, temp);
+		if (err < 0)
+			return err;
+	}
+
+	if (phydev->interface == PHY_INTERFACE_MODE_RTBI) {
+		temp = phy_read(phydev, MII_M1111_PHY_EXT_CR);
+		if (temp < 0)
+			return temp;
+		temp |= (MII_M1111_RX_DELAY | MII_M1111_TX_DELAY);
+		err = phy_write(phydev, MII_M1111_PHY_EXT_CR, temp);
+		if (err < 0)
+			return err;
+
+		temp = phy_read(phydev, MII_M1111_PHY_EXT_SR);
+		if (temp < 0)
+			return temp;
+		temp &= ~(MII_M1111_HWCFG_MODE_MASK | MII_M1111_HWCFG_FIBER_COPPER_RES);
+		temp |= 0x7 | MII_M1111_HWCFG_FIBER_COPPER_AUTO;
+		err = phy_write(phydev, MII_M1111_PHY_EXT_SR, temp);
+		if (err < 0)
+			return err;
+
+		/* soft reset */
+		err = phy_write(phydev, MII_BMCR, BMCR_RESET);
+		if (err < 0)
+			return err;
+		do
+			temp = phy_read(phydev, MII_BMCR);
+		while (temp & BMCR_RESET);
+
+		temp = phy_read(phydev, MII_M1111_PHY_EXT_SR);
+		if (temp < 0)
+			return temp;
+		temp &= ~(MII_M1111_HWCFG_MODE_MASK | MII_M1111_HWCFG_FIBER_COPPER_RES);
+		temp |= MII_M1111_HWCFG_MODE_COPPER_RTBI | MII_M1111_HWCFG_FIBER_COPPER_AUTO;
+		err = phy_write(phydev, MII_M1111_PHY_EXT_SR, temp);
+		if (err < 0)
+			return err;
+	}
+
+	err = marvell_of_reg_init(phydev);
+	if (err < 0)
+		return err;
+
+	err = phy_write(phydev, MII_BMCR, BMCR_RESET);
+	if (err < 0)
+		return err;
+
+	return 0;
+}
+
+static int m88e1118_config_aneg(struct phy_device *phydev)
+{
+	int err;
+
+	err = phy_write(phydev, MII_BMCR, BMCR_RESET);
+	if (err < 0)
+		return err;
+
+	err = phy_write(phydev, MII_M1011_PHY_SCR,
+			MII_M1011_PHY_SCR_AUTO_CROSS);
+	if (err < 0)
+		return err;
+
+	err = genphy_config_aneg(phydev);
+	return 0;
+}
+
+static int m88e1118_config_init(struct phy_device *phydev)
+{
+	int err;
+
+	/* Change address */
+	err = phy_write(phydev, MII_MARVELL_PHY_PAGE, 0x0002);
+	if (err < 0)
+		return err;
+
+	/* Enable 1000 Mbit */
+	err = phy_write(phydev, 0x15, 0x1070);
+	if (err < 0)
+		return err;
+
+	/* Change address */
+	err = phy_write(phydev, MII_MARVELL_PHY_PAGE, 0x0003);
+	if (err < 0)
+		return err;
+
+	/* Adjust LED Control */
+	if (phydev->dev_flags & MARVELL_PHY_M1118_DNS323_LEDS)
+		err = phy_write(phydev, 0x10, 0x1100);
+	else
+		err = phy_write(phydev, 0x10, 0x021e);
+	if (err < 0)
+		return err;
+
+	err = marvell_of_reg_init(phydev);
+	if (err < 0)
+		return err;
+
+	/* Reset address */
+	err = phy_write(phydev, MII_MARVELL_PHY_PAGE, 0x0);
+	if (err < 0)
+		return err;
+
+	err = phy_write(phydev, MII_BMCR, BMCR_RESET);
+	if (err < 0)
+		return err;
+
+	return 0;
+}
+
+static int m88e1149_config_init(struct phy_device *phydev)
+{
+	int err;
+
+	/* Change address */
+	err = phy_write(phydev, MII_MARVELL_PHY_PAGE, 0x0002);
+	if (err < 0)
+		return err;
+
+	/* Enable 1000 Mbit */
+	err = phy_write(phydev, 0x15, 0x1048);
+	if (err < 0)
+		return err;
+
+	err = marvell_of_reg_init(phydev);
+	if (err < 0)
+		return err;
+
+	/* Reset address */
+	err = phy_write(phydev, MII_MARVELL_PHY_PAGE, 0x0);
+	if (err < 0)
+		return err;
+
+	err = phy_write(phydev, MII_BMCR, BMCR_RESET);
+	if (err < 0)
+		return err;
+
+	return 0;
+}
+
+static int m88e1145_config_init(struct phy_device *phydev)
+{
+	int err;
+
+	/* Take care of errata E0 & E1 */
+	err = phy_write(phydev, 0x1d, 0x001b);
+	if (err < 0)
+		return err;
+
+	err = phy_write(phydev, 0x1e, 0x418f);
+	if (err < 0)
+		return err;
+
+	err = phy_write(phydev, 0x1d, 0x0016);
+	if (err < 0)
+		return err;
+
+	err = phy_write(phydev, 0x1e, 0xa2da);
+	if (err < 0)
+		return err;
+
+	if (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID) {
+		int temp = phy_read(phydev, MII_M1145_PHY_EXT_CR);
+		if (temp < 0)
+			return temp;
+
+		temp |= (MII_M1145_RGMII_RX_DELAY | MII_M1145_RGMII_TX_DELAY);
+
+		err = phy_write(phydev, MII_M1145_PHY_EXT_CR, temp);
+		if (err < 0)
+			return err;
+
+		if (phydev->dev_flags & MARVELL_PHY_M1145_FLAGS_RESISTANCE) {
+			err = phy_write(phydev, 0x1d, 0x0012);
+			if (err < 0)
+				return err;
+
+			temp = phy_read(phydev, 0x1e);
+			if (temp < 0)
+				return temp;
+
+			temp &= 0xf03f;
+			temp |= 2 << 9;	/* 36 ohm */
+			temp |= 2 << 6;	/* 39 ohm */
+
+			err = phy_write(phydev, 0x1e, temp);
+			if (err < 0)
+				return err;
+
+			err = phy_write(phydev, 0x1d, 0x3);
+			if (err < 0)
+				return err;
+
+			err = phy_write(phydev, 0x1e, 0x8000);
+			if (err < 0)
+				return err;
+		}
+	}
+
+	err = marvell_of_reg_init(phydev);
+	if (err < 0)
+		return err;
+
+	return 0;
+}
+
+/* marvell_read_status
+ *
+ * Generic status code does not detect Fiber correctly!
+ * Description:
+ *   Check the link, then figure out the current state
+ *   by comparing what we advertise with what the link partner
+ *   advertises.  Start by checking the gigabit possibilities,
+ *   then move on to 10/100.
+ */
+static int marvell_read_status(struct phy_device *phydev)
+{
+	int adv;
+	int err;
+	int lpa;
+	int status = 0;
+
+	/* Update the link, but return if there
+	 * was an error */
+	err = genphy_update_link(phydev);
+	if (err)
+		return err;
+
+	if (AUTONEG_ENABLE == phydev->autoneg) {
+		status = phy_read(phydev, MII_M1011_PHY_STATUS);
+		if (status < 0)
+			return status;
+
+		lpa = phy_read(phydev, MII_LPA);
+		if (lpa < 0)
+			return lpa;
+
+		adv = phy_read(phydev, MII_ADVERTISE);
+		if (adv < 0)
+			return adv;
+
+		lpa &= adv;
+
+		if (status & MII_M1011_PHY_STATUS_FULLDUPLEX)
+			phydev->duplex = DUPLEX_FULL;
+		else
+			phydev->duplex = DUPLEX_HALF;
+
+		status = status & MII_M1011_PHY_STATUS_SPD_MASK;
+		phydev->pause = phydev->asym_pause = 0;
+
+		switch (status) {
+		case MII_M1011_PHY_STATUS_1000:
+			phydev->speed = SPEED_1000;
+			break;
+
+		case MII_M1011_PHY_STATUS_100:
+			phydev->speed = SPEED_100;
+			break;
+
+		default:
+			phydev->speed = SPEED_10;
+			break;
+		}
+
+		if (phydev->duplex == DUPLEX_FULL) {
+			phydev->pause = lpa & LPA_PAUSE_CAP ? 1 : 0;
+			phydev->asym_pause = lpa & LPA_PAUSE_ASYM ? 1 : 0;
+		}
+	} else {
+		int bmcr = phy_read(phydev, MII_BMCR);
+
+		if (bmcr < 0)
+			return bmcr;
+
+		if (bmcr & BMCR_FULLDPLX)
+			phydev->duplex = DUPLEX_FULL;
+		else
+			phydev->duplex = DUPLEX_HALF;
+
+		if (bmcr & BMCR_SPEED1000)
+			phydev->speed = SPEED_1000;
+		else if (bmcr & BMCR_SPEED100)
+			phydev->speed = SPEED_100;
+		else
+			phydev->speed = SPEED_10;
+
+		phydev->pause = phydev->asym_pause = 0;
+	}
+
+	return 0;
+}
+
+static int m88e1121_did_interrupt(struct phy_device *phydev)
+{
+	int imask;
+
+	imask = phy_read(phydev, MII_M1011_IEVENT);
+
+	if (imask & MII_M1011_IMASK_INIT)
+		return 1;
+
+	return 0;
+}
+
+static struct phy_driver marvell_drivers[] = {
+	{
+		.phy_id = MARVELL_PHY_ID_88E1101,
+		.phy_id_mask = MARVELL_PHY_ID_MASK,
+		.name = "Marvell 88E1101",
+		.features = PHY_GBIT_FEATURES,
+		.flags = PHY_HAS_INTERRUPT,
+		.config_aneg = &marvell_config_aneg,
+		.read_status = &genphy_read_status,
+		.ack_interrupt = &marvell_ack_interrupt,
+		.config_intr = &marvell_config_intr,
+		.driver = { .owner = THIS_MODULE },
+	},
+	{
+		.phy_id = MARVELL_PHY_ID_88E1112,
+		.phy_id_mask = MARVELL_PHY_ID_MASK,
+		.name = "Marvell 88E1112",
+		.features = PHY_GBIT_FEATURES,
+		.flags = PHY_HAS_INTERRUPT,
+		.config_init = &m88e1111_config_init,
+		.config_aneg = &marvell_config_aneg,
+		.read_status = &genphy_read_status,
+		.ack_interrupt = &marvell_ack_interrupt,
+		.config_intr = &marvell_config_intr,
+		.driver = { .owner = THIS_MODULE },
+	},
+	{
+		.phy_id = MARVELL_PHY_ID_88E1111,
+		.phy_id_mask = MARVELL_PHY_ID_MASK,
+		.name = "Marvell 88E1111",
+		.features = PHY_GBIT_FEATURES,
+		.flags = PHY_HAS_INTERRUPT,
+		.config_init = &m88e1111_config_init,
+		.config_aneg = &marvell_config_aneg,
+		.read_status = &marvell_read_status,
+		.ack_interrupt = &marvell_ack_interrupt,
+		.config_intr = &marvell_config_intr,
+		.driver = { .owner = THIS_MODULE },
+	},
+	{
+		.phy_id = MARVELL_PHY_ID_88E1118,
+		.phy_id_mask = MARVELL_PHY_ID_MASK,
+		.name = "Marvell 88E1118",
+		.features = PHY_GBIT_FEATURES,
+		.flags = PHY_HAS_INTERRUPT,
+		.config_init = &m88e1118_config_init,
+		.config_aneg = &m88e1118_config_aneg,
+		.read_status = &genphy_read_status,
+		.ack_interrupt = &marvell_ack_interrupt,
+		.config_intr = &marvell_config_intr,
+		.driver = {.owner = THIS_MODULE,},
+	},
+	{
+		.phy_id = MARVELL_PHY_ID_88E1121R,
+		.phy_id_mask = MARVELL_PHY_ID_MASK,
+		.name = "Marvell 88E1121R",
+		.features = PHY_GBIT_FEATURES,
+		.flags = PHY_HAS_INTERRUPT,
+		.config_aneg = &m88e1121_config_aneg,
+		.read_status = &marvell_read_status,
+		.ack_interrupt = &marvell_ack_interrupt,
+		.config_intr = &marvell_config_intr,
+		.did_interrupt = &m88e1121_did_interrupt,
+		.driver = { .owner = THIS_MODULE },
+	},
+	{
+		.phy_id = MARVELL_PHY_ID_88E1318S,
+		.phy_id_mask = MARVELL_PHY_ID_MASK,
+		.name = "Marvell 88E1318S",
+		.features = PHY_GBIT_FEATURES,
+		.flags = PHY_HAS_INTERRUPT,
+		.config_aneg = &m88e1318_config_aneg,
+		.read_status = &marvell_read_status,
+		.ack_interrupt = &marvell_ack_interrupt,
+		.config_intr = &marvell_config_intr,
+		.did_interrupt = &m88e1121_did_interrupt,
+		.driver = { .owner = THIS_MODULE },
+	},
+	{
+		.phy_id = MARVELL_PHY_ID_88E1145,
+		.phy_id_mask = MARVELL_PHY_ID_MASK,
+		.name = "Marvell 88E1145",
+		.features = PHY_GBIT_FEATURES,
+		.flags = PHY_HAS_INTERRUPT,
+		.config_init = &m88e1145_config_init,
+		.config_aneg = &marvell_config_aneg,
+		.read_status = &genphy_read_status,
+		.ack_interrupt = &marvell_ack_interrupt,
+		.config_intr = &marvell_config_intr,
+		.driver = { .owner = THIS_MODULE },
+	},
+	{
+		.phy_id = MARVELL_PHY_ID_88E1149R,
+		.phy_id_mask = MARVELL_PHY_ID_MASK,
+		.name = "Marvell 88E1149R",
+		.features = PHY_GBIT_FEATURES,
+		.flags = PHY_HAS_INTERRUPT,
+		.config_init = &m88e1149_config_init,
+		.config_aneg = &m88e1118_config_aneg,
+		.read_status = &genphy_read_status,
+		.ack_interrupt = &marvell_ack_interrupt,
+		.config_intr = &marvell_config_intr,
+		.driver = { .owner = THIS_MODULE },
+	},
+	{
+		.phy_id = MARVELL_PHY_ID_88E1240,
+		.phy_id_mask = MARVELL_PHY_ID_MASK,
+		.name = "Marvell 88E1240",
+		.features = PHY_GBIT_FEATURES,
+		.flags = PHY_HAS_INTERRUPT,
+		.config_init = &m88e1111_config_init,
+		.config_aneg = &marvell_config_aneg,
+		.read_status = &genphy_read_status,
+		.ack_interrupt = &marvell_ack_interrupt,
+		.config_intr = &marvell_config_intr,
+		.driver = { .owner = THIS_MODULE },
+	},
+};
+
+static int __init marvell_init(void)
+{
+	int ret;
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(marvell_drivers); i++) {
+		ret = phy_driver_register(&marvell_drivers[i]);
+
+		if (ret) {
+			while (i-- > 0)
+				phy_driver_unregister(&marvell_drivers[i]);
+			return ret;
+		}
+	}
+
+	return 0;
+}
+
+static void __exit marvell_exit(void)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(marvell_drivers); i++)
+		phy_driver_unregister(&marvell_drivers[i]);
+}
+
+module_init(marvell_init);
+module_exit(marvell_exit);
+
+static struct mdio_device_id __maybe_unused marvell_tbl[] = {
+	{ 0x01410c60, 0xfffffff0 },
+	{ 0x01410c90, 0xfffffff0 },
+	{ 0x01410cc0, 0xfffffff0 },
+	{ 0x01410e10, 0xfffffff0 },
+	{ 0x01410cb0, 0xfffffff0 },
+	{ 0x01410cd0, 0xfffffff0 },
+	{ 0x01410e50, 0xfffffff0 },
+	{ 0x01410e30, 0xfffffff0 },
+	{ 0x01410e90, 0xfffffff0 },
+	{ }
+};
+
+MODULE_DEVICE_TABLE(mdio, marvell_tbl);
diff --git a/ap/os/linux/linux-3.4.x/drivers/net/phy/mdio-bitbang.c b/ap/os/linux/linux-3.4.x/drivers/net/phy/mdio-bitbang.c
new file mode 100644
index 0000000..daec9b0
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/net/phy/mdio-bitbang.c
@@ -0,0 +1,241 @@
+/*
+ * Bitbanged MDIO support.
+ *
+ * Author: Scott Wood <scottwood@freescale.com>
+ * Copyright (c) 2007 Freescale Semiconductor
+ *
+ * Based on CPM2 MDIO code which is:
+ *
+ * Copyright (c) 2003 Intracom S.A.
+ *  by Pantelis Antoniou <panto@intracom.gr>
+ *
+ * 2005 (c) MontaVista Software, Inc.
+ * Vitaly Bordug <vbordug@ru.mvista.com>
+ *
+ * This file is licensed under the terms of the GNU General Public License
+ * version 2. This program is licensed "as is" without any warranty of any
+ * kind, whether express or implied.
+ */
+
+#include <linux/module.h>
+#include <linux/mdio-bitbang.h>
+#include <linux/types.h>
+#include <linux/delay.h>
+
+#define MDIO_READ 2
+#define MDIO_WRITE 1
+
+#define MDIO_C45 (1<<15)
+#define MDIO_C45_ADDR (MDIO_C45 | 0)
+#define MDIO_C45_READ (MDIO_C45 | 3)
+#define MDIO_C45_WRITE (MDIO_C45 | 1)
+
+#define MDIO_SETUP_TIME 10
+#define MDIO_HOLD_TIME 10
+
+/* Minimum MDC period is 400 ns, plus some margin for error.  MDIO_DELAY
+ * is done twice per period.
+ */
+#define MDIO_DELAY 250
+
+/* The PHY may take up to 300 ns to produce data, plus some margin
+ * for error.
+ */
+#define MDIO_READ_DELAY 350
+
+/* MDIO must already be configured as output. */
+static void mdiobb_send_bit(struct mdiobb_ctrl *ctrl, int val)
+{
+	const struct mdiobb_ops *ops = ctrl->ops;
+
+	ops->set_mdio_data(ctrl, val);
+	ndelay(MDIO_DELAY);
+	ops->set_mdc(ctrl, 1);
+	ndelay(MDIO_DELAY);
+	ops->set_mdc(ctrl, 0);
+}
+
+/* MDIO must already be configured as input. */
+static int mdiobb_get_bit(struct mdiobb_ctrl *ctrl)
+{
+	const struct mdiobb_ops *ops = ctrl->ops;
+
+	ndelay(MDIO_DELAY);
+	ops->set_mdc(ctrl, 1);
+	ndelay(MDIO_READ_DELAY);
+	ops->set_mdc(ctrl, 0);
+
+	return ops->get_mdio_data(ctrl);
+}
+
+/* MDIO must already be configured as output. */
+static void mdiobb_send_num(struct mdiobb_ctrl *ctrl, u16 val, int bits)
+{
+	int i;
+
+	for (i = bits - 1; i >= 0; i--)
+		mdiobb_send_bit(ctrl, (val >> i) & 1);
+}
+
+/* MDIO must already be configured as input. */
+static u16 mdiobb_get_num(struct mdiobb_ctrl *ctrl, int bits)
+{
+	int i;
+	u16 ret = 0;
+
+	for (i = bits - 1; i >= 0; i--) {
+		ret <<= 1;
+		ret |= mdiobb_get_bit(ctrl);
+	}
+
+	return ret;
+}
+
+/* Utility to send the preamble, address, and
+ * register (common to read and write).
+ */
+static void mdiobb_cmd(struct mdiobb_ctrl *ctrl, int op, u8 phy, u8 reg)
+{
+	const struct mdiobb_ops *ops = ctrl->ops;
+	int i;
+
+	ops->set_mdio_dir(ctrl, 1);
+
+	/*
+	 * Send a 32 bit preamble ('1's) with an extra '1' bit for good
+	 * measure.  The IEEE spec says this is a PHY optional
+	 * requirement.  The AMD 79C874 requires one after power up and
+	 * one after a MII communications error.  This means that we are
+	 * doing more preambles than we need, but it is safer and will be
+	 * much more robust.
+	 */
+
+	for (i = 0; i < 32; i++)
+		mdiobb_send_bit(ctrl, 1);
+
+	/* send the start bit (01) and the read opcode (10) or write (10).
+	   Clause 45 operation uses 00 for the start and 11, 10 for
+	   read/write */
+	mdiobb_send_bit(ctrl, 0);
+	if (op & MDIO_C45)
+		mdiobb_send_bit(ctrl, 0);
+	else
+		mdiobb_send_bit(ctrl, 1);
+	mdiobb_send_bit(ctrl, (op >> 1) & 1);
+	mdiobb_send_bit(ctrl, (op >> 0) & 1);
+
+	mdiobb_send_num(ctrl, phy, 5);
+	mdiobb_send_num(ctrl, reg, 5);
+}
+
+/* In clause 45 mode all commands are prefixed by MDIO_ADDR to specify the
+   lower 16 bits of the 21 bit address. This transfer is done identically to a
+   MDIO_WRITE except for a different code. To enable clause 45 mode or
+   MII_ADDR_C45 into the address. Theoretically clause 45 and normal devices
+   can exist on the same bus. Normal devices should ignore the MDIO_ADDR
+   phase. */
+static int mdiobb_cmd_addr(struct mdiobb_ctrl *ctrl, int phy, u32 addr)
+{
+	unsigned int dev_addr = (addr >> 16) & 0x1F;
+	unsigned int reg = addr & 0xFFFF;
+	mdiobb_cmd(ctrl, MDIO_C45_ADDR, phy, dev_addr);
+
+	/* send the turnaround (10) */
+	mdiobb_send_bit(ctrl, 1);
+	mdiobb_send_bit(ctrl, 0);
+
+	mdiobb_send_num(ctrl, reg, 16);
+
+	ctrl->ops->set_mdio_dir(ctrl, 0);
+	mdiobb_get_bit(ctrl);
+
+	return dev_addr;
+}
+
+static int mdiobb_read(struct mii_bus *bus, int phy, int reg)
+{
+	struct mdiobb_ctrl *ctrl = bus->priv;
+	int ret, i;
+
+	if (reg & MII_ADDR_C45) {
+		reg = mdiobb_cmd_addr(ctrl, phy, reg);
+		mdiobb_cmd(ctrl, MDIO_C45_READ, phy, reg);
+	} else
+		mdiobb_cmd(ctrl, MDIO_READ, phy, reg);
+
+	ctrl->ops->set_mdio_dir(ctrl, 0);
+
+	/* check the turnaround bit: the PHY should be driving it to zero */
+	if (mdiobb_get_bit(ctrl) != 0) {
+		/* PHY didn't drive TA low -- flush any bits it
+		 * may be trying to send.
+		 */
+		for (i = 0; i < 32; i++)
+			mdiobb_get_bit(ctrl);
+
+		return 0xffff;
+	}
+
+	ret = mdiobb_get_num(ctrl, 16);
+	mdiobb_get_bit(ctrl);
+	return ret;
+}
+
+static int mdiobb_write(struct mii_bus *bus, int phy, int reg, u16 val)
+{
+	struct mdiobb_ctrl *ctrl = bus->priv;
+
+	if (reg & MII_ADDR_C45) {
+		reg = mdiobb_cmd_addr(ctrl, phy, reg);
+		mdiobb_cmd(ctrl, MDIO_C45_WRITE, phy, reg);
+	} else
+		mdiobb_cmd(ctrl, MDIO_WRITE, phy, reg);
+
+	/* send the turnaround (10) */
+	mdiobb_send_bit(ctrl, 1);
+	mdiobb_send_bit(ctrl, 0);
+
+	mdiobb_send_num(ctrl, val, 16);
+
+	ctrl->ops->set_mdio_dir(ctrl, 0);
+	mdiobb_get_bit(ctrl);
+	return 0;
+}
+
+static int mdiobb_reset(struct mii_bus *bus)
+{
+	struct mdiobb_ctrl *ctrl = bus->priv;
+	if (ctrl->reset)
+		ctrl->reset(bus);
+	return 0;
+}
+
+struct mii_bus *alloc_mdio_bitbang(struct mdiobb_ctrl *ctrl)
+{
+	struct mii_bus *bus;
+
+	bus = mdiobus_alloc();
+	if (!bus)
+		return NULL;
+
+	__module_get(ctrl->ops->owner);
+
+	bus->read = mdiobb_read;
+	bus->write = mdiobb_write;
+	bus->reset = mdiobb_reset;
+	bus->priv = ctrl;
+
+	return bus;
+}
+EXPORT_SYMBOL(alloc_mdio_bitbang);
+
+void free_mdio_bitbang(struct mii_bus *bus)
+{
+	struct mdiobb_ctrl *ctrl = bus->priv;
+
+	module_put(ctrl->ops->owner);
+	mdiobus_free(bus);
+}
+EXPORT_SYMBOL(free_mdio_bitbang);
+
+MODULE_LICENSE("GPL");
diff --git a/ap/os/linux/linux-3.4.x/drivers/net/phy/mdio-gpio.c b/ap/os/linux/linux-3.4.x/drivers/net/phy/mdio-gpio.c
new file mode 100644
index 0000000..7189adf
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/net/phy/mdio-gpio.c
@@ -0,0 +1,302 @@
+/*
+ * GPIO based MDIO bitbang driver.
+ * Supports OpenFirmware.
+ *
+ * Copyright (c) 2008 CSE Semaphore Belgium.
+ *  by Laurent Pinchart <laurentp@cse-semaphore.com>
+ *
+ * Copyright (C) 2008, Paulius Zaleckas <paulius.zaleckas@teltonika.lt>
+ *
+ * Based on earlier work by
+ *
+ * Copyright (c) 2003 Intracom S.A.
+ *  by Pantelis Antoniou <panto@intracom.gr>
+ *
+ * 2005 (c) MontaVista Software, Inc.
+ * Vitaly Bordug <vbordug@ru.mvista.com>
+ *
+ * This file is licensed under the terms of the GNU General Public License
+ * version 2. This program is licensed "as is" without any warranty of any
+ * kind, whether express or implied.
+ */
+
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <linux/gpio.h>
+#include <linux/mdio-gpio.h>
+
+#ifdef CONFIG_OF_GPIO
+#include <linux/of_gpio.h>
+#include <linux/of_mdio.h>
+#include <linux/of_platform.h>
+#endif
+
+struct mdio_gpio_info {
+	struct mdiobb_ctrl ctrl;
+	int mdc, mdio;
+};
+
+static void mdio_dir(struct mdiobb_ctrl *ctrl, int dir)
+{
+	struct mdio_gpio_info *bitbang =
+		container_of(ctrl, struct mdio_gpio_info, ctrl);
+
+	if (dir)
+		gpio_direction_output(bitbang->mdio, 1);
+	else
+		gpio_direction_input(bitbang->mdio);
+}
+
+static int mdio_get(struct mdiobb_ctrl *ctrl)
+{
+	struct mdio_gpio_info *bitbang =
+		container_of(ctrl, struct mdio_gpio_info, ctrl);
+
+	return gpio_get_value(bitbang->mdio);
+}
+
+static void mdio_set(struct mdiobb_ctrl *ctrl, int what)
+{
+	struct mdio_gpio_info *bitbang =
+		container_of(ctrl, struct mdio_gpio_info, ctrl);
+
+	gpio_set_value(bitbang->mdio, what);
+}
+
+static void mdc_set(struct mdiobb_ctrl *ctrl, int what)
+{
+	struct mdio_gpio_info *bitbang =
+		container_of(ctrl, struct mdio_gpio_info, ctrl);
+
+	gpio_set_value(bitbang->mdc, what);
+}
+
+static struct mdiobb_ops mdio_gpio_ops = {
+	.owner = THIS_MODULE,
+	.set_mdc = mdc_set,
+	.set_mdio_dir = mdio_dir,
+	.set_mdio_data = mdio_set,
+	.get_mdio_data = mdio_get,
+};
+
+static struct mii_bus * __devinit mdio_gpio_bus_init(struct device *dev,
+					struct mdio_gpio_platform_data *pdata,
+					int bus_id)
+{
+	struct mii_bus *new_bus;
+	struct mdio_gpio_info *bitbang;
+	int i;
+
+	bitbang = kzalloc(sizeof(*bitbang), GFP_KERNEL);
+	if (!bitbang)
+		goto out;
+
+	bitbang->ctrl.ops = &mdio_gpio_ops;
+	bitbang->ctrl.reset = pdata->reset;
+	bitbang->mdc = pdata->mdc;
+	bitbang->mdio = pdata->mdio;
+
+	new_bus = alloc_mdio_bitbang(&bitbang->ctrl);
+	if (!new_bus)
+		goto out_free_bitbang;
+
+	new_bus->name = "GPIO Bitbanged MDIO",
+
+	new_bus->phy_mask = pdata->phy_mask;
+	new_bus->irq = pdata->irqs;
+	new_bus->parent = dev;
+
+	if (new_bus->phy_mask == ~0)
+		goto out_free_bus;
+
+	for (i = 0; i < PHY_MAX_ADDR; i++)
+		if (!new_bus->irq[i])
+			new_bus->irq[i] = PHY_POLL;
+
+	snprintf(new_bus->id, MII_BUS_ID_SIZE, "gpio-%x", bus_id);
+
+	if (gpio_request(bitbang->mdc, "mdc"))
+		goto out_free_bus;
+
+	if (gpio_request(bitbang->mdio, "mdio"))
+		goto out_free_mdc;
+
+	gpio_direction_output(bitbang->mdc, 0);
+
+	dev_set_drvdata(dev, new_bus);
+
+	return new_bus;
+
+out_free_mdc:
+	gpio_free(bitbang->mdc);
+out_free_bus:
+	free_mdio_bitbang(new_bus);
+out_free_bitbang:
+	kfree(bitbang);
+out:
+	return NULL;
+}
+
+static void mdio_gpio_bus_deinit(struct device *dev)
+{
+	struct mii_bus *bus = dev_get_drvdata(dev);
+	struct mdio_gpio_info *bitbang = bus->priv;
+
+	dev_set_drvdata(dev, NULL);
+	gpio_free(bitbang->mdio);
+	gpio_free(bitbang->mdc);
+	free_mdio_bitbang(bus);
+	kfree(bitbang);
+}
+
+static void __devexit mdio_gpio_bus_destroy(struct device *dev)
+{
+	struct mii_bus *bus = dev_get_drvdata(dev);
+
+	mdiobus_unregister(bus);
+	mdio_gpio_bus_deinit(dev);
+}
+
+static int __devinit mdio_gpio_probe(struct platform_device *pdev)
+{
+	struct mdio_gpio_platform_data *pdata = pdev->dev.platform_data;
+	struct mii_bus *new_bus;
+	int ret;
+
+	if (!pdata)
+		return -ENODEV;
+
+	new_bus = mdio_gpio_bus_init(&pdev->dev, pdata, pdev->id);
+	if (!new_bus)
+		return -ENODEV;
+
+	ret = mdiobus_register(new_bus);
+	if (ret)
+		mdio_gpio_bus_deinit(&pdev->dev);
+
+	return ret;
+}
+
+static int __devexit mdio_gpio_remove(struct platform_device *pdev)
+{
+	mdio_gpio_bus_destroy(&pdev->dev);
+
+	return 0;
+}
+
+#ifdef CONFIG_OF_GPIO
+
+static int __devinit mdio_ofgpio_probe(struct platform_device *ofdev)
+{
+	struct mdio_gpio_platform_data *pdata;
+	struct mii_bus *new_bus;
+	int ret;
+
+	pdata = kzalloc(sizeof(*pdata), GFP_KERNEL);
+	if (!pdata)
+		return -ENOMEM;
+
+	ret = of_get_gpio(ofdev->dev.of_node, 0);
+	if (ret < 0)
+		goto out_free;
+	pdata->mdc = ret;
+
+	ret = of_get_gpio(ofdev->dev.of_node, 1);
+	if (ret < 0)
+		goto out_free;
+	pdata->mdio = ret;
+
+	new_bus = mdio_gpio_bus_init(&ofdev->dev, pdata, pdata->mdc);
+	if (!new_bus)
+		goto out_free;
+
+	ret = of_mdiobus_register(new_bus, ofdev->dev.of_node);
+	if (ret)
+		mdio_gpio_bus_deinit(&ofdev->dev);
+
+	return ret;
+
+out_free:
+	kfree(pdata);
+	return -ENODEV;
+}
+
+static int __devexit mdio_ofgpio_remove(struct platform_device *ofdev)
+{
+	mdio_gpio_bus_destroy(&ofdev->dev);
+	kfree(ofdev->dev.platform_data);
+
+	return 0;
+}
+
+static struct of_device_id mdio_ofgpio_match[] = {
+	{
+		.compatible = "virtual,mdio-gpio",
+	},
+	{},
+};
+MODULE_DEVICE_TABLE(of, mdio_ofgpio_match);
+
+static struct platform_driver mdio_ofgpio_driver = {
+	.driver = {
+		.name = "mdio-ofgpio",
+		.owner = THIS_MODULE,
+		.of_match_table = mdio_ofgpio_match,
+	},
+	.probe = mdio_ofgpio_probe,
+	.remove = __devexit_p(mdio_ofgpio_remove),
+};
+
+static inline int __init mdio_ofgpio_init(void)
+{
+	return platform_driver_register(&mdio_ofgpio_driver);
+}
+
+static inline void mdio_ofgpio_exit(void)
+{
+	platform_driver_unregister(&mdio_ofgpio_driver);
+}
+#else
+static inline int __init mdio_ofgpio_init(void) { return 0; }
+static inline void mdio_ofgpio_exit(void) { }
+#endif /* CONFIG_OF_GPIO */
+
+static struct platform_driver mdio_gpio_driver = {
+	.probe = mdio_gpio_probe,
+	.remove = __devexit_p(mdio_gpio_remove),
+	.driver		= {
+		.name	= "mdio-gpio",
+		.owner	= THIS_MODULE,
+	},
+};
+
+static int __init mdio_gpio_init(void)
+{
+	int ret;
+
+	ret = mdio_ofgpio_init();
+	if (ret)
+		return ret;
+
+	ret = platform_driver_register(&mdio_gpio_driver);
+	if (ret)
+		mdio_ofgpio_exit();
+
+	return ret;
+}
+module_init(mdio_gpio_init);
+
+static void __exit mdio_gpio_exit(void)
+{
+	platform_driver_unregister(&mdio_gpio_driver);
+	mdio_ofgpio_exit();
+}
+module_exit(mdio_gpio_exit);
+
+MODULE_ALIAS("platform:mdio-gpio");
+MODULE_AUTHOR("Laurent Pinchart, Paulius Zaleckas");
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Generic driver for MDIO bus emulation using GPIO");
diff --git a/ap/os/linux/linux-3.4.x/drivers/net/phy/mdio-octeon.c b/ap/os/linux/linux-3.4.x/drivers/net/phy/mdio-octeon.c
new file mode 100644
index 0000000..826d961
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/net/phy/mdio-octeon.c
@@ -0,0 +1,192 @@
+/*
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 2009 Cavium Networks
+ */
+
+#include <linux/gfp.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/phy.h>
+
+#include <asm/octeon/octeon.h>
+#include <asm/octeon/cvmx-smix-defs.h>
+
+#define DRV_VERSION "1.0"
+#define DRV_DESCRIPTION "Cavium Networks Octeon SMI/MDIO driver"
+
+struct octeon_mdiobus {
+	struct mii_bus *mii_bus;
+	int unit;
+	int phy_irq[PHY_MAX_ADDR];
+};
+
+static int octeon_mdiobus_read(struct mii_bus *bus, int phy_id, int regnum)
+{
+	struct octeon_mdiobus *p = bus->priv;
+	union cvmx_smix_cmd smi_cmd;
+	union cvmx_smix_rd_dat smi_rd;
+	int timeout = 1000;
+
+	smi_cmd.u64 = 0;
+	smi_cmd.s.phy_op = 1; /* MDIO_CLAUSE_22_READ */
+	smi_cmd.s.phy_adr = phy_id;
+	smi_cmd.s.reg_adr = regnum;
+	cvmx_write_csr(CVMX_SMIX_CMD(p->unit), smi_cmd.u64);
+
+	do {
+		/*
+		 * Wait 1000 clocks so we don't saturate the RSL bus
+		 * doing reads.
+		 */
+		cvmx_wait(1000);
+		smi_rd.u64 = cvmx_read_csr(CVMX_SMIX_RD_DAT(p->unit));
+	} while (smi_rd.s.pending && --timeout);
+
+	if (smi_rd.s.val)
+		return smi_rd.s.dat;
+	else
+		return -EIO;
+}
+
+static int octeon_mdiobus_write(struct mii_bus *bus, int phy_id,
+				int regnum, u16 val)
+{
+	struct octeon_mdiobus *p = bus->priv;
+	union cvmx_smix_cmd smi_cmd;
+	union cvmx_smix_wr_dat smi_wr;
+	int timeout = 1000;
+
+	smi_wr.u64 = 0;
+	smi_wr.s.dat = val;
+	cvmx_write_csr(CVMX_SMIX_WR_DAT(p->unit), smi_wr.u64);
+
+	smi_cmd.u64 = 0;
+	smi_cmd.s.phy_op = 0; /* MDIO_CLAUSE_22_WRITE */
+	smi_cmd.s.phy_adr = phy_id;
+	smi_cmd.s.reg_adr = regnum;
+	cvmx_write_csr(CVMX_SMIX_CMD(p->unit), smi_cmd.u64);
+
+	do {
+		/*
+		 * Wait 1000 clocks so we don't saturate the RSL bus
+		 * doing reads.
+		 */
+		cvmx_wait(1000);
+		smi_wr.u64 = cvmx_read_csr(CVMX_SMIX_WR_DAT(p->unit));
+	} while (smi_wr.s.pending && --timeout);
+
+	if (timeout <= 0)
+		return -EIO;
+
+	return 0;
+}
+
+static int __devinit octeon_mdiobus_probe(struct platform_device *pdev)
+{
+	struct octeon_mdiobus *bus;
+	union cvmx_smix_en smi_en;
+	int i;
+	int err = -ENOENT;
+
+	bus = devm_kzalloc(&pdev->dev, sizeof(*bus), GFP_KERNEL);
+	if (!bus)
+		return -ENOMEM;
+
+	/* The platform_device id is our unit number.  */
+	bus->unit = pdev->id;
+
+	bus->mii_bus = mdiobus_alloc();
+
+	if (!bus->mii_bus)
+		goto err;
+
+	smi_en.u64 = 0;
+	smi_en.s.en = 1;
+	cvmx_write_csr(CVMX_SMIX_EN(bus->unit), smi_en.u64);
+
+	/*
+	 * Standard Octeon evaluation boards don't support phy
+	 * interrupts, we need to poll.
+	 */
+	for (i = 0; i < PHY_MAX_ADDR; i++)
+		bus->phy_irq[i] = PHY_POLL;
+
+	bus->mii_bus->priv = bus;
+	bus->mii_bus->irq = bus->phy_irq;
+	bus->mii_bus->name = "mdio-octeon";
+	snprintf(bus->mii_bus->id, MII_BUS_ID_SIZE, "%s-%x",
+		bus->mii_bus->name, bus->unit);
+	bus->mii_bus->parent = &pdev->dev;
+
+	bus->mii_bus->read = octeon_mdiobus_read;
+	bus->mii_bus->write = octeon_mdiobus_write;
+
+	dev_set_drvdata(&pdev->dev, bus);
+
+	err = mdiobus_register(bus->mii_bus);
+	if (err)
+		goto err_register;
+
+	dev_info(&pdev->dev, "Version " DRV_VERSION "\n");
+
+	return 0;
+err_register:
+	mdiobus_free(bus->mii_bus);
+
+err:
+	devm_kfree(&pdev->dev, bus);
+	smi_en.u64 = 0;
+	cvmx_write_csr(CVMX_SMIX_EN(bus->unit), smi_en.u64);
+	return err;
+}
+
+static int __devexit octeon_mdiobus_remove(struct platform_device *pdev)
+{
+	struct octeon_mdiobus *bus;
+	union cvmx_smix_en smi_en;
+
+	bus = dev_get_drvdata(&pdev->dev);
+
+	mdiobus_unregister(bus->mii_bus);
+	mdiobus_free(bus->mii_bus);
+	smi_en.u64 = 0;
+	cvmx_write_csr(CVMX_SMIX_EN(bus->unit), smi_en.u64);
+	return 0;
+}
+
+static struct platform_driver octeon_mdiobus_driver = {
+	.driver = {
+		.name		= "mdio-octeon",
+		.owner		= THIS_MODULE,
+	},
+	.probe		= octeon_mdiobus_probe,
+	.remove		= __devexit_p(octeon_mdiobus_remove),
+};
+
+void octeon_mdiobus_force_mod_depencency(void)
+{
+	/* Let ethernet drivers force us to be loaded.  */
+}
+EXPORT_SYMBOL(octeon_mdiobus_force_mod_depencency);
+
+static int __init octeon_mdiobus_mod_init(void)
+{
+	return platform_driver_register(&octeon_mdiobus_driver);
+}
+
+static void __exit octeon_mdiobus_mod_exit(void)
+{
+	platform_driver_unregister(&octeon_mdiobus_driver);
+}
+
+module_init(octeon_mdiobus_mod_init);
+module_exit(octeon_mdiobus_mod_exit);
+
+MODULE_DESCRIPTION(DRV_DESCRIPTION);
+MODULE_VERSION(DRV_VERSION);
+MODULE_AUTHOR("David Daney");
+MODULE_LICENSE("GPL");
diff --git a/ap/os/linux/linux-3.4.x/drivers/net/phy/mdio_bus.c b/ap/os/linux/linux-3.4.x/drivers/net/phy/mdio_bus.c
new file mode 100644
index 0000000..8985cc6
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/net/phy/mdio_bus.c
@@ -0,0 +1,416 @@
+/*
+ * drivers/net/phy/mdio_bus.c
+ *
+ * MDIO Bus interface
+ *
+ * Author: Andy Fleming
+ *
+ * Copyright (c) 2004 Freescale Semiconductor, Inc.
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ *
+ */
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/errno.h>
+#include <linux/unistd.h>
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+#include <linux/spinlock.h>
+#include <linux/mm.h>
+#include <linux/module.h>
+#include <linux/mii.h>
+#include <linux/ethtool.h>
+#include <linux/phy.h>
+
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/uaccess.h>
+
+/**
+ * mdiobus_alloc_size - allocate a mii_bus structure
+ * @size: extra amount of memory to allocate for private storage.
+ * If non-zero, then bus->priv is points to that memory.
+ *
+ * Description: called by a bus driver to allocate an mii_bus
+ * structure to fill in.
+ */
+struct mii_bus *mdiobus_alloc_size(size_t size)
+{
+	struct mii_bus *bus;
+	size_t aligned_size = ALIGN(sizeof(*bus), NETDEV_ALIGN);
+	size_t alloc_size;
+
+	/* If we alloc extra space, it should be aligned */
+	if (size)
+		alloc_size = aligned_size + size;
+	else
+		alloc_size = sizeof(*bus);
+
+	bus = kzalloc(alloc_size, GFP_KERNEL);
+	if (bus) {
+		bus->state = MDIOBUS_ALLOCATED;
+		if (size)
+			bus->priv = (void *)bus + aligned_size;
+	}
+
+	return bus;
+}
+EXPORT_SYMBOL(mdiobus_alloc_size);
+
+/**
+ * mdiobus_release - mii_bus device release callback
+ * @d: the target struct device that contains the mii_bus
+ *
+ * Description: called when the last reference to an mii_bus is
+ * dropped, to free the underlying memory.
+ */
+static void mdiobus_release(struct device *d)
+{
+	struct mii_bus *bus = to_mii_bus(d);
+	BUG_ON(bus->state != MDIOBUS_RELEASED &&
+	       /* for compatibility with error handling in drivers */
+	       bus->state != MDIOBUS_ALLOCATED);
+	kfree(bus);
+}
+
+static struct class mdio_bus_class = {
+	.name		= "mdio_bus",
+	.dev_release	= mdiobus_release,
+};
+
+/**
+ * mdiobus_register - bring up all the PHYs on a given bus and attach them to bus
+ * @bus: target mii_bus
+ *
+ * Description: Called by a bus driver to bring up all the PHYs
+ *   on a given bus, and attach them to the bus.
+ *
+ * Returns 0 on success or < 0 on error.
+ */
+int mdiobus_register(struct mii_bus *bus)
+{
+	int i, err;
+
+	if (NULL == bus || NULL == bus->name ||
+			NULL == bus->read ||
+			NULL == bus->write)
+		return -EINVAL;
+
+	BUG_ON(bus->state != MDIOBUS_ALLOCATED &&
+	       bus->state != MDIOBUS_UNREGISTERED);
+
+	bus->dev.parent = bus->parent;
+	bus->dev.class = &mdio_bus_class;
+	bus->dev.groups = NULL;
+	dev_set_name(&bus->dev, "%s", bus->id);
+
+	err = device_register(&bus->dev);
+	if (err) {
+		printk(KERN_ERR "mii_bus %s failed to register\n", bus->id);
+		return -EINVAL;
+	}
+
+	mutex_init(&bus->mdio_lock);
+
+	if (bus->reset)
+		bus->reset(bus);
+
+	for (i = 0; i < PHY_MAX_ADDR; i++) {
+		if ((bus->phy_mask & (1 << i)) == 0) {
+			struct phy_device *phydev;
+
+			phydev = mdiobus_scan(bus, i);
+			if (IS_ERR(phydev)) {
+				err = PTR_ERR(phydev);
+				goto error;
+			}
+		}
+	}
+
+	bus->state = MDIOBUS_REGISTERED;
+	pr_info("%s: probed\n", bus->name);
+	return 0;
+
+error:
+	while (--i >= 0) {
+		if (bus->phy_map[i])
+			device_unregister(&bus->phy_map[i]->dev);
+	}
+	device_del(&bus->dev);
+	return err;
+}
+EXPORT_SYMBOL(mdiobus_register);
+
+void mdiobus_unregister(struct mii_bus *bus)
+{
+	int i;
+
+	BUG_ON(bus->state != MDIOBUS_REGISTERED);
+	bus->state = MDIOBUS_UNREGISTERED;
+
+	device_del(&bus->dev);
+	for (i = 0; i < PHY_MAX_ADDR; i++) {
+		if (bus->phy_map[i])
+			device_unregister(&bus->phy_map[i]->dev);
+		bus->phy_map[i] = NULL;
+	}
+}
+EXPORT_SYMBOL(mdiobus_unregister);
+
+/**
+ * mdiobus_free - free a struct mii_bus
+ * @bus: mii_bus to free
+ *
+ * This function releases the reference to the underlying device
+ * object in the mii_bus.  If this is the last reference, the mii_bus
+ * will be freed.
+ */
+void mdiobus_free(struct mii_bus *bus)
+{
+	/*
+	 * For compatibility with error handling in drivers.
+	 */
+	if (bus->state == MDIOBUS_ALLOCATED) {
+		kfree(bus);
+		return;
+	}
+
+	BUG_ON(bus->state != MDIOBUS_UNREGISTERED);
+	bus->state = MDIOBUS_RELEASED;
+
+	put_device(&bus->dev);
+}
+EXPORT_SYMBOL(mdiobus_free);
+
+struct phy_device *mdiobus_scan(struct mii_bus *bus, int addr)
+{
+	struct phy_device *phydev;
+	int err;
+
+	phydev = get_phy_device(bus, addr);
+	if (IS_ERR(phydev) || phydev == NULL)
+		return phydev;
+
+	err = phy_device_register(phydev);
+	if (err) {
+		phy_device_free(phydev);
+		return NULL;
+	}
+
+	return phydev;
+}
+EXPORT_SYMBOL(mdiobus_scan);
+
+/**
+ * mdiobus_read - Convenience function for reading a given MII mgmt register
+ * @bus: the mii_bus struct
+ * @addr: the phy address
+ * @regnum: register number to read
+ *
+ * NOTE: MUST NOT be called from interrupt context,
+ * because the bus read/write functions may wait for an interrupt
+ * to conclude the operation.
+ */
+int mdiobus_read(struct mii_bus *bus, int addr, u32 regnum)
+{
+	int retval;
+
+	BUG_ON(in_interrupt());
+
+	mutex_lock(&bus->mdio_lock);
+	retval = bus->read(bus, addr, regnum);
+	mutex_unlock(&bus->mdio_lock);
+
+	return retval;
+}
+EXPORT_SYMBOL(mdiobus_read);
+
+/**
+ * mdiobus_write - Convenience function for writing a given MII mgmt register
+ * @bus: the mii_bus struct
+ * @addr: the phy address
+ * @regnum: register number to write
+ * @val: value to write to @regnum
+ *
+ * NOTE: MUST NOT be called from interrupt context,
+ * because the bus read/write functions may wait for an interrupt
+ * to conclude the operation.
+ */
+int mdiobus_write(struct mii_bus *bus, int addr, u32 regnum, u16 val)
+{
+	int err;
+
+	BUG_ON(in_interrupt());
+
+	mutex_lock(&bus->mdio_lock);
+	err = bus->write(bus, addr, regnum, val);
+	mutex_unlock(&bus->mdio_lock);
+
+	return err;
+}
+EXPORT_SYMBOL(mdiobus_write);
+
+/**
+ * mdio_bus_match - determine if given PHY driver supports the given PHY device
+ * @dev: target PHY device
+ * @drv: given PHY driver
+ *
+ * Description: Given a PHY device, and a PHY driver, return 1 if
+ *   the driver supports the device.  Otherwise, return 0.
+ */
+static int mdio_bus_match(struct device *dev, struct device_driver *drv)
+{
+	struct phy_device *phydev = to_phy_device(dev);
+	struct phy_driver *phydrv = to_phy_driver(drv);
+
+	return ((phydrv->phy_id & phydrv->phy_id_mask) ==
+		(phydev->phy_id & phydrv->phy_id_mask));
+}
+
+#ifdef CONFIG_PM
+
+static bool mdio_bus_phy_may_suspend(struct phy_device *phydev)
+{
+	struct device_driver *drv = phydev->dev.driver;
+	struct phy_driver *phydrv = to_phy_driver(drv);
+	struct net_device *netdev = phydev->attached_dev;
+
+	if (!drv || !phydrv->suspend)
+		return false;
+
+	/* PHY not attached? May suspend. */
+	if (!netdev)
+		return true;
+
+	/*
+	 * Don't suspend PHY if the attched netdev parent may wakeup.
+	 * The parent may point to a PCI device, as in tg3 driver.
+	 */
+	if (netdev->dev.parent && device_may_wakeup(netdev->dev.parent))
+		return false;
+
+	/*
+	 * Also don't suspend PHY if the netdev itself may wakeup. This
+	 * is the case for devices w/o underlaying pwr. mgmt. aware bus,
+	 * e.g. SoC devices.
+	 */
+	if (device_may_wakeup(&netdev->dev))
+		return false;
+
+	return true;
+}
+
+static int mdio_bus_suspend(struct device *dev)
+{
+	struct phy_driver *phydrv = to_phy_driver(dev->driver);
+	struct phy_device *phydev = to_phy_device(dev);
+
+	/*
+	 * We must stop the state machine manually, otherwise it stops out of
+	 * control, possibly with the phydev->lock held. Upon resume, netdev
+	 * may call phy routines that try to grab the same lock, and that may
+	 * lead to a deadlock.
+	 */
+	if (phydev->attached_dev && phydev->adjust_link)
+		phy_stop_machine(phydev);
+
+	if (!mdio_bus_phy_may_suspend(phydev))
+		return 0;
+
+	return phydrv->suspend(phydev);
+}
+
+static int mdio_bus_resume(struct device *dev)
+{
+	struct phy_driver *phydrv = to_phy_driver(dev->driver);
+	struct phy_device *phydev = to_phy_device(dev);
+	int ret;
+
+	if (!mdio_bus_phy_may_suspend(phydev))
+		goto no_resume;
+
+	ret = phydrv->resume(phydev);
+	if (ret < 0)
+		return ret;
+
+no_resume:
+	if (phydev->attached_dev && phydev->adjust_link)
+		phy_start_machine(phydev, NULL);
+
+	return 0;
+}
+
+static int mdio_bus_restore(struct device *dev)
+{
+	struct phy_device *phydev = to_phy_device(dev);
+	struct net_device *netdev = phydev->attached_dev;
+	int ret;
+
+	if (!netdev)
+		return 0;
+
+	ret = phy_init_hw(phydev);
+	if (ret < 0)
+		return ret;
+
+	/* The PHY needs to renegotiate. */
+	phydev->link = 0;
+	phydev->state = PHY_UP;
+
+	phy_start_machine(phydev, NULL);
+
+	return 0;
+}
+
+static struct dev_pm_ops mdio_bus_pm_ops = {
+	.suspend = mdio_bus_suspend,
+	.resume = mdio_bus_resume,
+	.freeze = mdio_bus_suspend,
+	.thaw = mdio_bus_resume,
+	.restore = mdio_bus_restore,
+};
+
+#define MDIO_BUS_PM_OPS (&mdio_bus_pm_ops)
+
+#else
+
+#define MDIO_BUS_PM_OPS NULL
+
+#endif /* CONFIG_PM */
+
+struct bus_type mdio_bus_type = {
+	.name		= "mdio_bus",
+	.match		= mdio_bus_match,
+	.pm		= MDIO_BUS_PM_OPS,
+};
+EXPORT_SYMBOL(mdio_bus_type);
+
+int __init mdio_bus_init(void)
+{
+	int ret;
+
+	ret = class_register(&mdio_bus_class);
+	if (!ret) {
+		ret = bus_register(&mdio_bus_type);
+		if (ret)
+			class_unregister(&mdio_bus_class);
+	}
+
+	return ret;
+}
+
+void mdio_bus_exit(void)
+{
+	class_unregister(&mdio_bus_class);
+	bus_unregister(&mdio_bus_type);
+}
diff --git a/ap/os/linux/linux-3.4.x/drivers/net/phy/micrel.c b/ap/os/linux/linux-3.4.x/drivers/net/phy/micrel.c
new file mode 100644
index 0000000..590f902
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/net/phy/micrel.c
@@ -0,0 +1,251 @@
+/*
+ * drivers/net/phy/micrel.c
+ *
+ * Driver for Micrel PHYs
+ *
+ * Author: David J. Choi
+ *
+ * Copyright (c) 2010 Micrel, Inc.
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ *
+ * Support : ksz9021 1000/100/10 phy from Micrel
+ *		ks8001, ks8737, ks8721, ks8041, ks8051 100/10 phy
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/phy.h>
+#include <linux/micrel_phy.h>
+
+/* general Interrupt control/status reg in vendor specific block. */
+#define MII_KSZPHY_INTCS			0x1B
+#define	KSZPHY_INTCS_JABBER			(1 << 15)
+#define	KSZPHY_INTCS_RECEIVE_ERR		(1 << 14)
+#define	KSZPHY_INTCS_PAGE_RECEIVE		(1 << 13)
+#define	KSZPHY_INTCS_PARELLEL			(1 << 12)
+#define	KSZPHY_INTCS_LINK_PARTNER_ACK		(1 << 11)
+#define	KSZPHY_INTCS_LINK_DOWN			(1 << 10)
+#define	KSZPHY_INTCS_REMOTE_FAULT		(1 << 9)
+#define	KSZPHY_INTCS_LINK_UP			(1 << 8)
+#define	KSZPHY_INTCS_ALL			(KSZPHY_INTCS_LINK_UP |\
+						KSZPHY_INTCS_LINK_DOWN)
+
+/* general PHY control reg in vendor specific block. */
+#define	MII_KSZPHY_CTRL			0x1F
+/* bitmap of PHY register to set interrupt mode */
+#define KSZPHY_CTRL_INT_ACTIVE_HIGH		(1 << 9)
+#define KSZ9021_CTRL_INT_ACTIVE_HIGH		(1 << 14)
+#define KS8737_CTRL_INT_ACTIVE_HIGH		(1 << 14)
+#define KSZ8051_RMII_50MHZ_CLK			(1 << 7)
+
+static int kszphy_ack_interrupt(struct phy_device *phydev)
+{
+	/* bit[7..0] int status, which is a read and clear register. */
+	int rc;
+
+	rc = phy_read(phydev, MII_KSZPHY_INTCS);
+
+	return (rc < 0) ? rc : 0;
+}
+
+static int kszphy_set_interrupt(struct phy_device *phydev)
+{
+	int temp;
+	temp = (PHY_INTERRUPT_ENABLED == phydev->interrupts) ?
+		KSZPHY_INTCS_ALL : 0;
+	return phy_write(phydev, MII_KSZPHY_INTCS, temp);
+}
+
+static int kszphy_config_intr(struct phy_device *phydev)
+{
+	int temp, rc;
+
+	/* set the interrupt pin active low */
+	temp = phy_read(phydev, MII_KSZPHY_CTRL);
+	temp &= ~KSZPHY_CTRL_INT_ACTIVE_HIGH;
+	phy_write(phydev, MII_KSZPHY_CTRL, temp);
+	rc = kszphy_set_interrupt(phydev);
+	return rc < 0 ? rc : 0;
+}
+
+static int ksz9021_config_intr(struct phy_device *phydev)
+{
+	int temp, rc;
+
+	/* set the interrupt pin active low */
+	temp = phy_read(phydev, MII_KSZPHY_CTRL);
+	temp &= ~KSZ9021_CTRL_INT_ACTIVE_HIGH;
+	phy_write(phydev, MII_KSZPHY_CTRL, temp);
+	rc = kszphy_set_interrupt(phydev);
+	return rc < 0 ? rc : 0;
+}
+
+static int ks8737_config_intr(struct phy_device *phydev)
+{
+	int temp, rc;
+
+	/* set the interrupt pin active low */
+	temp = phy_read(phydev, MII_KSZPHY_CTRL);
+	temp &= ~KS8737_CTRL_INT_ACTIVE_HIGH;
+	phy_write(phydev, MII_KSZPHY_CTRL, temp);
+	rc = kszphy_set_interrupt(phydev);
+	return rc < 0 ? rc : 0;
+}
+
+static int kszphy_config_init(struct phy_device *phydev)
+{
+	return 0;
+}
+
+static int ks8051_config_init(struct phy_device *phydev)
+{
+	int regval;
+
+	if (phydev->dev_flags & MICREL_PHY_50MHZ_CLK) {
+		regval = phy_read(phydev, MII_KSZPHY_CTRL);
+		regval |= KSZ8051_RMII_50MHZ_CLK;
+		phy_write(phydev, MII_KSZPHY_CTRL, regval);
+	}
+
+	return 0;
+}
+
+static struct phy_driver ks8737_driver = {
+	.phy_id		= PHY_ID_KS8737,
+	.phy_id_mask	= 0x00fffff0,
+	.name		= "Micrel KS8737",
+	.features	= (PHY_BASIC_FEATURES | SUPPORTED_Pause),
+	.flags		= PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT,
+	.config_init	= kszphy_config_init,
+	.config_aneg	= genphy_config_aneg,
+	.read_status	= genphy_read_status,
+	.ack_interrupt	= kszphy_ack_interrupt,
+	.config_intr	= ks8737_config_intr,
+	.driver		= { .owner = THIS_MODULE,},
+};
+
+static struct phy_driver ks8041_driver = {
+	.phy_id		= PHY_ID_KS8041,
+	.phy_id_mask	= 0x00fffff0,
+	.name		= "Micrel KS8041",
+	.features	= (PHY_BASIC_FEATURES | SUPPORTED_Pause
+				| SUPPORTED_Asym_Pause),
+	.flags		= PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT,
+	.config_init	= kszphy_config_init,
+	.config_aneg	= genphy_config_aneg,
+	.read_status	= genphy_read_status,
+	.ack_interrupt	= kszphy_ack_interrupt,
+	.config_intr	= kszphy_config_intr,
+	.driver		= { .owner = THIS_MODULE,},
+};
+
+static struct phy_driver ks8051_driver = {
+	.phy_id		= PHY_ID_KS8051,
+	.phy_id_mask	= 0x00fffff0,
+	.name		= "Micrel KS8051",
+	.features	= (PHY_BASIC_FEATURES | SUPPORTED_Pause
+				| SUPPORTED_Asym_Pause),
+	.flags		= PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT,
+	.config_init	= ks8051_config_init,
+	.config_aneg	= genphy_config_aneg,
+	.read_status	= genphy_read_status,
+	.ack_interrupt	= kszphy_ack_interrupt,
+	.config_intr	= kszphy_config_intr,
+	.driver		= { .owner = THIS_MODULE,},
+};
+
+static struct phy_driver ks8001_driver = {
+	.phy_id		= PHY_ID_KS8001,
+	.name		= "Micrel KS8001 or KS8721",
+	.phy_id_mask	= 0x00fffff0,
+	.features	= (PHY_BASIC_FEATURES | SUPPORTED_Pause),
+	.flags		= PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT,
+	.config_init	= kszphy_config_init,
+	.config_aneg	= genphy_config_aneg,
+	.read_status	= genphy_read_status,
+	.ack_interrupt	= kszphy_ack_interrupt,
+	.config_intr	= kszphy_config_intr,
+	.driver		= { .owner = THIS_MODULE,},
+};
+
+static struct phy_driver ksz9021_driver = {
+	.phy_id		= PHY_ID_KSZ9021,
+	.phy_id_mask	= 0x000fff10,
+	.name		= "Micrel KSZ9021 Gigabit PHY",
+	.features	= (PHY_GBIT_FEATURES | SUPPORTED_Pause
+				| SUPPORTED_Asym_Pause),
+	.flags		= PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT,
+	.config_init	= kszphy_config_init,
+	.config_aneg	= genphy_config_aneg,
+	.read_status	= genphy_read_status,
+	.ack_interrupt	= kszphy_ack_interrupt,
+	.config_intr	= ksz9021_config_intr,
+	.driver		= { .owner = THIS_MODULE, },
+};
+
+static int __init ksphy_init(void)
+{
+	int ret;
+
+	ret = phy_driver_register(&ks8001_driver);
+	if (ret)
+		goto err1;
+
+	ret = phy_driver_register(&ksz9021_driver);
+	if (ret)
+		goto err2;
+
+	ret = phy_driver_register(&ks8737_driver);
+	if (ret)
+		goto err3;
+	ret = phy_driver_register(&ks8041_driver);
+	if (ret)
+		goto err4;
+	ret = phy_driver_register(&ks8051_driver);
+	if (ret)
+		goto err5;
+
+	return 0;
+
+err5:
+	phy_driver_unregister(&ks8041_driver);
+err4:
+	phy_driver_unregister(&ks8737_driver);
+err3:
+	phy_driver_unregister(&ksz9021_driver);
+err2:
+	phy_driver_unregister(&ks8001_driver);
+err1:
+	return ret;
+}
+
+static void __exit ksphy_exit(void)
+{
+	phy_driver_unregister(&ks8001_driver);
+	phy_driver_unregister(&ks8737_driver);
+	phy_driver_unregister(&ksz9021_driver);
+	phy_driver_unregister(&ks8041_driver);
+	phy_driver_unregister(&ks8051_driver);
+}
+
+module_init(ksphy_init);
+module_exit(ksphy_exit);
+
+MODULE_DESCRIPTION("Micrel PHY driver");
+MODULE_AUTHOR("David J. Choi");
+MODULE_LICENSE("GPL");
+
+static struct mdio_device_id __maybe_unused micrel_tbl[] = {
+	{ PHY_ID_KSZ9021, 0x000fff10 },
+	{ PHY_ID_KS8001, 0x00fffff0 },
+	{ PHY_ID_KS8737, 0x00fffff0 },
+	{ PHY_ID_KS8041, 0x00fffff0 },
+	{ PHY_ID_KS8051, 0x00fffff0 },
+	{ }
+};
+
+MODULE_DEVICE_TABLE(mdio, micrel_tbl);
diff --git a/ap/os/linux/linux-3.4.x/drivers/net/phy/national.c b/ap/os/linux/linux-3.4.x/drivers/net/phy/national.c
new file mode 100644
index 0000000..04bb8fc
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/net/phy/national.c
@@ -0,0 +1,164 @@
+/*
+ * drivers/net/phy/national.c
+ *
+ * Driver for National Semiconductor PHYs
+ *
+ * Author: Stuart Menefy <stuart.menefy@st.com>
+ * Maintainer: Giuseppe Cavallaro <peppe.cavallaro@st.com>
+ *
+ * Copyright (c) 2008 STMicroelectronics Limited
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/mii.h>
+#include <linux/ethtool.h>
+#include <linux/phy.h>
+#include <linux/netdevice.h>
+
+/* DP83865 phy identifier values */
+#define DP83865_PHY_ID	0x20005c7a
+
+#define DP83865_INT_STATUS	0x14
+#define DP83865_INT_MASK	0x15
+#define DP83865_INT_CLEAR	0x17
+
+#define DP83865_INT_REMOTE_FAULT 0x0008
+#define DP83865_INT_ANE_COMPLETED 0x0010
+#define DP83865_INT_LINK_CHANGE	0xe000
+#define DP83865_INT_MASK_DEFAULT (DP83865_INT_REMOTE_FAULT | \
+				DP83865_INT_ANE_COMPLETED | \
+				DP83865_INT_LINK_CHANGE)
+
+/* Advanced proprietary configuration */
+#define NS_EXP_MEM_CTL	0x16
+#define NS_EXP_MEM_DATA	0x1d
+#define NS_EXP_MEM_ADD	0x1e
+
+#define LED_CTRL_REG 0x13
+#define AN_FALLBACK_AN 0x0001
+#define AN_FALLBACK_CRC 0x0002
+#define AN_FALLBACK_IE 0x0004
+#define ALL_FALLBACK_ON (AN_FALLBACK_AN |  AN_FALLBACK_CRC | AN_FALLBACK_IE)
+
+enum hdx_loopback {
+	hdx_loopback_on = 0,
+	hdx_loopback_off = 1,
+};
+
+static u8 ns_exp_read(struct phy_device *phydev, u16 reg)
+{
+	phy_write(phydev, NS_EXP_MEM_ADD, reg);
+	return phy_read(phydev, NS_EXP_MEM_DATA);
+}
+
+static void ns_exp_write(struct phy_device *phydev, u16 reg, u8 data)
+{
+	phy_write(phydev, NS_EXP_MEM_ADD, reg);
+	phy_write(phydev, NS_EXP_MEM_DATA, data);
+}
+
+static int ns_config_intr(struct phy_device *phydev)
+{
+	int err;
+
+	if (phydev->interrupts == PHY_INTERRUPT_ENABLED)
+		err = phy_write(phydev, DP83865_INT_MASK,
+				DP83865_INT_MASK_DEFAULT);
+	else
+		err = phy_write(phydev, DP83865_INT_MASK, 0);
+
+	return err;
+}
+
+static int ns_ack_interrupt(struct phy_device *phydev)
+{
+	int ret = phy_read(phydev, DP83865_INT_STATUS);
+	if (ret < 0)
+		return ret;
+
+	/* Clear the interrupt status bit by writing a “1”
+	 * to the corresponding bit in INT_CLEAR (2:0 are reserved) */
+	ret = phy_write(phydev, DP83865_INT_CLEAR, ret & ~0x7);
+
+	return ret;
+}
+
+static void ns_giga_speed_fallback(struct phy_device *phydev, int mode)
+{
+	int bmcr = phy_read(phydev, MII_BMCR);
+
+	phy_write(phydev, MII_BMCR, (bmcr | BMCR_PDOWN));
+
+	/* Enable 8 bit expended memory read/write (no auto increment) */
+	phy_write(phydev, NS_EXP_MEM_CTL, 0);
+	phy_write(phydev, NS_EXP_MEM_ADD, 0x1C0);
+	phy_write(phydev, NS_EXP_MEM_DATA, 0x0008);
+	phy_write(phydev, MII_BMCR, (bmcr & ~BMCR_PDOWN));
+	phy_write(phydev, LED_CTRL_REG, mode);
+}
+
+static void ns_10_base_t_hdx_loopack(struct phy_device *phydev, int disable)
+{
+	if (disable)
+		ns_exp_write(phydev, 0x1c0, ns_exp_read(phydev, 0x1c0) | 1);
+	else
+		ns_exp_write(phydev, 0x1c0,
+			     ns_exp_read(phydev, 0x1c0) & 0xfffe);
+
+	printk(KERN_DEBUG "DP83865 PHY: 10BASE-T HDX loopback %s\n",
+	       (ns_exp_read(phydev, 0x1c0) & 0x0001) ? "off" : "on");
+}
+
+static int ns_config_init(struct phy_device *phydev)
+{
+	ns_giga_speed_fallback(phydev, ALL_FALLBACK_ON);
+	/* In the latest MAC or switches design, the 10 Mbps loopback
+	   is desired to be turned off. */
+	ns_10_base_t_hdx_loopack(phydev, hdx_loopback_off);
+	return ns_ack_interrupt(phydev);
+}
+
+static struct phy_driver dp83865_driver = {
+	.phy_id = DP83865_PHY_ID,
+	.phy_id_mask = 0xfffffff0,
+	.name = "NatSemi DP83865",
+	.features = PHY_GBIT_FEATURES | SUPPORTED_Pause | SUPPORTED_Asym_Pause,
+	.flags = PHY_HAS_INTERRUPT,
+	.config_init = ns_config_init,
+	.config_aneg = genphy_config_aneg,
+	.read_status = genphy_read_status,
+	.ack_interrupt = ns_ack_interrupt,
+	.config_intr = ns_config_intr,
+	.driver = {.owner = THIS_MODULE,}
+};
+
+static int __init ns_init(void)
+{
+	return phy_driver_register(&dp83865_driver);
+}
+
+static void __exit ns_exit(void)
+{
+	phy_driver_unregister(&dp83865_driver);
+}
+
+MODULE_DESCRIPTION("NatSemi PHY driver");
+MODULE_AUTHOR("Stuart Menefy");
+MODULE_LICENSE("GPL");
+
+module_init(ns_init);
+module_exit(ns_exit);
+
+static struct mdio_device_id __maybe_unused ns_tbl[] = {
+	{ DP83865_PHY_ID, 0xfffffff0 },
+	{ }
+};
+
+MODULE_DEVICE_TABLE(mdio, ns_tbl);
diff --git a/ap/os/linux/linux-3.4.x/drivers/net/phy/phy.c b/ap/os/linux/linux-3.4.x/drivers/net/phy/phy.c
new file mode 100644
index 0000000..2a68618
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/net/phy/phy.c
@@ -0,0 +1,981 @@
+/*
+ * drivers/net/phy/phy.c
+ *
+ * Framework for configuring and reading PHY devices
+ * Based on code in sungem_phy.c and gianfar_phy.c
+ *
+ * Author: Andy Fleming
+ *
+ * Copyright (c) 2004 Freescale Semiconductor, Inc.
+ * Copyright (c) 2006, 2007  Maciej W. Rozycki
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ *
+ */
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/errno.h>
+#include <linux/unistd.h>
+#include <linux/interrupt.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+#include <linux/mm.h>
+#include <linux/module.h>
+#include <linux/mii.h>
+#include <linux/ethtool.h>
+#include <linux/phy.h>
+#include <linux/timer.h>
+#include <linux/workqueue.h>
+
+#include <linux/atomic.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/uaccess.h>
+
+/**
+ * phy_print_status - Convenience function to print out the current phy status
+ * @phydev: the phy_device struct
+ */
+void phy_print_status(struct phy_device *phydev)
+{
+	pr_info("PHY: %s - Link is %s", dev_name(&phydev->dev),
+			phydev->link ? "Up" : "Down");
+	if (phydev->link)
+		printk(KERN_CONT " - %d/%s", phydev->speed,
+				DUPLEX_FULL == phydev->duplex ?
+				"Full" : "Half");
+
+	printk(KERN_CONT "\n");
+}
+EXPORT_SYMBOL(phy_print_status);
+
+
+/**
+ * phy_clear_interrupt - Ack the phy device's interrupt
+ * @phydev: the phy_device struct
+ *
+ * If the @phydev driver has an ack_interrupt function, call it to
+ * ack and clear the phy device's interrupt.
+ *
+ * Returns 0 on success on < 0 on error.
+ */
+static int phy_clear_interrupt(struct phy_device *phydev)
+{
+	int err = 0;
+
+	if (phydev->drv->ack_interrupt)
+		err = phydev->drv->ack_interrupt(phydev);
+
+	return err;
+}
+
+/**
+ * phy_config_interrupt - configure the PHY device for the requested interrupts
+ * @phydev: the phy_device struct
+ * @interrupts: interrupt flags to configure for this @phydev
+ *
+ * Returns 0 on success on < 0 on error.
+ */
+static int phy_config_interrupt(struct phy_device *phydev, u32 interrupts)
+{
+	int err = 0;
+
+	phydev->interrupts = interrupts;
+	if (phydev->drv->config_intr)
+		err = phydev->drv->config_intr(phydev);
+
+	return err;
+}
+
+
+/**
+ * phy_aneg_done - return auto-negotiation status
+ * @phydev: target phy_device struct
+ *
+ * Description: Reads the status register and returns 0 either if
+ *   auto-negotiation is incomplete, or if there was an error.
+ *   Returns BMSR_ANEGCOMPLETE if auto-negotiation is done.
+ */
+static inline int phy_aneg_done(struct phy_device *phydev)
+{
+	int retval;
+
+	if((phydev->drv->features & SUPPORTED_Autoneg)==0)
+		return BMSR_ANEGCOMPLETE;
+
+	retval = phy_read(phydev, MII_BMSR);
+
+	return (retval < 0) ? retval : (retval & BMSR_ANEGCOMPLETE);
+}
+
+/* A structure for mapping a particular speed and duplex
+ * combination to a particular SUPPORTED and ADVERTISED value */
+struct phy_setting {
+	int speed;
+	int duplex;
+	u32 setting;
+};
+
+/* A mapping of all SUPPORTED settings to speed/duplex */
+static const struct phy_setting settings[] = {
+	{
+		.speed = 10000,
+		.duplex = DUPLEX_FULL,
+		.setting = SUPPORTED_10000baseT_Full,
+	},
+	{
+		.speed = SPEED_1000,
+		.duplex = DUPLEX_FULL,
+		.setting = SUPPORTED_1000baseT_Full,
+	},
+	{
+		.speed = SPEED_1000,
+		.duplex = DUPLEX_HALF,
+		.setting = SUPPORTED_1000baseT_Half,
+	},
+	{
+		.speed = SPEED_100,
+		.duplex = DUPLEX_FULL,
+		.setting = SUPPORTED_100baseT_Full,
+	},
+	{
+		.speed = SPEED_100,
+		.duplex = DUPLEX_HALF,
+		.setting = SUPPORTED_100baseT_Half,
+	},
+	{
+		.speed = SPEED_10,
+		.duplex = DUPLEX_FULL,
+		.setting = SUPPORTED_10baseT_Full,
+	},
+	{
+		.speed = SPEED_10,
+		.duplex = DUPLEX_HALF,
+		.setting = SUPPORTED_10baseT_Half,
+	},
+};
+
+#define MAX_NUM_SETTINGS ARRAY_SIZE(settings)
+
+/**
+ * phy_find_setting - find a PHY settings array entry that matches speed & duplex
+ * @speed: speed to match
+ * @duplex: duplex to match
+ *
+ * Description: Searches the settings array for the setting which
+ *   matches the desired speed and duplex, and returns the index
+ *   of that setting.  Returns the index of the last setting if
+ *   none of the others match.
+ */
+static inline int phy_find_setting(int speed, int duplex)
+{
+	int idx = 0;
+
+	while (idx < ARRAY_SIZE(settings) &&
+			(settings[idx].speed != speed ||
+			settings[idx].duplex != duplex))
+		idx++;
+
+	return idx < MAX_NUM_SETTINGS ? idx : MAX_NUM_SETTINGS - 1;
+}
+
+/**
+ * phy_find_valid - find a PHY setting that matches the requested features mask
+ * @idx: The first index in settings[] to search
+ * @features: A mask of the valid settings
+ *
+ * Description: Returns the index of the first valid setting less
+ *   than or equal to the one pointed to by idx, as determined by
+ *   the mask in features.  Returns the index of the last setting
+ *   if nothing else matches.
+ */
+static inline int phy_find_valid(int idx, u32 features)
+{
+	while (idx < MAX_NUM_SETTINGS && !(settings[idx].setting & features))
+		idx++;
+
+	return idx < MAX_NUM_SETTINGS ? idx : MAX_NUM_SETTINGS - 1;
+}
+
+/**
+ * phy_sanitize_settings - make sure the PHY is set to supported speed and duplex
+ * @phydev: the target phy_device struct
+ *
+ * Description: Make sure the PHY is set to supported speeds and
+ *   duplexes.  Drop down by one in this order:  1000/FULL,
+ *   1000/HALF, 100/FULL, 100/HALF, 10/FULL, 10/HALF.
+ */
+static void phy_sanitize_settings(struct phy_device *phydev)
+{
+	u32 features = phydev->supported;
+	int idx;
+
+	/* Sanitize settings based on PHY capabilities */
+	if ((features & SUPPORTED_Autoneg) == 0)
+		phydev->autoneg = AUTONEG_DISABLE;
+
+	idx = phy_find_valid(phy_find_setting(phydev->speed, phydev->duplex),
+			features);
+
+	phydev->speed = settings[idx].speed;
+	phydev->duplex = settings[idx].duplex;
+}
+
+/**
+ * phy_ethtool_sset - generic ethtool sset function, handles all the details
+ * @phydev: target phy_device struct
+ * @cmd: ethtool_cmd
+ *
+ * A few notes about parameter checking:
+ * - We don't set port or transceiver, so we don't care what they
+ *   were set to.
+ * - phy_start_aneg() will make sure forced settings are sane, and
+ *   choose the next best ones from the ones selected, so we don't
+ *   care if ethtool tries to give us bad values.
+ */
+int phy_ethtool_sset(struct phy_device *phydev, struct ethtool_cmd *cmd)
+{
+	u32 speed = ethtool_cmd_speed(cmd);
+
+	if (cmd->phy_address != phydev->addr)
+		return -EINVAL;
+
+	/* We make sure that we don't pass unsupported
+	 * values in to the PHY */
+	cmd->advertising &= phydev->supported;
+
+	/* Verify the settings we care about. */
+	if (cmd->autoneg != AUTONEG_ENABLE && cmd->autoneg != AUTONEG_DISABLE)
+		return -EINVAL;
+
+	if (cmd->autoneg == AUTONEG_ENABLE && cmd->advertising == 0)
+		return -EINVAL;
+
+	if (cmd->autoneg == AUTONEG_DISABLE &&
+	    ((speed != SPEED_1000 &&
+	      speed != SPEED_100 &&
+	      speed != SPEED_10) ||
+	     (cmd->duplex != DUPLEX_HALF &&
+	      cmd->duplex != DUPLEX_FULL)))
+		return -EINVAL;
+
+	phydev->autoneg = cmd->autoneg;
+
+	phydev->speed = speed;
+
+	phydev->advertising = cmd->advertising;
+
+	if (AUTONEG_ENABLE == cmd->autoneg)
+		phydev->advertising |= ADVERTISED_Autoneg;
+	else
+		phydev->advertising &= ~ADVERTISED_Autoneg;
+
+	phydev->duplex = cmd->duplex;
+
+	/* Restart the PHY */
+	phy_start_aneg(phydev);
+
+	return 0;
+}
+EXPORT_SYMBOL(phy_ethtool_sset);
+
+int phy_ethtool_gset(struct phy_device *phydev, struct ethtool_cmd *cmd)
+{
+	cmd->supported = phydev->supported;
+
+	cmd->advertising = phydev->advertising;
+
+	ethtool_cmd_speed_set(cmd, phydev->speed);
+	cmd->duplex = phydev->duplex;
+	cmd->port = PORT_MII;
+	cmd->phy_address = phydev->addr;
+	cmd->transceiver = XCVR_EXTERNAL;
+	cmd->autoneg = phydev->autoneg;
+
+	return 0;
+}
+EXPORT_SYMBOL(phy_ethtool_gset);
+
+/**
+ * phy_mii_ioctl - generic PHY MII ioctl interface
+ * @phydev: the phy_device struct
+ * @ifr: &struct ifreq for socket ioctl's
+ * @cmd: ioctl cmd to execute
+ *
+ * Note that this function is currently incompatible with the
+ * PHYCONTROL layer.  It changes registers without regard to
+ * current state.  Use at own risk.
+ */
+int phy_mii_ioctl(struct phy_device *phydev,
+		struct ifreq *ifr, int cmd)
+{
+	struct mii_ioctl_data *mii_data = if_mii(ifr);
+	u16 val = mii_data->val_in;
+
+	switch (cmd) {
+	case SIOCGMIIPHY:
+		mii_data->phy_id = phydev->addr;
+		/* fall through */
+
+	case SIOCGMIIREG:
+		mii_data->val_out = mdiobus_read(phydev->bus, mii_data->phy_id,
+						 mii_data->reg_num);
+		break;
+
+	case SIOCSMIIREG:
+		if (mii_data->phy_id == phydev->addr) {
+			switch(mii_data->reg_num) {
+			case MII_BMCR:
+				if ((val & (BMCR_RESET|BMCR_ANENABLE)) == 0)
+					phydev->autoneg = AUTONEG_DISABLE;
+				else
+					phydev->autoneg = AUTONEG_ENABLE;
+				if ((!phydev->autoneg) && (val & BMCR_FULLDPLX))
+					phydev->duplex = DUPLEX_FULL;
+				else
+					phydev->duplex = DUPLEX_HALF;
+				if ((!phydev->autoneg) &&
+						(val & BMCR_SPEED1000))
+					phydev->speed = SPEED_1000;
+				else if ((!phydev->autoneg) &&
+						(val & BMCR_SPEED100))
+					phydev->speed = SPEED_100;
+				break;
+			case MII_ADVERTISE:
+				phydev->advertising = val;
+				break;
+			default:
+				/* do nothing */
+				break;
+			}
+		}
+
+		mdiobus_write(phydev->bus, mii_data->phy_id,
+			      mii_data->reg_num, val);
+
+		if (mii_data->reg_num == MII_BMCR &&
+		    val & BMCR_RESET &&
+		    phydev->drv->config_init) {
+			phy_scan_fixups(phydev);
+			phydev->drv->config_init(phydev);
+		}
+		break;
+		
+	case SIOCVLAN:
+		if (phydev->drv->auto_adapt)
+		    return phydev->drv->auto_adapt(phydev, ifr);
+		break;
+		
+	case SIOCSHWTSTAMP:
+		if (phydev->drv->hwtstamp)
+			return phydev->drv->hwtstamp(phydev, ifr);
+		/* fall through */
+
+	default:
+		return -EOPNOTSUPP;
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL(phy_mii_ioctl);
+
+/**
+ * phy_start_aneg - start auto-negotiation for this PHY device
+ * @phydev: the phy_device struct
+ *
+ * Description: Sanitizes the settings (if we're not autonegotiating
+ *   them), and then calls the driver's config_aneg function.
+ *   If the PHYCONTROL Layer is operating, we change the state to
+ *   reflect the beginning of Auto-negotiation or forcing.
+ */
+int phy_start_aneg(struct phy_device *phydev)
+{
+	int err;
+
+	mutex_lock(&phydev->lock);
+
+	if (AUTONEG_DISABLE == phydev->autoneg)
+		phy_sanitize_settings(phydev);
+
+	err = phydev->drv->config_aneg(phydev);
+
+	if (err < 0)
+		goto out_unlock;
+
+	if (phydev->state != PHY_HALTED) {
+		if (AUTONEG_ENABLE == phydev->autoneg) {
+			phydev->state = PHY_AN;
+			phydev->link_timeout = PHY_AN_TIMEOUT;
+		} else {
+			phydev->state = PHY_FORCING;
+			phydev->link_timeout = PHY_FORCE_TIMEOUT;
+		}
+	}
+
+out_unlock:
+	mutex_unlock(&phydev->lock);
+	return err;
+}
+EXPORT_SYMBOL(phy_start_aneg);
+
+
+static void phy_change(struct work_struct *work);
+
+/**
+ * phy_start_machine - start PHY state machine tracking
+ * @phydev: the phy_device struct
+ * @handler: callback function for state change notifications
+ *
+ * Description: The PHY infrastructure can run a state machine
+ *   which tracks whether the PHY is starting up, negotiating,
+ *   etc.  This function starts the timer which tracks the state
+ *   of the PHY.  If you want to be notified when the state changes,
+ *   pass in the callback @handler, otherwise, pass NULL.  If you
+ *   want to maintain your own state machine, do not call this
+ *   function.
+ */
+void phy_start_machine(struct phy_device *phydev,
+		void (*handler)(struct net_device *))
+{
+	phydev->adjust_state = handler;
+
+	schedule_delayed_work(&phydev->state_queue, HZ);
+}
+
+/**
+ * phy_stop_machine - stop the PHY state machine tracking
+ * @phydev: target phy_device struct
+ *
+ * Description: Stops the state machine timer, sets the state to UP
+ *   (unless it wasn't up yet). This function must be called BEFORE
+ *   phy_detach.
+ */
+void phy_stop_machine(struct phy_device *phydev)
+{
+	cancel_delayed_work_sync(&phydev->state_queue);
+
+	mutex_lock(&phydev->lock);
+	if (phydev->state > PHY_UP)
+		phydev->state = PHY_UP;
+	mutex_unlock(&phydev->lock);
+
+	phydev->adjust_state = NULL;
+}
+
+/**
+ * phy_force_reduction - reduce PHY speed/duplex settings by one step
+ * @phydev: target phy_device struct
+ *
+ * Description: Reduces the speed/duplex settings by one notch,
+ *   in this order--
+ *   1000/FULL, 1000/HALF, 100/FULL, 100/HALF, 10/FULL, 10/HALF.
+ *   The function bottoms out at 10/HALF.
+ */
+static void phy_force_reduction(struct phy_device *phydev)
+{
+	int idx;
+
+	idx = phy_find_setting(phydev->speed, phydev->duplex);
+	
+	idx++;
+
+	idx = phy_find_valid(idx, phydev->supported);
+
+	phydev->speed = settings[idx].speed;
+	phydev->duplex = settings[idx].duplex;
+
+	pr_info("Trying %d/%s\n", phydev->speed,
+			DUPLEX_FULL == phydev->duplex ?
+			"FULL" : "HALF");
+}
+
+
+/**
+ * phy_error - enter HALTED state for this PHY device
+ * @phydev: target phy_device struct
+ *
+ * Moves the PHY to the HALTED state in response to a read
+ * or write error, and tells the controller the link is down.
+ * Must not be called from interrupt context, or while the
+ * phydev->lock is held.
+ */
+static void phy_error(struct phy_device *phydev)
+{
+	mutex_lock(&phydev->lock);
+	phydev->state = PHY_HALTED;
+	mutex_unlock(&phydev->lock);
+}
+
+/**
+ * phy_interrupt - PHY interrupt handler
+ * @irq: interrupt line
+ * @phy_dat: phy_device pointer
+ *
+ * Description: When a PHY interrupt occurs, the handler disables
+ * interrupts, and schedules a work task to clear the interrupt.
+ */
+static irqreturn_t phy_interrupt(int irq, void *phy_dat)
+{
+	struct phy_device *phydev = phy_dat;
+
+	if (PHY_HALTED == phydev->state)
+		return IRQ_NONE;		/* It can't be ours.  */
+
+	/* The MDIO bus is not allowed to be written in interrupt
+	 * context, so we need to disable the irq here.  A work
+	 * queue will write the PHY to disable and clear the
+	 * interrupt, and then reenable the irq line. */
+	disable_irq_nosync(irq);
+	atomic_inc(&phydev->irq_disable);
+
+	schedule_work(&phydev->phy_queue);
+
+	return IRQ_HANDLED;
+}
+
+/**
+ * phy_enable_interrupts - Enable the interrupts from the PHY side
+ * @phydev: target phy_device struct
+ */
+static int phy_enable_interrupts(struct phy_device *phydev)
+{
+	int err;
+
+	err = phy_clear_interrupt(phydev);
+
+	if (err < 0)
+		return err;
+
+	err = phy_config_interrupt(phydev, PHY_INTERRUPT_ENABLED);
+
+	return err;
+}
+
+/**
+ * phy_disable_interrupts - Disable the PHY interrupts from the PHY side
+ * @phydev: target phy_device struct
+ */
+static int phy_disable_interrupts(struct phy_device *phydev)
+{
+	int err;
+
+	/* Disable PHY interrupts */
+	err = phy_config_interrupt(phydev, PHY_INTERRUPT_DISABLED);
+
+	if (err)
+		goto phy_err;
+
+	/* Clear the interrupt */
+	err = phy_clear_interrupt(phydev);
+
+	if (err)
+		goto phy_err;
+
+	return 0;
+
+phy_err:
+	phy_error(phydev);
+
+	return err;
+}
+
+/**
+ * phy_start_interrupts - request and enable interrupts for a PHY device
+ * @phydev: target phy_device struct
+ *
+ * Description: Request the interrupt for the given PHY.
+ *   If this fails, then we set irq to PHY_POLL.
+ *   Otherwise, we enable the interrupts in the PHY.
+ *   This should only be called with a valid IRQ number.
+ *   Returns 0 on success or < 0 on error.
+ */
+int phy_start_interrupts(struct phy_device *phydev)
+{
+	int err = 0;
+
+	INIT_WORK(&phydev->phy_queue, phy_change);
+
+	atomic_set(&phydev->irq_disable, 0);
+	if (request_irq(phydev->irq, phy_interrupt,
+				IRQF_SHARED,
+				"phy_interrupt",
+				phydev) < 0) {
+		printk(KERN_WARNING "%s: Can't get IRQ %d (PHY)\n",
+				phydev->bus->name,
+				phydev->irq);
+		phydev->irq = PHY_POLL;
+		return 0;
+	}
+
+	err = phy_enable_interrupts(phydev);
+
+	return err;
+}
+EXPORT_SYMBOL(phy_start_interrupts);
+
+/**
+ * phy_stop_interrupts - disable interrupts from a PHY device
+ * @phydev: target phy_device struct
+ */
+int phy_stop_interrupts(struct phy_device *phydev)
+{
+	int err;
+
+	err = phy_disable_interrupts(phydev);
+
+	if (err)
+		phy_error(phydev);
+
+	free_irq(phydev->irq, phydev);
+
+	/*
+	 * Cannot call flush_scheduled_work() here as desired because
+	 * of rtnl_lock(), but we do not really care about what would
+	 * be done, except from enable_irq(), so cancel any work
+	 * possibly pending and take care of the matter below.
+	 */
+	cancel_work_sync(&phydev->phy_queue);
+	/*
+	 * If work indeed has been cancelled, disable_irq() will have
+	 * been left unbalanced from phy_interrupt() and enable_irq()
+	 * has to be called so that other devices on the line work.
+	 */
+	while (atomic_dec_return(&phydev->irq_disable) >= 0)
+		enable_irq(phydev->irq);
+
+	return err;
+}
+EXPORT_SYMBOL(phy_stop_interrupts);
+
+
+/**
+ * phy_change - Scheduled by the phy_interrupt/timer to handle PHY changes
+ * @work: work_struct that describes the work to be done
+ */
+static void phy_change(struct work_struct *work)
+{
+	int err;
+	struct phy_device *phydev =
+		container_of(work, struct phy_device, phy_queue);
+
+	if (phydev->drv->did_interrupt &&
+	    !phydev->drv->did_interrupt(phydev))
+		goto ignore;
+
+	err = phy_disable_interrupts(phydev);
+
+	if (err)
+		goto phy_err;
+
+	mutex_lock(&phydev->lock);
+	if ((PHY_RUNNING == phydev->state) || (PHY_NOLINK == phydev->state))
+		phydev->state = PHY_CHANGELINK;
+	mutex_unlock(&phydev->lock);
+
+	atomic_dec(&phydev->irq_disable);
+	enable_irq(phydev->irq);
+
+	/* Reenable interrupts */
+	if (PHY_HALTED != phydev->state)
+		err = phy_config_interrupt(phydev, PHY_INTERRUPT_ENABLED);
+
+	if (err)
+		goto irq_enable_err;
+
+	/* reschedule state queue work to run as soon as possible */
+	cancel_delayed_work_sync(&phydev->state_queue);
+	schedule_delayed_work(&phydev->state_queue, 0);
+
+	return;
+
+ignore:
+	atomic_dec(&phydev->irq_disable);
+	enable_irq(phydev->irq);
+	return;
+
+irq_enable_err:
+	disable_irq(phydev->irq);
+	atomic_inc(&phydev->irq_disable);
+phy_err:
+	phy_error(phydev);
+}
+
+/**
+ * phy_stop - Bring down the PHY link, and stop checking the status
+ * @phydev: target phy_device struct
+ */
+void phy_stop(struct phy_device *phydev)
+{
+	mutex_lock(&phydev->lock);
+
+	if (PHY_HALTED == phydev->state)
+		goto out_unlock;
+
+	if (phydev->irq != PHY_POLL) {
+		/* Disable PHY Interrupts */
+		phy_config_interrupt(phydev, PHY_INTERRUPT_DISABLED);
+
+		/* Clear any pending interrupts */
+		phy_clear_interrupt(phydev);
+	}
+
+	phydev->state = PHY_HALTED;
+
+out_unlock:
+	mutex_unlock(&phydev->lock);
+
+	/*
+	 * Cannot call flush_scheduled_work() here as desired because
+	 * of rtnl_lock(), but PHY_HALTED shall guarantee phy_change()
+	 * will not reenable interrupts.
+	 */
+}
+
+
+/**
+ * phy_start - start or restart a PHY device
+ * @phydev: target phy_device struct
+ *
+ * Description: Indicates the attached device's readiness to
+ *   handle PHY-related work.  Used during startup to start the
+ *   PHY, and after a call to phy_stop() to resume operation.
+ *   Also used to indicate the MDIO bus has cleared an error
+ *   condition.
+ */
+void phy_start(struct phy_device *phydev)
+{
+	mutex_lock(&phydev->lock);
+
+	switch (phydev->state) {
+		case PHY_STARTING:
+			phydev->state = PHY_PENDING;
+			break;
+		case PHY_READY:
+			phydev->state = PHY_UP;
+			break;
+		case PHY_HALTED:
+			phydev->state = PHY_RESUMING;
+		default:
+			break;
+	}
+	mutex_unlock(&phydev->lock);
+}
+EXPORT_SYMBOL(phy_stop);
+EXPORT_SYMBOL(phy_start);
+
+/**
+ * phy_state_machine - Handle the state machine
+ * @work: work_struct that describes the work to be done
+ */
+void phy_state_machine(struct work_struct *work)
+{
+	struct delayed_work *dwork = to_delayed_work(work);
+	struct phy_device *phydev =
+			container_of(dwork, struct phy_device, state_queue);
+	int needs_aneg = 0;
+	int err = 0;
+
+	mutex_lock(&phydev->lock);
+
+	if (phydev->adjust_state)
+		phydev->adjust_state(phydev->attached_dev);
+
+	if ((phydev->drv)&&(phydev->drv->private_proc))
+		phydev->drv->private_proc(phydev);
+
+	switch(phydev->state) {
+		case PHY_DOWN:
+		case PHY_STARTING:
+		case PHY_READY:
+		case PHY_PENDING:
+			break;
+		case PHY_UP:
+			needs_aneg = 1;
+
+			phydev->link_timeout = PHY_AN_TIMEOUT;
+
+			break;
+		case PHY_AN:
+			err = phy_read_status(phydev);
+
+			if (err < 0)
+				break;
+
+			/* If the link is down, give up on
+			 * negotiation for now */
+			if (!phydev->link) {
+				phydev->state = PHY_NOLINK;
+				netif_carrier_off(phydev->attached_dev);
+				phydev->adjust_link(phydev->attached_dev);
+				break;
+			}
+
+			/* Check if negotiation is done.  Break
+			 * if there's an error */
+			err = phy_aneg_done(phydev);
+			if (err < 0)
+				break;
+
+			/* If AN is done, we're running */
+			if (err > 0) {
+				phydev->state = PHY_RUNNING;
+				netif_carrier_on(phydev->attached_dev);
+				phydev->adjust_link(phydev->attached_dev);
+
+			} else if (0 == phydev->link_timeout--) {
+				int idx;
+
+				needs_aneg = 1;
+				/* If we have the magic_aneg bit,
+				 * we try again */
+				if (phydev->drv->flags & PHY_HAS_MAGICANEG)
+					break;
+
+				/* The timer expired, and we still
+				 * don't have a setting, so we try
+				 * forcing it until we find one that
+				 * works, starting from the fastest speed,
+				 * and working our way down */
+				idx = phy_find_valid(0, phydev->supported);
+
+				phydev->speed = settings[idx].speed;
+				phydev->duplex = settings[idx].duplex;
+
+				phydev->autoneg = AUTONEG_DISABLE;
+
+				pr_info("Trying %d/%s\n", phydev->speed,
+						DUPLEX_FULL ==
+						phydev->duplex ?
+						"FULL" : "HALF");
+			}
+			break;
+		case PHY_NOLINK:
+			err = phy_read_status(phydev);
+
+			if (err)
+				break;
+
+			if (phydev->link) {
+				phydev->state = PHY_RUNNING;
+				netif_carrier_on(phydev->attached_dev);
+				phydev->adjust_link(phydev->attached_dev);
+			}
+			break;
+		case PHY_FORCING:
+			err = genphy_update_link(phydev);
+
+			if (err)
+				break;
+
+			if (phydev->link) {
+				phydev->state = PHY_RUNNING;
+				netif_carrier_on(phydev->attached_dev);
+			} else {
+				if (0 == phydev->link_timeout--) {
+					phy_force_reduction(phydev);
+					needs_aneg = 1;
+				}
+			}
+
+			phydev->adjust_link(phydev->attached_dev);
+			break;
+		case PHY_RUNNING:
+			/* Only register a CHANGE if we are
+			 * polling */
+			if (PHY_POLL == phydev->irq)
+				phydev->state = PHY_CHANGELINK;
+			break;
+		case PHY_CHANGELINK:
+			err = phy_read_status(phydev);
+
+			if (err)
+				break;
+
+			if (phydev->link) {
+				phydev->state = PHY_RUNNING;
+				netif_carrier_on(phydev->attached_dev);
+			} else {
+				phydev->state = PHY_NOLINK;
+				netif_carrier_off(phydev->attached_dev);
+			}
+
+			phydev->adjust_link(phydev->attached_dev);
+
+			if (PHY_POLL != phydev->irq)
+				err = phy_config_interrupt(phydev,
+						PHY_INTERRUPT_ENABLED);
+			break;
+		case PHY_HALTED:
+			if (phydev->link) {
+				phydev->link = 0;
+				netif_carrier_off(phydev->attached_dev);
+				phydev->adjust_link(phydev->attached_dev);
+			}
+			break;
+		case PHY_RESUMING:
+
+			err = phy_clear_interrupt(phydev);
+
+			if (err)
+				break;
+
+			err = phy_config_interrupt(phydev,
+					PHY_INTERRUPT_ENABLED);
+
+			if (err)
+				break;
+
+			if (AUTONEG_ENABLE == phydev->autoneg) {
+				err = phy_aneg_done(phydev);
+				if (err < 0)
+					break;
+
+				/* err > 0 if AN is done.
+				 * Otherwise, it's 0, and we're
+				 * still waiting for AN */
+				if (err > 0) {
+					err = phy_read_status(phydev);
+					if (err)
+						break;
+
+					if (phydev->link) {
+						phydev->state = PHY_RUNNING;
+						netif_carrier_on(phydev->attached_dev);
+					} else
+						phydev->state = PHY_NOLINK;
+					phydev->adjust_link(phydev->attached_dev);
+				} else {
+					phydev->state = PHY_AN;
+					phydev->link_timeout = PHY_AN_TIMEOUT;
+				}
+			} else {
+				err = phy_read_status(phydev);
+				if (err)
+					break;
+
+				if (phydev->link) {
+					phydev->state = PHY_RUNNING;
+					netif_carrier_on(phydev->attached_dev);
+				} else
+					phydev->state = PHY_NOLINK;
+				phydev->adjust_link(phydev->attached_dev);
+			}
+			break;
+	}
+
+	mutex_unlock(&phydev->lock);
+
+	if (needs_aneg)
+		err = phy_start_aneg(phydev);
+
+	if (err < 0)
+		phy_error(phydev);
+
+	schedule_delayed_work(&phydev->state_queue, PHY_STATE_TIME * HZ);
+}
diff --git a/ap/os/linux/linux-3.4.x/drivers/net/phy/phy_device.c b/ap/os/linux/linux-3.4.x/drivers/net/phy/phy_device.c
new file mode 100644
index 0000000..abb3669
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/net/phy/phy_device.c
@@ -0,0 +1,1034 @@
+/*
+ * drivers/net/phy/phy_device.c
+ *
+ * Framework for finding and configuring PHYs.
+ * Also contains generic PHY driver
+ *
+ * Author: Andy Fleming
+ *
+ * Copyright (c) 2004 Freescale Semiconductor, Inc.
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ *
+ */
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/errno.h>
+#include <linux/unistd.h>
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+#include <linux/mm.h>
+#include <linux/module.h>
+#include <linux/mii.h>
+#include <linux/ethtool.h>
+#include <linux/phy.h>
+
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/uaccess.h>
+
+MODULE_DESCRIPTION("PHY library");
+MODULE_AUTHOR("Andy Fleming");
+MODULE_LICENSE("GPL");
+
+void phy_device_free(struct phy_device *phydev)
+{
+	kfree(phydev);
+}
+EXPORT_SYMBOL(phy_device_free);
+
+static void phy_device_release(struct device *dev)
+{
+	phy_device_free(to_phy_device(dev));
+}
+
+static struct phy_driver genphy_driver;
+extern int mdio_bus_init(void);
+extern void mdio_bus_exit(void);
+
+static LIST_HEAD(phy_fixup_list);
+static DEFINE_MUTEX(phy_fixup_lock);
+
+static int phy_attach_direct(struct net_device *dev, struct phy_device *phydev,
+			     u32 flags, phy_interface_t interface);
+
+/*
+ * Creates a new phy_fixup and adds it to the list
+ * @bus_id: A string which matches phydev->dev.bus_id (or PHY_ANY_ID)
+ * @phy_uid: Used to match against phydev->phy_id (the UID of the PHY)
+ * 	It can also be PHY_ANY_UID
+ * @phy_uid_mask: Applied to phydev->phy_id and fixup->phy_uid before
+ * 	comparison
+ * @run: The actual code to be run when a matching PHY is found
+ */
+int phy_register_fixup(const char *bus_id, u32 phy_uid, u32 phy_uid_mask,
+		int (*run)(struct phy_device *))
+{
+	struct phy_fixup *fixup;
+
+	fixup = kzalloc(sizeof(struct phy_fixup), GFP_KERNEL);
+	if (!fixup)
+		return -ENOMEM;
+
+	strlcpy(fixup->bus_id, bus_id, sizeof(fixup->bus_id));
+	fixup->phy_uid = phy_uid;
+	fixup->phy_uid_mask = phy_uid_mask;
+	fixup->run = run;
+
+	mutex_lock(&phy_fixup_lock);
+	list_add_tail(&fixup->list, &phy_fixup_list);
+	mutex_unlock(&phy_fixup_lock);
+
+	return 0;
+}
+EXPORT_SYMBOL(phy_register_fixup);
+
+/* Registers a fixup to be run on any PHY with the UID in phy_uid */
+int phy_register_fixup_for_uid(u32 phy_uid, u32 phy_uid_mask,
+		int (*run)(struct phy_device *))
+{
+	return phy_register_fixup(PHY_ANY_ID, phy_uid, phy_uid_mask, run);
+}
+EXPORT_SYMBOL(phy_register_fixup_for_uid);
+
+/* Registers a fixup to be run on the PHY with id string bus_id */
+int phy_register_fixup_for_id(const char *bus_id,
+		int (*run)(struct phy_device *))
+{
+	return phy_register_fixup(bus_id, PHY_ANY_UID, 0xffffffff, run);
+}
+EXPORT_SYMBOL(phy_register_fixup_for_id);
+
+/*
+ * Returns 1 if fixup matches phydev in bus_id and phy_uid.
+ * Fixups can be set to match any in one or more fields.
+ */
+static int phy_needs_fixup(struct phy_device *phydev, struct phy_fixup *fixup)
+{
+	if (strcmp(fixup->bus_id, dev_name(&phydev->dev)) != 0)
+		if (strcmp(fixup->bus_id, PHY_ANY_ID) != 0)
+			return 0;
+
+	if ((fixup->phy_uid & fixup->phy_uid_mask) !=
+			(phydev->phy_id & fixup->phy_uid_mask))
+		if (fixup->phy_uid != PHY_ANY_UID)
+			return 0;
+
+	return 1;
+}
+
+/* Runs any matching fixups for this phydev */
+int phy_scan_fixups(struct phy_device *phydev)
+{
+	struct phy_fixup *fixup;
+
+	mutex_lock(&phy_fixup_lock);
+	list_for_each_entry(fixup, &phy_fixup_list, list) {
+		if (phy_needs_fixup(phydev, fixup)) {
+			int err;
+
+			err = fixup->run(phydev);
+
+			if (err < 0) {
+				mutex_unlock(&phy_fixup_lock);
+				return err;
+			}
+		}
+	}
+	mutex_unlock(&phy_fixup_lock);
+
+	return 0;
+}
+EXPORT_SYMBOL(phy_scan_fixups);
+
+static struct phy_device* phy_device_create(struct mii_bus *bus,
+					    int addr, int phy_id)
+{
+	struct phy_device *dev;
+
+	/* We allocate the device, and initialize the
+	 * default values */
+	dev = kzalloc(sizeof(*dev), GFP_KERNEL);
+
+	if (NULL == dev)
+		return (struct phy_device*) PTR_ERR((void*)-ENOMEM);
+
+	dev->dev.release = phy_device_release;
+
+	dev->speed = 0;
+	dev->duplex = -1;
+	dev->pause = dev->asym_pause = 0;
+	dev->link = 1;
+	dev->interface = PHY_INTERFACE_MODE_GMII;
+
+	dev->autoneg = AUTONEG_ENABLE;
+
+	dev->addr = addr;
+	dev->phy_id = phy_id;
+	dev->bus = bus;
+	dev->dev.parent = bus->parent;
+	dev->dev.bus = &mdio_bus_type;
+	dev->irq = bus->irq != NULL ? bus->irq[addr] : PHY_POLL;
+	dev_set_name(&dev->dev, PHY_ID_FMT, bus->id, addr);
+
+	dev->state = PHY_DOWN;
+
+	mutex_init(&dev->lock);
+	INIT_DELAYED_WORK(&dev->state_queue, phy_state_machine);
+
+	/* Request the appropriate module unconditionally; don't
+	   bother trying to do so only if it isn't already loaded,
+	   because that gets complicated. A hotplug event would have
+	   done an unconditional modprobe anyway.
+	   We don't do normal hotplug because it won't work for MDIO
+	   -- because it relies on the device staying around for long
+	   enough for the driver to get loaded. With MDIO, the NIC
+	   driver will get bored and give up as soon as it finds that
+	   there's no driver _already_ loaded. */
+	request_module(MDIO_MODULE_PREFIX MDIO_ID_FMT, MDIO_ID_ARGS(phy_id));
+
+	return dev;
+}
+
+/**
+ * get_phy_id - reads the specified addr for its ID.
+ * @bus: the target MII bus
+ * @addr: PHY address on the MII bus
+ * @phy_id: where to store the ID retrieved.
+ *
+ * Description: Reads the ID registers of the PHY at @addr on the
+ *   @bus, stores it in @phy_id and returns zero on success.
+ */
+int get_phy_id(struct mii_bus *bus, int addr, u32 *phy_id)
+{
+	int phy_reg;
+
+	/* Grab the bits from PHYIR1, and put them
+	 * in the upper half */
+	phy_reg = mdiobus_read(bus, addr, MII_PHYSID1);
+
+	if (phy_reg < 0)
+		return -EIO;
+
+	*phy_id = (phy_reg & 0xffff) << 16;
+
+	/* Grab the bits from PHYIR2, and put them in the lower half */
+	phy_reg = mdiobus_read(bus, addr, MII_PHYSID2);
+
+	if (phy_reg < 0)
+		return -EIO;
+
+	*phy_id |= (phy_reg & 0xffff);
+
+	return 0;
+}
+EXPORT_SYMBOL(get_phy_id);
+
+/**
+ * get_phy_device - reads the specified PHY device and returns its @phy_device struct
+ * @bus: the target MII bus
+ * @addr: PHY address on the MII bus
+ *
+ * Description: Reads the ID registers of the PHY at @addr on the
+ *   @bus, then allocates and returns the phy_device to represent it.
+ */
+struct phy_device * get_phy_device(struct mii_bus *bus, int addr)
+{
+	struct phy_device *dev = NULL;
+	u32 phy_id;
+	int r;
+
+	r = get_phy_id(bus, addr, &phy_id);
+	if (r)
+		return ERR_PTR(r);
+
+	printk("@@@@@@@@get_phy_device addr=%d, phy_id=0x%x.\n",addr,phy_id);
+
+	/* If the phy_id is mostly Fs, there is no device there */
+	if ((phy_id & 0x1fffffff) == 0x1fffffff)
+		return NULL;
+
+	dev = phy_device_create(bus, addr, phy_id);
+
+	return dev;
+}
+EXPORT_SYMBOL(get_phy_device);
+
+/**
+ * phy_device_register - Register the phy device on the MDIO bus
+ * @phydev: phy_device structure to be added to the MDIO bus
+ */
+int phy_device_register(struct phy_device *phydev)
+{
+	int err;
+
+	/* Don't register a phy if one is already registered at this
+	 * address */
+	if (phydev->bus->phy_map[phydev->addr])
+		return -EINVAL;
+	phydev->bus->phy_map[phydev->addr] = phydev;
+
+	/* Run all of the fixups for this PHY */
+	phy_scan_fixups(phydev);
+
+	err = device_register(&phydev->dev);
+	if (err) {
+		pr_err("phy %d failed to register\n", phydev->addr);
+		goto out;
+	}
+
+	return 0;
+
+ out:
+	phydev->bus->phy_map[phydev->addr] = NULL;
+	return err;
+}
+EXPORT_SYMBOL(phy_device_register);
+
+/**
+ * phy_find_first - finds the first PHY device on the bus
+ * @bus: the target MII bus
+ */
+struct phy_device *phy_find_first(struct mii_bus *bus)
+{
+	int addr;
+
+	for (addr = 0; addr < PHY_MAX_ADDR; addr++) {
+		if (bus->phy_map[addr])
+			return bus->phy_map[addr];
+	}
+	return NULL;
+}
+EXPORT_SYMBOL(phy_find_first);
+
+/**
+ * phy_prepare_link - prepares the PHY layer to monitor link status
+ * @phydev: target phy_device struct
+ * @handler: callback function for link status change notifications
+ *
+ * Description: Tells the PHY infrastructure to handle the
+ *   gory details on monitoring link status (whether through
+ *   polling or an interrupt), and to call back to the
+ *   connected device driver when the link status changes.
+ *   If you want to monitor your own link state, don't call
+ *   this function.
+ */
+static void phy_prepare_link(struct phy_device *phydev,
+		void (*handler)(struct net_device *))
+{
+	phydev->adjust_link = handler;
+}
+
+/**
+ * phy_connect_direct - connect an ethernet device to a specific phy_device
+ * @dev: the network device to connect
+ * @phydev: the pointer to the phy device
+ * @handler: callback function for state change notifications
+ * @flags: PHY device's dev_flags
+ * @interface: PHY device's interface
+ */
+int phy_connect_direct(struct net_device *dev, struct phy_device *phydev,
+		       void (*handler)(struct net_device *), u32 flags,
+		       phy_interface_t interface)
+{
+	int rc;
+
+	rc = phy_attach_direct(dev, phydev, flags, interface);
+	if (rc)
+		return rc;
+
+	phy_prepare_link(phydev, handler);
+	phy_start_machine(phydev, NULL);
+	if (phydev->irq > 0)
+		phy_start_interrupts(phydev);
+
+	return 0;
+}
+EXPORT_SYMBOL(phy_connect_direct);
+
+/**
+ * phy_connect - connect an ethernet device to a PHY device
+ * @dev: the network device to connect
+ * @bus_id: the id string of the PHY device to connect
+ * @handler: callback function for state change notifications
+ * @flags: PHY device's dev_flags
+ * @interface: PHY device's interface
+ *
+ * Description: Convenience function for connecting ethernet
+ *   devices to PHY devices.  The default behavior is for
+ *   the PHY infrastructure to handle everything, and only notify
+ *   the connected driver when the link status changes.  If you
+ *   don't want, or can't use the provided functionality, you may
+ *   choose to call only the subset of functions which provide
+ *   the desired functionality.
+ */
+struct phy_device * phy_connect(struct net_device *dev, const char *bus_id,
+		void (*handler)(struct net_device *), u32 flags,
+		phy_interface_t interface)
+{
+	struct phy_device *phydev;
+	struct device *d;
+	int rc;
+
+	/* Search the list of PHY devices on the mdio bus for the
+	 * PHY with the requested name */
+	d = bus_find_device_by_name(&mdio_bus_type, NULL, bus_id);
+	if (!d) {
+		pr_err("PHY %s not found\n", bus_id);
+		return ERR_PTR(-ENODEV);
+	}
+	phydev = to_phy_device(d);
+
+	rc = phy_connect_direct(dev, phydev, handler, flags, interface);
+	if (rc)
+		return ERR_PTR(rc);
+
+	return phydev;
+}
+EXPORT_SYMBOL(phy_connect);
+
+/**
+ * phy_disconnect - disable interrupts, stop state machine, and detach a PHY device
+ * @phydev: target phy_device struct
+ */
+void phy_disconnect(struct phy_device *phydev)
+{
+	if (phydev->irq > 0)
+		phy_stop_interrupts(phydev);
+
+	phy_stop_machine(phydev);
+	
+	phydev->adjust_link = NULL;
+
+	phy_detach(phydev);
+}
+EXPORT_SYMBOL(phy_disconnect);
+
+int phy_init_hw(struct phy_device *phydev)
+{
+	int ret;
+
+	if (!phydev->drv || !phydev->drv->config_init)
+		return 0;
+
+	ret = phy_scan_fixups(phydev);
+	if (ret < 0)
+		return ret;
+
+	return phydev->drv->config_init(phydev);
+}
+
+/**
+ * phy_attach_direct - attach a network device to a given PHY device pointer
+ * @dev: network device to attach
+ * @phydev: Pointer to phy_device to attach
+ * @flags: PHY device's dev_flags
+ * @interface: PHY device's interface
+ *
+ * Description: Called by drivers to attach to a particular PHY
+ *     device. The phy_device is found, and properly hooked up
+ *     to the phy_driver.  If no driver is attached, then the
+ *     genphy_driver is used.  The phy_device is given a ptr to
+ *     the attaching device, and given a callback for link status
+ *     change.  The phy_device is returned to the attaching driver.
+ */
+static int phy_attach_direct(struct net_device *dev, struct phy_device *phydev,
+			     u32 flags, phy_interface_t interface)
+{
+	struct device *d = &phydev->dev;
+	int err;
+
+	/* Assume that if there is no driver, that it doesn't
+	 * exist, and we should use the genphy driver. */
+	if (NULL == d->driver) {
+		d->driver = &genphy_driver.driver;
+
+		err = d->driver->probe(d);
+		if (err >= 0)
+			err = device_bind_driver(d);
+
+		if (err)
+			return err;
+	}
+
+	if (phydev->attached_dev) {
+		dev_err(&dev->dev, "PHY already attached\n");
+		return -EBUSY;
+	}
+
+	phydev->attached_dev = dev;
+	dev->phydev = phydev;
+
+	phydev->dev_flags = flags;
+
+	phydev->interface = interface;
+
+	phydev->state = PHY_READY;
+
+	/* Do initial configuration here, now that
+	 * we have certain key parameters
+	 * (dev_flags and interface) */
+	err = phy_init_hw(phydev);
+	if (err)
+		phy_detach(phydev);
+
+	return err;
+}
+
+/**
+ * phy_attach - attach a network device to a particular PHY device
+ * @dev: network device to attach
+ * @bus_id: Bus ID of PHY device to attach
+ * @flags: PHY device's dev_flags
+ * @interface: PHY device's interface
+ *
+ * Description: Same as phy_attach_direct() except that a PHY bus_id
+ *     string is passed instead of a pointer to a struct phy_device.
+ */
+struct phy_device *phy_attach(struct net_device *dev,
+		const char *bus_id, u32 flags, phy_interface_t interface)
+{
+	struct bus_type *bus = &mdio_bus_type;
+	struct phy_device *phydev;
+	struct device *d;
+	int rc;
+
+	/* Search the list of PHY devices on the mdio bus for the
+	 * PHY with the requested name */
+	d = bus_find_device_by_name(bus, NULL, bus_id);
+	if (!d) {
+		pr_err("PHY %s not found\n", bus_id);
+		return ERR_PTR(-ENODEV);
+	}
+	phydev = to_phy_device(d);
+
+	rc = phy_attach_direct(dev, phydev, flags, interface);
+	if (rc)
+		return ERR_PTR(rc);
+
+	return phydev;
+}
+EXPORT_SYMBOL(phy_attach);
+
+/**
+ * phy_detach - detach a PHY device from its network device
+ * @phydev: target phy_device struct
+ */
+void phy_detach(struct phy_device *phydev)
+{
+	phydev->attached_dev->phydev = NULL;
+	phydev->attached_dev = NULL;
+
+	/* If the device had no specific driver before (i.e. - it
+	 * was using the generic driver), we unbind the device
+	 * from the generic driver so that there's a chance a
+	 * real driver could be loaded */
+	if (phydev->dev.driver == &genphy_driver.driver)
+		device_release_driver(&phydev->dev);
+}
+EXPORT_SYMBOL(phy_detach);
+
+
+/* Generic PHY support and helper functions */
+
+/**
+ * genphy_config_advert - sanitize and advertise auto-negotiation parameters
+ * @phydev: target phy_device struct
+ *
+ * Description: Writes MII_ADVERTISE with the appropriate values,
+ *   after sanitizing the values to make sure we only advertise
+ *   what is supported.  Returns < 0 on error, 0 if the PHY's advertisement
+ *   hasn't changed, and > 0 if it has changed.
+ */
+static int genphy_config_advert(struct phy_device *phydev)
+{
+	u32 advertise;
+	int oldadv, adv;
+	int err, changed = 0;
+
+	/* Only allow advertising what
+	 * this PHY supports */
+	phydev->advertising &= phydev->supported;
+	advertise = phydev->advertising;
+
+	/* Setup standard advertisement */
+	oldadv = adv = phy_read(phydev, MII_ADVERTISE);
+
+	if (adv < 0)
+		return adv;
+
+	adv &= ~(ADVERTISE_ALL | ADVERTISE_100BASE4 | ADVERTISE_PAUSE_CAP |
+		 ADVERTISE_PAUSE_ASYM);
+	adv |= ethtool_adv_to_mii_adv_t(advertise);
+
+	if (adv != oldadv) {
+		err = phy_write(phydev, MII_ADVERTISE, adv);
+
+		if (err < 0)
+			return err;
+		changed = 1;
+	}
+
+	/* Configure gigabit if it's supported */
+	if (phydev->supported & (SUPPORTED_1000baseT_Half |
+				SUPPORTED_1000baseT_Full)) {
+		oldadv = adv = phy_read(phydev, MII_CTRL1000);
+
+		if (adv < 0)
+			return adv;
+
+		adv &= ~(ADVERTISE_1000FULL | ADVERTISE_1000HALF);
+		adv |= ethtool_adv_to_mii_ctrl1000_t(advertise);
+
+		if (adv != oldadv) {
+			err = phy_write(phydev, MII_CTRL1000, adv);
+
+			if (err < 0)
+				return err;
+			changed = 1;
+		}
+	}
+
+	return changed;
+}
+
+/**
+ * genphy_setup_forced - configures/forces speed/duplex from @phydev
+ * @phydev: target phy_device struct
+ *
+ * Description: Configures MII_BMCR to force speed/duplex
+ *   to the values in phydev. Assumes that the values are valid.
+ *   Please see phy_sanitize_settings().
+ */
+static int genphy_setup_forced(struct phy_device *phydev)
+{
+	int err;
+	int ctl = 0;
+
+	phydev->pause = phydev->asym_pause = 0;
+
+	if (SPEED_1000 == phydev->speed)
+		ctl |= BMCR_SPEED1000;
+	else if (SPEED_100 == phydev->speed)
+		ctl |= BMCR_SPEED100;
+
+	if (DUPLEX_FULL == phydev->duplex)
+		ctl |= BMCR_FULLDPLX;
+	
+	err = phy_write(phydev, MII_BMCR, ctl);
+
+	return err;
+}
+
+
+/**
+ * genphy_restart_aneg - Enable and Restart Autonegotiation
+ * @phydev: target phy_device struct
+ */
+int genphy_restart_aneg(struct phy_device *phydev)
+{
+	int ctl;
+
+	ctl = phy_read(phydev, MII_BMCR);
+
+	if (ctl < 0)
+		return ctl;
+
+	ctl |= (BMCR_ANENABLE | BMCR_ANRESTART);
+
+	/* Don't isolate the PHY if we're negotiating */
+	ctl &= ~(BMCR_ISOLATE);
+
+	ctl = phy_write(phydev, MII_BMCR, ctl);
+
+	return ctl;
+}
+EXPORT_SYMBOL(genphy_restart_aneg);
+
+
+/**
+ * genphy_config_aneg - restart auto-negotiation or write BMCR
+ * @phydev: target phy_device struct
+ *
+ * Description: If auto-negotiation is enabled, we configure the
+ *   advertising, and then restart auto-negotiation.  If it is not
+ *   enabled, then we write the BMCR.
+ */
+int genphy_config_aneg(struct phy_device *phydev)
+{
+	int result;
+
+	if (AUTONEG_ENABLE != phydev->autoneg)
+		return genphy_setup_forced(phydev);
+
+	result = genphy_config_advert(phydev);
+
+	if (result < 0) /* error */
+		return result;
+
+	if (result == 0) {
+		/* Advertisement hasn't changed, but maybe aneg was never on to
+		 * begin with?  Or maybe phy was isolated? */
+		int ctl = phy_read(phydev, MII_BMCR);
+
+		if (ctl < 0)
+			return ctl;
+
+		if (!(ctl & BMCR_ANENABLE) || (ctl & BMCR_ISOLATE))
+			result = 1; /* do restart aneg */
+	}
+
+	/* Only restart aneg if we are advertising something different
+	 * than we were before.	 */
+	if (result > 0)
+		result = genphy_restart_aneg(phydev);
+
+	return result;
+}
+EXPORT_SYMBOL(genphy_config_aneg);
+
+/**
+ * genphy_update_link - update link status in @phydev
+ * @phydev: target phy_device struct
+ *
+ * Description: Update the value in phydev->link to reflect the
+ *   current link value.  In order to do this, we need to read
+ *   the status register twice, keeping the second value.
+ */
+int genphy_update_link(struct phy_device *phydev)
+{
+	int status;
+
+	/* Do a fake read */
+	status = phy_read(phydev, MII_BMSR);
+
+	if (status < 0)
+		return status;
+
+	/* Read link and autonegotiation status */
+	status = phy_read(phydev, MII_BMSR);
+
+	if (status < 0)
+		return status;
+
+	if ((status & BMSR_LSTATUS) == 0)
+		phydev->link = 0;
+	else
+		phydev->link = 1;
+
+	return 0;
+}
+EXPORT_SYMBOL(genphy_update_link);
+
+/**
+ * genphy_read_status - check the link status and update current link state
+ * @phydev: target phy_device struct
+ *
+ * Description: Check the link, then figure out the current state
+ *   by comparing what we advertise with what the link partner
+ *   advertises.  Start by checking the gigabit possibilities,
+ *   then move on to 10/100.
+ */
+int genphy_read_status(struct phy_device *phydev)
+{
+	int adv;
+	int err;
+	int lpa;
+	int lpagb = 0;
+
+	/* Update the link, but return if there
+	 * was an error */
+	err = genphy_update_link(phydev);
+	if (err)
+		return err;
+
+	if (AUTONEG_ENABLE == phydev->autoneg) {
+		if (phydev->supported & (SUPPORTED_1000baseT_Half
+					| SUPPORTED_1000baseT_Full)) {
+			lpagb = phy_read(phydev, MII_STAT1000);
+
+			if (lpagb < 0)
+				return lpagb;
+
+			adv = phy_read(phydev, MII_CTRL1000);
+
+			if (adv < 0)
+				return adv;
+
+			lpagb &= adv << 2;
+		}
+
+		lpa = phy_read(phydev, MII_LPA);
+
+		if (lpa < 0)
+			return lpa;
+
+		adv = phy_read(phydev, MII_ADVERTISE);
+
+		if (adv < 0)
+			return adv;
+
+		lpa &= adv;
+
+		phydev->speed = SPEED_10;
+		phydev->duplex = DUPLEX_HALF;
+		phydev->pause = phydev->asym_pause = 0;
+
+		if (lpagb & (LPA_1000FULL | LPA_1000HALF)) {
+			phydev->speed = SPEED_1000;
+
+			if (lpagb & LPA_1000FULL)
+				phydev->duplex = DUPLEX_FULL;
+		} else if (lpa & (LPA_100FULL | LPA_100HALF)) {
+			phydev->speed = SPEED_100;
+			
+			if (lpa & LPA_100FULL)
+				phydev->duplex = DUPLEX_FULL;
+		} else
+			if (lpa & LPA_10FULL)
+				phydev->duplex = DUPLEX_FULL;
+
+		if (phydev->duplex == DUPLEX_FULL){
+			phydev->pause = lpa & LPA_PAUSE_CAP ? 1 : 0;
+			phydev->asym_pause = lpa & LPA_PAUSE_ASYM ? 1 : 0;
+		}
+	} else {
+		int bmcr = phy_read(phydev, MII_BMCR);
+		if (bmcr < 0)
+			return bmcr;
+
+		if (bmcr & BMCR_FULLDPLX)
+			phydev->duplex = DUPLEX_FULL;
+		else
+			phydev->duplex = DUPLEX_HALF;
+
+		if (bmcr & BMCR_SPEED1000)
+			phydev->speed = SPEED_1000;
+		else if (bmcr & BMCR_SPEED100)
+			phydev->speed = SPEED_100;
+		else
+			phydev->speed = SPEED_10;
+
+		phydev->pause = phydev->asym_pause = 0;
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL(genphy_read_status);
+
+static int genphy_config_init(struct phy_device *phydev)
+{
+	int val;
+	u32 features;
+
+	/* For now, I'll claim that the generic driver supports
+	 * all possible port types */
+	features = (SUPPORTED_TP | SUPPORTED_MII
+			| SUPPORTED_AUI | SUPPORTED_FIBRE |
+			SUPPORTED_BNC);
+
+	/* Do we support autonegotiation? */
+	val = phy_read(phydev, MII_BMSR);
+
+	if (val < 0)
+		return val;
+
+	if (val & BMSR_ANEGCAPABLE)
+		features |= SUPPORTED_Autoneg;
+
+	if (val & BMSR_100FULL)
+		features |= SUPPORTED_100baseT_Full;
+	if (val & BMSR_100HALF)
+		features |= SUPPORTED_100baseT_Half;
+	if (val & BMSR_10FULL)
+		features |= SUPPORTED_10baseT_Full;
+	if (val & BMSR_10HALF)
+		features |= SUPPORTED_10baseT_Half;
+
+	if (val & BMSR_ESTATEN) {
+		val = phy_read(phydev, MII_ESTATUS);
+
+		if (val < 0)
+			return val;
+
+		if (val & ESTATUS_1000_TFULL)
+			features |= SUPPORTED_1000baseT_Full;
+		if (val & ESTATUS_1000_THALF)
+			features |= SUPPORTED_1000baseT_Half;
+	}
+
+	phydev->supported = features;
+	phydev->advertising = features;
+
+	return 0;
+}
+int genphy_suspend(struct phy_device *phydev)
+{
+	int value;
+
+	mutex_lock(&phydev->lock);
+
+	value = phy_read(phydev, MII_BMCR);
+	phy_write(phydev, MII_BMCR, (value | BMCR_PDOWN));
+
+	mutex_unlock(&phydev->lock);
+
+	return 0;
+}
+EXPORT_SYMBOL(genphy_suspend);
+
+int genphy_resume(struct phy_device *phydev)
+{
+	int value;
+
+	mutex_lock(&phydev->lock);
+
+	value = phy_read(phydev, MII_BMCR);
+	phy_write(phydev, MII_BMCR, (value & ~BMCR_PDOWN));
+
+	mutex_unlock(&phydev->lock);
+
+	return 0;
+}
+EXPORT_SYMBOL(genphy_resume);
+
+/**
+ * phy_probe - probe and init a PHY device
+ * @dev: device to probe and init
+ *
+ * Description: Take care of setting up the phy_device structure,
+ *   set the state to READY (the driver's init function should
+ *   set it to STARTING if needed).
+ */
+static int phy_probe(struct device *dev)
+{
+	struct phy_device *phydev;
+	struct phy_driver *phydrv;
+	struct device_driver *drv;
+	int err = 0;
+
+	phydev = to_phy_device(dev);
+
+	drv = phydev->dev.driver;
+	phydrv = to_phy_driver(drv);
+	phydev->drv = phydrv;
+
+	/* Disable the interrupt if the PHY doesn't support it */
+	if (!(phydrv->flags & PHY_HAS_INTERRUPT))
+		phydev->irq = PHY_POLL;
+
+	mutex_lock(&phydev->lock);
+
+	/* Start out supporting everything. Eventually,
+	 * a controller will attach, and may modify one
+	 * or both of these values */
+	phydev->supported = phydrv->features;
+	phydev->advertising = phydrv->features;
+
+	/* Set the state to READY by default */
+	phydev->state = PHY_READY;
+
+	if (phydev->drv->probe)
+		err = phydev->drv->probe(phydev);
+
+	mutex_unlock(&phydev->lock);
+
+	return err;
+
+}
+
+static int phy_remove(struct device *dev)
+{
+	struct phy_device *phydev;
+
+	phydev = to_phy_device(dev);
+
+	mutex_lock(&phydev->lock);
+	phydev->state = PHY_DOWN;
+	mutex_unlock(&phydev->lock);
+
+	if (phydev->drv->remove)
+		phydev->drv->remove(phydev);
+	phydev->drv = NULL;
+
+	return 0;
+}
+
+/**
+ * phy_driver_register - register a phy_driver with the PHY layer
+ * @new_driver: new phy_driver to register
+ */
+int phy_driver_register(struct phy_driver *new_driver)
+{
+	int retval;
+
+	new_driver->driver.name = new_driver->name;
+	new_driver->driver.bus = &mdio_bus_type;
+	new_driver->driver.probe = phy_probe;
+	new_driver->driver.remove = phy_remove;
+
+	retval = driver_register(&new_driver->driver);
+
+	if (retval) {
+		printk(KERN_ERR "%s: Error %d in registering driver\n",
+				new_driver->name, retval);
+
+		return retval;
+	}
+
+	pr_debug("%s: Registered new driver\n", new_driver->name);
+
+	return 0;
+}
+EXPORT_SYMBOL(phy_driver_register);
+
+void phy_driver_unregister(struct phy_driver *drv)
+{
+	driver_unregister(&drv->driver);
+}
+EXPORT_SYMBOL(phy_driver_unregister);
+
+static struct phy_driver genphy_driver = {
+	.phy_id		= 0xffffffff,
+	.phy_id_mask	= 0xffffffff,
+	.name		= "Generic PHY",
+	.config_init	= genphy_config_init,
+	.features	= 0,
+	.config_aneg	= genphy_config_aneg,
+	.read_status	= genphy_read_status,
+	.suspend	= genphy_suspend,
+	.resume		= genphy_resume,
+	.driver		= {.owner= THIS_MODULE, },
+};
+
+static int __init phy_init(void)
+{
+	int rc;
+
+	rc = mdio_bus_init();
+	if (rc)
+		return rc;
+
+	rc = phy_driver_register(&genphy_driver);
+	if (rc)
+		mdio_bus_exit();
+
+	return rc;
+}
+
+static void __exit phy_exit(void)
+{
+	phy_driver_unregister(&genphy_driver);
+	mdio_bus_exit();
+}
+
+subsys_initcall(phy_init);
+module_exit(phy_exit);
diff --git a/ap/os/linux/linux-3.4.x/drivers/net/phy/qsemi.c b/ap/os/linux/linux-3.4.x/drivers/net/phy/qsemi.c
new file mode 100644
index 0000000..fe0d0a1
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/net/phy/qsemi.c
@@ -0,0 +1,146 @@
+/*
+ * drivers/net/phy/qsemi.c
+ *
+ * Driver for Quality Semiconductor PHYs
+ *
+ * Author: Andy Fleming
+ *
+ * Copyright (c) 2004 Freescale Semiconductor, Inc.
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ *
+ */
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/errno.h>
+#include <linux/unistd.h>
+#include <linux/interrupt.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+#include <linux/spinlock.h>
+#include <linux/mm.h>
+#include <linux/module.h>
+#include <linux/mii.h>
+#include <linux/ethtool.h>
+#include <linux/phy.h>
+
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/uaccess.h>
+
+/* ------------------------------------------------------------------------- */
+/* The Quality Semiconductor QS6612 is used on the RPX CLLF                  */
+
+/* register definitions */
+
+#define MII_QS6612_MCR		17  /* Mode Control Register      */
+#define MII_QS6612_FTR		27  /* Factory Test Register      */
+#define MII_QS6612_MCO		28  /* Misc. Control Register     */
+#define MII_QS6612_ISR		29  /* Interrupt Source Register  */
+#define MII_QS6612_IMR		30  /* Interrupt Mask Register    */
+#define MII_QS6612_IMR_INIT	0x003a
+#define MII_QS6612_PCR		31  /* 100BaseTx PHY Control Reg. */
+
+#define QS6612_PCR_AN_COMPLETE	0x1000
+#define QS6612_PCR_RLBEN	0x0200
+#define QS6612_PCR_DCREN	0x0100
+#define QS6612_PCR_4B5BEN	0x0040
+#define QS6612_PCR_TX_ISOLATE	0x0020
+#define QS6612_PCR_MLT3_DIS	0x0002
+#define QS6612_PCR_SCRM_DESCRM	0x0001
+
+MODULE_DESCRIPTION("Quality Semiconductor PHY driver");
+MODULE_AUTHOR("Andy Fleming");
+MODULE_LICENSE("GPL");
+
+/* Returns 0, unless there's a write error */
+static int qs6612_config_init(struct phy_device *phydev)
+{
+	/* The PHY powers up isolated on the RPX,
+	 * so send a command to allow operation.
+	 * XXX - My docs indicate this should be 0x0940
+	 * ...or something.  The current value sets three
+	 * reserved bits, bit 11, which specifies it should be
+	 * set to one, bit 10, which specifies it should be set
+	 * to 0, and bit 7, which doesn't specify.  However, my
+	 * docs are preliminary, and I will leave it like this
+	 * until someone more knowledgable corrects me or it.
+	 * -- Andy Fleming
+	 */
+	return phy_write(phydev, MII_QS6612_PCR, 0x0dc0);
+}
+
+static int qs6612_ack_interrupt(struct phy_device *phydev)
+{
+	int err;
+
+	err = phy_read(phydev, MII_QS6612_ISR);
+
+	if (err < 0)
+		return err;
+
+	err = phy_read(phydev, MII_BMSR);
+
+	if (err < 0)
+		return err;
+
+	err = phy_read(phydev, MII_EXPANSION);
+
+	if (err < 0)
+		return err;
+
+	return 0;
+}
+
+static int qs6612_config_intr(struct phy_device *phydev)
+{
+	int err;
+	if (phydev->interrupts == PHY_INTERRUPT_ENABLED)
+		err = phy_write(phydev, MII_QS6612_IMR,
+				MII_QS6612_IMR_INIT);
+	else
+		err = phy_write(phydev, MII_QS6612_IMR, 0);
+
+	return err;
+
+}
+
+static struct phy_driver qs6612_driver = {
+	.phy_id		= 0x00181440,
+	.name		= "QS6612",
+	.phy_id_mask	= 0xfffffff0,
+	.features	= PHY_BASIC_FEATURES,
+	.flags		= PHY_HAS_INTERRUPT,
+	.config_init	= qs6612_config_init,
+	.config_aneg	= genphy_config_aneg,
+	.read_status	= genphy_read_status,
+	.ack_interrupt	= qs6612_ack_interrupt,
+	.config_intr	= qs6612_config_intr,
+	.driver 	= { .owner = THIS_MODULE,},
+};
+
+static int __init qs6612_init(void)
+{
+	return phy_driver_register(&qs6612_driver);
+}
+
+static void __exit qs6612_exit(void)
+{
+	phy_driver_unregister(&qs6612_driver);
+}
+
+module_init(qs6612_init);
+module_exit(qs6612_exit);
+
+static struct mdio_device_id __maybe_unused qs6612_tbl[] = {
+	{ 0x00181440, 0xfffffff0 },
+	{ }
+};
+
+MODULE_DEVICE_TABLE(mdio, qs6612_tbl);
diff --git a/ap/os/linux/linux-3.4.x/drivers/net/phy/realtek.c b/ap/os/linux/linux-3.4.x/drivers/net/phy/realtek.c
new file mode 100644
index 0000000..f414ffb
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/net/phy/realtek.c
@@ -0,0 +1,88 @@
+/*
+ * drivers/net/phy/realtek.c
+ *
+ * Driver for Realtek PHYs
+ *
+ * Author: Johnson Leung <r58129@freescale.com>
+ *
+ * Copyright (c) 2004 Freescale Semiconductor, Inc.
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ *
+ */
+#include <linux/phy.h>
+#include <linux/module.h>
+
+#define RTL821x_PHYSR		0x11
+#define RTL821x_PHYSR_DUPLEX	0x2000
+#define RTL821x_PHYSR_SPEED	0xc000
+#define RTL821x_INER		0x12
+#define RTL821x_INER_INIT	0x6400
+#define RTL821x_INSR		0x13
+
+MODULE_DESCRIPTION("Realtek PHY driver");
+MODULE_AUTHOR("Johnson Leung");
+MODULE_LICENSE("GPL");
+
+static int rtl821x_ack_interrupt(struct phy_device *phydev)
+{
+	int err;
+
+	err = phy_read(phydev, RTL821x_INSR);
+
+	return (err < 0) ? err : 0;
+}
+
+static int rtl821x_config_intr(struct phy_device *phydev)
+{
+	int err;
+
+	if (phydev->interrupts == PHY_INTERRUPT_ENABLED)
+		err = phy_write(phydev, RTL821x_INER,
+				RTL821x_INER_INIT);
+	else
+		err = phy_write(phydev, RTL821x_INER, 0);
+
+	return err;
+}
+
+/* RTL8211B */
+static struct phy_driver rtl821x_driver = {
+	.phy_id		= 0x001cc912,
+	.name		= "RTL821x Gigabit Ethernet",
+	.phy_id_mask	= 0x001fffff,
+	.features	= PHY_GBIT_FEATURES,
+	.flags		= PHY_HAS_INTERRUPT,
+	.config_aneg	= &genphy_config_aneg,
+	.read_status	= &genphy_read_status,
+	.ack_interrupt	= &rtl821x_ack_interrupt,
+	.config_intr	= &rtl821x_config_intr,
+	.driver		= { .owner = THIS_MODULE,},
+};
+
+static int __init realtek_init(void)
+{
+	int ret;
+
+	ret = phy_driver_register(&rtl821x_driver);
+
+	return ret;
+}
+
+static void __exit realtek_exit(void)
+{
+	phy_driver_unregister(&rtl821x_driver);
+}
+
+module_init(realtek_init);
+module_exit(realtek_exit);
+
+static struct mdio_device_id __maybe_unused realtek_tbl[] = {
+	{ 0x001cc912, 0x001fffff },
+	{ }
+};
+
+MODULE_DEVICE_TABLE(mdio, realtek_tbl);
diff --git a/ap/os/linux/linux-3.4.x/drivers/net/phy/realtek/Kconfig b/ap/os/linux/linux-3.4.x/drivers/net/phy/realtek/Kconfig
new file mode 100755
index 0000000..39a1702
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/net/phy/realtek/Kconfig
@@ -0,0 +1,8 @@
+#
+# PHY/SWITCH device configuration
+#
+config RTK8306E_PHY
+	tristate "Drivers for Realtek PHYs"
+	---help---
+	  Supports the Realtek 821x and 8306e PHY.
+
diff --git a/ap/os/linux/linux-3.4.x/drivers/net/phy/realtek/Makefile b/ap/os/linux/linux-3.4.x/drivers/net/phy/realtek/Makefile
new file mode 100755
index 0000000..bbfbb5e
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/net/phy/realtek/Makefile
@@ -0,0 +1,3 @@
+obj-$(CONFIG_RTK8306E_PHY)	+= rtl8306e/rtk_api.o \
+					rtl8306e/rtl8306e_asicdrv.o
+obj-y += realtek.o
diff --git a/ap/os/linux/linux-3.4.x/drivers/net/phy/realtek/realtek.c b/ap/os/linux/linux-3.4.x/drivers/net/phy/realtek/realtek.c
new file mode 100755
index 0000000..6f201cc
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/net/phy/realtek/realtek.c
@@ -0,0 +1,218 @@
+/*
+ * drivers/net/phy/realtek.c
+ *
+ * Driver for Realtek PHYs
+ *
+ * Author: Johnson Leung <r58129@freescale.com>
+ *
+ * Copyright (c) 2004 Freescale Semiconductor, Inc.
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ *
+ */
+#include <linux/phy.h>
+#include <linux/module.h>
+#include <linux/gmac/gmac.h>
+#include "./rtl8306e/rtl8306e_types.h"
+#include "./rtl8306e/rtl8306e_asicdrv.h"
+#include "./rtl8306e/rtk_api.h"
+
+#define RTL821x_PHYSR		0x11
+#define RTL821x_PHYSR_DUPLEX	0x2000
+#define RTL821x_PHYSR_SPEED	0xc000
+#define RTL821x_INER		0x12
+#define RTL821x_INER_INIT	0x6400
+#define RTL821x_INSR		0x13
+
+MODULE_DESCRIPTION("Realtek PHY driver");
+MODULE_AUTHOR("Johnson Leung");
+MODULE_LICENSE("GPL");
+
+#ifdef CONFIG_RTK8306E_PHY
+struct phy_device *realtek_phydev;
+
+extern int rtl8306e_config_init(void);
+
+int smiRead(int phyad, int regad,int * data)
+{
+	*data = mdiobus_read(realtek_phydev->bus, phyad, regad);	
+	return 1;
+}
+
+int smiWrite(int phyad, int regad, int data)
+{
+	mdiobus_write(realtek_phydev->bus, phyad, regad, data);
+	return 1;
+}
+#endif
+
+static int rtl821x_ack_interrupt(struct phy_device *phydev)
+{
+	int err;
+
+	err = phy_read(phydev, RTL821x_INSR);
+
+	return (err < 0) ? err : 0;
+}
+
+static int rtl821x_config_intr(struct phy_device *phydev)
+{
+	int err;
+
+	if (phydev->interrupts == PHY_INTERRUPT_ENABLED)
+		err = phy_write(phydev, RTL821x_INER,
+				RTL821x_INER_INIT);
+	else
+		err = phy_write(phydev, RTL821x_INER, 0);
+
+	return err;
+}
+
+static int rtl8306x_config_init(struct phy_device *phydev)
+{
+	int err = 0;
+
+	printk("@@@@@@@@@@@@rtl8306x_config_init begin@@@@@@@@@@@@@\n");
+
+#ifdef CONFIG_RTK8306E_PHY
+	realtek_phydev = phydev;
+	err = rtl8306e_config_init();
+#endif
+
+	printk("@@@@@@@@@@@@rtl8306x_config_init end@@@@@@@@@@@@@\n");
+
+	return err;
+}
+
+typedef enum
+{
+	eLINK_OFF = 0,
+	eLINK_ON,
+	eLINK_END
+} E_LINK_STATE;
+static E_LINK_STATE rtk8306x_port_state[5]= {0};
+extern void gmac_event_notify(GMAC_NOTIFY_EVENT notify_type, void* puf);
+extern int32 rtl8306e_port_phyLinkStatus_get(uint32 phy, uint32 *plinkUp); 
+static int rtl8306x_private_proc(struct phy_device *phydev)
+{
+	int err = 0;
+	int i = 0;
+	int islink = 0;
+	int org_lan_status = 0;
+	int org_wan_status = 0;
+	int new_lan_status = 0;
+	int new_wan_status = 0;
+
+	for(i=0; i<4; i++) {
+		if(rtk8306x_port_state[i] == 1)
+			org_lan_status = 1; 
+
+		rtl8306e_port_phyLinkStatus_get(i,&islink);
+		rtk8306x_port_state[i] = islink;
+		if(islink == 1)
+			new_lan_status = 1;
+	}
+
+	org_wan_status = rtk8306x_port_state[4];
+	rtl8306e_port_phyLinkStatus_get(i,&islink);
+	rtk8306x_port_state[4] = islink;
+	if(islink == 1)
+		new_wan_status = 1;
+
+	if((org_lan_status == 0)&&(new_lan_status == 1))
+		gmac_event_notify(GMAC_ETH_SW_LAN_PLUGIN, NULL);
+
+	if((org_lan_status == 1)&&(new_lan_status == 0))
+		gmac_event_notify(GMAC_ETH_SW_LAN_PLUGOUT, NULL);
+
+	if((org_wan_status == 0)&&(new_wan_status == 1))
+		gmac_event_notify(GMAC_ETH_SW_WAN_PLUGIN, NULL);
+
+	if((org_wan_status == 1)&&(new_wan_status == 0))
+		gmac_event_notify(GMAC_ETH_SW_WAN_PLUGOUT, NULL);
+
+#if 0
+	for(i=0; i<5; i++) {
+		rtl8306e_port_phyLinkStatus_get(i,&islink);
+		if(rtk8306x_port_state[i] != islink) {
+			rtk8306x_port_state[i] = islink;
+			if(i == 4) {
+				if(islink == 1)
+					gmac_event_notify(GMAC_ETH_SW_WAN_PLUGIN, NULL);
+				else
+					gmac_event_notify(GMAC_ETH_SW_WAN_PLUGOUT, NULL);
+			} else {
+				if(islink == 1)
+					gmac_event_notify(GMAC_ETH_SW_LAN_PLUGIN, NULL);
+				else
+					gmac_event_notify(GMAC_ETH_SW_LAN_PLUGOUT, NULL);
+			}
+		}
+	}
+#endif
+	return err;
+}
+
+
+/* RTL8211B */
+static struct phy_driver rtl821x_driver = {
+	.phy_id		= 0x001cc912,
+	.name		= "RTL821x Gigabit Ethernet",
+	.phy_id_mask	= 0x001fffff,
+	.features	= PHY_GBIT_FEATURES,
+	.flags		= PHY_HAS_INTERRUPT,
+	.config_aneg	= &genphy_config_aneg,
+	.read_status	= &genphy_read_status,
+	.ack_interrupt	= &rtl821x_ack_interrupt,
+	.config_intr	= &rtl821x_config_intr,
+	.driver		= { .owner = THIS_MODULE,},
+};
+
+/* RTL8306E */
+static struct phy_driver rtl8306x_driver = {
+	.phy_id		= 0x001cc852,
+	.name		= "RTL8306x Ethernet",
+	.phy_id_mask	= 0x0fffffe0,
+	.features	= PHY_BASIC_FEATURES,
+	.config_aneg	= &genphy_config_aneg,
+	.read_status	= &genphy_read_status,
+	.config_init	= &rtl8306x_config_init,
+	.private_proc	= &rtl8306x_private_proc,
+	.suspend	= genphy_suspend,
+	.resume		= genphy_resume,
+	.driver		= { .owner = THIS_MODULE,},
+};
+
+
+static int __init realtek_init(void)
+{
+	int ret;
+
+	ret = phy_driver_register(&rtl821x_driver);
+	if (ret < 0)
+		return -ENODEV;
+
+	ret = phy_driver_register(&rtl8306x_driver);
+
+	return ret;
+}
+
+static void __exit realtek_exit(void)
+{
+	phy_driver_unregister(&rtl821x_driver);
+	phy_driver_unregister(&rtl8306x_driver);
+}
+
+module_init(realtek_init);
+module_exit(realtek_exit);
+
+static struct mdio_device_id __maybe_unused realtek_tbl[] = {
+	{ 0x001cc912, 0x001fffff },
+	{ 0x001cc852, 0x0fffffe0 },
+	{ }
+};
+
+MODULE_DEVICE_TABLE(mdio, realtek_tbl);
diff --git a/ap/os/linux/linux-3.4.x/drivers/net/phy/realtek/rtl8306e/rtk_api.c b/ap/os/linux/linux-3.4.x/drivers/net/phy/realtek/rtl8306e/rtk_api.c
new file mode 100755
index 0000000..ae2c5ac
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/net/phy/realtek/rtl8306e/rtk_api.c
@@ -0,0 +1,5344 @@
+/*
+* Copyright (C) 2010 Realtek Semiconductor Corp.
+* All Rights Reserved.
+*
+* This program is the proprietary software of Realtek Semiconductor
+* Corporation and/or its licensors, and only be used, duplicated,
+* modified or distributed under the authorized license from Realtek.
+*
+* ANY USE OF THE SOFTWARE OTEHR THAN AS AUTHORIZED UNDER 
+* THIS LICENSE OR COPYRIGHT LAW IS PROHIBITED.
+* 
+* $Revision: 26889 $ 
+* $Date: 2012-02-28 21:08:47 +0800 (星期二, 2012-02-28) $
+*
+* Purpose : realtek common API
+*
+* Feature :  This file consists of following modules:
+*                
+*
+*/
+
+#include "rtl8306e_types.h"
+#include "rtl8306e_asicdrv.h"
+#include "rtk_api.h"
+#include "rtk_api_ext.h"
+
+
+/* Function Name:
+ *      rtk_switch_init
+ * Description:
+ *      Set chip to default configuration enviroment
+ * Input:
+ *      none
+ * Output:
+ *      none
+ * Return:
+ *      RT_ERR_OK                     -  Success
+ *      RT_ERR_FAILED               -  Failure
+ * Note:
+ *     The API can set chip registers to default configuration for
+ *     different release chip model.
+ */
+rtk_api_ret_t rtk_switch_init(void)
+{
+    rtl8306e_asic_init();
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_switch_maxPktLen_set
+ * Description:
+ *      Set the max packet length of the specific unit
+ * Input:
+ *      len       -       max packet length
+ * Output:
+ *      none
+ * Return:
+ *      RT_ERR_OK                    -  Success
+ *      RT_ERR_FAILED               -  Failure
+ *      RT_ERR_INPUT                -  Invalid input parameter
+ * Note:
+ *      The API can set max packet length of the specific unit to
+ *          - MAXPKTLEN_1522B,
+ *          - MAXPKTLEN_1536B,
+ *          - MAXPKTLEN_1552B,
+ *          - MAXPKTLEN_2000B, 
+ */
+rtk_api_ret_t rtk_switch_maxPktLen_set(rtk_switch_maxPktLen_t len)
+{
+    rtk_api_ret_t retVal;
+    uint32          maxlen;
+
+    if (len > MAXPKTLEN_2000B)
+        return RT_ERR_INPUT;
+
+    switch(len)
+    {
+        case MAXPKTLEN_1522B:
+            maxlen = RTL8306_MAX_PKT_LEN_1518;
+            break;            
+        case MAXPKTLEN_1536B:
+            maxlen = RTL8306_MAX_PKT_LEN_1536;
+            break;
+        case MAXPKTLEN_1552B:
+            maxlen = RTL8306_MAX_PKT_LEN_1552;
+            break;
+        case MAXPKTLEN_2000B:
+            maxlen = RTL8306_MAX_PKT_LEN_2000;
+            break;
+        default:
+            return FAILED;
+    }
+
+    if((retVal = rtl8306e_switch_maxPktLen_set(maxlen)) != RT_ERR_OK)
+        return retVal;
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_switch_maxPktLen_get
+ * Description:
+ *      Get the max packet length of the specific unit
+ * Input:
+ *      none
+ * Output:
+ *      pLen                             -    the pointer of max packet length
+ * Return: 
+ *      RT_ERR_OK                    -  Success
+ *      RT_ERR_FAILED               -  Failure
+ *      RT_ERR_NULL_POINTER     -  Input parameter is null pointer 
+ * Note:
+ *      The API can set max packet length of the specific unit to
+ *          - MAXPKTLEN_1522B,
+ *          - MAXPKTLEN_1536B,
+ *          - MAXPKTLEN_1552B,
+ *          - MAXPKTLEN_2000B, 
+ */
+rtk_api_ret_t rtk_switch_maxPktLen_get(rtk_switch_maxPktLen_t *pLen)
+{
+    rtk_api_ret_t retVal;
+    uint32          maxlen;
+
+    if (NULL == pLen)
+        return RT_ERR_NULL_POINTER;
+    
+    if((retVal = rtl8306e_switch_maxPktLen_get(&maxlen)) != RT_ERR_OK)
+        return retVal;
+
+    switch(maxlen)
+    {
+        case RTL8306_MAX_PKT_LEN_1518:
+            *pLen = MAXPKTLEN_1522B;
+            break;
+
+        case RTL8306_MAX_PKT_LEN_1536:
+            *pLen = MAXPKTLEN_1536B;
+            break;
+            
+        case RTL8306_MAX_PKT_LEN_1552:
+            *pLen = MAXPKTLEN_1552B;
+            break;
+            
+        case RTL8306_MAX_PKT_LEN_2000:
+            *pLen = MAXPKTLEN_2000B;
+            break;
+
+        default:
+            return FAILED;
+    }
+    
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_port_phyReg_set
+ * Description:
+ *      Set PHY register data of the specific port
+ * Input:
+ *      phy                - phy number, 0 ~ 6 
+ *      reg                 - Register id
+ *      regData           - Register data
+ * Output:
+ *      none
+ * Return:
+ *      RT_ERR_OK         -  Success
+ *      RT_ERR_FAILED   -   Failure
+ * Note:
+ *      This API can set PHY register data of the specific port.
+ *      RTL8306E switch has 5 FE port, and port 4 could be set as
+ *      phy mode or mac mode, port 5 is mac mode which connect
+ *      with mii interface. so parameter phy 0 ~4 means port 0 ~4
+ *      phy register, 5 means port 4 mac mode, 6 means port 5.
+ *      
+ */
+ 
+rtk_api_ret_t rtk_port_phyReg_set(rtk_port_t phy, rtk_port_phy_reg_t reg, rtk_port_phy_data_t regData)
+{
+    rtk_api_ret_t retVal;
+    
+    if(phy > (RTL8306_PHY_NUMBER - 1))
+        return RT_ERR_PORT_ID;
+
+    retVal = rtl8306e_reg_set(phy, reg, 0, regData);
+    if(retVal != SUCCESS)
+        return RT_ERR_FAILED;
+    return RT_ERR_OK;
+}
+
+
+/* Function Name:
+ *      rtk_port_phyReg_get
+ * Description:
+ *      Get PHY register data of the specific port
+ * Input:
+ *      phy                  - phy number, 0 ~ 6
+ *      reg                   - Register id
+ * Output:
+ *      pData               - the pointer of Register data
+ * Return:
+ *      RT_ERR_OK        -  Success
+ *      RT_ERR_FAILED   -  Failure
+ * Note:
+ *      This API can set PHY register data of the specific port.
+ *      RTL8306E switch has 5 FE port, and port 4 could be set as
+ *      phy mode or mac mode, port 5 is mac mode which connect
+ *      with mii interface. so parameter phy 0 ~4 means port 0 ~4
+ *      phy register, 5 means port 4 mac mode, 6 means port 5.
+ *      
+ */
+ 
+rtk_api_ret_t rtk_port_phyReg_get(rtk_port_t phy, rtk_port_phy_reg_t reg, rtk_port_phy_data_t *pData) 
+{
+    rtk_api_ret_t retVal;
+
+    if(phy > (RTL8306_PHY_NUMBER - 1))
+        return RT_ERR_PORT_ID;
+
+    retVal = rtl8306e_reg_get(phy, reg, 0, pData);
+    if(retVal != SUCCESS)
+        return RT_ERR_FAILED;
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_port_phyAutoNegoAbility_set
+ * Description:
+ *      Set ethernet PHY auto-negotiation desired ability
+ * Input:
+ *      port       -  Port id
+ *      pAbility   -  Ability structure
+ * Output:
+ *      none
+ * Return:
+ *      RT_ERR_OK                        
+ *      RT_ERR_FAILED                  
+ *      RT_ERR_SMI       
+ *      RT_ERR_PORT_ID
+ *      RT_ERR_PHY_REG_ID
+ *      RT_ERR_NULL_POINTER
+ *      RT_ERR_BUSYWAIT_TIMEOUT
+ *     
+ * Note:
+ *      (1) RTL8306E switch only has 5 phy, so the input port id should be 0~4.
+ *      (2) In auto-negotiation mode, phy autoNegotiation ability must be enabled
+ */ 
+rtk_api_ret_t rtk_port_phyAutoNegoAbility_set(rtk_port_t port, rtk_port_phy_ability_t *pAbility)
+{
+    rtk_api_ret_t retVal;     
+    uint32 phyData;    
+    uint32 phyEnMsk0;
+    uint32 phyEnMsk4;
+
+    if(port > 4)
+        return RT_ERR_PORT_ID;         
+
+    if(NULL == pAbility)
+        return RT_ERR_NULL_POINTER;
+
+    if(pAbility->Half_10 >= RTK_ENABLE_END  || pAbility->Full_10 >= RTK_ENABLE_END ||
+       pAbility->Half_100 >= RTK_ENABLE_END || pAbility->Full_100 >= RTK_ENABLE_END ||
+       pAbility->AutoNegotiation >= RTK_ENABLE_END ||pAbility->AsyFC >= RTK_ENABLE_END ||
+       pAbility->FC >= RTK_ENABLE_END)
+        return RT_ERR_INPUT; 
+
+    /*for PHY auto mode setup*/
+    pAbility->AutoNegotiation = 1; 
+
+    phyEnMsk0 = 0;
+    phyEnMsk4 = 0;
+    
+    if(1 == pAbility->Half_10)
+    {
+        /*10BASE-TX half duplex capable in reg 4.5*/
+        phyEnMsk4 = phyEnMsk4 | (1<<5);
+    }
+
+    if(1 == pAbility->Full_10)
+    {
+        /*10BASE-TX full duplex capable in reg 4.6*/
+        phyEnMsk4 = phyEnMsk4 | (1<<6);        
+    }
+
+    if(1 == pAbility->Half_100)
+    {
+        /*100BASE-TX half duplex capable in reg 4.7*/
+        phyEnMsk4 = phyEnMsk4 | (1<<7);
+    }
+
+    if(1 == pAbility->Full_100)
+    {
+        /*100BASE-TX full duplex capable in reg 4.8*/
+        phyEnMsk4 = phyEnMsk4 | (1<<8);
+    }
+    
+    if(1 == pAbility->AutoNegotiation)
+    {
+        /*Auto-Negotiation setting in reg 0.12*/
+        phyEnMsk0 = phyEnMsk0 | (1<<12);
+    }
+
+    if(1 == pAbility->AsyFC)
+    {
+        /*Asymetric flow control in reg 4.11*/
+        phyEnMsk4 = phyEnMsk4 | (1<<11);
+    }
+    
+    if(1 == pAbility->FC)
+    {
+        /*Flow control in reg 4.10*/
+        phyEnMsk4 = phyEnMsk4 | (1<<10);
+    }
+
+    /*Auto-Negotiation control register setting*/
+    if((retVal = rtk_port_phyReg_get(port, (rtk_port_phy_reg_t)PHY_AN_ADVERTISEMENT_REG, &phyData)) != RT_ERR_OK)
+        return retVal;
+
+    phyData = (phyData & (~0x0DE0)) | phyEnMsk4;
+    if((retVal = rtk_port_phyReg_set(port, (rtk_port_phy_reg_t)PHY_AN_ADVERTISEMENT_REG, phyData)) != RT_ERR_OK)
+        return retVal;
+
+    /*Control register setting and restart auto*/
+    if((retVal = rtk_port_phyReg_get(port, (rtk_port_phy_reg_t)PHY_CONTROL_REG, &phyData)) != RT_ERR_OK)
+        return retVal;
+    phyData = (phyData & (~0x3100)) | phyEnMsk0;
+    
+    /*If have auto-negotiation capable, then restart auto negotiation*/
+    if(1 == pAbility->AutoNegotiation)
+    {
+        phyData = phyData | (1 << 9);
+    }
+
+    if((retVal = rtk_port_phyReg_set(port, (rtk_port_phy_reg_t)PHY_CONTROL_REG, phyData)) != RT_ERR_OK)
+        return retVal;    
+
+    return RT_ERR_OK;
+    
+}
+
+/* Function Name:
+ *      rtk_port_phyAutoNegoAbility_get
+ * Description:
+ *      Get ethernet PHY auto-negotiation desired ability
+ * Input:
+ *      port       -  Port id
+ * Output:
+ *      pAbility   -  Ability structure
+ * Return:
+ *      RT_ERR_OK                        
+ *      RT_ERR_FAILED                  
+ *      RT_ERR_SMI       
+ *      RT_ERR_PORT_ID
+ *      RT_ERR_PHY_REG_ID
+ *      RT_ERR_NULL_POINTER
+ *      RT_ERR_PHY_AUTO_NEGO_MODE
+ *      RT_ERR_BUSYWAIT_TIMEOUT
+ *     
+ * Note:
+ *      (1) RTL8306E switch only has 5 phy, so the input port id should be 0~4.
+ *      (2) In auto-negotiation mode, phy autoNegotiation ability must be enabled
+ */   
+rtk_api_ret_t rtk_port_phyAutoNegoAbility_get(rtk_port_t port, rtk_port_phy_ability_t *pAbility)
+{
+    uint32 phyData0;
+    uint32 phyData4;
+    rtk_api_ret_t retVal;  
+    
+    if(port > 4)
+        return RT_ERR_PORT_ID; 
+
+    if(NULL == pAbility)
+        return RT_ERR_NULL_POINTER;
+
+    /*Control register setting and restart auto*/
+    if((retVal = rtk_port_phyReg_get(port, (rtk_port_phy_reg_t)PHY_CONTROL_REG, &phyData0)) != RT_ERR_OK)
+        return retVal;
+
+    /*Auto-Negotiation control register setting*/
+    if((retVal = rtk_port_phyReg_get(port, (rtk_port_phy_reg_t)PHY_AN_ADVERTISEMENT_REG, &phyData4)) != RT_ERR_OK)
+        return retVal;
+
+    if(!(phyData0 & (1<<12)))
+        return RT_ERR_PHY_AUTO_NEGO_MODE;
+
+    if(phyData4 & (1<<11))
+        pAbility->AsyFC = 1;
+    else
+        pAbility->AsyFC = 0;
+
+    if(phyData4 & (1<<10))
+        pAbility->FC = 1;
+    else
+        pAbility->FC = 0;
+    
+    
+    if(phyData4 & (1<<8))
+        pAbility->Full_100= 1;
+    else
+        pAbility->Full_100= 0;
+    
+    if(phyData4 & (1<<7))
+        pAbility->Half_100= 1;
+    else
+        pAbility->Half_100= 0;
+
+    if(phyData4 & (1<<6))
+        pAbility->Full_10= 1;
+    else
+        pAbility->Full_10= 0;
+    
+    if(phyData4 & (1<<5))
+        pAbility->Half_10= 1;
+    else
+        pAbility->Half_10= 0;
+
+
+    if(phyData0 & (1<<12))
+        pAbility->AutoNegotiation= 1;
+    else
+        pAbility->AutoNegotiation= 0;
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *     rtk_port_phyForceModeAbility_set
+ * Description:
+ *      Set the port PHY force mode, config its speed/duplex mode/pause/asy_pause 
+ * Input:
+ *      port       -  Port id
+ *      pAbility   -  Ability structure
+ * Output:
+ *      none
+ * Return:
+ *      RT_ERR_OK                        
+ *      RT_ERR_FAILED                  
+ *      RT_ERR_SMI       
+ *      RT_ERR_PORT_ID
+ *      RT_ERR_PHY_REG_ID
+ *      RT_ERR_NULL_POINTER
+ *      RT_ERR_PHY_FORCE_1000
+ *      RT_ERR_BUSYWAIT_TIMEOUT
+ *     
+ * Note:
+ *      (1) RTL8306E switch only has 5 phy, so the input port id should be 0~4.
+ *      (2) In force mode, phy autoNegotiation ability must be disabled.
+ */
+rtk_api_ret_t rtk_port_phyForceModeAbility_set(rtk_port_t port, rtk_port_phy_ability_t *pAbility)
+{
+    rtk_api_ret_t retVal;           
+    uint32 phyData;
+    uint32 phyEnMsk0;
+    uint32 phyEnMsk4;
+    
+    if(port > 4)
+        return RT_ERR_PORT_ID;  
+    
+    if(NULL == pAbility)
+        return RT_ERR_NULL_POINTER;
+
+    if(pAbility->Half_10 >= RTK_ENABLE_END || pAbility->Full_10 >= RTK_ENABLE_END ||
+       pAbility->Half_100 >= RTK_ENABLE_END || pAbility->Full_100 >= RTK_ENABLE_END ||
+       pAbility->AutoNegotiation >= RTK_ENABLE_END ||pAbility->AsyFC >= RTK_ENABLE_END ||
+       pAbility->FC >= RTK_ENABLE_END)
+        return RT_ERR_INPUT; 
+
+    /*for PHY force mode setup*/
+    pAbility->AutoNegotiation = 0;
+    
+    phyEnMsk0 = 0;
+    phyEnMsk4 = 0;
+    
+    if(1 == pAbility->Half_10)
+    {
+        /*Speed selection in reg 0.13 */
+        /* 1= 100Mpbs*/
+        /* 0= 10Mpbs*/        
+        phyEnMsk0 = phyEnMsk0 & (~(1<<13));
+
+        /*Half duplex mode in reg 0.8*/
+        phyEnMsk0 = phyEnMsk0 & (~(1<<8));
+    }
+
+    if(1 == pAbility->Full_10)
+    {
+        /*Speed selection in reg 0.13 */
+        /* 1= 100Mpbs*/
+        /* 0= 10Mpbs*/        
+        phyEnMsk0 = phyEnMsk0 & (~(1<<13));
+
+        /*Full duplex mode in reg 0.8*/
+        phyEnMsk0 = phyEnMsk0 | (1<<8);
+        
+    }
+
+    if(1 == pAbility->Half_100)
+    {
+        /*Speed selection in reg 0.13 */
+        /* 1= 100Mpbs*/
+        /* 0= 10Mpbs*/       
+        phyEnMsk0 = phyEnMsk0 | (1<<13);
+        
+        /*Half duplex mode in reg 0.8*/
+        phyEnMsk0 = phyEnMsk0 & (~(1<<8));
+    }
+
+
+    if(1 == pAbility->Full_100)
+    {
+        /*Speed selection in reg 0.13 */
+        /* 1= 100Mpbs*/
+        /* 0= 10Mpbs*/       
+        phyEnMsk0 = phyEnMsk0 | (1<<13);
+        
+        /*Full duplex mode in reg 0.8*/
+        phyEnMsk0 = phyEnMsk0 | (1<<8);
+    }
+        
+    if(1 == pAbility->AsyFC)
+    {
+        /*Asymetric flow control in reg 4.11*/
+        phyEnMsk4 = phyEnMsk4 | (1<<11);
+    }
+    if(1 == pAbility->FC)
+    {
+        /*Flow control in reg 4.10*/
+        phyEnMsk4 = phyEnMsk4 | (1<<10);
+    }
+    
+    /*Auto-Negotiation control register setting*/
+    if((retVal = rtk_port_phyReg_get(port, (rtk_port_phy_reg_t)PHY_AN_ADVERTISEMENT_REG, &phyData))!= RT_ERR_OK)
+        return retVal;
+
+    phyData = (phyData & (~0x0DE0)) | phyEnMsk4;
+    if((retVal = rtk_port_phyReg_set(port, (rtk_port_phy_reg_t)PHY_AN_ADVERTISEMENT_REG, phyData)) != RT_ERR_OK)
+        return retVal;
+
+    /*Control register setting and restart auto*/
+    if((retVal = rtk_port_phyReg_get(port, (rtk_port_phy_reg_t)PHY_CONTROL_REG, &phyData)) != RT_ERR_OK)
+        return retVal;
+    phyData = (phyData & (~0x3100)) | phyEnMsk0;
+    if((retVal = rtk_port_phyReg_set(port, (rtk_port_phy_reg_t)PHY_CONTROL_REG, phyData)) != RT_ERR_OK)
+        return retVal;
+    
+       
+    return RT_ERR_OK;
+}
+
+
+/* Function Name:
+ *      rtk_port_phyForceModeAbility_get
+ * Description:
+ *      Get the port PHY speed/duplex mode/pause/asy_pause in force mode
+ * Input:
+ *      port       -  Port id
+ * Output:
+ *      pAbility   -  Ability structure
+ * Return:
+ *      RT_ERR_OK                        
+ *      RT_ERR_FAILED                  
+ *      RT_ERR_SMI       
+ *      RT_ERR_PORT_ID
+ *      RT_ERR_PHY_REG_ID
+ *      RT_ERR_NULL_POINTER
+ *      RT_ERR_BUSYWAIT_TIMEOUT
+ *     
+ * Note:
+ *      (1) RTL8306E switch only has 5 phy, so the input port id should be 0~4.
+ *      (2) In force mode, phy autoNegotiation ability must be disabled.
+ */
+rtk_api_ret_t rtk_port_phyForceModeAbility_get(rtk_port_t port, rtk_port_phy_ability_t *pAbility)
+{
+    uint32 phyData0;
+    uint32 phyData4;
+    rtk_api_ret_t retVal;    
+    
+    if(port > 4)
+        return RT_ERR_PORT_ID; 
+    
+    if(NULL == pAbility)
+        return RT_ERR_NULL_POINTER;
+                 
+
+    /*Control register setting and restart auto*/
+    if((retVal = rtk_port_phyReg_get(port, (rtk_port_phy_reg_t)PHY_CONTROL_REG, &phyData0)) != RT_ERR_OK)
+        return retVal;
+
+    /*Auto-Negotiation control register setting*/
+    if((retVal = rtk_port_phyReg_get(port, (rtk_port_phy_reg_t)PHY_AN_ADVERTISEMENT_REG, &phyData4)) != RT_ERR_OK)
+        return retVal;
+
+    if(phyData0 & (1<<12))
+        return RT_ERR_PHY_FORCE_ABILITY;
+
+    if(phyData4 & (1<<11))
+        pAbility->AsyFC = 1;
+    else
+        pAbility->AsyFC = 0;
+
+    if(phyData4 & (1<<10))
+        pAbility->FC = 1;
+    else
+        pAbility->FC = 0;
+    
+
+    pAbility->Full_100 = 0;
+    pAbility->Half_100 = 0;
+    pAbility->Full_10 = 0;    
+    pAbility->Half_10 = 0;
+    pAbility->Full_1000 = 0;
+
+    if(phyData0 & (1<<8) && phyData0 & (1<<13))
+        pAbility->Full_100= 1;
+    
+    if(!(phyData0 & (1<<8)) && phyData0 & (1<<13))
+        pAbility->Half_100= 1;
+
+    if(phyData0 & (1<<8) && !(phyData0 & (1<<13)))
+        pAbility->Full_10= 1;
+    
+    if(!(phyData0 & (1<<8)) && !(phyData0 & (1<<13)))
+        pAbility->Half_10= 1;
+
+    if(phyData0 & (1<<12))
+        pAbility->AutoNegotiation= 1;
+    else
+        pAbility->AutoNegotiation= 0;
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_port_phyStatus_get
+ * Description:
+ *      Get ethernet PHY linking status
+ * Input:
+ *      port             -  Port id
+ * Output:
+ *      pLinkStatus   -  the pointer of PHY link status 
+ *      pSpeed         -  the pointer of PHY link speed
+ *      pDuplex        -  the pointer of PHY duplex 
+ * Return:
+ *      RT_ERR_OK                        
+ *      RT_ERR_FAILED                  
+ *      RT_ERR_SMI       
+ *      RT_ERR_PORT_ID
+ *      RT_ERR_NULL_POINTER
+ *     
+ * Note:
+ *      RTL8306E switch only has 5 phy, so the input port id should be 0~4.
+ */
+rtk_api_ret_t rtk_port_phyStatus_get(rtk_port_t port, rtk_port_linkStatus_t *pLinkStatus, rtk_port_speed_t *pSpeed, rtk_port_duplex_t *pDuplex)
+{
+    rtk_api_ret_t retVal;
+    uint32 phyData0;
+    uint32  linkUp;
+    
+    if(port > 4)
+        return RT_ERR_PORT_ID; 
+    
+    if((NULL == pLinkStatus) || (NULL == pSpeed) || (NULL == pDuplex))
+        return RT_ERR_NULL_POINTER;
+
+    rtl8306e_port_phyLinkStatus_get(port, &linkUp);
+    if (TRUE == linkUp)
+    {
+        *pLinkStatus = PORT_LINKUP;
+        /*Control register setting and restart auto*/
+        if((retVal = rtk_port_phyReg_get(port, (rtk_port_phy_reg_t)PHY_CONTROL_REG, &phyData0)) != RT_ERR_OK)
+            return retVal;
+        *pSpeed = ((phyData0 & (0x1 << 13)) >> 13) ? PORT_SPEED_100M : PORT_SPEED_10M; 
+        *pDuplex = ((phyData0 & (0x1 << 8)) >> 8) ? PORT_FULL_DUPLEX : PORT_HALF_DUPLEX;
+    }
+    else
+    {
+        *pLinkStatus = PORT_LINKDOWN;
+        *pSpeed = PORT_SPEED_10M;
+        *pDuplex = PORT_HALF_DUPLEX; 
+    }
+  
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_port_macForceLinkExt0_set
+ * Description:
+ *      Set external interface 1(MAC 5) force linking configuration.
+ * Input:
+ *      mode - external interface mode
+ *      pPortability - port ability configuration
+ * Output:
+ *      None 
+ * Return:
+ *      RT_ERR_OK              - Success
+ *      RT_ERR_FAILED          - Failure
+ *      RT_ERR_INPUT       - Invalid input parameters.
+ * Note:
+ *      (1) This API can set external interface 1(MAC 5) force mode properties,
+ *      including link status,speed,duplex,and tx pause and tx pause ability.
+ *      In force mode, autoNegotiation ability must be disabled.
+ *      (2) For 8306E, the external interface 1(MAC 5) operating mode can be
+ *      MAC Mode (T)MII, PHY Mode (T)MII and RMII. The operating mode is 
+ *      determined by strapping pin upon reset, and can not be configured 
+ *      by software, except the selection of MII or TMII. 
+ *      (3)The input parament mode here is only used to select MII or TMII.
+ *      When operating mode is configured as MAC Mode (T)MII or PHY Mode (T)MII
+ *      via strapping pin, then the selection of MII or TMII can be done via software.
+ *      For example, set mode MODE_EXT_TMII_MAC to select TMII, and set mode
+ *      MODE_EXT_MII_MAC to select MII.
+ */
+rtk_api_ret_t rtk_port_macForceLinkExt0_set(rtk_mode_ext_t mode, rtk_port_mac_ability_t *pPortability)
+{
+    rtk_api_ret_t retVal;
+    uint32 regVal;
+
+    if (pPortability->speed > 1 || pPortability->duplex > 1 || pPortability->txpause > 1 ||
+        pPortability->rxpause > 1 || pPortability->link > 1)
+        return RT_ERR_INPUT;
+
+    if (MODE_EXT_TMII_MAC == mode || MODE_EXT_TMII_PHY == mode)
+    {
+        rtl8306e_regbit_set (0, 16, 14, 0, 1);
+        rtl8306e_regbit_set (4, 27, 12, 0, 1);    
+    }
+    else if (MODE_EXT_MII_MAC == mode || MODE_EXT_MII_PHY == mode)
+    {
+        rtl8306e_regbit_set (0, 16, 14, 0, 0);
+        rtl8306e_regbit_set (4, 27, 12, 0, 0); 
+    }
+
+    /*must be in forcemode*/
+    pPortability->forcemode = 1;
+
+    /*Nway ability must be disabled*/
+    pPortability->nway = 0;
+    if ((retVal = rtl8306e_regbit_set (6, 22, 6, 0, 0)) != RT_ERR_OK)
+        return retVal;
+    
+    if ((retVal = rtl8306e_regbit_set (6, 22, 15, 0, pPortability->link ? 1 : 0)) != RT_ERR_OK)
+        return retVal;
+    
+    rtl8306e_reg_get(6, 22, 0, &regVal);
+    regVal &= (~0x30);
+    if ((pPortability->speed == PORT_SPEED_100M) && (pPortability->duplex == PORT_FULL_DUPLEX))
+        regVal |= 0x30; 
+    else if ((pPortability->speed == PORT_SPEED_10M) && (pPortability->duplex == PORT_FULL_DUPLEX))
+        regVal |= 0x10;
+    else if ((pPortability->speed == PORT_SPEED_100M) && (pPortability->duplex == PORT_HALF_DUPLEX ))
+        regVal |= 0x20;
+    else
+        regVal |= 0x0;
+    if ((retVal = rtl8306e_reg_set (6, 22, 0, regVal)) != RT_ERR_OK)
+        return retVal;
+
+    /*Enable symmetric flow control of MAC 5*/
+    if (pPortability->symflc)
+    {
+       rtl8306e_regbit_set (6, 24, 12, 0, 0);
+       rtl8306e_regbit_set (6, 4, 10, 0, 1);
+    }
+    /*Enable asymmetric flow control of MAC 5*/
+    else
+    {
+        rtl8306e_regbit_set (6, 4, 10, 0, 0);
+        if ((retVal = rtl8306e_regbit_set (6, 24, 12, 0, 1)) != RT_ERR_OK)
+            return retVal;
+        if ((retVal = rtl8306e_regbit_set (6, 24, 14, 0, pPortability->txpause ? 0 : 1)) != RT_ERR_OK)
+            return retVal;
+        if ((retVal = rtl8306e_regbit_set (6, 24, 13, 0, pPortability->rxpause ? 0 : 1)) != RT_ERR_OK)
+            return retVal;
+    }
+
+    return RT_ERR_OK;
+}
+
+
+/* Function Name:
+ *      rtk_port_macForceLinkExt0_get
+ * Description:
+ *      Get external interface 1(MAC 5) force linking configuration.
+ * Input:
+ *      None
+ * Output:
+ *      pMode - external interface mode
+ *      pPortability - port ability configuration
+ * Return:
+ *      RT_ERR_OK              - Success
+ *      RT_ERR_FAILED          - Failure 
+ *      RT_ERR_INPUT - Invalid input parameters.
+ * Note:
+ *      This API can get external interface 1 (MAC 5) force mode properties.
+ *      The external interface 1 operating mode can be:
+ *      - MODE_EXT_MII_MAC,
+ *      - MODE_EXT_MII_PHY, 
+ *      - MODE_EXT_TMII_MAC,
+ *      - MODE_EXT_TMII_PHY, 
+ *      - MODE_EXT_RMII, 
+ */
+rtk_api_ret_t rtk_port_macForceLinkExt0_get(rtk_mode_ext_t *pMode, rtk_port_mac_ability_t *pPortability)
+{
+    uint32 regVal;
+    uint32 modesel;
+
+    rtl8306e_regbit_set(0, 16, 11, 0, 1);
+    rtl8306e_reg_get(6, 26, 3, &regVal);
+    modesel = regVal & 0x1F;
+    if (0x1 == modesel || 0x2 == modesel || 0x9 == modesel || 0x12 == modesel || 0x10 == modesel)
+        *pMode = MODE_EXT_MII_PHY;
+    else if (0xA == modesel || 0xB == modesel)
+        *pMode = MODE_EXT_MII_MAC;
+    else if (0x0 == modesel || 0x8 == modesel || 0x11 == modesel)
+        *pMode = MODE_EXT_RMII;
+    else
+        *pMode = MODE_EXT_END;
+    
+    rtl8306e_regbit_get (0, 16, 14, 0, &regVal);
+    if (regVal && (MODE_EXT_MII_PHY == *pMode))
+        *pMode = MODE_EXT_TMII_PHY;
+    
+    if (regVal && (MODE_EXT_MII_MAC == *pMode))
+        *pMode = MODE_EXT_TMII_MAC;
+
+    rtl8306e_regbit_get (6, 22, 6, 0, &regVal);
+    pPortability->nway = regVal ? 1 : 0;
+    pPortability->forcemode = ~(pPortability->nway);
+
+    rtl8306e_regbit_get (6, 24, 12, 0, &regVal);
+    pPortability->symflc = regVal ? 0 : 1;
+    
+    rtl8306e_regbit_get (6, 24, 13, 0, &regVal);
+    pPortability->rxpause = regVal ? 0 : 1;
+
+    rtl8306e_regbit_get (6, 24, 14, 0, &regVal);
+    pPortability->txpause = regVal ? 0 : 1;
+
+    rtl8306e_regbit_get (6, 22, 15, 0, &regVal);
+    pPortability->link= regVal ? 1 : 0;
+
+    rtl8306e_reg_get (6, 22, 0, &regVal);
+    if ((regVal & (0x3 << 4)) >> 4 == 0x3)
+    {
+        pPortability->speed =1;
+        pPortability->duplex =1;
+    }
+    else if ((regVal & (0x3 << 4)) >> 4 == 0x2)
+    {
+        pPortability->speed = 1;
+        pPortability->duplex =0;
+    }
+    else if ((regVal & (0x3 << 4)) >> 4 == 0x1)
+    {
+        pPortability->speed = 0;
+        pPortability->duplex =1;
+    }
+    else if ((regVal & (0x3 << 4)) >> 4 == 0x0)
+    {
+        pPortability->speed = 0;
+        pPortability->duplex =0;
+    }
+    
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_port_macForceLinkExt_set
+ * Description:
+ *      Set external interface force linking configuration.
+ * Input:
+ *      port    -   port number
+ *      mode - external interface mode
+ *      pPortability - port ability configuration
+ * Output:
+ *      None 
+ * Return:
+ *      RT_ERR_OK              - Success
+ *      RT_ERR_FAILED          - Failure
+ *      RT_ERR_INPUT       - Invalid input parameters.
+ * Note:
+ *      (1) This API can set external interface 0 and 1(MAC4 and MAC 5)force mode properties,
+ *      including link status,speed,duplex,and tx pause and tx pause ability.
+ *      In force mode, autoNegotiation ability must be disabled.
+ *      (2) For 8306E, the external interface 0(MAC 4) operating mode can be
+ *      MAC Mode MII, PHY Mode MII and RMII. The operating mode is 
+ *      determined by strapping pin upon reset, and can not be configured 
+ *      by software.  
+ *      (3) For 8306E, the external interface 1(MAC 5) operating mode can be
+ *      MAC Mode (T)MII, PHY Mode (T)MII and RMII. The operating mode is 
+ *      determined by strapping pin upon reset, and can not be configured 
+ *      by software, except the selection of MII or TMII. 
+ *      (4)The input parament mode here is only used to select MII or TMII. And it only takes effect
+ *      for external interface 1, neither for external interface 0.
+ *      When operating mode is configured as MAC Mode (T)MII or PHY Mode (T)MII
+ *      via strapping pin, then the selection of MII or TMII can be done via software.
+ *      For example, set mode MODE_EXT_TMII_MAC to select TMII, and set mode
+ *      MODE_EXT_MII_MAC to select MII.
+ */
+rtk_api_ret_t rtk_port_macForceLinkExt_set(rtk_port_t port, rtk_mode_ext_t mode, rtk_port_mac_ability_t *pPortability)
+{
+    rtk_api_ret_t retVal;
+    uint32 regVal;
+
+    if (port > RTL8306_PORT5)
+        return RT_ERR_INPUT; 
+    if (pPortability->speed > 1 || pPortability->duplex > 1 || pPortability->txpause > 1 ||
+        pPortability->rxpause > 1 || pPortability->link > 1)
+        return RT_ERR_INPUT; 
+
+    if (RTL8306_PORT4 == port)
+    {
+        /*must be in forcemode*/
+        pPortability->forcemode = 1;
+
+        /*Nway ability must be disabled*/
+        pPortability->nway = 0;
+
+        if ((retVal = rtl8306e_regbit_set (5, 0, 12, 0, 0)) != RT_ERR_OK)
+            return retVal;
+        rtl8306e_regbit_get (5, 0, 12, 0, &regVal);
+        
+        /*speed and duplex*/
+        rtl8306e_reg_get(5, 0, 0, &regVal);
+        regVal &= ~((0x1<<13) | (0x1<<8));
+        if (pPortability->speed == PORT_SPEED_100M) 
+            regVal |= (0x1 << 13);
+        else
+            regVal |= 0;
+        if (pPortability->duplex == PORT_FULL_DUPLEX)
+            regVal |= (0x1 << 8);
+        else
+            regVal |= 0;    
+        if ((retVal = rtl8306e_reg_set (5, 0, 0, regVal)) != RT_ERR_OK)
+            return retVal;
+        /*Enable advertising symmetric flow control ability of MAC 4*/
+        if (pPortability->symflc)
+            rtl8306e_regbit_set (5, 4, 10, 0, 1);
+        else 
+            rtl8306e_regbit_set (5, 4, 10, 0, 0);
+    }
+    else if (RTL8306_PORT5 == port)
+    {
+        if (MODE_EXT_TMII_MAC == mode || MODE_EXT_TMII_PHY == mode)
+        {
+            rtl8306e_regbit_set (0, 16, 14, 0, 1);
+            rtl8306e_regbit_set (4, 27, 12, 0, 1);    
+        }
+        else if (MODE_EXT_MII_MAC == mode || MODE_EXT_MII_PHY == mode)
+        {
+            rtl8306e_regbit_set (0, 16, 14, 0, 0);
+            rtl8306e_regbit_set (4, 27, 12, 0, 0); 
+        }
+
+        /*must be in forcemode*/
+        pPortability->forcemode = 1;
+
+        /*Nway ability must be disabled*/
+        pPortability->nway = 0;
+        if ((retVal = rtl8306e_regbit_set (6, 22, 6, 0, 0)) != RT_ERR_OK)
+            return retVal;
+        
+        if ((retVal = rtl8306e_regbit_set (6, 22, 15, 0, pPortability->link ? 1 : 0)) != RT_ERR_OK)
+            return retVal;
+        
+        rtl8306e_reg_get(6, 22, 0, &regVal);
+        regVal &= (~0x30);
+        if ((pPortability->speed == PORT_SPEED_100M) && (pPortability->duplex == PORT_FULL_DUPLEX))
+            regVal |= 0x30; 
+        else if ((pPortability->speed == PORT_SPEED_10M) && (pPortability->duplex == PORT_FULL_DUPLEX))
+            regVal |= 0x10;
+        else if ((pPortability->speed == PORT_SPEED_100M) && (pPortability->duplex == PORT_HALF_DUPLEX ))
+            regVal |= 0x20;
+        else
+            regVal |= 0x0;
+        if ((retVal = rtl8306e_reg_set (6, 22, 0, regVal)) != RT_ERR_OK)
+            return retVal;
+
+        /*Enable symmetric flow control of MAC 5*/
+        if (pPortability->symflc)
+        {
+           rtl8306e_regbit_set (6, 24, 12, 0, 0);
+           rtl8306e_regbit_set (6, 4, 10, 0, 1);
+        }
+        /*Enable asymmetric flow control of MAC 5*/
+        else
+        {
+            rtl8306e_regbit_set (6, 4, 10, 0, 0);
+            if ((retVal = rtl8306e_regbit_set (6, 24, 12, 0, 1)) != RT_ERR_OK)
+                return retVal;
+            if ((retVal = rtl8306e_regbit_set (6, 24, 14, 0, pPortability->txpause ? 0 : 1)) != RT_ERR_OK)
+                return retVal;
+            if ((retVal = rtl8306e_regbit_set (6, 24, 13, 0, pPortability->rxpause ? 0 : 1)) != RT_ERR_OK)
+                return retVal;
+        }        
+    }
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_port_macForceLinkExt_get
+ * Description:
+ *      Get external interface force linking configuration.
+ * Input:
+ *      port    -   port number
+ * Output:
+ *      pMode - external interface mode
+ *      pPortability - port ability configuration
+ * Return:
+ *      RT_ERR_OK              - Success
+ *      RT_ERR_FAILED          - Failure 
+ *      RT_ERR_INPUT - Invalid input parameters.
+ *      RT_ERR_NULL_POINTER - Null pointer
+ * Note:
+ *      This API can get external interface 0 (MAC 4) and 1 (MAC 5) force mode properties.
+ *      The external interface 0 operating mode can be:
+ *      - MODE_EXT_MII_MAC,
+ *      - MODE_EXT_MII_PHY, 
+ *      - MODE_EXT_RMII,     
+ *      The external interface 1 operating mode can be:
+ *      - MODE_EXT_MII_MAC,
+ *      - MODE_EXT_MII_PHY, 
+ *      - MODE_EXT_TMII_MAC,
+ *      - MODE_EXT_TMII_PHY, 
+ *      - MODE_EXT_RMII, 
+ */
+rtk_api_ret_t rtk_port_macForceLinkExt_get(rtk_port_t port, rtk_mode_ext_t *pMode, rtk_port_mac_ability_t *pPortability)
+{
+    uint32 regVal;
+    uint32 modesel;
+
+    if (port > RTL8306_PORT5)
+        return RT_ERR_INPUT; 
+    if((NULL == pMode) || (NULL == pPortability))
+        return RT_ERR_NULL_POINTER;
+
+    if (RTL8306_PORT4 == port)
+    {
+        rtl8306e_regbit_set(0, 16, 11, 0, 1);
+        rtl8306e_reg_get(6, 26, 3, &regVal);
+        modesel = regVal & 0x1F;
+        if (0x2 == modesel || 0x4 == modesel || 0x5 == modesel || 0x6 == modesel || 0x7 == modesel || \
+            0x14  == modesel || 0x15 == modesel || 0x16 == modesel || 0x17 == modesel)
+            *pMode = MODE_EXT_MII_PHY;
+        else if (0x8 == modesel || 0x9 == modesel || 0xA == modesel || 0xB == modesel || 0xC == modesel || 0xD == modesel || \
+            0xE == modesel || 0xF == modesel || 0x1C == modesel || 0x1D == modesel || 0x1E == modesel || 0X1F == modesel)
+            *pMode = MODE_EXT_MII_MAC;
+        else if (0x0 == modesel || 0x1 == modesel || 0x3 == modesel || 0x11 == modesel || 0x13 == modesel)
+            *pMode = MODE_EXT_RMII;
+        else
+            *pMode = MODE_EXT_END;
+
+        /*get nway bility*/
+        rtl8306e_regbit_get (5, 0, 12, 0, &regVal);
+        pPortability->nway = regVal ? 1 : 0;
+        pPortability->forcemode = regVal ? 0: 1;
+        
+        /*get speed and duplex ability*/
+        rtl8306e_regbit_get (5, 0, 13, 0, &regVal);
+        if(regVal)
+            pPortability->speed =PORT_SPEED_100M;
+        else 
+            pPortability->speed = PORT_SPEED_10M;
+        
+        rtl8306e_regbit_get (5, 0, 8, 0, &regVal);
+        if(regVal)
+            pPortability->duplex = PORT_FULL_DUPLEX;
+        else
+            pPortability->duplex = PORT_HALF_DUPLEX;
+        
+        /*get asymmetric flow control aibility*/
+        rtl8306e_regbit_get (5, 4, 10, 0, &regVal);
+        pPortability->symflc = regVal ? 1 : 0;
+        pPortability->rxpause = regVal ? 1 : 0;
+        pPortability->txpause = regVal ? 1 : 0;
+
+        /*get link status*/
+        rtl8306e_regbit_get (5, 1, 2, 0, &regVal);
+        pPortability->link= regVal ? 1 : 0;        
+    }
+    else if (RTL8306_PORT5 == port)
+    {
+        rtl8306e_regbit_set(0, 16, 11, 0, 1);
+        rtl8306e_reg_get(6, 26, 3, &regVal);
+        modesel = regVal & 0x1F;
+        if (0x1 == modesel || 0x2 == modesel || 0x9 == modesel || 0x12 == modesel || 0x10 == modesel)
+            *pMode = MODE_EXT_MII_PHY;
+        else if (0xA == modesel || 0xB == modesel)
+            *pMode = MODE_EXT_MII_MAC;
+        else if (0x0 == modesel || 0x8 == modesel || 0x11 == modesel)
+            *pMode = MODE_EXT_RMII;
+        else
+            *pMode = MODE_EXT_END;
+        
+        rtl8306e_regbit_get (0, 16, 14, 0, &regVal);
+        if (regVal && (MODE_EXT_MII_PHY == *pMode))
+            *pMode = MODE_EXT_TMII_PHY;
+        
+        if (regVal && (MODE_EXT_MII_MAC == *pMode))
+            *pMode = MODE_EXT_TMII_MAC;
+
+
+        rtl8306e_regbit_get (6, 22, 6, 0, &regVal);
+        pPortability->nway = regVal ? 1 : 0;
+        pPortability->forcemode = regVal ? 0: 1;
+
+        rtl8306e_regbit_get (6, 24, 12, 0, &regVal);
+        pPortability->symflc = regVal ? 0 : 1;
+        
+        rtl8306e_regbit_get (6, 24, 13, 0, &regVal);
+        pPortability->rxpause = regVal ? 0 : 1;
+
+        rtl8306e_regbit_get (6, 24, 14, 0, &regVal);
+        pPortability->txpause = regVal ? 0 : 1;
+
+        rtl8306e_regbit_get (6, 22, 15, 0, &regVal);
+        pPortability->link= regVal ? 1 : 0;
+
+        rtl8306e_reg_get (6, 22, 0, &regVal);
+        if ((regVal & (0x3 << 4)) >> 4 == 0x3)
+        {
+            pPortability->speed =PORT_SPEED_100M;
+            pPortability->duplex =PORT_FULL_DUPLEX;
+        }
+        else if ((regVal & (0x3 << 4)) >> 4 == 0x2)
+        {
+            pPortability->speed = PORT_SPEED_100M;
+            pPortability->duplex = PORT_HALF_DUPLEX;
+        }
+        else if ((regVal & (0x3 << 4)) >> 4 == 0x1)
+        {
+            pPortability->speed = PORT_SPEED_10M;
+            pPortability->duplex =PORT_FULL_DUPLEX;
+        }
+        else if ((regVal & (0x3 << 4)) >> 4 == 0x0)
+        {
+            pPortability->speed = PORT_SPEED_10M;
+            pPortability->duplex =PORT_HALF_DUPLEX;
+        }    
+    }
+
+    return RT_ERR_OK;
+}
+
+#ifdef CHIP_RTL8304E
+/* Function Name:
+ *      rtk_port_mii1Disable_set
+ * Description:
+ *      Disable MII1 for RTL8304E by trunk
+ * Input:
+ *      none
+ * Output:
+ *      none
+ * Return:
+ *      RT_ERR_OK
+ * Note:
+ *      Strapping pin 49 can be used to force MII1 link down for RTL8306E.
+ *      But there are no strapping pins or registers for RTL8304E to do so.
+ *      To disable MII1 for RTL8304E, trunk can be used. First enable trunk function,
+ *      Then trunk rtl8306e's port3 and port4 to be a trunk port. After this port2(MII1) is 
+ *      forced to be linking down for RTL8304E.    
+*/
+rtk_api_ret_t rtk_port_mii1Disable_set(void)
+{
+    rtl8306e_regbit_set(0,19,11,0,0);
+    rtl8306e_regbit_set(0,16,6,0,0);
+
+    return RT_ERR_OK;
+}
+#endif
+
+/* Function Name:
+ *      rtk_port_isolation_set
+ * Description:
+ *      Set permitted port isolation portmask
+ * Input:
+ *      port                - port id, 0 ~ 5 
+ *      portmask         - Permit port mask
+ * Output:
+ *      none
+ * Return:
+ *      RT_ERR_OK             -   Success
+ *      RT_ERR_PORT_ID     -   Invalid port number
+ *      RT_ERR_PORT_MASK -   Invalid portmask
+ *      RT_ERR_FAILED        -   Failure
+ * Note:
+ *      This API set the port mask that a port can trasmit packet to of each port.
+ *      A port can only transmit packet to ports included in permitted portmask  
+ */
+rtk_api_ret_t rtk_port_isolation_set(rtk_port_t port, rtk_portmask_t portmask)
+{
+    rtk_api_ret_t retVal;
+    uint32 isomask;
+    uint32 regval;
+
+    if (port > RTK_PORT_ID_MAX)
+        return RT_ERR_PORT_ID;
+
+    if( portmask.bits[0] > RTK_MAX_PORT_MASK)
+        return RT_ERR_PORT_MASK;
+    
+    isomask = (~ (portmask.bits[0])) & 0x3F;
+    rtl8306e_reg_get(0, 29, 3, &regval);
+    switch (port)
+    {
+        case 0:
+            regval &= ~0x1F;
+            if (isomask & 0x2)
+                regval |=  (1 << 0); 
+            if (isomask & 0x4)
+                regval |=  (1 << 1); 
+            if (isomask & 0x8)
+                regval |=  (1 << 2); 
+            if (isomask & 0x10)
+                regval |=  (1 << 3); 
+            if (isomask & 0x20)
+                regval |=  (1 << 4); 
+            break;
+        case 1:
+            regval &= ~0x1E1;
+            if (isomask & 0x1)
+                regval |=  (1 << 0); 
+            if (isomask & 0x4)
+                regval |=  (1 << 5); 
+            if (isomask & 0x8)
+                regval |=  (1 << 6); 
+            if (isomask & 0x10)
+                regval |=  (1 << 7); 
+            if (isomask & 0x20)
+                regval |=  (1 << 8); 
+            break;
+        case 2:
+            regval &= ~0xE42;
+            if (isomask & 0x1)
+                regval |=  (1 << 1); 
+            if (isomask & 0x2)
+                regval |=  (1 << 5); 
+            if (isomask & 0x8)
+                regval |=  (1 << 9); 
+            if (isomask & 0x10)
+                regval |=  (1 << 10); 
+            if (isomask & 0x20)
+                regval |=  (1 << 11); 
+            break;
+        case 3:
+            regval &= ~0x3244;
+            if (isomask & 0x1)
+                regval |=  (1 << 2); 
+            if (isomask & 0x2)
+                regval |=  (1 << 6); 
+            if (isomask & 0x4)
+                regval |=  (1 << 9);
+            if (isomask & 0x10)
+                regval |=  (1 << 12); 
+            if (isomask & 0x20)
+                regval |=  (1 << 13); 
+            break;
+        case 4:
+            regval &= ~0x5488;
+            if (isomask & 0x1)
+                regval |=  (1 << 3); 
+            if (isomask & 0x2)
+                regval |=  (1 << 7); 
+            if (isomask & 0x4)
+                regval |=  (1 << 10);
+            if (isomask & 0x8)
+                regval |=  (1 << 12); 
+            if (isomask & 0x20)
+                regval |=  (1 << 14); 
+            break;
+        case 5:
+            regval &= ~0x6910;
+            if (isomask & 0x1)
+                regval |=  (1 << 4); 
+            if (isomask & 0x2)
+                regval |=  (1 << 8); 
+            if (isomask & 0x4)
+                regval |=  (1 << 11);
+            if (isomask & 0x8)
+                regval |=  (1 << 13); 
+            if (isomask & 0x10)
+                regval |=  (1 << 14); 
+            break;
+        default:
+            return RT_ERR_PORT_ID;
+    }
+    if((retVal= rtl8306e_reg_set(0, 29, 3, regval)) != RT_ERR_OK)
+        return retVal;
+    
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_port_isolation_get
+ * Description:
+ *      Get permitted port isolation portmask
+ * Input:
+ *      port                - port id, 0 ~ 5 
+ * Output:
+ *      pPortmask       - the pointer of permit port mask
+ * Return:
+ *      RT_ERR_OK                  -   Success
+ *      RT_ERR_PORT_ID          -   Invalid port number
+ *      RT_ERR_NULL_POINTER  -   Input parameter is null pointer
+ *      RT_ERR_FAILED             -   Failure
+ * Note:
+ *      This API get the port mask that a port can transmit packet to of each port.
+ *      A port can only transmit packet to ports included in permitted portmask  
+ */
+rtk_api_ret_t rtk_port_isolation_get(rtk_port_t port, rtk_portmask_t *pPortmask)
+{
+    uint32 isomask;
+    uint32 regval;
+    
+    if (port > RTK_PORT_ID_MAX)
+        return RT_ERR_PORT_ID;
+    if (NULL == pPortmask)
+        return RT_ERR_NULL_POINTER;
+    
+    isomask = 0;
+    rtl8306e_reg_get(0, 29, 3, &regval);
+    switch (port)
+    {
+        case 0:
+            isomask |= 0x1;
+            if(regval & (1 << 0))
+                isomask |= 0x2;
+            if(regval & (1 << 1))
+                isomask |= 0x4;
+            if(regval & (1 << 2))
+                isomask |= 0x8;
+            if(regval & (1 << 3))
+                isomask |= 0x10;
+            if(regval & (1 << 4))
+                isomask |= 0x20;
+            break;
+        case 1:
+            isomask |= 0x2;
+            if(regval & (1 << 0))
+                isomask |= 0x1;
+            if(regval & (1 << 5))
+                isomask |= 0x4;
+            if(regval & (1 << 6))
+                isomask |= 0x8;
+            if(regval & (1 << 7))
+                isomask |= 0x10;
+            if(regval & (1 << 8))
+                isomask |= 0x20;
+            break;
+        case 2:
+            isomask |= 0x4;
+            if(regval & (1 << 1))
+                isomask |= 0x1;
+            if(regval & (1 << 5))
+                isomask |= 0x2;
+            if(regval & (1 << 9))
+                isomask |= 0x8;
+            if(regval & (1 << 10))
+                isomask |= 0x10;
+            if(regval & (1 << 11))
+                isomask |= 0x20;
+            break;
+        case 3:
+            isomask |= 0x8;
+            if(regval & (1 << 2))
+                isomask |= 0x1;
+            if(regval & (1 << 6))
+                isomask |= 0x2;
+            if(regval & (1 << 9))
+                isomask |= 0x4;
+            if(regval & (1 << 12))
+                isomask |= 0x10;
+            if(regval & (1 << 13))
+                isomask |= 0x20;
+            break;
+        case 4:
+            isomask |= 0x10;
+            if(regval & (1 << 3))
+                isomask |= 0x1;
+            if(regval & (1 << 7))
+                isomask |= 0x2;
+            if(regval & (1 << 10))
+                isomask |= 0x4;
+            if(regval & (1 << 12))
+                isomask |= 0x8;
+            if(regval & (1 << 14))
+                isomask |= 0x20;
+            break;
+        case 5:
+            isomask |= 0x20;
+            if(regval & (1 << 4))
+                isomask |= 0x1;
+            if(regval & (1 << 8))
+                isomask |= 0x2;
+            if(regval & (1 << 11))
+                isomask |= 0x4;
+            if(regval & (1 << 13))
+                isomask |= 0x8;
+            if(regval & (1 << 14))
+                isomask |= 0x10;
+            break;
+        default:
+            return RT_ERR_PORT_ID;
+    }
+    pPortmask->bits[0] = (~isomask) & 0x3F;
+    
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_stat_port_reset
+ * Description:
+ *      Reset per port MIB counter by port.
+ * Input:
+ *      port - port id.
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK              - set shared meter successfully
+ *      RT_ERR_FAILED          - FAILED to iset shared meter
+ * Note:
+ */
+rtk_api_ret_t rtk_stat_port_reset(rtk_port_t port)
+{
+    rtk_api_ret_t retVal;
+
+    if (port > RTK_PORT_ID_MAX)
+        return RT_ERR_PORT_ID; 
+    
+    if ((retVal = rtl8306e_mib_reset(port) ) != RT_ERR_OK)
+        return retVal; 
+        
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_rate_igrBandwidthCtrlRate_set
+ * Description:
+ *      Set port ingress bandwidth control
+ * Input:
+ *      port            -  Port id
+ *      rate            -  Rate of share meter
+ *      ifg_include   -  Rate's calculation including IFG, ENABLED:include DISABLED:exclude
+ * Output:
+ *      none
+ * Return:
+ *      RT_ERR_OK              -  Success
+ *      RT_ERR_PORT_ID      -  Invalid port number
+ *      RT_ERR_FAILED        -  Failure
+ *      RT_ERR_ENABLE       -  Invalid IFG parameter
+ *      RT_ERR_INBW_RATE -  Invalid ingress rate parameter
+ * Note:
+ *      The rate unit is 64Kbps and the range is from 64Kbps to 100Mbps. The granularity of rate is 64Kbps. 
+ *      The ifg_include parameter is used for rate calculation with/without inter-frame-gap and preamble. 
+ */
+
+rtk_api_ret_t rtk_rate_igrBandwidthCtrlRate_set( rtk_port_t port, rtk_rate_t rate,  rtk_enable_t ifg_include)
+{
+    rtk_api_ret_t retVal;
+
+    if(port > RTK_PORT_ID_MAX) 
+        return RT_ERR_PORT_ID;    
+    
+    if (rate > RTL8306_QOS_RATE_INPUT_MAX) 
+        return RT_ERR_INBW_RATE;
+
+    if(ifg_include >= RTK_ENABLE_END)
+        return RT_ERR_ENABLE;
+
+    if((retVal = rtl8306e_qos_portRate_set(port, rate, RTL8306_PORT_RX , TRUE)) != RT_ERR_OK)
+        return retVal;
+
+    rtl8306e_regbit_set(0, 21, 14, 3, ifg_include ? 1:0);
+    
+    return RT_ERR_OK;
+}
+
+
+/* Function Name:
+ *      rtk_rate_igrBandwidthCtrlRate_get
+ * Description:
+ *      Get port ingress bandwidth control
+ * Input:
+ *      port             -  Port id
+ * Output:
+ *      pRate           -  the pointer of rate of share meter
+ *      pIfg_include   -  Rate's calculation including IFG, ENABLED:include DISABLED:exclude
+ * Return:
+ *      RT_ERR_OK                      -  Success
+ *      RT_ERR_PORT_ID              -  Invalid port number
+ *      RT_ERR_FAILED                -  Failure
+ *      RT_ERR_ENABLE               -  Invalid IFG parameter
+ *      RT_ERR_NULL_POINTER      -  null pointer
+ * Note:
+ *      The rate unit is 64Kbps and the range is from 64Kbps to 100Mbps. The granularity of rate is 64Kbps. 
+ *      The ifg_include parameter is used for rate calculation with/without inter-frame-gap and preamble. 
+ */
+ 
+rtk_api_ret_t rtk_rate_igrBandwidthCtrlRate_get(rtk_port_t port, rtk_rate_t *pRate, rtk_enable_t *pIfg_include)
+{
+    rtk_api_ret_t retVal;
+    uint32 enabled;
+
+    if(port > RTK_PORT_ID_MAX) 
+        return RT_ERR_PORT_ID;    
+
+    if((NULL == pRate) || (NULL == pIfg_include))
+        return RT_ERR_NULL_POINTER;
+    
+    if((retVal = rtl8306e_qos_portRate_get(port, pRate, RTL8306_PORT_RX, &enabled)) != SUCCESS)
+        return retVal;
+
+    if(!enabled)
+        *pRate = RTL8306_QOS_RATE_INPUT_MAX;
+
+    rtl8306e_regbit_get(0, 21, 14, 3, &enabled);
+    *pIfg_include = enabled ? ENABLED : DISABLED;
+        
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_rate_egrBandwidthCtrlRate_set
+ * Description:
+ *      Set port egress bandwidth control
+ * Input:
+ *      port            -  Port id
+ *      rate            -  Rate of bandwidth control
+ *      ifg_include   -  Rate's calculation including IFG, ENABLED:include DISABLED:exclude
+ * Output:
+ *      none
+ * Return:
+ *      RT_ERR_OK                   -  Success
+ *      RT_ERR_PORT_ID           -  Invalid port number
+ *      RT_ERR_FAILED             -  Failure
+ *      RT_ERR_ENABLE             -  Invalid IFG parameter
+ *      RT_ERR_QOS_EBW_RATE -  Invalid egress rate parameter
+ * Note:
+ *      The rate unit is 64Kbps and the range is from 64Kbps to 100Mbps. The granularity of rate is 64Kbps. 
+ *      The ifg_include parameter is used for rate calculation with/without inter-frame-gap and preamble. 
+ */
+
+rtk_api_ret_t rtk_rate_egrBandwidthCtrlRate_set(rtk_port_t port, rtk_rate_t rate,  rtk_enable_t ifg_include)
+{
+    rtk_api_ret_t retVal;
+
+    if(port > RTK_PORT_ID_MAX) 
+        return RT_ERR_PORT_ID;    
+    
+    if (rate > RTL8306_QOS_RATE_INPUT_MAX) 
+        return RT_ERR_QOS_EBW_RATE;
+
+    if(ifg_include >= RTK_ENABLE_END)
+        return RT_ERR_ENABLE;
+
+    if((retVal = rtl8306e_qos_portRate_set(port, rate, RTL8306_PORT_TX , TRUE)) != RT_ERR_OK)
+        return retVal;
+
+    rtl8306e_regbit_set(port, 17, 15, 2, ifg_include ? 0 :1);
+    
+    return RT_ERR_OK;
+}
+
+
+/* Function Name:
+ *      rtk_rate_igrBandwidthCtrlRate_get
+ * Description:
+ *      Get port ingress bandwidth control
+ * Input:
+ *      port             -  Port id
+ * Output:
+ *      pRate           -  the pointer of rate of bandwidth control
+ *      pIfg_include   -  Rate's calculation including IFG, ENABLED:include DISABLED:exclude
+ * Return:
+ *      RT_ERR_OK                     -  Success
+ *      RT_ERR_PORT_ID             -  Invalid port number
+ *      RT_ERR_FAILED                -  Failure
+ *      RT_ERR_NULL_POINTER      -  null pointer
+ * Note:
+ *      The rate unit is 64Kbps and the range is from 64Kbps to 100Mbps. The granularity of rate is 64Kbps. 
+ *      The ifg_include parameter is used for rate calculation with/without inter-frame-gap and preamble. 
+ */
+
+rtk_api_ret_t rtk_rate_egrBandwidthCtrlRate_get(rtk_port_t port, rtk_rate_t *pRate, rtk_enable_t *pIfg_include)
+{
+    rtk_api_ret_t retVal;
+    uint32 enabled;
+    uint32 disabled;
+
+    if(port > RTK_PORT_ID_MAX) 
+        return RT_ERR_PORT_ID;    
+
+    if((NULL == pRate) || (NULL == pIfg_include))
+        return RT_ERR_NULL_POINTER;
+    
+    if((retVal = rtl8306e_qos_portRate_get(port, pRate, RTL8306_PORT_TX, &enabled)) != SUCCESS)
+        return retVal;
+
+    if(!enabled)
+        *pRate = RTL8306_QOS_RATE_INPUT_MAX;
+
+    rtl8306e_regbit_get(port, 17, 15, 2, &disabled);
+    *pIfg_include = disabled ? DISABLED : ENABLED;
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_qos_init
+ * Description:
+ *      Configure Qos default settings with queue number assigment to each port
+ * Input:
+ *      queueNum     -  Queue number of each port
+ * Output:
+ *      none
+ * Return:
+ *      RT_ERR_OK                     -  Success
+ *      RT_ERR_FAILED                -  Failure
+ *      RT_ERR_QUEUE_NUM         -  Error queue number
+ * Note:
+ *    This API will initialize related Qos setting with queue number assigment.
+ *    The queue number is from 1 to 4.
+ */
+
+rtk_api_ret_t rtk_qos_init(rtk_queue_num_t queueNum)
+{
+    uint32 queue, port;
+    
+    if (rtl8306e_qos_queueNum_set(queueNum) == FAILED)
+        return FAILED;
+    
+    switch(queueNum)
+    {
+        case 1:
+            /*priority to qid mapping*/
+            rtl8306e_qos_priToQueMap_set(0, 0);
+            rtl8306e_qos_priToQueMap_set(1, 0);       
+            rtl8306e_qos_priToQueMap_set(2, 0);                   
+            rtl8306e_qos_priToQueMap_set(3, 0);                               
+            break;
+            
+        case 2:
+            /*priority to qid mapping*/
+            rtl8306e_qos_priToQueMap_set(0, 0);
+            rtl8306e_qos_priToQueMap_set(1, 0);       
+            rtl8306e_qos_priToQueMap_set(2, 1);                   
+            rtl8306e_qos_priToQueMap_set(3, 1);                                           
+            break;
+            
+        case 3:
+            /*priority to qid mapping*/
+            rtl8306e_qos_priToQueMap_set(0, 0);
+            rtl8306e_qos_priToQueMap_set(1, 1);       
+            rtl8306e_qos_priToQueMap_set(2, 1);                   
+            rtl8306e_qos_priToQueMap_set(3, 2);                                                       
+            break;            
+            
+        case 4:
+            /*priority to qid mapping*/
+            rtl8306e_qos_priToQueMap_set(0, 0);
+            rtl8306e_qos_priToQueMap_set(1, 1);       
+            rtl8306e_qos_priToQueMap_set(2, 2);                   
+            rtl8306e_qos_priToQueMap_set(3, 3);
+
+            for(queue = 0; queue < 4; queue++)
+            {
+                /*queue threshold*/
+                rtl8306e_qos_queFlcThr_set(queue, RTL8306_FCO_QLEN, RTL8306_FCON, RTL8306_FCO_SET0, 9);
+                rtl8306e_qos_queFlcThr_set(queue, RTL8306_FCO_QLEN, RTL8306_FCOFF, RTL8306_FCO_SET0, 5);        
+                rtl8306e_qos_queFlcThr_set(queue, RTL8306_FCO_DSC, RTL8306_FCON, RTL8306_FCO_SET0, 40);
+                rtl8306e_qos_queFlcThr_set(queue, RTL8306_FCO_DSC, RTL8306_FCOFF, RTL8306_FCO_SET0, 28);                                     
+
+            }
+            for (port = 0; port < 6; port ++)
+            {
+                rtl8306e_qos_portFlcThr_set(port, 130, 100,  RTL8306_PORT_TX); 
+                for(queue = 0; queue < 4; queue++)
+                {
+                    /*queue threshold*/
+                    rtl8306e_qos_queFlcEnable_set(port, queue, TRUE);           
+                }
+            }
+                                      
+            break;
+            
+        default:
+            return RT_ERR_QUEUE_NUM;
+            
+    }
+
+    rtl8306e_qos_softReset_set();    
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_qos_priSel_set
+ * Description:
+ *      Configure the priority order among different priority mechanisms.
+ * Input:
+ *      pPriDec - priority level for port, dscp, 802.1Q, ACL and VID based priority decision.
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK              - success
+ *      RT_ERR_NULL_POINTER  -   Input parameter is null pointer
+ *      RT_ERR_FAILED          - failure 
+ *      RT_ERR_QOS_SEL_PRI_SOURCE - Invalid priority decision source parameter.
+ * Note: 
+ *      (1)For 8306E, there are 5 types of priority mechanisms that could be set arbitration level, which are 
+ *      ACL-based  priority, DSCP-based priority, 1Q-based priority, Port-based priority, VID-based priority.
+ *      Each one could be set level from 1 to 5.
+ *      (2)ASIC will follow user's arbitration level setting of priority mechanisms to select internal priority for receiving frame. 
+ *      If two priority mechanisms are the same level, the ASIC will chose the priority mechanism with highest level to 
+ *      assign internal priority to receiving frame.
+ */
+rtk_api_ret_t rtk_qos_priSel_set(rtk_priority_select_t *pPriDec)
+{ 
+    rtk_api_ret_t retVal;
+    rtl8306e_qosPriArbitPara_t priArbit;
+
+    if (NULL == pPriDec)
+        return RT_ERR_NULL_POINTER;
+    if (pPriDec->port_pri > 5 || pPriDec->dot1q_pri > 5 || pPriDec->acl_pri > 5 || pPriDec->dscp_pri > 5 
+        || pPriDec->vid_pri > 5)
+        return RT_ERR_QOS_SEL_PRI_SOURCE;
+
+    priArbit.port_pri_lev = pPriDec->port_pri;
+    priArbit.acl_pri_lev = pPriDec->acl_pri;
+    priArbit.dscp_pri_lev = pPriDec->dscp_pri;
+    priArbit.dot1q_pri_lev = pPriDec->dot1q_pri;
+    priArbit.vid_pri_lev = pPriDec->vid_pri;
+
+    if ((retVal = rtl8306e_qos_priSrcArbit_set(priArbit)) != RT_ERR_OK)
+        return retVal;
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_qos_priSel_get
+ * Description:
+ *      Get the priority order configuration among different priority mechanism.
+ * Input:
+ *      None
+ * Output:
+ *      pPriDec - priority level for port, dscp, 802.1Q, ACL and VID based priority decision.
+ * Return:
+ *      RT_ERR_OK              - success
+ *      RT_ERR_NULL_POINTER  -   Input parameter is null pointer
+ *      RT_ERR_FAILED          - failure 
+ * Note:
+ *      (1)For 8306E, there are 5 types of priority mechanisms that could be set arbitration level, which are 
+ *      ACL-based  priority, DSCP-based priority, 1Q-based priority,Port-based priority, VID-based priority.
+ *      Each one could be set level from 1 to 5.
+ *      (2)ASIC will follow user's arbitration level setting of priority mechanisms to select internal priority for receiving frame. 
+ *      If two priority mechanisms are the same level, the ASIC will chose the priority mechanism with the highest level to 
+ *      assign internal priority to receiving frame.
+ */
+
+rtk_api_ret_t rtk_qos_priSel_get(rtk_priority_select_t *pPriDec)
+{
+    rtk_api_ret_t retVal;
+    rtl8306e_qosPriArbitPara_t priArbit;   
+
+    if (NULL == pPriDec)
+        return RT_ERR_NULL_POINTER;
+    
+    if ((retVal = rtl8306e_qos_priSrcArbit_get(&priArbit)) != RT_ERR_OK)
+        return retVal;
+    pPriDec->port_pri = priArbit.port_pri_lev;
+    pPriDec->dot1q_pri = priArbit.dot1q_pri_lev;
+    pPriDec->dmac_pri = priArbit.dscp_pri_lev;
+    pPriDec->acl_pri = priArbit.acl_pri_lev;
+    pPriDec->vid_pri = priArbit.vid_pri_lev;
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_qos_1pPriRemap_set
+ * Description:
+ *      Configure 1Q priorities mapping to internal absolute priority
+ * Input:
+ *      dot1p_pri   -  802.1p priority value
+ *      int_pri       -  internal priority value
+ * Output:
+ *      none
+ * Return:
+ *      RT_ERR_OK                         -  Success
+ *      RT_ERR_FAILED                    -  Failure
+ *      RT_ERR_VLAN_PRIORITY        -  Invalid 1p priority
+ *      RT_ERR_QOS_INT_PRIORITY   -  Invalid priority
+ * Note:
+ *      Priority of 802.1Q assignment for internal asic priority, and it is used for queue usage 
+ *      and packet scheduling.
+ */
+rtk_api_ret_t rtk_qos_1pPriRemap_set(rtk_pri_t dot1p_pri, rtk_pri_t int_pri)
+{
+    rtk_api_ret_t retVal;
+
+    if (int_pri > RTL8306_PRIO3)
+        return RT_ERR_QOS_INT_PRIORITY;
+    
+    if (dot1p_pri > RTL8306_1QTAG_PRIO7)
+        return  RT_ERR_VLAN_PRIORITY;
+    
+    if ((retVal = rtl8306e_qos_1pPriRemap_set(dot1p_pri, int_pri)) != SUCCESS)
+        return retVal;
+    
+    return RT_ERR_OK;    
+}
+
+/* Function Name:
+ *      rtk_qos_1pPriRemap_get
+ * Description:
+ *      Get 1Q priorities mapping to internal absolute priority
+ * Input:
+ *      dot1p_pri    -  802.1p priority value
+ * Output:
+ *      pInt_pri      -  the pointer of internal priority value
+ * Return:
+ *      RT_ERR_OK                         -  Success
+ *      RT_ERR_FAILED                    -  Failure
+ *      RT_ERR_VLAN_PRIORITY        -  Invalid 1p priority
+ *      RT_ERR_NULL_POINTER         -   null pointer
+ * Note:
+ *      Priority of 802.1Q assignment for internal asic priority, and it is used for queue usage 
+ *      and packet scheduling.
+ */
+
+rtk_api_ret_t rtk_qos_1pPriRemap_get(rtk_pri_t dot1p_pri, rtk_pri_t *pInt_pri)
+{
+    rtk_api_ret_t retVal;
+    
+    if(NULL == pInt_pri)
+        return RT_ERR_NULL_POINTER;
+
+    if (dot1p_pri > RTL8306_1QTAG_PRIO7)
+        return  RT_ERR_VLAN_PRIORITY;
+    
+    if((retVal = rtl8306e_qos_1pPriRemap_get(dot1p_pri, pInt_pri)) != SUCCESS)
+        return retVal;
+    
+    return RT_ERR_OK;    
+}
+
+
+/* Function Name:
+ *      rtk_qos_dscpPriRemap_set
+ * Description:
+ *      Set DSCP-based priority
+ * Input:
+ *      code      -  dscp code
+ *      int_pri    -  internal priority value
+ * Output:
+ *      none
+ * Return:
+ *      RT_ERR_OK                         -  Success
+ *      RT_ERR_FAILED                    -  Failure
+ *      RT_ERR_QOS_INT_PRIORITY   -  invalid internal priority
+ *      RT_ERR_QOS_DSCP_VALUE    -   invalid DSCP value  
+ * Note:
+ *      switch support 16 kinds of dscp code:
+ *          RTL8306_DSCP_EF          
+ *                 - DSCP for the Expedited forwarding PHB, 101110   
+ *          RTL8306_DSCP_AFL1         
+ *                 - DSCP for AF PHB Class 1 low drop, 001010
+ *          RTL8306_DSCP_AFM1     
+ *                 - DSCP for AF PHB Class 1 medium drop, 001100
+ *          RTL8306_DSCP_AFH1      
+ *                 - DSCP for AF PHB Class 1 high drop, 001110
+ *          RTL8306_DSCP_AFL2       
+ *                 - DSCP for AF PHB Class 2 low drop, 01001
+ *          RTL8306_DSCP_AFM2       
+ *                 - DSCP for AF PHB Class 2 medium drop, 010100
+ *          RTL8306_DSCP_AFH2   
+ *                 - DSCP for AF PHB Class 2 high drop, 010110
+ *          RTL8306_DSCP_AFL3    
+ *                 - DSCP for AF PHB Class 3 low drop, 011010
+ *          RTL8306_DSCP_AFM3      
+ *                 - DSCP for AF PHB Class 3 medium drop, 011100
+ *          RTL8306_DSCP_AFH3    
+ *                 - DSCP for AF PHB Class 3 high drop, 0111
+ *          RTL8306_DSCP_AFL4     
+ *                 - DSCP for AF PHB Class 4 low drop, 100010
+ *          RTL8306_DSCP_AFM4    
+ *                 - DSCP for AF PHB Class 4 medium drop, 100100
+ *          RTL8306_DSCP_AFH4     
+ *                 - DSCP for AF PHB Class 4 high drop, 100110
+ *          RTL8306_DSCP_NC        
+ *                 - DSCP for network control, 110000 or 111000
+ *          RTL8306_DSCP_REG_PRI 
+ *                 - DSCP Register match priority, user could define two dscp code
+ *          RTL8306_DSCP_BF        
+ *                 - DSCP Default PHB
+ *
+ *     The Differentiated Service Code Point is a selector for router's per-hop behaviors. As a selector, there is no implication that a numerically 
+ *     greater DSCP implies a better network service. As can be seen, the DSCP totally overlaps the old precedence field of TOS. So if values of 
+ *     DSCP are carefully chosen then backward compatibility can be achieved.         
+ */ 
+rtk_api_ret_t rtk_qos_dscpPriRemap_set(rtk_dscp_t dscp, rtk_pri_t int_pri)
+{
+    rtk_api_ret_t retVal;
+
+    if (int_pri > RTL8306_PRIO3 )
+        return RT_ERR_QOS_INT_PRIORITY; 
+
+    if (dscp > RTL8306_DSCP_BF)
+        return RT_ERR_QOS_DSCP_VALUE; 
+
+    if((retVal = rtl8306e_qos_dscpPriRemap_set(dscp, int_pri)) != SUCCESS)
+        return RT_ERR_FAILED;
+    
+    return RT_ERR_OK;    
+}
+
+
+/* Function Name:
+ *      rtk_qos_dscpPriRemap_get
+ * Description:
+ *      Get DSCP-based priority
+ * Input:
+ *      dscp      -  dscp code
+ * Output:
+ *      pInt_pri  -  the pointer of internal priority value
+ * Return:
+ *      RT_ERR_OK                           -  Success
+ *      RT_ERR_FAILED                     -  Failure
+ *      RT_ERR_QOS_DSCP_VALUE      -  Invalid DSCP value
+ *      RT_ERR_NULL_POINTER           -  Input parameter is null pointer
+ * Note:
+ *      switch support 16 kinds of dscp code:
+ *          RTL8306_DSCP_EF          
+ *                 - DSCP for the Expedited forwarding PHB, 101110   
+ *          RTL8306_DSCP_AFL1         
+ *                 - DSCP for AF PHB Class 1 low drop, 001010
+ *          RTL8306_DSCP_AFM1     
+ *                 - DSCP for AF PHB Class 1 medium drop, 001100
+ *          RTL8306_DSCP_AFH1      
+ *                 - DSCP for AF PHB Class 1 high drop, 001110
+ *          RTL8306_DSCP_AFL2       
+ *                 - DSCP for AF PHB Class 2 low drop, 01001
+ *          RTL8306_DSCP_AFM2       
+ *                 - DSCP for AF PHB Class 2 medium drop, 010100
+ *          RTL8306_DSCP_AFH2   
+ *                 - DSCP for AF PHB Class 2 high drop, 010110
+ *          RTL8306_DSCP_AFL3    
+ *                 - DSCP for AF PHB Class 3 low drop, 011010
+ *          RTL8306_DSCP_AFM3      
+ *                 - DSCP for AF PHB Class 3 medium drop, 011100
+ *          RTL8306_DSCP_AFH3    
+ *                 - DSCP for AF PHB Class 3 high drop, 0111
+ *          RTL8306_DSCP_AFL4     
+ *                 - DSCP for AF PHB Class 4 low drop, 100010
+ *          RTL8306_DSCP_AFM4    
+ *                 - DSCP for AF PHB Class 4 medium drop, 100100
+ *          RTL8306_DSCP_AFH4     
+ *                 - DSCP for AF PHB Class 4 high drop, 100110
+ *          RTL8306_DSCP_NC        
+ *                 - DSCP for network control, 110000 or 111000
+ *          RTL8306_DSCP_REG_PRI 
+ *                 - DSCP Register match priority, user could define two dscp code
+ *          RTL8306_DSCP_BF        
+ *                 - DSCP Default PHB
+ *     The Differentiated Service Code Point is a selector for router's per-hop behaviors. As a selector, there is no implication that a numerically 
+ *     greater DSCP implies a better network service. As can be seen, the DSCP totally overlaps the old precedence field of TOS. So if values of 
+ *     DSCP are carefully chosen then backward compatibility can be achieved.         
+ */ 
+rtk_api_ret_t rtk_qos_dscpPriRemap_get(rtk_dscp_t dscp, rtk_pri_t *pInt_pri)
+{
+    rtk_api_ret_t retVal;
+    
+    if (dscp > RTL8306_DSCP_BF)
+        return RT_ERR_QOS_DSCP_VALUE; 
+    
+    if(NULL == pInt_pri)
+        return RT_ERR_NULL_POINTER;
+
+    if((retVal = rtl8306e_qos_dscpPriRemap_get(dscp, pInt_pri)) != SUCCESS)
+        return RT_ERR_FAILED;
+    
+
+    return RT_ERR_OK;
+}
+
+
+/* Function Name:
+ *      rtk_qos_portPri_set
+ * Description:
+ *      Configure priority usage to each port
+ * Input:
+ *      port                - Port id.                
+ *      int_pri             -  internal priority value
+ * Output:
+ *      none
+ * Return:
+ *      RT_ERR_OK                        -  Success
+ *      RT_ERR_FAILED                  -   Failure
+ *      RT_ERR_PORT_ID                -   Error port id
+ *      RT_ERR_QOS_INT_PRIORITY  -   Error internal priority value
+ * Note:
+ *     The API can set priority of port assignments for queue usage and packet scheduling.
+ */
+rtk_api_ret_t rtk_qos_portPri_set(rtk_port_t port, rtk_pri_t int_pri)
+{
+    rtk_api_ret_t retVal;
+    
+    if(port > RTK_PORT_ID_MAX) 
+        return RT_ERR_PORT_ID;    
+
+    if (int_pri > RTL8306_PRIO3 )
+        return RT_ERR_QOS_INT_PRIORITY; 
+
+    if((retVal = rtl8306e_qos_portPri_set(port, int_pri)) != SUCCESS)
+        return retVal;
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_qos_portPri_get
+ * Description:
+ *      Get priority usage to each port
+ * Input:
+ *      port                  - Port id.                
+ * Output:
+ *      pInt_pri             -  the pointer of internal priority value
+ * Return:
+ *      RT_ERR_OK                        -  Success
+ *      RT_ERR_FAILED                  -   Failure
+ *      RT_ERR_PORT_ID                -   Error port id
+ *      RT_ERR_NULL_POINTER        -   null pointer
+ * Note:
+ *      The API can get priority of port assignments for queue usage and packet scheduling.
+ */
+
+rtk_api_ret_t rtk_qos_portPri_get(rtk_port_t port, rtk_pri_t *pInt_pri)
+{
+    rtk_api_ret_t retVal;
+    
+    if(port > RTK_PORT_ID_MAX) 
+        return RT_ERR_PORT_ID;        
+    
+    if(NULL == pInt_pri)
+        return RT_ERR_NULL_POINTER;
+    
+    if((retVal = rtl8306e_qos_portPri_get(port, pInt_pri)) != SUCCESS)
+        return retVal;
+
+    return RT_ERR_OK;
+
+}
+
+/* Function Name:
+ *      rtk_qos_priMap_set
+ * Description:
+ *      Set internal priority mapping to queue ID for different queue number
+ * Input:
+ *      queue_num       - Queue number usage
+ *      pPri2qid            - Priority mapping to queue ID               
+ * Output:
+ *      none
+ * Return:
+ *      RT_ERR_OK                        -  Success
+ *      RT_ERR_FAILED                  -   Failure
+ *      RT_ERR_QUEUE_ID              -   Error queue id
+ *      RT_ERR_NULL_POINTER        -   null pointer
+ * Note:
+ *      ASIC supports priority mapping to queue with different queue number from 1 to 4.
+ *      For different queue numbers usage, ASIC supports different internal available queue IDs.
+ */
+
+rtk_api_ret_t rtk_qos_priMap_set(rtk_queue_num_t queue_num, rtk_qos_pri2queue_t *pPri2qid)
+{
+    rtk_api_ret_t retVal;
+    uint32 pri;
+
+    if((queue_num > 4) || (queue_num == 0))
+        return RT_ERR_QUEUE_NUM;           
+    
+    if(NULL == pPri2qid)
+        return RT_ERR_NULL_POINTER;
+
+    if((retVal = rtl8306e_qos_queueNum_set(queue_num)) != SUCCESS)
+        return RT_ERR_FAILED;
+
+    for(pri = RTL8306_PRIO0; pri <= RTL8306_PRIO3; pri++)
+    {
+        if(pPri2qid->pri2queue[pri] > (queue_num -1)) 
+            return RT_ERR_QUEUE_ID;
+        if((retVal = rtl8306e_qos_priToQueMap_set(pri, pPri2qid->pri2queue[pri])) != SUCCESS)
+            return RT_ERR_FAILED;
+    }
+            
+    return RT_ERR_OK;
+}
+
+
+/* Function Name:
+ *      rtk_qos_priMap_get
+ * Description:
+ *      Get priority to queue ID mapping table parameters
+ * Input:
+ *      queue_num       - Queue number usage
+ *      pPri2qid            - Priority mapping to queue ID               
+ * Output:
+ *      none
+ * Return:
+ *      RT_ERR_OK                        -  Success
+ *      RT_ERR_FAILED                  -   Failure
+ *      RT_ERR_QUEUE_ID              -   Error queue id
+ *      RT_ERR_NULL_POINTER        -   null pointer
+ * Note:
+ *      ASIC supports priority mapping to queue with different queue number from 1 to 4.
+ *      For different queue numbers usage, ASIC supports different internal available queue IDs.
+ */
+ 
+rtk_api_ret_t rtk_qos_priMap_get(rtk_queue_num_t queue_num, rtk_qos_pri2queue_t *pPri2qid)
+{
+    rtk_api_ret_t retVal;
+    uint32 pri;        
+
+    if((queue_num > 4) || (queue_num == 0))
+        return RT_ERR_QUEUE_NUM;           
+    
+    if(NULL == pPri2qid)
+        return RT_ERR_NULL_POINTER;
+
+    for(pri = RTL8306_PRIO0; pri <= RTL8306_PRIO3; pri++)
+    {
+        if((retVal = rtl8306e_qos_priToQueMap_get(pri, &(pPri2qid->pri2queue[pri]))) != SUCCESS)
+            return RT_ERR_FAILED;
+    }
+        
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_qos_1pRemarkEnable_set
+ * Description:
+ *      Set 802.1P remarking ability
+ * Input:
+ *      port       -  port number (0~5)
+ *      enabled  -  TRUE or FALSE
+ * Output:
+ *      none
+ * Return:
+ *      RT_ERR_OK              -  Success
+ *      RT_ERR_FAILED        -   Failure
+ *      RT_ERR_PORT_ID      -   Invalid port id
+ * Note:
+ *      
+ */
+rtk_api_ret_t rtk_qos_1pRemarkEnable_set(rtk_port_t port, rtk_enable_t enable)
+{
+    rtk_api_ret_t retVal;
+    
+    if(port > RTK_PORT_ID_MAX) 
+        return RT_ERR_PORT_ID;        
+
+    if((retVal = rtl8306e_qos_1pRemarkEnable_set(port, enable)) != SUCCESS)
+        return RT_ERR_FAILED;
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_qos_1pRemarkEnable_get
+ * Description:
+ *      Get 802.1P remarking ability
+ * Input:
+ *      port        -  port number (0~5)
+ * Output:
+ *      pEnabled  -  pointer of the ability status
+ * Return:
+ *      RT_ERR_OK                     -  Success
+ *      RT_ERR_FAILED               -   Failure
+ *      RT_ERR_PORT_ID             -   Invalid port id
+ *      RT_ERR_NULL_POINTER     -   Input parameter is null pointer
+ * Note:
+ *      
+ */
+rtk_api_ret_t rtk_qos_1pRemarkEnable_get(rtk_port_t port, rtk_enable_t *pEnable)
+{
+    rtk_api_ret_t retVal;
+    
+    if(port > RTK_PORT_ID_MAX) 
+        return RT_ERR_PORT_ID;        
+    if(NULL == pEnable)
+        return RT_ERR_NULL_POINTER;
+    if((retVal = rtl8306e_qos_1pRemarkEnable_get(port, (uint32 *)pEnable)) != SUCCESS)
+        return RT_ERR_FAILED;    
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_qos_1pRemark_set
+ * Description:
+ *      Set 802.1P remarking priority
+ * Input:
+ *      int_pri        -  Packet priority(0~4)
+ *      dot1p_pri    -  802.1P priority(0~7)
+ * Output:
+ *      none
+ * Return:
+ *      RT_ERR_OK                           - Success
+ *      RT_ERR_FAILED                      - Failure
+ *      RT_ERR_VLAN_PRIORITY          - Invalid 1p priority
+ *      RT_ERR_QOS_INT_PRIORITY     - Invalid internal priority 
+ * Note:
+ *      switch determines packet priority, the priority souce could
+ *      be port-based, 1Q-based, dscp-based, vid-based, ip address,
+ *      cpu tag.
+ */
+rtk_api_ret_t rtk_qos_1pRemark_set(rtk_pri_t int_pri, rtk_pri_t dot1p_pri)
+{
+    rtk_api_ret_t retVal;
+
+    if (int_pri > RTL8306_PRIO3 )
+        return RT_ERR_QOS_INT_PRIORITY; 
+
+    if (dot1p_pri > RTL8306_1QTAG_PRIO7)
+        return RT_ERR_VLAN_PRIORITY; 
+
+    if((retVal = rtl8306e_qos_1pRemark_set(int_pri, dot1p_pri)) != SUCCESS)
+        return RT_ERR_FAILED;
+    
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_qos_1pRemark_get
+ * Description:
+ *      Get 802.1P remarking priority
+ * Input:
+ *      int_pri        -  Packet priority(0~4)
+ * Output:
+ *      pDot1p_pri  -  the pointer of 802.1P priority(0~7)
+ * Return:
+ *      RT_ERR_OK                           -  Success
+ *      RT_ERR_FAILED                      -  Failure
+ *      RT_ERR_NULL_POINTER            -  Input parameter is null pointer
+ *      RT_ERR_QOS_INT_PRIORITY     -  Invalid internal priority 
+ * Note:
+ *      switch determines packet priority, the priority souce could
+ *      be port-based, 1Q-based, dscp-based, vid-based, ip address,
+ *      cpu tag.
+ */
+rtk_api_ret_t rtk_qos_1pRemark_get(rtk_pri_t int_pri, rtk_pri_t *pDot1p_pri)
+{
+    rtk_api_ret_t retVal;
+    
+    if (int_pri > RTL8306_PRIO3)
+        return RT_ERR_QOS_INT_PRIORITY; 
+    if(NULL == pDot1p_pri)
+        return RT_ERR_NULL_POINTER;
+    
+    if((retVal = rtl8306e_qos_1pRemark_get(int_pri, pDot1p_pri)) != SUCCESS)
+        return RT_ERR_FAILED;
+    
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_trap_unknownMcastPktAction_set
+ * Description:
+ *      Set behavior of unknown multicast
+ * Input:
+ *      port                -   port id
+ *      type               -   unknown multicast packet type
+ *      mcast_action    -  unknown multicast action
+ * Output:
+ *      none
+ * Return:
+ *      RT_ERR_OK                      -  Success
+ *      RT_ERR_FAILED                -  Failure
+ *      RT_ERR_PORT_ID              -  Invalid port id    
+ *      RT_ERR_INPUT                 -  Invalid input parameter 
+ * Note:
+ *      When receives an unknown multicast packet, switch may trap, drop this packet
+ *      The unknown multicast packet type is as following:
+ *               - MCAST_IPV4
+ *               - MCAST_IPV6
+ *      The unknown multicast action is as following:
+ *               - MCAST_ACTION_FORWARD
+ *               - MCAST_ACTION_DROP
+ */
+rtk_api_ret_t rtk_trap_unknownMcastPktAction_set(rtk_port_t port, rtk_mcast_type_t type, rtk_trap_mcast_action_t mcast_action)
+{
+    rtk_api_ret_t retVal;
+
+    if(port > RTK_PORT_ID_MAX) 
+        return RT_ERR_PORT_ID;    
+
+    if(mcast_action > MCAST_ACTION_DROP)
+        return RT_ERR_INPUT;
+    
+    if((MCAST_L2 == type) || (type > MCAST_IPV6 ))
+        return RT_ERR_INPUT;
+
+    if(MCAST_IPV4 == type)
+    {
+        retVal = rtl8306e_trap_unknownIPMcastPktAction_set(RTL8306_IPV4_MULTICAST, 
+                   (MCAST_ACTION_FORWARD == mcast_action) ? RTL8306_ACT_PERMIT: RTL8306_ACT_DROP);
+        if(retVal != SUCCESS)
+            return RT_ERR_FAILED;
+    }
+    else if(MCAST_IPV6 == type)
+    {
+        retVal = rtl8306e_trap_unknownIPMcastPktAction_set(RTL8306_IPV6_MULTICAST, 
+                   (MCAST_ACTION_FORWARD == mcast_action) ? RTL8306_ACT_PERMIT: RTL8306_ACT_DROP);
+        if(retVal != SUCCESS)
+            return RT_ERR_FAILED;        
+    }
+           
+    return RT_ERR_OK;
+}
+
+
+/* Function Name:
+ *      rtk_trap_unknownMcastPktAction_get
+ * Description:
+ *      Get behavior of unknown multicast
+ * Input:
+ *      port                  -   port id
+ *      type                 -   unknown multicast packet type
+ * Output:
+ *      pMcast_action    -   the pointer of unknown multicast action
+ * Return:
+ *      RT_ERR_OK                      -  Success
+ *      RT_ERR_FAILED                -  Failure
+ *      RT_ERR_PORT_ID              -  Invalid port id    
+ *      RT_ERR_NULL_POINTER      -  Input parameter is null pointer
+ * Note:
+ *      When receives an unknown multicast packet, switch may trap, drop this packet.
+ *      The unknown multicast packet type is as following:
+ *               - MCAST_IPV4
+ *               - MCAST_IPV6
+ *      The unknown multicast action is as following:
+ *               - MCAST_ACTION_FORWARD
+ *               - MCAST_ACTION_DROP
+ */
+rtk_api_ret_t rtk_trap_unknownMcastPktAction_get(rtk_port_t port, rtk_mcast_type_t type, rtk_trap_mcast_action_t *pMcast_action)
+{
+    rtk_api_ret_t retVal;
+    uint32 action;
+
+    if(port > RTK_PORT_ID_MAX) 
+        return RT_ERR_PORT_ID;    
+
+    if((MCAST_L2 == type) || (type > MCAST_IPV6 ))
+        return RT_ERR_INPUT;
+    
+    if(NULL == pMcast_action)
+        return RT_ERR_NULL_POINTER;
+
+    if(MCAST_IPV4 == type)
+    {
+        retVal = rtl8306e_trap_unknownIPMcastPktAction_get(RTL8306_IPV4_MULTICAST, &action);
+        if(retVal != SUCCESS)
+            return RT_ERR_FAILED;
+        *pMcast_action = (action == RTL8306_ACT_PERMIT) ? MCAST_ACTION_FORWARD: MCAST_ACTION_DROP;                        
+    }
+    else if(MCAST_IPV6 == type)
+    {
+        retVal = rtl8306e_trap_unknownIPMcastPktAction_get(RTL8306_IPV6_MULTICAST, &action);
+        if(retVal != SUCCESS)
+            return RT_ERR_FAILED;
+        *pMcast_action = (action == RTL8306_ACT_PERMIT) ? MCAST_ACTION_FORWARD: MCAST_ACTION_DROP;                        
+    }
+    
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_trap_igmpCtrlPktAction_set
+ * Description:
+ *      Set IGMP/MLD trap function
+ * Input:
+ *      type                -   IGMP/MLD packet type
+ *      igmp_action      -   IGMP/MLD action
+ * Output:
+ *      none
+ * Return:
+ *      RT_ERR_OK                      -  Success
+ *      RT_ERR_FAILED                -  Failure
+ *      RT_ERR_INPUT                 -  Invalid input parameter
+ *      RT_ERR_NOT_ALLOWED     -  Actions not allowed by the function
+ * Note:
+ *      This API can set both IPv4 IGMP/IPv6 MLD with/without PPPoE header trapping function.
+ *      All 4 kinds of IGMP/MLD function can be set separately.
+ *      The IGMP/MLD packet type is as following:
+ *          - IGMP_IPV4
+ *          - IGMP_MLD
+ *          - IGMP_PPPOE_IPV4
+ *          - IGMP_PPPOE_MLD
+ *      The IGMP/MLD action is as following:
+ *          - IGMP_ACTION_FORWARD
+ *          - IGMP_ACTION_TRAP2CPU
+ */ 
+rtk_api_ret_t rtk_trap_igmpCtrlPktAction_set(rtk_igmp_type_t type, rtk_trap_igmp_action_t igmp_action)
+{
+    rtk_api_ret_t retVal;
+    uint32 igmp_type, action;
+
+    if(type > IGMP_PPPOE_MLD)
+        return RT_ERR_INPUT;
+    if(igmp_action > IGMP_ACTION_TRAP2CPU)
+        return RT_ERR_NOT_ALLOWED;
+    
+    igmp_type = RTL8306_IGMP;
+    if(IGMP_IPV4 == type)
+    {
+        igmp_type = RTL8306_IGMP;
+    }
+    else if(IGMP_MLD == type)
+    {
+        igmp_type = RTL8306_MLD;
+    }
+    else if((IGMP_PPPOE_IPV4 == type) || (IGMP_PPPOE_MLD == type))
+    {
+        igmp_type = RTL8306_PPPOE_IGMPMLD;
+    }
+    action = (igmp_action == IGMP_ACTION_FORWARD) ? RTL8306_ACT_PERMIT: RTL8306_ACT_TRAPCPU;        
+    retVal = rtl8306e_trap_igmpCtrlPktAction_set(igmp_type, action);    
+    if(retVal != SUCCESS)
+        return RT_ERR_FAILED;
+
+    return RT_ERR_OK;
+}
+
+
+/* Function Name:
+ *      rtk_trap_igmpCtrlPktAction_get
+ * Description:
+ *      Get IGMP/MLD trap function
+ * Input:
+ *      type                -   IGMP/MLD packet type
+ * Output:
+ *      pIgmp_action    -   the pointer of IGMP/MLD action
+ * Return:
+ *      RT_ERR_OK                      -  Success
+ *      RT_ERR_FAILED                -  Failure
+ *      RT_ERR_INPUT                 -  Invalid input parameter
+ *      RT_ERR_NULL_POINTER      -  Input parameter is null pointer
+ * Note:
+ *      This API can get both IPv4 IGMP/IPv6 MLD with/without PPPoE header trapping function.
+ *      All 4 kinds of IGMP/MLD function can be set seperately.
+ *      The IGMP/MLD packet type is as following:
+ *          - IGMP_IPV4
+ *          - IGMP_MLD
+ *          - IGMP_PPPOE_IPV4
+ *          - IGMP_PPPOE_MLD
+ *      The IGMP/MLD action is as following:
+ *          - IGMP_ACTION_FORWARD
+ *          - IGMP_ACTION_TRAP2CPU
+ */
+rtk_api_ret_t rtk_trap_igmpCtrlPktAction_get(rtk_igmp_type_t type, rtk_trap_igmp_action_t *pIgmp_action)
+{
+    rtk_api_ret_t retVal;
+    uint32 igmp_type, action;
+
+    if(type > IGMP_PPPOE_MLD)
+        return RT_ERR_INPUT;
+    
+    if(NULL == pIgmp_action)
+        return RT_ERR_NULL_POINTER;
+    
+    igmp_type = RTL8306_IGMP;
+    if(IGMP_IPV4 == type)
+    {
+        igmp_type = RTL8306_IGMP;    
+    }
+    else if(IGMP_MLD == type)
+    {
+        igmp_type = RTL8306_MLD;
+    }
+    else if((IGMP_PPPOE_IPV4 == type) || (IGMP_PPPOE_MLD == type))
+    {
+        igmp_type = RTL8306_PPPOE_IGMPMLD;
+    }
+    retVal = rtl8306e_trap_igmpCtrlPktAction_get(igmp_type, &action);
+    if(retVal != SUCCESS)
+        return RT_ERR_FAILED;
+    *pIgmp_action = (action == RTL8306_ACT_PERMIT) ? IGMP_ACTION_FORWARD: IGMP_ACTION_TRAP2CPU;
+    
+    return RT_ERR_OK;
+}
+
+
+/* Function Name:
+ *      rtk_vlan_init
+ * Description:
+ *      Initialize VLAN
+ * Input:
+ *      none
+ * Output:
+ *      none
+ * Return:
+ *      RT_ERR_OK                     -  Success
+ *      RT_ERR_FAILED                -  Failure
+ * Note:
+ *      VLAN is disabled by default. User has to call this API to enable VLAN before
+ *      using it. And It will set a default VLAN(vid 1) including all ports and set 
+ *      all ports PVID to the default VLAN.
+ */
+
+rtk_api_ret_t rtk_vlan_init(void)
+{
+    uint32 i;
+    uint32 port;
+
+
+    /*clear vlan table*/
+    for(i = 0; i < 16; i++)
+        rtl8306e_vlan_entry_set(i, 0, 0, 0);
+
+    /*set switch default configuration:
+      *enable tag aware, disable ingress filter,
+      *admit all packet*/
+    rtl8306e_vlan_tagAware_set(TRUE);     
+    rtl8306e_vlan_IgrFilterEnable_set(FALSE);  
+    for (port = 0; port < 6; port++)
+    {
+        rtl8306e_vlan_portAcceptFrameType_set(port, RTL8306E_ACCEPT_ALL);
+    }
+
+    /*add a default vlan 1 which contains all ports*/
+    rtl8306e_vlan_entry_set(0, 1, 0x3F, 0);
+    
+    /*set all ports' vid to vlan 1*/
+    for(port = 0; port < 6; port++)
+        rtl8306e_vlan_portPvidIndex_set(port, 0);
+
+    /*set vlan enabled*/
+    rtl8306e_regbit_set(0, 18, 8, 0, 0);
+#ifdef RTL8306_TBLBAK
+    rtl8306_TblBak.vlanConfig.enVlan = TRUE; 
+#endif
+    /*disable trunk*/
+    rtl8306e_regbit_set(0, 19, 11, 0, 1);
+    
+    return RT_ERR_OK;
+   
+}
+
+/* Function Name:
+ *      rtk_vlan_set
+ * Description:
+ *      Set a VLAN entry
+ * Input:
+ *      vid              - VLAN ID to configure, should be 1~4094
+ *      mbrmsk        - VLAN member set portmask
+ *      untagmsk     - VLAN untag set portmask
+ *      fid              -  filtering database id, could be any value for RTL8306E
+ * Output:
+ *      none
+ * Return:
+ *      RT_ERR_OK                     -  Success
+ *      RT_ERR_FAILED                -  Failure
+ *      RT_ERR_VLAN_VID            -  Invalid vid
+ *      RT_ERR_INPUT                 -  Invalid input parameter 
+ *      RT_ERR_TBL_FULL            -  Input table full 
+ * Note:
+ *     There are 16 VLAN entry supported. User could configure the member set and untag set
+ *     for specified vid through this API. The portmask's bit N means port N.
+ *     For example, mbrmask 23=0x17=010111 means port 0,1,2,4 in the member set.
+ *     FID is for SVL/IVL usage, and the range is 0~4095, rtl8306E only supports SVL, 
+ *     so fid is no useage.
+ */
+rtk_api_ret_t rtk_vlan_set(rtk_vlan_t vid, rtk_portmask_t mbrmsk, rtk_portmask_t untagmsk, rtk_fid_t fid)
+{
+    uint32 vid_val, mbrmsk_val, untagmsk_val;
+    uint32 index, hit_index, hit_flag;
+    uint32 fullflag;
+    int32 i;
+
+    /* vid must be 1~4094 */
+    if ((vid == 0) || (vid > (RTL8306_VIDMAX - 1)))
+        return RT_ERR_VLAN_VID;
+
+    if (mbrmsk.bits[0] > RTL8306_MAX_PORTMASK)
+        return RT_ERR_INPUT;
+
+    if (untagmsk.bits[0] > RTL8306_MAX_PORTMASK)
+        return RT_ERR_INPUT;
+
+
+    /*check if vid exists and check if vlan is full*/
+    fullflag = TRUE;
+    hit_flag = FALSE;
+    index = 16;
+    hit_index= 16;
+    for(i = 15; i >= 0; i--)
+    {
+        rtl8306e_vlan_entry_get((uint32)i, &vid_val, &mbrmsk_val, &untagmsk_val);
+        if (0 == vid_val) 
+        {
+            index = (uint32)i; 
+            fullflag = FALSE;
+            continue;
+        }
+        
+        if (vid_val == vid)
+        {
+            hit_flag = TRUE;
+            hit_index = (uint32)i;
+            fullflag = FALSE;
+            break;
+        }            
+    }        
+    
+    if (fullflag)       
+        return RT_ERR_TBL_FULL;
+    else 
+    {
+        vid_val           = (uint32)vid;
+        mbrmsk_val     = mbrmsk.bits[0];
+        untagmsk_val  = untagmsk.bits[0];
+
+        /*both mbrmsk_val and untagmsk_val are zero will clear the vlan*/
+        if( (0 == mbrmsk_val) && (0 == untagmsk_val))
+            vid_val = 0;
+            
+        if (hit_flag)
+            rtl8306e_vlan_entry_set(hit_index, vid_val, mbrmsk_val, untagmsk_val);            
+        else
+            rtl8306e_vlan_entry_set(index, vid_val, mbrmsk_val, untagmsk_val);            
+    }
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_vlan_get
+ * Description:
+ *      Get a VLAN entry
+ * Input:
+ *      vid             - VLAN ID to configure
+ * Output:
+ *      pMbrmsk     - VLAN member set portmask
+ *      pUntagmsk  - VLAN untag set portmask
+ *      pFid           -  filtering database id
+ * Return:
+ *      RT_ERR_OK                                   -  Success
+ *      RT_ERR_FAILED                              -  Failure
+ *      RT_ERR_VLAN_VID                          -  Invalid vid
+ *      RT_ERR_NULL_POINTER                    -  Input parameter is null pointer
+ *      RT_ERR_VLAN_ENTRY_NOT_FOUND    -   Specified vlan entry not found
+ * Note:
+ *     There are 16 VLAN entry supported. User could configure the member set and untag set
+ *     for specified vid through this API. The portmask's bit N means port N.
+ *     For example, mbrmask 23=0x17=010111 means port 0,1,2,4 in the member set.
+ *     FID is for SVL/IVL usage, and the range is 0~4095, rtl8306E only supports SVL, 
+ *     so fid is no useage.
+ */
+ 
+rtk_api_ret_t rtk_vlan_get(rtk_vlan_t vid, rtk_portmask_t *pMbrmsk, rtk_portmask_t *pUntagmsk, rtk_fid_t *pFid)
+{
+    uint32 vid_val, mbrmsk_val, untagmsk_val;
+    uint32 hit_flag;
+    int32 i;
+
+    /* vid must be 1~4094 */
+    if ((vid == 0) || (vid > (RTL8306_VIDMAX - 1)))
+        return RT_ERR_VLAN_VID;
+
+    if ((NULL == pMbrmsk) || (NULL == pUntagmsk))
+        return RT_ERR_NULL_POINTER;
+
+    /*seach the vlan table*/
+    hit_flag = FALSE;
+    for (i = 15; i >= 0; i--)
+    {
+        rtl8306e_vlan_entry_get((rtk_vlan_t)i, &vid_val, &mbrmsk_val, &untagmsk_val);
+        if(vid_val == vid)
+        {
+            hit_flag = TRUE;
+            pMbrmsk->bits[0]    = mbrmsk_val;
+            pUntagmsk->bits[0] = untagmsk_val;         
+            *pFid = 0;
+            return RT_ERR_OK;
+        }
+    }
+
+    if(!hit_flag)
+        return RT_ERR_VLAN_ENTRY_NOT_FOUND;
+        
+    return RT_ERR_OK;
+}
+
+
+/* Function Name:
+ *      rtk_vlan_destroy
+ * Description:
+ *      delete vid from vlan table
+ * Input:
+ *      vid             - VLAN ID to configure
+ * Output:
+ *      none
+ * Return:
+ *      RT_ERR_OK                                   -  Success
+ *      RT_ERR_FAILED                              -  Failure
+ *      RT_ERR_VLAN_VID                          -  Invalid vid
+ *      RT_ERR_VLAN_ENTRY_NOT_FOUND    -  Specified vlan entry not found
+ * Note:
+ * 
+ */
+rtk_api_ret_t rtk_vlan_destroy(rtk_vlan_t vid)
+{
+    uint32 vid_val, mbrmsk_val, untagmsk_val;
+    uint32 hit_flag;
+    int32 i;
+    
+    /* vid must be 1~4094 */
+    if ((vid == 0) || (vid > (RTL8306_VIDMAX - 1)))
+        return RT_ERR_VLAN_VID;
+
+    hit_flag = FALSE;
+    for (i = 15; i >= 0; i--)
+    {
+        rtl8306e_vlan_entry_get((uint32)i, &vid_val, &mbrmsk_val, &untagmsk_val);
+        if(vid_val == vid)
+        {
+            hit_flag = TRUE;
+            vid_val = 0;
+            mbrmsk_val = 0;
+            untagmsk_val = 0;
+            rtl8306e_vlan_entry_set((uint32)i, vid_val, mbrmsk_val, untagmsk_val);
+            return RT_ERR_OK;
+        }        
+    }
+
+    if(!hit_flag)
+        return RT_ERR_VLAN_ENTRY_NOT_FOUND;    
+    else
+        return RT_ERR_OK;        
+
+}
+    
+
+/* Function Name:
+ *      rtk_vlan_portPvid_set
+ * Description:
+ *      Set port to specified VLAN ID(PVID)
+ * Input:
+ *      port             - Port id
+ *      pvid             - Specified VLAN ID
+ *      priority         - 802.1p priority for the PVID, 0~3 for RTL8306E 
+ * Output:
+ *      none
+ * Return:
+ *      RT_ERR_OK                                   -  Success
+ *      RT_ERR_FAILED                              -  Failure
+ *      RT_ERR_VLAN_VID                          -  Invalid vid
+ *      RT_ERR_VLAN_PRIORITY                  -  Invalid 1p priority 
+ *      RT_ERR_VLAN_ENTRY_NOT_FOUND    -  Specified vlan entry not found
+ * Note:
+ *      The API is used for Port-based VLAN. The untagged frame received from the
+ *      port will be classified to the specified VLAN and assigned to the specified priority.
+ */
+rtk_api_ret_t rtk_vlan_portPvid_set(rtk_port_t port, rtk_vlan_t pvid, rtk_pri_t priority)
+{
+    uint32 vid_val, mbrmsk_val, untagmsk_val;
+    uint32 hit_flag;
+    uint32 regVal;
+    int32 i;
+
+    if(port > RTK_PORT_ID_MAX) 
+        return RT_ERR_PORT_ID;    
+
+    if ((pvid == 0) || (pvid > (RTL8306_VIDMAX - 1)))
+        return RT_ERR_VLAN_VID;
+
+    if (priority > RTL8306_PRIO3)
+        return RT_ERR_VLAN_PRIORITY;
+
+    /*seach the vlan table*/
+    hit_flag = FALSE;
+    for (i = 15; i >= 0; i--)
+    {
+        rtl8306e_vlan_entry_get((uint32)i, &vid_val, &mbrmsk_val, &untagmsk_val);
+        if(vid_val == pvid)
+        {
+            hit_flag = TRUE;
+            rtl8306e_vlan_portPvidIndex_set(port, (uint32)i);
+            
+            /*802.1Q default priority for untag pkt*/
+            if (RTL8306_PORT5 == port)  
+                port ++ ;  
+            rtl8306e_reg_get(port, 17, 2, &regVal);
+            regVal = (regVal & 0x9FFF) | (priority << 13);
+            rtl8306e_reg_set(port, 17, 2, regVal);            
+            return RT_ERR_OK;
+        }
+    }
+
+    if (!hit_flag)
+        return RT_ERR_VLAN_ENTRY_NOT_FOUND;
+    
+    return RT_ERR_OK;
+}
+
+
+/* Function Name:
+ *      rtk_vlan_portPvid_get
+ * Description:
+ *      Get VLAN ID(PVID) on specified port
+ * Input:
+ *      port             - Port id
+ * Output:
+ *      pPvid            - Specified VLAN ID
+ *      pPriority        - 802.1p priority for the PVID
+ * Return:
+ *      RT_ERR_OK                                   - Success
+ *      RT_ERR_FAILED                             -  Failure
+ *      RT_ERR_PORT_ID                           -  Invalid port id
+ *      RT_ERR_NULL_POINTER                   -  Input parameter is null pointer
+ * Note:
+ *    The API is used for Port-based VLAN. The untagged frame received from the
+ *    port will be classified to the specified VLAN and assigned to the specified priority.
+ */
+
+rtk_api_ret_t rtk_vlan_portPvid_get(rtk_port_t port, rtk_vlan_t *pPvid, rtk_pri_t *pPriority)
+{
+    rtk_api_ret_t retVal;    
+    uint32 vid_val, mbrmsk_val, untagmsk_val;
+    uint32 index;
+    uint32 regVal;
+
+    if(port > RTK_PORT_ID_MAX) 
+        return RT_ERR_PORT_ID;    
+
+    if((NULL == pPvid) || (NULL == pPriority))
+        return RT_ERR_NULL_POINTER;
+
+    retVal = rtl8306e_vlan_portPvidIndex_get(port, &index);
+    if (retVal != SUCCESS)
+        return RT_ERR_FAILED;
+    
+    retVal = rtl8306e_vlan_entry_get(index, &vid_val, &mbrmsk_val, &untagmsk_val);    
+    if (retVal != SUCCESS)
+        return RT_ERR_FAILED;
+    *pPvid = vid_val;
+
+    /*get 802.1Q default priority for untag pkt*/
+    if (RTL8306_PORT5 == port)  
+        port ++ ;  
+    rtl8306e_reg_get(port, 17, 2, &regVal);
+    *pPriority = (regVal & 0x6000) >> 13;    
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_vlan_portIgrFilterEnable_set
+ * Description:
+ *      Set VLAN ingress for each port
+ * Input:
+ *      port             - Port id
+ *      igr_filter        - VLAN ingress function enable status
+ * Output:
+ *      none
+ * Return:
+ *      RT_ERR_OK                        - Success
+ *      RT_ERR_FAILED                  -  Failure
+ * Note:
+ *      RTL8306E use one ingress filter for whole system, not for each port, so 
+ *      any port you set will affect all ports ingress filter setting.
+ *      While VLAN function is enabled, ASIC will decide VLAN ID for each received frame 
+ *      and get belonged member ports from VLAN table. If received port is not belonged 
+ *      to VLAN member ports, ASIC will drop received frame if VLAN ingress function is enabled.
+ */
+rtk_api_ret_t rtk_vlan_portIgrFilterEnable_set(rtk_port_t port, rtk_enable_t igr_filter)
+{
+    rtk_api_ret_t retVal;    
+    
+    if(port > RTK_PORT_ID_MAX) 
+        return RT_ERR_PORT_ID;    
+
+    retVal = rtl8306e_vlan_IgrFilterEnable_set(igr_filter);
+    if (retVal != SUCCESS)
+        return RT_ERR_FAILED;
+            
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_vlan_portIgrFilterEnable_get
+ * Description:
+ *      get VLAN ingress for each port
+ * Input:
+ *      port             - Port id
+ * Output:
+ *      pIgr_filter     - the pointer of VLAN ingress function enable status
+ * Return:
+ *      RT_ERR_OK                 - Success
+ *      RT_ERR_FAILED           -  Failure
+ * Note:
+ *      RTL8306E use one ingress filter for whole system, not for each port, so 
+ *      any port you set will affect all ports ingress filter setting.
+ *      While VLAN function is enabled, ASIC will decide VLAN ID for each received frame 
+ *      and get belonged member ports from VLAN table. If received port is not belonged 
+ *      to VLAN member ports, ASIC will drop received frame if VLAN ingress function is enabled.
+ */
+rtk_api_ret_t rtk_vlan_portIgrFilterEnable_get(rtk_port_t port, rtk_enable_t *pIgr_filter)
+{
+    rtk_api_ret_t retVal;    
+    uint32 enabled;
+    
+    if(port > RTK_PORT_ID_MAX) 
+        return RT_ERR_PORT_ID;    
+    
+    if (NULL == pIgr_filter)
+        return RT_ERR_NULL_POINTER;
+
+    retVal = rtl8306e_vlan_IgrFilterEnable_get(&enabled);
+    if (retVal != SUCCESS)
+        return RT_ERR_FAILED;
+    *pIgr_filter = enabled ? ENABLED : DISABLED;
+        
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_vlan_portAcceptFrameType_set
+ * Description:
+ *      Set VLAN support frame type
+ * Input:
+ *      port                                 - Port id
+ *      accept_frame_type             - accept frame type
+ * Output:
+ *      none
+ * Return:
+ *      RT_ERR_OK                  - Success
+ *      RT_ERR_FAILED            -  Failure
+ *      RT_ERR_PORT_ID          -  Invalid port id
+ * Note:
+ *      The API is used for checking 802.1Q tagged frames.
+ *      The accept frame type as following:
+ *          - ACCEPT_FRAME_TYPE_ALL
+ *          - ACCEPT_FRAME_TYPE_TAG_ONLY
+ *          - ACCEPT_FRAME_TYPE_UNTAG_ONLY
+ */
+rtk_api_ret_t rtk_vlan_portAcceptFrameType_set(rtk_port_t port, rtk_vlan_acceptFrameType_t accept_frame_type)
+{
+    rtk_api_ret_t retVal;
+    rtl8306e_acceptFrameType_t accfrm_type;    
+
+    if ( port > RTK_PORT_ID_MAX)
+        return RT_ERR_PORT_ID;
+
+    switch (accept_frame_type)
+    {
+        case ACCEPT_FRAME_TYPE_ALL:
+            accfrm_type = RTL8306E_ACCEPT_ALL;
+            break;
+        case ACCEPT_FRAME_TYPE_TAG_ONLY:
+            accfrm_type = RTL8306E_ACCEPT_TAG_ONLY;
+            break;
+        case ACCEPT_FRAME_TYPE_UNTAG_ONLY:
+            accfrm_type = RTL8306E_ACCEPT_UNTAG_ONLY;
+            break;
+        default:
+            return RT_ERR_VLAN_ACCEPT_FRAME_TYPE;
+    }
+
+    retVal = rtl8306e_vlan_portAcceptFrameType_set(port, accfrm_type);
+    
+    return retVal;
+}
+
+/* Function Name:
+ *      rtk_vlan_portAcceptFrameType_get
+ * Description:
+ *      Get VLAN support frame type
+ * Input:
+ *      port                                 - Port id
+ *      accept_frame_type             - accept frame type
+ * Output:
+ *      none
+ * Return:
+ *      RT_ERR_OK                                   - Success
+ *      RT_ERR_FAILED                             -  Failure
+ *      RT_ERR_PORT_ID                           -  Invalid port id
+ *      RT_ERR_VLAN_ACCEPT_FRAME_TYPE -  Invalid accept frame type 
+ * Note:
+ *    The API is used for checking 802.1Q tagged frames.
+ *    The accept frame type as following:
+ *    - ACCEPT_FRAME_TYPE_ALL
+ *    - ACCEPT_FRAME_TYPE_TAG_ONLY
+ *    - ACCEPT_FRAME_TYPE_UNTAG_ONLY
+ */
+ 
+rtk_api_ret_t rtk_vlan_portAcceptFrameType_get(rtk_port_t port, rtk_vlan_acceptFrameType_t *pAccept_frame_type)
+{
+    rtk_api_ret_t retVal;
+    rtl8306e_acceptFrameType_t accfrm_type;    
+
+    if ( port > RTK_PORT_ID_MAX)
+        return RT_ERR_PORT_ID;
+
+    if (NULL == pAccept_frame_type)
+        return RT_ERR_NULL_POINTER;
+
+    retVal = rtl8306e_vlan_portAcceptFrameType_get(port, &accfrm_type);
+    switch(accfrm_type)
+    {
+        case RTL8306E_ACCEPT_ALL:
+            *pAccept_frame_type = ACCEPT_FRAME_TYPE_ALL;
+            break;
+        case RTL8306E_ACCEPT_TAG_ONLY:
+            *pAccept_frame_type = ACCEPT_FRAME_TYPE_TAG_ONLY;
+            break;
+        case RTL8306E_ACCEPT_UNTAG_ONLY:
+            *pAccept_frame_type = ACCEPT_FRAME_TYPE_UNTAG_ONLY;
+            break;
+        default:
+            return RT_ERR_VLAN_ACCEPT_FRAME_TYPE;
+    }
+
+    return retVal;
+}    
+
+
+/* Function Name:
+ *      rtk_vlan_vlanBasedPriority_set
+ * Description:
+ *      Set VLAN priority for each CVLAN
+ * Input:
+ *      vid                -Specified VLAN ID
+ *      priority           -priority for the VID
+ * Output:
+ *      none
+ * Return:
+ *      RT_ERR_OK                                -  Success
+ *      RT_ERR_FAILED                          -   Failure
+ *      RT_ERR_VLAN_VID                       -  Invalid vid 
+ *      RT_ERR_VLAN_PRIORITY               -  Invalid 1p priority
+ *      RT_ERR_VLAN_ENTRY_NOT_FOUND -  Specified vlan entry not found
+ * Note:
+ *      This API is used to set priority per VLAN.
+ */
+
+rtk_api_ret_t rtk_vlan_vlanBasedPriority_set(rtk_vlan_t vid, rtk_pri_t priority)
+{
+    uint32 vid_val, mbrmsk_val, untagmsk_val;
+    uint32 hit_flag;
+    int32 i;
+
+    /* vid must be 1~4094 */
+    if ((vid == 0) || (vid > (RTL8306_VIDMAX - 1)))
+        return RT_ERR_VLAN_VID;
+
+    if (priority > RTL8306_PRIO3)
+        return RT_ERR_VLAN_PRIORITY;    
+
+    /*seach the vlan table*/
+    hit_flag = FALSE;
+    for (i = 15; i >= 0; i--)
+    {
+        rtl8306e_vlan_entry_get((uint32)i, &vid_val, &mbrmsk_val, &untagmsk_val);
+        if(vid_val == vid)
+        {
+            hit_flag = TRUE;
+            rtl8306e_vlan_vlanBasedPriority_set((uint32)i, priority);            
+            return RT_ERR_OK;
+        }
+    }
+
+    if (!hit_flag)
+        return RT_ERR_VLAN_ENTRY_NOT_FOUND;
+        
+    return RT_ERR_OK;
+}
+
+
+/* Function Name:
+ *      rtk_vlan_vlanBasedPriority_get
+ * Description:
+ *      Get VLAN priority for each CVLAN
+ * Input:
+ *      vid                -Specified VLAN ID
+ * Output:
+ *      pPriority         -the pointer of priority for the VID
+ * Return:
+ *      RT_ERR_OK                                -  Success
+ *      RT_ERR_FAILED                          -   Failure
+ *      RT_ERR_VLAN_VID                       -  Invalid vid 
+ *      RT_ERR_NULL_POINTER                -   Input parameter is null pointer
+ *      RT_ERR_VLAN_ENTRY_NOT_FOUND -   Specified vlan entry not found 
+ * Note:
+ *      This API is used to set priority per VLAN.
+ */
+
+rtk_api_ret_t rtk_vlan_vlanBasedPriority_get(rtk_vlan_t vid, rtk_pri_t *pPriority)
+{
+    uint32 vid_val, mbrmsk_val, untagmsk_val;
+    uint32 hit_flag;
+    int32 i;
+
+    /* vid must be 1~4094 */
+    if ((vid == 0) || (vid > (RTL8306_VIDMAX - 1)))
+        return RT_ERR_VLAN_VID;
+
+    if (NULL == pPriority)
+        return RT_ERR_NULL_POINTER;
+
+    /*seach the vlan table*/
+    hit_flag = FALSE;
+    for (i = 15; i >= 0; i--)
+    {
+        rtl8306e_vlan_entry_get((uint32)i, &vid_val, &mbrmsk_val, &untagmsk_val);
+        if(vid_val == vid)
+        {
+            hit_flag = TRUE;
+            rtl8306e_vlan_vlanBasedPriority_get((uint32)i, pPriority);            
+            return RT_ERR_OK;
+        }
+    }
+
+    if (!hit_flag)
+        return RT_ERR_VLAN_ENTRY_NOT_FOUND;
+    
+    return RT_ERR_OK;
+}
+
+
+/* Function Name:
+ *      rtk_vlan_vidTranslation_set
+ * Description:
+ *      Set vid translated to new vid
+ * Input:
+ *      vid       -  old vid
+ *      nvid     -   new vid
+ * Output:
+ *      none
+ * Return:
+ *      RT_ERR_OK                                -  Success
+ *      RT_ERR_FAILED                          -   Failure
+ *      RT_ERR_VLAN_VID                       -  Invalid vid 
+ *      RT_ERR_VLAN_ENTRY_NOT_FOUND -   Specified vlan entry not found 
+ * Note:
+ *      This API is used to translate a vid to a new vid, the new vid could be 
+ *      used by Q-in-Q or vlan translation function.
+ */
+rtk_api_ret_t rtk_vlan_vidTranslation_set(rtk_vlan_t vid, rtk_vlan_t nvid)
+{
+    uint32 vid_val, mbrmsk_val, untagmsk_val;
+    uint32 hit_flag;
+    int32 i;
+    
+    if ((vid > RTL8306_VIDMAX ) || (nvid > RTL8306_VIDMAX ))
+        return RT_ERR_VLAN_VID;
+
+    hit_flag = FALSE;
+    for (i = 15; i >= 0; i--)
+    {
+        rtl8306e_vlan_entry_get((uint32)i, &vid_val, &mbrmsk_val, &untagmsk_val);
+        if(vid_val == vid)
+        {
+            hit_flag = TRUE;
+            rtl8306e_vlan_transVid_set((uint32)i, nvid);
+            return RT_ERR_OK;
+        }        
+    }
+
+    if(!hit_flag)
+        return RT_ERR_VLAN_ENTRY_NOT_FOUND;            
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_vlan_vidTranslation_get
+ * Description:
+ *      Get vid translation new vid
+ * Input:
+ *      vid        -  old vid
+ * Output:
+ *      pNvid     -  the pointer of new vid
+ * Return:
+ *      RT_ERR_OK                                -  Success
+ *      RT_ERR_FAILED                          -   Failure
+ *      RT_ERR_VLAN_VID                       -  Invalid vid 
+ *      RT_ERR_NULL_POINTER                -   NULL pointer
+ *      RT_ERR_VLAN_ENTRY_NOT_FOUND -   Specified vlan entry not found 
+ * Note:
+ *      This API is used to translate a vid to a new vid, the new vid could be 
+ *      used by Q-in-Q or vlan translation function.
+ */
+rtk_api_ret_t rtk_vlan_vidTranslation_get(rtk_vlan_t vid, rtk_vlan_t *pNvid)
+{
+
+    uint32 vid_val, mbrmsk_val, untagmsk_val;
+    uint32 hit_flag;
+    int32 i;
+
+    if (vid > RTL8306_VIDMAX )
+        return RT_ERR_VLAN_VID;
+    
+    if (NULL == pNvid)
+        return RT_ERR_NULL_POINTER;
+
+    hit_flag = FALSE;
+    for (i = 15; i >= 0; i--)
+    {
+        rtl8306e_vlan_entry_get((uint32)i, &vid_val, &mbrmsk_val, &untagmsk_val);
+        if(vid_val == vid)
+        {
+            hit_flag = TRUE;
+            rtl8306e_vlan_transVid_get((uint32)i, pNvid);
+            return RT_ERR_OK;
+        }        
+    }
+
+    if(!hit_flag)
+        return RT_ERR_VLAN_ENTRY_NOT_FOUND;            
+    
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_vlan_vidTranslationEnable_set
+ * Description:
+ *      Set vlan translation function enabled or disabled 
+ * Input:
+ *      enable        -  enable or disable
+ *      nniMask      -   NNI port mask
+ * Output:
+ *      pNvid     -  the pointer of new vid
+ * Return:
+ *      RT_ERR_OK                                -  Success
+ *      RT_ERR_FAILED                          -   Failure
+ *      RT_ERR_PORT_MASK                   -   Error port mask
+ * Note:
+ *      VLAN translation only happens between UNI and NNI port, 
+ *      in nniMask, 1 means the port is NNI port, 0 means the port
+ *      is UNI port
+ */
+rtk_api_ret_t rtk_vlan_vidTranslationEnable_set(rtk_enable_t enable, rtk_portmask_t nniMask)
+{
+    rtk_api_ret_t retVal;
+    uint32 port;
+    
+    if (nniMask.bits[0] > RTL8306_MAX_PORTMASK)
+        return RT_ERR_PORT_MASK; 
+
+    /*set default vid and priority src*/
+    if(enable)
+    {
+        for (port = 0; port < 6; port ++)
+            rtl8306e_svlan_otagSrc_set(port, RTL8306E_VIDSRC_NVID, RTL8306E_PRISRC_1PRMK);
+    }
+
+    retVal = rtl8306e_vlan_transEnable_set((uint32) enable, nniMask.bits[0]);
+    
+    return retVal;
+
+}
+
+
+/* Function Name:
+ *      rtk_vlan_vidTranslationEnable_get
+ * Description:
+ *      Get vlan translation function enabled or disabled 
+ * Input:
+ *      none
+ * Output:
+ *      pEnable      -   the pointer of enable or disable
+ *      pNniMask    -   the pointer of NNI port mask
+ * Return:
+ *      RT_ERR_OK                                -  Success
+ *      RT_ERR_FAILED                          -   Failure
+ *      RT_ERR_NULL_POINTER                -   NULL pointer
+ * Note:
+ *      VLAN translation only happens between UNI and NNI port, 
+ *      in nniMask, 1 means the port is NNI port, 0 means the port
+ *      is UNI port
+ */
+
+rtk_api_ret_t rtk_vlan_vidTranslationEnable_get(rtk_enable_t *pEnable, rtk_portmask_t *pNniMask)
+{
+    rtk_api_ret_t retVal;
+    uint32 enable, portmask;
+    
+    if((NULL == pEnable) || (NULL == pNniMask))
+        return RT_ERR_NULL_POINTER;
+
+    retVal = rtl8306e_vlan_transEnable_get(&enable, &portmask);
+    *pEnable = enable ? ENABLED : DISABLED;
+    pNniMask->bits[0] = portmask;
+
+    return retVal;
+
+}
+
+/* Function Name:
+ *      rtk_vlan_tagSrc_set
+ * Description:
+ *      Set tag vid and priority source for Q-in-Q and VLAN translation
+ * Input:
+ *      port          -    port id
+ *      vidSrc       -    vid source
+ *      priSrc        -    priority source
+ * Output:
+ *      none
+ * Return:
+ *      RT_ERR_OK                 -  Success
+ *      RT_ERR_FAILED            -   Failure
+ *      RT_ERR_PORT_ID          -   error port id
+ * Note:
+ *      Q-in-Q(SVLAN) and VLAN translation will modify tag, 
+ *      the API could set outer tag or translated VLAN tag
+ *      vid/priority source.
+ *      - vidSrc: 
+ *                - RTL8306E_VIDSRC_POVID - port-based otag vid,     
+ *                - RTL8306E_VIDSRC_NVID   - new vid(translated vid)
+ *       - priSrc:
+ *                - RTL8306E_PRISRC_PPRI    - port-based otag priority, 
+ *                - RTL8306E_PRISRC_1PRMK - 1p remarking priority
+ */
+rtk_api_ret_t rtk_vlan_tagSrc_set(rtk_port_t port, rtk_vidSrc_t vidSrc, rtk_priSrc_t priSrc)    
+{
+    rtk_api_ret_t retVal;
+
+    if(port > RTK_PORT_ID_MAX) 
+        return RT_ERR_PORT_ID;    
+
+    retVal = rtl8306e_svlan_otagSrc_set(port, vidSrc, priSrc);
+    
+    return retVal;
+}
+
+
+/* Function Name:
+ *      rtk_vlan_tagSrc_get
+ * Description:
+ *      Get tag vid and priority source for Q-in-Q and VLAN translation
+ * Input:
+ *      port          -    port id
+ * Output:
+ *      pVidSrc     -    the pointer of vid source
+ *      pPriSrc      -    the pointer of priority source
+ * Return:
+ *      RT_ERR_OK                 -  Success
+ *      RT_ERR_FAILED            -   Failure
+ *      RT_ERR_PORT_ID          -   error port id
+ * Note:
+ *      Q-in-Q(SVLAN) and VLAN translation will modify tag, 
+ *      the API could set outer tag or tranlated VLAN tag
+ *      vid/priority source.
+ *      vidSrc: 
+ *                RTL8306E_VIDSRC_POVID - port-based otag vid,     
+ *                RTL8306E_VIDSRC_NVID   - new vid(translated vid)
+ *       priSrc:
+ *                RTL8306E_PRISRC_PPRI    - port-based otag priority, 
+ *                RTL8306E_PRISRC_1PRMK - 1p remarking priority
+ */
+rtk_api_ret_t rtk_vlan_tagSrc_get(rtk_port_t port, rtk_vidSrc_t *pVidSrc, rtk_priSrc_t *pPriSrc)    
+{
+    rtk_api_ret_t retVal;
+    uint32 vidsrc, prisrc;
+
+    if(port > RTK_PORT_ID_MAX) 
+        return RT_ERR_PORT_ID;    
+    if((NULL == pVidSrc) || (NULL == pPriSrc))
+        return RT_ERR_NULL_POINTER;
+    
+    retVal = rtl8306e_svlan_otagSrc_get(port, &vidsrc, &prisrc);
+    *pVidSrc = (rtk_vidSrc_t)vidsrc;
+    *pPriSrc  = (rtk_priSrc_t)prisrc;
+    
+    return retVal;
+}
+
+
+/* Function Name:
+ *      rtk_stp_mstpState_set
+ * Description:
+ *      Configure spanning tree state per port
+ * Input:
+ *      msti              - Multiple spanning tree instance, no use for RTL8306E
+ *      port              - Port id
+ *      stp_state       - Spanning tree state
+ * Output:
+ *      none
+ * Return:
+ *      RT_ERR_OK                      -  Success
+ *      RT_ERR_FAILED                -  Failure
+ *      RT_ERR_PORT_ID              -  Invalid port id
+ *      RT_ERR_MSTP_STATE        -  Invalid spanning tree status
+ * Note:
+ *      Because RTL8306E does not support multiple spanning tree, so msti is no use. 
+ *      There are four states supported by ASIC.
+ *          - STP_STATE_DISABLED
+ *          - STP_STATE_BLOCKING
+ *          - STP_STATE_LEARNING
+ *          - STP_STATE_FORWARDING
+ */
+rtk_api_ret_t rtk_stp_mstpState_set(rtk_stp_msti_id_t msti, rtk_port_t port, rtk_stp_state_t stp_state)
+{
+    rtk_api_ret_t retVal;
+    
+    if(port > RTK_PORT_ID_MAX)
+        return RT_ERR_PORT_ID;
+    
+    if(stp_state >= STP_STATE_END)
+        return RT_ERR_MSTP_STATE;
+
+    retVal = rtl8306e_stp_set(port, stp_state);
+    return retVal;
+
+}    
+
+/* Function Name:
+ *      rtk_stp_mstpState_get
+ * Description:
+ *      Get Configuration of spanning tree state per port
+ * Input:
+ *      msti              - Multiple spanning tree instance, no use for RTL8306E
+ *      port              - Port id
+ * Output:
+ *      pStp_state     - the pointer of Spanning tree state
+ * Return:
+ *      RT_ERR_OK                      -  Success
+ *      RT_ERR_FAILED                -  Failure
+ *      RT_ERR_PORT_ID              -  Invalid port id
+ *      RT_ERR_NULL_POINTER      -  Input parameter is null pointer
+ * Note:
+ *      Because RTL8306E does not support multiple spanning tree, so msti is no use. 
+ *      There are four states supported by ASIC.
+ *          - STP_STATE_DISABLED
+ *          - STP_STATE_BLOCKING
+ *          - STP_STATE_LEARNING
+ *          - STP_STATE_FORWARDING
+ */
+rtk_api_ret_t rtk_stp_mstpState_get(rtk_stp_msti_id_t msti, rtk_port_t port, rtk_stp_state_t *pStp_state)
+{
+    rtk_api_ret_t retVal;
+    uint32 state;
+    
+    if(port > RTK_PORT_ID_MAX)
+        return RT_ERR_PORT_ID;
+    
+    if(NULL == pStp_state)
+        return RT_ERR_NULL_POINTER;
+
+    retVal = rtl8306e_stp_get(port, &state);
+    *pStp_state = (rtk_stp_state_t)state;
+
+    return retVal;
+}    
+
+/* Function Name:
+ *      rtk_l2_addr_add
+ * Description:
+ *      Set LUT unicast entry
+ * Input:
+ *      pMac               -   6 bytes unicast(I/G bit is 0) mac address to be written into LUT
+ *      pL2_data          -   the mac address attributes
+ * Output:
+ *      none
+ * Return:
+ *      RT_ERR_OK                       -  Success
+ *      RT_ERR_FAILED                 -   Failure
+ *      RT_ERR_INPUT                  -   Invalid input parameter
+ *      RT_ERR_MAC                    -   Wrong mac address, must be unicast mac        
+ *      RT_ERR_NULL_POINTER       -  Input parameter is null pointer    
+ *      RT_ERR_L2_INDEXTBL_FULL -  The L2 index table is full
+ * Note:
+ *      If the unicast mac address already existed in LUT, it will udpate the status of the entry. 
+ *      Otherwise, it will find an empty or asic auto learned entry to write. If all the entries 
+ *      with the same hash value can't be replaced, ASIC will return a RT_ERR_L2_INDEXTBL_FULL error.
+ *      for RTL8306E, pL2_data member fid and sa_block is no use, so it can be chosen any value.
+ */
+ 
+rtk_api_ret_t rtk_l2_addr_add(rtk_mac_t *pMac, rtk_l2_ucastAddr_t *pL2_data)
+{
+    rtk_api_ret_t retVal;
+    uint32 entryAddr;
+        
+    /* must be unicast address */
+    if((NULL == pMac) || (pMac->octet[0] & 0x1))
+        return RT_ERR_MAC;
+    
+    if(NULL == pL2_data)
+        return RT_ERR_NULL_POINTER;
+
+    if(pL2_data->port > RTK_PORT_ID_MAX)
+        return RT_ERR_PORT_ID;    
+
+    if(pL2_data->is_static >= RTK_ENABLE_END)
+        return RT_ERR_INPUT; 
+
+    if(pL2_data->auth >= RTK_ENABLE_END)
+        return RT_ERR_INPUT; 
+        
+    retVal = rtl8306e_l2_unicastMac_add(pMac->octet, RTL8306_LUT_AGE300, pL2_data->is_static, pL2_data->auth, pL2_data->port, &entryAddr);
+    if(RTL8306_LUT_FULL == retVal)
+        return RT_ERR_L2_INDEXTBL_FULL;
+    else if(retVal != SUCCESS)
+        return RT_ERR_FAILED;
+    
+    return RT_ERR_OK;
+}
+
+
+/* Function Name:
+ *      rtk_l2_addr_get
+ * Description:
+ *      Get LUT unicast entry
+ * Input:
+ *      pMac               -   6 bytes unicast(I/G bit is 0) mac address to be gotten
+ *      fid                   -   filtering database id, could be any value for RTL8306E switch
+ * Output:
+ *      pL2_data          -   the mac address attributes
+ * Return:
+ *      RT_ERR_OK                               -  Success
+ *      RT_ERR_FAILED                         -   Failure
+ *      RT_ERR_INPUT                          -   Invalid input parameter
+ *      RT_ERR_MAC                            -   Wrong mac address, must be unicast mac        
+ *      RT_ERR_NULL_POINTER              -   Input parameter is null pointer    
+ *      RT_ERR_L2_ENTRY_NOTFOUND    -   Specified entry not found
+ * Note:
+ *      If the unicast mac address existed in LUT, it will return the port where
+ *      the mac is learned, 802.1x authorized status and dynamic/static entry,
+ *      Otherwise, it will return a RT_ERR_L2_ENTRY_NOTFOUND error.
+ */
+
+rtk_api_ret_t rtk_l2_addr_get(rtk_mac_t *pMac, rtk_fid_t fid, rtk_l2_ucastAddr_t *pL2_data)
+{
+    rtk_api_ret_t retVal;
+    uint32 isStatic, isAuth, port, entryaddr;    
+
+    /* must be unicast address */
+    if((NULL == pMac) || (pMac->octet[0] & 0x1))
+        return RT_ERR_MAC;
+    
+    if(NULL == pL2_data)
+        return RT_ERR_NULL_POINTER;
+
+    pL2_data->auth = FALSE;    
+    pL2_data->fid = 1;
+    pL2_data->is_static = FALSE;
+    pL2_data->port = 0;
+    pL2_data->sa_block = FALSE;
+
+    retVal = rtl8306e_l2_mac_get(pMac->octet, &isStatic, &isAuth, &port, &entryaddr);
+    if(RTL8306_LUT_NOTEXIST == retVal)
+    {        
+        return RT_ERR_L2_ENTRY_NOTFOUND;        
+    }
+    else if(retVal != SUCCESS)
+    {
+        return RT_ERR_FAILED;
+    }
+
+    pL2_data->auth = isAuth;
+    pL2_data->port = port;
+    pL2_data->is_static = isStatic;
+    pL2_data->mac.octet[0] = pMac->octet[0];
+    pL2_data->mac.octet[1] = pMac->octet[1];
+    pL2_data->mac.octet[2] = pMac->octet[2];
+    pL2_data->mac.octet[3] = pMac->octet[3];
+    pL2_data->mac.octet[4] = pMac->octet[4];
+    pL2_data->mac.octet[5] = pMac->octet[5];    
+    
+    return RT_ERR_OK;
+    
+}
+
+
+/* Function Name:
+ *      rtk_l2_addr_del
+ * Description:
+ *      Delete LUT unicast entry
+ * Input:
+ *      pMac               -   6 bytes unicast mac address to be deleted
+ *      fid                   -   filtering database id, could be any value for RTL8306E switch
+ * Output:
+ *      none
+ * Return:
+ *      RT_ERR_OK                               -  Success
+ *      RT_ERR_FAILED                         -   Failure
+ *      RT_ERR_INPUT                          -   Invalid input parameter
+ *      RT_ERR_MAC                            -   Wrong mac address, must be unicast mac        
+ *      RT_ERR_NULL_POINTER              -   Input parameter is null pointer    
+ *      RT_ERR_L2_ENTRY_NOTFOUND    -   Specified entry not found 
+ * Note:
+ *      If the mac has existed in the LUT, it will be deleted.
+ *      Otherwise, it will return RT_ERR_L2_ENTRY_NOTFOUND.
+ */
+rtk_api_ret_t rtk_l2_addr_del(rtk_mac_t *pMac, rtk_fid_t fid)
+{
+    rtk_api_ret_t retVal;
+    uint32 entryAddr;
+
+    /* must be unicast address */
+    if((NULL == pMac) || (pMac->octet[0] & 0x1))
+        return RT_ERR_MAC;  
+
+    retVal = rtl8306e_l2_mac_del(pMac->octet, &entryAddr);
+    if(RTL8306_LUT_NOTEXIST == retVal)
+    {
+        return RT_ERR_L2_ENTRY_NOTFOUND;
+    }
+    else if(retVal != SUCCESS)
+    {
+        return RT_ERR_FAILED;
+    }
+
+    return RT_ERR_OK;
+}
+
+
+/* Function Name:
+ *      rtk_l2_mcastAddr_add
+ * Description:
+ *      Add LUT multicast entry
+ * Input:
+ *      pMac               -   6 bytes unicast mac address to be deleted
+ *      fid                   -   filtering database id, could be any value for RTL8306E switch
+ *      portmask          -   Port mask to be forwarded to 
+ * Output:
+ *      none
+ * Return:
+ *      RT_ERR_OK                               -  Success
+ *      RT_ERR_FAILED                         -   Failure
+ *      RT_ERR_INPUT                          -   Invalid input parameter
+ *      RT_ERR_PORT_MASK                  -   Invalid port mask
+ *      RT_ERR_MAC                            -   Wrong mac address, must be unicast mac        
+ *      RT_ERR_L2_INDEXTBL_FULL         -   Hashed index is full of entries
+ * Note:
+ *      If the multicast mac address already existed in the LUT, it will udpate the
+ *      port mask of the entry. Otherwise, it will find an empty or asic auto learned
+ *      entry to write. If all the entries with the same hash value can't be replaced, 
+ *      ASIC will return a RT_ERR_L2_INDEXTBL_FULL error.
+ */
+rtk_api_ret_t rtk_l2_mcastAddr_add(rtk_mac_t *pMac, rtk_fid_t fid, rtk_portmask_t portmask)
+{
+    rtk_api_ret_t retVal;
+    uint32 entryAddr;
+
+    /* must be L2 multicast address */
+    if((NULL == pMac) || (!(pMac->octet[0] & 0x1)))
+        return RT_ERR_MAC;
+
+    if(portmask.bits[0] > RTK_MAX_PORT_MASK)
+        return RT_ERR_PORT_MASK;    
+
+    retVal = rtl8306e_l2_multicastMac_add(pMac->octet, TRUE, portmask.bits[0], &entryAddr);
+    if(RTL8306_LUT_FULL == retVal)
+    {
+        return RT_ERR_L2_INDEXTBL_FULL;
+    }
+    else if(retVal != SUCCESS)
+    {
+        return RT_ERR_FAILED;
+    }
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_l2_mcastAddr_get
+ * Description:
+ *      Get LUT multicast entry
+ * Input:
+ *      pMac               -   6 bytes multicast(I/G bit is 0) mac address to be gotten
+ *      fid                   -   filtering database id, could be any value for RTL8306E switch
+ * Output:
+ *      pPortmask         -   the pointer of port mask      
+ * Return:
+ *      RT_ERR_OK                               -  Success
+ *      RT_ERR_FAILED                         -   Failure
+ *      RT_ERR_INPUT                          -   Invalid input parameter
+ *      RT_ERR_NULL_POINTER              -   Input parameter is null pointer    
+ *      RT_ERR_MAC                            -   Wrong mac address, must be unicast mac        
+ *      RT_ERR_L2_INDEXTBL_FULL         -   Hashed index is full of entries 
+ * Note:
+ *      If the multicast mac address existed in LUT, it will return the port mask where
+ *      the packet should be forwarded to, Otherwise, it will return a 
+ *      RT_ERR_L2_ENTRY_NOTFOUND error.
+ */
+
+rtk_api_ret_t rtk_l2_mcastAddr_get(rtk_mac_t *pMac, rtk_fid_t fid, rtk_portmask_t *pPortmask)
+{
+    rtk_api_ret_t retVal;
+    uint32 isStatic, isAuth, portmask, entryaddr;        
+
+    /* must be multicast address */
+    if((NULL == pMac) || !(pMac->octet[0] & 0x1))
+        return RT_ERR_MAC;  
+
+    
+    if(NULL == pPortmask)
+        return RT_ERR_NULL_POINTER;
+
+    retVal = rtl8306e_l2_mac_get(pMac->octet, &isStatic, &isAuth, &portmask, &entryaddr);
+    if(RTL8306_LUT_NOTEXIST == retVal)
+    {        
+        return RT_ERR_L2_ENTRY_NOTFOUND;        
+    }
+    else if(retVal != SUCCESS)
+    {
+        return RT_ERR_FAILED;
+    }
+
+    pPortmask->bits[0] = portmask;
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_l2_mcastAddr_del
+ * Description:
+ *      Delete LUT multicast entry
+ * Input:
+ *      pMac               -   6 bytes multicast(I/G bit is 1) mac address to be gotten
+ *      fid                   -   filtering database id, could be any value for RTL8306E switch
+ * Output:
+*       none
+ * Return:
+ *      RT_ERR_OK                               -  Success
+ *      RT_ERR_FAILED                         -   Failure
+ *      RT_ERR_INPUT                          -   Invalid input parameter
+ *      RT_ERR_MAC                            -   Wrong mac address, must be unicast mac        
+ *      RT_ERR_L2_ENTRY_NOTFOUND     -   No such LUT entry
+ * Note:
+ *      If the mac has existed in the LUT, it will be deleted.
+ *      Otherwise, it will return RT_ERR_L2_ENTRY_NOTFOUND.
+ */
+
+rtk_api_ret_t rtk_l2_mcastAddr_del(rtk_mac_t *pMac, rtk_fid_t fid)
+{
+    rtk_api_ret_t retVal;
+    uint32 entryAddr;
+
+    /* must be multicast address */
+    if((NULL == pMac) || !(pMac->octet[0] & 0x1))
+        return RT_ERR_MAC;  
+
+    retVal = rtl8306e_l2_mac_del(pMac->octet, &entryAddr);
+    if(RTL8306_LUT_NOTEXIST == retVal)
+    {
+        return RT_ERR_L2_ENTRY_NOTFOUND;
+    }
+    else if(retVal != SUCCESS)
+    {
+        return RT_ERR_FAILED;
+    }
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_l2_limitLearningCnt_set
+ * Description:
+ *      Set per-Port auto learning limit number
+ * Input:
+ *      port - Port id.
+ *      mac_cnt - Auto learning entries limit number
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK              - set shared meter successfully
+ *      RT_ERR_FAILED          - FAILED to iset shared meter
+ *      RT_ERR_PORT_ID - Invalid port number.
+ *      RT_ERR_LIMITED_L2ENTRY_NUM - Invalid auto learning limit number
+ * Note:
+ *      (1)The API can set per-port ASIC auto learning limit number from 0(disable learning) 
+ *      to 0x1F(31). 
+ *      (2)If mac_cnt is set from 0 to 0x1F, per-port ASIC auto learning limit will be enabled;
+ *      if mac_cnt is set 0xFF, per-port ASIC auto learning limit will be disabled.
+ */
+rtk_api_ret_t rtk_l2_limitLearningCnt_set(rtk_port_t port, rtk_mac_cnt_t mac_cnt)
+{
+    rtk_api_ret_t retVal;
+    uint32 enabled;
+    
+    if (port > RTK_PORT_ID_MAX)
+        return RT_ERR_PORT_ID;
+
+    if ((mac_cnt > RTK_MAX_NUM_OF_LEARN_LIMIT) && (0xFF != mac_cnt))
+        return RT_ERR_LIMITED_L2ENTRY_NUM;
+
+    enabled = (0xFF == mac_cnt ?  FALSE : TRUE);
+    if ((retVal = rtl8306e_l2_portMacLimit_set(port, enabled, mac_cnt)) != RT_ERR_OK)
+        return retVal; 
+    
+    return RT_ERR_OK;
+}    
+
+/* Function Name:
+ *      rtk_l2_limitLearningCnt_get
+ * Description:
+ *      Get per-Port auto learning limit number
+ * Input:
+ *      port - Port id.
+ * Output:
+ *      pMac_cnt - Auto learning entries limit number
+ * Return:
+ *      RT_ERR_OK              - Success
+ *      RT_ERR_FAILED          - Failure 
+ *      RT_ERR_PORT_ID - Invalid port number. 
+ * Note:
+ *      The API can get per-port ASIC auto learning limit number.
+ */
+rtk_api_ret_t rtk_l2_limitLearningCnt_get(rtk_port_t port, rtk_mac_cnt_t *pMac_cnt)
+{
+    rtk_api_ret_t retVal;
+    uint32 enabled;
+
+    if (port > RTK_PORT_ID_MAX)
+        return RT_ERR_PORT_ID;
+
+    if ((retVal = rtl8306e_l2_portMacLimit_get(port, &enabled, pMac_cnt)) != RT_ERR_OK)
+        return retVal;
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_l2_limitLearningCntAction_set
+ * Description:
+ *      Configure auto learn over limit number action.
+ * Input:
+ *      port - Port id (must be RTK_WHOLE_SYSTEM)
+ *      action - Auto learning entries limit number
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK              - Success
+ *      RT_ERR_FAILED          - Failure 
+ *      RT_ERR_PORT_ID - Invalid port number.
+ *      RT_ERR_NOT_ALLOWED - Invalid learn over action
+ * Note:
+ *      (1)The API can set SA unknown packet action while auto learn limit number is over. 
+ *      The action symbol as following:
+ *      - LIMIT_LEARN_CNT_ACTION_DROP,
+ *      - LIMIT_LEARN_CNT_ACTION_TO_CPU,
+ *      (2)The action is global, so the port must be set as RTK_WHOLE_SYSTEM
+ */
+rtk_api_ret_t rtk_l2_limitLearningCntAction_set(rtk_port_t port, rtk_l2_limitLearnCntAction_t action)
+{
+    rtk_api_ret_t retVal;
+    uint32 data;
+    
+    if (port != RTK_WHOLE_SYSTEM)
+        return RT_ERR_PORT_ID;    
+    
+    if ( LIMIT_LEARN_CNT_ACTION_DROP == action )
+        data = RTL8306_ACT_DROP;
+    else if ( LIMIT_LEARN_CNT_ACTION_TO_CPU == action )
+        data = RTL8306_ACT_TRAPCPU;
+    else
+        return RT_ERR_NOT_ALLOWED;    
+
+    
+    if ((retVal = rtl8306e_l2_macLimitAction_set(data)) != RT_ERR_OK)
+        return retVal; 
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_l2_limitLearningCntAction_get
+ * Description:
+ *      Get auto learn over limit number action.
+ * Input:
+ *      port - Port id (must be RTK_WHOLE_SYSTEM)
+ * Output:
+ *      pAction - Learn over action
+ * Return:
+ *      RT_ERR_OK              - Success
+ *      RT_ERR_FAILED          - Failure 
+ *      RT_ERR_PORT_ID - Invalid port number. 
+ * Note:
+ *      (1)The API can get SA unknown packet action while auto learn limit number is over. 
+ *      The action symbol as following:
+ *      - LIMIT_LEARN_CNT_ACTION_DROP,
+ *      - LIMIT_LEARN_CNT_ACTION_TO_CPU,
+ *      (2)The action is global, so the port must be set as RTK_WHOLE_SYSTEM
+ */
+rtk_api_ret_t rtk_l2_limitLearningCntAction_get(rtk_port_t port, rtk_l2_limitLearnCntAction_t *pAction)
+{
+    rtk_api_ret_t retVal;
+    uint32 action;
+    
+    if (port != RTK_WHOLE_SYSTEM)
+        return RT_ERR_PORT_ID;    
+    
+    if ((retVal = rtl8306e_l2_macLimitAction_get(&action)) != RT_ERR_OK)
+        return retVal; 
+
+    if (RTL8306_ACT_DROP == action)
+        *pAction = LIMIT_LEARN_CNT_ACTION_DROP;
+    else if (RTL8306_ACT_TRAPCPU == action)
+        *pAction = LIMIT_LEARN_CNT_ACTION_TO_CPU;
+    else
+        return RT_ERR_FAILED; 
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_l2_learningCnt_get
+ * Description:
+ *      Get per-Port current auto learning number
+ * Input:
+ *      port - Port id.
+ * Output:
+ *      pMac_cnt - ASIC auto learning entries number
+ * Return:
+ *      RT_ERR_OK              - Success
+ *      RT_ERR_PORT_ID - Invalid port number. 
+ *      RT_ERR_NULL_POINTER   -   Input parameter is null pointer  
+ * Note:
+ *      The API can get per-port ASIC auto learning number
+ */
+rtk_api_ret_t rtk_l2_learningCnt_get(rtk_port_t port, rtk_mac_cnt_t *pMac_cnt)
+{
+    uint32 regVal;
+    
+    if (port > RTK_PORT_ID_MAX)
+        return RT_ERR_PORT_ID;
+    
+    if (NULL == pMac_cnt)
+        return RT_ERR_NULL_POINTER;
+    
+    if (5 == port)
+        port ++;
+
+    if (0 == port)
+    {
+        rtl8306e_reg_get(0, 27, 3, &regVal);
+        *pMac_cnt = (regVal & 0x7FF) ;
+    }
+    else
+    {
+        rtl8306e_reg_get(port, 31, 1, &regVal);
+        *pMac_cnt = (regVal & 0x7FF) ;
+    }
+ 
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_cpu_enable_set
+ * Description:
+ *      Set cpu port function enable or disable
+ * Input:
+ *      enable          - enable or disable
+ * Output:
+ *      none
+ * Return:
+ *      RT_ERR_OK                        -  Success
+ *      RT_ERR_FAILED                  -   Failure
+ * Note:
+ *      The API can set CPU port function enable/disable
+ *      default port 4 is cpu port.
+ */
+rtk_api_ret_t rtk_cpu_enable_set(rtk_enable_t enable)
+{
+    rtk_api_ret_t retVal;
+
+    if (ENABLED == enable)
+        retVal = rtl8306e_cpu_set(RTL8306_PORT4, FALSE);
+    else
+        retVal = rtl8306e_cpu_set(RTL8306_NOCPUPORT, FALSE);
+    
+    return retVal;    
+}
+
+
+/* Function Name:
+ *      rtk_cpu_enable_get
+ * Description:
+ *      Get cpu port function enable or disable
+ * Input:
+ *      none
+ * Output:
+ *      pEnable          -  the pointer of enable or disable cpu port function
+ * Return:
+ *      RT_ERR_OK                   -  Success
+ *      RT_ERR_FAILED             -   Failure
+ * Note:
+ *      The API can set CPU port function enable/disable
+ */
+rtk_api_ret_t rtk_cpu_enable_get(rtk_enable_t *pEnable)
+{
+    rtk_api_ret_t retVal;
+    uint32 port, entag;
+    
+    if(NULL == pEnable)
+        return RT_ERR_NULL_POINTER;
+    
+    retVal = rtl8306e_cpu_get(&port, &entag);
+    if (retVal != SUCCESS)
+        return RT_ERR_FAILED;
+
+    if(RTL8306_NOCPUPORT == port)
+        *pEnable = DISABLED;
+    else
+        *pEnable = ENABLED;
+        
+    return RT_ERR_OK;    
+}
+
+/* Function Name:
+ *      rtk_cpu_tagPort_set
+ * Description:
+ *      Set CPU port and CPU tag insert mode
+ * Input:
+ *      port          -  Port id
+ *      mode        -  CPU tag insert for packets egress from CPU port
+ * Output:
+ *      none
+ * Return:
+ *      RT_ERR_OK                   -  Success
+ *      RT_ERR_FAILED             -   Failure
+ *      RT_ERR_PORT_ID           -   Invalid port id
+ * Note:
+ *      The API can set CPU port and inserting proprietary CPU tag mode (Length/Type 0x8899)
+ *      to the frame that transmitting to CPU port.
+ *      The inset cpu tag mode is as following:
+ *          - CPU_INSERT_TO_ALL
+ *          - CPU_INSERT_TO_TRAPPING
+ *          - CPU_INSERT_TO_NONE   
+ */
+ 
+rtk_api_ret_t rtk_cpu_tagPort_set(rtk_port_t port, rtk_cpu_insert_t mode)
+{
+    rtk_api_ret_t retVal;
+    uint32 regval;
+
+    if(port > RTK_PORT_ID_MAX)
+        return RT_ERR_PORT_ID;
+
+    switch(mode)
+    {
+        case CPU_INSERT_TO_ALL:
+            retVal = rtl8306e_cpu_set(port, TRUE);             
+            if(retVal != SUCCESS)
+                return RT_ERR_FAILED;
+            break;
+        case CPU_INSERT_TO_TRAPPING:
+            retVal = rtl8306e_cpu_set(port, FALSE);                        
+            if(retVal != SUCCESS)
+                return RT_ERR_FAILED;
+            /*enable insert cpu tag for trap pkt */
+            rtl8306e_reg_get(6, 30, 1, &regval);
+            regval |= (0x7F << 8);
+            rtl8306e_reg_set(6, 30, 1, regval);            
+            break;
+        case CPU_INSERT_TO_NONE:
+            retVal = rtl8306e_cpu_set(port, FALSE);                        
+            if(retVal != SUCCESS)
+                return RT_ERR_FAILED;
+            /*disable insert cpu tag for trap pkt */
+            rtl8306e_reg_get(6, 30, 1, &regval);
+            regval &= ~(0x7F << 8);
+            rtl8306e_reg_set(6, 30, 1, regval);                        
+            break;
+        default:
+            return RT_ERR_INPUT;
+    }
+                    
+    return RT_ERR_OK;        
+}
+
+
+/* Function Name:
+ *      rtk_cpu_tagPort_get
+ * Description:
+ *      Get CPU port and CPU tag insert mode
+ * Input:
+ *      port          -  Port id
+ * Output:
+ *      pMode       -  the pointer of CPU tag insert for packets egress from CPU port
+ * Return:
+ *      RT_ERR_OK                      -  Success
+ *      RT_ERR_FAILED                -   Failure
+ *      RT_ERR_NULL_POINTER      -   Input parameter is null pointer
+ * Note:
+ *      The API can set CPU port and inserting proprietary CPU tag mode (Length/Type 0x8899)
+ *      to the frame that transmitting to CPU port.
+ *      The inset cpu tag mode is as following:
+ *          CPU_INSERT_TO_ALL
+ *          CPU_INSERT_TO_TRAPPING
+ *          CPU_INSERT_TO_NONE   
+ */
+
+rtk_api_ret_t rtk_cpu_tagPort_get(rtk_port_t *pPort, rtk_cpu_insert_t *pMode)
+{
+    rtk_api_ret_t retVal;
+    uint32 enCputag;
+    uint32 regval;
+
+    if ((NULL == pPort) || (NULL == pMode))
+        return RT_ERR_NULL_POINTER;
+    
+    retVal = rtl8306e_cpu_get(pPort, &enCputag);
+    if(retVal != SUCCESS)
+        return RT_ERR_FAILED;
+    
+    if(enCputag)
+    {
+        *pMode = CPU_INSERT_TO_ALL;
+    }
+    else
+    {
+        /*enable insert cpu tag for trap pkt */
+        rtl8306e_reg_get(6, 30, 1, &regval);
+        if((0x7F << 8) == (regval & (0x7F << 8)))
+            *pMode = CPU_INSERT_TO_TRAPPING;
+        else
+            *pMode = CPU_INSERT_TO_NONE;
+    }
+    
+    return RT_ERR_OK;                    
+}
+
+
+
+/* Function Name:
+ *      rtk_mirror_portBased_set
+ * Description:
+ *      Set port mirror function
+ * Input:
+ *      mirroring_port                  - Monitor port, 7 means no monitor port
+ *      pMirrored_rx_portmask      - the pointer of Rx mirror port mask
+ *      pMirrored_tx_portmask      - the pointer of Tx mirror port mask
+ * Output:
+ *      none
+ * Return:
+ *      RT_ERR_OK                      -  Success
+ *      RT_ERR_FAILED                -   Failure
+ *      RT_ERR_PORT_MASK         -   Invalid port mask
+ * Note:
+ *      The API is to set mirror function of source port and mirror port. 
+ */
+
+rtk_api_ret_t rtk_mirror_portBased_set(rtk_port_t mirroring_port, rtk_portmask_t *pMirrored_rx_portmask, rtk_portmask_t *pMirrored_tx_portmask)
+{
+    rtk_api_ret_t retVal;
+        
+    if ((NULL == pMirrored_rx_portmask) || (NULL == pMirrored_tx_portmask))
+        return RT_ERR_NULL_POINTER;
+    
+    if (pMirrored_rx_portmask->bits[0] > RTL8306_MAX_PORTMASK)
+        return RT_ERR_PORT_MASK; 
+
+    if (pMirrored_tx_portmask->bits[0] > RTL8306_MAX_PORTMASK)
+        return RT_ERR_PORT_MASK;
+
+    retVal = rtl8306e_mirror_portBased_set(mirroring_port, 
+                pMirrored_rx_portmask->bits[0],
+                pMirrored_tx_portmask->bits[0]);
+    return retVal;
+}
+
+/* Function Name:
+ *      rtk_mirror_portBased_get
+ * Description:
+ *      Get port mirror function
+ * Input:
+ *      none 
+ * Output:
+ *      pMirroring_port             - the pointer Monitor port, 7 means no monitor port
+ *      pMirrored_rx_portmask   - the pointer of Rx mirror port mask
+ *      pMirrored_tx_portmask   - the pointer of Tx mirror port mask 
+ * Return:
+ *      RT_ERR_OK                      -  Success
+ *      RT_ERR_FAILED                -   Failure
+ *      RT_ERR_PORT_MASK         -   Invalid port mask
+ *      RT_ERR_NULL_POINTER      -   Input parameter is null pointer 
+ * Note:
+ *      The API is to set mirror function of source port and mirror port. 
+ */
+rtk_api_ret_t rtk_mirror_portBased_get(rtk_port_t *pMirroring_port, rtk_portmask_t *pMirrored_rx_portmask, rtk_portmask_t *pMirrored_tx_portmask)
+{
+    rtk_api_ret_t retVal;
+    
+    if ((NULL == pMirrored_rx_portmask) || (NULL == pMirrored_tx_portmask) ||
+        (NULL == pMirroring_port))
+        return RT_ERR_NULL_POINTER;
+    
+    retVal = rtl8306e_mirror_portBased_get(pMirroring_port, 
+                &(pMirrored_rx_portmask->bits[0]),
+                &(pMirrored_tx_portmask->bits[0]));
+    
+    return retVal;
+}
+
+/* Function Name:
+ *      rtk_dot1x_unauthPacketOper_set
+ * Description:
+ *      Set 802.1x unauth action configuration
+ * Input:
+ *      port                 -   Port id, no use for RTL8306E switch
+ *      unauth_action   -   802.1X unauth action    
+ * Output:
+ *      none
+ * Return:
+ *      RT_ERR_OK                      -  Success
+ *      RT_ERR_FAILED                -   Failure
+ *      RT_ERR_DOT1X_PROC        -   Unauthorized behavior error
+ * Note:
+ *      This API can set 802.1x unauth action configuration, 
+ *      for RTL8306E switch, the action is by whole system,
+ *      so port could be any value of 0~6.
+ *      The unauth action is as following:
+ *          - DOT1X_ACTION_DROP
+ *          - DOT1X_ACTION_TRAP2CPU
+ */
+rtk_api_ret_t rtk_dot1x_unauthPacketOper_set(rtk_port_t port, rtk_dot1x_unauth_action_t unauth_action)
+{
+    rtk_api_ret_t retVal;
+
+    if(unauth_action > DOT1X_ACTION_TRAP2CPU)
+        return RT_ERR_DOT1X_PROC;
+
+    if(DOT1X_ACTION_DROP == unauth_action)
+    {
+        retVal = rtl8306e_trap_abnormalPktAction_set(RTL8306_DOT1XUNAUTH, RTL8306_ACT_DROP);
+    }
+    else if(DOT1X_ACTION_TRAP2CPU == unauth_action)
+    {
+        retVal = rtl8306e_trap_abnormalPktAction_set(RTL8306_DOT1XUNAUTH, RTL8306_ACT_TRAPCPU);
+    }
+    else
+        retVal = RT_ERR_DOT1X_PROC;
+
+    return retVal;
+}
+
+/* Function Name:
+ *      rtk_dot1x_unauthPacketOper_get
+ * Description:
+ *      Get 802.1x unauth action configuration
+ * Input:
+ *      port                  -   Port id, no use for RTL8306E switch
+ * Output:
+ *      pUnauth_action   -  the pointer of 802.1X unauth action    
+ * Return:
+ *      RT_ERR_OK                      -  Success
+ *      RT_ERR_FAILED                -   Failure
+ *      RT_ERR_NULL_POINTER      -   Input parameter is null pointer
+ * Note:
+ *      This API can set 802.1x unauth action configuration, 
+ *      for RTL8306E switch, the action is by whole system,
+ *      so port could be any value of 0~6.
+ *      The unauth action is as following:
+ *          - DOT1X_ACTION_DROP
+ *          - DOT1X_ACTION_TRAP2CPU
+ */
+rtk_api_ret_t rtk_dot1x_unauthPacketOper_get(rtk_port_t port, rtk_dot1x_unauth_action_t *pUnauth_action)
+{
+    rtk_api_ret_t retVal;
+    uint32 action;
+    
+    if(NULL == pUnauth_action)
+        return RT_ERR_NULL_POINTER;
+    
+    retVal = rtl8306e_trap_abnormalPktAction_get(RTL8306_DOT1XUNAUTH, &action);
+
+    if (retVal != SUCCESS)
+        return RT_ERR_FAILED;
+    
+    if(RTL8306_ACT_DROP == action)
+    {
+        *pUnauth_action = DOT1X_ACTION_DROP;
+    }
+    else 
+    {
+        *pUnauth_action = DOT1X_ACTION_TRAP2CPU;
+    }
+    
+    return RT_ERR_OK;
+}
+
+
+/* Function Name:
+ *      rtk_dot1x_portBasedEnable_set
+ * Description:
+ *      Set 802.1x port-based enable configuration
+ * Input:
+ *      port                  -   Port id
+ *      enable               -   enable or disable
+ * Output:
+ *      none
+ * Return:
+ *      RT_ERR_OK                      -  Success
+ *      RT_ERR_FAILED                -   Failure
+ *      RT_ERR_PORT_ID              -   Invalid port id
+ * Note:
+ *      The API can update the port-based port enable register content. If a port is 802.1x 
+ *      port based network access control "enabled", it should be authenticated so packets 
+ *      from that port won't be dropped or trapped to CPU. 
+ *      The status of 802.1x port-based network access control is as following:
+ *          - DISABLED
+ *          - ENABLED
+ */    
+ 
+rtk_api_ret_t rtk_dot1x_portBasedEnable_set(rtk_port_t port, rtk_enable_t enable)
+{
+    rtk_api_ret_t retVal;
+    uint32 isAuth, direction, enDot1x;
+
+    if(port > RTK_PORT_ID_MAX) 
+        return RT_ERR_PORT_ID;    
+
+    retVal = rtl8306e_dot1x_portBased_get(port, &enDot1x, &isAuth, &direction);
+    if(retVal != SUCCESS)
+        return RT_ERR_FAILED;
+    
+    retVal = rtl8306e_dot1x_portBased_set(port, (uint32)enable, isAuth, direction);
+    if(retVal != SUCCESS)
+        return RT_ERR_FAILED;
+    
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_dot1x_portBasedEnable_get
+ * Description:
+ *      Get 802.1x port-based enable configuration
+ * Input:
+ *      port                  -   Port id
+ * Output:
+ *      pEnable             -   the pointer of enable or disable
+ * Return:
+ *      RT_ERR_OK                -  Success
+ *      RT_ERR_FAILED          -   Failure
+ *      RT_ERR_PORT_ID        -   Invalid port id
+ * Note:
+ *      The API can update the port-based port enable register content. If a port is 802.1x 
+ *      port based network access control "enabled", it should be authenticated so packets 
+ *      from that port won't be dropped or trapped to CPU. 
+ *      The status of 802.1x port-based network access control is as following:
+ *          - DISABLED
+ *          - ENABLED
+ */    
+ 
+rtk_api_ret_t rtk_dot1x_portBasedEnable_get(rtk_port_t port, rtk_enable_t *pEnable)
+{
+    rtk_api_ret_t retVal;
+    uint32 isAuth, direction, enDot1x;
+
+    if(port > RTK_PORT_ID_MAX) 
+        return RT_ERR_PORT_ID;    
+
+    if(NULL == pEnable)
+        return RT_ERR_NULL_POINTER;
+
+    retVal = rtl8306e_dot1x_portBased_get(port, &enDot1x, &isAuth, &direction);
+    if(retVal != SUCCESS)
+        return RT_ERR_FAILED;
+    
+    *pEnable = enDot1x ? ENABLED : DISABLED;
+            
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_dot1x_portBasedAuthStatus_set
+ * Description:
+ *      Set 802.1x port-based enable configuration
+ * Input:
+ *      port                  -   Port id
+ *      port_auth          -  The status of 802.1x port
+ * Output:
+ *      none
+ * Return:
+ *      RT_ERR_OK                                    -  Success
+ *      RT_ERR_FAILED                              -   Failure
+ *      RT_ERR_PORT_ID                            -   Invalid port id
+ *      RT_ERR_DOT1X_PORTBASEDAUTH      -   Port-based auth port error
+ * Note:
+ *      The authenticated status of 802.1x port-based network access control is as following:
+ *          - UNAUTH
+ *          - AUTH
+ */    
+rtk_api_ret_t rtk_dot1x_portBasedAuthStatus_set(rtk_port_t port, rtk_dot1x_auth_status_t port_auth)
+{
+    rtk_api_ret_t retVal;
+    uint32 isAuth, direction, enDot1x;
+
+    if(port > RTK_PORT_ID_MAX) 
+        return RT_ERR_PORT_ID;    
+
+    if(port_auth > AUTH_STATUS_END)
+        return RT_ERR_DOT1X_PORTBASEDAUTH;
+
+    retVal = rtl8306e_dot1x_portBased_get(port, &enDot1x, &isAuth, &direction);
+    if(retVal != SUCCESS)
+        return RT_ERR_FAILED;
+    
+    retVal = rtl8306e_dot1x_portBased_set(port, enDot1x, (uint32)port_auth, direction);
+    if(retVal != SUCCESS)
+        return RT_ERR_FAILED;
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_dot1x_portBasedAuthStatus_get
+ * Description:
+ *      Get 802.1x port-based enable configuration
+ * Input:
+ *      port                  -   Port id
+ * Output:
+ *      pPort_auth         -   the pointer of the status of 802.1x port
+ * Return:
+ *      RT_ERR_OK                          -  Success
+ *      RT_ERR_FAILED                     -  Failure
+ *      RT_ERR_PORT_ID                   -  Invalid port id
+ *      RT_ERR_NULL_POINTER           -  Input parameter is null pointer
+ * Note:
+ *      The authenticated status of 802.1x port-based network access control is as following:
+ *          - UNAUTH
+ *          - AUTH
+ */    
+rtk_api_ret_t rtk_dot1x_portBasedAuthStatus_get(rtk_port_t port, rtk_dot1x_auth_status_t *pPort_auth)
+{
+    rtk_api_ret_t retVal;
+    uint32 isAuth, direction, enDot1x;
+
+    if(port > RTK_PORT_ID_MAX) 
+        return RT_ERR_PORT_ID;    
+    if (NULL == pPort_auth)
+        return RT_ERR_NULL_POINTER;
+
+    retVal = rtl8306e_dot1x_portBased_get(port, &enDot1x, &isAuth, &direction);
+    if(retVal != SUCCESS)
+        return RT_ERR_FAILED;
+    *pPort_auth = isAuth ? AUTH: UNAUTH;
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_dot1x_portBasedDirection_set
+ * Description:
+ *      Set 802.1x port-based operational direction configuration
+ * Input:
+ *      port                  -   Port id
+ *      port_direction     -   Operation direction
+ * Output:
+ *      none
+ * Return:
+ *      RT_ERR_OK                                 -  Success
+ *      RT_ERR_FAILED                           -  Failure
+ *      RT_ERR_PORT_ID                         -  Invalid port id
+ *      RT_ERR_DOT1X_PORTBASEDOPDIR  -  Port-based opdir error
+ * Note:
+ *      The operate controlled direction of 802.1x port-based network access control is as following:
+ *          - BOTH
+ *          - IN
+ */    
+
+rtk_api_ret_t rtk_dot1x_portBasedDirection_set(rtk_port_t port, rtk_dot1x_direction_t port_direction)
+{
+    rtk_api_ret_t retVal;
+    uint32 isAuth, direction, enDot1x;
+
+    if(port > RTK_PORT_ID_MAX) 
+        return RT_ERR_PORT_ID;    
+    
+    if(port_direction >= DIRECTION_END)
+        return RT_ERR_DOT1X_PORTBASEDOPDIR;
+
+    retVal = rtl8306e_dot1x_portBased_get(port, &enDot1x, &isAuth, &direction);
+    if(retVal != SUCCESS)
+        return RT_ERR_FAILED;
+    
+    retVal = rtl8306e_dot1x_portBased_set(port, enDot1x, isAuth, (uint32)port_direction);
+    if(retVal != SUCCESS)
+        return RT_ERR_FAILED;
+    
+    return RT_ERR_OK;
+}
+
+
+/* Function Name:
+ *      rtk_dot1x_portBasedDirection_get
+ * Description:
+ *      Get 802.1x port-based operational direction configuration
+ * Input:
+ *      port                  -   Port id
+ * Output:
+ *      pPort_direction    -   the pointer of Operation direction
+ * Return:
+ *      RT_ERR_OK                         -  Success
+ *      RT_ERR_FAILED                    -  Failure
+ *      RT_ERR_PORT_ID                  -  Invalid port id
+ *      RT_ERR_NULL_POINTER          -  Input parameter is null pointer
+ * Note:
+ *      The operate controlled direction of 802.1x port-based network access control is as following:
+ *          - BOTH
+ *          - IN
+ */    
+rtk_api_ret_t rtk_dot1x_portBasedDirection_get(rtk_port_t port, rtk_dot1x_direction_t *pPort_direction)
+{
+    rtk_api_ret_t retVal;
+    uint32 isAuth, direction, enDot1x;
+
+    if(port > RTK_PORT_ID_MAX) 
+        return RT_ERR_PORT_ID;    
+
+    if(NULL == pPort_direction)
+        return RT_ERR_NULL_POINTER;
+    
+    retVal = rtl8306e_dot1x_portBased_get(port, &enDot1x, &isAuth, &direction);
+    if(retVal != SUCCESS)
+        return RT_ERR_FAILED;
+
+    *pPort_direction = (rtk_dot1x_direction_t)direction;
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_dot1x_macBasedEnable_set
+ * Description:
+ *      Set 802.1x mac-based port enable configuration
+ * Input:
+ *      port                  -   Port id
+ *      enable               -   The status of 802.1x mac-base funtion
+ * Output:
+ *      none
+ * Return:
+ *      RT_ERR_OK                         -  Success
+ *      RT_ERR_FAILED                    -  Failure
+ *      RT_ERR_PORT_ID                  -  Invalid port id
+ * Note:
+ *     If a port is 802.1x MAC based network access control "enabled", the incoming packets should 
+ *     be authenticated so packets from that port won't be dropped or trapped to CPU.
+ *     The status of 802.1x MAC-based network access control is as following:
+ *         - DISABLED
+ *         - ENABLED
+ */    
+rtk_api_ret_t rtk_dot1x_macBasedEnable_set(rtk_port_t port, rtk_enable_t enable)
+{
+    rtk_api_ret_t retVal;
+    uint32 direction, enMacBase;
+    
+    if(port > RTK_PORT_ID_MAX) 
+        return RT_ERR_PORT_ID;    
+    
+    retVal = rtl8306e_dot1x_macBased_get(port, &enMacBase, &direction); 
+    if (retVal != SUCCESS)
+        return RT_ERR_FAILED;
+
+    retVal = rtl8306e_dot1x_macBased_set(port, (uint32)enable, direction);
+    if (retVal != SUCCESS)
+        return RT_ERR_FAILED;
+       
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_dot1x_macBasedEnable_get
+ * Description:
+ *      Get 802.1x mac-based port enable configuration
+ * Input:
+ *      port                  -   Port id
+ * Output:
+ *      pEnable             -   the pointer of the status of 802.1x mac-base funtion
+ * Return:
+ *      RT_ERR_OK               -  Success
+ *      RT_ERR_FAILED         -   Failure
+ * Note:
+ *     If a port is 802.1x MAC based network access control "enabled", the incoming packets should 
+ *     be authenticated so packets from that port won't be dropped or trapped to CPU.
+ *     The status of 802.1x MAC-based network access control is as following:
+ *         - DISABLED
+ *         - ENABLED
+ */    
+rtk_api_ret_t rtk_dot1x_macBasedEnable_get(rtk_port_t port, rtk_enable_t *pEnable)
+{
+    rtk_api_ret_t retVal;
+    uint32 direction, enMacBase;
+    
+    if(port > RTK_PORT_ID_MAX) 
+        return RT_ERR_PORT_ID;    
+
+    if(NULL == pEnable)
+        return RT_ERR_NULL_POINTER;
+    
+    retVal = rtl8306e_dot1x_macBased_get(port, &enMacBase, &direction); 
+    if (retVal != SUCCESS)
+        return RT_ERR_FAILED;
+
+    *pEnable = enMacBase ? ENABLED: DISABLED;
+    
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_dot1x_macBasedDirection_set
+ * Description:
+ *      Set 802.1x mac-based operational direction configuration
+ * Input:
+ *      mac_direction    -   Operation direction
+ * Output:
+ *      none
+ * Return:
+ *      RT_ERR_OK                                    -  Success
+ *      RT_ERR_FAILED                              -  Failure
+ *      RT_ERR_DOT1X_MACBASEDOPDIR      -  MAC-based opdir error
+ * Note:
+ *      The operate controlled direction of 802.1x mac-based network access control is as following:
+ *          - BOTH
+ *          - IN
+ */    
+
+rtk_api_ret_t rtk_dot1x_macBasedDirection_set(rtk_dot1x_direction_t mac_direction)
+{
+    rtk_api_ret_t retVal;
+        
+    if(mac_direction > DIRECTION_END) 
+        return RT_ERR_DOT1X_MACBASEDOPDIR;    
+
+    retVal = rtl8306e_regbit_set(2, 22, 7, 3, mac_direction == BOTH ? 0:1);
+
+    return retVal;
+}
+    
+/* Function Name:
+ *      rtk_dot1x_macBasedDirection_get
+ * Description:
+ *      Get 802.1x mac-based operational direction configuration
+ * Input:
+ *      none
+ * Output:
+ *      pMac_direction    -   the pointer of Operation direction
+ * Return:
+ *      RT_ERR_OK                                    -  Success
+ *      RT_ERR_FAILED                              -  Failure
+ *      RT_ERR_NULL_POINTER                    -  Input parameter is null pointer
+ * Note:
+ *      The operate controlled direction of 802.1x mac-based network access control is as following:
+ *          - BOTH
+ *          - IN
+ */
+rtk_api_ret_t rtk_dot1x_macBasedDirection_get(rtk_dot1x_direction_t *pMac_direction)
+{
+    rtk_api_ret_t retVal;
+    uint32          dir;
+
+    if(NULL == pMac_direction)
+        return RT_ERR_NULL_POINTER;
+
+    retVal = rtl8306e_regbit_get(2, 22, 7, 3, &dir);
+    if(retVal != SUCCESS)
+        return RT_ERR_FAILED;
+    
+    *pMac_direction = dir ? IN: BOTH;
+    
+    return RT_ERR_OK;
+}
+
+
+/* Function Name:
+ *      rtk_dot1x_macBasedAuthMac_add
+ * Description:
+ *      Add an authenticated MAC to ASIC
+ * Input:
+ *      port            -  Port id
+ *      pAuth_mac   - The authenticated MAC
+ *      fid              -  no use for RTL8306E   
+ * Output:
+ *      none
+ * Return:
+ *      RT_ERR_OK                                       - Success
+ *      RT_ERR_FAILED                                 -  Failure
+ *      RT_ERR_L2_ENTRY_NOTFOUND             -  Specified entry not found
+ *      RT_ERR_DOT1X_MAC_PORT_MISMATCH  - Auth MAC and port mismatch eror 
+ * Note:
+ *     The API can add a 802.1x authenticated MAC address to port. If the MAC does not exist in LUT, 
+ *     user can't add this MAC to auth status.
+ */    
+
+rtk_api_ret_t rtk_dot1x_macBasedAuthMac_add(rtk_port_t port, rtk_mac_t *pAuth_mac, rtk_fid_t fid)
+{
+    int32 i;
+    uint8 macAddr[6];
+    uint32 index,entryaddr;
+    uint32 isStatic,isAuth,age, srcPort;
+    uint32 isHit;
+
+
+    if(port > RTK_PORT_ID_MAX) 
+        return RT_ERR_PORT_ID;        
+
+    if(NULL == pAuth_mac)
+        return RT_ERR_NULL_POINTER;
+
+    if(pAuth_mac->octet[0] & 0x1)
+        return RT_ERR_DOT1X_MAC_PORT_MISMATCH;
+
+    rtl8306e_l2_MacToIdx_get(pAuth_mac->octet, &index);   
+    
+    isHit = FALSE;
+    for (i = 3; i >= 0; i--) 
+    {
+        entryaddr = (index << 2) | (uint32)i;
+        if (rtl8306e_l2_unicastEntry_get(macAddr, entryaddr, &age, &isStatic, &isAuth, &srcPort) != SUCCESS) 
+        {
+            return RT_ERR_FAILED;
+        }
+        else if ((pAuth_mac->octet[0] == macAddr[0]) && (pAuth_mac->octet[1] == macAddr[1]) && 
+                   (pAuth_mac->octet[2] == macAddr[2]) && (pAuth_mac->octet[3] == macAddr[3]) &&
+                   (pAuth_mac->octet[4] == macAddr[4]) && (pAuth_mac->octet[5] == macAddr[5])) 
+        {
+            if(srcPort != port)
+                return RT_ERR_DOT1X_MAC_PORT_MISMATCH;
+            if (rtl8306e_l2_unicastEntry_set(pAuth_mac->octet, (uint32)i , age, isStatic, TRUE, port) != SUCCESS)
+                return RT_ERR_FAILED;
+            isHit = TRUE;
+            return RT_ERR_OK;
+        }
+    }
+
+    if(!isHit)
+        return RT_ERR_L2_ENTRY_NOTFOUND;
+    
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_dot1x_macBasedAuthMac_del
+ * Description:
+ *      Delete an authenticated MAC to ASIC
+ * Input:
+ *      port            -  Port id
+ *      pAuth_mac   - The authenticated MAC
+ *      fid              -  no use for RTL8306E   
+ * Output:
+ *      none
+ * Return:
+ *      RT_ERR_OK                                       - Success
+ *      RT_ERR_FAILED                                 -  Failure
+ *      RT_ERR_L2_ENTRY_NOTFOUND             -  Specified entry not found
+ *      RT_ERR_DOT1X_MAC_PORT_MISMATCH  - Auth MAC and port mismatch eror 
+ * Note:
+ *     The API can delete a 802.1x authenticated MAC address to port. It only change the auth status of
+ *     the MAC and won't delete it from LUT.
+ */
+rtk_api_ret_t rtk_dot1x_macBasedAuthMac_del(rtk_port_t port, rtk_mac_t *pAuth_mac, rtk_fid_t fid)
+{
+    int32 i;
+    uint8 macAddr[6];
+    uint32 index,entryaddr;
+    uint32 isStatic,isAuth,age, srcPort;
+    uint32 isHit;
+
+    if(port > RTK_PORT_ID_MAX) 
+        return RT_ERR_PORT_ID;        
+
+    if(NULL == pAuth_mac)
+        return RT_ERR_NULL_POINTER;
+
+    if(pAuth_mac->octet[0] & 0x1)
+        return RT_ERR_DOT1X_MAC_PORT_MISMATCH;
+
+    rtl8306e_l2_MacToIdx_get(pAuth_mac->octet, &index);   
+    
+    isHit = FALSE;
+    for (i = 3; i >= 0; i--) 
+    {
+        entryaddr = (index << 2) | (uint32)i;
+        if (rtl8306e_l2_unicastEntry_get(macAddr, entryaddr, &age, &isStatic, &isAuth, &srcPort) != SUCCESS) 
+        {
+            return RT_ERR_FAILED;
+        }
+        else if ((pAuth_mac->octet[0] == macAddr[0]) && (pAuth_mac->octet[1] == macAddr[1]) && 
+                   (pAuth_mac->octet[2] == macAddr[2]) && (pAuth_mac->octet[3] == macAddr[3]) &&
+                   (pAuth_mac->octet[4] == macAddr[4]) && (pAuth_mac->octet[5] == macAddr[5])) 
+        {
+            if(srcPort != port)
+                return RT_ERR_DOT1X_MAC_PORT_MISMATCH;
+            if (rtl8306e_l2_unicastEntry_set(pAuth_mac->octet, (uint32)i , age, isStatic, FALSE, port) != SUCCESS)
+                return RT_ERR_FAILED;
+            isHit = TRUE;
+            return RT_ERR_OK;
+        }
+    }
+
+    if(!isHit)
+        return RT_ERR_L2_ENTRY_NOTFOUND;
+    
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_svlan_init
+ * Description:
+ *      Initialize SVLAN Configuration
+ * Input:
+ *      none
+ * Output:
+ *      none
+ * Return:
+ *      RT_ERR_OK
+ *      RT_ERR_FAILED
+ *      RT_ERR_SMI
+ *      RT_ERR_INPUT
+ * Note:
+ *    Ether type of S-tag in 802.1ad is 0x88a8 and there are existed ether type 
+ *    0x9100 and 0x9200 for Q-in-Q SLAN design. User can set mathced ether 
+ *    type as service provider supported protocol. After call this API, all ports are 
+ *    set as CVLAN port. you can use rtk_svlan_servicePort_add to add SVLAN port. 
+ */
+rtk_api_ret_t rtk_svlan_init(void)
+{
+
+    uint32 regval;
+    uint32 port;
+    
+    /*enable Q_in_Q*/
+    rtl8306e_regbit_set(6, 30, 6, 3, 1);
+    rtl8306e_regbit_set(6, 30, 7, 3, 1);    
+
+   /*clear NNI port list*/
+   rtl8306e_reg_get(6, 30, 3, &regval);
+   regval &= (~0x3f);
+   rtl8306e_reg_set(6, 30, 3, regval);
+    
+   /*set default TPID*/
+    rtl8306e_reg_set(6, 28, 3, 0x88a8);
+
+   /*default use port-base otag PVID and priority as Otag source*/
+   for(port = 0; port < 6; port ++)
+        rtl8306e_svlan_otagSrc_set(port, 0, 0);
+
+   return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_svlan_servicePort_add
+ * Description:
+ *      Enable one service port in the specified device
+ * Input:
+ *      port     -  Port id
+ * Output:
+ *      none
+ * Return:
+ *      RT_ERR_OK
+ *      RT_ERR_FAILED
+ *      RT_ERR_SMI
+ * Note:
+ *    This API is setting which port is connected to provider switch. All frames receiving from this port
+ *    will recognize Service Vlan Tag.
+ *    
+ */
+rtk_api_ret_t rtk_svlan_servicePort_add(rtk_port_t port)
+{
+    uint32 regval;
+
+    if(port > RTK_PORT_ID_MAX) 
+        return RT_ERR_PORT_ID;        
+
+    /*add the port to NNI port list*/
+    rtl8306e_reg_get(6, 30, 3, &regval);    
+    regval |= (1 << port);
+    rtl8306e_reg_set(6, 30, 3, regval);
+    
+    return RT_ERR_OK;    
+}
+
+
+/* Function Name:
+ *      rtk_svlan_servicePort_del
+ * Description:
+ *      Disable one service port in the specified device
+ * Input:
+ *      none
+ * Output:
+ *      pSvlan_portmask  - svlan ports mask
+ * Return:
+ *      RT_ERR_OK
+ *      RT_ERR_FAILED
+ *      RT_ERR_SMI
+ * Note:
+ */
+rtk_api_ret_t rtk_svlan_servicePort_del(rtk_port_t port)
+{
+    uint32 regval;
+
+    if(port > RTK_PORT_ID_MAX) 
+        return RT_ERR_PORT_ID;        
+    
+    /*delete the port from NNI port list*/
+    rtl8306e_reg_get(6, 30, 3, &regval);    
+    regval &= (~(1 << port));
+    rtl8306e_reg_set(6, 30, 3, regval);
+        
+    return RT_ERR_OK;
+}
+
+
+/* Function Name:
+ *      rtk_svlan_servicePort_get
+ * Description:
+ *      Disable one service port in the specified device
+ * Input:
+ *      none
+ * Output:
+ *      pSvlan_portmask  - svlan ports mask
+ * Return:
+ *      RT_ERR_OK                 - success
+ *      RT_ERR_FAILED            -  fail
+ *      RT_ERR_NULL_POINTER  -  null pointer
+ * Note:
+ *      Ether type of S-tag in 802.1ad is 0x88a8 and there are existed ether type 0x9100 
+ *      and 0x9200 for Q-in-Q SLAN design. User can set mathced ether type as service 
+ *      provider supported protocol. 
+ */
+rtk_api_ret_t rtk_svlan_servicePort_get(rtk_portmask_t *pSvlan_portmask)
+{
+    uint32 regval;
+
+    if(NULL == pSvlan_portmask)
+        return RT_ERR_NULL_POINTER;
+
+    rtl8306e_reg_get(6, 30, 3, &regval);
+    pSvlan_portmask->bits[0] = regval & 0x3F;
+
+    return RT_ERR_OK;
+}
+
+
+/* Function Name:
+ *      rtk_svlan_tpidEntry_set
+ * Description:
+ *      Configure accepted S-VLAN ether type. The default ether type of S-VLAN is 0x88a8
+ * Input:
+ *      svlan_tag_id  - Ether type of S-tag frame parsing in uplink ports
+ * Output:
+ *      none
+ * Return:
+ *      RT_ERR_OK
+ *      RT_ERR_FAILED
+ *      RT_ERR_SMI
+ * Note:
+ *      Ether type of S-tag in 802.1ad is 0x88a8 and there are existed ether type 0x9100 
+ *      and 0x9200 for Q-in-Q SLAN design. User can set mathced ether type as service 
+ *      provider supported protocol. 
+ */
+rtk_api_ret_t rtk_svlan_tpidEntry_set(rtk_svlan_tpid_t svlan_tag_id)
+{
+
+    rtl8306e_reg_set(6, 28, 3, (uint32)svlan_tag_id);
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_svlan_tpidEntry_get
+ * Description:
+ *      Get accepted S-VLAN ether type. The default ether type of S-VLAN is 0x88a8
+ * Input:
+ *      pSvlan_tag_id       - Ether type of S-tag frame parsing in uplink ports
+ * Output:
+ *      none
+ * Return:
+ *      RT_ERR_OK
+ *      RT_ERR_FAILED
+ * Note:
+ *      Ether type of S-tag in 802.1ad is 0x88a8 and there are existed ether type 0x9100 
+ *      and 0x9200 for Q-in-Q SLAN design. User can set mathced ether type as service 
+ *      provider supported protocol. 
+ */
+rtk_api_ret_t rtk_svlan_tpidEntry_get(rtk_svlan_tpid_t *pSvlan_tag_id)
+{
+    uint32 regval;
+    
+    if(NULL == pSvlan_tag_id)
+        return RT_ERR_NULL_POINTER;
+    
+    rtl8306e_reg_get(6, 28, 3, &regval);
+    *pSvlan_tag_id = regval;    
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_svlan_portPvid_set
+ * Description:
+ *      Set port to specified VLAN ID(PVID) for Service Provider Port
+ * Input:
+ *      port             - Port id
+ *      pvid             - Specified Service VLAN ID
+ *      priority         - 802.1p priority for the PVID
+ *      dei               - Service VLAN tag DEI bit
+ * Output:
+ *      none
+ * Return:
+ *      RT_ERR_OK
+ *      RT_ERR_FAILED
+ *      RT_ERR_VLAN_VID
+ *      RT_ERR_SMI 
+ *      RT_ERR_VLAN_PRIORITY 
+ *      RT_ERR_VLAN_ENTRY_NOT_FOUND
+ * Note:
+ *    The API is used for Port-based VLAN. The untagged frame received from the
+ *    port will be classified to the specified VLAN and assigned to the specified priority.
+ */
+rtk_api_ret_t rtk_svlan_portPvid_set(rtk_port_t port, rtk_vlan_t pvid, rtk_pri_t priority, rtk_dei_t dei)
+{
+    uint32 regval;
+    
+    if(port > RTK_PORT_ID_MAX) 
+        return RT_ERR_PORT_ID;        
+    
+    /* vid must be 0~4095 */
+    if(pvid > 0x4095)
+        return RT_ERR_VLAN_VID;
+
+    /* priority must be 0~7 */
+    if(priority > 0x7)
+        return RT_ERR_VLAN_PRIORITY;
+
+    rtl8306e_reg_get(6, 26 + port, 0, &regval);
+    regval &= (1 << 12);
+    regval |= pvid | (priority << 13);
+    rtl8306e_reg_set(6, 26 + port, 0, regval);
+
+    return RT_ERR_OK;
+}
+
+
+
+/* Function Name:
+ *      rtk_svlan_portPvid_get
+ * Description:
+ *      Get Service VLAN ID(PVID) on specified port
+ * Input:
+ *      port             - Port id
+ *      pPvid            - Specified VLAN ID
+ *      pPriority        - 802.1p priority for the PVID
+ *      pDei             - DEI bit
+ * Output:
+ *      none
+ * Return:
+ *      RT_ERR_OK
+ *      RT_ERR_FAILED
+ *      RT_ERR_SMI
+ *      RT_ERR_PORT_ID
+ *      RT_ERR_NULL_POINTER 
+ * Note:
+ *    The API is used for Port-based VLAN. The untagged frame received from the
+ *    port will be classified to the specified VLAN and assigned to the specified priority.
+ */
+rtk_api_ret_t rtk_svlan_portPvid_get(rtk_port_t port, rtk_vlan_t *pPvid, rtk_pri_t* pPriority, rtk_dei_t *pDei)
+{
+    uint32 regval;
+    
+    if(port > RTK_PORT_ID_MAX) 
+        return RT_ERR_PORT_ID;        
+    
+    if((NULL == pPvid) || (NULL == pPriority) || (NULL == pDei))
+        return RT_ERR_NULL_POINTER;
+    
+    rtl8306e_reg_get(6, 26 + port, 0, &regval);
+    *pPvid = regval & 0xfff;
+    *pPriority = (regval & (0x7 << 13)) >> 13;
+    *pDei = 0;
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_filter_igrAcl_init
+ * Description:
+ *       Initialize ACL 
+ * Input:
+ *      none
+ * Output:
+ *      none
+ * Return:
+ *      RT_ERR_OK
+ *      RT_ERR_FAILED
+ * Note:
+ *      The API init ACL module.
+ */
+rtk_api_ret_t rtk_filter_igrAcl_init(void)
+{
+    uint32 entaddr;
+
+    /*empty the acl table*/
+    for (entaddr = 0; entaddr < RTL8306_ACL_ENTRYNUM; entaddr++ ) 
+    {
+        if (rtl8306e_acl_entry_set(entaddr, RTL8306_ACL_INVALID, RTL8306_ACT_DROP, RTL8306_ACL_ETHER, 0, 0) == FAILED)
+            return RT_ERR_FAILED;
+    }
+    
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_filter_igrAcl_rule_add
+ * Description:
+ *      Add an acl rule into acl table
+ * Input:
+ *      pRule    -  the pointer of rule structure
+ * Output:
+ *      none
+ * Return:
+ *      RT_ERR_OK
+ *      RT_ERR_FAILED
+ *      RT_ERR_TBL_FULL
+ *      RT_ERR_NULL_POINTER
+ * Note:
+ *      The API add an  ACL rule. <nl>
+ *      phyport could be  0~5: port number,  RTL8306_ACL_ANYPORT: any port;<nl>
+ *      protocol could be RTL8306_ACL_ETHER(ether type), RTL8306_ACL_TCP(TCP), RTL8306_ACL_UDP(UDP), RTL8306_ACL_TCPUDP(TCP or UDP);<nl>
+ *      prority could be RTL8306_PRIO0~RTL8306_PRIO3;<nl>
+ *      action could be RTL8306_ACT_DROP/RTL8306_ACT_PERMIT/RTL8306_ACT_TRAPCPU/RTL8306_ACT_MIRROR;<nl>
+ */
+
+rtk_api_ret_t rtk_filter_igrAcl_rule_add(rtk_filter_rule_t *pRule)
+{
+    uint32 entaddr;
+    uint32 port, pro, val, pri, act;  
+    uint32 isFull ;
+
+    if(NULL == pRule)
+        return RT_ERR_NULL_POINTER;
+    
+    isFull = TRUE;
+    
+    /*if  exist an  acl entry of the same rule according by phyport, protocol,data,
+     *only update priority and action
+     */
+    for (entaddr = 0; entaddr < RTL8306_ACL_ENTRYNUM; entaddr ++ ) 
+    {
+        if (rtl8306e_acl_entry_get(entaddr, &port, &act, &pro, &val, &pri) != SUCCESS)
+            return RT_ERR_FAILED;
+
+        if ((pRule->phyport == port) && (pRule->protocol == pro) && (pRule->data == val)) 
+        {
+            if (rtl8306e_acl_entry_set(entaddr, pRule->phyport, pRule->action, pRule->protocol, pRule->data, pRule->priority) != SUCCESS )
+                 return RT_ERR_FAILED;
+            else
+                 return RT_ERR_OK;
+        }            
+    }    
+
+    /*if not exist the rule, find an invalid entry to write it , else return table full */
+    for (entaddr = 0; entaddr < RTL8306_ACL_ENTRYNUM; entaddr ++ )
+    {
+        if (rtl8306e_acl_entry_get(entaddr, &port, &act, &pro, &val, &pri) != SUCCESS)
+            return RT_ERR_FAILED;
+        
+        if (port == RTL8306_ACL_INVALID) 
+        {
+            if (rtl8306e_acl_entry_set(entaddr, pRule->phyport, pRule->action, pRule->protocol, pRule->data, pRule->priority) != SUCCESS)
+                 return RT_ERR_FAILED;
+            else 
+            {
+                isFull = FALSE;
+                break;
+             }                        
+        }            
+    }    
+
+    if (isFull)
+        return RT_ERR_TBL_FULL;
+    else
+        return SUCCESS;
+
+
+   
+}
+
+
+/* Function Name:
+ *      rtk_filter_igrAcl_rule_get
+ * Description:
+ *      Get ACL rule priority and action 
+ * Input:
+ *      pRule    -  the pointer of rule structure
+ * Output:
+ *      pRule    -  the pointer of rule structure
+ * Return:
+ *      RT_ERR_OK
+ *      RT_ERR_FAILED
+ * Note:
+ *      The API add an  ACL rule. <nl>
+ *      phyport could be  0~5: port number,  RTL8306_ACL_ANYPORT: any port;<nl>
+ *      protocol could be RTL8306_ACL_ETHER(ether type), RTL8306_ACL_TCP(TCP), RTL8306_ACL_UDP(UDP), RTL8306_ACL_TCPUDP(TCP or UDP);<nl>
+ *      prority could be RTL8306_PRIO0~RTL8306_PRIO3;<nl>
+ *      action could be RTL8306_ACT_DROP/RTL8306_ACT_PERMIT/RTL8306_ACT_TRAPCPU/RTL8306_ACT_MIRROR;<nl>
+ */
+rtk_api_ret_t rtk_filter_igrAcl_rule_get(rtk_filter_rule_t *pRule)
+{
+    uint32 entaddr;
+    uint32 port, pro, val, pri, act;  
+
+
+    if(NULL == pRule)
+        return RT_ERR_NULL_POINTER;
+
+    /*if  exist an  acl entry of the same rule according by phyport, protocol,data,
+     *get the priority and action
+     */
+    for (entaddr = 0; entaddr < RTL8306_ACL_ENTRYNUM; entaddr ++ ) 
+    {
+        if (rtl8306e_acl_entry_get(entaddr, &port, &act, &pro, &val, &pri) != SUCCESS)
+            return RT_ERR_FAILED;
+
+        if ((pRule->phyport == port) && (pRule->protocol == pro) && (pRule->data == val)) 
+        {
+                 pRule->priority = pri;
+                 pRule->action = act;
+                 return RT_ERR_OK;
+        }            
+    }    
+
+    return RT_ERR_FAILED;
+}
+
+/* Function Name:
+ *      rtk_filter_igrAcl_rule_del
+ * Description:
+ *      Delete an acl rule into acl table
+ * Input:
+ *      pRule    -  the pointer of rule structure
+ * Output:
+ *      none
+ * Return:
+ *      RT_ERR_OK
+ *      RT_ERR_FAILED
+ *      RT_ERR_INPUT
+ *      RT_ERR_NULL_POINTER
+ * Note:
+ *      The API delete an  ACL rule. <nl>
+ *      only phyport/protocol/data field in pRule needs to be specified.
+ */
+rtk_api_ret_t rtk_filter_igrAcl_rule_del(rtk_filter_rule_t *pRule)
+{
+    uint32 entaddr;
+    uint32 port, pro, val, pri, act;  
+    uint32 isHit;
+
+    if(NULL == pRule)
+        return RT_ERR_NULL_POINTER;
+    
+    isHit = FALSE;
+    
+    if (pRule->phyport == RTL8306_ACL_INVALID)
+        return RT_ERR_INPUT;
+    
+    for (entaddr = 0; entaddr < RTL8306_ACL_ENTRYNUM; entaddr ++ ) 
+    {
+        if (rtl8306e_acl_entry_get(entaddr, &port, &act, &pro, &val, &pri) != SUCCESS)
+            return RT_ERR_FAILED;
+        
+        if ((port == pRule->phyport) && (pro == pRule->protocol) && (val == pRule->data))
+        {
+            if (rtl8306e_acl_entry_set(entaddr, RTL8306_ACL_INVALID, RTL8306_ACT_DROP, RTL8306_ACL_ETHER, 0, 0) != SUCCESS)
+                return RT_ERR_FAILED;
+            isHit = TRUE;
+            break;
+        }                
+    }
+
+    if (isHit)
+        return RT_ERR_OK;
+    else
+        return RT_ERR_INPUT;
+    
+
+
+}
+
+/*add at 2012-2-13*/
+rtk_api_ret_t rtk_mib_get(rtk_port_t port, rtk_mib_counter_t counter, rtk_mib_cntValue_t *pValue)
+{
+     rtk_api_ret_t retVal;
+
+     if (port > RTK_PORT_ID_MAX)
+        return RT_ERR_PORT_ID;
+     if (counter >= MIB_CNT_END)
+        return RT_ERR_INPUT;
+     if (NULL == pValue)
+        return RT_ERR_NULL_POINTER;
+
+     if ((retVal = rtl8306e_mib_get(port, counter, pValue)) != SUCCESS)
+        return RT_ERR_FAILED;
+
+     return RT_ERR_OK;
+}
+
+rtk_api_ret_t rtk_mib_cntType_set(rtk_port_t port, rtk_mib_counter_t counter, rtk_mib_cntType_t type)
+{ 
+
+    if (port > RTK_PORT_ID_MAX)
+        return RT_ERR_PORT_ID;
+    if (counter >= MIB_CNT_END)
+        return RT_ERR_INPUT;
+    if (type >= MIB_COUNTER_TYPE_END)
+        return RT_ERR_INPUT;
+
+    if (MIB_COUNTER_TYPE_BYTE == type)
+        rtl8306e_mibUnit_set(port, counter, RTL8306_MIB_BYTE);
+    else if (MIB_COUNTER_TYPE_PKT == type)
+        rtl8306e_mibUnit_set(port, counter, RTL8306_MIB_PKT);
+    
+    return RT_ERR_OK;
+}
+
+rtk_api_ret_t rtk_mib_cntType_get(rtk_port_t port, rtk_mib_counter_t counter, rtk_mib_cntType_t *pType)
+{
+    if (port > RTK_PORT_ID_MAX)
+        return RT_ERR_PORT_ID;
+    if (counter >= MIB_CNT_END)
+        return RT_ERR_INPUT;
+    if (NULL == pType)
+        return RT_ERR_NULL_POINTER;
+
+    rtl8306e_mibUnit_get(port, counter, pType);
+
+    return RT_ERR_OK;
+}
+
+rtk_api_ret_t rtk_mib_reset(rtk_port_t port)
+{
+    if (port > RTK_PORT_ID_MAX)
+        return RT_ERR_PORT_ID; 
+
+    rtl8306e_mib_reset(port);
+
+    return RT_ERR_OK;
+}
+
+
diff --git a/ap/os/linux/linux-3.4.x/drivers/net/phy/realtek/rtl8306e/rtk_api.h b/ap/os/linux/linux-3.4.x/drivers/net/phy/realtek/rtl8306e/rtk_api.h
new file mode 100755
index 0000000..7fc6286
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/net/phy/realtek/rtl8306e/rtk_api.h
@@ -0,0 +1,1290 @@
+/*
+* Copyright (C) 2010 Realtek Semiconductor Corp.
+* All Rights Reserved.
+*
+* This program is the proprietary software of Realtek Semiconductor
+* Corporation and/or its licensors, and only be used, duplicated,
+* modified or distributed under the authorized license from Realtek.
+*
+* ANY USE OF THE SOFTWARE OTEHR THAN AS AUTHORIZED UNDER 
+* THIS LICENSE OR COPYRIGHT LAW IS PROHIBITED.
+* 
+* $Revision: 26789 $ 
+* $Date: 2012-02-21 09:13:30 +0800 (星期二, 2012-02-21) $
+*
+* Purpose : realtek common API header file
+*
+* Feature :  This file consists of following modules:
+*                
+*
+*/
+
+#ifndef __RTK_API_H__
+#define __RTK_API_H__
+
+
+/*
+ * Include Files
+ */
+#include "rtl8306e_types.h"
+#include "rtl8306e_asicdrv.h"
+#include "rtk_error.h"
+
+/*
+ * Data Type Declaration
+ */
+#define ENABLE                                                    1
+#define DISABLE                                                   0
+
+#define PHY_CONTROL_REG                                   0
+#define PHY_STATUS_REG                                      1
+#define PHY_AN_ADVERTISEMENT_REG                    4
+#define PHY_AN_LINKPARTNER_REG                        5
+#define PHY_1000_BASET_CONTROL_REG                9
+#define PHY_1000_BASET_STATUS_REG                   10
+#define PHY_RESOLVED_REG                                   17
+
+/*Qos related configuration define*/
+#define QOS_DEFAULT_TICK_PERIOD                     (19-1)
+#define QOS_DEFAULT_BYTE_PER_TOKEN                  34
+#define QOS_DEFAULT_LK_THRESHOLD                    (34*3) /* Why use 0x400? */
+
+
+#define QOS_DEFAULT_INGRESS_BANDWIDTH               0x3FFF /* 0x3FFF => unlimit */
+#define QOS_DEFAULT_EGRESS_BANDWIDTH                0x3D08 /*( 0x3D08 + 1) * 64Kbps => 1Gbps*/
+#define QOS_DEFAULT_PREIFP                          1
+#define QOS_DEFAULT_PACKET_USED_PAGES_FC            0x60
+#define QOS_DEFAULT_PACKET_USED_FC_EN               0
+#define QOS_DEFAULT_QUEUE_BASED_FC_EN               1
+
+#define QOS_DEFAULT_PRIORITY_SELECT_PORT            8
+#define QOS_DEFAULT_PRIORITY_SELECT_1Q              0
+#define QOS_DEFAULT_PRIORITY_SELECT_ACL             0
+#define QOS_DEFAULT_PRIORITY_SELECT_DSCP            0
+
+#define QOS_DEFAULT_DSCP_MAPPING_PRIORITY           0
+
+#define QOS_DEFAULT_1Q_REMARKING_ABILITY             0
+#define QOS_DEFAULT_DSCP_REMARKING_ABILITY          0
+#define QOS_DEFAULT_QUEUE_GAP                                20
+#define QOS_DEFAULT_QUEUE_NO_MAX                          6
+#define QOS_DEFAULT_AVERAGE_PACKET_RATE             0x3FFF
+#define QOS_DEFAULT_BURST_SIZE_IN_APR                   0x3F
+#define QOS_DEFAULT_PEAK_PACKET_RATE                    2
+#define QOS_DEFAULT_SCHEDULER_ABILITY_APR           1     /*disable*/
+#define QOS_DEFAULT_SCHEDULER_ABILITY_PPR           1    /*disable*/
+#define QOS_DEFAULT_SCHEDULER_ABILITY_WFQ          1    /*disable*/
+
+#define QOS_WEIGHT_MAX                              128
+
+#define LED_GROUP_MAX                               3
+
+#define RTK_FILTER_RAW_FIELD_NUMBEER                8
+
+#define ACL_DEFAULT_ABILITY                         0
+#define ACL_DEFAULT_UNMATCH_PERMIT                  1
+
+#define ACL_RULE_FREE                               0
+#define ACL_RULE_INAVAILABLE                        1
+
+#define FILTER_POLICING_MAX                         8
+#define FILTER_LOGGING_MAX                          8
+#define FILTER_PATTERN_MAX                          4
+
+#define STORM_UNUC_INDEX                            39
+#define STORM_UNMC_INDEX                            47
+#define STORM_MC_INDEX                              55
+#define STORM_BC_INDEX                              63
+
+#define RTK_MAX_NUM_OF_INTERRUPT_TYPE               1
+#define RTK_TOTAL_NUM_OF_WORD_FOR_1BIT_PORT_LIST    1
+#define RTK_MAX_NUM_OF_PRIORITY                    4
+#define RTK_MAX_NUM_OF_QUEUE                        4
+#define RTK_MAX_NUM_OF_TRUNK_HASH_VAL               1
+#define RTK_MAX_NUM_OF_PORT                         6
+#define RTK_PORT_ID_MAX                             (RTK_MAX_NUM_OF_PORT-1)
+#define RTK_PHY_ID_MAX                             (RTK_MAX_NUM_OF_PORT-1)
+#define RTK_MAX_NUM_OF_PROTO_TYPE                   0xFFFF
+#define RTK_MAX_NUM_OF_MSTI                         0xF
+#define RTK_MAX_NUM_OF_LEARN_LIMIT                  0x1F
+#define RTK_MAX_PORT_MASK                             0x3F
+
+#define RTK_FLOWCTRL_PAUSE_ALL                      1980
+#define RTK_FLOWCTRL_DROP_ALL                       2012
+#define RTK_FLOWCTRL_PAUSE_SYSTEM_ON                1200
+#define RTK_FLOWCTRL_PAUSE_SYSTEM_OFF               1000
+#define RTK_FLOWCTRL_DROP_SYSTEM_ON                 1200
+#define RTK_FLOWCTRL_DROP_SYSTEM_OFF                1000
+#define RTK_FLOWCTRL_PAUSE_SHARE_ON                 216
+#define RTK_FLOWCTRL_PAUSE_SHARE_OFF                208
+#define RTK_FLOWCTRL_DROP_SHARE_ON                  216
+#define RTK_FLOWCTRL_DROP_SHARE_OFF                 208
+#define RTK_FLOWCTRL_PAUSE_PORT_ON                  140
+#define RTK_FLOWCTRL_PAUSE_PORT_OFF                 132
+#define RTK_FLOWCTRL_DROP_PORT_ON                   140
+#define RTK_FLOWCTRL_DROP_PORT_OFF                  132
+#define RTK_FLOWCTRL_PAUSE_PORT_PRIVATE_ON          26
+#define RTK_FLOWCTRL_PAUSE_PORT_PRIVATE_OFF         22
+#define RTK_FLOWCTRL_DROP_PORT_PRIVATE_ON           26
+#define RTK_FLOWCTRL_DROP_PORT_PRIVATE_OFF          22
+#define RTK_FLOWCTRL_PORT_DROP_EGRESS               210
+#define RTK_FLOWCTRL_QUEUE_DROP_EGRESS              2047
+#define RTK_FLOWCTRL_PORT_GAP                       72
+#define RTK_FLOWCTRL_QUEUE_GAP                      18
+
+#define RTK_WHOLE_SYSTEM                            0xFF
+
+#define RTK_EXT_0                                   0
+#define RTK_EXT_1                                   1
+
+#define RTK_EXT_0_MAC                               9
+#define RTK_EXT_1_MAC                               8
+
+#ifndef MAC_ADDR_LEN
+#define MAC_ADDR_LEN                                6
+#endif
+
+#define IPV6_ADDR_LEN                               16
+#define IPV4_ADDR_LEN                               4
+
+#define RTK_DOT_1AS_TIMESTAMP_UNIT_IN_WORD_LENGTH   3UL
+
+#define RTK_IPV6_ADDR_WORD_LENGTH                   4UL
+
+#define ALLPORT 0xFF
+
+typedef enum rtk_chip_mode_e
+{
+    CHIP_8367 = 0,
+    CHIP_8370,
+    CHIP_8370M,
+    CHIP_8376, 
+    CHIP_8218, 
+    CHIP_8306E,
+    CHIP_END
+}rtk_chip_mode_t;
+
+typedef enum rtk_cpu_insert_e
+{
+    CPU_INSERT_TO_ALL = 0,
+    CPU_INSERT_TO_TRAPPING,
+    CPU_INSERT_TO_NONE,
+    CPU_INSERT_END
+}rtk_cpu_insert_t;
+
+typedef enum rtk_cpu_position_e
+{
+    CPU_POS_ATTER_DA = 0,
+    CPU_POS_AFTER_CRC,
+    CPU_POS_END
+}rtk_cpu_position_t;
+
+
+/* Type of port-based dot1x auth/unauth*/
+typedef enum rtk_dot1x_auth_status_e
+{
+    UNAUTH = 0,
+    AUTH,
+    AUTH_STATUS_END
+} rtk_dot1x_auth_status_t;
+
+typedef enum rtk_dot1x_direction_e
+{
+    BOTH = 0,
+    IN,
+    DIRECTION_END
+} rtk_dot1x_direction_t;
+
+typedef enum rtk_mode_ext_e
+{
+    MODE_EXT_DISABLE = 0,
+    MODE_EXT_RGMII,
+    MODE_EXT_MII_MAC,
+    MODE_EXT_MII_PHY, 
+    MODE_EXT_TMII_MAC,
+    MODE_EXT_TMII_PHY, 
+    MODE_EXT_GMII,
+    MODE_EXT_RMII,
+    MODE_EXT_END
+} rtk_mode_ext_t;
+
+typedef struct
+{
+    uint32 value[RTK_DOT_1AS_TIMESTAMP_UNIT_IN_WORD_LENGTH];
+} rtk_filter_dot1as_timestamp_t;
+
+/* unauth pkt action */
+typedef enum rtk_dot1x_unauth_action_e
+{
+    DOT1X_ACTION_DROP = 0,
+    DOT1X_ACTION_TRAP2CPU,
+    DOT1X_ACTION_GUESTVLAN,
+    DOT1X_ACTION_END
+} rtk_dot1x_unauth_action_t;
+
+typedef uint32  rtk_dscp_t;         /* dscp vlaue */
+
+typedef enum rtk_enable_e
+{
+    DISABLED = 0,
+    ENABLED,
+    RTK_ENABLE_END
+} rtk_enable_t;
+
+typedef uint32  rtk_fid_t;        /* filter id type */
+
+/* ethernet address type */
+typedef struct  rtk_mac_s
+{
+    uint8 octet[ETHER_ADDR_LEN];
+} rtk_mac_t;
+
+typedef enum rtk_filter_act_enable_e
+{
+    /* CVLAN */
+    FILTER_ENACT_INGRESS_CVLAN_INDEX = 0,
+    FILTER_ENACT_INGRESS_CVLAN_VID,
+
+    /* SVLAN */
+    FILTER_ENACT_EGRESS_SVLAN_INDEX,
+
+    /* Policing and Logging */
+    FILTER_ENACT_POLICING_0,   
+
+    /* Forward */
+    FILTER_ENACT_TRAP_CPU,
+    FILTER_ENACT_COPY_CPU,
+    FILTER_ENACT_REDIRECT,
+    FILTER_ENACT_DROP,    
+    FILTER_ENACT_MIRROR,    
+    FILTER_ENACT_ADD_DSTPORT,    
+
+    /* QoS */
+    FILTER_ENACT_PRIORITY,
+
+    FILTER_ENACT_MAX
+} rtk_filter_act_enable_t;
+
+typedef struct
+{
+    rtk_filter_act_enable_t actEnable[FILTER_ENACT_MAX];
+
+    /* CVLAN acton */
+    uint32        filterIngressCvlanIdx;
+    uint32        filterIngressCvlanVid;
+
+    /* SVLAN action */
+    uint32        filterEgressSvlanIdx; 
+
+    /* Policing action */
+    uint32        filterPolicingIdx[FILTER_POLICING_MAX];
+
+    /* Forwarding action */
+    uint32        filterRedirectPortmask;
+    uint32        filterAddDstPortmask;  
+    
+    /* QOS action */
+    uint32        filterPriority;    
+} rtk_filter_action_t;
+
+typedef struct
+{
+    uint32 value;
+    uint32 mask;
+} rtk_filter_flag_t;
+
+typedef enum rtk_filter_care_tag_index_e
+{
+    CARE_TAG_CTAG = 0,
+    CARE_TAG_STAG,
+    CARE_TAG_PPPOE,
+    CARE_TAG_IPV4,
+    CARE_TAG_IPV6,
+    CARE_TAG_TCP,
+    CARE_TAG_UDP,    
+    CARE_TAG_ICMP,    
+    CARE_TAG_IGMP,    
+    CARE_TAG_MAX
+} rtk_filter_care_tag_index_t;
+
+typedef struct
+{
+    rtk_filter_flag_t tagType[CARE_TAG_MAX];
+} rtk_filter_care_tag_t;
+
+typedef struct rtk_filter_field rtk_filter_field_t;
+
+typedef enum rtk_filter_field_data_type_e
+{
+    FILTER_FIELD_DATA_MASK = 0,
+    FILTER_FIELD_DATA_RANGE,        
+    FILTER_FIELD_DATA_MAX
+} rtk_filter_field_data_type;
+
+typedef struct
+{
+    uint32 dataType;
+    uint32 rangeStart;
+    uint32 rangeEnd;
+    uint32 value;
+    uint32 mask;
+} rtk_filter_ip_t;
+
+typedef struct
+{
+    uint32 dataType;
+    rtk_mac_t value;
+    rtk_mac_t mask;
+    rtk_mac_t rangeStart;
+    rtk_mac_t rangeEnd;
+} rtk_filter_mac_t;
+
+typedef uint32 rtk_filter_op_t;
+
+typedef struct rtk_filter_value_s
+{
+    uint32 dataType;
+    uint32 value;
+    uint32 mask;
+    uint32 rangeStart;
+    uint32 rangeEnd;
+} rtk_filter_value_t;
+
+typedef struct rtk_filter_tag_s
+{
+    rtk_filter_value_t pri;
+    rtk_filter_flag_t cfi;
+    rtk_filter_value_t vid;
+} rtk_filter_tag_t;
+
+typedef struct
+{
+    rtk_filter_flag_t mf;
+    rtk_filter_flag_t df;
+} rtk_filter_ipFlag_t;
+
+typedef struct
+{
+    uint32 addr[RTK_IPV6_ADDR_WORD_LENGTH];
+} rtk_filter_ip6_addr_t;
+
+typedef struct
+{
+    uint32 dataType;
+    rtk_filter_ip6_addr_t value;
+    rtk_filter_ip6_addr_t mask;
+    rtk_filter_ip6_addr_t rangeStart;
+    rtk_filter_ip6_addr_t rangeEnd;
+} rtk_filter_ip6_t;
+
+typedef uint32 rtk_filter_number_t;
+
+typedef struct
+{
+    uint32 value[FILTER_PATTERN_MAX];
+    uint32 mask[FILTER_PATTERN_MAX];
+} rtk_filter_pattern_t;
+
+typedef struct
+{
+    rtk_filter_flag_t urg;
+    rtk_filter_flag_t ack;
+    rtk_filter_flag_t psh;
+    rtk_filter_flag_t rst;
+    rtk_filter_flag_t syn;
+    rtk_filter_flag_t fin;
+    rtk_filter_flag_t ns;
+    rtk_filter_flag_t cwr;
+    rtk_filter_flag_t ece;    
+} rtk_filter_tcpFlag_t;
+
+typedef uint32 rtk_filter_field_raw_t;
+
+struct rtk_filter_field
+{
+    uint32 fieldType;
+    
+    union
+    {
+        /* L2 struct */
+        rtk_filter_mac_t       dmac;
+        rtk_filter_mac_t       smac;
+        rtk_filter_value_t     etherType;
+        rtk_filter_tag_t       ctag;
+        rtk_filter_tag_t       relayCtag;
+        rtk_filter_tag_t       stag;
+        rtk_filter_dot1as_timestamp_t dot1asTimeStamp;
+        
+        /* L3 struct */
+        rtk_filter_ip_t      sip;
+        rtk_filter_ip_t      dip;
+        rtk_filter_value_t   protocol;
+        rtk_filter_value_t   ipTos;
+        rtk_filter_ipFlag_t  ipFlag;
+        rtk_filter_value_t   ipOffset;
+        rtk_filter_ip6_t     sipv6;
+        rtk_filter_ip6_t     dipv6;
+        rtk_filter_value_t   ipv6TrafficClass;        
+        rtk_filter_value_t   ipv6NextHeader;
+        rtk_filter_value_t   flowLabel;
+        
+        /* L4 struct */
+        rtk_filter_value_t   tcpSrcPort;
+        rtk_filter_value_t   tcpDstPort;
+        rtk_filter_tcpFlag_t tcpFlag;
+        rtk_filter_value_t   tcpSeqNumber;
+        rtk_filter_value_t   tcpAckNumber;
+        rtk_filter_value_t   udpSrcPort;
+        rtk_filter_value_t   udpDatcPort;
+        rtk_filter_value_t   icmpCode;
+        rtk_filter_value_t   icmpType;
+        rtk_filter_value_t   igmpType;
+
+        /* pattern match */
+        rtk_filter_pattern_t pattern;
+    } filter_pattern_union;
+
+    struct rtk_filter_field *next;
+};
+
+typedef enum rtk_filter_field_type_e
+{
+    FILTER_FIELD_DMAC = 0,
+    FILTER_FIELD_SMAC,
+    FILTER_FIELD_ETHERTYPE,
+    FILTER_FIELD_CTAG,
+    FILTER_FIELD_STAG, 
+    
+    FILTER_FIELD_IPV4_SIP,
+    FILTER_FIELD_IPV4_DIP,
+    FILTER_FIELD_IPV4_TOS,
+    FILTER_FIELD_IPV4_PROTOCOL,
+    FILTER_FIELD_IPV4_FLAG,
+    FILTER_FIELD_IPV4_OFFSET,
+    FILTER_FIELD_IPV6_SIPV6,
+    FILTER_FIELD_IPV6_DIPV6,
+    FILTER_FIELD_IPV6_TRAFFIC_CLASS,
+    FILTER_FIELD_IPV6_NEXT_HEADER,
+    
+    FILTER_FIELD_TCP_SPORT,
+    FILTER_FIELD_TCP_DPORT,
+    FILTER_FIELD_TCP_FLAG,
+    FILTER_FIELD_UDP_SPORT,
+    FILTER_FIELD_UDP_DPORT,
+    FILTER_FIELD_ICMP_CODE,
+    FILTER_FIELD_ICMP_TYPE,
+    FILTER_FIELD_IGMP_TYPE,
+    FILTER_FIELD_MAX
+} rtk_filter_field_type_t;
+
+typedef enum rtk_filter_field_type_raw_e
+{
+    FILTER_FIELD_RAW_DMAC_47_32 = 0,
+    FILTER_FIELD_RAW_DMAC_31_16,
+    FILTER_FIELD_RAW_DMAC_15_0,    
+    FILTER_FIELD_RAW_SMAC_47_32 = 0,
+    FILTER_FIELD_RAW_SMAC_31_16,
+    FILTER_FIELD_RAW_SMAC_15_0,    
+    FILTER_FIELD_RAW_ETHERTYPE,
+    FILTER_FIELD_RAW_CTAG,
+    FILTER_FIELD_RAW_STAG, 
+    
+    FILTER_FIELD_RAW_IPV4_SIP_31_16,
+    FILTER_FIELD_RAW_IPV4_SIP_15_0,    
+    FILTER_FIELD_RAW_IPV4_DIP_31_16,
+    FILTER_FIELD_RAW_IPV4_DIP_15_0,    
+    FILTER_FIELD_RAW_IPV4_TOS_PROTOCOL,
+    FILTER_FIELD_RAW_IPV4_FLAG_OFFSET,
+    FILTER_FIELD_RAW_IPV6_SIP_127_112,
+    FILTER_FIELD_RAW_IPV6_SIP_111_96,    
+    FILTER_FIELD_RAW_IPV6_SIP_95_80,    
+    FILTER_FIELD_RAW_IPV6_SIP_79_64,
+    FILTER_FIELD_RAW_IPV6_SIP_63_48,
+    FILTER_FIELD_RAW_IPV6_SIP_47_32,
+    FILTER_FIELD_RAW_IPV6_SIP_31_16,
+    FILTER_FIELD_RAW_IPV6_SIP_15_0,
+    FILTER_FIELD_RAW_IPV6_DIP_127_112,
+    FILTER_FIELD_RAW_IPV6_DIP_111_96,    
+    FILTER_FIELD_RAW_IPV6_DIP_95_80,    
+    FILTER_FIELD_RAW_IPV6_DIP_79_64,
+    FILTER_FIELD_RAW_IPV6_DIP_63_48,
+    FILTER_FIELD_RAW_IPV6_DIP_47_32,
+    FILTER_FIELD_RAW_IPV6_DIP_31_16,
+    FILTER_FIELD_RAW_IPV6_DIP_15_0,
+    FILTER_FIELD_RAW_IPV6_TRAFFIC_CLASS_NEXT_HEADER,
+    
+    FILTER_FIELD_RAW_L4_SPORT,
+    FILTER_FIELD_RAW_L4_DPORT,
+    FILTER_FIELD_RAW_TCP_FLAG,
+    FILTER_FIELD_RAW_ICMP_CODE_TYPE,
+    FILTER_FIELD_RAW_IGMP_TYPE,
+    FILTER_FIELD_RAW_MAX
+} rtk_filter_field_type_raw_t;
+
+
+typedef enum rtk_filter_flag_care_type_e
+{
+    FILTER_FLAG_CARE_DONT_CARE = 0,
+    FILTER_FLAG_CARE_1,
+    FILTER_FLAG_CARE_0,
+    FILTER_FLAG_END
+} rtk_filter_flag_care_type_t;
+
+typedef uint32  rtk_filter_id_t;    /* filter id type */
+
+typedef enum rtk_filter_invert_e
+{
+    FILTER_INVERT_DISABLE = 0,
+    FILTER_INVERT_ENABLE,
+    FILTER_INVERT_END
+} rtk_filter_invert_t;
+
+typedef uint32 rtk_filter_port_t;
+
+typedef uint32 rtk_filter_state_t;
+
+typedef uint32 rtk_filter_unmatch_action_t;
+
+typedef enum rtk_filter_unmatch_action_e
+{
+    FILTER_UNMATCH_DROP = 0,
+    FILTER_UNMATCH_PERMIT,
+    FILTER_UNMATCH_END
+} rtk_filter_unmatch_action_type_t;
+
+typedef struct
+{
+    rtk_filter_field_t      *fieldHead;
+    rtk_filter_care_tag_t   careTag;
+    rtk_filter_value_t      activeport;
+
+    rtk_filter_invert_t     invert;
+} rtk_filter_cfg_t;
+
+typedef struct
+{
+    rtk_filter_field_raw_t      dataFieldRaw[RTK_FILTER_RAW_FIELD_NUMBEER];     
+    rtk_filter_field_raw_t      careFieldRaw[RTK_FILTER_RAW_FIELD_NUMBEER];
+    rtk_filter_field_type_raw_t fieldRawType[RTK_FILTER_RAW_FIELD_NUMBEER];
+    rtk_filter_care_tag_t       careTag;
+    rtk_filter_value_t          activeport;
+    rtk_filter_invert_t         invert;
+    rtk_enable_t                valid;
+} rtk_filter_cfg_raw_t;
+
+typedef enum rtk_igmp_type_e
+{
+    IGMP_IPV4 = 0,
+    IGMP_PPPOE_IPV4,
+    IGMP_MLD,
+    IGMP_PPPOE_MLD,
+    IGMP_TYPE_END
+} rtk_igmp_type_t;
+
+typedef uint32 rtk_int_info_t;
+
+typedef enum rtk_int_interrupt_type_e
+{
+    INT_TYPE_LINK_STATUS = 0,
+    INT_TYPE_METER_EXCEED,
+    INT_TYPE_LEARN_LIMIT,    
+    INT_TYPE_LINK_SPEED,
+    INT_TYPE_CONGEST,
+    INT_TYPE_GREEN_FEATURE,
+    INT_TYPE_LOOP_DETECT,
+    INT_TYPE_8051,
+    INT_TYPE_END
+}rtk_int_interrupt_type_t;
+
+typedef enum rtk_int_advType_e
+{
+    ADV_L2_LEARN_PORT_MASK = 0,
+    ADV_SPEED_CHANGE_PORT_MASK,
+    ADV_SPECIAL_CONGESTION_PORT_MASK,
+    ADV_PORT_LINKDOWN_PORT_MASK,
+    ADV_PORT_LINKUP_PORT_MASK,
+    ADV_METER0_15_MASK,
+    ADV_METER16_31_MASK,
+    ADV_METER32_47,_MASK,
+    ADV_METER48_63_MASK,
+    ADV_END
+} rtk_int_advType_t;
+
+typedef enum rtk_int_polarity_e
+{
+    INT_POLAR_HIGH = 0,
+    INT_POLAR_LOW,
+    INT_POLAR_END
+} rtk_int_polarity_t;
+
+typedef struct  rtk_int_status_s
+{
+    uint8 value[RTK_MAX_NUM_OF_INTERRUPT_TYPE];
+} rtk_int_status_t;
+
+typedef enum rtk_int_type_e
+{
+    INT_LINK_CHANGE = 0,
+    INT_SPEED_CHANGE,
+    INT_RLDP,
+    INT_METER,
+    INT_LEARN_LIMIT,
+    INT_END
+} rtk_int_type_t;
+
+typedef uint32 rtk_ipaddr_t;
+
+typedef enum rtk_l2_age_time_e
+{
+    AGE_TIME_300S= 0,
+    AGE_TIME_2,
+    AGE_TIME_3,
+    AGE_TIME_4,
+    AGE_TIME_END
+} rtk_l2_age_time_t;
+
+typedef enum rtk_l2_flood_type_e
+{
+    FLOOD_UNKNOWNDA = 0,
+    FLOOD_UNKNOWNMC,
+    FLOOD_BC,
+    FLOOD_END
+} rtk_l2_flood_type_t;
+
+typedef uint32 rtk_l2_flushItem_t;
+
+typedef enum rtk_l2_flushType_e
+{
+    FLUSH_TYPE_BY_PORT = 0,       /* physical port       */
+    FLUSH_TYPE_END
+} rtk_l2_flushType_t;
+
+
+typedef enum rtk_l2_hash_method_e
+{
+    HSAH_OPT0 = 0,
+    HASH_OPT1,
+    HASH_END
+} rtk_hash_method_t;
+
+/* l2 limit learning count action */
+typedef enum rtk_l2_limitLearnCntAction_e
+{
+    LIMIT_LEARN_CNT_ACTION_DROP = 0,
+    LIMIT_LEARN_CNT_ACTION_FLOOD,
+    LIMIT_LEARN_CNT_ACTION_TO_CPU,
+    LIMIT_LEARN_CNT_ACTION_END
+} rtk_l2_limitLearnCntAction_t;
+
+typedef enum rtk_l2_lookup_type_e
+{
+    LOOKUP_MAC = 0,
+    LOOKUP_SIP_DIP,
+    LOOKUP_DIP,  
+    LOOKUP_END
+} rtk_l2_lookup_type_t;
+
+/* l2 address table - unicast data structure */
+typedef struct rtk_l2_ucastAddr_s
+{
+    rtk_mac_t   mac;
+    uint32        fid;
+    uint32        port;
+    uint32        sa_block;
+    uint32        auth;
+    uint32        is_static;
+}rtk_l2_ucastAddr_t;
+
+
+typedef enum rtk_leaky_type_e
+{
+    LEAKY_BRG_GROUP = 0,
+    LEAKY_FD_PAUSE,
+    LEAKY_SP_MCAST,
+    LEAKY_1X_PAE,
+    LEAKY_UNDEF_BRG_04,
+    LEAKY_UNDEF_BRG_05,
+    LEAKY_UNDEF_BRG_06,
+    LEAKY_UNDEF_BRG_07,    
+    LEAKY_PROVIDER_BRIDGE_GROUP_ADDRESS,
+    LEAKY_UNDEF_BRG_09,
+    LEAKY_UNDEF_BRG_0A,
+    LEAKY_UNDEF_BRG_0B,
+    LEAKY_UNDEF_BRG_0C,    
+    LEAKY_PROVIDER_BRIDGE_GVRP_ADDRESS,    
+    LEAKY_8021AB,
+    LEAKY_UNDEF_BRG_0F,    
+    LEAKY_BRG_MNGEMENT,
+    LEAKY_UNDEFINED_11,
+    LEAKY_UNDEFINED_12,
+    LEAKY_UNDEFINED_13,
+    LEAKY_UNDEFINED_14,
+    LEAKY_UNDEFINED_15,
+    LEAKY_UNDEFINED_16,
+    LEAKY_UNDEFINED_17,
+    LEAKY_UNDEFINED_18,
+    LEAKY_UNDEFINED_19,
+    LEAKY_UNDEFINED_1A,
+    LEAKY_UNDEFINED_1B,
+    LEAKY_UNDEFINED_1C,
+    LEAKY_UNDEFINED_1D,
+    LEAKY_UNDEFINED_1E,
+    LEAKY_UNDEFINED_1F,
+    LEAKY_GMRP,
+    LEAKY_GVRP,
+    LEAKY_UNDEF_GARP_22,
+    LEAKY_UNDEF_GARP_23,
+    LEAKY_UNDEF_GARP_24,
+    LEAKY_UNDEF_GARP_25,
+    LEAKY_UNDEF_GARP_26,
+    LEAKY_UNDEF_GARP_27,
+    LEAKY_UNDEF_GARP_28,
+    LEAKY_UNDEF_GARP_29,
+    LEAKY_UNDEF_GARP_2A,
+    LEAKY_UNDEF_GARP_2B,
+    LEAKY_UNDEF_GARP_2C,
+    LEAKY_UNDEF_GARP_2D,
+    LEAKY_UNDEF_GARP_2E,
+    LEAKY_UNDEF_GARP_2F,
+    LEAKY_IGMP,
+    LEAKY_IPMULTICAST,
+    LEAKY_END
+}rtk_leaky_type_t;
+
+typedef enum rtk_led_blink_rate_e
+{
+    LED_BLINKRATE_32MS=0,         
+    LED_BLINKRATE_64MS,        
+    LED_BLINKRATE_128MS,
+    LED_BLINKRATE_256MS,
+    LED_BLINKRATE_512MS,
+    LED_BLINKRATE_1024MS,
+    LED_BLINKRATE_48MS,
+    LED_BLINKRATE_96MS,
+    LED_BLINKRATE_END
+}rtk_led_blink_rate_t;
+
+typedef enum rtk_led_group_e
+{
+    LED_GROUP_0 = 0,
+    LED_GROUP_1,
+    LED_GROUP_2,
+    LED_GROUP_END
+}rtk_led_group_t;    
+
+typedef enum rtk_led_mode_e
+{
+    LED_MODE_0 = 0,
+    LED_MODE_1,
+    LED_MODE_2,
+    LED_MODE_3,
+    LED_MODE_END
+}rtk_led_mode_t;    
+
+
+typedef enum rtk_led_force_mode_e
+{
+
+    LED_FORCE_NORMAL=0,
+    LED_FORCE_BLINK,
+    LED_FORCE_OFF,
+    LED_FORCE_ON,
+    LED_FORCE_END
+}rtk_led_force_mode_t;
+
+typedef uint32  rtk_mac_cnt_t;     /* meter id type  */
+
+typedef enum rtk_mcast_type_e
+{
+    MCAST_L2 = 0,
+    MCAST_IPV4,
+    MCAST_IPV6,
+    MCAST_END
+} rtk_mcast_type_t;
+
+typedef uint32  rtk_meter_id_t;     /* meter id type  */
+
+typedef uint32  rtk_mode_t; 
+
+typedef uint32  rtk_port_t;        /* port is type */
+
+typedef enum rtk_port_duplex_e
+{
+    PORT_HALF_DUPLEX = 0,
+    PORT_FULL_DUPLEX,
+    PORT_DUPLEX_END
+} rtk_port_duplex_t;
+
+typedef enum rtk_port_linkStatus_e
+{
+    PORT_LINKDOWN = 0,
+    PORT_LINKUP,
+    PORT_LINKSTATUS_END
+} rtk_port_linkStatus_t;
+
+typedef struct  rtk_port_mac_ability_s
+{
+    uint32 forcemode;
+    uint32 speed;
+    uint32 duplex;
+    uint32 link;    
+    uint32 nway;
+    uint32 symflc;
+    uint32 txpause;
+    uint32 rxpause;      
+}rtk_port_mac_ability_t;
+
+typedef struct rtk_port_phy_ability_s
+{   
+    uint32    AutoNegotiation;  /*PHY register 0.12 setting for auto-negotiation process*/
+    uint32    Half_10;          /*PHY register 4.5 setting for 10BASE-TX half duplex capable*/
+    uint32    Full_10;          /*PHY register 4.6 setting for 10BASE-TX full duplex capable*/
+    uint32    Half_100;         /*PHY register 4.7 setting for 100BASE-TX half duplex capable*/
+    uint32    Full_100;         /*PHY register 4.8 setting for 100BASE-TX full duplex capable*/
+    uint32    Full_1000;        /*PHY register 9.9 setting for 1000BASE-T full duplex capable*/
+    uint32    FC;               /*PHY register 4.10 setting for flow control capability*/
+    uint32    AsyFC;            /*PHY register 4.11 setting for  asymmetric flow control capability*/
+} rtk_port_phy_ability_t;
+
+typedef uint32  rtk_port_phy_data_t;     /* phy page  */
+
+typedef uint32  rtk_port_phy_page_t;     /* phy page  */
+
+typedef enum rtk_port_phy_reg_e  
+{
+    PHY_REG_CONTROL             = 0,
+    PHY_REG_STATUS,
+    PHY_REG_IDENTIFIER_1,
+    PHY_REG_IDENTIFIER_2,
+    PHY_REG_AN_ADVERTISEMENT,
+    PHY_REG_AN_LINKPARTNER,
+    PHY_REG_1000_BASET_CONTROL  = 9,
+    PHY_REG_1000_BASET_STATUS,
+    PHY_REG_END                 = 32
+} rtk_port_phy_reg_t;
+
+typedef enum rtk_port_phy_test_mode_e  
+{
+    PHY_TEST_MODE_NORMAL= 0,
+    PHY_TEST_MODE_1,
+    PHY_TEST_MODE_2,
+    PHY_TEST_MODE_3,
+    PHY_TEST_MODE_4,
+    PHY_TEST_MODE_END           
+} rtk_port_phy_test_mode_t;
+
+typedef enum rtk_port_speed_e
+{
+    PORT_SPEED_10M = 0,
+    PORT_SPEED_100M,
+    PORT_SPEED_1000M,
+    PORT_SPEED_END
+} rtk_port_speed_t;
+
+typedef struct rtk_portmask_s
+{
+    uint32  bits[RTK_TOTAL_NUM_OF_WORD_FOR_1BIT_PORT_LIST];
+} rtk_portmask_t;
+
+typedef uint32  rtk_pri_t;         /*priority value */
+typedef uint32  rtk_dei_t;        /*dei value*/
+
+typedef struct rtk_priority_select_s
+{   
+    uint32 port_pri;
+    uint32 dot1q_pri;
+    uint32 acl_pri;
+    uint32 dscp_pri;
+    uint16 cvlan_pri;
+    uint32 svlan_pri;
+    uint32 dmac_pri;
+    uint32 smac_pri;
+    uint32 vid_pri;
+} rtk_priority_select_t;
+
+
+typedef uint32  rtk_qid_t;        /* queue id type */
+
+typedef struct rtk_qos_pri2queue_s
+{
+    uint32 pri2queue[RTK_MAX_NUM_OF_PRIORITY];
+} rtk_qos_pri2queue_t;
+
+typedef struct rtk_qos_queue_weights_s
+{
+    uint32 weights[RTK_MAX_NUM_OF_QUEUE];
+} rtk_qos_queue_weights_t;
+
+typedef enum rtk_qos_scheduling_type_e
+{
+    WFQ = 0,        /* Weighted-Fair-Queue */
+    WRR,            /* Weighted-Round-Robin */
+    SCHEDULING_TYPE_END
+} rtk_qos_scheduling_type_t;
+
+typedef uint32  rtk_queue_num_t;    /* queue number*/
+
+typedef enum rtk_rate_storm_group_e
+{
+    STORM_GROUP_UNKNOWN_UNICAST = 0,
+    STORM_GROUP_UNKNOWN_MULTICAST,
+    STORM_GROUP_MULTICAST,
+    STORM_GROUP_BROADCAST,
+    STORM_GROUP_END
+} rtk_rate_storm_group_t;
+
+typedef uint32  rtk_rate_t;     /* rate type  */
+
+typedef rtk_u_long_t rtk_stat_counter_t;
+
+#ifndef EMBEDDED_SUPPORT
+/* global statistic counter structure */
+typedef struct rtk_stat_global_cntr_s
+{
+    uint64 dot1dTpLearnedEntryDiscards;
+}rtk_stat_global_cntr_t;
+#endif
+
+typedef enum rtk_stat_global_type_e
+{
+    DOT1D_TP_LEARNED_ENTRY_DISCARDS_INDEX = 36,
+    MIB_GLOBAL_CNTR_END
+}rtk_stat_global_type_t;
+
+#ifndef EMBEDDED_SUPPORT
+/* port statistic counter structure */
+typedef struct rtk_stat_port_cntr_s
+{
+    uint64 ifInOctets;
+    uint32 dot3StatsFCSErrors;
+    uint32 dot3StatsSymbolErrors;
+    uint32 dot3InPauseFrames;
+    uint32 dot3ControlInUnknownOpcodes;
+    uint32 etherStatsFragments;
+    uint32 etherStatsJabbers;
+    uint32 ifInUcastPkts;
+    uint32 etherStatsDropEvents;
+    uint64 etherStatsOctets;
+    uint32 etherStatsUndersizePkts;
+    uint32 etherStatsOversizePkts;
+    uint32 etherStatsPkts64Octets;
+    uint32 etherStatsPkts65to127Octets;
+    uint32 etherStatsPkts128to255Octets;
+    uint32 etherStatsPkts256to511Octets;
+    uint32 etherStatsPkts512to1023Octets;
+    uint32 etherStatsPkts1024toMaxOctets;
+    uint32 etherStatsMcastPkts;
+    uint32 etherStatsBcastPkts;
+    uint64 ifOutOctets;
+    uint32 dot3StatsSingleCollisionFrames;
+    uint32 dot3StatsMultipleCollisionFrames;
+    uint32 dot3StatsDeferredTransmissions;
+    uint32 dot3StatsLateCollisions;
+    uint32 etherStatsCollisions;
+    uint32 dot3StatsExcessiveCollisions;
+    uint32 dot3OutPauseFrames;
+    uint32 dot1dBasePortDelayExceededDiscards;
+    uint32 dot1dTpPortInDiscards;
+    uint32 ifOutUcastPkts;
+    uint32 ifOutMulticastPkts;
+    uint32 ifOutBrocastPkts;
+    uint32 outOampduPkts;
+    uint32 inOampduPkts;
+    uint32 pktgenPkts;
+}rtk_stat_port_cntr_t;
+#endif
+
+/* port statistic counter index */
+typedef enum rtk_stat_port_type_e
+{
+    STAT_IfInOctets = 0,
+    STAT_Dot3StatsFCSErrors,
+    STAT_Dot3StatsSymbolErrors,
+    STAT_Dot3InPauseFrames,
+    STAT_Dot3ControlInUnknownOpcodes,        
+    STAT_EtherStatsFragments,
+    STAT_EtherStatsJabbers,
+    STAT_IfInUcastPkts,
+    STAT_EtherStatsDropEvents,
+    STAT_EtherStatsOctets,
+    STAT_EtherStatsUnderSizePkts,
+    STAT_EtherOversizeStats,
+    STAT_EtherStatsPkts64Octets,
+    STAT_EtherStatsPkts65to127Octets,
+    STAT_EtherStatsPkts128to255Octets,
+    STAT_EtherStatsPkts256to511Octets,
+    STAT_EtherStatsPkts512to1023Octets,
+    STAT_EtherStatsPkts1024to1518Octets,
+    STAT_EtherStatsMulticastPkts,
+    STAT_EtherStatsBroadcastPkts,    
+    STAT_IfOutOctets,
+    STAT_Dot3StatsSingleCollisionFrames,
+    STAT_Dot3StatsMultipleCollisionFrames,
+    STAT_Dot3StatsDeferredTransmissions,
+    STAT_Dot3StatsLateCollisions,
+    STAT_EtherStatsCollisions,
+    STAT_Dot3StatsExcessiveCollisions,
+    STAT_Dot3OutPauseFrames,
+    STAT_Dot1dBasePortDelayExceededDiscards,
+    STAT_Dot1dTpPortInDiscards,
+    STAT_IfOutUcastPkts,
+    STAT_IfOutMulticastPkts,
+    STAT_IfOutBroadcastPkts,
+    STAT_OutOampduPkts,
+    STAT_InOampduPkts,
+    STAT_PktgenPkts,
+    STAT_PORT_CNTR_END
+}rtk_stat_port_type_t;
+
+typedef uint32  rtk_stg_t;        /* spanning tree instance id type */
+
+typedef enum rtk_storm_bypass_e
+{
+    BYPASS_BRG_GROUP = 0,
+    BYPASS_FD_PAUSE,
+    BYPASS_SP_MCAST,
+    BYPASS_1X_PAE,
+    BYPASS_UNDEF_BRG_04,
+    BYPASS_UNDEF_BRG_05,
+    BYPASS_UNDEF_BRG_06,
+    BYPASS_UNDEF_BRG_07,    
+    BYPASS_PROVIDER_BRIDGE_GROUP_ADDRESS,
+    BYPASS_UNDEF_BRG_09,
+    BYPASS_UNDEF_BRG_0A,
+    BYPASS_UNDEF_BRG_0B,
+    BYPASS_UNDEF_BRG_0C,    
+    BYPASS_PROVIDER_BRIDGE_GVRP_ADDRESS,    
+    BYPASS_8021AB,
+    BYPASS_UNDEF_BRG_0F,    
+    BYPASS_BRG_MNGEMENT,
+    BYPASS_UNDEFINED_11,
+    BYPASS_UNDEFINED_12,
+    BYPASS_UNDEFINED_13,
+    BYPASS_UNDEFINED_14,
+    BYPASS_UNDEFINED_15,
+    BYPASS_UNDEFINED_16,
+    BYPASS_UNDEFINED_17,
+    BYPASS_UNDEFINED_18,
+    BYPASS_UNDEFINED_19,
+    BYPASS_UNDEFINED_1A,
+    BYPASS_UNDEFINED_1B,
+    BYPASS_UNDEFINED_1C,
+    BYPASS_UNDEFINED_1D,
+    BYPASS_UNDEFINED_1E,
+    BYPASS_UNDEFINED_1F,
+    BYPASS_GMRP,
+    BYPASS_GVRP,
+    BYPASS_UNDEF_GARP_22,
+    BYPASS_UNDEF_GARP_23,
+    BYPASS_UNDEF_GARP_24,
+    BYPASS_UNDEF_GARP_25,
+    BYPASS_UNDEF_GARP_26,
+    BYPASS_UNDEF_GARP_27,
+    BYPASS_UNDEF_GARP_28,
+    BYPASS_UNDEF_GARP_29,
+    BYPASS_UNDEF_GARP_2A,
+    BYPASS_UNDEF_GARP_2B,
+    BYPASS_UNDEF_GARP_2C,
+    BYPASS_UNDEF_GARP_2D,
+    BYPASS_UNDEF_GARP_2E,
+    BYPASS_UNDEF_GARP_2F,
+    BYPASS_IGMP,
+    BYPASS_END
+}rtk_storm_bypass_t;
+
+typedef uint32  rtk_stp_msti_id_t;     /* MSTI ID  */
+
+typedef enum rtk_stp_state_e
+{
+    STP_STATE_DISABLED = 0,
+    STP_STATE_BLOCKING,
+    STP_STATE_LEARNING,
+    STP_STATE_FORWARDING,
+    STP_STATE_END
+} rtk_stp_state_t;
+
+typedef uint32 rtk_svlan_index_t;
+
+typedef struct rtk_svlan_memberCfg_s{
+    uint32 svid;   
+    uint32 memberport;
+    uint32 fid;
+    uint32 priority;
+    uint32 reserved1;     
+    uint32 reserved2;    
+    uint32 reserved3; 
+    uint32 reserved4;   
+}rtk_svlan_memberCfg_t;
+
+typedef enum rtk_svlan_pri_ref_e
+{
+    REF_INTERNAL_PRI = 0,
+    REF_CTAG_PRI,
+    REF_SVLAN_PRI,
+    REF_PRI_END
+} rtk_svlan_pri_ref_t;
+
+
+typedef uint32 rtk_svlan_tpid_t;
+
+typedef enum rtk_switch_maxPktLen_e
+{
+    MAXPKTLEN_1522B = 0,
+    MAXPKTLEN_1536B,
+    MAXPKTLEN_1552B,
+    MAXPKTLEN_2000B, 
+    MAXPKTLEN_16000B,   
+    MAXPKTLEN_END   
+} rtk_switch_maxPktLen_t;
+
+typedef enum rtk_trap_igmp_action_e
+{
+    IGMP_ACTION_FORWARD = 0,
+    IGMP_ACTION_TRAP2CPU,
+    IGMP_ACTION_DROP,
+    IGMP_ACTION_FORWARD_EXCLUDE_CPU,
+    IGMP_ACTION_END
+} rtk_trap_igmp_action_t;
+
+typedef enum rtk_trap_mcast_action_e
+{
+    MCAST_ACTION_FORWARD = 0,
+    MCAST_ACTION_DROP,
+    MCAST_ACTION_TRAP2CPU,
+    MCAST_ACTION_END
+} rtk_trap_mcast_action_t;
+
+typedef enum rtk_trap_reason_type_e
+{
+    TRAP_REASON_RMA = 0,
+    TRAP_REASON_IPV4IGMP,
+    TRAP_REASON_IPV6MLD,
+    TRAP_REASON_1XEAPOL,
+    TRAP_REASON_VLANERR,
+    TRAP_REASON_SLPCHANGE,
+    TRAP_REASON_MULTICASTDLF,
+    TRAP_REASON_CFI,
+    TRAP_REASON_1XUNAUTH,
+    TRAP_REASON_END
+} rtk_trap_reason_type_t;
+
+
+typedef enum rtk_trap_rma_action_e
+{
+    RMA_ACTION_FORWARD = 0,
+    RMA_ACTION_TRAP2CPU,
+    RMA_ACTION_DROP,
+    RMA_ACTION_FORWARD_EXCLUDE_CPU,
+    RMA_ACTION_END
+} rtk_trap_rma_action_t;
+
+typedef enum rtk_trap_ucast_action_e
+{
+    UCAST_ACTION_FORWARD = 0,
+    UCAST_ACTION_DROP,
+    UCAST_ACTION_TRAP2CPU,
+    UCAST_ACTION_END
+} rtk_trap_ucast_action_t;
+
+typedef enum rtk_trap_ucast_type_e
+{
+    UCAST_UNKNOWNDA = 0,
+    UCAST_UNKNOWNSA,
+    UCAST_UNMATCHSA,
+    UCAST_END
+} rtk_trap_ucast_type_t;
+
+typedef enum rtk_trunk_group_e
+{
+    TRUNK_GROUP0 = 0,
+    TRUNK_GROUP1,
+    TRUNK_GROUP2,
+    TRUNK_GROUP3,
+    TRUNK_GROUP_END
+} rtk_trunk_group_t;
+
+typedef struct  rtk_trunk_hashVal2Port_s
+{
+    uint8 value[RTK_MAX_NUM_OF_TRUNK_HASH_VAL];
+} rtk_trunk_hashVal2Port_t;
+
+typedef uint32  rtk_vlan_proto_type_t;     /* protocol and port based VLAN protocol type  */
+
+
+typedef enum rtk_vlan_acceptFrameType_e
+{
+    ACCEPT_FRAME_TYPE_ALL = 0,             /* untagged, priority-tagged and tagged */
+    ACCEPT_FRAME_TYPE_TAG_ONLY,         /* tagged */
+    ACCEPT_FRAME_TYPE_UNTAG_ONLY,     /* untagged and priority-tagged */
+    ACCEPT_FRAME_TYPE_END
+} rtk_vlan_acceptFrameType_t;
+
+
+/* frame type of protocol vlan - reference 802.1v standard */
+typedef enum rtk_vlan_protoVlan_frameType_e
+{
+    FRAME_TYPE_ETHERNET = 0,
+    FRAME_TYPE_LLCOTHER,
+    FRAME_TYPE_RFC1042,
+    FRAME_TYPE_END
+} rtk_vlan_protoVlan_frameType_t;
+
+typedef uint32  rtk_vlan_t;        /* vlan id type */
+
+/* Protocol-and-port-based Vlan structure */
+typedef struct rtk_vlan_protoAndPortInfo_s
+{
+    uint32                         proto_type;
+    rtk_vlan_protoVlan_frameType_t frame_type;
+    rtk_vlan_t                     cvid;
+    rtk_pri_t                     cpri;
+}rtk_vlan_protoAndPortInfo_t;
+
+/* tagged mode of VLAN - reference realtek private specification */
+typedef enum rtk_vlan_tagMode_e
+{
+    VLAN_TAG_MODE_ORIGINAL = 0,
+    VLAN_TAG_MODE_KEEP_FORMAT,
+    VLAN_TAG_MODE_REAL_KEEP_FORMAT,
+    VLAN_TAG_MODE_PRI,
+    VLAN_TAG_MODE_END
+} rtk_vlan_tagMode_t;
+
+typedef uint32 rtk_mib_cntValue_t;
+typedef enum rtk_mib_cntType_e
+{
+    MIB_COUNTER_TYPE_BYTE = 0,
+    MIB_COUNTER_TYPE_PKT,
+    MIB_COUNTER_TYPE_END
+}rtk_mib_cntType_t;
+
+typedef enum rtk_mib_counter_e
+{
+    MIB_CNT1 = 0,
+    MIB_CNT2,
+    MIB_CNT3,
+    MIB_CNT4,
+    MIB_CNT5,
+    MIB_CNT_END
+}rtk_mib_counter_t;
+
+/*some type for RTL8306E*/
+
+typedef   rtl8306e_vidSrc_t   rtk_vidSrc_t;
+typedef   rtl8306e_priSrc_t    rtk_priSrc_t;    
+
+typedef struct rtk_filter_rule_e
+{
+    uint32 phyport;   /*the physical port where packet received*/
+    uint32 protocol;  /*Acl protocol which is in the packet*/
+    uint32 data;       /*16bit ether type or TCP/UDP source port, destination port value*/
+    uint32 priority;   /*Acl priority assigned to the packet*/
+    uint32 action;     /*How to deal with the packet*/
+} rtk_filter_rule_t;
+    
+
+
+#endif  /*__RTK_API_H__*/
+
+
+
diff --git a/ap/os/linux/linux-3.4.x/drivers/net/phy/realtek/rtl8306e/rtk_api_ext.h b/ap/os/linux/linux-3.4.x/drivers/net/phy/realtek/rtl8306e/rtk_api_ext.h
new file mode 100755
index 0000000..f2927a1
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/net/phy/realtek/rtl8306e/rtk_api_ext.h
@@ -0,0 +1,2384 @@
+/*
+* Copyright (C) 2010 Realtek Semiconductor Corp.
+* All Rights Reserved.
+*
+* This program is the proprietary software of Realtek Semiconductor
+* Corporation and/or its licensors, and only be used, duplicated,
+* modified or distributed under the authorized license from Realtek.
+*
+* ANY USE OF THE SOFTWARE OTEHR THAN AS AUTHORIZED UNDER 
+* THIS LICENSE OR COPYRIGHT LAW IS PROHIBITED.
+* 
+* $Revision: 26807 $ 
+* $Date: 2012-02-22 09:24:59 +0800 (星期三, 2012-02-22) $
+*
+* Purpose : Realtek common API function list supported by RTL8306E switch, 
+*               they could also be applied to chips 
+*               RTL8306M/RTL8305N/RTL8303/RTL8304E/RTL8306N
+* 
+* Feature : This file consists of following modules:
+*              (1)   Port Configuration              
+*              (2)   Rate Limit
+*              (3)   QOS
+*              (4)   TRAP
+*              (5)   VLAN
+*              (6)   Spanning Tree
+*              (7)   Address Table
+*              (8)   CPU Port
+*              (9)   Mirror
+*              (10)  IEEE 802.1x
+*              (11)  SVLAN
+*/
+
+
+#ifndef __RTK_API_EXT_H__
+#define __RTK_API_EXT_H__
+
+#include "rtl8306e_types.h"
+#include "rtk_api.h"
+
+/*
+ * Function Declaration
+ */
+ 
+/*Misc*/
+
+/* Function Name:
+ *      rtk_switch_init
+ * Description:
+ *      Set chip to default configuration enviroment
+ * Input:
+ *      none
+ * Output:
+ *      none
+ * Return:
+ *      RT_ERR_OK                     -  Success
+ *      RT_ERR_FAILED               -  Failure
+ * Note:
+ *     The API can set chip registers to default configuration for
+ *     different release chip model.
+ */ 
+extern rtk_api_ret_t rtk_switch_init(void);
+
+/* Function Name:
+ *      rtk_switch_maxPktLen_set
+ * Description:
+ *      Set the max packet length of the specific unit
+ * Input:
+ *      len       -       max packet length
+ * Output:
+ *      none
+ * Return:
+ *      RT_ERR_OK                    -  Success
+ *      RT_ERR_FAILED               -  Failure
+ *      RT_ERR_INPUT                -  Invalid input parameter
+ * Note:
+ *      The API can set max packet length of the specific unit to
+ *          MAXPKTLEN_1522B,
+ *          MAXPKTLEN_1536B,
+ *          MAXPKTLEN_1552B,
+ *          MAXPKTLEN_2000B, 
+ */ 
+extern rtk_api_ret_t rtk_switch_maxPktLen_set(rtk_switch_maxPktLen_t len); 
+
+/* Function Name:
+ *      rtk_switch_maxPktLen_get
+ * Description:
+ *      Get the max packet length of the specific unit
+ * Input:
+ *      none
+ * Output:
+ *      pLen                             -    the pointer of max packet length
+ * Return: 
+ *      RT_ERR_OK                    -  Success
+ *      RT_ERR_FAILED               -  Failure
+ *      RT_ERR_NULL_POINTER     -  Input parameter is null pointer 
+ * Note:
+ *      The API can set max packet length of the specific unit to
+ *          MAXPKTLEN_1522B,
+ *          MAXPKTLEN_1536B,
+ *          MAXPKTLEN_1552B,
+ *          MAXPKTLEN_2000B, 
+ */
+ extern rtk_api_ret_t rtk_switch_maxPktLen_get(rtk_switch_maxPktLen_t *pLen);
+
+/* Function Name:
+ *      rtk_port_phyReg_set
+ * Description:
+ *      Set PHY register data of the specific port
+ * Input:
+ *      phy                - phy number, 0 ~ 6 
+ *      reg                 - Register id
+ *      regData           - Register data
+ * Output:
+ *      none
+ * Return:
+ *      RT_ERR_OK         -  Success
+ *      RT_ERR_FAILED   -   Failure
+ * Note:
+ *      This API can set PHY register data of the specific port.
+ *      RTL8306E switch has 5 FE port, and port 4 could be set as
+ *      phy mode or mac mode, port 5 is mac mode which connect
+ *      with mii interface. so parameter phy 0 ~4 means port 0 ~4
+ *      phy register, 5 means port 4 mac mode, 6 means port 5.
+ *      
+ */
+extern rtk_api_ret_t rtk_port_phyReg_set(rtk_port_t port, rtk_port_phy_reg_t reg, rtk_port_phy_data_t value);
+
+/* Function Name:
+ *      rtk_port_phyReg_get
+ * Description:
+ *      Get PHY register data of the specific port
+ * Input:
+ *      phy                  - phy number, 0 ~ 6
+ *      reg                   - Register id
+ * Output:
+ *      pData               - the pointer of Register data
+ * Return:
+ *      RT_ERR_OK        -  Success
+ *      RT_ERR_FAILED   -  Failure
+ * Note:
+ *      This API can set PHY register data of the specific port.
+ *      RTL8306E switch has 5 FE port, and port 4 could be set as
+ *      phy mode or mac mode, port 5 is mac mode which connect
+ *      with mii interface. so parameter phy 0 ~4 means port 0 ~4
+ *      phy register, 5 means port 4 mac mode, 6 means port 5.
+ *      
+ */
+extern rtk_api_ret_t rtk_port_phyReg_get(rtk_port_t port, rtk_port_phy_reg_t reg, rtk_port_phy_data_t *pData); 
+
+/* Function Name:
+ *      rtk_port_phyAutoNegoAbility_set
+ * Description:
+ *      Set ethernet PHY auto-negotiation desired ability
+ * Input:
+ *      port       -  Port id
+ *      pAbility   -  Ability structure
+ * Output:
+ *      none
+ * Return:
+ *      RT_ERR_OK                        
+ *      RT_ERR_FAILED                  
+ *      RT_ERR_SMI       
+ *      RT_ERR_PORT_ID
+ *      RT_ERR_PHY_REG_ID
+ *      RT_ERR_NULL_POINTER
+ *      RT_ERR_BUSYWAIT_TIMEOUT
+ *     
+ * Note:
+ *      (1) RTL8306E switch only has 5 phy, so the input port id should be 0~4.
+ *      (2) In auto-negotiation mode, phy autoNegotiation ability must be enabled
+ */ 
+extern rtk_api_ret_t rtk_port_phyAutoNegoAbility_set(rtk_port_t port, rtk_port_phy_ability_t *pAbility);
+
+/* Function Name:
+ *      rtk_port_phyAutoNegoAbility_get
+ * Description:
+ *      Get ethernet PHY auto-negotiation desired ability
+ * Input:
+ *      port       -  Port id
+ * Output:
+ *      pAbility   -  Ability structure
+ * Return:
+ *      RT_ERR_OK                        
+ *      RT_ERR_FAILED                  
+ *      RT_ERR_SMI       
+ *      RT_ERR_PORT_ID
+ *      RT_ERR_PHY_REG_ID
+ *      RT_ERR_NULL_POINTER
+ *      RT_ERR_PHY_AUTO_NEGO_MODE
+ *      RT_ERR_BUSYWAIT_TIMEOUT
+ *     
+ * Note:
+ *      (1) RTL8306E switch only has 5 phy, so the input port id should be 0~4.
+ *      (2) In auto-negotiation mode, phy autoNegotiation ability must be enabled
+ */  
+extern rtk_api_ret_t rtk_port_phyAutoNegoAbility_get(rtk_port_t port, rtk_port_phy_ability_t *pAbility);
+
+/* Function Name:
+ *     rtk_port_phyForceModeAbility_set
+ * Description:
+ *      Set the port PHY force mode, config its speed/duplex mode/pause/asy_pause 
+ * Input:
+ *      port       -  Port id
+ *      pAbility   -  Ability structure
+ * Output:
+ *      none
+ * Return:
+ *      RT_ERR_OK                        
+ *      RT_ERR_FAILED                  
+ *      RT_ERR_SMI       
+ *      RT_ERR_PORT_ID
+ *      RT_ERR_PHY_REG_ID
+ *      RT_ERR_NULL_POINTER
+ *      RT_ERR_PHY_FORCE_1000
+ *      RT_ERR_BUSYWAIT_TIMEOUT
+ *     
+ * Note:
+ *      (1) RTL8306E switch only has 5 phy, so the input port id should be 0~4.
+ *      (2) In force mode,  phy autoNegotiation ability must be disabled.
+ */
+extern rtk_api_ret_t rtk_port_phyForceModeAbility_set(rtk_port_t port, rtk_port_phy_ability_t *pAbility);
+
+/* Function Name:
+ *      rtk_port_phyForceModeAbility_get
+ * Description:
+ *      Get the port PHY speed/duplex mode/pause/asy_pause in force mode
+ * Input:
+ *      port       -  Port id
+ * Output:
+ *      pAbility   -  Ability structure
+ * Return:
+ *      RT_ERR_OK                        
+ *      RT_ERR_FAILED                  
+ *      RT_ERR_SMI       
+ *      RT_ERR_PORT_ID
+ *      RT_ERR_PHY_REG_ID
+ *      RT_ERR_NULL_POINTER
+ *      RT_ERR_BUSYWAIT_TIMEOUT
+ *     
+ * Note:
+ *      (1) RTL8306E switch only has 5 phy, so the input port id should be 0~4.
+ *      (2) In force mode, phy autoNegotiation ability must be disabled.
+ */
+extern rtk_api_ret_t rtk_port_phyForceModeAbility_get(rtk_port_t port, rtk_port_phy_ability_t *pAbility);
+
+/* Function Name:
+ *      rtk_port_phyStatus_get
+ * Description:
+ *      Get ethernet PHY linking status
+ * Input:
+ *      port             -  Port id
+ * Output:
+ *      pLinkStatus   -  the pointer of PHY link status 
+ *      pSpeed         -  the pointer of PHY link speed
+ *      pDuplex        -  the pointer of PHY duplex 
+ * Return:
+ *      RT_ERR_OK                        
+ *      RT_ERR_FAILED                  
+ *      RT_ERR_SMI       
+ *      RT_ERR_PORT_ID
+ *      RT_ERR_NULL_POINTER
+ *     
+ * Note:
+ *      RTL8306E switch only has 5 phy, so the input port id should be 0~4.
+ */
+extern rtk_api_ret_t rtk_port_phyStatus_get(rtk_port_t port, rtk_port_linkStatus_t *pLinkStatus, rtk_port_speed_t *pSpeed, rtk_port_duplex_t *pDuplex);
+
+/* Function Name:
+ *      rtk_port_macForceLinkExt0_set
+ * Description:
+ *      Set external interface 1(MAC 5) force linking configuration.
+ * Input:
+ *      mode - external interface mode
+ *      pPortability - port ability configuration
+ * Output:
+ *      None 
+ * Return:
+ *      RT_ERR_OK              - Success
+ *      RT_ERR_FAILED          - Failure
+ *      RT_ERR_INPUT       - Invalid input parameters.
+ * Note:
+ *      (1) This API can set external interface 1(MAC 5) force mode properties,
+ *      including link status,speed,duplex,and tx pause and tx pause ability.
+ *      In force mode, autoNegotiation ability must be disabled.
+ *      (2) For 8306E, the external interface 1(MAC 5) operating mode can be
+ *      MAC Mode (T)MII, PHY Mode (T)MII and RMII. The operating mode is 
+ *      determined by strapping pin upon reset, and can not be configured 
+ *      by software, except the selection of MII or TMII. 
+ *      (3)The input parament mode here is only used to select MII or TMII.
+ *      When operating mode is configured as MAC Mode (T)MII or PHY Mode (T)MII
+ *      via strapping pin, then the selection of MII or TMII can be done via software.
+ *      For example, set mode MODE_EXT_TMII_MAC to select TMII, and set mode
+ *      MODE_EXT_MII_MAC to select MII.
+ */
+extern rtk_api_ret_t rtk_port_macForceLinkExt0_set(rtk_mode_ext_t mode, rtk_port_mac_ability_t *pPortability);
+
+/* Function Name:
+ *      rtk_port_macForceLinkExt0_get
+ * Description:
+ *      Get external interface 1(MAC 5) force linking configuration.
+ * Input:
+ *      None
+ * Output:
+ *      pMode - external interface mode
+ *      pPortability - port ability configuration
+ * Return:
+ *      RT_ERR_OK              - Success
+ *      RT_ERR_FAILED          - Failure 
+ *      RT_ERR_INPUT - Invalid input parameters.
+ * Note:
+ *      This API can get external interface 1 (MAC 5) force mode properties.
+ *      The external interface 1 operating mode can be:
+ *      - MODE_EXT_MII_MAC,
+ *      - MODE_EXT_MII_PHY, 
+ *      - MODE_EXT_TMII_MAC,
+ *      - MODE_EXT_TMII_PHY, 
+ *      - MODE_EXT_RMII, 
+ */
+extern rtk_api_ret_t rtk_port_macForceLinkExt0_get(rtk_mode_ext_t *pMode, rtk_port_mac_ability_t *pPortability);
+
+/* Function Name:
+ *      rtk_port_macForceLinkExt_set
+ * Description:
+ *      Set external interface force linking configuration.
+ * Input:
+ *      port    -   port number
+ *      mode - external interface mode
+ *      pPortability - port ability configuration
+ * Output:
+ *      None 
+ * Return:
+ *      RT_ERR_OK              - Success
+ *      RT_ERR_FAILED          - Failure
+ *      RT_ERR_INPUT       - Invalid input parameters.
+ * Note:
+ *      (1) This API can set external interface 0 and 1(MAC4 and MAC 5)force mode properties,
+ *      including link status,speed,duplex,and tx pause and tx pause ability.
+ *      In force mode, autoNegotiation ability must be disabled.
+ *      (2) For 8306E, the external interface 0(MAC 4) operating mode can be
+ *      MAC Mode MII, PHY Mode MII and RMII. The operating mode is 
+ *      determined by strapping pin upon reset, and can not be configured 
+ *      by software.  
+ *      (3) For 8306E, the external interface 1(MAC 5) operating mode can be
+ *      MAC Mode (T)MII, PHY Mode (T)MII and RMII. The operating mode is 
+ *      determined by strapping pin upon reset, and can not be configured 
+ *      by software, except the selection of MII or TMII. 
+ *      (4)The input parament mode here is only used to select MII or TMII. And it only takes effect
+ *      for external interface 1, neither for external interface 0.
+ *      When operating mode is configured as MAC Mode (T)MII or PHY Mode (T)MII
+ *      via strapping pin, then the selection of MII or TMII can be done via software.
+ *      For example, set mode MODE_EXT_TMII_MAC to select TMII, and set mode
+ *      MODE_EXT_MII_MAC to select MII.
+ */
+extern rtk_api_ret_t rtk_port_macForceLinkExt_set(rtk_port_t port, rtk_mode_ext_t mode, rtk_port_mac_ability_t *pPortability);
+
+/* Function Name:
+ *      rtk_port_macForceLinkExt_get
+ * Description:
+ *      Get external interface force linking configuration.
+ * Input:
+ *      port    -   port number
+ * Output:
+ *      pMode - external interface mode
+ *      pPortability - port ability configuration
+ * Return:
+ *      RT_ERR_OK              - Success
+ *      RT_ERR_FAILED          - Failure 
+ *      RT_ERR_INPUT - Invalid input parameters.
+ * Note:
+ *      This API can get external interface 0 (MAC 4) and 1 (MAC 5) force mode properties.
+ *      The external interface 0 operating mode can be:
+ *      - MODE_EXT_MII_MAC,
+ *      - MODE_EXT_MII_PHY, 
+ *      - MODE_EXT_RMII,     
+ *      The external interface 1 operating mode can be:
+ *      - MODE_EXT_MII_MAC,
+ *      - MODE_EXT_MII_PHY, 
+ *      - MODE_EXT_TMII_MAC,
+ *      - MODE_EXT_TMII_PHY, 
+ *      - MODE_EXT_RMII, 
+ */
+extern rtk_api_ret_t rtk_port_macForceLinkExt_get(rtk_port_t port, rtk_mode_ext_t *pMode, rtk_port_mac_ability_t *pPortability);
+
+#ifdef CHIP_RTL8304E
+/* Function Name:
+ *      rtk_port_mii1Disable_set
+ * Description:
+ *      Disable MII1 for RTL8304E by trunk
+ * Input:
+ *      none
+ * Output:
+ *      none
+ * Return:
+ *      RT_ERR_OK
+ * Note:
+ *      Strapping pin 49 can be used to force MII1 link down for RTL8306E.
+ *      But there are no strapping pins or registers for RTL8304E to do so.
+ *      To disable MII1 for RTL8304E, trunk can be used. First enable trunk function,
+ *      Then trunk rtl8306e's port3 and port4 to be a trunk port. After this port2(MII1) is 
+ *      forced to be linking down for RTL8304E.    
+*/
+extern rtk_api_ret_t rtk_port_mii1Disable_set(void);
+#endif
+
+/* Function Name:
+ *      rtk_port_isolation_set
+ * Description:
+ *      Set permitted port isolation portmask
+ * Input:
+ *      port                - port id, 0 ~ 5 
+ *      portmask         - Permit port mask
+ * Output:
+ *      none
+ * Return:
+ *      RT_ERR_OK             -   Success
+ *      RT_ERR_PORT_ID     -   Invalid port number
+ *      RT_ERR_PORT_MASK -   Invalid portmask
+ *      RT_ERR_FAILED        -   Failure
+ * Note:
+ *      This API set the port mask that a port can trasmit packet to of each port.
+ *      A port can only transmit packet to ports included in permitted portmask  
+ */
+extern rtk_api_ret_t rtk_port_isolation_set(rtk_port_t port, rtk_portmask_t portmask);
+
+/* Function Name:
+ *      rtk_port_isolation_get
+ * Description:
+ *      Get permitted port isolation portmask
+ * Input:
+ *      port                - port id, 0 ~ 5 
+ * Output:
+ *      pPortmask       - the pointer of permit port mask
+ * Return:
+ *      RT_ERR_OK                  -   Success
+ *      RT_ERR_PORT_ID          -   Invalid port number
+ *      RT_ERR_NULL_POINTER  -   Input parameter is null pointer
+ *      RT_ERR_FAILED             -   Failure
+ * Note:
+ *      This API get the port mask that a port can trasmit packet to of each port.
+ *      A port can only transmit packet to ports included in permitted portmask  
+ */
+ 
+extern rtk_api_ret_t rtk_port_isolation_get(rtk_port_t port, rtk_portmask_t *pPortmask);
+
+/* Function Name:
+ *      rtk_stat_port_reset
+ * Description:
+ *      Reset per port MIB counter by port.
+ * Input:
+ *      port - port id.
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK              - set shared meter successfully
+ *      RT_ERR_FAILED          - FAILED to iset shared meter
+ * Note:
+ */
+extern rtk_api_ret_t rtk_stat_port_reset(rtk_port_t port);
+
+
+/* Function Name:
+ *      rtk_rate_igrBandwidthCtrlRate_set
+ * Description:
+ *      Set port ingress bandwidth control
+ * Input:
+ *      port            -  Port id
+ *      rate            -  Rate of share meter
+ *      ifg_include   -  Rate's calculation including IFG, ENABLE:include DISABLE:exclude
+ * Output:
+ *      none
+ * Return:
+ *      RT_ERR_OK              -  Success
+ *      RT_ERR_PORT_ID      -  Invalid port number
+ *      RT_ERR_FAILED        -  Failure
+ *      RT_ERR_ENABLE       -  Invalid IFG parameter
+ *      RT_ERR_INBW_RATE -  Invalid ingress rate parameter
+ * Note:
+ *      The rate unit is 64Kbps and the range is from 64Kbps to 100Mbps. The granularity of rate is 64Kbps. 
+ *      The ifg_include parameter is used for rate calculation with/without inter-frame-gap and preamble. 
+ */ 
+extern rtk_api_ret_t rtk_rate_igrBandwidthCtrlRate_set( rtk_port_t port, rtk_rate_t rate,  rtk_enable_t ifg_include);
+
+/* Function Name:
+ *      rtk_rate_igrBandwidthCtrlRate_get
+ * Description:
+ *      Get port ingress bandwidth control
+ * Input:
+ *      port             -  Port id
+ * Output:
+ *      pRate           -  the pointer of rate of share meter
+ *      pIfg_include   -  Rate's calculation including IFG, ENABLE:include DISABLE:exclude
+ * Return:
+ *      RT_ERR_OK                      -  Success
+ *      RT_ERR_PORT_ID              -  Invalid port number
+ *      RT_ERR_FAILED                -  Failure
+ *      RT_ERR_ENABLE               -  Invalid IFG parameter
+ *      RT_ERR_NULL_POINTER      -  null pointer
+ * Note:
+ *      The rate unit is 64Kbps and the range is from 64Kbps to 100Mbps. The granularity of rate is 64Kbps. 
+ *      The ifg_include parameter is used for rate calculation with/without inter-frame-gap and preamble. 
+ */
+extern rtk_api_ret_t rtk_rate_igrBandwidthCtrlRate_get(rtk_port_t port, rtk_rate_t *pRate, rtk_enable_t *pIfg_include);
+
+/* Function Name:
+ *      rtk_rate_egrBandwidthCtrlRate_set
+ * Description:
+ *      Set port egress bandwidth control
+ * Input:
+ *      port            -  Port id
+ *      rate            -  Rate of bandwidth control
+ *      ifg_include   -  Rate's calculation including IFG, ENABLE:include DISABLE:exclude
+ * Output:
+ *      none
+ * Return:
+ *      RT_ERR_OK                   -  Success
+ *      RT_ERR_PORT_ID           -  Invalid port number
+ *      RT_ERR_FAILED             -  Failure
+ *      RT_ERR_ENABLE             -  Invalid IFG parameter
+ *      RT_ERR_QOS_EBW_RATE -  Invalid egress rate parameter
+ * Note:
+ *      The rate unit is 64Kbps and the range is from 64Kbps to 100Mbps. The granularity of rate is 64Kbps. 
+ *      The ifg_include parameter is used for rate calculation with/without inter-frame-gap and preamble. 
+ */
+extern rtk_api_ret_t rtk_rate_egrBandwidthCtrlRate_set(rtk_port_t port, rtk_rate_t rate,  rtk_enable_t ifg_include);
+
+/* Function Name:
+ *      rtk_rate_igrBandwidthCtrlRate_get
+ * Description:
+ *      Get port ingress bandwidth control
+ * Input:
+ *      port             -  Port id
+ * Output:
+ *      pRate           -  the pointer of rate of bandwidth control
+ *      pIfg_include   -  Rate's calculation including IFG, ENABLE:include DISABLE:exclude
+ * Return:
+ *      RT_ERR_OK                     -  Success
+ *      RT_ERR_PORT_ID             -  Invalid port number
+ *      RT_ERR_FAILED                -  Failure
+ *      RT_ERR_NULL_POINTER      -  null pointer
+ * Note:
+ *      The rate unit is 64Kbps and the range is from 64Kbps to 100Mbps. The granularity of rate is 64Kbps. 
+ *      The ifg_include parameter is used for rate calculation with/without inter-frame-gap and preamble. 
+ */
+extern rtk_api_ret_t rtk_rate_egrBandwidthCtrlRate_get(rtk_port_t port, rtk_rate_t *pRate, rtk_enable_t *pIfg_include);
+
+/* QoS */
+
+/* Function Name:
+ *      rtk_qos_init
+ * Description:
+ *      Configure Qos default settings with queue number assigment to each port
+ * Input:
+ *      queueNum     -  Queue number of each port
+ * Output:
+ *      none
+ * Return:
+ *      RT_ERR_OK                     -  Success
+ *      RT_ERR_FAILED                -  Failure
+ *      RT_ERR_QUEUE_NUM         -  Error queue number
+ * Note:
+ *    This API will initialize related Qos setting with queue number assigment.
+ *    The queue number is from 1 to 4.
+ */ 
+extern rtk_api_ret_t rtk_qos_init(rtk_queue_num_t queueNum);
+
+/* Function Name:
+ *      rtk_qos_1pPriRemap_set
+ * Description:
+ *      Configure 1Q priorities mapping to internal absolute priority
+ * Input:
+ *      dot1p_pri   -  802.1p priority value
+ *      int_pri       -  internal priority value
+ * Output:
+ *      none
+ * Return:
+ *      RT_ERR_OK                         -  Success
+ *      RT_ERR_FAILED                    -  Failure
+ *      RT_ERR_VLAN_PRIORITY        -  Invalid 1p priority
+ *      RT_ERR_QOS_INT_PRIORITY   -  Invalid priority
+ * Note:
+ *      Priority of 802.1Q assignment for internal asic priority, and it is used for queue usage 
+ *      and packet scheduling.
+ */ 
+extern rtk_api_ret_t rtk_qos_1pPriRemap_set(rtk_pri_t dot1p_pri, rtk_pri_t int_pri);
+
+/* Function Name:
+ *      rtk_qos_priSel_set
+ * Description:
+ *      Configure the priority order among different priority mechanisms.
+ * Input:
+ *      pPriDec - priority level for port, dscp, 802.1Q, ACL and VID based priority decision.
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK              - success
+ *      RT_ERR_NULL_POINTER  -   Input parameter is null pointer
+ *      RT_ERR_FAILED          - failure 
+ *      RT_ERR_QOS_SEL_PRI_SOURCE - Invalid priority decision source parameter.
+ * Note: 
+ *      (1)For 8306E, there are 5 types of priority mechanisms that could be set arbitration level, which are 
+ *      ACL-based  priority, DSCP-based priority, 1Q-based priority, Port-based priority, VID-based priority.
+ *      Each one could be set level from 1 to 5.
+ *      (2)ASIC will follow user's arbitration level setting of priority mechanisms to select internal priority for receiving frame. 
+ *      If two priority mechanisms are the same level, the ASIC will chose the priority mechanism with highest level to 
+ *      assign internal priority to receiving frame.
+ */
+extern rtk_api_ret_t rtk_qos_priSel_set(rtk_priority_select_t *pPriDec);
+
+/* Function Name:
+ *      rtk_qos_priSel_get
+ * Description:
+ *      Get the priority order configuration among different priority mechanism.
+ * Input:
+ *      None
+ * Output:
+ *      pPriDec - priority level for port, dscp, 802.1Q, ACL and VID based priority decision.
+ * Return:
+ *      RT_ERR_OK              - success
+ *      RT_ERR_NULL_POINTER  -   Input parameter is null pointer
+ *      RT_ERR_FAILED          - failure 
+ * Note:
+ *      (1)For 8306E, there are 5 types of priority mechanisms that could be set arbitration level, which are 
+ *      ACL-based  priority, DSCP-based priority, 1Q-based priority,Port-based priority, VID-based priority.
+ *      Each one could be set level from 1 to 5.
+ *      (2)ASIC will follow user's arbitration level setting of priority mechanisms to select internal priority for receiving frame. 
+ *      If two priority mechanisms are the same level, the ASIC will chose the priority mechanism with the highest level to 
+ *      assign internal priority to receiving frame.
+ */
+extern rtk_api_ret_t rtk_qos_priSel_get(rtk_priority_select_t *pPriDec);
+
+/* Function Name:
+ *      rtk_qos_1pPriRemap_get
+ * Description:
+ *      Get 1Q priorities mapping to internal absolute priority
+ * Input:
+ *      dot1p_pri    -  802.1p priority value
+ * Output:
+ *      pInt_pri      -  the pointer of internal priority value
+ * Return:
+ *      RT_ERR_OK                         -  Success
+ *      RT_ERR_FAILED                    -  Failure
+ *      RT_ERR_VLAN_PRIORITY        -  Invalid 1p priority
+ *      RT_ERR_NULL_POINTER         -   null pointer
+ * Note:
+ *      Priority of 802.1Q assignment for internal asic priority, and it is used for queue usage 
+ *      and packet scheduling.
+ */
+extern rtk_api_ret_t rtk_qos_1pPriRemap_get(rtk_pri_t dot1p_pri, rtk_pri_t *pInt_pri);
+
+/* Function Name:
+ *      rtk_qos_dscpPriRemap_set
+ * Description:
+ *      Set DSCP-based priority
+ * Input:
+ *      code      -  dscp code
+ *      int_pri    -  internal priority value
+ * Output:
+ *      none
+ * Return:
+ *      RT_ERR_OK                         -  Success
+ *      RT_ERR_FAILED                    -  Failure
+ *      RT_ERR_QOS_INT_PRIORITY   -  invalid internal priority
+ *      RT_ERR_QOS_DSCP_VALUE    -   invalid DSCP value  
+ * Note:
+ *      switch support 16 kinds of dscp code:
+ *          RTL8306_DSCP_EF          
+ *                 - DSCP for the Expedited forwarding PHB, 101110   
+ *          RTL8306_DSCP_AFL1         
+ *                 - DSCP for AF PHB Class 1 low drop, 001010
+ *          RTL8306_DSCP_AFM1     
+ *                 - DSCP for AF PHB Class 1 medium drop, 001100
+ *          RTL8306_DSCP_AFH1      
+ *                 - DSCP for AF PHB Class 1 high drop, 001110
+ *          RTL8306_DSCP_AFL2       
+ *                 - DSCP for AF PHB Class 2 low drop, 01001
+ *          RTL8306_DSCP_AFM2       
+ *                 - DSCP for AF PHB Class 2 medium drop, 010100
+ *          RTL8306_DSCP_AFH2   
+ *                 - DSCP for AF PHB Class 2 high drop, 010110
+ *          RTL8306_DSCP_AFL3    
+ *                 - DSCP for AF PHB Class 3 low drop, 011010
+ *          RTL8306_DSCP_AFM3      
+ *                 - DSCP for AF PHB Class 3 medium drop, 011100
+ *          RTL8306_DSCP_AFH3    
+ *                 - DSCP for AF PHB Class 3 high drop, 0111
+ *          RTL8306_DSCP_AFL4     
+ *                 - DSCP for AF PHB Class 4 low drop, 100010
+ *          RTL8306_DSCP_AFM4    
+ *                 - DSCP for AF PHB Class 4 medium drop, 100100
+ *          RTL8306_DSCP_AFH4     
+ *                 - DSCP for AF PHB Class 4 high drop, 100110
+ *          RTL8306_DSCP_NC        
+ *                 - DSCP for network control, 110000 or 111000
+ *          RTL8306_DSCP_REG_PRI 
+ *                 - DSCP Register match priority, user could define two dscp code
+ *          RTL8306_DSCP_BF        
+ *                 - DSCP Default PHB
+ *
+ *     The Differentiated Service Code Point is a selector for router's per-hop behaviors. As a selector, there is no implication that a numerically 
+ *     greater DSCP implies a better network service. As can be seen, the DSCP totally overlaps the old precedence field of TOS. So if values of 
+ *     DSCP are carefully chosen then backward compatibility can be achieved.         
+ */ 
+extern rtk_api_ret_t rtk_qos_dscpPriRemap_set(rtk_dscp_t dscp, rtk_pri_t int_pri);
+
+/* Function Name:
+ *      rtk_qos_dscpPriRemap_get
+ * Description:
+ *      Get DSCP-based priority
+ * Input:
+ *      dscp      -  dscp code
+ * Output:
+ *      pInt_pri  -  the pointer of internal priority value
+ * Return:
+ *      RT_ERR_OK                           -  Success
+ *      RT_ERR_FAILED                     -  Failure
+ *      RT_ERR_QOS_DSCP_VALUE      -  Invalid DSCP value
+ *      RT_ERR_NULL_POINTER           -  Input parameter is null pointer
+ * Note:
+ *      switch support 16 kinds of dscp code:
+ *          RTL8306_DSCP_EF          
+ *                 - DSCP for the Expedited forwarding PHB, 101110   
+ *          RTL8306_DSCP_AFL1         
+ *                 - DSCP for AF PHB Class 1 low drop, 001010
+ *          RTL8306_DSCP_AFM1     
+ *                 - DSCP for AF PHB Class 1 medium drop, 001100
+ *          RTL8306_DSCP_AFH1      
+ *                 - DSCP for AF PHB Class 1 high drop, 001110
+ *          RTL8306_DSCP_AFL2       
+ *                 - DSCP for AF PHB Class 2 low drop, 01001
+ *          RTL8306_DSCP_AFM2       
+ *                 - DSCP for AF PHB Class 2 medium drop, 010100
+ *          RTL8306_DSCP_AFH2   
+ *                 - DSCP for AF PHB Class 2 high drop, 010110
+ *          RTL8306_DSCP_AFL3    
+ *                 - DSCP for AF PHB Class 3 low drop, 011010
+ *          RTL8306_DSCP_AFM3      
+ *                 - DSCP for AF PHB Class 3 medium drop, 011100
+ *          RTL8306_DSCP_AFH3    
+ *                 - DSCP for AF PHB Class 3 high drop, 0111
+ *          RTL8306_DSCP_AFL4     
+ *                 - DSCP for AF PHB Class 4 low drop, 100010
+ *          RTL8306_DSCP_AFM4    
+ *                 - DSCP for AF PHB Class 4 medium drop, 100100
+ *          RTL8306_DSCP_AFH4     
+ *                 - DSCP for AF PHB Class 4 high drop, 100110
+ *          RTL8306_DSCP_NC        
+ *                 - DSCP for network control, 110000 or 111000
+ *          RTL8306_DSCP_REG_PRI 
+ *                 - DSCP Register match priority, user could define two dscp code
+ *          RTL8306_DSCP_BF        
+ *                 - DSCP Default PHB
+ *     The Differentiated Service Code Point is a selector for router's per-hop behaviors. As a selector, there is no implication that a numerically 
+ *     greater DSCP implies a better network service. As can be seen, the DSCP totally overlaps the old precedence field of TOS. So if values of 
+ *     DSCP are carefully chosen then backward compatibility can be achieved.         
+ */ 
+extern rtk_api_ret_t rtk_qos_dscpPriRemap_get(rtk_dscp_t dscp, rtk_pri_t *pInt_pri);
+
+/* Function Name:
+ *      rtk_qos_portPri_set
+ * Description:
+ *      Configure priority usage to each port
+ * Input:
+ *      port                - Port id.                
+ *      int_pri             -  internal priority value
+ * Output:
+ *      none
+ * Return:
+ *      RT_ERR_OK                        -  Success
+ *      RT_ERR_FAILED                  -   Failure
+ *      RT_ERR_PORT_ID                -   Error port id
+ *      RT_ERR_QOS_INT_PRIORITY  -   Error internal priority value
+ * Note:
+ *     The API can set priority of port assignments for queue usage and packet scheduling.
+ */
+ 
+extern rtk_api_ret_t rtk_qos_portPri_set(rtk_port_t port, rtk_pri_t int_pri) ;
+
+/* Function Name:
+ *      rtk_qos_portPri_get
+ * Description:
+ *      Get priority usage to each port
+ * Input:
+ *      port                  - Port id.                
+ * Output:
+ *      pInt_pri             -  the pointer of internal priority value
+ * Return:
+ *      RT_ERR_OK                        -  Success
+ *      RT_ERR_FAILED                  -   Failure
+ *      RT_ERR_PORT_ID                -   Error port id
+ *      RT_ERR_NULL_POINTER        -   null pointer
+ * Note:
+ *      The API can get priority of port assignments for queue usage and packet scheduling.
+ */
+ 
+extern rtk_api_ret_t rtk_qos_portPri_get(rtk_port_t port, rtk_pri_t *pInt_pri) ;
+
+/* Function Name:
+ *      rtk_qos_priMap_set
+ * Description:
+ *      Set internal priority mapping to queue ID for different queue number
+ * Input:
+ *      queue_num       - Queue number usage
+ *      pPri2qid            - Priority mapping to queue ID               
+ * Output:
+ *      none
+ * Return:
+ *      RT_ERR_OK                        -  Success
+ *      RT_ERR_FAILED                  -   Failure
+ *      RT_ERR_QUEUE_ID              -   Error queue id
+ *      RT_ERR_NULL_POINTER        -   null pointer
+ * Note:
+ *      ASIC supports priority mapping to queue with different queue number from 1 to 4.
+ *      For different queue numbers usage, ASIC supports different internal available queue IDs.
+ */
+
+extern rtk_api_ret_t rtk_qos_priMap_set(rtk_queue_num_t queue_num, rtk_qos_pri2queue_t *pPri2qid);
+
+/* Function Name:
+ *      rtk_qos_priMap_get
+ * Description:
+ *      Get priority to queue ID mapping table parameters
+ * Input:
+ *      queue_num       - Queue number usage
+ *      pPri2qid            - Priority mapping to queue ID               
+ * Output:
+ *      none
+ * Return:
+ *      RT_ERR_OK                        -  Success
+ *      RT_ERR_FAILED                  -   Failure
+ *      RT_ERR_QUEUE_ID              -   Error queue id
+ *      RT_ERR_NULL_POINTER        -   null pointer
+ * Note:
+ *      ASIC supports priority mapping to queue with different queue number from 1 to 4.
+ *      For different queue numbers usage, ASIC supports different internal available queue IDs.
+ */
+ 
+extern rtk_api_ret_t rtk_qos_priMap_get(rtk_queue_num_t queue_num, rtk_qos_pri2queue_t *pPri2qid);
+
+/* Function Name:
+ *      rtk_qos_1pRemarkEnable_set
+ * Description:
+ *      Set 802.1P remarking ability
+ * Input:
+ *      port       -  port number (0~5)
+ *      enabled  -  TRUE or FALSE
+ * Output:
+ *      none
+ * Return:
+ *      RT_ERR_OK              -  Success
+ *      RT_ERR_FAILED        -   Failure
+ *      RT_ERR_PORT_ID      -   Invalid port id
+ * Note:
+ *      
+ */
+extern rtk_api_ret_t rtk_qos_1pRemarkEnable_set(rtk_port_t port, rtk_enable_t enable); 
+
+/* Function Name:
+ *      rtk_qos_1pRemarkEnable_get
+ * Description:
+ *      Get 802.1P remarking ability
+ * Input:
+ *      port        -  port number (0~5)
+ * Output:
+ *      pEnabled  -  pointer of the ability status
+ * Return:
+ *      RT_ERR_OK                     -  Success
+ *      RT_ERR_FAILED               -   Failure
+ *      RT_ERR_PORT_ID             -   Invalid port id
+ *      RT_ERR_NULL_POINTER     -   Input parameter is null pointer
+ * Note:
+ *      
+ */
+extern rtk_api_ret_t rtk_qos_1pRemarkEnable_get(rtk_port_t port, rtk_enable_t *pEnable);
+
+/* Function Name:
+ *      rtk_qos_1pRemark_set
+ * Description:
+ *      Set 802.1P remarking priority
+ * Input:
+ *      int_pri        -  Packet priority(0~4)
+ *      dot1p_pri    -  802.1P priority(0~7)
+ * Output:
+ *      none
+ * Return:
+ *      RT_ERR_OK                           - Success
+ *      RT_ERR_FAILED                      - Failure
+ *      RT_ERR_VLAN_PRIORITY          - Invalid 1p priority
+ *      RT_ERR_QOS_INT_PRIORITY     - Invalid internal priority 
+ * Note:
+ *      switch determines packet priority, the priority souce could
+ *      be port-based, 1Q-based, dscp-based, vid-based, ip address,
+ *      cpu tag.
+ */ 
+extern rtk_api_ret_t rtk_qos_1pRemark_set(rtk_pri_t int_pri, rtk_pri_t dot1p_pri);
+
+/* Function Name:
+ *      rtk_qos_1pRemark_get
+ * Description:
+ *      Get 802.1P remarking priority
+ * Input:
+ *      int_pri        -  Packet priority(0~4)
+ * Output:
+ *      pDot1p_pri  -  the pointer of 802.1P priority(0~7)
+ * Return:
+ *      RT_ERR_OK                           -  Success
+ *      RT_ERR_FAILED                      -  Failure
+ *      RT_ERR_NULL_POINTER            -  Input parameter is null pointer
+ *      RT_ERR_QOS_INT_PRIORITY     -  Invalid internal priority 
+ * Note:
+ *      switch determines packet priority, the priority souce could
+ *      be port-based, 1Q-based, dscp-based, vid-based, ip address,
+ *      cpu tag.
+ */
+extern rtk_api_ret_t rtk_qos_1pRemark_get(rtk_pri_t int_pri, rtk_pri_t *pDot1p_pri);
+
+/* Trap & Reserved Multicast Address (More Action like leaky, bypass storm not define) */
+
+/* Function Name:
+ *      rtk_trap_unknownMcastPktAction_set
+ * Description:
+ *      Set behavior of unknown multicast
+ * Input:
+ *      port                -   port id
+ *      type               -   unknown multicast packet type
+ *      mcast_action    -  unknown multicast action
+ * Output:
+ *      none
+ * Return:
+ *      RT_ERR_OK                      -  Success
+ *      RT_ERR_FAILED                -  Failure
+ *      RT_ERR_PORT_ID              -  Invalid port id    
+ *      RT_ERR_INPUT                 -  Invalid input parameter 
+ * Note:
+ *      When receives an unknown multicast packet, switch may trap, drop this packet
+ *      The unknown multicast packet type is as following:
+ *               - MCAST_IPV4
+ *               - MCAST_IPV6
+ *      The unknown multicast action is as following:
+ *               - MCAST_ACTION_FORWARD
+ *               - MCAST_ACTION_DROP
+ */
+extern rtk_api_ret_t rtk_trap_unknownMcastPktAction_set(rtk_port_t port, rtk_mcast_type_t type, rtk_trap_mcast_action_t mcast_action);
+
+/* Function Name:
+ *      rtk_trap_unknownMcastPktAction_get
+ * Description:
+ *      Get behavior of unknown multicast
+ * Input:
+ *      port                  -   port id
+ *      type                 -   unknown multicast packet type
+ * Output:
+ *      pMcast_action    -   the pointer of unknown multicast action
+ * Return:
+ *      RT_ERR_OK                      -  Success
+ *      RT_ERR_FAILED                -  Failure
+ *      RT_ERR_PORT_ID              -  Invalid port id    
+ *      RT_ERR_NULL_POINTER      -  Input parameter is null pointer
+ * Note:
+ *      When receives an unknown multicast packet, switch may trap, drop this packet.
+ *      The unknown multicast packet type is as following:
+ *               - MCAST_IPV4
+ *               - MCAST_IPV6
+ *      The unknown multicast action is as following:
+ *               - MCAST_ACTION_FORWARD
+ *               - MCAST_ACTION_DROP
+ */
+extern rtk_api_ret_t rtk_trap_unknownMcastPktAction_get(rtk_port_t port, rtk_mcast_type_t type, rtk_trap_mcast_action_t *pMcast_action);
+
+/* Function Name:
+ *      rtk_trap_igmpCtrlPktAction_set
+ * Description:
+ *      Set IGMP/MLD trap function
+ * Input:
+ *      type                -   IGMP/MLD packet type
+ *      igmp_action      -   IGMP/MLD action
+ * Output:
+ *      none
+ * Return:
+ *      RT_ERR_OK                      -  Success
+ *      RT_ERR_FAILED                -  Failure
+ *      RT_ERR_INPUT                 -  Invalid input parameter
+ *      RT_ERR_NOT_ALLOWED     -  Actions not allowed by the function
+ * Note:
+ *      This API can set both IPv4 IGMP/IPv6 MLD with/without PPPoE header trapping function.
+ *      All 4 kinds of IGMP/MLD function can be set separately.
+ *      The IGMP/MLD packet type is as following:
+ *          - IGMP_IPV4
+ *          - IGMP_MLD
+ *          - IGMP_PPPOE_IPV4
+ *          - IGMP_PPPOE_MLD
+ *      The IGMP/MLD action is as following:
+ *          - IGMP_ACTION_FORWARD
+ *          - IGMP_ACTION_TRAP2CPU
+ */  
+extern rtk_api_ret_t rtk_trap_igmpCtrlPktAction_set(rtk_igmp_type_t type, rtk_trap_igmp_action_t igmp_action);
+
+/* Function Name:
+ *      rtk_trap_igmpCtrlPktAction_get
+ * Description:
+ *      Get IGMP/MLD trap function
+ * Input:
+ *      type                -   IGMP/MLD packet type
+ * Output:
+ *      pIgmp_action    -   the pointer of IGMP/MLD action
+ * Return:
+ *      RT_ERR_OK                      -  Success
+ *      RT_ERR_FAILED                -  Failure
+ *      RT_ERR_INPUT                 -  Invalid input parameter
+ *      RT_ERR_NULL_POINTER      -  Input parameter is null pointer
+ * Note:
+ *      This API can get both IPv4 IGMP/IPv6 MLD with/without PPPoE header trapping function.
+ *      All 4 kinds of IGMP/MLD function can be set separately.
+ *      The IGMP/MLD packet type is as following:
+ *          - IGMP_IPV4
+ *          - IGMP_MLD
+ *          - IGMP_PPPOE_IPV4
+ *          - IGMP_PPPOE_MLD
+ *      The IGMP/MLD action is as following:
+ *          - IGMP_ACTION_FORWARD
+ *          - IGMP_ACTION_TRAP2CPU
+ */
+extern rtk_api_ret_t rtk_trap_igmpCtrlPktAction_get(rtk_igmp_type_t type, rtk_trap_igmp_action_t *pIgmp_action);
+
+
+/* CVLAN */
+
+/* Function Name:
+ *      rtk_vlan_init
+ * Description:
+ *      Initialize VLAN
+ * Input:
+ *      none
+ * Output:
+ *      none
+ * Return:
+ *      RT_ERR_OK                     -  Success
+ *      RT_ERR_FAILED                -  Failure
+ * Note:
+ *      VLAN is disabled by default. User has to call this API to enable VLAN before
+ *      using it. And It will set a default VLAN(vid 1) including all ports and set 
+ *      all ports PVID to the default VLAN.
+ */
+extern rtk_api_ret_t rtk_vlan_init(void);
+
+/* Function Name:
+ *      rtk_vlan_set
+ * Description:
+ *      Set a VLAN entry
+ * Input:
+ *      vid              - VLAN ID to configure, should be 1~4094
+ *      mbrmsk        - VLAN member set portmask
+ *      untagmsk     - VLAN untag set portmask
+ *      fid              -  filtering database id, could be any value for RTL8306E
+ * Output:
+ *      none
+ * Return:
+ *      RT_ERR_OK                     -  Success
+ *      RT_ERR_FAILED                -  Failure
+ *      RT_ERR_VLAN_VID            -  Invalid vid
+ *      RT_ERR_INPUT                 -  Invalid input parameter 
+ *      RT_ERR_TBL_FULL            -  Input table full 
+ * Note:
+ *     There are 16 VLAN entry supported. User could configure the member set and untag set
+ *     for specified vid through this API. The portmask's bit N means port N.
+ *     For example, mbrmask 23=0x17=010111 means port 0,1,2,4 in the member set.
+ *     FID is for SVL/IVL usage, and the range is 0~4095, rtl8306E only supports SVL, 
+ *     so fid is no useage.
+ */
+extern rtk_api_ret_t rtk_vlan_set(rtk_vlan_t vid, rtk_portmask_t mbrmsk, rtk_portmask_t untagmsk, rtk_fid_t fid);
+
+/* Function Name:
+ *      rtk_vlan_get
+ * Description:
+ *      Get a VLAN entry
+ * Input:
+ *      vid             - VLAN ID to configure
+ * Output:
+ *      pMbrmsk     - VLAN member set portmask
+ *      pUntagmsk  - VLAN untag set portmask
+ *      pFid           -  filtering database id
+ * Return:
+ *      RT_ERR_OK                                   -  Success
+ *      RT_ERR_FAILED                              -  Failure
+ *      RT_ERR_VLAN_VID                          -  Invalid vid
+ *      RT_ERR_NULL_POINTER                    -  Input parameter is null pointer
+ *      RT_ERR_VLAN_ENTRY_NOT_FOUND    -   Specified vlan entry not found
+ * Note:
+ *     There are 16 VLAN entry supported. User could configure the member set and untag set
+ *     for specified vid through this API. The portmask's bit N means port N.
+ *     For example, mbrmask 23=0x17=010111 means port 0,1,2,4 in the member set.
+ *     FID is for SVL/IVL usage, and the range is 0~4095, rtl8306E only supports SVL, 
+ *     so fid is no useage.
+ */
+extern rtk_api_ret_t rtk_vlan_get(rtk_vlan_t vid, rtk_portmask_t *pMbrmsk, rtk_portmask_t *pUntagmsk, rtk_fid_t *pFid);
+
+/* Function Name:
+ *      rtk_vlan_destroy
+ * Description:
+ *      delete vid from vlan table
+ * Input:
+ *      vid             - VLAN ID to configure
+ * Output:
+ *      none
+ * Return:
+ *      RT_ERR_OK                                   -  Success
+ *      RT_ERR_FAILED                              -  Failure
+ *      RT_ERR_VLAN_VID                          -  Invalid vid
+ *      RT_ERR_VLAN_ENTRY_NOT_FOUND    -  Specified vlan entry not found
+ * Note:
+ * 
+ */ 
+extern rtk_api_ret_t rtk_vlan_destroy(rtk_vlan_t vid);
+
+/* Function Name:
+ *      rtk_vlan_portPvid_set
+ * Description:
+ *      Set port to specified VLAN ID(PVID)
+ * Input:
+ *      port             - Port id
+ *      pvid             - Specified VLAN ID
+ *      priority         - 802.1p priority for the PVID, 0~3 for RTL8306E 
+ * Output:
+ *      none
+ * Return:
+ *      RT_ERR_OK                                   -  Success
+ *      RT_ERR_FAILED                              -  Failure
+ *      RT_ERR_VLAN_VID                          -  Invalid vid
+ *      RT_ERR_VLAN_PRIORITY                  -  Invalid 1p priority 
+ *      RT_ERR_VLAN_ENTRY_NOT_FOUND    -  Specified vlan entry not found
+ * Note:
+ *      The API is used for Port-based VLAN. The untagged frame received from the
+ *      port will be classified to the specified VLAN and assigned to the specified priority.
+ */
+extern rtk_api_ret_t rtk_vlan_portPvid_set(rtk_port_t port, rtk_vlan_t pvid, rtk_pri_t priority);
+
+/* Function Name:
+ *      rtk_vlan_portPvid_get
+ * Description:
+ *      Get VLAN ID(PVID) on specified port
+ * Input:
+ *      port             - Port id
+ * Output:
+ *      pPvid            - Specified VLAN ID
+ *      pPriority        - 802.1p priority for the PVID
+ * Return:
+ *      RT_ERR_OK                                   - Success
+ *      RT_ERR_FAILED                             -  Failure
+ *      RT_ERR_PORT_ID                           -  Invalid port id
+ *      RT_ERR_NULL_POINTER                   -  Input parameter is null pointer
+ * Note:
+ *    The API is used for Port-based VLAN. The untagged frame received from the
+ *    port will be classified to the specified VLAN and assigned to the specified priority.
+ */
+extern rtk_api_ret_t rtk_vlan_portPvid_get(rtk_port_t port, rtk_vlan_t *pPvid, rtk_pri_t *pPriority);
+
+/* Function Name:
+ *      rtk_vlan_portIgrFilterEnable_set
+ * Description:
+ *      Set VLAN ingress for each port
+ * Input:
+ *      port             - Port id
+ *      igr_filter        - VLAN ingress function enable status
+ * Output:
+ *      none
+ * Return:
+ *      RT_ERR_OK                        - Success
+ *      RT_ERR_FAILED                  -  Failure
+ * Note:
+ *      RTL8306E use one ingress filter for whole system, not for each port, so 
+ *      any port you set will affect all ports ingress filter setting.
+ *      While VLAN function is enabled, ASIC will decide VLAN ID for each received frame 
+ *      and get belonged member ports from VLAN table. If received port is not belonged 
+ *      to VLAN member ports, ASIC will drop received frame if VLAN ingress function is enabled.
+ */
+extern rtk_api_ret_t rtk_vlan_portIgrFilterEnable_set(rtk_port_t port, rtk_enable_t igr_filter);
+
+/* Function Name:
+ *      rtk_vlan_portIgrFilterEnable_get
+ * Description:
+ *      get VLAN ingress for each port
+ * Input:
+ *      port             - Port id
+ * Output:
+ *      pIgr_filter     - the pointer of VLAN ingress function enable status
+ * Return:
+ *      RT_ERR_OK                 - Success
+ *      RT_ERR_FAILED           -  Failure
+ * Note:
+ *      RTL8306E use one ingress filter for whole system, not for each port, so 
+ *      any port you set will affect all ports ingress filter setting.
+ *      While VLAN function is enabled, ASIC will decide VLAN ID for each received frame 
+ *      and get belonged member ports from VLAN table. If received port is not belonged 
+ *      to VLAN member ports, ASIC will drop received frame if VLAN ingress function is enabled.
+ */
+extern rtk_api_ret_t rtk_vlan_portIgrFilterEnable_get(rtk_port_t port, rtk_enable_t *pIgr_filter);
+
+/* Function Name:
+ *      rtk_vlan_portAcceptFrameType_set
+ * Description:
+ *      Set VLAN support frame type
+ * Input:
+ *      port                                 - Port id
+ *      accept_frame_type             - accept frame type
+ * Output:
+ *      none
+ * Return:
+ *      RT_ERR_OK                  - Success
+ *      RT_ERR_FAILED            -  Failure
+ *      RT_ERR_PORT_ID          -  Invalid port id
+ * Note:
+ *      The API is used for checking 802.1Q tagged frames.
+ *      The accept frame type as following:
+ *          - ACCEPT_FRAME_TYPE_ALL
+ *          - ACCEPT_FRAME_TYPE_TAG_ONLY
+ *          - ACCEPT_FRAME_TYPE_UNTAG_ONLY
+ */
+extern rtk_api_ret_t rtk_vlan_portAcceptFrameType_set(rtk_port_t port, rtk_vlan_acceptFrameType_t accept_frame_type);
+
+/* Function Name:
+ *      rtk_vlan_portAcceptFrameType_get
+ * Description:
+ *      Get VLAN support frame type
+ * Input:
+ *      port                                 - Port id
+ *      accept_frame_type             - accept frame type
+ * Output:
+ *      none
+ * Return:
+ *      RT_ERR_OK                                   - Success
+ *      RT_ERR_FAILED                             -  Failure
+ *      RT_ERR_PORT_ID                           -  Invalid port id
+ *      RT_ERR_VLAN_ACCEPT_FRAME_TYPE -  Invalid accept frame type 
+ * Note:
+ *    The API is used for checking 802.1Q tagged frames.
+ *    The accept frame type as following:
+ *    - ACCEPT_FRAME_TYPE_ALL
+ *    - ACCEPT_FRAME_TYPE_TAG_ONLY
+ *    - ACCEPT_FRAME_TYPE_UNTAG_ONLY
+ */
+extern rtk_api_ret_t rtk_vlan_portAcceptFrameType_get(rtk_port_t port, rtk_vlan_acceptFrameType_t *pAccept_frame_type);
+
+/* Function Name:
+ *      rtk_vlan_vlanBasedPriority_set
+ * Description:
+ *      Set VLAN priority for each CVLAN
+ * Input:
+ *      vid                -Specified VLAN ID
+ *      priority           -priority for the VID
+ * Output:
+ *      none
+ * Return:
+ *      RT_ERR_OK                                -  Success
+ *      RT_ERR_FAILED                          -   Failure
+ *      RT_ERR_VLAN_VID                       -  Invalid vid 
+ *      RT_ERR_VLAN_PRIORITY               -  Invalid 1p priority
+ *      RT_ERR_VLAN_ENTRY_NOT_FOUND -  Specified vlan entry not found
+ * Note:
+ *      This API is used to set priority per VLAN.
+ */ 
+extern rtk_api_ret_t rtk_vlan_vlanBasedPriority_set(rtk_vlan_t vid, rtk_pri_t priority);
+
+/* Function Name:
+ *      rtk_vlan_vlanBasedPriority_get
+ * Description:
+ *      Get VLAN priority for each CVLAN
+ * Input:
+ *      vid                -Specified VLAN ID
+ * Output:
+ *      pPriority         -the pointer of priority for the VID
+ * Return:
+ *      RT_ERR_OK                                -  Success
+ *      RT_ERR_FAILED                          -   Failure
+ *      RT_ERR_VLAN_VID                       -  Invalid vid 
+ *      RT_ERR_NULL_POINTER                -   Input parameter is null pointer
+ *      RT_ERR_VLAN_ENTRY_NOT_FOUND -   Specified vlan entry not found 
+ * Note:
+ *      This API is used to set priority per VLAN.
+ */ 
+extern rtk_api_ret_t rtk_vlan_vlanBasedPriority_get(rtk_vlan_t vid, rtk_pri_t *pPriority);
+
+/* Function Name:
+ *      rtk_vlan_vidTranslation_set
+ * Description:
+ *      Set vid translated to new vid
+ * Input:
+ *      vid       -  old vid
+ *      nvid     -   new vid
+ * Output:
+ *      none
+ * Return:
+ *      RT_ERR_OK                                -  Success
+ *      RT_ERR_FAILED                          -   Failure
+ *      RT_ERR_VLAN_VID                       -  Invalid vid 
+ *      RT_ERR_VLAN_ENTRY_NOT_FOUND -   Specified vlan entry not found 
+ * Note:
+ *      This API is used to translate a vid to a new vid, the new vid could be 
+ *      used by Q-in-Q or vlan translation function.
+ */
+extern rtk_api_ret_t rtk_vlan_vidTranslation_set(rtk_vlan_t vid, rtk_vlan_t nvid);
+
+/* Function Name:
+ *      rtk_vlan_vidTranslation_get
+ * Description:
+ *      Get vid translation new vid
+ * Input:
+ *      vid        -  old vid
+ * Output:
+ *      pNvid     -  the pointer of new vid
+ * Return:
+ *      RT_ERR_OK                                -  Success
+ *      RT_ERR_FAILED                          -   Failure
+ *      RT_ERR_VLAN_VID                       -  Invalid vid 
+ *      RT_ERR_NULL_POINTER                -   NULL pointer
+ *      RT_ERR_VLAN_ENTRY_NOT_FOUND -   Specified vlan entry not found 
+ * Note:
+ *      This API is used to translate a vid to a new vid, the new vid could be 
+ *      used by Q-in-Q or vlan translation function.
+ */
+extern rtk_api_ret_t rtk_vlan_vidTranslation_get(rtk_vlan_t vid, rtk_vlan_t *pNvid);
+
+
+/* Function Name:
+ *      rtk_vlan_vidTranslationEnable_set
+ * Description:
+ *      Set vlan translation function enabled or disabled 
+ * Input:
+ *      enable        -  enable or disable
+ *      nniMask      -   NNI port mask
+ * Output:
+ *      pNvid     -  the pointer of new vid
+ * Return:
+ *      RT_ERR_OK                                -  Success
+ *      RT_ERR_FAILED                          -   Failure
+ *      RT_ERR_PORT_MASK                   -   Error port mask
+ * Note:
+ *      VLAN translation only happens between UNI and NNI port, 
+ *      in nniMask, 1 means the port is NNI port, 0 means the port
+ *      is UNI port
+ */
+extern rtk_api_ret_t rtk_vlan_vidTranslationEnable_set(rtk_enable_t enable, rtk_portmask_t nniMask);
+
+/* Function Name:
+ *      rtk_vlan_vidTranslationEnable_get
+ * Description:
+ *      Get vlan translation function enabled or disabled 
+ * Input:
+ * Output:
+ *      pEnable      -   the pointer of enable or disable
+ *      pNniMask    -   the pointer of NNI port mask
+ * Return:
+ *      RT_ERR_OK                                -  Success
+ *      RT_ERR_FAILED                          -   Failure
+ *      RT_ERR_NULL_POINTER                -   NULL pointer
+ * Note:
+ *      VLAN translation only happens between UNI and NNI port, 
+ *      in nniMask, 1 means the port is NNI port, 0 means the port
+ *      is UNI port
+ */
+
+extern rtk_api_ret_t rtk_vlan_vidTranslationEnable_get(rtk_enable_t *pEnable, rtk_portmask_t *pNniMask);
+
+
+/* Function Name:
+ *      rtk_vlan_tagSrc_set
+ * Description:
+ *      Set tag vid and priority source for Q-in-Q and VLAN translation
+ * Input:
+ *      port          -    port id
+ *      vidSrc       -    vid source
+ *      priSrc        -    priority source
+ * Output:
+ *      none
+ * Return:
+ *      RT_ERR_OK                 -  Success
+ *      RT_ERR_FAILED            -   Failure
+ *      RT_ERR_PORT_ID          -   error port id
+ * Note:
+ *     Q-in-Q(SVLAN) and VLAN translation will modify tag, 
+ *      the API could set outer tag or translated VLAN tag
+ *      vid/priority source.
+ *      - vidSrc: 
+ *                - RTL8306E_VIDSRC_POVID - port-based otag vid,     
+ *                - RTL8306E_VIDSRC_NVID   - new vid(translated vid)
+ *       - priSrc:
+ *                - RTL8306E_PRISRC_PPRI    - port-based otag priority, 
+ *                - RTL8306E_PRISRC_1PRMK - 1p remarking priority
+ */
+extern rtk_api_ret_t rtk_vlan_tagSrc_set(rtk_port_t port, rtk_vidSrc_t vidSrc, rtk_priSrc_t priSrc);
+
+/* Function Name:
+ *      rtk_vlan_tagSrc_get
+ * Description:
+ *      Get tag vid and priority source for Q-in-Q and VLAN translation
+ * Input:
+ *      port          -    port id
+ * Output:
+ *      pVidSrc     -    the pointer of vid source
+ *      pPriSrc      -    the pointer of priority source
+ * Return:
+ *      RT_ERR_OK                 -  Success
+ *      RT_ERR_FAILED            -   Failure
+ *      RT_ERR_PORT_ID          -   error port id
+ * Note:
+ *      Q-in-Q(SVLAN) and VLAN translation will modify tag, 
+ *      the API could set outer tag or tranlated VLAN tag
+ *      vid/priority source.
+ *      - vidSrc: 
+ *                - RTL8306E_VIDSRC_POVID - port-based otag vid,     
+ *                - RTL8306E_VIDSRC_NVID   - new vid(translated vid)
+ *       - priSrc:
+ *                - RTL8306E_PRISRC_PPRI    - port-based otag priority, 
+ *                - RTL8306E_PRISRC_1PRMK - 1p remarking priority
+ */
+extern rtk_api_ret_t rtk_vlan_tagSrc_get(rtk_port_t port, rtk_vidSrc_t *pVidSrc, rtk_priSrc_t *pPriSrc);    
+
+
+
+/*Spanning Tree*/
+
+/* Function Name:
+ *      rtk_stp_mstpState_set
+ * Description:
+ *      Configure spanning tree state per port
+ * Input:
+ *      msti              - Multiple spanning tree instance, no use for RTL8306E
+ *      port              - Port id
+ *      stp_state       - Spanning tree state
+ * Output:
+ *      none
+ * Return:
+ *      RT_ERR_OK                      -  Success
+ *      RT_ERR_FAILED                -  Failure
+ *      RT_ERR_PORT_ID              -  Invalid port id
+ *      RT_ERR_MSTP_STATE        -  Invalid spanning tree status
+ * Note:
+ *      Because RTL8306E does not support multiple spanning tree, so msti is no use. 
+ *      There are four states supported by ASIC.
+ *          - STP_STATE_DISABLED
+ *          - STP_STATE_BLOCKING
+ *          - STP_STATE_LEARNING
+ *          - STP_STATE_FORWARDING
+ */
+extern rtk_api_ret_t rtk_stp_mstpState_set(rtk_stp_msti_id_t msti, rtk_port_t port, rtk_stp_state_t stp_state);
+
+/* Function Name:
+ *      rtk_stp_mstpState_get
+ * Description:
+ *      Get Configuration of spanning tree state per port
+ * Input:
+ *      msti              - Multiple spanning tree instance, no use for RTL8306E
+ *      port              - Port id
+ * Output:
+ *      pStp_state     - the pointer of Spanning tree state
+ * Return:
+ *      RT_ERR_OK                      -  Success
+ *      RT_ERR_FAILED                -  Failure
+ *      RT_ERR_PORT_ID              -  Invalid port id
+ *      RT_ERR_NULL_POINTER      -  Input parameter is null pointer
+ * Note:
+ *      Because RTL8306E does not support multiple spanning tree, so msti is no use. 
+ *      There are four states supported by ASIC.
+ *          - STP_STATE_DISABLED
+ *          - STP_STATE_BLOCKING
+ *          - STP_STATE_LEARNING
+ *          - STP_STATE_FORWARDING
+ */
+extern rtk_api_ret_t rtk_stp_mstpState_get(rtk_stp_msti_id_t msti, rtk_port_t port, rtk_stp_state_t *pStp_state);
+
+/* LUT */
+
+/* Function Name:
+ *      rtk_l2_addr_add
+ * Description:
+ *      Set LUT unicast entry
+ * Input:
+ *      pMac               -   6 bytes unicast(I/G bit is 0) mac address to be written into LUT
+ *      pL2_data          -   the mac address attributes
+ * Output:
+ *      none
+ * Return:
+ *      RT_ERR_OK                       -  Success
+ *      RT_ERR_FAILED                 -   Failure
+ *      RT_ERR_INPUT                  -   Invalid input parameter
+ *      RT_ERR_MAC                    -   Wrong mac address, must be unicast mac        
+ *      RT_ERR_NULL_POINTER       -  Input parameter is null pointer    
+ *      RT_ERR_L2_INDEXTBL_FULL -  The L2 index table is full
+ * Note:
+ *      If the unicast mac address already existed in LUT, it will udpate the status of the entry. 
+ *      Otherwise, it will find an empty or asic auto learned entry to write. If all the entries 
+ *      with the same hash value can't be replaced, ASIC will return a RT_ERR_L2_INDEXTBL_FULL error.
+ *      for RTL8306E, pL2_data member fid and sa_block is no use, so it can be chosen any value.
+ */
+extern rtk_api_ret_t rtk_l2_addr_add(rtk_mac_t *pMac, rtk_l2_ucastAddr_t *pL2_data);
+
+/* Function Name:
+ *      rtk_l2_addr_get
+ * Description:
+ *      Get LUT unicast entry
+ * Input:
+ *      pMac               -   6 bytes unicast(I/G bit is 0) mac address to be gotten
+ *      fid                   -   filtering database id, could be any value for RTL8306E switch
+ * Output:
+ *      pL2_data          -   the mac address attributes
+ * Return:
+ *      RT_ERR_OK                               -  Success
+ *      RT_ERR_FAILED                         -   Failure
+ *      RT_ERR_INPUT                          -   Invalid input parameter
+ *      RT_ERR_MAC                            -   Wrong mac address, must be unicast mac        
+ *      RT_ERR_NULL_POINTER              -   Input parameter is null pointer    
+ *      RT_ERR_L2_ENTRY_NOTFOUND    -   Specified entry not found
+ * Note:
+ *      If the unicast mac address existed in LUT, it will return the port where
+ *      the mac is learned, 802.1x authorized status and dynamic/static entry,
+ *      Otherwise, it will return a RT_ERR_L2_ENTRY_NOTFOUND error.
+ */
+extern rtk_api_ret_t rtk_l2_addr_get(rtk_mac_t *pMac, rtk_fid_t fid, rtk_l2_ucastAddr_t *pL2_data);
+
+/* Function Name:
+ *      rtk_l2_addr_del
+ * Description:
+ *      Delete LUT unicast entry
+ * Input:
+ *      pMac               -   6 bytes unicast mac address to be deleted
+ *      fid                   -   filtering database id, could be any value for RTL8306E switch
+ * Output:
+ *      none
+ * Return:
+ *      RT_ERR_OK                               -  Success
+ *      RT_ERR_FAILED                         -   Failure
+ *      RT_ERR_INPUT                          -   Invalid input parameter
+ *      RT_ERR_MAC                            -   Wrong mac address, must be unicast mac        
+ *      RT_ERR_NULL_POINTER              -   Input parameter is null pointer    
+ *      RT_ERR_L2_ENTRY_NOTFOUND    -   Specified entry not found 
+ * Note:
+ *      If the mac has existed in the LUT, it will be deleted.
+ *      Otherwise, it will return RT_ERR_L2_ENTRY_NOTFOUND.
+ */
+extern rtk_api_ret_t rtk_l2_addr_del(rtk_mac_t *pMac, rtk_fid_t fid); 
+
+/* Function Name:
+ *      rtk_l2_mcastAddr_add
+ * Description:
+ *      Add LUT multicast entry
+ * Input:
+ *      pMac               -   6 bytes unicast mac address to be deleted
+ *      fid                   -   filtering database id, could be any value for RTL8306E switch
+ *      portmask          -   Port mask to be forwarded to 
+ * Output:
+ *      none
+ * Return:
+ *      RT_ERR_OK                               -  Success
+ *      RT_ERR_FAILED                         -   Failure
+ *      RT_ERR_INPUT                          -   Invalid input parameter
+ *      RT_ERR_PORT_MASK                  -   Invalid port mask
+ *      RT_ERR_MAC                            -   Wrong mac address, must be unicast mac        
+ *      RT_ERR_L2_INDEXTBL_FULL         -   Hashed index is full of entries
+ * Note:
+ *      If the multicast mac address already existed in the LUT, it will udpate the
+ *      port mask of the entry. Otherwise, it will find an empty or asic auto learned
+ *      entry to write. If all the entries with the same hash value can't be replaced, 
+ *      ASIC will return a RT_ERR_L2_INDEXTBL_FULL error.
+ */
+extern rtk_api_ret_t rtk_l2_mcastAddr_add(rtk_mac_t *pMac, rtk_fid_t fid, rtk_portmask_t portmask);
+
+/* Function Name:
+ *      rtk_l2_mcastAddr_get
+ * Description:
+ *      Get LUT multicast entry
+ * Input:
+ *      pMac               -   6 bytes multicast(I/G bit is 0) mac address to be gotten
+ *      fid                   -   filtering database id, could be any value for RTL8306E switch
+ * Output:
+ *      pPortmask         -   the pointer of port mask      
+ * Return:
+ *      RT_ERR_OK                               -  Success
+ *      RT_ERR_FAILED                         -   Failure
+ *      RT_ERR_INPUT                          -   Invalid input parameter
+ *      RT_ERR_NULL_POINTER              -   Input parameter is null pointer    
+ *      RT_ERR_MAC                            -   Wrong mac address, must be unicast mac        
+ *      RT_ERR_L2_INDEXTBL_FULL         -   Hashed index is full of entries 
+ * Note:
+ *      If the multicast mac address existed in LUT, it will return the port mask where
+ *      the packet should be forwarded to, Otherwise, it will return a 
+ *      RT_ERR_L2_ENTRY_NOTFOUND error.
+ */
+extern rtk_api_ret_t rtk_l2_mcastAddr_get(rtk_mac_t *pMac, rtk_fid_t fid, rtk_portmask_t *pPortmask);
+
+/* Function Name:
+ *      rtk_l2_mcastAddr_del
+ * Description:
+ *      Delete LUT unicast entry
+ * Input:
+ *      pMac               -   6 bytes multicast(I/G bit is 1) mac address to be gotten
+ *      fid                   -   filtering database id, could be any value for RTL8306E switch
+ * Output:
+*       none
+ * Return:
+ *      RT_ERR_OK                               -  Success
+ *      RT_ERR_FAILED                         -   Failure
+ *      RT_ERR_INPUT                          -   Invalid input parameter
+ *      RT_ERR_MAC                            -   Wrong mac address, must be unicast mac        
+ *      RT_ERR_L2_ENTRY_NOTFOUND     -   No such LUT entry
+ * Note:
+ *      If the mac has existed in the LUT, it will be deleted.
+ *      Otherwise, it will return RT_ERR_L2_ENTRY_NOTFOUND.
+ */
+extern rtk_api_ret_t rtk_l2_mcastAddr_del(rtk_mac_t *pMac, rtk_fid_t fid);    
+
+/* Function Name:
+ *      rtk_l2_limitLearningCnt_set
+ * Description:
+ *      Set per-Port auto learning limit number
+ * Input:
+ *      port - Port id.
+ *      mac_cnt - Auto learning entries limit number
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK              - set shared meter successfully
+ *      RT_ERR_FAILED          - FAILED to iset shared meter
+ *      RT_ERR_PORT_ID - Invalid port number.
+ *      RT_ERR_LIMITED_L2ENTRY_NUM - Invalid auto learning limit number
+ * Note:
+ *      (1)The API can set per-port ASIC auto learning limit number from 0(disable learning) 
+ *      to 0x1F(31). 
+ *      (2)If mac_cnt is set from 0 to 0x1F, per-port ASIC auto learning limit will be enabled;
+ *      if mac_cnt is set 0xFF, per-port ASIC auto learning limit will be disabled.
+ */
+extern rtk_api_ret_t rtk_l2_limitLearningCnt_set(rtk_port_t port, rtk_mac_cnt_t mac_cnt);
+
+/* Function Name:
+ *      rtk_l2_limitLearningCnt_get
+ * Description:
+ *      Get per-Port auto learning limit number
+ * Input:
+ *      port - Port id.
+ * Output:
+ *      pMac_cnt - Auto learning entries limit number
+ * Return:
+ *      RT_ERR_OK              - Success
+ *      RT_ERR_FAILED          - Failure 
+ *      RT_ERR_PORT_ID - Invalid port number. 
+ * Note:
+ *      The API can get per-port ASIC auto learning limit number.
+ */
+extern rtk_api_ret_t rtk_l2_limitLearningCnt_get(rtk_port_t port, rtk_mac_cnt_t *pMac_cnt);
+
+/* Function Name:
+ *      rtk_l2_limitLearningCntAction_set
+ * Description:
+ *      Configure auto learn over limit number action.
+ * Input:
+ *      port - Port id (must be RTK_WHOLE_SYSTEM)
+ *      action - Auto learning entries limit number
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK              - Success
+ *      RT_ERR_FAILED          - Failure 
+ *      RT_ERR_PORT_ID - Invalid port number.
+ *      RT_ERR_NOT_ALLOWED - Invalid learn over action
+ * Note:
+ *      (1)The API can set SA unknown packet action while auto learn limit number is over. 
+ *      The action symbol as following:
+ *      - LIMIT_LEARN_CNT_ACTION_DROP,
+ *      - LIMIT_LEARN_CNT_ACTION_TO_CPU,
+ *      (2)The action is global, so the port must be set as RTK_WHOLE_SYSTEM
+ */
+extern rtk_api_ret_t rtk_l2_limitLearningCntAction_set(rtk_port_t port, rtk_l2_limitLearnCntAction_t action);
+
+/* Function Name:
+ *      rtk_l2_limitLearningCntAction_get
+ * Description:
+ *      Get auto learn over limit number action.
+ * Input:
+ *      port - Port id (must be RTK_WHOLE_SYSTEM)
+ * Output:
+ *      pAction - Learn over action
+ * Return:
+ *      RT_ERR_OK              - Success
+ *      RT_ERR_FAILED          - Failure 
+ *      RT_ERR_PORT_ID - Invalid port number. 
+ * Note:
+ *      (1)The API can get SA unknown packet action while auto learn limit number is over. 
+ *      The action symbol as following:
+ *      - LIMIT_LEARN_CNT_ACTION_DROP,
+ *      - LIMIT_LEARN_CNT_ACTION_TO_CPU,
+ *      (2)The action is global, so the port must be set as RTK_WHOLE_SYSTEM
+ */
+extern rtk_api_ret_t rtk_l2_limitLearningCntAction_get(rtk_port_t port, rtk_l2_limitLearnCntAction_t *pAction);
+
+/* Function Name:
+ *      rtk_l2_learningCnt_get
+ * Description:
+ *      Get per-Port current auto learning number
+ * Input:
+ *      port - Port id.
+ * Output:
+ *      pMac_cnt - ASIC auto learning entries number
+ * Return:
+ *      RT_ERR_OK              - Success
+ *      RT_ERR_PORT_ID - Invalid port number. 
+ *      RT_ERR_NULL_POINTER   -   Input parameter is null pointer  
+ * Note:
+ *      The API can get per-port ASIC auto learning number
+ */
+extern rtk_api_ret_t rtk_l2_learningCnt_get(rtk_port_t port, rtk_mac_cnt_t *pMac_cnt);
+
+/* CPU Port */
+
+/* Function Name:
+ *      rtk_cpu_enable_set
+ * Description:
+ *      Set cpu port function enable or disable
+ * Input:
+ *      enable          - enable or disable
+ * Output:
+ *      none
+ * Return:
+ *      RT_ERR_OK                        -  Success
+ *      RT_ERR_FAILED                  -   Failure
+ * Note:
+ *      The API can set CPU port function enable/disable
+ *      default port 4 is cpu port.
+ */
+extern rtk_api_ret_t rtk_cpu_enable_set(rtk_enable_t enable);
+
+/* Function Name:
+ *      rtk_cpu_enable_get
+ * Description:
+ *      Get cpu port function enable or disable
+ * Input:
+ *      none
+ * Output:
+ *      pEnable          -  the pointer of enable or disable cpu port function
+ * Return:
+ *      RT_ERR_OK                   -  Success
+ *      RT_ERR_FAILED             -   Failure
+ * Note:
+ *      The API can set CPU port function enable/disable
+ */
+extern rtk_api_ret_t rtk_cpu_enable_get(rtk_enable_t *pEnable);
+
+/* Function Name:
+ *      rtk_cpu_tagPort_set
+ * Description:
+ *      Set CPU port and CPU tag insert mode
+ * Input:
+ *      port          -  Port id
+ *      mode        -  CPU tag insert for packets egress from CPU port
+ * Output:
+ *      none
+ * Return:
+ *      RT_ERR_OK                   -  Success
+ *      RT_ERR_FAILED             -   Failure
+ *      RT_ERR_PORT_ID           -   Invalid port id
+ * Note:
+ *      The API can set CPU port and inserting proprietary CPU tag mode (Length/Type 0x8899)
+ *      to the frame that transmitting to CPU port.
+ *      The inset cpu tag mode is as following:
+ *          - CPU_INSERT_TO_ALL
+ *          - CPU_INSERT_TO_TRAPPING
+ *          - CPU_INSERT_TO_NONE   
+ */ 
+extern rtk_api_ret_t rtk_cpu_tagPort_set(rtk_port_t port, rtk_cpu_insert_t mode);
+
+/* Function Name:
+ *      rtk_cpu_tagPort_get
+ * Description:
+ *      Get CPU port and CPU tag insert mode
+ * Input:
+ *      port          -  Port id
+ * Output:
+ *      pMode       -  the pointer of CPU tag insert for packets egress from CPU port
+ * Return:
+ *      RT_ERR_OK                      -  Success
+ *      RT_ERR_FAILED                -   Failure
+ *      RT_ERR_NULL_POINTER      -   Input parameter is null pointer
+ * Note:
+ *      The API can set CPU port and inserting proprietary CPU tag mode (Length/Type 0x8899)
+ *      to the frame that transmitting to CPU port.
+ *      The inset cpu tag mode is as following:
+ *          - CPU_INSERT_TO_ALL
+ *          - CPU_INSERT_TO_TRAPPING
+ *          - CPU_INSERT_TO_NONE    
+ */
+
+extern rtk_api_ret_t rtk_cpu_tagPort_get(rtk_port_t *pPort, rtk_cpu_insert_t *pMode);
+
+
+/*Port Mirror */
+
+/* Function Name:
+ *      rtk_mirror_portBased_set
+ * Description:
+ *      Set port mirror function
+ * Input:
+ *      mirroring_port                  - Monitor port, 7 means no monitor port
+ *      pMirrored_rx_portmask      - the pointer of Rx mirror port mask
+ *      pMirrored_tx_portmask      - the pointer of Tx mirror port mask
+ * Output:
+ *      none
+ * Return:
+ *      RT_ERR_OK                      -  Success
+ *      RT_ERR_FAILED                -   Failure
+ *      RT_ERR_PORT_MASK         -   Invalid port mask
+ * Note:
+ *      The API is to set mirror function of source port and mirror port. 
+ */
+extern rtk_api_ret_t rtk_mirror_portBased_set(rtk_port_t mirroring_port, rtk_portmask_t *pMirrored_rx_portmask, rtk_portmask_t *pMirrored_tx_portmask);
+
+/* Function Name:
+ *      rtk_mirror_portBased_get
+ * Description:
+ *      Get port mirror function
+ * Input:
+ *      none 
+ * Output:
+ *      pMirroring_port             - the pointer Monitor port, 7 means no monitor port
+ *      pMirrored_rx_portmask   - the pointer of Rx mirror port mask
+ *      pMirrored_tx_portmask   - the pointer of Tx mirror port mask 
+ * Return:
+ *      RT_ERR_OK                      -  Success
+ *      RT_ERR_FAILED                -   Failure
+ *      RT_ERR_PORT_MASK         -   Invalid port mask
+ *      RT_ERR_NULL_POINTER      -   Input parameter is null pointer 
+ * Note:
+ *      The API is to set mirror function of source port and mirror port. 
+ */
+extern rtk_api_ret_t rtk_mirror_portBased_get(rtk_port_t* pMirroring_port, rtk_portmask_t *pMirrored_rx_portmask, rtk_portmask_t *pMirrored_tx_portmask);
+
+/* 802.1X */
+
+/* Function Name:
+ *      rtk_dot1x_unauthPacketOper_set
+ * Description:
+ *      Set 802.1x unauth action configuration
+ * Input:
+ *      port                 -   Port id, no use for RTL8306E switch
+ *      unauth_action   -   802.1X unauth action    
+ * Output:
+ *      none
+ * Return:
+ *      RT_ERR_OK
+ *      RT_ERR_FAILED
+ *      RT_ERR_DOT1X_PROC
+ * Note:
+ *      This API can set 802.1x unauth action configuration, 
+ *      for RTL8306E switch, the action is by whole system,
+ *      so port could be any value of 0~6.
+ *      The unauth action is as following:
+ *          - DOT1X_ACTION_DROP
+ *          - DOT1X_ACTION_TRAP2CPU
+ */
+
+extern rtk_api_ret_t rtk_dot1x_unauthPacketOper_set(rtk_port_t port, rtk_dot1x_unauth_action_t unauth_action);
+
+/* Function Name:
+ *      rtk_dot1x_unauthPacketOper_get
+ * Description:
+ *      Get 802.1x unauth action configuration
+ * Input:
+ *      port                  -   Port id, no use for RTL8306E switch
+ * Output:
+ *      pUnauth_action   -  the pointer of 802.1X unauth action    
+ * Return:
+ *      RT_ERR_OK                      -  Success
+ *      RT_ERR_FAILED                -   Failure
+ *      RT_ERR_NULL_POINTER      -   Input parameter is null pointer
+ * Note:
+ *      This API can set 802.1x unauth action configuration, 
+ *      for RTL8306E switch, the action is by whole system,
+ *      so port could be any value of 0~6.
+ *      The unauth action is as following:
+ *          - DOT1X_ACTION_DROP
+ *          - DOT1X_ACTION_TRAP2CPU
+ */
+extern rtk_api_ret_t rtk_dot1x_unauthPacketOper_get(rtk_port_t port, rtk_dot1x_unauth_action_t *pUnauth_action);
+
+/* Function Name:
+ *      rtk_dot1x_portBasedEnable_set
+ * Description:
+ *      Set 802.1x port-based enable configuration
+ * Input:
+ *      port                  -   Port id
+ *      enable               -   enable or disable
+ * Output:
+ *      none
+ * Return:
+ *      RT_ERR_OK                      -  Success
+ *      RT_ERR_FAILED                -   Failure
+ *      RT_ERR_PORT_ID              -   Invalid port id
+ * Note:
+ *      The API can update the port-based port enable register content. If a port is 802.1x 
+ *      port based network access control "enabled", it should be authenticated so packets 
+ *      from that port won't be dropped or trapped to CPU. 
+ *      The status of 802.1x port-based network access control is as following:
+ *          - DISABLED
+ *          - ENABLED
+ */    
+extern rtk_api_ret_t rtk_dot1x_portBasedEnable_set(rtk_port_t port, rtk_enable_t enable);
+
+/* Function Name:
+ *      rtk_dot1x_portBasedEnable_get
+ * Description:
+ *      Get 802.1x port-based enable configuration
+ * Input:
+ *      port                  -   Port id
+ * Output:
+ *      pEnable             -   the pointer of enable or disable
+ * Return:
+ *      RT_ERR_OK                -  Success
+ *      RT_ERR_FAILED          -   Failure
+ *      RT_ERR_PORT_ID        -   Invalid port id
+ * Note:
+ *      The API can update the port-based port enable register content. If a port is 802.1x 
+ *      port based network access control "enabled", it should be authenticated so packets 
+ *      from that port won't be dropped or trapped to CPU. 
+ *      The status of 802.1x port-based network access control is as following:
+ *          - DISABLED
+ *          - ENABLED
+ */    
+extern rtk_api_ret_t rtk_dot1x_portBasedEnable_get(rtk_port_t port, rtk_enable_t *pEnable);
+
+/* Function Name:
+ *      rtk_dot1x_portBasedAuthStatus_set
+ * Description:
+ *      Set 802.1x port-based enable configuration
+ * Input:
+ *      port                  -   Port id
+ *      port_auth          -  The status of 802.1x port
+ * Output:
+ *      none
+ * Return:
+ *      RT_ERR_OK                                    -  Success
+ *      RT_ERR_FAILED                              -   Failure
+ *      RT_ERR_PORT_ID                            -   Invalid port id
+ *      RT_ERR_DOT1X_PORTBASEDAUTH      -   Port-based auth port error
+ * Note:
+ *      The authenticated status of 802.1x port-based network access control is as following:
+ *          - UNAUTH
+ *          - AUTH
+ */    
+extern rtk_api_ret_t rtk_dot1x_portBasedAuthStatus_set(rtk_port_t port, rtk_dot1x_auth_status_t port_auth);
+
+/* Function Name:
+ *      rtk_dot1x_portBasedAuthStatus_get
+ * Description:
+ *      Get 802.1x port-based enable configuration
+ * Input:
+ *      port                  -   Port id
+ * Output:
+ *      pPort_auth         -   the pointer of the status of 802.1x port
+ * Return:
+ *      RT_ERR_OK                          -  Success
+ *      RT_ERR_FAILED                     -  Failure
+ *      RT_ERR_PORT_ID                   -  Invalid port id
+ *      RT_ERR_NULL_POINTER           -  Input parameter is null pointer
+ * Note:
+ *      The authenticated status of 802.1x port-based network access control is as following:
+ *          - UNAUTH
+ *          - AUTH
+ */    
+extern rtk_api_ret_t rtk_dot1x_portBasedAuthStatus_get(rtk_port_t port, rtk_dot1x_auth_status_t *pPort_auth);
+
+/* Function Name:
+ *      rtk_dot1x_portBasedDirection_set
+ * Description:
+ *      Set 802.1x port-based operational direction configuration
+ * Input:
+ *      port                  -   Port id
+ *      port_direction     -   Operation direction
+ * Output:
+ *      none
+ * Return:
+ *      RT_ERR_OK                                 -  Success
+ *      RT_ERR_FAILED                           -  Failure
+ *      RT_ERR_PORT_ID                         -  Invalid port id
+ *      RT_ERR_DOT1X_PORTBASEDOPDIR  -  Port-based opdir error
+ * Note:
+ *      The operate controlled direction of 802.1x port-based network access control is as following:
+ *          - BOTH
+ *          - IN
+ */    
+extern rtk_api_ret_t rtk_dot1x_portBasedDirection_set(rtk_port_t port, rtk_dot1x_direction_t port_direction);
+
+/* Function Name:
+ *      rtk_dot1x_portBasedDirection_get
+ * Description:
+ *      Get 802.1x port-based operational direction configuration
+ * Input:
+ *      port                  -   Port id
+ * Output:
+ *      pPort_direction    -   the pointer of Operation direction
+ * Return:
+ *      RT_ERR_OK                         -  Success
+ *      RT_ERR_FAILED                    -  Failure
+ *      RT_ERR_PORT_ID                  -  Invalid port id
+ *      RT_ERR_NULL_POINTER          -  Input parameter is null pointer
+ * Note:
+ *      The operate controlled direction of 802.1x port-based network access control is as following:
+ *          - BOTH
+ *          - IN
+ */    
+extern rtk_api_ret_t rtk_dot1x_portBasedDirection_get(rtk_port_t port, rtk_dot1x_direction_t *pPort_direction);
+
+/* Function Name:
+ *      rtk_dot1x_macBasedEnable_set
+ * Description:
+ *      Set 802.1x mac-based port enable configuration
+ * Input:
+ *      port                  -   Port id
+ *      enable               -   The status of 802.1x mac-base funtion
+ * Output:
+ *      none
+ * Return:
+ *      RT_ERR_OK                         -  Success
+ *      RT_ERR_FAILED                    -  Failure
+ *      RT_ERR_PORT_ID                  -  Invalid port id
+ * Note:
+ *     If a port is 802.1x MAC based network access control "enabled", the incoming packets should 
+ *     be authenticated so packets from that port won't be dropped or trapped to CPU.
+ *     The status of 802.1x MAC-based network access control is as following:
+ *         - DISABLED
+ *         - ENABLED
+ */    
+extern rtk_api_ret_t rtk_dot1x_macBasedEnable_set(rtk_port_t port, rtk_enable_t enable);
+
+/* Function Name:
+ *      rtk_dot1x_macBasedEnable_get
+ * Description:
+ *      Get 802.1x mac-based port enable configuration
+ * Input:
+ *      port                  -   Port id
+ * Output:
+ *      pEnable             -   the pointer of the status of 802.1x mac-base funtion
+ * Return:
+ *      RT_ERR_OK               -  Success
+ *      RT_ERR_FAILED         -   Failure
+ * Note:
+ *     If a port is 802.1x MAC based network access control "enabled", the incoming packets should 
+ *     be authenticated so packets from that port won't be dropped or trapped to CPU.
+ *     The status of 802.1x MAC-based network access control is as following:
+ *         - DISABLED
+ *         - ENABLED
+ */    
+extern rtk_api_ret_t rtk_dot1x_macBasedEnable_get(rtk_port_t port, rtk_enable_t *pEnable);
+
+/* Function Name:
+ *      rtk_dot1x_macBasedDirection_set
+ * Description:
+ *      Set 802.1x mac-based operational direction configuration
+ * Input:
+ *      mac_direction    -   Operation direction
+ * Output:
+ *      none
+ * Return:
+ *      RT_ERR_OK                                    -  Success
+ *      RT_ERR_FAILED                              -  Failure
+ *      RT_ERR_DOT1X_MACBASEDOPDIR      -  MAC-based opdir error
+ * Note:
+ *      The operate controlled direction of 802.1x mac-based network access control is as following:
+ *          - BOTH
+ *          - IN
+ */     
+extern rtk_api_ret_t rtk_dot1x_macBasedDirection_set(rtk_dot1x_direction_t mac_direction);
+
+/* Function Name:
+ *      rtk_dot1x_macBasedDirection_get
+ * Description:
+ *      Get 802.1x mac-based operational direction configuration
+ * Input:
+ *      none
+ * Output:
+ *      pMac_direction    -   the pointer of Operation direction
+ * Return:
+ *      RT_ERR_OK                                    -  Success
+ *      RT_ERR_FAILED                              -  Failure
+ *      RT_ERR_NULL_POINTER                    -  Input parameter is null pointer
+ * Note:
+ *      The operate controlled direction of 802.1x mac-based network access control is as following:
+ *          - BOTH
+ *          - IN
+ */  
+extern rtk_api_ret_t rtk_dot1x_macBasedDirection_get(rtk_dot1x_direction_t *pMac_direction);
+
+/* Function Name:
+ *      rtk_dot1x_macBasedAuthMac_add
+ * Description:
+ *      Add an authenticated MAC to ASIC
+ * Input:
+ *      port            -  Port id
+ *      pAuth_mac   - The authenticated MAC
+ *      fid              -  no use for RTL8306E   
+ * Output:
+ *      none
+ * Return:
+ *      RT_ERR_OK                                       - Success
+ *      RT_ERR_FAILED                                 -  Failure
+ *      RT_ERR_L2_ENTRY_NOTFOUND             -  Specified entry not found
+ *      RT_ERR_DOT1X_MAC_PORT_MISMATCH  - Auth MAC and port mismatch eror 
+ * Note:
+ *     The API can add a 802.1x authenticated MAC address to port. If the MAC does not exist in LUT, 
+ *     user can't add this MAC to auth status.
+ */    
+extern rtk_api_ret_t rtk_dot1x_macBasedAuthMac_add(rtk_port_t port, rtk_mac_t *pAuth_mac, rtk_fid_t fid);
+
+/* Function Name:
+ *      rtk_dot1x_macBasedAuthMac_del
+ * Description:
+ *      Delete an authenticated MAC to ASIC
+ * Input:
+ *      port            -  Port id
+ *      pAuth_mac   - The authenticated MAC
+ *      fid              -  no use for RTL8306E   
+ * Output:
+ *      none
+ * Return:
+ *      RT_ERR_OK                                       - Success
+ *      RT_ERR_FAILED                                 -  Failure
+ *      RT_ERR_L2_ENTRY_NOTFOUND             -  Specified entry not found
+ *      RT_ERR_DOT1X_MAC_PORT_MISMATCH  - Auth MAC and port mismatch eror 
+ * Note:
+ *     The API can delete a 802.1x authenticated MAC address to port. It only change the auth status of
+ *     the MAC and won't delete it from LUT.
+ */    
+extern rtk_api_ret_t rtk_dot1x_macBasedAuthMac_del(rtk_port_t port, rtk_mac_t *pAuth_mac, rtk_fid_t fid);
+
+
+/* Function Name:
+ *      rtk_svlan_init
+ * Description:
+ *      Initialize SVLAN Configuration
+ * Input:
+ *      none
+ * Output:
+ *      none
+ * Return:
+ *      RT_ERR_OK
+ *      RT_ERR_FAILED
+ *      RT_ERR_SMI
+ *      RT_ERR_INPUT
+ * Note:
+ *    Ether type of S-tag in 802.1ad is 0x88a8 and there are existed ether type 
+ *    0x9100 and 0x9200 for Q-in-Q SLAN design. User can set mathced ether 
+ *    type as service provider supported protocol. After call this API, all ports are 
+ *    set as CVLAN port. you can use rtk_svlan_servicePort_add to add SVLAN port. 
+ */
+extern rtk_api_ret_t rtk_svlan_init(void);
+
+/* Function Name:
+ *      rtk_svlan_servicePort_add
+ * Description:
+ *      Enable one service port in the specified device
+ * Input:
+ *      port     -  Port id
+ * Output:
+ *      none
+ * Return:
+ *      RT_ERR_OK
+ *      RT_ERR_FAILED
+ *      RT_ERR_SMI
+ * Note:
+ *    This API is setting which port is connected to provider switch. All frames receiving from this port
+ *    will recognize Service Vlan Tag.
+ *    
+ */
+extern rtk_api_ret_t rtk_svlan_servicePort_add(rtk_port_t port);
+
+
+/* Function Name:
+ *      rtk_svlan_servicePort_del
+ * Description:
+ *      Disable one service port in the specified device
+ * Input:
+ *      none
+ * Output:
+ *      pSvlan_portmask  - svlan ports mask
+ * Return:
+ *      RT_ERR_OK
+ *      RT_ERR_FAILED
+ *      RT_ERR_SMI
+ * Note:
+ *      Ether type of S-tag in 802.1ad is 0x88a8 and there are existed ether type
+ *      0x9100 and 0x9200 for Q-in-Q SLAN design. User can set mathced ether type as service 
+ *      provider supported protocol. 
+ */
+extern rtk_api_ret_t rtk_svlan_servicePort_del(rtk_port_t port);
+
+/* Function Name:
+ *      rtk_svlan_servicePort_get
+ * Description:
+ *      Disable one service port in the specified device
+ * Input:
+ *      none
+ * Output:
+ *      pSvlan_portmask  - svlan ports mask
+ * Return:
+ *      RT_ERR_OK                 - success
+ *      RT_ERR_FAILED            -  fail
+ *      RT_ERR_NULL_POINTER  -  null pointer
+ * Note:
+ *      Ether type of S-tag in 802.1ad is 0x88a8 and there are existed ether type 0x9100 
+ *      and 0x9200 for Q-in-Q SLAN design. User can set mathced ether type as service 
+ *      provider supported protocol. 
+ */
+extern rtk_api_ret_t rtk_svlan_servicePort_get(rtk_portmask_t *pSvlan_portmask);
+
+/* Function Name:
+ *      rtk_svlan_tpidEntry_set
+ * Description:
+ *      Configure accepted S-VLAN ether type. The default ether type of S-VLAN is 0x88a8
+ * Input:
+ *      svlan_tag_id  - Ether type of S-tag frame parsing in uplink ports
+ * Output:
+ *      none
+ * Return:
+ *      RT_ERR_OK
+ *      RT_ERR_FAILED
+ *      RT_ERR_SMI
+ * Note:
+ *      Ether type of S-tag in 802.1ad is 0x88a8 and there are existed ether type 0x9100 
+ *      and 0x9200 for Q-in-Q SLAN design. User can set mathced ether type as service 
+ *      provider supported protocol. 
+ */
+extern rtk_api_ret_t rtk_svlan_tpidEntry_set(rtk_svlan_tpid_t svlan_tag_id);
+
+
+/* Function Name:
+ *      rtk_svlan_tpidEntry_get
+ * Description:
+ *      Get accepted S-VLAN ether type. The default ether type of S-VLAN is 0x88a8
+ * Input:
+ *      pSvlan_tag_id       - Ether type of S-tag frame parsing in uplink ports
+ * Output:
+ *      none
+ * Return:
+ *      RT_ERR_OK
+ *      RT_ERR_FAILED
+ * Note:
+ *      Ether type of S-tag in 802.1ad is 0x88a8 and there are existed ether type 0x9100 
+ *      and 0x9200 for Q-in-Q SLAN design. User can set mathced ether type as service 
+ *      provider supported protocol. 
+ */
+extern rtk_api_ret_t rtk_svlan_tpidEntry_get(rtk_svlan_tpid_t *pSvlan_tag_id);
+
+
+/* Function Name:
+ *      rtk_svlan_portPvid_set
+ * Description:
+ *      Set port to specified VLAN ID(PVID) for Service Provider Port
+ * Input:
+ *      port             - Port id
+ *      pvid             - Specified Service VLAN ID
+ *      priority         - 802.1p priority for the PVID
+ *      dei               - Service VLAN tag DEI bit
+ * Output:
+ *      none
+ * Return:
+ *      RT_ERR_OK
+ *      RT_ERR_FAILED
+ *      RT_ERR_VLAN_VID
+ *      RT_ERR_SMI 
+ *      RT_ERR_VLAN_PRIORITY 
+ *      RT_ERR_VLAN_ENTRY_NOT_FOUND
+ * Note:
+ *    The API is used for Port-based VLAN. The untagged frame received from the
+ *    port will be classified to the specified VLAN and assigned to the specified priority.
+ */
+extern rtk_api_ret_t rtk_svlan_portPvid_set(rtk_port_t port, rtk_vlan_t pvid, rtk_pri_t priority, rtk_dei_t dei);
+
+/* Function Name:
+ *      rtk_svlan_portPvid_get
+ * Description:
+ *      Get Service VLAN ID(PVID) on specified port
+ * Input:
+ *      port             - Port id
+ *      pPvid            - Specified VLAN ID
+ *      pPriority        - 802.1p priority for the PVID
+ *      pDei             - DEI bit
+ * Output:
+ *      none
+ * Return:
+ *      RT_ERR_OK
+ *      RT_ERR_FAILED
+ *      RT_ERR_SMI
+ *      RT_ERR_PORT_ID
+ *      RT_ERR_NULL_POINTER 
+ * Note:
+ *    The API is used for Port-based VLAN. The untagged frame received from the
+ *    port will be classified to the specified VLAN and assigned to the specified priority.
+ */
+extern rtk_api_ret_t rtk_svlan_portPvid_get(rtk_port_t port, rtk_vlan_t *pPvid, rtk_pri_t* pPriority, rtk_dei_t *pDei);
+
+/* Function Name:
+ *      rtk_filter_igrAcl_init
+ * Description:
+ *       Initialize ACL 
+ * Input:
+ *      none
+ * Output:
+ *      none
+ * Return:
+ *      RT_ERR_OK
+ *      RT_ERR_FAILED
+ * Note:
+ *      The API init ACL module.
+ */
+extern rtk_api_ret_t rtk_filter_igrAcl_init(void);
+
+/* Function Name:
+ *      rtk_filter_igrAcl_rule_add
+ * Description:
+ *      Add an acl rule into acl table
+ * Input:
+ *      pRule    -  the pointer of rule structure
+ * Output:
+ *      none
+ * Return:
+ *      RT_ERR_OK
+ *      RT_ERR_FAILED
+ *      RT_ERR_TBL_FULL
+ *      RT_ERR_NULL_POINTER
+ * Note:
+ *      The API add an  ACL rule. <nl>
+ *      phyport could be  0~5: port number,  RTL8306_ACL_ANYPORT: any port;<nl>
+ *      protocol could be RTL8306_ACL_ETHER(ether type), RTL8306_ACL_TCP(TCP), RTL8306_ACL_UDP(UDP), RTL8306_ACL_TCPUDP(TCP or UDP);<nl>
+ *      prority could be RTL8306_PRIO0~RTL8306_PRIO3;<nl>
+ *      action could be RTL8306_ACT_DROP/RTL8306_ACT_PERMIT/RTL8306_ACT_TRAPCPU/RTL8306_ACT_MIRROR;<nl>
+ */
+
+extern rtk_api_ret_t rtk_filter_igrAcl_rule_add(rtk_filter_rule_t *pRule);
+
+/* Function Name:
+ *      rtk_filter_igrAcl_rule_get
+ * Description:
+ *      Get ACL rule priority and action 
+ * Input:
+ *      pRule    -  the pointer of rule structure
+ * Output:
+ *      pRule    -  the pointer of rule structure
+ * Return:
+ *      RT_ERR_OK
+ *      RT_ERR_FAILED
+ * Note:
+ *      The API add an  ACL rule. <nl>
+ *      phyport could be  0~5: port number,  RTL8306_ACL_ANYPORT: any port;<nl>
+ *      protocol could be RTL8306_ACL_ETHER(ether type), RTL8306_ACL_TCP(TCP), RTL8306_ACL_UDP(UDP), RTL8306_ACL_TCPUDP(TCP or UDP);<nl>
+ *      prority could be RTL8306_PRIO0~RTL8306_PRIO3;<nl>
+ *      action could be RTL8306_ACT_DROP/RTL8306_ACT_PERMIT/RTL8306_ACT_TRAPCPU/RTL8306_ACT_MIRROR;<nl>
+ */
+extern rtk_api_ret_t rtk_filter_igrAcl_rule_get(rtk_filter_rule_t *pRule);
+
+
+
+/* Function Name:
+ *      rtk_filter_igrAcl_rule_del
+ * Description:
+ *      Delete an acl rule into acl table
+ * Input:
+ *      pRule    -  the pointer of rule structure
+ * Output:
+ *      none
+ * Return:
+ *      RT_ERR_OK
+ *      RT_ERR_FAILED
+ *      RT_ERR_INPUT
+ *      RT_ERR_NULL_POINTER
+ * Note:
+ *      The API delete an  ACL rule. <nl>
+ *      only phyport/protocol/data field in pRule needs to be specified.
+ */
+extern rtk_api_ret_t rtk_filter_igrAcl_rule_del(rtk_filter_rule_t *pRule);
+
+/*add at 2012-2-13*/
+extern rtk_api_ret_t rtk_mib_get(rtk_port_t port, rtk_mib_counter_t counter, rtk_mib_cntValue_t *pValue);
+extern rtk_api_ret_t rtk_mib_cntType_set(rtk_port_t port, rtk_mib_counter_t counter,rtk_mib_cntType_t type);
+extern rtk_api_ret_t rtk_mib_cntType_get(rtk_port_t port, rtk_mib_counter_t counter,rtk_mib_cntType_t *pType);
+extern rtk_api_ret_t rtk_mib_reset(rtk_port_t port);
+
+#endif   /*__RTK_API_EXT_H__*/
+
+
+
diff --git a/ap/os/linux/linux-3.4.x/drivers/net/phy/realtek/rtl8306e/rtk_error.h b/ap/os/linux/linux-3.4.x/drivers/net/phy/realtek/rtl8306e/rtk_error.h
new file mode 100755
index 0000000..ebbb5ea
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/net/phy/realtek/rtl8306e/rtk_error.h
@@ -0,0 +1,231 @@
+/*
+* Copyright (C) 2010 Realtek Semiconductor Corp.
+* All Rights Reserved.
+*
+* This program is the proprietary software of Realtek Semiconductor
+* Corporation and/or its licensors, and only be used, duplicated,
+* modified or distributed under the authorized license from Realtek.
+*
+* ANY USE OF THE SOFTWARE OTEHR THAN AS AUTHORIZED UNDER 
+* THIS LICENSE OR COPYRIGHT LAW IS PROHIBITED.
+* 
+* $Revision: 10083 $ 
+* $Date: 2010-06-07 11:18:41 +0800 (星期一, 2010-06-07) $
+*
+* Purpose : Definition the error number in the SDK
+*
+* Feature :  This file consists of following modules:
+*                
+*
+*/
+
+#ifndef __RTL_ERROR_H__
+#define __RTL_ERROR_H__
+
+/*
+ * Data Type Declaration
+ */
+typedef enum rt_error_code_e
+{
+    RT_ERR_FAILED = -1,                             /* General Error                                                                    */
+
+    /* 0x00xx for common error code */
+    RT_ERR_OK = 0,                                    /* 0x0000, OK                                                                   */
+    RT_ERR_INPUT,                                     /* 0x0001, invalid input parameter                                              */
+    RT_ERR_UNIT_ID,                                  /* 0x0002, invalid unit id                                                      */
+    RT_ERR_PORT_ID,                                 /* 0x0003, invalid port id                                                      */
+    RT_ERR_PORT_MASK,                            /* 0x0004, invalid port mask                                                    */
+    RT_ERR_PORT_LINKDOWN,                    /* 0x0005, link down port status                                                */
+    RT_ERR_ENTRY_INDEX,                         /* 0x0006, invalid entry index                                                  */
+    RT_ERR_NULL_POINTER,                       /* 0x0007, input parameter is null pointer                                      */
+    RT_ERR_QUEUE_ID,                             /* 0x0008, invalid queue id                                                     */
+    RT_ERR_QUEUE_NUM,                               /* 0x0009, invalid queue number                                                 */
+    RT_ERR_BUSYWAIT_TIMEOUT,                        /* 0x000a, busy watting time out                                                */
+    RT_ERR_MAC,                                     /* 0x000b, invalid mac address                                                  */
+    RT_ERR_OUT_OF_RANGE,                            /* 0x000c, input parameter out of range                                         */
+    RT_ERR_CHIP_NOT_SUPPORTED,                      /* 0x000d, functions not supported by this chip model                           */
+    RT_ERR_SMI,                                     /* 0x000e, SMI error                                                            */
+    RT_ERR_NOT_INIT,                                /* 0x000f, The module is not initial                                            */
+    RT_ERR_CHIP_NOT_FOUND,                          /* 0x0010, The chip can not found                                               */
+    RT_ERR_NOT_ALLOWED,                             /* 0x0011, actions not allowed by the function                                  */
+    RT_ERR_DRIVER_NOT_FOUND,                        /* 0x0012, The driver can not found                                             */
+    RT_ERR_SEM_LOCK_FAILED,                         /* 0x0013, Failed to lock semaphore                                             */
+    RT_ERR_SEM_UNLOCK_FAILED,                       /* 0x0014, Failed to unlock semaphore                                           */
+    RT_ERR_ENABLE,                                  /* 0x0015, invalid enable parameter                                             */
+    RT_ERR_TBL_FULL,                                /* 0x0016, input table full                                                     */
+
+    /* 0x01xx for vlan */
+    RT_ERR_VLAN_VID = 0x0100,                       /* 0x0100, invalid vid                                                          */
+    RT_ERR_VLAN_PRIORITY,                           /* 0x0101, invalid 1p priority                                                  */
+    RT_ERR_VLAN_EMPTY_ENTRY,                        /* 0x0102, emtpy entry of vlan table                                            */
+    RT_ERR_VLAN_ACCEPT_FRAME_TYPE,                  /* 0x0103, invalid accept frame type                                            */
+    RT_ERR_VLAN_EXIST,                              /* 0x0104, vlan is exist                                                        */
+    RT_ERR_VLAN_ENTRY_NOT_FOUND,                    /* 0x0105, specified vlan entry not found                                       */
+    RT_ERR_VLAN_PORT_MBR_EXIST,                     /* 0x0106, member port exist in the specified vlan                              */
+    RT_ERR_VLAN_PROTO_AND_PORT,                     /* 0x0108, invalid protocol and port based vlan                              */
+
+    /* 0x02xx for svlan */
+    RT_ERR_SVLAN_ENTRY_INDEX = 0x0200,              /* 0x0200, invalid svid entry no                                                */
+    RT_ERR_SVLAN_ETHER_TYPE,                        /* 0x0201, invalid SVLAN ether type                                             */
+    RT_ERR_SVLAN_TABLE_FULL,                        /* 0x0202, no empty entry in SVLAN table                                        */
+    RT_ERR_SVLAN_ENTRY_NOT_FOUND,                   /* 0x0203, specified svlan entry not found                                      */
+    RT_ERR_SVLAN_EXIST,                             /* 0x0204, SVLAN entry is exist                                                 */
+    RT_ERR_SVLAN_VID,                               /* 0x0205, invalid svid                                                         */
+
+    /* 0x03xx for MSTP */
+    RT_ERR_MSTI = 0x0300,                           /* 0x0300, invalid msti                                                         */
+    RT_ERR_MSTP_STATE,                              /* 0x0301, invalid spanning tree status                                         */
+    RT_ERR_MSTI_EXIST,                              /* 0x0302, MSTI exist                                                           */
+    RT_ERR_MSTI_NOT_EXIST,                          /* 0x0303, MSTI not exist                                                       */
+
+    /* 0x04xx for BUCKET */
+    RT_ERR_TIMESLOT = 0x0400,                       /* 0x0400, invalid time slot                                                    */
+    RT_ERR_TOKEN,                                   /* 0x0401, invalid token amount                                                 */
+    RT_ERR_RATE,                                    /* 0x0402, invalid rate                                                         */
+    RT_ERR_TICK,                                    /* 0x0403, invalid tick                                                 */
+
+    /* 0x05xx for RMA */
+    RT_ERR_RMA_ADDR = 0x0500,                       /* 0x0500, invalid rma mac address                                              */
+    RT_ERR_RMA_ACTION,                              /* 0x0501, invalid rma action                                                   */
+
+    /* 0x06xx for L2 */
+    RT_ERR_L2_HASH_KEY = 0x0600,                    /* 0x0600, invalid L2 Hash key                                                  */
+    RT_ERR_L2_HASH_INDEX,                           /* 0x0601, invalid L2 Hash index                                                */
+    RT_ERR_L2_CAM_INDEX,                            /* 0x0602, invalid L2 CAM index                                                 */
+    RT_ERR_L2_ENRTYSEL,                             /* 0x0603, invalid EntrySel                                                     */
+    RT_ERR_L2_INDEXTABLE_INDEX,                     /* 0x0604, invalid L2 index table(=portMask table) index                        */
+    RT_ERR_LIMITED_L2ENTRY_NUM,                     /* 0x0605, invalid limited L2 entry number                                      */
+    RT_ERR_L2_AGGREG_PORT,                          /* 0x0606, this aggregated port is not the lowest physical
+                                                               port of its aggregation group                                        */
+    RT_ERR_L2_FID,                                  /* 0x0607, invalid fid                                                          */
+    RT_ERR_L2_RVID,                                 /* 0x0608, invalid cvid                                                         */
+    RT_ERR_L2_NO_EMPTY_ENTRY,                       /* 0x0609, no empty entry in L2 table                                           */
+    RT_ERR_L2_ENTRY_NOTFOUND,                       /* 0x060a, specified entry not found                                            */
+    RT_ERR_L2_INDEXTBL_FULL,                        /* 0x060b, the L2 index table is full                                           */
+    RT_ERR_L2_INVALID_FLOWTYPE,                     /* 0x060c, invalid L2 flow type                                                 */
+    RT_ERR_L2_L2UNI_PARAM,                          /* 0x060d, invalid L2 unicast parameter                                         */
+    RT_ERR_L2_L2MULTI_PARAM,                        /* 0x060e, invalid L2 multicast parameter                                       */
+    RT_ERR_L2_IPMULTI_PARAM,                        /* 0x060f, invalid L2 ip multicast parameter                                    */
+    RT_ERR_L2_PARTIAL_HASH_KEY,                     /* 0x0610, invalid L2 partial Hash key                                          */
+    RT_ERR_L2_EMPTY_ENTRY,                          /* 0x0611, the entry is empty(invalid)                                          */
+    RT_ERR_L2_FLUSH_TYPE,                           /* 0x0612, the flush type is invalid                                            */
+    RT_ERR_L2_NO_CPU_PORT,                          /* 0x0613, CPU port not exist                                                   */
+
+    /* 0x07xx for FILTER (PIE) */
+    RT_ERR_FILTER_BLOCKNUM = 0x0700,                /* 0x0700, invalid block number                                                 */
+    RT_ERR_FILTER_ENTRYIDX,                         /* 0x0701, invalid entry index                                                  */
+    RT_ERR_FILTER_CUTLINE,                          /* 0x0702, invalid cutline value                                                */
+    RT_ERR_FILTER_FLOWTBLBLOCK,                     /* 0x0703, block belongs to flow table                                          */
+    RT_ERR_FILTER_INACLBLOCK,                       /* 0x0704, block belongs to ingress ACL                                         */
+    RT_ERR_FILTER_ACTION,                           /* 0x0705, action doesn't consist to entry type                                 */
+    RT_ERR_FILTER_INACL_RULENUM,                    /* 0x0706, invalid ACL rulenum                                                  */
+    RT_ERR_FILTER_INACL_TYPE,                       /* 0x0707, entry type isn't an ingress ACL rule                                 */
+    RT_ERR_FILTER_INACL_EXIST,                      /* 0x0708, ACL entry is already exit                                            */
+    RT_ERR_FILTER_INACL_EMPTY,                      /* 0x0709, ACL entry is empty                                                   */
+    RT_ERR_FILTER_FLOWTBL_TYPE,                     /* 0x070a, entry type isn't an flow table rule                                  */
+    RT_ERR_FILTER_FLOWTBL_RULENUM,                  /* 0x070b, invalid flow table rulenum                                           */
+    RT_ERR_FILTER_FLOWTBL_EMPTY,                    /* 0x070c, flow table entry is empty                                            */
+    RT_ERR_FILTER_FLOWTBL_EXIST,                    /* 0x070d, flow table entry is already exist                                    */
+    RT_ERR_FILTER_METER_ID,                         /* 0x070e, invalid metering id                                                  */
+    RT_ERR_FILTER_LOG_ID,                           /* 0x070f, invalid log id                                                       */
+    RT_ERR_FILTER_INACL_ACT_NOT_SUPPORT,            /* 0x0710, rule not support                                                     */        
+    RT_ERR_FILTER_INACL_RULE_NOT_SUPPORT,           /* 0x0710, action not support                                                   */    
+
+    /* 0x08xx for ACL Rate Limit */
+    RT_ERR_ACLRL_HTHR = 0x0800,                     /* 0x0800, invalid high threshold                                               */
+    RT_ERR_ACLRL_TIMESLOT,                          /* 0x0801, invalid time slot                                                    */
+    RT_ERR_ACLRL_TOKEN,                             /* 0x0802, invalid token amount                                                 */
+    RT_ERR_ACLRL_RATE,                              /* 0x0803, invalid rate                                                         */
+
+    /* 0x09xx for Link aggregation */
+    RT_ERR_LA_CPUPORT = 0x0900,                     /* 0x0900, CPU port can not be aggregated port                                  */
+    RT_ERR_LA_TRUNK_ID,                             /* 0x0901, invalid trunk id                                                     */
+    RT_ERR_LA_PORTMASK,                             /* 0x0902, invalid port mask                                                    */
+    RT_ERR_LA_HASHMASK,                             /* 0x0903, invalid hash mask                                                    */
+    RT_ERR_LA_DUMB,                                 /* 0x0904, this API should be used in 802.1ad dumb mode                         */
+    RT_ERR_LA_PORTNUM_DUMB,                         /* 0x0905, it can only aggregate at most four ports when 802.1ad dumb mode      */
+    RT_ERR_LA_PORTNUM_NORMAL,                       /* 0x0906, it can only aggregate at most eight ports when 802.1ad normal mode   */
+    RT_ERR_LA_MEMBER_OVERLAP,                       /* 0x0907, the specified port mask is overlapped with other group               */
+    RT_ERR_LA_NOT_MEMBER_PORT,                      /* 0x0908, the port is not a member port of the trunk                           */
+    RT_ERR_LA_TRUNK_NOT_EXIST,                      /* 0x0909, the trunk doesn't exist                                              */
+
+
+    /* 0x0axx for storm filter */
+    RT_ERR_SFC_TICK_PERIOD = 0x0a00,                /* 0x0a00, invalid SFC tick period                                              */
+    RT_ERR_SFC_UNKNOWN_GROUP,                       /* 0x0a01, Unknown Storm filter group                                           */
+
+    /* 0x0bxx for pattern match */
+    RT_ERR_PM_MASK = 0x0b00,                        /* 0x0b00, invalid pattern length. Pattern length should be 8                   */
+    RT_ERR_PM_LENGTH,                               /* 0x0b01, invalid pattern match mask, first byte must care                     */
+    RT_ERR_PM_MODE,                                 /* 0x0b02, invalid pattern match mode                                           */
+
+    /* 0x0cxx for input bandwidth control */
+    RT_ERR_INBW_TICK_PERIOD = 0x0c00,               /* 0x0c00, invalid tick period for input bandwidth control                      */
+    RT_ERR_INBW_TOKEN_AMOUNT,                       /* 0x0c01, invalid amount of token for input bandwidth control                  */
+    RT_ERR_INBW_FCON_VALUE,                         /* 0x0c02, invalid flow control ON threshold value for input bandwidth control  */
+    RT_ERR_INBW_FCOFF_VALUE,                        /* 0x0c03, invalid flow control OFF threshold value for input bandwidth control */
+    RT_ERR_INBW_FC_ALLOWANCE,                       /* 0x0c04, invalid allowance of incomming packet for input bandwidth control    */
+    RT_ERR_INBW_RATE,                               /* 0x0c05, invalid input bandwidth                                              */
+
+    /* 0x0dxx for QoS */
+    RT_ERR_QOS_1P_PRIORITY = 0x0d00,                /* 0x0d00, invalid 802.1P priority                                              */
+    RT_ERR_QOS_DSCP_VALUE,                          /* 0x0d01, invalid DSCP value                                                   */
+    RT_ERR_QOS_INT_PRIORITY,                        /* 0x0d02, invalid internal priority                                            */
+    RT_ERR_QOS_SEL_DSCP_PRI,                        /* 0x0d03, invalid DSCP selection priority                                      */
+    RT_ERR_QOS_SEL_PORT_PRI,                        /* 0x0d04, invalid port selection priority                                      */
+    RT_ERR_QOS_SEL_IN_ACL_PRI,                      /* 0x0d05, invalid ingress ACL selection priority                               */
+    RT_ERR_QOS_SEL_CLASS_PRI,                       /* 0x0d06, invalid classifier selection priority                                */
+    RT_ERR_QOS_EBW_RATE,                            /* 0x0d07, invalid egress bandwidth rate                                        */
+    RT_ERR_QOS_SCHE_TYPE,                           /* 0x0d08, invalid QoS scheduling type                                          */
+    RT_ERR_QOS_QUEUE_WEIGHT,                        /* 0x0d09, invalid Queue weight                                                 */
+    RT_ERR_QOS_SEL_PRI_SOURCE,                      /* 0x0d0a, invalid selection of priority source                                                 */
+    
+    /* 0x0exx for port ability */
+    RT_ERR_PHY_PAGE_ID = 0x0e00,                    /* 0x0e00, invalid PHY page id                                                  */
+    RT_ERR_PHY_REG_ID,                              /* 0x0e01, invalid PHY reg id                                                   */
+    RT_ERR_PHY_DATAMASK,                            /* 0x0e02, invalid PHY data mask                                                */
+    RT_ERR_PHY_AUTO_NEGO_MODE,                      /* 0x0e03, invalid PHY auto-negotiation mode*/
+    RT_ERR_PHY_SPEED,                               /* 0x0e04, invalid PHY speed setting                                            */
+    RT_ERR_PHY_DUPLEX,                              /* 0x0e05, invalid PHY duplex setting                                           */
+    RT_ERR_PHY_FORCE_ABILITY,                       /* 0x0e06, invalid PHY force mode ability parameter                             */
+    RT_ERR_PHY_FORCE_1000,                          /* 0x0e07, invalid PHY force mode 1G speed setting                              */
+    RT_ERR_PHY_TXRX,                                /* 0x0e08, invalid PHY tx/rx                                                    */
+
+    /* 0x0fxx for mirror */
+    RT_ERR_MIRROR_DIRECTION = 0x0f00,               /* 0x0f00, invalid error mirror direction                                       */
+    RT_ERR_MIRROR_SESSION_FULL,                     /* 0x0f01, mirroring session is full                                            */
+    RT_ERR_MIRROR_SESSION_NOEXIST,                  /* 0x0f02, mirroring session not exist                                          */
+    RT_ERR_MIRROR_PORT_EXIST,                       /* 0x0f03, mirroring port already exists                                        */
+    RT_ERR_MIRROR_PORT_NOT_EXIST,                   /* 0x0f04, mirroring port does not exists                                       */
+    RT_ERR_MIRROR_PORT_FULL,                        /* 0x0f05, Exceeds maximum number of supported mirroring port                   */
+
+    /* 0x10xx for stat */
+    RT_ERR_STAT_INVALID_GLOBAL_CNTR = 0x1000,       /* 0x1000, Invalid Global Counter                                               */
+    RT_ERR_STAT_INVALID_PORT_CNTR,                  /* 0x1001, Invalid Port Counter                                                 */
+    RT_ERR_STAT_GLOBAL_CNTR_FAIL,                   /* 0x1002, Could not retrieve/reset Global Counter                              */
+    RT_ERR_STAT_PORT_CNTR_FAIL,                     /* 0x1003, Could not retrieve/reset Port Counter                                */
+
+    /* 0x1100 for dot1x */
+    RT_ERR_DOT1X_INVALID_DIRECTION = 0x1100,        /* 0x1100, Invalid Authentication Direction                                     */
+    RT_ERR_DOT1X_PORTBASEDPNEN,                     /* 0x1101, Port-based enable port error                                         */
+    RT_ERR_DOT1X_PORTBASEDAUTH,                     /* 0x1102, Port-based auth port error                                           */
+    RT_ERR_DOT1X_PORTBASEDOPDIR,                    /* 0x1103, Port-based opdir error                                               */
+    RT_ERR_DOT1X_MACBASEDPNEN,                      /* 0x1104, MAC-based enable port error                                          */
+    RT_ERR_DOT1X_MACBASEDOPDIR,                     /* 0x1105, MAC-based opdir error                                                */
+    RT_ERR_DOT1X_PROC,                              /* 0x1106, unauthorized behavior error                                          */
+    RT_ERR_DOT1X_GVLANIDX,                          /* 0x1107, guest vlan index error                                               */
+    RT_ERR_DOT1X_GVLANTALK,                         /* 0x1108, guest vlan OPDIR error                                               */
+    RT_ERR_DOT1X_MAC_PORT_MISMATCH,                 /* 0x1109, Auth MAC and port mismatch eror                                      */
+
+    /* 0x1200 for jumbo */
+    RT_ERR_JUMBO_FRAME_SIZE = 0x1200,               /* Jumbo frame size not supported */
+    
+    RT_ERR_END                                       /* The symbol is the latest symbol                                                  */
+} rt_error_code_t;    
+
+
+#endif /*__RTL_ERROR_H__*/
+
+
+
+
diff --git a/ap/os/linux/linux-3.4.x/drivers/net/phy/realtek/rtl8306e/rtl8306e_asicdrv.c b/ap/os/linux/linux-3.4.x/drivers/net/phy/realtek/rtl8306e/rtl8306e_asicdrv.c
new file mode 100755
index 0000000..e4f2b8b
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/net/phy/realtek/rtl8306e/rtl8306e_asicdrv.c
@@ -0,0 +1,8877 @@
+/*
+* Copyright (C) 2010 Realtek Semiconductor Corp.
+* All Rights Reserved.
+*
+* This program is the proprietary software of Realtek Semiconductor
+* Corporation and/or its licensors, and only be used, duplicated,
+* modified or distributed under the authorized license from Realtek.
+*
+* ANY USE OF THE SOFTWARE OTEHR THAN AS AUTHORIZED UNDER 
+* THIS LICENSE OR COPYRIGHT LAW IS PROHIBITED.
+* 
+* $Revision: 26889 $ 
+* $Date: 2012-02-28 21:08:47 +0800 (星期二, 2012-02-28) $
+*
+* Purpose : asic-level driver implementation for RTL8306E switch
+*
+*  Feature :  This file consists of following modules:
+*                1) 
+*
+*/
+#include <linux/spinlock.h> 
+#include <linux/delay.h>
+#include <mach/iomap.h>
+#include <linux/fs.h>
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/cdev.h>
+#include <linux/ioport.h>
+#include <linux/pci.h>
+#include <asm/uaccess.h>
+#include <linux/interrupt.h>
+#include <linux/poll.h>
+#include <linux/platform_device.h>
+#include <linux/device.h>  
+#include <linux/slab.h>  
+#include <linux/mii.h> 
+#include "rtl8306e_types.h"
+#include "rtl8306e_asicdrv.h"
+#include "rtk_api.h"
+//#ifndef RTK_X86_ASICDRV
+//#include "mdcmdio.h"
+//#endif
+//rtk_mode_ext_e rtk_mode_ext_t;
+//rtk_mode_ext_t *Mode;
+//rtk_port_mac_ability_t portAbility;
+extern rtk_api_ret_t rtk_cpu_enable_set(rtk_enable_t enable);
+extern rtk_api_ret_t rtk_cpu_tagPort_set(rtk_port_t port, rtk_cpu_insert_t mode);
+extern rtk_api_ret_t rtk_port_isolation_set(rtk_port_t port, rtk_portmask_t portmask);
+extern rtk_api_ret_t rtk_port_phyReg_get(rtk_port_t phy, rtk_port_phy_reg_t reg, rtk_port_phy_data_t *pData); 
+extern rtk_api_ret_t rtk_port_macForceLinkExt0_set(rtk_mode_ext_t mode, rtk_port_mac_ability_t *pPortability);
+extern rtk_api_ret_t rtk_vlan_get(rtk_vlan_t vid, rtk_portmask_t *pMbrmsk, rtk_portmask_t *pUntagmsk, rtk_fid_t *pFid);
+extern rtk_api_ret_t rtk_vlan_portPvid_get(rtk_port_t port, rtk_vlan_t *pPvid, rtk_pri_t *pPriority);
+extern rtk_api_ret_t rtk_vlan_init(void);
+extern rtk_api_ret_t rtk_vlan_portPvid_set(rtk_port_t port, rtk_vlan_t pvid, rtk_pri_t priority);
+extern rtk_api_ret_t rtk_vlan_set(rtk_vlan_t vid, rtk_portmask_t mbrmsk, rtk_portmask_t untagmsk, rtk_fid_t fid);
+extern rtk_api_ret_t rtk_vlan_portAcceptFrameType_set(rtk_port_t port, rtk_vlan_acceptFrameType_t accept_frame_type);
+extern rtk_api_ret_t rtk_vlan_destroy(rtk_vlan_t vid);
+
+extern int smiRead(int phyad, int regad,int * data);
+extern int smiWrite(int phyad, int regad, int data);
+extern struct net_device* 	gmac_net_dev;
+volatile unsigned long virt, phys;//用于存放虚拟地址和物理地址
+#ifdef RTL8306_LUT_CACHE
+RTL8306_LUT rtl8306_LutCache[RTL8306_MAX_LUT_NUM];
+#endif
+#ifdef RTL8306_TBLBAK        
+rtl8306_ConfigBakPara_t rtl8306_TblBak; 
+#endif 
+
+int switch_ioctl (struct inode *node, struct file *filp, unsigned int cmd, unsigned long arg);
+int switch_open(struct inode *inode, struct file *file);
+static int switch_probe(struct platform_device *dev);
+int switch_remove(struct platform_device *dev);
+static int switch_drv_init(void);
+static int switch_drv_exit(void);
+static unsigned int switch_major; 
+static struct cdev *switch_cdev = NULL; 
+static struct class *switch_class = NULL;	 
+	 
+	 /* Function Name:
+ *      rtl8306e_reg_set
+ * Description:
+ *      Write Asic Register
+ * Input:
+ *      phyad   - Specify Phy address (0 ~6)
+ *      regad    - Specify register address (0 ~31)
+ *      npage   - Specify page number (0 ~3)
+ *      value    - Value to be write into the register
+ * Output:
+ *      none
+ * Return:
+ *      SUCCESS
+ *      FAILED
+ * Note:
+ *      Use this function you could write all configurable registers of RTL8306, 
+ *      it is realized by calling functions smiRead and smiWrite which are switch
+ *      MDC/MDIO interface access functions. Those two functions use two GPIO 
+ *      pins to simulate MDC/MDIO timing,  and they are based on rtl8651b platform,
+ *      to modify them,  you can port all asic API to other platform.
+ */
+
+int32 rtl8306e_reg_set(uint32 phyad, uint32 regad, uint32 npage, uint32 value) 
+{
+    uint32 rdata; 
+
+    if ((phyad >= RTL8306_PHY_NUMBER) || (npage >= RTL8306_PAGE_NUMBER))
+        return FAILED;
+    
+    /* Select PHY Register Page through configuring PHY 0 Register 16 [bit1 bit15] */
+    value = value & 0xFFFF;
+    smiRead(0, 16, &rdata); 
+    switch (npage) 
+    {
+        case RTL8306_REGPAGE0:
+            smiWrite(0, 16, (rdata & 0x7FFF) | 0x0002);
+            break;
+        case RTL8306_REGPAGE1:
+            smiWrite(0, 16, rdata | 0x8002 );
+            break;
+        case RTL8306_REGPAGE2:
+            smiWrite(0, 16, rdata & 0x7FFD);
+            break;
+        case RTL8306_REGPAGE3:
+            smiWrite(0, 16, (rdata & 0xFFFD) | 0x8000);
+            break;
+        case RTL8306_REGPAGE4:
+            smiRead(5, 16, &rdata);
+            rdata |= 0x2;
+            smiWrite(5, 16, rdata);
+            break;                        
+        default:
+            return FAILED;
+    }
+
+    smiWrite(phyad, regad, value);
+    
+    if(RTL8306_REGPAGE4 == npage)
+    {
+        /*exit page 4*/
+        smiRead(5, 16, &rdata);
+        rdata &= ~0x2;
+        smiWrite(5, 16, rdata);        
+    }
+    
+    return SUCCESS;
+    
+
+}
+
+
+/* Function Name:
+ *      rtl8306e_reg_get
+ * Description:
+ *      Read Asic Register
+ * Input:
+ *      phyad   - Specify Phy address (0 ~6)
+ *      regad    - Specify register address (0 ~31)
+ *      npage   - Specify page number (0 ~3)
+ * Output:
+ *      pvalue    - The pointer of value read back from register
+ * Return:
+ *      SUCCESS
+ *      FAILED
+ * Note:
+ *      Use this function you could write all configurable registers of RTL8306, 
+ *      it is realized by calling functions smiRead and smiWrite which are switch
+ *      MDC/MDIO interface access functions. Those two functions use two GPIO 
+ *      pins to simulate MDC/MDIO timing,  and they are based on rtl8651b platform,
+ *      to modify them,  you can port all asic API to other platform.
+ */
+ 
+int32  rtl8306e_reg_get(uint32 phyad, uint32 regad, uint32 npage, uint32 *pvalue)
+{
+
+    uint32 rdata;
+
+    if ((phyad >= RTL8306_PHY_NUMBER) || (npage >= RTL8306_PAGE_NUMBER))
+        return FAILED;
+
+    /* Select PHY Register Page through configuring PHY 0 Register 16 [bit1 bit15] */
+    smiRead(0, 16, &rdata); 
+    switch (npage) 
+    {
+        case RTL8306_REGPAGE0:
+            smiWrite(0, 16, (rdata & 0x7FFF) | 0x0002);
+            break;
+        case RTL8306_REGPAGE1:
+            smiWrite(0, 16, rdata | 0x8002 );
+            break;
+        case RTL8306_REGPAGE2:
+            smiWrite(0, 16, rdata & 0x7FFD);
+            break;
+        case RTL8306_REGPAGE3:
+            smiWrite(0, 16, (rdata & 0xFFFD) | 0x8000);
+            break;
+        case RTL8306_REGPAGE4:
+            smiRead(5, 16, &rdata);
+            rdata |= 0x2;
+            smiWrite(5, 16, rdata);            
+            break;
+        default:
+            return FAILED;
+    }
+
+    smiRead(phyad, regad, pvalue);
+
+    *pvalue = *pvalue & 0xFFFF;
+    if(RTL8306_REGPAGE4 == npage)
+    {
+        /*exit page 4*/
+        smiRead(5, 16, &rdata);
+        rdata &= ~0x2;
+        smiWrite(5, 16, rdata);        
+    }
+        
+    return SUCCESS;
+
+}
+
+
+/* Function Name:
+ *      rtl8306e_regbit_set
+ * Description:
+ *      Write one bit of Asic Register
+ * Input:
+ *      phyad   - Specify Phy address (0 ~6)
+ *      regad    - Specify register address (0 ~31)
+ *      bit        - Specify bit position(0 ~ 15)
+ *      npage   - Specify page number (0 ~3)
+ *      value    - Value to be write(0, 1)
+ * Output:
+ *      none
+ * Return:
+ *      SUCCESS
+ *      FAILED
+ * Note:
+ *      Use this function  you could write each bit of  all configurable registers of RTL8306.
+ */
+
+int32 rtl8306e_regbit_set(uint32 phyad, uint32 regad, uint32 bit, uint32 npage,  uint32 value) 
+{
+    uint32 rdata;
+    
+    if ((phyad >= RTL8306_PHY_NUMBER) || (npage >= RTL8306_PAGE_NUMBER) ||
+        (bit > 15) || (value > 1))
+        return FAILED;
+    
+    rtl8306e_reg_get(phyad, regad,  npage, &rdata);
+    if (value) 
+        rtl8306e_reg_set(phyad, regad, npage, rdata | (1 << bit));
+    else
+        rtl8306e_reg_set(phyad, regad, npage, rdata & (~(1 << bit)));
+    return SUCCESS;
+}
+
+
+/* Function Name:
+ *      rtl8306e_regbit_get
+ * Description:
+ *      Read one bit of Asic  PHY Register
+ * Input:
+ *      phyad   - Specify Phy address (0 ~6)
+ *      regad    - Specify register address (0 ~31)
+ *      bit        - Specify bit position(0 ~ 15)
+ *      npage   - Specify page number (0 ~3)
+ * Output:
+ *      pvalue  - The pointer of value read back
+ * Return:
+ *      SUCCESS
+ *      FAILED
+ * Note:
+ *      Use this function you could read each bit of  all configurable registers of RTL8306
+ */
+
+int32 rtl8306e_regbit_get(uint32 phyad, uint32 regad, uint32 bit, uint32 npage,  uint32 * pvalue) 
+{
+    uint32 rdata;
+
+    if ((phyad >= RTL8306_PHY_NUMBER) || (npage >= RTL8306_PAGE_NUMBER) || 
+        (bit > 15) || (pvalue == NULL))
+        return FAILED;
+    
+    rtl8306e_reg_get(phyad, regad, npage, &rdata);
+    if (rdata & (1 << bit))
+        *pvalue =1;
+    else 
+        *pvalue =0;
+
+    return SUCCESS;
+}
+
+int32 rtl8306e_phyReg_set(uint32 phyad, uint32 regad, uint32 npage, uint32 value) 
+{
+
+
+    uint32 rdata;
+    uint32 regval; 
+
+    if ((phyad >= RTL8306_PHY_NUMBER) || (npage > 0x5))
+        return FAILED;
+
+    /*read/write pcs register*/
+    smiRead(5, 16, &rdata); 
+    smiWrite(5, 16, rdata|0x0001);
+
+    /*Select PHY Register Page*/
+    smiRead(phyad, 31, &regval);
+    regval &= ~0xFF;
+    regval |= npage;
+    smiWrite(phyad, 31, regval);
+
+    smiWrite(phyad, regad, value);
+
+    smiWrite(5, 16, rdata & (~0x0001));
+    
+    return SUCCESS;
+}
+
+int32 rtl8306e_phyReg_get(uint32 phyad, uint32 regad, uint32 npage, uint32 *pvalue)
+{
+
+    uint32 rdata;
+    uint32 regval; 
+
+    if ((phyad >= RTL8306_PHY_NUMBER) || (npage > 0x5))
+        return FAILED;
+
+    /*read/write pcs register*/
+    smiRead(5, 16, &rdata);
+    smiWrite(5, 16, rdata|0x0001);
+
+    /*Select PHY Register Page*/
+    smiRead(phyad, 31, &regval);
+    regval &= ~0xFF;
+    regval |= npage;
+    smiWrite(phyad, 31, regval);
+    													
+    smiRead(phyad, regad, pvalue);
+
+    *pvalue = *pvalue & 0xFFFF;
+
+    smiWrite(5, 16, rdata & (~0x0001));
+    
+    return SUCCESS;
+    
+
+}
+
+int32 rtl8306e_asic_init(void)
+{
+    uint32 regval;
+    uint32 regval2;
+    uint32 regval3;
+    uint32 phy;
+    
+    /*by default: enable xor lut hash algorithm*/
+    rtl8306e_regbit_set(1, 23, 12, 0, 1);
+
+#ifdef RTL8306_LUT_CACHE
+    memset(rtl8306_LutCache, 0, sizeof(rtl8306_LutCache));
+#endif
+
+    rtl8306e_regbit_set(0, 16, 11, 0, 1);
+    rtl8306e_regbit_set(4, 23, 5, 0, 1); 
+    rtl8306e_reg_get(4, 30, 0, &regval);
+    rtl8306e_reg_get(4, 26, 0, &regval2);
+    rtl8306e_regbit_set(0, 16, 11, 0, 0);
+    rtl8306e_regbit_set(4, 23, 5, 0, 0); 
+    if (0x6167 == regval)
+    {
+        if ((((regval2 & (0x7<<13)) >> 13) == 1) || (((regval2 & (0x7<<13)) >> 13) == 2))
+        {
+            for (phy = 0; phy <= 4; phy++)
+            {
+                rtl8306e_phyReg_get(phy, 22, 0, &regval3);
+                regval3 &= ~(0x1 << 14);
+                rtl8306e_phyReg_set(phy, 22, 0, regval3);        
+            }
+        }
+        if (((regval2 & (0x7<<13)) >> 13) == 1)
+        {
+            rtl8306e_regbit_set(0, 19, 2, 0, 0);
+            rtl8306e_regbit_set(4, 23, 8, 0, 1);
+            rtl8306e_reg_get(0, 31, 3, &regval3);
+            regval3 &= ~0x3;
+            regval3 |= 0x2;
+            rtl8306e_reg_set(0, 31, 3, regval3);
+            rtl8306e_reg_get(1, 31, 3, &regval3);
+            regval3 &= ~0x3;
+            regval3 |= 0x2;
+            rtl8306e_reg_set(1, 31, 3, regval3);
+            rtl8306e_reg_get(2, 31, 3, &regval3);
+            regval3 &= ~0x3;
+            regval3 |= 0x2;
+            rtl8306e_reg_set(2, 31, 3, regval3);
+            rtl8306e_reg_get(3, 31, 3, &regval3);
+            regval3 &= ~0x3;
+            regval3 |= 0x2;
+            rtl8306e_reg_set(3, 31, 3, regval3);
+            rtl8306e_reg_get(5, 31, 3, &regval3);
+            regval3 &= ~0x3;
+            regval3 |= 0x2;
+            rtl8306e_reg_set(5, 31, 3, regval3);
+            rtl8306e_regbit_set(4, 23, 8, 0, 0);
+
+            rtl8306e_phyReg_get(0, 25, 4, &regval3);
+            regval3 &= ~(0x7 << 4);
+            regval3 |= (0x6 << 4);
+            rtl8306e_phyReg_set(0, 25, 4, regval3);
+
+            rtl8306e_phyReg_get(0, 28, 4, &regval3);
+            regval3 &= ~(0x1 << 8);
+            regval3 |= (0x1 << 8);
+            rtl8306e_phyReg_set(0, 28, 4, regval3);
+
+            rtl8306e_phyReg_set(0, 29, 4, 0x5000);
+            rtl8306e_phyReg_set(0, 29, 4, 0x6000);
+            rtl8306e_phyReg_set(0, 29, 4, 0x7000);
+            rtl8306e_phyReg_set(0, 29, 4, 0x4000);
+            rtl8306e_phyReg_set(0, 29, 4, 0x8700);
+            rtl8306e_phyReg_set(0, 29, 4, 0xD36C);
+            rtl8306e_phyReg_set(0, 29, 4, 0xFFFF);
+            rtl8306e_phyReg_set(0, 29, 4, 0xCA6C);
+            rtl8306e_phyReg_set(0, 29, 4, 0xFFFD);
+            rtl8306e_phyReg_set(0, 29, 4, 0x5060);
+            rtl8306e_phyReg_set(0, 29, 4, 0x61C5);
+            rtl8306e_phyReg_set(0, 29, 4, 0x7010);
+            rtl8306e_phyReg_set(0, 29, 4, 0x4001);
+            rtl8306e_phyReg_set(0, 29, 4, 0x5061);
+            rtl8306e_phyReg_set(0, 29, 4, 0x4001);
+            rtl8306e_phyReg_set(0, 29, 4, 0x87F1);
+            rtl8306e_phyReg_set(0, 29, 4, 0xCE60);
+            rtl8306e_phyReg_set(0, 29, 4, 0x0026);
+            rtl8306e_phyReg_set(0, 29, 4, 0x8E03);
+            rtl8306e_phyReg_set(0, 29, 4, 0xA021);
+            rtl8306e_phyReg_set(0, 29, 4, 0x300F);
+            rtl8306e_phyReg_set(0, 29, 4, 0x58A0);
+            rtl8306e_phyReg_set(0, 29, 4, 0x629C);
+            rtl8306e_phyReg_set(0, 29, 4, 0x7010);
+            rtl8306e_phyReg_set(0, 29, 4, 0x4002);
+            rtl8306e_phyReg_set(0, 29, 4, 0x58A1);
+            rtl8306e_phyReg_set(0, 29, 4, 0x87E6);
+            rtl8306e_phyReg_set(0, 29, 4, 0xAE25);
+            rtl8306e_phyReg_set(0, 29, 4, 0xA018);
+            rtl8306e_phyReg_set(0, 29, 4, 0x301A);
+            rtl8306e_phyReg_set(0, 29, 4, 0x6E94);
+            rtl8306e_phyReg_set(0, 29, 4, 0x6694);
+            rtl8306e_phyReg_set(0, 29, 4, 0x5123);
+            rtl8306e_phyReg_set(0, 29, 4, 0x63C2);
+            rtl8306e_phyReg_set(0, 29, 4, 0x5127);
+            rtl8306e_phyReg_set(0, 29, 4, 0x4003);
+            rtl8306e_phyReg_set(0, 29, 4, 0x87DC);
+            rtl8306e_phyReg_set(0, 29, 4, 0x8EF3);
+            rtl8306e_phyReg_set(0, 29, 4, 0xA10E);
+            rtl8306e_phyReg_set(0, 29, 4, 0xCC40);
+            rtl8306e_phyReg_set(0, 29, 4, 0x0007);
+            rtl8306e_phyReg_set(0, 29, 4, 0xCA40);
+            rtl8306e_phyReg_set(0, 29, 4, 0xFFDF);
+            rtl8306e_phyReg_set(0, 29, 4, 0xA202);
+            rtl8306e_phyReg_set(0, 29, 4, 0x3024);
+            rtl8306e_phyReg_set(0, 29, 4, 0x7018);
+            rtl8306e_phyReg_set(0, 29, 4, 0x3024);
+            rtl8306e_phyReg_set(0, 29, 4, 0xCC44);
+            rtl8306e_phyReg_set(0, 29, 4, 0xFFF4);
+            rtl8306e_phyReg_set(0, 29, 4, 0xCC44);
+            rtl8306e_phyReg_set(0, 29, 4, 0xFFF2);
+            rtl8306e_phyReg_set(0, 29, 4, 0x3000);
+            rtl8306e_phyReg_set(0, 29, 4, 0x5220);
+            rtl8306e_phyReg_set(0, 29, 4, 0x4004);
+            rtl8306e_phyReg_set(0, 29, 4, 0x3000);
+            rtl8306e_phyReg_set(0, 29, 4, 0x64A0);
+            rtl8306e_phyReg_set(0, 29, 4, 0x5429);
+            rtl8306e_phyReg_set(0, 29, 4, 0x4005);
+            rtl8306e_phyReg_set(0, 29, 4, 0x87C6);
+            rtl8306e_phyReg_set(0, 29, 4, 0xCE18);
+            rtl8306e_phyReg_set(0, 29, 4, 0xFFC4);
+            rtl8306e_phyReg_set(0, 29, 4, 0xCE64);
+            rtl8306e_phyReg_set(0, 29, 4, 0xFFCF);
+            rtl8306e_phyReg_set(0, 29, 4, 0x303A);
+            rtl8306e_phyReg_set(0, 29, 4, 0x65C0);
+            rtl8306e_phyReg_set(0, 29, 4, 0x50A9);
+            rtl8306e_phyReg_set(0, 29, 4, 0x4006);
+            rtl8306e_phyReg_set(0, 29, 4, 0xA3DB);
+            rtl8306e_phyReg_set(0, 29, 4, 0x3043);
+            rtl8306e_phyReg_set(0, 29, 4, 0x5000);
+            rtl8306e_phyReg_set(0, 29, 4, 0x60F3);
+            rtl8306e_phyReg_set(0, 29, 4, 0x5008);
+            rtl8306e_phyReg_set(0, 29, 4, 0x7010);
+            rtl8306e_phyReg_set(0, 29, 4, 0x4000);
+            rtl8306e_phyReg_set(0, 29, 4, 0x87B6);
+            rtl8306e_phyReg_set(0, 29, 4, 0xA3B5);
+            rtl8306e_phyReg_set(0, 29, 4, 0xD36C);
+            rtl8306e_phyReg_set(0, 29, 4, 0xFFFD);
+            rtl8306e_phyReg_set(0, 29, 4, 0xCA68);
+            rtl8306e_phyReg_set(0, 29, 4, 0xFFBA);
+            rtl8306e_phyReg_set(0, 29, 4, 0x0000);
+            rtl8306e_phyReg_set(0, 29, 4, 0x0000);
+            rtl8306e_phyReg_set(0, 29, 4, 0x0000);
+            rtl8306e_phyReg_set(0, 29, 4, 0x0000);
+            rtl8306e_phyReg_set(0, 29, 4, 0x0000);
+            rtl8306e_phyReg_set(0, 29, 4, 0x0000);
+            rtl8306e_phyReg_set(0, 29, 4, 0x0000);
+            rtl8306e_phyReg_set(0, 29, 4, 0x0000);
+            rtl8306e_phyReg_set(0, 29, 4, 0x0000);
+            rtl8306e_phyReg_set(0, 29, 4, 0x0000);
+            rtl8306e_phyReg_set(0, 29, 4, 0x0000);
+            rtl8306e_phyReg_set(0, 29, 4, 0x0000);
+            rtl8306e_phyReg_set(0, 29, 4, 0x0000);
+            rtl8306e_phyReg_set(0, 29, 4, 0x0000);
+            rtl8306e_phyReg_set(0, 29, 4, 0x0000);
+            rtl8306e_phyReg_set(0, 29, 4, 0x0000);
+            rtl8306e_phyReg_set(0, 29, 4, 0x0000);
+            rtl8306e_phyReg_set(0, 29, 4, 0x0000);
+            rtl8306e_phyReg_set(0, 29, 4, 0x0000);
+            rtl8306e_phyReg_set(0, 29, 4, 0x0000);
+            rtl8306e_phyReg_set(0, 29, 4, 0x0000);
+            rtl8306e_phyReg_set(0, 29, 4, 0x0000);
+            rtl8306e_phyReg_set(0, 29, 4, 0x0000);
+            rtl8306e_phyReg_set(0, 29, 4, 0x0000);
+            rtl8306e_phyReg_set(0, 29, 4, 0x0000);
+            rtl8306e_phyReg_set(0, 29, 4, 0x0000);
+            rtl8306e_phyReg_set(0, 29, 4, 0x0000);
+            rtl8306e_phyReg_set(0, 29, 4, 0x0000);
+            rtl8306e_phyReg_set(0, 29, 4, 0x0000);
+            rtl8306e_phyReg_set(0, 29, 4, 0x0000);
+            rtl8306e_phyReg_set(0, 29, 4, 0x0000);
+            rtl8306e_phyReg_set(0, 29, 4, 0x0000);
+            rtl8306e_phyReg_set(0, 29, 4, 0x0000);
+            rtl8306e_phyReg_set(0, 29, 4, 0x0000);
+            rtl8306e_phyReg_set(0, 29, 4, 0x0000);
+            rtl8306e_phyReg_set(0, 29, 4, 0x0000);
+            rtl8306e_phyReg_set(0, 29, 4, 0x0000);
+            rtl8306e_phyReg_set(0, 29, 4, 0x0000);
+            rtl8306e_phyReg_set(0, 29, 4, 0x0000);
+            rtl8306e_phyReg_set(0, 29, 4, 0x0000);
+            rtl8306e_phyReg_set(0, 29, 4, 0x0000);
+            rtl8306e_phyReg_set(0, 29, 4, 0x0000);
+            rtl8306e_phyReg_set(0, 29, 4, 0x0000);
+            rtl8306e_phyReg_set(0, 29, 4, 0x0000);
+            rtl8306e_phyReg_set(0, 29, 4, 0x0000);
+            rtl8306e_phyReg_set(0, 29, 4, 0x0000);
+            rtl8306e_phyReg_set(0, 29, 4, 0x0000);
+            rtl8306e_phyReg_set(0, 29, 4, 0x0000);
+
+            rtl8306e_phyReg_get(0, 28, 4, &regval3);
+            regval3 &= ~(0x1 << 8);
+            rtl8306e_phyReg_set(0, 28, 4, regval3);
+
+            rtl8306e_phyReg_get(0, 25, 4, &regval3);
+            regval3 &= ~(0x7 << 4);
+            regval3 |= (0x3 << 4);
+            rtl8306e_phyReg_set(0, 25, 4, regval3);
+
+            for (phy = 0; phy <= 4; phy++)
+            {
+                rtl8306e_phyReg_get(phy, 24, 4, &regval3);
+                regval3 &= ~(0xFF);
+                regval3 |= 0xF3;
+                rtl8306e_phyReg_set(phy, 24, 4, regval3);
+            }
+            
+            /*RTCT*/
+            for (phy = 0; phy <= 4; phy++)
+            {
+                rtl8306e_phyReg_get(phy, 16, 2, &regval3);
+                regval3 &= ~(0x3FF);
+                regval3 |= 0xFA;
+                rtl8306e_phyReg_set(phy, 16, 2, regval3);
+                rtl8306e_phyReg_get(phy, 22, 2, &regval3);
+                regval3 &= ~(0x7FF);
+                regval3 |= 0x12C;
+                rtl8306e_phyReg_set(phy, 22, 2, regval3);
+                rtl8306e_phyReg_get(phy, 23, 2, &regval3);
+                regval3 &= ~(0x3FF);
+                regval3 |= 0xC8;
+                rtl8306e_phyReg_set(phy, 23, 2, regval3);
+                rtl8306e_phyReg_get(phy, 24, 2, &regval3);
+                regval3 &= ~(0x1FF);
+                regval3 |= 0x32;
+                rtl8306e_phyReg_set(phy, 24, 2, regval3);
+                rtl8306e_phyReg_get(phy, 19, 2, &regval3);
+                regval3 &= ~(0xF << 12);
+                regval3 |= (0x4 << 12);
+                rtl8306e_phyReg_set(phy, 19, 2, regval3);
+                rtl8306e_phyReg_get(phy, 18, 2, &regval3);
+                regval3 &= ~(0x1F << 10);
+                regval3 |= (0x5 << 10);
+                rtl8306e_phyReg_set(phy, 18, 2, regval3);
+                rtl8306e_phyReg_get(phy, 25, 2, &regval3);
+                regval3 &= ~(0xFF << 8);
+                regval3 |= (0x4 << 8);
+                rtl8306e_phyReg_set(phy, 25, 2, regval3);
+                rtl8306e_phyReg_get(phy, 25, 2, &regval3);
+                regval3 &= ~0xFF;
+                regval3 |= 0x40;
+                rtl8306e_phyReg_set(phy, 25, 2, regval3);
+                
+            }
+        }    
+    }
+
+    return SUCCESS;
+}
+
+/* Function Name:
+ *      rtl8306e_phy_reset
+ * Description:
+ *      Reset the phy
+ * Input:
+ *      phy   - Specify Phy address (0 ~4)
+ * Output:
+ *      none
+ * Return:
+ *      SUCCESS
+ *      FAILED
+ * Note:
+ */
+int32 rtl8306e_phy_reset(uint32 phy)
+{
+    uint32 regval, regval2;
+    uint32 nway, pause, dupSpd;
+    if (phy > 4)
+        return FAILED;
+    
+    rtl8306e_regbit_set(0, 16, 11, 0, 1);
+    rtl8306e_regbit_set(4, 23, 5, 0, 1); 
+    rtl8306e_reg_get(4, 30, 0, &regval);
+    rtl8306e_reg_get(4, 26, 0, &regval2);
+    rtl8306e_regbit_set(0, 16, 11, 0, 0);
+    rtl8306e_regbit_set(4, 23, 5, 0, 0); 
+    if ((0x6167 == regval) && ((regval2 & (0x7<<13)) >> 13 == 1))
+    {
+        rtl8306e_regbit_get(phy, 22, 6, 0, &nway);
+        rtl8306e_regbit_get(phy, 22, 3, 0, &pause);
+        rtl8306e_reg_get(phy, 22, 0, &dupSpd);
+          
+        rtl8306e_regbit_set(phy, 0, 15, 0, 1);
+        if (nway)
+        {
+            switch((dupSpd & (0x3 << 4)) >> 4)
+            {
+                case 0x3:
+                    rtl8306e_regbit_set(phy, 0, 8, 0, 1);
+                    rtl8306e_regbit_set(phy, 0, 13, 0, 1);
+                    rtl8306e_regbit_set(phy, 4, 8, 0, 1);
+                    rtl8306e_regbit_set(phy, 4, 7, 0, 1);
+                    rtl8306e_regbit_set(phy, 4, 6, 0, 1);
+                    rtl8306e_regbit_set(phy, 4, 5, 0, 1);
+                    break;
+                case 0x2:
+                    rtl8306e_regbit_set(phy, 0, 8, 0, 0);
+                    rtl8306e_regbit_set(phy, 0, 13, 0, 1);
+                    rtl8306e_regbit_set(phy, 4, 8, 0, 0);
+                    rtl8306e_regbit_set(phy, 4, 7, 0, 1);
+                    rtl8306e_regbit_set(phy, 4, 6, 0, 1);
+                    rtl8306e_regbit_set(phy, 4, 5, 0, 1);
+                    break;
+                case 0x1:
+                    rtl8306e_regbit_set(phy, 0, 8, 0, 1);
+                    rtl8306e_regbit_set(phy, 0, 13, 0, 0);
+                    rtl8306e_regbit_set(phy, 4, 8, 0, 0);
+                    rtl8306e_regbit_set(phy, 4, 7, 0, 0);
+                    rtl8306e_regbit_set(phy, 4, 6, 0, 1);
+                    rtl8306e_regbit_set(phy, 4, 5, 0, 1);
+                    break;
+                case 0x0:
+                    rtl8306e_regbit_set(phy, 0, 8, 0, 0);
+                    rtl8306e_regbit_set(phy, 0, 13, 0, 0);
+                    rtl8306e_regbit_set(phy, 4, 8, 0, 0);
+                    rtl8306e_regbit_set(phy, 4, 7, 0, 0);
+                    rtl8306e_regbit_set(phy, 4, 6, 0, 0);
+                    rtl8306e_regbit_set(phy, 4, 5, 0, 1);
+                    break;
+                default:
+                   break;
+            } 
+            rtl8306e_regbit_set(phy, 0, 12, 0, 1);
+            rtl8306e_regbit_set(phy, 0, 9, 0, 1);
+        }
+        else
+        {
+            rtl8306e_regbit_set(phy, 0, 12, 0, 0);
+            switch((dupSpd & (0x3 << 4)) >> 4)
+            {
+                case 0x3:
+                    rtl8306e_regbit_set(phy, 0, 8, 0, 1);
+                    rtl8306e_regbit_set(phy, 0, 13, 0, 1);
+                    rtl8306e_regbit_set(phy, 4, 8, 0, 1);
+                    rtl8306e_regbit_set(phy, 4, 7, 0, 0);
+                    rtl8306e_regbit_set(phy, 4, 6, 0, 0);
+                    rtl8306e_regbit_set(phy, 4, 5, 0, 0);
+                    break;
+                case 0x2:
+                    rtl8306e_regbit_set(phy, 0, 8, 0, 0);
+                    rtl8306e_regbit_set(phy, 0, 13, 0, 1);
+                    rtl8306e_regbit_set(phy, 4, 8, 0, 0);
+                    rtl8306e_regbit_set(phy, 4, 7, 0, 1);
+                    rtl8306e_regbit_set(phy, 4, 6, 0, 0);
+                    rtl8306e_regbit_set(phy, 4, 5, 0, 0);
+                    break;
+                case 0x1:
+                    rtl8306e_regbit_set(phy, 0, 8, 0, 1);
+                    rtl8306e_regbit_set(phy, 0, 13, 0, 0);
+                    rtl8306e_regbit_set(phy, 4, 8, 0, 0);
+                    rtl8306e_regbit_set(phy, 4, 7, 0, 0);
+                    rtl8306e_regbit_set(phy, 4, 6, 0, 1);
+                    rtl8306e_regbit_set(phy, 4, 5, 0, 0);
+                    break;
+                case 0x0:
+                    rtl8306e_regbit_set(phy, 0, 8, 0, 0);
+                    rtl8306e_regbit_set(phy, 0, 13, 0, 0);
+                    rtl8306e_regbit_set(phy, 4, 8, 0, 0);
+                    rtl8306e_regbit_set(phy, 4, 7, 0, 0);
+                    rtl8306e_regbit_set(phy, 4, 6, 0, 0);
+                    rtl8306e_regbit_set(phy, 4, 5, 0, 1);
+                    break;
+                default:
+                   break;
+            }  
+        }
+        
+        rtl8306e_regbit_set(phy, 4, 10, 0, pause);
+        
+    }
+    else
+        rtl8306e_regbit_set(phy, 0, 15, 0, 1);
+
+    return SUCCESS;
+}
+
+/* Function Name:
+ *      rtl8306e_switch_maxPktLen_set
+ * Description:
+ *      set Max packet length which could be forwarded by
+ * Input:
+ *      maxLen         -  max packet length
+ * Output:
+ *      none
+ * Return:
+ *      SUCCESS
+ *      FAILED
+ * Note:
+ *      maxLen could be set : 
+ *      RTL8306_MAX_PKT_LEN_1518 -1518 bytes without any tag; 1522 bytes: 
+ *              with VLAN tag or CPU tag, 1526 bytes with CPU and VLAN tag;
+ *      RTL8306_MAX_PKT_LEN_1536 - 1536 bytes (all tags counted);
+ *      RTL8306_MAX_PKT_LEN_1552 - 1552 bytes (all tags counted); 
+ *      RTL8306_MAX_PKT_LEN_2000 - 2000 bytes (all tags counted) 
+ *              
+ */ 
+
+int32 rtl8306e_switch_maxPktLen_set(uint32 maxLen)
+{
+    switch(maxLen)
+    {
+        case RTL8306_MAX_PKT_LEN_1518:
+            rtl8306e_regbit_set(2, 23, 1, 3, 1);
+            rtl8306e_regbit_set(0, 29, 15, 3, 0);
+            break;
+
+        case RTL8306_MAX_PKT_LEN_1536:
+            rtl8306e_regbit_set(2, 23, 1, 3, 0);
+            rtl8306e_regbit_set(0, 18, 14, 0, 1);
+            rtl8306e_regbit_set(0, 29, 15, 3, 0);            
+            break;
+
+        case RTL8306_MAX_PKT_LEN_1552:
+            rtl8306e_regbit_set(2, 23, 1, 3, 0);
+            rtl8306e_regbit_set(0, 18, 14, 0, 0);
+            rtl8306e_regbit_set(0, 29, 15, 3, 0);            
+            break;
+
+        case RTL8306_MAX_PKT_LEN_2000:
+            rtl8306e_regbit_set(0, 29, 15, 3, 1);
+            break;
+            
+        default:
+            return FAILED;
+
+    }
+
+    return SUCCESS;
+}
+
+/* Function Name:
+ *      rtl8306e_switch_maxPktLen_get
+ * Description:
+ *      set Max packet length which could be forwarded by
+ * Input:
+ *      none
+ * Output:
+ *      maxLen         -  max packet length
+ * Return:
+ *      SUCCESS
+ *      FAILED
+ * Note:
+ *      maxLen could be set : 
+ *      RTL8306_MAX_PKT_LEN_1518 -1518 bytes without any tag; 1522 bytes: 
+ *              with VLAN tag or CPU tag, 1526 bytes with CPU and VLAN tag;
+ *      RTL8306_MAX_PKT_LEN_1536 - 1536 bytes (all tags counted);
+ *      RTL8306_MAX_PKT_LEN_1552 - 1552 bytes (all tags counted); 
+ *      RTL8306_MAX_PKT_LEN_2000 - 2000 bytes (all tags counted) 
+ *              
+ */ 
+int32 rtl8306e_switch_maxPktLen_get(uint32 *pMaxLen)
+{
+    uint32 regval;
+
+    if (pMaxLen == NULL)
+        return FAILED;
+    
+    rtl8306e_regbit_get(0, 29, 15, 3, &regval);
+    if(regval)
+    {
+        *pMaxLen = RTL8306_MAX_PKT_LEN_2000;
+    }
+    else
+    {
+        rtl8306e_regbit_get(2, 23, 1, 3, &regval);
+        if (regval)
+        {
+            *pMaxLen = RTL8306_MAX_PKT_LEN_1518;
+        }
+        else 
+        {
+            rtl8306e_regbit_get(0, 18, 14, 0, &regval);
+            if (regval)
+            {
+                *pMaxLen = RTL8306_MAX_PKT_LEN_1536;            
+            }
+            else
+            {
+                *pMaxLen = RTL8306_MAX_PKT_LEN_1552;                        
+            }
+        }
+    }
+    
+    return SUCCESS;
+}
+
+
+/* Function Name:
+ *      rtl8306e_port_etherPhy_set
+ * Description:
+ *      Configure PHY setting
+ * Input:
+ *      phy                    - Specify the phy to configure
+ *      autoNegotiation    - Specify whether enable auto-negotiation
+ *      advCapability       - When auto-negotiation is enabled, specify the advertised capability
+ *      speed                 - When auto-negotiation is disabled, specify the force mode speed
+ *      fullDuplex            - When auto-negotiatoin is disabled, specify the force mode duplex mode
+ * Output:
+ *      none
+ * Return:
+ *      SUCCESS
+ *      FAILED
+ * Note:
+ *      When auto-negotiation is enabled, the advertisement capability is used to handshaking with link partner.
+ *      When auto-negotiation is disabled, the phy is configured into force mode and the speed and duplex mode 
+ *      setting is based on speed and fullDuplex setting.Port number should be smaller than RTL8306_PHY_NUMBER.
+ *      AdverCapability should be ranged between RTL8306_ETHER_AUTO_100FULL and RTL8306_ETHER_AUTO_10HALF.
+ *      Speed should be either RTL8306_ETHER_SPEED_100 or RTL8306_ETHER_SPEED_10.
+ */
+int32 rtl8306e_port_etherPhy_set(uint32 phy, uint32 autoNegotiation, uint32 advCapability, uint32 speed, uint32 fullDuplex) 
+{
+    uint32 ctrlReg;
+
+    if(phy >= RTL8306_PHY_NUMBER || 
+       advCapability < RTL8306_ETHER_AUTO_100FULL ||
+       advCapability > RTL8306_ETHER_AUTO_10HALF ||
+       (speed != 100 && speed != 10))
+           return FAILED;
+
+    if(RTL8306_ETHER_AUTO_100FULL == advCapability)
+        rtl8306e_reg_set(phy, 4, 0, RTL8306_CAPABLE_PAUSE | RTL8306_CAPABLE_100BASE_TX_FD 
+                                  | RTL8306_CAPABLE_100BASE_TX_HD | RTL8306_CAPABLE_10BASE_TX_FD 
+                                  | RTL8306_CAPABLE_10BASE_TX_HD | 0x1);
+    else if(RTL8306_ETHER_AUTO_100HALF == advCapability)
+        rtl8306e_reg_set(phy, 4, 0, RTL8306_CAPABLE_PAUSE | RTL8306_CAPABLE_100BASE_TX_HD
+                                  | RTL8306_CAPABLE_10BASE_TX_FD | RTL8306_CAPABLE_10BASE_TX_HD | 0x1);
+    else if( RTL8306_ETHER_AUTO_10FULL == advCapability)
+        rtl8306e_reg_set(phy, 4, 0, RTL8306_CAPABLE_PAUSE | RTL8306_CAPABLE_10BASE_TX_FD 
+                                  | RTL8306_CAPABLE_10BASE_TX_HD | 0x1);
+    else if(RTL8306_ETHER_AUTO_10HALF == advCapability)
+        rtl8306e_reg_set(phy, 4, 0, RTL8306_CAPABLE_PAUSE | RTL8306_CAPABLE_10BASE_TX_HD | 0x1);
+
+    /*Each time the link ability of the RTL8306 is reconfigured, 
+     *the auto-negotiation process should be executed to allow
+     *the configuration to take effect. 
+     */
+    if(TRUE == autoNegotiation) 
+        ctrlReg = RTL8306_ENABLE_AUTONEGO | RTL8306_RESTART_AUTONEGO; 
+    else
+        ctrlReg = 0;
+    if(100 == speed) 
+        ctrlReg |= RTL8306_SPEED_SELECT_100M;
+    if(TRUE == fullDuplex)
+        ctrlReg |= RTL8306_SELECT_FULL_DUPLEX;
+    rtl8306e_reg_set(phy, 0, RTL8306_REGPAGE0, ctrlReg);
+
+    return SUCCESS;
+}
+
+/* Function Name:
+ *      rtl8306e_port_etherPhy_get
+ * Description:
+ *       Get PHY setting
+ * Input:
+ *      phy                    - Specify the phy to configure
+ * Output:
+ *      pAutoNegotiation    - Get whether auto-negotiation is enabled
+ *      pAdvCapability       - When auto-negotiation is enabled, Get the advertised capability
+ *      pSpeed                 - When auto-negotiation is disabled, Get the force mode speed
+ *      pFullDuplex            - When auto-negotiatoin is disabled, Get the force mode duplex mode
+
+ * Return:
+ *      SUCCESS
+ *      FAILED
+ * Note:
+ *      When auto-negotiation is enabled, the advertisement capability is used to handshaking with link partner.
+ *      When auto-negotiation is disabled, the phy is configured into force mode and the speed and duplex mode 
+ *      setting is based on speed and fullDuplex setting.Port number should be smaller than RTL8306_PHY_NUMBER.
+ *      AdverCapability should be ranged between RTL8306_ETHER_AUTO_100FULL and RTL8306_ETHER_AUTO_10HALF.
+ *      Speed should be either RTL8306_ETHER_SPEED_100 or RTL8306_ETHER_SPEED_10.
+ */
+
+int32 rtl8306e_port_etherPhy_get(uint32 phy, uint32 *pAutoNegotiation, uint32 *pAdvCapability, uint32 *pSpeed, uint32 *pFullDuplex)
+{
+    uint32 regData;
+
+    if((phy >= RTL8306_PHY_NUMBER) || (NULL == pAutoNegotiation) || (NULL == pAdvCapability)
+        || (NULL ==  pSpeed) || (NULL == pFullDuplex))
+        return FAILED;
+
+    rtl8306e_reg_get(phy, 0, RTL8306_REGPAGE0, &regData);
+    *pAutoNegotiation = (regData & RTL8306_ENABLE_AUTONEGO) ? TRUE: FALSE;
+    *pSpeed = (regData & RTL8306_SPEED_SELECT_100M) ? 100: 10;
+    *pFullDuplex = (regData & RTL8306_SELECT_FULL_DUPLEX) ? TRUE: FALSE;
+
+    rtl8306e_reg_get(phy, 4, RTL8306_REGPAGE0, &regData);
+    if(regData & RTL8306_CAPABLE_100BASE_TX_FD)
+        *pAdvCapability = RTL8306_ETHER_AUTO_100FULL;
+    else if(regData & RTL8306_CAPABLE_100BASE_TX_HD)
+        *pAdvCapability = RTL8306_ETHER_AUTO_100HALF;
+    else if(regData & RTL8306_CAPABLE_10BASE_TX_FD)
+        *pAdvCapability = RTL8306_ETHER_AUTO_10FULL;
+    else if(regData & RTL8306_CAPABLE_10BASE_TX_HD)
+        *pAdvCapability = RTL8306_ETHER_AUTO_10HALF;
+    return SUCCESS;
+}
+
+/* Function Name:
+ *      rtl8306e_port_port5LinkStatus_set
+ * Description:
+ *      Force port 5 link up or link down
+ * Input:
+ *      enabled   - true or false
+ * Output:
+ *      none
+ * Return:
+ *      SUCCESS
+ *      FAILED
+ * Note:
+ *      Port 5 should be manully enable / disable
+ */
+int32 rtl8306e_port_port5LinkStatus_set(uint32 enabled) 
+{
+    uint32 duplex, speed, nway;
+
+    /*save phy 6 reg 0.13, 0.12, 0.8*/
+    rtl8306e_regbit_get(6, 0, 13, 0, &speed);
+    rtl8306e_regbit_get(6, 0, 12, 0, &nway);
+    rtl8306e_regbit_get(6, 0, 8, 0, &duplex);
+      
+    rtl8306e_regbit_set(6, 22, 15, 0, enabled ? 1:0);
+    
+    /*restore phy 6 reg 0.13, 0.12, 0.8*/
+    rtl8306e_regbit_set(6, 0, 13, 0, speed);
+    rtl8306e_regbit_set(6, 0, 12, 0, nway);
+    rtl8306e_regbit_set(6, 0, 8, 0, duplex);
+
+    return SUCCESS;       
+}
+
+/* Function Name:
+ *      rtl8306e_port_port5LinkStatus_get
+ * Description:
+ *      get port 5 link status
+ * Input:
+ *      none
+ * Output:
+*      enabled   - true or false
+ * Return:
+ *      SUCCESS
+ *      FAILED
+ * Note:
+ *      Port 5 should be manully enable / disable
+ */
+
+int32 rtl8306e_port_port5LinkStatus_get(uint32 *pEnabled)
+{
+    uint32 bitValue;
+
+    if (NULL == pEnabled) 
+        return FAILED;
+    
+    rtl8306e_regbit_get(6, 22, 15, 0, &bitValue);
+    *pEnabled = (bitValue ? TRUE : FALSE);
+    return SUCCESS;
+}
+
+
+/* Function Name:
+ *      rtl8306e_port_phyLinkStatus_get
+ * Description:
+ *      Get PHY Link Status
+ * Input:
+*      phy        - Specify the phy 
+ * Output:
+*      plinkUp   - Describe whether link status is up or not
+ * Return:
+ *      SUCCESS
+ *      FAILED
+ * Note:
+ *       Read the link status of PHY register 1
+ */
+
+int32 rtl8306e_port_phyLinkStatus_get(uint32 phy, uint32 *plinkUp) 
+{
+    uint32 bitValue;
+
+    if (NULL == plinkUp)
+        return FAILED;
+    
+    rtl8306e_regbit_get(phy, 1, 2, RTL8306_REGPAGE0, &bitValue);
+    rtl8306e_regbit_get(phy, 1, 2, RTL8306_REGPAGE0, &bitValue);    
+    *plinkUp = (bitValue ? TRUE: FALSE);
+
+    return SUCCESS;
+}
+
+/* Function Name:
+ *      rtl8306e_port_phyAutoNegotiationDone_get
+ * Description:
+ *      Get PHY auto-negotiation result status
+ * Input:
+ *      phy      - Specify the phy to get status
+ * Output:
+*      pDone   -  Describe whether auto-negotiation is done or not
+ * Return:
+ *      SUCCESS
+ *      FAILED
+ * Note:
+ *      Read the auto-negotiation complete of PHY register 1.
+ */
+
+int32 rtl8306e_port_phyAutoNegotiationDone_get(uint32 phy, uint32 *pDone) 
+{
+    uint32 bitValue;
+
+    if (NULL == pDone)
+        return FAILED;
+    
+    rtl8306e_regbit_get(phy, 1, 5, 0, &bitValue);
+    *pDone = (bitValue ? TRUE: FALSE);
+    return SUCCESS;
+}
+
+/* Function Name:
+ *      rtl8306e_port_phyLoopback_set
+ * Description:
+ *       Set PHY loopback
+ * Input:
+ *      phy         - Specify the phy to configure
+ *      enabled   - Enable phy loopback
+ * Output:
+ *      none      
+ * Return:
+ *      SUCCESS
+ *      FAILED
+ * Note:
+ *      Only phy 0~4 could be configured the phy loopback
+ */
+
+int32 rtl8306e_port_phyLoopback_set(uint32 phy, uint32 enabled) 
+{
+    if(phy > 4)
+        return FAILED;
+    rtl8306e_regbit_set(phy, 0, 14, 0, enabled ? 1 : 0);
+    return SUCCESS;
+}
+
+/* Function Name:
+ *      rtl8306e_port_phyLoopback_get
+ * Description:
+ *      Get PHY loopback setting
+ * Input:
+ *      phy         - Specify the phy to get status
+ * Output:
+ *      pEnabled  -  phy loopback setting
+ * Return:
+ *      SUCCESS
+ *      FAILED
+ * Note:
+ *
+ */
+
+int32 rtl8306e_port_phyLoopback_get(uint32 phy, uint32 *pEnabled) 
+{
+    uint32 bitValue;
+
+    if (NULL == pEnabled)
+        return FAILED;
+    
+    rtl8306e_regbit_get(phy, 0, 14, 0, &bitValue);
+    *pEnabled = (bitValue ? TRUE: FALSE);
+    return SUCCESS;
+}
+
+/* Function Name:
+ *      rtl8306e_portLearningAbility_set
+ * Description:
+ *      Enable/disable physical port learning ability
+ * Input:
+ *      port        - Specify port number (0 ~ 5)
+ * Output:
+ *      enabled -  TRUE or FALSE
+ * Return:
+ *      SUCCESS
+ * Note:
+ *
+ */
+int32 rtl8306e_portLearningAbility_set(uint32 port, uint32 enabled)
+{
+    if (port > RTL8306_PORT5)
+        return FAILED;
+    if (RTL8306_PORT5 == port)
+        port++;
+
+    rtl8306e_regbit_set(port, 24, 9, 0, enabled ? 1 : 0);
+
+    return SUCCESS;
+}
+
+/* Function Name:
+ *      rtl8306e_port_isolation_set
+ * Description:
+ *      set port isolation 
+ * Input:
+ *      isomsk    - port isolation port mask
+ * Output:
+ *      none
+ * Return:
+ *      SUCCESS
+ *      FAILED
+ * Note:
+ *      each bit of isomsk determine two port's isolation,
+ *      1 means two port could not forward packet between
+ *      each other.
+ *      bit 0  - Port0 & Port1 
+ *      bit 1  - Port0 & Port2 
+ *      bit 2  - Port0 & Port3
+ *      bit 3  - Port0 & Port4
+ *      bit 4  - Port0 & Port5
+ *      bit 5  - Port1 & Port2
+ *      bit 6  - Port1 & Port3
+ *      bit 7  - Port1 & Port4
+ *      bit 8  - Port1 & Port5
+ *      bit 9  - Port2 & Port3
+ *      bit 10 - Port2 & Port4
+ *      bit 11 - Port2 & Port5
+ *      bit 12 - Port3 & Port4
+ *      bit 13 - Port3 & Port5
+ *      bit 14 - Port4 & Port5
+ */
+
+int32 rtl8306e_port_isolation_set(uint32 isomsk)
+{
+    uint32 regval;
+
+    rtl8306e_reg_get(0, 29, 3, &regval);
+    regval &= ~0x7FFF;
+    regval |= isomsk & 0x7FFF;
+    rtl8306e_reg_set(0, 29, 3, regval);
+    
+    return SUCCESS;
+}
+
+
+/* Function Name:
+ *      rtl8306e_port_isolation_set
+ * Description:
+ *      set port isolation 
+ * Input:
+ *      none
+ * Output:
+ *      pIsomsk    -  the pointer of port isolation port mask
+ * Return:
+ *      SUCCESS
+ *      FAILED
+ * Note:
+ *      each bit of isomsk determine two port's isolation,
+ *      1 means two port could not forward packet between
+ *      each other.
+ *      bit 0  - Port0 & Port1 
+ *      bit 1  - Port0 & Port2 
+ *      bit 2  - Port0 & Port3
+ *      bit 3  - Port0 & Port4
+ *      bit 4  - Port0 & Port5
+ *      bit 5  - Port1 & Port2
+ *      bit 6  - Port1 & Port3
+ *      bit 7  - Port1 & Port4
+ *      bit 8  - Port1 & Port5
+ *      bit 9  - Port2 & Port3
+ *      bit 10 - Port2 & Port4
+ *      bit 11 - Port2 & Port5
+ *      bit 12 - Port3 & Port4
+ *      bit 13 - Port3 & Port5
+ *      bit 14 - Port4 & Port5
+ */
+
+int32 rtl8306e_port_isolation_get(uint32 *pIsomsk)
+{
+    uint32 regval;
+
+    if (NULL == pIsomsk)
+        return FAILED;
+    rtl8306e_reg_get(0, 29, 3, &regval);
+    *pIsomsk = regval & 0x7FFF;
+
+    return SUCCESS;
+}
+
+
+/* Function Name:
+ *      rtl8306e_vlan_tagAware_set
+ * Description:
+ *      Configure switch to be VLAN tag awared
+ * Input:
+ *      enabled  - Configure RTL8306 VLAN tag awared
+ * Output:
+ *      none
+ * Return:
+ *      SUCCESS
+ *      FAILED
+ * Note:
+ *      If switch is unawared VLAN tag, packet with vlan tag is treated as untagged pkt
+ *      and assigned PVID as VID.
+ */
+int32 rtl8306e_vlan_tagAware_set(uint32 enabled) 
+{
+    rtl8306e_regbit_set(0, 16, 10, 0, enabled ? 0: 1);        
+#ifdef RTL8306_TBLBAK
+    rtl8306_TblBak.vlanConfig.enTagAware = (uint8) enabled;
+#endif
+    return SUCCESS;
+}
+
+/* Function Name:
+ *      rtl8306e_vlan_tagAware_set
+ * Description:
+ *      Get switch to be VLAN tag awared  or not
+ * Input:
+ *      none
+ * Output:
+ *      pEnabled  - the pointer of RTL8306 VLAN tag awared status
+ * Return:
+ *      SUCCESS
+ *      FAILED
+ * Note:
+ *      If switch is unawared VLAN tag, packet with vlan tag is treated as untagged pkt
+ *      and assigned PVID as VID.
+ */
+ 
+int32 rtl8306e_vlan_tagAware_get(uint32 * pEnabled) 
+{
+    uint32 bitValue;
+
+    if (NULL == pEnabled)
+        return FAILED;
+    
+    rtl8306e_regbit_get(0, 16, 10, 0, &bitValue);
+    *pEnabled = (bitValue ? FALSE: TRUE);
+    return SUCCESS;
+}
+
+/* Function Name:
+ *      rtl8306e_vlan_IgrFilterEnable_set
+ * Description:
+ *      Configure VLAN ingress filter
+ * Input:
+ *      enabled  - enable or disable
+ * Output:
+ *      none 
+ * Return:
+ *      SUCCESS
+ *      FAILED
+ * Note:
+ *
+ */
+int32 rtl8306e_vlan_IgrFilterEnable_set(uint32 enabled) 
+{
+
+    rtl8306e_regbit_set(0, 16, 9, 0, enabled ? 0 : 1);    
+#ifdef RTL8306_TBLBAK
+    rtl8306_TblBak.vlanConfig.enIngress = (uint8) enabled;
+#endif
+    return SUCCESS;
+}
+
+/* Function Name:
+ *      rtl8306e_vlan_IgrFilterEnable_get
+ * Description:
+ *      Get VLAN ingress filter enabled or disabled
+ * Input:
+ *      none
+ * Output:
+ *      pEnabled  - enable or disable
+ * Return:
+ *      SUCCESS
+ *      FAILED
+ * Note:
+ *
+ */
+int32 rtl8306e_vlan_IgrFilterEnable_get(uint32 *pEnabled) 
+{
+    uint32 bitValue;
+
+    if (NULL == pEnabled)
+        return FAILED;
+    
+    rtl8306e_regbit_get(0, 16, 9, 0, &bitValue);
+    *pEnabled = (bitValue ? 0: 1);
+    return SUCCESS;
+}
+
+
+/* Function Name:
+ *      rtl8306e_vlan_leaky_set
+ * Description:
+ *      Configure switch to forward frames to other VLANs ignoring the egress rule.
+ * Input:
+ *      type   -  vlan leaky type
+ *      enabled  - enable or disable
+ * Output:
+ *      none 
+ * Return:
+ *      SUCCESS
+ *      FAILED
+ * Note:
+ *      type coulde be:
+ *          RTL8306_VALN_LEAKY_UNICAST - Vlan leaky for unicast pkt
+ *          RTL8306_VALN_LEAKY_MULTICAST - Vlan leaky for multicast pkt
+ *          RTL8306_VALN_LEAKY_ARP - Vlan leaky for ARP brodcast pkt 
+ *          RTL8306_VALN_LEAKY_MIRROR - Vlan leaky for mirror function
+
+ *    1.When the Vlan leaky for unicast pkt is enabled, it enables the inter-VLANs unicast packet forwarding. 
+ *    That is, if the L2 look up MAC table search hit, then the unicast packet will be forwarded
+ *    to the egress port ignoring the egress rule.
+ *    2.When Vlan leaky for multicast pkt is enabled, multicast packet may be flood to all multicast address
+ *    group member set, ignoring the VLAN member set domain limitation.
+ *    3.When Vlan leaky for ARP pkt is enabled, the ARP broadcast packets will be forward to all the other
+ *    ports ignoring the egress rule.
+ *    4.When Vlan leaky for mirror function is enabled, it enables the inter-VLANs mirror function, 
+ *    ignoring the VLAN member set domain limitation.
+ */
+int32 rtl8306e_vlan_leaky_set(uint32 type, uint32 enabled)
+{
+    switch(type) 
+    {
+        case RTL8306_VALN_LEAKY_UNICAST:
+            rtl8306e_regbit_set(0, 18, 11, 0, enabled ? 0 : 1);
+#ifdef RTL8306_TBLBAK
+            rtl8306_TblBak.vlanConfig.enLeakVlan = (uint8) enabled;
+#endif
+            break;
+        case RTL8306_VALN_LEAKY_MULTICAST:
+            rtl8306e_regbit_set(2, 23, 7, 3, enabled ? 0 : 1);
+#ifdef RTL8306_TBLBAK
+            rtl8306_TblBak.vlanConfig.enIPMleaky = (uint8) enabled;
+#endif
+            break;
+        case RTL8306_VALN_LEAKY_ARP:
+            rtl8306e_regbit_set(0, 18, 10, 0, enabled ? 0 : 1);
+#ifdef RTL8306_TBLBAK
+            rtl8306_TblBak.vlanConfig.enArpVlan = (uint8) enabled;
+#endif
+            break;
+        case RTL8306_VALN_LEAKY_MIRROR:
+            rtl8306e_regbit_set(2, 23, 6, 3, enabled ? 0 : 1);
+#ifdef RTL8306_TBLBAK
+            rtl8306_TblBak.vlanConfig.enMirLeaky = (uint8) enabled;
+#endif
+            break;
+        default:
+            return FAILED;
+    }    
+    return SUCCESS;
+}
+
+/* Function Name:
+ *      rtl8306e_vlan_leaky_get
+ * Description:
+ *      Get switch whether forwards unicast frames to other VLANs
+ * Input:
+ *      type   -  vlan leaky type
+ * Output:
+ *      pEnabled  - the pointer of Vlan Leaky status(Dsiabled or Enabled) 
+ * Return:
+ *      SUCCESS
+ *      FAILED
+ * Note:
+ *   type coulde be:
+ *          RTL8306_VALN_LEAKY_UNICAST - Vlan leaky for unicast pkt
+ *          RTL8306_VALN_LEAKY_MULTICAST - Vlan leaky for multicast pkt
+ *          RTL8306_VALN_LEAKY_ARP - Vlan leaky for ARP brodcast pkt 
+ *    1.When the Vlan leaky for unicast pkt is enabled, it enables the inter-VLANs unicast packet forwarding. 
+ *    That is, if the L2 look up MAC table search hit, then the unicast packet will be forwarded
+ *    to the egress port ignoring the egress rule.
+ *    2.When Vlan leaky for multicast pkt is enabled, multicast packet may be flood to all multicast address
+ *    group member set, ignoring the VLAN member set domain limitation.
+ *    3.When Vlan leaky for ARP pkt is enabled, the ARP broadcast packets will be forward to all the other
+ *    ports ignoring the egress rule.
+ *    4.When Vlan leaky for mirror function is enabled, it enables the inter-VLANs mirror function, 
+ *    ignoring the VLAN member set domain limitation.
+ */
+
+int32 rtl8306e_vlan_leaky_get(uint32 type, uint32 *pEnabled)
+{
+    uint32 bitValue;
+
+    if(NULL == pEnabled)
+        return FAILED;
+
+    switch(type) 
+    {
+        case RTL8306_VALN_LEAKY_UNICAST:
+            rtl8306e_regbit_get(0, 18, 11, 0, &bitValue);
+            break;
+        case RTL8306_VALN_LEAKY_MULTICAST:
+            rtl8306e_regbit_get(2, 23, 7, 3, &bitValue);
+            break;
+        case RTL8306_VALN_LEAKY_ARP:
+            rtl8306e_regbit_get(0, 18, 10, 0, &bitValue);
+            break;
+        case RTL8306_VALN_LEAKY_MIRROR:
+            rtl8306e_regbit_get(2, 23, 6, 3, &bitValue);
+            break;
+        default:
+            return FAILED;
+    }
+    *pEnabled = (bitValue ?  FALSE : TRUE);
+
+    return SUCCESS;
+}
+
+/* Function Name:
+ *      rtl8306e_vlan_nullVidReplace_set
+ * Description:
+ *      Configure switch to replace Null VID tagged frame by PVID if it is tag aware
+ * Input:
+ *      port   -  port number
+ *      enabled  - enable or disable
+ * Output:
+ *      none 
+ * Return:
+ *      SUCCESS
+ *      FAILED
+ * Note:
+ *      1.When Null VID replacement is enabled, 8306E only captures tagged packet with VID=0,
+ *      then replace VID with input port's PVID. If switch received a packet that is not tagged, 
+ *      it will not insert a tag with PVID to this packet.
+ *      2. When Null VID replacement is disabled, switch will drop or deal the null VID tagged 
+ *      frame depends on the configuration.
+ */
+int32 rtl8306e_vlan_nullVidReplace_set(uint32 port, uint32 enabled)
+{
+    uint32 speed, duplex, nway;
+
+    if (port > RTL8306_PORT5)
+        return FAILED;
+    
+    speed = 0; 
+    duplex = 0;
+    nway = 0;
+    
+    /*save mac 4 or port status when operate reg.22*/    
+    if (4 == port) 
+    {
+        rtl8306e_regbit_get(5, 0, 13, 0, &speed);
+        rtl8306e_regbit_get(5, 0, 12, 0, &nway);
+        rtl8306e_regbit_get(5, 0, 8, 0, &duplex);            
+    } 
+    else if (5 == port) 
+    {
+        rtl8306e_regbit_get(6, 0, 13, 0, &speed);
+        rtl8306e_regbit_get(6, 0, 12, 0, &nway);
+        rtl8306e_regbit_get(6, 0, 8, 0, &duplex);            
+    }
+
+    /*Port 5 corresponding PHY6*/
+    if (RTL8306_PORT5 == port)  
+        port ++ ; 
+    
+    rtl8306e_regbit_set(port, 22, 12, 0, enabled ? 1 : 0);
+    
+    /*restore mac 4 or port status when operate reg.22*/    
+    if (4 == port) 
+    {
+        rtl8306e_regbit_set(5, 0, 13, 0, speed);
+        rtl8306e_regbit_set(5, 0, 12, 0, nway);
+        rtl8306e_regbit_set(5, 0, 8, 0, duplex);            
+    }
+    else if (6 == port) 
+    { 
+        /*for port++ when port 5*/
+        rtl8306e_regbit_set(6, 0, 13, 0, speed);
+        rtl8306e_regbit_set(6, 0, 12, 0, nway);
+        rtl8306e_regbit_set(6, 0, 8, 0, duplex);
+    }           
+    
+#ifdef RTL8306_TBLBAK
+    rtl8306_TblBak.vlanConfig_perport[port].enNulPvidRep = (uint8) enabled;
+#endif
+    return SUCCESS;
+}
+
+/* Function Name:
+ *      rtl8306e_vlan_nullVidReplace_get
+ * Description:
+ *      Configure switch to forward frames to other VLANs ignoring the egress rule.
+ * Input:
+ *      port   -  port number
+ * Output:
+ *      pEnabled  - the pointer of Null VID replacement ability(Dsiabled or Enabled) 
+ * Return:
+ *      SUCCESS
+ *      FAILED
+ * Note:
+ *      1.When Null VID replacement is enabled, 8306E only captures tagged packet with VID=0,
+ *      then replace VID with input port's PVID. If switch received a packet that is not tagged, 
+ *      it will not insert a tag with PVID to this packet.
+ *      2. When Null VID replacement is disabled, switch will drop or deal the null VID tagged 
+ *      frame depends on the configuration.
+ */
+int32 rtl8306e_vlan_nullVidReplace_get(uint32 port, uint32 *pEnabled)
+{
+    uint32 bitValue;
+    
+    if ( (port > RTL8306_PORT5) || (NULL == pEnabled ))
+        return FAILED;
+    
+    /*Port 5 corresponding PHY6*/    
+    if (RTL8306_PORT5 == port)  
+        port ++ ; 
+    
+    rtl8306e_regbit_get(port, 22, 12, 0, &bitValue);
+    *pEnabled = (bitValue ? TRUE : FALSE);
+
+    return SUCCESS;
+}
+
+/* Function Name:
+ *      rtl8306e_vlan_portPvidIndex_set
+ * Description:
+ *      Configure switch port PVID index 
+ * Input:
+ *      port           -   Specify the port(port 0 ~ port 5) to configure VLAN index
+ *      vlanIndex    -   Specify the VLAN index
+ * Output:
+ *      none
+ * Return:
+ *      SUCCESS
+ *      FAILED
+ * Note:
+ *      There are 16 vlan entry, VID of vlan entry pointed by PVID index  is the PVID 
+ */
+int32 rtl8306e_vlan_portPvidIndex_set(uint32 port, uint32 vlanIndex)
+{
+    uint32 regValue;
+
+    if(port > RTL8306_PORT5 || vlanIndex > (RTL8306_VLAN_ENTRYS -1))
+        return FAILED;
+    
+    if (port < RTL8306_PORT5) 
+    {
+        rtl8306e_reg_get(port, 24, 0, &regValue);
+        regValue = (regValue & 0xFFF) | (vlanIndex << 12);
+        rtl8306e_reg_set(port, 24, 0, regValue);
+    } else 
+    {
+        rtl8306e_reg_get(0, 26, 1, &regValue);
+        regValue = (regValue & 0xFFF) | (vlanIndex << 12);
+        rtl8306e_reg_set(0, 26, 1, regValue);
+    }
+#ifdef RTL8306_TBLBAK
+    rtl8306_TblBak.vlanPvidIdx[port]= (uint8) vlanIndex;
+#endif
+       
+    return SUCCESS;
+}
+
+
+/* Function Name:
+ *      rtl8306e_vlan_portPvidIndex_get
+ * Description:
+ *      Get switch port PVID index 
+ * Input:
+ *      port            -   Specify the port(port 0 ~ port 5) to configure VLAN index
+ * Output:
+ *      pVlanIndex   -   pointer of VLAN index number
+ * Return:
+ *      SUCCESS
+ *      FAILED
+ * Note:
+ *      There are 16 vlan entry, VID of vlan entry pointed by PVID index  is the PVID 
+ */
+ 
+int32 rtl8306e_vlan_portPvidIndex_get(uint32 port, uint32 *pVlanIndex) 
+{
+    if((port > RTL8306_PORT5) || pVlanIndex == NULL)
+        return FAILED;
+    
+    if (port < RTL8306_PORT5) 
+        rtl8306e_reg_get(port, 24, 0, pVlanIndex);
+    else 
+        rtl8306e_reg_get(0, 26, 1, pVlanIndex);
+    *pVlanIndex = (*pVlanIndex >> 12) & 0xF;
+    return SUCCESS;
+}
+
+/* Function Name:
+ *      rtl8306e_vlan_portAcceptFrameType_set
+ * Description:
+ *      Set VLAN support frame type
+ * Input:
+ *      port                                 - Port id
+ *      accept_frame_type             - accept frame type
+ * Output:
+ *      none
+ * Return:
+ *      SUCCESS
+ *      FAILED
+ * Note:
+ *    The API is used for checking 802.1Q tagged frames.
+ *    The accept frame type as following:
+ *    RTL8306E_ACCEPT_ALL
+ *    RTL8306E_ACCEPT_TAG_ONLY
+ *    RTL8306E_ACCEPT_UNTAG_ONLY
+ */
+int32 rtl8306e_vlan_portAcceptFrameType_set(uint32 port, rtl8306e_acceptFrameType_t accept_frame_type)
+{
+    uint32 regval;
+    
+    if(port > RTL8306_PORT5)
+        return FAILED;
+    
+    if(RTL8306_PORT0 == port)
+    {
+        rtl8306e_reg_get(0, 31, 0, &regval);
+        regval &= ~(0x3 << 7);
+        regval |= (accept_frame_type << 7);
+        rtl8306e_reg_set(0, 31, 0, regval);
+    }
+    else if (RTL8306_PORT5 == port)
+    {
+        rtl8306e_reg_get(6, 30, 1, &regval);
+        regval &= ~(0x3 << 6);
+        regval |= (accept_frame_type << 6);
+        rtl8306e_reg_set(6, 30, 1, regval);        
+    }
+    else
+    {
+        rtl8306e_reg_get(port, 21, 2, &regval);
+        regval &= ~(0x3 << 11);
+        regval |= (accept_frame_type << 11);
+        rtl8306e_reg_set(port, 21, 2, regval);        
+    }
+#ifdef RTL8306_TBLBAK
+    rtl8306_TblBak.vlanConfig.enVlanTagOnly = (accept_frame_type == RTL8306E_ACCEPT_TAG_ONLY ? TRUE : FALSE);
+#endif
+    return SUCCESS;
+}
+
+
+
+/* Function Name:
+ *      rtl8306e_vlan_portAcceptFrameType_get
+ * Description:
+ *      Get VLAN support frame type
+ * Input:
+ *      port                                 - Port id
+ * Output:
+ *      pAccept_frame_type             - accept frame type pointer
+ * Return:
+ *      SUCCESS
+ *      FAILED
+ * Note:
+ *    The API is used for checking 802.1Q tagged frames.
+ *    The accept frame type as following:
+ *    RTL8306E_ACCEPT_ALL
+ *    RTL8306E_ACCEPT_TAG_ONLY
+ *    RTL8306E_ACCEPT_UNTAG_ONLY
+ */
+int32 rtl8306e_vlan_portAcceptFrameType_get(uint32 port, rtl8306e_acceptFrameType_t *pAccept_frame_type)
+{
+    uint32 regval;
+    
+    if((port > RTL8306_PORT5) || (pAccept_frame_type == NULL))
+        return FAILED;
+
+    if(RTL8306_PORT0 == port)
+    {
+        rtl8306e_reg_get(0, 31, 0, &regval);
+        regval &= (0x3 << 7);
+        *pAccept_frame_type = (rtl8306e_acceptFrameType_t)(regval >> 7);
+    }
+    else if (RTL8306_PORT5 == port)
+    {
+        rtl8306e_reg_get(6, 30, 1, &regval);
+        regval &= (0x3 << 6);
+        *pAccept_frame_type = (rtl8306e_acceptFrameType_t)(regval >> 6);
+    }
+    else
+    {
+        rtl8306e_reg_get(port, 21, 2, &regval);
+        regval &= (0x3 << 11);
+        *pAccept_frame_type = (rtl8306e_acceptFrameType_t)(regval >> 11);        
+    }
+
+    return SUCCESS;
+}
+
+/* Function Name:
+ *      rtl8306e_vlan_tagInsert_set
+ * Description:
+ *      Insert VLAN tag by ingress port
+ * Input:
+ *      egPort               - egress port number 0~5
+ *      igPortMsk           - ingress port mask
+ * Output:
+ *      none
+ * Return:
+ *      SUCCESS
+ *      FAILED
+ * Note:
+ *      egPort is packet egress port, if the packet is untagged and its igress port
+ *      is in the igPortMsk, it will be inserted with an VLAN tag.
+ */
+int32 rtl8306e_vlan_tagInsert_set(uint32 egPort, uint32 igPortMsk)
+{
+    uint32 regval;
+    
+    if((egPort > RTL8306_PORT5) || (igPortMsk > 0x3F))
+        return FAILED;
+    
+    /*enable EN_INSERT_TAG*/
+    rtl8306e_regbit_set(0, 28, 0, 3, 1);
+
+    if(RTL8306_PORT0 == egPort)
+    {
+        rtl8306e_reg_get(0, 28, 3, &regval);
+        regval &= ~(0x3F << 1);
+        regval |= (igPortMsk << 1);
+        rtl8306e_reg_set(0, 28, 3, regval);        
+    }
+    else if(RTL8306_PORT5 == egPort)
+    {
+        rtl8306e_reg_get(6, 30, 1, &regval);
+        regval &= ~0x3F;
+        regval |= igPortMsk;
+        rtl8306e_reg_set(6, 30, 1, regval);
+    }
+    else
+    {
+        rtl8306e_reg_get(egPort, 30, 1, &regval);
+        regval &= ~(0x3F << 9);
+        regval |= (igPortMsk << 9);
+        rtl8306e_reg_set(egPort, 30, 1, regval);
+    }
+                
+    return SUCCESS;
+}
+
+
+/* Function Name:
+ *      rtl8306e_vlan_tagInsert_get
+ * Description:
+ *      get  ingress port mask of VLAN tag insertion for untagged packet
+ * Input:
+ *      egPort               - egress port number 0~5
+ *      igPortMsk           - ingress port mask
+ * Output:
+ *      none
+ * Return:
+ *      SUCCESS
+ *      FAILED
+ * Note:
+ *      egPort is packet egress port, if the packet is untagged and its igress port
+ *      is in the igPortMsk, it will be inserted with an VLAN tag.
+ */
+int32 rtl8306e_vlan_tagInsert_get(uint32 egPort, uint32 * pIgPortMsk)
+{
+    uint32 regval ;
+    
+    if ((egPort > RTL8306_PORT5) || (NULL == pIgPortMsk))
+        return FAILED;
+
+    /*EN_INSERT_TAG = 0, insert tag operation is disable*/
+    rtl8306e_regbit_get(0, 28, 0, 3, &regval);
+    if(!regval)
+        *pIgPortMsk = 0;
+    
+    if(RTL8306_PORT0 == egPort)
+    {
+        rtl8306e_reg_get(0, 28, 3, &regval);
+        regval &= (0x3F << 1);
+        *pIgPortMsk = regval >> 1;
+    }
+    else if(RTL8306_PORT5 == egPort)
+    {
+        rtl8306e_reg_get(6, 30, 1, &regval);
+        regval &= 0x3F;
+        *pIgPortMsk = regval;
+    }
+    else 
+    {
+        rtl8306e_reg_get(egPort, 30, 1, &regval);
+        regval &= (0x3F << 9);
+        *pIgPortMsk = regval >> 9;
+    }
+    
+    return SUCCESS;
+}
+
+/*added by Fan Kaixi, 2012-01-18*/
+
+/* Function Name:
+ *      rtl8306e_vlan_tagInsertRemove_set
+ * Description:
+ *      set per port vlan tag action
+ * Input:
+ *      Port               - egress port number 0~5
+ *      option              - action options, insert/remove/replace/untouch
+ * Output:
+ *      none
+ * Return:
+ *      SUCCESS
+ *      FAILED
+ * Note:
+ *      port is egress port number from 0 to 5. option is the action the egress
+ *      port will take on packets tx from itself.
+ *      option have values as follows:
+ *          RTL8306_VLAN_IRTAG = 0  ---  insert tag for untagged packets, remove tag from tagged packets and add new tag to it
+ *          RTL8306_VLAN_RTAG,      ---  remove tag from tagged packets, don't touch untagged packets                 
+ *          RTL8306_VLAN_ITAG,      ---  insert tag for untagged packets, don't touch tagged packets       
+ *          RTL8306_VLAN_UNDOTAG    ---  don't touch tag for packets 
+ *      when egress port decide to insert tag for untagged packets, the tag vid is derived from packets'
+ *      ingress port pvid.
+*/
+int32 rtl8306e_vlan_tagInsertRemove_set(uint32 port, uint32 option)
+{
+	uint32 regValue;
+	 uint32 speed, duplex, nway;
+     
+	if ( (port > RTL8306_PORT5) || (option > 0x3) ) 
+		return FAILED;
+
+       /*save mac 4 or port status when operate reg.22*/
+       if (port == 4) {
+            rtl8306e_regbit_get(5, 0, 13, 0, &speed);
+            rtl8306e_regbit_get(5, 0, 12, 0, &nway);
+            rtl8306e_regbit_get(5, 0, 8, 0, &duplex);            
+       } else if (port == 5) {
+            rtl8306e_regbit_get(6, 0, 13, 0, &speed);
+            rtl8306e_regbit_get(6, 0, 12, 0, &nway);
+            rtl8306e_regbit_get(6, 0, 8, 0, &duplex);            
+       }
+    
+	/*Port 5 corresponding PHY6*/	
+	if (port == RTL8306_PORT5 )  
+		port ++ ;  
+    rtl8306e_reg_get(port, 22, 0, &regValue);
+    regValue &= ~0x3;
+    regValue |= option;
+    rtl8306e_reg_set(port, 22, 0, regValue);
+
+       /*restore mac 4 or port status when operate reg.22*/
+      if (port == 4) {
+            rtl8306e_regbit_set(5, 0, 13, 0, speed);
+            rtl8306e_regbit_set(5, 0, 12, 0, nway);
+            rtl8306e_regbit_set(5, 0, 8, 0, duplex);        
+      } else if (port == 6)  {  /*for port++ when port 5*/
+           rtl8306e_regbit_set(6, 0, 13, 0, speed);
+           rtl8306e_regbit_set(6, 0, 12, 0, nway);
+           rtl8306e_regbit_set(6, 0, 8, 0, duplex);
+      }      
+
+	return SUCCESS;    
+}
+
+/* Function Name:
+ *      rtl8306e_vlan_tagInsertRemove_get
+ * Description:
+ *      get per port vlan tag action
+ * Input:
+ *      Port               - egress port number 0~5
+ * Output:
+ *      pOption              - action options, insert/remove/replace/untouch
+ * Return:
+ *      SUCCESS
+ *      FAILED
+ * Note:
+ *      port is egress port number from 0 to 5. option is the action the egress
+ *      port will take on packets tx from itself.
+ *      option have values as follows:
+ *          RTL8306_VLAN_IRTAG = 0  ---  insert tag for untagged packets, remove tag from tagged packets and add new tag to it
+ *          RTL8306_VLAN_RTAG,      ---  remove tag from tagged packets, don't touch untagged packets                 
+ *          RTL8306_VLAN_ITAG,      ---  insert tag for untagged packets, don't touch tagged packets       
+ *          RTL8306_VLAN_UNDOTAG    ---  don't touch tag for packets 
+ *      when egress port decide to insert tag for untagged packets, the tag vid is derived from packets'
+ *      ingress port pvid.
+*/
+int32 rtl8306e_vlan_tagInsertRemove_get(uint32 port, uint32 *pOption)
+{
+ 	uint32 regValue;
+	
+	if (port > RTL8306_PORT5 || (pOption == NULL))
+		return FAILED;
+	/*Port 5 corresponding PHY6*/	
+	if (port == RTL8306_PORT5 )  
+		port ++ ;  
+	rtl8306e_reg_get(port, 22, 0, &regValue);	
+	*pOption = regValue & 0x3;
+
+	return SUCCESS;   
+}
+
+/* Function Name:
+ *      rtk_vlan_set
+ * Description:
+ *      Set a VLAN entry
+ * Input:
+ *      vlanIndex  - VLAN entry index
+ *      vid           - VLAN ID to configure
+ *      mbrmsk     - VLAN member set portmask
+ *      untagmsk  - VLAN untag set portmask
+ * Output:
+ *      none
+ * Return:
+ *      SUCCESS
+ *      FAILED
+ * Note:
+ *     There are 16 VLAN entry supported. User could configure the member set and untag set
+ *     for specified vid through this API. The portmask's bit N means port N.
+ *     For example, mbrmask 23=0x17=010111 means port 0,1,2,4 in the member set.
+ */
+int32 rtl8306e_vlan_entry_set(uint32 vlanIndex, uint32 vid, uint32 mbrmsk, uint32 untagmsk )
+{
+    uint32 regValue;
+
+    if ((vid > RTL8306_VIDMAX) || (mbrmsk > 0x3F) || (untagmsk > 0x3F))
+        return FAILED;
+    
+    /*enable EN_UNTAG_SET*/
+    rtl8306e_regbit_set(0, 29, 12, 0, 1);
+    
+    /*set vlan entry*/
+    switch(vlanIndex) 
+    {
+        case 0: /* VLAN[A] */
+            rtl8306e_reg_get(0, 25, 0, &regValue);
+            regValue = (regValue & 0xF000) | vid ;
+            rtl8306e_reg_set(0, 25, 0, regValue);
+            rtl8306e_reg_get(0, 24, 0, &regValue);
+            regValue = (regValue & 0xFFC0) | mbrmsk;
+            rtl8306e_reg_set(0, 24, 0, regValue);
+            rtl8306e_reg_get(0, 29, 0, &regValue);
+            regValue &= ~0x3F;
+            regValue |= untagmsk;
+            rtl8306e_reg_set(0, 29, 0, regValue);            
+            break;
+
+        case 1: /* VLAN[B] */
+            rtl8306e_reg_get(1, 25, 0, &regValue);
+            regValue = (regValue & 0xF000) | vid ;
+            rtl8306e_reg_set(1, 25, 0, regValue);
+            rtl8306e_reg_get(1, 24, 0, &regValue);
+            regValue = (regValue & 0xFFC0) | mbrmsk;
+            rtl8306e_reg_set(1, 24, 0, regValue);
+            rtl8306e_reg_get(1, 30, 1, &regValue);
+            regValue &= ~0x3F;
+            regValue |= untagmsk;
+            rtl8306e_reg_set(1, 30, 1, regValue);            
+            break;
+
+        case 2: /* VLAN[C] */
+            rtl8306e_reg_get(2, 25, 0, &regValue);
+            regValue = (regValue & 0xF000) | vid ;
+            rtl8306e_reg_set(2, 25, 0, regValue);
+            rtl8306e_reg_get(2, 24, 0, &regValue);
+            regValue = (regValue & 0xFFC0) | mbrmsk;
+            rtl8306e_reg_set(2, 24, 0, regValue);
+            rtl8306e_reg_get(2, 30, 1, &regValue);
+            regValue &= ~0x3F;
+            regValue |= untagmsk;
+            rtl8306e_reg_set(2, 30, 1, regValue);                
+            break;
+
+        case 3: /* VLAN[D] */
+            rtl8306e_reg_get(3, 25, 0, &regValue);
+            regValue = (regValue & 0xF000) | vid;
+            rtl8306e_reg_set(3, 25, 0, regValue);
+            rtl8306e_reg_get(3, 24, 0, &regValue);
+            regValue = (regValue & 0xFFC0) | mbrmsk;
+            rtl8306e_reg_set(3, 24, 0, regValue);
+            rtl8306e_reg_get(3, 30, 1, &regValue);
+            regValue &= ~0x3F;
+            regValue |= untagmsk;
+            rtl8306e_reg_set(3, 30, 1, regValue);                
+            break;
+
+        case 4: /* VLAN[E] */
+            rtl8306e_reg_get(4, 25, 0, &regValue);
+            regValue = (regValue & 0xF000) | vid;
+            rtl8306e_reg_set(4, 25, 0, regValue);
+            rtl8306e_reg_get(4, 24, 0, &regValue);
+            regValue = (regValue & 0xFFC0) | mbrmsk;
+            rtl8306e_reg_set(4, 24, 0, regValue);
+            rtl8306e_reg_get(4, 30, 1, &regValue);
+            regValue &= ~0x3F;
+            regValue |= untagmsk;
+            rtl8306e_reg_set(4, 30, 1, regValue);                            
+            break;
+
+        case 5: /* VLAN[F] */
+            rtl8306e_reg_get(0, 27, 1, &regValue);
+            regValue = (regValue & 0xF000) | vid;
+            rtl8306e_reg_set(0, 27, 1, regValue);
+            rtl8306e_reg_get(0, 26, 1, &regValue);
+            regValue = (regValue & 0xFFC0) | mbrmsk;
+            rtl8306e_reg_set(0, 26, 1, regValue);
+            rtl8306e_reg_get(0, 26, 1, &regValue);
+            regValue &= ~(0x3F << 6);
+            regValue |= (untagmsk << 6);
+            rtl8306e_reg_set(0, 26, 1, regValue);            
+            break;
+        
+        case 6: /* VLAN[G] */
+            rtl8306e_reg_get(1, 27, 1, &regValue);
+            regValue = (regValue & 0xF000) | vid;
+            rtl8306e_reg_set(1, 27, 1, regValue);
+            rtl8306e_reg_get(1, 26, 1, &regValue);
+            regValue = (regValue & 0xFFC0) | mbrmsk;
+            rtl8306e_reg_set(1, 26, 1, regValue);
+            rtl8306e_reg_get(1, 26, 1, &regValue);
+            regValue &= ~(0x3F << 6);
+            regValue |= (untagmsk << 6);
+            rtl8306e_reg_set(1, 26, 1, regValue);                        
+            break;
+
+        case 7: /* VLAN[H] */
+            rtl8306e_reg_get(2, 27, 1, &regValue);
+            regValue = (regValue & 0xF000) | vid;
+            rtl8306e_reg_set(2, 27, 1, regValue);
+            rtl8306e_reg_get(2, 26, 1, &regValue);
+            regValue = (regValue & 0xFFC0) | mbrmsk;
+            rtl8306e_reg_set(2, 26, 1, regValue);
+            rtl8306e_reg_get(2, 26, 1, &regValue);
+            regValue &= ~(0x3F << 6);
+            regValue |= (untagmsk << 6);
+            rtl8306e_reg_set(2, 26, 1, regValue);                                    
+            break;
+
+        case 8: /* VLAN[I] */
+            rtl8306e_reg_get(3, 27, 1, &regValue);
+            regValue = (regValue & 0xF000) | vid;
+            rtl8306e_reg_set(3, 27, 1, regValue);
+            rtl8306e_reg_get(3, 26, 1, &regValue);
+            regValue = (regValue & 0xFFC0) | mbrmsk;
+            rtl8306e_reg_set(3, 26, 1, regValue);
+            rtl8306e_reg_get(3, 26, 1, &regValue);
+            regValue &= ~(0x3F << 6);
+            regValue |= (untagmsk << 6);
+            rtl8306e_reg_set(3, 26, 1, regValue);                        
+            
+            break;
+
+        case 9: /* VLAN[J] */
+            rtl8306e_reg_get(4, 27, 1, &regValue);
+            regValue = (regValue & 0xF000) | vid;
+            rtl8306e_reg_set(4, 27, 1, regValue);
+            rtl8306e_reg_get(4, 26, 1, &regValue);
+            regValue = (regValue & 0xFFC0) | mbrmsk;
+            rtl8306e_reg_set(4, 26, 1, regValue);
+            rtl8306e_reg_get(4, 26, 1, &regValue);
+            regValue &= ~(0x3F << 6);
+            regValue |= (untagmsk << 6);
+            rtl8306e_reg_set(4, 26, 1, regValue);                                    
+            break;
+
+        case 10: /* VLAN[K] */
+            rtl8306e_reg_get(0, 29, 1, &regValue);
+            regValue = (regValue & 0xF000) | vid;
+            rtl8306e_reg_set(0, 29, 1, regValue);
+            rtl8306e_reg_get(0, 28, 1, &regValue);
+            regValue = (regValue & 0xFFC0) | mbrmsk;
+            rtl8306e_reg_set(0, 28, 1, regValue);
+            rtl8306e_reg_get(0, 28, 1, &regValue);
+            regValue &= ~(0x3F << 6);
+            regValue |= (untagmsk << 6);
+            rtl8306e_reg_set(0, 28, 1, regValue);                                    
+            break;
+
+        case 11: /* VLAN[L] */
+            rtl8306e_reg_get(1, 29, 1, &regValue);
+            regValue = (regValue & 0xF000) | vid;
+            rtl8306e_reg_set(1, 29, 1, regValue);
+            rtl8306e_reg_get(1, 28, 1, &regValue);
+            regValue = (regValue & 0xFFC0) | mbrmsk;
+            rtl8306e_reg_set(1, 28, 1, regValue);
+            rtl8306e_reg_get(1, 28, 1, &regValue);
+            regValue &= ~(0x3F << 6);
+            regValue |= (untagmsk << 6);
+            rtl8306e_reg_set(1, 28, 1, regValue);                                                
+            break;
+
+        case 12: /* VLAN[M] */
+            rtl8306e_reg_get(2, 29, 1, &regValue);
+            regValue = (regValue & 0xF000) | vid;
+            rtl8306e_reg_set(2, 29, 1, regValue);
+            rtl8306e_reg_get(2, 28, 1, &regValue);
+            regValue = (regValue & 0xFFC0) | mbrmsk;
+            rtl8306e_reg_set(2, 28, 1, regValue);
+            rtl8306e_reg_get(2, 28, 1, &regValue);
+            regValue &= ~(0x3F << 6);
+            regValue |= (untagmsk << 6);
+            rtl8306e_reg_set(2, 28, 1, regValue);                                                
+            break;
+
+        case 13: /* VLAN[N] */
+            rtl8306e_reg_get(3, 29, 1, &regValue);
+            regValue = (regValue & 0xF000) | vid;
+            rtl8306e_reg_set(3, 29, 1, regValue);
+            rtl8306e_reg_get(3, 28, 1, &regValue);
+            regValue = (regValue & 0xFFC0) |mbrmsk;
+            rtl8306e_reg_set(3, 28, 1, regValue);
+            rtl8306e_reg_get(3, 28, 1, &regValue);
+            regValue &= ~(0x3F << 6);
+            regValue |= (untagmsk << 6);
+            rtl8306e_reg_set(3, 28, 1, regValue);                                                
+            break;
+
+        case 14: /* VLAN[O] */
+            rtl8306e_reg_get(4, 29, 1, &regValue);
+            regValue = (regValue & 0xF000) | vid;
+            rtl8306e_reg_set(4, 29, 1, regValue);
+            rtl8306e_reg_get(4, 28, 1, &regValue);
+            regValue = (regValue & 0xFFC0) | mbrmsk;
+            rtl8306e_reg_set(4, 28, 1, regValue);
+            rtl8306e_reg_get(4, 28, 1, &regValue);
+            regValue &= ~(0x3F << 6);
+            regValue |= (untagmsk << 6);
+            rtl8306e_reg_set(4, 28, 1, regValue);                                                
+            break;
+
+        case 15: /* VLAN[P] */
+            rtl8306e_reg_get(0, 31, 1, &regValue);
+            regValue = (regValue & 0xF000) | vid;
+            rtl8306e_reg_set(0, 31, 1, regValue);
+            rtl8306e_reg_get(0, 30, 1, &regValue);
+            regValue = (regValue & 0xFFC0) | mbrmsk;
+            rtl8306e_reg_set(0, 30, 1, regValue);
+            rtl8306e_reg_get(0, 30, 1, &regValue);
+            regValue &= ~(0x3F << 6);
+            regValue |= (untagmsk << 6);
+            rtl8306e_reg_set(0, 30, 1, regValue);                                                
+            break;
+        default:
+            return FAILED;
+
+    }    
+
+#ifdef RTL8306_TBLBAK
+    rtl8306_TblBak.vlanTable[vlanIndex].vid = (uint16)vid;
+    rtl8306_TblBak.vlanTable[vlanIndex].memberPortMask = (uint8)mbrmsk;
+#endif
+    return SUCCESS;
+}
+
+/* Function Name:
+ *      rtl8306e_vlan_entry_get
+ * Description:
+ *      Get a VLAN entry
+ * Input:
+ *      vlanIndex  - VLAN entry index
+ * Output:
+ *      pVid           -  the pointer of VLAN ID 
+ *      pMbrmsk     -  the pointer of VLAN member set portmask
+ *      pUntagmsk  -  the pointer of VLAN untag set portmask
+ * Return:
+ *      SUCCESS
+ *      FAILED
+ * Note:
+ *     There are 16 VLAN entry supported. User could configure the member set and untag set
+ *     for specified vid through this API. The portmask's bit N means port N.
+ *     For example, mbrmask 23=0x17=010111 means port 0,1,2,4 in the member set.
+ */
+int32 rtl8306e_vlan_entry_get(uint32 vlanIndex, uint32 *pVid, uint32 *pMbrmsk, uint32 *pUntagmsk)
+{
+
+    if(  (NULL == pVid) ||  (NULL == pMbrmsk))
+        return FAILED;
+    
+    switch(vlanIndex)
+    {
+        case 0: /*VLAN[A]*/
+            rtl8306e_reg_get(0, 25, 0, pVid);
+            rtl8306e_reg_get(0, 24, 0, pMbrmsk);
+            rtl8306e_reg_get(0, 29, 0, pUntagmsk);            
+            break;        
+            
+        case 1: /*VLAN[B]*/
+            rtl8306e_reg_get(1, 25, 0, pVid);
+            rtl8306e_reg_get(1, 24, 0, pMbrmsk);
+            rtl8306e_reg_get(1, 30, 1, pUntagmsk);                        
+            break;
+            
+        case 2: /*VLAN[C]*/
+            rtl8306e_reg_get(2, 25, 0, pVid);
+            rtl8306e_reg_get(2, 24, 0, pMbrmsk);
+            rtl8306e_reg_get(2, 30, 1, pUntagmsk);                                    
+            break;
+            
+        case 3: /*VLAN[D]*/
+            rtl8306e_reg_get(3, 25, 0, pVid);
+            rtl8306e_reg_get(3, 24, 0, pMbrmsk);
+            rtl8306e_reg_get(3, 30, 1, pUntagmsk);                                    
+            break;
+            
+        case 4: /*VLAN[E]*/
+            rtl8306e_reg_get(4, 25, 0, pVid);
+            rtl8306e_reg_get(4, 24, 0, pMbrmsk);
+            rtl8306e_reg_get(4, 30, 1, pUntagmsk);                                    
+            break;
+            
+        case 5: /*VLAN[F]*/
+            rtl8306e_reg_get(0, 27, 1, pVid);
+            rtl8306e_reg_get(0, 26, 1, pMbrmsk);
+            rtl8306e_reg_get(0, 26, 1, pUntagmsk);   
+            *pUntagmsk >>= 6;
+            break;
+            
+        case 6: /*VLAN[G]*/
+            rtl8306e_reg_get(1, 27, 1, pVid);
+            rtl8306e_reg_get(1, 26, 1, pMbrmsk);
+            rtl8306e_reg_get(1, 26, 1, pUntagmsk);   
+            *pUntagmsk >>= 6;
+            break;
+            
+        case 7: /*VLAN[H]*/
+            rtl8306e_reg_get(2, 27, 1, pVid);
+            rtl8306e_reg_get(2, 26, 1, pMbrmsk);
+            rtl8306e_reg_get(2, 26, 1, pUntagmsk);   
+            *pUntagmsk >>= 6;
+            break;
+            
+        case 8: /*VLAN[I]*/        
+            rtl8306e_reg_get(3, 27, 1, pVid);
+            rtl8306e_reg_get(3, 26, 1, pMbrmsk);
+            rtl8306e_reg_get(3, 26, 1, pUntagmsk);   
+            *pUntagmsk >>= 6;
+            break;
+            
+        case 9: /*VLAN[J]*/
+            rtl8306e_reg_get(4, 27, 1, pVid);
+            rtl8306e_reg_get(4, 26, 1, pMbrmsk);
+            rtl8306e_reg_get(4, 26, 1, pUntagmsk);   
+            *pUntagmsk >>= 6;
+            break;
+            
+        case 10: /*VLAN[K]*/
+            rtl8306e_reg_get(0, 29, 1, pVid);
+            rtl8306e_reg_get(0, 28, 1, pMbrmsk);
+            rtl8306e_reg_get(0, 28, 1, pUntagmsk);   
+            *pUntagmsk >>= 6;
+            break;
+            
+        case 11: /*VLAN[L]*/
+            rtl8306e_reg_get(1, 29, 1, pVid);
+            rtl8306e_reg_get(1, 28, 1, pMbrmsk);
+            rtl8306e_reg_get(1, 28, 1, pUntagmsk);   
+            *pUntagmsk >>= 6;
+            break;
+            
+        case 12: /*VLAN[M]*/
+            rtl8306e_reg_get(2, 29, 1, pVid);
+            rtl8306e_reg_get(2, 28, 1, pMbrmsk);
+            rtl8306e_reg_get(2, 28, 1, pUntagmsk);   
+            *pUntagmsk >>= 6;
+            break;
+            
+        case 13: /*VLAN[N]*/
+            rtl8306e_reg_get(3, 29, 1, pVid);
+            rtl8306e_reg_get(3, 28, 1, pMbrmsk);
+            rtl8306e_reg_get(3, 28, 1, pUntagmsk);   
+            *pUntagmsk >>= 6;
+            break;
+            
+        case 14: /*VLAN[O]*/
+            rtl8306e_reg_get(4, 29, 1, pVid);
+            rtl8306e_reg_get(4, 28, 1, pMbrmsk);
+            rtl8306e_reg_get(4, 28, 1, pUntagmsk);   
+            *pUntagmsk >>= 6;
+            break;
+            
+        case 15: /*VLAN[P]*/
+            rtl8306e_reg_get(0, 31, 1, pVid);
+            rtl8306e_reg_get(0, 30, 1, pMbrmsk);
+            rtl8306e_reg_get(0, 30, 1, pUntagmsk);   
+            *pUntagmsk >>= 6;
+            break;
+            
+        default:
+            return  FAILED;
+    }
+    
+    *pVid  &= 0xFFF;
+    *pMbrmsk  &= 0x3F;
+    *pUntagmsk &= 0x3F;
+    
+    return  SUCCESS;
+}
+
+
+/* Function Name:
+ *      rtl8306e_vlan_vlanBasedPriority_set
+ * Description:
+ *       Set VID based priority
+ * Input:
+ *      vlanIndex   -   Specify VLAN entry index
+ *      pri            -   the specified VLAN priority  
+ * Output:
+ *      none
+ * Return:
+ *      SUCCESS
+ *      FAILED
+ * Note:
+ *      each VLAN could be assigned an priority. if vlanIndex > 15, it means the VID
+ *      is not in VLAN entries, unmatched VID could also be assigned an priority.
+ *       
+ */
+int32 rtl8306e_vlan_vlanBasedPriority_set(uint32 vlanIndex, uint32 pri)
+{
+    uint32 regval;
+    
+    if (pri > 3)
+        return FAILED;
+
+    switch(vlanIndex)
+    {
+        case 0: /*VLAN[A]*/
+            rtl8306e_regbit_set(0, 29, 8, 0, 1);
+            rtl8306e_reg_get(0, 29, 0, &regval);
+            regval &= ~(0x3 << 6);
+            regval |= (pri << 6);
+            rtl8306e_reg_set(0, 29, 0, regval);            
+            break;        
+            
+        case 1: /*VLAN[B]*/
+            rtl8306e_regbit_set(1, 30, 8, 1, 1);
+            rtl8306e_reg_get(1, 30, 1, &regval);
+            regval &= ~(0x3 << 6);
+            regval |= (pri << 6);
+            rtl8306e_reg_set(1, 30, 1, regval);                                   
+            break;
+            
+        case 2: /*VLAN[C]*/
+            rtl8306e_regbit_set(2, 30, 8, 1, 1);
+            rtl8306e_reg_get(2, 30, 1, &regval);
+            regval &= ~(0x3 << 6);
+            regval |= (pri << 6);
+            rtl8306e_reg_set(2, 30, 1, regval);                                   
+            break;
+            
+        case 3: /*VLAN[D]*/
+            rtl8306e_regbit_set(3, 30, 8, 1, 1);
+            rtl8306e_reg_get(3, 30, 1, &regval);
+            regval &= ~(0x3 << 6);
+            regval |= (pri << 6);
+            rtl8306e_reg_set(3, 30, 1, regval);                                               
+            break;
+            
+        case 4: /*VLAN[E]*/
+            rtl8306e_regbit_set(4, 30, 8, 1, 1);
+            rtl8306e_reg_get(4, 30, 1, &regval);
+            regval &= ~(0x3 << 6);
+            regval |= (pri << 6);
+            rtl8306e_reg_set(4, 30, 1, regval);                                               
+            break;
+            
+        case 5: /*VLAN[F]*/
+            rtl8306e_regbit_set(0, 27, 14, 1, 0);
+            rtl8306e_reg_get(0, 27, 1, &regval);
+            regval &= ~(0x3 << 12);
+            regval |= (pri << 12);
+            rtl8306e_reg_set(0, 27, 1, regval);                                               
+            break;
+            
+        case 6: /*VLAN[G]*/
+            rtl8306e_regbit_set(1, 26, 14, 1, 0);
+            rtl8306e_reg_get(1, 26, 1, &regval);
+            regval &= ~(0x3 << 12);
+            regval |= (pri << 12);
+            rtl8306e_reg_set(1, 26, 1, regval);                                                           
+            break;
+            
+        case 7: /*VLAN[H]*/
+            rtl8306e_regbit_set(2, 26, 14, 1, 0);
+            rtl8306e_reg_get(2, 26, 1, &regval);
+            regval &= ~(0x3 << 12);
+            regval |= (pri << 12);
+            rtl8306e_reg_set(2, 26, 1, regval);                                                                       
+            break;
+            
+        case 8: /*VLAN[I]*/        
+            rtl8306e_regbit_set(3, 26, 14, 1, 1);
+            rtl8306e_reg_get(3, 26, 1, &regval);
+            regval &= ~(0x3 << 12);
+            regval |= (pri << 12);
+            rtl8306e_reg_set(3, 26, 1, regval);                                                                                   
+            break;
+            
+        case 9: /*VLAN[J]*/
+            rtl8306e_regbit_set(4, 26, 14, 1, 1);
+            rtl8306e_reg_get(4, 26, 1, &regval);
+            regval &= ~(0x3 << 12);
+            regval |= (pri << 12);
+            rtl8306e_reg_set(4, 26, 1, regval);                                                                                               
+            break;
+            
+        case 10: /*VLAN[K]*/
+            rtl8306e_regbit_set(0, 28, 14, 1, 1);
+            rtl8306e_reg_get(0, 28, 1, &regval);
+            regval &= ~(0x3 << 12);
+            regval |= (pri << 12);
+            rtl8306e_reg_set(0, 28, 1, regval);                                                                                                           
+            break;
+            
+        case 11: /*VLAN[L]*/
+            rtl8306e_regbit_set(1, 28, 14, 1, 1);
+            rtl8306e_reg_get(1, 28, 1, &regval);
+            regval &= ~(0x3 << 12);
+            regval |= (pri << 12);
+            rtl8306e_reg_set(1, 28, 1, regval);                                                                                                                       
+            break;
+            
+        case 12: /*VLAN[M]*/
+            rtl8306e_regbit_set(2, 28, 14, 1, 0);
+            rtl8306e_reg_get(2, 28, 1, &regval);
+            regval &= ~(0x3 << 12);
+            regval |= (pri << 12);
+            rtl8306e_reg_set(2, 28, 1, regval);                                                                                                                                   
+            break;
+            
+        case 13: /*VLAN[N]*/
+            rtl8306e_regbit_set(3, 28, 14, 1, 0);
+            rtl8306e_reg_get(3, 28, 1, &regval);
+            regval &= ~(0x3 << 12);
+            regval |= (pri << 12);
+            rtl8306e_reg_set(3, 28, 1, regval);                                                                                                                                               
+            break;
+            
+        case 14: /*VLAN[O]*/
+            rtl8306e_regbit_set(4, 28, 14, 1, 0);
+            rtl8306e_reg_get(4, 28, 1, &regval);
+            regval &= ~(0x3 << 12);
+            regval |= (pri << 12);
+            rtl8306e_reg_set(4, 28, 1, regval);                                                                                                                                                           
+            break;
+            
+        case 15: /*VLAN[P]*/
+            rtl8306e_regbit_set(0, 30, 14, 1, 0);
+            rtl8306e_reg_get(0, 30, 1, &regval);
+            regval &= ~(0x3 << 12);
+            regval |= (pri << 12);
+            rtl8306e_reg_set(0, 30, 1, regval);                                                                                                                                                                       
+            break;
+            
+        default: /*unmatched vlan entry*/
+            rtl8306e_regbit_set(0, 29, 11, 0, 1);
+            rtl8306e_reg_get(0, 29, 0, &regval);
+            regval &= ~(0x3 << 9);
+            regval |= (pri << 9);
+            rtl8306e_reg_set(0, 29, 0, regval);                                                                                                                                                                                                          
+            return  FAILED;
+    }
+    return SUCCESS;
+}
+
+
+/* Function Name:
+ *      rtl8306e_vlan_vlanBasedPriority_get
+ * Description:
+ *       Get VID based priority
+ * Input:
+ *      vlanIndex   -   Specify VLAN entry index
+ * Output:
+ *      pPri           -   the pointer of specified VLAN priority  
+ * Return:
+ *      SUCCESS
+ *      FAILED
+ * Note:
+ *      each VLAN could be assigned an priority. if vlanIndex > 15, it means the VID
+ *      is not in VLAN entries, unmatched VID could also be assigned an priority.
+ *       
+ */
+int32 rtl8306e_vlan_vlanBasedPriority_get(uint32 vlanIndex, uint32 *pPri)
+{
+    uint32 regval;
+    
+    if (NULL == pPri)
+        return FAILED;
+
+    switch(vlanIndex)
+    {
+        case 0: /*VLAN[A]*/
+            rtl8306e_reg_get(0, 29, 0, &regval);
+            regval &= (0x3 << 6);
+            *pPri = regval >> 6;
+            break;        
+            
+        case 1: /*VLAN[B]*/
+            rtl8306e_reg_get(1, 30, 1, &regval);
+            regval &= (0x3 << 6);
+            *pPri = regval >> 6;
+            break;
+            
+        case 2: /*VLAN[C]*/
+            rtl8306e_reg_get(2, 30, 1, &regval);
+            regval &= (0x3 << 6);
+            *pPri = regval >> 6;
+            break;
+            
+        case 3: /*VLAN[D]*/
+            rtl8306e_reg_get(3, 30, 1, &regval);
+            regval &= (0x3 << 6);
+            *pPri = regval >> 6;
+            break;
+            
+        case 4: /*VLAN[E]*/
+            rtl8306e_reg_get(4, 30, 1, &regval);
+            regval &= (0x3 << 6);
+            *pPri = regval >> 6;
+            break;
+            
+        case 5: /*VLAN[F]*/
+            rtl8306e_reg_get(0, 27, 1, &regval);
+            regval &= (0x3 << 12);
+            *pPri = regval >> 12;
+            break;
+            
+        case 6: /*VLAN[G]*/
+            rtl8306e_reg_get(1, 26, 1, &regval);
+            regval &= (0x3 << 12);
+            *pPri = regval >> 12;
+            break;
+            
+        case 7: /*VLAN[H]*/
+            rtl8306e_reg_get(2, 26, 1, &regval);
+            regval &= (0x3 << 12);
+            *pPri = regval >> 12;
+            break;
+            
+        case 8: /*VLAN[I]*/        
+            rtl8306e_reg_get(3, 26, 1, &regval);
+            regval &= (0x3 << 12);
+            *pPri = regval >> 12;
+            break;
+            
+        case 9: /*VLAN[J]*/
+            rtl8306e_reg_get(4, 26, 1, &regval);
+            regval &= (0x3 << 12);
+            *pPri = regval >> 12;
+            break;
+            
+        case 10: /*VLAN[K]*/
+            rtl8306e_reg_get(0, 28, 1, &regval);
+            regval &= (0x3 << 12);
+            *pPri = regval >> 12;
+            break;
+            
+        case 11: /*VLAN[L]*/
+            rtl8306e_reg_get(1, 28, 1, &regval);
+            regval &= (0x3 << 12);
+            *pPri = regval >> 12;
+            break;
+            
+        case 12: /*VLAN[M]*/
+            rtl8306e_reg_get(2, 28, 1, &regval);
+            regval &= (0x3 << 12);
+            *pPri = regval >> 12;
+            break;
+            
+        case 13: /*VLAN[N]*/
+            rtl8306e_reg_get(3, 28, 1, &regval);
+            regval &= (0x3 << 12);
+            *pPri = regval >> 12;
+            break;
+            
+        case 14: /*VLAN[O]*/
+            rtl8306e_reg_get(4, 28, 1, &regval);
+            regval &= (0x3 << 12);
+            *pPri = regval >> 12;
+            break;
+            
+        case 15: /*VLAN[P]*/
+            rtl8306e_reg_get(0, 30, 1, &regval);
+            regval &= (0x3 << 12);
+            *pPri = regval >> 12;
+            break;
+            
+        default: /*unmatched vlan entry*/
+            rtl8306e_reg_get(0, 29, 0, &regval);
+            regval &= (0x3 << 9);
+            *pPri = regval >> 9;
+            return  FAILED;
+    }
+    return SUCCESS;
+}
+
+
+/* Function Name:
+ *      rtl8306e_vlan_transEnable_set
+ * Description:
+ *      Enable VLAN translation 
+ * Input:
+ *      enable       -   enable or disable VLAN translation
+ *      portmask    -   NNI port is set 1 and UNI port is set 0
+ * Output:
+ *      none
+ * Return:
+ *      SUCCESS
+ *      FAILED
+ * Note:
+ *      Only the traffic between NNI port and UNI port will be change with VID,
+ *      the VLAN tranlation function and Q-in-Q(SVLAN) could not be enabled  
+ *      at the same time, user should choose one of them. 
+ */
+int32 rtl8306e_vlan_transEnable_set(uint32 enable, uint32 portmask)
+{
+    uint32 regval;
+
+    rtl8306e_reg_get(6, 30, 3, &regval);
+
+    if(enable)
+    {
+        regval &= ~0xff;
+        regval |= (1 << 6) | (portmask & 0x3F);
+        rtl8306e_reg_set(6, 30, 3, regval);
+    }
+    else
+    {
+        regval &= ~0xff;
+        rtl8306e_reg_set(6, 30, 3, regval);
+    }
+
+    return SUCCESS;
+}
+
+
+/* Function Name:
+ *      rtl8306e_vlan_transEnable_get
+ * Description:
+ *      Get VLAN translation setting
+ * Input:
+ *      none
+ * Output:
+ *      pEnable       -   the pointer of enable or disable VLAN translation
+ *      pPortMask    -   the pointer of VLAN translation port mask
+ * Return:
+ *      SUCCESS
+ *      FAILED
+ * Note:
+ *      Only the traffic between NNI port and UNI port will be change with VID,
+ *      the VLAN tranlation function and Q-in-Q(SVLAN) could not be enabled  
+ *      at the same time, user should choose one of them. 
+ */
+int32 rtl8306e_vlan_transEnable_get(uint32 *pEnable, uint32 *pPortMask)
+{
+    uint32 regval;
+
+    if((NULL == pEnable) || (NULL == pPortMask))
+        return FAILED;
+    
+    rtl8306e_reg_get(6, 30, 3, &regval);
+    if((regval & (0x3 << 6)) == (0x1 << 6))
+    {
+        *pEnable = 1;
+        *pPortMask = regval & 0x3F;
+    }
+    else
+    {
+        *pEnable = 0;
+        *pPortMask = 0;
+    }
+
+    return SUCCESS;
+}
+
+/* Function Name:
+ *      rtl8306e_vlan_transparentEnable_set
+ * Description:
+ *      Enable VLAN transparent 
+ * Input:
+ *      enable       -   enable or disable VLAN transparent
+ * Output:
+ *      none
+ * Return:
+ *      SUCCESS
+ *      FAILED
+ * Note:
+ */
+int32 rtl8306e_vlan_transparentEnable_set(uint32 enable)
+{
+    uint32 port;
+
+    if (enable)
+    {
+        /*set vlan disabled*/
+        rtl8306e_regbit_set(0, 18, 8, 0, 1);
+        
+        /*disable tag aware*/
+        rtl8306e_vlan_tagAware_set(FALSE); 
+
+        /*disable EN_UNTAG_SET*/
+        rtl8306e_regbit_set(0, 29, 12, 0, 0);
+        
+        /*set vlan translation disabled*/
+        rtl8306e_regbit_set(6, 30, 6, 3, 0);
+        
+        /*set port0~5 untag unawre and disable Non-PVID discard*/
+        for (port = 0; port < 5; port ++)
+        {
+            rtl8306e_regbit_set(port, 22, 15, 0, 1);
+            rtl8306e_regbit_set(port, 22, 11, 0, 0);
+        } 
+        rtl8306e_regbit_set(6, 24, 1, 0, 1);
+        rtl8306e_regbit_set(6, 22, 11, 0, 0);
+         
+        /*disable EN_INSERT_TAG*/
+        rtl8306e_regbit_set(0, 28, 0, 3, 0);
+    }
+    else
+    {
+        /*set vlan enabled*/
+        rtl8306e_regbit_set(0, 18, 8, 0, 0);
+        
+        /*enable tag aware*/
+        rtl8306e_vlan_tagAware_set(TRUE); 
+    }
+
+    
+    return SUCCESS;
+}
+
+/* Function Name:
+ *      rtl8306e_vlan_transVid_set
+ * Description:
+ *      Set the translated VID
+ * Input:
+ *      vlanIndex   -   the VLAN entry index
+ *      transVid     -   the new VID
+ * Output:
+ *      none
+ * Return:
+ *      SUCCESS
+ *      FAILED
+ * Note:
+ *      The VID in the entry indexed by vlanIndex will be replaced with
+ *      new VID.
+ */ 
+int32 rtl8306e_vlan_transVid_set(uint32 vlanIndex, uint32 transVid)    
+{
+   uint32 regval;
+   
+   if((vlanIndex > 15) || (transVid > 0xFFF))
+        return FAILED;
+
+   if(vlanIndex < 15)     
+   {
+        rtl8306e_reg_get(6, 17 + vlanIndex, 4, &regval);
+        regval &= ~0xfff;
+        regval |= transVid;
+        rtl8306e_reg_set(6, 17 + vlanIndex, 4, regval);
+   }
+   else
+   {
+        rtl8306e_reg_get(6, 18, 1, &regval);
+        regval &= ~0xfff;
+        regval |= transVid;
+        rtl8306e_reg_set(6, 18, 1, regval);
+   }
+       
+   return SUCCESS;
+}
+
+/* Function Name:
+ *      rtl8306e_vlan_transVid_get
+ * Description:
+ *      Get the translated VID
+ * Input:
+ *      vlanIndex   -   the VLAN entry index
+ * Output:
+ *      pTransVid   -   the pointer of the new VID
+ * Return:
+ *      SUCCESS
+ *      FAILED
+ * Note:
+ *      The VID in the entry indexed by vlanIndex will be replaced with
+ *      new VID.
+ */ 
+int32 rtl8306e_vlan_transVid_get(uint32 vlanIndex, uint32 *pTransVid)
+{
+    uint32 regval;
+
+    if((vlanIndex > 15) || (NULL == pTransVid))
+        return FAILED;
+
+    if(vlanIndex < 15)
+    {
+       rtl8306e_reg_get(6, 17 + vlanIndex, 4, &regval);
+       *pTransVid = (regval & 0xfff);
+    }
+    else
+    {
+       rtl8306e_reg_get(6, 18, 1, &regval);
+       *pTransVid = (regval & 0xfff);
+    }
+        
+    return SUCCESS;
+}
+
+
+/* Function Name:
+ *      rtl8306e_svlan_tagAdmit_set
+ * Description:
+ *      Set Q-in-Q tag admit control
+ * Input:
+ *      port          -   port id
+ *      enable       -   enable tag admit control 
+ * Output:
+ *      none
+ * Return:
+ *      SUCCESS
+ *      FAILED
+ * Note:
+ *       
+ */
+int32 rtl8306e_svlan_tagAdmit_set(uint32 port, uint32 enable)
+{
+    if (port > 5)
+        return FAILED;
+
+    if(5 == port)
+    {
+        rtl8306e_regbit_set(6, 23, 0, 0, enable ? 1:0);
+    }
+    else
+    {
+        rtl8306e_regbit_set(6, 17 + port, 0, 0, enable ? 1:0);
+    }
+
+    return SUCCESS;
+}
+
+/* Function Name:
+ *      rtl8306e_svlan_tagAdmit_get
+ * Description:
+ *      Get Q-in-Q tag admit control
+ * Input:
+ *      port          -   port id
+ * Output:
+ *      pEnable     -   the pointer of enable tag admit control 
+ * Return:
+ *      SUCCESS
+ *      FAILED
+ * Note:
+ *       
+ */
+int32 rtl8306e_svlan_tagAdmit_get(uint32 port, uint32 *pEnable)
+{
+    uint32 regval;
+    
+    if(port > 5)
+        return FAILED;
+    
+    if(5 == port)
+    {
+        rtl8306e_reg_get(6, 23, 0, &regval);
+        *pEnable = regval ? 1:0;
+    }
+    else 
+    {
+        rtl8306e_reg_get(6, 17 + port, 0, &regval);
+        *pEnable = regval ? 1:0;        
+    }
+        
+
+    return SUCCESS;
+}
+
+/* Function Name:
+ *      rtl8306e_svlan_otagSrc_set
+ * Description:
+ *      Set how to decide outer tag vid and priority 
+ * Input:
+ *      port          -   port id
+ *      ovidSrc      -   ovid comes from
+ *      opriSrc      -    opri comes from 
+ * Output:
+ *      none
+ * Return:
+ *      SUCCESS
+ *      FAILED
+ * Note:
+ *       ovidSrc RTL8306E_VIDSRC_POVID : ovid is port-based ovid,    RTL8306E_VIDSRC_NVID:ovid is new vid(translated vid)
+ *       opriSrc  RTL8306E_PRISRC_PPRI   : opri is port-based priority, RTL8306E_PRISRC_1PRMK: opri is 1p remarking value
+ */
+int32 rtl8306e_svlan_otagSrc_set(uint32 port, uint32 ovidSrc, uint32 opriSrc)
+{
+    uint32 regval;
+    
+    if(port > 5)
+        return FAILED;
+
+    if(5 == port)
+    {
+        rtl8306e_reg_get(6, 23, 0, &regval);
+        regval &= ~0xC;
+        regval |= ovidSrc ? (1 << 3):0;
+        regval |= opriSrc ? (1 << 2) :0;
+        rtl8306e_reg_set(6, 23, 0, regval);
+    }
+    else
+    {
+        rtl8306e_reg_get(6, 17 + port, 0, &regval);
+        regval &= ~0xC;
+        regval |= ovidSrc ? (1 << 3):0;
+        regval |= opriSrc ? (1 << 2) :0;
+        rtl8306e_reg_set(6, 17 + port, 0, regval);        
+    }
+
+    return SUCCESS;
+}
+
+
+/* Function Name:
+ *      rtl8306e_svlan_otagSrc_get
+ * Description:
+ *      Get how to decide outer tag vid and priority 
+ * Input:
+ *      port            -   port id
+ * Output:
+ *      pOvidsrc      -   the pointer of ovid comes from
+ *      pOpriSrc      -   the pointer of opri comes from 
+ * Return:
+ *      SUCCESS
+ *      FAILED
+ * Note:
+ *       ovidSrc RTL8306E_VIDSRC_POVID : ovid is port-based ovid,    RTL8306E_VIDSRC_NVID:ovid is new vid(translated vid)
+ *       opriSrc  RTL8306E_PRISRC_PPRI   : opri is port-based priority, RTL8306E_PRISRC_1PRMK: opri is 1p remarking value
+ */
+
+int32 rtl8306e_svlan_otagSrc_get(uint32 port, uint32 *pOvidsrc, uint32 *pOpriSrc)
+{
+    uint32 regval;
+
+    if(port > 5)
+        return FAILED;
+
+    if(5 == port)
+    {
+        rtl8306e_reg_get(6, 23, 0, &regval);
+        *pOvidsrc = (regval & (1 << 3)) ? 1:0;
+        *pOpriSrc = (regval & (1 << 2)) ? 1:0;
+    }
+    else
+    {
+        rtl8306e_reg_get(6, 17 + port, 0, &regval);
+        *pOvidsrc = (regval & (1 << 3)) ? 1:0;
+        *pOpriSrc = (regval & (1 << 2)) ? 1:0;
+    }
+
+    return SUCCESS;
+}
+
+
+/* Function Name:
+ *      rtl8306e_cpu_set
+ * Description:
+ *       Specify Asic CPU port 
+ * Input:
+ *      port       -   Specify the port
+ *      enTag    -    CPU tag insert or not
+ * Output:
+ *      none
+ * Return:
+ *      SUCCESS
+ *      FAILED
+ * Note:
+ *      If the port is specified RTL8306_NOCPUPORT, it means
+ *      that no port is assigned as cpu port
+ */
+int32 rtl8306e_cpu_set(uint32 port, uint32 enTag) 
+{
+    uint32 regValue;
+
+    if (port > RTL8306_NOCPUPORT)
+        return FAILED;
+
+    if (port < RTL8306_PORT_NUMBER) 
+    {
+        /*enable CPU port Function */
+        rtl8306e_regbit_set(2, 21, 15, 3, 0);        
+        
+        /*whether inserting CPU tag*/
+        rtl8306e_regbit_set(2, 21, 12, 3, enTag ? 1 : 0);
+        
+        /*enable the ability to check cpu tag*/
+        rtl8306e_regbit_set(4, 21, 7, 0, 1);
+        
+        /*enable removing CPU tag*/
+        rtl8306e_regbit_set(2, 21, 11, 3, 1);
+        rtl8306e_reg_get(4, 21, 0, &regValue);
+        regValue = (regValue & 0xFFF8) | port;
+        rtl8306e_reg_set(4, 21, 0, regValue);
+
+        /*enable asic recaculate crc for pkt with cpu tag*/
+        rtl8306e_regbit_set(4, 21, 3, 0, 0);
+        
+        /*disable IEEE802.1x function of CPU Port*/
+        if (port < RTL8306_PORT5) 
+        {
+            rtl8306e_regbit_set(port, 17, 9, 2, 0);
+            rtl8306e_regbit_set(port, 17, 8, 2, 0);
+        }
+        else 
+        {
+            rtl8306e_regbit_set(6, 17, 9, 2, 0);
+            rtl8306e_regbit_set(6, 17, 8, 2, 0);
+        }
+        
+        /*Port 5 should be enabled especially*/
+        if (RTL8306_PORT5 == port)
+        {
+            rtl8306e_regbit_set(6, 22, 15, 0, TRUE);
+        }
+    }   
+    else 
+    {
+        /*disable CPU port Function */
+        rtl8306e_regbit_set(2, 21, 15, 3, 1);
+        rtl8306e_regbit_set(2, 21, 12, 3, 0);        
+        rtl8306e_reg_get(4, 21, 0, &regValue);
+        regValue = (regValue & 0xFFF8) | port;
+        rtl8306e_reg_set(4, 21, 0, regValue);
+    }   
+
+
+    return SUCCESS;
+}
+
+/* Function Name:
+ *      rtl8306e_cpu_set
+ * Description:
+ *       Get Asic CPU port number
+ * Input:
+ *      none
+ * Output:
+ *      pPort     - the pointer of CPU port number
+ *      pEnTag  - the pointer of CPU tag insert or not
+ * Return:
+ *      SUCCESS
+ *      FAILED
+ * Note:
+ *      If the port is specified RTL8306_NOCPUPORT, it means
+ *      that no port is assigned as cpu port
+ */
+int32 rtl8306e_cpu_get(uint32 *pPort, uint32 *pEnTag) 
+{
+    uint32 regValue;
+    uint32 bitValue, bitVal, cpufun;
+
+    if ((NULL == pPort ) || (NULL == pEnTag))
+        return FAILED;
+    
+    rtl8306e_regbit_get(2, 21, 12, 3, &bitValue);
+    rtl8306e_regbit_get(2, 21, 15, 3, &cpufun);
+    rtl8306e_regbit_get(4, 21, 7, 0, &bitVal);
+    
+    rtl8306e_reg_get(4, 21, 0, &regValue);
+    *pPort = regValue & 0x7;
+
+    if ((!cpufun) && bitValue && bitVal)
+        *pEnTag = TRUE;
+    else 
+        *pEnTag = FALSE;
+    
+    if(cpufun)
+        *pPort = RTL8306_NOCPUPORT;
+    
+    return SUCCESS;
+}
+
+/*added by Fan Kaixi*/
+
+/* Function Name:
+ *      rtl8306e_cpu_doubleTagInsert_set
+ * Description:
+ *      Enable synchronously insertting cpu tag and vlan tag ability
+ * Input:
+ *      enabled     -   enable or disable
+ * Output:
+ *      none
+ * Return:
+ *      SUCCESS
+ *      FAILED
+ * Note:
+ *      This API can be called to enable synchronously insertting cpu tag and vlan tag ability.
+*/
+int32 rtl8306e_cpu_doubleTagInsert_set(uint32 enabled)
+{
+    if (enabled > 0x1)
+        return FAILED;
+    
+    rtl8306e_regbit_set(4, 21, 10, 0, enabled ?1:0);
+    
+    return SUCCESS;
+}
+
+/* Function Name:
+ *      rtl8306e_cpu_doubleTagInsert_get
+ * Description:
+ *      Get Enabled status of synchronously insertting cpu tag and vlan tag ability
+ * Input:
+ *      none
+ * Output:
+ *      pEnabled    -   enable or disable
+ * Return:
+ *      SUCCESS
+ *      FAILED
+ * Note:
+ *      This API can be called to enable synchronously insertting cpu tag and vlan tag ability.
+*/
+int32 rtl8306e_cpu_doubleTagInsert_get(uint32 *pEnabled)
+{
+    
+    if (pEnabled == NULL)
+        return FAILED;
+    
+    rtl8306e_regbit_get(4, 21, 10, 0, pEnabled);
+    return SUCCESS;
+}
+
+/* Function Name:
+ *      rtl8306e_qos_softReset_set
+ * Description:
+ *      Software reset the asic
+ * Input:
+ *      none
+ * Output:
+ *      none
+ * Return:
+ *      SUCCESS
+ *      FAILED
+ * Note:
+ *      reset packet buffer.
+ */
+ 
+int32 rtl8306e_qos_softReset_set(void) 
+{    
+    /*software reset*/
+    rtl8306e_regbit_set(0, 16, 12, 0, 1);    
+    return SUCCESS;
+}
+
+
+/* Function Name:
+ *      rtl8306e_qos_queueNum_set
+ * Description:
+ *      Set egress port queue number (1 ~4)
+ * Input:
+ *      none
+ * Output:
+ *      none
+ * Return:
+ *      SUCCESS
+ *      FAILED
+ * Note:
+ *      Queue number is global configuration for switch.
+ */
+
+int32 rtl8306e_qos_queueNum_set(uint32 num) 
+{
+    uint32 regValue;
+    
+    if ((num == 0) ||(num > 4))
+        return FAILED;
+    
+    rtl8306e_reg_get(2, 22, 3, &regValue);
+    rtl8306e_reg_set(2, 22, 3, (regValue & 0xFFF3) | ((num-1) << 2));
+    
+    /*A soft-reset is required after configuring queue num*/
+     rtl8306e_qos_softReset_set( );
+    
+    return SUCCESS;
+}
+
+/* Function Name:
+ *      rtl8306e_qos_queueNum_set
+ * Description:
+ *      Set egress port queue number (1 ~4)
+ * Input:
+ *      none
+ * Output:
+ *      none
+ * Return:
+ *      SUCCESS
+ *      FAILED
+ * Note:
+ *      Queue number is global configuration for switch.
+ */
+int32 rtl8306e_qos_queueNum_get(uint32 *pNum) 
+{
+    uint32 regValue;
+
+    if (NULL == pNum) 
+        return FAILED;
+    
+    rtl8306e_reg_get(2, 22, 3, &regValue);
+    *pNum =    ((regValue & 0xC) >> 2) + 1;
+    return SUCCESS;
+}
+
+
+/* Function Name:
+ *      rtl8306e_qos_priToQueMap_set
+ * Description:
+ *     Set priority to Queue ID mapping
+ * Input:
+ *      priority   -  priority value (0 ~ 3)
+ *      qid        -  Queue id (0~3)
+ * Output:
+ *      none
+ * Return:
+ *      SUCCESS
+ *      FAILED
+ * Note:
+ *      Packets could be classified into specified queue through their priority. 
+ *      we can use this function to set pkt priority with queue id mapping
+ */
+int32 rtl8306e_qos_priToQueMap_set(uint32 priority, uint32 qid) 
+{
+    uint32 regValue;
+
+    if ((qid > 3) || (priority > 3)) 
+        return FAILED;
+    
+    rtl8306e_reg_get(1, 22, 3, &regValue);
+    switch(priority) 
+    {
+        case 0:
+            regValue = (regValue & 0xFFFC) | qid;
+            break;
+        case 1:
+            regValue = (regValue & 0xFFF3) | (qid << 2);
+            break;
+        case 2:
+            regValue = (regValue & 0xFFCF) | (qid << 4);
+            break;
+        case 3:
+            regValue = (regValue & 0xFF3F) | (qid << 6);
+            break;
+        default:
+            return FAILED;
+    }
+    rtl8306e_reg_set(1, 22, 3, regValue);
+    return SUCCESS;
+}
+
+
+/* Function Name:
+ *      rtl8306e_qos_priToQueMap_get
+ * Description:
+ *      Get priority to Queue ID mapping
+ * Input:
+ *      priority   -  priority value (0 ~ 3)
+ * Output:
+ *      pQid      -  pointer of Queue id (0~3)
+ * Return:
+ *      SUCCESS
+ *      FAILED
+ * Note:
+ *      Packets could be classified into specified queue through their priority. 
+ *      we can use this function to set pkt priority with queue id mapping
+ */
+int32 rtl8306e_qos_priToQueMap_get(uint32 priority, uint32 *pQid) 
+{
+    uint32 regValue;
+
+    if ((priority > 3) || (NULL == pQid))
+        return FAILED;
+    
+    rtl8306e_reg_get(1, 22, 3, &regValue);
+    
+    switch(priority) 
+    {
+        case 0:
+            *pQid = regValue & 0x3;
+            break;
+        case 1:
+            *pQid = (regValue & 0xC) >> 2;
+            break;
+        case 2:
+            *pQid = (regValue & 0x30) >> 4;
+            break;
+        case 3:
+            *pQid = (regValue & 0xC0) >> 6;
+            break;
+        default:
+            return FAILED;
+    }
+    return SUCCESS;
+}
+
+
+/* Function Name:
+ *      rtl8306e_qos_portRate_set
+ * Description:
+ *      Set port bandwidth control
+ * Input:
+ *      port            -  port number (0~5)
+ *      n64Kbps       -  Port rate (0~1526), unit 64Kbps
+ *      direction      -  Ingress or Egress bandwidth control
+ *      enabled       -  enable bandwidth control
+ * Output:
+ *      none
+ * Return:
+ *      SUCCESS
+ *      FAILED
+ * Note:
+ *      For each port, both input and output bandwidth could be configured, 
+ *      RTL8306_PORT_RX represents port input bandwidth control, 
+ *      RTL8306_PORT_TX represents port output bandwidth control.
+ *      port rate unit is 64Kbps. For output rate control, enable/disable 
+ *      is configured per port, but for input rate control, it is for all port.
+ */
+int32 rtl8306e_qos_portRate_set(uint32 port, uint32 n64Kbps, uint32 direction, uint32 enabled)
+{
+    uint32 regValue;
+    
+    if ((port > RTL8306_PORT5) || (n64Kbps > 0x5F6) || (direction > 1))
+        return FAILED;
+    
+    /*Port 5 corresponding PHY6*/
+    if (RTL8306_PORT5 == port)  
+        port ++ ;  
+    
+    if (RTL8306_PORT_RX == direction) 
+    {  
+        /*configure port Rx rate*/
+        if (!enabled ) 
+        {
+            rtl8306e_regbit_set(0, 21, 15, 3, 1);
+        } 
+        else 
+        {
+            rtl8306e_regbit_set(0, 21, 15, 3, 0);
+            rtl8306e_reg_get(port, 21, 2, &regValue);
+            regValue = (regValue & 0xF800) | (n64Kbps & 0x7FF);
+            rtl8306e_reg_set(port, 21, 2, regValue);
+        }
+    } 
+    else 
+    {  
+        /*configure port Tx rate*/
+        if (!enabled) 
+        {
+            rtl8306e_regbit_set(port, 18, 15, 2, 0);
+        } 
+        else 
+        {
+            rtl8306e_regbit_set(port, 18, 15, 2, 1);
+            rtl8306e_reg_get(port, 18, 2, &regValue);
+            regValue = (regValue & 0xF800) | (n64Kbps & 0x7FF);
+            rtl8306e_reg_set(port, 18, 2, regValue);
+        }
+    }
+    return SUCCESS;
+}
+
+/* Function Name:
+ *      rtl8306e_qos_portRate_get
+ * Description:
+ *      Get port bandwidth control rate
+ * Input:
+ *      port                 -  Port number (0~5)
+ * Output:
+ *      *pN64Kbps        -  Port rate (0~1526), unit 64Kbps
+ *      direction           -  Input or output bandwidth control
+ *      *enabled           -  enabled or disabled bandwidth control
+ * Return:
+ *      SUCCESS
+ *      FAILED
+ * Note:
+ *      For each port, both input and output bandwidth could be configured, 
+ *      RTL8306_PORT_RX represents port input bandwidth control, 
+ *      RTL8306_PORT_TX represents port output bandwidth control.
+ *      port rate unit is 64Kbps. For output rate control, enable/disable 
+ *      is configured per port, but for input rate control, it is for all port.
+ */
+int32 rtl8306e_qos_portRate_get(uint32 port, uint32 *pN64Kbps, uint32 direction, uint32 *pEnabled) 
+{
+    uint32 regValue;
+
+    if ((port > RTL8306_PORT5) || (NULL == pN64Kbps) || (direction > RTL8306_PORT_TX) || (NULL == pEnabled))
+        return FAILED;
+    
+    /*Port 5 corresponding PHY6*/
+    if (RTL8306_PORT5 == port)  
+        port ++ ;  
+
+    if (RTL8306_PORT_RX == direction)
+    {
+        /*Get port Rx rate*/
+        rtl8306e_regbit_get(0, 21, 15, 3, &regValue);
+        *pEnabled = (regValue ? FALSE:TRUE);
+        rtl8306e_reg_get(port, 21, 2, &regValue);
+        *pN64Kbps = regValue & 0x7FF;
+    } 
+    else 
+    { 
+        /*Get port Tx rate*/
+        rtl8306e_regbit_get(port, 18, 15, 2, pEnabled);
+        rtl8306e_reg_get(port, 18, 2, &regValue);
+        *pN64Kbps = regValue & 0x7FF;
+    }
+    return SUCCESS;
+}
+
+
+/* Function Name:
+ *      rtl8306e_qos_1pRemarkEnable_set
+ * Description:
+ *      Set 802.1P remarking ability
+ * Input:
+ *      port       -  port number (0~5)
+ *      enabled  -  TRUE or FALSE
+ * Output:
+ *      none
+ * Return:
+ *      SUCCESS
+ *      FAILED
+ * Note:
+ *      
+ */
+int32 rtl8306e_qos_1pRemarkEnable_set(uint32 port, uint32 enabled)
+{
+
+    if (port > RTL8306_PORT5)
+        return FAILED;
+    
+    /*Port 5 corresponding PHY6*/
+    if (RTL8306_PORT5 == port)  
+        port ++ ;
+    /*enable new 1p remarking function*/
+    rtl8306e_regbit_set(0, 28, 13, 3, 1);
+    rtl8306e_regbit_set(port, 17, 0, 2, enabled ? 1:0);
+#ifdef RTL8306_TBLBAK
+    rtl8306_TblBak.vlanConfig_perport[port].en1PRemark= (uint8) enabled;
+#endif
+    
+    return SUCCESS;
+}
+
+/* Function Name:
+ *      rtl8306e_qos_1pRemarkEnable_set
+ * Description:
+ *      Get 802.1P remarking ability
+ * Input:
+ *      port        -  port number (0~5)
+ * Output:
+ *      pEnabled  -  pointer of the ability status
+ * Return:
+ *      SUCCESS
+ *      FAILED
+ * Note:
+ *      
+ */
+int32 rtl8306e_qos_1pRemarkEnable_get(uint32 port, uint32 *pEnabled) 
+{
+    uint32 bitValue;
+    
+    if (port > RTL8306_PORT5 || (NULL == pEnabled))
+        return FAILED;
+    
+    /*Port 5 corresponding PHY6*/
+    if (RTL8306_PORT5 == port)  
+        port ++ ;
+    
+    rtl8306e_regbit_get(port, 17, 0, 2, &bitValue);
+    *pEnabled = (bitValue ? TRUE:FALSE);
+    return SUCCESS;
+}
+
+/* Function Name:
+ *      rtl8306e_qos_1pRemark_set
+ * Description:
+ *      Set 802.1P remarking priority
+ * Input:
+ *      priority       -  Packet priority(0~4)
+ *      priority1p    -  802.1P priority(0~7)
+ * Output:
+ *      none
+ * Return:
+ *      SUCCESS
+ *      FAILED
+ * Note:
+ *      switch determines packet priority, the priority souce could
+ *      be port-based, 1Q-based, dscp-based, vid-based, ip address,
+ *      cpu tag.
+ */
+int32 rtl8306e_qos_1pRemark_set(uint32 priority, uint32 priority1p)
+{
+    uint32 regValue;
+
+    if ( (priority > 3) || (priority1p > 0x7) ) 
+        return FAILED;
+    
+    rtl8306e_reg_get(0, 24, 3, &regValue);
+    switch(priority) 
+    {
+        case 0:
+            regValue = (regValue & 0xFFF8) | priority1p;
+            break;
+        case 1:
+            regValue = (regValue & 0xFFC7) | (priority1p << 3);
+            break;
+        case 2:
+            regValue = (regValue & 0xFE3F) | (priority1p <<6);
+            break;
+        case 3:
+            regValue = (regValue & 0xF1FF) | (priority1p <<9);
+            break;
+        default:
+            return FAILED;
+    }    
+    rtl8306e_reg_set(0, 24, 3, regValue);
+#ifdef RTL8306_TBLBAK
+    rtl8306_TblBak.dot1PremarkCtl[priority] = (uint8) priority1p;
+#endif
+    
+    return SUCCESS;
+}
+
+/* Function Name:
+ *      rtl8306_getAsic1pRemarkingPriority
+ * Description:
+ *      Get 802.1P remarking priority
+ * Input:
+ *      priority       -  Packet priority(0~4)
+ * Output:
+ *      pPriority1p  -  the pointer of 802.1P priority(0~7)
+ * Return:
+ *      SUCCESS
+ *      FAILED
+ * Note:
+ *      switch determines packet priority, the priority souce could
+ *      be port-based, 1Q-based, dscp-based, vid-based, ip address,
+ *      cpu tag.
+ */
+int32 rtl8306e_qos_1pRemark_get(uint32 priority, uint32 *pPriority1p) 
+{
+    uint32 regValue;
+
+    if ( (priority > 3) || (NULL == pPriority1p) ) 
+        return FAILED;
+    
+    rtl8306e_reg_get(0, 24, 3, &regValue);
+    switch(priority)
+    {
+        case 0:
+            *pPriority1p = (regValue & 0x7);
+            break;
+        case 1:
+            *pPriority1p = (regValue & 0x0038) >> 3;
+            break;
+        case 2:
+            *pPriority1p = (regValue & 0x01C0) >> 6;
+            break;
+        case 3:
+            *pPriority1p = (regValue & 0x0E00) >> 9;
+            break;
+        default:
+            return FAILED;
+    }
+
+    return SUCCESS;
+}
+
+
+/* Function Name:
+ *      rtl8306e_qos_portPri_set
+ * Description:
+ *      Set port-based priority
+ * Input:
+ *      port          -  port number (0~5)
+ *      priority      -  Packet port-based priority(0~3)
+ * Output:
+*       none
+ * Return:
+ *      SUCCESS
+ *      FAILED
+ * Note:
+ *      packet will be assigned a port-based priority correspond to the ingress port.
+ */
+int32 rtl8306e_qos_portPri_set(uint32 port, uint32 priority)
+{
+    uint32 regValue;
+
+    if ((port > RTL8306_PORT5) ||(priority > 3))
+        return FAILED;
+    
+    /*Port 5 corresponding PHY6*/
+    if (RTL8306_PORT5 == port)  
+        port ++ ;  
+    
+    rtl8306e_reg_get(port, 17, 2, &regValue);
+    regValue = (regValue & 0xE7FF) | (priority << 11);
+    rtl8306e_reg_set(port, 17, 2, regValue);
+    
+    return SUCCESS;
+}
+
+/* Function Name:
+ *      rtl8306e_qos_portPri_get
+ * Description:
+ *      Get port-based priority
+ * Input:
+ *      port          -  port number (0~5)
+ * Output:
+ *      pPriority    -   pointer of packet port-based priority(0~4)
+ * Return:
+ *      SUCCESS
+ *      FAILED
+ * Note:
+ *      packet will be assigned a port-based priority correspond to the ingress port.
+ */ 
+int32 rtl8306e_qos_portPri_get(uint32 port, uint32 *pPriority) 
+{
+    uint32 regValue;
+
+    if ((port > RTL8306_PORT5) ||(NULL == pPriority))
+        return FAILED;
+    
+    if (port < RTL8306_PORT5) 
+        rtl8306e_reg_get(port, 17, 2, &regValue);
+    else
+        rtl8306e_reg_get(6, 17, 2, &regValue);
+    
+    *pPriority = (regValue & 0x1800) >> 11;
+
+    return SUCCESS;
+}
+
+/* Function Name:
+ *      rtl8306e_qos_1pPriRemap_set
+ * Description:
+ *      Set Asic 1Q-tag priority mapping to 2-bit priority
+ * Input:
+ *      tagprio  -  1Q-tag proirty (0~7, 3 bit value)
+ *      prio      -   internal use 2-bit priority
+ * Output:
+ *      none
+ * Return:
+ *      SUCCESS
+ *      FAILED
+ * Note:
+ *      switch internal use 2-bit priority, so it should map 3-bit 1Q-tag priority
+ *      to 2-bit priority
+ */ 
+int32 rtl8306e_qos_1pPriRemap_set(uint32 tagprio, uint32 prio) 
+{
+    uint32 regValue;
+
+    if ((tagprio > RTL8306_1QTAG_PRIO7) || (prio > RTL8306_PRIO3 ))
+        return FAILED;
+    
+    rtl8306e_reg_get(2, 24, 3, &regValue);
+    switch(tagprio) 
+    {
+        case RTL8306_1QTAG_PRIO0:
+            regValue = (regValue & 0xFFFC) | prio;
+            break;
+        case RTL8306_1QTAG_PRIO1:
+            regValue = (regValue & 0xFFF3) |(prio << 2);
+            break;
+        case RTL8306_1QTAG_PRIO2:
+            regValue = (regValue & 0xFFCF) | (prio << 4);
+            break;
+        case RTL8306_1QTAG_PRIO3:
+            regValue = (regValue & 0xFF3F) | (prio << 6);
+            break;
+        case RTL8306_1QTAG_PRIO4:
+            regValue = (regValue & 0xFCFF) | (prio << 8);
+            break;
+        case RTL8306_1QTAG_PRIO5:
+            regValue = (regValue & 0xF3FF) | (prio << 10);
+            break;
+        case RTL8306_1QTAG_PRIO6:
+            regValue = (regValue & 0xCFFF) | (prio << 12);
+            break;
+        case RTL8306_1QTAG_PRIO7:
+            regValue = (regValue & 0x3FFF) | (prio << 14);
+            break;
+        default:
+            return FAILED;
+    }    
+
+    rtl8306e_reg_set(2, 24, 3, regValue);    
+    return SUCCESS;
+}
+
+/* Function Name:
+ *      rtl8306e_qos_1pPriRemap_get
+ * Description:
+ *      Get Asic 1Q-tag priority mapping to 2-bit priority
+ * Input:
+ *      tagprio  -  1Q-tag proirty (0~7, 3 bit value)
+ * Output:
+ *      pPrio     -  pointer of  internal use 2-bit priority
+ * Return:
+ *      SUCCESS
+ *      FAILED
+ * Note:
+ *      switch internal use 2-bit priority, so it should map 3-bit 1Q-tag priority
+ *      to 2-bit priority
+ */ 
+int32 rtl8306e_qos_1pPriRemap_get(uint32 tagprio, uint32 *pPrio) 
+{
+    uint32 regValue;
+    
+    if ((tagprio > RTL8306_1QTAG_PRIO7) || (NULL == pPrio))
+        return FAILED;
+    
+    rtl8306e_reg_get(2, 24, 3, &regValue);
+    switch(tagprio) 
+    {
+        case RTL8306_1QTAG_PRIO0:
+            *pPrio = regValue & 0x3;
+            break;
+        case RTL8306_1QTAG_PRIO1:
+            *pPrio = (regValue & 0xC) >> 2;
+            break;
+        case RTL8306_1QTAG_PRIO2:
+            *pPrio = (regValue & 0x30) >> 4;
+            break;
+        case RTL8306_1QTAG_PRIO3:
+            *pPrio = (regValue & 0xC0) >> 6;
+            break;
+        case RTL8306_1QTAG_PRIO4:
+            *pPrio = (regValue & 0x300) >> 8;
+            break;
+        case RTL8306_1QTAG_PRIO5:
+            *pPrio = (regValue & 0xC00) >> 10;
+            break;
+        case RTL8306_1QTAG_PRIO6:
+            *pPrio = (regValue & 0x3000) >> 12;
+            break;
+        case RTL8306_1QTAG_PRIO7:
+            *pPrio = (regValue & 0xC000) >> 14;
+            break;
+        default:
+            return FAILED;
+    }
+
+    return SUCCESS;
+}
+
+/* Function Name:
+ *      rtl8306e_dscpPriRemap_set
+ * Description:
+ *      Set DSCP-based priority
+ * Input:
+ *      code      -  dscp code
+ *      priority   -  dscp-based priority
+ * Output:
+ *      none
+ * Return:
+ *      SUCCESS
+ *      FAILED
+ * Note:
+ *      switch support 16 kinds of dscp code:
+ *          RTL8306_DSCP_EF          
+ *                 - DSCP for the Expedited forwarding PHB, 101110   
+ *          RTL8306_DSCP_AFL1         
+ *                 - DSCP for AF PHB Class 1 low drop, 001010
+ *          RTL8306_DSCP_AFM1     
+ *                 - DSCP for AF PHB Class 1 medium drop, 001100
+ *          RTL8306_DSCP_AFH1      
+ *                 - DSCP for AF PHB Class 1 high drop, 001110
+ *          RTL8306_DSCP_AFL2       
+ *                 - DSCP for AF PHB Class 2 low drop, 01001
+ *          RTL8306_DSCP_AFM2       
+ *                 - DSCP for AF PHB Class 2 medium drop, 010100
+ *          RTL8306_DSCP_AFH2   
+ *                 - DSCP for AF PHB Class 2 high drop, 010110
+ *          RTL8306_DSCP_AFL3    
+ *                 - DSCP for AF PHB Class 3 low drop, 011010
+ *          RTL8306_DSCP_AFM3      
+ *                 - DSCP for AF PHB Class 3 medium drop, 011100
+ *          RTL8306_DSCP_AFH3    
+ *                 - DSCP for AF PHB Class 3 high drop, 0111
+ *          RTL8306_DSCP_AFL4     
+ *                 - DSCP for AF PHB Class 4 low drop, 100010
+ *          RTL8306_DSCP_AFM4    
+ *                 - DSCP for AF PHB Class 4 medium drop, 100100
+ *          RTL8306_DSCP_AFH4     
+ *                 - DSCP for AF PHB Class 4 high drop, 100110
+ *          RTL8306_DSCP_NC        
+ *                 - DSCP for network control, 110000 or 111000
+ *          RTL8306_DSCP_REG_PRI 
+ *                 - DSCP Register match priority, user could define two dscp code
+ *          RTL8306_DSCP_BF        
+ *                 - DSCP Default PHB
+ *     
+ */ 
+int32 rtl8306e_qos_dscpPriRemap_set(uint32 code, uint32 priority) 
+{
+    uint32 regValue1, regValue2;
+
+    if ((code > RTL8306_DSCP_BF) ||(priority > RTL8306_PRIO3))
+        return FAILED;
+
+    rtl8306e_reg_get(1, 23, 3, &regValue1);
+    rtl8306e_reg_get(1, 24, 3, &regValue2);
+    switch(code) 
+    {
+        case RTL8306_DSCP_EF:
+            regValue1 = (regValue1 & 0xFFFC) | priority;
+            rtl8306e_reg_set(1, 23, 3, regValue1);
+            break;            
+        case RTL8306_DSCP_AFL1:
+            regValue1 = (regValue1 & 0xFFF3) | (priority << 2);
+            rtl8306e_reg_set(1, 23, 3, regValue1);
+            break;
+        case RTL8306_DSCP_AFM1:
+            regValue1 = (regValue1 & 0xFFCF) | (priority << 4);
+            rtl8306e_reg_set(1, 23, 3, regValue1);
+            break;
+        case RTL8306_DSCP_AFH1:
+            regValue1 = (regValue1 & 0xFF3F) | (priority << 6);
+            rtl8306e_reg_set(1, 23, 3, regValue1);
+            break;
+        case RTL8306_DSCP_AFL2:
+            regValue1 = (regValue1 & 0xFCFF) | (priority << 8);
+            rtl8306e_reg_set(1, 23, 3, regValue1);
+            break;
+        case RTL8306_DSCP_AFM2:
+            regValue1 = (regValue1 & 0xF3FF) | (priority << 10);
+            rtl8306e_reg_set(1, 23, 3, regValue1);
+            break;
+        case RTL8306_DSCP_AFH2:
+            regValue1 = (regValue1 & 0xCFFF) |(priority << 12);
+            rtl8306e_reg_set(1, 23, 3, regValue1);
+            break;
+        case RTL8306_DSCP_AFL3:
+            regValue1 = (regValue1 & 0x3FFF) | (priority << 14);
+            rtl8306e_reg_set(1, 23, 3, regValue1);
+            break;
+        case RTL8306_DSCP_AFM3:
+            regValue2 = (regValue2 & 0xFFFC) | priority;
+            rtl8306e_reg_set(1, 24, 3, regValue2);
+            break;
+        case RTL8306_DSCP_AFH3:
+            regValue2 = (regValue2 & 0xFFF3) | (priority <<2);
+            rtl8306e_reg_set(1, 24, 3, regValue2);
+            break;
+        case RTL8306_DSCP_AFL4:
+            regValue2 = (regValue2 & 0xFFCF) | (priority <<4);
+            rtl8306e_reg_set(1, 24, 3, regValue2);
+            break;
+        case RTL8306_DSCP_AFM4:
+            regValue2 = (regValue2 & 0xFF3F) | (priority << 6);
+            rtl8306e_reg_set(1, 24, 3, regValue2);
+            break;
+        case RTL8306_DSCP_AFH4:
+            regValue2 = (regValue2 & 0xFCFF) | (priority << 8);
+            rtl8306e_reg_set(1, 24, 3, regValue2);
+            break;
+        case RTL8306_DSCP_NC:
+            regValue2 = (regValue2 & 0xF3FF) | (priority << 10);
+            rtl8306e_reg_set(1, 24, 3, regValue2);
+            break;
+        case RTL8306_DSCP_REG_PRI:
+            regValue2 = (regValue2 & 0xCFFF) | (priority << 12);
+            rtl8306e_reg_set(1, 24, 3, regValue2);
+            break;
+        case RTL8306_DSCP_BF:
+            regValue2 = (regValue2 & 0x3FFF) | (priority << 14);
+            rtl8306e_reg_set(1, 24, 3, regValue2);
+            break;
+        default:
+            return FAILED;
+    }
+    return SUCCESS;
+}
+
+
+/* Function Name:
+ *      rtl8306e_dscpPriRemap_set
+ * Description:
+ *      Get DSCP-based priority
+ * Input:
+ *      code      -  dscp code
+ * Output:
+ *      pPriority  -  the pointer of dscp-based priority
+ * Return:
+ *      SUCCESS
+ *      FAILED
+ * Note:
+ *      switch support 16 kinds of dscp code:
+ *          RTL8306_DSCP_EF          
+ *                 - DSCP for the Expedited forwarding PHB, 101110   
+ *          RTL8306_DSCP_AFL1         
+ *                 - DSCP for AF PHB Class 1 low drop, 001010
+ *          RTL8306_DSCP_AFM1     
+ *                 - DSCP for AF PHB Class 1 medium drop, 001100
+ *          RTL8306_DSCP_AFH1      
+ *                 - DSCP for AF PHB Class 1 high drop, 001110
+ *          RTL8306_DSCP_AFL2       
+ *                 - DSCP for AF PHB Class 2 low drop, 01001
+ *          RTL8306_DSCP_AFM2       
+ *                 - DSCP for AF PHB Class 2 medium drop, 010100
+ *          RTL8306_DSCP_AFH2   
+ *                 - DSCP for AF PHB Class 2 high drop, 010110
+ *          RTL8306_DSCP_AFL3    
+ *                 - DSCP for AF PHB Class 3 low drop, 011010
+ *          RTL8306_DSCP_AFM3      
+ *                 - DSCP for AF PHB Class 3 medium drop, 011100
+ *          RTL8306_DSCP_AFH3    
+ *                 - DSCP for AF PHB Class 3 high drop, 0111
+ *          RTL8306_DSCP_AFL4     
+ *                 - DSCP for AF PHB Class 4 low drop, 100010
+ *          RTL8306_DSCP_AFM4    
+ *                 - DSCP for AF PHB Class 4 medium drop, 100100
+ *          RTL8306_DSCP_AFH4     
+ *                 - DSCP for AF PHB Class 4 high drop, 100110
+ *          RTL8306_DSCP_NC        
+ *                 - DSCP for network control, 110000 or 111000
+ *          RTL8306_DSCP_REG_PRI 
+ *                 - DSCP Register match priority, user could define two dscp code
+ *          RTL8306_DSCP_BF        
+ *                 - DSCP Default PHB
+ *     
+ */ 
+int32 rtl8306e_qos_dscpPriRemap_get(uint32 code, uint32 *pPriority) 
+{
+    uint32  regValue1, regValue2;
+
+    if ((code > RTL8306_DSCP_BF) || (NULL == pPriority))
+        return FAILED;
+    
+    rtl8306e_reg_get(1, 23, 3, &regValue1);
+    rtl8306e_reg_get(1, 24, 3, &regValue2);
+    switch(code) 
+    {
+        case RTL8306_DSCP_EF:
+            *pPriority = regValue1 & 0x3;
+            break;
+        case RTL8306_DSCP_AFL1:
+            *pPriority = (regValue1 & 0xC)  >> 2;
+            break;
+        case RTL8306_DSCP_AFM1:
+            *pPriority = (regValue1 & 0x30) >> 4;
+            break;
+        case RTL8306_DSCP_AFH1:
+            *pPriority = (regValue1 & 0xC0) >> 6;
+            break;
+        case RTL8306_DSCP_AFL2:
+            *pPriority = (regValue1 & 0x300) >> 8;
+            break;
+        case RTL8306_DSCP_AFM2:
+            *pPriority = (regValue1 & 0xC00) >> 10;
+            break;
+        case RTL8306_DSCP_AFH2:
+            *pPriority = (regValue1 & 0x3000) >> 12;
+            break;
+        case RTL8306_DSCP_AFL3:
+            *pPriority = (regValue1 & 0xC000) >> 14;
+            break;
+        case RTL8306_DSCP_AFM3:
+            *pPriority = regValue2 & 0x3;
+            break;
+        case RTL8306_DSCP_AFH3:
+            *pPriority = (regValue2 & 0xC) >> 2;
+            break;
+        case RTL8306_DSCP_AFL4:
+            *pPriority = (regValue2 & 0x30) >> 4;
+            break;
+        case RTL8306_DSCP_AFM4:
+            *pPriority = (regValue2 & 0xC0) >> 6;
+            break;
+        case RTL8306_DSCP_AFH4:
+            *pPriority = (regValue2 & 0x300) >> 8;
+            break;
+        case RTL8306_DSCP_NC:
+            *pPriority = (regValue2 & 0xC00) >>10;
+            break;
+        case RTL8306_DSCP_REG_PRI:
+            *pPriority = (regValue2 & 0x3000) >> 12;
+            break;
+        case RTL8306_DSCP_BF:
+            *pPriority = (regValue2 & 0xC000) >> 14;
+            break;
+        default:
+            return FAILED;
+    }
+
+    return SUCCESS;
+} 
+
+
+/* Function Name:
+ *      rtl8306e_qos_priSrcArbit_set
+ * Description:
+ *      Set priority source arbitration level
+ * Input:
+ *      priArbit  - The structure describe levels of 5 kinds of priority 
+ * Output:
+ *      none
+ * Return:
+ *      SUCCESS
+ *      FAILED
+ * Note:
+ *      switch could recognize 7 types of priority source at most, 
+ *      and a packet properly has all of them. among them, there 
+ *      are 5 type priorities could be set priority level, they are 
+ *      ACL-based  priority, DSCP-based priority, 1Q-based priority,
+ *      Port-based priority, VID- based priority.each one could be 
+ *      set level from 0 to 5, arbitration module will decide their sequece 
+ *      to take, the highest level priority will be adopted at first, 
+ *      then  priority type of the sencond highest level. priority with level 0
+ *      will not be recognized any more. 
+ */
+
+int32 rtl8306e_qos_priSrcArbit_set(rtl8306e_qosPriArbitPara_t priArbit) 
+{
+    uint32 regval;
+
+    if ((priArbit.acl_pri_lev > 5) || (priArbit.dscp_pri_lev > 5) ||
+        (priArbit.dot1q_pri_lev > 5)   || (priArbit.port_pri_lev > 5)  ||
+        (priArbit.vid_pri_lev > 5))
+        return FAILED;
+    
+    /*vid based priority selection*/
+    rtl8306e_reg_get(0, 28, 3, &regval);
+    regval &= ~(0x1F << 8);
+    if (priArbit.vid_pri_lev)
+        regval |= (1 << (priArbit.vid_pri_lev -1 + 8));
+    rtl8306e_reg_set(0, 28, 3, regval);
+
+    /*acl based priority*/
+    rtl8306e_reg_get(1, 21, 3, &regval);
+    regval &= ~(0xF << 12);
+    rtl8306e_reg_set(1, 21, 3, regval);    
+    rtl8306e_regbit_set(0, 28, 7, 3, 0);
+    if (5 == priArbit.acl_pri_lev)
+    {
+        rtl8306e_regbit_set(0, 28, 7, 3, 1);
+    }
+    else if (priArbit.acl_pri_lev > 0)
+    {
+        rtl8306e_reg_get(1, 21, 3, &regval); 
+        regval |= (1 << (priArbit.acl_pri_lev -1 + 12));
+        rtl8306e_reg_set(1, 21, 3, regval);
+    }
+        
+    /*dscp based priority*/
+    rtl8306e_reg_get(1, 21, 3, &regval);
+    regval &= ~(0xF << 8);
+    rtl8306e_reg_set(1, 21, 3, regval);    
+    rtl8306e_regbit_set(0, 26, 15, 3, 0);
+    if (5 == priArbit.dscp_pri_lev)
+    {
+        rtl8306e_regbit_set(0, 26, 15, 3, 1);
+    }
+    else if (priArbit.dscp_pri_lev > 0)
+    {
+        rtl8306e_reg_get(1, 21, 3, &regval);
+        regval |= (1 << (priArbit.dscp_pri_lev -1 + 8));
+        rtl8306e_reg_set(1, 21, 3, regval);
+    }
+    
+    /*1Q based priority*/
+    rtl8306e_reg_get(1, 21, 3, &regval);
+    regval &= ~(0xF << 4);
+    rtl8306e_reg_set(1, 21, 3, regval);
+    rtl8306e_regbit_set(0, 26, 14, 3, 0);
+    if (5 == priArbit.dot1q_pri_lev)
+    {
+        rtl8306e_regbit_set(0, 26, 14, 3, 1);                    
+    }
+    else if (priArbit.dot1q_pri_lev > 0)
+    {
+        rtl8306e_reg_get(1, 21, 3, &regval);        
+        regval |= ( 1 << (priArbit.dot1q_pri_lev -1 + 4));
+        rtl8306e_reg_set(1, 21, 3, regval);
+    }
+
+    /*port based priority*/
+    rtl8306e_reg_get(1, 21, 3, &regval);
+    regval &= ~0xF;
+    rtl8306e_reg_set(1, 21, 3, regval);
+    rtl8306e_regbit_set(0, 26, 13, 3, 0);
+    if (5 == priArbit.port_pri_lev)
+    {
+        rtl8306e_regbit_set(0, 26, 13, 3, 1);        
+    }
+    else if (priArbit.port_pri_lev > 0)
+    {
+        rtl8306e_reg_get(1, 21, 3, &regval); 
+        regval |= (1 << (priArbit.port_pri_lev -1));
+        rtl8306e_reg_set(1, 21, 3, regval);
+    }
+    
+    return SUCCESS;
+}
+
+
+/* Function Name:
+ *      rtl8306e_qos_priSrcArbit_get
+ * Description:
+ *      Get priority source arbitration level
+ * Input:
+ *      none 
+ * Output:
+ *      pPriArbit  - The structure describe levels of 5 kinds of priority 
+ * Return:
+ *      SUCCESS
+ *      FAILED
+ * Note:
+ *      switch could recognize 7 types of priority source at most, 
+ *      and a packet properly has all of them. among them, there 
+ *      are 5 type priorities could be set priority level, they are 
+ *      ACL-based  priority, DSCP-based priority, 1Q-based priority,
+ *      Port-based priority, VID- based priority.each one could be 
+ *      set level from 0 to 5, arbitration module will decide their sequece 
+ *      to take, the highest level priority will be adopted at first, 
+ *      then  priority type of the sencond highest level. priority with level 0
+ *      will not be recognized any more. 
+ */
+int32 rtl8306e_qos_priSrcArbit_get(rtl8306e_qosPriArbitPara_t *pPriArbit)
+{
+    uint32 regval;
+    uint32 i ;
+        
+    if (NULL == pPriArbit)
+        return FAILED;
+
+    pPriArbit ->acl_pri_lev      = 0;
+    pPriArbit ->dot1q_pri_lev  = 0;
+    pPriArbit ->dscp_pri_lev   = 0;
+    pPriArbit ->port_pri_lev    = 0;
+    pPriArbit ->vid_pri_lev      = 0;
+
+    /*vid based priority selection*/
+    rtl8306e_reg_get(0, 28, 3, &regval);
+    regval &= (0x1F << 8);
+    regval >>= 8;
+    for (i = 5; i > 0; i --)
+    {
+        if(regval >> (i-1))
+        {
+            pPriArbit ->vid_pri_lev = i;
+            break;
+        }
+    }
+
+    /*acl based priority*/
+    rtl8306e_regbit_get(0, 28, 7, 3, &regval);
+    if(regval)
+    {
+        pPriArbit->acl_pri_lev = 5;
+    }
+    else
+    {
+        rtl8306e_reg_get(1, 21, 3, &regval);
+        regval &= (0xF << 12);
+        regval >>= 12;
+        for (i = 4; i > 0; i --)
+        {
+            if(regval >> (i-1))
+            {
+                pPriArbit ->acl_pri_lev = i;
+                break;
+            }
+        }        
+    }
+
+    /*dscp based priority*/
+    rtl8306e_regbit_get(0, 26, 15, 3, &regval);
+    if (regval)
+    {
+        pPriArbit ->dscp_pri_lev = 5;
+    }
+    else
+    {
+        rtl8306e_reg_get(1, 21, 3, &regval);
+        regval &= (0xF << 8);
+        regval >>= 8;
+        for (i = 4; i > 0; i --)
+        {
+            if(regval >> (i-1))
+            {
+                pPriArbit ->dscp_pri_lev =  i;
+                break;
+            }
+        }                
+    }
+
+    /*1Q based priority*/
+    rtl8306e_regbit_get(0, 26, 14, 3, &regval);
+    if (regval)
+    {
+        pPriArbit ->dot1q_pri_lev = 5;
+    }
+    else
+    {
+        rtl8306e_reg_get(1, 21, 3, &regval);
+        regval &= (0xF << 4);
+        regval >>= 4;
+        for (i = 4; i > 0; i --)
+        {
+            if(regval >> (i-1))
+            {
+                pPriArbit ->dot1q_pri_lev = i;
+                break;
+            }
+        }                        
+    }
+
+    /*port based priority*/
+    rtl8306e_regbit_get(0, 26, 13, 3, &regval);
+    if (regval)
+    {
+        pPriArbit ->port_pri_lev = 5;
+    }
+    else 
+    {
+        rtl8306e_reg_get(1, 21, 3, &regval);
+        regval &= 0xF;
+
+        for (i = 4; i > 0; i --)
+        {
+            if(regval >> (i-1))
+            {
+                pPriArbit ->port_pri_lev = i;
+                break;
+            }
+        }                                
+    }
+        
+    return SUCCESS;
+}
+
+/* Function Name:
+ *      rtl8306e_qos_priSrcEnable_set
+ * Description:
+ *      enable/disable Qos priority source for ingress port
+ * Input:
+ *      port      -  Specify port number (0 ~5)
+ *      priSrc    -  Specify priority source  
+ *      enabled -   TRUE of FALSE  
+ * Output:
+ *      none
+ * Return:
+ *      SUCCESS
+ *      FAILED
+ * Note:
+ *     There are 4 kind of priority source for each port which could
+ *     be enabled ordisabled:
+ *          RTL8306_DSCP_PRIO     - DSCP-based priority
+ *          RTL8306_1QBP_PRIO     - 1Q-based priority
+ *          RTL8306_PBP_PRIO        - port-based priority
+ *          RTL8306_CPUTAG_PRIO  - cpu tag priority
+ */
+int32 rtl8306e_qos_priSrcEnable_set(uint32 port, uint32 priSrc, uint32 enabled) 
+{
+    uint32 duplex, speed, nway;
+      
+    if (port > RTL8306_PORT5)
+        return FAILED;
+
+    duplex = 0;
+    speed = 0;
+    nway = 0;
+    
+    /*save mac 4 or port status when operate reg.22*/    
+    if (4 == port) 
+    {
+        rtl8306e_regbit_get(5, 0, 13, 0, &speed);
+        rtl8306e_regbit_get(5, 0, 12, 0, &nway);
+        rtl8306e_regbit_get(5, 0, 8, 0, &duplex);            
+    } 
+    else if (5 == port) 
+    {
+        rtl8306e_regbit_get(6, 0, 13, 0, &speed);
+        rtl8306e_regbit_get(6, 0, 12, 0, &nway);
+        rtl8306e_regbit_get(6, 0, 8, 0, &duplex);            
+    }
+
+    /*Port 5 corresponding PHY6*/
+    if (RTL8306_PORT5 == port)  
+        port ++ ;  
+    
+    switch(priSrc) 
+    {
+        case RTL8306_DSCP_PRIO:
+            rtl8306e_regbit_set(port, 22, 9, 0, enabled ? 0:1);
+            break;
+        case RTL8306_1QBP_PRIO:
+            rtl8306e_regbit_set(port, 22, 10, 0, enabled ? 0:1);
+            break;
+        case RTL8306_PBP_PRIO:
+            rtl8306e_regbit_set(port, 22, 8, 0, enabled ? 0:1);
+            break;
+        case RTL8306_CPUTAG_PRIO:
+            rtl8306e_regbit_set(port, 17, 1, 2, enabled ? 1:0);
+            break;
+        default:
+            return FAILED;
+    }
+    
+    /*restore mac 4 or port status when operate reg.22*/    
+    if (4 == port) 
+    {
+        rtl8306e_regbit_set(5, 0, 13, 0, speed);
+        rtl8306e_regbit_set(5, 0, 12, 0, nway);
+        rtl8306e_regbit_set(5, 0, 8, 0, duplex);            
+    }
+    else if (6 == port) 
+    { 
+        /*for port++ when port 5*/
+        rtl8306e_regbit_set(6, 0, 13, 0, speed);
+        rtl8306e_regbit_set(6, 0, 12, 0, nway);
+        rtl8306e_regbit_set(6, 0, 8, 0, duplex);
+    }      
+    return SUCCESS;
+}
+
+
+/* Function Name:
+ *      rtl8306e_qos_priSrcEnable_set
+ * Description:
+ *      enable/disable Qos priority source for  ingress port
+ * Input:
+ *      port       -  Specify port number (0 ~5)
+ *      priSrc     -  Specify priority source  
+ * Output:
+ *      pEnabled -  the pointer of priority source status  
+ * Return:
+ *      SUCCESS
+ *      FAILED
+ * Note:
+ *     There are 4 kind of priority source for each port which could
+ *     be enabled ordisabled:
+ *          RTL8306_DSCP_PRIO     - DSCP-based priority
+ *          RTL8306_1QBP_PRIO     - 1Q-based priority
+ *          RTL8306_PBP_PRIO        - port-based priority
+ *          RTL8306_CPUTAG_PRIO  - cpu tag priority
+ */
+int32 rtl8306e_qos_priSrcEnable_get(uint32 port, uint32 priSrc, uint32 *pEnabled) 
+{
+    uint32 bitValue;
+
+    if ((port > RTL8306_PORT5) || (NULL == pEnabled))
+        return FAILED;
+    
+    /*Port 5 corresponding PHY6*/
+    if (port == RTL8306_PORT5 )  
+        port ++ ;  
+    
+    switch(priSrc)
+    {
+        case RTL8306_DSCP_PRIO:
+            rtl8306e_regbit_get(port, 22, 9, 0, &bitValue);
+            *pEnabled = (bitValue ? FALSE : TRUE);
+            break;
+        case RTL8306_1QBP_PRIO:
+            rtl8306e_regbit_get(port, 22, 10, 0, &bitValue);
+            *pEnabled = (bitValue ? FALSE : TRUE);
+            break;
+        case RTL8306_PBP_PRIO:
+            rtl8306e_regbit_get(port, 22, 8, 0, &bitValue);
+            *pEnabled = (bitValue ? FALSE : TRUE);
+            break;
+        case RTL8306_CPUTAG_PRIO:
+            rtl8306e_regbit_get(port, 17, 1, 2, &bitValue);
+            *pEnabled = (bitValue ? TRUE : FALSE);
+            break;
+        default:
+            return FAILED;
+    }
+
+    return SUCCESS;
+}
+
+
+/* Function Name:
+ *      rtl8306e_qos_ipAddrPri_set
+ * Description:
+ *      Set IP address priority
+ * Input:
+ *      priority  -  internal use 2-bit priority value (0~3)  
+ * Output:
+ *      none
+ * Return:
+ *      SUCCESS
+ *      FAILED
+ * Note:
+ */
+int32 rtl8306e_qos_ipAddrPri_set(uint32 priority) 
+{
+    uint32 regValue;
+
+    if (priority > 3)
+        return FAILED;
+    
+    rtl8306e_reg_get(2, 22, 3, &regValue);
+    rtl8306e_reg_set(2, 22, 3, (regValue & 0xFFFC) |priority);
+
+    return SUCCESS;
+}
+
+
+/* Function Name:
+ *      rtl8306e_qos_ipAddrPri_get
+ * Description:
+ *      Get IP address priority
+ * Input:
+ *      priority  -  internal use 2-bit priority value (0~3)  
+ * Output:
+ *      none
+ * Return:
+ *      SUCCESS
+ *      FAILED
+ * Note:
+ */
+int32 rtl8306e_qos_ipAddrPri_get(uint32 *priority)
+{
+    uint32 regValue;
+
+    if (priority == NULL)
+        return FAILED;
+    
+    rtl8306e_reg_get(2, 22, 3, &regValue);
+    *priority =  regValue & 0x3;
+
+    return SUCCESS;
+}
+
+
+/* Function Name:
+ *      rtl8306e_qos_ipAddr_set
+ * Description:
+ *      Set IP address
+ * Input:
+ *      entry        -   specify entry
+         ip            -   ip address
+         mask        -  ip mask
+         enabled    -   enable the entry
+ * Output:
+ *      none
+ * Return:
+ *      SUCCESS
+ *      FAILED
+ * Note:
+ *      There are two entries RTL8306_IPADD_A and RTL8306_IPADD_B
+ *      for user setting ip address, if ip address of packet matches
+ *      the entry, the packet will be assign the priority of ip address
+ *      priority which is configured by rtl8306e_qos_ipAddrPri_set.
+ */
+int32 rtl8306e_qos_ipAddr_set(uint32 entry, uint32 ip, uint32 mask, uint32 enabled) 
+{
+    uint32 regValue;
+
+    if (entry > 1) 
+        return FAILED;
+
+    switch(entry) 
+    {
+        case RTL8306_IPADD_A:        
+            if (enabled == TRUE) 
+            {
+                rtl8306e_regbit_set(0, 17, 14, 0, 1);
+                regValue = ip & 0xFFFF;
+                rtl8306e_reg_set(1, 17, 0, regValue);
+                regValue = (ip & 0xFFFF0000) >> 16;
+                rtl8306e_reg_set(1, 16, 0, regValue);
+                regValue = mask & 0xFFFF;
+                rtl8306e_reg_set(2, 17, 0, regValue);
+                regValue = (mask & 0xFFFF0000) >> 16;
+                rtl8306e_reg_set(2, 16, 0, regValue);
+            }    
+            else 
+                rtl8306e_regbit_set(0, 17, 14, 0, 0);
+            break;
+        case RTL8306_IPADD_B:        
+            if (enabled == TRUE)
+            {
+                rtl8306e_regbit_set(0, 17, 6, 0, 1);
+                regValue = ip & 0xFFFF;
+                rtl8306e_reg_set(1, 19, 0, regValue);
+                regValue = (ip & 0xFFFF0000) >> 16;
+                rtl8306e_reg_set(1, 18, 0, regValue);
+                regValue = mask & 0xFFFF;
+                rtl8306e_reg_set(2, 19, 0, regValue);
+                regValue = (mask & 0xFFFF0000) >> 16;
+                rtl8306e_reg_set(2, 18, 0, regValue);
+            }
+            else 
+                rtl8306e_regbit_set(0, 17, 6, 0, 0);        
+            break;
+        default:
+            return FAILED;
+    }
+
+    return SUCCESS;
+}
+
+
+/* Function Name:
+ *      rtl8306e_qos_ipAddr_get
+ * Description:
+ *      Get IP address user seting
+ * Input:
+ *      entry       -   specify entry
+ * Output:
+ *      pIp            -   ip address
+         pMask        -   ip mask
+         pEnabled    -  enabled or disabled the entry for IP Priority
+ * Return:
+ *      SUCCESS
+ *      FAILED
+ * Note:
+ */
+int32 rtl8306e_qos_ipAddr_get(uint32 entry, uint32 *pIp, uint32 *pMask , uint32 *pEnabled) 
+{
+    uint32 hi, lo;
+    uint32 bitValue;
+
+    if ((entry > 1) || (pIp == NULL) || (pMask == NULL) || (pEnabled == NULL))
+        return FAILED;
+    
+    switch (entry) 
+    {
+        case RTL8306_IPADD_A :
+            rtl8306e_reg_get(1, 17, 0, &lo);
+            rtl8306e_reg_get(1, 16, 0, &hi);
+            *pIp = lo + (hi << 16);
+            rtl8306e_reg_get(2, 17, 0, &lo);
+            rtl8306e_reg_get(2, 16, 0, &hi);
+            *pMask = lo + (hi << 16);
+            rtl8306e_regbit_get(0, 17, 14, 0, &bitValue);
+            *pEnabled = (bitValue == 1 ? TRUE : FALSE);
+            break;
+        case RTL8306_IPADD_B :
+            rtl8306e_reg_get(1, 19, 0, &lo);
+            rtl8306e_reg_get(1, 18, 0, &hi);
+            *pIp = lo + (hi << 16);
+            rtl8306e_reg_get(2, 19, 0, &lo);
+            rtl8306e_reg_get(2, 18, 0, &hi);
+            *pMask = lo + (hi << 16); 
+            rtl8306e_regbit_get(0, 17, 6, 0, &bitValue);
+            *pEnabled = (bitValue == 1 ? TRUE : FALSE);
+
+            break;
+        default :
+            return FAILED;
+    }
+
+    
+    return SUCCESS;
+}
+
+
+/* Function Name:
+ *      rtl8306e_qos_schedulingPara_set
+ * Description:
+ *      Set qos scheduling parameter
+ * Input:
+ *      set          -  RTL8306_QOS_SET0 or RTL8306_QOS_SET1
+ *      sch_para  -  The structure describe schedule parameter
+ * Output:
+ *      none
+ * Return:
+ *      SUCCESS
+ *      FAILED
+ * Note:
+ *      switch supports 4 queue per egress port, scheduling algorithm could be WRR(Weight Round Robin) or 
+ *      SP(Strict Priority). Only high queue Q3 and Q2 could be set as strict priority queue. There two set of 
+ *      scheduling parameter in whole system(RTL8306_QOS_SET0/RTL8306_QOS_SET1), each egress port select
+ *      one of them. The parameter defined by rtl8306e_qosSchPara_t, q0_wt and q1_wt should between 1~127,
+ *      that means Q0 and Q1 WRR weight, q2_wt and  q3_wt could be 0~127, 0 means strict priority. q2_n64Kbps 
+ *      and q3_n64Kbps means Q2/Q3 queue bandwidth control, unit is 64Kbps.
+ */
+int32 rtl8306e_qos_schedulingPara_set(uint32 set, rtl8306e_qosSchPara_t sch_para)
+{
+    uint32 regValue;
+    if ((sch_para.q0_wt > 127) || (sch_para.q1_wt > 127) || (sch_para.q2_wt > 127) ||
+         (sch_para.q3_wt > 127) || (0 == sch_para.q0_wt ) || (0 == sch_para.q1_wt)  ||
+         (sch_para.q2_n64Kbps > 0x7FF) || (sch_para.q3_n64Kbps > 0x7FF))
+         return FAILED;
+
+    switch(set)
+    {
+        case RTL8306_QOS_SET0:   
+            rtl8306e_reg_get(5, 20, 3, &regValue);
+            regValue &= ~0x7F;
+            regValue &= ~(0x7F << 8); 
+            regValue |= (sch_para.q0_wt | (sch_para.q1_wt << 8));
+            rtl8306e_reg_set(5, 20, 3, regValue);
+
+            regValue = 0;
+            regValue |=  (!sch_para.q3_wt) ? (1 << 15) :0;
+            regValue |= (sch_para.q3_wt << 8);
+            regValue |= (!sch_para.q2_wt) ? (1 << 7):0;
+            regValue |= sch_para.q2_wt;
+            rtl8306e_reg_set(5, 21, 3, regValue);
+            
+            rtl8306e_reg_get(5, 18, 3, &regValue);
+            regValue &= ~0x7FF;
+            regValue |= sch_para.q2_n64Kbps;
+            rtl8306e_reg_set(5, 18, 3, regValue);
+            
+            rtl8306e_reg_get(5, 19, 3, &regValue);
+            regValue &= ~0x7FF;
+            regValue |= sch_para.q3_n64Kbps;
+            rtl8306e_reg_set(5, 19, 3, regValue);                        
+            break;
+
+        case RTL8306_QOS_SET1:
+            rtl8306e_reg_get(5, 25, 3, &regValue);
+            regValue &= ~0x7F;
+            regValue &= ~(0x7F << 8); 
+            regValue |= (sch_para.q0_wt | (sch_para.q1_wt << 8));
+            rtl8306e_reg_set(5, 25, 3, regValue);
+
+            regValue = 0;
+            regValue |=  (!sch_para.q3_wt) ? (1 << 15) :0;
+            regValue |= (sch_para.q3_wt << 8);
+            regValue |= (!sch_para.q2_wt) ? (1 << 7):0;
+            regValue |= sch_para.q2_wt;
+            rtl8306e_reg_set(5, 26, 3, regValue);
+
+            rtl8306e_reg_get(5, 23, 3, &regValue);
+            regValue &= ~0x7FF;
+            regValue |= sch_para.q2_n64Kbps;
+            rtl8306e_reg_set(5, 23, 3, regValue);
+
+            rtl8306e_reg_get(5, 24, 3, &regValue);
+            regValue &= ~0x7FF;
+            regValue |= sch_para.q3_n64Kbps;
+            rtl8306e_reg_set(5, 24, 3, regValue);                                                                       
+            break;
+
+         default:
+            return FAILED;
+    }
+                    
+    return SUCCESS;
+}
+
+/* Function Name:
+ *      rtl8306e_qos_schedulingPara_get
+ * Description:
+ *      Set qos scheduling parameter
+ * Input:
+ *      set           -  RTL8306_QOS_SET0 or RTL8306_QOS_SET1
+ * Output:
+ *      pSch_para  - the pointer of schedule parameter
+ * Return:
+ *      SUCCESS
+ *      FAILED
+ * Note:
+ *      switch supports 4 queue per egress port, scheduling algorithm could be WRR(Weight Round Robin) or 
+ *      SP(Strict Priority). Only high queue Q3 and Q3 could be set as strict priority queue. There two set of 
+ *      scheduling parameter in whole system(RTL8306_QOS_SET0/RTL8306_QOS_SET1), each egress port select
+ *      one of them. The parameter defined by rtl8306e_qosSchPara_t, q0_wt and q1_wt should between 1~127,
+ *      that means Q0 and Q1 WRR weight, q2_wt and  q3_wt could be 0~127, 0 means strict priority. q2_n64Kbps 
+ *      and q3_n64Kbps means Q2/Q3 queue bandwidth control, unit is 64Kbps.
+ */
+int32 rtl8306e_qos_schedulingPara_get(uint32 set, rtl8306e_qosSchPara_t *pSch_para)
+{
+    uint32 regValue;
+    
+    if (NULL == pSch_para)
+        return FAILED;
+
+    switch(set)
+    {
+        case RTL8306_QOS_SET0:
+            rtl8306e_reg_get(5, 20, 3, &regValue);            
+            pSch_para->q0_wt = regValue & 0x7F;
+            pSch_para->q1_wt = (regValue & (0x7F << 8)) >> 8;
+
+            rtl8306e_reg_get(5, 21, 3, &regValue);
+            pSch_para->q2_wt = regValue & 0x7F;
+            pSch_para->q3_wt = (regValue & (0x7F << 8)) >> 8;
+            if (regValue & (1 << 7))
+            {
+                pSch_para->q2_wt = 0;
+            }
+            
+            if (regValue & (1 << 15))
+            {
+                pSch_para->q3_wt = 0;
+            }
+
+            rtl8306e_reg_get(5, 18, 3, &regValue);
+            pSch_para->q2_n64Kbps = regValue & 0x7FF;
+            rtl8306e_reg_get(5, 19, 3, &regValue);
+            pSch_para->q3_n64Kbps = regValue & 0x7FF;
+                        
+            break;
+            
+        case RTL8306_QOS_SET1:
+            rtl8306e_reg_get(5, 25, 3, &regValue);            
+            pSch_para->q0_wt = regValue & 0x7F;
+            pSch_para->q1_wt = (regValue & (0x7F << 8)) >> 8;
+            
+            rtl8306e_reg_get(5, 26, 3, &regValue);
+            pSch_para->q2_wt = regValue & 0x7F;
+            pSch_para->q3_wt = (regValue & (0x7F << 8)) >> 8;
+
+            if (regValue & (1 << 7))
+            {
+                pSch_para->q2_wt = 0;
+            }
+            
+            if (regValue & (1 << 15))
+            {
+                pSch_para->q3_wt = 0;
+            }
+            
+            rtl8306e_reg_get(5, 23, 3, &regValue);
+            pSch_para->q2_n64Kbps = regValue & 0x7FF;
+            rtl8306e_reg_get(5, 24, 3, &regValue);
+            pSch_para->q3_n64Kbps = regValue & 0x7FF;            
+            
+            break;
+        default:
+            return FAILED;
+    }
+    
+    return SUCCESS;
+}
+
+/* Function Name:
+ *      rtl8306e_qos_portSchedulingMode_set
+ * Description:
+ *      Select port schedule algorithm  from two sets.
+ * Input:
+ *      port    -   port number (0 ~ 5)
+ *      set     -   RTL8306_QOS_SET0 or RTL8306_QOS_SET1
+ *      lbmsk  -   Queue mask for enable queue leaky buckt
+ * Output:
+ *      none
+ * Return:
+ *      SUCCESS
+ *      FAILED
+ * Note:
+ *      There are two sets configuration for schedule mode including strict priority 
+ *      enable/disable, queue weight and queue leaky bucket, every port could select
+ *      one of them. Queue leaky bucket of each port could be enable separately, so 
+ *      you can set queue mask to enable/disable them, because only queue 3 and queue 2
+ *      have leaky bucket, only bit 3 and bit 2 of quemask have effect, bit 3 represents
+ *      queue 3 and set 1 to enable it.
+ */
+int32 rtl8306e_qos_portSchedulingMode_set(uint32 port, uint32 set, uint32 lbmsk)
+{
+    uint32 regValue;
+    
+    if ((port > RTL8306_PORT5) ||(set > 1))
+        return FAILED;
+    
+    /*Port 5 corresponding PHY6*/
+    if (RTL8306_PORT5 == port)  
+        port ++ ; 
+    
+    lbmsk = ((lbmsk & 0x8) >> 3 ) | ((lbmsk & 0x4) >> 1);
+    rtl8306e_reg_get(port, 18, 2, &regValue);
+    regValue = (regValue & 0x97FF) | (lbmsk << 13) | (set & 0x1) << 11;
+    rtl8306e_reg_set(port, 18, 2, regValue);
+    return SUCCESS;
+}
+
+/* Function Name:
+ *      rtl8306e_qos_portSchedulingMode_get
+ * Description:
+ *      Get which set of schedule algorithm  for the specified port 
+ * Input:
+ *      port    -   port number (0 ~ 5)
+ *      set     -   RTL8306_QOS_SET0 or RTL8306_QOS_SET1
+ *      lbmsk  -   Queue mask for enable queue leaky buckt
+ * Output:
+ *      none
+ * Return:
+ *      SUCCESS
+ *      FAILED
+ * Note:
+ *      There are two sets configuration for schedule mode including strict priority 
+ *      enable/disable, queue weight and queue leaky bucket, every port could select
+ *      one of them. Queue leaky bucket of each port could be enable separately, so 
+ *      you can set queue mask to enable/disable them, because only queue 3 and queue 2
+ *      have leaky bucket, only bit 3 and bit 2 of quemask have effect, bit 3 represents
+ *      queue 3 and set 1 to enable it.
+ */
+int32 rtl8306e_qos_portSchedulingMode_get(uint32 port, uint32 *pSet, uint32 *pLbmsk) 
+{
+    uint32 regValue;
+
+    if ((port > RTL8306_PORT5) ||(NULL == pSet) || (NULL == pLbmsk))
+        return FAILED;
+
+    /*Port 5 corresponding PHY6*/
+    if (RTL8306_PORT5 == port)  
+        port ++ ;  
+
+    rtl8306e_reg_get(port, 18, 2, &regValue );
+    *pSet = (regValue >> 11) & 0x1;
+    *pLbmsk = (regValue >> 13) & 0x3;
+    *pLbmsk = ((*pLbmsk & 0x1) << 3) | ((*pLbmsk & 0x2) << 1);
+    
+    return SUCCESS;
+}
+
+
+int32 rtl8306e_qos_queFlcThr_set(uint32 queue, uint32 type, uint32 onoff, uint32 set, uint32 value)
+{
+    uint32 regValue, mask;
+    uint32 selection;
+    uint32 reg, shift;
+
+    if ((queue > RTL8306_QUEUE3) || (type > RTL8306_FCO_QLEN) ||
+        (onoff > RTL8306_FCON) || (set > RTL8306_FCO_SET1) || (value > 127))
+        return FAILED;
+    
+    selection = (set << 2) | (onoff <<1) |type;
+    value &= 0x7f;
+    switch (selection) 
+    {
+        case 0 :  /*set 0, turn off, DSC*/
+            if (RTL8306_QUEUE0 == queue)
+            {
+                reg = 17;
+                mask = 0xFFF0;
+                shift = 0;
+            } 
+            else if (RTL8306_QUEUE1 == queue) 
+            {
+                reg = 17;
+                mask = 0xF0FF;
+                shift = 8;
+            } 
+            else if (RTL8306_QUEUE2 == queue) 
+            {
+                reg = 20;
+                mask = 0xFFF0;
+                shift = 0;
+            } 
+            else 
+            {
+                reg = 20;
+                mask = 0xF0FF;
+                shift = 8;
+            }
+            rtl8306e_reg_get(5, reg, 2, &regValue);
+            regValue = (regValue & mask) | ((value & 0xf)  << shift);
+            rtl8306e_reg_set(5, reg, 2, regValue);
+        
+             /*flc bit[6:4]*/
+            if (RTL8306_QUEUE0 == queue) 
+            {
+                rtl8306e_reg_get(1, 26, 3, &regValue);  
+                regValue &= 0xfff8;
+                regValue |= (value & 0x70) >> 4;
+                rtl8306e_reg_set(1, 26, 3, regValue);                
+            } 
+            else if (RTL8306_QUEUE1 == queue) 
+            {
+                rtl8306e_reg_get(1, 26, 3, &regValue);  
+                regValue &= 0xfe3f;
+                regValue |= ((value & 0x70) >> 4) << 6;
+                rtl8306e_reg_set(1, 26, 3, regValue);
+            }
+            else if (RTL8306_QUEUE2 == queue) 
+            {
+                rtl8306e_reg_get(1, 26, 3, &regValue);  
+                regValue &= 0x8fff;
+                regValue |=   ((value & 0x70) >> 4) << 12;
+                rtl8306e_reg_set(1, 26, 3, regValue);                
+            } 
+            else  
+            {
+                rtl8306e_reg_get(1, 27, 3, &regValue);  
+                regValue &= 0xffe3;
+                regValue |=   ((value & 0x70) >> 4) << 2;
+                rtl8306e_reg_set(1, 27, 3, regValue);
+            }             
+            break;
+        
+        case 1 :     /*set 0, turn off, QLEN*/
+            if (RTL8306_QUEUE0 == queue) 
+            {
+                reg = 17;
+                mask = 0xFF0F;
+                shift = 4;
+            } 
+            else if (RTL8306_QUEUE1 == queue) 
+            {
+                reg = 17;
+                mask = 0x0FFF;
+                shift = 12;
+            } 
+            else if (RTL8306_QUEUE2 == queue) 
+            {
+                reg = 20;
+                mask = 0xFF0F;
+                shift = 4;
+            } 
+            else  
+            {
+                reg = 20;
+                mask = 0x0FFF;
+                shift = 12;
+            }
+            rtl8306e_reg_get(5, reg, 2, &regValue);
+            regValue = (regValue & mask) | ((value & 0xf) << shift);
+            rtl8306e_reg_set(5, reg, 2, regValue);
+
+            /*bit[6:4]*/
+            if (RTL8306_QUEUE0 == queue) 
+            {
+                rtl8306e_reg_get(1, 26, 3, &regValue);  
+                regValue &= 0xffc7;
+                regValue |= ((value & 0x70) >> 4) << 3;
+                rtl8306e_reg_set(1, 26, 3, regValue);                                   
+             } 
+             else if (RTL8306_QUEUE1 == queue) 
+             {
+                rtl8306e_reg_get(1, 26, 3, &regValue);  
+                regValue &= 0xf1ff;
+                regValue |= ((value & 0x70) >> 4) << 9;
+                rtl8306e_reg_set(1, 26, 3, regValue);                                                   
+             }
+             else if (RTL8306_QUEUE2 == queue) 
+             {
+                /*bit[4]*/
+                rtl8306e_reg_get(1, 26, 3, &regValue);                  
+                regValue &= 0x7fff;
+                regValue |= (((value & 0x10) >> 4) << 15);
+                rtl8306e_reg_set(1, 26, 3, regValue);   
+
+                /*bit[6:5]*/
+                rtl8306e_reg_get(1, 27, 3, &regValue);         
+                regValue &= 0xfffc;
+                regValue |= ((value & 0x60) >> 5) ;
+                rtl8306e_reg_set(1, 27, 3, regValue);
+             } 
+             else  
+             {
+                 rtl8306e_reg_get(1, 27, 3, &regValue);       
+                 regValue &= 0xff1f;
+                 regValue |= ((value & 0x70) >> 4) << 5;
+                 rtl8306e_reg_set(1, 27, 3, regValue);
+             }             
+                     
+             break;
+        case 2 :    /*set 0, turn on, DSC*/
+            if (RTL8306_QUEUE0 == queue) 
+                reg = 18;
+            else if (RTL8306_QUEUE1 == queue) 
+                reg = 19;
+            else if (RTL8306_QUEUE2 == queue)
+                reg = 21;
+            else  
+                reg = 22;
+            rtl8306e_reg_get(5, reg, 2, &regValue);
+            regValue = (regValue & 0xFFC0) | (value & 0x3f);
+            rtl8306e_reg_set(5, reg, 2, regValue);
+
+             /*bit[6]*/
+            if (RTL8306_QUEUE0 == queue) 
+            {
+                rtl8306e_regbit_set(5, 21, 7, 2, (value & 0x40) ? 1:0);            
+            }      
+            else if (RTL8306_QUEUE1 == queue) 
+            {
+                rtl8306e_regbit_set(5, 21, 15, 2, (value & 0x40) ? 1:0);            
+            }
+            else if (RTL8306_QUEUE2 == queue)
+            {
+                rtl8306e_regbit_set(5, 24, 7, 2, (value & 0x40) ? 1:0);                        
+            }
+            else 
+            {
+                rtl8306e_regbit_set(5, 24, 15, 2, (value & 0x40) ? 1:0);                        
+            }            
+            break;
+            
+        case 3:   /*set 0, turn  on, QLEN*/
+            if (RTL8306_QUEUE0 == queue) 
+                reg = 18;
+            else if (RTL8306_QUEUE1 == queue) 
+                reg = 19;
+            else if (RTL8306_QUEUE2 == queue) 
+                reg = 21;
+            else  
+                reg = 22;
+            if (queue != RTL8306_QUEUE3)  
+            {
+                rtl8306e_reg_get(5, reg, 2, &regValue);
+                regValue = (regValue & 0xC0FF) | ((value & 0x3f) << 8);
+                rtl8306e_reg_set(5, reg, 2, regValue);
+            }  
+            else 
+            {
+                rtl8306e_reg_get(5, reg, 2, &regValue);
+                regValue = (regValue & 0x3FF) | ((value & 0x3f) << 10);
+                rtl8306e_reg_set(5, reg, 2, regValue);
+            }
+        
+             /*bit[6]*/
+            if (RTL8306_QUEUE0 == queue) 
+            {
+                rtl8306e_regbit_set(5, 21, 6, 2, (value & 0x40) ? 1:0);    
+            }      
+            else if (RTL8306_QUEUE1 == queue) 
+            {
+                rtl8306e_regbit_set(5, 21, 14, 2, (value & 0x40) ? 1:0);                      
+            }
+            else if (RTL8306_QUEUE2 == queue)
+            {
+                rtl8306e_regbit_set(5, 24, 6, 2, (value & 0x40) ? 1:0);                        
+            }
+            else 
+            {
+                rtl8306e_regbit_set(5, 24, 14, 2, (value & 0x40) ? 1:0);                        
+            }                   
+            break;
+        
+        case 4:     /*set 1, turn off, DSC*/
+            if (RTL8306_QUEUE0 == queue) 
+            {
+                reg = 23;
+                mask = 0xFFF0;
+                shift =0;
+            } 
+            else if (RTL8306_QUEUE1 == queue) 
+            {
+                reg = 23;
+                mask = 0xF0FF;
+                shift =8;
+            } 
+            else if (RTL8306_QUEUE2 == queue)
+            {
+                reg = 26;
+                mask = 0xFFF0;
+                shift =0;
+            }
+            else 
+            {
+                reg = 26;
+                mask = 0xF0FF;
+                shift =8;
+            }
+            rtl8306e_reg_get(5, reg, 2, &regValue);
+            regValue = (regValue & mask) | ((value & 0xf) << shift);
+            rtl8306e_reg_set(5, reg, 2, regValue);
+
+            /*flc bit[6:4]*/
+            if (RTL8306_QUEUE0 == queue) 
+            {
+                rtl8306e_reg_get(1, 27, 3, &regValue);  
+                regValue &= 0xf8ff;
+                regValue |= ((value & 0x70) >> 4) << 8;
+                rtl8306e_reg_set(1, 27, 3, regValue);                
+             } 
+             else if (RTL8306_QUEUE1 == queue) 
+             {                
+                rtl8306e_reg_get(1, 27, 3, &regValue);  
+                regValue &= 0x3fff;
+                regValue |= ((value & 0x30) >> 4) << 14;
+                rtl8306e_reg_set(1, 27, 3, regValue);           
+                rtl8306e_regbit_set(1, 28, 0, 3, (value & 0x40) ? 1:0);
+                    
+             }
+             else if (RTL8306_QUEUE2 == queue) 
+             {
+                rtl8306e_reg_get(1, 28, 3, &regValue);
+                regValue &= 0xff8f;
+                regValue |= ((value & 0x70) >> 4) << 4;
+                rtl8306e_reg_set(1, 28, 3, regValue);
+             } 
+             else  
+             {
+                rtl8306e_reg_get(1, 28, 3, &regValue);
+                regValue &= 0xe3ff;
+                regValue |= ((value & 0x70) >> 4) << 10;
+                rtl8306e_reg_set(1, 28, 3, regValue);                
+             }                        
+            break;
+        
+        case 5:     /*set 1, turn off, QLEN*/
+            if (RTL8306_QUEUE0 == queue) 
+            {
+                reg = 23;
+                mask = 0xFF0F;
+                shift = 4;
+            } 
+            else if (RTL8306_QUEUE1 == queue) 
+            {
+                reg = 23;
+                mask = 0x0FFF;
+                shift = 12;
+            } 
+            else if (RTL8306_QUEUE2 == queue) 
+            {
+                reg = 26;
+                mask = 0xFF0F;
+                shift = 4;
+            } 
+            else 
+            {
+                reg = 26;
+                mask = 0x0FFF;
+                shift = 12;
+            }
+            rtl8306e_reg_get(5, reg, 2, &regValue);
+            regValue = (regValue & mask) | ((value & 0xf) << shift);
+            rtl8306e_reg_set(5, reg, 2, regValue);
+
+             /*bit[6:4]*/
+            if (RTL8306_QUEUE0 == queue) 
+            {
+                rtl8306e_reg_get(1, 27, 3, &regValue);  
+                regValue &= 0xc7ff;
+                regValue |= ((value & 0x70) >> 4) << 11;
+                rtl8306e_reg_set(1, 27, 3, regValue);
+            } 
+            else if (RTL8306_QUEUE1 == queue) 
+            {
+                rtl8306e_reg_get(1, 28, 3, &regValue);  
+                regValue &= 0xfff1;
+                regValue |= ((value & 0x70) >> 4) << 1;
+                rtl8306e_reg_set(1, 28, 3, regValue);                                
+            }
+            else if (RTL8306_QUEUE2 == queue) 
+            {
+                rtl8306e_reg_get(1, 28, 3, &regValue);  
+                regValue &= 0xfc7f;
+                regValue |= ((value & 0x70) >> 4) << 7;
+                rtl8306e_reg_set(1, 28, 3, regValue);                                
+            } 
+            else  
+            {
+                rtl8306e_reg_get(1, 28, 3, &regValue);
+                regValue &= 0x1fff;
+                regValue |= ((value & 0x70) >> 4) << 13;
+                rtl8306e_reg_set(1, 28, 3, regValue);                                                
+            }                                 
+            break;
+        
+        case 6:    /*set 1, turn on, DSC*/
+            if (RTL8306_QUEUE0 == queue) 
+                reg = 24;
+            else if  (RTL8306_QUEUE1 == queue) 
+                reg =25;
+            else if (RTL8306_QUEUE2 == queue) 
+                reg = 27;
+            else  
+                reg = 28;
+            rtl8306e_reg_get(5, reg, 2, &regValue);
+            regValue = (regValue & 0xFFC0) | (value & 0x3f);
+            rtl8306e_reg_set(5, reg, 2, regValue);
+
+             /*bit[6]*/
+            if (RTL8306_QUEUE0 == queue) 
+            {
+                rtl8306e_regbit_set(5, 25, 7, 2, (value & 0x40) ? 1:0);            
+            }      
+            else if(RTL8306_QUEUE1 == queue) 
+            {
+                rtl8306e_regbit_set(5, 25, 15, 2, (value & 0x40) ? 1:0);            
+            }
+            else if(RTL8306_QUEUE2 == queue)
+            {
+                rtl8306e_regbit_set(5, 27, 7, 2, (value & 0x40) ? 1:0);            
+            }
+            else 
+            {
+                rtl8306e_regbit_set(5, 27, 15, 2, (value & 0x40) ? 1:0);            
+            }              
+            break;
+        
+        case 7:     /*set 1, turn  on, QLEN*/
+            if (RTL8306_QUEUE0 == queue) 
+                reg = 24;
+            else if (RTL8306_QUEUE1 == queue) 
+                reg =25;
+            else if (RTL8306_QUEUE2 == queue) 
+                reg = 27;
+            else  
+                reg = 28;
+            if (queue != RTL8306_QUEUE3)  
+            {
+                rtl8306e_reg_get(5, reg, 2, &regValue);
+                regValue = (regValue & 0xC0FF) | ((value & 0x3f) << 8);
+                rtl8306e_reg_set(5, reg, 2, regValue);
+            } 
+            else 
+            {
+                rtl8306e_reg_get(5, reg, 2, &regValue);
+                regValue = (regValue & 0x3FF) | ((value & 0x3f) << 10);
+                rtl8306e_reg_set(5, reg, 2, regValue);
+            }
+
+            /*bit[6]*/
+            if (RTL8306_QUEUE0 == queue) 
+            {
+                rtl8306e_regbit_set(5, 25, 6, 2, (value & 0x40) ? 1:0);            
+            }      
+            else if(RTL8306_QUEUE1 == queue) 
+            {
+                rtl8306e_regbit_set(5, 25, 14, 2, (value & 0x40) ? 1:0);            
+            } 
+            else if (RTL8306_QUEUE2 == queue)
+            {
+                rtl8306e_regbit_set(5, 27, 6, 2, (value & 0x40) ? 1:0);                        
+            } 
+            else 
+            {
+                rtl8306e_regbit_set(5, 27, 14, 2, (value & 0x40) ? 1:0);                        
+            }              
+            break;
+            
+        default:
+            return FAILED;
+       }
+
+    return SUCCESS;
+}
+
+int32 rtl8306e_qos_queFlcThr_get(uint32 queue, uint32 type, uint32 onoff, uint32 set, uint32* pValue) 
+{
+    uint32 regValue, mask;
+    uint32 selection;
+    uint32 reg, shift = 0;
+    
+    if ((queue > RTL8306_QUEUE3) || (type > RTL8306_FCO_QLEN) || (onoff > RTL8306_FCON) ||
+        (set > RTL8306_FCO_SET1) || (NULL == pValue))
+        return FAILED;
+    
+    selection = (set << 2) | (onoff <<1) |type;
+    *pValue = 0;
+    switch (selection) 
+    {
+        case 0 :    /*set 0, turn off, DSC*/
+            if (RTL8306_QUEUE0 == queue) 
+            {
+                reg = 17;
+                mask = 0xF;
+                shift = 0;
+            } 
+            else if (RTL8306_QUEUE1 == queue) 
+            {
+                reg = 17;
+                mask = 0x0F00;
+                shift = 8;
+            }
+            else if (RTL8306_QUEUE2 == queue) 
+            {
+                reg = 20;
+                mask = 0xF;
+                shift = 0;
+            } else 
+            {
+                reg = 20;
+                mask = 0x0F00;
+                shift = 8;
+            }
+            rtl8306e_reg_get(5, reg, 2, &regValue);
+            *pValue = (regValue & mask) >> shift;
+
+            if (RTL8306_QUEUE0 == queue) 
+            {
+                rtl8306e_reg_get(1, 26, 3, &regValue);
+                regValue &= 0x7;
+                *pValue |= (regValue << 4);                    
+             } 
+            else if (RTL8306_QUEUE1 == queue) 
+            {
+                rtl8306e_reg_get(1, 26, 3, &regValue);
+                regValue &= 0x1c0;
+                regValue = regValue >> 6;
+                *pValue |= (regValue << 4);                     
+            } 
+            else if (RTL8306_QUEUE2 == queue) 
+            {
+                rtl8306e_reg_get(1, 26, 3, &regValue);
+                regValue &= 0x7000;
+                regValue = regValue >> 12;
+                *pValue |= (regValue << 4);                                
+            } 
+            else  
+            {
+                rtl8306e_reg_get(1, 27, 3, &regValue);
+                regValue &= 0x1c;
+                regValue = regValue >> 2;
+                *pValue |= (regValue << 4);                                                  
+            }                     
+            break;
+        
+        case 1 :    /*set 0, turn off, QLEN*/
+            if (RTL8306_QUEUE0 == queue) 
+            {
+                reg = 17;
+                mask = 0x00F0;
+                shift = 4;
+            } 
+            else if (RTL8306_QUEUE1 == queue) 
+            {
+                reg = 17;
+                mask = 0xF000;
+                shift = 12;
+            } 
+            else if (RTL8306_QUEUE2 == queue) 
+            {
+                reg = 20;
+                mask = 0x00F0;
+                shift = 4;
+            }
+            else  
+            {
+                reg = 20;
+                mask = 0xF000;
+                shift = 12;
+            }
+            rtl8306e_reg_get(5, reg, 2, &regValue);
+            *pValue = (regValue & mask) >> shift;
+
+            if (RTL8306_QUEUE0 == queue) 
+            {
+                rtl8306e_reg_get(1, 26, 3, &regValue);
+                regValue &= 0x38;
+                regValue = regValue >> 3;
+                *pValue |= (regValue << 4);                                                                           
+             } 
+            else if (RTL8306_QUEUE1 == queue) 
+            {
+                rtl8306e_reg_get(1, 26, 3, &regValue);
+                regValue &= 0xe00;
+                regValue = regValue >> 9;
+                *pValue |= (regValue << 4);                                                                                               
+            }
+            else if (RTL8306_QUEUE2 == queue)
+            {
+                rtl8306e_reg_get(1, 26, 3, &regValue);
+                regValue &= 0x8000;
+                regValue = regValue >> 15;
+                *pValue |= (regValue << 4);                                                                                               
+                  
+                rtl8306e_reg_get(1, 27, 3, &regValue);
+                regValue &= 0x3;
+                *pValue |= (regValue << 5);                                                                                                       
+            } 
+            else  
+            {
+                rtl8306e_reg_get(1, 27, 3, &regValue);
+                regValue &= 0xe0;
+                regValue = regValue >> 5;
+                *pValue |= (regValue << 4);  
+            }
+        
+        break;
+        
+        case 2 :    /*set 0, turn on, DSC*/
+            if (RTL8306_QUEUE0 == queue) 
+                reg = 18;
+            else if (RTL8306_QUEUE1 == queue) 
+                reg = 19;
+            else if (RTL8306_QUEUE2 == queue)
+                reg = 21;
+            else  
+                reg = 22;
+            rtl8306e_reg_get(5, reg, 2, &regValue);
+            *pValue = regValue & 0x3F;
+
+            if (RTL8306_QUEUE0 == queue) 
+            {
+                rtl8306e_regbit_get(5, 21, 7, 2, &regValue);
+                *pValue |= (regValue << 6);
+            }      
+            else if (RTL8306_QUEUE1 == queue) 
+            {
+                rtl8306e_regbit_get(5, 21, 15, 2, &regValue);
+                *pValue |= (regValue << 6);                
+            }      
+            else if (RTL8306_QUEUE2 == queue)
+            {
+                rtl8306e_regbit_get(5, 24, 7, 2, &regValue);
+                *pValue |= (regValue << 6);                             
+            }      
+            else  
+            {
+                rtl8306e_regbit_get(5, 24, 15, 2, &regValue);
+                *pValue |= (regValue << 6);                             
+            }              
+            break;
+            
+    case 3:   /*set 0, turn  on, QLEN*/
+        if (RTL8306_QUEUE0 == queue) 
+            reg = 18;
+        else if  (RTL8306_QUEUE1 == queue) 
+            reg = 19;
+        else if (RTL8306_QUEUE2 == queue) 
+            reg = 21;
+        else  
+            reg = 22;
+        if (queue != RTL8306_QUEUE3) 
+        {
+            rtl8306e_reg_get(5, reg, 2, &regValue);
+            *pValue = (regValue & 0x3F00) >> 8 ;
+        } else 
+        {
+            rtl8306e_reg_get(5, reg, 2, &regValue);
+            *pValue = (regValue & 0xFC00) >> 10;
+        }
+
+        if (RTL8306_QUEUE0 == queue) 
+        {
+            rtl8306e_regbit_get(5, 21, 6, 2, &regValue);
+            *pValue |= (regValue << 6);
+        }      
+        else if (RTL8306_QUEUE1 == queue) 
+        {
+            rtl8306e_regbit_get(5, 21, 14, 2, &regValue);
+            *pValue |= (regValue << 6);                
+        }      
+        else if (RTL8306_QUEUE2 == queue)
+        {
+            rtl8306e_regbit_get(5, 24, 6, 2, &regValue);
+            *pValue |= (regValue << 6);                             
+        }      
+        else  
+        {
+            rtl8306e_regbit_get(5, 24, 14, 2, &regValue);
+            *pValue |= (regValue << 6);                             
+        }               
+        break;
+        
+        case 4:     /*set 1, turn off, DSC*/
+            if (RTL8306_QUEUE0 == queue) 
+            {
+                reg = 23;
+                mask = 0x000F;
+                shift =0;
+            } 
+            else if (RTL8306_QUEUE1 == queue) 
+            {
+                reg = 23;
+                mask = 0x0F00;
+                shift =8;
+            }
+            else if (RTL8306_QUEUE2 == queue)
+            {
+                reg = 26;
+                mask = 0x000F;
+                shift =0;
+            }
+            else 
+            {
+                reg = 26;
+                mask = 0x0F00;
+                shift =8;
+            }
+            rtl8306e_reg_get(5, reg, 2, &regValue);
+            *pValue = (regValue & mask) >> shift;
+        
+            if (RTL8306_QUEUE0 == queue) 
+            {
+                rtl8306e_reg_get(1, 27, 3, &regValue);
+                regValue &= 0x700;
+                regValue = regValue >> 8;                 
+                *pValue |= (regValue << 4);                    
+            }
+            else if (RTL8306_QUEUE1 == queue) 
+            {
+                rtl8306e_reg_get(1, 27, 3, &regValue);
+                regValue &= 0xc000;
+                regValue = regValue >> 14;                 
+                *pValue |= (regValue << 4);
+                rtl8306e_regbit_get(1, 28, 0, 3, &regValue);
+                *pValue |= (regValue << 6);                 
+            }
+            else if (RTL8306_QUEUE2 == queue) 
+            {
+                rtl8306e_reg_get(1, 28, 3, &regValue);
+                regValue &= 0x70;
+                 regValue = regValue >> 4;                 
+                 *pValue |= (regValue << 4);  
+            } else  
+            {
+                rtl8306e_reg_get(1, 28, 3, &regValue);
+                regValue &= 0x1c00;
+                regValue = regValue >> 10;                 
+                *pValue |= (regValue << 4);  
+            }                             
+            break;
+        
+    case 5:     /*set 1, turn off, QLEN*/
+        if (RTL8306_QUEUE0 == queue) 
+        {
+            reg = 23;
+            mask = 0xF0;
+            shift = 4;
+        } 
+        else if (RTL8306_QUEUE1 == queue)
+        {
+            reg = 23;
+            mask = 0xF000;
+            shift = 12;
+        }
+        else if (RTL8306_QUEUE2 == queue)
+        {
+            reg = 26;
+            mask = 0xF0;
+            shift = 4;
+        } 
+        else  
+        {
+            reg = 26;
+            mask = 0xF000;
+            shift = 12;
+        }
+        rtl8306e_reg_get(5, reg, 2, &regValue);
+        *pValue = (regValue & mask) >> shift;
+
+        if (RTL8306_QUEUE0 == queue) 
+        {
+            rtl8306e_reg_get(1, 27, 3, &regValue);
+            regValue &= 0x3800;
+            regValue = regValue >> 11;                 
+            *pValue |= (regValue << 4);                    
+        } 
+        else if (RTL8306_QUEUE1 == queue) 
+        {
+            rtl8306e_reg_get(1, 28, 3, &regValue);
+            regValue &= 0xe;
+            regValue = regValue >> 1;                 
+            *pValue |= (regValue << 4);                    
+        } 
+        else if (RTL8306_QUEUE2 == queue)   
+        {
+            rtl8306e_reg_get(1, 28, 3, &regValue);
+            regValue &= 0x380;
+            regValue = regValue >> 7;                 
+            *pValue |= (regValue << 4);
+        }
+        else  
+        {
+            rtl8306e_reg_get(1, 28, 3, &regValue);
+            regValue &= 0xe000;
+            regValue = regValue >> 13;                 
+            *pValue |= (regValue << 4);
+        }                             
+        break;
+        
+        case 6:     /*set 1, turn on, DSC*/
+            if (RTL8306_QUEUE0 == queue) 
+                reg = 24;
+            else if (RTL8306_QUEUE1 == queue) 
+                reg =25;
+            else if (RTL8306_QUEUE2 == queue) 
+                reg = 27;
+            else  
+                reg = 28;
+            rtl8306e_reg_get(5, reg, 2, &regValue);
+            *pValue = (regValue & 0x3F) >> shift;
+        
+             /*bit 6*/
+            if (RTL8306_QUEUE0 == queue) 
+            {
+                rtl8306e_regbit_get(5, 25, 7, 2, &regValue);
+                *pValue |= (regValue << 6);
+            }      
+            else if (RTL8306_QUEUE1 == queue) 
+            {
+                 rtl8306e_regbit_get(5, 25, 15, 2, &regValue);
+                 *pValue |= (regValue << 6);                
+             }      
+            else if (RTL8306_QUEUE2 == queue)
+            {
+                rtl8306e_regbit_get(5, 27, 7, 2, &regValue);
+                *pValue |= (regValue << 6);                             
+            }      
+            else  
+            {
+                rtl8306e_regbit_get(5, 27, 15, 2, &regValue);
+                *pValue |= (regValue << 6);                             
+            }      
+        
+            break;
+        
+        case 7:      /*set 1, turn  on, QLEN*/
+            if (RTL8306_QUEUE0 == queue) 
+                reg = 24;
+            else if (RTL8306_QUEUE1 == queue) 
+                reg =25;
+            else if (RTL8306_QUEUE2 == queue) 
+                reg = 27;
+            else  
+                reg = 28;
+            if (queue != RTL8306_QUEUE3) 
+            {
+                rtl8306e_reg_get(5, reg, 2, &regValue);
+                *pValue = (regValue & 0x3F00) >> 8 ;
+            } 
+            else 
+            {
+                rtl8306e_reg_get(5, reg, 2, &regValue);
+                *pValue = (regValue & 0xFC00) >> 10;
+            }
+             /*bit 6*/
+            if (RTL8306_QUEUE0 == queue) 
+            {
+                rtl8306e_regbit_get(5, 25, 6, 2, &regValue);
+                *pValue |= (regValue << 6);
+            }      
+            else if (RTL8306_QUEUE1 == queue) 
+            {
+                 rtl8306e_regbit_get(5, 25, 14, 2, &regValue);
+                 *pValue |= (regValue << 6);                
+            }      
+            else if (RTL8306_QUEUE2 == queue)
+            {
+                rtl8306e_regbit_get(5, 27, 6, 2, &regValue);
+                *pValue |= (regValue << 6);                             
+            }      
+            else  
+            {
+                rtl8306e_regbit_get(5, 27, 14, 2, &regValue);
+                 *pValue |= (regValue << 6);                             
+            }               
+            break;
+
+        default:
+            return FAILED;
+    }
+
+    return SUCCESS;
+}
+
+int32 rtl8306e_qos_portFlcThr_set(uint32 port, uint32 onthr, uint32 offthr, uint32 direction ) 
+{
+    uint32 regValue;
+
+    if ((port > RTL8306_PORT5) || (direction > 1))
+        return FAILED;
+    
+    regValue = (offthr << 8) + onthr;
+
+    /*Port 5 corresponding PHY6*/
+    if (RTL8306_PORT5 == port)  
+        port ++ ;
+    
+    if (RTL8306_PORT_TX == direction) 
+        rtl8306e_reg_set(port, 20, 2, regValue);
+    else 
+        rtl8306e_reg_set(port, 19, 3, regValue);
+    return SUCCESS;
+}
+
+int32 rtl8306e_qos_portFlcThr_get(uint32 port, uint32 *pOnthr, uint32 *pOffthr, uint32 direction) 
+{
+    uint32 regValue;
+
+    if ((port > RTL8306_PORT5) || (NULL == pOnthr) || (NULL == pOffthr) || (direction > 1))
+        return FAILED;
+    
+    /*Port 5 corresponding PHY6*/
+    if (RTL8306_PORT5 == port)  
+        port ++ ; 
+    
+    if (RTL8306_PORT_TX == direction) 
+        rtl8306e_reg_get(port, 20, 2, &regValue);
+    else 
+        rtl8306e_reg_get(port, 19, 3, &regValue);
+    *pOnthr = regValue & 0xFF;
+    *pOffthr = (regValue & 0xFF00) >> 8;
+    return SUCCESS;
+}
+
+
+int32 rtl8306e_qos_portFlcMode_set(uint32 port, uint32 set) 
+{
+    if ((port > RTL8306_PORT5) || (set > RTL8306_FCO_SET1))
+        return FAILED;
+    
+    if (port < RTL8306_PORT5) 
+        rtl8306e_regbit_set(port, 18, 12, 2, set);
+    else 
+        rtl8306e_regbit_set(6, 18, 12, 2, set);
+    return SUCCESS;
+}
+
+
+int32 rtl8306e_qos_portFlcMode_get(uint32 port , uint32 *set) 
+{
+    if ((port > RTL8306_PORT5) || (set == NULL))
+        return FAILED;
+    
+    if (port < RTL8306_PORT5)
+        rtl8306e_regbit_get(port, 18, 12, 2, set);
+    else
+        rtl8306e_regbit_get(6, 18, 12, 2, set);
+    return SUCCESS;
+}
+
+int32 rtl8306e_qos_queFlcEnable_set( uint32 port, uint32 queue, uint32 enabled) 
+{
+
+    if ((port > RTL8306_PORT5) ||(queue > RTL8306_QUEUE3))
+        return FAILED;
+    
+    /*Enable/Disable Flow control of the specified queue*/
+    switch (port) 
+    {
+        case RTL8306_PORT0:
+            rtl8306e_regbit_set(6, 17, (4 + queue), 0, enabled ? 0:1);
+            break;
+        case RTL8306_PORT1:
+            rtl8306e_regbit_set(6, 18, (4 + queue), 0, enabled ? 0:1);
+            break;
+        case RTL8306_PORT2:
+            rtl8306e_regbit_set(6, 19, (4 + queue), 0, enabled ? 0:1);
+            break;
+        case RTL8306_PORT3:
+            rtl8306e_regbit_set(6, 20, (4 + queue), 0, enabled ? 0:1);
+            break;
+        case RTL8306_PORT4:
+            rtl8306e_regbit_set(6, 21, (4 + queue), 0, enabled ? 0:1);
+            break;
+        case RTL8306_PORT5:
+            rtl8306e_regbit_set(6, 23, (4 + queue), 0, enabled ? 0:1);
+            break;    
+        default:
+            return FAILED;
+    }
+    return SUCCESS;
+}
+
+int32 rtl8306e_qos_queFlcEnable_get(uint32 port, uint32 queue, uint32 *pEnabled) 
+{
+    uint32 bitValue;
+
+    if ((port > RTL8306_PORT5) || (queue > RTL8306_QUEUE3) || (NULL == pEnabled))
+        return FAILED;
+    
+    switch (port) 
+    {
+        case RTL8306_PORT0:
+            rtl8306e_regbit_get(6, 17, (4 + queue), 0, &bitValue);
+            break;
+        case RTL8306_PORT1:
+            rtl8306e_regbit_get(6, 18, (4 + queue), 0, &bitValue);
+            break;
+        case RTL8306_PORT2:
+            rtl8306e_regbit_get(6, 19, (4 + queue), 0, &bitValue);
+            break;
+        case RTL8306_PORT3:
+            rtl8306e_regbit_get(6, 20, (4 + queue), 0, &bitValue);
+            break;
+        case RTL8306_PORT4:
+            rtl8306e_regbit_get(6, 21, (4 + queue), 0, &bitValue);
+            break;
+        case RTL8306_PORT5:
+            rtl8306e_regbit_get(6, 23, (4 + queue), 0, &bitValue);
+            break;    
+        default:
+            return FAILED;
+    }
+    *pEnabled = (bitValue ? FALSE : TRUE);
+    
+    return SUCCESS;
+}
+
+
+/* Function Name:
+ *      rtl8306e_acl_entry_set
+ * Description:
+ *      Set Asic ACL table
+ * Input:
+ *      entryadd   - Acl entry address (0~15)
+ *      phyport    -  Acl physical port
+ *      action      -  Acl action 
+ *      protocol   -  Acl protocol
+ *      data        -  ether type value or TCP/UDP port
+ *      priority     -  Acl priority
+ * Output:
+ *      none
+ * Return:
+ *      SUCCESS
+ *      FAILED
+ * Note:
+ *      phyport could be 
+ *            0~5:       port number, 
+ *            RTL8306_ACL_INVALID: invalid entry,
+ *            RTL8306_ACL_ANYPORT: any port.
+ *      Acl action could be
+ *          RTL8306_ACT_DROP,
+ *          RTL8306_ACT_PERMIT, 
+ *          RTL8306_ACT_TRAPCPU, 
+ *          RTL8306_ACT_MIRROR
+ *      Acl protocol could be
+ *          RTL8306_ACL_ETHER(ether type), 
+ *          RTL8306_ACL_TCP(TCP), 
+ *          RTL8306_ACL_UDP(UDP),
+ *          RTL8306_ACL_TCPUDP(TCP or UDP)
+ *
+ *      Acl priority:
+ *          RTL8306_PRIO0~RTL8306_PRIO3
+ *       
+ */
+
+int32 rtl8306e_acl_entry_set(uint32 entryadd, uint32 phyport, uint32 action, uint32 protocol, uint32 data, uint32 priority) 
+{
+    uint32 regValue, value;
+    uint32 pollcnt  ;
+    uint32 bitValue;
+
+    if ((entryadd > RTL8306_ACL_ENTRYNUM - 1) || (phyport > RTL8306_ACL_ANYPORT) || 
+        (action > RTL8306_ACT_MIRROR) ||(protocol > RTL8306_ACL_TCPUDP) ||
+        (priority > RTL8306_PRIO3))
+        return FAILED;
+
+    /*Enable CPU port function, Enable inserting CPU TAG, Enable removing CPU TAG */
+    rtl8306e_reg_get(2, 21, 3, &regValue);
+    regValue = (regValue & 0x7FFF) | (1 << 11) | (1<<12);
+    rtl8306e_reg_set(2, 21, 3, regValue);
+    
+    /*set EtherType or TCP/UDP Ports, ACL entry access register 0*/
+    rtl8306e_reg_set(3, 21, 3, data);
+    
+    /*set ACL entry access register 1*/
+    rtl8306e_reg_get(3, 22, 3, &regValue);
+    value = (1 << 14) | (entryadd << 9)  | (priority << 7) | (action << 5) | (phyport << 2) | protocol ;
+    regValue = (regValue & 0x8000) | value  ;
+    rtl8306e_reg_set(3, 22, 3, regValue);
+    
+    /*Polling whether the command is done*/
+    for (pollcnt = 0; pollcnt < RTL8306_IDLE_TIMEOUT; pollcnt++) 
+    {
+        rtl8306e_regbit_get(3, 22, 14, 3, &bitValue);
+        if (!bitValue)
+            break;
+    }
+    if (pollcnt == RTL8306_IDLE_TIMEOUT)
+        return FAILED;
+
+#ifdef RTL8306_TBLBAK
+    rtl8306_TblBak.aclTbl[entryadd].phy_port = phyport;
+    rtl8306_TblBak.aclTbl[entryadd].action = action;
+    rtl8306_TblBak.aclTbl[entryadd].proto = protocol;
+    rtl8306_TblBak.aclTbl[entryadd].data = data;
+    rtl8306_TblBak.aclTbl[entryadd].pri = priority;
+#endif  
+    return SUCCESS;
+}
+
+/* Function Name:
+ *      rtl8306e_acl_entry_get
+ * Description:
+ *      Get Asic ACL entry
+ * Input:
+ *      entryadd   - Acl entry address (0~15)
+ * Output:
+ *      pPhyport    -  Acl physical port 
+ *      pAction      -  Acl action 
+ *      pProtocol   -  Acl protocol
+ *      pData        -  ether type value or TCP/UDP port
+ *      pPriority     -  Acl priority
+ * Return:
+ *      SUCCESS
+ *      FAILED
+ * Note:
+ *      phyport could be 
+ *            0~5:       port number, 
+ *            RTL8306_ACL_INVALID: invalid entry,
+ *            RTL8306_ACL_ANYPORT: any port.
+ *      Acl action could be
+ *          RTL8306_ACT_DROP,
+ *          RTL8306_ACT_PERMIT, 
+ *          RTL8306_ACT_TRAPCPU, 
+ *          RTL8306_ACT_MIRROR
+ *      Acl protocol could be
+ *          RTL8306_ACL_ETHER(ether type), 
+ *          RTL8306_ACL_TCP(TCP), 
+ *          RTL8306_ACL_UDP(UDP),
+ *          RTL8306_ACL_TCPUDP(TCP or UDP)
+ *
+ *      Acl priority:
+ *          RTL8306_PRIO0~RTL8306_PRIO3
+ *       
+ */
+int32 rtl8306e_acl_entry_get(uint32 entryadd, uint32 *pPhyport, uint32 *pAction, uint32 *pProtocol, uint32  *pData, uint32 *pPriority)
+{
+    uint32 regValue;
+    uint32 pollcnt  ;
+    uint32 bitValue;
+
+    if ((entryadd > RTL8306_ACL_ENTRYNUM - 1) || (NULL == pPhyport) || (NULL == pAction) || 
+        (NULL == pProtocol) || (NULL == pData) || (NULL == pPriority))
+        return FAILED;
+
+    /*trigger a command to read ACL entry*/
+    rtl8306e_reg_get(3, 22, 3, &regValue);
+    regValue = (regValue & 0x81FF) | (0x3 << 13) | (entryadd << 9);
+    rtl8306e_reg_set(3, 22, 3, regValue);
+    
+    /*Polling whether the command is done*/
+    for (pollcnt = 0; pollcnt < RTL8306_IDLE_TIMEOUT ; pollcnt++) 
+    {
+        rtl8306e_regbit_get(3, 22, 14, 3, &bitValue);
+        if (!bitValue)
+            break;
+    }
+    if (pollcnt == RTL8306_IDLE_TIMEOUT)
+        return FAILED;
+    
+    rtl8306e_reg_get(3, 21, 3, &regValue);
+    *pData = regValue;
+    rtl8306e_reg_get(3, 22, 3, &regValue);
+    *pPriority = (regValue  >> 7) & 0x3;
+    *pAction  = (regValue  >> 5) & 0x3;
+    *pPhyport = (regValue >> 2) & 0x7;
+    *pProtocol = regValue & 0x3;
+
+    return SUCCESS;
+}
+
+/* Function Name:
+ *      rtl8306e_mib_get
+ * Description:
+ *      Get the MIB counter for the specified port
+ * Input:
+ *      port         -  port number (0 ~ 5)
+ *      counter    -  Specify counter type  
+ * Output:
+ *      pValue -  the pointer of counter value 
+ * Return:
+ *      SUCCESS
+ *      FAILED
+ * Note:
+ *      There are five MIB counter for each port, they are:
+ *      RTL8306_MIB_CNT1 - TX count
+ *      RTL8306_MIB_CNT2 - RX count
+ *      RTL8306_MIB_CNT3 - RX Drop Count<nl>
+ *      RTL8306_MIB_CNT4 - RX CRC error Count
+ *      RTL8306_MIB_CNT5 - RX Fragment Count<nl>
+ */
+int32 rtl8306e_mib_get(uint32 port, uint32 counter, uint32 *pValue) 
+{
+    uint32 regValue1, regValue2;
+
+    if ((port > RTL8306_PORT5) || (counter > RTL8306_MIB_CNT5) ||
+        (NULL == pValue))
+        return FAILED;
+    
+    /*Port 5 corresponding PHY6*/
+    if (RTL8306_PORT5 == port)  
+        port ++ ;  
+    
+    switch(counter) 
+    {
+        case RTL8306_MIB_CNT1:            
+            /*Must read low 16 bit first, then hight 16 bit*/
+            rtl8306e_reg_get(port, 22, 2, &regValue1);
+            rtl8306e_reg_get(port, 23, 2, &regValue2);
+            *pValue = (regValue2 << 16) + regValue1;
+            break;
+            
+        case RTL8306_MIB_CNT2:
+            /*Must read low 16 bit first, then hight 16 bit*/
+            rtl8306e_reg_get(port, 24, 2, &regValue1);
+            rtl8306e_reg_get(port, 25, 2, &regValue2);
+            *pValue = (regValue2 << 16) + regValue1;
+            break;
+            
+        case RTL8306_MIB_CNT3:
+            /*Must read low 16 bit first, then hight 16 bit*/
+            rtl8306e_reg_get(port, 26, 2, &regValue1);
+            rtl8306e_reg_get(port, 27, 2, &regValue2);
+            *pValue = (regValue2 << 16) + regValue1;            
+            break;
+            
+        case RTL8306_MIB_CNT4:
+            /*Must read low 16 bit first, then hight 16 bit*/
+            rtl8306e_reg_get(port, 28, 2, &regValue1);
+            rtl8306e_reg_get(port, 29, 2, &regValue2);
+            *pValue = (regValue2 << 16) + regValue1;            
+            break;
+            
+        case RTL8306_MIB_CNT5:
+            /*Must read low 16 bit first, then hight 16 bit*/
+            rtl8306e_reg_get(port, 30, 2, &regValue1);
+            rtl8306e_reg_get(port, 31, 2, &regValue2);
+            *pValue = (regValue2 << 16) + regValue1;            
+            break;
+        default:
+            return FAILED;
+    }
+    return SUCCESS;
+}
+
+
+/* Function Name:
+ *      rtl8306e_mibUnit_set
+ * Description:
+ *      Set RX/Tx Mib counting unit: byte or packet
+ * Input:
+ *      port         -  port number (0 ~ 5)
+ *      counter    -  Specify counter type  
+ *      uint         -  Specify counting unit
+ * Output:
+ *      none  
+ * Return:
+ *      SUCCESS
+ *      FAILED
+ * Note:
+ *      1.There are five MIB counter for each port, they are:
+ *      RTL8306_MIB_CNT1 - TX count
+ *      RTL8306_MIB_CNT2 - RX count
+ *      RTL8306_MIB_CNT3 - RX Drop Count<nl>
+ *      RTL8306_MIB_CNT4 - RX CRC error Count
+ *      RTL8306_MIB_CNT5 - RX Fragment Count<nl>
+ *      2.Only RTL8306_MIB_CNT1 and RTL8306_MIB_CNT2 could set counting unit  
+ *      RTL8306_MIB_PKT or RTL8306_MIB_BYTE, default is RTL8306_MIB_PKT.
+ *      the other counters' counting uint is RTL8306_MIB_PKT
+ */
+int32 rtl8306e_mibUnit_set(uint32 port, uint32 counter, uint32 unit) 
+{
+
+    if ((port > RTL8306_PORT5) ||(unit > RTL8306_MIB_PKT))
+        return FAILED;
+    /*Port 5 corresponding PHY6*/
+    if (port == RTL8306_PORT5 )  
+        port ++ ;  
+    switch(counter) 
+    {
+        case RTL8306_MIB_CNT1:
+            rtl8306e_regbit_set(port, 17, 3, 2, unit);
+            break;
+        case RTL8306_MIB_CNT2:
+            rtl8306e_regbit_set(port, 17, 4, 2, unit);
+            break;
+        default :
+            return FAILED;
+    }
+    return SUCCESS;
+}
+
+/* Function Name:
+ *      rtl8306e_mibUnit_get
+ * Description:
+ *      Get Rx/Tx Mib counting unit
+ * Input:
+ *      port         -  port number (0 ~ 5)
+ *      counter    -  Specify counter type  
+ * Output:
+ *      pUnit         -  the pointer of counting unit
+ * Return:
+ *      SUCCESS
+ *      FAILED
+ * Note:
+ *      1.There are five MIB counter for each port, they are:
+ *      RTL8306_MIB_CNT1 - TX count
+ *      RTL8306_MIB_CNT2 - RX count
+ *      RTL8306_MIB_CNT3 - RX Drop Count<nl>
+ *      RTL8306_MIB_CNT4 - RX CRC error Count
+ *      RTL8306_MIB_CNT5 - RX Fragment Count<nl>
+ *      2.Only RTL8306_MIB_CNT1 and RTL8306_MIB_CNT2 could set counting unit  
+ *      RTL8306_MIB_PKT or RTL8306_MIB_BYTE, default is RTL8306_MIB_PKT.
+ *      the other counters' counting uint is RTL8306_MIB_PKT
+ */
+int32 rtl8306e_mibUnit_get(uint32 port, uint32 counter, uint32 *pUnit) 
+{ 
+    uint32 bitValue;
+    if ((port > RTL8306_PORT5) ||(pUnit == NULL))
+        return FAILED;
+    
+    /*Port 5 corresponding PHY6*/
+    if (port == RTL8306_PORT5 )  
+        port ++ ;  
+    switch(counter) 
+    {
+        case RTL8306_MIB_CNT1:
+            rtl8306e_regbit_get(port, 17, 3, 2, &bitValue);
+            break;
+        case RTL8306_MIB_CNT2:
+            rtl8306e_regbit_get(port, 17, 4, 2, &bitValue);
+            break;
+        default:
+            return FAILED;
+    }
+    *pUnit = (bitValue ? RTL8306_MIB_PKT : RTL8306_MIB_BYTE);
+    return SUCCESS;
+}
+
+/* Function Name:
+ *      rtl8306e_mib_reset
+ * Description:
+ *      reset MIB counter
+ * Input:
+ *      port         -  port number (0 ~ 5)
+ * Output:
+ *      none
+ * Return:
+ *      SUCCESS
+ *      FAILED
+ * Note:
+ */
+int32 rtl8306e_mib_reset(uint32 port) 
+{
+
+    if ((port > RTL8306_PORT5))
+        return FAILED;
+    
+    /*Port 5 corresponding PHY6*/
+    if (RTL8306_PORT5 == port)  
+        port ++ ;  
+
+    /*stop counting and clear Mib counter to 0*/
+    rtl8306e_regbit_set(port, 17, 2, 2, 1);    
+    
+    /*Start counting*/
+    rtl8306e_regbit_set(port, 17, 2, 2, 0);    
+    return SUCCESS;
+}
+
+/* Function Name:
+ *      rtl8306e_mirror_portBased_set
+ * Description:
+ *      Set asic Mirror port
+ * Input:
+ *      mirport         -  Specify mirror port 
+ *      rxmbr           -  Specify Rx mirror port mask
+ *      txmbr           -  Specify Tx mirror port mask
+ * Output:
+ *      none
+ * Return:
+ *      SUCCESS
+ *      FAILED
+ * Note:
+ *      mirport could be 0 ~ 5, represent physical port number, 
+ *      7 means that no port has mirror ability. rxmbr and txmbr
+ *      is 6 bit value, each bit corresponds one port. ingress packet
+ *      of port in rxmbr will be mirrored to mirport, egress packet 
+ *      of port in txmbr will be mirrored to mirport.
+ */
+int32 rtl8306e_mirror_portBased_set(uint32 mirport, uint32 rxmbr, uint32 txmbr) 
+{
+    uint32 regValue;
+
+    if ((mirport > 7) ||(rxmbr > 0x3F) || (txmbr > 0x3F) )
+        return FAILED;
+
+    /*Set Mirror Port*/
+    rtl8306e_reg_get(2, 22, 3, &regValue);
+    regValue = (regValue & 0xC7FF) | (mirport << 11);
+    rtl8306e_reg_set(2, 22, 3, regValue);
+    
+    /*enable mirror port to filter the mirrored packet sent from itself */
+    rtl8306e_regbit_set(6, 21, 7, 3, 1);
+        
+    /*Set Ports Whose RX Data are Mirrored */
+    rtl8306e_reg_get(6, 21, 3, &regValue);
+    regValue = (regValue & 0xFFC0) | rxmbr ;
+    rtl8306e_reg_set(6, 21, 3, regValue);
+    
+    /*Set Ports Whose TX Data are Mirrored */
+    rtl8306e_reg_get(6, 21, 3, &regValue);
+    regValue = (regValue & 0xC0FF) | (txmbr << 8);
+    rtl8306e_reg_set(6, 21, 3, regValue);
+
+#ifdef RTL8306_TBLBAK
+    rtl8306_TblBak.mir.mirPort = (uint8)mirport;
+    rtl8306_TblBak.mir.mirRxPortMask = (uint8)rxmbr;
+    rtl8306_TblBak.mir.mirTxPortMask = (uint8)txmbr;
+#endif
+    return SUCCESS;
+}
+
+/* Function Name:
+ *      rtl8306e_mirror_portBased_get
+ * Description:
+ *      Get asic Mirror port
+ * Input:
+ *      none 
+ * Output:
+ *      pMirport     -  the pointer of mirror port
+ *      pRxmbr       -  the pointer of  Rx mirror port mask
+ *      pTxmbr       -  the pointer of Tx mirror port mask 
+ * Return:
+ *      SUCCESS
+ *      FAILED
+ * Note:
+ *      mirport could be 0 ~ 5, represent physical port number, 
+ *      7 means that no port has mirror ability. rxmbr and txmbr
+ *      is 6 bit value, each bit corresponds one port. ingress packet
+ *      of port in rxmbr will be mirrored to mirport, egress packet 
+ *      of port in txmbr will be mirrored to mirport.
+ */
+int32 rtl8306e_mirror_portBased_get(uint32 *pMirport, uint32 *pRxmbr, uint32* pTxmbr) 
+{
+    uint32 regValue;
+
+    if ((NULL == pMirport) ||(NULL == pRxmbr) || (NULL == pTxmbr)) 
+        return FAILED;
+
+    /*Get Mirror Port*/
+    rtl8306e_reg_get(2, 22, 3, &regValue);
+    *pMirport = (regValue & 0x3800) >> 11;
+    
+    /*Get Ports Whose RX Data are Mirrored*/
+    rtl8306e_reg_get(6, 21, 3, &regValue);
+    *pRxmbr = regValue & 0x3F;
+    
+    /*Get Ports Whose TX Data are Mirrored */
+    rtl8306e_reg_get(6, 21, 3, &regValue);
+    *pTxmbr = (regValue & 0x3F00) >> 8;
+    return SUCCESS;
+}
+
+/* Function Name:
+ *      rtl8306e_mirror_macBased_set
+ * Description:
+ *      Set Mac address for mirror packet
+ * Input:
+ *      macAddr  - mirrored mac address, it could be SA or DA of the packet 
+ *      enabled   - enable mirror packet by mac address
+ * Output:
+ *      none
+ * Return:
+ *      SUCCESS
+ *      FAILED
+ * Note:
+ *
+ */
+int32 rtl8306e_mirror_macBased_set(uint8 *macAddr, uint32 enabled) 
+{
+
+    if (NULL == macAddr)
+        return FAILED;
+
+    if (!enabled) 
+    {
+        rtl8306e_regbit_set(6, 21, 14, 3, 0);
+#ifdef RTL8306_TBLBAK
+        rtl8306_TblBak.mir.enMirMac = (uint8)enabled;
+#endif
+    } 
+    else 
+    {
+        rtl8306e_regbit_set(6, 21, 14, 3, 1);
+        rtl8306e_reg_set(6, 22, 3, (macAddr[1] << 8) | macAddr[0]);
+        rtl8306e_reg_set(6, 23, 3, (macAddr[3] << 8) | macAddr[2]);
+        rtl8306e_reg_set(6, 24, 3, (macAddr[5] << 8) | macAddr[4]);
+#ifdef RTL8306_TBLBAK
+        rtl8306_TblBak.mir.enMirMac = (uint8)enabled;
+        rtl8306_TblBak.mir.mir_mac[0] = macAddr[0];
+        rtl8306_TblBak.mir.mir_mac[1] = macAddr[1];
+        rtl8306_TblBak.mir.mir_mac[2] = macAddr[2];
+        rtl8306_TblBak.mir.mir_mac[3] = macAddr[3];
+        rtl8306_TblBak.mir.mir_mac[4] = macAddr[4];
+        rtl8306_TblBak.mir.mir_mac[5] = macAddr[5];   
+#endif
+    }
+
+    return SUCCESS;
+}
+
+/* Function Name:
+ *      rtl8306e_mirror_macBased_set
+ * Description:
+ *      Set Mac address for mirror packet
+ * Input:
+ *      none 
+ * Output:
+ *      macAddr   - mirrored mac address, it could be SA or DA of the packet 
+ *      pEnabled   - the pointer of enable mirror packet by mac address 
+ * Return:
+ *      SUCCESS
+ *      FAILED
+ * Note:
+ * 
+ */
+int32 rtl8306e_mirror_macBased_get(uint8 *macAddr, uint32 *pEnabled) 
+{
+    uint32 regValue;
+    uint32 bitValue;
+
+    if (NULL == macAddr)
+        return FAILED;
+    
+    rtl8306e_regbit_get(6, 21, 14, 3, &bitValue);
+    *pEnabled = (bitValue  ? TRUE : FALSE);
+    rtl8306e_reg_get(6, 22, 3, &regValue);
+    macAddr[0] = regValue & 0xFF;
+    macAddr[1] = (regValue & 0xFF00) >> 8;
+    rtl8306e_reg_get(6, 23, 3, &regValue);
+    macAddr[2] = regValue & 0xFF;
+    macAddr[3] = (regValue & 0xFF00) >> 8;
+    rtl8306e_reg_get(6, 24, 3, &regValue);
+    macAddr[4] = regValue & 0xFF;
+    macAddr[5] = (regValue & 0xFF00) >> 8;
+    return SUCCESS;
+    
+}
+
+
+/* Function Name:
+ *      rtl8306e_l2_MacToIdx_get
+ * Description:
+ *      get L2 table hash value from mac address
+ * Input:
+ *      macAddr        -  mac address
+ * Output:
+ *      pIndex           -  mac address table index   
+ * Return:
+ *      SUCCESS
+ *      FAILED
+ * Note:
+ *      when a mac address is learned into mac address table, 
+ *      9 bit index value is got from the mac address by hashing 
+ *      algorithm, each index corresponds to 4 entry, it means
+ *      the table could save 4 mac addresses at the same time
+ *      whose index value is equal, so switch mac address table 
+ *      has 2048 entry. the API could get hash index from 
+ *      a specified mac address.
+ */
+int32 rtl8306e_l2_MacToIdx_get(uint8 *macAddr, uint32* pIndex)
+{
+    uint32 tmp_index;
+    uint32 status;
+
+    if ((NULL == macAddr) || (NULL == pIndex))
+        return FAILED;
+
+
+    rtl8306e_regbit_get(1, 23, 12, 0, &status);    
+    *pIndex = 0;
+    
+    if (status) 
+    {  
+        /* xor hash algorithm*/
+        
+        /* Index 0 = 4 ^ 11 ^ 18 ^ 25 ^ 32 */
+        *pIndex |= ((macAddr[5] & 0x8) >> 3) ^ ((macAddr[4] & 0x10) >> 4) ^ ((macAddr[3] & 0x20) >> 5) ^ ((macAddr[2] & 0x40) >> 6) ^  ((macAddr[1] & 0x80) >> 7); 
+
+        /* Index_1 = 3 ^ 10 ^ 17 ^ 24 ^ 47 */
+        tmp_index = ((macAddr[5] & 0x10) >> 4) ^ ((macAddr[4] & 0x20) >> 5) ^ ((macAddr[3] & 0x40) >> 6) ^ ((macAddr[2] & 0x80) >> 7) ^ ((macAddr[0] & 0x1) >> 0);
+        *pIndex |= tmp_index << 1;
+
+        /* Index_2 = 2 ^ 9 ^ 16 ^ 39 ^ 46 */
+        tmp_index = ((macAddr[5] & 0x20) >> 5) ^ ((macAddr[4] & 0x40) >> 6) ^ ((macAddr[3] & 0x80) >> 7) ^ ((macAddr[1] & 0x1) >> 0) ^ ((macAddr[0] & 0x2) >> 1);
+        *pIndex |= tmp_index << 2;
+
+        /* Index_3 = 1 ^ 8 ^ 31 ^ 38 ^ 45 */
+        tmp_index = ((macAddr[5] & 0x40) >> 6) ^ ((macAddr[4] & 0x80) >> 7) ^ ((macAddr[2] & 0x1) >> 0) ^ ((macAddr[1] & 0x2) >> 1) ^ ((macAddr[0] & 0x4) >> 2);
+        *pIndex |= tmp_index << 3;
+
+        /* Index_4 = 0 ^ 23 ^ 30 ^ 37 ^ 44 */
+        tmp_index = ((macAddr[5] & 0x80) >> 7) ^ ((macAddr[3] & 0x1) >> 0) ^ ((macAddr[2] & 0x2) >> 1) ^ ((macAddr[1] & 0x4) >> 2) ^ ((macAddr[0] & 0x8) >> 3);
+        *pIndex |= tmp_index << 4;
+
+        /* Index_5 = 15 ^ 22 ^ 29 ^ 36 ^ 43 */
+        tmp_index = ((macAddr[4] & 0x1) >> 0) ^ ((macAddr[3] & 0x2) >> 1) ^ ((macAddr[2] & 0x4) >> 2) ^ ((macAddr[1] & 0x8) >> 3) ^ ((macAddr[0] & 0x10) >> 4);
+        *pIndex |= tmp_index << 5;
+
+        /* Index_6 = 7 ^  14 ^ 21 ^ 28 ^ 35 ^ 42 */
+        tmp_index = ((macAddr[5] & 0x1) >> 0) ^ ((macAddr[4] & 0x2) >> 1) ^ ((macAddr[3] & 0x4) >> 2) ^ ((macAddr[2] & 0x8) >> 3) ^ ((macAddr[1] & 0x10) >> 4) ^ ((macAddr[0] & 0x20) >> 5);
+        *pIndex |= tmp_index << 6;
+
+        /* Index_7 = 6 ^ 13 ^ 20 ^ 27 ^ 34 ^ 41 */
+        tmp_index = ((macAddr[5] & 0x2) >> 1) ^ ((macAddr[4] & 0x4) >> 2) ^ ((macAddr[3] & 0x8) >> 3) ^ ((macAddr[2] & 0x10) >> 4) ^ ((macAddr[1] & 0x20) >> 5) ^ ((macAddr[0] & 0x40) >> 6);
+        *pIndex |= tmp_index << 7;
+
+        /* Index_8 = 5 ^ 12 ^ 19 ^ 26 ^ 33 ^ 40 */
+        tmp_index = ((macAddr[5] & 0x4) >> 2) ^ ((macAddr[4] & 0x8) >> 3) ^ ((macAddr[3] & 0x10) >> 4) ^ ((macAddr[2] & 0x20) >> 5) ^ ((macAddr[1] & 0x40) >> 6)  ^ ((macAddr[0] & 0x80) >> 7);
+        *pIndex |= tmp_index << 8;
+    }
+    else  
+    {
+        /*index direct from mac: LUT index MAC[13:15] + MAC[0:5]*/
+        *pIndex = ((macAddr[4] & 0x7) << 6) | ((macAddr[5] & 0xFC) >> 2);
+    }
+
+    return SUCCESS;
+}
+
+/* Function Name:
+ *      rtl8306e_l2_IdxToMac_get
+ * Description:
+ *      get Mac address for hash index
+ * Input:
+ *      pIndex        -  the pointer of address table index
+ * Output:
+ *      macAddr     -   the mac address   
+ * Return:
+ *      SUCCESS
+ *      FAILED
+ * Note:
+ *   
+ */ 
+static int32 rtl8306e_l2_IdxToMac_get(uint8 *macAddr, uint32* pIndex)
+{
+    uint32 tmp_index, regValue, status;
+
+    if ((NULL == macAddr) || (NULL == pIndex))
+        return FAILED;
+
+    rtl8306e_regbit_get(1, 23, 12, 0, &status);
+    
+    if (status) 
+    {
+        /* xor hash algorithm*/
+
+        /*Read Data[47:32]*/
+        rtl8306e_reg_get(4, 18, 0, &regValue);
+        macAddr[5] = (regValue & 0x300) >> 8; 
+        macAddr[4] = regValue & 0xF8;            
+  
+        /*Read Data[31:16]*/
+        rtl8306e_reg_get(4, 19, 0, &regValue);
+        macAddr[3] = (regValue & 0xFF00) >> 8; 
+        macAddr[2] = regValue & 0xFF;
+
+        /*Read Data[15:0]*/
+        rtl8306e_reg_get(4, 20, 0, &regValue);
+        macAddr[1] = (regValue & 0xFF00) >> 8;
+        macAddr[0] = regValue & 0xFF;
+
+        /* bit 4 =  Index_0 ^ 11 ^ 18 ^ 25 ^ 32; */
+        tmp_index = ((*pIndex & 0x4) >> 2) ^ ((macAddr[4] & 0x10) >> 4) ^ ((macAddr[3] & 0x20) >> 5) ^ ((macAddr[2] & 0x40) >> 6) ^  ((macAddr[1] & 0x80) >> 7); 
+        macAddr[5] |= (uint8)(tmp_index << 3);
+        /* bit 3 =  Index_1 ^ 10 ^ 17 ^ 24 ^ 47 */
+        tmp_index = ((*pIndex & 0x8) >> 3) ^ ((macAddr[4] & 0x20) >> 5) ^ ((macAddr[3] & 0x40) >> 6) ^ ((macAddr[2] & 0x80) >> 7) ^ ((macAddr[0] & 0x1) >> 0);
+        macAddr[5] |= (uint8)(tmp_index << 4);
+        /* bit 2 =  Index_2 ^ 9 ^ 16 ^ 39 ^ 46 */
+        tmp_index = ((*pIndex & 0x10) >> 4) ^ ((macAddr[4] & 0x40) >> 6) ^ ((macAddr[3] & 0x80) >> 7) ^ ((macAddr[1] & 0x1) >> 0) ^ ((macAddr[0] & 0x2) >> 1);
+        macAddr[5] |= (uint8)(tmp_index << 5);
+
+        /* bit 1 = Index_3 ^ 8 ^ 31 ^ 38 ^ 45 */
+        tmp_index = ((*pIndex & 0x20) >> 5) ^ ((macAddr[4] & 0x80) >> 7)  ^ ((macAddr[2] & 0x1) >> 0) ^ ((macAddr[1] & 0x2) >> 1) ^ ((macAddr[0] & 0x4) >> 2);
+        macAddr[5] |= (uint8)(tmp_index << 6);
+
+        /* bit 0 = Index_4 ^ 23 ^ 30 ^ 37 ^ 44 */
+        tmp_index = ((*pIndex & 0x40) >> 6) ^ ((macAddr[3] & 0x1) >> 0)  ^ ((macAddr[2] & 0x2) >> 1) ^ ((macAddr[1] & 0x4) >> 2) ^ ((macAddr[0] & 0x8) >> 3);
+        macAddr[5] |= (uint8)(tmp_index << 7);
+
+        /* bit 15 = Index_5 ^ 22 ^ 29 ^ 36 ^ 43 */
+        tmp_index = ((*pIndex & 0x80) >> 7) ^ ((macAddr[3] & 0x2) >> 1) ^ ((macAddr[2] & 0x4) >> 2) ^ ((macAddr[1] & 0x8) >> 3) ^ ((macAddr[0] & 0x10) >> 4);
+        macAddr[4] |= (uint8)(tmp_index << 0);
+        
+        /* bit 14 =  Index_6 ^ 7 ^ 21 ^ 28 ^ 35 ^ 42 */
+        tmp_index = ((*pIndex & 0x100) >> 8) ^ ((macAddr[5] & 0x1) >> 0) ^ ((macAddr[3] & 0x4) >> 2) ^ ((macAddr[2] & 0x8) >> 3) ^ ((macAddr[1] & 0x10) >> 4) ^ ((macAddr[0] & 0x20) >> 5);
+        macAddr[4] |= (uint8)(tmp_index << 1);
+
+        /* bit 13 =  Index_7 ^ 6 ^ 20 ^ 27 ^ 34 ^ 41 */
+        tmp_index = ((*pIndex & 0x200) >> 9) ^ ((macAddr[5] & 0x2) >> 1) ^ ((macAddr[3] & 0x8) >> 3) ^ ((macAddr[2] & 0x10) >> 4) ^ ((macAddr[1] & 0x20) >> 5) ^ ((macAddr[0] & 0x40) >> 6);
+        macAddr[4] |= (uint8)(tmp_index << 2);
+        
+        /* bit 5 =  Index_8 ^ 12 ^ 19 ^ 26 ^ 33 ^ 40 */
+        tmp_index = ((*pIndex & 0x400) >> 10) ^ ((macAddr[4] & 0x8) >> 3) ^ ((macAddr[3] & 0x10) >> 4) ^ ((macAddr[2] & 0x20) >> 5) ^ ((macAddr[1] & 0x40) >> 6)  ^ ((macAddr[0] & 0x80) >> 7);
+        macAddr[5] |= (uint8)(tmp_index << 2);
+ 
+    }
+    else  
+    {
+        /*Read Data[47:32]*/
+      rtl8306e_reg_get(4, 18, 0, &regValue);
+      macAddr[5] = ((regValue & 0x300) >> 8) | (*pIndex & 0xFC);
+      macAddr[4] = (regValue & 0xF8) | ((*pIndex >> 8) & 0x7);
+
+      /*Read Data[31:16]*/
+      rtl8306e_reg_get(4, 19, 0, &regValue);
+      macAddr[3] = (regValue & 0xFF00) >> 8;
+      macAddr[2] = regValue & 0xFF;
+
+      /*Read Data[15:0]*/
+      rtl8306e_reg_get(4, 20, 0, &regValue);
+      macAddr[1] = (regValue & 0xFF00) >> 8;
+      macAddr[0] = regValue & 0xFF;
+    }
+    
+    return SUCCESS;
+}
+
+/* Function Name:
+ *      rtl8306e_l2_unicastEntry_set
+ * Description:
+ *      write an unicast mac address into L2 table
+ * Input:
+ *      macAddress        -  Specify the unicast Mac address(6 bytes) to be written into LUT
+ *      entry                 -  Specify the 4-way entry to be written (0~3)
+ *      age                   -  Specify age time
+ *      isStatic              -  TRUE(static entry), FALSE(dynamic entry)
+ *      isAuth                -  Whether the mac address is authorized by IEEE 802.1x
+ *      port                  -   Specify the port number to be forwarded to  
+ * Output:
+ *      none
+ * Return:
+ *      SUCCESS
+ *      FAILED
+ * Note:
+ *      Age time has 4 value :
+ *          RTL8306_LUT_AGEOUT, 
+ *          RTL8306_LUT_AGE100(100s)
+ *          RTL8306_LUT_AGE200(200s)
+ *          RTL8306_LUT_AGE300(300s)
+ */ 
+
+int32 rtl8306e_l2_unicastEntry_set(uint8 *macAddress, uint32 entry, uint32 age, uint32 isStatic, uint32 isAuth, uint32 port) 
+{
+    uint32 regValue, index, pollcnt;
+    uint32 bitValue;
+
+    if ((NULL == macAddress) || (entry > RTL8306_LUT_ENTRY3) || (age > RTL8306_LUT_AGE300) ||
+        (port > RTL8306_PORT5))
+        return FAILED;
+
+    /*For unicast entry, MAC[47] is 0  */
+    if (macAddress[0] & 0x1)
+        return FAILED;
+    
+    /*Enable lookup table access*/
+    rtl8306e_regbit_set(0, 16, 13, 0, 1);
+    
+    /*Write Data[55:48]*/
+    if (RTL8306_LUT_AGE300 == age) 
+        age = 0x2;
+    else if (RTL8306_LUT_AGE200 == age)
+        age = 0x3;
+    else if (RTL8306_LUT_AGE100 == age)
+        age = 0x1;
+    else 
+        age = 0;
+
+    regValue = ((isAuth ? 1:0 ) << 7) | ((isStatic ? 1:0) << 6) | (age << 4) | port;
+    rtl8306e_reg_set(4, 17, 0, regValue & 0xFF);
+    /*write Data[47:32]*/
+    rtl8306e_reg_set(4, 18, 0, macAddress[5] << 8 | macAddress[4]);
+    /*wrtie Data[31:16]*/
+    rtl8306e_reg_set(4, 19, 0, macAddress[3] << 8 | macAddress[2]);
+    /*wrtie Data[15:0]*/
+    rtl8306e_reg_set(4, 20, 0, macAddress[1] << 8 | macAddress[0]);
+
+    /*LUT index */
+    rtl8306e_l2_MacToIdx_get(macAddress, &index);
+
+    /*Write Command, 2-bit indicating four-way lies in highest bit of Entry_Addr[10:0]*/
+    regValue = (entry << 13) | (index << 4) | 0x0;
+    rtl8306e_reg_set(4, 16, 0, regValue);
+    rtl8306e_regbit_set(4, 16, 1, 0, 1);
+    
+    /*Waiting for write command done and prevent polling dead loop*/
+    for (pollcnt = 0; pollcnt < RTL8306_IDLE_TIMEOUT; pollcnt ++) 
+    {
+        rtl8306e_regbit_get(4, 16, 1, 0, &bitValue);
+        if (!bitValue)
+            break;
+    }
+    if (pollcnt == RTL8306_IDLE_TIMEOUT)
+        return FAILED;
+
+    /*Disable lookup table access*/
+    rtl8306e_regbit_set(0, 16, 13, 0, 0);
+ #ifdef RTL8306_LUT_CACHE
+     memcpy(rtl8306_LutCache[ (index << 2) | entry].mac, macAddress, 6);
+     rtl8306_LutCache[ (index << 2) | entry].un.unicast.auth = isAuth;
+     rtl8306_LutCache[ (index << 2) | entry].un.unicast.spa= port;
+     rtl8306_LutCache[ (index << 2) | entry].un.unicast.isStatic= isStatic;
+     rtl8306_LutCache[ (index << 2) | entry].un.unicast.age= age;
+ #endif
+    return SUCCESS;
+}
+
+/* Function Name:
+ *      rtl8306e_l2_unicastEntry_get
+ * Description:
+ *      read an unicast mac address into L2 table
+ * Input:
+ *      entry               -  Specify the entry address to be read (0 ~ 2047), not four-way entry
+ * Output:
+ *      macAddress      -  the mac to be saved in the entry  
+ *      pAge               -  the pointer of the age time
+ *      pIsStatic         -   the pointer of static or dynamic entry
+ *      pIsAuth           -   the pointer of IEEE 802.1x authorized status
+ *      pPort              -   the pointer of the port the mac belongs to   
+ * Return:
+ *      SUCCESS
+ *      FAILED
+ * Note:
+ *      Age time has 4 value :
+ *          RTL8306_LUT_AGEOUT
+ *          RTL8306_LUT_AGE100(100s)
+ *          RTL8306_LUT_AGE200(200s)
+ *          RTL8306_LUT_AGE300(300s)
+ */ 
+ 
+int32 rtl8306e_l2_unicastEntry_get(uint8 *macAddress, uint32 entryAddr, uint32 *pAge, uint32 *pIsStatic, uint32 *pIsAuth, uint32 *pPort) 
+{
+    uint32 entryAddrHd;
+    uint32 regValue, pollcnt;
+    uint32 bitValue;
+
+    if ((NULL == macAddress) || (entryAddr > 0x7FF) || (NULL == pAge) || (NULL == pIsStatic) ||
+        (pIsAuth == NULL) || (pPort == NULL))
+        return FAILED;
+    
+    /*Hardware data format, four-way info is the highest 2 bits of 11-bit entry info*/
+    entryAddrHd = (entryAddr >> 2) | ((entryAddr & 0x3) << 9);
+    
+    /*Enable lookup table access*/
+    rtl8306e_regbit_set(0, 16, 13, 0, 1);
+    /*Read Command*/
+    regValue = (entryAddrHd << 4) | 0x1;
+    rtl8306e_reg_set(4, 16, 0, regValue);
+    rtl8306e_regbit_set(4, 16, 1, 0, 1);
+    
+    /*Waiting for Read command done and prevent polling dead loop*/
+    for (pollcnt = 0; pollcnt < RTL8306_IDLE_TIMEOUT; pollcnt ++) 
+    {
+        rtl8306e_regbit_get(4, 16, 1, 0, &bitValue);
+        if (!bitValue)
+            break;
+    }
+    if (pollcnt == RTL8306_IDLE_TIMEOUT)
+        return FAILED;
+    
+    /*Read Data[55:48]*/
+    rtl8306e_reg_get(4, 17, 0, &regValue);
+    *pIsAuth = (regValue & 0x80) ? TRUE: FALSE;
+    *pIsStatic = (regValue & 0x40) ? TRUE:FALSE;
+    *pAge = (regValue & 0x30) >> 4;
+    if (*pAge == 0x2) 
+        *pAge = RTL8306_LUT_AGE300;
+    else if (*pAge == 0x3)
+        *pAge = RTL8306_LUT_AGE200;
+    else if (*pAge == 0x1 )
+        *pAge = RTL8306_LUT_AGE100;
+    else 
+        *pAge = RTL8306_LUT_AGEOUT;
+    *pPort = regValue & 0x7;
+
+    rtl8306e_l2_IdxToMac_get(macAddress, &entryAddr);
+
+    /*Disable lookup table access*/
+    rtl8306e_regbit_set(0, 16, 13, 0, 0);
+    return SUCCESS;
+}
+
+#ifdef RTL8306_LUT_CACHE
+ 
+int32 rtl8306e_fastGetAsicLUTUnicastEntry(uint8 *macAddress, uint32 entryAddr, uint32 *pAge, uint32 *pIsStatic, uint32 *pIsAuth, uint32 *pPort) 
+{    
+    if ((NULL == macAddress) || (entryAddr > 0x7FF) || (NULL == pAge) || (NULL == pIsStatic ) ||
+        (NULL == pIsAuth) || (NULL == pPort))
+        return FAILED;
+
+    memcpy(macAddress, rtl8306_LutCache[entryAddr].mac, 6);
+
+    *pIsStatic= rtl8306_LutCache[entryAddr].un.unicast.isStatic;
+    *pIsAuth = rtl8306_LutCache[entryAddr].un.unicast.auth;
+    *pPort   = rtl8306_LutCache[entryAddr].un.unicast.spa;
+    *pAge     = rtl8306_LutCache[entryAddr].un.unicast.age;
+
+    return SUCCESS;
+}
+
+int32 rtl8306e_fastGetAsicLUTMulticastEntry(uint8 *macAddress, uint32 entryAddr, uint32 *pIsAuth, uint32 *pPortMask) 
+{
+    
+    if ((NULL == macAddress) || (entryAddr > 0x7FF) ||(NULL == pIsAuth) || (NULL == pPortMask))
+        return FAILED;      
+    memcpy(macAddress, rtl8306_LutCache[entryAddr].mac, 6);
+
+    *pIsAuth = rtl8306_LutCache[entryAddr].un.multicast.auth;
+    *pPortMask = rtl8306_LutCache[entryAddr].un.multicast.portMask;
+
+    return SUCCESS;   
+}
+
+#endif
+/* Function Name:
+ *      rtl8306e_l2_multicastEntry_set
+ * Description:
+ *      write an multicast mac address into L2 table
+ * Input:
+ *      macAddress      -  the mac to be saved in the entry  
+ *      entry               -  Specify the 4-way entry to be written (0~3)
+ *      isAuth              -  IEEE 802.1x authorized status
+ *      portMask          -  switch received thepacket with the specified macAddress, 
+ *                                and forward it to the member port of portMask
+ * Output:
+ *      none
+ * Return:
+ *      SUCCESS
+ *      FAILED
+ * Note:
+ *      get 9-bit as index value of lookup table by hashing the mac address , for each index value, 
+ *      there are 4-entry to save hash collision mac address, thus there are 2048 entries all together.
+ *      the entry could save both unicast multicast mac address.  multicast entry has no age time and
+ *      static bit, which has been set by software, unicast entry could be both auto learned and set by 
+ *      software. you had better set isAuth TRUE for general application because  IEEE 802.1x is usually
+ *      for unicast packet.portMask is 6-bit value, each bit represents one port, bit 0 corresponds to port 0
+ *      and bit 5 corresponds port 5.
+ */ 
+
+int32 rtl8306e_l2_multicastEntry_set(uint8 *macAddress, uint32 entry, uint32 isAuth, uint32 portMask) 
+{
+    uint32 regValue, index, pollcnt;
+    uint32 bitValue;
+
+    if ((NULL == macAddress) || (entry > RTL8306_LUT_ENTRY3) || (portMask > 0x3F ))
+        return FAILED;
+
+    /*For Muticast entry, MAC[47] is 1  */
+    if (!(macAddress[0] & 0x1))
+        return FAILED;
+    
+    /*Enalbe Lookup table access*/
+    rtl8306e_regbit_set(0, 16, 13, 0, 1);
+    
+    /*Write Data[55:48]*/
+    /*Multicast entry portmask bits is Data[54:52], Data[50:48]*/
+    regValue = ((isAuth ? 1: 0) << 7) | (portMask & 0x38) << 1 | (portMask & 0x7); 
+    rtl8306e_reg_set(4, 17, 0, regValue);
+    /*Write Data[47:32]*/
+    rtl8306e_reg_set(4, 18, 0, (macAddress[5] << 8) |macAddress[4]);
+    /*Write Data[31:16]*/
+    rtl8306e_reg_set(4, 19, 0, (macAddress[3] << 8) |macAddress[2]);
+    /*Write Data[15:0]*/
+    rtl8306e_reg_set(4, 20, 0, (macAddress[1] << 8) |macAddress[0]);
+
+    /*LUT index */
+    rtl8306e_l2_MacToIdx_get(macAddress, &index);
+
+    /*Write Command, 2-bit indicating four-way lies in highest bit of Entry_Addr[10:0]*/
+    regValue = (entry << 13) | (index << 4) | 0x2;
+    rtl8306e_reg_set(4, 16, 0, regValue);
+    
+    /*Waiting for write command done and prevent polling dead loop*/
+    for (pollcnt = 0; pollcnt < RTL8306_IDLE_TIMEOUT; pollcnt ++)
+    {
+        rtl8306e_regbit_get(4, 16, 1, 0, &bitValue);
+        if (!bitValue)
+          break;
+    }
+    
+    if (pollcnt == RTL8306_IDLE_TIMEOUT)
+        return FAILED;
+    
+    /*Disable Lookup table access*/
+    rtl8306e_regbit_set(0, 16, 13, 0, 0);
+    /*record it in software cache if define RTL8306_LUT_CACHE*/
+ #ifdef RTL8306_LUT_CACHE
+     memcpy(rtl8306_LutCache[ (index << 2) | entry].mac, macAddress, 6);
+     rtl8306_LutCache[ (index << 2) | entry].un.multicast.auth = isAuth;
+     rtl8306_LutCache[ (index << 2) | entry].un.multicast.portMask= portMask;
+ #endif
+    return SUCCESS;
+}
+
+/* Function Name:
+ *      rtl8306_getAsicLUTMulticastEntry
+ * Description:
+ *      Get LUT multicast entry
+ * Input:
+ *      entryAddr         -  Specify the LUT entry address(0~2047)
+
+ * Output:
+ *      macAddress      -  The read out multicast Mac address  
+ *      pIsAuth            -  the pointer of IEEE 802.1x authorized status
+ *      portMask          -  port mask 
+ * Return:
+ *      SUCCESS
+ *      FAILED
+ * Note:
+ *      Get multicast entry
+ */ 
+
+int32 rtl8306e_l2_multicastEntry_get(uint8 *macAddress, uint32 entryAddr, uint32 *pIsAuth, uint32 *pPortMask) 
+{
+    uint32 entryAddrHd;
+    uint32 regValue, pollcnt;
+    uint32 bitValue;
+
+    if ((NULL == macAddress) || (entryAddr > 0x7FF) ||(NULL == pIsAuth) || (NULL == pPortMask))
+        return FAILED;
+
+    /*Hardware data format, four-way info is the highest 2 bits of 11-bit entry info*/
+    entryAddrHd = (entryAddr >> 2) | ((entryAddr & 0x3) << 9);
+    
+    /*Enalbe Lookup table access*/
+    rtl8306e_regbit_set(0, 16, 13, 0, 1);
+    
+    /*Write Command*/
+    regValue = (entryAddrHd << 4) | 0x3;
+    rtl8306e_reg_set(4, 16, 0, regValue);
+    
+    /*Waiting for Read command done and prevent polling dead loop*/
+    for (pollcnt = 0; pollcnt < RTL8306_IDLE_TIMEOUT; pollcnt ++) 
+    {
+        rtl8306e_regbit_get(4, 16, 1, 0, &bitValue);
+        if (!bitValue)
+            break;
+    }
+    if (pollcnt == RTL8306_IDLE_TIMEOUT)
+        return FAILED;
+    
+    /*Read Data[55:48]*/
+    rtl8306e_reg_get(4, 17, 0, &regValue);
+    *pIsAuth = (regValue & 0x80 ? 1:0);
+    
+    /*Multicast entry portmask bits is Data[54:52], Data[50:48]*/
+    *pPortMask = ((regValue & 0x70) >> 4) << 3 | (regValue & 0x7);
+
+    rtl8306e_l2_IdxToMac_get(macAddress, &entryAddr);
+
+    return SUCCESS;
+}
+
+/* Function Name:
+ *      rtl8306e_l2_unicastMac_add
+ * Description:
+ *     Add an unicast mac address, software will detect empty entry
+ * Input:
+ *      macAddress      -  the mac to be saved in the entry  
+ *      age                 -  Specify age time
+ *      isStatic            -  TRUE(static entry), FALSE(dynamic entry)
+ *      isAuth              -  IEEE 802.1x authorized status
+ *      port                 -  the port which the mac address belongs to  
+ * Output:
+ *      pEntryaddr        -   the entry address (0 ~2047) which the unicast mac address is written into
+ * Return:
+ *      SUCCESS
+ *      FAILED
+ * Note:
+ *      Age time has 4 value :RTL8306_LUT_AGEOUT, RTL8306_LUT_AGE100(100s), 
+ *      RTL8306_LUT_AGE200(200s), RTL8306_LUT_AGE300(300s)
+ *      The lut has a 4-way entry of an index. If the macAddress has existed in the lut, it will update the entry,
+ *      otherwise the function will find an empty entry to put it.
+ *      When the index is full, it will find a dynamic & unauth unicast macAddress entry to replace with it. 
+ *      If the mac address has been written into LUT, function return value is SUCCESS,  *pEntryaddr is recorded the 
+ *      entry address of the Mac address stored.
+ *      If all the four entries can not be replaced, it will return a  RTL8306_LUT_FULL error, you can delete one of them 
+ *      and rewrite the unicast address.  
+ */ 
+
+int32 rtl8306e_l2_unicastMac_add(uint8 *macAddress, uint32 age, uint32 isStatic, uint32 isAuth, uint32 port, uint32 *pEntryaddr)
+{
+    int32 i;
+    uint8 macAddr[6];
+    uint32 index,entryaddr;
+    uint32 isStatic1,isAuth1,age1,port1;
+
+    /*check for macAddress. must be unicast address*/
+    if( (NULL == macAddress) || (macAddress[0] & 0x1))
+        return FAILED;
+
+    /*check port*/
+    if (port > 5)
+        return FAILED;
+
+    rtl8306e_l2_MacToIdx_get(macAddress, &index);
+
+    /*
+      *First scan four-ways, if the unicast entry has existed, only update the entry, that could 
+      *prevent two same Mac in four-ways; if the mac was not written into entry before, then scan 
+      *four-ways again, to Find an dynamic & unauthorized unicast entry which is auto learned, then  
+      *replace it with the multicast Mac addr. scanning sequence is from entry 3 to entry 0, because 
+      *priority of four way is entry 3 > entry 2 > entry 1 > entry 0
+      */
+    for (i = 3; i >= 0; i--) 
+    {
+        entryaddr = (index << 2) | (uint32)i;
+        if (rtl8306e_l2_unicastEntry_get(macAddr, entryaddr, &age1, &isStatic1, &isAuth1, &port1) != SUCCESS) 
+        {
+            return FAILED;
+        }
+        else if ((macAddress[0] == macAddr[0]) && (macAddress[1] == macAddr[1]) && 
+                   (macAddress[2] == macAddr[2]) && (macAddress[3] == macAddr[3]) &&
+                    (macAddress[4] == macAddr[4]) && (macAddress[5] == macAddr[5])) 
+        {
+            rtl8306e_l2_unicastEntry_set(macAddress, (uint32)i , age, isStatic, isAuth, port);
+            *pEntryaddr = entryaddr;
+            return SUCCESS;
+        }
+    }
+    
+    for (i = 3; i >= 0; i--) 
+    {
+        entryaddr = (index << 2) | (uint32)i ;
+        if (rtl8306e_l2_unicastEntry_get(macAddr, entryaddr, &age1, &isStatic1, &isAuth1, &port1) != SUCCESS) 
+        {
+            return FAILED;
+        }
+        else if (((macAddr[0] & 0x1) == 0) && (!isStatic1) && (!isAuth1))  
+        {
+            rtl8306e_l2_unicastEntry_set(macAddress, (uint32)i , age, isStatic, isAuth, port);
+            *pEntryaddr = entryaddr;
+            return SUCCESS;
+        }
+    }
+
+    /* four way are all full, return RTL8306_LUT_FULL*/
+    return RTL8306_LUT_FULL;
+}
+
+
+/* Function Name:
+ *      rtl8306e_l2_multicastMac_add
+ * Description:
+ *     Add an multicast mac address, software will detect empty entry
+ * Input:
+ *      macAddress      -  the mac to be saved in the entry  
+ *      isAuth              -  IEEE 802.1x authorized status
+ *      portMask          -  switch received the packet with the specified macAddress, 
+ *                                and forward it to the member port of portMask
+ * Output:
+ *      pEntryaddr        -   the entry address (0 ~2047) which the multicast mac address is written into
+ * Return:
+ *      SUCCESS
+ *      FAILED
+ * Note:
+ *      Add an multicast entry, it need not specify the 4-way like function rtl8306e_l2_multicastEntry_set,
+ *      if the mac address has written into LUT, function return value is SUCCESS,  *pEntryaddr is recorded the 
+ *      entry address of the Mac address stored, if  4-way entries are all written by cpu, this mac address could 
+ *      not written into LUT and the function return value is  RTL8306_LUT_FULL, but if the Mac address has exist, 
+ *      the port mask will be updated. When function return value is RTL8306_LUT_FULL, you can delete one of them 
+ *      and rewrite the multicast address. 
+ */ 
+int32  rtl8306e_l2_multicastMac_add(uint8 *macAddr,uint32 isAuth, uint32 portMask, uint32 *pEntryaddr) 
+{
+    int32  i;
+    uint8 macAddress[4][6];
+    uint32 index, entryAddress[4], age[4];
+    uint32 isStatic[4], isAuthority[4];
+    uint32 port[4];
+    uint32 isFull = TRUE;
+
+
+    if ((NULL == macAddr) || (!(macAddr[0] & 0x1)) || (NULL == pEntryaddr))
+        return FAILED;
+
+    rtl8306e_l2_MacToIdx_get(macAddr, &index);
+
+    /*
+      *First scan four-ways, if the multicast entry has existed, only update the entry, that could 
+      *prevent two same Mac in four-ways; if the mac was not written into entry before, then scan 
+      *four-ways again, to Find an dynamic & unauthorized unicast entry which is auto learned, then  
+      *replace it with the multicast Mac addr. scanning sequence is from entry 3 to entry 0, because priority
+      *of four way is entry 3 > entry 2 > entry 1 > entry 0
+      */
+    for (i = 3; i >= 0; i--) 
+    {
+        entryAddress[i] = (index << 2) | (uint32)i;
+#ifdef RTL8306_LUT_CACHE
+        if (rtl8306e_fastGetAsicLUTUnicastEntry(macAddress[i], entryAddress[i], &age[i], &isStatic[i], &isAuthority[i], &port[i]) != SUCCESS)
+#else
+        if (rtl8306e_l2_unicastEntry_get(macAddress[i], entryAddress[i], &age[i], &isStatic[i], &isAuthority[i], &port[i]) != SUCCESS) 
+#endif
+        {
+            return FAILED;
+        }
+        else if ((macAddr[0] == macAddress[i][0]) && (macAddr[1] == macAddress[i][1]) && 
+                    (macAddr[2] == macAddress[i][2]) && (macAddr[3] == macAddress[i][3]) &&
+                    (macAddr[4] == macAddress[i][4]) && (macAddr[5] == macAddress[i][5])) 
+        {
+            rtl8306e_l2_multicastEntry_set(macAddr, (uint32)i, isAuth, portMask);
+            *pEntryaddr = entryAddress[i];
+            isFull = FALSE;
+            return SUCCESS;
+        }
+    }
+    
+    for (i = 3; i >= 0; i--) 
+    {
+        if (((macAddress[i][0] & 0x1) == 0) && (!isStatic[i]) && (!isAuthority[i])) 
+        {
+            rtl8306e_l2_multicastEntry_set(macAddr, (uint32)i , isAuth, portMask);
+            *pEntryaddr = entryAddress[i];
+            isFull = FALSE;
+            break;
+        }
+    }
+
+    /*If four way are all full, return RTL8306_LUT_FULL*/
+    if (isFull) 
+    {
+        *pEntryaddr = 10000;
+        return RTL8306_LUT_FULL;
+    }
+    return SUCCESS;
+
+}
+
+/* Function Name:
+ *      rtl8306e_l2_mac_get
+ * Description:
+ *      Get an mac address information
+ * Input:
+ *      macAddress         -   the mac to be find in LUT  
+ * Output:
+ *      pIsStatic             -   the pointer of static or dynamic entry, for unicast mac address
+ *      pIsAuth               -   the pointer of IEEE 802.1x authorized status
+ *      pPortInfo             -   for unicast mac, it is the pointer of the port the mac belongs to;
+ *                                    for multicast mac, it is the pointer of portmask the mac forwarded to;
+ *      pEntryaddr           -   the entry address (0 ~2047) which the mac address is written into
+ * Return:
+ *      SUCCESS
+ *      FAILED
+ *      RTL8306_LUT_NOTEXIST
+ * Note:
+ *      use this API to get a mac address information in LUT.
+ */ 
+int32 rtl8306e_l2_mac_get(uint8 *macAddr, uint32 *pIsStatic, uint32 *pIsAuth, uint32 *pPortInfo, uint32 *pEntryaddr) 
+{
+    int32  i;
+    uint8 macAddress[6];
+    uint32 index, entryAddress, age;
+    uint32 isStatic, isAuth;
+    uint32 port, portmask;
+    uint32 isHit ;
+
+    if((NULL == macAddr) || (NULL == pIsAuth) || (NULL == pPortInfo) || (NULL == pEntryaddr))
+        return FAILED;
+    
+    isHit = FALSE;
+    
+    rtl8306e_l2_MacToIdx_get(macAddr, &index);
+
+    /*scanning sequence is from entry 3 to entry 0, because priority
+      *of four way is entry 3 > entry 2 > entry 1 > entry 0
+      */
+    for (i = 3; i >= 0; i--) 
+    {
+        entryAddress = (index << 2) |(uint32) i;
+        if (rtl8306e_l2_unicastEntry_get(macAddress, entryAddress, &age, &isStatic, &isAuth, &port) != SUCCESS) 
+        {
+            return FAILED;
+        }
+        else if ((macAddr[0] == macAddress[0]) && (macAddr[1] == macAddress[1]) && 
+                    (macAddr[2] == macAddress[2]) && (macAddr[3] == macAddress[3]) &&
+                    (macAddr[4] == macAddress[4]) && (macAddr[5] == macAddress[5])) 
+        {
+            if(macAddr[0] & 0x1)
+            {
+                rtl8306e_l2_multicastEntry_get(macAddress, entryAddress, &isAuth, &portmask);
+                *pIsStatic = TRUE;
+                *pIsAuth = isAuth;
+                *pPortInfo = portmask;
+            }
+            else 
+            {
+                *pIsStatic = isStatic;
+                *pIsAuth = isAuth;
+                *pPortInfo = port;
+                if ((RTL8306_LUT_AGEOUT == age) && !isStatic && !isAuth)
+                    return  RTL8306_LUT_NOTEXIST;                                                                  
+            }
+
+            *pEntryaddr = entryAddress;
+            isHit = TRUE;
+            return SUCCESS;
+        }
+    }
+
+    if(!isHit)
+        return RTL8306_LUT_NOTEXIST;
+
+    return SUCCESS;
+}
+    
+
+/* Function Name:
+ *      rtl8306e_l2_mac_del
+ * Description:
+ *     Delete the specified Mac address, could be both unicast and multicast 
+ * Input:
+ *      macAddress      -  the Mac address(unicast or multicast) to be delete  
+ *                                and forward it to the member port of portMask
+ * Output:
+ *      pEntryaddr        -  entry address from which the Mac address is deleted
+ * Return:
+ *      SUCCESS
+ *      FAILED
+ * Note:
+ *      Use this function to delete a Mac address, it does not require to specify the 
+ *      entry address, if the Mac has existed in the LUT, it will be deleted and function
+ *      return value is SUCCESS, *pEntryaddr is recorded the entry address of the Mac 
+ *      address stored. if the Mac does not existed in the LUT, function return value is
+ *      RTL8306_LUT_NOTEXIST, and *pEntryaddr equals 10000.
+ */ 
+int32 rtl8306e_l2_mac_del(uint8 *macAddr, uint32 *pEntryaddr)
+{
+    uint32  i, port, portmask;
+    uint8 macAddr1[6];
+    uint32 index, entryaddr1, age;
+    uint32 isStatic, isAuth;
+    uint32 isHit = FALSE;
+    uint32 hashStatus;
+    
+    if ((NULL == macAddr) || (NULL == pEntryaddr))
+        return FAILED;
+
+    rtl8306e_l2_MacToIdx_get(macAddr, &index);
+    
+    if (!(macAddr[0] & 0x1)) 
+    {  
+        /*Delete an unicast entry*/
+        for (i = 4; i >= 1; i --) 
+        {
+            entryaddr1 = (index << 2) | (i - 1);
+            if(rtl8306e_l2_unicastEntry_get(macAddr1, entryaddr1, &age, &isStatic, &isAuth, &port) != SUCCESS) 
+                return FAILED;
+            else if (macAddr[0] ==macAddr1[0] && macAddr[1] ==macAddr1[1] 
+                       && macAddr[2] ==macAddr1[2] && macAddr[3] ==macAddr1[3]
+                       && macAddr[4] ==macAddr1[4] && macAddr[5] ==macAddr1[5]) 
+            {  
+                rtl8306e_l2_unicastEntry_set(macAddr, i -1, 0, FALSE, FALSE, port);
+                *pEntryaddr = entryaddr1;
+                isHit = TRUE;
+            } 
+        }
+    }
+    else 
+    {
+        /*Delet an multicast entry*/
+        for (i = 4; i >= 1; i --)
+        {
+            entryaddr1 = (index << 2) | (i - 1);
+#ifdef RTL8306_LUT_CACHE
+            if(rtl8306e_fastGetAsicLUTMulticastEntry(macAddr1, entryaddr1, &isAuth, &portmask) == FAILED) 
+#else
+            if(rtl8306e_l2_multicastEntry_get(macAddr1, entryaddr1, &isAuth, &portmask) != SUCCESS)
+#endif
+                return FAILED;
+            else if (macAddr[0] ==macAddr1[0] && macAddr[1] ==macAddr1[1] 
+                       && macAddr[2] ==macAddr1[2] && macAddr[3] ==macAddr1[3]
+                       && macAddr[4] ==macAddr1[4] && macAddr[5] ==macAddr1[5]) 
+            {  
+               /*
+                 * Turn multicast address to unicast address. If new hash is used 
+                 * bit 24 will be performed not operation to make the Index unchange
+                 */
+                rtl8306e_regbit_get(1, 23, 12, 0, &hashStatus);            
+
+                if (hashStatus) 
+                {
+                    macAddr1[0] = macAddr1[0] & 0xFE; 
+                    macAddr1[2] ^= 0x80;
+                } 
+                else 
+                {
+                    macAddr1[0] = macAddr1[0] & 0xFE; 
+                }
+                
+                if (rtl8306e_l2_unicastEntry_set(macAddr1, (uint32)(i -1), 0, FALSE, FALSE, 0) != SUCCESS)
+                    return FAILED;
+                *pEntryaddr = entryaddr1;
+                isHit = TRUE;
+            } 
+        }
+
+    }
+
+    if (!isHit) 
+    {
+        *pEntryaddr = 10000;
+        return RTL8306_LUT_NOTEXIST;
+    }
+    else 
+        return SUCCESS;
+
+}
+
+/* Function Name:
+ *      rtl8306e_l2_portMacLimit_set
+ * Description:
+ *      Set per port mac limit ability and auto learning limit number
+ * Input:
+ *      port         -  port number (0 ~ 5)  
+ *      enabled    - TRUE of FALSE  
+ *      macCnt    - auto learning MAC limit number
+ * Output:
+ *      none
+ * Return:
+ *      SUCCESS
+ *      FAILED
+ * Note:
+ */ 
+int32 rtl8306e_l2_portMacLimit_set(uint32 port, uint32 enabled, uint32 macCnt) 
+{
+    uint32 regValue;
+
+    if (port > RTL8306_PORT5)
+        return FAILED;
+    if (5 == port)
+        port ++;
+
+    if (0 == port)
+    {
+        rtl8306e_regbit_set(0, 26, 12, 3, enabled ? 1 : 0);
+        rtl8306e_reg_get(0, 27, 3, &regValue);
+        regValue &= ~(0x1F << 11);
+        regValue |= ((macCnt & 0x1F) << 11);
+        rtl8306e_reg_set(0, 27, 3, regValue);
+    }
+    else
+    {
+        rtl8306e_regbit_set(port, 30, 15, 1, enabled ? 1 : 0);
+        rtl8306e_reg_get(port, 31, 1, &regValue);
+        regValue &= ~(0x1F << 11);
+        regValue |= ((macCnt & 0x1F) << 11);
+        rtl8306e_reg_set(port, 31, 1, regValue);
+    }
+ 
+    return SUCCESS;
+}
+
+/* Function Name:
+ *      rtl8306e_l2_portMacLimit_get
+ * Description:
+ *      Get per port mac limit ability and auto learning limit number
+ * Input:
+ *      port         -  port number (0 ~ 5)  
+ * Output:
+ *      pEnabled    -  enabled or disabled the port mac limit
+ *      pMacCnt     -  auto learning MAC limit number
+ * Return:
+ *      SUCCESS
+ *      FAILED
+ * Note:
+ */ 
+int32 rtl8306e_l2_portMacLimit_get(uint32 port, uint32 *pEnabled, uint32 *pMacCnt) 
+{
+    uint32 regValue;
+    uint32 bitValue;
+
+    if (port > RTL8306_PORT5 || NULL == pEnabled || NULL == pMacCnt)
+        return FAILED;
+    if (5 == port)
+        port ++;
+
+    if (0 == port)
+    {
+        rtl8306e_regbit_get(0, 26, 12, 3, &bitValue);
+        *pEnabled = bitValue ? TRUE : FALSE;
+        rtl8306e_reg_get(0, 27, 3, &regValue);
+        *pMacCnt = (regValue & (0x1F << 11)) >> 11;
+    }
+    else
+    {
+        rtl8306e_regbit_get(port, 30, 15, 1, &bitValue);
+        *pEnabled = bitValue ? TRUE : FALSE;
+        rtl8306e_reg_get(port, 31, 1, &regValue);
+        *pMacCnt = (regValue & (0x1F << 11)) >> 11;
+    }
+ 
+    return SUCCESS;
+}
+
+/* Function Name:
+ *      rtl8306e_l2_systemMacLimit_set
+ * Description:
+ *      Set the system mac limit ability and auto learning limit number
+ * Input:
+ *      enabled    - TRUE of FALSE  
+ *      macCnt    - system auto learning MAC limit number
+ *      mergMask  -  port mask for the ports merged to system mac limit
+ * Output:
+ *      none
+ * Return:
+ *      SUCCESS
+ *      FAILED
+ * Note:
+ *      Besides per port mac limit function, 8306E also supports system MAC limit function.
+ *      mergMask is to decide whitch ports are limited by system MAC limit function.
+ *      For example, when system mac limit is enabled, and mergMask is 0x15(0b010101),
+ *      that means the auto learning MAC number of port 0, port 2 and port 4 will also be
+ *      influenced by system MAC limit.    
+ */ 
+int32 rtl8306e_l2_systemMacLimit_set(uint32 enabled, uint32 macCnt, uint32 mergMask) 
+{
+    uint32 regValue;
+
+    rtl8306e_regbit_set(0, 26, 11, 3, enabled ? 1 : 0);
+    
+    rtl8306e_reg_get(0, 31, 0, &regValue);
+    regValue &= ~(0x7F);
+    regValue |= (macCnt & 0x7F) ;
+    rtl8306e_reg_set(0, 31, 0, regValue);
+    
+    rtl8306e_reg_get(0, 31, 0, &regValue);
+    regValue &= ~(0x3F << 10);
+    regValue |= ((mergMask & 0x3F) << 10);
+    rtl8306e_reg_set(0, 31, 0, regValue);
+ 
+    return SUCCESS;
+}
+
+/* Function Name:
+ *      rtl8306e_l2_systemMacLimit_get
+ * Description:
+ *      Get the system mac limit ability and auto learning limit number
+ * Input:
+ *      none
+ * Output:
+ *      pEnabled    -  enabled or disabled the system mac limit
+ *      pMacCnt    -   system auto learning MAC limit number
+ *      pMergMask  -  port mask for the ports merged to system mac limit
+ * Return:
+ *      SUCCESS
+ *      FAILED
+ * Note:
+ */ 
+int32 rtl8306e_l2_systemMacLimit_get(uint32 *pEnabled, uint32 *pMacCnt, uint32 *pMergMask) 
+{
+    uint32 regValue;
+    uint32 bitValue;
+
+    rtl8306e_regbit_get(0, 26, 11, 3, &bitValue);
+    *pEnabled = bitValue ? TRUE : FALSE;
+    
+    rtl8306e_reg_get(0, 31, 0, &regValue);
+    *pMacCnt = (regValue & 0x7F);
+    
+    rtl8306e_reg_get(0, 31, 0, &regValue);
+    *pMergMask = (regValue & (0x3F << 10)) >> 10;
+    
+    return SUCCESS;
+}
+
+/* Function Name:
+ *      rtl8306e_l2_macLimitAction_set
+ * Description:
+ *      Set the action taken by switch when auto learning MAC reach to the limit number
+ * Input:
+ *      action      -  the action taken when auto learning MAC reach to the max value 
+ * Output:
+ *      none
+ * Return:
+ *      SUCCESS
+ *      FAILED
+ * Note:
+ */ 
+int32 rtl8306e_l2_macLimitAction_set(uint32 action) 
+{
+    if (RTL8306_ACT_DROP == action)
+        rtl8306e_regbit_set(0, 31, 9, 0, 0);
+    else if (RTL8306_ACT_TRAPCPU == action)
+        rtl8306e_regbit_set(0, 31, 9, 0, 1);
+    else
+        return FAILED;
+
+    return SUCCESS;
+}
+
+/* Function Name:
+ *      rtl8306e_l2_macLimitAction_get
+ * Description:
+ *      Get the action taken by switch when auto learning MAC reach to the limit number
+ * Input:
+ *      pAction      -  the action taken when auto learning MAC reach to the max value
+ * Output:
+ *      none
+ * Return:
+ *      SUCCESS
+ *      FAILED
+ * Note:
+ */ 
+int32 rtl8306e_l2_macLimitAction_get(uint32 *pAction) 
+{
+    uint32 bitValue;
+
+    if (NULL == pAction)
+        return FAILED;
+    
+    rtl8306e_regbit_get(0, 31, 9, 0, &bitValue);
+    if (bitValue)
+        *pAction = RTL8306_ACT_TRAPCPU;
+    else
+        *pAction = RTL8306_ACT_DROP;
+
+    return SUCCESS;
+}
+
+/* Function Name:
+ *      rtl8306e_stp_set
+ * Description:
+ *      Set IEEE 802.1d port state
+ * Input:
+ *      port   -  Specify port number (0 ~ 5)
+ *      state -   Specify port state
+ * Output:
+ *      none
+ * Return:
+ *      SUCCESS
+ *      FAILED
+ * Note:
+ *     There are 4 port state:
+ *         RTL8306_SPAN_DISABLE   - Disable state
+ *         RTL8306_SPAN_BLOCK      - Blocking state
+ *         RTL8306_SPAN_LEARN      - Learning state
+ *         RTL8306_SPAN_FORWARD - Forwarding state
+ */ 
+int32 rtl8306e_stp_set(uint32 port, uint32 state) 
+{
+    uint32 regValue;
+
+    if ((port > RTL8306_PORT5) || (state > RTL8306_SPAN_FORWARD))
+        return FAILED;
+
+    /*Enable BPDU to trap to cpu, BPDU could not be flooded to all port*/
+    rtl8306e_regbit_set(2, 21, 6, 3, 1);
+    rtl8306e_reg_get(4, 21, 3, &regValue);
+    regValue = (regValue & (~(0x3 << (2*port)))) | (state << (2*port));
+    rtl8306e_reg_set(4, 21, 3, regValue);
+
+#ifdef RTL8306_TBLBAK
+    rtl8306_TblBak.dot1DportCtl[port] = (uint8)state;
+#endif
+    return SUCCESS;
+}
+
+/* Function Name:
+ *      rtl8306e_stp_get
+ * Description:
+ *      Get IEEE 802.1d port state
+ * Input:
+ *      port    -  Specify port number (0 ~ 5)
+ * Output:
+ *      pState -  get port state
+ * Return:
+ *      SUCCESS
+ *      FAILED
+ * Note:
+ *     There are 4 port state:
+ *         RTL8306_SPAN_DISABLE   - Disable state
+ *         RTL8306_SPAN_BLOCK      - Blocking state
+ *         RTL8306_SPAN_LEARN      - Learning state
+ *         RTL8306_SPAN_FORWARD - Forwarding state
+ */ 
+int32 rtl8306e_stp_get(uint32 port, uint32 *pState) 
+{
+    uint32 regValue;
+
+    if ((port > RTL8306_PORT5) || (NULL == pState))
+        return FAILED;
+    
+    rtl8306e_reg_get(4, 21, 3, &regValue);
+    *pState = (regValue & (0x3 << (2*port))) >> (2*port);
+    return SUCCESS;
+}
+
+/* Function Name:
+ *      rtl8306e_dot1x_portBased_set
+ * Description:
+ *      Set IEEE802.1x port-based access control
+ * Input:
+ *      port         -  Specify port number (0 ~ 5)
+ *      enabled    -   enable port-based access control
+ *      isAuth      -   Authorized or unauthorized state 
+ *      direction   -    set IEEE802.1x port-based control direction
+ * Output:
+ *      none
+ * Return:
+ *      SUCCESS
+ *      FAILED
+ * Note:
+ *     There are two IEEE802.1x port state:
+ *         RTL8306_PORT_AUTH      - authorized
+ *         RTL8306_PORT_UNAUTH  - unauthorized
+ *
+ *     There are also two 802.1x port-based control direction:
+ *         RTL8306_PORT_BOTHDIR - if port-base access control is enabled, 
+ *                                              forbid forwarding this port's traffic to unauthorized port
+ *         RTL8306_PORT_INDIR     - if port-base access control is enabled, permit forwarding this
+ *                                              port's traffic to unauthorized port
+ */ 
+int32 rtl8306e_dot1x_portBased_set(uint32 port, uint32 enabled, uint32 isAuth, uint32 direction)
+{
+
+    if (port > RTL8306_PORT5)
+        return FAILED;
+    
+    /*Port 5 corresponding PHY6*/
+    if (RTL8306_PORT5 == port)  
+        port ++ ;  
+    
+    if (!enabled) 
+    {
+        rtl8306e_regbit_set(port, 17, 8, 2, 0);
+        rtl8306e_regbit_set(port, 17, 6, 2, isAuth == RTL8306_PORT_AUTH ? 1:0);
+        rtl8306e_regbit_set(port, 17, 7, 2, direction == RTL8306_PORT_BOTHDIR ? 0:1);
+    } 
+    else 
+    {
+        rtl8306e_regbit_set(port, 17, 8, 2, 1);
+        rtl8306e_regbit_set(port, 17, 6, 2, isAuth == RTL8306_PORT_AUTH ? 1:0);
+        rtl8306e_regbit_set(port, 17, 7, 2, direction == RTL8306_PORT_BOTHDIR ? 0:1);
+    }
+
+    return SUCCESS;
+}
+
+/* Function Name:
+ *      rtl8306e_dot1x_portBased_set
+ * Description:
+ *      Set IEEE802.1x port-based access control
+ * Input:
+ *      port         -  Specify port number (0 ~ 5)
+ * Output:
+ *      pEnabled    - the pointer of port-based access control status
+ *      pIsAuth      - the pointer of authorized or unauthorized state 
+ *      pDirection   - the pointer of IEEE802.1x port-based control direction
+ * Return:
+ *      SUCCESS
+ *      FAILED
+ * Note:
+ *     There are two IEEE802.1x port state:
+ *         RTL8306_PORT_AUTH      - authorized
+ *         RTL8306_PORT_UNAUTH  - unauthorized
+ *
+ *     There are also two 802.1x port-based control direction:
+ *         RTL8306_PORT_BOTHDIR - if port-base access control is enabled, 
+ *                                              forbid forwarding this port's traffic to unauthorized port
+ *         RTL8306_PORT_INDIR     - if port-base access control is enabled, permit forwarding this
+ *                                              port's traffic to unauthorized port
+ */ 
+
+int32 rtl8306e_dot1x_portBased_get(uint32 port, uint32 *pEnabled, uint32 *pIsAuth, uint32 *pDirection) 
+{
+    uint32 bitValue;
+
+    if ((port > RTL8306_PORT5) || (NULL == pEnabled) || (NULL == pIsAuth) || (NULL == pDirection)) 
+        return FAILED;
+    
+    /*Port 5 corresponding PHY6*/
+    if (port == RTL8306_PORT5 )  
+        port ++ ;  
+    
+    rtl8306e_regbit_get(port, 17, 8, 2, &bitValue);
+    *pEnabled = (bitValue ? TRUE : FALSE);
+    rtl8306e_regbit_get(port, 17, 6, 2, &bitValue);
+    *pIsAuth = (bitValue ? RTL8306_PORT_AUTH : RTL8306_PORT_UNAUTH);
+    rtl8306e_regbit_get(port, 17, 7, 2, &bitValue);
+    *pDirection = (bitValue ? RTL8306_PORT_INDIR : RTL8306_PORT_BOTHDIR);
+    return SUCCESS;
+} 
+
+/* Function Name:
+ *      rtl8306e_dot1x_macBased_set
+ * Description:
+ *      Set IEEE802.1x port-based access control
+ * Input:
+ *      port         -  Specify port number (0 ~ 5)
+ * Output:
+ *      enabled    - Enable the port Mac-based access control ability
+ *      direction   -  IEEE802.1x mac-based access control direction
+ * Return:
+ *      SUCCESS
+ *      FAILED
+ * Note:
+ *      the mac address authentication status is saved in L2 table entry,
+ *      it should be set by software.
+ *      there are also two mac-based control directions which are not per 
+ *      port but global configurtion:
+ *      RTL8306_MAC_BOTHDIR - if Mac-based access control is enabled, packet with 
+ *      unauthorized DA will be dropped.
+ *      RTL8306_MAC_INDIR   - if Mac-based access control is enabled, packet with 
+ *      unauthorized DA will pass mac-based access control igress rule.
+ */ 
+int32 rtl8306e_dot1x_macBased_set(uint32 port, uint32 enabled, uint32 direction)
+{
+
+    if (port > RTL8306_PORT5)
+        return FAILED;
+    
+    /*Port 5 corresponding PHY6*/
+    if (RTL8306_PORT5 == port)  
+        port ++ ;  
+    
+    if (!enabled) 
+    {
+        rtl8306e_regbit_set(port, 17, 9, 2, 0);
+        return SUCCESS;
+    } 
+    else 
+    {
+        rtl8306e_regbit_set(port, 17, 9, 2, 1);
+        rtl8306e_regbit_set(2, 22, 7, 3, direction == RTL8306_MAC_BOTHDIR ?  0 : 1 );
+    }
+    return SUCCESS;
+}
+
+
+/* Function Name:
+ *      rtl8306e_dot1x_macBased_set
+ * Description:
+ *      Set IEEE802.1x port-based access control
+ * Input:
+ *      port         -  Specify port number (0 ~ 5)
+ * Output:
+ *      enabled    - Enable the port Mac-based access control ability
+ *      direction   -  IEEE802.1x mac-based access control direction
+ * Return:
+ *      SUCCESS
+ *      FAILED
+ * Note:
+ *      the mac address authentication status is saved in L2 table entry,
+ *      it should be set by software.
+ *      there are also two mac-based control directions which are not per 
+ *      port but global configurtion:
+ *      RTL8306_MAC_BOTHDIR - if Mac-based access control is enabled, packet with 
+ *      unauthorized DA will be dropped.
+ *      RTL8306_MAC_INDIR   - if Mac-based access control is enabled, packet with 
+ *      unauthorized DA will pass mac-based access control igress rule.
+ */ 
+ 
+int32 rtl8306e_dot1x_macBased_get(uint32 port, uint32 *pEnabled, uint32 *pDirection) 
+{
+    uint32 bitValue;
+
+    if ((port > RTL8306_PORT5) || (NULL == pEnabled) || (NULL == pDirection))
+        return FAILED;
+    
+    if (port  < RTL8306_PORT5 ) 
+        rtl8306e_regbit_get(port, 17, 9, 2, &bitValue);
+    else 
+        rtl8306e_regbit_get(6, 17, 9, 2, &bitValue);
+    *pEnabled = (bitValue ? TRUE : FALSE) ; 
+    rtl8306e_regbit_get(2, 22, 7, 3, &bitValue);
+    *pDirection = (bitValue ? RTL8306_PORT_INDIR : RTL8306_PORT_BOTHDIR);
+    return SUCCESS;
+}
+
+/* Function Name:
+ *      rtl8306e_trap_igmpCtrlPktAction_set
+ * Description:
+ *      Set IGMP/MLD trap function
+ * Input:
+ *      type         -  Specify IGMP/MLD or PPPOE
+ *      action       -  Action could be normal forward or trap
+ * Output:
+ *      none
+ * Return:
+ *      SUCCESS
+ *      FAILED
+ * Note:
+ *     type could be:
+ *          RTL8306_IGMP   - igmp packet without pppoe header 
+ *          RTL8306_MLD    - mld packet  without pppoe header
+ *          RTL8306_PPPOE_IGMPMLD - pppoe packet if enable trap RTL8306_IGMP 
+ *                                   or RTL8306_MLD whether pppoe packet 
+ *                                   should be trapped. In some application,
+ *                                   igmp and mld message is encapsulated in pppoed
+ *                                   packet.
+ *         
+ *      action could be:
+ *          RTL8306_ACT_PERMIT    - normal forward
+ *          RTL8306_ACT_TRAPCPU  - trap to cpu
+ */ 
+
+int32 rtl8306e_trap_igmpCtrlPktAction_set(uint32 type, uint32 action)
+{    
+    switch(type)
+    {
+        case RTL8306_IGMP:
+            if (RTL8306_ACT_PERMIT == action)
+            {
+                rtl8306e_regbit_set(2, 21, 14, 3, 0);
+            }
+            else if (RTL8306_ACT_TRAPCPU == action)
+            {
+                rtl8306e_regbit_set(2, 21, 14, 3, 1);                
+            }
+            else
+            {
+                return FAILED;
+            }            
+            break;
+            
+        case RTL8306_MLD:
+            if (RTL8306_ACT_PERMIT == action)
+            {
+                rtl8306e_regbit_set(2, 21, 13, 3, 0);
+            }
+            else if (RTL8306_ACT_TRAPCPU == action)
+            {
+                rtl8306e_regbit_set(2, 21, 13, 3, 1);                
+            }
+            else
+            {
+                return FAILED;
+            }            
+            
+            break;
+
+         case RTL8306_PPPOE_IGMPMLD:
+            if (RTL8306_ACT_PERMIT == action)
+            {
+                rtl8306e_regbit_set(2, 22, 4, 3, 1);
+            }
+            else if (RTL8306_ACT_TRAPCPU == action)
+            {
+                rtl8306e_regbit_set(2, 22, 4, 3, 0);                
+            }
+            else
+            {
+                return FAILED;
+            }                        
+            break;
+            
+         default:
+            return FAILED;
+           
+    }
+
+    return SUCCESS;
+}
+
+
+/* Function Name:
+ *      rtl8306e_trap_igmpCtrlPktAction_get
+ * Description:
+ *      Get IGMP/MLD trap setting
+ * Input:
+ *      type         -  Specify IGMP/MLD or PPPOE
+ * Output:
+ *      pAction     -  the pointer of action could be normal forward or trap
+ * Return:
+ *      SUCCESS
+ *      FAILED
+ * Note:
+ *     type could be:
+ *          RTL8306_IGMP   - igmp packet without pppoe header 
+ *          RTL8306_MLD    - mld packet  without pppoe header
+ *          RTL8306_PPPOE_IGMPMLD - pppoe packet if enable trap RTL8306_IGMP 
+ *                                   or RTL8306_MLD whether pppoe packet 
+ *                                   should be trapped. In some application,
+ *                                   igmp and mld message is encapsulated in pppoed
+ *                                   packet.
+ *      action could be:
+ *          RTL8306_ACT_PERMIT    - normal forward
+ *          RTL8306_ACT_TRAPCPU  - trap to cpu
+ */ 
+
+int32 rtl8306e_trap_igmpCtrlPktAction_get(uint32 type, uint32 *pAction)
+{
+    uint32 regval;
+
+    if (NULL == pAction)
+        return FAILED;
+    
+    switch(type)
+    {
+        case RTL8306_IGMP:
+            rtl8306e_regbit_get(2, 21, 14, 3, &regval);
+            *pAction = regval ? RTL8306_ACT_TRAPCPU : RTL8306_ACT_PERMIT;
+            break;            
+        case RTL8306_MLD:
+            rtl8306e_regbit_get(2, 21, 13, 3, &regval);
+            *pAction = regval ? RTL8306_ACT_TRAPCPU : RTL8306_ACT_PERMIT;            
+            break;
+         case RTL8306_PPPOE_IGMPMLD:
+            rtl8306e_regbit_get(2, 22, 4, 3, &regval);
+            *pAction = regval ?  RTL8306_ACT_PERMIT : RTL8306_ACT_TRAPCPU;
+            break;            
+         default:
+            return FAILED;           
+    }
+    return SUCCESS;
+}
+
+
+/* Function Name:
+ *      rtl8306e_trap_unknownIPMcastPktAction_set
+ * Description:
+ *      Set unknown ip multicast drop or normal forward
+ * Input:
+ *      type         -  Specify ipv4 or ipv6 unkown multicast
+ *      action       -  drop or normal forward
+ * Output:
+ *      none
+ * Return:
+ *      SUCCESS
+ *      FAILED
+ * Note:
+ *      type coulde be:
+ *          RTL8306_IPV4_MULTICAST - ipv4 unknown multicast
+ *          RTL8306_IPV6_MULTICAST - ipv6 unknown multicast
+ *      action could be:
+ *          RTL8306_ACT_DROP      - drop 
+ *          RTL8306_ACT_PERMIT   - normal forward
+ */  
+int32 rtl8306e_trap_unknownIPMcastPktAction_set(uint32 type, uint32 action)
+{    
+    switch(type)
+    {
+        case RTL8306_IPV4_MULTICAST:
+            if(RTL8306_ACT_DROP == action)
+                rtl8306e_regbit_set(4, 21, 9, 0, 1);
+            else if (RTL8306_ACT_PERMIT == action)
+                rtl8306e_regbit_set(4, 21, 9, 0, 0);
+            break;
+            
+        case RTL8306_IPV6_MULTICAST:
+            if(RTL8306_ACT_DROP == action)
+                rtl8306e_regbit_set(4, 21, 8, 0, 1);
+            else if (RTL8306_ACT_PERMIT == action)
+                rtl8306e_regbit_set(4, 21, 8, 0, 0);                                                
+            break;
+            
+        default:
+            return FAILED;
+    }
+
+    return SUCCESS;
+}
+
+
+/* Function Name:
+ *      rtl8306e_trap_unknownIPMcastPktAction_get
+ * Description:
+ *      Get unknown ip multicast drop or normal forward
+ * Input:
+ *      type         -  Specify ipv4 or ipv6 unkown multicast
+ * Output:
+ *      pAction     -  the pointer of drop or normal forward
+ * Return:
+ *      SUCCESS
+ *      FAILED
+ * Note:
+ *      type coulde be:
+ *          RTL8306_IPV4_MULTICAST - ipv4 unknown multicast
+ *          RTL8306_IPV6_MULTICAST - ipv6 unknown multicast
+ *      action could be:
+ *          RTL8306_ACT_DROP      - drop
+ *          RTL8306_ACT_PERMIT   - normal forward
+ */ 
+
+int32 rtl8306e_trap_unknownIPMcastPktAction_get(uint32 type, uint32 *pAction)
+{
+    uint32 regval;
+    
+    if (NULL == pAction)
+        return FAILED;
+
+    switch(type)
+    {
+        case RTL8306_IPV4_MULTICAST:
+            rtl8306e_regbit_get(4, 21, 9, 0, &regval);
+            *pAction = regval ? RTL8306_ACT_DROP: RTL8306_ACT_PERMIT;
+            break;
+        case RTL8306_IPV6_MULTICAST:
+            rtl8306e_regbit_get(4, 21, 8, 0, &regval);
+            *pAction = regval ? RTL8306_ACT_DROP: RTL8306_ACT_PERMIT;            
+            break;
+         default:
+            return FAILED;
+    }
+
+    return SUCCESS;
+}
+
+/* Function Name:
+ *      rtl8306e_trap_abnormalPktAction_set
+ * Description:
+ *      set abnormal packet action 
+ * Input:
+ *      type         -  abnormal packet type
+ *      action       -  drop or trap to cpu
+ * Output:
+ *      none
+ * Return:
+ *      SUCCESS
+ *      FAILED
+ * Note:
+ *      type coulde be:
+ *          RTL8306_UNMATCHVID   - vlan-tagged packet, vid dismatch vlan table 
+ *          RTL8306_DOT1XUNAUTH - 802.1x authentication fail packet
+ *      action could be:
+ *          RTL8306_ACT_DROP       - drop 
+ *          RTL8306_ACT_TRAPCPU  - trap to cpu
+ */ 
+
+int32 rtl8306e_trap_abnormalPktAction_set(uint32 type,  uint32 action)
+{
+    switch(type)
+    {
+        case RTL8306_UNMATCHVID:            
+            if(RTL8306_ACT_DROP == action)
+                rtl8306e_regbit_set(2, 22, 6, 3, 1);
+            else if (RTL8306_ACT_TRAPCPU == action)
+                rtl8306e_regbit_set(2, 22, 6, 3, 0);            
+            break;
+            
+        case RTL8306_DOT1XUNAUTH:
+            if(RTL8306_ACT_DROP == action)
+                rtl8306e_regbit_set(2, 22, 5, 3, 0);
+            else if (RTL8306_ACT_TRAPCPU == action)
+                rtl8306e_regbit_set(2, 22, 5, 3, 1);                        
+            break;
+        default:
+            return FAILED;
+    }
+    
+    return SUCCESS;
+}
+
+
+/* Function Name:
+ *      rtl8306e_trap_abnormalPktAction_get
+ * Description:
+ *      get abnormal packet action 
+ * Input:
+ *      type         -  abnormal packet type
+ * Output:
+ *      pAction     -  the pointer of action
+ * Return:
+ *      SUCCESS
+ *      FAILED
+ * Note:
+ *      type coulde be:
+ *          RTL8306_UNMATCHVID   - vlan-tagged packet, vid dismatch vlan table 
+ *          RTL8306_DOT1XUNAUTH - 802.1x authentication fail packet
+ *      action could be:
+ *          RTL8306_ACT_DROP       - drop 
+ *          RTL8306_ACT_TRAPCPU  - trap to cpu
+ */ 
+
+int32 rtl8306e_trap_abnormalPktAction_get(uint32 type,  uint32 *pAction)
+{
+    uint32 regval;
+
+    if (NULL ==pAction)
+        return FAILED;
+    
+    switch(type)
+    {
+        case RTL8306_UNMATCHVID:
+            rtl8306e_regbit_get(2, 22, 6, 3, &regval);
+            *pAction = regval ? RTL8306_ACT_DROP: RTL8306_ACT_TRAPCPU;
+            break;
+        case RTL8306_DOT1XUNAUTH:
+            rtl8306e_regbit_get(2, 22, 5, 3, &regval);
+            *pAction = regval ? RTL8306_ACT_TRAPCPU : RTL8306_ACT_DROP;
+            break;
+        default:
+            return FAILED;
+    }
+
+    return SUCCESS;
+}
+
+/* Function Name:
+ *      rtl8306e_trap_rmaAction_set
+ * Description:
+ *      Set reserved multicast Mac address forwarding behavior
+ * Input:
+ *      type         -  reserved Mac address type
+ *      action       -  forwarding behavior for the specified mac address
+ * Output:
+ *      none
+ * Return:
+ *      SUCCESS
+ *      FAILED
+ * Note:
+ *      There are eight types  reserved addresses which user can set asic to determine 
+ *       how to forwarding them:
+ *            RTL8306_RESADDRXX   - reserved address 01-80-c2-00-00-xx 
+ *                                              (exclude 00, 01, 02, 03, 10, 20, 21)
+ *            RTL8306_RESADDR21   -  reserved address 01-80-c2-00-00-21(GVRP address)
+ *            RTL8306_RESADDR20   -  reserved address 01-80-c2-00-00-20(GMRP Address)
+ *            RTL8306_RESADDR10   -  reserved address 01-80-c2-00-00-10(All LANs Bridge Management Group Address)
+ *            RTL8306_RESADDR03   -  reserved address 01-80-c2-00-00-03(IEEE Std 802.1X PAE address)
+ *            RTL8306_RESADDR02   -  reserved address 01-80-c2-00-00-02(IEEE Std 802.3ad Slow_Protocols-Multicast address)
+ *            RTL8306_RESADDR00   -  reserved address 01-80-c2-00-00-00(Bridge Group Address)
+ *            RTL8306_RESADDR01   -  reserved address 01-80-c2-00-00-01(Pause frame)
+ *       Actions are :
+ *            TL8306_ACT_DROP      - Drop the packet
+ *            TL8306_ACT_TRAPCPU - Trap the packet to cpu
+ *            RTL8306_ACT_FLOOD   - Flood the packet
+ */ 
+
+int32 rtl8306e_trap_rmaAction_set(uint32 type, uint32 action)
+{
+    if ((type > RTL8306_RESADDR01) || (action > RTL8306_ACT_FLOOD)) 
+        return FAILED;
+    
+    switch (type) 
+    {
+        case RTL8306_RESADDR21:
+        case RTL8306_RESADDR20:
+        case RTL8306_RESADDR10:
+        case RTL8306_RESADDR03:
+        case RTL8306_RESADDR00: 
+            
+            /*Above cases have same action*/
+            if (RTL8306_ACT_FLOOD == action) 
+                rtl8306e_regbit_set(2, 21, type, 3, 0);
+            else if (RTL8306_ACT_TRAPCPU == action)
+                rtl8306e_regbit_set(2, 21, type, 3, 1);
+            else 
+                return FAILED;
+            break;
+            
+        case RTL8306_RESADDR02:
+            if (RTL8306_ACT_FLOOD == action) 
+            {
+                rtl8306e_regbit_set(1, 23, 4, 0, 0); 
+                rtl8306e_regbit_set(2, 21, type, 3, 0);
+            }
+            else if (RTL8306_ACT_TRAPCPU == action) 
+            {
+                rtl8306e_regbit_set(1, 23, 4, 0, 0);
+                rtl8306e_regbit_set(2, 21, type, 3, 1);
+            }
+            else if (RTL8306_ACT_DROP == action) 
+                rtl8306e_regbit_set(1, 23, 4, 0, 1); 
+            else 
+                return FAILED;
+            break;
+        
+        case RTL8306_RESADDRXX:
+            if (RTL8306_ACT_FLOOD == action) 
+            {
+                rtl8306e_regbit_set(0, 18, 12, 0, 1); 
+                rtl8306e_regbit_set(2, 21, type, 3, 0);
+            } 
+            else if (RTL8306_ACT_TRAPCPU == action) 
+            {
+                rtl8306e_regbit_set(0, 18, 12, 0, 1);
+                rtl8306e_regbit_set(2, 21, type, 3, 1);
+            }
+            else if (RTL8306_ACT_DROP == action) 
+                rtl8306e_regbit_set(0, 18, 12, 0, 0);
+            else 
+                return FAILED;
+            break;
+        
+        case RTL8306_RESADDR01:
+            if (RTL8306_ACT_FLOOD == action) 
+                rtl8306e_regbit_set(0, 22, 14, 0, 1); 
+            else if (RTL8306_ACT_DROP == action)
+                rtl8306e_regbit_set(0, 22, 14, 0, 0);
+            else 
+                return FAILED;
+            break;
+        default :
+            return FAILED;
+    }
+    return SUCCESS;
+}
+
+/* Function Name:
+ *      rtl8306e_trap_rmaAction_get
+ * Description:
+ *      Get reserved multicast Mac address forwarding behavior
+ * Input:
+ *      type         -  reserved Mac address type
+ * Output:
+ *      pAction     -  the pointer of action
+ * Return:
+ *      SUCCESS
+ *      FAILED
+ * Note:
+ *      There are eight types  reserved addresses which user can set asic to determine 
+ *       how to forwarding them:
+ *            RTL8306_RESADDRXX   - reserved address 01-80-c2-00-00-xx 
+ *                                              (exclude 00, 01, 02, 03, 10, 20, 21)
+ *            RTL8306_RESADDR21   -  reserved address 01-80-c2-00-00-21(GVRP address)
+ *            RTL8306_RESADDR20   -  reserved address 01-80-c2-00-00-20(GMRP Address)
+ *            RTL8306_RESADDR10   -  reserved address 01-80-c2-00-00-10(All LANs Bridge Management Group Address)
+ *            RTL8306_RESADDR03   -  reserved address 01-80-c2-00-00-03(IEEE Std 802.1X PAE address)
+ *            RTL8306_RESADDR02   -  reserved address 01-80-c2-00-00-02(IEEE Std 802.3ad Slow_Protocols-Multicast address)
+ *            RTL8306_RESADDR00   -  reserved address 01-80-c2-00-00-00(Bridge Group Address)
+ *            RTL8306_RESADDR01   -  reserved address 01-80-c2-00-00-01(Pause frame)
+ *       Actions are :
+ *            TL8306_ACT_DROP      - Drop the packet
+ *            TL8306_ACT_TRAPCPU - Trap the packet to cpu
+ *            RTL8306_ACT_FLOOD   - Flood the packet
+ */ 
+
+int32 rtl8306e_trap_rmaAction_get(uint32 type, uint32 *pAction)
+{
+    uint32 bitValue1, bitValue2;
+
+    if ((type > RTL8306_RESADDR01) || (NULL == pAction )) 
+        return FAILED;
+
+    switch (type)
+    {
+        case RTL8306_RESADDR21:
+        case RTL8306_RESADDR20:
+        case RTL8306_RESADDR10:
+        case RTL8306_RESADDR03:
+        case RTL8306_RESADDR00: 
+            /*Above cases have same action*/
+            rtl8306e_regbit_get(2, 21, type, 3, &bitValue1);
+            if (bitValue1) 
+                *pAction = RTL8306_ACT_TRAPCPU; 
+            else
+                *pAction = RTL8306_ACT_FLOOD; 
+            break;
+        case RTL8306_RESADDR02:
+            rtl8306e_regbit_get(1, 23, 4, 0, &bitValue1);  
+            rtl8306e_regbit_get(2, 21, type, 3, &bitValue2);
+            if (bitValue1)
+                *pAction = RTL8306_ACT_DROP;
+            else if (bitValue2)
+                *pAction = RTL8306_ACT_TRAPCPU;
+            else
+                *pAction = RTL8306_ACT_FLOOD;
+            break;
+        case RTL8306_RESADDRXX:
+            rtl8306e_regbit_get(0, 18, 12, 0, &bitValue1); 
+            rtl8306e_regbit_get(2, 21, type, 3, &bitValue2);
+            if (!bitValue1)
+                *pAction = RTL8306_ACT_DROP;
+            else if (bitValue2)
+                *pAction = RTL8306_ACT_TRAPCPU;
+            else
+                *pAction = RTL8306_ACT_FLOOD;
+            break;
+        case RTL8306_RESADDR01:
+            rtl8306e_regbit_get(0, 22, 14, 0, &bitValue1); 
+            if (bitValue1)
+                *pAction = RTL8306_ACT_FLOOD;
+            else
+                *pAction = RTL8306_ACT_DROP;
+            break;
+       default :
+            return FAILED;
+    }
+    return SUCCESS;
+}
+
+/* Function Name:
+ *      rtl8306e_int_control_set
+ * Description:
+ *      Set asic interrupt 
+ * Input:
+ *      enInt        -  Enable interrupt cpu
+ *      intmask     -  interrupt event  mask
+ * Output:
+ *      none
+ * Return:
+ *      SUCCESS
+ *      FAILED
+ * Note:
+ *      enInt is global setting and  intmask  has 12 bits totally, each bit 
+ *      represents one interrupt event, 
+ *      - bit0 ~bit4 represent port 0 ~ port 4 link change, 
+ *      - bit 5 represents port 4 MAC link change
+ *      - bit 6 represents port 5 link change, 
+ *      - bit 7 represents storm filter interrupt,
+ *      - bit 8 represents loop event 
+ *      - bit 9 represents wake up frame interrupt
+ *      - bit 10 represents unmatched SA interrupt
+ *      - bit 11 represents Tx meter interrupt
+ *      write 1 to the bit to enable the interrupt and 0 will disable the interrupt. 
+ *
+ */ 
+int32 rtl8306e_int_control_set(uint32 enInt, uint32 intmask)
+{
+    uint32 regValue;
+
+    if (intmask > 0xFFF)
+        return FAILED;
+
+    if (!enInt) 
+    {
+        /*CPU interrupt disable, do not change interrupt port mask*/
+        rtl8306e_regbit_set(2, 22, 15, 3, 1);
+        return SUCCESS;
+    } 
+    
+    /*CPU interrupt enable*/
+    rtl8306e_regbit_set(2, 22, 15, 3, 0);
+    
+    /*Set link change interrupt mask*/
+    rtl8306e_reg_get(4, 23, 3, &regValue);
+    regValue = (regValue & 0xF000) | (intmask & 0xFFF);
+    rtl8306e_reg_set(4, 23, 3, regValue);
+    return SUCCESS;
+}
+
+/* Function Name:
+ *      rtl8306e_int_control_get
+ * Description:
+ *      Get Asic interrupt
+ * Input:
+ *      none 
+ * Output:
+ *      pEnInt       -  the pointer of  interrupt global enable bit
+ *      pIntmask    -  the pointer of interrupt event  mask 
+ * Return:
+ *      SUCCESS
+ *      FAILED
+ * Note:
+ *      enInt is global setting and  intmask  has 12 bits totally, each bit 
+ *      represents one interrupt event, 
+ *      - bit0 ~bit4 represent port 0 ~ port 4 link change, 
+ *      - bit 5 represents port 4 MAC link change
+ *      - bit 6 represents port 5 link change, 
+ *      - bit 7 represents storm filter interrupt,
+ *      - bit 8 represents loop event 
+ *      - bit 9 represents wake up frame interrupt
+ *      - bit 10 represents unmatched SA interrupt
+ *      - bit 11 represents Tx meter interrupt
+ *      write 1 to the bit to enable the interrupt and 0 will disable the interrupt. 
+ *
+ */ 
+int32 rtl8306e_int_control_get(uint32 *pEnInt, uint32 *pIntmask) 
+{
+    uint32 regValue;
+    uint32 bitValue;
+
+    if ((NULL == pEnInt) || (NULL == pIntmask))
+        return FAILED;
+    
+    rtl8306e_regbit_get(2, 22, 15, 3, &bitValue);
+    *pEnInt = (bitValue ? FALSE : TRUE);
+    rtl8306e_reg_get(4, 23, 3, &regValue);
+    *pIntmask = regValue & 0xFFF;
+    return SUCCESS;
+}
+
+/* Function Name:
+ *      rtl8306e_int_control_get
+ * Description:
+ *      Get Asic interrupt
+ * Input:
+ *      none 
+ * Output:
+ *      pEnInt       -  the pointer of  interrupt global enable bit
+ *      pIntmask    -  the pointer of interrupt event  mask 
+ * Return:
+ *      SUCCESS
+ *      FAILED
+ * Note:
+ *      enInt is global setting and  intmask  has 12 bits totally, each bit 
+ *      represents one interrupt event, 
+ *      - bit0 ~bit4 represent port 0 ~ port 4 link change, 
+ *      - bit 5 represents port 4 MAC link change
+ *      - bit 6 represents port 5 link change, 
+ *      - bit 7 represents storm filter interrupt,
+ *      - bit 8 represents loop event 
+ *      - bit 9 represents wake up frame interrupt
+ *      - bit 10 represents unmatched SA interrupt
+ *      - bit 11 represents Tx meter interrupt
+ *      write 1 to the bit to enable the interrupt and 0 will disable the interrupt. 
+ *
+ */ 
+int32 rtl8306e_int_status_get(uint32 *pStatusMask) 
+{
+    uint32 regValue;
+
+    if (NULL == pStatusMask)
+        return FAILED;
+    
+    rtl8306e_reg_get(4, 22, 3, &regValue);
+    *pStatusMask = regValue & 0xFFF;
+    return SUCCESS;
+}
+
+/* Function Name:
+ *      rtl8306e_storm_filterEnable_set
+ * Description:
+ *      Enable Asic storm filter 
+ * Input:
+ *      type      -  specify storm filter type
+ *      enabled  -  TRUE or FALSE
+ * Output:
+ *      none
+ * Return:
+ *      SUCCESS
+ *      FAILED
+ * Note:
+ *      There are 3 kinds of storm filter:
+ *      (1) RTL8306_BROADCASTPKT - storm filter for broadcast packet
+ *      (2) RTL8306_MULTICASTPKT - storm filter for multicast packet
+ *      (3) RTL8306_UDAPKT           - storm filter for unknown DA packet
+ */ 
+int32 rtl8306e_storm_filterEnable_set(uint32 type, uint32 enabled) 
+{
+
+   /*enable new storm filter*/
+   rtl8306e_regbit_set(6, 17, 1, 1, enabled ? 1:0);
+   
+    switch(type) 
+    {
+        case RTL8306_BROADCASTPKT:
+            rtl8306e_regbit_set(0, 18, 2, 0, enabled ? 0:1);
+            break;
+        case RTL8306_MULTICASTPKT:
+            rtl8306e_regbit_set(2, 23, 9, 3, enabled ? 0:1);
+            break;
+        case RTL8306_UDAPKT:
+            rtl8306e_regbit_set(2, 23, 8, 3, enabled ? 0:1);
+            break;
+        default:
+            return FAILED;
+    }
+    return SUCCESS;
+}
+
+/* Function Name:
+ *      rtl8306e_storm_filterEnable_get
+ * Description:
+ *      Get Asic storm filter enabled or disabled 
+ * Input:
+ *      type        -  specify storm filter type
+ * Output:
+ *      pEnabled  -  the pointer of enabled or disabled
+ * Return:
+ *      SUCCESS
+ *      FAILED
+ * Note:
+ *      There are 3 kinds of storm filter:
+ *      (1) RTL8306_BROADCASTPKT - storm filter for broadcast packet
+ *      (2) RTL8306_MULTICASTPKT - storm filter for multicast packet
+ *      (3) RTL8306_UDAPKT           - storm filter for unknown DA packet
+ */ 
+
+int32 rtl8306e_storm_filterEnable_get(uint32 type, uint32 *pEnabled) 
+{
+    uint32 bitValue;
+
+    if (pEnabled == NULL)
+        return FAILED;
+    
+    switch(type) 
+   {
+        case RTL8306_BROADCASTPKT:
+            rtl8306e_regbit_get(0, 18, 2, 0, &bitValue);
+            break;
+        case RTL8306_MULTICASTPKT:
+            rtl8306e_regbit_get(2, 23, 9, 3, &bitValue);
+            break;
+        case RTL8306_UDAPKT:
+            rtl8306e_regbit_get(2, 23, 8, 3, &bitValue);
+            break;
+        default:
+            return FAILED;
+
+    }
+
+    *pEnabled = (bitValue ? FALSE : TRUE);
+    return SUCCESS;
+}
+
+/* Function Name:
+ *      rtl8306e_storm_filter_set
+ * Description:
+ *      Set storm filter parameter
+ * Input:
+ *      trigNum        -  set packet threshold which trigger storm filter
+ *      filTime         -   set time window 
+ *      enStmInt     -   enable storm filter to interrupt cpu
+ * Output:
+ *      none
+ * Return:
+ *      SUCCESS
+ *      FAILED
+ * Note:
+ *      there are 6 value for trigNum:
+ *      - RTL8306_STM_FILNUM64, 64 pkts
+ *      - RTL8306_STM_FILNUM32, 32 pkts           
+ *      - RTL8306_STM_FILNUM16, 16 pkts           
+ *      - RTL8306_STM_FILNUM8,   8 pkts              
+ *      - RTL8306_STM_FILNUM128, 128 pkts          
+ *      - RTL8306_STM_FILNUM256, 256 pkts     
+ *      there are 4 value for filTime:
+ *      - RTL8306_STM_FIL800MS,  800ms 
+ *      - RTL8306_STM_FIL400MS,  400ms 
+ *      - RTL8306_STM_FIL200MS,  200ms
+ *      - RTL8306_STM_FIL100MS,  100ms
+ */ 
+
+int32 rtl8306e_storm_filter_set(uint32 trigNum, uint32 filTime, uint32 enStmInt) 
+{
+    uint32 regval;
+    
+    if ( (trigNum >= RTL8306_STM_FILNUM_END) || (filTime >= RTL8306_STM_FILTIM_END))
+        return FAILED;
+    
+    if(RTL8306_STM_FILNUM128 == trigNum)
+    {
+        rtl8306e_reg_get(6, 25, 0, &regval);
+        regval &= 0xFC1F;
+        regval |= (filTime << 5); 
+        rtl8306e_reg_set(6, 25, 0 , regval);        
+        rtl8306e_regbit_set(6, 17, 0, 1, 1);
+    }
+    else if(RTL8306_STM_FILNUM256 == trigNum)
+    {
+        rtl8306e_reg_get(6, 25, 0, &regval);
+        regval &= 0xFC1F;
+        regval |= (0x1 << 8) | (filTime << 5); 
+        rtl8306e_reg_set(6, 25, 0 , regval);        
+        rtl8306e_regbit_set(6, 17, 0, 1, 1);
+    }
+    else
+    {
+        rtl8306e_reg_get(6, 25, 0, &regval);
+        regval &= 0xFC1F;
+        regval |= (trigNum << 8) | (filTime << 5);
+        rtl8306e_reg_set(6, 25, 0 , regval);
+        rtl8306e_regbit_set(6, 17, 0, 1, 0);        
+    }
+        
+    /*Set whether storm filter interrupt cpu*/
+    rtl8306e_regbit_set(4, 23, 7, 3, enStmInt ? 1:0);
+    
+    /*CPU interrupt enable when enable storm filter interrupt*/
+    rtl8306e_regbit_set(2, 22, 15, 3, enStmInt ? 0:1);
+
+    return SUCCESS;
+
+}
+
+
+/* Function Name:
+ *      rtl8306e_storm_filter_get
+ * Description:
+ *      Get storm filter parameter
+ * Input:
+ *      none 
+ * Output:
+ *      pTrigNum        -  the pointer of packet threshold which trigger storm filter
+ *      pFilTime          -  the pointer of filter time window 
+ *      pEnStmInt       -  the pointer of enable storm filter to interrupt cpu
+ * Return:
+ *      SUCCESS
+ *      FAILED
+ * Note:
+ *      there are 6 value for trigNum:
+ *      - RTL8306_STM_FILNUM64, 64 pkts
+ *      - RTL8306_STM_FILNUM32, 32 pkts           
+ *      - RTL8306_STM_FILNUM16, 16 pkts           
+ *      - RTL8306_STM_FILNUM8,   8 pkts              
+ *      - RTL8306_STM_FILNUM128, 128 pkts          
+ *      - RTL8306_STM_FILNUM256, 256 pkts     
+ *      there are 4 value for filTime:
+ *      - RTL8306_STM_FIL800MS,  800ms 
+ *      - RTL8306_STM_FIL400MS,  400ms 
+ *      - RTL8306_STM_FIL200MS,  200ms
+ *      - RTL8306_STM_FIL100MS,  100ms
+ */ 
+
+int32 rtl8306e_storm_filter_get(uint32 *pTrigNum, uint32 *pFilTime, uint32 *pEnStmInt) 
+{
+    uint32 bitval, regval;
+    
+    if ((NULL == pTrigNum) || (NULL == pFilTime) || (NULL == pEnStmInt))
+        return FAILED;
+
+    rtl8306e_regbit_get(6, 17, 0, 1, &bitval);
+
+    if(bitval)
+    {
+        rtl8306e_reg_get(6, 25, 0, &regval);
+        *pTrigNum = ((regval >> 8) & 0x3) ? RTL8306_STM_FILNUM256 : RTL8306_STM_FILNUM128;
+        *pFilTime = (regval >> 5) & 0x3;
+    }
+    else
+    {
+        rtl8306e_reg_get(6, 25, 0, &regval);
+        *pTrigNum = (regval >> 8) & 0x3;
+        *pFilTime = (regval >> 5) & 0x3;
+    }
+    rtl8306e_regbit_get(4, 23, 7, 3, pEnStmInt);
+    
+    return SUCCESS;
+}
+
+
+
+
+int32 rtl8306e_vlan_portBase_set()
+{
+    uint32 i;
+    uint32 vid;
+    rtk_vlan_t pPvid;
+    rtk_pri_t pPriority;
+    rtk_portmask_t pMbrmsk;
+    rtk_portmask_t pUntagmsk;
+    rtk_portmask_t pMbrmsk2;
+    rtk_portmask_t pUntagmsk2;
+    rtk_fid_t pFid;
+    rtk_portmask_t mbrmsk;
+	rtk_portmask_t mbrmsk2;
+    rtk_portmask_t untagmsk;
+	rtk_portmask_t untagmsk2;
+	rtk_portmask_t portmask;
+    spinlock_t lock;
+    spin_lock_init(&lock);
+	
+  spin_lock_irq(&lock);
+	
+	//init vlan
+    rtk_vlan_init();
+    rtl8306e_vlan_IgrFilterEnable_set(TRUE);
+    
+	//delet default vlan 1,
+    rtk_vlan_destroy(1);
+	
+	//creat vlan 1
+    vid = 100; 
+    mbrmsk.bits[0] =  (0x1 << RTL8306_PORT0) | (0x1 << RTL8306_PORT1) |(0x1 << RTL8306_PORT2)|(0x1 << RTL8306_PORT3)| (0x1 << RTL8306_PORT5);                                 
+    untagmsk.bits[0] = (0x1 << RTL8306_PORT0) | (0x1 << RTL8306_PORT1) | (0x1 << RTL8306_PORT2)| (0x1 << RTL8306_PORT3);                                 
+    rtk_vlan_set(vid, mbrmsk, untagmsk, 0);  
+    //rtk_vlan_get(100, &pMbrmsk, &pUntagmsk, &pFid);	
+    //for(i=0;i<10;i++)
+	//printk("the value of pMbrmsk is %x\n", pMbrmsk.bits[0]);
+	
+	//creat vlan 2
+  
+    vid = 200; 
+    mbrmsk2.bits[0] =  (0x1 << RTL8306_PORT4)| (0x1 << RTL8306_PORT5); 
+    untagmsk2.bits[0] = (0x1 << RTL8306_PORT4); 
+    rtk_vlan_set(vid, mbrmsk2, untagmsk2, 0);
+    //rtk_vlan_get(200, &pMbrmsk2, &pUntagmsk2, &pFid);
+	
+	//for(i=0;i<10;i++)
+	//printk("the value of pMbrmsk2 is %x\n", pMbrmsk2.bits[0]);
+	
+	//set pvid
+    //spin_lock_irq(&lock);
+    rtk_vlan_portPvid_set(RTL8306_PORT0, 100, 0);
+	rtk_vlan_portPvid_set(RTL8306_PORT1, 100, 0); 	
+    rtk_vlan_portPvid_set(RTL8306_PORT2, 100, 0);
+	rtk_vlan_portPvid_set(RTL8306_PORT3, 100, 0);    
+    rtk_vlan_portPvid_set(RTL8306_PORT4, 200, 0);
+	rtk_vlan_portPvid_set(RTL8306_PORT5, 200, 0);
+    rtk_vlan_portPvid_get(RTL8306_PORT5, &pPvid, &pPriority);
+	//spin_unlock_irq(&lock);
+    
+	//set AcceptFrameType
+	rtk_vlan_portAcceptFrameType_set(RTL8306_PORT0, ACCEPT_FRAME_TYPE_UNTAG_ONLY);
+    rtk_vlan_portAcceptFrameType_set(RTL8306_PORT1, ACCEPT_FRAME_TYPE_UNTAG_ONLY);
+    rtk_vlan_portAcceptFrameType_set(RTL8306_PORT2, ACCEPT_FRAME_TYPE_UNTAG_ONLY);
+    rtk_vlan_portAcceptFrameType_set(RTL8306_PORT3, ACCEPT_FRAME_TYPE_UNTAG_ONLY);
+    rtk_vlan_portAcceptFrameType_set(RTL8306_PORT4, ACCEPT_FRAME_TYPE_UNTAG_ONLY);
+	    
+   //set CPU port insert tag based on ingress port 
+   rtl8306e_vlan_tagInsertRemove_set(RTL8306_PORT5, RTL8306_VLAN_ITAG); 
+   rtl8306e_vlan_leaky_set(RTL8306_VALN_LEAKY_ARP,0);//EC 616000558230
+     spin_unlock_irq(&lock);
+	return SUCCESS;
+}
+
+int32 set()
+{
+    uint32 i;
+    uint32 vid;
+    rtk_vlan_t pPvid;
+    rtk_pri_t pPriority;
+    rtk_portmask_t pMbrmsk;
+    rtk_portmask_t pUntagmsk;
+    rtk_portmask_t pMbrmsk2;
+    rtk_portmask_t pUntagmsk2;
+    rtk_fid_t pFid;
+    rtk_portmask_t mbrmsk;
+	rtk_portmask_t mbrmsk2;
+    rtk_portmask_t untagmsk;
+	rtk_portmask_t untagmsk2;
+	rtk_portmask_t portmask;
+    spinlock_t lock;
+    spin_lock_init(&lock);
+	
+  spin_lock_irq(&lock);
+	
+	//init vlan
+    rtk_vlan_init();
+    rtl8306e_vlan_IgrFilterEnable_set(TRUE);
+    
+	//delet default vlan 1,
+    rtk_vlan_destroy(1);
+	
+	//creat vlan 1
+    vid = 100; 
+    mbrmsk.bits[0] =  (0x1 << RTL8306_PORT0) | (0x1 << RTL8306_PORT1) |(0x1 << RTL8306_PORT2)|(0x1 << RTL8306_PORT3);//| (0x1 << RTL8306_PORT5);                                 
+    untagmsk.bits[0] = (0x1 << RTL8306_PORT0) | (0x1 << RTL8306_PORT1) | (0x1 << RTL8306_PORT2)| (0x1 << RTL8306_PORT3);                                 
+    rtk_vlan_set(vid, mbrmsk, untagmsk, 0);  
+   // rtk_vlan_get(100, &pMbrmsk, &pUntagmsk, &pFid);	
+   // for(i=0;i<10;i++)
+	//printk("the value of pMbrmsk is %x\n", pMbrmsk.bits[0]);
+	
+	//creat vlan 2
+  
+    vid = 200; 
+    mbrmsk2.bits[0] =  (0x1 << RTL8306_PORT4);//| (0x1 << RTL8306_PORT5); 
+    untagmsk2.bits[0] = (0x1 << RTL8306_PORT4); 
+    rtk_vlan_set(vid, mbrmsk2, untagmsk2, 0);
+  //  rtk_vlan_get(200, &pMbrmsk2, &pUntagmsk2, &pFid);
+	
+	//for(i=0;i<10;i++)
+	//printk("the value of pMbrmsk2 is %x\n", pMbrmsk2.bits[0]);
+	
+	//set pvid
+    //spin_lock_irq(&lock);
+    rtk_vlan_portPvid_set(RTL8306_PORT0, 100, 0);
+	rtk_vlan_portPvid_set(RTL8306_PORT1, 100, 0); 	
+    rtk_vlan_portPvid_set(RTL8306_PORT2, 100, 0);
+	rtk_vlan_portPvid_set(RTL8306_PORT3, 100, 0);    
+    rtk_vlan_portPvid_set(RTL8306_PORT4, 200, 0);
+	//rtk_vlan_portPvid_set(RTL8306_PORT5, 200, 0);
+    //rtk_vlan_portPvid_get(RTL8306_PORT5, &pPvid, &pPriority);
+	//spin_unlock_irq(&lock);
+    
+	//set AcceptFrameType
+	rtk_vlan_portAcceptFrameType_set(RTL8306_PORT0, ACCEPT_FRAME_TYPE_UNTAG_ONLY);
+    rtk_vlan_portAcceptFrameType_set(RTL8306_PORT1, ACCEPT_FRAME_TYPE_UNTAG_ONLY);
+    rtk_vlan_portAcceptFrameType_set(RTL8306_PORT2, ACCEPT_FRAME_TYPE_UNTAG_ONLY);
+    rtk_vlan_portAcceptFrameType_set(RTL8306_PORT3, ACCEPT_FRAME_TYPE_UNTAG_ONLY);
+    rtk_vlan_portAcceptFrameType_set(RTL8306_PORT4, ACCEPT_FRAME_TYPE_UNTAG_ONLY);
+	    
+   //set CPU port insert tag based on ingress port 
+  // rtl8306e_vlan_tagInsertRemove_set(RTL8306_PORT5, RTL8306_VLAN_ITAG); 
+
+     spin_unlock_irq(&lock);
+	return SUCCESS;
+}
+
+void port_isalation()
+{
+rtk_portmask_t portmask22222;
+//第一次是这样弄的:
+	//port isolation
+	portmask22222.bits[0] = (0x1 << RTL8306_PORT5);
+	rtk_port_isolation_set(RTL8306_PORT4,portmask22222);
+    //rtk_port_isolation_set(rtk_port_t port, portmask22222);
+//第二次这样弄:
+	//rtl8306e_port_isolation_set(0x2888);
+	rtk_cpu_enable_set(ENABLED); 
+    rtk_cpu_tagPort_set(RTL8306_PORT5, CPU_INSERT_TO_ALL); 
+}
+
+ void readreg()
+{
+int i;
+rtk_port_phy_data_t pData;
+    spinlock_t lock;
+    spin_lock_init(&lock);
+	
+  spin_lock_irq(&lock);
+//rtk_port_phyReg_get(rtk_port_t phy, rtk_port_phy_reg_t reg, rtk_port_phy_data_t *pData) 
+rtk_port_phyReg_get(0, 24, &pData);
+    for(i=0;i<10;i++)
+	printk("the value of PHY0 Register 24 is %x\n\n", pData);
+rtk_port_phyReg_get(0, 25, &pData);
+    for(i=0;i<10;i++)
+	printk("the value of PHY0 Register 25 is %x\n\n", pData);
+rtk_port_phyReg_get(1, 24, &pData);
+    for(i=0;i<10;i++)
+	printk("the value of PHY1 Register 24 is %x\n\n", pData);
+rtk_port_phyReg_get(1, 25, &pData);
+    for(i=0;i<10;i++)
+	printk("the value of PHY1 Register 25 is %x\n\n", pData);
+rtk_port_phyReg_get(2, 24, &pData);
+    for(i=0;i<10;i++)
+	printk("the value of PHY2 Register 24 is %x\n\n", pData);
+rtk_port_phyReg_get(2, 25, &pData);
+    for(i=0;i<10;i++)
+	printk("the value of PHY2 Register 25 is %x\n\n", pData);
+rtk_port_phyReg_get(3, 24, &pData);
+    for(i=0;i<10;i++)
+	printk("the value of PHY3 Register 24 is %x\n\n", pData);
+rtk_port_phyReg_get(3, 25, &pData);
+    for(i=0;i<10;i++)
+	printk("the value of PHY3 Register 25 is %x\n\n", pData);
+rtk_port_phyReg_get(4, 24, &pData);
+    for(i=0;i<10;i++)
+	printk("the value of PHY4 Register 24 is %x\n\n", pData);
+rtk_port_phyReg_get(4, 25, &pData);
+    for(i=0;i<10;i++)
+	printk("the value of PHY4 Register 25 is %x\n\n", pData);
+rtk_port_phyReg_get(0, 26, &pData);
+    for(i=0;i<10;i++)
+	printk("the value of PHY0 Register 26 is %x\n\n", pData);	
+	     spin_unlock_irq(&lock);
+}
+
+int rtl8306e_config_init(void)
+{
+	int tmp;
+	rtk_mode_ext_t  Mode;
+    rtk_port_mac_ability_t portAbility;
+
+	/*reset & wait reset complete*/
+	rtl8306e_regbit_set(1, 0, 15, 0, 1);
+	while (tmp == 1) {
+		rtl8306e_regbit_get(1, 0, 15, 0, &tmp);
+	}
+
+	/*enable interrupt*/
+    rtl8306e_regbit_set(2, 22, 15, 3, 0);
+    /*mask interrupt phy 0-5 */
+    rtl8306e_reg_get(4, 23, 3, &tmp);
+    tmp |= 0x1f;
+    rtl8306e_reg_set(4, 23, 3, tmp); 
+
+	rtl8306e_asic_init();
+
+	/*MAC5 force link up*/
+	Mode = MODE_EXT_RMII;
+	portAbility.forcemode = 1;
+	portAbility.nway = 0;
+	portAbility.speed = PORT_SPEED_100M;
+	portAbility.link = 1;
+	portAbility.duplex = PORT_FULL_DUPLEX;
+	portAbility.rxpause = 1;
+	portAbility.txpause = 1;
+	rtk_port_macForceLinkExt0_set(Mode,&portAbility);
+
+	/*vlan config*/
+	rtl8306e_vlan_portBase_set();
+
+	return 0;
+}
+
+int switch_open(struct inode *inode, struct file *file)
+{
+	return 0;
+}
+
+ int switch_ioctl (struct inode *node, struct file *filp, unsigned int cmd, unsigned long arg)
+{	
+	return 0;
+}
+/*4实现操作硬件的方法*/
+static struct file_operations switch_fops = {
+ .owner  = THIS_MODULE,
+ .open   = switch_open,
+ .unlocked_ioctl  = switch_ioctl,
+};
+
+/*3。实现probe函数*/
+static int switch_probe(struct platform_device *dev)
+{	
+	int i;
+	int32 flag;
+	uint32 value1;
+	uint32 *pVid;
+	uint32 *pMbrmsk;
+	uint32 *pUntagmsk;
+	rtk_mode_ext_t *Mode;
+    rtk_port_mac_ability_t portAbility;
+	#if 0
+    /*时钟设置*/
+    virt =(unsigned long)ioremap(0x13B000, 0x11C);
+    unsigned int value;
+	value = ioread32(virt+0x11C);
+	value   = 0x00000005;
+	iowrite32(value,virt+0x11C);
+	mdelay(10);
+
+    /*MAC5 force link up*/
+	 *Mode = MODE_EXT_RMII;
+  	 portAbility.forcemode = 1;
+	 portAbility.nway = 0;
+	 portAbility.speed = PORT_SPEED_100M;
+	 portAbility.link = 1;
+	 portAbility.duplex = PORT_FULL_DUPLEX;
+	 portAbility.rxpause = 1;
+	 portAbility.txpause = 1;
+
+	rtk_port_macForceLinkExt0_set(*Mode,&portAbility);
+#endif
+    switch_major =register_chrdev(0,"switch",&switch_fops);
+	switch_class = class_create(THIS_MODULE, "switch");
+	device_create(switch_class, NULL,MKDEV(switch_major,0),NULL,"switch" );
+	//rtl8306e_asic_init();
+	//rtl8306e_vlan_portBase_set();	
+    //port_isalation();
+    /*****test reg
+	flag == SUCCESS;
+	flag = rtl8306e_reg_get(6, 22, 0, &value1);
+
+	if (flag == SUCCESS)
+		{
+		for(i=0;i<100;i++)
+		{
+		printk("value1 value1value1value1value1value1 is%x", value1);
+	  }
+			}
+			else
+				{			
+					for(i=0;i<100;i++)
+		{		
+					printk("getfaultttttttttttttttttttttttttttttttttttttt");				
+					
+					}
+					}
+		***/			
+readreg();
+	 return 0;
+}
+
+int switch_remove(struct platform_device *dev)
+{
+     unregister_chrdev(switch_major, "switch");
+	 device_destroy(switch_class,MKDEV(switch_major,0));   
+	 class_destroy(switch_class);	 
+	 return 0;
+}
+
+
+static struct platform_driver switch_driver = {
+  .probe  = switch_probe,     
+  .remove  = switch_remove,   
+  .driver  = {
+	  .name = "switch",       
+	  .owner = THIS_MODULE,
+ },
+};
+
+static int switch_drv_init(void)
+{
+	 
+	 platform_driver_register(&switch_driver);
+	 return 0;
+}
+
+static int switch_drv_exit(void)
+{
+	 platform_driver_unregister(&switch_driver);
+	 return 0;
+}
+
+//module_init(switch_drv_init);
+//module_exit(switch_drv_exit);
+
+MODULE_LICENSE("GPL"); 
+ 
diff --git a/ap/os/linux/linux-3.4.x/drivers/net/phy/realtek/rtl8306e/rtl8306e_asicdrv.h b/ap/os/linux/linux-3.4.x/drivers/net/phy/realtek/rtl8306e/rtl8306e_asicdrv.h
new file mode 100755
index 0000000..406df1e
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/net/phy/realtek/rtl8306e/rtl8306e_asicdrv.h
@@ -0,0 +1,3233 @@
+/*
+* Copyright (C) 2010 Realtek Semiconductor Corp.
+* All Rights Reserved.
+*
+* This program is the proprietary software of Realtek Semiconductor
+* Corporation and/or its licensors, and only be used, duplicated,
+* modified or distributed under the authorized license from Realtek.
+*
+* ANY USE OF THE SOFTWARE OTEHR THAN AS AUTHORIZED UNDER 
+* THIS LICENSE OR COPYRIGHT LAW IS PROHIBITED.
+* 
+* $Revision: 26889 $ 
+* $Date: 2012-02-28 21:08:47 +0800 (星期二, 2012-02-28) $
+*
+* Purpose : asic-level driver implementation for RTL8306E switch
+*
+*  Feature :  This file consists of following modules:
+*                1) 
+*
+*/
+
+
+#ifndef __RTL8306E_ASICDRV_H__
+#define __RTL8306E_ASICDRV_H__
+
+/*save time of reading LUT*/
+/*#define RTL8306_LUT_CACHE */
+
+/*if you need backup asic info in cpu memroy in order to 
+ *accellerate CPU process, please define this macro. If 
+ *support IGMP snooping, this macro is required.
+ */
+#define RTL8306_TBLBAK   
+//#define RTK_X86_ASICDRV  
+#define RTL8306_PHY_NUMBER        7
+#define RTL8306_PAGE_NUMBER      5
+#define RTL8306_PORT_NUMBER      6
+#define RTL8306_VLAN_ENTRYS      16            /*Vlan entry number*/ 
+#define RTL8306_ACL_ENTRYNUM    16           /*ACL entry number*/
+
+#define RTL8306_IDLE_TIMEOUT   100
+#define RTL8306_QOS_RATE_INPUT_MAX 0x5F6
+#define RTL8306_VIDMAX                       0XFFF
+#define RTL8306_MAX_PORTMASK           0X3F
+
+
+enum RTL8306E_REGPAGE
+{
+    RTL8306_REGPAGE0 = 0,
+    RTL8306_REGPAGE1,
+    RTL8306_REGPAGE2,
+    RTL8306_REGPAGE3,
+    RTL8306_REGPAGE4,    
+    RTL8306_REGPAGE_END
+    
+};
+
+enum RTL8306E_PORTNUM
+{
+    RTL8306_PORT0 = 0,
+    RTL8306_PORT1,        
+    RTL8306_PORT2,
+    RTL8306_PORT3,  
+    RTL8306_PORT4,
+    RTL8306_PORT5,
+    RTL8306_NOCPUPORT = 7    
+};
+
+enum RTL8306E_PHYMODE
+{
+    RTL8306_ETHER_AUTO_100FULL = 1,
+    RTL8306_ETHER_AUTO_100HALF,
+    RTL8306_ETHER_AUTO_10FULL,
+    RTL8306_ETHER_AUTO_10HALF
+};
+
+enum RTL8306E_PHYSPD
+{
+    RTL8306_ETHER_SPEED_100 = 100,
+    RTL8306_ETHER_SPEED_10 = 10        
+};
+
+enum RTL8306E_TAGMOD
+{
+    RTL8306_VLAN_IRTAG = 0,             /*The switch will remove VLAN tags and add new tags */
+    RTL8306_VLAN_RTAG,                   /*The switch will remove VLAN tags */
+    RTL8306_VLAN_ITAG,                   /*The switch will  add new VLANtag */
+    RTL8306_VLAN_UNDOTAG            /*Do not insert or remove  VLAN tag */
+};
+
+enum RTL8306E_LEAKYVLAN
+{
+    RTL8306_VALN_LEAKY_UNICAST = 0,
+    RTL8306_VALN_LEAKY_MULTICAST,
+    RTL8306_VALN_LEAKY_ARP,
+    RTL8306_VALN_LEAKY_MIRROR,
+    RTL8306_VALN_LEAKY_END
+};
+
+/*ACL Packet processing method*/
+enum RTL8306E_ACTION
+{
+    RTL8306_ACT_DROP = 0,    /*drop the packet*/    
+    RTL8306_ACT_PERMIT,      /*permit the packet*/        
+    RTL8306_ACT_TRAPCPU,   /*trap the packet to cpu*/
+    RTL8306_ACT_MIRROR,     /*mirror the packet */
+    RTL8306_ACT_FLOOD      /*flood the packet  */    
+};
+
+/*
+  * PHY control register field definitions 
+  */
+#define RTL8306_SPEED_SELECT_100M                       (1 << 13)  
+#define RTL8306_ENABLE_AUTONEGO                         (1 << 12)
+#define RTL8306_RESTART_AUTONEGO                        (1 << 9)
+#define RTL8306_SELECT_FULL_DUPLEX                      (1 << 8)
+
+/* 
+  *PHY auto-negotiation advertisement and link partner 
+  *ability registers field definitions
+  */
+#define RTL8306_NEXT_PAGE_ENABLED                       (1 << 15)
+#define RTL8306_ACKNOWLEDGE                                 (1 << 14)
+#define RTL8306_REMOTE_FAULT                                 (1 << 13)
+#define RTL8306_CAPABLE_PAUSE                               (1 << 10)
+#define RTL8306_CAPABLE_100BASE_T4                      (1 << 9)
+#define RTL8306_CAPABLE_100BASE_TX_FD                (1 << 8)
+#define RTL8306_CAPABLE_100BASE_TX_HD                (1 << 7)
+#define RTL8306_CAPABLE_10BASE_TX_FD                  (1 << 6)
+#define RTL8306_CAPABLE_10BASE_TX_HD                  (1 << 5)
+#define RTL8306_SELECTOR_MASK                               0x1F
+#define RTL8306_SELECTOR_OFFSET                             0
+
+enum RTL8306E_IGMPCTL
+{
+    RTL8306_IGMP = 0,
+    RTL8306_MLD, 
+    RTL8306_PPPOE_IGMPMLD
+};
+
+enum RTL8306E_IPMULTICAST
+{
+    RTL8306_IPV4_MULTICAST = 0,
+    RTL8306_IPV6_MULTICAST
+};
+
+#define RTL8306_PORT_RX  0
+#define RTL8306_PORT_TX  1
+
+enum RTL8306E_QUENUM
+{
+    RTL8306_QUEUE0 = 0,
+    RTL8306_QUEUE1,
+    RTL8306_QUEUE2,
+    RTL8306_QUEUE3
+};
+
+enum RTL8306E_PRISRC
+{
+    RTL8306_ACL_PRIO = 0,           /*ACL-based priority*/
+    RTL8306_DSCP_PRIO,              /*DSCP-based priority*/
+    RTL8306_1QBP_PRIO,              /*802.1Q-based priority*/ 
+    RTL8306_PBP_PRIO,                /*port- based priority */
+    RTL8306_CPUTAG_PRIO,          /*cpu tag priority*/
+    RTL8306_IP_PRIO,                  /* ip address priority*/
+    RTL8306_1QTAG_PRIO,           /* VLAN tag priority */
+    RTL8306_PRI_1QDEFAULT      /* 802.1Q priority for untagged packet*/     
+};
+
+
+enum RTL8306E_1QPRI
+{
+    RTL8306_1QTAG_PRIO0 = 0,
+    RTL8306_1QTAG_PRIO1,
+    RTL8306_1QTAG_PRIO2,
+    RTL8306_1QTAG_PRIO3,
+    RTL8306_1QTAG_PRIO4,
+    RTL8306_1QTAG_PRIO5,
+    RTL8306_1QTAG_PRIO6,
+    RTL8306_1QTAG_PRIO7,
+    RTL8306_1QTAG_END
+};
+
+enum RTL8306E_PRI
+{
+    RTL8306_PRIO0 = 0,
+    RTL8306_PRIO1,
+    RTL8306_PRIO2,
+    RTL8306_PRIO3,    
+    RTL8306_PRI_END
+};
+
+enum RTL8306E_SCHSET
+{
+    RTL8306_QOS_SET0 = 0, 
+    RTL8306_QOS_SET1        
+};
+
+enum RTL8306E_DSCPCODE
+{
+    RTL8306_DSCP_EF = 0,
+    RTL8306_DSCP_AFL1,
+    RTL8306_DSCP_AFM1,    
+    RTL8306_DSCP_AFH1,
+    RTL8306_DSCP_AFL2,
+    RTL8306_DSCP_AFM2,
+    RTL8306_DSCP_AFH2,
+    RTL8306_DSCP_AFL3,
+    RTL8306_DSCP_AFM3,
+    RTL8306_DSCP_AFH3,
+    RTL8306_DSCP_AFL4,
+    RTL8306_DSCP_AFM4,
+    RTL8306_DSCP_AFH4,
+    RTL8306_DSCP_NC,
+    RTL8306_DSCP_REG_PRI,
+    RTL8306_DSCP_BF       
+};
+
+#define RTL8306_DSCP_USERA        0
+#define RTL8306_DSCP_USERB        1
+#define RTL8306_IPADD_A 0
+#define RTL8306_IPADD_B 1
+
+#define RTL8306_FCO_SET0            0x0
+#define RTL8306_FCO_SET1            0x1
+#define RTL8306_FCOFF                 0x0
+#define RTL8306_FCON                   0x1
+#define RTL8306_FCO_DSC             0x0
+#define RTL8306_FCO_QLEN           0x1
+#define RTL8306_FCO_FULLTHR      0x0
+#define RTL8306_FCO_OVERTHR     0x1
+
+
+#define RTL8306_ACL_INVALID       0x6
+#define RTL8306_ACL_ANYPORT     0x7
+
+enum RTL8306E_ACLPRO
+{
+    RTL8306_ACL_ETHER = 0,
+    RTL8306_ACL_TCP,
+    RTL8306_ACL_UDP,
+    RTL8306_ACL_TCPUDP    
+};
+
+enum RTL8306E_MIBCNT
+{
+    RTL8306_MIB_CNT1 = 0,
+    RTL8306_MIB_CNT2,
+    RTL8306_MIB_CNT3,
+    RTL8306_MIB_CNT4,
+    RTL8306_MIB_CNT5 
+};
+
+enum RTL8306E_MIBOP
+{
+    RTL8306_MIB_RESET = 0, 
+    RTL8306_MIB_START        
+};
+
+#define RTL8306_MIB_BYTE            0
+#define RTL8306_MIB_PKT              1
+
+#define RTL8306_MIR_INVALID       0x6
+
+enum RTL8306E_LUT4WAY
+{
+    RTL8306_LUT_ENTRY0 = 0,
+    RTL8306_LUT_ENTRY1,
+    RTL8306_LUT_ENTRY2,
+    RTL8306_LUT_ENTRY3    
+};    
+
+#define RTL8306_LUT_FULL            -2  /*Four way of the same entry are all written by cpu*/
+#define RTL8306_LUT_NOTEXIST     -3
+
+enum RTL8306E_LUTAGE
+{
+    RTL8306_LUT_AGEOUT = 0,
+    RTL8306_LUT_AGE100 = 100,
+    RTL8306_LUT_AGE200 = 200,
+    RTL8306_LUT_AGE300 = 300   
+};
+
+#define RTL8306_LUT_DYNAMIC      0
+#define RTL8306_LUT_STATIC         1
+#define RTL8306_LUT_UNAUTH       0
+#define RTL8306_LUT_AUTH           1
+
+enum RTL8306E_SPAN_STATE
+{
+    RTL8306_SPAN_DISABLE = 0,
+    RTL8306_SPAN_BLOCK,
+    RTL8306_SPAN_LEARN,
+    RTL8306_SPAN_FORWARD  
+};
+
+enum RTL8306E_DOT1X_STATE
+{
+    RTL8306_PORT_UNAUTH = 0, 
+    RTL8306_PORT_AUTH
+};
+
+enum RTL8306E_DOT1X_PORT_DIR
+{
+    RTL8306_PORT_BOTHDIR = 0,
+    RTL8306_PORT_INDIR      
+};
+
+enum RTL8306E_DOT1X_MAC_DIR
+{
+    RTL8306_MAC_BOTHDIR = 0,
+    RTL8306_MAC_INDIR      
+};
+
+enum RTL8306E_ABNORMAL_PKT
+{
+    RTL8306_UNMATCHVID =0,
+    RTL8306_DOT1XUNAUTH
+};
+
+enum RTL8306E_RMA
+{
+    RTL8306_RESADDRXX = 0, /*reserved address 01-80-c2-00-00-xx (exclude 00, 01, 02, 03, 10, 20, 21) */
+    RTL8306_RESADDR21,       /*reserved address 01-80-c2-00-00-21*/        
+    RTL8306_RESADDR20,       /*reserved address 01-80-c2-00-00-20*/
+    RTL8306_RESADDR10,       /*reserved address 01-80-c2-00-00-10*/
+    RTL8306_RESADDR03,      /*reserved address 01-80-c2-00-00-03*/
+    RTL8306_RESADDR02,      /*reserved address 01-80-c2-00-00-02*/
+    RTL8306_RESADDR00,      /*reserved address 01-80-c2-00-00-00*/
+    RTL8306_RESADDR01     /*reserved address 01-80-c2-00-00-01*/
+};
+
+enum RTL8306E_PKT_TYPE
+{
+    RTL8306_UNICASTPKT = 0,  /*Unicast packet, but not include unknown DA unicast packet*/
+    RTL8306_BROADCASTPKT,   /*Broadcast packet*/
+    RTL8306_MULTICASTPKT,    /*Multicast packet*/
+    RTL8306_UDAPKT             /*Unknown DA unicast packet*/
+};
+
+
+/*Max packet length*/
+enum RTL8306E_PKT_LEN
+{
+    RTL8306_MAX_PKT_LEN_1518 = 0,  /*1518 bytes without any tag; 1522 bytes: with VLAN tag or CPU tag*/
+    RTL8306_MAX_PKT_LEN_1536,       /*1536 bytes*/
+    RTL8306_MAX_PKT_LEN_1552,       /*1552 bytes*/
+    RTL8306_MAX_PKT_LEN_2000       /*1552 bytes*/
+};
+
+enum RTL8306E_STORM_THR
+{
+    RTL8306_STM_FILNUM64  =  0,     /*64 pkts will trigger storm fileter*/
+    RTL8306_STM_FILNUM32,            /*32 pkts will trigger storm fileter*/
+    RTL8306_STM_FILNUM16,            /*16 pkts will trigger storm fileter*/
+    RTL8306_STM_FILNUM8,              /*8 pkts will trigger storm fileter*/
+    RTL8306_STM_FILNUM128,          /*128 pkts will trigger storm fileter*/
+    RTL8306_STM_FILNUM256,          /*256 pkts will trigger storm fileter*/
+    RTL8306_STM_FILNUM_END    
+};
+
+enum RTL8306E_STORM_TIMEWIN
+{
+    RTL8306_STM_FIL800MS = 0,       /*filter 800ms after trigger storm filter*/
+    RTL8306_STM_FIL400MS,            /*filter 400ms after trigger storm filter*/
+    RTL8306_STM_FIL200MS,            /*filter 200ms after trigger storm filter*/
+    RTL8306_STM_FIL100MS,            /*filter 100ms after trigger storm filter*/
+    RTL8306_STM_FILTIM_END
+};
+
+typedef enum rtl8306e_acceptFrameType_e
+{
+    RTL8306E_ACCEPT_ALL = 0,                   /* untagged, priority-tagged and tagged */
+    RTL8306E_ACCEPT_TAG_ONLY = 2,         /* tagged */
+    RTL8306E_ACCEPT_UNTAG_ONLY = 3 ,    /* untagged and priority-tagged */
+    RTL8306E_ACCEPT_TYPE_END
+} rtl8306e_acceptFrameType_t;
+
+typedef enum rtl8306e_vidSrc_e
+{
+    RTL8306E_VIDSRC_POVID = 0,              /*port-based outer tag vid*/
+    RTL8306E_VIDSRC_NVID,                     /* new vid translated*/
+    RTL8306E_VIDSRC_END    
+
+} rtl8306e_vidSrc_t;
+
+typedef enum rtl8306e_priSrc_e
+{
+    RTL8306E_PRISRC_PPRI = 0,              /*port-based outer tag priority*/
+    RTL8306E_PRISRC_1PRMK,                /* 1p remarking priority*/
+    RTL8306E_PRISRC_END
+} rtl8306e_priSrc_t;
+
+
+typedef struct rtl8306e_qosPriArbitPara_s 
+{
+    uint32 acl_pri_lev;
+    uint32 dscp_pri_lev;
+    uint32 dot1q_pri_lev;
+    uint32 port_pri_lev;
+    uint32 vid_pri_lev;
+} rtl8306e_qosPriArbitPara_t;
+
+typedef struct rtl8306e_qosSchPara_s
+{
+    uint8   q0_wt;
+    uint8   q1_wt;
+    uint8   q2_wt;
+    uint8   q3_wt;
+    uint16 q2_n64Kbps;
+    uint16 q3_n64Kbps;    
+
+} rtl8306e_qosSchPara_t;
+
+#ifdef RTL8306_LUT_CACHE
+#define RTL8306_MAX_LUT_NUM    2048
+typedef struct RTL8306_LUT_s
+{
+    uint8   mac[6];
+    union
+    {
+        struct 
+        {
+            uint8 auth;
+            uint8 isStatic;
+            uint8 spa;
+            uint8 age;
+            uint8 reserved;
+        } unicast;
+        struct 
+        {
+            uint8 auth;
+            uint8 portMask;
+            uint8 reserved;
+        } multicast;
+    }un;
+}RTL8306_LUT;
+#endif
+
+#ifdef RTL8306_TBLBAK
+typedef struct rtl8306_vlanConfigBakPara_s 
+{
+    uint8 enVlan;
+    uint8 enArpVlan;
+    uint8 enLeakVlan;
+    uint8 enVlanTagOnly;
+    uint8 enIngress;
+    uint8 enTagAware;
+    uint8 enIPMleaky;
+    uint8 enMirLeaky;
+} rtl8306_vlanConfigBakPara_t;
+
+typedef struct rtl8306_vlanConfigPerPortBakPara_s 
+{
+    uint8 vlantagInserRm;
+    uint8 en1PRemark;
+    uint8 enNulPvidRep;         
+} rtl8306_vlanConfigPerPortBakPara_t;
+
+typedef struct  rtl8306_vlanTblBakPara_s 
+{
+    uint16 vid;
+    uint8 memberPortMask;        
+} rtl8306_vlanTblBakPara_t;
+
+typedef struct rtl8306_aclTblBakPara_s 
+{
+    uint8 phy_port;
+    uint8 proto;
+    uint16 data;
+    uint8 action;
+    uint8 pri;
+} rtl8306_aclTblBakPara_t;
+
+typedef struct rtl8306_mirConfigBakPara_s
+{
+    uint8 mirPort;
+    uint8 mirRxPortMask;
+    uint8 mirTxPortMask;
+    uint8 enMirself;
+    uint8 enMirMac;
+    uint8 mir_mac[6];
+} rtl8306_mirConfigBakPara_t;
+    
+
+typedef struct rtl8306_ConfigBakPara_s  
+{
+    rtl8306_vlanConfigBakPara_t vlanConfig;                    /*VLAN global configuration*/
+    rtl8306_vlanConfigPerPortBakPara_t vlanConfig_perport[6];   /*VLAN per-port configuration*/
+    rtl8306_vlanTblBakPara_t vlanTable[16]; /*It backups VLAN table in cpu memory*/
+    uint8 vlanPvidIdx[6];   /*per-port PVID index*/                  
+    uint8 En1PremarkPortMask; /*Enable/disable 802.1P remarking  port mask */
+    uint8 dot1PremarkCtl[4]; /*802.1p remarking table*/
+    uint8 dot1DportCtl[6]; /*Spanning tree port state*/
+    rtl8306_aclTblBakPara_t aclTbl[16];         /*ACL table*/
+    rtl8306_mirConfigBakPara_t mir; /*mirror configuration*/                                                                         
+} rtl8306_ConfigBakPara_t;
+
+extern rtl8306_ConfigBakPara_t rtl8306_TblBak; 
+
+#endif
+
+
+#define RTL8306_GET_REG_ADDR(x, page, phy, reg) \
+    do { (page) = ((x) & 0xFF0000) >> 16; (phy) = ((x) & 0x00FF00) >> 8; (reg) = ((x) & 0x0000FF);\
+    } while(0) \
+
+/*compute look up table index of a mac addrees, LUT index : MAC[13:15] + MAC[0:5]*/
+#define RTL8306_MAC_INDEX(mac, index)    rtl8306e_l2_MacToIdx_get(mac, &index)
+
+
+/* Function Name:
+ *      rtl8306e_reg_set
+ * Description:
+ *      Write Asic Register
+ * Input:
+ *      phyad   - Specify Phy address (0 ~6)
+ *      regad    - Specify register address (0 ~31)
+ *      npage   - Specify page number (0 ~3)
+ *      value    - Value to be write into the register
+ * Output:
+ *      none
+ * Return:
+ *      SUCCESS
+ *      FAILED
+ * Note:
+ *      Use this function you could write all configurable registers of RTL8306, 
+ *      it is realized by calling functions smiRead and smiWrite which are switch
+ *      MDC/MDIO interface access functions. Those two functions use two GPIO 
+ *      pins to simulate MDC/MDIO timing,  and they are based on rtl8651b platform,
+ *      to modify them,  you can port all asic API to other platform.
+ */
+extern int32 rtl8306e_reg_set(uint32 phyad, uint32 regad, uint32 npage, uint32 value) ;
+
+/* Function Name:
+ *      rtl8306e_reg_get
+ * Description:
+ *      Read Asic Register
+ * Input:
+ *      phyad   - Specify Phy address (0 ~6)
+ *      regad    - Specify register address (0 ~31)
+ *      npage   - Specify page number (0 ~3)
+ * Output:
+ *      pvalue    - The pointer of value read back from register
+ * Return:
+ *      SUCCESS
+ *      FAILED
+ * Note:
+ *      Use this function you could write all configurable registers of RTL8306, 
+ *      it is realized by calling functions smiRead and smiWrite which are switch
+ *      MDC/MDIO interface access functions. Those two functions use two GPIO 
+ *      pins to simulate MDC/MDIO timing,  and they are based on rtl8651b platform,
+ *      to modify them,  you can port all asic API to other platform.
+ */
+extern int32 rtl8306e_reg_get(uint32 phyad, uint32 regad, uint32 npage, uint32 *pvalue);
+
+/* Function Name:
+ *      rtl8306e_regbit_set
+ * Description:
+ *      Write one bit of Asic Register
+ * Input:
+ *      phyad   - Specify Phy address (0 ~6)
+ *      regad    - Specify register address (0 ~31)
+ *      bit        - Specify bit position(0 ~ 15)
+ *      npage   - Specify page number (0 ~3)
+ *      value    - Value to be write(0, 1)
+ * Output:
+ *      none
+ * Return:
+ *      SUCCESS
+ *      FAILED
+ * Note:
+ *      Use this function  you could write each bit of  all configurable registers of RTL8306.
+ */
+extern int32 rtl8306e_regbit_set(uint32 phyad, uint32 regad, uint32 bit, uint32 npage,  uint32 value);
+
+/* Function Name:
+ *      rtl8306e_regbit_get
+ * Description:
+ *      Read one bit of Asic  PHY Register
+ * Input:
+ *      phyad   - Specify Phy address (0 ~6)
+ *      regad    - Specify register address (0 ~31)
+ *      bit        - Specify bit position(0 ~ 15)
+ *      npage   - Specify page number (0 ~3)
+ * Output:
+ *      pvalue  - The pointer of value read back
+ * Return:
+ *      SUCCESS
+ *      FAILED
+ * Note:
+ *      Use this function you could read each bit of  all configurable registers of RTL8306
+ */
+extern int32 rtl8306e_regbit_get(uint32 phyad, uint32 regad, uint32 bit, uint32 npage,  uint32 * pvalue) ;
+
+/* Function Name:
+ *      rtl8306e_phyReg_set
+ * Description:
+ *      Write PCS page register
+ * Input:
+ *      phyad   - Specify Phy address (0 ~6)
+ *      regad    - Specify register address (0 ~31)
+ *      npage   - Specify page number (0 ~5)
+ *      value    - Value to be write into the register
+ * Output:
+ *      none
+ * Return:
+ *      SUCCESS
+ *      FAILED
+ * Note:
+ *      Use this function you could write all configurable pcs registers of RTL8306, 
+ *      it is realized by calling functions smiRead and smiWrite which are switch
+ *      MDC/MDIO interface access functions. Those two functions use two GPIO 
+ *      pins to simulate MDC/MDIO timing,  and they are based on rtl8651b platform,
+ *      to modify them,  you can port all asic API to other platform.
+ */
+extern int32 rtl8306e_phyReg_set(uint32 phyad, uint32 regad, uint32 npage, uint32 value);
+
+/* Function Name:
+ *      rtl8306e_phyReg_get
+ * Description:
+ *      Read PCS page register
+ * Input:
+ *      phyad   - Specify Phy address (0 ~6)
+ *      regad    - Specify register address (0 ~31)
+ *      npage   - Specify page number (0 ~5)
+ * Output:
+ *      pvalue    - The pointer of value read back from register
+ * Return:
+ *      SUCCESS
+ *      FAILED
+ * Note:
+ *      Use this function you could write all configurable pcs registers of RTL8306, 
+ *      it is realized by calling functions smiRead and smiWrite which are switch
+ *      MDC/MDIO interface access functions. Those two functions use two GPIO 
+ *      pins to simulate MDC/MDIO timing,  and they are based on rtl8651b platform,
+ *      to modify them,  you can port all asic API to other platform.
+ */
+extern int32 rtl8306e_phyReg_get(uint32 phyad, uint32 regad, uint32 npage, uint32 *pvalue);
+
+extern int32 rtl8306e_asic_init(void);
+
+/* Function Name:
+ *      rtl8306e_phy_reset
+ * Description:
+ *      Reset the phy
+ * Input:
+ *      phy   - Specify Phy address (0 ~6)
+ * Output:
+ *      none
+ * Return:
+ *      SUCCESS
+ *      FAILED
+ * Note:
+ */
+extern int32 rtl8306e_phy_reset(uint32 phy);
+
+/* Function Name:
+ *      rtl8306e_switch_maxPktLen_set
+ * Description:
+ *      set Max packet length which could be forwarded by
+ * Input:
+ *      maxLen         -  max packet length
+ * Output:
+ *      none
+ * Return:
+ *      SUCCESS
+ *      FAILED
+ * Note:
+ *      maxLen could be set : 
+ *      RTL8306_MAX_PKT_LEN_1518 -1518 bytes without any tag; 1522 bytes: 
+ *              with VLAN tag or CPU tag, 1526 bytes with CPU and VLAN tag;
+ *      RTL8306_MAX_PKT_LEN_1536 - 1536 bytes (all tags counted);
+ *      RTL8306_MAX_PKT_LEN_1552 - 1552 bytes (all tags counted); 
+ *      RTL8306_MAX_PKT_LEN_2000 - 2000 bytes (all tags counted) 
+ *              
+ */ 
+extern int32 rtl8306e_switch_maxPktLen_set(uint32 maxLen);
+
+/* Function Name:
+ *      rtl8306e_switch_maxPktLen_get
+ * Description:
+ *      set Max packet length which could be forwarded by
+ * Input:
+ *      none
+ * Output:
+ *      maxLen         -  max packet length
+ * Return:
+ *      SUCCESS
+ *      FAILED
+ * Note:
+ *      maxLen could be set : 
+ *      RTL8306_MAX_PKT_LEN_1518 -1518 bytes without any tag; 1522 bytes: 
+ *              with VLAN tag or CPU tag, 1526 bytes with CPU and VLAN tag;
+ *      RTL8306_MAX_PKT_LEN_1536 - 1536 bytes (all tags counted);
+ *      RTL8306_MAX_PKT_LEN_1552 - 1552 bytes (all tags counted); 
+ *      RTL8306_MAX_PKT_LEN_2000 - 2000 bytes (all tags counted) 
+ *              
+ */ 
+extern int32 rtl8306e_switch_maxPktLen_get(uint32 *pMaxLen);
+
+/*
+  *  physical port function
+  */
+
+/* Function Name:
+ *      rtl8306e_port_etherPhy_set
+ * Description:
+ *      Configure PHY setting
+ * Input:
+ *      phy                    - Specify the phy to configure
+ *      autoNegotiation    - Specify whether enable auto-negotiation
+ *      advCapability       - When auto-negotiation is enabled, specify the advertised capability
+ *      speed                 - When auto-negotiation is disabled, specify the force mode speed
+ *      fullDuplex            - When auto-negotiatoin is disabled, specify the force mode duplex mode
+ * Output:
+ *      none
+ * Return:
+ *      SUCCESS
+ *      FAILED
+ * Note:
+ *      When auto-negotiation is enabled, the advertisement capability is used to handshaking with link partner.
+ *      When auto-negotiation is disabled, the phy is configured into force mode and the speed and duplex mode 
+ *      setting is based on speed and fullDuplex setting.Port number should be smaller than RTL8306_PHY_NUMBER.
+ *      AdverCapability should be ranged between RTL8306_ETHER_AUTO_100FULL and RTL8306_ETHER_AUTO_10HALF.
+ *      Speed should be either RTL8306_ETHER_SPEED_100 or RTL8306_ETHER_SPEED_10.
+ */
+
+extern int32 rtl8306e_port_etherPhy_set(uint32 phy, uint32 autoNegotiation, uint32 advCapability, uint32 speed, uint32 fullDuplex) ;
+
+/* Function Name:
+ *      rtl8306e_port_etherPhy_get
+ * Description:
+ *       Get PHY setting
+ * Input:
+ *      phy                    - Specify the phy to configure
+ * Output:
+ *      pAutoNegotiation    - Get whether auto-negotiation is enabled
+ *      pAdvCapability       - When auto-negotiation is enabled, Get the advertised capability
+ *      pSpeed                 - When auto-negotiation is disabled, Get the force mode speed
+ *      pFullDuplex            - When auto-negotiatoin is disabled, Get the force mode duplex mode
+
+ * Return:
+ *      SUCCESS
+ *      FAILED
+ * Note:
+ *      When auto-negotiation is enabled, the advertisement capability is used to handshaking with link partner.
+ *      When auto-negotiation is disabled, the phy is configured into force mode and the speed and duplex mode 
+ *      setting is based on speed and fullDuplex setting.Port number should be smaller than RTL8306_PHY_NUMBER.
+ *      AdverCapability should be ranged between RTL8306_ETHER_AUTO_100FULL and RTL8306_ETHER_AUTO_10HALF.
+ *      Speed should be either RTL8306_ETHER_SPEED_100 or RTL8306_ETHER_SPEED_10.
+ */
+extern int32 rtl8306e_port_etherPhy_get(uint32 phy, uint32 *pAutoNegotiation, uint32 *pAdvCapability, uint32 *pSpeed, uint32 *pFullDuplex);
+
+/* Function Name:
+ *      rtl8306e_port_port5LinkStatus_set
+ * Description:
+ *      Force port 5 link up or link down
+ * Input:
+ *      enabled   - true or false
+ * Output:
+ *      none
+ * Return:
+ *      SUCCESS
+ *      FAILED
+ * Note:
+ *      Port 5 should be manully enable / disable
+ */
+extern int32 rtl8306e_port_port5LinkStatus_set(uint32 enabled) ;
+
+/* Function Name:
+ *      rtl8306e_port_port5LinkStatus_get
+ * Description:
+ *      get port 5 link status
+ * Input:
+ *      none
+ * Output:
+*      enabled   - true or false
+ * Return:
+ *      SUCCESS
+ *      FAILED
+ * Note:
+ *      Port 5 should be manully enable / disable
+ */
+extern int32 rtl8306e_port_port5LinkStatus_get(uint32 *pEnabled);
+
+/* Function Name:
+ *      rtl8306e_port_phyLinkStatus_get
+ * Description:
+ *      Get PHY Link Status
+ * Input:
+*      phy        - Specify the phy 
+ * Output:
+*      plinkUp   - Describe whether link status is up or not
+ * Return:
+ *      SUCCESS
+ *      FAILED
+ * Note:
+ *       Read the link status of PHY register 1
+ */
+extern int32 rtl8306e_port_phyLinkStatus_get(uint32 phy, uint32 *plinkUp);
+
+/* Function Name:
+ *      rtl8306e_port_phyAutoNegotiationDone_get
+ * Description:
+ *      Get PHY auto-negotiation result status
+ * Input:
+ *      phy      - Specify the phy to get status
+ * Output:
+*      pDone   -  Describe whether auto-negotiation is done or not
+ * Return:
+ *      SUCCESS
+ *      FAILED
+ * Note:
+ *      Read the auto-negotiation complete of PHY register 1.
+ */
+
+extern int32 rtl8306e_port_phyAutoNegotiationDone_get(uint32 phy, uint32 *pDone) ;
+
+/* Function Name:
+ *      rtl8306e_port_phyLoopback_set
+ * Description:
+ *       Set PHY loopback
+ * Input:
+ *      phy         - Specify the phy to configure
+ *      enabled   - Enable phy loopback
+ * Output:
+ *      none      
+ * Return:
+ *      SUCCESS
+ *      FAILED
+ * Note:
+ *      Only phy 0~4 could be configured the phy loopback
+ */
+extern int32 rtl8306e_port_phyLoopback_set(uint32 phy, uint32 enabled);
+
+/* Function Name:
+ *      rtl8306e_port_phyLoopback_get
+ * Description:
+ *      Get PHY loopback setting
+ * Input:
+ *      phy         - Specify the phy to get status
+ * Output:
+ *      pEnabled  -  phy loopback setting
+ * Return:
+ *      SUCCESS
+ *      FAILED
+ * Note:
+ *
+ */
+extern int32 rtl8306e_port_phyLoopback_get(uint32 phy, uint32 *pEnabled) ;
+
+/* Function Name:
+ *      rtl8306e_portLearningAbility_set
+ * Description:
+ *      Enable/disable physical port learning ability
+ * Input:
+ *      port        - Specify port number (0 ~ 5)
+ * Output:
+ *      enabled -  TRUE or FALSE
+ * Return:
+ *      SUCCESS
+ * Note:
+ *
+ */
+extern int32 rtl8306e_portLearningAbility_set(uint32 port, uint32 enabled);
+
+
+/* Function Name:
+ *      rtl8306e_port_isolation_set
+ * Description:
+ *      set port isolation 
+ * Input:
+ *      isomsk    - port isolation port mask
+ * Output:
+ *      none
+ * Return:
+ *      SUCCESS
+ *      FAILED
+ * Note:
+ *      each bit of isomsk determine two port's isolation,
+ *      1 means two port could not forward packet between
+ *      each other.
+ *      bit 0  - Port0 & Port1 
+ *      bit 1  - Port0 & Port2 
+ *      bit 2  - Port0 & Port3
+ *      bit 3  - Port0 & Port4
+ *      bit 4  - Port0 & Port5
+ *      bit 5  - Port1 & Port2
+ *      bit 6  - Port1 & Port3
+ *      bit 7  - Port1 & Port4
+ *      bit 8  - Port1 & Port5
+ *      bit 9  - Port2 & Port3
+ *      bit 10 - Port2 & Port4
+ *      bit 11 - Port2 & Port5
+ *      bit 12 - Port3 & Port4
+ *      bit 13 - Port3 & Port5
+ *      bit 14 - Port4 & Port5
+ */
+extern int32 rtl8306e_port_isolation_set(uint32 isomsk);
+
+/* Function Name:
+ *      rtl8306e_port_isolation_set
+ * Description:
+ *      set port isolation 
+ * Input:
+ *      none
+ * Output:
+ *      pIsomsk    -  the pointer of port isolation port mask
+ * Return:
+ *      SUCCESS
+ *      FAILED
+ * Note:
+ *      each bit of isomsk determine two port's isolation,
+ *      1 means two port could not forward packet between
+ *      each other.
+ *      bit 0  - Port0 & Port1 
+ *      bit 1  - Port0 & Port2 
+ *      bit 2  - Port0 & Port3
+ *      bit 3  - Port0 & Port4
+ *      bit 4  - Port0 & Port5
+ *      bit 5  - Port1 & Port2
+ *      bit 6  - Port1 & Port3
+ *      bit 7  - Port1 & Port4
+ *      bit 8  - Port1 & Port5
+ *      bit 9  - Port2 & Port3
+ *      bit 10 - Port2 & Port4
+ *      bit 11 - Port2 & Port5
+ *      bit 12 - Port3 & Port4
+ *      bit 13 - Port3 & Port5
+ *      bit 14 - Port4 & Port5
+ */
+extern int32 rtl8306e_port_isolation_get(uint32 *pIsomsk);
+
+/*
+  *  VLAN function
+  */
+
+/* Function Name:
+ *      rtl8306e_vlan_tagAware_set
+ * Description:
+ *      Configure switch to be VLAN tag awared
+ * Input:
+ *      enabled  - Configure RTL8306 VLAN tag awared
+ * Output:
+ *      none
+ * Return:
+ *      SUCCESS
+ *      FAILED
+ * Note:
+ *      If switch is unawared VLAN tag, packet with vlan tag is treated as untagged pkt
+ *      and assigned PVID as VID.
+ */
+extern int32 rtl8306e_vlan_tagAware_set(uint32 enabled);
+
+/* Function Name:
+ *      rtl8306e_vlan_tagAware_set
+ * Description:
+ *      Get switch to be VLAN tag awared  or not
+ * Input:
+ *      none
+ * Output:
+ *      pEnabled  - the pointer of RTL8306 VLAN tag awared status
+ * Return:
+ *      SUCCESS
+ *      FAILED
+ * Note:
+ *      If switch is unawared VLAN tag, packet with vlan tag is treated as untagged pkt
+ *      and assigned PVID as VID.
+ */
+extern int32 rtl8306e_vlan_tagAware_get(uint32 * pEnabled);
+
+/* Function Name:
+ *      rtl8306e_vlan_IgrFilterEnable_set
+ * Description:
+ *      Configure VLAN ingress filter
+ * Input:
+ *      enabled  - enable or disable
+ * Output:
+ *      none 
+ * Return:
+ *      SUCCESS
+ *      FAILED
+ * Note:
+ *
+ */
+extern int32 rtl8306e_vlan_IgrFilterEnable_set(uint32 enabled); 
+
+/* Function Name:
+ *      rtl8306e_vlan_IgrFilterEnable_get
+ * Description:
+ *      Get VLAN ingress filter enabled or disabled
+ * Input:
+ *      none
+ * Output:
+ *      pEnabled  - enable or disable
+ * Return:
+ *      SUCCESS
+ *      FAILED
+ * Note:
+ *
+ */
+extern int32 rtl8306e_vlan_IgrFilterEnable_get(uint32 *pEnabled); 
+
+/* Function Name:
+ *      rtl8306e_vlan_leaky_set
+ * Description:
+ *      Configure switch to forward frames to other VLANs ignoring the egress rule.
+ * Input:
+ *      type   -  vlan leaky type
+ *      enabled  - enable or disable
+ * Output:
+ *      none 
+ * Return:
+ *      SUCCESS
+ *      FAILED
+ * Note:
+ *      type coulde be:
+ *          RTL8306_VALN_LEAKY_UNICAST - Vlan leaky for unicast pkt
+ *          RTL8306_VALN_LEAKY_MULTICAST - Vlan leaky for multicast pkt
+ *          RTL8306_VALN_LEAKY_ARP - Vlan leaky for ARP brodcast pkt 
+ *          RTL8306_VALN_LEAKY_MIRROR - Vlan leaky for mirror function
+ *    1.When the Vlan leaky for unicast pkt is enabled, it enables the inter-VLANs unicast packet forwarding. 
+ *    That is, if the L2 look up MAC table search hit, then the unicast packet will be forwarded
+ *    to the egress port ignoring the egress rule.
+ *    2.When Vlan leaky for multicast pkt is enabled, multicast packet may be flood to all multicast address
+ *    group member set, ignoring the VLAN member set domain limitation.
+ *    3.When Vlan leaky for ARP pkt is enabled, the ARP broadcast packets will be forward to all the other
+ *    ports ignoring the egress rule.
+ *    4.When Vlan leaky for mirror function is enabled, it enables the inter-VLANs mirror function, 
+ *    ignoring the VLAN member set domain limitation.
+ */
+extern int32 rtl8306e_vlan_leaky_set(uint32 type, uint32 enabled);
+
+/* Function Name:
+ *      rtl8306e_vlan_leaky_get
+ * Description:
+ *      Get switch whether forwards unicast frames to other VLANs
+ * Input:
+ *      type   -  vlan leaky type
+ * Output:
+ *      pEnabled  - the pointer of Vlan Leaky status(Dsiabled or Enabled) 
+ * Return:
+ *      SUCCESS
+ *      FAILED
+ * Note:
+ *   type coulde be:
+ *          RTL8306_VALN_LEAKY_UNICAST - Vlan leaky for unicast pkt
+ *          RTL8306_VALN_LEAKY_MULTICAST - Vlan leaky for multicast pkt
+ *          RTL8306_VALN_LEAKY_ARP - Vlan leaky for ARP brodcast pkt 
+ *    1.When the Vlan leaky for unicast pkt is enabled, it enables the inter-VLANs unicast packet forwarding. 
+ *    That is, if the L2 look up MAC table search hit, then the unicast packet will be forwarded
+ *    to the egress port ignoring the egress rule.
+ *    2.When Vlan leaky for multicast pkt is enabled, multicast packet may be flood to all multicast address
+ *    group member set, ignoring the VLAN member set domain limitation.
+ *    3.When Vlan leaky for ARP pkt is enabled, the ARP broadcast packets will be forward to all the other
+ *    ports ignoring the egress rule.
+ *    4.When Vlan leaky for mirror function is enabled, it enables the inter-VLANs mirror function, 
+ *    ignoring the VLAN member set domain limitation.
+ */
+extern int32 rtl8306e_vlan_leaky_get(uint32 type, uint32 *pEnabled);
+
+/* Function Name:
+ *      rtl8306e_vlan_nullVidReplace_set
+ * Description:
+ *      Configure switch to replace Null VID tagged frame by PVID if it is tag aware
+ * Input:
+ *      port   -  port number
+ *      enabled  - enable or disable
+ * Output:
+ *      none 
+ * Return:
+ *      SUCCESS
+ *      FAILED
+ * Note:
+ *      1.When Null VID replacement is enabled, 8306E only captures tagged packet with VID=0,
+ *      then replace VID with input port's PVID. If switch received a packet that is not tagged, 
+ *      it will not insert a tag with PVID to this packet.
+ *      2. When Null VID replacement is disabled, switch will drop or deal the null VID tagged 
+ *      frame depends on the configuration.
+ */
+extern int32 rtl8306e_vlan_nullVidReplace_set(uint32 port, uint32 enabled);
+
+/* Function Name:
+ *      rtl8306e_vlan_nullVidReplace_get
+ * Description:
+ *      Configure switch to forward frames to other VLANs ignoring the egress rule.
+ * Input:
+ *      port   -  port number
+ * Output:
+ *      pEnabled  - the pointer of Null VID replacement ability(Dsiabled or Enabled) 
+ * Return:
+ *      SUCCESS
+ *      FAILED
+ * Note:
+ *      1.When Null VID replacement is enabled, 8306E only captures tagged packet with VID=0,
+ *      then replace VID with input port's PVID. If switch received a packet that is not tagged, 
+ *      it will not insert a tag with PVID to this packet.
+ *      2. When Null VID replacement is disabled, switch will drop or deal the null VID tagged 
+ *      frame depends on the configuration.
+ */
+extern int32 rtl8306e_vlan_nullVidReplace_get(uint32 port, uint32 *pEnabled);
+
+/* Function Name:
+ *      rtl8306e_vlan_portPvidIndex_set
+ * Description:
+ *      Configure switch port PVID index 
+ * Input:
+ *      port           -   Specify the port(port 0 ~ port 5) to configure VLAN index
+ *      vlanIndex    -   Specify the VLAN index
+ * Output:
+ *      none
+ * Return:
+ *      SUCCESS
+ *      FAILED
+ * Note:
+ *      There are 16 vlan entry, VID of vlan entry pointed by PVID index  is the PVID 
+ */
+
+extern int32 rtl8306e_vlan_portPvidIndex_set(uint32 port, uint32 vlanIndex);
+
+/* Function Name:
+ *      rtl8306e_vlan_portPvidIndex_get
+ * Description:
+ *      Get switch port PVID index 
+ * Input:
+ *      port            -   Specify the port(port 0 ~ port 5) to configure VLAN index
+ * Output:
+ *      pVlanIndex   -   pointer of VLAN index number
+ * Return:
+ *      SUCCESS
+ *      FAILED
+ * Note:
+ *      There are 16 vlan entry, VID of vlan entry pointed by PVID index  is the PVID 
+ */
+
+extern int32 rtl8306e_vlan_portPvidIndex_get(uint32 port, uint32 *pVlanIndex);
+
+/* Function Name:
+ *      rtl8306e_vlan_portAcceptFrameType_set
+ * Description:
+ *      Set VLAN support frame type
+ * Input:
+ *      port                                 - Port id
+ *      accept_frame_type             - accept frame type
+ * Output:
+ *      none
+ * Return:
+ *      SUCCESS
+ *      FAILED
+ * Note:
+ *    The API is used for checking 802.1Q tagged frames.
+ *    The accept frame type as following:
+ *    RTL8306E_ACCEPT_ALL
+ *    RTL8306E_ACCEPT_TAG_ONLY
+ *    RTL8306E_ACCEPT_UNTAG_ONLY
+ */
+extern int32 rtl8306e_vlan_portAcceptFrameType_set(uint32 port, rtl8306e_acceptFrameType_t accept_frame_type);
+
+/* Function Name:
+ *      rtl8306e_vlan_portAcceptFrameType_get
+ * Description:
+ *      Get VLAN support frame type
+ * Input:
+ *      port                                 - Port id
+ * Output:
+ *      pAccept_frame_type             - accept frame type pointer
+ * Return:
+ *      SUCCESS
+ *      FAILED
+ * Note:
+ *    The API is used for checking 802.1Q tagged frames.
+ *    The accept frame type as following:
+ *    RTL8306E_ACCEPT_ALL
+ *    RTL8306E_ACCEPT_TAG_ONLY
+ *    RTL8306E_ACCEPT_UNTAG_ONLY
+ */
+extern int32 rtl8306e_vlan_portAcceptFrameType_get(uint32 port, rtl8306e_acceptFrameType_t *pAccept_frame_type);
+
+/* Function Name:
+ *      rtl8306e_vlan_tagInsert_set
+ * Description:
+ *      Insert VLAN tag by ingress port
+ * Input:
+ *      egPort               - egress port number 0~5
+ *      igPortMsk           - ingress port mask
+ * Output:
+ *      none
+ * Return:
+ *      SUCCESS
+ *      FAILED
+ * Note:
+ *      egPort is packet egress port, if the packet is untagged and its igress port
+ *      is in the igPortMsk, it will be inserted with an VLAN tag.
+ */
+extern int32 rtl8306e_vlan_tagInsert_set(uint32 egPort, uint32 igPortMsk);
+
+/* Function Name:
+ *      rtl8306e_vlan_tagInsert_get
+ * Description:
+ *      get  ingress port mask of VLAN tag insertion for untagged packet
+ * Input:
+ *      egPort               - egress port number 0~5
+ *      igPortMsk           - ingress port mask
+ * Output:
+ *      none
+ * Return:
+ *      SUCCESS
+ *      FAILED
+ * Note:
+ *      egPort is packet egress port, if the packet is untagged and its igress port
+ *      is in the igPortMsk, it will be inserted with an VLAN tag.
+ */
+extern int32 rtl8306e_vlan_tagInsert_get(uint32 egPort, uint32 * pIgPortMsk);
+
+/*added by Fan Kaixi, 2012-01-18*/
+
+/* Function Name:
+ *      rtl8306e_vlan_tagInsertRemove_set
+ * Description:
+ *      set per port vlan tag action
+ * Input:
+ *      Port               - egress port number 0~5
+ *      option              - action options, insert/remove/replace/untouch
+ * Output:
+ *      none
+ * Return:
+ *      SUCCESS
+ *      FAILED
+ * Note:
+ *      port is egress port number from 0 to 5. option is the action the egress
+ *      port will take on packets tx from itself.
+ *      option have values as follows:
+ *          RTL8306_VLAN_IRTAG = 0  ---  insert tag for untagged packets, remove tag from tagged packets and add new tag to it
+ *          RTL8306_VLAN_RTAG,      ---  remove tag from tagged packets, don't touch untagged packets                 
+ *          RTL8306_VLAN_ITAG,      ---  insert tag for untagged packets, don't touch tagged packets       
+ *          RTL8306_VLAN_UNDOTAG    ---  don't touch tag for packets 
+ *      when egress port decide to insert tag for untagged packets, the tag vid is derived from packets'
+ *      ingress port pvid.
+*/
+extern int32 rtl8306e_vlan_tagInsertRemove_set(uint32 egport, uint32 option);
+
+/* Function Name:
+ *      rtl8306e_vlan_tagInsertRemove_get
+ * Description:
+ *      get per port vlan tag action
+ * Input:
+ *      Port               - egress port number 0~5
+ * Output:
+ *      pOption              - action options, insert/remove/replace/untouch
+ * Return:
+ *      SUCCESS
+ *      FAILED
+ * Note:
+ *      port is egress port number from 0 to 5. option is the action the egress
+ *      port will take on packets tx from itself.
+ *      option have values as follows:
+ *          RTL8306_VLAN_IRTAG = 0  ---  insert tag for untagged packets, remove tag from tagged packets and add new tag to it
+ *          RTL8306_VLAN_RTAG,      ---  remove tag from tagged packets, don't touch untagged packets                 
+ *          RTL8306_VLAN_ITAG,      ---  insert tag for untagged packets, don't touch tagged packets       
+ *          RTL8306_VLAN_UNDOTAG    ---  don't touch tag for packets 
+ *      when egress port decide to insert tag for untagged packets, the tag vid is derived from packets'
+ *      ingress port pvid.
+*/
+extern int32 rtl8306e_vlan_tagInsertRemove_get(uint32 egport, uint32 *pOption);
+
+/* Function Name:
+ *      rtk_vlan_set
+ * Description:
+ *      Set a VLAN entry
+ * Input:
+ *      vlanIndex  - VLAN entry index
+ *      vid           - VLAN ID to configure
+ *      mbrmsk     - VLAN member set portmask
+ *      untagmsk  - VLAN untag set portmask
+ * Output:
+ *      none
+ * Return:
+ *      SUCCESS
+ *      FAILED
+ * Note:
+ *     There are 16 VLAN entry supported. User could configure the member set and untag set
+ *     for specified vid through this API. The portmask's bit N means port N.
+ *     For example, mbrmask 23=0x17=010111 means port 0,1,2,4 in the member set.
+ */
+extern int32 rtl8306e_vlan_entry_set(uint32 vlanIndex, uint32 vid, uint32 mbrmsk, uint32 untagmsk );
+
+/* Function Name:
+ *      rtl8306e_vlan_entry_get
+ * Description:
+ *      Get a VLAN entry
+ * Input:
+ *      vlanIndex  - VLAN entry index
+ * Output:
+ *      pVid           -  the pointer of VLAN ID 
+ *      pMbrmsk     -  the pointer of VLAN member set portmask
+ *      pUntagmsk  -  the pointer of VLAN untag set portmask
+ * Return:
+ *      SUCCESS
+ *      FAILED
+ * Note:
+ *     There are 16 VLAN entry supported. User could configure the member set and untag set
+ *     for specified vid through this API. The portmask's bit N means port N.
+ *     For example, mbrmask 23=0x17=010111 means port 0,1,2,4 in the member set.
+ */
+extern int32 rtl8306e_vlan_entry_get(uint32 vlanIndex, uint32 *pVid, uint32 *pMbrmsk, uint32 *pUntagmsk);
+
+/* Function Name:
+ *      rtl8306e_vlan_vlanBasedPriority_set
+ * Description:
+ *       Set VID based priority
+ * Input:
+ *      vlanIndex   -   Specify VLAN entry index
+ *      pri            -   the specified VLAN priority  
+ * Output:
+ *      none
+ * Return:
+ *      SUCCESS
+ *      FAILED
+ * Note:
+ *      each VLAN could be assigned an priority. if vlanIndex > 15, it means the VID
+ *      is not in VLAN entries, unmatched VID could also be assigned an priority.
+ *       
+ */
+extern int32 rtl8306e_vlan_vlanBasedPriority_set(uint32 vlanIndex, uint32 pri);
+
+/* Function Name:
+ *      rtl8306e_vlan_vlanBasedPriority_get
+ * Description:
+ *       Get VID based priority
+ * Input:
+ *      vlanIndex   -   Specify VLAN entry index
+ * Output:
+ *      pPri           -   the pointer of specified VLAN priority  
+ * Return:
+ *      SUCCESS
+ *      FAILED
+ * Note:
+ *      each VLAN could be assigned an priority. if vlanIndex > 15, it means the VID
+ *      is not in VLAN entries, unmatched VID could also be assigned an priority.
+ *       
+ */
+extern int32 rtl8306e_vlan_vlanBasedPriority_get(uint32 vlanIndex, uint32 *pPri);
+
+/* Function Name:
+ *      rtl8306e_vlan_transEnable_set
+ * Description:
+ *      Enable VLAN translation 
+ * Input:
+ *      enable       -   enable or disable VLAN translation
+ *      portmask    -   NNI port is set 1 and UNI port is set 0
+ * Output:
+ *      none
+ * Return:
+ *      SUCCESS
+ *      FAILED
+ * Note:
+ *      Only the traffic between NNI port and UNI port will be change with VID,
+ *      the VLAN tranlation function and Q-in-Q(SVLAN) could not be enabled  
+ *      at the same time, user should choose one of them. 
+ */
+extern int32 rtl8306e_vlan_transEnable_set(uint32 enable, uint32 portmask);
+
+/* Function Name:
+ *      rtl8306e_vlan_transEnable_get
+ * Description:
+ *      Get VLAN translation setting
+ * Input:
+ *      none
+ * Output:
+ *      pEnable       -   the pointer of enable or disable VLAN translation
+ *      pPortMask    -   the pointer of VLAN translation port mask
+ * Return:
+ *      SUCCESS
+ *      FAILED
+ * Note:
+ *      Only the traffic between NNI port and UNI port will be change with VID,
+ *      the VLAN tranlation function and Q-in-Q(SVLAN) could not be enabled  
+ *      at the same time, user should choose one of them. 
+ */
+extern int32 rtl8306e_vlan_transEnable_get(uint32 *pEnable, uint32 *pPortMask);
+
+/* Function Name:
+ *      rtl8306e_vlan_transparentEnable_set
+ * Description:
+ *      Enable VLAN transparent 
+ * Input:
+ *      enable       -   enable or disable VLAN transparent
+ * Output:
+ *      none
+ * Return:
+ *      SUCCESS
+ *      FAILED
+ * Note:
+ */
+extern int32 rtl8306e_vlan_transparentEnable_set(uint32 enable);
+
+/* Function Name:
+ *      rtl8306e_vlan_transVid_set
+ * Description:
+ *      Set the translated VID
+ * Input:
+ *      vlanIndex   -   the VLAN entry index
+ *      transVid     -   the new VID
+ * Output:
+ *      none
+ * Return:
+ *      SUCCESS
+ *      FAILED
+ * Note:
+ *      The VID in the entry indexed by vlanIndex will be replaced with
+ *      new VID.
+ */ 
+extern int32 rtl8306e_vlan_transVid_set(uint32 vlanIndex, uint32 transVid);
+
+
+/* Function Name:
+ *      rtl8306e_vlan_transVid_get
+ * Description:
+ *      Get the translated VID
+ * Input:
+ *      vlanIndex   -   the VLAN entry index
+ * Output:
+ *      pTransVid   -   the pointer of the new VID
+ * Return:
+ *      SUCCESS
+ *      FAILED
+ * Note:
+ *      The VID in the entry indexed by vlanIndex will be replaced with
+ *      new VID.
+ */ 
+extern int32 rtl8306e_vlan_transVid_get(uint32 vlanIndex, uint32 *pTransVid);
+
+
+/* Function Name:
+ *      rtl8306e_svlan_tagAdmit_set
+ * Description:
+ *      Set Q-in-Q tag admit control
+ * Input:
+ *      port          -   port id
+ *      enable       -   enable tag admit control 
+ * Output:
+ *      none
+ * Return:
+ *      SUCCESS
+ *      FAILED
+ * Note:
+ *       
+ */
+extern int32 rtl8306e_svlan_tagAdmit_set(uint32 port, uint32 enable);
+
+/* Function Name:
+ *      rtl8306e_svlan_tagAdmit_get
+ * Description:
+ *      Get Q-in-Q tag admit control
+ * Input:
+ *      port          -   port id
+ * Output:
+ *      pEnable     -   the pointer of enable tag admit control 
+ * Return:
+ *      SUCCESS
+ *      FAILED
+ * Note:
+ *       
+ */
+extern int32 rtl8306e_svlan_tagAdmit_get(uint32 port, uint32 *pEnable);
+
+/* Function Name:
+ *      rtl8306e_svlan_otagSrc_set
+ * Description:
+ *      Set how to decide outer tag vid and priority 
+ * Input:
+ *      port          -   port id
+ *      ovidSrc      -   ovid comes from
+ *      opriSrc      -    opri comes from 
+ * Output:
+ *      none
+ * Return:
+ *      SUCCESS
+ *      FAILED
+ * Note:
+ *       ovidSrc RTL8306E_VIDSRC_POVID : ovid is port-based ovid,    RTL8306E_VIDSRC_NVID:ovid is new vid(translated vid)
+ *       opriSrc  RTL8306E_PRISRC_PPRI   : opri is port-based priority, RTL8306E_PRISRC_1PRMK: opri is 1p remarking value
+ */
+extern int32 rtl8306e_svlan_otagSrc_set(uint32 port, uint32 ovidSrc, uint32 opriSrc);
+
+/* Function Name:
+ *      rtl8306e_svlan_otagSrc_get
+ * Description:
+ *      Get how to decide outer tag vid and priority 
+ * Input:
+ *      port            -   port id
+ * Output:
+ *      pOvidsrc      -   the pointer of ovid comes from
+ *      pOpriSrc      -   the pointer of opri comes from 
+ * Return:
+ *      SUCCESS
+ *      FAILED
+ * Note:
+ *       ovidSrc RTL8306E_VIDSRC_POVID : ovid is port-based ovid,    RTL8306E_VIDSRC_NVID:ovid is new vid(translated vid)
+ *       opriSrc  RTL8306E_PRISRC_PPRI   : opri is port-based priority, RTL8306E_PRISRC_1PRMK: opri is 1p remarking value
+ */
+extern int32 rtl8306e_svlan_otagSrc_get(uint32 port, uint32 *pOvidsrc, uint32 *pOpriSrc);
+
+/* Function Name:
+ *      rtl8306e_cpu_set
+ * Description:
+ *       Specify Asic CPU port 
+ * Input:
+ *      port       -   Specify the port
+ *      enTag    -    CPU tag insert or not
+ * Output:
+ *      none
+ * Return:
+ *      SUCCESS
+ *      FAILED
+ * Note:
+ *      If the port is specified RTL8306_NOCPUPORT, it means
+ *      that no port is assigned as cpu port
+ */
+extern int32 rtl8306e_cpu_set(uint32 port, uint32 enTag) ;
+
+/* Function Name:
+ *      rtl8306e_cpu_set
+ * Description:
+ *       Get Asic CPU port number
+ * Input:
+ *      none
+ * Output:
+ *      pPort     - the pointer of CPU port number
+ *      pEnTag  - the pointer of CPU tag insert or not
+ * Return:
+ *      SUCCESS
+ *      FAILED
+ * Note:
+ *      If the port is specified RTL8306_NOCPUPORT, it means
+ *      that no port is assigned as cpu port
+ */
+
+extern int32 rtl8306e_cpu_get(uint32 *pPort, uint32 *pEnTag) ;
+
+/* Function Name:
+ *      rtl8306e_cpu_doubleTagInsert_set
+ * Description:
+ *      Enable synchronously insertting cpu tag and vlan tag ability
+ * Input:
+ *      enabled     -   enable or disable
+ * Output:
+ *      none
+ * Return:
+ *      SUCCESS
+ *      FAILED
+ * Note:
+ *      This API can be called to enable synchronously insertting cpu tag and vlan tag ability.
+*/
+extern int32 rtl8306e_cpu_doubleTagInsert_set(uint32 enabled);
+
+/* Function Name:
+ *      rtl8306e_cpu_doubleTagInsert_get
+ * Description:
+ *      Get Enabled status of synchronously insertting cpu tag and vlan tag ability
+ * Input:
+ *      none
+ * Output:
+ *      pEnabled    -   enable or disable
+ * Return:
+ *      SUCCESS
+ *      FAILED
+ * Note:
+ *      This API can be called to enable synchronously insertting cpu tag and vlan tag ability.
+*/
+extern int32 rtl8306e_cpu_doubleTagInsert_get(uint32 *pEnabled);
+
+/*
+  *  QOS  function
+  */
+
+/* Function Name:
+ *      rtl8306e_qos_softReset_set
+ * Description:
+ *      Software reset the asic
+ * Input:
+ *      none
+ * Output:
+ *      none
+ * Return:
+ *      SUCCESS
+ *      FAILED
+ * Note:
+ *      reset packet buffer.
+ */
+extern int32 rtl8306e_qos_softReset_set(void) ;
+
+/* Function Name:
+ *      rtl8306e_qos_queueNum_set
+ * Description:
+ *      Set egress port queue number (1 ~4)
+ * Input:
+ *      none
+ * Output:
+ *      none
+ * Return:
+ *      SUCCESS
+ *      FAILED
+ * Note:
+ *      Queue number is global configuration for switch.
+ */
+extern int32 rtl8306e_qos_queueNum_set(uint32 num);
+
+/* Function Name:
+ *      rtl8306e_qos_queueNum_set
+ * Description:
+ *      Set egress port queue number (1 ~4)
+ * Input:
+ *      none
+ * Output:
+ *      none
+ * Return:
+ *      SUCCESS
+ *      FAILED
+ * Note:
+ *      Queue number is global configuration for switch.
+ */
+extern int32 rtl8306e_qos_queueNum_get(uint32 *pNum) ;
+
+/* Function Name:
+ *      rtl8306e_qos_priToQueMap_set
+ * Description:
+ *     Set priority to Queue ID mapping
+ * Input:
+ *      priority   -  priority value (0 ~ 3)
+ *      qid        -  Queue id (0~3)
+ * Output:
+ *      none
+ * Return:
+ *      SUCCESS
+ *      FAILED
+ * Note:
+ *      Packets could be classified into specified queue through their priority. 
+ *      we can use this function to set pkt priority with queue id mapping
+ */
+extern int32 rtl8306e_qos_priToQueMap_set(uint32 priority, uint32 qid) ;
+
+/* Function Name:
+ *      rtl8306e_qos_priToQueMap_get
+ * Description:
+ *      Get priority to Queue ID mapping
+ * Input:
+ *      priority   -  priority value (0 ~ 3)
+ * Output:
+ *      pQid      -  pointer of Queue id (0~3)
+ * Return:
+ *      SUCCESS
+ *      FAILED
+ * Note:
+ *      Packets could be classified into specified queue through their priority. 
+ *      we can use this function to set pkt priority with queue id mapping
+ */
+extern int32 rtl8306e_qos_priToQueMap_get(uint32 priority, uint32 *pQid) ;
+
+/* Function Name:
+ *      rtl8306e_qos_portRate_set
+ * Description:
+ *      Set port bandwidth control
+ * Input:
+ *      port            -  port number (0~5)
+ *      n64Kbps       -  Port rate (0~1526), unit 64Kbps
+ *      direction      -  Ingress or Egress bandwidth control
+ *      enabled       -  enable bandwidth control
+ * Output:
+ *      none
+ * Return:
+ *      SUCCESS
+ *      FAILED
+ * Note:
+ *      For each port, both input and output bandwidth could be configured, 
+ *      RTL8306_PORT_RX represents port input bandwidth control, 
+ *      RTL8306_PORT_TX represents port output bandwidth control.
+ *      port rate unit is 64Kbps. For output rate control, enable/disable 
+ *      is configured per port, but for input rate control, it is for all port.
+ */
+extern int32 rtl8306e_qos_portRate_set(uint32 port, uint32 n64Kbps, uint32 direction, uint32 enabled);
+
+/* Function Name:
+ *      rtl8306e_qos_portRate_get
+ * Description:
+ *      Get port bandwidth control rate
+ * Input:
+ *      port                 -  Port number (0~5)
+ * Output:
+ *      *pN64Kbps        -  Port rate (0~1526), unit 64Kbps
+ *      direction           -  Input or output bandwidth control
+ *      *enabled           -  enabled or disabled bandwidth control
+ * Return:
+ *      SUCCESS
+ *      FAILED
+ * Note:
+ *      For each port, both input and output bandwidth could be configured, 
+ *      RTL8306_PORT_RX represents port input bandwidth control, 
+ *      RTL8306_PORT_TX represents port output bandwidth control.
+ *      port rate unit is 64Kbps. For output rate control, enable/disable 
+ *      is configured per port, but for input rate control, it is for all port.
+ */
+extern int32 rtl8306e_qos_portRate_get(uint32 port, uint32 *pN64Kbps, uint32 direction, uint32 *pEnabled);
+
+/* Function Name:
+ *      rtl8306e_qos_1pRemarkEnable_set
+ * Description:
+ *      Set 802.1P remarking ability
+ * Input:
+ *      port       -  port number (0~5)
+ *      enabled  -  TRUE or FALSE
+ * Output:
+ *      none
+ * Return:
+ *      SUCCESS
+ *      FAILED
+ * Note:
+ *      
+ */
+extern int32 rtl8306e_qos_1pRemarkEnable_set(uint32 port, uint32 enabled);
+
+/* Function Name:
+ *      rtl8306e_qos_1pRemarkEnable_set
+ * Description:
+ *      Get 802.1P remarking ability
+ * Input:
+ *      port        -  port number (0~5)
+ * Output:
+ *      pEnabled  -  pointer of the ability status
+ * Return:
+ *      SUCCESS
+ *      FAILED
+ * Note:
+ *      
+ */
+extern int32 rtl8306e_qos_1pRemarkEnable_get(uint32 port, uint32 *pEnabled) ;
+
+/* Function Name:
+ *      rtl8306e_qos_1pRemark_set
+ * Description:
+ *      Set 802.1P remarking priority
+ * Input:
+ *      priority       -  Packet priority(0~4)
+ *      priority1p    -  802.1P priority(0~7)
+ * Output:
+ *      none
+ * Return:
+ *      SUCCESS
+ *      FAILED
+ * Note:
+ *      switch determines packet priority, the priority souce could
+ *      be port-based, 1Q-based, dscp-based, vid-based, ip address,
+ *      cpu tag.
+ */
+extern int32 rtl8306e_qos_1pRemark_set(uint32 priority, uint32 priority1p);
+
+/* Function Name:
+ *      rtl8306_getAsic1pRemarkingPriority
+ * Description:
+ *      Get 802.1P remarking priority
+ * Input:
+ *      priority       -  Packet priority(0~4)
+ * Output:
+ *      pPriority1p  -  the pointer of 802.1P priority(0~7)
+ * Return:
+ *      SUCCESS
+ *      FAILED
+ * Note:
+ *      switch determines packet priority, the priority souce could
+ *      be port-based, 1Q-based, dscp-based, vid-based, ip address,
+ *      cpu tag.
+ */
+extern int32 rtl8306e_qos_1pRemark_get(uint32 priority, uint32 *pPriority1p);
+
+/* Function Name:
+ *      rtl8306e_qos_portPri_set
+ * Description:
+ *      Set port-based priority
+ * Input:
+ *      port          -  port number (0~5)
+ *      priority      -  Packet port-based priority(0~4)
+ * Output:
+*       none
+ * Return:
+ *      SUCCESS
+ *      FAILED
+ * Note:
+ *      packet will be assigned a port-based priority correspond to the ingress port.
+ */
+extern int32 rtl8306e_qos_portPri_set(uint32 port, uint32 priority);
+
+/* Function Name:
+ *      rtl8306e_qos_portPri_get
+ * Description:
+ *      Get port-based priority
+ * Input:
+ *      port          -  port number (0~5)
+ * Output:
+ *      pPriority    -   pointer of packet port-based priority(0~4)
+ * Return:
+ *      SUCCESS
+ *      FAILED
+ * Note:
+ *      packet will be assigned a port-based priority correspond to the ingress port.
+ */ 
+extern int32 rtl8306e_qos_portPri_get(uint32 port, uint32 *pPriority);
+
+/* Function Name:
+ *      rtl8306e_qos_1pPriRemap_set
+ * Description:
+ *      Set Asic 1Q-tag priority mapping to 2-bit priority
+ * Input:
+ *      tagprio  -  1Q-tag proirty (0~7, 3 bit value)
+ *      prio      -   internal use 2-bit priority
+ * Output:
+ *      none
+ * Return:
+ *      SUCCESS
+ *      FAILED
+ * Note:
+ *      switch internal use 2-bit priority, so it should map 3-bit 1Q-tag priority
+ *      to 2-bit priority
+ */ 
+extern int32 rtl8306e_qos_1pPriRemap_set(uint32 tagprio, uint32 prio) ;
+
+/* Function Name:
+ *      rtl8306e_qos_1pPriRemap_get
+ * Description:
+ *      Get Asic 1Q-tag priority mapping to 2-bit priority
+ * Input:
+ *      tagprio  -  1Q-tag proirty (0~7, 3 bit value)
+ * Output:
+ *      pPrio     -  pointer of  internal use 2-bit priority
+ * Return:
+ *      SUCCESS
+ *      FAILED
+ * Note:
+ *      switch internal use 2-bit priority, so it should map 3-bit 1Q-tag priority
+ *      to 2-bit priority
+ */ 
+extern int32 rtl8306e_qos_1pPriRemap_get(uint32 tagprio, uint32 *pPrio);
+
+/* Function Name:
+ *      rtl8306e_dscpPriRemap_set
+ * Description:
+ *      Set DSCP-based priority
+ * Input:
+ *      code      -  dscp code
+ *      priority   -  dscp-based priority
+ * Output:
+ *      none
+ * Return:
+ *      SUCCESS
+ *      FAILED
+ * Note:
+ *      switch support 16 kinds of dscp code:
+ *          RTL8306_DSCP_EF          
+ *                 - DSCP for the Expedited forwarding PHB, 101110   
+ *          RTL8306_DSCP_AFL1         
+ *                 - DSCP for AF PHB Class 1 low drop, 001010
+ *          RTL8306_DSCP_AFM1     
+ *                 - DSCP for AF PHB Class 1 medium drop, 001100
+ *          RTL8306_DSCP_AFH1      
+ *                 - DSCP for AF PHB Class 1 high drop, 001110
+ *          RTL8306_DSCP_AFL2       
+ *                 - DSCP for AF PHB Class 2 low drop, 01001
+ *          RTL8306_DSCP_AFM2       
+ *                 - DSCP for AF PHB Class 2 medium drop, 010100
+ *          RTL8306_DSCP_AFH2   
+ *                 - DSCP for AF PHB Class 2 high drop, 010110
+ *          RTL8306_DSCP_AFL3    
+ *                 - DSCP for AF PHB Class 3 low drop, 011010
+ *          RTL8306_DSCP_AFM3      
+ *                 - DSCP for AF PHB Class 3 medium drop, 011100
+ *          RTL8306_DSCP_AFH3    
+ *                 - DSCP for AF PHB Class 3 high drop, 0111
+ *          RTL8306_DSCP_AFL4     
+ *                 - DSCP for AF PHB Class 4 low drop, 100010
+ *          RTL8306_DSCP_AFM4    
+ *                 - DSCP for AF PHB Class 4 medium drop, 100100
+ *          RTL8306_DSCP_AFH4     
+ *                 - DSCP for AF PHB Class 4 high drop, 100110
+ *          RTL8306_DSCP_NC        
+ *                 - DSCP for network control, 110000 or 111000
+ *          RTL8306_DSCP_REG_PRI 
+ *                 - DSCP Register match priority, user could define two dscp code
+ *          RTL8306_DSCP_BF        
+ *                 - DSCP Default PHB
+ *     
+ */ 
+extern int32 rtl8306e_qos_dscpPriRemap_set(uint32 code, uint32 priority) ;
+
+/* Function Name:
+ *      rtl8306e_dscpPriRemap_set
+ * Description:
+ *      Get DSCP-based priority
+ * Input:
+ *      code      -  dscp code
+ * Output:
+ *      pPriority  -  the pointer of dscp-based priority
+ * Return:
+ *      SUCCESS
+ *      FAILED
+ * Note:
+ *      switch support 16 kinds of dscp code:
+ *          RTL8306_DSCP_EF          
+ *                 - DSCP for the Expedited forwarding PHB, 101110   
+ *          RTL8306_DSCP_AFL1         
+ *                 - DSCP for AF PHB Class 1 low drop, 001010
+ *          RTL8306_DSCP_AFM1     
+ *                 - DSCP for AF PHB Class 1 medium drop, 001100
+ *          RTL8306_DSCP_AFH1      
+ *                 - DSCP for AF PHB Class 1 high drop, 001110
+ *          RTL8306_DSCP_AFL2       
+ *                 - DSCP for AF PHB Class 2 low drop, 01001
+ *          RTL8306_DSCP_AFM2       
+ *                 - DSCP for AF PHB Class 2 medium drop, 010100
+ *          RTL8306_DSCP_AFH2   
+ *                 - DSCP for AF PHB Class 2 high drop, 010110
+ *          RTL8306_DSCP_AFL3    
+ *                 - DSCP for AF PHB Class 3 low drop, 011010
+ *          RTL8306_DSCP_AFM3      
+ *                 - DSCP for AF PHB Class 3 medium drop, 011100
+ *          RTL8306_DSCP_AFH3    
+ *                 - DSCP for AF PHB Class 3 high drop, 0111
+ *          RTL8306_DSCP_AFL4     
+ *                 - DSCP for AF PHB Class 4 low drop, 100010
+ *          RTL8306_DSCP_AFM4    
+ *                 - DSCP for AF PHB Class 4 medium drop, 100100
+ *          RTL8306_DSCP_AFH4     
+ *                 - DSCP for AF PHB Class 4 high drop, 100110
+ *          RTL8306_DSCP_NC        
+ *                 - DSCP for network control, 110000 or 111000
+ *          RTL8306_DSCP_REG_PRI 
+ *                 - DSCP Register match priority, user could define two dscp code
+ *          RTL8306_DSCP_BF        
+ *                 - DSCP Default PHB
+ *     
+ */ 
+extern int32 rtl8306e_qos_dscpPriRemap_get(uint32 code, uint32 *pPriority);
+
+/* Function Name:
+ *      rtl8306e_qos_priSrcArbit_set
+ * Description:
+ *      Set priority source arbitration level
+ * Input:
+ *      priArbit  - The structure describe levels of 5 kinds of priority 
+ * Output:
+ *      none
+ * Return:
+ *      SUCCESS
+ *      FAILED
+ * Note:
+ *      switch could recognize 7 types of priority source at most, 
+ *      and a packet properly has all of them. among them, there 
+ *      are 5 type priorities could be set priority level, they are 
+ *      ACL-based  priority, DSCP-based priority, 1Q-based priority,
+ *      Port-based priority, VID- based priority.each one could be 
+ *      set level from 0 to 5, arbitration module will decide their sequece 
+ *      to take, the highest level priority will be adopted at first, 
+ *      then  priority type of the sencond highest level. priority with level 0
+ *      will not be recognized any more. 
+ */
+extern int32 rtl8306e_qos_priSrcArbit_set(rtl8306e_qosPriArbitPara_t priArbit);
+
+/* Function Name:
+ *      rtl8306e_qos_priSrcArbit_get
+ * Description:
+ *      Get priority source arbitration level
+ * Input:
+ *      none 
+ * Output:
+ *      pPriArbit  - The structure describe levels of 5 kinds of priority 
+ * Return:
+ *      SUCCESS
+ *      FAILED
+ * Note:
+ *      switch could recognize 7 types of priority source at most, 
+ *      and a packet properly has all of them. among them, there 
+ *      are 5 type priorities could be set priority level, they are 
+ *      ACL-based  priority, DSCP-based priority, 1Q-based priority,
+ *      Port-based priority, VID- based priority.each one could be 
+ *      set level from 0 to 5, arbitration module will decide their sequece 
+ *      to take, the highest level priority will be adopted at first, 
+ *      then  priority type of the sencond highest level. priority with level 0
+ *      will not be recognized any more. 
+ */
+extern int32 rtl8306e_qos_priSrcArbit_get(rtl8306e_qosPriArbitPara_t *pPriArbit);
+
+/* Function Name:
+ *      rtl8306e_qos_priSrcEnable_set
+ * Description:
+ *      enable/disable Qos priority source for  ingress port
+ * Input:
+ *      port      -  Specify port number (0 ~5)
+ *      priSrc    -  Specify priority source  
+ *      enabled -   TRUE of FALSE  
+ * Output:
+ *      none
+ * Return:
+ *      SUCCESS
+ *      FAILED
+ * Note:
+ *     There are 4 kind of priority source for each port which could
+ *     be enabled ordisabled:
+ *          RTL8306_DSCP_PRIO     - DSCP-based priority
+ *          RTL8306_1QBP_PRIO     - 1Q-based priority
+ *          RTL8306_PBP_PRIO        - port-based priority
+ *          RTL8306_CPUTAG_PRIO  - cpu tag priority
+ */
+extern int32 rtl8306e_qos_priSrcEnable_set(uint32 port, uint32 priSrc, uint32 enabled);
+
+/* Function Name:
+ *      rtl8306e_qos_priSrcEnable_set
+ * Description:
+ *      enable/disable Qos priority source for  ingress port
+ * Input:
+ *      port       -  Specify port number (0 ~5)
+ *      priSrc     -  Specify priority source  
+ * Output:
+ *      pEnabled -  the pointer of priority source status  
+ * Return:
+ *      SUCCESS
+ *      FAILED
+ * Note:
+ *     There are 4 kind of priority source for each port which could
+ *     be enabled ordisabled:
+ *          RTL8306_DSCP_PRIO     - DSCP-based priority
+ *          RTL8306_1QBP_PRIO     - 1Q-based priority
+ *          RTL8306_PBP_PRIO        - port-based priority
+ *          RTL8306_CPUTAG_PRIO  - cpu tag priority
+ */
+extern int32 rtl8306e_qos_priSrcEnable_get(uint32 port, uint32 priSrc, uint32 *pEnabled);
+
+/* Function Name:
+ *      rtl8306e_qos_ipAddrPri_set
+ * Description:
+ *      Set IP address priority
+ * Input:
+ *      priority  -  internal use 2-bit priority value (0~3)  
+ * Output:
+ *      none
+ * Return:
+ *      SUCCESS
+ *      FAILED
+ * Note:
+ */
+extern int32 rtl8306e_qos_ipAddrPri_set(uint32 priority); 
+
+/* Function Name:
+ *      rtl8306e_qos_ipAddrPri_get
+ * Description:
+ *      Get IP address priority
+ * Input:
+ *      priority  -  internal use 2-bit priority value (0~3)  
+ * Output:
+ *      none
+ * Return:
+ *      SUCCESS
+ *      FAILED
+ * Note:
+ */
+extern int32 rtl8306e_qos_ipAddrPri_get(uint32 *priority);
+
+/* Function Name:
+ *      rtl8306e_qos_ipAddr_set
+ * Description:
+ *      Set IP address
+ * Input:
+ *      entry        -   specify entry
+         ip            -   ip address
+         mask        -  ip mask
+         enabled    -   enable the entry
+ * Output:
+ *      none
+ * Return:
+ *      SUCCESS
+ *      FAILED
+ * Note:
+ *      There are two entries RTL8306_IPADD_A and RTL8306_IPADD_B
+ *      for user setting ip address, if ip address of packet matches
+ *      the entry, the packet will be assign the priority of ip address
+ *      priority which is configured by rtl8306e_qos_ipAddrPri_set.
+ */
+extern int32 rtl8306e_qos_ipAddr_set(uint32 entry, uint32 ip, uint32 mask, uint32 enabled);
+
+/* Function Name:
+ *      rtl8306e_qos_ipAddr_get
+ * Description:
+ *      Get IP address user seting
+ * Input:
+ *      entry       -   specify entry
+ * Output:
+ *      pIp            -   ip address
+         pMask        -   ip mask
+         pEnabled    -  enabled or disabled the entry for IP Priority
+ * Return:
+ *      SUCCESS
+ *      FAILED
+ * Note:
+ */
+extern int32 rtl8306e_qos_ipAddr_get(uint32 entry, uint32 *pIp, uint32 *pMask , uint32 *pEnabled); 
+
+/* Function Name:
+ *      rtl8306e_qos_schedulingPara_set
+ * Description:
+ *      Set qos scheduling parameter
+ * Input:
+ *      set          -  RTL8306_QOS_SET0 or RTL8306_QOS_SET1
+ *      sch_para  -  The structure describe schedule parameter
+ * Output:
+ *      none
+ * Return:
+ *      SUCCESS
+ *      FAILED
+ * Note:
+ *      switch supports 4 queue per egress port, scheduling algorithm could be WRR(Weight Round Robin) or 
+ *      SP(Strict Priority). Only high queue Q3 and Q2 could be set as strict priority queue. There two set of 
+ *      scheduling parameter in whole system(RTL8306_QOS_SET0/RTL8306_QOS_SET1), each egress port select
+ *      one of them. The parameter defined by rtl8306e_qosSchPara_t, q0_wt and q1_wt should between 1~127,
+ *      that means Q0 and Q1 WRR weight, q2_wt and  q3_wt could be 0~127, 0 means strict priority. q2_n64Kbps 
+ *      and q3_n64Kbps means Q2/Q3 queue bandwidth control, unit is 64Kbps.
+ */
+extern int32 rtl8306e_qos_schedulingPara_set(uint32 set, rtl8306e_qosSchPara_t sch_para);
+
+/* Function Name:
+ *      rtl8306e_qos_schedulingPara_get
+ * Description:
+ *      Set qos scheduling parameter
+ * Input:
+ *      set           -  RTL8306_QOS_SET0 or RTL8306_QOS_SET1
+ * Output:
+ *      pSch_para  - the pointer of schedule parameter
+ * Return:
+ *      SUCCESS
+ *      FAILED
+ * Note:
+ *      switch supports 4 queue per egress port, scheduling algorithm could be WRR(Weight Round Robin) or 
+ *      SP(Strict Priority). Only high queue Q3 and Q3 could be set as strict priority queue. There two set of 
+ *      scheduling parameter in whole system(RTL8306_QOS_SET0/RTL8306_QOS_SET1), each egress port select
+ *      one of them. The parameter defined by rtl8306e_qosSchPara_t, q0_wt and q1_wt should between 1~127,
+ *      that means Q0 and Q1 WRR weight, q2_wt and  q3_wt could be 0~127, 0 means strict priority. q2_n64Kbps 
+ *      and q3_n64Kbps means Q2/Q3 queue bandwidth control, unit is 64Kbps.
+ */
+extern int32 rtl8306e_qos_schedulingPara_get(uint32 set, rtl8306e_qosSchPara_t *pSch_para);
+
+/* Function Name:
+ *      rtl8306e_qos_portSchedulingMode_set
+ * Description:
+ *      Select port schedule algorithm  from two sets.
+ * Input:
+ *      port    -   port number (0 ~ 5)
+ *      set     -   RTL8306_QOS_SET0 or RTL8306_QOS_SET1
+ *      lbmsk  -   Queue mask for enable queue leaky buckt
+ * Output:
+ *      none
+ * Return:
+ *      SUCCESS
+ *      FAILED
+ * Note:
+ *      There are two sets configuration for schedule mode including strict priority 
+ *      enable/disable, queue weight and queue leaky bucket, every port could select
+ *      one of them. Queue leaky bucket of each port could be enable separately, so 
+ *      you can set queue mask to enable/disable them, because only queue 3 and queue 2
+ *      have leaky bucket, only bit 3 and bit 2 of quemask have effect, bit 3 represents
+ *      queue 3 and set 1 to enable it.
+ */
+extern int32 rtl8306e_qos_portSchedulingMode_set(uint32 port, uint32 set, uint32 lbmsk);
+
+/* Function Name:
+ *      rtl8306e_qos_portSchedulingMode_get
+ * Description:
+ *      Get which set of schedule algorithm  for the specified port 
+ * Input:
+ *      port    -   port number (0 ~ 5)
+ *      set     -   RTL8306_QOS_SET0 or RTL8306_QOS_SET1
+ *      lbmsk  -   Queue mask for enable queue leaky buckt
+ * Output:
+ *      none
+ * Return:
+ *      SUCCESS
+ *      FAILED
+ * Note:
+ *      There are two sets configuration for schedule mode including strict priority 
+ *      enable/disable, queue weight and queue leaky bucket, every port could select
+ *      one of them. Queue leaky bucket of each port could be enable separately, so 
+ *      you can set queue mask to enable/disable them, because only queue 3 and queue 2
+ *      have leaky bucket, only bit 3 and bit 2 of quemask have effect, bit 3 represents
+ *      queue 3 and set 1 to enable it.
+ */
+extern int32 rtl8306e_qos_portSchedulingMode_get(uint32 port, uint32 *pSet, uint32 *pLbmsk);
+extern int32 rtl8306e_qos_queFlcThr_set(uint32 queue, uint32 type, uint32 onoff, uint32 set, uint32 value);
+extern int32 rtl8306e_qos_queFlcThr_get(uint32 queue, uint32 type, uint32 onoff, uint32 set, uint32* pValue);
+extern int32 rtl8306e_qos_portFlcThr_set(uint32 port, uint32 onthr, uint32 offthr, uint32 direction );
+extern int32 rtl8306e_qos_portFlcThr_get(uint32 port, uint32 *pOnthr, uint32 *pOffthr, uint32 direction);
+extern int32 rtl8306e_qos_queFlcEnable_set( uint32 port, uint32 queue, uint32 enabled);
+extern int32 rtl8306e_qos_queFlcEnable_get(uint32 port, uint32 queue, uint32 *pEnabled);
+
+
+/*
+  *  ACL  function
+  */
+
+/* Function Name:
+ *      rtl8306e_acl_entry_set
+ * Description:
+ *      Set Asic ACL table
+ * Input:
+ *      entryadd   - Acl entry address (0~15)
+ *      phyport    -  Acl physical port
+ *      action      -  Acl action 
+ *      protocol   -  Acl protocol
+ *      data        -  ether type value or TCP/UDP port
+ *      priority     -  Acl priority
+ * Output:
+ *      none
+ * Return:
+ *      SUCCESS
+ *      FAILED
+ * Note:
+ *      phyport could be 
+ *            0~5:       port number, 
+ *            RTL8306_ACL_INVALID: invalid entry,
+ *            RTL8306_ACL_ANYPORT: any port.
+ *      Acl action could be
+ *          RTL8306_ACT_DROP,
+ *          RTL8306_ACT_PERMIT, 
+ *          RTL8306_ACT_TRAPCPU, 
+ *          RTL8306_ACT_MIRROR
+ *      Acl protocol could be
+ *          RTL8306_ACL_ETHER(ether type), 
+ *          RTL8306_ACL_TCP(TCP), 
+ *          RTL8306_ACL_UDP(UDP),
+ *          RTL8306_ACL_TCPUDP(TCP or UDP)
+ *
+ *      Acl priority:
+ *          RTL8306_PRIO0~RTL8306_PRIO3
+ *       
+ */
+extern int32 rtl8306e_acl_entry_set(uint32 entryadd, uint32 phyport, uint32 action, uint32 protocol, uint32 data, uint32 priority) ;
+
+/* Function Name:
+ *      rtl8306e_acl_entry_get
+ * Description:
+ *      Get Asic ACL entry
+ * Input:
+ *      entryadd   - Acl entry address (0~15)
+ * Output:
+ *      pPhyport    -  Acl physical port 
+ *      pAction      -  Acl action 
+ *      pProtocol   -  Acl protocol
+ *      pData        -  ether type value or TCP/UDP port
+ *      pPriority     -  Acl priority
+ * Return:
+ *      SUCCESS
+ *      FAILED
+ * Note:
+ *      phyport could be 
+ *            0~5:       port number, 
+ *            RTL8306_ACL_INVALID: invalid entry,
+ *            RTL8306_ACL_ANYPORT: any port.
+ *      Acl action could be
+ *          RTL8306_ACT_DROP,
+ *          RTL8306_ACT_PERMIT, 
+ *          RTL8306_ACT_TRAPCPU, 
+ *          RTL8306_ACT_MIRROR
+ *      Acl protocol could be
+ *          RTL8306_ACL_ETHER(ether type), 
+ *          RTL8306_ACL_TCP(TCP), 
+ *          RTL8306_ACL_UDP(UDP),
+ *          RTL8306_ACL_TCPUDP(TCP or UDP)
+ *
+ *      Acl priority:
+ *          RTL8306_PRIO0~RTL8306_PRIO3
+ *       
+ */
+extern int32 rtl8306e_acl_entry_get(uint32 entryadd, uint32 *pPhyport, uint32 *pAction, uint32 *pProtocol, uint32  *pData, uint32 *pPriority);
+
+/*
+  *  Mib  function
+  */
+
+/* Function Name:
+ *      rtl8306e_mib_get
+ * Description:
+ *      enable/disable Qos priority source for  ingress port
+ * Input:
+ *      port         -  port number (0 ~ 5)
+ *      counter    -  Specify counter type  
+ * Output:
+ *      pEnabled -  the pointer of priority source status  
+ * Return:
+ *      SUCCESS
+ *      FAILED
+ * Note:
+ *      There are five MIB counter for each port, they are:
+ *      RTL8306_MIB_CNT1 - TX count
+ *      RTL8306_MIB_CNT2 - RX count
+ *      RTL8306_MIB_CNT3 - RX Drop Count<nl>
+ *      RTL8306_MIB_CNT4 - RX CRC error Count
+ *      RTL8306_MIB_CNT5 - RX Fragment Count<nl>
+ */
+extern int32 rtl8306e_mib_get(uint32 port, uint32 counter, uint32 *pValue); 
+
+/* Function Name:
+ *      rtl8306e_mibUnit_set
+ * Description:
+ *      Set RX/Tx Mib counting unit: byte or packet
+ * Input:
+ *      port         -  port number (0 ~ 5)
+ *      counter    -  Specify counter type  
+ *      uint         -  Specify counting unit
+ * Output:
+ *      none  
+ * Return:
+ *      SUCCESS
+ *      FAILED
+ * Note:
+ *      1.There are five MIB counter for each port, they are:
+ *      RTL8306_MIB_CNT1 - TX count
+ *      RTL8306_MIB_CNT2 - RX count
+ *      RTL8306_MIB_CNT3 - RX Drop Count<nl>
+ *      RTL8306_MIB_CNT4 - RX CRC error Count
+ *      RTL8306_MIB_CNT5 - RX Fragment Count<nl>
+ *      2.Only RTL8306_MIB_CNT1 and RTL8306_MIB_CNT2 could set counting unit  
+ *      RTL8306_MIB_PKT or RTL8306_MIB_BYTE, default is RTL8306_MIB_PKT.
+ *      the other counters' counting uint is RTL8306_MIB_PKT
+ */
+extern int32 rtl8306e_mibUnit_set(uint32 port, uint32 counter, uint32 unit);
+
+/* Function Name:
+ *      rtl8306e_mibUnit_get
+ * Description:
+ *      Get Rx/Tx Mib counting unit
+ * Input:
+ *      port         -  port number (0 ~ 5)
+ *      counter    -  Specify counter type  
+ * Output:
+ *      pUnit         -  the pointer of counting unit
+ * Return:
+ *      SUCCESS
+ *      FAILED
+ * Note:
+ *      1.There are five MIB counter for each port, they are:
+ *      RTL8306_MIB_CNT1 - TX count
+ *      RTL8306_MIB_CNT2 - RX count
+ *      RTL8306_MIB_CNT3 - RX Drop Count<nl>
+ *      RTL8306_MIB_CNT4 - RX CRC error Count
+ *      RTL8306_MIB_CNT5 - RX Fragment Count<nl>
+ *      2.Only RTL8306_MIB_CNT1 and RTL8306_MIB_CNT2 could set counting unit  
+ *      RTL8306_MIB_PKT or RTL8306_MIB_BYTE, default is RTL8306_MIB_PKT.
+ *      the other counters' counting uint is RTL8306_MIB_PKT
+ */
+extern int32 rtl8306e_mibUnit_get(uint32 port, uint32 counter, uint32 *pUnit);
+
+/* Function Name:
+ *      rtl8306e_mib_reset
+ * Description:
+ *      reset MIB counter
+ * Input:
+ *      port         -  port number (0 ~ 5)
+ * Output:
+ *      none
+ * Return:
+ *      SUCCESS
+ *      FAILED
+ * Note:
+ */
+extern int32 rtl8306e_mib_reset(uint32 port);
+
+/*
+  *  mirror  function
+  */
+
+/* Function Name:
+ *      rtl8306e_mirror_portBased_set
+ * Description:
+ *      Set asic Mirror port
+ * Input:
+ *      mirport         -  Specify mirror port 
+ *      rxmbr           -  Specify Rx mirror port mask
+ *      txmbr           -  Specify Tx mirror port mask
+ * Output:
+ *      none
+ * Return:
+ *      SUCCESS
+ *      FAILED
+ * Note:
+ *      mirport could be 0 ~ 5, represent physical port number, 
+ *      7 means that no port has mirror ability. rxmbr and txmbr
+ *      is 6 bit value, each bit corresponds one port. ingress packet
+ *      of port in rxmbr will be mirrored to mirport, egress packet 
+ *      of port in txmbr will be mirrored to mirport.
+ */
+extern int32 rtl8306e_mirror_portBased_set(uint32 mirport, uint32 rxmbr, uint32 txmbr) ;
+
+/* Function Name:
+ *      rtl8306e_mirror_portBased_get
+ * Description:
+ *      Get asic Mirror port
+ * Input:
+ *      none 
+ * Output:
+ *      pMirport     -  the pointer of mirror port
+ *      pRxmbr       -  the pointer of  Rx mirror port mask
+ *      pTxmbr       -  the pointer of Tx mirror port mask 
+ * Return:
+ *      SUCCESS
+ *      FAILED
+ * Note:
+ *      mirport could be 0 ~ 5, represent physical port number, 
+ *      7 means that no port has mirror ability. rxmbr and txmbr
+ *      is 6 bit value, each bit corresponds one port. ingress packet
+ *      of port in rxmbr will be mirrored to mirport, egress packet 
+ *      of port in txmbr will be mirrored to mirport.
+ */
+
+extern int32 rtl8306e_mirror_portBased_get(uint32 *pMirport, uint32 *pRxmbr, uint32* pTxmbr);
+
+/*
+  *  L2 table  function
+  */
+
+/* Function Name:
+ *      rtl8306e_l2_MacToIdx_get
+ * Description:
+ *      get L2 table hash value from mac address
+ * Input:
+ *      macAddr        -  mac address
+ * Output:
+ *      pIndex           -  mac address table index   
+ * Return:
+ *      SUCCESS
+ *      FAILED
+ * Note:
+ *      when a mac address is learned into mac address table, 
+ *      9 bit index value is got from the mac address by hashing 
+ *      algorithm, each index corresponds to 4 entry, it means
+ *      the table could save 4 mac addresses at the same time
+ *      whose index value is equal, so switch mac address table 
+ *      has 2048 entry. the API could get hash index from 
+ *      a specified mac address.
+ */
+extern int32 rtl8306e_l2_MacToIdx_get(uint8 *macAddr, uint32* pIndex);
+
+/* Function Name:
+ *      rtl8306e_l2_unicastEntry_set
+ * Description:
+ *      write an unicast mac address into L2 table
+ * Input:
+ *      macAddress        -  Specify the unicast Mac address(6 bytes) to be written into LUT
+ *      entry                 -  Specify the 4-way entry to be written (0~3)
+ *      age                   -  Specify age time
+ *      isStatic              -  TRUE(static entry), FALSE(dynamic entry)
+ *      isAuth                -  Whether the mac address is authorized by IEEE 802.1x
+ *      port                  -   Specify the port number to be forwarded to  
+ * Output:
+ *      none
+ * Return:
+ *      SUCCESS
+ *      FAILED
+ * Note:
+ *      Age time has 4 value :
+ *          RTL8306_LUT_AGEOUT, 
+ *          RTL8306_LUT_AGE100(100s)
+ *          RTL8306_LUT_AGE200(200s)
+ *          RTL8306_LUT_AGE300(300s)
+ */ 
+extern int32 rtl8306e_l2_unicastEntry_set(uint8 *macAddress, uint32 entry, uint32 age, uint32 isStatic, uint32 isAuth, uint32 port); 
+
+/* Function Name:
+ *      rtl8306e_l2_unicastEntry_get
+ * Description:
+ *      read an unicast mac address into L2 table
+ * Input:
+ *      entry               -  Specify the entry address to be read (0 ~ 2047), not four-way entry
+ * Output:
+ *      macAddress      -  the mac to be saved in the entry  
+ *      pAge               -  the pointer of the age time
+ *      pIsStatic         -   the pointer of static or dynamic entry
+ *      pIsAuth           -   the pointer of IEEE 802.1x authorized status
+ *      pPort              -   the pointer of the port the mac belongs to   
+ * Return:
+ *      SUCCESS
+ *      FAILED
+ * Note:
+ *      Age time has 4 value :
+ *          RTL8306_LUT_AGEOUT
+ *          RTL8306_LUT_AGE100(100s)
+ *          RTL8306_LUT_AGE200(200s)
+ *          RTL8306_LUT_AGE300(300s)
+ */ 
+extern int32 rtl8306e_l2_unicastEntry_get(uint8 *macAddress, uint32 entryAddr, uint32 *pAge, uint32 *pIsStatic, uint32 *pIsAuth, uint32 *pPort) ;
+
+/* Function Name:
+ *      rtl8306e_l2_multicastEntry_set
+ * Description:
+ *      write an multicast mac address into L2 table
+ * Input:
+ *      macAddress      -  the mac to be saved in the entry  
+ *      entry               -  Specify the 4-way entry to be written (0~3)
+ *      isAuth              -  IEEE 802.1x authorized status
+ *      portMask          -  switch received thepacket with the specified macAddress, 
+ *                                and forward it to the member port of portMask
+ * Output:
+ *      none
+ * Return:
+ *      SUCCESS
+ *      FAILED
+ * Note:
+ *      get 9-bit as index value of lookup table by hashing the mac address , for each index value, 
+ *      there are 4-entry to save hash collision mac address, thus there are 2048 entries all together.
+ *      the entry could save both unicast multicast mac address.  multicast entry has no age time and
+ *      static bit, which has been set by software, unicast entry could be both auto learned and set by 
+ *      software. you had better set isAuth TRUE for general application because  IEEE 802.1x is usually
+ *      for unicast packet.portMask is 6-bit value, each bit represents one port, bit 0 corresponds to port 0
+ *      and bit 5 corresponds port 5.
+ */ 
+
+extern int32 rtl8306e_l2_multicastEntry_set(uint8 *macAddress, uint32 entry, uint32 isAuth, uint32 portMask);
+
+/* Function Name:
+ *      rtl8306_getAsicLUTMulticastEntry
+ * Description:
+ *      Get LUT multicast entry
+ * Input:
+ *      entryAddr         -  Specify the LUT entry address(0~2047)
+
+ * Output:
+ *      macAddress      -  The read out multicast Mac address  
+ *      pIsAuth            -  the pointer of IEEE 802.1x authorized status
+ *      portMask          -  port mask 
+ * Return:
+ *      SUCCESS
+ *      FAILED
+ * Note:
+ *      Get multicast entry
+ */ 
+extern int32 rtl8306e_l2_multicastEntry_get(uint8 *macAddress, uint32 entryAddr, uint32 *pIsAuth, uint32 *pPortMask);
+
+/* Function Name:
+ *      rtl8306e_l2_unicastMac_add
+ * Description:
+ *     Add an unicast mac address, software will detect empty entry
+ * Input:
+ *      macAddress      -  the mac to be saved in the entry  
+ *      age                 -  Specify age time
+ *      isStatic            -  TRUE(static entry), FALSE(dynamic entry)
+ *      isAuth              -  IEEE 802.1x authorized status
+ *      port                 -  the port which the mac address belongs to  
+ * Output:
+ *      pEntryaddr        -   the entry address (0 ~2047) which the unicast mac address is written into
+ * Return:
+ *      SUCCESS
+ *      FAILED
+ * Note:
+ *      Age time has 4 value :RTL8306_LUT_AGEOUT, RTL8306_LUT_AGE100(100s), 
+ *      RTL8306_LUT_AGE200(200s), RTL8306_LUT_AGE300(300s)
+ *      The lut has a 4-way entry of an index. If the macAddress has existed in the lut, it will update the entry,
+ *      otherwise the function will find an empty entry to put it.
+ *      When the index is full, it will find a dynamic & unauth unicast macAddress entry to replace with it. 
+ *      If the mac address has been written into LUT, function return value is SUCCESS,  *pEntryaddr is recorded the 
+ *      entry address of the Mac address stored.
+ *      If all the four entries can not be replaced, it will return a  RTL8306_LUT_FULL error, you can delete one of them 
+ *      and rewrite the unicast address.  
+ */ 
+extern int32 rtl8306e_l2_unicastMac_add(uint8 *macAddress, uint32 age, uint32 isStatic, uint32 isAuth, uint32 port, uint32 *pEntryaddr);
+
+/* Function Name:
+ *      rtl8306e_l2_multicastMac_add
+ * Description:
+ *     Add an multicast mac address, software will detect empty entry
+ * Input:
+ *      macAddress      -  the mac to be saved in the entry  
+ *      isAuth              -  IEEE 802.1x authorized status
+ *      portMask          -  switch received thepacket with the specified macAddress, 
+ *                                and forward it to the member port of portMask
+ * Output:
+ *      pEntryaddr        -   the entry address (0 ~2047) which the multicast mac address is written into
+ * Return:
+ *      SUCCESS
+ *      FAILED
+ * Note:
+ *      add an multicast entry, it need not specify the 4-way like function rtl8306e_l2_multicastEntry_set,
+ *      if the mac address has written into LUT, function return value is SUCCESS,  *pEntryaddr is recorded the 
+ *      entry address of the Mac address stored, if  4-way entries are all written by cpu, this mac address could 
+ *      not written into LUT and the function return value is  RTL8306_LUT_FULL, but if the Mac address has exist, 
+ *      the port mask will be updated. When function return value is RTL8306_LUT_FULL, you can delete one of them 
+ *      and rewrite the multicast address. 
+ */ 
+extern int32 rtl8306e_l2_multicastMac_add(uint8 *macAddr,uint32 isAuth, uint32 portMask, uint32 *pEntryaddr);
+
+/* Function Name:
+ *      rtl8306e_l2_mac_get
+ * Description:
+ *      Get an mac address information
+ * Input:
+ *      macAddress         -   the mac to be find in LUT  
+ * Output:
+ *      pIsStatic             -   the pointer of static or dynamic entry, for unicast mac address
+ *      pIsAuth               -   the pointer of IEEE 802.1x authorized status
+ *      pPortInfo             -   for unicast mac, it is the pointer of the port the mac belongs to;
+ *                                    for multicast mac, it is the pointer of portmask the mac forwarded to;
+ *      pEntryaddr           -   the entry address (0 ~2047) which the mac address is written into
+ * Return:
+ *      SUCCESS
+ *      FAILED
+ *      RTL8306_LUT_NOTEXIST
+ * Note:
+ *      use this API to get a mac address information in LUT.
+ */ 
+extern int32 rtl8306e_l2_mac_get(uint8 *macAddr, uint32 *pIsStatic, uint32 *pIsAuth, uint32 *pPortInfo, uint32 *pEntryaddr); 
+
+/* Function Name:
+ *      rtl8306e_l2_mac_del
+ * Description:
+ *     Delete the specified Mac address, could be both unicast and multicast 
+ * Input:
+ *      macAddress      -  the Mac address(unicast or multicast) to be delete  
+ *                                and forward it to the member port of portMask
+ * Output:
+ *      pEntryaddr        -  entry address from which the Mac address is deleted
+ * Return:
+ *      SUCCESS
+ *      FAILED
+ * Note:
+ *      Use this function to delete a Mac address, it does not require to specify the 
+ *      entry address, if the Mac has existed in the LUT, it will be deleted and function
+ *      return value is SUCCESS, *pEntryaddr is recorded the entry address of the Mac 
+ *      address stored. if the Mac does not existed in the LUT, function return value is
+ *      RTL8306_LUT_NOTEXIST, and *pEntryaddr equals 10000.
+ */ 
+
+extern int32 rtl8306e_l2_mac_del(uint8 *macAddr, uint32 *pEntryaddr);
+extern int32 rtl8306e_l2_portMacLimit_set(uint32 port, uint32 enabled, uint32 macCnt) ;
+extern int32 rtl8306e_l2_portMacLimit_get(uint32 port, uint32 *pEnabled, uint32 *pMacCnt);
+extern int32 rtl8306e_l2_systemMacLimit_set(uint32 enabled, uint32 macCnt, uint32 mergMask);
+extern int32 rtl8306e_l2_systemMacLimit_get(uint32 *pEnabled, uint32 *pMacCnt, uint32 *pMergMask); 
+extern int32 rtl8306e_l2_macLimitAction_set(uint32 action); 
+extern int32 rtl8306e_l2_macLimitAction_get(uint32 *pAction);
+
+#ifdef RTL8306_LUT_CACHE
+/* Function Name:
+ *      rtl8306e_l2_unicastEntry_get
+ * Description:
+ *      Get LUT unicast entry from software
+ * Input:
+ *      entryAddr         -  Specify the entry address to be read (0 ~ 2047), not four-way entry
+ * Output:
+ *      macAddress      -  the mac to be saved in the entry  
+ *      pAge               -  the pointer of the age time
+ *      pIsStatic         -   the pointer of static or dynamic entry
+ *      pIsAuth           -   the pointer of IEEE 802.1x authorized status
+ *      pPort              -   the pointer of the port the mac belongs to   
+ * Return:
+ *      SUCCESS
+ *      FAILED
+ * Note:
+ *      Age time has 4 value :
+ *          RTL8306_LUT_AGEOUT
+ *          RTL8306_LUT_AGE100(100s)
+ *          RTL8306_LUT_AGE200(200s)
+ *          RTL8306_LUT_AGE300(300s)
+ */ 
+extern int32 rtl8306e_fastGetAsicLUTUnicastEntry(uint8 *macAddress, uint32 entryAddr, uint32 *age, uint32 *isStatic, uint32 *isAuth, uint32 *port);
+
+/* Function Name:
+ *      rtl8306e_fastGetAsicLUTMulticastEntry
+ * Description:
+ *      Get LUT multicast entry from software
+ * Input:
+ *      entryAddr         -  Specify the entry address to be read (0 ~ 2047), not four-way entry
+ * Output:
+ *      macAddress      -  the mac to be saved in the entry  
+ *      pIsAuth           -   the pointer of IEEE 802.1x authorized status
+ *      pPort              -   the pointer of the port the mac belongs to   
+ * Return:
+ *      SUCCESS
+ *      FAILED
+ * Note:
+ *      portMask is 6-bit value, each bit represents one port, bit 0 corresponds to port 0 
+ *      and bit 5 corresponds port 5.    
+ */ 
+extern int32 rtl8306e_fastGetAsicLUTMulticastEntry(uint8 *macAddress, uint32 entryAddr, uint32 *isAuth, uint32 *portMask);
+
+#endif
+/*
+  *  Spanning Tree  function
+  */
+
+/* Function Name:
+ *      rtl8306e_stp_set
+ * Description:
+ *      Set IEEE 802.1d port state
+ * Input:
+ *      port   -  Specify port number (0 ~ 5)
+ *      state -   Specify port state
+ * Output:
+ *      none
+ * Return:
+ *      SUCCESS
+ *      FAILED
+ * Note:
+ *     There are 4 port state:
+ *         RTL8306_SPAN_DISABLE   - Disable state
+ *         RTL8306_SPAN_BLOCK      - Blocking state
+ *         RTL8306_SPAN_LEARN      - Learning state
+ *         RTL8306_SPAN_FORWARD - Forwarding state
+ */ 
+extern int32 rtl8306e_stp_set(uint32 port, uint32 state) ;
+
+/* Function Name:
+ *      rtl8306e_stp_get
+ * Description:
+ *      Get IEEE 802.1d port state
+ * Input:
+ *      port    -  Specify port number (0 ~ 5)
+ * Output:
+ *      pState -  get port state
+ * Return:
+ *      SUCCESS
+ *      FAILED
+ * Note:
+ *     There are 4 port state:
+ *         RTL8306_SPAN_DISABLE   - Disable state
+ *         RTL8306_SPAN_BLOCK      - Blocking state
+ *         RTL8306_SPAN_LEARN      - Learning state
+ *         RTL8306_SPAN_FORWARD - Forwarding state
+ */ 
+extern int32 rtl8306e_stp_get(uint32 port, uint32 *pState) ;
+
+/*
+  *  802.1x  function
+  */
+
+/* Function Name:
+ *      rtl8306e_dot1x_portBased_set
+ * Description:
+ *      Set IEEE802.1x port-based access control
+ * Input:
+ *      port         -  Specify port number (0 ~ 5)
+ *      enabled    -   enable port-based access control
+ *      isAuth      -   Authorized or unauthorized state 
+ *      direction   -    set IEEE802.1x port-based control direction
+ * Output:
+ *      none
+ * Return:
+ *      SUCCESS
+ *      FAILED
+ * Note:
+ *     There are two IEEE802.1x port state:
+ *         RTL8306_PORT_AUTH      - authorized
+ *         RTL8306_PORT_UNAUTH  - unauthorized
+ *
+ *     There are also two 802.1x port-based control direction:
+ *         RTL8306_PORT_BOTHDIR - if port-base access control is enabled, 
+ *                                              forbid forwarding this port's traffic to unauthorized port
+ *         RTL8306_PORT_INDIR     - if port-base access control is enabled, permit forwarding this
+ *                                              port's traffic to unauthorized port
+ */ 
+extern int32 rtl8306e_dot1x_portBased_set(uint32 port, uint32 enabled, uint32 isAuth, uint32 direction);
+
+/* Function Name:
+ *      rtl8306e_dot1x_portBased_set
+ * Description:
+ *      Set IEEE802.1x port-based access control
+ * Input:
+ *      port         -  Specify port number (0 ~ 5)
+ * Output:
+ *      pEnabled    - the pointer of port-based access control status
+ *      pIsAuth      - the pointer of authorized or unauthorized state 
+ *      pDirection   - the pointer of IEEE802.1x port-based control direction
+ * Return:
+ *      SUCCESS
+ *      FAILED
+ * Note:
+ *     There are two IEEE802.1x port state:
+ *         RTL8306_PORT_AUTH      - authorized
+ *         RTL8306_PORT_UNAUTH  - unauthorized
+ *
+ *     There are also two 802.1x port-based control direction:
+ *         RTL8306_PORT_BOTHDIR - if port-base access control is enabled, 
+ *                                              forbid forwarding this port's traffic to unauthorized port
+ *         RTL8306_PORT_INDIR     - if port-base access control is enabled, permit forwarding this
+ *                                              port's traffic to unauthorized port
+ */ 
+extern int32 rtl8306e_dot1x_portBased_get(uint32 port, uint32 *pEnabled, uint32 *pIsAuth, uint32 *pDirection) ;
+
+/* Function Name:
+ *      rtl8306e_dot1x_macBased_set
+ * Description:
+ *      Set IEEE802.1x port-based access control
+ * Input:
+ *      port         -  Specify port number (0 ~ 5)
+ * Output:
+ *      enabled    - Enable the port Mac-based access control ability
+ *      direction   -  IEEE802.1x mac-based access control direction
+ * Return:
+ *      SUCCESS
+ *      FAILED
+ * Note:
+ *      the mac address authentication status is saved in L2 table entry,
+ *      it should be set by software.
+ *      there are also two mac-based control directions which are not per 
+ *      port but global configurtion:
+ *      RTL8306_MAC_BOTHDIR - if Mac-based access control is enabled, packet with 
+ *      unauthorized DA will be dropped.
+ *      RTL8306_MAC_INDIR   - if Mac-based access control is enabled, packet with 
+ *      unauthorized DA will pass mac-based access control igress rule.
+ */ 
+
+extern int32 rtl8306e_dot1x_macBased_set(uint32 port, uint32 enabled, uint32 direction);
+
+/* Function Name:
+ *      rtl8306e_dot1x_macBased_set
+ * Description:
+ *      Set IEEE802.1x port-based access control
+ * Input:
+ *      port         -  Specify port number (0 ~ 5)
+ * Output:
+ *      enabled    - Enable the port Mac-based access control ability
+ *      direction   -  IEEE802.1x mac-based access control direction
+ * Return:
+ *      SUCCESS
+ *      FAILED
+ * Note:
+ *      the mac address authentication status is saved in L2 table entry,
+ *      it should be set by software.
+ *      there are also two mac-based control directions which are not per 
+ *      port but global configurtion:
+ *      RTL8306_MAC_BOTHDIR - if Mac-based access control is enabled, packet with 
+ *      unauthorized DA will be dropped.
+ *      RTL8306_MAC_INDIR   - if Mac-based access control is enabled, packet with 
+ *      unauthorized DA will pass mac-based access control igress rule.
+ */ 
+extern int32 rtl8306e_dot1x_macBased_get(uint32 port, uint32 *pEnabled, uint32 *pDirection); 
+
+/* Function Name:
+ *      rtl8306e_trap_igmpCtrlPktAction_set
+ * Description:
+ *      Set IGMP/MLD trap function
+ * Input:
+ *      type         -  Specify IGMP/MLD or PPPOE
+ *      action       -  Action could be normal forward or trap
+ * Output:
+ *      none
+ * Return:
+ *      SUCCESS
+ *      FAILED
+ * Note:
+ *     type could be:
+ *          RTL8306_IGMP   - igmp packet without pppoe header 
+ *          RTL8306_MLD    - mld packet  without pppoe header
+ *          RTL8306_PPPOE_IGMPMLD - pppoe packet if enable trap RTL8306_IGMP 
+ *                                   or RTL8306_MLD whether pppoe packet 
+ *                                   should be trapped. In some application,
+ *                                   igmp and mld message is encapsulated in pppoed
+ *                                   packet.
+ *         
+ *      action could be:
+ *          RTL8306_ACT_PERMIT    - normal forward
+ *          RTL8306_ACT_TRAPCPU  - trap to cpu
+ */ 
+extern int32 rtl8306e_trap_igmpCtrlPktAction_set(uint32 type, uint32 action);
+
+/* Function Name:
+ *      rtl8306e_trap_igmpCtrlPktAction_get
+ * Description:
+ *      Get IGMP/MLD trap setting
+ * Input:
+ *      type         -  Specify IGMP/MLD or PPPOE
+ * Output:
+ *      pAction     -  the pointer of action could be normal forward or trap
+ * Return:
+ *      SUCCESS
+ *      FAILED
+ * Note:
+ *     type could be:
+ *          RTL8306_IGMP   - igmp packet without pppoe header 
+ *          RTL8306_MLD    - mld packet  without pppoe header
+ *          RTL8306_PPPOE_IGMPMLD - pppoe packet if enable trap RTL8306_IGMP 
+ *                                   or RTL8306_MLD whether pppoe packet 
+ *                                   should be trapped. In some application,
+ *                                   igmp and mld message is encapsulated in pppoed
+ *                                   packet.
+ *      action could be:
+ *          RTL8306_ACT_PERMIT    - normal forward
+ *          RTL8306_ACT_TRAPCPU  - trap to cpu
+ */ 
+extern int32 rtl8306e_trap_igmpCtrlPktAction_get(uint32 type, uint32 *pAction);
+
+/* Function Name:
+ *      rtl8306e_trap_unknownIPMcastPktAction_set
+ * Description:
+ *      Set unknown ip multicast drop or normal forward
+ * Input:
+ *      type         -  Specify ipv4 or ipv6 unkown multicast
+ *      action       -  drop or normal forward
+ * Output:
+ *      none
+ * Return:
+ *      SUCCESS
+ *      FAILED
+ * Note:
+ *      type coulde be:
+ *          RTL8306_IPV4_MULTICAST - ipv4 unknown multicast
+ *          RTL8306_IPV6_MULTICAST - ipv6 unknown multicast
+ *      action could be:
+ *          RTL8306_ACT_DROP      - trap to cpu 
+ *          RTL8306_ACT_PERMIT   - normal forward
+ */  
+extern int32 rtl8306e_trap_unknownIPMcastPktAction_set(uint32 type, uint32 action);
+
+/* Function Name:
+ *      rtl8306e_trap_unknownIPMcastPktAction_get
+ * Description:
+ *      Get unknown ip multicast drop or normal forward
+ * Input:
+ *      type         -  Specify ipv4 or ipv6 unkown multicast
+ * Output:
+ *      pAction     -  the pointer of drop or normal forward
+ * Return:
+ *      SUCCESS
+ *      FAILED
+ * Note:
+ *      type coulde be:
+ *          RTL8306_IPV4_MULTICAST - ipv4 unknown multicast
+ *          RTL8306_IPV6_MULTICAST - ipv6 unknown multicast
+ *      action could be:
+ *          RTL8306_ACT_DROP      - trap to cpu 
+ *          RTL8306_ACT_PERMIT   - normal forward
+ */ 
+extern int32 rtl8306e_trap_unknownIPMcastPktAction_get(uint32 type, uint32 *pAction);
+
+/* Function Name:
+ *      rtl8306e_trap_abnormalPktAction_set
+ * Description:
+ *      set abnormal packet action 
+ * Input:
+ *      type         -  abnormal packet type
+ *      action       -  drop or trap to cpu
+ * Output:
+ *      none
+ * Return:
+ *      SUCCESS
+ *      FAILED
+ * Note:
+ *      type coulde be:
+ *          RTL8306_UNMATCHVID   - vlan-tagged packet, vid dismatch vlan table 
+ *          RTL8306_DOT1XUNAUTH - 802.1x authentication fail packet
+ *      action could be:
+ *          RTL8306_ACT_DROP       - drop 
+ *          RTL8306_ACT_TRAPCPU  - trap to cpu
+ */ 
+extern int32 rtl8306e_trap_abnormalPktAction_set(uint32 type,  uint32 action);
+
+/* Function Name:
+ *      rtl8306e_trap_abnormalPktAction_get
+ * Description:
+ *      get abnormal packet action 
+ * Input:
+ *      type         -  abnormal packet type
+ * Output:
+ *      pAction     -  the pointer of action
+ * Return:
+ *      SUCCESS
+ *      FAILED
+ * Note:
+ *      type coulde be:
+ *          RTL8306_UNMATCHVID   - vlan-tagged packet, vid dismatch vlan table 
+ *          RTL8306_DOT1XUNAUTH - 802.1x authentication fail packet
+ *      action could be:
+ *          RTL8306_ACT_DROP       - drop 
+ *          RTL8306_ACT_TRAPCPU  - trap to cpu
+ */ 
+
+extern int32 rtl8306e_trap_abnormalPktAction_get(uint32 type,  uint32 *pAction);
+
+/* Function Name:
+ *      rtl8306e_trap_rmaAction_set
+ * Description:
+ *      Set reserved multicast Mac address forwarding behavior
+ * Input:
+ *      type         -  reserved Mac address type
+ *      action       -  forwarding behavior for the specified mac address
+ * Output:
+ *      none
+ * Return:
+ *      SUCCESS
+ *      FAILED
+ * Note:
+ *      There are eight types  reserved addresses which user can set asic to determine 
+ *       how to forwarding them:
+ *            RTL8306_RESADDRXX   - reserved address 01-80-c2-00-00-xx 
+ *                                              (exclude 00, 01, 02, 03, 10, 20, 21)
+ *            RTL8306_RESADDR21   -  reserved address 01-80-c2-00-00-21(GVRP address)
+ *            RTL8306_RESADDR20   -  reserved address 01-80-c2-00-00-20(GMRP Address)
+ *            RTL8306_RESADDR10   -  reserved address 01-80-c2-00-00-10(All LANs Bridge Management Group Address)
+ *            RTL8306_RESADDR03   -  reserved address 01-80-c2-00-00-03(IEEE Std 802.1X PAE address)
+ *            RTL8306_RESADDR02   -  reserved address 01-80-c2-00-00-02(IEEE Std 802.3ad Slow_Protocols-Multicast address)
+ *            RTL8306_RESADDR00   -  reserved address 01-80-c2-00-00-00(Bridge Group Address)
+ *            RTL8306_RESADDR01   -  reserved address 01-80-c2-00-00-01(Pause frame)
+ *       Actions are :
+ *            TL8306_ACT_DROP      - Drop the packet
+ *            TL8306_ACT_TRAPCPU - Trap the packet to cpu
+ *            RTL8306_ACT_FLOOD   - Flood the packet
+ */ 
+extern int32 rtl8306e_trap_rmaAction_set(uint32 type, uint32 action);
+
+/* Function Name:
+ *      rtl8306e_trap_rmaAction_get
+ * Description:
+ *      Get reserved multicast Mac address forwarding behavior
+ * Input:
+ *      type         -  reserved Mac address type
+ * Output:
+ *      pAction     -  the pointer of action
+ * Return:
+ *      SUCCESS
+ *      FAILED
+ * Note:
+ *      There are eight types  reserved addresses which user can set asic to determine 
+ *       how to forwarding them:
+ *            RTL8306_RESADDRXX   - reserved address 01-80-c2-00-00-xx 
+ *                                              (exclude 00, 01, 02, 03, 10, 20, 21)
+ *            RTL8306_RESADDR21   -  reserved address 01-80-c2-00-00-21(GVRP address)
+ *            RTL8306_RESADDR20   -  reserved address 01-80-c2-00-00-20(GMRP Address)
+ *            RTL8306_RESADDR10   -  reserved address 01-80-c2-00-00-10(All LANs Bridge Management Group Address)
+ *            RTL8306_RESADDR03   -  reserved address 01-80-c2-00-00-03(IEEE Std 802.1X PAE address)
+ *            RTL8306_RESADDR02   -  reserved address 01-80-c2-00-00-02(IEEE Std 802.3ad Slow_Protocols-Multicast address)
+ *            RTL8306_RESADDR00   -  reserved address 01-80-c2-00-00-00(Bridge Group Address)
+ *            RTL8306_RESADDR01   -  reserved address 01-80-c2-00-00-01(Pause frame)
+ *       Actions are :
+ *            TL8306_ACT_DROP      - Drop the packet
+ *            TL8306_ACT_TRAPCPU - Trap the packet to cpu
+ *            RTL8306_ACT_FLOOD   - Flood the packet
+ */ 
+extern int32 rtl8306e_trap_rmaAction_get(uint32 type, uint32 *pAction);
+
+
+/* Function Name:
+ *      rtl8306e_int_control_set
+ * Description:
+ *      Set asic interrupt 
+ * Input:
+ *      enInt        -  Enable interrupt cpu
+ *      intmask     -  interrupt event  mask
+ * Output:
+ *      none
+ * Return:
+ *      SUCCESS
+ *      FAILED
+ * Note:
+ *      enInt is global setting and  intmask  has 12 bits totally, each bit 
+ *      represents one interrupt event, 
+ *      - bit0 ~bit4 represent port 0 ~ port 4 link change, 
+ *      - bit 5 represents port 4 MAC link change
+ *      - bit 6 represents port 5 link change, 
+ *      - bit 7 represents storm filter interrupt,
+ *      - bit 8 represents loop event 
+ *      - bit 9 represents wake up frame interrupt
+ *      - bit 10 represents unmatched SA interrupt
+ *      - bit 11 represents Tx meter interrupt
+ *      write 1 to the bit to enable the interrupt and 0 will disable the interrupt. 
+ *
+ */ 
+extern int32 rtl8306e_int_control_set(uint32 enInt, uint32 intmask);
+
+/* Function Name:
+ *      rtl8306e_int_control_get
+ * Description:
+ *      Get Asic interrupt
+ * Input:
+ *      none 
+ * Output:
+ *      pEnInt       -  the pointer of  interrupt global enable bit
+ *      pIntmask    -  the pointer of interrupt event  mask 
+ * Return:
+ *      SUCCESS
+ *      FAILED
+ * Note:
+ *      enInt is global setting and  intmask  has 12 bits totally, each bit 
+ *      represents one interrupt event, 
+ *      - bit0 ~bit4 represent port 0 ~ port 4 link change, 
+ *      - bit 5 represents port 4 MAC link change
+ *      - bit 6 represents port 5 link change, 
+ *      - bit 7 represents storm filter interrupt,
+ *      - bit 8 represents loop event 
+ *      - bit 9 represents wake up frame interrupt
+ *      - bit 10 represents unmatched SA interrupt
+ *      - bit 11 represents Tx meter interrupt
+ *      write 1 to the bit to enable the interrupt and 0 will disable the interrupt. 
+ *
+ */ 
+extern int32 rtl8306e_int_control_get(uint32 *pEnInt, uint32 *pIntmask);
+
+
+
+/* Function Name:
+ *      rtl8306e_int_control_get
+ * Description:
+ *      Get Asic interrupt
+ * Input:
+ *      none 
+ * Output:
+ *      pEnInt       -  the pointer of  interrupt global enable bit
+ *      pIntmask    -  the pointer of interrupt event  mask 
+ * Return:
+ *      SUCCESS
+ *      FAILED
+ * Note:
+ *      enInt is global setting and  intmask  has 12 bits totally, each bit 
+ *      represents one interrupt event, 
+ *      - bit0 ~bit4 represent port 0 ~ port 4 link change, 
+ *      - bit 5 represents port 4 MAC link change
+ *      - bit 6 represents port 5 link change, 
+ *      - bit 7 represents storm filter interrupt,
+ *      - bit 8 represents loop event 
+ *      - bit 9 represents wake up frame interrupt
+ *      - bit 10 represents unmatched SA interrupt
+ *      - bit 11 represents Tx meter interrupt
+ *      write 1 to the bit to enable the interrupt and 0 will disable the interrupt. 
+ *
+ */ 
+extern int32 rtl8306e_int_status_get(uint32 *pStatusMask);
+
+
+/* Function Name:
+ *      rtl8306e_storm_filterEnable_set
+ * Description:
+ *      Enable Asic storm filter 
+ * Input:
+ *      type      -  specify storm filter type
+ *      enabled  -  TRUE or FALSE
+ * Output:
+ *      none
+ * Return:
+ *      SUCCESS
+ *      FAILED
+ * Note:
+ *      There are 3 kinds of storm filter:
+ *      (1) RTL8306_BROADCASTPKT - storm filter for broadcast packet
+ *      (2) RTL8306_MULTICASTPKT - storm filter for multicast packet
+ *      (3) RTL8306_UDAPKT           - storm filter for unknown DA packet
+ */ 
+extern int32 rtl8306e_storm_filterEnable_set(uint32 type, uint32 enabled);
+
+
+/* Function Name:
+ *      rtl8306e_storm_filterEnable_get
+ * Description:
+ *      Get Asic storm filter enabled or disabled 
+ * Input:
+ *      type        -  specify storm filter type
+ * Output:
+ *      pEnabled  -  the pointer of enabled or disabled
+ * Return:
+ *      SUCCESS
+ *      FAILED
+ * Note:
+ *      There are 3 kinds of storm filter:
+ *      (1) RTL8306_BROADCASTPKT - storm filter for broadcast packet
+ *      (2) RTL8306_MULTICASTPKT - storm filter for multicast packet
+ *      (3) RTL8306_UDAPKT           - storm filter for unknown DA packet
+ */ 
+
+extern int32 rtl8306e_storm_filterEnable_get(uint32 type, uint32 *pEnabled);
+
+
+/* Function Name:
+ *      rtl8306e_storm_filter_set
+ * Description:
+ *      Set storm filter parameter
+ * Input:
+ *      trigNum        -  set packet threshold which trigger storm filter
+ *      filTime         -   set time window 
+ *      enStmInt     -   enable storm filter to interrupt cpu
+ * Output:
+ *      none
+ * Return:
+ *      SUCCESS
+ *      FAILED
+ * Note:
+ *      there are 6 value for trigNum:
+ *      - RTL8306_STM_FILNUM64, 64 pkts
+ *      - RTL8306_STM_FILNUM32, 32 pkts           
+ *      - RTL8306_STM_FILNUM16, 16 pkts           
+ *      - RTL8306_STM_FILNUM8,   8 pkts              
+ *      - RTL8306_STM_FILNUM128, 128 pkts          
+ *      - RTL8306_STM_FILNUM256, 256 pkts     
+ *      there are 4 value for filTime:
+ *      - RTL8306_STM_FIL800MS,  800ms 
+ *      - RTL8306_STM_FIL400MS,  400ms 
+ *      - RTL8306_STM_FIL200MS,  200ms
+ *      - RTL8306_STM_FIL100MS,  100ms
+ */ 
+
+extern int32 rtl8306e_storm_filter_set(uint32 trigNum, uint32 filTime, uint32 enStmInt);
+
+/* Function Name:
+ *      rtl8306e_storm_filter_get
+ * Description:
+ *      Get storm filter parameter
+ * Input:
+ *      none 
+ * Output:
+ *      pTrigNum        -  the pointer of packet threshold which trigger storm filter
+ *      pFilTime          -  the pointer of filter time window 
+ *      pEnStmInt       -  the pointer of enable storm filter to interrupt cpu
+ * Return:
+ *      SUCCESS
+ *      FAILED
+ * Note:
+ *      there are 6 value for trigNum:
+ *      - RTL8306_STM_FILNUM64, 64 pkts
+ *      - RTL8306_STM_FILNUM32, 32 pkts           
+ *      - RTL8306_STM_FILNUM16, 16 pkts           
+ *      - RTL8306_STM_FILNUM8,   8 pkts              
+ *      - RTL8306_STM_FILNUM128, 128 pkts          
+ *      - RTL8306_STM_FILNUM256, 256 pkts     
+ *      there are 4 value for filTime:
+ *      - RTL8306_STM_FIL800MS,  800ms 
+ *      - RTL8306_STM_FIL400MS,  400ms 
+ *      - RTL8306_STM_FIL200MS,  200ms
+ *      - RTL8306_STM_FIL100MS,  100ms
+ */ 
+
+extern int32 rtl8306e_storm_filter_get(uint32 *pTrigNum, uint32 *pFilTime, uint32 *pEnStmInt);
+
+#endif
+
+
diff --git a/ap/os/linux/linux-3.4.x/drivers/net/phy/realtek/rtl8306e/rtl8306e_asictypes.h b/ap/os/linux/linux-3.4.x/drivers/net/phy/realtek/rtl8306e/rtl8306e_asictypes.h
new file mode 100755
index 0000000..1cbacb1
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/net/phy/realtek/rtl8306e/rtl8306e_asictypes.h
@@ -0,0 +1,52 @@
+/*
+* Copyright (C) 2010 Realtek Semiconductor Corp.
+* All Rights Reserved.
+*
+* This program is the proprietary software of Realtek Semiconductor
+* Corporation and/or its licensors, and only be used, duplicated,
+* modified or distributed under the authorized license from Realtek.
+*
+* ANY USE OF THE SOFTWARE OTEHR THAN AS AUTHORIZED UNDER 
+* THIS LICENSE OR COPYRIGHT LAW IS PROHIBITED.
+* 
+* $Revision: 26453 $ 
+* $Date: 2012-01-30 15:52:42 +0800 (星期一, 2012-01-30) $
+*
+* Purpose : asic-level port mapping for RTL8306E/8306M/8304E
+*
+*  Feature :  This file consists of following modules:
+*                1) 
+*
+*/
+#ifndef RTL8306E_ASICTYPES_H
+#define RTL8306E_ASICTYPES_H
+
+#include <rtl8306e_asicdrv.h>
+
+#define CHIP_RTL8306E
+
+#ifdef CHIP_RTL8306E
+#define RTL8306E_PORT0 RTL8306_PORT0
+#define RTL8306E_PORT1 RTL8306_PORT1
+#define RTL8306E_PORT2 RTL8306_PORT2
+#define RTL8306E_PORT3 RTL8306_PORT3
+#define RTL8306E_PORT4 RTL8306_PORT4
+#define RTL8306E_PORT5 RTL8306_PORT5
+#endif
+#ifdef CHIP_RTL8306M
+#define RTL8306M_PORT0 RTL8306_PORT0
+#define RTL8306M_PORT1 RTL8306_PORT1
+#define RTL8306M_PORT2 RTL8306_PORT2
+#define RTL8306M_PORT3 RTL8306_PORT3
+#define RTL8306M_PORT4 RTL8306_PORT4
+#define RTL8306M_PORT5 RTL8306_PORT5
+#endif
+#ifdef CHIP_RTL8304E
+#define RTL8304E_PORT0 RTL8306_PORT0
+#define RTL8304E_PORT1 RTL8306_PORT1
+#define RTL8304E_PORT2 RTL8306_PORT4
+#define RTL8304E_PORT3 RTL8306_PORT5
+#define RTL8304E_PORTMASKIN(x)  (((((uint32)x)&0xC)<<2)|(((uint32)x)&0x3))
+#define RTL8304E_PORTMASKOUT(x) (((((uint32)x)&0x30)>>2)|(((uint32)x)&0x3))
+#endif
+#endif
diff --git a/ap/os/linux/linux-3.4.x/drivers/net/phy/realtek/rtl8306e/rtl8306e_types.h b/ap/os/linux/linux-3.4.x/drivers/net/phy/realtek/rtl8306e/rtl8306e_types.h
new file mode 100755
index 0000000..fb25173
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/net/phy/realtek/rtl8306e/rtl8306e_types.h
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2009 Realtek Semiconductor Corp. 
+ * All Rights Reserved.
+ *
+ * This program is the proprietary software of Realtek Semiconductor
+ * Corporation and/or its licensors, and only be used, duplicated, 
+ * modified or distributed under the authorized license from Realtek. 
+ *
+ * ANY USE OF THE SOFTWARE OTHER THAN AS AUTHORIZED UNDER 
+ * THIS LICENSE OR COPYRIGHT LAW IS PROHIBITED. 
+ *
+ * $Revision: 10083 $
+ * $Date: 2010-06-07 11:18:41 +0800 (星期一, 2010-06-07) $
+ *
+ * Purpose : RTL8306E switch API varable type declaration
+ * Feature : 
+ *
+ */
+ 
+ 
+#ifndef __RTL8306E_TYPES_H__
+#define __RTL8306E_TYPES_H__
+
+    
+#ifndef _RTL_TYPES_H
+typedef unsigned long long uint64;
+typedef long long int64;
+typedef unsigned int uint32;
+typedef int int32;
+typedef unsigned short uint16;
+typedef short int16;
+typedef unsigned char uint8;
+typedef char int8;
+#endif
+
+typedef int32                   rtk_api_ret_t;
+typedef int32                   ret_t;
+typedef uint64                  rtk_u_long_t;
+
+#ifndef ETHER_ADDR_LEN
+#define ETHER_ADDR_LEN 6
+#endif
+
+
+#ifndef NULL
+#define NULL 0
+#endif
+#ifndef TRUE
+#define TRUE 1
+#endif
+#ifndef FALSE
+#define FALSE 0
+#endif
+
+#ifndef SUCCESS
+#define SUCCESS 0
+#endif
+#ifndef FAILED
+#define FAILED -1
+#endif
+
+#define rtlglue_printf printf
+
+#endif
diff --git a/ap/os/linux/linux-3.4.x/drivers/net/phy/realtek/rtl8306e/rtl_types.h b/ap/os/linux/linux-3.4.x/drivers/net/phy/realtek/rtl8306e/rtl_types.h
new file mode 100755
index 0000000..ca670dc
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/net/phy/realtek/rtl8306e/rtl_types.h
@@ -0,0 +1,656 @@
+/*
+* Copyright c                  Realtek Semiconductor Corporation, 2002  
+* All rights reserved.                                                    
+* 
+* Program : The header file of realtek type definition
+* Abstract :                                                           
+* Author :              
+* $Id: rtl_types.h,v 1.2 2008-01-18 07:53:11 hyking_liu Exp $
+* $Log: not supported by cvs2svn $
+* Revision 1.1  2007/12/21 10:29:52  davidhsu
+* +: support nic driver
+*
+* Revision 1.27  2007/07/27 09:31:23  chenyl
+* +: Add macro for MIPS16-enabled function declaration.
+*
+* Revision 1.26  2007/07/24 08:37:02  chenyl
+* *: For MIPS16 related macros
+*
+* Revision 1.25  2007/06/25 13:08:43  alva_zhang
+* -: remove suitable header file rtl_config.h
+*
+* Revision 1.24  2007/06/25 05:42:30  alva_zhang
+* *: reopen including rtl_config.h
+*
+* Revision 1.23  2007/06/25 02:29:27  alva_zhang
+* -: diable include rtl_config.h temporarily
+*
+* Revision 1.22  2007/06/23 09:11:00  alva_zhang
+* +: add rtl_config.h which includes the MAcro indicate the usage of SDK
+*
+* Revision 1.21  2007/05/15 03:36:56  michaelhuang
+* *: fixed compatibility for Linux Kernel 2.6
+*
+* Revision 1.20  2007/04/04 15:48:54  chenyl
+* +: cleshell commend for asic register configuration : mmtu ( multicast mtu )
+*
+* Revision 1.19  2006/08/29 13:00:00  chenyl
+* *: New SWNIC driver for RTL865xC
+* *: some rearrange in re_core.c for Bootstrap sequence being more readable.
+*
+* Revision 1.18  2006/02/27 07:47:06  ympan
+* +: No change by ympan
+*
+* Revision 1.17  2005/09/27 05:59:44  chenyl
+* *: modify IRAM / DRAM layout:
+* 	IRAM/DRAM-FWD		: external used, swNic ... blahblah
+* 	IRAM/DRAM-L2-FWD	: fwdengine internal used, L2 and below (ex. preprocess, postprocess)
+* 	IRAM/DRAM-L34-FWD	: fwdengine internal used, L3/L4 process only (ex. Routing, decision table...etc).
+*
+* 	=> If L34 is used, we strongly suggest L2 must be used, too.
+*
+* Revision 1.16  2005/08/23 14:38:26  chenyl
+* +: apply prioirty IRAM/DRAM usage
+*
+* Revision 1.15  2005/08/22 07:33:55  chenyl
+* *: don't set DRAM/IRAM for other OSs yet.
+*
+* Revision 1.14  2005/08/18 09:14:08  chenyl
+* *: add code to porting to other OSs
+*
+* Revision 1.13  2005/08/18 06:29:29  chenyl
+* +: always define the rtlglue_printf in rtl_types.h
+*
+* Revision 1.12  2005/07/01 09:34:41  yjlou
+* *: porting swNic2.c into model code.
+*
+* Revision 1.11  2005/06/19 05:29:37  yjlou
+* *: use 'unsigned int' to replace 'size_t'
+* *: define spinlock_t when RTL865X_MODEL_USER defined.
+*
+* Revision 1.10  2005/06/10 05:32:22  yjlou
+* +: Porting CLE Shell to Linux user space for model test.
+*    See RTL865X_MODEL_USER compile flags.
+*
+* Revision 1.9  2005/01/10 03:21:43  yjlou
+* *: always define __IRAM and __DRAM
+*
+* Revision 1.8  2004/07/23 13:42:45  tony
+* *: remove all warning messages
+*
+* Revision 1.7  2004/07/05 08:25:32  chenyl
+* +: define __IRAM, __DRAM for module test
+*
+* Revision 1.6  2004/07/04 15:04:55  cfliu
+* +: add IRAM and DRAM
+*
+* Revision 1.5  2004/04/20 03:44:03  tony
+* if disable define "RTL865X_OVER_KERNEL" and "RTL865X_OVER_LINUX", __KERNEL__ and __linux__ will be undefined.
+*
+* Revision 1.4  2004/03/19 13:13:35  cfliu
+* Reorganize ROME driver local header files. Put all private data structures into different .h file corrsponding to its layering
+* Rename printf, printk, malloc, free with rtlglue_XXX prefix
+*
+* Revision 1.3  2004/03/05 07:44:27  cfliu
+* fix header file problem for ctype.h
+*
+* Revision 1.2  2004/03/03 10:40:38  yjlou
+* *: commit for mergence the difference in rtl86xx_tbl/ since 2004/02/26.
+*
+* Revision 1.1  2004/02/25 14:26:33  chhuang
+* *** empty log message ***
+*
+* Revision 1.3  2004/02/25 14:24:52  chhuang
+* *** empty log message ***
+*
+* Revision 1.8  2003/12/10 06:30:12  tony
+* add linux/config.h, disable define CONFIG_RTL865X_NICDRV2 in mbuf.c by default
+*
+* Revision 1.7  2003/12/03 14:25:43  cfliu
+* change SIZE_T to _SIZE_T. Linux kernel seems to recognize _SIZE_T
+*
+* Revision 1.6  2003/10/01 12:29:02  tony
+* #define DEBUG_P(args...) while(0);
+*
+* Revision 1.5  2003/10/01 10:31:47  tony
+* solve all the compiler warnning messages in the board.c
+*
+* Revision 1.4  2003/09/30 06:07:50  orlando
+* check in RTL8651BLDRV_V20_20030930
+*
+* Revision 1.30  2003/07/21 06:27:49  cfliu
+* no message
+*
+* Revision 1.29  2003/04/30 15:32:30  cfliu
+* move macros to types.h
+*
+* Revision 1.28  2003/03/13 10:29:22  cfliu
+* Remove unused symbols
+*
+* Revision 1.27  2003/03/06 05:00:04  cfliu
+* Move '#pragma ghs inlineprologue' to rtl_depend.h since it is compiler dependent
+*
+* Revision 1.26  2003/03/06 03:41:46  danwu
+* Prevent compiler from generating internal sub-routine call code at the
+*  function prologue and epilogue automatically
+*
+* Revision 1.25  2003/03/03 09:16:35  hiwu
+* remove ip4a
+*
+* Revision 1.24  2003/02/18 10:04:06  jzchen
+* Add ether_addr_t to compatable with protocol stack's ether_addr
+*
+* Revision 1.23  2003/01/21 05:59:51  cfliu
+* add min, max, SETBITS, CLEARBITS, etc.
+*
+* Revision 1.22  2002/11/25 07:31:30  cfliu
+* Remove _POSIX_SOURCE since it is cygwin specific
+*
+* Revision 1.21  2002/09/30 11:51:49  jzchen
+* Add ASSERT_ISR for not print inside ISR
+*
+* Revision 1.20  2002/09/18 01:43:24  jzchen
+* Add type limit definition
+*
+* Revision 1.19  2002/09/16 00:14:34  elvis
+* remove struct posix_handle_t (change the handle type from
+*  structure to uint32)
+*
+* Revision 1.18  2002/08/20 01:40:40  danwu
+* Add definitions of ipaddr_t & macaddr_t.
+*
+* Revision 1.17  2002/07/30 04:36:30  danwu
+* Add ASSERT_CSP.
+*
+* Revision 1.16  2002/07/19 06:47:30  cfliu
+* Add _POSIX_SOURCE symbol
+*
+* Revision 1.15  2002/07/05 02:10:39  elvis
+* Add new types for OSK
+*
+* Revision 1.14  2002/07/03 12:36:21  orlando
+* <rtl_depend.h> will use type definitions. Has to be moved to
+* be after the type declaration lines.
+*
+* Revision 1.13  2002/07/03 09:19:00  cfliu
+* Removed all standard header files from source code. They would be included by <core/types.h>-><rtl_depend.h>
+*
+* Revision 1.12  2002/07/03 09:16:48  cfliu
+* Removed all standard header files from source code. They would be included by <core/types.h>-><rtl_depend.h>
+*
+* Revision 1.11  2002/07/03 07:14:47  orlando
+* Add "struct posix_handle_t_", used by POSIX module.
+*
+* Revision 1.9  2002/06/21 03:15:36  cfliu
+* Add time.h for struct timeval
+*
+* Revision 1.8  2002/06/14 01:58:03  cfliu
+* Move sa_family_t to socket
+*
+* Revision 1.7  2002/06/13 09:37:42  cfliu
+* Move byte order conversion routines to socket
+*
+* Revision 1.6  2002/05/23 04:24:37  hiwu
+* change memaddr_t to calladdr_t
+*
+* Revision 1.5  2002/05/13 10:15:16  hiwu
+* add new type definition
+*
+* Revision 1.4  2002/05/09 05:21:51  cfliu
+* Add parenthesis around swaps16, swapl32
+*
+* Revision 1.3  2002/04/30 03:07:34  orlando
+* Remove UIxx_T definitions to conform with new
+* naming conventions.
+*
+* Revision 1.2  2002/04/29 10:10:32  hiwu
+* add NTOHS macro
+*
+* Revision 1.1.1.1  2002/04/26 08:53:53  orlando
+* Initial source tree creation.
+*
+* Revision 1.9  2002/04/25 03:59:05  cfliu
+* no message
+*
+* Revision 1.8  2002/04/08 08:08:04  hiwu
+* initial version
+*
+*/
+
+
+#ifndef _RTL_TYPES_H
+#define _RTL_TYPES_H
+
+#define RTL_LAYERED_DRIVER_DEBUG 0
+
+#if 0
+#ifndef RTL865X_OVER_KERNEL
+	#undef __KERNEL__
+#endif
+
+#ifndef RTL865X_OVER_LINUX
+	#undef __linux__
+#endif
+#endif
+
+/*
+ * Internal names for basic integral types.  Omit the typedef if
+ * not possible for a machine/compiler combination.
+ */
+#ifdef __linux__
+#ifdef __KERNEL__
+#include <linux/version.h>
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0))
+#include <linux/config.h>
+#endif
+//#include <linux/ctype.h>
+#include <linux/module.h>
+//#include <linux/string.h>
+
+#endif /*__KERNEL__*/
+#endif /*__linux__*/
+
+/* ===============================================================================
+		IRAM / DRAM definition
+    =============================================================================== */
+#undef __DRAM_GEN
+#undef __DRAM_FWD
+#undef __DRAM_L2_FWD
+#undef __DRAM_L34_FWD
+#undef __DRAM_EXTDEV
+#undef __DRAM_AIRGO
+#undef __DRAM_RTKWLAN
+#undef __DRAM_CRYPTO
+#undef __DRAM_VOIP
+#undef __DRAM_TX
+#undef __DRAM
+
+#undef __IRAM_GEN
+#undef __IRAM_FWD
+#undef __IRAM_L2_FWD
+#undef __IRAM_L34_FWD
+#undef __IRAM_EXTDEV
+#undef __IRAM_AIRGO
+#undef __IRAM_RTKWLAN
+#undef __IRAM_CRYPTO
+#undef __IRAM_VOIP
+#undef __IRAM_TX
+#undef __IRAM
+
+#if defined(__linux__)&&defined(__KERNEL__)&&defined(CONFIG_RTL_819X)&&!defined(CONFIG_RTL_8198C)
+	#define __DRAM_GEN			__attribute__  ((section(".dram-gen")))
+	#define __DRAM_FWD			__attribute__  ((section(".dram-fwd")))
+	#define __DRAM_L2_FWD		__attribute__  ((section(".dram-l2-fwd")))
+	#define __DRAM_L34_FWD	__attribute__  ((section(".dram-l34-fwd")))
+	#define __DRAM_EXTDEV		__attribute__  ((section(".dram-extdev")))
+	#define __DRAM_AIRGO		__attribute__  ((section(".dram-airgo")))
+	#define __DRAM_RTKWLAN	__attribute__  ((section(".dram-rtkwlan")))
+	#define __DRAM_CRYPTO		__attribute__  ((section(".dram-crypto")))
+	#define __DRAM_VOIP			__attribute__  ((section(".dram-voip")))
+	#define __DRAM_TX			__attribute__  ((section(".dram-tx")))
+	#define __DRAM				__attribute__  ((section(".dram")))
+
+	#define __IRAM_GEN			__attribute__  ((section(".iram-gen")))
+	#define __IRAM_FWD			__attribute__  ((section(".iram-fwd")))
+	#define __IRAM_L2_FWD		__attribute__  ((section(".iram-l2-fwd")))
+	#define __IRAM_L34_FWD		__attribute__  ((section(".iram-l34-fwd")))
+	#define __IRAM_EXTDEV		__attribute__  ((section(".iram-extdev")))
+	#define __IRAM_AIRGO		__attribute__  ((section(".iram-airgo")))
+	#define __IRAM_RTKWLAN		__attribute__  ((section(".iram-rtkwlan")))
+	#define __IRAM_CRYPTO		__attribute__  ((section(".iram-crypto")))
+	#define __IRAM_VOIP			__attribute__  ((section(".iram-voip")))
+	#define __IRAM_TX			__attribute__  ((section(".iram-tx")))
+	#define __IRAM				__attribute__  ((section(".iram")))
+#else
+	#define __DRAM_GEN
+	#define __DRAM_FWD
+	#define __DRAM_L2_FWD
+	#define __DRAM_L34_FWD
+	#define __DRAM_EXTDEV
+	#define __DRAM_AIRGO
+	#define __DRAM_RTKWLAN
+	#define __DRAM_CRYPTO
+	#define __DRAM_VOIP
+	#define __DRAM_TX
+	#define __DRAM
+
+	#define __IRAM_GEN
+	#define __IRAM_FWD
+	#define __IRAM_L2_FWD
+	#define __IRAM_L34_FWD
+	#define __IRAM_EXTDEV
+	#define __IRAM_AIRGO
+	#define __IRAM_RTKWLAN
+	#define __IRAM_CRYPTO
+	#define __IRAM_VOIP
+	#define __IRAM_TX
+	#define __IRAM
+#endif
+
+#if defined(CONFIG_RTL_DYNAMIC_IRAM_MAPPING_FOR_WAPI) &&!defined(CONFIG_RTL_8198C)
+	#define __IRAM_GEN_WAPI			__attribute__  ((section(".iram-gen-wapi")))
+	#define __IRAM_FWD_WAPI			__attribute__  ((section(".iram-fwd-wapi")))
+	#define __IRAM_L2_FWD_WAPI		__attribute__  ((section(".iram-l2-fwd-wapi")))
+	#define __IRAM_L34_FWD_WAPI		__attribute__  ((section(".iram-l34-fwd-wapi")))
+	#define __IRAM_RTKWLAN_WAPI		__attribute__  ((section(".iram-rtkwlan-wapi")))
+	#define __IRAM_TX_WAPI			__attribute__  ((section(".iram-tx-wapi")))
+
+	#define FUNCTION_CHECK(x)	do \
+							{ \
+								if((x)==NULL) \
+									printk("---%s %s(%d) function is NULL!!\n",__FILE__,__FUNCTION__,__LINE__); \
+							} while(0)
+#endif
+
+
+/* ===============================================================================
+		Additional GCC attribute
+    =============================================================================== */
+
+#undef __NOMIPS16
+#undef __MIPS16
+
+#if defined(__linux__)&&defined(__KERNEL__)&&defined(CONFIG_RTL_819X) && !defined(CONFIG_RTL_8196C)
+#ifndef CONFIG_WIRELESS_LAN_MODULE  //mark_wrt eric-sync ??
+	#define __NOMIPS16			__attribute__((nomips16))	/* Inidcate to prevent from MIPS16 */
+	#define __MIPS16			__attribute__((mips16))		/* Inidcate to use MIPS16 */
+#else
+	#define __NOMIPS16
+	#define __MIPS16
+#endif
+#else
+	#define __NOMIPS16
+	#define __MIPS16
+#endif
+
+/* ===============================================================================
+		print macro
+    =============================================================================== */
+#if	defined(__linux__)&&defined(__KERNEL__)
+	
+	#define rtlglue_printf	panic_printk
+
+#else	/* defined(__linux__)&&defined(__KERNEL__) */
+
+#ifdef	RTL865X_TEST
+	#include <ctype.h>
+#endif	/* RTL865X_TEST */
+
+#define rtlglue_printf	printf
+
+#endif	/* defined(__linux__)&&defined(__KERNEL__) */
+
+/* ===============================================================================
+		Type definition
+    =============================================================================== */
+#if 1
+typedef unsigned long long	uint64;
+typedef signed long long	int64;
+typedef unsigned int	uint32;
+
+#ifdef int32
+#undef int32
+#endif
+typedef signed int		int32;
+
+typedef unsigned short	uint16;
+typedef signed short	int16;
+typedef unsigned char	uint8;
+typedef signed char		int8;
+
+#else
+typedef __u64 uint64;
+typedef __s64	int64;
+typedef __u32	uint32;
+#ifndef int32
+typedef __s32			int32;
+#endif
+typedef __u16	uint16;
+typedef __s16	int16;
+typedef __u8		uint8;
+typedef __s8			int8;
+#endif
+
+typedef uint32		memaddr;	
+typedef uint32          ipaddr_t;
+typedef struct {
+    uint16      mac47_32;
+    uint16      mac31_16;
+    uint16      mac15_0;
+} macaddr_t;
+
+#define ETHER_ADDR_LEN				6
+typedef struct ether_addr_s {
+	uint8 octet[ETHER_ADDR_LEN];
+} ether_addr_t;
+
+#define RX_OFFSET	2
+#define MBUF_LEN	1700
+#define CROSS_LAN_MBUF_LEN		(MBUF_LEN+RX_OFFSET+10)
+
+#if defined(CONFIG_RTL_819X)
+	#if defined(CONFIG_RTL_ETH_PRIV_SKB)
+	#define DELAY_REFILL_ETH_RX_BUF	1
+	#endif
+#endif
+
+/* 
+	CN SD6 Mantis issue #1085: NIC RX can't work correctly after runout.
+	this bug still happened in RTL8196B
+ */
+
+#ifndef NULL
+#define NULL 0
+#endif
+#ifndef TRUE
+#define TRUE 1
+#endif
+#ifndef FALSE
+#define FALSE 0
+#endif
+
+#ifndef SUCCESS
+#define SUCCESS 	0
+#endif
+#ifndef FAILED
+#define FAILED -1
+#endif
+
+
+
+#define DEBUG_P(args...) while(0);
+#ifndef OK
+#define OK		0
+#endif
+#ifndef NOT_OK
+#define NOT_OK  1
+#endif
+
+#ifndef CLEARBITS
+#define CLEARBITS(a,b)	((a) &= ~(b))
+#endif
+
+#ifndef SETBITS
+#define SETBITS(a,b)		((a) |= (b))
+#endif
+
+#ifndef ISSET
+#define ISSET(a,b)		(((a) & (b))!=0)
+#endif
+
+#ifndef ISCLEARED
+#define ISCLEARED(a,b)	(((a) & (b))==0)
+#endif
+
+#ifndef max
+#define max(a,b)  (((a) > (b)) ? (a) : (b))
+#endif			   /* max */
+
+#ifndef min
+#define min(a,b)  (((a) < (b)) ? (a) : (b))
+#endif			   /* min */
+
+//round down x to multiple of y.  Ex: ROUNDDOWN(20, 7)=14
+#ifndef ROUNDDOWN
+#define	ROUNDDOWN(x, y)	(((x)/(y))*(y))
+#endif
+
+//round up x to multiple of y. Ex: ROUNDUP(11, 7) = 14
+#ifndef ROUNDUP
+#define	ROUNDUP(x, y)	((((x)+((y)-1))/(y))*(y))  /* to any y */
+#endif
+
+#ifndef ROUNDUP2
+#define	ROUNDUP2(x, y)	(((x)+((y)-1))&(~((y)-1))) /* if y is powers of two */
+#endif
+
+#ifndef ROUNDUP4
+#define	ROUNDUP4(x)		((1+(((x)-1)>>2))<<2)
+#endif
+
+#ifndef IS4BYTEALIGNED
+#define IS4BYTEALIGNED(x)	 ((((x) & 0x3)==0)? 1 : 0)
+#endif
+
+#ifndef __offsetof
+#define __offsetof(type, field) ((unsigned long)(&((type *)0)->field))
+#endif
+
+#ifndef offsetof
+#define offsetof(type, field) __offsetof(type, field)
+#endif
+
+#ifndef RTL_PROC_CHECK
+#define RTL_PROC_CHECK(expr, success) \
+	do {\
+			int __retval; \
+			if ((__retval = (expr)) != (success))\
+			{\
+				rtlglue_printf("ERROR >>> [%s]:[%d] failed -- return value: %d\n", __FUNCTION__,__LINE__, __retval);\
+				return __retval; \
+			}\
+		}while(0)
+#endif
+
+#ifndef RTL_STREAM_SAME
+#define RTL_STREAM_SAME(s1, s2) \
+	((strlen(s1) == strlen(s2)) && (strcmp(s1, s2) == 0))
+#endif
+
+#define ASSERT_ISR(x) if(!(x)) {while(1);}
+#define RTL_STATIC_INLINE   static __inline__
+
+#define ASSERT_CSP(x) if (!(x)) {rtlglue_printf("\nAssert Fail: %s %d", __FILE__, __LINE__); while(1);}
+ 
+
+#if defined(RTL865X_TEST)||defined(RTL865X_MODEL_USER)
+#define UNCACHE_MASK		0
+#define UNCACHE(addr)		(addr)
+#define CACHED(addr)			((uint32)(addr))
+#else
+#define UNCACHE_MASK		0x20000000
+#define UNCACHE(addr)		((UNCACHE_MASK)|(uint32)(addr))
+#define CACHED(addr)			((uint32)(addr) & ~(UNCACHE_MASK))
+#endif
+
+/*	asic configuration	*/
+#define RTL8651_OUTPUTQUEUE_SIZE		6
+#define TOTAL_VLAN_PRIORITY_NUM	8
+#define RTL8651_RATELIMITTBL_SIZE			32
+
+#if defined(CONFIG_RTL_8196C)
+#define CONFIG_RTL8196C_ETH_IOT         1
+#ifdef CONFIG_MP_PSD_SUPPORT
+#undef CONFIG_RTL8196C_GREEN_ETHERNET
+#else
+//#define CONFIG_RTL_8196C_ESD            1 
+#endif
+#endif
+
+#if defined(CONFIG_RTL_8198) && !defined(CONFIG_RTL_819XD)
+#define CONFIG_RTL_8198_ESD        1
+#endif 
+
+#if defined(CONFIG_RTL_8198)
+#define RTL8198_EEE_MAC 	1
+#endif
+
+#if defined(CONFIG_RTL_819XD) || defined(CONFIG_RTL_8196E)
+#define CONFIG_RTL_8197D_DYN_THR		1
+#endif
+
+#define DYN_THR_LINK_UP_PORTS			3
+
+/* IC default value */
+#define DYN_THR_DEF_fcON				0xac
+#define DYN_THR_DEF_fcOFF				0xa0
+#define DYN_THR_DEF_sharedON			0x62
+#define DYN_THR_DEF_sharedOFF			0x4a
+
+/* aggressive value */
+#define DYN_THR_AGG_fcON				0xd0
+#define DYN_THR_AGG_fcOFF				0xc0
+#define DYN_THR_AGG_sharedON			0xc0
+#define DYN_THR_AGG_sharedOFF			0xa8
+
+#if defined(CONFIG_RTL_LOG_DEBUG)
+extern int scrlog_printk(const char * fmt, ...);
+
+extern struct RTL_LOG_PRINT_MASK
+{
+	uint32 ERROR:1;
+	uint32 WARN:1;
+	uint32 INFO:1;
+}RTL_LogTypeMask;
+
+extern struct RTL_LOG_ERROR_MASK
+{
+	uint32 MEM:1;
+	uint32 SKB:1;
+}RTL_LogErrorMask;
+extern uint32 RTL_LogRatelimit;
+
+extern struct RTL_LOG_MODULE_MASK
+{
+	uint8 NIC:1;
+	uint8 WIRELESS:1;
+	uint8 PROSTACK:1;
+}RTL_LogModuleMask;
+
+
+#define LOG_LIMIT (!RTL_LogRatelimit||net_ratelimit())
+
+
+#define LOG_ERROR(fmt, args...) do{ \
+	if(RTL_LogTypeMask.ERROR&&LOG_LIMIT)scrlog_printk("ERROR:"fmt, ## args); \
+		}while(0)
+		
+#define LOG_MEM_ERROR(fmt, args...) do{ \
+	if(RTL_LogTypeMask.ERROR&&RTL_LogErrorMask.MEM&&LOG_LIMIT)scrlog_printk("ERROR:"fmt, ## args); \
+		}while(0)
+		
+#define LOG_SKB_ERROR(fmt, args...) do{ \
+		if(RTL_LogTypeMask.ERROR&&RTL_LogErrorMask.SKB&&LOG_LIMIT)scrlog_printk("ERROR:"fmt, ## args); \
+			}while(0)
+			
+#define LOG_WARN(fmt, args...) do{ \
+		if(RTL_LogTypeMask.WARN&&LOG_LIMIT)scrlog_printk("WARN:"fmt, ## args); \
+			}while(0)
+			
+#define LOG_INFO(fmt, args...) do{ \
+		if(RTL_LogTypeMask.INFO&&LOG_LIMIT)scrlog_printk("INFO:"fmt, ## args); \
+			}while(0)
+
+#else
+
+#define LOG_ERROR(fmt, args...) 
+#define LOG_MEM_ERROR(fmt, args...) 
+#define LOG_SKB_ERROR(fmt, args...)
+#define LOG_WARN(fmt, args...)
+#define LOG_INFO(fmt, args...)
+
+#endif 
+
+#endif 
+
+
diff --git a/ap/os/linux/linux-3.4.x/drivers/net/phy/smsc.c b/ap/os/linux/linux-3.4.x/drivers/net/phy/smsc.c
new file mode 100644
index 0000000..fc3e7e9
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/net/phy/smsc.c
@@ -0,0 +1,247 @@
+/*
+ * drivers/net/phy/smsc.c
+ *
+ * Driver for SMSC PHYs
+ *
+ * Author: Herbert Valerio Riedel
+ *
+ * Copyright (c) 2006 Herbert Valerio Riedel <hvr@gnu.org>
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ *
+ * Support added for SMSC LAN8187 and LAN8700 by steve.glendinning@smsc.com
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/mii.h>
+#include <linux/ethtool.h>
+#include <linux/phy.h>
+#include <linux/netdevice.h>
+#include <linux/smscphy.h>
+
+static int smsc_phy_config_intr(struct phy_device *phydev)
+{
+	int rc = phy_write (phydev, MII_LAN83C185_IM,
+			((PHY_INTERRUPT_ENABLED == phydev->interrupts)
+			? MII_LAN83C185_ISF_INT_PHYLIB_EVENTS
+			: 0));
+
+	return rc < 0 ? rc : 0;
+}
+
+static int smsc_phy_ack_interrupt(struct phy_device *phydev)
+{
+	int rc = phy_read (phydev, MII_LAN83C185_ISF);
+
+	return rc < 0 ? rc : 0;
+}
+
+static int smsc_phy_config_init(struct phy_device *phydev)
+{
+	int rc = phy_read(phydev, MII_LAN83C185_CTRL_STATUS);
+	if (rc < 0)
+		return rc;
+
+	/* Enable energy detect mode for this SMSC Transceivers */
+	rc = phy_write(phydev, MII_LAN83C185_CTRL_STATUS,
+		       rc | MII_LAN83C185_EDPWRDOWN);
+	if (rc < 0)
+		return rc;
+
+	return smsc_phy_ack_interrupt (phydev);
+}
+
+static int lan911x_config_init(struct phy_device *phydev)
+{
+	return smsc_phy_ack_interrupt(phydev);
+}
+
+static struct phy_driver lan83c185_driver = {
+	.phy_id		= 0x0007c0a0, /* OUI=0x00800f, Model#=0x0a */
+	.phy_id_mask	= 0xfffffff0,
+	.name		= "SMSC LAN83C185",
+
+	.features	= (PHY_BASIC_FEATURES | SUPPORTED_Pause
+				| SUPPORTED_Asym_Pause),
+	.flags		= PHY_HAS_INTERRUPT | PHY_HAS_MAGICANEG,
+
+	/* basic functions */
+	.config_aneg	= genphy_config_aneg,
+	.read_status	= genphy_read_status,
+	.config_init	= smsc_phy_config_init,
+
+	/* IRQ related */
+	.ack_interrupt	= smsc_phy_ack_interrupt,
+	.config_intr	= smsc_phy_config_intr,
+
+	.suspend	= genphy_suspend,
+	.resume		= genphy_resume,
+
+	.driver		= { .owner = THIS_MODULE, }
+};
+
+static struct phy_driver lan8187_driver = {
+	.phy_id		= 0x0007c0b0, /* OUI=0x00800f, Model#=0x0b */
+	.phy_id_mask	= 0xfffffff0,
+	.name		= "SMSC LAN8187",
+
+	.features	= (PHY_BASIC_FEATURES | SUPPORTED_Pause
+				| SUPPORTED_Asym_Pause),
+	.flags		= PHY_HAS_INTERRUPT | PHY_HAS_MAGICANEG,
+
+	/* basic functions */
+	.config_aneg	= genphy_config_aneg,
+	.read_status	= genphy_read_status,
+	.config_init	= smsc_phy_config_init,
+
+	/* IRQ related */
+	.ack_interrupt	= smsc_phy_ack_interrupt,
+	.config_intr	= smsc_phy_config_intr,
+
+	.suspend	= genphy_suspend,
+	.resume		= genphy_resume,
+
+	.driver		= { .owner = THIS_MODULE, }
+};
+
+static struct phy_driver lan8700_driver = {
+	.phy_id		= 0x0007c0c0, /* OUI=0x00800f, Model#=0x0c */
+	.phy_id_mask	= 0xfffffff0,
+	.name		= "SMSC LAN8700",
+
+	.features	= (PHY_BASIC_FEATURES | SUPPORTED_Pause
+				| SUPPORTED_Asym_Pause),
+	.flags		= PHY_HAS_INTERRUPT | PHY_HAS_MAGICANEG,
+
+	/* basic functions */
+	.config_aneg	= genphy_config_aneg,
+	.read_status	= genphy_read_status,
+	.config_init	= smsc_phy_config_init,
+
+	/* IRQ related */
+	.ack_interrupt	= smsc_phy_ack_interrupt,
+	.config_intr	= smsc_phy_config_intr,
+
+	.suspend	= genphy_suspend,
+	.resume		= genphy_resume,
+
+	.driver		= { .owner = THIS_MODULE, }
+};
+
+static struct phy_driver lan911x_int_driver = {
+	.phy_id		= 0x0007c0d0, /* OUI=0x00800f, Model#=0x0d */
+	.phy_id_mask	= 0xfffffff0,
+	.name		= "SMSC LAN911x Internal PHY",
+
+	.features	= (PHY_BASIC_FEATURES | SUPPORTED_Pause
+				| SUPPORTED_Asym_Pause),
+	.flags		= PHY_HAS_INTERRUPT | PHY_HAS_MAGICANEG,
+
+	/* basic functions */
+	.config_aneg	= genphy_config_aneg,
+	.read_status	= genphy_read_status,
+	.config_init	= lan911x_config_init,
+
+	/* IRQ related */
+	.ack_interrupt	= smsc_phy_ack_interrupt,
+	.config_intr	= smsc_phy_config_intr,
+
+	.suspend	= genphy_suspend,
+	.resume		= genphy_resume,
+
+	.driver		= { .owner = THIS_MODULE, }
+};
+
+static struct phy_driver lan8710_driver = {
+	.phy_id		= 0x0007c0f0, /* OUI=0x00800f, Model#=0x0f */
+	.phy_id_mask	= 0xfffffff0,
+	.name		= "SMSC LAN8710/LAN8720",
+
+	.features	= (PHY_BASIC_FEATURES | SUPPORTED_Pause
+				| SUPPORTED_Asym_Pause),
+	.flags		= PHY_HAS_INTERRUPT | PHY_HAS_MAGICANEG,
+
+	/* basic functions */
+	.config_aneg	= genphy_config_aneg,
+	.read_status	= genphy_read_status,
+	.config_init	= smsc_phy_config_init,
+
+	/* IRQ related */
+	.ack_interrupt	= smsc_phy_ack_interrupt,
+	.config_intr	= smsc_phy_config_intr,
+
+	.suspend	= genphy_suspend,
+	.resume		= genphy_resume,
+
+	.driver		= { .owner = THIS_MODULE, }
+};
+
+static int __init smsc_init(void)
+{
+	int ret;
+
+	ret = phy_driver_register (&lan83c185_driver);
+	if (ret)
+		goto err1;
+
+	ret = phy_driver_register (&lan8187_driver);
+	if (ret)
+		goto err2;
+
+	ret = phy_driver_register (&lan8700_driver);
+	if (ret)
+		goto err3;
+
+	ret = phy_driver_register (&lan911x_int_driver);
+	if (ret)
+		goto err4;
+
+	ret = phy_driver_register (&lan8710_driver);
+	if (ret)
+		goto err5;
+
+	return 0;
+
+err5:
+	phy_driver_unregister (&lan911x_int_driver);
+err4:
+	phy_driver_unregister (&lan8700_driver);
+err3:
+	phy_driver_unregister (&lan8187_driver);
+err2:
+	phy_driver_unregister (&lan83c185_driver);
+err1:
+	return ret;
+}
+
+static void __exit smsc_exit(void)
+{
+	phy_driver_unregister (&lan8710_driver);
+	phy_driver_unregister (&lan911x_int_driver);
+	phy_driver_unregister (&lan8700_driver);
+	phy_driver_unregister (&lan8187_driver);
+	phy_driver_unregister (&lan83c185_driver);
+}
+
+MODULE_DESCRIPTION("SMSC PHY driver");
+MODULE_AUTHOR("Herbert Valerio Riedel");
+MODULE_LICENSE("GPL");
+
+module_init(smsc_init);
+module_exit(smsc_exit);
+
+static struct mdio_device_id __maybe_unused smsc_tbl[] = {
+	{ 0x0007c0a0, 0xfffffff0 },
+	{ 0x0007c0b0, 0xfffffff0 },
+	{ 0x0007c0c0, 0xfffffff0 },
+	{ 0x0007c0d0, 0xfffffff0 },
+	{ 0x0007c0f0, 0xfffffff0 },
+	{ }
+};
+
+MODULE_DEVICE_TABLE(mdio, smsc_tbl);
diff --git a/ap/os/linux/linux-3.4.x/drivers/net/phy/spi_ks8995.c b/ap/os/linux/linux-3.4.x/drivers/net/phy/spi_ks8995.c
new file mode 100644
index 0000000..116a2dd
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/net/phy/spi_ks8995.c
@@ -0,0 +1,375 @@
+/*
+ * SPI driver for Micrel/Kendin KS8995M ethernet switch
+ *
+ * Copyright (C) 2008 Gabor Juhos <juhosg at openwrt.org>
+ *
+ * This file was based on: drivers/spi/at25.c
+ *     Copyright (C) 2006 David Brownell
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation.
+ */
+
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+
+#include <linux/spi/spi.h>
+
+#define DRV_VERSION		"0.1.1"
+#define DRV_DESC		"Micrel KS8995 Ethernet switch SPI driver"
+
+/* ------------------------------------------------------------------------ */
+
+#define KS8995_REG_ID0		0x00    /* Chip ID0 */
+#define KS8995_REG_ID1		0x01    /* Chip ID1 */
+
+#define KS8995_REG_GC0		0x02    /* Global Control 0 */
+#define KS8995_REG_GC1		0x03    /* Global Control 1 */
+#define KS8995_REG_GC2		0x04    /* Global Control 2 */
+#define KS8995_REG_GC3		0x05    /* Global Control 3 */
+#define KS8995_REG_GC4		0x06    /* Global Control 4 */
+#define KS8995_REG_GC5		0x07    /* Global Control 5 */
+#define KS8995_REG_GC6		0x08    /* Global Control 6 */
+#define KS8995_REG_GC7		0x09    /* Global Control 7 */
+#define KS8995_REG_GC8		0x0a    /* Global Control 8 */
+#define KS8995_REG_GC9		0x0b    /* Global Control 9 */
+
+#define KS8995_REG_PC(p, r)	((0x10 * p) + r)	 /* Port Control */
+#define KS8995_REG_PS(p, r)	((0x10 * p) + r + 0xe)  /* Port Status */
+
+#define KS8995_REG_TPC0		0x60    /* TOS Priority Control 0 */
+#define KS8995_REG_TPC1		0x61    /* TOS Priority Control 1 */
+#define KS8995_REG_TPC2		0x62    /* TOS Priority Control 2 */
+#define KS8995_REG_TPC3		0x63    /* TOS Priority Control 3 */
+#define KS8995_REG_TPC4		0x64    /* TOS Priority Control 4 */
+#define KS8995_REG_TPC5		0x65    /* TOS Priority Control 5 */
+#define KS8995_REG_TPC6		0x66    /* TOS Priority Control 6 */
+#define KS8995_REG_TPC7		0x67    /* TOS Priority Control 7 */
+
+#define KS8995_REG_MAC0		0x68    /* MAC address 0 */
+#define KS8995_REG_MAC1		0x69    /* MAC address 1 */
+#define KS8995_REG_MAC2		0x6a    /* MAC address 2 */
+#define KS8995_REG_MAC3		0x6b    /* MAC address 3 */
+#define KS8995_REG_MAC4		0x6c    /* MAC address 4 */
+#define KS8995_REG_MAC5		0x6d    /* MAC address 5 */
+
+#define KS8995_REG_IAC0		0x6e    /* Indirect Access Control 0 */
+#define KS8995_REG_IAC1		0x6f    /* Indirect Access Control 0 */
+#define KS8995_REG_IAD7		0x70    /* Indirect Access Data 7 */
+#define KS8995_REG_IAD6		0x71    /* Indirect Access Data 6 */
+#define KS8995_REG_IAD5		0x72    /* Indirect Access Data 5 */
+#define KS8995_REG_IAD4		0x73    /* Indirect Access Data 4 */
+#define KS8995_REG_IAD3		0x74    /* Indirect Access Data 3 */
+#define KS8995_REG_IAD2		0x75    /* Indirect Access Data 2 */
+#define KS8995_REG_IAD1		0x76    /* Indirect Access Data 1 */
+#define KS8995_REG_IAD0		0x77    /* Indirect Access Data 0 */
+
+#define KS8995_REGS_SIZE	0x80
+
+#define ID1_CHIPID_M		0xf
+#define ID1_CHIPID_S		4
+#define ID1_REVISION_M		0x7
+#define ID1_REVISION_S		1
+#define ID1_START_SW		1	/* start the switch */
+
+#define FAMILY_KS8995		0x95
+#define CHIPID_M		0
+
+#define KS8995_CMD_WRITE	0x02U
+#define KS8995_CMD_READ		0x03U
+
+#define KS8995_RESET_DELAY	10 /* usec */
+
+struct ks8995_pdata {
+	/* not yet implemented */
+};
+
+struct ks8995_switch {
+	struct spi_device	*spi;
+	struct mutex		lock;
+	struct ks8995_pdata	*pdata;
+};
+
+static inline u8 get_chip_id(u8 val)
+{
+	return (val >> ID1_CHIPID_S) & ID1_CHIPID_M;
+}
+
+static inline u8 get_chip_rev(u8 val)
+{
+	return (val >> ID1_REVISION_S) & ID1_REVISION_M;
+}
+
+/* ------------------------------------------------------------------------ */
+static int ks8995_read(struct ks8995_switch *ks, char *buf,
+		 unsigned offset, size_t count)
+{
+	u8 cmd[2];
+	struct spi_transfer t[2];
+	struct spi_message m;
+	int err;
+
+	spi_message_init(&m);
+
+	memset(&t, 0, sizeof(t));
+
+	t[0].tx_buf = cmd;
+	t[0].len = sizeof(cmd);
+	spi_message_add_tail(&t[0], &m);
+
+	t[1].rx_buf = buf;
+	t[1].len = count;
+	spi_message_add_tail(&t[1], &m);
+
+	cmd[0] = KS8995_CMD_READ;
+	cmd[1] = offset;
+
+	mutex_lock(&ks->lock);
+	err = spi_sync(ks->spi, &m);
+	mutex_unlock(&ks->lock);
+
+	return err ? err : count;
+}
+
+
+static int ks8995_write(struct ks8995_switch *ks, char *buf,
+		 unsigned offset, size_t count)
+{
+	u8 cmd[2];
+	struct spi_transfer t[2];
+	struct spi_message m;
+	int err;
+
+	spi_message_init(&m);
+
+	memset(&t, 0, sizeof(t));
+
+	t[0].tx_buf = cmd;
+	t[0].len = sizeof(cmd);
+	spi_message_add_tail(&t[0], &m);
+
+	t[1].tx_buf = buf;
+	t[1].len = count;
+	spi_message_add_tail(&t[1], &m);
+
+	cmd[0] = KS8995_CMD_WRITE;
+	cmd[1] = offset;
+
+	mutex_lock(&ks->lock);
+	err = spi_sync(ks->spi, &m);
+	mutex_unlock(&ks->lock);
+
+	return err ? err : count;
+}
+
+static inline int ks8995_read_reg(struct ks8995_switch *ks, u8 addr, u8 *buf)
+{
+	return (ks8995_read(ks, buf, addr, 1) != 1);
+}
+
+static inline int ks8995_write_reg(struct ks8995_switch *ks, u8 addr, u8 val)
+{
+	char buf = val;
+
+	return (ks8995_write(ks, &buf, addr, 1) != 1);
+}
+
+/* ------------------------------------------------------------------------ */
+
+static int ks8995_stop(struct ks8995_switch *ks)
+{
+	return ks8995_write_reg(ks, KS8995_REG_ID1, 0);
+}
+
+static int ks8995_start(struct ks8995_switch *ks)
+{
+	return ks8995_write_reg(ks, KS8995_REG_ID1, 1);
+}
+
+static int ks8995_reset(struct ks8995_switch *ks)
+{
+	int err;
+
+	err = ks8995_stop(ks);
+	if (err)
+		return err;
+
+	udelay(KS8995_RESET_DELAY);
+
+	return ks8995_start(ks);
+}
+
+/* ------------------------------------------------------------------------ */
+
+static ssize_t ks8995_registers_read(struct file *filp, struct kobject *kobj,
+	struct bin_attribute *bin_attr, char *buf, loff_t off, size_t count)
+{
+	struct device *dev;
+	struct ks8995_switch *ks8995;
+
+	dev = container_of(kobj, struct device, kobj);
+	ks8995 = dev_get_drvdata(dev);
+
+	if (unlikely(off > KS8995_REGS_SIZE))
+		return 0;
+
+	if ((off + count) > KS8995_REGS_SIZE)
+		count = KS8995_REGS_SIZE - off;
+
+	if (unlikely(!count))
+		return count;
+
+	return ks8995_read(ks8995, buf, off, count);
+}
+
+
+static ssize_t ks8995_registers_write(struct file *filp, struct kobject *kobj,
+	struct bin_attribute *bin_attr, char *buf, loff_t off, size_t count)
+{
+	struct device *dev;
+	struct ks8995_switch *ks8995;
+
+	dev = container_of(kobj, struct device, kobj);
+	ks8995 = dev_get_drvdata(dev);
+
+	if (unlikely(off >= KS8995_REGS_SIZE))
+		return -EFBIG;
+
+	if ((off + count) > KS8995_REGS_SIZE)
+		count = KS8995_REGS_SIZE - off;
+
+	if (unlikely(!count))
+		return count;
+
+	return ks8995_write(ks8995, buf, off, count);
+}
+
+
+static struct bin_attribute ks8995_registers_attr = {
+	.attr = {
+		.name   = "registers",
+		.mode   = S_IRUSR | S_IWUSR,
+	},
+	.size   = KS8995_REGS_SIZE,
+	.read   = ks8995_registers_read,
+	.write  = ks8995_registers_write,
+};
+
+/* ------------------------------------------------------------------------ */
+
+static int __devinit ks8995_probe(struct spi_device *spi)
+{
+	struct ks8995_switch    *ks;
+	struct ks8995_pdata     *pdata;
+	u8      ids[2];
+	int     err;
+
+	/* Chip description */
+	pdata = spi->dev.platform_data;
+
+	ks = kzalloc(sizeof(*ks), GFP_KERNEL);
+	if (!ks) {
+		dev_err(&spi->dev, "no memory for private data\n");
+		return -ENOMEM;
+	}
+
+	mutex_init(&ks->lock);
+	ks->pdata = pdata;
+	ks->spi = spi_dev_get(spi);
+	dev_set_drvdata(&spi->dev, ks);
+
+	spi->mode = SPI_MODE_0;
+	spi->bits_per_word = 8;
+	err = spi_setup(spi);
+	if (err) {
+		dev_err(&spi->dev, "spi_setup failed, err=%d\n", err);
+		goto err_drvdata;
+	}
+
+	err = ks8995_read(ks, ids, KS8995_REG_ID0, sizeof(ids));
+	if (err < 0) {
+		dev_err(&spi->dev, "unable to read id registers, err=%d\n",
+				err);
+		goto err_drvdata;
+	}
+
+	switch (ids[0]) {
+	case FAMILY_KS8995:
+		break;
+	default:
+		dev_err(&spi->dev, "unknown family id:%02x\n", ids[0]);
+		err = -ENODEV;
+		goto err_drvdata;
+	}
+
+	err = ks8995_reset(ks);
+	if (err)
+		goto err_drvdata;
+
+	err = sysfs_create_bin_file(&spi->dev.kobj, &ks8995_registers_attr);
+	if (err) {
+		dev_err(&spi->dev, "unable to create sysfs file, err=%d\n",
+				    err);
+		goto err_drvdata;
+	}
+
+	dev_info(&spi->dev, "KS89%02X device found, Chip ID:%01x, "
+			"Revision:%01x\n", ids[0],
+			get_chip_id(ids[1]), get_chip_rev(ids[1]));
+
+	return 0;
+
+err_drvdata:
+	dev_set_drvdata(&spi->dev, NULL);
+	kfree(ks);
+	return err;
+}
+
+static int __devexit ks8995_remove(struct spi_device *spi)
+{
+	struct ks8995_data      *ks8995;
+
+	ks8995 = dev_get_drvdata(&spi->dev);
+	sysfs_remove_bin_file(&spi->dev.kobj, &ks8995_registers_attr);
+
+	dev_set_drvdata(&spi->dev, NULL);
+	kfree(ks8995);
+
+	return 0;
+}
+
+/* ------------------------------------------------------------------------ */
+
+static struct spi_driver ks8995_driver = {
+	.driver = {
+		.name	    = "spi-ks8995",
+		.bus	     = &spi_bus_type,
+		.owner	   = THIS_MODULE,
+	},
+	.probe	  = ks8995_probe,
+	.remove	  = __devexit_p(ks8995_remove),
+};
+
+static int __init ks8995_init(void)
+{
+	printk(KERN_INFO DRV_DESC " version " DRV_VERSION"\n");
+
+	return spi_register_driver(&ks8995_driver);
+}
+module_init(ks8995_init);
+
+static void __exit ks8995_exit(void)
+{
+	spi_unregister_driver(&ks8995_driver);
+}
+module_exit(ks8995_exit);
+
+MODULE_DESCRIPTION(DRV_DESC);
+MODULE_VERSION(DRV_VERSION);
+MODULE_AUTHOR("Gabor Juhos <juhosg at openwrt.org>");
+MODULE_LICENSE("GPL v2");
diff --git a/ap/os/linux/linux-3.4.x/drivers/net/phy/ste10Xp.c b/ap/os/linux/linux-3.4.x/drivers/net/phy/ste10Xp.c
new file mode 100644
index 0000000..187a2fa
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/net/phy/ste10Xp.c
@@ -0,0 +1,145 @@
+/*
+ * drivers/net/phy/ste10Xp.c
+ *
+ * Driver for STMicroelectronics STe10Xp PHYs
+ *
+ * Author: Giuseppe Cavallaro <peppe.cavallaro@st.com>
+ *
+ * Copyright (c) 2008 STMicroelectronics Limited
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/moduleparam.h>
+#include <linux/interrupt.h>
+#include <linux/netdevice.h>
+#include <linux/ethtool.h>
+#include <linux/mii.h>
+#include <linux/phy.h>
+
+#define MII_XCIIS   	0x11	/* Configuration Info IRQ & Status Reg */
+#define MII_XIE     	0x12	/* Interrupt Enable Register */
+#define MII_XIE_DEFAULT_MASK 0x0070 /* ANE complete, Remote Fault, Link Down */
+
+#define STE101P_PHY_ID		0x00061c50
+#define STE100P_PHY_ID       	0x1c040011
+
+static int ste10Xp_config_init(struct phy_device *phydev)
+{
+	int value, err;
+
+	/* Software Reset PHY */
+	value = phy_read(phydev, MII_BMCR);
+	if (value < 0)
+		return value;
+
+	value |= BMCR_RESET;
+	err = phy_write(phydev, MII_BMCR, value);
+	if (err < 0)
+		return err;
+
+	do {
+		value = phy_read(phydev, MII_BMCR);
+	} while (value & BMCR_RESET);
+
+	return 0;
+}
+
+static int ste10Xp_config_intr(struct phy_device *phydev)
+{
+	int err, value;
+
+	if (phydev->interrupts == PHY_INTERRUPT_ENABLED) {
+		/* Enable all STe101P interrupts (PR12) */
+		err = phy_write(phydev, MII_XIE, MII_XIE_DEFAULT_MASK);
+		/* clear any pending interrupts */
+		if (err == 0) {
+			value = phy_read(phydev, MII_XCIIS);
+			if (value < 0)
+				err = value;
+		}
+	} else
+		err = phy_write(phydev, MII_XIE, 0);
+
+	return err;
+}
+
+static int ste10Xp_ack_interrupt(struct phy_device *phydev)
+{
+	int err = phy_read(phydev, MII_XCIIS);
+	if (err < 0)
+		return err;
+
+	return 0;
+}
+
+static struct phy_driver ste101p_pdriver = {
+	.phy_id = STE101P_PHY_ID,
+	.phy_id_mask = 0xfffffff0,
+	.name = "STe101p",
+	.features = PHY_BASIC_FEATURES | SUPPORTED_Pause,
+	.flags = PHY_HAS_INTERRUPT,
+	.config_init = ste10Xp_config_init,
+	.config_aneg = genphy_config_aneg,
+	.read_status = genphy_read_status,
+	.ack_interrupt = ste10Xp_ack_interrupt,
+	.config_intr = ste10Xp_config_intr,
+	.suspend = genphy_suspend,
+	.resume = genphy_resume,
+	.driver = {.owner = THIS_MODULE,}
+};
+
+static struct phy_driver ste100p_pdriver = {
+	.phy_id = STE100P_PHY_ID,
+	.phy_id_mask = 0xffffffff,
+	.name = "STe100p",
+	.features = PHY_BASIC_FEATURES | SUPPORTED_Pause,
+	.flags = PHY_HAS_INTERRUPT,
+	.config_init = ste10Xp_config_init,
+	.config_aneg = genphy_config_aneg,
+	.read_status = genphy_read_status,
+	.ack_interrupt = ste10Xp_ack_interrupt,
+	.config_intr = ste10Xp_config_intr,
+	.suspend = genphy_suspend,
+	.resume = genphy_resume,
+	.driver = {.owner = THIS_MODULE,}
+};
+
+static int __init ste10Xp_init(void)
+{
+	int retval;
+
+	retval = phy_driver_register(&ste100p_pdriver);
+	if (retval < 0)
+		return retval;
+	return phy_driver_register(&ste101p_pdriver);
+}
+
+static void __exit ste10Xp_exit(void)
+{
+	phy_driver_unregister(&ste100p_pdriver);
+	phy_driver_unregister(&ste101p_pdriver);
+}
+
+module_init(ste10Xp_init);
+module_exit(ste10Xp_exit);
+
+static struct mdio_device_id __maybe_unused ste10Xp_tbl[] = {
+	{ STE101P_PHY_ID, 0xfffffff0 },
+	{ STE100P_PHY_ID, 0xffffffff },
+	{ }
+};
+
+MODULE_DEVICE_TABLE(mdio, ste10Xp_tbl);
+
+MODULE_DESCRIPTION("STMicroelectronics STe10Xp PHY driver");
+MODULE_AUTHOR("Giuseppe Cavallaro <peppe.cavallaro@st.com>");
+MODULE_LICENSE("GPL");
diff --git a/ap/os/linux/linux-3.4.x/drivers/net/phy/vitesse.c b/ap/os/linux/linux-3.4.x/drivers/net/phy/vitesse.c
new file mode 100644
index 0000000..0ec8e09
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/net/phy/vitesse.c
@@ -0,0 +1,211 @@
+/*
+ * Driver for Vitesse PHYs
+ *
+ * Author: Kriston Carson
+ *
+ * Copyright (c) 2005, 2009 Freescale Semiconductor, Inc.
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/mii.h>
+#include <linux/ethtool.h>
+#include <linux/phy.h>
+
+/* Vitesse Extended Control Register 1 */
+#define MII_VSC8244_EXT_CON1           0x17
+#define MII_VSC8244_EXTCON1_INIT       0x0000
+#define MII_VSC8244_EXTCON1_TX_SKEW_MASK	0x0c00
+#define MII_VSC8244_EXTCON1_RX_SKEW_MASK	0x0300
+#define MII_VSC8244_EXTCON1_TX_SKEW	0x0800
+#define MII_VSC8244_EXTCON1_RX_SKEW	0x0200
+
+/* Vitesse Interrupt Mask Register */
+#define MII_VSC8244_IMASK		0x19
+#define MII_VSC8244_IMASK_IEN		0x8000
+#define MII_VSC8244_IMASK_SPEED		0x4000
+#define MII_VSC8244_IMASK_LINK		0x2000
+#define MII_VSC8244_IMASK_DUPLEX	0x1000
+#define MII_VSC8244_IMASK_MASK		0xf000
+
+#define MII_VSC8221_IMASK_MASK		0xa000
+
+/* Vitesse Interrupt Status Register */
+#define MII_VSC8244_ISTAT		0x1a
+#define MII_VSC8244_ISTAT_STATUS	0x8000
+#define MII_VSC8244_ISTAT_SPEED		0x4000
+#define MII_VSC8244_ISTAT_LINK		0x2000
+#define MII_VSC8244_ISTAT_DUPLEX	0x1000
+
+/* Vitesse Auxiliary Control/Status Register */
+#define MII_VSC8244_AUX_CONSTAT        	0x1c
+#define MII_VSC8244_AUXCONSTAT_INIT    	0x0000
+#define MII_VSC8244_AUXCONSTAT_DUPLEX  	0x0020
+#define MII_VSC8244_AUXCONSTAT_SPEED   	0x0018
+#define MII_VSC8244_AUXCONSTAT_GBIT    	0x0010
+#define MII_VSC8244_AUXCONSTAT_100     	0x0008
+
+#define MII_VSC8221_AUXCONSTAT_INIT	0x0004 /* need to set this bit? */
+#define MII_VSC8221_AUXCONSTAT_RESERVED	0x0004
+
+#define PHY_ID_VSC8244			0x000fc6c0
+#define PHY_ID_VSC8221			0x000fc550
+
+MODULE_DESCRIPTION("Vitesse PHY driver");
+MODULE_AUTHOR("Kriston Carson");
+MODULE_LICENSE("GPL");
+
+int vsc824x_add_skew(struct phy_device *phydev)
+{
+	int err;
+	int extcon;
+
+	extcon = phy_read(phydev, MII_VSC8244_EXT_CON1);
+
+	if (extcon < 0)
+		return extcon;
+
+	extcon &= ~(MII_VSC8244_EXTCON1_TX_SKEW_MASK |
+			MII_VSC8244_EXTCON1_RX_SKEW_MASK);
+
+	extcon |= (MII_VSC8244_EXTCON1_TX_SKEW |
+			MII_VSC8244_EXTCON1_RX_SKEW);
+
+	err = phy_write(phydev, MII_VSC8244_EXT_CON1, extcon);
+
+	return err;
+}
+EXPORT_SYMBOL(vsc824x_add_skew);
+
+static int vsc824x_config_init(struct phy_device *phydev)
+{
+	int err;
+
+	err = phy_write(phydev, MII_VSC8244_AUX_CONSTAT,
+			MII_VSC8244_AUXCONSTAT_INIT);
+	if (err < 0)
+		return err;
+
+	if (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID)
+		err = vsc824x_add_skew(phydev);
+
+	return err;
+}
+
+static int vsc824x_ack_interrupt(struct phy_device *phydev)
+{
+	int err = 0;
+	
+	/*
+	 * Don't bother to ACK the interrupts if interrupts
+	 * are disabled.  The 824x cannot clear the interrupts
+	 * if they are disabled.
+	 */
+	if (phydev->interrupts == PHY_INTERRUPT_ENABLED)
+		err = phy_read(phydev, MII_VSC8244_ISTAT);
+
+	return (err < 0) ? err : 0;
+}
+
+static int vsc82xx_config_intr(struct phy_device *phydev)
+{
+	int err;
+
+	if (phydev->interrupts == PHY_INTERRUPT_ENABLED)
+		err = phy_write(phydev, MII_VSC8244_IMASK,
+			phydev->drv->phy_id == PHY_ID_VSC8244 ?
+				MII_VSC8244_IMASK_MASK :
+				MII_VSC8221_IMASK_MASK);
+	else {
+		/*
+		 * The Vitesse PHY cannot clear the interrupt
+		 * once it has disabled them, so we clear them first
+		 */
+		err = phy_read(phydev, MII_VSC8244_ISTAT);
+
+		if (err < 0)
+			return err;
+
+		err = phy_write(phydev, MII_VSC8244_IMASK, 0);
+	}
+
+	return err;
+}
+
+/* Vitesse 824x */
+static struct phy_driver vsc8244_driver = {
+	.phy_id		= PHY_ID_VSC8244,
+	.name		= "Vitesse VSC8244",
+	.phy_id_mask	= 0x000fffc0,
+	.features	= PHY_GBIT_FEATURES,
+	.flags		= PHY_HAS_INTERRUPT,
+	.config_init	= &vsc824x_config_init,
+	.config_aneg	= &genphy_config_aneg,
+	.read_status	= &genphy_read_status,
+	.ack_interrupt	= &vsc824x_ack_interrupt,
+	.config_intr	= &vsc82xx_config_intr,
+	.driver 	= { .owner = THIS_MODULE,},
+};
+
+static int vsc8221_config_init(struct phy_device *phydev)
+{
+	int err;
+
+	err = phy_write(phydev, MII_VSC8244_AUX_CONSTAT,
+			MII_VSC8221_AUXCONSTAT_INIT);
+	return err;
+
+	/* Perhaps we should set EXT_CON1 based on the interface?
+	   Options are 802.3Z SerDes or SGMII */
+}
+
+/* Vitesse 8221 */
+static struct phy_driver vsc8221_driver = {
+	.phy_id		= PHY_ID_VSC8221,
+	.phy_id_mask	= 0x000ffff0,
+	.name		= "Vitesse VSC8221",
+	.features	= PHY_GBIT_FEATURES,
+	.flags		= PHY_HAS_INTERRUPT,
+	.config_init	= &vsc8221_config_init,
+	.config_aneg	= &genphy_config_aneg,
+	.read_status	= &genphy_read_status,
+	.ack_interrupt	= &vsc824x_ack_interrupt,
+	.config_intr	= &vsc82xx_config_intr,
+	.driver 	= { .owner = THIS_MODULE,},
+};
+
+static int __init vsc82xx_init(void)
+{
+	int err;
+
+	err = phy_driver_register(&vsc8244_driver);
+	if (err < 0)
+		return err;
+	err = phy_driver_register(&vsc8221_driver);
+	if (err < 0)
+		phy_driver_unregister(&vsc8244_driver);
+	return err;
+}
+
+static void __exit vsc82xx_exit(void)
+{
+	phy_driver_unregister(&vsc8244_driver);
+	phy_driver_unregister(&vsc8221_driver);
+}
+
+module_init(vsc82xx_init);
+module_exit(vsc82xx_exit);
+
+static struct mdio_device_id __maybe_unused vitesse_tbl[] = {
+	{ PHY_ID_VSC8244, 0x000fffc0 },
+	{ PHY_ID_VSC8221, 0x000ffff0 },
+	{ }
+};
+
+MODULE_DEVICE_TABLE(mdio, vitesse_tbl);