Commit 961d4187 authored by Roger Quadros's avatar Roger Quadros Committed by David S. Miller

net: ethernet: ti: cpsw_ale: add policer/classifier helpers and setup defaults

The Policer registers in the ALE register space are just shadow registers
and use an index field in the policer table control register to read/write
to the actual Polier registers.
Add helper functions to Read and Write to Policer registers.

Also add a helper function to set the thread value to classifier/policer
mapping. Any packet that first matches the classifier will be sent to the
thread (flow) that is set in the classifier to thread mapping table.
If not set then it goes to the default flow.

Default behaviour is to have 8 classifiers to map 8 DSCP/PCP
priorities to N receive threads (flows). N depends on number of
RX channels enabled for the port.
As per the standard [1] User prioritie 1 (Background) and 2 (Spare) have
lower priority than the user priority 0 (default). User priority 1 being
of the lowest priority.

[1] IEEE802.1D-2004, IEEE Standard for Local and metropolitan area networks
Table G-2 - Traffic type acronyms
Table G-3 - Defining traffic types
Signed-off-by: default avatarRoger Quadros <rogerq@kernel.org>
Reviewed-by: default avatarSimon Horman <horms@kernel.org>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent eb41dd76
......@@ -1627,3 +1627,97 @@ u32 cpsw_ale_get_num_entries(struct cpsw_ale *ale)
{
return ale ? ale->params.ale_entries : 0;
}
/* Reads the specified policer index into ALE POLICER registers */
static void cpsw_ale_policer_read_idx(struct cpsw_ale *ale, u32 idx)
{
idx &= ALE_POLICER_TBL_INDEX_MASK;
writel_relaxed(idx, ale->params.ale_regs + ALE_POLICER_TBL_CTL);
}
/* Writes the ALE POLICER registers into the specified policer index */
static void cpsw_ale_policer_write_idx(struct cpsw_ale *ale, u32 idx)
{
idx &= ALE_POLICER_TBL_INDEX_MASK;
idx |= ALE_POLICER_TBL_WRITE_ENABLE;
writel_relaxed(idx, ale->params.ale_regs + ALE_POLICER_TBL_CTL);
}
/* enables/disables the custom thread value for the specified policer index */
static void cpsw_ale_policer_thread_idx_enable(struct cpsw_ale *ale, u32 idx,
u32 thread_id, bool enable)
{
regmap_field_write(ale->fields[ALE_THREAD_CLASS_INDEX], idx);
regmap_field_write(ale->fields[ALE_THREAD_VALUE], thread_id);
regmap_field_write(ale->fields[ALE_THREAD_ENABLE], enable ? 1 : 0);
}
/* Disable all policer entries and thread mappings */
static void cpsw_ale_policer_reset(struct cpsw_ale *ale)
{
int i;
for (i = 0; i < ale->params.num_policers ; i++) {
cpsw_ale_policer_read_idx(ale, i);
regmap_field_write(ale->fields[POL_PORT_MEN], 0);
regmap_field_write(ale->fields[POL_PRI_MEN], 0);
regmap_field_write(ale->fields[POL_OUI_MEN], 0);
regmap_field_write(ale->fields[POL_DST_MEN], 0);
regmap_field_write(ale->fields[POL_SRC_MEN], 0);
regmap_field_write(ale->fields[POL_OVLAN_MEN], 0);
regmap_field_write(ale->fields[POL_IVLAN_MEN], 0);
regmap_field_write(ale->fields[POL_ETHERTYPE_MEN], 0);
regmap_field_write(ale->fields[POL_IPSRC_MEN], 0);
regmap_field_write(ale->fields[POL_IPDST_MEN], 0);
regmap_field_write(ale->fields[POL_EN], 0);
regmap_field_write(ale->fields[POL_RED_DROP_EN], 0);
regmap_field_write(ale->fields[POL_YELLOW_DROP_EN], 0);
regmap_field_write(ale->fields[POL_PRIORITY_THREAD_EN], 0);
cpsw_ale_policer_thread_idx_enable(ale, i, 0, 0);
}
}
/* Default classifier is to map 8 user priorities to N receive channels */
void cpsw_ale_classifier_setup_default(struct cpsw_ale *ale, int num_rx_ch)
{
int pri, idx;
/* IEEE802.1D-2004, Standard for Local and metropolitan area networks
* Table G-2 - Traffic type acronyms
* Table G-3 - Defining traffic types
* User priority values 1 and 2 effectively communicate a lower
* priority than 0. In the below table 0 is assigned to higher priority
* thread than 1 and 2 wherever possible.
* The below table maps which thread the user priority needs to be
* sent to for a given number of threads (RX channels). Upper threads
* have higher priority.
* e.g. if number of threads is 8 then user priority 0 will map to
* pri_thread_map[8-1][0] i.e. thread 2
*/
int pri_thread_map[8][8] = { { 0, 0, 0, 0, 0, 0, 0, 0, },
{ 0, 0, 0, 0, 1, 1, 1, 1, },
{ 0, 0, 0, 0, 1, 1, 2, 2, },
{ 1, 0, 0, 1, 2, 2, 3, 3, },
{ 1, 0, 0, 1, 2, 3, 4, 4, },
{ 1, 0, 0, 2, 3, 4, 5, 5, },
{ 1, 0, 0, 2, 3, 4, 5, 6, },
{ 2, 0, 1, 3, 4, 5, 6, 7, } };
cpsw_ale_policer_reset(ale);
/* use first 8 classifiers to map 8 (DSCP/PCP) priorities to channels */
for (pri = 0; pri < 8; pri++) {
idx = pri;
/* Classifier 'idx' match on priority 'pri' */
cpsw_ale_policer_read_idx(ale, idx);
regmap_field_write(ale->fields[POL_PRI_VAL], pri);
regmap_field_write(ale->fields[POL_PRI_MEN], 1);
cpsw_ale_policer_write_idx(ale, idx);
/* Map Classifier 'idx' to thread provided by the map */
cpsw_ale_policer_thread_idx_enable(ale, idx,
pri_thread_map[num_rx_ch - 1][pri],
1);
}
}
......@@ -193,5 +193,6 @@ int cpsw_ale_vlan_add_modify(struct cpsw_ale *ale, u16 vid, int port_mask,
int cpsw_ale_vlan_del_modify(struct cpsw_ale *ale, u16 vid, int port_mask);
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);
#endif
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment