Add cpsw_ale_policer_set/clr_entry() helpers. So far Raw Ethernet matching based on Source/Destination address and VLAN Priority (PCP) is supported. Signed-off-by: Roger Quadros <rogerq@xxxxxxxxxx> --- drivers/net/ethernet/ti/cpsw_ale.c | 84 ++++++++++++++++++++++++++++++++++++++ drivers/net/ethernet/ti/cpsw_ale.h | 28 +++++++++++++ 2 files changed, 112 insertions(+) diff --git a/drivers/net/ethernet/ti/cpsw_ale.c b/drivers/net/ethernet/ti/cpsw_ale.c index 630e3a555190..f5ca18d4ea6a 100644 --- a/drivers/net/ethernet/ti/cpsw_ale.c +++ b/drivers/net/ethernet/ti/cpsw_ale.c @@ -1746,3 +1746,87 @@ void cpsw_ale_classifier_setup_default(struct cpsw_ale *ale, int num_rx_ch) 1); } } + +#define HOST_PORT_NUM 0 + +/* Clear Policer and associated ALE table entries */ +void cpsw_ale_policer_clr_entry(struct cpsw_ale *ale, u32 policer_idx, + struct cpsw_ale_policer_cfg *cfg) +{ + cpsw_ale_policer_reset_entry(ale, policer_idx); + + /* We do not delete ALE entries that were added in set_entry + * as they might still be in use by the port e.g. VLAN id + * or port MAC address + */ + + /* clear BLOCKED in case we set it */ + if ((cfg->match_flags & CPSW_ALE_POLICER_MATCH_MACSRC) && cfg->drop) + cpsw_ale_add_ucast(ale, cfg->src_addr, HOST_PORT_NUM, 0, 0); + + if ((cfg->match_flags & CPSW_ALE_POLICER_MATCH_MACDST) && cfg->drop) + cpsw_ale_add_ucast(ale, cfg->dst_addr, HOST_PORT_NUM, 0, 0); +} + +int cpsw_ale_policer_set_entry(struct cpsw_ale *ale, u32 policer_idx, + struct cpsw_ale_policer_cfg *cfg) +{ + int ale_idx; + u16 ale_flags = cfg->drop ? ALE_BLOCKED : 0; + + /* A single policer can support multiple match types simultaneously + * There can be only one ALE entry per address + */ + cpsw_ale_policer_reset_entry(ale, policer_idx); + cpsw_ale_policer_read_idx(ale, policer_idx); + + if (cfg->match_flags & CPSW_ALE_POLICER_MATCH_MACSRC) { + ale_idx = cpsw_ale_add_ucast(ale, cfg->src_addr, HOST_PORT_NUM, ale_flags, 0); + if (ale_idx < 0) + return -ENOENT; + + /* update policer entry */ + regmap_field_write(ale->fields[POL_SRC_INDEX], ale_idx); + regmap_field_write(ale->fields[POL_SRC_MEN], 1); + } + + if (cfg->match_flags & CPSW_ALE_POLICER_MATCH_MACDST) { + ale_idx = cpsw_ale_add_ucast(ale, cfg->dst_addr, HOST_PORT_NUM, ale_flags, 0); + if (ale_idx < 0) + return -ENOENT; + + /* update policer entry */ + regmap_field_write(ale->fields[POL_DST_INDEX], ale_idx); + regmap_field_write(ale->fields[POL_DST_MEN], 1); + } + + if (cfg->match_flags & CPSW_ALE_POLICER_MATCH_OVLAN) { +/* FIXME: VLAN ID based flow routing not yet working, Only PCP matching for now + * u32 port_mask, unreg_mcast = 0; + * + * port_mask = BIT(cfg->port_id) | ALE_PORT_HOST; + * if (!cfg->vid) + * unreg_mcast = port_mask; + * ale_idx = cpsw_ale_vlan_add_modify(ale, cfg->vid, port_mask, + * unreg_mcast, port_mask, 0); + * if (ale_idx < 0) + * return -ENOENT; + * + * regmap_field_write(ale->fields[POL_OVLAN_INDEX], ale_idx); + * regmap_field_write(ale->fields[POL_OVLAN_MEN], 1); + */ + + regmap_field_write(ale->fields[POL_PRI_VAL], cfg->vlan_prio); + regmap_field_write(ale->fields[POL_PRI_MEN], 1); + } + + cpsw_ale_policer_write_idx(ale, policer_idx); + + /* Map to thread id provided by the config */ + if (!cfg->drop) { + cpsw_ale_policer_thread_idx_enable(ale, policer_idx, + cfg->thread_id, true); + } + + return 0; +} diff --git a/drivers/net/ethernet/ti/cpsw_ale.h b/drivers/net/ethernet/ti/cpsw_ale.h index ce59fec75774..11d333bf5a52 100644 --- a/drivers/net/ethernet/ti/cpsw_ale.h +++ b/drivers/net/ethernet/ti/cpsw_ale.h @@ -159,6 +159,30 @@ enum cpsw_ale_port_state { /* Policer */ #define CPSW_ALE_POLICER_ENTRY_WORDS 8 +/* Policer match flags */ +#define CPSW_ALE_POLICER_MATCH_PORT BIT(0) +#define CPSW_ALE_POLICER_MATCH_PRI BIT(1) +#define CPSW_ALE_POLICER_MATCH_OUI BIT(2) +#define CPSW_ALE_POLICER_MATCH_MACDST BIT(3) +#define CPSW_ALE_POLICER_MATCH_MACSRC BIT(4) +#define CPSW_ALE_POLICER_MATCH_OVLAN BIT(5) +#define CPSW_ALE_POLICER_MATCH_IVLAN BIT(6) +#define CPSW_ALE_POLICER_MATCH_ETHTYPE BIT(7) +#define CPSW_ALE_POLICER_MATCH_IPSRC BIT(8) +#define CPSW_ALE_POLICER_MATCH_IPDST BIT(9) + +struct cpsw_ale_policer_cfg { + u32 match_flags; + u16 ether_type; + u16 vid; + u8 vlan_prio; + u8 src_addr[ETH_ALEN]; + u8 dst_addr[ETH_ALEN]; + bool drop; + u64 thread_id; + int port_id; +}; + struct cpsw_ale *cpsw_ale_create(struct cpsw_ale_params *params); void cpsw_ale_start(struct cpsw_ale *ale); @@ -199,5 +223,9 @@ void cpsw_ale_set_unreg_mcast(struct cpsw_ale *ale, int unreg_mcast_mask, bool add); void cpsw_ale_classifier_setup_default(struct cpsw_ale *ale, int num_rx_ch); void cpsw_ale_policer_reset(struct cpsw_ale *ale); +int cpsw_ale_policer_set_entry(struct cpsw_ale *ale, u32 policer_idx, + struct cpsw_ale_policer_cfg *cfg); +void cpsw_ale_policer_clr_entry(struct cpsw_ale *ale, u32 policer_idx, + struct cpsw_ale_policer_cfg *cfg); #endif -- 2.34.1