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, ®_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(®_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
