net: dsa: bcm_sf2: Split rule handling from HW operation
In preparation for restoring CFP rules during system wide system suspend/resume where the hardware loses its context, split the rule validation from its actual insertion as well as the rule removal from its actual hardware deletion operation. Signed-off-by: Florian Fainelli <f.fainelli@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
ae7a5aff78
commit
ce24b08a2e
|
@ -789,32 +789,14 @@ out_err:
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int bcm_sf2_cfp_rule_set(struct dsa_switch *ds, int port,
|
static int bcm_sf2_cfp_rule_insert(struct dsa_switch *ds, int port,
|
||||||
struct ethtool_rx_flow_spec *fs)
|
struct ethtool_rx_flow_spec *fs)
|
||||||
{
|
{
|
||||||
struct bcm_sf2_priv *priv = bcm_sf2_to_priv(ds);
|
struct bcm_sf2_priv *priv = bcm_sf2_to_priv(ds);
|
||||||
s8 cpu_port = ds->ports[port].cpu_dp->index;
|
s8 cpu_port = ds->ports[port].cpu_dp->index;
|
||||||
__u64 ring_cookie = fs->ring_cookie;
|
__u64 ring_cookie = fs->ring_cookie;
|
||||||
unsigned int queue_num, port_num;
|
unsigned int queue_num, port_num;
|
||||||
struct cfp_rule *rule = NULL;
|
int ret;
|
||||||
int ret = -EINVAL;
|
|
||||||
|
|
||||||
/* Check for unsupported extensions */
|
|
||||||
if ((fs->flow_type & FLOW_EXT) && (fs->m_ext.vlan_etype ||
|
|
||||||
fs->m_ext.data[1]))
|
|
||||||
return -EINVAL;
|
|
||||||
|
|
||||||
if (fs->location != RX_CLS_LOC_ANY &&
|
|
||||||
test_bit(fs->location, priv->cfp.used))
|
|
||||||
return -EBUSY;
|
|
||||||
|
|
||||||
if (fs->location != RX_CLS_LOC_ANY &&
|
|
||||||
fs->location > bcm_sf2_cfp_rule_size(priv))
|
|
||||||
return -EINVAL;
|
|
||||||
|
|
||||||
ret = bcm_sf2_cfp_rule_cmp(priv, port, fs);
|
|
||||||
if (ret == 0)
|
|
||||||
return -EEXIST;
|
|
||||||
|
|
||||||
/* This rule is a Wake-on-LAN filter and we must specifically
|
/* This rule is a Wake-on-LAN filter and we must specifically
|
||||||
* target the CPU port in order for it to be working.
|
* target the CPU port in order for it to be working.
|
||||||
|
@ -841,10 +823,6 @@ static int bcm_sf2_cfp_rule_set(struct dsa_switch *ds, int port,
|
||||||
if (port_num >= 7)
|
if (port_num >= 7)
|
||||||
port_num -= 1;
|
port_num -= 1;
|
||||||
|
|
||||||
rule = kzalloc(sizeof(*rule), GFP_KERNEL);
|
|
||||||
if (!rule)
|
|
||||||
return -ENOMEM;
|
|
||||||
|
|
||||||
switch (fs->flow_type & ~FLOW_EXT) {
|
switch (fs->flow_type & ~FLOW_EXT) {
|
||||||
case TCP_V4_FLOW:
|
case TCP_V4_FLOW:
|
||||||
case UDP_V4_FLOW:
|
case UDP_V4_FLOW:
|
||||||
|
@ -861,6 +839,38 @@ static int bcm_sf2_cfp_rule_set(struct dsa_switch *ds, int port,
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int bcm_sf2_cfp_rule_set(struct dsa_switch *ds, int port,
|
||||||
|
struct ethtool_rx_flow_spec *fs)
|
||||||
|
{
|
||||||
|
struct bcm_sf2_priv *priv = bcm_sf2_to_priv(ds);
|
||||||
|
struct cfp_rule *rule = NULL;
|
||||||
|
int ret = -EINVAL;
|
||||||
|
|
||||||
|
/* Check for unsupported extensions */
|
||||||
|
if ((fs->flow_type & FLOW_EXT) && (fs->m_ext.vlan_etype ||
|
||||||
|
fs->m_ext.data[1]))
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
if (fs->location != RX_CLS_LOC_ANY &&
|
||||||
|
test_bit(fs->location, priv->cfp.used))
|
||||||
|
return -EBUSY;
|
||||||
|
|
||||||
|
if (fs->location != RX_CLS_LOC_ANY &&
|
||||||
|
fs->location > bcm_sf2_cfp_rule_size(priv))
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
ret = bcm_sf2_cfp_rule_cmp(priv, port, fs);
|
||||||
|
if (ret == 0)
|
||||||
|
return -EEXIST;
|
||||||
|
|
||||||
|
rule = kzalloc(sizeof(*rule), GFP_KERNEL);
|
||||||
|
if (!rule)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
ret = bcm_sf2_cfp_rule_insert(ds, port, fs);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
kfree(rule);
|
kfree(rule);
|
||||||
return ret;
|
return ret;
|
||||||
|
@ -910,13 +920,28 @@ static int bcm_sf2_cfp_rule_del_one(struct bcm_sf2_priv *priv, int port,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int bcm_sf2_cfp_rule_del(struct bcm_sf2_priv *priv, int port,
|
static int bcm_sf2_cfp_rule_remove(struct bcm_sf2_priv *priv, int port,
|
||||||
u32 loc)
|
u32 loc)
|
||||||
{
|
{
|
||||||
struct cfp_rule *rule;
|
|
||||||
u32 next_loc = 0;
|
u32 next_loc = 0;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
|
ret = bcm_sf2_cfp_rule_del_one(priv, port, loc, &next_loc);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
/* If this was an IPv6 rule, delete is companion rule too */
|
||||||
|
if (next_loc)
|
||||||
|
ret = bcm_sf2_cfp_rule_del_one(priv, port, next_loc, NULL);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int bcm_sf2_cfp_rule_del(struct bcm_sf2_priv *priv, int port, u32 loc)
|
||||||
|
{
|
||||||
|
struct cfp_rule *rule;
|
||||||
|
int ret;
|
||||||
|
|
||||||
/* Refuse deleting unused rules, and those that are not unique since
|
/* Refuse deleting unused rules, and those that are not unique since
|
||||||
* that could leave IPv6 rules with one of the chained rule in the
|
* that could leave IPv6 rules with one of the chained rule in the
|
||||||
* table.
|
* table.
|
||||||
|
@ -928,13 +953,7 @@ static int bcm_sf2_cfp_rule_del(struct bcm_sf2_priv *priv, int port,
|
||||||
if (!rule)
|
if (!rule)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
ret = bcm_sf2_cfp_rule_del_one(priv, port, loc, &next_loc);
|
ret = bcm_sf2_cfp_rule_remove(priv, port, loc);
|
||||||
if (ret)
|
|
||||||
return ret;
|
|
||||||
|
|
||||||
/* If this was an IPv6 rule, delete is companion rule too */
|
|
||||||
if (next_loc)
|
|
||||||
ret = bcm_sf2_cfp_rule_del_one(priv, port, next_loc, NULL);
|
|
||||||
|
|
||||||
list_del(&rule->next);
|
list_del(&rule->next);
|
||||||
kfree(rule);
|
kfree(rule);
|
||||||
|
|
Loading…
Reference in New Issue