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, ®Val);
+ 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, ®Val);
+ 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, ®Val);
+ 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, ®Val);
+ pPortability->nway = regVal ? 1 : 0;
+ pPortability->forcemode = ~(pPortability->nway);
+
+ rtl8306e_regbit_get (6, 24, 12, 0, ®Val);
+ pPortability->symflc = regVal ? 0 : 1;
+
+ rtl8306e_regbit_get (6, 24, 13, 0, ®Val);
+ pPortability->rxpause = regVal ? 0 : 1;
+
+ rtl8306e_regbit_get (6, 24, 14, 0, ®Val);
+ pPortability->txpause = regVal ? 0 : 1;
+
+ rtl8306e_regbit_get (6, 22, 15, 0, ®Val);
+ pPortability->link= regVal ? 1 : 0;
+
+ rtl8306e_reg_get (6, 22, 0, ®Val);
+ 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, ®Val);
+
+ /*speed and duplex*/
+ rtl8306e_reg_get(5, 0, 0, ®Val);
+ 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, ®Val);
+ 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, ®Val);
+ 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, ®Val);
+ pPortability->nway = regVal ? 1 : 0;
+ pPortability->forcemode = regVal ? 0: 1;
+
+ /*get speed and duplex ability*/
+ rtl8306e_regbit_get (5, 0, 13, 0, ®Val);
+ if(regVal)
+ pPortability->speed =PORT_SPEED_100M;
+ else
+ pPortability->speed = PORT_SPEED_10M;
+
+ rtl8306e_regbit_get (5, 0, 8, 0, ®Val);
+ 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, ®Val);
+ 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, ®Val);
+ pPortability->link= regVal ? 1 : 0;
+ }
+ else if (RTL8306_PORT5 == port)
+ {
+ rtl8306e_regbit_set(0, 16, 11, 0, 1);
+ rtl8306e_reg_get(6, 26, 3, ®Val);
+ 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, ®Val);
+ 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, ®Val);
+ pPortability->nway = regVal ? 1 : 0;
+ pPortability->forcemode = regVal ? 0: 1;
+
+ rtl8306e_regbit_get (6, 24, 12, 0, ®Val);
+ pPortability->symflc = regVal ? 0 : 1;
+
+ rtl8306e_regbit_get (6, 24, 13, 0, ®Val);
+ pPortability->rxpause = regVal ? 0 : 1;
+
+ rtl8306e_regbit_get (6, 24, 14, 0, ®Val);
+ pPortability->txpause = regVal ? 0 : 1;
+
+ rtl8306e_regbit_get (6, 22, 15, 0, ®Val);
+ pPortability->link= regVal ? 1 : 0;
+
+ rtl8306e_reg_get (6, 22, 0, ®Val);
+ 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, ®val);
+ 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, ®val);
+ 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, ®Val);
+ 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, ®Val);
+ *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, ®Val);
+ *pMac_cnt = (regVal & 0x7FF) ;
+ }
+ else
+ {
+ rtl8306e_reg_get(port, 31, 1, ®Val);
+ *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, ®val);
+ 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, ®val);
+ 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, ®val);
+ 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, ®val);
+ 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, ®val);
+ 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, ®val);
+ 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, ®val);
+ 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, ®val);
+ *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, ®val);
+ 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, ®val);
+ *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, ®val);
+ 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, ®val);
+ 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, ®val);
+ rtl8306e_reg_get(4, 26, 0, ®val2);
+ 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, ®val3);
+ 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, ®val3);
+ regval3 &= ~0x3;
+ regval3 |= 0x2;
+ rtl8306e_reg_set(0, 31, 3, regval3);
+ rtl8306e_reg_get(1, 31, 3, ®val3);
+ regval3 &= ~0x3;
+ regval3 |= 0x2;
+ rtl8306e_reg_set(1, 31, 3, regval3);
+ rtl8306e_reg_get(2, 31, 3, ®val3);
+ regval3 &= ~0x3;
+ regval3 |= 0x2;
+ rtl8306e_reg_set(2, 31, 3, regval3);
+ rtl8306e_reg_get(3, 31, 3, ®val3);
+ regval3 &= ~0x3;
+ regval3 |= 0x2;
+ rtl8306e_reg_set(3, 31, 3, regval3);
+ rtl8306e_reg_get(5, 31, 3, ®val3);
+ 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, ®val3);
+ regval3 &= ~(0x7 << 4);
+ regval3 |= (0x6 << 4);
+ rtl8306e_phyReg_set(0, 25, 4, regval3);
+
+ rtl8306e_phyReg_get(0, 28, 4, ®val3);
+ 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, ®val3);
+ regval3 &= ~(0x1 << 8);
+ rtl8306e_phyReg_set(0, 28, 4, regval3);
+
+ rtl8306e_phyReg_get(0, 25, 4, ®val3);
+ 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, ®val3);
+ regval3 &= ~(0xFF);
+ regval3 |= 0xF3;
+ rtl8306e_phyReg_set(phy, 24, 4, regval3);
+ }
+
+ /*RTCT*/
+ for (phy = 0; phy <= 4; phy++)
+ {
+ rtl8306e_phyReg_get(phy, 16, 2, ®val3);
+ regval3 &= ~(0x3FF);
+ regval3 |= 0xFA;
+ rtl8306e_phyReg_set(phy, 16, 2, regval3);
+ rtl8306e_phyReg_get(phy, 22, 2, ®val3);
+ regval3 &= ~(0x7FF);
+ regval3 |= 0x12C;
+ rtl8306e_phyReg_set(phy, 22, 2, regval3);
+ rtl8306e_phyReg_get(phy, 23, 2, ®val3);
+ regval3 &= ~(0x3FF);
+ regval3 |= 0xC8;
+ rtl8306e_phyReg_set(phy, 23, 2, regval3);
+ rtl8306e_phyReg_get(phy, 24, 2, ®val3);
+ regval3 &= ~(0x1FF);
+ regval3 |= 0x32;
+ rtl8306e_phyReg_set(phy, 24, 2, regval3);
+ rtl8306e_phyReg_get(phy, 19, 2, ®val3);
+ regval3 &= ~(0xF << 12);
+ regval3 |= (0x4 << 12);
+ rtl8306e_phyReg_set(phy, 19, 2, regval3);
+ rtl8306e_phyReg_get(phy, 18, 2, ®val3);
+ regval3 &= ~(0x1F << 10);
+ regval3 |= (0x5 << 10);
+ rtl8306e_phyReg_set(phy, 18, 2, regval3);
+ rtl8306e_phyReg_get(phy, 25, 2, ®val3);
+ regval3 &= ~(0xFF << 8);
+ regval3 |= (0x4 << 8);
+ rtl8306e_phyReg_set(phy, 25, 2, regval3);
+ rtl8306e_phyReg_get(phy, 25, 2, ®val3);
+ 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, ®val);
+ rtl8306e_reg_get(4, 26, 0, ®val2);
+ 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, ®val);
+ if(regval)
+ {
+ *pMaxLen = RTL8306_MAX_PKT_LEN_2000;
+ }
+ else
+ {
+ rtl8306e_regbit_get(2, 23, 1, 3, ®val);
+ if (regval)
+ {
+ *pMaxLen = RTL8306_MAX_PKT_LEN_1518;
+ }
+ else
+ {
+ rtl8306e_regbit_get(0, 18, 14, 0, ®val);
+ 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, ®Data);
+ *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, ®Data);
+ 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, ®val);
+ 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, ®val);
+ *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, ®Value);
+ regValue = (regValue & 0xFFF) | (vlanIndex << 12);
+ rtl8306e_reg_set(port, 24, 0, regValue);
+ } else
+ {
+ rtl8306e_reg_get(0, 26, 1, ®Value);
+ 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, ®val);
+ 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, ®val);
+ regval &= ~(0x3 << 6);
+ regval |= (accept_frame_type << 6);
+ rtl8306e_reg_set(6, 30, 1, regval);
+ }
+ else
+ {
+ rtl8306e_reg_get(port, 21, 2, ®val);
+ 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, ®val);
+ regval &= (0x3 << 7);
+ *pAccept_frame_type = (rtl8306e_acceptFrameType_t)(regval >> 7);
+ }
+ else if (RTL8306_PORT5 == port)
+ {
+ rtl8306e_reg_get(6, 30, 1, ®val);
+ regval &= (0x3 << 6);
+ *pAccept_frame_type = (rtl8306e_acceptFrameType_t)(regval >> 6);
+ }
+ else
+ {
+ rtl8306e_reg_get(port, 21, 2, ®val);
+ 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, ®val);
+ regval &= ~(0x3F << 1);
+ regval |= (igPortMsk << 1);
+ rtl8306e_reg_set(0, 28, 3, regval);
+ }
+ else if(RTL8306_PORT5 == egPort)
+ {
+ rtl8306e_reg_get(6, 30, 1, ®val);
+ regval &= ~0x3F;
+ regval |= igPortMsk;
+ rtl8306e_reg_set(6, 30, 1, regval);
+ }
+ else
+ {
+ rtl8306e_reg_get(egPort, 30, 1, ®val);
+ 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, ®val);
+ if(!regval)
+ *pIgPortMsk = 0;
+
+ if(RTL8306_PORT0 == egPort)
+ {
+ rtl8306e_reg_get(0, 28, 3, ®val);
+ regval &= (0x3F << 1);
+ *pIgPortMsk = regval >> 1;
+ }
+ else if(RTL8306_PORT5 == egPort)
+ {
+ rtl8306e_reg_get(6, 30, 1, ®val);
+ regval &= 0x3F;
+ *pIgPortMsk = regval;
+ }
+ else
+ {
+ rtl8306e_reg_get(egPort, 30, 1, ®val);
+ 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, ®Value);
+ 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, ®Value);
+ *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, ®Value);
+ regValue = (regValue & 0xF000) | vid ;
+ rtl8306e_reg_set(0, 25, 0, regValue);
+ rtl8306e_reg_get(0, 24, 0, ®Value);
+ regValue = (regValue & 0xFFC0) | mbrmsk;
+ rtl8306e_reg_set(0, 24, 0, regValue);
+ rtl8306e_reg_get(0, 29, 0, ®Value);
+ regValue &= ~0x3F;
+ regValue |= untagmsk;
+ rtl8306e_reg_set(0, 29, 0, regValue);
+ break;
+
+ case 1: /* VLAN[B] */
+ rtl8306e_reg_get(1, 25, 0, ®Value);
+ regValue = (regValue & 0xF000) | vid ;
+ rtl8306e_reg_set(1, 25, 0, regValue);
+ rtl8306e_reg_get(1, 24, 0, ®Value);
+ regValue = (regValue & 0xFFC0) | mbrmsk;
+ rtl8306e_reg_set(1, 24, 0, regValue);
+ rtl8306e_reg_get(1, 30, 1, ®Value);
+ regValue &= ~0x3F;
+ regValue |= untagmsk;
+ rtl8306e_reg_set(1, 30, 1, regValue);
+ break;
+
+ case 2: /* VLAN[C] */
+ rtl8306e_reg_get(2, 25, 0, ®Value);
+ regValue = (regValue & 0xF000) | vid ;
+ rtl8306e_reg_set(2, 25, 0, regValue);
+ rtl8306e_reg_get(2, 24, 0, ®Value);
+ regValue = (regValue & 0xFFC0) | mbrmsk;
+ rtl8306e_reg_set(2, 24, 0, regValue);
+ rtl8306e_reg_get(2, 30, 1, ®Value);
+ regValue &= ~0x3F;
+ regValue |= untagmsk;
+ rtl8306e_reg_set(2, 30, 1, regValue);
+ break;
+
+ case 3: /* VLAN[D] */
+ rtl8306e_reg_get(3, 25, 0, ®Value);
+ regValue = (regValue & 0xF000) | vid;
+ rtl8306e_reg_set(3, 25, 0, regValue);
+ rtl8306e_reg_get(3, 24, 0, ®Value);
+ regValue = (regValue & 0xFFC0) | mbrmsk;
+ rtl8306e_reg_set(3, 24, 0, regValue);
+ rtl8306e_reg_get(3, 30, 1, ®Value);
+ regValue &= ~0x3F;
+ regValue |= untagmsk;
+ rtl8306e_reg_set(3, 30, 1, regValue);
+ break;
+
+ case 4: /* VLAN[E] */
+ rtl8306e_reg_get(4, 25, 0, ®Value);
+ regValue = (regValue & 0xF000) | vid;
+ rtl8306e_reg_set(4, 25, 0, regValue);
+ rtl8306e_reg_get(4, 24, 0, ®Value);
+ regValue = (regValue & 0xFFC0) | mbrmsk;
+ rtl8306e_reg_set(4, 24, 0, regValue);
+ rtl8306e_reg_get(4, 30, 1, ®Value);
+ regValue &= ~0x3F;
+ regValue |= untagmsk;
+ rtl8306e_reg_set(4, 30, 1, regValue);
+ break;
+
+ case 5: /* VLAN[F] */
+ rtl8306e_reg_get(0, 27, 1, ®Value);
+ regValue = (regValue & 0xF000) | vid;
+ rtl8306e_reg_set(0, 27, 1, regValue);
+ rtl8306e_reg_get(0, 26, 1, ®Value);
+ regValue = (regValue & 0xFFC0) | mbrmsk;
+ rtl8306e_reg_set(0, 26, 1, regValue);
+ rtl8306e_reg_get(0, 26, 1, ®Value);
+ regValue &= ~(0x3F << 6);
+ regValue |= (untagmsk << 6);
+ rtl8306e_reg_set(0, 26, 1, regValue);
+ break;
+
+ case 6: /* VLAN[G] */
+ rtl8306e_reg_get(1, 27, 1, ®Value);
+ regValue = (regValue & 0xF000) | vid;
+ rtl8306e_reg_set(1, 27, 1, regValue);
+ rtl8306e_reg_get(1, 26, 1, ®Value);
+ regValue = (regValue & 0xFFC0) | mbrmsk;
+ rtl8306e_reg_set(1, 26, 1, regValue);
+ rtl8306e_reg_get(1, 26, 1, ®Value);
+ regValue &= ~(0x3F << 6);
+ regValue |= (untagmsk << 6);
+ rtl8306e_reg_set(1, 26, 1, regValue);
+ break;
+
+ case 7: /* VLAN[H] */
+ rtl8306e_reg_get(2, 27, 1, ®Value);
+ regValue = (regValue & 0xF000) | vid;
+ rtl8306e_reg_set(2, 27, 1, regValue);
+ rtl8306e_reg_get(2, 26, 1, ®Value);
+ regValue = (regValue & 0xFFC0) | mbrmsk;
+ rtl8306e_reg_set(2, 26, 1, regValue);
+ rtl8306e_reg_get(2, 26, 1, ®Value);
+ regValue &= ~(0x3F << 6);
+ regValue |= (untagmsk << 6);
+ rtl8306e_reg_set(2, 26, 1, regValue);
+ break;
+
+ case 8: /* VLAN[I] */
+ rtl8306e_reg_get(3, 27, 1, ®Value);
+ regValue = (regValue & 0xF000) | vid;
+ rtl8306e_reg_set(3, 27, 1, regValue);
+ rtl8306e_reg_get(3, 26, 1, ®Value);
+ regValue = (regValue & 0xFFC0) | mbrmsk;
+ rtl8306e_reg_set(3, 26, 1, regValue);
+ rtl8306e_reg_get(3, 26, 1, ®Value);
+ regValue &= ~(0x3F << 6);
+ regValue |= (untagmsk << 6);
+ rtl8306e_reg_set(3, 26, 1, regValue);
+
+ break;
+
+ case 9: /* VLAN[J] */
+ rtl8306e_reg_get(4, 27, 1, ®Value);
+ regValue = (regValue & 0xF000) | vid;
+ rtl8306e_reg_set(4, 27, 1, regValue);
+ rtl8306e_reg_get(4, 26, 1, ®Value);
+ regValue = (regValue & 0xFFC0) | mbrmsk;
+ rtl8306e_reg_set(4, 26, 1, regValue);
+ rtl8306e_reg_get(4, 26, 1, ®Value);
+ regValue &= ~(0x3F << 6);
+ regValue |= (untagmsk << 6);
+ rtl8306e_reg_set(4, 26, 1, regValue);
+ break;
+
+ case 10: /* VLAN[K] */
+ rtl8306e_reg_get(0, 29, 1, ®Value);
+ regValue = (regValue & 0xF000) | vid;
+ rtl8306e_reg_set(0, 29, 1, regValue);
+ rtl8306e_reg_get(0, 28, 1, ®Value);
+ regValue = (regValue & 0xFFC0) | mbrmsk;
+ rtl8306e_reg_set(0, 28, 1, regValue);
+ rtl8306e_reg_get(0, 28, 1, ®Value);
+ regValue &= ~(0x3F << 6);
+ regValue |= (untagmsk << 6);
+ rtl8306e_reg_set(0, 28, 1, regValue);
+ break;
+
+ case 11: /* VLAN[L] */
+ rtl8306e_reg_get(1, 29, 1, ®Value);
+ regValue = (regValue & 0xF000) | vid;
+ rtl8306e_reg_set(1, 29, 1, regValue);
+ rtl8306e_reg_get(1, 28, 1, ®Value);
+ regValue = (regValue & 0xFFC0) | mbrmsk;
+ rtl8306e_reg_set(1, 28, 1, regValue);
+ rtl8306e_reg_get(1, 28, 1, ®Value);
+ regValue &= ~(0x3F << 6);
+ regValue |= (untagmsk << 6);
+ rtl8306e_reg_set(1, 28, 1, regValue);
+ break;
+
+ case 12: /* VLAN[M] */
+ rtl8306e_reg_get(2, 29, 1, ®Value);
+ regValue = (regValue & 0xF000) | vid;
+ rtl8306e_reg_set(2, 29, 1, regValue);
+ rtl8306e_reg_get(2, 28, 1, ®Value);
+ regValue = (regValue & 0xFFC0) | mbrmsk;
+ rtl8306e_reg_set(2, 28, 1, regValue);
+ rtl8306e_reg_get(2, 28, 1, ®Value);
+ regValue &= ~(0x3F << 6);
+ regValue |= (untagmsk << 6);
+ rtl8306e_reg_set(2, 28, 1, regValue);
+ break;
+
+ case 13: /* VLAN[N] */
+ rtl8306e_reg_get(3, 29, 1, ®Value);
+ regValue = (regValue & 0xF000) | vid;
+ rtl8306e_reg_set(3, 29, 1, regValue);
+ rtl8306e_reg_get(3, 28, 1, ®Value);
+ regValue = (regValue & 0xFFC0) |mbrmsk;
+ rtl8306e_reg_set(3, 28, 1, regValue);
+ rtl8306e_reg_get(3, 28, 1, ®Value);
+ regValue &= ~(0x3F << 6);
+ regValue |= (untagmsk << 6);
+ rtl8306e_reg_set(3, 28, 1, regValue);
+ break;
+
+ case 14: /* VLAN[O] */
+ rtl8306e_reg_get(4, 29, 1, ®Value);
+ regValue = (regValue & 0xF000) | vid;
+ rtl8306e_reg_set(4, 29, 1, regValue);
+ rtl8306e_reg_get(4, 28, 1, ®Value);
+ regValue = (regValue & 0xFFC0) | mbrmsk;
+ rtl8306e_reg_set(4, 28, 1, regValue);
+ rtl8306e_reg_get(4, 28, 1, ®Value);
+ regValue &= ~(0x3F << 6);
+ regValue |= (untagmsk << 6);
+ rtl8306e_reg_set(4, 28, 1, regValue);
+ break;
+
+ case 15: /* VLAN[P] */
+ rtl8306e_reg_get(0, 31, 1, ®Value);
+ regValue = (regValue & 0xF000) | vid;
+ rtl8306e_reg_set(0, 31, 1, regValue);
+ rtl8306e_reg_get(0, 30, 1, ®Value);
+ regValue = (regValue & 0xFFC0) | mbrmsk;
+ rtl8306e_reg_set(0, 30, 1, regValue);
+ rtl8306e_reg_get(0, 30, 1, ®Value);
+ 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, ®val);
+ 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, ®val);
+ 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, ®val);
+ 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, ®val);
+ 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, ®val);
+ 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, ®val);
+ 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, ®val);
+ 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, ®val);
+ 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, ®val);
+ 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, ®val);
+ 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, ®val);
+ 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, ®val);
+ 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, ®val);
+ 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, ®val);
+ 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, ®val);
+ 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, ®val);
+ 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, ®val);
+ 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, ®val);
+ regval &= (0x3 << 6);
+ *pPri = regval >> 6;
+ break;
+
+ case 1: /*VLAN[B]*/
+ rtl8306e_reg_get(1, 30, 1, ®val);
+ regval &= (0x3 << 6);
+ *pPri = regval >> 6;
+ break;
+
+ case 2: /*VLAN[C]*/
+ rtl8306e_reg_get(2, 30, 1, ®val);
+ regval &= (0x3 << 6);
+ *pPri = regval >> 6;
+ break;
+
+ case 3: /*VLAN[D]*/
+ rtl8306e_reg_get(3, 30, 1, ®val);
+ regval &= (0x3 << 6);
+ *pPri = regval >> 6;
+ break;
+
+ case 4: /*VLAN[E]*/
+ rtl8306e_reg_get(4, 30, 1, ®val);
+ regval &= (0x3 << 6);
+ *pPri = regval >> 6;
+ break;
+
+ case 5: /*VLAN[F]*/
+ rtl8306e_reg_get(0, 27, 1, ®val);
+ regval &= (0x3 << 12);
+ *pPri = regval >> 12;
+ break;
+
+ case 6: /*VLAN[G]*/
+ rtl8306e_reg_get(1, 26, 1, ®val);
+ regval &= (0x3 << 12);
+ *pPri = regval >> 12;
+ break;
+
+ case 7: /*VLAN[H]*/
+ rtl8306e_reg_get(2, 26, 1, ®val);
+ regval &= (0x3 << 12);
+ *pPri = regval >> 12;
+ break;
+
+ case 8: /*VLAN[I]*/
+ rtl8306e_reg_get(3, 26, 1, ®val);
+ regval &= (0x3 << 12);
+ *pPri = regval >> 12;
+ break;
+
+ case 9: /*VLAN[J]*/
+ rtl8306e_reg_get(4, 26, 1, ®val);
+ regval &= (0x3 << 12);
+ *pPri = regval >> 12;
+ break;
+
+ case 10: /*VLAN[K]*/
+ rtl8306e_reg_get(0, 28, 1, ®val);
+ regval &= (0x3 << 12);
+ *pPri = regval >> 12;
+ break;
+
+ case 11: /*VLAN[L]*/
+ rtl8306e_reg_get(1, 28, 1, ®val);
+ regval &= (0x3 << 12);
+ *pPri = regval >> 12;
+ break;
+
+ case 12: /*VLAN[M]*/
+ rtl8306e_reg_get(2, 28, 1, ®val);
+ regval &= (0x3 << 12);
+ *pPri = regval >> 12;
+ break;
+
+ case 13: /*VLAN[N]*/
+ rtl8306e_reg_get(3, 28, 1, ®val);
+ regval &= (0x3 << 12);
+ *pPri = regval >> 12;
+ break;
+
+ case 14: /*VLAN[O]*/
+ rtl8306e_reg_get(4, 28, 1, ®val);
+ regval &= (0x3 << 12);
+ *pPri = regval >> 12;
+ break;
+
+ case 15: /*VLAN[P]*/
+ rtl8306e_reg_get(0, 30, 1, ®val);
+ regval &= (0x3 << 12);
+ *pPri = regval >> 12;
+ break;
+
+ default: /*unmatched vlan entry*/
+ rtl8306e_reg_get(0, 29, 0, ®val);
+ 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, ®val);
+
+ 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, ®val);
+ 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, ®val);
+ regval &= ~0xfff;
+ regval |= transVid;
+ rtl8306e_reg_set(6, 17 + vlanIndex, 4, regval);
+ }
+ else
+ {
+ rtl8306e_reg_get(6, 18, 1, ®val);
+ 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, ®val);
+ *pTransVid = (regval & 0xfff);
+ }
+ else
+ {
+ rtl8306e_reg_get(6, 18, 1, ®val);
+ *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, ®val);
+ *pEnable = regval ? 1:0;
+ }
+ else
+ {
+ rtl8306e_reg_get(6, 17 + port, 0, ®val);
+ *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, ®val);
+ 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, ®val);
+ 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, ®val);
+ *pOvidsrc = (regval & (1 << 3)) ? 1:0;
+ *pOpriSrc = (regval & (1 << 2)) ? 1:0;
+ }
+ else
+ {
+ rtl8306e_reg_get(6, 17 + port, 0, ®val);
+ *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, ®Value);
+ 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, ®Value);
+ 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, ®Value);
+ *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, ®Value);
+ 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, ®Value);
+ *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, ®Value);
+ 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, ®Value);
+
+ 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, ®Value);
+ 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, ®Value);
+ 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, ®Value);
+ *pEnabled = (regValue ? FALSE:TRUE);
+ rtl8306e_reg_get(port, 21, 2, ®Value);
+ *pN64Kbps = regValue & 0x7FF;
+ }
+ else
+ {
+ /*Get port Tx rate*/
+ rtl8306e_regbit_get(port, 18, 15, 2, pEnabled);
+ rtl8306e_reg_get(port, 18, 2, ®Value);
+ *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, ®Value);
+ 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, ®Value);
+ 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, ®Value);
+ 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, ®Value);
+ else
+ rtl8306e_reg_get(6, 17, 2, ®Value);
+
+ *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, ®Value);
+ 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, ®Value);
+ 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, ®Value1);
+ rtl8306e_reg_get(1, 24, 3, ®Value2);
+ 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, ®Value1);
+ rtl8306e_reg_get(1, 24, 3, ®Value2);
+ 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, ®val);
+ 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, ®val);
+ 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, ®val);
+ regval |= (1 << (priArbit.acl_pri_lev -1 + 12));
+ rtl8306e_reg_set(1, 21, 3, regval);
+ }
+
+ /*dscp based priority*/
+ rtl8306e_reg_get(1, 21, 3, ®val);
+ 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, ®val);
+ regval |= (1 << (priArbit.dscp_pri_lev -1 + 8));
+ rtl8306e_reg_set(1, 21, 3, regval);
+ }
+
+ /*1Q based priority*/
+ rtl8306e_reg_get(1, 21, 3, ®val);
+ 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, ®val);
+ regval |= ( 1 << (priArbit.dot1q_pri_lev -1 + 4));
+ rtl8306e_reg_set(1, 21, 3, regval);
+ }
+
+ /*port based priority*/
+ rtl8306e_reg_get(1, 21, 3, ®val);
+ 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, ®val);
+ 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, ®val);
+ 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, ®val);
+ if(regval)
+ {
+ pPriArbit->acl_pri_lev = 5;
+ }
+ else
+ {
+ rtl8306e_reg_get(1, 21, 3, ®val);
+ 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, ®val);
+ if (regval)
+ {
+ pPriArbit ->dscp_pri_lev = 5;
+ }
+ else
+ {
+ rtl8306e_reg_get(1, 21, 3, ®val);
+ 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, ®val);
+ if (regval)
+ {
+ pPriArbit ->dot1q_pri_lev = 5;
+ }
+ else
+ {
+ rtl8306e_reg_get(1, 21, 3, ®val);
+ 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, ®val);
+ if (regval)
+ {
+ pPriArbit ->port_pri_lev = 5;
+ }
+ else
+ {
+ rtl8306e_reg_get(1, 21, 3, ®val);
+ 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, ®Value);
+ 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, ®Value);
+ *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, ®Value);
+ 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, ®Value);
+ regValue &= ~0x7FF;
+ regValue |= sch_para.q2_n64Kbps;
+ rtl8306e_reg_set(5, 18, 3, regValue);
+
+ rtl8306e_reg_get(5, 19, 3, ®Value);
+ 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, ®Value);
+ 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, ®Value);
+ regValue &= ~0x7FF;
+ regValue |= sch_para.q2_n64Kbps;
+ rtl8306e_reg_set(5, 23, 3, regValue);
+
+ rtl8306e_reg_get(5, 24, 3, ®Value);
+ 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, ®Value);
+ pSch_para->q0_wt = regValue & 0x7F;
+ pSch_para->q1_wt = (regValue & (0x7F << 8)) >> 8;
+
+ rtl8306e_reg_get(5, 21, 3, ®Value);
+ 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, ®Value);
+ pSch_para->q2_n64Kbps = regValue & 0x7FF;
+ rtl8306e_reg_get(5, 19, 3, ®Value);
+ pSch_para->q3_n64Kbps = regValue & 0x7FF;
+
+ break;
+
+ case RTL8306_QOS_SET1:
+ rtl8306e_reg_get(5, 25, 3, ®Value);
+ pSch_para->q0_wt = regValue & 0x7F;
+ pSch_para->q1_wt = (regValue & (0x7F << 8)) >> 8;
+
+ rtl8306e_reg_get(5, 26, 3, ®Value);
+ 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, ®Value);
+ pSch_para->q2_n64Kbps = regValue & 0x7FF;
+ rtl8306e_reg_get(5, 24, 3, ®Value);
+ 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, ®Value);
+ 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, ®Value );
+ *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, ®Value);
+ 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, ®Value);
+ regValue &= 0xfff8;
+ regValue |= (value & 0x70) >> 4;
+ rtl8306e_reg_set(1, 26, 3, regValue);
+ }
+ else if (RTL8306_QUEUE1 == queue)
+ {
+ rtl8306e_reg_get(1, 26, 3, ®Value);
+ 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, ®Value);
+ regValue &= 0x8fff;
+ regValue |= ((value & 0x70) >> 4) << 12;
+ rtl8306e_reg_set(1, 26, 3, regValue);
+ }
+ else
+ {
+ rtl8306e_reg_get(1, 27, 3, ®Value);
+ 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, ®Value);
+ 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, ®Value);
+ 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, ®Value);
+ 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, ®Value);
+ regValue &= 0x7fff;
+ regValue |= (((value & 0x10) >> 4) << 15);
+ rtl8306e_reg_set(1, 26, 3, regValue);
+
+ /*bit[6:5]*/
+ rtl8306e_reg_get(1, 27, 3, ®Value);
+ regValue &= 0xfffc;
+ regValue |= ((value & 0x60) >> 5) ;
+ rtl8306e_reg_set(1, 27, 3, regValue);
+ }
+ else
+ {
+ rtl8306e_reg_get(1, 27, 3, ®Value);
+ 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, ®Value);
+ 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, ®Value);
+ regValue = (regValue & 0xC0FF) | ((value & 0x3f) << 8);
+ rtl8306e_reg_set(5, reg, 2, regValue);
+ }
+ else
+ {
+ rtl8306e_reg_get(5, reg, 2, ®Value);
+ 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, ®Value);
+ 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, ®Value);
+ 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, ®Value);
+ 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, ®Value);
+ regValue &= 0xff8f;
+ regValue |= ((value & 0x70) >> 4) << 4;
+ rtl8306e_reg_set(1, 28, 3, regValue);
+ }
+ else
+ {
+ rtl8306e_reg_get(1, 28, 3, ®Value);
+ 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, ®Value);
+ 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, ®Value);
+ 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, ®Value);
+ 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, ®Value);
+ regValue &= 0xfc7f;
+ regValue |= ((value & 0x70) >> 4) << 7;
+ rtl8306e_reg_set(1, 28, 3, regValue);
+ }
+ else
+ {
+ rtl8306e_reg_get(1, 28, 3, ®Value);
+ 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, ®Value);
+ 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, ®Value);
+ regValue = (regValue & 0xC0FF) | ((value & 0x3f) << 8);
+ rtl8306e_reg_set(5, reg, 2, regValue);
+ }
+ else
+ {
+ rtl8306e_reg_get(5, reg, 2, ®Value);
+ 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, ®Value);
+ *pValue = (regValue & mask) >> shift;
+
+ if (RTL8306_QUEUE0 == queue)
+ {
+ rtl8306e_reg_get(1, 26, 3, ®Value);
+ regValue &= 0x7;
+ *pValue |= (regValue << 4);
+ }
+ else if (RTL8306_QUEUE1 == queue)
+ {
+ rtl8306e_reg_get(1, 26, 3, ®Value);
+ regValue &= 0x1c0;
+ regValue = regValue >> 6;
+ *pValue |= (regValue << 4);
+ }
+ else if (RTL8306_QUEUE2 == queue)
+ {
+ rtl8306e_reg_get(1, 26, 3, ®Value);
+ regValue &= 0x7000;
+ regValue = regValue >> 12;
+ *pValue |= (regValue << 4);
+ }
+ else
+ {
+ rtl8306e_reg_get(1, 27, 3, ®Value);
+ 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, ®Value);
+ *pValue = (regValue & mask) >> shift;
+
+ if (RTL8306_QUEUE0 == queue)
+ {
+ rtl8306e_reg_get(1, 26, 3, ®Value);
+ regValue &= 0x38;
+ regValue = regValue >> 3;
+ *pValue |= (regValue << 4);
+ }
+ else if (RTL8306_QUEUE1 == queue)
+ {
+ rtl8306e_reg_get(1, 26, 3, ®Value);
+ regValue &= 0xe00;
+ regValue = regValue >> 9;
+ *pValue |= (regValue << 4);
+ }
+ else if (RTL8306_QUEUE2 == queue)
+ {
+ rtl8306e_reg_get(1, 26, 3, ®Value);
+ regValue &= 0x8000;
+ regValue = regValue >> 15;
+ *pValue |= (regValue << 4);
+
+ rtl8306e_reg_get(1, 27, 3, ®Value);
+ regValue &= 0x3;
+ *pValue |= (regValue << 5);
+ }
+ else
+ {
+ rtl8306e_reg_get(1, 27, 3, ®Value);
+ 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, ®Value);
+ *pValue = regValue & 0x3F;
+
+ if (RTL8306_QUEUE0 == queue)
+ {
+ rtl8306e_regbit_get(5, 21, 7, 2, ®Value);
+ *pValue |= (regValue << 6);
+ }
+ else if (RTL8306_QUEUE1 == queue)
+ {
+ rtl8306e_regbit_get(5, 21, 15, 2, ®Value);
+ *pValue |= (regValue << 6);
+ }
+ else if (RTL8306_QUEUE2 == queue)
+ {
+ rtl8306e_regbit_get(5, 24, 7, 2, ®Value);
+ *pValue |= (regValue << 6);
+ }
+ else
+ {
+ rtl8306e_regbit_get(5, 24, 15, 2, ®Value);
+ *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, ®Value);
+ *pValue = (regValue & 0x3F00) >> 8 ;
+ } else
+ {
+ rtl8306e_reg_get(5, reg, 2, ®Value);
+ *pValue = (regValue & 0xFC00) >> 10;
+ }
+
+ if (RTL8306_QUEUE0 == queue)
+ {
+ rtl8306e_regbit_get(5, 21, 6, 2, ®Value);
+ *pValue |= (regValue << 6);
+ }
+ else if (RTL8306_QUEUE1 == queue)
+ {
+ rtl8306e_regbit_get(5, 21, 14, 2, ®Value);
+ *pValue |= (regValue << 6);
+ }
+ else if (RTL8306_QUEUE2 == queue)
+ {
+ rtl8306e_regbit_get(5, 24, 6, 2, ®Value);
+ *pValue |= (regValue << 6);
+ }
+ else
+ {
+ rtl8306e_regbit_get(5, 24, 14, 2, ®Value);
+ *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, ®Value);
+ *pValue = (regValue & mask) >> shift;
+
+ if (RTL8306_QUEUE0 == queue)
+ {
+ rtl8306e_reg_get(1, 27, 3, ®Value);
+ regValue &= 0x700;
+ regValue = regValue >> 8;
+ *pValue |= (regValue << 4);
+ }
+ else if (RTL8306_QUEUE1 == queue)
+ {
+ rtl8306e_reg_get(1, 27, 3, ®Value);
+ regValue &= 0xc000;
+ regValue = regValue >> 14;
+ *pValue |= (regValue << 4);
+ rtl8306e_regbit_get(1, 28, 0, 3, ®Value);
+ *pValue |= (regValue << 6);
+ }
+ else if (RTL8306_QUEUE2 == queue)
+ {
+ rtl8306e_reg_get(1, 28, 3, ®Value);
+ regValue &= 0x70;
+ regValue = regValue >> 4;
+ *pValue |= (regValue << 4);
+ } else
+ {
+ rtl8306e_reg_get(1, 28, 3, ®Value);
+ 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, ®Value);
+ *pValue = (regValue & mask) >> shift;
+
+ if (RTL8306_QUEUE0 == queue)
+ {
+ rtl8306e_reg_get(1, 27, 3, ®Value);
+ regValue &= 0x3800;
+ regValue = regValue >> 11;
+ *pValue |= (regValue << 4);
+ }
+ else if (RTL8306_QUEUE1 == queue)
+ {
+ rtl8306e_reg_get(1, 28, 3, ®Value);
+ regValue &= 0xe;
+ regValue = regValue >> 1;
+ *pValue |= (regValue << 4);
+ }
+ else if (RTL8306_QUEUE2 == queue)
+ {
+ rtl8306e_reg_get(1, 28, 3, ®Value);
+ regValue &= 0x380;
+ regValue = regValue >> 7;
+ *pValue |= (regValue << 4);
+ }
+ else
+ {
+ rtl8306e_reg_get(1, 28, 3, ®Value);
+ 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, ®Value);
+ *pValue = (regValue & 0x3F) >> shift;
+
+ /*bit 6*/
+ if (RTL8306_QUEUE0 == queue)
+ {
+ rtl8306e_regbit_get(5, 25, 7, 2, ®Value);
+ *pValue |= (regValue << 6);
+ }
+ else if (RTL8306_QUEUE1 == queue)
+ {
+ rtl8306e_regbit_get(5, 25, 15, 2, ®Value);
+ *pValue |= (regValue << 6);
+ }
+ else if (RTL8306_QUEUE2 == queue)
+ {
+ rtl8306e_regbit_get(5, 27, 7, 2, ®Value);
+ *pValue |= (regValue << 6);
+ }
+ else
+ {
+ rtl8306e_regbit_get(5, 27, 15, 2, ®Value);
+ *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, ®Value);
+ *pValue = (regValue & 0x3F00) >> 8 ;
+ }
+ else
+ {
+ rtl8306e_reg_get(5, reg, 2, ®Value);
+ *pValue = (regValue & 0xFC00) >> 10;
+ }
+ /*bit 6*/
+ if (RTL8306_QUEUE0 == queue)
+ {
+ rtl8306e_regbit_get(5, 25, 6, 2, ®Value);
+ *pValue |= (regValue << 6);
+ }
+ else if (RTL8306_QUEUE1 == queue)
+ {
+ rtl8306e_regbit_get(5, 25, 14, 2, ®Value);
+ *pValue |= (regValue << 6);
+ }
+ else if (RTL8306_QUEUE2 == queue)
+ {
+ rtl8306e_regbit_get(5, 27, 6, 2, ®Value);
+ *pValue |= (regValue << 6);
+ }
+ else
+ {
+ rtl8306e_regbit_get(5, 27, 14, 2, ®Value);
+ *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, ®Value);
+ else
+ rtl8306e_reg_get(port, 19, 3, ®Value);
+ *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, ®Value);
+ 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, ®Value);
+ 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, ®Value);
+ 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, ®Value);
+ *pData = regValue;
+ rtl8306e_reg_get(3, 22, 3, ®Value);
+ *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, ®Value1);
+ rtl8306e_reg_get(port, 23, 2, ®Value2);
+ *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, ®Value1);
+ rtl8306e_reg_get(port, 25, 2, ®Value2);
+ *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, ®Value1);
+ rtl8306e_reg_get(port, 27, 2, ®Value2);
+ *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, ®Value1);
+ rtl8306e_reg_get(port, 29, 2, ®Value2);
+ *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, ®Value1);
+ rtl8306e_reg_get(port, 31, 2, ®Value2);
+ *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, ®Value);
+ 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, ®Value);
+ regValue = (regValue & 0xFFC0) | rxmbr ;
+ rtl8306e_reg_set(6, 21, 3, regValue);
+
+ /*Set Ports Whose TX Data are Mirrored */
+ rtl8306e_reg_get(6, 21, 3, ®Value);
+ 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, ®Value);
+ *pMirport = (regValue & 0x3800) >> 11;
+
+ /*Get Ports Whose RX Data are Mirrored*/
+ rtl8306e_reg_get(6, 21, 3, ®Value);
+ *pRxmbr = regValue & 0x3F;
+
+ /*Get Ports Whose TX Data are Mirrored */
+ rtl8306e_reg_get(6, 21, 3, ®Value);
+ *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, ®Value);
+ macAddr[0] = regValue & 0xFF;
+ macAddr[1] = (regValue & 0xFF00) >> 8;
+ rtl8306e_reg_get(6, 23, 3, ®Value);
+ macAddr[2] = regValue & 0xFF;
+ macAddr[3] = (regValue & 0xFF00) >> 8;
+ rtl8306e_reg_get(6, 24, 3, ®Value);
+ 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, ®Value);
+ macAddr[5] = (regValue & 0x300) >> 8;
+ macAddr[4] = regValue & 0xF8;
+
+ /*Read Data[31:16]*/
+ rtl8306e_reg_get(4, 19, 0, ®Value);
+ macAddr[3] = (regValue & 0xFF00) >> 8;
+ macAddr[2] = regValue & 0xFF;
+
+ /*Read Data[15:0]*/
+ rtl8306e_reg_get(4, 20, 0, ®Value);
+ 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, ®Value);
+ macAddr[5] = ((regValue & 0x300) >> 8) | (*pIndex & 0xFC);
+ macAddr[4] = (regValue & 0xF8) | ((*pIndex >> 8) & 0x7);
+
+ /*Read Data[31:16]*/
+ rtl8306e_reg_get(4, 19, 0, ®Value);
+ macAddr[3] = (regValue & 0xFF00) >> 8;
+ macAddr[2] = regValue & 0xFF;
+
+ /*Read Data[15:0]*/
+ rtl8306e_reg_get(4, 20, 0, ®Value);
+ 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, ®Value);
+ *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, ®Value);
+ *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, ®Value);
+ 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, ®Value);
+ 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, ®Value);
+ *pMacCnt = (regValue & (0x1F << 11)) >> 11;
+ }
+ else
+ {
+ rtl8306e_regbit_get(port, 30, 15, 1, &bitValue);
+ *pEnabled = bitValue ? TRUE : FALSE;
+ rtl8306e_reg_get(port, 31, 1, ®Value);
+ *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, ®Value);
+ regValue &= ~(0x7F);
+ regValue |= (macCnt & 0x7F) ;
+ rtl8306e_reg_set(0, 31, 0, regValue);
+
+ rtl8306e_reg_get(0, 31, 0, ®Value);
+ 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, ®Value);
+ *pMacCnt = (regValue & 0x7F);
+
+ rtl8306e_reg_get(0, 31, 0, ®Value);
+ *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, ®Value);
+ 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, ®Value);
+ *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, ®val);
+ *pAction = regval ? RTL8306_ACT_TRAPCPU : RTL8306_ACT_PERMIT;
+ break;
+ case RTL8306_MLD:
+ rtl8306e_regbit_get(2, 21, 13, 3, ®val);
+ *pAction = regval ? RTL8306_ACT_TRAPCPU : RTL8306_ACT_PERMIT;
+ break;
+ case RTL8306_PPPOE_IGMPMLD:
+ rtl8306e_regbit_get(2, 22, 4, 3, ®val);
+ *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, ®val);
+ *pAction = regval ? RTL8306_ACT_DROP: RTL8306_ACT_PERMIT;
+ break;
+ case RTL8306_IPV6_MULTICAST:
+ rtl8306e_regbit_get(4, 21, 8, 0, ®val);
+ *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, ®val);
+ *pAction = regval ? RTL8306_ACT_DROP: RTL8306_ACT_TRAPCPU;
+ break;
+ case RTL8306_DOT1XUNAUTH:
+ rtl8306e_regbit_get(2, 22, 5, 3, ®val);
+ *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, ®Value);
+ 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, ®Value);
+ *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, ®Value);
+ *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, ®val);
+ 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, ®val);
+ 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, ®val);
+ 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, ®val);
+ *pTrigNum = ((regval >> 8) & 0x3) ? RTL8306_STM_FILNUM256 : RTL8306_STM_FILNUM128;
+ *pFilTime = (regval >> 5) & 0x3;
+ }
+ else
+ {
+ rtl8306e_reg_get(6, 25, 0, ®val);
+ *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);