Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 8a75f4f2 authored by Florian Fainelli's avatar Florian Fainelli Committed by David S. Miller
Browse files

net: dsa: bcm_sf2: Propagate ethtool::rxnfc to CPU port



Allow propagating ethtool::rxnfc programming to the CPU/management port
such that it is possible for such a CPU to perform e.g: Wake-on-LAN
using filters configured by the switch. We need a tiny bit of
cooperation between the switch drivers which is able to do the full flow
matching, whereas the CPU/management port might not. The CPU/management
driver needs to return -EOPNOTSUPP to indicate an non critical error,
any other error code otherwise.

Signed-off-by: default avatarFlorian Fainelli <f.fainelli@gmail.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 6cfef793
Loading
Loading
Loading
Loading
+40 −3
Original line number Diff line number Diff line
@@ -732,6 +732,8 @@ 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);
	s8 cpu_port = ds->ports[port].cpu_dp->index;
	__u64 ring_cookie = fs->ring_cookie;
	unsigned int queue_num, port_num;
	int ret = -EINVAL;

@@ -748,13 +750,19 @@ static int bcm_sf2_cfp_rule_set(struct dsa_switch *ds, int port,
	    fs->location > bcm_sf2_cfp_rule_size(priv))
		return -EINVAL;

	/* This rule is a Wake-on-LAN filter and we must specifically
	 * target the CPU port in order for it to be working.
	 */
	if (ring_cookie == RX_CLS_FLOW_WAKE)
		ring_cookie = cpu_port * SF2_NUM_EGRESS_QUEUES;

	/* We do not support discarding packets, check that the
	 * destination port is enabled and that we are within the
	 * number of ports supported by the switch
	 */
	port_num = fs->ring_cookie / SF2_NUM_EGRESS_QUEUES;
	port_num = ring_cookie / SF2_NUM_EGRESS_QUEUES;

	if (fs->ring_cookie == RX_CLS_FLOW_DISC ||
	if (ring_cookie == RX_CLS_FLOW_DISC ||
	    !(dsa_is_user_port(ds, port_num) ||
	      dsa_is_cpu_port(ds, port_num)) ||
	    port_num >= priv->hw_params.num_ports)
@@ -763,7 +771,7 @@ static int bcm_sf2_cfp_rule_set(struct dsa_switch *ds, int port,
	 * We have a small oddity where Port 6 just does not have a
	 * valid bit here (so we substract by one).
	 */
	queue_num = fs->ring_cookie % SF2_NUM_EGRESS_QUEUES;
	queue_num = ring_cookie % SF2_NUM_EGRESS_QUEUES;
	if (port_num >= 7)
		port_num -= 1;

@@ -1188,6 +1196,7 @@ static int bcm_sf2_cfp_rule_get_all(struct bcm_sf2_priv *priv,
int bcm_sf2_get_rxnfc(struct dsa_switch *ds, int port,
		      struct ethtool_rxnfc *nfc, u32 *rule_locs)
{
	struct net_device *p = ds->ports[port].cpu_dp->master;
	struct bcm_sf2_priv *priv = bcm_sf2_to_priv(ds);
	int ret = 0;

@@ -1214,12 +1223,23 @@ int bcm_sf2_get_rxnfc(struct dsa_switch *ds, int port,

	mutex_unlock(&priv->cfp.lock);

	if (ret)
		return ret;

	/* Pass up the commands to the attached master network device */
	if (p->ethtool_ops->get_rxnfc) {
		ret = p->ethtool_ops->get_rxnfc(p, nfc, rule_locs);
		if (ret == -EOPNOTSUPP)
			ret = 0;
	}

	return ret;
}

int bcm_sf2_set_rxnfc(struct dsa_switch *ds, int port,
		      struct ethtool_rxnfc *nfc)
{
	struct net_device *p = ds->ports[port].cpu_dp->master;
	struct bcm_sf2_priv *priv = bcm_sf2_to_priv(ds);
	int ret = 0;

@@ -1240,6 +1260,23 @@ int bcm_sf2_set_rxnfc(struct dsa_switch *ds, int port,

	mutex_unlock(&priv->cfp.lock);

	if (ret)
		return ret;

	/* Pass up the commands to the attached master network device.
	 * This can fail, so rollback the operation if we need to.
	 */
	if (p->ethtool_ops->set_rxnfc) {
		ret = p->ethtool_ops->set_rxnfc(p, nfc);
		if (ret && ret != -EOPNOTSUPP) {
			mutex_lock(&priv->cfp.lock);
			bcm_sf2_cfp_rule_del(priv, port, nfc->fs.location);
			mutex_unlock(&priv->cfp.lock);
		} else {
			ret = 0;
		}
	}

	return ret;
}