Commit ac22bfb1 authored by David S. Miller's avatar David S. Miller

Merge branch 'dsa-bcm_sf2-CFP-fixes'

Florian Fainelli says:

====================
net: dsa: bcm_sf2: CFP fixes

This patch series fixes a number of usability issues with the SF2 Compact Field
Processor code:

- we would not be properly bound checking the location when we let the kernel
  automatically place rules with RX_CLS_LOC_ANY

- when using IPv6 rules and user space specifies a location identifier we
  would be off by one in what the chain ID (within the Broadcom tag) indicates

- it would be possible to delete one of the two slices of an IPv6 while leaving
  the other one programming leading to various problems
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents e1b505a6 1942adf6
...@@ -354,10 +354,13 @@ static int bcm_sf2_cfp_ipv4_rule_set(struct bcm_sf2_priv *priv, int port, ...@@ -354,10 +354,13 @@ static int bcm_sf2_cfp_ipv4_rule_set(struct bcm_sf2_priv *priv, int port,
/* Locate the first rule available */ /* Locate the first rule available */
if (fs->location == RX_CLS_LOC_ANY) if (fs->location == RX_CLS_LOC_ANY)
rule_index = find_first_zero_bit(priv->cfp.used, rule_index = find_first_zero_bit(priv->cfp.used,
bcm_sf2_cfp_rule_size(priv)); priv->num_cfp_rules);
else else
rule_index = fs->location; rule_index = fs->location;
if (rule_index > bcm_sf2_cfp_rule_size(priv))
return -ENOSPC;
layout = &udf_tcpip4_layout; layout = &udf_tcpip4_layout;
/* We only use one UDF slice for now */ /* We only use one UDF slice for now */
slice_num = bcm_sf2_get_slice_number(layout, 0); slice_num = bcm_sf2_get_slice_number(layout, 0);
...@@ -562,19 +565,21 @@ static int bcm_sf2_cfp_ipv6_rule_set(struct bcm_sf2_priv *priv, int port, ...@@ -562,19 +565,21 @@ static int bcm_sf2_cfp_ipv6_rule_set(struct bcm_sf2_priv *priv, int port,
* first half because the HW search is by incrementing addresses. * first half because the HW search is by incrementing addresses.
*/ */
if (fs->location == RX_CLS_LOC_ANY) if (fs->location == RX_CLS_LOC_ANY)
rule_index[0] = find_first_zero_bit(priv->cfp.used, rule_index[1] = find_first_zero_bit(priv->cfp.used,
bcm_sf2_cfp_rule_size(priv)); priv->num_cfp_rules);
else else
rule_index[0] = fs->location; rule_index[1] = fs->location;
if (rule_index[1] > bcm_sf2_cfp_rule_size(priv))
return -ENOSPC;
/* Flag it as used (cleared on error path) such that we can immediately /* Flag it as used (cleared on error path) such that we can immediately
* obtain a second one to chain from. * obtain a second one to chain from.
*/ */
set_bit(rule_index[0], priv->cfp.used); set_bit(rule_index[1], priv->cfp.used);
rule_index[1] = find_first_zero_bit(priv->cfp.used, rule_index[0] = find_first_zero_bit(priv->cfp.used,
bcm_sf2_cfp_rule_size(priv)); priv->num_cfp_rules);
if (rule_index[1] > bcm_sf2_cfp_rule_size(priv)) { if (rule_index[0] > bcm_sf2_cfp_rule_size(priv)) {
ret = -ENOSPC; ret = -ENOSPC;
goto out_err; goto out_err;
} }
...@@ -712,14 +717,14 @@ static int bcm_sf2_cfp_ipv6_rule_set(struct bcm_sf2_priv *priv, int port, ...@@ -712,14 +717,14 @@ static int bcm_sf2_cfp_ipv6_rule_set(struct bcm_sf2_priv *priv, int port,
/* Flag the second half rule as being used now, return it as the /* Flag the second half rule as being used now, return it as the
* location, and flag it as unique while dumping rules * location, and flag it as unique while dumping rules
*/ */
set_bit(rule_index[1], priv->cfp.used); set_bit(rule_index[0], priv->cfp.used);
set_bit(rule_index[1], priv->cfp.unique); set_bit(rule_index[1], priv->cfp.unique);
fs->location = rule_index[1]; fs->location = rule_index[1];
return ret; return ret;
out_err: out_err:
clear_bit(rule_index[0], priv->cfp.used); clear_bit(rule_index[1], priv->cfp.used);
return ret; return ret;
} }
...@@ -785,10 +790,6 @@ static int bcm_sf2_cfp_rule_del_one(struct bcm_sf2_priv *priv, int port, ...@@ -785,10 +790,6 @@ static int bcm_sf2_cfp_rule_del_one(struct bcm_sf2_priv *priv, int port,
int ret; int ret;
u32 reg; u32 reg;
/* Refuse deletion of unused rules, and the default reserved rule */
if (!test_bit(loc, priv->cfp.used) || loc == 0)
return -EINVAL;
/* Indicate which rule we want to read */ /* Indicate which rule we want to read */
bcm_sf2_cfp_rule_addr_set(priv, loc); bcm_sf2_cfp_rule_addr_set(priv, loc);
...@@ -826,6 +827,13 @@ static int bcm_sf2_cfp_rule_del(struct bcm_sf2_priv *priv, int port, ...@@ -826,6 +827,13 @@ static int bcm_sf2_cfp_rule_del(struct bcm_sf2_priv *priv, int port,
u32 next_loc = 0; u32 next_loc = 0;
int ret; int ret;
/* Refuse deleting unused rules, and those that are not unique since
* that could leave IPv6 rules with one of the chained rule in the
* table.
*/
if (!test_bit(loc, priv->cfp.unique) || loc == 0)
return -EINVAL;
ret = bcm_sf2_cfp_rule_del_one(priv, port, loc, &next_loc); ret = bcm_sf2_cfp_rule_del_one(priv, port, loc, &next_loc);
if (ret) if (ret)
return ret; return ret;
......
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