aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/dsa/bcm_sf2_cfp.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/dsa/bcm_sf2_cfp.c')
-rw-r--r--drivers/net/dsa/bcm_sf2_cfp.c46
1 files changed, 42 insertions, 4 deletions
diff --git a/drivers/net/dsa/bcm_sf2_cfp.c b/drivers/net/dsa/bcm_sf2_cfp.c
index b89acaee12d4..47c5f272a084 100644
--- a/drivers/net/dsa/bcm_sf2_cfp.c
+++ b/drivers/net/dsa/bcm_sf2_cfp.c
@@ -732,6 +732,8 @@ static int bcm_sf2_cfp_rule_set(struct dsa_switch *ds, int port,
732 struct ethtool_rx_flow_spec *fs) 732 struct ethtool_rx_flow_spec *fs)
733{ 733{
734 struct bcm_sf2_priv *priv = bcm_sf2_to_priv(ds); 734 struct bcm_sf2_priv *priv = bcm_sf2_to_priv(ds);
735 s8 cpu_port = ds->ports[port].cpu_dp->index;
736 __u64 ring_cookie = fs->ring_cookie;
735 unsigned int queue_num, port_num; 737 unsigned int queue_num, port_num;
736 int ret = -EINVAL; 738 int ret = -EINVAL;
737 739
@@ -748,21 +750,28 @@ static int bcm_sf2_cfp_rule_set(struct dsa_switch *ds, int port,
748 fs->location > bcm_sf2_cfp_rule_size(priv)) 750 fs->location > bcm_sf2_cfp_rule_size(priv))
749 return -EINVAL; 751 return -EINVAL;
750 752
753 /* This rule is a Wake-on-LAN filter and we must specifically
754 * target the CPU port in order for it to be working.
755 */
756 if (ring_cookie == RX_CLS_FLOW_WAKE)
757 ring_cookie = cpu_port * SF2_NUM_EGRESS_QUEUES;
758
751 /* We do not support discarding packets, check that the 759 /* We do not support discarding packets, check that the
752 * destination port is enabled and that we are within the 760 * destination port is enabled and that we are within the
753 * number of ports supported by the switch 761 * number of ports supported by the switch
754 */ 762 */
755 port_num = fs->ring_cookie / SF2_NUM_EGRESS_QUEUES; 763 port_num = ring_cookie / SF2_NUM_EGRESS_QUEUES;
756 764
757 if (fs->ring_cookie == RX_CLS_FLOW_DISC || 765 if (ring_cookie == RX_CLS_FLOW_DISC ||
758 !dsa_is_user_port(ds, port_num) || 766 !(dsa_is_user_port(ds, port_num) ||
767 dsa_is_cpu_port(ds, port_num)) ||
759 port_num >= priv->hw_params.num_ports) 768 port_num >= priv->hw_params.num_ports)
760 return -EINVAL; 769 return -EINVAL;
761 /* 770 /*
762 * We have a small oddity where Port 6 just does not have a 771 * We have a small oddity where Port 6 just does not have a
763 * valid bit here (so we substract by one). 772 * valid bit here (so we substract by one).
764 */ 773 */
765 queue_num = fs->ring_cookie % SF2_NUM_EGRESS_QUEUES; 774 queue_num = ring_cookie % SF2_NUM_EGRESS_QUEUES;
766 if (port_num >= 7) 775 if (port_num >= 7)
767 port_num -= 1; 776 port_num -= 1;
768 777
@@ -1187,6 +1196,7 @@ static int bcm_sf2_cfp_rule_get_all(struct bcm_sf2_priv *priv,
1187int bcm_sf2_get_rxnfc(struct dsa_switch *ds, int port, 1196int bcm_sf2_get_rxnfc(struct dsa_switch *ds, int port,
1188 struct ethtool_rxnfc *nfc, u32 *rule_locs) 1197 struct ethtool_rxnfc *nfc, u32 *rule_locs)
1189{ 1198{
1199 struct net_device *p = ds->ports[port].cpu_dp->master;
1190 struct bcm_sf2_priv *priv = bcm_sf2_to_priv(ds); 1200 struct bcm_sf2_priv *priv = bcm_sf2_to_priv(ds);
1191 int ret = 0; 1201 int ret = 0;
1192 1202
@@ -1213,12 +1223,23 @@ int bcm_sf2_get_rxnfc(struct dsa_switch *ds, int port,
1213 1223
1214 mutex_unlock(&priv->cfp.lock); 1224 mutex_unlock(&priv->cfp.lock);
1215 1225
1226 if (ret)
1227 return ret;
1228
1229 /* Pass up the commands to the attached master network device */
1230 if (p->ethtool_ops->get_rxnfc) {
1231 ret = p->ethtool_ops->get_rxnfc(p, nfc, rule_locs);
1232 if (ret == -EOPNOTSUPP)
1233 ret = 0;
1234 }
1235
1216 return ret; 1236 return ret;
1217} 1237}
1218 1238
1219int bcm_sf2_set_rxnfc(struct dsa_switch *ds, int port, 1239int bcm_sf2_set_rxnfc(struct dsa_switch *ds, int port,
1220 struct ethtool_rxnfc *nfc) 1240 struct ethtool_rxnfc *nfc)
1221{ 1241{
1242 struct net_device *p = ds->ports[port].cpu_dp->master;
1222 struct bcm_sf2_priv *priv = bcm_sf2_to_priv(ds); 1243 struct bcm_sf2_priv *priv = bcm_sf2_to_priv(ds);
1223 int ret = 0; 1244 int ret = 0;
1224 1245
@@ -1239,6 +1260,23 @@ int bcm_sf2_set_rxnfc(struct dsa_switch *ds, int port,
1239 1260
1240 mutex_unlock(&priv->cfp.lock); 1261 mutex_unlock(&priv->cfp.lock);
1241 1262
1263 if (ret)
1264 return ret;
1265
1266 /* Pass up the commands to the attached master network device.
1267 * This can fail, so rollback the operation if we need to.
1268 */
1269 if (p->ethtool_ops->set_rxnfc) {
1270 ret = p->ethtool_ops->set_rxnfc(p, nfc);
1271 if (ret && ret != -EOPNOTSUPP) {
1272 mutex_lock(&priv->cfp.lock);
1273 bcm_sf2_cfp_rule_del(priv, port, nfc->fs.location);
1274 mutex_unlock(&priv->cfp.lock);
1275 } else {
1276 ret = 0;
1277 }
1278 }
1279
1242 return ret; 1280 return ret;
1243} 1281}
1244 1282