hi, all:
we will try to add one feature for AR8337 switch: port ingress rate limit.
we can use swconfig extension command to implement it as below example:
swconfig dev eth0 set extension_switch "port_rate_limit set port 1 rate
100000"
Note: in this example, 100000 means 100000Kbps.
1. We use one special communication command in swconfig "extension_switch"
to transfer the extension command for AR8337 switch enhanced feature.


Signed-off-by: Yue Lun <[email protected]>

---
 .../linux/generic/files/drivers/net/phy/ar8216.c   |  10 +
 .../generic/files/drivers/net/phy/ar8216_ext.c     | 792
+++++++++++++++++++++
 .../generic/files/drivers/net/phy/ar8216_ext.h     | 269 +++++++
 .../generic/patches-3.10/724-phy_ar8216.patch      |   2 +-
 .../generic/patches-3.10/725-phy_rtl8306.patch     |   2 +-
 .../generic/patches-3.10/726-phy_rtl8366.patch     |   2 +-
 .../generic/patches-3.14/724-phy_ar8216.patch      |   2 +-
 7 files changed, 1075 insertions(+), 4 deletions(-)
 mode change 100644 => 100755
target/linux/generic/files/drivers/net/phy/ar8216.c
 create mode 100755 target/linux/generic/files/drivers/net/phy/ar8216_ext.c
 create mode 100755 target/linux/generic/files/drivers/net/phy/ar8216_ext.h
 mode change 100644 => 100755
target/linux/generic/patches-3.10/724-phy_ar8216.patch
 mode change 100644 => 100755
target/linux/generic/patches-3.10/725-phy_rtl8306.patch
 mode change 100644 => 100755
target/linux/generic/patches-3.10/726-phy_rtl8366.patch
 mode change 100644 => 100755
target/linux/generic/patches-3.14/724-phy_ar8216.patch

diff --git a/target/linux/generic/files/drivers/net/phy/ar8216.c
b/target/linux/generic/files/drivers/net/phy/ar8216.c
old mode 100644
new mode 100755
index 3f60878..bf5a078
--- a/target/linux/generic/files/drivers/net/phy/ar8216.c
+++ b/target/linux/generic/files/drivers/net/phy/ar8216.c
@@ -38,6 +38,7 @@
 #include <linux/gpio.h>

 #include "ar8216.h"
+#include "ar8216_ext.h"

 /* size of the vlan table */
 #define AR8X16_MAX_VLANS       128
@@ -2389,6 +2390,12 @@ static struct switch_attr ar8327_sw_attr_globals[] = {
                .get = ar8xxx_sw_get_mirror_source_port,
                .max = AR8327_NUM_PORTS - 1
        },
+       {
+               .type = SWITCH_TYPE_STRING,
+               .name = "extension_switch",
+               .description = "Enhanced switch feature",
+               .set = ar8xxx_sw_set_extension_switch,
+       },
 };

 static struct switch_attr ar8xxx_sw_attr_port[] = {
@@ -2669,6 +2676,7 @@ ar8xxx_probe_switch(struct ar8xxx_priv *priv)
        return 0;
 }

+extern int ar8216_ext_init(struct ar8xxx_priv *priv);
 static int
 ar8xxx_start(struct ar8xxx_priv *priv)
 {
@@ -2688,6 +2696,8 @@ ar8xxx_start(struct ar8xxx_priv *priv)

        ar8xxx_mib_start(priv);

+       ar8216_ext_init(priv);
+
        return 0;
 }

diff --git a/target/linux/generic/files/drivers/net/phy/ar8216_ext.c
b/target/linux/generic/files/drivers/net/phy/ar8216_ext.c
new file mode 100755
index 0000000..e31868f
--- /dev/null
+++ b/target/linux/generic/files/drivers/net/phy/ar8216_ext.c
@@ -0,0 +1,792 @@
+/*
+ * ar8216_ext.c: AR8216 switch driver enhanced feature
+ *
+ * Copyright (C) 2014 Zou Shunxiang <[email protected]>
+ *
+ *
+ * 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.
+ */
+
+#include <linux/if.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/list.h>
+#include <linux/if_ether.h>
+#include <linux/skbuff.h>
+#include <linux/netdevice.h>
+#include <linux/netlink.h>
+#include <linux/bitops.h>
+#include <net/genetlink.h>
+#include <linux/switch.h>
+#include <linux/delay.h>
+#include <linux/phy.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/lockdep.h>
+#include <linux/ar8216_platform.h>
+#include <linux/workqueue.h>
+#include <linux/of_device.h>
+#include <linux/leds.h>
+#include <linux/gpio.h>
+
+#include "ar8216_ext.h"
+#include "ar8216.h"
+
+/* size of the vlan table */
+#define AR8X16_MAX_VLANS       128
+#define AR8X16_PROBE_RETRIES   10
+#define AR8X16_MAX_PORTS       8
+struct ar8xxx_mib_desc {
+       unsigned int size;
+       unsigned int offset;
+       const char *name;
+};
+
+struct ar8xxx_chip {
+       unsigned long caps;
+
+       int (*hw_init)(struct ar8xxx_priv *priv);
+       void (*cleanup)(struct ar8xxx_priv *priv);
+
+       void (*init_globals)(struct ar8xxx_priv *priv);
+       void (*init_port)(struct ar8xxx_priv *priv, int port);
+       void (*setup_port)(struct ar8xxx_priv *priv, int port, u32 egress,
+                          u32 ingress, u32 members, u32 pvid);
+       u32 (*read_port_status)(struct ar8xxx_priv *priv, int port);
+       int (*atu_flush)(struct ar8xxx_priv *priv);
+       void (*vtu_flush)(struct ar8xxx_priv *priv);
+       void (*vtu_load_vlan)(struct ar8xxx_priv *priv, u32 vid, u32 port_mask);
+
+       const struct ar8xxx_mib_desc *mib_decs;
+       unsigned num_mibs;
+};
+
+enum ar8327_led_pattern {
+       AR8327_LED_PATTERN_OFF = 0,
+       AR8327_LED_PATTERN_BLINK,
+       AR8327_LED_PATTERN_ON,
+       AR8327_LED_PATTERN_RULE,
+};
+
+struct ar8327_led {
+       struct led_classdev cdev;
+       struct ar8xxx_priv *sw_priv;
+
+       char *name;
+       bool active_low;
+       u8 led_num;
+       enum ar8327_led_mode mode;
+
+       struct mutex mutex;
+       spinlock_t lock;
+       struct work_struct led_work;
+       bool enable_hw_mode;
+       enum ar8327_led_pattern pattern;
+};
+
+struct ar8327_data {
+       u32 port0_status;
+       u32 port6_status;
+
+       struct ar8327_led **leds;
+       unsigned int num_leds;
+};
+
+struct ar8xxx_priv {
+       struct switch_dev dev;
+       struct mii_bus *mii_bus;
+       struct phy_device *phy;
+
+       u32 (*read)(struct ar8xxx_priv *priv, int reg);
+       void (*write)(struct ar8xxx_priv *priv, int reg, u32 val);
+       u32 (*rmw)(struct ar8xxx_priv *priv, int reg, u32 mask, u32 val);
+
+       int (*get_port_link)(unsigned port);
+
+       const struct net_device_ops *ndo_old;
+       struct net_device_ops ndo;
+       struct mutex reg_mutex;
+       u8 chip_ver;
+       u8 chip_rev;
+       const struct ar8xxx_chip *chip;
+       union {
+               struct ar8327_data ar8327;
+       } chip_data;
+       bool initialized;
+       bool port4_phy;
+       char buf[2048];
+
+       bool init;
+       bool mii_lo_first;
+
+       struct mutex mib_lock;
+       struct delayed_work mib_work;
+       int mib_next_port;
+       u64 *mib_stats;
+
+       struct list_head list;
+       unsigned int use_count;
+
+       /* all fields below are cleared on reset */
+       bool vlan;
+       u16 vlan_id[AR8X16_MAX_VLANS];
+       u8 vlan_table[AR8X16_MAX_VLANS];
+       u8 vlan_tagged;
+       u16 pvid[AR8X16_MAX_PORTS];
+
+       /* mirroring */
+       bool mirror_rx;
+       bool mirror_tx;
+       int source_port;
+       int monitor_port;
+};
+
+static u8 ar8xxx_chip_version = 0xff;
+struct ar8xxx_priv *ext_priv;
+static hsl_api_t hsl_api_table;
+
+/* register functions */
+#define SW_BIT_MASK_U32(nr) (~(0xFFFFFFFF << (nr)))
+
+#define SW_FIELD_MASK_U32(offset, len) \
+       ((SW_BIT_MASK_U32(len) << (offset)))
+
+#define SW_FIELD_MASK_NOT_U32(offset,len) \
+       (~(SW_BIT_MASK_U32(len) << (offset)))
+
+#define SW_FIELD_2_REG(field_val, bit_offset) \
+       (field_val << (bit_offset) )
+
+#define SW_REG_2_FIELD(reg_val, bit_offset, field_len) \
+       (((reg_val) >> (bit_offset)) & ((1 << (field_len)) - 1))
+
+#define SW_REG_SET_BY_FIELD_U32(reg_value, field_value, bit_offset,
field_len)\
+       do { \
+               (reg_value) = \
+               (((reg_value) & 
SW_FIELD_MASK_NOT_U32((bit_offset),(field_len))) \
+               | (((field_value) & SW_BIT_MASK_U32(field_len)) << 
(bit_offset)));\
+       } while (0)
+
+#define SW_FIELD_GET_BY_REG_U32(reg_value, field_value, bit_offset,
field_len)\
+       do { \
+               (field_value) = \
+               (((reg_value) >> (bit_offset)) & SW_BIT_MASK_U32(field_len)); \
+       } while (0)
+
+#define SW_SET_REG_BY_FIELD(reg, field, field_value, reg_value) \
+       SW_REG_SET_BY_FIELD_U32(reg_value, field_value, 
reg##_##field##_BOFFSET, \
+                                                       reg##_##field##_BLEN)
+
+#define SW_GET_FIELD_BY_REG(reg, field, field_value, reg_value) \
+       SW_FIELD_GET_BY_REG_U32(reg_value, field_value, 
reg##_##field##_BOFFSET, \
+                                                       reg##_##field##_BLEN)
+
+static inline void
+split_addr(u32 regaddr, u16 *r1, u16 *r2, u16 *page)
+{
+       regaddr >>= 1;
+       *r1 = regaddr & 0x1e;
+
+       regaddr >>= 5;
+       *r2 = regaddr & 0x7;
+
+       regaddr >>= 3;
+       *page = regaddr & 0x1ff;
+}
+
+static u32
+ar8xxx_mii_read(struct ar8xxx_priv *priv, int reg)
+{
+       struct mii_bus *bus = priv->mii_bus;
+       u16 r1, r2, page;
+       u16 lo, hi;
+
+       split_addr((u32) reg, &r1, &r2, &page);
+
+       mutex_lock(&bus->mdio_lock);
+
+       bus->write(bus, 0x18, 0, page);
+       usleep_range(1000, 2000); /* wait for the page switch to propagate */
+       lo = bus->read(bus, 0x10 | r2, r1);
+       hi = bus->read(bus, 0x10 | r2, r1 + 1);
+
+       mutex_unlock(&bus->mdio_lock);
+
+       return (hi << 16) | lo;
+}
+
+static void
+ar8xxx_mii_write(struct ar8xxx_priv *priv, int reg, u32 val)
+{
+       struct mii_bus *bus = priv->mii_bus;
+       u16 r1, r2, r3;
+       u16 lo, hi;
+
+       split_addr((u32) reg, &r1, &r2, &r3);
+       lo = val & 0xffff;
+       hi = (u16) (val >> 16);
+
+       mutex_lock(&bus->mdio_lock);
+
+       bus->write(bus, 0x18, 0, r3);
+       usleep_range(1000, 2000); /* wait for the page switch to propagate */
+       if (priv->mii_lo_first) {
+               bus->write(bus, 0x10 | r2, r1, lo);
+               bus->write(bus, 0x10 | r2, r1 + 1, hi);
+       } else {
+               bus->write(bus, 0x10 | r2, r1 + 1, hi);
+               bus->write(bus, 0x10 | r2, r1, lo);
+       }
+
+       mutex_unlock(&bus->mdio_lock);
+}
+
+static int
+_isisc_mdio_reg_get(u32 reg_addr,
+                   u8 value[], u32 value_len)
+{
+       u32 reg_val;
+
+       if (value_len != sizeof (u32))
+               return -3;
+
+       reg_val = ar8xxx_mii_read(ext_priv, reg_addr);
+       memcpy(value, &reg_val, sizeof (u32));
+
+       return 0;
+}
+
+static int
+_isisc_mdio_reg_set(u32 reg_addr, u8 value[], u32 value_len)
+{
+       u32 reg_val;
+
+       if (value_len != sizeof (u32))
+               return -3;
+
+       memcpy(&reg_val, value, sizeof (u32));
+
+       ar8xxx_mii_write(ext_priv, reg_addr, reg_val);
+
+       return 0;
+}
+
+int
+isisc_reg_get(u32 reg_addr, u8 value[],
+             u32 value_len)
+{
+       int rv;
+       unsigned long flags;
+
+       local_irq_save(flags);
+       rv = _isisc_mdio_reg_get(reg_addr, value, value_len);
+       local_irq_restore(flags);
+
+       return rv;
+}
+
+int
+isisc_reg_set(u32 reg_addr, u8 value[], u32 value_len)
+{
+       int rv;
+       unsigned long flags;
+
+       u32 rt_value = 0;
+
+       /*get MODULE_EN reg rsv */
+       if (isisc_reg_get(0x30,(void *)&rt_value,4) != 0)
+               return -1;
+
+       local_irq_save(flags);
+       rv = _isisc_mdio_reg_set(reg_addr, value, value_len);
+       local_irq_restore(flags);
+
+       return rv;
+}
+
+int
+isisc_reg_field_get(u32 reg_addr,
+                                       u32 bit_offset, u32 field_len,
+                                       u8 value[], u32 value_len)
+{
+       u32 reg_val = 0;
+
+       if ((bit_offset >= 32 || (field_len > 32)) || (field_len == 0))
+               return -4;
+
+       if (value_len != sizeof (u32))
+               return -3;
+
+       if (isisc_reg_get(reg_addr, (u8 *) & reg_val, sizeof (u32)) != 0)
+               return -1;
+
+       if(32 == field_len) {
+               *((u32 *) value) = reg_val;
+       } else {
+               *((u32 *) value) = SW_REG_2_FIELD(reg_val, bit_offset, 
field_len);
+       }
+
+       return 0;
+}
+
+int
+isisc_reg_field_set(u32 reg_addr,
+                                       u32 bit_offset, u32 field_len,
+                                       const u8 value[], u32 value_len)
+{
+       u32 reg_val;
+       u32 field_val = *((u32 *) value);
+
+       if ((bit_offset >= 32 || (field_len > 32)) || (field_len == 0))
+               return -4;
+
+       if (value_len != sizeof (u32))
+               return -3;
+
+       if (isisc_reg_get(reg_addr, (u8 *) & reg_val, sizeof (u32)) != 0)
+               return -1;
+
+       if(32 == field_len) {
+               reg_val = field_val;
+       } else {
+               SW_REG_SET_BY_FIELD_U32(reg_val, field_val, bit_offset, 
field_len);
+       }
+
+       if (isisc_reg_set(reg_addr, (u8 *) & reg_val, sizeof (u32)) != 0)
+               return -1;
+
+       return 0;
+}
+
+#define HSL_REG_ENTRY_GET(rv, reg, index, value, val_len) \
+       do { \
+               rv = hsl_api_table.reg_get(reg##_OFFSET + ((u32)index) * 
reg##_E_OFFSET,\
+                                                               (u8*)value, 
(u8)val_len); \
+       } while (0);
+
+#define HSL_REG_ENTRY_SET(rv, reg, index, value, val_len) \
+       do { \
+               rv = hsl_api_table.reg_set (reg##_OFFSET + ((u32)index) * 
reg##_E_OFFSET,\
+                                                               (u8*)value, 
(u8)val_len); \
+       } while (0);
+
+
+static void
+_isisc_ingress_bs_byte_sw_to_hw(u32 sw_bs, u32 * hw_bs)
+{
+       u32 i;
+       u32 data[8] = {
+       0, 4 * 1024, 32 * 1024, 128 * 1024, 512 * 1024, 2 * 1024 * 1024,
+       8 * 1024 * 1024, 32 * 1024 * 1024
+       };
+
+       for (i = 7; i >= 0; i--) {
+               if (sw_bs >= data[i]) {
+                       *hw_bs = i;
+                       break;
+               }
+       }
+
+       return;
+}
+
+static void
+_isisc_ingress_bs_byte_hw_to_sw(u32 hw_bs, u32 * sw_bs)
+{
+       u32 data[8] = {
+               0, 4 * 1024, 32 * 1024, 128 * 1024, 512 * 1024, 2 * 1024 * 1024,
+               8 * 1024 * 1024, 32 * 1024 * 1024
+       };
+
+       *sw_bs = data[hw_bs & 0x7];
+
+       return;
+}
+
+static void
+_isisc_ingress_bs_frame_sw_to_hw(u32 sw_bs, u32 * hw_bs)
+{
+       u32 data[8] = { 0, 4, 16, 64, 256, 1024, 4096, 16384 };
+       u32 i;
+
+       for (i = 7; i >= 0; i--) {
+               if (sw_bs >= data[i]) {
+                       *hw_bs = i;
+                       break;
+               }
+       }
+
+       return;
+}
+
+static void
+_isisc_ingress_bs_frame_hw_to_sw(u32 hw_bs, u32 * sw_bs)
+{
+       u32 data[8] = { 0, 4, 16, 64, 256, 1024, 4096, 16384 };
+
+       *sw_bs = data[hw_bs & 0x7];
+
+       return;
+}
+
+static void
+_isisc_rate_flag_parse(u32 sw_flag, u32 * hw_flag)
+{
+       *hw_flag = 0;
+
+       if (FAL_INGRESS_POLICING_TCP_CTRL & sw_flag) {
+               *hw_flag |= (0x1 << 1);
+       }
+
+       if (FAL_INGRESS_POLICING_MANAGEMENT & sw_flag) {
+               *hw_flag |= (0x1 << 2);
+       }
+
+       if (FAL_INGRESS_POLICING_BROAD & sw_flag) {
+               *hw_flag |= (0x1 << 3);
+       }
+
+       if (FAL_INGRESS_POLICING_UNK_UNI & sw_flag) {
+               *hw_flag |= (0x1 << 4);
+       }
+
+       if (FAL_INGRESS_POLICING_UNK_MUL & sw_flag) {
+               *hw_flag |= (0x1 << 5);
+       }
+
+       if (FAL_INGRESS_POLICING_UNI & sw_flag) {
+               *hw_flag |= (0x1 << 6);
+       }
+
+       if (FAL_INGRESS_POLICING_MUL & sw_flag) {
+               *hw_flag |= (0x1 << 7);
+       }
+
+       return;
+}
+
+static void
+_isisc_rate_ts_parse(fal_rate_mt_t sw, u32 * hw)
+{
+       if (FAL_RATE_MI_100US == sw) {
+               *hw = 0;
+       } else if (FAL_RATE_MI_1MS == sw) {
+               *hw = 1;
+       } else if (FAL_RATE_MI_10MS == sw) {
+               *hw = 2;
+       } else if (FAL_RATE_MI_100MS) {
+               *hw = 3;
+       } else {
+               *hw = 0;
+       }
+
+       return;
+}
+
+static int
+isisc_rate_port_policer_set(u32 port_id,
+                            fal_port_policer_t * policer)
+{
+       int rv;
+       u32 cir = 0x7fff, eir = 0x7fff, cbs = 0, ebs = 0, tmp, data[3] = { 0 };
+
+       data[0] = 0x18000000;
+       if (FAL_BYTE_BASED == policer->meter_unit) {
+               if (true == policer->c_enable) {
+                       cir = policer->cir >> 5;
+                       policer->cir = cir << 5;
+                       _isisc_ingress_bs_byte_sw_to_hw(policer->cbs, &cbs);
+                       _isisc_ingress_bs_byte_hw_to_sw(cbs, &(policer->cbs));
+               }
+
+               if (false == policer->e_enable) {
+                       eir = policer->eir >> 5;
+                       policer->eir = eir << 5;
+                       _isisc_ingress_bs_byte_sw_to_hw(policer->ebs, &ebs);
+                       _isisc_ingress_bs_byte_hw_to_sw(ebs, &(policer->ebs));
+               }
+
+               SW_SET_REG_BY_FIELD(INGRESS_POLICER1, INGRESS_UNIT, 0, data[1]);
+       } else if (FAL_FRAME_BASED == policer->meter_unit) {
+               if (true == policer->c_enable) {
+                       cir = (policer->cir * 2) / 125;
+                       policer->cir = cir / 2 * 125 + cir % 2 * 63;
+                       _isisc_ingress_bs_frame_sw_to_hw(policer->cbs, &cbs);
+                       _isisc_ingress_bs_frame_hw_to_sw(cbs, &(policer->cbs));
+               }
+
+               if (true == policer->c_enable) {
+                       eir = (policer->eir * 2) / 125;
+                       policer->eir = eir / 2 * 125 + eir % 2 * 63;
+                       _isisc_ingress_bs_frame_sw_to_hw(policer->ebs, &ebs);
+                       _isisc_ingress_bs_frame_hw_to_sw(ebs, &(policer->ebs));
+               }
+
+               SW_SET_REG_BY_FIELD(INGRESS_POLICER1, INGRESS_UNIT, 1, data[1]);
+       } else {
+               return -6;
+       }
+
+       SW_SET_REG_BY_FIELD(INGRESS_POLICER0, INGRESS_CIR, cir, data[0]);
+       SW_SET_REG_BY_FIELD(INGRESS_POLICER0, INGRESS_CBS, cbs, data[0]);
+       SW_SET_REG_BY_FIELD(INGRESS_POLICER1, INGRESS_EIR, eir, data[1]);
+       SW_SET_REG_BY_FIELD(INGRESS_POLICER1, INGRESS_EBS, ebs, data[1]);
+
+       if (true == policer->combine_mode) {
+               SW_SET_REG_BY_FIELD(INGRESS_POLICER0, RATE_MODE, 1, data[0]);
+       }
+
+       if (true == policer->deficit_en) {
+               SW_SET_REG_BY_FIELD(INGRESS_POLICER1, INGRESS_BORROW, 1, 
data[1]);
+       }
+
+       if (true == policer->color_mode) {
+               SW_SET_REG_BY_FIELD(INGRESS_POLICER1, INGRESS_CM, 1, data[1]);
+       }
+
+       if (true == policer->couple_flag) {
+               SW_SET_REG_BY_FIELD(INGRESS_POLICER1, INGRESS_CF, 1, data[1]);
+       }
+
+       _isisc_rate_ts_parse(policer->c_meter_interval, &tmp);
+       SW_SET_REG_BY_FIELD(INGRESS_POLICER0, C_ING_TS, tmp, data[0]);
+
+       _isisc_rate_ts_parse(policer->e_meter_interval, &tmp);
+       SW_SET_REG_BY_FIELD(INGRESS_POLICER1, E_ING_TS, tmp, data[1]);
+
+       _isisc_rate_flag_parse(policer->c_rate_flag, &tmp);
+       data[2] = (tmp << 8) & 0xff00;
+
+       _isisc_rate_flag_parse(policer->e_rate_flag, &tmp);
+       data[2] |= (tmp & 0xff);
+
+       HSL_REG_ENTRY_SET(rv, INGRESS_POLICER0, port_id,
+                                       (u8 *) (&data[0]), sizeof (u32));
+
+       HSL_REG_ENTRY_SET(rv, INGRESS_POLICER1, port_id,
+                                       (u8 *) (&data[1]), sizeof (u32));
+
+       HSL_REG_ENTRY_SET(rv, INGRESS_POLICER2, port_id,
+                                       (u8 *) (&data[2]), sizeof (u32));
+
+       return rv;
+}
+
+int isisc_rate_init()
+{
+       hsl_api_table.rate_port_policer_set = isisc_rate_port_policer_set;
+
+       return 0;
+}
+
+int isisc_init()
+{
+       hsl_api_table.reg_get = isisc_reg_get;
+       hsl_api_table.reg_set = isisc_reg_set;
+       hsl_api_table.reg_field_get = isisc_reg_field_get;
+       hsl_api_table.reg_field_set = isisc_reg_field_set;
+
+       isisc_rate_init();
+
+       return 0;
+}
+
+int fal_init(u8 chip_type)
+{
+       int rv = 0;
+
+       memset(&hsl_api_table, 0, sizeof (hsl_api_t));
+
+       ar8xxx_chip_version = chip_type;
+
+       switch (ar8xxx_chip_version) {
+               case 0x13:
+                       rv = isisc_init();
+                       break;
+
+               default:
+                       return -2;
+       }
+
+       return rv;
+}
+
+int ar8216_ext_init(struct ar8xxx_priv *priv)
+{
+       ext_priv = priv;
+       fal_init(priv->chip_ver);
+
+       return 0;
+}
+
+/*fal api for externel calling*/
+int
+fal_rate_port_policer_set(u32 port_id,
+                           fal_port_policer_t * policer)
+{
+       int rv;
+
+       if (NULL == hsl_api_table.rate_port_policer_set)
+               return -26;
+
+       rv = hsl_api_table.rate_port_policer_set(port_id, policer);
+
+       return rv;
+}
+
+#define EXT_CMD_STR_MAX   128
+#define EXT_CMD_WORDS_MAX  16
+#define EXT_CMD_WORDS_LENGTH_MAX  32
+/*
+@cmd_str   [in]
+@cmd_words [out]
+*/
+static int
+ext_cmd_words_get(char *cmd_str,
+       char cmd_words[EXT_CMD_WORDS_MAX][EXT_CMD_WORDS_LENGTH_MAX])
+{
+       int nr = 0;
+       char *s = cmd_str, *tok;
+       char delim[] = " ";
+
+       for (tok = strsep(&s, delim); tok; tok = strsep(&s, delim)) {
+               strcpy(cmd_words[nr], tok);
+               nr++;
+       }
+
+       return nr;
+}
+
+/*
+@cmd_str  [in]
+@val [out]
+*/
+static int
+ext_cmd_uint32_get(char *cmd_word, unsigned int *val)
+{
+       int rv=0;
+
+       if (NULL == cmd_word) {
+               return -EINVAL;
+       }
+
+       if (0 == cmd_word[0]) {
+               return -EINVAL;
+       }
+
+       if (cmd_word[0] == '0' && (cmd_word[1] == 'x' || cmd_word[1] == 'X')) {
+               rv = sscanf(cmd_word, "%x", val);
+       } else {
+               rv = sscanf(cmd_word, "%d", val);
+       }
+
+       if (1 != rv) {
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+#define to_ar8xxx(_dev) container_of(_dev, struct ar8xxx_priv, dev)
+void
+ar8xxx_sw_ext_help()
+{
+       printk("ext cmd help:\n");
+       printk("\"port_rate_limit set port <port_id> rate <rate(Kpbs)>\"\n");
+}
+
+static int
+ar8xxx_sw_port_rate_limit(struct switch_dev *dev,
+       char cmd_words[EXT_CMD_WORDS_MAX][EXT_CMD_WORDS_LENGTH_MAX])
+{
+       int port = 0;
+       u32 rate = 0;
+       fal_port_policer_t port_policer;
+
+       if (NULL == cmd_words[1])
+               return -EINVAL;
+
+       if (0 == strcmp(cmd_words[1], "set")) {
+               /*port_rate_limit get/set port <port_it> rate <rate(Kpbs)>*/
+               /*        0                 1         2       3          4      
       
5*/
+               if (NULL == cmd_words[2] || NULL == cmd_words[3] ||
+                       NULL == cmd_words[4] ||NULL == cmd_words[5])
+                       return -EINVAL;
+               if (0 != strcmp(cmd_words[2], "port"))
+                       return -EINVAL;
+               if (0 != strcmp(cmd_words[4], "rate"))
+                       return -EINVAL;
+
+               if ((-EINVAL) == ext_cmd_uint32_get(cmd_words[3], &port))
+                       return -EINVAL;
+               if ((-EINVAL) == ext_cmd_uint32_get(cmd_words[5], &rate))
+                       return -EINVAL;
+
+               port_policer.combine_mode = 0;
+               port_policer.meter_unit= 0;
+               port_policer.couple_flag = 0;
+               port_policer.color_mode = 0;
+               port_policer.deficit_en = 0;
+               port_policer.c_enable = 1;
+               port_policer.cir = (rate/32)*32;
+               port_policer.cbs = 32768; //32kbps
+               port_policer.c_rate_flag = 0xfe;
+               port_policer.c_meter_interval = 1; // 1ms
+               port_policer.e_enable = 0;
+               port_policer.eir = 0;
+               port_policer.ebs = 0;
+               port_policer.e_rate_flag = 0;
+               port_policer.e_meter_interval = 1;
+               fal_rate_port_policer_set(port, &port_policer);
+       } else {
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+int
+ar8xxx_sw_set_extension_switch(struct switch_dev *dev,
+                                const struct switch_attr *attr,
+                                struct switch_val *val)
+{
+       int ret = 0;
+       char cmd_str[EXT_CMD_STR_MAX] = {0};
+       char cmd_words[EXT_CMD_WORDS_MAX][EXT_CMD_WORDS_LENGTH_MAX] = {0};
+       struct ar8xxx_priv *priv = to_ar8xxx(dev);
+
+       if (NULL == val->value.s)
+               return -EINVAL;
+
+       if (EXT_CMD_STR_MAX <=strlen(val->value.s)) {
+               return -EINVAL;
+       }
+
+       strcpy(cmd_str, val->value.s);
+
+       if (0 == ext_cmd_words_get(cmd_str, cmd_words)) {
+               return -EINVAL;
+       }
+
+       if (NULL == cmd_words[0] || NULL == cmd_words[1])
+               return -EINVAL;
+
+       mutex_lock(&priv->reg_mutex);
+       if (0 == strcmp(cmd_words[0], "port_rate_limit")) {
+               ret = ar8xxx_sw_port_rate_limit(dev, cmd_words);
+       } else {
+               ar8xxx_sw_ext_help();
+       }
+       mutex_unlock(&priv->reg_mutex);
+
+       return ret;
+}
+
diff --git a/target/linux/generic/files/drivers/net/phy/ar8216_ext.h
b/target/linux/generic/files/drivers/net/phy/ar8216_ext.h
new file mode 100755
index 0000000..d560f5a
--- /dev/null
+++ b/target/linux/generic/files/drivers/net/phy/ar8216_ext.h
@@ -0,0 +1,269 @@
+/*
+ * ar8216_ext.c: AR8216 switch driver enhanced feature
+ *
+ * Copyright (C) 2014 Zou Shunxiang <[email protected]>
+ *
+ * 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.
+ */
+
+#ifndef __AR8216_EXT_H
+#define __AR8216_EXT_H
+
+#define HSL_RW 1
+#define HSL_RO 0
+/* INGRESS Policer Register0 */
+#define INGRESS_POLICER0
+#define INGRESS_POLICER0_OFFSET         0x0b00
+#define INGRESS_POLICER0_E_LENGTH       4
+#define INGRESS_POLICER0_E_OFFSET       0x0010
+#define INGRESS_POLICER0_NR_E           7
+
+#define ADD_RATE_BYTE
+#define INGRESS_POLICER0_ADD_RATE_BYTE_BOFFSET 24
+#define INGRESS_POLICER0_ADD_RATE_BYTE_BLEN 8
+#define INGRESS_POLICER0_ADD_RATE_BYTE_FLAG HSL_RW
+
+#define C_ING_TS
+#define INGRESS_POLICER0_C_ING_TS_BOFFSET          22
+#define INGRESS_POLICER0_C_ING_TS_BLEN             2
+#define INGRESS_POLICER0_C_ING_TS_FLAG             HSL_RW
+
+#define RATE_MODE
+#define INGRESS_POLICER0_RATE_MODE_BOFFSET          20
+#define INGRESS_POLICER0_RATE_MODE_BLEN             1
+#define INGRESS_POLICER0_RATE_MODE_FLAG             HSL_RW
+
+#define INGRESS_CBS
+#define INGRESS_POLICER0_INGRESS_CBS_BOFFSET          15
+#define INGRESS_POLICER0_INGRESS_CBS_BLEN             3
+#define INGRESS_POLICER0_INGRESS_CBS_FLAG             HSL_RW
+
+#define INGRESS_CIR
+#define INGRESS_POLICER0_INGRESS_CIR_BOFFSET          0
+#define INGRESS_POLICER0_INGRESS_CIR_BLEN             15
+#define INGRESS_POLICER0_INGRESS_CIR_FLAG             HSL_RW
+
+
+/* INGRESS Policer Register1 */
+#define INGRESS_POLICER1
+#define INGRESS_POLICER1_OFFSET         0x0b04
+#define INGRESS_POLICER1_E_LENGTH       4
+#define INGRESS_POLICER1_E_OFFSET       0x0010
+#define INGRESS_POLICER1_NR_E           7
+
+#define INGRESS_BORROW
+#define INGRESS_POLICER1_INGRESS_BORROW_BOFFSET          23
+#define INGRESS_POLICER1_INGRESS_BORROW_BLEN             1
+#define INGRESS_POLICER1_INGRESS_BORROW_FLAG             HSL_RW
+
+#define INGRESS_UNIT
+#define INGRESS_POLICER1_INGRESS_UNIT_BOFFSET          22
+#define INGRESS_POLICER1_INGRESS_UNIT_BLEN             1
+#define INGRESS_POLICER1_INGRESS_UNIT_FLAG             HSL_RW
+
+#define INGRESS_CF
+#define INGRESS_POLICER1_INGRESS_CF_BOFFSET          21
+#define INGRESS_POLICER1_INGRESS_CF_BLEN             1
+#define INGRESS_POLICER1_INGRESS_CF_FLAG             HSL_RW
+
+#define INGRESS_CM
+#define INGRESS_POLICER1_INGRESS_CM_BOFFSET          20
+#define INGRESS_POLICER1_INGRESS_CM_BLEN             1
+#define INGRESS_POLICER1_INGRESS_CM_FLAG             HSL_RW
+
+#define E_ING_TS
+#define INGRESS_POLICER1_E_ING_TS_BOFFSET          18
+#define INGRESS_POLICER1_E_ING_TS_BLEN             2
+#define INGRESS_POLICER1_E_ING_TS_FLAG             HSL_RW
+
+#define INGRESS_EBS
+#define INGRESS_POLICER1_INGRESS_EBS_BOFFSET          15
+#define INGRESS_POLICER1_INGRESS_EBS_BLEN             3
+#define INGRESS_POLICER1_INGRESS_EBS_FLAG             HSL_RW
+
+#define INGRESS_EIR
+#define INGRESS_POLICER1_INGRESS_EIR_BOFFSET          0
+#define INGRESS_POLICER1_INGRESS_EIR_BLEN             15
+#define INGRESS_POLICER1_INGRESS_EIR_FLAG             HSL_RW
+
+
+/* INGRESS Policer Register2 */
+#define INGRESS_POLICER2
+#define INGRESS_POLICER2_OFFSET                 0x0b08
+#define INGRESS_POLICER2_E_LENGTH               4
+#define INGRESS_POLICER2_E_OFFSET               0x0010
+#define INGRESS_POLICER2_NR_E                   7
+
+#define C_MUL
+#define INGRESS_POLICER2_C_MUL_BOFFSET          15
+#define INGRESS_POLICER2_C_MUL_BLEN             1
+#define INGRESS_POLICER2_C_UNK_MUL_FLAG         HSL_RW
+
+#define C_UNI
+#define INGRESS_POLICER2_C_UNI_BOFFSET          14
+#define INGRESS_POLICER2_C_UNI_BLEN             1
+#define INGRESS_POLICER2_C_UNI_FLAG             HSL_RW
+
+#define C_UNK_MUL
+#define INGRESS_POLICER2_C_UNK_MUL_BOFFSET      13
+#define INGRESS_POLICER2_C_UNK_MUL_BLEN         1
+#define INGRESS_POLICER2_C_UNK_MUL_FLAG         HSL_RW
+
+#define C_UNK_UNI
+#define INGRESS_POLICER2_C_UNK_UNI_BOFFSET      12
+#define INGRESS_POLICER2_C_UNK_UNI_BLEN         1
+#define INGRESS_POLICER2_C_UNK_UNI_FLAG         HSL_RW
+
+#define C_BROAD
+#define INGRESS_POLICER2_C_BROAD_BOFFSET        11
+#define INGRESS_POLICER2_C_BROAD_BLEN           1
+#define INGRESS_POLICER2_C_BROAD_FLAG           HSL_RW
+
+#define C_MANAGE
+#define INGRESS_POLICER2_C_MANAGC_BOFFSET       10
+#define INGRESS_POLICER2_C_MANAGC_BLEN          1
+#define INGRESS_POLICER2_C_MANAGC_FLAG          HSL_RW
+
+#define C_TCP
+#define INGRESS_POLICER2_C_TCP_BOFFSET          9
+#define INGRESS_POLICER2_C_TCP_BLEN             1
+#define INGRESS_POLICER2_C_TCP_FLAG             HSL_RW
+
+#define C_MIRR
+#define INGRESS_POLICER2_C_MIRR_BOFFSET         8
+#define INGRESS_POLICER2_C_MIRR_BLEN            1
+#define INGRESS_POLICER2_C_MIRR_FLAG            HSL_RW
+
+#define E_MUL
+#define INGRESS_POLICER2_E_MUL_BOFFSET          7
+#define INGRESS_POLICER2_E_MUL_BLEN             1
+#define INGRESS_POLICER2_E_UNK_MUL_FLAG         HSL_RW
+
+#define E_UNI
+#define INGRESS_POLICER2_E_UNI_BOFFSET          6
+#define INGRESS_POLICER2_E_UNI_BLEN             1
+#define INGRESS_POLICER2_E_UNI_FLAG             HSL_RW
+
+#define E_UNK_MUL
+#define INGRESS_POLICER2_E_UNK_MUL_BOFFSET      5
+#define INGRESS_POLICER2_E_UNK_MUL_BLEN         1
+#define INGRESS_POLICER2_E_UNK_MUL_FLAG         HSL_RW
+
+#define E_UNK_UNI
+#define INGRESS_POLICER2_E_UNK_UNI_BOFFSET      4
+#define INGRESS_POLICER2_E_UNK_UNI_BLEN         1
+#define INGRESS_POLICER2_E_UNK_UNI_FLAG         HSL_RW
+
+#define E_BROAD
+#define INGRESS_POLICER2_E_BROAD_BOFFSET        3
+#define INGRESS_POLICER2_E_BROAD_BLEN           1
+#define INGRESS_POLICER2_E_BROAD_FLAG           HSL_RW
+
+#define E_MANAGE
+#define INGRESS_POLICER2_E_MANAGE_BOFFSET       2
+#define INGRESS_POLICER2_E_MANAGE_BLEN          1
+#define INGRESS_POLICER2_E_MANAGE_FLAG          HSL_RW
+
+#define E_TCP
+#define INGRESS_POLICER2_E_TCP_BOFFSET          1
+#define INGRESS_POLICER2_E_TCP_BLEN             1
+#define INGRESS_POLICER2_E_TCP_FLAG             HSL_RW
+
+#define E_MIRR
+#define INGRESS_POLICER2_E_MIRR_BOFFSET         0
+#define INGRESS_POLICER2_E_MIRR_BLEN            1
+#define INGRESS_POLICER2_E_MIRR_FLAG            HSL_RW
+
+
+#define FAL_INGRESS_POLICING_TCP_CTRL     0x2
+#define FAL_INGRESS_POLICING_MANAGEMENT   0x4
+#define FAL_INGRESS_POLICING_BROAD        0x8
+#define FAL_INGRESS_POLICING_UNK_UNI      0x10
+#define FAL_INGRESS_POLICING_UNK_MUL      0x20
+#define FAL_INGRESS_POLICING_UNI          0x40
+#define FAL_INGRESS_POLICING_MUL          0x80
+
+typedef enum {
+       FAL_BYTE_BASED = 0,
+       FAL_FRAME_BASED,
+       FAL_RATE_MODE_BUTT
+} fal_traffic_unit_t;
+
+typedef enum {
+       FAL_RATE_MI_100US = 0,
+       FAL_RATE_MI_1MS,
+       FAL_RATE_MI_10MS,
+       FAL_RATE_MI_100MS,
+} fal_rate_mt_t;
+
+typedef struct {
+       bool c_enable;
+       bool e_enable;
+       bool combine_mode;
+       fal_traffic_unit_t meter_unit;
+       bool color_mode;
+       bool couple_flag;
+       bool deficit_en;
+       bool cir;
+       bool eir;
+       bool cbs;
+       bool ebs;
+       bool c_rate_flag;
+       bool e_rate_flag;
+       fal_rate_mt_t c_meter_interval;
+       fal_rate_mt_t e_meter_interval;
+} fal_port_policer_t;
+
+
+typedef int
+       (*hsl_rate_port_policer_set)(u32 port_id,
+                                                               
fal_port_policer_t * policer);
+/* REG */
+typedef int
+       (*hsl_reg_get) (u32 reg_addr,
+                                       u8 value[], u32 value_len);
+
+typedef int
+       (*hsl_reg_set) (u32 reg_addr,
+                                       u8 value[], u32 value_len);
+
+typedef int
+       (*hsl_reg_field_get) (u32 reg_addr,
+                                               u32 bit_offset, u32 field_len,
+                                               u8 value[], u32 value_len);
+
+typedef int
+       (*hsl_reg_field_set) (u32 reg_addr,
+                                               u32 bit_offset, u32 field_len,
+                                               const u8 value[], u32 
value_len);
+
+typedef struct {
+       hsl_rate_port_policer_set rate_port_policer_set;
+
+       /* REG Access */
+       hsl_reg_get reg_get;
+       hsl_reg_set reg_set;
+       hsl_reg_field_get reg_field_get;
+       hsl_reg_field_set reg_field_set;
+} hsl_api_t;
+
+extern int fal_rate_port_policer_set(u32 port_id,
+                                                                       
fal_port_policer_t * policer);
+
+extern int fal_init(u8 chip_type);
+
+extern int
+ar8xxx_sw_set_extension_switch(struct switch_dev *dev,
+                                const struct switch_attr *attr,
+                                struct switch_val *val);
+
+
+#endif
diff --git a/target/linux/generic/patches-3.10/724-phy_ar8216.patch
b/target/linux/generic/patches-3.10/724-phy_ar8216.patch
old mode 100644
new mode 100755
index d3b238e..58c6244
--- a/target/linux/generic/patches-3.10/724-phy_ar8216.patch
+++ b/target/linux/generic/patches-3.10/724-phy_ar8216.patch
@@ -18,7 +18,7 @@
  obj-$(CONFIG_MVSWITCH_PHY)    += mvswitch.o
  obj-$(CONFIG_IP17XX_PHY)      += ip17xx.o
  obj-$(CONFIG_REALTEK_PHY)     += realtek.o
-+obj-$(CONFIG_AR8216_PHY)      += ar8216.o
++obj-$(CONFIG_AR8216_PHY)      += ar8216.o ar8216_ext.o
  obj-$(CONFIG_LSI_ET1011C_PHY) += et1011c.o
  obj-$(CONFIG_FIXED_PHY)               += fixed.o
  obj-$(CONFIG_MDIO_BITBANG)    += mdio-bitbang.o
diff --git a/target/linux/generic/patches-3.10/725-phy_rtl8306.patch
b/target/linux/generic/patches-3.10/725-phy_rtl8306.patch
old mode 100644
new mode 100755
index 56899a7..43cbb8a
--- a/target/linux/generic/patches-3.10/725-phy_rtl8306.patch
+++ b/target/linux/generic/patches-3.10/725-phy_rtl8306.patch
@@ -16,7 +16,7 @@
 @@ -22,6 +22,7 @@ obj-$(CONFIG_MVSWITCH_PHY)   += mvswitch.o
  obj-$(CONFIG_IP17XX_PHY)      += ip17xx.o
  obj-$(CONFIG_REALTEK_PHY)     += realtek.o
- obj-$(CONFIG_AR8216_PHY)      += ar8216.o
+ obj-$(CONFIG_AR8216_PHY)      += ar8216.o ar8216_ext.o
 +obj-$(CONFIG_RTL8306_PHY)     += rtl8306.o
  obj-$(CONFIG_LSI_ET1011C_PHY) += et1011c.o
  obj-$(CONFIG_FIXED_PHY)               += fixed.o
diff --git a/target/linux/generic/patches-3.10/726-phy_rtl8366.patch
b/target/linux/generic/patches-3.10/726-phy_rtl8366.patch
old mode 100644
new mode 100755
index cbb5ce1..d190a38
--- a/target/linux/generic/patches-3.10/726-phy_rtl8366.patch
+++ b/target/linux/generic/patches-3.10/726-phy_rtl8366.patch
@@ -35,7 +35,7 @@
 +++ b/drivers/net/phy/Makefile
 @@ -23,6 +23,9 @@ obj-$(CONFIG_IP17XX_PHY)     += ip17xx.o
  obj-$(CONFIG_REALTEK_PHY)     += realtek.o
- obj-$(CONFIG_AR8216_PHY)      += ar8216.o
+ obj-$(CONFIG_AR8216_PHY)      += ar8216.o ar8216_ext.o
  obj-$(CONFIG_RTL8306_PHY)     += rtl8306.o
 +obj-$(CONFIG_RTL8366_SMI)     += rtl8366_smi.o
 +obj-$(CONFIG_RTL8366S_PHY)    += rtl8366s.o
diff --git a/target/linux/generic/patches-3.14/724-phy_ar8216.patch
b/target/linux/generic/patches-3.14/724-phy_ar8216.patch
old mode 100644
new mode 100755
index d3b238e..58c6244
--- a/target/linux/generic/patches-3.14/724-phy_ar8216.patch
+++ b/target/linux/generic/patches-3.14/724-phy_ar8216.patch
@@ -18,7 +18,7 @@
  obj-$(CONFIG_MVSWITCH_PHY)    += mvswitch.o
  obj-$(CONFIG_IP17XX_PHY)      += ip17xx.o
  obj-$(CONFIG_REALTEK_PHY)     += realtek.o
-+obj-$(CONFIG_AR8216_PHY)      += ar8216.o
++obj-$(CONFIG_AR8216_PHY)      += ar8216.o ar8216_ext.o
  obj-$(CONFIG_LSI_ET1011C_PHY) += et1011c.o
  obj-$(CONFIG_FIXED_PHY)               += fixed.o
  obj-$(CONFIG_MDIO_BITBANG)    += mdio-bitbang.o
-- 
1.8.2.1
_______________________________________________
openwrt-devel mailing list
[email protected]
https://lists.openwrt.org/cgi-bin/mailman/listinfo/openwrt-devel

Reply via email to